mirror of https://github.com/golang/go.git
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:
parent
d7e043eaf5
commit
f00c19add5
File diff suppressed because it is too large
Load Diff
|
|
@ -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)
|
||||
}
|
||||
|
|
@ -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
|
||||
*/
|
||||
|
|
@ -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(®, gc.Types[gc.TINT], ppc64.REG_R0)
|
||||
|
||||
gins(ppc64.AOR, ®, ®)
|
||||
}
|
||||
|
||||
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(®, gc.Types[gc.Tptr], ppc64.REGCTXT)
|
||||
var r1 gc.Node
|
||||
gc.Nodreg(&r1, gc.Types[gc.Tptr], ppc64.REG_R3)
|
||||
gmove(f, ®)
|
||||
reg.Op = gc.OINDREG
|
||||
gmove(®, &r1)
|
||||
reg.Op = gc.OREGISTER
|
||||
ginsBL(®, &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(®, gc.Types[gc.TINT64], ppc64.REG_R3)
|
||||
var reg2 gc.Node
|
||||
gc.Nodreg(®2, gc.Types[gc.TINT64], ppc64.REG_R4)
|
||||
gmove(f, ®)
|
||||
|
||||
gmove(&con, ®2)
|
||||
p := gins(ppc64.AMOVW, ®2, nil)
|
||||
p.To.Type = obj.TYPE_MEM
|
||||
p.To.Reg = ppc64.REGSP
|
||||
p.To.Offset = 8
|
||||
|
||||
p = gins(ppc64.AMOVD, ®, 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(®, gc.Types[gc.TINT64], ppc64.REG_R3)
|
||||
p := gins(ppc64.ACMP, ®, 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
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -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)
|
||||
)
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -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]
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
)
|
||||
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
Loading…
Reference in New Issue