diff --git a/lld/MachO/UnwindInfoSection.cpp b/lld/MachO/UnwindInfoSection.cpp --- a/lld/MachO/UnwindInfoSection.cpp +++ b/lld/MachO/UnwindInfoSection.cpp @@ -316,6 +316,31 @@ markNoUnwindInfo(d); } +static bool canFoldEncoding(compact_unwind_encoding_t encoding) { + // From compact_unwind_encoding.h: + // UNWIND_X86_64_MODE_STACK_IND: + // A "frameless" (RBP not used as frame pointer) function large constant + // stack size. This case is like the previous, except the stack size is too + // large to encode in the compact unwind encoding. Instead it requires that + // the function contains "subq $nnnnnnnn,RSP" in its prolog. The compact + // encoding contains the offset to the nnnnnnnn value in the function in + // UNWIND_X86_64_FRAMELESS_STACK_SIZE. + // Since this means the unwinder has to look at the `subq` in the function + // of the unwind info's unwind address, two functions that have identical + // unwind info can't be folded if it's using this encoding since both + // entries need unique addresses. + static_assert(UNWIND_X86_64_MODE_MASK == UNWIND_X86_MODE_MASK, ""); + static_assert(UNWIND_X86_64_MODE_STACK_IND == UNWIND_X86_MODE_STACK_IND, ""); + if ((target->cpuType == CPU_TYPE_X86_64 || target->cpuType == CPU_TYPE_X86) && + (encoding & UNWIND_X86_64_MODE_MASK) == UNWIND_X86_64_MODE_STACK_IND) { + // FIXME: Consider passing in the two function addresses and getting + // their two stack sizes off the `subq` and only returning false if they're + // actually different. + return false; + } + return true; +} + // Scan the __LD,__compact_unwind entries and compute the space needs of // __TEXT,__unwind_info and __TEXT,__eh_frame template void UnwindInfoSectionImpl::finalize() { @@ -377,7 +402,8 @@ while (++foldEnd < cuPtrVector.end() && (*foldBegin)->encoding == (*foldEnd)->encoding && (*foldBegin)->personality == (*foldEnd)->personality && - (*foldBegin)->lsda == (*foldEnd)->lsda) + (*foldBegin)->lsda == (*foldEnd)->lsda && + canFoldEncoding((*foldEnd)->encoding)) ; *foldWrite++ = *foldBegin; foldBegin = foldEnd; diff --git a/lld/test/MachO/compact-unwind-stack-ind.s b/lld/test/MachO/compact-unwind-stack-ind.s new file mode 100644 --- /dev/null +++ b/lld/test/MachO/compact-unwind-stack-ind.s @@ -0,0 +1,54 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin19.0.0 %s -o %t.o +# RUN: %lld -arch x86_64 -dylib %t.o -o %t.dylib +# RUN: llvm-objdump --macho --syms --unwind-info %t.dylib | FileCheck %s + +## Both _f and _g have the same compact unwind encoding, +## but different stack sizes. So their compact unwindings +## can't be merged. +# CHECK: SYMBOL TABLE: +# CHECK: [[#%x,F:]] g F __TEXT,__text _f +# CHECK: [[#%x,G:]] g F __TEXT,__text _g +# CHECK: Number of common encodings in array: 0x1 +# CHECK: Common encodings: (count = 1) +# CHECK: encoding[0]: 0x03032000 +# CHECK: Second level indices: +# CHECK: Second level index[0]: +# CHECK: [0]: function offset=0x[[#%.8x,F]], encoding[0]=0x03032000 +# CHECK: [1]: function offset=0x[[#%.8x,G]], encoding[0]=0x03032000 + +## Based on compiling +## int f() { +## char alloca[3260] = { 0 }; +## return alloca[0]; +## } +## +## int g() { +## char alloca[2560] = { 0 }; +## return alloca[0]; +## } +## with `-fomit-frame-pointer -fno-stack-protector -S`. +.section __TEXT,__text,regular,pure_instructions +.build_version macos, 10, 15 sdk_version 10, 15, 6 + +.globl _f +.p2align 4, 0x90 +_f: + .cfi_startproc + subq $3272, %rsp + .cfi_def_cfa_offset 3280 + addq $3272, %rsp + retq + .cfi_endproc + +.globl _g +.p2align 4, 0x90 +_g: + .cfi_startproc + subq $2568, %rsp + .cfi_def_cfa_offset 2576 + addq $2568, %rsp + retq + .cfi_endproc + +.subsections_via_symbols