重定位表项在平面二进制文件中的存储位置

Where Are Relocation Entries Stored in Flat Binaries?

本文关键字:存储 位置 二进制文件 平面 定位      更新时间:2023-10-16

请注意下面的例子。我有一个c++代码,我想在powerpc下编译并生成二进制代码。

#include <stdio.h>
int function(int x);
int myfunction(int x);
int main() 
{
    int x = function(2);
    int y = myfunction(2);
    return x + y;
}
int function(int x)
{
    return x * myfunction(x);
}
int myfunction(int x)
{
    return x;
}

我有两个函数调用:call function(2)call myfunction(2)。我在powerpc‍‍‍下编译这个c++代码。所以,现在我使用objdump来获取目标文件后面的程序集,如下所示:

00000000 <main>:
   0:   94 21 ff e0     stwu    r1,-32(r1)
   4:   7c 08 02 a6     mflr    r0
   8:   93 e1 00 1c     stw r31,28(r1)
   c:   90 01 00 24     stw r0,36(r1)
  10:   7c 3f 0b 78     mr  r31,r1
  14:   38 60 00 02     li  r3,2
  18:   48 00 00 01     bl  18 <main+0x18>
  1c:   7c 60 1b 78     mr  r0,r3
  20:   90 1f 00 08     stw r0,8(r31)
  24:   38 60 00 02     li  r3,2
  28:   48 00 00 01     bl  28 <main+0x28>
  2c:   7c 60 1b 78     mr  r0,r3
  30:   90 1f 00 0c     stw r0,12(r31)
  34:   80 1f 00 08     lwz r0,8(r31)
  38:   81 3f 00 0c     lwz r9,12(r31)
  3c:   7c 00 4a 14     add r0,r0,r9
  40:   7c 03 03 78     mr  r3,r0
  44:   48 00 00 0c     b   50 <main+0x50>
  48:   38 60 00 00     li  r3,0
  4c:   48 00 00 04     b   50 <main+0x50>
  50:   81 61 00 00     lwz r11,0(r1)
  54:   80 0b 00 04     lwz r0,4(r11)
  58:   7c 08 03 a6     mtlr    r0
  5c:   83 eb ff fc     lwz r31,-4(r11)
  60:   7d 61 5b 78     mr  r1,r11
  64:   4e 80 00 20     blr
00000068 <function__Fi>:
  68:   94 21 ff e0     stwu    r1,-32(r1)
  6c:   7c 08 02 a6     mflr    r0
  70:   93 e1 00 1c     stw r31,28(r1)
  74:   90 01 00 24     stw r0,36(r1)
  78:   7c 3f 0b 78     mr  r31,r1
  7c:   90 7f 00 08     stw r3,8(r31)
  80:   80 7f 00 08     lwz r3,8(r31)
  84:   48 00 00 01     bl  84 <function__Fi+0x1c>
  88:   7c 60 1b 78     mr  r0,r3
  8c:   81 3f 00 08     lwz r9,8(r31)
  90:   7c 00 49 d6     mullw   r0,r0,r9
  94:   7c 03 03 78     mr  r3,r0
  98:   48 00 00 0c     b   a4 <function__Fi+0x3c>
  9c:   48 00 00 08     b   a4 <function__Fi+0x3c>
  a0:   48 00 00 04     b   a4 <function__Fi+0x3c>
  a4:   81 61 00 00     lwz r11,0(r1)
  a8:   80 0b 00 04     lwz r0,4(r11)
  ac:   7c 08 03 a6     mtlr    r0
  b0:   83 eb ff fc     lwz r31,-4(r11)
  b4:   7d 61 5b 78     mr  r1,r11
  b8:   4e 80 00 20     blr
000000bc <myfunction__Fi>:
  bc:   94 21 ff e0     stwu    r1,-32(r1)
  c0:   93 e1 00 1c     stw r31,28(r1)
  c4:   7c 3f 0b 78     mr  r31,r1
  c8:   90 7f 00 08     stw r3,8(r31)
  cc:   80 1f 00 08     lwz r0,8(r31)
  d0:   7c 03 03 78     mr  r3,r0
  d4:   48 00 00 04     b   d8 <myfunction__Fi+0x1c>
  d8:   81 61 00 00     lwz r11,0(r1)
  dc:   83 eb ff fc     lwz r31,-4(r11)
  e0:   7d 61 5b 78     mr  r1,r11
  e4:   4e 80 00 20     blr

让我感到奇怪的是做函数调用的那一行:

  18:   48 00 00 01     bl  18 <main+0x18>
  ...
  28:   48 00 00 01     bl  28 <main+0x28>

如您所见,两者都是二进制代码"48 00 00 01",但一个调用function,另一个调用myfunction。问题是我们怎样才能找到call target。正如我所发现的,调用目标写在RELOCATION ENTRIES上。哦,一切正常,我使用下面的命令来生成重定位表项,如下所示:

RELOCATION RECORDS FOR [.text]:
OFFSET   TYPE              VALUE 
00000018 R_PPC_REL24       function__Fi
00000028 R_PPC_REL24       myfunction__Fi
00000084 R_PPC_REL24       myfunction__Fi

这些条目对于查找调用目标很有用。现在,我使用objcopy -O binary命令生成原始二进制文件(平面二进制文件)。

objcopy -O binary object-file
我的object-fileelf32-powerpc。输出二进制文件如下块所示:
2564 0000 2564 0a00 93e1 001c 9001 0024
7c3f 0b78 3860 0002 4800 0001 7c60 1b78
901f 0008 3860 0002 4800 0001 7c60 1b78
901f 000c 801f 0008 2c00 0002 4182 003c
2c00 0002 4181 0010 2c00 0001 4182 0014
4800 0058 2c00 0003 4182 0038 4800 004c
3d20 0000 3869 0000 389f 0008 4cc6 3182
4800 0001 4800 004c 3d20 0000 3869 0004
3880 0014 4cc6 3182 4800 0001 4800 0034
3d20 0000 3869 0004 3880 001e 4cc6 3182
4800 0001 4800 001c 3d20 0000 3869 0004
3880 0028 4cc6 3182 4800 0001 4800 0004
3860 0000 4800 0004 8161 0000 800b 0004
7c08 03a6 83eb fffc 7d61 5b78 4e80 0020
9421 ffe0 7c08 02a6 93e1 001c 9001 0024
7c3f 0b78 907f 0008 807f 0008 4800 0001
7c60 1b78 813f 0008 7c00 49d6 7c03 0378
4800 000c 4800 0008 4800 0004 8161 0000
800b 0004 7c08 03a6 83eb fffc 7d61 5b78
4e80 0020 9421 ffe0 93e1 001c 7c3f 0b78
907f 0008 801f 0008 7c03 0378 4800 0004
8161 0000 83eb fffc 7d61 5b78 4e80 0020

我们可以在上面找到4800 0001。但是没有relocation entries。谁能告诉我怎么才能找到relocation entries ?

当您执行objcopy时,您的重定位项将被丢弃。从手册:

objcopy可用于通过输出生成原始二进制文件目标的二进制(例如,使用-O二进制)。当objcopy生成raw二进制文件,它将生成内容的内存转储输入对象文件的。所有符号和重定位信息将被丢弃。内存转储将从对象的加载地址开始将最低部分复制到输出文件中。

要使原始二进制文件有用,这里有几个选项:

您可以在构建过程中执行重定位,以便您的原始二进制文件准备好运行。但是,这意味着二进制文件需要在内存中的固定地址运行。

或者,您可以生成一个不需要重定位的对象文件——所有的地址引用都需要是相对的。查看"位置无关代码"获取更多详细信息。

最后,您还可以使用其他方式生成原始二进制文件(而不是objcopy阶段),其中包括输出文件中的重定位表,然后让您的代码在运行时手动处理这些重定位。

这里的选择取决于你想做什么,以及你的运行时环境有什么限制。