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