устаревшие проблемы с компилятором gcc - PullRequest
7 голосов
/ 23 апреля 2009

Мы используем устаревший компилятор, основанный на gcc 2.6.0, для кросс-компиляции для старого встроенного процессора, который мы все еще используем (да, он все еще используется с 1994 года!). Инженер, который сделал gcc-порт для этого чипа, давно ушел. Хотя мы можем восстановить исходный код gcc 2.6.0 из Интернета, набор изменений для этого чипа имеет исчез в залах корпоративной истории. До недавнего времени мы путались, поскольку компилятор все еще выполнял и создавал работоспособные исполняемые файлы, но начиная с ядра Linux 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 показывает, что в новых системах немного больше памяти и немного больше места подкачки. Может быть, это проблема фрагментации или куда загружается программа?

Я провел дальнейшие исследования, и в ядре 2.6.25 была добавлена ​​«рандомизация brk», однако 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, я отследил проблему до первого вызова malloc в устаревшем коде. Устаревший gcc вызывает malloc, который возвращает NULL, что приводит к сообщению «исчерпана виртуальная память» на stderr. Этот malloc находится в libc.so.5 и вызывает getenv несколько раз и в конечном итоге вызывает brk () ... я думаю, чтобы увеличить кучу ... который не удается.

Из этого я могу только предположить, что проблема заключается не только в рандомизации brk, либо я не полностью отключил рандомизацию brk, несмотря на то, что параметры sysctl randomize_va_space = 0 и legacy_va_layout = 1.

Ответы [ 6 ]

12 голосов
/ 23 апреля 2009

Установите linux + старый gcc на виртуальную машину.

5 голосов
/ 23 апреля 2009

Есть ли у вас исходники для этого пользовательского компилятора? Если вы можете восстановить базовый уровень 2.6.0 (и это должно быть относительно просто), тогда diff и patch должны восстановить ваш набор изменений.

То, что я тогда порекомендовал бы, это использовать этот набор изменений для создания новой версии в соответствии с последним gcc. И затем положить его под контроль конфигурации.

Извините, не хочу кричать. Просто я говорил то же самое в течение 30 лет.

2 голосов
/ 23 апреля 2009

Можете ли вы 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 в командную строку ядра (эквивалент) и будьте счастливы снова.

1 голос
/ 27 апреля 2009

Итак, я кое-что решил ... это не полное решение, но оно преодолевает первоначальную проблему, с которой я столкнулся с устаревшим 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 и по-видимому, существует версия libg ++ libc5. so.27 (libg ++ 27-altdev ??) а как насчет libc5-compat?

Так что, как я уже сказал, еще не дома свободным ... быть ближе. Я, вероятно, отправлю новый вопрос о проблеме nld.

Редактировать :

Изначально я воздерживался от «принятия» этого ответа, поскольку у меня все еще есть проблема с соответствующим унаследованным компоновщиком, но для того, чтобы хотя бы получить некоторую окончательность по этому вопросу, я переосмысливаю эту позицию.

Спасибо, вы вышли на:

  • an0nym0usc0ward за предложение использовать vm (которое в конечном итоге может стать принятым ответом)
  • эфемент для предложения использования 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. Это НЕ является удовлетворительным решением для меня, так как я слепо исправляю критический двоичный исполняемый файл, и хотя запуск исправленного компоновщика на более новом ядре дал немного идентичный вывод исходному компоновщику, запущенному на более старом ядре, это не доказывает, что некоторые другие входные данные компоновщика (т.е. мы меняем связываемую программу) также будут давать идентичные результаты.

1 голос
/ 24 апреля 2009

Я наткнулся на это и подумал о вашей проблеме. Может быть, вы можете найти способ поиграть с двоичным файлом, чтобы перевести его в формат ELF? Или, может быть, это не имеет значения, но игра с objdump может предоставить вам больше информации.

Можете ли вы взглянуть на карту памяти процесса?

0 голосов
/ 23 апреля 2009

Не могли бы вы просто создать образ диска, который можно переустановить, если система умрет? или сделать ВМ?

...