diff --git a/lld/test/ELF/cheri/exception-table.cpp b/lld/test/ELF/cheri/exception-table.cpp deleted file mode 100644 index 5e79217d9aff..000000000000 --- a/lld/test/ELF/cheri/exception-table.cpp +++ /dev/null @@ -1,104 +0,0 @@ -// RUN: %cheri_purecap_cc1 -O2 -mframe-pointer=none -fcxx-exceptions -fexceptions %s -emit-obj -o %t.o -// RUN: llvm-readobj -r %t.o | FileCheck %s --check-prefix=MIPS-OBJ-RELOCS -// RUN: %riscv64_cheri_purecap_cc1 -O2 -mframe-pointer=none -fcxx-exceptions -fexceptions %s -emit-obj -o %t-riscv64.o -// RUN: llvm-readobj -r %t-riscv64.o | FileCheck %s --check-prefix=RV64-OBJ-RELOCS -/// Should have two relocations against a local alias for _Z4testll -// MIPS-OBJ-RELOCS: Section ({{.+}}) .rela.gcc_except_table { -// MIPS-OBJ-RELOCS-NEXT: R_MIPS_CHERI_CAPABILITY/R_MIPS_NONE/R_MIPS_NONE .L_Z4testll$eh_alias -// MIPS-OBJ-RELOCS-NEXT: R_MIPS_CHERI_CAPABILITY/R_MIPS_NONE/R_MIPS_NONE .L_Z4testll$eh_alias -// MIPS-OBJ-RELOCS-NEXT: } -// RV64-OBJ-RELOCS: Section ({{.+}}) .rela.gcc_except_table { -// RV64-OBJ-RELOCS-NEXT: R_RISCV_ADD32 0x0 -// RV64-OBJ-RELOCS-NEXT: R_RISCV_SUB32 0x0 -// RV64-OBJ-RELOCS-NEXT: R_RISCV_ADD32 0x0 -// RV64-OBJ-RELOCS-NEXT: R_RISCV_SUB32 0x0 -// RV64-OBJ-RELOCS-NEXT: R_RISCV_CHERI_CAPABILITY .L_Z4testll$eh_alias -// RV64-OBJ-RELOCS-NEXT: R_RISCV_ADD32 0x0 -// RV64-OBJ-RELOCS-NEXT: R_RISCV_SUB32 0x0 -// RV64-OBJ-RELOCS-NEXT: R_RISCV_ADD32 0x0 -// RV64-OBJ-RELOCS-NEXT: R_RISCV_SUB32 0x0 -// RV64-OBJ-RELOCS-NEXT: R_RISCV_CHERI_CAPABILITY .L_Z4testll$eh_alias -// RV64-OBJ-RELOCS-NEXT: R_RISCV_ADD32 0x0 -// RV64-OBJ-RELOCS-NEXT: R_RISCV_SUB32 0x0 -// RV64-OBJ-RELOCS-NEXT: R_RISCV_ADD32 0x0 -// RV64-OBJ-RELOCS-NEXT: R_RISCV_SUB32 0x0 -// RV64-OBJ-RELOCS-NEXT: } - -/// This should work with both -z text and -z notext -/// Check that .gcc_except_table ends up in the relro section and the relocations are correct -// RUN: ld.lld -shared %t.o -o %t.so -z notext -// RUN: llvm-readelf -r --section-mapping --sections --program-headers --cap-relocs %t.so | FileCheck %s --check-prefixes=HEADERS,MIPS-RELOCS -// RUN: ld.lld -shared %t.o -o %t.so -z text -// RUN: llvm-readelf -r --section-mapping %t.so -// RUN: llvm-readelf -r --section-mapping --sections --program-headers --cap-relocs %t.so | FileCheck %s --check-prefixes=HEADERS,MIPS-RELOCS - -// HEADERS-LABEL: There are 10 program headers, starting at -// HEADERS-EMPTY: -// HEADERS-NEXT: Program Headers: -// HEADERS-NEXT: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align -// HEADERS-NEXT: PHDR 0x{{.+}} 0x{{.+}} 0x{{.+}} 0x{{.+}} 0x{{.+}} R 0x8 -// HEADERS-NEXT: LOAD 0x{{.+}} 0x{{.+}} 0x{{.+}} 0x{{.+}} 0x{{.+}} R 0x10000 -// HEADERS-NEXT: LOAD 0x{{.+}} 0x{{.+}} 0x{{.+}} 0x{{.+}} 0x{{.+}} R E 0x10000 -// HEADERS-NEXT: LOAD 0x{{.+}} 0x{{.+}} 0x{{.+}} 0x{{.+}} 0x{{.+}} RW 0x10000 -// HEADERS-NEXT: LOAD 0x{{.+}} 0x{{.+}} 0x{{.+}} 0x{{.+}} 0x{{.+}} RW 0x10000 -// HEADERS-NEXT: DYNAMIC 0x{{.+}} 0x{{.+}} 0x{{.+}} 0x{{.+}} 0x{{.+}} R 0x8 -// HEADERS-NEXT: GNU_RELRO 0x{{.+}} 0x{{.+}} 0x{{.+}} 0x{{.+}} 0x{{.+}} R 0x1 -// HEADERS-NEXT: GNU_STACK 0x{{.+}} 0x{{.+}} 0x{{.+}} 0x{{.+}} 0x{{.+}} RW 0x0 -// HEADERS-NEXT: OPTIONS 0x{{.+}} 0x{{.+}} 0x{{.+}} 0x{{.+}} 0x{{.+}} R 0x8 -// HEADERS-NEXT: ABIFLAGS 0x{{.+}} 0x{{.+}} 0x{{.+}} 0x{{.+}} 0x{{.+}} R 0x8 -// HEADERS-EMPTY: -// HEADERS-NEXT: Section to Segment mapping: -// HEADERS-NEXT: Segment Sections... -// HEADERS-NEXT: 00 -// HEADERS-NEXT: 01 .MIPS.abiflags .MIPS.options .dynsym .hash .dynamic .dynstr .rel.dyn .rel.plt .eh_frame __cap_relocs {{$}} -// HEADERS-NEXT: 02 .text -// HEADERS-NEXT: 03 .gcc_except_table -// HEADERS-NEXT: 04 .data .captable .got -// HEADERS-NEXT: 05 .dynamic -// HEADERS-NEXT: 06 .gcc_except_table -// HEADERS-NEXT: 07 -// HEADERS-NEXT: 08 .MIPS.options -// HEADERS-NEXT: 09 .MIPS.abiflags -// HEADERS-NEXT: None .bss .mdebug.abi64 .pdr .comment .symtab .shstrtab .strtab - -// MIPS-RELOCS-LABEL: Relocation section '.rel.dyn' {{.+}} contains 1 entries: -// MIPS-RELOCS-NEXT: Offset Info Type Symbol's Value Symbol's Name -// MIPS-RELOCS-NEXT: R_MIPS_CHERI_CAPABILITY/R_MIPS_NONE/R_MIPS_NONE 0000000000000000 __gxx_personality_v0 -// MIPS-RELOCS-EMPTY: -// MIPS-RELOCS-NEXT: Relocation section '.rel.plt' at offset {{.+}} contains 3 entries: -// MIPS-RELOCS-NEXT: Offset Info Type Symbol's Value Symbol's Name -// MIPS-RELOCS-NEXT: R_MIPS_CHERI_CAPABILITY_CALL/R_MIPS_NONE/R_MIPS_NONE 0000000000000000 _Z11external_fnl -// MIPS-RELOCS-NEXT: R_MIPS_CHERI_CAPABILITY_CALL/R_MIPS_NONE/R_MIPS_NONE 0000000000000000 __cxa_begin_catch -// MIPS-RELOCS-NEXT: R_MIPS_CHERI_CAPABILITY_CALL/R_MIPS_NONE/R_MIPS_NONE 0000000000000000 __cxa_end_catch - -/// Local relocations for exception handling: -// MIPS-RELOCS-NEXT: CHERI __cap_relocs [ -// MIPS-RELOCS-NEXT: 0x02{{.+}} Base: 0x1{{.+}} (.L_Z4testll$eh_alias+132) Length: 164 Perms: Function -// MIPS-RELOCS-NEXT: 0x02{{.+}} Base: 0x1{{.+}} (.L_Z4testll$eh_alias+100) Length: 164 Perms: Function -// MIPS-RELOCS-NEXT: ] - -/// Should also emit __cap_relocs for RISC-V: -// RUN: ld.lld -shared %t-riscv64.o -o %t.so -// RUN: llvm-readelf -r --cap-relocs %t.so | FileCheck %s --check-prefixes=RV64-RELOCS -// RV64-RELOCS: CHERI __cap_relocs [ -// RV64-RELOCS-NEXT: 0x002{{.+}} Base: 0x1{{.+}} (.L_Z4testll$eh_alias+96) Length: 120 Perms: Function -// RV64-RELOCS-NEXT: 0x002{{.+}} Base: 0x1{{.+}} (.L_Z4testll$eh_alias+72) Length: 120 Perms: Function -// RV64-RELOCS-NEXT: ] - -long external_fn(long arg); - -long test(long arg, long arg2) { - int a = 0; - int b = 0; - try { - a = external_fn(arg); - } catch (...) { - return -1; - } - try { - b = external_fn(arg2); - } catch (...) { - return a; - } - return a + b; -} diff --git a/lld/test/ELF/cheri/exception-table.ll b/lld/test/ELF/cheri/exception-table.ll new file mode 100644 index 000000000000..c6d3be8269e0 --- /dev/null +++ b/lld/test/ELF/cheri/exception-table.ll @@ -0,0 +1,215 @@ +; RUN: %cheri_purecap_llc --relocation-model=pic < %s -filetype=obj -o %t.o +; RUN: llvm-readobj -r %t.o | FileCheck %s --check-prefix=MIPS-OBJ-RELOCS +; RUN: %riscv64_cheri_purecap_llc --relocation-model=pic < %s -filetype=obj -o %t-riscv64.o +; RUN: llvm-readobj -r %t-riscv64.o | FileCheck %s --check-prefix=RV64-OBJ-RELOCS +;; Should have two relocations against a local alias for _Z4testll +; MIPS-OBJ-RELOCS: Section ({{.+}}) .rela.gcc_except_table { +; MIPS-OBJ-RELOCS-NEXT: R_MIPS_CHERI_CAPABILITY/R_MIPS_NONE/R_MIPS_NONE .L_Z4testll$local 0x80 +; MIPS-OBJ-RELOCS-NEXT: R_MIPS_CHERI_CAPABILITY/R_MIPS_NONE/R_MIPS_NONE .L_Z4testll$local 0x60 +; MIPS-OBJ-RELOCS-NEXT: R_MIPS_CHERI_CAPABILITY/R_MIPS_NONE/R_MIPS_NONE .L_Z5test2ll$local 0x60 +; MIPS-OBJ-RELOCS-NEXT: R_MIPS_PC32/R_MIPS_NONE/R_MIPS_NONE .L_ZTIl.DW.stub 0x0 +; MIPS-OBJ-RELOCS-NEXT: } +; RV64-OBJ-RELOCS: Section ({{.+}}) .rela.gcc_except_table { +; RV64-OBJ-RELOCS-NEXT: R_RISCV_ADD32 0x0 +; RV64-OBJ-RELOCS-NEXT: R_RISCV_SUB32 0x0 +; RV64-OBJ-RELOCS-NEXT: R_RISCV_ADD32 0x0 +; RV64-OBJ-RELOCS-NEXT: R_RISCV_SUB32 0x0 +; RV64-OBJ-RELOCS-NEXT: R_RISCV_CHERI_CAPABILITY .L_Z4testll$local 0x5C +; RV64-OBJ-RELOCS-NEXT: R_RISCV_ADD32 0x0 +; RV64-OBJ-RELOCS-NEXT: R_RISCV_SUB32 0x0 +; RV64-OBJ-RELOCS-NEXT: R_RISCV_ADD32 0x0 +; RV64-OBJ-RELOCS-NEXT: R_RISCV_SUB32 0x0 +; RV64-OBJ-RELOCS-NEXT: R_RISCV_CHERI_CAPABILITY .L_Z4testll$local 0x48 +; RV64-OBJ-RELOCS-NEXT: R_RISCV_ADD32 0x0 +; RV64-OBJ-RELOCS-NEXT: R_RISCV_SUB32 0x0 +; RV64-OBJ-RELOCS-NEXT: R_RISCV_ADD32 0x0 +; RV64-OBJ-RELOCS-NEXT: R_RISCV_SUB32 0x0 +; RV64-OBJ-RELOCS-NEXT: R_RISCV_ADD32 0x0 +; RV64-OBJ-RELOCS-NEXT: R_RISCV_SUB32 0x0 +; RV64-OBJ-RELOCS-NEXT: R_RISCV_ADD32 0x0 +; RV64-OBJ-RELOCS-NEXT: R_RISCV_SUB32 0x0 +; RV64-OBJ-RELOCS-NEXT: R_RISCV_CHERI_CAPABILITY .L_Z5test2ll$local 0x48 +; RV64-OBJ-RELOCS-NEXT: R_RISCV_ADD32 0x0 +; RV64-OBJ-RELOCS-NEXT: R_RISCV_SUB32 0x0 +; RV64-OBJ-RELOCS-NEXT: R_RISCV_ADD32 0x0 +; RV64-OBJ-RELOCS-NEXT: R_RISCV_SUB32 0x0 +; RV64-OBJ-RELOCS-NEXT: R_RISCV_32_PCREL .L_ZTIl.DW.stub 0x0 +; RV64-OBJ-RELOCS-NEXT: } + +;; This should work with both -z text and -z notext +;; Check that .gcc_except_table ends up in the relro section and the relocations are correct +; RUN: ld.lld -shared %t.o -o %t.so -z notext +; RUN: llvm-readelf -r --section-mapping --sections --program-headers --cap-relocs %t.so | FileCheck %s --check-prefixes=HEADERS,MIPS-RELOCS +; RUN: ld.lld -shared %t.o -o %t.so -z text +; RUN: llvm-readelf -r --section-mapping %t.so +; RUN: llvm-readelf -r --section-mapping --sections --program-headers --cap-relocs %t.so | FileCheck %s --check-prefixes=HEADERS,MIPS-RELOCS + +; HEADERS-LABEL: There are 10 program headers, starting at +; HEADERS-EMPTY: +; HEADERS-NEXT: Program Headers: +; HEADERS-NEXT: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align +; HEADERS-NEXT: PHDR 0x{{.+}} 0x{{.+}} 0x{{.+}} 0x{{.+}} 0x{{.+}} R 0x8 +; HEADERS-NEXT: LOAD 0x{{.+}} 0x{{.+}} 0x{{.+}} 0x{{.+}} 0x{{.+}} R 0x10000 +; HEADERS-NEXT: LOAD 0x{{.+}} 0x{{.+}} 0x{{.+}} 0x{{.+}} 0x{{.+}} R E 0x10000 +; HEADERS-NEXT: LOAD 0x{{.+}} 0x{{.+}} 0x{{.+}} 0x{{.+}} 0x{{.+}} RW 0x10000 +; HEADERS-NEXT: LOAD 0x{{.+}} 0x{{.+}} 0x{{.+}} 0x{{.+}} 0x{{.+}} RW 0x10000 +; HEADERS-NEXT: DYNAMIC 0x{{.+}} 0x{{.+}} 0x{{.+}} 0x{{.+}} 0x{{.+}} R 0x8 +; HEADERS-NEXT: GNU_RELRO 0x{{.+}} 0x{{.+}} 0x{{.+}} 0x{{.+}} 0x{{.+}} R 0x1 +; HEADERS-NEXT: GNU_STACK 0x{{.+}} 0x{{.+}} 0x{{.+}} 0x{{.+}} 0x{{.+}} RW 0x0 +; HEADERS-NEXT: OPTIONS 0x{{.+}} 0x{{.+}} 0x{{.+}} 0x{{.+}} 0x{{.+}} R 0x8 +; HEADERS-NEXT: ABIFLAGS 0x{{.+}} 0x{{.+}} 0x{{.+}} 0x{{.+}} 0x{{.+}} R 0x8 +; HEADERS-EMPTY: +; HEADERS-NEXT: Section to Segment mapping: +; HEADERS-NEXT: Segment Sections... +; HEADERS-NEXT: 00 +; HEADERS-NEXT: 01 .MIPS.abiflags .MIPS.options .dynsym .hash .dynamic .dynstr .rel.dyn .rel.plt .eh_frame __cap_relocs {{$}} +; HEADERS-NEXT: 02 .text +; HEADERS-NEXT: 03 .gcc_except_table +; HEADERS-NEXT: 04 .data .captable .got +; HEADERS-NEXT: 05 .dynamic +; HEADERS-NEXT: 06 .gcc_except_table +; HEADERS-NEXT: 07 +; HEADERS-NEXT: 08 .MIPS.options +; HEADERS-NEXT: 09 .MIPS.abiflags +; HEADERS-NEXT: None .bss .mdebug.abi64 .pdr .comment .symtab .shstrtab .strtab + +; MIPS-RELOCS-LABEL: Relocation section '.rel.dyn' {{.+}} contains 2 entries: +; MIPS-RELOCS-NEXT: Offset Info Type Symbol's Value Symbol's Name +; MIPS-RELOCS-NEXT: R_MIPS_CHERI_CAPABILITY/R_MIPS_NONE/R_MIPS_NONE 0000000000000000 _ZTIl +; MIPS-RELOCS-NEXT: R_MIPS_CHERI_CAPABILITY/R_MIPS_NONE/R_MIPS_NONE 0000000000000000 __gxx_personality_v0 +; MIPS-RELOCS-EMPTY: +; MIPS-RELOCS-NEXT: Relocation section '.rel.plt' at offset {{.+}} contains 3 entries: +; MIPS-RELOCS-NEXT: Offset Info Type Symbol's Value Symbol's Name +; MIPS-RELOCS-NEXT: R_MIPS_CHERI_CAPABILITY_CALL/R_MIPS_NONE/R_MIPS_NONE 0000000000000000 _Z11external_fnl +; MIPS-RELOCS-NEXT: R_MIPS_CHERI_CAPABILITY_CALL/R_MIPS_NONE/R_MIPS_NONE 0000000000000000 __cxa_begin_catch +; MIPS-RELOCS-NEXT: R_MIPS_CHERI_CAPABILITY_CALL/R_MIPS_NONE/R_MIPS_NONE 0000000000000000 __cxa_end_catch + +;; Local relocations for exception handling: +; MIPS-RELOCS-NEXT: CHERI __cap_relocs [ +; MIPS-RELOCS-NEXT: 0x02{{.+}} Base: 0x1{{.+}} (.L_Z4testll$local+128) Length: 160 Perms: Function +; MIPS-RELOCS-NEXT: 0x02{{.+}} Base: 0x1{{.+}} (.L_Z4testll$local+96) Length: 160 Perms: Function +; MIPS-RELOCS-NEXT: 0x02{{.+}} Base: 0x1{{.+}} (.L_Z5test2ll$local+96) Length: 168 Perms: Function +; MIPS-RELOCS-NEXT: ] + +;; Should also emit __cap_relocs for RISC-V: +; RUN: ld.lld -shared %t-riscv64.o -o %t.so +; RUN: llvm-readelf -r --cap-relocs %t.so | FileCheck %s --check-prefixes=RV64-RELOCS +; RV64-RELOCS: CHERI __cap_relocs [ +; RV64-RELOCS-NEXT: 0x002{{.+}} Base: 0x1{{.+}} (.L_Z4testll$local+92) Length: 116 Perms: Function +; RV64-RELOCS-NEXT: 0x002{{.+}} Base: 0x1{{.+}} (.L_Z4testll$local+72) Length: 116 Perms: Function +; RV64-RELOCS-NEXT: 0x002{{.+}} Base: 0x1{{.+}} (.L_Z5test2ll$local+72) Length: 124 Perms: Function +; RV64-RELOCS-NEXT: ] + +; IR was generated from the following code: +; long external_fn(long arg); +; +; long test(long arg, long arg2) { +; long a = 0; +; long b = 0; +; try { +; a = external_fn(arg); +; } catch (...) { +; return -1; +; } +; try { +; b = external_fn(arg2); +; } catch (...) { +; return a; +; } +; return a + b; +; } +; +; long test2(long arg, long arg2) { +; try { +; return external_fn(arg) - external_fn(arg2); +; } catch (long &err) { +; return err; +; } catch (...) { +; return -1; +; } +; } + +@_ZTIl = external dso_local addrspace(200) constant ptr addrspace(200) + +define dso_local noundef i64 @_Z4testll(i64 noundef %arg, i64 noundef %arg2) local_unnamed_addr addrspace(200) uwtable personality ptr addrspace(200) @__gxx_personality_v0 { +entry: + %call = invoke noundef i64 @_Z11external_fnl(i64 noundef %arg) + to label %invoke.cont unwind label %lpad + +invoke.cont: + %call3 = invoke noundef i64 @_Z11external_fnl(i64 noundef %arg2) + to label %invoke.cont2 unwind label %lpad1 + +lpad: + %0 = landingpad { ptr addrspace(200), i32 } + catch ptr addrspace(200) null + %1 = extractvalue { ptr addrspace(200), i32 } %0, 0 + %2 = tail call ptr addrspace(200) @__cxa_begin_catch(ptr addrspace(200) %1) nounwind + tail call void @__cxa_end_catch() + br label %cleanup + +invoke.cont2: + %add = add nsw i64 %call3, %call + br label %cleanup + +lpad1: + %3 = landingpad { ptr addrspace(200), i32 } + catch ptr addrspace(200) null + %4 = extractvalue { ptr addrspace(200), i32 } %3, 0 + %5 = tail call ptr addrspace(200) @__cxa_begin_catch(ptr addrspace(200) %4) nounwind + tail call void @__cxa_end_catch() + br label %cleanup + +cleanup: + %retval.0 = phi i64 [ %add, %invoke.cont2 ], [ %call, %lpad1 ], [ -1, %lpad ] + ret i64 %retval.0 +} + +declare dso_local noundef i64 @_Z11external_fnl(i64 noundef) local_unnamed_addr addrspace(200) + +declare dso_local i32 @__gxx_personality_v0(...) addrspace(200) + +declare dso_local ptr addrspace(200) @__cxa_begin_catch(ptr addrspace(200)) local_unnamed_addr addrspace(200) + +declare dso_local void @__cxa_end_catch() local_unnamed_addr addrspace(200) + +; Function Attrs: mustprogress uwtable +define dso_local noundef i64 @_Z5test2ll(i64 noundef %arg, i64 noundef %arg2) local_unnamed_addr addrspace(200) #0 personality ptr addrspace(200) @__gxx_personality_v0 { +entry: + %call = invoke noundef i64 @_Z11external_fnl(i64 noundef %arg) + to label %invoke.cont unwind label %lpad + +invoke.cont: + %call2 = invoke noundef i64 @_Z11external_fnl(i64 noundef %arg2) + to label %invoke.cont1 unwind label %lpad + +invoke.cont1: + %sub = sub nsw i64 %call, %call2 + br label %return + +lpad: + %0 = landingpad { ptr addrspace(200), i32 } + catch ptr addrspace(200) @_ZTIl + catch ptr addrspace(200) null + %1 = extractvalue { ptr addrspace(200), i32 } %0, 0 + %2 = extractvalue { ptr addrspace(200), i32 } %0, 1 + %3 = tail call i32 @llvm.eh.typeid.for(ptr addrspacecast (ptr addrspace(200) @_ZTIl to ptr)) nounwind + %matches = icmp eq i32 %2, %3 + %4 = tail call ptr addrspace(200) @__cxa_begin_catch(ptr addrspace(200) %1) nounwind + br i1 %matches, label %catch3, label %catch + +catch3: + %5 = load i64, ptr addrspace(200) %4, align 8 + tail call void @__cxa_end_catch() nounwind + br label %return + +catch: + tail call void @__cxa_end_catch() + br label %return + +return: + %retval.0 = phi i64 [ %sub, %invoke.cont1 ], [ %5, %catch3 ], [ -1, %catch ] + ret i64 %retval.0 +} + +declare i32 @llvm.eh.typeid.for(ptr) addrspace(200) diff --git a/lld/test/ELF/cheri/lit.local.cfg b/lld/test/ELF/cheri/lit.local.cfg index d6da5e3f9c44..6c91db14db14 100644 --- a/lld/test/ELF/cheri/lit.local.cfg +++ b/lld/test/ELF/cheri/lit.local.cfg @@ -26,7 +26,8 @@ config.lld = lit.util.which('ld.lld', config.llvm_tools_dir) # These substitutions rely on %clang, etc. so must come before even if clang isn't found add_sub('%clang_link_purecap ', '%cheri_purecap_clang ' + '-fuse-ld=' + config.lld + ' -nostdlib -Wl,-melf64btsmip_cheri_fbsd ') -local_llvm_config.add_cheri_tool_substitutions(['llvm-mc']) +local_llvm_config.use_llvm_tool("llc") +local_llvm_config.add_cheri_tool_substitutions(['llvm-mc', 'llc']) local_llvm_config.use_clang(required=False) if config.clang: if lit_config.debug: diff --git a/llvm/include/llvm/CodeGen/AsmPrinter.h b/llvm/include/llvm/CodeGen/AsmPrinter.h index 059856e0cbfa..2bf744727ec9 100644 --- a/llvm/include/llvm/CodeGen/AsmPrinter.h +++ b/llvm/include/llvm/CodeGen/AsmPrinter.h @@ -199,11 +199,8 @@ class AsmPrinter : public MachineFunctionPass { protected: MCSymbol *CurrentFnBegin = nullptr; - /// The symbol used to represent the start of the current function for the - /// purpose of exception handling for pure-capability CHERI targets. - MCSymbol *CurrentFnBeginForEH = nullptr; - /// For dso_local functions, the current $local alias for the function. + /// Also used for exception handling for pure-capability CHERI targets. MCSymbol *CurrentFnBeginLocal = nullptr; /// A vector of all debug/EH info emitters we should use. This vector @@ -333,7 +330,10 @@ class AsmPrinter : public MachineFunctionPass { /// Similar to getSymbol() but preferred for references. On ELF, this uses a /// local symbol if a reference to GV is guaranteed to be resolved to the /// definition in the same module. - MCSymbol *getSymbolPreferLocal(const GlobalValue &GV) const; + /// If \p Force is set to true, return a local alias if possible even if the + /// normal heuristics say it is not beneficial. + MCSymbol *getSymbolPreferLocal(const GlobalValue &GV, + bool Force = false) const; bool doesDwarfUseRelocationsAcrossSections() const { return DwarfUsesRelocationsAcrossSections; diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp index ccd1ea6826db..d6ce24929c8a 100644 --- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -672,7 +672,8 @@ MCSymbol *AsmPrinter::getSymbol(const GlobalValue *GV) const { return TM.getSymbol(GV); } -MCSymbol *AsmPrinter::getSymbolPreferLocal(const GlobalValue &GV) const { +MCSymbol *AsmPrinter::getSymbolPreferLocal(const GlobalValue &GV, + bool Force) const { // On ELF, use .Lfoo$local if GV is a non-interposable GlobalObject with an // exact definion (intersection of GlobalValue::hasExactDefinition() and // !isInterposable()). These linkages include: external, appending, internal, @@ -680,7 +681,10 @@ MCSymbol *AsmPrinter::getSymbolPreferLocal(const GlobalValue &GV) const { // assembler would otherwise be conservative and assume a global default // visibility symbol can be interposable, even if the code generator already // assumed it. - if (TM.getTargetTriple().isOSBinFormatELF() && GV.canBenefitFromLocalAlias()) { + if (Force) + return getSymbolWithGlobalValueBase(&GV, "$local"); + if (TM.getTargetTriple().isOSBinFormatELF() && + GV.canBenefitFromLocalAlias()) { const Module &M = *GV.getParent(); if (TM.getRelocationModel() != Reloc::Static && M.getPIELevel() == PIELevel::Default && GV.isDSOLocal()) @@ -954,9 +958,6 @@ void AsmPrinter::emitFunctionHeader() { if (MAI->hasDotTypeDotSizeDirective()) { OutStreamer->emitSymbolAttribute(CurrentFnSym, MCSA_ELF_TypeFunction); - if (CurrentFnBeginForEH) - OutStreamer->emitSymbolAttribute(CurrentFnBeginForEH, - MCSA_ELF_TypeFunction); } if (F.hasFnAttribute(Attribute::Cold)) @@ -1047,14 +1048,9 @@ void AsmPrinter::emitFunctionHeader() { if (MAI->useAssignmentForEHBegin()) { MCSymbol *CurPos = OutContext.createTempSymbol(); OutStreamer->emitLabel(CurPos); - if (CurrentFnBeginForEH) - OutStreamer->emitAssignment(CurrentFnBeginForEH, - MCSymbolRefExpr::create(CurPos, OutContext)); OutStreamer->emitAssignment(CurrentFnBegin, MCSymbolRefExpr::create(CurPos, OutContext)); } else { - if (CurrentFnBeginForEH) - OutStreamer->emitLabel(CurrentFnBeginForEH); OutStreamer->emitLabel(CurrentFnBegin); } } @@ -1076,6 +1072,8 @@ void AsmPrinter::emitFunctionHeader() { emitGlobalConstant(F.getParent()->getDataLayout(), F.getPrologueData(), 0); } +static bool needFuncLabelsForEH(const MachineFunction &MF); + /// EmitFunctionEntryLabel - Emit the label that is the entrypoint for the /// function. This can be overridden by targets as required to do custom stuff. void AsmPrinter::emitFunctionEntryLabel() { @@ -1090,7 +1088,10 @@ void AsmPrinter::emitFunctionEntryLabel() { OutStreamer->emitLabel(CurrentFnSym); if (TM.getTargetTriple().isOSBinFormatELF()) { - MCSymbol *Sym = getSymbolPreferLocal(MF->getFunction()); + // For CHERI purecap exception handling, we always have to use a local + // alias even if the function is not dso_local. + bool ForceLocal = MAI->isCheriPurecapABI() && needFuncLabelsForEH(*MF); + MCSymbol *Sym = getSymbolPreferLocal(MF->getFunction(), ForceLocal); if (Sym != CurrentFnSym) { cast(Sym)->setType(ELF::STT_FUNC); CurrentFnBeginLocal = Sym; @@ -1903,8 +1904,6 @@ void AsmPrinter::emitFunctionBody() { MCSymbolRefExpr::create(CurrentFnEnd, OutContext), MCSymbolRefExpr::create(CurrentFnSymForSize, OutContext), OutContext); OutStreamer->emitELFSize(CurrentFnSym, SizeExp); - if (CurrentFnBeginForEH) - OutStreamer->emitELFSize(CurrentFnBeginForEH, SizeExp); if (CurrentFnBeginLocal) OutStreamer->emitELFSize(CurrentFnBeginLocal, SizeExp); } @@ -2504,7 +2503,6 @@ void AsmPrinter::SetupMachineFunction(MachineFunction &MF) { CurrentFnSymForSize = CurrentFnSym; CurrentFnBegin = nullptr; - CurrentFnBeginForEH = nullptr; CurrentFnBeginLocal = nullptr; CurrentSectionBeginSym = nullptr; MBBSectionRanges.clear(); @@ -2518,14 +2516,6 @@ void AsmPrinter::SetupMachineFunction(MachineFunction &MF) { CurrentFnBegin = createTempSymbol("func_begin"); if (NeedsLocalForSize) CurrentFnSymForSize = CurrentFnBegin; - // In the pure-capability ABI we have to create dynamic relocations for the - // landing pads. To avoid creating an (unnecessary and incorrect) dynamic - // relocation with a non-zero addend, we need to ensure that the target - // symbol is non-preemptible by creating a local alias for the function. - // See https://github.com/CTSRD-CHERI/llvm-project/issues/512. - // TODO: could probably omit this for !F.isInterposable()? - if (MAI->isCheriPurecapABI() && needFuncLabelsForEH(MF)) - CurrentFnBeginForEH = getSymbolWithGlobalValueBase(&F, "$eh_alias"); } ORE = &getAnalysis().getORE(); diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp index 34d93a11615e..4feca927f162 100644 --- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp @@ -214,8 +214,8 @@ void AsmPrinter::emitCallSiteCheriCapability(const MCSymbol *Hi, // this would result in EmitCheriCapability() creating a relocation against // section plus offset rather than function + offset. We need the right // bounds and permissions info and need to use a non-preemptible alias. - assert(CurrentFnBeginForEH && "Missing local function entry alias for EH!"); - OutStreamer->EmitCheriCapability(CurrentFnBeginForEH, DiffToStart, + assert(CurrentFnBeginLocal && "Missing local function entry alias for EH!"); + OutStreamer->EmitCheriCapability(CurrentFnBeginLocal, DiffToStart, TLOF.getCheriCapabilitySize(TM)); } diff --git a/llvm/lib/Target/Mips/MipsAsmPrinter.cpp b/llvm/lib/Target/Mips/MipsAsmPrinter.cpp index 047179d8b5d6..669477f5de30 100644 --- a/llvm/lib/Target/Mips/MipsAsmPrinter.cpp +++ b/llvm/lib/Target/Mips/MipsAsmPrinter.cpp @@ -428,7 +428,7 @@ void MipsAsmPrinter::emitFunctionEntryLabel() { TS.emitDirectiveSetNoMips16(); TS.emitDirectiveEnt(*CurrentFnSym); - OutStreamer->emitLabel(CurrentFnSym); + AsmPrinter::emitFunctionEntryLabel(); } /// EmitFunctionBodyStart - Targets can override this to emit stuff before diff --git a/llvm/test/CodeGen/CHERI-Generic/Inputs/landingpad-non-preemptible.ll b/llvm/test/CodeGen/CHERI-Generic/Inputs/landingpad-non-preemptible.ll index ebcbdff39225..c82d222e3505 100644 --- a/llvm/test/CodeGen/CHERI-Generic/Inputs/landingpad-non-preemptible.ll +++ b/llvm/test/CodeGen/CHERI-Generic/Inputs/landingpad-non-preemptible.ll @@ -1,5 +1,5 @@ -; RUN: llc @PURECAP_HARDFLOAT_ARGS@ < %s -o - | FileCheck %s -; RUN: llc @PURECAP_HARDFLOAT_ARGS@ < %s -o - -filetype=obj | llvm-readobj --relocs --symbols - | FileCheck %s --check-prefix=RELOCS +; RUN: llc @PURECAP_HARDFLOAT_ARGS@ --relocation-model=pic < %s -o - | FileCheck %s +; RUN: llc @PURECAP_HARDFLOAT_ARGS@ --relocation-model=pic < %s -o - -filetype=obj | llvm-readobj --relocs --symbols - | FileCheck %s --check-prefix=RELOCS ; Capabilities for exception landing pads were using preemptible relocations such as ; .chericap foo + .Ltmp - .Lfunc_begin instead of using a local alias. ; https://github.com/CTSRD-CHERI/llvm-project/issues/512 @@ -15,34 +15,32 @@ ; } ; } -; UTC_ARGS: --disable -; CHECK: .type .L_Z8do_catchv$eh_alias,@function -; UTC_ARGS: --enable - -@_ZTIi = external dso_local addrspace(200) constant i8 addrspace(200)* -define dso_local i32 @_Z8do_catchv() local_unnamed_addr addrspace(200) uwtable personality i8 addrspace(200)* bitcast (i32 (...) addrspace(200)* @__gxx_personality_v0 to i8 addrspace(200)*) { +@_ZTIi = external dso_local addrspace(200) constant ptr addrspace(200) +define dso_local noundef signext i32 @_Z8do_catchv() local_unnamed_addr addrspace(200) #0 personality ptr addrspace(200) @__gxx_personality_v0 { entry: - %call = invoke i32 @_Z3foov() to label %return unwind label %lpad -lpad: - %0 = landingpad { i8 addrspace(200)*, i32 } - catch i8 addrspace(200)* bitcast (i8 addrspace(200)* addrspace(200)* @_ZTIi to i8 addrspace(200)*) - catch i8 addrspace(200)* null - %1 = extractvalue { i8 addrspace(200)*, i32 } %0, 0 - %2 = extractvalue { i8 addrspace(200)*, i32 } %0, 1 - %3 = tail call i32 @llvm.eh.typeid.for(i8* addrspacecast (i8 addrspace(200)* bitcast (i8 addrspace(200)* addrspace(200)* @_ZTIi to i8 addrspace(200)*) to i8*)) + %call = invoke noundef signext i32 @_Z3foov() + to label %return unwind label %lpad + +lpad: ; preds = %entry + %0 = landingpad { ptr addrspace(200), i32 } + catch ptr addrspace(200) @_ZTIi + catch ptr addrspace(200) null + %1 = extractvalue { ptr addrspace(200), i32 } %0, 0 + %2 = extractvalue { ptr addrspace(200), i32 } %0, 1 + %3 = tail call i32 @llvm.eh.typeid.for(ptr addrspacecast (ptr addrspace(200) @_ZTIi to ptr)) nounwind %matches = icmp eq i32 %2, %3 - %4 = tail call i8 addrspace(200)* @__cxa_begin_catch(i8 addrspace(200)* %1) nounwind + %4 = tail call ptr addrspace(200) @__cxa_begin_catch(ptr addrspace(200) %1) nounwind br i1 %matches, label %catch1, label %catch -catch1: +catch1: ; preds = %lpad tail call void @__cxa_end_catch() nounwind br label %return -catch: +catch: ; preds = %lpad tail call void @__cxa_end_catch() br label %return -return: +return: ; preds = %entry, %catch1, %catch %retval.0 = phi i32 [ 1, %catch1 ], [ 2, %catch ], [ %call, %entry ] ret i32 %retval.0 } @@ -53,14 +51,14 @@ declare dso_local i32 @__gxx_personality_v0(...) addrspace(200) declare i32 @llvm.eh.typeid.for(i8*) addrspace(200) nounwind readnone -declare dso_local i8 addrspace(200)* @__cxa_begin_catch(i8 addrspace(200)*) local_unnamed_addr addrspace(200) +declare dso_local ptr addrspace(200) @__cxa_begin_catch(ptr addrspace(200)) local_unnamed_addr addrspace(200) declare dso_local void @__cxa_end_catch() local_unnamed_addr addrspace(200) ; UTC_ARGS: --disable ; CHECK: .Lfunc_end0: ; CHECK-NEXT: .size _Z8do_catchv, .Lfunc_end0-_Z8do_catchv -; CHECK-NEXT: .size .L_Z8do_catchv$eh_alias, .Lfunc_end0-_Z8do_catchv +; CHECK-NEXT: .size .L_Z8do_catchv$local, .Lfunc_end0-_Z8do_catchv ; CHECK: GCC_except_table0: ; CHECK-NEXT: .Lexception0: @@ -78,7 +76,7 @@ declare dso_local void @__cxa_end_catch() local_unnamed_addr addrspace(200) ; Note: RISC-V uses DW_EH_PE_udata4, so the 0xc marker uses 4 bytes instead of 1 ; CHECK-NEXT: [[SMALL_CS_DIRECTIVE:(\.byte)|(\.word)]] 12 # (landing pad is a capability) ; Note: the following line should not be using _Z8do_catchv, but a local alias -; CHECK-NEXT: .chericap .L_Z8do_catchv$eh_alias + .Ltmp2-.Lfunc_begin0 # jumps to .Ltmp2 +; CHECK-NEXT: .chericap .L_Z8do_catchv$local + .Ltmp2-.Lfunc_begin0 # jumps to .Ltmp2 ; CHECK-NEXT: .byte 3 # On action: 2 ; CHECK-NEXT: [[CS_DIRECTIVE]] .Ltmp1-.Lfunc_begin0 # >> Call Site 2 << ; CHECK-NEXT: [[CS_DIRECTIVE]] .Lfunc_end0-.Ltmp1 # Call between .Ltmp1 and .Lfunc_end0 @@ -105,13 +103,13 @@ declare dso_local void @__cxa_end_catch() local_unnamed_addr addrspace(200) ; RELOCS-LABEL: Relocations [ ; RELOCS-LABEL: Section ({{.+}}) .rela.gcc_except_table { -@IF-MIPS@; RELOCS-NEXT: R_MIPS_CHERI_CAPABILITY/R_MIPS_NONE/R_MIPS_NONE .L_Z8do_catchv$eh_alias 0x4C +@IF-MIPS@; RELOCS-NEXT: R_MIPS_CHERI_CAPABILITY/R_MIPS_NONE/R_MIPS_NONE .L_Z8do_catchv$local 0x4C @IF-MIPS@; RELOCS-NEXT: R_MIPS_PC32/R_MIPS_NONE/R_MIPS_NONE .L_ZTIi.DW.stub 0x0 @IF-RISCV@; RELOCS-NEXT: R_RISCV_ADD32 0x0 @IF-RISCV@; RELOCS-NEXT: R_RISCV_SUB32 0x0 @IF-RISCV@; RELOCS-NEXT: R_RISCV_ADD32 0x0 @IF-RISCV@; RELOCS-NEXT: R_RISCV_SUB32 0x0 -@IF-RISCV@; RELOCS-NEXT: R_RISCV_CHERI_CAPABILITY .L_Z8do_catchv$eh_alias 0x34 +@IF-RISCV@; RELOCS-NEXT: R_RISCV_CHERI_CAPABILITY .L_Z8do_catchv$locals 0x34 @IF-RISCV@; RELOCS-NEXT: R_RISCV_ADD32 0x0 @IF-RISCV@; RELOCS-NEXT: R_RISCV_SUB32 0x0 @IF-RISCV@; RELOCS-NEXT: R_RISCV_ADD32 0x0 @@ -121,7 +119,7 @@ declare dso_local void @__cxa_end_catch() local_unnamed_addr addrspace(200) ; The local alias should have the same type and non-zero size as the real function: ; RELOCS: Symbol { -; RELOCS-LABEL: Name: .L_Z8do_catchv$eh_alias ( +; RELOCS-LABEL: Name: .L_Z8do_catchv$local ( ; RELOCS-NEXT: Value: 0x0 ; RELOCS-NEXT: Size: [[FN_SIZE:[1-9][0-9]*]] ; RELOCS-NEXT: Binding: Local (0x0) diff --git a/llvm/test/CodeGen/CHERI-Generic/MIPS/landingpad-non-preemptible.ll b/llvm/test/CodeGen/CHERI-Generic/MIPS/landingpad-non-preemptible.ll index 8f20ed0ce192..b1803957a8dc 100644 --- a/llvm/test/CodeGen/CHERI-Generic/MIPS/landingpad-non-preemptible.ll +++ b/llvm/test/CodeGen/CHERI-Generic/MIPS/landingpad-non-preemptible.ll @@ -1,7 +1,7 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --scrub-attributes --version 2 ; DO NOT EDIT -- This file was generated from test/CodeGen/CHERI-Generic/Inputs/landingpad-non-preemptible.ll -; RUN: llc -mtriple=mips64 -mcpu=cheri128 -mattr=+cheri128 --relocation-model=pic -target-abi purecap < %s -o - | FileCheck %s -; RUN: llc -mtriple=mips64 -mcpu=cheri128 -mattr=+cheri128 --relocation-model=pic -target-abi purecap < %s -o - -filetype=obj | llvm-readobj --relocs --symbols - | FileCheck %s --check-prefix=RELOCS +; RUN: llc -mtriple=mips64 -mcpu=cheri128 -mattr=+cheri128 --relocation-model=pic -target-abi purecap --relocation-model=pic < %s -o - | FileCheck %s +; RUN: llc -mtriple=mips64 -mcpu=cheri128 -mattr=+cheri128 --relocation-model=pic -target-abi purecap --relocation-model=pic < %s -o - -filetype=obj | llvm-readobj --relocs --symbols - | FileCheck %s --check-prefix=RELOCS ; Capabilities for exception landing pads were using preemptible relocations such as ; .chericap foo + .Ltmp - .Lfunc_begin instead of using a local alias. ; https://github.com/CTSRD-CHERI/llvm-project/issues/512 @@ -17,12 +17,8 @@ ; } ; } -; UTC_ARGS: --disable -; CHECK: .type .L_Z8do_catchv$eh_alias,@function -; UTC_ARGS: --enable - -@_ZTIi = external dso_local addrspace(200) constant i8 addrspace(200)* -define dso_local i32 @_Z8do_catchv() local_unnamed_addr addrspace(200) uwtable personality i8 addrspace(200)* bitcast (i32 (...) addrspace(200)* @__gxx_personality_v0 to i8 addrspace(200)*) { +@_ZTIi = external dso_local addrspace(200) constant ptr addrspace(200) +define dso_local noundef signext i32 @_Z8do_catchv() local_unnamed_addr addrspace(200) #0 personality ptr addrspace(200) @__gxx_personality_v0 { ; CHECK-LABEL: _Z8do_catchv: ; CHECK: # %bb.0: # %entry ; CHECK-NEXT: cincoffset $c11, $c11, -48 @@ -46,7 +42,7 @@ define dso_local i32 @_Z8do_catchv() local_unnamed_addr addrspace(200) uwtable p ; CHECK-NEXT: # %bb.1: ; CHECK-NEXT: move $16, $2 ; CHECK-NEXT: .LBB0_2: # %return -; CHECK-NEXT: move $2, $16 +; CHECK-NEXT: sll $2, $16, 0 ; CHECK-NEXT: clc $c17, $zero, 0($c11) # 16-byte Folded Reload ; CHECK-NEXT: clc $c18, $zero, 16($c11) # 16-byte Folded Reload ; CHECK-NEXT: cld $16, $zero, 32($c11) # 8-byte Folded Reload @@ -75,27 +71,29 @@ define dso_local i32 @_Z8do_catchv() local_unnamed_addr addrspace(200) uwtable p ; CHECK-NEXT: b .LBB0_2 ; CHECK-NEXT: nop entry: - %call = invoke i32 @_Z3foov() to label %return unwind label %lpad -lpad: - %0 = landingpad { i8 addrspace(200)*, i32 } - catch i8 addrspace(200)* bitcast (i8 addrspace(200)* addrspace(200)* @_ZTIi to i8 addrspace(200)*) - catch i8 addrspace(200)* null - %1 = extractvalue { i8 addrspace(200)*, i32 } %0, 0 - %2 = extractvalue { i8 addrspace(200)*, i32 } %0, 1 - %3 = tail call i32 @llvm.eh.typeid.for(i8* addrspacecast (i8 addrspace(200)* bitcast (i8 addrspace(200)* addrspace(200)* @_ZTIi to i8 addrspace(200)*) to i8*)) + %call = invoke noundef signext i32 @_Z3foov() + to label %return unwind label %lpad + +lpad: ; preds = %entry + %0 = landingpad { ptr addrspace(200), i32 } + catch ptr addrspace(200) @_ZTIi + catch ptr addrspace(200) null + %1 = extractvalue { ptr addrspace(200), i32 } %0, 0 + %2 = extractvalue { ptr addrspace(200), i32 } %0, 1 + %3 = tail call i32 @llvm.eh.typeid.for(ptr addrspacecast (ptr addrspace(200) @_ZTIi to ptr)) nounwind %matches = icmp eq i32 %2, %3 - %4 = tail call i8 addrspace(200)* @__cxa_begin_catch(i8 addrspace(200)* %1) nounwind + %4 = tail call ptr addrspace(200) @__cxa_begin_catch(ptr addrspace(200) %1) nounwind br i1 %matches, label %catch1, label %catch -catch1: +catch1: ; preds = %lpad tail call void @__cxa_end_catch() nounwind br label %return -catch: +catch: ; preds = %lpad tail call void @__cxa_end_catch() br label %return -return: +return: ; preds = %entry, %catch1, %catch %retval.0 = phi i32 [ 1, %catch1 ], [ 2, %catch ], [ %call, %entry ] ret i32 %retval.0 } @@ -106,14 +104,14 @@ declare dso_local i32 @__gxx_personality_v0(...) addrspace(200) declare i32 @llvm.eh.typeid.for(i8*) addrspace(200) nounwind readnone -declare dso_local i8 addrspace(200)* @__cxa_begin_catch(i8 addrspace(200)*) local_unnamed_addr addrspace(200) +declare dso_local ptr addrspace(200) @__cxa_begin_catch(ptr addrspace(200)) local_unnamed_addr addrspace(200) declare dso_local void @__cxa_end_catch() local_unnamed_addr addrspace(200) ; UTC_ARGS: --disable ; CHECK: .Lfunc_end0: ; CHECK-NEXT: .size _Z8do_catchv, .Lfunc_end0-_Z8do_catchv -; CHECK-NEXT: .size .L_Z8do_catchv$eh_alias, .Lfunc_end0-_Z8do_catchv +; CHECK-NEXT: .size .L_Z8do_catchv$local, .Lfunc_end0-_Z8do_catchv ; CHECK: GCC_except_table0: ; CHECK-NEXT: .Lexception0: @@ -130,7 +128,7 @@ declare dso_local void @__cxa_end_catch() local_unnamed_addr addrspace(200) ; Note: RISC-V uses DW_EH_PE_udata4, so the 0xc marker uses 4 bytes instead of 1 ; CHECK-NEXT: [[SMALL_CS_DIRECTIVE:(\.byte)|(\.word)]] 12 # (landing pad is a capability) ; Note: the following line should not be using _Z8do_catchv, but a local alias -; CHECK-NEXT: .chericap .L_Z8do_catchv$eh_alias + .Ltmp2-.Lfunc_begin0 # jumps to .Ltmp2 +; CHECK-NEXT: .chericap .L_Z8do_catchv$local + .Ltmp2-.Lfunc_begin0 # jumps to .Ltmp2 ; CHECK-NEXT: .byte 3 # On action: 2 ; CHECK-NEXT: [[CS_DIRECTIVE]] .Ltmp1-.Lfunc_begin0 # >> Call Site 2 << ; CHECK-NEXT: [[CS_DIRECTIVE]] .Lfunc_end0-.Ltmp1 # Call between .Ltmp1 and .Lfunc_end0 @@ -157,13 +155,13 @@ declare dso_local void @__cxa_end_catch() local_unnamed_addr addrspace(200) ; RELOCS-LABEL: Relocations [ ; RELOCS-LABEL: Section ({{.+}}) .rela.gcc_except_table { -; RELOCS-NEXT: R_MIPS_CHERI_CAPABILITY/R_MIPS_NONE/R_MIPS_NONE .L_Z8do_catchv$eh_alias 0x4C +; RELOCS-NEXT: R_MIPS_CHERI_CAPABILITY/R_MIPS_NONE/R_MIPS_NONE .L_Z8do_catchv$local 0x4C ; RELOCS-NEXT: R_MIPS_PC32/R_MIPS_NONE/R_MIPS_NONE .L_ZTIi.DW.stub 0x0 ; RELOCS-NEXT: } ; The local alias should have the same type and non-zero size as the real function: ; RELOCS: Symbol { -; RELOCS-LABEL: Name: .L_Z8do_catchv$eh_alias ( +; RELOCS-LABEL: Name: .L_Z8do_catchv$local ( ; RELOCS-NEXT: Value: 0x0 ; RELOCS-NEXT: Size: [[FN_SIZE:[1-9][0-9]*]] ; RELOCS-NEXT: Binding: Local (0x0) diff --git a/llvm/test/CodeGen/CHERI-Generic/RISCV32/landingpad-non-preemptible.ll b/llvm/test/CodeGen/CHERI-Generic/RISCV32/landingpad-non-preemptible.ll index 9b6af164849d..12bf3d033598 100644 --- a/llvm/test/CodeGen/CHERI-Generic/RISCV32/landingpad-non-preemptible.ll +++ b/llvm/test/CodeGen/CHERI-Generic/RISCV32/landingpad-non-preemptible.ll @@ -1,7 +1,7 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --scrub-attributes --version 2 ; DO NOT EDIT -- This file was generated from test/CodeGen/CHERI-Generic/Inputs/landingpad-non-preemptible.ll -; RUN: llc -mtriple=riscv32 --relocation-model=pic -target-abi il32pc64f -mattr=+xcheri,+cap-mode,+f < %s -o - | FileCheck %s -; RUN: llc -mtriple=riscv32 --relocation-model=pic -target-abi il32pc64f -mattr=+xcheri,+cap-mode,+f < %s -o - -filetype=obj | llvm-readobj --relocs --symbols - | FileCheck %s --check-prefix=RELOCS +; RUN: llc -mtriple=riscv32 --relocation-model=pic -target-abi il32pc64f -mattr=+xcheri,+cap-mode,+f --relocation-model=pic < %s -o - | FileCheck %s +; RUN: llc -mtriple=riscv32 --relocation-model=pic -target-abi il32pc64f -mattr=+xcheri,+cap-mode,+f --relocation-model=pic < %s -o - -filetype=obj | llvm-readobj --relocs --symbols - | FileCheck %s --check-prefix=RELOCS ; Capabilities for exception landing pads were using preemptible relocations such as ; .chericap foo + .Ltmp - .Lfunc_begin instead of using a local alias. ; https://github.com/CTSRD-CHERI/llvm-project/issues/512 @@ -17,12 +17,8 @@ ; } ; } -; UTC_ARGS: --disable -; CHECK: .type .L_Z8do_catchv$eh_alias,@function -; UTC_ARGS: --enable - -@_ZTIi = external dso_local addrspace(200) constant i8 addrspace(200)* -define dso_local i32 @_Z8do_catchv() local_unnamed_addr addrspace(200) uwtable personality i8 addrspace(200)* bitcast (i32 (...) addrspace(200)* @__gxx_personality_v0 to i8 addrspace(200)*) { +@_ZTIi = external dso_local addrspace(200) constant ptr addrspace(200) +define dso_local noundef signext i32 @_Z8do_catchv() local_unnamed_addr addrspace(200) #0 personality ptr addrspace(200) @__gxx_personality_v0 { ; CHECK-LABEL: _Z8do_catchv: ; CHECK: # %bb.0: # %entry ; CHECK-NEXT: cincoffset csp, csp, -32 @@ -59,27 +55,29 @@ define dso_local i32 @_Z8do_catchv() local_unnamed_addr addrspace(200) uwtable p ; CHECK-NEXT: ccall __cxa_end_catch ; CHECK-NEXT: j .LBB0_2 entry: - %call = invoke i32 @_Z3foov() to label %return unwind label %lpad -lpad: - %0 = landingpad { i8 addrspace(200)*, i32 } - catch i8 addrspace(200)* bitcast (i8 addrspace(200)* addrspace(200)* @_ZTIi to i8 addrspace(200)*) - catch i8 addrspace(200)* null - %1 = extractvalue { i8 addrspace(200)*, i32 } %0, 0 - %2 = extractvalue { i8 addrspace(200)*, i32 } %0, 1 - %3 = tail call i32 @llvm.eh.typeid.for(i8* addrspacecast (i8 addrspace(200)* bitcast (i8 addrspace(200)* addrspace(200)* @_ZTIi to i8 addrspace(200)*) to i8*)) + %call = invoke noundef signext i32 @_Z3foov() + to label %return unwind label %lpad + +lpad: ; preds = %entry + %0 = landingpad { ptr addrspace(200), i32 } + catch ptr addrspace(200) @_ZTIi + catch ptr addrspace(200) null + %1 = extractvalue { ptr addrspace(200), i32 } %0, 0 + %2 = extractvalue { ptr addrspace(200), i32 } %0, 1 + %3 = tail call i32 @llvm.eh.typeid.for(ptr addrspacecast (ptr addrspace(200) @_ZTIi to ptr)) nounwind %matches = icmp eq i32 %2, %3 - %4 = tail call i8 addrspace(200)* @__cxa_begin_catch(i8 addrspace(200)* %1) nounwind + %4 = tail call ptr addrspace(200) @__cxa_begin_catch(ptr addrspace(200) %1) nounwind br i1 %matches, label %catch1, label %catch -catch1: +catch1: ; preds = %lpad tail call void @__cxa_end_catch() nounwind br label %return -catch: +catch: ; preds = %lpad tail call void @__cxa_end_catch() br label %return -return: +return: ; preds = %entry, %catch1, %catch %retval.0 = phi i32 [ 1, %catch1 ], [ 2, %catch ], [ %call, %entry ] ret i32 %retval.0 } @@ -90,14 +88,14 @@ declare dso_local i32 @__gxx_personality_v0(...) addrspace(200) declare i32 @llvm.eh.typeid.for(i8*) addrspace(200) nounwind readnone -declare dso_local i8 addrspace(200)* @__cxa_begin_catch(i8 addrspace(200)*) local_unnamed_addr addrspace(200) +declare dso_local ptr addrspace(200) @__cxa_begin_catch(ptr addrspace(200)) local_unnamed_addr addrspace(200) declare dso_local void @__cxa_end_catch() local_unnamed_addr addrspace(200) ; UTC_ARGS: --disable ; CHECK: .Lfunc_end0: ; CHECK-NEXT: .size _Z8do_catchv, .Lfunc_end0-_Z8do_catchv -; CHECK-NEXT: .size .L_Z8do_catchv$eh_alias, .Lfunc_end0-_Z8do_catchv +; CHECK-NEXT: .size .L_Z8do_catchv$local, .Lfunc_end0-_Z8do_catchv ; CHECK: GCC_except_table0: ; CHECK-NEXT: .Lexception0: @@ -114,7 +112,7 @@ declare dso_local void @__cxa_end_catch() local_unnamed_addr addrspace(200) ; Note: RISC-V uses DW_EH_PE_udata4, so the 0xc marker uses 4 bytes instead of 1 ; CHECK-NEXT: [[SMALL_CS_DIRECTIVE:(\.byte)|(\.word)]] 12 # (landing pad is a capability) ; Note: the following line should not be using _Z8do_catchv, but a local alias -; CHECK-NEXT: .chericap .L_Z8do_catchv$eh_alias + .Ltmp2-.Lfunc_begin0 # jumps to .Ltmp2 +; CHECK-NEXT: .chericap .L_Z8do_catchv$local + .Ltmp2-.Lfunc_begin0 # jumps to .Ltmp2 ; CHECK-NEXT: .byte 3 # On action: 2 ; CHECK-NEXT: [[CS_DIRECTIVE]] .Ltmp1-.Lfunc_begin0 # >> Call Site 2 << ; CHECK-NEXT: [[CS_DIRECTIVE]] .Lfunc_end0-.Ltmp1 # Call between .Ltmp1 and .Lfunc_end0 @@ -145,7 +143,7 @@ declare dso_local void @__cxa_end_catch() local_unnamed_addr addrspace(200) ; RELOCS-NEXT: R_RISCV_SUB32 0x0 ; RELOCS-NEXT: R_RISCV_ADD32 0x0 ; RELOCS-NEXT: R_RISCV_SUB32 0x0 -; RELOCS-NEXT: R_RISCV_CHERI_CAPABILITY .L_Z8do_catchv$eh_alias 0x34 +; RELOCS-NEXT: R_RISCV_CHERI_CAPABILITY .L_Z8do_catchv$local 0x34 ; RELOCS-NEXT: R_RISCV_ADD32 0x0 ; RELOCS-NEXT: R_RISCV_SUB32 0x0 ; RELOCS-NEXT: R_RISCV_ADD32 0x0 @@ -155,7 +153,7 @@ declare dso_local void @__cxa_end_catch() local_unnamed_addr addrspace(200) ; The local alias should have the same type and non-zero size as the real function: ; RELOCS: Symbol { -; RELOCS-LABEL: Name: .L_Z8do_catchv$eh_alias ( +; RELOCS-LABEL: Name: .L_Z8do_catchv$local ( ; RELOCS-NEXT: Value: 0x0 ; RELOCS-NEXT: Size: [[FN_SIZE:[1-9][0-9]*]] ; RELOCS-NEXT: Binding: Local (0x0) diff --git a/llvm/test/CodeGen/CHERI-Generic/RISCV64/landingpad-non-preemptible.ll b/llvm/test/CodeGen/CHERI-Generic/RISCV64/landingpad-non-preemptible.ll index c1b9bcd22ff1..e3ecc26598d3 100644 --- a/llvm/test/CodeGen/CHERI-Generic/RISCV64/landingpad-non-preemptible.ll +++ b/llvm/test/CodeGen/CHERI-Generic/RISCV64/landingpad-non-preemptible.ll @@ -1,7 +1,7 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --scrub-attributes --version 2 ; DO NOT EDIT -- This file was generated from test/CodeGen/CHERI-Generic/Inputs/landingpad-non-preemptible.ll -; RUN: llc -mtriple=riscv64 --relocation-model=pic -target-abi l64pc128d -mattr=+xcheri,+cap-mode,+f,+d < %s -o - | FileCheck %s -; RUN: llc -mtriple=riscv64 --relocation-model=pic -target-abi l64pc128d -mattr=+xcheri,+cap-mode,+f,+d < %s -o - -filetype=obj | llvm-readobj --relocs --symbols - | FileCheck %s --check-prefix=RELOCS +; RUN: llc -mtriple=riscv64 --relocation-model=pic -target-abi l64pc128d -mattr=+xcheri,+cap-mode,+f,+d --relocation-model=pic < %s -o - | FileCheck %s +; RUN: llc -mtriple=riscv64 --relocation-model=pic -target-abi l64pc128d -mattr=+xcheri,+cap-mode,+f,+d --relocation-model=pic < %s -o - -filetype=obj | llvm-readobj --relocs --symbols - | FileCheck %s --check-prefix=RELOCS ; Capabilities for exception landing pads were using preemptible relocations such as ; .chericap foo + .Ltmp - .Lfunc_begin instead of using a local alias. ; https://github.com/CTSRD-CHERI/llvm-project/issues/512 @@ -17,12 +17,8 @@ ; } ; } -; UTC_ARGS: --disable -; CHECK: .type .L_Z8do_catchv$eh_alias,@function -; UTC_ARGS: --enable - -@_ZTIi = external dso_local addrspace(200) constant i8 addrspace(200)* -define dso_local i32 @_Z8do_catchv() local_unnamed_addr addrspace(200) uwtable personality i8 addrspace(200)* bitcast (i32 (...) addrspace(200)* @__gxx_personality_v0 to i8 addrspace(200)*) { +@_ZTIi = external dso_local addrspace(200) constant ptr addrspace(200) +define dso_local noundef signext i32 @_Z8do_catchv() local_unnamed_addr addrspace(200) #0 personality ptr addrspace(200) @__gxx_personality_v0 { ; CHECK-LABEL: _Z8do_catchv: ; CHECK: # %bb.0: # %entry ; CHECK-NEXT: cincoffset csp, csp, -48 @@ -59,27 +55,29 @@ define dso_local i32 @_Z8do_catchv() local_unnamed_addr addrspace(200) uwtable p ; CHECK-NEXT: ccall __cxa_end_catch ; CHECK-NEXT: j .LBB0_2 entry: - %call = invoke i32 @_Z3foov() to label %return unwind label %lpad -lpad: - %0 = landingpad { i8 addrspace(200)*, i32 } - catch i8 addrspace(200)* bitcast (i8 addrspace(200)* addrspace(200)* @_ZTIi to i8 addrspace(200)*) - catch i8 addrspace(200)* null - %1 = extractvalue { i8 addrspace(200)*, i32 } %0, 0 - %2 = extractvalue { i8 addrspace(200)*, i32 } %0, 1 - %3 = tail call i32 @llvm.eh.typeid.for(i8* addrspacecast (i8 addrspace(200)* bitcast (i8 addrspace(200)* addrspace(200)* @_ZTIi to i8 addrspace(200)*) to i8*)) + %call = invoke noundef signext i32 @_Z3foov() + to label %return unwind label %lpad + +lpad: ; preds = %entry + %0 = landingpad { ptr addrspace(200), i32 } + catch ptr addrspace(200) @_ZTIi + catch ptr addrspace(200) null + %1 = extractvalue { ptr addrspace(200), i32 } %0, 0 + %2 = extractvalue { ptr addrspace(200), i32 } %0, 1 + %3 = tail call i32 @llvm.eh.typeid.for(ptr addrspacecast (ptr addrspace(200) @_ZTIi to ptr)) nounwind %matches = icmp eq i32 %2, %3 - %4 = tail call i8 addrspace(200)* @__cxa_begin_catch(i8 addrspace(200)* %1) nounwind + %4 = tail call ptr addrspace(200) @__cxa_begin_catch(ptr addrspace(200) %1) nounwind br i1 %matches, label %catch1, label %catch -catch1: +catch1: ; preds = %lpad tail call void @__cxa_end_catch() nounwind br label %return -catch: +catch: ; preds = %lpad tail call void @__cxa_end_catch() br label %return -return: +return: ; preds = %entry, %catch1, %catch %retval.0 = phi i32 [ 1, %catch1 ], [ 2, %catch ], [ %call, %entry ] ret i32 %retval.0 } @@ -90,14 +88,14 @@ declare dso_local i32 @__gxx_personality_v0(...) addrspace(200) declare i32 @llvm.eh.typeid.for(i8*) addrspace(200) nounwind readnone -declare dso_local i8 addrspace(200)* @__cxa_begin_catch(i8 addrspace(200)*) local_unnamed_addr addrspace(200) +declare dso_local ptr addrspace(200) @__cxa_begin_catch(ptr addrspace(200)) local_unnamed_addr addrspace(200) declare dso_local void @__cxa_end_catch() local_unnamed_addr addrspace(200) ; UTC_ARGS: --disable ; CHECK: .Lfunc_end0: ; CHECK-NEXT: .size _Z8do_catchv, .Lfunc_end0-_Z8do_catchv -; CHECK-NEXT: .size .L_Z8do_catchv$eh_alias, .Lfunc_end0-_Z8do_catchv +; CHECK-NEXT: .size .L_Z8do_catchv$local, .Lfunc_end0-_Z8do_catchv ; CHECK: GCC_except_table0: ; CHECK-NEXT: .Lexception0: @@ -114,7 +112,7 @@ declare dso_local void @__cxa_end_catch() local_unnamed_addr addrspace(200) ; Note: RISC-V uses DW_EH_PE_udata4, so the 0xc marker uses 4 bytes instead of 1 ; CHECK-NEXT: [[SMALL_CS_DIRECTIVE:(\.byte)|(\.word)]] 12 # (landing pad is a capability) ; Note: the following line should not be using _Z8do_catchv, but a local alias -; CHECK-NEXT: .chericap .L_Z8do_catchv$eh_alias + .Ltmp2-.Lfunc_begin0 # jumps to .Ltmp2 +; CHECK-NEXT: .chericap .L_Z8do_catchv$local + .Ltmp2-.Lfunc_begin0 # jumps to .Ltmp2 ; CHECK-NEXT: .byte 3 # On action: 2 ; CHECK-NEXT: [[CS_DIRECTIVE]] .Ltmp1-.Lfunc_begin0 # >> Call Site 2 << ; CHECK-NEXT: [[CS_DIRECTIVE]] .Lfunc_end0-.Ltmp1 # Call between .Ltmp1 and .Lfunc_end0 @@ -145,7 +143,7 @@ declare dso_local void @__cxa_end_catch() local_unnamed_addr addrspace(200) ; RELOCS-NEXT: R_RISCV_SUB32 0x0 ; RELOCS-NEXT: R_RISCV_ADD32 0x0 ; RELOCS-NEXT: R_RISCV_SUB32 0x0 -; RELOCS-NEXT: R_RISCV_CHERI_CAPABILITY .L_Z8do_catchv$eh_alias 0x34 +; RELOCS-NEXT: R_RISCV_CHERI_CAPABILITY .L_Z8do_catchv$local 0x34 ; RELOCS-NEXT: R_RISCV_ADD32 0x0 ; RELOCS-NEXT: R_RISCV_SUB32 0x0 ; RELOCS-NEXT: R_RISCV_ADD32 0x0 @@ -155,7 +153,7 @@ declare dso_local void @__cxa_end_catch() local_unnamed_addr addrspace(200) ; The local alias should have the same type and non-zero size as the real function: ; RELOCS: Symbol { -; RELOCS-LABEL: Name: .L_Z8do_catchv$eh_alias ( +; RELOCS-LABEL: Name: .L_Z8do_catchv$local ( ; RELOCS-NEXT: Value: 0x0 ; RELOCS-NEXT: Size: [[FN_SIZE:[1-9][0-9]*]] ; RELOCS-NEXT: Binding: Local (0x0) diff --git a/llvm/test/CodeGen/RISCV/cheri/function-start-directives.ll b/llvm/test/CodeGen/RISCV/cheri/function-start-directives.ll new file mode 100644 index 000000000000..ad5573fd1fad --- /dev/null +++ b/llvm/test/CodeGen/RISCV/cheri/function-start-directives.ll @@ -0,0 +1,56 @@ +;; Check that the directives at the start of the function are emitted in a sensible order +; RUN: %riscv64_cheri_purecap_llc -relocation-model=pic < %s | FileCheck %s +; RUN: %riscv64_cheri_purecap_llc -relocation-model=static < %s | FileCheck %s + +target triple = "riscv64-unknown-freebsd13" + +define noundef signext i32 @_Z4testv() local_unnamed_addr addrspace(200) uwtable personality ptr addrspace(200) @__gxx_personality_v0 { +entry: + %call = invoke noundef signext i32 @_Z3foov(ptr addrspace(200) @_Z4testv) + to label %return unwind label %lpad + +lpad: ; preds = %entry + %0 = landingpad { ptr addrspace(200), i32 } + catch ptr addrspace(200) null + %1 = extractvalue { ptr addrspace(200), i32 } %0, 0 + %2 = tail call ptr addrspace(200) @__cxa_begin_catch(ptr addrspace(200) %1) #2 + tail call void @__cxa_end_catch() + br label %return + +return: ; preds = %entry, %lpad + %retval.0 = phi i32 [ 3, %lpad ], [ %call, %entry ] + ret i32 %retval.0 +} + +declare dso_local noundef signext i32 @_Z3foov(ptr addrspace(200)) local_unnamed_addr addrspace(200) + +declare dso_local i32 @__gxx_personality_v0(...) addrspace(200) + +declare dso_local ptr addrspace(200) @__cxa_begin_catch(ptr addrspace(200)) local_unnamed_addr addrspace(200) + +declare dso_local void @__cxa_end_catch() local_unnamed_addr addrspace(200) + +; CHECK: .text +; CHECK-NEXT: .attribute 4, 16 +; CHECK-NEXT: .attribute 5, "rv64i2p1_xcheri0p0" +; CHECK-NEXT: .file "" +; CHECK-NEXT: .globl _Z4testv # -- Begin function _Z4testv +; CHECK-NEXT: .p2align 2 +; CHECK-NEXT: .type _Z4testv,@function +; CHECK-NEXT: _Z4testv: # @_Z4testv +; CHECK-NEXT: .L_Z4testv$local: +; CHECK-NEXT: .type .L_Z4testv$local,@function +; CHECK-NEXT: .Lfunc_begin0: +; CHECK-NEXT: .cfi_startproc +; CHECK-NEXT: .cfi_personality 155, DW.ref.__gxx_personality_v0 +; CHECK-NEXT: .cfi_lsda 27, .Lexception0 +; CHECK-NEXT: # %bb.0: # %entry + +; CHECK: .Lfunc_end0: +; CHECK-NEXT: .size _Z4testv, .Lfunc_end0-_Z4testv +; CHECK-NEXT: .size .L_Z4testv$local, .Lfunc_end0-_Z4testv +; CHECK-NEXT: .cfi_endproc + +; CHECK: .section .gcc_except_table +; CHECK: .word 12 # (landing pad is a capability) +; CHECK-NEXT: .chericap .L_Z4testv$local + .Ltmp2-.Lfunc_begin0 # jumps to .Ltmp2 diff --git a/llvm/utils/UpdateTestChecks/asm.py b/llvm/utils/UpdateTestChecks/asm.py index 383f8704b701..e59dbdef158b 100644 --- a/llvm/utils/UpdateTestChecks/asm.py +++ b/llvm/utils/UpdateTestChecks/asm.py @@ -79,6 +79,8 @@ class string: ASM_FUNCTION_MIPS_RE = re.compile( r'^_?(?P[^:]+):[ \t]*#+[ \t]*@"?(?P=func)"?\n[^:]*?' # f: (name of func) + r"(?:\s*\.?L(?P=func)\$local:\n)?" # optional .L$local: due to -fno-semantic-interposition + r"(?:\s*\.type\s+\.?L(?P=func)\$local,@function\n)?" # optional .type .L$local r"(?:\s*\.?Ltmp[^:\n]*:\n)?[^:]*?" # optional .Ltmp for EH r"(?:^[ \t]+\.(frame|f?mask|set).*?\n)+" # Mips+LLVM standard asm prologue r"(?P.*?)\n" # (body of the function) @@ -117,7 +119,7 @@ class string: ASM_FUNCTION_RISCV_RE = re.compile( r'^_?(?P[^:]+):[ \t]*#+[ \t]*@"?(?P=func)"?\n' - r"(?:\s*\.?L(?P=func)\$eh_alias:\n)?" # optional .L$eh_alias: due to CHERI EH + r"(?:\s*\.?L(?P=func)\$jump_table_base:\n)?" # optional .L$jump_table_base: due to CHERI jump tables r"(?:\s*\.?L(?P=func)\$local:\n)?" # optional .L$local: due to -fno-semantic-interposition r"(?:\s*\.type\s+\.?L(?P=func)\$local,@function\n)?" # optional .type .L$local r"(?:\s*\.?Lfunc_begin[^:\n]*:\n)?[^:]*?"