Compiling Inline asm with 1.73.0, error: invalid CFI advance_loc expression

When I build https://github.com/tipo159/rust-instruction-dispatch/tree/main/Rust/direct-threading with Rustc 1.73.0, I get the following error.

$ cargo build      
Compiling direct-threading v0.1.0 (rust-instruction-dispatch/Rust/direct-threading)
error: invalid CFI advance_loc expression

error: could not compile `direct-threading' (lib) due to previous error

This error message does not tell me which line of the program is the problem, so please let me know how to fix it.

I don't know the exact issue, but your code had UB. You aren't allowed to jump out of or into the middle of an inline asm block. The compiler doesn't know that there is a control-flow edge between the jump and the label, so it may remove the label entirely if the inline asm block seems unreachable. In addition inline asm blocks may actually be implemented as an external function. In this case jumping into the middle of an inline asm block would corrupt the stack.

1 Like

I think the error is caused by inline asm related changes in 1.73, since 1.72.1 was able to compile as shown below.

cargo build
   Compiling direct-threading v0.1.0 (rust-instruction-dispatch/Rust/direct-threading)
    Finished dev [unoptimized + debuginfo] target(s) in 0.76s

The thing with UB is that it may just happen to work by chance, but there is no guarantee that it will remain working. And not working can both be a compile error as well as silent corruption or a noisy crash at runtime. In your case it may just be the case that the update to LLVM 17 added an optimization exploiting this UB resulting in invalid ir that was later catched or maybe LLVM 17 introduced an extra validation for this kind of invalid ir?

In any case to quote the exact rules you are violating from https://doc.rust-lang.org/reference/inline-assembly.html#rules-for-inline-assembly:

Jumping to other inline asm blocks in the same function is not allowed:

When returning to a different asm! block than you entered (e.g. for context switching), these registers must contain the value they had upon entering the asm! block that you are exiting.

  • You cannot exit an asm! block that has not been entered.
  • [...]
  • You cannot jump from an address in one asm! block to an address in another, even within the same function or block, without treating their contexts as potentially different and requiring context switching. You cannot assume that any particular value in those contexts (e.g. current stack pointer or temporary values below the stack pointer) will remain unchanged between the two asm! blocks.

Using named labels should be avoided as functions may be duplicated, but named labels are global to a codegen unit and thus duplicates would conflict:

You cannot assume that an asm! block will appear exactly once in the output binary. The compiler is allowed to instantiate multiple copies of the asm! block, for example when the function containing it is inlined in multiple places.

2 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.