8

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

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

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

4

2 回答 2

12

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

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

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

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

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

主.asm:

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

消息.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”函数你运行可执行文件。

于 2011-05-29T11:32:06.380 回答
1

简单解释:

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

于 2011-05-29T12:41:00.010 回答