aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/internal/obj/ppc64
diff options
context:
space:
mode:
authorMichael Hudson-Doyle <michael.hudson@canonical.com>2015-10-16 15:42:09 +1300
committerMichael Hudson-Doyle <michael.hudson@canonical.com>2015-11-12 23:18:58 +0000
commit368d54841704fabfcd87a39c66ff56ca87f6eeea (patch)
tree994c86285a0e42ae5bceef86df39c0258fb873ab /src/cmd/internal/obj/ppc64
parentdbdd8c2c94ec118050331455681606b9f14b6244 (diff)
downloadgo-368d54841704fabfcd87a39c66ff56ca87f6eeea.tar.xz
cmd/compile, cmd/link, runtime: on ppc64x, maintain the TOC pointer in R2 when compiling PIC
The PowerPC ISA does not have a PC-relative load instruction, which poses obvious challenges when generating position-independent code. The way the ELFv2 ABI addresses this is to specify that r2 points to a per "module" (shared library or executable) TOC pointer. Maintaining this pointer requires cooperation between codegen and the system linker: * Non-leaf functions leave space on the stack at r1+24 to save the TOC pointer. * A call to a function that *might* have to go via a PLT stub must be followed by a nop instruction that the system linker can replace with "ld r1, 24(r1)" to restore the TOC pointer (only when dynamically linking Go code). * When calling a function via a function pointer, the address of the function must be in r12, and the first couple of instructions (the "global entry point") of the called function use this to derive the address of the TOC for the module it is in. * When calling a function that is implemented in the same module, the system linker adjusts the call to skip over the instructions mentioned above (the "local entry point"), assuming that r2 is already correctly set. So this changeset adds the global entry point instructions, sets the metadata so the system linker knows where the local entry point is, inserts code to save the TOC pointer at 24(r1), adds a nop after any call not known to be local and copes with the odd non-local code transfer in the runtime (e.g. the stuff around jmpdefer). It does not actually compile PIC yet. Change-Id: I7522e22bdfd2f891745a900c60254fe9e372c854 Reviewed-on: https://go-review.googlesource.com/15967 Reviewed-by: Russ Cox <rsc@golang.org>
Diffstat (limited to 'src/cmd/internal/obj/ppc64')
-rw-r--r--src/cmd/internal/obj/ppc64/a.out.go1
-rw-r--r--src/cmd/internal/obj/ppc64/asm9.go5
-rw-r--r--src/cmd/internal/obj/ppc64/obj9.go53
3 files changed, 55 insertions, 4 deletions
diff --git a/src/cmd/internal/obj/ppc64/a.out.go b/src/cmd/internal/obj/ppc64/a.out.go
index ea868fdb5f..3fd4685769 100644
--- a/src/cmd/internal/obj/ppc64/a.out.go
+++ b/src/cmd/internal/obj/ppc64/a.out.go
@@ -205,6 +205,7 @@ const (
C_DACON /* $n(REG) where int32 < n */
C_SBRA
C_LBRA
+ C_LBRAPIC
C_SAUTO
C_LAUTO
C_SEXT
diff --git a/src/cmd/internal/obj/ppc64/asm9.go b/src/cmd/internal/obj/ppc64/asm9.go
index 3e3a020a7c..22514e514e 100644
--- a/src/cmd/internal/obj/ppc64/asm9.go
+++ b/src/cmd/internal/obj/ppc64/asm9.go
@@ -281,6 +281,7 @@ var optab = []Optab{
{ABEQ, C_NONE, C_NONE, C_NONE, C_SBRA, 16, 4, 0},
{ABEQ, C_CREG, C_NONE, C_NONE, C_SBRA, 16, 4, 0},
{ABR, C_NONE, C_NONE, C_NONE, C_LBRA, 11, 4, 0},
+ {ABR, C_NONE, C_NONE, C_NONE, C_LBRAPIC, 11, 8, 0},
{ABC, C_SCON, C_REG, C_NONE, C_SBRA, 16, 4, 0},
{ABC, C_SCON, C_REG, C_NONE, C_LBRA, 17, 4, 0},
{ABR, C_NONE, C_NONE, C_NONE, C_LR, 18, 4, 0},
@@ -704,6 +705,9 @@ func aclass(ctxt *obj.Link, a *obj.Addr) int {
return C_DCON
case obj.TYPE_BRANCH:
+ if a.Sym != nil && ctxt.Flag_dynlink {
+ return C_LBRAPIC
+ }
return C_SBRA
}
@@ -1714,6 +1718,7 @@ func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
rel.Add = int64(v)
rel.Type = obj.R_CALLPOWER
}
+ o2 = 0x60000000 // nop, sometimes overwritten by ld r2, 24(r1) when dynamic linking
case 12: /* movb r,r (extsb); movw r,r (extsw) */
if p.To.Reg == REGZERO && p.From.Type == obj.TYPE_CONST {
diff --git a/src/cmd/internal/obj/ppc64/obj9.go b/src/cmd/internal/obj/ppc64/obj9.go
index e72832d445..389d6ac88d 100644
--- a/src/cmd/internal/obj/ppc64/obj9.go
+++ b/src/cmd/internal/obj/ppc64/obj9.go
@@ -342,11 +342,45 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
p.To.Offset = int64(autosize)
- if p.From3.Offset&obj.NOSPLIT == 0 {
- p = stacksplit(ctxt, p, autosize) // emit split check
+ q = p
+
+ if ctxt.Flag_shared != 0 && cursym.Name != "runtime.duffzero" && cursym.Name != "runtime.duffcopy" {
+ // When compiling Go into PIC, all functions must start
+ // with instructions to load the TOC pointer into r2:
+ //
+ // addis r2, r12, .TOC.-func@ha
+ // addi r2, r2, .TOC.-func@l+4
+ //
+ // We could probably skip this prologue in some situations
+ // but it's a bit subtle. However, it is both safe and
+ // necessary to leave the prologue off duffzero and
+ // duffcopy as we rely on being able to jump to a specific
+ // instruction offset for them.
+ //
+ // These are AWORDS because there is no (afaict) way to
+ // generate the addis instruction except as part of the
+ // load of a large constant, and in that case there is no
+ // way to use r12 as the source.
+ q = obj.Appendp(ctxt, q)
+ q.As = AWORD
+ q.Lineno = p.Lineno
+ q.From.Type = obj.TYPE_CONST
+ q.From.Offset = 0x3c4c0000
+ q = obj.Appendp(ctxt, q)
+ q.As = AWORD
+ q.Lineno = p.Lineno
+ q.From.Type = obj.TYPE_CONST
+ q.From.Offset = 0x38420000
+ rel := obj.Addrel(ctxt.Cursym)
+ rel.Off = 0
+ rel.Siz = 8
+ rel.Sym = obj.Linklookup(ctxt, ".TOC.", 0)
+ rel.Type = obj.R_ADDRPOWER_PCREL
}
- q = p
+ if cursym.Text.From3.Offset&obj.NOSPLIT == 0 {
+ q = stacksplit(ctxt, q, autosize) // emit split check
+ }
if autosize != 0 {
/* use MOVDU to adjust R1 when saving R31, if autosize is small */
@@ -354,7 +388,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
mov = AMOVDU
aoffset = int(-autosize)
} else {
- q = obj.Appendp(ctxt, p)
+ q = obj.Appendp(ctxt, q)
q.As = AADD
q.Lineno = p.Lineno
q.From.Type = obj.TYPE_CONST
@@ -395,6 +429,17 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
q.Spadj = int32(-aoffset)
}
+ if ctxt.Flag_shared != 0 {
+ q = obj.Appendp(ctxt, q)
+ q.As = AMOVD
+ q.Lineno = p.Lineno
+ q.From.Type = obj.TYPE_REG
+ q.From.Reg = REG_R2
+ q.To.Type = obj.TYPE_MEM
+ q.To.Reg = REGSP
+ q.To.Offset = 24
+ }
+
if cursym.Text.From3.Offset&obj.WRAPPER != 0 {
// if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame
//