Программно вызвать исключение Undefined Instruction
Я хочу вызвать исключение неопределенной инструкции ARM Cortex-M3 для теста моего тестового прибора. Компилятор IAR поддерживает это с помощью встроенной сборки следующим образом:
asm ("udf.w # 0");
К сожалению, встроенный ассемблер GNU CC не знает этот код операции для NXP LPC177x8x. Это пишет диагностику:
ccw3kZ46.s:404: Error: bad instruction `udf.w #0'
Как я могу создать функцию, которая вызывает исключение Undefined Instruction?
4 ответа
Опираясь на ответ Masta79:
В справочном руководстве по архитектуре ARMv7-M приведена кодировка "навсегда неопределенная" - ARM DDI 0403D ( заполнитель документации, требуется регистрация). Кодировка - 0xf7fXaXXX (где "X" игнорируется). Конечно, выборки инструкций имеют младший порядок, поэтому (без тестирования):
asm volatile (".word 0xf7f0a000\n");
должен давать гарантированную неопределенную инструкцию на любом процессоре ARMv7-M или новее.
Некоторая дополнительная информация...
Одна из встроенных функций GCC
void __builtin_trap (void)
Эта функция приводит к аварийному завершению программы. GCC реализует эту функцию, используя целевой механизм (например, намеренное выполнение недопустимой инструкции) или вызывая прерывание. Используемый механизм может варьироваться от релиза к релизу, поэтому не стоит полагаться на какую-либо конкретную реализацию.
Его реализация для ARMv7:
(define_insn "trap"
[(trap_if (const_int 1) (const_int 0))]
""
"*
if (TARGET_ARM)
return \".inst\\t0xe7f000f0\";
else
return \".inst\\t0xdeff\";
"
[(set (attr "length")
(if_then_else (eq_attr "is_thumb" "yes")
(const_int 2)
(const_int 4)))
(set_attr "type" "trap")
(set_attr "conds" "unconditional")]
)
Так что для режима ARM сгенерирует gcc 0x7f000f0 (f0 00 f0 07)
и для других режимов 0xdeff (ff de)
(пригодится при разборке / отладке).
these encodings match the UDF instruction that is defined in the most
recent edition of the ARM architecture reference manual.
Thumb: 0xde00 | imm8 (we chose 0xff for the imm8)
ARM: 0xe7f000f0 | (imm12 << 8) | imm4 (we chose to use 0 for both imms)
Для LLVM __builtin_trap
генерируемые значения 0xe7ffdefe
а также 0xdefe
:
case ARM::TRAP: {
// Non-Darwin binutils don't yet support the "trap" mnemonic.
// FIXME: Remove this special case when they do.
if (!Subtarget->isTargetDarwin()) {
//.long 0xe7ffdefe @ trap
uint32_t Val = 0xe7ffdefeUL;
OutStreamer.AddComment("trap");
OutStreamer.EmitIntValue(Val, 4);
return;
}
break;
}
case ARM::tTRAP: {
// Non-Darwin binutils don't yet support the "trap" mnemonic.
// FIXME: Remove this special case when they do.
if (!Subtarget->isTargetDarwin()) {
//.short 57086 @ trap
uint16_t Val = 0xdefe;
OutStreamer.AddComment("trap");
OutStreamer.EmitIntValue(Val, 2);
return;
}
break;
}
В [1] есть разные официальные неопределенные инструкции (ищите UDF; .
ниже можно заменить любой шестнадцатеричной цифрой):
0xe7f...f.
- кодировка ARM или A1 (ARMv4T, ARMv5T, ARMv6, ARMv7)0xde..
- кодирование большого пальца или T1 (ARMv4T, ARMv5T, ARMv6, ARMv7)0xf7f.a...
- кодировка Thumb2 или T2 (ARMv6T2, ARMv7)
Есть и другие, но они, вероятно, так же, как и будущее.
Что касается генерации кода, который его запускает, вы можете просто использовать .short
или же .word
, как это:
asm volatile (".short 0xde00\n");
/ * большой палец незаконная инструкция */asm volatile (".word 0xe7f000f0\n");
/ * вооружить незаконную инструкцию */asm volatile (".word 0xe7f0def0\n");
/ * рука + палец недопустимая инструкция */
Обратите внимание, что последний будет декодировать в 0xdef0
, 0xe7f0
в контексте большого пальца, и, следовательно, также вызвать неопределенное исключение инструкции.
[1] http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.subset.architecture.reference/index.html
Версия thumb-16 постоянно неопределенной инструкции 0xDExx
, Таким образом, вы можете сделать это в своем коде, чтобы вызвать исключение:
.short 0xde00
Ссылка: Справочное руководство по архитектуре ARMv7-M, раздел A5.2.6.
(Обратите внимание, что кодирование 0xF7Fx, 0xAxxx также постоянно не определено, но является 32-битной инструкцией.)