diff --git a/llvm/lib/CodeGen/AsmPrinter/EHStreamer.cpp b/llvm/lib/CodeGen/AsmPrinter/EHStreamer.cpp --- a/llvm/lib/CodeGen/AsmPrinter/EHStreamer.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/EHStreamer.cpp @@ -15,20 +15,24 @@ #include "llvm/ADT/Twine.h" #include "llvm/ADT/iterator_range.h" #include "llvm/BinaryFormat/Dwarf.h" +#include "llvm/BinaryFormat/ELF.h" #include "llvm/CodeGen/AsmPrinter.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineInstr.h" #include "llvm/CodeGen/MachineOperand.h" +#include "llvm/IR/Comdat.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/Function.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCContext.h" +#include "llvm/MC/MCSectionELF.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSymbol.h" #include "llvm/MC/MCTargetOptions.h" #include "llvm/Support/Casting.h" #include "llvm/Support/LEB128.h" #include "llvm/Target/TargetLoweringObjectFile.h" +#include "llvm/Target/TargetMachine.h" #include #include #include @@ -458,8 +462,25 @@ // Begin the exception table. // Sometimes we want not to emit the data into separate section (e.g. ARM // EHABI). In this case LSDASection will be NULL. - if (LSDASection) + if (LSDASection) { + const Function &F = MF->getFunction(); + if (Asm->TM.getTargetTriple().isOSBinFormatELF()) { + const MCSymbolELF *LinkedToSym = nullptr; + unsigned Flags = ELF::SHF_ALLOC; + StringRef Group; + if (F.hasComdat()) { + Group = F.getComdat()->getName(); + Flags |= ELF::SHF_GROUP; + } + // Append the function name as a suffix like GCC. Note in the + // -fno-unique-section-names case we could use SHF_LINK_ORDER but that + // would require that we know the linker is a modern LLD (11.0 or later). + LSDASection = Asm->OutContext.getELFSection( + LSDASection->getName() + "." + F.getName(), ELF::SHT_PROGBITS, Flags, + 0, Group, MCSection::NonUniqueID, LinkedToSym); + } Asm->OutStreamer->SwitchSection(LSDASection); + } Asm->emitAlignment(Align(4)); // Emit the LSDA. diff --git a/llvm/test/CodeGen/X86/gcc_except_table-multi.ll b/llvm/test/CodeGen/X86/gcc_except_table-multi.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/X86/gcc_except_table-multi.ll @@ -0,0 +1,44 @@ +; RUN: llc < %s -mtriple x86_64 | FileCheck %s +@_ZTIi = external constant i8* + +;; If the function is in a comdat group, the generated .gcc_except_table should +;; be placed in the same group, so that .gcc_except_table can be discarded if +;; the comdat is not prevailing. +$group = comdat any +define i32 @group() uwtable comdat personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) { +; CHECK-LABEL: group: +; CHECK: .cfi_endproc +; CHECK-NEXT: .section .gcc_except_table.group,"aG",@progbits,group,comdat +entry: + invoke void @ext() to label %try.cont unwind label %lpad +lpad: + %0 = landingpad { i8*, i32 } catch i8* bitcast (i8** @_ZTIi to i8*) + br label %eh.resume +try.cont: + ret i32 0 +eh.resume: + resume { i8*, i32 } %0 +} + +;; Append the function name to get a unique section name like GCC. +;; This allows --gc-sections and STB_LOCAL relocations referencing text +;; sections if call-site code ranges are not compile-time constant (RISC-V +;; -mrelax or -fbasic-block-sections=). +define i32 @foo() uwtable personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) { +; CHECK-LABEL: foo: +; CHECK: .cfi_endproc +; CHECK-NEXT: .section .gcc_except_table.foo,"a",@progbits +entry: + invoke void @ext() to label %try.cont unwind label %lpad +lpad: + %0 = landingpad { i8*, i32 } catch i8* bitcast (i8** @_ZTIi to i8*) + br label %eh.resume +try.cont: + ret i32 0 +eh.resume: + resume { i8*, i32 } %0 +} + +declare void @ext() + +declare i32 @__gxx_personality_v0(...)