GCC编译错误,代码大于2 GB

bbt*_*trb 108 c c++ gcc compiler-errors

我有大量的功能,总共大约2.8 GB的目标代码(遗憾的是,没有办法,科学计算......)

当我尝试链接它们时,我得到(预期的)relocation truncated to fit: R_X86_64_32S错误,我希望通过指定编译器标志来避免这些错误-mcmodel=medium.我控制的所有链接的库都使用该-fpic标志进行编译.

仍然,错误仍然存​​在,我认为我链接到的一些库不是用PIC编译的.

这是错误:

/usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../lib64/crt1.o: In function `_start':
(.text+0x12): relocation truncated to fit: R_X86_64_32S against symbol `__libc_csu_fini'     defined in .text section in /usr/lib64/libc_nonshared.a(elf-init.oS)
/usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../lib64/crt1.o: In function `_start':
(.text+0x19): relocation truncated to fit: R_X86_64_32S against symbol `__libc_csu_init'    defined in .text section in /usr/lib64/libc_nonshared.a(elf-init.oS)
/usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../lib64/crt1.o: In function `_start':
(.text+0x20): undefined reference to `main'
/usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../lib64/crti.o: In function    `call_gmon_start':
(.text+0x7): relocation truncated to fit: R_X86_64_GOTPCREL against undefined symbol      `__gmon_start__'
/usr/lib/gcc/x86_64-redhat-linux/4.1.2/crtbegin.o: In function `__do_global_dtors_aux':
crtstuff.c:(.text+0xb): relocation truncated to fit: R_X86_64_PC32 against `.bss' 
crtstuff.c:(.text+0x13): relocation truncated to fit: R_X86_64_32 against symbol `__DTOR_END__' defined in .dtors section in /usr/lib/gcc/x86_64-redhat-linux/4.1.2/crtend.o
crtstuff.c:(.text+0x19): relocation truncated to fit: R_X86_64_32S against `.dtors'
crtstuff.c:(.text+0x28): relocation truncated to fit: R_X86_64_PC32 against `.bss'
crtstuff.c:(.text+0x38): relocation truncated to fit: R_X86_64_PC32 against `.bss'
crtstuff.c:(.text+0x3f): relocation truncated to fit: R_X86_64_32S against `.dtors'
crtstuff.c:(.text+0x46): relocation truncated to fit: R_X86_64_PC32 against `.bss'
crtstuff.c:(.text+0x51): additional relocation overflows omitted from the output
collect2: ld returned 1 exit status
make: *** [testsme] Error 1
Run Code Online (Sandbox Code Playgroud)

和我链接的系统库:

-lgfortran -lm -lrt -lpthread
Run Code Online (Sandbox Code Playgroud)

有什么线索在哪里寻找问题?

编辑:首先,感谢您的讨论...为了澄清一点,我有数百个函数(每个大小约1 MB在单独的目标文件中),如下所示:

double func1(std::tr1::unordered_map<int, double> & csc, 
             std::vector<EvaluationNode::Ptr> & ti, 
             ProcessVars & s)
{
    double sum, prefactor, expr;

    prefactor = +s.ds8*s.ds10*ti[0]->value();
    expr =       ( - 5/243.*(s.x14*s.x15*csc[49300] + 9/10.*s.x14*s.x15*csc[49301] +
           1/10.*s.x14*s.x15*csc[49302] - 3/5.*s.x14*s.x15*csc[49303] -
           27/10.*s.x14*s.x15*csc[49304] + 12/5.*s.x14*s.x15*csc[49305] -
           3/10.*s.x14*s.x15*csc[49306] - 4/5.*s.x14*s.x15*csc[49307] +
           21/10.*s.x14*s.x15*csc[49308] + 1/10.*s.x14*s.x15*csc[49309] -
           s.x14*s.x15*csc[51370] - 9/10.*s.x14*s.x15*csc[51371] -
           1/10.*s.x14*s.x15*csc[51372] + 3/5.*s.x14*s.x15*csc[51373] +
           27/10.*s.x14*s.x15*csc[51374] - 12/5.*s.x14*s.x15*csc[51375] +
           3/10.*s.x14*s.x15*csc[51376] + 4/5.*s.x14*s.x15*csc[51377] -
           21/10.*s.x14*s.x15*csc[51378] - 1/10.*s.x14*s.x15*csc[51379] -
           2*s.x14*s.x15*csc[55100] - 9/5.*s.x14*s.x15*csc[55101] -
           1/5.*s.x14*s.x15*csc[55102] + 6/5.*s.x14*s.x15*csc[55103] +
           27/5.*s.x14*s.x15*csc[55104] - 24/5.*s.x14*s.x15*csc[55105] +
           3/5.*s.x14*s.x15*csc[55106] + 8/5.*s.x14*s.x15*csc[55107] -
           21/5.*s.x14*s.x15*csc[55108] - 1/5.*s.x14*s.x15*csc[55109] -
           2*s.x14*s.x15*csc[55170] - 9/5.*s.x14*s.x15*csc[55171] -
           1/5.*s.x14*s.x15*csc[55172] + 6/5.*s.x14*s.x15*csc[55173] +
           27/5.*s.x14*s.x15*csc[55174] - 24/5.*s.x14*s.x15*csc[55175] +
           // ...
           ;

        sum += prefactor*expr;
    // ...
    return sum;
}
Run Code Online (Sandbox Code Playgroud)

该对象s相对较小并保持所需的常量x14,x15,...,ds0,...等,而ti只是从外部库返回一个double.正如您所看到的,csc[]是一个预先计算的值映射,它也在以下形式的单独目标文件(再次数百个,每个大约约1 MB)中进行评估:

void cscs132(std::tr1::unordered_map<int,double> & csc, ProcessVars & s)
{
    {
    double csc19295 =       + s.ds0*s.ds1*s.ds2 * ( -
           32*s.x12pow2*s.x15*s.x34*s.mbpow2*s.mWpowinv2 -
           32*s.x12pow2*s.x15*s.x35*s.mbpow2*s.mWpowinv2 -
           32*s.x12pow2*s.x15*s.x35*s.x45*s.mWpowinv2 -
           32*s.x12pow2*s.x25*s.x34*s.mbpow2*s.mWpowinv2 -
           32*s.x12pow2*s.x25*s.x35*s.mbpow2*s.mWpowinv2 -
           32*s.x12pow2*s.x25*s.x35*s.x45*s.mWpowinv2 +
           32*s.x12pow2*s.x34*s.mbpow4*s.mWpowinv2 +
           32*s.x12pow2*s.x34*s.x35*s.mbpow2*s.mWpowinv2 +
           32*s.x12pow2*s.x34*s.x45*s.mbpow2*s.mWpowinv2 +
           32*s.x12pow2*s.x35*s.mbpow4*s.mWpowinv2 +
           32*s.x12pow2*s.x35pow2*s.mbpow2*s.mWpowinv2 +
           32*s.x12pow2*s.x35pow2*s.x45*s.mWpowinv2 +
           64*s.x12pow2*s.x35*s.x45*s.mbpow2*s.mWpowinv2 +
           32*s.x12pow2*s.x35*s.x45pow2*s.mWpowinv2 -
           64*s.x12*s.p1p3*s.x15*s.mbpow4*s.mWpowinv2 +
           64*s.x12*s.p1p3*s.x15pow2*s.mbpow2*s.mWpowinv2 +
           96*s.x12*s.p1p3*s.x15*s.x25*s.mbpow2*s.mWpowinv2 -
           64*s.x12*s.p1p3*s.x15*s.x35*s.mbpow2*s.mWpowinv2 -
           64*s.x12*s.p1p3*s.x15*s.x45*s.mbpow2*s.mWpowinv2 -
           32*s.x12*s.p1p3*s.x25*s.mbpow4*s.mWpowinv2 +
           32*s.x12*s.p1p3*s.x25pow2*s.mbpow2*s.mWpowinv2 -
           32*s.x12*s.p1p3*s.x25*s.x35*s.mbpow2*s.mWpowinv2 -
           32*s.x12*s.p1p3*s.x25*s.x45*s.mbpow2*s.mWpowinv2 -
           32*s.x12*s.p1p3*s.x45*s.mbpow2 +
           64*s.x12*s.x14*s.x15pow2*s.x35*s.mWpowinv2 +
           96*s.x12*s.x14*s.x15*s.x25*s.x35*s.mWpowinv2 +
           32*s.x12*s.x14*s.x15*s.x34*s.mbpow2*s.mWpowinv2 -
           32*s.x12*s.x14*s.x15*s.x35*s.mbpow2*s.mWpowinv2 -
           64*s.x12*s.x14*s.x15*s.x35pow2*s.mWpowinv2 -
           32*s.x12*s.x14*s.x15*s.x35*s.x45*s.mWpowinv2 +
           32*s.x12*s.x14*s.x25pow2*s.x35*s.mWpowinv2 +
           32*s.x12*s.x14*s.x25*s.x34*s.mbpow2*s.mWpowinv2 -
           32*s.x12*s.x14*s.x25*s.x35pow2*s.mWpowinv2 -
           // ...

       csc.insert(cscMap::value_type(192953, csc19295));
    }

    {
       double csc19296 =      // ... ;

       csc.insert(cscMap::value_type(192956, csc19296));
    }

    // ...
}
Run Code Online (Sandbox Code Playgroud)

就是这样.最后一步只是调用所有这些func[i]并总结结果.

关于这是一个相当特殊和不寻常的案例:是的,它是.这是人们在尝试为粒子物理进行高精度计算时必须应对的.

EDIT2:我还应该补充说x12,x13等不是真正的常量.它们被设置为特定值,运行所有这些函数并返回结果,然后选择一组新的x12,x13等来生成下一个值.这必须完成10 ^ 5到10 ^ 6次......

EDIT3:感谢您的建议和讨论到目前为止......我会尝试以某种方式在代码生成上推动循环,不确定如何准确,但说实话,但这是最好的选择.

顺便说一句,我没有试图隐藏"这是科学计算 - 无法优化".只是这个代码的基础是来自"黑盒子"的东西,在那里我没有真正的访问权限,而且,整个事情在简单的例子中运行得很好,我主要感到不知所措在真实中发生了什么.世界申请......

EDIT4:所以,我csc通过简化计算机代数系统(Mathematica)中的表达式,设法将定义的代码大小减少了大约一.我现在也看到了一些方法,通过在生成代码之前应用一些其他技巧(将这部分降低到大约100 MB)将其减少一个数量级左右,我希望这个想法有效.

现在与你的答案有关:我正试图在funcs中再次回滚循环,CAS不会有太多帮助,但我已经有了一些想法.例如,通过变量对表达式进行排序,例如,用Python x12, x13,...解析cscs并生成将它们相互关联的表.然后我至少可以生成这些部分作为循环.由于这似乎是迄今为止最好的解决方案,我将此标记为最佳答案.

不过,我还要赞扬VJo.GCC 4.6的确运行更好,代码更小,速度更快.使用大型模型可以按原样使用代码.从技术上讲,这是正确答案,但改变整个概念是一种更好的方法.

谢谢大家的建议和帮助.如果有人有兴趣,我会在准备好后立即发布最终结果.

备注:对其他一些答案的一些评论:我试图运行的代码并不是源于简单函数/算法的扩展和愚蠢的不必要的展开.实际发生的事情是,我们开始的东西是相当复杂的数学对象,并将它们以数字可计算的形式生成这些表达式.问题实际上在于潜在的物理理论.因为众所周知,中间表达式的复杂性是按比例缩放的,但是当将所有这些东西组合成物理上可测量的东西时 - 一个可观察的东西 - 它只能归结为构成表达式基础的少数非常小的函数.(在这方面肯定存在一些"错误"与一般而且唯一可用的ansatz被称为"扰动理论")我们试图将这个ansatz带到另一个层次,这在分析上是不可行的,并且所需函数的基础是未知.所以我们试着像这样蛮力.不是最好的方法,但希望最终有助于我们理解手头的物理...

最后编辑: 感谢你的所有建议,我已经设法大大减少了代码大小,使用Mathematica和代码生成器的修改,func有点像最顶层的答案:)

我已经csc使用Mathematica 简化了功能,将其降低到92 MB.这是不可简化的部分.第一次尝试是永远的,但经过一些优化后,现在在一个CPU上运行大约10分钟.

funcs 的影响是戏剧性的:它们的整个代码大小下降到大约9 MB,因此代码现在总计在100 MB范围内.现在,启用优化并执行速度非常快.

再次,谢谢大家的建议,我学到了很多东西.

And*_*rei 53

所以,你已经有了一个生成这个文本的程序:

prefactor = +s.ds8*s.ds10*ti[0]->value();
expr = ( - 5/243.*(s.x14*s.x15*csc[49300] + 9/10.*s.x14*s.x15*csc[49301] +
       1/10.*s.x14*s.x15*csc[49302] - 3/5.*s.x14*s.x15*csc[49303] -...
Run Code Online (Sandbox Code Playgroud)

double csc19295 =       + s.ds0*s.ds1*s.ds2 * ( -
       32*s.x12pow2*s.x15*s.x34*s.mbpow2*s.mWpowinv2 -
       32*s.x12pow2*s.x15*s.x35*s.mbpow2*s.mWpowinv2 -
       32*s.x12pow2*s.x15*s.x35*s.x45*s.mWpowinv2 -...
Run Code Online (Sandbox Code Playgroud)

对?

如果你的所有函数都有一个类似的"格式"(将n个数乘以m次并添加结果 - 或类似的东西),那么我认为你可以这样做:

  • 更改生成器程序以输出偏移量而不是字符串(即代替字符串"s.ds0"它将产生 offsetof(ProcessVars, ds0)
  • 创建一个这样的偏移数组
  • 编写一个评估器,它接受上面的数组和结构指针的基地址,并产生一个结果

数组+求值程序将表示与您的某个函数相同的逻辑,但只有求值程序才是代码.该数组是"数据",可以在运行时生成,也可以保存在磁盘上,读取数据块或使用内存映射文件.

对于FUNC1您的具体的例子想象你将如何通过评估重写功能,如果你有机会访问的基地址scsc和也喜欢常量,你需要添加到基址去的偏移表示一个向量x14,ds8csc[51370]

您需要创建一种新形式的"数据",它将描述如何处理传递给大量函数的实际数据.


BЈо*_*вић 45

Linux使用x86-64 ABI定义了一个"大型模型",专门用于避免这种大小限制,其中包括GOT和PLT的64位重定位类型.(参见4.4.2节中的表格,以及3.5.5中的指令序列,说明如何使用它们.)

由于你的功能占用2.8 GB,你运气不好,因为gcc不支持大型号.您可以做的是以一种允许您将其拆分为动态链接的共享库的方式重新组织代码.

如果这是不可能的,就像有人建议的那样,而不是将数据放入代码(编译和链接它),因为它很大,你可以在运行时加载它(作为普通文件,或者你可以mmap它).

编辑

似乎gcc 4.6支持大型模型(参见本页).您可以尝试这一点,但上述内容仍然适用于重新组织代码.

  • WTF?这段代码必须由某些脚本生成; 没人用手写兆字节的代码!*生成*代码的相同逻辑也可用于*运行*计算. (18认同)
  • 我强烈建议尝试使用gcc 4.6,它很可能比gcc 4.1为这个程序生成更好的代码; 它甚至可以将整个东西压缩到2GB,而不必做任何聪明的事情,消除问题(尝试-Os,-fwhole-program和-flto的组合 - 使用这个代码量,优化大小*是*优化速度).但是,如果这没有足够的帮助,您还应该知道,要使大型模型起作用,您将不得不在大型模型中重建至少部分C库(crt*.o,libc_nonshared.a和libpthread_nonshared.a). (6认同)
  • @bbtrb对.但我仍然会寻找另一种实现功能的方法.我打赌你的编译需要永远 (3认同)

bdo*_*lan 37

使用该方程序,代码的缓存未命中很可能超过运行时循环的成本.我建议你回到你的代码生成器,让它为它想要评估的内容生成一些紧凑的表示(即,一个可能适合D-cache),然后在你的程序中用解释器执行它.您还可以看看是否可以分解仍然具有大量操作的较小内核,然后将其用作解释代码中的"指令".


zvr*_*rba 21

发生错误的原因是您有太多的CODE,而不是数据!这由例如__libc_csu_fini引用的(它是一个函数)表示,_start并且重定位被截断以适合.这意味着_start(程序的真正入口点)试图通过SIGNED 32位偏移调用该函数,该偏移的范围仅为2 GB.由于您的目标代码总量约为2.8 GB,因此可以查看事实.

如果你可以重新设计你的数据结构,你可以通过将巨大的表达式重写为简单的循环来"压缩"你的大部分代码.

此外,您可以csc[]在不同的程序中进行计算,将结果存储在文件中,并在必要时加载它们.

  • @bbtr:例如,对于上面的`func1`,类似于:`for(int i = 0; i <N; ++ i)expr + = constants [i].*s.x14*s.x15*csc [ 49300 + i];`. (4认同)
  • @bbtrb:因为没有人会编写足够的源来手工生成2.8GB的目标代码,特别是使用这种非助记符号名称,所以使用了代码生成器_must_.使用它. (2认同)

Ale*_*Sin 15

我想每个人都同意应该采用不同的方式来做你想做的事情.编译数百兆字节(千兆字节?)的代码,将其链接到一个数千兆字节大小的可执行文件并运行它听起来非常低效.

如果我正确理解你的问题,你可以使用某种代码生成器G来生成一堆函数func1...N,这些函数将一堆映射csc1...M作为输入.你想要做的是计算csc1...M,并为不同的输入运行1,000,000次循环,每次查找s = func1 + func2 + ... + funcN.但是你没有说明如何fucn1...N与之相关csc1...M.

如果一切正确,那么您似乎应该能够以不同的方式解决问题,这可能更易于管理,甚至可能更快(即让您的机器的缓存实际运行).

除了目标文件大小的实际问题之外,您当前的程序效率不高,因为它不会本地化对数据的访问(太多的大型映射)并且没有本地化代码执行(太多非常长的函数).

如何将您的程序分为3阶段:阶段1构建csc1...M和存储它们.阶段2一次构建一个func,每次输入运行1,000,000次并存储结果.阶段3找到func1...N每次运行1,000,000次的存储结果的总和.关于这个解决方案的好处是它可以很容易地在几台独立的机器上并行.

编辑:@bbtrb,你可以制作一个功能和一个csc可用吗?它们似乎是高度规则和可压缩的.例如,func1似乎只是表达式的总和,每个表达式由1个系数组成,2个索引指向s中的变量,1个索引指向csc.所以它可以简化为一个很好的循环.如果您提供完整的示例,我确信可以找到将它们压缩成循环而不是长表达式的方法.


APr*_*mer 5

如果我正确地读取了你的错误,那么让你超越限制的是初始化数据部分(如果是代码,你会有更多的错误恕我直言).你有大量的全球数据吗?如果是这种情况,我会重新构建程序,以便动态分配它们.如果数据已初始化,我会从配置文件中读取它.

BTW看到这个:

(.text + 0x20):对'main'的未定义引用

我想你还有另外一个问题.