我们正在使用基于 gcc 2.6.0 的遗留编译器来交叉编译我们仍在使用的旧嵌入式处理器(是的,它自 1994 年以来仍在使用!)。为该芯片进行 gcc 移植的工程师早已离开。尽管我们可能能够从网络上的某个地方恢复GCC 2.6.0源,但该芯片的变更设置在公司历史大厅中消失了。直到最近,我们一直处于混乱状态,因为编译器仍在运行并生成了可用的可执行文件,但从 Linux 内核 2.6.25(以及 2.6.26)开始,它失败并显示以下消息 gcc: virtual memory exhausted...即使在没有参数或仅使用参数的情况下运行 -v. 。我已经使用 2.6.24 内核重新启动了我的开发系统(从 2.6.26 开始),编译器再次工作(使用 2.6.25 重新启动则不起作用)。

我们有一个系统保留在 2.6.24,只是为了构建该芯片,但感觉有点暴露,以防 Linux 世界发展到我们无法再重建可以运行的系统的地步。编译器(即我们的 2.6.24 系统死机了,我们无法让 2.6.24 在新系统上安装和运行,因为某些软件部件不再可用)。

有谁知道我们可以对更现代的安装做些什么来让这个遗留编译器运行?

编辑:

回答一些评论...

遗憾的是,我们芯片特有的源代码更改丢失了。这种损失发生在两个主要公司重组和几个系统管理员(其中几个确实留下了烂摊子)的过程中。我们现在使用配置控制,但是对于这个问题来说,关闭谷仓门已经太晚了。

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

最后,我按照 ehemient 的建议尝试了 strace,发现最后一个系统调用是 brk(),它在新系统(2.6.26 内核)上返回错误,在旧系统(2.6.24 内核)上返回成功。这表明我确实耗尽了虚拟内存,除了 tcsh“limit”在新旧系统上返回相同的值,并且 /proc/meminfo 显示新系统具有稍微更多的内存和更多的交换空间。也许是碎片问题或程序加载位置的问题?

我做了一些进一步的研究,并且在内核 2.6.25 中添加了“brk randomization”,但是 CONFIG_COMPAT_BRK 据说默认情况下启用(这会禁用 brk 随机化)。

编辑:

好的,更多信息:看来 brk 随机化确实是罪魁祸首,旧版 gcc 正在调用 brk() 来更改数据段的末尾,但现在失败了,导致旧版 gcc 报告“虚拟内存耗尽”。有一些记录在案的方法可以禁用 brk 随机化:

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

  • sudo sysctl -w kernel.randomize_va_space=0

  • 开始一个新的外壳 setarch i386 -R tcsh (或“-R -L”)

我已经尝试过它们,它们似乎确实有效果,因为 brk() 返回值与没有它们时不同(并且始终相同)(在内核 2.6.25 和 2.6.26 上都尝试过),但是 brk()仍然失败,因此旧版 gcc 仍然失败:-(。

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

编辑:

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

brk(0x80556d4) = 0x8056000

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

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .interp       00000013  080480d4  080480d4  000000d4  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  1 .hash         000001a0  080480e8  080480e8  000000e8  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  2 .dynsym       00000410  08048288  08048288  00000288  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  3 .dynstr       0000020e  08048698  08048698  00000698  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  4 .rel.bss      00000038  080488a8  080488a8  000008a8  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  5 .rel.plt      00000158  080488e0  080488e0  000008e0  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  6 .init         00000008  08048a40  08048a40  00000a40  2**4
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  7 .plt          000002c0  08048a48  08048a48  00000a48  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  8 .text         000086cc  08048d10  08048d10  00000d10  2**4
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  9 .fini         00000008  080513e0  080513e0  000093e0  2**4
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
 10 .rodata       000027d0  080513e8  080513e8  000093e8  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 11 .data         000005d4  08054bb8  08054bb8  0000bbb8  2**2
                  CONTENTS, ALLOC, LOAD, DATA
 12 .ctors        00000008  0805518c  0805518c  0000c18c  2**2
                  CONTENTS, ALLOC, LOAD, DATA
 13 .dtors        00000008  08055194  08055194  0000c194  2**2
                  CONTENTS, ALLOC, LOAD, DATA
 14 .got          000000b8  0805519c  0805519c  0000c19c  2**2
                  CONTENTS, ALLOC, LOAD, DATA
 15 .dynamic      00000088  08055254  08055254  0000c254  2**2
                  CONTENTS, ALLOC, LOAD, DATA
 16 .bss          000003b8  080552dc  080552dc  0000c2dc  2**3
                  ALLOC
 17 .note         00000064  00000000  00000000  0000c2dc  2**0
                  CONTENTS, READONLY
 18 .comment      00000062  00000000  00000000  0000c340  2**0
                  CONTENTS, READONLY
SYMBOL TABLE:
no symbols

编辑:

回应下面的 ephemient 评论:“将 GCC 视为没有源代码的二进制文件真是太奇怪了”!

因此,使用 strace、objdump、gdb 以及我对 386 汇编器和架构的有限理解,我将问题追溯到遗留代码中的第一个 malloc 调用。旧版 gcc 调用 malloc,它返回 NULL,这会导致 stderr 上出现“虚拟内存耗尽”消息。此malloc在libc.so.5中,它将getenv召集了很多次,最终调用brk()...我想增加堆......这失败了。

由此我只能推测问题不仅仅是 brk 随机化,或者我没有完全禁用 brk 随机化,尽管 randomize_va_space=0 和 Legacy_va_layout=1 sysctl 设置。

有帮助吗?

解决方案

将Linux +旧的GCC安装到虚拟机上。

其他提示

你有吗 来源 对于此自定义编译器?如果您可以恢复2.6.0基线(这应该相对容易),则diff和patch应该恢复您的更改集。

然后,我建议使用该更改集来构建针对最新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, ,但这仍然会随机化除堆之外的所有内容(brk).

看看您的问题是否会消失 echo 0 > /proc/sys/kernel/randomize_va_space 或者 sysctl kernel.randomize_va_space=0 (相等的)。

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

我碰到 这个 并想到你的问题。也许您可以找到一种使用二进制文件将其移至精灵格式的方法吗?或可能是无关紧要的,但是与Objdump一起玩可以为您提供更多信息。

您可以查看过程内存图吗?

因此,我已经解决了一些问题……这不是一个完整的解决方案,但是它确实已经解决了我对传统海湾合作委员会的原始问题。

在.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

然后,传统海湾合作委员会有效!!!!

但是,不自由家庭,它在失败之前就可以到达构建中的链接,因此我们拥有的旧版NLD进一步发生了一些事情:-(它正在报告:

    Virtual memory exceeded in `new'

在/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,显然有那里有。 libg ++的libc5版本so.27(libg ++ 27-altdev ??)和libc5-compat呢?

因此,正如我所说的,还没有自由回家...越来越近。我可能会发布一个有关NLD问题的新问题。

编辑:

我最初会避免“接受”此答案,因为我仍然对相应的旧链接器有问题,但是至少为了在这个问题上获得一些最终性,我正在重新考虑该立场。

谢谢,你出去了:

  • an0nym0usc0ward建议使用VM(最终可能成为公认的答案)
  • 用于建议使用strace并帮助Stackoverflow使用的临时使用者
  • Shodanex建议使用objdump

编辑

以下是我学到的最后一件事,现在我将接受VM解决方案,因为我无法完全解决任何其他方法(至少在为此分配的时间)。

较新的内核有一个config_compat_brk构建标志来允许使用libc5,因此大概可以用此标志构建新的内核可以解决该问题(并浏览核心SRC,看起来它会这样,但是我不能确定,因为我做到了,因为我做到了不遵循所有路径)。还有另一种记录的方法可以在运行时(而不是在内核构建时间)使用LIBC5:sudo sysctl -w kernel.randomize_va_space = 0。但是,这并不是完成完整的工作,有些(大多数?)LIBC5应用程序仍然会破裂,例如我们的传统编译器和链接器。这似乎是由于较新内核和旧内核之间的一致性假设的差异所致。我已经修补了链接器二进制文件,以使其认为它具有较大的BSS部分,以使BSS的末端到达页面边界,当Sysctl var kernel.randomize_va_space = 0时,这在较新的内核上起作用。这对我来说不是一个令人满意的解决方案,因为我盲目地修补了关键的二进制可执行文件,即使在较新的内核上运行修补的链接器,也对旧核上的原始链接器产生了一个相同的输出,但并不能证明这一点其他一些链接器输入(即我们更改正在链接的程序)也将产生相同的结果。

如果系统死亡,您是否可以简单地制作可以重新安装的光盘映像?还是制作VM?

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top