Перейти к содержанию
    

Неверное вычисление адресов mb-gcc при включении опции relax у линкера

Всем привет!

Обнаружилась одна очень неприятная ошибка в поведении линкера для microblaze (mb-ld), по крайней мере для Vivado 2019.2 (на других еще не проверял). Выражается она в неправильном вычислении линкером смещений упакованных структур, содержащихся внутри не упакованных. Так это проявилось у меня. При этом изменение порядка полей в структуре (сначала неупакованные данные, потом упакованные структуры) на первый взгляд убирает проблему, но пока гарантий нет никаких.Эта ошибка достаточно коварна, т.к. на её появление влияет также порядок вызова функций в программе. В моём случае добавления в начало main() вызова функции, использующего эти данные, устраняет ошибку обращения конкретно к этой структуре. Судя по наблюдаемому поведению линкера, проблема заключается в удалении из результирующего ELF "ненужных" команд imm 0, но без последующей коррекции смещений. Нашел сходный баг, которому уже 10 лет и он по-прежнему без движения. В нем описывается данное поведение только для исходников на ассемблере, но в моем случае то же самое наблюдается и для исходников на C/C++. Слева результат objdump после компиляции с --no-relax, справа с опцией --relax:

1810986302_.thumb.png.ba74883e5bc9ebef708cd6a2261b602f.png
Как видно, была удалена та самая команда imm 0.

Поскольку при использовании для линковки mb-gcc опция --relax включена по-умолчанию, то такое поведение может внезапно выйти боком в самый неожиданный момент. Минус отключения relax - возрастание размера прошивки, но по-моему обычно стабильность важнее. Тем более что проверить, что именно ваш проект не подвержен этой ошибке можно только длительным тестированием и то гарантии в результате дать практически невозможно.

Кто-нибудь еще сталкивался с подобной проблемой? Может быть я что-то упускаю и есть другой путь обхода этой проблемы?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

чёто мне кажется теплое и мягкое...

какая связь между "Выражается она в неправильном вычислении линкером смещений упакованных структур, содержащихся внутри не упакованных." и изменением (наличия) тех или иных ассемблерных команд ???

Тестовый пример ???

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 минуту назад, Alex77 сказал:

Тестовый пример ???

Тестовый пример по ссылке https://sourceware.org/bugzilla/show_bug.cgi?id=11085

Вы описание этого бага в багзилле смотрели?

PS: Выделить пример в виде простого тестового модуля я пока не успел, а сам проект целиком, на котором это прекрасно видно, извините, выложить не могу.

2 минуты назад, Alex77 сказал:

какая связь между "Выражается она в неправильном вычислении линкером смещений упакованных структур, содержащихся внутри не упакованных." и изменением (наличия) тех или иных ассемблерных команд ???

Прямая связь через оптимизатор линкера, работа которого определяется наличием опции relax:

Цитата

       --relax
       --no-relax

           An option with machine dependent effects.  This option is only supported on a few targets.

           On some platforms the --relax option performs target specific, global optimizations that become possible when the linker resolves addressing in the program, such as relaxing address modes,
           synthesizing new instructions, selecting shorter version of current instructions, and combining constant values
.

           On some platforms these link time global optimizations may make symbolic debugging of the resulting executable impossible.  This is known to be the case for the Matsushita MN10200 and MN10300
           family of processors.

           On platforms where this is not supported, --relax is accepted, but ignored.

           On platforms where --relax is accepted the option --no-relax can be used to disable the feature.

Обратите внимание на выделенное. О чем это говорит?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1) ну как бы там говорится про исходный текст на асме.

2) у вас исходник на С ?

3) там говорится о сползании "меток"  на используемые функции.

4) и где там про "упакованные" структуры ???

Тестовый пример?

иначе это сотрясание воздуха.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

ещё раз перечитал...

1) я не заметил "Тестовый пример" по ссылке. я там вижу только "дизасм" объектного кода

2) и повторю вопрос " где там про "упакованные" структуры ??? "

"подымите мне веки"(с) "Вий"

 

"Выражается она в неправильном вычислении линкером смещений упакованных структур, содержащихся внутри не упакованных." и "только длительным тестированием" тоже как то не вяжется между собой.

Если линкёр начудил - то это "навсегда" и как следствие программа "всегда" будет иметь "доступ к левым данным" - а значит и глючить будет постоянно. Где здесь место для "только длительным тестированием" ? другое дело что искать (где) глюки можно долго, но глючить будет сразу...

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

44 минуты назад, Alex77 сказал:

1) ну как бы там говорится про исходный текст на асме.

Я показал, что у меня точно так же, как в описании бага в багзилле при наличии relax удаляются imm 0. У gcc трансляция, как ни странно, идёт через ассемблер. Поэтому эта проблема не зависит от формата исходного текста.

46 минут назад, Alex77 сказал:

2) у вас исходник на С ?

Чистый C.

46 минут назад, Alex77 сказал:

3) там говорится о сползании "меток"  на используемые функции.

У них это проявилось в виде сползания меток. У меня в виде сползания смещений на поля структуры, причём вычисленные через offsetof смещения, которые выводится в отладку, правильные. Т.е. проблема 100% на на фазе линковки.

48 минут назад, Alex77 сказал:

4) и где там про "упакованные" структуры ???

Там про это нет, но результат у меня тот же - неверные смещения (указатели) в итоговом файле.

50 минут назад, Alex77 сказал:

Тестовый пример?

Я обязательно попробую его сделать, в частности для того, чтобы сравнить поведение разных версий компиляторов. Но еще раз повторюсь: проблема возникает в очень узком диапазоне довольно большого по объему проекта. Сам проект я передать не могу. Вам показать значения указателей? Они отличаются на 28 байт в двух соседних функциях. При этом для одной функции в map-файле есть строчка с текстом "0x90c (size before relaxing)" - в этой функции указатели неверные, а у другой (с верными значениями указателей) такой строчки нет.

52 минуты назад, Alex77 сказал:

иначе это сотрясание воздуха.

Я не собираюсь вам что-либо доказывать. Проблему я описал, предупредил про опасность relax со ссылкой на баг в багзилле, который не был исправлен (статус NEW). Дальше думайте сами, хотя можете поучаствовать в создании тестового примера для отправки разработчикам.

17 минут назад, Alex77 сказал:

1) я не заметил "Тестовый пример" по ссылке. я там вижу только "дизасм" объектного кода

Объектного кода их тестового примера, на котором наблюдается это поведение. Перевести его в assembler не такая большая сложность. Но смысл? Если все пишут на C?

18 минут назад, Alex77 сказал:

2) и повторю вопрос " где там про "упакованные" структуры ??? "

Я не говорил, что там про упакованные структуры. Я говорил про сходные проблемы (неправильные смещения) при включении relax.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

ну у меня есть "куча" структур данных упакованных (вот не помню их "вложенность"), про опцию --relax  услышал только "сейчас". Она ж вроде как по умолчанию ? правда gcc древний у меня (ise 12). "таких проблем не видел".

опять же "там" утверждают что " We did not notice this behavior in linked object files compiled from C/C++ Code." по русски звучит "При компиляции с С/C++ Code  проблем нет".

Мне не нужны доказательства - мне важно (интересно) "мне надо бояться, скрытого глюка" ???

пс: мож всё ж тестовый пример сообразите ?

Изменено пользователем Alex77

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

3 минуты назад, Alex77 сказал:

ну у меня есть "куча" структур данных упакованных (вот не помню их "вложенность"), про опцию --relax  услышал только "сейчас". Она ж вроде как по умолчанию ? правда gcc древний у меня (ise 12). "таких проблем не видел".

У меня тоже до прошлой недели таких проблем не было, всё работало хорошо. Но внезапно перестало, причем перестал работать уже давно отлаженный код. Была гипотеза, что малину портит LTO, но его отключение ничего не дало. На той неделе про relax я тоже не знал, дошел до этого в принципе достаточно случайно только сегодня.

4 минуты назад, Alex77 сказал:

опять же "там" утверждают что " We did not notice this behavior in linked object files compiled from C/C++ Code." по русски звучит "При компиляции с С/C++ Code  проблем нет".

Почитайте про логику возникновения этой ошибки. Дело в удаляемых из кода "imm 0", которые могут быть в любом коде. Что в написанном вручную, что в коде после компилятора. В первом посте темы я как раз привёл иллюстрацию того, что включение relax удаляет эти команды из результирующего кода, делая его компактнее. Но видимо не всегда делает это правильно.

6 минут назад, Alex77 сказал:

Мне не нужны доказательства - мне важно (интересно) "мне надо бояться, скрытого глюка" ???

Каждый решает для себя, чего ему бояться. Форум - это место обмена опытом. Я наступил на эти грабли, провёл небольшое исследование, поделился результатом и решением, которое позволяет решить проблему. Мог не писать, но считаю что для всех будет полезнее делиться путём обхода граблей, чтобы не наступать на них по многу раз подряд.

8 минут назад, Alex77 сказал:

пс: мож всё ж тестовый пример сообразите ?

Я попробую его сделать, но не уверен, что получится сделать быстро.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

у меня mb-gcc (GCC) 4.1.2 20070214 (Xilinx 12.3 Build EDK_MS3.66 15 Jul 2010)

во всех объектниках есть "imm 0"

пробовал  подсунуть опцию  "--relax" - либо лыжи не идут либо gcc игнорирует полностью сию опцию

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

У меня поновее будет:
 

mb-gcc --version
mb-gcc (crosstool-NG 1.20.0) 8.2.0
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  
mb-ld --version
GNU ld (crosstool-NG 1.20.0) 2.31
Copyright (C) 2018 Free Software Foundation, Inc.
This program is free software; you may redistribute it under the terms of
the GNU General Public License version 3 or (at your option) a later version.
This program has absolutely no warranty.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Продолжение истории. Собрал комплект с gcc версии 10.2.0 из исходников с сайта Xilinx. С ним проект собирается и работает успешно, т.е. искажений смещений в структурах (указателей) похоже нет. Глобальным отличием получаемых объектных файлов оказалось размещение глобальных структур в отдельных секциях .bss.<имя структуры> у gcc 10.2.0, в отличие от размещения в COMMON у gcc 8.2.0 (и там, и там использовался ключ -fdata-sections). Кроме этого я попробовал собрать объектные файлы gcc 8.2.0, а слинковать финальный elf с помощью ld из комплекта 10.2.0 и ошибка никуда не ушла (смещения в структурах искажаются). Т.е. получается, что линкер до сих пор содержит в себе эту проблему, но она маскируется благодаря изменившейся логике работы компилятора gcc 10.2.0, который честно выделяет отдельные секции для глобальных данных.

Я добавил отладку в линкер и судя по имеющимся результатам проблема заключается в том, что после выполнения фазы garbage collection (ключ --gc-sections у ld) происходит искажение индекса секции у символа, соответствующего глобальной структуре, принадлежащего к глобальной секции COMMON. После gc символ для структуры начинает принадлежать к секции .text и в результате в процессе выполнения оптимизации (relax) происходит его смещение в сторону начала адресов, т.к. линкер выполняет удаление ненужных команд "imm 0".

К сожалению нормального примера, который бы воспроизводил эту проблему на компактном тестовом проекте, до сих пор сделать не удалось.

Итого: пока я остановился на использовании компилятора 10.2.0, который пока что не был пойман на каких-либо ошибках, но тестирование продолжается.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Похоже, что дело в некорректной реализации кешировании таблицы символов, которая используется на фазе relax. При выполнении garbage collection ld анализирует используемые/неиспользуемые символы во всех входных секциях объектных файлов и для оптимизации кеширует их содержимое, но только для локальных символов. А во время фазы relax производится анализ всех символов, но если есть кеш, то использует его. Однако если разрешен garbage collection, то к моменту запуска фазы relax в кеше уже есть символы, но только локальные. Поэтому для глобальных происходит некорректная обработка.

В порядке эксперимента я попробовал отключить кеширование с помощью ключа линкера --no-keep-memory и что характерно, ld стал падать с ошибкой free():

/opt/Xilinx/Vitis/2021.1/gnu/microblaze/lin/bin/mb-gcc ..... microblaze/libmicroblaze.a -Wl,--no-keep-memory
free(): invalid pointer
collect2.real: fatal error: ld terminated with signal 6 [Aborted]
compilation terminated.

При этом ld из комплекта 8.2.0 из комплекта 10.2.0 ведут себя одинаково.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В итоге разобрался с этими проблемами. Дело было в банальном выходе за пределы массивов описателей символов при обработке фазы relax, которые создавались при кешировании в процесс обработки. Поэтому получалось, что для глобальных символов, которые в контексте relax неактуальны, выполнялись дополнительные модификации, приводившие в итоге к сдвигу указателя в выходном двоичном файле.

Ошибка "free(): invalid pointer" при задании ключа -Wl,--no-keep-memory тоже была в функции relax.

В итоге ошибки поправил, на моей сборке проблем больше не наблюдалось, патчи прикладываю: mb-gnu-2021-0623-patches.tar.gz

PS: Если кто-нибудь знает адрес багтрекера Xilinx - напишите, пожалуйста. На сайте Xilinx я не нашел, на github у Xilinx GNU Toolchain только для Yocto (по-моему это немного другой тулчейн) и куда слать багрепорты и/или push-реквесты совершенно непонятно.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...