我有一个有趣的编译问题。 首先,请查看要编译的代码。
$ ls
Makefile main.c sub.c sub.h
$ gcc -v
...
gcc version 4.8.5 20150623 (Red Hat 4.8.5-16) (GCC)
## Makefile
%.o: CFLAGS+=-fPIE #[2]
main.so: main.o sub.o
$(CC) -shared -fPIC -o $@ $^
//main.c
#include "sub.h"
int main_func(void){
sub_func();
subsub_func();
return 0;
}
//sub.h
#pragma once
void subsub_func(void);
void sub_func(void);
//sub.c
#include "sub.h"
#include <stdio.h>
void subsub_func(void){
printf("%s\n", __func__);
}
void sub_func(void){
subsub_func();//[1]
printf("%s\n", __func__);
}
我编译代码时出现以下错误:
$ LANG=en make
cc -fPIE -c -o main.o main.c
cc -fPIE -c -o sub.o sub.c
cc -shared -fPIC -o main.so main.o sub.o
/usr/bin/ld: sub.o: relocation R_X86_64_PC32 against symbol `subsub_func' can not be used when making a shared object; recompile with -fPIC
/usr/bin/ld: final link failed: Bad value
collect2: error: ld returned 1 exit status
make: *** [main.so] Error 1
接着,我修改了代码(删除了一行[1] / 使用-fPIC而不是-PIE [2]),然后成功编译了这些内容。
$ make #[1]
cc -fPIE -c -o main.o main.c
cc -fPIE -c -o sub.o sub.c
cc -shared -fPIC -o main.so main.o sub.o
$ make #[2]
cc -fPIC -c -o main.o main.c
cc -fPIC -c -o sub.o sub.c
cc -shared -fPIC -o main.so main.o sub.o
为什么会出现这种现象?
我听说,当一个对象内部调用函数时,如果使用-fPIC编译,则通过PLT进行调用;而如果使用-fPIE编译,则直接跳转到该函数。 我猜想,使用-fPIE时的函数调用机制避免了重定位。 但我想知道更确切和准确的解释。
你能帮我吗?
谢谢大家。