Index: vendor/lld/dist/COFF/PDB.cpp =================================================================== --- vendor/lld/dist/COFF/PDB.cpp (revision 317766) +++ vendor/lld/dist/COFF/PDB.cpp (revision 317767) @@ -1,230 +1,230 @@ //===- PDB.cpp ------------------------------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "PDB.h" #include "Chunks.h" #include "Config.h" #include "Error.h" #include "SymbolTable.h" #include "Symbols.h" #include "llvm/DebugInfo/CodeView/CVDebugRecord.h" #include "llvm/DebugInfo/CodeView/CVTypeDumper.h" #include "llvm/DebugInfo/CodeView/SymbolDumper.h" #include "llvm/DebugInfo/CodeView/TypeDatabase.h" #include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h" #include "llvm/DebugInfo/CodeView/TypeStreamMerger.h" #include "llvm/DebugInfo/CodeView/TypeTableBuilder.h" #include "llvm/DebugInfo/MSF/MSFBuilder.h" #include "llvm/DebugInfo/MSF/MSFCommon.h" #include "llvm/DebugInfo/PDB/Native/DbiStream.h" #include "llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h" #include "llvm/DebugInfo/PDB/Native/InfoStream.h" #include "llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h" #include "llvm/DebugInfo/PDB/Native/PDBFile.h" #include "llvm/DebugInfo/PDB/Native/PDBFileBuilder.h" +#include "llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h" #include "llvm/DebugInfo/PDB/Native/PDBTypeServerHandler.h" -#include "llvm/DebugInfo/PDB/Native/StringTableBuilder.h" #include "llvm/DebugInfo/PDB/Native/TpiStream.h" #include "llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h" #include "llvm/Object/COFF.h" #include "llvm/Support/BinaryByteStream.h" #include "llvm/Support/Endian.h" #include "llvm/Support/FileOutputBuffer.h" #include "llvm/Support/Path.h" #include "llvm/Support/ScopedPrinter.h" #include using namespace lld; using namespace lld::coff; using namespace llvm; using namespace llvm::codeview; using namespace llvm::support; using namespace llvm::support::endian; using llvm::object::coff_section; static ExitOnError ExitOnErr; // Returns a list of all SectionChunks. static std::vector getInputSections(SymbolTable *Symtab) { std::vector V; for (Chunk *C : Symtab->getChunks()) if (auto *SC = dyn_cast(C)) V.push_back(*SC->Header); return V; } static SectionChunk *findByName(std::vector &Sections, StringRef Name) { for (SectionChunk *C : Sections) if (C->getSectionName() == Name) return C; return nullptr; } static ArrayRef getDebugSection(ObjectFile *File, StringRef SecName) { SectionChunk *Sec = findByName(File->getDebugChunks(), SecName); if (!Sec) return {}; // First 4 bytes are section magic. ArrayRef Data = Sec->getContents(); if (Data.size() < 4) fatal(SecName + " too short"); if (read32le(Data.data()) != COFF::DEBUG_SECTION_MAGIC) fatal(SecName + " has an invalid magic"); return Data.slice(4); } static void addTypeInfo(pdb::TpiStreamBuilder &TpiBuilder, codeview::TypeTableBuilder &TypeTable) { // Start the TPI or IPI stream header. TpiBuilder.setVersionHeader(pdb::PdbTpiV80); // Flatten the in memory type table. TypeTable.ForEachRecord([&](TypeIndex TI, ArrayRef Rec) { // FIXME: Hash types. TpiBuilder.addTypeRecord(Rec, None); }); } // Merge .debug$T sections into IpiData and TpiData. static void mergeDebugT(SymbolTable *Symtab, pdb::PDBFileBuilder &Builder, codeview::TypeTableBuilder &TypeTable, codeview::TypeTableBuilder &IDTable) { // Visit all .debug$T sections to add them to Builder. for (ObjectFile *File : Symtab->ObjectFiles) { ArrayRef Data = getDebugSection(File, ".debug$T"); if (Data.empty()) continue; BinaryByteStream Stream(Data, support::little); codeview::CVTypeArray Types; BinaryStreamReader Reader(Stream); // 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, &Handler, Types)) fatal(Err, "codeview::mergeTypeStreams failed"); } // Construct TPI stream contents. addTypeInfo(Builder.getTpiBuilder(), TypeTable); // Construct IPI stream contents. addTypeInfo(Builder.getIpiBuilder(), IDTable); } static void dumpDebugT(ScopedPrinter &W, ObjectFile *File) { ListScope LS(W, "DebugT"); ArrayRef Data = getDebugSection(File, ".debug$T"); if (Data.empty()) return; TypeDatabase TDB; TypeDumpVisitor TDV(TDB, &W, false); // Use a default implementation that does not follow type servers and instead // just dumps the contents of the TypeServer2 record. CVTypeDumper TypeDumper(TDB); if (auto EC = TypeDumper.dump(Data, TDV)) fatal(EC, "CVTypeDumper::dump failed"); } static void dumpDebugS(ScopedPrinter &W, ObjectFile *File) { ListScope LS(W, "DebugS"); ArrayRef Data = getDebugSection(File, ".debug$S"); if (Data.empty()) return; BinaryByteStream Stream(Data, llvm::support::little); CVSymbolArray Symbols; BinaryStreamReader Reader(Stream); if (auto EC = Reader.readArray(Symbols, Reader.getLength())) fatal(EC, "StreamReader.readArray failed"); TypeDatabase TDB; CVSymbolDumper SymbolDumper(W, TDB, nullptr, false); if (auto EC = SymbolDumper.dump(Symbols)) fatal(EC, "CVSymbolDumper::dump failed"); } // Dump CodeView debug info. This is for debugging. static void dumpCodeView(SymbolTable *Symtab) { ScopedPrinter W(outs()); for (ObjectFile *File : Symtab->ObjectFiles) { dumpDebugT(W, File); dumpDebugS(W, File); } } // Creates a PDB file. void coff::createPDB(StringRef Path, SymbolTable *Symtab, ArrayRef SectionTable, const llvm::codeview::DebugInfo *DI) { if (Config->DumpPdb) dumpCodeView(Symtab); BumpPtrAllocator Alloc; pdb::PDBFileBuilder Builder(Alloc); ExitOnErr(Builder.initialize(4096)); // 4096 is blocksize // Create streams in MSF for predefined streams, namely // PDB, TPI, DBI and IPI. for (int I = 0; I < (int)pdb::kSpecialStreamCount; ++I) ExitOnErr(Builder.getMsfBuilder().addStream(0)); // Add an Info stream. auto &InfoBuilder = Builder.getInfoBuilder(); InfoBuilder.setAge(DI ? DI->PDB70.Age : 0); pdb::PDB_UniqueId uuid{}; if (DI) memcpy(&uuid, &DI->PDB70.Signature, sizeof(uuid)); InfoBuilder.setGuid(uuid); // Should be the current time, but set 0 for reproducibilty. InfoBuilder.setSignature(0); InfoBuilder.setVersion(pdb::PdbRaw_ImplVer::PdbImplVC70); // Add an empty DPI stream. auto &DbiBuilder = Builder.getDbiBuilder(); DbiBuilder.setVersionHeader(pdb::PdbDbiV110); codeview::TypeTableBuilder TypeTable(BAlloc); codeview::TypeTableBuilder IDTable(BAlloc); mergeDebugT(Symtab, Builder, TypeTable, IDTable); // Add Section Contributions. std::vector Contribs = pdb::DbiStreamBuilder::createSectionContribs(getInputSections(Symtab)); DbiBuilder.setSectionContribs(Contribs); // Add Section Map stream. ArrayRef Sections = { (const object::coff_section *)SectionTable.data(), SectionTable.size() / sizeof(object::coff_section)}; std::vector SectionMap = pdb::DbiStreamBuilder::createSectionMap(Sections); DbiBuilder.setSectionMap(SectionMap); ExitOnErr(DbiBuilder.addModuleInfo("* Linker *")); // Add COFF section header stream. ExitOnErr( DbiBuilder.addDbgStream(pdb::DbgHeaderType::SectionHdr, SectionTable)); // Write to a file. ExitOnErr(Builder.commit(Path)); } Index: vendor/lld/dist/ELF/Driver.h =================================================================== --- vendor/lld/dist/ELF/Driver.h (revision 317766) +++ vendor/lld/dist/ELF/Driver.h (revision 317767) @@ -1,77 +1,75 @@ //===- Driver.h -------------------------------------------------*- C++ -*-===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #ifndef LLD_ELF_DRIVER_H #define LLD_ELF_DRIVER_H #include "SymbolTable.h" #include "lld/Core/LLVM.h" #include "lld/Core/Reproduce.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSet.h" #include "llvm/Option/ArgList.h" #include "llvm/Support/raw_ostream.h" namespace lld { namespace elf { extern class LinkerDriver *Driver; class LinkerDriver { public: void main(ArrayRef Args, bool CanExitEarly); void addFile(StringRef Path, bool WithLOption); void addLibrary(StringRef Name); private: void readConfigs(llvm::opt::InputArgList &Args); void createFiles(llvm::opt::InputArgList &Args); void inferMachineType(); template void link(llvm::opt::InputArgList &Args); // True if we are in --whole-archive and --no-whole-archive. bool InWholeArchive = false; // True if we are in --start-lib and --end-lib. bool InLib = false; // True if we are in -format=binary and -format=elf. bool InBinary = false; std::vector Files; }; // Parses command line options. class ELFOptTable : public llvm::opt::OptTable { public: ELFOptTable(); llvm::opt::InputArgList parse(ArrayRef Argv); }; // Create enum with OPT_xxx values for each option in Options.td enum { OPT_INVALID = 0, #define OPTION(_1, _2, ID, _4, _5, _6, _7, _8, _9, _10, _11) OPT_##ID, #include "Options.inc" #undef OPTION }; void printHelp(const char *Argv0); -std::vector parseHexstring(StringRef S); - std::string createResponseFile(const llvm::opt::InputArgList &Args); llvm::Optional findFromSearchPaths(StringRef Path); llvm::Optional searchLibrary(StringRef Path); } // namespace elf } // namespace lld #endif Index: vendor/lld/dist/ELF/InputFiles.cpp =================================================================== --- vendor/lld/dist/ELF/InputFiles.cpp (revision 317766) +++ vendor/lld/dist/ELF/InputFiles.cpp (revision 317767) @@ -1,1076 +1,1076 @@ //===- InputFiles.cpp -----------------------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "InputFiles.h" #include "Error.h" #include "InputSection.h" #include "LinkerScript.h" #include "Memory.h" #include "SymbolTable.h" #include "Symbols.h" #include "SyntheticSections.h" #include "llvm/ADT/STLExtras.h" #include "llvm/CodeGen/Analysis.h" #include "llvm/DebugInfo/DWARF/DWARFContext.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" #include "llvm/LTO/LTO.h" #include "llvm/MC/StringTableBuilder.h" #include "llvm/Object/ELFObjectFile.h" #include "llvm/Support/Path.h" #include "llvm/Support/TarWriter.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; using namespace llvm::ELF; using namespace llvm::object; using namespace llvm::sys::fs; using namespace lld; using namespace lld::elf; TarWriter *elf::Tar; InputFile::InputFile(Kind K, MemoryBufferRef M) : MB(M), FileKind(K) {} namespace { // In ELF object file all section addresses are zero. If we have multiple // .text sections (when using -ffunction-section or comdat group) then // LLVM DWARF parser will not be able to parse .debug_line correctly, unless // we assign each section some unique address. This callback method assigns // each section an address equal to its offset in ELF object file. class ObjectInfo : public LoadedObjectInfo { public: uint64_t getSectionLoadAddress(const object::SectionRef &Sec) const override { return static_cast(Sec).getOffset(); } std::unique_ptr clone() const override { return std::unique_ptr(); } }; } Optional elf::readFile(StringRef Path) { log(Path); auto MBOrErr = MemoryBuffer::getFile(Path); if (auto EC = MBOrErr.getError()) { error("cannot open " + Path + ": " + EC.message()); return None; } std::unique_ptr &MB = *MBOrErr; MemoryBufferRef MBRef = MB->getMemBufferRef(); make>(std::move(MB)); // take MB ownership if (Tar) Tar->append(relativeToRoot(Path), MBRef.getBuffer()); return MBRef; } template void elf::ObjectFile::initializeDwarfLine() { std::unique_ptr Obj = check(object::ObjectFile::createObjectFile(this->MB), toString(this)); ObjectInfo ObjInfo; DWARFContextInMemory Dwarf(*Obj, &ObjInfo); DwarfLine.reset(new DWARFDebugLine(&Dwarf.getLineSection().Relocs)); DataExtractor LineData(Dwarf.getLineSection().Data, Config->IsLE, Config->Wordsize); // The second parameter is offset in .debug_line section // for compilation unit (CU) of interest. We have only one // CU (object file), so offset is always 0. DwarfLine->getOrParseLineTable(LineData, 0); } // Returns source line information for a given offset // using DWARF debug info. template Optional elf::ObjectFile::getDILineInfo(InputSectionBase *S, uint64_t Offset) { if (!DwarfLine) initializeDwarfLine(); // The offset to CU is 0. const DWARFDebugLine::LineTable *Tbl = DwarfLine->getLineTable(0); if (!Tbl) return None; // Use fake address calcuated by adding section file offset and offset in // section. See comments for ObjectInfo class. DILineInfo Info; Tbl->getFileLineInfoForAddress( S->getOffsetInFile() + Offset, nullptr, DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, Info); if (Info.Line == 0) return None; return Info; } // Returns source line information for a given offset // using DWARF debug info. template std::string elf::ObjectFile::getLineInfo(InputSectionBase *S, uint64_t Offset) { if (Optional Info = getDILineInfo(S, Offset)) return Info->FileName + ":" + std::to_string(Info->Line); return ""; } // Returns "", "foo.a(bar.o)" or "baz.o". std::string lld::toString(const InputFile *F) { if (!F) return ""; if (F->ToStringCache.empty()) { if (F->ArchiveName.empty()) F->ToStringCache = F->getName(); else F->ToStringCache = (F->ArchiveName + "(" + F->getName() + ")").str(); } return F->ToStringCache; } template ELFFileBase::ELFFileBase(Kind K, MemoryBufferRef MB) : InputFile(K, MB) { if (ELFT::TargetEndianness == support::little) EKind = ELFT::Is64Bits ? ELF64LEKind : ELF32LEKind; else EKind = ELFT::Is64Bits ? ELF64BEKind : ELF32BEKind; EMachine = getObj().getHeader()->e_machine; OSABI = getObj().getHeader()->e_ident[llvm::ELF::EI_OSABI]; } template typename ELFT::SymRange ELFFileBase::getGlobalSymbols() { return makeArrayRef(Symbols.begin() + FirstNonLocal, Symbols.end()); } template uint32_t ELFFileBase::getSectionIndex(const Elf_Sym &Sym) const { return check(getObj().getSectionIndex(&Sym, Symbols, SymtabSHNDX), toString(this)); } template void ELFFileBase::initSymtab(ArrayRef Sections, const Elf_Shdr *Symtab) { FirstNonLocal = Symtab->sh_info; Symbols = check(getObj().symbols(Symtab), toString(this)); if (FirstNonLocal == 0 || FirstNonLocal > Symbols.size()) fatal(toString(this) + ": invalid sh_info in symbol table"); StringTable = check(getObj().getStringTableForSymtab(*Symtab, Sections), toString(this)); } template elf::ObjectFile::ObjectFile(MemoryBufferRef M, StringRef ArchiveName) : ELFFileBase(Base::ObjectKind, M) { this->ArchiveName = ArchiveName; } template ArrayRef elf::ObjectFile::getLocalSymbols() { if (this->SymbolBodies.empty()) return this->SymbolBodies; return makeArrayRef(this->SymbolBodies).slice(1, this->FirstNonLocal - 1); } template ArrayRef elf::ObjectFile::getSymbols() { if (this->SymbolBodies.empty()) return this->SymbolBodies; return makeArrayRef(this->SymbolBodies).slice(1); } template void elf::ObjectFile::parse(DenseSet &ComdatGroups) { // Read section and symbol tables. initializeSections(ComdatGroups); initializeSymbols(); } // Sections with SHT_GROUP and comdat bits define comdat section groups. // They are identified and deduplicated by group name. This function // returns a group name. template StringRef elf::ObjectFile::getShtGroupSignature(ArrayRef Sections, const Elf_Shdr &Sec) { if (this->Symbols.empty()) this->initSymtab( Sections, check(object::getSection(Sections, Sec.sh_link), toString(this))); const Elf_Sym *Sym = check( object::getSymbol(this->Symbols, Sec.sh_info), toString(this)); return check(Sym->getName(this->StringTable), toString(this)); } template ArrayRef::Elf_Word> elf::ObjectFile::getShtGroupEntries(const Elf_Shdr &Sec) { const ELFFile &Obj = this->getObj(); ArrayRef Entries = check( Obj.template getSectionContentsAsArray(&Sec), toString(this)); if (Entries.empty() || Entries[0] != GRP_COMDAT) fatal(toString(this) + ": unsupported SHT_GROUP format"); return Entries.slice(1); } template bool elf::ObjectFile::shouldMerge(const Elf_Shdr &Sec) { // We don't merge sections if -O0 (default is -O1). This makes sometimes // the linker significantly faster, although the output will be bigger. if (Config->Optimize == 0) return false; // Do not merge sections if generating a relocatable object. It makes // the code simpler because we do not need to update relocation addends // to reflect changes introduced by merging. Instead of that we write // such "merge" sections into separate OutputSections and keep SHF_MERGE // / SHF_STRINGS flags and sh_entsize value to be able to perform merging // later during a final linking. if (Config->Relocatable) return false; // A mergeable section with size 0 is useless because they don't have // any data to merge. A mergeable string section with size 0 can be // argued as invalid because it doesn't end with a null character. // We'll avoid a mess by handling them as if they were non-mergeable. if (Sec.sh_size == 0) return false; // Check for sh_entsize. The ELF spec is not clear about the zero // sh_entsize. It says that "the member [sh_entsize] contains 0 if // the section does not hold a table of fixed-size entries". We know // that Rust 1.13 produces a string mergeable section with a zero // sh_entsize. Here we just accept it rather than being picky about it. uint64_t EntSize = Sec.sh_entsize; if (EntSize == 0) return false; if (Sec.sh_size % EntSize) fatal(toString(this) + ": SHF_MERGE section size must be a multiple of sh_entsize"); uint64_t Flags = Sec.sh_flags; if (!(Flags & SHF_MERGE)) return false; if (Flags & SHF_WRITE) fatal(toString(this) + ": writable SHF_MERGE section is not supported"); // Don't try to merge if the alignment is larger than the sh_entsize and this // is not SHF_STRINGS. // // Since this is not a SHF_STRINGS, we would need to pad after every entity. // It would be equivalent for the producer of the .o to just set a larger // sh_entsize. if (Flags & SHF_STRINGS) return true; return Sec.sh_addralign <= EntSize; } template void elf::ObjectFile::initializeSections( DenseSet &ComdatGroups) { ArrayRef ObjSections = check(this->getObj().sections(), toString(this)); const ELFFile &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; if (this->Sections[I] == &InputSection::Discarded) continue; // SHF_EXCLUDE'ed sections are discarded by the linker. However, // if -r is given, we'll let the final link discard such sections. // This is compatible with GNU. if ((Sec.sh_flags & SHF_EXCLUDE) && !Config->Relocatable) { this->Sections[I] = &InputSection::Discarded; continue; } switch (Sec.sh_type) { case SHT_GROUP: this->Sections[I] = &InputSection::Discarded; if (ComdatGroups .insert( CachedHashStringRef(getShtGroupSignature(ObjSections, Sec))) .second) continue; for (uint32_t SecIndex : getShtGroupEntries(Sec)) { if (SecIndex >= Size) fatal(toString(this) + ": invalid section index in group: " + Twine(SecIndex)); this->Sections[SecIndex] = &InputSection::Discarded; } break; case SHT_SYMTAB: this->initSymtab(ObjSections, &Sec); break; case SHT_SYMTAB_SHNDX: this->SymtabSHNDX = check(Obj.getSHNDXTable(Sec, ObjSections), toString(this)); break; case SHT_STRTAB: case SHT_NULL: break; default: this->Sections[I] = createInputSection(Sec, SectionStringTable); } // .ARM.exidx sections have a reverse dependency on the InputSection they // have a SHF_LINK_ORDER dependency, this is identified by the sh_link. if (Sec.sh_flags & SHF_LINK_ORDER) { if (Sec.sh_link >= this->Sections.size()) fatal(toString(this) + ": invalid sh_link index: " + Twine(Sec.sh_link)); this->Sections[Sec.sh_link]->DependentSections.push_back( this->Sections[I]); } } } template InputSectionBase *elf::ObjectFile::getRelocTarget(const Elf_Shdr &Sec) { uint32_t Idx = Sec.sh_info; if (Idx >= this->Sections.size()) fatal(toString(this) + ": invalid relocated section index: " + Twine(Idx)); InputSectionBase *Target = this->Sections[Idx]; // Strictly speaking, a relocation section must be included in the // group of the section it relocates. However, LLVM 3.3 and earlier // would fail to do so, so we gracefully handle that case. if (Target == &InputSection::Discarded) return nullptr; if (!Target) fatal(toString(this) + ": unsupported relocation reference"); return Target; } // Create a regular InputSection class that has the same contents // as a given section. InputSectionBase *toRegularSection(MergeInputSection *Sec) { auto *Ret = make(Sec->Flags, Sec->Type, Sec->Alignment, Sec->Data, Sec->Name); Ret->File = Sec->File; return Ret; } template InputSectionBase * elf::ObjectFile::createInputSection(const Elf_Shdr &Sec, StringRef SectionStringTable) { StringRef Name = check( this->getObj().getSectionName(&Sec, SectionStringTable), toString(this)); switch (Sec.sh_type) { case SHT_ARM_ATTRIBUTES: // FIXME: ARM meta-data section. Retain the first attribute section // we see. The eglibc ARM dynamic loaders require the presence of an // attribute section for dlopen to work. // In a full implementation we would merge all attribute sections. if (In::ARMAttributes == nullptr) { In::ARMAttributes = make(this, &Sec, Name); return In::ARMAttributes; } return &InputSection::Discarded; case SHT_RELA: case SHT_REL: { // Find the relocation target section and associate this // section with it. Target can be discarded, for example // if it is a duplicated member of SHT_GROUP section, we // do not create or proccess relocatable sections then. InputSectionBase *Target = getRelocTarget(Sec); if (!Target) return nullptr; // This section contains relocation information. // If -r is given, we do not interpret or apply relocation // but just copy relocation sections to output. if (Config->Relocatable) return make(this, &Sec, Name); if (Target->FirstRelocation) fatal(toString(this) + ": multiple relocation sections to one section are not supported"); // Mergeable sections with relocations are tricky because relocations // need to be taken into account when comparing section contents for - // merging. It doesn't worth supporting such mergeable sections because + // merging. It's not worth supporting such mergeable sections because // they are rare and it'd complicates the internal design (we usually // have to determine if two sections are mergeable early in the link // process much before applying relocations). We simply handle mergeable // sections with relocations as non-mergeable. if (auto *MS = dyn_cast(Target)) { Target = toRegularSection(MS); this->Sections[Sec.sh_info] = Target; } size_t NumRelocations; if (Sec.sh_type == SHT_RELA) { ArrayRef Rels = check(this->getObj().relas(&Sec), toString(this)); Target->FirstRelocation = Rels.begin(); NumRelocations = Rels.size(); Target->AreRelocsRela = true; } else { ArrayRef Rels = check(this->getObj().rels(&Sec), toString(this)); Target->FirstRelocation = Rels.begin(); NumRelocations = Rels.size(); Target->AreRelocsRela = false; } assert(isUInt<31>(NumRelocations)); Target->NumRelocations = NumRelocations; // Relocation sections processed by the linker are usually removed // from the output, so returning `nullptr` for the normal case. // However, if -emit-relocs is given, we need to leave them in the output. // (Some post link analysis tools need this information.) if (Config->EmitRelocs) { InputSection *RelocSec = make(this, &Sec, Name); // We will not emit relocation section if target was discarded. Target->DependentSections.push_back(RelocSec); return RelocSec; } return nullptr; } } // The GNU linker uses .note.GNU-stack section as a marker indicating // that the code in the object file does not expect that the stack is // executable (in terms of NX bit). If all input files have the marker, // the GNU linker adds a PT_GNU_STACK segment to tells the loader to // make the stack non-executable. Most object files have this section as // of 2017. // // But making the stack non-executable is a norm today for security // reasons. Failure to do so may result in a serious security issue. // Therefore, we make LLD always add PT_GNU_STACK unless it is // explicitly told to do otherwise (by -z execstack). Because the stack // executable-ness is controlled solely by command line options, // .note.GNU-stack sections are simply ignored. if (Name == ".note.GNU-stack") return &InputSection::Discarded; // Split stacks is a feature to support a discontiguous stack. At least // as of 2017, it seems that the feature is not being used widely. // Only GNU gold supports that. We don't. For the details about that, // see https://gcc.gnu.org/wiki/SplitStacks if (Name == ".note.GNU-split-stack") { error(toString(this) + ": object file compiled with -fsplit-stack is not supported"); return &InputSection::Discarded; } if (Config->Strip != StripPolicy::None && Name.startswith(".debug")) return &InputSection::Discarded; // If -gdb-index is given, LLD creates .gdb_index section, and that // section serves the same purpose as .debug_gnu_pub{names,types} sections. // If that's the case, we want to eliminate .debug_gnu_pub{names,types} // because they are redundant and can waste large amount of disk space // (for example, they are about 400 MiB in total for a clang debug build.) if (Config->GdbIndex && (Name == ".debug_gnu_pubnames" || Name == ".debug_gnu_pubtypes")) return &InputSection::Discarded; // The linkonce feature is a sort of proto-comdat. Some glibc i386 object // files contain definitions of symbol "__x86.get_pc_thunk.bx" in linkonce // sections. Drop those sections to avoid duplicate symbol errors. // FIXME: This is glibc PR20543, we should remove this hack once that has been // fixed for a while. if (Name.startswith(".gnu.linkonce.")) return &InputSection::Discarded; // The linker merges EH (exception handling) frames and creates a // .eh_frame_hdr section for runtime. So we handle them with a special // class. For relocatable outputs, they are just passed through. if (Name == ".eh_frame" && !Config->Relocatable) return make(this, &Sec, Name); if (shouldMerge(Sec)) return make(this, &Sec, Name); return make(this, &Sec, Name); } template void elf::ObjectFile::initializeSymbols() { SymbolBodies.reserve(this->Symbols.size()); for (const Elf_Sym &Sym : this->Symbols) SymbolBodies.push_back(createSymbolBody(&Sym)); } template InputSectionBase *elf::ObjectFile::getSection(const Elf_Sym &Sym) const { uint32_t Index = this->getSectionIndex(Sym); if (Index >= this->Sections.size()) fatal(toString(this) + ": invalid section index: " + Twine(Index)); InputSectionBase *S = this->Sections[Index]; // We found that GNU assembler 2.17.50 [FreeBSD] 2007-07-03 could // generate broken objects. STT_SECTION/STT_NOTYPE symbols can be // associated with SHT_REL[A]/SHT_SYMTAB/SHT_STRTAB sections. // In this case it is fine for section to be null here as we do not // allocate sections of these types. if (!S) { if (Index == 0 || Sym.getType() == STT_SECTION || Sym.getType() == STT_NOTYPE) return nullptr; fatal(toString(this) + ": invalid section index: " + Twine(Index)); } if (S == &InputSection::Discarded) return S; return S->Repl; } template SymbolBody *elf::ObjectFile::createSymbolBody(const Elf_Sym *Sym) { int Binding = Sym->getBinding(); InputSectionBase *Sec = getSection(*Sym); uint8_t StOther = Sym->st_other; uint8_t Type = Sym->getType(); uint64_t Value = Sym->st_value; uint64_t Size = Sym->st_size; if (Binding == STB_LOCAL) { if (Sym->getType() == STT_FILE) SourceFile = check(Sym->getName(this->StringTable), toString(this)); if (this->StringTable.size() <= Sym->st_name) fatal(toString(this) + ": invalid symbol name offset"); StringRefZ Name = this->StringTable.data() + Sym->st_name; if (Sym->st_shndx == SHN_UNDEF) return make(Name, /*IsLocal=*/true, StOther, Type, this); return make(Name, /*IsLocal=*/true, StOther, Type, Value, Size, Sec, this); } StringRef Name = check(Sym->getName(this->StringTable), toString(this)); switch (Sym->st_shndx) { case SHN_UNDEF: return elf::Symtab::X ->addUndefined(Name, /*IsLocal=*/false, Binding, StOther, Type, /*CanOmitFromDynSym=*/false, this) ->body(); case SHN_COMMON: if (Value == 0 || Value >= UINT32_MAX) fatal(toString(this) + ": common symbol '" + Name + "' has invalid alignment: " + Twine(Value)); return elf::Symtab::X ->addCommon(Name, Size, Value, Binding, StOther, Type, this) ->body(); } switch (Binding) { default: fatal(toString(this) + ": unexpected binding: " + Twine(Binding)); case STB_GLOBAL: case STB_WEAK: case STB_GNU_UNIQUE: if (Sec == &InputSection::Discarded) return elf::Symtab::X ->addUndefined(Name, /*IsLocal=*/false, Binding, StOther, Type, /*CanOmitFromDynSym=*/false, this) ->body(); return elf::Symtab::X ->addRegular(Name, StOther, Type, Value, Size, Binding, Sec, this) ->body(); } } template void ArchiveFile::parse() { File = check(Archive::create(MB), MB.getBufferIdentifier() + ": failed to parse archive"); // Read the symbol table to construct Lazy objects. for (const Archive::Symbol &Sym : File->symbols()) { Symtab::X->addLazyArchive(this, Sym); } if (File->symbols().begin() == File->symbols().end()) Config->ArchiveWithoutSymbolsSeen = true; } // Returns a buffer pointing to a member file containing a given symbol. std::pair ArchiveFile::getMember(const Archive::Symbol *Sym) { Archive::Child C = check(Sym->getMember(), toString(this) + ": could not get the member for symbol " + Sym->getName()); if (!Seen.insert(C.getChildOffset()).second) return {MemoryBufferRef(), 0}; MemoryBufferRef Ret = check(C.getMemoryBufferRef(), toString(this) + ": could not get the buffer for the member defining symbol " + Sym->getName()); if (C.getParent()->isThin() && Tar) Tar->append(relativeToRoot(check(C.getFullName(), toString(this))), Ret.getBuffer()); if (C.getParent()->isThin()) return {Ret, 0}; return {Ret, C.getChildOffset()}; } template SharedFile::SharedFile(MemoryBufferRef M, StringRef DefaultSoName) : ELFFileBase(Base::SharedKind, M), SoName(DefaultSoName), AsNeeded(Config->AsNeeded) {} template const typename ELFT::Shdr * SharedFile::getSection(const Elf_Sym &Sym) const { return check( this->getObj().getSection(&Sym, this->Symbols, this->SymtabSHNDX), toString(this)); } // Partially parse the shared object file so that we can call // getSoName on this object. template void SharedFile::parseSoName() { const Elf_Shdr *DynamicSec = nullptr; const ELFFile Obj = this->getObj(); ArrayRef Sections = check(Obj.sections(), toString(this)); // Search for .dynsym, .dynamic, .symtab, .gnu.version and .gnu.version_d. for (const Elf_Shdr &Sec : Sections) { switch (Sec.sh_type) { default: continue; case SHT_DYNSYM: this->initSymtab(Sections, &Sec); break; case SHT_DYNAMIC: DynamicSec = &Sec; break; case SHT_SYMTAB_SHNDX: this->SymtabSHNDX = check(Obj.getSHNDXTable(Sec, Sections), toString(this)); break; case SHT_GNU_versym: this->VersymSec = &Sec; break; case SHT_GNU_verdef: this->VerdefSec = &Sec; break; } } if (this->VersymSec && this->Symbols.empty()) error("SHT_GNU_versym should be associated with symbol table"); // Search for a DT_SONAME tag to initialize this->SoName. if (!DynamicSec) return; ArrayRef Arr = check(Obj.template getSectionContentsAsArray(DynamicSec), toString(this)); for (const Elf_Dyn &Dyn : Arr) { if (Dyn.d_tag == DT_SONAME) { uint64_t Val = Dyn.getVal(); if (Val >= this->StringTable.size()) fatal(toString(this) + ": invalid DT_SONAME entry"); SoName = this->StringTable.data() + Val; return; } } } // Parse the version definitions in the object file if present. Returns a vector // whose nth element contains a pointer to the Elf_Verdef for version identifier // n. Version identifiers that are not definitions map to nullptr. The array // always has at least length 1. template std::vector SharedFile::parseVerdefs(const Elf_Versym *&Versym) { std::vector Verdefs(1); // We only need to process symbol versions for this DSO if it has both a // versym and a verdef section, which indicates that the DSO contains symbol // version definitions. if (!VersymSec || !VerdefSec) return Verdefs; // The location of the first global versym entry. const char *Base = this->MB.getBuffer().data(); Versym = reinterpret_cast(Base + VersymSec->sh_offset) + this->FirstNonLocal; // We cannot determine the largest verdef identifier without inspecting // every Elf_Verdef, but both bfd and gold assign verdef identifiers // sequentially starting from 1, so we predict that the largest identifier // will be VerdefCount. unsigned VerdefCount = VerdefSec->sh_info; Verdefs.resize(VerdefCount + 1); // Build the Verdefs array by following the chain of Elf_Verdef objects // from the start of the .gnu.version_d section. const char *Verdef = Base + VerdefSec->sh_offset; for (unsigned I = 0; I != VerdefCount; ++I) { auto *CurVerdef = reinterpret_cast(Verdef); Verdef += CurVerdef->vd_next; unsigned VerdefIndex = CurVerdef->vd_ndx; if (Verdefs.size() <= VerdefIndex) Verdefs.resize(VerdefIndex + 1); Verdefs[VerdefIndex] = CurVerdef; } return Verdefs; } // Fully parse the shared object file. This must be called after parseSoName(). template void SharedFile::parseRest() { // Create mapping from version identifiers to Elf_Verdef entries. const Elf_Versym *Versym = nullptr; std::vector Verdefs = parseVerdefs(Versym); Elf_Sym_Range Syms = this->getGlobalSymbols(); for (const Elf_Sym &Sym : Syms) { unsigned VersymIndex = 0; if (Versym) { VersymIndex = Versym->vs_index; ++Versym; } bool Hidden = VersymIndex & VERSYM_HIDDEN; VersymIndex = VersymIndex & ~VERSYM_HIDDEN; StringRef Name = check(Sym.getName(this->StringTable), toString(this)); if (Sym.isUndefined()) { Undefs.push_back(Name); continue; } // Ignore local symbols. if (Versym && VersymIndex == VER_NDX_LOCAL) continue; const Elf_Verdef *V = VersymIndex == VER_NDX_GLOBAL ? nullptr : Verdefs[VersymIndex]; if (!Hidden) elf::Symtab::X->addShared(this, Name, Sym, V); // Also add the symbol with the versioned name to handle undefined symbols // with explicit versions. if (V) { StringRef VerName = this->StringTable.data() + V->getAux()->vda_name; Name = Saver.save(Name + "@" + VerName); elf::Symtab::X->addShared(this, Name, Sym, V); } } } static ELFKind getBitcodeELFKind(const Triple &T) { if (T.isLittleEndian()) return T.isArch64Bit() ? ELF64LEKind : ELF32LEKind; return T.isArch64Bit() ? ELF64BEKind : ELF32BEKind; } static uint8_t getBitcodeMachineKind(StringRef Path, const Triple &T) { switch (T.getArch()) { case Triple::aarch64: return EM_AARCH64; case Triple::arm: case Triple::thumb: return EM_ARM; case Triple::mips: case Triple::mipsel: case Triple::mips64: case Triple::mips64el: return EM_MIPS; case Triple::ppc: return EM_PPC; case Triple::ppc64: return EM_PPC64; case Triple::x86: return T.isOSIAMCU() ? EM_IAMCU : EM_386; case Triple::x86_64: return EM_X86_64; default: fatal(Path + ": could not infer e_machine from bitcode target triple " + T.str()); } } BitcodeFile::BitcodeFile(MemoryBufferRef MB, StringRef ArchiveName, uint64_t OffsetInArchive) : InputFile(BitcodeKind, MB) { this->ArchiveName = ArchiveName; // Here we pass a new MemoryBufferRef which is identified by ArchiveName // (the fully resolved path of the archive) + member name + offset of the // member in the archive. // ThinLTO uses the MemoryBufferRef identifier to access its internal // data structures and if two archives define two members with the same name, // this causes a collision which result in only one of the objects being // taken into consideration at LTO time (which very likely causes undefined // symbols later in the link stage). MemoryBufferRef MBRef(MB.getBuffer(), Saver.save(ArchiveName + MB.getBufferIdentifier() + utostr(OffsetInArchive))); Obj = check(lto::InputFile::create(MBRef), toString(this)); Triple T(Obj->getTargetTriple()); EKind = getBitcodeELFKind(T); EMachine = getBitcodeMachineKind(MB.getBufferIdentifier(), T); } static uint8_t mapVisibility(GlobalValue::VisibilityTypes GvVisibility) { switch (GvVisibility) { case GlobalValue::DefaultVisibility: return STV_DEFAULT; case GlobalValue::HiddenVisibility: return STV_HIDDEN; case GlobalValue::ProtectedVisibility: return STV_PROTECTED; } llvm_unreachable("unknown visibility"); } template static Symbol *createBitcodeSymbol(const std::vector &KeptComdats, const lto::InputFile::Symbol &ObjSym, BitcodeFile *F) { StringRef NameRef = Saver.save(ObjSym.getName()); uint32_t Binding = ObjSym.isWeak() ? STB_WEAK : STB_GLOBAL; uint8_t Type = ObjSym.isTLS() ? STT_TLS : STT_NOTYPE; uint8_t Visibility = mapVisibility(ObjSym.getVisibility()); bool CanOmitFromDynSym = ObjSym.canBeOmittedFromSymbolTable(); int C = ObjSym.getComdatIndex(); if (C != -1 && !KeptComdats[C]) return Symtab::X->addUndefined(NameRef, /*IsLocal=*/false, Binding, Visibility, Type, CanOmitFromDynSym, F); if (ObjSym.isUndefined()) return Symtab::X->addUndefined(NameRef, /*IsLocal=*/false, Binding, Visibility, Type, CanOmitFromDynSym, F); if (ObjSym.isCommon()) return Symtab::X->addCommon(NameRef, ObjSym.getCommonSize(), ObjSym.getCommonAlignment(), Binding, Visibility, STT_OBJECT, F); return Symtab::X->addBitcode(NameRef, Binding, Visibility, Type, CanOmitFromDynSym, F); } template void BitcodeFile::parse(DenseSet &ComdatGroups) { std::vector KeptComdats; for (StringRef S : Obj->getComdatTable()) KeptComdats.push_back(ComdatGroups.insert(CachedHashStringRef(S)).second); for (const lto::InputFile::Symbol &ObjSym : Obj->symbols()) Symbols.push_back(createBitcodeSymbol(KeptComdats, ObjSym, this)); } static ELFKind getELFKind(MemoryBufferRef MB) { unsigned char Size; unsigned char Endian; std::tie(Size, Endian) = getElfArchType(MB.getBuffer()); if (Endian != ELFDATA2LSB && Endian != ELFDATA2MSB) fatal(MB.getBufferIdentifier() + ": invalid data encoding"); if (Size != ELFCLASS32 && Size != ELFCLASS64) fatal(MB.getBufferIdentifier() + ": invalid file class"); size_t BufSize = MB.getBuffer().size(); if ((Size == ELFCLASS32 && BufSize < sizeof(Elf32_Ehdr)) || (Size == ELFCLASS64 && BufSize < sizeof(Elf64_Ehdr))) fatal(MB.getBufferIdentifier() + ": file is too short"); if (Size == ELFCLASS32) return (Endian == ELFDATA2LSB) ? ELF32LEKind : ELF32BEKind; return (Endian == ELFDATA2LSB) ? ELF64LEKind : ELF64BEKind; } template void BinaryFile::parse() { ArrayRef Data = toArrayRef(MB.getBuffer()); auto *Section = make(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, 8, Data, ".data"); Sections.push_back(Section); // For each input file foo that is embedded to a result as a binary // blob, we define _binary_foo_{start,end,size} symbols, so that // user programs can access blobs by name. Non-alphanumeric // characters in a filename are replaced with underscore. std::string S = "_binary_" + MB.getBufferIdentifier().str(); for (size_t I = 0; I < S.size(); ++I) if (!isalnum(S[I])) S[I] = '_'; elf::Symtab::X->addRegular(Saver.save(S + "_start"), STV_DEFAULT, STT_OBJECT, 0, 0, STB_GLOBAL, Section, nullptr); elf::Symtab::X->addRegular(Saver.save(S + "_end"), STV_DEFAULT, STT_OBJECT, Data.size(), 0, STB_GLOBAL, Section, nullptr); elf::Symtab::X->addRegular(Saver.save(S + "_size"), STV_DEFAULT, STT_OBJECT, Data.size(), 0, STB_GLOBAL, nullptr, nullptr); } static bool isBitcode(MemoryBufferRef MB) { using namespace sys::fs; return identify_magic(MB.getBuffer()) == file_magic::bitcode; } InputFile *elf::createObjectFile(MemoryBufferRef MB, StringRef ArchiveName, uint64_t OffsetInArchive) { if (isBitcode(MB)) return make(MB, ArchiveName, OffsetInArchive); switch (getELFKind(MB)) { case ELF32LEKind: return make>(MB, ArchiveName); case ELF32BEKind: return make>(MB, ArchiveName); case ELF64LEKind: return make>(MB, ArchiveName); case ELF64BEKind: return make>(MB, ArchiveName); default: llvm_unreachable("getELFKind"); } } InputFile *elf::createSharedFile(MemoryBufferRef MB, StringRef DefaultSoName) { switch (getELFKind(MB)) { case ELF32LEKind: return make>(MB, DefaultSoName); case ELF32BEKind: return make>(MB, DefaultSoName); case ELF64LEKind: return make>(MB, DefaultSoName); case ELF64BEKind: return make>(MB, DefaultSoName); default: llvm_unreachable("getELFKind"); } } MemoryBufferRef LazyObjectFile::getBuffer() { if (Seen) return MemoryBufferRef(); Seen = true; return MB; } template void LazyObjectFile::parse() { for (StringRef Sym : getSymbols()) Symtab::X->addLazyObject(Sym, *this); } template std::vector LazyObjectFile::getElfSymbols() { typedef typename ELFT::Shdr Elf_Shdr; typedef typename ELFT::Sym Elf_Sym; typedef typename ELFT::SymRange Elf_Sym_Range; const ELFFile Obj(this->MB.getBuffer()); ArrayRef Sections = check(Obj.sections(), toString(this)); for (const Elf_Shdr &Sec : Sections) { if (Sec.sh_type != SHT_SYMTAB) continue; Elf_Sym_Range Syms = check(Obj.symbols(&Sec), toString(this)); uint32_t FirstNonLocal = Sec.sh_info; StringRef StringTable = check(Obj.getStringTableForSymtab(Sec, Sections), toString(this)); std::vector V; for (const Elf_Sym &Sym : Syms.slice(FirstNonLocal)) if (Sym.st_shndx != SHN_UNDEF) V.push_back(check(Sym.getName(StringTable), toString(this))); return V; } return {}; } std::vector LazyObjectFile::getBitcodeSymbols() { std::unique_ptr Obj = check(lto::InputFile::create(this->MB), toString(this)); std::vector V; for (const lto::InputFile::Symbol &Sym : Obj->symbols()) if (!Sym.isUndefined()) V.push_back(Saver.save(Sym.getName())); return V; } // Returns a vector of globally-visible defined symbol names. std::vector LazyObjectFile::getSymbols() { if (isBitcode(this->MB)) return getBitcodeSymbols(); switch (getELFKind(this->MB)) { case ELF32LEKind: return getElfSymbols(); case ELF32BEKind: return getElfSymbols(); case ELF64LEKind: return getElfSymbols(); case ELF64BEKind: return getElfSymbols(); default: llvm_unreachable("getELFKind"); } } template void ArchiveFile::parse(); template void ArchiveFile::parse(); template void ArchiveFile::parse(); template void ArchiveFile::parse(); template void BitcodeFile::parse(DenseSet &); template void BitcodeFile::parse(DenseSet &); template void BitcodeFile::parse(DenseSet &); template void BitcodeFile::parse(DenseSet &); template void LazyObjectFile::parse(); template void LazyObjectFile::parse(); template void LazyObjectFile::parse(); template void LazyObjectFile::parse(); template class elf::ELFFileBase; template class elf::ELFFileBase; template class elf::ELFFileBase; template class elf::ELFFileBase; template class elf::ObjectFile; template class elf::ObjectFile; template class elf::ObjectFile; template class elf::ObjectFile; template class elf::SharedFile; template class elf::SharedFile; template class elf::SharedFile; template class elf::SharedFile; template void BinaryFile::parse(); template void BinaryFile::parse(); template void BinaryFile::parse(); template void BinaryFile::parse(); Index: vendor/lld/dist/ELF/LTO.cpp =================================================================== --- vendor/lld/dist/ELF/LTO.cpp (revision 317766) +++ vendor/lld/dist/ELF/LTO.cpp (revision 317767) @@ -1,190 +1,185 @@ //===- LTO.cpp ------------------------------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "LTO.h" #include "Config.h" #include "Error.h" #include "InputFiles.h" #include "Symbols.h" #include "lld/Core/TargetOptionsCommandFlags.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" #include "llvm/IR/DiagnosticPrinter.h" #include "llvm/LTO/Caching.h" #include "llvm/LTO/Config.h" #include "llvm/LTO/LTO.h" #include "llvm/Object/SymbolicFile.h" #include "llvm/Support/CodeGen.h" #include "llvm/Support/ELF.h" #include "llvm/Support/Error.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" #include #include #include #include #include #include using namespace llvm; using namespace llvm::object; using namespace llvm::ELF; using namespace lld; using namespace lld::elf; // This is for use when debugging LTO. static void saveBuffer(StringRef Buffer, const Twine &Path) { std::error_code EC; raw_fd_ostream OS(Path.str(), EC, sys::fs::OpenFlags::F_None); if (EC) error("cannot create " + Path + ": " + EC.message()); OS << Buffer; } static void diagnosticHandler(const DiagnosticInfo &DI) { SmallString<128> ErrStorage; raw_svector_ostream OS(ErrStorage); DiagnosticPrinterRawOStream DP(OS); DI.print(DP); warn(ErrStorage); } static void checkError(Error E) { handleAllErrors(std::move(E), [&](ErrorInfoBase &EIB) -> Error { error(EIB.message()); return Error::success(); }); } static std::unique_ptr createLTO() { lto::Config Conf; // LLD supports the new relocations. Conf.Options = InitTargetOptionsFromCodeGenFlags(); Conf.Options.RelaxELFRelocations = true; Conf.RelocModel = Config->Pic ? Reloc::PIC_ : Reloc::Static; Conf.CodeModel = GetCodeModelFromCMModel(); Conf.DisableVerify = Config->DisableVerify; Conf.DiagHandler = diagnosticHandler; Conf.OptLevel = Config->LTOO; // Set up a custom pipeline if we've been asked to. Conf.OptPipeline = Config->LTONewPmPasses; Conf.AAPipeline = Config->LTOAAPipeline; // Set up optimization remarks if we've been asked to. Conf.RemarksFilename = Config->OptRemarksFilename; Conf.RemarksWithHotness = Config->OptRemarksWithHotness; if (Config->SaveTemps) checkError(Conf.addSaveTemps(std::string(Config->OutputFile) + ".", /*UseInputModulePath*/ true)); lto::ThinBackend Backend; if (Config->ThinLTOJobs != -1u) Backend = lto::createInProcessThinBackend(Config->ThinLTOJobs); return llvm::make_unique(std::move(Conf), Backend, Config->LTOPartitions); } BitcodeCompiler::BitcodeCompiler() : LTOObj(createLTO()) {} BitcodeCompiler::~BitcodeCompiler() = default; static void undefine(Symbol *S) { replaceBody(S, S->body()->getName(), /*IsLocal=*/false, STV_DEFAULT, S->body()->Type, nullptr); - // It shouldn't normally matter what the binding is, but if a bug in the LTO - // implementation causes it to fail to provide a definition for a symbol, - // setting the binding to STB_GLOBAL will cause the linker to report an - // undefined symbol error, even if the definition was weak. - S->Binding = STB_GLOBAL; } void BitcodeCompiler::add(BitcodeFile &F) { lto::InputFile &Obj = *F.Obj; unsigned SymNum = 0; std::vector Syms = F.getSymbols(); std::vector Resols(Syms.size()); // Provide a resolution to the LTO API for each symbol. for (const lto::InputFile::Symbol &ObjSym : Obj.symbols()) { Symbol *Sym = Syms[SymNum]; lto::SymbolResolution &R = Resols[SymNum]; ++SymNum; SymbolBody *B = Sym->body(); // Ideally we shouldn't check for SF_Undefined but currently IRObjectFile // reports two symbols for module ASM defined. Without this check, lld // flags an undefined in IR with a definition in ASM as prevailing. // Once IRObjectFile is fixed to report only one symbol this hack can // be removed. R.Prevailing = !ObjSym.isUndefined() && B->File == &F; R.VisibleToRegularObj = Sym->IsUsedInRegularObj || (R.Prevailing && Sym->includeInDynsym()); if (R.Prevailing) undefine(Sym); } checkError(LTOObj->add(std::move(F.Obj), Resols)); } // Merge all the bitcode files we have seen, codegen the result // and return the resulting ObjectFile(s). std::vector BitcodeCompiler::compile() { std::vector Ret; unsigned MaxTasks = LTOObj->getMaxTasks(); Buff.resize(MaxTasks); Files.resize(MaxTasks); // The --thinlto-cache-dir option specifies the path to a directory in which // to cache native object files for ThinLTO incremental builds. If a path was // specified, configure LTO to use it as the cache directory. lto::NativeObjectCache Cache; if (!Config->ThinLTOCacheDir.empty()) Cache = check( lto::localCache(Config->ThinLTOCacheDir, [&](size_t Task, std::unique_ptr MB) { Files[Task] = std::move(MB); })); checkError(LTOObj->run( [&](size_t Task) { return llvm::make_unique( llvm::make_unique(Buff[Task])); }, Cache)); if (!Config->ThinLTOCacheDir.empty()) pruneCache(Config->ThinLTOCacheDir, Config->ThinLTOCachePolicy); for (unsigned I = 0; I != MaxTasks; ++I) { if (Buff[I].empty()) continue; if (Config->SaveTemps) { if (I == 0) saveBuffer(Buff[I], Config->OutputFile + ".lto.o"); else saveBuffer(Buff[I], Config->OutputFile + Twine(I) + ".lto.o"); } InputFile *Obj = createObjectFile(MemoryBufferRef(Buff[I], "lto.tmp")); Ret.push_back(Obj); } for (std::unique_ptr &File : Files) if (File) Ret.push_back(createObjectFile(*File)); return Ret; } Index: vendor/lld/dist/ELF/LinkerScript.cpp =================================================================== --- vendor/lld/dist/ELF/LinkerScript.cpp (revision 317766) +++ vendor/lld/dist/ELF/LinkerScript.cpp (revision 317767) @@ -1,1068 +1,1069 @@ //===- LinkerScript.cpp ---------------------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file contains the parser/evaluator of the linker script. // //===----------------------------------------------------------------------===// #include "LinkerScript.h" #include "Config.h" #include "InputSection.h" #include "Memory.h" #include "OutputSections.h" #include "Strings.h" #include "SymbolTable.h" #include "Symbols.h" #include "SyntheticSections.h" #include "Writer.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Casting.h" #include "llvm/Support/ELF.h" #include "llvm/Support/Endian.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" #include #include #include #include #include #include #include #include using namespace llvm; using namespace llvm::ELF; using namespace llvm::object; using namespace llvm::support::endian; using namespace lld; using namespace lld::elf; LinkerScript *elf::Script; uint64_t ExprValue::getValue() const { if (Sec) return Sec->getOffset(Val) + Sec->getOutputSection()->Addr; return Val; } uint64_t ExprValue::getSecAddr() const { if (Sec) return Sec->getOffset(0) + Sec->getOutputSection()->Addr; return 0; } template static SymbolBody *addRegular(SymbolAssignment *Cmd) { Symbol *Sym; uint8_t Visibility = Cmd->Hidden ? STV_HIDDEN : STV_DEFAULT; std::tie(Sym, std::ignore) = Symtab::X->insert( Cmd->Name, /*Type*/ 0, Visibility, /*CanOmitFromDynSym*/ false, /*File*/ nullptr); Sym->Binding = STB_GLOBAL; ExprValue Value = Cmd->Expression(); SectionBase *Sec = Value.isAbsolute() ? nullptr : Value.Sec; // We want to set symbol values early if we can. This allows us to use symbols // as variables in linker scripts. Doing so allows us to write expressions // like this: `alignment = 16; . = ALIGN(., alignment)` uint64_t SymValue = Value.isAbsolute() ? Value.getValue() : 0; replaceBody(Sym, Cmd->Name, /*IsLocal=*/false, Visibility, STT_NOTYPE, SymValue, 0, Sec, nullptr); return Sym->body(); } OutputSection *LinkerScript::getOutputSection(const Twine &Loc, StringRef Name) { for (OutputSection *Sec : *OutputSections) if (Sec->Name == Name) return Sec; static OutputSection Dummy("", 0, 0); if (ErrorOnMissingSection) error(Loc + ": undefined section " + Name); return &Dummy; } // This function is essentially the same as getOutputSection(Name)->Size, // but it won't print out an error message if a given section is not found. // // Linker script does not create an output section if its content is empty. // We want to allow SIZEOF(.foo) where .foo is a section which happened to // be empty. That is why this function is different from getOutputSection(). uint64_t LinkerScript::getOutputSectionSize(StringRef Name) { for (OutputSection *Sec : *OutputSections) if (Sec->Name == Name) return Sec->Size; return 0; } void LinkerScript::setDot(Expr E, const Twine &Loc, bool InSec) { uint64_t Val = E().getValue(); if (Val < Dot) { if (InSec) error(Loc + ": unable to move location counter backward for: " + CurOutSec->Name); else error(Loc + ": unable to move location counter backward"); } Dot = Val; // Update to location counter means update to section size. if (InSec) CurOutSec->Size = Dot - CurOutSec->Addr; } // Sets value of a symbol. Two kinds of symbols are processed: synthetic // symbols, whose value is an offset from beginning of section and regular // symbols whose value is absolute. void LinkerScript::assignSymbol(SymbolAssignment *Cmd, bool InSec) { if (Cmd->Name == ".") { setDot(Cmd->Expression, Cmd->Location, InSec); return; } if (!Cmd->Sym) return; auto *Sym = cast(Cmd->Sym); ExprValue V = Cmd->Expression(); if (V.isAbsolute()) { Sym->Value = V.getValue(); } else { Sym->Section = V.Sec; if (Sym->Section->Flags & SHF_ALLOC) Sym->Value = V.Val; else Sym->Value = V.getValue(); } } static SymbolBody *findSymbol(StringRef S) { switch (Config->EKind) { case ELF32LEKind: return Symtab::X->find(S); case ELF32BEKind: return Symtab::X->find(S); case ELF64LEKind: return Symtab::X->find(S); case ELF64BEKind: return Symtab::X->find(S); default: llvm_unreachable("unknown Config->EKind"); } } static SymbolBody *addRegularSymbol(SymbolAssignment *Cmd) { switch (Config->EKind) { case ELF32LEKind: return addRegular(Cmd); case ELF32BEKind: return addRegular(Cmd); case ELF64LEKind: return addRegular(Cmd); case ELF64BEKind: return addRegular(Cmd); default: llvm_unreachable("unknown Config->EKind"); } } void LinkerScript::addSymbol(SymbolAssignment *Cmd) { if (Cmd->Name == ".") return; // If a symbol was in PROVIDE(), we need to define it only when // it is a referenced undefined symbol. SymbolBody *B = findSymbol(Cmd->Name); if (Cmd->Provide && (!B || B->isDefined())) return; Cmd->Sym = addRegularSymbol(Cmd); } bool SymbolAssignment::classof(const BaseCommand *C) { return C->Kind == AssignmentKind; } bool OutputSectionCommand::classof(const BaseCommand *C) { return C->Kind == OutputSectionKind; } bool InputSectionDescription::classof(const BaseCommand *C) { return C->Kind == InputSectionKind; } bool AssertCommand::classof(const BaseCommand *C) { return C->Kind == AssertKind; } bool BytesDataCommand::classof(const BaseCommand *C) { return C->Kind == BytesDataKind; } static StringRef basename(InputSectionBase *S) { if (S->File) return sys::path::filename(S->File->getName()); return ""; } bool LinkerScript::shouldKeep(InputSectionBase *S) { for (InputSectionDescription *ID : Opt.KeptSections) if (ID->FilePat.match(basename(S))) for (SectionPattern &P : ID->SectionPatterns) if (P.SectionPat.match(S->Name)) return true; return false; } // A helper function for the SORT() command. static std::function getComparator(SortSectionPolicy K) { switch (K) { case SortSectionPolicy::Alignment: return [](InputSectionBase *A, InputSectionBase *B) { // ">" is not a mistake. Sections with larger alignments are placed // before sections with smaller alignments in order to reduce the // amount of padding necessary. This is compatible with GNU. return A->Alignment > B->Alignment; }; case SortSectionPolicy::Name: return [](InputSectionBase *A, InputSectionBase *B) { return A->Name < B->Name; }; case SortSectionPolicy::Priority: return [](InputSectionBase *A, InputSectionBase *B) { return getPriority(A->Name) < getPriority(B->Name); }; default: llvm_unreachable("unknown sort policy"); } } // A helper function for the SORT() command. static bool matchConstraints(ArrayRef Sections, ConstraintKind Kind) { if (Kind == ConstraintKind::NoConstraint) return true; bool IsRW = llvm::any_of(Sections, [](InputSectionBase *Sec) { return static_cast(Sec)->Flags & SHF_WRITE; }); return (IsRW && Kind == ConstraintKind::ReadWrite) || (!IsRW && Kind == ConstraintKind::ReadOnly); } static void sortSections(InputSectionBase **Begin, InputSectionBase **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 LinkerScript::computeInputSections(const InputSectionDescription *Cmd) { std::vector Ret; // Collects all sections that satisfy constraints of Cmd. for (const SectionPattern &Pat : Cmd->SectionPatterns) { size_t SizeBefore = Ret.size(); for (InputSectionBase *Sec : InputSections) { if (Sec->Assigned) continue; // For -emit-relocs we have to ignore entries like // .rela.dyn : { *(.rela.data) } // which are common because they are in the default bfd script. if (Sec->Type == SHT_REL || Sec->Type == SHT_RELA) continue; StringRef Filename = basename(Sec); if (!Cmd->FilePat.match(Filename) || Pat.ExcludedFilePat.match(Filename) || !Pat.SectionPat.match(Sec->Name)) continue; Ret.push_back(Sec); Sec->Assigned = true; } // Sort sections as instructed by SORT-family commands and --sort-section // option. Because SORT-family commands can be nested at most two depth // (e.g. SORT_BY_NAME(SORT_BY_ALIGNMENT(.text.*))) and because the command // line option is respected even if a SORT command is given, the exact // behavior we have here is a bit complicated. Here are the rules. // // 1. If two SORT commands are given, --sort-section is ignored. // 2. If one SORT command is given, and if it is not SORT_NONE, // --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(); if (Pat.SortOuter != SortSectionPolicy::None) { if (Pat.SortInner == SortSectionPolicy::Default) sortSections(Begin, End, Config->SortSection); else sortSections(Begin, End, Pat.SortInner); sortSections(Begin, End, Pat.SortOuter); } } return Ret; } void LinkerScript::discard(ArrayRef V) { for (InputSectionBase *S : V) { S->Live = false; if (S == InX::ShStrTab) error("discarding .shstrtab section is not allowed"); discard(S->DependentSections); } } std::vector LinkerScript::createInputSectionList(OutputSectionCommand &OutCmd) { std::vector Ret; for (BaseCommand *Base : OutCmd.Commands) { auto *Cmd = dyn_cast(Base); if (!Cmd) continue; Cmd->Sections = computeInputSections(Cmd); Ret.insert(Ret.end(), Cmd->Sections.begin(), Cmd->Sections.end()); } return Ret; } void LinkerScript::processCommands(OutputSectionFactory &Factory) { // A symbol can be assigned before any section is mentioned in the linker // script. In an DSO, the symbol values are addresses, so the only important // section values are: // * SHN_UNDEF // * SHN_ABS // * Any value meaning a regular section. // To handle that, create a dummy aether section that fills the void before // the linker scripts switches to another section. It has an index of one // which will map to whatever the first actual section is. Aether = make("", 0, SHF_ALLOC); Aether->SectionIndex = 1; CurOutSec = Aether; Dot = 0; for (size_t I = 0; I < Opt.Commands.size(); ++I) { // Handle symbol assignments outside of any output section. if (auto *Cmd = dyn_cast(Opt.Commands[I])) { addSymbol(Cmd); continue; } if (auto *Cmd = dyn_cast(Opt.Commands[I])) { std::vector V = createInputSectionList(*Cmd); // The output section name `/DISCARD/' is special. // Any input section assigned to it is discarded. if (Cmd->Name == "/DISCARD/") { discard(V); continue; } // This is for ONLY_IF_RO and ONLY_IF_RW. An output section directive // ".foo : ONLY_IF_R[OW] { ... }" is handled only if all member input // sections satisfy a given constraint. If not, a directive is handled // as if it wasn't present from the beginning. // // Because we'll iterate over Commands many more times, the easiest // way to "make it as if it wasn't present" is to just remove it. if (!matchConstraints(V, Cmd->Constraint)) { for (InputSectionBase *S : V) S->Assigned = false; Opt.Commands.erase(Opt.Commands.begin() + I); --I; continue; } // A directive may contain symbol definitions like this: // ".foo : { ...; bar = .; }". Handle them. for (BaseCommand *Base : Cmd->Commands) if (auto *OutCmd = dyn_cast(Base)) addSymbol(OutCmd); // Handle subalign (e.g. ".foo : SUBALIGN(32) { ... }"). If subalign // is given, input sections are aligned to that value, whether the // given value is larger or smaller than the original section alignment. if (Cmd->SubalignExpr) { uint32_t Subalign = Cmd->SubalignExpr().getValue(); for (InputSectionBase *S : V) S->Alignment = Subalign; } // Add input sections to an output section. unsigned Pos = 0; for (InputSectionBase *S : V) { // The actual offset will be computed during // assignAddresses. For now, use the index as a very crude // approximation so that it is at least easy for other code to // know the section order. cast(S)->OutSecOff = Pos++; Factory.addInputSec(S, Cmd->Name, Cmd->Sec); } } } CurOutSec = nullptr; } void LinkerScript::fabricateDefaultCommands(bool AllocateHeader) { std::vector Commands; // Define start address uint64_t StartAddr = Config->ImageBase; if (AllocateHeader) StartAddr += elf::getHeaderSize(); - // The Sections with -T
are sorted in order of ascending address - // we must use this if it is lower than StartAddr as calls to setDot() must - // be monotonically increasing - if (!Config->SectionStartMap.empty()) { - uint64_t LowestSecStart = Config->SectionStartMap.begin()->second; - StartAddr = std::min(StartAddr, LowestSecStart); - } + // The Sections with -T
have been sorted in order of ascending + // address. We must lower StartAddr if the lowest -T
as + // calls to setDot() must be monotonically increasing. + for (auto& KV : Config->SectionStartMap) + StartAddr = std::min(StartAddr, KV.second); + Commands.push_back( make(".", [=] { return StartAddr; }, "")); // For each OutputSection that needs a VA fabricate an OutputSectionCommand // with an InputSectionDescription describing the InputSections for (OutputSection *Sec : *OutputSections) { if (!(Sec->Flags & SHF_ALLOC)) continue; + auto *OSCmd = make(Sec->Name); + OSCmd->Sec = Sec; + + // Prefer user supplied address over additional alignment constraint auto I = Config->SectionStartMap.find(Sec->Name); if (I != Config->SectionStartMap.end()) Commands.push_back( make(".", [=] { return I->second; }, "")); - - auto *OSCmd = make(Sec->Name); - OSCmd->Sec = Sec; - if (Sec->PageAlign) + else if (Sec->PageAlign) OSCmd->AddrExpr = [=] { return alignTo(Script->getDot(), Config->MaxPageSize); }; + Commands.push_back(OSCmd); if (Sec->Sections.size()) { auto *ISD = make(""); OSCmd->Commands.push_back(ISD); for (InputSection *ISec : Sec->Sections) { ISD->Sections.push_back(ISec); ISec->Assigned = true; } } } // SECTIONS commands run before other non SECTIONS commands Commands.insert(Commands.end(), Opt.Commands.begin(), Opt.Commands.end()); Opt.Commands = std::move(Commands); } // Add sections that didn't match any sections command. void LinkerScript::addOrphanSections(OutputSectionFactory &Factory) { for (InputSectionBase *S : InputSections) { if (!S->Live || S->OutSec) continue; StringRef Name = getOutputSectionName(S->Name); auto I = std::find_if( Opt.Commands.begin(), Opt.Commands.end(), [&](BaseCommand *Base) { if (auto *Cmd = dyn_cast(Base)) return Cmd->Name == Name; return false; }); if (I == Opt.Commands.end()) { Factory.addInputSec(S, Name); } else { auto *Cmd = cast(*I); Factory.addInputSec(S, Name, Cmd->Sec); auto *ISD = make(""); ISD->Sections.push_back(S); Cmd->Commands.push_back(ISD); } } } static bool isTbss(OutputSection *Sec) { return (Sec->Flags & SHF_TLS) && Sec->Type == SHT_NOBITS; } void LinkerScript::output(InputSection *S) { bool IsTbss = isTbss(CurOutSec); uint64_t Pos = IsTbss ? Dot + ThreadBssOffset : Dot; Pos = alignTo(Pos, S->Alignment); S->OutSecOff = Pos - CurOutSec->Addr; Pos += S->getSize(); // Update output section size after adding each section. This is so that // SIZEOF works correctly in the case below: // .foo { *(.aaa) a = SIZEOF(.foo); *(.bbb) } CurOutSec->Size = Pos - CurOutSec->Addr; // If there is a memory region associated with this input section, then // place the section in that region and update the region index. if (CurMemRegion) { CurMemRegion->Offset += CurOutSec->Size; uint64_t CurSize = CurMemRegion->Offset - CurMemRegion->Origin; if (CurSize > CurMemRegion->Length) { uint64_t OverflowAmt = CurSize - CurMemRegion->Length; error("section '" + CurOutSec->Name + "' will not fit in region '" + CurMemRegion->Name + "': overflowed by " + Twine(OverflowAmt) + " bytes"); } } if (IsTbss) ThreadBssOffset = Pos - Dot; else Dot = Pos; } void LinkerScript::switchTo(OutputSection *Sec) { if (CurOutSec == Sec) return; CurOutSec = Sec; Dot = alignTo(Dot, CurOutSec->Alignment); CurOutSec->Addr = isTbss(CurOutSec) ? Dot + ThreadBssOffset : Dot; // If neither AT nor AT> is specified for an allocatable section, the linker // will set the LMA such that the difference between VMA and LMA for the // section is the same as the preceding output section in the same region // https://sourceware.org/binutils/docs-2.20/ld/Output-Section-LMA.html if (LMAOffset) CurOutSec->LMAOffset = LMAOffset(); } void LinkerScript::process(BaseCommand &Base) { // This handles the assignments to symbol or to the dot. if (auto *Cmd = dyn_cast(&Base)) { assignSymbol(Cmd, true); return; } // Handle BYTE(), SHORT(), LONG(), or QUAD(). if (auto *Cmd = dyn_cast(&Base)) { Cmd->Offset = Dot - CurOutSec->Addr; Dot += Cmd->Size; CurOutSec->Size = Dot - CurOutSec->Addr; return; } // Handle ASSERT(). if (auto *Cmd = dyn_cast(&Base)) { Cmd->Expression(); return; } // Handle a single input section description command. // It calculates and assigns the offsets for each section and also // updates the output section size. auto &Cmd = cast(Base); for (InputSectionBase *Sec : Cmd.Sections) { // We tentatively added all synthetic sections at the beginning and removed // empty ones afterwards (because there is no way to know whether they were // going be empty or not other than actually running linker scripts.) // We need to ignore remains of empty sections. if (auto *S = dyn_cast(Sec)) if (S->empty()) continue; if (!Sec->Live) continue; assert(CurOutSec == Sec->OutSec); output(cast(Sec)); } } // This function searches for a memory region to place the given output // section in. If found, a pointer to the appropriate memory region is // returned. Otherwise, a nullptr is returned. MemoryRegion *LinkerScript::findMemoryRegion(OutputSectionCommand *Cmd) { // If a memory region name was specified in the output section command, // then try to find that region first. if (!Cmd->MemoryRegionName.empty()) { auto It = Opt.MemoryRegions.find(Cmd->MemoryRegionName); if (It != Opt.MemoryRegions.end()) return &It->second; error("memory region '" + Cmd->MemoryRegionName + "' not declared"); return nullptr; } // If at least one memory region is defined, all sections must // belong to some memory region. Otherwise, we don't need to do // anything for memory regions. if (Opt.MemoryRegions.empty()) return nullptr; OutputSection *Sec = Cmd->Sec; // See if a region can be found by matching section flags. for (auto &Pair : Opt.MemoryRegions) { MemoryRegion &M = Pair.second; if ((M.Flags & Sec->Flags) && (M.NegFlags & Sec->Flags) == 0) return &M; } // Otherwise, no suitable region was found. if (Sec->Flags & SHF_ALLOC) error("no memory region specified for section '" + Sec->Name + "'"); return nullptr; } // This function assigns offsets to input sections and an output section // for a single sections command (e.g. ".text { *(.text); }"). void LinkerScript::assignOffsets(OutputSectionCommand *Cmd) { OutputSection *Sec = Cmd->Sec; if (!Sec) return; if (Cmd->AddrExpr && (Sec->Flags & SHF_ALLOC)) setDot(Cmd->AddrExpr, Cmd->Location, false); if (Cmd->LMAExpr) { uint64_t D = Dot; LMAOffset = [=] { return Cmd->LMAExpr().getValue() - D; }; } CurMemRegion = Cmd->MemRegion; if (CurMemRegion) Dot = CurMemRegion->Offset; switchTo(Sec); for (BaseCommand *C : Cmd->Commands) process(*C); } void LinkerScript::removeEmptyCommands() { // It is common practice to use very generic linker scripts. So for any // given run some of the output sections in the script will be empty. // We could create corresponding empty output sections, but that would // clutter the output. // We instead remove trivially empty sections. The bfd linker seems even // more aggressive at removing them. auto Pos = std::remove_if( Opt.Commands.begin(), Opt.Commands.end(), [&](BaseCommand *Base) { if (auto *Cmd = dyn_cast(Base)) return std::find(OutputSections->begin(), OutputSections->end(), Cmd->Sec) == OutputSections->end(); return false; }); Opt.Commands.erase(Pos, Opt.Commands.end()); } static bool isAllSectionDescription(const OutputSectionCommand &Cmd) { for (BaseCommand *Base : Cmd.Commands) if (!isa(*Base)) return false; return true; } void LinkerScript::adjustSectionsBeforeSorting() { // If the output section contains only symbol assignments, create a // corresponding output section. The bfd linker seems to only create them if // '.' 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 (BaseCommand *Base : Opt.Commands) { auto *Cmd = dyn_cast(Base); if (!Cmd) continue; if (OutputSection *Sec = Cmd->Sec) { Flags = Sec->Flags; Type = Sec->Type; continue; } if (isAllSectionDescription(*Cmd)) continue; auto *OutSec = make(Cmd->Name, Type, Flags); OutputSections->push_back(OutSec); Cmd->Sec = OutSec; } } void LinkerScript::adjustSectionsAfterSorting() { placeOrphanSections(); // Try and find an appropriate memory region to assign offsets in. for (BaseCommand *Base : Opt.Commands) { if (auto *Cmd = dyn_cast(Base)) { Cmd->MemRegion = findMemoryRegion(Cmd); // Handle align (e.g. ".foo : ALIGN(16) { ... }"). if (Cmd->AlignExpr) Cmd->Sec->updateAlignment(Cmd->AlignExpr().getValue()); } } // If output section command doesn't specify any segments, // and we haven't previously assigned any section to segment, // then we simply assign section to the very first load segment. // Below is an example of such linker script: // PHDRS { seg PT_LOAD; } // SECTIONS { .aaa : { *(.aaa) } } std::vector DefPhdrs; auto FirstPtLoad = std::find_if(Opt.PhdrsCommands.begin(), Opt.PhdrsCommands.end(), [](const PhdrsCommand &Cmd) { return Cmd.Type == PT_LOAD; }); if (FirstPtLoad != Opt.PhdrsCommands.end()) DefPhdrs.push_back(FirstPtLoad->Name); // Walk the commands and propagate the program headers to commands that don't // explicitly specify them. for (BaseCommand *Base : Opt.Commands) { auto *Cmd = dyn_cast(Base); if (!Cmd) continue; if (Cmd->Phdrs.empty()) Cmd->Phdrs = DefPhdrs; else DefPhdrs = Cmd->Phdrs; } removeEmptyCommands(); } // When placing orphan sections, we want to place them after symbol assignments // so that an orphan after // begin_foo = .; // foo : { *(foo) } // end_foo = .; // doesn't break the intended meaning of the begin/end symbols. // We don't want to go over sections since Writer::sortSections is the // one in charge of deciding the order of the sections. // We don't want to go over alignments, since doing so in // rx_sec : { *(rx_sec) } // . = ALIGN(0x1000); // /* The RW PT_LOAD starts here*/ // rw_sec : { *(rw_sec) } // would mean that the RW PT_LOAD would become unaligned. static bool shouldSkip(BaseCommand *Cmd) { if (isa(Cmd)) return false; if (auto *Assign = dyn_cast(Cmd)) return Assign->Name != "."; return true; } // Orphan sections are sections present in the input files which are // not explicitly placed into the output file by the linker script. // // When the control reaches this function, Opt.Commands contains // output section commands for non-orphan sections only. This function // adds new elements for orphan sections so that all sections are // explicitly handled by Opt.Commands. // // Writer::sortSections has already sorted output sections. // What we need to do is to scan OutputSections vector and // Opt.Commands in parallel to find orphan sections. If there is an // output section that doesn't have a corresponding entry in // Opt.Commands, we will insert a new entry to Opt.Commands. // // There is some ambiguity as to where exactly a new entry should be // inserted, because Opt.Commands contains not only output section // commands but also other types of commands such as symbol assignment // expressions. There's no correct answer here due to the lack of the // formal specification of the linker script. We use heuristics to // determine whether a new output command should be added before or // after another commands. For the details, look at shouldSkip // function. void LinkerScript::placeOrphanSections() { // The OutputSections are already in the correct order. // This loops creates or moves commands as needed so that they are in the // correct order. int CmdIndex = 0; // As a horrible special case, skip the first . assignment if it is before any // section. We do this because it is common to set a load address by starting // the script with ". = 0xabcd" and the expectation is that every section is // after that. auto FirstSectionOrDotAssignment = std::find_if(Opt.Commands.begin(), Opt.Commands.end(), [](BaseCommand *Cmd) { return !shouldSkip(Cmd); }); if (FirstSectionOrDotAssignment != Opt.Commands.end()) { CmdIndex = FirstSectionOrDotAssignment - Opt.Commands.begin(); if (isa(**FirstSectionOrDotAssignment)) ++CmdIndex; } for (OutputSection *Sec : *OutputSections) { StringRef Name = Sec->Name; // Find the last spot where we can insert a command and still get the // correct result. auto CmdIter = Opt.Commands.begin() + CmdIndex; auto E = Opt.Commands.end(); while (CmdIter != E && shouldSkip(*CmdIter)) { ++CmdIter; ++CmdIndex; } // If there is no command corresponding to this output section, // create one and put a InputSectionDescription in it so that both // representations agree on which input sections to use. auto Pos = std::find_if(CmdIter, E, [&](BaseCommand *Base) { auto *Cmd = dyn_cast(Base); return Cmd && Cmd->Name == Name; }); if (Pos == E) { auto *Cmd = make(Name); Opt.Commands.insert(CmdIter, Cmd); ++CmdIndex; Cmd->Sec = Sec; auto *ISD = make(""); for (InputSection *IS : Sec->Sections) ISD->Sections.push_back(IS); Cmd->Commands.push_back(ISD); continue; } // Continue from where we found it. CmdIndex = (Pos - Opt.Commands.begin()) + 1; } } void LinkerScript::processNonSectionCommands() { for (BaseCommand *Base : Opt.Commands) { if (auto *Cmd = dyn_cast(Base)) assignSymbol(Cmd, false); else if (auto *Cmd = dyn_cast(Base)) Cmd->Expression(); } } // Do a last effort at synchronizing the linker script "AST" and the section // list. This is needed to account for last minute changes, like adding a // .ARM.exidx terminator and sorting SHF_LINK_ORDER sections. // // FIXME: We should instead create the "AST" earlier and the above changes would // be done directly in the "AST". // // This can only handle new sections being added and sections being reordered. void LinkerScript::synchronize() { for (BaseCommand *Base : Opt.Commands) { auto *Cmd = dyn_cast(Base); if (!Cmd) continue; ArrayRef Sections = Cmd->Sec->Sections; std::vector ScriptSections; DenseSet ScriptSectionsSet; for (BaseCommand *Base : Cmd->Commands) { auto *ISD = dyn_cast(Base); if (!ISD) continue; for (InputSectionBase *&IS : ISD->Sections) { if (IS->Live) { ScriptSections.push_back(&IS); ScriptSectionsSet.insert(IS); } } } std::vector Missing; for (InputSection *IS : Sections) if (!ScriptSectionsSet.count(IS)) Missing.push_back(IS); if (!Missing.empty()) { auto ISD = make(""); ISD->Sections = Missing; Cmd->Commands.push_back(ISD); for (InputSectionBase *&IS : ISD->Sections) if (IS->Live) ScriptSections.push_back(&IS); } assert(ScriptSections.size() == Sections.size()); for (int I = 0, N = Sections.size(); I < N; ++I) *ScriptSections[I] = Sections[I]; } } void LinkerScript::assignAddresses(std::vector &Phdrs) { // Assign addresses as instructed by linker script SECTIONS sub-commands. Dot = 0; ErrorOnMissingSection = true; switchTo(Aether); for (BaseCommand *Base : Opt.Commands) { if (auto *Cmd = dyn_cast(Base)) { assignSymbol(Cmd, false); continue; } if (auto *Cmd = dyn_cast(Base)) { Cmd->Expression(); continue; } auto *Cmd = cast(Base); assignOffsets(Cmd); } uint64_t MinVA = std::numeric_limits::max(); for (OutputSection *Sec : *OutputSections) { if (Sec->Flags & SHF_ALLOC) MinVA = std::min(MinVA, Sec->Addr); else Sec->Addr = 0; } allocateHeaders(Phdrs, *OutputSections, MinVA); } // Creates program headers as instructed by PHDRS linker script command. std::vector LinkerScript::createPhdrs() { std::vector Ret; // Process PHDRS and FILEHDR keywords because they are not // real output sections and cannot be added in the following loop. for (const PhdrsCommand &Cmd : Opt.PhdrsCommands) { Ret.emplace_back(Cmd.Type, Cmd.Flags == UINT_MAX ? PF_R : Cmd.Flags); PhdrEntry &Phdr = Ret.back(); if (Cmd.HasFilehdr) Phdr.add(Out::ElfHeader); if (Cmd.HasPhdrs) Phdr.add(Out::ProgramHeaders); if (Cmd.LMAExpr) { Phdr.p_paddr = Cmd.LMAExpr().getValue(); Phdr.HasLMA = true; } } // Add output sections to program headers. for (OutputSection *Sec : *OutputSections) { if (!(Sec->Flags & SHF_ALLOC)) break; // Assign headers specified by linker script for (size_t Id : getPhdrIndices(Sec->Name)) { Ret[Id].add(Sec); if (Opt.PhdrsCommands[Id].Flags == UINT_MAX) Ret[Id].p_flags |= Sec->getPhdrFlags(); } } return Ret; } bool LinkerScript::ignoreInterpSection() { // Ignore .interp section in case we have PHDRS specification // and PT_INTERP isn't listed. if (Opt.PhdrsCommands.empty()) return false; for (PhdrsCommand &Cmd : Opt.PhdrsCommands) if (Cmd.Type == PT_INTERP) return false; return true; } Optional LinkerScript::getFiller(StringRef Name) { for (BaseCommand *Base : Opt.Commands) if (auto *Cmd = dyn_cast(Base)) if (Cmd->Name == Name) return Cmd->Filler; return None; } static void writeInt(uint8_t *Buf, uint64_t Data, uint64_t Size) { if (Size == 1) *Buf = Data; else if (Size == 2) write16(Buf, Data, Config->Endianness); else if (Size == 4) write32(Buf, Data, Config->Endianness); else if (Size == 8) write64(Buf, Data, Config->Endianness); else llvm_unreachable("unsupported Size argument"); } void LinkerScript::writeDataBytes(StringRef Name, uint8_t *Buf) { int I = getSectionIndex(Name); if (I == INT_MAX) return; auto *Cmd = dyn_cast(Opt.Commands[I]); for (BaseCommand *Base : Cmd->Commands) if (auto *Data = dyn_cast(Base)) writeInt(Buf + Data->Offset, Data->Expression().getValue(), Data->Size); } bool LinkerScript::hasLMA(StringRef Name) { for (BaseCommand *Base : Opt.Commands) if (auto *Cmd = dyn_cast(Base)) if (Cmd->LMAExpr && Cmd->Name == Name) return true; return false; } // Returns the index of the given section name in linker script // SECTIONS commands. Sections are laid out as the same order as they // were in the script. If a given name did not appear in the script, // it returns INT_MAX, so that it will be laid out at end of file. int LinkerScript::getSectionIndex(StringRef Name) { for (int I = 0, E = Opt.Commands.size(); I != E; ++I) if (auto *Cmd = dyn_cast(Opt.Commands[I])) if (Cmd->Name == Name) return I; return INT_MAX; } ExprValue LinkerScript::getSymbolValue(const Twine &Loc, StringRef S) { if (S == ".") return {CurOutSec, Dot - CurOutSec->Addr}; if (SymbolBody *B = findSymbol(S)) { if (auto *D = dyn_cast(B)) return {D->Section, D->Value}; if (auto *C = dyn_cast(B)) return {InX::Common, C->Offset}; } error(Loc + ": symbol not found: " + S); return 0; } bool LinkerScript::isDefined(StringRef S) { return findSymbol(S) != nullptr; } // Returns indices of ELF headers containing specific section, identified // by Name. Each index is a zero based number of ELF header listed within // PHDRS {} script block. std::vector LinkerScript::getPhdrIndices(StringRef SectionName) { for (BaseCommand *Base : Opt.Commands) { auto *Cmd = dyn_cast(Base); if (!Cmd || Cmd->Name != SectionName) continue; std::vector Ret; for (StringRef PhdrName : Cmd->Phdrs) Ret.push_back(getPhdrIndex(Cmd->Location, PhdrName)); return Ret; } return {}; } size_t LinkerScript::getPhdrIndex(const Twine &Loc, StringRef PhdrName) { size_t I = 0; for (PhdrsCommand &Cmd : Opt.PhdrsCommands) { if (Cmd.Name == PhdrName) return I; ++I; } error(Loc + ": section header '" + PhdrName + "' is not listed in PHDRS"); return 0; } Index: vendor/lld/dist/ELF/SymbolTable.cpp =================================================================== --- vendor/lld/dist/ELF/SymbolTable.cpp (revision 317766) +++ vendor/lld/dist/ELF/SymbolTable.cpp (revision 317767) @@ -1,738 +1,739 @@ //===- SymbolTable.cpp ----------------------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // Symbol table is a bag of all known symbols. We put all symbols of // all input files to the symbol table. The symbol table is basically // a hash table with the logic to resolve symbol name conflicts using // the symbol types. // //===----------------------------------------------------------------------===// #include "SymbolTable.h" #include "Config.h" #include "Error.h" #include "LinkerScript.h" #include "Memory.h" #include "Symbols.h" #include "llvm/ADT/STLExtras.h" using namespace llvm; using namespace llvm::object; using namespace llvm::ELF; using namespace lld; using namespace lld::elf; // All input object files must be for the same architecture // (e.g. it does not make sense to link x86 object files with // MIPS object files.) This function checks for that error. template static bool isCompatible(InputFile *F) { if (!isa>(F) && !isa(F)) return true; if (F->EKind == Config->EKind && F->EMachine == Config->EMachine) { if (Config->EMachine != EM_MIPS) return true; if (isMipsN32Abi(F) == Config->MipsN32Abi) return true; } if (!Config->Emulation.empty()) error(toString(F) + " is incompatible with " + Config->Emulation); else error(toString(F) + " is incompatible with " + toString(Config->FirstElf)); return false; } // Add symbols in File to the symbol table. template void SymbolTable::addFile(InputFile *File) { if (!Config->FirstElf && isa>(File)) Config->FirstElf = File; if (!isCompatible(File)) return; // Binary file if (auto *F = dyn_cast(File)) { BinaryFiles.push_back(F); F->parse(); return; } // .a file if (auto *F = dyn_cast(File)) { F->parse(); return; } // Lazy object file if (auto *F = dyn_cast(File)) { F->parse(); return; } if (Config->Trace) message(toString(File)); // .so file if (auto *F = dyn_cast>(File)) { // DSOs are uniquified not by filename but by soname. F->parseSoName(); if (ErrorCount || !SoNames.insert(F->SoName).second) return; SharedFiles.push_back(F); F->parseRest(); return; } // LLVM bitcode file if (auto *F = dyn_cast(File)) { BitcodeFiles.push_back(F); F->parse(ComdatGroups); return; } // Regular object file auto *F = cast>(File); ObjectFiles.push_back(F); F->parse(ComdatGroups); } // This function is where all the optimizations of link-time // optimization happens. When LTO is in use, some input files are // not in native object file format but in the LLVM bitcode format. // This function compiles bitcode files into a few big native files // using LLVM functions and replaces bitcode symbols with the results. // Because all bitcode files that consist of a program are passed // to the compiler at once, it can do whole-program optimization. template void SymbolTable::addCombinedLTOObject() { if (BitcodeFiles.empty()) return; // Compile bitcode files and replace bitcode symbols. LTO.reset(new BitcodeCompiler); for (BitcodeFile *F : BitcodeFiles) LTO->add(*F); for (InputFile *File : LTO->compile()) { ObjectFile *Obj = cast>(File); DenseSet DummyGroups; Obj->parse(DummyGroups); ObjectFiles.push_back(Obj); } } template DefinedRegular *SymbolTable::addAbsolute(StringRef Name, uint8_t Visibility, uint8_t Binding) { Symbol *Sym = addRegular(Name, Visibility, STT_NOTYPE, 0, 0, Binding, nullptr, nullptr); return cast(Sym->body()); } // Add Name as an "ignored" symbol. An ignored symbol is a regular // linker-synthesized defined symbol, but is only defined if needed. template DefinedRegular *SymbolTable::addIgnored(StringRef Name, uint8_t Visibility) { SymbolBody *S = find(Name); if (!S || S->isInCurrentDSO()) return nullptr; return addAbsolute(Name, Visibility); } // Set a flag for --trace-symbol so that we can print out a log message // if a new symbol with the same name is inserted into the symbol table. template void SymbolTable::trace(StringRef Name) { Symtab.insert({CachedHashStringRef(Name), {-1, true}}); } // Rename SYM as __wrap_SYM. The original symbol is preserved as __real_SYM. // Used to implement --wrap. template void SymbolTable::wrap(StringRef Name) { SymbolBody *B = find(Name); if (!B) return; Symbol *Sym = B->symbol(); Symbol *Real = addUndefined(Saver.save("__real_" + Name)); Symbol *Wrap = addUndefined(Saver.save("__wrap_" + Name)); // We rename symbols by replacing the old symbol's SymbolBody with the new // symbol's SymbolBody. This causes all SymbolBody pointers referring to the // old symbol to instead refer to the new symbol. memcpy(Real->Body.buffer, Sym->Body.buffer, sizeof(Sym->Body)); memcpy(Sym->Body.buffer, Wrap->Body.buffer, sizeof(Wrap->Body)); } // Creates alias for symbol. Used to implement --defsym=ALIAS=SYM. template void SymbolTable::alias(StringRef Alias, StringRef Name) { SymbolBody *B = find(Name); if (!B) { error("-defsym: undefined symbol: " + Name); return; } Symbol *Sym = B->symbol(); Symbol *AliasSym = addUndefined(Alias); memcpy(AliasSym->Body.buffer, Sym->Body.buffer, sizeof(AliasSym->Body)); } static uint8_t getMinVisibility(uint8_t VA, uint8_t VB) { if (VA == STV_DEFAULT) return VB; if (VB == STV_DEFAULT) return VA; return std::min(VA, VB); } // Find an existing symbol or create and insert a new one. template std::pair SymbolTable::insert(StringRef Name) { auto P = Symtab.insert( {CachedHashStringRef(Name), SymIndex((int)SymVector.size(), false)}); SymIndex &V = P.first->second; bool IsNew = P.second; if (V.Idx == -1) { IsNew = true; V = SymIndex((int)SymVector.size(), true); } Symbol *Sym; if (IsNew) { Sym = make(); Sym->InVersionScript = false; Sym->Binding = STB_WEAK; Sym->Visibility = STV_DEFAULT; Sym->IsUsedInRegularObj = false; Sym->ExportDynamic = false; Sym->Traced = V.Traced; Sym->VersionId = Config->DefaultSymbolVersion; SymVector.push_back(Sym); } else { Sym = SymVector[V.Idx]; } return {Sym, IsNew}; } // Find an existing symbol or create and insert a new one, then apply the given // attributes. template std::pair SymbolTable::insert(StringRef Name, uint8_t Type, uint8_t Visibility, bool CanOmitFromDynSym, InputFile *File) { bool IsUsedInRegularObj = !File || File->kind() == InputFile::ObjectKind; Symbol *S; bool WasInserted; std::tie(S, WasInserted) = insert(Name); // Merge in the new symbol's visibility. S->Visibility = getMinVisibility(S->Visibility, Visibility); if (!CanOmitFromDynSym && (Config->Shared || Config->ExportDynamic)) S->ExportDynamic = true; if (IsUsedInRegularObj) S->IsUsedInRegularObj = true; if (!WasInserted && S->body()->Type != SymbolBody::UnknownType && ((Type == STT_TLS) != S->body()->isTls())) { error("TLS attribute mismatch: " + toString(*S->body()) + "\n>>> defined in " + toString(S->body()->File) + "\n>>> defined in " + toString(File)); } return {S, WasInserted}; } template Symbol *SymbolTable::addUndefined(StringRef Name) { return addUndefined(Name, /*IsLocal=*/false, STB_GLOBAL, STV_DEFAULT, /*Type*/ 0, /*CanOmitFromDynSym*/ false, /*File*/ nullptr); } static uint8_t getVisibility(uint8_t StOther) { return StOther & 3; } template Symbol *SymbolTable::addUndefined(StringRef Name, bool IsLocal, uint8_t Binding, uint8_t StOther, uint8_t Type, bool CanOmitFromDynSym, InputFile *File) { Symbol *S; bool WasInserted; uint8_t Visibility = getVisibility(StOther); std::tie(S, WasInserted) = insert(Name, Type, Visibility, CanOmitFromDynSym, File); // An undefined symbol with non default visibility must be satisfied // in the same DSO. if (WasInserted || (isa(S->body()) && Visibility != STV_DEFAULT)) { S->Binding = Binding; replaceBody(S, Name, IsLocal, StOther, Type, File); return S; } if (Binding != STB_WEAK) { - if (S->body()->isShared() || S->body()->isLazy()) + SymbolBody *B = S->body(); + if (B->isShared() || B->isLazy() || B->isUndefined()) S->Binding = Binding; - if (auto *SS = dyn_cast(S->body())) + if (auto *SS = dyn_cast(B)) cast>(SS->File)->IsUsed = true; } if (auto *L = dyn_cast(S->body())) { // An undefined weak will not fetch archive members, but we have to remember // its type. See also comment in addLazyArchive. if (S->isWeak()) L->Type = Type; else if (InputFile *F = L->fetch()) addFile(F); } return S; } // We have a new defined symbol with the specified binding. Return 1 if the new // symbol should win, -1 if the new symbol should lose, or 0 if both symbols are // strong defined symbols. static int compareDefined(Symbol *S, bool WasInserted, uint8_t Binding) { if (WasInserted) return 1; SymbolBody *Body = S->body(); if (Body->isLazy() || !Body->isInCurrentDSO()) return 1; if (Binding == STB_WEAK) return -1; if (S->isWeak()) return 1; return 0; } // We have a new non-common defined symbol with the specified binding. Return 1 // if the new symbol should win, -1 if the new symbol should lose, or 0 if there // is a conflict. If the new symbol wins, also update the binding. template static int compareDefinedNonCommon(Symbol *S, bool WasInserted, uint8_t Binding, bool IsAbsolute, typename ELFT::uint Value) { if (int Cmp = compareDefined(S, WasInserted, Binding)) { if (Cmp > 0) S->Binding = Binding; return Cmp; } SymbolBody *B = S->body(); if (isa(B)) { // Non-common symbols take precedence over common symbols. if (Config->WarnCommon) warn("common " + S->body()->getName() + " is overridden"); return 1; } else if (auto *R = dyn_cast(B)) { if (R->Section == nullptr && Binding == STB_GLOBAL && IsAbsolute && R->Value == Value) return -1; } return 0; } template Symbol *SymbolTable::addCommon(StringRef N, uint64_t Size, uint32_t Alignment, uint8_t Binding, uint8_t StOther, uint8_t Type, InputFile *File) { Symbol *S; bool WasInserted; std::tie(S, WasInserted) = insert(N, Type, getVisibility(StOther), /*CanOmitFromDynSym*/ false, File); int Cmp = compareDefined(S, WasInserted, Binding); if (Cmp > 0) { S->Binding = Binding; replaceBody(S, N, Size, Alignment, StOther, Type, File); } else if (Cmp == 0) { auto *C = dyn_cast(S->body()); if (!C) { // Non-common symbols take precedence over common symbols. if (Config->WarnCommon) warn("common " + S->body()->getName() + " is overridden"); return S; } if (Config->WarnCommon) warn("multiple common of " + S->body()->getName()); Alignment = C->Alignment = std::max(C->Alignment, Alignment); if (Size > C->Size) replaceBody(S, N, Size, Alignment, StOther, Type, File); } return S; } static void warnOrError(const Twine &Msg) { if (Config->AllowMultipleDefinition) warn(Msg); else error(Msg); } static void reportDuplicate(SymbolBody *Sym, InputFile *NewFile) { warnOrError("duplicate symbol: " + toString(*Sym) + "\n>>> defined in " + toString(Sym->File) + "\n>>> defined in " + toString(NewFile)); } template static void reportDuplicate(SymbolBody *Sym, InputSectionBase *ErrSec, typename ELFT::uint ErrOffset) { DefinedRegular *D = dyn_cast(Sym); if (!D || !D->Section || !ErrSec) { reportDuplicate(Sym, ErrSec ? ErrSec->getFile() : nullptr); return; } // Construct and print an error message in the form of: // // ld.lld: error: duplicate symbol: foo // >>> defined at bar.c:30 // >>> bar.o (/home/alice/src/bar.o) // >>> defined at baz.c:563 // >>> baz.o in archive libbaz.a auto *Sec1 = cast(D->Section); std::string Src1 = Sec1->getSrcMsg(D->Value); std::string Obj1 = Sec1->getObjMsg(D->Value); std::string Src2 = ErrSec->getSrcMsg(ErrOffset); std::string Obj2 = ErrSec->getObjMsg(ErrOffset); std::string Msg = "duplicate symbol: " + toString(*Sym) + "\n>>> defined at "; if (!Src1.empty()) Msg += Src1 + "\n>>> "; Msg += Obj1 + "\n>>> defined at "; if (!Src2.empty()) Msg += Src2 + "\n>>> "; Msg += Obj2; warnOrError(Msg); } template Symbol *SymbolTable::addRegular(StringRef Name, uint8_t StOther, uint8_t Type, uint64_t Value, uint64_t Size, uint8_t Binding, SectionBase *Section, InputFile *File) { Symbol *S; bool WasInserted; std::tie(S, WasInserted) = insert(Name, Type, getVisibility(StOther), /*CanOmitFromDynSym*/ false, File); int Cmp = compareDefinedNonCommon(S, WasInserted, Binding, Section == nullptr, Value); if (Cmp > 0) replaceBody(S, Name, /*IsLocal=*/false, StOther, Type, Value, Size, Section, File); else if (Cmp == 0) reportDuplicate(S->body(), dyn_cast_or_null(Section), Value); return S; } template void SymbolTable::addShared(SharedFile *File, StringRef Name, const Elf_Sym &Sym, const typename ELFT::Verdef *Verdef) { // DSO symbols do not affect visibility in the output, so we pass STV_DEFAULT // as the visibility, which will leave the visibility in the symbol table // unchanged. Symbol *S; bool WasInserted; std::tie(S, WasInserted) = insert(Name, Sym.getType(), STV_DEFAULT, /*CanOmitFromDynSym*/ true, File); // Make sure we preempt DSO symbols with default visibility. if (Sym.getVisibility() == STV_DEFAULT) S->ExportDynamic = true; SymbolBody *Body = S->body(); // An undefined symbol with non default visibility must be satisfied // in the same DSO. if (WasInserted || (isa(Body) && Body->getVisibility() == STV_DEFAULT)) { replaceBody(S, File, Name, Sym.st_other, Sym.getType(), &Sym, Verdef); if (!S->isWeak()) File->IsUsed = true; } } template Symbol *SymbolTable::addBitcode(StringRef Name, uint8_t Binding, uint8_t StOther, uint8_t Type, bool CanOmitFromDynSym, BitcodeFile *F) { Symbol *S; bool WasInserted; std::tie(S, WasInserted) = insert(Name, Type, getVisibility(StOther), CanOmitFromDynSym, F); int Cmp = compareDefinedNonCommon(S, WasInserted, Binding, /*IsAbs*/ false, /*Value*/ 0); if (Cmp > 0) replaceBody(S, Name, /*IsLocal=*/false, StOther, Type, 0, 0, nullptr, F); else if (Cmp == 0) reportDuplicate(S->body(), F); return S; } template SymbolBody *SymbolTable::find(StringRef Name) { auto It = Symtab.find(CachedHashStringRef(Name)); if (It == Symtab.end()) return nullptr; SymIndex V = It->second; if (V.Idx == -1) return nullptr; return SymVector[V.Idx]->body(); } template SymbolBody *SymbolTable::findInCurrentDSO(StringRef Name) { if (SymbolBody *S = find(Name)) if (S->isInCurrentDSO()) return S; return nullptr; } template void SymbolTable::addLazyArchive(ArchiveFile *F, const object::Archive::Symbol Sym) { Symbol *S; bool WasInserted; StringRef Name = Sym.getName(); std::tie(S, WasInserted) = insert(Name); if (WasInserted) { replaceBody(S, *F, Sym, SymbolBody::UnknownType); return; } if (!S->body()->isUndefined()) return; // Weak undefined symbols should not fetch members from archives. If we were // to keep old symbol we would not know that an archive member was available // if a strong undefined symbol shows up afterwards in the link. If a strong // undefined symbol never shows up, this lazy symbol will get to the end of // the link and must be treated as the weak undefined one. We already marked // this symbol as used when we added it to the symbol table, but we also need // to preserve its type. FIXME: Move the Type field to Symbol. if (S->isWeak()) { replaceBody(S, *F, Sym, S->body()->Type); return; } std::pair MBInfo = F->getMember(&Sym); if (!MBInfo.first.getBuffer().empty()) addFile(createObjectFile(MBInfo.first, F->getName(), MBInfo.second)); } template void SymbolTable::addLazyObject(StringRef Name, LazyObjectFile &Obj) { Symbol *S; bool WasInserted; std::tie(S, WasInserted) = insert(Name); if (WasInserted) { replaceBody(S, Name, Obj, SymbolBody::UnknownType); return; } if (!S->body()->isUndefined()) return; // See comment for addLazyArchive above. if (S->isWeak()) { replaceBody(S, Name, Obj, S->body()->Type); } else { MemoryBufferRef MBRef = Obj.getBuffer(); if (!MBRef.getBuffer().empty()) addFile(createObjectFile(MBRef)); } } // Process undefined (-u) flags by loading lazy symbols named by those flags. template void SymbolTable::scanUndefinedFlags() { for (StringRef S : Config->Undefined) if (auto *L = dyn_cast_or_null(find(S))) if (InputFile *File = L->fetch()) addFile(File); } // This function takes care of the case in which shared libraries depend on // the user program (not the other way, which is usual). Shared libraries // may have undefined symbols, expecting that the user program provides // the definitions for them. An example is BSD's __progname symbol. // We need to put such symbols to the main program's .dynsym so that // shared libraries can find them. // Except this, we ignore undefined symbols in DSOs. template void SymbolTable::scanShlibUndefined() { for (SharedFile *File : SharedFiles) { for (StringRef U : File->getUndefinedSymbols()) { SymbolBody *Sym = find(U); if (!Sym || !Sym->isDefined()) continue; Sym->symbol()->ExportDynamic = true; // If -dynamic-list is given, the default version is set to // VER_NDX_LOCAL, which prevents a symbol to be exported via .dynsym. // Set to VER_NDX_GLOBAL so the symbol will be handled as if it were // specified by -dynamic-list. Sym->symbol()->VersionId = VER_NDX_GLOBAL; } } } // Initialize DemangledSyms with a map from demangled symbols to symbol // objects. Used to handle "extern C++" directive in version scripts. // // The map will contain all demangled symbols. That can be very large, // and in LLD we generally want to avoid do anything for each symbol. // Then, why are we doing this? Here's why. // // Users can use "extern C++ {}" directive to match against demangled // C++ symbols. For example, you can write a pattern such as // "llvm::*::foo(int, ?)". Obviously, there's no way to handle this // other than trying to match a pattern against all demangled symbols. // So, if "extern C++" feature is used, we need to demangle all known // symbols. template StringMap> &SymbolTable::getDemangledSyms() { if (!DemangledSyms) { DemangledSyms.emplace(); for (Symbol *Sym : SymVector) { SymbolBody *B = Sym->body(); if (B->isUndefined()) continue; if (Optional S = demangle(B->getName())) (*DemangledSyms)[*S].push_back(B); else (*DemangledSyms)[B->getName()].push_back(B); } } return *DemangledSyms; } template std::vector SymbolTable::findByVersion(SymbolVersion Ver) { if (Ver.IsExternCpp) return getDemangledSyms().lookup(Ver.Name); if (SymbolBody *B = find(Ver.Name)) if (!B->isUndefined()) return {B}; return {}; } template std::vector SymbolTable::findAllByVersion(SymbolVersion Ver) { std::vector Res; StringMatcher M(Ver.Name); if (Ver.IsExternCpp) { for (auto &P : getDemangledSyms()) if (M.match(P.first())) Res.insert(Res.end(), P.second.begin(), P.second.end()); return Res; } for (Symbol *Sym : SymVector) { SymbolBody *B = Sym->body(); if (!B->isUndefined() && M.match(B->getName())) Res.push_back(B); } return Res; } // If there's only one anonymous version definition in a version // script file, the script does not actually define any symbol version, // but just specifies symbols visibilities. template void SymbolTable::handleAnonymousVersion() { for (SymbolVersion &Ver : Config->VersionScriptGlobals) assignExactVersion(Ver, VER_NDX_GLOBAL, "global"); for (SymbolVersion &Ver : Config->VersionScriptGlobals) assignWildcardVersion(Ver, VER_NDX_GLOBAL); for (SymbolVersion &Ver : Config->VersionScriptLocals) assignExactVersion(Ver, VER_NDX_LOCAL, "local"); for (SymbolVersion &Ver : Config->VersionScriptLocals) assignWildcardVersion(Ver, VER_NDX_LOCAL); } // Set symbol versions to symbols. This function handles patterns // containing no wildcard characters. template void SymbolTable::assignExactVersion(SymbolVersion Ver, uint16_t VersionId, StringRef VersionName) { if (Ver.HasWildcard) return; // Get a list of symbols which we need to assign the version to. std::vector Syms = findByVersion(Ver); if (Syms.empty()) { if (Config->NoUndefinedVersion) error("version script assignment of '" + VersionName + "' to symbol '" + Ver.Name + "' failed: symbol not defined"); return; } // Assign the version. for (SymbolBody *B : Syms) { Symbol *Sym = B->symbol(); if (Sym->InVersionScript) warn("duplicate symbol '" + Ver.Name + "' in version script"); Sym->VersionId = VersionId; Sym->InVersionScript = true; } } template void SymbolTable::assignWildcardVersion(SymbolVersion Ver, uint16_t VersionId) { if (!Ver.HasWildcard) return; std::vector Syms = findAllByVersion(Ver); // Exact matching takes precendence over fuzzy matching, // so we set a version to a symbol only if no version has been assigned // to the symbol. This behavior is compatible with GNU. for (SymbolBody *B : Syms) if (B->symbol()->VersionId == Config->DefaultSymbolVersion) B->symbol()->VersionId = VersionId; } // This function processes version scripts by updating VersionId // member of symbols. template void SymbolTable::scanVersionScript() { // Symbol themselves might know their versions because symbols // can contain versions in the form of @. // Let them parse their names. if (!Config->VersionDefinitions.empty()) for (Symbol *Sym : SymVector) Sym->body()->parseSymbolVersion(); // Handle edge cases first. handleAnonymousVersion(); if (Config->VersionDefinitions.empty()) return; // Now we have version definitions, so we need to set version ids to symbols. // Each version definition has a glob pattern, and all symbols that match // with the pattern get that version. // First, we assign versions to exact matching symbols, // i.e. version definitions not containing any glob meta-characters. for (VersionDefinition &V : Config->VersionDefinitions) for (SymbolVersion &Ver : V.Globals) assignExactVersion(Ver, V.Id, V.Name); // Next, we assign versions to fuzzy matching symbols, // i.e. version definitions containing glob meta-characters. // Note that because the last match takes precedence over previous matches, // we iterate over the definitions in the reverse order. for (VersionDefinition &V : llvm::reverse(Config->VersionDefinitions)) for (SymbolVersion &Ver : V.Globals) assignWildcardVersion(Ver, V.Id); } template class elf::SymbolTable; template class elf::SymbolTable; template class elf::SymbolTable; template class elf::SymbolTable; Index: vendor/lld/dist/ELF/Target.cpp =================================================================== --- vendor/lld/dist/ELF/Target.cpp (revision 317766) +++ vendor/lld/dist/ELF/Target.cpp (revision 317767) @@ -1,2437 +1,2437 @@ //===- Target.cpp ---------------------------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // Machine-specific things, such as applying relocations, creation of // GOT or PLT entries, etc., are handled in this file. // // Refer the ELF spec for the single letter variables, S, A or P, used // in this file. // // Some functions defined in this file has "relaxTls" as part of their names. // They do peephole optimization for TLS variables by rewriting instructions. // They are not part of the ABI but optional optimization, so you can skip // them if you are not interested in how TLS variables are optimized. // See the following paper for the details. // // Ulrich Drepper, ELF Handling For Thread-Local Storage // http://www.akkadia.org/drepper/tls.pdf // //===----------------------------------------------------------------------===// #include "Target.h" #include "Error.h" #include "InputFiles.h" #include "Memory.h" #include "OutputSections.h" #include "SymbolTable.h" #include "Symbols.h" #include "SyntheticSections.h" #include "Thunks.h" #include "Writer.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/Object/ELF.h" #include "llvm/Support/ELF.h" #include "llvm/Support/Endian.h" using namespace llvm; using namespace llvm::object; using namespace llvm::support::endian; using namespace llvm::ELF; std::string lld::toString(uint32_t Type) { StringRef S = getELFRelocationTypeName(elf::Config->EMachine, Type); if (S == "Unknown") return ("Unknown (" + Twine(Type) + ")").str(); return S; } namespace lld { namespace elf { TargetInfo *Target; static void or32le(uint8_t *P, int32_t V) { write32le(P, read32le(P) | V); } static void or32be(uint8_t *P, int32_t V) { write32be(P, read32be(P) | V); } template static std::string getErrorLoc(const uint8_t *Loc) { for (InputSectionBase *D : InputSections) { auto *IS = dyn_cast_or_null(D); if (!IS || !IS->OutSec) continue; uint8_t *ISLoc = cast(IS->OutSec)->Loc + IS->OutSecOff; if (ISLoc <= Loc && Loc < ISLoc + IS->getSize()) return IS->template getLocation(Loc - ISLoc) + ": "; } return ""; } static std::string getErrorLocation(const uint8_t *Loc) { switch (Config->EKind) { case ELF32LEKind: return getErrorLoc(Loc); case ELF32BEKind: return getErrorLoc(Loc); case ELF64LEKind: return getErrorLoc(Loc); case ELF64BEKind: return getErrorLoc(Loc); default: llvm_unreachable("unknown ELF type"); } } template static void checkInt(uint8_t *Loc, int64_t V, uint32_t Type) { if (!isInt(V)) error(getErrorLocation(Loc) + "relocation " + toString(Type) + " out of range"); } template static void checkUInt(uint8_t *Loc, uint64_t V, uint32_t Type) { if (!isUInt(V)) error(getErrorLocation(Loc) + "relocation " + toString(Type) + " out of range"); } template static void checkIntUInt(uint8_t *Loc, uint64_t V, uint32_t Type) { if (!isInt(V) && !isUInt(V)) error(getErrorLocation(Loc) + "relocation " + toString(Type) + " out of range"); } template static void checkAlignment(uint8_t *Loc, uint64_t V, uint32_t Type) { if ((V & (N - 1)) != 0) error(getErrorLocation(Loc) + "improper alignment for relocation " + toString(Type)); } namespace { class X86TargetInfo final : public TargetInfo { public: X86TargetInfo(); RelExpr getRelExpr(uint32_t Type, const SymbolBody &S, const uint8_t *Loc) const override; int64_t getImplicitAddend(const uint8_t *Buf, uint32_t Type) const override; void writeGotPltHeader(uint8_t *Buf) const override; uint32_t getDynRel(uint32_t Type) const override; bool isTlsLocalDynamicRel(uint32_t Type) const override; bool isTlsInitialExecRel(uint32_t Type) const override; void writeGotPlt(uint8_t *Buf, const SymbolBody &S) const override; void writeIgotPlt(uint8_t *Buf, const SymbolBody &S) const override; void writePltHeader(uint8_t *Buf) const override; void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const override; void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; RelExpr adjustRelaxExpr(uint32_t Type, const uint8_t *Data, RelExpr Expr) const override; void relaxTlsGdToIe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; void relaxTlsGdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; void relaxTlsIeToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; void relaxTlsLdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; }; template class X86_64TargetInfo final : public TargetInfo { public: X86_64TargetInfo(); RelExpr getRelExpr(uint32_t Type, const SymbolBody &S, const uint8_t *Loc) const override; bool isPicRel(uint32_t Type) const override; bool isTlsLocalDynamicRel(uint32_t Type) const override; bool isTlsInitialExecRel(uint32_t Type) const override; void writeGotPltHeader(uint8_t *Buf) const override; void writeGotPlt(uint8_t *Buf, const SymbolBody &S) const override; void writePltHeader(uint8_t *Buf) const override; void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const override; void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; RelExpr adjustRelaxExpr(uint32_t Type, const uint8_t *Data, RelExpr Expr) const override; void relaxGot(uint8_t *Loc, uint64_t Val) const override; void relaxTlsGdToIe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; void relaxTlsGdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; void relaxTlsIeToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; void relaxTlsLdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; private: void relaxGotNoPic(uint8_t *Loc, uint64_t Val, uint8_t Op, uint8_t ModRm) const; }; class PPCTargetInfo final : public TargetInfo { public: PPCTargetInfo(); void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; RelExpr getRelExpr(uint32_t Type, const SymbolBody &S, const uint8_t *Loc) const override; }; class PPC64TargetInfo final : public TargetInfo { public: PPC64TargetInfo(); RelExpr getRelExpr(uint32_t Type, const SymbolBody &S, const uint8_t *Loc) const override; void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const override; void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; }; class AArch64TargetInfo final : public TargetInfo { public: AArch64TargetInfo(); RelExpr getRelExpr(uint32_t Type, const SymbolBody &S, const uint8_t *Loc) const override; bool isPicRel(uint32_t Type) const override; bool isTlsInitialExecRel(uint32_t Type) const override; void writeGotPlt(uint8_t *Buf, const SymbolBody &S) const override; void writePltHeader(uint8_t *Buf) const override; void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const override; bool usesOnlyLowPageBits(uint32_t Type) const override; void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; RelExpr adjustRelaxExpr(uint32_t Type, const uint8_t *Data, RelExpr Expr) const override; void relaxTlsGdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; void relaxTlsGdToIe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; void relaxTlsIeToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; }; class AMDGPUTargetInfo final : public TargetInfo { public: AMDGPUTargetInfo(); void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; RelExpr getRelExpr(uint32_t Type, const SymbolBody &S, const uint8_t *Loc) const override; }; class ARMTargetInfo final : public TargetInfo { public: ARMTargetInfo(); RelExpr getRelExpr(uint32_t Type, const SymbolBody &S, const uint8_t *Loc) const override; bool isPicRel(uint32_t Type) const override; uint32_t getDynRel(uint32_t Type) const override; int64_t getImplicitAddend(const uint8_t *Buf, uint32_t Type) const override; void writeGotPlt(uint8_t *Buf, const SymbolBody &S) const override; void writeIgotPlt(uint8_t *Buf, const SymbolBody &S) const override; void writePltHeader(uint8_t *Buf) const override; void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const override; void addPltSymbols(InputSectionBase *IS, uint64_t Off) const override; void addPltHeaderSymbols(InputSectionBase *ISD) const override; bool needsThunk(RelExpr Expr, uint32_t RelocType, const InputFile *File, const SymbolBody &S) const override; void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; }; template class MipsTargetInfo final : public TargetInfo { public: MipsTargetInfo(); RelExpr getRelExpr(uint32_t Type, const SymbolBody &S, const uint8_t *Loc) const override; int64_t getImplicitAddend(const uint8_t *Buf, uint32_t Type) const override; bool isPicRel(uint32_t Type) const override; uint32_t getDynRel(uint32_t Type) const override; void writeGotPlt(uint8_t *Buf, const SymbolBody &S) const override; void writePltHeader(uint8_t *Buf) const override; void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const override; bool needsThunk(RelExpr Expr, uint32_t RelocType, const InputFile *File, const SymbolBody &S) const override; void relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const override; bool usesOnlyLowPageBits(uint32_t Type) const override; }; } // anonymous namespace TargetInfo *createTarget() { switch (Config->EMachine) { case EM_386: case EM_IAMCU: return make(); case EM_AARCH64: return make(); case EM_AMDGPU: return make(); case EM_ARM: return make(); case EM_MIPS: switch (Config->EKind) { case ELF32LEKind: return make>(); case ELF32BEKind: return make>(); case ELF64LEKind: return make>(); case ELF64BEKind: return make>(); default: fatal("unsupported MIPS target"); } case EM_PPC: return make(); case EM_PPC64: return make(); case EM_X86_64: if (Config->EKind == ELF32LEKind) return make>(); return make>(); } fatal("unknown target machine"); } TargetInfo::~TargetInfo() {} int64_t TargetInfo::getImplicitAddend(const uint8_t *Buf, uint32_t Type) const { return 0; } bool TargetInfo::usesOnlyLowPageBits(uint32_t Type) const { return false; } bool TargetInfo::needsThunk(RelExpr Expr, uint32_t RelocType, const InputFile *File, const SymbolBody &S) const { return false; } bool TargetInfo::isTlsInitialExecRel(uint32_t Type) const { return false; } bool TargetInfo::isTlsLocalDynamicRel(uint32_t Type) const { return false; } void TargetInfo::writeIgotPlt(uint8_t *Buf, const SymbolBody &S) const { writeGotPlt(Buf, S); } RelExpr TargetInfo::adjustRelaxExpr(uint32_t Type, const uint8_t *Data, RelExpr Expr) const { return Expr; } void TargetInfo::relaxGot(uint8_t *Loc, uint64_t Val) const { llvm_unreachable("Should not have claimed to be relaxable"); } void TargetInfo::relaxTlsGdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const { llvm_unreachable("Should not have claimed to be relaxable"); } void TargetInfo::relaxTlsGdToIe(uint8_t *Loc, uint32_t Type, uint64_t Val) const { llvm_unreachable("Should not have claimed to be relaxable"); } void TargetInfo::relaxTlsIeToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const { llvm_unreachable("Should not have claimed to be relaxable"); } void TargetInfo::relaxTlsLdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const { llvm_unreachable("Should not have claimed to be relaxable"); } X86TargetInfo::X86TargetInfo() { CopyRel = R_386_COPY; GotRel = R_386_GLOB_DAT; PltRel = R_386_JUMP_SLOT; IRelativeRel = R_386_IRELATIVE; RelativeRel = R_386_RELATIVE; TlsGotRel = R_386_TLS_TPOFF; TlsModuleIndexRel = R_386_TLS_DTPMOD32; TlsOffsetRel = R_386_TLS_DTPOFF32; GotEntrySize = 4; GotPltEntrySize = 4; PltEntrySize = 16; PltHeaderSize = 16; TlsGdRelaxSkip = 2; // 0xCC is the "int3" (call debug exception handler) instruction. TrapInstr = 0xcccccccc; } RelExpr X86TargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S, const uint8_t *Loc) const { switch (Type) { case R_386_8: case R_386_16: case R_386_32: case R_386_TLS_LDO_32: return R_ABS; case R_386_TLS_GD: return R_TLSGD; case R_386_TLS_LDM: return R_TLSLD; case R_386_PLT32: return R_PLT_PC; case R_386_PC8: case R_386_PC16: case R_386_PC32: return R_PC; case R_386_GOTPC: return R_GOTONLY_PC_FROM_END; case R_386_TLS_IE: return R_GOT; case R_386_GOT32: case R_386_GOT32X: // These relocations can be calculated in two different ways. // Usual calculation is G + A - GOT what means an offset in GOT table // (R_GOT_FROM_END). When instruction pointed by relocation has no base // register, then relocations can be used when PIC code is disabled. In that // case calculation is G + A, it resolves to an address of entry in GOT // (R_GOT) and not an offset. // // To check that instruction has no base register we scan ModR/M byte. // See "Table 2-2. 32-Bit Addressing Forms with the ModR/M Byte" // (http://www.intel.com/content/dam/www/public/us/en/documents/manuals/ // 64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf) if ((Loc[-1] & 0xc7) != 0x5) return R_GOT_FROM_END; if (Config->Pic) error(toString(S.File) + ": relocation " + toString(Type) + " against '" + S.getName() + "' without base register can not be used when PIC enabled"); return R_GOT; case R_386_TLS_GOTIE: return R_GOT_FROM_END; case R_386_GOTOFF: return R_GOTREL_FROM_END; case R_386_TLS_LE: return R_TLS; case R_386_TLS_LE_32: return R_NEG_TLS; case R_386_NONE: return R_NONE; default: error(toString(S.File) + ": unknown relocation type: " + toString(Type)); return R_HINT; } } RelExpr X86TargetInfo::adjustRelaxExpr(uint32_t Type, const uint8_t *Data, RelExpr Expr) const { switch (Expr) { default: return Expr; case R_RELAX_TLS_GD_TO_IE: return R_RELAX_TLS_GD_TO_IE_END; case R_RELAX_TLS_GD_TO_LE: return R_RELAX_TLS_GD_TO_LE_NEG; } } void X86TargetInfo::writeGotPltHeader(uint8_t *Buf) const { write32le(Buf, In::Dynamic->getVA()); } void X86TargetInfo::writeGotPlt(uint8_t *Buf, const SymbolBody &S) const { // Entries in .got.plt initially points back to the corresponding // PLT entries with a fixed offset to skip the first instruction. write32le(Buf, S.getPltVA() + 6); } void X86TargetInfo::writeIgotPlt(uint8_t *Buf, const SymbolBody &S) const { // An x86 entry is the address of the ifunc resolver function. write32le(Buf, S.getVA()); } uint32_t X86TargetInfo::getDynRel(uint32_t Type) const { if (Type == R_386_TLS_LE) return R_386_TLS_TPOFF; if (Type == R_386_TLS_LE_32) return R_386_TLS_TPOFF32; return Type; } bool X86TargetInfo::isTlsLocalDynamicRel(uint32_t Type) const { return Type == R_386_TLS_LDO_32 || Type == R_386_TLS_LDM; } bool X86TargetInfo::isTlsInitialExecRel(uint32_t Type) const { return Type == R_386_TLS_IE || Type == R_386_TLS_GOTIE; } void X86TargetInfo::writePltHeader(uint8_t *Buf) const { if (Config->Pic) { const uint8_t V[] = { 0xff, 0xb3, 0x04, 0x00, 0x00, 0x00, // pushl GOTPLT+4(%ebx) 0xff, 0xa3, 0x08, 0x00, 0x00, 0x00, // jmp *GOTPLT+8(%ebx) 0x90, 0x90, 0x90, 0x90 // nop }; memcpy(Buf, V, sizeof(V)); uint32_t Ebx = In::Got->getVA() + In::Got->getSize(); uint32_t GotPlt = In::GotPlt->getVA() - Ebx; write32le(Buf + 2, GotPlt + 4); write32le(Buf + 8, GotPlt + 8); return; } const uint8_t PltData[] = { 0xff, 0x35, 0x00, 0x00, 0x00, 0x00, // pushl (GOTPLT+4) 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *(GOTPLT+8) 0x90, 0x90, 0x90, 0x90 // nop }; memcpy(Buf, PltData, sizeof(PltData)); uint32_t GotPlt = In::GotPlt->getVA(); write32le(Buf + 2, GotPlt + 4); write32le(Buf + 8, GotPlt + 8); } void X86TargetInfo::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const { const uint8_t Inst[] = { 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, // jmp *foo_in_GOT|*foo@GOT(%ebx) 0x68, 0x00, 0x00, 0x00, 0x00, // pushl $reloc_offset 0xe9, 0x00, 0x00, 0x00, 0x00 // jmp .PLT0@PC }; memcpy(Buf, Inst, sizeof(Inst)); if (Config->Pic) { // jmp *foo@GOT(%ebx) uint32_t Ebx = In::Got->getVA() + In::Got->getSize(); Buf[1] = 0xa3; write32le(Buf + 2, GotPltEntryAddr - Ebx); } else { // jmp *foo_in_GOT Buf[1] = 0x25; write32le(Buf + 2, GotPltEntryAddr); } write32le(Buf + 7, RelOff); write32le(Buf + 12, -Index * PltEntrySize - PltHeaderSize - 16); } int64_t X86TargetInfo::getImplicitAddend(const uint8_t *Buf, uint32_t Type) const { switch (Type) { default: return 0; case R_386_8: case R_386_PC8: return SignExtend64<8>(*Buf); case R_386_16: case R_386_PC16: return SignExtend64<16>(read16le(Buf)); case R_386_32: case R_386_GOT32: case R_386_GOT32X: case R_386_GOTOFF: case R_386_GOTPC: case R_386_PC32: case R_386_PLT32: case R_386_TLS_LDO_32: case R_386_TLS_LE: return SignExtend64<32>(read32le(Buf)); } } void X86TargetInfo::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const { // R_386_{PC,}{8,16} are not part of the i386 psABI, but they are // being used for some 16-bit programs such as boot loaders, so // we want to support them. switch (Type) { case R_386_8: checkUInt<8>(Loc, Val, Type); *Loc = Val; break; case R_386_PC8: checkInt<8>(Loc, Val, Type); *Loc = Val; break; case R_386_16: checkUInt<16>(Loc, Val, Type); write16le(Loc, Val); break; case R_386_PC16: checkInt<16>(Loc, Val, Type); write16le(Loc, Val); break; default: checkInt<32>(Loc, Val, Type); write32le(Loc, Val); } } void X86TargetInfo::relaxTlsGdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const { // Convert // leal x@tlsgd(, %ebx, 1), // call __tls_get_addr@plt // to // movl %gs:0,%eax // subl $x@ntpoff,%eax const uint8_t Inst[] = { 0x65, 0xa1, 0x00, 0x00, 0x00, 0x00, // movl %gs:0, %eax 0x81, 0xe8, 0x00, 0x00, 0x00, 0x00 // subl 0(%ebx), %eax }; memcpy(Loc - 3, Inst, sizeof(Inst)); write32le(Loc + 5, Val); } void X86TargetInfo::relaxTlsGdToIe(uint8_t *Loc, uint32_t Type, uint64_t Val) const { // Convert // leal x@tlsgd(, %ebx, 1), // call __tls_get_addr@plt // to // movl %gs:0, %eax // addl x@gotntpoff(%ebx), %eax const uint8_t Inst[] = { 0x65, 0xa1, 0x00, 0x00, 0x00, 0x00, // movl %gs:0, %eax 0x03, 0x83, 0x00, 0x00, 0x00, 0x00 // addl 0(%ebx), %eax }; memcpy(Loc - 3, Inst, sizeof(Inst)); write32le(Loc + 5, Val); } // In some conditions, relocations can be optimized to avoid using GOT. // This function does that for Initial Exec to Local Exec case. void X86TargetInfo::relaxTlsIeToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const { // Ulrich's document section 6.2 says that @gotntpoff can // be used with MOVL or ADDL instructions. // @indntpoff is similar to @gotntpoff, but for use in // position dependent code. uint8_t Reg = (Loc[-1] >> 3) & 7; if (Type == R_386_TLS_IE) { if (Loc[-1] == 0xa1) { // "movl foo@indntpoff,%eax" -> "movl $foo,%eax" // This case is different from the generic case below because // this is a 5 byte instruction while below is 6 bytes. Loc[-1] = 0xb8; } else if (Loc[-2] == 0x8b) { // "movl foo@indntpoff,%reg" -> "movl $foo,%reg" Loc[-2] = 0xc7; Loc[-1] = 0xc0 | Reg; } else { // "addl foo@indntpoff,%reg" -> "addl $foo,%reg" Loc[-2] = 0x81; Loc[-1] = 0xc0 | Reg; } } else { assert(Type == R_386_TLS_GOTIE); if (Loc[-2] == 0x8b) { // "movl foo@gottpoff(%rip),%reg" -> "movl $foo,%reg" Loc[-2] = 0xc7; Loc[-1] = 0xc0 | Reg; } else { // "addl foo@gotntpoff(%rip),%reg" -> "leal foo(%reg),%reg" Loc[-2] = 0x8d; Loc[-1] = 0x80 | (Reg << 3) | Reg; } } write32le(Loc, Val); } void X86TargetInfo::relaxTlsLdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const { if (Type == R_386_TLS_LDO_32) { write32le(Loc, Val); return; } // Convert // leal foo(%reg),%eax // call ___tls_get_addr // to // movl %gs:0,%eax // nop // leal 0(%esi,1),%esi const uint8_t Inst[] = { 0x65, 0xa1, 0x00, 0x00, 0x00, 0x00, // movl %gs:0,%eax 0x90, // nop 0x8d, 0x74, 0x26, 0x00 // leal 0(%esi,1),%esi }; memcpy(Loc - 2, Inst, sizeof(Inst)); } template X86_64TargetInfo::X86_64TargetInfo() { CopyRel = R_X86_64_COPY; GotRel = R_X86_64_GLOB_DAT; PltRel = R_X86_64_JUMP_SLOT; RelativeRel = R_X86_64_RELATIVE; IRelativeRel = R_X86_64_IRELATIVE; TlsGotRel = R_X86_64_TPOFF64; TlsModuleIndexRel = R_X86_64_DTPMOD64; TlsOffsetRel = R_X86_64_DTPOFF64; GotEntrySize = 8; GotPltEntrySize = 8; PltEntrySize = 16; PltHeaderSize = 16; TlsGdRelaxSkip = 2; // Align to the large page size (known as a superpage or huge page). // FreeBSD automatically promotes large, superpage-aligned allocations. DefaultImageBase = 0x200000; // 0xCC is the "int3" (call debug exception handler) instruction. TrapInstr = 0xcccccccc; } template RelExpr X86_64TargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S, const uint8_t *Loc) const { switch (Type) { case R_X86_64_8: case R_X86_64_16: case R_X86_64_32: case R_X86_64_32S: case R_X86_64_64: case R_X86_64_DTPOFF32: case R_X86_64_DTPOFF64: return R_ABS; case R_X86_64_TPOFF32: return R_TLS; case R_X86_64_TLSLD: return R_TLSLD_PC; case R_X86_64_TLSGD: return R_TLSGD_PC; case R_X86_64_SIZE32: case R_X86_64_SIZE64: return R_SIZE; case R_X86_64_PLT32: return R_PLT_PC; case R_X86_64_PC32: case R_X86_64_PC64: return R_PC; case R_X86_64_GOT32: case R_X86_64_GOT64: return R_GOT_FROM_END; case R_X86_64_GOTPCREL: case R_X86_64_GOTPCRELX: case R_X86_64_REX_GOTPCRELX: case R_X86_64_GOTTPOFF: return R_GOT_PC; case R_X86_64_NONE: return R_NONE; default: error(toString(S.File) + ": unknown relocation type: " + toString(Type)); return R_HINT; } } template void X86_64TargetInfo::writeGotPltHeader(uint8_t *Buf) const { // The first entry holds the value of _DYNAMIC. It is not clear why that is // required, but it is documented in the psabi and the glibc dynamic linker // seems to use it (note that this is relevant for linking ld.so, not any // other program). write64le(Buf, In::Dynamic->getVA()); } template void X86_64TargetInfo::writeGotPlt(uint8_t *Buf, const SymbolBody &S) const { // See comments in X86TargetInfo::writeGotPlt. write32le(Buf, S.getPltVA() + 6); } template void X86_64TargetInfo::writePltHeader(uint8_t *Buf) const { const uint8_t PltData[] = { 0xff, 0x35, 0x00, 0x00, 0x00, 0x00, // pushq GOTPLT+8(%rip) 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *GOTPLT+16(%rip) 0x0f, 0x1f, 0x40, 0x00 // nop }; memcpy(Buf, PltData, sizeof(PltData)); uint64_t GotPlt = In::GotPlt->getVA(); uint64_t Plt = In::Plt->getVA(); write32le(Buf + 2, GotPlt - Plt + 2); // GOTPLT+8 write32le(Buf + 8, GotPlt - Plt + 4); // GOTPLT+16 } template void X86_64TargetInfo::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const { const uint8_t Inst[] = { 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmpq *got(%rip) 0x68, 0x00, 0x00, 0x00, 0x00, // pushq 0xe9, 0x00, 0x00, 0x00, 0x00 // jmpq plt[0] }; memcpy(Buf, Inst, sizeof(Inst)); write32le(Buf + 2, GotPltEntryAddr - PltEntryAddr - 6); write32le(Buf + 7, Index); write32le(Buf + 12, -Index * PltEntrySize - PltHeaderSize - 16); } template bool X86_64TargetInfo::isPicRel(uint32_t Type) const { return Type != R_X86_64_PC32 && Type != R_X86_64_32; } template bool X86_64TargetInfo::isTlsInitialExecRel(uint32_t Type) const { return Type == R_X86_64_GOTTPOFF; } template bool X86_64TargetInfo::isTlsLocalDynamicRel(uint32_t Type) const { return Type == R_X86_64_DTPOFF32 || Type == R_X86_64_DTPOFF64 || Type == R_X86_64_TLSLD; } template void X86_64TargetInfo::relaxTlsGdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const { // Convert // .byte 0x66 // leaq x@tlsgd(%rip), %rdi // .word 0x6666 // rex64 // call __tls_get_addr@plt // to // mov %fs:0x0,%rax // lea x@tpoff,%rax const uint8_t Inst[] = { 0x64, 0x48, 0x8b, 0x04, 0x25, 0x00, 0x00, 0x00, 0x00, // mov %fs:0x0,%rax 0x48, 0x8d, 0x80, 0x00, 0x00, 0x00, 0x00 // lea x@tpoff,%rax }; memcpy(Loc - 4, Inst, sizeof(Inst)); // The original code used a pc relative relocation and so we have to // compensate for the -4 in had in the addend. write32le(Loc + 8, Val + 4); } template void X86_64TargetInfo::relaxTlsGdToIe(uint8_t *Loc, uint32_t Type, uint64_t Val) const { // Convert // .byte 0x66 // leaq x@tlsgd(%rip), %rdi // .word 0x6666 // rex64 // call __tls_get_addr@plt // to // mov %fs:0x0,%rax // addq x@tpoff,%rax const uint8_t Inst[] = { 0x64, 0x48, 0x8b, 0x04, 0x25, 0x00, 0x00, 0x00, 0x00, // mov %fs:0x0,%rax 0x48, 0x03, 0x05, 0x00, 0x00, 0x00, 0x00 // addq x@tpoff,%rax }; memcpy(Loc - 4, Inst, sizeof(Inst)); // Both code sequences are PC relatives, but since we are moving the constant // forward by 8 bytes we have to subtract the value by 8. write32le(Loc + 8, Val - 8); } // In some conditions, R_X86_64_GOTTPOFF relocation can be optimized to // R_X86_64_TPOFF32 so that it does not use GOT. template void X86_64TargetInfo::relaxTlsIeToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const { uint8_t *Inst = Loc - 3; uint8_t Reg = Loc[-1] >> 3; uint8_t *RegSlot = Loc - 1; // Note that ADD with RSP or R12 is converted to ADD instead of LEA // because LEA with these registers needs 4 bytes to encode and thus // wouldn't fit the space. if (memcmp(Inst, "\x48\x03\x25", 3) == 0) { // "addq foo@gottpoff(%rip),%rsp" -> "addq $foo,%rsp" memcpy(Inst, "\x48\x81\xc4", 3); } else if (memcmp(Inst, "\x4c\x03\x25", 3) == 0) { // "addq foo@gottpoff(%rip),%r12" -> "addq $foo,%r12" memcpy(Inst, "\x49\x81\xc4", 3); } else if (memcmp(Inst, "\x4c\x03", 2) == 0) { // "addq foo@gottpoff(%rip),%r[8-15]" -> "leaq foo(%r[8-15]),%r[8-15]" memcpy(Inst, "\x4d\x8d", 2); *RegSlot = 0x80 | (Reg << 3) | Reg; } else if (memcmp(Inst, "\x48\x03", 2) == 0) { // "addq foo@gottpoff(%rip),%reg -> "leaq foo(%reg),%reg" memcpy(Inst, "\x48\x8d", 2); *RegSlot = 0x80 | (Reg << 3) | Reg; } else if (memcmp(Inst, "\x4c\x8b", 2) == 0) { // "movq foo@gottpoff(%rip),%r[8-15]" -> "movq $foo,%r[8-15]" memcpy(Inst, "\x49\xc7", 2); *RegSlot = 0xc0 | Reg; } else if (memcmp(Inst, "\x48\x8b", 2) == 0) { // "movq foo@gottpoff(%rip),%reg" -> "movq $foo,%reg" memcpy(Inst, "\x48\xc7", 2); *RegSlot = 0xc0 | Reg; } else { error(getErrorLocation(Loc - 3) + "R_X86_64_GOTTPOFF must be used in MOVQ or ADDQ instructions only"); } // The original code used a PC relative relocation. // Need to compensate for the -4 it had in the addend. write32le(Loc, Val + 4); } template void X86_64TargetInfo::relaxTlsLdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const { // Convert // leaq bar@tlsld(%rip), %rdi // callq __tls_get_addr@PLT // leaq bar@dtpoff(%rax), %rcx // to // .word 0x6666 // .byte 0x66 // mov %fs:0,%rax // leaq bar@tpoff(%rax), %rcx if (Type == R_X86_64_DTPOFF64) { write64le(Loc, Val); return; } if (Type == R_X86_64_DTPOFF32) { write32le(Loc, Val); return; } const uint8_t Inst[] = { 0x66, 0x66, // .word 0x6666 0x66, // .byte 0x66 0x64, 0x48, 0x8b, 0x04, 0x25, 0x00, 0x00, 0x00, 0x00 // mov %fs:0,%rax }; memcpy(Loc - 3, Inst, sizeof(Inst)); } template void X86_64TargetInfo::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const { switch (Type) { case R_X86_64_8: checkUInt<8>(Loc, Val, Type); *Loc = Val; break; case R_X86_64_16: checkUInt<16>(Loc, Val, Type); write16le(Loc, Val); break; case R_X86_64_32: checkUInt<32>(Loc, Val, Type); write32le(Loc, Val); break; case R_X86_64_32S: case R_X86_64_TPOFF32: case R_X86_64_GOT32: case R_X86_64_GOTPCREL: case R_X86_64_GOTPCRELX: case R_X86_64_REX_GOTPCRELX: case R_X86_64_PC32: case R_X86_64_GOTTPOFF: case R_X86_64_PLT32: case R_X86_64_TLSGD: case R_X86_64_TLSLD: case R_X86_64_DTPOFF32: case R_X86_64_SIZE32: checkInt<32>(Loc, Val, Type); write32le(Loc, Val); break; case R_X86_64_64: case R_X86_64_DTPOFF64: case R_X86_64_GLOB_DAT: case R_X86_64_PC64: case R_X86_64_SIZE64: case R_X86_64_GOT64: write64le(Loc, Val); break; default: llvm_unreachable("unexpected relocation"); } } template RelExpr X86_64TargetInfo::adjustRelaxExpr(uint32_t Type, const uint8_t *Data, RelExpr RelExpr) const { if (Type != R_X86_64_GOTPCRELX && Type != R_X86_64_REX_GOTPCRELX) return RelExpr; const uint8_t Op = Data[-2]; const uint8_t ModRm = Data[-1]; // FIXME: When PIC is disabled and foo is defined locally in the // lower 32 bit address space, memory operand in mov can be converted into // immediate operand. Otherwise, mov must be changed to lea. We support only // latter relaxation at this moment. if (Op == 0x8b) return R_RELAX_GOT_PC; // Relax call and jmp. if (Op == 0xff && (ModRm == 0x15 || ModRm == 0x25)) return R_RELAX_GOT_PC; // Relaxation of test, adc, add, and, cmp, or, sbb, sub, xor. // If PIC then no relaxation is available. // We also don't relax test/binop instructions without REX byte, // they are 32bit operations and not common to have. assert(Type == R_X86_64_REX_GOTPCRELX); return Config->Pic ? RelExpr : R_RELAX_GOT_PC_NOPIC; } // A subset of relaxations can only be applied for no-PIC. This method // handles such relaxations. Instructions encoding information was taken from: // "Intel 64 and IA-32 Architectures Software Developer's Manual V2" // (http://www.intel.com/content/dam/www/public/us/en/documents/manuals/ // 64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf) template void X86_64TargetInfo::relaxGotNoPic(uint8_t *Loc, uint64_t Val, uint8_t Op, uint8_t ModRm) const { const uint8_t Rex = Loc[-3]; // Convert "test %reg, foo@GOTPCREL(%rip)" to "test $foo, %reg". if (Op == 0x85) { // See "TEST-Logical Compare" (4-428 Vol. 2B), // TEST r/m64, r64 uses "full" ModR / M byte (no opcode extension). // ModR/M byte has form XX YYY ZZZ, where // YYY is MODRM.reg(register 2), ZZZ is MODRM.rm(register 1). // XX has different meanings: // 00: The operand's memory address is in reg1. // 01: The operand's memory address is reg1 + a byte-sized displacement. // 10: The operand's memory address is reg1 + a word-sized displacement. // 11: The operand is reg1 itself. // If an instruction requires only one operand, the unused reg2 field // holds extra opcode bits rather than a register code // 0xC0 == 11 000 000 binary. // 0x38 == 00 111 000 binary. // We transfer reg2 to reg1 here as operand. // See "2.1.3 ModR/M and SIB Bytes" (Vol. 2A 2-3). Loc[-1] = 0xc0 | (ModRm & 0x38) >> 3; // ModR/M byte. // Change opcode from TEST r/m64, r64 to TEST r/m64, imm32 // See "TEST-Logical Compare" (4-428 Vol. 2B). Loc[-2] = 0xf7; // Move R bit to the B bit in REX byte. // REX byte is encoded as 0100WRXB, where // 0100 is 4bit fixed pattern. // REX.W When 1, a 64-bit operand size is used. Otherwise, when 0, the // default operand size is used (which is 32-bit for most but not all // instructions). // REX.R This 1-bit value is an extension to the MODRM.reg field. // REX.X This 1-bit value is an extension to the SIB.index field. // REX.B This 1-bit value is an extension to the MODRM.rm field or the // SIB.base field. // See "2.2.1.2 More on REX Prefix Fields " (2-8 Vol. 2A). Loc[-3] = (Rex & ~0x4) | (Rex & 0x4) >> 2; write32le(Loc, Val); return; } // If we are here then we need to relax the adc, add, and, cmp, or, sbb, sub // or xor operations. // Convert "binop foo@GOTPCREL(%rip), %reg" to "binop $foo, %reg". // Logic is close to one for test instruction above, but we also // write opcode extension here, see below for details. Loc[-1] = 0xc0 | (ModRm & 0x38) >> 3 | (Op & 0x3c); // ModR/M byte. // Primary opcode is 0x81, opcode extension is one of: // 000b = ADD, 001b is OR, 010b is ADC, 011b is SBB, // 100b is AND, 101b is SUB, 110b is XOR, 111b is CMP. // This value was wrote to MODRM.reg in a line above. // See "3.2 INSTRUCTIONS (A-M)" (Vol. 2A 3-15), // "INSTRUCTION SET REFERENCE, N-Z" (Vol. 2B 4-1) for // descriptions about each operation. Loc[-2] = 0x81; Loc[-3] = (Rex & ~0x4) | (Rex & 0x4) >> 2; write32le(Loc, Val); } template void X86_64TargetInfo::relaxGot(uint8_t *Loc, uint64_t Val) const { const uint8_t Op = Loc[-2]; const uint8_t ModRm = Loc[-1]; // Convert "mov foo@GOTPCREL(%rip),%reg" to "lea foo(%rip),%reg". if (Op == 0x8b) { Loc[-2] = 0x8d; write32le(Loc, Val); return; } if (Op != 0xff) { // We are relaxing a rip relative to an absolute, so compensate // for the old -4 addend. assert(!Config->Pic); relaxGotNoPic(Loc, Val + 4, Op, ModRm); return; } // Convert call/jmp instructions. if (ModRm == 0x15) { // ABI says we can convert "call *foo@GOTPCREL(%rip)" to "nop; call foo". // Instead we convert to "addr32 call foo" where addr32 is an instruction // prefix. That makes result expression to be a single instruction. Loc[-2] = 0x67; // addr32 prefix Loc[-1] = 0xe8; // call write32le(Loc, Val); return; } // Convert "jmp *foo@GOTPCREL(%rip)" to "jmp foo; nop". // jmp doesn't return, so it is fine to use nop here, it is just a stub. assert(ModRm == 0x25); Loc[-2] = 0xe9; // jmp Loc[3] = 0x90; // nop write32le(Loc - 1, Val + 1); } // Relocation masks following the #lo(value), #hi(value), #ha(value), // #higher(value), #highera(value), #highest(value), and #highesta(value) // macros defined in section 4.5.1. Relocation Types of the PPC-elf64abi // document. static uint16_t applyPPCLo(uint64_t V) { return V; } static uint16_t applyPPCHi(uint64_t V) { return V >> 16; } static uint16_t applyPPCHa(uint64_t V) { return (V + 0x8000) >> 16; } static uint16_t applyPPCHigher(uint64_t V) { return V >> 32; } static uint16_t applyPPCHighera(uint64_t V) { return (V + 0x8000) >> 32; } static uint16_t applyPPCHighest(uint64_t V) { return V >> 48; } static uint16_t applyPPCHighesta(uint64_t V) { return (V + 0x8000) >> 48; } PPCTargetInfo::PPCTargetInfo() {} void PPCTargetInfo::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const { switch (Type) { case R_PPC_ADDR16_HA: write16be(Loc, applyPPCHa(Val)); break; case R_PPC_ADDR16_LO: write16be(Loc, applyPPCLo(Val)); break; case R_PPC_ADDR32: case R_PPC_REL32: write32be(Loc, Val); break; case R_PPC_REL24: or32be(Loc, Val & 0x3FFFFFC); break; default: error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type)); } } RelExpr PPCTargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S, const uint8_t *Loc) const { switch (Type) { case R_PPC_REL24: case R_PPC_REL32: return R_PC; default: return R_ABS; } } PPC64TargetInfo::PPC64TargetInfo() { PltRel = GotRel = R_PPC64_GLOB_DAT; RelativeRel = R_PPC64_RELATIVE; GotEntrySize = 8; GotPltEntrySize = 8; PltEntrySize = 32; PltHeaderSize = 0; // We need 64K pages (at least under glibc/Linux, the loader won't // set different permissions on a finer granularity than that). DefaultMaxPageSize = 65536; // The PPC64 ELF ABI v1 spec, says: // // It is normally desirable to put segments with different characteristics // in separate 256 Mbyte portions of the address space, to give the // operating system full paging flexibility in the 64-bit address space. // // And because the lowest non-zero 256M boundary is 0x10000000, PPC64 linkers // use 0x10000000 as the starting address. DefaultImageBase = 0x10000000; } static uint64_t PPC64TocOffset = 0x8000; uint64_t getPPC64TocBase() { // The TOC consists of sections .got, .toc, .tocbss, .plt in that order. The // TOC starts where the first of these sections starts. We always create a // .got when we see a relocation that uses it, so for us the start is always // the .got. uint64_t TocVA = In::Got->getVA(); // Per the ppc64-elf-linux ABI, The TOC base is TOC value plus 0x8000 // thus permitting a full 64 Kbytes segment. Note that the glibc startup // code (crt1.o) assumes that you can get from the TOC base to the // start of the .toc section with only a single (signed) 16-bit relocation. return TocVA + PPC64TocOffset; } RelExpr PPC64TargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S, const uint8_t *Loc) const { switch (Type) { default: return R_ABS; case R_PPC64_TOC16: case R_PPC64_TOC16_DS: case R_PPC64_TOC16_HA: case R_PPC64_TOC16_HI: case R_PPC64_TOC16_LO: case R_PPC64_TOC16_LO_DS: return R_GOTREL; case R_PPC64_TOC: return R_PPC_TOC; case R_PPC64_REL24: return R_PPC_PLT_OPD; } } void PPC64TargetInfo::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const { uint64_t Off = GotPltEntryAddr - getPPC64TocBase(); // FIXME: What we should do, in theory, is get the offset of the function // descriptor in the .opd section, and use that as the offset from %r2 (the // TOC-base pointer). Instead, we have the GOT-entry offset, and that will // be a pointer to the function descriptor in the .opd section. Using // this scheme is simpler, but requires an extra indirection per PLT dispatch. write32be(Buf, 0xf8410028); // std %r2, 40(%r1) write32be(Buf + 4, 0x3d620000 | applyPPCHa(Off)); // addis %r11, %r2, X@ha write32be(Buf + 8, 0xe98b0000 | applyPPCLo(Off)); // ld %r12, X@l(%r11) write32be(Buf + 12, 0xe96c0000); // ld %r11,0(%r12) write32be(Buf + 16, 0x7d6903a6); // mtctr %r11 write32be(Buf + 20, 0xe84c0008); // ld %r2,8(%r12) write32be(Buf + 24, 0xe96c0010); // ld %r11,16(%r12) write32be(Buf + 28, 0x4e800420); // bctr } static std::pair toAddr16Rel(uint32_t Type, uint64_t Val) { uint64_t V = Val - PPC64TocOffset; switch (Type) { case R_PPC64_TOC16: return {R_PPC64_ADDR16, V}; case R_PPC64_TOC16_DS: return {R_PPC64_ADDR16_DS, V}; case R_PPC64_TOC16_HA: return {R_PPC64_ADDR16_HA, V}; case R_PPC64_TOC16_HI: return {R_PPC64_ADDR16_HI, V}; case R_PPC64_TOC16_LO: return {R_PPC64_ADDR16_LO, V}; case R_PPC64_TOC16_LO_DS: return {R_PPC64_ADDR16_LO_DS, V}; default: return {Type, Val}; } } void PPC64TargetInfo::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const { // For a TOC-relative relocation, proceed in terms of the corresponding // ADDR16 relocation type. std::tie(Type, Val) = toAddr16Rel(Type, Val); switch (Type) { case R_PPC64_ADDR14: { checkAlignment<4>(Loc, Val, Type); // Preserve the AA/LK bits in the branch instruction uint8_t AALK = Loc[3]; write16be(Loc + 2, (AALK & 3) | (Val & 0xfffc)); break; } case R_PPC64_ADDR16: checkInt<16>(Loc, Val, Type); write16be(Loc, Val); break; case R_PPC64_ADDR16_DS: checkInt<16>(Loc, Val, Type); write16be(Loc, (read16be(Loc) & 3) | (Val & ~3)); break; case R_PPC64_ADDR16_HA: case R_PPC64_REL16_HA: write16be(Loc, applyPPCHa(Val)); break; case R_PPC64_ADDR16_HI: case R_PPC64_REL16_HI: write16be(Loc, applyPPCHi(Val)); break; case R_PPC64_ADDR16_HIGHER: write16be(Loc, applyPPCHigher(Val)); break; case R_PPC64_ADDR16_HIGHERA: write16be(Loc, applyPPCHighera(Val)); break; case R_PPC64_ADDR16_HIGHEST: write16be(Loc, applyPPCHighest(Val)); break; case R_PPC64_ADDR16_HIGHESTA: write16be(Loc, applyPPCHighesta(Val)); break; case R_PPC64_ADDR16_LO: write16be(Loc, applyPPCLo(Val)); break; case R_PPC64_ADDR16_LO_DS: case R_PPC64_REL16_LO: write16be(Loc, (read16be(Loc) & 3) | (applyPPCLo(Val) & ~3)); break; case R_PPC64_ADDR32: case R_PPC64_REL32: checkInt<32>(Loc, Val, Type); write32be(Loc, Val); break; case R_PPC64_ADDR64: case R_PPC64_REL64: case R_PPC64_TOC: write64be(Loc, Val); break; case R_PPC64_REL24: { uint32_t Mask = 0x03FFFFFC; checkInt<24>(Loc, Val, Type); write32be(Loc, (read32be(Loc) & ~Mask) | (Val & Mask)); break; } default: error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type)); } } AArch64TargetInfo::AArch64TargetInfo() { CopyRel = R_AARCH64_COPY; RelativeRel = R_AARCH64_RELATIVE; IRelativeRel = R_AARCH64_IRELATIVE; GotRel = R_AARCH64_GLOB_DAT; PltRel = R_AARCH64_JUMP_SLOT; TlsDescRel = R_AARCH64_TLSDESC; TlsGotRel = R_AARCH64_TLS_TPREL64; GotEntrySize = 8; GotPltEntrySize = 8; PltEntrySize = 16; PltHeaderSize = 32; DefaultMaxPageSize = 65536; // It doesn't seem to be documented anywhere, but tls on aarch64 uses variant // 1 of the tls structures and the tcb size is 16. TcbSize = 16; } RelExpr AArch64TargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S, const uint8_t *Loc) const { switch (Type) { default: return R_ABS; case R_AARCH64_TLSDESC_ADR_PAGE21: return R_TLSDESC_PAGE; - case R_AARCH64_TLSDESC_LD64_LO12_NC: - case R_AARCH64_TLSDESC_ADD_LO12_NC: + case R_AARCH64_TLSDESC_LD64_LO12: + case R_AARCH64_TLSDESC_ADD_LO12: return R_TLSDESC; case R_AARCH64_TLSDESC_CALL: return R_TLSDESC_CALL; case R_AARCH64_TLSLE_ADD_TPREL_HI12: case R_AARCH64_TLSLE_ADD_TPREL_LO12_NC: return R_TLS; case R_AARCH64_CALL26: case R_AARCH64_CONDBR19: case R_AARCH64_JUMP26: case R_AARCH64_TSTBR14: return R_PLT_PC; case R_AARCH64_PREL16: case R_AARCH64_PREL32: case R_AARCH64_PREL64: case R_AARCH64_ADR_PREL_LO21: return R_PC; case R_AARCH64_ADR_PREL_PG_HI21: return R_PAGE_PC; case R_AARCH64_LD64_GOT_LO12_NC: case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: return R_GOT; case R_AARCH64_ADR_GOT_PAGE: case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21: return R_GOT_PAGE_PC; case R_AARCH64_NONE: return R_NONE; } } RelExpr AArch64TargetInfo::adjustRelaxExpr(uint32_t Type, const uint8_t *Data, RelExpr Expr) const { if (Expr == R_RELAX_TLS_GD_TO_IE) { if (Type == R_AARCH64_TLSDESC_ADR_PAGE21) return R_RELAX_TLS_GD_TO_IE_PAGE_PC; return R_RELAX_TLS_GD_TO_IE_ABS; } return Expr; } bool AArch64TargetInfo::usesOnlyLowPageBits(uint32_t Type) const { switch (Type) { default: return false; case R_AARCH64_ADD_ABS_LO12_NC: case R_AARCH64_LD64_GOT_LO12_NC: case R_AARCH64_LDST128_ABS_LO12_NC: case R_AARCH64_LDST16_ABS_LO12_NC: case R_AARCH64_LDST32_ABS_LO12_NC: case R_AARCH64_LDST64_ABS_LO12_NC: case R_AARCH64_LDST8_ABS_LO12_NC: - case R_AARCH64_TLSDESC_ADD_LO12_NC: - case R_AARCH64_TLSDESC_LD64_LO12_NC: + case R_AARCH64_TLSDESC_ADD_LO12: + case R_AARCH64_TLSDESC_LD64_LO12: case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: return true; } } bool AArch64TargetInfo::isTlsInitialExecRel(uint32_t Type) const { return Type == R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 || Type == R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC; } bool AArch64TargetInfo::isPicRel(uint32_t Type) const { return Type == R_AARCH64_ABS32 || Type == R_AARCH64_ABS64; } void AArch64TargetInfo::writeGotPlt(uint8_t *Buf, const SymbolBody &) const { write64le(Buf, In::Plt->getVA()); } // Page(Expr) is the page address of the expression Expr, defined // as (Expr & ~0xFFF). (This applies even if the machine page size // supported by the platform has a different value.) uint64_t getAArch64Page(uint64_t Expr) { return Expr & (~static_cast(0xFFF)); } void AArch64TargetInfo::writePltHeader(uint8_t *Buf) const { const uint8_t PltData[] = { 0xf0, 0x7b, 0xbf, 0xa9, // stp x16, x30, [sp,#-16]! 0x10, 0x00, 0x00, 0x90, // adrp x16, Page(&(.plt.got[2])) 0x11, 0x02, 0x40, 0xf9, // ldr x17, [x16, Offset(&(.plt.got[2]))] 0x10, 0x02, 0x00, 0x91, // add x16, x16, Offset(&(.plt.got[2])) 0x20, 0x02, 0x1f, 0xd6, // br x17 0x1f, 0x20, 0x03, 0xd5, // nop 0x1f, 0x20, 0x03, 0xd5, // nop 0x1f, 0x20, 0x03, 0xd5 // nop }; memcpy(Buf, PltData, sizeof(PltData)); uint64_t Got = In::GotPlt->getVA(); uint64_t Plt = In::Plt->getVA(); relocateOne(Buf + 4, R_AARCH64_ADR_PREL_PG_HI21, getAArch64Page(Got + 16) - getAArch64Page(Plt + 4)); relocateOne(Buf + 8, R_AARCH64_LDST64_ABS_LO12_NC, Got + 16); relocateOne(Buf + 12, R_AARCH64_ADD_ABS_LO12_NC, Got + 16); } void AArch64TargetInfo::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const { const uint8_t Inst[] = { 0x10, 0x00, 0x00, 0x90, // adrp x16, Page(&(.plt.got[n])) 0x11, 0x02, 0x40, 0xf9, // ldr x17, [x16, Offset(&(.plt.got[n]))] 0x10, 0x02, 0x00, 0x91, // add x16, x16, Offset(&(.plt.got[n])) 0x20, 0x02, 0x1f, 0xd6 // br x17 }; memcpy(Buf, Inst, sizeof(Inst)); relocateOne(Buf, R_AARCH64_ADR_PREL_PG_HI21, getAArch64Page(GotPltEntryAddr) - getAArch64Page(PltEntryAddr)); relocateOne(Buf + 4, R_AARCH64_LDST64_ABS_LO12_NC, GotPltEntryAddr); relocateOne(Buf + 8, R_AARCH64_ADD_ABS_LO12_NC, GotPltEntryAddr); } static void write32AArch64Addr(uint8_t *L, uint64_t Imm) { uint32_t ImmLo = (Imm & 0x3) << 29; uint32_t ImmHi = (Imm & 0x1FFFFC) << 3; uint64_t Mask = (0x3 << 29) | (0x1FFFFC << 3); write32le(L, (read32le(L) & ~Mask) | ImmLo | ImmHi); } // Return the bits [Start, End] from Val shifted Start bits. // For instance, getBits(0xF0, 4, 8) returns 0xF. static uint64_t getBits(uint64_t Val, int Start, int End) { uint64_t Mask = ((uint64_t)1 << (End + 1 - Start)) - 1; return (Val >> Start) & Mask; } // Update the immediate field in a AARCH64 ldr, str, and add instruction. static void or32AArch64Imm(uint8_t *L, uint64_t Imm) { or32le(L, (Imm & 0xFFF) << 10); } void AArch64TargetInfo::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const { switch (Type) { case R_AARCH64_ABS16: case R_AARCH64_PREL16: checkIntUInt<16>(Loc, Val, Type); write16le(Loc, Val); break; case R_AARCH64_ABS32: case R_AARCH64_PREL32: checkIntUInt<32>(Loc, Val, Type); write32le(Loc, Val); break; case R_AARCH64_ABS64: case R_AARCH64_GLOB_DAT: case R_AARCH64_PREL64: write64le(Loc, Val); break; case R_AARCH64_ADD_ABS_LO12_NC: or32AArch64Imm(Loc, Val); break; case R_AARCH64_ADR_GOT_PAGE: case R_AARCH64_ADR_PREL_PG_HI21: case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21: case R_AARCH64_TLSDESC_ADR_PAGE21: checkInt<33>(Loc, Val, Type); write32AArch64Addr(Loc, Val >> 12); break; case R_AARCH64_ADR_PREL_LO21: checkInt<21>(Loc, Val, Type); write32AArch64Addr(Loc, Val); break; case R_AARCH64_CALL26: case R_AARCH64_JUMP26: checkInt<28>(Loc, Val, Type); or32le(Loc, (Val & 0x0FFFFFFC) >> 2); break; case R_AARCH64_CONDBR19: checkInt<21>(Loc, Val, Type); or32le(Loc, (Val & 0x1FFFFC) << 3); break; case R_AARCH64_LD64_GOT_LO12_NC: case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: - case R_AARCH64_TLSDESC_LD64_LO12_NC: + case R_AARCH64_TLSDESC_LD64_LO12: checkAlignment<8>(Loc, Val, Type); or32le(Loc, (Val & 0xFF8) << 7); break; case R_AARCH64_LDST8_ABS_LO12_NC: or32AArch64Imm(Loc, getBits(Val, 0, 11)); break; case R_AARCH64_LDST16_ABS_LO12_NC: or32AArch64Imm(Loc, getBits(Val, 1, 11)); break; case R_AARCH64_LDST32_ABS_LO12_NC: or32AArch64Imm(Loc, getBits(Val, 2, 11)); break; case R_AARCH64_LDST64_ABS_LO12_NC: or32AArch64Imm(Loc, getBits(Val, 3, 11)); break; case R_AARCH64_LDST128_ABS_LO12_NC: or32AArch64Imm(Loc, getBits(Val, 4, 11)); break; case R_AARCH64_MOVW_UABS_G0_NC: or32le(Loc, (Val & 0xFFFF) << 5); break; case R_AARCH64_MOVW_UABS_G1_NC: or32le(Loc, (Val & 0xFFFF0000) >> 11); break; case R_AARCH64_MOVW_UABS_G2_NC: or32le(Loc, (Val & 0xFFFF00000000) >> 27); break; case R_AARCH64_MOVW_UABS_G3: or32le(Loc, (Val & 0xFFFF000000000000) >> 43); break; case R_AARCH64_TSTBR14: checkInt<16>(Loc, Val, Type); or32le(Loc, (Val & 0xFFFC) << 3); break; case R_AARCH64_TLSLE_ADD_TPREL_HI12: checkInt<24>(Loc, Val, Type); or32AArch64Imm(Loc, Val >> 12); break; case R_AARCH64_TLSLE_ADD_TPREL_LO12_NC: - case R_AARCH64_TLSDESC_ADD_LO12_NC: + case R_AARCH64_TLSDESC_ADD_LO12: or32AArch64Imm(Loc, Val); break; default: error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type)); } } void AArch64TargetInfo::relaxTlsGdToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const { // TLSDESC Global-Dynamic relocation are in the form: // adrp x0, :tlsdesc:v [R_AARCH64_TLSDESC_ADR_PAGE21] - // ldr x1, [x0, #:tlsdesc_lo12:v [R_AARCH64_TLSDESC_LD64_LO12_NC] - // add x0, x0, :tlsdesc_los:v [_AARCH64_TLSDESC_ADD_LO12_NC] + // ldr x1, [x0, #:tlsdesc_lo12:v [R_AARCH64_TLSDESC_LD64_LO12] + // add x0, x0, :tlsdesc_los:v [R_AARCH64_TLSDESC_ADD_LO12] // .tlsdesccall [R_AARCH64_TLSDESC_CALL] // blr x1 // And it can optimized to: // movz x0, #0x0, lsl #16 // movk x0, #0x10 // nop // nop checkUInt<32>(Loc, Val, Type); switch (Type) { - case R_AARCH64_TLSDESC_ADD_LO12_NC: + case R_AARCH64_TLSDESC_ADD_LO12: case R_AARCH64_TLSDESC_CALL: write32le(Loc, 0xd503201f); // nop return; case R_AARCH64_TLSDESC_ADR_PAGE21: write32le(Loc, 0xd2a00000 | (((Val >> 16) & 0xffff) << 5)); // movz return; - case R_AARCH64_TLSDESC_LD64_LO12_NC: + case R_AARCH64_TLSDESC_LD64_LO12: write32le(Loc, 0xf2800000 | ((Val & 0xffff) << 5)); // movk return; default: llvm_unreachable("unsupported relocation for TLS GD to LE relaxation"); } } void AArch64TargetInfo::relaxTlsGdToIe(uint8_t *Loc, uint32_t Type, uint64_t Val) const { // TLSDESC Global-Dynamic relocation are in the form: // adrp x0, :tlsdesc:v [R_AARCH64_TLSDESC_ADR_PAGE21] - // ldr x1, [x0, #:tlsdesc_lo12:v [R_AARCH64_TLSDESC_LD64_LO12_NC] - // add x0, x0, :tlsdesc_los:v [_AARCH64_TLSDESC_ADD_LO12_NC] + // ldr x1, [x0, #:tlsdesc_lo12:v [R_AARCH64_TLSDESC_LD64_LO12] + // add x0, x0, :tlsdesc_los:v [R_AARCH64_TLSDESC_ADD_LO12] // .tlsdesccall [R_AARCH64_TLSDESC_CALL] // blr x1 // And it can optimized to: // adrp x0, :gottprel:v // ldr x0, [x0, :gottprel_lo12:v] // nop // nop switch (Type) { - case R_AARCH64_TLSDESC_ADD_LO12_NC: + case R_AARCH64_TLSDESC_ADD_LO12: case R_AARCH64_TLSDESC_CALL: write32le(Loc, 0xd503201f); // nop break; case R_AARCH64_TLSDESC_ADR_PAGE21: write32le(Loc, 0x90000000); // adrp relocateOne(Loc, R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21, Val); break; - case R_AARCH64_TLSDESC_LD64_LO12_NC: + case R_AARCH64_TLSDESC_LD64_LO12: write32le(Loc, 0xf9400000); // ldr relocateOne(Loc, R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC, Val); break; default: llvm_unreachable("unsupported relocation for TLS GD to LE relaxation"); } } void AArch64TargetInfo::relaxTlsIeToLe(uint8_t *Loc, uint32_t Type, uint64_t Val) const { checkUInt<32>(Loc, Val, Type); if (Type == R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21) { // Generate MOVZ. uint32_t RegNo = read32le(Loc) & 0x1f; write32le(Loc, (0xd2a00000 | RegNo) | (((Val >> 16) & 0xffff) << 5)); return; } if (Type == R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC) { // Generate MOVK. uint32_t RegNo = read32le(Loc) & 0x1f; write32le(Loc, (0xf2800000 | RegNo) | ((Val & 0xffff) << 5)); return; } llvm_unreachable("invalid relocation for TLS IE to LE relaxation"); } AMDGPUTargetInfo::AMDGPUTargetInfo() { RelativeRel = R_AMDGPU_REL64; GotRel = R_AMDGPU_ABS64; GotEntrySize = 8; } void AMDGPUTargetInfo::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const { switch (Type) { case R_AMDGPU_ABS32: case R_AMDGPU_GOTPCREL: case R_AMDGPU_GOTPCREL32_LO: case R_AMDGPU_REL32: case R_AMDGPU_REL32_LO: write32le(Loc, Val); break; case R_AMDGPU_ABS64: write64le(Loc, Val); break; case R_AMDGPU_GOTPCREL32_HI: case R_AMDGPU_REL32_HI: write32le(Loc, Val >> 32); break; default: error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type)); } } RelExpr AMDGPUTargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S, const uint8_t *Loc) const { switch (Type) { case R_AMDGPU_ABS32: case R_AMDGPU_ABS64: return R_ABS; case R_AMDGPU_REL32: case R_AMDGPU_REL32_LO: case R_AMDGPU_REL32_HI: return R_PC; case R_AMDGPU_GOTPCREL: case R_AMDGPU_GOTPCREL32_LO: case R_AMDGPU_GOTPCREL32_HI: return R_GOT_PC; default: error(toString(S.File) + ": unknown relocation type: " + toString(Type)); return R_HINT; } } ARMTargetInfo::ARMTargetInfo() { CopyRel = R_ARM_COPY; RelativeRel = R_ARM_RELATIVE; IRelativeRel = R_ARM_IRELATIVE; GotRel = R_ARM_GLOB_DAT; PltRel = R_ARM_JUMP_SLOT; TlsGotRel = R_ARM_TLS_TPOFF32; TlsModuleIndexRel = R_ARM_TLS_DTPMOD32; TlsOffsetRel = R_ARM_TLS_DTPOFF32; GotEntrySize = 4; GotPltEntrySize = 4; PltEntrySize = 16; PltHeaderSize = 20; // ARM uses Variant 1 TLS TcbSize = 8; NeedsThunks = true; } RelExpr ARMTargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S, const uint8_t *Loc) const { switch (Type) { default: return R_ABS; case R_ARM_THM_JUMP11: return R_PC; case R_ARM_CALL: case R_ARM_JUMP24: case R_ARM_PC24: case R_ARM_PLT32: case R_ARM_PREL31: case R_ARM_THM_JUMP19: case R_ARM_THM_JUMP24: case R_ARM_THM_CALL: return R_PLT_PC; case R_ARM_GOTOFF32: // (S + A) - GOT_ORG return R_GOTREL; case R_ARM_GOT_BREL: // GOT(S) + A - GOT_ORG return R_GOT_OFF; case R_ARM_GOT_PREL: case R_ARM_TLS_IE32: // GOT(S) + A - P return R_GOT_PC; case R_ARM_TARGET1: return Config->Target1Rel ? R_PC : R_ABS; case R_ARM_TARGET2: if (Config->Target2 == Target2Policy::Rel) return R_PC; if (Config->Target2 == Target2Policy::Abs) return R_ABS; return R_GOT_PC; case R_ARM_TLS_GD32: return R_TLSGD_PC; case R_ARM_TLS_LDM32: return R_TLSLD_PC; case R_ARM_BASE_PREL: // B(S) + A - P // FIXME: currently B(S) assumed to be .got, this may not hold for all // platforms. return R_GOTONLY_PC; case R_ARM_MOVW_PREL_NC: case R_ARM_MOVT_PREL: case R_ARM_REL32: case R_ARM_THM_MOVW_PREL_NC: case R_ARM_THM_MOVT_PREL: return R_PC; case R_ARM_NONE: return R_NONE; case R_ARM_TLS_LE32: return R_TLS; } } bool ARMTargetInfo::isPicRel(uint32_t Type) const { return (Type == R_ARM_TARGET1 && !Config->Target1Rel) || (Type == R_ARM_ABS32); } uint32_t ARMTargetInfo::getDynRel(uint32_t Type) const { if (Type == R_ARM_TARGET1 && !Config->Target1Rel) return R_ARM_ABS32; if (Type == R_ARM_ABS32) return Type; // Keep it going with a dummy value so that we can find more reloc errors. return R_ARM_ABS32; } void ARMTargetInfo::writeGotPlt(uint8_t *Buf, const SymbolBody &) const { write32le(Buf, In::Plt->getVA()); } void ARMTargetInfo::writeIgotPlt(uint8_t *Buf, const SymbolBody &S) const { // An ARM entry is the address of the ifunc resolver function. write32le(Buf, S.getVA()); } void ARMTargetInfo::writePltHeader(uint8_t *Buf) const { const uint8_t PltData[] = { 0x04, 0xe0, 0x2d, 0xe5, // str lr, [sp,#-4]! 0x04, 0xe0, 0x9f, 0xe5, // ldr lr, L2 0x0e, 0xe0, 0x8f, 0xe0, // L1: add lr, pc, lr 0x08, 0xf0, 0xbe, 0xe5, // ldr pc, [lr, #8] 0x00, 0x00, 0x00, 0x00, // L2: .word &(.got.plt) - L1 - 8 }; memcpy(Buf, PltData, sizeof(PltData)); uint64_t GotPlt = In::GotPlt->getVA(); uint64_t L1 = In::Plt->getVA() + 8; write32le(Buf + 16, GotPlt - L1 - 8); } void ARMTargetInfo::addPltHeaderSymbols(InputSectionBase *ISD) const { auto *IS = cast(ISD); addSyntheticLocal("$a", STT_NOTYPE, 0, 0, IS); addSyntheticLocal("$d", STT_NOTYPE, 16, 0, IS); } void ARMTargetInfo::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const { // FIXME: Using simple code sequence with simple relocations. // There is a more optimal sequence but it requires support for the group // relocations. See ELF for the ARM Architecture Appendix A.3 const uint8_t PltData[] = { 0x04, 0xc0, 0x9f, 0xe5, // ldr ip, L2 0x0f, 0xc0, 0x8c, 0xe0, // L1: add ip, ip, pc 0x00, 0xf0, 0x9c, 0xe5, // ldr pc, [ip] 0x00, 0x00, 0x00, 0x00, // L2: .word Offset(&(.plt.got) - L1 - 8 }; memcpy(Buf, PltData, sizeof(PltData)); uint64_t L1 = PltEntryAddr + 4; write32le(Buf + 12, GotPltEntryAddr - L1 - 8); } void ARMTargetInfo::addPltSymbols(InputSectionBase *ISD, uint64_t Off) const { auto *IS = cast(ISD); addSyntheticLocal("$a", STT_NOTYPE, Off, 0, IS); addSyntheticLocal("$d", STT_NOTYPE, Off + 12, 0, IS); } bool ARMTargetInfo::needsThunk(RelExpr Expr, uint32_t RelocType, const InputFile *File, const SymbolBody &S) const { // If S is an undefined weak symbol in an executable we don't need a Thunk. // In a DSO calls to undefined symbols, including weak ones get PLT entries // which may need a thunk. if (S.isUndefined() && !S.isLocal() && S.symbol()->isWeak() && !Config->Shared) return false; // A state change from ARM to Thumb and vice versa must go through an // interworking thunk if the relocation type is not R_ARM_CALL or // R_ARM_THM_CALL. switch (RelocType) { case R_ARM_PC24: case R_ARM_PLT32: case R_ARM_JUMP24: // Source is ARM, all PLT entries are ARM so no interworking required. // Otherwise we need to interwork if Symbol has bit 0 set (Thumb). if (Expr == R_PC && ((S.getVA() & 1) == 1)) return true; break; case R_ARM_THM_JUMP19: case R_ARM_THM_JUMP24: // Source is Thumb, all PLT entries are ARM so interworking is required. // Otherwise we need to interwork if Symbol has bit 0 clear (ARM). if (Expr == R_PLT_PC || ((S.getVA() & 1) == 0)) return true; break; } return false; } void ARMTargetInfo::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const { switch (Type) { case R_ARM_ABS32: case R_ARM_BASE_PREL: case R_ARM_GLOB_DAT: case R_ARM_GOTOFF32: case R_ARM_GOT_BREL: case R_ARM_GOT_PREL: case R_ARM_REL32: case R_ARM_RELATIVE: case R_ARM_TARGET1: case R_ARM_TARGET2: case R_ARM_TLS_GD32: case R_ARM_TLS_IE32: case R_ARM_TLS_LDM32: case R_ARM_TLS_LDO32: case R_ARM_TLS_LE32: case R_ARM_TLS_TPOFF32: case R_ARM_TLS_DTPOFF32: write32le(Loc, Val); break; case R_ARM_TLS_DTPMOD32: write32le(Loc, 1); break; case R_ARM_PREL31: checkInt<31>(Loc, Val, Type); write32le(Loc, (read32le(Loc) & 0x80000000) | (Val & ~0x80000000)); break; case R_ARM_CALL: // R_ARM_CALL is used for BL and BLX instructions, depending on the // value of bit 0 of Val, we must select a BL or BLX instruction if (Val & 1) { // If bit 0 of Val is 1 the target is Thumb, we must select a BLX. // The BLX encoding is 0xfa:H:imm24 where Val = imm24:H:'1' checkInt<26>(Loc, Val, Type); write32le(Loc, 0xfa000000 | // opcode ((Val & 2) << 23) | // H ((Val >> 2) & 0x00ffffff)); // imm24 break; } if ((read32le(Loc) & 0xfe000000) == 0xfa000000) // BLX (always unconditional) instruction to an ARM Target, select an // unconditional BL. write32le(Loc, 0xeb000000 | (read32le(Loc) & 0x00ffffff)); // fall through as BL encoding is shared with B case R_ARM_JUMP24: case R_ARM_PC24: case R_ARM_PLT32: checkInt<26>(Loc, Val, Type); write32le(Loc, (read32le(Loc) & ~0x00ffffff) | ((Val >> 2) & 0x00ffffff)); break; case R_ARM_THM_JUMP11: checkInt<12>(Loc, Val, Type); write16le(Loc, (read32le(Loc) & 0xf800) | ((Val >> 1) & 0x07ff)); break; case R_ARM_THM_JUMP19: // Encoding T3: Val = S:J2:J1:imm6:imm11:0 checkInt<21>(Loc, Val, Type); write16le(Loc, (read16le(Loc) & 0xfbc0) | // opcode cond ((Val >> 10) & 0x0400) | // S ((Val >> 12) & 0x003f)); // imm6 write16le(Loc + 2, 0x8000 | // opcode ((Val >> 8) & 0x0800) | // J2 ((Val >> 5) & 0x2000) | // J1 ((Val >> 1) & 0x07ff)); // imm11 break; case R_ARM_THM_CALL: // R_ARM_THM_CALL is used for BL and BLX instructions, depending on the // value of bit 0 of Val, we must select a BL or BLX instruction if ((Val & 1) == 0) { // Ensure BLX destination is 4-byte aligned. As BLX instruction may // only be two byte aligned. This must be done before overflow check Val = alignTo(Val, 4); } // Bit 12 is 0 for BLX, 1 for BL write16le(Loc + 2, (read16le(Loc + 2) & ~0x1000) | (Val & 1) << 12); // Fall through as rest of encoding is the same as B.W case R_ARM_THM_JUMP24: // Encoding B T4, BL T1, BLX T2: Val = S:I1:I2:imm10:imm11:0 // FIXME: Use of I1 and I2 require v6T2ops checkInt<25>(Loc, Val, Type); write16le(Loc, 0xf000 | // opcode ((Val >> 14) & 0x0400) | // S ((Val >> 12) & 0x03ff)); // imm10 write16le(Loc + 2, (read16le(Loc + 2) & 0xd000) | // opcode (((~(Val >> 10)) ^ (Val >> 11)) & 0x2000) | // J1 (((~(Val >> 11)) ^ (Val >> 13)) & 0x0800) | // J2 ((Val >> 1) & 0x07ff)); // imm11 break; case R_ARM_MOVW_ABS_NC: case R_ARM_MOVW_PREL_NC: write32le(Loc, (read32le(Loc) & ~0x000f0fff) | ((Val & 0xf000) << 4) | (Val & 0x0fff)); break; case R_ARM_MOVT_ABS: case R_ARM_MOVT_PREL: checkInt<32>(Loc, Val, Type); write32le(Loc, (read32le(Loc) & ~0x000f0fff) | (((Val >> 16) & 0xf000) << 4) | ((Val >> 16) & 0xfff)); break; case R_ARM_THM_MOVT_ABS: case R_ARM_THM_MOVT_PREL: // Encoding T1: A = imm4:i:imm3:imm8 checkInt<32>(Loc, Val, Type); write16le(Loc, 0xf2c0 | // opcode ((Val >> 17) & 0x0400) | // i ((Val >> 28) & 0x000f)); // imm4 write16le(Loc + 2, (read16le(Loc + 2) & 0x8f00) | // opcode ((Val >> 12) & 0x7000) | // imm3 ((Val >> 16) & 0x00ff)); // imm8 break; case R_ARM_THM_MOVW_ABS_NC: case R_ARM_THM_MOVW_PREL_NC: // Encoding T3: A = imm4:i:imm3:imm8 write16le(Loc, 0xf240 | // opcode ((Val >> 1) & 0x0400) | // i ((Val >> 12) & 0x000f)); // imm4 write16le(Loc + 2, (read16le(Loc + 2) & 0x8f00) | // opcode ((Val << 4) & 0x7000) | // imm3 (Val & 0x00ff)); // imm8 break; default: error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type)); } } int64_t ARMTargetInfo::getImplicitAddend(const uint8_t *Buf, uint32_t Type) const { switch (Type) { default: return 0; case R_ARM_ABS32: case R_ARM_BASE_PREL: case R_ARM_GOTOFF32: case R_ARM_GOT_BREL: case R_ARM_GOT_PREL: case R_ARM_REL32: case R_ARM_TARGET1: case R_ARM_TARGET2: case R_ARM_TLS_GD32: case R_ARM_TLS_LDM32: case R_ARM_TLS_LDO32: case R_ARM_TLS_IE32: case R_ARM_TLS_LE32: return SignExtend64<32>(read32le(Buf)); case R_ARM_PREL31: return SignExtend64<31>(read32le(Buf)); case R_ARM_CALL: case R_ARM_JUMP24: case R_ARM_PC24: case R_ARM_PLT32: return SignExtend64<26>(read32le(Buf) << 2); case R_ARM_THM_JUMP11: return SignExtend64<12>(read16le(Buf) << 1); case R_ARM_THM_JUMP19: { // Encoding T3: A = S:J2:J1:imm10:imm6:0 uint16_t Hi = read16le(Buf); uint16_t Lo = read16le(Buf + 2); return SignExtend64<20>(((Hi & 0x0400) << 10) | // S ((Lo & 0x0800) << 8) | // J2 ((Lo & 0x2000) << 5) | // J1 ((Hi & 0x003f) << 12) | // imm6 ((Lo & 0x07ff) << 1)); // imm11:0 } case R_ARM_THM_CALL: case R_ARM_THM_JUMP24: { // Encoding B T4, BL T1, BLX T2: A = S:I1:I2:imm10:imm11:0 // I1 = NOT(J1 EOR S), I2 = NOT(J2 EOR S) // FIXME: I1 and I2 require v6T2ops uint16_t Hi = read16le(Buf); uint16_t Lo = read16le(Buf + 2); return SignExtend64<24>(((Hi & 0x0400) << 14) | // S (~((Lo ^ (Hi << 3)) << 10) & 0x00800000) | // I1 (~((Lo ^ (Hi << 1)) << 11) & 0x00400000) | // I2 ((Hi & 0x003ff) << 12) | // imm0 ((Lo & 0x007ff) << 1)); // imm11:0 } // ELF for the ARM Architecture 4.6.1.1 the implicit addend for MOVW and // MOVT is in the range -32768 <= A < 32768 case R_ARM_MOVW_ABS_NC: case R_ARM_MOVT_ABS: case R_ARM_MOVW_PREL_NC: case R_ARM_MOVT_PREL: { uint64_t Val = read32le(Buf) & 0x000f0fff; return SignExtend64<16>(((Val & 0x000f0000) >> 4) | (Val & 0x00fff)); } case R_ARM_THM_MOVW_ABS_NC: case R_ARM_THM_MOVT_ABS: case R_ARM_THM_MOVW_PREL_NC: case R_ARM_THM_MOVT_PREL: { // Encoding T3: A = imm4:i:imm3:imm8 uint16_t Hi = read16le(Buf); uint16_t Lo = read16le(Buf + 2); return SignExtend64<16>(((Hi & 0x000f) << 12) | // imm4 ((Hi & 0x0400) << 1) | // i ((Lo & 0x7000) >> 4) | // imm3 (Lo & 0x00ff)); // imm8 } } } template MipsTargetInfo::MipsTargetInfo() { GotPltHeaderEntriesNum = 2; DefaultMaxPageSize = 65536; GotEntrySize = sizeof(typename ELFT::uint); GotPltEntrySize = sizeof(typename ELFT::uint); PltEntrySize = 16; PltHeaderSize = 32; CopyRel = R_MIPS_COPY; PltRel = R_MIPS_JUMP_SLOT; NeedsThunks = true; if (ELFT::Is64Bits) { RelativeRel = (R_MIPS_64 << 8) | R_MIPS_REL32; TlsGotRel = R_MIPS_TLS_TPREL64; TlsModuleIndexRel = R_MIPS_TLS_DTPMOD64; TlsOffsetRel = R_MIPS_TLS_DTPREL64; } else { RelativeRel = R_MIPS_REL32; TlsGotRel = R_MIPS_TLS_TPREL32; TlsModuleIndexRel = R_MIPS_TLS_DTPMOD32; TlsOffsetRel = R_MIPS_TLS_DTPREL32; } } template RelExpr MipsTargetInfo::getRelExpr(uint32_t Type, const SymbolBody &S, const uint8_t *Loc) const { // See comment in the calculateMipsRelChain. if (ELFT::Is64Bits || Config->MipsN32Abi) Type &= 0xff; switch (Type) { default: return R_ABS; case R_MIPS_JALR: return R_HINT; case R_MIPS_GPREL16: case R_MIPS_GPREL32: return R_MIPS_GOTREL; case R_MIPS_26: return R_PLT; case R_MIPS_HI16: case R_MIPS_LO16: // R_MIPS_HI16/R_MIPS_LO16 relocations against _gp_disp calculate // offset between start of function and 'gp' value which by default // equal to the start of .got section. In that case we consider these // relocations as relative. if (&S == ElfSym::MipsGpDisp) return R_MIPS_GOT_GP_PC; if (&S == ElfSym::MipsLocalGp) return R_MIPS_GOT_GP; // fallthrough case R_MIPS_GOT_OFST: return R_ABS; case R_MIPS_PC32: case R_MIPS_PC16: case R_MIPS_PC19_S2: case R_MIPS_PC21_S2: case R_MIPS_PC26_S2: case R_MIPS_PCHI16: case R_MIPS_PCLO16: return R_PC; case R_MIPS_GOT16: if (S.isLocal()) return R_MIPS_GOT_LOCAL_PAGE; // fallthrough case R_MIPS_CALL16: case R_MIPS_GOT_DISP: case R_MIPS_TLS_GOTTPREL: return R_MIPS_GOT_OFF; case R_MIPS_CALL_HI16: case R_MIPS_CALL_LO16: case R_MIPS_GOT_HI16: case R_MIPS_GOT_LO16: return R_MIPS_GOT_OFF32; case R_MIPS_GOT_PAGE: return R_MIPS_GOT_LOCAL_PAGE; case R_MIPS_TLS_GD: return R_MIPS_TLSGD; case R_MIPS_TLS_LDM: return R_MIPS_TLSLD; } } template bool MipsTargetInfo::isPicRel(uint32_t Type) const { return Type == R_MIPS_32 || Type == R_MIPS_64; } template uint32_t MipsTargetInfo::getDynRel(uint32_t Type) const { return RelativeRel; } template void MipsTargetInfo::writeGotPlt(uint8_t *Buf, const SymbolBody &) const { write32(Buf, In::Plt->getVA()); } template static int64_t getPcRelocAddend(const uint8_t *Loc) { uint32_t Instr = read32(Loc); uint32_t Mask = 0xffffffff >> (32 - BSIZE); return SignExtend64((Instr & Mask) << SHIFT); } template static void applyMipsPcReloc(uint8_t *Loc, uint32_t Type, uint64_t V) { uint32_t Mask = 0xffffffff >> (32 - BSIZE); uint32_t Instr = read32(Loc); if (SHIFT > 0) checkAlignment<(1 << SHIFT)>(Loc, V, Type); checkInt(Loc, V, Type); write32(Loc, (Instr & ~Mask) | ((V >> SHIFT) & Mask)); } template static void writeMipsHi16(uint8_t *Loc, uint64_t V) { uint32_t Instr = read32(Loc); uint16_t Res = ((V + 0x8000) >> 16) & 0xffff; write32(Loc, (Instr & 0xffff0000) | Res); } template static void writeMipsHigher(uint8_t *Loc, uint64_t V) { uint32_t Instr = read32(Loc); uint16_t Res = ((V + 0x80008000) >> 32) & 0xffff; write32(Loc, (Instr & 0xffff0000) | Res); } template static void writeMipsHighest(uint8_t *Loc, uint64_t V) { uint32_t Instr = read32(Loc); uint16_t Res = ((V + 0x800080008000) >> 48) & 0xffff; write32(Loc, (Instr & 0xffff0000) | Res); } template static void writeMipsLo16(uint8_t *Loc, uint64_t V) { uint32_t Instr = read32(Loc); write32(Loc, (Instr & 0xffff0000) | (V & 0xffff)); } template static bool isMipsR6() { const auto &FirstObj = cast>(*Config->FirstElf); uint32_t Arch = FirstObj.getObj().getHeader()->e_flags & EF_MIPS_ARCH; return Arch == EF_MIPS_ARCH_32R6 || Arch == EF_MIPS_ARCH_64R6; } template void MipsTargetInfo::writePltHeader(uint8_t *Buf) const { const endianness E = ELFT::TargetEndianness; if (Config->MipsN32Abi) { write32(Buf, 0x3c0e0000); // lui $14, %hi(&GOTPLT[0]) write32(Buf + 4, 0x8dd90000); // lw $25, %lo(&GOTPLT[0])($14) write32(Buf + 8, 0x25ce0000); // addiu $14, $14, %lo(&GOTPLT[0]) write32(Buf + 12, 0x030ec023); // subu $24, $24, $14 } else { write32(Buf, 0x3c1c0000); // lui $28, %hi(&GOTPLT[0]) write32(Buf + 4, 0x8f990000); // lw $25, %lo(&GOTPLT[0])($28) write32(Buf + 8, 0x279c0000); // addiu $28, $28, %lo(&GOTPLT[0]) write32(Buf + 12, 0x031cc023); // subu $24, $24, $28 } write32(Buf + 16, 0x03e07825); // move $15, $31 write32(Buf + 20, 0x0018c082); // srl $24, $24, 2 write32(Buf + 24, 0x0320f809); // jalr $25 write32(Buf + 28, 0x2718fffe); // subu $24, $24, 2 uint64_t GotPlt = In::GotPlt->getVA(); writeMipsHi16(Buf, GotPlt); writeMipsLo16(Buf + 4, GotPlt); writeMipsLo16(Buf + 8, GotPlt); } template void MipsTargetInfo::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const { const endianness E = ELFT::TargetEndianness; write32(Buf, 0x3c0f0000); // lui $15, %hi(.got.plt entry) write32(Buf + 4, 0x8df90000); // l[wd] $25, %lo(.got.plt entry)($15) // jr $25 write32(Buf + 8, isMipsR6() ? 0x03200009 : 0x03200008); write32(Buf + 12, 0x25f80000); // addiu $24, $15, %lo(.got.plt entry) writeMipsHi16(Buf, GotPltEntryAddr); writeMipsLo16(Buf + 4, GotPltEntryAddr); writeMipsLo16(Buf + 12, GotPltEntryAddr); } template bool MipsTargetInfo::needsThunk(RelExpr Expr, uint32_t Type, const InputFile *File, const SymbolBody &S) const { // Any MIPS PIC code function is invoked with its address in register $t9. // So if we have a branch instruction from non-PIC code to the PIC one // we cannot make the jump directly and need to create a small stubs // to save the target function address. // See page 3-38 ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf if (Type != R_MIPS_26) return false; auto *F = dyn_cast_or_null>(File); if (!F) return false; // If current file has PIC code, LA25 stub is not required. if (F->getObj().getHeader()->e_flags & EF_MIPS_PIC) return false; auto *D = dyn_cast(&S); // LA25 is required if target file has PIC code // or target symbol is a PIC symbol. return D && D->isMipsPIC(); } template int64_t MipsTargetInfo::getImplicitAddend(const uint8_t *Buf, uint32_t Type) const { const endianness E = ELFT::TargetEndianness; switch (Type) { default: return 0; case R_MIPS_32: case R_MIPS_GPREL32: case R_MIPS_TLS_DTPREL32: case R_MIPS_TLS_TPREL32: return SignExtend64<32>(read32(Buf)); case R_MIPS_26: // FIXME (simon): If the relocation target symbol is not a PLT entry // we should use another expression for calculation: // ((A << 2) | (P & 0xf0000000)) >> 2 return SignExtend64<28>((read32(Buf) & 0x3ffffff) << 2); case R_MIPS_GPREL16: case R_MIPS_LO16: case R_MIPS_PCLO16: case R_MIPS_TLS_DTPREL_HI16: case R_MIPS_TLS_DTPREL_LO16: case R_MIPS_TLS_TPREL_HI16: case R_MIPS_TLS_TPREL_LO16: return SignExtend64<16>(read32(Buf)); case R_MIPS_PC16: return getPcRelocAddend(Buf); case R_MIPS_PC19_S2: return getPcRelocAddend(Buf); case R_MIPS_PC21_S2: return getPcRelocAddend(Buf); case R_MIPS_PC26_S2: return getPcRelocAddend(Buf); case R_MIPS_PC32: return getPcRelocAddend(Buf); } } static std::pair calculateMipsRelChain(uint8_t *Loc, uint32_t Type, uint64_t Val) { // MIPS N64 ABI packs multiple relocations into the single relocation // record. In general, all up to three relocations can have arbitrary // types. In fact, Clang and GCC uses only a few combinations. For now, // we support two of them. That is allow to pass at least all LLVM // test suite cases. // / R_MIPS_SUB / R_MIPS_HI16 | R_MIPS_LO16 // / R_MIPS_64 / R_MIPS_NONE // The first relocation is a 'real' relocation which is calculated // using the corresponding symbol's value. The second and the third // relocations used to modify result of the first one: extend it to // 64-bit, extract high or low part etc. For details, see part 2.9 Relocation // at the https://dmz-portal.mips.com/mw/images/8/82/007-4658-001.pdf uint32_t Type2 = (Type >> 8) & 0xff; uint32_t Type3 = (Type >> 16) & 0xff; if (Type2 == R_MIPS_NONE && Type3 == R_MIPS_NONE) return std::make_pair(Type, Val); if (Type2 == R_MIPS_64 && Type3 == R_MIPS_NONE) return std::make_pair(Type2, Val); if (Type2 == R_MIPS_SUB && (Type3 == R_MIPS_HI16 || Type3 == R_MIPS_LO16)) return std::make_pair(Type3, -Val); error(getErrorLocation(Loc) + "unsupported relocations combination " + Twine(Type)); return std::make_pair(Type & 0xff, Val); } template void MipsTargetInfo::relocateOne(uint8_t *Loc, uint32_t Type, uint64_t Val) const { const endianness E = ELFT::TargetEndianness; // Thread pointer and DRP offsets from the start of TLS data area. // https://www.linux-mips.org/wiki/NPTL if (Type == R_MIPS_TLS_DTPREL_HI16 || Type == R_MIPS_TLS_DTPREL_LO16 || Type == R_MIPS_TLS_DTPREL32 || Type == R_MIPS_TLS_DTPREL64) Val -= 0x8000; else if (Type == R_MIPS_TLS_TPREL_HI16 || Type == R_MIPS_TLS_TPREL_LO16 || Type == R_MIPS_TLS_TPREL32 || Type == R_MIPS_TLS_TPREL64) Val -= 0x7000; if (ELFT::Is64Bits || Config->MipsN32Abi) std::tie(Type, Val) = calculateMipsRelChain(Loc, Type, Val); switch (Type) { case R_MIPS_32: case R_MIPS_GPREL32: case R_MIPS_TLS_DTPREL32: case R_MIPS_TLS_TPREL32: write32(Loc, Val); break; case R_MIPS_64: case R_MIPS_TLS_DTPREL64: case R_MIPS_TLS_TPREL64: write64(Loc, Val); break; case R_MIPS_26: write32(Loc, (read32(Loc) & ~0x3ffffff) | ((Val >> 2) & 0x3ffffff)); break; case R_MIPS_GOT16: // The R_MIPS_GOT16 relocation's value in "relocatable" linking mode // is updated addend (not a GOT index). In that case write high 16 bits // to store a correct addend value. if (Config->Relocatable) writeMipsHi16(Loc, Val); else { checkInt<16>(Loc, Val, Type); writeMipsLo16(Loc, Val); } break; case R_MIPS_GOT_DISP: case R_MIPS_GOT_PAGE: case R_MIPS_GPREL16: case R_MIPS_TLS_GD: case R_MIPS_TLS_LDM: checkInt<16>(Loc, Val, Type); // fallthrough case R_MIPS_CALL16: case R_MIPS_CALL_LO16: case R_MIPS_GOT_LO16: case R_MIPS_GOT_OFST: case R_MIPS_LO16: case R_MIPS_PCLO16: case R_MIPS_TLS_DTPREL_LO16: case R_MIPS_TLS_GOTTPREL: case R_MIPS_TLS_TPREL_LO16: writeMipsLo16(Loc, Val); break; case R_MIPS_CALL_HI16: case R_MIPS_GOT_HI16: case R_MIPS_HI16: case R_MIPS_PCHI16: case R_MIPS_TLS_DTPREL_HI16: case R_MIPS_TLS_TPREL_HI16: writeMipsHi16(Loc, Val); break; case R_MIPS_HIGHER: writeMipsHigher(Loc, Val); break; case R_MIPS_HIGHEST: writeMipsHighest(Loc, Val); break; case R_MIPS_JALR: // Ignore this optimization relocation for now break; case R_MIPS_PC16: applyMipsPcReloc(Loc, Type, Val); break; case R_MIPS_PC19_S2: applyMipsPcReloc(Loc, Type, Val); break; case R_MIPS_PC21_S2: applyMipsPcReloc(Loc, Type, Val); break; case R_MIPS_PC26_S2: applyMipsPcReloc(Loc, Type, Val); break; case R_MIPS_PC32: applyMipsPcReloc(Loc, Type, Val); break; default: error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type)); } } template bool MipsTargetInfo::usesOnlyLowPageBits(uint32_t Type) const { return Type == R_MIPS_LO16 || Type == R_MIPS_GOT_OFST; } } } Index: vendor/lld/dist/ELF/Writer.cpp =================================================================== --- vendor/lld/dist/ELF/Writer.cpp (revision 317766) +++ vendor/lld/dist/ELF/Writer.cpp (revision 317767) @@ -1,1822 +1,1822 @@ //===- Writer.cpp ---------------------------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "Writer.h" #include "Config.h" #include "Filesystem.h" #include "LinkerScript.h" #include "MapFile.h" #include "Memory.h" #include "OutputSections.h" #include "Relocations.h" #include "Strings.h" #include "SymbolTable.h" #include "SyntheticSections.h" #include "Target.h" #include "Threads.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/FileOutputBuffer.h" #include "llvm/Support/raw_ostream.h" #include using namespace llvm; using namespace llvm::ELF; using namespace llvm::object; using namespace llvm::support; using namespace llvm::support::endian; using namespace lld; using namespace lld::elf; namespace { // The writer writes a SymbolTable result to a file. template class Writer { public: typedef typename ELFT::Shdr Elf_Shdr; typedef typename ELFT::Ehdr Elf_Ehdr; typedef typename ELFT::Phdr Elf_Phdr; void run(); private: void createSyntheticSections(); void copyLocalSymbols(); void addSectionSymbols(); void addReservedSymbols(); void createSections(); void forEachRelSec(std::function Fn); void sortSections(); void finalizeSections(); void addPredefinedSections(); std::vector createPhdrs(); void removeEmptyPTLoad(); void addPtArmExid(std::vector &Phdrs); void assignFileOffsets(); void assignFileOffsetsBinary(); void setPhdrs(); void fixHeaders(); void fixSectionAlignments(); void fixPredefinedSymbols(); void openFile(); void writeHeader(); void writeSections(); void writeSectionsBinary(); void writeBuildId(); std::unique_ptr Buffer; std::vector OutputSections; OutputSectionFactory Factory{OutputSections}; void addRelIpltSymbols(); void addStartEndSymbols(); void addStartStopSymbols(OutputSection *Sec); uint64_t getEntryAddr(); OutputSection *findSection(StringRef Name); std::vector Phdrs; uint64_t FileSize; uint64_t SectionHeaderOff; bool AllocateHeader = true; }; } // anonymous namespace StringRef elf::getOutputSectionName(StringRef Name) { if (Config->Relocatable) return Name; // If -emit-relocs is given (which is rare), we need to copy // relocation sections to the output. If input section .foo is // output as .bar, we want to rename .rel.foo .rel.bar as well. if (Config->EmitRelocs) { for (StringRef V : {".rel.", ".rela."}) { if (Name.startswith(V)) { StringRef Inner = getOutputSectionName(Name.substr(V.size() - 1)); return Saver.save(V.drop_back() + Inner); } } } for (StringRef V : {".text.", ".rodata.", ".data.rel.ro.", ".data.", ".bss.rel.ro.", ".bss.", ".init_array.", ".fini_array.", ".ctors.", ".dtors.", ".tbss.", ".gcc_except_table.", ".tdata.", ".ARM.exidx."}) { StringRef Prefix = V.drop_back(); if (Name.startswith(V) || Name == Prefix) return Prefix; } // CommonSection is identified as "COMMON" in linker scripts. // By default, it should go to .bss section. if (Name == "COMMON") return ".bss"; // ".zdebug_" is a prefix for ZLIB-compressed sections. // Because we decompressed input sections, we want to remove 'z'. if (Name.startswith(".zdebug_")) return Saver.save("." + Name.substr(2)); return Name; } template static bool needsInterpSection() { return !Symtab::X->getSharedFiles().empty() && !Config->DynamicLinker.empty() && !Script->ignoreInterpSection(); } template void elf::writeResult() { Writer().run(); } template void Writer::removeEmptyPTLoad() { auto I = std::remove_if(Phdrs.begin(), Phdrs.end(), [&](const PhdrEntry &P) { if (P.p_type != PT_LOAD) return false; if (!P.First) return true; uint64_t Size = P.Last->Addr + P.Last->Size - P.First->Addr; return Size == 0; }); Phdrs.erase(I, Phdrs.end()); } // This function scans over the input sections and creates mergeable // synthetic sections. It removes MergeInputSections from array and // adds new synthetic ones. Each synthetic section is added to the // location of the first input section it replaces. static void combineMergableSections() { std::vector MergeSections; for (InputSectionBase *&S : InputSections) { MergeInputSection *MS = dyn_cast(S); if (!MS) continue; // We do not want to handle sections that are not alive, so just remove // them instead of trying to merge. if (!MS->Live) continue; StringRef OutsecName = getOutputSectionName(MS->Name); uint64_t Flags = MS->Flags & ~(uint64_t)(SHF_GROUP | SHF_COMPRESSED); uint32_t Alignment = std::max(MS->Alignment, MS->Entsize); auto I = llvm::find_if(MergeSections, [=](MergeSyntheticSection *Sec) { return Sec->Name == OutsecName && Sec->Flags == Flags && Sec->Alignment == Alignment; }); if (I == MergeSections.end()) { MergeSyntheticSection *Syn = make(OutsecName, MS->Type, Flags, Alignment); MergeSections.push_back(Syn); I = std::prev(MergeSections.end()); S = Syn; } else { S = nullptr; } (*I)->addSection(MS); } std::vector &V = InputSections; V.erase(std::remove(V.begin(), V.end(), nullptr), V.end()); } template static void combineEhFrameSections() { for (InputSectionBase *&S : InputSections) { EhInputSection *ES = dyn_cast(S); if (!ES || !ES->Live) continue; In::EhFrame->addSection(ES); S = nullptr; } std::vector &V = InputSections; V.erase(std::remove(V.begin(), V.end(), nullptr), V.end()); } // The main function of the writer. template void Writer::run() { // Create linker-synthesized sections such as .got or .plt. // Such sections are of type input section. createSyntheticSections(); combineMergableSections(); if (!Config->Relocatable) combineEhFrameSections(); // We need to create some reserved symbols such as _end. Create them. if (!Config->Relocatable) addReservedSymbols(); // Create output sections. Script->OutputSections = &OutputSections; if (Script->Opt.HasSections) { // If linker script contains SECTIONS commands, let it create sections. Script->processCommands(Factory); // Linker scripts may have left some input sections unassigned. // Assign such sections using the default rule. Script->addOrphanSections(Factory); } else { // If linker script does not contain SECTIONS commands, create // output sections by default rules. We still need to give the // linker script a chance to run, because it might contain // non-SECTIONS commands such as ASSERT. createSections(); Script->processCommands(Factory); } if (Config->Discard != DiscardPolicy::All) copyLocalSymbols(); if (Config->CopyRelocs) addSectionSymbols(); // Now that we have a complete set of output sections. This function // completes section contents. For example, we need to add strings // to the string table, and add entries to .got and .plt. // finalizeSections does that. finalizeSections(); if (ErrorCount) return; if (Config->Relocatable) { assignFileOffsets(); } else { if (!Script->Opt.HasSections) { fixSectionAlignments(); - Script->fabricateDefaultCommands(Config->MaxPageSize); + Script->fabricateDefaultCommands(AllocateHeader); } Script->synchronize(); Script->assignAddresses(Phdrs); // Remove empty PT_LOAD to avoid causing the dynamic linker to try to mmap a // 0 sized region. This has to be done late since only after assignAddresses // we know the size of the sections. removeEmptyPTLoad(); if (!Config->OFormatBinary) assignFileOffsets(); else assignFileOffsetsBinary(); setPhdrs(); fixPredefinedSymbols(); } // It does not make sense try to open the file if we have error already. if (ErrorCount) return; // Write the result down to a file. openFile(); if (ErrorCount) return; if (!Config->OFormatBinary) { writeHeader(); writeSections(); } else { writeSectionsBinary(); } // 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. writeBuildId(); if (ErrorCount) return; // Handle -Map option. writeMapFile(OutputSections); if (ErrorCount) return; if (auto EC = Buffer->commit()) error("failed to write to the output file: " + EC.message()); // Flush the output streams and exit immediately. A full shutdown // is a good test that we are keeping track of all allocated memory, // but actually freeing it is a waste of time in a regular linker run. if (Config->ExitEarly) exitLld(0); } // Initialize Out members. template void Writer::createSyntheticSections() { // Initialize all pointers with NULL. This is needed because // you can call lld::elf::main more than once as a library. memset(&Out::First, 0, sizeof(Out)); auto Add = [](InputSectionBase *Sec) { InputSections.push_back(Sec); }; In::DynStrTab = make(".dynstr", true); In::Dynamic = make>(); In::RelaDyn = make>( Config->IsRela ? ".rela.dyn" : ".rel.dyn", Config->ZCombreloc); In::ShStrTab = make(".shstrtab", false); Out::ElfHeader = make("", 0, SHF_ALLOC); Out::ElfHeader->Size = sizeof(Elf_Ehdr); Out::ProgramHeaders = make("", 0, SHF_ALLOC); Out::ProgramHeaders->updateAlignment(Config->Wordsize); if (needsInterpSection()) { In::Interp = createInterpSection(); Add(In::Interp); } else { In::Interp = nullptr; } if (!Config->Relocatable) Add(createCommentSection()); if (Config->Strip != StripPolicy::All) { In::StrTab = make(".strtab", false); In::SymTab = make>(*In::StrTab); } if (Config->BuildId != BuildIdKind::None) { In::BuildId = make(); Add(In::BuildId); } In::Common = createCommonSection(); if (In::Common) Add(InX::Common); In::Bss = make(".bss"); Add(In::Bss); In::BssRelRo = make(".bss.rel.ro"); Add(In::BssRelRo); // Add MIPS-specific sections. bool HasDynSymTab = !Symtab::X->getSharedFiles().empty() || Config->Pic || Config->ExportDynamic; if (Config->EMachine == EM_MIPS) { if (!Config->Shared && HasDynSymTab) { In::MipsRldMap = make(); Add(In::MipsRldMap); } if (auto *Sec = MipsAbiFlagsSection::create()) Add(Sec); if (auto *Sec = MipsOptionsSection::create()) Add(Sec); if (auto *Sec = MipsReginfoSection::create()) Add(Sec); } if (HasDynSymTab) { In::DynSymTab = make>(*In::DynStrTab); Add(In::DynSymTab); In::VerSym = make>(); Add(In::VerSym); if (!Config->VersionDefinitions.empty()) { In::VerDef = make>(); Add(In::VerDef); } In::VerNeed = make>(); Add(In::VerNeed); if (Config->GnuHash) { In::GnuHashTab = make>(); Add(In::GnuHashTab); } if (Config->SysvHash) { In::HashTab = make>(); Add(In::HashTab); } Add(In::Dynamic); Add(In::DynStrTab); Add(In::RelaDyn); } // Add .got. MIPS' .got is so different from the other archs, // it has its own class. if (Config->EMachine == EM_MIPS) { In::MipsGot = make(); Add(In::MipsGot); } else { In::Got = make>(); Add(In::Got); } In::GotPlt = make(); Add(In::GotPlt); In::IgotPlt = make(); Add(In::IgotPlt); if (Config->GdbIndex) { In::GdbIndex = make(); Add(In::GdbIndex); } // We always need to add rel[a].plt to output if it has entries. // Even for static linking it can contain R_[*]_IRELATIVE relocations. In::RelaPlt = make>( Config->IsRela ? ".rela.plt" : ".rel.plt", false /*Sort*/); Add(In::RelaPlt); // The RelaIplt immediately follows .rel.plt (.rel.dyn for ARM) to ensure // that the IRelative relocations are processed last by the dynamic loader In::RelaIplt = make>( (Config->EMachine == EM_ARM) ? ".rel.dyn" : In::RelaPlt->Name, false /*Sort*/); Add(In::RelaIplt); In::Plt = make(Target->PltHeaderSize); Add(In::Plt); In::Iplt = make(0); Add(In::Iplt); if (!Config->Relocatable) { if (Config->EhFrameHdr) { In::EhFrameHdr = make>(); Add(In::EhFrameHdr); } In::EhFrame = make>(); Add(In::EhFrame); } if (In::SymTab) Add(In::SymTab); Add(In::ShStrTab); if (In::StrTab) Add(In::StrTab); } static bool shouldKeepInSymtab(SectionBase *Sec, StringRef SymName, const SymbolBody &B) { if (B.isFile() || B.isSection()) return false; // If sym references a section in a discarded group, don't keep it. if (Sec == &InputSection::Discarded) return false; if (Config->Discard == DiscardPolicy::None) return true; // In ELF assembly .L symbols are normally discarded by the assembler. // If the assembler fails to do so, the linker discards them if // * --discard-locals is used. // * The symbol is in a SHF_MERGE section, which is normally the reason for // the assembler keeping the .L symbol. if (!SymName.startswith(".L") && !SymName.empty()) return true; if (Config->Discard == DiscardPolicy::Locals) return false; return !Sec || !(Sec->Flags & SHF_MERGE); } static bool includeInSymtab(const SymbolBody &B) { if (!B.isLocal() && !B.symbol()->IsUsedInRegularObj) return false; if (auto *D = dyn_cast(&B)) { // Always include absolute symbols. SectionBase *Sec = D->Section; if (!Sec) return true; if (auto *IS = dyn_cast(Sec)) { Sec = IS->Repl; IS = cast(Sec); // Exclude symbols pointing to garbage-collected sections. if (!IS->Live) return false; } if (auto *S = dyn_cast(Sec)) if (!S->getSectionPiece(D->Value)->Live) return false; } return true; } // Local symbols are not in the linker's symbol table. This function scans // each object file's symbol table to copy local symbols to the output. template void Writer::copyLocalSymbols() { if (!In::SymTab) return; for (elf::ObjectFile *F : Symtab::X->getObjectFiles()) { for (SymbolBody *B : F->getLocalSymbols()) { if (!B->IsLocal) fatal(toString(F) + ": broken object: getLocalSymbols returns a non-local symbol"); auto *DR = dyn_cast(B); // No reason to keep local undefined symbol in symtab. if (!DR) continue; if (!includeInSymtab(*B)) continue; SectionBase *Sec = DR->Section; if (!shouldKeepInSymtab(Sec, B->getName(), *B)) continue; In::SymTab->addSymbol(B); } } } template void Writer::addSectionSymbols() { // Create one STT_SECTION symbol for each output section we might // have a relocation with. for (OutputSection *Sec : OutputSections) { if (Sec->Sections.empty()) continue; InputSection *IS = Sec->Sections[0]; if (isa(IS) || IS->Type == SHT_REL || IS->Type == SHT_RELA) continue; auto *Sym = make("", /*IsLocal=*/true, /*StOther=*/0, STT_SECTION, /*Value=*/0, /*Size=*/0, IS, nullptr); In::SymTab->addSymbol(Sym); } } // PPC64 has a number of special SHT_PROGBITS+SHF_ALLOC+SHF_WRITE sections that // we would like to make sure appear is a specific order to maximize their // coverage by a single signed 16-bit offset from the TOC base pointer. // Conversely, the special .tocbss section should be first among all SHT_NOBITS // sections. This will put it next to the loaded special PPC64 sections (and, // thus, within reach of the TOC base pointer). static int getPPC64SectionRank(StringRef SectionName) { return StringSwitch(SectionName) .Case(".tocbss", 0) .Case(".branch_lt", 2) .Case(".toc", 3) .Case(".toc1", 4) .Case(".opd", 5) .Default(1); } // All sections with SHF_MIPS_GPREL flag should be grouped together // because data in these sections is addressable with a gp relative address. static int getMipsSectionRank(const OutputSection *S) { if ((S->Flags & SHF_MIPS_GPREL) == 0) return 0; if (S->Name == ".got") return 1; return 2; } // Today's loaders have a feature to make segments read-only after // processing dynamic relocations to enhance security. PT_GNU_RELRO // is defined for that. // // This function returns true if a section needs to be put into a // PT_GNU_RELRO segment. template bool elf::isRelroSection(const OutputSection *Sec) { if (!Config->ZRelro) return false; uint64_t Flags = Sec->Flags; // Non-allocatable or non-writable sections don't need RELRO because // they are not writable or not even mapped to memory in the first place. // RELRO is for sections that are essentially read-only but need to // be writable only at process startup to allow dynamic linker to // apply relocations. if (!(Flags & SHF_ALLOC) || !(Flags & SHF_WRITE)) return false; // Once initialized, TLS data segments are used as data templates // for a thread-local storage. For each new thread, runtime // allocates memory for a TLS and copy templates there. No thread // are supposed to use templates directly. Thus, it can be in RELRO. if (Flags & SHF_TLS) return true; // .init_array, .preinit_array and .fini_array contain pointers to // functions that are executed on process startup or exit. These // pointers are set by the static linker, and they are not expected // to change at runtime. But if you are an attacker, you could do // interesting things by manipulating pointers in .fini_array, for // example. So they are put into RELRO. uint32_t Type = Sec->Type; if (Type == SHT_INIT_ARRAY || Type == SHT_FINI_ARRAY || Type == SHT_PREINIT_ARRAY) return true; // .got contains pointers to external symbols. They are resolved by // the dynamic linker when a module is loaded into memory, and after // that they are not expected to change. So, it can be in RELRO. if (In::Got && Sec == In::Got->OutSec) return true; // .got.plt contains pointers to external function symbols. They are // by default resolved lazily, so we usually cannot put it into RELRO. // However, if "-z now" is given, the lazy symbol resolution is // disabled, which enables us to put it into RELRO. if (Sec == In::GotPlt->OutSec) return Config->ZNow; // .dynamic section contains data for the dynamic linker, and // there's no need to write to it at runtime, so it's better to put // it into RELRO. if (Sec == In::Dynamic->OutSec) return true; // .bss.rel.ro is used for copy relocations for read-only symbols. // Since the dynamic linker needs to process copy relocations, the // section cannot be read-only, but once initialized, they shouldn't // change. if (Sec == In::BssRelRo->OutSec) return true; // Sections with some special names are put into RELRO. This is a // bit unfortunate because section names shouldn't be significant in // ELF in spirit. But in reality many linker features depend on // magic section names. StringRef S = Sec->Name; return S == ".data.rel.ro" || S == ".ctors" || S == ".dtors" || S == ".jcr" || S == ".eh_frame" || S == ".openbsd.randomdata"; } template static bool compareSectionsNonScript(const OutputSection *A, const OutputSection *B) { // Put .interp first because some loaders want to see that section // on the first page of the executable file when loaded into memory. bool AIsInterp = A->Name == ".interp"; bool BIsInterp = B->Name == ".interp"; if (AIsInterp != BIsInterp) return AIsInterp; // Allocatable sections go first to reduce the total PT_LOAD size and // so debug info doesn't change addresses in actual code. bool AIsAlloc = A->Flags & SHF_ALLOC; bool BIsAlloc = B->Flags & SHF_ALLOC; if (AIsAlloc != BIsAlloc) return AIsAlloc; // We don't have any special requirements for the relative order of two non // allocatable sections. if (!AIsAlloc) return false; // We want to put section specified by -T option first, so we // can start assigning VA starting from them later. auto AAddrSetI = Config->SectionStartMap.find(A->Name); auto BAddrSetI = Config->SectionStartMap.find(B->Name); bool AHasAddrSet = AAddrSetI != Config->SectionStartMap.end(); bool BHasAddrSet = BAddrSetI != Config->SectionStartMap.end(); if (AHasAddrSet != BHasAddrSet) return AHasAddrSet; if (AHasAddrSet) return AAddrSetI->second < BAddrSetI->second; // 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. bool AIsWritable = A->Flags & SHF_WRITE; bool BIsWritable = B->Flags & SHF_WRITE; if (AIsWritable != BIsWritable) return BIsWritable; if (!Config->SingleRoRx) { // 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. bool AIsExec = A->Flags & SHF_EXECINSTR; bool BIsExec = B->Flags & SHF_EXECINSTR; if (AIsExec != BIsExec) return BIsExec; } // If we got here we know that both A and B are in the same PT_LOAD. bool AIsTls = A->Flags & SHF_TLS; bool BIsTls = B->Flags & SHF_TLS; bool AIsNoBits = A->Type == SHT_NOBITS; bool BIsNoBits = B->Type == SHT_NOBITS; // The first requirement we have is to put (non-TLS) nobits sections last. The // reason is that the only thing the dynamic linker will see about them is a // p_memsz that is larger than p_filesz. Seeing that it zeros the end of the // PT_LOAD, so that has to correspond to the nobits sections. bool AIsNonTlsNoBits = AIsNoBits && !AIsTls; bool BIsNonTlsNoBits = BIsNoBits && !BIsTls; if (AIsNonTlsNoBits != BIsNonTlsNoBits) return BIsNonTlsNoBits; // We place nobits RelRo sections before plain r/w ones, and non-nobits RelRo // sections after r/w ones, so that the RelRo sections are contiguous. bool AIsRelRo = isRelroSection(A); bool BIsRelRo = isRelroSection(B); if (AIsRelRo != BIsRelRo) return AIsNonTlsNoBits ? AIsRelRo : BIsRelRo; // The TLS initialization block needs to be a single contiguous block in a R/W // PT_LOAD, so stick TLS sections directly before the other RelRo R/W // sections. The TLS NOBITS sections are placed here as they don't take up // virtual address space in the PT_LOAD. if (AIsTls != BIsTls) return AIsTls; // Within the TLS initialization block, the non-nobits sections need to appear // first. if (AIsNoBits != BIsNoBits) return BIsNoBits; // Some architectures have additional ordering restrictions for sections // within the same PT_LOAD. if (Config->EMachine == EM_PPC64) return getPPC64SectionRank(A->Name) < getPPC64SectionRank(B->Name); if (Config->EMachine == EM_MIPS) return getMipsSectionRank(A) < getMipsSectionRank(B); return false; } // Output section ordering is determined by this function. template static bool compareSections(const OutputSection *A, const OutputSection *B) { // For now, put sections mentioned in a linker script first. int AIndex = Script->getSectionIndex(A->Name); int BIndex = Script->getSectionIndex(B->Name); bool AInScript = AIndex != INT_MAX; bool BInScript = BIndex != INT_MAX; if (AInScript != BInScript) return AInScript; // If both are in the script, use that order. if (AInScript) return AIndex < BIndex; 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) First = Sec; p_align = std::max(p_align, Sec->Alignment); if (p_type == PT_LOAD) Sec->FirstInPtLoad = First; } template static Symbol *addRegular(StringRef Name, SectionBase *Sec, uint64_t Value, uint8_t StOther = STV_HIDDEN, uint8_t Binding = STB_WEAK) { // The linker generated symbols are added as STB_WEAK to allow user defined // ones to override them. return Symtab::X->addRegular(Name, StOther, STT_NOTYPE, Value, /*Size=*/0, Binding, Sec, /*File=*/nullptr); } template static DefinedRegular * addOptionalRegular(StringRef Name, SectionBase *Sec, uint64_t Val, uint8_t StOther = STV_HIDDEN, uint8_t Binding = STB_GLOBAL) { SymbolBody *S = Symtab::X->find(Name); if (!S) return nullptr; if (S->isInCurrentDSO()) return nullptr; return cast( addRegular(Name, Sec, Val, StOther, Binding)->body()); } // The beginning and the ending of .rel[a].plt section are marked // with __rel[a]_iplt_{start,end} symbols if it is a statically linked // executable. The runtime needs these symbols in order to resolve // all IRELATIVE relocs on startup. For dynamic executables, we don't // need these symbols, since IRELATIVE relocs are resolved through GOT // and PLT. For details, see http://www.airs.com/blog/archives/403. template void Writer::addRelIpltSymbols() { if (In::DynSymTab) return; StringRef S = Config->IsRela ? "__rela_iplt_start" : "__rel_iplt_start"; addOptionalRegular(S, In::RelaIplt, 0, STV_HIDDEN, STB_WEAK); S = Config->IsRela ? "__rela_iplt_end" : "__rel_iplt_end"; addOptionalRegular(S, In::RelaIplt, -1, STV_HIDDEN, STB_WEAK); } // The linker is expected to define some symbols depending on // the linking result. This function defines such symbols. template void Writer::addReservedSymbols() { if (Config->EMachine == EM_MIPS) { // Define _gp for MIPS. st_value of _gp symbol will be updated by Writer // so that it points to an absolute address which by default is relative // to GOT. Default offset is 0x7ff0. // See "Global Data Symbols" in Chapter 6 in the following document: // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf ElfSym::MipsGp = Symtab::X->addAbsolute("_gp", STV_HIDDEN, STB_LOCAL); // On MIPS O32 ABI, _gp_disp is a magic symbol designates offset between // start of function and 'gp' pointer into GOT. if (Symtab::X->find("_gp_disp")) ElfSym::MipsGpDisp = Symtab::X->addAbsolute("_gp_disp", STV_HIDDEN, STB_LOCAL); // The __gnu_local_gp is a magic symbol equal to the current value of 'gp' // pointer. This symbol is used in the code generated by .cpload pseudo-op // in case of using -mno-shared option. // https://sourceware.org/ml/binutils/2004-12/msg00094.html if (Symtab::X->find("__gnu_local_gp")) ElfSym::MipsLocalGp = Symtab::X->addAbsolute("__gnu_local_gp", STV_HIDDEN, STB_LOCAL); } // In the assembly for 32 bit x86 the _GLOBAL_OFFSET_TABLE_ symbol // is magical and is used to produce a R_386_GOTPC relocation. // The R_386_GOTPC relocation value doesn't actually depend on the // symbol value, so it could use an index of STN_UNDEF which, according // to the spec, means the symbol value is 0. // Unfortunately both gas and MC keep the _GLOBAL_OFFSET_TABLE_ symbol in // the object file. // The situation is even stranger on x86_64 where the assembly doesn't // need the magical symbol, but gas still puts _GLOBAL_OFFSET_TABLE_ as // an undefined symbol in the .o files. // Given that the symbol is effectively unused, we just create a dummy // hidden one to avoid the undefined symbol error. Symtab::X->addIgnored("_GLOBAL_OFFSET_TABLE_"); // __tls_get_addr is defined by the dynamic linker for dynamic ELFs. For // static linking the linker is required to optimize away any references to // __tls_get_addr, so it's not defined anywhere. Create a hidden definition // to avoid the undefined symbol error. if (!In::DynSymTab) Symtab::X->addIgnored("__tls_get_addr"); // If linker script do layout we do not need to create any standart symbols. if (Script->Opt.HasSections) return; // __ehdr_start is the location of ELF file headers. addOptionalRegular("__ehdr_start", Out::ElfHeader, 0, STV_HIDDEN); auto Add = [](StringRef S) { return addOptionalRegular(S, Out::ElfHeader, 0, STV_DEFAULT); }; ElfSym::Bss = Add("__bss_start"); ElfSym::End1 = Add("end"); ElfSym::End2 = Add("_end"); ElfSym::Etext1 = Add("etext"); ElfSym::Etext2 = Add("_etext"); ElfSym::Edata1 = Add("edata"); ElfSym::Edata2 = Add("_edata"); } // Sort input sections by section name suffixes for // __attribute__((init_priority(N))). static void sortInitFini(OutputSection *S) { if (S) reinterpret_cast(S)->sortInitFini(); } // Sort input sections by the special rule for .ctors and .dtors. static void sortCtorsDtors(OutputSection *S) { if (S) reinterpret_cast(S)->sortCtorsDtors(); } // Sort input sections using the list provided by --symbol-ordering-file. template static void sortBySymbolsOrder(ArrayRef OutputSections) { if (Config->SymbolOrderingFile.empty()) return; // Build a map from symbols to their priorities. Symbols that didn't // appear in the symbol ordering file have the lowest priority 0. // All explicitly mentioned symbols have negative (higher) priorities. DenseMap SymbolOrder; int Priority = -Config->SymbolOrderingFile.size(); for (StringRef S : Config->SymbolOrderingFile) SymbolOrder.insert({S, Priority++}); // Build a map from sections to their priorities. DenseMap SectionOrder; for (elf::ObjectFile *File : Symtab::X->getObjectFiles()) { for (SymbolBody *Body : File->getSymbols()) { auto *D = dyn_cast(Body); if (!D || !D->Section) continue; int &Priority = SectionOrder[D->Section]; Priority = std::min(Priority, SymbolOrder.lookup(D->getName())); } } // Sort sections by priority. for (OutputSection *Base : OutputSections) if (auto *Sec = dyn_cast(Base)) Sec->sort([&](InputSectionBase *S) { return SectionOrder.lookup(S); }); } template void Writer::forEachRelSec(std::function Fn) { for (InputSectionBase *IS : InputSections) { if (!IS->Live) continue; // Scan all relocations. Each relocation goes through a series // of tests to determine if it needs special treatment, such as // creating GOT, PLT, copy relocations, etc. // Note that relocations for non-alloc sections are directly // processed by InputSection::relocateNonAlloc. if (!(IS->Flags & SHF_ALLOC)) continue; if (isa(IS) || isa(IS)) Fn(*IS); } if (!Config->Relocatable) { for (EhInputSection *ES : In::EhFrame->Sections) Fn(*ES); } } template void Writer::createSections() { for (InputSectionBase *IS : InputSections) if (IS) Factory.addInputSec(IS, getOutputSectionName(IS->Name)); sortBySymbolsOrder(OutputSections); sortInitFini(findSection(".init_array")); sortInitFini(findSection(".fini_array")); sortCtorsDtors(findSection(".ctors")); sortCtorsDtors(findSection(".dtors")); for (OutputSection *Sec : OutputSections) Sec->assignOffsets(); } static bool canSharePtLoad(const OutputSection &S1, const OutputSection &S2) { if (!(S1.Flags & SHF_ALLOC) || !(S2.Flags & SHF_ALLOC)) return false; bool S1IsWrite = S1.Flags & SHF_WRITE; bool S2IsWrite = S2.Flags & SHF_WRITE; if (S1IsWrite != S2IsWrite) return false; if (!S1IsWrite) return true; // RO and RX share a PT_LOAD with linker scripts. return (S1.Flags & SHF_EXECINSTR) == (S2.Flags & SHF_EXECINSTR); } template void Writer::sortSections() { // Don't sort if using -r. It is not necessary and we want to preserve the // relative order for SHF_LINK_ORDER sections. if (Config->Relocatable) return; if (!Script->Opt.HasSections) { std::stable_sort(OutputSections.begin(), OutputSections.end(), compareSectionsNonScript); return; } Script->adjustSectionsBeforeSorting(); // The order of the sections in the script is arbitrary and may not agree with // compareSectionsNonScript. This means that we cannot easily define a // strict weak ordering. To see why, consider a comparison of a section in the // script and one not in the script. We have a two simple options: // * Make them equivalent (a is not less than b, and b is not less than a). // The problem is then that equivalence has to be transitive and we can // have sections a, b and c with only b in a script and a less than c // which breaks this property. // * Use compareSectionsNonScript. Given that the script order doesn't have // to match, we can end up with sections a, b, c, d where b and c are in the // script and c is compareSectionsNonScript less than b. In which case d // can be equivalent to c, a to b and d < a. As a concrete example: // .a (rx) # not in script // .b (rx) # in script // .c (ro) # in script // .d (ro) # not in script // // The way we define an order then is: // * First put script sections at the start and sort the script and // non-script sections independently. // * Move each non-script section to its preferred position. We try // to put each section in the last position where it it can share // a PT_LOAD. std::stable_sort(OutputSections.begin(), OutputSections.end(), compareSections); auto I = OutputSections.begin(); auto E = OutputSections.end(); auto NonScriptI = std::find_if(OutputSections.begin(), E, [](OutputSection *S) { return Script->getSectionIndex(S->Name) == INT_MAX; }); while (NonScriptI != E) { auto BestPos = std::max_element( I, NonScriptI, [&](OutputSection *&A, OutputSection *&B) { bool ACanSharePtLoad = canSharePtLoad(**NonScriptI, *A); bool BCanSharePtLoad = canSharePtLoad(**NonScriptI, *B); if (ACanSharePtLoad != BCanSharePtLoad) return BCanSharePtLoad; bool ACmp = compareSectionsNonScript(*NonScriptI, A); bool BCmp = compareSectionsNonScript(*NonScriptI, B); if (ACmp != BCmp) return BCmp; // FIXME: missing test size_t PosA = &A - &OutputSections[0]; size_t PosB = &B - &OutputSections[0]; return ACmp ? PosA > PosB : PosA < PosB; }); // max_element only returns NonScriptI if the range is empty. If the range // is not empty we should consider moving the the element forward one // position. if (BestPos != NonScriptI && !compareSectionsNonScript(*NonScriptI, *BestPos)) ++BestPos; std::rotate(BestPos, NonScriptI, NonScriptI + 1); ++NonScriptI; } Script->adjustSectionsAfterSorting(); } static void applySynthetic(const std::vector &Sections, std::function Fn) { for (SyntheticSection *SS : Sections) if (SS && SS->OutSec && !SS->empty()) { Fn(SS); SS->OutSec->assignOffsets(); } } // We need to add input synthetic sections early in createSyntheticSections() // to make them visible from linkescript side. But not all sections are always // required to be in output. For example we don't need dynamic section content // sometimes. This function filters out such unused sections from the output. static void removeUnusedSyntheticSections(std::vector &V) { // All input synthetic sections that can be empty are placed after // all regular ones. We iterate over them all and exit at first // non-synthetic. for (InputSectionBase *S : llvm::reverse(InputSections)) { SyntheticSection *SS = dyn_cast(S); if (!SS) return; if (!SS->empty() || !SS->OutSec) continue; SS->OutSec->Sections.erase(std::find(SS->OutSec->Sections.begin(), SS->OutSec->Sections.end(), SS)); SS->Live = false; // If there are no other sections in the output section, remove it from the // output. if (SS->OutSec->Sections.empty()) V.erase(std::find(V.begin(), V.end(), SS->OutSec)); } } // Create output section objects and add them to OutputSections. template void Writer::finalizeSections() { Out::DebugInfo = findSection(".debug_info"); Out::PreinitArray = findSection(".preinit_array"); Out::InitArray = findSection(".init_array"); Out::FiniArray = findSection(".fini_array"); // The linker needs to define SECNAME_start, SECNAME_end and SECNAME_stop // symbols for sections, so that the runtime can get the start and end // addresses of each section by section name. Add such symbols. if (!Config->Relocatable) { addStartEndSymbols(); for (OutputSection *Sec : OutputSections) addStartStopSymbols(Sec); } // Add _DYNAMIC symbol. Unlike GNU gold, our _DYNAMIC symbol has no type. // It should be okay as no one seems to care about the type. // Even the author of gold doesn't remember why gold behaves that way. // https://sourceware.org/ml/binutils/2002-03/msg00360.html if (In::DynSymTab) addRegular("_DYNAMIC", In::Dynamic, 0); // Define __rel[a]_iplt_{start,end} symbols if needed. addRelIpltSymbols(); // This responsible for splitting up .eh_frame section into // pieces. The relocation scan uses those pieces, so this has to be // earlier. applySynthetic({In::EhFrame}, [](SyntheticSection *SS) { SS->finalizeContents(); }); // Scan relocations. This must be done after every symbol is declared so that // we can correctly decide if a dynamic relocation is needed. forEachRelSec(scanRelocations); if (In::Plt && !In::Plt->empty()) In::Plt->addSymbols(); if (In::Iplt && !In::Iplt->empty()) In::Iplt->addSymbols(); // Now that we have defined all possible global symbols including linker- // synthesized ones. Visit all symbols to give the finishing touches. for (Symbol *S : Symtab::X->getSymbols()) { SymbolBody *Body = S->body(); if (!includeInSymtab(*Body)) continue; if (In::SymTab) In::SymTab->addSymbol(Body); if (In::DynSymTab && S->includeInDynsym()) { In::DynSymTab->addSymbol(Body); if (auto *SS = dyn_cast(Body)) if (cast>(SS->File)->isNeeded()) In::VerNeed->addSymbol(SS); } } // Do not proceed if there was an undefined symbol. if (ErrorCount) return; // So far we have added sections from input object files. // This function adds linker-created Out::* sections. addPredefinedSections(); removeUnusedSyntheticSections(OutputSections); sortSections(); // This is a bit of a hack. A value of 0 means undef, so we set it // to 1 t make __ehdr_start defined. The section number is not // particularly relevant. Out::ElfHeader->SectionIndex = 1; unsigned I = 1; for (OutputSection *Sec : OutputSections) { Sec->SectionIndex = I++; Sec->ShName = In::ShStrTab->addString(Sec->Name); } // Binary and relocatable output does not have PHDRS. // The headers have to be created before finalize as that can influence the // image base and the dynamic section on mips includes the image base. if (!Config->Relocatable && !Config->OFormatBinary) { Phdrs = Script->hasPhdrsCommands() ? Script->createPhdrs() : createPhdrs(); addPtArmExid(Phdrs); fixHeaders(); } // Dynamic section must be the last one in this list and dynamic // symbol table section (DynSymTab) must be the first one. applySynthetic({In::DynSymTab, In::Bss, In::BssRelRo, In::GnuHashTab, In::HashTab, In::SymTab, In::ShStrTab, In::StrTab, In::VerDef, In::DynStrTab, In::GdbIndex, In::Got, In::MipsGot, In::IgotPlt, In::GotPlt, In::RelaDyn, In::RelaIplt, In::RelaPlt, In::Plt, In::Iplt, In::Plt, In::EhFrameHdr, In::VerSym, In::VerNeed, In::Dynamic}, [](SyntheticSection *SS) { SS->finalizeContents(); }); // Some architectures use small displacements for jump instructions. // It is linker's responsibility to create thunks containing long // jump instructions if jump targets are too far. Create thunks. if (Target->NeedsThunks) { // FIXME: only ARM Interworking and Mips LA25 Thunks are implemented, // these // do not require address information. To support range extension Thunks // we need to assign addresses so that we can tell if jump instructions // are out of range. This will need to turn into a loop that converges // when no more Thunks are added ThunkCreator TC; if (TC.createThunks(OutputSections)) applySynthetic({In::MipsGot}, [](SyntheticSection *SS) { SS->updateAllocSize(); }); } // Fill other section headers. The dynamic table is finalized // at the end because some tags like RELSZ depend on result // of finalizing other sections. for (OutputSection *Sec : OutputSections) Sec->finalize(); // 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(); }); // createThunks may have added local symbols to the static symbol table applySynthetic({In::SymTab, In::ShStrTab, In::StrTab}, [](SyntheticSection *SS) { SS->postThunkContents(); }); } template void Writer::addPredefinedSections() { // ARM ABI requires .ARM.exidx to be terminated by some piece of data. // We have the terminater synthetic section class. Add that at the end. auto *OS = dyn_cast_or_null(findSection(".ARM.exidx")); if (OS && !OS->Sections.empty() && !Config->Relocatable) OS->addSection(make()); } // The linker is expected to define SECNAME_start and SECNAME_end // symbols for a few sections. This function defines them. template void Writer::addStartEndSymbols() { auto Define = [&](StringRef Start, StringRef End, OutputSection *OS) { // These symbols resolve to the image base if the section does not exist. // A special value -1 indicates end of the section. if (OS) { addOptionalRegular(Start, OS, 0); addOptionalRegular(End, OS, -1); } else { if (Config->Pic) OS = Out::ElfHeader; addOptionalRegular(Start, OS, 0); addOptionalRegular(End, OS, 0); } }; Define("__preinit_array_start", "__preinit_array_end", Out::PreinitArray); Define("__init_array_start", "__init_array_end", Out::InitArray); Define("__fini_array_start", "__fini_array_end", Out::FiniArray); if (OutputSection *Sec = findSection(".ARM.exidx")) Define("__exidx_start", "__exidx_end", Sec); } // If a section name is valid as a C identifier (which is rare because of // the leading '.'), linkers are expected to define __start_ and // __stop_ symbols. They are at beginning and end of the section, // respectively. This is not requested by the ELF standard, but GNU ld and // gold provide the feature, and used by many programs. template void Writer::addStartStopSymbols(OutputSection *Sec) { StringRef S = Sec->Name; if (!isValidCIdentifier(S)) return; addOptionalRegular(Saver.save("__start_" + S), Sec, 0, STV_DEFAULT); addOptionalRegular(Saver.save("__stop_" + S), Sec, -1, STV_DEFAULT); } template OutputSection *Writer::findSection(StringRef Name) { for (OutputSection *Sec : OutputSections) if (Sec->Name == Name) return Sec; return nullptr; } static bool needsPtLoad(OutputSection *Sec) { if (!(Sec->Flags & SHF_ALLOC)) return false; // Don't allocate VA space for TLS NOBITS sections. The PT_TLS PHDR is // responsible for allocating space for them, not the PT_LOAD that // contains the TLS initialization image. if (Sec->Flags & SHF_TLS && Sec->Type == SHT_NOBITS) return false; return true; } // Linker scripts are responsible for aligning addresses. Unfortunately, most // linker scripts are designed for creating two PT_LOADs only, one RX and one // RW. This means that there is no alignment in the RO to RX transition and we // cannot create a PT_LOAD there. static uint64_t computeFlags(uint64_t Flags) { if (Config->Omagic) return PF_R | PF_W | PF_X; if (Config->SingleRoRx && !(Flags & PF_W)) return Flags | PF_X; return Flags; } // Decide which program headers to create and which sections to include in each // one. template std::vector Writer::createPhdrs() { std::vector Ret; auto AddHdr = [&](unsigned Type, unsigned Flags) -> PhdrEntry * { Ret.emplace_back(Type, Flags); return &Ret.back(); }; // The first phdr entry is PT_PHDR which describes the program header itself. AddHdr(PT_PHDR, PF_R)->add(Out::ProgramHeaders); // PT_INTERP must be the second entry if exists. if (OutputSection *Sec = findSection(".interp")) AddHdr(PT_INTERP, Sec->getPhdrFlags())->add(Sec); // Add the first PT_LOAD segment for regular output sections. uint64_t Flags = computeFlags(PF_R); PhdrEntry *Load = AddHdr(PT_LOAD, Flags); for (OutputSection *Sec : OutputSections) { if (!(Sec->Flags & SHF_ALLOC)) break; if (!needsPtLoad(Sec)) continue; // Segments are contiguous memory regions that has the same attributes // (e.g. executable or writable). There is one phdr for each segment. // Therefore, we need to create a new phdr when the next section has // different flags or is loaded at a discontiguous address using AT linker // script command. uint64_t NewFlags = computeFlags(Sec->getPhdrFlags()); if (Script->hasLMA(Sec->Name) || Flags != NewFlags) { Load = AddHdr(PT_LOAD, NewFlags); Flags = NewFlags; } Load->add(Sec); } // Add a TLS segment if any. PhdrEntry TlsHdr(PT_TLS, PF_R); for (OutputSection *Sec : OutputSections) if (Sec->Flags & SHF_TLS) TlsHdr.add(Sec); if (TlsHdr.First) Ret.push_back(std::move(TlsHdr)); // Add an entry for .dynamic. if (In::DynSymTab) AddHdr(PT_DYNAMIC, In::Dynamic->OutSec->getPhdrFlags()) ->add(In::Dynamic->OutSec); // PT_GNU_RELRO includes all sections that should be marked as // read-only by dynamic linker after proccessing relocations. PhdrEntry RelRo(PT_GNU_RELRO, PF_R); for (OutputSection *Sec : OutputSections) if (needsPtLoad(Sec) && isRelroSection(Sec)) RelRo.add(Sec); if (RelRo.First) Ret.push_back(std::move(RelRo)); // PT_GNU_EH_FRAME is a special section pointing on .eh_frame_hdr. if (!In::EhFrame->empty() && In::EhFrameHdr && In::EhFrame->OutSec && In::EhFrameHdr->OutSec) AddHdr(PT_GNU_EH_FRAME, In::EhFrameHdr->OutSec->getPhdrFlags()) ->add(In::EhFrameHdr->OutSec); // PT_OPENBSD_RANDOMIZE is an OpenBSD-specific feature. That makes // the dynamic linker fill the segment with random data. if (OutputSection *Sec = findSection(".openbsd.randomdata")) AddHdr(PT_OPENBSD_RANDOMIZE, Sec->getPhdrFlags())->add(Sec); // PT_GNU_STACK is a special section to tell the loader to make the // pages for the stack non-executable. If you really want an executable // stack, you can pass -z execstack, but that's not recommended for // security reasons. unsigned Perm; if (Config->ZExecstack) Perm = PF_R | PF_W | PF_X; else Perm = PF_R | PF_W; AddHdr(PT_GNU_STACK, Perm)->p_memsz = Config->ZStackSize; // PT_OPENBSD_WXNEEDED is a OpenBSD-specific header to mark the executable // is expected to perform W^X violations, such as calling mprotect(2) or // mmap(2) with PROT_WRITE | PROT_EXEC, which is prohibited by default on // OpenBSD. if (Config->ZWxneeded) AddHdr(PT_OPENBSD_WXNEEDED, PF_X); // Create one PT_NOTE per a group of contiguous .note sections. PhdrEntry *Note = nullptr; for (OutputSection *Sec : OutputSections) { if (Sec->Type == SHT_NOTE) { if (!Note || Script->hasLMA(Sec->Name)) Note = AddHdr(PT_NOTE, PF_R); Note->add(Sec); } else { Note = nullptr; } } return Ret; } template void Writer::addPtArmExid(std::vector &Phdrs) { if (Config->EMachine != EM_ARM) return; auto I = std::find_if( OutputSections.begin(), OutputSections.end(), [](OutputSection *Sec) { return Sec->Type == SHT_ARM_EXIDX; }); if (I == OutputSections.end()) return; // PT_ARM_EXIDX is the ARM EHABI equivalent of PT_GNU_EH_FRAME PhdrEntry ARMExidx(PT_ARM_EXIDX, PF_R); ARMExidx.add(*I); Phdrs.push_back(ARMExidx); } // The first section of each PT_LOAD, the first section in PT_GNU_RELRO and the // first section after PT_GNU_RELRO have to be page aligned so that the dynamic // linker can set the permissions. template void Writer::fixSectionAlignments() { for (const PhdrEntry &P : Phdrs) if (P.p_type == PT_LOAD && P.First) P.First->PageAlign = true; for (const PhdrEntry &P : Phdrs) { if (P.p_type != PT_GNU_RELRO) continue; if (P.First) P.First->PageAlign = true; // Find the first section after PT_GNU_RELRO. If it is in a PT_LOAD we // have to align it to a page. auto End = OutputSections.end(); auto I = std::find(OutputSections.begin(), End, P.Last); if (I == End || (I + 1) == End) continue; OutputSection *Sec = *(I + 1); if (needsPtLoad(Sec)) Sec->PageAlign = true; } } bool elf::allocateHeaders(std::vector &Phdrs, ArrayRef OutputSections, uint64_t Min) { auto FirstPTLoad = std::find_if(Phdrs.begin(), Phdrs.end(), [](const PhdrEntry &E) { return E.p_type == PT_LOAD; }); if (FirstPTLoad == Phdrs.end()) return false; uint64_t HeaderSize = getHeaderSize(); if (HeaderSize > Min) { auto PhdrI = std::find_if(Phdrs.begin(), Phdrs.end(), [](const PhdrEntry &E) { return E.p_type == PT_PHDR; }); if (PhdrI != Phdrs.end()) Phdrs.erase(PhdrI); return false; } Min = alignDown(Min - HeaderSize, Config->MaxPageSize); if (!Script->Opt.HasSections) Config->ImageBase = Min = std::min(Min, Config->ImageBase); Out::ElfHeader->Addr = Min; Out::ProgramHeaders->Addr = Min + Out::ElfHeader->Size; if (Script->hasPhdrsCommands()) return true; if (FirstPTLoad->First) for (OutputSection *Sec : OutputSections) if (Sec->FirstInPtLoad == FirstPTLoad->First) Sec->FirstInPtLoad = Out::ElfHeader; FirstPTLoad->First = Out::ElfHeader; if (!FirstPTLoad->Last) FirstPTLoad->Last = Out::ProgramHeaders; return true; } // We should set file offsets and VAs for elf header and program headers // sections. These are special, we do not include them into output sections // list, but have them to simplify the code. template void Writer::fixHeaders() { Out::ProgramHeaders->Size = sizeof(Elf_Phdr) * Phdrs.size(); // If the script has SECTIONS, assignAddresses will compute the values. if (Script->Opt.HasSections) return; // When -T
option is specified, lower the base to make room for those // sections. uint64_t Min = -1; if (!Config->SectionStartMap.empty()) for (const auto &P : Config->SectionStartMap) Min = std::min(Min, P.second); AllocateHeader = allocateHeaders(Phdrs, OutputSections, Min); } // Adjusts the file alignment for a given output section and returns // its new file offset. The file offset must be the same with its // virtual address (modulo the page size) so that the loader can load // executables without any address adjustment. static uint64_t getFileAlignment(uint64_t Off, OutputSection *Sec) { OutputSection *First = Sec->FirstInPtLoad; // If the section is not in a PT_LOAD, we just have to align it. if (!First) return alignTo(Off, Sec->Alignment); // The first section in a PT_LOAD has to have congruent offset and address // module the page size. if (Sec == First) return alignTo(Off, Config->MaxPageSize, Sec->Addr); // If two sections share the same PT_LOAD the file offset is calculated // using this formula: Off2 = Off1 + (VA2 - VA1). return First->Offset + Sec->Addr - First->Addr; } static uint64_t setOffset(OutputSection *Sec, uint64_t Off) { if (Sec->Type == SHT_NOBITS) { Sec->Offset = Off; return Off; } Off = getFileAlignment(Off, Sec); Sec->Offset = Off; return Off + Sec->Size; } template void Writer::assignFileOffsetsBinary() { uint64_t Off = 0; for (OutputSection *Sec : OutputSections) if (Sec->Flags & SHF_ALLOC) Off = setOffset(Sec, Off); FileSize = alignTo(Off, Config->Wordsize); } // Assign file offsets to output sections. template void Writer::assignFileOffsets() { uint64_t Off = 0; Off = setOffset(Out::ElfHeader, Off); Off = setOffset(Out::ProgramHeaders, Off); for (OutputSection *Sec : OutputSections) Off = setOffset(Sec, Off); SectionHeaderOff = alignTo(Off, Config->Wordsize); FileSize = SectionHeaderOff + (OutputSections.size() + 1) * sizeof(Elf_Shdr); } // Finalize the program headers. We call this function after we assign // file offsets and VAs to all sections. template void Writer::setPhdrs() { for (PhdrEntry &P : Phdrs) { OutputSection *First = P.First; OutputSection *Last = P.Last; if (First) { P.p_filesz = Last->Offset - First->Offset; if (Last->Type != SHT_NOBITS) P.p_filesz += Last->Size; P.p_memsz = Last->Addr + Last->Size - First->Addr; P.p_offset = First->Offset; P.p_vaddr = First->Addr; if (!P.HasLMA) P.p_paddr = First->getLMA(); } if (P.p_type == PT_LOAD) P.p_align = Config->MaxPageSize; else if (P.p_type == PT_GNU_RELRO) { P.p_align = 1; // The glibc dynamic loader rounds the size down, so we need to round up // to protect the last page. This is a no-op on FreeBSD which always // rounds up. P.p_memsz = alignTo(P.p_memsz, Target->PageSize); } // The TLS pointer goes after PT_TLS. At least glibc will align it, // so round up the size to make sure the offsets are correct. if (P.p_type == PT_TLS) { Out::TlsPhdr = &P; if (P.p_memsz) P.p_memsz = alignTo(P.p_memsz, P.p_align); } } } // The entry point address is chosen in the following ways. // // 1. the '-e' entry command-line option; // 2. the ENTRY(symbol) command in a linker control script; // 3. the value of the symbol start, if present; // 4. the address of the first byte of the .text section, if present; // 5. the address 0. template uint64_t Writer::getEntryAddr() { // Case 1, 2 or 3. As a special case, if the symbol is actually // a number, we'll use that number as an address. if (SymbolBody *B = Symtab::X->find(Config->Entry)) return B->getVA(); uint64_t Addr; if (!Config->Entry.getAsInteger(0, Addr)) return Addr; // Case 4 if (OutputSection *Sec = findSection(".text")) { if (Config->WarnMissingEntry) warn("cannot find entry symbol " + Config->Entry + "; defaulting to 0x" + utohexstr(Sec->Addr)); return Sec->Addr; } // Case 5 if (Config->WarnMissingEntry) warn("cannot find entry symbol " + Config->Entry + "; not setting start address"); return 0; } static uint16_t getELFType() { if (Config->Pic) return ET_DYN; if (Config->Relocatable) return ET_REL; return ET_EXEC; } // This function is called after we have assigned address and size // to each section. This function fixes some predefined // symbol values that depend on section address and size. template void Writer::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. PhdrEntry *Last = nullptr; PhdrEntry *LastRO = nullptr; PhdrEntry *LastRW = nullptr; for (PhdrEntry &P : Phdrs) { if (P.p_type != PT_LOAD) continue; Last = &P; if (P.p_flags & PF_W) LastRW = &P; 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); if (ElfSym::Bss) ElfSym::Bss->Section = findSection(".bss"); // Setup MIPS _gp_disp/__gnu_local_gp symbols which should // be equal to the _gp symbol's value. if (Config->EMachine == EM_MIPS) { if (!ElfSym::MipsGp->Value) { // Find GP-relative section with the lowest address // and use this address to calculate default _gp value. uint64_t Gp = -1; for (const OutputSection *OS : OutputSections) if ((OS->Flags & SHF_MIPS_GPREL) && OS->Addr < Gp) Gp = OS->Addr; if (Gp != (uint64_t)-1) ElfSym::MipsGp->Value = Gp + 0x7ff0; } } } template void Writer::writeHeader() { uint8_t *Buf = Buffer->getBufferStart(); memcpy(Buf, "\177ELF", 4); // Write the ELF header. auto *EHdr = reinterpret_cast(Buf); EHdr->e_ident[EI_CLASS] = Config->Is64 ? ELFCLASS64 : ELFCLASS32; EHdr->e_ident[EI_DATA] = Config->IsLE ? ELFDATA2LSB : ELFDATA2MSB; EHdr->e_ident[EI_VERSION] = EV_CURRENT; EHdr->e_ident[EI_OSABI] = Config->OSABI; EHdr->e_type = getELFType(); EHdr->e_machine = Config->EMachine; EHdr->e_version = EV_CURRENT; EHdr->e_entry = getEntryAddr(); EHdr->e_shoff = SectionHeaderOff; EHdr->e_ehsize = sizeof(Elf_Ehdr); EHdr->e_phnum = Phdrs.size(); EHdr->e_shentsize = sizeof(Elf_Shdr); EHdr->e_shnum = OutputSections.size() + 1; EHdr->e_shstrndx = In::ShStrTab->OutSec->SectionIndex; if (Config->EMachine == EM_ARM) // We don't currently use any features incompatible with EF_ARM_EABI_VER5, // but we don't have any firm guarantees of conformance. Linux AArch64 // kernels (as of 2016) require an EABI version to be set. EHdr->e_flags = EF_ARM_EABI_VER5; else if (Config->EMachine == EM_MIPS) EHdr->e_flags = getMipsEFlags(); if (!Config->Relocatable) { EHdr->e_phoff = sizeof(Elf_Ehdr); EHdr->e_phentsize = sizeof(Elf_Phdr); } // Write the program header table. auto *HBuf = reinterpret_cast(Buf + EHdr->e_phoff); for (PhdrEntry &P : Phdrs) { HBuf->p_type = P.p_type; HBuf->p_flags = P.p_flags; HBuf->p_offset = P.p_offset; HBuf->p_vaddr = P.p_vaddr; HBuf->p_paddr = P.p_paddr; HBuf->p_filesz = P.p_filesz; HBuf->p_memsz = P.p_memsz; HBuf->p_align = P.p_align; ++HBuf; } // Write the section header table. Note that the first table entry is null. auto *SHdrs = reinterpret_cast(Buf + EHdr->e_shoff); for (OutputSection *Sec : OutputSections) Sec->writeHeaderTo(++SHdrs); } // Open a result file. template void Writer::openFile() { if (!Config->Is64 && FileSize > UINT32_MAX) { error("output file too large: " + Twine(FileSize) + " bytes"); return; } unlinkAsync(Config->OutputFile); ErrorOr> BufferOrErr = FileOutputBuffer::create(Config->OutputFile, FileSize, FileOutputBuffer::F_executable); if (auto EC = BufferOrErr.getError()) error("failed to open " + Config->OutputFile + ": " + EC.message()); else Buffer = std::move(*BufferOrErr); } template void Writer::writeSectionsBinary() { uint8_t *Buf = Buffer->getBufferStart(); for (OutputSection *Sec : OutputSections) if (Sec->Flags & SHF_ALLOC) Sec->writeTo(Buf + Sec->Offset); } // Write section contents to a mmap'ed file. template void Writer::writeSections() { uint8_t *Buf = Buffer->getBufferStart(); // PPC64 needs to process relocations in the .opd section // before processing relocations in code-containing sections. Out::Opd = findSection(".opd"); if (Out::Opd) { Out::OpdBuf = Buf + Out::Opd->Offset; Out::Opd->template writeTo(Buf + Out::Opd->Offset); } OutputSection *EhFrameHdr = In::EhFrameHdr ? In::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) if (Sec->Type == SHT_REL || Sec->Type == SHT_RELA) Sec->writeTo(Buf + Sec->Offset); for (OutputSection *Sec : OutputSections) if (Sec != Out::Opd && Sec != EhFrameHdr && Sec->Type != SHT_REL && Sec->Type != SHT_RELA) Sec->writeTo(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(Buf + EhFrameHdr->Offset); } template void Writer::writeBuildId() { if (!In::BuildId || !In::BuildId->OutSec) return; // Compute a hash of all sections of the output file. uint8_t *Start = Buffer->getBufferStart(); uint8_t *End = Start + FileSize; In::BuildId->writeBuildId({Start, End}); } template void elf::writeResult(); template void elf::writeResult(); template void elf::writeResult(); template void elf::writeResult(); template bool elf::isRelroSection(const OutputSection *); template bool elf::isRelroSection(const OutputSection *); template bool elf::isRelroSection(const OutputSection *); template bool elf::isRelroSection(const OutputSection *); Index: vendor/lld/dist/test/ELF/Inputs/weak-and-strong-undef.s =================================================================== --- vendor/lld/dist/test/ELF/Inputs/weak-and-strong-undef.s (nonexistent) +++ vendor/lld/dist/test/ELF/Inputs/weak-and-strong-undef.s (revision 317767) @@ -0,0 +1 @@ + .weak foo Property changes on: vendor/lld/dist/test/ELF/Inputs/weak-and-strong-undef.s ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/lld/dist/test/ELF/gdb-index-ranges.s =================================================================== --- vendor/lld/dist/test/ELF/gdb-index-ranges.s (nonexistent) +++ vendor/lld/dist/test/ELF/gdb-index-ranges.s (revision 317767) @@ -0,0 +1,66 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o +# RUN: ld.lld --gdb-index -e main %t.o -o %t +# RUN: llvm-dwarfdump -debug-dump=gdb_index %t | FileCheck %s + +# CHECK: .gnu_index contents: +# CHECK: Address area offset = 0x28, has 2 entries: +# CHECK-NEXT: Low/High address = [0x201000, 0x201001) (Size: 0x1), CU id = 0 +# CHECK-NEXT: Low/High address = [0x201001, 0x201003) (Size: 0x2), CU id = 0 + +.section .text.foo1,"ax",@progbits +.Lfunc_begin0: + nop +.Lfunc_end0: + +.section .text.foo2,"ax",@progbits +.Lfunc_begin1: + nop + nop +.Lfunc_end1: + +.section .debug_abbrev,"",@progbits +.byte 1 # Abbreviation Code +.byte 17 # DW_TAG_compile_unit +.byte 0 # DW_CHILDREN_no +.byte 37 # DW_AT_producer +.byte 14 # DW_FORM_strp +.byte 19 # DW_AT_language +.byte 5 # DW_FORM_data2 +.byte 3 # DW_AT_name +.byte 14 # DW_FORM_strp +.byte 16 # DW_AT_stmt_list +.byte 23 # DW_FORM_sec_offset +.byte 27 # DW_AT_comp_dir +.byte 14 # DW_FORM_strp +.byte 17 # DW_AT_low_pc +.byte 1 # DW_FORM_addr +.byte 85 # DW_AT_ranges +.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 38 # 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:0x1f DW_TAG_compile_unit +.long 0 # DW_AT_producer +.short 4 # DW_AT_language +.long 0 # DW_AT_name +.long 0 # DW_AT_stmt_list +.long 0 # DW_AT_comp_dir +.quad 0 # DW_AT_low_pc +.long .Ldebug_ranges0 # DW_AT_ranges + +.section .debug_ranges,"",@progbits +.Ldebug_ranges0: +.quad .Lfunc_begin0 +.quad .Lfunc_end0 +.quad .Lfunc_begin1 +.quad .Lfunc_end1 +.quad 0 +.quad 0 Property changes on: vendor/lld/dist/test/ELF/gdb-index-ranges.s ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/lld/dist/test/ELF/sectionstart-noallochdr.s =================================================================== --- vendor/lld/dist/test/ELF/sectionstart-noallochdr.s (nonexistent) +++ vendor/lld/dist/test/ELF/sectionstart-noallochdr.s (revision 317767) @@ -0,0 +1,23 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +# RUN: ld.lld %t.o --section-start .data=0x20 \ +# RUN: --section-start .bss=0x30 --section-start .text=0x10 -o %t1 +# RUN: llvm-objdump -section-headers %t1 | FileCheck %s + +# CHECK: Sections: +# CHECK-NEXT: Idx Name Size Address Type +# CHECK-NEXT: 0 00000000 0000000000000000 +# CHECK-NEXT: 1 .text 00000001 0000000000000010 TEXT DATA +# CHECK-NEXT: 2 .data 00000004 0000000000000020 DATA +# CHECK-NEXT: 3 .bss 00000004 0000000000000030 BSS + +.text +.globl _start +_start: + nop + +.data +.long 0 + +.bss +.zero 4 Property changes on: vendor/lld/dist/test/ELF/sectionstart-noallochdr.s ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/lld/dist/test/ELF/weak-and-strong-undef.s =================================================================== --- vendor/lld/dist/test/ELF/weak-and-strong-undef.s (nonexistent) +++ vendor/lld/dist/test/ELF/weak-and-strong-undef.s (revision 317767) @@ -0,0 +1,12 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t1.o +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/weak-and-strong-undef.s -o %t2.o +# RUN: not ld.lld %t1.o %t2.o -o %t 2>&1 | FileCheck %s +# RUN: not ld.lld %t2.o %t1.o -o %t 2>&1 | FileCheck %s + +# CHECK: error: undefined symbol: foo + +.long foo +.globl _start +_start: +ret Property changes on: vendor/lld/dist/test/ELF/weak-and-strong-undef.s ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property