【问题标题】:How does an assembler work?汇编程序是如何工作的?
【发布时间】:2011-09-04 06:19:29
【问题描述】:

我正在寻找关于使用汇编程序生成机器代码的简要说明。

所以我知道汇编是机器代码的 1:1 翻译。但我对目标代码和链接器以及它们如何放入其中感到困惑。

我不需要一个复杂的答案,只要一个简单的就可以了

【问题讨论】:

    标签: object assembly linker machine-code


    【解决方案1】:

    汇编器和编译器都将源文件转换为目标文件。

    目标文件实际上是最终可执行输出(由链接器生成)之前的中间步骤。

    链接器获取指定的目标文件和库(它们是目标文件的包)并解析重定位(或“修复”)记录。

    这些重定位记录是在编译器/汇编器不知道源代码中使用的函数或变量的地址时制作的,并通过名称为其生成引用,链接器可以解析该引用。

    例如,假设您希望一个程序将消息打印到屏幕上,分成两个源文件,并且您希望将它们分开组装并链接它们(例如使用 Linux x86-64 系统调用) -

    main.asm:

    bits 64
    section .text
    extern do_message
    global _start
    _start:
        call do_message
        mov rax, 1
        int 0x80 
    

    message.asm:

    bits 64
    section .text
    global do_message
    do_message:
        mov rdi, message
        mov rcx, dword -1
        xor rax, rax
        repnz scasb
        sub rdi, message
        mov rax, 4
        mov rbx, 1
        mov rcx, message
        mov rdx, rdi
        int 0x80
        ret
    
    section .data
    message: db "hello world",10,0
    

    如果您将这些组合起来并查看 main.asm 的目标文件输出(例如,objdump -d main.o),您会注意到“call do_message”的地址为 00 00 00 00 - 这是无效的。

    0000000000000000 <_start>:
       0:   e8 00 00 00 00          callq  5 <_start+0x5>
       5:   48 c7 c0 01 00 00 00    mov    $0x1,%rax
       c:   cd 80                   int    $0x80
    

    但是,地址的4个字节做了一个重定位记录:

    $ objdump -r main.o
    main.o:     file format elf64-x86-64
    RELOCATION RECORDS FOR [.text]:
    OFFSET           TYPE              VALUE 
    0000000000000001 R_X86_64_PC32     do_message+0xfffffffffffffffc
    000000000000000d R_X86_64_32       .data
    

    偏移量为“1”,类型为“R_X86_64_PC32”,它告诉链接器解析此引用,并将解析后的地址放入指定的偏移量。

    当您将最终程序与“ld -o program main.o message.o”链接时,所有重定位都已解决,如果没有任何问题未解决,您将得到一个可执行文件。

    当我们'objdump -d'可执行文件时,我们可以看到解析的地址:

    00000000004000f0 <_start>:
      4000f0:   e8 0b 00 00 00          callq  400100 <do_message>
      4000f5:   48 c7 c0 01 00 00 00    mov    $0x1,%rax
      4000fc:   cd 80                   int    $0x80
    

    变量和函数使用相同类型的重定位。 当您将程序与多个大型库(例如 libc)链接时,会发生相同的过程 - 您定义了一个名为“main”的函数,libc 对其有外部引用 - 然后 libc 在您的程序之前启动,并在以下情况下调用您的“main”函数你运行可执行文件。

    【讨论】:

    • asm -> 对象 -> 链接...简洁的小例子。
    • 能否请您解释一下为什么目标文件中的偏移量是 1,以及它是如何计算的?对不起,如果这是一个愚蠢的问题。
    • @gavlaaaaaaaa :在 main.o 中 do_message 重定位引用的偏移量为 1,因为代码从 0 开始,偏移量 0 是操作码 'e8',即指令 'callq',偏移量 1是下一个 32 位值的开始,它是“callq”指令的操作数。
    【解决方案2】:

    简单解释:

    一旦汇编语言被汇编成目标代码,链接器就被用来将目标代码转换成计算机可以理解和运行的可执行命令。生成的机器码可以被 cpu 的控制器解释。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-09-21
      • 1970-01-01
      • 1970-01-01
      • 2019-05-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多