diff options
| author | Fangrui Song <maskray@google.com> | 2019-06-14 02:14:53 +0000 |
|---|---|---|
| committer | Fangrui Song <maskray@google.com> | 2019-06-14 02:14:53 +0000 |
| commit | 5b4285d82ded14b5f486df39fbef6aacdfbd8659 (patch) | |
| tree | 958e3bddde8e08f49d826bce76db284ffb803391 | |
| parent | d54d4f990592bfcc9d6cdccc2eb086c83bfbaa3a (diff) | |
| download | bcm5719-llvm-5b4285d82ded14b5f486df39fbef6aacdfbd8659.tar.gz bcm5719-llvm-5b4285d82ded14b5f486df39fbef6aacdfbd8659.zip | |
[ELF][RISCV] Create dummy .sdata for __global_pointer$ if .sdata does not exist
If .sdata is absent, linker synthesized __global_pointer$ gets a section index of SHN_ABS.
(ld.bfd has a similar issue: binutils PR24678)
Scrt1.o may use `lla gp, __global_pointer$` to reference the symbol PC
relatively. In -pie/-shared mode, lld complains if a PC relative
relocation references an absolute symbol (SHN_ABS) but ld.bfd doesn't:
ld.lld: error: relocation R_RISCV_PCREL_HI20 cannot refer to lute symbol: __global_pointer$
Let the reference of __global_pointer$ to force creation of .sdata to
fix the problem. This is similar to _GLOBAL_OFFSET_TABLE_, which forces
creation of .got or .got.plt .
Also, change the visibility from STV_HIDDEN to STV_DEFAULT and don't
define the symbol for -shared. This matches ld.bfd, though I don't
understand why it uses STV_DEFAULT.
Reviewed By: ruiu, jrtc27
Differential Revision: https://reviews.llvm.org/D63132
llvm-svn: 363351
| -rw-r--r-- | lld/ELF/Symbols.cpp | 1 | ||||
| -rw-r--r-- | lld/ELF/Symbols.h | 3 | ||||
| -rw-r--r-- | lld/ELF/SyntheticSections.cpp | 17 | ||||
| -rw-r--r-- | lld/ELF/SyntheticSections.h | 10 | ||||
| -rw-r--r-- | lld/ELF/Writer.cpp | 14 | ||||
| -rw-r--r-- | lld/test/ELF/riscv-gp-dummy-sdata.s | 25 | ||||
| -rw-r--r-- | lld/test/ELF/riscv-gp.s | 26 |
7 files changed, 93 insertions, 3 deletions
diff --git a/lld/ELF/Symbols.cpp b/lld/ELF/Symbols.cpp index 231ba7c1fd6..a5bc49dee23 100644 --- a/lld/ELF/Symbols.cpp +++ b/lld/ELF/Symbols.cpp @@ -39,6 +39,7 @@ Defined *ElfSym::MipsGpDisp; Defined *ElfSym::MipsLocalGp; Defined *ElfSym::RelaIpltStart; Defined *ElfSym::RelaIpltEnd; +Defined *ElfSym::RISCVGlobalPointer; Defined *ElfSym::TlsModuleBase; static uint64_t getSymVA(const Symbol &Sym, int64_t &Addend) { diff --git a/lld/ELF/Symbols.h b/lld/ELF/Symbols.h index 685f25494b5..0782cf01f17 100644 --- a/lld/ELF/Symbols.h +++ b/lld/ELF/Symbols.h @@ -437,6 +437,9 @@ struct ElfSym { static Defined *RelaIpltStart; static Defined *RelaIpltEnd; + // __global_pointer$ for RISC-V. + static Defined *RISCVGlobalPointer; + // _TLS_MODULE_BASE_ on targets that support TLSDESC. static Defined *TlsModuleBase; }; diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp index 15433deb96c..53c347fe413 100644 --- a/lld/ELF/SyntheticSections.cpp +++ b/lld/ELF/SyntheticSections.cpp @@ -3386,6 +3386,23 @@ bool PPC64LongBranchTargetSection::isNeeded() const { return !Finalized || !Entries.empty(); } +RISCVSdataSection::RISCVSdataSection() + : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, 1, ".sdata") {} + +bool RISCVSdataSection::isNeeded() const { + if (!ElfSym::RISCVGlobalPointer) + return false; + + // __global_pointer$ is defined relative to .sdata . If the section does not + // exist, create a dummy one. + for (BaseCommand *Base : getParent()->SectionCommands) + if (auto *ISD = dyn_cast<InputSectionDescription>(Base)) + for (InputSection *IS : ISD->Sections) + if (IS != this) + return false; + return true; +} + static uint8_t getAbiVersion() { // MIPS non-PIC executable gets ABI version 1. if (Config->EMachine == EM_MIPS) { diff --git a/lld/ELF/SyntheticSections.h b/lld/ELF/SyntheticSections.h index 0dcc44e7fb7..ace9f26155a 100644 --- a/lld/ELF/SyntheticSections.h +++ b/lld/ELF/SyntheticSections.h @@ -1098,6 +1098,15 @@ public: void writeTo(uint8_t *Buf) override; }; +// Create a dummy .sdata for __global_pointer$ if .sdata does not exist. +class RISCVSdataSection final : public SyntheticSection { +public: + RISCVSdataSection(); + size_t getSize() const override { return 0; } + bool isNeeded() const override; + void writeTo(uint8_t *Buf) override {} +}; + InputSection *createInterpSection(); MergeInputSection *createCommentSection(); template <class ELFT> void splitSections(); @@ -1162,6 +1171,7 @@ struct InStruct { PltSection *Plt; PltSection *Iplt; PPC32Got2Section *PPC32Got2; + RISCVSdataSection *RISCVSdata; RelocationBaseSection *RelaPlt; RelocationBaseSection *RelaIplt; StringTableSection *ShStrTab; diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp index c6ba893db0b..a667c9b28ab 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -476,6 +476,11 @@ template <class ELFT> static void createSyntheticSections() { Add(In.PPC64LongBranchTarget); } + if (Config->EMachine == EM_RISCV) { + In.RISCVSdata = make<RISCVSdataSection>(); + Add(In.RISCVSdata); + } + In.GotPlt = make<GotPltSection>(); Add(In.GotPlt); In.IgotPlt = make<IgotPltSection>(); @@ -1692,9 +1697,11 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() { addRelIpltSymbols(); // RISC-V's gp can address +/- 2 KiB, set it to .sdata + 0x800 if not defined. - if (Config->EMachine == EM_RISCV) - if (!dyn_cast_or_null<Defined>(Symtab->find("__global_pointer$"))) - addOptionalRegular("__global_pointer$", findSection(".sdata"), 0x800); + // This symbol should only be defined in an executable. + if (Config->EMachine == EM_RISCV && !Config->Shared) + ElfSym::RISCVGlobalPointer = + addOptionalRegular("__global_pointer$", findSection(".sdata"), 0x800, + STV_DEFAULT, STB_GLOBAL); if (Config->EMachine == EM_X86_64) { // On targets that support TLSDESC, _TLS_MODULE_BASE_ is defined in such a @@ -1871,6 +1878,7 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() { finalizeSynthetic(In.Plt); finalizeSynthetic(In.Iplt); finalizeSynthetic(In.PPC32Got2); + finalizeSynthetic(In.RISCVSdata); finalizeSynthetic(In.PartIndex); // Dynamic section must be the last one in this list and dynamic diff --git a/lld/test/ELF/riscv-gp-dummy-sdata.s b/lld/test/ELF/riscv-gp-dummy-sdata.s new file mode 100644 index 00000000000..e04b170d5b2 --- /dev/null +++ b/lld/test/ELF/riscv-gp-dummy-sdata.s @@ -0,0 +1,25 @@ +# REQUIRES: riscv +# RUN: llvm-mc -filetype=obj -triple=riscv32 %s -o %t.32.o +# RUN: ld.lld -pie %t.32.o -o %t.32 +# RUN: llvm-readelf -S %t.32 | FileCheck --check-prefix=SEC %s +# RUN: llvm-readelf -s %t.32 | FileCheck --check-prefix=SYM %s + +# RUN: llvm-mc -filetype=obj -triple=riscv64 %s -o %t.64.o +# RUN: ld.lld -pie %t.64.o -o %t.64 +# RUN: llvm-readelf -S %t.64 | FileCheck --check-prefix=SEC %s +# RUN: llvm-readelf -s %t.64 | FileCheck --check-prefix=SYM %s + +## If there is an undefined reference to __global_pointer$ but .sdata doesn't +## exist, create a dummy one. + +## __global_pointer$ = .sdata+0x800 +# SEC: [ 7] .sdata PROGBITS {{0*}}00003000 +# SYM: {{0*}}00003800 0 NOTYPE GLOBAL DEFAULT 7 __global_pointer$ + +## If __global_pointer$ is not used, don't create .sdata . + +# RUN: llvm-mc -filetype=obj -triple=riscv32 /dev/null -o %t.32.o +# RUN: ld.lld -pie %t.32.o -o %t.32 +# RUN: llvm-readelf -S %t.32 | FileCheck --implicit-check-not=.sdata /dev/null + +lla gp, __global_pointer$ diff --git a/lld/test/ELF/riscv-gp.s b/lld/test/ELF/riscv-gp.s new file mode 100644 index 00000000000..83b5f0dd735 --- /dev/null +++ b/lld/test/ELF/riscv-gp.s @@ -0,0 +1,26 @@ +# REQUIRES: riscv +# RUN: llvm-mc -filetype=obj -triple=riscv32 %s -o %t.32.o +# RUN: ld.lld -pie %t.32.o -o %t.32 +# RUN: llvm-readelf -s %t.32 | FileCheck --check-prefix=SYM %s +# RUN: llvm-readelf -S %t.32 | FileCheck --check-prefix=SEC %s +# RUN: not ld.lld -shared %t.32.o -o /dev/null 2>&1 | FileCheck --check-prefix=ERR %s + +# RUN: llvm-mc -filetype=obj -triple=riscv64 %s -o %t.64.o +# RUN: ld.lld -pie %t.64.o -o %t.64 +# RUN: llvm-readelf -s %t.64 | FileCheck --check-prefix=SYM %s +# RUN: llvm-readelf -S %t.64 | FileCheck --check-prefix=SEC %s +# RUN: not ld.lld -shared %t.64.o -o /dev/null 2>&1 | FileCheck --check-prefix=ERR %s + +## __global_pointer$ = .sdata+0x800 = 0x3800 +# SEC: [ 7] .sdata PROGBITS {{0*}}00003000 +# SYM: {{0*}}00003800 0 NOTYPE GLOBAL DEFAULT 7 __global_pointer$ + +## __global_pointer$ - 0x1000 = 4096*3-2048 +# DIS: 1000: auipc gp, 3 +# DIS-NEXT: addi gp, gp, -2048 + +# ERR: error: relocation R_RISCV_PCREL_HI20 cannot be used against symbol __global_pointer$; recompile with -fPIC + +lla gp, __global_pointer$ + +.section .sdata,"aw" |

