[lld/mac] Add explicit "no unwind info" entries for functions without unwind info
Fixes PR50529. With this, lld-linked Chromium base_unittests passes on arm macs. Surprisingly, no measurable impact on link time. Differential Revision: https://reviews.llvm.org/D104681
This commit is contained in:
@@ -256,9 +256,9 @@ relocateCompactUnwind(ConcatOutputSection *compactUnwindSection,
|
||||
// There should only be a handful of unique personality pointers, so we can
|
||||
// encode them as 2-bit indices into a small array.
|
||||
template <class Ptr>
|
||||
void encodePersonalities(
|
||||
const std::vector<CompactUnwindEntry<Ptr> *> &cuPtrVector,
|
||||
std::vector<uint32_t> &personalities) {
|
||||
static void
|
||||
encodePersonalities(const std::vector<CompactUnwindEntry<Ptr> *> &cuPtrVector,
|
||||
std::vector<uint32_t> &personalities) {
|
||||
for (CompactUnwindEntry<Ptr> *cu : cuPtrVector) {
|
||||
if (cu->personality == 0)
|
||||
continue;
|
||||
@@ -280,6 +280,40 @@ void encodePersonalities(
|
||||
") for compact unwind to encode");
|
||||
}
|
||||
|
||||
// __unwind_info stores unwind data for address ranges. If several
|
||||
// adjacent functions have the same unwind encoding, LSDA, and personality
|
||||
// function, they share one unwind entry. For this to work, functions without
|
||||
// unwind info need explicit "no unwind info" unwind entries -- else the
|
||||
// unwinder would think they have the unwind info of the closest function
|
||||
// with unwind info right before in the image.
|
||||
template <class Ptr>
|
||||
static void addEntriesForFunctionsWithoutUnwindInfo(
|
||||
std::vector<CompactUnwindEntry<Ptr>> &cuVector) {
|
||||
DenseSet<Ptr> hasUnwindInfo;
|
||||
for (CompactUnwindEntry<Ptr> &cuEntry : cuVector)
|
||||
if (cuEntry.functionAddress != UINT64_MAX)
|
||||
hasUnwindInfo.insert(cuEntry.functionAddress);
|
||||
|
||||
// Add explicit "has no unwind info" entries for all global and local symbols
|
||||
// without unwind info.
|
||||
auto markNoUnwindInfo = [&cuVector, &hasUnwindInfo](const Defined *d) {
|
||||
if (d->isLive() && isCodeSection(d->isec)) {
|
||||
Ptr ptr = d->getVA();
|
||||
if (!hasUnwindInfo.count(ptr))
|
||||
cuVector.push_back({ptr, 0, 0, 0, 0});
|
||||
}
|
||||
};
|
||||
for (Symbol *sym : symtab->getSymbols())
|
||||
if (auto *d = dyn_cast<Defined>(sym))
|
||||
markNoUnwindInfo(d);
|
||||
for (const InputFile *file : inputFiles)
|
||||
if (auto *objFile = dyn_cast<ObjFile>(file))
|
||||
for (Symbol *sym : objFile->symbols)
|
||||
if (auto *d = dyn_cast_or_null<Defined>(sym))
|
||||
if (!d->isExternal())
|
||||
markNoUnwindInfo(d);
|
||||
}
|
||||
|
||||
// Scan the __LD,__compact_unwind entries and compute the space needs of
|
||||
// __TEXT,__unwind_info and __TEXT,__eh_frame
|
||||
template <class Ptr> void UnwindInfoSectionImpl<Ptr>::finalize() {
|
||||
@@ -301,6 +335,8 @@ template <class Ptr> void UnwindInfoSectionImpl<Ptr>::finalize() {
|
||||
cuVector.resize(cuCount);
|
||||
relocateCompactUnwind(compactUnwindSection, cuVector);
|
||||
|
||||
addEntriesForFunctionsWithoutUnwindInfo(cuVector);
|
||||
|
||||
// Rather than sort & fold the 32-byte entries directly, we create a
|
||||
// vector of pointers to entries and sort & fold that instead.
|
||||
cuPtrVector.reserve(cuCount);
|
||||
|
||||
@@ -33,7 +33,9 @@
|
||||
|
||||
# CHECK: SYMBOL TABLE:
|
||||
# CHECK-DAG: [[#%x,MAIN:]] g F __TEXT,__text _main
|
||||
# CHECK-DAG: [[#%x,QUUX:]] g F __TEXT,__text _quux
|
||||
# CHECK-DAG: [[#%x,FOO:]] l F __TEXT,__text _foo
|
||||
# CHECK-DAG: [[#%x,BAZ:]] l F __TEXT,__text _baz
|
||||
# CHECK-DAG: [[#%x,EXCEPTION0:]] g O __TEXT,__gcc_except_tab _exception0
|
||||
# CHECK-DAG: [[#%x,EXCEPTION1:]] g O __TEXT,__gcc_except_tab _exception1
|
||||
|
||||
@@ -44,6 +46,11 @@
|
||||
# CHECK: LSDA descriptors:
|
||||
# CHECK-DAG: function offset=0x[[#%.8x,FOO-BASE]], LSDA offset=0x[[#%.8x,EXCEPTION0-BASE]]
|
||||
# CHECK-DAG: function offset=0x[[#%.8x,MAIN-BASE]], LSDA offset=0x[[#%.8x,EXCEPTION1-BASE]]
|
||||
# CHECK: Second level indices:
|
||||
# CHECK-DAG: function offset=0x[[#%.8x,MAIN-BASE]], encoding
|
||||
# CHECK-DAG: function offset=0x[[#%.8x,FOO-BASE]], encoding
|
||||
# CHECK-DAG: function offset=0x[[#%.8x,BAZ-BASE]], encoding
|
||||
# CHECK-DAG: function offset=0x[[#%.8x,QUUX-BASE]], encoding{{.*}}=0x00000000
|
||||
|
||||
## Check that we do not add rebase opcodes to the compact unwind section.
|
||||
# CHECK: Rebase table:
|
||||
@@ -83,7 +90,7 @@ _exception0:
|
||||
.space 1
|
||||
|
||||
#--- main.s
|
||||
.globl _main, _my_personality, _exception1
|
||||
.globl _main, _quux, _my_personality, _exception1
|
||||
|
||||
.text
|
||||
.p2align 2
|
||||
@@ -95,6 +102,14 @@ _main:
|
||||
ret
|
||||
.cfi_endproc
|
||||
|
||||
## _quux has no unwind information.
|
||||
## (In real life, it'd be part of a separate TU that was built with
|
||||
## -fno-exceptions, while the previous and next TU might be Objective-C++
|
||||
## which has unwind info for Objective-C).
|
||||
.p2align 2
|
||||
_quux:
|
||||
ret
|
||||
|
||||
.p2align 2
|
||||
_baz:
|
||||
.cfi_startproc
|
||||
|
||||
@@ -37,9 +37,12 @@ def main():
|
||||
if not object_encodings_map:
|
||||
sys.exit("no object encodings found in input")
|
||||
|
||||
# generate-cfi-funcs.py doesn't generate unwind info for _main.
|
||||
object_encodings_map['_main'] = '00000000'
|
||||
|
||||
program_symbols_map = {address:symbol
|
||||
for address, symbol in
|
||||
re.findall(r"^%s(%s) g\s+F __TEXT,__text (x\1)$" % (hex8, hex8),
|
||||
re.findall(r"^%s(%s) g\s+F __TEXT,__text (x\1|_main)$" % (hex8, hex8),
|
||||
objdump_string, re.MULTILINE)}
|
||||
if not program_symbols_map:
|
||||
sys.exit("no program symbols found in input")
|
||||
|
||||
Reference in New Issue
Block a user