mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-24 03:33:20 +01:00
ARM64: use GOT for weak symbols & PIC.
Weak symbols cannot use the small code model's usual ADRP sequences since the instruction simply may not be able to encode a value of 0. This redirects them to use the GOT, which hopefully linkers are able to cope with even in the static relocation model. llvm-svn: 205426
This commit is contained in:
parent
01192b285d
commit
0688295f2f
@ -50,16 +50,33 @@ ARM64Subtarget::ClassifyGlobalReference(const GlobalValue *GV,
|
||||
if (GV->isDeclaration() && !GV->isMaterializable())
|
||||
isDecl = true;
|
||||
|
||||
// If symbol visibility is hidden, the extra load is not needed if
|
||||
// the symbol is definitely defined in the current translation unit.
|
||||
if (TM.getRelocationModel() != Reloc::Static && GV->hasDefaultVisibility() &&
|
||||
(isDecl || GV->isWeakForLinker()))
|
||||
return ARM64II::MO_GOT;
|
||||
|
||||
// MachO large model always goes via a GOT, simply to get a single 8-byte
|
||||
// absolute relocation on all global addresses.
|
||||
if (TM.getCodeModel() == CodeModel::Large && isTargetMachO())
|
||||
return ARM64II::MO_GOT;
|
||||
|
||||
// FIXME: this will fail on static ELF for weak symbols.
|
||||
// The small code mode's direct accesses use ADRP, which cannot necessarily
|
||||
// produce the value 0 (if the code is above 4GB). Therefore they must use the
|
||||
// GOT.
|
||||
if (TM.getCodeModel() == CodeModel::Small && GV->isWeakForLinker() && isDecl)
|
||||
return ARM64II::MO_GOT;
|
||||
|
||||
// If symbol visibility is hidden, the extra load is not needed if
|
||||
// the symbol is definitely defined in the current translation unit.
|
||||
|
||||
// The handling of non-hidden symbols in PIC mode is rather target-dependent:
|
||||
// + On MachO, if the symbol is defined in this module the GOT can be
|
||||
// skipped.
|
||||
// + On ELF, the R_AARCH64_COPY relocation means that even symbols actually
|
||||
// defined could end up in unexpected places. Use a GOT.
|
||||
if (TM.getRelocationModel() != Reloc::Static && GV->hasDefaultVisibility()) {
|
||||
if (isTargetMachO())
|
||||
return (isDecl || GV->isWeakForLinker()) ? ARM64II::MO_GOT
|
||||
: ARM64II::MO_NO_FLAG;
|
||||
else
|
||||
return ARM64II::MO_GOT;
|
||||
}
|
||||
|
||||
return ARM64II::MO_NO_FLAG;
|
||||
}
|
||||
|
||||
|
54
test/CodeGen/ARM64/basic-pic.ll
Normal file
54
test/CodeGen/ARM64/basic-pic.ll
Normal file
@ -0,0 +1,54 @@
|
||||
; RUN: llc -mtriple=arm64-none-linux-gnu -verify-machineinstrs -relocation-model=pic %s -o - | FileCheck %s
|
||||
|
||||
@var = global i32 0
|
||||
|
||||
define i32 @get_globalvar() {
|
||||
; CHECK-LABEL: get_globalvar:
|
||||
|
||||
%val = load i32* @var
|
||||
; CHECK: adrp x[[GOTHI:[0-9]+]], :got:var
|
||||
; CHECK: ldr x[[GOTLOC:[0-9]+]], [x[[GOTHI]], :got_lo12:var]
|
||||
; CHECK: ldr w0, [x[[GOTLOC]]]
|
||||
|
||||
ret i32 %val
|
||||
}
|
||||
|
||||
define i32* @get_globalvaraddr() {
|
||||
; CHECK-LABEL: get_globalvaraddr:
|
||||
|
||||
%val = load i32* @var
|
||||
; CHECK: adrp x[[GOTHI:[0-9]+]], :got:var
|
||||
; CHECK: ldr x0, [x[[GOTHI]], :got_lo12:var]
|
||||
|
||||
ret i32* @var
|
||||
}
|
||||
|
||||
@hiddenvar = hidden global i32 0
|
||||
|
||||
define i32 @get_hiddenvar() {
|
||||
; CHECK-LABEL: get_hiddenvar:
|
||||
|
||||
%val = load i32* @hiddenvar
|
||||
; CHECK: adrp x[[HI:[0-9]+]], hiddenvar
|
||||
; CHECK: ldr w0, [x[[HI]], :lo12:hiddenvar]
|
||||
|
||||
ret i32 %val
|
||||
}
|
||||
|
||||
define i32* @get_hiddenvaraddr() {
|
||||
; CHECK-LABEL: get_hiddenvaraddr:
|
||||
|
||||
%val = load i32* @hiddenvar
|
||||
; CHECK: adrp [[HI:x[0-9]+]], hiddenvar
|
||||
; CHECK: add x0, [[HI]], :lo12:hiddenvar
|
||||
|
||||
ret i32* @hiddenvar
|
||||
}
|
||||
|
||||
define void()* @get_func() {
|
||||
; CHECK-LABEL: get_func:
|
||||
|
||||
ret void()* bitcast(void()*()* @get_func to void()*)
|
||||
; CHECK: adrp x[[GOTHI:[0-9]+]], :got:get_func
|
||||
; CHECK: ldr x0, [x[[GOTHI]], :got_lo12:get_func]
|
||||
}
|
51
test/CodeGen/ARM64/extern-weak.ll
Normal file
51
test/CodeGen/ARM64/extern-weak.ll
Normal file
@ -0,0 +1,51 @@
|
||||
; RUN: llc -mtriple=arm64-none-linux-gnu -o - < %s | FileCheck %s
|
||||
; RUN: llc -mtriple=arm64-none-linux-gnu -code-model=large -o - < %s | FileCheck --check-prefix=CHECK-LARGE %s
|
||||
|
||||
declare extern_weak i32 @var()
|
||||
|
||||
define i32()* @foo() {
|
||||
; The usual ADRP/ADD pair can't be used for a weak reference because it must
|
||||
; evaluate to 0 if the symbol is undefined. We use a litpool entry.
|
||||
ret i32()* @var
|
||||
|
||||
; CHECK: adrp x[[VAR:[0-9]+]], :got:var
|
||||
; CHECK: ldr x0, [x[[VAR]], :got_lo12:var]
|
||||
|
||||
; In the large model, the usual relocations are absolute and can
|
||||
; materialise 0.
|
||||
; CHECK-LARGE: movz x0, #:abs_g3:var
|
||||
; CHECK-LARGE: movk x0, #:abs_g2_nc:var
|
||||
; CHECK-LARGE: movk x0, #:abs_g1_nc:var
|
||||
; CHECK-LARGE: movk x0, #:abs_g0_nc:var
|
||||
}
|
||||
|
||||
|
||||
@arr_var = extern_weak global [10 x i32]
|
||||
|
||||
define i32* @bar() {
|
||||
%addr = getelementptr [10 x i32]* @arr_var, i32 0, i32 5
|
||||
; CHECK: adrp x[[ARR_VAR_HI:[0-9]+]], :got:arr_var
|
||||
; CHECK: ldr [[ARR_VAR:x[0-9]+]], [x[[ARR_VAR_HI]], :got_lo12:arr_var]
|
||||
; CHECK: add x0, [[ARR_VAR]], #20
|
||||
ret i32* %addr
|
||||
|
||||
; In the large model, the usual relocations are absolute and can
|
||||
; materialise 0.
|
||||
; CHECK-LARGE: movz [[ARR_VAR:x[0-9]+]], #:abs_g3:arr_var
|
||||
; CHECK-LARGE: movk [[ARR_VAR]], #:abs_g2_nc:arr_var
|
||||
; CHECK-LARGE: movk [[ARR_VAR]], #:abs_g1_nc:arr_var
|
||||
; CHECK-LARGE: movk [[ARR_VAR]], #:abs_g0_nc:arr_var
|
||||
}
|
||||
|
||||
@defined_weak_var = internal unnamed_addr global i32 0
|
||||
|
||||
define i32* @wibble() {
|
||||
ret i32* @defined_weak_var
|
||||
; CHECK: adrp [[BASE:x[0-9]+]], defined_weak_var
|
||||
; CHECK: add x0, [[BASE]], :lo12:defined_weak_var
|
||||
|
||||
; CHECK-LARGE: movz x0, #:abs_g3:defined_weak_var
|
||||
; CHECK-LARGE: movk x0, #:abs_g2_nc:defined_weak_var
|
||||
; CHECK-LARGE: movk x0, #:abs_g1_nc:defined_weak_var
|
||||
; CHECK-LARGE: movk x0, #:abs_g0_nc:defined_weak_var
|
||||
}
|
Loading…
Reference in New Issue
Block a user