diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2017-12-24 01:00:50 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2017-12-24 01:00:50 +0000 |
commit | 0d9ba4fe26725cacc7253fc3c72c4574f26bc099 (patch) | |
tree | 90c426d54188ca226b29aaf8a308bba364a73d1a | |
parent | eb1ff93d02b5f17b6b409e83c6d9be585f4a04b3 (diff) |
Vendor import of lld trunk r321414:vendor/lld/lld-trunk-r321414
Notes
Notes:
svn path=/vendor/lld/dist/; revision=327130
svn path=/vendor/lld/lld-trunk-r321414/; revision=327131; tag=vendor/lld/lld-trunk-r321414
69 files changed, 1000 insertions, 603 deletions
diff --git a/COFF/DLL.cpp b/COFF/DLL.cpp index 847d15d8594a..195839139670 100644 --- a/COFF/DLL.cpp +++ b/COFF/DLL.cpp @@ -362,12 +362,12 @@ public: size_t getSize() const override { return Size * 4; } void writeTo(uint8_t *Buf) const override { - uint32_t Bit = 0; - // Pointer to thumb code must have the LSB set, so adjust it. - if (Config->Machine == ARMNT) - Bit = 1; - for (Export &E : Config->Exports) { + for (const Export &E : Config->Exports) { uint8_t *P = Buf + OutputSectionOff + E.Ordinal * 4; + uint32_t Bit = 0; + // Pointer to thumb code must have the LSB set, so adjust it. + if (Config->Machine == ARMNT && !E.Data) + Bit = 1; if (E.ForwardChunk) { write32le(P, E.ForwardChunk->getRVA() | Bit); } else { diff --git a/ELF/AArch64ErrataFix.cpp b/ELF/AArch64ErrataFix.cpp index 6cc68cc08e10..9c0d536dea71 100644 --- a/ELF/AArch64ErrataFix.cpp +++ b/ELF/AArch64ErrataFix.cpp @@ -400,8 +400,8 @@ lld::elf::Patch843419Section::Patch843419Section(InputSection *P, uint64_t Off) this->Parent = P->getParent(); PatchSym = addSyntheticLocal( Saver.save("__CortexA53843419_" + utohexstr(getLDSTAddr())), STT_FUNC, 0, - getSize(), this); - addSyntheticLocal(Saver.save("$x"), STT_NOTYPE, 0, 0, this); + getSize(), *this); + addSyntheticLocal(Saver.save("$x"), STT_NOTYPE, 0, 0, *this); } uint64_t lld::elf::Patch843419Section::getLDSTAddr() const { diff --git a/ELF/Arch/ARM.cpp b/ELF/Arch/ARM.cpp index 94a98e7679bd..b9f551e4b3be 100644 --- a/ELF/Arch/ARM.cpp +++ b/ELF/Arch/ARM.cpp @@ -37,8 +37,8 @@ public: 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; + void addPltSymbols(InputSection &IS, uint64_t Off) const override; + void addPltHeaderSymbols(InputSection &ISD) const override; bool needsThunk(RelExpr Expr, RelType Type, const InputFile *File, uint64_t BranchAddr, const Symbol &S) const override; bool inBranchRange(RelType Type, uint64_t Src, uint64_t Dst) const override; @@ -184,7 +184,7 @@ void ARM::writeIgotPlt(uint8_t *Buf, const Symbol &S) const { write32le(Buf, S.getVA()); } -// Long form PLT Heade that does not have any restrictions on the displacement +// Long form PLT Header that does not have any restrictions on the displacement // of the .plt from the .plt.got. static void writePltHeaderLong(uint8_t *Buf) { const uint8_t PltData[] = { @@ -232,8 +232,7 @@ void ARM::writePltHeader(uint8_t *Buf) const { write32le(Buf + 28, TrapInstr); } -void ARM::addPltHeaderSymbols(InputSectionBase *ISD) const { - auto *IS = cast<InputSection>(ISD); +void ARM::addPltHeaderSymbols(InputSection &IS) const { addSyntheticLocal("$a", STT_NOTYPE, 0, 0, IS); addSyntheticLocal("$d", STT_NOTYPE, 16, 0, IS); } @@ -282,8 +281,7 @@ void ARM::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, write32le(Buf + 12, TrapInstr); // Pad to 16-byte boundary } -void ARM::addPltSymbols(InputSectionBase *ISD, uint64_t Off) const { - auto *IS = cast<InputSection>(ISD); +void ARM::addPltSymbols(InputSection &IS, uint64_t Off) const { addSyntheticLocal("$a", STT_NOTYPE, Off, 0, IS); addSyntheticLocal("$d", STT_NOTYPE, Off + 12, 0, IS); } diff --git a/ELF/Driver.cpp b/ELF/Driver.cpp index 2b6925031b07..cc76fea2ad5e 100644 --- a/ELF/Driver.cpp +++ b/ELF/Driver.cpp @@ -1056,7 +1056,7 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) { // We need to create some reserved symbols such as _end. Create them. if (!Config->Relocatable) - addReservedSymbols<ELFT>(); + addReservedSymbols(); // Apply version scripts. Symtab->scanVersionScript(); @@ -1111,7 +1111,7 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) { // before decompressAndMergeSections because the .comment section is a // mergeable section. if (!Config->Relocatable) - InputSections.push_back(createCommentSection<ELFT>()); + InputSections.push_back(createCommentSection()); // Do size optimizations: garbage collection, merging of SHF_MERGE sections // and identical code folding. diff --git a/ELF/InputFiles.cpp b/ELF/InputFiles.cpp index 1f68340c9428..f514870ca84a 100644 --- a/ELF/InputFiles.cpp +++ b/ELF/InputFiles.cpp @@ -32,6 +32,7 @@ using namespace llvm; using namespace llvm::ELF; using namespace llvm::object; +using namespace llvm::sys; using namespace llvm::sys::fs; using namespace lld; @@ -69,6 +70,50 @@ Optional<MemoryBufferRef> elf::readFile(StringRef Path) { return MBRef; } +// Concatenates arguments to construct a string representing an error location. +static std::string createFileLineMsg(StringRef Path, unsigned Line) { + std::string Filename = path::filename(Path); + std::string Lineno = ":" + std::to_string(Line); + if (Filename == Path) + return Filename + Lineno; + return Filename + Lineno + " (" + Path.str() + Lineno + ")"; +} + +template <class ELFT> +static std::string getSrcMsgAux(ObjFile<ELFT> &File, const Symbol &Sym, + InputSectionBase &Sec, uint64_t Offset) { + // In DWARF, functions and variables are stored to different places. + // First, lookup a function for a given offset. + if (Optional<DILineInfo> Info = File.getDILineInfo(&Sec, Offset)) + return createFileLineMsg(Info->FileName, Info->Line); + + // If it failed, lookup again as a variable. + if (Optional<std::pair<std::string, unsigned>> FileLine = + File.getVariableLoc(Sym.getName())) + return createFileLineMsg(FileLine->first, FileLine->second); + + // File.SourceFile contains STT_FILE symbol, and that is a last resort. + return File.SourceFile; +} + +std::string InputFile::getSrcMsg(const Symbol &Sym, InputSectionBase &Sec, + uint64_t Offset) { + if (kind() != ObjKind) + return ""; + switch (Config->EKind) { + default: + llvm_unreachable("Invalid kind"); + case ELF32LEKind: + return getSrcMsgAux(cast<ObjFile<ELF32LE>>(*this), Sym, Sec, Offset); + case ELF32BEKind: + return getSrcMsgAux(cast<ObjFile<ELF32BE>>(*this), Sym, Sec, Offset); + case ELF64LEKind: + return getSrcMsgAux(cast<ObjFile<ELF64LE>>(*this), Sym, Sec, Offset); + case ELF64BEKind: + return getSrcMsgAux(cast<ObjFile<ELF64BE>>(*this), Sym, Sec, Offset); + } +} + template <class ELFT> void ObjFile<ELFT>::initializeDwarf() { DWARFContext Dwarf(make_unique<LLDDwarfObj<ELFT>>(this)); const DWARFObject &Obj = Dwarf.getDWARFObj(); @@ -384,8 +429,8 @@ void ObjFile<ELFT>::initializeSections( // 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)); + fatal(toString(this) + + ": invalid sh_link index: " + Twine(Sec.sh_link)); this->Sections[Sec.sh_link]->DependentSections.push_back( cast<InputSection>(this->Sections[I])); } @@ -454,11 +499,9 @@ InputSectionBase *ObjFile<ELFT>::getRelocTarget(const Elf_Shdr &Sec) { // Create a regular InputSection class that has the same contents // as a given section. -InputSectionBase *toRegularSection(MergeInputSection *Sec) { - auto *Ret = make<InputSection>(Sec->Flags, Sec->Type, Sec->Alignment, - Sec->Data, Sec->Name); - Ret->File = Sec->File; - return Ret; +static InputSection *toRegularSection(MergeInputSection *Sec) { + return make<InputSection>(Sec->File, Sec->Flags, Sec->Type, Sec->Alignment, + Sec->Data, Sec->Name); } template <class ELFT> @@ -471,13 +514,13 @@ InputSectionBase *ObjFile<ELFT>::createInputSection(const Elf_Shdr &Sec) { break; ARMAttributeParser Attributes; ArrayRef<uint8_t> Contents = check(this->getObj().getSectionContents(&Sec)); - Attributes.Parse(Contents, /*isLittle*/Config->EKind == ELF32LEKind); + Attributes.Parse(Contents, /*isLittle*/ Config->EKind == ELF32LEKind); updateSupportedARMFeatures(Attributes); // FIXME: 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 (InX::ARMAttributes == nullptr) { - InX::ARMAttributes = make<InputSection>(this, &Sec, Name); + InX::ARMAttributes = make<InputSection>(*this, Sec, Name); return InX::ARMAttributes; } return &InputSection::Discarded; @@ -496,7 +539,7 @@ InputSectionBase *ObjFile<ELFT>::createInputSection(const Elf_Shdr &Sec) { // If -r is given, we do not interpret or apply relocation // but just copy relocation sections to output. if (Config->Relocatable) - return make<InputSection>(this, &Sec, Name); + return make<InputSection>(*this, Sec, Name); if (Target->FirstRelocation) fatal(toString(this) + @@ -534,7 +577,7 @@ InputSectionBase *ObjFile<ELFT>::createInputSection(const Elf_Shdr &Sec) { // 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<InputSection>(this, &Sec, Name); + InputSection *RelocSec = make<InputSection>(*this, Sec, Name); // We will not emit relocation section if target was discarded. Target->DependentSections.push_back(RelocSec); return RelocSec; @@ -581,11 +624,11 @@ InputSectionBase *ObjFile<ELFT>::createInputSection(const Elf_Shdr &Sec) { // .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<EhInputSection>(this, &Sec, Name); + return make<EhInputSection>(*this, Sec, Name); if (shouldMerge(Sec)) - return make<MergeInputSection>(this, &Sec, Name); - return make<InputSection>(this, &Sec, Name); + return make<MergeInputSection>(*this, Sec, Name); + return make<InputSection>(*this, Sec, Name); } template <class ELFT> @@ -636,7 +679,7 @@ template <class ELFT> Symbol *ObjFile<ELFT>::createSymbol(const Elf_Sym *Sym) { if (Value == 0 || Value >= UINT32_MAX) fatal(toString(this) + ": common symbol '" + Name + "' has invalid alignment: " + Twine(Value)); - return Symtab->addCommon(Name, Size, Value, Binding, StOther, Type, this); + return Symtab->addCommon(Name, Size, Value, Binding, StOther, Type, *this); } switch (Binding) { @@ -648,8 +691,8 @@ template <class ELFT> Symbol *ObjFile<ELFT>::createSymbol(const Elf_Sym *Sym) { if (Sec == &InputSection::Discarded) return Symtab->addUndefined<ELFT>(Name, Binding, StOther, Type, /*CanOmitFromDynSym=*/false, this); - return Symtab->addRegular<ELFT>(Name, StOther, Type, Value, Size, Binding, - Sec, this); + return Symtab->addRegular(Name, StOther, Type, Value, Size, Binding, Sec, + this); } } @@ -660,7 +703,7 @@ ArchiveFile::ArchiveFile(std::unique_ptr<Archive> &&File) template <class ELFT> void ArchiveFile::parse() { Symbols.reserve(File->getNumberOfSymbols()); for (const Archive::Symbol &Sym : File->symbols()) - Symbols.push_back(Symtab->addLazyArchive<ELFT>(Sym.getName(), this, Sym)); + Symbols.push_back(Symtab->addLazyArchive<ELFT>(Sym.getName(), *this, Sym)); } // Returns a buffer pointing to a member file containing a given symbol. @@ -841,14 +884,14 @@ template <class ELFT> void SharedFile<ELFT>::parseRest() { error(toString(this) + ": alignment too large: " + Name); if (!Hidden) - Symtab->addShared(Name, this, Sym, Alignment, VersymIndex); + Symtab->addShared(Name, *this, Sym, Alignment, VersymIndex); // Also add the symbol with the versioned name to handle undefined symbols // with explicit versions. if (Ver) { StringRef VerName = this->StringTable.data() + Ver->getAux()->vda_name; Name = Saver.save(Name + "@" + VerName); - Symtab->addShared(Name, this, Sym, Alignment, VersymIndex); + Symtab->addShared(Name, *this, Sym, Alignment, VersymIndex); } } } @@ -925,7 +968,7 @@ static uint8_t mapVisibility(GlobalValue::VisibilityTypes GvVisibility) { template <class ELFT> static Symbol *createBitcodeSymbol(const std::vector<bool> &KeptComdats, const lto::InputFile::Symbol &ObjSym, - BitcodeFile *F) { + BitcodeFile &F) { StringRef NameRef = Saver.save(ObjSym.getName()); uint32_t Binding = ObjSym.isWeak() ? STB_WEAK : STB_GLOBAL; @@ -936,11 +979,11 @@ static Symbol *createBitcodeSymbol(const std::vector<bool> &KeptComdats, int C = ObjSym.getComdatIndex(); if (C != -1 && !KeptComdats[C]) return Symtab->addUndefined<ELFT>(NameRef, Binding, Visibility, Type, - CanOmitFromDynSym, F); + CanOmitFromDynSym, &F); if (ObjSym.isUndefined()) return Symtab->addUndefined<ELFT>(NameRef, Binding, Visibility, Type, - CanOmitFromDynSym, F); + CanOmitFromDynSym, &F); if (ObjSym.isCommon()) return Symtab->addCommon(NameRef, ObjSym.getCommonSize(), @@ -958,7 +1001,7 @@ void BitcodeFile::parse(DenseSet<CachedHashStringRef> &ComdatGroups) { KeptComdats.push_back(ComdatGroups.insert(CachedHashStringRef(S)).second); for (const lto::InputFile::Symbol &ObjSym : Obj->symbols()) - Symbols.push_back(createBitcodeSymbol<ELFT>(KeptComdats, ObjSym, this)); + Symbols.push_back(createBitcodeSymbol<ELFT>(KeptComdats, ObjSym, *this)); } static ELFKind getELFKind(MemoryBufferRef MB) { @@ -981,10 +1024,10 @@ static ELFKind getELFKind(MemoryBufferRef MB) { return (Endian == ELFDATA2LSB) ? ELF64LEKind : ELF64BEKind; } -template <class ELFT> void BinaryFile::parse() { +void BinaryFile::parse() { ArrayRef<uint8_t> Data = toArrayRef(MB.getBuffer()); - auto *Section = - make<InputSection>(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, 8, Data, ".data"); + auto *Section = make<InputSection>(nullptr, 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 @@ -996,12 +1039,12 @@ template <class ELFT> void BinaryFile::parse() { if (!isAlnum(S[I])) S[I] = '_'; - Symtab->addRegular<ELFT>(Saver.save(S + "_start"), STV_DEFAULT, STT_OBJECT, - 0, 0, STB_GLOBAL, Section, nullptr); - Symtab->addRegular<ELFT>(Saver.save(S + "_end"), STV_DEFAULT, STT_OBJECT, - Data.size(), 0, STB_GLOBAL, Section, nullptr); - Symtab->addRegular<ELFT>(Saver.save(S + "_size"), STV_DEFAULT, STT_OBJECT, - Data.size(), 0, STB_GLOBAL, nullptr, nullptr); + Symtab->addRegular(Saver.save(S + "_start"), STV_DEFAULT, STT_OBJECT, 0, 0, + STB_GLOBAL, Section, nullptr); + Symtab->addRegular(Saver.save(S + "_end"), STV_DEFAULT, STT_OBJECT, + Data.size(), 0, STB_GLOBAL, Section, nullptr); + Symtab->addRegular(Saver.save(S + "_size"), STV_DEFAULT, STT_OBJECT, + Data.size(), 0, STB_GLOBAL, nullptr, nullptr); } static bool isBitcode(MemoryBufferRef MB) { @@ -1145,8 +1188,3 @@ template class elf::SharedFile<ELF32LE>; template class elf::SharedFile<ELF32BE>; template class elf::SharedFile<ELF64LE>; template class elf::SharedFile<ELF64BE>; - -template void BinaryFile::parse<ELF32LE>(); -template void BinaryFile::parse<ELF32BE>(); -template void BinaryFile::parse<ELF64LE>(); -template void BinaryFile::parse<ELF64BE>(); diff --git a/ELF/InputFiles.h b/ELF/InputFiles.h index 427f2fdea53e..dda1de81570c 100644 --- a/ELF/InputFiles.h +++ b/ELF/InputFiles.h @@ -72,6 +72,11 @@ public: Kind kind() const { return FileKind; } + bool isElf() const { + Kind K = kind(); + return K == ObjKind || K == SharedKind; + } + StringRef getName() const { return MB.getBufferIdentifier(); } MemoryBufferRef MB; @@ -104,6 +109,9 @@ public: // Cache for toString(). Only toString() should use this member. mutable std::string ToStringCache; + std::string getSrcMsg(const Symbol &Sym, InputSectionBase &Sec, + uint64_t Offset); + protected: InputFile(Kind K, MemoryBufferRef M); std::vector<InputSectionBase *> Sections; @@ -121,10 +129,7 @@ public: typedef typename ELFT::SymRange Elf_Sym_Range; ELFFileBase(Kind K, MemoryBufferRef M); - static bool classof(const InputFile *F) { - Kind K = F->kind(); - return K == ObjKind || K == SharedKind; - } + static bool classof(const InputFile *F) { return F->isElf(); } llvm::object::ELFFile<ELFT> getObj() const { return check(llvm::object::ELFFile<ELFT>::create(MB.getBuffer())); @@ -325,7 +330,7 @@ class BinaryFile : public InputFile { public: explicit BinaryFile(MemoryBufferRef M) : InputFile(BinaryKind, M) {} static bool classof(const InputFile *F) { return F->kind() == BinaryKind; } - template <class ELFT> void parse(); + void parse(); }; InputFile *createObjectFile(MemoryBufferRef MB, StringRef ArchiveName = "", diff --git a/ELF/InputSection.cpp b/ELF/InputSection.cpp index 02cad56ca508..93baefadce6e 100644 --- a/ELF/InputSection.cpp +++ b/ELF/InputSection.cpp @@ -24,7 +24,6 @@ #include "llvm/Support/Compiler.h" #include "llvm/Support/Compression.h" #include "llvm/Support/Endian.h" -#include "llvm/Support/Path.h" #include "llvm/Support/Threading.h" #include "llvm/Support/xxhash.h" #include <mutex> @@ -73,11 +72,11 @@ DenseMap<SectionBase *, int> elf::buildSectionOrder() { } template <class ELFT> -static ArrayRef<uint8_t> getSectionContents(ObjFile<ELFT> *File, - const typename ELFT::Shdr *Hdr) { - if (!File || Hdr->sh_type == SHT_NOBITS) - return makeArrayRef<uint8_t>(nullptr, Hdr->sh_size); - return check(File->getObj().getSectionContents(Hdr)); +static ArrayRef<uint8_t> getSectionContents(ObjFile<ELFT> &File, + const typename ELFT::Shdr &Hdr) { + if (Hdr.sh_type == SHT_NOBITS) + return makeArrayRef<uint8_t>(nullptr, Hdr.sh_size); + return check(File.getObj().getSectionContents(&Hdr)); } InputSectionBase::InputSectionBase(InputFile *File, uint64_t Flags, @@ -88,6 +87,12 @@ InputSectionBase::InputSectionBase(InputFile *File, uint64_t Flags, : SectionBase(SectionKind, Name, Flags, Entsize, Alignment, Type, Info, Link), File(File), Data(Data) { + // In order to reduce memory allocation, we assume that mergeable + // sections are smaller than 4 GiB, which is not an unreasonable + // assumption as of 2017. + if (SectionKind == SectionBase::Merge && Data.size() > UINT32_MAX) + error(toString(this) + ": section too large"); + NumRelocations = 0; AreRelocsRela = false; @@ -128,18 +133,18 @@ static uint64_t getType(uint64_t Type, StringRef Name) { } template <class ELFT> -InputSectionBase::InputSectionBase(ObjFile<ELFT> *File, - const typename ELFT::Shdr *Hdr, +InputSectionBase::InputSectionBase(ObjFile<ELFT> &File, + const typename ELFT::Shdr &Hdr, StringRef Name, Kind SectionKind) - : InputSectionBase(File, getFlags(Hdr->sh_flags), - getType(Hdr->sh_type, Name), Hdr->sh_entsize, - Hdr->sh_link, Hdr->sh_info, Hdr->sh_addralign, + : InputSectionBase(&File, getFlags(Hdr.sh_flags), + getType(Hdr.sh_type, Name), Hdr.sh_entsize, Hdr.sh_link, + Hdr.sh_info, Hdr.sh_addralign, getSectionContents(File, Hdr), Name, SectionKind) { // We reject object files having insanely large alignments even though // they are allowed by the spec. I think 4GB is a reasonable limitation. // We might want to relax this in the future. - if (Hdr->sh_addralign > UINT32_MAX) - fatal(toString(File) + ": section sh_addralign is too large"); + if (Hdr.sh_addralign > UINT32_MAX) + fatal(toString(&File) + ": section sh_addralign is too large"); } size_t InputSectionBase::getSize() const { @@ -211,8 +216,8 @@ void InputSectionBase::maybeUncompress() { fatal(toString(this) + ": decompress failed: " + llvm::toString(std::move(E))); - this->Data = makeArrayRef((uint8_t *)UncompressBuf.get(), Size); - this->Flags &= ~(uint64_t)SHF_COMPRESSED; + Data = makeArrayRef((uint8_t *)UncompressBuf.get(), Size); + Flags &= ~(uint64_t)SHF_COMPRESSED; } InputSection *InputSectionBase::getLinkOrderDep() const { @@ -257,40 +262,17 @@ std::string InputSectionBase::getLocation(uint64_t Offset) { return (SrcFile + ":(" + Name + "+0x" + utohexstr(Offset) + ")").str(); } -// Concatenates arguments to construct a string representing an error location. -static std::string createFileLineMsg(StringRef Path, unsigned Line) { - std::string Filename = path::filename(Path); - std::string Lineno = ":" + std::to_string(Line); - if (Filename == Path) - return Filename + Lineno; - return Filename + Lineno + " (" + Path.str() + Lineno + ")"; -} - // This function is intended to be used for constructing an error message. // The returned message looks like this: // // foo.c:42 (/home/alice/possibly/very/long/path/foo.c:42) // // Returns an empty string if there's no way to get line info. -template <class ELFT> std::string InputSectionBase::getSrcMsg(const Symbol &Sym, uint64_t Offset) { // Synthetic sections don't have input files. - ObjFile<ELFT> *File = getFile<ELFT>(); if (!File) return ""; - - // In DWARF, functions and variables are stored to different places. - // First, lookup a function for a given offset. - if (Optional<DILineInfo> Info = File->getDILineInfo(this, Offset)) - return createFileLineMsg(Info->FileName, Info->Line); - - // If it failed, lookup again as a variable. - if (Optional<std::pair<std::string, unsigned>> FileLine = - File->getVariableLoc(Sym.getName())) - return createFileLineMsg(FileLine->first, FileLine->second); - - // File->SourceFile contains STT_FILE symbol, and that is a last resort. - return File->SourceFile; + return File->getSrcMsg(Sym, *this, Offset); } // Returns a filename string along with an optional section name. This @@ -323,16 +305,17 @@ std::string InputSectionBase::getObjMsg(uint64_t Off) { .str(); } -InputSection InputSection::Discarded(0, 0, 0, ArrayRef<uint8_t>(), ""); +InputSection InputSection::Discarded(nullptr, 0, 0, 0, ArrayRef<uint8_t>(), ""); -InputSection::InputSection(uint64_t Flags, uint32_t Type, uint32_t Alignment, - ArrayRef<uint8_t> Data, StringRef Name, Kind K) - : InputSectionBase(nullptr, Flags, Type, +InputSection::InputSection(InputFile *F, uint64_t Flags, uint32_t Type, + uint32_t Alignment, ArrayRef<uint8_t> Data, + StringRef Name, Kind K) + : InputSectionBase(F, Flags, Type, /*Entsize*/ 0, /*Link*/ 0, /*Info*/ 0, Alignment, Data, Name, K) {} template <class ELFT> -InputSection::InputSection(ObjFile<ELFT> *F, const typename ELFT::Shdr *Header, +InputSection::InputSection(ObjFile<ELFT> &F, const typename ELFT::Shdr &Header, StringRef Name) : InputSectionBase(F, Header, Name, InputSectionBase::Regular) {} @@ -357,15 +340,15 @@ template <class ELFT> void InputSection::copyShtGroup(uint8_t *Buf) { // Adjust section numbers because section numbers in an input object // files are different in the output. - ArrayRef<InputSectionBase *> Sections = this->File->getSections(); + ArrayRef<InputSectionBase *> Sections = File->getSections(); for (uint32_t Idx : From.slice(1)) *To++ = Sections[Idx]->getOutputSection()->SectionIndex; } InputSectionBase *InputSection::getRelocatedSection() { - assert(this->Type == SHT_RELA || this->Type == SHT_REL); - ArrayRef<InputSectionBase *> Sections = this->File->getSections(); - return Sections[this->Info]; + assert(Type == SHT_RELA || Type == SHT_REL); + ArrayRef<InputSectionBase *> Sections = File->getSections(); + return Sections[Info]; } // This is used for -r and --emit-relocs. We can't use memcpy to copy @@ -377,7 +360,7 @@ void InputSection::copyRelocations(uint8_t *Buf, ArrayRef<RelTy> Rels) { for (const RelTy &Rel : Rels) { RelType Type = Rel.getType(Config->IsMips64EL); - Symbol &Sym = this->getFile<ELFT>()->getRelocTargetSym(Rel); + Symbol &Sym = getFile<ELFT>()->getRelocTargetSym(Rel); auto *P = reinterpret_cast<typename ELFT::Rela *>(Buf); Buf += sizeof(RelTy); @@ -679,7 +662,7 @@ void InputSection::relocateNonAlloc(uint8_t *Buf, ArrayRef<RelTy> Rels) { if (!RelTy::IsRela) Addend += Target->getImplicitAddend(BufLoc, Type); - Symbol &Sym = this->getFile<ELFT>()->getRelocTargetSym(Rel); + Symbol &Sym = getFile<ELFT>()->getRelocTargetSym(Rel); RelExpr Expr = Target->getRelExpr(Type, Sym, BufLoc); if (Expr == R_NONE) continue; @@ -691,7 +674,7 @@ void InputSection::relocateNonAlloc(uint8_t *Buf, ArrayRef<RelTy> Rels) { if (Config->EMachine == EM_386 && Type == R_386_GOTPC) continue; - error(this->getLocation<ELFT>(Offset) + ": has non-ABS relocation " + + error(getLocation<ELFT>(Offset) + ": has non-ABS relocation " + toString(Type) + " against symbol '" + toString(Sym) + "'"); return; } @@ -765,7 +748,7 @@ void InputSectionBase::relocateAlloc(uint8_t *Buf, uint8_t *BufEnd) { } template <class ELFT> void InputSection::writeTo(uint8_t *Buf) { - if (this->Type == SHT_NOBITS) + if (Type == SHT_NOBITS) return; if (auto *S = dyn_cast<SyntheticSection>(this)) { @@ -775,19 +758,17 @@ template <class ELFT> void InputSection::writeTo(uint8_t *Buf) { // If -r or --emit-relocs is given, then an InputSection // may be a relocation section. - if (this->Type == SHT_RELA) { - copyRelocations<ELFT>(Buf + OutSecOff, - this->template getDataAs<typename ELFT::Rela>()); + if (Type == SHT_RELA) { + copyRelocations<ELFT>(Buf + OutSecOff, getDataAs<typename ELFT::Rela>()); return; } - if (this->Type == SHT_REL) { - copyRelocations<ELFT>(Buf + OutSecOff, - this->template getDataAs<typename ELFT::Rel>()); + if (Type == SHT_REL) { + copyRelocations<ELFT>(Buf + OutSecOff, getDataAs<typename ELFT::Rel>()); return; } // If -r is given, we may have a SHT_GROUP section. - if (this->Type == SHT_GROUP) { + if (Type == SHT_GROUP) { copyShtGroup<ELFT>(Buf + OutSecOff); return; } @@ -796,18 +777,18 @@ template <class ELFT> void InputSection::writeTo(uint8_t *Buf) { // and then apply relocations. memcpy(Buf + OutSecOff, Data.data(), Data.size()); uint8_t *BufEnd = Buf + OutSecOff + Data.size(); - this->relocate<ELFT>(Buf, BufEnd); + relocate<ELFT>(Buf, BufEnd); } void InputSection::replace(InputSection *Other) { - this->Alignment = std::max(this->Alignment, Other->Alignment); - Other->Repl = this->Repl; + Alignment = std::max(Alignment, Other->Alignment); + Other->Repl = Repl; Other->Live = false; } template <class ELFT> -EhInputSection::EhInputSection(ObjFile<ELFT> *F, - const typename ELFT::Shdr *Header, +EhInputSection::EhInputSection(ObjFile<ELFT> &F, + const typename ELFT::Shdr &Header, StringRef Name) : InputSectionBase(F, Header, Name, InputSectionBase::EHFrame) {} @@ -838,22 +819,21 @@ static unsigned getReloc(IntTy Begin, IntTy Size, const ArrayRef<RelTy> &Rels, // This function splits an input section into records and returns them. template <class ELFT> void EhInputSection::split() { // Early exit if already split. - if (!this->Pieces.empty()) + if (!Pieces.empty()) return; - if (this->AreRelocsRela) - split<ELFT>(this->relas<ELFT>()); + if (AreRelocsRela) + split<ELFT>(relas<ELFT>()); else - split<ELFT>(this->rels<ELFT>()); + split<ELFT>(rels<ELFT>()); } template <class ELFT, class RelTy> void EhInputSection::split(ArrayRef<RelTy> Rels) { - ArrayRef<uint8_t> Data = this->Data; unsigned RelI = 0; for (size_t Off = 0, End = Data.size(); Off != End;) { size_t Size = readEhRecordSize(this, Off); - this->Pieces.emplace_back(Off, this, Size, getReloc(Off, Size, Rels, RelI)); + Pieces.emplace_back(Off, this, Size, getReloc(Off, Size, Rels, RelI)); // The empty record is the end marker. if (Size == 4) break; @@ -882,7 +862,7 @@ SyntheticSection *MergeInputSection::getParent() const { // null-terminated strings. void MergeInputSection::splitStrings(ArrayRef<uint8_t> Data, size_t EntSize) { size_t Off = 0; - bool IsAlloc = this->Flags & SHF_ALLOC; + bool IsAlloc = Flags & SHF_ALLOC; StringRef S = toStringRef(Data); while (!S.empty()) { @@ -903,7 +883,7 @@ void MergeInputSection::splitNonStrings(ArrayRef<uint8_t> Data, size_t EntSize) { size_t Size = Data.size(); assert((Size % EntSize) == 0); - bool IsAlloc = this->Flags & SHF_ALLOC; + bool IsAlloc = Flags & SHF_ALLOC; for (size_t I = 0; I != Size; I += EntSize) Pieces.emplace_back(I, xxHash64(toStringRef(Data.slice(I, EntSize))), @@ -911,16 +891,16 @@ void MergeInputSection::splitNonStrings(ArrayRef<uint8_t> Data, } template <class ELFT> -MergeInputSection::MergeInputSection(ObjFile<ELFT> *F, - const typename ELFT::Shdr *Header, +MergeInputSection::MergeInputSection(ObjFile<ELFT> &F, + const typename ELFT::Shdr &Header, StringRef Name) - : InputSectionBase(F, Header, Name, InputSectionBase::Merge) { - // In order to reduce memory allocation, we assume that mergeable - // sections are smaller than 4 GiB, which is not an unreasonable - // assumption as of 2017. - if (Data.size() > UINT32_MAX) - error(toString(this) + ": section too large"); -} + : InputSectionBase(F, Header, Name, InputSectionBase::Merge) {} + +MergeInputSection::MergeInputSection(uint64_t Flags, uint32_t Type, + uint64_t Entsize, ArrayRef<uint8_t> Data, + StringRef Name) + : InputSectionBase(nullptr, Flags, Type, Entsize, /*Link*/ 0, /*Info*/ 0, + /*Alignment*/ Entsize, Data, Name, SectionBase::Merge) {} // This function is called after we obtain a complete list of input sections // that need to be linked. This is responsible to split section contents @@ -931,14 +911,14 @@ MergeInputSection::MergeInputSection(ObjFile<ELFT> *F, void MergeInputSection::splitIntoPieces() { assert(Pieces.empty()); - if (this->Flags & SHF_STRINGS) + if (Flags & SHF_STRINGS) splitStrings(Data, Entsize); else splitNonStrings(Data, Entsize); - if (Config->GcSections && (this->Flags & SHF_ALLOC)) + if (Config->GcSections && (Flags & SHF_ALLOC)) for (uint64_t Off : LiveOffsets) - this->getSectionPiece(Off)->Live = true; + getSectionPiece(Off)->Live = true; } // Do binary search to get a section piece at a given input offset. @@ -993,7 +973,7 @@ uint64_t MergeInputSection::getOffset(uint64_t Offset) const { // If Offset is not at beginning of a section piece, it is not in the map. // In that case we need to search from the original section piece vector. - const SectionPiece &Piece = *this->getSectionPiece(Offset); + const SectionPiece &Piece = *getSectionPiece(Offset); if (!Piece.Live) return 0; @@ -1001,13 +981,13 @@ uint64_t MergeInputSection::getOffset(uint64_t Offset) const { return Piece.OutputOff + Addend; } -template InputSection::InputSection(ObjFile<ELF32LE> *, const ELF32LE::Shdr *, +template InputSection::InputSection(ObjFile<ELF32LE> &, const ELF32LE::Shdr &, StringRef); -template InputSection::InputSection(ObjFile<ELF32BE> *, const ELF32BE::Shdr *, +template InputSection::InputSection(ObjFile<ELF32BE> &, const ELF32BE::Shdr &, StringRef); -template InputSection::InputSection(ObjFile<ELF64LE> *, const ELF64LE::Shdr *, +template InputSection::InputSection(ObjFile<ELF64LE> &, const ELF64LE::Shdr &, StringRef); -template InputSection::InputSection(ObjFile<ELF64BE> *, const ELF64BE::Shdr *, +template InputSection::InputSection(ObjFile<ELF64BE> &, const ELF64BE::Shdr &, StringRef); template std::string InputSectionBase::getLocation<ELF32LE>(uint64_t); @@ -1015,37 +995,28 @@ template std::string InputSectionBase::getLocation<ELF32BE>(uint64_t); template std::string InputSectionBase::getLocation<ELF64LE>(uint64_t); template std::string InputSectionBase::getLocation<ELF64BE>(uint64_t); -template std::string InputSectionBase::getSrcMsg<ELF32LE>(const Symbol &, - uint64_t); -template std::string InputSectionBase::getSrcMsg<ELF32BE>(const Symbol &, - uint64_t); -template std::string InputSectionBase::getSrcMsg<ELF64LE>(const Symbol &, - uint64_t); -template std::string InputSectionBase::getSrcMsg<ELF64BE>(const Symbol &, - uint64_t); - template void InputSection::writeTo<ELF32LE>(uint8_t *); template void InputSection::writeTo<ELF32BE>(uint8_t *); template void InputSection::writeTo<ELF64LE>(uint8_t *); template void InputSection::writeTo<ELF64BE>(uint8_t *); -template MergeInputSection::MergeInputSection(ObjFile<ELF32LE> *, - const ELF32LE::Shdr *, StringRef); -template MergeInputSection::MergeInputSection(ObjFile<ELF32BE> *, - const ELF32BE::Shdr *, StringRef); -template MergeInputSection::MergeInputSection(ObjFile<ELF64LE> *, - const ELF64LE::Shdr *, StringRef); -template MergeInputSection::MergeInputSection(ObjFile<ELF64BE> *, - const ELF64BE::Shdr *, StringRef); - -template EhInputSection::EhInputSection(ObjFile<ELF32LE> *, - const ELF32LE::Shdr *, StringRef); -template EhInputSection::EhInputSection(ObjFile<ELF32BE> *, - const ELF32BE::Shdr *, StringRef); -template EhInputSection::EhInputSection(ObjFile<ELF64LE> *, - const ELF64LE::Shdr *, StringRef); -template EhInputSection::EhInputSection(ObjFile<ELF64BE> *, - const ELF64BE::Shdr *, StringRef); +template MergeInputSection::MergeInputSection(ObjFile<ELF32LE> &, + const ELF32LE::Shdr &, StringRef); +template MergeInputSection::MergeInputSection(ObjFile<ELF32BE> &, + const ELF32BE::Shdr &, StringRef); +template MergeInputSection::MergeInputSection(ObjFile<ELF64LE> &, + const ELF64LE::Shdr &, StringRef); +template MergeInputSection::MergeInputSection(ObjFile<ELF64BE> &, + const ELF64BE::Shdr &, StringRef); + +template EhInputSection::EhInputSection(ObjFile<ELF32LE> &, + const ELF32LE::Shdr &, StringRef); +template EhInputSection::EhInputSection(ObjFile<ELF32BE> &, + const ELF32BE::Shdr &, StringRef); +template EhInputSection::EhInputSection(ObjFile<ELF64LE> &, + const ELF64LE::Shdr &, StringRef); +template EhInputSection::EhInputSection(ObjFile<ELF64BE> &, + const ELF64BE::Shdr &, StringRef); template void EhInputSection::split<ELF32LE>(); template void EhInputSection::split<ELF32BE>(); diff --git a/ELF/InputSection.h b/ELF/InputSection.h index dfd78a8fb458..8c114ae71948 100644 --- a/ELF/InputSection.h +++ b/ELF/InputSection.h @@ -93,7 +93,7 @@ protected: class InputSectionBase : public SectionBase { public: template <class ELFT> - InputSectionBase(ObjFile<ELFT> *File, const typename ELFT::Shdr *Header, + InputSectionBase(ObjFile<ELFT> &File, const typename ELFT::Shdr &Header, StringRef Name, Kind SectionKind); InputSectionBase(InputFile *File, uint64_t Flags, uint32_t Type, @@ -168,7 +168,6 @@ public: // Returns a source location string. Used to construct an error message. template <class ELFT> std::string getLocation(uint64_t Offset); - template <class ELFT> std::string getSrcMsg(const Symbol &Sym, uint64_t Offset); std::string getObjMsg(uint64_t Offset); @@ -216,8 +215,11 @@ static_assert(sizeof(SectionPiece) == 16, "SectionPiece is too big"); class MergeInputSection : public InputSectionBase { public: template <class ELFT> - MergeInputSection(ObjFile<ELFT> *F, const typename ELFT::Shdr *Header, + MergeInputSection(ObjFile<ELFT> &F, const typename ELFT::Shdr &Header, StringRef Name); + MergeInputSection(uint64_t Flags, uint32_t Type, uint64_t Entsize, + ArrayRef<uint8_t> Data, StringRef Name); + static bool classof(const SectionBase *S) { return S->kind() == Merge; } void splitIntoPieces(); @@ -279,7 +281,7 @@ struct EhSectionPiece { class EhInputSection : public InputSectionBase { public: template <class ELFT> - EhInputSection(ObjFile<ELFT> *F, const typename ELFT::Shdr *Header, + EhInputSection(ObjFile<ELFT> &F, const typename ELFT::Shdr &Header, StringRef Name); static bool classof(const SectionBase *S) { return S->kind() == EHFrame; } template <class ELFT> void split(); @@ -298,10 +300,10 @@ public: // .eh_frame. It also includes the synthetic sections themselves. class InputSection : public InputSectionBase { public: - InputSection(uint64_t Flags, uint32_t Type, uint32_t Alignment, + InputSection(InputFile *F, uint64_t Flags, uint32_t Type, uint32_t Alignment, ArrayRef<uint8_t> Data, StringRef Name, Kind K = Regular); template <class ELFT> - InputSection(ObjFile<ELFT> *F, const typename ELFT::Shdr *Header, + InputSection(ObjFile<ELFT> &F, const typename ELFT::Shdr &Header, StringRef Name); // Write this section to a mmap'ed file, assuming Buf is pointing to diff --git a/ELF/MarkLive.cpp b/ELF/MarkLive.cpp index 36f994f20490..88f558c7a3c6 100644 --- a/ELF/MarkLive.cpp +++ b/ELF/MarkLive.cpp @@ -68,7 +68,7 @@ static void resolveReloc(InputSectionBase &Sec, RelT &Rel, B.Used = true; if (auto *SS = dyn_cast<SharedSymbol>(&B)) if (!SS->isWeak()) - SS->getFile<ELFT>()->IsNeeded = true; + SS->getFile<ELFT>().IsNeeded = true; if (auto *D = dyn_cast<Defined>(&B)) { auto *RelSec = dyn_cast_or_null<InputSectionBase>(D->Section); @@ -246,7 +246,7 @@ template <class ELFT> static void doGcSections() { // that point to .eh_frames. Otherwise, the garbage collector would drop // all of them. We also want to preserve personality routines and LSDA // referenced by .eh_frame sections, so we scan them for that here. - if (auto *EH = dyn_cast_or_null<EhInputSection>(Sec)) { + if (auto *EH = dyn_cast<EhInputSection>(Sec)) { EH->Live = true; scanEhFrameSection<ELFT>(*EH, Enqueue); } diff --git a/ELF/Relocations.cpp b/ELF/Relocations.cpp index 96e409578f5c..94ea3e1557c4 100644 --- a/ELF/Relocations.cpp +++ b/ELF/Relocations.cpp @@ -70,12 +70,11 @@ using namespace lld::elf; // >>> defined in /home/alice/src/foo.o // >>> referenced by bar.c:12 (/home/alice/src/bar.c:12) // >>> /home/alice/src/bar.o:(.text+0x1) -template <class ELFT> static std::string getLocation(InputSectionBase &S, const Symbol &Sym, uint64_t Off) { std::string Msg = "\n>>> defined in " + toString(Sym.File) + "\n>>> referenced by "; - std::string Src = S.getSrcMsg<ELFT>(Sym, Off); + std::string Src = S.getSrcMsg(Sym, Off); if (!Src.empty()) Msg += Src + "\n>>> "; return Msg + S.getObjMsg(Off); @@ -365,7 +364,6 @@ static bool isRelExpr(RelExpr Expr) { // // If this function returns false, that means we need to emit a // dynamic relocation so that the relocation will be fixed at load-time. -template <class ELFT> static bool isStaticLinkTimeConstant(RelExpr E, RelType Type, const Symbol &Sym, InputSectionBase &S, uint64_t RelOff) { // These expressions always compute a constant @@ -410,7 +408,7 @@ static bool isStaticLinkTimeConstant(RelExpr E, RelType Type, const Symbol &Sym, return true; error("relocation " + toString(Type) + " cannot refer to absolute symbol: " + - toString(Sym) + getLocation<ELFT>(S, Sym, RelOff)); + toString(Sym) + getLocation(S, Sym, RelOff)); return true; } @@ -443,8 +441,8 @@ template <class ELFT> static bool isReadOnly(SharedSymbol *SS) { typedef typename ELFT::Phdr Elf_Phdr; // Determine if the symbol is read-only by scanning the DSO's program headers. - const SharedFile<ELFT> *File = SS->getFile<ELFT>(); - for (const Elf_Phdr &Phdr : check(File->getObj().program_headers())) + const SharedFile<ELFT> &File = SS->getFile<ELFT>(); + for (const Elf_Phdr &Phdr : check(File.getObj().program_headers())) if ((Phdr.p_type == ELF::PT_LOAD || Phdr.p_type == ELF::PT_GNU_RELRO) && !(Phdr.p_flags & ELF::PF_W) && SS->Value >= Phdr.p_vaddr && SS->Value < Phdr.p_vaddr + Phdr.p_memsz) @@ -461,14 +459,14 @@ template <class ELFT> static std::vector<SharedSymbol *> getSymbolsAt(SharedSymbol *SS) { typedef typename ELFT::Sym Elf_Sym; - SharedFile<ELFT> *File = SS->getFile<ELFT>(); + SharedFile<ELFT> &File = SS->getFile<ELFT>(); std::vector<SharedSymbol *> Ret; - for (const Elf_Sym &S : File->getGlobalELFSyms()) { + for (const Elf_Sym &S : File.getGlobalELFSyms()) { if (S.st_shndx == SHN_UNDEF || S.st_shndx == SHN_ABS || S.st_value != SS->Value) continue; - StringRef Name = check(S.getName(File->getStringTable())); + StringRef Name = check(S.getName(File.getStringTable())); Symbol *Sym = Symtab->find(Name); if (auto *Alias = dyn_cast_or_null<SharedSymbol>(Sym)) Ret.push_back(Alias); @@ -554,22 +552,57 @@ static void errorOrWarn(const Twine &Msg) { warn(Msg); } +// Returns PLT relocation expression. +// +// This handles a non PIC program call to function in a shared library. In +// an ideal world, we could just report an error saying the relocation can +// overflow at runtime. In the real world with glibc, crt1.o has a +// R_X86_64_PC32 pointing to libc.so. +// +// The general idea on how to handle such cases is to create a PLT entry and +// use that as the function value. +// +// For the static linking part, we just return a plt expr and everything +// else will use the the PLT entry as the address. +// +// The remaining problem is making sure pointer equality still works. We +// need the help of the dynamic linker for that. We let it know that we have +// a direct reference to a so symbol by creating an undefined symbol with a +// non zero st_value. Seeing that, the dynamic linker resolves the symbol to +// the value of the symbol we created. This is true even for got entries, so +// pointer equality is maintained. To avoid an infinite loop, the only entry +// that points to the real function is a dedicated got entry used by the +// plt. That is identified by special relocation types (R_X86_64_JUMP_SLOT, +// R_386_JMP_SLOT, etc). +static RelExpr getPltExpr(Symbol &Sym, RelExpr Expr, bool &IsConstant) { + Sym.NeedsPltAddr = true; + Sym.IsPreemptible = false; + IsConstant = true; + return toPlt(Expr); +} + template <class ELFT> static RelExpr adjustExpr(Symbol &Sym, RelExpr Expr, RelType Type, - InputSectionBase &S, uint64_t RelOff) { + InputSectionBase &S, uint64_t RelOff, + bool &IsConstant) { // We can create any dynamic relocation if a section is simply writable. if (S.Flags & SHF_WRITE) return Expr; // Or, if we are allowed to create dynamic relocations against - // read-only sections (i.e. unless "-z notext" is given), + // read-only sections (i.e. when "-z notext" is given), // we can create a dynamic relocation as we want, too. - if (!Config->ZText) + if (!Config->ZText) { + // We use PLT for relocations that may overflow in runtime, + // see comment for getPltExpr(). + if (Sym.isFunc() && !Target->isPicRel(Type)) + return getPltExpr(Sym, Expr, IsConstant); return Expr; + } // If a relocation can be applied at link-time, we don't need to // create a dynamic relocation in the first place. - if (isStaticLinkTimeConstant<ELFT>(Expr, Type, Sym, S, RelOff)) + if (IsConstant) return Expr; // If we got here we know that this relocation would require the dynamic @@ -579,6 +612,7 @@ static RelExpr adjustExpr(Symbol &Sym, RelExpr Expr, RelType Type, // non preemptible 0. if (Sym.isUndefWeak()) { Sym.IsPreemptible = false; + IsConstant = true; return Expr; } @@ -589,13 +623,13 @@ static RelExpr adjustExpr(Symbol &Sym, RelExpr Expr, RelType Type, "can't create dynamic relocation " + toString(Type) + " against " + (Sym.getName().empty() ? "local symbol" : "symbol: " + toString(Sym)) + " in readonly segment; recompile object files with -fPIC" + - getLocation<ELFT>(S, Sym, RelOff)); + getLocation(S, Sym, RelOff)); return Expr; } if (Sym.getVisibility() != STV_DEFAULT) { error("cannot preempt symbol: " + toString(Sym) + - getLocation<ELFT>(S, Sym, RelOff)); + getLocation(S, Sym, RelOff)); return Expr; } @@ -607,38 +641,16 @@ static RelExpr adjustExpr(Symbol &Sym, RelExpr Expr, RelType Type, error("unresolvable relocation " + toString(Type) + " against symbol '" + toString(*B) + "'; recompile with -fPIC or remove '-z nocopyreloc'" + - getLocation<ELFT>(S, Sym, RelOff)); + getLocation(S, Sym, RelOff)); addCopyRelSymbol<ELFT>(B); } + IsConstant = true; return Expr; } - if (Sym.isFunc()) { - // This handles a non PIC program call to function in a shared library. In - // an ideal world, we could just report an error saying the relocation can - // overflow at runtime. In the real world with glibc, crt1.o has a - // R_X86_64_PC32 pointing to libc.so. - // - // The general idea on how to handle such cases is to create a PLT entry and - // use that as the function value. - // - // For the static linking part, we just return a plt expr and everything - // else will use the the PLT entry as the address. - // - // The remaining problem is making sure pointer equality still works. We - // need the help of the dynamic linker for that. We let it know that we have - // a direct reference to a so symbol by creating an undefined symbol with a - // non zero st_value. Seeing that, the dynamic linker resolves the symbol to - // the value of the symbol we created. This is true even for got entries, so - // pointer equality is maintained. To avoid an infinite loop, the only entry - // that points to the real function is a dedicated got entry used by the - // plt. That is identified by special relocation types (R_X86_64_JUMP_SLOT, - // R_386_JMP_SLOT, etc). - Sym.NeedsPltAddr = true; - Sym.IsPreemptible = false; - return toPlt(Expr); - } + if (Sym.isFunc()) + return getPltExpr(Sym, Expr, IsConstant); errorOrWarn("symbol '" + toString(Sym) + "' defined in " + toString(Sym.File) + " has no type"); @@ -708,7 +720,6 @@ static int64_t computeAddend(const RelTy &Rel, const RelTy *End, // Report an undefined symbol if necessary. // Returns true if this function printed out an error message. -template <class ELFT> static bool maybeReportUndefined(Symbol &Sym, InputSectionBase &Sec, uint64_t Offset) { if (Config->UnresolvedSymbols == UnresolvedPolicy::IgnoreAll) @@ -725,7 +736,7 @@ static bool maybeReportUndefined(Symbol &Sym, InputSectionBase &Sec, std::string Msg = "undefined symbol: " + toString(Sym) + "\n>>> referenced by "; - std::string Src = Sec.getSrcMsg<ELFT>(Sym, Offset); + std::string Src = Sec.getSrcMsg(Sym, Offset); if (!Src.empty()) Msg += Src + "\n>>> "; Msg += Sec.getObjMsg(Offset); @@ -846,7 +857,7 @@ template <class ELFT> static void addGotEntry(Symbol &Sym, bool Preemptible) { // // This is ugly -- the difference between REL and RELA should be // handled in a better way. It's a TODO. - if (!Config->IsRela) + if (!Config->IsRela && !Preemptible) InX::Got->Relocations.push_back({R_ABS, Target->GotRel, Off, 0, &Sym}); } @@ -885,7 +896,7 @@ static void scanRelocs(InputSectionBase &Sec, ArrayRef<RelTy> Rels) { continue; // Skip if the target symbol is an erroneous undefined symbol. - if (maybeReportUndefined<ELFT>(Sym, Sec, Rel.r_offset)) + if (maybeReportUndefined(Sym, Sec, Rel.r_offset)) continue; RelExpr Expr = @@ -923,7 +934,10 @@ static void scanRelocs(InputSectionBase &Sec, ArrayRef<RelTy> Rels) { else if (!Preemptible) Expr = fromPlt(Expr); - Expr = adjustExpr<ELFT>(Sym, Expr, Type, Sec, Rel.r_offset); + bool IsConstant = + isStaticLinkTimeConstant(Expr, Type, Sym, Sec, Rel.r_offset); + + Expr = adjustExpr<ELFT>(Sym, Expr, Type, Sec, Rel.r_offset, IsConstant); if (errorCount()) continue; @@ -980,7 +994,7 @@ static void scanRelocs(InputSectionBase &Sec, ArrayRef<RelTy> Rels) { errorOrWarn( "relocation " + toString(Type) + " cannot be used against shared object; recompile with -fPIC" + - getLocation<ELFT>(Sec, Sym, Offset)); + getLocation(Sec, Sym, Offset)); InX::RelaDyn->addReloc( {Target->getDynRel(Type), &Sec, Offset, false, &Sym, Addend}); @@ -1005,10 +1019,6 @@ static void scanRelocs(InputSectionBase &Sec, ArrayRef<RelTy> Rels) { continue; } - // If the relocation points to something in the file, we can process it. - bool IsConstant = - isStaticLinkTimeConstant<ELFT>(Expr, Type, Sym, Sec, Rel.r_offset); - // The size is not going to change, so we fold it in here. if (Expr == R_SIZE) Addend += Sym.getSize(); diff --git a/ELF/ScriptParser.cpp b/ELF/ScriptParser.cpp index d56500ae7dd8..c1176ccfa8d5 100644 --- a/ELF/ScriptParser.cpp +++ b/ELF/ScriptParser.cpp @@ -151,6 +151,8 @@ static ExprValue add(ExprValue A, ExprValue B) { } static ExprValue sub(ExprValue A, ExprValue B) { + if (!A.isAbsolute() && !B.isAbsolute()) + return A.getValue() - B.getValue(); return {A.Sec, false, A.getSectionOffset() - B.getValue(), A.Loc}; } diff --git a/ELF/SymbolTable.cpp b/ELF/SymbolTable.cpp index 12509c9a1757..b6bf21998863 100644 --- a/ELF/SymbolTable.cpp +++ b/ELF/SymbolTable.cpp @@ -44,8 +44,8 @@ static InputFile *getFirstElf() { // 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 <class ELFT> static bool isCompatible(InputFile *F) { - if (!isa<ELFFileBase<ELFT>>(F) && !isa<BitcodeFile>(F)) +static bool isCompatible(InputFile *F) { + if (!F->isElf() && !isa<BitcodeFile>(F)) return true; if (F->EKind == Config->EKind && F->EMachine == Config->EMachine) { @@ -64,13 +64,13 @@ template <class ELFT> static bool isCompatible(InputFile *F) { // Add symbols in File to the symbol table. template <class ELFT> void SymbolTable::addFile(InputFile *File) { - if (!isCompatible<ELFT>(File)) + if (!isCompatible(File)) return; // Binary file if (auto *F = dyn_cast<BinaryFile>(File)) { BinaryFiles.push_back(F); - F->parse<ELFT>(); + F->parse(); return; } @@ -135,11 +135,10 @@ template <class ELFT> void SymbolTable::addCombinedLTOObject() { } } -template <class ELFT> Defined *SymbolTable::addAbsolute(StringRef Name, uint8_t Visibility, uint8_t Binding) { - Symbol *Sym = addRegular<ELFT>(Name, Visibility, STT_NOTYPE, 0, 0, Binding, - nullptr, nullptr); + Symbol *Sym = + addRegular(Name, Visibility, STT_NOTYPE, 0, 0, Binding, nullptr, nullptr); return cast<Defined>(Sym); } @@ -306,7 +305,7 @@ Symbol *SymbolTable::addUndefined(StringRef Name, uint8_t Binding, if (Binding != STB_WEAK) { if (auto *SS = dyn_cast<SharedSymbol>(S)) if (!Config->GcSections) - SS->getFile<ELFT>()->IsNeeded = true; + SS->getFile<ELFT>().IsNeeded = true; } if (auto *L = dyn_cast<Lazy>(S)) { // An undefined weak will not fetch archive members. See comment on Lazy in @@ -377,19 +376,19 @@ static int compareDefinedNonCommon(Symbol *S, bool WasInserted, uint8_t Binding, Symbol *SymbolTable::addCommon(StringRef N, uint64_t Size, uint32_t Alignment, uint8_t Binding, uint8_t StOther, uint8_t Type, - InputFile *File) { + InputFile &File) { Symbol *S; bool WasInserted; std::tie(S, WasInserted) = insert(N, Type, getVisibility(StOther), - /*CanOmitFromDynSym*/ false, File); + /*CanOmitFromDynSym*/ false, &File); int Cmp = compareDefined(S, WasInserted, Binding, N); if (Cmp > 0) { auto *Bss = make<BssSection>("COMMON", Size, Alignment); - Bss->File = File; + Bss->File = &File; Bss->Live = !Config->GcSections; InputSections.push_back(Bss); - replaceSymbol<Defined>(S, File, N, Binding, StOther, Type, 0, Size, Bss); + replaceSymbol<Defined>(S, &File, N, Binding, StOther, Type, 0, Size, Bss); } else if (Cmp == 0) { auto *D = cast<Defined>(S); auto *Bss = dyn_cast_or_null<BssSection>(D->Section); @@ -405,7 +404,7 @@ Symbol *SymbolTable::addCommon(StringRef N, uint64_t Size, uint32_t Alignment, Bss->Alignment = std::max(Bss->Alignment, Alignment); if (Size > Bss->Size) { - D->File = Bss->File = File; + D->File = Bss->File = &File; D->Size = Bss->Size = Size; } } @@ -424,9 +423,8 @@ static void reportDuplicate(Symbol *Sym, InputFile *NewFile) { toString(Sym->File) + "\n>>> defined in " + toString(NewFile)); } -template <class ELFT> static void reportDuplicate(Symbol *Sym, InputSectionBase *ErrSec, - typename ELFT::uint ErrOffset) { + uint64_t ErrOffset) { Defined *D = cast<Defined>(Sym); if (!D->Section || !ErrSec) { reportDuplicate(Sym, ErrSec ? ErrSec->File : nullptr); @@ -441,9 +439,9 @@ static void reportDuplicate(Symbol *Sym, InputSectionBase *ErrSec, // >>> defined at baz.c:563 // >>> baz.o in archive libbaz.a auto *Sec1 = cast<InputSectionBase>(D->Section); - std::string Src1 = Sec1->getSrcMsg<ELFT>(*Sym, D->Value); + std::string Src1 = Sec1->getSrcMsg(*Sym, D->Value); std::string Obj1 = Sec1->getObjMsg(D->Value); - std::string Src2 = ErrSec->getSrcMsg<ELFT>(*Sym, ErrOffset); + std::string Src2 = ErrSec->getSrcMsg(*Sym, ErrOffset); std::string Obj2 = ErrSec->getObjMsg(ErrOffset); std::string Msg = "duplicate symbol: " + toString(*Sym) + "\n>>> defined at "; @@ -456,7 +454,6 @@ static void reportDuplicate(Symbol *Sym, InputSectionBase *ErrSec, warnOrError(Msg); } -template <typename ELFT> Symbol *SymbolTable::addRegular(StringRef Name, uint8_t StOther, uint8_t Type, uint64_t Value, uint64_t Size, uint8_t Binding, SectionBase *Section, InputFile *File) { @@ -470,13 +467,12 @@ Symbol *SymbolTable::addRegular(StringRef Name, uint8_t StOther, uint8_t Type, replaceSymbol<Defined>(S, File, Name, Binding, StOther, Type, Value, Size, Section); else if (Cmp == 0) - reportDuplicate<ELFT>(S, dyn_cast_or_null<InputSectionBase>(Section), - Value); + reportDuplicate(S, dyn_cast_or_null<InputSectionBase>(Section), Value); return S; } template <typename ELFT> -void SymbolTable::addShared(StringRef Name, SharedFile<ELFT> *File, +void SymbolTable::addShared(StringRef Name, SharedFile<ELFT> &File, const typename ELFT::Sym &Sym, uint32_t Alignment, uint32_t VerdefIndex) { // DSO symbols do not affect visibility in the output, so we pass STV_DEFAULT @@ -485,7 +481,7 @@ void SymbolTable::addShared(StringRef Name, SharedFile<ELFT> *File, Symbol *S; bool WasInserted; std::tie(S, WasInserted) = insert(Name, Sym.getType(), STV_DEFAULT, - /*CanOmitFromDynSym*/ true, File); + /*CanOmitFromDynSym*/ true, &File); // Make sure we preempt DSO symbols with default visibility. if (Sym.getVisibility() == STV_DEFAULT) S->ExportDynamic = true; @@ -501,24 +497,24 @@ void SymbolTable::addShared(StringRef Name, SharedFile<ELFT> *File, if (!WasInserted) { S->Binding = Binding; if (!S->isWeak() && !Config->GcSections) - File->IsNeeded = true; + File.IsNeeded = true; } } } Symbol *SymbolTable::addBitcode(StringRef Name, uint8_t Binding, uint8_t StOther, uint8_t Type, - bool CanOmitFromDynSym, BitcodeFile *F) { + bool CanOmitFromDynSym, BitcodeFile &F) { Symbol *S; bool WasInserted; std::tie(S, WasInserted) = - insert(Name, Type, getVisibility(StOther), CanOmitFromDynSym, F); + insert(Name, Type, getVisibility(StOther), CanOmitFromDynSym, &F); int Cmp = compareDefinedNonCommon(S, WasInserted, Binding, /*IsAbs*/ false, /*Value*/ 0, Name); if (Cmp > 0) - replaceSymbol<Defined>(S, F, Name, Binding, StOther, Type, 0, 0, nullptr); + replaceSymbol<Defined>(S, &F, Name, Binding, StOther, Type, 0, 0, nullptr); else if (Cmp == 0) - reportDuplicate(S, F); + reportDuplicate(S, &F); return S; } @@ -532,7 +528,7 @@ Symbol *SymbolTable::find(StringRef Name) { } template <class ELFT> -Symbol *SymbolTable::addLazyArchive(StringRef Name, ArchiveFile *F, +Symbol *SymbolTable::addLazyArchive(StringRef Name, ArchiveFile &F, const object::Archive::Symbol Sym) { Symbol *S; bool WasInserted; @@ -551,9 +547,9 @@ Symbol *SymbolTable::addLazyArchive(StringRef Name, ArchiveFile *F, S->Binding = STB_WEAK; return S; } - std::pair<MemoryBufferRef, uint64_t> MBInfo = F->getMember(&Sym); + std::pair<MemoryBufferRef, uint64_t> MBInfo = F.getMember(&Sym); if (!MBInfo.first.getBuffer().empty()) - addFile<ELFT>(createObjectFile(MBInfo.first, F->getName(), MBInfo.second)); + addFile<ELFT>(createObjectFile(MBInfo.first, F.getName(), MBInfo.second)); return S; } @@ -563,7 +559,7 @@ void SymbolTable::addLazyObject(StringRef Name, LazyObjFile &Obj) { bool WasInserted; std::tie(S, WasInserted) = insert(Name); if (WasInserted) { - replaceSymbol<LazyObject>(S, &Obj, Name, Symbol::UnknownType); + replaceSymbol<LazyObject>(S, Obj, Name, Symbol::UnknownType); return; } if (!S->isUndefined()) @@ -571,7 +567,7 @@ void SymbolTable::addLazyObject(StringRef Name, LazyObjFile &Obj) { // See comment for addLazyArchive above. if (S->isWeak()) - replaceSymbol<LazyObject>(S, &Obj, Name, S->Type); + replaceSymbol<LazyObject>(S, Obj, Name, S->Type); else if (InputFile *F = Obj.fetch()) addFile<ELFT>(F); } @@ -582,7 +578,7 @@ template <class ELFT> void SymbolTable::fetchIfLazy(StringRef Name) { // Mark the symbol not to be eliminated by LTO // even if it is a bitcode symbol. B->IsUsedInRegularObj = true; - if (auto *L = dyn_cast_or_null<Lazy>(B)) + if (auto *L = dyn_cast<Lazy>(B)) if (InputFile *File = L->fetch()) addFile<ELFT>(File); } @@ -797,39 +793,17 @@ template void SymbolTable::addCombinedLTOObject<ELF32BE>(); template void SymbolTable::addCombinedLTOObject<ELF64LE>(); template void SymbolTable::addCombinedLTOObject<ELF64BE>(); -template Symbol *SymbolTable::addRegular<ELF32LE>(StringRef, uint8_t, uint8_t, - uint64_t, uint64_t, uint8_t, - SectionBase *, InputFile *); -template Symbol *SymbolTable::addRegular<ELF32BE>(StringRef, uint8_t, uint8_t, - uint64_t, uint64_t, uint8_t, - SectionBase *, InputFile *); -template Symbol *SymbolTable::addRegular<ELF64LE>(StringRef, uint8_t, uint8_t, - uint64_t, uint64_t, uint8_t, - SectionBase *, InputFile *); -template Symbol *SymbolTable::addRegular<ELF64BE>(StringRef, uint8_t, uint8_t, - uint64_t, uint64_t, uint8_t, - SectionBase *, InputFile *); - -template Defined *SymbolTable::addAbsolute<ELF32LE>(StringRef, uint8_t, - uint8_t); -template Defined *SymbolTable::addAbsolute<ELF32BE>(StringRef, uint8_t, - uint8_t); -template Defined *SymbolTable::addAbsolute<ELF64LE>(StringRef, uint8_t, - uint8_t); -template Defined *SymbolTable::addAbsolute<ELF64BE>(StringRef, uint8_t, - uint8_t); - template Symbol * -SymbolTable::addLazyArchive<ELF32LE>(StringRef, ArchiveFile *, +SymbolTable::addLazyArchive<ELF32LE>(StringRef, ArchiveFile &, const object::Archive::Symbol); template Symbol * -SymbolTable::addLazyArchive<ELF32BE>(StringRef, ArchiveFile *, +SymbolTable::addLazyArchive<ELF32BE>(StringRef, ArchiveFile &, const object::Archive::Symbol); template Symbol * -SymbolTable::addLazyArchive<ELF64LE>(StringRef, ArchiveFile *, +SymbolTable::addLazyArchive<ELF64LE>(StringRef, ArchiveFile &, const object::Archive::Symbol); template Symbol * -SymbolTable::addLazyArchive<ELF64BE>(StringRef, ArchiveFile *, +SymbolTable::addLazyArchive<ELF64BE>(StringRef, ArchiveFile &, const object::Archive::Symbol); template void SymbolTable::addLazyObject<ELF32LE>(StringRef, LazyObjFile &); @@ -837,16 +811,16 @@ template void SymbolTable::addLazyObject<ELF32BE>(StringRef, LazyObjFile &); template void SymbolTable::addLazyObject<ELF64LE>(StringRef, LazyObjFile &); template void SymbolTable::addLazyObject<ELF64BE>(StringRef, LazyObjFile &); -template void SymbolTable::addShared<ELF32LE>(StringRef, SharedFile<ELF32LE> *, +template void SymbolTable::addShared<ELF32LE>(StringRef, SharedFile<ELF32LE> &, const typename ELF32LE::Sym &, uint32_t Alignment, uint32_t); -template void SymbolTable::addShared<ELF32BE>(StringRef, SharedFile<ELF32BE> *, +template void SymbolTable::addShared<ELF32BE>(StringRef, SharedFile<ELF32BE> &, const typename ELF32BE::Sym &, uint32_t Alignment, uint32_t); -template void SymbolTable::addShared<ELF64LE>(StringRef, SharedFile<ELF64LE> *, +template void SymbolTable::addShared<ELF64LE>(StringRef, SharedFile<ELF64LE> &, const typename ELF64LE::Sym &, uint32_t Alignment, uint32_t); -template void SymbolTable::addShared<ELF64BE>(StringRef, SharedFile<ELF64BE> *, +template void SymbolTable::addShared<ELF64BE>(StringRef, SharedFile<ELF64BE> &, const typename ELF64BE::Sym &, uint32_t Alignment, uint32_t); diff --git a/ELF/SymbolTable.h b/ELF/SymbolTable.h index 738311c089db..e7341b05baf5 100644 --- a/ELF/SymbolTable.h +++ b/ELF/SymbolTable.h @@ -42,7 +42,6 @@ public: ArrayRef<Symbol *> getSymbols() const { return SymVector; } - template <class ELFT> Defined *addAbsolute(StringRef Name, uint8_t Visibility = llvm::ELF::STV_HIDDEN, uint8_t Binding = llvm::ELF::STB_GLOBAL); @@ -51,28 +50,27 @@ public: template <class ELFT> Symbol *addUndefined(StringRef Name, uint8_t Binding, uint8_t StOther, uint8_t Type, bool CanOmitFromDynSym, InputFile *File); - template <class ELFT> Symbol *addRegular(StringRef Name, uint8_t StOther, uint8_t Type, uint64_t Value, uint64_t Size, uint8_t Binding, SectionBase *Section, InputFile *File); template <class ELFT> - void addShared(StringRef Name, SharedFile<ELFT> *F, + void addShared(StringRef Name, SharedFile<ELFT> &F, const typename ELFT::Sym &Sym, uint32_t Alignment, uint32_t VerdefIndex); template <class ELFT> - Symbol *addLazyArchive(StringRef Name, ArchiveFile *F, + Symbol *addLazyArchive(StringRef Name, ArchiveFile &F, const llvm::object::Archive::Symbol S); template <class ELFT> void addLazyObject(StringRef Name, LazyObjFile &Obj); Symbol *addBitcode(StringRef Name, uint8_t Binding, uint8_t StOther, - uint8_t Type, bool CanOmitFromDynSym, BitcodeFile *File); + uint8_t Type, bool CanOmitFromDynSym, BitcodeFile &File); Symbol *addCommon(StringRef Name, uint64_t Size, uint32_t Alignment, uint8_t Binding, uint8_t StOther, uint8_t Type, - InputFile *File); + InputFile &File); std::pair<Symbol *, bool> insert(StringRef Name); std::pair<Symbol *, bool> insert(StringRef Name, uint8_t Type, diff --git a/ELF/Symbols.cpp b/ELF/Symbols.cpp index ab42fcd51a81..13a91aab80bb 100644 --- a/ELF/Symbols.cpp +++ b/ELF/Symbols.cpp @@ -116,12 +116,6 @@ static uint64_t getSymVA(const Symbol &Sym, int64_t &Addend) { llvm_unreachable("invalid symbol kind"); } -// Returns true if this is a weak undefined symbol. -bool Symbol::isUndefWeak() const { - // See comment on Lazy in Symbols.h for the details. - return isWeak() && (isUndefined() || isLazy()); -} - uint64_t Symbol::getVA(int64_t Addend) const { uint64_t OutVA = getSymVA(*this, Addend); return OutVA + Addend; @@ -224,21 +218,21 @@ InputFile *Lazy::fetch() { return cast<LazyObject>(this)->fetch(); } -ArchiveFile *LazyArchive::getFile() { return cast<ArchiveFile>(File); } +ArchiveFile &LazyArchive::getFile() { return *cast<ArchiveFile>(File); } InputFile *LazyArchive::fetch() { - std::pair<MemoryBufferRef, uint64_t> MBInfo = getFile()->getMember(&Sym); + std::pair<MemoryBufferRef, uint64_t> MBInfo = getFile().getMember(&Sym); // getMember returns an empty buffer if the member was already // read from the library. if (MBInfo.first.getBuffer().empty()) return nullptr; - return createObjectFile(MBInfo.first, getFile()->getName(), MBInfo.second); + return createObjectFile(MBInfo.first, getFile().getName(), MBInfo.second); } -LazyObjFile *LazyObject::getFile() { return cast<LazyObjFile>(File); } +LazyObjFile &LazyObject::getFile() { return *cast<LazyObjFile>(File); } -InputFile *LazyObject::fetch() { return getFile()->fetch(); } +InputFile *LazyObject::fetch() { return getFile().fetch(); } uint8_t Symbol::computeBinding() const { if (Config->Relocatable) diff --git a/ELF/Symbols.h b/ELF/Symbols.h index f4bb245f955d..9b7207383345 100644 --- a/ELF/Symbols.h +++ b/ELF/Symbols.h @@ -102,7 +102,10 @@ public: // True is this is an undefined weak symbol. This only works once // all input files have been added. - bool isUndefWeak() const; + bool isUndefWeak() const { + // See comment on Lazy the details. + return isWeak() && (isUndefined() || isLazy()); + } StringRef getName() const { return Name; } uint8_t getVisibility() const { return StOther & 0x3; } @@ -208,14 +211,14 @@ class SharedSymbol : public Symbol { public: static bool classof(const Symbol *S) { return S->kind() == SharedKind; } - SharedSymbol(InputFile *File, StringRef Name, uint8_t Binding, + SharedSymbol(InputFile &File, StringRef Name, uint8_t Binding, uint8_t StOther, uint8_t Type, uint64_t Value, uint64_t Size, uint32_t Alignment, uint32_t VerdefIndex) - : Symbol(SharedKind, File, Name, Binding, StOther, Type), Value(Value), + : Symbol(SharedKind, &File, Name, Binding, StOther, Type), Value(Value), Size(Size), VerdefIndex(VerdefIndex), Alignment(Alignment) { // GNU ifunc is a mechanism to allow user-supplied functions to // resolve PLT slot values at load-time. This is contrary to the - // regualr symbol resolution scheme in which symbols are resolved just + // regular symbol resolution scheme in which symbols are resolved just // by name. Using this hook, you can program how symbols are solved // for you program. For example, you can make "memcpy" to be resolved // to a SSE-enabled version of memcpy only when a machine running the @@ -233,8 +236,8 @@ public: this->Type = llvm::ELF::STT_FUNC; } - template <class ELFT> SharedFile<ELFT> *getFile() const { - return cast<SharedFile<ELFT>>(File); + template <class ELFT> SharedFile<ELFT> &getFile() const { + return *cast<SharedFile<ELFT>>(File); } // If not null, there is a copy relocation to this section. @@ -267,8 +270,8 @@ public: InputFile *fetch(); protected: - Lazy(Kind K, InputFile *File, StringRef Name, uint8_t Type) - : Symbol(K, File, Name, llvm::ELF::STB_GLOBAL, llvm::ELF::STV_DEFAULT, + Lazy(Kind K, InputFile &File, StringRef Name, uint8_t Type) + : Symbol(K, &File, Name, llvm::ELF::STB_GLOBAL, llvm::ELF::STV_DEFAULT, Type) {} }; @@ -278,13 +281,13 @@ protected: // symbol. class LazyArchive : public Lazy { public: - LazyArchive(InputFile *File, const llvm::object::Archive::Symbol S, + LazyArchive(InputFile &File, const llvm::object::Archive::Symbol S, uint8_t Type) : Lazy(LazyArchiveKind, File, S.getName(), Type), Sym(S) {} static bool classof(const Symbol *S) { return S->kind() == LazyArchiveKind; } - ArchiveFile *getFile(); + ArchiveFile &getFile(); InputFile *fetch(); private: @@ -295,12 +298,12 @@ private: // --start-lib and --end-lib options. class LazyObject : public Lazy { public: - LazyObject(InputFile *File, StringRef Name, uint8_t Type) + LazyObject(InputFile &File, StringRef Name, uint8_t Type) : Lazy(LazyObjectKind, File, Name, Type) {} static bool classof(const Symbol *S) { return S->kind() == LazyObjectKind; } - LazyObjFile *getFile(); + LazyObjFile &getFile(); InputFile *fetch(); }; diff --git a/ELF/SyntheticSections.cpp b/ELF/SyntheticSections.cpp index b408e653dfa0..a5e291b79a4d 100644 --- a/ELF/SyntheticSections.cpp +++ b/ELF/SyntheticSections.cpp @@ -81,17 +81,9 @@ static ArrayRef<uint8_t> getVersion() { // With this feature, you can identify LLD-generated binaries easily // by "readelf --string-dump .comment <file>". // The returned object is a mergeable string section. -template <class ELFT> MergeInputSection *elf::createCommentSection() { - typename ELFT::Shdr Hdr = {}; - Hdr.sh_flags = SHF_MERGE | SHF_STRINGS; - Hdr.sh_type = SHT_PROGBITS; - Hdr.sh_entsize = 1; - Hdr.sh_addralign = 1; - - auto *Ret = - make<MergeInputSection>((ObjFile<ELFT> *)nullptr, &Hdr, ".comment"); - Ret->Data = getVersion(); - return Ret; +MergeInputSection *elf::createCommentSection() { + return make<MergeInputSection>(SHF_MERGE | SHF_STRINGS, SHT_PROGBITS, 1, + getVersion(), ".comment"); } // .MIPS.abiflags section. @@ -268,16 +260,16 @@ InputSection *elf::createInterpSection() { StringRef S = Saver.save(Config->DynamicLinker); ArrayRef<uint8_t> Contents = {(const uint8_t *)S.data(), S.size() + 1}; - auto *Sec = - make<InputSection>(SHF_ALLOC, SHT_PROGBITS, 1, Contents, ".interp"); + auto *Sec = make<InputSection>(nullptr, SHF_ALLOC, SHT_PROGBITS, 1, Contents, + ".interp"); Sec->Live = true; return Sec; } Symbol *elf::addSyntheticLocal(StringRef Name, uint8_t Type, uint64_t Value, - uint64_t Size, InputSectionBase *Section) { - auto *S = make<Defined>(Section->File, Name, STB_LOCAL, STV_DEFAULT, Type, - Value, Size, Section); + uint64_t Size, InputSectionBase &Section) { + auto *S = make<Defined>(Section.File, Name, STB_LOCAL, STV_DEFAULT, Type, + Value, Size, &Section); if (InX::SymTab) InX::SymTab->addSymbol(S); return S; @@ -1893,10 +1885,10 @@ size_t PltSection::getSize() const { void PltSection::addSymbols() { // The PLT may have symbols defined for the Header, the IPLT has no header if (HeaderSize != 0) - Target->addPltHeaderSymbols(this); + Target->addPltHeaderSymbols(*this); size_t Off = HeaderSize; for (size_t I = 0; I < Entries.size(); ++I) { - Target->addPltSymbols(this, Off); + Target->addPltSymbols(*this, Off); Off += Target->PltEntrySize; } } @@ -2299,8 +2291,8 @@ VersionNeedSection<ELFT>::VersionNeedSection() template <class ELFT> void VersionNeedSection<ELFT>::addSymbol(SharedSymbol *SS) { - SharedFile<ELFT> *File = SS->getFile<ELFT>(); - const typename ELFT::Verdef *Ver = File->Verdefs[SS->VerdefIndex]; + SharedFile<ELFT> &File = SS->getFile<ELFT>(); + const typename ELFT::Verdef *Ver = File.Verdefs[SS->VerdefIndex]; if (!Ver) { SS->VersionId = VER_NDX_GLOBAL; return; @@ -2309,14 +2301,14 @@ void VersionNeedSection<ELFT>::addSymbol(SharedSymbol *SS) { // If we don't already know that we need an Elf_Verneed for this DSO, prepare // to create one by adding it to our needed list and creating a dynstr entry // for the soname. - if (File->VerdefMap.empty()) - Needed.push_back({File, InX::DynStrTab->addString(File->SoName)}); - typename SharedFile<ELFT>::NeededVer &NV = File->VerdefMap[Ver]; + if (File.VerdefMap.empty()) + Needed.push_back({&File, InX::DynStrTab->addString(File.SoName)}); + typename SharedFile<ELFT>::NeededVer &NV = File.VerdefMap[Ver]; // If we don't already know that we need an Elf_Vernaux for this Elf_Verdef, // prepare to create one by allocating a version identifier and creating a // dynstr entry for the version name. if (NV.Index == 0) { - NV.StrTab = InX::DynStrTab->addString(File->getStringTable().data() + + NV.StrTab = InX::DynStrTab->addString(File.getStringTable().data() + Ver->getAux()->vda_name); NV.Index = NextIndex++; } @@ -2561,31 +2553,25 @@ ARMExidxSentinelSection::ARMExidxSentinelSection() // The sentinel must have the PREL31 value of an address higher than any // address described by any other table entry. void ARMExidxSentinelSection::writeTo(uint8_t *Buf) { - // The Sections are sorted in order of ascending PREL31 address with the - // sentinel last. We need to find the InputSection that precedes the - // sentinel. - OutputSection *C = getParent(); - InputSection *Highest = nullptr; - unsigned Skip = 1; - for (const BaseCommand *Base : llvm::reverse(C->SectionCommands)) { - if (!isa<InputSectionDescription>(Base)) - continue; - auto L = cast<InputSectionDescription>(Base); - if (Skip >= L->Sections.size()) { - Skip -= L->Sections.size(); - continue; - } - Highest = L->Sections[L->Sections.size() - Skip - 1]; - break; - } assert(Highest); - InputSection *LS = Highest->getLinkOrderDep(); - uint64_t S = LS->getParent()->Addr + LS->getOffset(LS->getSize()); + uint64_t S = + Highest->getParent()->Addr + Highest->getOffset(Highest->getSize()); uint64_t P = getVA(); Target->relocateOne(Buf, R_ARM_PREL31, S - P); write32le(Buf + 4, 1); } +// The sentinel has to be removed if there are no other .ARM.exidx entries. +bool ARMExidxSentinelSection::empty() const { + OutputSection *OS = getParent(); + for (auto *B : OS->SectionCommands) + if (auto *ISD = dyn_cast<InputSectionDescription>(B)) + for (auto *S : ISD->Sections) + if (!isa<ARMExidxSentinelSection>(S)) + return false; + return true; +} + ThunkSection::ThunkSection(OutputSection *OS, uint64_t Off) : SyntheticSection(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS, Config->Wordsize, ".text.thunk") { @@ -2655,11 +2641,6 @@ template void PltSection::addEntry<ELF32BE>(Symbol &Sym); template void PltSection::addEntry<ELF64LE>(Symbol &Sym); template void PltSection::addEntry<ELF64BE>(Symbol &Sym); -template MergeInputSection *elf::createCommentSection<ELF32LE>(); -template MergeInputSection *elf::createCommentSection<ELF32BE>(); -template MergeInputSection *elf::createCommentSection<ELF64LE>(); -template MergeInputSection *elf::createCommentSection<ELF64BE>(); - template class elf::MipsAbiFlagsSection<ELF32LE>; template class elf::MipsAbiFlagsSection<ELF32BE>; template class elf::MipsAbiFlagsSection<ELF64LE>; diff --git a/ELF/SyntheticSections.h b/ELF/SyntheticSections.h index 5aaf479f3e35..a990590513bb 100644 --- a/ELF/SyntheticSections.h +++ b/ELF/SyntheticSections.h @@ -36,7 +36,7 @@ class SyntheticSection : public InputSection { public: SyntheticSection(uint64_t Flags, uint32_t Type, uint32_t Alignment, StringRef Name) - : InputSection(Flags, Type, Alignment, {}, Name, + : InputSection(nullptr, Flags, Type, Alignment, {}, Name, InputSectionBase::Synthetic) { this->Live = true; } @@ -785,6 +785,9 @@ public: ARMExidxSentinelSection(); size_t getSize() const override { return 8; } void writeTo(uint8_t *Buf) override; + bool empty() const override; + + InputSection *Highest = 0; }; // A container for one or more linker generated thunks. Instances of these @@ -809,12 +812,12 @@ private: }; InputSection *createInterpSection(); -template <class ELFT> MergeInputSection *createCommentSection(); +MergeInputSection *createCommentSection(); void decompressSections(); void mergeSections(); Symbol *addSyntheticLocal(StringRef Name, uint8_t Type, uint64_t Value, - uint64_t Size, InputSectionBase *Section); + uint64_t Size, InputSectionBase &Section); // Linker generated sections which can be used as inputs. struct InX { diff --git a/ELF/Target.cpp b/ELF/Target.cpp index ddd408906d14..b528fd583c1a 100644 --- a/ELF/Target.cpp +++ b/ELF/Target.cpp @@ -89,7 +89,7 @@ TargetInfo *elf::getTarget() { template <class ELFT> static std::string getErrorLoc(const uint8_t *Loc) { for (InputSectionBase *D : InputSections) { - auto *IS = dyn_cast_or_null<InputSection>(D); + auto *IS = dyn_cast<InputSection>(D); if (!IS || !IS->getParent()) continue; diff --git a/ELF/Target.h b/ELF/Target.h index 2902dbc99149..1f58adba1817 100644 --- a/ELF/Target.h +++ b/ELF/Target.h @@ -40,8 +40,8 @@ public: virtual void writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const {} - virtual void addPltHeaderSymbols(InputSectionBase *IS) const {} - virtual void addPltSymbols(InputSectionBase *IS, uint64_t Off) const {} + virtual void addPltHeaderSymbols(InputSection &IS) const {} + virtual void addPltSymbols(InputSection &IS, uint64_t Off) const {} // Returns true if a relocation only uses the low bits of a value such that // all those bits are in in the same page. For example, if the relocation diff --git a/ELF/Thunks.cpp b/ELF/Thunks.cpp index 91ca3b9b5bc2..b0bbf6da705a 100644 --- a/ELF/Thunks.cpp +++ b/ELF/Thunks.cpp @@ -164,9 +164,9 @@ void AArch64ABSLongThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const { void AArch64ABSLongThunk::addSymbols(ThunkSection &IS) { ThunkSym = addSyntheticLocal( Saver.save("__AArch64AbsLongThunk_" + Destination.getName()), STT_FUNC, - Offset, size(), &IS); - addSyntheticLocal("$x", STT_NOTYPE, Offset, 0, &IS); - addSyntheticLocal("$d", STT_NOTYPE, Offset + 8, 0, &IS); + Offset, size(), IS); + addSyntheticLocal("$x", STT_NOTYPE, Offset, 0, IS); + addSyntheticLocal("$d", STT_NOTYPE, Offset + 8, 0, IS); } // This Thunk has a maximum range of 4Gb, this is sufficient for all programs @@ -192,8 +192,8 @@ void AArch64ADRPThunk::addSymbols(ThunkSection &IS) { ThunkSym = addSyntheticLocal( Saver.save("__AArch64ADRPThunk_" + Destination.getName()), STT_FUNC, - Offset, size(), &IS); - addSyntheticLocal("$x", STT_NOTYPE, Offset, 0, &IS); + Offset, size(), IS); + addSyntheticLocal("$x", STT_NOTYPE, Offset, 0, IS); } // ARM Target Thunks @@ -217,8 +217,8 @@ void ARMV7ABSLongThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const { void ARMV7ABSLongThunk::addSymbols(ThunkSection &IS) { ThunkSym = addSyntheticLocal( Saver.save("__ARMv7ABSLongThunk_" + Destination.getName()), STT_FUNC, - Offset, size(), &IS); - addSyntheticLocal("$a", STT_NOTYPE, Offset, 0, &IS); + Offset, size(), IS); + addSyntheticLocal("$a", STT_NOTYPE, Offset, 0, IS); } bool ARMV7ABSLongThunk::isCompatibleWith(RelType Type) const { @@ -241,8 +241,8 @@ void ThumbV7ABSLongThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const { void ThumbV7ABSLongThunk::addSymbols(ThunkSection &IS) { ThunkSym = addSyntheticLocal( Saver.save("__Thumbv7ABSLongThunk_" + Destination.getName()), STT_FUNC, - Offset | 0x1, size(), &IS); - addSyntheticLocal("$t", STT_NOTYPE, Offset, 0, &IS); + Offset | 0x1, size(), IS); + addSyntheticLocal("$t", STT_NOTYPE, Offset, 0, IS); } bool ThumbV7ABSLongThunk::isCompatibleWith(RelType Type) const { @@ -268,8 +268,8 @@ void ARMV7PILongThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const { void ARMV7PILongThunk::addSymbols(ThunkSection &IS) { ThunkSym = addSyntheticLocal( Saver.save("__ARMV7PILongThunk_" + Destination.getName()), STT_FUNC, - Offset, size(), &IS); - addSyntheticLocal("$a", STT_NOTYPE, Offset, 0, &IS); + Offset, size(), IS); + addSyntheticLocal("$a", STT_NOTYPE, Offset, 0, IS); } bool ARMV7PILongThunk::isCompatibleWith(RelType Type) const { @@ -295,8 +295,8 @@ void ThumbV7PILongThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const { void ThumbV7PILongThunk::addSymbols(ThunkSection &IS) { ThunkSym = addSyntheticLocal( Saver.save("__ThumbV7PILongThunk_" + Destination.getName()), STT_FUNC, - Offset | 0x1, size(), &IS); - addSyntheticLocal("$t", STT_NOTYPE, Offset, 0, &IS); + Offset | 0x1, size(), IS); + addSyntheticLocal("$t", STT_NOTYPE, Offset, 0, IS); } bool ThumbV7PILongThunk::isCompatibleWith(RelType Type) const { @@ -318,7 +318,7 @@ void MipsThunk::writeTo(uint8_t *Buf, ThunkSection &) const { void MipsThunk::addSymbols(ThunkSection &IS) { ThunkSym = addSyntheticLocal(Saver.save("__LA25Thunk_" + Destination.getName()), - STT_FUNC, Offset, size(), &IS); + STT_FUNC, Offset, size(), IS); } InputSection *MipsThunk::getTargetInputSection() const { @@ -342,7 +342,7 @@ void MicroMipsThunk::writeTo(uint8_t *Buf, ThunkSection &) const { void MicroMipsThunk::addSymbols(ThunkSection &IS) { ThunkSym = addSyntheticLocal(Saver.save("__microLA25Thunk_" + Destination.getName()), - STT_FUNC, Offset, size(), &IS); + STT_FUNC, Offset, size(), IS); ThunkSym->StOther |= STO_MIPS_MICROMIPS; } @@ -367,7 +367,7 @@ void MicroMipsR6Thunk::writeTo(uint8_t *Buf, ThunkSection &) const { void MicroMipsR6Thunk::addSymbols(ThunkSection &IS) { ThunkSym = addSyntheticLocal(Saver.save("__microLA25Thunk_" + Destination.getName()), - STT_FUNC, Offset, size(), &IS); + STT_FUNC, Offset, size(), IS); ThunkSym->StOther |= STO_MIPS_MICROMIPS; } diff --git a/ELF/Writer.cpp b/ELF/Writer.cpp index c7a3cae49ae6..15f382104756 100644 --- a/ELF/Writer.cpp +++ b/ELF/Writer.cpp @@ -54,7 +54,6 @@ private: void resolveShfLinkOrder(); void sortInputSections(); void finalizeSections(); - void addPredefinedSections(); void setReservedSymbolSections(); std::vector<PhdrEntry *> createPhdrs(); @@ -157,35 +156,34 @@ template <class ELFT> static void combineEhFrameSections() { V.erase(std::remove(V.begin(), V.end(), nullptr), V.end()); } -template <class ELFT> static Defined *addOptionalRegular(StringRef Name, SectionBase *Sec, uint64_t Val, uint8_t StOther = STV_HIDDEN, uint8_t Binding = STB_GLOBAL) { Symbol *S = Symtab->find(Name); if (!S || S->isDefined()) return nullptr; - Symbol *Sym = Symtab->addRegular<ELFT>(Name, StOther, STT_NOTYPE, Val, - /*Size=*/0, Binding, Sec, - /*File=*/nullptr); + Symbol *Sym = Symtab->addRegular(Name, StOther, STT_NOTYPE, Val, + /*Size=*/0, Binding, Sec, + /*File=*/nullptr); return cast<Defined>(Sym); } // The linker is expected to define some symbols depending on // the linking result. This function defines such symbols. -template <class ELFT> void elf::addReservedSymbols() { +void elf::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->addAbsolute<ELFT>("_gp", STV_HIDDEN, STB_GLOBAL); + ElfSym::MipsGp = Symtab->addAbsolute("_gp", STV_HIDDEN, STB_GLOBAL); // On MIPS O32 ABI, _gp_disp is a magic symbol designates offset between // start of function and 'gp' pointer into GOT. if (Symtab->find("_gp_disp")) ElfSym::MipsGpDisp = - Symtab->addAbsolute<ELFT>("_gp_disp", STV_HIDDEN, STB_GLOBAL); + Symtab->addAbsolute("_gp_disp", STV_HIDDEN, STB_GLOBAL); // 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 @@ -193,10 +191,10 @@ template <class ELFT> void elf::addReservedSymbols() { // https://sourceware.org/ml/binutils/2004-12/msg00094.html if (Symtab->find("__gnu_local_gp")) ElfSym::MipsLocalGp = - Symtab->addAbsolute<ELFT>("__gnu_local_gp", STV_HIDDEN, STB_GLOBAL); + Symtab->addAbsolute("__gnu_local_gp", STV_HIDDEN, STB_GLOBAL); } - ElfSym::GlobalOffsetTable = addOptionalRegular<ELFT>( + ElfSym::GlobalOffsetTable = addOptionalRegular( "_GLOBAL_OFFSET_TABLE_", Out::ElfHeader, Target->GotBaseSymOff); // __ehdr_start is the location of ELF file headers. Note that we define @@ -210,14 +208,14 @@ template <class ELFT> void elf::addReservedSymbols() { // different in different DSOs, so we chose the start address of the DSO. for (const char *Name : {"__ehdr_start", "__executable_start", "__dso_handle"}) - addOptionalRegular<ELFT>(Name, Out::ElfHeader, 0, STV_HIDDEN); + addOptionalRegular(Name, Out::ElfHeader, 0, STV_HIDDEN); // If linker script do layout we do not need to create any standart symbols. if (Script->HasSectionsCommand) return; auto Add = [](StringRef S, int64_t Pos) { - return addOptionalRegular<ELFT>(S, Out::ElfHeader, Pos, STV_DEFAULT); + return addOptionalRegular(S, Out::ElfHeader, Pos, STV_DEFAULT); }; ElfSym::Bss = Add("__bss_start", 0); @@ -390,6 +388,11 @@ template <class ELFT> static void createSyntheticSections() { Add(InX::ShStrTab); if (InX::StrTab) Add(InX::StrTab); + + if (Config->EMachine == EM_ARM && !Config->Relocatable) + // Add a sentinel to terminate .ARM.exidx. It helps an unwinder + // to find the exact address range of the last entry. + Add(make<ARMExidxSentinelSection>()); } // The main function of the writer. @@ -830,10 +833,10 @@ template <class ELFT> void Writer<ELFT>::addRelIpltSymbols() { if (!Config->Static) return; StringRef S = Config->IsRela ? "__rela_iplt_start" : "__rel_iplt_start"; - addOptionalRegular<ELFT>(S, InX::RelaIplt, 0, STV_HIDDEN, STB_WEAK); + addOptionalRegular(S, InX::RelaIplt, 0, STV_HIDDEN, STB_WEAK); S = Config->IsRela ? "__rela_iplt_end" : "__rel_iplt_end"; - addOptionalRegular<ELFT>(S, InX::RelaIplt, -1, STV_HIDDEN, STB_WEAK); + addOptionalRegular(S, InX::RelaIplt, -1, STV_HIDDEN, STB_WEAK); } template <class ELFT> @@ -1145,10 +1148,10 @@ template <class ELFT> void Writer<ELFT>::sortSections() { } static bool compareByFilePosition(InputSection *A, InputSection *B) { - // Synthetic doesn't have link order dependecy, stable_sort will keep it last + // Synthetic, i. e. a sentinel section, should go last. if (A->kind() == InputSectionBase::Synthetic || B->kind() == InputSectionBase::Synthetic) - return false; + return A->kind() != InputSectionBase::Synthetic; InputSection *LA = A->getLinkOrderDep(); InputSection *LB = B->getLinkOrderDep(); OutputSection *AOut = LA->getParent(); @@ -1231,23 +1234,37 @@ template <class ELFT> void Writer<ELFT>::resolveShfLinkOrder() { } std::stable_sort(Sections.begin(), Sections.end(), compareByFilePosition); - if (Config->MergeArmExidx && !Config->Relocatable && - Config->EMachine == EM_ARM && Sec->Type == SHT_ARM_EXIDX) { - // The EHABI for the Arm Architecture permits consecutive identical - // table entries to be merged. We use a simple implementation that - // removes a .ARM.exidx Input Section if it can be merged into the - // previous one. This does not require any rewriting of InputSection - // contents but misses opportunities for fine grained deduplication where - // only a subset of the InputSection contents can be merged. - int Cur = 1; - int Prev = 0; - int N = Sections.size(); - while (Cur < N) { - if (isDuplicateArmExidxSec(Sections[Prev], Sections[Cur])) - Sections[Cur] = nullptr; - else - Prev = Cur; - ++Cur; + if (!Config->Relocatable && Config->EMachine == EM_ARM && + Sec->Type == SHT_ARM_EXIDX) { + + if (!Sections.empty() && isa<ARMExidxSentinelSection>(Sections.back())) { + assert(Sections.size() >= 2 && + "We should create a sentinel section only if there are " + "alive regular exidx sections."); + // The last executable section is required to fill the sentinel. + // Remember it here so that we don't have to find it again. + auto *Sentinel = cast<ARMExidxSentinelSection>(Sections.back()); + Sentinel->Highest = Sections[Sections.size() - 2]->getLinkOrderDep(); + } + + if (Config->MergeArmExidx) { + // The EHABI for the Arm Architecture permits consecutive identical + // table entries to be merged. We use a simple implementation that + // removes a .ARM.exidx Input Section if it can be merged into the + // previous one. This does not require any rewriting of InputSection + // contents but misses opportunities for fine grained deduplication + // where only a subset of the InputSection contents can be merged. + int Cur = 1; + int Prev = 0; + // The last one is a sentinel entry which should not be removed. + int N = Sections.size() - 1; + while (Cur < N) { + if (isDuplicateArmExidxSec(Sections[Prev], Sections[Cur])) + Sections[Cur] = nullptr; + else + Prev = Cur; + ++Cur; + } } } @@ -1367,9 +1384,9 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() { // Even the author of gold doesn't remember why gold behaves that way. // https://sourceware.org/ml/binutils/2002-03/msg00360.html if (InX::DynSymTab) - Symtab->addRegular<ELFT>("_DYNAMIC", STV_HIDDEN, STT_NOTYPE, 0 /*Value*/, - /*Size=*/0, STB_WEAK, InX::Dynamic, - /*File=*/nullptr); + Symtab->addRegular("_DYNAMIC", STV_HIDDEN, STT_NOTYPE, 0 /*Value*/, + /*Size=*/0, STB_WEAK, InX::Dynamic, + /*File=*/nullptr); // Define __rel[a]_iplt_{start,end} symbols if needed. addRelIpltSymbols(); @@ -1413,7 +1430,6 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() { if (errorCount()) return; - addPredefinedSections(); removeUnusedSyntheticSections(); sortSections(); @@ -1510,17 +1526,6 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() { [](SyntheticSection *SS) { SS->postThunkContents(); }); } -template <class ELFT> void Writer<ELFT>::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. - OutputSection *Cmd = findSection(".ARM.exidx"); - if (!Cmd || !Cmd->Live || Config->Relocatable) - return; - - auto *Sentinel = make<ARMExidxSentinelSection>(); - Cmd->addSection(Sentinel); -} - // The linker is expected to define SECNAME_start and SECNAME_end // symbols for a few sections. This function defines them. template <class ELFT> void Writer<ELFT>::addStartEndSymbols() { @@ -1528,13 +1533,13 @@ template <class ELFT> void Writer<ELFT>::addStartEndSymbols() { // 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<ELFT>(Start, OS, 0); - addOptionalRegular<ELFT>(End, OS, -1); + addOptionalRegular(Start, OS, 0); + addOptionalRegular(End, OS, -1); } else { if (Config->Pic) OS = Out::ElfHeader; - addOptionalRegular<ELFT>(Start, OS, 0); - addOptionalRegular<ELFT>(End, OS, 0); + addOptionalRegular(Start, OS, 0); + addOptionalRegular(End, OS, 0); } }; @@ -1556,8 +1561,8 @@ void Writer<ELFT>::addStartStopSymbols(OutputSection *Sec) { StringRef S = Sec->Name; if (!isValidCIdentifier(S)) return; - addOptionalRegular<ELFT>(Saver.save("__start_" + S), Sec, 0, STV_DEFAULT); - addOptionalRegular<ELFT>(Saver.save("__stop_" + S), Sec, -1, STV_DEFAULT); + addOptionalRegular(Saver.save("__start_" + S), Sec, 0, STV_DEFAULT); + addOptionalRegular(Saver.save("__stop_" + S), Sec, -1, STV_DEFAULT); } static bool needsPtLoad(OutputSection *Sec) { @@ -2057,8 +2062,3 @@ template void elf::writeResult<ELF32LE>(); template void elf::writeResult<ELF32BE>(); template void elf::writeResult<ELF64LE>(); template void elf::writeResult<ELF64BE>(); - -template void elf::addReservedSymbols<ELF32LE>(); -template void elf::addReservedSymbols<ELF32BE>(); -template void elf::addReservedSymbols<ELF64LE>(); -template void elf::addReservedSymbols<ELF64BE>(); diff --git a/ELF/Writer.h b/ELF/Writer.h index 32d3c23047dd..d247068bab23 100644 --- a/ELF/Writer.h +++ b/ELF/Writer.h @@ -46,7 +46,7 @@ struct PhdrEntry { bool HasLMA = false; }; -template <class ELFT> void addReservedSymbols(); +void addReservedSymbols(); llvm::StringRef getOutputSectionName(InputSectionBase *S); template <class ELFT> uint32_t calcMipsEFlags(); diff --git a/README.md b/README.md index 34372a4c3ad5..3b8cd7a14948 100644 --- a/README.md +++ b/README.md @@ -16,4 +16,4 @@ same tests, we create a collection of self contained programs. It is hosted at https://s3-us-west-2.amazonaws.com/linker-tests/lld-speed-test.tar.xz -The current sha256 is 69cff27cf63304a3f766e72dc9010407eced5c60635254a3c31496e1183ef9e1. +The current sha256 is 10eec685463d5a8bbf08d77f4ca96282161d396c65bd97dc99dbde644a31610f. diff --git a/test/COFF/export-armnt.yaml b/test/COFF/export-armnt.yaml index 461d5a033fe2..367dabf70d88 100644 --- a/test/COFF/export-armnt.yaml +++ b/test/COFF/export-armnt.yaml @@ -2,16 +2,17 @@ # RUN: yaml2obj < %s > %t.obj # -# RUN: lld-link /out:%t.dll /dll %t.obj /export:exportfn1 /export:exportfn2 +# RUN: lld-link /out:%t.dll /dll %t.obj /export:exportfn1 /export:exportfn2 /export:exportdata,data # RUN: llvm-objdump -p %t.dll | FileCheck %s # CHECK: Export Table: # CHECK: DLL name: export-armnt.yaml.tmp.dll # CHECK: Ordinal RVA Name # CHECK-NEXT: 0 0 -# CHECK-NEXT: 1 0x1005 exportfn1 -# CHECK-NEXT: 2 0x1009 exportfn2 -# CHECK-NEXT: 3 0x1009 exportfn3 +# CHECK-NEXT: 1 0x1000 exportdata +# CHECK-NEXT: 2 0x2005 exportfn1 +# CHECK-NEXT: 3 0x2009 exportfn2 +# CHECK-NEXT: 4 0x2009 exportfn3 --- !COFF header: @@ -22,6 +23,10 @@ sections: Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] Alignment: 4 SectionData: 704700bf704700bf704700bf + - Name: .data + Characteristics: [ IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ] + Alignment: 4 + SectionData: 00000000 - Name: .drectve Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ] Alignment: 1 @@ -39,6 +44,18 @@ symbols: NumberOfLinenumbers: 0 CheckSum: 0 Number: 0 + - Name: .data + Value: 0 + SectionNumber: 2 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 4 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 0 - Name: _DllMainCRTStartup Value: 0 SectionNumber: 1 @@ -63,6 +80,12 @@ symbols: SimpleType: IMAGE_SYM_TYPE_NULL ComplexType: IMAGE_SYM_DTYPE_NULL StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: exportdata + Value: 0 + SectionNumber: 2 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_EXTERNAL - Name: '?mangled@@YAHXZ' Value: 8 SectionNumber: 1 diff --git a/test/COFF/lto.ll b/test/COFF/lto.ll index b8f8d7063343..587ca5ddcf13 100644 --- a/test/COFF/lto.ll +++ b/test/COFF/lto.ll @@ -82,7 +82,21 @@ ; TEXT-10: Disassembly of section .text: ; TEXT-10-NEXT: .text: ; TEXT-10-NEXT: retq -; TEXT-10-NEXT: nopw %cs:(%rax,%rax) +; TEXT-10-NEXT: nop +; TEXT-10-NEXT: nop +; TEXT-10-NEXT: nop +; TEXT-10-NEXT: nop +; TEXT-10-NEXT: nop +; TEXT-10-NEXT: nop +; TEXT-10-NEXT: nop +; TEXT-10-NEXT: nop +; TEXT-10-NEXT: nop +; TEXT-10-NEXT: nop +; TEXT-10-NEXT: nop +; TEXT-10-NEXT: nop +; TEXT-10-NEXT: nop +; TEXT-10-NEXT: nop +; TEXT-10-NEXT: nop ; TEXT-10-NEXT: retq ; TEXT-10-NEXT: int3 ; TEXT-10-NEXT: int3 diff --git a/test/ELF/Inputs/znotext-plt-relocations.s b/test/ELF/Inputs/znotext-plt-relocations.s new file mode 100644 index 000000000000..f269cf906619 --- /dev/null +++ b/test/ELF/Inputs/znotext-plt-relocations.s @@ -0,0 +1,10 @@ +.text +.global atexit +.type atexit,@function +atexit: + nop + +.global foo +.type foo,@function +foo: + nop diff --git a/test/ELF/arm-exidx-dedup-and-sentinel.s b/test/ELF/arm-exidx-dedup-and-sentinel.s new file mode 100644 index 000000000000..84ef318a3850 --- /dev/null +++ b/test/ELF/arm-exidx-dedup-and-sentinel.s @@ -0,0 +1,29 @@ +// REQUIRES: arm +// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t.o +// RUN: ld.lld %t.o -shared -o %t.so --section-start .text=0x2000 --section-start .ARM.exidx=0x1000 +// RUN: llvm-objdump -s -triple=armv7a-none-linux-gnueabi %t.so | FileCheck %s + + .syntax unified + + .section .text.foo, "ax", %progbits + .globl foo +foo: + .fnstart + bx lr + .cantunwind + .fnend + + .section .text.bar, "ax", %progbits + .globl bar +bar: + .fnstart + bx lr + .cantunwind + .fnend + +// CHECK: Contents of section .ARM.exidx: +// 1000 + 1000 = 0x2000 = foo +// The entry for bar is the same as previous and is eliminated. +// The sentinel entry should be preserved. +// 1008 + 1000 = 0x2008 = bar + sizeof(bar) +// CHECK-NEXT: 1000 00100000 01000000 00100000 01000000 diff --git a/test/ELF/i386-got-value.s b/test/ELF/i386-got-value.s index f42555b79272..8803fcffb312 100644 --- a/test/ELF/i386-got-value.s +++ b/test/ELF/i386-got-value.s @@ -1,10 +1,10 @@ # RUN: llvm-mc %s -o %t.o -filetype=obj -triple=i386-pc-linux # RUN: ld.lld %t.o -o %t.so -shared -# RUN: llvm-readobj --relocations --symbols --sections --section-data %t.so | FileCheck %s +# RUN: llvm-readobj --relocations --sections --section-data %t.so | FileCheck %s -# Check that the value of a preemptible symbol is written to the got -# entry when using Elf_Rel. It is not clear why that is required, but -# freebsd i386 seems to depend on it. +# Check that the value of a preemptible symbol is not written to the +# got entry when using Elf_Rel. It is not needed since the dynamic +# linker will write the final value. # CHECK: Name: .got # CHECK-NEXT: Type: SHT_PROGBITS @@ -20,14 +20,11 @@ # CHECK-NEXT: AddressAlignment: # CHECK-NEXT: EntrySize: # CHECK-NEXT: SectionData ( -# CHECK-NEXT: 0000: 00200000 +# CHECK-NEXT: 0000: 00000000 # CHECK-NEXT: ) # CHECK: R_386_GLOB_DAT bar 0x0 -# CHECK: Name: bar -# CHECK-NEXT: Value: 0x2000 - movl bar@GOT(%eax), %eax .data diff --git a/test/ELF/i386-tls-initial-exec-local.s b/test/ELF/i386-tls-initial-exec-local.s new file mode 100644 index 000000000000..dd7de7b431e5 --- /dev/null +++ b/test/ELF/i386-tls-initial-exec-local.s @@ -0,0 +1,36 @@ +# REQUIRES: x86 +# RUN: llvm-mc %s -o %t.o -filetype=obj -triple=i386-pc-linux +# RUN: ld.lld %t.o -o %t.so -shared +# RUN: llvm-readobj --relocations --sections --section-data %t.so | FileCheck %s + +# Check initial exec access to a local symbol. + +# CHECK: Name: .got ( +# CHECK-NEXT: Type: +# CHECK-NEXT: Flags [ +# CHECK-NEXT: SHF_ALLOC +# CHECK-NEXT: SHF_WRITE +# CHECK-NEXT: ] +# CHECK-NEXT: Address: +# CHECK-NEXT: Offset: +# CHECK-NEXT: Size: 8 +# CHECK-NEXT: Link: +# CHECK-NEXT: Info: +# CHECK-NEXT: AddressAlignment: +# CHECK-NEXT: EntrySize: +# CHECK-NEXT: SectionData ( +# CHECK-NEXT: 0000: 00000000 04000000 +# CHECK-NEXT: ) + +# CHECK: R_386_TLS_TPOFF - 0x0 +# CHECK-NEXT: R_386_TLS_TPOFF - 0x0 + + movl bar1@GOTNTPOFF(%eax), %ecx + movl bar2@GOTNTPOFF(%eax), %eax + + .section .tdata,"awT",@progbits +bar1: + .long 42 + +bar2: + .long 42 diff --git a/test/ELF/linkerscript/arm-exidx-sentinel-and-assignment.s b/test/ELF/linkerscript/arm-exidx-sentinel-and-assignment.s index 8cee22f7fed2..332ed93a4605 100644 --- a/test/ELF/linkerscript/arm-exidx-sentinel-and-assignment.s +++ b/test/ELF/linkerscript/arm-exidx-sentinel-and-assignment.s @@ -8,6 +8,7 @@ ## was anything but an input section description. # RUN: ld.lld --no-merge-exidx-entries -T %t.script %t.o -shared -o %t.so # RUN: llvm-objdump -s -triple=armv7a-none-linux-gnueabi %t.so | FileCheck %s +# RUN: llvm-readobj -s -t %t.so | FileCheck %s --check-prefix=SYMBOL .syntax unified .text @@ -18,7 +19,23 @@ _start: bx lr .fnend -// CHECK: Contents of section .ARM.exidx: -// 1000 + 1000 = 0x2000 = _start -// 1008 + 0ffc = 0x2004 = _start + sizeof(_start) -// CHECK-NEXT: 1000 00100000 01000000 fc0f0000 01000000 +# CHECK: Contents of section .ARM.exidx: +# 1000 + 1000 = 0x2000 = _start +# 1008 + 0ffc = 0x2004 = _start + sizeof(_start) +# CHECK-NEXT: 1000 00100000 01000000 fc0f0000 01000000 + +# SYMBOL: Section { +# SYMBOL: Name: .ARM.exidx +# SYMBOL-NEXT: Type: SHT_ARM_EXIDX +# SYMBOL-NEXT: Flags [ +# SYMBOL-NEXT: SHF_ALLOC +# SYMBOL-NEXT: SHF_LINK_ORDER +# SYMBOL-NEXT: ] +# SYMBOL-NEXT: Address: 0x1000 +# SYMBOL-NEXT: Offset: +# SYMBOL-NEXT: Size: 16 + +# Symbol 'foo' is expected to point at the end of the section. +# SYMBOL: Symbol { +# SYMBOL: Name: foo +# SYMBOL-NEXT: Value: 0x1010 diff --git a/test/ELF/linkerscript/operators.s b/test/ELF/linkerscript/operators.s index 868805b34c2e..494fc08c0f99 100644 --- a/test/ELF/linkerscript/operators.s +++ b/test/ELF/linkerscript/operators.s @@ -1,6 +1,7 @@ # REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t # RUN: echo "SECTIONS { \ +# RUN: _start = .; \ # RUN: plus = 1 + 2 + 3; \ # RUN: minus = 5 - 1; \ # RUN: div = 6 / 2; \ @@ -26,6 +27,9 @@ # RUN: . = 0xfff0; \ # RUN: datasegmentalign = DATA_SEGMENT_ALIGN (0xffff, 0); \ # RUN: datasegmentalign2 = DATA_SEGMENT_ALIGN (0, 0); \ +# RUN: _end = .; \ +# RUN: minus_rel = _end - 0x10; \ +# RUN: minus_abs = _end - _start; \ # RUN: }" > %t.script # RUN: ld.lld %t --script %t.script -o %t2 # RUN: llvm-objdump -t %t2 | FileCheck %s @@ -53,6 +57,8 @@ # CHECK: 00000000001000 *ABS* 00000000 commonpagesize # CHECK: 0000000000ffff *ABS* 00000000 datasegmentalign # CHECK: 0000000000fff0 *ABS* 00000000 datasegmentalign2 +# CHECK: 0000000000ffe0 .text 00000000 minus_rel +# CHECK: 0000000000fff0 *ABS* 00000000 minus_abs ## Mailformed number error. # RUN: echo "SECTIONS { . = 0x12Q41; }" > %t.script diff --git a/test/ELF/znotext-plt-relocations.s b/test/ELF/znotext-plt-relocations.s new file mode 100644 index 000000000000..ad305b0c1f6c --- /dev/null +++ b/test/ELF/znotext-plt-relocations.s @@ -0,0 +1,20 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/znotext-plt-relocations.s -o %t2.o +# RUN: ld.lld %t2.o -o %t2.so -shared +# RUN: ld.lld -z notext %t.o %t2.so -o %t +# RUN: llvm-readobj -r %t | FileCheck %s + +# CHECK: Relocations [ +# CHECK-NEXT: Section {{.*}} .rela.dyn { +# CHECK-NEXT: R_X86_64_64 foo 0x0 +# CHECK-NEXT: } +# CHECK-NEXT: Section {{.*}} .rela.plt { +# CHECK-NEXT: R_X86_64_JUMP_SLOT atexit 0x0 +# CHECK-NEXT: } +# CHECK-NEXT: ] + +.text +_start: +callq atexit +.quad foo diff --git a/test/wasm/Inputs/global-ctor-dtor.ll b/test/wasm/Inputs/global-ctor-dtor.ll new file mode 100644 index 000000000000..5cacd7e433ab --- /dev/null +++ b/test/wasm/Inputs/global-ctor-dtor.ll @@ -0,0 +1,14 @@ +define hidden void @myctor() { +entry: + ret void +} + +define hidden void @mydtor() { +entry: + %ptr = alloca i32 + ret void +} + +@llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @myctor, i8* null }] + +@llvm.global_dtors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @mydtor, i8* null }] diff --git a/test/wasm/Inputs/weak-alias.ll b/test/wasm/Inputs/weak-alias.ll index 079e68e3ce7a..b911b35529c5 100644 --- a/test/wasm/Inputs/weak-alias.ll +++ b/test/wasm/Inputs/weak-alias.ll @@ -1,13 +1,37 @@ ; Function Attrs: norecurse nounwind readnone -define i32 @foo() #0 { +define i32 @direct_fn() #0 { entry: ret i32 0 } -@bar = weak alias i32 (), i32 ()* @foo +@alias_fn = weak alias i32 (), i32 ()* @direct_fn -define i32 @call_bar() #0 { +define i32 @call_direct() #0 { entry: - %call = call i32 @bar() + %call = call i32 @direct_fn() + ret i32 %call +} + +define i32 @call_alias() #0 { +entry: + %call = call i32 @alias_fn() + ret i32 %call +} + +define i32 @call_alias_ptr() #0 { +entry: + %fnptr = alloca i32 ()*, align 8 + store i32 ()* @alias_fn, i32 ()** %fnptr, align 8 + %0 = load i32 ()*, i32 ()** %fnptr, align 8 + %call = call i32 %0() + ret i32 %call +} + +define i32 @call_direct_ptr() #0 { +entry: + %fnptr = alloca i32 ()*, align 8 + store i32 ()* @direct_fn, i32 ()** %fnptr, align 8 + %0 = load i32 ()*, i32 ()** %fnptr, align 8 + %call = call i32 %0() ret i32 %call } diff --git a/test/wasm/Inputs/weak-symbol1.ll b/test/wasm/Inputs/weak-symbol1.ll index 2d561716f825..61e7e5818c54 100644 --- a/test/wasm/Inputs/weak-symbol1.ll +++ b/test/wasm/Inputs/weak-symbol1.ll @@ -7,3 +7,5 @@ define i32 @exportWeak1() { entry: ret i32 ptrtoint (i32 ()* @weakFn to i32) } + +@weakGlobal = weak global i32 1 diff --git a/test/wasm/Inputs/weak-symbol2.ll b/test/wasm/Inputs/weak-symbol2.ll index f43ea96673b9..9e2e270f8693 100644 --- a/test/wasm/Inputs/weak-symbol2.ll +++ b/test/wasm/Inputs/weak-symbol2.ll @@ -7,3 +7,5 @@ define i32 @exportWeak2() { entry: ret i32 ptrtoint (i32 ()* @weakFn to i32) } + +@weakGlobal = weak global i32 2 diff --git a/test/wasm/archive.ll b/test/wasm/archive.ll index 18f35330d1e9..a43e460d69f2 100644 --- a/test/wasm/archive.ll +++ b/test/wasm/archive.ll @@ -1,7 +1,7 @@ -; RUN: llc -filetype=obj -mtriple=wasm32-unknown-uknown-wasm %s -o %t.o -; RUN: llc -filetype=obj -mtriple=wasm32-unknown-uknown-wasm %S/Inputs/archive1.ll -o %t.a1.o -; RUN: llc -filetype=obj -mtriple=wasm32-unknown-uknown-wasm %S/Inputs/archive2.ll -o %t.a2.o -; RUN: llc -filetype=obj -mtriple=wasm32-unknown-uknown-wasm %S/Inputs/hello.ll -o %t.a3.o +; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %s -o %t.o +; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %S/Inputs/archive1.ll -o %t.a1.o +; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %S/Inputs/archive2.ll -o %t.a2.o +; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %S/Inputs/hello.ll -o %t.a3.o ; RUN: llvm-ar rcs %t.a %t.a1.o %t.a2.o %t.a3.o ; RUN: lld -flavor wasm %t.a %t.o -o %t.wasm ; RUN: llvm-nm -a %t.wasm | FileCheck %s diff --git a/test/wasm/call-indirect.ll b/test/wasm/call-indirect.ll index 14845eb50f83..2b838a8efa4d 100644 --- a/test/wasm/call-indirect.ll +++ b/test/wasm/call-indirect.ll @@ -1,5 +1,5 @@ -; RUN: llc -filetype=obj -mtriple=wasm32-unknown-uknown-wasm %p/Inputs/call-indirect.ll -o %t2.o -; RUN: llc -filetype=obj -mtriple=wasm32-unknown-uknown-wasm %s -o %t.o +; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %p/Inputs/call-indirect.ll -o %t2.o +; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %s -o %t.o ; RUN: lld -flavor wasm -o %t.wasm %t2.o %t.o ; RUN: obj2yaml %t.wasm | FileCheck %s @@ -20,10 +20,17 @@ entry: define i32 @_start() local_unnamed_addr #1 { entry: %0 = load i32 ()*, i32 ()** @indirect_func, align 4 - %call = tail call i32 %0() #2 + %call = call i32 %0() #2 ret i32 0 } +; Indirect function call where no function actually has this type. +; Ensures that the type entry is still created in this case. +define void @call_ptr(i64 (i64)* %arg) { + %1 = call i64 %arg(i64 1) + ret void +} + ; CHECK: !WASM ; CHECK-NEXT: FileHeader: ; CHECK-NEXT: Version: 0x00000001 @@ -36,8 +43,16 @@ entry: ; CHECK-NEXT: - Index: 1 ; CHECK-NEXT: ReturnType: NORESULT ; CHECK-NEXT: ParamTypes: +; CHECK-NEXT: - Index: 2 +; CHECK-NEXT: ReturnType: NORESULT +; CHECK-NEXT: ParamTypes: +; CHECK-NEXT: - I32 +; CHECK-NEXT: - Index: 3 +; CHECK-NEXT: ReturnType: I64 +; CHECK-NEXT: ParamTypes: +; CHECK-NEXT: - I64 ; CHECK-NEXT: - Type: FUNCTION -; CHECK-NEXT: FunctionTypes: [ 0, 1, 0, 0 ] +; CHECK-NEXT: FunctionTypes: [ 0, 1, 0, 0, 2 ] ; CHECK-NEXT: - Type: TABLE ; CHECK-NEXT: Tables: ; CHECK-NEXT: - ElemType: ANYFUNC @@ -72,6 +87,9 @@ entry: ; CHECK-NEXT: - Name: call_bar_indirect ; CHECK-NEXT: Kind: FUNCTION ; CHECK-NEXT: Index: 1 +; CHECK-NEXT: - Name: call_ptr +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Index: 4 ; CHECK-NEXT: - Type: ELEM ; CHECK-NEXT: Segments: ; CHECK-NEXT: - Offset: @@ -88,6 +106,8 @@ entry: ; CHECK-NEXT: Body: 41020B ; CHECK-NEXT: - Locals: ; CHECK-NEXT: Body: 410028028888808000118080808000001A41000B +; CHECK-NEXT: - Locals: +; CHECK-NEXT: Body: 42012000118380808000001A0B ; CHECK-NEXT: - Type: DATA ; CHECK-NEXT: Segments: ; CHECK-NEXT: - SectionOffset: 7 diff --git a/test/wasm/conflict.test b/test/wasm/conflict.test index a0a2eb4e3b3a..41684ae51a12 100644 --- a/test/wasm/conflict.test +++ b/test/wasm/conflict.test @@ -1,4 +1,4 @@ -# RUN: llc -filetype=obj -mtriple=wasm32-unknown-uknown-wasm %p/Inputs/ret32.ll -o %t.ret32.o +# RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %p/Inputs/ret32.ll -o %t.ret32.o # RUN: not lld -flavor wasm -o %t.wasm %t.ret32.o %t.ret32.o 2>&1 | FileCheck %s # CHECK: duplicate symbol: ret32 diff --git a/test/wasm/data-layout.ll b/test/wasm/data-layout.ll index 0b2c61da5547..2300b362a55f 100644 --- a/test/wasm/data-layout.ll +++ b/test/wasm/data-layout.ll @@ -1,5 +1,5 @@ -; RUN: llc -filetype=obj -mtriple=wasm32-unknown-uknown-wasm %p/Inputs/hello.ll -o %t.hello.o -; RUN: llc -filetype=obj -mtriple=wasm32-unknown-uknown-wasm %s -o %t.o +; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %p/Inputs/hello.ll -o %t.hello.o +; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %s -o %t.o ; RUN: lld -flavor wasm --emit-relocs --allow-undefined --no-entry -o %t.wasm %t.o %t.hello.o ; RUN: obj2yaml %t.wasm | FileCheck %s diff --git a/test/wasm/entry.ll b/test/wasm/entry.ll index e51c7055b80e..4749d8306651 100644 --- a/test/wasm/entry.ll +++ b/test/wasm/entry.ll @@ -1,4 +1,4 @@ -; RUN: llc -filetype=obj -mtriple=wasm32-unknown-uknown-wasm %s -o %t.o +; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %s -o %t.o ; RUN: lld -flavor wasm -e entry -o %t.wasm %t.o ; RUN: obj2yaml %t.wasm | FileCheck %s ; RUN: lld -flavor wasm --entry=entry -o %t.wasm %t.o diff --git a/test/wasm/function-imports-first.ll b/test/wasm/function-imports-first.ll index 085345ad7ffc..eda1302703c0 100644 --- a/test/wasm/function-imports-first.ll +++ b/test/wasm/function-imports-first.ll @@ -1,5 +1,5 @@ -; RUN: llc -filetype=obj -mtriple=wasm32-unknown-uknown-wasm %p/Inputs/ret32.ll -o %t.ret32.o -; RUN: llc -filetype=obj -mtriple=wasm32-unknown-uknown-wasm %s -o %t.o +; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %p/Inputs/ret32.ll -o %t.ret32.o +; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %s -o %t.o ; RUN: lld -flavor wasm -o %t.wasm %t.o %t.ret32.o ; RUN: obj2yaml %t.wasm | FileCheck %s diff --git a/test/wasm/function-imports.ll b/test/wasm/function-imports.ll index e0988ff95f96..072554d8400a 100644 --- a/test/wasm/function-imports.ll +++ b/test/wasm/function-imports.ll @@ -1,5 +1,5 @@ -; RUN: llc -filetype=obj -mtriple=wasm32-unknown-uknown-wasm %p/Inputs/ret32.ll -o %t.ret32.o -; RUN: llc -filetype=obj -mtriple=wasm32-unknown-uknown-wasm %s -o %t.o +; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %p/Inputs/ret32.ll -o %t.ret32.o +; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %s -o %t.o ; RUN: lld -flavor wasm -o %t.wasm %t.ret32.o %t.o ; RUN: obj2yaml %t.wasm | FileCheck %s diff --git a/test/wasm/function-index.test b/test/wasm/function-index.test index 03bd879b5176..c65c560d11c8 100644 --- a/test/wasm/function-index.test +++ b/test/wasm/function-index.test @@ -1,5 +1,5 @@ -# RUN: llc -filetype=obj -mtriple=wasm32-unknown-uknown-wasm %p/Inputs/ret32.ll -o %t.ret32.o -# RUN: llc -filetype=obj -mtriple=wasm32-unknown-uknown-wasm %p/Inputs/ret64.ll -o %t.ret64.o +# RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %p/Inputs/ret32.ll -o %t.ret32.o +# RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %p/Inputs/ret64.ll -o %t.ret64.o # RUN: lld -flavor wasm -r -o %t.wasm %t.ret32.o %t.ret64.o # RUN: obj2yaml %t.wasm | FileCheck %s diff --git a/test/wasm/import-memory.test b/test/wasm/import-memory.test index af0ff910449c..9713e6cd5a17 100644 --- a/test/wasm/import-memory.test +++ b/test/wasm/import-memory.test @@ -1,4 +1,4 @@ -# RUN: llc -filetype=obj -mtriple=wasm32-unknown-uknown-wasm %p/Inputs/ret32.ll -o %t.ret32.o +# RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %p/Inputs/ret32.ll -o %t.ret32.o # RUN: lld -flavor wasm -entry ret32 --import-memory -o %t.wasm %t.ret32.o # RUN: obj2yaml %t.wasm | FileCheck %s diff --git a/test/wasm/init-fini.ll b/test/wasm/init-fini.ll new file mode 100644 index 000000000000..bdae29811d8e --- /dev/null +++ b/test/wasm/init-fini.ll @@ -0,0 +1,99 @@ +; RUN: llc -mtriple=wasm32-unknown-unknown-wasm -filetype=obj -o %t.o %s +; RUN: llc -mtriple=wasm32-unknown-unknown-wasm -filetype=obj %S/Inputs/global-ctor-dtor.ll -o %t.global-ctor-dtor.o + +define hidden void @func1() { +entry: + ret void +} + +define hidden void @func2() { +entry: + ret void +} + +define void @__cxa_atexit() { + ret void +} + +define hidden void @_start() { +entry: + ret void +} + +@llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @func1, i8* null }] + +@llvm.global_dtors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @func2, i8* null }] + +; RUN: lld -flavor wasm %t.o %t.global-ctor-dtor.o -o %t.wasm +; RUN: obj2yaml %t.wasm | FileCheck %s + +; CHECK: Name: linking +; CHECK-NEXT: DataSize: 0 +; CHECK-NEXT: - Type: CUSTOM +; CHECK-NEXT: Name: name +; CHECK-NEXT: FunctionNames: +; CHECK-NEXT: - Index: 0 +; CHECK-NEXT: Name: func1 +; CHECK-NEXT: - Index: 1 +; CHECK-NEXT: Name: func2 +; CHECK-NEXT: - Index: 2 +; CHECK-NEXT: Name: __cxa_atexit +; CHECK-NEXT: - Index: 3 +; CHECK-NEXT: Name: _start +; CHECK-NEXT: - Index: 4 +; CHECK-NEXT: Name: .Lcall_dtors +; CHECK-NEXT: - Index: 5 +; CHECK-NEXT: Name: .Lregister_call_dtors +; CHECK-NEXT: - Index: 6 +; CHECK-NEXT: Name: .Lbitcast +; CHECK-NEXT: - Index: 7 +; CHECK-NEXT: Name: myctor +; CHECK-NEXT: - Index: 8 +; CHECK-NEXT: Name: mydtor +; CHECK-NEXT: - Index: 9 +; CHECK-NEXT: Name: .Lcall_dtors +; CHECK-NEXT: - Index: 10 +; CHECK-NEXT: Name: .Lregister_call_dtors +; CHECK-NEXT: ... + + +; RUN: lld -flavor wasm -r %t.o %t.global-ctor-dtor.o -o %t.reloc.wasm +; RUN: obj2yaml %t.reloc.wasm | FileCheck -check-prefix=RELOC %s + +; RELOC: Name: linking +; RELOC-NEXT: DataSize: 0 +; RELOC-NEXT: InitFunctions: +; RELOC-NEXT: - Priority: 65535 +; RELOC-NEXT: FunctionIndex: 0 +; RELOC-NEXT: - Priority: 65535 +; RELOC-NEXT: FunctionIndex: 5 +; RELOC-NEXT: - Priority: 65535 +; RELOC-NEXT: FunctionIndex: 7 +; RELOC-NEXT: - Priority: 65535 +; RELOC-NEXT: FunctionIndex: 10 +; RELOC-NEXT: - Type: CUSTOM +; RELOC-NEXT: Name: name +; RELOC-NEXT: FunctionNames: +; RELOC-NEXT: - Index: 0 +; RELOC-NEXT: Name: func1 +; RELOC-NEXT: - Index: 1 +; RELOC-NEXT: Name: func2 +; RELOC-NEXT: - Index: 2 +; RELOC-NEXT: Name: __cxa_atexit +; RELOC-NEXT: - Index: 3 +; RELOC-NEXT: Name: _start +; RELOC-NEXT: - Index: 4 +; RELOC-NEXT: Name: .Lcall_dtors +; RELOC-NEXT: - Index: 5 +; RELOC-NEXT: Name: .Lregister_call_dtors +; RELOC-NEXT: - Index: 6 +; RELOC-NEXT: Name: .Lbitcast +; RELOC-NEXT: - Index: 7 +; RELOC-NEXT: Name: myctor +; RELOC-NEXT: - Index: 8 +; RELOC-NEXT: Name: mydtor +; RELOC-NEXT: - Index: 9 +; RELOC-NEXT: Name: .Lcall_dtors +; RELOC-NEXT: - Index: 10 +; RELOC-NEXT: Name: .Lregister_call_dtors +; RELOC-NEXT: ... diff --git a/test/wasm/invalid-stack-size.test b/test/wasm/invalid-stack-size.test index 6597c548499a..484bbd3ca2c8 100644 --- a/test/wasm/invalid-stack-size.test +++ b/test/wasm/invalid-stack-size.test @@ -1,4 +1,4 @@ -; RUN: llc -mtriple wasm32-unknown-unknown-wasm -filetype=obj %s -o %t.o +; RUN: llc -mtriple=wasm32-unknown-unknown-wasm -filetype=obj %s -o %t.o ; RUN: not lld -flavor wasm -o %t.wasm -z stack-size=1 %t.o 2>&1 | FileCheck %s define i32 @_start() local_unnamed_addr #1 { diff --git a/test/wasm/local-symbols.ll b/test/wasm/local-symbols.ll index 3e6722b124ec..e88f656e14c6 100644 --- a/test/wasm/local-symbols.ll +++ b/test/wasm/local-symbols.ll @@ -1,4 +1,4 @@ -; RUN: llc -filetype=obj -mtriple=wasm32-unknown-uknown-wasm %s -o %t.o +; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %s -o %t.o ; RUN: lld -flavor wasm -o %t.wasm %t.o ; RUN: obj2yaml %t.wasm | FileCheck %s diff --git a/test/wasm/many-functions.ll b/test/wasm/many-functions.ll index 77326d739a8b..f21298d862d6 100644 --- a/test/wasm/many-functions.ll +++ b/test/wasm/many-functions.ll @@ -1,5 +1,5 @@ -; RUN: llc -filetype=obj -mtriple=wasm32-unknown-uknown-wasm %p/Inputs/many-funcs.ll -o %t.many.o -; RUN: llc -filetype=obj -mtriple=wasm32-unknown-uknown-wasm %s -o %t.o +; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %p/Inputs/many-funcs.ll -o %t.many.o +; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %s -o %t.o ; RUN: lld -flavor wasm -r -o %t.wasm %t.many.o %t.o ; RUN: obj2yaml %t.wasm | FileCheck %s diff --git a/test/wasm/relocatable.ll b/test/wasm/relocatable.ll index cb86aa20cab2..d9d2e02bdabb 100644 --- a/test/wasm/relocatable.ll +++ b/test/wasm/relocatable.ll @@ -1,5 +1,5 @@ -; RUN: llc -filetype=obj -mtriple=wasm32-unknown-uknown-wasm %p/Inputs/hello.ll -o %t.hello.o -; RUN: llc -filetype=obj -mtriple=wasm32-unknown-uknown-wasm %s -o %t.o +; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %p/Inputs/hello.ll -o %t.hello.o +; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %s -o %t.o ; RUN: lld -flavor wasm -r -o %t.wasm %t.hello.o %t.o ; RUN: obj2yaml %t.wasm | FileCheck %s diff --git a/test/wasm/signature-mismatch.ll b/test/wasm/signature-mismatch.ll index 88f70fea5123..842b8289afd9 100644 --- a/test/wasm/signature-mismatch.ll +++ b/test/wasm/signature-mismatch.ll @@ -1,5 +1,5 @@ -; RUN: llc -filetype=obj -mtriple=wasm32-unknown-uknown-wasm %p/Inputs/ret32.ll -o %t.ret32.o -; RUN: llc -filetype=obj -mtriple=wasm32-unknown-uknown-wasm %s -o %t.main.o +; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %p/Inputs/ret32.ll -o %t.ret32.o +; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %s -o %t.main.o ; RUN: not lld -flavor wasm --check-signatures -o %t.wasm %t.main.o %t.ret32.o 2>&1 | FileCheck %s ; Function Attrs: nounwind diff --git a/test/wasm/stack-pointer.ll b/test/wasm/stack-pointer.ll index 738f0dce8e81..c5be94af4e39 100644 --- a/test/wasm/stack-pointer.ll +++ b/test/wasm/stack-pointer.ll @@ -1,4 +1,4 @@ -; RUN: llc -filetype=obj -mtriple=wasm32-unknown-uknown-wasm %s -o %t.o +; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %s -o %t.o ; RUN: lld -flavor wasm --emit-relocs -o %t.wasm %t.o ; RUN: obj2yaml %t.wasm | FileCheck %s diff --git a/test/wasm/strip-debug.test b/test/wasm/strip-debug.test index 57667a9f4406..ca4b02a4a5fb 100644 --- a/test/wasm/strip-debug.test +++ b/test/wasm/strip-debug.test @@ -1,4 +1,4 @@ -RUN: llc -filetype=obj -mtriple=wasm32-unknown-uknown-wasm %p/Inputs/ret32.ll -o %t.ret32.o +RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %p/Inputs/ret32.ll -o %t.ret32.o RUN: lld -flavor wasm --strip-debug --entry=ret32 -o %t.wasm %t.ret32.o RUN: obj2yaml %t.wasm | FileCheck %s diff --git a/test/wasm/symbol-type-mismatch.ll b/test/wasm/symbol-type-mismatch.ll index 706a361dd767..b7e37c142549 100644 --- a/test/wasm/symbol-type-mismatch.ll +++ b/test/wasm/symbol-type-mismatch.ll @@ -1,5 +1,5 @@ -; RUN: llc -filetype=obj -mtriple=wasm32-unknown-uknown-wasm %s -o %t.o -; RUN: llc -filetype=obj -mtriple=wasm32-unknown-uknown-wasm %p/Inputs/ret32.ll -o %t.ret32.o +; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %s -o %t.o +; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %p/Inputs/ret32.ll -o %t.ret32.o ; RUN: not lld -flavor wasm -o %t.wasm %t.o %t.ret32.o 2>&1 | FileCheck %s @ret32 = extern_weak global i32, align 4 diff --git a/test/wasm/undefined-entry.test b/test/wasm/undefined-entry.test index 00a0761f4b6c..55f7d6fb7843 100644 --- a/test/wasm/undefined-entry.test +++ b/test/wasm/undefined-entry.test @@ -1,4 +1,4 @@ -RUN: llc -filetype=obj -mtriple=wasm32-unknown-uknown-wasm %p/Inputs/ret32.ll -o %t.ret32.o +RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %p/Inputs/ret32.ll -o %t.ret32.o RUN: not lld -flavor wasm -o %t.wasm %t.ret32.o 2>&1 | FileCheck %s CHECK: error: undefined symbol: _start diff --git a/test/wasm/undefined.ll b/test/wasm/undefined.ll index c5f266431702..249afe243b07 100644 --- a/test/wasm/undefined.ll +++ b/test/wasm/undefined.ll @@ -1,4 +1,4 @@ -; RUN: llc -filetype=obj -mtriple=wasm32-unknown-uknown-wasm %s -o %t.o +; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %s -o %t.o ; RUN: lld -flavor wasm --allow-undefined -o %t.wasm %t.o ; Fails due to undefined 'foo' diff --git a/test/wasm/version.ll b/test/wasm/version.ll index aed7b39ff3b9..2ae65d9ad37f 100644 --- a/test/wasm/version.ll +++ b/test/wasm/version.ll @@ -1,4 +1,4 @@ -; RUN: llc -filetype=obj -mtriple=wasm32-unknown-uknown-wasm %s -o %t.o +; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %s -o %t.o ; RUN: lld -flavor wasm -o %t.wasm %t.o ; RUN: llvm-readobj -file-headers %t.wasm | FileCheck %s diff --git a/test/wasm/weak-alias-overide.ll b/test/wasm/weak-alias-overide.ll index 5f4021e18b0f..c2f673a52725 100644 --- a/test/wasm/weak-alias-overide.ll +++ b/test/wasm/weak-alias-overide.ll @@ -1,19 +1,19 @@ -; RUN: llc -mtriple wasm32-unknown-unknown-wasm -filetype=obj -o %t.o %s +; RUN: llc -mtriple=wasm32-unknown-unknown-wasm -filetype=obj -o %t.o %s ; RUN: llc -mtriple=wasm32-unknown-unknown-wasm -filetype=obj %S/Inputs/weak-alias.ll -o %t2.o ; RUN: lld -flavor wasm %t.o %t2.o -o %t.wasm ; RUN: obj2yaml %t.wasm | FileCheck %s -; Test that the strongly defined bar is used correctly despite the existence -; of the weak alias +; Test that the strongly defined alias_fn from this file is used both here +; and in call_alias. -define i32 @bar() local_unnamed_addr #1 { +define i32 @alias_fn() local_unnamed_addr #1 { ret i32 1 } ; Function Attrs: nounwind uwtable define void @_start() local_unnamed_addr #1 { entry: - %call = tail call i32 @bar() #2 + %call = tail call i32 @alias_fn() #2 ret void } @@ -30,14 +30,14 @@ entry: ; CHECK-NEXT: ReturnType: NORESULT ; CHECK-NEXT: ParamTypes: ; CHECK-NEXT: - Type: FUNCTION -; CHECK-NEXT: FunctionTypes: [ 0, 1, 0, 0 ] +; CHECK-NEXT: FunctionTypes: [ 0, 1, 0, 0, 0, 0, 0 ] ; CHECK-NEXT: - Type: TABLE ; CHECK-NEXT: Tables: ; CHECK-NEXT: - ElemType: ANYFUNC ; CHECK-NEXT: Limits: ; CHECK-NEXT: Flags: [ HAS_MAX ] -; CHECK-NEXT: Initial: 0x00000001 -; CHECK-NEXT: Maximum: 0x00000001 +; CHECK-NEXT: Initial: 0x00000003 +; CHECK-NEXT: Maximum: 0x00000003 ; CHECK-NEXT: - Type: MEMORY ; CHECK-NEXT: Memories: ; CHECK-NEXT: - Initial: 0x00000002 @@ -56,15 +56,30 @@ entry: ; CHECK-NEXT: - Name: _start ; CHECK-NEXT: Kind: FUNCTION ; CHECK-NEXT: Index: 1 -; CHECK-NEXT: - Name: bar +; CHECK-NEXT: - Name: alias_fn ; CHECK-NEXT: Kind: FUNCTION ; CHECK-NEXT: Index: 0 -; CHECK-NEXT: - Name: foo +; CHECK-NEXT: - Name: direct_fn ; CHECK-NEXT: Kind: FUNCTION ; CHECK-NEXT: Index: 2 -; CHECK-NEXT: - Name: call_bar +; CHECK-NEXT: - Name: call_direct ; CHECK-NEXT: Kind: FUNCTION ; CHECK-NEXT: Index: 3 +; CHECK-NEXT: - Name: call_alias +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Index: 4 +; CHECK-NEXT: - Name: call_alias_ptr +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Index: 5 +; CHECK-NEXT: - Name: call_direct_ptr +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Index: 6 +; CHECK-NEXT: - Type: ELEM +; CHECK-NEXT: Segments: +; CHECK-NEXT: - Offset: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 1 +; CHECK-NEXT: Functions: [ 0, 2 ] ; CHECK-NEXT: - Type: CODE ; CHECK-NEXT: Functions: ; CHECK-NEXT: - Locals: @@ -74,7 +89,17 @@ entry: ; CHECK-NEXT: - Locals: ; CHECK-NEXT: Body: 41000B ; CHECK-NEXT: - Locals: +; CHECK-NEXT: Body: 1082808080000B +; CHECK-NEXT: - Locals: ; CHECK-NEXT: Body: 1080808080000B +; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Type: I32 +; CHECK-NEXT: Count: 2 +; CHECK-NEXT: Body: 23808080800041106B220024808080800020004181808080003602081080808080002101200041106A24808080800020010B +; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Type: I32 +; CHECK-NEXT: Count: 2 +; CHECK-NEXT: Body: 23808080800041106B220024808080800020004182808080003602081082808080002101200041106A24808080800020010B ; CHECK-NEXT: - Type: CUSTOM ; CHECK-NEXT: Name: linking ; CHECK-NEXT: DataSize: 0 @@ -82,11 +107,17 @@ entry: ; CHECK-NEXT: Name: name ; CHECK-NEXT: FunctionNames: ; CHECK-NEXT: - Index: 0 -; CHECK-NEXT: Name: bar +; CHECK-NEXT: Name: alias_fn ; CHECK-NEXT: - Index: 1 ; CHECK-NEXT: Name: _start ; CHECK-NEXT: - Index: 2 -; CHECK-NEXT: Name: foo +; CHECK-NEXT: Name: direct_fn ; CHECK-NEXT: - Index: 3 -; CHECK-NEXT: Name: call_bar +; CHECK-NEXT: Name: call_direct +; CHECK-NEXT: - Index: 4 +; CHECK-NEXT: Name: call_alias +; CHECK-NEXT: - Index: 5 +; CHECK-NEXT: Name: call_alias_ptr +; CHECK-NEXT: - Index: 6 +; CHECK-NEXT: Name: call_direct_ptr ; CHECK-NEXT: ... diff --git a/test/wasm/weak-alias.ll b/test/wasm/weak-alias.ll index 6f96d4d17643..6a345ec0c63e 100644 --- a/test/wasm/weak-alias.ll +++ b/test/wasm/weak-alias.ll @@ -1,16 +1,16 @@ -; RUN: llc -mtriple wasm32-unknown-unknown-wasm -filetype=obj -o %t.o %s +; RUN: llc -mtriple=wasm32-unknown-unknown-wasm -filetype=obj -o %t.o %s ; RUN: llc -mtriple=wasm32-unknown-unknown-wasm -filetype=obj %S/Inputs/weak-alias.ll -o %t2.o ; RUN: lld -flavor wasm %t.o %t2.o -o %t.wasm ; RUN: obj2yaml %t.wasm | FileCheck %s -; Test that weak aliases (bar is a weak alias of foo) are linked correctly +; Test that weak aliases (alias_fn is a weak alias of direct_fn) are linked correctly -declare i32 @bar() local_unnamed_addr #1 +declare i32 @alias_fn() local_unnamed_addr #1 ; Function Attrs: nounwind uwtable define i32 @_start() local_unnamed_addr #1 { entry: - %call = tail call i32 @bar() #2 + %call = tail call i32 @alias_fn() #2 ret i32 %call } @@ -24,14 +24,14 @@ entry: ; CHECK-NEXT: ReturnType: I32 ; CHECK-NEXT: ParamTypes: ; CHECK-NEXT: - Type: FUNCTION -; CHECK-NEXT: FunctionTypes: [ 0, 0, 0 ] +; CHECK-NEXT: FunctionTypes: [ 0, 0, 0, 0, 0, 0 ] ; CHECK-NEXT: - Type: TABLE ; CHECK-NEXT: Tables: ; CHECK-NEXT: - ElemType: ANYFUNC ; CHECK-NEXT: Limits: ; CHECK-NEXT: Flags: [ HAS_MAX ] -; CHECK-NEXT: Initial: 0x00000001 -; CHECK-NEXT: Maximum: 0x00000001 +; CHECK-NEXT: Initial: 0x00000003 +; CHECK-NEXT: Maximum: 0x00000003 ; CHECK-NEXT: - Type: MEMORY ; CHECK-NEXT: Memories: ; CHECK-NEXT: - Initial: 0x00000002 @@ -50,15 +50,30 @@ entry: ; CHECK-NEXT: - Name: _start ; CHECK-NEXT: Kind: FUNCTION ; CHECK-NEXT: Index: 0 -; CHECK-NEXT: - Name: bar +; CHECK-NEXT: - Name: alias_fn ; CHECK-NEXT: Kind: FUNCTION ; CHECK-NEXT: Index: 1 -; CHECK-NEXT: - Name: foo +; CHECK-NEXT: - Name: direct_fn ; CHECK-NEXT: Kind: FUNCTION ; CHECK-NEXT: Index: 1 -; CHECK-NEXT: - Name: call_bar +; CHECK-NEXT: - Name: call_direct ; CHECK-NEXT: Kind: FUNCTION ; CHECK-NEXT: Index: 2 +; CHECK-NEXT: - Name: call_alias +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Index: 3 +; CHECK-NEXT: - Name: call_alias_ptr +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Index: 4 +; CHECK-NEXT: - Name: call_direct_ptr +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Index: 5 +; CHECK-NEXT: - Type: ELEM +; CHECK-NEXT: Segments: +; CHECK-NEXT: - Offset: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 1 +; CHECK-NEXT: Functions: [ 1, 1 ] ; CHECK-NEXT: - Type: CODE ; CHECK-NEXT: Functions: ; CHECK-NEXT: - Locals: @@ -67,6 +82,16 @@ entry: ; CHECK-NEXT: Body: 41000B ; CHECK-NEXT: - Locals: ; CHECK-NEXT: Body: 1081808080000B +; CHECK-NEXT: - Locals: +; CHECK-NEXT: Body: 1081808080000B +; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Type: I32 +; CHECK-NEXT: Count: 2 +; CHECK-NEXT: Body: 23808080800041106B220024808080800020004181808080003602081081808080002101200041106A24808080800020010B +; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Type: I32 +; CHECK-NEXT: Count: 2 +; CHECK-NEXT: Body: 23808080800041106B220024808080800020004182808080003602081081808080002101200041106A24808080800020010B ; CHECK-NEXT: - Type: CUSTOM ; CHECK-NEXT: Name: linking ; CHECK-NEXT: DataSize: 0 @@ -76,7 +101,13 @@ entry: ; CHECK-NEXT: - Index: 0 ; CHECK-NEXT: Name: _start ; CHECK-NEXT: - Index: 1 -; CHECK-NEXT: Name: foo +; CHECK-NEXT: Name: direct_fn ; CHECK-NEXT: - Index: 2 -; CHECK-NEXT: Name: call_bar +; CHECK-NEXT: Name: call_direct +; CHECK-NEXT: - Index: 3 +; CHECK-NEXT: Name: call_alias +; CHECK-NEXT: - Index: 4 +; CHECK-NEXT: Name: call_alias_ptr +; CHECK-NEXT: - Index: 5 +; CHECK-NEXT: Name: call_direct_ptr ; CHECK-NEXT: ... diff --git a/test/wasm/weak-external.ll b/test/wasm/weak-external.ll index 891f7666ec76..e5025db53693 100644 --- a/test/wasm/weak-external.ll +++ b/test/wasm/weak-external.ll @@ -1,4 +1,4 @@ -; RUN: llc -mtriple wasm32-unknown-unknown-wasm -filetype=obj -o %t.o %s +; RUN: llc -mtriple=wasm32-unknown-unknown-wasm -filetype=obj -o %t.o %s ; RUN: lld -flavor wasm -strip-debug %t.o -o %t.wasm ; RUN: obj2yaml %t.wasm | FileCheck %s diff --git a/test/wasm/weak-symbols.ll b/test/wasm/weak-symbols.ll index c282d005623f..4e4e2edfa9b2 100644 --- a/test/wasm/weak-symbols.ll +++ b/test/wasm/weak-symbols.ll @@ -1,15 +1,17 @@ -; RUN: llc -filetype=obj -mtriple=wasm32-unknown-uknown-wasm %p/Inputs/weak-symbol1.ll -o %t1.o -; RUN: llc -filetype=obj -mtriple=wasm32-unknown-uknown-wasm %p/Inputs/weak-symbol2.ll -o %t2.o -; RUN: llc -filetype=obj -mtriple=wasm32-unknown-uknown-wasm %s -o %t.o +; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %p/Inputs/weak-symbol1.ll -o %t1.o +; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %p/Inputs/weak-symbol2.ll -o %t2.o +; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %s -o %t.o ; RUN: lld -flavor wasm -o %t.wasm %t.o %t1.o %t2.o ; RUN: obj2yaml %t.wasm | FileCheck %s declare i32 @weakFn() local_unnamed_addr +@weakGlobal = external global i32 -define void @_start() local_unnamed_addr { +define i32 @_start() local_unnamed_addr { entry: %call = call i32 @weakFn() - ret void + %val = load i32, i32* @weakGlobal, align 4 + ret i32 %val } ; CHECK: --- !WASM @@ -19,13 +21,10 @@ entry: ; CHECK-NEXT: - Type: TYPE ; CHECK-NEXT: Signatures: ; CHECK-NEXT: - Index: 0 -; CHECK-NEXT: ReturnType: NORESULT -; CHECK-NEXT: ParamTypes: -; CHECK-NEXT: - Index: 1 ; CHECK-NEXT: ReturnType: I32 ; CHECK-NEXT: ParamTypes: ; CHECK-NEXT: - Type: FUNCTION -; CHECK-NEXT: FunctionTypes: [ 0, 1, 1, 1, 1 ] +; CHECK-NEXT: FunctionTypes: [ 0, 0, 0, 0, 0 ] ; CHECK-NEXT: - Type: TABLE ; CHECK-NEXT: Tables: ; CHECK-NEXT: - ElemType: ANYFUNC @@ -42,7 +41,7 @@ entry: ; CHECK-NEXT: Mutable: true ; CHECK-NEXT: InitExpr: ; CHECK-NEXT: Opcode: I32_CONST -; CHECK-NEXT: Value: 66560 +; CHECK-NEXT: Value: 66576 ; CHECK-NEXT: - Type: EXPORT ; CHECK-NEXT: Exports: ; CHECK-NEXT: - Name: memory @@ -69,7 +68,7 @@ entry: ; CHECK-NEXT: - Type: CODE ; CHECK-NEXT: Functions: ; CHECK-NEXT: - Locals: -; CHECK-NEXT: Body: 1081808080001A0B +; CHECK-NEXT: Body: 1081808080001A4100280280888080000B ; CHECK-NEXT: - Locals: ; CHECK-NEXT: Body: 41010B ; CHECK-NEXT: - Locals: @@ -78,9 +77,17 @@ entry: ; CHECK-NEXT: Body: 41020B ; CHECK-NEXT: - Locals: ; CHECK-NEXT: Body: 4181808080000B +; CHECK-NEXT: - Type: DATA +; CHECK-NEXT: Segments: +; CHECK-NEXT: - SectionOffset: 7 +; CHECK-NEXT: MemoryIndex: 0 +; CHECK-NEXT: Offset: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 1024 +; CHECK-NEXT: Content: '0100000002000000' ; CHECK-NEXT: - Type: CUSTOM ; CHECK-NEXT: Name: linking -; CHECK-NEXT: DataSize: 0 +; CHECK-NEXT: DataSize: 8 ; CHECK-NEXT: - Type: CUSTOM ; CHECK-NEXT: Name: name ; CHECK-NEXT: FunctionNames: diff --git a/wasm/InputFiles.cpp b/wasm/InputFiles.cpp index e7463da39db9..1a1a6812c48e 100644 --- a/wasm/InputFiles.cpp +++ b/wasm/InputFiles.cpp @@ -198,13 +198,22 @@ void ObjFile::initializeSymbols() { DEBUG(dbgs() << "Function: " << WasmSym.ElementIndex << " -> " << toString(*S) << "\n"); FunctionSymbols[WasmSym.ElementIndex] = S; + if (WasmSym.HasAltIndex) + FunctionSymbols[WasmSym.AltIndex] = S; } else { DEBUG(dbgs() << "Global: " << WasmSym.ElementIndex << " -> " << toString(*S) << "\n"); GlobalSymbols[WasmSym.ElementIndex] = S; + if (WasmSym.HasAltIndex) + GlobalSymbols[WasmSym.AltIndex] = S; } } + DEBUG(for (size_t I = 0; I < FunctionSymbols.size(); ++I) + assert(FunctionSymbols[I] != nullptr); + for (size_t I = 0; I < GlobalSymbols.size(); ++I) + assert(GlobalSymbols[I] != nullptr);); + // Populate `TableSymbols` with all symbols that are called indirectly uint32_t SegmentCount = WasmObj->elements().size(); if (SegmentCount) { diff --git a/wasm/InputSegment.h b/wasm/InputSegment.h index 64124b1ebc2c..f70a3ded895e 100644 --- a/wasm/InputSegment.h +++ b/wasm/InputSegment.h @@ -21,6 +21,7 @@ #ifndef LLD_WASM_INPUT_SEGMENT_H #define LLD_WASM_INPUT_SEGMENT_H +#include "WriterUtils.h" #include "lld/Common/ErrorHandler.h" #include "llvm/Object/Wasm.h" @@ -62,6 +63,7 @@ public: const WasmSegment *Segment; const ObjFile *File; std::vector<WasmRelocation> Relocations; + std::vector<OutputRelocation> OutRelocations; protected: const OutputSegment *OutputSeg = nullptr; diff --git a/wasm/OutputSections.cpp b/wasm/OutputSections.cpp index e5253640b9db..a55538269065 100644 --- a/wasm/OutputSections.cpp +++ b/wasm/OutputSections.cpp @@ -63,10 +63,10 @@ static StringRef sectionTypeToString(uint32_t SectionType) { } } -std::string lld::toString(OutputSection *Section) { - std::string rtn = sectionTypeToString(Section->Type); - if (!Section->Name.empty()) - rtn += "(" + Section->Name + ")"; +std::string lld::toString(const OutputSection &Section) { + std::string rtn = Section.getSectionName(); + if (!Section.Name.empty()) + rtn += "(" + Section.Name + ")"; return rtn; } @@ -108,12 +108,12 @@ static void applyRelocation(uint8_t *Buf, const OutputRelocation &Reloc) { } } -static void applyRelocations(uint8_t *Buf, - ArrayRef<OutputRelocation> Relocs) { +static void applyRelocations(uint8_t *Buf, ArrayRef<OutputRelocation> Relocs) { + if (!Relocs.size()) + return; log("applyRelocations: count=" + Twine(Relocs.size())); - for (const OutputRelocation &Reloc : Relocs) { + for (const OutputRelocation &Reloc : Relocs) applyRelocation(Buf, Reloc); - } } // Relocations contain an index into the function, global or table index @@ -177,14 +177,21 @@ static void calcRelocations(const ObjFile &File, } } +std::string OutputSection::getSectionName() const { + return sectionTypeToString(Type); +} + +std::string SubSection::getSectionName() const { + return std::string("subsection <type=") + std::to_string(Type) + ">"; +} + void OutputSection::createHeader(size_t BodySize) { raw_string_ostream OS(Header); - debugWrite(OS.tell(), - "section type [" + Twine(sectionTypeToString(Type)) + "]"); + debugWrite(OS.tell(), "section type [" + Twine(getSectionName()) + "]"); writeUleb128(OS, Type, nullptr); writeUleb128(OS, BodySize, "section size"); OS.flush(); - log("createHeader: " + toString(this) + " body=" + Twine(BodySize) + + log("createHeader: " + toString(*this) + " body=" + Twine(BodySize) + " total=" + Twine(getSize())); } @@ -215,7 +222,7 @@ CodeSection::CodeSection(uint32_t NumFunctions, ArrayRef<ObjFile *> Objs) } void CodeSection::writeTo(uint8_t *Buf) { - log("writing " + toString(this)); + log("writing " + toString(*this)); log(" size=" + Twine(getSize())); Buf += Offset; @@ -245,8 +252,7 @@ void CodeSection::writeTo(uint8_t *Buf) { PayloadSize); log("applying relocations for: " + File->getName()); - if (File->CodeRelocations.size()) - applyRelocations(ContentsStart, File->CodeRelocations); + applyRelocations(ContentsStart, File->CodeRelocations); }); } @@ -282,13 +288,13 @@ DataSection::DataSection(ArrayRef<OutputSegment *> Segments) Segment->setSectionOffset(BodySize); BodySize += Segment->Header.size(); log("Data segment: size=" + Twine(Segment->Size)); - for (const InputSegment *InputSeg : Segment->InputSegments) { + for (InputSegment *InputSeg : Segment->InputSegments) { uint32_t InputOffset = InputSeg->getInputSectionOffset(); uint32_t OutputOffset = Segment->getSectionOffset() + Segment->Header.size() + InputSeg->getOutputSegmentOffset(); - calcRelocations(*InputSeg->File, InputSeg->Relocations, Relocations, - OutputOffset - InputOffset); + calcRelocations(*InputSeg->File, InputSeg->Relocations, + InputSeg->OutRelocations, OutputOffset - InputOffset); } BodySize += Segment->Size; } @@ -297,7 +303,7 @@ DataSection::DataSection(ArrayRef<OutputSegment *> Segments) } void DataSection::writeTo(uint8_t *Buf) { - log("writing " + toString(this) + " size=" + Twine(getSize()) + + log("writing " + toString(*this) + " size=" + Twine(getSize()) + " body=" + Twine(BodySize)); Buf += Offset; @@ -321,13 +327,22 @@ void DataSection::writeTo(uint8_t *Buf) { memcpy(SegStart + Segment->Header.size() + Input->getOutputSegmentOffset(), Content.data(), Content.size()); + applyRelocations(ContentsStart, Input->OutRelocations); } }); +} - applyRelocations(ContentsStart, Relocations); +uint32_t DataSection::numRelocations() const { + uint32_t Count = 0; + for (const OutputSegment *Seg : Segments) + for (const InputSegment *InputSeg : Seg->InputSegments) + Count += InputSeg->OutRelocations.size(); + return Count; } void DataSection::writeRelocations(raw_ostream &OS) const { - for (const OutputRelocation &Reloc : Relocations) - writeReloc(OS, Reloc); + for (const OutputSegment *Seg : Segments) + for (const InputSegment *InputSeg : Seg->InputSegments) + for (const OutputRelocation &Reloc : InputSeg->OutRelocations) + writeReloc(OS, Reloc); } diff --git a/wasm/OutputSections.h b/wasm/OutputSections.h index 926101710cdf..fc73f36ad286 100644 --- a/wasm/OutputSections.h +++ b/wasm/OutputSections.h @@ -23,7 +23,7 @@ namespace lld { namespace wasm { class OutputSection; } -std::string toString(wasm::OutputSection *Section); +std::string toString(const wasm::OutputSection &Section); namespace wasm { @@ -34,26 +34,24 @@ class OutputSection { public: OutputSection(uint32_t Type, std::string Name = "") : Type(Type), Name(Name) {} - virtual ~OutputSection() = default; + std::string getSectionName() const; void setOffset(size_t NewOffset) { - log("setOffset: " + toString(this) + " -> " + Twine(NewOffset)); + log("setOffset: " + toString(*this) + ": " + Twine(NewOffset)); Offset = NewOffset; } - void createHeader(size_t BodySize); virtual size_t getSize() const = 0; virtual void writeTo(uint8_t *Buf) = 0; virtual void finalizeContents() {} + virtual uint32_t numRelocations() const { return 0; } + virtual void writeRelocations(raw_ostream &OS) const {} std::string Header; uint32_t Type; std::string Name; - virtual uint32_t numRelocations() const { return 0; } - virtual void writeRelocations(raw_ostream &OS) const {} - protected: size_t Offset = 0; }; @@ -68,7 +66,7 @@ public: void writeTo(uint8_t *Buf) override { assert(Offset); - log("writing " + toString(this)); + log("writing " + toString(*this)); memcpy(Buf + Offset, Header.data(), Header.size()); memcpy(Buf + Offset + Header.size(), Body.data(), Body.size()); } @@ -97,6 +95,7 @@ class SubSection : public SyntheticSection { public: explicit SubSection(uint32_t Type) : SyntheticSection(Type) {} + std::string getSectionName() const; void writeToStream(raw_ostream &OS) { writeBytes(OS, Header.data(), Header.size()); writeBytes(OS, Body.data(), Body.size()); @@ -122,11 +121,10 @@ public: explicit DataSection(ArrayRef<OutputSegment *> Segments); size_t getSize() const override { return Header.size() + BodySize; } void writeTo(uint8_t *Buf) override; - uint32_t numRelocations() const override { return Relocations.size(); } + uint32_t numRelocations() const override; void writeRelocations(raw_ostream &OS) const override; protected: - std::vector<OutputRelocation> Relocations; ArrayRef<OutputSegment *> Segments; std::string DataSectionHeader; size_t BodySize = 0; diff --git a/wasm/OutputSegment.h b/wasm/OutputSegment.h index 1375aefae92f..a22c80234420 100644 --- a/wasm/OutputSegment.h +++ b/wasm/OutputSegment.h @@ -38,7 +38,7 @@ public: StringRef Name; uint32_t Alignment = 0; uint32_t StartVA = 0; - std::vector<const InputSegment *> InputSegments; + std::vector<InputSegment *> InputSegments; // Sum of the size of the all the input segments uint32_t Size = 0; diff --git a/wasm/SymbolTable.cpp b/wasm/SymbolTable.cpp index d9a6fa1f04f5..751008da0536 100644 --- a/wasm/SymbolTable.cpp +++ b/wasm/SymbolTable.cpp @@ -83,15 +83,7 @@ static const WasmSignature *getFunctionSig(const ObjFile &Obj, const WasmSymbol &Sym) { DEBUG(dbgs() << "getFunctionSig: " << Sym.Name << "\n"); const WasmObjectFile *WasmObj = Obj.getWasmObj(); - uint32_t FunctionType; - if (Obj.isImportedFunction(Sym.ElementIndex)) { - const WasmImport &Import = WasmObj->imports()[Sym.ImportIndex]; - FunctionType = Import.SigIndex; - } else { - uint32_t FuntionIndex = Sym.ElementIndex - Obj.NumFunctionImports(); - FunctionType = WasmObj->functionTypes()[FuntionIndex]; - } - return &WasmObj->types()[FunctionType]; + return &WasmObj->types()[Sym.FunctionType]; } // Check the type of new symbol matches that of the symbol is replacing. diff --git a/wasm/SymbolTable.h b/wasm/SymbolTable.h index e1e7da120b93..fbb74ed14796 100644 --- a/wasm/SymbolTable.h +++ b/wasm/SymbolTable.h @@ -42,7 +42,6 @@ public: void addFile(InputFile *File); std::vector<ObjFile *> ObjectFiles; - std::vector<Symbol *> SyntheticSymbols; void reportDuplicate(Symbol *Existing, InputFile *NewFile); void reportRemainingUndefines(); diff --git a/wasm/Writer.cpp b/wasm/Writer.cpp index 61ac54a3e4b3..e7dd49d52213 100644 --- a/wasm/Writer.cpp +++ b/wasm/Writer.cpp @@ -174,7 +174,7 @@ void Writer::createImportSection() { Import.Field = Sym->getName(); Import.Kind = WASM_EXTERNAL_GLOBAL; Import.Global.Mutable = false; - Import.Global.Type = WASM_TYPE_I32; // Sym->getGlobalType(); + Import.Global.Type = WASM_TYPE_I32; writeImport(OS, Import); } } @@ -183,9 +183,8 @@ void Writer::createTypeSection() { SyntheticSection *Section = createSyntheticSection(WASM_SEC_TYPE); raw_ostream &OS = Section->getStream(); writeUleb128(OS, Types.size(), "type count"); - for (const WasmSignature *Sig : Types) { + for (const WasmSignature *Sig : Types) writeSig(OS, *Sig); - } } void Writer::createFunctionSection() { @@ -196,11 +195,9 @@ void Writer::createFunctionSection() { raw_ostream &OS = Section->getStream(); writeUleb128(OS, NumFunctions, "function count"); - for (ObjFile *File : Symtab->ObjectFiles) { - for (uint32_t Sig : File->getWasmObj()->functionTypes()) { + for (ObjFile *File : Symtab->ObjectFiles) + for (uint32_t Sig : File->getWasmObj()->functionTypes()) writeUleb128(OS, File->relocateTypeIndex(Sig), "sig index"); - } - } } void Writer::createMemorySection() { @@ -358,7 +355,7 @@ void Writer::createDataSection() { OutputSections.push_back(Section); } -// Create reloctions sections in the final output. +// Create relocations sections in the final output. // These are only created when relocatable output is requested. void Writer::createRelocSections() { log("createRelocSections"); @@ -376,7 +373,7 @@ void Writer::createRelocSections() { else if (S->Type == WASM_SEC_CODE) name = "reloc.CODE"; else - llvm_unreachable("relocations only support for code and data"); + llvm_unreachable("relocations only supported for code and data"); SyntheticSection *Section = createSyntheticSection(WASM_SEC_CUSTOM, name); raw_ostream &OS = Section->getStream(); @@ -398,7 +395,10 @@ void Writer::createLinkingSection() { DataSizeSubSection.finalizeContents(); DataSizeSubSection.writeToStream(OS); - if (Segments.size() && Config->Relocatable) { + if (!Config->Relocatable) + return; + + if (Segments.size()) { SubSection SubSection(WASM_SEGMENT_INFO); writeUleb128(SubSection.getStream(), Segments.size(), "num data segments"); for (const OutputSegment *S : Segments) { @@ -409,6 +409,27 @@ void Writer::createLinkingSection() { SubSection.finalizeContents(); SubSection.writeToStream(OS); } + + std::vector<WasmInitFunc> InitFunctions; + for (ObjFile *File : Symtab->ObjectFiles) { + const WasmLinkingData &L = File->getWasmObj()->linkingData(); + InitFunctions.reserve(InitFunctions.size() + L.InitFunctions.size()); + for (const WasmInitFunc &F : L.InitFunctions) + InitFunctions.emplace_back(WasmInitFunc{ + F.Priority, File->relocateFunctionIndex(F.FunctionIndex)}); + } + + if (!InitFunctions.empty()) { + SubSection SubSection(WASM_INIT_FUNCS); + writeUleb128(SubSection.getStream(), InitFunctions.size(), + "num init functionsw"); + for (const WasmInitFunc &F : InitFunctions) { + writeUleb128(SubSection.getStream(), F.Priority, "priority"); + writeUleb128(SubSection.getStream(), F.FunctionIndex, "function index"); + } + SubSection.finalizeContents(); + SubSection.writeToStream(OS); + } } // Create the custom "name" section containing debug symbol names. @@ -501,7 +522,7 @@ void Writer::layoutMemory() { SyntheticSection *Writer::createSyntheticSection(uint32_t Type, std::string Name) { auto Sec = make<SyntheticSection>(Type, Name); - log("createSection: " + toString(Sec)); + log("createSection: " + toString(*Sec)); OutputSections.push_back(Sec); return Sec; } |