1
Fork 0

correct calling convention for x86_64

This commit is contained in:
Niko Matsakis 2011-11-08 14:25:41 -08:00
parent a8c0c2b871
commit b30a76ed1b
4 changed files with 107 additions and 66 deletions

View file

@ -1,3 +1,5 @@
#include "x86_64_regs.h"
.text .text
/* /*
@ -46,54 +48,68 @@ First four arguments:
.globl swap_registers .globl swap_registers
swap_registers: swap_registers:
// n.b. when we enter, the return address is at the top of // n.b. when we enter, the return address is at the top of
// the stack (i.e., 0(%RSP)). We // the stack (i.e., 0(%RSP)) and the argument is in
// RUSTRT_ARG0_S. We
// simply save all NV registers into oregs. // simply save all NV registers into oregs.
// We then restore all NV registers from regs. This restores // We then restore all NV registers from regs. This restores
// the old stack pointer, which should include the proper // the old stack pointer, which should include the proper
// return address. We can therefore just return normally to // return address. We can therefore just return normally to
// jump back into the old code. // jump back into the old code.
# if defined(RUSTRT_ARG0_S)
mov RUSTRT_ARG0_S, %rdi
mov RUSTRT_ARG1_S, %rsi
# endif
// Save instruction pointer: // Save instruction pointer:
pop %rax pop %rax
mov %rax, 56(%rdi) mov %rax, (RUSTRT_IP*8)(%rdi)
// Save non-volatile integer registers: // Save non-volatile integer registers:
// (including RSP) // (including RSP)
mov %rbx, 0(%rdi) mov %rbx, (RUSTRT_RBX*8)(%rdi)
mov %rsp, 8(%rdi) mov %rsp, (RUSTRT_RSP*8)(%rdi)
mov %rbp, 16(%rdi) mov %rbp, (RUSTRT_RBP*8)(%rdi)
mov %r12, 24(%rdi) mov %r12, (RUSTRT_R12*8)(%rdi)
mov %r13, 32(%rdi) mov %r13, (RUSTRT_R13*8)(%rdi)
mov %r14, 40(%rdi) mov %r14, (RUSTRT_R14*8)(%rdi)
mov %r15, 48(%rdi) mov %r15, (RUSTRT_R15*8)(%rdi)
// Save relevant argument registers:
mov %rcx, (RUSTRT_RCX*8)(%rdi)
mov %rdi, (RUSTRT_RDI*8)(%rdi)
// Save non-volatile XMM registers: // Save non-volatile XMM registers:
movapd %xmm0, 64(%rdi) movapd %xmm0, (RUSTRT_XMM0*8)(%rdi)
movapd %xmm1, 80(%rdi) movapd %xmm1, (RUSTRT_XMM1*8)(%rdi)
movapd %xmm2, 96(%rdi) movapd %xmm2, (RUSTRT_XMM2*8)(%rdi)
movapd %xmm3, 112(%rdi) movapd %xmm3, (RUSTRT_XMM3*8)(%rdi)
movapd %xmm4, 128(%rdi) movapd %xmm4, (RUSTRT_XMM4*8)(%rdi)
movapd %xmm5, 144(%rdi) movapd %xmm5, (RUSTRT_XMM5*8)(%rdi)
// Restore non-volatile integer registers: // Restore non-volatile integer registers:
// (including RSP) // (including RSP)
mov 0(%rsi), %rbx mov (RUSTRT_RBX*8)(%rsi), %rbx
mov 8(%rsi), %rsp mov (RUSTRT_RSP*8)(%rsi), %rsp
mov 16(%rsi), %rbp mov (RUSTRT_RBP*8)(%rsi), %rbp
mov 24(%rsi), %r12 mov (RUSTRT_R12*8)(%rsi), %r12
mov 32(%rsi), %r13 mov (RUSTRT_R13*8)(%rsi), %r13
mov 40(%rsi), %r14 mov (RUSTRT_R14*8)(%rsi), %r14
mov 48(%rsi), %r15 mov (RUSTRT_R15*8)(%rsi), %r15
// Restore relevant argument registers:
mov (RUSTRT_RCX*8)(%rdi), %rcx
mov (RUSTRT_RDI*8)(%rdi), %rdi
// Restore non-volatile XMM registers: // Restore non-volatile XMM registers:
movapd 64(%rsi), %xmm0 movapd (RUSTRT_XMM0*8)(%rsi), %xmm0
movapd 80(%rsi), %xmm1 movapd (RUSTRT_XMM1*8)(%rsi), %xmm1
movapd 96(%rsi), %xmm2 movapd (RUSTRT_XMM2*8)(%rsi), %xmm2
movapd 112(%rsi), %xmm3 movapd (RUSTRT_XMM3*8)(%rsi), %xmm3
movapd 128(%rsi), %xmm4 movapd (RUSTRT_XMM4*8)(%rsi), %xmm4
movapd 144(%rsi), %xmm5 movapd (RUSTRT_XMM5*8)(%rsi), %xmm5
// Jump to the instruction pointer // Jump to the instruction pointer
// found in regs: // found in regs:
jmp *56(%rsi) jmp *(RUSTRT_IP*8)(%rsi)

View file

@ -25,14 +25,11 @@ void context::call(void *f, void *arg, void *stack) {
// given function. // given function.
swap(*this); swap(*this);
// set up the trampoline frame // set up the stack
uint64_t *sp = (uint64_t *)stack; uint32_t *sp = (uint32_t *)stack;
sp = align_down(sp);
// Shift the stack pointer so the alignment works out right. regs.data[RUSTRT_ARG0] = (uint64_t)arg;
sp = align_down(sp) - 3; regs.data[RUSTRT_RSP] = (uint64_t)sp;
*--sp = (uint64_t)arg; regs.data[RUSTRT_IP] = (uint64_t)f;
*--sp = 0xdeadbeef;
regs.regs[RSP] = (uint64_t)sp;
regs.ip = (uint64_t)f;
} }

View file

@ -20,18 +20,17 @@ T align_down(T sp)
return (T)((uint64_t)sp & ~(16 - 1)); return (T)((uint64_t)sp & ~(16 - 1));
} }
// The struct in which we store the saved data. This is mostly the
// volatile registers and instruction pointer, but it also includes
// RCX/RDI which are used to pass arguments. The indices for each
// register are found in <x86_64_regs.h>:
#include "x86_64_regs.h"
struct registers_t { struct registers_t {
uint64_t regs[7]; // Space for the volatile regs: rbx, rsp, rbp, r12:r15 uint64_t data[RUSTRT_MAX];
uint64_t ip;
// n.b.: These must be 16-byte aligned or movapd is unhappy.
__m128 xmms[6]; // Space for the volatile regs: xmm0:xmm5
}; };
class context { class context {
public: public:
static const int RSP = 1;
registers_t regs; registers_t regs;
context(); context();
@ -47,7 +46,7 @@ public:
// function being called causes the task to fail, then we have to avoid // function being called causes the task to fail, then we have to avoid
// leaking space on the C stack. // leaking space on the C stack.
inline void *alloc_stack(size_t nbytes) { inline void *alloc_stack(size_t nbytes) {
uint32_t bot = regs.regs[RSP]; uint32_t bot = regs.data[RUSTRT_RSP];
uint32_t top = align_down(bot - nbytes); uint32_t top = align_down(bot - nbytes);
#ifdef HAVE_VALGRIND #ifdef HAVE_VALGRIND

View file

@ -0,0 +1,29 @@
#define RUSTRT_RBX 0
#define RUSTRT_RSP 1
#define RUSTRT_RBP 2
#define RUSTRT_RDI 3
#define RUSTRT_RCX 4
#define RUSTRT_R12 5
#define RUSTRT_R13 6
#define RUSTRT_R14 7
#define RUSTRT_R15 8
#define RUSTRT_IP 9
#define RUSTRT_XMM0 10
#define RUSTRT_XMM1 12
#define RUSTRT_XMM2 14
#define RUSTRT_XMM3 16
#define RUSTRT_XMM4 18
#define RUSTRT_XMM5 20
#define RUSTRT_MAX 22
// ARG0 is the register in which the first argument goes.
// Naturally this depends on your operating system.
#if defined(__MINGW32__) || defined(_WINDOWS)
# define RUSTRT_ARG0 RUSTRT_RCX
# define RUSTRT_ARG0_S %rcx
# define RUSTRT_ARG1_S %rdx
#else
# define RUSTRT_ARG0 RUSTRT_RDI
#endif