#rust #mips #inline-assembly
Вопрос:
У меня есть следующая (упрощенная) функция, использующая встроенную сборку, нацеленную на mips:
#[naked]
pub unsafe extern "C" fn test() {
asm!(
".set noreorder",
"jr $ra",
"li $v0, 0x123",
options(noreturn),
)
}
Я ожидал, что это будет скомпилировано только в 2 указанные инструкции (в режиме выпуска), поскольку это голая функция, но break
в конце добавляется инструкция:
00000000 <test>:
0: 03e00008 jr ra
4: 24020123 li v0,291
8: 0000000d break
Я предполагаю, что это контрмера против неопределенного поведения либо rustc, либо llvm, но мне нужно создать точную сборку, которую я указываю в функции.
Есть ли какой-либо способ запретить rustc, llvm или ассемблеру генерировать эту дополнительную инструкцию в целом?
Я протестировал его на существующих целях, таких как mipsel-unknown-none
, и он также создал break
инструкцию, но я компилирую на следующей пользовательской цели, если это имеет значение:
{
"arch": "mips",
"cpu": "mips1",
"data-layout": "e-m:m-p:32:32-i8:8:32-i16:16:32-i32:32-n32-S32",
"emit-debug-gdb-scripts": false,
"executables": false,
"features": " mips32, soft-float, noabicalls",
"linker": "rust-lld",
"linker-flavor": "ld.lld",
"llvm-target": "mipsel-unknown-linux-gnu",
"relocation-model": "static",
"target-pointer-width": "32",
"panic-strategy": "abort",
"singlethread": true,
"dynamic-linking": false,
"function-sections": true
}
Я также использую a #![no_std]
и #![no_core]
staticlib
crate с внедренными необходимыми элементами lang и просто компилирую с помощью cargo build --release --target=my-target.json
Редактировать: После предложения Питера Кордеса я попробовал то же самое в C с
__attribute__((naked)) void test() {
__asm__(
".set noreordern"
"jr $ran"
"li $v0, 0x123n"
);
}
Скомпилировано с использованием
clang -O3 test.c -c -o test.o -target mips-unknown-none
И результат
00000000 <test>:
0: 03e00008 jr ra
4: 24020123 li v0,291
Без a break
, так что, похоже, он был включен компилятором rust.
Комментарии:
1. Если вы удалите noreturn, возвращает ли он нормальную функцию return? Учитывая, что это голая функция, я не уверен. В любом случае, похоже, стоит попробовать.
2. @DavidWohlferd К сожалению, если я ее удалю, я получу предупреждение (в котором говорится, что оно скоро будет переведено в ошибку), в котором говорится, что asm в голых функциях должен иметь
noreturn
.3. Интересно, делает ли clang это с помощью встроенного asm C для MIPS?
4. @PeterCordes На самом деле этого не происходит (см. Редактирование вопроса), поэтому кажется, что компилятор rust добавляет его в какой-то момент, я пойду проверю излучаемый llvm ir, чтобы увидеть, есть ли он.
5. На самом деле, как ни странно, если я создаю llvm-ir из rust, передаю его в llvm с
llc test.ir -o test.s -mtriple=mips-unknown-none
помощью, а затем собираю его сmips-unknown-gnu-as test.s -o test.o
помощью, у него также нет инструкции break, я предполагаю, что это какой-то флаг, который rustc передает llvm, который вызывает это
Ответ №1:
Да! Выполните одно из:
- Добавьте
"trap_unreachable": false
в свой target.json - Сборка с
RUSTFLAGS=-Ztrap-unreachable=no
помощью . (хотя только по ночам)
К сожалению, это не очень хорошо документировано. Дальнейшее чтение: PR, где была добавлена генерация команды trap , PR, где был добавлен trap-unreachable = no
Комментарии:
1. В первом она должна быть
trap-unreachable
(с дефисом вместо подчеркивания), но, кроме этого, это работает отлично! Спасибо за отслеживание реализации и пометку PR2. Странно, что это вообще необходимо в
naked
функции; это особый случай, когда выполнение никогда не должно выпадать из нижней части инструкции asm.