在 gas 中是否有类似 org for nasm 的东西?

Is there something like org for nasm in gas?

在 nasm 中,当我键入

bits 32
org 1
jmp mylabel
mylabel:

org 指令将所有标签的地址偏移 1。 但是,当我在 GAS 中执行此操作时:

.org 1
jmp mylabel
mylabel:

我得到一个文件,其中标签地址与程序没有 org 相同,但编译文件中有 1 个前导 0。 GAS 中是否有一个指令的行为类似于 nasm 中的组织?

GNU 汇编程序没有与 NASM 的 ORG 指令等效的指令。 GNU 汇编程序的 .ORG 指令更像 MASM 的 ORG 指令,这可能是 NASM 和 GAS 指令仿照的地方。

NASM 的 ORG 指令比 GAS 或 MASMs 指令更受限制。正如 Frank Kotler 所说,它只适用于 "bin" 输出格式,并且只能在源文件中使用一次。来自 NASM Manual:

Unlike the ORG directive provided by MASM-compatible assemblers, which allows you to jump around in the object file and overwrite code you have already generated, NASM's ORG does exactly what the directive says: origin. Its sole function is to specify one offset which is added to all internal address references within the section; it does not permit any of the trickery that MASM's version does.

GNU 汇编程序 .ORG 指令不允许 MASM 的 ORG 指令允许的 "trickery"。您不能向后移动原点并覆盖已经生成的代码。然而,GAS 确实允许您多次使用它,最重要的是它适用于 object 文件格式,如 ELF 和 PECOFF。没有办法用这些 object 文件格式实现 NASM 的 ORG 指令的行为,因为没有办法说应该在特定地址加载一个部分。

正如 dwelch 所说,无论您使用什么汇编器,ORG 指令都只能用于单文件汇编项目。 NASM 强制这样做,因为它只适用于 "bin" 输出格式,不能 linked。对于 GAS 和 MASM,.ORG/ORG 指令仅相对于 object 文件中 section/segment 的开头。这意味着如果您希望这些指令在 linked 图像中设置绝对地址,则带有指令的部分必须是第一个或唯一的部分,并且该部分必须从地址 0 开始。

要使用 GNU 汇编器和 linker 获得您想要的行为,您需要两件事。首先,您希望生成的二进制图像在加载到 ORG 指令给定的绝对地址时工作。这意味着任何绝对内存引用都需要使用引用位置加载到内存中的内存位置,而不是引用位置在二进制文件中的位置。由于您的第二个要求,这两个位置不同。您的第二个要求是二进制文件从代码中的第一个位置开始,而不是地址 0。

为了向您展示如何使用 GNU 汇编程序和 linker 执行此操作,我将使用一个创建 MS-DOS .COM 文件的更实际的示例。 COM 文件是简单的二进制文件。与其他可执行格式一样,文件中没有存储 headers 或其他信息,只有原始二进制映像。该文件被加载到单个 16 位段中,从偏移量 0x100 开始。所以这就像你的 NASM 示例一样,文件中的第一个字节不应该加载到地址 0。在这种情况下,它加载到地址 0x100.

所以这是一个简单的 MS-DOS "Hello, World!" 程序,用 GNU 汇编语言编写:

        .code16
        .text

        mov     $msg,%dx
        mov     ,%ah
        int     [=10=]x21
        mov     [=10=]x4c00,%ax
        int     [=10=]x21

msg:
        .ascii  "Hello, world!$"

注意,上面的源代码示例中没有 .ORG 指令。事实证明,它对创建未在地址 0 加载的二进制文件没有帮助。它可以正常组装,但要 link 正确,您需要使用 -Ttext= 选项,如住:

as -o hello.o hello.s
ld -Ttext=0x100 --oformat binary -o hello.com hello.o

请注意,上述命令不适用于 Windows PECOFF 版本的 GNU 汇编器和 linker。您需要在 Linux 或其他使用 ELF object 文件格式的机器上 运行 这些命令。

您可以看到 linker 使用以下命令正确生成了 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    [=12=]x10c,%dx
 103:   b4 09                   mov    [=12=]x9,%ah
 105:   cd 21                   int    [=12=]x21
 107:   b8 00 4c                mov    [=12=]x4c00,%ax
 10a:   cd 21                   int    [=12=]x21
 10c:   48                      dec    %ax
 10d:   65                      gs
...

文件的第一个字节是mov $msg,%dx指令,如hd所示。没有额外的字节填充 COM 文件的开头。 objdump 反汇编程序输出显示对符号 msg 的绝对内存引用已被正确解析。它指向字符串将被加载到内存中的地址 (0x010c),而不是字符串在文件中的位置 (0x000c)。

对于 link 编辑多个文件或使用多个部分的更复杂的示例,您可能需要使用 linker 脚本而不是 -Ttext= 选项。