975 lines
		
	
	
		
			28 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			975 lines
		
	
	
		
			28 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"
 | |
| 	"fmt"
 | |
| 
 | |
| 	"github.com/google/gops/internal/sys"
 | |
| )
 | |
| 
 | |
| // 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.
 | |
| //		Encoding:
 | |
| //			type = TYPE_REGLIST
 | |
| //			offset = bit mask of registers in list; R0 is low bit.
 | |
| //
 | |
| //	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
 | |
| //
 | |
| type Addr struct {
 | |
| 	Reg    int16
 | |
| 	Index  int16
 | |
| 	Scale  int16 // Sometimes holds a register.
 | |
| 	Type   AddrType
 | |
| 	Name   int8
 | |
| 	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{}
 | |
| 
 | |
| 	Node interface{} // for use by compiler
 | |
| }
 | |
| 
 | |
| type AddrType uint8
 | |
| 
 | |
| const (
 | |
| 	NAME_NONE = 0 + 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
 | |
| )
 | |
| 
 | |
| const (
 | |
| 	TYPE_NONE AddrType = 0
 | |
| 
 | |
| 	TYPE_BRANCH AddrType = 5 + iota
 | |
| 	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:
 | |
| //
 | |
| //	As.Scond From, Reg, From3, To, RegTo2
 | |
| //
 | |
| // where As is an opcode and the others are arguments:
 | |
| // From, Reg, From3 are sources, and To, RegTo2 are 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.
 | |
| //
 | |
| // 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 Lineno, an index into the line history (see LineHist).
 | |
| // Every Prog has a Ctxt field that defines various context, including the current LineHist.
 | |
| // Progs should be allocated using ctxt.NewProg(), not 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
 | |
| 	From3  *Addr       // third source operand (second is Reg below)
 | |
| 	To     Addr        // destination operand (second is RegTo2 below)
 | |
| 	Pcond  *Prog       // target of conditional jump
 | |
| 	Opt    interface{} // available to optimization passes to hold per-Prog state
 | |
| 	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
 | |
| 	Lineno int32       // line number 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       // condition bits for conditional instruction (e.g., on ARM)
 | |
| 	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
 | |
| 	Mode   int8        // for x86 back end: 32- or 64-bit mode
 | |
| }
 | |
| 
 | |
| // From3Type returns From3.Type, or TYPE_NONE when From3 is nil.
 | |
| func (p *Prog) From3Type() AddrType {
 | |
| 	if p.From3 == nil {
 | |
| 		return TYPE_NONE
 | |
| 	}
 | |
| 	return p.From3.Type
 | |
| }
 | |
| 
 | |
| // From3Offset returns From3.Offset, or 0 when From3 is nil.
 | |
| func (p *Prog) From3Offset() int64 {
 | |
| 	if p.From3 == nil {
 | |
| 		return 0
 | |
| 	}
 | |
| 	return p.From3.Offset
 | |
| }
 | |
| 
 | |
| // 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
 | |
| 	APCDATA
 | |
| 	ARET
 | |
| 	ATEXT
 | |
| 	ATYPE
 | |
| 	AUNDEF
 | |
| 	AUSEFIELD
 | |
| 	AVARDEF
 | |
| 	AVARKILL
 | |
| 	AVARLIVE
 | |
| 	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) << 10
 | |
| 	ABaseARM
 | |
| 	ABaseAMD64
 | |
| 	ABasePPC64
 | |
| 	ABaseARM64
 | |
| 	ABaseMIPS64
 | |
| 	ABaseS390X
 | |
| 
 | |
| 	AllowedOpCodes = 1 << 10            // 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.
 | |
| type LSym struct {
 | |
| 	Name    string
 | |
| 	Type    SymKind
 | |
| 	Version int16
 | |
| 	Attribute
 | |
| 
 | |
| 	RefIdx int // Index of this symbol in the symbol reference list.
 | |
| 	Args   int32
 | |
| 	Locals int32
 | |
| 	Size   int64
 | |
| 	Gotype *LSym
 | |
| 	Autom  *Auto
 | |
| 	Text   *Prog
 | |
| 	Pcln   *Pcln
 | |
| 	P      []byte
 | |
| 	R      []Reloc
 | |
| }
 | |
| 
 | |
| // Attribute is a set of symbol attributes.
 | |
| type Attribute int16
 | |
| 
 | |
| const (
 | |
| 	AttrDuplicateOK Attribute = 1 << iota
 | |
| 	AttrCFunc
 | |
| 	AttrNoSplit
 | |
| 	AttrLeaf
 | |
| 	AttrSeenGlobl
 | |
| 	AttrOnList
 | |
| 
 | |
| 	// 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
 | |
| )
 | |
| 
 | |
| 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) Set(flag Attribute, value bool) {
 | |
| 	if value {
 | |
| 		*a |= flag
 | |
| 	} else {
 | |
| 		*a &^= flag
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // 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
 | |
| 	Pcdata      []Pcdata
 | |
| 	Funcdata    []*LSym
 | |
| 	Funcdataoff []int64
 | |
| 	File        []*LSym
 | |
| 	Lastfile    *LSym
 | |
| 	Lastindex   int
 | |
| }
 | |
| 
 | |
| // A SymKind describes the kind of memory represented by a symbol.
 | |
| type SymKind int16
 | |
| 
 | |
| // Defined SymKind values.
 | |
| //
 | |
| // TODO(rsc): Give idiomatic Go names.
 | |
| // TODO(rsc): Reduce the number of symbol types in the object files.
 | |
| //go:generate stringer -type=SymKind
 | |
| const (
 | |
| 	Sxxx SymKind = iota
 | |
| 	STEXT
 | |
| 	SELFRXSECT
 | |
| 
 | |
| 	// Read-only sections.
 | |
| 	STYPE
 | |
| 	SSTRING
 | |
| 	SGOSTRING
 | |
| 	SGOFUNC
 | |
| 	SGCBITS
 | |
| 	SRODATA
 | |
| 	SFUNCTAB
 | |
| 
 | |
| 	SELFROSECT
 | |
| 	SMACHOPLT
 | |
| 
 | |
| 	// Read-only sections with relocations.
 | |
| 	//
 | |
| 	// Types STYPE-SFUNCTAB above are written to the .rodata section by default.
 | |
| 	// When linking a shared object, some conceptually "read only" types need to
 | |
| 	// be written to by relocations and putting them in a section called
 | |
| 	// ".rodata" interacts poorly with the system linkers. The GNU linkers
 | |
| 	// support this situation by arranging for sections of the name
 | |
| 	// ".data.rel.ro.XXX" to be mprotected read only by the dynamic linker after
 | |
| 	// relocations have applied, so when the Go linker is creating a shared
 | |
| 	// object it checks all objects of the above types and bumps any object that
 | |
| 	// has a relocation to it to the corresponding type below, which are then
 | |
| 	// written to sections with appropriate magic names.
 | |
| 	STYPERELRO
 | |
| 	SSTRINGRELRO
 | |
| 	SGOSTRINGRELRO
 | |
| 	SGOFUNCRELRO
 | |
| 	SGCBITSRELRO
 | |
| 	SRODATARELRO
 | |
| 	SFUNCTABRELRO
 | |
| 
 | |
| 	// Part of .data.rel.ro if it exists, otherwise part of .rodata.
 | |
| 	STYPELINK
 | |
| 	SITABLINK
 | |
| 	SSYMTAB
 | |
| 	SPCLNTAB
 | |
| 
 | |
| 	// Writable sections.
 | |
| 	SELFSECT
 | |
| 	SMACHO
 | |
| 	SMACHOGOT
 | |
| 	SWINDOWS
 | |
| 	SELFGOT
 | |
| 	SNOPTRDATA
 | |
| 	SINITARR
 | |
| 	SDATA
 | |
| 	SBSS
 | |
| 	SNOPTRBSS
 | |
| 	STLSBSS
 | |
| 	SXREF
 | |
| 	SMACHOSYMSTR
 | |
| 	SMACHOSYMTAB
 | |
| 	SMACHOINDIRECTPLT
 | |
| 	SMACHOINDIRECTGOT
 | |
| 	SFILE
 | |
| 	SFILEPATH
 | |
| 	SCONST
 | |
| 	SDYNIMPORT
 | |
| 	SHOSTOBJ
 | |
| 	SDWARFSECT
 | |
| 	SDWARFINFO
 | |
| 	SSUB       = SymKind(1 << 8)
 | |
| 	SMASK      = SymKind(SSUB - 1)
 | |
| 	SHIDDEN    = SymKind(1 << 9)
 | |
| 	SCONTAINER = SymKind(1 << 10) // has a sub-symbol
 | |
| )
 | |
| 
 | |
| // ReadOnly are the symbol kinds that form read-only sections. In some
 | |
| // cases, if they will require relocations, they are transformed into
 | |
| // rel-ro sections using RelROMap.
 | |
| var ReadOnly = []SymKind{
 | |
| 	STYPE,
 | |
| 	SSTRING,
 | |
| 	SGOSTRING,
 | |
| 	SGOFUNC,
 | |
| 	SGCBITS,
 | |
| 	SRODATA,
 | |
| 	SFUNCTAB,
 | |
| }
 | |
| 
 | |
| // RelROMap describes the transformation of read-only symbols to rel-ro
 | |
| // symbols.
 | |
| var RelROMap = map[SymKind]SymKind{
 | |
| 	STYPE:     STYPERELRO,
 | |
| 	SSTRING:   SSTRINGRELRO,
 | |
| 	SGOSTRING: SGOSTRINGRELRO,
 | |
| 	SGOFUNC:   SGOFUNCRELRO,
 | |
| 	SGCBITS:   SGCBITSRELRO,
 | |
| 	SRODATA:   SRODATARELRO,
 | |
| 	SFUNCTAB:  SFUNCTABRELRO,
 | |
| }
 | |
| 
 | |
| type Reloc struct {
 | |
| 	Off  int32
 | |
| 	Siz  uint8
 | |
| 	Type RelocType
 | |
| 	Add  int64
 | |
| 	Sym  *LSym
 | |
| }
 | |
| 
 | |
| type RelocType int32
 | |
| 
 | |
| //go:generate stringer -type=RelocType
 | |
| const (
 | |
| 	R_ADDR RelocType = 1 + iota
 | |
| 	// R_ADDRPOWER relocates a pair of "D-form" instructions (instructions with 16-bit
 | |
| 	// immediates in the low half of the instruction word), usually addis followed by
 | |
| 	// another add or a load, inserting the "high adjusted" 16 bits of the address of
 | |
| 	// the referenced symbol into the immediate field of the first instruction and the
 | |
| 	// low 16 bits into that of the second instruction.
 | |
| 	R_ADDRPOWER
 | |
| 	// R_ADDRARM64 relocates an adrp, add pair to compute the address of the
 | |
| 	// referenced symbol.
 | |
| 	R_ADDRARM64
 | |
| 	// R_ADDRMIPS (only used on mips64) resolves to the low 16 bits of an external
 | |
| 	// address, by encoding it into the instruction.
 | |
| 	R_ADDRMIPS
 | |
| 	// R_ADDROFF resolves to a 32-bit offset from the beginning of the section
 | |
| 	// holding the data being relocated to the referenced symbol.
 | |
| 	R_ADDROFF
 | |
| 	R_SIZE
 | |
| 	R_CALL
 | |
| 	R_CALLARM
 | |
| 	R_CALLARM64
 | |
| 	R_CALLIND
 | |
| 	R_CALLPOWER
 | |
| 	// R_CALLMIPS (only used on mips64) resolves to non-PC-relative target address
 | |
| 	// of a CALL (JAL) instruction, by encoding the address into the instruction.
 | |
| 	R_CALLMIPS
 | |
| 	R_CONST
 | |
| 	R_PCREL
 | |
| 	// R_TLS_LE, used on 386, amd64, and ARM, resolves to the offset of the
 | |
| 	// thread-local symbol from the thread local base and is used to implement the
 | |
| 	// "local exec" model for tls access (r.Sym is not set on intel platforms but is
 | |
| 	// set to a TLS symbol -- runtime.tlsg -- in the linker when externally linking).
 | |
| 	R_TLS_LE
 | |
| 	// R_TLS_IE, used 386, amd64, and ARM resolves to the PC-relative offset to a GOT
 | |
| 	// slot containing the offset from the thread-local symbol from the thread local
 | |
| 	// base and is used to implemented the "initial exec" model for tls access (r.Sym
 | |
| 	// is not set on intel platforms but is set to a TLS symbol -- runtime.tlsg -- in
 | |
| 	// the linker when externally linking).
 | |
| 	R_TLS_IE
 | |
| 	R_GOTOFF
 | |
| 	R_PLT0
 | |
| 	R_PLT1
 | |
| 	R_PLT2
 | |
| 	R_USEFIELD
 | |
| 	// R_USETYPE resolves to an *rtype, but no relocation is created. The
 | |
| 	// linker uses this as a signal that the pointed-to type information
 | |
| 	// should be linked into the final binary, even if there are no other
 | |
| 	// direct references. (This is used for types reachable by reflection.)
 | |
| 	R_USETYPE
 | |
| 	// R_METHODOFF resolves to a 32-bit offset from the beginning of the section
 | |
| 	// holding the data being relocated to the referenced symbol.
 | |
| 	// It is a variant of R_ADDROFF used when linking from the uncommonType of a
 | |
| 	// *rtype, and may be set to zero by the linker if it determines the method
 | |
| 	// text is unreachable by the linked program.
 | |
| 	R_METHODOFF
 | |
| 	R_POWER_TOC
 | |
| 	R_GOTPCREL
 | |
| 	// R_JMPMIPS (only used on mips64) resolves to non-PC-relative target address
 | |
| 	// of a JMP instruction, by encoding the address into the instruction.
 | |
| 	// The stack nosplit check ignores this since it is not a function call.
 | |
| 	R_JMPMIPS
 | |
| 	// R_DWARFREF resolves to the offset of the symbol from its section.
 | |
| 	R_DWARFREF
 | |
| 
 | |
| 	// Platform dependent relocations. Architectures with fixed width instructions
 | |
| 	// have the inherent issue that a 32-bit (or 64-bit!) displacement cannot be
 | |
| 	// stuffed into a 32-bit instruction, so an address needs to be spread across
 | |
| 	// several instructions, and in turn this requires a sequence of relocations, each
 | |
| 	// updating a part of an instruction. This leads to relocation codes that are
 | |
| 	// inherently processor specific.
 | |
| 
 | |
| 	// Arm64.
 | |
| 
 | |
| 	// Set a MOV[NZ] immediate field to bits [15:0] of the offset from the thread
 | |
| 	// local base to the thread local variable defined by the referenced (thread
 | |
| 	// local) symbol. Error if the offset does not fit into 16 bits.
 | |
| 	R_ARM64_TLS_LE
 | |
| 
 | |
| 	// Relocates an ADRP; LD64 instruction sequence to load the offset between
 | |
| 	// the thread local base and the thread local variable defined by the
 | |
| 	// referenced (thread local) symbol from the GOT.
 | |
| 	R_ARM64_TLS_IE
 | |
| 
 | |
| 	// R_ARM64_GOTPCREL relocates an adrp, ld64 pair to compute the address of the GOT
 | |
| 	// slot of the referenced symbol.
 | |
| 	R_ARM64_GOTPCREL
 | |
| 
 | |
| 	// PPC64.
 | |
| 
 | |
| 	// R_POWER_TLS_LE is used to implement the "local exec" model for tls
 | |
| 	// access. It resolves to the offset of the thread-local symbol from the
 | |
| 	// thread pointer (R13) and inserts this value into the low 16 bits of an
 | |
| 	// instruction word.
 | |
| 	R_POWER_TLS_LE
 | |
| 
 | |
| 	// R_POWER_TLS_IE is used to implement the "initial exec" model for tls access. It
 | |
| 	// relocates a D-form, DS-form instruction sequence like R_ADDRPOWER_DS. It
 | |
| 	// inserts to the offset of GOT slot for the thread-local symbol from the TOC (the
 | |
| 	// GOT slot is filled by the dynamic linker with the offset of the thread-local
 | |
| 	// symbol from the thread pointer (R13)).
 | |
| 	R_POWER_TLS_IE
 | |
| 
 | |
| 	// R_POWER_TLS marks an X-form instruction such as "MOVD 0(R13)(R31*1), g" as
 | |
| 	// accessing a particular thread-local symbol. It does not affect code generation
 | |
| 	// but is used by the system linker when relaxing "initial exec" model code to
 | |
| 	// "local exec" model code.
 | |
| 	R_POWER_TLS
 | |
| 
 | |
| 	// R_ADDRPOWER_DS is similar to R_ADDRPOWER above, but assumes the second
 | |
| 	// instruction is a "DS-form" instruction, which has an immediate field occupying
 | |
| 	// bits [15:2] of the instruction word. Bits [15:2] of the address of the
 | |
| 	// relocated symbol are inserted into this field; it is an error if the last two
 | |
| 	// bits of the address are not 0.
 | |
| 	R_ADDRPOWER_DS
 | |
| 
 | |
| 	// R_ADDRPOWER_PCREL relocates a D-form, DS-form instruction sequence like
 | |
| 	// R_ADDRPOWER_DS but inserts the offset of the GOT slot for the referenced symbol
 | |
| 	// from the TOC rather than the symbol's address.
 | |
| 	R_ADDRPOWER_GOT
 | |
| 
 | |
| 	// R_ADDRPOWER_PCREL relocates two D-form instructions like R_ADDRPOWER, but
 | |
| 	// inserts the displacement from the place being relocated to the address of the
 | |
| 	// the relocated symbol instead of just its address.
 | |
| 	R_ADDRPOWER_PCREL
 | |
| 
 | |
| 	// R_ADDRPOWER_TOCREL relocates two D-form instructions like R_ADDRPOWER, but
 | |
| 	// inserts the offset from the TOC to the address of the the relocated symbol
 | |
| 	// rather than the symbol's address.
 | |
| 	R_ADDRPOWER_TOCREL
 | |
| 
 | |
| 	// R_ADDRPOWER_TOCREL relocates a D-form, DS-form instruction sequence like
 | |
| 	// R_ADDRPOWER_DS but inserts the offset from the TOC to the address of the the
 | |
| 	// relocated symbol rather than the symbol's address.
 | |
| 	R_ADDRPOWER_TOCREL_DS
 | |
| 
 | |
| 	// R_PCRELDBL relocates s390x 2-byte aligned PC-relative addresses.
 | |
| 	// TODO(mundaym): remove once variants can be serialized - see issue 14218.
 | |
| 	R_PCRELDBL
 | |
| 
 | |
| 	// R_ADDRMIPSU (only used on mips64) resolves to the sign-adjusted "upper" 16
 | |
| 	// bits (bit 16-31) of an external address, by encoding it into the instruction.
 | |
| 	R_ADDRMIPSU
 | |
| 	// R_ADDRMIPSTLS (only used on mips64) resolves to the low 16 bits of a TLS
 | |
| 	// address (offset from thread pointer), by encoding it into the instruction.
 | |
| 	R_ADDRMIPSTLS
 | |
| )
 | |
| 
 | |
| // IsDirectJump returns whether r is a relocation for a direct jump.
 | |
| // A direct jump is a CALL or JMP instruction that takes the target address
 | |
| // as immediate. The address is embedded into the instruction, possibly
 | |
| // with limited width.
 | |
| // An indirect jump is a CALL or JMP instruction that takes the target address
 | |
| // in register or memory.
 | |
| func (r RelocType) IsDirectJump() bool {
 | |
| 	switch r {
 | |
| 	case R_CALL, R_CALLARM, R_CALLARM64, R_CALLPOWER, R_CALLMIPS, R_JMPMIPS:
 | |
| 		return true
 | |
| 	}
 | |
| 	return false
 | |
| }
 | |
| 
 | |
| type Auto struct {
 | |
| 	Asym    *LSym
 | |
| 	Link    *Auto
 | |
| 	Aoffset int32
 | |
| 	Name    int16
 | |
| 	Gotype  *LSym
 | |
| }
 | |
| 
 | |
| // Auto.name
 | |
| const (
 | |
| 	A_AUTO = 1 + iota
 | |
| 	A_PARAM
 | |
| )
 | |
| 
 | |
| type Pcdata struct {
 | |
| 	P []byte
 | |
| }
 | |
| 
 | |
| // symbol version, incremented each time a file is loaded.
 | |
| // version==1 is reserved for savehist.
 | |
| const (
 | |
| 	HistVersion = 1
 | |
| )
 | |
| 
 | |
| // 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      HeadType
 | |
| 	Arch          *LinkArch
 | |
| 	Debugasm      int32
 | |
| 	Debugvlog     int32
 | |
| 	Debugdivmod   int32
 | |
| 	Debugpcln     int32
 | |
| 	Flag_shared   bool
 | |
| 	Flag_dynlink  bool
 | |
| 	Flag_optimize bool
 | |
| 	Bso           *bufio.Writer
 | |
| 	Pathname      string
 | |
| 	Hash          map[SymVer]*LSym
 | |
| 	LineHist      LineHist
 | |
| 	Imports       []string
 | |
| 	Plists        []*Plist
 | |
| 	Sym_div       *LSym
 | |
| 	Sym_divu      *LSym
 | |
| 	Sym_mod       *LSym
 | |
| 	Sym_modu      *LSym
 | |
| 	Plan9privates *LSym
 | |
| 	Curp          *Prog
 | |
| 	Printp        *Prog
 | |
| 	Blitrl        *Prog
 | |
| 	Elitrl        *Prog
 | |
| 	Rexflag       int
 | |
| 	Vexflag       int
 | |
| 	Rep           int
 | |
| 	Repn          int
 | |
| 	Lock          int
 | |
| 	Asmode        int
 | |
| 	AsmBuf        AsmBuf // instruction buffer for x86
 | |
| 	Instoffset    int64
 | |
| 	Autosize      int32
 | |
| 	Armsize       int32
 | |
| 	Pc            int64
 | |
| 	DiagFunc      func(string, ...interface{})
 | |
| 	Mode          int
 | |
| 	Cursym        *LSym
 | |
| 	Version       int
 | |
| 	Errors        int
 | |
| 
 | |
| 	Framepointer_enabled bool
 | |
| 
 | |
| 	// state for writing objects
 | |
| 	Text []*LSym
 | |
| 	Data []*LSym
 | |
| 
 | |
| 	// Cache of Progs
 | |
| 	allocIdx int
 | |
| 	progs    [10000]Prog
 | |
| }
 | |
| 
 | |
| 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:
 | |
| 		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)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| type SymVer struct {
 | |
| 	Name    string
 | |
| 	Version int // TODO: make int16 to match LSym.Version?
 | |
| }
 | |
| 
 | |
| // LinkArch is the definition of a single architecture.
 | |
| type LinkArch struct {
 | |
| 	*sys.Arch
 | |
| 	Preprocess func(*Link, *LSym)
 | |
| 	Assemble   func(*Link, *LSym)
 | |
| 	Follow     func(*Link, *LSym)
 | |
| 	Progedit   func(*Link, *Prog)
 | |
| 	UnaryDst   map[As]bool // Instruction takes one operand, a destination.
 | |
| }
 | |
| 
 | |
| // HeadType is the executable header type.
 | |
| type HeadType uint8
 | |
| 
 | |
| const (
 | |
| 	Hunknown HeadType = iota
 | |
| 	Hdarwin
 | |
| 	Hdragonfly
 | |
| 	Hfreebsd
 | |
| 	Hlinux
 | |
| 	Hnacl
 | |
| 	Hnetbsd
 | |
| 	Hopenbsd
 | |
| 	Hplan9
 | |
| 	Hsolaris
 | |
| 	Hwindows
 | |
| 	Hwindowsgui
 | |
| )
 | |
| 
 | |
| func (h *HeadType) Set(s string) error {
 | |
| 	switch s {
 | |
| 	case "darwin":
 | |
| 		*h = Hdarwin
 | |
| 	case "dragonfly":
 | |
| 		*h = Hdragonfly
 | |
| 	case "freebsd":
 | |
| 		*h = Hfreebsd
 | |
| 	case "linux", "android":
 | |
| 		*h = Hlinux
 | |
| 	case "nacl":
 | |
| 		*h = Hnacl
 | |
| 	case "netbsd":
 | |
| 		*h = Hnetbsd
 | |
| 	case "openbsd":
 | |
| 		*h = Hopenbsd
 | |
| 	case "plan9":
 | |
| 		*h = Hplan9
 | |
| 	case "solaris":
 | |
| 		*h = Hsolaris
 | |
| 	case "windows":
 | |
| 		*h = Hwindows
 | |
| 	case "windowsgui":
 | |
| 		*h = Hwindowsgui
 | |
| 	default:
 | |
| 		return fmt.Errorf("invalid headtype: %q", s)
 | |
| 	}
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func (h *HeadType) String() string {
 | |
| 	switch *h {
 | |
| 	case Hdarwin:
 | |
| 		return "darwin"
 | |
| 	case Hdragonfly:
 | |
| 		return "dragonfly"
 | |
| 	case Hfreebsd:
 | |
| 		return "freebsd"
 | |
| 	case Hlinux:
 | |
| 		return "linux"
 | |
| 	case Hnacl:
 | |
| 		return "nacl"
 | |
| 	case Hnetbsd:
 | |
| 		return "netbsd"
 | |
| 	case Hopenbsd:
 | |
| 		return "openbsd"
 | |
| 	case Hplan9:
 | |
| 		return "plan9"
 | |
| 	case Hsolaris:
 | |
| 		return "solaris"
 | |
| 	case Hwindows:
 | |
| 		return "windows"
 | |
| 	case Hwindowsgui:
 | |
| 		return "windowsgui"
 | |
| 	}
 | |
| 	return fmt.Sprintf("HeadType(%d)", *h)
 | |
| }
 | |
| 
 | |
| // AsmBuf is a simple buffer to assemble variable-length x86 instructions into.
 | |
| type AsmBuf struct {
 | |
| 	buf [100]byte
 | |
| 	off int
 | |
| }
 | |
| 
 | |
| // Put1 appends one byte to the end of the buffer.
 | |
| func (a *AsmBuf) Put1(x byte) {
 | |
| 	a.buf[a.off] = x
 | |
| 	a.off++
 | |
| }
 | |
| 
 | |
| // Put2 appends two bytes to the end of the buffer.
 | |
| func (a *AsmBuf) Put2(x, y byte) {
 | |
| 	a.buf[a.off+0] = x
 | |
| 	a.buf[a.off+1] = y
 | |
| 	a.off += 2
 | |
| }
 | |
| 
 | |
| // Put3 appends three bytes to the end of the buffer.
 | |
| func (a *AsmBuf) Put3(x, y, z byte) {
 | |
| 	a.buf[a.off+0] = x
 | |
| 	a.buf[a.off+1] = y
 | |
| 	a.buf[a.off+2] = z
 | |
| 	a.off += 3
 | |
| }
 | |
| 
 | |
| // Put4 appends four bytes to the end of the buffer.
 | |
| func (a *AsmBuf) Put4(x, y, z, w byte) {
 | |
| 	a.buf[a.off+0] = x
 | |
| 	a.buf[a.off+1] = y
 | |
| 	a.buf[a.off+2] = z
 | |
| 	a.buf[a.off+3] = w
 | |
| 	a.off += 4
 | |
| }
 | |
| 
 | |
| // PutInt16 writes v into the buffer using little-endian encoding.
 | |
| func (a *AsmBuf) PutInt16(v int16) {
 | |
| 	a.buf[a.off+0] = byte(v)
 | |
| 	a.buf[a.off+1] = byte(v >> 8)
 | |
| 	a.off += 2
 | |
| }
 | |
| 
 | |
| // PutInt32 writes v into the buffer using little-endian encoding.
 | |
| func (a *AsmBuf) PutInt32(v int32) {
 | |
| 	a.buf[a.off+0] = byte(v)
 | |
| 	a.buf[a.off+1] = byte(v >> 8)
 | |
| 	a.buf[a.off+2] = byte(v >> 16)
 | |
| 	a.buf[a.off+3] = byte(v >> 24)
 | |
| 	a.off += 4
 | |
| }
 | |
| 
 | |
| // PutInt64 writes v into the buffer using little-endian encoding.
 | |
| func (a *AsmBuf) PutInt64(v int64) {
 | |
| 	a.buf[a.off+0] = byte(v)
 | |
| 	a.buf[a.off+1] = byte(v >> 8)
 | |
| 	a.buf[a.off+2] = byte(v >> 16)
 | |
| 	a.buf[a.off+3] = byte(v >> 24)
 | |
| 	a.buf[a.off+4] = byte(v >> 32)
 | |
| 	a.buf[a.off+5] = byte(v >> 40)
 | |
| 	a.buf[a.off+6] = byte(v >> 48)
 | |
| 	a.buf[a.off+7] = byte(v >> 56)
 | |
| 	a.off += 8
 | |
| }
 | |
| 
 | |
| // Put copies b into the buffer.
 | |
| func (a *AsmBuf) Put(b []byte) {
 | |
| 	copy(a.buf[a.off:], b)
 | |
| 	a.off += len(b)
 | |
| }
 | |
| 
 | |
| // Insert inserts b at offset i.
 | |
| func (a *AsmBuf) Insert(i int, b byte) {
 | |
| 	a.off++
 | |
| 	copy(a.buf[i+1:a.off], a.buf[i:a.off-1])
 | |
| 	a.buf[i] = b
 | |
| }
 | |
| 
 | |
| // Last returns the byte at the end of the buffer.
 | |
| func (a *AsmBuf) Last() byte { return a.buf[a.off-1] }
 | |
| 
 | |
| // Len returns the length of the buffer.
 | |
| func (a *AsmBuf) Len() int { return a.off }
 | |
| 
 | |
| // Bytes returns the contents of the buffer.
 | |
| func (a *AsmBuf) Bytes() []byte { return a.buf[:a.off] }
 | |
| 
 | |
| // Reset empties the buffer.
 | |
| func (a *AsmBuf) Reset() { a.off = 0 }
 | |
| 
 | |
| // Peek returns the byte at offset i.
 | |
| func (a *AsmBuf) Peek(i int) byte { return a.buf[i] }
 | 
