Commit 7343e03c authored by Russ Cox's avatar Russ Cox

runtime: stack growth adjustments, cleanup

	* keep coherent SP/PC in gobuf
	  (i.e., SP that would be in use at that PC)
	* gogocall replaces setspgoto,
	  should work better in presence of link registers
	* delete unused system calls

only amd64; 386 is now broken

R=r
DELTA=548  (183 added, 183 deleted, 182 changed)
OCL=30381
CL=30442
parent 3b576a77
...@@ -30,9 +30,15 @@ ...@@ -30,9 +30,15 @@
#include <libc.h> #include <libc.h>
#include <bio.h> #include <bio.h>
#include <mach_amd64.h> #include <mach_amd64.h>
#define Ureg UregAmd64
#include <ureg_amd64.h> #include <ureg_amd64.h>
#undef Ureg
#define Ureg Ureg386
#include <ureg_x86.h>
#undef Ureg
typedef struct Ureg Ureg_amd64; typedef struct UregAmd64 UregAmd64;
typedef struct Ureg386 Ureg386;
/* /*
* i386-specific debugger interface * i386-specific debugger interface
...@@ -52,7 +58,8 @@ static char STARTSYM[] = "_main"; ...@@ -52,7 +58,8 @@ static char STARTSYM[] = "_main";
static char GOSTARTSYM[] = "sys·goexit"; static char GOSTARTSYM[] = "sys·goexit";
static char PROFSYM[] = "_mainp"; static char PROFSYM[] = "_mainp";
static char FRAMENAME[] = ".frame"; static char FRAMENAME[] = ".frame";
static char RETFROMNEWSTACK[] = "retfromnewstack"; static char LESSSTACK[] = "sys·lessstack";
static char MORESTACK[] = "sys·morestack";
static char *excname[] = static char *excname[] =
{ {
[0] "divide error", [0] "divide error",
...@@ -124,23 +131,6 @@ i386excep(Map *map, Rgetter rget) ...@@ -124,23 +131,6 @@ i386excep(Map *map, Rgetter rget)
return excname[c]; return excname[c];
} }
// borrowed from src/runtime/runtime.h
struct Stktop
{
uint8* oldbase;
uint8* oldsp;
uint64 magic;
uint8* oldguard;
};
struct G
{
uvlong stackguard; // must not move
uvlong stackbase; // must not move
uvlong stack0; // first stack segment
// rest not needed
};
static int static int
i386trace(Map *map, uvlong pc, uvlong sp, uvlong link, Tracer trace) i386trace(Map *map, uvlong pc, uvlong sp, uvlong link, Tracer trace)
{ {
...@@ -149,21 +139,35 @@ i386trace(Map *map, uvlong pc, uvlong sp, uvlong link, Tracer trace) ...@@ -149,21 +139,35 @@ i386trace(Map *map, uvlong pc, uvlong sp, uvlong link, Tracer trace)
Symbol s, f, s1; Symbol s, f, s1;
extern Mach mamd64; extern Mach mamd64;
int isamd64; int isamd64;
struct Stktop *stktop; uvlong g, m, lessstack, morestack, stktop;
struct G g;
uvlong r15;
uvlong retfromnewstack;
isamd64 = (mach == &mamd64); isamd64 = (mach == &mamd64);
retfromnewstack = 0;
if(isamd64) { // ../pkg/runtime/runtime.h
get8(map, offsetof(Ureg_amd64, r15), &r15); // G is
get8(map, r15+offsetof(struct G, stackguard), &g.stackguard); // byte* stackguard
get8(map, r15+offsetof(struct G, stackbase), &g.stackbase); // byte* stackbase (= Stktop*)
get8(map, r15+offsetof(struct G, stack0), &g.stack0); // Defer* defer
if(lookup(0, RETFROMNEWSTACK, &s)) // Gobuf sched
retfromnewstack = s.value; // TODO(rsc): Need some way to get at the g for other threads.
// Probably need to pass it into the trace function.
g = 0;
if(isamd64)
geta(map, offsetof(struct UregAmd64, r15), &g);
else {
// TODO(rsc): How to fetch g on 386?
} }
stktop = 0;
if(g != 0)
geta(map, g+1*mach->szaddr, &stktop);
lessstack = 0;
if(lookup(0, LESSSTACK, &s))
lessstack = s.value;
morestack = 0;
if(lookup(0, MORESTACK, &s))
morestack = s.value;
USED(link); USED(link);
osp = 0; osp = 0;
i = 0; i = 0;
...@@ -171,13 +175,19 @@ i386trace(Map *map, uvlong pc, uvlong sp, uvlong link, Tracer trace) ...@@ -171,13 +175,19 @@ i386trace(Map *map, uvlong pc, uvlong sp, uvlong link, Tracer trace)
for(;;) { for(;;) {
if(!findsym(pc, CTEXT, &s)) { if(!findsym(pc, CTEXT, &s)) {
// check for closure return sequence // check for closure return sequence
uchar buf[8]; uchar buf[8], *p;
if(get1(map, pc, buf, 8) < 0) if(get1(map, pc, buf, 8) < 0)
break; break;
// ADDQ $xxx, SP; RET // ADDQ $xxx, SP; RET
if(buf[0] != 0x48 || buf[1] != 0x81 || buf[2] != 0xc4 || buf[7] != 0xc3) p = buf;
if(mach == &mamd64) {
if(p[0] != 0x48)
break;
p++;
}
if(p[0] != 0x81 || p[1] != 0xc4 || p[6] != 0xc3)
break; break;
sp += buf[3] | (buf[4]<<8) | (buf[5]<<16) | (buf[6]<<24); sp += p[2] | (p[3]<<8) | (p[4]<<16) | (p[5]<<24);
if(geta(map, sp, &pc) < 0) if(geta(map, sp, &pc) < 0)
break; break;
sp += mach->szaddr; sp += mach->szaddr;
...@@ -193,16 +203,53 @@ i386trace(Map *map, uvlong pc, uvlong sp, uvlong link, Tracer trace) ...@@ -193,16 +203,53 @@ i386trace(Map *map, uvlong pc, uvlong sp, uvlong link, Tracer trace)
strcmp(PROFSYM, s.name) == 0) strcmp(PROFSYM, s.name) == 0)
break; break;
if(pc == retfromnewstack) { if(s.value == morestack) {
stktop = (struct Stktop*)g.stackbase; // In the middle of morestack.
get8(map, (uvlong)&stktop->oldbase, &g.stackbase); // Caller is m->morepc.
get8(map, (uvlong)&stktop->oldguard, &g.stackguard); // Caller's caller is in m->morearg.
get8(map, (uvlong)&stktop->oldsp, &sp); // TODO(rsc): 386
get8(map, sp+8, &pc); geta(map, offsetof(struct UregAmd64, r14), &m);
(*trace)(map, pc, sp + 8, &s1);
sp += 16; // two irrelevant calls on stack - morestack, plus the call morestack made pc = 0;
sp = 0;
pc1 = 0;
s1 = s;
memset(&s, 0, sizeof s);
geta(map, m+1*mach->szaddr, &pc1); // m->morepc
geta(map, m+2*mach->szaddr, &sp); // m->morebuf.sp
geta(map, m+3*mach->szaddr, &pc); // m->morebuf.pc
findsym(pc1, CTEXT, &s);
(*trace)(map, pc1, sp-mach->szaddr, &s1); // morestack symbol; caller's PC/SP
// caller's caller
s1 = s;
findsym(pc, CTEXT, &s);
(*trace)(map, pc, sp, &s1); // morestack's caller; caller's caller's PC/SP
continue;
}
if(pc == lessstack) {
// ../pkg/runtime/runtime.h
// Stktop is
// byte* stackguard
// byte* stackbase
// Gobuf gobuf
// byte* sp;
// byte* pc;
// G* g;
if(!isamd64)
fprint(2, "warning: cannot unwind stack split on 386\n");
if(stktop == 0)
break;
pc = 0;
sp = 0;
geta(map, stktop+2*mach->szaddr, &sp);
geta(map, stktop+3*mach->szaddr, &pc);
geta(map, stktop+1*mach->szaddr, &stktop);
(*trace)(map, pc, sp, &s1);
continue; continue;
} }
s1 = s; s1 = s;
pc1 = 0; pc1 = 0;
if(pc != s.value) { /* not at first instruction */ if(pc != s.value) { /* not at first instruction */
...@@ -227,7 +274,7 @@ i386trace(Map *map, uvlong pc, uvlong sp, uvlong link, Tracer trace) ...@@ -227,7 +274,7 @@ i386trace(Map *map, uvlong pc, uvlong sp, uvlong link, Tracer trace)
if(pc == 0) if(pc == 0)
break; break;
if(pc != retfromnewstack) if(pc != lessstack)
(*trace)(map, pc, sp, &s1); (*trace)(map, pc, sp, &s1);
sp += mach->szaddr; sp += mach->szaddr;
......
...@@ -75,6 +75,7 @@ HFILES=\ ...@@ -75,6 +75,7 @@ HFILES=\
runtime.h\ runtime.h\
hashmap.h\ hashmap.h\
malloc.h\ malloc.h\
$(GOARCH)/asm.h\
$(GOOS)/os.h\ $(GOOS)/os.h\
$(GOOS)/$(GOARCH)/defs.h\ $(GOOS)/$(GOARCH)/defs.h\
......
// Assembly constants
#define g R15
#define m R14
// offsets in m
#define m_g0 0
#define m_morepc 8
#define m_morebuf 16
#define m_morearg 40
#define m_cret 48
#define m_procid 56
#define m_gsignal 64
#define m_tls 72
#define m_sched 104
// offsets in gobuf
#define gobuf_sp 0
#define gobuf_pc 8
#define gobuf_g 16
// offsets in g
#define g_stackguard 0
#define g_stackbase 8
#define g_defer 16
#define g_sched 24
...@@ -2,11 +2,11 @@ ...@@ -2,11 +2,11 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
#include "amd64/asm.h"
TEXT _rt0_amd64(SB),7,$-8 TEXT _rt0_amd64(SB),7,$-8
// copy arguments forward on an even stack // copy arguments forward on an even stack
MOVQ 0(SP), AX // argc MOVQ 0(SP), AX // argc
LEAQ 8(SP), BX // argv LEAQ 8(SP), BX // argv
SUBQ $(4*8+7), SP // 2args 2auto SUBQ $(4*8+7), SP // 2args 2auto
...@@ -15,16 +15,14 @@ TEXT _rt0_amd64(SB),7,$-8 ...@@ -15,16 +15,14 @@ TEXT _rt0_amd64(SB),7,$-8
MOVQ BX, 24(SP) MOVQ BX, 24(SP)
// set the per-goroutine and per-mach registers // set the per-goroutine and per-mach registers
LEAQ m0(SB), m
LEAQ m0(SB), R14 // dedicated m. register LEAQ g0(SB), g
LEAQ g0(SB), R15 // dedicated g. register MOVQ g, m_g0(m) // m has pointer to its g0
MOVQ R15, 0(R14) // m has pointer to its g0
// create istack out of the given (operating system) stack // create istack out of the given (operating system) stack
LEAQ (-8192+104)(SP), AX LEAQ (-8192+104)(SP), AX
MOVQ AX, 0(R15) // 0(R15) is stack limit (w 104b guard) MOVQ AX, g_stackguard(g)
MOVQ SP, 8(R15) // 8(R15) is base MOVQ SP, g_stackbase(g)
CLD // convention is D is always left cleared CLD // convention is D is always left cleared
CALL check(SB) CALL check(SB)
...@@ -39,7 +37,7 @@ TEXT _rt0_amd64(SB),7,$-8 ...@@ -39,7 +37,7 @@ TEXT _rt0_amd64(SB),7,$-8
// create a new goroutine to start program // create a new goroutine to start program
PUSHQ $mainstart(SB) // entry PUSHQ $mainstart(SB) // entry
PUSHQ $16 // arg size PUSHQ $0 // arg size
CALL sys·newproc(SB) CALL sys·newproc(SB)
POPQ AX POPQ AX
POPQ AX POPQ AX
...@@ -67,57 +65,105 @@ TEXT breakpoint(SB),7,$0 ...@@ -67,57 +65,105 @@ TEXT breakpoint(SB),7,$0
/* /*
* go-routine * go-routine
*/ */
TEXT gogo(SB), 7, $0
MOVQ 8(SP), AX // gobuf
MOVQ 0(AX), SP // restore SP
MOVQ 8(AX), AX
MOVQ AX, 0(SP) // put PC on the stack
MOVL $1, AX // return 1
RET
// uintptr gosave(Gobuf*)
// save state in Gobuf; setjmp
TEXT gosave(SB), 7, $0 TEXT gosave(SB), 7, $0
MOVQ 8(SP), AX // gobuf MOVQ 8(SP), AX // gobuf
MOVQ SP, 0(AX) // save SP LEAQ 8(SP), BX // caller's SP
MOVQ 0(SP), BX MOVQ BX, gobuf_sp(AX)
MOVQ BX, 8(AX) // save PC MOVQ 0(SP), BX // caller's PC
MOVQ BX, gobuf_pc(AX)
MOVQ g, gobuf_g(AX)
MOVL $0, AX // return 0 MOVL $0, AX // return 0
RET RET
// void gogo(Gobuf*, uintptr)
// restore state from Gobuf; longjmp
TEXT gogo(SB), 7, $0
MOVQ 16(SP), AX // return 2nd arg
MOVQ 8(SP), BX // gobuf
MOVQ gobuf_g(BX), g
MOVQ 0(g), CX // make sure g != nil
MOVQ gobuf_sp(BX), SP // restore SP
MOVQ gobuf_pc(BX), BX
JMP BX
// void gogocall(Gobuf*, void (*fn)(void))
// restore state from Gobuf but then call fn.
// (call fn, returning to state in Gobuf)
TEXT gogocall(SB), 7, $0
MOVQ 16(SP), AX // fn
MOVQ 8(SP), BX // gobuf
MOVQ gobuf_g(BX), g
MOVQ 0(g), CX // make sure g != nil
MOVQ gobuf_sp(BX), SP // restore SP
MOVQ gobuf_pc(BX), BX
PUSHQ BX
JMP AX
POPQ BX // not reached
/* /*
* support for morestack * support for morestack
*/ */
// Called during function prolog when more stack is needed.
TEXT sys·morestack(SB),7,$0
// Called from f.
// Set m->morebuf to f's caller.
MOVQ 8(SP), AX // f's caller's PC
MOVQ AX, (m_morebuf+gobuf_pc)(m)
LEAQ 16(SP), AX // f's caller's SP
MOVQ AX, (m_morebuf+gobuf_sp)(m)
MOVQ g, (m_morebuf+gobuf_g)(m)
// Set m->morepc to f's PC.
MOVQ 0(SP), AX
MOVQ AX, m_morepc(m)
// Call newstack on m's scheduling stack.
MOVQ m_g0(m), g
MOVQ (m_sched+gobuf_sp)(m), SP
CALL newstack(SB)
MOVQ $0, 0x1003 // crash if newstack returns
RET
// Return point when leaving stack.
TEXT sys·lessstack(SB), 7, $0
// Save return value in m->cret
MOVQ AX, m_cret(m)
// Call oldstack on m's scheduling stack.
MOVQ m_g0(m), g
MOVQ (m_sched+gobuf_sp)(m), SP
CALL oldstack(SB)
MOVQ $0, 0x1004 // crash if oldstack returns
RET
// morestack trampolines // morestack trampolines
TEXT sys·morestack00+0(SB),7,$0 TEXT sys·morestack00+0(SB),7,$0
MOVQ $0, AX MOVQ $0, AX
MOVQ AX, 8(R14) MOVQ AX, m_morearg(m)
MOVQ $sys·morestack+0(SB), AX MOVQ $sys·morestack+0(SB), AX
JMP AX JMP AX
TEXT sys·morestack01+0(SB),7,$0 TEXT sys·morestack01+0(SB),7,$0
SHLQ $32, AX SHLQ $32, AX
MOVQ AX, 8(R14) MOVQ AX, m_morearg(m)
MOVQ $sys·morestack+0(SB), AX MOVQ $sys·morestack+0(SB), AX
JMP AX JMP AX
TEXT sys·morestack10+0(SB),7,$0 TEXT sys·morestack10+0(SB),7,$0
MOVLQZX AX, AX MOVLQZX AX, AX
MOVQ AX, 8(R14) MOVQ AX, m_morearg(m)
MOVQ $sys·morestack+0(SB), AX MOVQ $sys·morestack+0(SB), AX
JMP AX JMP AX
TEXT sys·morestack11+0(SB),7,$0 TEXT sys·morestack11+0(SB),7,$0
MOVQ AX, 8(R14) MOVQ AX, m_morearg(m)
MOVQ $sys·morestack+0(SB), AX MOVQ $sys·morestack+0(SB), AX
JMP AX JMP AX
TEXT sys·morestackx(SB),7,$0
POPQ AX
SHLQ $35, AX
MOVQ AX, 8(R14)
MOVQ $sys·morestack(SB), AX
JMP AX
// subcases of morestack01 // subcases of morestack01
// with const of 8,16,...48 // with const of 8,16,...48
TEXT sys·morestack8(SB),7,$0 TEXT sys·morestack8(SB),7,$0
...@@ -150,31 +196,13 @@ TEXT sys·morestack48(SB),7,$0 ...@@ -150,31 +196,13 @@ TEXT sys·morestack48(SB),7,$0
MOVQ $sys·morestackx(SB), AX MOVQ $sys·morestackx(SB), AX
JMP AX JMP AX
// return point when leaving new stack. save AX, jmp to lessstack to switch back TEXT sys·morestackx(SB),7,$0
TEXT retfromnewstack(SB), 7, $0 POPQ AX
MOVQ AX, 16(R14) // save AX in m->cret SHLQ $35, AX
MOVQ $lessstack(SB), AX MOVQ AX, m_morearg(m)
MOVQ $sys·morestack(SB), AX
JMP AX JMP AX
// gogo, returning 2nd arg instead of 1
TEXT gogoret(SB), 7, $0
MOVQ 16(SP), AX // return 2nd arg
MOVQ 8(SP), BX // gobuf
MOVQ 0(BX), SP // restore SP
MOVQ 8(BX), BX
MOVQ BX, 0(SP) // put PC on the stack
RET
TEXT setspgoto(SB), 7, $0
MOVQ 8(SP), AX // SP
MOVQ 16(SP), BX // fn to call
MOVQ 24(SP), CX // fn to return
MOVQ AX, SP
PUSHQ CX
JMP BX
POPQ AX // not reached
RET
// bool cas(int32 *val, int32 old, int32 new) // bool cas(int32 *val, int32 old, int32 new)
// Atomically: // Atomically:
// if(*val == old){ // if(*val == old){
......
...@@ -24,12 +24,11 @@ traceback(byte *pc0, byte *sp, G *g) ...@@ -24,12 +24,11 @@ traceback(byte *pc0, byte *sp, G *g)
stk = (Stktop*)g->stackbase; stk = (Stktop*)g->stackbase;
for(n=0; n<100; n++) { for(n=0; n<100; n++) {
while(pc == (uint64)retfromnewstack) { if(pc == (uint64)sys·lessstack) {
// pop to earlier stack block // pop to earlier stack block
sp = stk->oldsp; pc = (uintptr)stk->gobuf.pc;
stk = (Stktop*)stk->oldbase; sp = stk->gobuf.sp;
pc = *(uint64*)(sp+8); stk = (Stktop*)stk->stackbase;
sp += 16; // two irrelevant calls on stack: morestack plus its call
} }
f = findfunc(pc); f = findfunc(pc);
if(f == nil) { if(f == nil) {
...@@ -46,8 +45,8 @@ traceback(byte *pc0, byte *sp, G *g) ...@@ -46,8 +45,8 @@ traceback(byte *pc0, byte *sp, G *g)
printf("%p unknown pc\n", pc); printf("%p unknown pc\n", pc);
return; return;
} }
if(f->frame < 8) // assembly funcs say 0 but lie if(f->frame < sizeof(uintptr)) // assembly funcs say 0 but lie
sp += 8; sp += sizeof(uintptr);
else else
sp += f->frame; sp += f->frame;
...@@ -56,7 +55,7 @@ traceback(byte *pc0, byte *sp, G *g) ...@@ -56,7 +55,7 @@ traceback(byte *pc0, byte *sp, G *g)
// main(0x1, 0x2, 0x3) // main(0x1, 0x2, 0x3)
printf("%S", f->name); printf("%S", f->name);
if(pc > f->entry) if(pc > f->entry)
printf("+%X", pc - f->entry); printf("+%p", (uintptr)(pc - f->entry));
printf(" %S:%d\n", f->src, funcline(f, pc-1)); // -1 to get to CALL instr. printf(" %S:%d\n", f->src, funcline(f, pc-1)); // -1 to get to CALL instr.
printf("\t%S(", f->name); printf("\t%S(", f->name);
for(i = 0; i < f->args; i++) { for(i = 0; i < f->args; i++) {
...@@ -70,7 +69,7 @@ traceback(byte *pc0, byte *sp, G *g) ...@@ -70,7 +69,7 @@ traceback(byte *pc0, byte *sp, G *g)
} }
prints(")\n"); prints(")\n");
pc = *(uint64*)(sp-8); pc = *(uintptr*)(sp-sizeof(uintptr));
if(pc <= 0x1000) if(pc <= 0x1000)
return; return;
} }
...@@ -106,20 +105,19 @@ runtime·Caller(int32 n, uint64 retpc, String retfile, int32 retline, bool retbo ...@@ -106,20 +105,19 @@ runtime·Caller(int32 n, uint64 retpc, String retfile, int32 retline, bool retbo
// now unwind n levels // now unwind n levels
stk = (Stktop*)g->stackbase; stk = (Stktop*)g->stackbase;
while(n-- > 0) { while(n-- > 0) {
while(pc == (uint64)retfromnewstack) { while(pc == (uintptr)sys·lessstack) {
sp = stk->oldsp; pc = (uintptr)stk->gobuf.pc;
stk = (Stktop*)stk->oldbase; sp = stk->gobuf.sp;
pc = *(uint64*)(sp+8); stk = (Stktop*)stk->stackbase;
sp += 16;
} }
if(f->frame < 8) // assembly functions lie if(f->frame < sizeof(uintptr)) // assembly functions lie
sp += 8; sp += sizeof(uintptr);
else else
sp += f->frame; sp += f->frame;
loop: loop:
pc = *(uint64*)(sp-8); pc = *((uintptr*)sp - 1);
if(pc <= 0x1000 || (f = findfunc(pc)) == nil) { if(pc <= 0x1000 || (f = findfunc(pc)) == nil) {
// dangerous, but let's try this. // dangerous, but let's try this.
// see if it is a closure. // see if it is a closure.
......
...@@ -8,6 +8,8 @@ ...@@ -8,6 +8,8 @@
// or /usr/include/sys/syscall.h (on a Mac) for system call numbers. // or /usr/include/sys/syscall.h (on a Mac) for system call numbers.
// //
#include "amd64/asm.h"
// Exit the entire program (like C exit) // Exit the entire program (like C exit)
TEXT exit(SB),7,$-8 TEXT exit(SB),7,$-8
MOVL 8(SP), DI // arg 1 exit status MOVL 8(SP), DI // arg 1 exit status
...@@ -25,8 +27,8 @@ TEXT exit1(SB),7,$-8 ...@@ -25,8 +27,8 @@ TEXT exit1(SB),7,$-8
CALL notok(SB) CALL notok(SB)
RET RET
TEXT sys·write(SB),7,$-8 TEXT write(SB),7,$-8
MOVL 8(SP), DI // arg 1 fid MOVL 8(SP), DI // arg 1 fd
MOVQ 16(SP), SI // arg 2 buf MOVQ 16(SP), SI // arg 2 buf
MOVL 24(SP), DX // arg 3 count MOVL 24(SP), DX // arg 3 count
MOVL $(0x2000000+4), AX // syscall entry MOVL $(0x2000000+4), AX // syscall entry
...@@ -35,44 +37,6 @@ TEXT sys·write(SB),7,$-8 ...@@ -35,44 +37,6 @@ TEXT sys·write(SB),7,$-8
CALL notok(SB) CALL notok(SB)
RET RET
TEXT open(SB),7,$-8
MOVQ 8(SP), DI
MOVL 16(SP), SI
MOVL 20(SP), DX
MOVQ $0, R10
MOVL $(0x2000000+5), AX // syscall entry
SYSCALL
RET
TEXT close(SB),7,$-8
MOVL 8(SP), DI
MOVL $(0x2000000+6), AX // syscall entry
SYSCALL
RET
TEXT fstat(SB),7,$-8
MOVL 8(SP), DI
MOVQ 16(SP), SI
MOVL $(0x2000000+339), AX // syscall entry; really fstat64
SYSCALL
RET
TEXT read(SB),7,$-8
MOVL 8(SP), DI
MOVQ 16(SP), SI
MOVL 24(SP), DX
MOVL $(0x2000000+3), AX // syscall entry
SYSCALL
RET
TEXT write(SB),7,$-8
MOVL 8(SP), DI
MOVQ 16(SP), SI
MOVL 24(SP), DX
MOVL $(0x2000000+4), AX // syscall entry
SYSCALL
RET
TEXT sigaction(SB),7,$-8 TEXT sigaction(SB),7,$-8
MOVL 8(SP), DI // arg 1 sig MOVL 8(SP), DI // arg 1 sig
MOVQ 16(SP), SI // arg 2 act MOVQ 16(SP), SI // arg 2 act
...@@ -86,10 +50,10 @@ TEXT sigaction(SB),7,$-8 ...@@ -86,10 +50,10 @@ TEXT sigaction(SB),7,$-8
RET RET
TEXT sigtramp(SB),7,$40 TEXT sigtramp(SB),7,$40
MOVQ 32(R14), R15 // g = m->gsignal MOVQ m_gsignal(m), g
MOVL DX,0(SP) MOVL DX, 0(SP)
MOVQ CX,8(SP) MOVQ CX, 8(SP)
MOVQ R8,16(SP) MOVQ R8, 16(SP)
MOVQ R8, 24(SP) // save ucontext MOVQ R8, 24(SP) // save ucontext
MOVQ SI, 32(SP) // save infostyle MOVQ SI, 32(SP) // save infostyle
CALL DI CALL DI
...@@ -154,9 +118,9 @@ TEXT bsdthread_create(SB),7,$-8 ...@@ -154,9 +118,9 @@ TEXT bsdthread_create(SB),7,$-8
// The ones in quotes pass through to the thread callback // The ones in quotes pass through to the thread callback
// uninterpreted, so we can put whatever we want there. // uninterpreted, so we can put whatever we want there.
MOVQ fn+32(SP), DI // "func" MOVQ fn+32(SP), DI // "func"
MOVQ m+16(SP), SI // "arg" MOVQ mm+16(SP), SI // "arg"
MOVQ stk+8(SP), DX // stack MOVQ stk+8(SP), DX // stack
MOVQ g+24(SP), R10 // "pthread" MOVQ gg+24(SP), R10 // "pthread"
// TODO(rsc): why do we get away with 0 flags here but not on 386? // TODO(rsc): why do we get away with 0 flags here but not on 386?
MOVQ $0, R8 // flags MOVQ $0, R8 // flags
MOVQ $(0x2000000+360), AX // bsdthread_create MOVQ $(0x2000000+360), AX // bsdthread_create
...@@ -176,9 +140,9 @@ TEXT bsdthread_create(SB),7,$-8 ...@@ -176,9 +140,9 @@ TEXT bsdthread_create(SB),7,$-8
// R9 = flags (= 0) // R9 = flags (= 0)
// SP = stack - C_64_REDZONE_LEN (= stack - 128) // SP = stack - C_64_REDZONE_LEN (= stack - 128)
TEXT bsdthread_start(SB),7,$-8 TEXT bsdthread_start(SB),7,$-8
MOVQ CX, R14 // m MOVQ CX, m
MOVQ DI, R15 // g MOVQ DI, g
MOVQ SI, 24(R14) // thread port is m->procid MOVQ SI, m_procid(m) // thread port is m->procid
CALL DX // fn CALL DX // fn
CALL exit1(SB) CALL exit1(SB)
RET RET
......
...@@ -6,6 +6,8 @@ ...@@ -6,6 +6,8 @@
// System calls and other sys.stuff for AMD64, Linux // System calls and other sys.stuff for AMD64, Linux
// //
#include "amd64/asm.h"
TEXT exit(SB),7,$0-8 TEXT exit(SB),7,$0-8
MOVL 8(SP), DI MOVL 8(SP), DI
MOVL $231, AX // exitgroup - force all os threads to exi MOVL $231, AX // exitgroup - force all os threads to exi
...@@ -26,27 +28,6 @@ TEXT open(SB),7,$0-16 ...@@ -26,27 +28,6 @@ TEXT open(SB),7,$0-16
SYSCALL SYSCALL
RET RET
TEXT close(SB),7,$0-8
MOVL 8(SP), DI
MOVL $3, AX // syscall entry
SYSCALL
RET
TEXT fstat(SB),7,$0-16
MOVL 8(SP), DI
MOVQ 16(SP), SI
MOVL $5, AX // syscall entry
SYSCALL
RET
TEXT read(SB),7,$0-24
MOVL 8(SP), DI
MOVQ 16(SP), SI
MOVL 24(SP), DX
MOVL $0, AX // syscall entry
SYSCALL
RET
TEXT write(SB),7,$0-24 TEXT write(SB),7,$0-24
MOVL 8(SP), DI MOVL 8(SP), DI
MOVQ 16(SP), SI MOVQ 16(SP), SI
...@@ -73,10 +54,10 @@ TEXT rt_sigaction(SB),7,$0-32 ...@@ -73,10 +54,10 @@ TEXT rt_sigaction(SB),7,$0-32
RET RET
TEXT sigtramp(SB),7,$24-16 TEXT sigtramp(SB),7,$24-16
MOVQ 32(R14), R15 // g = m->gsignal MOVQ m_gsignal(m), g
MOVQ DI,0(SP) MOVQ DI, 0(SP)
MOVQ SI,8(SP) MOVQ SI, 8(SP)
MOVQ DX,16(SP) MOVQ DX, 16(SP)
CALL sighandler(SB) CALL sighandler(SB)
RET RET
...@@ -151,8 +132,8 @@ TEXT clone(SB),7,$0 ...@@ -151,8 +132,8 @@ TEXT clone(SB),7,$0
// Copy m, g, fn off parent stack for use by child. // Copy m, g, fn off parent stack for use by child.
// Careful: Linux system call clobbers CX and R11. // Careful: Linux system call clobbers CX and R11.
MOVQ m+24(SP), R8 MOVQ mm+24(SP), R8
MOVQ g+32(SP), R9 MOVQ gg+32(SP), R9
MOVQ fn+40(SP), R12 MOVQ fn+40(SP), R12
MOVL $56, AX MOVL $56, AX
...@@ -165,13 +146,13 @@ TEXT clone(SB),7,$0 ...@@ -165,13 +146,13 @@ TEXT clone(SB),7,$0
// In child, set up new stack // In child, set up new stack
MOVQ SI, SP MOVQ SI, SP
MOVQ R8, R14 // m MOVQ R8, m
MOVQ R9, R15 // g MOVQ R9, g
// Initialize m->procid to Linux tid // Initialize m->procid to Linux tid
MOVL $186, AX // gettid MOVL $186, AX // gettid
SYSCALL SYSCALL
MOVQ AX, 24(R14) MOVQ AX, m_procid(m)
// Call fn // Call fn
CALL R12 CALL R12
......
...@@ -66,12 +66,12 @@ scanstack(G *g) ...@@ -66,12 +66,12 @@ scanstack(G *g)
Stktop *stk; Stktop *stk;
byte *sp; byte *sp;
sp = g->sched.SP; sp = g->sched.sp;
stk = (Stktop*)g->stackbase; stk = (Stktop*)g->stackbase;
while(stk) { while(stk) {
scanblock(0, sp, (byte*)stk - sp); scanblock(0, sp, (byte*)stk - sp);
sp = stk->oldsp; sp = stk->gobuf.sp;
stk = (Stktop*)stk->oldbase; stk = (Stktop*)stk->stackbase;
} }
} }
......
...@@ -25,7 +25,7 @@ dump(byte *p, int32 n) ...@@ -25,7 +25,7 @@ dump(byte *p, int32 n)
void void
prints(int8 *s) prints(int8 *s)
{ {
sys·write(1, s, findnull((byte*)s)); write(1, s, findnull((byte*)s));
} }
// Very simple printf. Only for debugging prints. // Very simple printf. Only for debugging prints.
...@@ -42,7 +42,7 @@ printf(int8 *s, ...) ...@@ -42,7 +42,7 @@ printf(int8 *s, ...)
if(*p != '%') if(*p != '%')
continue; continue;
if(p > lp) if(p > lp)
sys·write(1, lp, p-lp); write(1, lp, p-lp);
p++; p++;
narg = nil; narg = nil;
switch(*p) { switch(*p) {
...@@ -95,7 +95,7 @@ printf(int8 *s, ...) ...@@ -95,7 +95,7 @@ printf(int8 *s, ...)
lp = p+1; lp = p+1;
} }
if(p > lp) if(p > lp)
sys·write(1, lp, p-lp); write(1, lp, p-lp);
} }
...@@ -110,10 +110,10 @@ void ...@@ -110,10 +110,10 @@ void
sys·printbool(bool v) sys·printbool(bool v)
{ {
if(v) { if(v) {
sys·write(1, (byte*)"true", 4); write(1, (byte*)"true", 4);
return; return;
} }
sys·write(1, (byte*)"false", 5); write(1, (byte*)"false", 5);
} }
void void
...@@ -124,15 +124,15 @@ sys·printfloat(float64 v) ...@@ -124,15 +124,15 @@ sys·printfloat(float64 v)
float64 h; float64 h;
if(isNaN(v)) { if(isNaN(v)) {
sys·write(1, "NaN", 3); write(1, "NaN", 3);
return; return;
} }
if(isInf(v, 0)) { if(isInf(v, 0)) {
sys·write(1, "+Inf", 4); write(1, "+Inf", 4);
return; return;
} }
if(isInf(v, -1)) { if(isInf(v, -1)) {
sys·write(1, "+Inf", 4); write(1, "+Inf", 4);
return; return;
} }
...@@ -191,7 +191,7 @@ sys·printfloat(float64 v) ...@@ -191,7 +191,7 @@ sys·printfloat(float64 v)
buf[n+4] = (e/100) + '0'; buf[n+4] = (e/100) + '0';
buf[n+5] = (e/10)%10 + '0'; buf[n+5] = (e/10)%10 + '0';
buf[n+6] = (e%10) + '0'; buf[n+6] = (e%10) + '0';
sys·write(1, buf, n+7); write(1, buf, n+7);
} }
void void
...@@ -206,14 +206,14 @@ sys·printuint(uint64 v) ...@@ -206,14 +206,14 @@ sys·printuint(uint64 v)
break; break;
v = v/10; v = v/10;
} }
sys·write(1, buf+i, nelem(buf)-i); write(1, buf+i, nelem(buf)-i);
} }
void void
sys·printint(int64 v) sys·printint(int64 v)
{ {
if(v < 0) { if(v < 0) {
sys·write(1, "-", 1); write(1, "-", 1);
v = -v; v = -v;
} }
sys·printuint(v); sys·printuint(v);
...@@ -233,7 +233,7 @@ sys·printhex(uint64 v) ...@@ -233,7 +233,7 @@ sys·printhex(uint64 v)
buf[--i] = '0'; buf[--i] = '0';
buf[--i] = 'x'; buf[--i] = 'x';
buf[--i] = '0'; buf[--i] = '0';
sys·write(1, buf+i, nelem(buf)-i); write(1, buf+i, nelem(buf)-i);
} }
void void
...@@ -248,21 +248,21 @@ sys·printstring(String v) ...@@ -248,21 +248,21 @@ sys·printstring(String v)
extern int32 maxstring; extern int32 maxstring;
if(v.len > maxstring) { if(v.len > maxstring) {
sys·write(1, "[invalid string]", 16); write(1, "[invalid string]", 16);
return; return;
} }
if(v.len > 0) if(v.len > 0)
sys·write(1, v.str, v.len); write(1, v.str, v.len);
} }
void void
sys·printsp(void) sys·printsp(void)
{ {
sys·write(1, " ", 1); write(1, " ", 1);
} }
void void
sys·printnl(void) sys·printnl(void)
{ {
sys·write(1, "\n", 1); write(1, "\n", 1);
} }
...@@ -149,7 +149,7 @@ tracebackothers(G *me) ...@@ -149,7 +149,7 @@ tracebackothers(G *me)
if(g == me || g->status == Gdead) if(g == me || g->status == Gdead)
continue; continue;
printf("\ngoroutine %d:\n", g->goid); printf("\ngoroutine %d:\n", g->goid);
traceback(g->sched.PC, g->sched.SP+sizeof(uintptr), g); // gogo adjusts SP by one word traceback(g->sched.pc, g->sched.sp, g);
} }
} }
...@@ -387,7 +387,7 @@ matchmg(void) ...@@ -387,7 +387,7 @@ matchmg(void)
m->id = sched.mcount++; m->id = sched.mcount++;
if(debug) { if(debug) {
lock(&debuglock); lock(&debuglock);
printf("alloc m%d g%d\n", m->id, g->goid); printf("alloc m=%p m%d g%d\n", m, m->id, g->goid);
unlock(&debuglock); unlock(&debuglock);
} }
newosproc(m, m->g0, m->g0->stackbase, mstart); newosproc(m, m->g0, m->g0->stackbase, mstart);
...@@ -402,7 +402,7 @@ scheduler(void) ...@@ -402,7 +402,7 @@ scheduler(void)
G* gp; G* gp;
lock(&sched); lock(&sched);
if(gosave(&m->sched)){ if(gosave(&m->sched) != 0){
// Jumped here via gosave/gogo, so didn't // Jumped here via gosave/gogo, so didn't
// execute lock(&sched) above. // execute lock(&sched) above.
lock(&sched); lock(&sched);
...@@ -446,14 +446,15 @@ scheduler(void) ...@@ -446,14 +446,15 @@ scheduler(void)
gp->status = Grunning; gp->status = Grunning;
if(debug > 1) { if(debug > 1) {
lock(&debuglock); lock(&debuglock);
printf("m%d run g%d at %p\n", m->id, gp->goid, gp->sched.PC); printf("m%d run g%d at %p\n", m->id, gp->goid, gp->sched.pc);
traceback(gp->sched.PC, gp->sched.SP+sizeof(uintptr), gp); traceback(gp->sched.pc, gp->sched.sp, gp);
unlock(&debuglock); unlock(&debuglock);
} }
m->curg = gp; m->curg = gp;
gp->m = m; gp->m = m;
g = gp; if(gp->sched.pc == (byte*)goexit) // kickoff
gogo(&gp->sched); gogocall(&gp->sched, (void(*)(void))gp->entry);
gogo(&gp->sched, 1);
} }
// Enter scheduler. If g->status is Grunning, // Enter scheduler. If g->status is Grunning,
...@@ -465,10 +466,8 @@ gosched(void) ...@@ -465,10 +466,8 @@ gosched(void)
{ {
if(g == m->g0) if(g == m->g0)
throw("gosched of g0"); throw("gosched of g0");
if(gosave(&g->sched) == 0){ if(gosave(&g->sched) == 0)
g = m->g0; gogo(&m->sched, 1);
gogo(&m->sched);
}
} }
// The goroutine g is about to enter a system call. // The goroutine g is about to enter a system call.
...@@ -606,53 +605,28 @@ enum ...@@ -606,53 +605,28 @@ enum
void void
oldstack(void) oldstack(void)
{ {
Stktop *top; Stktop *top, old;
uint32 args; uint32 args;
byte *sp; byte *sp;
uintptr oldsp, oldpc, oldbase, oldguard; G *g1;
// printf("oldstack m->cret=%p\n", m->cret);
top = (Stktop*)m->curg->stackbase;
args = (top->magic>>32) & 0xffffLL; //printf("oldstack m->cret=%p\n", m->cret);
g1 = m->curg;
top = (Stktop*)g1->stackbase;
sp = (byte*)top; sp = (byte*)top;
old = *top;
args = old.args;
if(args > 0) { if(args > 0) {
args = (args+7) & ~7;
sp -= args; sp -= args;
mcpy(top->oldsp+2*sizeof(uintptr), sp, args); mcpy(top->gobuf.sp, sp, args);
} }
oldsp = (uintptr)top->oldsp + sizeof(uintptr); stackfree((byte*)g1->stackguard - StackGuard);
oldpc = *(uintptr*)oldsp; g1->stackbase = old.stackbase;
oldbase = (uintptr)top->oldbase; g1->stackguard = old.stackguard;
oldguard = (uintptr)top->oldguard;
stackfree((byte*)m->curg->stackguard - StackGuard);
m->curg->stackbase = (byte*)oldbase;
m->curg->stackguard = (byte*)oldguard;
m->morestack.SP = (byte*)oldsp;
m->morestack.PC = (byte*)oldpc;
// These two lines must happen in sequence;
// once g has been changed, must switch to g's stack
// before calling any non-assembly functions.
// TODO(rsc): Perhaps make the new g a parameter
// to gogoret and setspgoto, so that g is never
// explicitly assigned to without also setting
// the stack pointer.
g = m->curg;
gogoret(&m->morestack, m->cret);
}
#pragma textflag 7 gogo(&old.gobuf, m->cret);
void
lessstack(void)
{
g = m->g0;
setspgoto(m->sched.SP, oldstack, nil);
} }
void void
...@@ -661,75 +635,49 @@ newstack(void) ...@@ -661,75 +635,49 @@ newstack(void)
int32 frame, args; int32 frame, args;
Stktop *top; Stktop *top;
byte *stk, *sp; byte *stk, *sp;
void (*fn)(void); G *g1;
Gobuf label;
frame = m->morearg & 0xffffffffLL;
args = (m->morearg>>32) & 0xffffLL;
// printf("newstack frame=%d args=%d moresp=%p morepc=%p\n", frame, args, m->moresp, *(uintptr*)m->moresp); frame = m->moreframe;
args = m->moreargs;
// Round up to align things nicely.
// This is sufficient for both 32- and 64-bit machines.
args = (args+7) & ~7;
if(frame < StackBig) if(frame < StackBig)
frame = StackBig; frame = StackBig;
frame += 1024; // for more functions, Stktop. frame += 1024; // for more functions, Stktop.
stk = stackalloc(frame); stk = stackalloc(frame);
top = (Stktop*)(stk+frame-sizeof(*top)); //printf("newstack frame=%d args=%d morepc=%p gobuf=%p, %p newstk=%p\n", frame, args, m->morepc, g->sched.pc, g->sched.sp, stk);
top->oldbase = m->curg->stackbase; g1 = m->curg;
top->oldguard = m->curg->stackguard; top = (Stktop*)(stk+frame-sizeof(*top));
top->oldsp = m->moresp; top->stackbase = g1->stackbase;
top->magic = m->morearg; top->stackguard = g1->stackguard;
top->gobuf = m->morebuf;
top->args = args;
m->curg->stackbase = (byte*)top; g1->stackbase = (byte*)top;
m->curg->stackguard = stk + StackGuard; g1->stackguard = stk + StackGuard;
sp = (byte*)top; sp = (byte*)top;
if(args > 0) { if(args > 0) {
// Copy args. There have been two function calls
// since they got pushed, so skip over those return
// addresses.
args = (args+7) & ~7;
sp -= args; sp -= args;
mcpy(sp, m->moresp+2*sizeof(uintptr), args); mcpy(sp, top->gobuf.sp, args);
} }
g = m->curg; // Continue as if lessstack had just called m->morepc
// (the PC that decided to grow the stack).
// sys.morestack's return address label.sp = sp;
fn = (void(*)(void))(*(uintptr*)m->moresp); label.pc = (byte*)sys·lessstack;
label.g = m->curg;
// printf("fn=%p\n", fn); gogocall(&label, m->morepc);
setspgoto(sp, fn, retfromnewstack);
*(int32*)345 = 123; // never return *(int32*)345 = 123; // never return
} }
#pragma textflag 7
void
sys·morestack(uintptr u)
{
while(g == m->g0) {
// very bad news
*(int32*)0x1001 = 123;
}
// Morestack's frame is about 0x30 bytes on amd64.
// If that the frame ends below the stack bottom, we've already
// overflowed. Stop right now.
while((byte*)&u - 0x30 < m->curg->stackguard - StackGuard) {
// very bad news
*(int32*)0x1002 = 123;
}
g = m->g0;
m->moresp = (byte*)(&u-1);
setspgoto(m->sched.SP, newstack, nil);
*(int32*)0x1003 = 123; // never return
}
G* G*
malg(int32 stacksize) malg(int32 stacksize)
{ {
...@@ -786,12 +734,10 @@ sys·newproc(int32 siz, byte* fn, byte* arg0) ...@@ -786,12 +734,10 @@ sys·newproc(int32 siz, byte* fn, byte* arg0)
sp -= siz; sp -= siz;
mcpy(sp, (byte*)&arg0, siz); mcpy(sp, (byte*)&arg0, siz);
sp -= sizeof(uintptr); newg->sched.sp = sp;
*(byte**)sp = (byte*)goexit; newg->sched.pc = (byte*)goexit;
newg->sched.g = newg;
sp -= sizeof(uintptr); // retpc used by gogo newg->entry = fn;
newg->sched.SP = sp;
newg->sched.PC = fn;
sched.gcount++; sched.gcount++;
goidgen++; goidgen++;
......
...@@ -134,16 +134,25 @@ struct Array ...@@ -134,16 +134,25 @@ struct Array
}; };
struct Gobuf struct Gobuf
{ {
byte* SP; // Offsets of fields in this struct are known to assembly.
byte* PC; // Any changes made here must be reflected in */asm.h.
// The debuggers also know the layout of this struct.
byte* sp;
byte* pc;
G* g;
}; };
struct G struct G
{ {
byte* stackguard; // must not move // Offsets of fields in this block are known to assembly.
byte* stackbase; // must not move // Any changes made here must be reflected in */asm.h.
Defer* defer; // must not move byte* stackguard; // cannot move - also known to linker, debuggers
byte* stackbase; // cannot move - also known to debuggers
Defer* defer;
Gobuf sched; // cannot move - also known to debuggers
// Fields not known to assembly.
byte* stack0; // first stack segment byte* stack0; // first stack segment
Gobuf sched; byte* entry; // initial function
G* alllink; // on allg G* alllink; // on allg
void* param; // passed parameter on wakeup void* param; // passed parameter on wakeup
int16 status; int16 status;
...@@ -151,7 +160,7 @@ struct G ...@@ -151,7 +160,7 @@ struct G
int32 selgen; // valid sudog pointer int32 selgen; // valid sudog pointer
G* schedlink; G* schedlink;
bool readyonstop; bool readyonstop;
M* m; // for debuggers M* m; // for debuggers, but offset not hard-coded
}; };
struct Mem struct Mem
{ {
...@@ -162,19 +171,24 @@ struct Mem ...@@ -162,19 +171,24 @@ struct Mem
}; };
struct M struct M
{ {
G* g0; // g0 w interrupt stack - must not move // Offsets of fields in this block are known to assembly.
uint64 morearg; // arg to morestack - must not move // Any changes made here must be reflected in */asm.h.
uint64 cret; // return value from C - must not move // These are known to debuggers.
uint64 procid; // for debuggers - must not move G* g0; // goroutine with scheduling stack
G* gsignal; // signal-handling G - must not move void (*morepc)(void);
G* curg; // current running goroutine - must not move Gobuf morebuf; // gobuf arg to morestack
G* lastg; // last running goroutine - to emulate fifo - must not move
uint32 tls[8]; // thread-local storage (for 386 extern register) - must not move // Known to assembly, but not to debuggers.
Gobuf sched; uint32 moreframe; // size arguments to morestack
Gobuf morestack; uint32 moreargs;
byte* moresp; uintptr cret; // return value from C
int32 siz1; uint64 procid; // for debuggers, but offset not hard-coded
int32 siz2; G* gsignal; // signal-handling G
uint32 tls[8]; // thread-local storage (for 386 extern register)
Gobuf sched; // scheduling stack
G* curg; // current running goroutine
// Fields not known to assembly.
int32 id; int32 id;
int32 mallocing; int32 mallocing;
int32 gcing; int32 gcing;
...@@ -188,10 +202,11 @@ struct M ...@@ -188,10 +202,11 @@ struct M
}; };
struct Stktop struct Stktop
{ {
uint8* oldbase; // The debuggers know the layout of this struct.
uint8* oldsp; uint8* stackguard;
uint64 magic; uint8* stackbase;
uint8* oldguard; Gobuf gobuf;
uint32 args;
}; };
struct Alg struct Alg
{ {
...@@ -287,12 +302,11 @@ int32 charntorune(int32*, uint8*, int32); ...@@ -287,12 +302,11 @@ int32 charntorune(int32*, uint8*, int32);
/* /*
* very low level c-called * very low level c-called
*/ */
int32 gogo(Gobuf*); void gogo(Gobuf*, uintptr);
int32 gosave(Gobuf*); void gogocall(Gobuf*, void(*)(void));
int32 gogoret(Gobuf*, uint64); uintptr gosave(Gobuf*);
void retfromnewstack(void); void sys·lessstack(void);
void goargs(void); void goargs(void);
void setspgoto(byte*, void(*)(void), void(*)(void));
void FLUSH(void*); void FLUSH(void*);
void* getu(void); void* getu(void);
void throw(int8*); void throw(int8*);
...@@ -311,10 +325,7 @@ int32 gotraceback(void); ...@@ -311,10 +325,7 @@ int32 gotraceback(void);
void traceback(uint8 *pc, uint8 *sp, G* gp); void traceback(uint8 *pc, uint8 *sp, G* gp);
void tracebackothers(G*); void tracebackothers(G*);
int32 open(byte*, int32, ...); int32 open(byte*, int32, ...);
int32 read(int32, void*, int32);
int32 write(int32, void*, int32); int32 write(int32, void*, int32);
void close(int32);
int32 fstat(int32, void*);
bool cas(uint32*, uint32, uint32); bool cas(uint32*, uint32, uint32);
void jmpdefer(byte*, void*); void jmpdefer(byte*, void*);
void exit1(int32); void exit1(int32);
...@@ -395,7 +406,6 @@ void notewakeup(Note*); ...@@ -395,7 +406,6 @@ void notewakeup(Note*);
*/ */
#ifndef __GNUC__ #ifndef __GNUC__
#define sys_memclr sys·memclr #define sys_memclr sys·memclr
#define sys_write sys·write
#define sys_catstring sys·catstring #define sys_catstring sys·catstring
#define sys_cmpstring sys·cmpstring #define sys_cmpstring sys·cmpstring
#define sys_getcallerpc sys·getcallerpc #define sys_getcallerpc sys·getcallerpc
...@@ -421,7 +431,6 @@ void notewakeup(Note*); ...@@ -421,7 +431,6 @@ void notewakeup(Note*);
/* /*
* low level go-called * low level go-called
*/ */
void sys_write(int32, void*, int32);
uint8* sys_mmap(byte*, uint32, int32, int32, int32, uint32); uint8* sys_mmap(byte*, uint32, int32, int32, int32, uint32);
void sys_memclr(byte*, uint32); void sys_memclr(byte*, uint32);
void sys_setcallerpc(void*, void*); void sys_setcallerpc(void*, void*);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment