传统的gcc编译器问题

我们正在使用一个基于gcc 2.6.0的遗留编译器来交叉编译我们现在仍在使用的旧embedded式处理器(是的,它自1994年起仍在使用!)。 为这个芯片做了gcc端口的工程师早就开始工作了。 尽pipe我们可以从网上的某个地方恢复gcc 2.6.0源码,但是这个芯片的设置已经在公司历史的大厅里消失了。 直到最近,由于编译器仍在运行并生成可用的可执行文件,所以直到最近,我们一直在困惑,但是从2.6.25内核(也是2.6.26)开始,它会失败并显示消息gcc: virtual memory exhausted …即使不带参数运行或只有-v 。 我已经使用2.6.24内核重启了我的开发系统(从2.6.26开始),编译器再次运行(2.6.25不重启)。

我们有一个系统,我们在2.6.24中只是为了构build这个芯片而做的,但是当linux世界移动到我们不能再重build一个将运行的系统编译器(即我们的2.6.24系统死机,我们不能得到2.6.24安装和运行在一个新的系统,因为一些软件部分不再可用)。

有没有人有任何想法,我们可以做一个更现代化的安装,让这个遗留的编译器运行?

编辑

回答一些评论…

不幸的是,这是我们的芯片特有的源代码更改丢失。 这个损失发生在两个主要的公司reorgs和几个系统pipe理员(其中几个真的留下了一个烂摊子)。 我们现在使用configuration控制,但是对于这个问题,closures仓库门太晚了。

虚拟机的使用是一个好主意,也可能是我们最终做的事情。 谢谢你的想法。

最后,我试着用ephemientbuild议strace,发现最后一个系统调用是brk(),它在新系统(2.6.26内核)上返回一个错误,并在旧系统(2.6.24内核)上返回成功。 这表明我真的用完了虚拟内存,除了tcsh“limit”在旧系统和新系统上返回相同的值,而/ proc / meminfo显示新系统的内存稍微多一些,交换空间也多了一点。 也许这是一个碎片问题或程序正在加载?

我做了一些进一步的研究,并在内核2.6.25中添加了“brk随机化”,但CONFIG_COMPAT_BRK默认启用(禁用brk随机化)。

编辑

OK,更多信息:看起来像brk随机化是罪魁祸首,遗留gcc调用brk()来更改数据段的结尾,现在失败,导致遗留gcc报告“虚拟内存已耗尽”。 有几个logging的方法来禁用brk随机化:

  • sudo echo 0 > /proc/sys/kernel/randomize_va_space

  • sudo sysctl -w kernel.randomize_va_space=0

  • setarch i386 -R tcsh (或“-R -L”)启动一个新的shell

我已经尝试过,他们似乎有一个效果,brk()返回值是不同的(总是相同的)比没有他们(在内核2.6.25和2.6.26尝试),但brk()仍然失败,所以传统的gcc仍然失败:-(。

另外,我已经设置vm.legacy_va_layout=1vm.overcommit_memory=2没有任何变化,我已经用/etc/sysctl.conf中保存的vm.legacy_va_layout=1kernel.randomize_va_space=0设置重新启动。 仍然没有改变。

编辑

在内核2.6.26(和2.6.25)上使用kernel.randomize_va_space=0导致strace legacy-gcc报告的以下brk()调用:

brk(0x80556d4) = 0x8056000

这表明brk()失败,但看起来像是失败了,因为数据段已经超出了请求的范围。 使用objdump,我可以看到数据段应该在0x805518c结束,而失败的brk()表示数据段当前在0x8056000结束:

部分:
 Idx名称大小VMA LMA文件closuresAlgn
   0 .interp 00000013 080480d4 080480d4 000000d4 2 ** 0
                  内容,ALLOC,LOAD,READONLY,DATA
   1 .hash 000001a0 080480e8 080480e8 000000e8 2 ** 2
                  内容,ALLOC,LOAD,READONLY,DATA
   2 .dynsym 00000410 08048288 08048288 00000288 2 ** 2
                  内容,ALLOC,LOAD,READONLY,DATA
   3 .dynstr 0000020e 08048698 08048698 00000698 2 ** 0
                  内容,ALLOC,LOAD,READONLY,DATA
   4 .rel.bss 00000038 080488a8 080488a8 000008a8 2 ** 2
                  内容,ALLOC,LOAD,READONLY,DATA
   5 .rel.plt 00000158 080488e0 080488e0 000008e0 2 ** 2
                  内容,ALLOC,LOAD,READONLY,DATA
   6 .init 00000008 08048a40 08048a40 00000a40 2 ** 4
                  目录,ALLOC,LOAD,READONLY,CODE
   7 .plt 000002c0 08048a48 08048a48 00000a48 2 ** 2
                  目录,ALLOC,LOAD,READONLY,CODE
   8 .text 000086cc 08048d10 08048d10 00000d10 2 ** 4
                  目录,ALLOC,LOAD,READONLY,CODE
   9 .fini 00000008 080513e0 080513e0 000093e0 2 ** 4
                  目录,ALLOC,LOAD,READONLY,CODE
  10.rodata 000027d0 080513e8 080513e8 000093e8 2 ** 0
                  内容,ALLOC,LOAD,READONLY,DATA
  11.数据000005d4 08054bb8 08054bb8 0000bbb8 2 ** 2
                  目录,ALLOC,负载,数据
  12。茶几00000008 0805518c 0805518c 0000c18c 2 ** 2
                  目录,ALLOC,负载,数据
  13 .dtors 00000008 08055194 08055194 0000c194 2 ** 2
                  目录,ALLOC,负载,数据
  14 .got 000000b8 0805519c 0805519c 0000c19c 2 ** 2
                  目录,ALLOC,负载,数据
  15.dynamic00000088 08055254 08055254 0000c254 2 ** 2
                  目录,ALLOC,负载,数据
  16 .bss 000003b8 080552dc 080552dc 0000c2dc 2 ** 3
                   ALLOC
  17 .note 00000064 00000000 00000000 0000c2dc 2 ** 0
                  内容,READONLY
  180000 00000062 00000000 00000000 0000c340 2 ** 0
                  内容,READONLY
符号表:
没有符号

编辑

回声ephemient的评论下面:“很奇怪把GCC当作一个无源二进制文件”!

因此,使用strace,objdump,gdb和我对386汇编器和体系结构的有限理解,我已经将问题追溯到遗留代码中的第一个malloc调用。 传统的gcc调用malloc,它返回NULL,导致stderr上的“虚拟内存耗尽”消息。 这个malloc是在libc.so.5中,它调用getenv一堆,最后调用brk()…我想增加堆…失败。

从这里我只能推测,这个问题比brk随机化要多,或者我还没有完全禁用brk随机化,尽piperandomize_va_space = 0和legacy_va_layout = 1的sysctl设置。

Solutions Collecting From Web of "传统的gcc编译器问题"

将linux +旧的gcc安装到虚拟机上。

你有这个自定义编译器的来源吗? 如果你可以恢复2.6.0的基准(这应该是相对容易的),那么差异和补丁应该恢复你的变更集。

那么我会推荐的是使用该更改集来构建一个新版本,而不是最新的gcc。 然后将其置于配置控制之下。

对不起,不要吼。 这只是30年来我一直在说同样的事情。

你可以stracegcc-2.6.0可执行文件? 它可能正在读取/proc/$$/maps ,当输出以不重要的方式变化时会变得困惑。 最近在2.6.28和2.6.29之间发现了类似的问题。

如果是这样的话,可以破解/usr/src/linux/fs/proc/task_mmu.c或其附近的恢复旧的输出,或者设置一些$LD_PRELOAD来伪造gcc读取另一个文件。

编辑

既然你提到brk

CONFIG_COMPAT_BRK使默认的kernel.randomize_va_space=1而不是2 ,但仍然随机kernel.randomize_va_space=1堆( brk )以外的所有内容。

如果echo 0 > /proc/sys/kernel/randomize_va_spacesysctl kernel.randomize_va_space=0 (等价),则查看问题是否消失。

如果是这样,请将kernel.randomize_va_space = 0添加到/etc/sysctl.conf或将norandmaps添加到内核命令行(等效),然后再次开心。

我遇到这个 ,想到你的问题。 也许你可以找到一种方式来玩二进制将其移动到ELF格式? 或者可能是无关紧要的,但是使用objdump可以为您提供更多的信息。

你可以看看进程内存映射吗?

所以我已经做了一些…这不是一个完整的解决方案,但它确实超过了我与遗留gcc的原始问题。

在.plt(过程链接表)中放置每个libc调用的断点我看到malloc(在libc.so.5中)调用getenv()来获得:

     MALLOC_TRIM_THRESHOLD_
     MALLOC_TOP_PAD_
     MALLOC_MMAP_THRESHOLD_
     MALLOC_MMAP_MAX_
     MALLOC_CHECK_

所以我网络搜索这些,并找到这个建议

     setenv MALLOC_TOP_PAD_ 536870912

那么传统的gcc工作!

但是没有免费的,在失败之前,它已经到达了构建的链接,所以我们还有一些进一步的问题:-(这是报告:

    虚拟内存超出“新”

在/etc/sysctl.conf中我有:

     kernel.randomize_va_space = 0
     vm.legacy_va_layout = 1

它仍然工作相同,如果

     kernel.randomize_va_space = 1
     vm.legacy_va_layout = 0

但如果没有

  kernel.randomize_va_space = 2 

有一个建议使用“ldd”来查看共享库的依赖关系:遗留的gcc只需要libc5,但遗留的nld也需要libg ++。so.27,libstdc ++。so.27,libm.so.5,显然有一个libc ++版本的libg ++。so.27(libg ++ 27-altdev ??)和libc5-compat?

所以,正如我所说,还没有家免费…越来越近。 我可能会发布有关nld问题的新问题。

编辑

我原本不会接受这个答案,因为我仍然有相应的遗留链接器的问题,但为了至少在这个问题上得到一些结论,我正在重新思考这个问题。

谢谢你出去:

  • an0nym0usc0ward建议使用vm(最终可能成为Accepted Answer)
  • ephemient建议使用strace,并帮助使用stackoverflow
  • shodanex建议使用objdump

编辑

下面是我学到的最后一个东西,现在我将接受虚拟机解决方案,因为我无法以任何其他方式完全解决(至少在为此分配的时间)。

较新的内核有一个CONFIG_COMPAT_BRK构建标志允许libc5被使用,所以大概用这个标志来构建一个新的内核将会解决这个问题(并且通过内核src来看,它看起来像是会的,但是我不能确定,因为我做了不遵循所有的路径)。 还有另外一种记录的方法来允许libc5在运行时使用(而不是在内核编译时):sudo sysctl -w kernel.randomize_va_space = 0。 然而,这并不是一个完整的工作,一些(大多数?)libc5应用程序仍然会崩溃,例如我们的遗留编译器和链接器。 这似乎是由于新旧内核之间的对齐假设不同所致。 我已经修补了连接器二进制文件,使其认为它有一个更大的bss部分,以便将bss的末端放到一个页面边界上,并且当sysctl var kernel.randomize_va_space = 0时,这可以在较新的内核上工作。 这对我来说并不是一个令人满意的解决方案,因为我盲目地修补了一个关键的二进制可执行文件,即使在较新的内核上运行修补的链接程序,也会产生与旧内核上运行的原始链接程序相同的输出结果,一些其他的链接器输入(即我们改变被链接的程序)也会产生相同的结果。

如果系统死了,你能不能简单地制作一张可以重新安装的光盘映像? 或者做一个虚拟机?