1//===-- xray_trampoline_x86.s -----------------------------------*- ASM -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file is a part of XRay, a dynamic runtime instrumentation system.
10//
11// This implements the X86-specific assembler for the trampolines.
12//
13//===----------------------------------------------------------------------===//
14
15#include "../builtins/assembly.h"
16#include "../sanitizer_common/sanitizer_asm.h"
17
18
19
20.macro SAVE_REGISTERS
21	pushfq
22	subq $240, %rsp
23	CFI_DEF_CFA_OFFSET(248)
24	movq %rbp, 232(%rsp)
25	movupd	%xmm0, 216(%rsp)
26	movupd	%xmm1, 200(%rsp)
27	movupd	%xmm2, 184(%rsp)
28	movupd	%xmm3, 168(%rsp)
29	movupd	%xmm4, 152(%rsp)
30	movupd	%xmm5, 136(%rsp)
31	movupd	%xmm6, 120(%rsp)
32	movupd	%xmm7, 104(%rsp)
33	movq	%rdi, 96(%rsp)
34	movq	%rax, 88(%rsp)
35	movq	%rdx, 80(%rsp)
36	movq	%rsi, 72(%rsp)
37	movq	%rcx, 64(%rsp)
38	movq	%r8, 56(%rsp)
39	movq	%r9, 48(%rsp)
40	movq  %r10, 40(%rsp)
41	movq  %r11, 32(%rsp)
42	movq  %r12, 24(%rsp)
43	movq  %r13, 16(%rsp)
44	movq  %r14, 8(%rsp)
45	movq  %r15, 0(%rsp)
46.endm
47
48.macro RESTORE_REGISTERS
49	movq  232(%rsp), %rbp
50	movupd	216(%rsp), %xmm0
51	movupd	200(%rsp), %xmm1
52	movupd	184(%rsp), %xmm2
53	movupd	168(%rsp), %xmm3
54	movupd	152(%rsp), %xmm4
55	movupd	136(%rsp), %xmm5
56	movupd	120(%rsp) , %xmm6
57	movupd	104(%rsp) , %xmm7
58	movq	96(%rsp), %rdi
59	movq	88(%rsp), %rax
60	movq	80(%rsp), %rdx
61	movq	72(%rsp), %rsi
62	movq	64(%rsp), %rcx
63	movq	56(%rsp), %r8
64	movq	48(%rsp), %r9
65	movq  40(%rsp), %r10
66	movq  32(%rsp), %r11
67	movq  24(%rsp), %r12
68	movq  16(%rsp), %r13
69	movq  8(%rsp), %r14
70	movq  0(%rsp), %r15
71	addq	$240, %rsp
72	popfq
73	CFI_DEF_CFA_OFFSET(8)
74.endm
75
76.macro ALIGNED_CALL_RAX
77	// Call the logging handler, after aligning the stack to a 16-byte boundary.
78	// The approach we're taking here uses additional stack space to stash the
79	// stack pointer twice before aligning the pointer to 16-bytes. If the stack
80	// was 8-byte aligned, it will become 16-byte aligned -- when restoring the
81	// pointer, we can always look -8 bytes from the current position to get
82	// either of the values we've stashed in the first place.
83	pushq %rsp
84	pushq (%rsp)
85	andq $-0x10, %rsp
86  callq *%rax
87	movq 8(%rsp), %rsp
88.endm
89
90	.text
91#if !defined(__APPLE__)
92	.section .text
93	.file "xray_trampoline_x86.S"
94#else
95	.section __TEXT,__text
96#endif
97
98//===----------------------------------------------------------------------===//
99
100	.globl ASM_SYMBOL(__xray_FunctionEntry)
101	.align 16, 0x90
102	ASM_TYPE_FUNCTION(__xray_FunctionEntry)
103# LLVM-MCA-BEGIN __xray_FunctionEntry
104ASM_SYMBOL(__xray_FunctionEntry):
105	CFI_STARTPROC
106	SAVE_REGISTERS
107
108	// This load has to be atomic, it's concurrent with __xray_patch().
109	// On x86/amd64, a simple (type-aligned) MOV instruction is enough.
110	movq	ASM_SYMBOL(_ZN6__xray19XRayPatchedFunctionE)(%rip), %rax
111	testq	%rax, %rax
112	je	.Ltmp0
113
114	// The patched function prologue puts its xray_instr_map index into %r10d.
115	movl	%r10d, %edi
116	xor	%esi,%esi
117	ALIGNED_CALL_RAX
118
119.Ltmp0:
120	RESTORE_REGISTERS
121	retq
122# LLVM-MCA-END
123	ASM_SIZE(__xray_FunctionEntry)
124	CFI_ENDPROC
125
126//===----------------------------------------------------------------------===//
127
128	.globl ASM_SYMBOL(__xray_FunctionExit)
129	.align 16, 0x90
130	ASM_TYPE_FUNCTION(__xray_FunctionExit)
131# LLVM-MCA-BEGIN __xray_FunctionExit
132ASM_SYMBOL(__xray_FunctionExit):
133	CFI_STARTPROC
134	// Save the important registers first. Since we're assuming that this
135	// function is only jumped into, we only preserve the registers for
136	// returning.
137	subq	$56, %rsp
138	CFI_DEF_CFA_OFFSET(64)
139	movq  %rbp, 48(%rsp)
140	movupd	%xmm0, 32(%rsp)
141	movupd	%xmm1, 16(%rsp)
142	movq	%rax, 8(%rsp)
143	movq	%rdx, 0(%rsp)
144	movq	ASM_SYMBOL(_ZN6__xray19XRayPatchedFunctionE)(%rip), %rax
145	testq %rax,%rax
146	je	.Ltmp2
147
148	movl	%r10d, %edi
149	movl	$1, %esi
150  ALIGNED_CALL_RAX
151
152.Ltmp2:
153	// Restore the important registers.
154	movq  48(%rsp), %rbp
155	movupd	32(%rsp), %xmm0
156	movupd	16(%rsp), %xmm1
157	movq	8(%rsp), %rax
158	movq	0(%rsp), %rdx
159	addq	$56, %rsp
160	CFI_DEF_CFA_OFFSET(8)
161	retq
162# LLVM-MCA-END
163	ASM_SIZE(__xray_FunctionExit)
164	CFI_ENDPROC
165
166//===----------------------------------------------------------------------===//
167
168	.globl ASM_SYMBOL(__xray_FunctionTailExit)
169	.align 16, 0x90
170	ASM_TYPE_FUNCTION(__xray_FunctionTailExit)
171# LLVM-MCA-BEGIN __xray_FunctionTailExit
172ASM_SYMBOL(__xray_FunctionTailExit):
173	CFI_STARTPROC
174	SAVE_REGISTERS
175
176	movq	ASM_SYMBOL(_ZN6__xray19XRayPatchedFunctionE)(%rip), %rax
177	testq %rax,%rax
178	je	.Ltmp4
179
180	movl	%r10d, %edi
181	movl	$2, %esi
182
183  ALIGNED_CALL_RAX
184
185.Ltmp4:
186	RESTORE_REGISTERS
187	retq
188# LLVM-MCA-END
189	ASM_SIZE(__xray_FunctionTailExit)
190	CFI_ENDPROC
191
192//===----------------------------------------------------------------------===//
193
194	.globl ASM_SYMBOL(__xray_ArgLoggerEntry)
195	.align 16, 0x90
196	ASM_TYPE_FUNCTION(__xray_ArgLoggerEntry)
197# LLVM-MCA-BEGIN __xray_ArgLoggerEntry
198ASM_SYMBOL(__xray_ArgLoggerEntry):
199	CFI_STARTPROC
200	SAVE_REGISTERS
201
202	// Again, these function pointer loads must be atomic; MOV is fine.
203	movq	ASM_SYMBOL(_ZN6__xray13XRayArgLoggerE)(%rip), %rax
204	testq	%rax, %rax
205	jne	.Larg1entryLog
206
207	// If [arg1 logging handler] not set, defer to no-arg logging.
208	movq	ASM_SYMBOL(_ZN6__xray19XRayPatchedFunctionE)(%rip), %rax
209	testq	%rax, %rax
210	je	.Larg1entryFail
211
212.Larg1entryLog:
213
214	// First argument will become the third
215	movq	%rdi, %rdx
216
217	// XRayEntryType::LOG_ARGS_ENTRY into the second
218	mov	$0x3, %esi
219
220	// 32-bit function ID becomes the first
221	movl	%r10d, %edi
222	ALIGNED_CALL_RAX
223
224.Larg1entryFail:
225	RESTORE_REGISTERS
226	retq
227# LLVM-MCA-END
228	ASM_SIZE(__xray_ArgLoggerEntry)
229	CFI_ENDPROC
230
231//===----------------------------------------------------------------------===//
232
233	.global ASM_SYMBOL(__xray_CustomEvent)
234	.align 16, 0x90
235	ASM_TYPE_FUNCTION(__xray_CustomEvent)
236# LLVM-MCA-BEGIN __xray_CustomEvent
237ASM_SYMBOL(__xray_CustomEvent):
238	CFI_STARTPROC
239	SAVE_REGISTERS
240
241	// We take two arguments to this trampoline, which should be in rdi	and rsi
242	// already.
243	movq ASM_SYMBOL(_ZN6__xray22XRayPatchedCustomEventE)(%rip), %rax
244	testq %rax,%rax
245	je .LcustomEventCleanup
246
247	ALIGNED_CALL_RAX
248
249.LcustomEventCleanup:
250	RESTORE_REGISTERS
251	retq
252# LLVM-MCA-END
253	ASM_SIZE(__xray_CustomEvent)
254	CFI_ENDPROC
255
256//===----------------------------------------------------------------------===//
257
258	.global ASM_SYMBOL(__xray_TypedEvent)
259	.align 16, 0x90
260	ASM_TYPE_FUNCTION(__xray_TypedEvent)
261# LLVM-MCA-BEGIN __xray_TypedEvent
262ASM_SYMBOL(__xray_TypedEvent):
263	CFI_STARTPROC
264	SAVE_REGISTERS
265
266	// We pass three arguments to this trampoline, which should be in rdi, rsi
267	// and rdx without our intervention.
268	movq ASM_SYMBOL(_ZN6__xray21XRayPatchedTypedEventE)(%rip), %rax
269	testq %rax,%rax
270	je .LtypedEventCleanup
271
272	ALIGNED_CALL_RAX
273
274.LtypedEventCleanup:
275	RESTORE_REGISTERS
276	retq
277# LLVM-MCA-END
278	ASM_SIZE(__xray_TypedEvent)
279	CFI_ENDPROC
280
281//===----------------------------------------------------------------------===//
282
283NO_EXEC_STACK_DIRECTIVE
284