проблемы с устаревшим компилятором gcc
-
13-09-2019 - |
Вопрос
Мы используем устаревший компилятор, основанный на gcc 2.6.0, для перекрестной компиляции для старого встроенного процессора, который мы все еще используем (да, он все еще используется с 1994 года!).Инженер, который создавал порт gcc для этого чипа, уже давно ушел.Хотя мы могли бы восстановить исходный код gcc 2.6.0 откуда-нибудь в Интернете, набор изменений для этого чипа
исчез в залах корпоративной истории.До недавнего времени мы путались, поскольку компилятор все еще запускался и создавал работоспособные исполняемые файлы, но начиная с ядра Linux 2.6.25 (а также 2.6.26) он выдает сообщение об ошибке gcc: virtual memory exhausted
...даже при запуске без параметров или только с -v
.Я перезагрузил свою систему разработки (начиная с 2.6.26), используя ядро 2.6.24, и компилятор снова работает (перезагрузка с 2.6.25 - нет).
У нас есть одна система, которую мы сохраняем на версии 2.6.24 только с целью выполнения сборок для этого чипа, но чувствуем себя немного уязвимыми на случай, если мир Linux перейдет к тому, что мы больше не сможем перестроить систему, которая будет запускать компилятор (т.Е.наша система 2.6.24 умирает, и мы не можем установить и запустить 2.6.24 в новой системе, потому что некоторые части программного обеспечения больше недоступны).
Есть ли у кого-нибудь какие-либо идеи относительно того, что мы могли бы сделать с более современной установкой, чтобы запустить этот устаревший компилятор?
Редактировать:
Чтобы ответить на некоторые комментарии...
К сожалению, утрачены изменения исходного кода, характерные для нашего чипа.Эта потеря произошла из-за двух крупных реорганизаций компании и нескольких системных администраторов (пара из которых действительно привела к беспорядку).Теперь мы используем управление конфигурацией, но это приводит к закрытию двери сарая слишком поздно для решения этой проблемы.
Использование виртуальной машины - хорошая идея, и, возможно, именно это мы в конечном итоге и делаем.Спасибо вам за эту идею.
Наконец, я попробовал strace, как предложил ephemient, и обнаружил, что последним системным вызовом был brk(), который вернул ошибку в новой системе (ядро 2.6.26) и вернул успех в старой системе (ядро 2.6.24).Это означало бы, что у меня действительно заканчивается виртуальная память, за исключением того, что tcsh "limit" возвращает одинаковые значения в старых и новых системах, а /proc /meminfo показывает, что в новых системах немного больше памяти и совсем немного больше места подкачки.Может быть, это проблема фрагментации или того, куда загружается программа?
Я провел некоторые дальнейшие исследования, и, однако, "рандомизация brk" была добавлена в ядро 2.6.25 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=1
и vm.overcommit_memory=2
без каких-либо изменений, и я перезагрузился с помощью vm.legacy_va_layout=1
и kernel.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
Редактировать:
Чтобы повторить комментарий эфемера ниже:"Так странно рассматривать GCC как двоичный файл без исходного кода"!
Итак, используя strace, objdump, gdb и мое ограниченное понимание ассемблера и архитектуры 386, я проследил проблему до 1-го вызова malloc в устаревшем коде.Устаревший gcc вызывает malloc, который возвращает NULL, что приводит к сообщению "виртуальная память исчерпана" в stderr.Этот malloc находится в libc.so.5, и он вызывает getenv кучу раз и в конечном итоге вызывает brk()...Я думаю, чтобы увеличить кучу...который терпит неудачу.
Исходя из этого, я могу только предположить, что проблема заключается не только в рандомизации brk, или я не полностью отключил рандомизацию brk, несмотря на настройки sysctl randomize_va_space=0 и legacy_va_layout= 1.
Решение
Установите linux + старый gcc на виртуальную машину.
Другие советы
У вас есть необходимые источники для этого пользовательского компилятора?Если вы сможете восстановить базовую версию 2.6.0 (а это должно быть относительно легко), то diff и patch должны восстановить ваш набор изменений.
Тогда я бы порекомендовал использовать этот набор изменений для создания новой версии на основе обновленного gcc.А ЗАТЕМ ПОСТАВЬТЕ ЕГО ПОД КОНТРОЛЬ КОНФИГУРАЦИИ.
Извини, не хотел кричать.Просто я говорю одно и то же почти 30 лет.
Сможешь ли ты strace
тот самый gcc-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
перейдите в командную строку ядра (эквивалент) и снова будьте счастливы.
Я наткнулся на это и подумал о твоей проблеме.Может быть, вы сможете найти способ поиграть с двоичным файлом, чтобы перевести его в формат ELF?Или, может быть, это не имеет значения, но игра с objdump может предоставить вам больше информации.
Можете ли вы взглянуть на карту памяти процесса ?
Итак, я кое-что придумал...это не полное решение, но оно устраняет первоначальную проблему, которая у меня была с устаревшим gcc.
Установка точек останова при каждом вызове libc в .plt (таблица привязки процедур) Я вижу, что 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 РАБОТАЕТ!!!!
Но не бесплатно для дома, он перешел по ссылке в сборке перед сбоем, так что с устаревшим 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 и, по-видимому, существует libc5-версия libg ++.so.27 (libg ++ 27-altdev ??) а как насчет libc5-compat?
Так что, как я уже сказал, я еще не свободен от дома...становлюсь все ближе.Вероятно, я опубликую новый вопрос о проблеме nld.
Редактировать:
Изначально я собирался воздержаться от "Принятия" этого ответа, поскольку у меня все еще есть проблема с соответствующим устаревшим компоновщиком, но для того, чтобы получить хотя бы некоторую окончательность в этом вопросе, я переосмысливаю эту позицию.
Спасибо, что вышли на улицу, чтобы:
- an0nym0usc0ward за предложение использовать виртуальную машину (которое в конечном итоге может стать принятым ответом)
- эфемерно для того, чтобы предложить использовать strace, и помочь с использованием stackoverflow
- shodanex за предложение использовать objdump
Редактировать
Ниже приведен последний материал, который я выучил, и теперь я приму решение виртуальной машины, поскольку я не мог полностью решить его каким-либо другим способом (по крайней мере, за отведенное для этого время).
Более новые ядра имеют флаг сборки CONFIG_COMPAT_BRK, позволяющий использовать libc5, поэтому, предположительно, создание нового ядра с этим флагом устранит проблему (и, просматривая src ядра, похоже, что так и будет, но я не могу быть уверен, поскольку я не следовал всем путям).Существует также другой документированный способ разрешить использование libc5 во время выполнения (а не во время сборки ядра).:sudo sysctl -w ядро.randomize_va_space=0.Это, однако, не выполняет полную работу, и некоторые (большинство?) приложения libc5 все равно будут ломаться, напримернаш устаревший компилятор и компоновщик.По-видимому, это связано с различием в предположениях о выравнивании между более новым и старым ядрами.Я исправил двоичный файл компоновщика, чтобы заставить его думать, что у него есть раздел bss большего размера, чтобы довести конец bss до границы страницы, и это работает на более новом ядре, когда sysctl var kernel.randomize_va_space=0.Это НЕ является удовлетворительным решением для меня, поскольку я слепо исправляю критический двоичный исполняемый файл, и даже несмотря на то, что запуск исправленного компоновщика на более новом ядре выдал результат, немного идентичный исходному компоновщику, запущенному на более старом ядре, это не доказывает, что какой-то другой ввод компоновщика (т. Е.мы меняем программу, на которую ссылаемся), также приведет к идентичным результатам.
Не могли бы вы просто создать образ диска, который можно будет переустановить, если система выйдет из строя?или создать виртуальную машину?