首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >对象文件的重定位表中项的含义

对象文件的重定位表中项的含义
EN

Stack Overflow用户
提问于 2018-09-07 04:51:22
回答 1查看 1.7K关注 0票数 7

我在理解从C源文件编译的重新定位表的条目时遇到了一些问题。我的节目如下:

代码语言:javascript
运行
复制
//a.c
extern int shared;
int main(){
    int a = 100;
    swap(&a, &shared);
    a = 200;
    shared = 1;
    swap(&a, &shared);
}
//b.c
int shared = 1;
void swap(int* a, int* b) {
    if (a != b)
        *b ^= *a ^= *b, *a ^= *b;
}

我用以下命令gcc -c -fno-stack-protector a.c b.cld a.o b.o -e main -o ab编译并链接它们。然后我用objdump -r a.o检查它的重新定位表。

代码语言:javascript
运行
复制
RELOCATION RECORDS FOR [.text]:
OFFSET           TYPE              VALUE 
0000000000000014 R_X86_64_32       shared
0000000000000021 R_X86_64_PC32     swap-0x0000000000000004
000000000000002e R_X86_64_PC32     shared-0x0000000000000008
000000000000003b R_X86_64_32       shared
0000000000000048 R_X86_64_PC32     swap-0x0000000000000004

a.o的反汇编是

代码语言:javascript
运行
复制
Disassembly of section .text:

0000000000000000 <main>:
0:  55                      push   %rbp
1:  48 89 e5                mov    %rsp,%rbp
4:  48 83 ec 10             sub    $0x10,%rsp
8:  c7 45 fc 64 00 00 00    movl   $0x64,-0x4(%rbp)
f:  48 8d 45 fc             lea    -0x4(%rbp),%rax
13: be 00 00 00 00          mov    $0x0,%esi
18: 48 89 c7                mov    %rax,%rdi
1b: b8 00 00 00 00          mov    $0x0,%eax
20: e8 00 00 00 00          callq  25 <main+0x25>
25: c7 45 fc c8 00 00 00    movl   $0xc8,-0x4(%rbp)
2c: c7 05 00 00 00 00 01    movl   $0x1,0x0(%rip)  # 36 <main+0x36>
33: 00 00 00 
36: 48 8d 45 fc             lea    -0x4(%rbp),%rax
3a: be 00 00 00 00          mov    $0x0,%esi
3f: 48 89 c7                mov    %rax,%rdi
42: b8 00 00 00 00          mov    $0x0,%eax
47: e8 00 00 00 00          callq  4c <main+0x4c>
4c: b8 00 00 00 00          mov    $0x0,%eax
51: c9                      leaveq 
52: c3                      retq  

我的问题是: 14的shared和2e的shared都是完全相同的物体。为什么他们有不同的符号名?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-09-11 20:53:05

这是相同的地址,但重新定位类型是不同的。重新定位类型是在x86-64-abi中定义的。

有什么关系?

0x140x3b:为了调用函数swap,必须将全局变量shared的地址移动到注册%rsi

但是,由于程序是用-mcmodel=small编译的(默认为gcc,参见这个问题),编译器可以假设地址符合32位,使用movl而不是movq (实际上编译器会使用其他指令,但将movl与“朴素”movq进行比较可以很好地解释差异),这需要更多的字节进行编码。

因此,重新定位的结果是R_X86_64_32 (即64位地址被截断为32位,没有符号扩展名),而不是R_X86_64_64,即链接器将写入4个较低的地址字节,而不是占位符,占位符也是4个字节宽。

0x2e,您希望将值1写入内存地址shared。然而,目标地址是相对于%rip的,即相对于0x36的。

代码语言:javascript
运行
复制
movl   $0x1,0x0(%rip)  # 36 <main+0x36>

显然,仅仅将shared的绝对地址通过R_X86_64_32并不会有任何好处--需要更复杂的计算,这就是R_X86_64_PC32的目的。

再一次,由于编译器可以假设的小代码模型,32位相对偏移量就足够了(因此使用了重定位R_X86_64_PC32而不是R_X86_64_PC64 ),占位符只有4个字节宽。

根据x86-64-abi的规定,搬迁的公式是(4.4节):

代码语言:javascript
运行
复制
result = S+A-P (32bit-word, i.e. the lower 4 bytes of the result) 
S = the value of the symbol whose index resides in the relocation entry 
A = the addend used to compute the value of the relocatable field 
P = the place (section offset or address) of the storage unit being relocated (computed using r_offset)

这意味着:

  • Sshared变量的地址。
  • A-8 (例如,可以通过调用readelf -r a.oobjdump -r a.o来查看),因为重定位0x2e的偏移量与实际的%rip - 0x36之间存在8字节的差异。
  • P是重定位的偏移量,即0x26P-A%rip中的地址。

正如您所看到的,结果不是像上面的S那样是R_X86_64_32,而是S - (P-A)。它也可以在生成的二进制文件中看到--对于这两种不同的重新定位类型,不同的值将在占位符上进行修补。

那里是Eli关于这个主题的一篇很棒的文章。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/52215495

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档