PowerPC TOC 和 SDA

逆向工程 拆卸 登记 电源
2021-06-10 17:45:16

我试图理解TOCSDAin的概念PowerPC

据我了解,它们基本上是指向全局值表的指针,何时TOC存储在r2SDAr13

但是它们之间有什么区别呢?我编译了一个简单的 ppc 项目,我看到只有r2使用了,但r13没有使用。是否应该明确说要使用SDA

此外,我看到我所有的全局字符串实际上根本没有被访问r2看起来r2我的代码中唯一的用途就是访问堆栈变量。是否有意义?

另外,它们应该在哪里初始化?我没有在我的代码中找到任何r2初始化的地方,只是使用了。

1个回答

首先,了解为什么需要这些寄存器的一些背景知识。PPC 是一种类似于 RISC 的 ISA,因为所有指令的大小都相同(32 位),并且用于地址等内容的立即值(通常最多 16 位)的空间有限。那么你如何解决超过 16 位的问题呢?

一种选择是按 16 位切片构建地址,例如:

 lis     r4,msg@ha     # load top 16 bits of &msg
 addi    r4,r4,msg@l   # add bottom 16 bits

另一种是使用 PIC(位置无关代码)来寻址与当前地址相关的事物:

  bcl 20, 4*cr7+so, loc_picbase #branch and link to next location 
loc_picbase:
  mflr      r31 # load link register (lr) into r31. It will be equal to loc_picbase
  addis     r2, r31, (_NXArgc - loc_picbase)@ha
  stw       r28, (_NXArgc - loc_picbase)@l(r2)
  <and so on>

然而,使用其中任何一个都需要每次数据访问多条指令,并且并不总是可行(例如,如果二进制文件需要重新定位,则第一个变体将需要修补指令,而这在运行只读代码时无法完成)。因此,在某些平台上,他们提出了 TOC(目录)的概念,它是一个固定寄存器,对整个模块具有相同的值,并且所有数据都使用偏移量寻址。该寄存器r2是为此目的保留的,AFAIK 应该由 OS 加载程序设置。由于 PPC 指令中的偏移量限制为 16 位(-32768 到 +32767),因此您可以寻址大约 64K 的数据r2(通常放置在数据区域的中间以获得最大的覆盖范围)。如果模块需要更多的数据,大于 16 位的偏移量会分几个步骤构造,或者可以使用多个 TOC(在这种情况下,不同的功能可能使用不同的 TOC)。

在 PPC64 ABI 中,后者是通过所谓的函数描述符实现的,它是一对指针,其中一个是函数代码的地址,另一个是函数期望的 TOC 值。任何时候调用函数时,都会在跳转到函数代码之前从描述符加载 TOC(除非编译器知道目标函数使用相同的 TOC 值,在这种情况下可以跳过 TOC 重新加载)。

在嵌入式环境中,通常没有操作系统,只有一个单片固件,这个概念通过使用寄存器r13SDA(小数据区)和r2额外的数据区(SDA2 -小数据区 2)来应用到整个固件)。所谓的零数据区 (ZDA) 也可用于放置在地址 0 附近的数据(使用寄存器中的特殊寻址模式r0)。

一些编译器(特别是青山)支持额外的数据指针(r14r15等等)。

在嵌入式环境中,数据寄存器(r2r13等)应在启动代码初始化,复位后不久,随着固件的其余部分通常希望他们拥有正确的价值观。

PS 的使用r2取决于环境。您正在编译的目标环境很可能不使用 TOC,因此您没有看到它被使用(PowerPC 上的堆栈指针是r1,而不是r2)。

一些参考: