1 /**
2  * \file
3  * JIT trampoline code for amd64
4  *
5  * Authors:
6  *   Dietmar Maurer (dietmar@ximian.com)
7  *   Zoltan Varga (vargaz@gmail.com)
8  *   Johan Lorensson (lateralusx.github@gmail.com)
9  *
10  * (C) 2001 Ximian, Inc.
11  * Copyright 2003-2011 Novell, Inc (http://www.novell.com)
12  * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
13  * Licensed under the MIT license. See LICENSE file in the project root for full license information.
14  */
15 
16 #include <config.h>
17 #include <glib.h>
18 
19 #include <mono/metadata/abi-details.h>
20 #include <mono/metadata/appdomain.h>
21 #include <mono/metadata/marshal.h>
22 #include <mono/metadata/tabledefs.h>
23 #include <mono/metadata/profiler-private.h>
24 #include <mono/metadata/gc-internals.h>
25 #include <mono/arch/amd64/amd64-codegen.h>
26 
27 #include <mono/utils/memcheck.h>
28 
29 #include "mini.h"
30 #include "mini-amd64.h"
31 #include "mini-runtime.h"
32 #include "debugger-agent.h"
33 
34 #ifndef DISABLE_INTERPRETER
35 #include "interp/interp.h"
36 #endif
37 
38 #define ALIGN_TO(val,align) ((((guint64)val) + ((align) - 1)) & ~((align) - 1))
39 
40 #define IS_REX(inst) (((inst) >= 0x40) && ((inst) <= 0x4f))
41 
42 #ifndef DISABLE_JIT
43 /*
44  * mono_arch_get_unbox_trampoline:
45  * @m: method pointer
46  * @addr: pointer to native code for @m
47  *
48  * when value type methods are called through the vtable we need to unbox the
49  * this argument. This method returns a pointer to a trampoline which does
50  * unboxing before calling the method
51  */
52 gpointer
mono_arch_get_unbox_trampoline(MonoMethod * m,gpointer addr)53 mono_arch_get_unbox_trampoline (MonoMethod *m, gpointer addr)
54 {
55 	guint8 *code, *start;
56 	GSList *unwind_ops;
57 	int this_reg, size = 20;
58 
59 	MonoDomain *domain = mono_domain_get ();
60 
61 	this_reg = mono_arch_get_this_arg_reg (NULL);
62 
63 	start = code = (guint8 *)mono_domain_code_reserve (domain, size + MONO_TRAMPOLINE_UNWINDINFO_SIZE(0));
64 
65 	unwind_ops = mono_arch_get_cie_program ();
66 
67 	amd64_alu_reg_imm (code, X86_ADD, this_reg, sizeof (MonoObject));
68 	/* FIXME: Optimize this */
69 	amd64_mov_reg_imm (code, AMD64_RAX, addr);
70 	amd64_jump_reg (code, AMD64_RAX);
71 	g_assert ((code - start) < size);
72 	g_assert_checked (mono_arch_unwindinfo_validate_size (unwind_ops, MONO_TRAMPOLINE_UNWINDINFO_SIZE(0)));
73 
74 	mono_arch_flush_icache (start, code - start);
75 	MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_UNBOX_TRAMPOLINE, m));
76 
77 	mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, unwind_ops), domain);
78 
79 	return start;
80 }
81 
82 /*
83  * mono_arch_get_static_rgctx_trampoline:
84  *
85  *   Create a trampoline which sets RGCTX_REG to ARG, then jumps to ADDR.
86  */
87 gpointer
mono_arch_get_static_rgctx_trampoline(gpointer arg,gpointer addr)88 mono_arch_get_static_rgctx_trampoline (gpointer arg, gpointer addr)
89 {
90 	guint8 *code, *start;
91 	GSList *unwind_ops;
92 	int buf_len;
93 
94 	MonoDomain *domain = mono_domain_get ();
95 
96 #ifdef MONO_ARCH_NOMAP32BIT
97 	buf_len = 32;
98 #else
99 	/* AOTed code could still have a non-32 bit address */
100 	if ((((guint64)addr) >> 32) == 0)
101 		buf_len = 16;
102 	else
103 		buf_len = 30;
104 #endif
105 
106 	start = code = (guint8 *)mono_domain_code_reserve (domain, buf_len + MONO_TRAMPOLINE_UNWINDINFO_SIZE(0));
107 
108 	unwind_ops = mono_arch_get_cie_program ();
109 
110 	amd64_mov_reg_imm (code, MONO_ARCH_RGCTX_REG, arg);
111 	amd64_jump_code (code, addr);
112 	g_assert ((code - start) < buf_len);
113 	g_assert_checked (mono_arch_unwindinfo_validate_size (unwind_ops, MONO_TRAMPOLINE_UNWINDINFO_SIZE(0)));
114 
115 	mono_arch_flush_icache (start, code - start);
116 	MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_GENERICS_TRAMPOLINE, NULL));
117 
118 	mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, unwind_ops), domain);
119 
120 	return start;
121 }
122 #endif /* !DISABLE_JIT */
123 
124 #ifdef _WIN64
125 // Workaround lack of Valgrind support for 64-bit Windows
126 #define VALGRIND_DISCARD_TRANSLATIONS(...)
127 #endif
128 
129 /*
130  * mono_arch_patch_callsite:
131  *
132  *   Patch the callsite whose address is given by ORIG_CODE so it calls ADDR. ORIG_CODE
133  * points to the pc right after the call.
134  */
135 void
mono_arch_patch_callsite(guint8 * method_start,guint8 * orig_code,guint8 * addr)136 mono_arch_patch_callsite (guint8 *method_start, guint8 *orig_code, guint8 *addr)
137 {
138 	guint8 *code;
139 	guint8 buf [16];
140 	gboolean can_write = mono_breakpoint_clean_code (method_start, orig_code, 14, buf, sizeof (buf));
141 
142 	code = buf + 14;
143 
144 	/* mov 64-bit imm into r11 (followed by call reg?)  or direct call*/
145 	if (((code [-13] == 0x49) && (code [-12] == 0xbb)) || (code [-5] == 0xe8)) {
146 		if (code [-5] != 0xe8) {
147 			if (can_write) {
148 				g_assert ((guint64)(orig_code - 11) % 8 == 0);
149 				mono_atomic_xchg_ptr ((gpointer*)(orig_code - 11), addr);
150 				VALGRIND_DISCARD_TRANSLATIONS (orig_code - 11, sizeof (gpointer));
151 			}
152 		} else {
153 			gboolean disp_32bit = ((((gint64)addr - (gint64)orig_code)) < (1 << 30)) && ((((gint64)addr - (gint64)orig_code)) > -(1 << 30));
154 
155 			if ((((guint64)(addr)) >> 32) != 0 && !disp_32bit) {
156 				/*
157 				 * This might happen with LLVM or when calling AOTed code. Create a thunk.
158 				 */
159 				guint8 *thunk_start, *thunk_code;
160 
161 				thunk_start = thunk_code = (guint8 *)mono_domain_code_reserve (mono_domain_get (), 32);
162 				amd64_jump_membase (thunk_code, AMD64_RIP, 0);
163 				*(guint64*)thunk_code = (guint64)addr;
164 				addr = thunk_start;
165 				g_assert ((((guint64)(addr)) >> 32) == 0);
166 				mono_arch_flush_icache (thunk_start, thunk_code - thunk_start);
167 				MONO_PROFILER_RAISE (jit_code_buffer, (thunk_start, thunk_code - thunk_start, MONO_PROFILER_CODE_BUFFER_HELPER, NULL));
168 			}
169 			if (can_write) {
170 				mono_atomic_xchg_i32 ((gint32*)(orig_code - 4), ((gint64)addr - (gint64)orig_code));
171 				VALGRIND_DISCARD_TRANSLATIONS (orig_code - 5, 4);
172 			}
173 		}
174 	}
175 	else if ((code [-7] == 0x41) && (code [-6] == 0xff) && (code [-5] == 0x15)) {
176 		/* call *<OFFSET>(%rip) */
177 		gpointer *got_entry = (gpointer*)((guint8*)orig_code + (*(guint32*)(orig_code - 4)));
178 		if (can_write) {
179 			mono_atomic_xchg_ptr (got_entry, addr);
180 			VALGRIND_DISCARD_TRANSLATIONS (orig_code - 5, sizeof (gpointer));
181 		}
182 	}
183 }
184 
185 #ifndef DISABLE_JIT
186 guint8*
mono_arch_create_llvm_native_thunk(MonoDomain * domain,guint8 * addr)187 mono_arch_create_llvm_native_thunk (MonoDomain *domain, guint8 *addr)
188 {
189 	/*
190 	 * The caller is LLVM code and the call displacement might exceed 32 bits. We can't determine the caller address, so
191 	 * we add a thunk every time.
192 	 * Since the caller is also allocated using the domain code manager, hopefully the displacement will fit into 32 bits.
193 	 * FIXME: Avoid this if possible if !MONO_ARCH_NOMAP32BIT and ADDR is 32 bits.
194 	 */
195 	guint8 *thunk_start, *thunk_code;
196 
197 	thunk_start = thunk_code = (guint8 *)mono_domain_code_reserve (mono_domain_get (), 32);
198 	amd64_jump_membase (thunk_code, AMD64_RIP, 0);
199 	*(guint64*)thunk_code = (guint64)addr;
200 	addr = thunk_start;
201 	mono_arch_flush_icache (thunk_start, thunk_code - thunk_start);
202 	MONO_PROFILER_RAISE (jit_code_buffer, (thunk_start, thunk_code - thunk_start, MONO_PROFILER_CODE_BUFFER_HELPER, NULL));
203 	return addr;
204 }
205 #endif /* !DISABLE_JIT */
206 
207 void
mono_arch_patch_plt_entry(guint8 * code,gpointer * got,mgreg_t * regs,guint8 * addr)208 mono_arch_patch_plt_entry (guint8 *code, gpointer *got, mgreg_t *regs, guint8 *addr)
209 {
210 	gint32 disp;
211 	gpointer *plt_jump_table_entry;
212 
213 	/* A PLT entry: jmp *<DISP>(%rip) */
214 	g_assert (code [0] == 0xff);
215 	g_assert (code [1] == 0x25);
216 
217 	disp = *(gint32*)(code + 2);
218 
219 	plt_jump_table_entry = (gpointer*)(code + 6 + disp);
220 
221 	mono_atomic_xchg_ptr (plt_jump_table_entry, addr);
222 }
223 
224 #ifndef DISABLE_JIT
225 static void
stack_unaligned(MonoTrampolineType tramp_type)226 stack_unaligned (MonoTrampolineType tramp_type)
227 {
228 	printf ("%d\n", tramp_type);
229 	g_assert_not_reached ();
230 }
231 
232 guchar*
mono_arch_create_generic_trampoline(MonoTrampolineType tramp_type,MonoTrampInfo ** info,gboolean aot)233 mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInfo **info, gboolean aot)
234 {
235 	char *tramp_name;
236 	guint8 *buf, *code, *tramp, *br [2], *r11_save_code, *after_r11_save_code, *br_ex_check;
237 	int i, lmf_offset, offset, res_offset, arg_offset, rax_offset, ex_offset, tramp_offset, ctx_offset, saved_regs_offset;
238 	int r11_save_offset, saved_fpregs_offset, rbp_offset, framesize, orig_rsp_to_rbp_offset, cfa_offset;
239 	gboolean has_caller;
240 	GSList *unwind_ops = NULL;
241 	MonoJumpInfo *ji = NULL;
242 	const guint kMaxCodeSize = 630;
243 
244 	if (tramp_type == MONO_TRAMPOLINE_JUMP)
245 		has_caller = FALSE;
246 	else
247 		has_caller = TRUE;
248 
249 	code = buf = (guint8 *)mono_global_codeman_reserve (kMaxCodeSize + MONO_MAX_TRAMPOLINE_UNWINDINFO_SIZE);
250 
251 	/* Compute stack frame size and offsets */
252 	offset = 0;
253 	rbp_offset = -offset;
254 
255 	offset += sizeof(mgreg_t);
256 	rax_offset = -offset;
257 
258 	offset += sizeof(mgreg_t);
259 	ex_offset = -offset;
260 
261 	offset += sizeof(mgreg_t);
262 	r11_save_offset = -offset;
263 
264 	offset += sizeof(mgreg_t);
265 	tramp_offset = -offset;
266 
267 	offset += sizeof(gpointer);
268 	arg_offset = -offset;
269 
270 	offset += sizeof(mgreg_t);
271 	res_offset = -offset;
272 
273 	offset += sizeof (MonoContext);
274 	ctx_offset = -offset;
275 	saved_regs_offset = ctx_offset + MONO_STRUCT_OFFSET (MonoContext, gregs);
276 	saved_fpregs_offset = ctx_offset + MONO_STRUCT_OFFSET (MonoContext, fregs);
277 
278 	offset += sizeof (MonoLMFTramp);
279 	lmf_offset = -offset;
280 
281 #ifdef TARGET_WIN32
282 	/* Reserve space where the callee can save the argument registers */
283 	offset += 4 * sizeof (mgreg_t);
284 #endif
285 
286 	framesize = ALIGN_TO (offset, MONO_ARCH_FRAME_ALIGNMENT);
287 
288 	// CFA = sp + 16 (the trampoline address is on the stack)
289 	cfa_offset = 16;
290 	mono_add_unwind_op_def_cfa (unwind_ops, code, buf, AMD64_RSP, 16);
291 	// IP saved at CFA - 8
292 	mono_add_unwind_op_offset (unwind_ops, code, buf, AMD64_RIP, -8);
293 
294 	orig_rsp_to_rbp_offset = 0;
295 	r11_save_code = code;
296 	/* Reserve space for the mov_membase_reg to save R11 */
297 	code += 5;
298 	after_r11_save_code = code;
299 
300 	/* Pop the return address off the stack */
301 	amd64_pop_reg (code, AMD64_R11);
302 	orig_rsp_to_rbp_offset += sizeof(mgreg_t);
303 
304 	cfa_offset -= sizeof(mgreg_t);
305 	mono_add_unwind_op_def_cfa_offset (unwind_ops, code, buf, cfa_offset);
306 
307 	/*
308 	 * Allocate a new stack frame
309 	 */
310 	amd64_push_reg (code, AMD64_RBP);
311 	cfa_offset += sizeof(mgreg_t);
312 	mono_add_unwind_op_def_cfa_offset (unwind_ops, code, buf, cfa_offset);
313 	mono_add_unwind_op_offset (unwind_ops, code, buf, AMD64_RBP, - cfa_offset);
314 
315 	orig_rsp_to_rbp_offset -= sizeof(mgreg_t);
316 	amd64_mov_reg_reg (code, AMD64_RBP, AMD64_RSP, sizeof(mgreg_t));
317 	mono_add_unwind_op_def_cfa_reg (unwind_ops, code, buf, AMD64_RBP);
318 	mono_add_unwind_op_fp_alloc (unwind_ops, code, buf, AMD64_RBP, 0);
319 	amd64_alu_reg_imm (code, X86_SUB, AMD64_RSP, framesize);
320 
321 	/* Compute the trampoline address from the return address */
322 	if (aot) {
323 		/* 7 = length of call *<offset>(rip) */
324 		amd64_alu_reg_imm (code, X86_SUB, AMD64_R11, 7);
325 	} else {
326 		/* 5 = length of amd64_call_membase () */
327 		amd64_alu_reg_imm (code, X86_SUB, AMD64_R11, 5);
328 	}
329 	amd64_mov_membase_reg (code, AMD64_RBP, tramp_offset, AMD64_R11, sizeof(gpointer));
330 
331 	/* Save all registers */
332 	for (i = 0; i < AMD64_NREG; ++i) {
333 		if (i == AMD64_RBP) {
334 			/* RAX is already saved */
335 			amd64_mov_reg_membase (code, AMD64_RAX, AMD64_RBP, rbp_offset, sizeof(mgreg_t));
336 			amd64_mov_membase_reg (code, AMD64_RBP, saved_regs_offset + (i * sizeof(mgreg_t)), AMD64_RAX, sizeof(mgreg_t));
337 		} else if (i == AMD64_RIP) {
338 			if (has_caller)
339 				amd64_mov_reg_membase (code, AMD64_R11, AMD64_RBP, 8, sizeof(gpointer));
340 			else
341 				amd64_mov_reg_imm (code, AMD64_R11, 0);
342 			amd64_mov_membase_reg (code, AMD64_RBP, saved_regs_offset + (i * sizeof(mgreg_t)), AMD64_R11, sizeof(mgreg_t));
343 		} else if (i == AMD64_RSP) {
344 			amd64_mov_reg_reg (code, AMD64_R11, AMD64_RSP, sizeof(mgreg_t));
345 			amd64_alu_reg_imm (code, X86_ADD, AMD64_R11, framesize + 16);
346 			amd64_mov_membase_reg (code, AMD64_RBP, saved_regs_offset + (i * sizeof(mgreg_t)), AMD64_R11, sizeof(mgreg_t));
347 		} else if (i != AMD64_R11) {
348 			amd64_mov_membase_reg (code, AMD64_RBP, saved_regs_offset + (i * sizeof(mgreg_t)), i, sizeof(mgreg_t));
349 		} else {
350 			/* We have to save R11 right at the start of
351 			   the trampoline code because it's used as a
352 			   scratch register */
353 			/* This happens before the frame is set up, so it goes into the redzone */
354 			amd64_mov_membase_reg (r11_save_code, AMD64_RSP, r11_save_offset + orig_rsp_to_rbp_offset, i, sizeof(mgreg_t));
355 			g_assert (r11_save_code == after_r11_save_code);
356 
357 			/* Copy from the save slot into the register array slot */
358 			amd64_mov_reg_membase (code, i, AMD64_RSP, r11_save_offset + orig_rsp_to_rbp_offset, sizeof(mgreg_t));
359 			amd64_mov_membase_reg (code, AMD64_RBP, saved_regs_offset + (i * sizeof(mgreg_t)), i, sizeof(mgreg_t));
360 		}
361 		/* cfa = rbp + cfa_offset */
362 		mono_add_unwind_op_offset (unwind_ops, code, buf, i, - cfa_offset + saved_regs_offset + (i * sizeof (mgreg_t)));
363 	}
364 	for (i = 0; i < AMD64_XMM_NREG; ++i)
365 		if (AMD64_IS_ARGUMENT_XREG (i))
366 #if defined(MONO_HAVE_SIMD_REG)
367 			amd64_movdqu_membase_reg (code, AMD64_RBP, saved_fpregs_offset + (i * sizeof(MonoContextSimdReg)), i);
368 #else
369 			amd64_movsd_membase_reg (code, AMD64_RBP, saved_fpregs_offset + (i * sizeof(double)), i);
370 #endif
371 
372 	/* Check that the stack is aligned */
373 	amd64_mov_reg_reg (code, AMD64_R11, AMD64_RSP, sizeof (mgreg_t));
374 	amd64_alu_reg_imm (code, X86_AND, AMD64_R11, 15);
375 	amd64_alu_reg_imm (code, X86_CMP, AMD64_R11, 0);
376 	br [0] = code;
377 	amd64_branch_disp (code, X86_CC_Z, 0, FALSE);
378 	if (aot) {
379 		amd64_mov_reg_imm (code, AMD64_R11, 0);
380 		amd64_mov_reg_membase (code, AMD64_R11, AMD64_R11, 0, 8);
381 	} else {
382 		amd64_mov_reg_imm (code, MONO_AMD64_ARG_REG1, tramp_type);
383 		amd64_mov_reg_imm (code, AMD64_R11, stack_unaligned);
384 		amd64_call_reg (code, AMD64_R11);
385 	}
386 	mono_amd64_patch (br [0], code);
387 	//amd64_breakpoint (code);
388 
389 	/* Obtain the trampoline argument which is encoded in the instruction stream */
390 	if (aot) {
391 		/* Load the GOT offset */
392 		amd64_mov_reg_membase (code, AMD64_R11, AMD64_RBP, tramp_offset, sizeof(gpointer));
393 		/*
394 		 * r11 points to a call *<offset>(%rip) instruction, load the
395 		 * pc-relative offset from the instruction itself.
396 		 */
397 		amd64_mov_reg_membase (code, AMD64_RAX, AMD64_R11, 3, 4);
398 		/* 7 is the length of the call, 8 is the offset to the next got slot */
399 		amd64_alu_reg_imm_size (code, X86_ADD, AMD64_RAX, 7 + sizeof (gpointer), sizeof(gpointer));
400 		/* Compute the address of the GOT slot */
401 		amd64_alu_reg_reg_size (code, X86_ADD, AMD64_R11, AMD64_RAX, sizeof(gpointer));
402 		/* Load the value */
403 		amd64_mov_reg_membase (code, AMD64_R11, AMD64_R11, 0, sizeof(gpointer));
404 	} else {
405 		amd64_mov_reg_membase (code, AMD64_R11, AMD64_RBP, tramp_offset, sizeof(gpointer));
406 		amd64_mov_reg_membase (code, AMD64_RAX, AMD64_R11, 5, 1);
407 		amd64_widen_reg (code, AMD64_RAX, AMD64_RAX, TRUE, FALSE);
408 		amd64_alu_reg_imm_size (code, X86_CMP, AMD64_RAX, 4, 1);
409 		br [0] = code;
410 		x86_branch8 (code, X86_CC_NE, 6, FALSE);
411 		/* 32 bit immediate */
412 		amd64_mov_reg_membase (code, AMD64_R11, AMD64_R11, 6, 4);
413 		br [1] = code;
414 		x86_jump8 (code, 10);
415 		/* 64 bit immediate */
416 		mono_amd64_patch (br [0], code);
417 		amd64_mov_reg_membase (code, AMD64_R11, AMD64_R11, 6, 8);
418 		mono_amd64_patch (br [1], code);
419 	}
420 	amd64_mov_membase_reg (code, AMD64_RBP, arg_offset, AMD64_R11, sizeof(gpointer));
421 
422 	/* Save LMF begin */
423 
424 	/* Save sp */
425 	amd64_mov_reg_reg (code, AMD64_R11, AMD64_RSP, sizeof(mgreg_t));
426 	amd64_alu_reg_imm (code, X86_ADD, AMD64_R11, framesize + 16);
427 	amd64_mov_membase_reg (code, AMD64_RBP, lmf_offset + MONO_STRUCT_OFFSET (MonoLMF, rsp), AMD64_R11, sizeof(mgreg_t));
428 	/* Save pointer to context */
429 	amd64_lea_membase (code, AMD64_R11, AMD64_RBP, ctx_offset);
430 	amd64_mov_membase_reg (code, AMD64_RBP, lmf_offset + MONO_STRUCT_OFFSET (MonoLMFTramp, ctx), AMD64_R11, sizeof(mgreg_t));
431 
432 	if (aot) {
433 		code = mono_arch_emit_load_aotconst (buf, code, &ji, MONO_PATCH_INFO_JIT_ICALL_ADDR, "mono_get_lmf_addr");
434 	} else {
435 		amd64_mov_reg_imm (code, AMD64_R11, mono_get_lmf_addr);
436 	}
437 	amd64_call_reg (code, AMD64_R11);
438 
439 	/* Save lmf_addr */
440 	amd64_mov_membase_reg (code, AMD64_RBP, lmf_offset + MONO_STRUCT_OFFSET (MonoLMFTramp, lmf_addr), AMD64_RAX, sizeof(gpointer));
441 	/* Save previous_lmf */
442 	/* Set the third lowest bit to signal that this is a MonoLMFTramp structure */
443 	amd64_mov_reg_membase (code, AMD64_R11, AMD64_RAX, 0, sizeof(gpointer));
444 	amd64_alu_reg_imm_size (code, X86_ADD, AMD64_R11, 0x5, sizeof(gpointer));
445 	amd64_mov_membase_reg (code, AMD64_RBP, lmf_offset + MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), AMD64_R11, sizeof(gpointer));
446 	/* Set new lmf */
447 	amd64_lea_membase (code, AMD64_R11, AMD64_RBP, lmf_offset);
448 	amd64_mov_membase_reg (code, AMD64_RAX, 0, AMD64_R11, sizeof(gpointer));
449 
450 	/* Save LMF end */
451 
452 	/* Arg1 is the pointer to the saved registers */
453 	amd64_lea_membase (code, AMD64_ARG_REG1, AMD64_RBP, saved_regs_offset);
454 
455 	/* Arg2 is the address of the calling code */
456 	if (has_caller)
457 		amd64_mov_reg_membase (code, AMD64_ARG_REG2, AMD64_RBP, 8, sizeof(gpointer));
458 	else
459 		amd64_mov_reg_imm (code, AMD64_ARG_REG2, 0);
460 
461 	/* Arg3 is the method/vtable ptr */
462 	amd64_mov_reg_membase (code, AMD64_ARG_REG3, AMD64_RBP, arg_offset, sizeof(gpointer));
463 
464 	/* Arg4 is the trampoline address */
465 	amd64_mov_reg_membase (code, AMD64_ARG_REG4, AMD64_RBP, tramp_offset, sizeof(gpointer));
466 
467 	if (aot) {
468 		char *icall_name = g_strdup_printf ("trampoline_func_%d", tramp_type);
469 		code = mono_arch_emit_load_aotconst (buf, code, &ji, MONO_PATCH_INFO_JIT_ICALL_ADDR, icall_name);
470 	} else {
471 		tramp = (guint8*)mono_get_trampoline_func (tramp_type);
472 		amd64_mov_reg_imm (code, AMD64_R11, tramp);
473 	}
474 	amd64_call_reg (code, AMD64_R11);
475 	amd64_mov_membase_reg (code, AMD64_RBP, res_offset, AMD64_RAX, sizeof(mgreg_t));
476 
477 	/* Restore LMF */
478 	amd64_mov_reg_membase (code, AMD64_RCX, AMD64_RBP, lmf_offset + MONO_STRUCT_OFFSET (MonoLMF, previous_lmf), sizeof(gpointer));
479 	amd64_alu_reg_imm_size (code, X86_SUB, AMD64_RCX, 0x5, sizeof(gpointer));
480 	amd64_mov_reg_membase (code, AMD64_R11, AMD64_RBP, lmf_offset + MONO_STRUCT_OFFSET (MonoLMFTramp, lmf_addr), sizeof(gpointer));
481 	amd64_mov_membase_reg (code, AMD64_R11, 0, AMD64_RCX, sizeof(gpointer));
482 
483 	/*
484 	 * Save rax to the stack, after the leave instruction, this will become part of
485 	 * the red zone.
486 	 */
487 	amd64_mov_reg_membase (code, AMD64_RAX, AMD64_RBP, res_offset, sizeof(mgreg_t));
488 	amd64_mov_membase_reg (code, AMD64_RBP, rax_offset, AMD64_RAX, sizeof(mgreg_t));
489 
490 	/* Check for thread interruption */
491 	/* This is not perf critical code so no need to check the interrupt flag */
492 	/*
493 	 * Have to call the _force_ variant, since there could be a protected wrapper on the top of the stack.
494 	 */
495 	if (aot) {
496 		code = mono_arch_emit_load_aotconst (buf, code, &ji, MONO_PATCH_INFO_JIT_ICALL_ADDR, "mono_thread_force_interruption_checkpoint_noraise");
497 	} else {
498 		amd64_mov_reg_imm (code, AMD64_R11, (guint8*)mono_thread_force_interruption_checkpoint_noraise);
499 	}
500 	amd64_call_reg (code, AMD64_R11);
501 
502 	amd64_test_reg_reg (code, AMD64_RAX, AMD64_RAX);
503 	br_ex_check = code;
504 	amd64_branch8 (code, X86_CC_Z, -1, 1);
505 
506 	/*
507 	 * Exception case:
508 	 * We have an exception we want to throw in the caller's frame, so pop
509 	 * the trampoline frame and throw from the caller.
510 	 */
511 #if TARGET_WIN32
512 	amd64_lea_membase (code, AMD64_RSP, AMD64_RBP, 0);
513 	amd64_pop_reg (code, AMD64_RBP);
514 	mono_add_unwind_op_same_value (unwind_ops, code, buf, AMD64_RBP);
515 #else
516 	amd64_leave (code);
517 #endif
518 	/* We are in the parent frame, the exception is in rax */
519 	/*
520 	 * EH is initialized after trampolines, so get the address of the variable
521 	 * which contains throw_exception, and load it from there.
522 	 */
523 	if (aot) {
524 		/* Not really a jit icall */
525 		code = mono_arch_emit_load_aotconst (buf, code, &ji, MONO_PATCH_INFO_JIT_ICALL_ADDR, "throw_exception_addr");
526 	} else {
527 		amd64_mov_reg_imm (code, AMD64_R11, (guint8*)mono_get_throw_exception_addr ());
528 	}
529 	amd64_mov_reg_membase (code, AMD64_R11, AMD64_R11, 0, sizeof(gpointer));
530 	amd64_mov_reg_reg (code, AMD64_ARG_REG1, AMD64_RAX, sizeof(mgreg_t));
531 	/*
532 	 * We still have the original return value on the top of the stack, so the
533 	 * throw trampoline will use that as the throw site.
534 	 */
535 	amd64_jump_reg (code, AMD64_R11);
536 
537 	/* Normal case */
538 	mono_amd64_patch (br_ex_check, code);
539 
540 	/* Restore argument registers, r10 (imt method/rgxtx)
541 	   and rax (needed for direct calls to C vararg functions). */
542 	for (i = 0; i < AMD64_NREG; ++i)
543 		if (AMD64_IS_ARGUMENT_REG (i) || i == AMD64_R10 || i == AMD64_RAX)
544 			amd64_mov_reg_membase (code, i, AMD64_RBP, saved_regs_offset + (i * sizeof(mgreg_t)), sizeof(mgreg_t));
545 	for (i = 0; i < AMD64_XMM_NREG; ++i)
546 		if (AMD64_IS_ARGUMENT_XREG (i))
547 #if defined(MONO_HAVE_SIMD_REG)
548 			amd64_movdqu_reg_membase (code, i, AMD64_RBP, saved_fpregs_offset + (i * sizeof(MonoContextSimdReg)));
549 #else
550 			amd64_movsd_reg_membase (code, i, AMD64_RBP, saved_fpregs_offset + (i * sizeof(double)));
551 #endif
552 
553 	/* Restore stack */
554 #if TARGET_WIN32
555 	amd64_lea_membase (code, AMD64_RSP, AMD64_RBP, 0);
556 	amd64_pop_reg (code, AMD64_RBP);
557 	mono_add_unwind_op_same_value (unwind_ops, code, buf, AMD64_RBP);
558 #else
559 	amd64_leave (code);
560 #endif
561 	cfa_offset -= sizeof (mgreg_t);
562 	mono_add_unwind_op_def_cfa (unwind_ops, code, buf, AMD64_RSP, cfa_offset);
563 
564 	if (MONO_TRAMPOLINE_TYPE_MUST_RETURN (tramp_type)) {
565 		/* Load result */
566 		amd64_mov_reg_membase (code, AMD64_RAX, AMD64_RSP, rax_offset - sizeof(mgreg_t), sizeof(mgreg_t));
567 		amd64_ret (code);
568 	} else {
569 		/* call the compiled method using the saved rax */
570 		amd64_jump_membase (code, AMD64_RSP, rax_offset - sizeof(mgreg_t));
571 	}
572 
573 	g_assert ((code - buf) <= kMaxCodeSize);
574 	g_assert_checked (mono_arch_unwindinfo_validate_size (unwind_ops, MONO_MAX_TRAMPOLINE_UNWINDINFO_SIZE));
575 
576 	mono_arch_flush_icache (buf, code - buf);
577 	MONO_PROFILER_RAISE (jit_code_buffer, (buf, code - buf, MONO_PROFILER_CODE_BUFFER_HELPER, NULL));
578 
579 	tramp_name = mono_get_generic_trampoline_name (tramp_type);
580 	*info = mono_tramp_info_create (tramp_name, buf, code - buf, ji, unwind_ops);
581 	g_free (tramp_name);
582 
583 	return buf;
584 }
585 
586 gpointer
mono_arch_create_specific_trampoline(gpointer arg1,MonoTrampolineType tramp_type,MonoDomain * domain,guint32 * code_len)587 mono_arch_create_specific_trampoline (gpointer arg1, MonoTrampolineType tramp_type, MonoDomain *domain, guint32 *code_len)
588 {
589 	guint8 *code, *buf, *tramp;
590 	int size;
591 	gboolean far_addr = FALSE;
592 
593 	tramp = mono_get_trampoline_code (tramp_type);
594 
595 	if ((((guint64)arg1) >> 32) == 0)
596 		size = 5 + 1 + 4;
597 	else
598 		size = 5 + 1 + 8;
599 
600 	code = buf = (guint8 *)mono_domain_code_reserve_align (domain, size, 1);
601 
602 	if (((gint64)tramp - (gint64)code) >> 31 != 0 && ((gint64)tramp - (gint64)code) >> 31 != -1) {
603 #ifndef MONO_ARCH_NOMAP32BIT
604 		g_assert_not_reached ();
605 #endif
606 		far_addr = TRUE;
607 		size += 16;
608 		code = buf = (guint8 *)mono_domain_code_reserve_align (domain, size, 1);
609 	}
610 
611 	if (far_addr) {
612 		amd64_mov_reg_imm (code, AMD64_R11, tramp);
613 		amd64_call_reg (code, AMD64_R11);
614 	} else {
615 		amd64_call_code (code, tramp);
616 	}
617 	/* The trampoline code will obtain the argument from the instruction stream */
618 	if ((((guint64)arg1) >> 32) == 0) {
619 		*code = 0x4;
620 		*(guint32*)(code + 1) = (gint64)arg1;
621 		code += 5;
622 	} else {
623 		*code = 0x8;
624 		*(guint64*)(code + 1) = (gint64)arg1;
625 		code += 9;
626 	}
627 
628 	g_assert ((code - buf) <= size);
629 
630 	if (code_len)
631 		*code_len = size;
632 
633 	mono_arch_flush_icache (buf, size);
634 	MONO_PROFILER_RAISE (jit_code_buffer, (buf, code - buf, MONO_PROFILER_CODE_BUFFER_SPECIFIC_TRAMPOLINE, mono_get_generic_trampoline_simple_name (tramp_type)));
635 
636 	return buf;
637 }
638 
639 gpointer
mono_arch_create_rgctx_lazy_fetch_trampoline(guint32 slot,MonoTrampInfo ** info,gboolean aot)640 mono_arch_create_rgctx_lazy_fetch_trampoline (guint32 slot, MonoTrampInfo **info, gboolean aot)
641 {
642 	guint8 *tramp;
643 	guint8 *code, *buf;
644 	guint8 **rgctx_null_jumps;
645 	int tramp_size;
646 	int depth, index;
647 	int i;
648 	gboolean mrgctx;
649 	MonoJumpInfo *ji = NULL;
650 	GSList *unwind_ops;
651 
652 	mrgctx = MONO_RGCTX_SLOT_IS_MRGCTX (slot);
653 	index = MONO_RGCTX_SLOT_INDEX (slot);
654 	if (mrgctx)
655 		index += MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT / sizeof (gpointer);
656 	for (depth = 0; ; ++depth) {
657 		int size = mono_class_rgctx_get_array_size (depth, mrgctx);
658 
659 		if (index < size - 1)
660 			break;
661 		index -= size - 1;
662 	}
663 
664 	tramp_size = 64 + 8 * depth;
665 
666 	code = buf = (guint8 *)mono_global_codeman_reserve (tramp_size + MONO_TRAMPOLINE_UNWINDINFO_SIZE(0));
667 
668 	unwind_ops = mono_arch_get_cie_program ();
669 
670 	rgctx_null_jumps = (guint8 **)g_malloc (sizeof (guint8*) * (depth + 2));
671 
672 	if (mrgctx) {
673 		/* get mrgctx ptr */
674 		amd64_mov_reg_reg (code, AMD64_RAX, AMD64_ARG_REG1, 8);
675 	} else {
676 		/* load rgctx ptr from vtable */
677 		amd64_mov_reg_membase (code, AMD64_RAX, AMD64_ARG_REG1, MONO_STRUCT_OFFSET (MonoVTable, runtime_generic_context), sizeof(gpointer));
678 		/* is the rgctx ptr null? */
679 		amd64_test_reg_reg (code, AMD64_RAX, AMD64_RAX);
680 		/* if yes, jump to actual trampoline */
681 		rgctx_null_jumps [0] = code;
682 		amd64_branch8 (code, X86_CC_Z, -1, 1);
683 	}
684 
685 	for (i = 0; i < depth; ++i) {
686 		/* load ptr to next array */
687 		if (mrgctx && i == 0)
688 			amd64_mov_reg_membase (code, AMD64_RAX, AMD64_RAX, MONO_SIZEOF_METHOD_RUNTIME_GENERIC_CONTEXT, sizeof(gpointer));
689 		else
690 			amd64_mov_reg_membase (code, AMD64_RAX, AMD64_RAX, 0, sizeof(gpointer));
691 		/* is the ptr null? */
692 		amd64_test_reg_reg (code, AMD64_RAX, AMD64_RAX);
693 		/* if yes, jump to actual trampoline */
694 		rgctx_null_jumps [i + 1] = code;
695 		amd64_branch8 (code, X86_CC_Z, -1, 1);
696 	}
697 
698 	/* fetch slot */
699 	amd64_mov_reg_membase (code, AMD64_RAX, AMD64_RAX, sizeof (gpointer) * (index + 1), sizeof(gpointer));
700 	/* is the slot null? */
701 	amd64_test_reg_reg (code, AMD64_RAX, AMD64_RAX);
702 	/* if yes, jump to actual trampoline */
703 	rgctx_null_jumps [depth + 1] = code;
704 	amd64_branch8 (code, X86_CC_Z, -1, 1);
705 	/* otherwise return */
706 	amd64_ret (code);
707 
708 	for (i = mrgctx ? 1 : 0; i <= depth + 1; ++i)
709 		mono_amd64_patch (rgctx_null_jumps [i], code);
710 
711 	g_free (rgctx_null_jumps);
712 
713 	if (MONO_ARCH_VTABLE_REG != AMD64_ARG_REG1) {
714 		/* move the rgctx pointer to the VTABLE register */
715 		amd64_mov_reg_reg (code, MONO_ARCH_VTABLE_REG, AMD64_ARG_REG1, sizeof(gpointer));
716 	}
717 
718 	if (aot) {
719 		code = mono_arch_emit_load_aotconst (buf, code, &ji, MONO_PATCH_INFO_JIT_ICALL_ADDR, g_strdup_printf ("specific_trampoline_lazy_fetch_%u", slot));
720 		amd64_jump_reg (code, AMD64_R11);
721 	} else {
722 		tramp = (guint8 *)mono_arch_create_specific_trampoline (GUINT_TO_POINTER (slot), MONO_TRAMPOLINE_RGCTX_LAZY_FETCH, mono_get_root_domain (), NULL);
723 
724 		/* jump to the actual trampoline */
725 		amd64_jump_code (code, tramp);
726 	}
727 
728 	mono_arch_flush_icache (buf, code - buf);
729 	MONO_PROFILER_RAISE (jit_code_buffer, (buf, code - buf, MONO_PROFILER_CODE_BUFFER_GENERICS_TRAMPOLINE, NULL));
730 
731 	g_assert (code - buf <= tramp_size);
732 	g_assert_checked (mono_arch_unwindinfo_validate_size (unwind_ops, MONO_TRAMPOLINE_UNWINDINFO_SIZE(0)));
733 
734 	char *name = mono_get_rgctx_fetch_trampoline_name (slot);
735 	*info = mono_tramp_info_create (name, buf, code - buf, ji, unwind_ops);
736 	g_free (name);
737 
738 	return buf;
739 }
740 
741 gpointer
mono_arch_create_general_rgctx_lazy_fetch_trampoline(MonoTrampInfo ** info,gboolean aot)742 mono_arch_create_general_rgctx_lazy_fetch_trampoline (MonoTrampInfo **info, gboolean aot)
743 {
744 	guint8 *code, *buf;
745 	int tramp_size;
746 	MonoJumpInfo *ji = NULL;
747 	GSList *unwind_ops;
748 
749 	g_assert (aot);
750 	tramp_size = 64;
751 
752 	code = buf = (guint8 *)mono_global_codeman_reserve (tramp_size + MONO_TRAMPOLINE_UNWINDINFO_SIZE(0));
753 
754 	unwind_ops = mono_arch_get_cie_program ();
755 
756 	// FIXME: Currently, we always go to the slow path.
757 	/* This receives a <slot, trampoline> in the rgctx arg reg. */
758 	/* Load trampoline addr */
759 	amd64_mov_reg_membase (code, AMD64_R11, MONO_ARCH_RGCTX_REG, 8, 8);
760 	/* move the rgctx pointer to the VTABLE register */
761 	amd64_mov_reg_reg (code, MONO_ARCH_VTABLE_REG, AMD64_ARG_REG1, sizeof(gpointer));
762 	/* Jump to the trampoline */
763 	amd64_jump_reg (code, AMD64_R11);
764 
765 	mono_arch_flush_icache (buf, code - buf);
766 	MONO_PROFILER_RAISE (jit_code_buffer, (buf, code - buf, MONO_PROFILER_CODE_BUFFER_GENERICS_TRAMPOLINE, NULL));
767 
768 	g_assert (code - buf <= tramp_size);
769 	g_assert_checked (mono_arch_unwindinfo_validate_size (unwind_ops, MONO_TRAMPOLINE_UNWINDINFO_SIZE(0)));
770 
771 	if (info)
772 		*info = mono_tramp_info_create ("rgctx_fetch_trampoline_general", buf, code - buf, ji, unwind_ops);
773 
774 	return buf;
775 }
776 
777 void
mono_arch_invalidate_method(MonoJitInfo * ji,void * func,gpointer func_arg)778 mono_arch_invalidate_method (MonoJitInfo *ji, void *func, gpointer func_arg)
779 {
780 	/* FIXME: This is not thread safe */
781 	guint8 *code = (guint8 *)ji->code_start;
782 
783 	amd64_mov_reg_imm (code, AMD64_ARG_REG1, func_arg);
784 	amd64_mov_reg_imm (code, AMD64_R11, func);
785 
786 	x86_push_imm (code, (guint64)func_arg);
787 	amd64_call_reg (code, AMD64_R11);
788 }
789 #endif /* !DISABLE_JIT */
790 
791 /*
792  * mono_arch_get_call_target:
793  *
794  *   Return the address called by the code before CODE if exists.
795  */
796 guint8*
mono_arch_get_call_target(guint8 * code)797 mono_arch_get_call_target (guint8 *code)
798 {
799 	if (code [-5] == 0xe8) {
800 		gint32 disp = *(gint32*)(code - 4);
801 		guint8 *target = code + disp;
802 
803 		return target;
804 	} else {
805 		return NULL;
806 	}
807 }
808 
809 /*
810  * mono_arch_get_plt_info_offset:
811  *
812  *   Return the PLT info offset belonging to the plt entry PLT_ENTRY.
813  */
814 guint32
mono_arch_get_plt_info_offset(guint8 * plt_entry,mgreg_t * regs,guint8 * code)815 mono_arch_get_plt_info_offset (guint8 *plt_entry, mgreg_t *regs, guint8 *code)
816 {
817 	return *(guint32*)(plt_entry + 6);
818 }
819 
820 #ifndef DISABLE_JIT
821 /*
822  * mono_arch_create_sdb_trampoline:
823  *
824  *   Return a trampoline which captures the current context, passes it to
825  * debugger_agent_single_step_from_context ()/debugger_agent_breakpoint_from_context (),
826  * then restores the (potentially changed) context.
827  */
828 guint8*
mono_arch_create_sdb_trampoline(gboolean single_step,MonoTrampInfo ** info,gboolean aot)829 mono_arch_create_sdb_trampoline (gboolean single_step, MonoTrampInfo **info, gboolean aot)
830 {
831 	int tramp_size = 512;
832 	int i, framesize, ctx_offset, cfa_offset, gregs_offset;
833 	guint8 *code, *buf;
834 	GSList *unwind_ops = NULL;
835 	MonoJumpInfo *ji = NULL;
836 
837 	code = buf = (guint8 *)mono_global_codeman_reserve (tramp_size + MONO_MAX_TRAMPOLINE_UNWINDINFO_SIZE);
838 
839 	framesize = 0;
840 #ifdef TARGET_WIN32
841 	/* Reserve space where the callee can save the argument registers */
842 	framesize += 4 * sizeof (mgreg_t);
843 #endif
844 
845 	ctx_offset = framesize;
846 	framesize += sizeof (MonoContext);
847 
848 	framesize = ALIGN_TO (framesize, MONO_ARCH_FRAME_ALIGNMENT);
849 
850 	// CFA = sp + 8
851 	cfa_offset = 8;
852 	mono_add_unwind_op_def_cfa (unwind_ops, code, buf, AMD64_RSP, 8);
853 	// IP saved at CFA - 8
854 	mono_add_unwind_op_offset (unwind_ops, code, buf, AMD64_RIP, -cfa_offset);
855 
856 	amd64_push_reg (code, AMD64_RBP);
857 	cfa_offset += sizeof(mgreg_t);
858 	mono_add_unwind_op_def_cfa_offset (unwind_ops, code, buf, cfa_offset);
859 	mono_add_unwind_op_offset (unwind_ops, code, buf, AMD64_RBP, - cfa_offset);
860 
861 	amd64_mov_reg_reg (code, AMD64_RBP, AMD64_RSP, sizeof(mgreg_t));
862 	mono_add_unwind_op_def_cfa_reg (unwind_ops, code, buf, AMD64_RBP);
863 	mono_add_unwind_op_fp_alloc (unwind_ops, code, buf, AMD64_RBP, 0);
864 	amd64_alu_reg_imm (code, X86_SUB, AMD64_RSP, framesize);
865 
866 	gregs_offset = ctx_offset + MONO_STRUCT_OFFSET (MonoContext, gregs);
867 
868 	/* Initialize a MonoContext structure on the stack */
869 	for (i = 0; i < AMD64_NREG; ++i) {
870 		if (i != AMD64_RIP && i != AMD64_RSP && i != AMD64_RBP)
871 			amd64_mov_membase_reg (code, AMD64_RSP, gregs_offset + (i * sizeof (mgreg_t)), i, sizeof (mgreg_t));
872 	}
873 	amd64_mov_reg_membase (code, AMD64_R11, AMD64_RBP, 0, sizeof (mgreg_t));
874 	amd64_mov_membase_reg (code, AMD64_RSP, gregs_offset + (AMD64_RBP * sizeof (mgreg_t)), AMD64_R11, sizeof (mgreg_t));
875 	amd64_lea_membase (code, AMD64_R11, AMD64_RBP, 2 * sizeof (mgreg_t));
876 	amd64_mov_membase_reg (code, AMD64_RSP, gregs_offset + (AMD64_RSP * sizeof (mgreg_t)), AMD64_R11, sizeof (mgreg_t));
877 	amd64_mov_reg_membase (code, AMD64_R11, AMD64_RBP, sizeof (mgreg_t), sizeof (mgreg_t));
878 	amd64_mov_membase_reg (code, AMD64_RSP, gregs_offset + (AMD64_RIP * sizeof (mgreg_t)), AMD64_R11, sizeof (mgreg_t));
879 
880 	/* Call the single step/breakpoint function in sdb */
881 	amd64_lea_membase (code, AMD64_ARG_REG1, AMD64_RSP, ctx_offset);
882 
883 	if (aot) {
884 		if (single_step)
885 			code = mono_arch_emit_load_aotconst (buf, code, &ji, MONO_PATCH_INFO_JIT_ICALL_ADDR, "debugger_agent_single_step_from_context");
886 		else
887 			code = mono_arch_emit_load_aotconst (buf, code, &ji, MONO_PATCH_INFO_JIT_ICALL_ADDR, "debugger_agent_breakpoint_from_context");
888 	} else {
889 		if (single_step)
890 			amd64_mov_reg_imm (code, AMD64_R11, debugger_agent_single_step_from_context);
891 		else
892 			amd64_mov_reg_imm (code, AMD64_R11, debugger_agent_breakpoint_from_context);
893 	}
894 	amd64_call_reg (code, AMD64_R11);
895 
896 	/* Restore registers from ctx */
897 	for (i = 0; i < AMD64_NREG; ++i) {
898 		if (i != AMD64_RIP && i != AMD64_RSP && i != AMD64_RBP)
899 			amd64_mov_reg_membase (code, i, AMD64_RSP, gregs_offset + (i * sizeof (mgreg_t)), sizeof (mgreg_t));
900 	}
901 	amd64_mov_reg_membase (code, AMD64_R11, AMD64_RSP, gregs_offset + (AMD64_RBP * sizeof (mgreg_t)), sizeof (mgreg_t));
902 	amd64_mov_membase_reg (code, AMD64_RBP, 0, AMD64_R11, sizeof (mgreg_t));
903 	amd64_mov_reg_membase (code, AMD64_R11, AMD64_RSP, gregs_offset + (AMD64_RIP * sizeof (mgreg_t)), sizeof (mgreg_t));
904 	amd64_mov_membase_reg (code, AMD64_RBP, sizeof (mgreg_t), AMD64_R11, sizeof (mgreg_t));
905 
906 #if TARGET_WIN32
907 	amd64_lea_membase (code, AMD64_RSP, AMD64_RBP, 0);
908 	amd64_pop_reg (code, AMD64_RBP);
909 	mono_add_unwind_op_same_value (unwind_ops, code, buf, AMD64_RBP);
910 #else
911 	amd64_leave (code);
912 #endif
913 	cfa_offset -= sizeof (mgreg_t);
914 	mono_add_unwind_op_def_cfa (unwind_ops, code, buf, AMD64_RSP, cfa_offset);
915 	amd64_ret (code);
916 
917 	mono_arch_flush_icache (code, code - buf);
918 	MONO_PROFILER_RAISE (jit_code_buffer, (buf, code - buf, MONO_PROFILER_CODE_BUFFER_HELPER, NULL));
919 	g_assert (code - buf <= tramp_size);
920 	g_assert_checked (mono_arch_unwindinfo_validate_size (unwind_ops, MONO_MAX_TRAMPOLINE_UNWINDINFO_SIZE));
921 
922 	const char *tramp_name = single_step ? "sdb_single_step_trampoline" : "sdb_breakpoint_trampoline";
923 	*info = mono_tramp_info_create (tramp_name, buf, code - buf, ji, unwind_ops);
924 
925 	return buf;
926 }
927 
928 /*
929  * mono_arch_get_enter_icall_trampoline:
930  *
931  *   A trampoline that handles the transition from interpreter into native
932  *   world. It requiers to set up a descriptor (InterpMethodArguments), so the
933  *   trampoline can translate the arguments into the native calling convention.
934  *
935  *   See also `build_args_from_sig ()` in interp.c.
936  */
937 gpointer
mono_arch_get_enter_icall_trampoline(MonoTrampInfo ** info)938 mono_arch_get_enter_icall_trampoline (MonoTrampInfo **info)
939 {
940 #ifndef DISABLE_INTERPRETER
941 	guint8 *start = NULL, *code, *label_gexits [INTERP_ICALL_TRAMP_IARGS], *label_fexits [INTERP_ICALL_TRAMP_FARGS], *label_leave_tramp [3], *label_is_float_ret;
942 	MonoJumpInfo *ji = NULL;
943 	GSList *unwind_ops = NULL;
944 	static int farg_regs[] = {AMD64_XMM0, AMD64_XMM1, AMD64_XMM2, AMD64_XMM3};
945 	int buf_len, i, framesize = 0, off_rbp, off_methodargs, off_targetaddr;
946 
947 	g_assert ((sizeof (farg_regs) / sizeof (farg_regs [0])) >= INTERP_ICALL_TRAMP_FARGS);
948 	buf_len = 512 + MONO_TRAMPOLINE_UNWINDINFO_SIZE(0);
949 	start = code = (guint8 *) mono_global_codeman_reserve (buf_len);
950 
951 	off_rbp = -framesize;
952 
953 	framesize += sizeof (mgreg_t);
954 	off_methodargs = -framesize;
955 
956 	framesize += sizeof (mgreg_t);
957 	off_targetaddr = -framesize;
958 
959 	framesize += (INTERP_ICALL_TRAMP_IARGS - PARAM_REGS) * sizeof (mgreg_t);
960 
961 	amd64_push_reg (code, AMD64_RBP);
962 	amd64_mov_reg_reg (code, AMD64_RBP, AMD64_RSP, sizeof (mgreg_t));
963 	amd64_alu_reg_imm (code, X86_SUB, AMD64_RSP, ALIGN_TO (framesize, MONO_ARCH_FRAME_ALIGNMENT));
964 
965 	/* save InterpMethodArguments* onto stack */
966 	amd64_mov_membase_reg (code, AMD64_RBP, off_methodargs, AMD64_ARG_REG2, sizeof (mgreg_t));
967 
968 	/* save target address on stack */
969 	amd64_mov_membase_reg (code, AMD64_RBP, off_targetaddr, AMD64_ARG_REG1, sizeof (mgreg_t));
970 
971 	/* load pointer to InterpMethodArguments* into R11 */
972 	amd64_mov_reg_reg (code, AMD64_R11, AMD64_ARG_REG2, 8);
973 
974 	/* move flen into RAX */
975 	amd64_mov_reg_membase (code, AMD64_RAX, AMD64_R11, MONO_STRUCT_OFFSET (InterpMethodArguments, flen), sizeof (mgreg_t));
976 	/* load pointer to fargs into R11 */
977 	amd64_mov_reg_membase (code, AMD64_R11, AMD64_R11, MONO_STRUCT_OFFSET (InterpMethodArguments, fargs), sizeof (mgreg_t));
978 
979 	for (i = 0; i < INTERP_ICALL_TRAMP_FARGS; ++i) {
980 		amd64_test_reg_reg (code, AMD64_RAX, AMD64_RAX);
981 		label_fexits [i] = code;
982 		x86_branch8 (code, X86_CC_Z, 0, FALSE);
983 
984 		amd64_sse_movsd_reg_membase (code, farg_regs [i], AMD64_R11, i * sizeof (double));
985 		amd64_dec_reg_size (code, AMD64_RAX, 1);
986 	}
987 
988 	for (i = 0; i < INTERP_ICALL_TRAMP_FARGS; i++)
989 		x86_patch (label_fexits [i], code);
990 
991 	/* load pointer to InterpMethodArguments* into R11 */
992 	amd64_mov_reg_reg (code, AMD64_R11, AMD64_ARG_REG2, sizeof (mgreg_t));
993 	/* move ilen into RAX */
994 	amd64_mov_reg_membase (code, AMD64_RAX, AMD64_R11, MONO_STRUCT_OFFSET (InterpMethodArguments, ilen), sizeof (mgreg_t));
995 
996 	int stack_offset = 0;
997 	for (i = 0; i < INTERP_ICALL_TRAMP_IARGS; i++) {
998 		amd64_test_reg_reg (code, AMD64_RAX, AMD64_RAX);
999 		label_gexits [i] = code;
1000 		x86_branch32 (code, X86_CC_Z, 0, FALSE);
1001 
1002 		/* load pointer to InterpMethodArguments* into R11 */
1003 		amd64_mov_reg_membase (code, AMD64_R11, AMD64_RBP, off_methodargs, sizeof (mgreg_t));
1004 		/* load pointer to iargs into R11 */
1005 		amd64_mov_reg_membase (code, AMD64_R11, AMD64_R11, MONO_STRUCT_OFFSET (InterpMethodArguments, iargs), sizeof (mgreg_t));
1006 
1007 		if (i < PARAM_REGS) {
1008 			amd64_mov_reg_membase (code, param_regs [i], AMD64_R11, i * sizeof (mgreg_t), sizeof (mgreg_t));
1009 		} else {
1010 			amd64_mov_reg_membase (code, AMD64_R11, AMD64_R11, i * sizeof (mgreg_t), sizeof (mgreg_t));
1011 			amd64_mov_membase_reg (code, AMD64_RSP, stack_offset, AMD64_R11, sizeof (mgreg_t));
1012 			stack_offset += sizeof (mgreg_t);
1013 		}
1014 		amd64_dec_reg_size (code, AMD64_RAX, 1);
1015 	}
1016 
1017 	for (i = 0; i < INTERP_ICALL_TRAMP_IARGS; i++)
1018 		x86_patch (label_gexits [i], code);
1019 
1020 	/* load target addr */
1021 	amd64_mov_reg_membase (code, AMD64_R11, AMD64_RBP, off_targetaddr, sizeof (mgreg_t));
1022 
1023 	/* call into native function */
1024 	amd64_call_reg (code, AMD64_R11);
1025 
1026 	/* load InterpMethodArguments */
1027 	amd64_mov_reg_membase (code, AMD64_R11, AMD64_RBP, off_methodargs, sizeof (mgreg_t));
1028 
1029 	/* load is_float_ret */
1030 	amd64_mov_reg_membase (code, AMD64_R11, AMD64_R11, MONO_STRUCT_OFFSET (InterpMethodArguments, is_float_ret), sizeof (mgreg_t));
1031 
1032 	/* check if a float return value is expected */
1033 	amd64_test_reg_reg (code, AMD64_R11, AMD64_R11);
1034 
1035 	label_is_float_ret = code;
1036 	x86_branch8 (code, X86_CC_NZ, 0, FALSE);
1037 
1038 	/* greg return */
1039 	/* load InterpMethodArguments */
1040 	amd64_mov_reg_membase (code, AMD64_R11, AMD64_RBP, off_methodargs, sizeof (mgreg_t));
1041 	/* load retval */
1042 	amd64_mov_reg_membase (code, AMD64_R11, AMD64_R11, MONO_STRUCT_OFFSET (InterpMethodArguments, retval), sizeof (mgreg_t));
1043 
1044 	amd64_test_reg_reg (code, AMD64_R11, AMD64_R11);
1045 	label_leave_tramp [0] = code;
1046 	x86_branch8 (code, X86_CC_Z, 0, FALSE);
1047 
1048 	amd64_mov_membase_reg (code, AMD64_R11, 0, AMD64_RAX, sizeof (mgreg_t));
1049 
1050 	label_leave_tramp [1] = code;
1051 	x86_jump8 (code, 0);
1052 
1053 	/* freg return */
1054 	x86_patch (label_is_float_ret, code);
1055 	/* load InterpMethodArguments */
1056 	amd64_mov_reg_membase (code, AMD64_R11, AMD64_RBP, off_methodargs, sizeof (mgreg_t));
1057 	/* load retval */
1058 	amd64_mov_reg_membase (code, AMD64_R11, AMD64_R11, MONO_STRUCT_OFFSET (InterpMethodArguments, retval), sizeof (mgreg_t));
1059 
1060 	amd64_test_reg_reg (code, AMD64_R11, AMD64_R11);
1061 	label_leave_tramp [2] = code;
1062 	x86_branch8 (code, X86_CC_Z, 0, FALSE);
1063 
1064 	amd64_sse_movsd_membase_reg (code, AMD64_R11, 0, AMD64_XMM0);
1065 
1066 	for (i = 0; i < 3; i++)
1067 		x86_patch (label_leave_tramp [i], code);
1068 
1069 	amd64_alu_reg_imm (code, X86_ADD, AMD64_RSP, ALIGN_TO (framesize, MONO_ARCH_FRAME_ALIGNMENT));
1070 	amd64_pop_reg (code, AMD64_RBP);
1071 	amd64_ret (code);
1072 
1073 	g_assert (code - start < buf_len);
1074 
1075 	mono_arch_flush_icache (start, code - start);
1076 	MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL));
1077 
1078 	if (info)
1079 		*info = mono_tramp_info_create ("enter_icall_trampoline", start, code - start, ji, unwind_ops);
1080 
1081 	return start;
1082 #else
1083 	g_assert_not_reached ();
1084 	return NULL;
1085 #endif /* DISABLE_INTERPRETER */
1086 }
1087 #endif /* !DISABLE_JIT */
1088 
1089 #ifdef DISABLE_JIT
1090 gpointer
mono_arch_get_unbox_trampoline(MonoMethod * m,gpointer addr)1091 mono_arch_get_unbox_trampoline (MonoMethod *m, gpointer addr)
1092 {
1093 	g_assert_not_reached ();
1094 	return NULL;
1095 }
1096 
1097 gpointer
mono_arch_get_static_rgctx_trampoline(gpointer arg,gpointer addr)1098 mono_arch_get_static_rgctx_trampoline (gpointer arg, gpointer addr)
1099 {
1100 	g_assert_not_reached ();
1101 	return NULL;
1102 }
1103 
1104 gpointer
mono_arch_create_rgctx_lazy_fetch_trampoline(guint32 slot,MonoTrampInfo ** info,gboolean aot)1105 mono_arch_create_rgctx_lazy_fetch_trampoline (guint32 slot, MonoTrampInfo **info, gboolean aot)
1106 {
1107 	g_assert_not_reached ();
1108 	return NULL;
1109 }
1110 
1111 guchar*
mono_arch_create_generic_trampoline(MonoTrampolineType tramp_type,MonoTrampInfo ** info,gboolean aot)1112 mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInfo **info, gboolean aot)
1113 {
1114 	g_assert_not_reached ();
1115 	return NULL;
1116 }
1117 
1118 gpointer
mono_arch_create_specific_trampoline(gpointer arg1,MonoTrampolineType tramp_type,MonoDomain * domain,guint32 * code_len)1119 mono_arch_create_specific_trampoline (gpointer arg1, MonoTrampolineType tramp_type, MonoDomain *domain, guint32 *code_len)
1120 {
1121 	g_assert_not_reached ();
1122 	return NULL;
1123 }
1124 
1125 gpointer
mono_arch_create_general_rgctx_lazy_fetch_trampoline(MonoTrampInfo ** info,gboolean aot)1126 mono_arch_create_general_rgctx_lazy_fetch_trampoline (MonoTrampInfo **info, gboolean aot)
1127 {
1128 	g_assert_not_reached ();
1129 	return NULL;
1130 }
1131 
1132 void
mono_arch_invalidate_method(MonoJitInfo * ji,void * func,gpointer func_arg)1133 mono_arch_invalidate_method (MonoJitInfo *ji, void *func, gpointer func_arg)
1134 {
1135 	g_assert_not_reached ();
1136 	return;
1137 }
1138 
1139 guint8*
mono_arch_create_sdb_trampoline(gboolean single_step,MonoTrampInfo ** info,gboolean aot)1140 mono_arch_create_sdb_trampoline (gboolean single_step, MonoTrampInfo **info, gboolean aot)
1141 {
1142 	g_assert_not_reached ();
1143 	return NULL;
1144 }
1145 
1146 gpointer
mono_arch_get_enter_icall_trampoline(MonoTrampInfo ** info)1147 mono_arch_get_enter_icall_trampoline (MonoTrampInfo **info)
1148 {
1149 	g_assert_not_reached ();
1150 	return NULL;
1151 }
1152 #endif /* DISABLE_JIT */
1153