diff --git a/lld/MachO/UnwindInfoSection.h b/lld/MachO/UnwindInfoSection.h --- a/lld/MachO/UnwindInfoSection.h +++ b/lld/MachO/UnwindInfoSection.h @@ -66,6 +66,9 @@ // Indices of personality functions within the GOT. std::vector personalities; std::vector lsdaEntries; + // Map of function offset (from the image base) to an index within the LSDA + // array. + llvm::DenseMap functionToLsdaIndex; std::vector cuVector; std::vector cuPtrVector; std::vector secondLevelPages; diff --git a/lld/MachO/UnwindInfoSection.cpp b/lld/MachO/UnwindInfoSection.cpp --- a/lld/MachO/UnwindInfoSection.cpp +++ b/lld/MachO/UnwindInfoSection.cpp @@ -341,6 +341,14 @@ } } + for (const CompactUnwindEntry64 *cu : cuPtrVector) { + uint32_t functionOffset = cu->functionAddress - in.header->addr; + functionToLsdaIndex[functionOffset] = lsdaEntries.size(); + if (cu->lsda != 0) + lsdaEntries.push_back( + {functionOffset, static_cast(cu->lsda - in.header->addr)}); + } + // compute size of __TEXT,__unwind_info section level2PagesOffset = sizeof(unwind_info_section_header) + @@ -386,9 +394,12 @@ uint64_t l2PagesOffset = level2PagesOffset; auto *iep = reinterpret_cast(i32p); for (const SecondLevelPage &page : secondLevelPages) { - iep->functionOffset = cuPtrVector[page.entryIndex]->functionAddress; + iep->functionOffset = + cuPtrVector[page.entryIndex]->functionAddress - in.header->addr; iep->secondLevelPagesSectionOffset = l2PagesOffset; - iep->lsdaIndexArraySectionOffset = lsdaOffset; + iep->lsdaIndexArraySectionOffset = + lsdaOffset + functionToLsdaIndex.lookup(iep->functionOffset) * + sizeof(unwind_info_section_header_lsda_index_entry); iep++; l2PagesOffset += SECOND_LEVEL_PAGE_BYTES; } @@ -396,19 +407,19 @@ const CompactUnwindEntry64 &cuEnd = cuVector.back(); iep->functionOffset = cuEnd.functionAddress + cuEnd.functionLength; iep->secondLevelPagesSectionOffset = 0; - iep->lsdaIndexArraySectionOffset = lsdaOffset; + iep->lsdaIndexArraySectionOffset = + lsdaOffset + + lsdaEntries.size() * sizeof(unwind_info_section_header_lsda_index_entry); iep++; // LSDAs - auto *lep = - reinterpret_cast(iep); - for (const unwind_info_section_header_lsda_index_entry &lsda : lsdaEntries) { - lep->functionOffset = lsda.functionOffset; - lep->lsdaOffset = lsda.lsdaOffset; - } + size_t lsdaBytes = + lsdaEntries.size() * sizeof(unwind_info_section_header_lsda_index_entry); + memcpy(iep, lsdaEntries.data(), lsdaBytes); // Level-2 pages - auto *pp = reinterpret_cast(lep); + auto *pp = reinterpret_cast(reinterpret_cast(iep) + + lsdaBytes); for (const SecondLevelPage &page : secondLevelPages) { if (page.kind == UNWIND_SECOND_LEVEL_COMPRESSED) { uintptr_t functionAddressBase = diff --git a/lld/test/MachO/compact-unwind.s b/lld/test/MachO/compact-unwind.s --- a/lld/test/MachO/compact-unwind.s +++ b/lld/test/MachO/compact-unwind.s @@ -1,17 +1,26 @@ # REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin19.0.0 %s -o %t.o # RUN: %lld -pie -lSystem -lc++ %t.o -o %t -# RUN: llvm-objdump --macho --unwind-info --indirect-symbols --rebase %t | FileCheck %s +# RUN: llvm-objdump --macho --unwind-info --syms --indirect-symbols --rebase %t | FileCheck %s # CHECK: Indirect symbols for (__DATA_CONST,__got) # CHECK-NEXT: address index name # CHECK-DAG: 0x[[#%x,GXX_PERSONALITY:]] [[#]] ___gxx_personality_v0 # CHECK-DAG: 0x[[#%x,MY_PERSONALITY:]] LOCAL +# CHECK: SYMBOL TABLE: +# CHECK-DAG: [[#%x,MAIN:]] g F __TEXT,__text _main +# CHECK-DAG: [[#%x,FOO:]] g F __TEXT,__text _foo +# CHECK-DAG: [[#%x,EXCEPTION0:]] g O __TEXT,__gcc_except_tab _exception0 +# CHECK-DAG: [[#%x,EXCEPTION1:]] g O __TEXT,__gcc_except_tab _exception1 + # CHECK: Contents of __unwind_info section: # CHECK: Personality functions: (count = 2) # CHECK-NEXT: personality[1]: 0x{{0*}}[[#MY_PERSONALITY-0x100000000]] # CHECK-NEXT: personality[2]: 0x{{0*}}[[#GXX_PERSONALITY-0x100000000]] +# CHECK: LSDA descriptors: +# CHECK-NEXT: [0]: function offset=0x{{0*}}[[#FOO-0x100000000]], LSDA offset=0x{{0*}}[[#EXCEPTION0-0x100000000]] +# CHECK-NEXT: [1]: function offset=0x{{0*}}[[#MAIN-0x100000000]], LSDA offset=0x{{0*}}[[#EXCEPTION1-0x100000000]] ## Check that we do not add rebase opcodes to the compact unwind section. # CHECK: Rebase table: @@ -20,12 +29,13 @@ # CHECK-NEXT: __DATA_CONST __got 0x{{[0-9a-f]*}} pointer # CHECK-EMPTY: -.globl _main, _foo, _my_personality, _bar +.globl _main, _foo, _my_personality, _bar, _exception0, _exception1 .text _foo: .cfi_startproc .cfi_personality 155, _my_personality + .cfi_lsda 16, _exception0 .cfi_def_cfa_offset 16 retq .cfi_endproc @@ -34,6 +44,7 @@ .cfi_startproc ## Check that we dedup references to the same statically-linked personality. .cfi_personality 155, _my_personality + .cfi_lsda 16, _exception0 .cfi_def_cfa_offset 16 retq .cfi_endproc @@ -41,9 +52,16 @@ _main: .cfi_startproc .cfi_personality 155, ___gxx_personality_v0 + .cfi_lsda 16, _exception1 .cfi_def_cfa_offset 16 retq .cfi_endproc _my_personality: retq + +.section __TEXT,__gcc_except_tab +_exception0: + .space 1 +_exception1: + .space 1