Index: lib/ReaderWriter/ELF/File.h =================================================================== --- lib/ReaderWriter/ELF/File.h +++ lib/ReaderWriter/ELF/File.h @@ -274,17 +274,6 @@ const Elf_Shdr *section = _objFile->getElfSection(sit); const Elf_Sym *symbol = _objFile->getElfSymbol(it); - // If its a merge section, the atoms have already - // been created, lets not create the atoms again - if (doStringsMerge) { - int64_t sectionFlags = section->sh_flags; - sectionFlags &= ~llvm::ELF::SHF_ALLOC; - if ((section->sh_entsize < 2) && - (sectionFlags == (llvm::ELF::SHF_MERGE | llvm::ELF::SHF_STRINGS))) { - continue; - } - } - StringRef symbolName; if ((EC = _objFile->getSymbolName(section, symbol, symbolName))) return; @@ -364,6 +353,8 @@ if ((EC = _objFile->getSymbolName(i.first, *si, symbolName))) return; + const Elf_Shdr *section = _objFile->getSection(*si); + bool isCommon = (*si)->getType() == llvm::ELF::STT_COMMON || (*si)->st_shndx == llvm::ELF::SHN_COMMON; @@ -423,6 +414,23 @@ previous_atom->addReference(followOn); } + // If the linker finds that a section has global atoms that are in a + // mergeable section, treat them as defined atoms + int64_t sectionFlags = 0; + if (section) + sectionFlags = section->sh_flags; + sectionFlags &= ~llvm::ELF::SHF_ALLOC; + if (doStringsMerge && section && (section->sh_entsize < 2) && + (sectionFlags == (llvm::ELF::SHF_MERGE | llvm::ELF::SHF_STRINGS))) { + if ((*si)->getBinding() == llvm::ELF::STB_GLOBAL) { + auto definedMergeAtom = new (_readerStorage) ELFDefinedAtom( + *this, symbolName, sectionName, (*si), section, symbolData, + _references.size(), _references.size(), _references); + _definedAtoms._atoms.push_back(definedMergeAtom); + } + continue; + } + auto newAtom = createDefinedAtomAndAssignRelocations( symbolName, sectionName, *si, i.first, symbolData); @@ -468,11 +476,14 @@ // refer to the MergeAtom to allow deduping if (doStringsMerge && shdr && (shdr->sh_entsize < 2) && (sectionFlags == (llvm::ELF::SHF_MERGE | llvm::ELF::SHF_STRINGS))) { - const MergeSectionKey ms(shdr, ri->addend()); + const TargetRelocationHandler &relHandler = _elfTargetInfo + .template getTargetHandler().getRelocationHandler(); + int64_t fixAddend = relHandler.fixupAddend(*ri); + uint64_t addend = ri->addend() + fixAddend; + const MergeSectionKey ms(shdr, addend); if (_mergedSectionMap.find(ms) == _mergedSectionMap.end()) { - uint64_t addend = ri->addend(); if (Symbol->getType() != llvm::ELF::STT_SECTION) - addend = Symbol->st_value + ri->addend(); + addend = Symbol->st_value + addend; MergeAtomsIter mai = findMergeAtom(shdr, addend); if (mai != _mergeAtoms.end()) { ri->setOffset(addend - ((*mai)->offset())); Index: lib/ReaderWriter/ELF/TargetHandler.h =================================================================== --- lib/ReaderWriter/ELF/TargetHandler.h +++ lib/ReaderWriter/ELF/TargetHandler.h @@ -33,6 +33,7 @@ namespace lld { namespace elf { template class ELFDefinedAtom; +template class ELFReference; class ELFWriter; template class Header; template class Section; @@ -54,17 +55,20 @@ return DefinedAtom::typeZeroFill; } - virtual DefinedAtom::ContentPermissions contentPermissions( - const ELFDefinedAtom *atom) const { + virtual DefinedAtom::ContentPermissions + contentPermissions(const ELFDefinedAtom *atom) const { return atom->permissions(); } + }; template class TargetRelocationHandler { public: - virtual ErrorOr applyRelocation(ELFWriter &, llvm::FileOutputBuffer &, - const AtomLayout &, - const Reference &)const = 0; + virtual ErrorOr + applyRelocation(ELFWriter &, llvm::FileOutputBuffer &, const AtomLayout &, + const Reference &)const = 0; + + virtual int64_t fixupAddend(const Reference &)const { return 0; } }; /// \brief An interface to override functions that are provided by the Index: lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.h =================================================================== --- lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.h +++ lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.h @@ -26,9 +26,11 @@ X86_64TargetRelocationHandler(const X86_64TargetInfo &ti) : _tlsSize(0), _targetInfo(ti) {} - virtual ErrorOr applyRelocation(ELFWriter &, llvm::FileOutputBuffer &, - const AtomLayout &, - const Reference &)const; + virtual ErrorOr + applyRelocation(ELFWriter &, llvm::FileOutputBuffer &, const AtomLayout &, + const Reference &)const; + + virtual int64_t fixupAddend(const Reference &)const; private: // Cached size of the TLS segment. Index: lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.cpp =================================================================== --- lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.cpp +++ lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.cpp @@ -52,6 +52,16 @@ } } // end anon namespace +int64_t X86_64TargetRelocationHandler::fixupAddend(const Reference &ref) const { + switch (ref.kind()) { + case R_X86_64_PC32: + return 4; + default: + return 0; + } + return 0; +} + ErrorOr X86_64TargetRelocationHandler::applyRelocation( ELFWriter &writer, llvm::FileOutputBuffer &buf, const AtomLayout &atom, const Reference &ref) const { Index: test/elf/Inputs/globalconst.c =================================================================== --- test/elf/Inputs/globalconst.c +++ test/elf/Inputs/globalconst.c @@ -0,0 +1,2 @@ +/* compile the code with -fmerge-all-constants */ +const char mystr[] = "foobar"; Index: test/elf/mergeglobalatoms.objtxt =================================================================== --- test/elf/mergeglobalatoms.objtxt +++ test/elf/mergeglobalatoms.objtxt @@ -0,0 +1,10 @@ +# ELF files can have mergeable strings which are global!, treat them as global +# defined atoms +RUN: lld-core -merge-strings=true -reader ELF %p/Inputs/globalconst.o.x86-64 | FileCheck -check-prefix=globalatoms %s + +globalatoms: - name: mystr +globalatoms: scope: global +globalatoms: type: constant +globalatoms: content: [ 66, 6F, 6F, 62, 61, 72, 00 ] +globalatoms: section-choice: custom-required +globalatoms: section-name: .rodata.str1.1