【问题标题】:Linking position-dependent assembly on Debian在 Debian 上链接位置相关的程序集
【发布时间】:2017-08-11 22:01:29
【问题描述】:

我在 Debian 9 上使用 GCC 链接位置相关程序集时遇到问题。以下是程序集中的 hello.s 文件:

  .section .rodata
hello_str:
  .string "Hello world"
  .text
  .globl main
main:
  xor %rdi, %rdi
  mov $hello_str, %rdi
  call puts      # puts("Hello world");
  xor %rax, %rax # return 0;
  ret

在运行gcc hello.s 时,我收到以下错误:

$ gcc hello.s
/usr/bin/ld: /tmp/ccDvqMUc.o: relocation R_X86_64_32S against `.rodata' can not be used when making a shared object; recompile with -fPIC
/usr/bin/ld: final link failed: Nonrepresentable section on output
collect2: error: ld returned 1 exit status

clang hello.s 生成一个可执行文件:

$ clang hello.s
$ file ./a.out 
./a.out: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=ca2f0204d60b5fc197b95c5ccb626a9dfb355a9b, not stripped
$ ./a.out
Hello world

当我将hello.s 转换为与位置无关的代码并将其存储到hello-pic.s 文件中时:

  .section .rodata
hello_str:
  .string "Hello world"
  .text
  .globl main
main:
  xor %rdi, %rdi
  leaq hello_str(%rip), %rdi
  call puts@PLT  # puts("Hello world");
  xor %rax, %rax # return 0;
  ret

然后gcc hello-pic.s 生成一个可执行文件(file 命令和生成的a.out 可执行文件的输出与clanghello.s 相同)。

我无法在其他 Linux 机器(Ubuntu、CentOS)上重现此问题,这让我相信 Debian 上的 GCC 是使用一些非标准标志构建的。如果是这样,基本原理是什么?如何强制 GCC 链接位置相关的代码?附上我目前安装的 CPU 架构和相关包:

$ uname -m
x86_64
$ apt list | grep -Ei '(gcc|llvm|clang).*installed'
clang/testing,unstable,now 1:3.8-34+nmu1 amd64 [installed]
clang-3.8/testing,now 1:3.8.1-17 amd64 [installed,automatic]
gcc/testing,now 4:6.3.0-1 amd64 [installed,automatic]
gcc-4.9/stable,now 4.9.2-10 amd64 [installed,automatic]
gcc-4.9-base/stable,now 4.9.2-10 amd64 [installed,automatic]
gcc-5-base/unstable,now 5.4.1-8 amd64 [installed]
gcc-6/testing,now 6.3.0-6 amd64 [installed,automatic]
gcc-6-base/testing,now 6.3.0-6 amd64 [installed]
gcc-6-doc/testing,testing,unstable,unstable,now 6.1.0-1 all [installed,automatic]
gcc-6-multilib/testing,now 6.3.0-6 amd64 [installed,automatic]
gcc-doc/testing,unstable,now 5:6.1.0-1 amd64 [installed]
gcc-doc-base/testing,testing,unstable,unstable,now 6.1.0-1 all [installed,automatic]
gcc-multilib/testing,now 4:6.3.0-1 amd64 [installed]
lib32gcc-6-dev/testing,now 6.3.0-6 amd64 [installed,automatic]
lib32gcc1/testing,now 1:6.3.0-6 amd64 [installed,automatic]
libclang-common-3.8-dev/testing,now 1:3.8.1-17 amd64 [installed,automatic]
libclang1-3.8/testing,now 1:3.8.1-17 amd64 [installed,automatic]
libgcc-4.9-dev/stable,now 4.9.2-10 amd64 [installed,automatic]
libgcc-5-dev/unstable,now 5.4.1-8 amd64 [installed,automatic]
libgcc-6-dev/testing,now 6.3.0-6 amd64 [installed,automatic]
libgcc1/testing,now 1:6.3.0-6 amd64 [installed]
libllvm3.8/testing,now 1:3.8.1-17 amd64 [installed,automatic]
libllvm3.9/testing,now 1:3.9.1-4 amd64 [installed,automatic]
libx32gcc-6-dev/testing,now 6.3.0-6 amd64 [installed,automatic]
libx32gcc1/testing,now 1:6.3.0-6 amd64 [installed,automatic]
linux-compiler-gcc-6-x86/testing,unstable,now 4.9.13-1 amd64 [installed,automatic]
llvm-3.8/testing,now 1:3.8.1-17 amd64 [installed,automatic]
llvm-3.8-dev/testing,now 1:3.8.1-17 amd64 [installed,automatic]
llvm-3.8-runtime/testing,now 1:3.8.1-17 amd64 [installed,automatic]

【问题讨论】:

  • 可能是-fno-pic-fno-PIC-fno-pie中的一个或多个。
  • 即使gcc hello.s -no-pie 也应该工作?但是我没有 deb9 机器 now 来验证,而其他一些带有一些 gcc 5.x 的发行版将它报告为未知选项,但它可以在文档中找到,所以我很困惑(它确实编译了你的源代码,并且使用-pie 选项它以与你在debian中相同的错误结束)。由于 Debian 现在默认设置为 pic/pie,它希望能理解相反的选项吗?试试看。
  • gcc hello.s -no-pie 可以解决问题。不过,为什么 -pie 会成为默认值?
  • 出于安全原因。 ASLR 与 PIE 配合得更好。
  • 你真的应该养成使用leaq hello_str(%rip), %rdi的习惯,因为它更短更快速。

标签: linux gcc assembly clang x86-64


【解决方案1】:

由于其他发行版 Debian 9 似乎默认启用 PIE(出于安全原因):

For the stretch release, the Debian version of the GNU GCC 6 compiler now defaults
to compiling "position independent executables" (PIE).

要获得旧行为,您需要将 -no-pie 添加到 CFLAGS

【讨论】:

    猜你喜欢
    • 2012-01-02
    • 1970-01-01
    • 2012-04-19
    • 1970-01-01
    • 1970-01-01
    • 2021-11-29
    • 2019-07-06
    • 1970-01-01
    • 2016-06-01
    相关资源
    最近更新 更多