根据Assemblers And Loaders(一本24年前关于装配工如何运作的书):
...单程汇编程序无法生成可重定位目标文件。该 可以确定指令的类型(绝对或可重定位) 只能通过检查原始来源指令。一次通过 汇编程序将机器指令直接加载到内存中。曾在 内存,指令只是一个数字。通过看一台机器 在记忆中的指令,是不可能分辨原来的 指令是绝对的或可重新定位的。
本书给出了以下可重定位和绝对指令的伪代码:
JMP TO
...
TO: ADD 1,2
第一条指令使用符号TO
,第二条指令将寄存器“1”中的值相加,并注册“2”。
据我了解,您不需要源代码就知道第一条指令的机器代码是可重定位的。应该可以使用操作码表来确定它是JMP
指令,并且它必须跳转到需要可重定位的地址。
我的假设是否正确?
背景:虽然这本书很旧,但我正在阅读它,可以更好地理解6502和65816等旧CPU的装配。
答案 0 :(得分:2)
你的书是误导性的,一个单程汇编程序,因为大多数人都会理解这个术语,可以通过发出称为重定位的特殊数据来生成可重定位目标文件,这些数据告诉链接器/加载器如何重定位代码。本书似乎使用了“一次通过汇编程序”的特定定义,这种定义通过其自己的定义无法输出具有重定位的“可重定位目标文件”。
然而,一般情况下,您无法确定给定的机器代码指令是否可重定位,除非有一组可用的重定位来说明什么是可重定位的(以及如何重新定位非重定位的指令) )。某些指令显而易见,例如,您可以根据目标地址的编码方式判断JMP TO
指令是否可重定位。如果目标地址被编码为JMP指令地址的相对偏移量,那么它是可重定位的。另一方面,如果编码为绝对地址,则指令不可重定位。在第一种情况下,程序可以在没有修改的情况下重新定位到内存中,JMP指令仍将跳转到相同的代码。在第二种情况下,JMP指令将始终跳转到相同的地址,无论代码何处被重定位,除非指令被更改为跳转到正确的位置。
在x86程序集中,第一种情况的具体示例如下:
0056: EB 10 JMP LO
指令中的第一个字节是操作码EB
(我在这里使用的数字都是十六进制的),表示具有8位相对偏移的近JMP指令。指令中的第二个字节是8位相对偏移量。它实际上是相对于以下指令的开头,因此地址跳转到0056 + 2 + 10
或0068
。
在6502汇编中,第二种情况的例子是:
0056: 4C 68 00 JMP LO
在这种情况下,操作码字节4C
表示JMP指令,该指令使用2字节绝对地址编码到指令中。接下来的两个字节以小端字节顺序组成该地址:0068
。
另一个简单的例子是ADD 1,2
,它只使用寄存器。由于没有涉及地址,因此指令可以在不进行修改的情况下重新定位,因为指令中没有编码地址。问题在于ADD #1000,2
之类的指令,它将文字值1000添加到寄存器2中存储的值。在这种情况下,数字1000在指令中编码,并且无法知道该数字是否被使用作为地址与否。脱离上下文,无法知道指令中是否包含编码地址。
16位x86汇编语言中的ADD #1000,2
示例如下:
0068: 81 C3 EB 03 ADD BX, 1000
指令EB 03
的最后两个字节是十进制值1000,是指令的立即(文字)操作数的编码位置。该指令将1000添加到BX寄存器。如果没有更多的上下文,就不可能知道1000是否应该是一个地址。例如,代码可能会计算位于从地址1000开始的表中的某些内容的地址。
你可能想找另一本书,因为它似乎花了很多时间来处理24年前已经过时的机器架构,并且今天完全过时了。