This repository has been archived by the owner on Jul 6, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 7
/
Store.go
106 lines (80 loc) · 2.42 KB
/
Store.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
package asm
import (
"log"
"github.com/akyoto/asm/opcode"
)
// StoreNumber stores a number into the memory address included in the given register.
func (a *Assembler) StoreNumber(registerNameTo string, offset byte, byteCount byte, number uint64) {
a.store(0xc7, 0xc6, registerNameTo, offset, byteCount, "")
// Number
switch byteCount {
case 8, 4:
a.WriteUint32(uint32(number))
case 2:
a.WriteUint16(uint16(number))
case 1:
a.WriteBytes(byte(number))
}
}
// StoreRegister stores the contents of a register into the memory address included in the given register.
func (a *Assembler) StoreRegister(registerNameTo string, offset byte, byteCount byte, registerNameFrom string) {
a.store(0x89, 0x88, registerNameTo, offset, byteCount, registerNameFrom)
}
// store is the core function for memory store instructions.
func (a *Assembler) store(baseCode byte, oneByteCode byte, registerNameTo string, offset byte, byteCount byte, registerNameFrom string) {
registerTo, exists := registers[registerNameTo]
if !exists {
log.Fatal("Unknown register name: " + registerNameTo)
}
registerFrom := registers[registerNameFrom]
if registerFrom != nil && registerFrom.MustHaveREX {
a.WriteBytes(0x40)
}
switch byteCount {
case 2:
a.WriteBytes(0x66)
case 1:
baseCode = oneByteCode
}
// REX prefix
w := byte(0) // Indicates a 64-bit register.
r := byte(0) // Extension to the "reg" field in ModRM.
x := byte(0) // Extension to the SIB index field.
b := byte(0) // Extension to the "rm" field in ModRM or the SIB base (r8 up to r15 use this).
if byteCount == 8 {
w = 1
}
if registerFrom != nil && registerFrom.BaseCodeOffset >= 8 {
r = 1
}
if registerTo.BaseCodeOffset >= 8 {
b = 1
}
if w != 0 || b != 0 || x != 0 || registerTo.MustHaveREX {
a.WriteBytes(opcode.REX(w, r, x, b))
}
// Base code
a.WriteBytes(baseCode)
// ModRM
hasOffset := offset != 0
// rbp and r13 always have an offset
if registerNameTo == "rbp" || registerNameTo == "r13" {
hasOffset = true
}
reg := byte(0)
if registerFrom != nil {
reg = registerFrom.BaseCodeOffset % 8
}
if hasOffset {
a.WriteBytes(opcode.ModRM(0b01, reg, registerTo.BaseCodeOffset%8))
} else {
a.WriteBytes(opcode.ModRM(0b00, reg, registerTo.BaseCodeOffset%8))
}
// rsp and r12 always need an SIB byte
if registerNameTo == "rsp" || registerNameTo == "r12" {
a.WriteBytes(opcode.SIB(0b00, 0b100, 0b100))
}
if hasOffset {
a.WriteBytes(offset)
}
}