| Issue |
180358
|
| Summary |
[ARM] calls to `hidden` functions that cross the thumb/arm boundary miscompile
|
| Labels |
new issue
|
| Assignees |
|
| Reporter |
folkertdev
|
The example below has two declarations, that link to identical (modulo names) assembly code and directives. One is marked `dso_local`, the other is marked `hidden`. These declarations are meant to be in "arm mode" while the remainder of the file is in "thumb mode". The `-thumb-mode` target feature makes this clear, and is applied to both declarations.
```llvm
target triple = "thumbv4t-unknown-none-eabi"
module asm ".balign 4"
module asm ".arm"
module asm ".type globalfn1, %function"
module asm "globalfn1:"
module asm "bx lr"
module asm ".size globalfn1, . - globalfn1"
module asm ".thumb"
module asm ".balign 4"
module asm ".arm"
module asm ".type globalfn2, %function"
module asm "globalfn2:"
module asm "bx lr"
module asm ".size globalfn2, . - globalfn2"
module asm ".thumb"
define dso_local void @entry() unnamed_addr #2 {
start:
tail call void @globalfn1() #4
tail call void @globalfn2() #4
ret void
}
declare hidden void @globalfn1() unnamed_addr #3
declare dso_local void @globalfn2() unnamed_addr #3
attributes #2 = { nounwind "frame-pointer"="all" "target-cpu"="generic" "target-features"="+soft-float,+strict-align" }
attributes #3 = { nounwind "frame-pointer"="all" "target-cpu"="generic" "target-features"="+soft-float,+strict-align,-thumb-mode" }
attributes #4 = { nounwind }
```
If you compile this with
```
clang-20 -target thumbv4t-unknown-none-eabi -mthumb a32.ll -o a32.elf -nostdlib -ffreestanding
arm-none-eabi-objdump -d a32.elf
```
(I can't get godbolt to do this, unfortunately. clang-20 is what I have, but the underlying issue is still present in rust nightly, which uses LLVM 22)
You'll see that the hidden function is called without a thunk, and the dso_local function does get a thunk.
```
a32.elf: file format elf32-littlearm
Disassembly of section .text:
000200e4 <globalfn1>:
200e4: e12fff1e bx lr
000200e8 <globalfn2>:
200e8: e12fff1e bx lr
000200ec <entry>:
200ec: b580 push {r7, lr}
200ee: af00 add r7, sp, #0
200f0: f7ff fff8 bl 200e4 <globalfn1>
200f4: f000 f804 bl 20100 <__Thumbv4ABSLongBXThunk_globalfn2>
200f8: bc80 pop {r7}
200fa: bc01 pop {r0}
200fc: 4686 mov lr, r0
200fe: 4770 bx lr
00020100 <__Thumbv4ABSLongBXThunk_globalfn2>:
20100: 4778 bx pc
20102: e7fd b.n 20100 <__Thumbv4ABSLongBXThunk_globalfn2>
20104: e51ff004 ldr pc, [pc, #-4] @ 20108 <__Thumbv4ABSLongBXThunk_globalfn2+0x8>
20108: 000200e8 .word 0x000200e8
```
You can flip the order of the assembly, make them both hidden or not, and the correlation just seems to be that a hidden function is always emitted as a thumb symbol. That is a miscompilation.
This problem is relevant for rust because we use hidden functions when lowering naked functions to work around LTO issues. There may be other workarounds, but still I believe this is a real issue that should be fixed.
cc https://github.com/rust-lang/rust/issues/151946
_______________________________________________
llvm-bugs mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs