Ответвление на символ переменного тока из встроенной сборки большого пальца - PullRequest
0 голосов
/ 22 мая 2018

Я на устройстве Cortex-M0 + (только с большим пальцем) и пытаюсь динамически сгенерировать некоторый код в оперативной памяти, а затем перейти к нему, например, так:

uint16_t code_buf[18];
...
void jump() {
  register volatile uint32_t* PASET asm("r0") = &(PA->OUTSET.reg);
  register volatile uint32_t* PACLR asm("r1") = &(PA->OUTCLR.reg);
  register uint32_t set asm("r2") = startset;
  register uint32_t cl0 asm("r3") = clears[0];
  register uint32_t cl1 asm("r4") = clears[1];
  register uint32_t cl2 asm("r5") = clears[2];
  register uint32_t cl3 asm("r6") = clears[3];
  register uint32_t dl0 asm("r8") = delays[0];
  register uint32_t dl1 asm("r9") = delays[1];
  register uint32_t dl2 asm("r10") = delays[2];
  register uint32_t dl3 asm("r11") = delays[3];
  asm volatile (
    "bl code_buf\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"
  );
}

Код в code_bufбудет использовать аргументы, передаваемые через регистры (поэтому я форсирую конкретные регистры).Этот код компилируется нормально, но когда я смотрю на разборку, инструкция перехода была изменена на

     a14:   f004 ebb0   blx 0x5178

, которая будет пытаться переключить процессор в режим ARM и вызвать HardFault.Есть ли способ заставить ассемблер сохранить ветку как простой бл?

Ответы [ 3 ]

0 голосов
/ 23 мая 2018

IDK, почему ваш ассемблер изменит bl на blx.Мой не использует arm-none-eabi-gcc 7.3.0 в Arch Linux.arm-none-eabi-as --version показывает Binutils 2.30.

unsigned short code_buf[18];
void jump() {
  asm("bl code_buf");
  asm("blx code_buf");  // still assembles to BL, not BLX
//  asm("blx jump");
//  asm("bl jump");
}

, скомпилированный с arm-none-eabi-gcc -O2 -nostdlib arm-bl.c -mcpu=cortex-m0plus -mthumb (я создал связанный исполняемый файл с -nostdlib, чтобы я мог видеть фактические смещения ветвей, а не заполнители).

Разборкас arm-none-eabi-objdump -d a.out показывает

00008000 <jump>:
    8000:       f010 f804       bl      1800c <__data_start>
    8004:       f010 f802       bl      1800c <__data_start>
    8008:       4770            bx      lr
    800a:       46c0            nop                     ; (mov r8, r8)

Ваш f004 ebb0 может быть кодированием Thumb2 для BLX.Я не знаю, почему вы это получаете.

Кодировка Thumb для bl описана в разделе 5.19 этого руководства ISA ARM7TDMI ("длинная ветвь со ссылкой"),но в этом руководстве вообще не упоминается кодировка Thumb для blx (потому что это только Thumb, а не Thumb 2).Кодировка Thumb bl хранит смещение ветви, смещенное вправо на 1 (т.е. без младшего бита), и всегда остается в режиме Thumb.

На самом деле это две отдельные инструкции;один, который помещает старшие 12 бит смещения в LR, и другой, который разветвляет и обновляет LR по адресу возврата.(Этот хак из двух инструкций позволяет Thumb1 работать без 32-битных инструкций Thumb2).Обе инструкции начинаются с f, поэтому ваша разборка показывает, что вы получили что-то еще;первый 16-битный блок f004 ebb0 является настройкой LR, но ebb0 не соответствует ни одной инструкции Thumb 1.


Возможно, asm("bl code_buf+1" : ...); или blx code_buf+1 могут работать, если+1 убеждает ассемблера рассматривать его как цель большого пальца.Но вам может понадобиться использовать asm, чтобы каким-то образом применить директиву .thumb_func к code_buf, чтобы ваш ассемблер был доволен.

0 голосов
/ 24 мая 2018

Получается, что используемая мной цепочка инструментов (gcc 4.8) глючит и делает две ошибки: она интерпретирует code_buf как адрес руки и выдает фиктивный blx label, который даже недопустим для коры.m0 +.Я обновил его до 6.3.1, и встроенный asm был преобразован в bl label, как и предполагалось.

0 голосов
/ 23 мая 2018

Из раздела 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, а недопустимой инструкцией.Правильно ли настроен ваш компилятор?

...