Skip to content
Permalink
b2482e4817
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
 
 
Cannot retrieve contributors at this time
282 lines (253 sloc) 7.31 KB
// Copyright 2013 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 obj
import (
"cmd/internal/objabi"
"fmt"
"strings"
)
type Plist struct {
Firstpc *Prog
Curfn interface{} // holds a *gc.Node, if non-nil
}
// ProgAlloc is a function that allocates Progs.
// It is used to provide access to cached/bulk-allocated Progs to the assemblers.
type ProgAlloc func() *Prog
func Flushplist(ctxt *Link, plist *Plist, newprog ProgAlloc, myimportpath string) {
// Build list of symbols, and assign instructions to lists.
var curtext *LSym
var etext *Prog
var text []*LSym
var plink *Prog
for p := plist.Firstpc; p != nil; p = plink {
if ctxt.Debugasm > 0 && ctxt.Debugvlog {
fmt.Printf("obj: %v\n", p)
}
plink = p.Link
p.Link = nil
switch p.As {
case AEND:
continue
case ATEXT:
s := p.From.Sym
if s == nil {
// func _() { }
curtext = nil
continue
}
text = append(text, s)
etext = p
curtext = s
continue
case AFUNCDATA:
// Rewrite reference to go_args_stackmap(SB) to the Go-provided declaration information.
if curtext == nil { // func _() {}
continue
}
if p.To.Sym.Name == "go_args_stackmap" {
if p.From.Type != TYPE_CONST || p.From.Offset != objabi.FUNCDATA_ArgsPointerMaps {
ctxt.Diag("FUNCDATA use of go_args_stackmap(SB) without FUNCDATA_ArgsPointerMaps")
}
p.To.Sym = ctxt.LookupDerived(curtext, curtext.Name+".args_stackmap")
}
}
if curtext == nil {
etext = nil
continue
}
etext.Link = p
etext = p
}
if newprog == nil {
newprog = ctxt.NewProg
}
// Add reference to Go arguments for C or assembly functions without them.
for _, s := range text {
if !strings.HasPrefix(s.Name, "\"\".") {
continue
}
found := false
for p := s.Func.Text; p != nil; p = p.Link {
if p.As == AFUNCDATA && p.From.Type == TYPE_CONST && p.From.Offset == objabi.FUNCDATA_ArgsPointerMaps {
found = true
break
}
}
if !found {
p := Appendp(s.Func.Text, newprog)
p.As = AFUNCDATA
p.From.Type = TYPE_CONST
p.From.Offset = objabi.FUNCDATA_ArgsPointerMaps
p.To.Type = TYPE_MEM
p.To.Name = NAME_EXTERN
p.To.Sym = ctxt.LookupDerived(s, s.Name+".args_stackmap")
}
}
// Turn functions into machine code images.
for _, s := range text {
mkfwd(s)
linkpatch(ctxt, s, newprog)
ctxt.Arch.Preprocess(ctxt, s, newprog)
ctxt.Arch.Assemble(ctxt, s, newprog)
if ctxt.Errors > 0 {
continue
}
linkpcln(ctxt, s)
ctxt.populateDWARF(plist.Curfn, s, myimportpath)
}
}
func (ctxt *Link) InitTextSym(s *LSym, flag int) {
if s == nil {
// func _() { }
return
}
if s.Func != nil {
ctxt.Diag("InitTextSym double init for %s", s.Name)
}
s.Func = new(FuncInfo)
if s.OnList() {
ctxt.Diag("symbol %s listed multiple times", s.Name)
}
s.Set(AttrOnList, true)
s.Set(AttrDuplicateOK, flag&DUPOK != 0)
s.Set(AttrNoSplit, flag&NOSPLIT != 0)
s.Set(AttrReflectMethod, flag&REFLECTMETHOD != 0)
s.Set(AttrWrapper, flag&WRAPPER != 0)
s.Set(AttrNeedCtxt, flag&NEEDCTXT != 0)
s.Set(AttrNoFrame, flag&NOFRAME != 0)
s.Set(AttrTopFrame, flag&TOPFRAME != 0)
s.Type = objabi.STEXT
ctxt.Text = append(ctxt.Text, s)
// Set up DWARF entries for s.
info, loc, ranges, _, lines := ctxt.dwarfSym(s)
info.Type = objabi.SDWARFINFO
info.Set(AttrDuplicateOK, s.DuplicateOK())
if loc != nil {
loc.Type = objabi.SDWARFLOC
loc.Set(AttrDuplicateOK, s.DuplicateOK())
ctxt.Data = append(ctxt.Data, loc)
}
ranges.Type = objabi.SDWARFRANGE
ranges.Set(AttrDuplicateOK, s.DuplicateOK())
ctxt.Data = append(ctxt.Data, info, ranges)
lines.Type = objabi.SDWARFLINES
lines.Set(AttrDuplicateOK, s.DuplicateOK())
ctxt.Data = append(ctxt.Data, lines)
}
func (ctxt *Link) Globl(s *LSym, size int64, flag int) {
if s.SeenGlobl() {
fmt.Printf("duplicate %v\n", s)
}
s.Set(AttrSeenGlobl, true)
if s.OnList() {
ctxt.Diag("symbol %s listed multiple times", s.Name)
}
s.Set(AttrOnList, true)
ctxt.Data = append(ctxt.Data, s)
s.Size = size
if s.Type == 0 {
s.Type = objabi.SBSS
}
if flag&DUPOK != 0 {
s.Set(AttrDuplicateOK, true)
}
if flag&RODATA != 0 {
s.Type = objabi.SRODATA
} else if flag&NOPTR != 0 {
if s.Type == objabi.SDATA {
s.Type = objabi.SNOPTRDATA
} else {
s.Type = objabi.SNOPTRBSS
}
} else if flag&TLSBSS != 0 {
s.Type = objabi.STLSBSS
}
}
// EmitEntryLiveness generates PCDATA Progs after p to switch to the
// liveness map active at the entry of function s. It returns the last
// Prog generated.
func (ctxt *Link) EmitEntryLiveness(s *LSym, p *Prog, newprog ProgAlloc) *Prog {
pcdata := ctxt.EmitEntryStackMap(s, p, newprog)
pcdata = ctxt.EmitEntryRegMap(s, pcdata, newprog)
return pcdata
}
// Similar to EmitEntryLiveness, but just emit stack map.
func (ctxt *Link) EmitEntryStackMap(s *LSym, p *Prog, newprog ProgAlloc) *Prog {
pcdata := Appendp(p, newprog)
pcdata.Pos = s.Func.Text.Pos
pcdata.As = APCDATA
pcdata.From.Type = TYPE_CONST
pcdata.From.Offset = objabi.PCDATA_StackMapIndex
pcdata.To.Type = TYPE_CONST
pcdata.To.Offset = -1 // pcdata starts at -1 at function entry
return pcdata
}
// Similar to EmitEntryLiveness, but just emit register map.
func (ctxt *Link) EmitEntryRegMap(s *LSym, p *Prog, newprog ProgAlloc) *Prog {
pcdata := Appendp(p, newprog)
pcdata.Pos = s.Func.Text.Pos
pcdata.As = APCDATA
pcdata.From.Type = TYPE_CONST
pcdata.From.Offset = objabi.PCDATA_RegMapIndex
pcdata.To.Type = TYPE_CONST
pcdata.To.Offset = -1
return pcdata
}
// StartUnsafePoint generates PCDATA Progs after p to mark the
// beginning of an unsafe point. The unsafe point starts immediately
// after p.
// It returns the last Prog generated.
func (ctxt *Link) StartUnsafePoint(p *Prog, newprog ProgAlloc) *Prog {
pcdata := Appendp(p, newprog)
pcdata.As = APCDATA
pcdata.From.Type = TYPE_CONST
pcdata.From.Offset = objabi.PCDATA_RegMapIndex
pcdata.To.Type = TYPE_CONST
pcdata.To.Offset = -2 // pcdata -2 marks unsafe point
return pcdata
}
// EndUnsafePoint generates PCDATA Progs after p to mark the end of an
// unsafe point, restoring the stack map index to oldval.
// The unsafe point ends right after p.
// It returns the last Prog generated.
func (ctxt *Link) EndUnsafePoint(p *Prog, newprog ProgAlloc, oldval int64) *Prog {
pcdata := Appendp(p, newprog)
pcdata.As = APCDATA
pcdata.From.Type = TYPE_CONST
pcdata.From.Offset = objabi.PCDATA_RegMapIndex
pcdata.To.Type = TYPE_CONST
pcdata.To.Offset = oldval
// TODO: register map?
return pcdata
}
// MarkUnsafePoints inserts PCDATAs to mark nonpreemptible instruction
// sequences, based on isUnsafePoint predicate. p0 is the start of the
// instruction stream.
func MarkUnsafePoints(ctxt *Link, p0 *Prog, newprog ProgAlloc, isUnsafePoint func(*Prog) bool) {
prev := p0
oldval := int64(-1) // entry pcdata
for p := prev.Link; p != nil; p, prev = p.Link, p {
if p.As == APCDATA && p.From.Offset == objabi.PCDATA_RegMapIndex {
oldval = p.To.Offset
continue
}
if oldval == -2 {
continue // already unsafe
}
if isUnsafePoint(p) {
q := ctxt.StartUnsafePoint(prev, newprog)
q.Pc = p.Pc
q.Link = p
// Advance to the end of unsafe point.
for p.Link != nil && isUnsafePoint(p.Link) {
p = p.Link
}
if p.Link == nil {
break // Reached the end, don't bother marking the end
}
p = ctxt.EndUnsafePoint(p, newprog, oldval)
p.Pc = p.Link.Pc
}
}
}