mirror of
https://git.FreeBSD.org/src.git
synced 2024-12-31 12:13:10 +00:00
Vendor import of lld trunk r321414:
https://llvm.org/svn/llvm-project/lld/trunk@321414
This commit is contained in:
parent
eb1ff93d02
commit
0d9ba4fe26
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/vendor/lld/dist/; revision=327130 svn path=/vendor/lld/lld-trunk-r321414/; revision=327131; tag=vendor/lld/lld-trunk-r321414
10
COFF/DLL.cpp
10
COFF/DLL.cpp
@ -362,12 +362,12 @@ class AddressTableChunk : public Chunk {
|
||||
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 {
|
||||
|
@ -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 {
|
||||
|
@ -37,8 +37,8 @@ class ARM final : public TargetInfo {
|
||||
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);
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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>();
|
||||
|
@ -72,6 +72,11 @@ class InputFile {
|
||||
|
||||
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 @@ class InputFile {
|
||||
// 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 @@ template <typename ELFT> class ELFFileBase : public InputFile {
|
||||
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 = "",
|
||||
|
@ -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 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 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>();
|
||||
|
@ -93,7 +93,7 @@ class SectionBase {
|
||||
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 @@ class InputSectionBase : public SectionBase {
|
||||
|
||||
// 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 @@ class EhInputSection : public InputSectionBase {
|
||||
// .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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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};
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -42,7 +42,6 @@ class SymbolTable {
|
||||
|
||||
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 @@ class SymbolTable {
|
||||
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,
|
||||
|
@ -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)
|
||||
|
@ -102,7 +102,10 @@ class Symbol {
|
||||
|
||||
// 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 @@ class SharedSymbol : public Symbol {
|
||||
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 @@ class Lazy : public Symbol {
|
||||
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 @@ class Lazy : public Symbol {
|
||||
// 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 @@ class LazyArchive : public Lazy {
|
||||
// --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();
|
||||
};
|
||||
|
||||
|
@ -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>;
|
||||
|
@ -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 @@ class ARMExidxSentinelSection : public SyntheticSection {
|
||||
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 @@ class ThunkSection : public SyntheticSection {
|
||||
};
|
||||
|
||||
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 {
|
||||
|
@ -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;
|
||||
|
||||
|
@ -40,8 +40,8 @@ class TargetInfo {
|
||||
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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
118
ELF/Writer.cpp
118
ELF/Writer.cpp
@ -54,7 +54,6 @@ template <class ELFT> class Writer {
|
||||
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>();
|
||||
|
@ -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();
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
10
test/ELF/Inputs/znotext-plt-relocations.s
Normal file
10
test/ELF/Inputs/znotext-plt-relocations.s
Normal file
@ -0,0 +1,10 @@
|
||||
.text
|
||||
.global atexit
|
||||
.type atexit,@function
|
||||
atexit:
|
||||
nop
|
||||
|
||||
.global foo
|
||||
.type foo,@function
|
||||
foo:
|
||||
nop
|
29
test/ELF/arm-exidx-dedup-and-sentinel.s
Normal file
29
test/ELF/arm-exidx-dedup-and-sentinel.s
Normal file
@ -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
|
@ -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
|
||||
|
36
test/ELF/i386-tls-initial-exec-local.s
Normal file
36
test/ELF/i386-tls-initial-exec-local.s
Normal file
@ -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
|
@ -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
|
||||
|
@ -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
|
||||
|
20
test/ELF/znotext-plt-relocations.s
Normal file
20
test/ELF/znotext-plt-relocations.s
Normal file
@ -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
|
14
test/wasm/Inputs/global-ctor-dtor.ll
Normal file
14
test/wasm/Inputs/global-ctor-dtor.ll
Normal file
@ -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 }]
|
@ -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
|
||||
}
|
||||
|
@ -7,3 +7,5 @@ define i32 @exportWeak1() {
|
||||
entry:
|
||||
ret i32 ptrtoint (i32 ()* @weakFn to i32)
|
||||
}
|
||||
|
||||
@weakGlobal = weak global i32 1
|
||||
|
@ -7,3 +7,5 @@ define i32 @exportWeak2() {
|
||||
entry:
|
||||
ret i32 ptrtoint (i32 ()* @weakFn to i32)
|
||||
}
|
||||
|
||||
@weakGlobal = weak global i32 2
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
99
test/wasm/init-fini.ll
Normal file
99
test/wasm/init-fini.ll
Normal file
@ -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: ...
|
@ -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 {
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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'
|
||||
|
@ -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
|
||||
|
||||
|
@ -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: ...
|
||||
|
@ -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: ...
|
||||
|
@ -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
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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) {
|
||||
|
@ -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 @@ class InputSegment {
|
||||
const WasmSegment *Segment;
|
||||
const ObjFile *File;
|
||||
std::vector<WasmRelocation> Relocations;
|
||||
std::vector<OutputRelocation> OutRelocations;
|
||||
|
||||
protected:
|
||||
const OutputSegment *OutputSeg = nullptr;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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 @@ class SyntheticSection : public OutputSection {
|
||||
|
||||
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 @@ class DataSection : public OutputSection {
|
||||
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;
|
||||
|
@ -38,7 +38,7 @@ class OutputSegment {
|
||||
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;
|
||||
|
@ -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.
|
||||
|
@ -42,7 +42,6 @@ class SymbolTable {
|
||||
void addFile(InputFile *File);
|
||||
|
||||
std::vector<ObjFile *> ObjectFiles;
|
||||
std::vector<Symbol *> SyntheticSymbols;
|
||||
|
||||
void reportDuplicate(Symbol *Existing, InputFile *NewFile);
|
||||
void reportRemainingUndefines();
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user