A PIC data reference forms the symbol's GOT offset with R_SPARC_GOTDATA_OP_HIX22 and R_SPARC_GOTDATA_OP_LOX10 and loads through it, with R_SPARC_GOTDATA_OP marking the load: ``` sethi %gdop_hix22(sym), %g1 xor %g1, %gdop_lox10(sym), %g1 ldx [%l7 + %g1], %g1, %gdop(sym) ``` When the symbol is neither preemptible nor absolute, optimize the load to `add %l7, %g1, %g1` over the symbol's GOT-relative address. An absolute symbol keeps the GOT load, as it can be arbitrarily far from .got and we don't want the X86_64::relaxOpt complexity. Co-authored-by: Kirill A. Korinsky <kirill@korins.ky> Co-authored-by: LemonBoy <thatlemon@gmail.com> Co-authored-by: Alex Rønne Petersen <alex@alexrp.com>
141 lines
4.9 KiB
ArmAsm
141 lines
4.9 KiB
ArmAsm
# REQUIRES: sparc
|
|
## Test R_SPARC_GOTDATA_OP_HIX22, R_SPARC_GOTDATA_OP_LOX10 and R_SPARC_GOTDATA_OP.
|
|
## The GOT load is optimized to an add of the symbol's GOT-relative address
|
|
## unless the symbol is preemptible or absolute.
|
|
|
|
# RUN: rm -rf %t && split-file %s %t && cd %t
|
|
# RUN: llvm-mc -filetype=obj -triple=sparcv9 a.s -o a.o
|
|
# RUN: llvm-mc -filetype=obj -triple=sparcv9 b.s -o b.o
|
|
# RUN: llvm-mc -filetype=obj -triple=sparcv9 c.s -o c.o
|
|
# RUN: llvm-mc -filetype=obj -triple=sparcv9 ifunc.s -o ifunc.o
|
|
|
|
# RUN: ld.lld -shared a.o c.o -o a.so
|
|
# RUN: llvm-readelf -S -r a.so | FileCheck %s --check-prefix=RELOC
|
|
# RUN: llvm-objdump -d -j .text --no-show-raw-insn --no-print-imm-hex a.so | FileCheck %s
|
|
|
|
# RELOC: [ 8] .got PROGBITS 0000000000200390 {{[0-9a-f]+}} 000020
|
|
# RELOC: Relocation section '.rela.dyn' {{.*}} contains 1 entries:
|
|
# RELOC: 0000000000200398 {{.*}} R_SPARC_GLOB_DAT {{.*}} foo + 0
|
|
|
|
## foo is preemptible, so the GOT load stays.
|
|
## .got[1] - _GLOBAL_OFFSET_TABLE_ = 0x200398 - 0x200390 = 8.
|
|
# CHECK-LABEL: <_start>:
|
|
# CHECK-NEXT: sethi 0, %l1
|
|
# CHECK-NEXT: xor %l1, 8, %l1
|
|
# CHECK-NEXT: ldx [%l7+%l1], %l2
|
|
## hid0 - _GLOBAL_OFFSET_TABLE_ = 0x3003b0 - 0x200390 = 0x100020.
|
|
# CHECK-NEXT: sethi 1024, %g1
|
|
# CHECK-NEXT: xor %g1, 32, %g1
|
|
# CHECK-NEXT: add %l7, %g1, %g1
|
|
## hid1 - _GLOBAL_OFFSET_TABLE_ = 0x1002ec - 0x200390 = -0x1000a4. sethi holds
|
|
## the complement, which the sign-extended xor operand undoes.
|
|
# CHECK-NEXT: sethi 1024, %o2
|
|
# CHECK-NEXT: xor %o2, -164, %o2
|
|
# CHECK-NEXT: add %i0, %o2, %i5
|
|
## An undefined symbol and an absolute symbol both have an absolute address, so
|
|
## neither is optimized.
|
|
# CHECK-NEXT: sethi 0, %l1
|
|
# CHECK-NEXT: xor %l1, 16, %l1
|
|
# CHECK-NEXT: ldx [%l7+%l1], %l2
|
|
# CHECK-NEXT: sethi 0, %g4
|
|
# CHECK-NEXT: xor %g4, 24, %g4
|
|
# CHECK-NEXT: ldx [%l7+%g4], %o3
|
|
|
|
## foo is not preemptible in an executable and is optimized as well. undefweak
|
|
## and absolute keep the GOT load in every mode.
|
|
# RUN: ld.lld a.o c.o -o a
|
|
# RUN: llvm-objdump -d -j .text --no-show-raw-insn --no-print-imm-hex a | FileCheck %s --check-prefix=NOPIE
|
|
# NOPIE-LABEL: <_start>:
|
|
# NOPIE-NEXT: sethi 1024, %l1
|
|
# NOPIE-NEXT: xor %l1, -4, %l1
|
|
# NOPIE-NEXT: add %l7, %l1, %l2
|
|
# NOPIE: sethi 0, %l1
|
|
# NOPIE-NEXT: xor %l1, 8, %l1
|
|
# NOPIE-NEXT: ldx [%l7+%l1], %l2
|
|
# NOPIE-NEXT: sethi 0, %g4
|
|
# NOPIE-NEXT: xor %g4, 16, %g4
|
|
# NOPIE-NEXT: ldx [%l7+%g4], %o3
|
|
|
|
## .got holds nothing but the header, yet must be kept: %l7 points at it.
|
|
# RUN: ld.lld -shared b.o -o b.so
|
|
# RUN: llvm-readelf -S b.so | FileCheck %s --check-prefix=HEADER
|
|
# HEADER: [ 7] .got PROGBITS 00000000002002b8 {{[0-9a-f]+}} 000008
|
|
|
|
# RUN: not ld.lld -shared ifunc.o 2>&1 | FileCheck %s --check-prefix=IFUNC --implicit-check-not=error:
|
|
# IFUNC: error: {{.*}}relocation R_SPARC_WDISP19 out of range
|
|
|
|
## The optimization is decided before addresses are known, so an out-of-range
|
|
## offset is an error rather than a fallback to the GOT load. The offset is
|
|
## reported as signed, not as the complement the sethi encodes. Only hid0, in
|
|
## .data, is out of range; the other symbols stay next to .got.
|
|
# RUN: not ld.lld -shared a.o c.o --section-start=.text=0x10000 --section-start=.got=0x20000 \
|
|
# RUN: --section-start=.data=0x200000000 2>&1 | FileCheck %s --check-prefix=ERR -DVAL=8589803520 --implicit-check-not=error:
|
|
# RUN: not ld.lld -shared a.o c.o --section-start=.data=0x10000 --section-start=.text=0x200000000 \
|
|
# RUN: --section-start=.got=0x200020000 2>&1 | FileCheck %s --check-prefix=ERR -DVAL=-8590000128 --implicit-check-not=error:
|
|
# ERR: error: a.o:(.text+0xc): relocation R_SPARC_GOTDATA_OP_HIX22 out of range: [[VAL]] is not in [-4294967296, 4294967295]; references 'hid0'
|
|
|
|
#--- a.s
|
|
.text
|
|
.globl _start
|
|
_start:
|
|
sethi %gdop_hix22(foo), %l1
|
|
xor %l1, %gdop_lox10(foo), %l1
|
|
ldx [%l7 + %l1], %l2, %gdop(foo)
|
|
|
|
sethi %gdop_hix22(hid0), %g1
|
|
xor %g1, %gdop_lox10(hid0), %g1
|
|
ldx [%l7 + %g1], %g1, %gdop(hid0)
|
|
|
|
## The add keeps rs1, rs2 and rd of the load, and ld is optimized like ldx.
|
|
sethi %gdop_hix22(hid1), %o2
|
|
xor %o2, %gdop_lox10(hid1), %o2
|
|
ld [%i0 + %o2], %i5, %gdop(hid1)
|
|
|
|
sethi %gdop_hix22(undefweak), %l1
|
|
xor %l1, %gdop_lox10(undefweak), %l1
|
|
ldx [%l7 + %l1], %l2, %gdop(undefweak)
|
|
|
|
sethi %gdop_hix22(absolute), %g4
|
|
xor %g4, %gdop_lox10(absolute), %g4
|
|
ldx [%l7 + %g4], %o3, %gdop(absolute)
|
|
|
|
.globl foo, hid0, hid1
|
|
.hidden hid0, hid1
|
|
foo:
|
|
hid1:
|
|
nop
|
|
|
|
.weak undefweak
|
|
.hidden undefweak
|
|
|
|
.data
|
|
hid0:
|
|
.xword 0
|
|
|
|
#--- b.s
|
|
.globl _start
|
|
_start:
|
|
sethi %gdop_hix22(local), %l1
|
|
xor %l1, %gdop_lox10(local), %l1
|
|
ldx [%l7 + %l1], %l2, %gdop(local)
|
|
local:
|
|
nop
|
|
|
|
#--- c.s
|
|
## Separate file to test %gdop_lox10(absolute) relocations in a.s
|
|
.globl absolute
|
|
.hidden absolute
|
|
absolute = 0x1234
|
|
|
|
#--- ifunc.s
|
|
.globl _start
|
|
_start:
|
|
sethi %gdop_hix22(ifunc), %l1
|
|
xor %l1, %gdop_lox10(ifunc), %l1
|
|
ldx [%l7 + %l1], %l2, %gdop(ifunc)
|
|
|
|
.globl ifunc
|
|
.hidden ifunc
|
|
.type ifunc, @gnu_indirect_function
|
|
ifunc:
|
|
nop
|