我在编译静态链接静态库的共享对象时遇到了很多问题。此问题仅出现在x84_64平台上。在x86_32上进行相同的编译工作时,我没有任何问题。
也许这是一个特定于操作系统的GCC配置,但我的研究表明它是如何在x86_64平台上运行的。无论如何,我在Ubuntu 10.04 x86_64上使用gcc 4.4.3。
如何修复问题?...确保使用-fPIC编译所有静态库依赖项。
问题1: -fpic和-fPIC有什么区别(显然-fPIC会在x86上生成更多指令)?为什么后一种类型在x86_64上下文中更相关?
问题2:我的假设是,当您链接静态代码时,您在链接时将函数硬连接到二进制文件中,为什么它需要间接级别“位置无关代码“机器提供?
问题3:现在,如果x86不需要-fpic / -fPIC来链接共享对象与静态存档,为什么在x86_64中需要它?
问题4:即使需要,为什么不隐式提供?我认为突破性变化应该是一个很大的禁忌
答案 0 :(得分:44)
另外,我的建议是:如果你需要担心,你做错了(或者你喜欢学习困难的方法,这很好,因为你会从经验中获得更多)。编译系统(libtool,cmake,无论你使用什么)都应该为你做。
答案 1 :(得分:0)
典型的.a
静态库只是常规.o
对象的集合
因此,从概念上讲,您通常可以在命令行上用完全相同的.a
文件列表替换.o
,而无需重新定位。
例如考虑以下minimal runnable example:
a.c
#include "a.h"
int a(void) { return 1; }
a.h
#ifndef A_H
#define A_H
int a(void);
#endif
b.c
#include "b.h"
int b(void) { return 2; }
b.h
#ifndef B_H
#define B_H
int b(void);
#endif
main.c
#include <assert.h>
#include <stdlib.h>
#include "a.h"
#include "b.h"
int main(void) {
assert(a() == 1);
assert(b() == 2);
return EXIT_SUCCESS;
}
编译并运行:
gcc -ggdb3 -std=c89 -Wall -Wextra -pedantic-errors -fPIC -c 'main.c' -o 'main.o'
gcc -ggdb3 -std=c89 -Wall -Wextra -pedantic-errors -fPIC -c 'a.c' -o 'a.o'
gcc -ggdb3 -std=c89 -Wall -Wextra -pedantic-errors -fPIC -c 'b.c' -o 'b.o'
ar rcs ab.a a.o b.o
gcc -ggdb3 -std=c89 -Wall -Wextra -pedantic-errors main.o ab.a -o maina.out
./maina.out
由此我们可以清楚地看到,ar
只是将a.o
和b.o
打包到ab.a
中。
因此,以下命令也有效:
gcc -ggdb3 -std=c89 -Wall -Wextra -pedantic-errors main.o a.o b.o -o maina.out
由此可以明确地看出,.a
存档中的目标文件通常不需要与位置无关。
如果需要,可以使他们的位置独立。例如将它们链接到共享库。一切都像以前一样适用:.a
仅包含它们而不修改它们。
此答案也可能令人感兴趣:What is the -fPIE option for position-independent executables in gcc and ld?
在Ubuntu 20.04上测试。