[lld] [llvm] [dyndbg][LLD][ELF] Initial LLD support for dynamic debugging (PR #214188)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Aug 5 03:21:30 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-lld-coff
Author: Andrew Ng (nga888)
<details>
<summary>Changes</summary>
The key changes are:
* Enable the nested "inner" unoptimized dynamic debugging relocatable link within the "outer" optimized link.
* Handle the dependencies between the "inner" unoptimized objects and the "outer" optimized objects.
* Make the "inner" unoptimized relocatable link more like a final executable link (to reduce output size overheads) except when the "outer" is itself a relocatable link.
RFC: https://discourse.llvm.org/t/90113
---
Patch is 43.05 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/214188.diff
16 Files Affected:
- (modified) lld/Common/CommonLinkerContext.cpp (+14)
- (modified) lld/ELF/Config.h (+17-2)
- (modified) lld/ELF/Driver.cpp (+65-14)
- (modified) lld/ELF/InputFiles.cpp (+90-1)
- (modified) lld/ELF/InputFiles.h (+6)
- (modified) lld/ELF/LinkerScript.cpp (+3-1)
- (modified) lld/ELF/MarkLive.cpp (+12-3)
- (modified) lld/ELF/Symbols.h (+5)
- (modified) lld/ELF/SyntheticSections.cpp (+37)
- (modified) lld/ELF/SyntheticSections.h (+14)
- (modified) lld/ELF/Writer.cpp (+41-2)
- (added) lld/test/ELF/Inputs/trace-symbols-dyndbg-opt.s (+4)
- (added) lld/test/ELF/Inputs/trace-symbols-dyndbg-unopt.s (+5)
- (added) lld/test/ELF/dynamic-debug.test (+401)
- (modified) lld/test/ELF/trace-symbols.s (+32-19)
- (modified) llvm/include/llvm/BinaryFormat/ELF.h (+1)
``````````diff
diff --git a/lld/Common/CommonLinkerContext.cpp b/lld/Common/CommonLinkerContext.cpp
index 12f56bc10ec96..cafd78df4a2ba 100644
--- a/lld/Common/CommonLinkerContext.cpp
+++ b/lld/Common/CommonLinkerContext.cpp
@@ -22,7 +22,14 @@ using namespace lld;
// state.
static CommonLinkerContext *lctx;
+static uint32_t numNestedCtx;
+
CommonLinkerContext::CommonLinkerContext() {
+ if (lctx) {
+ ++numNestedCtx;
+ return;
+ }
+
lctx = this;
// Fire off the static initializations in CGF's constructor.
codegen::RegisterCodeGenFlags CGF;
@@ -34,6 +41,13 @@ CommonLinkerContext::~CommonLinkerContext() {
// new in SpecificAlloc::create().
for (auto &it : instances)
it.second->~SpecificAllocBase();
+
+ if (numNestedCtx) {
+ assert(lctx != this);
+ --numNestedCtx;
+ return;
+ }
+
lctx = nullptr;
}
diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h
index 54e0aa58591ad..de61f3674d4ef 100644
--- a/lld/ELF/Config.h
+++ b/lld/ELF/Config.h
@@ -209,6 +209,7 @@ class LinkerDriver {
void linkerMain(ArrayRef<const char *> args);
void addFile(StringRef path, bool withLOption);
void addLibrary(StringRef name);
+ void addFile(std::unique_ptr<ELFFileBase> ef);
private:
Ctx &ctx;
@@ -233,8 +234,8 @@ class LinkerDriver {
public:
// See InputFile::groupId.
- uint32_t nextGroupId;
- bool isInGroup;
+ uint32_t nextGroupId = 0;
+ bool isInGroup = false;
std::unique_ptr<InputFile> armCmseImpLib;
SmallVector<std::pair<StringRef, unsigned>, 0> archiveFiles;
};
@@ -646,6 +647,8 @@ struct InStruct {
std::unique_ptr<SymtabShndxSection> symTabShndx;
std::unique_ptr<SyntheticSection> hexagonAttributes;
std::unique_ptr<SyntheticSection> riscvAttributes;
+ std::unique_ptr<SyntheticSection> dynDbg;
+ std::unique_ptr<SyntheticSection> dynDbgNote;
};
struct Ctx : CommonLinkerContext {
@@ -784,6 +787,18 @@ struct Ctx : CommonLinkerContext {
llvm::raw_fd_ostream openAuxiliaryFile(llvm::StringRef, std::error_code &);
std::optional<AArch64PauthAbiCoreInfo> aarch64PauthAbiCoreInfo;
+
+ // True if performing the embedded unoptimized dynamic debugging relocatable
+ // link.
+ bool inDynDbgLink = false;
+ // True if performing dynamic debugging style relocatable link rather than a
+ // regular relocatable link.
+ bool dynDbgRelocatable = false;
+ // True if the link contains dynamic debugging.
+ bool hasDynDbg = false;
+ // Pointer to the output of the embedded unoptimized dynamic debugging
+ // relocatable link.
+ std::unique_ptr<llvm::FileOutputBuffer> dynDbgOutput;
};
// The first two elements of versionDefinitions represent VER_NDX_LOCAL and
diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp
index 0393410b35d4d..7130da9608e61 100644
--- a/lld/ELF/Driver.cpp
+++ b/lld/ELF/Driver.cpp
@@ -113,6 +113,22 @@ llvm::raw_fd_ostream Ctx::openAuxiliaryFile(llvm::StringRef filename,
return {filename, ec, flags};
}
+static void initContext(Ctx &ctx, LinkerScript &script, StringRef arg0,
+ llvm::raw_ostream &stdoutOS,
+ llvm::raw_ostream &stderrOS, bool exitEarly,
+ bool disableOutput) {
+ ErrorHandler &e = ctx.e;
+ e.initialize(stdoutOS, stderrOS, exitEarly, disableOutput);
+ e.logName = args::getFilenameWithoutExe(arg0);
+ e.errorLimitExceededMsg = "too many errors emitted, stopping now (use "
+ "--error-limit=0 to see all errors)";
+ ctx.script = &script;
+ ctx.symAux.emplace_back();
+ ctx.symtab = std::make_unique<SymbolTable>(ctx);
+
+ ctx.arg.progName = arg0;
+}
+
namespace lld {
namespace elf {
bool link(ArrayRef<const char *> args, llvm::raw_ostream &stdoutOS,
@@ -120,19 +136,9 @@ bool link(ArrayRef<const char *> args, llvm::raw_ostream &stdoutOS,
// This driver-specific context will be freed later by unsafeLldMain().
auto *context = new Ctx;
Ctx &ctx = *context;
-
- context->e.initialize(stdoutOS, stderrOS, exitEarly, disableOutput);
- context->e.logName = args::getFilenameWithoutExe(args[0]);
- context->e.errorLimitExceededMsg =
- "too many errors emitted, stopping now (use "
- "--error-limit=0 to see all errors)";
-
LinkerScript script(ctx);
- ctx.script = &script;
- ctx.symAux.emplace_back();
- ctx.symtab = std::make_unique<SymbolTable>(ctx);
-
- ctx.arg.progName = args[0];
+ initContext(ctx, script, args[0], stdoutOS, stderrOS, exitEarly,
+ disableOutput);
ctx.driver.linkerMain(args);
@@ -301,6 +307,11 @@ void LinkerDriver::addLibrary(StringRef name) {
{name});
}
+// Add an ELF input file directly.
+void LinkerDriver::addFile(std::unique_ptr<ELFFileBase> ef) {
+ files.push_back(std::move(ef));
+}
+
// This function is called on startup. We need this for LTO since
// LTO calls LLVM functions to compile bitcode files to native code.
// Technically this can be delayed until we read bitcode files, but
@@ -2230,8 +2241,6 @@ void LinkerDriver::createFiles(opt::InputArgList &args) {
// Iterate over argv to process input files and positional arguments.
std::optional<MemoryBufferRef> defaultScript;
- nextGroupId = 0;
- isInGroup = false;
bool hasInput = false, hasScript = false;
for (auto *arg : args) {
switch (arg->getOption().getID()) {
@@ -3240,6 +3249,41 @@ static void postParseObjectFile(ELFFileBase *file) {
}
}
+template <class ELFT> static void linkDynamicDebug(Ctx &ctx) {
+ Ctx dc;
+ LinkerScript script(dc);
+ initContext(dc, script, ctx.arg.progName, ctx.e.outs(), ctx.e.errs(),
+ ctx.e.exitEarly, ctx.e.disableOutput);
+ dc.inDynDbgLink = true;
+ dc.dynDbgRelocatable = !ctx.arg.relocatable;
+
+ for (auto *file : ctx.objectFiles) {
+ auto *obj = cast<ObjFile<ELFT>>(file);
+ if (obj->dynDbgSec) {
+ auto content = obj->dynDbgSec->content();
+ MemoryBufferRef mb({(const char *)content.data(), content.size()},
+ obj->mb.getBufferIdentifier());
+ dc.driver.addFile(createObjFile(dc, mb));
+ }
+ }
+
+ if (errCount(ctx))
+ return;
+
+ std::vector<const char *> args{
+ dc.arg.progName.data(), "-r", "-o", "-",
+ dc.saver.save(Twine("-O") + Twine(ctx.arg.optimize)).data()};
+ if (ctx.arg.resolveGroups)
+ args.push_back("--force-group-allocation");
+ dc.driver.linkerMain(args);
+ if (errCount(dc) > 0 || !dc.dynDbgOutput) {
+ Err(ctx) << "Failed to create relocatable dynamic debug object";
+ return;
+ }
+
+ ctx.dynDbgOutput.swap(dc.dynDbgOutput);
+}
+
// Do actual linking. Note that when this function is called,
// all linker scripts have already been parsed.
template <class ELFT> void LinkerDriver::link(opt::InputArgList &args) {
@@ -3533,6 +3577,13 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &args) {
createTaggedSymbols(ctx);
}
+ if (ctx.hasDynDbg) {
+ llvm::TimeTraceScope timeScope("Link dynamic debugging");
+ linkDynamicDebug<ELFT>(ctx);
+ if (errCount(ctx))
+ return;
+ }
+
// Create synthesized sections such as .got and .plt. This is called before
// processSectionCommands() so that they can be placed by SECTIONS commands.
createSyntheticSections<ELFT>(ctx);
diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp
index 05c0f3f1c445b..31c22472519d5 100644
--- a/lld/ELF/InputFiles.cpp
+++ b/lld/ELF/InputFiles.cpp
@@ -588,6 +588,7 @@ template <class ELFT> void ObjFile<ELFT>::parse(bool ignoreComdats) {
if (LLVM_LIKELY(sec.sh_type == SHT_PROGBITS))
continue;
+
if (LLVM_LIKELY(sec.sh_type == SHT_GROUP)) {
StringRef signature = getShtGroupSignature(objSections, sec);
ArrayRef<Elf_Word> entries =
@@ -640,6 +641,26 @@ template <class ELFT> void ObjFile<ELFT>::parse(bool ignoreComdats) {
continue;
}
+ if (sec.sh_type == SHT_LLVM_DYNDBG_ELF) {
+ // Check for presence of dynamic debugging section and create the input
+ // section but mark for discard.
+ StringRef name = check(obj.getSectionName(sec, shstrtab));
+ if (name == dynDbgSecName) {
+ sections[i] = &InputSection::discarded;
+ dynDbgSec = std::make_unique<InputSection>(*this, sec, name);
+ ctx.hasDynDbg = true;
+
+ // If ICF is enabled, warn and disable it because it's incompatible with
+ // dynamic debugging.
+ if (ctx.arg.icf != ICFLevel::None) {
+ Warn(ctx) << "ICF disabled because it is incompatible with dynamic "
+ "debugging";
+ ctx.arg.icf = ICFLevel::None;
+ }
+ }
+ continue;
+ }
+
switch (ctx.arg.emachine) {
case EM_ARM:
if (sec.sh_type == SHT_ARM_ATTRIBUTES) {
@@ -827,7 +848,9 @@ void ObjFile<ELFT>::initializeSections(bool ignoreComdats,
}
switch (type) {
case SHT_GROUP: {
- if (!ctx.arg.relocatable)
+ // Discard groups for the embedded unoptimized dynamic debugging
+ // relocatable link.
+ if (!ctx.arg.relocatable || ctx.dynDbgRelocatable)
sections[i] = &InputSection::discarded;
// Use the verdict parse() recorded for this group instead of repeating
// the signature hashing and comdatGroups lookup.
@@ -1246,6 +1269,72 @@ void ObjFile<ELFT>::initializeSymbols(const object::ELFFile<ELFT> &obj) {
sym->isUsedInRegularObj = true;
sym->referenced = true;
}
+
+ // Process the undefined symbols of the "inner" embedded unoptimized dynamic
+ // debugging object to ensure that the "outer" ELF contains the dependencies
+ // of the "inner" ELF. Also tag which "outer" global symbols are dynamic
+ // debugging references, i.e. used in an "inner" relocation for a SHT_PROGBITS
+ // and SHF_ALLOC section, via the `isDynDbgRef` flag.
+ if (dynDbgSec) {
+ auto content = dynDbgSec->content();
+ MemoryBufferRef dbgMb({(const char *)content.data(), content.size()},
+ mb.getBufferIdentifier());
+ std::unique_ptr<ELFFileBase> efb = createObjFile(ctx, dbgMb);
+ ObjFile<ELFT> *dbgObj = dyn_cast<ObjFile<ELFT>>(efb.get());
+ if (dbgObj) {
+ SmallVector<bool, 0> globalUsed(dbgObj->numSymbols - dbgObj->firstGlobal);
+ ArrayRef<Elf_Shdr> shdrs = dbgObj->template getELFShdrs<ELFT>();
+ for (size_t i = 0, end = shdrs.size(); i != end; ++i) {
+ const Elf_Shdr &sh = shdrs[i];
+ if (!isStaticRelSecType(sh.sh_type))
+ continue;
+
+ const Elf_Shdr &target = shdrs[sh.sh_info];
+ if (target.sh_type != SHT_PROGBITS ||
+ (target.sh_flags & SHF_ALLOC) == 0)
+ continue;
+
+ auto setSymUsed = [&,
+ firstGlobal = dbgObj->firstGlobal](uint32_t symIdx) {
+ if (symIdx >= firstGlobal)
+ globalUsed[symIdx - firstGlobal] = true;
+ };
+
+ auto isec = std::make_unique<InputSection>(*dbgObj, sh, StringRef());
+ isec->relSecIdx = i;
+ auto relocs = isec->template relsOrRelas<ELFT>(/*supportsCrel=*/false);
+ if (relocs.areRelocsRel()) {
+ for (auto const &r : relocs.rels)
+ setSymUsed(r.getSymbol(ctx.arg.isMips64EL));
+ } else {
+ for (auto const &r : relocs.relas)
+ setSymUsed(r.getSymbol(ctx.arg.isMips64EL));
+ }
+ }
+
+ ArrayRef<Elf_Sym> dbgSyms = dbgObj->template getGlobalELFSyms<ELFT>();
+ assert(dbgSyms.size() == globalUsed.size());
+ for (size_t i = 0, end = dbgSyms.size(); i != end; ++i) {
+ const Elf_Sym &s = dbgSyms[i];
+ if (s.st_shndx != SHN_UNDEF)
+ continue;
+
+ StringRef name = CHECK2(s.getName(dbgObj->stringTable), this);
+ Symbol *sym = symtab->addSymbol(
+ Undefined{this, name, s.getBinding(), s.st_other, s.getType()});
+ sym->isUsedInRegularObj = true;
+ sym->referenced = true;
+ if (globalUsed[i]) {
+ sym->isDynDbgRef = true;
+ if (sym->traced)
+ Msg(ctx) << this << ": dynamic debugging reference to " << name;
+ }
+ }
+ } else {
+ Err(ctx) << this << ": " << dynDbgSecName
+ << " contains an incompatible ELF type";
+ }
+ }
}
template <class ELFT>
diff --git a/lld/ELF/InputFiles.h b/lld/ELF/InputFiles.h
index 0ded9b2fa38e2..22c29f9ea7909 100644
--- a/lld/ELF/InputFiles.h
+++ b/lld/ELF/InputFiles.h
@@ -268,6 +268,9 @@ template <class ELFT> class ObjFile : public ELFFileBase {
// Pointer to this input file's .llvm_addrsig section, if it has one.
const Elf_Shdr *addrsigSec = nullptr;
+ // Embedded unoptimized dynamic debug input section.
+ std::unique_ptr<InputSection> dynDbgSec;
+
// SHT_LLVM_CALL_GRAPH_PROFILE section index.
uint32_t cgProfileSectionIndex = 0;
@@ -389,6 +392,9 @@ std::unique_ptr<ELFFileBase> createObjFile(Ctx &, MemoryBufferRef mb,
std::string replaceThinLTOSuffix(Ctx &, StringRef path);
+// Name of embedded unoptimized dynamic debug input/output section.
+constexpr StringRef dynDbgSecName = ".debug_llvm_dyndbg";
+
} // namespace elf
} // namespace lld
diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp
index 64fb717e17d9d..d7a057c1915b0 100644
--- a/lld/ELF/LinkerScript.cpp
+++ b/lld/ELF/LinkerScript.cpp
@@ -67,7 +67,9 @@ StringRef LinkerScript::getOutputSectionName(const InputSectionBase *s) const {
return ss.save(".rela" + out->name);
return ss.save(".rel" + out->name);
}
- if (ctx.arg.relocatable)
+ // Use default LLD behavior for the embedded unoptimized dynamic debugging
+ // relocatable link.
+ if (ctx.arg.relocatable && !ctx.dynDbgRelocatable)
return s->name;
}
diff --git a/lld/ELF/MarkLive.cpp b/lld/ELF/MarkLive.cpp
index 2820818133d5c..8e5071cdc0073 100644
--- a/lld/ELF/MarkLive.cpp
+++ b/lld/ELF/MarkLive.cpp
@@ -363,11 +363,20 @@ template <class ELFT, bool TrackWhyLive>
void MarkLive<ELFT, TrackWhyLive>::run() {
// Add GC root symbols.
- // Preserve externally-visible symbols if the symbols defined by this
- // file can interpose other ELF file's symbols at runtime.
- for (Symbol *sym : ctx.symtab->getSymbols())
+ for (Symbol *sym : ctx.symtab->getSymbols()) {
+ // For now, preserve all symbols required by the embedded unoptimized part
+ // of dynamic debugging. TODO: better support for `--gc-sections`.
+ if (sym->isDynDbgRef) {
+ markSymbol(sym, "dynamic debugging");
+ sym->setFlags(USED);
+ continue;
+ }
+
+ // Preserve externally-visible symbols if the symbols defined by this
+ // file can interpose other ELF file's symbols at runtime.
if (sym->isExported)
markSymbol(sym, "externally visible symbol");
+ }
markSymbol(ctx.symtab->find(ctx.arg.entry), "entry point");
markSymbol(ctx.symtab->find(ctx.arg.init), "initializer function");
diff --git a/lld/ELF/Symbols.h b/lld/ELF/Symbols.h
index 0893776882dc6..9a0909037f51e 100644
--- a/lld/ELF/Symbols.h
+++ b/lld/ELF/Symbols.h
@@ -341,6 +341,11 @@ class Symbol {
LLVM_PREFERRED_TYPE(bool)
uint8_t referencedAfterWrap : 1;
+ // True if this symbol is referenced by the embedded unoptimized part of
+ // dynamic debugging.
+ LLVM_PREFERRED_TYPE(bool)
+ uint8_t isDynDbgRef : 1;
+
void setFlags(uint16_t bits) {
flags.fetch_or(bits, std::memory_order_relaxed);
}
diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp
index 6bac881446fd0..84099e6e7503c 100644
--- a/lld/ELF/SyntheticSections.cpp
+++ b/lld/ELF/SyntheticSections.cpp
@@ -4411,6 +4411,36 @@ size_t MemtagGlobalDescriptors::getSize() const {
return createMemtagGlobalDescriptors(ctx, symbols);
}
+DynamicDebugSection::DynamicDebugSection(Ctx &ctx)
+ : SyntheticSection(ctx, dynDbgSecName, SHT_LLVM_DYNDBG_ELF, 0, 8) {
+ assert(ctx.dynDbgOutput);
+}
+
+size_t DynamicDebugSection::getSize() const {
+ return ctx.dynDbgOutput->getBufferSize();
+}
+
+void DynamicDebugSection::writeTo(uint8_t *buf) {
+ memcpy(buf, ctx.dynDbgOutput->getBufferStart(),
+ ctx.dynDbgOutput->getBufferSize());
+}
+
+DynamicDebugNote::DynamicDebugNote(Ctx &ctx)
+ : SyntheticSection(ctx, ".note.llvm.dyndbg", SHT_NOTE, 0, 4) {}
+
+size_t DynamicDebugNote::getSize() const {
+ return /*hdrsz=*/12 + /*namesz=*/8 + /*descsz=*/sizeof(uint32_t);
+}
+
+void DynamicDebugNote::writeTo(uint8_t *buf) {
+ write32(ctx, buf, 5); // Name size
+ write32(ctx, buf + 4, sizeof(uint32_t)); // Content size
+ write32(ctx, buf + 8, NT_LLVM_DYNAMIC_DEBUGGING); // Type
+ memcpy(buf + 12, "LLVM", 5); // Name string
+ uint32_t version = 0;
+ write32(ctx, buf + 20, version);
+}
+
static OutputSection *findSection(Ctx &ctx, StringRef name) {
for (SectionCommand *cmd : ctx.script->sectionCommands)
if (auto *osd = dyn_cast<OutputDesc>(cmd))
@@ -4635,6 +4665,13 @@ template <class ELFT> void elf::createSyntheticSections(Ctx &ctx) {
add(*ctx.in.shStrTab);
if (ctx.in.strTab)
add(*ctx.in.strTab);
+
+ if (ctx.dynDbgOutput) {
+ ctx.in.dynDbg = std::make_unique<DynamicDebugSection>(ctx);
+ add(*ctx.in.dynDbg);
+ ctx.in.dynDbgNote = std::make_unique<DynamicDebugNote>(ctx);
+ add(*ctx.in.dynDbgNote);
+ }
}
template void elf::splitSections<ELF32LE>(Ctx &);
diff --git a/lld/ELF/SyntheticSections.h b/lld/ELF/SyntheticSections.h
index 19d4461348f3f..fefd21b336e24 100644
--- a/lld/ELF/SyntheticSections.h
+++ b/lld/ELF/SyntheticSections.h
@@ -1317,6 +1317,20 @@ class MemtagGlobalDescriptors final : public SyntheticSection {
SmallVector<const Symbol *, 0> symbols;
};
+class DynamicDebugSection final : public SyntheticSection {
+public:
+ DynamicDebugSection(Ctx &);
+ size_t getSize() const override;
+ void writeTo(uint8_t *buf) override;
+};
+
+class DynamicDebugNote final : public SyntheticSection {
+public:
+ DynamicDebugNote(Ctx &);
+ size_t getSize() const override;
+ void writeTo(uint8_t *buf) override;
+};
+
template <class ELFT> void createSyntheticSections(Ctx &);
InputSection *createInterpSection(Ctx &);
MergeInputSection *createCommentSection(Ctx &);
diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp
index 8cf88cd99cf8a..bd0d394386aac 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -365,10 +365,14 @@ template <class ELFT> void Writer<ELFT>::run() {
if (errCount(ctx))
return;
- // With -o -, write to lld::outs() (the stdoutOS argument of
+ // Capture output for the embedded unoptimized dynamic debugging relocatable
+ // link.
+ // Otherwise, with -o -, write to lld::outs() (the stdoutOS argument of
// link()) instead of committing the buffer, which would write to the
// process's stdout.
- if (ctx.arg.outputFile == "-") {
+ if (ctx.inDynDbgLink)
+ ctx.dynDbgOutput.swap(buffer);
+ else if (ctx.arg.outputFile == "-") {
ctx.e.outs() << StringRef(
reinterpret_cast<const char *>(buffer->getBufferStart()),
buffer->getBufferSize());
@@ -1914,6 +1918,41 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
// called after processSymbolAssignments() because it needs to know whether
// a linker-script-defined symbol is absolute.
scanRelocations<ELFT>(ctx);
+
+ // Process symbols referenced by the embedded unoptimized part of dynamic
+ // debugging.
+ if (ctx.hasDynDbg) {
+ bool ignoreUnresolved =
+ (ctx.arg.unresolvedSymbols == UnresolvedPolicy::Ignore);
+ bool warnOnly = (ctx.arg.unresolvedSymbols == UnresolvedPolicy::Warn);
+ for (Symbol *sym : ctx.symtab->getSymbols()) {
+ if (!sym->isDynDbgRef)
+ continue;
+
+ if (sym->isUndefined()) {
+ if (ignoreUnresolved || sym->isWeak())
+ continue;
+
+ static InputSection dummy(ctx.internalFile, dynDbgSecName, 0, 0, 0, 0,
+ ArrayRef<uint8_t>());
+ ObjFile<ELFT> *dbgObj = dyn_cast<ObjFile<ELFT>>(sym->file);
+ InputSectionBase *isec =
+ dbgObj && dbgObj->dynDbgSec ? dbgObj->dynDbgSec.get() : &dummy;
+ ctx.undefErrs.push_back(
+ {cast<Undefined>(sym), {{isec, 0}}, warnOnly});
+ continue;
+ }
+
+ // Ensure there are PLT/GOT entries for references to shared symbols.
+ if (sym->isShared() && sym->isUsedInRegularObj && sym->dsoDefined) {
+ if (sym->isFunc())
+ sym->setFlags(NEEDS_PLT);
+ else if (sym->isObject())
+ sym->s...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/214188
More information about the llvm-commits
mailing list