【发布时间】: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 可执行文件的输出与clang 的hello.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