Vendor import of lld trunk r256945:
https://llvm.org/svn/llvm-project/lld/trunk@256945
This commit is contained in:
parent
5a5c549fe9
commit
fba2c04f31
@ -30,6 +30,10 @@ enum ELFKind {
|
||||
ELF64BEKind
|
||||
};
|
||||
|
||||
// This struct contains the global configuration for the linker.
|
||||
// Most fields are direct mapping from the command line options
|
||||
// and such fields have the same name as the corresponding options.
|
||||
// Most fields are initialized by the driver.
|
||||
struct Configuration {
|
||||
SymbolBody *EntrySym = nullptr;
|
||||
SymbolBody *MipsGpDisp = nullptr;
|
||||
@ -76,6 +80,7 @@ struct Configuration {
|
||||
unsigned Optimize = 0;
|
||||
};
|
||||
|
||||
// The only instance of Configuration struct.
|
||||
extern Configuration *Config;
|
||||
|
||||
} // namespace elf2
|
||||
|
@ -57,6 +57,24 @@ static std::pair<ELFKind, uint16_t> parseEmulation(StringRef S) {
|
||||
error("Unknown emulation: " + S);
|
||||
}
|
||||
|
||||
// Returns slices of MB by parsing MB as an archive file.
|
||||
// Each slice consists of a member file in the archive.
|
||||
static std::vector<MemoryBufferRef> getArchiveMembers(MemoryBufferRef MB) {
|
||||
ErrorOr<std::unique_ptr<Archive>> FileOrErr = Archive::create(MB);
|
||||
error(FileOrErr, "Failed to parse archive");
|
||||
std::unique_ptr<Archive> File = std::move(*FileOrErr);
|
||||
|
||||
std::vector<MemoryBufferRef> V;
|
||||
for (const ErrorOr<Archive::Child> &C : File->children()) {
|
||||
error(C, "Could not get the child of the archive " + File->getFileName());
|
||||
ErrorOr<MemoryBufferRef> MbOrErr = C->getMemoryBufferRef();
|
||||
error(MbOrErr, "Could not get the buffer for a child of the archive " +
|
||||
File->getFileName());
|
||||
V.push_back(*MbOrErr);
|
||||
}
|
||||
return V;
|
||||
}
|
||||
|
||||
// Opens and parses a file. Path has to be resolved already.
|
||||
// Newly created memory buffers are owned by this driver.
|
||||
void LinkerDriver::addFile(StringRef Path) {
|
||||
@ -75,19 +93,17 @@ void LinkerDriver::addFile(StringRef Path) {
|
||||
return;
|
||||
case file_magic::archive:
|
||||
if (WholeArchive) {
|
||||
auto File = make_unique<ArchiveFile>(MBRef);
|
||||
for (MemoryBufferRef &MB : File->getMembers())
|
||||
Files.push_back(createELFFile<ObjectFile>(MB));
|
||||
OwningArchives.emplace_back(std::move(File));
|
||||
for (MemoryBufferRef MB : getArchiveMembers(MBRef))
|
||||
Files.push_back(createObjectFile(MB));
|
||||
return;
|
||||
}
|
||||
Files.push_back(make_unique<ArchiveFile>(MBRef));
|
||||
return;
|
||||
case file_magic::elf_shared_object:
|
||||
Files.push_back(createELFFile<SharedFile>(MBRef));
|
||||
Files.push_back(createSharedFile(MBRef));
|
||||
return;
|
||||
default:
|
||||
Files.push_back(createELFFile<ObjectFile>(MBRef));
|
||||
Files.push_back(createObjectFile(MBRef));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -38,7 +38,6 @@ class LinkerDriver {
|
||||
llvm::BumpPtrAllocator Alloc;
|
||||
bool WholeArchive = false;
|
||||
std::vector<std::unique_ptr<InputFile>> Files;
|
||||
std::vector<std::unique_ptr<ArchiveFile>> OwningArchives;
|
||||
std::vector<std::unique_ptr<MemoryBuffer>> OwningMBs;
|
||||
};
|
||||
|
||||
|
@ -37,10 +37,9 @@ ELFFileBase<ELFT>::ELFFileBase(Kind K, MemoryBufferRef M)
|
||||
|
||||
template <class ELFT>
|
||||
ELFKind ELFFileBase<ELFT>::getELFKind() {
|
||||
using llvm::support::little;
|
||||
if (ELFT::Is64Bits)
|
||||
return ELFT::TargetEndianness == little ? ELF64LEKind : ELF64BEKind;
|
||||
return ELFT::TargetEndianness == little ? ELF32LEKind : ELF32BEKind;
|
||||
if (ELFT::TargetEndianness == support::little)
|
||||
return ELFT::Is64Bits ? ELF64LEKind : ELF32LEKind;
|
||||
return ELFT::Is64Bits ? ELF64BEKind : ELF32BEKind;
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
@ -63,8 +62,7 @@ template <class ELFT>
|
||||
uint32_t ELFFileBase<ELFT>::getSectionIndex(const Elf_Sym &Sym) const {
|
||||
uint32_t I = Sym.st_shndx;
|
||||
if (I == ELF::SHN_XINDEX)
|
||||
return this->ELFObj.getExtendedSymbolTableIndex(&Sym, this->Symtab,
|
||||
SymtabSHNDX);
|
||||
return ELFObj.getExtendedSymbolTableIndex(&Sym, Symtab, SymtabSHNDX);
|
||||
if (I >= ELF::SHN_LORESERVE || I == ELF::SHN_ABS)
|
||||
return 0;
|
||||
return I;
|
||||
@ -74,7 +72,7 @@ template <class ELFT> void ELFFileBase<ELFT>::initStringTable() {
|
||||
if (!Symtab)
|
||||
return;
|
||||
ErrorOr<StringRef> StringTableOrErr = ELFObj.getStringTableForSymtab(*Symtab);
|
||||
error(StringTableOrErr.getError());
|
||||
error(StringTableOrErr);
|
||||
StringTable = *StringTableOrErr;
|
||||
}
|
||||
|
||||
@ -108,9 +106,9 @@ ObjectFile<ELFT>::getLocalSymbol(uintX_t SymIndex) {
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
void elf2::ObjectFile<ELFT>::parse(DenseSet<StringRef> &Comdats) {
|
||||
void ObjectFile<ELFT>::parse(DenseSet<StringRef> &ComdatGroups) {
|
||||
// Read section and symbol tables.
|
||||
initializeSections(Comdats);
|
||||
initializeSections(ComdatGroups);
|
||||
initializeSymbols();
|
||||
}
|
||||
|
||||
@ -139,7 +137,7 @@ ObjectFile<ELFT>::getShtGroupEntries(const Elf_Shdr &Sec) {
|
||||
const ELFFile<ELFT> &Obj = this->ELFObj;
|
||||
ErrorOr<ArrayRef<GroupEntryType>> EntriesOrErr =
|
||||
Obj.template getSectionContentsAsArray<GroupEntryType>(&Sec);
|
||||
error(EntriesOrErr.getError());
|
||||
error(EntriesOrErr);
|
||||
ArrayRef<GroupEntryType> Entries = *EntriesOrErr;
|
||||
if (Entries.empty() || Entries[0] != GRP_COMDAT)
|
||||
error("Unsupported SHT_GROUP format");
|
||||
@ -174,7 +172,7 @@ static bool shouldMerge(const typename ELFFile<ELFT>::Elf_Shdr &Sec) {
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
void elf2::ObjectFile<ELFT>::initializeSections(DenseSet<StringRef> &Comdats) {
|
||||
void ObjectFile<ELFT>::initializeSections(DenseSet<StringRef> &ComdatGroups) {
|
||||
uint64_t Size = this->ELFObj.getNumSections();
|
||||
Sections.resize(Size);
|
||||
unsigned I = -1;
|
||||
@ -187,7 +185,7 @@ void elf2::ObjectFile<ELFT>::initializeSections(DenseSet<StringRef> &Comdats) {
|
||||
switch (Sec.sh_type) {
|
||||
case SHT_GROUP:
|
||||
Sections[I] = &InputSection<ELFT>::Discarded;
|
||||
if (Comdats.insert(getShtGroupSignature(Sec)).second)
|
||||
if (ComdatGroups.insert(getShtGroupSignature(Sec)).second)
|
||||
continue;
|
||||
for (GroupEntryType E : getShtGroupEntries(Sec)) {
|
||||
uint32_t SecIndex = E;
|
||||
@ -235,7 +233,7 @@ void elf2::ObjectFile<ELFT>::initializeSections(DenseSet<StringRef> &Comdats) {
|
||||
}
|
||||
|
||||
template <class ELFT> InputSectionBase<ELFT> *
|
||||
elf2::ObjectFile<ELFT>::createInputSection(const Elf_Shdr &Sec) {
|
||||
ObjectFile<ELFT>::createInputSection(const Elf_Shdr &Sec) {
|
||||
ErrorOr<StringRef> NameOrErr = this->ELFObj.getSectionName(&Sec);
|
||||
error(NameOrErr);
|
||||
StringRef Name = *NameOrErr;
|
||||
@ -250,29 +248,29 @@ elf2::ObjectFile<ELFT>::createInputSection(const Elf_Shdr &Sec) {
|
||||
// A MIPS object file has a special section that contains register
|
||||
// usage info, which needs to be handled by the linker specially.
|
||||
if (Config->EMachine == EM_MIPS && Name == ".reginfo") {
|
||||
MipsReginfo = new (this->Alloc) MipsReginfoInputSection<ELFT>(this, &Sec);
|
||||
MipsReginfo = new (Alloc) MipsReginfoInputSection<ELFT>(this, &Sec);
|
||||
return MipsReginfo;
|
||||
}
|
||||
|
||||
if (Name == ".eh_frame")
|
||||
return new (this->EHAlloc.Allocate()) EHInputSection<ELFT>(this, &Sec);
|
||||
return new (EHAlloc.Allocate()) EHInputSection<ELFT>(this, &Sec);
|
||||
if (shouldMerge<ELFT>(Sec))
|
||||
return new (this->MAlloc.Allocate()) MergeInputSection<ELFT>(this, &Sec);
|
||||
return new (this->Alloc) InputSection<ELFT>(this, &Sec);
|
||||
return new (MAlloc.Allocate()) MergeInputSection<ELFT>(this, &Sec);
|
||||
return new (Alloc) InputSection<ELFT>(this, &Sec);
|
||||
}
|
||||
|
||||
template <class ELFT> void elf2::ObjectFile<ELFT>::initializeSymbols() {
|
||||
template <class ELFT> void ObjectFile<ELFT>::initializeSymbols() {
|
||||
this->initStringTable();
|
||||
Elf_Sym_Range Syms = this->getNonLocalSymbols();
|
||||
uint32_t NumSymbols = std::distance(Syms.begin(), Syms.end());
|
||||
this->SymbolBodies.reserve(NumSymbols);
|
||||
SymbolBodies.reserve(NumSymbols);
|
||||
for (const Elf_Sym &Sym : Syms)
|
||||
this->SymbolBodies.push_back(createSymbolBody(this->StringTable, &Sym));
|
||||
SymbolBodies.push_back(createSymbolBody(this->StringTable, &Sym));
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
InputSectionBase<ELFT> *
|
||||
elf2::ObjectFile<ELFT>::getSection(const Elf_Sym &Sym) const {
|
||||
ObjectFile<ELFT>::getSection(const Elf_Sym &Sym) const {
|
||||
uint32_t Index = this->getSectionIndex(Sym);
|
||||
if (Index == 0)
|
||||
return nullptr;
|
||||
@ -282,19 +280,19 @@ elf2::ObjectFile<ELFT>::getSection(const Elf_Sym &Sym) const {
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
SymbolBody *elf2::ObjectFile<ELFT>::createSymbolBody(StringRef StringTable,
|
||||
SymbolBody *ObjectFile<ELFT>::createSymbolBody(StringRef StringTable,
|
||||
const Elf_Sym *Sym) {
|
||||
ErrorOr<StringRef> NameOrErr = Sym->getName(StringTable);
|
||||
error(NameOrErr.getError());
|
||||
error(NameOrErr);
|
||||
StringRef Name = *NameOrErr;
|
||||
|
||||
switch (Sym->st_shndx) {
|
||||
case SHN_UNDEF:
|
||||
return new (this->Alloc) UndefinedElf<ELFT>(Name, *Sym);
|
||||
return new (Alloc) UndefinedElf<ELFT>(Name, *Sym);
|
||||
case SHN_COMMON:
|
||||
return new (this->Alloc) DefinedCommon(
|
||||
Name, Sym->st_size, Sym->st_value,
|
||||
Sym->getBinding() == llvm::ELF::STB_WEAK, Sym->getVisibility());
|
||||
return new (Alloc) DefinedCommon(Name, Sym->st_size, Sym->st_value,
|
||||
Sym->getBinding() == llvm::ELF::STB_WEAK,
|
||||
Sym->getVisibility());
|
||||
}
|
||||
|
||||
switch (Sym->getBinding()) {
|
||||
@ -305,20 +303,16 @@ SymbolBody *elf2::ObjectFile<ELFT>::createSymbolBody(StringRef StringTable,
|
||||
case STB_GNU_UNIQUE: {
|
||||
InputSectionBase<ELFT> *Sec = getSection(*Sym);
|
||||
if (Sec == &InputSection<ELFT>::Discarded)
|
||||
return new (this->Alloc) UndefinedElf<ELFT>(Name, *Sym);
|
||||
return new (this->Alloc) DefinedRegular<ELFT>(Name, *Sym, Sec);
|
||||
return new (Alloc) UndefinedElf<ELFT>(Name, *Sym);
|
||||
return new (Alloc) DefinedRegular<ELFT>(Name, *Sym, Sec);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static std::unique_ptr<Archive> openArchive(MemoryBufferRef MB) {
|
||||
ErrorOr<std::unique_ptr<Archive>> ArchiveOrErr = Archive::create(MB);
|
||||
error(ArchiveOrErr, "Failed to parse archive");
|
||||
return std::move(*ArchiveOrErr);
|
||||
}
|
||||
|
||||
void ArchiveFile::parse() {
|
||||
File = openArchive(MB);
|
||||
ErrorOr<std::unique_ptr<Archive>> FileOrErr = Archive::create(MB);
|
||||
error(FileOrErr, "Failed to parse archive");
|
||||
File = std::move(*FileOrErr);
|
||||
|
||||
// Allocate a buffer for Lazy objects.
|
||||
size_t NumSyms = File->getNumberOfSymbols();
|
||||
@ -345,28 +339,9 @@ MemoryBufferRef ArchiveFile::getMember(const Archive::Symbol *Sym) {
|
||||
return *RefOrErr;
|
||||
}
|
||||
|
||||
std::vector<MemoryBufferRef> ArchiveFile::getMembers() {
|
||||
File = openArchive(MB);
|
||||
|
||||
std::vector<MemoryBufferRef> Result;
|
||||
for (auto &ChildOrErr : File->children()) {
|
||||
error(ChildOrErr,
|
||||
"Could not get the child of the archive " + File->getFileName());
|
||||
const Archive::Child Child(*ChildOrErr);
|
||||
ErrorOr<MemoryBufferRef> MbOrErr = Child.getMemoryBufferRef();
|
||||
if (!MbOrErr)
|
||||
error(MbOrErr, "Could not get the buffer for a child of the archive " +
|
||||
File->getFileName());
|
||||
Result.push_back(MbOrErr.get());
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
SharedFile<ELFT>::SharedFile(MemoryBufferRef M)
|
||||
: ELFFileBase<ELFT>(Base::SharedKind, M) {
|
||||
AsNeeded = Config->AsNeeded;
|
||||
}
|
||||
: ELFFileBase<ELFT>(Base::SharedKind, M), AsNeeded(Config->AsNeeded) {}
|
||||
|
||||
template <class ELFT>
|
||||
const typename ELFFile<ELFT>::Elf_Shdr *
|
||||
@ -379,6 +354,8 @@ SharedFile<ELFT>::getSection(const Elf_Sym &Sym) const {
|
||||
return *Ret;
|
||||
}
|
||||
|
||||
// Partially parse the shared object file so that we can call
|
||||
// getSoName on this object.
|
||||
template <class ELFT> void SharedFile<ELFT>::parseSoName() {
|
||||
typedef typename ELFFile<ELFT>::Elf_Dyn Elf_Dyn;
|
||||
typedef typename ELFFile<ELFT>::uintX_t uintX_t;
|
||||
@ -405,7 +382,7 @@ template <class ELFT> void SharedFile<ELFT>::parseSoName() {
|
||||
}
|
||||
|
||||
this->initStringTable();
|
||||
this->SoName = this->getName();
|
||||
SoName = this->getName();
|
||||
|
||||
if (!DynamicSec)
|
||||
return;
|
||||
@ -418,13 +395,14 @@ template <class ELFT> void SharedFile<ELFT>::parseSoName() {
|
||||
uintX_t Val = Dyn.getVal();
|
||||
if (Val >= this->StringTable.size())
|
||||
error("Invalid DT_SONAME entry");
|
||||
this->SoName = StringRef(this->StringTable.data() + Val);
|
||||
SoName = StringRef(this->StringTable.data() + Val);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class ELFT> void SharedFile<ELFT>::parse() {
|
||||
// Fully parse the shared object file. This must be called after parseSoName().
|
||||
template <class ELFT> void SharedFile<ELFT>::parseRest() {
|
||||
Elf_Sym_Range Syms = this->getNonLocalSymbols();
|
||||
uint32_t NumSymbols = std::distance(Syms.begin(), Syms.end());
|
||||
SymbolBodies.reserve(NumSymbols);
|
||||
@ -456,7 +434,7 @@ static std::unique_ptr<InputFile> createELFFileAux(MemoryBufferRef MB) {
|
||||
}
|
||||
|
||||
template <template <class> class T>
|
||||
std::unique_ptr<InputFile> lld::elf2::createELFFile(MemoryBufferRef MB) {
|
||||
static std::unique_ptr<InputFile> createELFFile(MemoryBufferRef MB) {
|
||||
std::pair<unsigned char, unsigned char> Type = getElfArchType(MB.getBuffer());
|
||||
if (Type.second != ELF::ELFDATA2LSB && Type.second != ELF::ELFDATA2MSB)
|
||||
error("Invalid data encoding: " + MB.getBufferIdentifier());
|
||||
@ -474,6 +452,14 @@ std::unique_ptr<InputFile> lld::elf2::createELFFile(MemoryBufferRef MB) {
|
||||
error("Invalid file class: " + MB.getBufferIdentifier());
|
||||
}
|
||||
|
||||
std::unique_ptr<InputFile> elf2::createObjectFile(MemoryBufferRef MB) {
|
||||
return createELFFile<ObjectFile>(MB);
|
||||
}
|
||||
|
||||
std::unique_ptr<InputFile> elf2::createSharedFile(MemoryBufferRef MB) {
|
||||
return createELFFile<SharedFile>(MB);
|
||||
}
|
||||
|
||||
template class elf2::ELFFileBase<ELF32LE>;
|
||||
template class elf2::ELFFileBase<ELF32BE>;
|
||||
template class elf2::ELFFileBase<ELF64LE>;
|
||||
@ -488,9 +474,3 @@ template class elf2::SharedFile<ELF32LE>;
|
||||
template class elf2::SharedFile<ELF32BE>;
|
||||
template class elf2::SharedFile<ELF64LE>;
|
||||
template class elf2::SharedFile<ELF64BE>;
|
||||
|
||||
template std::unique_ptr<InputFile>
|
||||
elf2::createELFFile<ObjectFile>(MemoryBufferRef);
|
||||
|
||||
template std::unique_ptr<InputFile>
|
||||
elf2::createELFFile<SharedFile>(MemoryBufferRef);
|
||||
|
@ -101,10 +101,10 @@ template <class ELFT> class ObjectFile : public ELFFileBase<ELFT> {
|
||||
return F->kind() == Base::ObjectKind;
|
||||
}
|
||||
|
||||
ArrayRef<SymbolBody *> getSymbols() { return this->SymbolBodies; }
|
||||
ArrayRef<SymbolBody *> getSymbols() { return SymbolBodies; }
|
||||
|
||||
explicit ObjectFile(MemoryBufferRef M);
|
||||
void parse(llvm::DenseSet<StringRef> &Comdats);
|
||||
void parse(llvm::DenseSet<StringRef> &ComdatGroups);
|
||||
|
||||
ArrayRef<InputSectionBase<ELFT> *> getSections() const { return Sections; }
|
||||
InputSectionBase<ELFT> *getSection(const Elf_Sym &Sym) const;
|
||||
@ -113,7 +113,7 @@ template <class ELFT> class ObjectFile : public ELFFileBase<ELFT> {
|
||||
uint32_t FirstNonLocal = this->Symtab->sh_info;
|
||||
if (SymbolIndex < FirstNonLocal)
|
||||
return nullptr;
|
||||
return this->SymbolBodies[SymbolIndex - FirstNonLocal];
|
||||
return SymbolBodies[SymbolIndex - FirstNonLocal];
|
||||
}
|
||||
|
||||
Elf_Sym_Range getLocalSymbols();
|
||||
@ -127,7 +127,7 @@ template <class ELFT> class ObjectFile : public ELFFileBase<ELFT> {
|
||||
uint32_t getMipsGp0() const;
|
||||
|
||||
private:
|
||||
void initializeSections(llvm::DenseSet<StringRef> &Comdats);
|
||||
void initializeSections(llvm::DenseSet<StringRef> &ComdatGroups);
|
||||
void initializeSymbols();
|
||||
InputSectionBase<ELFT> *createInputSection(const Elf_Shdr &Sec);
|
||||
|
||||
@ -159,7 +159,6 @@ class ArchiveFile : public InputFile {
|
||||
MemoryBufferRef getMember(const Archive::Symbol *Sym);
|
||||
|
||||
llvm::MutableArrayRef<Lazy> getLazySymbols() { return LazySymbols; }
|
||||
std::vector<MemoryBufferRef> getMembers();
|
||||
|
||||
private:
|
||||
std::unique_ptr<Archive> File;
|
||||
@ -194,7 +193,7 @@ template <class ELFT> class SharedFile : public ELFFileBase<ELFT> {
|
||||
explicit SharedFile(MemoryBufferRef M);
|
||||
|
||||
void parseSoName();
|
||||
void parse();
|
||||
void parseRest();
|
||||
|
||||
// Used for --as-needed
|
||||
bool AsNeeded = false;
|
||||
@ -202,8 +201,8 @@ template <class ELFT> class SharedFile : public ELFFileBase<ELFT> {
|
||||
bool isNeeded() const { return !AsNeeded || IsUsed; }
|
||||
};
|
||||
|
||||
template <template <class> class T>
|
||||
std::unique_ptr<InputFile> createELFFile(MemoryBufferRef MB);
|
||||
std::unique_ptr<InputFile> createObjectFile(MemoryBufferRef MB);
|
||||
std::unique_ptr<InputFile> createSharedFile(MemoryBufferRef MB);
|
||||
|
||||
} // namespace elf2
|
||||
} // namespace lld
|
||||
|
@ -93,6 +93,10 @@ InputSectionBase<ELFT>
|
||||
InputSectionBase<ELFT>::Discarded(nullptr, nullptr,
|
||||
InputSectionBase<ELFT>::Regular);
|
||||
|
||||
// Usually sections are copied to the output as atomic chunks of data,
|
||||
// but some special types of sections are split into small pieces of data
|
||||
// and each piece is copied to a different place in the output.
|
||||
// This class represents such special sections.
|
||||
template <class ELFT> class SplitInputSection : public InputSectionBase<ELFT> {
|
||||
typedef typename llvm::object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr;
|
||||
typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t;
|
||||
@ -100,7 +104,11 @@ template <class ELFT> class SplitInputSection : public InputSectionBase<ELFT> {
|
||||
public:
|
||||
SplitInputSection(ObjectFile<ELFT> *File, const Elf_Shdr *Header,
|
||||
typename InputSectionBase<ELFT>::Kind SectionKind);
|
||||
|
||||
// For each piece of data, we maintain the offsets in the input section and
|
||||
// in the output section. The latter may be -1 if it is not assigned yet.
|
||||
std::vector<std::pair<uintX_t, uintX_t>> Offsets;
|
||||
|
||||
std::pair<std::pair<uintX_t, uintX_t> *, uintX_t>
|
||||
getRangeAndSize(uintX_t Offset);
|
||||
};
|
||||
|
@ -16,7 +16,7 @@
|
||||
// by default. Starting with GC-root symbols or sections, markLive function
|
||||
// defined in this file visits all reachable sections to set their Live
|
||||
// bits. Writer will then ignore sections whose Live bits are off, so that
|
||||
// such sections are removed from output.
|
||||
// such sections are not included into output.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
@ -37,7 +37,7 @@ using namespace llvm::object;
|
||||
using namespace lld;
|
||||
using namespace lld::elf2;
|
||||
|
||||
// Calls Fn for each section that Sec refers to.
|
||||
// Calls Fn for each section that Sec refers to via relocations.
|
||||
template <class ELFT>
|
||||
static void forEachSuccessor(InputSection<ELFT> *Sec,
|
||||
std::function<void(InputSectionBase<ELFT> *)> Fn) {
|
||||
@ -104,7 +104,7 @@ template <class ELFT> void lld::elf2::markLive(SymbolTable<ELFT> *Symtab) {
|
||||
MarkSymbol(Symtab->find(S));
|
||||
|
||||
// Preserve externally-visible symbols if the symbols defined by this
|
||||
// file could override other ELF file's symbols at runtime.
|
||||
// file can interrupt other ELF file's symbols at runtime.
|
||||
if (Config->Shared || Config->ExportDynamic) {
|
||||
for (const std::pair<StringRef, Symbol *> &P : Symtab->getSymbols()) {
|
||||
SymbolBody *B = P.second->Body;
|
||||
|
@ -239,14 +239,13 @@ bool RelocationSection<ELFT>::applyTlsDynamicReloc(SymbolBody *Body,
|
||||
}
|
||||
|
||||
template <class ELFT> void RelocationSection<ELFT>::writeTo(uint8_t *Buf) {
|
||||
const unsigned EntrySize = IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel);
|
||||
for (const DynamicReloc<ELFT> &Rel : Relocs) {
|
||||
auto *P = reinterpret_cast<Elf_Rel *>(Buf);
|
||||
Buf += EntrySize;
|
||||
Buf += IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel);
|
||||
|
||||
// Skip placeholder for global dynamic TLS relocation pair. It was already
|
||||
// handled by the previous relocation.
|
||||
if (!Rel.C || !Rel.RI)
|
||||
if (!Rel.C)
|
||||
continue;
|
||||
|
||||
InputSectionBase<ELFT> &C = *Rel.C;
|
||||
@ -262,16 +261,16 @@ template <class ELFT> void RelocationSection<ELFT>::writeTo(uint8_t *Buf) {
|
||||
continue;
|
||||
bool NeedsCopy = Body && Target->needsCopyRel(Type, *Body);
|
||||
bool NeedsGot = Body && Target->relocNeedsGot(Type, *Body);
|
||||
bool CanBePreempted = canBePreempted(Body, NeedsGot);
|
||||
bool CBP = canBePreempted(Body, NeedsGot);
|
||||
bool LazyReloc = Body && Target->supportsLazyRelocations() &&
|
||||
Target->relocNeedsPlt(Type, *Body);
|
||||
bool IsDynRelative = Type == Target->getRelativeReloc();
|
||||
|
||||
unsigned Sym = CanBePreempted ? Body->DynamicSymbolTableIndex : 0;
|
||||
unsigned Sym = CBP ? Body->DynamicSymbolTableIndex : 0;
|
||||
unsigned Reloc;
|
||||
if (!CanBePreempted && Body && isGnuIFunc<ELFT>(*Body))
|
||||
if (!CBP && Body && isGnuIFunc<ELFT>(*Body))
|
||||
Reloc = Target->getIRelativeReloc();
|
||||
else if (!CanBePreempted || IsDynRelative)
|
||||
else if (!CBP || IsDynRelative)
|
||||
Reloc = Target->getRelativeReloc();
|
||||
else if (LazyReloc)
|
||||
Reloc = Target->getPltReloc();
|
||||
@ -289,7 +288,7 @@ template <class ELFT> void RelocationSection<ELFT>::writeTo(uint8_t *Buf) {
|
||||
P->r_offset = Out<ELFT>::Got->getEntryAddr(*Body);
|
||||
else if (NeedsCopy)
|
||||
P->r_offset = Out<ELFT>::Bss->getVA() +
|
||||
dyn_cast<SharedSymbol<ELFT>>(Body)->OffsetInBSS;
|
||||
cast<SharedSymbol<ELFT>>(Body)->OffsetInBss;
|
||||
else
|
||||
P->r_offset = C.getOffset(RI.r_offset) + C.OutSec->getVA();
|
||||
|
||||
@ -300,7 +299,7 @@ template <class ELFT> void RelocationSection<ELFT>::writeTo(uint8_t *Buf) {
|
||||
uintX_t Addend;
|
||||
if (NeedsCopy)
|
||||
Addend = 0;
|
||||
else if (CanBePreempted || IsDynRelative)
|
||||
else if (CBP || IsDynRelative)
|
||||
Addend = OrigAddend;
|
||||
else if (Body)
|
||||
Addend = getSymVA<ELFT>(*Body) + OrigAddend;
|
||||
@ -640,6 +639,9 @@ template <class ELFT> void DynamicSection<ELFT>::finalize() {
|
||||
if (DtFlags1)
|
||||
++NumEntries; // DT_FLAGS_1
|
||||
|
||||
if (!Config->Entry.empty())
|
||||
++NumEntries; // DT_DEBUG
|
||||
|
||||
if (Config->EMachine == EM_MIPS) {
|
||||
++NumEntries; // DT_MIPS_RLD_VERSION
|
||||
++NumEntries; // DT_MIPS_FLAGS
|
||||
@ -738,6 +740,8 @@ template <class ELFT> void DynamicSection<ELFT>::writeTo(uint8_t *Buf) {
|
||||
WriteVal(DT_FLAGS, DtFlags);
|
||||
if (DtFlags1)
|
||||
WriteVal(DT_FLAGS_1, DtFlags1);
|
||||
if (!Config->Entry.empty())
|
||||
WriteVal(DT_DEBUG, 0);
|
||||
|
||||
// See "Dynamic Section" in Chapter 5 in the following document
|
||||
// for detailed description:
|
||||
@ -799,11 +803,11 @@ typename ELFFile<ELFT>::uintX_t lld::elf2::getSymVA(const SymbolBody &S) {
|
||||
return SC->OutSec->getVA() + SC->getOffset(DR.Sym);
|
||||
}
|
||||
case SymbolBody::DefinedCommonKind:
|
||||
return Out<ELFT>::Bss->getVA() + cast<DefinedCommon>(S).OffsetInBSS;
|
||||
return Out<ELFT>::Bss->getVA() + cast<DefinedCommon>(S).OffsetInBss;
|
||||
case SymbolBody::SharedKind: {
|
||||
auto &SS = cast<SharedSymbol<ELFT>>(S);
|
||||
if (SS.NeedsCopy)
|
||||
return Out<ELFT>::Bss->getVA() + SS.OffsetInBSS;
|
||||
return Out<ELFT>::Bss->getVA() + SS.OffsetInBss;
|
||||
return 0;
|
||||
}
|
||||
case SymbolBody::UndefinedElfKind:
|
||||
@ -1119,9 +1123,9 @@ void MergeOutputSection<ELFT>::addSection(InputSectionBase<ELFT> *C) {
|
||||
ArrayRef<uint8_t> D = S->getSectionData();
|
||||
StringRef Data((const char *)D.data(), D.size());
|
||||
uintX_t EntSize = S->getSectionHdr()->sh_entsize;
|
||||
uintX_t Offset = 0;
|
||||
|
||||
if (this->Header.sh_flags & SHF_STRINGS) {
|
||||
uintX_t Offset = 0;
|
||||
while (!Data.empty()) {
|
||||
size_t End = findNull(Data, EntSize);
|
||||
if (End == StringRef::npos)
|
||||
@ -1139,8 +1143,7 @@ void MergeOutputSection<ELFT>::addSection(InputSectionBase<ELFT> *C) {
|
||||
for (unsigned I = 0, N = Data.size(); I != N; I += EntSize) {
|
||||
StringRef Entry = Data.substr(I, EntSize);
|
||||
size_t OutputOffset = Builder.add(Entry);
|
||||
S->Offsets.push_back(std::make_pair(Offset, OutputOffset));
|
||||
Offset += EntSize;
|
||||
S->Offsets.push_back(std::make_pair(I, OutputOffset));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,7 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Symbol table is a bag of all known symbols. We put all symbols of
|
||||
// all input files to the symbol table. The symbol Table is basically
|
||||
// all input files to the symbol table. The symbol table is basically
|
||||
// a hash table with the logic to resolve symbol name conflicts using
|
||||
// the symbol types.
|
||||
//
|
||||
@ -28,6 +28,9 @@ using namespace lld::elf2;
|
||||
|
||||
template <class ELFT> SymbolTable<ELFT>::SymbolTable() {}
|
||||
|
||||
// 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 void checkCompatibility(InputFile *FileP) {
|
||||
auto *F = dyn_cast<ELFFileBase<ELFT>>(FileP);
|
||||
@ -42,6 +45,7 @@ static void checkCompatibility(InputFile *FileP) {
|
||||
error(A + " is incompatible with " + B);
|
||||
}
|
||||
|
||||
// Add symbols in File to the symbol table.
|
||||
template <class ELFT>
|
||||
void SymbolTable<ELFT>::addFile(std::unique_ptr<InputFile> File) {
|
||||
InputFile *FileP = File.get();
|
||||
@ -64,7 +68,7 @@ void SymbolTable<ELFT>::addFile(std::unique_ptr<InputFile> File) {
|
||||
return;
|
||||
|
||||
SharedFiles.emplace_back(cast<SharedFile<ELFT>>(File.release()));
|
||||
F->parse();
|
||||
F->parseRest();
|
||||
for (SharedSymbol<ELFT> &B : F->getSharedSymbols())
|
||||
resolve(&B);
|
||||
return;
|
||||
@ -73,7 +77,7 @@ void SymbolTable<ELFT>::addFile(std::unique_ptr<InputFile> File) {
|
||||
// .o file
|
||||
auto *F = cast<ObjectFile<ELFT>>(FileP);
|
||||
ObjectFiles.emplace_back(cast<ObjectFile<ELFT>>(File.release()));
|
||||
F->parse(Comdats);
|
||||
F->parse(ComdatGroups);
|
||||
for (SymbolBody *B : F->getSymbols())
|
||||
resolve(B);
|
||||
}
|
||||
@ -109,6 +113,9 @@ void SymbolTable<ELFT>::addSynthetic(StringRef Name,
|
||||
resolve(Sym);
|
||||
}
|
||||
|
||||
// Add Name as an "ignored" symbol. An ignored symbol is a regular
|
||||
// linker-synthesized defined symbol, but it is not recorded to the output
|
||||
// file's symbol table. Such symbols are useful for some linker-defined symbols.
|
||||
template <class ELFT>
|
||||
SymbolBody *SymbolTable<ELFT>::addIgnored(StringRef Name) {
|
||||
auto *Sym = new (Alloc)
|
||||
@ -117,18 +124,10 @@ SymbolBody *SymbolTable<ELFT>::addIgnored(StringRef Name) {
|
||||
return Sym;
|
||||
}
|
||||
|
||||
template <class ELFT> bool SymbolTable<ELFT>::isUndefined(StringRef Name) {
|
||||
if (SymbolBody *Sym = find(Name))
|
||||
return Sym->isUndefined();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Returns a file from which symbol B was created.
|
||||
// If B does not belong to any file in ObjectFiles, returns a nullptr.
|
||||
// If B does not belong to any file, returns a nullptr.
|
||||
template <class ELFT>
|
||||
ELFFileBase<ELFT> *
|
||||
elf2::findFile(ArrayRef<std::unique_ptr<ObjectFile<ELFT>>> ObjectFiles,
|
||||
const SymbolBody *B) {
|
||||
ELFFileBase<ELFT> *SymbolTable<ELFT>::findFile(SymbolBody *B) {
|
||||
for (const std::unique_ptr<ObjectFile<ELFT>> &F : ObjectFiles) {
|
||||
ArrayRef<SymbolBody *> Syms = F->getSymbols();
|
||||
if (std::find(Syms.begin(), Syms.end(), B) != Syms.end())
|
||||
@ -139,8 +138,8 @@ elf2::findFile(ArrayRef<std::unique_ptr<ObjectFile<ELFT>>> ObjectFiles,
|
||||
|
||||
template <class ELFT>
|
||||
std::string SymbolTable<ELFT>::conflictMsg(SymbolBody *Old, SymbolBody *New) {
|
||||
ELFFileBase<ELFT> *OldFile = findFile<ELFT>(ObjectFiles, Old);
|
||||
ELFFileBase<ELFT> *NewFile = findFile<ELFT>(ObjectFiles, New);
|
||||
ELFFileBase<ELFT> *OldFile = findFile(Old);
|
||||
ELFFileBase<ELFT> *NewFile = findFile(New);
|
||||
|
||||
StringRef Sym = Old->getName();
|
||||
StringRef F1 = OldFile ? OldFile->getName() : "(internal)";
|
||||
@ -173,15 +172,15 @@ template <class ELFT> void SymbolTable<ELFT>::resolve(SymbolBody *New) {
|
||||
|
||||
// compare() returns -1, 0, or 1 if the lhs symbol is less preferable,
|
||||
// equivalent (conflicting), or more preferable, respectively.
|
||||
int comp = Existing->compare<ELFT>(New);
|
||||
if (comp == 0) {
|
||||
int Comp = Existing->compare<ELFT>(New);
|
||||
if (Comp == 0) {
|
||||
std::string S = "duplicate symbol: " + conflictMsg(Existing, New);
|
||||
if (!Config->AllowMultipleDefinition)
|
||||
error(S);
|
||||
warning(S);
|
||||
return;
|
||||
}
|
||||
if (comp < 0)
|
||||
if (Comp < 0)
|
||||
Sym->Body = New;
|
||||
}
|
||||
|
||||
@ -248,20 +247,7 @@ template <class ELFT> void SymbolTable<ELFT>::scanShlibUndefined() {
|
||||
Sym->setUsedInDynamicReloc();
|
||||
}
|
||||
|
||||
template class lld::elf2::SymbolTable<ELF32LE>;
|
||||
template class lld::elf2::SymbolTable<ELF32BE>;
|
||||
template class lld::elf2::SymbolTable<ELF64LE>;
|
||||
template class lld::elf2::SymbolTable<ELF64BE>;
|
||||
|
||||
template ELFFileBase<ELF32LE> *
|
||||
lld::elf2::findFile(ArrayRef<std::unique_ptr<ObjectFile<ELF32LE>>>,
|
||||
const SymbolBody *);
|
||||
template ELFFileBase<ELF32BE> *
|
||||
lld::elf2::findFile(ArrayRef<std::unique_ptr<ObjectFile<ELF32BE>>>,
|
||||
const SymbolBody *);
|
||||
template ELFFileBase<ELF64LE> *
|
||||
lld::elf2::findFile(ArrayRef<std::unique_ptr<ObjectFile<ELF64LE>>>,
|
||||
const SymbolBody *);
|
||||
template ELFFileBase<ELF64BE> *
|
||||
lld::elf2::findFile(ArrayRef<std::unique_ptr<ObjectFile<ELF64BE>>>,
|
||||
const SymbolBody *);
|
||||
template class elf2::SymbolTable<ELF32LE>;
|
||||
template class elf2::SymbolTable<ELF32BE>;
|
||||
template class elf2::SymbolTable<ELF64LE>;
|
||||
template class elf2::SymbolTable<ELF64BE>;
|
||||
|
@ -55,9 +55,9 @@ template <class ELFT> class SymbolTable {
|
||||
void addSynthetic(StringRef Name, OutputSectionBase<ELFT> &Section,
|
||||
typename llvm::object::ELFFile<ELFT>::uintX_t Value);
|
||||
SymbolBody *addIgnored(StringRef Name);
|
||||
bool isUndefined(StringRef Name);
|
||||
void scanShlibUndefined();
|
||||
SymbolBody *find(StringRef Name);
|
||||
ELFFileBase<ELFT> *findFile(SymbolBody *B);
|
||||
|
||||
private:
|
||||
Symbol *insert(SymbolBody *New);
|
||||
@ -78,7 +78,7 @@ template <class ELFT> class SymbolTable {
|
||||
llvm::MapVector<StringRef, Symbol *> Symtab;
|
||||
llvm::BumpPtrAllocator Alloc;
|
||||
|
||||
llvm::DenseSet<StringRef> Comdats;
|
||||
llvm::DenseSet<StringRef> ComdatGroups;
|
||||
|
||||
// The writer needs to infer the machine type from the object files.
|
||||
std::vector<std::unique_ptr<ObjectFile<ELFT>>> ObjectFiles;
|
||||
@ -87,11 +87,6 @@ template <class ELFT> class SymbolTable {
|
||||
llvm::DenseSet<StringRef> IncludedSoNames;
|
||||
};
|
||||
|
||||
template <class ELFT>
|
||||
ELFFileBase<ELFT> *
|
||||
findFile(ArrayRef<std::unique_ptr<ObjectFile<ELFT>>> ObjectFiles,
|
||||
const SymbolBody *B);
|
||||
|
||||
} // namespace elf2
|
||||
} // namespace lld
|
||||
|
||||
|
@ -115,8 +115,7 @@ std::unique_ptr<InputFile> Lazy::getMember() {
|
||||
// read from the library.
|
||||
if (MBRef.getBuffer().empty())
|
||||
return std::unique_ptr<InputFile>(nullptr);
|
||||
|
||||
return createELFFile<ObjectFile>(MBRef);
|
||||
return createObjectFile(MBRef);
|
||||
}
|
||||
|
||||
template <class ELFT> static void doInitSymbols() {
|
||||
|
@ -173,7 +173,7 @@ class DefinedCommon : public Defined {
|
||||
|
||||
// The output offset of this common symbol in the output bss. Computed by the
|
||||
// writer.
|
||||
uint64_t OffsetInBSS;
|
||||
uint64_t OffsetInBss;
|
||||
|
||||
// The maximum alignment we have seen for this symbol.
|
||||
uint64_t MaxAlignment;
|
||||
@ -262,9 +262,9 @@ template <class ELFT> class SharedSymbol : public DefinedElf<ELFT> {
|
||||
SharedFile<ELFT> *File;
|
||||
|
||||
// True if the linker has to generate a copy relocation for this shared
|
||||
// symbol. OffsetInBSS is significant only when NeedsCopy is true.
|
||||
// symbol. OffsetInBss is significant only when NeedsCopy is true.
|
||||
bool NeedsCopy = false;
|
||||
uintX_t OffsetInBSS = 0;
|
||||
uintX_t OffsetInBss = 0;
|
||||
};
|
||||
|
||||
// This class represents a symbol defined in an archive file. It is
|
||||
|
@ -320,7 +320,7 @@ void X86TargetInfo::writePltZeroEntry(uint8_t *Buf, uint64_t GotEntryAddr,
|
||||
// separate procedure linkage tables.
|
||||
if (Config->Shared) {
|
||||
const uint8_t V[] = {
|
||||
0xff, 0xb3, 0x04, 0x00, 0x00, 0x00, // pushl 4(%ebx
|
||||
0xff, 0xb3, 0x04, 0x00, 0x00, 0x00, // pushl 4(%ebx)
|
||||
0xff, 0xa3, 0x08, 0x00, 0x00, 0x00, // jmp *8(%ebx)
|
||||
0x90, 0x90, 0x90, 0x90 // nop;nop;nop;nop
|
||||
};
|
||||
|
@ -69,7 +69,7 @@ template <class ELFT> class Writer {
|
||||
}
|
||||
int getPhdrsNum() const;
|
||||
|
||||
OutputSection<ELFT> *getBSS();
|
||||
OutputSection<ELFT> *getBss();
|
||||
void addCommonSymbols(std::vector<DefinedCommon *> &Syms);
|
||||
void addCopyRelSymbols(std::vector<SharedSymbol<ELFT> *> &Syms);
|
||||
|
||||
@ -330,18 +330,17 @@ void Writer<ELFT>::scanRelocs(InputSectionBase<ELFT> &S,
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
static void reportUndefined(const SymbolTable<ELFT> &S, const SymbolBody &Sym) {
|
||||
static void reportUndefined(SymbolTable<ELFT> &Symtab, SymbolBody *Sym) {
|
||||
if (Config->Shared && !Config->NoUndefined)
|
||||
return;
|
||||
|
||||
ELFFileBase<ELFT> *SymFile = findFile<ELFT>(S.getObjectFiles(), &Sym);
|
||||
std::string Message = "undefined symbol: " + Sym.getName().str();
|
||||
if (SymFile)
|
||||
Message += " in " + SymFile->getName().str();
|
||||
std::string Msg = "undefined symbol: " + Sym->getName().str();
|
||||
if (ELFFileBase<ELFT> *File = Symtab.findFile(Sym))
|
||||
Msg += " in " + File->getName().str();
|
||||
if (Config->NoInhibitExec)
|
||||
warning(Message);
|
||||
warning(Msg);
|
||||
else
|
||||
error(Message);
|
||||
error(Msg);
|
||||
}
|
||||
|
||||
// Local symbols are not in the linker's symbol table. This function scans
|
||||
@ -466,7 +465,7 @@ static bool compareOutputSections(OutputSectionBase<ELFT> *A,
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class ELFT> OutputSection<ELFT> *Writer<ELFT>::getBSS() {
|
||||
template <class ELFT> OutputSection<ELFT> *Writer<ELFT>::getBss() {
|
||||
if (!Out<ELFT>::Bss) {
|
||||
Out<ELFT>::Bss =
|
||||
new OutputSection<ELFT>(".bss", SHT_NOBITS, SHF_ALLOC | SHF_WRITE);
|
||||
@ -480,8 +479,6 @@ template <class ELFT> OutputSection<ELFT> *Writer<ELFT>::getBSS() {
|
||||
// This function adds them to end of BSS section.
|
||||
template <class ELFT>
|
||||
void Writer<ELFT>::addCommonSymbols(std::vector<DefinedCommon *> &Syms) {
|
||||
typedef typename ELFFile<ELFT>::uintX_t uintX_t;
|
||||
|
||||
if (Syms.empty())
|
||||
return;
|
||||
|
||||
@ -491,11 +488,11 @@ void Writer<ELFT>::addCommonSymbols(std::vector<DefinedCommon *> &Syms) {
|
||||
return A->MaxAlignment > B->MaxAlignment;
|
||||
});
|
||||
|
||||
uintX_t Off = getBSS()->getSize();
|
||||
uintX_t Off = getBss()->getSize();
|
||||
for (DefinedCommon *C : Syms) {
|
||||
uintX_t Align = C->MaxAlignment;
|
||||
Off = RoundUpToAlignment(Off, Align);
|
||||
C->OffsetInBSS = Off;
|
||||
C->OffsetInBss = Off;
|
||||
Off += C->Size;
|
||||
}
|
||||
|
||||
@ -507,7 +504,7 @@ template <class ELFT>
|
||||
void Writer<ELFT>::addCopyRelSymbols(std::vector<SharedSymbol<ELFT> *> &Syms) {
|
||||
if (Syms.empty())
|
||||
return;
|
||||
uintX_t Off = getBSS()->getSize();
|
||||
uintX_t Off = getBss()->getSize();
|
||||
for (SharedSymbol<ELFT> *C : Syms) {
|
||||
const Elf_Sym &Sym = C->Sym;
|
||||
const Elf_Shdr *Sec = C->File->getSection(Sym);
|
||||
@ -518,7 +515,7 @@ void Writer<ELFT>::addCopyRelSymbols(std::vector<SharedSymbol<ELFT> *> &Syms) {
|
||||
uintX_t Align = 1 << TrailingZeros;
|
||||
Out<ELFT>::Bss->updateAlign(Align);
|
||||
Off = RoundUpToAlignment(Off, Align);
|
||||
C->OffsetInBSS = Off;
|
||||
C->OffsetInBss = Off;
|
||||
Off += Sym.st_size;
|
||||
}
|
||||
Out<ELFT>::Bss->setSize(Off);
|
||||
@ -803,7 +800,7 @@ template <class ELFT> void Writer<ELFT>::createSections() {
|
||||
SymbolBody *Body = P.second->Body;
|
||||
if (auto *U = dyn_cast<Undefined>(Body))
|
||||
if (!U->isWeak() && !U->canKeepUndefined())
|
||||
reportUndefined<ELFT>(Symtab, *Body);
|
||||
reportUndefined<ELFT>(Symtab, Body);
|
||||
|
||||
if (auto *C = dyn_cast<DefinedCommon>(Body))
|
||||
CommonSymbols.push_back(C);
|
||||
@ -958,10 +955,12 @@ void Writer<ELFT>::addStartStopSymbols(OutputSectionBase<ELFT> *Sec) {
|
||||
StringSaver Saver(Alloc);
|
||||
StringRef Start = Saver.save("__start_" + S);
|
||||
StringRef Stop = Saver.save("__stop_" + S);
|
||||
if (Symtab.isUndefined(Start))
|
||||
Symtab.addSynthetic(Start, *Sec, 0);
|
||||
if (Symtab.isUndefined(Stop))
|
||||
Symtab.addSynthetic(Stop, *Sec, Sec->getSize());
|
||||
if (SymbolBody *B = Symtab.find(Start))
|
||||
if (B->isUndefined())
|
||||
Symtab.addSynthetic(Start, *Sec, 0);
|
||||
if (SymbolBody *B = Symtab.find(Stop))
|
||||
if (B->isUndefined())
|
||||
Symtab.addSynthetic(Stop, *Sec, Sec->getSize());
|
||||
}
|
||||
|
||||
template <class ELFT> static bool needsPhdr(OutputSectionBase<ELFT> *Sec) {
|
||||
@ -1016,7 +1015,7 @@ template <class ELFT> void Writer<ELFT>::assignAddresses() {
|
||||
Elf_Phdr GnuRelroPhdr = {};
|
||||
Elf_Phdr TlsPhdr{};
|
||||
bool RelroAligned = false;
|
||||
uintX_t ThreadBSSOffset = 0;
|
||||
uintX_t ThreadBssOffset = 0;
|
||||
// Create phdrs as we assign VAs and file offsets to all output sections.
|
||||
for (OutputSectionBase<ELFT> *Sec : OutputSections) {
|
||||
Elf_Phdr *PH = &Phdrs[PhdrIdx];
|
||||
@ -1042,11 +1041,11 @@ template <class ELFT> void Writer<ELFT>::assignAddresses() {
|
||||
setPhdr(&TlsPhdr, PT_TLS, PF_R, FileOff, VA, 0, Sec->getAlign());
|
||||
if (Sec->getType() != SHT_NOBITS)
|
||||
VA = RoundUpToAlignment(VA, Sec->getAlign());
|
||||
uintX_t TVA = RoundUpToAlignment(VA + ThreadBSSOffset, Sec->getAlign());
|
||||
uintX_t TVA = RoundUpToAlignment(VA + ThreadBssOffset, Sec->getAlign());
|
||||
Sec->setVA(TVA);
|
||||
TlsPhdr.p_memsz += Sec->getSize();
|
||||
if (Sec->getType() == SHT_NOBITS) {
|
||||
ThreadBSSOffset = TVA - VA + Sec->getSize();
|
||||
ThreadBssOffset = TVA - VA + Sec->getSize();
|
||||
} else {
|
||||
TlsPhdr.p_filesz += Sec->getSize();
|
||||
VA += Sec->getSize();
|
||||
|
@ -507,6 +507,23 @@ void ArchHandler_arm64::generateAtomContent(
|
||||
// Copy raw bytes.
|
||||
memcpy(atomContentBuffer, atom.rawContent().data(), atom.size());
|
||||
// Apply fix-ups.
|
||||
#ifndef NDEBUG
|
||||
if (atom.begin() != atom.end()) {
|
||||
DEBUG_WITH_TYPE("atom-content", llvm::dbgs()
|
||||
<< "Applying fixups to atom:\n"
|
||||
<< " address="
|
||||
<< llvm::format(" 0x%09lX", &atom)
|
||||
<< ", file=#"
|
||||
<< atom.file().ordinal()
|
||||
<< ", atom=#"
|
||||
<< atom.ordinal()
|
||||
<< ", name="
|
||||
<< atom.name()
|
||||
<< ", type="
|
||||
<< atom.contentType()
|
||||
<< "\n");
|
||||
}
|
||||
#endif
|
||||
for (const Reference *ref : atom) {
|
||||
uint32_t offset = ref->offsetInAtom();
|
||||
const Atom *target = ref->target();
|
||||
|
@ -647,13 +647,33 @@ void ArchHandler_x86_64::applyFixupRelocatable(const Reference &ref,
|
||||
*loc32 = ref.addend() + inAtomAddress - fixupAddress;
|
||||
return;
|
||||
case delta32Anon:
|
||||
*loc32 = (targetAddress - fixupAddress) + ref.addend();
|
||||
// The value we write here should be the the delta to the target
|
||||
// after taking in to account the difference from the fixup back to the
|
||||
// last defined label
|
||||
// ie, if we have:
|
||||
// _base: ...
|
||||
// Lfixup: .quad Ltarget - .
|
||||
// ...
|
||||
// Ltarget:
|
||||
//
|
||||
// Then we want to encode the value (Ltarget + addend) - (LFixup - _base)
|
||||
*loc32 = (targetAddress + ref.addend()) - (fixupAddress - inAtomAddress);
|
||||
return;
|
||||
case delta64:
|
||||
*loc64 = ref.addend() + inAtomAddress - fixupAddress;
|
||||
return;
|
||||
case delta64Anon:
|
||||
*loc64 = (targetAddress - fixupAddress) + ref.addend();
|
||||
// The value we write here should be the the delta to the target
|
||||
// after taking in to account the difference from the fixup back to the
|
||||
// last defined label
|
||||
// ie, if we have:
|
||||
// _base: ...
|
||||
// Lfixup: .quad Ltarget - .
|
||||
// ...
|
||||
// Ltarget:
|
||||
//
|
||||
// Then we want to encode the value (Ltarget + addend) - (LFixup - _base)
|
||||
*loc64 = (targetAddress + ref.addend()) - (fixupAddress - inAtomAddress);
|
||||
return;
|
||||
case negDelta32:
|
||||
*loc32 = fixupAddress - targetAddress + ref.addend();
|
||||
|
@ -406,14 +406,8 @@ bool Util::TextSectionSorter::operator()(const SectionInfo *left,
|
||||
}
|
||||
|
||||
void Util::organizeSections() {
|
||||
if (_ctx.outputMachOType() == llvm::MachO::MH_OBJECT) {
|
||||
// Leave sections ordered as normalized file specified.
|
||||
uint32_t sectionIndex = 1;
|
||||
for (SectionInfo *si : _sectionInfos) {
|
||||
si->finalSectionIndex = sectionIndex++;
|
||||
}
|
||||
} else {
|
||||
switch (_ctx.outputMachOType()) {
|
||||
// NOTE!: Keep this in sync with assignAddressesToSections.
|
||||
switch (_ctx.outputMachOType()) {
|
||||
case llvm::MachO::MH_EXECUTE:
|
||||
// Main executables, need a zero-page segment
|
||||
segmentForName("__PAGEZERO");
|
||||
@ -425,32 +419,30 @@ void Util::organizeSections() {
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
// Group sections into segments.
|
||||
for (SectionInfo *si : _sectionInfos) {
|
||||
SegmentInfo *seg = segmentForName(si->segmentName);
|
||||
seg->sections.push_back(si);
|
||||
}
|
||||
// Sort segments.
|
||||
std::sort(_segmentInfos.begin(), _segmentInfos.end(), SegmentSorter());
|
||||
}
|
||||
// Group sections into segments.
|
||||
for (SectionInfo *si : _sectionInfos) {
|
||||
SegmentInfo *seg = segmentForName(si->segmentName);
|
||||
seg->sections.push_back(si);
|
||||
}
|
||||
// Sort segments.
|
||||
std::sort(_segmentInfos.begin(), _segmentInfos.end(), SegmentSorter());
|
||||
|
||||
// Sort sections within segments.
|
||||
for (SegmentInfo *seg : _segmentInfos) {
|
||||
if (seg->name.equals("__TEXT")) {
|
||||
std::sort(seg->sections.begin(), seg->sections.end(),
|
||||
TextSectionSorter());
|
||||
}
|
||||
// Sort sections within segments.
|
||||
for (SegmentInfo *seg : _segmentInfos) {
|
||||
if (seg->name.equals("__TEXT")) {
|
||||
std::sort(seg->sections.begin(), seg->sections.end(),
|
||||
TextSectionSorter());
|
||||
}
|
||||
}
|
||||
|
||||
// Record final section indexes.
|
||||
uint32_t segmentIndex = 0;
|
||||
uint32_t sectionIndex = 1;
|
||||
for (SegmentInfo *seg : _segmentInfos) {
|
||||
seg->normalizedSegmentIndex = segmentIndex++;
|
||||
for (SectionInfo *sect : seg->sections) {
|
||||
sect->finalSectionIndex = sectionIndex++;
|
||||
}
|
||||
}
|
||||
// Record final section indexes.
|
||||
uint32_t segmentIndex = 0;
|
||||
uint32_t sectionIndex = 1;
|
||||
for (SegmentInfo *seg : _segmentInfos) {
|
||||
seg->normalizedSegmentIndex = segmentIndex++;
|
||||
for (SectionInfo *sect : seg->sections)
|
||||
sect->finalSectionIndex = sectionIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
@ -487,54 +479,39 @@ void Util::layoutSectionsInTextSegment(size_t hlcSize, SegmentInfo *seg,
|
||||
}
|
||||
|
||||
void Util::assignAddressesToSections(const NormalizedFile &file) {
|
||||
// NOTE!: Keep this in sync with organizeSections.
|
||||
size_t hlcSize = headerAndLoadCommandsSize(file);
|
||||
uint64_t address = 0;
|
||||
if (_ctx.outputMachOType() != llvm::MachO::MH_OBJECT) {
|
||||
for (SegmentInfo *seg : _segmentInfos) {
|
||||
if (seg->name.equals("__PAGEZERO")) {
|
||||
seg->size = _ctx.pageZeroSize();
|
||||
address += seg->size;
|
||||
}
|
||||
else if (seg->name.equals("__TEXT")) {
|
||||
// _ctx.baseAddress() == 0 implies it was either unspecified or
|
||||
// pageZeroSize is also 0. In either case resetting address is safe.
|
||||
address = _ctx.baseAddress() ? _ctx.baseAddress() : address;
|
||||
layoutSectionsInTextSegment(hlcSize, seg, address);
|
||||
} else
|
||||
layoutSectionsInSegment(seg, address);
|
||||
for (SegmentInfo *seg : _segmentInfos) {
|
||||
if (seg->name.equals("__PAGEZERO")) {
|
||||
seg->size = _ctx.pageZeroSize();
|
||||
address += seg->size;
|
||||
}
|
||||
else if (seg->name.equals("__TEXT")) {
|
||||
// _ctx.baseAddress() == 0 implies it was either unspecified or
|
||||
// pageZeroSize is also 0. In either case resetting address is safe.
|
||||
address = _ctx.baseAddress() ? _ctx.baseAddress() : address;
|
||||
layoutSectionsInTextSegment(hlcSize, seg, address);
|
||||
} else
|
||||
layoutSectionsInSegment(seg, address);
|
||||
|
||||
address = llvm::RoundUpToAlignment(address, _ctx.pageSize());
|
||||
}
|
||||
DEBUG_WITH_TYPE("WriterMachO-norm",
|
||||
llvm::dbgs() << "assignAddressesToSections()\n";
|
||||
for (SegmentInfo *sgi : _segmentInfos) {
|
||||
llvm::dbgs() << " address=" << llvm::format("0x%08llX", sgi->address)
|
||||
<< ", size=" << llvm::format("0x%08llX", sgi->size)
|
||||
<< ", segment-name='" << sgi->name
|
||||
<< "'\n";
|
||||
for (SectionInfo *si : sgi->sections) {
|
||||
llvm::dbgs()<< " addr=" << llvm::format("0x%08llX", si->address)
|
||||
<< ", size=" << llvm::format("0x%08llX", si->size)
|
||||
<< ", section-name='" << si->sectionName
|
||||
<< "\n";
|
||||
}
|
||||
}
|
||||
);
|
||||
} else {
|
||||
for (SectionInfo *sect : _sectionInfos) {
|
||||
sect->address = llvm::RoundUpToAlignment(address, sect->alignment);
|
||||
address = sect->address + sect->size;
|
||||
}
|
||||
DEBUG_WITH_TYPE("WriterMachO-norm",
|
||||
llvm::dbgs() << "assignAddressesToSections()\n";
|
||||
for (SectionInfo *si : _sectionInfos) {
|
||||
llvm::dbgs() << " section=" << si->sectionName
|
||||
<< " address= " << llvm::format("0x%08X", si->address)
|
||||
<< " size= " << llvm::format("0x%08X", si->size)
|
||||
<< "\n";
|
||||
}
|
||||
);
|
||||
address = llvm::RoundUpToAlignment(address, _ctx.pageSize());
|
||||
}
|
||||
DEBUG_WITH_TYPE("WriterMachO-norm",
|
||||
llvm::dbgs() << "assignAddressesToSections()\n";
|
||||
for (SegmentInfo *sgi : _segmentInfos) {
|
||||
llvm::dbgs() << " address=" << llvm::format("0x%08llX", sgi->address)
|
||||
<< ", size=" << llvm::format("0x%08llX", sgi->size)
|
||||
<< ", segment-name='" << sgi->name
|
||||
<< "'\n";
|
||||
for (SectionInfo *si : sgi->sections) {
|
||||
llvm::dbgs()<< " addr=" << llvm::format("0x%08llX", si->address)
|
||||
<< ", size=" << llvm::format("0x%08llX", si->size)
|
||||
<< ", section-name='" << si->sectionName
|
||||
<< "\n";
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
void Util::copySegmentInfo(NormalizedFile &file) {
|
||||
@ -604,16 +581,9 @@ void Util::copySectionContent(NormalizedFile &file) {
|
||||
|
||||
void Util::copySectionInfo(NormalizedFile &file) {
|
||||
file.sections.reserve(_sectionInfos.size());
|
||||
// For final linked images, write sections grouped by segment.
|
||||
if (_ctx.outputMachOType() != llvm::MachO::MH_OBJECT) {
|
||||
for (SegmentInfo *sgi : _segmentInfos) {
|
||||
for (SectionInfo *si : sgi->sections) {
|
||||
appendSection(si, file);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Object files write sections in default order.
|
||||
for (SectionInfo *si : _sectionInfos) {
|
||||
// Write sections grouped by segment.
|
||||
for (SegmentInfo *sgi : _segmentInfos) {
|
||||
for (SectionInfo *si : sgi->sections) {
|
||||
appendSection(si, file);
|
||||
}
|
||||
}
|
||||
@ -621,20 +591,12 @@ void Util::copySectionInfo(NormalizedFile &file) {
|
||||
|
||||
void Util::updateSectionInfo(NormalizedFile &file) {
|
||||
file.sections.reserve(_sectionInfos.size());
|
||||
if (_ctx.outputMachOType() != llvm::MachO::MH_OBJECT) {
|
||||
// For final linked images, sections grouped by segment.
|
||||
for (SegmentInfo *sgi : _segmentInfos) {
|
||||
Segment *normSeg = &file.segments[sgi->normalizedSegmentIndex];
|
||||
normSeg->address = sgi->address;
|
||||
normSeg->size = sgi->size;
|
||||
for (SectionInfo *si : sgi->sections) {
|
||||
Section *normSect = &file.sections[si->normalizedSectionIndex];
|
||||
normSect->address = si->address;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Object files write sections in default order.
|
||||
for (SectionInfo *si : _sectionInfos) {
|
||||
// sections grouped by segment.
|
||||
for (SegmentInfo *sgi : _segmentInfos) {
|
||||
Segment *normSeg = &file.segments[sgi->normalizedSegmentIndex];
|
||||
normSeg->address = sgi->address;
|
||||
normSeg->size = sgi->size;
|
||||
for (SectionInfo *si : sgi->sections) {
|
||||
Section *normSect = &file.sections[si->normalizedSectionIndex];
|
||||
normSect->address = si->address;
|
||||
}
|
||||
@ -663,19 +625,47 @@ void Util::buildAtomToAddressMap() {
|
||||
_entryAtom = info.atom;
|
||||
}
|
||||
DEBUG_WITH_TYPE("WriterMachO-address", llvm::dbgs()
|
||||
<< " address="
|
||||
<< llvm::format("0x%016X", _atomToAddress[info.atom])
|
||||
<< " atom=" << info.atom
|
||||
<< " name=" << info.atom->name() << "\n");
|
||||
<< " address="
|
||||
<< llvm::format("0x%016X", _atomToAddress[info.atom])
|
||||
<< llvm::format(" 0x%09lX", info.atom)
|
||||
<< ", file=#"
|
||||
<< info.atom->file().ordinal()
|
||||
<< ", atom=#"
|
||||
<< info.atom->ordinal()
|
||||
<< ", name="
|
||||
<< info.atom->name()
|
||||
<< ", type="
|
||||
<< info.atom->contentType()
|
||||
<< "\n");
|
||||
}
|
||||
}
|
||||
DEBUG_WITH_TYPE("WriterMachO-address", llvm::dbgs()
|
||||
<< "assign header alias atom addresses:\n");
|
||||
for (const Atom *atom : _machHeaderAliasAtoms) {
|
||||
_atomToAddress[atom] = _ctx.baseAddress();
|
||||
DEBUG_WITH_TYPE("WriterMachO-address", llvm::dbgs()
|
||||
<< " address="
|
||||
<< llvm::format("0x%016X", _atomToAddress[atom])
|
||||
<< " atom=" << atom
|
||||
<< " name=" << atom->name() << "\n");
|
||||
#ifndef NDEBUG
|
||||
if (auto *definedAtom = dyn_cast<DefinedAtom>(atom)) {
|
||||
DEBUG_WITH_TYPE("WriterMachO-address", llvm::dbgs()
|
||||
<< " address="
|
||||
<< llvm::format("0x%016X", _atomToAddress[atom])
|
||||
<< llvm::format(" 0x%09lX", atom)
|
||||
<< ", file=#"
|
||||
<< definedAtom->file().ordinal()
|
||||
<< ", atom=#"
|
||||
<< definedAtom->ordinal()
|
||||
<< ", name="
|
||||
<< definedAtom->name()
|
||||
<< ", type="
|
||||
<< definedAtom->contentType()
|
||||
<< "\n");
|
||||
} else {
|
||||
DEBUG_WITH_TYPE("WriterMachO-address", llvm::dbgs()
|
||||
<< " address="
|
||||
<< llvm::format("0x%016X", _atomToAddress[atom])
|
||||
<< " atom=" << atom
|
||||
<< " name=" << atom->name() << "\n");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@ -999,11 +989,9 @@ void Util::segIndexForSection(const SectionInfo *sect, uint8_t &segmentIndex,
|
||||
|
||||
uint32_t Util::sectionIndexForAtom(const Atom *atom) {
|
||||
uint64_t address = _atomToAddress[atom];
|
||||
uint32_t index = 1;
|
||||
for (const SectionInfo *si : _sectionInfos) {
|
||||
if ((si->address <= address) && (address < si->address+si->size))
|
||||
return index;
|
||||
++index;
|
||||
return si->finalSectionIndex;
|
||||
}
|
||||
llvm_unreachable("atom not in any section");
|
||||
}
|
||||
|
18
test/ELF/dt_tags.s
Normal file
18
test/ELF/dt_tags.s
Normal file
@ -0,0 +1,18 @@
|
||||
# REQUIRES: x86
|
||||
|
||||
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-freebsd %s -o %t
|
||||
# RUN: ld.lld -shared %t -o %t.so
|
||||
# RUN: ld.lld %t %t.so -o %t.exe
|
||||
# RUN: llvm-readobj -dynamic-table %t.so | FileCheck -check-prefix=DSO %s
|
||||
# RUN: llvm-readobj -dynamic-table %t.exe | FileCheck -check-prefix=EXE %s
|
||||
|
||||
# EXE: DynamicSection [
|
||||
# EXE: 0x0000000000000015 DEBUG 0x0
|
||||
# EXE: ]
|
||||
|
||||
# DSO: DynamicSection [
|
||||
# DSO-NOT: 0x0000000000000015 DEBUG 0x0
|
||||
# DSO: ]
|
||||
|
||||
.globl _start
|
||||
_start:
|
@ -53,6 +53,7 @@
|
||||
// CHECK-NEXT: 0x000000000000000A STRSZ
|
||||
// CHECK-NEXT: 0x0000000000000004 HASH
|
||||
// CHECK-NEXT: 0x0000000000000001 NEEDED SharedLibrary ({{.*}}2.so)
|
||||
// CHECK-NEXT: 0x0000000000000015 DEBUG 0x0
|
||||
// CHECK-NEXT: 0x0000000000000000 NULL 0x0
|
||||
// CHECK-NEXT: ]
|
||||
|
||||
|
@ -12,7 +12,7 @@
|
||||
// CHECK-NEXT: SHF_ALLOC
|
||||
// CHECK-NEXT: SHF_WRITE
|
||||
// CHECK-NEXT: ]
|
||||
// CHECK-NEXT: Address: 0x120A0
|
||||
// CHECK-NEXT: Address: 0x120B0
|
||||
// CHECK-NEXT: Offset:
|
||||
// CHECK-NEXT: Size: 16
|
||||
// CHECK-NEXT: Link: 0
|
||||
@ -21,22 +21,22 @@
|
||||
|
||||
// CHECK: Relocations [
|
||||
// CHECK-NEXT: Section ({{.*}}) .rela.dyn {
|
||||
// CHECK-NEXT: 0x120A0 R_X86_64_GLOB_DAT bar 0x0
|
||||
// CHECK-NEXT: 0x120A8 R_X86_64_GLOB_DAT zed 0x0
|
||||
// CHECK-NEXT: 0x120B0 R_X86_64_GLOB_DAT bar 0x0
|
||||
// CHECK-NEXT: 0x120B8 R_X86_64_GLOB_DAT zed 0x0
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: ]
|
||||
|
||||
|
||||
// Unfortunately FileCheck can't do math, so we have to check for explicit
|
||||
// values:
|
||||
// 0x120A0 - (0x11000 + 2) - 4 = 4250
|
||||
// 0x120A0 - (0x11006 + 2) - 4 = 4244
|
||||
// 0x120A8 - (0x1100c + 2) - 4 = 4246
|
||||
// 0x120B0 - (0x11000 + 2) - 4 = 4266
|
||||
// 0x120B0 - (0x11006 + 2) - 4 = 4260
|
||||
// 0x120A8 - (0x1100c + 2) - 4 = 4262
|
||||
|
||||
// DISASM: _start:
|
||||
// DISASM-NEXT: 11000: {{.*}} jmpq *4250(%rip)
|
||||
// DISASM-NEXT: 11006: {{.*}} jmpq *4244(%rip)
|
||||
// DISASM-NEXT: 1100c: {{.*}} jmpq *4246(%rip)
|
||||
// DISASM-NEXT: 11000: {{.*}} jmpq *4266(%rip)
|
||||
// DISASM-NEXT: 11006: {{.*}} jmpq *4260(%rip)
|
||||
// DISASM-NEXT: 1100c: {{.*}} jmpq *4262(%rip)
|
||||
|
||||
.global _start
|
||||
_start:
|
||||
|
@ -14,11 +14,11 @@ _start:
|
||||
foo:
|
||||
nop
|
||||
|
||||
// 0x120A0 - 0x11000 - 5 = 4251
|
||||
// 0x120A8 - 0x11005 - 5 = 4254
|
||||
// 0x120B0 - 0x11000 - 5 = 4251
|
||||
// 0x120B8 - 0x11005 - 5 = 4254
|
||||
// DISASM: _start:
|
||||
// DISASM-NEXT: 11000: {{.*}} callq 4251
|
||||
// DISASM-NEXT: 11005: {{.*}} callq 4254
|
||||
// DISASM-NEXT: 11000: {{.*}} callq 4267
|
||||
// DISASM-NEXT: 11005: {{.*}} callq 4270
|
||||
|
||||
// DISASM: foo:
|
||||
// DISASM-NEXT: 1100a: {{.*}} nop
|
||||
@ -29,7 +29,7 @@ foo:
|
||||
// CHECK-NEXT: SHF_ALLOC
|
||||
// CHECK-NEXT: SHF_WRITE
|
||||
// CHECK-NEXT: ]
|
||||
// CHECK-NEXT: Address: 0x120A0
|
||||
// CHECK-NEXT: Address: 0x120B0
|
||||
// CHECK-NEXT: Offset:
|
||||
// CHECK-NEXT: Size: 16
|
||||
// CHECK-NEXT: Link: 0
|
||||
@ -43,6 +43,6 @@ foo:
|
||||
|
||||
// CHECK: Relocations [
|
||||
// CHECK-NEXT: Section ({{.*}}) .rela.dyn {
|
||||
// CHECK-NEXT: 0x120A0 R_X86_64_GLOB_DAT bar 0x0
|
||||
// CHECK-NEXT: 0x120B0 R_X86_64_GLOB_DAT bar 0x0
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: ]
|
||||
|
@ -55,7 +55,7 @@ movl bar@GOT, %eax
|
||||
// ADDR-NEXT: SHF_ALLOC
|
||||
// ADDR-NEXT: SHF_WRITE
|
||||
// ADDR-NEXT: ]
|
||||
// ADDR-NEXT: Address: 0x12070
|
||||
// ADDR-NEXT: Address: 0x12078
|
||||
|
||||
.section .R_386_GOTPC,"ax",@progbits
|
||||
R_386_GOTPC:
|
||||
@ -65,7 +65,7 @@ R_386_GOTPC:
|
||||
|
||||
// CHECK: Disassembly of section .R_386_GOTPC:
|
||||
// CHECK-NEXT: R_386_GOTPC:
|
||||
// CHECK-NEXT: 11014: {{.*}} movl $4188, %eax
|
||||
// CHECK-NEXT: 11014: {{.*}} movl $4196, %eax
|
||||
|
||||
.section .dynamic_reloc, "ax",@progbits
|
||||
call bar
|
||||
|
@ -22,7 +22,7 @@
|
||||
// SEC-NEXT: SHF_ALLOC
|
||||
// SEC-NEXT: SHF_WRITE
|
||||
// SEC-NEXT: ]
|
||||
// SEC-NEXT: Address: 0x120E0
|
||||
// SEC-NEXT: Address: 0x120F0
|
||||
// SEC-NEXT: Offset:
|
||||
// SEC-NEXT: Size: 8
|
||||
// SEC-NEXT: Link: 0
|
||||
@ -111,7 +111,7 @@ R_X86_64_64:
|
||||
R_X86_64_GOTPCREL:
|
||||
.long zed@gotpcrel
|
||||
|
||||
// 0x120E8 - 0x101D8 = 7952
|
||||
// 0x120F8 - 0x101D8 = 7952
|
||||
// 7952 = 0x101f0000 in little endian
|
||||
// CHECK: Contents of section .R_X86_64_GOTPCREL
|
||||
// CHECK-NEXT: 101d0 101f0000
|
||||
// CHECK-NEXT: 101d0 201f0000
|
||||
|
@ -17,8 +17,8 @@
|
||||
// FULLRELRO-NEXT: SHF_ALLOC
|
||||
// FULLRELRO-NEXT: SHF_WRITE
|
||||
// FULLRELRO-NEXT: ]
|
||||
// FULLRELRO-NEXT: Address: 0x12100
|
||||
// FULLRELRO-NEXT: Offset: 0x2100
|
||||
// FULLRELRO-NEXT: Address: 0x12110
|
||||
// FULLRELRO-NEXT: Offset: 0x2110
|
||||
// FULLRELRO-NEXT: Size: 8
|
||||
// FULLRELRO-NEXT: Link: 0
|
||||
// FULLRELRO-NEXT: Info: 0
|
||||
@ -36,8 +36,8 @@
|
||||
// FULLRELRO-NEXT: SHF_ALLOC
|
||||
// FULLRELRO-NEXT: SHF_WRITE
|
||||
// FULLRELRO-NEXT: ]
|
||||
// FULLRELRO-NEXT: Address: 0x12108
|
||||
// FULLRELRO-NEXT: Offset: 0x2108
|
||||
// FULLRELRO-NEXT: Address: 0x12118
|
||||
// FULLRELRO-NEXT: Offset: 0x2118
|
||||
// FULLRELRO-NEXT: Size: 32
|
||||
// FULLRELRO-NEXT: Link: 0
|
||||
// FULLRELRO-NEXT: Info: 0
|
||||
@ -103,8 +103,8 @@
|
||||
// FULLRELRO-NEXT: Offset: 0x
|
||||
// FULLRELRO-NEXT: VirtualAddress: [[RWADDR]]
|
||||
// FULLRELRO-NEXT: PhysicalAddress:
|
||||
// FULLRELRO-NEXT: FileSize: 296
|
||||
// FULLRELRO-NEXT: MemSize: 296
|
||||
// FULLRELRO-NEXT: FileSize: 312
|
||||
// FULLRELRO-NEXT: MemSize: 312
|
||||
// FULLRELRO-NEXT: Flags [
|
||||
// FULLRELRO-NEXT: PF_R
|
||||
// FULLRELRO-NEXT: ]
|
||||
@ -119,8 +119,8 @@
|
||||
// PARTRELRO-NEXT: SHF_ALLOC
|
||||
// PARTRELRO-NEXT: SHF_WRITE
|
||||
// PARTRELRO-NEXT: ]
|
||||
// PARTRELRO-NEXT: Address: 0x120E0
|
||||
// PARTRELRO-NEXT: Offset: 0x20E0
|
||||
// PARTRELRO-NEXT: Address: 0x120F0
|
||||
// PARTRELRO-NEXT: Offset: 0x20F0
|
||||
// PARTRELRO-NEXT: Size: 8
|
||||
// PARTRELRO-NEXT: Link: 0
|
||||
// PARTRELRO-NEXT: Info: 0
|
||||
@ -219,8 +219,8 @@
|
||||
// PARTRELRO-NEXT: Offset: 0x2000
|
||||
// PARTRELRO-NEXT: VirtualAddress: [[RWADDR]]
|
||||
// PARTRELRO-NEXT: PhysicalAddress:
|
||||
// PARTRELRO-NEXT: FileSize: 232
|
||||
// PARTRELRO-NEXT: MemSize: 232
|
||||
// PARTRELRO-NEXT: FileSize: 248
|
||||
// PARTRELRO-NEXT: MemSize: 248
|
||||
// PARTRELRO-NEXT: Flags [
|
||||
// PARTRELRO-NEXT: PF_R
|
||||
// PARTRELRO-NEXT: ]
|
||||
|
@ -25,6 +25,7 @@
|
||||
// CHECK-NEXT: 0x0000000000000009 RELAENT [[RELENT]] (bytes)
|
||||
// CHECK: 0x000000000000001D RUNPATH foo:bar
|
||||
// CHECK-NEXT: 0x0000000000000001 NEEDED SharedLibrary ({{.*}}2.so)
|
||||
// CHECK-NEXT: 0x0000000000000015 DEBUG 0x0
|
||||
// CHECK-NEXT: 0x0000000000000000 NULL 0x0
|
||||
// CHECK-NEXT: ]
|
||||
|
||||
|
@ -253,6 +253,7 @@
|
||||
// CHECK-NEXT: 0x00000004 HASH [[HASHADDR]]
|
||||
// CHECK-NEXT: 0x0000001D RUNPATH foo:bar
|
||||
// CHECK-NEXT: 0x00000001 NEEDED SharedLibrary ({{.*}}2.so)
|
||||
// CHECK-NEXT: 0x00000015 DEBUG 0x0
|
||||
// CHECK-NEXT: 0x00000000 NULL 0x0
|
||||
// CHECK-NEXT: ]
|
||||
|
||||
|
@ -14,7 +14,7 @@
|
||||
// CHECK-NEXT: SHF_WRITE
|
||||
// CHECK-NEXT: ]
|
||||
// CHECK-NEXT: Address: [[ADDR:.*]]
|
||||
// CHECK-NEXT: Offset: 0x20A0
|
||||
// CHECK-NEXT: Offset: 0x20B0
|
||||
// CHECK-NEXT: Size: 16
|
||||
// CHECK-NEXT: Link: 0
|
||||
// CHECK-NEXT: Info: 0
|
||||
@ -25,20 +25,20 @@
|
||||
// CHECK: Relocations [
|
||||
// CHECK-NEXT: Section (4) .rela.dyn {
|
||||
// CHECK-NEXT: [[ADDR]] R_X86_64_TPOFF64 tls1 0x0
|
||||
// CHECK-NEXT: 0x120A8 R_X86_64_TPOFF64 tls0 0x0
|
||||
// CHECK-NEXT: 0x120B8 R_X86_64_TPOFF64 tls0 0x0
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: ]
|
||||
|
||||
//0x11000 + 4249 + 7 = 0x120A0
|
||||
//0x1100A + 4247 + 7 = 0x120A8
|
||||
//0x11014 + 4237 + 7 = 0x120A8
|
||||
//0x11000 + 4249 + 7 = 0x120B0
|
||||
//0x1100A + 4247 + 7 = 0x120B8
|
||||
//0x11014 + 4237 + 7 = 0x120B8
|
||||
//DISASM: Disassembly of section .text:
|
||||
//DISASM-NEXT: main:
|
||||
//DISASM-NEXT: 11000: 48 8b 05 99 10 00 00 movq 4249(%rip), %rax
|
||||
//DISASM-NEXT: 11000: 48 8b 05 a9 10 00 00 movq 4265(%rip), %rax
|
||||
//DISASM-NEXT: 11007: 64 8b 00 movl %fs:(%rax), %eax
|
||||
//DISASM-NEXT: 1100a: 48 8b 05 97 10 00 00 movq 4247(%rip), %rax
|
||||
//DISASM-NEXT: 1100a: 48 8b 05 a7 10 00 00 movq 4263(%rip), %rax
|
||||
//DISASM-NEXT: 11011: 64 8b 00 movl %fs:(%rax), %eax
|
||||
//DISASM-NEXT: 11014: 48 8b 05 8d 10 00 00 movq 4237(%rip), %rax
|
||||
//DISASM-NEXT: 11014: 48 8b 05 9d 10 00 00 movq 4253(%rip), %rax
|
||||
//DISASM-NEXT: 1101b: 64 8b 00 movl %fs:(%rax), %eax
|
||||
//DISASM-NEXT: 1101e: c3 retq
|
||||
|
||||
|
@ -13,8 +13,8 @@
|
||||
//RELOC-NEXT: SHF_ALLOC
|
||||
//RELOC-NEXT: SHF_WRITE
|
||||
//RELOC-NEXT: ]
|
||||
//RELOC-NEXT: Address: 0x120E0
|
||||
//RELOC-NEXT: Offset: 0x20E0
|
||||
//RELOC-NEXT: Address: 0x120F0
|
||||
//RELOC-NEXT: Offset: 0x20F0
|
||||
//RELOC-NEXT: Size: 16
|
||||
//RELOC-NEXT: Link: 0
|
||||
//RELOC-NEXT: Info: 0
|
||||
@ -23,22 +23,22 @@
|
||||
//RELOC-NEXT: }
|
||||
//RELOC: Relocations [
|
||||
//RELOC-NEXT: Section (4) .rela.dyn {
|
||||
//RELOC-NEXT: 0x120E0 R_X86_64_TPOFF64 tlsshared0 0x0
|
||||
//RELOC-NEXT: 0x120E8 R_X86_64_TPOFF64 tlsshared1 0x0
|
||||
//RELOC-NEXT: 0x120F0 R_X86_64_TPOFF64 tlsshared0 0x0
|
||||
//RELOC-NEXT: 0x120F8 R_X86_64_TPOFF64 tlsshared1 0x0
|
||||
//RELOC-NEXT: }
|
||||
//RELOC-NEXT: Section (5) .rela.plt {
|
||||
//RELOC-NEXT: 0x13018 R_X86_64_JUMP_SLOT __tls_get_addr 0x0
|
||||
//RELOC-NEXT: }
|
||||
//RELOC-NEXT: ]
|
||||
|
||||
//0x11009 + (4304 + 7) = 0x120E0
|
||||
//0x11019 + (4296 + 7) = 0x120E8
|
||||
//0x11009 + (4304 + 7) = 0x120F0
|
||||
//0x11019 + (4296 + 7) = 0x120F8
|
||||
// DISASM: Disassembly of section .text:
|
||||
// DISASM-NEXT: _start:
|
||||
// DISASM-NEXT: 11000: 64 48 8b 04 25 00 00 00 00 movq %fs:0, %rax
|
||||
// DISASM-NEXT: 11009: 48 03 05 d0 10 00 00 addq 4304(%rip), %rax
|
||||
// DISASM-NEXT: 11009: 48 03 05 e0 10 00 00 addq 4320(%rip), %rax
|
||||
// DISASM-NEXT: 11010: 64 48 8b 04 25 00 00 00 00 movq %fs:0, %rax
|
||||
// DISASM-NEXT: 11019: 48 03 05 c8 10 00 00 addq 4296(%rip), %rax
|
||||
// DISASM-NEXT: 11019: 48 03 05 d8 10 00 00 addq 4312(%rip), %rax
|
||||
|
||||
.section .text
|
||||
.globl _start
|
||||
|
@ -7,8 +7,8 @@
|
||||
|
||||
// NORELOC: Relocations [
|
||||
// NORELOC-NEXT: Section ({{.*}}) .rel.dyn {
|
||||
// NORELOC-NEXT: 0x12050 R_386_TLS_TPOFF tlsshared0 0x0
|
||||
// NORELOC-NEXT: 0x12054 R_386_TLS_TPOFF tlsshared1 0x0
|
||||
// NORELOC-NEXT: 0x12058 R_386_TLS_TPOFF tlsshared0 0x0
|
||||
// NORELOC-NEXT: 0x1205C R_386_TLS_TPOFF tlsshared1 0x0
|
||||
// NORELOC-NEXT: }
|
||||
// NORELOC-NEXT: ]
|
||||
|
||||
|
@ -16,8 +16,8 @@
|
||||
// GOTREL-NEXT: SHF_ALLOC
|
||||
// GOTREL-NEXT: SHF_WRITE
|
||||
// GOTREL-NEXT: ]
|
||||
// GOTREL-NEXT: Address: 0x12050
|
||||
// GOTREL-NEXT: Offset: 0x2050
|
||||
// GOTREL-NEXT: Address: 0x12058
|
||||
// GOTREL-NEXT: Offset: 0x2058
|
||||
// GOTREL-NEXT: Size: 8
|
||||
// GOTREL-NEXT: Link: 0
|
||||
// GOTREL-NEXT: Info: 0
|
||||
@ -26,8 +26,8 @@
|
||||
// GOTREL-NEXT: }
|
||||
// GOTREL: Relocations [
|
||||
// GOTREL-NEXT: Section ({{.*}}) .rel.dyn {
|
||||
// GOTREL-NEXT: 0x12050 R_386_TLS_TPOFF tlsshared0 0x0
|
||||
// GOTREL-NEXT: 0x12054 R_386_TLS_TPOFF tlsshared1 0x0
|
||||
// GOTREL-NEXT: 0x12058 R_386_TLS_TPOFF tlsshared0 0x0
|
||||
// GOTREL-NEXT: 0x1205C R_386_TLS_TPOFF tlsshared1 0x0
|
||||
// GOTREL-NEXT: }
|
||||
// GOTREL-NEXT: ]
|
||||
|
||||
@ -35,8 +35,8 @@
|
||||
// DISASM-NEXT: _start:
|
||||
// 4294967288 = 0xFFFFFFF8
|
||||
// 4294967292 = 0xFFFFFFFC
|
||||
// 73808 = (.got)[0] = 0x12050
|
||||
// 73812 = (.got)[1] = 0x12054
|
||||
// 73808 = (.got)[0] = 0x12058
|
||||
// 73812 = (.got)[1] = 0x1205C
|
||||
// DISASM-NEXT: 11000: c7 c1 f8 ff ff ff movl $4294967288, %ecx
|
||||
// DISASM-NEXT: 11006: 65 8b 01 movl %gs:(%ecx), %eax
|
||||
// DISASM-NEXT: 11009: b8 f8 ff ff ff movl $4294967288, %eax
|
||||
@ -49,9 +49,9 @@
|
||||
// DISASM-NEXT: 11028: 65 8b 00 movl %gs:(%eax), %eax
|
||||
// DISASM-NEXT: 1102b: 81 c1 fc ff ff ff addl $4294967292, %ecx
|
||||
// DISASM-NEXT: 11031: 65 8b 01 movl %gs:(%ecx), %eax
|
||||
// DISASM-NEXT: 11034: 8b 0d 50 20 01 00 movl 73808, %ecx
|
||||
// DISASM-NEXT: 11034: 8b 0d 58 20 01 00 movl 73816, %ecx
|
||||
// DISASM-NEXT: 1103a: 65 8b 01 movl %gs:(%ecx), %eax
|
||||
// DISASM-NEXT: 1103d: 03 0d 54 20 01 00 addl 73812, %ecx
|
||||
// DISASM-NEXT: 1103d: 03 0d 5c 20 01 00 addl 73820, %ecx
|
||||
// DISASM-NEXT: 11043: 65 8b 01 movl %gs:(%ecx), %eax
|
||||
|
||||
// GOTRELSHARED: Section {
|
||||
|
@ -6,12 +6,12 @@
|
||||
# The reference from FDE->CIE is implicitly created as a negDelta32.
|
||||
# We don't emit these in to the binary as relocations, so we need to
|
||||
# make sure that the offset in the FDE to the CIE is the correct value.
|
||||
# CHECK: 0010 10000000 00000000 017a5200 01781e01
|
||||
# CHECK: 0020 100c1f00 20000000 18000000 e4ffffff
|
||||
# Note, this one that matters ^~~~~~~~
|
||||
# CHECK: {{[0-9abcdef]*}} 10000000 00000000 017a5200 01781e01
|
||||
# CHECK: {{[0-9abcdef]*}} 100c1f00 20000000 18000000 e4ffffff
|
||||
# Note, this one that matters ^~~~~~~~
|
||||
# It needs to be 0x18 as that is the offset back to 0 where the CIE is.
|
||||
# CHECK: 0030 ffffffff 20000000 00000000 00480e10
|
||||
# CHECK: 0040 9e019d02 00000000
|
||||
# CHECK: {{[0-9abcdef]*}} ffffffff 20000000 00000000 00480e10
|
||||
# CHECK: {{[0-9abcdef]*}} 9e019d02 00000000
|
||||
|
||||
--- !mach-o
|
||||
arch: arm64
|
||||
|
67
test/mach-o/arm64-section-order.yaml
Normal file
67
test/mach-o/arm64-section-order.yaml
Normal file
@ -0,0 +1,67 @@
|
||||
# RUN: lld -flavor darwin -arch arm64 -r -print_atoms %s -o %t
|
||||
# RUN: lld -flavor darwin -arch arm64 -r -print_atoms %t -o %t2
|
||||
# RUN: llvm-objdump -section-headers %t | FileCheck %s
|
||||
# RUN: llvm-objdump -section-headers %t2 | FileCheck %s
|
||||
|
||||
# Make sure that the sections are sorted. Currently we want this order:
|
||||
# __text, __unwind_info
|
||||
|
||||
# CHECK: Sections:
|
||||
# CHECK: 0 __text {{.*}} TEXT
|
||||
# CHECK: 1 __compact_unwind {{.*}}
|
||||
|
||||
|
||||
--- !mach-o
|
||||
arch: arm64
|
||||
file-type: MH_OBJECT
|
||||
flags: [ MH_SUBSECTIONS_VIA_SYMBOLS ]
|
||||
compat-version: 0.0
|
||||
current-version: 0.0
|
||||
has-UUID: false
|
||||
OS: unknown
|
||||
sections:
|
||||
- segment: __TEXT
|
||||
section: __text
|
||||
type: S_REGULAR
|
||||
attributes: [ S_ATTR_PURE_INSTRUCTIONS, S_ATTR_SOME_INSTRUCTIONS ]
|
||||
alignment: 8
|
||||
address: 0x0000000000000000
|
||||
content: [ 0xC0, 0x03, 0x5F, 0xD6, 0xC0, 0x03, 0x5F, 0xD6 ]
|
||||
- segment: __LD
|
||||
section: __compact_unwind
|
||||
type: S_REGULAR
|
||||
attributes: [ ]
|
||||
alignment: 8
|
||||
address: 0x0000000000000008
|
||||
content: [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ]
|
||||
relocations:
|
||||
- offset: 0x00000020
|
||||
type: ARM64_RELOC_UNSIGNED
|
||||
length: 3
|
||||
pc-rel: false
|
||||
extern: false
|
||||
symbol: 1
|
||||
- offset: 0x00000000
|
||||
type: ARM64_RELOC_UNSIGNED
|
||||
length: 3
|
||||
pc-rel: false
|
||||
extern: false
|
||||
symbol: 1
|
||||
global-symbols:
|
||||
- name: __Z3fooi
|
||||
type: N_SECT
|
||||
scope: [ N_EXT ]
|
||||
sect: 1
|
||||
value: 0x0000000000000000
|
||||
- name: __Z4foo2i
|
||||
type: N_SECT
|
||||
scope: [ N_EXT ]
|
||||
sect: 1
|
||||
value: 0x0000000000000004
|
@ -268,7 +268,7 @@ page-size: 0x00000000
|
||||
# CHECK: type: data
|
||||
# CHECK: content: [ 00, 00, 00, 00, 00, 00, 00, 00, 04, 00, 00, 00,
|
||||
# CHECK: 00, 00, 00, 00, F0, FF, FF, FF, FF, FF, FF, FF,
|
||||
# CHECK: {{..}}, 00, 00, 00, 00, 00, 00, 00, {{..}}, 00, 00, 00,
|
||||
# CHECK: {{..}}, {{..}}, 00, 00, 00, 00, 00, 00, {{..}}, {{..}}, 00, 00,
|
||||
# CHECK: 00, 00, 00, 00, D8, FF, FF, FF, FF, FF, FF, FF,
|
||||
# CHECK: D4, FF, FF, FF, FF, FF, FF, FF, {{..}}, {{..}}, {{..}}, {{..}},
|
||||
# CHECK: {{..}}, {{..}}, {{..}}, {{..}}, C0, FF, FF, FF, C0, FF, FF, FF,
|
||||
|
Loading…
Reference in New Issue
Block a user