diff options
47 files changed, 1009 insertions, 475 deletions
| diff --git a/COFF/ICF.cpp b/COFF/ICF.cpp index 3b7cc424f0a2..da8ca360542a 100644 --- a/COFF/ICF.cpp +++ b/COFF/ICF.cpp @@ -56,7 +56,6 @@ private:    std::vector<SectionChunk *> Chunks;    int Cnt = 0; -  std::atomic<uint32_t> NextId = {1};    std::atomic<bool> Repeat = {false};  }; @@ -98,10 +97,10 @@ void ICF::segregate(size_t Begin, size_t End, bool Constant) {          });      size_t Mid = Bound - Chunks.begin(); -    // Split [Begin, End) into [Begin, Mid) and [Mid, End). -    uint32_t Id = NextId++; +    // Split [Begin, End) into [Begin, Mid) and [Mid, End). We use Mid as an +    // equivalence class ID because every group ends with a unique index.      for (size_t I = Begin; I < Mid; ++I) -      Chunks[I]->Class[(Cnt + 1) % 2] = Id; +      Chunks[I]->Class[(Cnt + 1) % 2] = Mid;      // If we created a group, we need to iterate the main loop again.      if (Mid != End) @@ -186,6 +185,7 @@ void ICF::forEachClass(std::function<void(size_t, size_t)> Fn) {    // call Fn sequentially.    if (Chunks.size() < 1024) {      forEachClassRange(0, Chunks.size(), Fn); +    ++Cnt;      return;    } @@ -193,9 +193,10 @@ void ICF::forEachClass(std::function<void(size_t, size_t)> Fn) {    size_t NumShards = 256;    size_t Step = Chunks.size() / NumShards;    for_each_n(parallel::par, size_t(0), NumShards, [&](size_t I) { -    forEachClassRange(I * Step, (I + 1) * Step, Fn); +    size_t End = (I == NumShards - 1) ? Chunks.size() : (I + 1) * Step; +    forEachClassRange(I * Step, End, Fn);    }); -  forEachClassRange(Step * NumShards, Chunks.size(), Fn); +  ++Cnt;  }  // Merge identical COMDAT sections. @@ -203,22 +204,20 @@ void ICF::forEachClass(std::function<void(size_t, size_t)> Fn) {  // contents and relocations are all the same.  void ICF::run(const std::vector<Chunk *> &Vec) {    // Collect only mergeable sections and group by hash value. +  uint32_t NextId = 1;    for (Chunk *C : Vec) { -    auto *SC = dyn_cast<SectionChunk>(C); -    if (!SC) -      continue; - -    if (isEligible(SC)) { -      // Set MSB to 1 to avoid collisions with non-hash classs. -      SC->Class[0] = getHash(SC) | (1 << 31); -      Chunks.push_back(SC); -    } else { -      SC->Class[0] = NextId++; +    if (auto *SC = dyn_cast<SectionChunk>(C)) { +      if (isEligible(SC)) +        Chunks.push_back(SC); +      else +        SC->Class[0] = NextId++;      }    } -  if (Chunks.empty()) -    return; +  // Initially, we use hash values to partition sections. +  for (SectionChunk *SC : Chunks) +    // Set MSB to 1 to avoid collisions with non-hash classs. +    SC->Class[0] = getHash(SC) | (1 << 31);    // From now on, sections in Chunks are ordered so that sections in    // the same group are consecutive in the vector. @@ -229,14 +228,12 @@ void ICF::run(const std::vector<Chunk *> &Vec) {    // Compare static contents and assign unique IDs for each static content.    forEachClass([&](size_t Begin, size_t End) { segregate(Begin, End, true); }); -  ++Cnt;    // Split groups by comparing relocations until convergence is obtained.    do {      Repeat = false;      forEachClass(          [&](size_t Begin, size_t End) { segregate(Begin, End, false); }); -    ++Cnt;    } while (Repeat);    log("ICF needed " + Twine(Cnt) + " iterations"); diff --git a/COFF/InputFiles.cpp b/COFF/InputFiles.cpp index 6e6465cd5d62..258d9fd74b4d 100644 --- a/COFF/InputFiles.cpp +++ b/COFF/InputFiles.cpp @@ -48,13 +48,11 @@ namespace coff {  /// alias to Target.  static void checkAndSetWeakAlias(SymbolTable *Symtab, InputFile *F,                                   SymbolBody *Source, SymbolBody *Target) { -  auto *U = dyn_cast<Undefined>(Source); -  if (!U) -    return; -  else if (!U->WeakAlias) +  if (auto *U = dyn_cast<Undefined>(Source)) { +    if (U->WeakAlias && U->WeakAlias != Target) +      Symtab->reportDuplicate(Source->symbol(), F);      U->WeakAlias = Target; -  else if (U->WeakAlias != Target) -    Symtab->reportDuplicate(Source->symbol(), F); +  }  }  ArchiveFile::ArchiveFile(MemoryBufferRef M) : InputFile(ArchiveKind, M) {} @@ -153,8 +151,10 @@ void ObjectFile::initializeSymbols() {    uint32_t NumSymbols = COFFObj->getNumberOfSymbols();    SymbolBodies.reserve(NumSymbols);    SparseSymbolBodies.resize(NumSymbols); +    SmallVector<std::pair<SymbolBody *, uint32_t>, 8> WeakAliases;    int32_t LastSectionNumber = 0; +    for (uint32_t I = 0; I < NumSymbols; ++I) {      // Get a COFFSymbolRef object.      ErrorOr<COFFSymbolRef> SymOrErr = COFFObj->getSymbol(I); @@ -185,9 +185,12 @@ void ObjectFile::initializeSymbols() {      I += Sym.getNumberOfAuxSymbols();      LastSectionNumber = Sym.getSectionNumber();    } -  for (auto WeakAlias : WeakAliases) -    checkAndSetWeakAlias(Symtab, this, WeakAlias.first, -                         SparseSymbolBodies[WeakAlias.second]); + +  for (auto &KV : WeakAliases) { +    SymbolBody *Sym = KV.first; +    uint32_t Idx = KV.second; +    checkAndSetWeakAlias(Symtab, this, Sym, SparseSymbolBodies[Idx]); +  }  }  SymbolBody *ObjectFile::createUndefined(COFFSymbolRef Sym) { diff --git a/COFF/InputFiles.h b/COFF/InputFiles.h index 9e32b3b9f9d6..9449f24ac241 100644 --- a/COFF/InputFiles.h +++ b/COFF/InputFiles.h @@ -10,6 +10,7 @@  #ifndef LLD_COFF_INPUT_FILES_H  #define LLD_COFF_INPUT_FILES_H +#include "Config.h"  #include "lld/Core/LLVM.h"  #include "llvm/ADT/ArrayRef.h"  #include "llvm/ADT/DenseSet.h" @@ -161,7 +162,9 @@ private:  // for details about the format.  class ImportFile : public InputFile {  public: -  explicit ImportFile(MemoryBufferRef M) : InputFile(ImportKind, M) {} +  explicit ImportFile(MemoryBufferRef M) +      : InputFile(ImportKind, M), Live(!Config->DoGC) {} +    static bool classof(const InputFile *F) { return F->kind() == ImportKind; }    DefinedImportData *ImpSym = nullptr; @@ -176,6 +179,14 @@ public:    StringRef ExternalName;    const coff_import_header *Hdr;    Chunk *Location = nullptr; + +  // We want to eliminate dllimported symbols if no one actually refers them. +  // This "Live" bit is used to keep track of which import library members +  // are actually in use. +  // +  // If the Live bit is turned off by MarkLive, Writer will ignore dllimported +  // symbols provided by this import library member. +  bool Live;  };  // Used for LTO. diff --git a/COFF/MarkLive.cpp b/COFF/MarkLive.cpp index 0156d238b672..25e5cc350673 100644 --- a/COFF/MarkLive.cpp +++ b/COFF/MarkLive.cpp @@ -37,19 +37,26 @@ void markLive(const std::vector<Chunk *> &Chunks) {      Worklist.push_back(C);    }; +  auto AddSym = [&](SymbolBody *B) { +    if (auto *Sym = dyn_cast<DefinedRegular>(B)) +      Enqueue(Sym->getChunk()); +    else if (auto *Sym = dyn_cast<DefinedImportData>(B)) +      Sym->File->Live = true; +    else if (auto *Sym = dyn_cast<DefinedImportThunk>(B)) +      Sym->WrappedSym->File->Live = true; +  }; +    // Add GC root chunks.    for (SymbolBody *B : Config->GCRoot) -    if (auto *D = dyn_cast<DefinedRegular>(B)) -      Enqueue(D->getChunk()); +    AddSym(B);    while (!Worklist.empty()) {      SectionChunk *SC = Worklist.pop_back_val();      assert(SC->isLive() && "We mark as live when pushing onto the worklist!");      // Mark all symbols listed in the relocation table for this section. -    for (SymbolBody *S : SC->symbols()) -      if (auto *D = dyn_cast<DefinedRegular>(S)) -        Enqueue(D->getChunk()); +    for (SymbolBody *B : SC->symbols()) +      AddSym(B);      // Mark associative sections if any.      for (SectionChunk *C : SC->children()) diff --git a/COFF/PDB.cpp b/COFF/PDB.cpp index 0266148cc6c9..a3b3ab7bbab0 100644 --- a/COFF/PDB.cpp +++ b/COFF/PDB.cpp @@ -99,6 +99,12 @@ static void addTypeInfo(pdb::TpiStreamBuilder &TpiBuilder,  static void mergeDebugT(SymbolTable *Symtab, pdb::PDBFileBuilder &Builder,                          codeview::TypeTableBuilder &TypeTable,                          codeview::TypeTableBuilder &IDTable) { +  // Follow type servers.  If the same type server is encountered more than +  // once for this instance of `PDBTypeServerHandler` (for example if many +  // object files reference the same TypeServer), the types from the +  // TypeServer will only be visited once. +  pdb::PDBTypeServerHandler Handler; +    // Visit all .debug$T sections to add them to Builder.    for (ObjectFile *File : Symtab->ObjectFiles) {      ArrayRef<uint8_t> Data = getDebugSection(File, ".debug$T"); @@ -109,16 +115,11 @@ static void mergeDebugT(SymbolTable *Symtab, pdb::PDBFileBuilder &Builder,      codeview::CVTypeArray Types;      BinaryStreamReader Reader(Stream);      SmallVector<TypeIndex, 128> SourceToDest; -    // Follow type servers.  If the same type server is encountered more than -    // once for this instance of `PDBTypeServerHandler` (for example if many -    // object files reference the same TypeServer), the types from the -    // TypeServer will only be visited once. -    pdb::PDBTypeServerHandler Handler;      Handler.addSearchPath(llvm::sys::path::parent_path(File->getName()));      if (auto EC = Reader.readArray(Types, Reader.getLength()))        fatal(EC, "Reader::readArray failed"); -    if (auto Err = codeview::mergeTypeStreams(IDTable, TypeTable, SourceToDest, -                                              &Handler, Types)) +    if (auto Err = codeview::mergeTypeAndIdRecords( +            IDTable, TypeTable, SourceToDest, &Handler, Types))        fatal(Err, "codeview::mergeTypeStreams failed");    } diff --git a/COFF/Symbols.cpp b/COFF/Symbols.cpp index 993e920ce7f7..5c185a511dd7 100644 --- a/COFF/Symbols.cpp +++ b/COFF/Symbols.cpp @@ -61,16 +61,19 @@ COFFSymbolRef DefinedCOFF::getCOFFSymbol() {    return COFFSymbolRef(reinterpret_cast<const coff_symbol32 *>(Sym));  } +static Chunk *makeImportThunk(DefinedImportData *S, uint16_t Machine) { +  if (Machine == AMD64) +    return make<ImportThunkChunkX64>(S); +  if (Machine == I386) +    return make<ImportThunkChunkX86>(S); +  assert(Machine == ARMNT); +  return make<ImportThunkChunkARM>(S); +} +  DefinedImportThunk::DefinedImportThunk(StringRef Name, DefinedImportData *S,                                         uint16_t Machine) -    : Defined(DefinedImportThunkKind, Name) { -  switch (Machine) { -  case AMD64: Data = make<ImportThunkChunkX64>(S); return; -  case I386:  Data = make<ImportThunkChunkX86>(S); return; -  case ARMNT: Data = make<ImportThunkChunkARM>(S); return; -  default:    llvm_unreachable("unknown machine type"); -  } -} +    : Defined(DefinedImportThunkKind, Name), WrappedSym(S), +      Data(makeImportThunk(S, Machine)) {}  Defined *Undefined::getWeakAlias() {    // A weak alias may be a weak alias to another symbol, so check recursively. diff --git a/COFF/Symbols.h b/COFF/Symbols.h index 1b83f73ff20c..801fc87f91d9 100644 --- a/COFF/Symbols.h +++ b/COFF/Symbols.h @@ -300,7 +300,6 @@ public:    void setLocation(Chunk *AddressTable) { File->Location = AddressTable; }    uint16_t getOrdinal() { return File->Hdr->OrdinalHint; } -private:    ImportFile *File;  }; @@ -320,6 +319,8 @@ public:    uint64_t getRVA() { return Data->getRVA(); }    Chunk *getChunk() { return Data; } +  DefinedImportData *WrappedSym; +  private:    Chunk *Data;  }; diff --git a/COFF/Writer.cpp b/COFF/Writer.cpp index cf3ad7ef045c..fb1f3cae5bb2 100644 --- a/COFF/Writer.cpp +++ b/COFF/Writer.cpp @@ -365,6 +365,9 @@ void Writer::createImportTables() {    // the same order as in the command line. (That affects DLL    // initialization order, and this ordering is MSVC-compatible.)    for (ImportFile *File : Symtab->ImportFiles) { +    if (!File->Live) +      continue; +      std::string DLL = StringRef(File->DLLName).lower();      if (Config->DLLOrder.count(DLL) == 0)        Config->DLLOrder[DLL] = Config->DLLOrder.size(); @@ -372,19 +375,28 @@ void Writer::createImportTables() {    OutputSection *Text = createSection(".text");    for (ImportFile *File : Symtab->ImportFiles) { +    if (!File->Live) +      continue; +      if (DefinedImportThunk *Thunk = File->ThunkSym)        Text->addChunk(Thunk->getChunk()); +      if (Config->DelayLoads.count(StringRef(File->DLLName).lower())) { +      if (!File->ThunkSym) +        fatal("cannot delay-load " + toString(File) + +              " due to import of data: " + toString(*File->ImpSym));        DelayIdata.add(File->ImpSym);      } else {        Idata.add(File->ImpSym);      }    } +    if (!Idata.empty()) {      OutputSection *Sec = createSection(".idata");      for (Chunk *C : Idata.getChunks())        Sec->addChunk(C);    } +    if (!DelayIdata.empty()) {      Defined *Helper = cast<Defined>(Config->DelayLoadHelper);      DelayIdata.create(Helper); @@ -437,6 +449,14 @@ Optional<coff_symbol16> Writer::createSymbol(Defined *Def) {      if (!D->getChunk()->isLive())        return None; +  if (auto *Sym = dyn_cast<DefinedImportData>(Def)) +    if (!Sym->File->Live) +      return None; + +  if (auto *Sym = dyn_cast<DefinedImportThunk>(Def)) +    if (!Sym->WrappedSym->File->Live) +      return None; +    coff_symbol16 Sym;    StringRef Name = Def->getName();    if (Name.size() > COFF::NameSize) { @@ -491,14 +511,17 @@ void Writer::createSymbolAndStringTable() {      Sec->setStringTableOff(addEntryToStringTable(Name));    } -  for (lld::coff::ObjectFile *File : Symtab->ObjectFiles) -    for (SymbolBody *B : File->getSymbols()) -      if (auto *D = dyn_cast<Defined>(B)) -        if (!D->WrittenToSymtab) { -          D->WrittenToSymtab = true; -          if (Optional<coff_symbol16> Sym = createSymbol(D)) -            OutputSymtab.push_back(*Sym); -        } +  for (lld::coff::ObjectFile *File : Symtab->ObjectFiles) { +    for (SymbolBody *B : File->getSymbols()) { +      auto *D = dyn_cast<Defined>(B); +      if (!D || D->WrittenToSymtab) +        continue; +      D->WrittenToSymtab = true; + +      if (Optional<coff_symbol16> Sym = createSymbol(D)) +        OutputSymtab.push_back(*Sym); +    } +  }    OutputSection *LastSection = OutputSections.back();    // We position the symbol table to be adjacent to the end of the last section. @@ -782,19 +805,15 @@ void Writer::writeBuildId() {    if (BuildId == nullptr)      return; -  MD5 Hash; -  MD5::MD5Result Res; - -  Hash.update(ArrayRef<uint8_t>{Buffer->getBufferStart(), -                                Buffer->getBufferEnd()}); -  Hash.final(Res); -    assert(BuildId->DI->Signature.CVSignature == OMF::Signature::PDB70 &&           "only PDB 7.0 is supported"); -  assert(sizeof(Res) == sizeof(BuildId->DI->PDB70.Signature) && +  assert(sizeof(BuildId->DI->PDB70.Signature) == 16 &&           "signature size mismatch"); -  memcpy(BuildId->DI->PDB70.Signature, Res.Bytes.data(), -         sizeof(codeview::PDB70DebugInfo::Signature)); + +  // Compute an MD5 hash. +  ArrayRef<uint8_t> Buf(Buffer->getBufferStart(), Buffer->getBufferEnd()); +  memcpy(BuildId->DI->PDB70.Signature, MD5::hash(Buf).data(), 16); +    // TODO(compnerd) track the Age    BuildId->DI->PDB70.Age = 1;  } diff --git a/ELF/Config.h b/ELF/Config.h index 57a0e5a5ec73..54f6dc2acc7c 100644 --- a/ELF/Config.h +++ b/ELF/Config.h @@ -145,6 +145,7 @@ struct Configuration {    bool ZNow;    bool ZOrigin;    bool ZRelro; +  bool ZRodynamic;    bool ZText;    bool ExitEarly;    bool ZWxneeded; diff --git a/ELF/Driver.cpp b/ELF/Driver.cpp index 737c6a6bf114..325404447b24 100644 --- a/ELF/Driver.cpp +++ b/ELF/Driver.cpp @@ -572,10 +572,14 @@ static std::pair<bool, bool> getHashStyle(opt::InputArgList &Args) {  // -build-id=sha1 are actually tree hashes for performance reasons.  static std::pair<BuildIdKind, std::vector<uint8_t>>  getBuildId(opt::InputArgList &Args) { -  if (Args.hasArg(OPT_build_id)) +  auto *Arg = Args.getLastArg(OPT_build_id, OPT_build_id_eq); +  if (!Arg) +    return {BuildIdKind::None, {}}; + +  if (Arg->getOption().getID() == OPT_build_id)      return {BuildIdKind::Fast, {}}; -  StringRef S = getString(Args, OPT_build_id_eq, "none"); +  StringRef S = Arg->getValue();    if (S == "md5")      return {BuildIdKind::Md5, {}};    if (S == "sha1" || S == "tree") @@ -688,6 +692,7 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) {    Config->ZNow = hasZOption(Args, "now");    Config->ZOrigin = hasZOption(Args, "origin");    Config->ZRelro = !hasZOption(Args, "norelro"); +  Config->ZRodynamic = hasZOption(Args, "rodynamic");    Config->ZStackSize = getZOptionValue(Args, "stack-size", 0);    Config->ZText = !hasZOption(Args, "notext");    Config->ZWxneeded = hasZOption(Args, "wxneeded"); diff --git a/ELF/ICF.cpp b/ELF/ICF.cpp index 3722d4e3ed2f..419ae6816328 100644 --- a/ELF/ICF.cpp +++ b/ELF/ICF.cpp @@ -326,9 +326,9 @@ void ICF<ELFT>::forEachClass(std::function<void(size_t, size_t)> Fn) {    size_t NumShards = 256;    size_t Step = Sections.size() / NumShards;    parallelForEachN(0, NumShards, [&](size_t I) { -    forEachClassRange(I * Step, (I + 1) * Step, Fn); +    size_t End = (I == NumShards - 1) ? Sections.size() : (I + 1) * Step; +    forEachClassRange(I * Step, End, Fn);    }); -  forEachClassRange(Step * NumShards, Sections.size(), Fn);    ++Cnt;  } diff --git a/ELF/InputFiles.cpp b/ELF/InputFiles.cpp index fe036a644f41..98189825ccbf 100644 --- a/ELF/InputFiles.cpp +++ b/ELF/InputFiles.cpp @@ -281,18 +281,20 @@ bool elf::ObjectFile<ELFT>::shouldMerge(const Elf_Shdr &Sec) {  template <class ELFT>  void elf::ObjectFile<ELFT>::initializeSections(      DenseSet<CachedHashStringRef> &ComdatGroups) { +  const ELFFile<ELFT> &Obj = this->getObj(); +    ArrayRef<Elf_Shdr> ObjSections =        check(this->getObj().sections(), toString(this)); -  const ELFFile<ELFT> &Obj = this->getObj();    uint64_t Size = ObjSections.size();    this->Sections.resize(Size); -  unsigned I = -1; +    StringRef SectionStringTable =        check(Obj.getSectionStringTable(ObjSections), toString(this)); -  for (const Elf_Shdr &Sec : ObjSections) { -    ++I; + +  for (size_t I = 0, E = ObjSections.size(); I < E; I++) {      if (this->Sections[I] == &InputSection::Discarded)        continue; +    const Elf_Shdr &Sec = ObjSections[I];      // SHF_EXCLUDE'ed sections are discarded by the linker. However,      // if -r is given, we'll let the final link discard such sections. @@ -303,13 +305,22 @@ void elf::ObjectFile<ELFT>::initializeSections(      }      switch (Sec.sh_type) { -    case SHT_GROUP: -      this->Sections[I] = &InputSection::Discarded; -      if (ComdatGroups -              .insert( -                  CachedHashStringRef(getShtGroupSignature(ObjSections, Sec))) -              .second) +    case SHT_GROUP: { +      // We discard comdat sections usually. When -r we should not do that. We +      // still do deduplication in this case to simplify implementation, because +      // otherwise merging group sections together would requre additional +      // regeneration of its contents. +      bool New = ComdatGroups +                     .insert(CachedHashStringRef( +                         getShtGroupSignature(ObjSections, Sec))) +                     .second; +      if (New && Config->Relocatable) +        this->Sections[I] = createInputSection(Sec, SectionStringTable); +      else +        this->Sections[I] = &InputSection::Discarded; +      if (New)          continue; +        for (uint32_t SecIndex : getShtGroupEntries(Sec)) {          if (SecIndex >= Size)            fatal(toString(this) + @@ -317,6 +328,7 @@ void elf::ObjectFile<ELFT>::initializeSections(          this->Sections[SecIndex] = &InputSection::Discarded;        }        break; +    }      case SHT_SYMTAB:        this->initSymtab(ObjSections, &Sec);        break; diff --git a/ELF/InputSection.cpp b/ELF/InputSection.cpp index e8cfd21c4c49..466656efbf08 100644 --- a/ELF/InputSection.cpp +++ b/ELF/InputSection.cpp @@ -23,6 +23,7 @@  #include "llvm/Support/Compression.h"  #include "llvm/Support/Endian.h"  #include "llvm/Support/Path.h" +#include "llvm/Support/Threading.h"  #include <mutex>  using namespace llvm; @@ -172,7 +173,8 @@ void InputSectionBase::uncompress() {    if (Error E = Dec.decompress({OutputBuf, Size}))      fatal(toString(this) +            ": decompress failed: " + llvm::toString(std::move(E))); -  Data = ArrayRef<uint8_t>((uint8_t *)OutputBuf, Size); +  this->Data = ArrayRef<uint8_t>((uint8_t *)OutputBuf, Size); +  this->Flags &= ~(uint64_t)SHF_COMPRESSED;  }  uint64_t SectionBase::getOffset(const DefinedRegular &Sym) const { @@ -293,6 +295,24 @@ bool InputSectionBase::classof(const SectionBase *S) {    return S->kind() != Output;  } +void InputSection::copyShtGroup(uint8_t *Buf) { +  assert(this->Type == SHT_GROUP); + +  ArrayRef<uint32_t> From = getDataAs<uint32_t>(); +  uint32_t *To = reinterpret_cast<uint32_t *>(Buf); + +  // First entry is a flag word, we leave it unchanged. +  *To++ = From[0]; + +  // Here we adjust indices of sections that belong to group as it +  // might change during linking. +  ArrayRef<InputSectionBase *> Sections = this->File->getSections(); +  for (uint32_t Val : From.slice(1)) { +    uint32_t Index = read32(&Val, Config->Endianness); +    write32(To++, Sections[Index]->OutSec->SectionIndex, Config->Endianness); +  } +} +  InputSectionBase *InputSection::getRelocatedSection() {    assert(this->Type == SHT_RELA || this->Type == SHT_REL);    ArrayRef<InputSectionBase *> Sections = this->File->getSections(); @@ -678,6 +698,13 @@ template <class ELFT> void InputSection::writeTo(uint8_t *Buf) {      return;    } +  // If -r is given, linker should keep SHT_GROUP sections. We should fixup +  // them, see copyShtGroup(). +  if (this->Type == SHT_GROUP) { +    copyShtGroup(Buf + OutSecOff); +    return; +  } +    // Copy section contents from source object file to output file    // and then apply relocations.    memcpy(Buf + OutSecOff, Data.data(), Data.size()); @@ -866,7 +893,7 @@ const SectionPiece *MergeInputSection::getSectionPiece(uint64_t Offset) const {  // it is not just an addition to a base output offset.  uint64_t MergeInputSection::getOffset(uint64_t Offset) const {    // Initialize OffsetMap lazily. -  std::call_once(InitOffsetMap, [&] { +  llvm::call_once(InitOffsetMap, [&] {      OffsetMap.reserve(Pieces.size());      for (const SectionPiece &Piece : Pieces)        OffsetMap[Piece.InputOff] = Piece.OutputOff; diff --git a/ELF/InputSection.h b/ELF/InputSection.h index 303c398b58cd..4ef4328e8a5d 100644 --- a/ELF/InputSection.h +++ b/ELF/InputSection.h @@ -18,6 +18,7 @@  #include "llvm/ADT/DenseSet.h"  #include "llvm/ADT/TinyPtrVector.h"  #include "llvm/Object/ELF.h" +#include "llvm/Support/Threading.h"  #include <mutex>  namespace lld { @@ -248,7 +249,7 @@ private:    std::vector<uint32_t> Hashes;    mutable llvm::DenseMap<uint64_t, uint64_t> OffsetMap; -  mutable std::once_flag InitOffsetMap; +  mutable llvm::once_flag InitOffsetMap;    llvm::DenseSet<uint64_t> LiveOffsets;  }; @@ -318,6 +319,8 @@ public:  private:    template <class ELFT, class RelTy>    void copyRelocations(uint8_t *Buf, llvm::ArrayRef<RelTy> Rels); + +  void copyShtGroup(uint8_t *Buf);  };  // The list of all input sections. diff --git a/ELF/LTO.cpp b/ELF/LTO.cpp index dd435173101a..6915d9713891 100644 --- a/ELF/LTO.cpp +++ b/ELF/LTO.cpp @@ -73,7 +73,12 @@ static std::unique_ptr<lto::LTO> createLTO() {    Conf.Options = InitTargetOptionsFromCodeGenFlags();    Conf.Options.RelaxELFRelocations = true; -  Conf.RelocModel = Config->Pic ? Reloc::PIC_ : Reloc::Static; +  if (Config->Relocatable) +    Conf.RelocModel = None; +  else if (Config->Pic) +    Conf.RelocModel = Reloc::PIC_; +  else +    Conf.RelocModel = Reloc::Static;    Conf.CodeModel = GetCodeModelFromCMModel();    Conf.DisableVerify = Config->DisableVerify;    Conf.DiagHandler = diagnosticHandler; diff --git a/ELF/LinkerScript.cpp b/ELF/LinkerScript.cpp index c303f0524ad4..492b81c1fa76 100644 --- a/ELF/LinkerScript.cpp +++ b/ELF/LinkerScript.cpp @@ -20,6 +20,8 @@  #include "SymbolTable.h"  #include "Symbols.h"  #include "SyntheticSections.h" +#include "Target.h" +#include "Threads.h"  #include "Writer.h"  #include "llvm/ADT/STLExtras.h"  #include "llvm/ADT/StringRef.h" @@ -198,6 +200,15 @@ bool OutputSectionCommand::classof(const BaseCommand *C) {    return C->Kind == OutputSectionKind;  } +// Fill [Buf, Buf + Size) with Filler. +// This is used for linker script "=fillexp" command. +static void fill(uint8_t *Buf, size_t Size, uint32_t Filler) { +  size_t I = 0; +  for (; I + 4 < Size; I += 4) +    memcpy(Buf + I, &Filler, 4); +  memcpy(Buf + I, &Filler, Size - I); +} +  bool InputSectionDescription::classof(const BaseCommand *C) {    return C->Kind == InputSectionKind;  } @@ -263,16 +274,16 @@ static bool matchConstraints(ArrayRef<InputSectionBase *> Sections,           (!IsRW && Kind == ConstraintKind::ReadOnly);  } -static void sortSections(InputSectionBase **Begin, InputSectionBase **End, +static void sortSections(InputSection **Begin, InputSection **End,                           SortSectionPolicy K) {    if (K != SortSectionPolicy::Default && K != SortSectionPolicy::None)      std::stable_sort(Begin, End, getComparator(K));  }  // Compute and remember which sections the InputSectionDescription matches. -std::vector<InputSectionBase *> +std::vector<InputSection *>  LinkerScript::computeInputSections(const InputSectionDescription *Cmd) { -  std::vector<InputSectionBase *> Ret; +  std::vector<InputSection *> Ret;    // Collects all sections that satisfy constraints of Cmd.    for (const SectionPattern &Pat : Cmd->SectionPatterns) { @@ -294,7 +305,7 @@ LinkerScript::computeInputSections(const InputSectionDescription *Cmd) {            !Pat.SectionPat.match(Sec->Name))          continue; -      Ret.push_back(Sec); +      Ret.push_back(cast<InputSection>(Sec));        Sec->Assigned = true;      } @@ -309,8 +320,8 @@ LinkerScript::computeInputSections(const InputSectionDescription *Cmd) {      //    --sort-section is handled as an inner SORT command.      // 3. If one SORT command is given, and if it is SORT_NONE, don't sort.      // 4. If no SORT command is given, sort according to --sort-section. -    InputSectionBase **Begin = Ret.data() + SizeBefore; -    InputSectionBase **End = Ret.data() + Ret.size(); +    InputSection **Begin = Ret.data() + SizeBefore; +    InputSection **End = Ret.data() + Ret.size();      if (Pat.SortOuter != SortSectionPolicy::None) {        if (Pat.SortInner == SortSectionPolicy::Default)          sortSections(Begin, End, Config->SortSection); @@ -493,7 +504,7 @@ void LinkerScript::addOrphanSections(OutputSectionFactory &Factory) {          Sec->SectionIndex = Index;        }        auto *ISD = make<InputSectionDescription>(""); -      ISD->Sections.push_back(S); +      ISD->Sections.push_back(cast<InputSection>(S));        Cmd->Commands.push_back(ISD);      }    } @@ -684,7 +695,6 @@ void LinkerScript::adjustSectionsBeforeSorting() {    // '.' is assigned to, but creating these section should not have any bad    // consequeces and gives us a section to put the symbol in.    uint64_t Flags = SHF_ALLOC; -  uint32_t Type = SHT_PROGBITS;    for (int I = 0, E = Opt.Commands.size(); I != E; ++I) {      auto *Cmd = dyn_cast<OutputSectionCommand>(Opt.Commands[I]); @@ -692,14 +702,13 @@ void LinkerScript::adjustSectionsBeforeSorting() {        continue;      if (OutputSection *Sec = Cmd->Sec) {        Flags = Sec->Flags; -      Type = Sec->Type;        continue;      }      if (isAllSectionDescription(*Cmd))        continue; -    auto *OutSec = make<OutputSection>(Cmd->Name, Type, Flags); +    auto *OutSec = make<OutputSection>(Cmd->Name, SHT_PROGBITS, Flags);      OutSec->SectionIndex = I;      OutputSections->push_back(OutSec);      Cmd->Sec = OutSec; @@ -875,20 +884,20 @@ void LinkerScript::synchronize() {      if (!Cmd)        continue;      ArrayRef<InputSection *> Sections = Cmd->Sec->Sections; -    std::vector<InputSectionBase **> ScriptSections; -    DenseSet<InputSectionBase *> ScriptSectionsSet; +    std::vector<InputSection **> ScriptSections; +    DenseSet<InputSection *> ScriptSectionsSet;      for (BaseCommand *Base : Cmd->Commands) {        auto *ISD = dyn_cast<InputSectionDescription>(Base);        if (!ISD)          continue; -      for (InputSectionBase *&IS : ISD->Sections) { +      for (InputSection *&IS : ISD->Sections) {          if (IS->Live) {            ScriptSections.push_back(&IS);            ScriptSectionsSet.insert(IS);          }        }      } -    std::vector<InputSectionBase *> Missing; +    std::vector<InputSection *> Missing;      for (InputSection *IS : Sections)        if (!ScriptSectionsSet.count(IS))          Missing.push_back(IS); @@ -896,7 +905,7 @@ void LinkerScript::synchronize() {        auto ISD = make<InputSectionDescription>("");        ISD->Sections = Missing;        Cmd->Commands.push_back(ISD); -      for (InputSectionBase *&IS : ISD->Sections) +      for (InputSection *&IS : ISD->Sections)          if (IS->Live)            ScriptSections.push_back(&IS);      } @@ -1034,10 +1043,12 @@ OutputSectionCommand *LinkerScript::getCmd(OutputSection *Sec) const {    return I->second;  } -Optional<uint32_t> LinkerScript::getFiller(OutputSection *Sec) { -  if (OutputSectionCommand *Cmd = getCmd(Sec)) -    return Cmd->Filler; -  return None; +uint32_t OutputSectionCommand::getFiller() { +  if (Filler) +    return *Filler; +  if (Sec->Flags & SHF_EXECINSTR) +    return Target->TrapInstr; +  return 0;  }  static void writeInt(uint8_t *Buf, uint64_t Data, uint64_t Size) { @@ -1053,11 +1064,45 @@ static void writeInt(uint8_t *Buf, uint64_t Data, uint64_t Size) {      llvm_unreachable("unsupported Size argument");  } -void LinkerScript::writeDataBytes(OutputSection *Sec, uint8_t *Buf) { -  if (OutputSectionCommand *Cmd = getCmd(Sec)) -    for (BaseCommand *Base : Cmd->Commands) -      if (auto *Data = dyn_cast<BytesDataCommand>(Base)) -        writeInt(Buf + Data->Offset, Data->Expression().getValue(), Data->Size); +template <class ELFT> void OutputSectionCommand::writeTo(uint8_t *Buf) { +  Sec->Loc = Buf; + +  // We may have already rendered compressed content when using +  // -compress-debug-sections option. Write it together with header. +  if (!Sec->CompressedData.empty()) { +    memcpy(Buf, Sec->ZDebugHeader.data(), Sec->ZDebugHeader.size()); +    memcpy(Buf + Sec->ZDebugHeader.size(), Sec->CompressedData.data(), +           Sec->CompressedData.size()); +    return; +  } + +  // Write leading padding. +  ArrayRef<InputSection *> Sections = Sec->Sections; +  uint32_t Filler = getFiller(); +  if (Filler) +    fill(Buf, Sections.empty() ? Sec->Size : Sections[0]->OutSecOff, Filler); + +  parallelForEachN(0, Sections.size(), [=](size_t I) { +    InputSection *IS = Sections[I]; +    IS->writeTo<ELFT>(Buf); + +    // Fill gaps between sections. +    if (Filler) { +      uint8_t *Start = Buf + IS->OutSecOff + IS->getSize(); +      uint8_t *End; +      if (I + 1 == Sections.size()) +        End = Buf + Sec->Size; +      else +        End = Buf + Sections[I + 1]->OutSecOff; +      fill(Start, End - Start, Filler); +    } +  }); + +  // Linker scripts may have BYTE()-family commands with which you +  // can write arbitrary bytes to the output. Process them if any. +  for (BaseCommand *Base : Commands) +    if (auto *Data = dyn_cast<BytesDataCommand>(Base)) +      writeInt(Buf + Data->Offset, Data->Expression().getValue(), Data->Size);  }  bool LinkerScript::hasLMA(OutputSection *Sec) { @@ -1104,3 +1149,8 @@ size_t LinkerScript::getPhdrIndex(const Twine &Loc, StringRef PhdrName) {    error(Loc + ": section header '" + PhdrName + "' is not listed in PHDRS");    return 0;  } + +template void OutputSectionCommand::writeTo<ELF32LE>(uint8_t *Buf); +template void OutputSectionCommand::writeTo<ELF32BE>(uint8_t *Buf); +template void OutputSectionCommand::writeTo<ELF64LE>(uint8_t *Buf); +template void OutputSectionCommand::writeTo<ELF64BE>(uint8_t *Buf); diff --git a/ELF/LinkerScript.h b/ELF/LinkerScript.h index d0a4d83d72b0..e56e569d4e72 100644 --- a/ELF/LinkerScript.h +++ b/ELF/LinkerScript.h @@ -130,6 +130,9 @@ struct OutputSectionCommand : BaseCommand {    ConstraintKind Constraint = ConstraintKind::NoConstraint;    std::string Location;    std::string MemoryRegionName; + +  template <class ELFT> void writeTo(uint8_t *Buf); +  uint32_t getFiller();  };  // This struct represents one section match pattern in SECTIONS() command. @@ -157,7 +160,7 @@ struct InputSectionDescription : BaseCommand {    // will be associated with this InputSectionDescription.    std::vector<SectionPattern> SectionPatterns; -  std::vector<InputSectionBase *> Sections; +  std::vector<InputSection *> Sections;  };  // Represents an ASSERT(). @@ -213,11 +216,10 @@ struct ScriptConfiguration {  class LinkerScript final {    llvm::DenseMap<OutputSection *, OutputSectionCommand *> SecToCommand; -  OutputSectionCommand *getCmd(OutputSection *Sec) const;    void assignSymbol(SymbolAssignment *Cmd, bool InSec);    void setDot(Expr E, const Twine &Loc, bool InSec); -  std::vector<InputSectionBase *> +  std::vector<InputSection *>    computeInputSections(const InputSectionDescription *);    std::vector<InputSectionBase *> @@ -244,6 +246,7 @@ class LinkerScript final {    MemoryRegion *CurMemRegion = nullptr;  public: +  OutputSectionCommand *getCmd(OutputSection *Sec) const;    bool hasPhdrsCommands() { return !Opt.PhdrsCommands.empty(); }    uint64_t getDot() { return Dot; }    OutputSection *getOutputSection(const Twine &Loc, StringRef S); @@ -263,7 +266,6 @@ public:    std::vector<PhdrEntry> createPhdrs();    bool ignoreInterpSection(); -  llvm::Optional<uint32_t> getFiller(OutputSection *Sec);    bool hasLMA(OutputSection *Sec);    bool shouldKeep(InputSectionBase *S);    void assignOffsets(OutputSectionCommand *Cmd); @@ -272,7 +274,6 @@ public:    void synchronize();    void assignAddresses(std::vector<PhdrEntry> &Phdrs); -  void writeDataBytes(OutputSection *Sec, uint8_t *Buf);    void addSymbol(SymbolAssignment *Cmd);    void processCommands(OutputSectionFactory &Factory); diff --git a/ELF/MapFile.cpp b/ELF/MapFile.cpp index 7b82eceba02a..806e99e3d9dd 100644 --- a/ELF/MapFile.cpp +++ b/ELF/MapFile.cpp @@ -132,12 +132,17 @@ void elf::writeMapFile(llvm::ArrayRef<BaseCommand *> Script) {      OS << OSec->Name << '\n';      // Dump symbols for each input section. -    for (InputSection *IS : OSec->Sections) { -      writeHeader<ELFT>(OS, OSec->Addr + IS->OutSecOff, IS->getSize(), -                        IS->Alignment); -      OS << indent(1) << toString(IS) << '\n'; -      for (DefinedRegular *Sym : SectionSyms[IS]) -        OS << SymStr[Sym] << '\n'; +    for (BaseCommand *Base : Cmd->Commands) { +      auto *ISD = dyn_cast<InputSectionDescription>(Base); +      if (!ISD) +        continue; +      for (InputSection *IS : ISD->Sections) { +        writeHeader<ELFT>(OS, OSec->Addr + IS->OutSecOff, IS->getSize(), +                          IS->Alignment); +        OS << indent(1) << toString(IS) << '\n'; +        for (DefinedRegular *Sym : SectionSyms[IS]) +          OS << SymStr[Sym] << '\n'; +      }      }    }  } diff --git a/ELF/Options.td b/ELF/Options.td index 65a0e72d2320..335c7ade6db2 100644 --- a/ELF/Options.td +++ b/ELF/Options.td @@ -313,6 +313,7 @@ def alias_o_output2 : Separate<["--"], "output">, Alias<o>;  def alias_pie_pic_executable: F<"pic-executable">, Alias<pie>;  def alias_print_map_M: Flag<["-"], "M">, Alias<print_map>;  def alias_relocatable_r: Flag<["-"], "r">, Alias<relocatable>; +def alias_reproduce_eq: J<"reproduce=">, Alias<reproduce>;  def alias_retain_symbols_file: S<"retain-symbols-file">, Alias<retain_symbols_file>;  def alias_rpath_R: JoinedOrSeparate<["-"], "R">, Alias<rpath>;  def alias_rpath_rpath: J<"rpath=">, Alias<rpath>; diff --git a/ELF/OutputSections.cpp b/ELF/OutputSections.cpp index dcefd03766d7..d82fdcdc31ba 100644 --- a/ELF/OutputSections.cpp +++ b/ELF/OutputSections.cpp @@ -103,7 +103,7 @@ template <class ELFT> void OutputSection::maybeCompress() {    // Write section contents to a temporary buffer and compress it.    std::vector<uint8_t> Buf(Size); -  writeTo<ELFT>(Buf.data()); +  Script->getCmd(this)->writeTo<ELFT>(Buf.data());    if (Error E = zlib::compress(toStringRef(Buf), CompressedData))      fatal("compress failed: " + llvm::toString(std::move(E))); @@ -112,6 +112,19 @@ template <class ELFT> void OutputSection::maybeCompress() {    Flags |= SHF_COMPRESSED;  } +template <class ELFT> static void finalizeShtGroup(OutputSection *Sec) { +  // sh_link field for SHT_GROUP sections should contain the section index of +  // the symbol table. +  Sec->Link = InX::SymTab->OutSec->SectionIndex; + +  // sh_link then contain index of an entry in symbol table section which +  // provides signature of the section group. +  elf::ObjectFile<ELFT> *Obj = Sec->Sections[0]->getFile<ELFT>(); +  assert(Config->Relocatable && Sec->Sections.size() == 1); +  ArrayRef<SymbolBody *> Symbols = Obj->getSymbols(); +  Sec->Info = InX::SymTab->getSymbolIndex(Symbols[Sec->Sections[0]->Info - 1]); +} +  template <class ELFT> void OutputSection::finalize() {    if ((this->Flags & SHF_LINK_ORDER) && !this->Sections.empty()) {      std::sort(Sections.begin(), Sections.end(), compareByFilePosition); @@ -126,6 +139,11 @@ template <class ELFT> void OutputSection::finalize() {    }    uint32_t Type = this->Type; +  if (Type == SHT_GROUP) { +    finalizeShtGroup<ELFT>(this); +    return; +  } +    if (!Config->CopyRelocs || (Type != SHT_RELA && Type != SHT_REL))      return; @@ -259,69 +277,6 @@ void OutputSection::sortCtorsDtors() {    std::stable_sort(Sections.begin(), Sections.end(), compCtors);  } -// Fill [Buf, Buf + Size) with Filler. -// This is used for linker script "=fillexp" command. -static void fill(uint8_t *Buf, size_t Size, uint32_t Filler) { -  size_t I = 0; -  for (; I + 4 < Size; I += 4) -    memcpy(Buf + I, &Filler, 4); -  memcpy(Buf + I, &Filler, Size - I); -} - -uint32_t OutputSection::getFiller() { -  // Determine what to fill gaps between InputSections with, as specified by the -  // linker script. If nothing is specified and this is an executable section, -  // fall back to trap instructions to prevent bad diassembly and detect invalid -  // jumps to padding. -  if (Optional<uint32_t> Filler = Script->getFiller(this)) -    return *Filler; -  if (Flags & SHF_EXECINSTR) -    return Target->TrapInstr; -  return 0; -} - -template <class ELFT> void OutputSection::writeTo(uint8_t *Buf) { -  Loc = Buf; - -  // We may have already rendered compressed content when using -  // -compress-debug-sections option. Write it together with header. -  if (!CompressedData.empty()) { -    memcpy(Buf, ZDebugHeader.data(), ZDebugHeader.size()); -    memcpy(Buf + ZDebugHeader.size(), CompressedData.data(), -           CompressedData.size()); -    return; -  } - -  // Write leading padding. -  uint32_t Filler = getFiller(); -  if (Filler) -    fill(Buf, Sections.empty() ? Size : Sections[0]->OutSecOff, Filler); - -  parallelForEachN(0, Sections.size(), [=](size_t I) { -    InputSection *Sec = Sections[I]; -    Sec->writeTo<ELFT>(Buf); - -    // Fill gaps between sections. -    if (Filler) { -      uint8_t *Start = Buf + Sec->OutSecOff + Sec->getSize(); -      uint8_t *End; -      if (I + 1 == Sections.size()) -        End = Buf + Size; -      else -        End = Buf + Sections[I + 1]->OutSecOff; -      fill(Start, End - Start, Filler); -    } -  }); - -  // Linker scripts may have BYTE()-family commands with which you -  // can write arbitrary bytes to the output. Process them if any. -  Script->writeDataBytes(this, Buf); -} - -static uint64_t getOutFlags(InputSectionBase *S) { -  return S->Flags & ~SHF_GROUP & ~SHF_COMPRESSED; -} -  static SectionKey createKey(InputSectionBase *C, StringRef OutsecName) {    //  The ELF spec just says    // ---------------------------------------------------------------- @@ -418,7 +373,10 @@ void OutputSectionFactory::addInputSec(InputSectionBase *IS,      return;    } -  uint64_t Flags = getOutFlags(IS); +  uint64_t Flags = IS->Flags; +  if (!Config->Relocatable) +    Flags &= ~(uint64_t)SHF_GROUP; +    if (Sec) {      if (getIncompatibleFlags(Sec->Flags) != getIncompatibleFlags(IS->Flags))        error("incompatible section flags for " + Sec->Name + @@ -484,8 +442,3 @@ template void OutputSection::maybeCompress<ELF32LE>();  template void OutputSection::maybeCompress<ELF32BE>();  template void OutputSection::maybeCompress<ELF64LE>();  template void OutputSection::maybeCompress<ELF64BE>(); - -template void OutputSection::writeTo<ELF32LE>(uint8_t *Buf); -template void OutputSection::writeTo<ELF32BE>(uint8_t *Buf); -template void OutputSection::writeTo<ELF64LE>(uint8_t *Buf); -template void OutputSection::writeTo<ELF64BE>(uint8_t *Buf); diff --git a/ELF/OutputSections.h b/ELF/OutputSections.h index 413871b60cf7..08655a9ed67b 100644 --- a/ELF/OutputSections.h +++ b/ELF/OutputSections.h @@ -82,8 +82,6 @@ public:    void sort(std::function<int(InputSectionBase *S)> Order);    void sortInitFini();    void sortCtorsDtors(); -  uint32_t getFiller(); -  template <class ELFT> void writeTo(uint8_t *Buf);    template <class ELFT> void finalize();    template <class ELFT> void maybeCompress();    void assignOffsets(); diff --git a/ELF/SyntheticSections.cpp b/ELF/SyntheticSections.cpp index 599f1441a47f..d3db32613a8a 100644 --- a/ELF/SyntheticSections.cpp +++ b/ELF/SyntheticSections.cpp @@ -1005,10 +1005,11 @@ DynamicSection<ELFT>::DynamicSection()                         ".dynamic") {    this->Entsize = ELFT::Is64Bits ? 16 : 8; -  // .dynamic section is not writable on MIPS. +  // .dynamic section is not writable on MIPS and on Fuchsia OS +  // which passes -z rodynamic.    // See "Special Section" in Chapter 4 in the following document:    // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf -  if (Config->EMachine == EM_MIPS) +  if (Config->EMachine == EM_MIPS || Config->ZRodynamic)      this->Flags = SHF_ALLOC;    addEntries(); @@ -1053,7 +1054,15 @@ template <class ELFT> void DynamicSection<ELFT>::addEntries() {    if (DtFlags1)      add({DT_FLAGS_1, DtFlags1}); -  if (!Config->Shared && !Config->Relocatable) +  // DT_DEBUG is a pointer to debug informaion used by debuggers at runtime. We +  // need it for each process, so we don't write it for DSOs. The loader writes +  // the pointer into this entry. +  // +  // DT_DEBUG is the only .dynamic entry that needs to be written to. Some +  // systems (currently only Fuchsia OS) provide other means to give the +  // debugger this information. Such systems may choose make .dynamic read-only. +  // If the target is such a system (used -z rodynamic) don't write DT_DEBUG. +  if (!Config->Shared && !Config->Relocatable && !Config->ZRodynamic)      add({DT_DEBUG, (uint64_t)0});  } @@ -1778,11 +1787,10 @@ void GdbIndexSection::readDwarf(InputSection *Sec) {      std::tie(IsNew, Sym) = SymbolTable.add(Hash, Offset);      if (IsNew) {        Sym->CuVectorIndex = CuVectors.size(); -      CuVectors.push_back({{CuId, Pair.second}}); -      continue; +      CuVectors.resize(CuVectors.size() + 1);      } -    CuVectors[Sym->CuVectorIndex].push_back({CuId, Pair.second}); +    CuVectors[Sym->CuVectorIndex].insert((Pair.second << 24) | (uint32_t)CuId);    }  } @@ -1806,7 +1814,7 @@ void GdbIndexSection::finalizeContents() {    ConstantPoolOffset =        SymTabOffset + SymbolTable.getCapacity() * SymTabEntrySize; -  for (std::vector<std::pair<uint32_t, uint8_t>> &CuVec : CuVectors) { +  for (std::set<uint32_t> &CuVec : CuVectors) {      CuVectorsOffset.push_back(CuVectorsSize);      CuVectorsSize += OffsetTypeSize * (CuVec.size() + 1);    } @@ -1859,14 +1867,11 @@ void GdbIndexSection::writeTo(uint8_t *Buf) {    }    // Write the CU vectors into the constant pool. -  for (std::vector<std::pair<uint32_t, uint8_t>> &CuVec : CuVectors) { +  for (std::set<uint32_t> &CuVec : CuVectors) {      write32le(Buf, CuVec.size());      Buf += 4; -    for (std::pair<uint32_t, uint8_t> &P : CuVec) { -      uint32_t Index = P.first; -      uint8_t Flags = P.second; -      Index |= Flags << 24; -      write32le(Buf, Index); +    for (uint32_t Val : CuVec) { +      write32le(Buf, Val);        Buf += 4;      }    } @@ -2173,17 +2178,6 @@ MipsRldMapSection::MipsRldMapSection()      : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, Config->Wordsize,                         ".rld_map") {} -void MipsRldMapSection::writeTo(uint8_t *Buf) { -  // Apply filler from linker script. -  Optional<uint32_t> Fill = Script->getFiller(this->OutSec); -  if (!Fill || *Fill == 0) -    return; - -  uint64_t Filler = *Fill; -  Filler = (Filler << 32) | Filler; -  memcpy(Buf, &Filler, getSize()); -} -  ARMExidxSentinelSection::ARMExidxSentinelSection()      : SyntheticSection(SHF_ALLOC | SHF_LINK_ORDER, SHT_ARM_EXIDX,                         Config->Wordsize, ".ARM.exidx") {} @@ -2194,7 +2188,7 @@ ARMExidxSentinelSection::ARMExidxSentinelSection()  // | PREL31 upper bound of code that has exception tables | EXIDX_CANTUNWIND |  void ARMExidxSentinelSection::writeTo(uint8_t *Buf) {    // Get the InputSection before us, we are by definition last -  auto RI = cast<OutputSection>(this->OutSec)->Sections.rbegin(); +  auto RI = this->OutSec->Sections.rbegin();    InputSection *LE = *(++RI);    InputSection *LC = cast<InputSection>(LE->getLinkOrderDep());    uint64_t S = LC->OutSec->Addr + LC->getOffset(LC->getSize()); diff --git a/ELF/SyntheticSections.h b/ELF/SyntheticSections.h index c5ffb88c1366..61cc03de222e 100644 --- a/ELF/SyntheticSections.h +++ b/ELF/SyntheticSections.h @@ -27,6 +27,8 @@  #include "llvm/ADT/MapVector.h"  #include "llvm/MC/StringTableBuilder.h" +#include <set> +  namespace lld {  namespace elf { @@ -515,7 +517,7 @@ public:    GdbHashTab SymbolTable;    // The CU vector portion of the constant pool. -  std::vector<std::vector<std::pair<uint32_t, uint8_t>>> CuVectors; +  std::vector<std::set<uint32_t>> CuVectors;    std::vector<AddressEntry> AddressArea; @@ -709,7 +711,7 @@ class MipsRldMapSection : public SyntheticSection {  public:    MipsRldMapSection();    size_t getSize() const override { return Config->Wordsize; } -  void writeTo(uint8_t *Buf) override; +  void writeTo(uint8_t *Buf) override {}  };  class ARMExidxSentinelSection : public SyntheticSection { diff --git a/ELF/Writer.cpp b/ELF/Writer.cpp index 7a21d2b9f13d..e539d8ffce6e 100644 --- a/ELF/Writer.cpp +++ b/ELF/Writer.cpp @@ -46,6 +46,7 @@ public:    void run();  private: +  void clearOutputSections();    void createSyntheticSections();    void copyLocalSymbols();    void addSectionSymbols(); @@ -80,6 +81,8 @@ private:    void addStartStopSymbols(OutputSection *Sec);    uint64_t getEntryAddr();    OutputSection *findSection(StringRef Name); +  OutputSection *findSectionInScript(StringRef Name); +  OutputSectionCommand *findSectionCommand(StringRef Name);    std::vector<PhdrEntry> Phdrs; @@ -161,7 +164,7 @@ static void combineMergableSections() {        continue;      StringRef OutsecName = getOutputSectionName(MS->Name); -    uint64_t Flags = MS->Flags & ~(uint64_t)(SHF_GROUP | SHF_COMPRESSED); +    uint64_t Flags = MS->Flags & ~(uint64_t)SHF_GROUP;      uint32_t Alignment = std::max<uint32_t>(MS->Alignment, MS->Entsize);      auto I = llvm::find_if(MergeSections, [=](MergeSyntheticSection *Sec) { @@ -198,6 +201,15 @@ template <class ELFT> static void combineEhFrameSections() {    V.erase(std::remove(V.begin(), V.end(), nullptr), V.end());  } +template <class ELFT> void Writer<ELFT>::clearOutputSections() { +  // Clear the OutputSections to make sure it is not used anymore. Any +  // code from this point on should be using the linker script +  // commands. +  for (OutputSection *Sec : OutputSections) +    Sec->Sections.clear(); +  OutputSections.clear(); +} +  // The main function of the writer.  template <class ELFT> void Writer<ELFT>::run() {    // Create linker-synthesized sections such as .got or .plt. @@ -244,13 +256,21 @@ template <class ELFT> void Writer<ELFT>::run() {    if (ErrorCount)      return; +  if (!Script->Opt.HasSections) { +    if (!Config->Relocatable) +      fixSectionAlignments(); +    Script->fabricateDefaultCommands(); +  } + +  // If -compressed-debug-sections is specified, we need to compress +  // .debug_* sections. Do it right now because it changes the size of +  // output sections. +  parallelForEach(OutputSections.begin(), OutputSections.end(), +                  [](OutputSection *S) { S->maybeCompress<ELFT>(); }); +    if (Config->Relocatable) {      assignFileOffsets();    } else { -    if (!Script->Opt.HasSections) { -      fixSectionAlignments(); -      Script->fabricateDefaultCommands(); -    }      Script->synchronize();      Script->assignAddresses(Phdrs); @@ -281,6 +301,7 @@ template <class ELFT> void Writer<ELFT>::run() {    } else {      writeSectionsBinary();    } +  clearOutputSections();    // Backfill .note.gnu.build-id section content. This is done at last    // because the content is usually a hash value of the entire output file. @@ -288,10 +309,6 @@ template <class ELFT> void Writer<ELFT>::run() {    if (ErrorCount)      return; -  // Clear the OutputSections to make sure it is not used anymore. Any -  // code from this point on should be using the linker script -  // commands. -  OutputSections.clear();    // Handle -Map option.    writeMapFile<ELFT>(Script->Opt.Commands); @@ -631,10 +648,11 @@ bool elf::isRelroSection(const OutputSection *Sec) {  // * It is easy to check if a give branch was taken.  // * It is easy two see how similar two ranks are (see getRankProximity).  enum RankFlags { -  RF_NOT_ADDR_SET = 1 << 15, -  RF_NOT_INTERP = 1 << 14, -  RF_NOT_ALLOC = 1 << 13, -  RF_WRITE = 1 << 12, +  RF_NOT_ADDR_SET = 1 << 16, +  RF_NOT_INTERP = 1 << 15, +  RF_NOT_ALLOC = 1 << 14, +  RF_WRITE = 1 << 13, +  RF_EXEC_WRITE = 1 << 12,    RF_EXEC = 1 << 11,    RF_NON_TLS_BSS = 1 << 10,    RF_NON_TLS_BSS_RO = 1 << 9, @@ -669,19 +687,29 @@ static unsigned getSectionRank(const OutputSection *Sec) {    if (!(Sec->Flags & SHF_ALLOC))      return Rank | RF_NOT_ALLOC; -  // We want the read only sections first so that they go in the PT_LOAD -  // covering the program headers at the start of the file. -  if (Sec->Flags & SHF_WRITE) -    Rank |= RF_WRITE; - -  if (Sec->Flags & SHF_EXECINSTR) { -    // For a corresponding reason, put non exec sections first (the program -    // header PT_LOAD is not executable). -    // We only do that if we are not using linker scripts, since with linker -    // scripts ro and rx sections are in the same PT_LOAD, so their relative -    // order is not important. The same applies for -no-rosegment. -    if ((Rank & RF_WRITE) || !Config->SingleRoRx) +  // Sort sections based on their access permission in the following +  // order: R, RX, RWX, RW.  This order is based on the following +  // considerations: +  // * Read-only sections come first such that they go in the +  //   PT_LOAD covering the program headers at the start of the file. +  // * Read-only, executable sections come next, unless the +  //   -no-rosegment option is used. +  // * Writable, executable sections follow such that .plt on +  //   architectures where it needs to be writable will be placed +  //   between .text and .data. +  // * Writable sections come last, such that .bss lands at the very +  //   end of the last PT_LOAD. +  bool IsExec = Sec->Flags & SHF_EXECINSTR; +  bool IsWrite = Sec->Flags & SHF_WRITE; + +  if (IsExec) { +    if (IsWrite) +      Rank |= RF_EXEC_WRITE; +    else if (!Config->SingleRoRx)        Rank |= RF_EXEC; +  } else { +    if (IsWrite) +      Rank |= RF_WRITE;    }    // If we got here we know that both A and B are in the same PT_LOAD. @@ -778,12 +806,6 @@ static bool compareSections(const OutputSection *A, const OutputSection *B) {    return compareSectionsNonScript(A, B);  } -// Program header entry -PhdrEntry::PhdrEntry(unsigned Type, unsigned Flags) { -  p_type = Type; -  p_flags = Flags; -} -  void PhdrEntry::add(OutputSection *Sec) {    Last = Sec;    if (!First) @@ -1239,12 +1261,6 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {    for (OutputSection *Sec : OutputSections)      Sec->finalize<ELFT>(); -  // If -compressed-debug-sections is specified, we need to compress -  // .debug_* sections. Do it right now because it changes the size of -  // output sections. -  parallelForEach(OutputSections.begin(), OutputSections.end(), -                  [](OutputSection *S) { S->maybeCompress<ELFT>(); }); -    // createThunks may have added local symbols to the static symbol table    applySynthetic({InX::SymTab, InX::ShStrTab, InX::StrTab},                   [](SyntheticSection *SS) { SS->postThunkContents(); }); @@ -1297,6 +1313,21 @@ void Writer<ELFT>::addStartStopSymbols(OutputSection *Sec) {    addOptionalRegular<ELFT>(Saver.save("__stop_" + S), Sec, -1, STV_DEFAULT);  } +template <class ELFT> +OutputSectionCommand *Writer<ELFT>::findSectionCommand(StringRef Name) { +  for (BaseCommand *Base : Script->Opt.Commands) +    if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base)) +      if (Cmd->Name == Name) +        return Cmd; +  return nullptr; +} + +template <class ELFT> OutputSection *Writer<ELFT>::findSectionInScript(StringRef Name) { +  if (OutputSectionCommand *Cmd = findSectionCommand(Name)) +    return Cmd->Sec; +  return nullptr; +} +  template <class ELFT> OutputSection *Writer<ELFT>::findSection(StringRef Name) {    for (OutputSection *Sec : OutputSections)      if (Sec->Name == Name) @@ -1583,7 +1614,7 @@ template <class ELFT> uint64_t Writer<ELFT>::getEntryAddr() {      return Addr;    // Case 4 -  if (OutputSection *Sec = findSection(".text")) { +  if (OutputSection *Sec = findSectionInScript(".text")) {      if (Config->WarnMissingEntry)        warn("cannot find entry symbol " + Config->Entry + "; defaulting to 0x" +             utohexstr(Sec->Addr)); @@ -1609,18 +1640,6 @@ static uint16_t getELFType() {  // to each section. This function fixes some predefined  // symbol values that depend on section address and size.  template <class ELFT> void Writer<ELFT>::fixPredefinedSymbols() { -  auto Set = [](DefinedRegular *S1, DefinedRegular *S2, OutputSection *Sec, -                uint64_t Value) { -    if (S1) { -      S1->Section = Sec; -      S1->Value = Value; -    } -    if (S2) { -      S2->Section = Sec; -      S2->Value = Value; -    } -  }; -    // _etext is the first location after the last read-only loadable segment.    // _edata is the first location after the last read-write loadable segment.    // _end is the first location after the uninitialized data region. @@ -1636,15 +1655,29 @@ template <class ELFT> void Writer<ELFT>::fixPredefinedSymbols() {      else        LastRO = &P;    } -  if (Last) -    Set(ElfSym::End1, ElfSym::End2, Last->First, Last->p_memsz); -  if (LastRO) -    Set(ElfSym::Etext1, ElfSym::Etext2, LastRO->First, LastRO->p_filesz); -  if (LastRW) -    Set(ElfSym::Edata1, ElfSym::Edata2, LastRW->First, LastRW->p_filesz); + +  auto Set = [](DefinedRegular *S, OutputSection *Sec, uint64_t Value) { +    if (S) { +      S->Section = Sec; +      S->Value = Value; +    } +  }; + +  if (Last) { +    Set(ElfSym::End1, Last->First, Last->p_memsz); +    Set(ElfSym::End2, Last->First, Last->p_memsz); +  } +  if (LastRO) { +    Set(ElfSym::Etext1, LastRO->First, LastRO->p_filesz); +    Set(ElfSym::Etext2, LastRO->First, LastRO->p_filesz); +  } +  if (LastRW) { +    Set(ElfSym::Edata1, LastRW->First, LastRW->p_filesz); +    Set(ElfSym::Edata2, LastRW->First, LastRW->p_filesz); +  }    if (ElfSym::Bss) -    ElfSym::Bss->Section = findSection(".bss"); +    ElfSym::Bss->Section = findSectionInScript(".bss");    // Setup MIPS _gp_disp/__gnu_local_gp symbols which should    // be equal to the _gp symbol's value. @@ -1736,9 +1769,14 @@ template <class ELFT> void Writer<ELFT>::openFile() {  template <class ELFT> void Writer<ELFT>::writeSectionsBinary() {    uint8_t *Buf = Buffer->getBufferStart(); -  for (OutputSection *Sec : OutputSections) +  for (BaseCommand *Base : Script->Opt.Commands) { +    auto *Cmd = dyn_cast<OutputSectionCommand>(Base); +    if (!Cmd) +      continue; +    OutputSection *Sec = Cmd->Sec;      if (Sec->Flags & SHF_ALLOC) -      Sec->writeTo<ELFT>(Buf + Sec->Offset); +      Cmd->writeTo<ELFT>(Buf + Sec->Offset); +  }  }  // Write section contents to a mmap'ed file. @@ -1747,31 +1785,45 @@ template <class ELFT> void Writer<ELFT>::writeSections() {    // PPC64 needs to process relocations in the .opd section    // before processing relocations in code-containing sections. -  Out::Opd = findSection(".opd"); -  if (Out::Opd) { +  if (auto *OpdCmd = findSectionCommand(".opd")) { +    Out::Opd = OpdCmd->Sec;      Out::OpdBuf = Buf + Out::Opd->Offset; -    Out::Opd->template writeTo<ELFT>(Buf + Out::Opd->Offset); +    OpdCmd->template writeTo<ELFT>(Buf + Out::Opd->Offset);    }    OutputSection *EhFrameHdr = -      In<ELFT>::EhFrameHdr ? In<ELFT>::EhFrameHdr->OutSec : nullptr; +      (In<ELFT>::EhFrameHdr && !In<ELFT>::EhFrameHdr->empty()) +          ? In<ELFT>::EhFrameHdr->OutSec +          : nullptr;    // In -r or -emit-relocs mode, write the relocation sections first as in    // ELf_Rel targets we might find out that we need to modify the relocated    // section while doing it. -  for (OutputSection *Sec : OutputSections) +  for (BaseCommand *Base : Script->Opt.Commands) { +    auto *Cmd = dyn_cast<OutputSectionCommand>(Base); +    if (!Cmd) +      continue; +    OutputSection *Sec = Cmd->Sec;      if (Sec->Type == SHT_REL || Sec->Type == SHT_RELA) -      Sec->writeTo<ELFT>(Buf + Sec->Offset); +      Cmd->writeTo<ELFT>(Buf + Sec->Offset); +  } -  for (OutputSection *Sec : OutputSections) +  for (BaseCommand *Base : Script->Opt.Commands) { +    auto *Cmd = dyn_cast<OutputSectionCommand>(Base); +    if (!Cmd) +      continue; +    OutputSection *Sec = Cmd->Sec;      if (Sec != Out::Opd && Sec != EhFrameHdr && Sec->Type != SHT_REL &&          Sec->Type != SHT_RELA) -      Sec->writeTo<ELFT>(Buf + Sec->Offset); +      Cmd->writeTo<ELFT>(Buf + Sec->Offset); +  }    // The .eh_frame_hdr depends on .eh_frame section contents, therefore    // it should be written after .eh_frame is written. -  if (EhFrameHdr && !EhFrameHdr->Sections.empty()) -    EhFrameHdr->writeTo<ELFT>(Buf + EhFrameHdr->Offset); +  if (EhFrameHdr) { +    OutputSectionCommand *Cmd = Script->getCmd(EhFrameHdr); +    Cmd->writeTo<ELFT>(Buf + EhFrameHdr->Offset); +  }  }  template <class ELFT> void Writer<ELFT>::writeBuildId() { diff --git a/ELF/Writer.h b/ELF/Writer.h index 17fbda394a20..e935b6419de6 100644 --- a/ELF/Writer.h +++ b/ELF/Writer.h @@ -30,7 +30,7 @@ bool isRelroSection(const OutputSection *Sec);  // Each contains type, access flags and range of output sections that will be  // placed in it.  struct PhdrEntry { -  PhdrEntry(unsigned Type, unsigned Flags); +  PhdrEntry(unsigned Type, unsigned Flags) : p_type(Type), p_flags(Flags) {}    void add(OutputSection *Sec);    uint64_t p_paddr = 0; diff --git a/test/COFF/Inputs/delayimports-error.yaml b/test/COFF/Inputs/delayimports-error.yaml new file mode 100644 index 000000000000..60b395938dfd --- /dev/null +++ b/test/COFF/Inputs/delayimports-error.yaml @@ -0,0 +1,29 @@ +--- !COFF +header: +  Machine:         IMAGE_FILE_MACHINE_AMD64 +  Characteristics: [] +sections: +  - Name:            .data +    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ] +    Alignment:       4 +    SectionData:     0000000000000000 +symbols: +  - Name:            .data +    Value:           0 +    SectionNumber:   1 +    SimpleType:      IMAGE_SYM_TYPE_NULL +    ComplexType:     IMAGE_SYM_DTYPE_NULL +    StorageClass:    IMAGE_SYM_CLASS_STATIC +    SectionDefinition: +      Length:          8 +      NumberOfRelocations: 0 +      NumberOfLinenumbers: 0 +      CheckSum:        0 +      Number:          0 +  - Name:            datasym +    Value:           0 +    SectionNumber:   1 +    SimpleType:      IMAGE_SYM_TYPE_NULL +    ComplexType:     IMAGE_SYM_DTYPE_NULL +    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL +... diff --git a/test/COFF/Inputs/import.yaml b/test/COFF/Inputs/import.yaml index 493400143d6c..b7ae026de29b 100644 --- a/test/COFF/Inputs/import.yaml +++ b/test/COFF/Inputs/import.yaml @@ -7,6 +7,13 @@ sections:      Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]      Alignment:       4      SectionData:     0000000000000000 +    Relocations: +      - VirtualAddress:  0 +        SymbolName:      exportfn1 +        Type:            IMAGE_REL_AMD64_ADDR32NB +      - VirtualAddress:  4 +        SymbolName:      exportfn2 +        Type:            IMAGE_REL_AMD64_ADDR32NB  symbols:    - Name:            .text      Value:           0 @@ -16,7 +23,7 @@ symbols:      StorageClass:    IMAGE_SYM_CLASS_STATIC      SectionDefinition:        Length:          8 -      NumberOfRelocations: 0 +      NumberOfRelocations: 2        NumberOfLinenumbers: 0        CheckSum:        0        Number:          0 diff --git a/test/COFF/Inputs/oldname.yaml b/test/COFF/Inputs/oldname.yaml new file mode 100644 index 000000000000..42ee5b2269bd --- /dev/null +++ b/test/COFF/Inputs/oldname.yaml @@ -0,0 +1,26 @@ +--- !COFF +header: +  Machine:         IMAGE_FILE_MACHINE_UNKNOWN +  Characteristics: [  ] +sections: +  - Name:            .drectve +    Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ] +    Alignment:       1 +    SectionData:     '' +symbols: +  - Name:            exportfn1 +    Value:           0 +    SectionNumber:   0 +    SimpleType:      IMAGE_SYM_TYPE_NULL +    ComplexType:     IMAGE_SYM_DTYPE_NULL +    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL +  - Name:            exportfn1_alias +    Value:           0 +    SectionNumber:   0 +    SimpleType:      IMAGE_SYM_TYPE_NULL +    ComplexType:     IMAGE_SYM_DTYPE_NULL +    StorageClass:    IMAGE_SYM_CLASS_WEAK_EXTERNAL +    WeakExternal: +      TagIndex:        0 +      Characteristics: IMAGE_WEAK_EXTERN_SEARCH_ALIAS +... diff --git a/test/COFF/delayimports-error.test b/test/COFF/delayimports-error.test new file mode 100644 index 000000000000..3fea1bc099c2 --- /dev/null +++ b/test/COFF/delayimports-error.test @@ -0,0 +1,46 @@ +# RUN: mkdir -p %t.dir +# RUN: yaml2obj < %p/Inputs/delayimports-error.yaml > %t1.obj +# RUN: lld-link /out:%t.dir/foo.dll /dll %t1.obj /export:datasym,DATA /noentry + +# RUN: yaml2obj < %s > %t2.obj +# RUN: not lld-link /out:%t.exe /entry:main %t2.obj %t.dir/foo.lib /delayload:foo.dll \ +# RUN:   /alternatename:__delayLoadHelper2=main /opt:noref >& %t.log +# RUN: FileCheck %s < %t.log + +# CHECK: cannot delay-load foo.dll due to import of data: __imp_datasym + +--- !COFF +header: +  Machine:         IMAGE_FILE_MACHINE_AMD64 +  Characteristics: [] +sections: +  - Name:            .text +    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] +    Alignment:       16 +    SectionData:     0000000000000000 +symbols: +  - Name:            .text +    Value:           0 +    SectionNumber:   1 +    SimpleType:      IMAGE_SYM_TYPE_NULL +    ComplexType:     IMAGE_SYM_DTYPE_NULL +    StorageClass:    IMAGE_SYM_CLASS_STATIC +    SectionDefinition: +      Length:          8 +      NumberOfRelocations: 0 +      NumberOfLinenumbers: 0 +      CheckSum:        0 +      Number:          0 +  - Name:            main +    Value:           0 +    SectionNumber:   1 +    SimpleType:      IMAGE_SYM_TYPE_NULL +    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION +    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL +  - Name:            __imp_datasym +    Value:           0 +    SectionNumber:   0 +    SimpleType:      IMAGE_SYM_TYPE_NULL +    ComplexType:     IMAGE_SYM_DTYPE_NULL +    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL +... diff --git a/test/COFF/dllimport-gc.test b/test/COFF/dllimport-gc.test new file mode 100644 index 000000000000..54ae773e793f --- /dev/null +++ b/test/COFF/dllimport-gc.test @@ -0,0 +1,58 @@ +# REQUIRES: winres + +# RUN: yaml2obj < %p/Inputs/export.yaml > %t-lib.obj +# RUN: lld-link /out:%t.dll /dll %t-lib.obj /implib:%t.lib /export:exportfn1 + +# RUN: yaml2obj < %p/Inputs/oldname.yaml > %t-oldname.obj + +# RUN: yaml2obj < %s > %t.obj + +# RUN: lld-link /out:%t1.exe /entry:main %t.obj %t-oldname.obj %t.lib +# RUN: llvm-readobj -coff-imports %t1.exe | FileCheck -check-prefix=REF %s +# REF-NOT: Symbol: exportfn1 + +# RUN: lld-link /out:%t2.exe /entry:main %t.obj %t-oldname.obj %t.lib /opt:noref +# RUN: llvm-readobj -coff-imports %t2.exe | FileCheck -check-prefix=NOREF %s +# NOREF: Symbol: exportfn1 + +--- !COFF +header: +  Machine:         IMAGE_FILE_MACHINE_AMD64 +  Characteristics: [] +sections: +  - Name:            .text +    Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] +    Alignment:       4 +    SectionData:     0000000000000000 +symbols: +  - Name:            .text +    Value:           0 +    SectionNumber:   1 +    SimpleType:      IMAGE_SYM_TYPE_NULL +    ComplexType:     IMAGE_SYM_DTYPE_NULL +    StorageClass:    IMAGE_SYM_CLASS_STATIC +    SectionDefinition: +      Length:          8 +      NumberOfRelocations: 0 +      NumberOfLinenumbers: 0 +      CheckSum:        0 +      Number:          0 +  - Name:            main +    Value:           0 +    SectionNumber:   1 +    SimpleType:      IMAGE_SYM_TYPE_NULL +    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION +    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL +  - Name:            exportfn1 +    Value:           0 +    SectionNumber:   0 +    SimpleType:      IMAGE_SYM_TYPE_NULL +    ComplexType:     IMAGE_SYM_DTYPE_NULL +    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL +  - Name:            exportfn1_alias +    Value:           0 +    SectionNumber:   0 +    SimpleType:      IMAGE_SYM_TYPE_NULL +    ComplexType:     IMAGE_SYM_DTYPE_NULL +    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL +... diff --git a/test/ELF/Inputs/rodynamic.s b/test/ELF/Inputs/rodynamic.s new file mode 100644 index 000000000000..a06f4bef0084 --- /dev/null +++ b/test/ELF/Inputs/rodynamic.s @@ -0,0 +1,4 @@ +.global foo +.type foo, @function +foo: +  ret diff --git a/test/ELF/amdgpu-globals.s b/test/ELF/amdgpu-globals.s index f30c0ed40157..17dfc82ef8f3 100644 --- a/test/ELF/amdgpu-globals.s +++ b/test/ELF/amdgpu-globals.s @@ -41,6 +41,19 @@ program_global_readonly:  	.long	0                       ; 0x0  # CHECK: Section { +# CHECK: Name: .hsatext +# CHECK: Type: SHT_PROGBITS +# CHECK: Flags [ (0xC00007) +# CHECK: SHF_ALLOC (0x2) +# CHECK: SHF_AMDGPU_HSA_AGENT (0x800000) +# CHECK: SHF_AMDGPU_HSA_CODE (0x400000) +# CHECK: SHF_EXECINSTR (0x4) +# CHECK: SHF_WRITE (0x1) +# CHECK: ] +# CHECK: Address: [[HSATEXT_ADDR:[0-9xa-f]+]] +# CHECK: } + +# CHECK: Section {  # CHECK: Name: .hsadata_global_program  # CHECK: Type: SHT_PROGBITS (0x1)  # CHECK: Flags [ (0x100003) @@ -62,19 +75,6 @@ program_global_readonly:  # CHECK: ]  # CHECK: } -# CHECK: Section { -# CHECK: Name: .hsatext -# CHECK: Type: SHT_PROGBITS -# CHECK: Flags [ (0xC00007) -# CHECK: SHF_ALLOC (0x2) -# CHECK: SHF_AMDGPU_HSA_AGENT (0x800000) -# CHECK: SHF_AMDGPU_HSA_CODE (0x400000) -# CHECK: SHF_EXECINSTR (0x4) -# CHECK: SHF_WRITE (0x1) -# CHECK: ] -# CHECK: Address: [[HSATEXT_ADDR:[0-9xa-f]+]] -# CHECK: } -  # CHECK: Symbol {  # CHECK: Name: module_global_agent  # CHECK: Value: diff --git a/test/ELF/build-id.s b/test/ELF/build-id.s index ffd8d7744f70..2d193478df71 100644 --- a/test/ELF/build-id.s +++ b/test/ELF/build-id.s @@ -33,6 +33,10 @@  # RUN: ld.lld --build-id=md5 --build-id=none %t -o %t2  # RUN: llvm-objdump -s %t2 | FileCheck -check-prefix=NONE %s +# RUN: ld.lld --build-id --build-id=none %t -o %t2 +# RUN: llvm-objdump -s %t2 | FileCheck -check-prefix=NONE %s +# RUN: ld.lld --build-id=none --build-id %t -o %t2 +# RUN: llvm-objdump -s %t2 | FileCheck -check-prefix=DEFAULT %s  .globl _start  _start: diff --git a/test/ELF/gc-sections.s b/test/ELF/gc-sections.s index f100153ec358..0ae6fa4f06de 100644 --- a/test/ELF/gc-sections.s +++ b/test/ELF/gc-sections.s @@ -10,10 +10,10 @@  # NOGC: Name: .eh_frame  # NOGC: Name: .text -# NOGC: Name: .ctors -# NOGC: Name: .dtors  # NOGC: Name: .init  # NOGC: Name: .fini +# NOGC: Name: .ctors +# NOGC: Name: .dtors  # NOGC: Name: .debug_pubtypes  # NOGC: Name: .comment  # NOGC: Name: a @@ -25,10 +25,10 @@  # GC1:     Name: .eh_frame  # GC1:     Name: .text -# GC1:     Name: .ctors -# GC1:     Name: .dtors  # GC1:     Name: .init  # GC1:     Name: .fini +# GC1:     Name: .ctors +# GC1:     Name: .dtors  # GC1:     Name: .debug_pubtypes  # GC1:     Name: .comment  # GC1:     Name: a @@ -40,10 +40,10 @@  # GC2:     Name: .eh_frame  # GC2:     Name: .text -# GC2:     Name: .ctors -# GC2:     Name: .dtors  # GC2:     Name: .init  # GC2:     Name: .fini +# GC2:     Name: .ctors +# GC2:     Name: .dtors  # GC2:     Name: .debug_pubtypes  # GC2:     Name: .comment  # GC2:     Name: a diff --git a/test/ELF/gdb-index-dup-types.s b/test/ELF/gdb-index-dup-types.s new file mode 100644 index 000000000000..e0bed33eed4d --- /dev/null +++ b/test/ELF/gdb-index-dup-types.s @@ -0,0 +1,60 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o +# RUN: ld.lld --gdb-index %t.o -o %t +# RUN: llvm-dwarfdump -debug-dump=gdb_index %t | FileCheck %s + +## Testcase is based on output produced by gcc version 5.4.1 20160904 +## it has duplicate entries in .debug_gnu_pubtypes which seems to be +## compiler bug. In that case it is useless to have them in .gdb_index +## and we filter such entries out to reduce size of .gdb_index. + +## CHECK: Constant pool offset = {{.*}}, has 1 CU vectors: +## CHECK-NOT: 0(0x0): 0x90000000 0x90000000 + +.section .debug_abbrev,"",@progbits + .byte 1                       # Abbreviation Code + .byte 17                      # DW_TAG_compile_unit + .byte 0                       # DW_CHILDREN_no + .byte 16                      # DW_AT_stmt_list + .byte 23                      # DW_FORM_sec_offset + .ascii "\260B"                # DW_AT_GNU_dwo_name + .byte 14                      # DW_FORM_strp + .byte 27                      # DW_AT_comp_dir + .byte 14                      # DW_FORM_strp + .ascii "\264B"                # DW_AT_GNU_pubnames + .byte 25                      # DW_FORM_flag_present + .ascii "\261B"                # DW_AT_GNU_dwo_id + .byte 7                       # DW_FORM_data8 + .ascii "\263B"                # DW_AT_GNU_addr_base + .byte 23                      # DW_FORM_sec_offset + .byte 0                       # EOM(1) + .byte 0                       # EOM(2) + .byte 0                       # EOM(3) + +.section .debug_info,"",@progbits +.Lcu_begin0: + .long 32                       # Length of Unit + .short 4                       # DWARF version number + .long .debug_abbrev            # Offset Into Abbrev. Section + .byte 8                        # Address Size (in bytes) + .byte 1                        # Abbrev [1] 0xb:0x19 DW_TAG_compile_unit + .long 0                        # DW_AT_stmt_list + .long 0                        # DW_AT_GNU_dwo_name + .long 0                        # DW_AT_comp_dir + .quad 0                        # DW_AT_GNU_dwo_id + .long 0                        # DW_AT_GNU_addr_base + +.section .debug_gnu_pubtypes,"",@progbits +.long .LpubTypes_end0-.LpubTypes_begin0 # Length of Public Types Info +.LpubTypes_begin0: + .short 2                      # DWARF Version + .long .Lcu_begin0             # Offset of Compilation Unit Info + .long 36                      # Compilation Unit Length + .long 36                      # DIE offset + .byte 144                     # Kind: TYPE, STATIC + .asciz "int"                  # External Name + .long 36                      # DIE offset + .byte 144                     # Kind: TYPE, STATIC + .asciz "int"                  # External Name + .long 0                       # End Mark +.LpubTypes_end0: diff --git a/test/ELF/i386-tls-ie-shared.s b/test/ELF/i386-tls-ie-shared.s index 8becc3199f95..f419eb45dfb9 100644 --- a/test/ELF/i386-tls-ie-shared.s +++ b/test/ELF/i386-tls-ie-shared.s @@ -13,8 +13,8 @@  // GOTRELSHARED-NEXT:     SHF_ALLOC  // GOTRELSHARED-NEXT:     SHF_WRITE  // GOTRELSHARED-NEXT:   ] -// GOTRELSHARED-NEXT:   Address: 0x1058 -// GOTRELSHARED-NEXT:   Offset: 0x1058 +// GOTRELSHARED-NEXT:   Address: 0x2058 +// GOTRELSHARED-NEXT:   Offset: 0x2058  // GOTRELSHARED-NEXT:   Size: 16  // GOTRELSHARED-NEXT:   Link: 0  // GOTRELSHARED-NEXT:   Info: 0 @@ -23,44 +23,44 @@  // GOTRELSHARED-NEXT: }  // GOTRELSHARED:      Relocations [  // GOTRELSHARED-NEXT:   Section ({{.*}}) .rel.dyn { -// GOTRELSHARED-NEXT:     0x2002 R_386_RELATIVE - 0x0 -// GOTRELSHARED-NEXT:     0x200A R_386_RELATIVE - 0x0 -// GOTRELSHARED-NEXT:     0x2013 R_386_RELATIVE - 0x0 -// GOTRELSHARED-NEXT:     0x201C R_386_RELATIVE - 0x0 -// GOTRELSHARED-NEXT:     0x2024 R_386_RELATIVE - 0x0 -// GOTRELSHARED-NEXT:     0x202D R_386_RELATIVE - 0x0 -// GOTRELSHARED-NEXT:     0x2036 R_386_RELATIVE - 0x0 -// GOTRELSHARED-NEXT:     0x203F R_386_RELATIVE - 0x0 -// GOTRELSHARED-NEXT:     0x1058 R_386_TLS_TPOFF tlslocal0 0x0 -// GOTRELSHARED-NEXT:     0x105C R_386_TLS_TPOFF tlslocal1 0x0 -// GOTRELSHARED-NEXT:     0x1060 R_386_TLS_TPOFF tlsshared0 0x0 -// GOTRELSHARED-NEXT:     0x1064 R_386_TLS_TPOFF tlsshared1 0x0 +// GOTRELSHARED-NEXT:     0x1002 R_386_RELATIVE - 0x0 +// GOTRELSHARED-NEXT:     0x100A R_386_RELATIVE - 0x0 +// GOTRELSHARED-NEXT:     0x1013 R_386_RELATIVE - 0x0 +// GOTRELSHARED-NEXT:     0x101C R_386_RELATIVE - 0x0 +// GOTRELSHARED-NEXT:     0x1024 R_386_RELATIVE - 0x0 +// GOTRELSHARED-NEXT:     0x102D R_386_RELATIVE - 0x0 +// GOTRELSHARED-NEXT:     0x1036 R_386_RELATIVE - 0x0 +// GOTRELSHARED-NEXT:     0x103F R_386_RELATIVE - 0x0 +// GOTRELSHARED-NEXT:     0x2058 R_386_TLS_TPOFF tlslocal0 0x0 +// GOTRELSHARED-NEXT:     0x205C R_386_TLS_TPOFF tlslocal1 0x0 +// GOTRELSHARED-NEXT:     0x2060 R_386_TLS_TPOFF tlsshared0 0x0 +// GOTRELSHARED-NEXT:     0x2064 R_386_TLS_TPOFF tlsshared1 0x0  // GOTRELSHARED-NEXT:   }  // GOTRELSHARED-NEXT: ]  // GOTRELSHARED:      0x6FFFFFFA RELCOUNT             8  // DISASMSHARED:       Disassembly of section test:  // DISASMSHARED-NEXT:  _start: -// (.got)[0] = 0x2050 = 8272 -// (.got)[1] = 0x2054 = 8276 -// (.got)[2] = 0x2058 = 8280 -// (.got)[3] = 0x205C = 8284 -// DISASMSHARED-NEXT:  2000: 8b 0d 58 10 00 00   movl  4184, %ecx -// DISASMSHARED-NEXT:  2006: 65 8b 01  movl  %gs:(%ecx), %eax -// DISASMSHARED-NEXT:  2009: a1 58 10 00 00  movl  4184, %eax -// DISASMSHARED-NEXT:  200e: 65 8b 00  movl  %gs:(%eax), %eax -// DISASMSHARED-NEXT:  2011: 03 0d 58 10 00 00   addl  4184, %ecx -// DISASMSHARED-NEXT:  2017: 65 8b 01  movl  %gs:(%ecx), %eax -// DISASMSHARED-NEXT:  201a: 8b 0d 5c 10 00 00   movl  4188, %ecx -// DISASMSHARED-NEXT:  2020: 65 8b 01  movl  %gs:(%ecx), %eax -// DISASMSHARED-NEXT:  2023: a1 5c 10 00 00  movl  4188, %eax -// DISASMSHARED-NEXT:  2028: 65 8b 00  movl  %gs:(%eax), %eax -// DISASMSHARED-NEXT:  202b: 03 0d 5c 10 00 00   addl  4188, %ecx -// DISASMSHARED-NEXT:  2031: 65 8b 01  movl  %gs:(%ecx), %eax -// DISASMSHARED-NEXT:  2034: 8b 0d 60 10 00 00   movl  4192, %ecx -// DISASMSHARED-NEXT:  203a: 65 8b 01  movl  %gs:(%ecx), %eax -// DISASMSHARED-NEXT:  203d: 03 0d 64 10 00 00   addl  4196, %ecx -// DISASMSHARED-NEXT:  2043: 65 8b 01  movl  %gs:(%ecx), %eax +// (.got)[0] = 0x2058 = 8280 +// (.got)[1] = 0x205C = 8284 +// (.got)[2] = 0x2060 = 8288 +// (.got)[3] = 0x2064 = 8292 +// DISASMSHARED-NEXT:  1000: 8b 0d 58 20 00 00   movl  8280, %ecx +// DISASMSHARED-NEXT:  1006: 65 8b 01  movl  %gs:(%ecx), %eax +// DISASMSHARED-NEXT:  1009: a1 58 20 00 00  movl  8280, %eax +// DISASMSHARED-NEXT:  100e: 65 8b 00  movl  %gs:(%eax), %eax +// DISASMSHARED-NEXT:  1011: 03 0d 58 20 00 00   addl  8280, %ecx +// DISASMSHARED-NEXT:  1017: 65 8b 01  movl  %gs:(%ecx), %eax +// DISASMSHARED-NEXT:  101a: 8b 0d 5c 20 00 00   movl  8284, %ecx +// DISASMSHARED-NEXT:  1020: 65 8b 01  movl  %gs:(%ecx), %eax +// DISASMSHARED-NEXT:  1023: a1 5c 20 00 00  movl  8284, %eax +// DISASMSHARED-NEXT:  1028: 65 8b 00  movl  %gs:(%eax), %eax +// DISASMSHARED-NEXT:  102b: 03 0d 5c 20 00 00   addl  8284, %ecx +// DISASMSHARED-NEXT:  1031: 65 8b 01  movl  %gs:(%ecx), %eax +// DISASMSHARED-NEXT:  1034: 8b 0d 60 20 00 00   movl  8288, %ecx +// DISASMSHARED-NEXT:  103a: 65 8b 01  movl  %gs:(%ecx), %eax +// DISASMSHARED-NEXT:  103d: 03 0d 64 20 00 00   addl  8292, %ecx +// DISASMSHARED-NEXT:  1043: 65 8b 01  movl  %gs:(%ecx), %eax  .type tlslocal0,@object  .section .tbss,"awT",@nobits diff --git a/test/ELF/linkerscript/arm-lscript.s b/test/ELF/linkerscript/arm-lscript.s new file mode 100644 index 000000000000..c377764e9776 --- /dev/null +++ b/test/ELF/linkerscript/arm-lscript.s @@ -0,0 +1,9 @@ +// REQUIRES: arm +// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t.o +// RUN: echo  "SECTIONS { \ +// RUN:         .rel.dyn : {    } \ +// RUN:         .zed     : { PROVIDE_HIDDEN (foobar = .); } \ +// RUN:         }" > %t.script +// This is a test case for PR33029. Making sure that linker can digest +// the above script without dumping core. +// RUN: ld.lld -emit-relocs -T %t.script %t.o -shared -o %t.so diff --git a/test/ELF/linkerscript/sections-constraint.s b/test/ELF/linkerscript/sections-constraint.s index 796240627170..4d95ec18336c 100644 --- a/test/ELF/linkerscript/sections-constraint.s +++ b/test/ELF/linkerscript/sections-constraint.s @@ -24,8 +24,8 @@  # NO1-NEXT: 0               00000000  # NO1:  .writable     00000004  # NO1:  .foo.2        00000004 -# NO1:  .foo.1        00000004  # NO1:  .readable     00000004 +# NO1:  .foo.1        00000004  .global _start  _start: diff --git a/test/ELF/lto/Inputs/relocation-model-pic.ll b/test/ELF/lto/Inputs/relocation-model-pic.ll new file mode 100644 index 000000000000..e76605435e87 --- /dev/null +++ b/test/ELF/lto/Inputs/relocation-model-pic.ll @@ -0,0 +1,11 @@ +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +@foo = external global i32 +define i32 @main() { +  %t = load i32, i32* @foo +  ret i32 %t +} + +!llvm.module.flags = !{!0} +!0 = !{i32 1, !"PIC Level", i32 2} diff --git a/test/ELF/lto/relocation-model.ll b/test/ELF/lto/relocation-model.ll new file mode 100644 index 000000000000..78334dd5cd2c --- /dev/null +++ b/test/ELF/lto/relocation-model.ll @@ -0,0 +1,46 @@ +; REQUIRES: x86 + +; RUN: llvm-as %s -o %t.o +; RUN: llvm-as %p/Inputs/relocation-model-pic.ll -o %t.pic.o + +;; Non-PIC source. + +; RUN: ld.lld %t.o -o %t-out -save-temps -shared +; RUN: llvm-readobj -r %t-out.lto.o | FileCheck %s --check-prefix=PIC + +; RUN: ld.lld %t.o -o %t-out -save-temps --export-dynamic --noinhibit-exec -pie +; RUN: llvm-readobj -r %t-out.lto.o | FileCheck %s --check-prefix=PIC + +; RUN: ld.lld %t.o -o %t-out -save-temps --export-dynamic --noinhibit-exec +; RUN: llvm-readobj -r %t-out.lto.o | FileCheck %s --check-prefix=STATIC + +; RUN: ld.lld %t.o -o %t-out -save-temps -r --export-dynamic +; RUN: llvm-readobj -r %t-out.lto.o | FileCheck %s --check-prefix=STATIC + + +;; PIC source. + +; RUN: ld.lld %t.pic.o -o %t-out -save-temps -shared +; RUN: llvm-readobj -r %t-out.lto.o | FileCheck %s --check-prefix=PIC + +; RUN: ld.lld %t.pic.o -o %t-out -save-temps --export-dynamic --noinhibit-exec -pie +; RUN: llvm-readobj -r %t-out.lto.o | FileCheck %s --check-prefix=PIC + +; RUN: ld.lld %t.pic.o -o %t-out -save-temps --export-dynamic --noinhibit-exec +; RUN: llvm-readobj -r %t-out.lto.o | FileCheck %s --check-prefix=STATIC + +; RUN: ld.lld %t.pic.o -o %t-out -save-temps -r --export-dynamic +; RUN: llvm-readobj -r %t-out.lto.o | FileCheck %s --check-prefix=PIC + + +; PIC: R_X86_64_REX_GOTPCRELX foo +; STATIC: R_X86_64_PC32 foo + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +@foo = external global i32 +define i32 @main() { +  %t = load i32, i32* @foo +  ret i32 %t +} diff --git a/test/ELF/relocatable-comdat.s b/test/ELF/relocatable-comdat.s new file mode 100644 index 000000000000..24504d23884f --- /dev/null +++ b/test/ELF/relocatable-comdat.s @@ -0,0 +1,45 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +# RUN: ld.lld -r %t.o %t.o -o %t +# RUN: llvm-readobj -elf-section-groups -sections %t | FileCheck %s + +# CHECK:        Name: .text.bar +# CHECK-NEXT:   Type: SHT_PROGBITS +# CHECK-NEXT:   Flags [ +# CHECK-NEXT:     SHF_ALLOC +# CHECK-NEXT:     SHF_EXECINSTR +# CHECK-NEXT:     SHF_GROUP +# CHECK-NEXT:   ] +# CHECK-NEXT:   Address: +# CHECK-NEXT:   Offset: +# CHECK-NEXT:   Size: 8 +# CHECK:      Section { +# CHECK-NEXT:   Index: 4 +# CHECK-NEXT:   Name: .text.foo +# CHECK-NEXT:   Type: SHT_PROGBITS +# CHECK-NEXT:   Flags [ +# CHECK-NEXT:     SHF_ALLOC +# CHECK-NEXT:     SHF_EXECINSTR +# CHECK-NEXT:     SHF_GROUP +# CHECK-NEXT:   ] +# CHECK-NEXT:   Address: +# CHECK-NEXT:   Offset: +# CHECK-NEXT:   Size: 4 + +# CHECK:       Groups { +# CHECK-NEXT:    Group { +# CHECK-NEXT:      Name: .group +# CHECK-NEXT:      Index: 2 +# CHECK-NEXT:      Type: COMDAT +# CHECK-NEXT:      Signature: abc +# CHECK-NEXT:      Section(s) in group [ +# CHECK-NEXT:        .text.bar +# CHECK-NEXT:        .text.foo +# CHECK-NEXT:      ] +# CHECK-NEXT:    } +# CHECK-NEXT:  } + +.section .text.bar,"axG",@progbits,abc,comdat +.quad 42 +.section .text.foo,"axG",@progbits,abc,comdat +.long 42 diff --git a/test/ELF/relocation-size-shared.s b/test/ELF/relocation-size-shared.s index 7b700ad74401..cea9e64d58ed 100644 --- a/test/ELF/relocation-size-shared.s +++ b/test/ELF/relocation-size-shared.s @@ -7,48 +7,48 @@  // RELOCSHARED:       Relocations [  // RELOCSHARED-NEXT:  Section ({{.*}}) .rela.dyn { -// RELOCSHARED-NEXT:    0x203018 R_X86_64_SIZE64 fooshared 0xFFFFFFFFFFFFFFFF -// RELOCSHARED-NEXT:    0x203020 R_X86_64_SIZE64 fooshared 0x0 -// RELOCSHARED-NEXT:    0x203028 R_X86_64_SIZE64 fooshared 0x1 -// RELOCSHARED-NEXT:    0x203048 R_X86_64_SIZE32 fooshared 0xFFFFFFFFFFFFFFFF -// RELOCSHARED-NEXT:    0x20304F R_X86_64_SIZE32 fooshared 0x0 -// RELOCSHARED-NEXT:    0x203056 R_X86_64_SIZE32 fooshared 0x1 +// RELOCSHARED-NEXT:    0x201018 R_X86_64_SIZE64 fooshared 0xFFFFFFFFFFFFFFFF +// RELOCSHARED-NEXT:    0x201020 R_X86_64_SIZE64 fooshared 0x0 +// RELOCSHARED-NEXT:    0x201028 R_X86_64_SIZE64 fooshared 0x1 +// RELOCSHARED-NEXT:    0x201048 R_X86_64_SIZE32 fooshared 0xFFFFFFFFFFFFFFFF +// RELOCSHARED-NEXT:    0x20104F R_X86_64_SIZE32 fooshared 0x0 +// RELOCSHARED-NEXT:    0x201056 R_X86_64_SIZE32 fooshared 0x1  // RELOCSHARED-NEXT:  }  // RELOCSHARED-NEXT:]  // DISASM:      Disassembly of section test  // DISASM:      _data: -// DISASM-NEXT: 203000: 19 00 -// DISASM-NEXT: 203002: 00 00 -// DISASM-NEXT: 203004: 00 00 -// DISASM-NEXT: 203006: 00 00 -// DISASM-NEXT: 203008: 1a 00 -// DISASM-NEXT: 20300a: 00 00 -// DISASM-NEXT: 20300c: 00 00 -// DISASM-NEXT: 20300e: 00 00 -// DISASM-NEXT: 203010: 1b 00 -// DISASM-NEXT: 203012: 00 00 -// DISASM-NEXT: 203014: 00 00 -// DISASM-NEXT: 203016: 00 00 -// DISASM-NEXT: 203018: 00 00 -// DISASM-NEXT: 20301a: 00 00 -// DISASM-NEXT: 20301c: 00 00 -// DISASM-NEXT: 20301e: 00 00 -// DISASM-NEXT: 203020: 00 00 -// DISASM-NEXT: 203022: 00 00 -// DISASM-NEXT: 203024: 00 00 -// DISASM-NEXT: 203026: 00 00 -// DISASM-NEXT: 203028: 00 00 -// DISASM-NEXT: 20302a: 00 00 -// DISASM-NEXT: 20302c: 00 00 -// DISASM-NEXT: 20302e: 00 00 +// DISASM-NEXT: 201000: 19 00 +// DISASM-NEXT: 201002: 00 00 +// DISASM-NEXT: 201004: 00 00 +// DISASM-NEXT: 201006: 00 00 +// DISASM-NEXT: 201008: 1a 00 +// DISASM-NEXT: 20100a: 00 00 +// DISASM-NEXT: 20100c: 00 00 +// DISASM-NEXT: 20100e: 00 00 +// DISASM-NEXT: 201010: 1b 00 +// DISASM-NEXT: 201012: 00 00 +// DISASM-NEXT: 201014: 00 00 +// DISASM-NEXT: 201016: 00 00 +// DISASM-NEXT: 201018: 00 00 +// DISASM-NEXT: 20101a: 00 00 +// DISASM-NEXT: 20101c: 00 00 +// DISASM-NEXT: 20101e: 00 00 +// DISASM-NEXT: 201020: 00 00 +// DISASM-NEXT: 201022: 00 00 +// DISASM-NEXT: 201024: 00 00 +// DISASM-NEXT: 201026: 00 00 +// DISASM-NEXT: 201028: 00 00 +// DISASM-NEXT: 20102a: 00 00 +// DISASM-NEXT: 20102c: 00 00 +// DISASM-NEXT: 20102e: 00 00  // DISASM:      _start: -// DISASM-NEXT: 203030: 8b 04 25 19 00 00 00 movl 25, %eax -// DISASM-NEXT: 203037: 8b 04 25 1a 00 00 00 movl 26, %eax -// DISASM-NEXT: 20303e: 8b 04 25 1b 00 00 00 movl 27, %eax -// DISASM-NEXT: 203045: 8b 04 25 00 00 00 00 movl 0, %eax -// DISASM-NEXT: 20304c: 8b 04 25 00 00 00 00 movl 0, %eax -// DISASM-NEXT: 203053: 8b 04 25 00 00 00 00 movl 0, %eax +// DISASM-NEXT: 201030: 8b 04 25 19 00 00 00 movl 25, %eax +// DISASM-NEXT: 201037: 8b 04 25 1a 00 00 00 movl 26, %eax +// DISASM-NEXT: 20103e: 8b 04 25 1b 00 00 00 movl 27, %eax +// DISASM-NEXT: 201045: 8b 04 25 00 00 00 00 movl 0, %eax +// DISASM-NEXT: 20104c: 8b 04 25 00 00 00 00 movl 0, %eax +// DISASM-NEXT: 201053: 8b 04 25 00 00 00 00 movl 0, %eax  .data  .global foo diff --git a/test/ELF/relocation-size.s b/test/ELF/relocation-size.s index 2256be67df06..419b8a17fad9 100644 --- a/test/ELF/relocation-size.s +++ b/test/ELF/relocation-size.s @@ -11,82 +11,82 @@  // DISASM:      Disassembly of section test:  // DISASM-NEXT: _data: -// DISASM-NEXT: 202000: 19 00 -// DISASM-NEXT: 202002: 00 00 -// DISASM-NEXT: 202004: 00 00 -// DISASM-NEXT: 202006: 00 00 -// DISASM-NEXT: 202008: 1a 00 -// DISASM-NEXT: 20200a: 00 00 -// DISASM-NEXT: 20200c: 00 00 -// DISASM-NEXT: 20200e: 00 00 -// DISASM-NEXT: 202010: 1b 00 -// DISASM-NEXT: 202012: 00 00 -// DISASM-NEXT: 202014: 00 00 -// DISASM-NEXT: 202016: 00 00 -// DISASM-NEXT: 202018: 19 00 -// DISASM-NEXT: 20201a: 00 00 -// DISASM-NEXT: 20201c: 00 00 -// DISASM-NEXT: 20201e: 00 00 -// DISASM-NEXT: 202020: 1a 00 -// DISASM-NEXT: 202022: 00 00 -// DISASM-NEXT: 202024: 00 00 -// DISASM-NEXT: 202026: 00 00 -// DISASM-NEXT: 202028: 1b 00 -// DISASM-NEXT: 20202a: 00 00 -// DISASM-NEXT: 20202c: 00 00 -// DISASM-NEXT: 20202e: 00 00 +// DISASM-NEXT: 201000: 19 00 +// DISASM-NEXT: 201002: 00 00 +// DISASM-NEXT: 201004: 00 00 +// DISASM-NEXT: 201006: 00 00 +// DISASM-NEXT: 201008: 1a 00 +// DISASM-NEXT: 20100a: 00 00 +// DISASM-NEXT: 20100c: 00 00 +// DISASM-NEXT: 20100e: 00 00 +// DISASM-NEXT: 201010: 1b 00 +// DISASM-NEXT: 201012: 00 00 +// DISASM-NEXT: 201014: 00 00 +// DISASM-NEXT: 201016: 00 00 +// DISASM-NEXT: 201018: 19 00 +// DISASM-NEXT: 20101a: 00 00 +// DISASM-NEXT: 20101c: 00 00 +// DISASM-NEXT: 20101e: 00 00 +// DISASM-NEXT: 201020: 1a 00 +// DISASM-NEXT: 201022: 00 00 +// DISASM-NEXT: 201024: 00 00 +// DISASM-NEXT: 201026: 00 00 +// DISASM-NEXT: 201028: 1b 00 +// DISASM-NEXT: 20102a: 00 00 +// DISASM-NEXT: 20102c: 00 00 +// DISASM-NEXT: 20102e: 00 00  // DISASM:      _start: -// DISASM-NEXT: 202030: 8b 04 25 19 00 00 00 movl 25, %eax -// DISASM-NEXT: 202037: 8b 04 25 1a 00 00 00 movl 26, %eax -// DISASM-NEXT: 20203e: 8b 04 25 1b 00 00 00 movl 27, %eax -// DISASM-NEXT: 202045: 8b 04 25 19 00 00 00 movl 25, %eax -// DISASM-NEXT: 20204c: 8b 04 25 1a 00 00 00 movl 26, %eax -// DISASM-NEXT: 202053: 8b 04 25 1b 00 00 00 movl 27, %eax +// DISASM-NEXT: 201030: 8b 04 25 19 00 00 00 movl 25, %eax +// DISASM-NEXT: 201037: 8b 04 25 1a 00 00 00 movl 26, %eax +// DISASM-NEXT: 20103e: 8b 04 25 1b 00 00 00 movl 27, %eax +// DISASM-NEXT: 201045: 8b 04 25 19 00 00 00 movl 25, %eax +// DISASM-NEXT: 20104c: 8b 04 25 1a 00 00 00 movl 26, %eax +// DISASM-NEXT: 201053: 8b 04 25 1b 00 00 00 movl 27, %eax  // RELOCSHARED:      Relocations [  // RELOCSHARED-NEXT: Section ({{.*}}) .rela.dyn { -// RELOCSHARED-NEXT:    0x3000 R_X86_64_SIZE64 foo 0xFFFFFFFFFFFFFFFF -// RELOCSHARED-NEXT:    0x3008 R_X86_64_SIZE64 foo 0x0 -// RELOCSHARED-NEXT:    0x3010 R_X86_64_SIZE64 foo 0x1 -// RELOCSHARED-NEXT:    0x3033 R_X86_64_SIZE32 foo 0xFFFFFFFFFFFFFFFF -// RELOCSHARED-NEXT:    0x303A R_X86_64_SIZE32 foo 0x0 -// RELOCSHARED-NEXT:    0x3041 R_X86_64_SIZE32 foo 0x1 +// RELOCSHARED-NEXT:    0x1000 R_X86_64_SIZE64 foo 0xFFFFFFFFFFFFFFFF +// RELOCSHARED-NEXT:    0x1008 R_X86_64_SIZE64 foo 0x0 +// RELOCSHARED-NEXT:    0x1010 R_X86_64_SIZE64 foo 0x1 +// RELOCSHARED-NEXT:    0x1033 R_X86_64_SIZE32 foo 0xFFFFFFFFFFFFFFFF +// RELOCSHARED-NEXT:    0x103A R_X86_64_SIZE32 foo 0x0 +// RELOCSHARED-NEXT:    0x1041 R_X86_64_SIZE32 foo 0x1  // RELOCSHARED-NEXT:  }  // RELOCSHARED-NEXT: ]  // DISASMSHARED:      Disassembly of section test:  // DISASMSHARED-NEXT: _data: -// DISASMSHARED-NEXT: 3000: 00 00 -// DISASMSHARED-NEXT: 3002: 00 00 -// DISASMSHARED-NEXT: 3004: 00 00 -// DISASMSHARED-NEXT: 3006: 00 00 -// DISASMSHARED-NEXT: 3008: 00 00 -// DISASMSHARED-NEXT: 300a: 00 00 -// DISASMSHARED-NEXT: 300c: 00 00 -// DISASMSHARED-NEXT: 300e: 00 00 -// DISASMSHARED-NEXT: 3010: 00 00 -// DISASMSHARED-NEXT: 3012: 00 00 -// DISASMSHARED-NEXT: 3014: 00 00 -// DISASMSHARED-NEXT: 3016: 00 00 -// DISASMSHARED-NEXT: 3018: 19 00 -// DISASMSHARED-NEXT: 301a: 00 00 -// DISASMSHARED-NEXT: 301c: 00 00 -// DISASMSHARED-NEXT: 301e: 00 00 -// DISASMSHARED-NEXT: 3020: 1a 00 -// DISASMSHARED-NEXT: 3022: 00 00 -// DISASMSHARED-NEXT: 3024: 00 00 -// DISASMSHARED-NEXT: 3026: 00 00 -// DISASMSHARED-NEXT: 3028: 1b 00 -// DISASMSHARED-NEXT: 302a: 00 00 -// DISASMSHARED-NEXT: 302c: 00 00 -// DISASMSHARED-NEXT: 302e: 00 00 +// DISASMSHARED-NEXT: 1000: 00 00 +// DISASMSHARED-NEXT: 1002: 00 00 +// DISASMSHARED-NEXT: 1004: 00 00 +// DISASMSHARED-NEXT: 1006: 00 00 +// DISASMSHARED-NEXT: 1008: 00 00 +// DISASMSHARED-NEXT: 100a: 00 00 +// DISASMSHARED-NEXT: 100c: 00 00 +// DISASMSHARED-NEXT: 100e: 00 00 +// DISASMSHARED-NEXT: 1010: 00 00 +// DISASMSHARED-NEXT: 1012: 00 00 +// DISASMSHARED-NEXT: 1014: 00 00 +// DISASMSHARED-NEXT: 1016: 00 00 +// DISASMSHARED-NEXT: 1018: 19 00 +// DISASMSHARED-NEXT: 101a: 00 00 +// DISASMSHARED-NEXT: 101c: 00 00 +// DISASMSHARED-NEXT: 101e: 00 00 +// DISASMSHARED-NEXT: 1020: 1a 00 +// DISASMSHARED-NEXT: 1022: 00 00 +// DISASMSHARED-NEXT: 1024: 00 00 +// DISASMSHARED-NEXT: 1026: 00 00 +// DISASMSHARED-NEXT: 1028: 1b 00 +// DISASMSHARED-NEXT: 102a: 00 00 +// DISASMSHARED-NEXT: 102c: 00 00 +// DISASMSHARED-NEXT: 102e: 00 00  // DISASMSHARED:      _start: -// DISASMSHARED-NEXT: 3030: 8b 04 25 00 00 00 00 movl 0, %eax -// DISASMSHARED-NEXT: 3037: 8b 04 25 00 00 00 00 movl 0, %eax -// DISASMSHARED-NEXT: 303e: 8b 04 25 00 00 00 00 movl 0, %eax -// DISASMSHARED-NEXT: 3045: 8b 04 25 19 00 00 00 movl 25, %eax -// DISASMSHARED-NEXT: 304c: 8b 04 25 1a 00 00 00 movl 26, %eax -// DISASMSHARED-NEXT: 3053: 8b 04 25 1b 00 00 00 movl 27, %eax +// DISASMSHARED-NEXT: 1030: 8b 04 25 00 00 00 00 movl 0, %eax +// DISASMSHARED-NEXT: 1037: 8b 04 25 00 00 00 00 movl 0, %eax +// DISASMSHARED-NEXT: 103e: 8b 04 25 00 00 00 00 movl 0, %eax +// DISASMSHARED-NEXT: 1045: 8b 04 25 19 00 00 00 movl 25, %eax +// DISASMSHARED-NEXT: 104c: 8b 04 25 1a 00 00 00 movl 26, %eax +// DISASMSHARED-NEXT: 1053: 8b 04 25 1b 00 00 00 movl 27, %eax  .data  .global foo diff --git a/test/ELF/reproduce.s b/test/ELF/reproduce.s index 94823d6d377f..0a93be08d040 100644 --- a/test/ELF/reproduce.s +++ b/test/ELF/reproduce.s @@ -63,7 +63,7 @@  ## Check that directory path is stripped from -o <file-path>  # RUN: mkdir -p %t.dir/build3/a/b/c  # RUN: cd %t.dir -# RUN: ld.lld build1/foo.o -o build3/a/b/c/bar -shared --as-needed --reproduce repro3.tar +# RUN: ld.lld build1/foo.o -o build3/a/b/c/bar -shared --as-needed --reproduce=repro3.tar  # RUN: tar xf repro3.tar  # RUN: FileCheck %s --check-prefix=RSP3 < repro3/response.txt  # RSP3: -o bar diff --git a/test/ELF/rodynamic.s b/test/ELF/rodynamic.s new file mode 100644 index 000000000000..441e5c395e7c --- /dev/null +++ b/test/ELF/rodynamic.s @@ -0,0 +1,35 @@ +# RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux +# RUN: llvm-mc %p/Inputs/rodynamic.s -o %t.so.o -filetype=obj -triple=x86_64-pc-linux + +# RUN: ld.lld -shared %t.so.o -o %t.so +# RUN: ld.lld %t.o %t.so -o %t.exe +# RUN: llvm-readobj -dynamic-table %t.exe | FileCheck -check-prefix=DEFDEBUG %s +# RUN: llvm-readobj -sections %t.exe | FileCheck -check-prefix=DEFSEC %s + +# RUN: ld.lld -shared -z rodynamic %t.so.o -o %t.so +# RUN: ld.lld -z rodynamic %t.o %t.so -o %t.exe +# RUN: llvm-readobj -dynamic-table %t.exe | FileCheck -check-prefix=RODEBUG %s +# RUN: llvm-readobj -sections %t.exe | FileCheck -check-prefix=ROSEC %s + +.globl _start +_start: +  call foo + +# DEFDEBUG: DEBUG + +# DEFSEC:      Section { +# DEFSEC:        Name: .dynamic +# DEFSEC-NEXT:   Type: SHT_DYNAMIC +# DEFSEC-NEXT:   Flags [ +# DEFSEC-NEXT:     SHF_ALLOC +# DEFSEC-NEXT:     SHF_WRITE +# DEFSEC-NEXT:   ] + +# RODEBUG-NOT: DEBUG + +# ROSEC:      Section { +# ROSEC:        Name: .dynamic +# ROSEC-NEXT:   Type: SHT_DYNAMIC +# ROSEC-NEXT:   Flags [ +# ROSEC-NEXT:     SHF_ALLOC +# ROSEC-NEXT:   ] diff --git a/test/ELF/section-layout.s b/test/ELF/section-layout.s index f63066e0d926..7febec85a629 100644 --- a/test/ELF/section-layout.s +++ b/test/ELF/section-layout.s @@ -34,6 +34,11 @@ _start:  // CHECK: Name: c  // CHECK: Name: d +// Sections that are both writable and executable appear before +// sections that are only writable. +// CHECK: Name: k +// CHECK: Name: l +  // Writable sections appear before TLS and other relro sections.  // CHECK: Name: i @@ -42,8 +47,6 @@ _start:  // CHECK: Name: g  // CHECK: Name: j -// CHECK: Name: k -// CHECK: Name: l  // Non allocated sections are in input order.  // CHECK: Name: t diff --git a/test/ELF/tls-i686.s b/test/ELF/tls-i686.s index 2a04a555865a..7f2dd605cacd 100644 --- a/test/ELF/tls-i686.s +++ b/test/ELF/tls-i686.s @@ -32,38 +32,38 @@ _start:  // DIS:      Disassembly of section test:  // DIS-NEXT: _start: -// DIS-NEXT: 12000: ba 08 00 00 00       movl $8, %edx -// DIS-NEXT: 12005: 65 8b 0d 00 00 00 00 movl %gs:0, %ecx -// DIS-NEXT: 1200c: 29 d0                subl %edx, %eax -// DIS-NEXT: 1200e: ba 04 00 00 00       movl $4, %edx -// DIS-NEXT: 12013: 65 8b 0d 00 00 00 00 movl %gs:0, %ecx -// DIS-NEXT: 1201a: 29 d0                subl %edx, %eax -// DIS-NEXT: 1201c: 65 8b 0d 00 00 00 00 movl %gs:0, %ecx -// DIS-NEXT: 12023: 8d 81 f8 ff ff ff    leal -8(%ecx), %eax -// DIS-NEXT: 12029: 65 8b 0d 00 00 00 00 movl %gs:0, %ecx -// DIS-NEXT: 12030: 8d 81 77 00 00 00    leal 119(%ecx), %eax +// DIS-NEXT: 11000: ba 08 00 00 00       movl $8, %edx +// DIS-NEXT: 11005: 65 8b 0d 00 00 00 00 movl %gs:0, %ecx +// DIS-NEXT: 1100c: 29 d0                subl %edx, %eax +// DIS-NEXT: 1100e: ba 04 00 00 00       movl $4, %edx +// DIS-NEXT: 11013: 65 8b 0d 00 00 00 00 movl %gs:0, %ecx +// DIS-NEXT: 1101a: 29 d0                subl %edx, %eax +// DIS-NEXT: 1101c: 65 8b 0d 00 00 00 00 movl %gs:0, %ecx +// DIS-NEXT: 11023: 8d 81 f8 ff ff ff    leal -8(%ecx), %eax +// DIS-NEXT: 11029: 65 8b 0d 00 00 00 00 movl %gs:0, %ecx +// DIS-NEXT: 11030: 8d 81 77 00 00 00    leal 119(%ecx), %eax  // RELOC: Relocations [  // RELOC-NEXT: ]  // DISSHARED: Disassembly of section test:  // DISSHARED-NEXT: _start: -// DISSHARED-NEXT: 2000: ba 00 00 00 00 movl   $0, %edx -// DISSHARED-NEXT: 2005: 65 8b 0d 00 00 00 00  movl %gs:0, %ecx -// DISSHARED-NEXT: 200c: 29 d0 subl            %edx, %eax -// DISSHARED-NEXT: 200e: ba 00 00 00 00        movl $0, %edx -// DISSHARED-NEXT: 2013: 65 8b 0d 00 00 00 00  movl %gs:0, %ecx -// DISSHARED-NEXT: 201a: 29 d0 subl            %edx, %eax -// DISSHARED-NEXT: 201c: 65 8b 0d 00 00 00 00  movl %gs:0, %ecx -// DISSHARED-NEXT: 2023: 8d 81 00 00 00 00     leal (%ecx), %eax -// DISSHARED-NEXT: 2029: 65 8b 0d 00 00 00 00  movl %gs:0, %ecx -// DISSHARED-NEXT: 2030: 8d 81 7b 00 00 00     leal 123(%ecx), %eax +// DISSHARED-NEXT: 1000: ba 00 00 00 00 movl   $0, %edx +// DISSHARED-NEXT: 1005: 65 8b 0d 00 00 00 00  movl %gs:0, %ecx +// DISSHARED-NEXT: 100c: 29 d0 subl            %edx, %eax +// DISSHARED-NEXT: 100e: ba 00 00 00 00        movl $0, %edx +// DISSHARED-NEXT: 1013: 65 8b 0d 00 00 00 00  movl %gs:0, %ecx +// DISSHARED-NEXT: 101a: 29 d0 subl            %edx, %eax +// DISSHARED-NEXT: 101c: 65 8b 0d 00 00 00 00  movl %gs:0, %ecx +// DISSHARED-NEXT: 1023: 8d 81 00 00 00 00     leal (%ecx), %eax +// DISSHARED-NEXT: 1029: 65 8b 0d 00 00 00 00  movl %gs:0, %ecx +// DISSHARED-NEXT: 1030: 8d 81 7b 00 00 00     leal 123(%ecx), %eax  // RELOCSHARED:      Relocations [  // RELOCSHARED-NEXT: Section (4) .rel.dyn { -// RELOCSHARED-NEXT:   0x2001 R_386_TLS_TPOFF32 var 0x0 -// RELOCSHARED-NEXT:   0x2025 R_386_TLS_TPOFF var 0x0 -// RELOCSHARED-NEXT:   0x200F R_386_TLS_TPOFF32 var1 0x0 -// RELOCSHARED-NEXT:   0x2032 R_386_TLS_TPOFF var1 0x0 +// RELOCSHARED-NEXT:   0x1001 R_386_TLS_TPOFF32 var 0x0 +// RELOCSHARED-NEXT:   0x1025 R_386_TLS_TPOFF var 0x0 +// RELOCSHARED-NEXT:   0x100F R_386_TLS_TPOFF32 var1 0x0 +// RELOCSHARED-NEXT:   0x1032 R_386_TLS_TPOFF var1 0x0  // RELOCSHARED-NEXT:  }  // RELOCSHARED-NEXT: ] | 
