aboutsummaryrefslogtreecommitdiff
path: root/ELF
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2017-07-01 13:24:45 +0000
committerDimitry Andric <dim@FreeBSD.org>2017-07-01 13:24:45 +0000
commit0317860f00ca8e821989c92c8a6cc461fd5f2009 (patch)
treeba31f275eb4dfa527c0cd564ba6c5016e2318b16 /ELF
parent4ea16835ba66f2240d050ffcaee44cee6c97cab9 (diff)
downloadsrc-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.cpp149
-rw-r--r--ELF/CMakeLists.txt1
-rw-r--r--ELF/InputFiles.cpp6
-rw-r--r--ELF/SymbolTable.cpp32
-rw-r--r--ELF/SymbolTable.h2
-rw-r--r--ELF/Symbols.cpp15
-rw-r--r--ELF/Symbols.h2
-rw-r--r--ELF/SyntheticSections.cpp29
-rw-r--r--ELF/Target.cpp2
-rw-r--r--ELF/Target.h1
-rw-r--r--ELF/Writer.cpp8
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)