[ELF] Remove the symbol partition feature (#199186)
Follow-up to #198718: SHT_LLVM_SYMPART sections are no longer recognized and are treated as ordinary sections. The sole user has been retired (crbug.com/401249151). The per-partition synthetic sections (.dynamic, .dynsym, .gnu.hash, .eh_frame, .ARM.exidx, ...) move into `ctx.in`; the program headers move into `ctx.phdrs`. Delete the `Partition` struct, `ctx.mainPart`, `ctx.partitions`, the PartitionElfHeaderSection/PartitionProgramHeadersSection shim sections, and the `.part.end` marker.
This commit is contained in:
1 parent
081d6881d5
commit
5fb0fe4a10
25 files changed
+371
-903
No files matched your search
@@ -209,7 +209,7 @@ void PPC::writeGotHeader(uint8_t *buf) const {
|
||||
// _GLOBAL_OFFSET_TABLE_[0] = _DYNAMIC
|
||||
// glibc stores _dl_runtime_resolve in _GLOBAL_OFFSET_TABLE_[1],
|
||||
// link_map in _GLOBAL_OFFSET_TABLE_[2].
|
||||
write32(ctx, buf, ctx.mainPart->dynamic->getVA());
|
||||
write32(ctx, buf, ctx.in.dynamic->getVA());
|
||||
}
|
||||
|
||||
void PPC::writeGotPlt(uint8_t *buf, const Symbol &s) const {
|
||||
|
||||
@@ -218,9 +218,9 @@ int64_t RISCV::getImplicitAddend(const uint8_t *buf, RelType type) const {
|
||||
|
||||
void RISCV::writeGotHeader(uint8_t *buf) const {
|
||||
if (ctx.arg.is64)
|
||||
write64le(buf, ctx.mainPart->dynamic->getVA());
|
||||
write64le(buf, ctx.in.dynamic->getVA());
|
||||
else
|
||||
write32le(buf, ctx.mainPart->dynamic->getVA());
|
||||
write32le(buf, ctx.in.dynamic->getVA());
|
||||
}
|
||||
|
||||
void RISCV::writeGotPlt(uint8_t *buf, const Symbol &s) const {
|
||||
|
||||
@@ -104,7 +104,7 @@ RelExpr SystemZ::getRelExpr(RelType type, const Symbol &s,
|
||||
void SystemZ::writeGotHeader(uint8_t *buf) const {
|
||||
// _GLOBAL_OFFSET_TABLE_[0] holds the value of _DYNAMIC.
|
||||
// _GLOBAL_OFFSET_TABLE_[1] and [2] are reserved.
|
||||
write64be(buf, ctx.mainPart->dynamic->getVA());
|
||||
write64be(buf, ctx.in.dynamic->getVA());
|
||||
}
|
||||
|
||||
void SystemZ::writeGotPlt(uint8_t *buf, const Symbol &s) const {
|
||||
|
||||
@@ -106,7 +106,7 @@ RelExpr X86::getRelExpr(RelType type, const Symbol &s,
|
||||
}
|
||||
|
||||
void X86::writeGotPltHeader(uint8_t *buf) const {
|
||||
write32le(buf, ctx.mainPart->dynamic->getVA());
|
||||
write32le(buf, ctx.in.dynamic->getVA());
|
||||
}
|
||||
|
||||
void X86::writeGotPlt(uint8_t *buf, const Symbol &s) const {
|
||||
|
||||
@@ -403,7 +403,7 @@ void X86_64::writeGotPltHeader(uint8_t *buf) const {
|
||||
// in the psABI and glibc before Aug 2021 used the entry to compute run-time
|
||||
// load address of the shared object (note that this is relevant for linking
|
||||
// ld.so, not any other program).
|
||||
write64le(buf, ctx.mainPart->dynamic->getVA());
|
||||
write64le(buf, ctx.in.dynamic->getVA());
|
||||
}
|
||||
|
||||
void X86_64::writeGotPlt(uint8_t *buf, const Symbol &s) const {
|
||||
|
||||
+43
-19
@@ -53,25 +53,36 @@ class OutputSection;
|
||||
class LinkerScript;
|
||||
class TargetInfo;
|
||||
struct Ctx;
|
||||
struct Partition;
|
||||
struct PhdrEntry;
|
||||
|
||||
class ARMExidxSyntheticSection;
|
||||
class BssSection;
|
||||
class BuildIdSection;
|
||||
class EhFrameHeader;
|
||||
class EhFrameSection;
|
||||
class GdbIndexSection;
|
||||
class GnuHashTableSection;
|
||||
class GotPltSection;
|
||||
class GotSection;
|
||||
class HashTableSection;
|
||||
class IgotPltSection;
|
||||
class InputSection;
|
||||
class IpltSection;
|
||||
class MemtagAndroidNote;
|
||||
class MemtagGlobalDescriptors;
|
||||
class MipsGotSection;
|
||||
class PPC64LongBranchTargetSection;
|
||||
class PackageMetadataNote;
|
||||
class PltSection;
|
||||
class RelocationBaseSection;
|
||||
class RelrBaseSection;
|
||||
class RelroPaddingSection;
|
||||
class StringTableSection;
|
||||
class SymbolTableBaseSection;
|
||||
class SymtabShndxSection;
|
||||
class SyntheticSection;
|
||||
class VersionDefinitionSection;
|
||||
class VersionTableSection;
|
||||
|
||||
enum ELFKind : uint8_t {
|
||||
ELFNoneKind,
|
||||
@@ -582,33 +593,48 @@ struct UndefinedDiag {
|
||||
bool isWarning;
|
||||
};
|
||||
|
||||
// Linker generated sections which can be used as inputs and are not specific to
|
||||
// a partition.
|
||||
// Linker generated sections which can be used as inputs.
|
||||
struct InStruct {
|
||||
std::unique_ptr<InputSection> attributes;
|
||||
std::unique_ptr<SyntheticSection> hexagonAttributes;
|
||||
std::unique_ptr<SyntheticSection> riscvAttributes;
|
||||
std::unique_ptr<BssSection> bss;
|
||||
std::unique_ptr<BssSection> bssRelRo;
|
||||
std::unique_ptr<BuildIdSection> buildId;
|
||||
std::unique_ptr<EhFrameHeader> ehFrameHdr;
|
||||
std::unique_ptr<EhFrameSection> ehFrame;
|
||||
std::unique_ptr<GnuHashTableSection> gnuHashTab;
|
||||
std::unique_ptr<GotPltSection> gotPlt;
|
||||
std::unique_ptr<GotSection> got;
|
||||
std::unique_ptr<HashTableSection> hashTab;
|
||||
std::unique_ptr<IgotPltSection> igotPlt;
|
||||
std::unique_ptr<IpltSection> iplt;
|
||||
std::unique_ptr<MemtagAndroidNote> memtagAndroidNote;
|
||||
std::unique_ptr<MemtagGlobalDescriptors> memtagGlobalDescriptors;
|
||||
std::unique_ptr<PackageMetadataNote> packageMetadataNote;
|
||||
std::unique_ptr<PltSection> plt;
|
||||
std::unique_ptr<RelocationBaseSection> relaDyn;
|
||||
std::unique_ptr<RelocationBaseSection> relaPlt;
|
||||
std::unique_ptr<RelrBaseSection> relrAuthDyn;
|
||||
std::unique_ptr<RelrBaseSection> relrDyn;
|
||||
std::unique_ptr<RelroPaddingSection> relroPadding;
|
||||
std::unique_ptr<StringTableSection> dynStrTab;
|
||||
std::unique_ptr<SymbolTableBaseSection> dynSymTab;
|
||||
std::unique_ptr<SyntheticSection> dynamic;
|
||||
std::unique_ptr<SyntheticSection> gnuProperty;
|
||||
std::unique_ptr<SyntheticSection> gnuStack;
|
||||
std::unique_ptr<GotSection> got;
|
||||
std::unique_ptr<GotPltSection> gotPlt;
|
||||
std::unique_ptr<IgotPltSection> igotPlt;
|
||||
std::unique_ptr<RelroPaddingSection> relroPadding;
|
||||
std::unique_ptr<SyntheticSection> ibtPlt;
|
||||
std::unique_ptr<SyntheticSection> verNeed;
|
||||
std::unique_ptr<VersionDefinitionSection> verDef;
|
||||
std::unique_ptr<VersionTableSection> verSym;
|
||||
|
||||
std::unique_ptr<SyntheticSection> armCmseSGSection;
|
||||
std::unique_ptr<ARMExidxSyntheticSection> armExidx;
|
||||
std::unique_ptr<PPC64LongBranchTargetSection> ppc64LongBranchTarget;
|
||||
std::unique_ptr<SyntheticSection> mipsAbiFlags;
|
||||
std::unique_ptr<MipsGotSection> mipsGot;
|
||||
std::unique_ptr<SyntheticSection> mipsOptions;
|
||||
std::unique_ptr<SyntheticSection> mipsReginfo;
|
||||
std::unique_ptr<SyntheticSection> mipsRldMap;
|
||||
std::unique_ptr<SyntheticSection> partEnd;
|
||||
std::unique_ptr<PltSection> plt;
|
||||
std::unique_ptr<IpltSection> iplt;
|
||||
std::unique_ptr<SyntheticSection> ppc32Got2;
|
||||
std::unique_ptr<SyntheticSection> ibtPlt;
|
||||
std::unique_ptr<RelocationBaseSection> relaPlt;
|
||||
// Non-SHF_ALLOC sections
|
||||
std::unique_ptr<SyntheticSection> debugNames;
|
||||
std::unique_ptr<GdbIndexSection> gdbIndex;
|
||||
@@ -616,6 +642,8 @@ struct InStruct {
|
||||
std::unique_ptr<StringTableSection> strTab;
|
||||
std::unique_ptr<SymbolTableBaseSection> symTab;
|
||||
std::unique_ptr<SymtabShndxSection> symTabShndx;
|
||||
std::unique_ptr<SyntheticSection> hexagonAttributes;
|
||||
std::unique_ptr<SyntheticSection> riscvAttributes;
|
||||
};
|
||||
|
||||
struct Ctx : CommonLinkerContext {
|
||||
@@ -627,8 +655,8 @@ struct Ctx : CommonLinkerContext {
|
||||
// These variables are initialized by Writer and should not be used before
|
||||
// Writer is initialized.
|
||||
uint8_t *bufferStart = nullptr;
|
||||
Partition *mainPart = nullptr;
|
||||
PhdrEntry *tlsPhdr = nullptr;
|
||||
SmallVector<std::unique_ptr<PhdrEntry>, 0> phdrs;
|
||||
struct OutSections {
|
||||
std::unique_ptr<OutputSection> elfHeader;
|
||||
std::unique_ptr<OutputSection> programHeaders;
|
||||
@@ -638,8 +666,6 @@ struct Ctx : CommonLinkerContext {
|
||||
};
|
||||
OutSections out;
|
||||
SmallVector<OutputSection *, 0> outputSections;
|
||||
// [0] main output; [1..] header-only shims for SHT_LLVM_SYMPART inputs.
|
||||
std::vector<Partition> partitions;
|
||||
|
||||
InStruct in;
|
||||
|
||||
@@ -726,8 +752,6 @@ struct Ctx : CommonLinkerContext {
|
||||
Undefined *dummySym = nullptr;
|
||||
// True if symbols can be exported (isExported) or preemptible.
|
||||
bool hasDynsym = false;
|
||||
// True if SHT_LLVM_SYMPART is used.
|
||||
std::atomic<bool> hasSympart{false};
|
||||
// True if there are TLS IE relocations. Set DF_STATIC_TLS if -shared.
|
||||
std::atomic<bool> hasTlsIe{false};
|
||||
// True if we need to reserve two .got entries for local-dynamic TLS model.
|
||||
|
||||
@@ -132,9 +132,6 @@ bool link(ArrayRef<const char *> args, llvm::raw_ostream &stdoutOS,
|
||||
ctx.symAux.emplace_back();
|
||||
ctx.symtab = std::make_unique<SymbolTable>(ctx);
|
||||
|
||||
ctx.partitions.clear();
|
||||
ctx.partitions.emplace_back();
|
||||
|
||||
ctx.arg.progName = args[0];
|
||||
|
||||
ctx.driver.linkerMain(args);
|
||||
@@ -2748,53 +2745,6 @@ static void findKeepUniqueSections(Ctx &ctx, opt::InputArgList &args) {
|
||||
}
|
||||
}
|
||||
|
||||
// Read an SHT_LLVM_SYMPART specification. Each unique partition name now just
|
||||
// allocates an empty shim so `llvm-objcopy --extract-partition` keeps working.
|
||||
template <typename ELFT>
|
||||
static void readSymbolPartitionSection(Ctx &ctx, InputSectionBase *s) {
|
||||
// Read the relocation that refers to the partition's entry point symbol.
|
||||
Symbol *sym;
|
||||
const RelsOrRelas<ELFT> rels = s->template relsOrRelas<ELFT>();
|
||||
auto readEntry = [](InputFile *file, const auto &rels) -> Symbol * {
|
||||
for (const auto &rel : rels)
|
||||
return &file->getRelocTargetSym(rel);
|
||||
return nullptr;
|
||||
};
|
||||
if (rels.areRelocsCrel())
|
||||
sym = readEntry(s->file, rels.crels);
|
||||
else if (rels.areRelocsRel())
|
||||
sym = readEntry(s->file, rels.rels);
|
||||
else
|
||||
sym = readEntry(s->file, rels.relas);
|
||||
if (!isa_and_nonnull<Defined>(sym) || !sym->isExported)
|
||||
return;
|
||||
|
||||
StringRef partName = reinterpret_cast<const char *>(s->content().data());
|
||||
for (Partition &shim : llvm::drop_begin(ctx.partitions))
|
||||
if (shim.name == partName)
|
||||
return;
|
||||
|
||||
// Forbid partitions from being used on incompatible targets, and forbid them
|
||||
// from being used together with various linker features that assume a single
|
||||
// set of output sections.
|
||||
if (ctx.script->hasSectionsCommand)
|
||||
ErrAlways(ctx) << s->file
|
||||
<< ": partitions cannot be used with the SECTIONS command";
|
||||
if (ctx.script->hasPhdrsCommands())
|
||||
ErrAlways(ctx) << s->file
|
||||
<< ": partitions cannot be used with the PHDRS command";
|
||||
if (!ctx.arg.sectionStartMap.empty())
|
||||
ErrAlways(ctx) << s->file
|
||||
<< ": partitions cannot be used with "
|
||||
"--section-start, -Ttext, -Tdata or -Tbss";
|
||||
if (ctx.arg.emachine == EM_MIPS)
|
||||
ErrAlways(ctx) << s->file << ": partitions cannot be used on this target";
|
||||
|
||||
Partition &shim = ctx.partitions.emplace_back();
|
||||
shim.partno = ctx.partitions.size();
|
||||
shim.name = partName;
|
||||
}
|
||||
|
||||
static void markBuffersAsDontNeed(Ctx &ctx, bool skipLinkedOutput) {
|
||||
// With --thinlto-index-only, all buffers are nearly unused from now on
|
||||
// (except symbol/section names used by infrequent passes). Mark input file
|
||||
@@ -3516,14 +3466,6 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &args) {
|
||||
|
||||
{
|
||||
llvm::TimeTraceScope timeScope("Strip sections");
|
||||
if (ctx.hasSympart.load(std::memory_order_relaxed)) {
|
||||
llvm::erase_if(ctx.inputSections, [&ctx = ctx](InputSectionBase *s) {
|
||||
if (s->type != SHT_LLVM_SYMPART)
|
||||
return false;
|
||||
readSymbolPartitionSection<ELFT>(ctx, s);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
// We do not want to emit debug sections if --strip-all
|
||||
// or --strip-debug are given.
|
||||
if (ctx.arg.strip != StripPolicy::None) {
|
||||
@@ -3545,10 +3487,6 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &args) {
|
||||
if (!ctx.arg.dependencyFile.empty())
|
||||
writeDependencyFile(ctx);
|
||||
|
||||
// Now that the number of partitions is fixed, save a pointer to the main
|
||||
// partition.
|
||||
ctx.mainPart = &ctx.partitions[0];
|
||||
|
||||
// Read .note.gnu.property sections from input object files which
|
||||
// contain a hint to tweak linker's and loader's behaviors.
|
||||
readSecurityNotes(ctx);
|
||||
|
||||
+1
-1
@@ -471,7 +471,7 @@ template <class ELFT> void ICF<ELFT>::run() {
|
||||
// If two .gcc_except_table have identical semantics (usually identical
|
||||
// content with PC-relative encoding), we will lose folding opportunity.
|
||||
uint32_t uniqueId = 0;
|
||||
ctx.mainPart->ehFrame->iterateFDEWithLSDA<ELFT>(
|
||||
ctx.in.ehFrame->iterateFDEWithLSDA<ELFT>(
|
||||
[&](InputSection &s) { s.eqClass[0] = s.eqClass[1] = ++uniqueId; });
|
||||
|
||||
// Collect sections to merge.
|
||||
|
||||
@@ -868,10 +868,8 @@ void ObjFile<ELFT>::initializeSections(bool ignoreComdats,
|
||||
default:
|
||||
this->sections[i] =
|
||||
createInputSection(i, sec, check(obj.getSectionName(sec, shstrtab)));
|
||||
if (type == SHT_LLVM_SYMPART)
|
||||
ctx.hasSympart.store(true, std::memory_order_relaxed);
|
||||
else if (ctx.arg.rejectMismatch &&
|
||||
!isKnownSpecificSectionType(type, sec.sh_flags))
|
||||
if (ctx.arg.rejectMismatch &&
|
||||
!isKnownSpecificSectionType(type, sec.sh_flags))
|
||||
Err(ctx) << this->sections[i] << ": unknown section type 0x"
|
||||
<< Twine::utohexstr(type);
|
||||
break;
|
||||
|
||||
@@ -28,7 +28,6 @@ class InputFile;
|
||||
class Symbol;
|
||||
|
||||
class Defined;
|
||||
struct Partition;
|
||||
class SyntheticSection;
|
||||
template <class ELFT> class ObjFile;
|
||||
class OutputSection;
|
||||
@@ -78,8 +77,6 @@ public:
|
||||
|
||||
StringRef name;
|
||||
|
||||
elf::Partition &getPartition(Ctx &) const;
|
||||
|
||||
// These corresponds to the fields in Elf_Shdr.
|
||||
uint64_t flags;
|
||||
uint32_t type;
|
||||
@@ -89,8 +86,7 @@ public:
|
||||
uint32_t entsize;
|
||||
|
||||
Kind sectionKind;
|
||||
// 0 (dead) or 1 (live). Shim synthetic sections also use this field to
|
||||
// carry their partition number (2..) or 255 for the partEnd marker.
|
||||
// 0 (dead) or 1 (live).
|
||||
uint8_t partition = 1;
|
||||
|
||||
// The next two bit fields are only used by InputSectionBase, but we
|
||||
|
||||
@@ -698,7 +698,7 @@ void LinkerScript::discard(InputSectionBase &s) {
|
||||
}
|
||||
|
||||
void LinkerScript::discardSynthetic(OutputSection &outCmd) {
|
||||
ARMExidxSyntheticSection *armExidx = ctx.mainPart->armExidx.get();
|
||||
ARMExidxSyntheticSection *armExidx = ctx.in.armExidx.get();
|
||||
if (!armExidx || !armExidx->isLive())
|
||||
return;
|
||||
SmallVector<InputSectionBase *, 0> secs(armExidx->exidxSections.begin(),
|
||||
@@ -762,9 +762,7 @@ void LinkerScript::processSectionCommands() {
|
||||
s->addralign = subalign;
|
||||
}
|
||||
|
||||
// Set the partition field the same way OutputSection::recordSection()
|
||||
// does. Partitions cannot be used with the SECTIONS command, so this is
|
||||
// always 1.
|
||||
// Mark the output section live, like OutputSection::recordSection().
|
||||
osec->partition = 1;
|
||||
return true;
|
||||
};
|
||||
|
||||
+2
-2
@@ -113,8 +113,8 @@ public:
|
||||
// PIC when the relocation uses the full address (not just low page bits).
|
||||
if (ieExpr == R_GOT && ctx.arg.isPic &&
|
||||
!ctx.target->usesOnlyLowPageBits(type))
|
||||
sec->getPartition(ctx).relaDyn->addRelativeReloc(
|
||||
ctx.target->relativeRel, *sec, offset, sym, addend, type, ieExpr);
|
||||
ctx.in.relaDyn->addRelativeReloc(ctx.target->relativeRel, *sec, offset,
|
||||
sym, addend, type, ieExpr);
|
||||
else
|
||||
sec->addReloc({ieExpr, type, offset, addend, &sym});
|
||||
}
|
||||
|
||||
+24
-28
@@ -323,7 +323,7 @@ template <class ELFT> static void addCopyRelSymbol(Ctx &ctx, SharedSymbol &ss) {
|
||||
for (SharedSymbol *sym : getSymbolsAt<ELFT>(ctx, ss))
|
||||
replaceWithDefined(ctx, *sym, *sec, 0, sym->size);
|
||||
|
||||
ctx.mainPart->relaDyn->addSymbolReloc(ctx.target->copyRel, *sec, 0, ss);
|
||||
ctx.in.relaDyn->addSymbolReloc(ctx.target->copyRel, *sec, 0, ss);
|
||||
}
|
||||
|
||||
// .eh_frame sections are mergeable input sections, so their input
|
||||
@@ -701,7 +701,6 @@ template <bool shard = false>
|
||||
static void addRelativeReloc(Ctx &ctx, InputSectionBase &isec,
|
||||
uint64_t offsetInSec, Symbol &sym, int64_t addend,
|
||||
RelExpr expr, RelType type) {
|
||||
Partition &part = isec.getPartition(ctx);
|
||||
bool isAArch64Auth =
|
||||
ctx.arg.emachine == EM_AARCH64 && type == R_AARCH64_AUTH_ABS64;
|
||||
|
||||
@@ -717,9 +716,9 @@ static void addRelativeReloc(Ctx &ctx, InputSectionBase &isec,
|
||||
//
|
||||
// MTE globals may need to store the original addend as well so cannot use
|
||||
// relrDyn. TODO: It should be unambiguous when not using R_ADDEND_NEG below?
|
||||
RelrBaseSection *relrDyn = part.relrDyn.get();
|
||||
RelrBaseSection *relrDyn = ctx.in.relrDyn.get();
|
||||
if (isAArch64Auth)
|
||||
relrDyn = part.relrAuthDyn.get();
|
||||
relrDyn = ctx.in.relrAuthDyn.get();
|
||||
if (sym.isTagged())
|
||||
relrDyn = nullptr;
|
||||
if (relrDyn && isec.addralign >= 2 && offsetInSec % 2 == 0) {
|
||||
@@ -730,8 +729,8 @@ static void addRelativeReloc(Ctx &ctx, InputSectionBase &isec,
|
||||
RelType relativeType = ctx.target->relativeRel;
|
||||
if (isAArch64Auth)
|
||||
relativeType = R_AARCH64_AUTH_RELATIVE;
|
||||
part.relaDyn->addRelativeReloc<shard>(relativeType, isec, offsetInSec, sym,
|
||||
addend, type, expr);
|
||||
ctx.in.relaDyn->addRelativeReloc<shard>(relativeType, isec, offsetInSec, sym,
|
||||
addend, type, expr);
|
||||
// With MTE globals, we always want to derive the address tag by `ldg`-ing
|
||||
// the symbol. When we have a RELATIVE relocation though, we no longer have
|
||||
// a reference to the symbol. Because of this, when we have an addend that
|
||||
@@ -764,7 +763,7 @@ void elf::addGotEntry(Ctx &ctx, Symbol &sym) {
|
||||
|
||||
// If preemptible, emit a GLOB_DAT relocation.
|
||||
if (sym.isPreemptible) {
|
||||
ctx.mainPart->relaDyn->addReloc(
|
||||
ctx.in.relaDyn->addReloc(
|
||||
{ctx.target->gotRel, ctx.in.got.get(), off, true, sym, 0, R_ADDEND});
|
||||
return;
|
||||
}
|
||||
@@ -785,13 +784,13 @@ static void addGotAuthEntry(Ctx &ctx, Symbol &sym) {
|
||||
|
||||
// If preemptible, emit a GLOB_DAT relocation.
|
||||
if (sym.isPreemptible) {
|
||||
ctx.mainPart->relaDyn->addReloc({R_AARCH64_AUTH_GLOB_DAT, ctx.in.got.get(),
|
||||
off, true, sym, 0, R_ADDEND});
|
||||
ctx.in.relaDyn->addReloc({R_AARCH64_AUTH_GLOB_DAT, ctx.in.got.get(), off,
|
||||
true, sym, 0, R_ADDEND});
|
||||
return;
|
||||
}
|
||||
|
||||
// Signed GOT requires dynamic relocation.
|
||||
ctx.in.got->getPartition(ctx).relaDyn->addReloc(
|
||||
ctx.in.relaDyn->addReloc(
|
||||
{R_AARCH64_AUTH_RELATIVE, ctx.in.got.get(), off, false, sym, 0, R_ABS});
|
||||
}
|
||||
|
||||
@@ -802,7 +801,7 @@ static void addTpOffsetGotEntry(Ctx &ctx, Symbol &sym) {
|
||||
ctx.in.got->addConstant({R_TPREL, ctx.target->symbolicRel, off, 0, &sym});
|
||||
return;
|
||||
}
|
||||
ctx.mainPart->relaDyn->addAddendOnlyRelocIfNonPreemptible(
|
||||
ctx.in.relaDyn->addAddendOnlyRelocIfNonPreemptible(
|
||||
ctx.target->tlsGotRel, *ctx.in.got, off, sym, ctx.target->symbolicRel);
|
||||
}
|
||||
|
||||
@@ -938,8 +937,7 @@ void RelocScan::process(RelExpr expr, RelType type, uint64_t offset,
|
||||
if (LLVM_UNLIKELY(isIfunc) && ctx.arg.zIfuncNoplt) {
|
||||
std::lock_guard<std::mutex> lock(ctx.relocMutex);
|
||||
sym.isExported = true;
|
||||
ctx.mainPart->relaDyn->addSymbolReloc(type, *sec, offset, sym, addend,
|
||||
type);
|
||||
ctx.in.relaDyn->addSymbolReloc(type, *sec, offset, sym, addend, type);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1004,7 +1002,6 @@ void RelocScan::processAux(RelExpr expr, RelType type, uint64_t offset,
|
||||
if (ctx.arg.emachine == EM_MIPS && rel == ctx.target->symbolicRel)
|
||||
rel = ctx.target->relativeRel;
|
||||
std::lock_guard<std::mutex> lock(ctx.relocMutex);
|
||||
Partition &part = sec->getPartition(ctx);
|
||||
if (LLVM_UNLIKELY(type == ctx.target->iRelSymbolicRel)) {
|
||||
if (sym.isPreemptible) {
|
||||
auto diag = Err(ctx);
|
||||
@@ -1017,12 +1014,12 @@ void RelocScan::processAux(RelExpr expr, RelType type, uint64_t offset,
|
||||
<< " cannot be used against ifunc symbol '" << &sym << "'";
|
||||
printLocation(diag, *sec, sym, offset);
|
||||
} else {
|
||||
part.relaDyn->addReloc({ctx.target->iRelativeRel, sec, offset, false,
|
||||
sym, addend, R_ABS});
|
||||
ctx.in.relaDyn->addReloc({ctx.target->iRelativeRel, sec, offset,
|
||||
false, sym, addend, R_ABS});
|
||||
return;
|
||||
}
|
||||
}
|
||||
part.relaDyn->addSymbolReloc(rel, *sec, offset, sym, addend, type);
|
||||
ctx.in.relaDyn->addSymbolReloc(rel, *sec, offset, sym, addend, type);
|
||||
|
||||
// MIPS ABI turns using of GOT and dynamic relocations inside out.
|
||||
// While regular ABI uses dynamic relocations to fill up GOT entries
|
||||
@@ -1197,9 +1194,9 @@ template <class ELFT> void elf::scanRelocations(Ctx &ctx) {
|
||||
}
|
||||
auto scanEH = [&] {
|
||||
RelocScan scanner(ctx);
|
||||
for (EhInputSection *sec : ctx.mainPart->ehFrame->sections)
|
||||
for (EhInputSection *sec : ctx.in.ehFrame->sections)
|
||||
scanner.scanEhSection(*sec);
|
||||
ARMExidxSyntheticSection *armExidx = ctx.mainPart->armExidx.get();
|
||||
ARMExidxSyntheticSection *armExidx = ctx.in.armExidx.get();
|
||||
if (armExidx && armExidx->isLive())
|
||||
for (InputSection *sec : armExidx->exidxSections)
|
||||
if (sec->isLive())
|
||||
@@ -1225,8 +1222,7 @@ RelocationBaseSection &elf::getIRelativeSection(Ctx &ctx) {
|
||||
// unrelocated globals with RELR relocations when
|
||||
// --pack-relative-relocs=android+relr is enabled. Work around this by placing
|
||||
// IRELATIVE in .rela.plt.
|
||||
return ctx.arg.androidPackDynRelocs ? *ctx.in.relaPlt
|
||||
: *ctx.mainPart->relaDyn;
|
||||
return ctx.arg.androidPackDynRelocs ? *ctx.in.relaPlt : *ctx.in.relaDyn;
|
||||
}
|
||||
|
||||
static bool handleNonPreemptibleIfunc(Ctx &ctx, Symbol &sym, uint16_t flags) {
|
||||
@@ -1296,7 +1292,7 @@ void elf::postScanRelocations(Ctx &ctx) {
|
||||
return;
|
||||
|
||||
if (sym.isTagged() && sym.isDefined())
|
||||
ctx.mainPart->memtagGlobalDescriptors->addSymbol(sym);
|
||||
ctx.in.memtagGlobalDescriptors->addSymbol(sym);
|
||||
|
||||
if (!sym.needsDynReloc())
|
||||
return;
|
||||
@@ -1361,7 +1357,7 @@ void elf::postScanRelocations(Ctx &ctx) {
|
||||
got->addTlsDescAuthEntry();
|
||||
tlsDescRel = ELF::R_AARCH64_AUTH_TLSDESC;
|
||||
}
|
||||
ctx.mainPart->relaDyn->addAddendOnlyRelocIfNonPreemptible(
|
||||
ctx.in.relaDyn->addAddendOnlyRelocIfNonPreemptible(
|
||||
tlsDescRel, *got, got->getTlsDescOffset(sym), sym, tlsDescRel);
|
||||
}
|
||||
if (flags & NEEDS_TLSGD) {
|
||||
@@ -1371,15 +1367,15 @@ void elf::postScanRelocations(Ctx &ctx) {
|
||||
// Write one to the GOT slot.
|
||||
got->addConstant({R_ADDEND, ctx.target->symbolicRel, off, 1, &sym});
|
||||
else
|
||||
ctx.mainPart->relaDyn->addSymbolReloc(ctx.target->tlsModuleIndexRel,
|
||||
*got, off, sym);
|
||||
ctx.in.relaDyn->addSymbolReloc(ctx.target->tlsModuleIndexRel, *got, off,
|
||||
sym);
|
||||
|
||||
// If the symbol is preemptible we need the dynamic linker to write
|
||||
// the offset too.
|
||||
uint64_t offsetOff = off + ctx.arg.wordsize;
|
||||
if (sym.isPreemptible)
|
||||
ctx.mainPart->relaDyn->addSymbolReloc(ctx.target->tlsOffsetRel, *got,
|
||||
offsetOff, sym);
|
||||
ctx.in.relaDyn->addSymbolReloc(ctx.target->tlsOffsetRel, *got,
|
||||
offsetOff, sym);
|
||||
else
|
||||
got->addConstant({R_ABS, ctx.target->tlsOffsetRel, offsetOff, 0, &sym});
|
||||
}
|
||||
@@ -1400,7 +1396,7 @@ void elf::postScanRelocations(Ctx &ctx) {
|
||||
GotSection *got = ctx.in.got.get();
|
||||
if (ctx.needsTlsLd.load(std::memory_order_relaxed) && got->addTlsIndex()) {
|
||||
if (ctx.arg.shared)
|
||||
ctx.mainPart->relaDyn->addReloc(
|
||||
ctx.in.relaDyn->addReloc(
|
||||
{ctx.target->tlsModuleIndexRel, got, got->getTlsIndexOff()});
|
||||
else
|
||||
got->addConstant({R_ADDEND, ctx.target->symbolicRel,
|
||||
|
||||
+162
-243
@@ -263,8 +263,7 @@ Defined *EhFrameSection::isFdeLive(EhSectionPiece &fde,
|
||||
if (firstRelI == (unsigned)-1)
|
||||
return nullptr;
|
||||
|
||||
// FDEs for garbage-collected or merged-by-ICF sections, or sections in
|
||||
// another partition, are dead.
|
||||
// FDEs for garbage-collected or merged-by-ICF sections are dead.
|
||||
if (auto *d = dyn_cast<Defined>(rels[firstRelI].sym))
|
||||
if (!d->folded && d->section && d->section->partition == partition)
|
||||
return d;
|
||||
@@ -391,7 +390,7 @@ void EhFrameSection::writeTo(uint8_t *buf) {
|
||||
for (EhInputSection *s : sections)
|
||||
ctx.target->relocateEh(*s, buf);
|
||||
|
||||
EhFrameHeader *hdr = getPartition(ctx).ehFrameHdr.get();
|
||||
EhFrameHeader *hdr = ctx.in.ehFrameHdr.get();
|
||||
if (!hdr || !hdr->getParent())
|
||||
return;
|
||||
|
||||
@@ -431,14 +430,14 @@ void EhFrameHeader::writeTo(uint8_t *buf) {
|
||||
}
|
||||
|
||||
bool EhFrameHeader::isNeeded() const {
|
||||
return isLive() && getPartition(ctx).ehFrame->isNeeded();
|
||||
return isLive() && ctx.in.ehFrame->isNeeded();
|
||||
}
|
||||
|
||||
void EhFrameHeader::finalizeContents() {
|
||||
// Compute size: 4-byte header + eh_frame_ptr + fde_count + FDE table.
|
||||
// Initially `large` is false; updateAllocSize may set it to true if addresses
|
||||
// exceed the 32-bit range, then call finalizeContents again.
|
||||
auto numFdes = getPartition(ctx).ehFrame->numFdes;
|
||||
auto numFdes = ctx.in.ehFrame->numFdes;
|
||||
size = 4 + (large ? 8 : 4) + 4 + numFdes * (large ? 16 : 8);
|
||||
}
|
||||
|
||||
@@ -446,7 +445,7 @@ bool EhFrameHeader::updateAllocSize(Ctx &ctx) {
|
||||
// This is called after `finalizeSynthetic`, so in the typical case without
|
||||
// .relr.dyn, this function will not change the size and assignAddresses
|
||||
// will not need another iteration.
|
||||
EhFrameSection *ehFrame = getPartition(ctx).ehFrame.get();
|
||||
EhFrameSection *ehFrame = ctx.in.ehFrame.get();
|
||||
uint64_t hdrVA = getVA();
|
||||
int64_t ehFramePtr = ehFrame->getParent()->addr - hdrVA - 4;
|
||||
// Determine if 64-bit encodings are needed.
|
||||
@@ -897,7 +896,7 @@ void MipsGotSection::build() {
|
||||
if (!s->isPreemptible && !ctx.arg.shared)
|
||||
addConstant({R_TPREL, ctx.target->symbolicRel, offset, 0, s});
|
||||
else
|
||||
ctx.mainPart->relaDyn->addAddendOnlyRelocIfNonPreemptible(
|
||||
ctx.in.relaDyn->addAddendOnlyRelocIfNonPreemptible(
|
||||
ctx.target->tlsGotRel, *this, offset, *s, ctx.target->symbolicRel);
|
||||
}
|
||||
for (std::pair<Symbol *, size_t> &p : got.dynTlsSymbols) {
|
||||
@@ -905,7 +904,7 @@ void MipsGotSection::build() {
|
||||
uint64_t offset = p.second * ctx.arg.wordsize;
|
||||
if (s == nullptr) {
|
||||
if (ctx.arg.shared)
|
||||
ctx.mainPart->relaDyn->addReloc(
|
||||
ctx.in.relaDyn->addReloc(
|
||||
{ctx.target->tlsModuleIndexRel, this, offset});
|
||||
else
|
||||
addConstant(
|
||||
@@ -919,14 +918,14 @@ void MipsGotSection::build() {
|
||||
// Write one to the GOT slot.
|
||||
addConstant({R_ADDEND, ctx.target->symbolicRel, offset, 1, s});
|
||||
else
|
||||
ctx.mainPart->relaDyn->addSymbolReloc(ctx.target->tlsModuleIndexRel,
|
||||
*this, offset, *s);
|
||||
ctx.in.relaDyn->addSymbolReloc(ctx.target->tlsModuleIndexRel, *this,
|
||||
offset, *s);
|
||||
offset += ctx.arg.wordsize;
|
||||
// However, we can skip writing the TLS offset reloc for non-preemptible
|
||||
// symbols since it is known even in shared libraries
|
||||
if (s->isPreemptible)
|
||||
ctx.mainPart->relaDyn->addSymbolReloc(ctx.target->tlsOffsetRel, *this,
|
||||
offset, *s);
|
||||
ctx.in.relaDyn->addSymbolReloc(ctx.target->tlsOffsetRel, *this,
|
||||
offset, *s);
|
||||
else
|
||||
addConstant({R_ABS, ctx.target->tlsOffsetRel, offset, 0, s});
|
||||
}
|
||||
@@ -938,8 +937,8 @@ void MipsGotSection::build() {
|
||||
if (&got == primGot)
|
||||
addConstant({R_ABS, ctx.target->relativeRel, offset, 0, p.first});
|
||||
else
|
||||
ctx.mainPart->relaDyn->addSymbolReloc(ctx.target->relativeRel, *this,
|
||||
offset, *p.first);
|
||||
ctx.in.relaDyn->addSymbolReloc(ctx.target->relativeRel, *this, offset,
|
||||
*p.first);
|
||||
}
|
||||
// Relocation-only entries exist as dummy entries for dynamic symbols that
|
||||
// aren't otherwise in the primary GOT, as the ABI requires an entry for
|
||||
@@ -962,7 +961,7 @@ void MipsGotSection::build() {
|
||||
addConstant({RE_MIPS_OSEC_LOCAL_PAGE, ctx.target->relativeRel, offset,
|
||||
addend, l.second.repSym});
|
||||
else
|
||||
ctx.mainPart->relaDyn->addRelativeReloc(
|
||||
ctx.in.relaDyn->addRelativeReloc(
|
||||
ctx.target->relativeRel, *this, offset, *l.second.repSym, addend,
|
||||
ctx.target->relativeRel, RE_MIPS_OSEC_LOCAL_PAGE);
|
||||
}
|
||||
@@ -976,9 +975,9 @@ void MipsGotSection::build() {
|
||||
addConstant({R_ABS, ctx.target->relativeRel, offset, p.first.second,
|
||||
p.first.first});
|
||||
else
|
||||
ctx.mainPart->relaDyn->addRelativeReloc(
|
||||
ctx.target->relativeRel, *this, offset, *p.first.first,
|
||||
p.first.second, ctx.target->relativeRel, R_ABS);
|
||||
ctx.in.relaDyn->addRelativeReloc(ctx.target->relativeRel, *this, offset,
|
||||
*p.first.first, p.first.second,
|
||||
ctx.target->relativeRel, R_ABS);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1154,7 +1153,7 @@ DynamicSection<ELFT>::DynamicSection(Ctx &ctx)
|
||||
|
||||
// The output section .rela.dyn may include these synthetic sections:
|
||||
//
|
||||
// - part.relaDyn
|
||||
// - ctx.in.relaDyn
|
||||
// - ctx.in.relaPlt: this is included if a linker script places .rela.plt inside
|
||||
// .rela.dyn
|
||||
//
|
||||
@@ -1176,8 +1175,6 @@ static uint64_t addPltRelSz(Ctx &ctx) { return ctx.in.relaPlt->getSize(); }
|
||||
template <class ELFT>
|
||||
std::vector<std::pair<int32_t, uint64_t>>
|
||||
DynamicSection<ELFT>::computeContents() {
|
||||
elf::Partition &part = getPartition(ctx);
|
||||
bool isMain = part.name.empty();
|
||||
std::vector<std::pair<int32_t, uint64_t>> entries;
|
||||
|
||||
auto addInt = [&](int32_t tag, uint64_t val) {
|
||||
@@ -1188,26 +1185,20 @@ DynamicSection<ELFT>::computeContents() {
|
||||
};
|
||||
|
||||
for (StringRef s : ctx.arg.filterList)
|
||||
addInt(DT_FILTER, part.dynStrTab->addString(s));
|
||||
addInt(DT_FILTER, ctx.in.dynStrTab->addString(s));
|
||||
for (StringRef s : ctx.arg.auxiliaryList)
|
||||
addInt(DT_AUXILIARY, part.dynStrTab->addString(s));
|
||||
addInt(DT_AUXILIARY, ctx.in.dynStrTab->addString(s));
|
||||
|
||||
if (!ctx.arg.rpath.empty())
|
||||
addInt(ctx.arg.enableNewDtags ? DT_RUNPATH : DT_RPATH,
|
||||
part.dynStrTab->addString(ctx.arg.rpath));
|
||||
ctx.in.dynStrTab->addString(ctx.arg.rpath));
|
||||
|
||||
for (SharedFile *file : ctx.sharedFiles)
|
||||
if (file->isNeeded)
|
||||
addInt(DT_NEEDED, part.dynStrTab->addString(file->soName));
|
||||
addInt(DT_NEEDED, ctx.in.dynStrTab->addString(file->soName));
|
||||
|
||||
if (isMain) {
|
||||
if (!ctx.arg.soName.empty())
|
||||
addInt(DT_SONAME, part.dynStrTab->addString(ctx.arg.soName));
|
||||
} else {
|
||||
if (!ctx.arg.soName.empty())
|
||||
addInt(DT_NEEDED, part.dynStrTab->addString(ctx.arg.soName));
|
||||
addInt(DT_SONAME, part.dynStrTab->addString(part.name));
|
||||
}
|
||||
if (!ctx.arg.soName.empty())
|
||||
addInt(DT_SONAME, ctx.in.dynStrTab->addString(ctx.arg.soName));
|
||||
|
||||
// Set DT_FLAGS and DT_FLAGS_1.
|
||||
uint32_t dtFlags = 0;
|
||||
@@ -1257,10 +1248,10 @@ DynamicSection<ELFT>::computeContents() {
|
||||
if (!ctx.arg.shared && !ctx.arg.relocatable && !ctx.arg.zRodynamic)
|
||||
addInt(DT_DEBUG, 0);
|
||||
|
||||
if (part.relaDyn->isNeeded()) {
|
||||
addInSec(part.relaDyn->dynamicTag, *part.relaDyn);
|
||||
entries.emplace_back(part.relaDyn->sizeDynamicTag,
|
||||
addRelaSz(ctx, *part.relaDyn));
|
||||
if (ctx.in.relaDyn->isNeeded()) {
|
||||
addInSec(ctx.in.relaDyn->dynamicTag, *ctx.in.relaDyn);
|
||||
entries.emplace_back(ctx.in.relaDyn->sizeDynamicTag,
|
||||
addRelaSz(ctx, *ctx.in.relaDyn));
|
||||
|
||||
bool isRela = ctx.arg.isRela;
|
||||
addInt(isRela ? DT_RELAENT : DT_RELENT,
|
||||
@@ -1270,27 +1261,27 @@ DynamicSection<ELFT>::computeContents() {
|
||||
// The problem is in the tight relation between dynamic
|
||||
// relocations and GOT. So do not emit this tag on MIPS.
|
||||
if (ctx.arg.emachine != EM_MIPS) {
|
||||
size_t numRelativeRels = part.relaDyn->getRelativeRelocCount();
|
||||
size_t numRelativeRels = ctx.in.relaDyn->getRelativeRelocCount();
|
||||
if (ctx.arg.zCombreloc && numRelativeRels)
|
||||
addInt(isRela ? DT_RELACOUNT : DT_RELCOUNT, numRelativeRels);
|
||||
}
|
||||
}
|
||||
if (part.relrDyn && part.relrDyn->getParent() &&
|
||||
!part.relrDyn->relocs.empty()) {
|
||||
if (ctx.in.relrDyn && ctx.in.relrDyn->getParent() &&
|
||||
!ctx.in.relrDyn->relocs.empty()) {
|
||||
addInSec(ctx.arg.useAndroidRelrTags ? DT_ANDROID_RELR : DT_RELR,
|
||||
*part.relrDyn);
|
||||
*ctx.in.relrDyn);
|
||||
addInt(ctx.arg.useAndroidRelrTags ? DT_ANDROID_RELRSZ : DT_RELRSZ,
|
||||
part.relrDyn->getParent()->size);
|
||||
ctx.in.relrDyn->getParent()->size);
|
||||
addInt(ctx.arg.useAndroidRelrTags ? DT_ANDROID_RELRENT : DT_RELRENT,
|
||||
sizeof(Elf_Relr));
|
||||
}
|
||||
if (part.relrAuthDyn && part.relrAuthDyn->getParent() &&
|
||||
!part.relrAuthDyn->relocs.empty()) {
|
||||
addInSec(DT_AARCH64_AUTH_RELR, *part.relrAuthDyn);
|
||||
addInt(DT_AARCH64_AUTH_RELRSZ, part.relrAuthDyn->getParent()->size);
|
||||
if (ctx.in.relrAuthDyn && ctx.in.relrAuthDyn->getParent() &&
|
||||
!ctx.in.relrAuthDyn->relocs.empty()) {
|
||||
addInSec(DT_AARCH64_AUTH_RELR, *ctx.in.relrAuthDyn);
|
||||
addInt(DT_AARCH64_AUTH_RELRSZ, ctx.in.relrAuthDyn->getParent()->size);
|
||||
addInt(DT_AARCH64_AUTH_RELRENT, sizeof(Elf_Relr));
|
||||
}
|
||||
if (isMain && ctx.in.relaPlt->isNeeded()) {
|
||||
if (ctx.in.relaPlt->isNeeded()) {
|
||||
addInSec(DT_JMPREL, *ctx.in.relaPlt);
|
||||
entries.emplace_back(DT_PLTRELSZ, addPltRelSz(ctx));
|
||||
switch (ctx.arg.emachine) {
|
||||
@@ -1338,56 +1329,53 @@ DynamicSection<ELFT>::computeContents() {
|
||||
ctx.arg.memtagMode == NT_MEMTAG_LEVEL_ASYNC);
|
||||
addInt(DT_AARCH64_MEMTAG_HEAP, ctx.arg.memtagHeap);
|
||||
addInt(DT_AARCH64_MEMTAG_STACK, ctx.arg.memtagStack);
|
||||
if (ctx.mainPart->memtagGlobalDescriptors->isNeeded()) {
|
||||
addInSec(DT_AARCH64_MEMTAG_GLOBALS,
|
||||
*ctx.mainPart->memtagGlobalDescriptors);
|
||||
if (ctx.in.memtagGlobalDescriptors->isNeeded()) {
|
||||
addInSec(DT_AARCH64_MEMTAG_GLOBALS, *ctx.in.memtagGlobalDescriptors);
|
||||
addInt(DT_AARCH64_MEMTAG_GLOBALSSZ,
|
||||
ctx.mainPart->memtagGlobalDescriptors->getSize());
|
||||
ctx.in.memtagGlobalDescriptors->getSize());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
addInSec(DT_SYMTAB, *part.dynSymTab);
|
||||
addInSec(DT_SYMTAB, *ctx.in.dynSymTab);
|
||||
addInt(DT_SYMENT, sizeof(Elf_Sym));
|
||||
addInSec(DT_STRTAB, *part.dynStrTab);
|
||||
addInt(DT_STRSZ, part.dynStrTab->getSize());
|
||||
addInSec(DT_STRTAB, *ctx.in.dynStrTab);
|
||||
addInt(DT_STRSZ, ctx.in.dynStrTab->getSize());
|
||||
if (!ctx.arg.zText)
|
||||
addInt(DT_TEXTREL, 0);
|
||||
if (part.gnuHashTab && part.gnuHashTab->getParent())
|
||||
addInSec(DT_GNU_HASH, *part.gnuHashTab);
|
||||
if (part.hashTab && part.hashTab->getParent())
|
||||
addInSec(DT_HASH, *part.hashTab);
|
||||
if (ctx.in.gnuHashTab && ctx.in.gnuHashTab->getParent())
|
||||
addInSec(DT_GNU_HASH, *ctx.in.gnuHashTab);
|
||||
if (ctx.in.hashTab && ctx.in.hashTab->getParent())
|
||||
addInSec(DT_HASH, *ctx.in.hashTab);
|
||||
|
||||
if (isMain) {
|
||||
if (ctx.out.preinitArray) {
|
||||
addInt(DT_PREINIT_ARRAY, ctx.out.preinitArray->addr);
|
||||
addInt(DT_PREINIT_ARRAYSZ, ctx.out.preinitArray->size);
|
||||
}
|
||||
if (ctx.out.initArray) {
|
||||
addInt(DT_INIT_ARRAY, ctx.out.initArray->addr);
|
||||
addInt(DT_INIT_ARRAYSZ, ctx.out.initArray->size);
|
||||
}
|
||||
if (ctx.out.finiArray) {
|
||||
addInt(DT_FINI_ARRAY, ctx.out.finiArray->addr);
|
||||
addInt(DT_FINI_ARRAYSZ, ctx.out.finiArray->size);
|
||||
}
|
||||
|
||||
if (Symbol *b = ctx.symtab->find(ctx.arg.init))
|
||||
if (b->isDefined())
|
||||
addInt(DT_INIT, b->getVA(ctx));
|
||||
if (Symbol *b = ctx.symtab->find(ctx.arg.fini))
|
||||
if (b->isDefined())
|
||||
addInt(DT_FINI, b->getVA(ctx));
|
||||
if (ctx.out.preinitArray) {
|
||||
addInt(DT_PREINIT_ARRAY, ctx.out.preinitArray->addr);
|
||||
addInt(DT_PREINIT_ARRAYSZ, ctx.out.preinitArray->size);
|
||||
}
|
||||
if (ctx.out.initArray) {
|
||||
addInt(DT_INIT_ARRAY, ctx.out.initArray->addr);
|
||||
addInt(DT_INIT_ARRAYSZ, ctx.out.initArray->size);
|
||||
}
|
||||
if (ctx.out.finiArray) {
|
||||
addInt(DT_FINI_ARRAY, ctx.out.finiArray->addr);
|
||||
addInt(DT_FINI_ARRAYSZ, ctx.out.finiArray->size);
|
||||
}
|
||||
|
||||
if (part.verSym && part.verSym->isNeeded())
|
||||
addInSec(DT_VERSYM, *part.verSym);
|
||||
if (part.verDef && part.verDef->isLive()) {
|
||||
addInSec(DT_VERDEF, *part.verDef);
|
||||
if (Symbol *b = ctx.symtab->find(ctx.arg.init))
|
||||
if (b->isDefined())
|
||||
addInt(DT_INIT, b->getVA(ctx));
|
||||
if (Symbol *b = ctx.symtab->find(ctx.arg.fini))
|
||||
if (b->isDefined())
|
||||
addInt(DT_FINI, b->getVA(ctx));
|
||||
|
||||
if (ctx.in.verSym && ctx.in.verSym->isNeeded())
|
||||
addInSec(DT_VERSYM, *ctx.in.verSym);
|
||||
if (ctx.in.verDef && ctx.in.verDef->isLive()) {
|
||||
addInSec(DT_VERDEF, *ctx.in.verDef);
|
||||
addInt(DT_VERDEFNUM, getVerDefNum(ctx));
|
||||
}
|
||||
if (part.verNeed && part.verNeed->isNeeded()) {
|
||||
addInSec(DT_VERNEED, *part.verNeed);
|
||||
if (ctx.in.verNeed && ctx.in.verNeed->isNeeded()) {
|
||||
addInSec(DT_VERNEED, *ctx.in.verNeed);
|
||||
unsigned needNum = 0;
|
||||
for (SharedFile *f : ctx.sharedFiles)
|
||||
if (!f->verneedInfo.empty())
|
||||
@@ -1399,13 +1387,13 @@ DynamicSection<ELFT>::computeContents() {
|
||||
addInt(DT_MIPS_RLD_VERSION, 1);
|
||||
addInt(DT_MIPS_FLAGS, RHF_NOTPOT);
|
||||
addInt(DT_MIPS_BASE_ADDRESS, ctx.target->getImageBase());
|
||||
addInt(DT_MIPS_SYMTABNO, part.dynSymTab->getNumSymbols());
|
||||
addInt(DT_MIPS_SYMTABNO, ctx.in.dynSymTab->getNumSymbols());
|
||||
addInt(DT_MIPS_LOCAL_GOTNO, ctx.in.mipsGot->getLocalEntriesNum());
|
||||
|
||||
if (const Symbol *b = ctx.in.mipsGot->getFirstGlobalEntry())
|
||||
addInt(DT_MIPS_GOTSYM, b->dynsymIndex);
|
||||
else
|
||||
addInt(DT_MIPS_GOTSYM, part.dynSymTab->getNumSymbols());
|
||||
addInt(DT_MIPS_GOTSYM, ctx.in.dynSymTab->getNumSymbols());
|
||||
addInSec(DT_PLTGOT, *ctx.in.mipsGot);
|
||||
if (ctx.in.mipsRldMap) {
|
||||
if (!ctx.arg.pie)
|
||||
@@ -1438,7 +1426,7 @@ DynamicSection<ELFT>::computeContents() {
|
||||
}
|
||||
|
||||
template <class ELFT> void DynamicSection<ELFT>::finalizeContents() {
|
||||
if (OutputSection *sec = getPartition(ctx).dynStrTab->getParent())
|
||||
if (OutputSection *sec = ctx.in.dynStrTab->getParent())
|
||||
getParent()->link = sec->sectionIndex;
|
||||
this->size = computeContents().size() * this->entsize;
|
||||
}
|
||||
@@ -1472,7 +1460,7 @@ uint32_t DynamicReloc::getSymIndex(SymbolTableBaseSection *symTab) const {
|
||||
assert((index != 0 ||
|
||||
(type != symTab->ctx.target->gotRel &&
|
||||
type != symTab->ctx.target->pltRel) ||
|
||||
!symTab->ctx.mainPart->dynSymTab->getParent()) &&
|
||||
!symTab->ctx.in.dynSymTab->getParent()) &&
|
||||
"GOT or PLT relocation must refer to symbol in dynamic symbol table");
|
||||
return index;
|
||||
}
|
||||
@@ -1525,7 +1513,7 @@ void RelocationBaseSection::finalizeContents() {
|
||||
// to emit DT_RELACOUNT, so this must match.
|
||||
if (combreloc)
|
||||
numRelativeRelocs = relativeRelocs.size();
|
||||
SymbolTableBaseSection *symTab = getPartition(ctx).dynSymTab.get();
|
||||
SymbolTableBaseSection *symTab = ctx.in.dynSymTab.get();
|
||||
|
||||
// When linking glibc statically, .rel{,a}.plt contains R_*_IRELATIVE
|
||||
// relocations due to IFUNC (e.g. strcpy). sh_link will be set to 0 in that
|
||||
@@ -1549,7 +1537,7 @@ void DynamicReloc::finalize(Ctx &ctx, SymbolTableBaseSection *symt) {
|
||||
}
|
||||
|
||||
void RelocationBaseSection::computeRels() {
|
||||
SymbolTableBaseSection *symTab = getPartition(ctx).dynSymTab.get();
|
||||
SymbolTableBaseSection *symTab = ctx.in.dynSymTab.get();
|
||||
parallelForEach(relativeRelocs, [&ctx = ctx, symTab](DynamicReloc &rel) {
|
||||
rel.finalize(ctx, symTab);
|
||||
});
|
||||
@@ -1691,7 +1679,7 @@ bool AndroidPackedRelocationSection<ELFT>::updateAllocSize(Ctx &ctx) {
|
||||
add(relativeRelocs.size() + relocs.size());
|
||||
add(0);
|
||||
|
||||
SymbolTableBaseSection *symTab = getPartition(ctx).dynSymTab.get();
|
||||
SymbolTableBaseSection *symTab = ctx.in.dynSymTab.get();
|
||||
auto makeRela = [&](const DynamicReloc &rel) {
|
||||
Elf_Rela r;
|
||||
r.r_offset = rel.getOffset();
|
||||
@@ -2002,20 +1990,19 @@ void SymbolTableBaseSection::finalizeContents() {
|
||||
// Because the first symbol entry is a null entry, 1 is the first.
|
||||
getParent()->info = 1;
|
||||
|
||||
if (getPartition(ctx).gnuHashTab) {
|
||||
if (ctx.in.gnuHashTab) {
|
||||
// NB: It also sorts Symbols to meet the GNU hash table requirements.
|
||||
getPartition(ctx).gnuHashTab->addSymbols(symbols);
|
||||
ctx.in.gnuHashTab->addSymbols(symbols);
|
||||
} else if (ctx.arg.emachine == EM_MIPS) {
|
||||
sortMipsSymbols(ctx, symbols);
|
||||
}
|
||||
|
||||
// Only the main partition's dynsym indexes are stored in the symbols
|
||||
// themselves. All other partitions use a lookup table.
|
||||
if (this == ctx.mainPart->dynSymTab.get()) {
|
||||
size_t i = 0;
|
||||
for (const SymbolTableEntry &s : symbols)
|
||||
s.sym->dynsymIndex = ++i;
|
||||
}
|
||||
// The dynamic symbol table records each symbol's index in the symbol itself.
|
||||
// The static .symtab cannot (the slot is taken) and instead uses a lazy
|
||||
// lookup table; see getSymbolIndex.
|
||||
size_t i = 0;
|
||||
for (const SymbolTableEntry &s : symbols)
|
||||
s.sym->dynsymIndex = ++i;
|
||||
}
|
||||
|
||||
// The ELF spec requires that all local symbols precede global symbols, so we
|
||||
@@ -2055,11 +2042,11 @@ void SymbolTableBaseSection::addSymbol(Symbol *b) {
|
||||
}
|
||||
|
||||
size_t SymbolTableBaseSection::getSymbolIndex(const Symbol &sym) {
|
||||
if (this == ctx.mainPart->dynSymTab.get())
|
||||
if (this == ctx.in.dynSymTab.get())
|
||||
return sym.dynsymIndex;
|
||||
|
||||
// Initializes symbol lookup tables lazily. This is used only for -r,
|
||||
// --emit-relocs and dynsyms in partitions other than the main one.
|
||||
// Initialize the symbol lookup table lazily. This is used for the static
|
||||
// symbol table (.symtab), e.g. with -r or --emit-relocs.
|
||||
llvm::call_once(onceFlag, [&] {
|
||||
symbolIndexMap.reserve(symbols.size());
|
||||
size_t i = 0;
|
||||
@@ -2248,7 +2235,7 @@ GnuHashTableSection::GnuHashTableSection(Ctx &ctx)
|
||||
ctx.arg.wordsize) {}
|
||||
|
||||
void GnuHashTableSection::finalizeContents() {
|
||||
if (OutputSection *sec = getPartition(ctx).dynSymTab->getParent())
|
||||
if (OutputSection *sec = ctx.in.dynSymTab->getParent())
|
||||
getParent()->link = sec->sectionIndex;
|
||||
|
||||
// Computes bloom filter size in word size. We want to allocate 12
|
||||
@@ -2269,8 +2256,7 @@ void GnuHashTableSection::finalizeContents() {
|
||||
void GnuHashTableSection::writeTo(uint8_t *buf) {
|
||||
// Write a header.
|
||||
write32(ctx, buf, nBuckets);
|
||||
write32(ctx, buf + 4,
|
||||
getPartition(ctx).dynSymTab->getNumSymbols() - symbols.size());
|
||||
write32(ctx, buf + 4, ctx.in.dynSymTab->getNumSymbols() - symbols.size());
|
||||
write32(ctx, buf + 8, maskWords);
|
||||
write32(ctx, buf + 12, Shift2);
|
||||
buf += 16;
|
||||
@@ -2306,7 +2292,7 @@ void GnuHashTableSection::writeTo(uint8_t *buf) {
|
||||
// Write a hash bucket. Hash buckets contain indices in the following hash
|
||||
// value table.
|
||||
write32(ctx, buckets + i->bucketIdx,
|
||||
getPartition(ctx).dynSymTab->getSymbolIndex(*i->sym));
|
||||
ctx.in.dynSymTab->getSymbolIndex(*i->sym));
|
||||
oldBucket = i->bucketIdx;
|
||||
}
|
||||
}
|
||||
@@ -2359,7 +2345,7 @@ HashTableSection::HashTableSection(Ctx &ctx)
|
||||
}
|
||||
|
||||
void HashTableSection::finalizeContents() {
|
||||
SymbolTableBaseSection *symTab = getPartition(ctx).dynSymTab.get();
|
||||
SymbolTableBaseSection *symTab = ctx.in.dynSymTab.get();
|
||||
|
||||
if (OutputSection *sec = symTab->getParent())
|
||||
getParent()->link = sec->sectionIndex;
|
||||
@@ -2373,7 +2359,7 @@ void HashTableSection::finalizeContents() {
|
||||
}
|
||||
|
||||
void HashTableSection::writeTo(uint8_t *buf) {
|
||||
SymbolTableBaseSection *symTab = getPartition(ctx).dynSymTab.get();
|
||||
SymbolTableBaseSection *symTab = ctx.in.dynSymTab.get();
|
||||
unsigned numSymbols = symTab->getNumSymbols();
|
||||
|
||||
uint32_t *p = reinterpret_cast<uint32_t *>(buf);
|
||||
@@ -3505,19 +3491,17 @@ VersionDefinitionSection::VersionDefinitionSection(Ctx &ctx)
|
||||
sizeof(uint32_t)) {}
|
||||
|
||||
StringRef VersionDefinitionSection::getFileDefName() {
|
||||
if (!getPartition(ctx).name.empty())
|
||||
return getPartition(ctx).name;
|
||||
if (!ctx.arg.soName.empty())
|
||||
return ctx.arg.soName;
|
||||
return ctx.arg.outputFile;
|
||||
}
|
||||
|
||||
void VersionDefinitionSection::finalizeContents() {
|
||||
fileDefNameOff = getPartition(ctx).dynStrTab->addString(getFileDefName());
|
||||
fileDefNameOff = ctx.in.dynStrTab->addString(getFileDefName());
|
||||
for (const VersionDefinition &v : namedVersionDefs(ctx))
|
||||
verDefNameOffs.push_back(getPartition(ctx).dynStrTab->addString(v.name));
|
||||
verDefNameOffs.push_back(ctx.in.dynStrTab->addString(v.name));
|
||||
|
||||
if (OutputSection *sec = getPartition(ctx).dynStrTab->getParent())
|
||||
if (OutputSection *sec = ctx.in.dynStrTab->getParent())
|
||||
getParent()->link = sec->sectionIndex;
|
||||
|
||||
// sh_info should be set to the number of definitions. This fact is missed in
|
||||
@@ -3569,17 +3553,17 @@ VersionTableSection::VersionTableSection(Ctx &ctx)
|
||||
}
|
||||
|
||||
void VersionTableSection::finalizeContents() {
|
||||
if (OutputSection *osec = getPartition(ctx).dynSymTab->getParent())
|
||||
if (OutputSection *osec = ctx.in.dynSymTab->getParent())
|
||||
getParent()->link = osec->sectionIndex;
|
||||
}
|
||||
|
||||
size_t VersionTableSection::getSize() const {
|
||||
return (getPartition(ctx).dynSymTab->getSymbols().size() + 1) * 2;
|
||||
return (ctx.in.dynSymTab->getSymbols().size() + 1) * 2;
|
||||
}
|
||||
|
||||
void VersionTableSection::writeTo(uint8_t *buf) {
|
||||
buf += 2;
|
||||
for (const SymbolTableEntry &s : getPartition(ctx).dynSymTab->getSymbols()) {
|
||||
for (const SymbolTableEntry &s : ctx.in.dynSymTab->getSymbols()) {
|
||||
// For an unextracted lazy symbol (undefined weak), it must have been
|
||||
// converted to Undefined.
|
||||
assert(!s.sym->isLazy());
|
||||
@@ -3590,8 +3574,7 @@ void VersionTableSection::writeTo(uint8_t *buf) {
|
||||
}
|
||||
|
||||
bool VersionTableSection::isNeeded() const {
|
||||
return isLive() &&
|
||||
(getPartition(ctx).verDef || getPartition(ctx).verNeed->isNeeded());
|
||||
return isLive() && (ctx.in.verDef || ctx.in.verNeed->isNeeded());
|
||||
}
|
||||
|
||||
void elf::addVerneed(Ctx &ctx, Symbol &ss) {
|
||||
@@ -3624,7 +3607,7 @@ template <class ELFT> void VersionNeedSection<ELFT>::finalizeContents() {
|
||||
continue;
|
||||
verneeds.emplace_back();
|
||||
Verneed &vn = verneeds.back();
|
||||
vn.nameStrTab = getPartition(ctx).dynStrTab->addString(f->soName);
|
||||
vn.nameStrTab = ctx.in.dynStrTab->addString(f->soName);
|
||||
bool isLibc = ctx.arg.relrGlibc && f->soName.starts_with("libc.so.");
|
||||
bool isGlibc2 = false;
|
||||
for (unsigned i = 0; i != f->verneedInfo.size(); ++i) {
|
||||
@@ -3640,18 +3623,18 @@ template <class ELFT> void VersionNeedSection<ELFT>::finalizeContents() {
|
||||
if (isLibc && ver.starts_with("GLIBC_2."))
|
||||
isGlibc2 = true;
|
||||
vn.vernauxs.push_back({verdef->vd_hash, f->verneedInfo[i],
|
||||
getPartition(ctx).dynStrTab->addString(ver)});
|
||||
ctx.in.dynStrTab->addString(ver)});
|
||||
}
|
||||
if (isGlibc2) {
|
||||
const char *ver = "GLIBC_ABI_DT_RELR";
|
||||
vn.vernauxs.push_back(
|
||||
{hashSysV(ver),
|
||||
{uint16_t(++ctx.vernauxNum + getVerDefNum(ctx)), false},
|
||||
getPartition(ctx).dynStrTab->addString(ver)});
|
||||
ctx.in.dynStrTab->addString(ver)});
|
||||
}
|
||||
}
|
||||
|
||||
if (OutputSection *sec = getPartition(ctx).dynStrTab->getParent())
|
||||
if (OutputSection *sec = ctx.in.dynStrTab->getParent())
|
||||
getParent()->link = sec->sectionIndex;
|
||||
getParent()->info = verneeds.size();
|
||||
}
|
||||
@@ -3829,23 +3812,20 @@ template <class ELFT> void elf::splitSections(Ctx &ctx) {
|
||||
void elf::combineEhSections(Ctx &ctx) {
|
||||
llvm::TimeTraceScope timeScope("Combine EH sections");
|
||||
for (EhInputSection *sec : ctx.ehInputSections) {
|
||||
EhFrameSection &eh = *sec->getPartition(ctx).ehFrame;
|
||||
EhFrameSection &eh = *ctx.in.ehFrame;
|
||||
sec->parent = &eh;
|
||||
eh.addralign = std::max(eh.addralign, sec->addralign);
|
||||
eh.sections.push_back(sec);
|
||||
llvm::append_range(eh.dependentSections, sec->dependentSections);
|
||||
}
|
||||
|
||||
if (!ctx.mainPart->armExidx)
|
||||
if (!ctx.in.armExidx)
|
||||
return;
|
||||
llvm::erase_if(ctx.inputSections, [&](InputSectionBase *s) {
|
||||
// Ignore dead sections and the partition end marker (.part.end),
|
||||
// whose partition number is out of bounds.
|
||||
if (!s->isLive() || s->partition == 255)
|
||||
if (!s->isLive())
|
||||
return false;
|
||||
Partition &part = s->getPartition(ctx);
|
||||
return s->kind() == SectionBase::Regular && part.armExidx &&
|
||||
part.armExidx->addSection(cast<InputSection>(s));
|
||||
return s->kind() == SectionBase::Regular &&
|
||||
ctx.in.armExidx->addSection(cast<InputSection>(s));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -4204,8 +4184,7 @@ static uint8_t getAbiVersion(Ctx &ctx) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <typename ELFT>
|
||||
void elf::writeEhdr(Ctx &ctx, uint8_t *buf, Partition &part) {
|
||||
template <typename ELFT> void elf::writeEhdr(Ctx &ctx, uint8_t *buf) {
|
||||
memcpy(buf, "\177ELF", 4);
|
||||
|
||||
auto *eHdr = reinterpret_cast<typename ELFT::Ehdr *>(buf);
|
||||
@@ -4219,7 +4198,7 @@ void elf::writeEhdr(Ctx &ctx, uint8_t *buf, Partition &part) {
|
||||
eHdr->e_version = EV_CURRENT;
|
||||
eHdr->e_flags = ctx.arg.eflags;
|
||||
eHdr->e_ehsize = sizeof(typename ELFT::Ehdr);
|
||||
eHdr->e_phnum = part.phdrs.size();
|
||||
eHdr->e_phnum = ctx.phdrs.size();
|
||||
eHdr->e_shentsize = sizeof(typename ELFT::Shdr);
|
||||
|
||||
if (!ctx.arg.relocatable) {
|
||||
@@ -4228,10 +4207,10 @@ void elf::writeEhdr(Ctx &ctx, uint8_t *buf, Partition &part) {
|
||||
}
|
||||
}
|
||||
|
||||
template <typename ELFT> void elf::writePhdrs(uint8_t *buf, Partition &part) {
|
||||
template <typename ELFT> void elf::writePhdrs(Ctx &ctx, uint8_t *buf) {
|
||||
// Write the program header table.
|
||||
auto *hBuf = reinterpret_cast<typename ELFT::Phdr *>(buf);
|
||||
for (std::unique_ptr<PhdrEntry> &p : part.phdrs) {
|
||||
for (std::unique_ptr<PhdrEntry> &p : ctx.phdrs) {
|
||||
hBuf->p_type = p->p_type;
|
||||
hBuf->p_flags = p->p_flags;
|
||||
hBuf->p_offset = p->p_offset;
|
||||
@@ -4244,39 +4223,6 @@ template <typename ELFT> void elf::writePhdrs(uint8_t *buf, Partition &part) {
|
||||
}
|
||||
}
|
||||
|
||||
template <typename ELFT>
|
||||
PartitionElfHeaderSection<ELFT>::PartitionElfHeaderSection(Ctx &ctx)
|
||||
: SyntheticSection(ctx, "", SHT_LLVM_PART_EHDR, SHF_ALLOC, 1) {}
|
||||
|
||||
template <typename ELFT>
|
||||
size_t PartitionElfHeaderSection<ELFT>::getSize() const {
|
||||
return sizeof(typename ELFT::Ehdr);
|
||||
}
|
||||
|
||||
template <typename ELFT>
|
||||
void PartitionElfHeaderSection<ELFT>::writeTo(uint8_t *buf) {
|
||||
writeEhdr<ELFT>(ctx, buf, ctx.partitions[partition - 1]);
|
||||
|
||||
// Loadable partitions are always ET_DYN.
|
||||
auto *eHdr = reinterpret_cast<typename ELFT::Ehdr *>(buf);
|
||||
eHdr->e_type = ET_DYN;
|
||||
}
|
||||
|
||||
template <typename ELFT>
|
||||
PartitionProgramHeadersSection<ELFT>::PartitionProgramHeadersSection(Ctx &ctx)
|
||||
: SyntheticSection(ctx, ".phdrs", SHT_LLVM_PART_PHDR, SHF_ALLOC, 1) {}
|
||||
|
||||
template <typename ELFT>
|
||||
size_t PartitionProgramHeadersSection<ELFT>::getSize() const {
|
||||
return sizeof(typename ELFT::Phdr) *
|
||||
ctx.partitions[partition - 1].phdrs.size();
|
||||
}
|
||||
|
||||
template <typename ELFT>
|
||||
void PartitionProgramHeadersSection<ELFT>::writeTo(uint8_t *buf) {
|
||||
writePhdrs<ELFT>(buf, ctx.partitions[partition - 1]);
|
||||
}
|
||||
|
||||
static bool needsInterpSection(Ctx &ctx) {
|
||||
return !ctx.arg.relocatable && !ctx.arg.shared &&
|
||||
!ctx.arg.dynamicLinker.empty() && ctx.script->needsInterpSection();
|
||||
@@ -4466,124 +4412,97 @@ template <class ELFT> void elf::createSyntheticSections(Ctx &ctx) {
|
||||
|
||||
const unsigned threadCount = ctx.arg.threadCount;
|
||||
do {
|
||||
Partition &part = *ctx.mainPart;
|
||||
auto add = [&](SyntheticSection &sec) {
|
||||
sec.partition = part.partno;
|
||||
ctx.inputSections.push_back(&sec);
|
||||
};
|
||||
|
||||
if (ctx.arg.buildId != BuildIdKind::None) {
|
||||
part.buildId = std::make_unique<BuildIdSection>(ctx);
|
||||
add(*part.buildId);
|
||||
ctx.in.buildId = std::make_unique<BuildIdSection>(ctx);
|
||||
add(*ctx.in.buildId);
|
||||
}
|
||||
|
||||
// dynSymTab is always present to simplify several finalizeSections
|
||||
// functions.
|
||||
part.dynStrTab = std::make_unique<StringTableSection>(ctx, ".dynstr", true);
|
||||
part.dynSymTab =
|
||||
std::make_unique<SymbolTableSection<ELFT>>(ctx, *part.dynStrTab);
|
||||
ctx.in.dynStrTab =
|
||||
std::make_unique<StringTableSection>(ctx, ".dynstr", true);
|
||||
ctx.in.dynSymTab =
|
||||
std::make_unique<SymbolTableSection<ELFT>>(ctx, *ctx.in.dynStrTab);
|
||||
|
||||
if (ctx.arg.relocatable)
|
||||
break;
|
||||
part.dynamic = std::make_unique<DynamicSection<ELFT>>(ctx);
|
||||
ctx.in.dynamic = std::make_unique<DynamicSection<ELFT>>(ctx);
|
||||
|
||||
if (hasMemtag(ctx)) {
|
||||
if (ctx.arg.memtagAndroidNote) {
|
||||
part.memtagAndroidNote = std::make_unique<MemtagAndroidNote>(ctx);
|
||||
add(*part.memtagAndroidNote);
|
||||
ctx.in.memtagAndroidNote = std::make_unique<MemtagAndroidNote>(ctx);
|
||||
add(*ctx.in.memtagAndroidNote);
|
||||
}
|
||||
if (canHaveMemtagGlobals(ctx)) {
|
||||
part.memtagGlobalDescriptors =
|
||||
ctx.in.memtagGlobalDescriptors =
|
||||
std::make_unique<MemtagGlobalDescriptors>(ctx);
|
||||
add(*part.memtagGlobalDescriptors);
|
||||
add(*ctx.in.memtagGlobalDescriptors);
|
||||
}
|
||||
}
|
||||
|
||||
if (ctx.arg.androidPackDynRelocs)
|
||||
part.relaDyn = std::make_unique<AndroidPackedRelocationSection<ELFT>>(
|
||||
ctx.in.relaDyn = std::make_unique<AndroidPackedRelocationSection<ELFT>>(
|
||||
ctx, relaDynName, threadCount);
|
||||
else
|
||||
part.relaDyn = std::make_unique<RelocationSection<ELFT>>(
|
||||
ctx.in.relaDyn = std::make_unique<RelocationSection<ELFT>>(
|
||||
ctx, relaDynName, /*combreloc=*/true, threadCount);
|
||||
|
||||
if (ctx.hasDynsym) {
|
||||
add(*part.dynSymTab);
|
||||
add(*ctx.in.dynSymTab);
|
||||
|
||||
part.verSym = std::make_unique<VersionTableSection>(ctx);
|
||||
add(*part.verSym);
|
||||
ctx.in.verSym = std::make_unique<VersionTableSection>(ctx);
|
||||
add(*ctx.in.verSym);
|
||||
|
||||
if (!namedVersionDefs(ctx).empty()) {
|
||||
part.verDef = std::make_unique<VersionDefinitionSection>(ctx);
|
||||
add(*part.verDef);
|
||||
ctx.in.verDef = std::make_unique<VersionDefinitionSection>(ctx);
|
||||
add(*ctx.in.verDef);
|
||||
}
|
||||
|
||||
part.verNeed = std::make_unique<VersionNeedSection<ELFT>>(ctx);
|
||||
add(*part.verNeed);
|
||||
ctx.in.verNeed = std::make_unique<VersionNeedSection<ELFT>>(ctx);
|
||||
add(*ctx.in.verNeed);
|
||||
|
||||
if (ctx.arg.gnuHash) {
|
||||
part.gnuHashTab = std::make_unique<GnuHashTableSection>(ctx);
|
||||
add(*part.gnuHashTab);
|
||||
ctx.in.gnuHashTab = std::make_unique<GnuHashTableSection>(ctx);
|
||||
add(*ctx.in.gnuHashTab);
|
||||
}
|
||||
|
||||
if (ctx.arg.sysvHash) {
|
||||
part.hashTab = std::make_unique<HashTableSection>(ctx);
|
||||
add(*part.hashTab);
|
||||
ctx.in.hashTab = std::make_unique<HashTableSection>(ctx);
|
||||
add(*ctx.in.hashTab);
|
||||
}
|
||||
|
||||
add(*part.dynamic);
|
||||
add(*part.dynStrTab);
|
||||
add(*ctx.in.dynamic);
|
||||
add(*ctx.in.dynStrTab);
|
||||
}
|
||||
add(*part.relaDyn);
|
||||
add(*ctx.in.relaDyn);
|
||||
|
||||
if (ctx.arg.relrPackDynRelocs) {
|
||||
part.relrDyn = std::make_unique<RelrSection<ELFT>>(ctx, threadCount);
|
||||
add(*part.relrDyn);
|
||||
part.relrAuthDyn = std::make_unique<RelrSection<ELFT>>(
|
||||
ctx.in.relrDyn = std::make_unique<RelrSection<ELFT>>(ctx, threadCount);
|
||||
add(*ctx.in.relrDyn);
|
||||
ctx.in.relrAuthDyn = std::make_unique<RelrSection<ELFT>>(
|
||||
ctx, threadCount, /*isAArch64Auth=*/true);
|
||||
add(*part.relrAuthDyn);
|
||||
add(*ctx.in.relrAuthDyn);
|
||||
}
|
||||
|
||||
if (ctx.arg.ehFrameHdr) {
|
||||
part.ehFrameHdr = std::make_unique<EhFrameHeader>(ctx);
|
||||
add(*part.ehFrameHdr);
|
||||
ctx.in.ehFrameHdr = std::make_unique<EhFrameHeader>(ctx);
|
||||
add(*ctx.in.ehFrameHdr);
|
||||
}
|
||||
part.ehFrame = std::make_unique<EhFrameSection>(ctx);
|
||||
add(*part.ehFrame);
|
||||
ctx.in.ehFrame = std::make_unique<EhFrameSection>(ctx);
|
||||
add(*ctx.in.ehFrame);
|
||||
|
||||
if (ctx.arg.emachine == EM_ARM) {
|
||||
// This section replaces all the individual .ARM.exidx InputSections.
|
||||
part.armExidx = std::make_unique<ARMExidxSyntheticSection>(ctx);
|
||||
add(*part.armExidx);
|
||||
ctx.in.armExidx = std::make_unique<ARMExidxSyntheticSection>(ctx);
|
||||
add(*ctx.in.armExidx);
|
||||
}
|
||||
|
||||
if (!ctx.arg.packageMetadata.empty()) {
|
||||
part.packageMetadataNote = std::make_unique<PackageMetadataNote>(ctx);
|
||||
add(*part.packageMetadataNote);
|
||||
ctx.in.packageMetadataNote = std::make_unique<PackageMetadataNote>(ctx);
|
||||
add(*ctx.in.packageMetadataNote);
|
||||
}
|
||||
} while (0);
|
||||
|
||||
for (Partition &shim : llvm::drop_begin(ctx.partitions)) {
|
||||
shim.elfHeader = std::make_unique<PartitionElfHeaderSection<ELFT>>(ctx);
|
||||
shim.elfHeader->name = shim.name;
|
||||
shim.elfHeader->partition = shim.partno;
|
||||
ctx.inputSections.push_back(shim.elfHeader.get());
|
||||
|
||||
shim.programHeaders =
|
||||
std::make_unique<PartitionProgramHeadersSection<ELFT>>(ctx);
|
||||
shim.programHeaders->partition = shim.partno;
|
||||
ctx.inputSections.push_back(shim.programHeaders.get());
|
||||
}
|
||||
|
||||
if (ctx.partitions.size() > 1) {
|
||||
// Create the partition end marker. This needs to be in partition number 255
|
||||
// so that it is sorted after all other partitions. It also has other
|
||||
// special handling (see createPhdrs() and combineEhSections()).
|
||||
ctx.in.partEnd =
|
||||
std::make_unique<BssSection>(ctx, ".part.end", ctx.arg.maxPageSize, 1);
|
||||
ctx.in.partEnd->partition = 255;
|
||||
add(*ctx.in.partEnd);
|
||||
}
|
||||
|
||||
// Add .got. MIPS' .got is so different from the other archs,
|
||||
// it has its own class.
|
||||
if (ctx.arg.emachine == EM_MIPS) {
|
||||
@@ -4685,15 +4604,15 @@ template class elf::SymbolTableSection<ELF32BE>;
|
||||
template class elf::SymbolTableSection<ELF64LE>;
|
||||
template class elf::SymbolTableSection<ELF64BE>;
|
||||
|
||||
template void elf::writeEhdr<ELF32LE>(Ctx &, uint8_t *Buf, Partition &Part);
|
||||
template void elf::writeEhdr<ELF32BE>(Ctx &, uint8_t *Buf, Partition &Part);
|
||||
template void elf::writeEhdr<ELF64LE>(Ctx &, uint8_t *Buf, Partition &Part);
|
||||
template void elf::writeEhdr<ELF64BE>(Ctx &, uint8_t *Buf, Partition &Part);
|
||||
template void elf::writeEhdr<ELF32LE>(Ctx &, uint8_t *Buf);
|
||||
template void elf::writeEhdr<ELF32BE>(Ctx &, uint8_t *Buf);
|
||||
template void elf::writeEhdr<ELF64LE>(Ctx &, uint8_t *Buf);
|
||||
template void elf::writeEhdr<ELF64BE>(Ctx &, uint8_t *Buf);
|
||||
|
||||
template void elf::writePhdrs<ELF32LE>(uint8_t *Buf, Partition &Part);
|
||||
template void elf::writePhdrs<ELF32BE>(uint8_t *Buf, Partition &Part);
|
||||
template void elf::writePhdrs<ELF64LE>(uint8_t *Buf, Partition &Part);
|
||||
template void elf::writePhdrs<ELF64BE>(uint8_t *Buf, Partition &Part);
|
||||
template void elf::writePhdrs<ELF32LE>(Ctx &, uint8_t *Buf);
|
||||
template void elf::writePhdrs<ELF32BE>(Ctx &, uint8_t *Buf);
|
||||
template void elf::writePhdrs<ELF64LE>(Ctx &, uint8_t *Buf);
|
||||
template void elf::writePhdrs<ELF64BE>(Ctx &, uint8_t *Buf);
|
||||
|
||||
template void elf::createSyntheticSections<ELF32LE>(Ctx &);
|
||||
template void elf::createSyntheticSections<ELF32BE>(Ctx &);
|
||||
|
||||
@@ -1269,22 +1269,6 @@ private:
|
||||
bool finalized = false;
|
||||
};
|
||||
|
||||
template <typename ELFT>
|
||||
class PartitionElfHeaderSection final : public SyntheticSection {
|
||||
public:
|
||||
PartitionElfHeaderSection(Ctx &);
|
||||
size_t getSize() const override;
|
||||
void writeTo(uint8_t *buf) override;
|
||||
};
|
||||
|
||||
template <typename ELFT>
|
||||
class PartitionProgramHeadersSection final : public SyntheticSection {
|
||||
public:
|
||||
PartitionProgramHeadersSection(Ctx &);
|
||||
size_t getSize() const override;
|
||||
void writeTo(uint8_t *buf) override;
|
||||
};
|
||||
|
||||
// See the following link for the Android-specific loader code that operates on
|
||||
// this section:
|
||||
// https://cs.android.com/android/platform/superproject/+/master:bionic/libc/bionic/libc_init_static.cpp;drc=9425b16978f9c5aa8f2c50c873db470819480d1d;l=192
|
||||
@@ -1339,8 +1323,8 @@ void combineEhSections(Ctx &);
|
||||
bool hasMemtag(Ctx &);
|
||||
bool canHaveMemtagGlobals(Ctx &);
|
||||
|
||||
template <typename ELFT> void writeEhdr(Ctx &, uint8_t *buf, Partition &part);
|
||||
template <typename ELFT> void writePhdrs(uint8_t *buf, Partition &part);
|
||||
template <typename ELFT> void writeEhdr(Ctx &, uint8_t *buf);
|
||||
template <typename ELFT> void writePhdrs(Ctx &, uint8_t *buf);
|
||||
|
||||
Defined *addSyntheticLocal(Ctx &ctx, StringRef name, uint8_t type,
|
||||
uint64_t value, uint64_t size,
|
||||
@@ -1373,40 +1357,6 @@ struct PhdrEntry {
|
||||
uint64_t lmaOffset = 0;
|
||||
};
|
||||
|
||||
// Linker generated per-partition sections.
|
||||
struct Partition {
|
||||
StringRef name;
|
||||
unsigned partno = 1;
|
||||
|
||||
std::unique_ptr<SyntheticSection> elfHeader;
|
||||
std::unique_ptr<SyntheticSection> programHeaders;
|
||||
SmallVector<std::unique_ptr<PhdrEntry>, 0> phdrs;
|
||||
|
||||
std::unique_ptr<ARMExidxSyntheticSection> armExidx;
|
||||
std::unique_ptr<BuildIdSection> buildId;
|
||||
std::unique_ptr<SyntheticSection> dynamic;
|
||||
std::unique_ptr<StringTableSection> dynStrTab;
|
||||
std::unique_ptr<SymbolTableBaseSection> dynSymTab;
|
||||
std::unique_ptr<EhFrameHeader> ehFrameHdr;
|
||||
std::unique_ptr<EhFrameSection> ehFrame;
|
||||
std::unique_ptr<GnuHashTableSection> gnuHashTab;
|
||||
std::unique_ptr<HashTableSection> hashTab;
|
||||
std::unique_ptr<MemtagAndroidNote> memtagAndroidNote;
|
||||
std::unique_ptr<MemtagGlobalDescriptors> memtagGlobalDescriptors;
|
||||
std::unique_ptr<PackageMetadataNote> packageMetadataNote;
|
||||
std::unique_ptr<RelocationBaseSection> relaDyn;
|
||||
std::unique_ptr<RelrBaseSection> relrDyn;
|
||||
std::unique_ptr<RelrBaseSection> relrAuthDyn;
|
||||
std::unique_ptr<VersionDefinitionSection> verDef;
|
||||
std::unique_ptr<SyntheticSection> verNeed;
|
||||
std::unique_ptr<VersionTableSection> verSym;
|
||||
};
|
||||
|
||||
inline Partition &SectionBase::getPartition(Ctx &ctx) const {
|
||||
assert(isLive());
|
||||
return *ctx.mainPart;
|
||||
}
|
||||
|
||||
} // namespace lld::elf
|
||||
|
||||
#endif
|
||||
+1
-1
@@ -596,7 +596,7 @@ public:
|
||||
assert(!dest.isPreemptible);
|
||||
if (std::optional<uint32_t> index =
|
||||
ctx.in.ppc64LongBranchTarget->addEntry(&dest, addend)) {
|
||||
ctx.mainPart->relaDyn->addRelativeReloc(
|
||||
ctx.in.relaDyn->addRelativeReloc(
|
||||
ctx.target->relativeRel, *ctx.in.ppc64LongBranchTarget,
|
||||
*index * UINT64_C(8), dest,
|
||||
addend + getPPC64GlobalEntryToLocalEntryOffset(ctx, dest.stOther),
|
||||
|
||||
+104
-167
@@ -67,12 +67,11 @@ private:
|
||||
void checkExecuteOnlyReport();
|
||||
void setReservedSymbolSections();
|
||||
|
||||
SmallVector<std::unique_ptr<PhdrEntry>, 0> createPhdrs(Partition &part);
|
||||
void addPhdrForSection(Partition &part, unsigned shType, unsigned pType,
|
||||
unsigned pFlags);
|
||||
SmallVector<std::unique_ptr<PhdrEntry>, 0> createPhdrs();
|
||||
void addPhdrForSection(unsigned shType, unsigned pType, unsigned pFlags);
|
||||
void assignFileOffsets();
|
||||
void assignFileOffsetsBinary();
|
||||
void setPhdrs(Partition &part);
|
||||
void setPhdrs();
|
||||
void checkSections();
|
||||
void fixSectionAlignments();
|
||||
void openFile();
|
||||
@@ -282,11 +281,10 @@ static void demoteSymbolsAndComputeIsPreemptible(Ctx &ctx) {
|
||||
}
|
||||
}
|
||||
|
||||
static OutputSection *findSection(Ctx &ctx, StringRef name,
|
||||
unsigned partition = 1) {
|
||||
static OutputSection *findSection(Ctx &ctx, StringRef name) {
|
||||
for (SectionCommand *cmd : ctx.script->sectionCommands)
|
||||
if (auto *osd = dyn_cast<OutputDesc>(cmd))
|
||||
if (osd->osec.name == name && osd->osec.partition == partition)
|
||||
if (osd->osec.name == name)
|
||||
return &osd->osec;
|
||||
return nullptr;
|
||||
}
|
||||
@@ -307,19 +305,19 @@ template <class ELFT> void Writer<ELFT>::run() {
|
||||
sec->maybeCompress<ELFT>(ctx);
|
||||
|
||||
if (ctx.script->hasSectionsCommand)
|
||||
ctx.script->allocateHeaders(ctx.mainPart->phdrs);
|
||||
ctx.script->allocateHeaders(ctx.phdrs);
|
||||
|
||||
// Remove empty PT_LOAD to avoid causing the dynamic linker to try to mmap a
|
||||
// 0 sized region. This has to be done late since only after assignAddresses
|
||||
// we know the size of the sections.
|
||||
removeEmptyPTLoad(ctx, ctx.mainPart->phdrs);
|
||||
removeEmptyPTLoad(ctx, ctx.phdrs);
|
||||
|
||||
if (!ctx.arg.oFormatBinary)
|
||||
assignFileOffsets();
|
||||
else
|
||||
assignFileOffsetsBinary();
|
||||
|
||||
setPhdrs(*ctx.mainPart);
|
||||
setPhdrs();
|
||||
|
||||
// Handle --print-map(-M)/--Map and --cref. Dump them before checkSections()
|
||||
// because the files may be useful in case checkSections() or openFile()
|
||||
@@ -643,7 +641,6 @@ static bool isRelroSection(Ctx &ctx, const OutputSection *sec) {
|
||||
enum RankFlags {
|
||||
RF_NOT_ADDR_SET = 1 << 27,
|
||||
RF_NOT_ALLOC = 1 << 26,
|
||||
RF_PARTITION = 1 << 18, // Partition number (8 bits)
|
||||
RF_LARGE_EXEC_WRITE = 1 << 16,
|
||||
RF_LARGE_ALT = 1 << 15,
|
||||
RF_WRITE = 1 << 14,
|
||||
@@ -658,7 +655,7 @@ enum RankFlags {
|
||||
};
|
||||
|
||||
unsigned elf::getSectionRank(Ctx &ctx, OutputSection &osec) {
|
||||
unsigned rank = osec.partition * RF_PARTITION;
|
||||
unsigned rank = 0;
|
||||
|
||||
// We want to put section specified by -T option first, so we
|
||||
// can start assigning VA starting from them later.
|
||||
@@ -697,22 +694,18 @@ unsigned elf::getSectionRank(Ctx &ctx, OutputSection &osec) {
|
||||
else
|
||||
rank |= ctx.arg.zLrodataAfterBss ? 0 : RF_LARGE;
|
||||
|
||||
if (osec.type == SHT_LLVM_PART_EHDR)
|
||||
;
|
||||
else if (osec.type == SHT_LLVM_PART_PHDR)
|
||||
if (osec.name == ".interp")
|
||||
rank |= 1;
|
||||
else if (osec.name == ".interp")
|
||||
rank |= 2;
|
||||
// Put .note sections at the beginning so that they are likely to be
|
||||
// included in a truncate core file. In particular, .note.gnu.build-id, if
|
||||
// available, can identify the object file.
|
||||
else if (osec.type == SHT_NOTE)
|
||||
rank |= 3;
|
||||
rank |= 2;
|
||||
// Make PROGBITS sections (e.g .rodata .eh_frame) closer to .text to
|
||||
// alleviate relocation overflow pressure. Large special sections such as
|
||||
// .dynstr and .dynsym can be away from .text.
|
||||
else if (osec.type != SHT_PROGBITS)
|
||||
rank |= 4;
|
||||
rank |= 3;
|
||||
else
|
||||
rank |= RF_RODATA;
|
||||
} else if (isExec) {
|
||||
@@ -858,7 +851,7 @@ template <class ELFT> void Writer<ELFT>::setReservedSymbolSections() {
|
||||
auto isLarge = [&ctx = ctx](OutputSection *osec) {
|
||||
return ctx.arg.emachine == EM_X86_64 && osec->flags & SHF_X86_64_LARGE;
|
||||
};
|
||||
for (auto &p : ctx.mainPart->phdrs) {
|
||||
for (auto &p : ctx.phdrs) {
|
||||
if (p->p_type != PT_LOAD)
|
||||
continue;
|
||||
last = p.get();
|
||||
@@ -1506,7 +1499,7 @@ template <class ELFT> void Writer<ELFT>::finalizeAddressDependentContent() {
|
||||
// increasing. Anything here must be repeatable, since spilling may change
|
||||
// section order.
|
||||
const auto finalizeOrderDependentContent = [this] {
|
||||
finalizeSynthetic(ctx, ctx.mainPart->armExidx.get());
|
||||
finalizeSynthetic(ctx, ctx.in.armExidx.get());
|
||||
resolveShfLinkOrder();
|
||||
};
|
||||
finalizeOrderDependentContent();
|
||||
@@ -1547,38 +1540,37 @@ template <class ELFT> void Writer<ELFT>::finalizeAddressDependentContent() {
|
||||
if (ctx.in.mipsGot)
|
||||
ctx.in.mipsGot->updateAllocSize(ctx);
|
||||
|
||||
Partition &part = *ctx.mainPart;
|
||||
// The R_AARCH64_AUTH_RELATIVE has a smaller addend field as bits [63:32]
|
||||
// encode the signing schema. We've put relocations in .relr.auth.dyn
|
||||
// during RelocationScanner::processAux, but the target VA for some of
|
||||
// them might be wider than 32 bits. We can only know the final VA at this
|
||||
// point, so move relocations with large values from .relr.auth.dyn to
|
||||
// .rela.dyn. See also AArch64::relocate.
|
||||
if (part.relrAuthDyn) {
|
||||
if (ctx.in.relrAuthDyn) {
|
||||
auto it = llvm::remove_if(
|
||||
part.relrAuthDyn->relocs, [this, &part](const RelativeReloc &elem) {
|
||||
ctx.in.relrAuthDyn->relocs, [this](const RelativeReloc &elem) {
|
||||
Relocation &reloc = elem.inputSec->relocs()[elem.relocIdx];
|
||||
if (isInt<32>(reloc.sym->getVA(ctx, reloc.addend)))
|
||||
return false;
|
||||
reloc.expr = R_NONE;
|
||||
part.relaDyn->addReloc({R_AARCH64_AUTH_RELATIVE, elem.inputSec,
|
||||
reloc.offset, false, *reloc.sym,
|
||||
reloc.addend, R_ABS});
|
||||
ctx.in.relaDyn->addReloc({R_AARCH64_AUTH_RELATIVE, elem.inputSec,
|
||||
reloc.offset, false, *reloc.sym,
|
||||
reloc.addend, R_ABS});
|
||||
return true;
|
||||
});
|
||||
changed |= (it != part.relrAuthDyn->relocs.end());
|
||||
part.relrAuthDyn->relocs.erase(it, part.relrAuthDyn->relocs.end());
|
||||
changed |= (it != ctx.in.relrAuthDyn->relocs.end());
|
||||
ctx.in.relrAuthDyn->relocs.erase(it, ctx.in.relrAuthDyn->relocs.end());
|
||||
}
|
||||
if (part.relaDyn)
|
||||
changed |= part.relaDyn->updateAllocSize(ctx);
|
||||
if (part.relrDyn)
|
||||
changed |= part.relrDyn->updateAllocSize(ctx);
|
||||
if (part.relrAuthDyn)
|
||||
changed |= part.relrAuthDyn->updateAllocSize(ctx);
|
||||
if (part.memtagGlobalDescriptors)
|
||||
changed |= part.memtagGlobalDescriptors->updateAllocSize(ctx);
|
||||
if (part.ehFrameHdr && part.ehFrameHdr->isNeeded())
|
||||
changed |= part.ehFrameHdr->updateAllocSize(ctx);
|
||||
if (ctx.in.relaDyn)
|
||||
changed |= ctx.in.relaDyn->updateAllocSize(ctx);
|
||||
if (ctx.in.relrDyn)
|
||||
changed |= ctx.in.relrDyn->updateAllocSize(ctx);
|
||||
if (ctx.in.relrAuthDyn)
|
||||
changed |= ctx.in.relrAuthDyn->updateAllocSize(ctx);
|
||||
if (ctx.in.memtagGlobalDescriptors)
|
||||
changed |= ctx.in.memtagGlobalDescriptors->updateAllocSize(ctx);
|
||||
if (ctx.in.ehFrameHdr && ctx.in.ehFrameHdr->isNeeded())
|
||||
changed |= ctx.in.ehFrameHdr->updateAllocSize(ctx);
|
||||
|
||||
std::pair<const OutputSection *, const Defined *> changes =
|
||||
ctx.script->assignAddresses();
|
||||
@@ -1603,7 +1595,7 @@ template <class ELFT> void Writer<ELFT>::finalizeAddressDependentContent() {
|
||||
finalizeOrderDependentContent();
|
||||
}
|
||||
// If updateAllocSize reported errors (e.g. "unknown FDE size encoding" for
|
||||
// part.ehFrameHdr), break to avoid duplicate diagnostics from the loop.
|
||||
// ctx.in.ehFrameHdr), break to avoid duplicate diagnostics from the loop.
|
||||
if (errCount(ctx))
|
||||
break;
|
||||
}
|
||||
@@ -1764,7 +1756,7 @@ static void removeUnusedSyntheticSections(Ctx &ctx) {
|
||||
// Conservatively keep .rela.dyn. .relr.auth.dyn can be made empty, but
|
||||
// we would fail to remove it here.
|
||||
if (ctx.arg.emachine == EM_AARCH64 && ctx.arg.relrPackDynRelocs &&
|
||||
sec == ctx.mainPart->relaDyn.get())
|
||||
sec == ctx.in.relaDyn.get())
|
||||
return false;
|
||||
unused.insert(sec);
|
||||
return true;
|
||||
@@ -1804,10 +1796,10 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
|
||||
// It should be okay as no one seems to care about the type.
|
||||
// Even the author of gold doesn't remember why gold behaves that way.
|
||||
// https://sourceware.org/ml/binutils/2002-03/msg00360.html
|
||||
if (ctx.mainPart->dynamic->parent) {
|
||||
if (ctx.in.dynamic->parent) {
|
||||
Symbol *s = ctx.symtab->addSymbol(Defined{
|
||||
ctx, ctx.internalFile, "_DYNAMIC", STB_WEAK, STV_HIDDEN, STT_NOTYPE,
|
||||
/*value=*/0, /*size=*/0, ctx.mainPart->dynamic.get()});
|
||||
/*value=*/0, /*size=*/0, ctx.in.dynamic.get()});
|
||||
s->isUsedInRegularObj = true;
|
||||
}
|
||||
|
||||
@@ -1860,7 +1852,7 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
|
||||
// earlier.
|
||||
{
|
||||
llvm::TimeTraceScope timeScope("Finalize .eh_frame");
|
||||
finalizeSynthetic(ctx, ctx.mainPart->ehFrame.get());
|
||||
finalizeSynthetic(ctx, ctx.in.ehFrame.get());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1958,7 +1950,7 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
|
||||
// computeBinding might localize a symbol that was considered exported
|
||||
// but then synthesized as hidden (e.g. _DYNAMIC).
|
||||
if ((sym->isExported || sym->isPreemptible) && !sym->isLocal()) {
|
||||
ctx.mainPart->dynSymTab->addSymbol(sym);
|
||||
ctx.in.dynSymTab->addSymbol(sym);
|
||||
if (auto *file = dyn_cast<SharedFile>(sym->file))
|
||||
if (file->isNeeded && !sym->isUndefined())
|
||||
addVerneed(ctx, *sym);
|
||||
@@ -2007,33 +1999,25 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
|
||||
// The headers have to be created before finalize as that can influence the
|
||||
// image base and the dynamic section on mips includes the image base.
|
||||
if (!ctx.arg.relocatable && !ctx.arg.oFormatBinary) {
|
||||
Partition &part = *ctx.mainPart;
|
||||
part.phdrs = ctx.script->hasPhdrsCommands() ? ctx.script->createPhdrs()
|
||||
: createPhdrs(part);
|
||||
ctx.phdrs = ctx.script->hasPhdrsCommands() ? ctx.script->createPhdrs()
|
||||
: createPhdrs();
|
||||
if (ctx.arg.emachine == EM_ARM) {
|
||||
// PT_ARM_EXIDX is the ARM EHABI equivalent of PT_GNU_EH_FRAME
|
||||
addPhdrForSection(part, SHT_ARM_EXIDX, PT_ARM_EXIDX, PF_R);
|
||||
addPhdrForSection(SHT_ARM_EXIDX, PT_ARM_EXIDX, PF_R);
|
||||
}
|
||||
if (ctx.arg.emachine == EM_MIPS) {
|
||||
// Add separate segments for MIPS-specific sections.
|
||||
addPhdrForSection(part, SHT_MIPS_REGINFO, PT_MIPS_REGINFO, PF_R);
|
||||
addPhdrForSection(part, SHT_MIPS_OPTIONS, PT_MIPS_OPTIONS, PF_R);
|
||||
addPhdrForSection(part, SHT_MIPS_ABIFLAGS, PT_MIPS_ABIFLAGS, PF_R);
|
||||
addPhdrForSection(SHT_MIPS_REGINFO, PT_MIPS_REGINFO, PF_R);
|
||||
addPhdrForSection(SHT_MIPS_OPTIONS, PT_MIPS_OPTIONS, PF_R);
|
||||
addPhdrForSection(SHT_MIPS_ABIFLAGS, PT_MIPS_ABIFLAGS, PF_R);
|
||||
}
|
||||
if (ctx.arg.emachine == EM_RISCV)
|
||||
addPhdrForSection(part, SHT_RISCV_ATTRIBUTES, PT_RISCV_ATTRIBUTES, PF_R);
|
||||
// Shims only need the basic PT_PHDR/PT_LOAD set; no target-specific
|
||||
// segments since shims hold no input sections.
|
||||
for (Partition &shim : llvm::drop_begin(ctx.partitions))
|
||||
shim.phdrs = createPhdrs(shim);
|
||||
ctx.out.programHeaders->size =
|
||||
sizeof(Elf_Phdr) * ctx.mainPart->phdrs.size();
|
||||
addPhdrForSection(SHT_RISCV_ATTRIBUTES, PT_RISCV_ATTRIBUTES, PF_R);
|
||||
ctx.out.programHeaders->size = sizeof(Elf_Phdr) * ctx.phdrs.size();
|
||||
|
||||
// Find the TLS segment. This happens before the section layout loop so that
|
||||
// Android relocation packing can look up TLS symbol addresses. We only need
|
||||
// to care about the main partition here because all TLS symbols were moved
|
||||
// to the main partition (see MarkLive.cpp).
|
||||
for (auto &p : ctx.mainPart->phdrs)
|
||||
// Android relocation packing can look up TLS symbol addresses.
|
||||
for (auto &p : ctx.phdrs)
|
||||
if (p->p_type == PT_TLS)
|
||||
ctx.tlsPhdr = p.get();
|
||||
}
|
||||
@@ -2066,19 +2050,18 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
|
||||
|
||||
// Dynamic section must be the last one in this list and dynamic
|
||||
// symbol table section (dynSymTab) must be the first one.
|
||||
Partition &part = *ctx.mainPart;
|
||||
finalizeSynthetic(ctx, part.relaDyn.get());
|
||||
finalizeSynthetic(ctx, part.relrDyn.get());
|
||||
finalizeSynthetic(ctx, part.relrAuthDyn.get());
|
||||
finalizeSynthetic(ctx, ctx.in.relaDyn.get());
|
||||
finalizeSynthetic(ctx, ctx.in.relrDyn.get());
|
||||
finalizeSynthetic(ctx, ctx.in.relrAuthDyn.get());
|
||||
|
||||
finalizeSynthetic(ctx, part.dynSymTab.get());
|
||||
finalizeSynthetic(ctx, part.gnuHashTab.get());
|
||||
finalizeSynthetic(ctx, part.hashTab.get());
|
||||
finalizeSynthetic(ctx, part.verDef.get());
|
||||
finalizeSynthetic(ctx, part.ehFrameHdr.get());
|
||||
finalizeSynthetic(ctx, part.verSym.get());
|
||||
finalizeSynthetic(ctx, part.verNeed.get());
|
||||
finalizeSynthetic(ctx, part.dynamic.get());
|
||||
finalizeSynthetic(ctx, ctx.in.dynSymTab.get());
|
||||
finalizeSynthetic(ctx, ctx.in.gnuHashTab.get());
|
||||
finalizeSynthetic(ctx, ctx.in.hashTab.get());
|
||||
finalizeSynthetic(ctx, ctx.in.verDef.get());
|
||||
finalizeSynthetic(ctx, ctx.in.ehFrameHdr.get());
|
||||
finalizeSynthetic(ctx, ctx.in.verSym.get());
|
||||
finalizeSynthetic(ctx, ctx.in.verNeed.get());
|
||||
finalizeSynthetic(ctx, ctx.in.dynamic.get());
|
||||
}
|
||||
|
||||
if (!ctx.script->hasSectionsCommand && !ctx.arg.relocatable)
|
||||
@@ -2263,17 +2246,13 @@ static uint64_t computeFlags(Ctx &ctx, uint64_t flags) {
|
||||
// Decide which program headers to create and which sections to include in each
|
||||
// one.
|
||||
template <class ELFT>
|
||||
SmallVector<std::unique_ptr<PhdrEntry>, 0>
|
||||
Writer<ELFT>::createPhdrs(Partition &part) {
|
||||
SmallVector<std::unique_ptr<PhdrEntry>, 0> Writer<ELFT>::createPhdrs() {
|
||||
SmallVector<std::unique_ptr<PhdrEntry>, 0> ret;
|
||||
auto addHdr = [&, &ctx = ctx](unsigned type, unsigned flags) -> PhdrEntry * {
|
||||
ret.push_back(std::make_unique<PhdrEntry>(ctx, type, flags));
|
||||
return ret.back().get();
|
||||
};
|
||||
|
||||
unsigned partNo = part.partno;
|
||||
bool isMain = partNo == 1;
|
||||
|
||||
// Add the first PT_LOAD segment for regular output sections.
|
||||
uint64_t flags = computeFlags(ctx, PF_R);
|
||||
PhdrEntry *load = nullptr;
|
||||
@@ -2283,23 +2262,16 @@ Writer<ELFT>::createPhdrs(Partition &part) {
|
||||
if (!ctx.arg.nmagic && !ctx.arg.omagic) {
|
||||
// The first phdr entry is PT_PHDR which describes the program header
|
||||
// itself.
|
||||
if (isMain)
|
||||
addHdr(PT_PHDR, PF_R)->add(ctx.out.programHeaders.get());
|
||||
else
|
||||
addHdr(PT_PHDR, PF_R)->add(part.programHeaders->getParent());
|
||||
addHdr(PT_PHDR, PF_R)->add(ctx.out.programHeaders.get());
|
||||
|
||||
// PT_INTERP must be the second entry if exists.
|
||||
if (OutputSection *cmd = findSection(ctx, ".interp", partNo))
|
||||
if (OutputSection *cmd = findSection(ctx, ".interp"))
|
||||
addHdr(PT_INTERP, cmd->getPhdrFlags())->add(cmd);
|
||||
|
||||
// Add the headers. We will remove them if they don't fit.
|
||||
// In the other partitions the headers are ordinary sections, so they don't
|
||||
// need to be added here.
|
||||
if (isMain) {
|
||||
load = addHdr(PT_LOAD, flags);
|
||||
load->add(ctx.out.elfHeader.get());
|
||||
load->add(ctx.out.programHeaders.get());
|
||||
}
|
||||
load = addHdr(PT_LOAD, flags);
|
||||
load->add(ctx.out.elfHeader.get());
|
||||
load->add(ctx.out.programHeaders.get());
|
||||
}
|
||||
|
||||
// PT_GNU_RELRO includes all sections that should be marked as
|
||||
@@ -2310,7 +2282,7 @@ Writer<ELFT>::createPhdrs(Partition &part) {
|
||||
bool inRelroPhdr = false;
|
||||
OutputSection *relroEnd = nullptr;
|
||||
for (OutputSection *sec : ctx.outputSections) {
|
||||
if (sec->partition != partNo || !needsPtLoad(sec))
|
||||
if (!needsPtLoad(sec))
|
||||
continue;
|
||||
if (isRelroSection(ctx, sec)) {
|
||||
inRelroPhdr = true;
|
||||
@@ -2330,18 +2302,6 @@ Writer<ELFT>::createPhdrs(Partition &part) {
|
||||
if (!needsPtLoad(sec))
|
||||
continue;
|
||||
|
||||
// Normally, sections in partitions other than the current partition are
|
||||
// ignored. But partition number 255 is a special case: it contains the
|
||||
// partition end marker (.part.end). It needs to be added to the main
|
||||
// partition so that a segment is created for it in the main partition,
|
||||
// which will cause the dynamic loader to reserve space for the other
|
||||
// partitions.
|
||||
if (sec->partition != partNo) {
|
||||
if (isMain && sec->partition == 255)
|
||||
addHdr(PT_LOAD, computeFlags(ctx, sec->getPhdrFlags()))->add(sec);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Segments are contiguous memory regions that has the same attributes
|
||||
// (e.g. executable or writable). There is one phdr for each segment.
|
||||
// Therefore, we need to create a new phdr when the next section has
|
||||
@@ -2391,38 +2351,38 @@ Writer<ELFT>::createPhdrs(Partition &part) {
|
||||
// Add a TLS segment if any.
|
||||
auto tlsHdr = std::make_unique<PhdrEntry>(ctx, PT_TLS, PF_R);
|
||||
for (OutputSection *sec : ctx.outputSections)
|
||||
if (sec->partition == partNo && sec->flags & SHF_TLS)
|
||||
if (sec->flags & SHF_TLS)
|
||||
tlsHdr->add(sec);
|
||||
if (tlsHdr->firstSec)
|
||||
ret.push_back(std::move(tlsHdr));
|
||||
|
||||
// Add an entry for .dynamic. Shim partitions don't carry a .dynamic.
|
||||
if (part.dynamic)
|
||||
if (OutputSection *sec = part.dynamic->getParent())
|
||||
// Add an entry for .dynamic.
|
||||
if (ctx.in.dynamic)
|
||||
if (OutputSection *sec = ctx.in.dynamic->getParent())
|
||||
addHdr(PT_DYNAMIC, sec->getPhdrFlags())->add(sec);
|
||||
|
||||
if (relRo->firstSec)
|
||||
ret.push_back(std::move(relRo));
|
||||
|
||||
// PT_GNU_EH_FRAME is a special section pointing on .eh_frame_hdr.
|
||||
if (part.ehFrameHdr && part.ehFrameHdr->isNeeded())
|
||||
addHdr(PT_GNU_EH_FRAME, part.ehFrameHdr->getParent()->getPhdrFlags())
|
||||
->add(part.ehFrameHdr->getParent());
|
||||
if (ctx.in.ehFrameHdr && ctx.in.ehFrameHdr->isNeeded())
|
||||
addHdr(PT_GNU_EH_FRAME, ctx.in.ehFrameHdr->getParent()->getPhdrFlags())
|
||||
->add(ctx.in.ehFrameHdr->getParent());
|
||||
|
||||
if (ctx.arg.osabi == ELFOSABI_OPENBSD) {
|
||||
// PT_OPENBSD_MUTABLE makes the dynamic linker fill the segment with
|
||||
// zero data, like bss, but it can be treated differently.
|
||||
if (OutputSection *cmd = findSection(ctx, ".openbsd.mutable", partNo))
|
||||
if (OutputSection *cmd = findSection(ctx, ".openbsd.mutable"))
|
||||
addHdr(PT_OPENBSD_MUTABLE, cmd->getPhdrFlags())->add(cmd);
|
||||
|
||||
// PT_OPENBSD_RANDOMIZE makes the dynamic linker fill the segment
|
||||
// with random data.
|
||||
if (OutputSection *cmd = findSection(ctx, ".openbsd.randomdata", partNo))
|
||||
if (OutputSection *cmd = findSection(ctx, ".openbsd.randomdata"))
|
||||
addHdr(PT_OPENBSD_RANDOMIZE, cmd->getPhdrFlags())->add(cmd);
|
||||
|
||||
// PT_OPENBSD_SYSCALLS makes the kernel and dynamic linker register
|
||||
// system call sites.
|
||||
if (OutputSection *cmd = findSection(ctx, ".openbsd.syscalls", partNo))
|
||||
if (OutputSection *cmd = findSection(ctx, ".openbsd.syscalls"))
|
||||
addHdr(PT_OPENBSD_SYSCALLS, cmd->getPhdrFlags())->add(cmd);
|
||||
}
|
||||
|
||||
@@ -2449,15 +2409,13 @@ Writer<ELFT>::createPhdrs(Partition &part) {
|
||||
if (ctx.arg.zWxneeded)
|
||||
addHdr(PT_OPENBSD_WXNEEDED, PF_X);
|
||||
|
||||
if (OutputSection *cmd = findSection(ctx, ".note.gnu.property", partNo))
|
||||
if (OutputSection *cmd = findSection(ctx, ".note.gnu.property"))
|
||||
addHdr(PT_GNU_PROPERTY, PF_R)->add(cmd);
|
||||
|
||||
// Create one PT_NOTE per a group of contiguous SHT_NOTE sections with the
|
||||
// same alignment.
|
||||
PhdrEntry *note = nullptr;
|
||||
for (OutputSection *sec : ctx.outputSections) {
|
||||
if (sec->partition != partNo)
|
||||
continue;
|
||||
if (sec->type == SHT_NOTE && (sec->flags & SHF_ALLOC)) {
|
||||
if (!note || sec->lmaExpr || note->lastSec->addralign != sec->addralign)
|
||||
note = addHdr(PT_NOTE, PF_R);
|
||||
@@ -2470,18 +2428,17 @@ Writer<ELFT>::createPhdrs(Partition &part) {
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
void Writer<ELFT>::addPhdrForSection(Partition &part, unsigned shType,
|
||||
unsigned pType, unsigned pFlags) {
|
||||
unsigned partNo = part.partno;
|
||||
void Writer<ELFT>::addPhdrForSection(unsigned shType, unsigned pType,
|
||||
unsigned pFlags) {
|
||||
auto i = llvm::find_if(ctx.outputSections, [=](OutputSection *cmd) {
|
||||
return cmd->partition == partNo && cmd->type == shType;
|
||||
return cmd->type == shType;
|
||||
});
|
||||
if (i == ctx.outputSections.end())
|
||||
return;
|
||||
|
||||
auto entry = std::make_unique<PhdrEntry>(ctx, pType, pFlags);
|
||||
entry->add(*i);
|
||||
part.phdrs.push_back(std::move(entry));
|
||||
ctx.phdrs.push_back(std::move(entry));
|
||||
}
|
||||
|
||||
// Place the first section of each PT_LOAD to a different page (of maxPageSize).
|
||||
@@ -2502,16 +2459,9 @@ template <class ELFT> void Writer<ELFT>::fixSectionAlignments() {
|
||||
// between an executable segment and a non-executable segment. We align to
|
||||
// the next maximum page size boundary on transitions between executable
|
||||
// and non-executable segments.
|
||||
//
|
||||
// SHT_LLVM_PART_EHDR marks the start of a partition. The partition
|
||||
// sections will be extracted to a separate file. Align to the next
|
||||
// maximum page size boundary so that we can find the ELF header at the
|
||||
// start. We cannot benefit from overlapping p_offset ranges with the
|
||||
// previous segment anyway.
|
||||
if (ctx.arg.zSeparate == SeparateSegmentKind::Loadable ||
|
||||
(ctx.arg.zSeparate == SeparateSegmentKind::Code && prev &&
|
||||
(prev->p_flags & PF_X) != (p->p_flags & PF_X)) ||
|
||||
cmd->type == SHT_LLVM_PART_EHDR)
|
||||
(prev->p_flags & PF_X) != (p->p_flags & PF_X)))
|
||||
cmd->addrExpr = [&ctx = this->ctx] {
|
||||
return alignToPowerOf2(ctx.script->getDot(), ctx.arg.maxPageSize);
|
||||
};
|
||||
@@ -2542,17 +2492,12 @@ template <class ELFT> void Writer<ELFT>::fixSectionAlignments() {
|
||||
}
|
||||
};
|
||||
|
||||
auto alignPhdrs = [&](Partition &p) {
|
||||
prev = nullptr;
|
||||
for (auto &ph : p.phdrs)
|
||||
if (ph->p_type == PT_LOAD && ph->firstSec) {
|
||||
pageAlign(ph.get());
|
||||
prev = ph.get();
|
||||
}
|
||||
};
|
||||
alignPhdrs(*ctx.mainPart);
|
||||
for (Partition &shim : llvm::drop_begin(ctx.partitions))
|
||||
alignPhdrs(shim);
|
||||
prev = nullptr;
|
||||
for (auto &ph : ctx.phdrs)
|
||||
if (ph->p_type == PT_LOAD && ph->firstSec) {
|
||||
pageAlign(ph.get());
|
||||
prev = ph.get();
|
||||
}
|
||||
}
|
||||
|
||||
// Compute an in-file position for a given section. The file offset must be the
|
||||
@@ -2611,7 +2556,7 @@ template <class ELFT> void Writer<ELFT>::assignFileOffsets() {
|
||||
uint64_t off = ctx.out.elfHeader->size + ctx.out.programHeaders->size;
|
||||
|
||||
PhdrEntry *lastRX = nullptr;
|
||||
for (auto &p : ctx.mainPart->phdrs)
|
||||
for (auto &p : ctx.phdrs)
|
||||
if (p->p_type == PT_LOAD && (p->p_flags & PF_X))
|
||||
lastRX = p.get();
|
||||
|
||||
@@ -2665,25 +2610,22 @@ template <class ELFT> void Writer<ELFT>::assignFileOffsets() {
|
||||
|
||||
// Finalize the program headers. We call this function after we assign
|
||||
// file offsets and VAs to all sections.
|
||||
template <class ELFT> void Writer<ELFT>::setPhdrs(Partition &part) {
|
||||
for (std::unique_ptr<PhdrEntry> &p : part.phdrs) {
|
||||
template <class ELFT> void Writer<ELFT>::setPhdrs() {
|
||||
for (std::unique_ptr<PhdrEntry> &p : ctx.phdrs) {
|
||||
OutputSection *first = p->firstSec;
|
||||
OutputSection *last = p->lastSec;
|
||||
|
||||
// .ARM.exidx sections may not be within a single .ARM.exidx
|
||||
// output section. We always want to describe just the
|
||||
// SyntheticSection.
|
||||
if (part.armExidx && p->p_type == PT_ARM_EXIDX) {
|
||||
p->p_filesz = part.armExidx->getSize();
|
||||
if (ctx.in.armExidx && p->p_type == PT_ARM_EXIDX) {
|
||||
p->p_filesz = ctx.in.armExidx->getSize();
|
||||
p->p_memsz = p->p_filesz;
|
||||
p->p_offset = first->offset + part.armExidx->outSecOff;
|
||||
p->p_vaddr = first->addr + part.armExidx->outSecOff;
|
||||
p->p_align = part.armExidx->addralign;
|
||||
if (part.elfHeader)
|
||||
p->p_offset -= part.elfHeader->getParent()->offset;
|
||||
|
||||
p->p_offset = first->offset + ctx.in.armExidx->outSecOff;
|
||||
p->p_vaddr = first->addr + ctx.in.armExidx->outSecOff;
|
||||
p->p_align = ctx.in.armExidx->addralign;
|
||||
if (!p->hasLMA)
|
||||
p->p_paddr = first->getLMA() + part.armExidx->outSecOff;
|
||||
p->p_paddr = first->getLMA() + ctx.in.armExidx->outSecOff;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2696,11 +2638,6 @@ template <class ELFT> void Writer<ELFT>::setPhdrs(Partition &part) {
|
||||
p->p_offset = first->offset;
|
||||
p->p_vaddr = first->addr;
|
||||
|
||||
// File offsets in partitions other than the main partition are relative
|
||||
// to the offset of the ELF headers. Perform that adjustment now.
|
||||
if (part.elfHeader)
|
||||
p->p_offset -= part.elfHeader->getParent()->offset;
|
||||
|
||||
if (!p->hasLMA)
|
||||
p->p_paddr = first->getLMA();
|
||||
}
|
||||
@@ -2832,8 +2769,8 @@ static uint16_t getELFType(Ctx &ctx) {
|
||||
}
|
||||
|
||||
template <class ELFT> void Writer<ELFT>::writeHeader() {
|
||||
writeEhdr<ELFT>(ctx, ctx.bufferStart, *ctx.mainPart);
|
||||
writePhdrs<ELFT>(ctx.bufferStart + sizeof(Elf_Ehdr), *ctx.mainPart);
|
||||
writeEhdr<ELFT>(ctx, ctx.bufferStart);
|
||||
writePhdrs<ELFT>(ctx, ctx.bufferStart + sizeof(Elf_Ehdr));
|
||||
|
||||
auto *eHdr = reinterpret_cast<Elf_Ehdr *>(ctx.bufferStart);
|
||||
eHdr->e_type = getELFType(ctx);
|
||||
@@ -2936,7 +2873,7 @@ template <class ELFT> void Writer<ELFT>::writeTrapInstr() {
|
||||
}
|
||||
|
||||
// Fill the last page.
|
||||
for (std::unique_ptr<PhdrEntry> &p : ctx.mainPart->phdrs)
|
||||
for (std::unique_ptr<PhdrEntry> &p : ctx.phdrs)
|
||||
if (p->p_type == PT_LOAD && (p->p_flags & PF_X))
|
||||
fillTrap(
|
||||
ctx.target->trapInstr,
|
||||
@@ -2948,7 +2885,7 @@ template <class ELFT> void Writer<ELFT>::writeTrapInstr() {
|
||||
// an executable segment to ensure that other tools don't accidentally
|
||||
// trim the instruction padding (e.g. when stripping the file).
|
||||
PhdrEntry *last = nullptr;
|
||||
for (std::unique_ptr<PhdrEntry> &p : ctx.mainPart->phdrs)
|
||||
for (std::unique_ptr<PhdrEntry> &p : ctx.phdrs)
|
||||
if (p->p_type == PT_LOAD)
|
||||
last = p.get();
|
||||
|
||||
@@ -3010,16 +2947,16 @@ computeHash(llvm::MutableArrayRef<uint8_t> hashBuf,
|
||||
}
|
||||
|
||||
template <class ELFT> void Writer<ELFT>::writeBuildId() {
|
||||
if (!ctx.mainPart->buildId || !ctx.mainPart->buildId->getParent())
|
||||
if (!ctx.in.buildId || !ctx.in.buildId->getParent())
|
||||
return;
|
||||
|
||||
if (ctx.arg.buildId == BuildIdKind::Hexstring) {
|
||||
ctx.mainPart->buildId->writeBuildId(ctx.arg.buildIdVector);
|
||||
ctx.in.buildId->writeBuildId(ctx.arg.buildIdVector);
|
||||
return;
|
||||
}
|
||||
|
||||
// Compute a hash of all sections of the output file.
|
||||
size_t hashSize = ctx.mainPart->buildId->hashSize;
|
||||
size_t hashSize = ctx.in.buildId->hashSize;
|
||||
std::unique_ptr<uint8_t[]> buildId(new uint8_t[hashSize]);
|
||||
MutableArrayRef<uint8_t> output(buildId.get(), hashSize);
|
||||
llvm::ArrayRef<uint8_t> input{ctx.bufferStart, size_t(fileSize)};
|
||||
@@ -3053,7 +2990,7 @@ template <class ELFT> void Writer<ELFT>::writeBuildId() {
|
||||
default:
|
||||
llvm_unreachable("unknown BuildIdKind");
|
||||
}
|
||||
ctx.mainPart->buildId->writeBuildId(output);
|
||||
ctx.in.buildId->writeBuildId(output);
|
||||
}
|
||||
|
||||
template void elf::writeResult<ELF32LE>(Ctx &);
|
||||
|
||||
@@ -43,10 +43,10 @@ ELF Improvements
|
||||
Breaking changes
|
||||
----------------
|
||||
|
||||
* The symbol partition feature is now shim-only. Every input section and every
|
||||
symbol stays in the main partition; each loadable partition from input
|
||||
``SHT_LLVM_SYMPART`` produces an empty ``.so`` shim so the existing
|
||||
``llvm-objcopy --extract-partition`` extraction pipeline keeps working.
|
||||
* The symbol partition feature has been removed. lld no longer recognizes
|
||||
``SHT_LLVM_SYMPART`` sections, which are now treated as ordinary sections. The
|
||||
feature saw no adoption beyond a Chromium experiment that has since been
|
||||
retired.
|
||||
|
||||
COFF Improvements
|
||||
-----------------
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
## Test that we don't create a .ARM.exidx for the main partition.
|
||||
## Previously we were doing so, which is unnecessary and led to a crash.
|
||||
|
||||
# REQUIRES: arm
|
||||
# RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %p/Inputs/shared.s -o %t1.o
|
||||
# RUN: ld.lld -shared %t1.o -o %t.so
|
||||
# RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t.o
|
||||
|
||||
# RUN: ld.lld -shared --gc-sections --dynamic-linker foo %t.o %t.so -o %t
|
||||
# RUN: llvm-readelf --section-headers %t | FileCheck %s
|
||||
|
||||
# CHECK: .ARM.exidx
|
||||
# CHECK-NOT: .ARM.exidx
|
||||
|
||||
.section .llvm_sympart,"",%llvm_sympart
|
||||
.asciz "part1"
|
||||
.4byte p1
|
||||
|
||||
.section .text.p1,"ax",%progbits
|
||||
.globl p1
|
||||
p1:
|
||||
.fnstart
|
||||
bx lr
|
||||
.cantunwind
|
||||
.fnend
|
||||
@@ -1,28 +0,0 @@
|
||||
// REQUIRES: x86, mips
|
||||
/// Link against a DSO to ensure that sections are not discarded by --gc-sections.
|
||||
// RUN: llvm-mc %S/Inputs/shared.s -o %ts.o -filetype=obj --triple=x86_64
|
||||
// RUN: ld.lld -shared -soname=ts %ts.o -o %ts.so
|
||||
// RUN: llvm-mc -triple=x86_64-unknown-linux -filetype=obj -o %t.o %s
|
||||
// RUN: echo "SECTIONS {}" > %t.script
|
||||
// RUN: not ld.lld --export-dynamic %ts.so %t.o %t.script 2>&1 | FileCheck %s
|
||||
// RUN: echo "PHDRS { text PT_LOAD; }" > %t2.script
|
||||
// RUN: not ld.lld --export-dynamic %ts.so %t.o %t2.script 2>&1 | FileCheck %s
|
||||
// RUN: not ld.lld --export-dynamic %ts.so %t.o --section-start .text=0 2>&1 | FileCheck %s
|
||||
// RUN: not ld.lld --export-dynamic %ts.so %t.o -Ttext=0 2>&1 | FileCheck %s
|
||||
// RUN: not ld.lld --export-dynamic %ts.so %t.o -Tdata=0 2>&1 | FileCheck %s
|
||||
// RUN: not ld.lld --export-dynamic %ts.so %t.o -Tbss=0 2>&1 | FileCheck %s
|
||||
|
||||
// RUN: llvm-mc %S/Inputs/shared.s -o %ts.o -filetype=obj --triple=mipsel-unknown-linux
|
||||
// RUN: ld.lld -shared -soname=ts %ts.o -o %ts.so
|
||||
// RUN: llvm-mc -triple=mipsel-unknown-linux -filetype=obj -o %t2.o %s
|
||||
// RUN: not ld.lld --export-dynamic %t2.o %ts.so 2>&1 | FileCheck %s
|
||||
|
||||
// CHECK: error: {{.*}}.o: partitions cannot be used
|
||||
|
||||
.section .llvm_sympart.f1,"",@llvm_sympart
|
||||
.asciz "part1"
|
||||
.quad f1
|
||||
|
||||
.text
|
||||
.globl f1
|
||||
f1:
|
||||
@@ -1,57 +0,0 @@
|
||||
// REQUIRES: x86
|
||||
/// Link against a DSO to ensure that sections are not discarded by --gc-sections.
|
||||
// RUN: llvm-mc -filetype=obj -triple=x86_64 %S/Inputs/shared.s -o %ts.o
|
||||
// RUN: ld.lld -shared -soname=ts %ts.o -o %ts.so
|
||||
// RUN: llvm-mc %s -o %t.o -filetype=obj --triple=x86_64-unknown-linux
|
||||
// RUN: ld.lld %t.o %ts.so -o %t --export-dynamic --gc-sections --icf=all
|
||||
// RUN: llvm-readelf -S -s %t | FileCheck %s
|
||||
|
||||
/// Symbols stay in the main partition; ICF folds the identical bodies of
|
||||
/// (f1, f2) and (g1, g2) into a single section even though they were tagged
|
||||
/// with different SHT_LLVM_SYMPART entries.
|
||||
|
||||
// CHECK: [[MAIN:[0-9]+]]] .text
|
||||
// CHECK: part1 LLVM_PART_EHDR
|
||||
// CHECK: part2 LLVM_PART_EHDR
|
||||
|
||||
// CHECK: Symbol table '.symtab'
|
||||
// CHECK-DAG: [[MAIN]] f1
|
||||
// CHECK-DAG: [[MAIN]] f2
|
||||
// CHECK-DAG: [[MAIN]] g1
|
||||
// CHECK-DAG: [[MAIN]] g2
|
||||
|
||||
.section .llvm_sympart.f1,"",@llvm_sympart
|
||||
.asciz "part1"
|
||||
.quad f1
|
||||
|
||||
.section .llvm_sympart.f2,"",@llvm_sympart
|
||||
.asciz "part2"
|
||||
.quad f2
|
||||
|
||||
.section .llvm_sympart.g1,"",@llvm_sympart
|
||||
.asciz "part1"
|
||||
.quad g1
|
||||
|
||||
.section .llvm_sympart.g2,"",@llvm_sympart
|
||||
.asciz "part2"
|
||||
.quad g2
|
||||
|
||||
.section .text.f1,"ax",@progbits
|
||||
.globl f1
|
||||
f1:
|
||||
.byte 1
|
||||
|
||||
.section .text.f2,"ax",@progbits
|
||||
.globl f2
|
||||
f2:
|
||||
.byte 2
|
||||
|
||||
.section .text.g1,"ax",@progbits
|
||||
.globl g1
|
||||
g1:
|
||||
.byte 3
|
||||
|
||||
.section .text.g2,"ax",@progbits
|
||||
.globl g2
|
||||
g2:
|
||||
.byte 3
|
||||
@@ -1,40 +0,0 @@
|
||||
// REQUIRES: x86
|
||||
/// Link against a DSO to ensure that sections are not discarded by --gc-sections.
|
||||
// RUN: llvm-mc -filetype=obj -triple=x86_64 %S/Inputs/shared.s -o %ts.o
|
||||
// RUN: ld.lld -shared -soname=ts %ts.o -o %ts.so
|
||||
// RUN: llvm-mc %s -o %t.o -filetype=obj --triple=x86_64-unknown-linux
|
||||
// RUN: ld.lld %t.o %ts.so -o %t --export-dynamic --gc-sections
|
||||
// RUN: llvm-readelf -S %t | FileCheck --implicit-check-not=has_startstop --implicit-check-not=no_startstop %s
|
||||
|
||||
/// All input sections now live in the main partition, so a section that
|
||||
/// could otherwise have been split (no_startstop) is also merged into a
|
||||
/// single output section. __start_/__stop_ semantics keep working naturally.
|
||||
|
||||
// CHECK: has_startstop
|
||||
// CHECK: no_startstop
|
||||
|
||||
.section .llvm_sympart.f1,"",@llvm_sympart
|
||||
.asciz "part1"
|
||||
.quad f1
|
||||
|
||||
.section .text._start,"ax",@progbits
|
||||
.globl _start
|
||||
_start:
|
||||
call __start_has_startstop
|
||||
call __stop_has_startstop
|
||||
|
||||
.section .text.f1,"ax",@progbits
|
||||
.globl f1
|
||||
f1:
|
||||
|
||||
.section has_startstop,"ao",@progbits,.text._start,unique,1
|
||||
.quad 1
|
||||
|
||||
.section has_startstop,"ao",@progbits,.text.f1,unique,2
|
||||
.quad 2
|
||||
|
||||
.section no_startstop,"ao",@progbits,.text._start,unique,1
|
||||
.quad 3
|
||||
|
||||
.section no_startstop,"ao",@progbits,.text.f1,unique,2
|
||||
.quad 4
|
||||
@@ -1,44 +0,0 @@
|
||||
// REQUIRES: x86
|
||||
// RUN: llvm-mc %s -o %t.o -filetype=obj --triple=x86_64-unknown-linux
|
||||
// RUN: ld.lld %t.o -o %t --export-dynamic --gc-sections
|
||||
// RUN: llvm-readelf -S -s %t | FileCheck %s
|
||||
|
||||
// Ordinarily, the TLS and IFUNC sections would be split into partitions.
|
||||
// Make sure that that didn't happen by checking that there is only one
|
||||
// of each section.
|
||||
|
||||
// CHECK: .ifunc
|
||||
// CHECK: .tdata
|
||||
|
||||
// CHECK-NOT: .ifunc
|
||||
// CHECK-NOT: .tdata
|
||||
|
||||
.section .llvm_sympart.f1,"",@llvm_sympart
|
||||
.asciz "part1"
|
||||
.quad f1
|
||||
|
||||
.section .text._start,"ax",@progbits
|
||||
.globl _start
|
||||
_start:
|
||||
call tls1
|
||||
call ifunc1
|
||||
|
||||
.section .text.f1,"ax",@progbits
|
||||
.globl f1
|
||||
f1:
|
||||
call tls2
|
||||
call ifunc2
|
||||
|
||||
.section .ifunc,"ax",@progbits,unique,1
|
||||
.type ifunc1 STT_GNU_IFUNC
|
||||
ifunc1:
|
||||
|
||||
.section .ifunc,"ax",@progbits,unique,2
|
||||
.type ifunc2 STT_GNU_IFUNC
|
||||
ifunc2:
|
||||
|
||||
.section .tdata,"awT",@progbits,unique,1
|
||||
tls1:
|
||||
|
||||
.section .tdata,"awT",@progbits,unique,2
|
||||
tls2:
|
||||
@@ -1,58 +0,0 @@
|
||||
// Test that Android and RELR packed relocation sections still emit correctly
|
||||
// for the main partition; the shim has no input sections so its rela/relr
|
||||
// sections are empty by construction.
|
||||
|
||||
// REQUIRES: x86
|
||||
|
||||
// RUN: llvm-mc %s -o %t.o -filetype=obj --triple=x86_64-unknown-linux
|
||||
// RUN: ld.lld %t.o -o %t --shared --gc-sections --pack-dyn-relocs=android+relr
|
||||
|
||||
// RUN: llvm-objcopy --extract-main-partition %t %t0
|
||||
// RUN: llvm-objcopy --extract-partition=part1 %t %t1
|
||||
|
||||
// RUN: llvm-readelf --all %t0 | FileCheck --check-prefix=MAIN %s
|
||||
// RUN: llvm-readelf --all %t1 | FileCheck --check-prefix=SHIM %s
|
||||
|
||||
/// Main retains both packed sections referencing every relocatable global.
|
||||
// MAIN: Section Headers:
|
||||
// MAIN: .rela.dyn ANDROID_RELA
|
||||
// MAIN: .relr.dyn RELR
|
||||
// MAIN: .data PROGBITS
|
||||
// MAIN: Relocation section '.rela.dyn'
|
||||
// MAIN: R_X86_64_64 {{.*}} p0 + 0
|
||||
// MAIN: R_X86_64_64 {{.*}} p1 + 0
|
||||
// MAIN: Relocation section '.relr.dyn'
|
||||
// MAIN-DAG: p0
|
||||
// MAIN-DAG: p1
|
||||
|
||||
/// The shim has no input sections. Enumerate every section and program
|
||||
/// header so any spurious .rela.dyn / .relr.dyn / ANDROID_RELA would fail.
|
||||
// SHIM: Section Headers:
|
||||
// SHIM-NEXT: [Nr] Name Type
|
||||
// SHIM-NEXT: [ 0] NULL
|
||||
// SHIM-NEXT: [ 1] .comment PROGBITS
|
||||
// SHIM-NEXT: [ 2] .shstrtab STRTAB
|
||||
// SHIM: Program Headers:
|
||||
// SHIM-NEXT: Type Offset
|
||||
// SHIM-NEXT: PHDR
|
||||
// SHIM-NEXT: LOAD
|
||||
// SHIM-NEXT: GNU_STACK
|
||||
// SHIM: There are no relocations in this file.
|
||||
|
||||
.section .llvm_sympart,"",@llvm_sympart
|
||||
.asciz "part1"
|
||||
.quad p1
|
||||
|
||||
.section .data.p0,"aw",@progbits
|
||||
.align 8
|
||||
.globl p0
|
||||
p0:
|
||||
.quad __ehdr_start
|
||||
.quad p0
|
||||
|
||||
.section .data.p1,"aw",@progbits
|
||||
.align 8
|
||||
.globl p1
|
||||
p1:
|
||||
.quad __ehdr_start
|
||||
.quad p1
|
||||
+17
-53
@@ -1,64 +1,28 @@
|
||||
// REQUIRES: aarch64, x86
|
||||
// REQUIRES: x86
|
||||
/// The symbol partition feature has been removed. lld no longer treats
|
||||
/// SHT_LLVM_SYMPART specially: the marker sections are retained as ordinary
|
||||
/// sections, no SHT_LLVM_PART_EHDR/PHDR output is produced, and every symbol
|
||||
/// stays in the single output.
|
||||
/// Link against a DSO to ensure that sections are not discarded by --gc-sections.
|
||||
// RUN: llvm-mc %S/Inputs/shared.s -o %ts.o -filetype=obj --triple=x86_64
|
||||
// RUN: ld.lld -shared -soname=ts %ts.o -o %ts.so
|
||||
// RUN: llvm-mc %s -o %t.o -filetype=obj --triple=x86_64-unknown-linux
|
||||
// RUN: ld.lld %t.o %ts.so -o %t --export-dynamic --gc-sections -z max-page-size=65536
|
||||
// RUN: llvm-readelf -S -s %t | FileCheck %s
|
||||
|
||||
/// End-to-end round-trip: llvm-objcopy --extract-partition produces an
|
||||
/// empty-but-valid shim .so; --extract-main-partition produces a main image
|
||||
/// that carries every export and no SHT_LLVM_PART_* sections.
|
||||
// RUN: llvm-objcopy --extract-main-partition %t %t.main
|
||||
// RUN: llvm-objcopy --extract-partition=part1 %t %t.part1
|
||||
// RUN: llvm-readelf -S -s %t.main | FileCheck --check-prefix=EXMAIN --implicit-check-not=LLVM_PART_EHDR --implicit-check-not=LLVM_PART_PHDR %s
|
||||
// RUN: llvm-readelf -h -S -l -d -r -s %t.part1 | FileCheck --check-prefix=SHIM %s
|
||||
|
||||
// RUN: llvm-mc %S/Inputs/shared.s -o %ts.o -filetype=obj --triple=aarch64
|
||||
// RUN: ld.lld -shared -soname=ts %ts.o -o %ts.so
|
||||
// RUN: llvm-mc %s -o %t.o -filetype=obj --triple=aarch64 --crel
|
||||
// RUN: ld.lld %t.o %ts.so -o %t --export-dynamic --gc-sections
|
||||
// RUN: llvm-readelf -S -s %t | FileCheck %s
|
||||
// RUN: llvm-readelf -S -s %t | FileCheck %s \
|
||||
// RUN: --implicit-check-not=LLVM_PART_EHDR --implicit-check-not=LLVM_PART_PHDR
|
||||
|
||||
/// Every input section and every symbol now stays in the main partition.
|
||||
/// Named SHT_LLVM_SYMPART inputs still emit empty-but-valid PART_EHDR shim
|
||||
/// shells so `llvm-objcopy --extract-partition` keeps working.
|
||||
|
||||
// CHECK: [[MAIN:[0-9]+]]] .text
|
||||
// CHECK: part1 LLVM_PART_EHDR
|
||||
// CHECK: part2 LLVM_PART_EHDR
|
||||
/// The SHT_LLVM_SYMPART markers pass through as ordinary sections.
|
||||
// CHECK: .llvm_sympart.f1 LLVM_SYMPART
|
||||
// CHECK: .llvm_sympart.f2 LLVM_SYMPART
|
||||
|
||||
// CHECK: Symbol table '.symtab'
|
||||
// CHECK-DAG: [[MAIN]] f1
|
||||
// CHECK-DAG: [[MAIN]] f2
|
||||
// CHECK-DAG: [[MAIN]] f3
|
||||
// CHECK-DAG: [[MAIN]] f4
|
||||
// CHECK-DAG: [[MAIN]] f5
|
||||
// CHECK-DAG: [[MAIN]] f6
|
||||
// CHECK-DAG: [[MAIN]] _start
|
||||
|
||||
/// Extracted main carries every export and no PART_* sections.
|
||||
// EXMAIN: Symbol table '.dynsym'
|
||||
// EXMAIN-DAG: f1
|
||||
// EXMAIN-DAG: f2
|
||||
// EXMAIN-DAG: _start
|
||||
|
||||
/// Extracted shim is a minimal-but-parseable `.so`: ELF header, a PT_PHDR
|
||||
/// and at least one PT_LOAD. No `.dynsym`, `.dynamic`, or notes — shim
|
||||
/// partitions carry no per-partition content. Enumerate sections and
|
||||
/// program headers with -NEXT so any spurious entry would fail the check.
|
||||
// SHIM: Type: DYN
|
||||
// SHIM: Section Headers:
|
||||
// SHIM-NEXT: [Nr] Name Type
|
||||
// SHIM-NEXT: [ 0] NULL
|
||||
// SHIM-NEXT: [ 1] .comment PROGBITS
|
||||
// SHIM-NEXT: [ 2] .shstrtab STRTAB
|
||||
// SHIM: Program Headers:
|
||||
// SHIM-NEXT: Type Offset
|
||||
// SHIM-NEXT: PHDR
|
||||
// SHIM-NEXT: LOAD
|
||||
// SHIM-NEXT: GNU_STACK
|
||||
// SHIM: There are no relocations in this file.
|
||||
// CHECK-DAG: _start
|
||||
// CHECK-DAG: f1
|
||||
// CHECK-DAG: f2
|
||||
// CHECK-DAG: f3
|
||||
// CHECK-DAG: f4
|
||||
// CHECK-DAG: f5
|
||||
// CHECK-DAG: f6
|
||||
|
||||
.section .llvm_sympart.f1,"",@llvm_sympart
|
||||
.asciz "part1"
|
||||
|
||||
Reference in new issue
Block a user