diff --git a/lld/MachO/UnwindInfoSection.cpp b/lld/MachO/UnwindInfoSection.cpp --- a/lld/MachO/UnwindInfoSection.cpp +++ b/lld/MachO/UnwindInfoSection.cpp @@ -358,13 +358,9 @@ if (!d->unwindEntry) return; - // If we have DWARF unwind info, create a CU entry that points to it. + // If we have DWARF unwind info, set the DWARF encoding flag. if (d->unwindEntry->getName() == section_names::ehFrame) { cu.encoding = target->modeDwarfEncoding | d->unwindEntry->outSecOff; - const FDE &fde = cast(d->getFile())->fdes[d->unwindEntry]; - cu.functionLength = fde.funcLength; - cu.personality = fde.personality; - cu.lsda = fde.lsda; return; } diff --git a/lld/test/MachO/compact-unwind-both-local-and-dylib-personality.s b/lld/test/MachO/compact-unwind-both-local-and-dylib-personality.s --- a/lld/test/MachO/compact-unwind-both-local-and-dylib-personality.s +++ b/lld/test/MachO/compact-unwind-both-local-and-dylib-personality.s @@ -1,10 +1,14 @@ -## Tests that lld-macho can handle the case where personality symbols with the same name +>## Tests that lld-macho can handle the case where personality symbols with the same name ## are both from a dylib and locally defined in an object file. # REQUIRES: x86 # RUN: rm -rf %t; split-file %s %t -# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin19.0.0 %t/user_2.s -o %t/user_2.o -# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin19.0.0 %t/user_3.s -o %t/user_3.o +# RUN: llvm-mc -emit-compact-unwind-non-canonical=true -filetype=obj -triple=x86_64-apple-darwin19.0.0 %t/user_2.s -o %t/user_2.o +# RUN: llvm-mc -emit-compact-unwind-non-canonical=true -filetype=obj -triple=x86_64-apple-darwin19.0.0 %t/user_3.s -o %t/user_3.o + +## Test case for linking 3+ personaltiies (all globals) without crashing because all the non-canonical are DWARFs +# RUN: llvm-mc -emit-compact-unwind-non-canonical=false -filetype=obj -triple=x86_64-apple-darwin19.0.0 %t/user_4.s -o %t/user_4.o + # RUN: yaml2obj %t/combined.yaml > %t/combined.o ## Pre-condition: check that ___gxx_personality_v0 really is locally defined in combined.o before we proceed. @@ -21,6 +25,12 @@ ## ___gxx_personality_v0 (global), ___gxx_personality_v0(local), _personality_1, and _personality_2 # RUN: %lld -lSystem -dylib %t/user_3.o %t/combined.o %t/user_2.o -o %t/c.out +## check that we can link with 3+ personalities without crashing because +## non-canonical personalities are dwarf. +## This has ___gxx_personality_v0(global), ___gxx_personality_v0(local), and _personality_{1,2,3,4} +## Only the ___gxx_personality_v0(global) should have compact-unwind. The rest should have DWARFs. +# RUN: %lld -lSystem -lc++ %t/user_4.o %t/combined.o -o %t/d.out + ## Postlink checks. # RUN: llvm-nm %t/a.out | FileCheck %s --check-prefix=POSTCHECK # POSTCHECK: {{.*}} U ___gxx_personality_v0 @@ -30,6 +40,8 @@ # RUN: llvm-objdump --macho --unwind-info --syms --indirect-symbols --bind %t/b.out | FileCheck %s --check-prefixes=BC,CHECK -D#%x,OFF=0x100000000 # RUN: llvm-objdump --macho --unwind-info --syms --indirect-symbols --bind %t/c.out | FileCheck %s --check-prefixes=BC,C,CHECK -D#%x,OFF=0 +# RUN: llvm-objdump --macho --indirect-symbols --unwind-info --bind %t/d.out | FileCheck %s --check-prefixes=D -D#%x,OFF=0x100000000 + # A: Indirect symbols for (__DATA_CONST,__got) # A-NEXT: address index name # A: 0x[[#%x,GXX_PERSONALITY_LO:]] [[#]] ___gxx_personality_v0 @@ -53,11 +65,80 @@ # A-NEXT: segment section address type addend dylib symbol # A-NEXT: __DATA_CONST __got 0x[[#GXX_PERSONALITY_LO-0]] pointer 0 libc++abi ___gxx_personality_v0 + +# D: Indirect symbols for (__DATA_CONST,__got) +# D-NEXT: address index name +# D: 0x[[#%x,GXX_PERSONALITY_HI:]] [[#]] ___gxx_personality_v0 +# D: 0x[[#%x,PERSONALITY_1:]] [[#]] _personality_1 +# D: 0x[[#%x,PERSONALITY_2:]] [[#]] _personality_2 +# D: 0x[[#%x,PERSONALITY_3:]] [[#]] _personality_3 +# D: 0x[[#%x,PERSONALITY_4:]] [[#]] _personality_4 +# D: 0x[[#%x,GXX_PERSONALITY_LO:]] [[#]] ___gxx_personality_v0 + +# D: Contents of __unwind_info section: +# D: Personality functions: (count = 1) + personality[1]: 0x{{0*}}[[#GXX_PERSONALITY_HI-OFF]] + +# D: Bind table: +# D: segment section address type addend dylib symbol +# D: __DATA_CONST __got 0x[[#GXX_PERSONALITY_HI-0]] pointer 0 libc++abi ___gxx_personality_v0 + + ## Error cases. ## Check that dylib symbols are picked (which means without libc++, we'd get an undefined symbol error. # RUN: not %lld -lSystem %t/user_2.o %t/combined.o -o /dev/null 2>&1 | FileCheck %s --check-prefix=ERRORCHECK # ERRORCHECK: {{.*}} undefined symbol: ___gxx_personality_v0 +#--- user_4.s +.globl _main, _personality_1, _personality_2, _personality_3, _personality_4 + +.text + +_baz1: + .cfi_startproc + .cfi_personality 155, _personality_1 + .cfi_def_cfa_offset 16 + retq + .cfi_endproc + +_baz2: + .cfi_startproc + .cfi_personality 155, _personality_2 + .cfi_def_cfa_offset 16 + retq + .cfi_endproc + +_baz3: + .cfi_startproc + .cfi_personality 155, _personality_3 + .cfi_def_cfa_offset 16 + retq + .cfi_endproc + + +_baz4: + .cfi_startproc + .cfi_personality 155, _personality_4 + .cfi_def_cfa_offset 16 + retq + .cfi_endproc + +_main: + .cfi_startproc + .cfi_personality 155, ___gxx_personality_v0 + .cfi_def_cfa_offset 16 + retq + .cfi_endproc + +_personality_1: + retq +_personality_2: + retq +_personality_3: + retq +_personality_4: + retq + #--- user_3.s .globl _baz3 .private_extern ___gxx_personality_v0 diff --git a/llvm/include/llvm/MC/MCAsmBackend.h b/llvm/include/llvm/MC/MCAsmBackend.h --- a/llvm/include/llvm/MC/MCAsmBackend.h +++ b/llvm/include/llvm/MC/MCAsmBackend.h @@ -25,7 +25,8 @@ class MCSymbol; class MCAsmLayout; class MCAssembler; -class MCCFIInstruction; +class MCContext; +class MCDwarfFrameInfo; struct MCFixupKindInfo; class MCInst; class MCObjectStreamer; @@ -210,8 +211,8 @@ virtual void handleAssemblerFlag(MCAssemblerFlag Flag) {} /// Generate the compact unwind encoding for the CFI instructions. - virtual uint32_t - generateCompactUnwindEncoding(ArrayRef) const { + virtual uint32_t generateCompactUnwindEncoding(const MCDwarfFrameInfo *FI, + const MCContext *Ctxt) const { return 0; } @@ -219,6 +220,8 @@ virtual bool isMicroMips(const MCSymbol *Sym) const { return false; } + + bool isDarwinCanonicalPersonality(const MCSymbol *Sym) const; }; } // end namespace llvm diff --git a/llvm/include/llvm/MC/MCContext.h b/llvm/include/llvm/MC/MCContext.h --- a/llvm/include/llvm/MC/MCContext.h +++ b/llvm/include/llvm/MC/MCContext.h @@ -788,6 +788,7 @@ void setGenDwarfForAssembly(bool Value) { GenDwarfForAssembly = Value; } unsigned getGenDwarfFileNumber() { return GenDwarfFileNumber; } EmitDwarfUnwindType emitDwarfUnwindInfo() const; + bool emitCompactUnwindNonCanonical() const; void setGenDwarfFileNumber(unsigned FileNumber) { GenDwarfFileNumber = FileNumber; diff --git a/llvm/include/llvm/MC/MCTargetOptions.h b/llvm/include/llvm/MC/MCTargetOptions.h --- a/llvm/include/llvm/MC/MCTargetOptions.h +++ b/llvm/include/llvm/MC/MCTargetOptions.h @@ -85,6 +85,10 @@ /// integrated assembler. std::vector IASSearchPaths; + // Whether to emit compact-unwind for non-canonical personality + // functions on Darwins. + bool EmitCompactUnwindNonCanonical : 1; + MCTargetOptions(); /// getABIName - If this returns a non-empty string this represents the diff --git a/llvm/include/llvm/MC/MCTargetOptionsCommandFlags.h b/llvm/include/llvm/MC/MCTargetOptionsCommandFlags.h --- a/llvm/include/llvm/MC/MCTargetOptionsCommandFlags.h +++ b/llvm/include/llvm/MC/MCTargetOptionsCommandFlags.h @@ -35,6 +35,8 @@ EmitDwarfUnwindType getEmitDwarfUnwind(); +bool getEmitCompactUnwindNonCanonical(); + bool getShowMCInst(); bool getFatalWarnings(); diff --git a/llvm/lib/MC/MCAsmBackend.cpp b/llvm/lib/MC/MCAsmBackend.cpp --- a/llvm/lib/MC/MCAsmBackend.cpp +++ b/llvm/lib/MC/MCAsmBackend.cpp @@ -115,3 +115,12 @@ return true; return fixupNeedsRelaxation(Fixup, Value, DF, Layout); } + +bool MCAsmBackend::isDarwinCanonicalPersonality(const MCSymbol *Sym) const { + if (Sym && Sym->isMachO() && Sym->isExternal()) { + StringRef name = Sym->getName(); + return name.compare("__gxx_personality_v0,") == 0 || + name.compare("__objc_personality_v0") == 0; + } + return false; +} diff --git a/llvm/lib/MC/MCContext.cpp b/llvm/lib/MC/MCContext.cpp --- a/llvm/lib/MC/MCContext.cpp +++ b/llvm/lib/MC/MCContext.cpp @@ -928,6 +928,13 @@ return TargetOptions->EmitDwarfUnwind; } +bool MCContext::emitCompactUnwindNonCanonical() const { + if (TargetOptions) + return TargetOptions->EmitCompactUnwindNonCanonical; + // FIXME(oontvoo): Flip this to false in up-comping patch. + return true; +} + void MCContext::setGenDwarfRootFile(StringRef InputFileName, StringRef Buffer) { // MCDwarf needs the root file as well as the compilation directory. // If we find a '.file 0' directive that will supersede these values. diff --git a/llvm/lib/MC/MCStreamer.cpp b/llvm/lib/MC/MCStreamer.cpp --- a/llvm/lib/MC/MCStreamer.cpp +++ b/llvm/lib/MC/MCStreamer.cpp @@ -126,7 +126,7 @@ void MCStreamer::generateCompactUnwindEncodings(MCAsmBackend *MAB) { for (auto &FI : DwarfFrameInfos) FI.CompactUnwindEncoding = - (MAB ? MAB->generateCompactUnwindEncoding(FI.Instructions) : 0); + (MAB ? MAB->generateCompactUnwindEncoding(&FI, &Context) : 0); } /// EmitIntValue - Special case of EmitValue that avoids the client having to diff --git a/llvm/lib/MC/MCTargetOptionsCommandFlags.cpp b/llvm/lib/MC/MCTargetOptionsCommandFlags.cpp --- a/llvm/lib/MC/MCTargetOptionsCommandFlags.cpp +++ b/llvm/lib/MC/MCTargetOptionsCommandFlags.cpp @@ -39,6 +39,7 @@ MCOPT(int, DwarfVersion) MCOPT(bool, Dwarf64) MCOPT(EmitDwarfUnwindType, EmitDwarfUnwind) +MCOPT(bool, EmitCompactUnwindNonCanonical) MCOPT(bool, ShowMCInst) MCOPT(bool, FatalWarnings) MCOPT(bool, NoWarn) @@ -87,6 +88,13 @@ "Use target platform default"))); MCBINDOPT(EmitDwarfUnwind); + static cl::opt EmitCompactUnwindNonCanonical( + "emit-compact-unwind-non-canonical", + cl::desc( + "Whether to try to emit Compact Unwind for non canonical entries."), + cl::init(true)); // FIXME(oontvoo) Flip this to false in up-coming patch. + MCBINDOPT(EmitCompactUnwindNonCanonical); + static cl::opt ShowMCInst( "asm-show-inst", cl::desc("Emit internal instruction representation to assembly file")); @@ -135,6 +143,7 @@ Options.MCNoDeprecatedWarn = getNoDeprecatedWarn(); Options.MCNoTypeCheck = getNoTypeCheck(); Options.EmitDwarfUnwind = getEmitDwarfUnwind(); + Options.EmitCompactUnwindNonCanonical = getEmitCompactUnwindNonCanonical(); Options.AsSecureLogFile = getAsSecureLogFile(); return Options; diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64AsmBackend.cpp b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64AsmBackend.cpp --- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64AsmBackend.cpp +++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64AsmBackend.cpp @@ -564,10 +564,14 @@ } /// Generate the compact unwind encoding from the CFI directives. - uint32_t generateCompactUnwindEncoding( - ArrayRef Instrs) const override { + uint32_t generateCompactUnwindEncoding(const MCDwarfFrameInfo *FI, + const MCContext *Ctxt) const override { + ArrayRef Instrs = FI->Instructions; if (Instrs.empty()) return CU::UNWIND_ARM64_MODE_FRAMELESS; + if (!isDarwinCanonicalPersonality(FI->Personality) && + !Ctxt->emitCompactUnwindNonCanonical()) + return 0; bool HasFP = false; unsigned StackSize = 0; diff --git a/llvm/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.cpp b/llvm/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.cpp --- a/llvm/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.cpp +++ b/llvm/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.cpp @@ -1109,14 +1109,19 @@ /// encoded in compact unwind, the method returns UNWIND_ARM_MODE_DWARF which /// tells the runtime to fallback and unwind using dwarf. uint32_t ARMAsmBackendDarwin::generateCompactUnwindEncoding( - ArrayRef Instrs) const { + const MCDwarfFrameInfo *FI, const MCContext *Ctxt) const { DEBUG_WITH_TYPE("compact-unwind", llvm::dbgs() << "generateCU()\n"); // Only armv7k uses CFI based unwinding. if (Subtype != MachO::CPU_SUBTYPE_ARM_V7K) return 0; // No .cfi directives means no frame. + ArrayRef Instrs = FI->Instructions; if (Instrs.empty()) return 0; + if (!isDarwinCanonicalPersonality(FI->Personality) && + !Ctxt->emitCompactUnwindNonCanonical()) + return 0; + // Start off assuming CFA is at SP+0. unsigned CFARegister = ARM::SP; int CFARegisterOffset = 0; diff --git a/llvm/lib/Target/ARM/MCTargetDesc/ARMAsmBackendDarwin.h b/llvm/lib/Target/ARM/MCTargetDesc/ARMAsmBackendDarwin.h --- a/llvm/lib/Target/ARM/MCTargetDesc/ARMAsmBackendDarwin.h +++ b/llvm/lib/Target/ARM/MCTargetDesc/ARMAsmBackendDarwin.h @@ -11,6 +11,7 @@ #include "ARMAsmBackend.h" #include "llvm/BinaryFormat/MachO.h" +#include "llvm/MC/MCContext.h" #include "llvm/MC/MCObjectWriter.h" namespace llvm { @@ -32,8 +33,8 @@ /*Is64Bit=*/false, cantFail(MachO::getCPUType(TT)), Subtype); } - uint32_t generateCompactUnwindEncoding( - ArrayRef Instrs) const override; + uint32_t generateCompactUnwindEncoding(const MCDwarfFrameInfo *FI, + const MCContext *Ctxt) const override; }; } // end namespace llvm diff --git a/llvm/lib/Target/X86/MCTargetDesc/X86AsmBackend.cpp b/llvm/lib/Target/X86/MCTargetDesc/X86AsmBackend.cpp --- a/llvm/lib/Target/X86/MCTargetDesc/X86AsmBackend.cpp +++ b/llvm/lib/Target/X86/MCTargetDesc/X86AsmBackend.cpp @@ -1352,9 +1352,13 @@ /// Implementation of algorithm to generate the compact unwind encoding /// for the CFI instructions. - uint32_t - generateCompactUnwindEncoding(ArrayRef Instrs) const override { + uint32_t generateCompactUnwindEncoding(const MCDwarfFrameInfo *FI, + const MCContext *Ctxt) const override { + ArrayRef Instrs = FI->Instructions; if (Instrs.empty()) return 0; + if (!isDarwinCanonicalPersonality(FI->Personality) && + !Ctxt->emitCompactUnwindNonCanonical()) + return 0; // Reset the saved registers. unsigned SavedRegIdx = 0;