Нативный код Android падает в режиме большого пальца, но не в режиме охраны - PullRequest
2 голосов
/ 02 апреля 2012

Я пытаюсь скомпилировать и запустить собственный код для платформы Android с помощью Android NDK. Во многих местах кода я пытаюсь привести короткий целочисленный указатель к целочисленному указателю, поэтому у него возникают проблемы с выравниванием памяти, хотя он правильно работает с X86. Я компилирую код в режиме большого пальца, код не работает из-за невыровненного доступа, как я уже говорил выше. Но если я скомпилирую код в режиме ARM, он не сбоит и не работает должным образом.

Я сомневаюсь, почему код не падает при компиляции в режиме arm, хотя у него есть проблемы с выравниванием памяти.

У меня очень мало знаний о наборах команд ARM и THUMB. Я знаю, что набор инструкций ARM имеет ширину 32 бита, а большой палец - 16 бит. Но как это влияет на непривязанный доступ?

Ответы [ 2 ]

2 голосов
/ 02 апреля 2012

Не думаю, что сбой вызван длиной кодировки инструкций. Режимы ARM и Thumb должны иметь одинаковую способность загружать данные с выровненных или невыровненных адресов.

Во-первых, используете ли вы реальное оборудование ARMv5, которое действительно не допускает выравнивания 32-битных нагрузок? Потому что более новые чипы ARM, например, чипы ARMv6 ( ARM11 ), работающие под управлением Android, скомпилированные для ARMv5TE, могут выполнять 32-разрядные загрузки без выравнивания и не дают сбоя. Конечно, если ваш манифест утверждает, что он скомпилирован для ARMv5TE, тогда устройство Android, работающее на реальном оборудовании ARMv5, с радостью установит его и выйдет из строя - вы должны убедиться, что ваше приложение действительно совместимо с тем, что оно заявляет.

Qemu (включая эмулятор, включенный в Android SDK) не правильно эмулирует сбой при невыровненных 32-битных нагрузках, когда он эмулирует чип arm926ej-s (ARMv5TEJ). Вы не можете полагаться на эмулятор, чтобы поймать это. В этом отношении это действительно хорошо только для разработки на Java.

Можете ли вы увидеть сбой в GDB? Можете ли вы показать дамп регистра и увидеть загрузку с ненастроенного адреса? Вы уверены, что компилятор не меняет смысл вашего кода (допустимым образом)?

Для переносимости после x86, вы действительно не должны выполнять приведение от uint16_t* до uint32_t*. Язык C не гарантирует, что они будут работать. Технически ваш код всегда был «неправильным». Посмотрите на переносимый код в дикой природе: он использует макросы препроцессора или статические встроенные функции для абстрагирования от таких понятий, как «get_unaligned_le32» или целых функций, которые в x86 полагаются на доступ без выравнивания.

0 голосов
/ 03 апреля 2012

Инструкции большого пальца имеют длину 16 бит каждая, в то время как ARM имеют размер 32 бита.

Это означает, что в режиме ARM гарантируется, что раздел данных в коде выровнен по 4 байта, но не в режиме большого пальца.

Вы можете попробовать настроить директивы. Синтаксис выравнивания варьируется в зависимости от компилятора / ассемблера.

Некоторые (аппаратно-зависимые) подпрограммы в некоторых библиотеках предполагают, что данные выровнены по 4 байта независимо от типа данных. Если это условие не выполняется, оно либо аварийно завершает работу, либо производительность сильно снижается.

Кроме того, если принять во внимание кэш, все равно целесообразно выровнять данные, критичные для производительности. Совместимое с кэшем выравнивание зависит от SoC, но обычно оно составляет 32 байт до ARM11, 64 байт в Coretex.

...