// This test checks that we emit unwind info correctly for epilogs that: // 1. mirror the prolog; or // 2. are subsequence at the end of the prolog; or // 3. neither of above two. // in the same segment. // RUN: llvm-mc -triple aarch64-pc-win32 -filetype=obj %s -o %t.o // RUN: llvm-readobj -S -r -u %t.o | FileCheck %s // CHECK: Section { // CHECK: Number: 4 // CHECK-NEXT: Name: .xdata (2E 78 64 61 74 61 00 00) // CHECK-NEXT: VirtualSize: 0x0 // CHECK-NEXT: VirtualAddress: 0x0 // CHECK-NEXT: RawDataSize: 80 // CHECK-NEXT: PointerToRawData: 0x1251AC // CHECK-NEXT: PointerToRelocations: 0x0 // CHECK-NEXT: PointerToLineNumbers: 0x0 // CHECK-NEXT: RelocationCount: 0 // CHECK-NEXT: LineNumberCount: 0 // CHECK-NEXT: Characteristics [ (0x40300040) // CHECK-NEXT: IMAGE_SCN_ALIGN_4BYTES (0x300000) // CHECK-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA (0x40) // CHECK-NEXT: IMAGE_SCN_MEM_READ (0x40000000) // CHECK-NEXT: ] // CHECK-NEXT: } // CHECK-NEXT: Section { // CHECK-NEXT: Number: 5 // CHECK-NEXT: Name: .pdata (2E 70 64 61 74 61 00 00) // CHECK-NEXT: VirtualSize: 0x0 // CHECK-NEXT: VirtualAddress: 0x0 // CHECK-NEXT: RawDataSize: 16 // CHECK-NEXT: PointerToRawData: 0x1251FC // CHECK-NEXT: PointerToRelocations: 0x12520C // CHECK-NEXT: PointerToLineNumbers: 0x0 // CHECK-NEXT: RelocationCount: 4 // CHECK-NEXT: LineNumberCount: 0 // CHECK-NEXT: Characteristics [ (0x40300040) // CHECK-NEXT: IMAGE_SCN_ALIGN_4BYTES (0x300000) // CHECK-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA (0x40) // CHECK-NEXT: IMAGE_SCN_MEM_READ (0x40000000) // CHECK-NEXT: ] // CHECK-NEXT: } // CHECK-NEXT:] // CHECK-LABEL:Relocations [ // CHECK-NEXT: Section (1) .text { // CHECK-NEXT: 0x94 IMAGE_REL_ARM64_BRANCH26 foo (12) // CHECK-NEXT: 0x125068 IMAGE_REL_ARM64_BRANCH26 foo (12) // CHECK-NEXT: } // CHECK-NEXT: Section (5) .pdata { // CHECK-NEXT: 0x0 IMAGE_REL_ARM64_ADDR32NB .text (0) // CHECK-NEXT: 0x4 IMAGE_REL_ARM64_ADDR32NB .xdata (7) // CHECK-NEXT: 0x8 IMAGE_REL_ARM64_ADDR32NB .text (0) // CHECK-NEXT: 0xC IMAGE_REL_ARM64_ADDR32NB .xdata (7) // CHECK-NEXT: } // CHECK-NEXT:] // CHECK-LABEL:UnwindInformation [ // CHECK-NEXT: RuntimeFunction { // CHECK-NEXT: Function: multi_epilog (0x0) // CHECK-NEXT: ExceptionRecord: .xdata (0x0) // CHECK-NEXT: ExceptionData { // CHECK-NEXT: FunctionLength: 1048572 // CHECK-NEXT: Version: 0 // CHECK-NEXT: ExceptionData: No // CHECK-NEXT: EpiloguePacked: No // CHECK-NEXT: EpilogueScopes: 3 // CHECK-NEXT: ByteCodeLength: 24 // CHECK-NEXT: Prologue [ // CHECK-NEXT: 0xe1 ; mov fp, sp // CHECK-NEXT: 0xca16 ; stp x27, x28, [sp, #176] // CHECK-NEXT: 0xc998 ; stp x25, x26, [sp, #192] // CHECK-NEXT: 0xc91a ; stp x23, x24, [sp, #208] // CHECK-NEXT: 0xc89c ; stp x21, x22, [sp, #224] // CHECK-NEXT: 0xc81e ; stp x19, x20, [sp, #240] // CHECK-NEXT: 0x9f ; stp x29, x30, [sp, #-256]! // CHECK-NEXT: 0xe4 ; end // CHECK-NEXT: ] // CHECK-NEXT: EpilogueScopes [ // CHECK-NEXT: EpilogueScope { // CHECK-NEXT: StartOffset: 38 // CHECK-NEXT: EpilogueStartIndex: 0 // CHECK-NEXT: Opcodes [ // CHECK-NEXT: 0xe1 ; mov sp, fp // CHECK-NEXT: 0xca16 ; ldp x27, x28, [sp, #176] // CHECK-NEXT: 0xc998 ; ldp x25, x26, [sp, #192] // CHECK-NEXT: 0xc91a ; ldp x23, x24, [sp, #208] // CHECK-NEXT: 0xc89c ; ldp x21, x22, [sp, #224] // CHECK-NEXT: 0xc81e ; ldp x19, x20, [sp, #240] // CHECK-NEXT: 0x9f ; ldp x29, x30, [sp], #256 // CHECK-NEXT: 0xe4 ; end // CHECK-NEXT: ] // CHECK-NEXT: } // CHECK-NEXT: EpilogueScope { // CHECK-NEXT: StartOffset: 46 // CHECK-NEXT: EpilogueStartIndex: 3 // CHECK-NEXT: Opcodes [ // CHECK-NEXT: 0xc998 ; ldp x25, x26, [sp, #192] // CHECK-NEXT: 0xc91a ; ldp x23, x24, [sp, #208] // CHECK-NEXT: 0xc89c ; ldp x21, x22, [sp, #224] // CHECK-NEXT: 0xc81e ; ldp x19, x20, [sp, #240] // CHECK-NEXT: 0x9f ; ldp x29, x30, [sp], #256 // CHECK-NEXT: 0xe4 ; end // CHECK-NEXT: ] // CHECK-NEXT: } // CHECK-NEXT: EpilogueScope { // CHECK-NEXT: StartOffset: 52 // CHECK-NEXT: EpilogueStartIndex: 13 // CHECK-NEXT: Opcodes [ // CHECK-NEXT: 0xe1 ; mov sp, fp // CHECK-NEXT: 0xc91a ; ldp x23, x24, [sp, #208] // CHECK-NEXT: 0xc89c ; ldp x21, x22, [sp, #224] // CHECK-NEXT: 0xc81e ; ldp x19, x20, [sp, #240] // CHECK-NEXT: 0x9f ; ldp x29, x30, [sp], #256 // CHECK-NEXT: 0xe4 ; end // CHECK-NEXT: ] // CHECK-NEXT: } // CHECK-NEXT: ] // CHECK-NEXT: } // CHECK-NEXT: } // CHECK-NEXT: RuntimeFunction { // CHECK-NEXT: Function: multi_epilog +0xFFFFC (0xFFFFC) // CHECK-NEXT: ExceptionRecord: .xdata +0x28 (0x28) // CHECK-NEXT: ExceptionData { // CHECK-NEXT: FunctionLength: 151744 // CHECK-NEXT: Version: 0 // CHECK-NEXT: ExceptionData: No // CHECK-NEXT: EpiloguePacked: No // CHECK-NEXT: EpilogueScopes: 3 // CHECK-NEXT: ByteCodeLength: 24 // CHECK-NEXT: Prologue [ // CHECK-NEXT: 0xe5 ; end_c // CHECK-NEXT: 0xe1 ; mov fp, sp // CHECK-NEXT: 0xca16 ; stp x27, x28, [sp, #176] // CHECK-NEXT: 0xc998 ; stp x25, x26, [sp, #192] // CHECK-NEXT: 0xc91a ; stp x23, x24, [sp, #208] // CHECK-NEXT: 0xc89c ; stp x21, x22, [sp, #224] // CHECK-NEXT: 0xc81e ; stp x19, x20, [sp, #240] // CHECK-NEXT: 0x9f ; stp x29, x30, [sp, #-256]! // CHECK-NEXT: 0xe4 ; end // CHECK-NEXT: ] // CHECK-NEXT: EpilogueScopes [ // CHECK-NEXT: EpilogueScope { // CHECK-NEXT: StartOffset: 37916 // CHECK-NEXT: EpilogueStartIndex: 1 // CHECK-NEXT: Opcodes [ // CHECK-NEXT: 0xe1 ; mov sp, fp // CHECK-NEXT: 0xca16 ; ldp x27, x28, [sp, #176] // CHECK-NEXT: 0xc998 ; ldp x25, x26, [sp, #192] // CHECK-NEXT: 0xc91a ; ldp x23, x24, [sp, #208] // CHECK-NEXT: 0xc89c ; ldp x21, x22, [sp, #224] // CHECK-NEXT: 0xc81e ; ldp x19, x20, [sp, #240] // CHECK-NEXT: 0x9f ; ldp x29, x30, [sp], #256 // CHECK-NEXT: 0xe4 ; end // CHECK-NEXT: ] // CHECK-NEXT: } // CHECK-NEXT: EpilogueScope { // CHECK-NEXT: StartOffset: 37924 // CHECK-NEXT: EpilogueStartIndex: 4 // CHECK-NEXT: Opcodes [ // CHECK-NEXT: 0xc998 ; ldp x25, x26, [sp, #192] // CHECK-NEXT: 0xc91a ; ldp x23, x24, [sp, #208] // CHECK-NEXT: 0xc89c ; ldp x21, x22, [sp, #224] // CHECK-NEXT: 0xc81e ; ldp x19, x20, [sp, #240] // CHECK-NEXT: 0x9f ; ldp x29, x30, [sp], #256 // CHECK-NEXT: 0xe4 ; end // CHECK-NEXT: ] // CHECK-NEXT: } // CHECK-NEXT: EpilogueScope { // CHECK-NEXT: StartOffset: 37930 // CHECK-NEXT: EpilogueStartIndex: 14 // CHECK-NEXT: Opcodes [ // CHECK-NEXT: 0xe1 ; mov sp, fp // CHECK-NEXT: 0xc91a ; ldp x23, x24, [sp, #208] // CHECK-NEXT: 0xc89c ; ldp x21, x22, [sp, #224] // CHECK-NEXT: 0xc81e ; ldp x19, x20, [sp, #240] // CHECK-NEXT: 0x9f ; ldp x29, x30, [sp], #256 // CHECK-NEXT: 0xe4 ; end // CHECK-NEXT: ] // CHECK-NEXT: } // CHECK-NEXT: ] // CHECK-NEXT: } // CHECK-NEXT: } // CHECK-NEXT:] .text .global multi_epilog .p2align 2 .seh_proc multi_epilog multi_epilog: stp x29, lr, [sp, #-256]! .seh_save_fplr_x 256 stp x19, x20, [sp, #240] .seh_save_regp x19, 240 stp x21, x22, [sp, #224] .seh_save_regp x21, 224 stp x23, x24, [sp, #208] .seh_save_regp x23, 208 stp x25, x26, [sp, #192] .seh_save_regp x25, 192 stp x27, x28, [sp, #176] .seh_save_regp x27, 176 mov x29, fp .seh_set_fp .seh_endprologue .rept 30 nop .endr bl foo // Epilogs 1, 2 and 3 are in the same segment as prolog. // epilog1 - mirroring prolog .seh_startepilogue mov sp, x29 .seh_set_fp stp x27, x28, [sp, #176] .seh_save_regp x27, 176 stp x25, x26, [sp, #192] .seh_save_regp x25, 192 stp x23, x24, [sp, #208] .seh_save_regp x23, 208 stp x21, x22, [sp, #224] .seh_save_regp x21, 224 ldp x19, x20, [sp, #240] .seh_save_regp x19, 240 ldp x29, lr, [sp], #256 .seh_save_fplr_x 256 .seh_endepilogue ret // epilog2 - a subsequence at the end of prolog, can use prolog's opcodes. .seh_startepilogue stp x25, x26, [sp, #192] .seh_save_regp x25, 192 stp x23, x24, [sp, #208] .seh_save_regp x23, 208 stp x21, x22, [sp, #224] .seh_save_regp x21, 224 ldp x19, x20, [sp, #240] .seh_save_regp x19, 240 ldp x29, lr, [sp], #256 .seh_save_fplr_x 256 .seh_endepilogue ret // epilog3 - cannot use prolog's opcode. .seh_startepilogue mov sp, x29 .seh_set_fp stp x23, x24, [sp, #208] .seh_save_regp x23, 208 stp x21, x22, [sp, #224] .seh_save_regp x21, 224 ldp x19, x20, [sp, #240] .seh_save_regp x19, 240 ldp x29, lr, [sp], #256 .seh_save_fplr_x 256 .seh_endepilogue ret .rept 300000 nop .endr bl foo // Epilogs below are in a segment without prolog // epilog4 - mirroring prolog, its start index should be 1, counting the end_c. .seh_startepilogue mov sp, x29 .seh_set_fp stp x27, x28, [sp, #176] .seh_save_regp x27, 176 stp x25, x26, [sp, #192] .seh_save_regp x25, 192 stp x23, x24, [sp, #208] .seh_save_regp x23, 208 stp x21, x22, [sp, #224] .seh_save_regp x21, 224 ldp x19, x20, [sp, #240] .seh_save_regp x19, 240 ldp x29, lr, [sp], #256 .seh_save_fplr_x 256 .seh_endepilogue ret // epilog5 - same as epilog2, its start index should be: 1 + epilog2's index. .seh_startepilogue stp x25, x26, [sp, #192] .seh_save_regp x25, 192 stp x23, x24, [sp, #208] .seh_save_regp x23, 208 stp x21, x22, [sp, #224] .seh_save_regp x21, 224 ldp x19, x20, [sp, #240] .seh_save_regp x19, 240 ldp x29, lr, [sp], #256 .seh_save_fplr_x 256 .seh_endepilogue ret // epilog6 - same as epilog3, cannot use prolog's opcode. Again its start index // should be: 1 + epilog3's index. .seh_startepilogue mov sp, x29 .seh_set_fp stp x23, x24, [sp, #208] .seh_save_regp x23, 208 stp x21, x22, [sp, #224] .seh_save_regp x21, 224 ldp x19, x20, [sp, #240] .seh_save_regp x19, 240 ldp x29, lr, [sp], #256 .seh_save_fplr_x 256 .seh_endepilogue ret .seh_endfunclet .seh_endproc