64位Linux默认使用小内存模型,它将所有代码和静态数据置于2GB地址限制之下.这可确保您可以使用32位绝对地址.较旧版本的gcc使用静态数组的32位绝对地址,以便为相对地址计算保存额外的指令.但是,这不再有效.如果我尝试在汇编中创建一个32位的绝对地址,我会收到链接器错误:"在创建共享对象时,不能使用".data"重定位R_X86_64_32S;使用-fPIC重新编译".当然,此错误消息具有误导性,因为我没有创建共享对象,-fPIC也没有帮助.到目前为止我发现的是:gcc版本4.8.5对静态数组使用32位绝对地址,gcc版本6.3.0不使用.版本5可能也没有.binutils 2.24中的链接器允许32位绝对地址,而2.28则不允许.
这种变化的后果是必须重新编译旧库并破坏传统汇编代码.
现在我想问一下:这个改变是什么时候做的?它在某处记录了吗?是否有一个链接器选项,使其接受32位绝对地址?
我注意到我的C程序的性能差异很大,具体取决于-fPIC标志.当我使用它时,我的程序比没有它的程序慢约30%.我将它与一个调用C函数的Lua程序进行比较(所有繁重的计算都完成了).首先,我使用C函数创建了一个共享对象,因此必须使用-fPIC标志.性能与带有-fPIC标志的C代码非常相似.所以现在我试着没有.so:我从C调用了Lua:
int main()
{
lua_State* L = luaL_newstate();
luaL_openlibs(L);
lua_register(L, "my_c_function", my_c_function);
luaL_dofile(L, "my_lua_program.lua");
lua_close(L);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
但是,无论我是否使用-fPIC标志(与使用.so的方法相同),这里的性能都是相同的.如果没有-fPIC标志,我期待一些改进...有关如何进一步调查的任何建议?第二种方法是否创建了与位置无关的代码,这就是性能相似的原因?谢谢!
更多信息,如评论所示:我使用-O3标志,gcc 4.7.2,Ubuntu 12.04.2,x86_64.是的,我对这么大的开销感到非常惊讶......我的程序正在计算Mandelbrot分形.所以有两个循环迭代x和y,我在C中的函数是isMandelbrot:它需要迭代次数并返回bool:属于Mandelbrot set或者不属于Mandelbrot.我将共享对象与'require'一起使用.
ELF 可执行文件有一个固定的加载地址(32 位 x86 Linux 二进制文件为 0x804800,64 位 x86_64 二进制文件为 0x40000)。
我阅读了关于这些特定地址的历史原因的 SO 答案(例如,this one)。我仍然不明白的是为什么要使用固定的加载地址而不是随机的地址(给定一些范围内要随机化)?
我很惊讶地发现gcc强制代码与位置无关,即使命令行中没有明确提供这样的标志.
我怀疑它可能与Android动态加载器的某些期望有关(例如对重定位类型的期望以及将代码放在任何地方的自由)但我不确定.
任何人都能解释为什么会这样吗?
$ arm-linux-androideabi-gcc --version | grep GCC
arm-linux-androideabi-gcc (GCC) 4.4.3
$ arm-linux-androideabi-gcc -v -S main.c |& grep fpic
/home1/local64/android-toolchain/bin/../libexec/gcc/arm-linux-androideabi/4.4.3/cc1 -quiet -v -iprefix /home1/local64/android-toolchain/bin/../lib/gcc/arm-linux-androideabi/4.4.3/ -isysroot /home1/local64/android-toolchain/bin/../sysroot main.c -mbionic -fpic -quiet -dumpbase main.c -march=armv5te -mfloat-abi=soft -mfpu=vfp -auxbase main -version -o main.s
Run Code Online (Sandbox Code Playgroud) 我想将目标文件和静态库合并到共享库中,但不得公开静态库,它只能在进入共享库的对象文件中引用。我认为在这种情况下,我不需要使用来编译静态库,-fPIC但是我不知道如何告诉链接器我不会使用静态库中的符号这一事实。为了说明我的问题,请使用以下文件:
档案foo.cpp:
#include "static.h"
using namespace std;
string version_info()
{
return static_version_info();
}
Run Code Online (Sandbox Code Playgroud)
档案static.cpp:
#include"static.h"
#include <vector>
using namespace std;
string static_version_info()
{
std::vector<int> ivec;
return to_string(ivec.size());
}
Run Code Online (Sandbox Code Playgroud)
档案static.h:
#ifndef STATIC_H
#define STATIC_H
#include<iostream>
using namespace std;
std::string static_version_info();
#endif
Run Code Online (Sandbox Code Playgroud)
然后做
$ g++ -c foo.cpp -o foo.o -fPIC
$ g++ -c static.cpp -o static.o
$ gcc-ar rcs static.a static.o
$ g++ -shared foo.o static.a
/usr/bin/ld: static.a(static.o): relocation R_X86_64_PC32 against symbol `_ZNSt6vectorIiSaIiEEC1Ev' can …Run Code Online (Sandbox Code Playgroud) gcc ×3
c ×2
linker ×2
linux ×2
android ×1
c++ ×1
compilation ×1
elf ×1
g++ ×1
libtool ×1
lua ×1
performance ×1
relocation ×1
x86-64 ×1