aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/cmd/6g/gsubr.c5
-rw-r--r--src/cmd/6g/reg.c3
-rw-r--r--src/liblink/go.c2
-rw-r--r--src/liblink/obj6.c52
-rw-r--r--src/runtime/arch1_amd64.go2
-rw-r--r--src/runtime/asm_amd64.s26
-rw-r--r--src/runtime/cgocall.go5
-rw-r--r--src/runtime/proc1.go3
-rw-r--r--src/runtime/runtime2.go1
-rw-r--r--src/runtime/stack1.go17
-rw-r--r--src/runtime/traceback.go6
11 files changed, 114 insertions, 8 deletions
diff --git a/src/cmd/6g/gsubr.c b/src/cmd/6g/gsubr.c
index ee6852d6f6..1e996ae162 100644
--- a/src/cmd/6g/gsubr.c
+++ b/src/cmd/6g/gsubr.c
@@ -285,6 +285,9 @@ ginit(void)
if(nacl) {
reg[REG_BP]++;
reg[REG_R15]++;
+ } else if(framepointer_enabled) {
+ // BP is part of the calling convention of framepointer_enabled.
+ reg[REG_BP]++;
}
}
@@ -298,6 +301,8 @@ gclean(void)
if(nacl) {
reg[REG_BP]--;
reg[REG_R15]--;
+ } else if(framepointer_enabled) {
+ reg[REG_BP]--;
}
diff --git a/src/cmd/6g/reg.c b/src/cmd/6g/reg.c
index 2581128b58..7db44245f1 100644
--- a/src/cmd/6g/reg.c
+++ b/src/cmd/6g/reg.c
@@ -1186,6 +1186,9 @@ BtoR(uint32 b)
b &= 0xffffL;
if(nacl)
b &= ~((1<<(REG_BP-REG_AX)) | (1<<(REG_R15-REG_AX)));
+ else if(framepointer_enabled)
+ // BP is part of the calling convention if framepointer_enabled.
+ b &= ~(1<<(REG_BP-REG_AX));
if(b == 0)
return 0;
return bitno(b) + REG_AX;
diff --git a/src/liblink/go.c b/src/liblink/go.c
index e31c71ab92..3bc780b852 100644
--- a/src/liblink/go.c
+++ b/src/liblink/go.c
@@ -21,7 +21,7 @@ static struct {
int *val;
} exper[] = {
{"fieldtrack", &fieldtrack_enabled},
- {"basepointer", &framepointer_enabled},
+ {"framepointer", &framepointer_enabled},
};
static void
diff --git a/src/liblink/obj6.c b/src/liblink/obj6.c
index 696026300c..0ccb03924f 100644
--- a/src/liblink/obj6.c
+++ b/src/liblink/obj6.c
@@ -379,7 +379,7 @@ preprocess(Link *ctxt, LSym *cursym)
{
Prog *p, *q, *p1, *p2;
int32 autoffset, deltasp;
- int a, pcsize;
+ int a, pcsize, bpsize;
vlong textstksiz, textarg;
if(ctxt->tlsg == nil)
@@ -403,6 +403,18 @@ preprocess(Link *ctxt, LSym *cursym)
if(autoffset < 0)
autoffset = 0;
+ if(framepointer_enabled && autoffset > 0) {
+ // Make room for to save a base pointer. If autoffset == 0,
+ // this might do something special like a tail jump to
+ // another function, so in that case we omit this.
+ bpsize = ctxt->arch->ptrsize;
+ autoffset += bpsize;
+ textstksiz += bpsize;
+ p->to.offset = ((uint64)p->to.offset & (0xffffffffull<<32)) | (uint32)autoffset;
+ } else {
+ bpsize = 0;
+ }
+
cursym->args = p->to.offset>>32;
cursym->locals = textstksiz;
@@ -447,6 +459,28 @@ preprocess(Link *ctxt, LSym *cursym)
if(q != nil)
q->pcond = p;
deltasp = autoffset;
+
+ if(bpsize > 0) {
+ // Save caller's BP
+ p = appendp(ctxt, p);
+ p->as = AMOVQ;
+ p->from.type = TYPE_REG;
+ p->from.reg = REG_BP;
+ p->to.type = TYPE_MEM;
+ p->to.reg = REG_SP;
+ p->to.scale = 1;
+ p->to.offset = autoffset - bpsize;
+
+ // Move current frame to BP
+ p = appendp(ctxt, p);
+ p->as = ALEAQ;
+ p->from.type = TYPE_MEM;
+ p->from.reg = REG_SP;
+ p->from.scale = 1;
+ p->from.offset = autoffset - bpsize;
+ p->to.type = TYPE_REG;
+ p->to.reg = REG_BP;
+ }
if(cursym->text->from.scale & WRAPPER) {
// if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame
@@ -580,12 +614,12 @@ preprocess(Link *ctxt, LSym *cursym)
pcsize = p->mode/8;
a = p->from.name;
if(a == NAME_AUTO)
- p->from.offset += deltasp;
+ p->from.offset += deltasp - bpsize;
if(a == NAME_PARAM)
p->from.offset += deltasp + pcsize;
a = p->to.name;
if(a == NAME_AUTO)
- p->to.offset += deltasp;
+ p->to.offset += deltasp - bpsize;
if(a == NAME_PARAM)
p->to.offset += deltasp + pcsize;
@@ -630,6 +664,18 @@ preprocess(Link *ctxt, LSym *cursym)
ctxt->diag("unbalanced PUSH/POP");
if(autoffset) {
+ if(bpsize > 0) {
+ // Restore caller's BP
+ p->as = AMOVQ;
+ p->from.type = TYPE_MEM;
+ p->from.reg = REG_SP;
+ p->from.scale = 1;
+ p->from.offset = autoffset - bpsize;
+ p->to.type = TYPE_REG;
+ p->to.reg = REG_BP;
+ p = appendp(ctxt, p);
+ }
+
p->as = AADJSP;
p->from.type = TYPE_CONST;
p->from.offset = -autoffset;
diff --git a/src/runtime/arch1_amd64.go b/src/runtime/arch1_amd64.go
index 794b7f65c4..7a7f3e75fc 100644
--- a/src/runtime/arch1_amd64.go
+++ b/src/runtime/arch1_amd64.go
@@ -8,7 +8,7 @@ const (
thechar = '6'
_BigEndian = 0
_CacheLineSize = 64
- _RuntimeGogoBytes = 64 + (goos_plan9|goos_solaris|goos_windows)*16
+ _RuntimeGogoBytes = 80 + (goos_plan9|goos_solaris|goos_windows)*16
_PhysPageSize = 4096
_PCQuantum = 1
_Int64Align = 8
diff --git a/src/runtime/asm_amd64.s b/src/runtime/asm_amd64.s
index b1bf4ca987..f09e5ae250 100644
--- a/src/runtime/asm_amd64.s
+++ b/src/runtime/asm_amd64.s
@@ -134,6 +134,7 @@ TEXT runtime·gosave(SB), NOSPLIT, $0-8
MOVQ BX, gobuf_pc(AX)
MOVQ $0, gobuf_ret(AX)
MOVQ $0, gobuf_ctxt(AX)
+ MOVQ BP, gobuf_bp(AX)
get_tls(CX)
MOVQ g(CX), BX
MOVQ BX, gobuf_g(AX)
@@ -150,9 +151,11 @@ TEXT runtime·gogo(SB), NOSPLIT, $0-8
MOVQ gobuf_sp(BX), SP // restore SP
MOVQ gobuf_ret(BX), AX
MOVQ gobuf_ctxt(BX), DX
+ MOVQ gobuf_bp(BX), BP
MOVQ $0, gobuf_sp(BX) // clear to help garbage collector
MOVQ $0, gobuf_ret(BX)
MOVQ $0, gobuf_ctxt(BX)
+ MOVQ $0, gobuf_bp(BX)
MOVQ gobuf_pc(BX), BX
JMP BX
@@ -170,6 +173,7 @@ TEXT runtime·mcall(SB), NOSPLIT, $0-8
LEAQ fn+0(FP), BX // caller's SP
MOVQ BX, (g_sched+gobuf_sp)(AX)
MOVQ AX, (g_sched+gobuf_g)(AX)
+ MOVQ BP, (g_sched+gobuf_bp)(AX)
// switch to m->g0 & its stack, call fn
MOVQ g(CX), BX
@@ -228,6 +232,7 @@ switch:
MOVQ SI, (g_sched+gobuf_pc)(AX)
MOVQ SP, (g_sched+gobuf_sp)(AX)
MOVQ AX, (g_sched+gobuf_g)(AX)
+ MOVQ BP, (g_sched+gobuf_bp)(AX)
// switch to g0
MOVQ DX, g(CX)
@@ -303,6 +308,7 @@ TEXT runtime·morestack(SB),NOSPLIT,$0-0
LEAQ 8(SP), AX // f's SP
MOVQ AX, (g_sched+gobuf_sp)(SI)
MOVQ DX, (g_sched+gobuf_ctxt)(SI)
+ MOVQ BP, (g_sched+gobuf_bp)(SI)
// Call newstack on m->g0's stack.
MOVQ m_g0(BX), BX
@@ -592,6 +598,7 @@ TEXT gosave<>(SB),NOSPLIT,$0
MOVQ R9, (g_sched+gobuf_sp)(R8)
MOVQ $0, (g_sched+gobuf_ret)(R8)
MOVQ $0, (g_sched+gobuf_ctxt)(R8)
+ MOVQ BP, (g_sched+gobuf_bp)(R8)
RET
// asmcgocall(void(*fn)(void*), void *arg)
@@ -747,17 +754,30 @@ havem:
MOVQ (g_sched+gobuf_sp)(SI), DI // prepare stack as DI
MOVQ (g_sched+gobuf_pc)(SI), BX
MOVQ BX, -8(DI)
- LEAQ -(8+8)(DI), SP
+ // Compute the size of the frame, including return PC and, if
+ // GOEXPERIMENT=framepointer, the saved based pointer
+ LEAQ x+0(FP), AX
+ SUBQ SP, AX
+ SUBQ AX, DI
+ MOVQ DI, SP
+
MOVQ R8, 0(SP)
CALL runtime·cgocallbackg(SB)
MOVQ 0(SP), R8
+ // Compute the size of the frame again. FP and SP have
+ // completely different values here than they did above,
+ // but only their difference matters.
+ LEAQ x+0(FP), AX
+ SUBQ SP, AX
+
// Restore g->sched (== m->curg->sched) from saved values.
get_tls(CX)
MOVQ g(CX), SI
- MOVQ 8(SP), BX
+ MOVQ SP, DI
+ ADDQ AX, DI
+ MOVQ -8(DI), BX
MOVQ BX, (g_sched+gobuf_pc)(SI)
- LEAQ (8+8)(SP), DI
MOVQ DI, (g_sched+gobuf_sp)(SI)
// Switch back to m->g0's stack and restore m->g0->sched.sp.
diff --git a/src/runtime/cgocall.go b/src/runtime/cgocall.go
index 96873cc2da..e7aeb7bee3 100644
--- a/src/runtime/cgocall.go
+++ b/src/runtime/cgocall.go
@@ -225,6 +225,11 @@ func cgocallbackg1() {
cb = (*args)(unsafe.Pointer(sp + 4*ptrSize))
case "amd64":
// On amd64, stack frame is one word, plus caller PC.
+ if framepointer_enabled {
+ // In this case, there's also saved BP.
+ cb = (*args)(unsafe.Pointer(sp + 3*ptrSize))
+ break
+ }
cb = (*args)(unsafe.Pointer(sp + 2*ptrSize))
case "386":
// On 386, stack frame is three words, plus caller PC.
diff --git a/src/runtime/proc1.go b/src/runtime/proc1.go
index 8f5aaa8630..31bbd0d366 100644
--- a/src/runtime/proc1.go
+++ b/src/runtime/proc1.go
@@ -113,6 +113,9 @@ func schedinit() {
sched.maxmcount = 10000
+ // Cache the framepointer experiment. This affects stack unwinding.
+ framepointer_enabled = haveexperiment("framepointer")
+
tracebackinit()
symtabinit()
stackinit()
diff --git a/src/runtime/runtime2.go b/src/runtime/runtime2.go
index fd448901a6..e38d11a59d 100644
--- a/src/runtime/runtime2.go
+++ b/src/runtime/runtime2.go
@@ -125,6 +125,7 @@ type gobuf struct {
ctxt unsafe.Pointer // this has to be a pointer so that gc scans it
ret uintreg
lr uintptr
+ bp uintptr // for GOEXPERIMENT=framepointer
}
// Known to compiler.
diff --git a/src/runtime/stack1.go b/src/runtime/stack1.go
index 8ad331777c..1e9ccfebb5 100644
--- a/src/runtime/stack1.go
+++ b/src/runtime/stack1.go
@@ -46,6 +46,9 @@ var stackpoolmu mutex
var stackfreequeue stack
+// Cached value of haveexperiment("framepointer")
+var framepointer_enabled bool
+
func stackinit() {
if _StackCacheSize&_PageMask != 0 {
throw("cache size must be a multiple of page size")
@@ -308,6 +311,8 @@ var mapnames = []string{
// | args from caller |
// +------------------+ <- frame->argp
// | return address |
+// +------------------+
+// | caller's BP (*) | (*) if framepointer_enabled && varp < sp
// +------------------+ <- frame->varp
// | locals |
// +------------------+
@@ -460,6 +465,18 @@ func adjustframe(frame *stkframe, arg unsafe.Pointer) bool {
adjustpointers(unsafe.Pointer(frame.varp-size), &bv, adjinfo, f)
}
+ // Adjust saved base pointer if there is one.
+ if thechar == '6' && frame.argp-frame.varp == 2*ptrSize {
+ if !framepointer_enabled {
+ print("runtime: found space for saved base pointer, but no framepointer experiment")
+ throw("bad frame layout")
+ }
+ if stackDebug >= 3 {
+ print(" saved bp\n")
+ }
+ adjustpointer(adjinfo, unsafe.Pointer(frame.varp))
+ }
+
// Adjust arguments.
if frame.arglen > 0 {
var bv bitvector
diff --git a/src/runtime/traceback.go b/src/runtime/traceback.go
index 499256f42d..c813453399 100644
--- a/src/runtime/traceback.go
+++ b/src/runtime/traceback.go
@@ -232,6 +232,12 @@ func gentraceback(pc0 uintptr, sp0 uintptr, lr0 uintptr, gp *g, skip int, pcbuf
frame.varp -= regSize
}
+ // If framepointer_enabled and there's a frame, then
+ // there's a saved bp here.
+ if GOARCH == "amd64" && frame.varp > frame.sp && framepointer_enabled {
+ frame.varp -= ptrSize
+ }
+
// Derive size of arguments.
// Most functions have a fixed-size argument block,
// so we can use metadata about the function f.