PyNerva 0.0.7__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- nervapy/__init__.py +50 -0
- nervapy/abi.py +91 -0
- nervapy/arm/__init__.py +124 -0
- nervapy/arm/__main__.py +0 -0
- nervapy/arm/abi.py +138 -0
- nervapy/arm/formats.py +49 -0
- nervapy/arm/function.py +2465 -0
- nervapy/arm/generic.py +10796 -0
- nervapy/arm/instructions.py +519 -0
- nervapy/arm/isa.py +409 -0
- nervapy/arm/literal_pool.py +331 -0
- nervapy/arm/microarchitecture.py +211 -0
- nervapy/arm/pseudo.py +652 -0
- nervapy/arm/registers.py +1458 -0
- nervapy/arm/vfpneon.py +4092 -0
- nervapy/arm.py +13 -0
- nervapy/c/__init__.py +1 -0
- nervapy/c/types.py +436 -0
- nervapy/codegen.py +99 -0
- nervapy/common/__init__.py +4 -0
- nervapy/common/function.py +5 -0
- nervapy/common/regalloc.py +121 -0
- nervapy/constant_data.py +282 -0
- nervapy/encoder.py +246 -0
- nervapy/formats/__init__.py +2 -0
- nervapy/formats/elf/__init__.py +4 -0
- nervapy/formats/elf/file.py +178 -0
- nervapy/formats/elf/image.py +106 -0
- nervapy/formats/elf/section.py +422 -0
- nervapy/formats/elf/symbol.py +281 -0
- nervapy/formats/macho/__init__.py +2 -0
- nervapy/formats/macho/file.py +123 -0
- nervapy/formats/macho/image.py +143 -0
- nervapy/formats/macho/section.py +322 -0
- nervapy/formats/macho/symbol.py +158 -0
- nervapy/formats/mscoff/__init__.py +8 -0
- nervapy/formats/mscoff/image.py +132 -0
- nervapy/formats/mscoff/section.py +181 -0
- nervapy/formats/mscoff/symbol.py +148 -0
- nervapy/function.py +136 -0
- nervapy/literal.py +731 -0
- nervapy/loader.py +188 -0
- nervapy/name.py +159 -0
- nervapy/parse.py +52 -0
- nervapy/stream.py +58 -0
- nervapy/util.py +126 -0
- nervapy/writer.py +518 -0
- nervapy/x86_64/__init__.py +324 -0
- nervapy/x86_64/__main__.py +407 -0
- nervapy/x86_64/abi.py +517 -0
- nervapy/x86_64/amd.py +6464 -0
- nervapy/x86_64/avx.py +102029 -0
- nervapy/x86_64/crypto.py +1533 -0
- nervapy/x86_64/encoding.py +424 -0
- nervapy/x86_64/fma.py +19138 -0
- nervapy/x86_64/function.py +2707 -0
- nervapy/x86_64/generic.py +23384 -0
- nervapy/x86_64/instructions.py +500 -0
- nervapy/x86_64/isa.py +476 -0
- nervapy/x86_64/lower.py +126 -0
- nervapy/x86_64/mask.py +2593 -0
- nervapy/x86_64/meta.py +143 -0
- nervapy/x86_64/mmxsse.py +17265 -0
- nervapy/x86_64/nacl.py +327 -0
- nervapy/x86_64/operand.py +1204 -0
- nervapy/x86_64/options.py +21 -0
- nervapy/x86_64/pseudo.py +686 -0
- nervapy/x86_64/registers.py +1225 -0
- nervapy/x86_64/types.py +17 -0
- nervapy/x86_64/uarch.py +580 -0
- pynerva-0.0.7.dist-info/METADATA +310 -0
- pynerva-0.0.7.dist-info/RECORD +74 -0
- pynerva-0.0.7.dist-info/WHEEL +4 -0
- pynerva-0.0.7.dist-info/licenses/LICENSE.rst +15 -0
|
@@ -0,0 +1,500 @@
|
|
|
1
|
+
# This file is part of PeachPy package and is licensed under the Simplified BSD license.
|
|
2
|
+
# See license.rst for the full text of the license.
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class Instruction(object):
|
|
6
|
+
def __init__(self, name, origin=None, prototype=None):
|
|
7
|
+
super(Instruction, self).__init__()
|
|
8
|
+
self.name = name
|
|
9
|
+
|
|
10
|
+
self.line_number = None
|
|
11
|
+
self.source_file = None
|
|
12
|
+
self.source_code = None
|
|
13
|
+
if origin is not None:
|
|
14
|
+
self.line_number = origin[1][2]
|
|
15
|
+
self.source_file = origin[1][1]
|
|
16
|
+
self.source_code = origin[1][4][0].strip()
|
|
17
|
+
elif prototype is not None:
|
|
18
|
+
self.line_number = prototype.line_number
|
|
19
|
+
self.source_file = prototype.source_file
|
|
20
|
+
self.source_code = prototype.source_code
|
|
21
|
+
|
|
22
|
+
self.operands = ()
|
|
23
|
+
self._implicit_in_regs = dict()
|
|
24
|
+
self._implicit_out_regs = dict()
|
|
25
|
+
self.in_regs = ()
|
|
26
|
+
self.out_regs = ()
|
|
27
|
+
self.out_operands = ()
|
|
28
|
+
self.encodings = []
|
|
29
|
+
|
|
30
|
+
self.bytecode = None
|
|
31
|
+
|
|
32
|
+
self._gas_name = None
|
|
33
|
+
self.go_name = None
|
|
34
|
+
self.isa_extensions = frozenset()
|
|
35
|
+
self.mmx_mode = None
|
|
36
|
+
self.avx_mode = None
|
|
37
|
+
self._cancelling_inputs = False
|
|
38
|
+
if prototype is None:
|
|
39
|
+
self._available_registers = dict()
|
|
40
|
+
self._live_registers = dict()
|
|
41
|
+
self._indent_level = 0
|
|
42
|
+
else:
|
|
43
|
+
self._available_registers = prototype._available_registers.copy()
|
|
44
|
+
self._live_registers = prototype._available_registers.copy()
|
|
45
|
+
self._indent_level = prototype._indent_level
|
|
46
|
+
|
|
47
|
+
def __str__(self):
|
|
48
|
+
if self.operands:
|
|
49
|
+
return str(self.name) + " " + ", ".join(map(str, self.operands))
|
|
50
|
+
else:
|
|
51
|
+
return str(self.name)
|
|
52
|
+
|
|
53
|
+
@property
|
|
54
|
+
def gas_name(self):
|
|
55
|
+
if self._gas_name is None:
|
|
56
|
+
return self.name.lower()
|
|
57
|
+
else:
|
|
58
|
+
return self._gas_name
|
|
59
|
+
|
|
60
|
+
def format(self, assembly_format, indent=False, line_number=None):
|
|
61
|
+
from nervapy.x86_64.operand import format_operand
|
|
62
|
+
|
|
63
|
+
text = "\t" * self._indent_level if indent else ""
|
|
64
|
+
if assembly_format == "peachpy":
|
|
65
|
+
return text + str(self)
|
|
66
|
+
elif assembly_format == "nasm":
|
|
67
|
+
return text + str(self)
|
|
68
|
+
elif assembly_format == "gas":
|
|
69
|
+
if self.operands:
|
|
70
|
+
from nervapy.x86_64.pseudo import Label
|
|
71
|
+
|
|
72
|
+
if (
|
|
73
|
+
line_number is not None
|
|
74
|
+
and len(self.operands) == 1
|
|
75
|
+
and isinstance(self.operands[0], Label)
|
|
76
|
+
and self.operands[0].line_number is not None
|
|
77
|
+
):
|
|
78
|
+
label = self.operands[0]
|
|
79
|
+
return "{indent}{mnemonic} {label_line}{direction} # {label_name}".format(
|
|
80
|
+
indent=text,
|
|
81
|
+
mnemonic=self.gas_name,
|
|
82
|
+
label_line=self.operands[0].line_number,
|
|
83
|
+
label_name=str(self.operands[0]),
|
|
84
|
+
direction=(
|
|
85
|
+
"b" if self.operands[0].line_number < line_number else "f"
|
|
86
|
+
),
|
|
87
|
+
)
|
|
88
|
+
else:
|
|
89
|
+
return (
|
|
90
|
+
text
|
|
91
|
+
+ self.gas_name
|
|
92
|
+
+ " "
|
|
93
|
+
+ ", ".join(
|
|
94
|
+
format_operand(op, assembly_format)
|
|
95
|
+
for op in reversed(self.operands)
|
|
96
|
+
)
|
|
97
|
+
)
|
|
98
|
+
else:
|
|
99
|
+
return text + self.gas_name
|
|
100
|
+
elif assembly_format == "go":
|
|
101
|
+
if self.go_name:
|
|
102
|
+
from nervapy.util import is_int
|
|
103
|
+
|
|
104
|
+
if self.name == "CMP" and is_int(self.operands[1]):
|
|
105
|
+
# CMP instruction with an immediate operand has operands in normal (non-reversed) order
|
|
106
|
+
return (
|
|
107
|
+
text
|
|
108
|
+
+ str(self.go_name)
|
|
109
|
+
+ " "
|
|
110
|
+
+ ", ".join(
|
|
111
|
+
format_operand(op, assembly_format) for op in self.operands
|
|
112
|
+
)
|
|
113
|
+
)
|
|
114
|
+
elif self.operands:
|
|
115
|
+
return (
|
|
116
|
+
text
|
|
117
|
+
+ str(self.go_name)
|
|
118
|
+
+ " "
|
|
119
|
+
+ ", ".join(
|
|
120
|
+
format_operand(op, assembly_format)
|
|
121
|
+
for op in reversed(self.operands)
|
|
122
|
+
)
|
|
123
|
+
)
|
|
124
|
+
else:
|
|
125
|
+
return text + str(self.go_name)
|
|
126
|
+
else:
|
|
127
|
+
return (
|
|
128
|
+
text
|
|
129
|
+
+ "; ".join(map(lambda b: "BYTE $0x%02X" % b, self.encode()))
|
|
130
|
+
+ " // "
|
|
131
|
+
+ str(self)
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
def format_encoding(self, indent):
|
|
135
|
+
if self.bytecode:
|
|
136
|
+
text = "\t" * self._indent_level if indent else ""
|
|
137
|
+
return text + "# " + " ".join("%02X" % byte for byte in self.bytecode)
|
|
138
|
+
|
|
139
|
+
@property
|
|
140
|
+
def registers(self):
|
|
141
|
+
from nervapy.x86_64.operand import get_operand_registers
|
|
142
|
+
|
|
143
|
+
registers = set()
|
|
144
|
+
for operand in self.operands:
|
|
145
|
+
registers.update(get_operand_registers(operand))
|
|
146
|
+
return registers
|
|
147
|
+
|
|
148
|
+
@property
|
|
149
|
+
def register_objects(self):
|
|
150
|
+
from nervapy.x86_64.operand import get_operand_registers
|
|
151
|
+
|
|
152
|
+
return sum(map(get_operand_registers, self.operands), [])
|
|
153
|
+
|
|
154
|
+
@property
|
|
155
|
+
def available_registers(self):
|
|
156
|
+
from nervapy.x86_64.registers import Register
|
|
157
|
+
|
|
158
|
+
return Register._reconstruct_multiple(self._available_registers)
|
|
159
|
+
|
|
160
|
+
@property
|
|
161
|
+
def live_registers(self):
|
|
162
|
+
from nervapy.x86_64.registers import Register
|
|
163
|
+
|
|
164
|
+
return Register._reconstruct_multiple(self._live_registers)
|
|
165
|
+
|
|
166
|
+
@property
|
|
167
|
+
def input_registers(self):
|
|
168
|
+
from nervapy.x86_64.registers import Register
|
|
169
|
+
|
|
170
|
+
return Register._reconstruct_multiple(self.input_registers_masks)
|
|
171
|
+
|
|
172
|
+
@property
|
|
173
|
+
def input_registers_masks(self):
|
|
174
|
+
from nervapy.x86_64.operand import get_operand_registers
|
|
175
|
+
|
|
176
|
+
if self._cancelling_inputs:
|
|
177
|
+
from nervapy.x86_64.registers import Register
|
|
178
|
+
|
|
179
|
+
input_operands = [
|
|
180
|
+
operand
|
|
181
|
+
for (is_input_reg, operand) in zip(self.in_regs, self.operands)
|
|
182
|
+
if is_input_reg
|
|
183
|
+
]
|
|
184
|
+
assert (
|
|
185
|
+
len(input_operands) == 2
|
|
186
|
+
), "Instruction forms with cancelling inputs must have two inputs"
|
|
187
|
+
assert all(
|
|
188
|
+
map(lambda op: isinstance(op, Register), input_operands)
|
|
189
|
+
), "Both inputs of instruction form with cancelling inputs must be registers"
|
|
190
|
+
if input_operands[0] == input_operands[1]:
|
|
191
|
+
return dict()
|
|
192
|
+
else:
|
|
193
|
+
return {reg._internal_id: reg.mask for reg in input_operands}
|
|
194
|
+
else:
|
|
195
|
+
registers_masks = self._implicit_in_regs.copy()
|
|
196
|
+
for has_input_registers, operand in zip(self.in_regs, self.operands):
|
|
197
|
+
if has_input_registers:
|
|
198
|
+
for register in get_operand_registers(operand):
|
|
199
|
+
register_id = register._internal_id
|
|
200
|
+
registers_masks[register_id] = (
|
|
201
|
+
registers_masks.get(register_id, 0) | register.mask
|
|
202
|
+
)
|
|
203
|
+
return registers_masks
|
|
204
|
+
|
|
205
|
+
@property
|
|
206
|
+
def output_registers(self):
|
|
207
|
+
from nervapy.x86_64.registers import Register
|
|
208
|
+
|
|
209
|
+
return Register._reconstruct_multiple(self.output_registers_masks)
|
|
210
|
+
|
|
211
|
+
@property
|
|
212
|
+
def output_registers_masks(self):
|
|
213
|
+
from nervapy.x86_64.operand import get_operand_registers
|
|
214
|
+
from nervapy.x86_64.registers import (GeneralPurposeRegister32,
|
|
215
|
+
GeneralPurposeRegister64,
|
|
216
|
+
XMMRegister, YMMRegister)
|
|
217
|
+
|
|
218
|
+
registers_masks = self._implicit_out_regs.copy()
|
|
219
|
+
for is_output_register, operand in zip(self.out_regs, self.operands):
|
|
220
|
+
if is_output_register:
|
|
221
|
+
for register in get_operand_registers(operand):
|
|
222
|
+
register_id = register._internal_id
|
|
223
|
+
register_mask = register.mask
|
|
224
|
+
if register_mask == GeneralPurposeRegister32._mask:
|
|
225
|
+
register_mask = GeneralPurposeRegister64._mask
|
|
226
|
+
elif bool(self.avx_mode) and register_mask == XMMRegister._mask:
|
|
227
|
+
register_mask = YMMRegister._mask
|
|
228
|
+
registers_masks[register_id] = (
|
|
229
|
+
registers_masks.get(register_id, 0) | register_mask
|
|
230
|
+
)
|
|
231
|
+
return registers_masks
|
|
232
|
+
|
|
233
|
+
@property
|
|
234
|
+
def constant(self):
|
|
235
|
+
from nervapy.literal import Constant
|
|
236
|
+
from nervapy.x86_64.operand import MemoryOperand
|
|
237
|
+
|
|
238
|
+
return next(
|
|
239
|
+
iter(
|
|
240
|
+
operand.symbol
|
|
241
|
+
for operand in self.operands
|
|
242
|
+
if isinstance(operand, MemoryOperand)
|
|
243
|
+
and isinstance(operand.symbol, Constant)
|
|
244
|
+
),
|
|
245
|
+
None,
|
|
246
|
+
)
|
|
247
|
+
|
|
248
|
+
@property
|
|
249
|
+
def local_variable(self):
|
|
250
|
+
from nervapy.x86_64.function import LocalVariable
|
|
251
|
+
from nervapy.x86_64.operand import MemoryOperand
|
|
252
|
+
|
|
253
|
+
return next(
|
|
254
|
+
iter(
|
|
255
|
+
operand.symbol
|
|
256
|
+
for operand in self.operands
|
|
257
|
+
if isinstance(operand, MemoryOperand)
|
|
258
|
+
and isinstance(operand.symbol, LocalVariable)
|
|
259
|
+
),
|
|
260
|
+
None,
|
|
261
|
+
)
|
|
262
|
+
|
|
263
|
+
@property
|
|
264
|
+
def memory_address(self):
|
|
265
|
+
from nervapy.x86_64.operand import MemoryOperand
|
|
266
|
+
|
|
267
|
+
memory_operands = [
|
|
268
|
+
operand for operand in self.operands if isinstance(operand, MemoryOperand)
|
|
269
|
+
]
|
|
270
|
+
if memory_operands:
|
|
271
|
+
assert (
|
|
272
|
+
len(memory_operands) == 1
|
|
273
|
+
), "x86-64 instructions can not have more than 1 explicit memory operand"
|
|
274
|
+
return memory_operands[0].address
|
|
275
|
+
|
|
276
|
+
def encode(self):
|
|
277
|
+
encodings = self._filter_encodings()
|
|
278
|
+
if encodings:
|
|
279
|
+
bytecodes = [encoding(self.operands) for (_, encoding) in encodings]
|
|
280
|
+
return min(bytecodes, key=len)
|
|
281
|
+
else:
|
|
282
|
+
return bytearray()
|
|
283
|
+
|
|
284
|
+
def encode_options(self):
|
|
285
|
+
if self.encodings:
|
|
286
|
+
bytecodes = [
|
|
287
|
+
encoding(self.operands) for (_, encoding) in self._filter_encodings()
|
|
288
|
+
]
|
|
289
|
+
min_length = min(map(len, bytecodes))
|
|
290
|
+
return filter(lambda b: len(b) == min_length, bytecodes)
|
|
291
|
+
else:
|
|
292
|
+
return bytearray()
|
|
293
|
+
|
|
294
|
+
def encode_length_options(self):
|
|
295
|
+
from nervapy.x86_64.encoding import Flags, Options
|
|
296
|
+
|
|
297
|
+
length_encoding_map = {}
|
|
298
|
+
encode_options = []
|
|
299
|
+
for flags, encode in self._filter_encodings():
|
|
300
|
+
options = 0
|
|
301
|
+
baseline = encode(self.operands)
|
|
302
|
+
if flags & Flags.ModRMSIBDisp != 0:
|
|
303
|
+
if len(encode(self.operands, sib=True)) != len(baseline):
|
|
304
|
+
options |= Options.SIB
|
|
305
|
+
if len(encode(self.operands, min_disp=1)) != len(baseline):
|
|
306
|
+
options |= Options.Disp8
|
|
307
|
+
if len(encode(self.operands, min_disp=4)) != len(baseline):
|
|
308
|
+
options |= Options.Disp32
|
|
309
|
+
if flags & Flags.OptionalREX != 0:
|
|
310
|
+
if len(encode(self.operands, rex=True)) != len(baseline):
|
|
311
|
+
options |= Options.REX
|
|
312
|
+
if flags & Flags.VEX2 != 0:
|
|
313
|
+
if len(encode(self.operands, vex3=True)) != len(baseline):
|
|
314
|
+
options |= Options.VEX3
|
|
315
|
+
length_encoding_map.setdefault(len(baseline), baseline)
|
|
316
|
+
encode_options.append((options, encode))
|
|
317
|
+
# Try disp8/disp32 options as they never involve any decoding overhead
|
|
318
|
+
for options, encode in encode_options:
|
|
319
|
+
if options & Options.Disp8:
|
|
320
|
+
bytecode = encode(self.operands, min_disp=1)
|
|
321
|
+
length_encoding_map.setdefault(len(bytecode), bytecode)
|
|
322
|
+
if options & Options.Disp32:
|
|
323
|
+
bytecode = encode(self.operands, min_disp=4)
|
|
324
|
+
length_encoding_map.setdefault(len(bytecode), bytecode)
|
|
325
|
+
# Try to use SIB byte as well (may cause spilling into multiple uops)
|
|
326
|
+
for options, encode in encode_options:
|
|
327
|
+
if options & Options.SIB:
|
|
328
|
+
bytecode = encode(self.operands, sib=True)
|
|
329
|
+
length_encoding_map.setdefault(len(bytecode), bytecode)
|
|
330
|
+
# Or try to combine SIB with disp8/disp32
|
|
331
|
+
if options & Options.Disp8:
|
|
332
|
+
bytecode = encode(self.operands, min_disp=1)
|
|
333
|
+
length_encoding_map.setdefault(len(bytecode), bytecode)
|
|
334
|
+
if options & Options.Disp32:
|
|
335
|
+
bytecode = encode(self.operands, min_disp=4)
|
|
336
|
+
length_encoding_map.setdefault(len(bytecode), bytecode)
|
|
337
|
+
# Try to use VEX3
|
|
338
|
+
for options, encode in encode_options:
|
|
339
|
+
if options & Options.VEX3:
|
|
340
|
+
bytecode = encode(self.operands, vex3=True)
|
|
341
|
+
length_encoding_map.setdefault(len(bytecode), bytecode)
|
|
342
|
+
# Combinations of VEX3 with disp8/disp32
|
|
343
|
+
if options & Options.Disp8:
|
|
344
|
+
bytecode = encode(self.operands, vex3=True, min_disp=1)
|
|
345
|
+
length_encoding_map.setdefault(len(bytecode), bytecode)
|
|
346
|
+
if options & Options.Disp32:
|
|
347
|
+
bytecode = encode(self.operands, vex3=True, min_disp=4)
|
|
348
|
+
length_encoding_map.setdefault(len(bytecode), bytecode)
|
|
349
|
+
# Try to use VEX3 + SIB
|
|
350
|
+
for options, encode in encode_options:
|
|
351
|
+
if options & Options.VEX3 and options & Options.SIB:
|
|
352
|
+
bytecode = encode(self.operands, vex3=True, sib=True)
|
|
353
|
+
length_encoding_map.setdefault(len(bytecode), bytecode)
|
|
354
|
+
# Combinations of VEX3, SIB, disp8/disp32
|
|
355
|
+
if options & Options.Disp8:
|
|
356
|
+
bytecode = encode(self.operands, vex3=True, sib=True, min_disp=1)
|
|
357
|
+
length_encoding_map.setdefault(len(bytecode), bytecode)
|
|
358
|
+
if options & Options.Disp32:
|
|
359
|
+
bytecode = encode(self.operands, vex3=True, sib=True, min_disp=4)
|
|
360
|
+
length_encoding_map.setdefault(len(bytecode), bytecode)
|
|
361
|
+
# Try to use REX
|
|
362
|
+
for options, encode in encode_options:
|
|
363
|
+
if options & Options.REX:
|
|
364
|
+
bytecode = encode(self.operands, rex=True)
|
|
365
|
+
length_encoding_map.setdefault(len(bytecode), bytecode)
|
|
366
|
+
# Combinations of REX with disp8/disp32
|
|
367
|
+
if options & Options.Disp8:
|
|
368
|
+
bytecode = encode(self.operands, rex=True, min_disp=1)
|
|
369
|
+
length_encoding_map.setdefault(len(bytecode), bytecode)
|
|
370
|
+
if options & Options.Disp32:
|
|
371
|
+
bytecode = encode(self.operands, rex=True, min_disp=4)
|
|
372
|
+
length_encoding_map.setdefault(len(bytecode), bytecode)
|
|
373
|
+
# Try to use REX + SIB
|
|
374
|
+
for options, encode in encode_options:
|
|
375
|
+
if options & Options.REX and options & Options.SIB:
|
|
376
|
+
bytecode = encode(self.operands, rex=True, sib=True)
|
|
377
|
+
length_encoding_map.setdefault(len(bytecode), bytecode)
|
|
378
|
+
# Combinations of REX, SIB, disp8/disp32
|
|
379
|
+
if options & Options.Disp8:
|
|
380
|
+
bytecode = encode(self.operands, rex=True, sib=True, min_disp=1)
|
|
381
|
+
length_encoding_map.setdefault(len(bytecode), bytecode)
|
|
382
|
+
if options & Options.Disp32:
|
|
383
|
+
bytecode = encode(self.operands, rex=True, sib=True, min_disp=4)
|
|
384
|
+
length_encoding_map.setdefault(len(bytecode), bytecode)
|
|
385
|
+
return length_encoding_map
|
|
386
|
+
|
|
387
|
+
def _filter_encodings(self):
|
|
388
|
+
encodings = []
|
|
389
|
+
from nervapy.x86_64.encoding import Flags
|
|
390
|
+
|
|
391
|
+
for flags, encoding in self.encodings:
|
|
392
|
+
if flags & Flags.AccumulatorOp0 != 0:
|
|
393
|
+
if self.operands[0].physical_id == 0:
|
|
394
|
+
encodings.append((flags, encoding))
|
|
395
|
+
elif flags & Flags.AccumulatorOp1 != 0:
|
|
396
|
+
if self.operands[1].physical_id == 0:
|
|
397
|
+
encodings.append((flags, encoding))
|
|
398
|
+
else:
|
|
399
|
+
encodings.append((flags, encoding))
|
|
400
|
+
return encodings
|
|
401
|
+
|
|
402
|
+
@property
|
|
403
|
+
def relocation(self):
|
|
404
|
+
"""Returns relocation corresponding to encoding of this instruction of None if no relocation needed.
|
|
405
|
+
Relocation offset and type variables are initialized, symbol variable needs to be initialized by the caller.
|
|
406
|
+
Relocation offset specifies offset relative to the start of instruction encoding.
|
|
407
|
+
"""
|
|
408
|
+
|
|
409
|
+
from nervapy.x86_64.meta import Relocation, RelocationType
|
|
410
|
+
|
|
411
|
+
if self.bytecode:
|
|
412
|
+
from nervapy.literal import Constant
|
|
413
|
+
|
|
414
|
+
if self.constant is not None:
|
|
415
|
+
# Mini-disassembler for instruction encoding.
|
|
416
|
+
# Possible encoding sequences:
|
|
417
|
+
# | [66, F2, or F3 prefix] | [REX] | [66, F2, or F3 prefix] | ...
|
|
418
|
+
# ... [0F, 0F 38, or 0F 3A opcode extension] | Opcode | Mod R/M | disp32 | [imm] |
|
|
419
|
+
# | C5 ... 2-byte VEX | Opcode | Mod R/M | disp32 | [imm] |
|
|
420
|
+
# | C4 ... 3-byte VEX | Opcode | Mod R/M | disp32 | [imm] |
|
|
421
|
+
# | 8F ... 3-byte XOP | Opcode | Mod R/M | disp32 | [imm] |
|
|
422
|
+
# | 62 ... 4-byte EVEX | Opcode | Mod R/M | disp32 | [imm] |
|
|
423
|
+
prefix_lengths = {0xC5: 2, 0xC4: 3, 0x8F: 3, 0x62: 4}
|
|
424
|
+
if self.bytecode[0] in prefix_lengths:
|
|
425
|
+
mod_rm_position = prefix_lengths[self.bytecode[0]] + 1
|
|
426
|
+
else:
|
|
427
|
+
decode_position = 0
|
|
428
|
+
if self.bytecode[0] in [0x66, 0xF2, 0xF3]:
|
|
429
|
+
# Legacy prefix
|
|
430
|
+
decode_position += 1
|
|
431
|
+
if self.bytecode[decode_position] & 0xF0 == 0x40:
|
|
432
|
+
# REX prefix
|
|
433
|
+
decode_position += 1
|
|
434
|
+
if self.bytecode[decode_position] in [0x66, 0xF2, 0xF3]:
|
|
435
|
+
# Legacy prefix += 1
|
|
436
|
+
decode_position += 1
|
|
437
|
+
if self.bytecode[decode_position] == 0x0F:
|
|
438
|
+
# Opcode extension
|
|
439
|
+
decode_position += 1
|
|
440
|
+
if self.bytecode[decode_position] in [0x38, 0x3A]:
|
|
441
|
+
# 2-byte 0F 38 or 0F 3A opcode extension
|
|
442
|
+
decode_position += 1
|
|
443
|
+
# Opcode
|
|
444
|
+
mod_rm_position = decode_position + 1
|
|
445
|
+
mod_rm = self.bytecode[mod_rm_position]
|
|
446
|
+
rm = mod_rm & 0b111
|
|
447
|
+
mode = mod_rm >> 6
|
|
448
|
+
assert (
|
|
449
|
+
rm == 0b101 and mode == 0b00
|
|
450
|
+
), "Encoding must use rip-relative disp32 addressing, can't have SIB byte"
|
|
451
|
+
return Relocation(
|
|
452
|
+
mod_rm_position + 1,
|
|
453
|
+
RelocationType.rip_disp32,
|
|
454
|
+
program_counter=len(self.bytecode),
|
|
455
|
+
)
|
|
456
|
+
|
|
457
|
+
|
|
458
|
+
class BranchInstruction(Instruction):
|
|
459
|
+
def __init__(self, name, origin=None, prototype=None):
|
|
460
|
+
super(BranchInstruction, self).__init__(
|
|
461
|
+
name, origin=origin, prototype=prototype
|
|
462
|
+
)
|
|
463
|
+
self.is_conditional = name != "JMP"
|
|
464
|
+
|
|
465
|
+
def _encode_label_branch(self, address, label_address=None, long_encoding=False):
|
|
466
|
+
if label_address is None:
|
|
467
|
+
encodings = [encode(0) for (_, encode) in self.encodings]
|
|
468
|
+
else:
|
|
469
|
+
encodings = []
|
|
470
|
+
from nervapy.util import is_sint8, is_sint32
|
|
471
|
+
from nervapy.x86_64.encoding import Flags
|
|
472
|
+
|
|
473
|
+
for flags, encode in self.encodings:
|
|
474
|
+
offset = label_address - (address + len(encode(0)))
|
|
475
|
+
if (
|
|
476
|
+
flags & Flags.Rel8Label != 0
|
|
477
|
+
and is_sint8(offset)
|
|
478
|
+
or flags & Flags.Rel32Label != 0
|
|
479
|
+
and is_sint32(offset)
|
|
480
|
+
):
|
|
481
|
+
encodings.append(encode(offset))
|
|
482
|
+
if not encodings:
|
|
483
|
+
raise ValueError("Can not encode offset to label %s" % self.label_name)
|
|
484
|
+
assert (
|
|
485
|
+
len(encodings) <= 2
|
|
486
|
+
), "At most 2 encodings expected for branch instructions with immediate code offset"
|
|
487
|
+
if len(encodings) == 1:
|
|
488
|
+
return True, encodings[0]
|
|
489
|
+
else:
|
|
490
|
+
if long_encoding:
|
|
491
|
+
return True, max(encodings, key=len)
|
|
492
|
+
else:
|
|
493
|
+
return False, min(encodings, key=len)
|
|
494
|
+
|
|
495
|
+
@property
|
|
496
|
+
def label_name(self):
|
|
497
|
+
from nervapy.x86_64.pseudo import Label
|
|
498
|
+
|
|
499
|
+
if isinstance(self.operands[0], Label):
|
|
500
|
+
return self.operands[0].name
|