Commit af7ca8dc authored by Austin Clements's avatar Austin Clements

cmd/cgo, runtime/cgo: support ppc64

This implements support for calls to and from C in the ppc64 C ABI, as
well as supporting functionality such as an entry point from the
dynamic linker.

Change-Id: I68da6df50d5638cb1a3d3fef773fb412d7bf631a
Reviewed-on: https://go-review.googlesource.com/2009Reviewed-by: 's avatarRuss Cox <rsc@golang.org>
parent f1c4444d
......@@ -60,6 +60,7 @@ func (p *Package) writeDefs() {
}
fmt.Fprintf(fm, "void _cgo_allocate(void *a, int c) { }\n")
fmt.Fprintf(fm, "void _cgo_panic(void *a, int c) { }\n")
fmt.Fprintf(fm, "void _cgo_reginit(void) { }\n")
// Write second Go output: definitions of _C_xxx.
// In a separate file so that the import of "unsafe" does not
......
......@@ -267,6 +267,7 @@ var cgoEnabled = map[string]bool{
"linux/386": true,
"linux/amd64": true,
"linux/arm": true,
"linux/ppc64le": true,
"android/386": true,
"android/amd64": true,
"android/arm": true,
......
......@@ -118,6 +118,7 @@ export GOTRACEBACK=2
go test -ldflags '-linkmode=auto' || exit 1
# linkmode=internal fails on dragonfly since errno is a TLS relocation.
[ "$GOHOSTOS" == dragonfly ] || go test -ldflags '-linkmode=internal' || exit 1
# TODO(austin): Add linux-ppc64(le) once external linking works (issue #8912)
case "$GOHOSTOS-$GOARCH" in
openbsd-386 | openbsd-amd64)
# test linkmode=external, but __thread not supported, so skip testtls.
......
......@@ -29,8 +29,29 @@ TEXT runtime·rt0_go(SB),NOSPLIT,$0
MOVD R3, (g_stack+stack_lo)(g)
MOVD R1, (g_stack+stack_hi)(g)
// TODO: if there is a _cgo_init, call it.
// TODO: add TLS
// if there is a _cgo_init, call it using the gcc ABI.
MOVD _cgo_init(SB), R12
CMP R0, R12
BEQ nocgo
MOVD R12, CTR // r12 = "global function entry point"
MOVD R13, R5 // arg 2: TLS base pointer
MOVD $setg_gcc<>(SB), R4 // arg 1: setg
MOVD g, R3 // arg 0: G
// C functions expect 32 bytes of space on caller stack frame
// and a 16-byte aligned R1
MOVD R1, R14 // save current stack
SUB $32, R1 // reserve 32 bytes
RLDCR $0, R1, $~15, R1 // 16-byte align
BL (CTR) // may clobber R0, R3-R12
MOVD R14, R1 // restore stack
XOR R0, R0 // fix R0
nocgo:
// update stackguard after _cgo_init
MOVD (g_stack+stack_lo)(g), R3
ADD $const__StackGuard, R3
MOVD R3, g_stackguard0(g)
MOVD R3, g_stackguard1(g)
// set the per-goroutine and per-mach "registers"
MOVD $runtime·m0(SB), R3
......@@ -71,6 +92,11 @@ TEXT runtime·breakpoint(SB),NOSPLIT,$-8-0
TEXT runtime·asminit(SB),NOSPLIT,$-8-0
RETURN
TEXT _cgo_reginit(SB),NOSPLIT,$-8-0
// crosscall_ppc64 and crosscall2 need to reginit, but can't
// get at the 'runtime.reginit' symbol.
BR runtime·reginit(SB)
TEXT runtime·reginit(SB),NOSPLIT,$-8-0
// set R0 to zero, it's expected by the toolchain
XOR R0, R0
......@@ -625,26 +651,207 @@ TEXT gosave<>(SB),NOSPLIT,$-8
// aligned appropriately for the gcc ABI.
// See cgocall.c for more details.
TEXT ·asmcgocall(SB),NOSPLIT,$0-16
MOVD R0, 21(R0)
MOVD fn+0(FP), R3
MOVD arg+8(FP), R4
BL asmcgocall<>(SB)
RET
TEXT ·asmcgocall_errno(SB),NOSPLIT,$0-24
MOVD fn+0(FP), R3
MOVD arg+8(FP), R4
BL asmcgocall<>(SB)
MOVD R3, ret+16(FP)
RET
// asmcgocall common code. fn in R3, arg in R4. returns errno in R3.
TEXT asmcgocall<>(SB),NOSPLIT,$0-0
MOVD R1, R2 // save original stack pointer
MOVD g, R5
// Figure out if we need to switch to m->g0 stack.
// We get called to create new OS threads too, and those
// come in on the m->g0 stack already.
MOVD g_m(g), R6
MOVD m_g0(R6), R6
CMP R6, g
BEQ g0
BL gosave<>(SB)
MOVD R6, g
BL runtime·save_g(SB)
MOVD (g_sched+gobuf_sp)(g), R1
// Now on a scheduling stack (a pthread-created stack).
g0:
// Save room for two of our pointers, plus 32 bytes of callee
// save area that lives on the caller stack.
SUB $48, R1
RLDCR $0, R1, $~15, R1 // 16-byte alignment for gcc ABI
MOVD R5, 40(R1) // save old g on stack
MOVD (g_stack+stack_hi)(R5), R5
SUB R2, R5
MOVD R5, 32(R1) // save depth in old g stack (can't just save SP, as stack might be copied during a callback)
MOVD R0, 0(R1) // clear back chain pointer (TODO can we give it real back trace information?)
// This is a "global call", so put the global entry point in r12
MOVD R3, R12
MOVD R12, CTR
MOVD R4, R3 // arg in r3
BL (CTR)
// C code can clobber R0, so set it back to 0. F27-F31 are
// callee save, so we don't need to recover those.
XOR R0, R0
// Restore g, stack pointer. R3 is errno, so don't touch it
MOVD 40(R1), g
BL runtime·save_g(SB)
MOVD (g_stack+stack_hi)(g), R5
MOVD 32(R1), R6
SUB R6, R5
MOVD R5, R1
RET
// cgocallback(void (*fn)(void*), void *frame, uintptr framesize)
// Turn the fn into a Go func (by taking its address) and call
// cgocallback_gofunc.
TEXT runtime·cgocallback(SB),NOSPLIT,$24-24
MOVD R0, 22(R0)
MOVD $fn+0(FP), R3
MOVD R3, 8(R1)
MOVD frame+8(FP), R3
MOVD R3, 16(R1)
MOVD framesize+16(FP), R3
MOVD R3, 24(R1)
MOVD $runtime·cgocallback_gofunc(SB), R3
MOVD R3, CTR
BL (CTR)
RET
// cgocallback_gofunc(FuncVal*, void *frame, uintptr framesize)
// See cgocall.c for more details.
TEXT ·cgocallback_gofunc(SB),NOSPLIT,$8-24
MOVD R0, 23(R0)
TEXT ·cgocallback_gofunc(SB),NOSPLIT,$16-24
NO_LOCAL_POINTERS
// Load m and g from thread-local storage.
MOVB runtime·iscgo(SB), R3
CMP R3, $0
BEQ nocgo
BL runtime·load_g(SB)
nocgo:
// If g is nil, Go did not create the current thread.
// Call needm to obtain one for temporary use.
// In this case, we're running on the thread stack, so there's
// lots of space, but the linker doesn't know. Hide the call from
// the linker analysis by using an indirect call.
CMP g, $0
BNE havem
MOVD g, savedm-8(SP) // g is zero, so is m.
MOVD $runtime·needm(SB), R3
MOVD R3, CTR
BL (CTR)
// Set m->sched.sp = SP, so that if a panic happens
// during the function we are about to execute, it will
// have a valid SP to run on the g0 stack.
// The next few lines (after the havem label)
// will save this SP onto the stack and then write
// the same SP back to m->sched.sp. That seems redundant,
// but if an unrecovered panic happens, unwindm will
// restore the g->sched.sp from the stack location
// and then systemstack will try to use it. If we don't set it here,
// that restored SP will be uninitialized (typically 0) and
// will not be usable.
MOVD g_m(g), R3
MOVD m_g0(R3), R3
MOVD R1, (g_sched+gobuf_sp)(R3)
havem:
MOVD g_m(g), R8
MOVD R8, savedm-8(SP)
// Now there's a valid m, and we're running on its m->g0.
// Save current m->g0->sched.sp on stack and then set it to SP.
// Save current sp in m->g0->sched.sp in preparation for
// switch back to m->curg stack.
// NOTE: unwindm knows that the saved g->sched.sp is at 8(R1) aka savedsp-16(SP).
MOVD m_g0(R8), R3
MOVD (g_sched+gobuf_sp)(R3), R4
MOVD R4, savedsp-16(SP)
MOVD R1, (g_sched+gobuf_sp)(R3)
// Switch to m->curg stack and call runtime.cgocallbackg.
// Because we are taking over the execution of m->curg
// but *not* resuming what had been running, we need to
// save that information (m->curg->sched) so we can restore it.
// We can restore m->curg->sched.sp easily, because calling
// runtime.cgocallbackg leaves SP unchanged upon return.
// To save m->curg->sched.pc, we push it onto the stack.
// This has the added benefit that it looks to the traceback
// routine like cgocallbackg is going to return to that
// PC (because the frame we allocate below has the same
// size as cgocallback_gofunc's frame declared above)
// so that the traceback will seamlessly trace back into
// the earlier calls.
//
// In the new goroutine, -16(SP) and -8(SP) are unused.
MOVD m_curg(R8), g
BL runtime·save_g(SB)
MOVD (g_sched+gobuf_sp)(g), R4 // prepare stack as R4
MOVD (g_sched+gobuf_pc)(g), R5
MOVD R5, -24(R4)
MOVD $-24(R4), R1
BL runtime·cgocallbackg(SB)
// Restore g->sched (== m->curg->sched) from saved values.
MOVD 0(R1), R5
MOVD R5, (g_sched+gobuf_pc)(g)
MOVD $24(R1), R4
MOVD R4, (g_sched+gobuf_sp)(g)
// Switch back to m->g0's stack and restore m->g0->sched.sp.
// (Unlike m->curg, the g0 goroutine never uses sched.pc,
// so we do not have to restore it.)
MOVD g_m(g), R8
MOVD m_g0(R8), g
BL runtime·save_g(SB)
MOVD (g_sched+gobuf_sp)(g), R1
MOVD savedsp-16(SP), R4
MOVD R4, (g_sched+gobuf_sp)(g)
// If the m on entry was nil, we called needm above to borrow an m
// for the duration of the call. Since the call is over, return it with dropm.
MOVD savedm-8(SP), R6
CMP R6, $0
BNE droppedm
MOVD $runtime·dropm(SB), R3
MOVD R3, CTR
BL (CTR)
droppedm:
// Done!
RET
// void setg(G*); set g. for use by needm.
TEXT runtime·setg(SB), NOSPLIT, $0-8
MOVD R0, 24(R0)
MOVD gg+0(FP), g
// This only happens if iscgo, so jump straight to save_g
BL runtime·save_g(SB)
RET
// void setg_gcc(G*); set g in C TLS.
// Must obey the gcc calling convention.
TEXT setg_gcc<>(SB),NOSPLIT,$-8-0
// The standard prologue clobbers R31, which is callee-save in
// the C ABI, so we have to use $-8-0 and save LR ourselves.
MOVD LR, R4
// Also save g and R31, since they're callee-save in C ABI
MOVD R31, R5
MOVD g, R6
MOVD R3, g
BL runtime·save_g(SB)
// void setg_gcc(G*); set g called from gcc.
TEXT setg_gcc<>(SB),NOSPLIT,$0
MOVD R0, 25(R0)
MOVD R6, g
MOVD R5, R31
MOVD R4, LR
RET
TEXT runtime·getcallerpc(SB),NOSPLIT,$-8-16
MOVD 0(R1), R3
......@@ -989,8 +1196,21 @@ TEXT runtime·return0(SB), NOSPLIT, $0
// Called from cgo wrappers, this function returns g->m->curg.stack.hi.
// Must obey the gcc calling convention.
TEXT _cgo_topofstack(SB),NOSPLIT,$0
MOVD R0, 26(R0)
TEXT _cgo_topofstack(SB),NOSPLIT,$-8
// g (R30) and R31 are callee-save in the C ABI, so save them
MOVD g, R4
MOVD R31, R5
MOVD LR, R6
BL runtime·load_g(SB) // clobbers g (R30), R31
MOVD g_m(g), R3
MOVD m_curg(R3), R3
MOVD (g_stack+stack_hi)(R3), R3
MOVD R4, g
MOVD R5, R31
MOVD R6, LR
RET
// The top-most function running on a goroutine
// returns to goexit+PCQuantum.
......
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build ppc64 ppc64le
#include "textflag.h"
/*
* void crosscall2(void (*fn)(void*, int32), void*, int32)
* Save registers and call fn with two arguments.
* crosscall2 obeys the C ABI; fn obeys the Go ABI.
*/
TEXT crosscall2(SB),NOSPLIT,$-8
// TODO(austin): ABI v1 (fn is probably a function descriptor)
// Start with standard C stack frame layout and linkage
MOVD LR, R0
MOVD R0, 16(R1) // Save LR in caller's frame
MOVD R2, 24(R1) // Save TOC in caller's frame
BL saveregs2<>(SB)
MOVDU R1, (-288-3*8)(R1)
// Initialize Go ABI environment
BL runtime·reginit(SB)
BL runtime·load_g(SB)
MOVD R3, CTR
MOVD R4, 8(R1)
MOVD R5, 16(R1)
BL (CTR)
ADD $(288+3*8), R1
BL restoreregs2<>(SB)
MOVD 24(R1), R2
MOVD 16(R1), R0
MOVD R0, LR
RET
TEXT saveregs2<>(SB),NOSPLIT,$-8
// O=-288; for R in R{14..31}; do echo "\tMOVD\t$R, $O(R1)"|sed s/R30/g/; ((O+=8)); done; for F in F{14..31}; do echo "\tFMOVD\t$F, $O(R1)"; ((O+=8)); done
MOVD R14, -288(R1)
MOVD R15, -280(R1)
MOVD R16, -272(R1)
MOVD R17, -264(R1)
MOVD R18, -256(R1)
MOVD R19, -248(R1)
MOVD R20, -240(R1)
MOVD R21, -232(R1)
MOVD R22, -224(R1)
MOVD R23, -216(R1)
MOVD R24, -208(R1)
MOVD R25, -200(R1)
MOVD R26, -192(R1)
MOVD R27, -184(R1)
MOVD R28, -176(R1)
MOVD R29, -168(R1)
MOVD g, -160(R1)
MOVD R31, -152(R1)
FMOVD F14, -144(R1)
FMOVD F15, -136(R1)
FMOVD F16, -128(R1)
FMOVD F17, -120(R1)
FMOVD F18, -112(R1)
FMOVD F19, -104(R1)
FMOVD F20, -96(R1)
FMOVD F21, -88(R1)
FMOVD F22, -80(R1)
FMOVD F23, -72(R1)
FMOVD F24, -64(R1)
FMOVD F25, -56(R1)
FMOVD F26, -48(R1)
FMOVD F27, -40(R1)
FMOVD F28, -32(R1)
FMOVD F29, -24(R1)
FMOVD F30, -16(R1)
FMOVD F31, -8(R1)
RET
TEXT restoreregs2<>(SB),NOSPLIT,$-8
// O=-288; for R in R{14..31}; do echo "\tMOVD\t$O(R1), $R"|sed s/R30/g/; ((O+=8)); done; for F in F{14..31}; do echo "\tFMOVD\t$O(R1), $F"; ((O+=8)); done
MOVD -288(R1), R14
MOVD -280(R1), R15
MOVD -272(R1), R16
MOVD -264(R1), R17
MOVD -256(R1), R18
MOVD -248(R1), R19
MOVD -240(R1), R20
MOVD -232(R1), R21
MOVD -224(R1), R22
MOVD -216(R1), R23
MOVD -208(R1), R24
MOVD -200(R1), R25
MOVD -192(R1), R26
MOVD -184(R1), R27
MOVD -176(R1), R28
MOVD -168(R1), R29
MOVD -160(R1), g
MOVD -152(R1), R31
FMOVD -144(R1), F14
FMOVD -136(R1), F15
FMOVD -128(R1), F16
FMOVD -120(R1), F17
FMOVD -112(R1), F18
FMOVD -104(R1), F19
FMOVD -96(R1), F20
FMOVD -88(R1), F21
FMOVD -80(R1), F22
FMOVD -72(R1), F23
FMOVD -64(R1), F24
FMOVD -56(R1), F25
FMOVD -48(R1), F26
FMOVD -40(R1), F27
FMOVD -32(R1), F28
FMOVD -24(R1), F29
FMOVD -16(R1), F30
FMOVD -8(R1), F31
RET
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build ppc64 ppc64le
#include <pthread.h>
#include <string.h>
#include <signal.h>
#include "libcgo.h"
static void *threadentry(void*);
void (*x_cgo_inittls)(void **tlsg, void **tlsbase);
static void (*setg_gcc)(void*);
void
x_cgo_init(G *g, void (*setg)(void*), void **tlsbase)
{
pthread_attr_t attr;
size_t size;
setg_gcc = setg;
pthread_attr_init(&attr);
pthread_attr_getstacksize(&attr, &size);
g->stacklo = (uintptr)&attr - size + 4096;
pthread_attr_destroy(&attr);
}
void
_cgo_sys_thread_start(ThreadStart *ts)
{
pthread_attr_t attr;
sigset_t ign, oset;
pthread_t p;
size_t size;
int err;
sigfillset(&ign);
pthread_sigmask(SIG_SETMASK, &ign, &oset);
pthread_attr_init(&attr);
pthread_attr_getstacksize(&attr, &size);
// Leave stacklo=0 and set stackhi=size; mstack will do the rest.
ts->g->stackhi = size;
err = pthread_create(&p, &attr, threadentry, ts);
pthread_sigmask(SIG_SETMASK, &oset, nil);
if (err != 0) {
fatalf("pthread_create failed: %s", strerror(err));
}
}
extern void crosscall_ppc64(void (*fn)(void), void *g);
static void*
threadentry(void *v)
{
ThreadStart ts;
ts = *(ThreadStart*)v;
free(v);
// Save g for this thread in C TLS
setg_gcc((void*)ts.g);
crosscall_ppc64(ts.fn, (void*)ts.g);
return nil;
}
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build ppc64 ppc64le
/*
* Apple still insists on underscore prefixes for C function names.
*/
#if defined(__APPLE__)
#define EXT(s) _##s
#else
#define EXT(s) s
#endif
/*
* void crosscall_ppc64(void (*fn)(void), void *g)
*
* Calling into the 9g tool chain, where all registers are caller save.
* Called from standard ppc64 C ABI, where r2, r14-r31, f14-f31 are
* callee-save, so they must be saved explicitly.
*/
.globl EXT(crosscall_ppc64)
EXT(crosscall_ppc64):
// Start with standard C stack frame layout and linkage
mflr %r0
std %r0, 16(%r1) // Save LR in caller's frame
std %r2, 24(%r1) // Save TOC in caller's frame
bl saveregs
stdu %r1, -296(%r1)
// Set up Go ABI constant registers
bl _cgo_reginit
// Restore g pointer (r30 in Go ABI, which may have been clobbered by C)
mr %r30, %r4
// Call fn
mtctr %r3
bctrl
addi %r1, %r1, 296
bl restoreregs
ld %r2, 24(%r1)
ld %r0, 16(%r1)
mtlr %r0
blr
saveregs:
// Save callee-save registers
// O=-288; for R in %r{14..31}; do echo "\tstd\t$R, $O(%r1)"; ((O+=8)); done; for F in f{14..31}; do echo "\tstfd\t$F, $O(%r1)"; ((O+=8)); done
std %r14, -288(%r1)
std %r15, -280(%r1)
std %r16, -272(%r1)
std %r17, -264(%r1)
std %r18, -256(%r1)
std %r19, -248(%r1)
std %r20, -240(%r1)
std %r21, -232(%r1)
std %r22, -224(%r1)
std %r23, -216(%r1)
std %r24, -208(%r1)
std %r25, -200(%r1)
std %r26, -192(%r1)
std %r27, -184(%r1)
std %r28, -176(%r1)
std %r29, -168(%r1)
std %r30, -160(%r1)
std %r31, -152(%r1)
stfd %f14, -144(%r1)
stfd %f15, -136(%r1)
stfd %f16, -128(%r1)
stfd %f17, -120(%r1)
stfd %f18, -112(%r1)
stfd %f19, -104(%r1)
stfd %f20, -96(%r1)
stfd %f21, -88(%r1)
stfd %f22, -80(%r1)
stfd %f23, -72(%r1)
stfd %f24, -64(%r1)
stfd %f25, -56(%r1)
stfd %f26, -48(%r1)
stfd %f27, -40(%r1)
stfd %f28, -32(%r1)
stfd %f29, -24(%r1)
stfd %f30, -16(%r1)
stfd %f31, -8(%r1)
blr
restoreregs:
// O=-288; for R in %r{14..31}; do echo "\tld\t$R, $O(%r1)"; ((O+=8)); done; for F in %f{14..31}; do echo "\tlfd\t$F, $O(%r1)"; ((O+=8)); done
ld %r14, -288(%r1)
ld %r15, -280(%r1)
ld %r16, -272(%r1)
ld %r17, -264(%r1)
ld %r18, -256(%r1)
ld %r19, -248(%r1)
ld %r20, -240(%r1)
ld %r21, -232(%r1)
ld %r22, -224(%r1)
ld %r23, -216(%r1)
ld %r24, -208(%r1)
ld %r25, -200(%r1)
ld %r26, -192(%r1)
ld %r27, -184(%r1)
ld %r28, -176(%r1)
ld %r29, -168(%r1)
ld %r30, -160(%r1)
ld %r31, -152(%r1)
lfd %f14, -144(%r1)
lfd %f15, -136(%r1)
lfd %f16, -128(%r1)
lfd %f17, -120(%r1)
lfd %f18, -112(%r1)
lfd %f19, -104(%r1)
lfd %f20, -96(%r1)
lfd %f21, -88(%r1)
lfd %f22, -80(%r1)
lfd %f23, -72(%r1)
lfd %f24, -64(%r1)
lfd %f25, -56(%r1)
lfd %f26, -48(%r1)
lfd %f27, -40(%r1)
lfd %f28, -32(%r1)
lfd %f29, -24(%r1)
lfd %f30, -16(%r1)
lfd %f31, -8(%r1)
blr
.globl EXT(__stack_chk_fail_local)
EXT(__stack_chk_fail_local):
1:
// TODO(austin)
b 1b
#ifdef __ELF__
.section .note.GNU-stack,"",%progbits
#endif
......@@ -229,6 +229,11 @@ func cgocallbackg1() {
case "386":
// On 386, stack frame is three words, plus caller PC.
cb = (*args)(unsafe.Pointer(sp + 4*ptrSize))
case "ppc64", "ppc64le":
// On ppc64, stack frame is two words and there's a
// saved LR between SP and the stack frame and between
// the stack frame and the arguments.
cb = (*args)(unsafe.Pointer(sp + 4*ptrSize))
}
// Invoke callback.
......@@ -263,6 +268,8 @@ func unwindm(restore *bool) {
sched.sp = *(*uintptr)(unsafe.Pointer(sched.sp))
case "arm":
sched.sp = *(*uintptr)(unsafe.Pointer(sched.sp + 4))
case "ppc64", "ppc64le":
sched.sp = *(*uintptr)(unsafe.Pointer(sched.sp + 8))
}
releasem(mp)
}
......
......@@ -68,6 +68,11 @@ func TestCgoExternalThreadSIGPROF(t *testing.T) {
t.Skipf("no external linking on OS X 10.6")
}
}
if runtime.GOARCH == "ppc64" || runtime.GOARCH == "ppc64le" {
// TODO(austin) External linking not implemented on
// ppc64 (issue #8912)
t.Skipf("no external linking on ppc64")
}
got := executeTest(t, cgoExternalThreadSIGPROFSource, nil)
want := "OK\n"
if got != want {
......
......@@ -7,6 +7,12 @@ TEXT _rt0_ppc64_linux(SB),NOSPLIT,$0
DWORD $0
TEXT _main<>(SB),NOSPLIT,$-8
// In a statically linked binary, the stack contains argc,
// argv as argc string pointers followed by a NULL, envv as a
// sequence of string pointers followed by a NULL, and auxv.
// There is no TLS base pointer.
//
// TODO(austin): Support ABI v1 dynamic linking entry point
MOVD 0(R1), R3 // argc
ADD $8, R1, R4 // argv
BR main(SB)
......
......@@ -4,11 +4,29 @@ TEXT _rt0_ppc64le_linux(SB),NOSPLIT,$0
BR _main<>(SB)
TEXT _main<>(SB),NOSPLIT,$-8
MOVD 0(R1), R3 // argc
ADD $8, R1, R4 // argv
// In a statically linked binary, the stack contains argc,
// argv as argc string pointers followed by a NULL, envv as a
// sequence of string pointers followed by a NULL, and auxv.
// There is no TLS base pointer.
//
// In a dynamically linked binary, r3 contains argc, r4
// contains argv, r5 contains envp, r6 contains auxv, and r13
// contains the TLS pointer.
//
// Figure out which case this is by looking at r4: if it's 0,
// we're statically linked; otherwise we're dynamically
// linked.
CMP R0, R4
BNE dlink
// Statically linked
MOVD 0(R1), R3 // argc
ADD $8, R1, R4 // argv
MOVD $runtime·tls0(SB), R13 // TLS
ADD $0x7000, R13
BR main(SB)
dlink:
BR main(SB)
TEXT main(SB),NOSPLIT,$-8
MOVD $runtime·rt0_go(SB), R31
......
......@@ -77,6 +77,9 @@ func goargs() {
}
func goenvs_unix() {
// TODO(austin): ppc64 in dynamic linking mode doesn't
// guarantee env[] will immediately follow argv. Might cause
// problems.
n := int32(0)
for argv_index(argv, argc+1+n) != nil {
n++
......
......@@ -193,6 +193,13 @@ TEXT runtime·_sigtramp(SB),NOSPLIT,$64
// initialize essential registers (just in case)
BL runtime·reginit(SB)
// this might be called in external code context,
// where g is not set.
MOVB runtime·iscgo(SB), R6
CMP R6, $0
BEQ 2(PC)
BL runtime·load_g(SB)
// check that g exists
CMP g, $0
BNE 6(PC)
......
......@@ -20,6 +20,8 @@
// ppc64 code that will overwrite this register.
//
// If !iscgo, this is a no-op.
//
// NOTE: setg_gcc<> assume this clobbers only R31.
TEXT runtime·save_g(SB),NOSPLIT,$-8-0
MOVB runtime·iscgo(SB), R31
CMP R31, $0
......@@ -46,6 +48,8 @@ nocgo:
// This is never called directly from C code (it doesn't have to
// follow the C ABI), but it may be called from a C context, where the
// usual Go registers aren't set up.
//
// NOTE: _cgo_topofstack assumes this only clobbers g (R30), and R31.
TEXT runtime·load_g(SB),NOSPLIT,$-8-0
MOVD $runtime·tlsg(SB), R31
// R13 is the C ABI TLS base pointer + 0x7000
......
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