Skip to content

Commit 7f275e0

Browse files
authored
[ELF][LTO] Add baseline test for invalid relocations against runtime calls
This can happen when using a LTO build of compiler-rt for ARM and the program uses 64-bit division. The 64-bit division function in compiler-rt (__aeabi_ldivmod) is written in assembly and calls the C function __divmoddi4, which works fine in non-LTO links. However, when building with LTO the call inside __aeabi_ldivmod is replaced with a jump to address zero, which then crashes the program. Building with -pie generates an error instead of a jump to address zero, and surprisingly just declaring the __aeabi_ldivmod function (but not calling it) in the input IR also avoids this issue. Reported as llvm#127284 Co-authored-by: Fangrui Song <[email protected]> Reviewed By: MaskRay Pull Request: llvm#127286
1 parent 2775122 commit 7f275e0

File tree

1 file changed

+126
-0
lines changed

1 file changed

+126
-0
lines changed

lld/test/ELF/lto/arm-rtlibcall.ll

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
; REQUIRES: arm
2+
;; Test for LTO optimizing out references to symbols that are pulled in by
3+
;; compiler-generated libcalls (post LTO).
4+
;; Lazy files extracted post LTO compilation might reference other lazy files.
5+
;; Referenced relocatable files are extracted and everything works as intended.
6+
;; However, if the referenced lazy file is a bitcode file, no further LTO
7+
;; compilation occurs. lld currently treats any symbols from that bitcode file
8+
;; as absolute, which leads to a "refer to absolute symbol" error in PIC links
9+
;; and leads to silently broken output. For example, lazy aeabi_ldivmod.o post
10+
;; LTO extraction might call __divmoddi4 defined in an unextracted lazy bitcode
11+
;; file (https://github.com/llvm/llvm-project/issues/127284).
12+
; RUN: rm -rf %t && split-file %s %t && cd %t
13+
; RUN: llvm-as divmoddi4.ll -o divmoddi4.bc
14+
; RUN: llvm-mc -filetype=obj -triple=armv7-none-unknown-eabi aeabi_ldivmod.s -o aeabi_ldivmod.o
15+
;; With an explicit __aebi_ldivmod call in the input IR this works as expected:
16+
; RUN: llvm-as main-explicit.ll -o main-explicit-ldivmod.bc
17+
; RUN: ld.lld main-explicit-ldivmod.bc --start-lib aeabi_ldivmod.o divmoddi4.bc --end-lib -o out.explicit
18+
; RUN: llvm-objdump -d -r -t out.explicit | FileCheck %s --check-prefix=GOOD-DUMP
19+
; GOOD-DUMP-LABEL: SYMBOL TABLE:
20+
; GOOD-DUMP: [[#]] g F .text 00000024 __aeabi_ldivmod
21+
; GOOD-DUMP: [[#]] g F .text [[#]] __divmoddi4
22+
; GOOD-DUMP-LABEL: <__aeabi_ldivmod>:
23+
; GOOD-DUMP: bl 0x20140 <__divmoddi4> @ imm = #0x28
24+
25+
;; But if the call is generated by ISel, we end up with an invalid reference:
26+
; RUN: llvm-as main-implicit.ll -o main-implicit-ldivmod.bc
27+
; RUN: ld.lld main-implicit-ldivmod.bc --start-lib aeabi_ldivmod.o divmoddi4.bc --end-lib -o out.implicit
28+
; RUN: llvm-objdump -d -r -t out.implicit | FileCheck %s --check-prefix=BAD-DUMP
29+
;; We jump to address zero here and __divmoddi4 ends up being an absolute symbol:
30+
; BAD-DUMP-LABEL: SYMBOL TABLE:
31+
; BAD-DUMP: [[#]] g F .text 00000024 __aeabi_ldivmod
32+
; BAD-DUMP: [[#]] g *ABS* 00000000 __divmoddi4
33+
; BAD-DUMP-LABEL: <__aeabi_ldivmod>:
34+
; BAD-DUMP: bl 0x0 <__divmoddi4>
35+
;; Linking with -pie complains about the invalid relocation (and even points back to the source files)
36+
; RUN: not ld.lld main-implicit-ldivmod.bc --start-lib aeabi_ldivmod.o divmoddi4.bc --end-lib -o out.pie --no-undefined -pie --no-dynamic-linker 2>&1 | FileCheck %s --check-prefix=PIE-ERROR
37+
PIE-ERROR: ld.lld: error: relocation R_ARM_CALL cannot refer to absolute symbol: __divmoddi4
38+
PIE-ERROR-NEXT: >>> defined in divmoddi4.bc
39+
PIE-ERROR-NEXT: >>> referenced by aeabi_ldivmod.o:(__aeabi_ldivmod)
40+
;; Removing --start-lib/--end-lib also ensures that the reference is retained
41+
; RUN: ld.lld main-implicit-ldivmod.bc aeabi_ldivmod.o divmoddi4.bc -o out.nolib
42+
; RUN: llvm-objdump -d -r -t out.nolib | FileCheck %s --check-prefix=GOOD-DUMP
43+
44+
;; Interestingly, just declaring __aeabi_ldivmod is sufficient to not run into this issue.
45+
; RUN: llvm-as main-declared.ll -o main-declared-ldivmod.bc
46+
; RUN: ld.lld main-declared-ldivmod.bc --start-lib aeabi_ldivmod.o divmoddi4.bc --end-lib -o out.declared
47+
; RUN: llvm-objdump -d -r -t out.declared | FileCheck %s --check-prefix=GOOD-DUMP
48+
49+
;--- divmoddi4.ll
50+
target datalayout = "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64"
51+
target triple = "armv7-none-unknown-eabi"
52+
53+
; Adding it to llvm.used does not appears to have any effect!
54+
;; @llvm.used = appending global [1 x ptr] [ptr @__divmoddi4], section "llvm.metadata"
55+
56+
; Stub version of the real __divmoddi4
57+
define i64 @__divmoddi4(i64 %a, i64 %b, ptr writeonly %rem) #0 align 32 {
58+
entry:
59+
%sub = sub i64 %a, %b
60+
store i64 0, ptr %rem, align 8
61+
ret i64 %sub
62+
}
63+
64+
attributes #0 = { mustprogress nofree noinline norecurse nosync nounwind willreturn memory(argmem: write) "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="cortex-a15" }
65+
66+
;--- aeabi_ldivmod.s
67+
.syntax unified
68+
.p2align 2
69+
.arm
70+
.globl __aeabi_ldivmod
71+
.type __aeabi_ldivmod,%function
72+
__aeabi_ldivmod:
73+
push {r6, lr}
74+
sub sp, sp, #16
75+
add r6, sp, #8
76+
str r6, [sp]
77+
bl __divmoddi4
78+
ldr r2, [sp, #8]
79+
ldr r3, [sp, #12]
80+
add sp, sp, #16
81+
pop {r6, pc}
82+
.size __aeabi_ldivmod, . - __aeabi_ldivmod
83+
84+
;--- main-implicit.ll
85+
target datalayout = "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64"
86+
target triple = "armv7-none-unknown-eabi"
87+
88+
define dso_local i64 @_start(i64 %num, i64 %denom) local_unnamed_addr #0 {
89+
entry:
90+
%div = sdiv i64 %num, %denom
91+
%ret = add i64 %div, 2
92+
ret i64 %ret
93+
}
94+
95+
attributes #0 = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="cortex-a15" }
96+
97+
;--- main-explicit.ll
98+
target datalayout = "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64"
99+
target triple = "armv7-none-unknown-eabi"
100+
101+
declare { i64, i64 } @__aeabi_ldivmod(i64, i64)
102+
103+
define dso_local noundef i64 @_start(i64 noundef %num, i64 noundef %denom) local_unnamed_addr #0 {
104+
entry:
105+
%quotrem = call { i64, i64 } @__aeabi_ldivmod(i64 %num, i64 %denom)
106+
%div = extractvalue { i64, i64 } %quotrem, 0
107+
%ret = add i64 %div, 2
108+
ret i64 %ret
109+
}
110+
111+
attributes #0 = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="cortex-a15" }
112+
113+
;--- main-declared.ll
114+
target datalayout = "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64"
115+
target triple = "armv7-none-unknown-eabi"
116+
117+
declare { i64, i64 } @__aeabi_ldivmod(i64, i64)
118+
119+
define dso_local i64 @_start(i64 %num, i64 %denom) local_unnamed_addr #0 {
120+
entry:
121+
%div = sdiv i64 %num, %denom
122+
%ret = add i64 %div, 2
123+
ret i64 %ret
124+
}
125+
126+
attributes #0 = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="cortex-a15" }

0 commit comments

Comments
 (0)