你能从机器代码中判断一条指令是否可重定位吗?

Mic*_*out 4 assembly

根据《Assemblers And Loaders》(一本有 24 年历史的关于汇编程序如何工作的书):

...一次性汇编器无法生成可重定位目标文件。指令的类型(绝对指令或可重定位指令)只能通过检查原始源指令来确定。一次性汇编器将机器指令直接加载到内存中。一旦进入内存,指令就只是一个数字。通过查看内存中的机器指令,无法判断原始指令是绝对指令还是可重定位指令。

书中给出了以下可重定位指令和绝对指令的伪代码:

    JMP TO
    ...
TO: ADD 1,2
Run Code Online (Sandbox Code Playgroud)

其中第一条指令使用符号TO,第二条指令将寄存器“​​1”和寄存器“2”中的值相加。

据我了解,您不需要源代码就知道第一条指令的机器代码是可重定位的。应该可以使用操作码表来确定它是指令JMP并且它必须跳转到需要可重定位的地址。

我的假设正确吗?

背景:虽然这本书很旧,但我通过阅读它可以更好地了解 6502 和 65816 等旧 CPU 的汇编。

Ros*_*dge 5

您的书具有误导性,正如大多数人所理解的那样,一次性汇编器可以通过发出称为重定位的特殊数据来生成可重定位的目标文件,这些数据告诉链接器/加载器如何重定位代码。这本书似乎使用了“一次性汇编程序”的特定定义,根据其自己的定义,该汇编程序无法输出带有重定位的“可重定位目标文件”。

然而,确实,一般来说,您无法判断给定的机器代码指令是否可重定位,除非有一组重定位可用于判断什么是可重定位的或不可重定位的(以及如何重定位不可重定位的指令)。某些指令使其显而易见,例如,您可以JMP TO根据目标地址的编码方式来判断指令是否可重定位。如果目标地址被编码为 JMP 指令地址的相对偏移量,那么它是可重定位的。另一方面,如果编码为绝对地址,则指令不可重定位。在第一种情况下,程序可以在内存中重定位而无需修改,并且 JMP 指令仍然会跳转到相同的代码。在第二种情况下,JMP 指令将始终跳转到相同的地址,无论代码已重定位到何处,除非将指令更改为跳转到正确的位置。

在 x86 汇编中,第一种情况的具体示例如下:

0056: EB 10     JMP LO
Run Code Online (Sandbox Code Playgroud)

指令中的第一个字节是操作码EB(我在这里使用的数字都是十六进制的),它表示具有 8 位相对偏移量的近 JMP 指令。指令中的第二个字节是 8 位相对偏移量。它实际上是相对于下一条指令的开始位置的,因此跳转到的地址是0056 + 2 + 10or 0068

在 6502 汇编中,第二种情况的示例是:

0056: 4C 68 00   JMP LO
Run Code Online (Sandbox Code Playgroud)

在这种情况下,操作码字节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
Run Code Online (Sandbox Code Playgroud)

指令的最后两个字节EB 03是十进制值 1000,也是指令的立即(文字)操作数的编码位置。该指令将 1000 添加到 BX 寄存器。如果没有更多上下文,就不可能知道 1000 是否应该是一个地址。例如,代码可能会计算位于从地址 1000 开始的表中的某个内容的地址。

你可能想找另一本书,因为它似乎花了很多时间来讨论 24 年前就已经过时的机器架构,而在今天已经完全过时了。