- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我通过在 x86 arch 中静态链接 libc 库为一个简单程序构建了一个可执行文件。该可执行文件的重定位表如预期的那样为空:
$ readelf -r 测试
此文件中没有重定位。
$
当我为同一个程序构建一个可执行文件时,通过静态链接 libc 库,在 x86_64 arch 中,重定位表不为空:
$ readelf -r 测试
偏移量 0x1d8 处的重定位部分“.rela.plt”包含 12 个条目:
偏移信息类型符号。值(value)符号。名称 + 加号
0000006c2058 000000000025 R_X86_64_IRELATIV 000000000042de70
0000006c2050 000000000025 R_X86_64_IRELATIV 00000000004829d0
0000006c2048 000000000025 R_X86_64_IRELATIV 000000000042dfe0
0000006c2040 000000000025 R_X86_64_IRELATIV 000000000040a330
0000006c2038 000000000025 R_X86_64_IRELATIV 0000000000432520
0000006c2030 000000000025 R_X86_64_IRELATIV 0000000000409ef0
0000006c2028 000000000025 R_X86_64_IRELATIV 0000000000445ca0
0000006c2020 000000000025 R_X86_64_IRELATIV 0000000000437f40
0000006c2018 000000000025 R_X86_64_IRELATIV 00000000004323b0
0000006c2010 000000000025 R_X86_64_IRELATIV 0000000000430540
0000006c2008 000000000025 R_X86_64_IRELATIV 0000000000430210
0000006c2000 000000000025 R_X86_64_IRELATIV 0000000000432400
$
我用谷歌搜索了重定位类型“R_X86_64_IRELATIV”,但我可以找到有关它的任何信息。所以有人可以告诉我这是什么意思吗?
我想如果我用 gdb 调试可执行文件,我可能会找到答案。但实际上它带来了很多问题:) 以下是我的分析:
上表中的 Sym.Name 字段列出了一些 libc 函数的虚拟地址。当我 objdump 可执行 'test' 时,我发现虚拟地址 0x430210 包含 strcpy 函数。在加载在位置 0x6c2008 找到的相应 PLT 条目时,它从 0x400326(下一条指令的虚拟地址,即设置解析器)更改为 0x0x443cc0(名为 __strcpy_sse2_unaligned 的 libc 函数的虚拟地址)我不知道为什么它会解析为不同的函数而不是strcpy?我假设它是 strcpy 的不同变体。
完成此分析后,我意识到我错过了前面的基本点“加载静态可执行文件时,动态链接器为什么会出现?”我没有找到 .interp 部分,因此肯定不涉及动态链接器。然后我观察到,一个 libc 函数“__libc_csu_irel()”修改了 PLT 条目而不是动态链接器。
如果我的分析对任何人更有意义,请让我知道这一切。我很乐意知道其背后的原因。
非常感谢!!!
最佳答案
TL; 博士
你是对的。那些重定位只是试图找出应该使用(不仅是)libc 函数的什么实现。它们在 main
之前解决了由函数 __libc_start_main
执行在链接时插入二进制文件。
我将尝试解释这种重定位类型是如何工作的。
这个例子
我正在使用此代码作为引用
//test.c
#include <stdio.h>
#include <string.h>
int main(void)
{
char tmp[10];
char target[10];
fgets(tmp, 10, stdin);
strcpy(target, tmp);
}
使用 GCC 7.3.1 编译
gcc -O0 -g -no-pie -fno-pie -o test -static test.c
重定位表的缩短输出(
readelf -r test
):
Relocation section '.rela.plt' at offset 0x1d8 contains 21 entries:
Offset Info Type Sym. Value Sym. Name + Addend
...
00000069bfd8 000000000025 R_X86_64_IRELATIV 415fe0
00000069c018 000000000025 R_X86_64_IRELATIV 416060
节标题的缩短输出(
readelf -S test
):
[Nr] Name Type Address Offset
Size EntSize Flags Link Info Align
...
[19] .got.plt PROGBITS 000000000069c000 0009c000
0000000000000020 0000000000000008 WA 0 0 8
...
它说
.got.plt
部分在地址
0x69c000
.
void reolve_reloc(uintptr_t* offset, void* (*addend)())
{
//addend is pointer to function
*offset = addend();
}
来自本答案开头的示例。重定位表中的最后一个加数指向地址
0x416060
这是函数
strcpy_ifunc
.查看反汇编的输出:
0000000000416060 <strcpy_ifunc>:
416060: f6 05 05 8d 28 00 10 testb $0x10,0x288d05(%rip) # 69ed6c <_dl_x86_cpu_features+0x4c>
416067: 75 27 jne 416090 <strcpy_ifunc+0x30>
416069: f6 05 c1 8c 28 00 02 testb $0x2,0x288cc1(%rip) # 69ed31 <_dl_x86_cpu_features+0x11>
416070: 75 0e jne 416080 <strcpy_ifunc+0x20>
416072: 48 c7 c0 70 dd 42 00 mov $0x42dd70,%rax
416079: c3 retq
41607a: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1)
416080: 48 c7 c0 30 df 42 00 mov $0x42df30,%rax
416087: c3 retq
416088: 0f 1f 84 00 00 00 00 nopl 0x0(%rax,%rax,1)
41608f: 00
416090: 48 c7 c0 f0 0e 43 00 mov $0x430ef0,%rax
416097: c3 retq
416098: 0f 1f 84 00 00 00 00 nopl 0x0(%rax,%rax,1)
41609f: 00
strcpy_ifunc
选择最好的选择
strcpy
实现 an 返回指针。就我而言,它返回地址
0x430ef0
这是
__strcpy_sse2_unaligned
.这个地址是十放在
0x69c018
这是在
.glob.plt + 0x18
谁和何时解决它
ldd
)。但在这种情况下,程序是静态链接的,
.interp
部分是空的。在这种情况下,它在函数
__libc_start_main
中解析这是 GLIBC 的一部分。除了解决重定位这个函数还负责将命令行参数传递给您的
main
并做一些其他的事情。
__libc_start_main
访问保存在 ELF header 中的重定位表?第一个想法是它以某种方式打开正在运行的二进制文件以进行读取和处理。当然,这是完全错误的。如果您查看可执行文件的程序头,您会看到类似这样的内容 (
readlef -l test
):
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
LOAD 0x0000000000000000 0x0000000000400000 0x0000000000400000
0x0000000000098451 0x0000000000098451 R E 0x200000
...
此 header 中的偏移量是从可执行文件的第一个字节开始的偏移量。所以程序头中的第一项是复制
test
的前 0x98451 个字节。文件存入内存。但是在偏移量 0x0 上是 ELF header 。因此,对于代码段,它还会将 ELF header 加载到内存和
__libc_start_main
中。可以轻松访问它。
关于linker - R_X86_64_IRELATIV 是什么意思?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17404672/
我的makefile的一部分看起来像这样...... ifdef vis flg += -framework GLUT -framework OpenGL -Dvis obj += camfun.o
我正在尝试将 MPI 与 D 编程语言结合使用。 D 完全支持 C ABI,可以链接和调用任何 C 代码。我已经完成了显而易见的工作并将 MPI header 翻译为 D。然后我翻译了 a test
我研究了 makefile 项目。我正在使用 gnu gcc 并作为链接器,我使用带有以下参数的 gcc: linkerCmdLine=$(exe) -Wl,--start-group -nostdl
我尝试使用 FMDB 数据库,但出现错误: Undefined symbols for architecture i386: "_OBJC_CLASS_$_FMDatabase", referen
我想知道“本地链接器符号”和“本地程序变量”之间的区别? 我正在读一本书,里面有这样的: alt text http://img682.imageshack.us/img682/9816/symbol
假设我正在使用 clang 构建和链接我的应用程序 clang -I/usr/local/include -c -o app.o main.c clang -L/usr/local/lib -o ap
我正在从程序员的角度阅读计算机系统,关于链接的章节。它解释了如何使用程序 ld 在 linux x86-64 中进行链接。作者声称,为了从可重定位的目标文件构建可执行文件,链接器做了两件事:符号解析和
所以,这是我发现自己想到的任务。假装一下,我有大量的内容。我想查看哪些网站链接到我的内容。我知道我可以研究 TrackBack 或 PingBack,但是那些不使用能够处理这些问题的工具的人呢? 似乎
我认为 动态加载意味着在加载或运行时将库(或任何其他二进制文件)加载到内存中。所以在下面的程序中,当 dlopen() 调用动态加载器时,它会出现,如果库尚未加载,它会将库加载到内存中。 动态链接是指
我想澄清我对共享库的困惑。当我在网上搜索时,我在对静态链接的解释中发现,由于库包含在可执行文件本身中,因此它会导致更大的可执行文件,从而增加程序的内存占用。 而在动态库/共享库的情况下,库是在运行时链
我正在开发一个嵌入式系统(Stellaris Launchpad)并编写一个简单的操作系统(作为一个爱好项目)。使用的工具链是 gcc-none-eabi。 我的下一步是习惯 MPU 以允许内核阻止用
我正在与 JNI 合作。我有一个包装库 (wrapper.so),它使用两个共享库:one.so 和 two.so 一切正常。所有 *.so 都在 lib 文件夹中,在程序文件夹内。 问题是,如果我将
使用通过“node-gyp”传递的链接器命令行选项,我指定了我希望程序链接的库路径和库名称。但是生成的可执行文件没有引用我指定的文件,它在 /usr/lib 中引用了一个不同的名称。 . 我正在使用
我正在为 AWS lambda 开发 native 节点模块。此节点模块需要 json-c 根据 AWS lambda guidelines节点模块不应具有动态依赖关系。所以尝试链接json-c库的静
我想配置一个自动工具化的项目来调用一个非标准的 链接器( gold linker ), 使用 Linux Mint 16/Ubuntu 13.10 的库存自动工具 我相信我会通过以下方式实现这一目标:
要将可执行文件与位于标准位置的库链接,可以在 CmakeLists.txt 文件中执行以下操作: create_executable(generate_mesh generate_mesh.cpp)
链接描述脚本是否可以访问makefile/shell变量并根据所述变量做出决定? 例如,假设我想在不使用其他链接程序脚本的情况下更改下面RAM区域的开始,是否可以使用make变量来执行此操作? MEM
第三方为我提供了一个静态lib(.a)以便与solaris站链接。 我尝试使用sunpro进行编译,但在链接步骤失败。 我想问题出在我使用的编译器(而不是gcc?)或它的版本(由于编译器提供的std
当我们编译代码时,将生成一个目标文件。在链接过程中,从该目标文件生成一个可执行文件。 为什么我们需要一个目标文件?目标文件有什么用?不可能直接生成可执行文件吗?毕竟,我们使用可执行文件来运行该程序。
我知道头文件包含函数和变量的声明,它们在编译期间帮助判断输入的参数是否有效。 所有的库函数都是默认链接的吗? //#include //#include int main() { printf
我是一名优秀的程序员,十分优秀!