2013-08-15 2 views
2

Я строю проект Windows Phone с некоторыми его частями в сборке. Мой файл сборки находится в режиме ARM (CODE32), и он пытается перейти к функции C, которую я знаю, скомпилирован для Thumb. Код выглядит следующим образом:ARM/Thumb interworking в сборке

ldr r12, [pFunc] 
    mov pc, r12 
pFunc 
    dcd My_C_Function 

Вот что странно. Значение в pFunc в фрагменте является указателем на функцию thunk plus one. То есть устанавливается 0-й бит, как если бы целью перехода был Thumb, а команда перехода - BX. Но трюк явно ARM! Thunk загружает адрес тела функции плюс один и выполняет BX для него, правильно переключая режимы.

Попытка BX к этому адресу, вероятно, потерпит крах, поскольку это переключит режимы и попытается выполнить код ARM в режиме Thumb, это не очень хорошая идея. Пытаться просто перейти на этот адрес (как это делает текущий код), вероятно, тоже произойдет сбой, потому что ПК окажется неравнозначным.

Я мог бы теоретически вручную очистить 0-й бит, а затем прыгнуть, но я должен подумать об ошибке. Thunk генерируется компилятором C - правильно? Компилятор C знает, что thunk - это код ARM. Адрес в pFunc генерируется компоновщиком, так как это межмодульный вызов. Таким образом, младший бит помещается туда компоновщиком; почему линкер не знает, что эти трюки являются ARM?

Любые объяснения, пожалуйста?

У меня сейчас нет устройства WP8, поэтому я не могу попробовать его в реальном оборудовании. Ужасно глядя на сгенерированный код - это единственная технология отладки, которая у меня есть :(

EDIT: но что, если эти громкости не являются ARM, но Thumb-2? Thumb-2 поддерживает 32-разрядную команду IIRC. то же, что и в режиме ARM? Как все-таки декодируют команды Thumb-2?

+0

Если вы определили все свои ярлыки прямо в сборке (с помощью ассемблера gnu вы преследуете метки ярлыков с помощью .thumb_func, не знаете, как это сделать с другими инструментальными целями), а C должен позаботиться о себе. оттуда ассемблер, компилятор и компоновщик позаботятся о bx на четный или нечетный адрес в зависимости от адресата. –

+0

Ассемблер - это аромат ARM от MASM. Я проверю, могу ли я соответствующим образом украсить ярлык. Но, по общему признаку, я не могу теоретически знать, какие режимы являются другими объектными файлами. Что делать, если они являются объектами сторонних разработчиков? Я бы ожидал, что компоновщик будет умным. –

+0

Это моя точка зрения, я бы ожидал, что компоновщик будет умным, используйте дизассемблер, если у вас есть возможность проверить и убедиться, что инструменты сделали это правильно. –

ответ

2

Дисассемблер (в частности, IDA Demo) вводит меня в заблуждение, объединяя несколько команд в одну строку. Он сделал одну линию mov из последовательности mov-orr-orr, которая предназначалась для назначения полной 32-разрядной константы регистру. В конце концов, толчки были Thumbks. Компилятор работает так, как он был разработан.

IDA в отличном состоянии. В глубине души я знал об этом конкретном поведении в отношении ARM, но на этот раз он поскользнулся.

Неплохо, спасибо и поддержите всех, кто пытался помочь.

3

Подробности, которые вы хотите, указаны в разделе «A2.3.2. Псевдокод подробностей операций с основными регистрами ARM» в «Справочном руководстве по архитектуре ARM», ARMv7 . -А и ARMv7-R издание»Вот соответствующая псевдокод (из приведенного выше руководства) о записи в регистр PC:

BXWritePC(bits(32) address) 
    if CurrentInstrSet() == InstrSet_ThumbEE then 
     if address<0> == '1' then 
      BranchTo(address<31:1>:'0'); // Remaining in ThumbEE state 
     else 
      UNPREDICTABLE; 
    else 
     if address<0> == '1' then 
      SelectInstrSet(InstrSet_Thumb); 
      BranchTo(address<31:1>:'0'); 
     elsif address<1> == '0' then 
      SelectInstrSet(InstrSet_ARM); 
      BranchTo(address); 
     else // address<1:0> == '10' 
      UNPREDICTABLE; 

Если Ио бит бит (бит 0) установлен, процессор очистит этот бит, переключится в режим Thumb и выполнит переход к новому адресу.

Данное поведение верно для ARMv7 и более поздних версий (т. Е. Применимо ко всем устройствам Windows Phone, но не для всех устройств Android/iOS).

+0

Это подтверждает мое подозрение, что код выключен, но не объясняет, почему компоновщик пишет указатель Thumby в пункт назначения ARMy. Это линкер, не так ли? –

+1

Непонятная часть в вашем вопросе: «Попытка просто перейти на этот адрес (как это делает текущий код), вероятно, тоже закончится крахом, потому что ПК закончит без выравнивания». Как предложено вышеописанным псевдокодом, процессор автоматически очистит младший бит и будет использовать его только как индикацию для переключения в режим Thumb. –

+0

IDK, какой инструмент отвечает за настройку бита 0 в указателях функций на Windows Phone, это может быть либо статический компоновщик (адреса экспортированных функций Thumb будут установлены бит 0), либо загрузчик (он может использовать metainfo о функциях Thumb для установки бит 0 в указателе в таблице импорта). Практически это мало. –

2

Возможно, у вас действительно есть действительная/настоящая проблема на вашей руке. Afaik Windows Phone - это required to be Thumb-2 only, поэтому использующий компоновщик, возможно, не сможет обрабатывать вызовы в режиме ARM. См. Ту же ссылку для некоторых соображений при смешивании сборки и C.

Если бы это был вопрос Linux/ELF, я бы ответил иначе;

Адрес под pFunc порождается линкера, так как это кросс-модуль вызова. Таким образом, младший бит размещается там компоновщиком.

pFunc порождается compiler и linker исправит его, когда вы создаете загружаемый образ, который уже будет полностью решена для статического перемещения вызовов.Все переносимые объектные файлы должны содержать таблицу о функциональных режимах, чтобы позднее компоновщики могли обрабатывать их и соответственно перемещать и обновлять последовательности вызовов.

См. ELF for the ARM Architecture - 4.6 Relocation, как это делается через ELF.

+0

Релевантная цитата: «Ассемблер устанавливает LSB каждого слова символа в разделе кода, потому что он интерпретирует их как инструкции назначения». Похоже, это возможно. –