Skip to content

Commit faa1649

Browse files
nikomatsakisbrson
authored andcommitted
---
yaml --- r: 6098 b: refs/heads/master c: 6a0d86c h: refs/heads/master v: v3
1 parent f018a88 commit faa1649

File tree

5 files changed

+234
-1
lines changed

5 files changed

+234
-1
lines changed

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
---
2-
refs/heads/master: 5b3bddcd8753d14a3f299c4f28f932570f2276b1
2+
refs/heads/master: 6a0d86c75472e1d8c4ad7bfc7d5e642cec48ff4d

trunk/src/rt/arch/x64/_context.S

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
.text
2+
3+
/*
4+
Callee save registers:
5+
ebp, ebx, esi, edi
6+
7+
Caller save registers:
8+
eax, ecx, edx
9+
*/
10+
11+
/*
12+
Stores current registers into arg0/RCX and restores
13+
registers found in arg1/RDX. This is used by our
14+
implementation of getcontext.
15+
*/
16+
17+
// swap_registers(registers_t *oregs, registers_t *regs)
18+
.globl swap_registers
19+
swap_registers:
20+
// save the old context
21+
movl 4(%esp), %eax
22+
//movl %eax, 0(%eax)
23+
movl %ebx, 4(%eax)
24+
movl %ecx, 8(%eax)
25+
movl %edx, 12(%eax)
26+
movl %ebp, 16(%eax)
27+
movl %esi, 20(%eax)
28+
movl %edi, 24(%eax)
29+
//movl %cs, 32(%eax)
30+
//movl %ds, 34(%eax)
31+
//movl %ss, 36(%eax)
32+
//movl %es, 38(%eax)
33+
//movl %fs, 40(%eax)
34+
//movl %gs, 42(%eax)
35+
36+
// save the flags
37+
pushf
38+
popl %ecx
39+
movl %ecx, 44(%eax)
40+
41+
// save the return address as the instruction pointer
42+
// and save the stack pointer of the caller
43+
popl %ecx
44+
movl %esp, 28(%eax)
45+
movl %ecx, 48(%eax)
46+
47+
// restore the new context
48+
movl 4(%esp), %eax
49+
50+
movl 4(%eax), %ebx
51+
// save ecx for later...
52+
movl 12(%eax), %edx
53+
movl 16(%eax), %ebp
54+
movl 20(%eax), %esi
55+
movl 24(%eax), %edi
56+
movl 28(%eax), %esp
57+
// We can't actually change this...
58+
//movl 32(%eax), %cs
59+
//movl 34(%eax), %ds
60+
//movl 36(%eax), %ss
61+
//movl 38(%eax), %es
62+
//movl 40(%eax), %fs
63+
//movl 42(%eax), %gs
64+
65+
// restore the flags
66+
movl 44(%eax), %ecx
67+
push %ecx
68+
popf
69+
70+
// ok, now we can restore ecx
71+
movl 8(%eax), %ecx
72+
73+
// Return!
74+
jmp *48(%eax)
75+
76+

trunk/src/rt/arch/x64/ccall.S

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
.text
2+
3+
// upcall_call_c_stack(void (*fn)(), void *new_esp)
4+
//
5+
// Note that we could use |enter| and |leave| but the manuals tell me they're
6+
// slower.
7+
#if defined(__APPLE__) || defined(_WIN32)
8+
.globl _upcall_call_c_stack
9+
_upcall_call_c_stack:
10+
#else
11+
.globl upcall_call_c_stack
12+
upcall_call_c_stack:
13+
#endif
14+
pushl %ebp
15+
movl %esp,%ebp // save esp
16+
movl 8(%esp),%eax // eax = callee
17+
movl 12(%esp),%esp // switch stack
18+
calll *%eax
19+
movl %ebp,%esp // would like to use "leave" but it's slower
20+
popl %ebp
21+
ret
22+

trunk/src/rt/arch/x64/context.cpp

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
#include "context.h"
2+
3+
#include "../../rust.h"
4+
5+
#include <stdio.h>
6+
#include <stdlib.h>
7+
#include <assert.h>
8+
9+
extern "C" uint32_t CDECL swap_registers(registers_t *oregs,
10+
registers_t *regs)
11+
asm ("swap_registers");
12+
13+
context::context()
14+
{
15+
assert((void*)&regs == (void*)this);
16+
}
17+
18+
void context::swap(context &out)
19+
{
20+
swap_registers(&out.regs, &regs);
21+
}
22+
23+
void context::call(void *f, void *arg, void *stack) {
24+
// Get the current context, which we will then modify to call the
25+
// given function.
26+
swap(*this);
27+
28+
// set up the trampoline frame
29+
uint32_t *sp = (uint32_t *)stack;
30+
31+
// Shift the stack pointer so the alignment works out right.
32+
sp = align_down(sp) - 3;
33+
*--sp = (uint32_t)arg;
34+
*--sp = 0xdeadbeef;
35+
36+
regs.esp = (uint32_t)sp;
37+
regs.eip = (uint32_t)f;
38+
}
39+
40+
#if 0
41+
// This is some useful code to check how the registers struct got
42+
// layed out in memory.
43+
int main() {
44+
registers_t regs;
45+
46+
printf("Register offsets\n");
47+
48+
#define REG(r) \
49+
printf(" %6s: +%ld\n", #r, (intptr_t)&regs.r - (intptr_t)&regs);
50+
51+
REG(eax);
52+
REG(ebx);
53+
REG(ecx);
54+
REG(edx);
55+
REG(ebp);
56+
REG(esi);
57+
REG(edi);
58+
REG(esp);
59+
60+
REG(cs);
61+
REG(ds);
62+
REG(ss);
63+
REG(es);
64+
REG(fs);
65+
REG(gs);
66+
67+
REG(eflags);
68+
69+
REG(eip);
70+
71+
return 0;
72+
}
73+
#endif

trunk/src/rt/arch/x64/context.h

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// -*- mode: c++ -*-
2+
3+
#ifndef CONTEXT_H
4+
#define CONTEXT_H
5+
6+
#include <cstdlib>
7+
#include <inttypes.h>
8+
#include <stdint.h>
9+
10+
#ifdef HAVE_VALGRIND
11+
#include <valgrind/memcheck.h>
12+
#endif
13+
14+
template<typename T>
15+
T align_down(T sp)
16+
{
17+
// There is no platform we care about that needs more than a
18+
// 16-byte alignment.
19+
return (T)((uint32_t)sp & ~(16 - 1));
20+
}
21+
22+
struct registers_t {
23+
// general purpose registers
24+
uint32_t eax, ebx, ecx, edx, ebp, esi, edi, esp;
25+
26+
// segment registers
27+
uint16_t cs, ds, ss, es, fs, gs;
28+
29+
uint32_t eflags;
30+
31+
uint32_t eip;
32+
};
33+
34+
class context {
35+
public:
36+
registers_t regs;
37+
38+
context();
39+
40+
context *next;
41+
42+
void swap(context &out);
43+
void call(void *f, void *arg, void *sp);
44+
void call(void *f, void *sp);
45+
46+
// Note that this doesn't actually adjust esp. Instead, we adjust esp when
47+
// we actually do the call. This is needed for exception safety -- if the
48+
// function being called causes the task to fail, then we have to avoid
49+
// leaking space on the C stack.
50+
inline void *alloc_stack(size_t nbytes) {
51+
uint32_t bot = regs.esp;
52+
uint32_t top = align_down(bot - nbytes);
53+
54+
#ifdef HAVE_VALGRIND
55+
(void)VALGRIND_MAKE_MEM_UNDEFINED(top - 4, bot - top + 4);
56+
#endif
57+
58+
return reinterpret_cast<void *>(top);
59+
}
60+
};
61+
62+
#endif

0 commit comments

Comments
 (0)