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,322 @@
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
+ from enum import IntEnum
5
+
6
+
7
+ class MemoryProtection(IntEnum):
8
+ read = 0x01
9
+ write = 0x02
10
+ execute = 0x04
11
+ default = 0x07
12
+
13
+
14
+ class Segment:
15
+ def __init__(self, name):
16
+ self.name = name
17
+ self.sections = list()
18
+ self.flags = 0
19
+
20
+ def add_section(self, section):
21
+ assert isinstance(section, Section)
22
+ assert section.segment_name == self.name
23
+
24
+ self.sections.append(section)
25
+
26
+ def get_command_size(self, abi):
27
+ from nervapy.abi import ABI
28
+
29
+ assert isinstance(abi, ABI)
30
+ assert abi.pointer_size in [4, 8]
31
+
32
+ return {4: 56, 8: 72}[abi.pointer_size] + sum(
33
+ section.get_command_size(abi) for section in self.sections
34
+ )
35
+
36
+ def encode_command(
37
+ self, encoder, section_offset_map, section_address_map, section_relocations_map
38
+ ):
39
+ import nervapy.encoder
40
+
41
+ assert isinstance(encoder, nervapy.encoder.Encoder)
42
+
43
+ offset = section_offset_map[self.sections[0]]
44
+ memory_size = (
45
+ section_address_map[self.sections[-1]] + self.sections[-1].content_size
46
+ )
47
+ file_size = sum(section.content_size for section in self.sections)
48
+
49
+ address = 0
50
+ if self.sections:
51
+ address = section_address_map[self.sections[0]]
52
+ # TODO: combine the two cases
53
+ if encoder.bitness == 32:
54
+ command_id = 0x1
55
+ command_size = 56 + len(self.sections) * 68
56
+ command = (
57
+ encoder.uint32(command_id)
58
+ + encoder.uint32(command_size)
59
+ + encoder.fixed_string(self.name, 16)
60
+ + encoder.uint32(address)
61
+ + encoder.uint32(memory_size)
62
+ + encoder.uint32(offset)
63
+ + encoder.uint32(file_size)
64
+ + encoder.uint32(MemoryProtection.default)
65
+ + encoder.uint32(MemoryProtection.default)
66
+ + encoder.uint32(len(self.sections))
67
+ + encoder.uint32(self.flags)
68
+ )
69
+ else:
70
+ command_id = 0x19
71
+ command_size = 72 + len(self.sections) * 80
72
+ command = (
73
+ encoder.uint32(command_id)
74
+ + encoder.uint32(command_size)
75
+ + encoder.fixed_string(self.name, 16)
76
+ + encoder.uint64(address)
77
+ + encoder.uint64(memory_size)
78
+ + encoder.uint64(offset)
79
+ + encoder.uint64(file_size)
80
+ + encoder.uint32(MemoryProtection.default)
81
+ + encoder.uint32(MemoryProtection.default)
82
+ + encoder.uint32(len(self.sections))
83
+ + encoder.uint32(self.flags)
84
+ )
85
+ for section in self.sections:
86
+ command += section.encode_command(
87
+ encoder,
88
+ section_offset_map[section],
89
+ section_address_map[section],
90
+ section_relocations_map.get(section),
91
+ )
92
+ from nervapy.x86_64.abi import system_v_x86_64_abi
93
+
94
+ return command
95
+
96
+
97
+ class SectionIndex(IntEnum):
98
+ no_section = 0
99
+
100
+
101
+ class SectionType(IntEnum):
102
+ regular = 0x00
103
+ zero_fill = 0x01
104
+ gb_zero_fill = 0x0C
105
+ cstring_literals = 0x02
106
+ four_byte_literals = 0x03
107
+ eight_byte_literals = 0x04
108
+ sixteen_byte_literals = 0x0E
109
+ literal_pointers = 0x05
110
+ non_lazy_symbol_pointers = 0x06
111
+ lazy_symbol_pointers = 0x07
112
+ symbol_stubs = 0x08
113
+ module_init_function_pointers = 0x09
114
+ module_terminate_function_pointers = 0x0A
115
+ coalesced_symbols = 0x0B
116
+ interposing = 0x0D
117
+ dtrace_object_format = 0x0F
118
+ lazy_dylib_symbol_pointers = 0x10
119
+ thread_local_regular = 0x11
120
+ thread_local_zero_fill = 0x12
121
+ thread_local_variable_descriptors = 0x13
122
+ thread_local_variable_pointers = 0x14
123
+ thread_local_function_pointers = 0x15
124
+
125
+
126
+ class SectionAttributes(IntEnum):
127
+ only_instructions = 0x80000000
128
+ coalesced_symbols = 0x40000000
129
+ strip_static_symbols = 0x20000000
130
+ no_dead_stripping = 0x10000000
131
+ live_support = 0x08000000
132
+ self_modifying_code = 0x04000000
133
+ debug = 0x02000000
134
+ some_instructions = 0x00000400
135
+ external_relocations = 0x00000200
136
+ local_relocations = 0x00000100
137
+
138
+
139
+ class Section(object):
140
+ def __init__(self, type, segment_name, section_name):
141
+ self.type = type
142
+ self.segment_name = segment_name
143
+ self.section_name = section_name
144
+ self.attributes = 0
145
+ self._alignment = 1
146
+ self.relocations = []
147
+ self.content = bytearray()
148
+
149
+ @property
150
+ def alignment(self):
151
+ return self._alignment
152
+
153
+ @alignment.setter
154
+ def alignment(self, alignment):
155
+ from nervapy.util import is_uint32
156
+
157
+ if not is_uint32(alignment):
158
+ raise TypeError(
159
+ "Section alignment %s is not representable as a 32-bit unsigned integer"
160
+ % str(alignment)
161
+ )
162
+ if alignment & (alignment - 1) != 0:
163
+ raise ValueError("Section alignment %d is not a power of 2" % alignment)
164
+ if alignment == 0:
165
+ alignment = 1
166
+ self._alignment = alignment
167
+
168
+ @property
169
+ def log2_alignment(self):
170
+ from nervapy.util import ilog2
171
+
172
+ return ilog2(self._alignment)
173
+
174
+ @property
175
+ def relocations_count(self):
176
+ return len(self.relocations)
177
+
178
+ @property
179
+ def content_size(self):
180
+ return len(self.content)
181
+
182
+ @staticmethod
183
+ def get_command_size(abi):
184
+ from nervapy.abi import ABI
185
+
186
+ assert isinstance(abi, ABI)
187
+ assert abi.pointer_size in [4, 8]
188
+
189
+ return {4: 68, 8: 80}[abi.pointer_size]
190
+
191
+ def encode_command(self, encoder, offset, address, relocations_offset):
192
+ import nervapy.encoder
193
+
194
+ assert isinstance(encoder, nervapy.encoder.Encoder)
195
+
196
+ if len(self.relocations) == 0:
197
+ relocations_offset = 0
198
+ if encoder.bitness == 32:
199
+ return (
200
+ encoder.fixed_string(self.section_name, 16)
201
+ + encoder.fixed_string(self.segment_name, 16)
202
+ + encoder.uint32(address)
203
+ + encoder.uint32(self.content_size)
204
+ + encoder.uint32(offset)
205
+ + encoder.uint32(self.log2_alignment)
206
+ + encoder.uint32(relocations_offset)
207
+ + encoder.uint32(self.relocations_count)
208
+ + encoder.uint32(self.type | self.attributes)
209
+ + bytearray(8)
210
+ )
211
+ else:
212
+ return (
213
+ encoder.fixed_string(self.section_name, 16)
214
+ + encoder.fixed_string(self.segment_name, 16)
215
+ + encoder.uint64(address)
216
+ + encoder.uint64(self.content_size)
217
+ + encoder.uint32(offset)
218
+ + encoder.uint32(self.log2_alignment)
219
+ + encoder.uint32(relocations_offset)
220
+ + encoder.uint32(self.relocations_count)
221
+ + encoder.uint32(self.type | self.attributes)
222
+ + bytearray(12)
223
+ )
224
+
225
+
226
+ class RegularSection(Section):
227
+ def __init__(self, segment_name, section_name):
228
+ super(RegularSection, self).__init__(
229
+ SectionType.regular, segment_name, section_name
230
+ )
231
+
232
+ def align(self, alignment):
233
+ import nervapy.util
234
+
235
+ ilog2_alignment = nervapy.util.ilog2(alignment)
236
+ self.alignment = max(self.alignment, ilog2_alignment)
237
+ if len(self.content) % alignment != 0:
238
+ padding_length = alignment - len(self.content) % alignment
239
+ self.content += bytearray(padding_length)
240
+
241
+
242
+ class TextSection(RegularSection):
243
+ def __init__(self):
244
+ super(TextSection, self).__init__("__TEXT", "__text")
245
+ self.attributes = (
246
+ SectionAttributes.only_instructions | SectionAttributes.some_instructions
247
+ )
248
+
249
+
250
+ class ConstSection(RegularSection):
251
+ def __init__(self):
252
+ super(ConstSection, self).__init__("__TEXT", "__const")
253
+
254
+
255
+ class SymbolTable:
256
+ command_size = 24
257
+
258
+ def __init__(self, string_table):
259
+ assert isinstance(string_table, StringTable)
260
+
261
+ self.symbols = list()
262
+ self.string_table = string_table
263
+
264
+ def add_symbol(self, symbol):
265
+ from nervapy.formats.macho.symbol import Symbol
266
+
267
+ assert isinstance(symbol, Symbol)
268
+
269
+ self.symbols.append(symbol)
270
+ self.string_table.add(symbol.name)
271
+
272
+ def encode_command(self, encoder, symbol_offset_map, string_offset):
273
+ import nervapy.encoder
274
+
275
+ assert isinstance(encoder, nervapy.encoder.Encoder)
276
+
277
+ command_id = 0x2
278
+ symbols_offset = 0
279
+ if self.symbols:
280
+ symbols_offset = symbol_offset_map[self.symbols[0]]
281
+ return (
282
+ encoder.uint32(command_id)
283
+ + encoder.uint32(SymbolTable.command_size)
284
+ + encoder.uint32(symbols_offset)
285
+ + encoder.uint32(len(self.symbols))
286
+ + encoder.uint32(string_offset)
287
+ + encoder.uint32(self.string_table.size)
288
+ )
289
+
290
+
291
+ class StringTable:
292
+ def __init__(self):
293
+ self.string_index_map = dict()
294
+ self.size = 0
295
+
296
+ def add(self, string):
297
+ import codecs
298
+
299
+ if string is None or len(string) == 0:
300
+ return 0
301
+ if string in self.string_index_map:
302
+ return self.string_index_map[string]
303
+ else:
304
+ content_size = self.size
305
+ if content_size == 0:
306
+ content_size = 1
307
+ string_index = content_size
308
+ self.string_index_map[string] = string_index
309
+ bytestring = codecs.encode(string, "utf-8")
310
+ content_size += len(bytestring) + 1
311
+ self.size = content_size
312
+
313
+ def encode(self):
314
+ import codecs
315
+
316
+ if self.size != 0:
317
+ bytestring = b"\x00"
318
+ for string in sorted(self.string_index_map, key=self.string_index_map.get):
319
+ bytestring += codecs.encode(string, "utf8") + b"\x00"
320
+ return bytestring
321
+ else:
322
+ return bytearray()
@@ -0,0 +1,158 @@
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
+ from enum import IntEnum
5
+
6
+
7
+ class SymbolVisibility(IntEnum):
8
+ external = 0x01
9
+ private_external = 0x10
10
+
11
+
12
+ class SymbolType(IntEnum):
13
+ undefined = 0x00
14
+ prebound_undefined = 0x0C
15
+ absolute = 0x02
16
+ section_relative = 0x0E
17
+ indirect = 0x0A
18
+
19
+
20
+ class SymbolDescription(IntEnum):
21
+ undefined_lazy = 0x00
22
+ undefined_non_lazy = 0x01
23
+ defined = 0x02
24
+ private_defined = 0x03
25
+ private_undefined_lazy = 0x05
26
+ private_undefined_non_lazy = 0x04
27
+
28
+
29
+ class SymbolFlags(IntEnum):
30
+ referenced_dynamically = 0x10
31
+ no_dead_strip = 0x20
32
+ weak_reference = 0x40
33
+ weak_definition = 0x80
34
+
35
+
36
+ class Symbol:
37
+ def __init__(self, name, type, section, value=None):
38
+ self.name = name
39
+ self.visibility = 0
40
+ self.type = type
41
+ self.section = section
42
+ self.description = 0
43
+ self.flags = 0
44
+ self.value = value
45
+
46
+ @staticmethod
47
+ def get_entry_size(abi):
48
+ from nervapy.abi import ABI
49
+
50
+ assert isinstance(abi, ABI)
51
+ assert abi.pointer_size in [4, 8]
52
+
53
+ return {4: 12, 8: 16}[abi.pointer_size]
54
+
55
+ def encode(self, encoder, name_index_map, section_index_map, section_address_map):
56
+ import nervapy.encoder
57
+
58
+ assert isinstance(encoder, nervapy.encoder.Encoder)
59
+ assert self.name in name_index_map
60
+ assert self.section is None or self.section in section_index_map
61
+
62
+ name_index = name_index_map[self.name]
63
+ section_index = 0
64
+ if self.section is not None:
65
+ section_index = section_index_map[self.section]
66
+ if encoder.bitness == 32:
67
+ return (
68
+ encoder.uint32(name_index)
69
+ + encoder.uint8(self.type | self.visibility)
70
+ + encoder.uint8(section_index)
71
+ + encoder.uint16(self.description | self.flags)
72
+ + encoder.uint32(self.value)
73
+ )
74
+ else:
75
+ return (
76
+ encoder.uint32(name_index)
77
+ + encoder.uint8(self.type | self.visibility)
78
+ + encoder.uint8(section_index)
79
+ + encoder.uint16(self.description | self.flags)
80
+ + encoder.uint64(self.value + section_address_map[self.section])
81
+ )
82
+
83
+
84
+ class RelocationType(IntEnum):
85
+ x86_64_unsigned = 0
86
+ x86_64_signed = 1
87
+ # CALL or JMP instruction with 32-bit displacement.
88
+ x86_64_branch = 2
89
+ # Load (MOVQ) of a 64-bit Global Offset Table entry
90
+ x86_64_got_load = 3
91
+ x86_64_got = 4
92
+ x86_64_subtractor = 5
93
+ # Signed 32-bit displacement with a -1 addend
94
+ x86_64_signed_minus_1 = 6
95
+ # Signed 32-bit displacement with a -2 addend
96
+ x86_64_signed_minus_2 = 7
97
+ # Signed 32-bit displacement with a -4 addend
98
+ x86_64_signed_minus_4 = 8
99
+
100
+ arm_vanilla = 0
101
+ arm_pair = 1
102
+ arm_sectdiff = 2
103
+ arm_local_sectdiff = 3
104
+ arm_pb_la_ptr = 4
105
+ arm_br_24 = 5
106
+ arm_half = 6
107
+ arm_half_sectdiff = 7
108
+
109
+ arm64_unsigned = 0
110
+ arm64_subtractor = 1
111
+ arm64_branch26 = 2
112
+ arm64_page21 = 3
113
+ arm64_pageoff12 = 4
114
+ arm64_got_load_page21 = 5
115
+ arm64_got_load_pageoff12 = 6
116
+ arm64_pointer_to_got = 7
117
+ arm64_tlvp_load_page21 = 8
118
+ arm64_tlvp_load_pageoff12 = 9
119
+ arm64_reloc_addend = 10
120
+
121
+
122
+ class Relocation:
123
+ size = 8
124
+
125
+ def __init__(self, type, offset, size, symbol, is_pc_relative=False):
126
+ from nervapy.util import is_sint32
127
+
128
+ assert is_sint32(offset)
129
+ assert offset >= 0
130
+ assert size in [1, 2, 4, 8]
131
+ from nervapy.formats.macho.section import Section
132
+
133
+ assert symbol is None or isinstance(symbol, (Section, Symbol))
134
+
135
+ self.type = type
136
+ self.offset = offset
137
+ self.size = size
138
+ self.symbol = symbol
139
+ self.is_pc_relative = is_pc_relative
140
+
141
+ def encode(self, encoder, section_index_map, symbol_index_map):
142
+ from nervapy.formats.macho.section import Section
143
+ from nervapy.util import ilog2
144
+
145
+ symbol = 0
146
+ if isinstance(self.symbol, Symbol):
147
+ # Set "external" bit (bit 27) if referencing an external symbol
148
+ symbol = symbol_index_map[self.symbol] | 0x8000000
149
+ elif isinstance(self.symbol, Section):
150
+ symbol = section_index_map[self.symbol]
151
+ if self.is_pc_relative:
152
+ # Set "pc_relative" bit (bit 24) if the relocation is relative to the program counter
153
+ symbol |= 0x1000000
154
+ log2_size = ilog2(self.size)
155
+ symbol |= log2_size << 25
156
+ symbol |= self.type << 28
157
+
158
+ return encoder.uint32(self.offset) + encoder.uint32(symbol)
@@ -0,0 +1,8 @@
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
+ from nervapy.formats.mscoff.image import Image, MachineType
5
+ from nervapy.formats.mscoff.section import (ReadOnlyDataSection, Section,
6
+ TextSection)
7
+ from nervapy.formats.mscoff.symbol import (Relocation, RelocationType,
8
+ StorageClass, Symbol, SymbolType)
@@ -0,0 +1,132 @@
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
+ from enum import IntEnum
5
+
6
+
7
+ class MachineType(IntEnum):
8
+ # Machine-independent
9
+ unknown = 0
10
+ # IA32 (x86)
11
+ x86 = 0x14C
12
+ # x86-64 (AMD64, Intel64, x64)
13
+ x86_64 = 0x8664
14
+ # IA64 (Itanium)
15
+ ia64 = 0x200
16
+ # ARM
17
+ arm = 0x1C0
18
+ # ARMv7 (Thumb mode only)
19
+ armnt = 0x1C4
20
+ # ARMv8 AArch64
21
+ arm64 = 0xAA64
22
+ # EFI bytecode
23
+ efi_bytecode = 0xEBC
24
+
25
+
26
+ class Image:
27
+ file_header_size = 20
28
+
29
+ def __init__(self, abi, source=None):
30
+ from nervapy.formats.mscoff.section import StringTable
31
+
32
+ self.abi = abi
33
+ self.sections = list()
34
+ self.symbols = list()
35
+ self.string_table = StringTable()
36
+
37
+ def add_section(self, section):
38
+ from nervapy.formats.mscoff.section import Section
39
+
40
+ assert isinstance(section, Section)
41
+
42
+ self.sections.append(section)
43
+
44
+ def add_symbol(self, symbol):
45
+ from nervapy.formats.mscoff.symbol import Symbol
46
+
47
+ assert isinstance(symbol, Symbol)
48
+
49
+ self.symbols.append(symbol)
50
+
51
+ def encode(self):
52
+ from nervapy.encoder import Encoder
53
+
54
+ encoder = Encoder(self.abi.endianness)
55
+
56
+ # Collect names that need to be encoded in the string table
57
+ import codecs
58
+
59
+ for section in self.sections:
60
+ if len(codecs.encode(section.name, "utf8")) > 8:
61
+ self.string_table.add(section.name)
62
+ for symbol in self.symbols:
63
+ if len(codecs.encode(symbol.name, "utf8")) > 8:
64
+ self.string_table.add(symbol.name)
65
+
66
+ # Layout sections offsets
67
+ from nervapy.formats.mscoff.section import Section
68
+
69
+ section_offset_map = dict()
70
+ symbol_table_offset = (
71
+ Image.file_header_size + len(self.sections) * Section.header_size
72
+ )
73
+ data_offset = symbol_table_offset + self.string_table.size
74
+ for symbol in self.symbols:
75
+ data_offset += symbol.entry_size
76
+ for section in self.sections:
77
+ section_offset_map[section] = data_offset
78
+ data_offset += section.content_size
79
+
80
+ # Layout section relocations
81
+ from nervapy.formats.mscoff.symbol import Relocation
82
+
83
+ section_relocations_map = dict()
84
+ for section in self.sections:
85
+ if section.relocations:
86
+ section_relocations_map[section] = data_offset
87
+ data_offset += Relocation.entry_size * len(section.relocations)
88
+
89
+ section_index_map = {
90
+ section: index + 1 for index, section in enumerate(self.sections)
91
+ }
92
+ symbol_index_map = {symbol: index for index, symbol in enumerate(self.symbols)}
93
+
94
+ # Write file header
95
+ timestamp = 0
96
+ file_flags = 0
97
+ data = (
98
+ encoder.uint16(self.abi.mscoff_machine_type)
99
+ + encoder.uint16(len(self.sections))
100
+ + encoder.uint32(timestamp)
101
+ + encoder.uint32(symbol_table_offset)
102
+ + encoder.uint32(len(self.symbols))
103
+ + encoder.uint16(0)
104
+ + encoder.uint16(file_flags)
105
+ )
106
+
107
+ # Write section headers
108
+ for section in self.sections:
109
+ data += section.encode_header(
110
+ encoder,
111
+ self.string_table._strings,
112
+ section_offset_map[section],
113
+ section_relocations_map.get(section),
114
+ )
115
+
116
+ # Write symbol table and string table (immediately follows symbols table)
117
+ for symbol in self.symbols:
118
+ data += symbol.encode_entry(
119
+ encoder, self.string_table._strings, section_index_map
120
+ )
121
+ data += self.string_table.encode()
122
+
123
+ # Write section content
124
+ for section in self.sections:
125
+ data += section.content
126
+
127
+ # Write section relocations
128
+ for section in self.sections:
129
+ for relocation in section.relocations:
130
+ data += relocation.encode_entry(encoder, symbol_index_map)
131
+
132
+ return data