mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-11-03 19:22:24 -06:00 
			
		
		
		
	Bumps [github.com/gin-contrib/gzip](https://github.com/gin-contrib/gzip) from 1.0.0 to 1.0.1. - [Release notes](https://github.com/gin-contrib/gzip/releases) - [Changelog](https://github.com/gin-contrib/gzip/blob/master/.goreleaser.yaml) - [Commits](https://github.com/gin-contrib/gzip/compare/v1.0.0...v1.0.1) --- updated-dependencies: - dependency-name: github.com/gin-contrib/gzip dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
		
			
				
	
	
		
			584 lines
		
	
	
	
		
			13 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			584 lines
		
	
	
	
		
			13 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
//
 | 
						|
// Copyright 2024 CloudWeGo Authors
 | 
						|
//
 | 
						|
// Licensed under the Apache License, Version 2.0 (the "License");
 | 
						|
// you may not use this file except in compliance with the License.
 | 
						|
// You may obtain a copy of the License at
 | 
						|
//
 | 
						|
//     http://www.apache.org/licenses/LICENSE-2.0
 | 
						|
//
 | 
						|
// Unless required by applicable law or agreed to in writing, software
 | 
						|
// distributed under the License is distributed on an "AS IS" BASIS,
 | 
						|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
						|
// See the License for the specific language governing permissions and
 | 
						|
// limitations under the License.
 | 
						|
//
 | 
						|
 | 
						|
package x86_64
 | 
						|
 | 
						|
import (
 | 
						|
	"fmt"
 | 
						|
	"math"
 | 
						|
	"math/bits"
 | 
						|
 | 
						|
	"github.com/cloudwego/iasm/expr"
 | 
						|
)
 | 
						|
 | 
						|
type (
 | 
						|
	_PseudoType         int
 | 
						|
	_InstructionEncoder func(*Program, ...interface{}) *Instruction
 | 
						|
)
 | 
						|
 | 
						|
const (
 | 
						|
	_PseudoNop _PseudoType = iota + 1
 | 
						|
	_PseudoByte
 | 
						|
	_PseudoWord
 | 
						|
	_PseudoLong
 | 
						|
	_PseudoQuad
 | 
						|
	_PseudoData
 | 
						|
	_PseudoAlign
 | 
						|
)
 | 
						|
 | 
						|
func (self _PseudoType) String() string {
 | 
						|
	switch self {
 | 
						|
	case _PseudoNop:
 | 
						|
		return ".nop"
 | 
						|
	case _PseudoByte:
 | 
						|
		return ".byte"
 | 
						|
	case _PseudoWord:
 | 
						|
		return ".word"
 | 
						|
	case _PseudoLong:
 | 
						|
		return ".long"
 | 
						|
	case _PseudoQuad:
 | 
						|
		return ".quad"
 | 
						|
	case _PseudoData:
 | 
						|
		return ".data"
 | 
						|
	case _PseudoAlign:
 | 
						|
		return ".align"
 | 
						|
	default:
 | 
						|
		panic("unreachable")
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
type _Pseudo struct {
 | 
						|
	kind _PseudoType
 | 
						|
	data []byte
 | 
						|
	uint uint64
 | 
						|
	expr *expr.Expr
 | 
						|
}
 | 
						|
 | 
						|
func (self *_Pseudo) free() {
 | 
						|
	if self.expr != nil {
 | 
						|
		self.expr.Free()
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (self *_Pseudo) encode(m *[]byte, pc uintptr) int {
 | 
						|
	switch self.kind {
 | 
						|
	case _PseudoNop:
 | 
						|
		return 0
 | 
						|
	case _PseudoByte:
 | 
						|
		self.encodeByte(m)
 | 
						|
		return 1
 | 
						|
	case _PseudoWord:
 | 
						|
		self.encodeWord(m)
 | 
						|
		return 2
 | 
						|
	case _PseudoLong:
 | 
						|
		self.encodeLong(m)
 | 
						|
		return 4
 | 
						|
	case _PseudoQuad:
 | 
						|
		self.encodeQuad(m)
 | 
						|
		return 8
 | 
						|
	case _PseudoData:
 | 
						|
		self.encodeData(m)
 | 
						|
		return len(self.data)
 | 
						|
	case _PseudoAlign:
 | 
						|
		self.encodeAlign(m, pc)
 | 
						|
		return self.alignSize(pc)
 | 
						|
	default:
 | 
						|
		panic("invalid pseudo instruction")
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (self *_Pseudo) evalExpr(low int64, high int64) int64 {
 | 
						|
	if v, err := self.expr.Evaluate(); err != nil {
 | 
						|
		panic(err)
 | 
						|
	} else if v < low || v > high {
 | 
						|
		panic(fmt.Sprintf("expression out of range [%d, %d]: %d", low, high, v))
 | 
						|
	} else {
 | 
						|
		return v
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (self *_Pseudo) alignSize(pc uintptr) int {
 | 
						|
	if !ispow2(self.uint) {
 | 
						|
		panic(fmt.Sprintf("aligment should be a power of 2, not %d", self.uint))
 | 
						|
	} else {
 | 
						|
		return align(int(pc), bits.TrailingZeros64(self.uint)) - int(pc)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (self *_Pseudo) encodeData(m *[]byte) {
 | 
						|
	if m != nil {
 | 
						|
		*m = append(*m, self.data...)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (self *_Pseudo) encodeByte(m *[]byte) {
 | 
						|
	if m != nil {
 | 
						|
		append8(m, byte(self.evalExpr(math.MinInt8, math.MaxUint8)))
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (self *_Pseudo) encodeWord(m *[]byte) {
 | 
						|
	if m != nil {
 | 
						|
		append16(m, uint16(self.evalExpr(math.MinInt16, math.MaxUint16)))
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (self *_Pseudo) encodeLong(m *[]byte) {
 | 
						|
	if m != nil {
 | 
						|
		append32(m, uint32(self.evalExpr(math.MinInt32, math.MaxUint32)))
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (self *_Pseudo) encodeQuad(m *[]byte) {
 | 
						|
	if m != nil {
 | 
						|
		if v, err := self.expr.Evaluate(); err != nil {
 | 
						|
			panic(err)
 | 
						|
		} else {
 | 
						|
			append64(m, uint64(v))
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (self *_Pseudo) encodeAlign(m *[]byte, pc uintptr) {
 | 
						|
	if m != nil {
 | 
						|
		if self.expr == nil {
 | 
						|
			expandmm(m, self.alignSize(pc), 0)
 | 
						|
		} else {
 | 
						|
			expandmm(m, self.alignSize(pc), byte(self.evalExpr(math.MinInt8, math.MaxUint8)))
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// Operands represents a sequence of operand required by an instruction.
 | 
						|
type Operands [_N_args]interface{}
 | 
						|
 | 
						|
// InstructionDomain represents the domain of an instruction.
 | 
						|
type InstructionDomain uint8
 | 
						|
 | 
						|
const (
 | 
						|
	DomainGeneric InstructionDomain = iota
 | 
						|
	DomainMMXSSE
 | 
						|
	DomainAVX
 | 
						|
	DomainFMA
 | 
						|
	DomainCrypto
 | 
						|
	DomainMask
 | 
						|
	DomainAMDSpecific
 | 
						|
	DomainMisc
 | 
						|
	DomainPseudo
 | 
						|
)
 | 
						|
 | 
						|
type (
 | 
						|
	_BranchType uint8
 | 
						|
)
 | 
						|
 | 
						|
const (
 | 
						|
	_B_none _BranchType = iota
 | 
						|
	_B_conditional
 | 
						|
	_B_unconditional
 | 
						|
)
 | 
						|
 | 
						|
// Instruction represents an unencoded instruction.
 | 
						|
type Instruction struct {
 | 
						|
	next   *Instruction
 | 
						|
	pc     uintptr
 | 
						|
	nb     int
 | 
						|
	len    int
 | 
						|
	argc   int
 | 
						|
	name   string
 | 
						|
	argv   Operands
 | 
						|
	forms  [_N_forms]_Encoding
 | 
						|
	pseudo _Pseudo
 | 
						|
	branch _BranchType
 | 
						|
	domain InstructionDomain
 | 
						|
	prefix []byte
 | 
						|
}
 | 
						|
 | 
						|
func (self *Instruction) add(flags int, encoder func(m *_Encoding, v []interface{})) {
 | 
						|
	self.forms[self.len].flags = flags
 | 
						|
	self.forms[self.len].encoder = encoder
 | 
						|
	self.len++
 | 
						|
}
 | 
						|
 | 
						|
func (self *Instruction) free() {
 | 
						|
	self.clear()
 | 
						|
	self.pseudo.free()
 | 
						|
	//freeInstruction(self)
 | 
						|
}
 | 
						|
 | 
						|
func (self *Instruction) clear() {
 | 
						|
	for i := 0; i < self.argc; i++ {
 | 
						|
		if v, ok := self.argv[i].(Disposable); ok {
 | 
						|
			v.Free()
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (self *Instruction) check(e *_Encoding) bool {
 | 
						|
	if (e.flags & _F_rel1) != 0 {
 | 
						|
		return isRel8(self.argv[0])
 | 
						|
	} else if (e.flags & _F_rel4) != 0 {
 | 
						|
		return isRel32(self.argv[0]) || isLabel(self.argv[0])
 | 
						|
	} else {
 | 
						|
		return true
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (self *Instruction) encode(m *[]byte) int {
 | 
						|
	n := math.MaxInt64
 | 
						|
	p := (*_Encoding)(nil)
 | 
						|
 | 
						|
	/* encode prefixes if any */
 | 
						|
	if self.nb = len(self.prefix); m != nil {
 | 
						|
		*m = append(*m, self.prefix...)
 | 
						|
	}
 | 
						|
 | 
						|
	/* check for pseudo-instructions */
 | 
						|
	if self.pseudo.kind != 0 {
 | 
						|
		self.nb += self.pseudo.encode(m, self.pc)
 | 
						|
		return self.nb
 | 
						|
	}
 | 
						|
 | 
						|
	/* find the shortest encoding */
 | 
						|
	for i := 0; i < self.len; i++ {
 | 
						|
		if e := &self.forms[i]; self.check(e) {
 | 
						|
			if v := e.encode(self.argv[:self.argc]); v < n {
 | 
						|
				n = v
 | 
						|
				p = e
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	/* add to buffer if needed */
 | 
						|
	if m != nil {
 | 
						|
		*m = append(*m, p.bytes[:n]...)
 | 
						|
	}
 | 
						|
 | 
						|
	/* update the instruction length */
 | 
						|
	self.nb += n
 | 
						|
	return self.nb
 | 
						|
}
 | 
						|
 | 
						|
/** Instruction Prefixes **/
 | 
						|
 | 
						|
const (
 | 
						|
	_P_cs   = 0x2e
 | 
						|
	_P_ds   = 0x3e
 | 
						|
	_P_es   = 0x26
 | 
						|
	_P_fs   = 0x64
 | 
						|
	_P_gs   = 0x65
 | 
						|
	_P_ss   = 0x36
 | 
						|
	_P_lock = 0xf0
 | 
						|
)
 | 
						|
 | 
						|
// CS overrides the memory operation of this instruction to CS.
 | 
						|
func (self *Instruction) CS() *Instruction {
 | 
						|
	self.prefix = append(self.prefix, _P_cs)
 | 
						|
	return self
 | 
						|
}
 | 
						|
 | 
						|
// DS overrides the memory operation of this instruction to DS,
 | 
						|
// this is the default section for most instructions if not specified.
 | 
						|
func (self *Instruction) DS() *Instruction {
 | 
						|
	self.prefix = append(self.prefix, _P_ds)
 | 
						|
	return self
 | 
						|
}
 | 
						|
 | 
						|
// ES overrides the memory operation of this instruction to ES.
 | 
						|
func (self *Instruction) ES() *Instruction {
 | 
						|
	self.prefix = append(self.prefix, _P_es)
 | 
						|
	return self
 | 
						|
}
 | 
						|
 | 
						|
// FS overrides the memory operation of this instruction to FS.
 | 
						|
func (self *Instruction) FS() *Instruction {
 | 
						|
	self.prefix = append(self.prefix, _P_fs)
 | 
						|
	return self
 | 
						|
}
 | 
						|
 | 
						|
// GS overrides the memory operation of this instruction to GS.
 | 
						|
func (self *Instruction) GS() *Instruction {
 | 
						|
	self.prefix = append(self.prefix, _P_gs)
 | 
						|
	return self
 | 
						|
}
 | 
						|
 | 
						|
// SS overrides the memory operation of this instruction to SS.
 | 
						|
func (self *Instruction) SS() *Instruction {
 | 
						|
	self.prefix = append(self.prefix, _P_ss)
 | 
						|
	return self
 | 
						|
}
 | 
						|
 | 
						|
// LOCK causes the processor's LOCK# signal to be asserted during execution of
 | 
						|
// the accompanying instruction (turns the instruction into an atomic instruction).
 | 
						|
// In a multiprocessor environment, the LOCK# signal insures that the processor
 | 
						|
// has exclusive use of any shared memory while the signal is asserted.
 | 
						|
func (self *Instruction) LOCK() *Instruction {
 | 
						|
	self.prefix = append(self.prefix, _P_lock)
 | 
						|
	return self
 | 
						|
}
 | 
						|
 | 
						|
/** Basic Instruction Properties **/
 | 
						|
 | 
						|
// Name returns the instruction name.
 | 
						|
func (self *Instruction) Name() string {
 | 
						|
	return self.name
 | 
						|
}
 | 
						|
 | 
						|
// Domain returns the domain of this instruction.
 | 
						|
func (self *Instruction) Domain() InstructionDomain {
 | 
						|
	return self.domain
 | 
						|
}
 | 
						|
 | 
						|
// Operands returns the operands of this instruction.
 | 
						|
func (self *Instruction) Operands() []interface{} {
 | 
						|
	return self.argv[:self.argc]
 | 
						|
}
 | 
						|
 | 
						|
// Program represents a sequence of instructions.
 | 
						|
type Program struct {
 | 
						|
	arch *Arch
 | 
						|
	head *Instruction
 | 
						|
	tail *Instruction
 | 
						|
}
 | 
						|
 | 
						|
const (
 | 
						|
	_N_near       = 2 // near-branch (-128 ~ +127) takes 2 bytes to encode
 | 
						|
	_N_far_cond   = 6 // conditional far-branch takes 6 bytes to encode
 | 
						|
	_N_far_uncond = 5 // unconditional far-branch takes 5 bytes to encode
 | 
						|
)
 | 
						|
 | 
						|
func (self *Program) clear() {
 | 
						|
	for p, q := self.head, self.head; p != nil; p = q {
 | 
						|
		q = p.next
 | 
						|
		p.free()
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (self *Program) alloc(name string, argc int, argv Operands) *Instruction {
 | 
						|
	p := self.tail
 | 
						|
	q := newInstruction(name, argc, argv)
 | 
						|
 | 
						|
	/* attach to tail if any */
 | 
						|
	if p != nil {
 | 
						|
		p.next = q
 | 
						|
	} else {
 | 
						|
		self.head = q
 | 
						|
	}
 | 
						|
 | 
						|
	/* set the new tail */
 | 
						|
	self.tail = q
 | 
						|
	return q
 | 
						|
}
 | 
						|
 | 
						|
func (self *Program) pseudo(kind _PseudoType) (p *Instruction) {
 | 
						|
	p = self.alloc(kind.String(), 0, Operands{})
 | 
						|
	p.domain = DomainPseudo
 | 
						|
	p.pseudo.kind = kind
 | 
						|
	return
 | 
						|
}
 | 
						|
 | 
						|
func (self *Program) require(isa ISA) {
 | 
						|
	if !self.arch.HasISA(isa) {
 | 
						|
		panic("ISA '" + isa.String() + "' was not enabled")
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (self *Program) branchSize(p *Instruction) int {
 | 
						|
	switch p.branch {
 | 
						|
	case _B_none:
 | 
						|
		panic("p is not a branch")
 | 
						|
	case _B_conditional:
 | 
						|
		return _N_far_cond
 | 
						|
	case _B_unconditional:
 | 
						|
		return _N_far_uncond
 | 
						|
	default:
 | 
						|
		panic("invalid instruction")
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/** Pseudo-Instructions **/
 | 
						|
 | 
						|
// Byte is a pseudo-instruction to add raw byte to the assembled code.
 | 
						|
func (self *Program) Byte(v *expr.Expr) (p *Instruction) {
 | 
						|
	p = self.pseudo(_PseudoByte)
 | 
						|
	p.pseudo.expr = v
 | 
						|
	return
 | 
						|
}
 | 
						|
 | 
						|
// Word is a pseudo-instruction to add raw uint16 as little-endian to the assembled code.
 | 
						|
func (self *Program) Word(v *expr.Expr) (p *Instruction) {
 | 
						|
	p = self.pseudo(_PseudoWord)
 | 
						|
	p.pseudo.expr = v
 | 
						|
	return
 | 
						|
}
 | 
						|
 | 
						|
// Long is a pseudo-instruction to add raw uint32 as little-endian to the assembled code.
 | 
						|
func (self *Program) Long(v *expr.Expr) (p *Instruction) {
 | 
						|
	p = self.pseudo(_PseudoLong)
 | 
						|
	p.pseudo.expr = v
 | 
						|
	return
 | 
						|
}
 | 
						|
 | 
						|
// Quad is a pseudo-instruction to add raw uint64 as little-endian to the assembled code.
 | 
						|
func (self *Program) Quad(v *expr.Expr) (p *Instruction) {
 | 
						|
	p = self.pseudo(_PseudoQuad)
 | 
						|
	p.pseudo.expr = v
 | 
						|
	return
 | 
						|
}
 | 
						|
 | 
						|
// Data is a pseudo-instruction to add raw bytes to the assembled code.
 | 
						|
func (self *Program) Data(v []byte) (p *Instruction) {
 | 
						|
	p = self.pseudo(_PseudoData)
 | 
						|
	p.pseudo.data = v
 | 
						|
	return
 | 
						|
}
 | 
						|
 | 
						|
// Align is a pseudo-instruction to ensure the PC is aligned to a certain value.
 | 
						|
func (self *Program) Align(align uint64, padding *expr.Expr) (p *Instruction) {
 | 
						|
	p = self.pseudo(_PseudoAlign)
 | 
						|
	p.pseudo.uint = align
 | 
						|
	p.pseudo.expr = padding
 | 
						|
	return
 | 
						|
}
 | 
						|
 | 
						|
/** Program Assembler **/
 | 
						|
 | 
						|
// Free returns the Program object into pool.
 | 
						|
// Any operation performed after Free is undefined behavior.
 | 
						|
//
 | 
						|
// NOTE: This also frees all the instructions, labels, memory
 | 
						|
//
 | 
						|
//	operands and expressions associated with this program.
 | 
						|
func (self *Program) Free() {
 | 
						|
	self.clear()
 | 
						|
	//freeProgram(self)
 | 
						|
}
 | 
						|
 | 
						|
// Link pins a label at the current position.
 | 
						|
func (self *Program) Link(p *Label) {
 | 
						|
	if p.Dest != nil {
 | 
						|
		panic("lable was alreay linked")
 | 
						|
	} else {
 | 
						|
		p.Dest = self.pseudo(_PseudoNop)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// Assemble assembles and links the entire program into machine code.
 | 
						|
func (self *Program) Assemble(pc uintptr) (ret []byte) {
 | 
						|
	orig := pc
 | 
						|
	next := true
 | 
						|
	offs := uintptr(0)
 | 
						|
 | 
						|
	/* Pass 0: PC-precompute, assume all labeled branches are far-branches. */
 | 
						|
	for p := self.head; p != nil; p = p.next {
 | 
						|
		if p.pc = pc; !isLabel(p.argv[0]) || p.branch == _B_none {
 | 
						|
			pc += uintptr(p.encode(nil))
 | 
						|
		} else {
 | 
						|
			pc += uintptr(self.branchSize(p))
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	/* allocate space for the machine code */
 | 
						|
	nb := int(pc - orig)
 | 
						|
	ret = make([]byte, 0, nb)
 | 
						|
 | 
						|
	/* Pass 1: adjust all the jumps */
 | 
						|
	for next {
 | 
						|
		next = false
 | 
						|
		offs = uintptr(0)
 | 
						|
 | 
						|
		/* scan all the branches */
 | 
						|
		for p := self.head; p != nil; p = p.next {
 | 
						|
			var ok bool
 | 
						|
			var lb *Label
 | 
						|
 | 
						|
			/* re-calculate the alignment here */
 | 
						|
			if nb = p.nb; p.pseudo.kind == _PseudoAlign {
 | 
						|
				p.pc -= offs
 | 
						|
				offs += uintptr(nb - p.encode(nil))
 | 
						|
				continue
 | 
						|
			}
 | 
						|
 | 
						|
			/* adjust the program counter */
 | 
						|
			p.pc -= offs
 | 
						|
			lb, ok = p.argv[0].(*Label)
 | 
						|
 | 
						|
			/* only care about labeled far-branches */
 | 
						|
			if !ok || p.nb == _N_near || p.branch == _B_none {
 | 
						|
				continue
 | 
						|
			}
 | 
						|
 | 
						|
			/* calculate the jump offset */
 | 
						|
			size := self.branchSize(p)
 | 
						|
			diff := lb.offset(p.pc, size)
 | 
						|
 | 
						|
			/* too far to be a near jump */
 | 
						|
			if diff > 127 || diff < -128 {
 | 
						|
				p.nb = size
 | 
						|
				continue
 | 
						|
			}
 | 
						|
 | 
						|
			/* a far jump becomes a near jump, calculate
 | 
						|
			 * the PC adjustment value and assemble again */
 | 
						|
			next = true
 | 
						|
			p.nb = _N_near
 | 
						|
			offs += uintptr(size - _N_near)
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	/* Pass 3: link all the cross-references */
 | 
						|
	for p := self.head; p != nil; p = p.next {
 | 
						|
		for i := 0; i < p.argc; i++ {
 | 
						|
			var ok bool
 | 
						|
			var lb *Label
 | 
						|
			var op *MemoryOperand
 | 
						|
 | 
						|
			/* resolve labels */
 | 
						|
			if lb, ok = p.argv[i].(*Label); ok {
 | 
						|
				p.argv[i] = lb.offset(p.pc, p.nb)
 | 
						|
				continue
 | 
						|
			}
 | 
						|
 | 
						|
			/* check for memory operands */
 | 
						|
			if op, ok = p.argv[i].(*MemoryOperand); !ok {
 | 
						|
				continue
 | 
						|
			}
 | 
						|
 | 
						|
			/* check for label references */
 | 
						|
			if op.Addr.Type != Reference {
 | 
						|
				continue
 | 
						|
			}
 | 
						|
 | 
						|
			/* replace the label with the real offset */
 | 
						|
			op.Addr.Type = Offset
 | 
						|
			op.Addr.Offset = op.Addr.Reference.offset(p.pc, p.nb)
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	/* Pass 4: actually encode all the instructions */
 | 
						|
	for p := self.head; p != nil; p = p.next {
 | 
						|
		p.encode(&ret)
 | 
						|
	}
 | 
						|
 | 
						|
	/* all done */
 | 
						|
	return ret
 | 
						|
}
 | 
						|
 | 
						|
// AssembleAndFree is like Assemble, but it frees the Program after assembling.
 | 
						|
func (self *Program) AssembleAndFree(pc uintptr) (ret []byte) {
 | 
						|
	ret = self.Assemble(pc)
 | 
						|
	self.Free()
 | 
						|
	return
 | 
						|
}
 |