Из раздела 4.1.1 Справочного руководства по архитектуре ARMv6-M :
Взаимодействие большого пальца удерживается как бит [0] адреса взаимодействия .Адреса взаимодействия используются в следующих инструкциях: BX
, BLX
или POP
, который загружает ПК.
ARMv6-M поддерживает только состояние выполнения команды Thumb, поэтому значение адреса бит [0] должно быть 1 в инструкциях по взаимодействию, в противном случае происходит сбой.Все инструкции игнорируют бит [0] и записывают биты [31: 1]: «0» при обновлении ПК.
Цель вашей ветви, code_buf
, будет выровнена по слову (возможно,выровнено по двойному слову), поэтому бит 0 будет очищен в своем адресе.Главное, чтобы бит 0 был установлен перед переходом, и даже если инструментальная цепочка выберет инструкцию по взаимодействию, вы останетесь в режиме большого пальца.
У меня нет среды разработки передо мнойчтобы проверить это, но я бы предложил привести к типу указатель на один байт и использовать арифметику указателя для установки бита 0:
uint8_t *thumb_target = ((uint8_t *)code_buf) + 1;
asm volatile (
"bl thumb_target\n"
: [set]"+r" (set) : [PASET]"r" (PASET), [PACLR]"r" (PACLR), [cl0]"r" (cl0), [cl1]"r" (cl1), [cl2]"r" (cl2), [cl3]"r" (cl3), [dl0]"r" (dl0), [dl1]"r" (dl1), [dl2]"r" (dl2), [dl3]"r" (dl3) : "lr"
);
Редактировать: Выше неработать, как указывает Питер Кордес, потому что локальная переменная не может использоваться во встроенном ASM в этом контексте.Не разбираясь во встроенном ASM gcc, я не буду пытаться это исправить.
Теперь у меня была возможность протестировать предоставленный код, а gcc 7.2.1 с -S -mtune=cortex-m0plus -fomit-frame-pointer
генерирует BL
не BLX
.
Редактировать 2: Документация (раздел A6.7.14) предполагает, что в архитектуре ARMv6-M присутствует только версия BLX с регистром назначения (это похоже на устройства ARMv7, с которыми я больше всего знаком), и поэтому мне кажется, что ошибка вызвана не попыткой переключения в режим ARM, а недопустимой инструкцией.Правильно ли настроен ваш компилятор?