附加到装配结束的说明

时间:2016-09-12 18:03:39

标签: gcc assembly x86 nasm ld

我正在尝试按照this教程创建二进制文件,但链接器似乎在程序集的末尾添加了附加指令。我认为这是操作系统的拆除过程。

本教程尝试在Linux上编译一个简单的32位C程序:

int main() {
}

使用这些命令:

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

我正在运行64位Linux,因此将编译步骤修改为以下内容:

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

预期输出为:

00000000 55            push ebp
00000001 89E5          mov ebp,esp
00000003 C9            leave
00000004 C3            ret

我的输出如下:

;; 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

附加说明的目的是什么,以及如何从目标文件和二进制文件中删除它们?

编辑:

  • 错误objcopy args(commet - >评论)。更新了反汇编输出。

1 个答案:

答案 0 :(得分:3)

通常,当您在输出文件中看到其他数据/说明时,问题的来源可能是在您预期的代码之后出现的部分。解决此问题的方法是查询 ELF 可执行文件以查看它定义的部分。可以只查询-x参数到OBJDUMP的部分。使用此命令:

objdump -x test

使用默认参数在 GCC 的大多数现代版本中应该产生类似(不完全)的输出:

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

首先应该寻找意想不到的部分。在输出到文件-R之前,您的OBJCOPY命令使用test.bin ELF 对象中删除了部分。你做了:

objcopy -R .note -R .comment -S -O binary test test.bin

如果我们排除.note.comment部分,则 OBJDUMP 输出中剩余的明显部分为.eh_frame。在.eh_frame部分之后,test.bin已放入您的文件.text。这包含异常展开信息。这不是实际的指示。 NDISASM将非代码转储为指令,因为二进制文件不区分代码和数据。 NDISASM 盲目地将所有数据转换为指令。

有很多方法可以解决这个问题。您可以像对待其他两个一样排除.eh_frame部分。你可以使用:

objcopy -R .note -R .comment -R .eh_frame -S -O binary test test.bin

您还可以告诉 GCC 不要在代码中生成异步异常展开表。这可以通过 GCC 选项完成:

gcc -m32 -c test.c -fno-asynchronous-unwind-tables  

这与我的评论有所不同,因为我建议禁用所有异常。您只需要禁用异步展开表以禁止.eh_frame部分。本节讨论了本节的用处(或缺乏)Stackoverflow answer GCC 的手册页(man gcc)讨论选项-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).

这是目前大多数 GCC 的默认设置。使用-fno-asynchronous-unwind-tables可以关闭此功能。

您链接的tutorial是在2000年制作的。 GCC 及其选项(以及发行版使用的默认值)多年来都发生了变化。可能在创建该教程时,异步展开表还不存在。这可以解释为什么您观察到的输出与教程不同。