如何使用GNU GAS汇编器生成像nasm -f bin一样的纯二进制文件?

26

我有一些NASM文件,它们通常具有以下结构:

        [BITS 64]
        [ORG 0x0000000000200000]

start:
        ...

        ret

我是这样组装它们的:

nasm -f bin abc.asm

我想使用GAS来编写其中一些。有两个问题:

  • GAS中应该使用哪些指令?我找到了'.org'指令,但是GAS似乎没有'.bits'指令。

  • 我应该传递什么给gccas以生成纯二进制文件?也就是说,与NASM的-f bin选项相同。


出于好奇:那段代码的目标平台是什么?我见过最常见的是为引导扇区编写16位裸汇编,但由于你使用的是64位,这不是情况。 - Ciro Santilli OurBigBook.com
2个回答

22

在GAS中应该使用什么指令?我发现了'.org'指令,但是GAS似乎没有'.bits'指令。

对于我而言,汇编器默认为64位,你可以使用--32--64命令行选项来选择。查看as手册以了解如何在代码内部更改体系结构(例如,可使用.code16生成引导加载程序的实模式代码)。

您很可能不想使用.org指令指定代码位置,而是可能想要使用链接脚本或在命令行上指定文本和数据段的加载位置。(org 0x0000000000200000将导致生成一个超过2MB的二进制文件)。

我应该向gcc或as传递什么参数才能生成普通的二进制文件?也就是说,与NASM一起使用-f bin选项的作用相同。

$ cat test.S
.section .text
.globl _start
_start:
        xor %rax, %rax
        mov test, %rax
        ret

test: .quad 0x1234567812345678


$ as --64 -o test.o test.S
$ ld -Ttext 200000 --oformat binary -o test.bin test.o
$ objdump -D -b binary -m i386:x86-64 test.bin
test.bin: 二进制文件格式
.data段的反汇编:
0000000000000000 <.data>:
   0:   48 31 c0                xor    %rax,%rax
   3:   48 8b 04 25 0c 00 20    mov    0x20000c,%rax
   a:   00 
   b:   c3                      retq
c: 78 56 js 0x64 e: 34 12 xor $0x12,%al 10: 78 56 js 0x68 12: 34 12 xor $0x12,%al

原始的NASM文件包含一些像这样的行:xyz equ 0x0000000000100010。然后它们能够执行call xyz。我尝试在GAS中做同样的事情,但好像不起作用。即使用.set xyz, 0x0000000000100010,然后再执行call xyz似乎不能奏效。您有什么想法吗?也许我应该另开一个问题。 - dharmatech
你需要哪种跳转?我认为绝对的64位调用不可能。对于间接调用,你需要使用 call *xyz - user786653
当我反汇编NASM代码时,它显示:对于call xyzcallq 0xfffffffffff00040,其中xyz equ 0x0000000000100040 - dharmatech
顺便再次感谢!这里的目标是使用GAS为BareMetal操作系统生成二进制文件。现在已经可以工作了,只要不涉及系统调用的非常简单的二进制文件。现在我正在尝试解决上述的等式/调用问题以访问系统调用。 - dharmatech
此外,当我反汇编(不工作的)GAS代码时,它显示callq *0x100040用于call xyz,其中.set xyz, 0x0000000000100040 - dharmatech
请尝试使用.set xyz,$0x0000000000100040,否则请提出新问题。 - user786653

11

objcopy -O binary

一个很好的选项是:

as -o test.o test.S
ld -Ttext 0x7C00 -o test.elf test.o
objcopy -O binary kernel.elf kernel.bin

与使用ld --oformat binary相比,优点在于更容易通过符号进行调试:
qemu-system-i386 -hda main.img -S -s &
gdb main.elf -ex 'target remote localhost:1234'

另请参阅:https://dev59.com/5lwY5IYBdhLWcg3wJU54#32960272

链接脚本

-Ttext 用于快速测试,但对于严肃的工作,您应该使用脚本来增加鲁棒性。

否则,ld 将使用一个默认脚本 (ld --verbose),该脚本适用于用户空间应用程序,而不是您的应用程序。

如果没有更多信息,我可以提供的最小脚本如下:

SECTIONS
{
    . = 2M;
    .text :
    {
        *(.*)
    }
}

然后使用-T参数:

as --64 -o test.o test.S
ld -T linker.ld --oformat binary -o test.bin test.o

但是您可能需要根据您的具体应用程序修改该脚本。

另请参阅:有没有办法让gcc输出原始二进制文件?

我有一个存储库,其中包含一些常见用例的工作示例:


2
为什么有些人在att约定使用第一个作为输入,第二个作为输出时,会非常坚持使用gcc -o outfile infile或者as -o outfile infile。我知道如果把输入放在输出之前,Flex/Bison甚至不能正常工作。这背后的原因是什么? - Dmytro
4
请遵循大多数其他命令行工具的惯例:首先是可选参数-o val,然后是位置参数。这一点尤其重要,当使用 -- -positional -with -leading hyphens 时。 - Ciro Santilli OurBigBook.com

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