这里有几个相关的问题。 考虑一个仅包含以下两条指令的程序
movq 1, %rax
cpuid
如果我把它扔进一个名为Foo.asm
的文件中,并运行as Foo.asm
,其中as
是可移植的GNU汇编程序,我将得到一个名为a.out
的文件,在我的系统上大小为665字节。
如果我然后chmod 700 a.out
并尝试./a.out
,我会收到错误cannot execute binary file
。
asm
指令翻译成二进制文件,为什么文件太大?asm
指令的二进制操作码,而不是一堆额外的东西?答案 0 :(得分:9)
如果我只想将两个asm指令翻译成二进制文件,为什么文件太大?
因为汇编程序创建了一个relocatable object file
,其中包含其他信息,例如内存部分和符号表。
为什么不能执行二进制文件?
因为它是(可重定位的)object file
,而不是loadable file
。您需要链接它以使其可执行,以便操作系统可以加载它:
$ ld -o Foo a.out
您还需要通过指定_start
符号,向链接器提供有关程序启动位置的提示。
但是,然而,Foo
可执行文件仍然比您预期的要大,因为它仍然包含操作系统实际启动程序所需的其他信息(例如elf header
)。
此外,如果您现在启动可执行文件,则会生成segmentation fault
,因为您要将address
1的内容(未映射到您的地址空间)加载到{{1} }}。尽管如此,如果你解决这个问题,程序最后会遇到未定义的代码 - 你需要确保通过rax
优雅地退出程序。
最小运行示例(假设x86_64架构)看起来像
syscall
如何在输入文件中准确获取asm指令的二进制操作码,而不是一堆额外的东西?
You can use objcopy
从目标文件生成二进制图像 :
.globl _start
_start:
movq $1, %rax
cpuid
mov $60, %rax # System-call "sys_exit"
mov $0, %rdi # exit code 0
syscall
然后,$ objcopy -O binary a.out Foo.bin
仅包含指令操作码。
nasm有一个Foo.bin
选项,可以创建汇编代码的二进制表示形式。我使用它来实现bare boot loader for VirtualBox(警告:未记录,仅原型!),以在没有操作系统的情况下直接在VirtualBox图像中启动二进制代码。
一旦我得到3的答案,我怎样才能让我的处理器执行它们?
您将无法在Linux下直接执行原始二进制文件。您需要为此编写自己的加载器或根本不使用操作系统。例如,请参阅上面的裸引导加载程序链接 - 这将操作码写入VirtualBox光盘映像的引导加载程序,以便在启动VirtualBox机器时执行这些指令。
答案 1 :(得分:1)
对于GNU工具集,也许有类似于exe2bin实用程序的东西。我已经使用各种版本的exe2bin和Microsoft工具,ARM工具包可以生成二进制文件,但我不记得它是直接来自链接输出还是类似exe2bin。
答案 2 :(得分:1)
旧的MS-DOS COM文件格式不包含标头。它实际上只包含二进制可执行代码。但是,代码大小不能超过64kb。我不知道Linux是否可以执行这些。