mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
Generate inline code at defer time to save the args of defer calls to unique (autotmp) stack slots, and generate inline code at exit time to check which defer calls were made and make the associated function/method/interface calls. We remember that a particular defer statement was reached by storing in the deferBits variable (always stored on the stack). At exit time, we check the bits of the deferBits variable to determine which defer function calls to make (in reverse order). These low-cost defers are only used for functions where no defers appear in loops. In addition, we don't do these low-cost defers if there are too many defer statements or too many exits in a function (to limit code increase). When a function uses open-coded defers, we produce extra FUNCDATA_OpenCodedDeferInfo information that specifies the number of defers, and for each defer, the stack slots where the closure and associated args have been stored. The funcdata also includes the location of the deferBits variable. Therefore, for panics, we can use this funcdata to determine exactly which defers are active, and call the appropriate functions/methods/closures with the correct arguments for each active defer. In order to unwind the stack correctly after a recover(), we need to add an extra code segment to functions with open-coded defers that simply calls deferreturn() and returns. This segment is not reachable by the normal function, but is returned to by the runtime during recovery. We set the liveness information of this deferreturn() to be the same as the liveness at the first function call during the last defer exit code (so all return values and all stack slots needed by the defer calls will be live). I needed to increase the stackguard constant from 880 to 896, because of a small amount of new code in deferreturn(). The -N flag disables open-coded defers. '-d defer' prints out the kind of defer being used at each defer statement (heap-allocated, stack-allocated, or open-coded). Cost of defer statement [ go test -run NONE -bench BenchmarkDefer$ runtime ] With normal (stack-allocated) defers only: 35.4 ns/op With open-coded defers: 5.6 ns/op Cost of function call alone (remove defer keyword): 4.4 ns/op Text size increase (including funcdata) for go binary without/with open-coded defers: 0.09% The average size increase (including funcdata) for only the functions that use open-coded defers is 1.1%. The cost of a panic followed by a recover got noticeably slower, since panic processing now requires a scan of the stack for open-coded defer frames. This scan is required, even if no frames are using open-coded defers: Cost of panic and recover [ go test -run NONE -bench BenchmarkPanicRecover runtime ] Without open-coded defers: 62.0 ns/op With open-coded defers: 255 ns/op A CGO Go-to-C-to-Go benchmark got noticeably faster because of open-coded defers: CGO Go-to-C-to-Go benchmark [cd misc/cgo/test; go test -run NONE -bench BenchmarkCGoCallback ] Without open-coded defers: 443 ns/op With open-coded defers: 347 ns/op Updates #14939 (defer performance) Updates #34481 (design doc) Change-Id: I63b1a60d1ebf28126f55ee9fd7ecffe9cb23d1ff Reviewed-on: https://go-review.googlesource.com/c/go/+/202340 Reviewed-by: Austin Clements <austin@google.com>
713 lines
22 KiB
Go
713 lines
22 KiB
Go
// Derived from Inferno utils/6l/l.h and related files.
|
|
// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/l.h
|
|
//
|
|
// 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 obj
|
|
|
|
import (
|
|
"bufio"
|
|
"cmd/internal/dwarf"
|
|
"cmd/internal/objabi"
|
|
"cmd/internal/src"
|
|
"cmd/internal/sys"
|
|
"fmt"
|
|
"sync"
|
|
)
|
|
|
|
// An Addr is an argument to an instruction.
|
|
// The general forms and their encodings are:
|
|
//
|
|
// sym±offset(symkind)(reg)(index*scale)
|
|
// Memory reference at address &sym(symkind) + offset + reg + index*scale.
|
|
// Any of sym(symkind), ±offset, (reg), (index*scale), and *scale can be omitted.
|
|
// If (reg) and *scale are both omitted, the resulting expression (index) is parsed as (reg).
|
|
// To force a parsing as index*scale, write (index*1).
|
|
// Encoding:
|
|
// type = TYPE_MEM
|
|
// name = symkind (NAME_AUTO, ...) or 0 (NAME_NONE)
|
|
// sym = sym
|
|
// offset = ±offset
|
|
// reg = reg (REG_*)
|
|
// index = index (REG_*)
|
|
// scale = scale (1, 2, 4, 8)
|
|
//
|
|
// $<mem>
|
|
// Effective address of memory reference <mem>, defined above.
|
|
// Encoding: same as memory reference, but type = TYPE_ADDR.
|
|
//
|
|
// $<±integer value>
|
|
// This is a special case of $<mem>, in which only ±offset is present.
|
|
// It has a separate type for easy recognition.
|
|
// Encoding:
|
|
// type = TYPE_CONST
|
|
// offset = ±integer value
|
|
//
|
|
// *<mem>
|
|
// Indirect reference through memory reference <mem>, defined above.
|
|
// Only used on x86 for CALL/JMP *sym(SB), which calls/jumps to a function
|
|
// pointer stored in the data word sym(SB), not a function named sym(SB).
|
|
// Encoding: same as above, but type = TYPE_INDIR.
|
|
//
|
|
// $*$<mem>
|
|
// No longer used.
|
|
// On machines with actual SB registers, $*$<mem> forced the
|
|
// instruction encoding to use a full 32-bit constant, never a
|
|
// reference relative to SB.
|
|
//
|
|
// $<floating point literal>
|
|
// Floating point constant value.
|
|
// Encoding:
|
|
// type = TYPE_FCONST
|
|
// val = floating point value
|
|
//
|
|
// $<string literal, up to 8 chars>
|
|
// String literal value (raw bytes used for DATA instruction).
|
|
// Encoding:
|
|
// type = TYPE_SCONST
|
|
// val = string
|
|
//
|
|
// <register name>
|
|
// Any register: integer, floating point, control, segment, and so on.
|
|
// If looking for specific register kind, must check type and reg value range.
|
|
// Encoding:
|
|
// type = TYPE_REG
|
|
// reg = reg (REG_*)
|
|
//
|
|
// x(PC)
|
|
// Encoding:
|
|
// type = TYPE_BRANCH
|
|
// val = Prog* reference OR ELSE offset = target pc (branch takes priority)
|
|
//
|
|
// $±x-±y
|
|
// Final argument to TEXT, specifying local frame size x and argument size y.
|
|
// In this form, x and y are integer literals only, not arbitrary expressions.
|
|
// This avoids parsing ambiguities due to the use of - as a separator.
|
|
// The ± are optional.
|
|
// If the final argument to TEXT omits the -±y, the encoding should still
|
|
// use TYPE_TEXTSIZE (not TYPE_CONST), with u.argsize = ArgsSizeUnknown.
|
|
// Encoding:
|
|
// type = TYPE_TEXTSIZE
|
|
// offset = x
|
|
// val = int32(y)
|
|
//
|
|
// reg<<shift, reg>>shift, reg->shift, reg@>shift
|
|
// Shifted register value, for ARM and ARM64.
|
|
// In this form, reg must be a register and shift can be a register or an integer constant.
|
|
// Encoding:
|
|
// type = TYPE_SHIFT
|
|
// On ARM:
|
|
// offset = (reg&15) | shifttype<<5 | count
|
|
// shifttype = 0, 1, 2, 3 for <<, >>, ->, @>
|
|
// count = (reg&15)<<8 | 1<<4 for a register shift count, (n&31)<<7 for an integer constant.
|
|
// On ARM64:
|
|
// offset = (reg&31)<<16 | shifttype<<22 | (count&63)<<10
|
|
// shifttype = 0, 1, 2 for <<, >>, ->
|
|
//
|
|
// (reg, reg)
|
|
// A destination register pair. When used as the last argument of an instruction,
|
|
// this form makes clear that both registers are destinations.
|
|
// Encoding:
|
|
// type = TYPE_REGREG
|
|
// reg = first register
|
|
// offset = second register
|
|
//
|
|
// [reg, reg, reg-reg]
|
|
// Register list for ARM, ARM64, 386/AMD64.
|
|
// Encoding:
|
|
// type = TYPE_REGLIST
|
|
// On ARM:
|
|
// offset = bit mask of registers in list; R0 is low bit.
|
|
// On ARM64:
|
|
// offset = register count (Q:size) | arrangement (opcode) | first register
|
|
// On 386/AMD64:
|
|
// reg = range low register
|
|
// offset = 2 packed registers + kind tag (see x86.EncodeRegisterRange)
|
|
//
|
|
// reg, reg
|
|
// Register pair for ARM.
|
|
// TYPE_REGREG2
|
|
//
|
|
// (reg+reg)
|
|
// Register pair for PPC64.
|
|
// Encoding:
|
|
// type = TYPE_MEM
|
|
// reg = first register
|
|
// index = second register
|
|
// scale = 1
|
|
//
|
|
// reg.[US]XT[BHWX]
|
|
// Register extension for ARM64
|
|
// Encoding:
|
|
// type = TYPE_REG
|
|
// reg = REG_[US]XT[BHWX] + register + shift amount
|
|
// offset = ((reg&31) << 16) | (exttype << 13) | (amount<<10)
|
|
//
|
|
// reg.<T>
|
|
// Register arrangement for ARM64 SIMD register
|
|
// e.g.: V1.S4, V2.S2, V7.D2, V2.H4, V6.B16
|
|
// Encoding:
|
|
// type = TYPE_REG
|
|
// reg = REG_ARNG + register + arrangement
|
|
//
|
|
// reg.<T>[index]
|
|
// Register element for ARM64
|
|
// Encoding:
|
|
// type = TYPE_REG
|
|
// reg = REG_ELEM + register + arrangement
|
|
// index = element index
|
|
|
|
type Addr struct {
|
|
Reg int16
|
|
Index int16
|
|
Scale int16 // Sometimes holds a register.
|
|
Type AddrType
|
|
Name AddrName
|
|
Class int8
|
|
Offset int64
|
|
Sym *LSym
|
|
|
|
// argument value:
|
|
// for TYPE_SCONST, a string
|
|
// for TYPE_FCONST, a float64
|
|
// for TYPE_BRANCH, a *Prog (optional)
|
|
// for TYPE_TEXTSIZE, an int32 (optional)
|
|
Val interface{}
|
|
}
|
|
|
|
type AddrName int8
|
|
|
|
const (
|
|
NAME_NONE AddrName = iota
|
|
NAME_EXTERN
|
|
NAME_STATIC
|
|
NAME_AUTO
|
|
NAME_PARAM
|
|
// A reference to name@GOT(SB) is a reference to the entry in the global offset
|
|
// table for 'name'.
|
|
NAME_GOTREF
|
|
// Indicates that this is a reference to a TOC anchor.
|
|
NAME_TOCREF
|
|
)
|
|
|
|
//go:generate stringer -type AddrType
|
|
|
|
type AddrType uint8
|
|
|
|
const (
|
|
TYPE_NONE AddrType = iota
|
|
TYPE_BRANCH
|
|
TYPE_TEXTSIZE
|
|
TYPE_MEM
|
|
TYPE_CONST
|
|
TYPE_FCONST
|
|
TYPE_SCONST
|
|
TYPE_REG
|
|
TYPE_ADDR
|
|
TYPE_SHIFT
|
|
TYPE_REGREG
|
|
TYPE_REGREG2
|
|
TYPE_INDIR
|
|
TYPE_REGLIST
|
|
)
|
|
|
|
// Prog describes a single machine instruction.
|
|
//
|
|
// The general instruction form is:
|
|
//
|
|
// (1) As.Scond From [, ...RestArgs], To
|
|
// (2) As.Scond From, Reg [, ...RestArgs], To, RegTo2
|
|
//
|
|
// where As is an opcode and the others are arguments:
|
|
// From, Reg are sources, and To, RegTo2 are destinations.
|
|
// RestArgs can hold additional sources and destinations.
|
|
// Usually, not all arguments are present.
|
|
// For example, MOVL R1, R2 encodes using only As=MOVL, From=R1, To=R2.
|
|
// The Scond field holds additional condition bits for systems (like arm)
|
|
// that have generalized conditional execution.
|
|
// (2) form is present for compatibility with older code,
|
|
// to avoid too much changes in a single swing.
|
|
// (1) scheme is enough to express any kind of operand combination.
|
|
//
|
|
// Jump instructions use the Pcond field to point to the target instruction,
|
|
// which must be in the same linked list as the jump instruction.
|
|
//
|
|
// The Progs for a given function are arranged in a list linked through the Link field.
|
|
//
|
|
// Each Prog is charged to a specific source line in the debug information,
|
|
// specified by Pos.Line().
|
|
// Every Prog has a Ctxt field that defines its context.
|
|
// For performance reasons, Progs usually are usually bulk allocated, cached, and reused;
|
|
// those bulk allocators should always be used, rather than new(Prog).
|
|
//
|
|
// The other fields not yet mentioned are for use by the back ends and should
|
|
// be left zeroed by creators of Prog lists.
|
|
type Prog struct {
|
|
Ctxt *Link // linker context
|
|
Link *Prog // next Prog in linked list
|
|
From Addr // first source operand
|
|
RestArgs []Addr // can pack any operands that not fit into {Prog.From, Prog.To}
|
|
To Addr // destination operand (second is RegTo2 below)
|
|
Pcond *Prog // target of conditional jump
|
|
Forwd *Prog // for x86 back end
|
|
Rel *Prog // for x86, arm back ends
|
|
Pc int64 // for back ends or assembler: virtual or actual program counter, depending on phase
|
|
Pos src.XPos // source position of this instruction
|
|
Spadj int32 // effect of instruction on stack pointer (increment or decrement amount)
|
|
As As // assembler opcode
|
|
Reg int16 // 2nd source operand
|
|
RegTo2 int16 // 2nd destination operand
|
|
Mark uint16 // bitmask of arch-specific items
|
|
Optab uint16 // arch-specific opcode index
|
|
Scond uint8 // bits that describe instruction suffixes (e.g. ARM conditions)
|
|
Back uint8 // for x86 back end: backwards branch state
|
|
Ft uint8 // for x86 back end: type index of Prog.From
|
|
Tt uint8 // for x86 back end: type index of Prog.To
|
|
Isize uint8 // for x86 back end: size of the instruction in bytes
|
|
}
|
|
|
|
// From3Type returns p.GetFrom3().Type, or TYPE_NONE when
|
|
// p.GetFrom3() returns nil.
|
|
//
|
|
// Deprecated: for the same reasons as Prog.GetFrom3.
|
|
func (p *Prog) From3Type() AddrType {
|
|
if p.RestArgs == nil {
|
|
return TYPE_NONE
|
|
}
|
|
return p.RestArgs[0].Type
|
|
}
|
|
|
|
// GetFrom3 returns second source operand (the first is Prog.From).
|
|
// In combination with Prog.From and Prog.To it makes common 3 operand
|
|
// case easier to use.
|
|
//
|
|
// Should be used only when RestArgs is set with SetFrom3.
|
|
//
|
|
// Deprecated: better use RestArgs directly or define backend-specific getters.
|
|
// Introduced to simplify transition to []Addr.
|
|
// Usage of this is discouraged due to fragility and lack of guarantees.
|
|
func (p *Prog) GetFrom3() *Addr {
|
|
if p.RestArgs == nil {
|
|
return nil
|
|
}
|
|
return &p.RestArgs[0]
|
|
}
|
|
|
|
// SetFrom3 assigns []Addr{a} to p.RestArgs.
|
|
// In pair with Prog.GetFrom3 it can help in emulation of Prog.From3.
|
|
//
|
|
// Deprecated: for the same reasons as Prog.GetFrom3.
|
|
func (p *Prog) SetFrom3(a Addr) {
|
|
p.RestArgs = []Addr{a}
|
|
}
|
|
|
|
// An As denotes an assembler opcode.
|
|
// There are some portable opcodes, declared here in package obj,
|
|
// that are common to all architectures.
|
|
// However, the majority of opcodes are arch-specific
|
|
// and are declared in their respective architecture's subpackage.
|
|
type As int16
|
|
|
|
// These are the portable opcodes.
|
|
const (
|
|
AXXX As = iota
|
|
ACALL
|
|
ADUFFCOPY
|
|
ADUFFZERO
|
|
AEND
|
|
AFUNCDATA
|
|
AJMP
|
|
ANOP
|
|
APCALIGN
|
|
APCDATA
|
|
ARET
|
|
AGETCALLERPC
|
|
ATEXT
|
|
AUNDEF
|
|
A_ARCHSPECIFIC
|
|
)
|
|
|
|
// Each architecture is allotted a distinct subspace of opcode values
|
|
// for declaring its arch-specific opcodes.
|
|
// Within this subspace, the first arch-specific opcode should be
|
|
// at offset A_ARCHSPECIFIC.
|
|
//
|
|
// Subspaces are aligned to a power of two so opcodes can be masked
|
|
// with AMask and used as compact array indices.
|
|
const (
|
|
ABase386 = (1 + iota) << 11
|
|
ABaseARM
|
|
ABaseAMD64
|
|
ABasePPC64
|
|
ABaseARM64
|
|
ABaseMIPS
|
|
ABaseRISCV
|
|
ABaseS390X
|
|
ABaseWasm
|
|
|
|
AllowedOpCodes = 1 << 11 // The number of opcodes available for any given architecture.
|
|
AMask = AllowedOpCodes - 1 // AND with this to use the opcode as an array index.
|
|
)
|
|
|
|
// An LSym is the sort of symbol that is written to an object file.
|
|
// It represents Go symbols in a flat pkg+"."+name namespace.
|
|
type LSym struct {
|
|
Name string
|
|
Type objabi.SymKind
|
|
Attribute
|
|
|
|
RefIdx int // Index of this symbol in the symbol reference list.
|
|
Size int64
|
|
Gotype *LSym
|
|
P []byte
|
|
R []Reloc
|
|
|
|
Func *FuncInfo
|
|
}
|
|
|
|
// A FuncInfo contains extra fields for STEXT symbols.
|
|
type FuncInfo struct {
|
|
Args int32
|
|
Locals int32
|
|
Text *Prog
|
|
Autot map[*LSym]struct{}
|
|
Pcln Pcln
|
|
InlMarks []InlMark
|
|
|
|
dwarfInfoSym *LSym
|
|
dwarfLocSym *LSym
|
|
dwarfRangesSym *LSym
|
|
dwarfAbsFnSym *LSym
|
|
dwarfDebugLinesSym *LSym
|
|
|
|
GCArgs *LSym
|
|
GCLocals *LSym
|
|
GCRegs *LSym
|
|
StackObjects *LSym
|
|
OpenCodedDeferInfo *LSym
|
|
}
|
|
|
|
type InlMark struct {
|
|
// When unwinding from an instruction in an inlined body, mark
|
|
// where we should unwind to.
|
|
// id records the global inlining id of the inlined body.
|
|
// p records the location of an instruction in the parent (inliner) frame.
|
|
p *Prog
|
|
id int32
|
|
}
|
|
|
|
// Mark p as the instruction to set as the pc when
|
|
// "unwinding" the inlining global frame id. Usually it should be
|
|
// instruction with a file:line at the callsite, and occur
|
|
// just before the body of the inlined function.
|
|
func (fi *FuncInfo) AddInlMark(p *Prog, id int32) {
|
|
fi.InlMarks = append(fi.InlMarks, InlMark{p: p, id: id})
|
|
}
|
|
|
|
// Record the type symbol for an auto variable so that the linker
|
|
// an emit DWARF type information for the type.
|
|
func (fi *FuncInfo) RecordAutoType(gotype *LSym) {
|
|
if fi.Autot == nil {
|
|
fi.Autot = make(map[*LSym]struct{})
|
|
}
|
|
fi.Autot[gotype] = struct{}{}
|
|
}
|
|
|
|
//go:generate stringer -type ABI
|
|
|
|
// ABI is the calling convention of a text symbol.
|
|
type ABI uint8
|
|
|
|
const (
|
|
// ABI0 is the stable stack-based ABI. It's important that the
|
|
// value of this is "0": we can't distinguish between
|
|
// references to data and ABI0 text symbols in assembly code,
|
|
// and hence this doesn't distinguish between symbols without
|
|
// an ABI and text symbols with ABI0.
|
|
ABI0 ABI = iota
|
|
|
|
// ABIInternal is the internal ABI that may change between Go
|
|
// versions. All Go functions use the internal ABI and the
|
|
// compiler generates wrappers for calls to and from other
|
|
// ABIs.
|
|
ABIInternal
|
|
|
|
ABICount
|
|
)
|
|
|
|
// Attribute is a set of symbol attributes.
|
|
type Attribute uint16
|
|
|
|
const (
|
|
AttrDuplicateOK Attribute = 1 << iota
|
|
AttrCFunc
|
|
AttrNoSplit
|
|
AttrLeaf
|
|
AttrWrapper
|
|
AttrNeedCtxt
|
|
AttrNoFrame
|
|
AttrSeenGlobl
|
|
AttrOnList
|
|
AttrStatic
|
|
|
|
// MakeTypelink means that the type should have an entry in the typelink table.
|
|
AttrMakeTypelink
|
|
|
|
// ReflectMethod means the function may call reflect.Type.Method or
|
|
// reflect.Type.MethodByName. Matching is imprecise (as reflect.Type
|
|
// can be used through a custom interface), so ReflectMethod may be
|
|
// set in some cases when the reflect package is not called.
|
|
//
|
|
// Used by the linker to determine what methods can be pruned.
|
|
AttrReflectMethod
|
|
|
|
// Local means make the symbol local even when compiling Go code to reference Go
|
|
// symbols in other shared libraries, as in this mode symbols are global by
|
|
// default. "local" here means in the sense of the dynamic linker, i.e. not
|
|
// visible outside of the module (shared library or executable) that contains its
|
|
// definition. (When not compiling to support Go shared libraries, all symbols are
|
|
// local in this sense unless there is a cgo_export_* directive).
|
|
AttrLocal
|
|
|
|
// For function symbols; indicates that the specified function was the
|
|
// target of an inline during compilation
|
|
AttrWasInlined
|
|
|
|
// TopFrame means that this function is an entry point and unwinders should not
|
|
// keep unwinding beyond this frame.
|
|
AttrTopFrame
|
|
|
|
// attrABIBase is the value at which the ABI is encoded in
|
|
// Attribute. This must be last; all bits after this are
|
|
// assumed to be an ABI value.
|
|
//
|
|
// MUST BE LAST since all bits above this comprise the ABI.
|
|
attrABIBase
|
|
)
|
|
|
|
func (a Attribute) DuplicateOK() bool { return a&AttrDuplicateOK != 0 }
|
|
func (a Attribute) MakeTypelink() bool { return a&AttrMakeTypelink != 0 }
|
|
func (a Attribute) CFunc() bool { return a&AttrCFunc != 0 }
|
|
func (a Attribute) NoSplit() bool { return a&AttrNoSplit != 0 }
|
|
func (a Attribute) Leaf() bool { return a&AttrLeaf != 0 }
|
|
func (a Attribute) SeenGlobl() bool { return a&AttrSeenGlobl != 0 }
|
|
func (a Attribute) OnList() bool { return a&AttrOnList != 0 }
|
|
func (a Attribute) ReflectMethod() bool { return a&AttrReflectMethod != 0 }
|
|
func (a Attribute) Local() bool { return a&AttrLocal != 0 }
|
|
func (a Attribute) Wrapper() bool { return a&AttrWrapper != 0 }
|
|
func (a Attribute) NeedCtxt() bool { return a&AttrNeedCtxt != 0 }
|
|
func (a Attribute) NoFrame() bool { return a&AttrNoFrame != 0 }
|
|
func (a Attribute) Static() bool { return a&AttrStatic != 0 }
|
|
func (a Attribute) WasInlined() bool { return a&AttrWasInlined != 0 }
|
|
func (a Attribute) TopFrame() bool { return a&AttrTopFrame != 0 }
|
|
|
|
func (a *Attribute) Set(flag Attribute, value bool) {
|
|
if value {
|
|
*a |= flag
|
|
} else {
|
|
*a &^= flag
|
|
}
|
|
}
|
|
|
|
func (a Attribute) ABI() ABI { return ABI(a / attrABIBase) }
|
|
func (a *Attribute) SetABI(abi ABI) {
|
|
const mask = 1 // Only one ABI bit for now.
|
|
*a = (*a &^ (mask * attrABIBase)) | Attribute(abi)*attrABIBase
|
|
}
|
|
|
|
var textAttrStrings = [...]struct {
|
|
bit Attribute
|
|
s string
|
|
}{
|
|
{bit: AttrDuplicateOK, s: "DUPOK"},
|
|
{bit: AttrMakeTypelink, s: ""},
|
|
{bit: AttrCFunc, s: "CFUNC"},
|
|
{bit: AttrNoSplit, s: "NOSPLIT"},
|
|
{bit: AttrLeaf, s: "LEAF"},
|
|
{bit: AttrSeenGlobl, s: ""},
|
|
{bit: AttrOnList, s: ""},
|
|
{bit: AttrReflectMethod, s: "REFLECTMETHOD"},
|
|
{bit: AttrLocal, s: "LOCAL"},
|
|
{bit: AttrWrapper, s: "WRAPPER"},
|
|
{bit: AttrNeedCtxt, s: "NEEDCTXT"},
|
|
{bit: AttrNoFrame, s: "NOFRAME"},
|
|
{bit: AttrStatic, s: "STATIC"},
|
|
{bit: AttrWasInlined, s: ""},
|
|
{bit: AttrTopFrame, s: "TOPFRAME"},
|
|
}
|
|
|
|
// TextAttrString formats a for printing in as part of a TEXT prog.
|
|
func (a Attribute) TextAttrString() string {
|
|
var s string
|
|
for _, x := range textAttrStrings {
|
|
if a&x.bit != 0 {
|
|
if x.s != "" {
|
|
s += x.s + "|"
|
|
}
|
|
a &^= x.bit
|
|
}
|
|
}
|
|
switch a.ABI() {
|
|
case ABI0:
|
|
case ABIInternal:
|
|
s += "ABIInternal|"
|
|
a.SetABI(0) // Clear ABI so we don't print below.
|
|
}
|
|
if a != 0 {
|
|
s += fmt.Sprintf("UnknownAttribute(%d)|", a)
|
|
}
|
|
// Chop off trailing |, if present.
|
|
if len(s) > 0 {
|
|
s = s[:len(s)-1]
|
|
}
|
|
return s
|
|
}
|
|
|
|
// The compiler needs LSym to satisfy fmt.Stringer, because it stores
|
|
// an LSym in ssa.ExternSymbol.
|
|
func (s *LSym) String() string {
|
|
return s.Name
|
|
}
|
|
|
|
type Pcln struct {
|
|
Pcsp Pcdata
|
|
Pcfile Pcdata
|
|
Pcline Pcdata
|
|
Pcinline Pcdata
|
|
Pcdata []Pcdata
|
|
Funcdata []*LSym
|
|
Funcdataoff []int64
|
|
File []string
|
|
Lastfile string
|
|
Lastindex int
|
|
InlTree InlTree // per-function inlining tree extracted from the global tree
|
|
}
|
|
|
|
type Reloc struct {
|
|
Off int32
|
|
Siz uint8
|
|
Type objabi.RelocType
|
|
Add int64
|
|
Sym *LSym
|
|
}
|
|
|
|
type Auto struct {
|
|
Asym *LSym
|
|
Aoffset int32
|
|
Name AddrName
|
|
Gotype *LSym
|
|
}
|
|
|
|
type Pcdata struct {
|
|
P []byte
|
|
}
|
|
|
|
// Link holds the context for writing object code from a compiler
|
|
// to be linker input or for reading that input into the linker.
|
|
type Link struct {
|
|
Headtype objabi.HeadType
|
|
Arch *LinkArch
|
|
Debugasm int
|
|
Debugvlog bool
|
|
Debugpcln string
|
|
Flag_shared bool
|
|
Flag_dynlink bool
|
|
Flag_optimize bool
|
|
Flag_locationlists bool
|
|
Bso *bufio.Writer
|
|
Pathname string
|
|
hashmu sync.Mutex // protects hash, funchash
|
|
hash map[string]*LSym // name -> sym mapping
|
|
funchash map[string]*LSym // name -> sym mapping for ABIInternal syms
|
|
statichash map[string]*LSym // name -> sym mapping for static syms
|
|
PosTable src.PosTable
|
|
InlTree InlTree // global inlining tree used by gc/inl.go
|
|
DwFixups *DwarfFixupTable
|
|
Imports []string
|
|
DiagFunc func(string, ...interface{})
|
|
DiagFlush func()
|
|
DebugInfo func(fn *LSym, info *LSym, curfn interface{}) ([]dwarf.Scope, dwarf.InlCalls) // if non-nil, curfn is a *gc.Node
|
|
GenAbstractFunc func(fn *LSym)
|
|
Errors int
|
|
|
|
InParallel bool // parallel backend phase in effect
|
|
Framepointer_enabled bool
|
|
UseBASEntries bool // Use Base Address Selection Entries in location lists and PC ranges
|
|
|
|
// state for writing objects
|
|
Text []*LSym
|
|
Data []*LSym
|
|
|
|
// ABIAliases are text symbols that should be aliased to all
|
|
// ABIs. These symbols may only be referenced and not defined
|
|
// by this object, since the need for an alias may appear in a
|
|
// different object than the definition. Hence, this
|
|
// information can't be carried in the symbol definition.
|
|
//
|
|
// TODO(austin): Replace this with ABI wrappers once the ABIs
|
|
// actually diverge.
|
|
ABIAliases []*LSym
|
|
}
|
|
|
|
func (ctxt *Link) Diag(format string, args ...interface{}) {
|
|
ctxt.Errors++
|
|
ctxt.DiagFunc(format, args...)
|
|
}
|
|
|
|
func (ctxt *Link) Logf(format string, args ...interface{}) {
|
|
fmt.Fprintf(ctxt.Bso, format, args...)
|
|
ctxt.Bso.Flush()
|
|
}
|
|
|
|
// The smallest possible offset from the hardware stack pointer to a local
|
|
// variable on the stack. Architectures that use a link register save its value
|
|
// on the stack in the function prologue and so always have a pointer between
|
|
// the hardware stack pointer and the local variable area.
|
|
func (ctxt *Link) FixedFrameSize() int64 {
|
|
switch ctxt.Arch.Family {
|
|
case sys.AMD64, sys.I386, sys.Wasm:
|
|
return 0
|
|
case sys.PPC64:
|
|
// PIC code on ppc64le requires 32 bytes of stack, and it's easier to
|
|
// just use that much stack always on ppc64x.
|
|
return int64(4 * ctxt.Arch.PtrSize)
|
|
default:
|
|
return int64(ctxt.Arch.PtrSize)
|
|
}
|
|
}
|
|
|
|
// LinkArch is the definition of a single architecture.
|
|
type LinkArch struct {
|
|
*sys.Arch
|
|
Init func(*Link)
|
|
Preprocess func(*Link, *LSym, ProgAlloc)
|
|
Assemble func(*Link, *LSym, ProgAlloc)
|
|
Progedit func(*Link, *Prog, ProgAlloc)
|
|
UnaryDst map[As]bool // Instruction takes one operand, a destination.
|
|
DWARFRegisters map[int16]int16
|
|
}
|