diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h --- a/lld/ELF/Config.h +++ b/lld/ELF/Config.h @@ -145,6 +145,7 @@ bool checkSections; bool compressDebugSections; bool cref; + std::vector> deadNonAllocReloc; bool defineCommon; bool demangle = true; bool dependentLibraries; diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -444,6 +444,7 @@ s == "rela" || s == "relro" || s == "retpolineplt" || s == "rodynamic" || s == "shstk" || s == "text" || s == "undefs" || s == "wxneeded" || s.startswith("common-page-size=") || + s.startswith("dead-reloc-in-nonalloc=") || s.startswith("max-page-size=") || s.startswith("stack-size=") || s.startswith("start-stop-visibility="); } @@ -1069,6 +1070,26 @@ config->zText = getZFlag(args, "text", "notext", true); config->zWxneeded = hasZOption(args, "wxneeded"); + for (opt::Arg *arg : args.filtered(OPT_z)) { + std::pair option = + StringRef(arg->getValue()).split('='); + if (option.first != "dead-reloc-in-nonalloc") + continue; + std::pair kv = option.second.split('='); + if (kv.second.empty()) { + error(arg->getSpelling() + ": expected ="); + continue; + } + uint64_t v; + if (!to_integer(kv.second, v)) + error(arg->getSpelling() + ": expected an integer, but got '" + + kv.second + "'"); + else if (Expected pat = GlobPattern::create(kv.first)) + config->deadNonAllocReloc.emplace_back(std::move(*pat), v); + else + error(arg->getSpelling() + ": " + toString(pat.takeError())); + } + // Parse LTO options. if (auto *arg = args.getLastArg(OPT_plugin_opt_mcpu_eq)) parseClangOption(saver.save("-mcpu=" + StringRef(arg->getValue())), diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp --- a/lld/ELF/InputSection.cpp +++ b/lld/ELF/InputSection.cpp @@ -857,6 +857,12 @@ const bool isDebugLocOrRanges = isDebug && (name == ".debug_loc" || name == ".debug_ranges"); const bool isDebugLine = isDebug && name == ".debug_line"; + Optional tombstone; + for (const auto &patAndValue : llvm::reverse(config->deadNonAllocReloc)) + if (patAndValue.first.match(this->name)) { + tombstone = patAndValue.second; + break; + } for (const RelTy &rel : rels) { RelType type = rel.getType(config->isMips64EL); @@ -907,7 +913,8 @@ continue; } - if (isDebug && (type == target->symbolicRel || expr == R_DTPREL)) { + if (tombstone || + (isDebug && (type == target->symbolicRel || expr == R_DTPREL))) { // Resolve relocations in .debug_* referencing (discarded symbols or ICF // folded section symbols) to a tombstone value. Resolving to addend is // unsatisfactory because the result address range may collide with a @@ -935,8 +942,11 @@ auto *ds = dyn_cast(&sym); if (!sym.getOutputSection() || (ds && ds->section->repl != ds->section && !isDebugLine)) { - target->relocateNoSym(bufLoc, type, - isDebugLocOrRanges ? UINT64_MAX - 1 : UINT64_MAX); + // If -z dead-reloc-in-nonalloc= is specified, respect it. + const uint64_t value = + tombstone ? SignExtend64(*tombstone) + : (isDebugLocOrRanges ? UINT64_MAX - 1 : UINT64_MAX); + target->relocateNoSym(bufLoc, type, value); continue; } } diff --git a/lld/ELF/Options.td b/lld/ELF/Options.td --- a/lld/ELF/Options.td +++ b/lld/ELF/Options.td @@ -124,6 +124,11 @@ "Output cross reference table", "Do not output cross reference table">; +defm dead_nonalloc_reloc_value : EEq<"dead-nonalloc-reloc-value", + "Resolve a relocation from a matched non-SHF_ALLOC section to a discarded " + "symbol to the specified value">, + MetaVarName<"=">; + defm define_common: B<"define-common", "Assign space to common symbols", "Do not assign space to common symbols">; diff --git a/lld/test/ELF/debug-dead-reloc-icf.s b/lld/test/ELF/debug-dead-reloc-icf.s --- a/lld/test/ELF/debug-dead-reloc-icf.s +++ b/lld/test/ELF/debug-dead-reloc-icf.s @@ -14,6 +14,16 @@ # CHECK-NEXT: 0000 [[ADDR:[0-9a-f]+]] 00000000 # CHECK-SAME: [[ADDR]] 00000000 +## -z dead-reloc-in-nonalloc can override the decision. +# RUN: ld.lld --icf=all -z dead-reloc-in-nonalloc=.debug_info=3 %t.o -o %t1 +# RUN: llvm-objdump -s %t1 | FileCheck %s --check-prefix=OVERRIDE + +# OVERRIDE: Contents of section .debug_info: +# OVERRIDE-NEXT: 0000 {{[0-9a-f]+}}000 00000000 03000000 00000000 +# OVERRIDE: Contents of section .debug_line: +# OVERRIDE-NEXT: 0000 [[ADDR:[0-9a-f]+]] 00000000 +# OVERRIDE-SAME: [[ADDR]] 00000000 + .globl _start _start: ret