bool checkSections;
bool compressDebugSections;
bool cref;
+ std::vector<std::pair<llvm::GlobPattern, uint64_t>> deadRelocInNonAlloc;
bool defineCommon;
bool demangle = true;
bool dependentLibraries;
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=");
}
config->zText = getZFlag(args, "text", "notext", true);
config->zWxneeded = hasZOption(args, "wxneeded");
+ for (opt::Arg *arg : args.filtered(OPT_z)) {
+ std::pair<StringRef, StringRef> option =
+ StringRef(arg->getValue()).split('=');
+ if (option.first != "dead-reloc-in-nonalloc")
+ continue;
+ constexpr StringRef errPrefix = "-z dead-reloc-in-nonalloc=: ";
+ std::pair<StringRef, StringRef> kv = option.second.split('=');
+ if (kv.first.empty() || kv.second.empty()) {
+ error(errPrefix + "expected <section_glob>=<value>");
+ continue;
+ }
+ uint64_t v;
+ if (!to_integer(kv.second, v))
+ error(errPrefix + "expected a non-negative integer, but got '" +
+ kv.second + "'");
+ else if (Expected<GlobPattern> pat = GlobPattern::create(kv.first))
+ config->deadRelocInNonAlloc.emplace_back(std::move(*pat), v);
+ else
+ error(errPrefix + toString(pat.takeError()));
+ }
+
// Parse LTO options.
if (auto *arg = args.getLastArg(OPT_plugin_opt_mcpu_eq))
parseClangOption(saver.save("-mcpu=" + StringRef(arg->getValue())),
const bool isDebugLocOrRanges =
isDebug && (name == ".debug_loc" || name == ".debug_ranges");
const bool isDebugLine = isDebug && name == ".debug_line";
+ Optional<uint64_t> tombstone;
+ for (const auto &patAndValue : llvm::reverse(config->deadRelocInNonAlloc))
+ if (patAndValue.first.match(this->name)) {
+ tombstone = patAndValue.second;
+ break;
+ }
for (const RelTy &rel : rels) {
RelType type = rel.getType(config->isMips64EL);
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
auto *ds = dyn_cast<Defined>(&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<bits>(*tombstone)
+ : (isDebugLocOrRanges ? UINT64_MAX - 1 : UINT64_MAX);
+ target->relocateNoSym(bufLoc, type, value);
continue;
}
}
Linker option extensions.
.Bl -tag -width indent -compact
.Pp
+.It Cm dead-reloc-in-nonalloc Ns = Ns Ar section_glob=value
+Resolve a relocation in a matched non-SHF_ALLOC section referencing a discarded symbol to
+.Ar value
+Accepts globs, in the event of a section matching more than one option, the last
+option takes precedence. An order of least specific to most specific match is
+recommended.
+.Pp
.It Cm execstack
Make the main stack executable.
Stack permissions are recorded in the
--- /dev/null
+# REQUIRES: x86
+## Test that -z dead-reloc-in-nonalloc= can customize the tombstone value we
+## use for an absolute relocation referencing a discarded symbol.
+
+# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o
+# RUN: ld.lld --icf=all -z dead-reloc-in-nonalloc=.debug_info=0xaaaaaaaa \
+# RUN: -z dead-reloc-in-nonalloc=.not_debug=0xbbbbbbbb %t.o -o %t
+# RUN: llvm-objdump -s %t | FileCheck %s --check-prefixes=COMMON,AA
+## 0xaaaaaaaa == 2863311530
+# RUN: ld.lld --icf=all -z dead-reloc-in-nonalloc=.debug_info=2863311530 \
+# RUN: -z dead-reloc-in-nonalloc=.not_debug=0xbbbbbbbb %t.o -o - | cmp %t -
+
+# COMMON: Contents of section .debug_addr:
+# COMMON-NEXT: 0000 [[ADDR:[0-9a-f]+]] 00000000 ffffffff ffffffff
+
+# AA: Contents of section .debug_info:
+# AA-NEXT: 0000 [[ADDR]] 00000000 aaaaaaaa 00000000
+# AA: Contents of section .not_debug:
+# AA-NEXT: 0000 bbbbbbbb
+
+## Specifying zero can get a behavior similar to GNU ld.
+# RUN: ld.lld --icf=all -z dead-reloc-in-nonalloc=.debug_info=0 %t.o -o %tzero
+# RUN: llvm-objdump -s %tzero | FileCheck %s --check-prefixes=COMMON,ZERO
+
+# ZERO: Contents of section .debug_info:
+# ZERO-NEXT: 0000 {{[0-9a-f]+}}000 00000000 00000000 00000000
+
+## Glob works.
+# RUN: ld.lld --icf=all -z dead-reloc-in-nonalloc='.debug_i*=0xaaaaaaaa' \
+# RUN: -z dead-reloc-in-nonalloc='[.]not_debug=0xbbbbbbbb' %t.o -o - | cmp %t -
+
+## If a section matches multiple option. The last option wins.
+# RUN: ld.lld --icf=all -z dead-reloc-in-nonalloc='.debug_info=1' \
+# RUN: -z dead-reloc-in-nonalloc='.debug_i*=0' %t.o -o - | cmp %tzero -
+
+## Test all possible invalid cases.
+# RUN: not ld.lld -z dead-reloc-in-nonalloc= 2>&1 | FileCheck %s --check-prefix=USAGE
+# RUN: not ld.lld -z dead-reloc-in-nonalloc=a= 2>&1 | FileCheck %s --check-prefix=USAGE
+# RUN: not ld.lld -z dead-reloc-in-nonalloc==0 2>&1 | FileCheck %s --check-prefix=USAGE
+
+# USAGE: error: -z dead-reloc-in-nonalloc=: expected <section_glob>=<value>
+
+# RUN: not ld.lld -z dead-reloc-in-nonalloc=a=-1 2>&1 | FileCheck %s --check-prefix=NON-INTEGER
+
+# NON-INTEGER: error: -z dead-reloc-in-nonalloc=: expected a non-negative integer, but got '-1'
+
+# RUN: not ld.lld -z dead-reloc-in-nonalloc='['=0 2>&1 | FileCheck %s --check-prefix=INVALID
+
+# INVALID: error: -z dead-reloc-in-nonalloc=: invalid glob pattern: [
+
+.globl _start
+_start:
+ ret
+
+## .text.1 will be folded by ICF.
+.section .text.1,"ax"
+ ret
+
+.section .debug_addr
+ .quad .text+8
+ .quad .text.1+8
+
+.section .debug_info
+ .quad .text+8
+ .quad .text.1+8
+
+## Test a non-.debug_ section.
+.section .not_debug
+ .long .text.1+8
# CHECK-NEXT: 0000 ffffffff ffffffff 08000000 00000000
# CHECK-NEXT: 0010 ffffffff ffffffff 08000000 00000000
+## -z dead-reloc-in-nonalloc= can override the tombstone value.
+# RUN: ld.lld --gc-sections -z dead-reloc-in-nonalloc=.debug_loc=42 %t.o %t1.o %t1.o -o %t42
+# RUN: llvm-objdump -s %t42 | FileCheck %s --check-prefix=OVERRIDE
+
+# OVERRIDE: Contents of section .debug_loc:
+# OVERRIDE-NEXT: 0000 2a000000 00000000 2a000000 00000000
+
.section .text.1,"ax"
.byte 0
.section .text.2,"axe"