【发布时间】:2018-03-21 14:23:09
【问题描述】:
如何使用最近(启用 PIC)gcc 创建不可重定位符号? 我基本上想让下面的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" as
绝对部分:此部分的地址 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_
[...]
但它仍然被重新定位。
【问题讨论】:
-
使用
-fno-pie -no-pie制作一个与位置相关的可执行文件不是更容易很多吗? -
如果这是一个 Fortran 程序,为什么它被标记为 C 而不是 Fortran?如果你想将数组从 C 传递到 Fortran,为什么不直接传递
NULL? -
Fortran 只是问题背后的基本原理,但问题与它无关。基本上,我想传递 NULL,但问题是如何去做。只是
mem_ = NULL不起作用,因为它将符号的值设置为NULL,而不是符号本身。 -
Peter,我不想使用
-no-pie,因为现在 PIE 是默认设置(例如在 Debian 上),它启用了 f.e.一些code hardening options。此外,用户可以选择链接他们自己的可执行文件,并且需要特殊标志始终是错误的来源。我只想让一个符号不重定位,为什么要为其余的可执行文件禁用它? -
您能否说明您正在为哪个平台(以及在哪个平台上)进行编译?