From bbef90e7dbd431993d3f5d8e2045dc348bc7ae3a Mon Sep 17 00:00:00 2001 From: Jay Foad Date: Wed, 29 Nov 2023 14:19:51 +0000 Subject: [PATCH] Add support for SHT_RELA in LGC ElfLinker (#2856) Currently LLVM generates relocations in an ELF SHT_REL section. To allow for changing the compiler to use SHT_RELA instead, this patch updates ElfLinker to support both section types. --- lgc/elfLinker/ElfLinker.cpp | 49 +++++++++++++++++++++++++++++-------- 1 file changed, 39 insertions(+), 10 deletions(-) diff --git a/lgc/elfLinker/ElfLinker.cpp b/lgc/elfLinker/ElfLinker.cpp index 952eed3954..efb6f34b76 100644 --- a/lgc/elfLinker/ElfLinker.cpp +++ b/lgc/elfLinker/ElfLinker.cpp @@ -94,7 +94,7 @@ class OutputSection { // Add a relocation to the output elf void addRelocation(object::ELFRelocationRef relocRef, StringRef id, unsigned int relocSectionOffset, - unsigned int targetSectionOffset); + unsigned int targetSectionOffset, unsigned sectType); // Get the output file offset of a particular input section in the output section uint64_t getOutputOffset(unsigned inputIdx) { return m_offset + m_inputSections[inputIdx].offset; } @@ -180,6 +180,7 @@ class ElfLinkerImpl final : public ElfLinker { StringRef getStrings() { return m_strings; } SmallVectorImpl &getSymbols() { return m_symbols; } SmallVectorImpl &getRelocations() { return m_relocations; } + SmallVectorImpl &getRelocationsA() { return m_relocationsA; } void setStringTableIndex(unsigned index) { m_ehdr.e_shstrndx = index; } StringRef getNotes() { return m_notes; } @@ -229,6 +230,7 @@ class ElfLinkerImpl final : public ElfLinker { SmallVector m_outputSections; // Output sections SmallVector m_symbols; // Symbol table SmallVector m_relocations; // Relocations + SmallVector m_relocationsA; // Relocations with explicit addend StringMap m_symbolMap; // Map from name to symbol index std::string m_strings; // Strings for string table StringMap m_stringMap; // Map from string to string table index @@ -447,16 +449,22 @@ bool ElfLinkerImpl::link(raw_pwrite_stream &outStream) { // The creation of the relocation section is delayed below so we can create it only if there is at least one // relocation. bool relSectionCreated = false; + bool relaSectionCreated = false; // Allocate input sections to output sections. for (auto &elfInput : m_elfInputs) { for (const object::SectionRef §ion : elfInput.objectFile->sections()) { unsigned sectType = object::ELFSectionRef(section).getType(); - if (sectType == ELF::SHT_REL || sectType == ELF::SHT_RELA) { - if (!relSectionCreated && section.relocation_begin() != section.relocation_end()) { + if (sectType == ELF::SHT_REL) { + if (!relSectionCreated && !section.relocations().empty()) { m_outputSections.push_back(OutputSection(this, ".rel.text", ELF::SHT_REL)); relSectionCreated = true; } + } else if (sectType == ELF::SHT_RELA) { + if (!relaSectionCreated && !section.relocations().empty()) { + m_outputSections.push_back(OutputSection(this, ".rela.text", ELF::SHT_RELA)); + relaSectionCreated = true; + } } else if (sectType == ELF::SHT_PROGBITS) { // Put same-named sections together (excluding symbol table, string table, reloc sections). StringRef name = cantFail(section.getName()); @@ -547,7 +555,6 @@ bool ElfLinkerImpl::link(raw_pwrite_stream &outStream) { if (targetSectionIdx != UINT_MAX) { (void)(textSectionIdx); assert(targetSectionIdx == textSectionIdx && "We assume all relocations are applied to the text section"); - assert(sectType == ELF::SHT_REL && "We do not output a RELA section yet"); object::SectionRef relocSection = *cantFail(reloc.getSymbol()->getSection()); unsigned relocSectionId = UINT_MAX; unsigned relocIdxInSection = UINT_MAX; @@ -555,7 +562,8 @@ bool ElfLinkerImpl::link(raw_pwrite_stream &outStream) { uint64_t relocSectionOffset = m_outputSections[relocSectionId].getOutputOffset(relocIdxInSection); uint64_t targetSectionOffset = m_outputSections[targetSectionIdx].getOutputOffset(targetIdxInSection); StringRef id = sys::path::filename(elfInput.objectFile->getFileName()); - m_outputSections[relocSectionId].addRelocation(reloc, id, relocSectionOffset, targetSectionOffset); + m_outputSections[relocSectionId].addRelocation(reloc, id, relocSectionOffset, targetSectionOffset, + sectType); } } } @@ -965,8 +973,7 @@ void OutputSection::addSymbol(const object::ELFSymbolRef &elfSymRef, unsigned in // Add a relocation to the output elf void OutputSection::addRelocation(object::ELFRelocationRef relocRef, StringRef id, unsigned int relocSectionOffset, - unsigned int targetSectionOffset) { - ELF::Elf64_Rel newReloc = {}; + unsigned int targetSectionOffset, unsigned sectType) { object::ELFSymbolRef relocSymRef(*relocRef.getSymbol()); std::string rodataSymName = cantFail(relocSymRef.getName()).str(); rodataSymName += "."; @@ -984,9 +991,19 @@ void OutputSection::addRelocation(object::ELFRelocationRef relocRef, StringRef i rodataSymIdx = m_linker->getSymbols().size(); m_linker->getSymbols().push_back(newSym); } - newReloc.setSymbolAndType(rodataSymIdx, relocRef.getType()); - newReloc.r_offset = targetSectionOffset + relocRef.getOffset(); - m_linker->getRelocations().push_back(newReloc); + if (sectType == ELF::SHT_REL) { + ELF::Elf64_Rel newReloc = {}; + newReloc.setSymbolAndType(rodataSymIdx, relocRef.getType()); + newReloc.r_offset = targetSectionOffset + relocRef.getOffset(); + m_linker->getRelocations().push_back(newReloc); + } else { + assert(sectType == ELF::SHT_RELA); + ELF::Elf64_Rela newReloc = {}; + newReloc.setSymbolAndType(rodataSymIdx, relocRef.getType()); + newReloc.r_offset = targetSectionOffset + relocRef.getOffset(); + newReloc.r_addend = cantFail(relocRef.getAddend()); + m_linker->getRelocationsA().push_back(newReloc); + } } // ===================================================================================================================== @@ -1037,6 +1054,18 @@ void OutputSection::write(raw_pwrite_stream &outStream, ELF::Elf64_Shdr *shdr) { return; } + if (m_type == ELF::SHT_RELA) { + ArrayRef relocations = m_linker->getRelocationsA(); + shdr->sh_type = m_type; + shdr->sh_size = relocations.size() * sizeof(ELF::Elf64_Rela); + shdr->sh_entsize = sizeof(ELF::Elf64_Rela); + shdr->sh_link = 2; // Section index of symbol table + shdr->sh_info = 3; // Section index of the .text section + outStream << StringRef(reinterpret_cast(relocations.data()), + relocations.size() * sizeof(ELF::Elf64_Rela)); + return; + } + if (m_inputSections.empty()) return;