1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
|
// 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
|