|
danderson@3977
|
1 |
/** |
|
danderson@3977
|
2 |
* vim: set ts=8 sts=2 sw=2 tw=99 et: |
|
danderson@3977
|
3 |
* ============================================================================= |
|
danderson@3977
|
4 |
* SourcePawn JIT SDK |
|
danderson@3977
|
5 |
* Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. |
|
danderson@3977
|
6 |
* ============================================================================= |
|
danderson@3977
|
7 |
* |
|
danderson@3977
|
8 |
* This program is free software; you can redistribute it and/or modify it under |
|
danderson@3977
|
9 |
* the terms of the GNU General Public License, version 3.0, as published by the |
|
danderson@3977
|
10 |
* Free Software Foundation. |
|
danderson@3977
|
11 |
* |
|
danderson@3977
|
12 |
* This program is distributed in the hope that it will be useful, but WITHOUT |
|
danderson@3977
|
13 |
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
|
danderson@3977
|
14 |
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more |
|
danderson@3977
|
15 |
* details. |
|
danderson@3977
|
16 |
* |
|
danderson@3977
|
17 |
* You should have received a copy of the GNU General Public License along with |
|
danderson@3977
|
18 |
* this program. If not, see <http://www.gnu.org/licenses/>. |
|
danderson@3977
|
19 |
* |
|
danderson@3977
|
20 |
* As a special exception, AlliedModders LLC gives you permission to link the |
|
danderson@3977
|
21 |
* code of this program (as well as its derivative works) to "Half-Life 2," the |
|
danderson@3977
|
22 |
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software |
|
danderson@3977
|
23 |
* by the Valve Corporation. You must obey the GNU General Public License in |
|
danderson@3977
|
24 |
* all respects for all other code used. Additionally, AlliedModders LLC grants |
|
danderson@3977
|
25 |
* this exception to all derivative works. AlliedModders LLC defines further |
|
danderson@3977
|
26 |
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), |
|
danderson@3977
|
27 |
* or <http://www.sourcemod.net/license.php>. |
|
danderson@3977
|
28 |
* |
|
danderson@3977
|
29 |
* Version: $Id$ |
|
danderson@3977
|
30 |
*/ |
|
danderson@3977
|
31 |
#ifndef _include_sourcepawn_assembler_x86_h__ |
|
danderson@3977
|
32 |
#define _include_sourcepawn_assembler_x86_h__ |
|
danderson@3977
|
33 |
|
|
danderson@3977
|
34 |
#include <assembler.h> |
|
danderson@3977
|
35 |
#include <ke_vector.h> |
|
danderson@3977
|
36 |
#include <string.h> |
|
danderson@3977
|
37 |
|
|
danderson@3977
|
38 |
struct Register |
|
danderson@3977
|
39 |
{ |
|
danderson@3977
|
40 |
const char *name() const { |
|
danderson@3977
|
41 |
static const char *names[] = { |
|
danderson@3977
|
42 |
"eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi" |
|
danderson@3977
|
43 |
}; |
|
danderson@3977
|
44 |
return names[code]; |
|
danderson@3977
|
45 |
} |
|
danderson@3977
|
46 |
|
|
danderson@3977
|
47 |
int code; |
|
danderson@3977
|
48 |
|
|
danderson@3977
|
49 |
bool operator == (const Register &other) const { |
|
danderson@3977
|
50 |
return code == other.code; |
|
danderson@3977
|
51 |
} |
|
danderson@3977
|
52 |
bool operator != (const Register &other) const { |
|
danderson@3977
|
53 |
return code != other.code; |
|
danderson@3977
|
54 |
} |
|
danderson@3977
|
55 |
}; |
|
danderson@3977
|
56 |
|
|
danderson@3977
|
57 |
// X86 has an ancient FPU (called x87) which has a stack of registers |
|
danderson@3977
|
58 |
// numbered st0 through st7. |
|
danderson@3977
|
59 |
struct FpuRegister |
|
danderson@3977
|
60 |
{ |
|
danderson@3977
|
61 |
const char *name() const { |
|
danderson@3977
|
62 |
static const char *names[] = { |
|
danderson@3977
|
63 |
"st0", "st1", "st2", "st3", "st4", "st5", "st6", "st7" |
|
danderson@3977
|
64 |
}; |
|
danderson@3977
|
65 |
return names[code]; |
|
danderson@3977
|
66 |
} |
|
danderson@3977
|
67 |
|
|
danderson@3977
|
68 |
int code; |
|
danderson@3977
|
69 |
|
|
danderson@3977
|
70 |
bool operator == (const FpuRegister &other) const { |
|
danderson@3977
|
71 |
return code == other.code; |
|
danderson@3977
|
72 |
} |
|
danderson@3977
|
73 |
bool operator != (const FpuRegister &other) const { |
|
danderson@3977
|
74 |
return code != other.code; |
|
danderson@3977
|
75 |
} |
|
danderson@3977
|
76 |
}; |
|
danderson@3977
|
77 |
|
|
danderson@3977
|
78 |
struct FloatRegister |
|
danderson@3977
|
79 |
{ |
|
danderson@3977
|
80 |
const char *name() const { |
|
danderson@3977
|
81 |
static const char *names[] = { |
|
danderson@3977
|
82 |
"xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7" |
|
danderson@3977
|
83 |
}; |
|
danderson@3977
|
84 |
return names[code]; |
|
danderson@3977
|
85 |
} |
|
danderson@3977
|
86 |
|
|
danderson@3977
|
87 |
int code; |
|
danderson@3977
|
88 |
|
|
danderson@3977
|
89 |
bool operator == (const FloatRegister &other) const { |
|
danderson@3977
|
90 |
return code == other.code; |
|
danderson@3977
|
91 |
} |
|
danderson@3977
|
92 |
bool operator != (const FloatRegister &other) const { |
|
danderson@3977
|
93 |
return code != other.code; |
|
danderson@3977
|
94 |
} |
|
danderson@3977
|
95 |
}; |
|
danderson@3977
|
96 |
|
|
danderson@3977
|
97 |
const Register eax = { 0 }; |
|
danderson@3977
|
98 |
const Register ecx = { 1 }; |
|
danderson@3977
|
99 |
const Register edx = { 2 }; |
|
danderson@3977
|
100 |
const Register ebx = { 3 }; |
|
danderson@3977
|
101 |
const Register esp = { 4 }; |
|
danderson@3977
|
102 |
const Register ebp = { 5 }; |
|
danderson@3977
|
103 |
const Register esi = { 6 }; |
|
danderson@3977
|
104 |
const Register edi = { 7 }; |
|
danderson@3977
|
105 |
|
|
danderson@3977
|
106 |
const Register r8_al = { 0 }; |
|
danderson@3977
|
107 |
const Register r8_cl = { 1 }; |
|
danderson@3977
|
108 |
const Register r8_dl = { 2 }; |
|
danderson@3977
|
109 |
const Register r8_bl = { 3 }; |
|
danderson@3977
|
110 |
const Register r8_ah = { 4 }; |
|
danderson@3977
|
111 |
const Register r8_ch = { 5 }; |
|
danderson@3977
|
112 |
const Register r8_dh = { 6 }; |
|
danderson@3977
|
113 |
const Register r8_bh = { 7 }; |
|
danderson@3977
|
114 |
|
|
danderson@3977
|
115 |
const FpuRegister st0 = { 0 }; |
|
danderson@3977
|
116 |
const FpuRegister st1 = { 1 }; |
|
danderson@3977
|
117 |
const FpuRegister st2 = { 2 }; |
|
danderson@3977
|
118 |
const FpuRegister st3 = { 3 }; |
|
danderson@3977
|
119 |
const FpuRegister st4 = { 4 }; |
|
danderson@3977
|
120 |
const FpuRegister st5 = { 5 }; |
|
danderson@3977
|
121 |
const FpuRegister st6 = { 6 }; |
|
danderson@3977
|
122 |
const FpuRegister st7 = { 7 }; |
|
danderson@3977
|
123 |
|
|
danderson@3977
|
124 |
const FloatRegister xmm0 = { 0 }; |
|
danderson@3977
|
125 |
const FloatRegister xmm1 = { 1 }; |
|
danderson@3977
|
126 |
const FloatRegister xmm2 = { 2 }; |
|
danderson@3977
|
127 |
const FloatRegister xmm3 = { 3 }; |
|
danderson@3977
|
128 |
const FloatRegister xmm4 = { 4 }; |
|
danderson@3977
|
129 |
const FloatRegister xmm5 = { 5 }; |
|
danderson@3977
|
130 |
const FloatRegister xmm6 = { 6 }; |
|
danderson@3977
|
131 |
const FloatRegister xmm7 = { 7 }; |
|
danderson@3977
|
132 |
|
|
danderson@3977
|
133 |
static const uint8_t kModeDisp0 = 0; |
|
danderson@3977
|
134 |
static const uint8_t kModeDisp8 = 1; |
|
danderson@3977
|
135 |
static const uint8_t kModeDisp32 = 2; |
|
danderson@3977
|
136 |
static const uint8_t kModeReg = 3; |
|
danderson@3977
|
137 |
static const uint8_t kNoIndex = 4; |
|
danderson@3977
|
138 |
static const uint8_t kSIB = 4; |
|
danderson@3977
|
139 |
static const uint8_t kRIP = 5; |
|
danderson@3977
|
140 |
|
|
danderson@3977
|
141 |
enum ConditionCode { |
|
danderson@3977
|
142 |
overflow, |
|
danderson@3977
|
143 |
no_overflow, |
|
danderson@3977
|
144 |
below, |
|
danderson@3977
|
145 |
not_below, |
|
danderson@3977
|
146 |
equal, |
|
danderson@3977
|
147 |
not_equal, |
|
danderson@3977
|
148 |
not_above, |
|
danderson@3977
|
149 |
above, |
|
danderson@3977
|
150 |
negative, |
|
danderson@3977
|
151 |
not_negative, |
|
danderson@3977
|
152 |
even_parity, |
|
danderson@3977
|
153 |
odd_parity, |
|
danderson@3977
|
154 |
less, |
|
danderson@3977
|
155 |
not_less, |
|
danderson@3977
|
156 |
not_greater, |
|
danderson@3977
|
157 |
greater, |
|
danderson@3977
|
158 |
|
|
danderson@3977
|
159 |
zero = equal, |
|
danderson@3977
|
160 |
not_zero = not_equal, |
|
danderson@3977
|
161 |
less_equal = not_greater, |
|
danderson@3977
|
162 |
greater_equal = not_less |
|
danderson@3977
|
163 |
}; |
|
danderson@3977
|
164 |
|
|
danderson@3977
|
165 |
enum Scale { |
|
danderson@3977
|
166 |
NoScale, |
|
danderson@3977
|
167 |
ScaleTwo, |
|
danderson@3977
|
168 |
ScaleFour, |
|
danderson@3977
|
169 |
ScaleEight, |
|
danderson@3977
|
170 |
ScalePointer = ScaleFour |
|
danderson@3977
|
171 |
}; |
|
danderson@3977
|
172 |
|
|
danderson@3977
|
173 |
struct Operand |
|
danderson@3977
|
174 |
{ |
|
danderson@3977
|
175 |
friend class AssemblerX86; |
|
danderson@3977
|
176 |
|
|
danderson@3977
|
177 |
public: |
|
danderson@3977
|
178 |
Operand(Register reg, int32_t disp) { |
|
danderson@3977
|
179 |
if (reg == esp) { |
|
danderson@3977
|
180 |
// If the reg is esp, we need a SIB encoding. |
|
danderson@3977
|
181 |
if (disp == 0) |
|
danderson@3977
|
182 |
sib_disp0(NoScale, kNoIndex, reg.code); |
|
danderson@3977
|
183 |
else if (disp >= SCHAR_MIN && disp <= SCHAR_MAX) |
|
danderson@3977
|
184 |
sib_disp8(NoScale, kNoIndex, reg.code, disp); |
|
danderson@3977
|
185 |
else |
|
danderson@3977
|
186 |
sib_disp32(NoScale, kNoIndex, reg.code, disp); |
|
danderson@3977
|
187 |
} else if (disp == 0 && reg != ebp) { |
|
danderson@3977
|
188 |
// note, [ebp+0] is disp32/rip |
|
danderson@3977
|
189 |
modrm_disp0(reg.code); |
|
danderson@3977
|
190 |
} else if (disp >= SCHAR_MIN && disp <= SCHAR_MAX) { |
|
danderson@3977
|
191 |
modrm_disp8(reg.code, disp); |
|
danderson@3977
|
192 |
} else { |
|
danderson@3977
|
193 |
modrm_disp32(reg.code, disp); |
|
danderson@3977
|
194 |
} |
|
danderson@3977
|
195 |
} |
|
danderson@3977
|
196 |
|
|
danderson@3977
|
197 |
Operand(Register base, Scale scale, int32_t disp = 0) { |
|
danderson@3977
|
198 |
if (disp == 0 && base != ebp) |
|
danderson@3977
|
199 |
sib_disp0(scale, kNoIndex, base.code); |
|
danderson@3977
|
200 |
else if (disp >= SCHAR_MIN && disp <= SCHAR_MAX) |
|
danderson@3977
|
201 |
sib_disp8(scale, kNoIndex, base.code, disp); |
|
danderson@3977
|
202 |
else |
|
danderson@3977
|
203 |
sib_disp32(scale, kNoIndex, base.code, disp); |
|
danderson@3977
|
204 |
} |
|
danderson@3977
|
205 |
|
|
danderson@3977
|
206 |
Operand(Register base, Register index, Scale scale, int32_t disp = 0) { |
|
danderson@3977
|
207 |
assert(index.code != kNoIndex); |
|
danderson@3977
|
208 |
if (disp == 0 && base != ebp) |
|
danderson@3977
|
209 |
sib_disp0(scale, index.code, base.code); |
|
danderson@3977
|
210 |
else if (disp >= SCHAR_MIN && disp <= SCHAR_MAX) |
|
danderson@3977
|
211 |
sib_disp8(scale, index.code, base.code, disp); |
|
danderson@3977
|
212 |
else |
|
danderson@3977
|
213 |
sib_disp32(scale, index.code, base.code, disp); |
|
danderson@3977
|
214 |
} |
|
danderson@3977
|
215 |
|
|
danderson@3977
|
216 |
explicit Operand(ExternalAddress address) { |
|
danderson@3977
|
217 |
modrm(kModeDisp0, kRIP); |
|
danderson@3977
|
218 |
*reinterpret_cast<const void **>(bytes_ + 1) = address.address(); |
|
danderson@3977
|
219 |
} |
|
danderson@3977
|
220 |
|
|
danderson@3977
|
221 |
bool isRegister() const { |
|
danderson@3977
|
222 |
return mode() == kModeReg; |
|
danderson@3977
|
223 |
} |
|
danderson@3977
|
224 |
bool isRegister(Register r) const { |
|
danderson@3977
|
225 |
return mode() == kModeReg && rm() == r.code; |
|
danderson@3977
|
226 |
} |
|
danderson@3977
|
227 |
int registerCode() const { |
|
danderson@3977
|
228 |
return rm(); |
|
danderson@3977
|
229 |
} |
|
danderson@3977
|
230 |
|
|
danderson@3977
|
231 |
uint8_t getByte(size_t index) const { |
|
danderson@3977
|
232 |
assert(index < length()); |
|
danderson@3977
|
233 |
return bytes_[index]; |
|
danderson@3977
|
234 |
} |
|
danderson@3977
|
235 |
|
|
danderson@3977
|
236 |
size_t length() const { |
|
danderson@3977
|
237 |
if (mode() == kModeDisp0 && rm() == kRIP) |
|
danderson@3977
|
238 |
return 5; |
|
danderson@3977
|
239 |
size_t sib = (mode() != kModeReg && rm() == kSIB); |
|
danderson@3977
|
240 |
if (mode() == kModeDisp32) |
|
danderson@3977
|
241 |
return 5 + sib; |
|
danderson@3977
|
242 |
if (mode() == kModeDisp8) |
|
danderson@3977
|
243 |
return 2 + sib; |
|
danderson@3977
|
244 |
return 1 + sib; |
|
danderson@3977
|
245 |
} |
|
danderson@3977
|
246 |
|
|
danderson@3977
|
247 |
private: |
|
danderson@3977
|
248 |
explicit Operand(Register reg) { |
|
danderson@3977
|
249 |
modrm(kModeReg, reg.code); |
|
danderson@3977
|
250 |
} |
|
danderson@3977
|
251 |
|
|
danderson@3977
|
252 |
void modrm(uint8_t mode, uint8_t rm) { |
|
danderson@3977
|
253 |
assert(mode <= 3); |
|
danderson@3977
|
254 |
assert(rm <= 7); |
|
danderson@3977
|
255 |
bytes_[0] = (mode << 6) | rm; |
|
danderson@3977
|
256 |
} |
|
danderson@3977
|
257 |
void modrm_disp0(uint8_t rm) { |
|
danderson@3977
|
258 |
modrm(kModeDisp0, rm); |
|
danderson@3977
|
259 |
} |
|
danderson@3977
|
260 |
void modrm_disp8(uint8_t rm, int8_t disp) { |
|
danderson@3977
|
261 |
modrm(kModeDisp8, rm); |
|
danderson@3977
|
262 |
bytes_[1] = disp; |
|
danderson@3977
|
263 |
} |
|
danderson@3977
|
264 |
void modrm_disp32(uint8_t rm, int32_t disp) { |
|
danderson@3977
|
265 |
modrm(kModeDisp32, rm); |
|
danderson@3977
|
266 |
*reinterpret_cast<int32_t *>(bytes_ + 1) = disp; |
|
danderson@3977
|
267 |
} |
|
danderson@3977
|
268 |
void sib(uint8_t mode, Scale scale, uint8_t index, uint8_t base) { |
|
danderson@3977
|
269 |
modrm(mode, kSIB); |
|
danderson@3977
|
270 |
|
|
danderson@3977
|
271 |
assert(scale <= 3); |
|
danderson@3977
|
272 |
assert(index <= 7); |
|
danderson@3977
|
273 |
assert(base <= 7); |
|
danderson@3977
|
274 |
bytes_[1] = (uint8_t(scale) << 6) | (index << 3) | base; |
|
danderson@3977
|
275 |
} |
|
danderson@3977
|
276 |
void sib_disp0(Scale scale, uint8_t index, uint8_t base) { |
|
danderson@3977
|
277 |
sib(kModeDisp0, scale, index, base); |
|
danderson@3977
|
278 |
} |
|
danderson@3977
|
279 |
void sib_disp8(Scale scale, uint8_t index, uint8_t base, int8_t disp) { |
|
danderson@3977
|
280 |
sib(kModeDisp8, scale, index, base); |
|
danderson@3977
|
281 |
bytes_[2] = disp; |
|
danderson@3977
|
282 |
} |
|
danderson@3977
|
283 |
void sib_disp32(Scale scale, uint8_t index, uint8_t base, int32_t disp) { |
|
danderson@3977
|
284 |
sib(kModeDisp32, scale, index, base); |
|
danderson@3977
|
285 |
*reinterpret_cast<int32_t *>(bytes_ + 2) = disp; |
|
danderson@3977
|
286 |
} |
|
danderson@3977
|
287 |
|
|
danderson@3977
|
288 |
private: |
|
danderson@3977
|
289 |
uint8_t rm() const { |
|
danderson@3977
|
290 |
return bytes_[0] & 7; |
|
danderson@3977
|
291 |
} |
|
danderson@3977
|
292 |
uint8_t mode() const { |
|
danderson@3977
|
293 |
return bytes_[0] >> 6; |
|
danderson@3977
|
294 |
} |
|
danderson@3977
|
295 |
|
|
danderson@3977
|
296 |
private: |
|
danderson@3977
|
297 |
uint8_t bytes_[6]; |
|
danderson@3977
|
298 |
}; |
|
danderson@3977
|
299 |
|
|
danderson@3977
|
300 |
class AssemblerX86 : public Assembler |
|
danderson@3977
|
301 |
{ |
|
danderson@3977
|
302 |
public: |
|
danderson@3977
|
303 |
void movl(Register dest, Register src) { |
|
danderson@3977
|
304 |
emit1(0x89, src.code, dest.code); |
|
danderson@3977
|
305 |
} |
|
danderson@3977
|
306 |
void movl(Register dest, const Operand &src) { |
|
danderson@3977
|
307 |
emit1(0x8b, dest.code, src); |
|
danderson@3977
|
308 |
} |
|
danderson@3977
|
309 |
void movl(const Operand &dest, Register src) { |
|
danderson@3977
|
310 |
emit1(0x89, src.code, dest); |
|
danderson@3977
|
311 |
} |
|
danderson@3977
|
312 |
void movl(Register dest, int32_t imm) { |
|
danderson@3977
|
313 |
emit1(0xb8 + dest.code); |
|
danderson@3977
|
314 |
writeInt32(imm); |
|
danderson@3977
|
315 |
} |
|
danderson@3977
|
316 |
void movl(const Operand &dest, int32_t imm) { |
|
danderson@3977
|
317 |
if (dest.isRegister()) |
|
danderson@3977
|
318 |
emit1(0xb8 + dest.registerCode()); |
|
danderson@3977
|
319 |
else |
|
danderson@3977
|
320 |
emit1(0xc7, 0, dest); |
|
danderson@3977
|
321 |
writeInt32(imm); |
|
danderson@3977
|
322 |
} |
|
danderson@3977
|
323 |
void movw(const Operand &dest, Register src) { |
|
danderson@3977
|
324 |
emit1(0x89, src.code, dest); |
|
danderson@3977
|
325 |
} |
|
danderson@3977
|
326 |
void movw(Register dest, const Operand &src) { |
|
danderson@3977
|
327 |
emit1(0x8b, dest.code, src); |
|
danderson@3977
|
328 |
} |
|
danderson@3977
|
329 |
void movb(const Operand &dest, Register src) { |
|
danderson@3977
|
330 |
emit1(0x88, src.code, dest); |
|
danderson@3977
|
331 |
} |
|
danderson@3977
|
332 |
void movb(Register dest, const Operand &src) { |
|
danderson@3977
|
333 |
emit1(0x8a, dest.code, src); |
|
danderson@3977
|
334 |
} |
|
danderson@3977
|
335 |
void movzxb(Register dest, const Operand &src) { |
|
danderson@3977
|
336 |
emit2(0x0f, 0xb6, dest.code, src); |
|
danderson@3977
|
337 |
} |
|
danderson@3977
|
338 |
void movzxb(Register dest, const Register src) { |
|
danderson@3977
|
339 |
emit2(0x0f, 0xb6, dest.code, src.code); |
|
danderson@3977
|
340 |
} |
|
danderson@3977
|
341 |
void movzxw(Register dest, const Operand &src) { |
|
danderson@3977
|
342 |
emit2(0x0f, 0xb7, dest.code, src); |
|
danderson@3977
|
343 |
} |
|
danderson@3977
|
344 |
void movzxw(Register dest, const Register src) { |
|
danderson@3977
|
345 |
emit2(0x0f, 0xb7, dest.code, src.code); |
|
danderson@3977
|
346 |
} |
|
danderson@3977
|
347 |
|
|
danderson@3977
|
348 |
void lea(Register dest, const Operand &src) { |
|
danderson@3977
|
349 |
emit1(0x8d, dest.code, src); |
|
danderson@3977
|
350 |
} |
|
danderson@3977
|
351 |
|
|
danderson@3977
|
352 |
void xchgl(Register dest, Register src) { |
|
danderson@3977
|
353 |
if (src == eax) |
|
danderson@3977
|
354 |
emit1(0x90 + dest.code); |
|
danderson@3977
|
355 |
else if (dest == eax) |
|
danderson@3977
|
356 |
emit1(0x90 + src.code); |
|
danderson@3977
|
357 |
else |
|
danderson@3977
|
358 |
emit1(0x87, src.code, dest.code); |
|
danderson@3977
|
359 |
} |
|
danderson@3977
|
360 |
|
|
danderson@3977
|
361 |
void shll_cl(Register dest) { |
|
danderson@3977
|
362 |
shift_cl(dest.code, 4); |
|
danderson@3977
|
363 |
} |
|
danderson@3977
|
364 |
void shll(Register dest, uint8_t imm) { |
|
danderson@3977
|
365 |
shift_imm(dest.code, 4, imm); |
|
danderson@3977
|
366 |
} |
|
danderson@3977
|
367 |
void shll(const Operand &dest, uint8_t imm) { |
|
danderson@3977
|
368 |
shift_imm(dest, 4, imm); |
|
danderson@3977
|
369 |
} |
|
danderson@3977
|
370 |
void shrl_cl(Register dest) { |
|
danderson@3977
|
371 |
shift_cl(dest.code, 5); |
|
danderson@3977
|
372 |
} |
|
danderson@3977
|
373 |
void shrl(Register dest, uint8_t imm) { |
|
danderson@3977
|
374 |
shift_imm(dest.code, 5, imm); |
|
danderson@3977
|
375 |
} |
|
danderson@3977
|
376 |
void shrl(const Operand &dest, uint8_t imm) { |
|
danderson@3977
|
377 |
shift_imm(dest, 5, imm); |
|
danderson@3977
|
378 |
} |
|
danderson@3977
|
379 |
void sarl_cl(Register dest) { |
|
danderson@3977
|
380 |
shift_cl(dest.code, 7); |
|
danderson@3977
|
381 |
} |
|
danderson@3977
|
382 |
void sarl(Register dest, uint8_t imm) { |
|
danderson@3977
|
383 |
shift_imm(dest.code, 7, imm); |
|
danderson@3977
|
384 |
} |
|
danderson@3977
|
385 |
void sarl(const Operand &dest, uint8_t imm) { |
|
danderson@3977
|
386 |
shift_imm(dest, 7, imm); |
|
danderson@3977
|
387 |
} |
|
danderson@3977
|
388 |
|
|
danderson@3977
|
389 |
void cmpl(Register left, int32_t imm) { |
|
danderson@3977
|
390 |
alu_imm(7, imm, Operand(left)); |
|
danderson@3977
|
391 |
} |
|
danderson@3977
|
392 |
void cmpl(const Operand &left, int32_t imm) { |
|
danderson@3977
|
393 |
alu_imm(7, imm, left); |
|
danderson@3977
|
394 |
} |
|
danderson@3977
|
395 |
void cmpl(Register left, Register right) { |
|
danderson@3977
|
396 |
emit1(0x39, right.code, left.code); |
|
danderson@3977
|
397 |
} |
|
danderson@3977
|
398 |
void cmpl(const Operand &left, Register right) { |
|
danderson@3977
|
399 |
emit1(0x39, right.code, left); |
|
danderson@3977
|
400 |
} |
|
danderson@3977
|
401 |
void cmpl(Register left, const Operand &right) { |
|
danderson@3977
|
402 |
emit1(0x3b, left.code, right); |
|
danderson@3977
|
403 |
} |
|
danderson@3977
|
404 |
void andl(Register dest, int32_t imm) { |
|
danderson@3977
|
405 |
alu_imm(4, imm, Operand(dest)); |
|
danderson@3977
|
406 |
} |
|
danderson@3977
|
407 |
void andl(const Operand &dest, int32_t imm) { |
|
danderson@3977
|
408 |
alu_imm(4, imm, dest); |
|
danderson@3977
|
409 |
} |
|
danderson@3977
|
410 |
void andl(Register dest, Register src) { |
|
danderson@3977
|
411 |
emit1(0x21, src.code, dest.code); |
|
danderson@3977
|
412 |
} |
|
danderson@3977
|
413 |
void andl(const Operand &dest, Register src) { |
|
danderson@3977
|
414 |
emit1(0x21, src.code, dest); |
|
danderson@3977
|
415 |
} |
|
danderson@3977
|
416 |
void andl(Register dest, const Operand &src) { |
|
danderson@3977
|
417 |
emit1(0x23, dest.code, src); |
|
danderson@3977
|
418 |
} |
|
danderson@3977
|
419 |
void orl(Register dest, Register src) { |
|
danderson@3977
|
420 |
emit1(0x09, src.code, dest.code); |
|
danderson@3977
|
421 |
} |
|
danderson@3977
|
422 |
void orl(const Operand &dest, Register src) { |
|
danderson@3977
|
423 |
emit1(0x09, src.code, dest); |
|
danderson@3977
|
424 |
} |
|
danderson@3977
|
425 |
void orl(Register dest, const Operand &src) { |
|
danderson@3977
|
426 |
emit1(0x0b, dest.code, src); |
|
danderson@3977
|
427 |
} |
|
danderson@3977
|
428 |
void xorl(Register dest, Register src) { |
|
danderson@3977
|
429 |
emit1(0x31, src.code, dest.code); |
|
danderson@3977
|
430 |
} |
|
danderson@3977
|
431 |
void xorl(const Operand &dest, Register src) { |
|
danderson@3977
|
432 |
emit1(0x31, src.code, dest); |
|
danderson@3977
|
433 |
} |
|
danderson@3977
|
434 |
void xorl(Register dest, const Operand &src) { |
|
danderson@3977
|
435 |
emit1(0x33, dest.code, src); |
|
danderson@3977
|
436 |
} |
|
danderson@3977
|
437 |
|
|
danderson@3977
|
438 |
void subl(Register dest, Register src) { |
|
danderson@3977
|
439 |
emit1(0x29, src.code, dest.code); |
|
danderson@3977
|
440 |
} |
|
danderson@3977
|
441 |
void subl(const Operand &dest, Register src) { |
|
danderson@3977
|
442 |
emit1(0x29, src.code, dest); |
|
danderson@3977
|
443 |
} |
|
danderson@3977
|
444 |
void subl(Register dest, const Operand &src) { |
|
danderson@3977
|
445 |
emit1(0x2b, dest.code, src); |
|
danderson@3977
|
446 |
} |
|
danderson@3977
|
447 |
void subl(Register dest, int32_t imm) { |
|
danderson@3977
|
448 |
alu_imm(5, imm, Operand(dest)); |
|
danderson@3977
|
449 |
} |
|
danderson@3977
|
450 |
void subl(const Operand &dest, int32_t imm) { |
|
danderson@3977
|
451 |
alu_imm(5, imm, dest); |
|
danderson@3977
|
452 |
} |
|
danderson@3977
|
453 |
void addl(Register dest, Register src) { |
|
danderson@3977
|
454 |
emit1(0x01, src.code, dest.code); |
|
danderson@3977
|
455 |
} |
|
danderson@3977
|
456 |
void addl(const Operand &dest, Register src) { |
|
danderson@3977
|
457 |
emit1(0x01, src.code, dest); |
|
danderson@3977
|
458 |
} |
|
danderson@3977
|
459 |
void addl(Register dest, const Operand &src) { |
|
danderson@3977
|
460 |
emit1(0x03, dest.code, src); |
|
danderson@3977
|
461 |
} |
|
danderson@3977
|
462 |
void addl(Register dest, int32_t imm) { |
|
danderson@3977
|
463 |
alu_imm(0, imm, Operand(dest)); |
|
danderson@3977
|
464 |
} |
|
danderson@3977
|
465 |
void addl(const Operand &dest, int32_t imm) { |
|
danderson@3977
|
466 |
alu_imm(0, imm, dest); |
|
danderson@3977
|
467 |
} |
|
danderson@3977
|
468 |
|
|
danderson@3977
|
469 |
void imull(Register dest, const Operand &src) { |
|
danderson@3977
|
470 |
emit2(0x0f, 0xaf, dest.code, src); |
|
danderson@3977
|
471 |
} |
|
danderson@3977
|
472 |
void imull(Register dest, Register src) { |
|
danderson@3977
|
473 |
emit2(0x0f, 0xaf, dest.code, src.code); |
|
danderson@3977
|
474 |
} |
|
danderson@3977
|
475 |
void imull(Register dest, const Operand &src, int32_t imm) { |
|
danderson@3977
|
476 |
if (imm >= SCHAR_MIN && imm <= SCHAR_MAX) { |
|
danderson@3977
|
477 |
emit1(0x6b, dest.code, src); |
|
danderson@3977
|
478 |
*pos_++ = imm; |
|
danderson@3977
|
479 |
} else { |
|
danderson@3977
|
480 |
emit1(0x69, dest.code, src); |
|
danderson@3977
|
481 |
writeInt32(imm); |
|
danderson@3977
|
482 |
} |
|
danderson@3977
|
483 |
} |
|
danderson@3977
|
484 |
void imull(Register dest, Register src, int32_t imm) { |
|
danderson@3977
|
485 |
imull(dest, Operand(src), imm); |
|
danderson@3977
|
486 |
} |
|
danderson@3977
|
487 |
|
|
danderson@3977
|
488 |
void testl(const Operand &op1, Register op2) { |
|
danderson@3977
|
489 |
emit1(0x85, op2.code, op1); |
|
danderson@3977
|
490 |
} |
|
danderson@3977
|
491 |
void testl(Register op1, Register op2) { |
|
danderson@3977
|
492 |
emit1(0x85, op2.code, op1.code); |
|
danderson@3977
|
493 |
} |
|
danderson@3977
|
494 |
void set(ConditionCode cc, const Operand &dest) { |
|
danderson@3977
|
495 |
emit2(0x0f, 0x90 + uint8_t(cc), 0, dest); |
|
danderson@3977
|
496 |
} |
|
danderson@3977
|
497 |
void set(ConditionCode cc, Register dest) { |
|
danderson@3977
|
498 |
emit2(0x0f, 0x90 + uint8_t(cc), 0, dest.code); |
|
danderson@3977
|
499 |
} |
|
danderson@3977
|
500 |
void negl(Register srcdest) { |
|
danderson@3977
|
501 |
emit1(0xf7, 3, srcdest.code); |
|
danderson@3977
|
502 |
} |
|
danderson@3977
|
503 |
void negl(const Operand &srcdest) { |
|
danderson@3977
|
504 |
emit1(0xf7, 3, srcdest); |
|
danderson@3977
|
505 |
} |
|
danderson@3977
|
506 |
void notl(Register srcdest) { |
|
danderson@3977
|
507 |
emit1(0xf7, 2, srcdest.code); |
|
danderson@3977
|
508 |
} |
|
danderson@3977
|
509 |
void notl(const Operand &srcdest) { |
|
danderson@3977
|
510 |
emit1(0xf7, 2, srcdest); |
|
danderson@3977
|
511 |
} |
|
danderson@3977
|
512 |
void idivl(Register dividend) { |
|
danderson@3977
|
513 |
emit1(0xf7, 7, dividend.code); |
|
danderson@3977
|
514 |
} |
|
danderson@3977
|
515 |
void idivl(const Operand ÷nd) { |
|
danderson@3977
|
516 |
emit1(0xf7, 7, dividend); |
|
danderson@3977
|
517 |
} |
|
danderson@3977
|
518 |
|
|
danderson@3977
|
519 |
void ret() { |
|
danderson@3977
|
520 |
emit1(0xc3); |
|
danderson@3977
|
521 |
} |
|
danderson@3977
|
522 |
void cld() { |
|
danderson@3977
|
523 |
emit1(0xfc); |
|
danderson@3977
|
524 |
} |
|
danderson@3977
|
525 |
void push(Register reg) { |
|
danderson@3977
|
526 |
emit1(0x50 + reg.code); |
|
danderson@3977
|
527 |
} |
|
danderson@3977
|
528 |
void push(const Operand &src) { |
|
danderson@3977
|
529 |
if (src.isRegister()) |
|
danderson@3977
|
530 |
emit1(0x50 + src.registerCode()); |
|
danderson@3977
|
531 |
else |
|
danderson@3977
|
532 |
emit1(0xff, 6, src); |
|
danderson@3977
|
533 |
} |
|
danderson@3977
|
534 |
void push(int32_t imm) { |
|
danderson@3977
|
535 |
emit1(0x68); |
|
danderson@3977
|
536 |
writeInt32(imm); |
|
danderson@3977
|
537 |
} |
|
danderson@3977
|
538 |
void pop(Register reg) { |
|
danderson@3977
|
539 |
emit1(0x58 + reg.code); |
|
danderson@3977
|
540 |
} |
|
danderson@3977
|
541 |
void pop(const Operand &src) { |
|
danderson@3977
|
542 |
if (src.isRegister()) |
|
danderson@3977
|
543 |
emit1(0x58 + src.registerCode()); |
|
danderson@3977
|
544 |
else |
|
danderson@3977
|
545 |
emit1(0x8f, 0, src); |
|
danderson@3977
|
546 |
} |
|
danderson@3977
|
547 |
|
|
danderson@3977
|
548 |
void rep_movsb() { |
|
danderson@3977
|
549 |
emit2(0xf3, 0xa4); |
|
danderson@3977
|
550 |
} |
|
danderson@3977
|
551 |
void rep_movsd() { |
|
danderson@3977
|
552 |
emit2(0xf3, 0xa5); |
|
danderson@3977
|
553 |
} |
|
danderson@3977
|
554 |
void rep_stosd() { |
|
danderson@3977
|
555 |
emit2(0xf3, 0xab); |
|
danderson@3977
|
556 |
} |
|
danderson@3977
|
557 |
void breakpoint() { |
|
danderson@3977
|
558 |
emit1(0xcc); |
|
danderson@3977
|
559 |
} |
|
danderson@3977
|
560 |
|
|
danderson@3977
|
561 |
void fld32(const Operand &src) { |
|
danderson@3977
|
562 |
emit1(0xd9, 0, src); |
|
danderson@3977
|
563 |
} |
|
danderson@3977
|
564 |
void fild32(const Operand &src) { |
|
danderson@3977
|
565 |
emit1(0xdb, 0, src); |
|
danderson@3977
|
566 |
} |
|
danderson@3977
|
567 |
void fistp32(const Operand &dest) { |
|
danderson@3977
|
568 |
emit1(0xdb, 3, dest); |
|
danderson@3977
|
569 |
} |
|
danderson@3977
|
570 |
void fadd32(const Operand &src) { |
|
danderson@3977
|
571 |
emit1(0xd8, 0, src); |
|
danderson@3977
|
572 |
} |
|
danderson@3977
|
573 |
void fsub32(const Operand &src) { |
|
danderson@3977
|
574 |
emit1(0xd8, 4, src); |
|
danderson@3977
|
575 |
} |
|
danderson@3977
|
576 |
void fmul32(const Operand &src) { |
|
danderson@3977
|
577 |
emit1(0xd8, 1, src); |
|
danderson@3977
|
578 |
} |
|
danderson@3977
|
579 |
void fdiv32(const Operand &src) { |
|
danderson@3977
|
580 |
emit1(0xd8, 6, src); |
|
danderson@3977
|
581 |
} |
|
danderson@3977
|
582 |
void fstp32(const Operand &dest) { |
|
danderson@3977
|
583 |
emit1(0xd9, 3, dest); |
|
danderson@3977
|
584 |
} |
|
danderson@3977
|
585 |
void fstp(FpuRegister src) { |
|
danderson@3977
|
586 |
emit2(0xdd, 0xd8 + src.code); |
|
danderson@3977
|
587 |
} |
|
danderson@3977
|
588 |
void fldcw(const Operand &src) { |
|
danderson@3977
|
589 |
emit1(0xd9, 5, src); |
|
danderson@3977
|
590 |
} |
|
danderson@3977
|
591 |
void fstcw(const Operand &dest) { |
|
danderson@3977
|
592 |
emit2(0x9b, 0xd9, 7, dest); |
|
danderson@3977
|
593 |
} |
|
danderson@3977
|
594 |
void fsubr32(const Operand &src) { |
|
danderson@3977
|
595 |
emit1(0xd8, 5, src); |
|
danderson@3977
|
596 |
} |
|
danderson@3977
|
597 |
|
|
danderson@3977
|
598 |
// Compare st0 with stN. |
|
danderson@3977
|
599 |
void fucomip(FpuRegister other) { |
|
danderson@3977
|
600 |
emit2(0xdf, 0xe8 + other.code); |
|
danderson@3977
|
601 |
} |
|
danderson@3977
|
602 |
|
|
danderson@3977
|
603 |
// At least one argument of these forms must be st0. |
|
danderson@3977
|
604 |
void fadd32(FpuRegister dest, FpuRegister src) { |
|
danderson@3977
|
605 |
assert(dest == st0 || src == st0); |
|
danderson@3977
|
606 |
if (dest == st0) |
|
danderson@3977
|
607 |
emit2(0xd8, 0xc0 + dest.code); |
|
danderson@3977
|
608 |
else |
|
danderson@3977
|
609 |
emit2(0xdc, 0xc0 + src.code); |
|
danderson@3977
|
610 |
} |
|
danderson@3977
|
611 |
|
|
danderson@3977
|
612 |
void jmp(Label *dest) { |
|
danderson@3977
|
613 |
int8_t d8; |
|
danderson@3977
|
614 |
if (canEmitSmallJump(dest, &d8)) { |
|
danderson@3977
|
615 |
emit2(0xeb, d8); |
|
danderson@3977
|
616 |
} else { |
|
danderson@3977
|
617 |
emit1(0xe9); |
|
danderson@3977
|
618 |
emitJumpTarget(dest); |
|
danderson@3977
|
619 |
} |
|
danderson@3977
|
620 |
} |
|
danderson@3977
|
621 |
void jmp(Register target) { |
|
danderson@3977
|
622 |
emit1(0xff, 4, target.code); |
|
danderson@3977
|
623 |
} |
|
danderson@3977
|
624 |
void jmp(const Operand &target) { |
|
danderson@3977
|
625 |
emit1(0xff, 4, target); |
|
danderson@3977
|
626 |
} |
|
danderson@3977
|
627 |
void j(ConditionCode cc, Label *dest) { |
|
danderson@3977
|
628 |
int8_t d8; |
|
danderson@3977
|
629 |
if (canEmitSmallJump(dest, &d8)) { |
|
danderson@3977
|
630 |
emit2(0x70 + uint8_t(cc), d8); |
|
danderson@3977
|
631 |
} else { |
|
danderson@3977
|
632 |
emit2(0x0f, 0x80 + uint8_t(cc)); |
|
danderson@3977
|
633 |
emitJumpTarget(dest); |
|
danderson@3977
|
634 |
} |
|
danderson@3977
|
635 |
} |
|
danderson@3977
|
636 |
void call(Label *dest) { |
|
danderson@3977
|
637 |
emit1(0xe8); |
|
danderson@3977
|
638 |
emitJumpTarget(dest); |
|
danderson@3977
|
639 |
} |
|
danderson@3977
|
640 |
void bind(Label *target) { |
|
danderson@3977
|
641 |
if (outOfMemory()) { |
|
danderson@3977
|
642 |
// If we ran out of memory, the code stream is potentially invalid and |
|
danderson@3977
|
643 |
// we cannot use the embedded linked list. |
|
danderson@3977
|
644 |
target->bind(pc()); |
|
danderson@3977
|
645 |
return; |
|
danderson@3977
|
646 |
} |
|
danderson@3977
|
647 |
|
|
danderson@3977
|
648 |
assert(!target->bound()); |
|
danderson@3977
|
649 |
uint32_t status = target->status(); |
|
danderson@3977
|
650 |
while (Label::More(status)) { |
|
danderson@3977
|
651 |
// Grab the offset. It should be at least a 1byte op + rel32. |
|
danderson@3977
|
652 |
uint32_t offset = Label::ToOffset(status); |
|
danderson@3977
|
653 |
assert(offset >= 5); |
|
danderson@3977
|
654 |
|
|
danderson@3977
|
655 |
// Grab the delta from target to pc. |
|
danderson@3977
|
656 |
ptrdiff_t delta = pos_ - (buffer() + offset); |
|
danderson@3977
|
657 |
assert(delta >= INT_MIN && delta <= INT_MAX); |
|
danderson@3977
|
658 |
|
|
danderson@3977
|
659 |
int32_t *p = reinterpret_cast<int32_t *>(buffer() + offset - 4); |
|
danderson@3977
|
660 |
status = *p; |
|
danderson@3977
|
661 |
*p = delta; |
|
danderson@3977
|
662 |
} |
|
danderson@3977
|
663 |
target->bind(pc()); |
|
danderson@3977
|
664 |
} |
|
danderson@3977
|
665 |
|
|
danderson@3977
|
666 |
void bind(DataLabel *address) { |
|
danderson@3977
|
667 |
if (outOfMemory()) |
|
danderson@3977
|
668 |
return; |
|
danderson@3977
|
669 |
if (address->used()) { |
|
danderson@3977
|
670 |
uint32_t offset = DataLabel::ToOffset(address->status()); |
|
danderson@3977
|
671 |
*reinterpret_cast<int32_t *>(buffer() + offset - 4) = position() - int32_t(offset); |
|
danderson@3977
|
672 |
} |
|
danderson@3977
|
673 |
address->bind(pc()); |
|
danderson@3977
|
674 |
} |
|
danderson@3977
|
675 |
void movl(Register dest, DataLabel *src) { |
|
danderson@3977
|
676 |
emit1(0xb8 + dest.code); |
|
danderson@3977
|
677 |
if (src->bound()) { |
|
danderson@3977
|
678 |
writeInt32(int32_t(src->offset()) - (position() + 4)); |
|
danderson@3977
|
679 |
} else { |
|
danderson@3977
|
680 |
writeInt32(0xabcdef0); |
|
danderson@3977
|
681 |
src->use(pc()); |
|
danderson@3977
|
682 |
} |
|
danderson@3977
|
683 |
if (!local_refs_.append(pc())) |
|
danderson@3977
|
684 |
outOfMemory_ = true; |
|
danderson@3977
|
685 |
} |
|
danderson@3977
|
686 |
void emit_absolute_address(Label *address) { |
|
danderson@3977
|
687 |
if (address->bound()) |
|
danderson@3977
|
688 |
writeUint32(int32_t(address->offset()) - (position() + 4)); |
|
danderson@3977
|
689 |
else |
|
danderson@3977
|
690 |
writeUint32(address->addPending(position() + 4)); |
|
danderson@3977
|
691 |
if (!local_refs_.append(pc())) |
|
danderson@3977
|
692 |
outOfMemory_ = true; |
|
danderson@3977
|
693 |
} |
|
danderson@3977
|
694 |
|
|
danderson@3977
|
695 |
void call(Register target) { |
|
danderson@3977
|
696 |
emit1(0xff, 2, target.code); |
|
danderson@3977
|
697 |
} |
|
danderson@3977
|
698 |
void call(const Operand &target) { |
|
danderson@3977
|
699 |
emit1(0xff, 2, target); |
|
danderson@3977
|
700 |
} |
|
danderson@3977
|
701 |
void call(ExternalAddress address) { |
|
danderson@3977
|
702 |
emit1(0xe8); |
|
danderson@3977
|
703 |
writeInt32(address.value()); |
|
danderson@3977
|
704 |
if (!external_refs_.append(pc())) |
|
danderson@3977
|
705 |
outOfMemory_ = true; |
|
danderson@3977
|
706 |
} |
|
danderson@3977
|
707 |
void jmp(ExternalAddress address) { |
|
danderson@3977
|
708 |
assert(sizeof(address) == sizeof(int32_t)); |
|
danderson@3977
|
709 |
emit1(0xe9); |
|
danderson@3977
|
710 |
writeInt32(address.value()); |
|
danderson@3977
|
711 |
if (!external_refs_.append(pc())) |
|
danderson@3977
|
712 |
outOfMemory_ = true; |
|
danderson@3977
|
713 |
} |
|
danderson@3977
|
714 |
|
|
danderson@3977
|
715 |
static void PatchRel32Absolute(uint8_t *ip, void *ptr) { |
|
danderson@3977
|
716 |
int32_t delta = uint32_t(ptr) - uint32_t(ip); |
|
danderson@3977
|
717 |
*reinterpret_cast<int32_t *>(ip - 4) = delta; |
|
danderson@3977
|
718 |
} |
|
danderson@3977
|
719 |
|
|
danderson@3977
|
720 |
void emitToExecutableMemory(void *code) { |
|
danderson@3977
|
721 |
assert(!outOfMemory()); |
|
danderson@3977
|
722 |
|
|
danderson@3977
|
723 |
// Relocate anything we emitted as rel32 with an external pointer. |
|
danderson@3977
|
724 |
uint8_t *base = reinterpret_cast<uint8_t *>(code); |
|
danderson@3977
|
725 |
memcpy(base, buffer(), length()); |
|
danderson@3977
|
726 |
for (size_t i = 0; i < external_refs_.length(); i++) { |
|
danderson@3977
|
727 |
size_t offset = external_refs_[i]; |
|
danderson@3977
|
728 |
PatchRel32Absolute(base + offset, *reinterpret_cast<void **>(base + offset - 4)); |
|
danderson@3977
|
729 |
} |
|
danderson@3977
|
730 |
|
|
danderson@3977
|
731 |
// Relocate everything we emitted as an abs32 with an internal offset. Note |
|
danderson@3977
|
732 |
// that in the code stream, we use relative offsets so we can use both Label |
|
danderson@3977
|
733 |
// and DataLabel. |
|
danderson@3977
|
734 |
for (size_t i = 0; i < local_refs_.length(); i++) { |
|
danderson@3977
|
735 |
size_t offset = local_refs_[i]; |
|
danderson@3977
|
736 |
int32_t delta = *reinterpret_cast<int32_t *>(base + offset - 4); |
|
danderson@3977
|
737 |
*reinterpret_cast<void **>(base + offset - 4) = base + offset + delta; |
|
danderson@3977
|
738 |
} |
|
danderson@3977
|
739 |
} |
|
danderson@3977
|
740 |
|
|
danderson@3977
|
741 |
void align(uint32_t bytes) { |
|
danderson@3977
|
742 |
int32_t delta = (pc() & ~(bytes - 1)) + bytes - pc(); |
|
danderson@3977
|
743 |
for (int32_t i = 0; i < delta; i++) |
|
danderson@3977
|
744 |
emit1(0xcc); |
|
danderson@3977
|
745 |
} |
|
danderson@3977
|
746 |
|
|
danderson@3977
|
747 |
private: |
|
danderson@3977
|
748 |
bool canEmitSmallJump(Label *dest, int8_t *deltap) { |
|
danderson@3977
|
749 |
if (!dest->bound()) |
|
danderson@3977
|
750 |
return false; |
|
danderson@3977
|
751 |
|
|
danderson@3977
|
752 |
// All small jumps are assumed to be 2 bytes. |
|
danderson@3977
|
753 |
ptrdiff_t delta = ptrdiff_t(dest->offset()) - (position() + 2); |
|
danderson@3977
|
754 |
if (delta < SCHAR_MIN || delta > SCHAR_MAX) |
|
danderson@3977
|
755 |
return false; |
|
danderson@3977
|
756 |
*deltap = delta; |
|
danderson@3977
|
757 |
return true; |
|
danderson@3977
|
758 |
} |
|
danderson@3977
|
759 |
void emitJumpTarget(Label *dest) { |
|
danderson@3977
|
760 |
if (dest->bound()) { |
|
danderson@3977
|
761 |
ptrdiff_t delta = ptrdiff_t(dest->offset()) - (position() + 4); |
|
danderson@3977
|
762 |
assert(delta >= INT_MIN && delta <= INT_MAX); |
|
danderson@3977
|
763 |
writeInt32(delta); |
|
danderson@3977
|
764 |
} else { |
|
danderson@3977
|
765 |
writeUint32(dest->addPending(position() + 4)); |
|
danderson@3977
|
766 |
} |
|
danderson@3977
|
767 |
} |
|
danderson@3977
|
768 |
|
|
danderson@3977
|
769 |
void emit(uint8_t reg, const Operand &operand) { |
|
danderson@3977
|
770 |
*pos_++ = operand.getByte(0) | (reg << 3); |
|
danderson@3977
|
771 |
size_t length = operand.length(); |
|
danderson@3977
|
772 |
for (size_t i = 1; i < length; i++) |
|
danderson@3977
|
773 |
*pos_++ = operand.getByte(i); |
|
danderson@3977
|
774 |
} |
|
danderson@3977
|
775 |
|
|
danderson@3977
|
776 |
void emit1(uint8_t opcode) { |
|
danderson@3977
|
777 |
ensureSpace(); |
|
danderson@3977
|
778 |
*pos_++ = opcode; |
|
danderson@3977
|
779 |
} |
|
danderson@3977
|
780 |
void emit1(uint8_t opcode, uint8_t reg, uint8_t opreg) { |
|
danderson@3977
|
781 |
ensureSpace(); |
|
danderson@3977
|
782 |
assert(reg <= 7); |
|
danderson@3977
|
783 |
assert(opreg <= 7); |
|
danderson@3977
|
784 |
*pos_++ = opcode; |
|
danderson@3977
|
785 |
*pos_++ = (kModeReg << 6) | (reg << 3) | opreg; |
|
danderson@3977
|
786 |
} |
|
danderson@3977
|
787 |
void emit1(uint8_t opcode, uint8_t reg, const Operand &operand) { |
|
danderson@3977
|
788 |
ensureSpace(); |
|
danderson@3977
|
789 |
assert(reg <= 7); |
|
danderson@3977
|
790 |
*pos_++ = opcode; |
|
danderson@3977
|
791 |
emit(reg, operand); |
|
danderson@3977
|
792 |
} |
|
danderson@3977
|
793 |
|
|
danderson@3977
|
794 |
void emit2(uint8_t prefix, uint8_t opcode) { |
|
danderson@3977
|
795 |
ensureSpace(); |
|
danderson@3977
|
796 |
*pos_++ = prefix; |
|
danderson@3977
|
797 |
*pos_++ = opcode; |
|
danderson@3977
|
798 |
} |
|
danderson@3977
|
799 |
void emit2(uint8_t prefix, uint8_t opcode, uint8_t reg, uint8_t opreg) { |
|
danderson@3977
|
800 |
emit2(prefix, opcode); |
|
danderson@3977
|
801 |
assert(reg <= 7); |
|
danderson@3977
|
802 |
*pos_++ = (kModeReg << 6) | (reg << 3) | opreg; |
|
danderson@3977
|
803 |
} |
|
danderson@3977
|
804 |
void emit2(uint8_t prefix, uint8_t opcode, uint8_t reg, const Operand &operand) { |
|
danderson@3977
|
805 |
emit2(prefix, opcode); |
|
danderson@3977
|
806 |
emit(reg, operand); |
|
danderson@3977
|
807 |
} |
|
danderson@3977
|
808 |
|
|
danderson@3977
|
809 |
template <typename T> |
|
danderson@3977
|
810 |
void shift_cl(const T &t, uint8_t r) { |
|
danderson@3977
|
811 |
emit1(0xd3, r, t); |
|
danderson@3977
|
812 |
} |
|
danderson@3977
|
813 |
|
|
danderson@3977
|
814 |
template <typename T> |
|
danderson@3977
|
815 |
void shift_imm(const T &t, uint8_t r, int32_t imm) { |
|
danderson@3977
|
816 |
if (imm == 1) { |
|
danderson@3977
|
817 |
emit1(0xd1, r, t); |
|
danderson@3977
|
818 |
} else { |
|
danderson@3977
|
819 |
emit1(0xc1, r, t); |
|
danderson@3977
|
820 |
*pos_++ = imm & 0x1F; |
|
danderson@3977
|
821 |
} |
|
danderson@3977
|
822 |
} |
|
danderson@3977
|
823 |
void alu_imm(uint8_t r, int32_t imm, const Operand &operand) { |
|
danderson@3977
|
824 |
if (imm >= SCHAR_MIN && imm <= SCHAR_MAX) { |
|
danderson@3977
|
825 |
emit1(0x83, r, operand); |
|
danderson@3977
|
826 |
*pos_++ = uint8_t(imm & 0xff); |
|
danderson@3977
|
827 |
} else if (operand.isRegister(eax)) { |
|
danderson@3977
|
828 |
emit1(0x05 | (r << 3)); |
|
danderson@3977
|
829 |
writeInt32(imm); |
|
danderson@3977
|
830 |
} else { |
|
danderson@3977
|
831 |
emit1(0x81, r, operand); |
|
danderson@3977
|
832 |
writeInt32(imm); |
|
danderson@3977
|
833 |
} |
|
danderson@3977
|
834 |
} |
|
danderson@3977
|
835 |
|
|
danderson@3977
|
836 |
private: |
|
danderson@3977
|
837 |
ke::Vector<uint32_t> external_refs_; |
|
danderson@3977
|
838 |
ke::Vector<uint32_t> local_refs_; |
|
danderson@3977
|
839 |
}; |
|
danderson@3977
|
840 |
|
|
danderson@3977
|
841 |
#endif // _include_sourcepawn_assembler_x86_h__ |
|
danderson@3977
|
842 |
|