cmd/7g, cmd/7l, cmd/go: copy 9g/9l to 7g/7l, and build as tools

Kick start the upstreaming of the arm64 port. The only manual
change is cmd/go/pkg.go.

Change-Id: I0607ad045486f0998c4e21654b59276ca5348069
Reviewed-on: https://go-review.googlesource.com/7075
Reviewed-by: Aram Hăvărneanu <aram@mgk.ro>
Run-TryBot: Aram Hăvărneanu <aram@mgk.ro>
TryBot-Result: Gobot Gobot <gobot@golang.org>
This commit is contained in:
Shenghou Ma 2015-03-08 04:32:55 -04:00 committed by Minux Ma
parent d7e043eaf5
commit f00c19add5
14 changed files with 6652 additions and 0 deletions

1882
src/cmd/7g/cgen.go Normal file

File diff suppressed because it is too large Load Diff

93
src/cmd/7g/galign.go Normal file
View File

@ -0,0 +1,93 @@
// Copyright 2009 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.
package main
import (
"cmd/internal/gc"
"cmd/internal/obj"
"cmd/internal/obj/ppc64"
)
var thechar int = '9'
var thestring string = "ppc64"
var thelinkarch *obj.LinkArch
func linkarchinit() {
thestring = obj.Getgoarch()
gc.Thearch.Thestring = thestring
if thestring == "ppc64le" {
thelinkarch = &ppc64.Linkppc64le
} else {
thelinkarch = &ppc64.Linkppc64
}
gc.Thearch.Thelinkarch = thelinkarch
}
var MAXWIDTH int64 = 1 << 50
/*
* go declares several platform-specific type aliases:
* int, uint, float, and uintptr
*/
var typedefs = []gc.Typedef{
gc.Typedef{"int", gc.TINT, gc.TINT64},
gc.Typedef{"uint", gc.TUINT, gc.TUINT64},
gc.Typedef{"uintptr", gc.TUINTPTR, gc.TUINT64},
}
func betypeinit() {
gc.Widthptr = 8
gc.Widthint = 8
gc.Widthreg = 8
}
func main() {
gc.Thearch.Thechar = thechar
gc.Thearch.Thestring = thestring
gc.Thearch.Thelinkarch = thelinkarch
gc.Thearch.Typedefs = typedefs
gc.Thearch.REGSP = ppc64.REGSP
gc.Thearch.REGCTXT = ppc64.REGCTXT
gc.Thearch.MAXWIDTH = MAXWIDTH
gc.Thearch.Anyregalloc = anyregalloc
gc.Thearch.Betypeinit = betypeinit
gc.Thearch.Bgen = bgen
gc.Thearch.Cgen = cgen
gc.Thearch.Cgen_call = cgen_call
gc.Thearch.Cgen_callinter = cgen_callinter
gc.Thearch.Cgen_ret = cgen_ret
gc.Thearch.Clearfat = clearfat
gc.Thearch.Defframe = defframe
gc.Thearch.Excise = excise
gc.Thearch.Expandchecks = expandchecks
gc.Thearch.Gclean = gclean
gc.Thearch.Ginit = ginit
gc.Thearch.Gins = gins
gc.Thearch.Ginscall = ginscall
gc.Thearch.Igen = igen
gc.Thearch.Linkarchinit = linkarchinit
gc.Thearch.Peep = peep
gc.Thearch.Proginfo = proginfo
gc.Thearch.Regalloc = regalloc
gc.Thearch.Regfree = regfree
gc.Thearch.Regtyp = regtyp
gc.Thearch.Sameaddr = sameaddr
gc.Thearch.Smallindir = smallindir
gc.Thearch.Stackaddr = stackaddr
gc.Thearch.Excludedregs = excludedregs
gc.Thearch.RtoB = RtoB
gc.Thearch.FtoB = RtoB
gc.Thearch.BtoR = BtoR
gc.Thearch.BtoF = BtoF
gc.Thearch.Optoas = optoas
gc.Thearch.Doregbits = doregbits
gc.Thearch.Regnames = regnames
gc.Main()
gc.Exit(0)
}

28
src/cmd/7g/gg.go Normal file
View File

@ -0,0 +1,28 @@
// Copyright 2009 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.
package main
import "cmd/internal/obj/ppc64"
import "cmd/internal/gc"
// 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.
var reg [ppc64.NREG + ppc64.NFREG]uint8
var panicdiv *gc.Node
/*
* cgen.c
*/
/*
* list.c
*/
/*
* reg.c
*/

884
src/cmd/7g/ggen.go Normal file
View File

@ -0,0 +1,884 @@
// Copyright 2009 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.
package main
import (
"cmd/internal/gc"
"cmd/internal/obj"
"cmd/internal/obj/ppc64"
"fmt"
)
func defframe(ptxt *obj.Prog) {
var n *gc.Node
// fill in argument size, stack size
ptxt.To.Type = obj.TYPE_TEXTSIZE
ptxt.To.U.Argsize = int32(gc.Rnd(gc.Curfn.Type.Argwid, int64(gc.Widthptr)))
frame := uint32(gc.Rnd(gc.Stksize+gc.Maxarg, int64(gc.Widthreg)))
ptxt.To.Offset = int64(frame)
// insert code to zero ambiguously live variables
// so that the garbage collector only sees initialized values
// when it looks for pointers.
p := ptxt
hi := int64(0)
lo := hi
// iterate through declarations - they are sorted in decreasing xoffset order.
for l := gc.Curfn.Dcl; l != nil; l = l.Next {
n = l.N
if !n.Needzero {
continue
}
if n.Class != gc.PAUTO {
gc.Fatal("needzero class %d", n.Class)
}
if n.Type.Width%int64(gc.Widthptr) != 0 || n.Xoffset%int64(gc.Widthptr) != 0 || n.Type.Width == 0 {
gc.Fatal("var %v has size %d offset %d", gc.Nconv(n, obj.FmtLong), int(n.Type.Width), int(n.Xoffset))
}
if lo != hi && n.Xoffset+n.Type.Width >= lo-int64(2*gc.Widthreg) {
// merge with range we already have
lo = n.Xoffset
continue
}
// zero old range
p = zerorange(p, int64(frame), lo, hi)
// set new range
hi = n.Xoffset + n.Type.Width
lo = n.Xoffset
}
// zero final range
zerorange(p, int64(frame), lo, hi)
}
func zerorange(p *obj.Prog, frame int64, lo int64, hi int64) *obj.Prog {
cnt := hi - lo
if cnt == 0 {
return p
}
if cnt < int64(4*gc.Widthptr) {
for i := int64(0); i < cnt; i += int64(gc.Widthptr) {
p = appendpp(p, ppc64.AMOVD, obj.TYPE_REG, ppc64.REGZERO, 0, obj.TYPE_MEM, ppc64.REGSP, 8+frame+lo+i)
}
} else if cnt <= int64(128*gc.Widthptr) {
p = appendpp(p, ppc64.AADD, obj.TYPE_CONST, 0, 8+frame+lo-8, obj.TYPE_REG, ppc64.REGRT1, 0)
p.Reg = ppc64.REGSP
p = appendpp(p, obj.ADUFFZERO, obj.TYPE_NONE, 0, 0, obj.TYPE_MEM, 0, 0)
f := gc.Sysfunc("duffzero")
p.To = gc.Naddr(f, 1)
gc.Afunclit(&p.To, f)
p.To.Offset = 4 * (128 - cnt/int64(gc.Widthptr))
} else {
p = appendpp(p, ppc64.AMOVD, obj.TYPE_CONST, 0, 8+frame+lo-8, obj.TYPE_REG, ppc64.REGTMP, 0)
p = appendpp(p, ppc64.AADD, obj.TYPE_REG, ppc64.REGTMP, 0, obj.TYPE_REG, ppc64.REGRT1, 0)
p.Reg = ppc64.REGSP
p = appendpp(p, ppc64.AMOVD, obj.TYPE_CONST, 0, cnt, obj.TYPE_REG, ppc64.REGTMP, 0)
p = appendpp(p, ppc64.AADD, obj.TYPE_REG, ppc64.REGTMP, 0, obj.TYPE_REG, ppc64.REGRT2, 0)
p.Reg = ppc64.REGRT1
p = appendpp(p, ppc64.AMOVDU, obj.TYPE_REG, ppc64.REGZERO, 0, obj.TYPE_MEM, ppc64.REGRT1, int64(gc.Widthptr))
p1 := p
p = appendpp(p, ppc64.ACMP, obj.TYPE_REG, ppc64.REGRT1, 0, obj.TYPE_REG, ppc64.REGRT2, 0)
p = appendpp(p, ppc64.ABNE, obj.TYPE_NONE, 0, 0, obj.TYPE_BRANCH, 0, 0)
gc.Patch(p, p1)
}
return p
}
func appendpp(p *obj.Prog, as int, ftype int, freg int, foffset int64, ttype int, treg int, toffset int64) *obj.Prog {
q := gc.Ctxt.NewProg()
gc.Clearp(q)
q.As = int16(as)
q.Lineno = p.Lineno
q.From.Type = int16(ftype)
q.From.Reg = int16(freg)
q.From.Offset = foffset
q.To.Type = int16(ttype)
q.To.Reg = int16(treg)
q.To.Offset = toffset
q.Link = p.Link
p.Link = q
return q
}
/*
* generate: BL reg, f
* where both reg and f are registers.
* On power, f must be moved to CTR first.
*/
func ginsBL(reg *gc.Node, f *gc.Node) {
p := gins(ppc64.AMOVD, f, nil)
p.To.Type = obj.TYPE_REG
p.To.Reg = ppc64.REG_CTR
p = gins(ppc64.ABL, reg, nil)
p.To.Type = obj.TYPE_REG
p.To.Reg = ppc64.REG_CTR
}
/*
* generate:
* call f
* proc=-1 normal call but no return
* proc=0 normal call
* proc=1 goroutine run in new proc
* proc=2 defer call save away stack
* proc=3 normal call to C pointer (not Go func value)
*/
func ginscall(f *gc.Node, proc int) {
if f.Type != nil {
extra := int32(0)
if proc == 1 || proc == 2 {
extra = 2 * int32(gc.Widthptr)
}
gc.Setmaxarg(f.Type, extra)
}
switch proc {
default:
gc.Fatal("ginscall: bad proc %d", proc)
case 0, // normal call
-1: // normal call but no return
if f.Op == gc.ONAME && f.Class == gc.PFUNC {
if f == gc.Deferreturn {
// Deferred calls will appear to be returning to
// the CALL deferreturn(SB) that we are about to emit.
// However, the stack trace code will show the line
// of the instruction byte before the return PC.
// To avoid that being an unrelated instruction,
// insert a ppc64 NOP that we will have the right line number.
// The ppc64 NOP is really or r0, r0, r0; use that description
// because the NOP pseudo-instruction would be removed by
// the linker.
var reg gc.Node
gc.Nodreg(&reg, gc.Types[gc.TINT], ppc64.REG_R0)
gins(ppc64.AOR, &reg, &reg)
}
p := gins(ppc64.ABL, nil, f)
gc.Afunclit(&p.To, f)
if proc == -1 || gc.Noreturn(p) {
gins(obj.AUNDEF, nil, nil)
}
break
}
var reg gc.Node
gc.Nodreg(&reg, gc.Types[gc.Tptr], ppc64.REGCTXT)
var r1 gc.Node
gc.Nodreg(&r1, gc.Types[gc.Tptr], ppc64.REG_R3)
gmove(f, &reg)
reg.Op = gc.OINDREG
gmove(&reg, &r1)
reg.Op = gc.OREGISTER
ginsBL(&reg, &r1)
case 3: // normal call of c function pointer
ginsBL(nil, f)
case 1, // call in new proc (go)
2: // deferred call (defer)
var con gc.Node
gc.Nodconst(&con, gc.Types[gc.TINT64], int64(gc.Argsize(f.Type)))
var reg gc.Node
gc.Nodreg(&reg, gc.Types[gc.TINT64], ppc64.REG_R3)
var reg2 gc.Node
gc.Nodreg(&reg2, gc.Types[gc.TINT64], ppc64.REG_R4)
gmove(f, &reg)
gmove(&con, &reg2)
p := gins(ppc64.AMOVW, &reg2, nil)
p.To.Type = obj.TYPE_MEM
p.To.Reg = ppc64.REGSP
p.To.Offset = 8
p = gins(ppc64.AMOVD, &reg, nil)
p.To.Type = obj.TYPE_MEM
p.To.Reg = ppc64.REGSP
p.To.Offset = 16
if proc == 1 {
ginscall(gc.Newproc, 0)
} else {
if gc.Hasdefer == 0 {
gc.Fatal("hasdefer=0 but has defer")
}
ginscall(gc.Deferproc, 0)
}
if proc == 2 {
gc.Nodreg(&reg, gc.Types[gc.TINT64], ppc64.REG_R3)
p := gins(ppc64.ACMP, &reg, nil)
p.To.Type = obj.TYPE_REG
p.To.Reg = ppc64.REG_R0
p = gc.Gbranch(ppc64.ABEQ, nil, +1)
cgen_ret(nil)
gc.Patch(p, gc.Pc)
}
}
}
/*
* n is call to interface method.
* generate res = n.
*/
func cgen_callinter(n *gc.Node, res *gc.Node, proc int) {
i := n.Left
if i.Op != gc.ODOTINTER {
gc.Fatal("cgen_callinter: not ODOTINTER %v", gc.Oconv(int(i.Op), 0))
}
f := i.Right // field
if f.Op != gc.ONAME {
gc.Fatal("cgen_callinter: not ONAME %v", gc.Oconv(int(f.Op), 0))
}
i = i.Left // interface
if i.Addable == 0 {
var tmpi gc.Node
gc.Tempname(&tmpi, i.Type)
cgen(i, &tmpi)
i = &tmpi
}
gc.Genlist(n.List) // assign the args
// i is now addable, prepare an indirected
// register to hold its address.
var nodi gc.Node
igen(i, &nodi, res) // REG = &inter
var nodsp gc.Node
gc.Nodindreg(&nodsp, gc.Types[gc.Tptr], ppc64.REGSP)
nodsp.Xoffset = int64(gc.Widthptr)
if proc != 0 {
nodsp.Xoffset += 2 * int64(gc.Widthptr) // leave room for size & fn
}
nodi.Type = gc.Types[gc.Tptr]
nodi.Xoffset += int64(gc.Widthptr)
cgen(&nodi, &nodsp) // {8 or 24}(SP) = 8(REG) -- i.data
var nodo gc.Node
regalloc(&nodo, gc.Types[gc.Tptr], res)
nodi.Type = gc.Types[gc.Tptr]
nodi.Xoffset -= int64(gc.Widthptr)
cgen(&nodi, &nodo) // REG = 0(REG) -- i.tab
regfree(&nodi)
var nodr gc.Node
regalloc(&nodr, gc.Types[gc.Tptr], &nodo)
if n.Left.Xoffset == gc.BADWIDTH {
gc.Fatal("cgen_callinter: badwidth")
}
gc.Cgen_checknil(&nodo) // in case offset is huge
nodo.Op = gc.OINDREG
nodo.Xoffset = n.Left.Xoffset + 3*int64(gc.Widthptr) + 8
if proc == 0 {
// plain call: use direct c function pointer - more efficient
cgen(&nodo, &nodr) // REG = 32+offset(REG) -- i.tab->fun[f]
proc = 3
} else {
// go/defer. generate go func value.
p := gins(ppc64.AMOVD, &nodo, &nodr) // REG = &(32+offset(REG)) -- i.tab->fun[f]
p.From.Type = obj.TYPE_ADDR
}
nodr.Type = n.Left.Type
ginscall(&nodr, proc)
regfree(&nodr)
regfree(&nodo)
}
/*
* generate function call;
* proc=0 normal call
* proc=1 goroutine run in new proc
* proc=2 defer call save away stack
*/
func cgen_call(n *gc.Node, proc int) {
if n == nil {
return
}
var afun gc.Node
if n.Left.Ullman >= gc.UINF {
// if name involves a fn call
// precompute the address of the fn
gc.Tempname(&afun, gc.Types[gc.Tptr])
cgen(n.Left, &afun)
}
gc.Genlist(n.List) // assign the args
t := n.Left.Type
// call tempname pointer
if n.Left.Ullman >= gc.UINF {
var nod gc.Node
regalloc(&nod, gc.Types[gc.Tptr], nil)
gc.Cgen_as(&nod, &afun)
nod.Type = t
ginscall(&nod, proc)
regfree(&nod)
return
}
// call pointer
if n.Left.Op != gc.ONAME || n.Left.Class != gc.PFUNC {
var nod gc.Node
regalloc(&nod, gc.Types[gc.Tptr], nil)
gc.Cgen_as(&nod, n.Left)
nod.Type = t
ginscall(&nod, proc)
regfree(&nod)
return
}
// call direct
n.Left.Method = 1
ginscall(n.Left, proc)
}
/*
* call to n has already been generated.
* generate:
* res = return value from call.
*/
func cgen_callret(n *gc.Node, res *gc.Node) {
t := n.Left.Type
if t.Etype == gc.TPTR32 || t.Etype == gc.TPTR64 {
t = t.Type
}
var flist gc.Iter
fp := gc.Structfirst(&flist, gc.Getoutarg(t))
if fp == nil {
gc.Fatal("cgen_callret: nil")
}
var nod gc.Node
nod.Op = gc.OINDREG
nod.Val.U.Reg = ppc64.REGSP
nod.Addable = 1
nod.Xoffset = fp.Width + int64(gc.Widthptr) // +widthptr: saved LR at 0(R1)
nod.Type = fp.Type
gc.Cgen_as(res, &nod)
}
/*
* call to n has already been generated.
* generate:
* res = &return value from call.
*/
func cgen_aret(n *gc.Node, res *gc.Node) {
t := n.Left.Type
if gc.Isptr[t.Etype] {
t = t.Type
}
var flist gc.Iter
fp := gc.Structfirst(&flist, gc.Getoutarg(t))
if fp == nil {
gc.Fatal("cgen_aret: nil")
}
var nod1 gc.Node
nod1.Op = gc.OINDREG
nod1.Val.U.Reg = ppc64.REGSP
nod1.Addable = 1
nod1.Xoffset = fp.Width + int64(gc.Widthptr) // +widthptr: saved lr at 0(SP)
nod1.Type = fp.Type
if res.Op != gc.OREGISTER {
var nod2 gc.Node
regalloc(&nod2, gc.Types[gc.Tptr], res)
agen(&nod1, &nod2)
gins(ppc64.AMOVD, &nod2, res)
regfree(&nod2)
} else {
agen(&nod1, res)
}
}
/*
* generate return.
* n->left is assignments to return values.
*/
func cgen_ret(n *gc.Node) {
if n != nil {
gc.Genlist(n.List) // copy out args
}
if gc.Hasdefer != 0 {
ginscall(gc.Deferreturn, 0)
}
gc.Genlist(gc.Curfn.Exit)
p := gins(obj.ARET, nil, nil)
if n != nil && n.Op == gc.ORETJMP {
p.To.Name = obj.NAME_EXTERN
p.To.Type = obj.TYPE_ADDR
p.To.Sym = gc.Linksym(n.Left.Sym)
}
}
/*
* generate division.
* generates one of:
* res = nl / nr
* res = nl % nr
* according to op.
*/
func dodiv(op int, nl *gc.Node, nr *gc.Node, res *gc.Node) {
// Have to be careful about handling
// most negative int divided by -1 correctly.
// The hardware will generate undefined result.
// Also need to explicitly trap on division on zero,
// the hardware will silently generate undefined result.
// DIVW will leave unpredicable result in higher 32-bit,
// so always use DIVD/DIVDU.
t := nl.Type
t0 := t
check := 0
if gc.Issigned[t.Etype] {
check = 1
if gc.Isconst(nl, gc.CTINT) && gc.Mpgetfix(nl.Val.U.Xval) != -(1<<uint64(t.Width*8-1)) {
check = 0
} else if gc.Isconst(nr, gc.CTINT) && gc.Mpgetfix(nr.Val.U.Xval) != -1 {
check = 0
}
}
if t.Width < 8 {
if gc.Issigned[t.Etype] {
t = gc.Types[gc.TINT64]
} else {
t = gc.Types[gc.TUINT64]
}
check = 0
}
a := optoas(gc.ODIV, t)
var tl gc.Node
regalloc(&tl, t0, nil)
var tr gc.Node
regalloc(&tr, t0, nil)
if nl.Ullman >= nr.Ullman {
cgen(nl, &tl)
cgen(nr, &tr)
} else {
cgen(nr, &tr)
cgen(nl, &tl)
}
if t != t0 {
// Convert
tl2 := tl
tr2 := tr
tl.Type = t
tr.Type = t
gmove(&tl2, &tl)
gmove(&tr2, &tr)
}
// Handle divide-by-zero panic.
p1 := gins(optoas(gc.OCMP, t), &tr, nil)
p1.To.Type = obj.TYPE_REG
p1.To.Reg = ppc64.REGZERO
p1 = gc.Gbranch(optoas(gc.ONE, t), nil, +1)
if panicdiv == nil {
panicdiv = gc.Sysfunc("panicdivide")
}
ginscall(panicdiv, -1)
gc.Patch(p1, gc.Pc)
var p2 *obj.Prog
if check != 0 {
var nm1 gc.Node
gc.Nodconst(&nm1, t, -1)
gins(optoas(gc.OCMP, t), &tr, &nm1)
p1 := gc.Gbranch(optoas(gc.ONE, t), nil, +1)
if op == gc.ODIV {
// a / (-1) is -a.
gins(optoas(gc.OMINUS, t), nil, &tl)
gmove(&tl, res)
} else {
// a % (-1) is 0.
var nz gc.Node
gc.Nodconst(&nz, t, 0)
gmove(&nz, res)
}
p2 = gc.Gbranch(obj.AJMP, nil, 0)
gc.Patch(p1, gc.Pc)
}
p1 = gins(a, &tr, &tl)
if op == gc.ODIV {
regfree(&tr)
gmove(&tl, res)
} else {
// A%B = A-(A/B*B)
var tm gc.Node
regalloc(&tm, t, nil)
// patch div to use the 3 register form
// TODO(minux): add gins3?
p1.Reg = p1.To.Reg
p1.To.Reg = tm.Val.U.Reg
gins(optoas(gc.OMUL, t), &tr, &tm)
regfree(&tr)
gins(optoas(gc.OSUB, t), &tm, &tl)
regfree(&tm)
gmove(&tl, res)
}
regfree(&tl)
if check != 0 {
gc.Patch(p2, gc.Pc)
}
}
/*
* generate division according to op, one of:
* res = nl / nr
* res = nl % nr
*/
func cgen_div(op int, nl *gc.Node, nr *gc.Node, res *gc.Node) {
// TODO(minux): enable division by magic multiply (also need to fix longmod below)
//if(nr->op != OLITERAL)
// division and mod using (slow) hardware instruction
dodiv(op, nl, nr, res)
return
}
/*
* generate high multiply:
* res = (nl*nr) >> width
*/
func cgen_hmul(nl *gc.Node, nr *gc.Node, res *gc.Node) {
// largest ullman on left.
if nl.Ullman < nr.Ullman {
tmp := (*gc.Node)(nl)
nl = nr
nr = tmp
}
t := (*gc.Type)(nl.Type)
w := int(int(t.Width * 8))
var n1 gc.Node
cgenr(nl, &n1, res)
var n2 gc.Node
cgenr(nr, &n2, nil)
switch gc.Simtype[t.Etype] {
case gc.TINT8,
gc.TINT16,
gc.TINT32:
gins(optoas(gc.OMUL, t), &n2, &n1)
p := (*obj.Prog)(gins(ppc64.ASRAD, nil, &n1))
p.From.Type = obj.TYPE_CONST
p.From.Offset = int64(w)
case gc.TUINT8,
gc.TUINT16,
gc.TUINT32:
gins(optoas(gc.OMUL, t), &n2, &n1)
p := (*obj.Prog)(gins(ppc64.ASRD, nil, &n1))
p.From.Type = obj.TYPE_CONST
p.From.Offset = int64(w)
case gc.TINT64,
gc.TUINT64:
if gc.Issigned[t.Etype] {
gins(ppc64.AMULHD, &n2, &n1)
} else {
gins(ppc64.AMULHDU, &n2, &n1)
}
default:
gc.Fatal("cgen_hmul %v", gc.Tconv(t, 0))
}
cgen(&n1, res)
regfree(&n1)
regfree(&n2)
}
/*
* generate shift according to op, one of:
* res = nl << nr
* res = nl >> nr
*/
func cgen_shift(op int, bounded bool, nl *gc.Node, nr *gc.Node, res *gc.Node) {
a := int(optoas(op, nl.Type))
if nr.Op == gc.OLITERAL {
var n1 gc.Node
regalloc(&n1, nl.Type, res)
cgen(nl, &n1)
sc := uint64(uint64(gc.Mpgetfix(nr.Val.U.Xval)))
if sc >= uint64(nl.Type.Width*8) {
// large shift gets 2 shifts by width-1
var n3 gc.Node
gc.Nodconst(&n3, gc.Types[gc.TUINT32], nl.Type.Width*8-1)
gins(a, &n3, &n1)
gins(a, &n3, &n1)
} else {
gins(a, nr, &n1)
}
gmove(&n1, res)
regfree(&n1)
return
}
if nl.Ullman >= gc.UINF {
var n4 gc.Node
gc.Tempname(&n4, nl.Type)
cgen(nl, &n4)
nl = &n4
}
if nr.Ullman >= gc.UINF {
var n5 gc.Node
gc.Tempname(&n5, nr.Type)
cgen(nr, &n5)
nr = &n5
}
// Allow either uint32 or uint64 as shift type,
// to avoid unnecessary conversion from uint32 to uint64
// just to do the comparison.
tcount := gc.Types[gc.Simtype[nr.Type.Etype]]
if tcount.Etype < gc.TUINT32 {
tcount = gc.Types[gc.TUINT32]
}
var n1 gc.Node
regalloc(&n1, nr.Type, nil) // to hold the shift type in CX
var n3 gc.Node
regalloc(&n3, tcount, &n1) // to clear high bits of CX
var n2 gc.Node
regalloc(&n2, nl.Type, res)
if nl.Ullman >= nr.Ullman {
cgen(nl, &n2)
cgen(nr, &n1)
gmove(&n1, &n3)
} else {
cgen(nr, &n1)
gmove(&n1, &n3)
cgen(nl, &n2)
}
regfree(&n3)
// test and fix up large shifts
if !bounded {
gc.Nodconst(&n3, tcount, nl.Type.Width*8)
gins(optoas(gc.OCMP, tcount), &n1, &n3)
p1 := (*obj.Prog)(gc.Gbranch(optoas(gc.OLT, tcount), nil, +1))
if op == gc.ORSH && gc.Issigned[nl.Type.Etype] {
gc.Nodconst(&n3, gc.Types[gc.TUINT32], nl.Type.Width*8-1)
gins(a, &n3, &n2)
} else {
gc.Nodconst(&n3, nl.Type, 0)
gmove(&n3, &n2)
}
gc.Patch(p1, gc.Pc)
}
gins(a, &n1, &n2)
gmove(&n2, res)
regfree(&n1)
regfree(&n2)
}
func clearfat(nl *gc.Node) {
/* clear a fat object */
if gc.Debug['g'] != 0 {
fmt.Printf("clearfat %v (%v, size: %d)\n", gc.Nconv(nl, 0), gc.Tconv(nl.Type, 0), nl.Type.Width)
}
w := uint64(uint64(nl.Type.Width))
// Avoid taking the address for simple enough types.
//if(componentgen(N, nl))
// return;
c := uint64(w % 8) // bytes
q := uint64(w / 8) // dwords
if reg[ppc64.REGRT1-ppc64.REG_R0] > 0 {
gc.Fatal("R%d in use during clearfat", ppc64.REGRT1-ppc64.REG_R0)
}
var r0 gc.Node
gc.Nodreg(&r0, gc.Types[gc.TUINT64], ppc64.REG_R0) // r0 is always zero
var dst gc.Node
gc.Nodreg(&dst, gc.Types[gc.Tptr], ppc64.REGRT1)
reg[ppc64.REGRT1-ppc64.REG_R0]++
agen(nl, &dst)
var boff uint64
if q > 128 {
p := gins(ppc64.ASUB, nil, &dst)
p.From.Type = obj.TYPE_CONST
p.From.Offset = 8
var end gc.Node
regalloc(&end, gc.Types[gc.Tptr], nil)
p = gins(ppc64.AMOVD, &dst, &end)
p.From.Type = obj.TYPE_ADDR
p.From.Offset = int64(q * 8)
p = gins(ppc64.AMOVDU, &r0, &dst)
p.To.Type = obj.TYPE_MEM
p.To.Offset = 8
pl := (*obj.Prog)(p)
p = gins(ppc64.ACMP, &dst, &end)
gc.Patch(gc.Gbranch(ppc64.ABNE, nil, 0), pl)
regfree(&end)
// The loop leaves R3 on the last zeroed dword
boff = 8
} else if q >= 4 {
p := gins(ppc64.ASUB, nil, &dst)
p.From.Type = obj.TYPE_CONST
p.From.Offset = 8
f := (*gc.Node)(gc.Sysfunc("duffzero"))
p = gins(obj.ADUFFZERO, nil, f)
gc.Afunclit(&p.To, f)
// 4 and 128 = magic constants: see ../../runtime/asm_ppc64x.s
p.To.Offset = int64(4 * (128 - q))
// duffzero leaves R3 on the last zeroed dword
boff = 8
} else {
var p *obj.Prog
for t := uint64(0); t < q; t++ {
p = gins(ppc64.AMOVD, &r0, &dst)
p.To.Type = obj.TYPE_MEM
p.To.Offset = int64(8 * t)
}
boff = 8 * q
}
var p *obj.Prog
for t := uint64(0); t < c; t++ {
p = gins(ppc64.AMOVB, &r0, &dst)
p.To.Type = obj.TYPE_MEM
p.To.Offset = int64(t + boff)
}
reg[ppc64.REGRT1-ppc64.REG_R0]--
}
// Called after regopt and peep have run.
// Expand CHECKNIL pseudo-op into actual nil pointer check.
func expandchecks(firstp *obj.Prog) {
var p1 *obj.Prog
var p2 *obj.Prog
for p := (*obj.Prog)(firstp); p != nil; p = p.Link {
if gc.Debug_checknil != 0 && gc.Ctxt.Debugvlog != 0 {
fmt.Printf("expandchecks: %v\n", p)
}
if p.As != obj.ACHECKNIL {
continue
}
if gc.Debug_checknil != 0 && p.Lineno > 1 { // p->lineno==1 in generated wrappers
gc.Warnl(int(p.Lineno), "generated nil check")
}
if p.From.Type != obj.TYPE_REG {
gc.Fatal("invalid nil check %v\n", p)
}
/*
// check is
// TD $4, R0, arg (R0 is always zero)
// eqv. to:
// tdeq r0, arg
// NOTE: this needs special runtime support to make SIGTRAP recoverable.
reg = p->from.reg;
p->as = ATD;
p->from = p->to = p->from3 = zprog.from;
p->from.type = TYPE_CONST;
p->from.offset = 4;
p->from.reg = 0;
p->reg = REG_R0;
p->to.type = TYPE_REG;
p->to.reg = reg;
*/
// check is
// CMP arg, R0
// BNE 2(PC) [likely]
// MOVD R0, 0(R0)
p1 = gc.Ctxt.NewProg()
p2 = gc.Ctxt.NewProg()
gc.Clearp(p1)
gc.Clearp(p2)
p1.Link = p2
p2.Link = p.Link
p.Link = p1
p1.Lineno = p.Lineno
p2.Lineno = p.Lineno
p1.Pc = 9999
p2.Pc = 9999
p.As = ppc64.ACMP
p.To.Type = obj.TYPE_REG
p.To.Reg = ppc64.REGZERO
p1.As = ppc64.ABNE
//p1->from.type = TYPE_CONST;
//p1->from.offset = 1; // likely
p1.To.Type = obj.TYPE_BRANCH
p1.To.U.Branch = p2.Link
// crash by write to memory address 0.
p2.As = ppc64.AMOVD
p2.From.Type = obj.TYPE_REG
p2.From.Reg = ppc64.REG_R0
p2.To.Type = obj.TYPE_MEM
p2.To.Reg = ppc64.REG_R0
p2.To.Offset = 0
}
}

1147
src/cmd/7g/gsubr.go Normal file

File diff suppressed because it is too large Load Diff

12
src/cmd/7g/opt.go Normal file
View File

@ -0,0 +1,12 @@
// 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.
package main
// Many Power ISA arithmetic and logical instructions come in four
// standard variants. These bits let us map between variants.
const (
V_CC = 1 << 0 // xCC (affect CR field 0 flags)
V_V = 1 << 1 // xV (affect SO and OV flags)
)

1053
src/cmd/7g/peep.go Normal file

File diff suppressed because it is too large Load Diff

316
src/cmd/7g/prog.go Normal file
View File

@ -0,0 +1,316 @@
// 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.
package main
import (
"cmd/internal/gc"
"cmd/internal/obj"
"cmd/internal/obj/ppc64"
)
const (
LeftRdwr uint32 = gc.LeftRead | gc.LeftWrite
RightRdwr uint32 = gc.RightRead | gc.RightWrite
)
// This table gives the basic information about instruction
// generated by the compiler and processed in the optimizer.
// See opt.h for bit definitions.
//
// Instructions not generated need not be listed.
// As an exception to that rule, we typically write down all the
// size variants of an operation even if we just use a subset.
//
// The table is formatted for 8-space tabs.
var progtable = [ppc64.ALAST]gc.ProgInfo{
obj.ATYPE: gc.ProgInfo{gc.Pseudo | gc.Skip, 0, 0, 0},
obj.ATEXT: gc.ProgInfo{gc.Pseudo, 0, 0, 0},
obj.AFUNCDATA: gc.ProgInfo{gc.Pseudo, 0, 0, 0},
obj.APCDATA: gc.ProgInfo{gc.Pseudo, 0, 0, 0},
obj.AUNDEF: gc.ProgInfo{gc.Break, 0, 0, 0},
obj.AUSEFIELD: gc.ProgInfo{gc.OK, 0, 0, 0},
obj.ACHECKNIL: gc.ProgInfo{gc.LeftRead, 0, 0, 0},
obj.AVARDEF: gc.ProgInfo{gc.Pseudo | gc.RightWrite, 0, 0, 0},
obj.AVARKILL: gc.ProgInfo{gc.Pseudo | gc.RightWrite, 0, 0, 0},
// NOP is an internal no-op that also stands
// for USED and SET annotations, not the Power opcode.
obj.ANOP: gc.ProgInfo{gc.LeftRead | gc.RightWrite, 0, 0, 0},
// Integer
ppc64.AADD: gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
ppc64.ASUB: gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
ppc64.ANEG: gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
ppc64.AAND: gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
ppc64.AOR: gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
ppc64.AXOR: gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
ppc64.AMULLD: gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
ppc64.AMULLW: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
ppc64.AMULHD: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
ppc64.AMULHDU: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
ppc64.ADIVD: gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
ppc64.ADIVDU: gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
ppc64.ASLD: gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
ppc64.ASRD: gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
ppc64.ASRAD: gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
ppc64.ACMP: gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RightRead, 0, 0, 0},
ppc64.ACMPU: gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RightRead, 0, 0, 0},
ppc64.ATD: gc.ProgInfo{gc.SizeQ | gc.RightRead, 0, 0, 0},
// Floating point.
ppc64.AFADD: gc.ProgInfo{gc.SizeD | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
ppc64.AFADDS: gc.ProgInfo{gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
ppc64.AFSUB: gc.ProgInfo{gc.SizeD | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
ppc64.AFSUBS: gc.ProgInfo{gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
ppc64.AFMUL: gc.ProgInfo{gc.SizeD | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
ppc64.AFMULS: gc.ProgInfo{gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
ppc64.AFDIV: gc.ProgInfo{gc.SizeD | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
ppc64.AFDIVS: gc.ProgInfo{gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
ppc64.AFCTIDZ: gc.ProgInfo{gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
ppc64.AFCFID: gc.ProgInfo{gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite, 0, 0, 0},
ppc64.AFCMPU: gc.ProgInfo{gc.SizeD | gc.LeftRead | gc.RightRead, 0, 0, 0},
ppc64.AFRSP: gc.ProgInfo{gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv, 0, 0, 0},
// Moves
ppc64.AMOVB: gc.ProgInfo{gc.SizeB | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv, 0, 0, 0},
ppc64.AMOVBU: gc.ProgInfo{gc.SizeB | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv | gc.PostInc, 0, 0, 0},
ppc64.AMOVBZ: gc.ProgInfo{gc.SizeB | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv, 0, 0, 0},
ppc64.AMOVH: gc.ProgInfo{gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv, 0, 0, 0},
ppc64.AMOVHU: gc.ProgInfo{gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv | gc.PostInc, 0, 0, 0},
ppc64.AMOVHZ: gc.ProgInfo{gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv, 0, 0, 0},
ppc64.AMOVW: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv, 0, 0, 0},
// there is no AMOVWU.
ppc64.AMOVWZU: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv | gc.PostInc, 0, 0, 0},
ppc64.AMOVWZ: gc.ProgInfo{gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv, 0, 0, 0},
ppc64.AMOVD: gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Move, 0, 0, 0},
ppc64.AMOVDU: gc.ProgInfo{gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Move | gc.PostInc, 0, 0, 0},
ppc64.AFMOVS: gc.ProgInfo{gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv, 0, 0, 0},
ppc64.AFMOVD: gc.ProgInfo{gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Move, 0, 0, 0},
// Jumps
ppc64.ABR: gc.ProgInfo{gc.Jump | gc.Break, 0, 0, 0},
ppc64.ABL: gc.ProgInfo{gc.Call, 0, 0, 0},
ppc64.ABEQ: gc.ProgInfo{gc.Cjmp, 0, 0, 0},
ppc64.ABNE: gc.ProgInfo{gc.Cjmp, 0, 0, 0},
ppc64.ABGE: gc.ProgInfo{gc.Cjmp, 0, 0, 0},
ppc64.ABLT: gc.ProgInfo{gc.Cjmp, 0, 0, 0},
ppc64.ABGT: gc.ProgInfo{gc.Cjmp, 0, 0, 0},
ppc64.ABLE: gc.ProgInfo{gc.Cjmp, 0, 0, 0},
ppc64.ARETURN: gc.ProgInfo{gc.Break, 0, 0, 0},
obj.ADUFFZERO: gc.ProgInfo{gc.Call, 0, 0, 0},
obj.ADUFFCOPY: gc.ProgInfo{gc.Call, 0, 0, 0},
}
var initproginfo_initialized int
func initproginfo() {
var addvariant = []int{V_CC, V_V, V_CC | V_V}
if initproginfo_initialized != 0 {
return
}
initproginfo_initialized = 1
// Perform one-time expansion of instructions in progtable to
// their CC, V, and VCC variants
var as2 int
var i int
var variant int
for as := int(0); as < len(progtable); as++ {
if progtable[as].Flags == 0 {
continue
}
variant = as2variant(as)
for i = 0; i < len(addvariant); i++ {
as2 = variant2as(as, variant|addvariant[i])
if as2 != 0 && progtable[as2].Flags == 0 {
progtable[as2] = progtable[as]
}
}
}
}
func proginfo(p *obj.Prog) (info gc.ProgInfo) {
initproginfo()
info = progtable[p.As]
if info.Flags == 0 {
info = progtable[ppc64.AADD]
gc.Fatal("proginfo: unknown instruction %v", p)
}
if (info.Flags&gc.RegRead != 0) && p.Reg == 0 {
info.Flags &^= gc.RegRead
info.Flags |= gc.RightRead /*CanRegRead |*/
}
if (p.From.Type == obj.TYPE_MEM || p.From.Type == obj.TYPE_ADDR) && p.From.Reg != 0 {
info.Regindex |= RtoB(int(p.From.Reg))
if info.Flags&gc.PostInc != 0 {
info.Regset |= RtoB(int(p.From.Reg))
}
}
if (p.To.Type == obj.TYPE_MEM || p.To.Type == obj.TYPE_ADDR) && p.To.Reg != 0 {
info.Regindex |= RtoB(int(p.To.Reg))
if info.Flags&gc.PostInc != 0 {
info.Regset |= RtoB(int(p.To.Reg))
}
}
if p.From.Type == obj.TYPE_ADDR && p.From.Sym != nil && (info.Flags&gc.LeftRead != 0) {
info.Flags &^= gc.LeftRead
info.Flags |= gc.LeftAddr
}
if p.As == obj.ADUFFZERO {
info.Reguse |= 1<<0 | RtoB(ppc64.REG_R3)
info.Regset |= RtoB(ppc64.REG_R3)
}
if p.As == obj.ADUFFCOPY {
// TODO(austin) Revisit when duffcopy is implemented
info.Reguse |= RtoB(ppc64.REG_R3) | RtoB(ppc64.REG_R4) | RtoB(ppc64.REG_R5)
info.Regset |= RtoB(ppc64.REG_R3) | RtoB(ppc64.REG_R4)
}
return
}
// Instruction variants table. Initially this contains entries only
// for the "base" form of each instruction. On the first call to
// as2variant or variant2as, we'll add the variants to the table.
var varianttable = [ppc64.ALAST][4]int{
ppc64.AADD: [4]int{ppc64.AADD, ppc64.AADDCC, ppc64.AADDV, ppc64.AADDVCC},
ppc64.AADDC: [4]int{ppc64.AADDC, ppc64.AADDCCC, ppc64.AADDCV, ppc64.AADDCVCC},
ppc64.AADDE: [4]int{ppc64.AADDE, ppc64.AADDECC, ppc64.AADDEV, ppc64.AADDEVCC},
ppc64.AADDME: [4]int{ppc64.AADDME, ppc64.AADDMECC, ppc64.AADDMEV, ppc64.AADDMEVCC},
ppc64.AADDZE: [4]int{ppc64.AADDZE, ppc64.AADDZECC, ppc64.AADDZEV, ppc64.AADDZEVCC},
ppc64.AAND: [4]int{ppc64.AAND, ppc64.AANDCC, 0, 0},
ppc64.AANDN: [4]int{ppc64.AANDN, ppc64.AANDNCC, 0, 0},
ppc64.ACNTLZD: [4]int{ppc64.ACNTLZD, ppc64.ACNTLZDCC, 0, 0},
ppc64.ACNTLZW: [4]int{ppc64.ACNTLZW, ppc64.ACNTLZWCC, 0, 0},
ppc64.ADIVD: [4]int{ppc64.ADIVD, ppc64.ADIVDCC, ppc64.ADIVDV, ppc64.ADIVDVCC},
ppc64.ADIVDU: [4]int{ppc64.ADIVDU, ppc64.ADIVDUCC, ppc64.ADIVDUV, ppc64.ADIVDUVCC},
ppc64.ADIVW: [4]int{ppc64.ADIVW, ppc64.ADIVWCC, ppc64.ADIVWV, ppc64.ADIVWVCC},
ppc64.ADIVWU: [4]int{ppc64.ADIVWU, ppc64.ADIVWUCC, ppc64.ADIVWUV, ppc64.ADIVWUVCC},
ppc64.AEQV: [4]int{ppc64.AEQV, ppc64.AEQVCC, 0, 0},
ppc64.AEXTSB: [4]int{ppc64.AEXTSB, ppc64.AEXTSBCC, 0, 0},
ppc64.AEXTSH: [4]int{ppc64.AEXTSH, ppc64.AEXTSHCC, 0, 0},
ppc64.AEXTSW: [4]int{ppc64.AEXTSW, ppc64.AEXTSWCC, 0, 0},
ppc64.AFABS: [4]int{ppc64.AFABS, ppc64.AFABSCC, 0, 0},
ppc64.AFADD: [4]int{ppc64.AFADD, ppc64.AFADDCC, 0, 0},
ppc64.AFADDS: [4]int{ppc64.AFADDS, ppc64.AFADDSCC, 0, 0},
ppc64.AFCFID: [4]int{ppc64.AFCFID, ppc64.AFCFIDCC, 0, 0},
ppc64.AFCTID: [4]int{ppc64.AFCTID, ppc64.AFCTIDCC, 0, 0},
ppc64.AFCTIDZ: [4]int{ppc64.AFCTIDZ, ppc64.AFCTIDZCC, 0, 0},
ppc64.AFCTIW: [4]int{ppc64.AFCTIW, ppc64.AFCTIWCC, 0, 0},
ppc64.AFCTIWZ: [4]int{ppc64.AFCTIWZ, ppc64.AFCTIWZCC, 0, 0},
ppc64.AFDIV: [4]int{ppc64.AFDIV, ppc64.AFDIVCC, 0, 0},
ppc64.AFDIVS: [4]int{ppc64.AFDIVS, ppc64.AFDIVSCC, 0, 0},
ppc64.AFMADD: [4]int{ppc64.AFMADD, ppc64.AFMADDCC, 0, 0},
ppc64.AFMADDS: [4]int{ppc64.AFMADDS, ppc64.AFMADDSCC, 0, 0},
ppc64.AFMOVD: [4]int{ppc64.AFMOVD, ppc64.AFMOVDCC, 0, 0},
ppc64.AFMSUB: [4]int{ppc64.AFMSUB, ppc64.AFMSUBCC, 0, 0},
ppc64.AFMSUBS: [4]int{ppc64.AFMSUBS, ppc64.AFMSUBSCC, 0, 0},
ppc64.AFMUL: [4]int{ppc64.AFMUL, ppc64.AFMULCC, 0, 0},
ppc64.AFMULS: [4]int{ppc64.AFMULS, ppc64.AFMULSCC, 0, 0},
ppc64.AFNABS: [4]int{ppc64.AFNABS, ppc64.AFNABSCC, 0, 0},
ppc64.AFNEG: [4]int{ppc64.AFNEG, ppc64.AFNEGCC, 0, 0},
ppc64.AFNMADD: [4]int{ppc64.AFNMADD, ppc64.AFNMADDCC, 0, 0},
ppc64.AFNMADDS: [4]int{ppc64.AFNMADDS, ppc64.AFNMADDSCC, 0, 0},
ppc64.AFNMSUB: [4]int{ppc64.AFNMSUB, ppc64.AFNMSUBCC, 0, 0},
ppc64.AFNMSUBS: [4]int{ppc64.AFNMSUBS, ppc64.AFNMSUBSCC, 0, 0},
ppc64.AFRES: [4]int{ppc64.AFRES, ppc64.AFRESCC, 0, 0},
ppc64.AFRSP: [4]int{ppc64.AFRSP, ppc64.AFRSPCC, 0, 0},
ppc64.AFRSQRTE: [4]int{ppc64.AFRSQRTE, ppc64.AFRSQRTECC, 0, 0},
ppc64.AFSEL: [4]int{ppc64.AFSEL, ppc64.AFSELCC, 0, 0},
ppc64.AFSQRT: [4]int{ppc64.AFSQRT, ppc64.AFSQRTCC, 0, 0},
ppc64.AFSQRTS: [4]int{ppc64.AFSQRTS, ppc64.AFSQRTSCC, 0, 0},
ppc64.AFSUB: [4]int{ppc64.AFSUB, ppc64.AFSUBCC, 0, 0},
ppc64.AFSUBS: [4]int{ppc64.AFSUBS, ppc64.AFSUBSCC, 0, 0},
ppc64.AMTFSB0: [4]int{ppc64.AMTFSB0, ppc64.AMTFSB0CC, 0, 0},
ppc64.AMTFSB1: [4]int{ppc64.AMTFSB1, ppc64.AMTFSB1CC, 0, 0},
ppc64.AMULHD: [4]int{ppc64.AMULHD, ppc64.AMULHDCC, 0, 0},
ppc64.AMULHDU: [4]int{ppc64.AMULHDU, ppc64.AMULHDUCC, 0, 0},
ppc64.AMULHW: [4]int{ppc64.AMULHW, ppc64.AMULHWCC, 0, 0},
ppc64.AMULHWU: [4]int{ppc64.AMULHWU, ppc64.AMULHWUCC, 0, 0},
ppc64.AMULLD: [4]int{ppc64.AMULLD, ppc64.AMULLDCC, ppc64.AMULLDV, ppc64.AMULLDVCC},
ppc64.AMULLW: [4]int{ppc64.AMULLW, ppc64.AMULLWCC, ppc64.AMULLWV, ppc64.AMULLWVCC},
ppc64.ANAND: [4]int{ppc64.ANAND, ppc64.ANANDCC, 0, 0},
ppc64.ANEG: [4]int{ppc64.ANEG, ppc64.ANEGCC, ppc64.ANEGV, ppc64.ANEGVCC},
ppc64.ANOR: [4]int{ppc64.ANOR, ppc64.ANORCC, 0, 0},
ppc64.AOR: [4]int{ppc64.AOR, ppc64.AORCC, 0, 0},
ppc64.AORN: [4]int{ppc64.AORN, ppc64.AORNCC, 0, 0},
ppc64.AREM: [4]int{ppc64.AREM, ppc64.AREMCC, ppc64.AREMV, ppc64.AREMVCC},
ppc64.AREMD: [4]int{ppc64.AREMD, ppc64.AREMDCC, ppc64.AREMDV, ppc64.AREMDVCC},
ppc64.AREMDU: [4]int{ppc64.AREMDU, ppc64.AREMDUCC, ppc64.AREMDUV, ppc64.AREMDUVCC},
ppc64.AREMU: [4]int{ppc64.AREMU, ppc64.AREMUCC, ppc64.AREMUV, ppc64.AREMUVCC},
ppc64.ARLDC: [4]int{ppc64.ARLDC, ppc64.ARLDCCC, 0, 0},
ppc64.ARLDCL: [4]int{ppc64.ARLDCL, ppc64.ARLDCLCC, 0, 0},
ppc64.ARLDCR: [4]int{ppc64.ARLDCR, ppc64.ARLDCRCC, 0, 0},
ppc64.ARLDMI: [4]int{ppc64.ARLDMI, ppc64.ARLDMICC, 0, 0},
ppc64.ARLWMI: [4]int{ppc64.ARLWMI, ppc64.ARLWMICC, 0, 0},
ppc64.ARLWNM: [4]int{ppc64.ARLWNM, ppc64.ARLWNMCC, 0, 0},
ppc64.ASLD: [4]int{ppc64.ASLD, ppc64.ASLDCC, 0, 0},
ppc64.ASLW: [4]int{ppc64.ASLW, ppc64.ASLWCC, 0, 0},
ppc64.ASRAD: [4]int{ppc64.ASRAD, ppc64.ASRADCC, 0, 0},
ppc64.ASRAW: [4]int{ppc64.ASRAW, ppc64.ASRAWCC, 0, 0},
ppc64.ASRD: [4]int{ppc64.ASRD, ppc64.ASRDCC, 0, 0},
ppc64.ASRW: [4]int{ppc64.ASRW, ppc64.ASRWCC, 0, 0},
ppc64.ASUB: [4]int{ppc64.ASUB, ppc64.ASUBCC, ppc64.ASUBV, ppc64.ASUBVCC},
ppc64.ASUBC: [4]int{ppc64.ASUBC, ppc64.ASUBCCC, ppc64.ASUBCV, ppc64.ASUBCVCC},
ppc64.ASUBE: [4]int{ppc64.ASUBE, ppc64.ASUBECC, ppc64.ASUBEV, ppc64.ASUBEVCC},
ppc64.ASUBME: [4]int{ppc64.ASUBME, ppc64.ASUBMECC, ppc64.ASUBMEV, ppc64.ASUBMEVCC},
ppc64.ASUBZE: [4]int{ppc64.ASUBZE, ppc64.ASUBZECC, ppc64.ASUBZEV, ppc64.ASUBZEVCC},
ppc64.AXOR: [4]int{ppc64.AXOR, ppc64.AXORCC, 0, 0},
}
var initvariants_initialized int
func initvariants() {
if initvariants_initialized != 0 {
return
}
initvariants_initialized = 1
var j int
for i := int(0); i < len(varianttable); i++ {
if varianttable[i][0] == 0 {
// Instruction has no variants
varianttable[i][0] = i
continue
}
// Copy base form to other variants
if varianttable[i][0] == i {
for j = 0; j < len(varianttable[i]); j++ {
varianttable[varianttable[i][j]] = varianttable[i]
}
}
}
}
// as2variant returns the variant (V_*) flags of instruction as.
func as2variant(as int) int {
initvariants()
for i := int(0); i < len(varianttable[as]); i++ {
if varianttable[as][i] == as {
return i
}
}
gc.Fatal("as2variant: instruction %v is not a variant of itself", obj.Aconv(as))
return 0
}
// variant2as returns the instruction as with the given variant (V_*) flags.
// If no such variant exists, this returns 0.
func variant2as(as int, flags int) int {
initvariants()
return varianttable[as][flags]
}

162
src/cmd/7g/reg.go Normal file
View File

@ -0,0 +1,162 @@
// Derived from Inferno utils/6c/reg.c
// http://code.google.com/p/inferno-os/source/browse/utils/6c/reg.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
// Portions Copyright © 1997-1999 Vita Nuova Limited
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
// Portions Copyright © 2004,2006 Bruce Ellis
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
// Portions Copyright © 2009 The Go Authors. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package main
import "cmd/internal/obj/ppc64"
import "cmd/internal/gc"
const (
NREGVAR = 64 /* 32 general + 32 floating */
)
var regname = []string{
".R0",
".R1",
".R2",
".R3",
".R4",
".R5",
".R6",
".R7",
".R8",
".R9",
".R10",
".R11",
".R12",
".R13",
".R14",
".R15",
".R16",
".R17",
".R18",
".R19",
".R20",
".R21",
".R22",
".R23",
".R24",
".R25",
".R26",
".R27",
".R28",
".R29",
".R30",
".R31",
".F0",
".F1",
".F2",
".F3",
".F4",
".F5",
".F6",
".F7",
".F8",
".F9",
".F10",
".F11",
".F12",
".F13",
".F14",
".F15",
".F16",
".F17",
".F18",
".F19",
".F20",
".F21",
".F22",
".F23",
".F24",
".F25",
".F26",
".F27",
".F28",
".F29",
".F30",
".F31",
}
func regnames(n *int) []string {
*n = NREGVAR
return regname
}
func excludedregs() uint64 {
// Exclude registers with fixed functions
regbits := uint64(1<<0 | RtoB(ppc64.REGSP) | RtoB(ppc64.REGG) | RtoB(ppc64.REGTLS))
// Also exclude floating point registers with fixed constants
regbits |= RtoB(ppc64.REG_F27) | RtoB(ppc64.REG_F28) | RtoB(ppc64.REG_F29) | RtoB(ppc64.REG_F30) | RtoB(ppc64.REG_F31)
return regbits
}
func doregbits(r int) uint64 {
return 0
}
/*
* track register variables including external registers:
* bit reg
* 0 R0
* 1 R1
* ... ...
* 31 R31
* 32+0 F0
* 32+1 F1
* ... ...
* 32+31 F31
*/
func RtoB(r int) uint64 {
if r > ppc64.REG_R0 && r <= ppc64.REG_R31 {
return 1 << uint(r-ppc64.REG_R0)
}
if r >= ppc64.REG_F0 && r <= ppc64.REG_F31 {
return 1 << uint(32+r-ppc64.REG_F0)
}
return 0
}
func BtoR(b uint64) int {
b &= 0xffffffff
if b == 0 {
return 0
}
return gc.Bitno(b) + ppc64.REG_R0
}
func BtoF(b uint64) int {
b >>= 32
if b == 0 {
return 0
}
return gc.Bitno(b) + ppc64.REG_F0
}

12
src/cmd/7g/util.go Normal file
View File

@ -0,0 +1,12 @@
// Copyright 2015 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.
package main
func bool2int(b bool) int {
if b {
return 1
}
return 0
}

819
src/cmd/7l/asm.go Normal file
View File

@ -0,0 +1,819 @@
// Inferno utils/5l/asm.c
// http://code.google.com/p/inferno-os/source/browse/utils/5l/asm.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
// Portions Copyright © 1997-1999 Vita Nuova Limited
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
// Portions Copyright © 2004,2006 Bruce Ellis
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
// Portions Copyright © 2009 The Go Authors. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package main
import (
"cmd/internal/ld"
"cmd/internal/obj"
"encoding/binary"
"fmt"
"log"
)
func needlib(name string) int {
if name[0] == '\x00' {
return 0
}
/* reuse hash code in symbol table */
p := fmt.Sprintf(".dynlib.%s", name)
s := ld.Linklookup(ld.Ctxt, p, 0)
if s.Type == 0 {
s.Type = 100 // avoid SDATA, etc.
return 1
}
return 0
}
func gentext() {
var s *ld.LSym
var stub *ld.LSym
var pprevtextp **ld.LSym
var r *ld.Reloc
var n string
var o1 uint32
var i int
// The ppc64 ABI PLT has similar concepts to other
// architectures, but is laid out quite differently. When we
// see an R_PPC64_REL24 relocation to a dynamic symbol
// (indicating that the call needs to go through the PLT), we
// generate up to three stubs and reserve a PLT slot.
//
// 1) The call site will be bl x; nop (where the relocation
// applies to the bl). We rewrite this to bl x_stub; ld
// r2,24(r1). The ld is necessary because x_stub will save
// r2 (the TOC pointer) at 24(r1) (the "TOC save slot").
//
// 2) We reserve space for a pointer in the .plt section (once
// per referenced dynamic function). .plt is a data
// section filled solely by the dynamic linker (more like
// .plt.got on other architectures). Initially, the
// dynamic linker will fill each slot with a pointer to the
// corresponding x@plt entry point.
//
// 3) We generate the "call stub" x_stub (once per dynamic
// function/object file pair). This saves the TOC in the
// TOC save slot, reads the function pointer from x's .plt
// slot and calls it like any other global entry point
// (including setting r12 to the function address).
//
// 4) We generate the "symbol resolver stub" x@plt (once per
// dynamic function). This is solely a branch to the glink
// resolver stub.
//
// 5) We generate the glink resolver stub (only once). This
// computes which symbol resolver stub we came through and
// invokes the dynamic resolver via a pointer provided by
// the dynamic linker. This will patch up the .plt slot to
// point directly at the function so future calls go
// straight from the call stub to the real function, and
// then call the function.
// NOTE: It's possible we could make ppc64 closer to other
// architectures: ppc64's .plt is like .plt.got on other
// platforms and ppc64's .glink is like .plt on other
// platforms.
// Find all R_PPC64_REL24 relocations that reference dynamic
// imports. Reserve PLT entries for these symbols and
// generate call stubs. The call stubs need to live in .text,
// which is why we need to do this pass this early.
//
// This assumes "case 1" from the ABI, where the caller needs
// us to save and restore the TOC pointer.
pprevtextp = &ld.Ctxt.Textp
for s = *pprevtextp; s != nil; (func() { pprevtextp = &s.Next; s = *pprevtextp })() {
for i = range s.R {
r = &s.R[i]
if r.Type != 256+ld.R_PPC64_REL24 || r.Sym.Type != ld.SDYNIMPORT {
continue
}
// Reserve PLT entry and generate symbol
// resolver
addpltsym(ld.Ctxt, r.Sym)
// Generate call stub
n = fmt.Sprintf("%s.%s", s.Name, r.Sym.Name)
stub = ld.Linklookup(ld.Ctxt, n, 0)
stub.Reachable = stub.Reachable || s.Reachable
if stub.Size == 0 {
// Need outer to resolve .TOC.
stub.Outer = s
// Link in to textp before s (we could
// do it after, but would have to skip
// the subsymbols)
*pprevtextp = stub
stub.Next = s
pprevtextp = &stub.Next
gencallstub(1, stub, r.Sym)
}
// Update the relocation to use the call stub
r.Sym = stub
// Restore TOC after bl. The compiler put a
// nop here for us to overwrite.
o1 = 0xe8410018 // ld r2,24(r1)
ld.Ctxt.Arch.ByteOrder.PutUint32(s.P[r.Off+4:], o1)
}
}
}
// Construct a call stub in stub that calls symbol targ via its PLT
// entry.
func gencallstub(abicase int, stub *ld.LSym, targ *ld.LSym) {
if abicase != 1 {
// If we see R_PPC64_TOCSAVE or R_PPC64_REL24_NOTOC
// relocations, we'll need to implement cases 2 and 3.
log.Fatalf("gencallstub only implements case 1 calls")
}
plt := ld.Linklookup(ld.Ctxt, ".plt", 0)
stub.Type = ld.STEXT
// Save TOC pointer in TOC save slot
ld.Adduint32(ld.Ctxt, stub, 0xf8410018) // std r2,24(r1)
// Load the function pointer from the PLT.
r := ld.Addrel(stub)
r.Off = int32(stub.Size)
r.Sym = plt
r.Add = int64(targ.Plt)
r.Siz = 2
if ld.Ctxt.Arch.ByteOrder == binary.BigEndian {
r.Off += int32(r.Siz)
}
r.Type = ld.R_POWER_TOC
r.Variant = ld.RV_POWER_HA
ld.Adduint32(ld.Ctxt, stub, 0x3d820000) // addis r12,r2,targ@plt@toc@ha
r = ld.Addrel(stub)
r.Off = int32(stub.Size)
r.Sym = plt
r.Add = int64(targ.Plt)
r.Siz = 2
if ld.Ctxt.Arch.ByteOrder == binary.BigEndian {
r.Off += int32(r.Siz)
}
r.Type = ld.R_POWER_TOC
r.Variant = ld.RV_POWER_LO
ld.Adduint32(ld.Ctxt, stub, 0xe98c0000) // ld r12,targ@plt@toc@l(r12)
// Jump to the loaded pointer
ld.Adduint32(ld.Ctxt, stub, 0x7d8903a6) // mtctr r12
ld.Adduint32(ld.Ctxt, stub, 0x4e800420) // bctr
}
func adddynrela(rel *ld.LSym, s *ld.LSym, r *ld.Reloc) {
log.Fatalf("adddynrela not implemented")
}
func adddynrel(s *ld.LSym, r *ld.Reloc) {
targ := r.Sym
ld.Ctxt.Cursym = s
switch r.Type {
default:
if r.Type >= 256 {
ld.Diag("unexpected relocation type %d", r.Type)
return
}
// Handle relocations found in ELF object files.
case 256 + ld.R_PPC64_REL24:
r.Type = ld.R_CALLPOWER
// This is a local call, so the caller isn't setting
// up r12 and r2 is the same for the caller and
// callee. Hence, we need to go to the local entry
// point. (If we don't do this, the callee will try
// to use r12 to compute r2.)
r.Add += int64(r.Sym.Localentry) * 4
if targ.Type == ld.SDYNIMPORT {
// Should have been handled in elfsetupplt
ld.Diag("unexpected R_PPC64_REL24 for dyn import")
}
return
case 256 + ld.R_PPC64_ADDR64:
r.Type = ld.R_ADDR
if targ.Type == ld.SDYNIMPORT {
// These happen in .toc sections
adddynsym(ld.Ctxt, targ)
rela := ld.Linklookup(ld.Ctxt, ".rela", 0)
ld.Addaddrplus(ld.Ctxt, rela, s, int64(r.Off))
ld.Adduint64(ld.Ctxt, rela, ld.ELF64_R_INFO(uint32(targ.Dynid), ld.R_PPC64_ADDR64))
ld.Adduint64(ld.Ctxt, rela, uint64(r.Add))
r.Type = 256 // ignore during relocsym
}
return
case 256 + ld.R_PPC64_TOC16:
r.Type = ld.R_POWER_TOC
r.Variant = ld.RV_POWER_LO | ld.RV_CHECK_OVERFLOW
return
case 256 + ld.R_PPC64_TOC16_LO:
r.Type = ld.R_POWER_TOC
r.Variant = ld.RV_POWER_LO
return
case 256 + ld.R_PPC64_TOC16_HA:
r.Type = ld.R_POWER_TOC
r.Variant = ld.RV_POWER_HA | ld.RV_CHECK_OVERFLOW
return
case 256 + ld.R_PPC64_TOC16_HI:
r.Type = ld.R_POWER_TOC
r.Variant = ld.RV_POWER_HI | ld.RV_CHECK_OVERFLOW
return
case 256 + ld.R_PPC64_TOC16_DS:
r.Type = ld.R_POWER_TOC
r.Variant = ld.RV_POWER_DS | ld.RV_CHECK_OVERFLOW
return
case 256 + ld.R_PPC64_TOC16_LO_DS:
r.Type = ld.R_POWER_TOC
r.Variant = ld.RV_POWER_DS
return
case 256 + ld.R_PPC64_REL16_LO:
r.Type = ld.R_PCREL
r.Variant = ld.RV_POWER_LO
r.Add += 2 // Compensate for relocation size of 2
return
case 256 + ld.R_PPC64_REL16_HI:
r.Type = ld.R_PCREL
r.Variant = ld.RV_POWER_HI | ld.RV_CHECK_OVERFLOW
r.Add += 2
return
case 256 + ld.R_PPC64_REL16_HA:
r.Type = ld.R_PCREL
r.Variant = ld.RV_POWER_HA | ld.RV_CHECK_OVERFLOW
r.Add += 2
return
}
// Handle references to ELF symbols from our own object files.
if targ.Type != ld.SDYNIMPORT {
return
}
// TODO(austin): Translate our relocations to ELF
ld.Diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ.Name, r.Type, targ.Type)
}
func elfreloc1(r *ld.Reloc, sectoff int64) int {
// TODO(minux)
return -1
}
func elfsetupplt() {
plt := ld.Linklookup(ld.Ctxt, ".plt", 0)
if plt.Size == 0 {
// The dynamic linker stores the address of the
// dynamic resolver and the DSO identifier in the two
// doublewords at the beginning of the .plt section
// before the PLT array. Reserve space for these.
plt.Size = 16
}
}
func machoreloc1(r *ld.Reloc, sectoff int64) int {
return -1
}
// Return the value of .TOC. for symbol s
func symtoc(s *ld.LSym) int64 {
var toc *ld.LSym
if s.Outer != nil {
toc = ld.Linkrlookup(ld.Ctxt, ".TOC.", int(s.Outer.Version))
} else {
toc = ld.Linkrlookup(ld.Ctxt, ".TOC.", int(s.Version))
}
if toc == nil {
ld.Diag("TOC-relative relocation in object without .TOC.")
return 0
}
return toc.Value
}
func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int {
if ld.Linkmode == ld.LinkExternal {
// TODO(minux): translate R_ADDRPOWER and R_CALLPOWER into standard ELF relocations.
// R_ADDRPOWER corresponds to R_PPC_ADDR16_HA and R_PPC_ADDR16_LO.
// R_CALLPOWER corresponds to R_PPC_REL24.
return -1
}
switch r.Type {
case ld.R_CONST:
*val = r.Add
return 0
case ld.R_GOTOFF:
*val = ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ld.Linklookup(ld.Ctxt, ".got", 0))
return 0
case ld.R_ADDRPOWER:
// r->add is two ppc64 instructions holding an immediate 32-bit constant.
// We want to add r->sym's address to that constant.
// The encoding of the immediate x<<16 + y,
// where x is the low 16 bits of the first instruction and y is the low 16
// bits of the second. Both x and y are signed (int16, not uint16).
o1 := uint32(r.Add >> 32)
o2 := uint32(r.Add)
t := ld.Symaddr(r.Sym)
if t < 0 {
ld.Ctxt.Diag("relocation for %s is too big (>=2G): %d", s.Name, ld.Symaddr(r.Sym))
}
t += int64((o1&0xffff)<<16 + uint32(int32(o2)<<16>>16))
if t&0x8000 != 0 {
t += 0x10000
}
o1 = o1&0xffff0000 | (uint32(t)>>16)&0xffff
o2 = o2&0xffff0000 | uint32(t)&0xffff
// when laid out, the instruction order must always be o1, o2.
if ld.Ctxt.Arch.ByteOrder == binary.BigEndian {
*val = int64(o1)<<32 | int64(o2)
} else {
*val = int64(o2)<<32 | int64(o1)
}
return 0
case ld.R_CALLPOWER:
// Bits 6 through 29 = (S + A - P) >> 2
var o1 uint32
if ld.Ctxt.Arch.ByteOrder == binary.BigEndian {
o1 = ld.Be32(s.P[r.Off:])
} else {
o1 = ld.Le32(s.P[r.Off:])
}
t := ld.Symaddr(r.Sym) + r.Add - (s.Value + int64(r.Off))
if t&3 != 0 {
ld.Ctxt.Diag("relocation for %s+%d is not aligned: %d", r.Sym.Name, r.Off, t)
}
if int64(int32(t<<6)>>6) != t {
// TODO(austin) This can happen if text > 32M.
// Add a call trampoline to .text in that case.
ld.Ctxt.Diag("relocation for %s+%d is too big: %d", r.Sym.Name, r.Off, t)
}
*val = int64(o1&0xfc000003 | uint32(t)&^0xfc000003)
return 0
case ld.R_POWER_TOC: // S + A - .TOC.
*val = ld.Symaddr(r.Sym) + r.Add - symtoc(s)
return 0
}
return -1
}
func archrelocvariant(r *ld.Reloc, s *ld.LSym, t int64) int64 {
switch r.Variant & ld.RV_TYPE_MASK {
default:
ld.Diag("unexpected relocation variant %d", r.Variant)
fallthrough
case ld.RV_NONE:
return t
case ld.RV_POWER_LO:
if r.Variant&ld.RV_CHECK_OVERFLOW != 0 {
// Whether to check for signed or unsigned
// overflow depends on the instruction
var o1 uint32
if ld.Ctxt.Arch.ByteOrder == binary.BigEndian {
o1 = ld.Be32(s.P[r.Off-2:])
} else {
o1 = ld.Le32(s.P[r.Off:])
}
switch o1 >> 26 {
case 24, // ori
26, // xori
28: // andi
if t>>16 != 0 {
goto overflow
}
default:
if int64(int16(t)) != t {
goto overflow
}
}
}
return int64(int16(t))
case ld.RV_POWER_HA:
t += 0x8000
fallthrough
// Fallthrough
case ld.RV_POWER_HI:
t >>= 16
if r.Variant&ld.RV_CHECK_OVERFLOW != 0 {
// Whether to check for signed or unsigned
// overflow depends on the instruction
var o1 uint32
if ld.Ctxt.Arch.ByteOrder == binary.BigEndian {
o1 = ld.Be32(s.P[r.Off-2:])
} else {
o1 = ld.Le32(s.P[r.Off:])
}
switch o1 >> 26 {
case 25, // oris
27, // xoris
29: // andis
if t>>16 != 0 {
goto overflow
}
default:
if int64(int16(t)) != t {
goto overflow
}
}
}
return int64(int16(t))
case ld.RV_POWER_DS:
var o1 uint32
if ld.Ctxt.Arch.ByteOrder == binary.BigEndian {
o1 = uint32(ld.Be16(s.P[r.Off:]))
} else {
o1 = uint32(ld.Le16(s.P[r.Off:]))
}
if t&3 != 0 {
ld.Diag("relocation for %s+%d is not aligned: %d", r.Sym.Name, r.Off, t)
}
if (r.Variant&ld.RV_CHECK_OVERFLOW != 0) && int64(int16(t)) != t {
goto overflow
}
return int64(o1)&0x3 | int64(int16(t))
}
overflow:
ld.Diag("relocation for %s+%d is too big: %d", r.Sym.Name, r.Off, t)
return t
}
func addpltsym(ctxt *ld.Link, s *ld.LSym) {
if s.Plt >= 0 {
return
}
adddynsym(ctxt, s)
if ld.Iself {
plt := ld.Linklookup(ctxt, ".plt", 0)
rela := ld.Linklookup(ctxt, ".rela.plt", 0)
if plt.Size == 0 {
elfsetupplt()
}
// Create the glink resolver if necessary
glink := ensureglinkresolver()
// Write symbol resolver stub (just a branch to the
// glink resolver stub)
r := ld.Addrel(glink)
r.Sym = glink
r.Off = int32(glink.Size)
r.Siz = 4
r.Type = ld.R_CALLPOWER
ld.Adduint32(ctxt, glink, 0x48000000) // b .glink
// In the ppc64 ABI, the dynamic linker is responsible
// for writing the entire PLT. We just need to
// reserve 8 bytes for each PLT entry and generate a
// JMP_SLOT dynamic relocation for it.
//
// TODO(austin): ABI v1 is different
s.Plt = int32(plt.Size)
plt.Size += 8
ld.Addaddrplus(ctxt, rela, plt, int64(s.Plt))
ld.Adduint64(ctxt, rela, ld.ELF64_R_INFO(uint32(s.Dynid), ld.R_PPC64_JMP_SLOT))
ld.Adduint64(ctxt, rela, 0)
} else {
ld.Diag("addpltsym: unsupported binary format")
}
}
// Generate the glink resolver stub if necessary and return the .glink section
func ensureglinkresolver() *ld.LSym {
glink := ld.Linklookup(ld.Ctxt, ".glink", 0)
if glink.Size != 0 {
return glink
}
// This is essentially the resolver from the ppc64 ELF ABI.
// At entry, r12 holds the address of the symbol resolver stub
// for the target routine and the argument registers hold the
// arguments for the target routine.
//
// This stub is PIC, so first get the PC of label 1 into r11.
// Other things will be relative to this.
ld.Adduint32(ld.Ctxt, glink, 0x7c0802a6) // mflr r0
ld.Adduint32(ld.Ctxt, glink, 0x429f0005) // bcl 20,31,1f
ld.Adduint32(ld.Ctxt, glink, 0x7d6802a6) // 1: mflr r11
ld.Adduint32(ld.Ctxt, glink, 0x7c0803a6) // mtlf r0
// Compute the .plt array index from the entry point address.
// Because this is PIC, everything is relative to label 1b (in
// r11):
// r0 = ((r12 - r11) - (res_0 - r11)) / 4 = (r12 - res_0) / 4
ld.Adduint32(ld.Ctxt, glink, 0x3800ffd0) // li r0,-(res_0-1b)=-48
ld.Adduint32(ld.Ctxt, glink, 0x7c006214) // add r0,r0,r12
ld.Adduint32(ld.Ctxt, glink, 0x7c0b0050) // sub r0,r0,r11
ld.Adduint32(ld.Ctxt, glink, 0x7800f082) // srdi r0,r0,2
// r11 = address of the first byte of the PLT
r := ld.Addrel(glink)
r.Off = int32(glink.Size)
r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
r.Siz = 8
r.Type = ld.R_ADDRPOWER
// addis r11,0,.plt@ha; addi r11,r11,.plt@l
r.Add = 0x3d600000<<32 | 0x396b0000
glink.Size += 8
// Load r12 = dynamic resolver address and r11 = DSO
// identifier from the first two doublewords of the PLT.
ld.Adduint32(ld.Ctxt, glink, 0xe98b0000) // ld r12,0(r11)
ld.Adduint32(ld.Ctxt, glink, 0xe96b0008) // ld r11,8(r11)
// Jump to the dynamic resolver
ld.Adduint32(ld.Ctxt, glink, 0x7d8903a6) // mtctr r12
ld.Adduint32(ld.Ctxt, glink, 0x4e800420) // bctr
// The symbol resolvers must immediately follow.
// res_0:
// Add DT_PPC64_GLINK .dynamic entry, which points to 32 bytes
// before the first symbol resolver stub.
s := ld.Linklookup(ld.Ctxt, ".dynamic", 0)
ld.Elfwritedynentsymplus(s, ld.DT_PPC64_GLINK, glink, glink.Size-32)
return glink
}
func adddynsym(ctxt *ld.Link, s *ld.LSym) {
if s.Dynid >= 0 {
return
}
if ld.Iself {
s.Dynid = int32(ld.Nelfsym)
ld.Nelfsym++
d := ld.Linklookup(ctxt, ".dynsym", 0)
name := s.Extname
ld.Adduint32(ctxt, d, uint32(ld.Addstring(ld.Linklookup(ctxt, ".dynstr", 0), name)))
/* type */
t := ld.STB_GLOBAL << 4
if s.Cgoexport != 0 && s.Type&ld.SMASK == ld.STEXT {
t |= ld.STT_FUNC
} else {
t |= ld.STT_OBJECT
}
ld.Adduint8(ctxt, d, uint8(t))
/* reserved */
ld.Adduint8(ctxt, d, 0)
/* section where symbol is defined */
if s.Type == ld.SDYNIMPORT {
ld.Adduint16(ctxt, d, ld.SHN_UNDEF)
} else {
ld.Adduint16(ctxt, d, 1)
}
/* value */
if s.Type == ld.SDYNIMPORT {
ld.Adduint64(ctxt, d, 0)
} else {
ld.Addaddr(ctxt, d, s)
}
/* size of object */
ld.Adduint64(ctxt, d, uint64(s.Size))
} else {
ld.Diag("adddynsym: unsupported binary format")
}
}
func adddynlib(lib string) {
if needlib(lib) == 0 {
return
}
if ld.Iself {
s := ld.Linklookup(ld.Ctxt, ".dynstr", 0)
if s.Size == 0 {
ld.Addstring(s, "")
}
ld.Elfwritedynent(ld.Linklookup(ld.Ctxt, ".dynamic", 0), ld.DT_NEEDED, uint64(ld.Addstring(s, lib)))
} else {
ld.Diag("adddynlib: unsupported binary format")
}
}
func asmb() {
if ld.Debug['v'] != 0 {
fmt.Fprintf(&ld.Bso, "%5.2f asmb\n", obj.Cputime())
}
ld.Bflush(&ld.Bso)
if ld.Iself {
ld.Asmbelfsetup()
}
sect := ld.Segtext.Sect
ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
ld.Codeblk(int64(sect.Vaddr), int64(sect.Length))
for sect = sect.Next; sect != nil; sect = sect.Next {
ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
ld.Datblk(int64(sect.Vaddr), int64(sect.Length))
}
if ld.Segrodata.Filelen > 0 {
if ld.Debug['v'] != 0 {
fmt.Fprintf(&ld.Bso, "%5.2f rodatblk\n", obj.Cputime())
}
ld.Bflush(&ld.Bso)
ld.Cseek(int64(ld.Segrodata.Fileoff))
ld.Datblk(int64(ld.Segrodata.Vaddr), int64(ld.Segrodata.Filelen))
}
if ld.Debug['v'] != 0 {
fmt.Fprintf(&ld.Bso, "%5.2f datblk\n", obj.Cputime())
}
ld.Bflush(&ld.Bso)
ld.Cseek(int64(ld.Segdata.Fileoff))
ld.Datblk(int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen))
/* output symbol table */
ld.Symsize = 0
ld.Lcsize = 0
symo := uint32(0)
if ld.Debug['s'] == 0 {
// TODO: rationalize
if ld.Debug['v'] != 0 {
fmt.Fprintf(&ld.Bso, "%5.2f sym\n", obj.Cputime())
}
ld.Bflush(&ld.Bso)
switch ld.HEADTYPE {
default:
if ld.Iself {
symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen)
symo = uint32(ld.Rnd(int64(symo), int64(ld.INITRND)))
}
case ld.Hplan9:
symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen)
}
ld.Cseek(int64(symo))
switch ld.HEADTYPE {
default:
if ld.Iself {
if ld.Debug['v'] != 0 {
fmt.Fprintf(&ld.Bso, "%5.2f elfsym\n", obj.Cputime())
}
ld.Asmelfsym()
ld.Cflush()
ld.Cwrite(ld.Elfstrdat)
if ld.Debug['v'] != 0 {
fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime())
}
ld.Dwarfemitdebugsections()
if ld.Linkmode == ld.LinkExternal {
ld.Elfemitreloc()
}
}
case ld.Hplan9:
ld.Asmplan9sym()
ld.Cflush()
sym := ld.Linklookup(ld.Ctxt, "pclntab", 0)
if sym != nil {
ld.Lcsize = int32(len(sym.P))
for i := 0; int32(i) < ld.Lcsize; i++ {
ld.Cput(uint8(sym.P[i]))
}
ld.Cflush()
}
}
}
ld.Ctxt.Cursym = nil
if ld.Debug['v'] != 0 {
fmt.Fprintf(&ld.Bso, "%5.2f header\n", obj.Cputime())
}
ld.Bflush(&ld.Bso)
ld.Cseek(0)
switch ld.HEADTYPE {
default:
case ld.Hplan9: /* plan 9 */
ld.Thearch.Lput(0x647) /* magic */
ld.Thearch.Lput(uint32(ld.Segtext.Filelen)) /* sizes */
ld.Thearch.Lput(uint32(ld.Segdata.Filelen))
ld.Thearch.Lput(uint32(ld.Segdata.Length - ld.Segdata.Filelen))
ld.Thearch.Lput(uint32(ld.Symsize)) /* nsyms */
ld.Thearch.Lput(uint32(ld.Entryvalue())) /* va of entry */
ld.Thearch.Lput(0)
ld.Thearch.Lput(uint32(ld.Lcsize))
case ld.Hlinux,
ld.Hfreebsd,
ld.Hnetbsd,
ld.Hopenbsd,
ld.Hnacl:
ld.Asmbelf(int64(symo))
}
ld.Cflush()
if ld.Debug['c'] != 0 {
fmt.Printf("textsize=%d\n", ld.Segtext.Filelen)
fmt.Printf("datsize=%d\n", ld.Segdata.Filelen)
fmt.Printf("bsssize=%d\n", ld.Segdata.Length-ld.Segdata.Filelen)
fmt.Printf("symsize=%d\n", ld.Symsize)
fmt.Printf("lcsize=%d\n", ld.Lcsize)
fmt.Printf("total=%d\n", ld.Segtext.Filelen+ld.Segdata.Length+uint64(ld.Symsize)+uint64(ld.Lcsize))
}
}

77
src/cmd/7l/l.go Normal file
View File

@ -0,0 +1,77 @@
// Inferno utils/5l/asm.c
// http://code.google.com/p/inferno-os/source/browse/utils/5l/asm.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
// Portions Copyright © 1997-1999 Vita Nuova Limited
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
// Portions Copyright © 2004,2006 Bruce Ellis
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
// Portions Copyright © 2009 The Go Authors. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package main
// Writing object files.
// cmd/9l/l.h from Vita Nuova.
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
// Portions Copyright © 1997-1999 Vita Nuova Limited
// Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com)
// Portions Copyright © 2004,2006 Bruce Ellis
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
// Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others
// Portions Copyright © 2009 The Go Authors. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
const (
thechar = '9'
PtrSize = 8
IntSize = 8
RegSize = 8
MaxAlign = 32 // max data alignment
FuncAlign = 8
MINLC = 4
)
/* Used by ../ld/dwarf.c */
const (
DWARFREGSP = 1
)

165
src/cmd/7l/obj.go Normal file
View File

@ -0,0 +1,165 @@
// Inferno utils/5l/obj.c
// http://code.google.com/p/inferno-os/source/browse/utils/5l/obj.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
// Portions Copyright © 1997-1999 Vita Nuova Limited
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
// Portions Copyright © 2004,2006 Bruce Ellis
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
// Portions Copyright © 2009 The Go Authors. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package main
import (
"cmd/internal/ld"
"cmd/internal/obj"
"fmt"
"log"
)
// Reading object files.
func main() {
linkarchinit()
ld.Ldmain()
}
func linkarchinit() {
ld.Thestring = obj.Getgoarch()
if ld.Thestring == "ppc64le" {
ld.Thelinkarch = &ld.Linkppc64le
} else {
ld.Thelinkarch = &ld.Linkppc64
}
ld.Thearch.Thechar = thechar
ld.Thearch.Ptrsize = ld.Thelinkarch.Ptrsize
ld.Thearch.Intsize = ld.Thelinkarch.Ptrsize
ld.Thearch.Regsize = ld.Thelinkarch.Regsize
ld.Thearch.Funcalign = FuncAlign
ld.Thearch.Maxalign = MaxAlign
ld.Thearch.Minlc = MINLC
ld.Thearch.Dwarfregsp = DWARFREGSP
ld.Thearch.Adddynlib = adddynlib
ld.Thearch.Adddynrel = adddynrel
ld.Thearch.Adddynsym = adddynsym
ld.Thearch.Archinit = archinit
ld.Thearch.Archreloc = archreloc
ld.Thearch.Archrelocvariant = archrelocvariant
ld.Thearch.Asmb = asmb
ld.Thearch.Elfreloc1 = elfreloc1
ld.Thearch.Elfsetupplt = elfsetupplt
ld.Thearch.Gentext = gentext
ld.Thearch.Machoreloc1 = machoreloc1
if ld.Thelinkarch == &ld.Linkppc64le {
ld.Thearch.Lput = ld.Lputl
ld.Thearch.Wput = ld.Wputl
ld.Thearch.Vput = ld.Vputl
} else {
ld.Thearch.Lput = ld.Lputb
ld.Thearch.Wput = ld.Wputb
ld.Thearch.Vput = ld.Vputb
}
// TODO(austin): ABI v1 uses /usr/lib/ld.so.1
ld.Thearch.Linuxdynld = "/lib64/ld64.so.1"
ld.Thearch.Freebsddynld = "XXX"
ld.Thearch.Openbsddynld = "XXX"
ld.Thearch.Netbsddynld = "XXX"
ld.Thearch.Dragonflydynld = "XXX"
ld.Thearch.Solarisdynld = "XXX"
}
func archinit() {
// getgoextlinkenabled is based on GO_EXTLINK_ENABLED when
// Go was built; see ../../make.bash.
if ld.Linkmode == ld.LinkAuto && obj.Getgoextlinkenabled() == "0" {
ld.Linkmode = ld.LinkInternal
}
switch ld.HEADTYPE {
default:
if ld.Linkmode == ld.LinkAuto {
ld.Linkmode = ld.LinkInternal
}
if ld.Linkmode == ld.LinkExternal && obj.Getgoextlinkenabled() != "1" {
log.Fatalf("cannot use -linkmode=external with -H %s", ld.Headstr(int(ld.HEADTYPE)))
}
}
switch ld.HEADTYPE {
default:
ld.Diag("unknown -H option")
ld.Errorexit()
fallthrough
case ld.Hplan9: /* plan 9 */
ld.HEADR = 32
if ld.INITTEXT == -1 {
ld.INITTEXT = 4128
}
if ld.INITDAT == -1 {
ld.INITDAT = 0
}
if ld.INITRND == -1 {
ld.INITRND = 4096
}
case ld.Hlinux: /* ppc64 elf */
if ld.Thestring == "ppc64" {
ld.Debug['d'] = 1 // TODO(austin): ELF ABI v1 not supported yet
}
ld.Elfinit()
ld.HEADR = ld.ELFRESERVE
if ld.INITTEXT == -1 {
ld.INITTEXT = 0x10000 + int64(ld.HEADR)
}
if ld.INITDAT == -1 {
ld.INITDAT = 0
}
if ld.INITRND == -1 {
ld.INITRND = 0x10000
}
case ld.Hnacl:
ld.Elfinit()
ld.HEADR = 0x10000
ld.Funcalign = 16
if ld.INITTEXT == -1 {
ld.INITTEXT = 0x20000
}
if ld.INITDAT == -1 {
ld.INITDAT = 0
}
if ld.INITRND == -1 {
ld.INITRND = 0x10000
}
}
if ld.INITDAT != 0 && ld.INITRND != 0 {
fmt.Printf("warning: -D0x%x is ignored because of -R0x%x\n", uint64(ld.INITDAT), uint32(ld.INITRND))
}
}

View File

@ -395,6 +395,8 @@ var goTools = map[string]targetDir{
"cmd/5l": toTool,
"cmd/6g": toTool,
"cmd/6l": toTool,
"cmd/7g": toTool,
"cmd/7l": toTool,
"cmd/8g": toTool,
"cmd/8l": toTool,
"cmd/9g": toTool,