从我的教科书上:
要在汇编语言程序中生成每个指令的二进制版本,汇编程序必须确定与所有标签相对应的地址。汇编器在符号表中跟踪分支中使用的标签和数据传输指令。如您所料,该表包含符号和地址对。
为什么需要符号表?如果我们有一个带有标签名称和地址的符号表,该地址的用途是什么?地址是什么...只是标签的名称?还是标签上的说明?
说我们在汇编MIPS中有这样一条指令:
add_numbers:
addi, $s0, $t0, 2
为什么符号表不只存储add_numbers | <the_binary_representation_of_the_instruction>
而不是add_numbers | <address_location_of_label>
?
答案 0 :(得分:2)
标签是一个地址,它是程序员为汇编器提供地址但不必知道物理地址的一种方式。让工具链为您完成这项工作。
我不记得我的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