【问题标题】:Can you tell from machine code if an instruction is relocatable?你能从机器代码中判断一条指令是否可重定位吗?
【发布时间】:2017-02-09 20:43:18
【问题描述】:

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

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

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

    JMP TO
    ...
TO: ADD 1,2

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

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

我的假设正确吗?

背景:虽然这本书很旧,但我正在阅读它以更好地了解 6502 和 65816 等旧 CPU 的组装。

【问题讨论】:

  • 真的和你的其他问题没有什么不同。那本书谈到了可重定位的位是吗?那将是机器代码。对于一般的其他指令集,地址是加载到寄存器然后分支到因为它是外部地址还是仅仅因为作者或编译器是这样做的? (与使用 pc 相对偏移量相比)
  • 我在想也许你应该停止阅读那本书。获取一个 gnu 工具链(最好是除 x86、arm、mips 之外的任何工具链,都是不错的选择),然后编译、反汇编然后链接和反汇编,然后思考甚至编写自己的工具(汇编器然后链接器)以查看问题是如何出现或可能出现的解决了。​​

标签: assembly


【解决方案1】:

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

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

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

0056: EB 10     JMP LO

指令中的第一个字节,是操作码EB(我这里使用的数字都是十六进制的),表示一个near JMP指令,相对偏移量为8位。指令中的第二个字节是 8 位相对偏移量。它实际上是相对于下面指令的开始,所以跳转到的地址是0056 + 2 + 100068

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

0056: 4C 68 00   JMP LO

在这种情况下,操作码字节4C 表示一条 JMP 指令,该指令使用 2 字节绝对地址编码到指令中。接下来的两个字节以 little-endian 字节顺序组成该地址: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 年前已经过时并且今天完全过时的机器架构。

【讨论】:

  • 感谢您的解释!我认为在您的答案的第二部分中缺少一些单词,您可以校对以确保它是正确的吗? (“既然有 >no?can be?no?
  • 关于最后一个示例,我希望指令字节指示EB 03 是要添加到 BX 的立即值还是应该获取要添加到 BX 的值的地址从。 CPU 怎样才能正确执行这些指令?
  • @MichielvanOosterhout 在最后一个示例中,我没有解释如何解码操作码和其他操作数,因为它比其他示例更复杂,可能会造成混淆。第一个字节81 表示它是立即数组 1 指令,具有 16 位目标操作数和 16 位立即数操作数。第二个字节C3 表示它是一条 ADD 指令,目标操作数是 BX。我已经编辑了你提到的问题句。
  • 但是解码是相关的,因为字节表明指令的第一个操作数是内存中的位置这一事实可用于确定在重定位代码时需要更改操作数。考虑到这一点,我仍然不明白你为什么写“但是,通常你无法判断给定的机器代码指令是否可重定位,除非有一组重定位可用于判断什么是或不是可重定位”。
  • @MichielvanOosterhout 你错了。在我的最后一个示例中,指令编码中没有字节表明第一个操作数是内存中的一个位置。第一个操作数是寄存器 BX,它不是内存中的位置。执行指令时,该寄存器可能包含也可能不包含地址,但这无关紧要。第一个操作数的值没有在指令本身中编码,因此不能通过修改指令来更改,也不应该更改。这是第二个操作数,它的值被编码在指令中,这就是问题所在。
猜你喜欢
  • 2011-11-20
  • 2013-01-27
  • 2016-06-06
  • 2016-11-02
  • 2023-04-02
  • 1970-01-01
  • 2019-09-01
  • 1970-01-01
  • 2016-09-25
相关资源
最近更新 更多