来自我的教科书:
为了在汇编语言程序中生成每个指令的二进制版本,汇编程序必须确定对应于所有标签的地址。汇编程序跟踪分支中使用的标签和符号表中的数据传输指令。如您所料,该表包含符号和地址对。
为什么需要符号表?如果我们有一个带有标签名称和地址的符号表,地址有什么用?地址是什么...只是标签的名称?还是标签的说明?
假设我们在汇编 MIPS 中有这样的指令:
add_numbers:
addi, $s0, $t0, 2
为什么符号表不只存储add_numbers | <the_binary_representation_of_the_instruction>
而不是add_numbers | <address_location_of_label>
?
标签是一个地址,它是程序员向汇编程序提供地址的一种方式,但不必知道物理地址。 让工具链为您完成这项工作。
我不记得我的MIPS了,所以这里有一些伪代码。
loop_top:
nop
nop
sub r0,1
cmp r0,0
bne loop_top
取决于指令集,但通常条件分支将是相对于 pc 的。 在组装过程中通常使用的表,表上有一个或多个刀路将解析分支和目标之间的距离,以便可以完全对分支进行编码。 上述大多数指令集都可以一次性解决。 loop_top是一个具有地址的标签,但对于这里的分支,它是相对于 PC 的,您不需要知道物理地址。
但
call my_fun
一旦对代码进行传递,汇编程序就会发现此文件中未定义my_fun和/或汇编语言在使用之前有一些语法将其标记为外部。 无论哪种方式,它都是外部的。 在组装此文件时无法解析。 因此,需要指示标签名称的表,以及指令在此对象中的位置,根据汇编程序,它可能会暂时将临时偏移量或完整地址填充为零,或者将其编码为无限循环。
链接器稍后确定处理器内存空间中事物的实际地址,链接器最终将有一个包含所有(工具链此阶段的相关标签(标签及其链接地址的表,然后链接器将返回到代码中并修复/创建此调用指令的机器代码,因为它知道该标签的实际地址是什么。
j hello
对象:
Disassembly of section .text:
00000000 <.text>:
0: 08000000 j 0x0
4: 00000000 nop
另一个对象:
.globl hello
hello:
j hello
.word hello
链接它们
Disassembly of section .text:
00001000 <_ftext>:
1000: 08000402 j 1008 <hello>
1004: 00000000 nop
00001008 <hello>:
1008: 08000402 j 1008 <hello>
100c: 00000000 nop
1010: 00001008 0x1008
作为对象,所有工具链都必须继续使用标签hello作为稍后解析的地址。 在这种情况下,在链接时,链接器通过对象工作,对字节进行计数,形成标签及其地址表。 在第一次或其他一些过程中,它将根据需要更改指令或数据以解析这些标签。
现在老式汇编程序完成了从同一源文件组装和链接的工作,声明"汇编程序必须确定对应于所有标签的地址"。 通常,使用常用工具链的汇编程序不是执行链接器工作。 因此,引用的声明可以使用一些改进。 但希望这表明标签是地址,它们代表尚未确定的地址,因此代码比这样的东西更容易编写
nop
nop
j pc-2
然后,如果您添加另一条指令
nop
add r0,r1
nop
j pc-3
或
j 0x1008
然后必须花费大量时间重写程序,以将每个地址硬编码到程序中。 添加/删除一行,并且必须更改许多其他代码。 代表地址的标签使这一切变得更加容易,工具链确定地址,然后返回并基本上用地址替换标签......
添加了一个nop:
Disassembly of section .text:
00001000 <_ftext>:
1000: 08000403 j 100c <hello>
1004: 00000000 nop
1008: 00000000 nop
0000100c <hello>:
100c: 08000403 j 100c <hello>
1010: 00000000 nop
1014: 0000100c
如果我们没有标签并且必须对地址进行硬编码,那么您将不得不更改这三个位置,因为 nop。 一行。如果你添加几十行,几百行。 您将如何跟踪这一切? 通过在评论中贴标签? 一遍又一遍地组装、拆卸和修补源代码,直到它看起来有点正确,并希望没有错误。
mips-elf-readelf -s so.elf
Symbol table '.symtab' contains 14 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 00000000 0 NOTYPE LOCAL DEFAULT UND
1: 00001000 0 SECTION LOCAL DEFAULT 1
2: 00400000 0 SECTION LOCAL DEFAULT 2
3: 00400018 0 SECTION LOCAL DEFAULT 3
4: 00000000 0 SECTION LOCAL DEFAULT 4
5: 0000a010 0 NOTYPE LOCAL DEFAULT 2 _gp
6: 00002018 0 NOTYPE GLOBAL DEFAULT 4 _fdata
7: 0000100c 0 OBJECT GLOBAL DEFAULT 1 hello
8: 00001000 0 NOTYPE GLOBAL DEFAULT 1 _ftext
9: 00000000 0 NOTYPE GLOBAL DEFAULT UND _start
10: 00002018 0 NOTYPE GLOBAL DEFAULT 2 __bss_start
11: 00002018 0 NOTYPE GLOBAL DEFAULT 2 _edata
12: 00002018 0 NOTYPE GLOBAL DEFAULT 2 _end
13: 00002018 0 NOTYPE GLOBAL DEFAULT 2 _fbss
这是感兴趣的一个:
7: 0000100c 0 OBJECT GLOBAL DEFAULT 1 hello
标签 hello 一旦组装并链接到最终二进制文件,就等于地址0x100C。