如何使用最近的gcc(启用PIC)创建不可重定位的符号?
我基本上想让以下C程序打印NULL:
#include <stdio.h>
extern int mem_;
int main(void) {
printf("%p\n", &mem_);
return 0;
}
我试过的是一个小的汇编文件:
.data
.globl mem_
.type mem_,@object
.set mem_, 0
但这会创建一个可重定位的符号,该符号在运行时不具有值0。
背景:我正在尝试运行一个旧程序,该程序使用此技巧直接从Fortran中以数组形式访问(分配)内存。由于该程序具有≫10⁵ LOC,因此重写所有内容是不可行的。
[编辑] GNU汇编程序手册documents an "absolute section"为
绝对节:该节的地址0始终“重定位”到运行时地址0。如果要引用的地址在重定位时ld不得更改,则此功能很有用。从这个意义上讲,我们说绝对地址是“无法重定位”的:它们在重定位期间不会改变。
这可能是我在这里需要的(对吗?),但是我找不到启用此部分的方法。
.struct
指令是documented to switch to the "absolute section";但是以下汇编程序也不起作用: .globl mem_
.struct 0
mem_:
在这种情况下,符号显示为
*ABS*
和objdump
:$ objdump -t memc
memc: file format elf64-x86-64
[...]
0000000000000540 g F .text 000000000000002b _start
0000000000201030 g .bss 0000000000000000 __bss_start
000000000000064a g F .text 000000000000003c main
0000000000000000 g *ABS* 0000000000000000 mem_
[...]
但它仍然被重新安置。
最佳答案
您可以将符号放在“fixedloc”部分中,并在链接时指定地址:
#include <stdio.h>
int mem_ __attribute__ ((section ("fixedloc")));
int main (void) {
printf("%p\n", &mem_);
return 0;
}
并编译/链接
gcc -O2 mem.c -o mem -Wl,--section-start=fixedloc=0x1230000
$ nm mem
...
0000000001230000 D mem
...
$ ./mem
0x1230000
请注意,如果未将/proc/sys/vm/mmap_min_addr设置为0(默认值为65536),则即使在最新的Linux内核上,它也不能与
0
位置一起使用,即使这样,动态链接器也会阻塞该位置。但是其他地址可以完美地工作。