Я получаю ошибку связи:
опасное перемещение: l32r: буквально после использования:
Я все еще пытаюсь отладить; Однако я хочу лучше понять эту ошибку. Я понимаю, что такое переезд; Однако я не уверен, насколько это может быть опасно, и искал некоторые разъяснения. Также будет полезен небольшой фрагмент кода, который может генерировать ошибки такого типа.
Короче что такоеопасное перемещение«?
Это ответ из двух частей, так как здесь действительно два вопроса: один общий («что такое опасное перемещение?») И один специфический для 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 и выдает эту ошибку, это признак того, что ваш буквальный пул переполнен. Компилятор должен сгенерировать «клей», необходимый для переключения литеральных пулов в этом случае, однако: если это не так, поздравляем! Вы только что нашли ошибку компилятора!
Вот http://www.mail-archive.com/[email protected]/msg11488.html
Это может быть полезно для вас.
Удачи 🙂