Что означает опасная ошибка перемещения?

Я получаю ошибку связи:

опасное перемещение: l32r: буквально после использования:

Я все еще пытаюсь отладить; Однако я хочу лучше понять эту ошибку. Я понимаю, что такое переезд; Однако я не уверен, насколько это может быть опасно, и искал некоторые разъяснения. Также будет полезен небольшой фрагмент кода, который может генерировать ошибки такого типа.

Короче что такоеопасное перемещение«?

7

Решение

Это ответ из двух частей, так как здесь действительно два вопроса: один общий («что такое опасное перемещение?») И один специфический для Xtensa («почему вы не можете поместить литерал после того, как он используется в код?»).

В любом случае, что это за опасные переселения?

Чтобы понять, что такое «опасное перемещение», мы должны сначала понять, что такое перемещение. Поскольку компилятор генерирует объектный файл из некоторого фрагмента кода, он должен ссылаться на символы, которые определены где-то еще: возможно, в другом объектном файле в ссылке или в общей библиотеке. Однако компилятор не знает адреса внешних символов при компиляции заданного объектного файла. Он должен испускать перемещение, чтобы служить именованным заполнителем, сообщая компоновщику: «Хорошо, отправьте адрес foobar в это место, и, о, вы должны сделать X, Y и Z, чтобы оно вписывалось в инструкции там «.

В большинстве случаев это работает без проблем, вы получаете двоичный файл из своего компоновщика, а Боб — ваш дядя. Когда этот процесс прерывается, и компоновщик не может сделать адрес символа, который компилятор дал ему вписать в инструкции на месте перемещения, он отказывается и выбрасывает сообщение «опасное перемещение» (среди прочего — все -to-common ‘перемещение, усеченное до нужного’ также появляется из этого процесса), чтобы сообщить программисту, что что-то пошло не так.

Что не так с литералом, размещенным после того, где он используется?

Теперь, когда мы знаем, что такое общее «опасное перемещение», мы можем перейти ко второй половине сообщения об ошибке, а именно: «l32r: литерал помещен после использования». Xtensa использует инструкцию, известную как L32R загружать постоянные значения из памяти, которые не вписываются в Xtensa MOVI инструкция немедленной загрузки, которая имеет 12-битовое поле непосредственного подписания. L32R инструкция описана в Xtensa ISA ссылка следующее:

L32R — это 32-битная загрузка из памяти для ПК. Обычно используется для загрузки постоянной
значения в регистр, когда константа не может быть закодирована в инструкции MOVI.

L32R формирует виртуальный адрес, добавляя закодированное 16-битное одно расширенное постоянное значение
в командном слове, сдвинутом влево на два адреса L32R
плюс три с очищенными двумя младшими битами. Поэтому смещение всегда можно
указать 32-битные выровненные адреса от -262141 до -4 байтов от адреса L32R
инструкция. 32 бита (четыре байта) считываются с физического адреса. Эти данные затем
записано в адресный регистр at,

Учитывая ограничения на L32R цитируемое выше сообщение об ошибке довольно хорошо разбивается: компилятор сгенерировал L32R загрузить константу (которая может быть значением или адресом) где-то в вашем коде, но либо значение константы не было доступно компилятору (подумайте extern const), или адрес должен был быть заполнен компоновщиком (это вероятный случай). Итак, это испускало это L32R переезд, чтобы сказать компоновщику «заполнить пробел» в L32R инструкция с адресом постоянного значения или постоянным адресом где-то в вашей программе. Однако компоновщик не смог найти нигде в предыдущих 256 КБ кода — или литеральном пуле, в зависимости от того, как настроен ваш компилятор и ядро ​​Xtensa — чтобы запихнуть константу, поэтому он сдался и выдал сообщение об ошибке, которое вы спросили около.

Как это исправить?

К сожалению, «опасное перемещение» такого рода зависит от размера кода, поэтому, если у вас нет добросовестной ошибки компилятора или компоновщика, воспроизвести его с небольшим фрагментом кода будет невозможно. Однако есть две возможные причины, которые вы можете попытаться устранить.

Там нет места для моего буквального пула!

Если вы компилируете с -mno-text-section-literals (что по умолчанию), компоновщик получает литеральные пулы как отдельные секции, которые он затем должен чередовать с секциями кода. Если у вас есть особенно большой объектный файл в вашей ссылке, он может содержать более 256 КБ кода .text раздел, не оставляя нигде в диапазоне L32R инструкция для компоновщика для размещения соответствующего литерального раздела в пуле. Компилирование с -mtext-section-literals следует устранить ошибку; если он не работает, у вас уже есть этот флаг, или если вы используете -ffunction-sections (который помещает каждую функцию в отдельный раздел; иногда она используется во встроенной работе, чтобы компоновщик мог выбросить неиспользуемый код), читайте дальше.

Линкер (или ассемблер) до сих пор не может найти место для размещения моих литералов!

Когда компилятору и ассемблеру предписывается выдавать литералы в текстовый раздел, они ограничивают размещение литеральных пулов перед функциями, которые их используют (т.е. перед ENTRY инструкции функции), чтобы минимизировать риск того, что литеральные пулы будут выполняться как код, с явно плохими результатами. Если у вас есть очень длинная функция в вашем коде — я не могу понять, какая функция может генерировать более 256 КБ кода — литеральный пул «по умолчанию», помещенный перед ENTRY инструкция может оказаться вне диапазона L32R инструкции в конце функции. Обычно компилятор испускает директиву ассемблера, известную как .literal_position, а также прыжок вокруг литерала средней функции, чтобы предоставить ассемблеру и компоновщику дополнительное место для вставки литералов. Вы можете указать компилятору выводить список ассемблера, используя -save-temps а затем искать его .literal_position директивы; если нет в функции, которая имеет L32R инструкции мимо отметки 256KB, поздравляю! Вы только что нашли ошибку компилятора!

Что еще может произойти, чтобы произвести это?

Единственное другое обстоятельство, которое я вижу, которое может спровоцировать такую ​​проблему, — это то, что до ENTRY инструкция, что компилятор или компоновщик может поместить буквальный пул, а также компилятор не может понять это самостоятельно — это может происходить с обработчиками прерываний или функциями, которые явно размещаются в начале границы физической памяти сценарием компоновщика. В этом случае вам нужно будет вставить .literal_position директива и связанный с ней прыжок & этикетка от руки в asm оператор в верхней части функции преступника, чтобы предоставить ассемблеру место для размещения литералов функции преступника. Как ГАЗ ручной кладет это:

Ассемблер автоматически разместит текстовые секции буквальных пулов перед ENTRY
инструкции, поэтому .literal_position Директива нужна только для указания некоторых других
место для буквального пула. Вам может понадобиться добавить явную инструкцию перехода, чтобы пропустить
через встроенный буквальный пул.

Например, вектор прерывания не начинается с ENTRY инструкция так
Ассемблер не сможет автоматически найти подходящее место для размещения буквального пула.
Более того, код для вектора прерывания должен быть по определенному начальному адресу, поэтому
буквальный пул не может прийти до начала кода. Буквальный пул для
вектор должен быть явно расположен в середине вектора (перед любым использованием
литералы, из-за отрицательных смещений, используемых ПК-родственником L32R инструкции).

Подождите, я использую абсолютную буквальную опцию!

Если у вас есть LITBASE опция включена в ядре Xtensa и выдает эту ошибку, это признак того, что ваш буквальный пул переполнен. Компилятор должен сгенерировать «клей», необходимый для переключения литеральных пулов в этом случае, однако: если это не так, поздравляем! Вы только что нашли ошибку компилятора!

7

Другие решения

Вот http://www.mail-archive.com/[email protected]/msg11488.html
Это может быть полезно для вас.

Удачи 🙂

0

По вопросам рекламы [email protected]