diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2017-07-01 13:24:45 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2017-07-01 13:24:45 +0000 |
commit | 0317860f00ca8e821989c92c8a6cc461fd5f2009 (patch) | |
tree | ba31f275eb4dfa527c0cd564ba6c5016e2318b16 /ELF | |
parent | 4ea16835ba66f2240d050ffcaee44cee6c97cab9 (diff) | |
download | src-0317860f00ca8e821989c92c8a6cc461fd5f2009.tar.gz src-0317860f00ca8e821989c92c8a6cc461fd5f2009.zip |
Vendor import of lld trunk r306956:vendor/lld/lld-trunk-r306956
Notes
Notes:
svn path=/vendor/lld/dist/; revision=320541
svn path=/vendor/lld/lld-trunk-r306956/; revision=320542; tag=vendor/lld/lld-trunk-r306956
Diffstat (limited to 'ELF')
-rw-r--r-- | ELF/Arch/SPARCV9.cpp | 149 | ||||
-rw-r--r-- | ELF/CMakeLists.txt | 1 | ||||
-rw-r--r-- | ELF/InputFiles.cpp | 6 | ||||
-rw-r--r-- | ELF/SymbolTable.cpp | 32 | ||||
-rw-r--r-- | ELF/SymbolTable.h | 2 | ||||
-rw-r--r-- | ELF/Symbols.cpp | 15 | ||||
-rw-r--r-- | ELF/Symbols.h | 2 | ||||
-rw-r--r-- | ELF/SyntheticSections.cpp | 29 | ||||
-rw-r--r-- | ELF/Target.cpp | 2 | ||||
-rw-r--r-- | ELF/Target.h | 1 | ||||
-rw-r--r-- | ELF/Writer.cpp | 8 |
11 files changed, 223 insertions, 24 deletions
diff --git a/ELF/Arch/SPARCV9.cpp b/ELF/Arch/SPARCV9.cpp new file mode 100644 index 000000000000..1f977c1e9cf2 --- /dev/null +++ b/ELF/Arch/SPARCV9.cpp @@ -0,0 +1,149 @@ +//===- SPARCV9.cpp --------------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Error.h" +#include "InputFiles.h" +#include "Symbols.h" +#include "SyntheticSections.h" +#include "Target.h" +#include "llvm/Support/Endian.h" + +using namespace llvm; +using namespace llvm::support::endian; +using namespace llvm::ELF; +using namespace lld; +using namespace lld::elf; + +namespace { +class SPARCV9 final : public TargetInfo { +public: + SPARCV9(); + RelExpr getRelExpr(uint32_t Type, const SymbolBody &S, + const uint8_t *Loc) const override; + void writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr, + int32_t Index, unsigned RelOff) const override; + void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; +}; +} // namespace + +SPARCV9::SPARCV9() { + CopyRel = R_SPARC_COPY; + GotRel = R_SPARC_GLOB_DAT; + PltRel = R_SPARC_JMP_SLOT; + RelativeRel = R_SPARC_RELATIVE; + GotEntrySize = 8; + PltEntrySize = 32; + PltHeaderSize = 4 * PltEntrySize; + + PageSize = 8192; + DefaultMaxPageSize = 0x100000; + DefaultImageBase = 0x100000; +} + +RelExpr SPARCV9::getRelExpr(uint32_t Type, const SymbolBody &S, + const uint8_t *Loc) const { + switch (Type) { + case R_SPARC_32: + case R_SPARC_UA32: + case R_SPARC_64: + case R_SPARC_UA64: + return R_ABS; + case R_SPARC_PC10: + case R_SPARC_PC22: + case R_SPARC_DISP32: + case R_SPARC_WDISP30: + return R_PC; + case R_SPARC_GOT10: + return R_GOT_OFF; + case R_SPARC_GOT22: + return R_GOT_OFF; + case R_SPARC_WPLT30: + return R_PLT_PC; + case R_SPARC_NONE: + return R_NONE; + default: + error(toString(S.File) + ": unknown relocation type: " + toString(Type)); + return R_HINT; + } +} + +void SPARCV9::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const { + switch (Type) { + case R_SPARC_32: + case R_SPARC_UA32: + // V-word32 + checkUInt<32>(Loc, Val, Type); + write32be(Loc, Val); + break; + case R_SPARC_DISP32: + // V-disp32 + checkInt<32>(Loc, Val, Type); + write32be(Loc, Val); + break; + case R_SPARC_WDISP30: + case R_SPARC_WPLT30: + // V-disp30 + checkInt<32>(Loc, Val, Type); + write32be(Loc, (read32be(Loc) & ~0x3fffffff) | ((Val >> 2) & 0x3fffffff)); + break; + case R_SPARC_22: + // V-imm22 + checkUInt<22>(Loc, Val, Type); + write32be(Loc, (read32be(Loc) & ~0x003fffff) | (Val & 0x003fffff)); + break; + case R_SPARC_GOT22: + case R_SPARC_PC22: + // T-imm22 + write32be(Loc, (read32be(Loc) & ~0x003fffff) | ((Val >> 10) & 0x003fffff)); + break; + case R_SPARC_WDISP19: + // V-disp19 + checkInt<21>(Loc, Val, Type); + write32be(Loc, (read32be(Loc) & ~0x0007ffff) | ((Val >> 2) & 0x0007ffff)); + break; + case R_SPARC_GOT10: + case R_SPARC_PC10: + // T-simm10 + write32be(Loc, (read32be(Loc) & ~0x000003ff) | (Val & 0x000003ff)); + break; + case R_SPARC_64: + case R_SPARC_UA64: + case R_SPARC_GLOB_DAT: + // V-xword64 + write64be(Loc, Val); + break; + default: + error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type)); + } +} + +void SPARCV9::writePlt(uint8_t *Buf, uint64_t GotEntryAddr, + uint64_t PltEntryAddr, int32_t Index, + unsigned RelOff) const { + const uint8_t PltData[] = { + 0x03, 0x00, 0x00, 0x00, // sethi (. - .PLT0), %g1 + 0x30, 0x68, 0x00, 0x00, // ba,a %xcc, .PLT1 + 0x01, 0x00, 0x00, 0x00, // nop + 0x01, 0x00, 0x00, 0x00, // nop + 0x01, 0x00, 0x00, 0x00, // nop + 0x01, 0x00, 0x00, 0x00, // nop + 0x01, 0x00, 0x00, 0x00, // nop + 0x01, 0x00, 0x00, 0x00 // nop + }; + memcpy(Buf, PltData, sizeof(PltData)); + + uint64_t Off = PltHeaderSize + Index * PltEntrySize; + relocateOne(Buf, R_SPARC_22, Off); + relocateOne(Buf + 4, R_SPARC_WDISP19, -(Off + 4 - PltEntrySize)); +} + +TargetInfo *elf::getSPARCV9TargetInfo() { + static SPARCV9 Target; + return &Target; +} diff --git a/ELF/CMakeLists.txt b/ELF/CMakeLists.txt index b4bc215a77eb..77243bd494d1 100644 --- a/ELF/CMakeLists.txt +++ b/ELF/CMakeLists.txt @@ -15,6 +15,7 @@ add_lld_library(lldELF Arch/MipsArchTree.cpp Arch/PPC.cpp Arch/PPC64.cpp + Arch/SPARCV9.cpp Arch/X86.cpp Arch/X86_64.cpp Driver.cpp diff --git a/ELF/InputFiles.cpp b/ELF/InputFiles.cpp index 1ff0b4224e70..e07f24d665df 100644 --- a/ELF/InputFiles.cpp +++ b/ELF/InputFiles.cpp @@ -79,9 +79,9 @@ template <class ELFT> void elf::ObjectFile<ELFT>::initializeDwarfLine() { ObjectInfo ObjInfo; DWARFContextInMemory Dwarf(*Obj, &ObjInfo); - DwarfLine.reset(new DWARFDebugLine(&Dwarf.getLineSection().Relocs)); - DataExtractor LineData(Dwarf.getLineSection().Data, Config->IsLE, - Config->Wordsize); + DwarfLine.reset(new DWARFDebugLine); + DWARFDataExtractor LineData(Dwarf.getLineSection(), Config->IsLE, + Config->Wordsize); // The second parameter is offset in .debug_line section // for compilation unit (CU) of interest. We have only one diff --git a/ELF/SymbolTable.cpp b/ELF/SymbolTable.cpp index ab8802c86d8e..d75b89f17527 100644 --- a/ELF/SymbolTable.cpp +++ b/ELF/SymbolTable.cpp @@ -195,14 +195,8 @@ template <class ELFT> void SymbolTable<ELFT>::applySymbolRenames() { for (auto &KV : Config->RenamedSymbols) { Symbol *Dst = KV.first; Symbol *Src = KV.second.Target; + Dst->body()->copy(Src->body()); Dst->Binding = KV.second.OriginalBinding; - - // We rename symbols by replacing the old symbol's SymbolBody with - // the new symbol's SymbolBody. The only attribute we want to keep - // is the symbol name, so that two symbols don't have the same name. - StringRef S = Dst->body()->getName(); - memcpy(Dst->Body.buffer, Src->Body.buffer, sizeof(Symbol::Body)); - Dst->body()->setName(S); } } @@ -718,15 +712,31 @@ void SymbolTable<ELFT>::assignWildcardVersion(SymbolVersion Ver, B->symbol()->VersionId = VersionId; } +static bool isDefaultVersion(SymbolBody *B) { + return B->isInCurrentDSO() && B->getName().find("@@") != StringRef::npos; +} + // This function processes version scripts by updating VersionId // member of symbols. template <class ELFT> void SymbolTable<ELFT>::scanVersionScript() { // Symbol themselves might know their versions because symbols // can contain versions in the form of <name>@<version>. - // Let them parse their names. - if (!Config->VersionDefinitions.empty()) - for (Symbol *Sym : SymVector) - Sym->body()->parseSymbolVersion(); + // Let them parse and update their names to exclude version suffix. + for (Symbol *Sym : SymVector) { + SymbolBody *Body = Sym->body(); + bool IsDefault = isDefaultVersion(Body); + Body->parseSymbolVersion(); + + if (!IsDefault) + continue; + + // <name>@@<version> means the symbol is the default version. If that's the + // case, the symbol is not used only to resolve <name> of version <version> + // but also undefined unversioned symbols with name <name>. + SymbolBody *S = find(Body->getName()); + if (S && S->isUndefined()) + S->copy(Body); + } // Handle edge cases first. handleAnonymousVersion(); diff --git a/ELF/SymbolTable.h b/ELF/SymbolTable.h index 316d9c9bf373..4ba101fa5d50 100644 --- a/ELF/SymbolTable.h +++ b/ELF/SymbolTable.h @@ -18,7 +18,7 @@ namespace lld { namespace elf { -class Lazy; + struct Symbol; // SymbolTable is a bucket of all known symbols, including defined, diff --git a/ELF/Symbols.cpp b/ELF/Symbols.cpp index 5dce71a32c9c..e8cd662c69ac 100644 --- a/ELF/Symbols.cpp +++ b/ELF/Symbols.cpp @@ -159,6 +159,21 @@ bool SymbolBody::isPreemptible() const { return true; } +// Overwrites all attributes except symbol name with Other's so that +// this symbol becomes an alias to Other. This is useful for handling +// some options such as --wrap. +// +// The reason why we want to keep the symbol name is because, if we +// copy symbol names, we'll end up having symbol tables in resulting +// executables or DSOs containing two or more identical symbols, which +// is just inconvenient. +void SymbolBody::copy(SymbolBody *Other) { + StringRef S = Name; + memcpy(symbol()->Body.buffer, Other->symbol()->Body.buffer, + sizeof(Symbol::Body)); + Name = S; +} + uint64_t SymbolBody::getVA(int64_t Addend) const { uint64_t OutVA = getSymVA(*this, Addend); return OutVA + Addend; diff --git a/ELF/Symbols.h b/ELF/Symbols.h index 406fd8e0f57b..773e1ad9588a 100644 --- a/ELF/Symbols.h +++ b/ELF/Symbols.h @@ -69,9 +69,9 @@ public: bool isLocal() const { return IsLocal; } bool isPreemptible() const; StringRef getName() const { return Name; } - void setName(StringRef S) { Name = S; } uint8_t getVisibility() const { return StOther & 0x3; } void parseSymbolVersion(); + void copy(SymbolBody *Other); bool isInGot() const { return GotIndex != -1U; } bool isInPlt() const { return PltIndex != -1U; } diff --git a/ELF/SyntheticSections.cpp b/ELF/SyntheticSections.cpp index cb1494d427a0..995d05692ee2 100644 --- a/ELF/SyntheticSections.cpp +++ b/ELF/SyntheticSections.cpp @@ -1090,8 +1090,17 @@ template <class ELFT> void DynamicSection<ELFT>::finalizeContents() { if (In<ELFT>::RelaPlt->getParent()->Size > 0) { add({DT_JMPREL, In<ELFT>::RelaPlt}); add({DT_PLTRELSZ, In<ELFT>::RelaPlt->getParent()->Size}); - add({Config->EMachine == EM_MIPS ? DT_MIPS_PLTGOT : DT_PLTGOT, - InX::GotPlt}); + switch (Config->EMachine) { + case EM_MIPS: + add({DT_MIPS_PLTGOT, In<ELFT>::GotPlt}); + break; + case EM_SPARCV9: + add({DT_PLTGOT, In<ELFT>::Plt}); + break; + default: + add({DT_PLTGOT, In<ELFT>::GotPlt}); + break; + } add({DT_PLTREL, uint64_t(Config->IsRela ? DT_RELA : DT_REL)}); } @@ -1376,7 +1385,6 @@ template <class ELFT> void SymbolTableSection<ELFT>::writeTo(uint8_t *Buf) { } ESym->st_name = Ent.StrTabOffset; - ESym->st_size = Body->getSize<ELFT>(); // Set a section index. if (const OutputSection *OutSec = Body->getOutputSection()) @@ -1386,6 +1394,14 @@ template <class ELFT> void SymbolTableSection<ELFT>::writeTo(uint8_t *Buf) { else if (isa<DefinedCommon>(Body)) ESym->st_shndx = SHN_COMMON; + // Copy symbol size if it is a defined symbol. st_size is not significant + // for undefined symbols, so whether copying it or not is up to us if that's + // the case. We'll leave it as zero because by not setting a value, we can + // get the exact same outputs for two sets of input files that differ only + // in undefined symbol size in DSOs. + if (ESym->st_shndx != SHN_UNDEF) + ESym->st_size = Body->getSize<ELFT>(); + // st_value is usually an address of a symbol, but that has a // special meaining for uninstantiated common symbols (this can // occur if -r is given). @@ -1625,7 +1641,12 @@ template <class ELFT> void HashTableSection<ELFT>::writeTo(uint8_t *Buf) { PltSection::PltSection(size_t S) : SyntheticSection(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS, 16, ".plt"), - HeaderSize(S) {} + HeaderSize(S) { + // The PLT needs to be writable on SPARC as the dynamic linker will + // modify the instructions in the PLT entries. + if (Config->EMachine == EM_SPARCV9) + this->Flags |= SHF_WRITE; +} void PltSection::writeTo(uint8_t *Buf) { // At beginning of PLT but not the IPLT, we have code to call the dynamic diff --git a/ELF/Target.cpp b/ELF/Target.cpp index c1a85e165258..c886419971bc 100644 --- a/ELF/Target.cpp +++ b/ELF/Target.cpp @@ -77,6 +77,8 @@ TargetInfo *elf::getTarget() { return getPPCTargetInfo(); case EM_PPC64: return getPPC64TargetInfo(); + case EM_SPARCV9: + return getSPARCV9TargetInfo(); case EM_X86_64: if (Config->EKind == ELF32LEKind) return getX32TargetInfo(); diff --git a/ELF/Target.h b/ELF/Target.h index bf703fd0086a..5914d9bbb7ef 100644 --- a/ELF/Target.h +++ b/ELF/Target.h @@ -112,6 +112,7 @@ TargetInfo *getARMTargetInfo(); TargetInfo *getAVRTargetInfo(); TargetInfo *getPPC64TargetInfo(); TargetInfo *getPPCTargetInfo(); +TargetInfo *getSPARCV9TargetInfo(); TargetInfo *getX32TargetInfo(); TargetInfo *getX86TargetInfo(); TargetInfo *getX86_64TargetInfo(); diff --git a/ELF/Writer.cpp b/ELF/Writer.cpp index 4c12b18836bf..080d8e787301 100644 --- a/ELF/Writer.cpp +++ b/ELF/Writer.cpp @@ -104,7 +104,7 @@ StringRef elf::getOutputSectionName(StringRef Name) { for (StringRef V : {".text.", ".rodata.", ".data.rel.ro.", ".data.", ".bss.rel.ro.", ".bss.", ".init_array.", ".fini_array.", ".ctors.", ".dtors.", ".tbss.", - ".gcc_except_table.", ".tdata.", ".ARM.exidx."}) { + ".gcc_except_table.", ".tdata.", ".ARM.exidx.", ".ARM.extab."}) { StringRef Prefix = V.drop_back(); if (Name.startswith(V) || Name == Prefix) return Prefix; @@ -1014,14 +1014,14 @@ findOrphanPos(std::vector<BaseCommand *>::iterator B, } template <class ELFT> void Writer<ELFT>::sortSections() { + if (Script->Opt.HasSections) + Script->adjustSectionsBeforeSorting(); + // Don't sort if using -r. It is not necessary and we want to preserve the // relative order for SHF_LINK_ORDER sections. if (Config->Relocatable) return; - if (Script->Opt.HasSections) - Script->adjustSectionsBeforeSorting(); - for (BaseCommand *Base : Script->Opt.Commands) if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base)) if (OutputSection *Sec = Cmd->Sec) |