From c8d298df422106cd08f8032ab26ebdd98abd4fc9 Mon Sep 17 00:00:00 2001 From: deepakshirkem Date: Sun, 3 May 2026 02:01:18 +0530 Subject: [PATCH] [X86] Emit _GLOBAL_OFFSET_TABLE_ symbol for x86-64 ELD did not emit _GLOBAL_OFFSET_TABLE_ for x86-64, causing an undefined reference error when object files reference this symbol. Add _GLOBAL_OFFSET_TABLE_ support for x86-64 and refactor the common implementation into GNULDBackend base class: - GNULDBackend::defineGlobalOffsetTableSymbol(): new helper that defines _GLOBAL_OFFSET_TABLE_ with consistent properties across all targets: Type: Object - consistent with ARM ELD and BFD Binding: Local - consistent with ARM ELD and BFD Visibility: Hidden - consistent with ARM ELD and LLD - x86_64LDBackend::initTargetSymbols(): use helper instead of duplicated addSymbol block. - x86_64LDBackend::defineGOTSymbol(): bind symbol to first .got.plt fragment so it points to the GOT base address. - x86_64LDBackend::finalizeScanRelocations(): call defineGOTSymbol() after scan and report an error if .got.plt is discarded but the symbol is referenced, consistent with GNU ld behavior. Refactor ARM, AArch64, Hexagon backends to use the same helper, eliminating duplicated code. Add _GLOBAL_OFFSET_TABLE_ to RISCV backend which was missing it entirely. Move tests from x86_64/standalone/ to Common/standalone/ following the DynamicGOTPLT pattern. Add per-target test variants for ARM, AArch64, Hexagon, and RISCV covering executable, shared library, PIE, and discard error cases. Fixes #570. Signed-off-by: deepakshirkem --- include/eld/Target/GNULDBackend.h | 1 + lib/Target/AArch64/AArch64LDBackend.cpp | 63 +++++++------------ lib/Target/ARM/ARMLDBackend.cpp | 31 +++------ lib/Target/GNULDBackend.cpp | 16 +++++ lib/Target/Hexagon/HexagonLDBackend.cpp | 24 ++----- lib/Target/RISCV/RISCVLDBackend.cpp | 36 ++++++----- lib/Target/X86/x86_64LDBackend.cpp | 42 +++++++++++++ lib/Target/X86/x86_64LDBackend.h | 7 ++- .../GlobalOffsetTable/GlobalOffsetTable.test | 15 +++++ .../standalone/GlobalOffsetTable/Inputs/1.c | 7 +++ .../GlobalOffsetTableDiscard_ARM.test | 14 +++++ .../GlobalOffsetTableDiscard_Hexagon.test | 12 ++++ .../GlobalOffsetTableDiscard_RISCV.test | 13 ++++ .../GlobalOffsetTableDiscard_X86.test | 13 ++++ .../GlobalOffsetTableDiscard/Inputs/1.c | 4 ++ .../GlobalOffsetTableDiscard/Inputs/1_arm.c | 5 ++ .../GlobalOffsetTableDiscard/Inputs/discard.t | 3 + .../GlobalOffsetTableDiscard/Inputs/lib_arm.c | 1 + .../GlobalOffsetTablePIE_ARM.test | 13 ++++ .../GlobalOffsetTablePIE_Hexagon.test | 13 ++++ .../GlobalOffsetTablePIE_RISCV.test | 13 ++++ .../GlobalOffsetTablePIE_X86.test | 14 +++++ .../GlobalOffsetTablePIE/Inputs/1.c | 4 ++ .../GlobalOffsetTablePIE/Inputs/1_aarch64.c | 3 + .../GlobalOffsetTablePIE/Inputs/1_arm.c | 6 ++ .../GlobalOffsetTablePIE/Inputs/1_hexagon.c | 5 ++ .../GlobalOffsetTableShared_ARM.test | 13 ++++ .../GlobalOffsetTableShared_Hexagon.test | 13 ++++ .../GlobalOffsetTableShared_RISCV.test | 13 ++++ .../GlobalOffsetTableShared_X86.test | 14 +++++ .../GlobalOffsetTableShared/Inputs/1.c | 4 ++ .../Inputs/1_aarch64.c | 3 + .../GlobalOffsetTableShared/Inputs/1_arm.c | 6 ++ .../Inputs/1_hexagon.c | 5 ++ .../GlobalOffsetTable/GlobalOffsetTable.test | 13 ---- .../standalone/GlobalOffsetTable/Inputs/1.c | 3 - test/lit.cfg | 7 +++ 37 files changed, 355 insertions(+), 117 deletions(-) create mode 100644 test/Common/standalone/GlobalOffsetTable/GlobalOffsetTable.test create mode 100644 test/Common/standalone/GlobalOffsetTable/Inputs/1.c create mode 100644 test/Common/standalone/GlobalOffsetTableDiscard/GlobalOffsetTableDiscard_ARM.test create mode 100644 test/Common/standalone/GlobalOffsetTableDiscard/GlobalOffsetTableDiscard_Hexagon.test create mode 100644 test/Common/standalone/GlobalOffsetTableDiscard/GlobalOffsetTableDiscard_RISCV.test create mode 100644 test/Common/standalone/GlobalOffsetTableDiscard/GlobalOffsetTableDiscard_X86.test create mode 100644 test/Common/standalone/GlobalOffsetTableDiscard/Inputs/1.c create mode 100644 test/Common/standalone/GlobalOffsetTableDiscard/Inputs/1_arm.c create mode 100644 test/Common/standalone/GlobalOffsetTableDiscard/Inputs/discard.t create mode 100644 test/Common/standalone/GlobalOffsetTableDiscard/Inputs/lib_arm.c create mode 100644 test/Common/standalone/GlobalOffsetTablePIE/GlobalOffsetTablePIE_ARM.test create mode 100644 test/Common/standalone/GlobalOffsetTablePIE/GlobalOffsetTablePIE_Hexagon.test create mode 100644 test/Common/standalone/GlobalOffsetTablePIE/GlobalOffsetTablePIE_RISCV.test create mode 100644 test/Common/standalone/GlobalOffsetTablePIE/GlobalOffsetTablePIE_X86.test create mode 100644 test/Common/standalone/GlobalOffsetTablePIE/Inputs/1.c create mode 100644 test/Common/standalone/GlobalOffsetTablePIE/Inputs/1_aarch64.c create mode 100644 test/Common/standalone/GlobalOffsetTablePIE/Inputs/1_arm.c create mode 100644 test/Common/standalone/GlobalOffsetTablePIE/Inputs/1_hexagon.c create mode 100644 test/Common/standalone/GlobalOffsetTableShared/GlobalOffsetTableShared_ARM.test create mode 100644 test/Common/standalone/GlobalOffsetTableShared/GlobalOffsetTableShared_Hexagon.test create mode 100644 test/Common/standalone/GlobalOffsetTableShared/GlobalOffsetTableShared_RISCV.test create mode 100644 test/Common/standalone/GlobalOffsetTableShared/GlobalOffsetTableShared_X86.test create mode 100644 test/Common/standalone/GlobalOffsetTableShared/Inputs/1.c create mode 100644 test/Common/standalone/GlobalOffsetTableShared/Inputs/1_aarch64.c create mode 100644 test/Common/standalone/GlobalOffsetTableShared/Inputs/1_arm.c create mode 100644 test/Common/standalone/GlobalOffsetTableShared/Inputs/1_hexagon.c delete mode 100644 test/RISCV/standalone/GlobalOffsetTable/GlobalOffsetTable.test delete mode 100644 test/RISCV/standalone/GlobalOffsetTable/Inputs/1.c diff --git a/include/eld/Target/GNULDBackend.h b/include/eld/Target/GNULDBackend.h index 5b0d81d9e..5dd84e194 100644 --- a/include/eld/Target/GNULDBackend.h +++ b/include/eld/Target/GNULDBackend.h @@ -932,6 +932,7 @@ class GNULDBackend { virtual void addTargetSpecificSegments(); void addSectionInfo(LDSymbol *symbol, ELFSection *section); + LDSymbol *defineGlobalOffsetTableSymbol(); /// Returns the name of the common symbol associated with the section /// 'commonSection'. diff --git a/lib/Target/AArch64/AArch64LDBackend.cpp b/lib/Target/AArch64/AArch64LDBackend.cpp index fb5dff28d..9d6924374 100644 --- a/lib/Target/AArch64/AArch64LDBackend.cpp +++ b/lib/Target/AArch64/AArch64LDBackend.cpp @@ -54,8 +54,7 @@ using namespace llvm; //===----------------------------------------------------------------------===// // AArch64LDBackend //===----------------------------------------------------------------------===// -AArch64LDBackend::AArch64LDBackend(eld::Module &pModule, - TargetInfo *pInfo) +AArch64LDBackend::AArch64LDBackend(eld::Module &pModule, TargetInfo *pInfo) : GNULDBackend(pModule, pInfo), m_pErrata843419Factory(nullptr), m_pAArch64ErrataIslandFactory(nullptr), m_pRelocator(nullptr), m_pDynamic(nullptr), m_pIRelativeStart(nullptr), m_pIRelativeEnd(nullptr), @@ -109,24 +108,8 @@ void AArch64LDBackend::initTargetSections(ObjectBuilder &pBuilder) { } void AArch64LDBackend::initTargetSymbols() { - // Define the symbol _GLOBAL_OFFSET_TABLE_ if there is a symbol with the - // same name in input - auto SymbolName = "_GLOBAL_OFFSET_TABLE_"; - if (LinkerConfig::Object != config().codeGenType()) { - m_pGOTSymbol = - m_Module.getIRBuilder() - ->addSymbol( - m_Module.getInternalInput(Module::Script), SymbolName, - ResolveInfo::Object, ResolveInfo::Define, ResolveInfo::Local, - 0x0, // size - 0x0, // value - FragmentRef::null(), ResolveInfo::Hidden); - if (m_Module.getConfig().options().isSymbolTracingRequested() && - m_Module.getConfig().options().traceSymbol(SymbolName)) - config().raise(Diag::target_specific_symbol) << SymbolName; - if (m_pGOTSymbol) - m_pGOTSymbol->setShouldIgnore(false); - } + if (LinkerConfig::Object != config().codeGenType()) + m_pGOTSymbol = defineGlobalOffsetTableSymbol(); } bool AArch64LDBackend::initRelocator() { @@ -136,8 +119,7 @@ bool AArch64LDBackend::initRelocator() { return true; } -bool AArch64LDBackend::processInputFiles( - std::vector &Inputs) { +bool AArch64LDBackend::processInputFiles(std::vector &Inputs) { if (!m_pGPF) return config().getDiagEngine()->diagnose(); for (auto &I : Inputs) { @@ -220,8 +202,7 @@ void AArch64LDBackend::doPreLayout() { m_ptbss = m_Module.getScript().sectionMap().find(".tbss"); } -void AArch64LDBackend::initSegmentFromLinkerScript( - ELFSegment *pSegment) { +void AArch64LDBackend::initSegmentFromLinkerScript(ELFSegment *pSegment) { auto sect = pSegment->begin(), sectEnd = pSegment->end(); bool isPrevBSS = false; bool hasMixedBSS = false; @@ -260,8 +241,8 @@ void AArch64LDBackend::initSegmentFromLinkerScript( AArch64ELFDynamic *AArch64LDBackend::dynamic() { return m_pDynamic; } -unsigned int AArch64LDBackend::getTargetSectionOrder( - const ELFSection &pSectHdr) const { +unsigned int +AArch64LDBackend::getTargetSectionOrder(const ELFSection &pSectHdr) const { if (pSectHdr.name() == ".got") { if (config().options().hasNow()) return SHO_RELRO; @@ -349,9 +330,8 @@ void AArch64LDBackend::mayBeRelax(int pass, bool &pFinished) { } // Return whether this is a 3-insn erratum sequence. -bool AArch64LDBackend::isErratum843419Sequence(uint32_t insn1, - uint32_t insn2, - uint32_t insn3) { +bool AArch64LDBackend::isErratum843419Sequence(uint32_t insn1, uint32_t insn2, + uint32_t insn3) { unsigned rt1, rt2; bool load, pair; @@ -462,7 +442,7 @@ bool AArch64LDBackend::scanErrata843419() { } void AArch64LDBackend::createErratum843419Stub(Fragment *frag, - uint32_t offset) { + uint32_t offset) { BranchIsland *branchIsland = m_pErrata843419Factory->create( frag, offset, *m_Module.getIRBuilder(), *m_pAArch64ErrataIslandFactory); switch (config().options().getStripSymbolMode()) { @@ -645,9 +625,9 @@ bool AArch64LDBackend::ltoNeedAssembler() { return true; } -bool AArch64LDBackend::ltoCallExternalAssembler( - const std::string &Input, std::string RelocModel, - const std::string &Output) { +bool AArch64LDBackend::ltoCallExternalAssembler(const std::string &Input, + std::string RelocModel, + const std::string &Output) { bool traceLTO = config().options().traceLTO(); // Invoke assembler. @@ -712,10 +692,8 @@ bool AArch64LDBackend::ltoCallExternalAssembler( } // Create GOT entry. -AArch64GOT *AArch64LDBackend::createGOT(GOT::GOTType T, - ELFObjectFile *Obj, - ResolveInfo *R, - bool SkipPLTRef) { +AArch64GOT *AArch64LDBackend::createGOT(GOT::GOTType T, ELFObjectFile *Obj, + ResolveInfo *R, bool SkipPLTRef) { if (R != nullptr && ((config().options().isSymbolTracingRequested() && config().options().traceSymbol(*R)) || @@ -827,7 +805,8 @@ void AArch64LDBackend::recordPLT(ResolveInfo *I, AArch64PLT *P) { m_PLTMap[I] = P; } -Relocation *AArch64LDBackend::findRelativeReloc(const Relocation *pReloc) const { +Relocation * +AArch64LDBackend::findRelativeReloc(const Relocation *pReloc) const { return m_RelativeRelocMap.lookup(pReloc); } @@ -894,7 +873,7 @@ ELFSection *AArch64LDBackend::mergeSection(ELFSection *S) { // Read .note.gnu.property and extract features for pointer authentication. template bool AArch64LDBackend::readGNUProperty(InputFile &pInput, ELFSection *S, - uint32_t &featureSet) { + uint32_t &featureSet) { using Elf_Nhdr = typename ELFT::Nhdr; using Elf_Note = typename ELFT::Note; @@ -973,10 +952,10 @@ namespace eld { //===----------------------------------------------------------------------===// GNULDBackend *createAArch64LDBackend(Module &pModule) { if (pModule.getConfig().targets().triple().isOSLinux()) - return make( - pModule, make(pModule.getConfig())); + return make(pModule, + make(pModule.getConfig())); return make(pModule, - make(pModule.getConfig())); + make(pModule.getConfig())); } uint64_t AArch64LDBackend::StaticTCBSize = 0x10; diff --git a/lib/Target/ARM/ARMLDBackend.cpp b/lib/Target/ARM/ARMLDBackend.cpp index 4a8a7743f..7ed79d8a0 100644 --- a/lib/Target/ARM/ARMLDBackend.cpp +++ b/lib/Target/ARM/ARMLDBackend.cpp @@ -126,31 +126,15 @@ void ARMGNULDBackend::initTargetSections(ObjectBuilder &pBuilder) { } void ARMGNULDBackend::initTargetSymbols() { - // Define the symbol _GLOBAL_OFFSET_TABLE_ if there is a symbol with the - // same name in input - auto SymbolName = "_GLOBAL_OFFSET_TABLE_"; - if (LinkerConfig::Object != config().codeGenType()) { - m_pGOTSymbol = - m_Module.getIRBuilder() - ->addSymbol( - m_Module.getInternalInput(Module::Script), SymbolName, - ResolveInfo::Object, ResolveInfo::Define, ResolveInfo::Local, - 0x0, // size - 0x0, // value - FragmentRef::null(), ResolveInfo::Hidden); - if (m_Module.getConfig().options().isSymbolTracingRequested() && - m_Module.getConfig().options().traceSymbol(SymbolName)) - config().raise(Diag::target_specific_symbol) << SymbolName; - if (m_pGOTSymbol) - m_pGOTSymbol->setShouldIgnore(false); - } + if (LinkerConfig::Object != config().codeGenType()) + m_pGOTSymbol = defineGlobalOffsetTableSymbol(); // If linker script, lets not add this symbol. if (m_Module.getScript().linkerScriptHasSectionsCommand()) return; - const NamePool& NP = m_Module.getNamePool(); - SymbolName = "__exidx_start"; + const NamePool &NP = m_Module.getNamePool(); + const char *SymbolName = "__exidx_start"; const ResolveInfo *EXIDXStartInfo = NP.findInfo(SymbolName); if (EXIDXStartInfo && EXIDXStartInfo->isUndef()) { m_pEXIDXStart = @@ -218,8 +202,7 @@ void ARMGNULDBackend::doPreLayout() { if (isMicroController() && ((config().codeGenType() == LinkerConfig::DynObj) || (config().options().isPIE()))) { - config().raise(Diag::not_supported) << "SharedLibrary/PIE" - << "Cortex-M"; + config().raise(Diag::not_supported) << "SharedLibrary/PIE" << "Cortex-M"; m_Module.setFailure(true); return; } @@ -517,7 +500,7 @@ bool ARMGNULDBackend::readSection(InputFile &pInput, ELFSection *S) { LayoutInfo *layoutInfo = getModule().getLayoutInfo(); if (layoutInfo) layoutInfo->recordFragment(m_pARMAttributeSection->getInputFile(), - m_pARMAttributeSection, AttributeFragment); + m_pARMAttributeSection, AttributeFragment); } AttributeFragment->updateAttributes( Region, m_Module, llvm::dyn_cast(&pInput), config()); @@ -1192,7 +1175,7 @@ void ARMGNULDBackend::finishAssignOutputSections() { LayoutInfo *layoutInfo = getModule().getLayoutInfo(); if (layoutInfo) layoutInfo->recordFragment(m_pRegionTableSection->getInputFile(), - m_pRegionTableSection, m_pRegionTableFragment); + m_pRegionTableSection, m_pRegionTableFragment); } // Update the RegionTable with updated information from the Backend. diff --git a/lib/Target/GNULDBackend.cpp b/lib/Target/GNULDBackend.cpp index 0dd419d59..f1dabbbb5 100644 --- a/lib/Target/GNULDBackend.cpp +++ b/lib/Target/GNULDBackend.cpp @@ -4885,6 +4885,22 @@ size_t GNULDBackend::getGOTSymbolAddr() const { return (fragRef->getOutputOffset(m_Module) + section->addr()); } +LDSymbol *GNULDBackend::defineGlobalOffsetTableSymbol() { + const std::string SymbolName = "_GLOBAL_OFFSET_TABLE_"; + LDSymbol *Sym = + m_Module.getIRBuilder() + ->addSymbol( + m_Module.getInternalInput(Module::Script), SymbolName, + ResolveInfo::Object, ResolveInfo::Define, ResolveInfo::Local, 0x0, + 0x0, FragmentRef::null(), ResolveInfo::Hidden); + if (Sym) + Sym->setShouldIgnore(false); + if (m_Module.getConfig().options().isSymbolTracingRequested() && + m_Module.getConfig().options().traceSymbol(SymbolName)) + config().raise(Diag::target_specific_symbol) << SymbolName; + return Sym; +} + std::string GNULDBackend::getCommonSymbolName(const CommonELFSection *commonSection) const { llvm::StringRef sectionName = commonSection->name(); diff --git a/lib/Target/Hexagon/HexagonLDBackend.cpp b/lib/Target/Hexagon/HexagonLDBackend.cpp index 8cad29296..c0f521ac1 100644 --- a/lib/Target/Hexagon/HexagonLDBackend.cpp +++ b/lib/Target/Hexagon/HexagonLDBackend.cpp @@ -250,8 +250,8 @@ void HexagonLDBackend::createAttributeSection() { AttributeFragment = make(AttributeSection); AttributeSection->addFragment(AttributeFragment); if (auto *layoutInfo = getModule().getLayoutInfo()) - layoutInfo->recordFragment(AttributeSection->getInputFile(), AttributeSection, - AttributeFragment); + layoutInfo->recordFragment(AttributeSection->getInputFile(), + AttributeSection, AttributeFragment); } void HexagonLDBackend::initTargetSections(ObjectBuilder &pBuilder) { @@ -314,23 +314,9 @@ void HexagonLDBackend::initTargetSections(ObjectBuilder &pBuilder) { void HexagonLDBackend::initTargetSymbols() { if (config().codeGenType() == LinkerConfig::Object) return; - auto SymbolName = "_GLOBAL_OFFSET_TABLE_"; - // Define the symbol _GLOBAL_OFFSET_TABLE_ if there is a symbol with the - // same name in input - m_pGOTSymbol = - m_Module.getIRBuilder() - ->addSymbol( - m_Module.getInternalInput(Module::Script), SymbolName, - ResolveInfo::Object, ResolveInfo::Define, ResolveInfo::Local, - 0x0, // size - 0x0, // value - FragmentRef::null(), ResolveInfo::Hidden); - if (m_pGOTSymbol) - m_pGOTSymbol->setShouldIgnore(false); - if (m_Module.getConfig().options().isSymbolTracingRequested() && - m_Module.getConfig().options().traceSymbol(SymbolName)) - config().raise(Diag::target_specific_symbol) << SymbolName; - SymbolName = "___end"; + m_pGOTSymbol = defineGlobalOffsetTableSymbol(); + + const char *SymbolName = "___end"; m_pEndOfImage = m_Module.getNamePool().findSymbol(SymbolName); if (!m_pEndOfImage) m_pEndOfImage = diff --git a/lib/Target/RISCV/RISCVLDBackend.cpp b/lib/Target/RISCV/RISCVLDBackend.cpp index bbfd5bbe8..5f330a7c9 100644 --- a/lib/Target/RISCV/RISCVLDBackend.cpp +++ b/lib/Target/RISCV/RISCVLDBackend.cpp @@ -110,7 +110,7 @@ void RISCVLDBackend::initTargetSections(ObjectBuilder &pBuilder) { LayoutInfo *layoutInfo = getModule().getLayoutInfo(); if (layoutInfo) layoutInfo->recordFragment(m_pRISCVAttributeSection->getInputFile(), - m_pRISCVAttributeSection, AttributeFragment); + m_pRISCVAttributeSection, AttributeFragment); if (LinkerConfig::Object == config().codeGenType()) return; @@ -135,7 +135,8 @@ void RISCVLDBackend::initPatchSections(ELFObjectFile &InputFile) { void RISCVLDBackend::initTargetSymbols() { if (config().codeGenType() == LinkerConfig::Object) return; - // Do not create another __global_pointer$ when linking a patch. + m_pGOTSymbol = defineGlobalOffsetTableSymbol(); + if (config().options().getPatchBase()) return; if (m_Module.getScript().linkerScriptHasSectionsCommand()) { @@ -312,7 +313,8 @@ bool RISCVLDBackend::doRelaxationCall(Relocation *reloc) { ->getInput() ->decoratedPath(); - region->replaceInstruction(offset, reloc, reinterpret_cast(&c_j), 2); + region->replaceInstruction(offset, reloc, reinterpret_cast(&c_j), + 2); reloc->setTargetData(c_j); reloc->setType(llvm::ELF::R_RISCV_RVC_JUMP); relaxDeleteBytes("RISCV_CALL_C", *region, offset + 2, 6, @@ -325,7 +327,8 @@ bool RISCVLDBackend::doRelaxationCall(Relocation *reloc) { // Replace the instruction to JAL uint32_t jal = 0x6fu | rd << 7; - region->replaceInstruction(offset, reloc, reinterpret_cast(&jal), 4); + region->replaceInstruction(offset, reloc, reinterpret_cast(&jal), + 4); reloc->setTargetData(jal); reloc->setType(llvm::ELF::R_RISCV_JAL); // Delete the next instruction @@ -344,7 +347,8 @@ bool RISCVLDBackend::doRelaxationCall(Relocation *reloc) { const char *msg = (rd == 1) ? "R_RISCV_CALL_QC_E_JAL" : "R_RISCV_CALL_QC_E_J"; - region->replaceInstruction(offset, reloc, reinterpret_cast(&qc_e_j), 6); + region->replaceInstruction(offset, reloc, + reinterpret_cast(&qc_e_j), 6); reloc->setTargetData(qc_e_j); reloc->setType(ELF::riscv::internal::R_RISCV_QC_E_CALL_PLT); relaxDeleteBytes(msg, *region, offset + 6, 2, reloc->symInfo()->name()); @@ -405,26 +409,26 @@ bool RISCVLDBackend::doRelaxationQCCall(Relocation *reloc) { ->getInput() ->decoratedPath(); - region->replaceInstruction(offset, reloc, reinterpret_cast(&compressed), 2); + region->replaceInstruction(offset, reloc, + reinterpret_cast(&compressed), 2); // Replace the reloc to R_RISCV_RVC_JUMP reloc->setType(llvm::ELF::R_RISCV_RVC_JUMP); reloc->setTargetData(compressed); - relaxDeleteBytes(msg, *region, offset + 2, 4, - reloc->symInfo()->name()); + relaxDeleteBytes(msg, *region, offset + 2, 4, reloc->symInfo()->name()); return true; } // Replace the instruction to JAL unsigned rd = isTailCall ? /*x0*/ 0 : /*ra*/ 1; uint32_t jal_instr = 0x6fu | rd << 7; - region->replaceInstruction(offset, reloc, reinterpret_cast(&jal_instr), 4); + region->replaceInstruction(offset, reloc, + reinterpret_cast(&jal_instr), 4); // Replace the reloc to R_RISCV_JAL reloc->setType(llvm::ELF::R_RISCV_JAL); reloc->setTargetData(jal_instr); // Delete the next instruction const char *msg = isTailCall ? "RISCV_QC_E_J" : "RISCV_QC_E_JAL"; - relaxDeleteBytes(msg, *region, offset + 4, 2, - reloc->symInfo()->name()); + relaxDeleteBytes(msg, *region, offset + 4, 2, reloc->symInfo()->name()); return true; } @@ -621,7 +625,8 @@ bool RISCVLDBackend::doRelaxationQCELi(Relocation *reloc, Relocator::DWord G) { if (canRelaxQcLi) { uint32_t qc_li = 0x0000001bu | rd << 7; - region->replaceInstruction(offset, reloc, reinterpret_cast(&qc_li), 4); + region->replaceInstruction(offset, reloc, + reinterpret_cast(&qc_li), 4); reloc->setTargetData(qc_li); reloc->setType(ELF::riscv::internal::R_RISCV_QC_ABS20_U); relaxDeleteBytes(msg, *region, offset + 4, 2, reloc->symInfo()->name()); @@ -633,7 +638,8 @@ bool RISCVLDBackend::doRelaxationQCELi(Relocation *reloc, Relocator::DWord G) { unsigned rs = 3; // x3 = gp uint32_t addi = 0x00000013u | (rd << 7) | (rs << 15); - region->replaceInstruction(offset, reloc, reinterpret_cast(&addi), 4); + region->replaceInstruction(offset, reloc, + reinterpret_cast(&addi), 4); reloc->setTargetData(addi); reloc->setType(ELF::riscv::internal::R_RISCV_GPREL_I); relaxDeleteBytes(msg, *region, offset + 4, 2, reloc->symInfo()->name()); @@ -669,8 +675,8 @@ bool RISCVLDBackend::doRelaxationTLSDESC(Relocation &R, bool Relax) { // Otherwise, the instruction is replaced with a NOP. reportMissedRelaxation(RelaxType, *region, offset, 4, Sym.name()); uint32_t NOPi32 = static_cast(NOP); - region->replaceInstruction( - offset, &R, reinterpret_cast(&NOPi32), 4); + region->replaceInstruction(offset, &R, + reinterpret_cast(&NOPi32), 4); } R.setType(llvm::ELF::R_RISCV_NONE); return Relaxed; diff --git a/lib/Target/X86/x86_64LDBackend.cpp b/lib/Target/X86/x86_64LDBackend.cpp index 06106997a..ad82d98d7 100644 --- a/lib/Target/X86/x86_64LDBackend.cpp +++ b/lib/Target/X86/x86_64LDBackend.cpp @@ -83,6 +83,7 @@ void x86_64LDBackend::initDynamicSections(ELFObjectFile &InputFile) { void x86_64LDBackend::initTargetSymbols() { if (config().codeGenType() == LinkerConfig::Object) return; + m_pGOTSymbol = defineGlobalOffsetTableSymbol(); m_pEndOfImage = m_Module.getIRBuilder()->addSymbol( @@ -95,6 +96,47 @@ void x86_64LDBackend::initTargetSymbols() { m_pEndOfImage->setShouldIgnore(false); } +void x86_64LDBackend::defineGOTSymbol(Fragment &pFrag) { + const std::string GOTSymName = "_GLOBAL_OFFSET_TABLE_"; + if (m_pGOTSymbol != nullptr) { + m_pGOTSymbol = + m_Module.getIRBuilder() + ->addSymbol( + m_Module.getInternalInput(Module::Script), GOTSymName, + ResolveInfo::Object, ResolveInfo::Define, ResolveInfo::Local, + 0x0, // size + 0x0, // value + make(pFrag, 0x0), ResolveInfo::Hidden); + } else { + m_pGOTSymbol = + m_Module.getIRBuilder() + ->addSymbol( + pFrag.getOwningSection()->getInputFile(), GOTSymName, + ResolveInfo::Object, ResolveInfo::Define, ResolveInfo::Local, + 0x0, // size + 0x0, // value + make(pFrag, 0x0), ResolveInfo::Hidden); + } + if (m_pGOTSymbol) + m_pGOTSymbol->setShouldIgnore(false); +} + +bool x86_64LDBackend::finalizeScanRelocations() { + if (m_pGOTSymbol != nullptr && !getGOTPLT()->isIgnore()) + createGOT(GOT::GOTPLT0, nullptr, nullptr); + Fragment *frag = nullptr; + if (auto *GOTPLT = getGOTPLT()) { + if (!GOTPLT->isIgnore() && GOTPLT->hasFragments()) + frag = *GOTPLT->getFragmentList().begin(); + } + if (frag) { + defineGOTSymbol(*frag); + } else if (m_pGOTSymbol != nullptr) { + reportErrorIfGOTPLTIsDiscarded(m_pGOTSymbol->resolveInfo()); + } + return true; +} + bool x86_64LDBackend::initBRIslandFactory() { return true; } bool x86_64LDBackend::initStubFactory() { return true; } diff --git a/lib/Target/X86/x86_64LDBackend.h b/lib/Target/X86/x86_64LDBackend.h index 6c9f08e8d..a33abb57f 100644 --- a/lib/Target/X86/x86_64LDBackend.h +++ b/lib/Target/X86/x86_64LDBackend.h @@ -55,6 +55,10 @@ class x86_64LDBackend : public GNULDBackend { /// finalizeTargetSymbols - finalize the symbol value bool finalizeTargetSymbols() override; + bool finalizeScanRelocations() override; + + void defineGOTSymbol(Fragment &pFrag); + uint64_t getValueForDiscardedRelocations(const Relocation *R) const override; x86_64ELFDynamic *dynamic() override; @@ -109,7 +113,8 @@ class x86_64LDBackend : public GNULDBackend { return DynRelocType::GLOB_DAT; if (X->type() == llvm::ELF::R_X86_64_JUMP_SLOT) return DynRelocType::JMP_SLOT; - if (X->type() == llvm::ELF::R_X86_64_RELATIVE || X->type()==llvm::ELF::R_X86_64_IRELATIVE) + if (X->type() == llvm::ELF::R_X86_64_RELATIVE || + X->type() == llvm::ELF::R_X86_64_IRELATIVE) return DynRelocType::RELATIVE; if (X->type() == llvm::ELF::R_X86_64_DTPMOD64) { if (X->symInfo() && X->symInfo()->binding() == ResolveInfo::Local) diff --git a/test/Common/standalone/GlobalOffsetTable/GlobalOffsetTable.test b/test/Common/standalone/GlobalOffsetTable/GlobalOffsetTable.test new file mode 100644 index 000000000..78767122e --- /dev/null +++ b/test/Common/standalone/GlobalOffsetTable/GlobalOffsetTable.test @@ -0,0 +1,15 @@ +#----------GlobalOffsetTable.test--------------------- Executable ------# +#BEGIN_COMMENT +# Test that _GLOBAL_OFFSET_TABLE_ symbol is emitted and points to +# the GOT section with a non-zero address. +# The GOT section name varies per target: +# .got.plt -> X86, ARM, Hexagon +# .got -> AArch64, RISCV +#END_COMMENT +#START_TEST +RUN: %clang %clangopts -c %p/Inputs/1.c -o %t1.o -fPIC -ffunction-sections +RUN: %link %linkopts %t1.o -o %t1.out 2>&1 +RUN: %readelf -S -W -s %t1.out 2>&1 | %filecheck %s -DGlobalOffsetTableSection=%GlobalOffsetTableSection +#END_TEST +CHECK: [[GlobalOffsetTableSection]] PROGBITS [[ADDR:0*[1-9a-f][0-9a-f]*]] +CHECK: {{.*}} [[ADDR]] {{.*}} _GLOBAL_OFFSET_TABLE_ diff --git a/test/Common/standalone/GlobalOffsetTable/Inputs/1.c b/test/Common/standalone/GlobalOffsetTable/Inputs/1.c new file mode 100644 index 000000000..ede309d9d --- /dev/null +++ b/test/Common/standalone/GlobalOffsetTable/Inputs/1.c @@ -0,0 +1,7 @@ +extern int _GLOBAL_OFFSET_TABLE_; + +int *v = &_GLOBAL_OFFSET_TABLE_; + +int a = 0; + +int foo() { return a; } diff --git a/test/Common/standalone/GlobalOffsetTableDiscard/GlobalOffsetTableDiscard_ARM.test b/test/Common/standalone/GlobalOffsetTableDiscard/GlobalOffsetTableDiscard_ARM.test new file mode 100644 index 000000000..4834a76e5 --- /dev/null +++ b/test/Common/standalone/GlobalOffsetTableDiscard/GlobalOffsetTableDiscard_ARM.test @@ -0,0 +1,14 @@ +#---GlobalOffsetTableDiscard_ARM.test----------- Executable -----------------# +# REQUIRES: arm +#BEGIN_COMMENT +# Verify that ELD errors out when a GOTPLT relocation is present +# but .got.plt section is discarded via linker script for ARM. +# Consistent with GNU ld behavior. +#END_COMMENT +#START_TEST +RUN: %clang %clangopts -c %p/Inputs/lib_arm.c -o %t1.lib.o -fPIC -ffunction-sections +RUN: %link %linkopts %t1.lib.o -o %t1.so -shared 2>&1 +RUN: %clang %clangopts -c %p/Inputs/1_arm.c -o %t1.o -fPIC -ffunction-sections +RUN: %not %link %linkopts -T %p/Inputs/discard.t %t1.o %t1.so -o %t1.out 2>&1 | %filecheck %s +#END_TEST +CHECK: depends upon discarded .got.plt section diff --git a/test/Common/standalone/GlobalOffsetTableDiscard/GlobalOffsetTableDiscard_Hexagon.test b/test/Common/standalone/GlobalOffsetTableDiscard/GlobalOffsetTableDiscard_Hexagon.test new file mode 100644 index 000000000..bc8ef7f18 --- /dev/null +++ b/test/Common/standalone/GlobalOffsetTableDiscard/GlobalOffsetTableDiscard_Hexagon.test @@ -0,0 +1,12 @@ +#---GlobalOffsetTableDiscard_Hexagon.test----------- Executable -----------------# +# REQUIRES: hexagon +#BEGIN_COMMENT +# Verify that ELD errors out when _GLOBAL_OFFSET_TABLE_ is referenced +# but .got.plt section is discarded via linker script for Hexagon. +#END_COMMENT +#START_TEST +RUN: %clang %clangopts -c %p/Inputs/1.c -o %t1.o -fPIC -ffunction-sections +RUN: %not %link %linkopts -T %p/Inputs/discard.t %t1.o -o %t1.out 2>&1 | %filecheck %s +#END_TEST +CHECK: _GLOBAL_OFFSET_TABLE_ +CHECK: defined in discarded section diff --git a/test/Common/standalone/GlobalOffsetTableDiscard/GlobalOffsetTableDiscard_RISCV.test b/test/Common/standalone/GlobalOffsetTableDiscard/GlobalOffsetTableDiscard_RISCV.test new file mode 100644 index 000000000..ec6f1d3a9 --- /dev/null +++ b/test/Common/standalone/GlobalOffsetTableDiscard/GlobalOffsetTableDiscard_RISCV.test @@ -0,0 +1,13 @@ +#---GlobalOffsetTableDiscard_RISCV.test----------- Executable -----------------# +# REQUIRES: riscv +#BEGIN_COMMENT +# Verify that ELD errors out when _GLOBAL_OFFSET_TABLE_ is referenced +# but .got.plt section is discarded via linker script for RISCV. +# Consistent with GNU ld behavior. +#END_COMMENT +#START_TEST +RUN: %clang %clangopts -c %p/Inputs/1.c -o %t1.o -fPIC -ffunction-sections +RUN: %not %link %linkopts -T %p/Inputs/discard.t %t1.o -o %t1.out 2>&1 | %filecheck %s +#END_TEST +CHECK: symbol '_GLOBAL_OFFSET_TABLE_' referenced +CHECK: depends upon discarded .got.plt section diff --git a/test/Common/standalone/GlobalOffsetTableDiscard/GlobalOffsetTableDiscard_X86.test b/test/Common/standalone/GlobalOffsetTableDiscard/GlobalOffsetTableDiscard_X86.test new file mode 100644 index 000000000..8047836c6 --- /dev/null +++ b/test/Common/standalone/GlobalOffsetTableDiscard/GlobalOffsetTableDiscard_X86.test @@ -0,0 +1,13 @@ +#---GlobalOffsetTableDiscard.test----------- Executable -----------------# +# REQUIRES: x86 +#BEGIN_COMMENT +# Verify that ELD errors out when _GLOBAL_OFFSET_TABLE_ is referenced +# but .got.plt section is discarded via linker script. +# Consistent with GNU ld behavior. +#END_COMMENT +#START_TEST +RUN: %clang %clangopts -c %p/Inputs/1.c -o %t1.o -fPIC -ffunction-sections +RUN: %not %link %linkopts -T %p/Inputs/discard.t %t1.o -o %t1.out 2>&1 | %filecheck %s +#END_TEST +CHECK: symbol '_GLOBAL_OFFSET_TABLE_' referenced +CHECK: depends upon discarded .got.plt section diff --git a/test/Common/standalone/GlobalOffsetTableDiscard/Inputs/1.c b/test/Common/standalone/GlobalOffsetTableDiscard/Inputs/1.c new file mode 100644 index 000000000..aa4002fdb --- /dev/null +++ b/test/Common/standalone/GlobalOffsetTableDiscard/Inputs/1.c @@ -0,0 +1,4 @@ +extern int _GLOBAL_OFFSET_TABLE_; +int *v = &_GLOBAL_OFFSET_TABLE_; +int a = 0; +int foo() { return a; } diff --git a/test/Common/standalone/GlobalOffsetTableDiscard/Inputs/1_arm.c b/test/Common/standalone/GlobalOffsetTableDiscard/Inputs/1_arm.c new file mode 100644 index 000000000..f805b79e4 --- /dev/null +++ b/test/Common/standalone/GlobalOffsetTableDiscard/Inputs/1_arm.c @@ -0,0 +1,5 @@ +// Calling an external function forces a PLT/GOTPLT entry on ARM +// which triggers reportErrorIfGOTPLTIsDiscarded when .got.plt is discarded +extern int external_func(); +int foo() { return external_func(); } +int bar() { return foo(); } diff --git a/test/Common/standalone/GlobalOffsetTableDiscard/Inputs/discard.t b/test/Common/standalone/GlobalOffsetTableDiscard/Inputs/discard.t new file mode 100644 index 000000000..1fb569773 --- /dev/null +++ b/test/Common/standalone/GlobalOffsetTableDiscard/Inputs/discard.t @@ -0,0 +1,3 @@ +SECTIONS { + /DISCARD/ : { *(.got.plt) } +} diff --git a/test/Common/standalone/GlobalOffsetTableDiscard/Inputs/lib_arm.c b/test/Common/standalone/GlobalOffsetTableDiscard/Inputs/lib_arm.c new file mode 100644 index 000000000..00174e400 --- /dev/null +++ b/test/Common/standalone/GlobalOffsetTableDiscard/Inputs/lib_arm.c @@ -0,0 +1 @@ +int external_func() { return 42; } diff --git a/test/Common/standalone/GlobalOffsetTablePIE/GlobalOffsetTablePIE_ARM.test b/test/Common/standalone/GlobalOffsetTablePIE/GlobalOffsetTablePIE_ARM.test new file mode 100644 index 000000000..3147e8fbf --- /dev/null +++ b/test/Common/standalone/GlobalOffsetTablePIE/GlobalOffsetTablePIE_ARM.test @@ -0,0 +1,13 @@ +#---GlobalOffsetTablePIE_ARM.test----------- PIE Executable ------------------# +# REQUIRES: arm +#BEGIN_COMMENT +# Verify that _GLOBAL_OFFSET_TABLE_ is emitted with a valid address +# pointing to .got.plt when building a PIE executable for ARM. +#END_COMMENT +#START_TEST +RUN: %clang %clangopts -c %p/Inputs/1_arm.c -o %t1.o -fPIC -ffunction-sections +RUN: %link %linkopts %t1.o -o %t1.pie -pie 2>&1 +RUN: %readelf -S -W -s %t1.pie 2>&1 | %filecheck %s +#END_TEST +CHECK: .got.plt PROGBITS [[ADDR:[xa-f0-9]+]] +CHECK: {{.*}} [[ADDR]] {{.*}} _GLOBAL_OFFSET_TABLE_ diff --git a/test/Common/standalone/GlobalOffsetTablePIE/GlobalOffsetTablePIE_Hexagon.test b/test/Common/standalone/GlobalOffsetTablePIE/GlobalOffsetTablePIE_Hexagon.test new file mode 100644 index 000000000..2a637ce2a --- /dev/null +++ b/test/Common/standalone/GlobalOffsetTablePIE/GlobalOffsetTablePIE_Hexagon.test @@ -0,0 +1,13 @@ +#---GlobalOffsetTablePIE_Hexagon.test----------- PIE Executable ------------------# +# REQUIRES: hexagon +#BEGIN_COMMENT +# Verify that _GLOBAL_OFFSET_TABLE_ is emitted with a valid address +# pointing to .got.plt when building a PIE executable for Hexagon. +#END_COMMENT +#START_TEST +RUN: %clang %clangopts -c %p/Inputs/1_hexagon.c -o %t1.o -fPIC -ffunction-sections +RUN: %link %linkopts %t1.o -o %t1.pie -pie 2>&1 +RUN: %readelf -S -W -s %t1.pie 2>&1 | %filecheck %s +#END_TEST +CHECK: .got.plt PROGBITS [[ADDR:[xa-f0-9]+]] +CHECK: {{.*}} [[ADDR]] {{.*}} _GLOBAL_OFFSET_TABLE_ diff --git a/test/Common/standalone/GlobalOffsetTablePIE/GlobalOffsetTablePIE_RISCV.test b/test/Common/standalone/GlobalOffsetTablePIE/GlobalOffsetTablePIE_RISCV.test new file mode 100644 index 000000000..41b38690b --- /dev/null +++ b/test/Common/standalone/GlobalOffsetTablePIE/GlobalOffsetTablePIE_RISCV.test @@ -0,0 +1,13 @@ +#---GlobalOffsetTablePIE_RISCV.test----------- PIE Executable ------------------# +# REQUIRES: riscv +#BEGIN_COMMENT +# Verify that _GLOBAL_OFFSET_TABLE_ is emitted with a valid address +# pointing to .got when building a PIE executable for RISCV. +#END_COMMENT +#START_TEST +RUN: %clang %clangopts -c %p/Inputs/1.c -o %t1.o -fPIC -ffunction-sections +RUN: %link %linkopts %t1.o -o %t1.pie -pie 2>&1 +RUN: %readelf -S -W -s %t1.pie 2>&1 | %filecheck %s +#END_TEST +CHECK: .got PROGBITS [[ADDR:[xa-f0-9]+]] +CHECK: {{.*}} [[ADDR]] {{.*}} _GLOBAL_OFFSET_TABLE_ diff --git a/test/Common/standalone/GlobalOffsetTablePIE/GlobalOffsetTablePIE_X86.test b/test/Common/standalone/GlobalOffsetTablePIE/GlobalOffsetTablePIE_X86.test new file mode 100644 index 000000000..673abd6dd --- /dev/null +++ b/test/Common/standalone/GlobalOffsetTablePIE/GlobalOffsetTablePIE_X86.test @@ -0,0 +1,14 @@ +#---GlobalOffsetTablePIE.test----------- PIE Executable ------------------# +# REQUIRES: x86 +#BEGIN_COMMENT +# Verify that _GLOBAL_OFFSET_TABLE_ is emitted with a valid address +# pointing to .got.plt when building a PIE executable with no PLT +# relocations. ELD was incorrectly emitting value 0x0 in this case. +#END_COMMENT +#START_TEST +RUN: %clang %clangopts -c %p/Inputs/1.c -o %t1.o -fPIC -ffunction-sections +RUN: %link %linkopts %t1.o -o %t1.pie -pie 2>&1 +RUN: %readelf -S -W -s %t1.pie 2>&1 | %filecheck %s +#END_TEST +CHECK: .got.plt PROGBITS [[ADDR:[xa-f0-9]+]] +CHECK: {{.*}} [[ADDR]] {{.*}} _GLOBAL_OFFSET_TABLE_ diff --git a/test/Common/standalone/GlobalOffsetTablePIE/Inputs/1.c b/test/Common/standalone/GlobalOffsetTablePIE/Inputs/1.c new file mode 100644 index 000000000..2e0376d80 --- /dev/null +++ b/test/Common/standalone/GlobalOffsetTablePIE/Inputs/1.c @@ -0,0 +1,4 @@ +extern int _GLOBAL_OFFSET_TABLE_; +int foo() { return 1; } +int bar() { return 3; } +int *u = &_GLOBAL_OFFSET_TABLE_; diff --git a/test/Common/standalone/GlobalOffsetTablePIE/Inputs/1_aarch64.c b/test/Common/standalone/GlobalOffsetTablePIE/Inputs/1_aarch64.c new file mode 100644 index 000000000..5e35665c2 --- /dev/null +++ b/test/Common/standalone/GlobalOffsetTablePIE/Inputs/1_aarch64.c @@ -0,0 +1,3 @@ +int val = 10; +__attribute__((section(".text.foo"))) int foo() { return val; } +__attribute__((section(".text.bar"))) int bar() { return foo(); } diff --git a/test/Common/standalone/GlobalOffsetTablePIE/Inputs/1_arm.c b/test/Common/standalone/GlobalOffsetTablePIE/Inputs/1_arm.c new file mode 100644 index 000000000..1510c38e8 --- /dev/null +++ b/test/Common/standalone/GlobalOffsetTablePIE/Inputs/1_arm.c @@ -0,0 +1,6 @@ +__attribute__((constructor)) int cfoo() { return 0; } +__attribute__((destructor)) int dbar() { return 0; } +int val = 10; +// Access val from GOT - triggers .got.plt creation on ARM +__attribute__((section(".text.foo"))) int foo() { return val; } +__attribute__((section(".text.bar"))) int bar() { return foo(); } diff --git a/test/Common/standalone/GlobalOffsetTablePIE/Inputs/1_hexagon.c b/test/Common/standalone/GlobalOffsetTablePIE/Inputs/1_hexagon.c new file mode 100644 index 000000000..d21823e7d --- /dev/null +++ b/test/Common/standalone/GlobalOffsetTablePIE/Inputs/1_hexagon.c @@ -0,0 +1,5 @@ +__attribute__((constructor)) int cfoo() { return 0; } +__attribute__((destructor)) int dbar() { return 0; } +int val = 10; +__attribute__((section(".text.foo"))) int foo() { return val; } +__attribute__((section(".text.bar"))) int bar() { return foo(); } diff --git a/test/Common/standalone/GlobalOffsetTableShared/GlobalOffsetTableShared_ARM.test b/test/Common/standalone/GlobalOffsetTableShared/GlobalOffsetTableShared_ARM.test new file mode 100644 index 000000000..3db5a6745 --- /dev/null +++ b/test/Common/standalone/GlobalOffsetTableShared/GlobalOffsetTableShared_ARM.test @@ -0,0 +1,13 @@ +#---GlobalOffsetTableShared_ARM.test----------- Shared Library ---------------# +# REQUIRES: arm +#BEGIN_COMMENT +# Verify that _GLOBAL_OFFSET_TABLE_ is emitted with a valid address +# pointing to .got.plt when building a shared library for ARM. +#END_COMMENT +#START_TEST +RUN: %clang %clangopts -c %p/Inputs/1_arm.c -o %t1.o -fPIC -ffunction-sections +RUN: %link %linkopts %t1.o -o %t1.so -shared 2>&1 +RUN: %readelf -S -W -s %t1.so 2>&1 | %filecheck %s +#END_TEST +CHECK: .got.plt PROGBITS [[ADDR:[xa-f0-9]+]] +CHECK: {{.*}} [[ADDR]] {{.*}} _GLOBAL_OFFSET_TABLE_ diff --git a/test/Common/standalone/GlobalOffsetTableShared/GlobalOffsetTableShared_Hexagon.test b/test/Common/standalone/GlobalOffsetTableShared/GlobalOffsetTableShared_Hexagon.test new file mode 100644 index 000000000..b03a8038a --- /dev/null +++ b/test/Common/standalone/GlobalOffsetTableShared/GlobalOffsetTableShared_Hexagon.test @@ -0,0 +1,13 @@ +#---GlobalOffsetTableShared_Hexagon.test----------- Shared Library ---------------# +# REQUIRES: hexagon +#BEGIN_COMMENT +# Verify that _GLOBAL_OFFSET_TABLE_ is emitted with a valid address +# pointing to .got.plt when building a shared library for Hexagon. +#END_COMMENT +#START_TEST +RUN: %clang %clangopts -c %p/Inputs/1_hexagon.c -o %t1.o -fPIC -ffunction-sections +RUN: %link %linkopts %t1.o -o %t1.so -shared 2>&1 +RUN: %readelf -S -W -s %t1.so 2>&1 | %filecheck %s +#END_TEST +CHECK: .got.plt PROGBITS [[ADDR:[xa-f0-9]+]] +CHECK: {{.*}} [[ADDR]] {{.*}} _GLOBAL_OFFSET_TABLE_ diff --git a/test/Common/standalone/GlobalOffsetTableShared/GlobalOffsetTableShared_RISCV.test b/test/Common/standalone/GlobalOffsetTableShared/GlobalOffsetTableShared_RISCV.test new file mode 100644 index 000000000..814cdae04 --- /dev/null +++ b/test/Common/standalone/GlobalOffsetTableShared/GlobalOffsetTableShared_RISCV.test @@ -0,0 +1,13 @@ +#---GlobalOffsetTableShared_RISCV.test----------- Shared Library ---------------# +# REQUIRES: riscv +#BEGIN_COMMENT +# Verify that _GLOBAL_OFFSET_TABLE_ is emitted with a valid address +# pointing to .got when building a shared library for RISCV. +#END_COMMENT +#START_TEST +RUN: %clang %clangopts -c %p/Inputs/1.c -o %t1.o -fPIC -ffunction-sections +RUN: %link %linkopts %t1.o -o %t1.so -shared 2>&1 +RUN: %readelf -S -W -s %t1.so 2>&1 | %filecheck %s +#END_TEST +CHECK: .got PROGBITS [[ADDR:[xa-f0-9]+]] +CHECK: {{.*}} [[ADDR]] {{.*}} _GLOBAL_OFFSET_TABLE_ diff --git a/test/Common/standalone/GlobalOffsetTableShared/GlobalOffsetTableShared_X86.test b/test/Common/standalone/GlobalOffsetTableShared/GlobalOffsetTableShared_X86.test new file mode 100644 index 000000000..46cdee402 --- /dev/null +++ b/test/Common/standalone/GlobalOffsetTableShared/GlobalOffsetTableShared_X86.test @@ -0,0 +1,14 @@ +#---GlobalOffsetTableShared.test----------- Shared Library ---------------# +# REQUIRES: x86 +#BEGIN_COMMENT +# Verify that _GLOBAL_OFFSET_TABLE_ is emitted with a valid address +# pointing to .got.plt when building a shared library with no PLT +# relocations. ELD was incorrectly emitting value 0x0 in this case. +#END_COMMENT +#START_TEST +RUN: %clang %clangopts -c %p/Inputs/1.c -o %t1.o -fPIC -ffunction-sections +RUN: %link %linkopts %t1.o -o %t1.so -shared 2>&1 +RUN: %readelf -S -W -s %t1.so 2>&1 | %filecheck %s +#END_TEST +CHECK: .got.plt PROGBITS [[ADDR:[xa-f0-9]+]] +CHECK: {{.*}} [[ADDR]] {{.*}} _GLOBAL_OFFSET_TABLE_ diff --git a/test/Common/standalone/GlobalOffsetTableShared/Inputs/1.c b/test/Common/standalone/GlobalOffsetTableShared/Inputs/1.c new file mode 100644 index 000000000..2e0376d80 --- /dev/null +++ b/test/Common/standalone/GlobalOffsetTableShared/Inputs/1.c @@ -0,0 +1,4 @@ +extern int _GLOBAL_OFFSET_TABLE_; +int foo() { return 1; } +int bar() { return 3; } +int *u = &_GLOBAL_OFFSET_TABLE_; diff --git a/test/Common/standalone/GlobalOffsetTableShared/Inputs/1_aarch64.c b/test/Common/standalone/GlobalOffsetTableShared/Inputs/1_aarch64.c new file mode 100644 index 000000000..5e35665c2 --- /dev/null +++ b/test/Common/standalone/GlobalOffsetTableShared/Inputs/1_aarch64.c @@ -0,0 +1,3 @@ +int val = 10; +__attribute__((section(".text.foo"))) int foo() { return val; } +__attribute__((section(".text.bar"))) int bar() { return foo(); } diff --git a/test/Common/standalone/GlobalOffsetTableShared/Inputs/1_arm.c b/test/Common/standalone/GlobalOffsetTableShared/Inputs/1_arm.c new file mode 100644 index 000000000..1510c38e8 --- /dev/null +++ b/test/Common/standalone/GlobalOffsetTableShared/Inputs/1_arm.c @@ -0,0 +1,6 @@ +__attribute__((constructor)) int cfoo() { return 0; } +__attribute__((destructor)) int dbar() { return 0; } +int val = 10; +// Access val from GOT - triggers .got.plt creation on ARM +__attribute__((section(".text.foo"))) int foo() { return val; } +__attribute__((section(".text.bar"))) int bar() { return foo(); } diff --git a/test/Common/standalone/GlobalOffsetTableShared/Inputs/1_hexagon.c b/test/Common/standalone/GlobalOffsetTableShared/Inputs/1_hexagon.c new file mode 100644 index 000000000..d21823e7d --- /dev/null +++ b/test/Common/standalone/GlobalOffsetTableShared/Inputs/1_hexagon.c @@ -0,0 +1,5 @@ +__attribute__((constructor)) int cfoo() { return 0; } +__attribute__((destructor)) int dbar() { return 0; } +int val = 10; +__attribute__((section(".text.foo"))) int foo() { return val; } +__attribute__((section(".text.bar"))) int bar() { return foo(); } diff --git a/test/RISCV/standalone/GlobalOffsetTable/GlobalOffsetTable.test b/test/RISCV/standalone/GlobalOffsetTable/GlobalOffsetTable.test deleted file mode 100644 index c9b0aad9c..000000000 --- a/test/RISCV/standalone/GlobalOffsetTable/GlobalOffsetTable.test +++ /dev/null @@ -1,13 +0,0 @@ -#----------GlobalOffsetTable.test--------------------- Executable ------# -#BEGIN_COMMENT -#Test the value of the variable _GLOBAL_OFFSET_TABLE_ and make sure it points -#to .got.plt -#END_COMMENT -#START_TEST -RUN: %clang %clangopts -c %p/Inputs/1.c -o %t1.1.o -fPIC -RUN: %link %linkopts %t1.1.o -o %t1.out 2>&1 -RUN: %readelf -S -W -s %t1.out 2>&1 | %filecheck %s -#END_Test - -CHECK: .got PROGBITS [[ADDR:[xa-f0-9]+]] -CHECK: {{.*}} [[ADDR]] {{.*}} _GLOBAL_OFFSET_TABLE_ diff --git a/test/RISCV/standalone/GlobalOffsetTable/Inputs/1.c b/test/RISCV/standalone/GlobalOffsetTable/Inputs/1.c deleted file mode 100644 index 0eeeb7e49..000000000 --- a/test/RISCV/standalone/GlobalOffsetTable/Inputs/1.c +++ /dev/null @@ -1,3 +0,0 @@ -int b = 10; -int c = 20; -int foo() { return b + c; } diff --git a/test/lit.cfg b/test/lit.cfg index 6ec513b79..13e36dd5c 100644 --- a/test/lit.cfg +++ b/test/lit.cfg @@ -313,6 +313,7 @@ if config.test_target == 'Hexagon': if ('hexagon-unknown-linux' in config.available_features or 'hexagon-standalone-env' in config.available_features): config.available_features.add('hexagon') + got_section = '.got.plt' if config.test_target == 'X86': if not config.target_triple: @@ -332,6 +333,7 @@ if config.test_target == 'X86': if hasattr(config,'eld_option') and config.eld_option != 'default': linkopts = '--thread-count 4 ' + config.eld_option config.available_features.add('x86') + got_section = '.got.plt' if config.test_target == 'ARM': if not config.target_triple: @@ -350,6 +352,7 @@ if config.test_target == 'ARM': if ('arm-windows' in config.available_features or 'arm-linux' in config.available_features): config.available_features.add('arm') + got_section = '.got.plt' link = 'ld.eld' linkopts = '--thread-count 4 --threads' if hasattr(config,'eld_option') and config.eld_option != 'default': @@ -382,6 +385,7 @@ if config.test_target == 'AArch64': if ('aarch64-windows' in config.available_features or 'aarch64-linux' in config.available_features): config.available_features.add('aarch64') + got_section = '.got' xlen = 8 config.emulation = '-m aarch64elf' link = 'ld.eld -m aarch64elf -mtriple aarch64-unknown-none-elf' @@ -412,6 +416,7 @@ if config.test_target == 'RISCV64': config.march = '-march=riscv64' datalayout = 'e-m:e-p:64:64-i64:64-i128:128-n32:64-S128' config.available_features.add('riscv64') + got_section = '.got' xlen = 8 clang = 'clang -target riscv64' clangxx = 'clang++ -target riscv64' @@ -442,6 +447,7 @@ if config.test_target == 'RISCV': config.march = '-march=riscv32' datalayout = 'e-m:e-p:32:32-i64:64-n32-S128' config.available_features.add('riscv32') + got_section = '.got' clang = 'clang -target riscv32' clangxx = 'clang++ -target riscv32' link = 'ld.eld' @@ -707,6 +713,7 @@ config.substitutions.append( ("%emulation","".join(config.emulation)) ) config.substitutions.append( ("%run_cc", run_cc) ) config.substitutions.append( ("%run_cxx", run_cxx) ) config.substitutions.append( ("%sysroot", sysroot) ) +config.substitutions.append( ("%GlobalOffsetTableSection", got_section) ) config.substitutions.append( ("%run","".join(run)) ) if muslclang is not None: config.substitutions.append( ("%musl-clang","".join(muslclang)) )