在nasm中,当我输入
时bits 32
org 1
jmp mylabel
mylabel:
组织指令将所有标签的地址偏移1。 但是,当我在GAS中这样做时:
.org 1
jmp mylabel
mylabel:
我得到一个文件,其中标签地址与程序没有组织相同,但编译文件中有1个前导0。 GAS中是否有类似于来自nasm的组织的指令?
答案 0 :(得分:3)
GNU汇编程序没有与NASM的ORG指令等效的指令。 GNU汇编程序的.ORG指令更像是MASM的ORG指令,它可能是NASM和GAS指令的模型。
NASM的ORG指令比GAS或MASMs指令更受限制。正如Frank Kotler所说,它只适用于“bin”输出格式,并且只能在源文件中使用一次。来自NASM Manual:
与MASM兼容的汇编程序提供的ORG指令不同 允许您在目标文件中跳转并覆盖您拥有的代码 已经生成,NASM的ORG正是指令所说的:起源。 它唯一的功能是指定一个添加到所有内部的偏移量 在该部分内提供参考;它不允许任何欺骗 MASM的版本确实如此。
GNU汇编程序.ORG指令不允许MASM的ORG指令执行“欺骗”。您无法向后移动原点并覆盖已生成的代码。但是,GAS允许您多次使用它,最重要的是它可以使用ELF和PECOFF等目标文件格式。没有办法用这些目标文件格式实现NASM的ORG指令的行为,因为没有办法说某个部分应该加载到特定的地址。
正如dwelch所说,ORG指令,无论你使用什么汇编程序,都只能用于单文件汇编项目。 NASM强制执行此操作,因为它仅适用于无法链接的“bin”输出格式。对于GAS和MASM,.ORG / ORG指令仅相对于目标文件中节/段的开头。这意味着如果您希望这些指令在链接图像中设置绝对地址,则带有该指令的部分必须是第一个或唯一的部分,该部分必须从地址0开始。
要使用GNU汇编器和链接器获得所需的行为,您需要做两件事。首先,您希望生成的二进制映像在ORG指令给出的绝对地址处加载时起作用。这意味着任何绝对内存引用都需要使用内存中的位置,其中引用位置被加载到内存中,而不是引用位置在二进制文件中的位置。由于您的第二个要求,这两个位置是不同的。您的第二个要求是二进制文件从代码中的第一个位置开始,而不是从地址0开始。
为了向您展示如何使用GNU汇编器和链接器执行此操作,我将使用更实际的示例来创建MS-DOS .COM文件。 COM文件是简单的二进制文件。文件中没有与其他可执行格式一样存储的标题或其他信息,只有原始二进制图像。该文件从偏移量0x100开始加载到单个16位段中。所以这就像你的NASM示例一样,文件中的第一个字节不应该在地址0加载。在这种情况下,它加载到地址0x100。
所以这是一个简单的MS-DOS“Hello,World!”程序,用GNU程序集编写:
.code16
.text
mov $msg,%dx
mov $9,%ah
int $0x21
mov $0x4c00,%ax
int $0x21
msg:
.ascii "Hello, world!$"
注意,上面的源代码示例中没有.ORG指令。事实证明它没有帮助创建一个未在地址0加载的二进制文件。它可以正常组装,但要正确链接它,你需要使用dwelch提到的-Ttext=
选项:
as -o hello.o hello.s
ld -Ttext=0x100 --oformat binary -o hello.com hello.o
请注意,上述命令不适用于GNU汇编程序和链接程序的Windows PECOFF版本。您需要在Linux或其他使用ELF目标文件格式的计算机上运行这些命令。
您可以看到链接器使用以下命令正确生成COM:
$ hd hello.com
00000000 ba 0c 01 b4 09 cd 21 b8 00 4c cd 21 48 65 6c 6c |......!..L.!Hell|
00000010 6f 2c 20 77 6f 72 6c 64 21 24 |o, world!$|
0000001a
$ objdump -b binary -m i8086 --adjust-vma=0x100 -D hello.com
...
00000100 <.data>:
100: ba 0c 01 mov $0x10c,%dx
103: b4 09 mov $0x9,%ah
105: cd 21 int $0x21
107: b8 00 4c mov $0x4c00,%ax
10a: cd 21 int $0x21
10c: 48 dec %ax
10d: 65 gs
...
文件中的第一个字节是mov $msg,%dx
指令,如hd
所示。在COM文件的开头没有额外的字节填充。 objdump
反汇编程序输出显示已正确解析符号msg
的绝对内存引用。它指向将字符串加载到内存中的地址(0x010c
),而不是文件中字符串的位置(0x000c
)。
对于将多个文件链接在一起或使用多个部分的更复杂的示例,您可能需要使用链接描述文件而不是-Ttext=
选项。