如何使用GNU汇编程序(as)将程序集文件编译为原始二进制文件(如DOS .com)格式?

Ami*_*yan 5 assembly gnu-assembler binutils

我想在Windows中编译这个源代码(这只是一个例子):

start:
NOP
NOP
Run Code Online (Sandbox Code Playgroud)

当我用NASM或FASM编译它时,输出文件长度是2个字节.但是当我用GNU汇编程序(as)编译它时,输出文件长度是292字节!

如何使用GNU汇编程序(as)将程序集文件编译为原始二进制文件(如DOS .com)格式?


为什么我这样做?

我想编写自己的简单操作系统,用C编写代码(不使用任何C标准库,甚至是stdio.h或math.h)并将其转换为汇编:

gcc -S my_os.c -o my_os.asm -masm=intel
Run Code Online (Sandbox Code Playgroud)

然后,我将汇编文件编译为原始二进制文件:

as my_os.asm
Run Code Online (Sandbox Code Playgroud)

然后我重命名a.out(汇编程序的输出)到my_os.flp最后用VMWare启动我的操作系统:)

Cir*_*四事件 5

ld --oformat binary

对于快速和肮脏的测试,您可以:

as -o a.o a.S
ld --oformat binary -o a.out a.o
hd a.out
Run Code Online (Sandbox Code Playgroud)

得到:

00000000  90 90                                             |..|
00000002
Run Code Online (Sandbox Code Playgroud)

不幸的是,这给出了警告:

ld: warning: cannot find entry symbol _start; defaulting to 0000000000400000
Run Code Online (Sandbox Code Playgroud)

哪个没有多大意义binary.它可能会沉默:

.section .text
.globl start
start:
nop
nop
Run Code Online (Sandbox Code Playgroud)

和:

ld -e start --oformat binary -o a.out a.o
Run Code Online (Sandbox Code Playgroud)

或者只是:

ld -e 0 --oformat binary -o a.out a.o
Run Code Online (Sandbox Code Playgroud)

它告诉ld入口点不是_start地址的代码0.

很遗憾,既不能as也不ld能从stdin/stdout输入/ ouptut,所以没有管道.

适当的引导扇区

如果你想要更严肃的事情,最好的方法是生成一个干净的最小链接描述文件.linker.ld:

SECTIONS
{
    . = 0x7c00;
    .text :
    {
        *(.*)
        . = 0x1FE;
        SHORT(0xAA55)
    }
}
Run Code Online (Sandbox Code Playgroud)

这里我们还将魔术字节放在链接器脚本中.

首先,链接器脚本在重定位后控制输出地址非常重要.有关重新定位的详细信息,访问:https://stackoverflow.com/a/30507725/895245

用它作为:

as -o a.o a.S
ld --oformat binary -o a.img -T linker.ld a.o
Run Code Online (Sandbox Code Playgroud)

然后你可以启动:

qemu-system-i386 -hda a.img
Run Code Online (Sandbox Code Playgroud)

此存储库中的工作示例:https://github.com/cirosantilli/x86-bare-metal-examples/blob/d217b180be4220a0b4a453f31275d38e697a99e0/Makefile

测试了Binutils 2.24,Ubuntu 14.04.