llvm-project/lld/test/ELF/mips-tls.s

107 lines
4.0 KiB
ArmAsm
Raw Normal View History

# REQUIRES: mips
# Check MIPS TLS relocations handling.
# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \
# RUN: %p/Inputs/mips-tls.s -o %t.so.o
# RUN: ld.lld -shared %t.so.o -o %t.so
# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o
# RUN: ld.lld %t.o %t.so -o %t.exe
# RUN: llvm-objdump -d -s -t %t.exe | FileCheck -check-prefix=DIS %s
# RUN: llvm-readobj -r --mips-plt-got %t.exe | FileCheck %s
# RUN: ld.lld -shared %t.o %t.so -o %t-out.so
# RUN: llvm-objdump -d -s -t %t-out.so | FileCheck -check-prefix=DIS-SO %s
# RUN: llvm-readobj -r --mips-plt-got %t-out.so | FileCheck -check-prefix=SO %s
# DIS: __start:
[ELF][MIPS] Multi-GOT implementation Almost all entries inside MIPS GOT are referenced by signed 16-bit index. Zero entry lies approximately in the middle of the GOT. So the total number of GOT entries cannot exceed ~16384 for 32-bit architecture and ~8192 for 64-bit architecture. This limitation makes impossible to link rather large application like for example LLVM+Clang. There are two workaround for this problem. The first one is using the -mxgot compiler's flag. It enables using a 32-bit index to access GOT entries. But each access requires two assembly instructions two load GOT entry index to a register. Another workaround is multi-GOT. This patch implements it. Here is a brief description of multi-GOT for detailed one see the following link https://dmz-portal.mips.com/wiki/MIPS_Multi_GOT. If the sum of local, global and tls entries is less than 64K only single got is enough. Otherwise, multi-got is created. Series of primary and multiple secondary GOTs have the following layout: ``` - Primary GOT Header Local entries Global entries Relocation only entries TLS entries - Secondary GOT Local entries Global entries TLS entries ... ``` All GOT entries required by relocations from a single input file entirely belong to either primary or one of secondary GOTs. To reference GOT entries each GOT has its own _gp value points to the "middle" of the GOT. In the code this value loaded to the register which is used for GOT access. MIPS 32 function's prologue: ``` lui v0,0x0 0: R_MIPS_HI16 _gp_disp addiu v0,v0,0 4: R_MIPS_LO16 _gp_disp ``` MIPS 64 function's prologue: ``` lui at,0x0 14: R_MIPS_GPREL16 main ``` Dynamic linker does not know anything about secondary GOTs and cannot use a regular MIPS mechanism for GOT entries initialization. So we have to use an approach accepted by other architectures and create dynamic relocations R_MIPS_REL32 to initialize global entries (and local in case of PIC code) in secondary GOTs. But ironically MIPS dynamic linker requires GOT entries and correspondingly ordered dynamic symbol table entries to deal with dynamic relocations. To handle this problem relocation-only section in the primary GOT contains entries for all symbols referenced in global parts of secondary GOTs. Although the sum of local and normal global entries of the primary got should be less than 64K, the size of the primary got (including relocation-only entries can be greater than 64K, because parts of the primary got that overflow the 64K limit are used only by the dynamic linker at dynamic link-time and not by 16-bit gp-relative addressing at run-time. The patch affects common LLD code in the following places: - Added new hidden -mips-got-size flag. This flag required to set low maximum size of a single GOT to be able to test the implementation using small test cases. - Added InputFile argument to the getRelocTargetVA function. The same symbol referenced by GOT relocation from different input file might be allocated in different GOT. So result of relocation depends on the file. - Added new ctor to the DynamicReloc class. This constructor records settings of dynamic relocation which used to adjust address of 64kb page lies inside a specific output section. With the patch LLD is able to link all LLVM+Clang+LLD applications and libraries for MIPS 32/64 targets. Differential revision: https://reviews.llvm.org/D31528 llvm-svn: 334390
2018-06-11 15:24:31 +08:00
# DIS-NEXT: 20000: 24 62 80 20 addiu $2, $3, -32736
# DIS-NEXT: 20004: 24 62 80 18 addiu $2, $3, -32744
# DIS-NEXT: 20008: 24 62 80 28 addiu $2, $3, -32728
# DIS-NEXT: 2000c: 24 62 80 30 addiu $2, $3, -32720
# DIS-NEXT: 20010: 24 62 80 1c addiu $2, $3, -32740
# DIS: Contents of section .got:
# DIS-NEXT: 40010 00000000 80000000 00000000 ffff9004
# DIS-NEXT: 40020 00000000 00000000 00000001 00000000
# DIS-NEXT: 40030 00000001 ffff8004
# DIS: 00000000 l O .tdata 00000000 loc
# DIS: 00000004 g O .tdata 00000000 bar
# DIS: 00000000 g O *UND* 00000000 foo
# CHECK: Relocations [
# CHECK-NEXT: Section (7) .rel.dyn {
# CHECK-NEXT: 0x40018 R_MIPS_TLS_TPREL32 foo 0x0
# CHECK-NEXT: 0x40020 R_MIPS_TLS_DTPMOD32 foo 0x0
# CHECK-NEXT: 0x40024 R_MIPS_TLS_DTPREL32 foo 0x0
# CHECK-NEXT: }
# CHECK-NEXT: ]
# CHECK-NEXT: Primary GOT {
# CHECK-NEXT: Canonical gp value: 0x48000
# CHECK-NEXT: Reserved entries [
# CHECK: ]
# CHECK-NEXT: Local entries [
# CHECK-NEXT: ]
# CHECK-NEXT: Global entries [
# CHECK-NEXT: ]
# CHECK-NEXT: Number of TLS and multi-GOT entries: 8
[ELF][MIPS] Multi-GOT implementation Almost all entries inside MIPS GOT are referenced by signed 16-bit index. Zero entry lies approximately in the middle of the GOT. So the total number of GOT entries cannot exceed ~16384 for 32-bit architecture and ~8192 for 64-bit architecture. This limitation makes impossible to link rather large application like for example LLVM+Clang. There are two workaround for this problem. The first one is using the -mxgot compiler's flag. It enables using a 32-bit index to access GOT entries. But each access requires two assembly instructions two load GOT entry index to a register. Another workaround is multi-GOT. This patch implements it. Here is a brief description of multi-GOT for detailed one see the following link https://dmz-portal.mips.com/wiki/MIPS_Multi_GOT. If the sum of local, global and tls entries is less than 64K only single got is enough. Otherwise, multi-got is created. Series of primary and multiple secondary GOTs have the following layout: ``` - Primary GOT Header Local entries Global entries Relocation only entries TLS entries - Secondary GOT Local entries Global entries TLS entries ... ``` All GOT entries required by relocations from a single input file entirely belong to either primary or one of secondary GOTs. To reference GOT entries each GOT has its own _gp value points to the "middle" of the GOT. In the code this value loaded to the register which is used for GOT access. MIPS 32 function's prologue: ``` lui v0,0x0 0: R_MIPS_HI16 _gp_disp addiu v0,v0,0 4: R_MIPS_LO16 _gp_disp ``` MIPS 64 function's prologue: ``` lui at,0x0 14: R_MIPS_GPREL16 main ``` Dynamic linker does not know anything about secondary GOTs and cannot use a regular MIPS mechanism for GOT entries initialization. So we have to use an approach accepted by other architectures and create dynamic relocations R_MIPS_REL32 to initialize global entries (and local in case of PIC code) in secondary GOTs. But ironically MIPS dynamic linker requires GOT entries and correspondingly ordered dynamic symbol table entries to deal with dynamic relocations. To handle this problem relocation-only section in the primary GOT contains entries for all symbols referenced in global parts of secondary GOTs. Although the sum of local and normal global entries of the primary got should be less than 64K, the size of the primary got (including relocation-only entries can be greater than 64K, because parts of the primary got that overflow the 64K limit are used only by the dynamic linker at dynamic link-time and not by 16-bit gp-relative addressing at run-time. The patch affects common LLD code in the following places: - Added new hidden -mips-got-size flag. This flag required to set low maximum size of a single GOT to be able to test the implementation using small test cases. - Added InputFile argument to the getRelocTargetVA function. The same symbol referenced by GOT relocation from different input file might be allocated in different GOT. So result of relocation depends on the file. - Added new ctor to the DynamicReloc class. This constructor records settings of dynamic relocation which used to adjust address of 64kb page lies inside a specific output section. With the patch LLD is able to link all LLVM+Clang+LLD applications and libraries for MIPS 32/64 targets. Differential revision: https://reviews.llvm.org/D31528 llvm-svn: 334390
2018-06-11 15:24:31 +08:00
# ^-- -32744 R_MIPS_TLS_GOTTPREL R_MIPS_TLS_TPREL32 foo
# ^-- -32740 R_MIPS_TLS_GOTTPREL VA - 0x7000 bar
# ^-- -32736 R_MIPS_TLS_GD R_MIPS_TLS_DTPMOD32 foo
# ^-- -32732 R_MIPS_TLS_DTPREL32 foo
# ^-- -32728 R_MIPS_TLS_LDM 1 loc
# ^-- -32724 0 loc
# ^-- -32720 R_MIPS_TLS_GD 1 bar
# ^-- -32716 VA - 0x8000 bar
# DIS-SO: Contents of section .got:
# DIS-SO-NEXT: 30000 00000000 80000000 00000000 00000004
# DIS-SO-NEXT: 30010 00000000 00000000 00000000 00000000
# DIS-SO-NEXT: 30020 00000000 00000000
# SO: Relocations [
# SO-NEXT: Section (7) .rel.dyn {
# SO-NEXT: 0x30018 R_MIPS_TLS_DTPMOD32 - 0x0
# SO-NEXT: 0x3000C R_MIPS_TLS_TPREL32 bar 0x0
# SO-NEXT: 0x30020 R_MIPS_TLS_DTPMOD32 bar 0x0
# SO-NEXT: 0x30024 R_MIPS_TLS_DTPREL32 bar 0x0
# SO-NEXT: 0x30008 R_MIPS_TLS_TPREL32 foo 0x0
# SO-NEXT: 0x30010 R_MIPS_TLS_DTPMOD32 foo 0x0
# SO-NEXT: 0x30014 R_MIPS_TLS_DTPREL32 foo 0x0
# SO-NEXT: }
# SO-NEXT: ]
# SO-NEXT: Primary GOT {
# SO-NEXT: Canonical gp value: 0x37FF0
# SO-NEXT: Reserved entries [
# SO: ]
# SO-NEXT: Local entries [
# SO-NEXT: ]
# SO-NEXT: Global entries [
# SO-NEXT: ]
# SO-NEXT: Number of TLS and multi-GOT entries: 8
[ELF][MIPS] Multi-GOT implementation Almost all entries inside MIPS GOT are referenced by signed 16-bit index. Zero entry lies approximately in the middle of the GOT. So the total number of GOT entries cannot exceed ~16384 for 32-bit architecture and ~8192 for 64-bit architecture. This limitation makes impossible to link rather large application like for example LLVM+Clang. There are two workaround for this problem. The first one is using the -mxgot compiler's flag. It enables using a 32-bit index to access GOT entries. But each access requires two assembly instructions two load GOT entry index to a register. Another workaround is multi-GOT. This patch implements it. Here is a brief description of multi-GOT for detailed one see the following link https://dmz-portal.mips.com/wiki/MIPS_Multi_GOT. If the sum of local, global and tls entries is less than 64K only single got is enough. Otherwise, multi-got is created. Series of primary and multiple secondary GOTs have the following layout: ``` - Primary GOT Header Local entries Global entries Relocation only entries TLS entries - Secondary GOT Local entries Global entries TLS entries ... ``` All GOT entries required by relocations from a single input file entirely belong to either primary or one of secondary GOTs. To reference GOT entries each GOT has its own _gp value points to the "middle" of the GOT. In the code this value loaded to the register which is used for GOT access. MIPS 32 function's prologue: ``` lui v0,0x0 0: R_MIPS_HI16 _gp_disp addiu v0,v0,0 4: R_MIPS_LO16 _gp_disp ``` MIPS 64 function's prologue: ``` lui at,0x0 14: R_MIPS_GPREL16 main ``` Dynamic linker does not know anything about secondary GOTs and cannot use a regular MIPS mechanism for GOT entries initialization. So we have to use an approach accepted by other architectures and create dynamic relocations R_MIPS_REL32 to initialize global entries (and local in case of PIC code) in secondary GOTs. But ironically MIPS dynamic linker requires GOT entries and correspondingly ordered dynamic symbol table entries to deal with dynamic relocations. To handle this problem relocation-only section in the primary GOT contains entries for all symbols referenced in global parts of secondary GOTs. Although the sum of local and normal global entries of the primary got should be less than 64K, the size of the primary got (including relocation-only entries can be greater than 64K, because parts of the primary got that overflow the 64K limit are used only by the dynamic linker at dynamic link-time and not by 16-bit gp-relative addressing at run-time. The patch affects common LLD code in the following places: - Added new hidden -mips-got-size flag. This flag required to set low maximum size of a single GOT to be able to test the implementation using small test cases. - Added InputFile argument to the getRelocTargetVA function. The same symbol referenced by GOT relocation from different input file might be allocated in different GOT. So result of relocation depends on the file. - Added new ctor to the DynamicReloc class. This constructor records settings of dynamic relocation which used to adjust address of 64kb page lies inside a specific output section. With the patch LLD is able to link all LLVM+Clang+LLD applications and libraries for MIPS 32/64 targets. Differential revision: https://reviews.llvm.org/D31528 llvm-svn: 334390
2018-06-11 15:24:31 +08:00
# ^-- -32744 R_MIPS_TLS_GOTTPREL R_MIPS_TLS_TPREL32 foo
# ^-- -32740 R_MIPS_TLS_GOTTPREL R_MIPS_TLS_TPREL32 bar
# ^-- -32736 R_MIPS_TLS_GD R_MIPS_TLS_DTPMOD32 foo
# ^-- -32732 R_MIPS_TLS_DTPREL32 foo
# ^-- -32728 R_MIPS_TLS_LDM R_MIPS_TLS_DTPMOD32 loc
# ^-- -32724 0 loc
# ^-- -32720 R_MIPS_TLS_GD R_MIPS_TLS_DTPMOD32 bar
# ^-- -32716 R_MIPS_TLS_DTPREL32 bar
.text
.global __start
__start:
addiu $2, $3, %tlsgd(foo) # R_MIPS_TLS_GD
addiu $2, $3, %gottprel(foo) # R_MIPS_TLS_GOTTPREL
addiu $2, $3, %tlsldm(loc) # R_MIPS_TLS_LDM
addiu $2, $3, %tlsgd(bar) # R_MIPS_TLS_GD
addiu $2, $3, %gottprel(bar) # R_MIPS_TLS_GOTTPREL
.section .tdata,"awT",%progbits
.global bar
loc:
.word 0
bar:
.word 0