diff --git a/lld/MachO/UnwindInfoSection.cpp b/lld/MachO/UnwindInfoSection.cpp --- a/lld/MachO/UnwindInfoSection.cpp +++ b/lld/MachO/UnwindInfoSection.cpp @@ -179,6 +179,9 @@ DenseMap lsdaIndex; std::vector secondLevelPages; uint64_t level2PagesOffset = 0; + // The highest-address function plus its size. The unwinder needs this to + // determine the address range that is covered by unwind info. + uint64_t finalEndingAddress = 0; }; UnwindInfoSection::UnwindInfoSection() @@ -458,6 +461,10 @@ return cuEntries[a].functionAddress < cuEntries[b].functionAddress; }); + // Record the ending boundary before we fold the entries. + finalEndingAddress = cuEntries[cuIndices.back()].functionAddress + + cuEntries[cuIndices.back()].functionLength; + // Fold adjacent entries with matching encoding+personality and without LSDA // We use three iterators on the same cuIndices to fold in-situ: // (1) `foldBegin` is the first of a potential sequence of matching entries @@ -631,6 +638,9 @@ for (const Symbol *personality : personalities) *i32p++ = personality->getGotVA() - in.header->addr; + // FIXME: LD64 checks and warns aboutgaps or overlapse in cuEntries address + // ranges. We should do the same too + // Level-1 index uint32_t lsdaOffset = uip->indexSectionOffset + @@ -648,9 +658,7 @@ l2PagesOffset += SECOND_LEVEL_PAGE_BYTES; } // Level-1 sentinel - const CompactUnwindEntry &cuEnd = cuEntries[cuIndices.back()]; - iep->functionOffset = - cuEnd.functionAddress - in.header->addr + cuEnd.functionLength; + iep->functionOffset = finalEndingAddress - in.header->addr + 1; iep->secondLevelPagesSectionOffset = 0; iep->lsdaIndexArraySectionOffset = lsdaOffset + entriesWithLsda.size() * diff --git a/lld/test/MachO/compact-unwind-folding-bug.s b/lld/test/MachO/compact-unwind-folding-bug.s new file mode 100644 --- /dev/null +++ b/lld/test/MachO/compact-unwind-folding-bug.s @@ -0,0 +1,61 @@ +# REQUIRES: x86 +# Test to verify that the folded CUEs covered up to the last entries, even if they were removed/folded. + +# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %s -o %t.o +# RUN: %lld -o %t.out %t.o +# RUN: llvm-objdump --macho --syms --unwind-info %t.out | FileCheck %s + +# CHECK-LABEL: SYMBOL TABLE: +# CHECK: [[#%x,A_ADDR:]] l F __TEXT,__text _a +# CHECK: [[#%x,B_ADDR:]] l F __TEXT,__text _b +# CHECK: [[#%x,C_ADDR:]] l F __TEXT,__text _c +# CHECK: [[#%x,MAIN_ADDR:]] g F __TEXT,__text _main + +## Check that [1] offset starts at c's address + 1 + 3 (its length). +# CHECK-LABEL: Contents of __unwind_info section: +# CHECK: Top level indices: (count = 2) +# CHECK-NEXT : [0]: function offset=[[#%#.7x,MAIN_ADDR]] +# CHECK-NEXT : [1]: function offset=[[#%#.7x,C_ADDR + 4]] + .section __TEXT,__text,regular,pure_instructions + .globl _main + .p2align 4, 0x90 +_main: + .cfi_startproc + pushq %rbp + callq _a + popq %rbp + retq + .cfi_endproc + + .p2align 4, 0x90 +_a: + .cfi_startproc + pushq %rbp + callq _b + popq %rbp + retq + .cfi_endproc + + .p2align 4, 0x90 +_b: + .cfi_startproc + pushq %rbp + callq _c + popq %rbp + retq + .cfi_endproc + + .p2align 4, 0x90 +_c: + .cfi_startproc + pushq %rbp + popq %rbp + retq + .cfi_endproc + + .section __DATA,__objc_imageinfo,regular,no_dead_strip +L_OBJC_IMAGE_INFO: + .long 0 + .long 64 + +.subsections_via_symbols