[lld] 65226d3 - [lld-macho] Fix bug in CUE folding that resulted in wrong unwind table.

Vy Nguyen via llvm-commits llvm-commits at lists.llvm.org
Tue Nov 22 07:40:36 PST 2022


Author: Vy Nguyen
Date: 2022-11-22T10:39:51-05:00
New Revision: 65226d3f1f533914a5fcc2d94bb1ff95b0d55d5d

URL: https://github.com/llvm/llvm-project/commit/65226d3f1f533914a5fcc2d94bb1ff95b0d55d5d
DIFF: https://github.com/llvm/llvm-project/commit/65226d3f1f533914a5fcc2d94bb1ff95b0d55d5d.diff

LOG: [lld-macho] Fix bug in CUE folding that resulted in wrong unwind table.

PR/59070

Differential Revision: https://reviews.llvm.org/D138320

Added: 
    lld/test/MachO/compact-unwind-foldings.s

Modified: 
    lld/MachO/UnwindInfoSection.cpp

Removed: 
    


################################################################################
diff  --git a/lld/MachO/UnwindInfoSection.cpp b/lld/MachO/UnwindInfoSection.cpp
index b83aa896b1527..6a58b5129478b 100644
--- a/lld/MachO/UnwindInfoSection.cpp
+++ b/lld/MachO/UnwindInfoSection.cpp
@@ -179,6 +179,9 @@ class UnwindInfoSectionImpl final : public UnwindInfoSection {
   DenseMap<size_t, uint32_t> lsdaIndex;
   std::vector<SecondLevelPage> 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 cueEndBoundary = 0;
 };
 
 UnwindInfoSection::UnwindInfoSection()
@@ -458,6 +461,10 @@ void UnwindInfoSectionImpl::finalize() {
     return cuEntries[a].functionAddress < cuEntries[b].functionAddress;
   });
 
+  // Record the ending boundary before we fold the entries.
+  cueEndBoundary = 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 @@ void UnwindInfoSectionImpl::writeTo(uint8_t *buf) const {
   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,10 @@ void UnwindInfoSectionImpl::writeTo(uint8_t *buf) const {
     l2PagesOffset += SECOND_LEVEL_PAGE_BYTES;
   }
   // Level-1 sentinel
-  const CompactUnwindEntry &cuEnd = cuEntries[cuIndices.back()];
-  iep->functionOffset =
-      cuEnd.functionAddress - in.header->addr + cuEnd.functionLength;
+  // XXX(vyng): Note that LD64 adds +1 here.
+  // Unsure whether it's a bug or it's their workaround for something else.
+  // See comments from https://reviews.llvm.org/D138320.
+  iep->functionOffset = cueEndBoundary - in.header->addr;
   iep->secondLevelPagesSectionOffset = 0;
   iep->lsdaIndexArraySectionOffset =
       lsdaOffset + entriesWithLsda.size() *

diff  --git a/lld/test/MachO/compact-unwind-foldings.s b/lld/test/MachO/compact-unwind-foldings.s
new file mode 100644
index 0000000000000..18511da772144
--- /dev/null
+++ b/lld/test/MachO/compact-unwind-foldings.s
@@ -0,0 +1,104 @@
+# REQUIRES: x86
+# Tests to verify that
+#    - the folded CUEs covered up to the last entries, even if they were removed/folded.
+#    - only entries that *should* be in eh_frame are actually included. (**)
+# (**) This is where LD64 does 
diff erently.
+
+# RUN: rm -rf %t; split-file %s %t
+# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/fold-tail.s -o %t/fold-tail.o
+# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/cues-range-gap.s -o %t/cues-range-gap.o
+
+# RUN: %lld -o %t/fold-tail.out %t/fold-tail.o
+# RUN: llvm-objdump --macho --syms --unwind-info %t/fold-tail.out | FileCheck %s 
+
+# RUN: %lld -o %t/cues-range-gap.out %t/cues-range-gap.o
+
+# 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,D_ADDR:]]  l     F __TEXT,__text _d
+# CHECK:       [[#%x,MAIN_ADDR:]]  g     F __TEXT,__text _main
+
+## Check that [1] offset starts at c's address + 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 + 3]]
+
+#--- fold-tail.s
+        .text
+        .globl  _main
+        .p2align        4, 0x90
+_main:
+        .cfi_startproc
+        callq   _a
+        retq
+        .cfi_endproc
+
+        .p2align        4, 0x90
+_a:
+        .cfi_startproc
+        callq   _b
+        retq
+        .cfi_endproc
+
+        .p2align        4, 0x90
+_b:
+        .cfi_startproc
+        callq   _c
+        retq
+        .cfi_endproc
+
+        .p2align        4, 0x90
+_c:
+        .cfi_startproc
+        retq
+        .cfi_endproc
+
+// _d should NOT have an entry in .eh_frame
+// So it shouldn't be covered by the unwind table.
+_d:
+        xorl %eax, %eax
+        ret
+
+.subsections_via_symbols
+
+#--- cues-range-gap.s
+        .text
+        .globl  _main
+        .p2align        4, 0x90
+_main:
+        .cfi_startproc
+        callq   _a
+        retq
+        .cfi_endproc
+
+        .p2align        4, 0x90
+_a:
+        .cfi_startproc
+        callq   _b
+        retq
+        .cfi_endproc
+
+// _d is intentionally placed in between the symbols with eh_frame entries.
+// but _d should NOT have an entry in .eh_frame
+// So it shouldn't be covered by the unwind table.
+_d:
+        xorl %eax, %eax
+        ret
+
+        .p2align        4, 0x90
+_b:
+        .cfi_startproc
+        callq   _c
+        retq
+        .cfi_endproc
+
+        .p2align        4, 0x90
+_c:
+        .cfi_startproc
+        retq
+        .cfi_endproc
+
+.subsections_via_symbols


        


More information about the llvm-commits mailing list