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.
Files changed (74) hide show
  1. nervapy/__init__.py +50 -0
  2. nervapy/abi.py +91 -0
  3. nervapy/arm/__init__.py +124 -0
  4. nervapy/arm/__main__.py +0 -0
  5. nervapy/arm/abi.py +138 -0
  6. nervapy/arm/formats.py +49 -0
  7. nervapy/arm/function.py +2465 -0
  8. nervapy/arm/generic.py +10796 -0
  9. nervapy/arm/instructions.py +519 -0
  10. nervapy/arm/isa.py +409 -0
  11. nervapy/arm/literal_pool.py +331 -0
  12. nervapy/arm/microarchitecture.py +211 -0
  13. nervapy/arm/pseudo.py +652 -0
  14. nervapy/arm/registers.py +1458 -0
  15. nervapy/arm/vfpneon.py +4092 -0
  16. nervapy/arm.py +13 -0
  17. nervapy/c/__init__.py +1 -0
  18. nervapy/c/types.py +436 -0
  19. nervapy/codegen.py +99 -0
  20. nervapy/common/__init__.py +4 -0
  21. nervapy/common/function.py +5 -0
  22. nervapy/common/regalloc.py +121 -0
  23. nervapy/constant_data.py +282 -0
  24. nervapy/encoder.py +246 -0
  25. nervapy/formats/__init__.py +2 -0
  26. nervapy/formats/elf/__init__.py +4 -0
  27. nervapy/formats/elf/file.py +178 -0
  28. nervapy/formats/elf/image.py +106 -0
  29. nervapy/formats/elf/section.py +422 -0
  30. nervapy/formats/elf/symbol.py +281 -0
  31. nervapy/formats/macho/__init__.py +2 -0
  32. nervapy/formats/macho/file.py +123 -0
  33. nervapy/formats/macho/image.py +143 -0
  34. nervapy/formats/macho/section.py +322 -0
  35. nervapy/formats/macho/symbol.py +158 -0
  36. nervapy/formats/mscoff/__init__.py +8 -0
  37. nervapy/formats/mscoff/image.py +132 -0
  38. nervapy/formats/mscoff/section.py +181 -0
  39. nervapy/formats/mscoff/symbol.py +148 -0
  40. nervapy/function.py +136 -0
  41. nervapy/literal.py +731 -0
  42. nervapy/loader.py +188 -0
  43. nervapy/name.py +159 -0
  44. nervapy/parse.py +52 -0
  45. nervapy/stream.py +58 -0
  46. nervapy/util.py +126 -0
  47. nervapy/writer.py +518 -0
  48. nervapy/x86_64/__init__.py +324 -0
  49. nervapy/x86_64/__main__.py +407 -0
  50. nervapy/x86_64/abi.py +517 -0
  51. nervapy/x86_64/amd.py +6464 -0
  52. nervapy/x86_64/avx.py +102029 -0
  53. nervapy/x86_64/crypto.py +1533 -0
  54. nervapy/x86_64/encoding.py +424 -0
  55. nervapy/x86_64/fma.py +19138 -0
  56. nervapy/x86_64/function.py +2707 -0
  57. nervapy/x86_64/generic.py +23384 -0
  58. nervapy/x86_64/instructions.py +500 -0
  59. nervapy/x86_64/isa.py +476 -0
  60. nervapy/x86_64/lower.py +126 -0
  61. nervapy/x86_64/mask.py +2593 -0
  62. nervapy/x86_64/meta.py +143 -0
  63. nervapy/x86_64/mmxsse.py +17265 -0
  64. nervapy/x86_64/nacl.py +327 -0
  65. nervapy/x86_64/operand.py +1204 -0
  66. nervapy/x86_64/options.py +21 -0
  67. nervapy/x86_64/pseudo.py +686 -0
  68. nervapy/x86_64/registers.py +1225 -0
  69. nervapy/x86_64/types.py +17 -0
  70. nervapy/x86_64/uarch.py +580 -0
  71. pynerva-0.0.7.dist-info/METADATA +310 -0
  72. pynerva-0.0.7.dist-info/RECORD +74 -0
  73. pynerva-0.0.7.dist-info/WHEEL +4 -0
  74. 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