是否可以使用`as`组装和运行原始CPU指令?

mer*_*011 2 linux x86 assembly gnu-assembler

这里有几个相关的问题.考虑一个仅包含以下两条指令的程序

movq 1, %rax
cpuid
Run Code Online (Sandbox Code Playgroud)

如果我把它扔进一个名为的文件Foo.asm,并运行as Foo.asm,as那么便携式GNU汇编器,我将a.out在我的系统上得到一个大小为665字节的文件.

如果我然后chmod 700 a.out尝试./a.out,我会收到一个错误说cannot execute binary file.

  1. 如果我只是想将两条asm指令翻译成二进制文件,为什么文件如此之大?
  2. 为什么不能执行二进制文件?我提供有效的指令,所以我希望CPU能够执行它们.
  3. 如何获得asm输入文件中指令的二进制操作码,而不是一堆额外的东西?
  4. 一旦得到3的答案,我怎样才能让我的处理器执行它们?(假设我没有运行特权指令.)

And*_*ter 9

  1. 如果我只是试图将两个asm指令转换为二进制文件,为什么文件如此之大?

    因为汇编程序创建了一个relocatable object file包含附加信息的内容,例如内存段符号表.

  2. 为什么不能执行二进制文件?

    因为它是一个(可重定位的)object file,而不是一个loadable file.您需要链接它以使其可执行,以便操作系统可以加载它:

    $ ld  -o Foo a.out
    
    Run Code Online (Sandbox Code Playgroud)

    您还需要通过指定_start符号为链接器提供程序启动位置的提示.

    但是,仍然,Foo可执行文件比您预期的要大,因为它仍然包含elf header操作系统实际启动程序所需的其他信息(例如).

    此外,如果您现在启动可执行文件,它将导致a segmentation fault,因为您正在加载address未映射到您的地址空间的1 的内容rax.尽管如此,如果你解决这个问题,程序最后会遇到未定义的代码 - 你需要确保通过a优雅地退出程序syscall.

    最小的运行示例(假设为x86_64架构)看起来像

    .globl  _start
    _start:
        movq $1, %rax
        cpuid
    
        mov     $60, %rax       # System-call "sys_exit"
        mov     $0, %rdi        # exit code 0
        syscall
    
    Run Code Online (Sandbox Code Playgroud)
  3. 如何在输入文件中准确获取asm指令的二进制操作码,而不是一堆额外的东西?

  4. 一旦得到3的答案,我怎样才能让我的处理器执行它们?

    您将无法在Linux下直接执行原始二进制文件.您需要为此编写自己的加载器或根本不使用操作系统.例如,请参阅上面的裸引导加载程序链接 - 这将操作码写入VirtualBox光盘映像的引导加载程序,以便在启动VirtualBox机器时执行指令.