linux - ELF 重定位:有偏移量,但我看不到偏移量的要求
问题描述
我正在尝试了解精灵搬迁,但有几件事我不太了解:
说我有:relamin.c
#include <stdio.h>
#include <stdlib.h>
#include "relafoo.c"
int main() {
int n;
scanf("%d",&n);
printf("\ngot %d, %d!=%d",n,n,factorial(n));
return 0;
}
和 relafoo.c
int factorial(int n) {
if (n == 0 || n == 1) {
return 1;
}
return factorial(n-1)*n;
}
现在在 relamain.o readelf -ri 看到:
000000000027 000900000002 R_X86_64_PC32 0000000000000000 factorial - 4
000000000052 000500000002 R_X86_64_PC32 0000000000000000 .rodata - 4
00000000005c 000c00000004 R_X86_64_PLT32 0000000000000000 __isoc99_scanf - 4
000000000066 000900000002 R_X86_64_PC32 0000000000000000 factorial - 4
- 为什么我有两个相同函数的偏移量(阶乘)
我 objdump -d relamain.o:
0000000000000031 <main>:
31: 55 push rbp
32: 48 89 e5 mov rbp,rsp
35: 48 83 ec 10 sub rsp,0x10
39: 64 48 8b 04 25 28 00 mov rax,QWORD PTR fs:0x28
40: 00 00
42: 48 89 45 f8 mov QWORD PTR [rbp-0x8],rax
46: 31 c0 xor eax,eax
48: 48 8d 45 f4 lea rax,[rbp-0xc]
4c: 48 89 c6 mov rsi,rax
4f: 48 8d 3d 00 00 00 00 lea rdi,[rip+0x0] # 56 <main+0x25>
56: b8 00 00 00 00 mov eax,0x0
5b: e8 00 00 00 00 call 60 <main+0x2f>
60: 8b 45 f4 mov eax,DWORD PTR [rbp-0xc]
63: 89 c7 mov edi,eax
65: e8 00 00 00 00 call 6a <main+0x39>
6a: 89 c1 mov ecx,eax
6c: 8b 55 f4 mov edx,DWORD PTR [rbp-0xc]
6f: 8b 45 f4 mov eax,DWORD PTR [rbp-0xc]
72: 89 c6 mov esi,eax
74: 48 8d 3d 00 00 00 00 lea rdi,[rip+0x0] # 7b <main+0x4a>
7b: b8 00 00 00 00 mov eax,0x0
80: e8 00 00 00 00 call 85 <main+0x54>
85: b8 00 00 00 00 mov eax,0x0
8a: 48 8b 75 f8 mov rsi,QWORD PTR [rbp-0x8]
8e: 64 48 33 34 25 28 00 xor rsi,QWORD PTR fs:0x28
95: 00 00
97: 74 05 je 9e <main+0x6d>
99: e8 00 00 00 00 call 9e <main+0x6d>
9e: c9 leave
9f: c3 ret
查看生成的代码,我发现所有调用都不是指 66 或 27,它们是我的阶乘函数的偏移量,这是为什么呢?根据 Ryan“elfmaster”O'Neill 的“learning linux binary analysis”,我应该期望至少我应该看到
call 66
或者call 27
,有人可以解释一下吗?如果有人可以将我链接到一本好书,该书通过示例(除了 man ofc 之外)详细解释了所有内容动态链接和重定位,那就太好了
解决方案
1-同一功能没有两个偏移量。当必须应用重定位时,您对两个位置有两个偏移量。在您的示例中,您有两次调用函数阶乘。一个在偏移量 0x26 处,另一个在偏移量 0x66 处,并且链接到这些调用的重定位偏移量在偏移量 0x27 和 0x67 处。偏移量 0x27 和 0x66 处的“00000000”将被链接器计算的值替换。您可以肯定地看到可执行文件的转储。
2-创建目标文件时。汇编器不知道factorial
address ,因此它放置“00000000”并放置一个重定位以告诉链接器将这些 0 替换为所需的值,factorial
因为只有链接器会知道它的确切位置。
3- 可能是 John R. Levine 的 Linkers & Loaders。但是我建议你开始阅读http://www.skyfree.org/linux/references/ELF_Format.pdf。也许它就足够了,这取决于你寻求的理解程度。
推荐阅读
- laravel - 如何在 laravel 和 vue 中自动获取身份验证令牌?
- postgresql - 在 k8s 中创建 postgresql 时出现 CreateContainerError
- html - 如何将标题 svg 与导航栏对齐?
- c++ - FilesSearcher 程序 - 程序收到信号 SIGSEGV,分段错误
- reactjs - 如何构建 django + react 项目进行部署?
- java - java - 如何使用Java中的Volley库将JSON api数据放入recyclerview?
- ruby-on-rails - 创建孩子时需要 parent 属性
- installation - 我无法使用 Chocolatey 安装软件包
- python-3.x - 如何使删除反应在 discord.py 中编辑消息?
- python - 用其他列的平均值填充熊猫中的空白