我正在寻找使用汇编程序生成机器代码的简要说明。
所以我知道汇编是机器码的1:1翻译。但我对目标代码和链接器以及它们如何置于其中感到困惑。
我不需要复杂的答案,只需要一个简单的答案就可以了。
答案 0 :(得分:11)
汇编程序和编译器都将源文件转换为目标文件。
目标文件实际上是最终可执行输出(由链接器生成)之前的中间步骤。
链接器获取指定的目标文件和库(它们是目标文件包)并解析重定位(或“fixup”)记录。
当编译器/汇编器不知道源代码中使用的函数或变量的地址时,会生成这些重定位记录,并按名称生成对它的引用,这可以由链接器解析。
例如,假设您希望程序将消息打印到屏幕上,分成两个源文件,并且您希望单独组装它们并链接它们(例如使用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”函数时调用你运行可执行文件。
答案 1 :(得分:1)
简单说明:
将汇编语言组装成目标代码后,链接器将用于将目标代码转换为计算机可以理解和运行的命令的可执行文件。生成的机器代码可以由cpu的控制器解释。