summaryrefslogtreecommitdiff
path: root/vendor/github.com/cloudwego/iasm/x86_64/program.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/cloudwego/iasm/x86_64/program.go')
-rw-r--r--vendor/github.com/cloudwego/iasm/x86_64/program.go584
1 files changed, 0 insertions, 584 deletions
diff --git a/vendor/github.com/cloudwego/iasm/x86_64/program.go b/vendor/github.com/cloudwego/iasm/x86_64/program.go
deleted file mode 100644
index f0c9b18c6..000000000
--- a/vendor/github.com/cloudwego/iasm/x86_64/program.go
+++ /dev/null
@@ -1,584 +0,0 @@
-//
-// 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
-}