使用NASM + LD编写/链接平面二进制文件

6

我正在创建自己的“玩具”操作系统,现在我正在尝试理解链接和可执行文件格式 - 特别是我有一个扁平文件二进制格式的可执行文件,我正在将其加载到地址0x500的内存中,然后直接调用。例如,考虑以下两个指令(我知道这是人为的,我只是想在我的示例中包含一个callmov

mov ax, some_label
call some_label
; some_label is at address 0x99 into the resulting binary

到目前为止,我一直使用NASM来使用org 0x500指令和命令nasm -f bin myfile.asm来生成所需的输出。生成的反汇编结果看起来像这样,并且可以完美运行:

mov ax, 0x599
call 0x599

我现在想开始使用LD,以便可以链接其他对象,但是经过大量实验和阅读后,我仍然不太理解发生了什么,无法获得可靠的结果。

我已经了解到为了产生类似的输出,我需要:

  • 使NASM输出obj格式,其中包含适合链接的符号信息(我选择ELF,因为它似乎是任何格式中最好的)
  • 使LD将结果与.text部分的地址链接为0x500,然后将结果作为平坦二进制文件发出 - 是链接器最终决定各种偏移量在最终二进制文件中被解析的。

到目前为止,我尝试过以下内容:

:: Output as ELF 
nasm -f elf myfile.asm
:: Then link and output as binary with the address of .text as 0x500
ld --oformat binary -Ttext 0x500 myfile.o

然而,这给我带来了以下错误(在Mingw上):

ld:无法对非PE输出文件执行PE操作

Google搜索导致我找到了这个邮件列表,看起来很有道理,因此我尝试了以下方法:
:: Output as ELF
nasm -f elf myfile.asm -o myfile.o
:: Link using LD
ld myfile.o -Ttext 0x500 -s -o myfile.tmp
:: Use objdump to output as a flat binary
objcopy -O binary myfile.tmp myfile

然而,生成的myfile看起来像垃圾:
00000000  66B8C105E8B8      mov eax,0xb8e805c1
00000006  0000              add [bx+si],al

我尝试了以上几种变化,但没有一种能够产生我期望的结果,所以现在我感到相当困惑:

  • 有人可以帮我理解这里正在发生什么吗?
  • 还有我应该做些什么来获得对生成二进制文件中地址被解析到的控制权呢?
1个回答

4

我发现自己犯了多个错误,其中最严重的是试图使用不支持16位代码的LD进行编译和链接16位代码,并且没有明确指定代码为16位,使用BITS 16(这意味着NASM发出32位内存地址)。

总体而言,这解释了LD在某些情况下给我奇怪的错误消息以及链接二进制文件的反汇编结果垃圾的原因——我试图将32位代码反编译为16位代码或反之亦然。

理想情况下,我希望能够链接16位代码,但是既然发现不能用LD(几乎没有其他替代品可以做到),我决定接受使用32位代码时的情况。我的输入文件:

; Address locations are now 32 bits so I must use `eax` instead of `ax`
mov eax, some_label 
call some_label
; some_label is at a different address into the resulting binary (because 
; pointers are wider the resulting machine code is larger)

I then link this using the following:

:: Output as win32 object files - makes it possible to use -r with LD.
nasm -f win myfile.asm -o myfile.o
:: Link using LD - the -r flag prevents extra un-used code (e.g. __CTOR_LIST__) being generated - see the link in my original question text
ld myfile.o -Ttext 0x500 -s -r -o myfile.tmp
:: Use objdump to output as a flat binary - -j .text ensures that just the .text section is included which keeps the output file size down
objcopy -O binary -j .text myfile.tmp myfile

使用 ndisasm 进行反汇编时,需要指定 -b 32 才能正确解释代码为 32 位。
经过大量实验和阅读晦涩的论坛链接,我现在对整个过程有了更好的理解。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接