问题
I am trying to follow this tutorial for creating a binary file, but the linker appears to be appending additional instructions at the end of the assembly. I assume this is the OS's tear-down process.
The tutorial attempts to compile a bare bones 32-bit C program on Linux:
int main() {
}
using these commands:
gcc -c test.c
ld -o test -Ttext 0x0 -e main test.o
objcopy -R .note -R .comment -S -O binary test test.bin
ndisasm -b 32 test.bin
I am running 64-bit Linux, and hence modified the compilation steps to be the following:
gcc -m32 -c test.c
ld -m elf_i386 -o test -Ttext 0x0 -e main test.o
objcopy -R .note -R .comment -S -O binary test test.bin
ndisasm -b 32 test.bin
The expected output is:
00000000 55 push ebp
00000001 89E5 mov ebp,esp
00000003 C9 leave
00000004 C3 ret
My output is the following:
;; START expected output
00000000 55 push bp
00000001 89E5 mov bp,sp
00000003 5D pop bp
00000004 C3 ret
;; END expected output
00000005 0000 add [eax],al
00000007 001400 add [eax+eax],dl
0000000A 0000 add [eax],al
0000000C 0000 add [eax],al
0000000E 0000 add [eax],al
00000010 017A52 add [edx+0x52],edi
00000013 0001 add [ecx],al
00000015 7C08 jl 0x1f
00000017 011B add [ebx],ebx
00000019 0C04 or al,0x4
0000001B 0488 add al,0x88
0000001D 0100 add [eax],eax
0000001F 001C00 add [eax+eax],bl
00000022 0000 add [eax],al
00000024 1C00 sbb al,0x0
00000026 0000 add [eax],al
00000028 D8FF fdivr st7
0000002A FF db 0xff
0000002B FF0500000000 inc dword [dword 0x0]
00000031 41 inc ecx
00000032 0E push cs
00000033 088502420D05 or [ebp+0x50d4202],al
00000039 41 inc ecx
0000003A C50C04 lds ecx,[esp+eax]
0000003D 0400 add al,0x0
0000003F 00 db 0x00
What is the purpose of the additional instructions, and how can I strip them from the object file and binary?
EDIT:
- Typo in
objcopy
args (commet -> comment). Updated disassembly output.
回答1:
Generally when you see additional data/instructions in the output file the source of the issue is probably a section that appears after your expected code. A way to deal with this is to query the ELF executable to see what sections it defines. One can query just the sections with the -x
parameter to OBJDUMP. Using this command:
objdump -x test
Should produce output similar (not exact) to this in most modern versions of GCC using default parameters:
test: file format elf32-i386 test architecture: i386, flags 0x00000112: EXEC_P, HAS_SYMS, D_PAGED start address 0x00000000 Program Header: LOAD off 0x00001000 vaddr 0x00000000 paddr 0x00000000 align 2**12 filesz 0x00000040 memsz 0x00000040 flags r-x STACK off 0x00000000 vaddr 0x00000000 paddr 0x00000000 align 2**4 filesz 0x00000000 memsz 0x00000000 flags rw- Sections: Idx Name Size VMA LMA File off Algn 0 .text 00000005 00000000 00000000 00001000 2**0 CONTENTS, ALLOC, LOAD, READONLY, CODE 1 .eh_frame 00000038 00000008 00000008 00001008 2**2 CONTENTS, ALLOC, LOAD, READONLY, DATA 2 .comment 0000001d 00000000 00000000 00001040 2**0 CONTENTS, READONLY SYMBOL TABLE: 00000000 l d .text 00000000 .text 00000008 l d .eh_frame 00000000 .eh_frame 00000000 l d .comment 00000000 .comment 00000000 l df *ABS* 00000000 test.c 00001040 g .eh_frame 00000000 __bss_start 00000000 g F .text 00000005 main 00001040 g .eh_frame 00000000 _edata 00001040 g .eh_frame 00000000 _end
One should first look for unexpected sections. Your OBJCOPY command used -R
to remove sections from the ELF object before outputting to the file test.bin
. You did:
objcopy -R .note -R .comment -S -O binary test test.bin
If we exclude .note
and .comment
sections the obvious one remaining in the OBJDUMP output above is .eh_frame
. .eh_frame
was placed into your file test.bin
after the .text
section. This contains exception unwinding information. It isn't actual instructions. NDISASM is dumping non-code as instructions because a binary file doesn't distinguish between code and data. NDISASM blindly converted all the data to instructions.
There are a couple of ways around this. You can exclude the .eh_frame
section like you did with the other two. You could use:
objcopy -R .note -R .comment -R .eh_frame -S -O binary test test.bin
You could also tell GCC not to produce asynchronous exception unwinding tables in the code. This can be done with the GCC option:
gcc -m32 -c test.c -fno-asynchronous-unwind-tables
This differs from my comment a bit, as I suggested disabling all exceptions. You just need to disable the asynchronous unwind tables to suppress the .eh_frame
section. The usefulness (or lack thereof) of this section is discussed in this Stackoverflow answer. The man page (man gcc
) for GCC discusses the option -fasynchronous-unwind-tables
-fasynchronous-unwind-tables Generate unwind table in DWARF 2 format, if supported by target machine. The table is exact at each instruction boundary, so it can be used for stack unwinding from asynchronous events (such as debugger or garbage collector).
This is the default on most GCCs these days. Using -fno-asynchronous-unwind-tables
turns this feature off.
The tutorial you linked to was produced in 2000. GCC and its options (and the defaults used by distributions) have changed over the years. Likely when that tutorial was created the asynchronous unwind tables didn't yet exist. This would explain why your observed output differed from the tutorial.
来源:https://stackoverflow.com/questions/39456178/instructions-appended-to-end-of-assembly