我试图更好地理解 Linux 中的运行时重定位,特别是谁在不同情况下执行它们。以下是我目前的理解,是否准确?
ld.so) 加载库,然后执行重定位ld.so是一个自重定位的二进制文件谢谢
我目前很难理解链接/加载概念。
您能告诉我以下关于符号和重定位表的使用的陈述是否正确?
谢谢你的时间!
是否可以将代码中的某些功能移动到可执行文件的特定部分中?如果是这样,如何?
对于使用 gcc 编译的应用程序,我们有更多的源文件,包括 Xc 每个对象都是从关联的源(Xo 是从 Xc 获得的)编译的,并且链接器生成一个大的可执行文件。
我需要来自 Xc 的两个函数位于可执行文件的特定部分,例如 .magic_section。我想要这个的原因是该部分将被加载到另一个内存区域而不是其余部分。
我的问题是我不能更改源 Xc,否则我会使用特定的标志,例如__attribute__ ((section ("magic_section")))函数。
我在链接器的文档中阅读了一些内容并为链接器编写了一个自定义脚本,但是我没有指定必须将特定符号放置在哪个部分。我只设法移动了整个部分。
我有一个带有两个绝对符号的内核的链接描述文件:_kernel_start和_kernel_end.但是,我只收到链接器重定位错误_kernel_end:
In function `kernel::mem::mm::setup_memorymap':
/home/virtlink/kernel/src/mem/mm.rs:25:(.text._ZN3mem2mm15setup_memorymap):
relocation truncated to fit: R_X86_64_PC32 against symbol `_kernel_end'
defined in *ABS* section in ./kernel.bin
Run Code Online (Sandbox Code Playgroud)
这里有很多关于这个错误的问题,但我没有找到解决我特定问题的问题.
显然,这个:
_kernel_start = .;
Run Code Online (Sandbox Code Playgroud)
...被视为32位,而这:
. += KERNEL_BASE;
_kernel_end = . - KERNEL_BASE;
Run Code Online (Sandbox Code Playgroud)
...被视为64位.如果我将_kernel_end符号移动到. += KERNEL_BASE线上方,如下所示:
_kernel_end = .;
. += KERNEL_BASE;
Run Code Online (Sandbox Code Playgroud)
......然后再次运作.但我想_kernel_end在我的链接器脚本的末尾.
链接描述文件将引导代码放在内存开头,其余代码放在64位虚拟内存空间的上半部分.它看起来像这样:
OUTPUT_FORMAT(elf64-x86-64)
KERNEL_BASE = 0xFFFFFFFF80000000;
SECTIONS
{
/* Boot code at 1 MiB */
. = 1M;
_kernel_start = .;
.boot :
{
KEEP( *(.multiboot) …Run Code Online (Sandbox Code Playgroud) 我注意到使用-r部分链接实际上并没有解决任何重定位问题,即使它们可以通过相对寻址解决。例如,考虑f.o并g.o与f.o含f()这就要求g()内g.o。在链接之前,拆卸和重定位按预期进行。然而,在部分链接到一个新文件h.o(通过ld -r -o h.o f.o g.o)之后,仍然存在对调用的重定位g(),即使理论上它可以用相对地址解析。
这是h.o( objdump -d h.o)的反汇编,包含f()和g()。您可以看到对 的调用g()仍未解决:
h.o: file format elf64-x86-64
Disassembly of section .text:
0000000000000000 <f>:
0: 55 push %rbp
1: 48 89 e5 mov %rsp,%rbp
4: e8 00 00 00 00 callq 9 <f+0x9>
9: 90 nop
a: 5d pop %rbp
b: c3 retq
000000000000000c …Run Code Online (Sandbox Code Playgroud) 我尝试用汇编语言创建函数并将它们放在动态库中,因此我使用此命令创建带有.S的.o
nasm -f elf64 hello.S -o hello.o
但是当我想用gcc创建lib时:
gcc -fPIC -shared hello.o -o libasm.so
它会显示以下错误:
/usr/bin/ld: hello.o: relocation R_X86_64_PC32 against undefined symbol printf@@GLIBC_2.2.5 can not be used when making a shared object; recompile with -fPIC
我目前有一个名为LIBS的项目,其结构如下:
??? Lib1
? ??? CMakeLists.txt
? ??? lib1-class.cpp
? ??? lib1-class.h
??? lib2
? ??? CMakeLists.txt
? ??? lib2-class.cpp
? ??? lib2-class.h
??? cmake
? ??? LIBSConfig.cmake.in
??? CMakeLists.txt
Run Code Online (Sandbox Code Playgroud)
在主cmake文件中,我有:
install(
TARGETS
lib1
lib2
DESTINATION
${PROJECT_DIRNAME_lib}
EXPORT
${PROJECT_NAME}Exports
)
install(
EXPORT
${PROJECT_NAME}Exports
DESTINATION
${PROJECT_DIRNAME_lib}
)
Run Code Online (Sandbox Code Playgroud)
因为我想将它们导出到find_package()可以发现的包中.
我的问题是我生成lib1并lib2在各自的目录中安装它们时,Cmake告诉我
Error:install TARGETS given target "lib1" which does not exist in this directory.
Run Code Online (Sandbox Code Playgroud)
正如这里所建议的,我的理解是我应该Export()在lib1和lib2中使用以下形式的东西:
export(TARGETS lib1 FILE lib1Exports.cmake)
Run Code Online (Sandbox Code Playgroud)
在LIBS项目中,有这样的事情:
ADD_LIBRARY(lib1 UNKNOWN …Run Code Online (Sandbox Code Playgroud) 我在理解从 C 源文件编译的重定位表的条目时遇到了一些问题。我的程序如下:
//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;
}
Run Code Online (Sandbox Code Playgroud)
我使用以下命令gcc -c -fno-stack-protector a.c b.c和ld a.o b.o -e main -o ab. 然后我objdump -r a.o检查它的重定位表。
RELOCATION RECORDS FOR [.text]:
OFFSET TYPE VALUE
0000000000000014 R_X86_64_32 shared
0000000000000021 R_X86_64_PC32 …Run Code Online (Sandbox Code Playgroud) 我正在尝试为准系统ARM应用程序创建一个简单的链接器。当前,加载模块的加载器只会将偏移量添加到.got和.data.rel部分中的所有记录中。这适用于.got所有需要重定位的符号.data.rel。对于所有不可重定位的数据,它都会中断,因为那些数据也将获得此偏移量。
例:
void some_function() { return; }
struct a {
void* fptr;
int number;
};
static struct a = {
.fptr = some_function,
.number = 0x1000,
};
Run Code Online (Sandbox Code Playgroud)
此处a.fptr将正确解决该函数的实际位置,但a.number将错误地保持0x1000 + offset,而不是0x1000。
我应该如何区分两者?.symtab仅检查该部分并仅重定位在此找到的地址就足够了吗?但是,如果符号实际上位于该位置0x1000怎么办?还是链接程序解决了这个问题(因此它将不会在address放置函数0x1000)?.symtabs实际上是否包含在.got和中可以找到的所有符号.data.rel?
在手册页中nm。它说
\n\n\n\xe2\x80\x9cA\xe2\x80\x9d 符号的值是绝对的,不会因进一步链接而改变。
\n
但是,我不知道这意味着什么。如何在 C 中定义一个变量或其他东西以使其值绝对?
\n\ntest.c如果我在其文件范围内声明一个变量
int a;\nRun Code Online (Sandbox Code Playgroud)\n\n然后在 的输出中nm,a 的条目在我的机器上将如下
int a;\nRun Code Online (Sandbox Code Playgroud)\n\n所以我想知道我该怎么做才能使nm变量的输出 \xe2\x80\x9cA\xe2\x80\x9d 。而且我不知道 \xe2\x80\x9cabsolute\xe2\x80\x9d 是什么意思。