#define STACK_ALIGN 16
#define STACK_OFFSET sizeof(void *)
+#ifdef _WIN64
+/* In the Microsoft x64 calling convention, it's the caller's responsibility
+ * to allocate 32 bytes of "shadow space" on the stack right before calling
+ * the function (regardless of the actual number of parameters used). */
+#define STACK_SHADOW_SPACE 32
+#else
+#define STACK_SHADOW_SPACE 0
+#endif
uae_s8 always_used[]={4,-1};
#if defined(CPU_x86_64)
by pushing, even though they are "saved" across function calls
*/
#if defined(CPU_x86_64)
+#ifdef _WIN64
+/* https://msdn.microsoft.com/en-us/library/6t169e9c.aspx:
+ * "The registers RBX, RBP, RDI, RSI, RSP, R12, R13, R14, and R15 are
+ * considered nonvolatile and must be saved and restored by a function that
+ * uses them". Also saving r11 for now (see comment below). */
+static const uae_u8 need_to_preserve[]={0,0,0,1,0,1,1,1,0,0,0,1,1,1,1,1};
+#else
/* callee-saved registers as defined by Linux AMD64 ABI: rbx, rbp, rsp, r12 - r15 */
/* preserve r11 because it's generally used to hold pointers to functions */
+/* FIXME: not really sure what the point of saving r11 is (??). If functions
+ * cannot assume calle preserves it, it will not be used across calls anyway? */
static const uae_u8 need_to_preserve[]={0,0,0,1,0,1,0,0,0,0,0,1,1,1,1,1};
+#endif
#else
/* callee-saved registers as defined by System V IA-32 ABI: edi, esi, ebx, ebp */
static const uae_u8 need_to_preserve[]={0,0,0,1,0,1,1,1};
static inline void raw_dec_sp(int off)
{
- if (off) raw_sub_l_ri(ESP_INDEX,off);
+ if (off) {
+#ifdef CPU_x86_64
+ emit_byte(0x48); /* REX prefix */
+#endif
+ raw_sub_l_ri(ESP_INDEX,off);
+ }
}
static inline void raw_inc_sp(int off)
{
- if (off) raw_add_l_ri(ESP_INDEX,off);
+ if (off) {
+#ifdef CPU_x86_64
+ emit_byte(0x48); /* REX prefix */
+#endif
+ raw_add_l_ri(ESP_INDEX,off);
+ }
}
static inline void raw_push_regs_to_preserve(void) {
MIDFUNC(1,call_r,(RR4 r)) /* Clobbering is implicit */
{
r=readreg(r,4);
+ raw_dec_sp(STACK_SHADOW_SPACE);
raw_call_r(r);
+ raw_inc_sp(STACK_SHADOW_SPACE);
unlock2(r);
}
MENDFUNC(1,call_r,(RR4 r)) /* Clobbering is implicit */
unlock2(r);
prepare_for_call_2();
+ raw_dec_sp(STACK_SHADOW_SPACE);
raw_call_r(r);
+ raw_inc_sp(STACK_SHADOW_SPACE);
#if USE_NORMAL_CALLING_CONVENTION
raw_inc_sp(4);
unlock2(in1);
unlock2(in2);
prepare_for_call_2();
+ raw_dec_sp(STACK_SHADOW_SPACE);
raw_call_r(r);
+ raw_inc_sp(STACK_SHADOW_SPACE);
#if USE_NORMAL_CALLING_CONVENTION
raw_inc_sp(8);
#endif
compemu_raw_jcc_b_oponly(NATIVE_CC_GT);
uae_s8 *branchadd=(uae_s8*)get_target();
skip_byte();
+ raw_dec_sp(STACK_SHADOW_SPACE);
compemu_raw_call((uintptr)cpu_do_check_ticks);
+ raw_inc_sp(STACK_SHADOW_SPACE);
*branchadd=(uintptr)get_target()-((uintptr)branchadd+1);
#endif
prepare_for_call_1();
unlock2(arg);
prepare_for_call_2();
+ raw_dec_sp(STACK_SHADOW_SPACE);
compemu_raw_call((uintptr)m68k_record_step);
+ raw_inc_sp(STACK_SHADOW_SPACE);
}
#endif
#endif
compemu_raw_mov_l_mi((uintptr)®s.pc_p,
(uintptr)pc_hist[i].location);
+ raw_dec_sp(STACK_SHADOW_SPACE);
compemu_raw_call((uintptr)cputbl[opcode]);
+ raw_inc_sp(STACK_SHADOW_SPACE);
#ifdef PROFILE_UNTRANSLATED_INSNS
// raw_cputbl_count[] is indexed with plain opcode (in m68k order)
compemu_raw_add_l_mi((uintptr)&raw_cputbl_count[cft_map(opcode)],1);