【问题标题】:How to create a non-relocatable symbol如何创建不可重定位符号
【发布时间】: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。此外,用户可以选择链接他们自己的可执行文件,并且需要特殊标志始终是错误的来源。我只想让一个符号不重定位,为什么要为其余的可执行文件禁用它?
  • 您能否说明您正在为哪个平台(以及在哪个平台上)进行编译?

标签: assembly linker


【解决方案1】:

您可以将符号放在“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,即使这样,动态链接器也会阻塞它。但其他地址完美无缺。

【讨论】:

  • 我认为 OP 使用 _mem 作为在 Fortran 中使用整数作为指针的基地址。如果他们可以在任何地方的源中添加一个常量偏移量,那么如果没有办法让动态链接器接受它,那么可以使用_mem 的非零值(地址)来解决。但如果可以的话,可能更容易使用-fno-pie -no-pie 来制作与位置相关的可执行文件。
  • 不幸的是,这也不起作用。我仍然得到 mem_ 的不同地址。而且我不明白mmap_min地址在这里的作用:我当然不会直接访问地址0mem_ 在 Fortran 中始终用于具有非零索引的数组。
  • @olebole 我看不出这怎么行。您在哪里偏离了我在答案中显示的步骤?如果你完全复制它,你将不得不得到相同的结果。
  • 我没有:$ cat memc.c #include &lt;stdio.h&gt; int mem_ __attribute__ ((section ("fixedloc"))); int main(void) { printf("%p\n", &amp;mem_); return 0; } $ gcc -O2 memc.c -o memc -Wl,--section-start=fixedloc=0x1230000 $ ./memc 0x55648e902000 这正是你的代码。顺便说一句,对不起;我意外编辑了您的代码:-)
  • 也许你应该提到这仅适用于 ELF 二进制文件而不适用于 COFF(Windows 使用它)。由于任何部分的最大 RVA 在 COFF 中只能是 32 位。此外,标志 --section-start 不适用于 Windows 链接器。
猜你喜欢
  • 2011-07-29
  • 2019-01-13
  • 1970-01-01
  • 2013-11-13
  • 2020-07-10
  • 2020-12-09
  • 1970-01-01
  • 2020-01-20
  • 1970-01-01
相关资源
最近更新 更多