【问题标题】:Removing appended "break" instruction in inline mips assembly删除内联 mips 程序集中附加的“中断”指令
【发布时间】:2021-12-11 05:11:03
【问题描述】:

我有以下(简化的)函数使用内联汇编,目标是 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
}

我还使用了 #![no_std]#![no_core] staticlib crate,实现了所需的 lang 项,并使用 cargo build --release --target=my-target.json 进行简单编译

编辑:根据 Peter Cordes 的建议,我在 C 中尝试了同样的方法

__attribute__((naked)) void test() {
    __asm__(
        ".set noreorder\n"
        "jr $ra\n"
        "li $v0, 0x123\n"
    );
}

编译使用

clang -O3 test.c -c -o test.o -target mips-unknown-none

结果是

00000000 <test>:
   0:   03e00008    jr  ra
   4:   24020123    li  v0,291

没有break,所以它似乎被 rust 编译器包含了。

【问题讨论】:

  • 如果去掉noreturn,是不是把正常的函数return了?鉴于它是一个裸函数,我不确定。无论如何,似乎要尝试一下。
  • @DavidWohlferd 不幸的是,如果我删除它,我会收到一条警告(表示它很快会升级为错误),说裸函数中的 asm 必须有 noreturn
  • 我想知道 clang 是否使用 C inline asm for MIPS 做到这一点?
  • @PeterCordes 实际上没有(参见问题编辑),所以似乎是 rust 编译器在某个时候添加了它,我会去检查发出的 llvm ir 看它是否存在.
  • 实际上,奇怪的是,如果我从 rust 中发出 llvm-ir,用 llc test.ir -o test.s -mtriple=mips-unknown-none 将它传递给 llvm,然后用 mips-unknown-gnu-as test.s -o test.o 组装它,它也没有 break 指令,我假设然后,是一些标志 rustc 传递给 llvm 导致这个

标签: rust mips inline-assembly


【解决方案1】:

是的!执行以下操作之一:

  • "trap_unreachable": false 添加到您的target.json
  • 使用RUSTFLAGS=-Ztrap-unreachable=no 构建。 (但仅限夜间)

不幸的是,它没有很好的记录。延伸阅读:PR where the trap instruction generation was addedPR where trap-unreachable=no was added

【讨论】:

  • 首先它应该是trap-unreachable(用连字符代替下划线),但除此之外,它完美地工作!感谢您跟踪实施并标记 PR
  • 奇怪的是,naked 函数根本需要这样做;这是一种特殊情况,执行不应该落在 asm 语句的底部。
猜你喜欢
  • 2018-12-13
  • 1970-01-01
  • 2013-04-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多