325 lines
10 KiB
ArmAsm
325 lines
10 KiB
ArmAsm
// This test checks that the SEH directives emit the correct unwind data.
|
|
|
|
// RUN: llvm-mc -triple thumbv7-pc-win32 -filetype=obj %s | llvm-readobj -S -r -u - | FileCheck %s
|
|
|
|
// Check that the output assembler directives also can be parsed, and
|
|
// that they produce equivalent output:
|
|
|
|
// RUN: llvm-mc -triple thumbv7-pc-win32 -filetype=asm %s | llvm-mc -triple thumbv7-pc-win32 -filetype=obj - | llvm-readobj -S -r -u - | FileCheck %s
|
|
|
|
// CHECK: Sections [
|
|
// CHECK: Section {
|
|
// CHECK: Name: .text
|
|
// CHECK: RelocationCount: 1
|
|
// CHECK: Characteristics [
|
|
// CHECK-NEXT: ALIGN_4BYTES
|
|
// CHECK-NEXT: CNT_CODE
|
|
// CHECK-NEXT: MEM_16BIT
|
|
// CHECK-NEXT: MEM_EXECUTE
|
|
// CHECK-NEXT: MEM_PURGEABLE
|
|
// CHECK-NEXT: MEM_READ
|
|
// CHECK-NEXT: ]
|
|
// CHECK-NEXT: }
|
|
// CHECK: Section {
|
|
// CHECK: Name: .xdata
|
|
// CHECK: RawDataSize: 100
|
|
// CHECK: RelocationCount: 1
|
|
// CHECK: Characteristics [
|
|
// CHECK-NEXT: ALIGN_4BYTES
|
|
// CHECK-NEXT: CNT_INITIALIZED_DATA
|
|
// CHECK-NEXT: MEM_READ
|
|
// CHECK-NEXT: ]
|
|
// CHECK-NEXT: }
|
|
// CHECK: Section {
|
|
// CHECK: Name: .pdata
|
|
// CHECK: RelocationCount: 10
|
|
// CHECK: Characteristics [
|
|
// CHECK-NEXT: ALIGN_4BYTES
|
|
// CHECK-NEXT: CNT_INITIALIZED_DATA
|
|
// CHECK-NEXT: MEM_READ
|
|
// CHECK-NEXT: ]
|
|
// CHECK-NEXT: }
|
|
// CHECK-NEXT: ]
|
|
|
|
// CHECK-NEXT: Relocations [
|
|
// CHECK-NEXT: Section (1) .text {
|
|
// CHECK-NEXT: 0x5C IMAGE_REL_ARM_BRANCH24T tailcall
|
|
// CHECK-NEXT: }
|
|
// CHECK-NEXT: Section (4) .xdata {
|
|
// CHECK-NEXT: 0x34 IMAGE_REL_ARM_ADDR32NB __C_specific_handler
|
|
// CHECK-NEXT: }
|
|
// CHECK-NEXT: Section (5) .pdata {
|
|
// CHECK-NEXT: 0x0 IMAGE_REL_ARM_ADDR32NB .text
|
|
// CHECK-NEXT: 0x4 IMAGE_REL_ARM_ADDR32NB .xdata
|
|
// CHECK-NEXT: 0x8 IMAGE_REL_ARM_ADDR32NB .text
|
|
// CHECK-NEXT: 0xC IMAGE_REL_ARM_ADDR32NB .xdata
|
|
// CHECK-NEXT: 0x10 IMAGE_REL_ARM_ADDR32NB .text
|
|
// CHECK-NEXT: 0x14 IMAGE_REL_ARM_ADDR32NB .xdata
|
|
// CHECK-NEXT: 0x18 IMAGE_REL_ARM_ADDR32NB .text
|
|
// CHECK-NEXT: 0x1C IMAGE_REL_ARM_ADDR32NB .xdata
|
|
// CHECK-NEXT: 0x20 IMAGE_REL_ARM_ADDR32NB .text
|
|
// CHECK-NEXT: 0x24 IMAGE_REL_ARM_ADDR32NB .xdata
|
|
// CHECK-NEXT: }
|
|
// CHECK-NEXT: ]
|
|
|
|
// CHECK-NEXT: UnwindInformation [
|
|
// CHECK-NEXT: RuntimeFunction {
|
|
// CHECK-NEXT: Function: func
|
|
// CHECK-NEXT: ExceptionRecord: .xdata
|
|
// CHECK-NEXT: ExceptionData {
|
|
// CHECK-NEXT: FunctionLength: 86
|
|
// CHECK: EpiloguePacked: Yes
|
|
// CHECK: Fragment: No
|
|
// CHECK: EpilogueOffset: 31
|
|
// CHECK: Prologue [
|
|
// CHECK-NEXT: 0xed 0xf8 ; push {r3-r7, lr}
|
|
// CHECK-NEXT: 0xf6 0x27 ; vpush {d18-d23}
|
|
// CHECK-NEXT: 0xf5 0x7e ; vpush {d7-d14}
|
|
// CHECK-NEXT: 0xfb ; nop
|
|
// CHECK-NEXT: 0xce ; mov r14, sp
|
|
// CHECK-NEXT: 0xe3 ; vpush {d8-d11}
|
|
// CHECK-NEXT: 0xe6 ; vpush {d8-d14}
|
|
// CHECK-NEXT: 0xed 0xf8 ; push {r3-r7, lr}
|
|
// CHECK-NEXT: 0xbd 0x50 ; push.w {r4, r6, r8, r10-r12, lr}
|
|
// CHECK-NEXT: 0xd7 ; push {r4-r7, lr}
|
|
// CHECK-NEXT: 0xdd ; push.w {r4-r9, lr}
|
|
// CHECK-NEXT: 0xfa 0x01 0x00 0x00 ; sub.w sp, sp, #(65536 * 4)
|
|
// CHECK-NEXT: 0xfc ; nop.w
|
|
// CHECK-NEXT: 0xfc ; nop.w
|
|
// CHECK-NEXT: 0xf9 0x04 0x00 ; sub.w sp, sp, #(1024 * 4)
|
|
// CHECK-NEXT: 0xe8 0x80 ; sub.w sp, #(128 * 4)
|
|
// CHECK-NEXT: 0xe8 0x80 ; sub.w sp, #(128 * 4)
|
|
// CHECK-NEXT: 0x06 ; sub sp, #(6 * 4)
|
|
// CHECK-NEXT: ]
|
|
// CHECK-NEXT: Epilogue [
|
|
// CHECK-NEXT: 0xfc ; nop.w
|
|
// CHECK-NEXT: 0xf7 0x00 0x80 ; add sp, sp, #(128 * 4)
|
|
// CHECK-NEXT: 0xfc ; nop.w
|
|
// CHECK-NEXT: 0xfc ; nop.w
|
|
// CHECK-NEXT: 0xf8 0x01 0x00 0x00 ; add sp, sp, #(65536 * 4)
|
|
// CHECK-NEXT: 0x06 ; add sp, #(6 * 4)
|
|
// CHECK-NEXT: 0xef 0x04 ; ldr.w lr, [sp], #16
|
|
// CHECK-NEXT: 0xfd ; bx <reg>
|
|
// CHECK-NEXT: ]
|
|
// CHECK-NEXT: ExceptionHandler [
|
|
// CHECK-NEXT: Routine: __C_specific_handler
|
|
// CHECK-NEXT: Parameter: 0x0
|
|
// CHECK-NEXT: ]
|
|
// CHECK-NEXT: }
|
|
// CHECK-NEXT: }
|
|
// CHECK-NEXT: RuntimeFunction {
|
|
// CHECK-NEXT: Function: func2
|
|
// CHECK: Prologue [
|
|
// CHECK-NEXT: 0xd3 ; push {r4-r7}
|
|
// CHECK-NEXT: ]
|
|
// CHECK-NEXT: Epilogue [
|
|
// CHECK-NEXT: 0xd2 ; pop {r4-r6}
|
|
// CHECK-NEXT: 0xfe ; b.w <target>
|
|
// CHECK-NEXT: ]
|
|
// CHECK-NEXT: }
|
|
// CHECK-NEXT: }
|
|
// CHECK-NEXT: RuntimeFunction {
|
|
// CHECK-NEXT: Function: func3
|
|
// CHECK: FunctionLength: 8
|
|
// CHECK: EpilogueOffset: 2
|
|
// CHECK: Prologue [
|
|
// CHECK-NEXT: 0xd5 ; push {r4-r5, lr}
|
|
// CHECK-NEXT: ]
|
|
// CHECK-NEXT: Epilogue [
|
|
// CHECK-NEXT: 0xd6 ; pop {r4-r6, pc}
|
|
// CHECK-NEXT: ]
|
|
// CHECK-NEXT: }
|
|
// CHECK-NEXT: }
|
|
// CHECK-NEXT: RuntimeFunction {
|
|
// CHECK-NEXT: Function: fragment
|
|
// CHECK: FunctionLength: 6
|
|
// CHECK: Fragment: Yes
|
|
// CHECK: Prologue [
|
|
// CHECK-NEXT: 0xcb ; mov r11, sp
|
|
// CHECK-NEXT: 0x10 ; sub sp, #(16 * 4)
|
|
// CHECK-NEXT: 0xd5 ; push {r4-r5, lr}
|
|
// CHECK-NEXT: ]
|
|
// CHECK-NEXT: Epilogue [
|
|
// CHECK-NEXT: 0x10 ; add sp, #(16 * 4)
|
|
// CHECK-NEXT: 0xd5 ; pop {r4-r5, pc}
|
|
// CHECK-NEXT: ]
|
|
// CHECK-NEXT: }
|
|
// CHECK-NEXT: }
|
|
// CHECK-NEXT: RuntimeFunction {
|
|
// CHECK-NEXT: Function: condepilog
|
|
// CHECK: FunctionLength: 8
|
|
// CHECK: Prologue [
|
|
// CHECK-NEXT: 0xd5 ; push {r4-r5, lr}
|
|
// CHECK-NEXT: ]
|
|
// CHECK-NEXT: EpilogueScopes [
|
|
// CHECK-NEXT: EpilogueScope {
|
|
// CHECK-NEXT: StartOffset: 3
|
|
// CHECK-NEXT: Condition: 10
|
|
// CHECK-NEXT: EpilogueStartIndex: 0
|
|
// CHECK-NEXT: Opcodes [
|
|
// CHECK-NEXT: 0xd5 ; pop {r4-r5, pc}
|
|
// CHECK-NEXT: ]
|
|
// CHECK-NEXT: }
|
|
// CHECK-NEXT: ]
|
|
// CHECK-NEXT: }
|
|
// CHECK-NEXT: }
|
|
// CHECK-NEXT: ]
|
|
|
|
.text
|
|
.syntax unified
|
|
.globl func
|
|
.def func
|
|
.scl 2
|
|
.type 32
|
|
.endef
|
|
.seh_proc func
|
|
func:
|
|
sub sp, sp, #24
|
|
.seh_stackalloc 24
|
|
sub sp, sp, #512
|
|
.seh_stackalloc_w 512
|
|
sub sp, sp, #512
|
|
.seh_stackalloc_w 512
|
|
sub sp, sp, #4096
|
|
.seh_stackalloc_w 4096
|
|
movw r7, #0
|
|
.seh_nop_w
|
|
movt r7, #0x4 // 0x40000
|
|
.seh_nop_w
|
|
sub sp, sp, r7
|
|
.seh_stackalloc_w 0x40000
|
|
push {r4-r8,lr}
|
|
.seh_save_regs_w {r4-r9,lr}
|
|
push {r4-r7,lr}
|
|
.seh_save_regs {r4-r7,lr}
|
|
push {r4,r6,r8,r10,r11,r12,lr}
|
|
.seh_save_regs_w {r4,r6,r8,r10,r11,r12,lr}
|
|
push {r3-r7,lr}
|
|
.seh_save_regs {r3-r7,lr}
|
|
vpush {d8-d14}
|
|
.seh_save_fregs {d8-d14}
|
|
vpush {q4-q5}
|
|
.seh_save_fregs {q4-q5}
|
|
mov lr, sp
|
|
.seh_save_sp lr
|
|
nop
|
|
.seh_nop
|
|
vpush {d7-d14}
|
|
.seh_save_fregs {d7-d14}
|
|
vpush {d18-d23}
|
|
.seh_save_fregs {d18-d23}
|
|
push {r3-r7,lr}
|
|
.seh_custom 0xed, 0xf8
|
|
.seh_endprologue
|
|
nop
|
|
.seh_startepilogue
|
|
mov r7, #512
|
|
.seh_nop_w
|
|
add sp, sp, r7
|
|
.seh_stackalloc 512
|
|
movw r7, #0
|
|
.seh_nop_w
|
|
movt r7, #0x4 // 0x40000
|
|
.seh_nop_w
|
|
add sp, sp, r7
|
|
.seh_stackalloc 0x40000
|
|
add sp, sp, #24
|
|
.seh_stackalloc 24
|
|
ldr lr, [sp], #16
|
|
.seh_save_lr 16
|
|
bx lr
|
|
.seh_nop
|
|
.seh_endepilogue
|
|
.seh_handler __C_specific_handler, %except
|
|
.seh_handlerdata
|
|
.long 0
|
|
.text
|
|
.seh_endproc
|
|
|
|
.seh_proc func2
|
|
func2:
|
|
push {r4-r7}
|
|
.seh_save_regs {r4-r7}
|
|
.seh_endprologue
|
|
nop
|
|
.seh_startepilogue
|
|
pop {r4-r6}
|
|
.seh_save_regs {r4-r6}
|
|
b.w tailcall
|
|
.seh_nop_w
|
|
.seh_endepilogue
|
|
.seh_endproc
|
|
|
|
.seh_proc func3
|
|
func3:
|
|
push {r4-r5,lr}
|
|
.seh_save_regs {r4-r5,lr}
|
|
.seh_endprologue
|
|
nop
|
|
// The p2align causes the length of the function to be unknown.
|
|
.p2align 1
|
|
nop
|
|
.seh_startepilogue
|
|
pop {r4-r6,pc}
|
|
.seh_save_regs {r4-r6,pc}
|
|
.seh_endepilogue
|
|
.seh_endproc
|
|
|
|
.seh_proc fragment
|
|
fragment:
|
|
// Prologue opcodes without matching instructions
|
|
.seh_save_regs {r4-r5,lr}
|
|
.seh_stackalloc 64
|
|
.seh_save_sp r11
|
|
.seh_endprologue_fragment
|
|
nop
|
|
.seh_startepilogue
|
|
add sp, sp, #64
|
|
.seh_stackalloc 64
|
|
pop {r4-r5,pc}
|
|
.seh_save_regs {r4-r5,pc}
|
|
.seh_endepilogue
|
|
.seh_endproc
|
|
|
|
.seh_proc condepilog
|
|
condepilog:
|
|
push {r4-r5,lr}
|
|
.seh_save_regs {r4-r5,lr}
|
|
.seh_endprologue
|
|
nop
|
|
it ge
|
|
.seh_startepilogue_cond ge
|
|
popge {r4-r5,pc}
|
|
.seh_save_regs {r4-r5,pc}
|
|
.seh_endepilogue
|
|
.seh_endproc
|
|
|
|
// Function with no .seh directives; no pdata/xdata entries are
|
|
// generated.
|
|
.globl smallFunc
|
|
.def smallFunc
|
|
.scl 2
|
|
.type 32
|
|
.endef
|
|
.seh_proc smallFunc
|
|
smallFunc:
|
|
bx lr
|
|
.seh_endproc
|
|
|
|
// Function with no .seh directives, but with .seh_handlerdata.
|
|
// No xdata/pdata entries are generated, but the custom handler data
|
|
// (the .long after .seh_handlerdata) is left orphaned in the xdata
|
|
// section.
|
|
.globl handlerFunc
|
|
.def handlerFunc
|
|
.scl 2
|
|
.type 32
|
|
.endef
|
|
.seh_proc handlerFunc
|
|
handlerFunc:
|
|
bx lr
|
|
.seh_handler __C_specific_handler, %except
|
|
.seh_handlerdata
|
|
.long 0
|
|
.text
|
|
.seh_endproc
|