Index: ELF/SyntheticSections.h =================================================================== --- ELF/SyntheticSections.h +++ ELF/SyntheticSections.h @@ -1098,6 +1098,15 @@ 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 void splitSections(); Index: ELF/SyntheticSections.cpp =================================================================== --- ELF/SyntheticSections.cpp +++ ELF/SyntheticSections.cpp @@ -3386,6 +3386,20 @@ return !Finalized || !Entries.empty(); } +RISCVSdataSection::RISCVSdataSection() + : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, 1, ".sdata") {} + +bool RISCVSdataSection::isNeeded() const { + // __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(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) { Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -476,6 +476,9 @@ Add(In.PPC64LongBranchTarget); } + if (Config->EMachine == EM_RISCV) + Add(make()); + In.GotPlt = make(); Add(In.GotPlt); In.IgotPlt = make(); @@ -1693,8 +1696,8 @@ // 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(Symtab->find("__global_pointer$"))) - addOptionalRegular("__global_pointer$", findSection(".sdata"), 0x800); + 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 Index: test/ELF/riscv-gp-dummy-sdata.s =================================================================== --- /dev/null +++ test/ELF/riscv-gp-dummy-sdata.s @@ -0,0 +1,20 @@ +# 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. + +# SEC: [ 7] .sdata PROGBITS {{0*}}00003000 + +## __global_pointer$ = .sdata+0x800 +# SYM: {{0*}}00003800 0 NOTYPE GLOBAL DEFAULT 7 __global_pointer$ + +lla gp, __global_pointer$ Index: test/ELF/riscv-gp.s =================================================================== --- /dev/null +++ test/ELF/riscv-gp.s @@ -0,0 +1,22 @@ +# 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: 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 + +## __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 + +lla gp, __global_pointer$ + +.section .sdata,"aw"