RetroLinker
Linker for several 8-bit, 16-bit and 32-bit formats
Loading...
Searching...
No Matches
mpwobj.h
1#ifndef _MPWOBJ_H
2#define _MPWOBJ_H
3
4#include <map>
5#include <memory>
6#include <vector>
7#include <set>
8#include <string>
9#include "../linker/format.h"
10#include "../linker/image.h"
11#include "../linker/reader.h"
12#include "../linker/writer.h"
13#include "../dumper/dumper.h"
14#include "apple.h"
15
16// TODO: attempt at parsing MPW object files
17
18// based on Macintosh Programmer's Workshop 3.0 Reference, Appendix H, Object File Format
19
20namespace MPW
21{
23 {
24 public:
25 class Record
26 {
27 protected:
28 static const std::map<offset_t, std::string> record_type_names;
29 public:
30 enum record_type
31 {
32 Pad = 0,
33 First = 1,
34 Last = 2,
35 Comment = 3,
36 Dictionary = 4,
37 Module = 5,
38 EntryPoint = 6,
39 Size = 7,
40 Contents = 8,
41 Reference = 9,
42 ComputedReference = 10,
43 Filename = 11,
44 SourceStatement = 12,
45 ModuleBegin = 13,
46 ModuleEnd = 14,
47 BlockBegin = 15,
48 BlockEnd = 16,
49 LocalIdentifier = 17,
50 LocalLabel = 18,
51 LocalType = 19,
52 };
53
54 offset_t record_offset;
55 record_type type;
56
57 Record(record_type type = record_type(0), offset_t record_offset = 0)
58 : record_offset(record_offset), type(type)
59 {
60 }
61
62 virtual ~Record() = default;
63 static std::shared_ptr<Record> ReadFile(const std::shared_ptr<Linker::Reader>& rd);
64 virtual void ReadBody(const std::shared_ptr<Linker::Reader>& rd);
65 virtual offset_t ImageSize() const;
66 virtual offset_t WriteFile(const std::shared_ptr<Linker::Writer>& wr) const;
67 virtual void Dump(Dumper::Dumper& dump, offset_t record_index) const;
68 };
69
70 class FirstRecord : public Record
71 {
72 public:
73 FirstRecord(record_type type = record_type(0), offset_t record_offset = 0)
74 : Record(type, record_offset)
75 {
76 }
77
78 static constexpr uint8_t Nested = 0x01;
79 uint8_t flags = 0;
80
81 enum version_type : uint16_t
82 {
83 Nonsymbolic_2_0 = 1,
84 Nonsymbolic_3_0 = 2,
85 Symbolic = 3,
86 };
87 version_type version = version_type(0);
88
89 void ReadBody(const std::shared_ptr<Linker::Reader>& rd) override;
90 offset_t ImageSize() const override;
91 offset_t WriteFile(const std::shared_ptr<Linker::Writer>& wr) const override;
92 void Dump(Dumper::Dumper& dump, offset_t record_index) const override;
93 };
94
95 class CommentRecord : public Record
96 {
97 public:
98 CommentRecord(record_type type = record_type(0), offset_t record_offset = 0)
99 : Record(type, record_offset)
100 {
101 }
102
103 std::shared_ptr<Linker::Contents> comments;
104
105 void ReadBody(const std::shared_ptr<Linker::Reader>& rd) override;
106 offset_t ImageSize() const override;
107 offset_t WriteFile(const std::shared_ptr<Linker::Writer>& wr) const override;
108 void Dump(Dumper::Dumper& dump, offset_t record_index) const override;
109 };
110
112 {
113 public:
114 DictionaryRecord(record_type type = record_type(0), offset_t record_offset = 0)
115 : Record(type, record_offset)
116 {
117 }
118 static constexpr uint8_t DebugFlag = 0x80;
119 uint8_t flags = 0;
120 uint16_t first_id = 0;
121 std::vector<std::string> names;
122
123 void ReadBody(const std::shared_ptr<Linker::Reader>& rd) override;
124 offset_t ImageSize() const override;
125 offset_t WriteFile(const std::shared_ptr<Linker::Writer>& wr) const override;
126 void Dump(Dumper::Dumper& dump, offset_t record_index) const override;
127 };
128
129 class ModuleRecord : public Record
130 {
131 public:
132 ModuleRecord(record_type type = record_type(0), offset_t record_offset = 0)
133 : Record(type, record_offset)
134 {
135 }
136 static constexpr uint8_t DataFlag = 0x01;
137 static constexpr uint8_t ExternFlag = 0x08;
138 static constexpr uint8_t MainFlag = 0x10;
139 static constexpr uint8_t ForceActiveFlag = 0x80;
140
141 uint8_t flags = 0;
142 uint16_t module_id = 0;
143 union
144 {
145 uint16_t id;
146 uint16_t size;
147 } segment = { };
148
149 void ReadBody(const std::shared_ptr<Linker::Reader>& rd) override;
150 offset_t ImageSize() const override;
151 offset_t WriteFile(const std::shared_ptr<Linker::Writer>& wr) const override;
152 void Dump(Dumper::Dumper& dump, offset_t record_index) const override;
153 };
154
156 {
157 public:
158 EntryPointRecord(record_type type = record_type(0), offset_t record_offset = 0)
159 : Record(type, record_offset)
160 {
161 }
162 static constexpr uint8_t DataFlag = 0x01;
163 static constexpr uint8_t ExternFlag = 0x08;
164 static constexpr uint8_t MainFlag = 0x10;
165
166 uint8_t flags = 0;
167 uint16_t entry_id = 0;
168 uint32_t offset = 0;
169
170 void ReadBody(const std::shared_ptr<Linker::Reader>& rd) override;
171 offset_t ImageSize() const override;
172 offset_t WriteFile(const std::shared_ptr<Linker::Writer>& wr) const override;
173 void Dump(Dumper::Dumper& dump, offset_t record_index) const override;
174 };
175
176 class SizeRecord : public Record
177 {
178 public:
179 SizeRecord(record_type type = record_type(0), offset_t record_offset = 0)
180 : Record(type, record_offset)
181 {
182 }
183 static constexpr uint8_t DataFlag = 0x01;
184
185 uint8_t flags = 0;
186 uint32_t module_size = 0;
187
188 void ReadBody(const std::shared_ptr<Linker::Reader>& rd) override;
189 offset_t ImageSize() const override;
190 offset_t WriteFile(const std::shared_ptr<Linker::Writer>& wr) const override;
191 void Dump(Dumper::Dumper& dump, offset_t record_index) const override;
192 };
193
194 class ContentsRecord : public Record
195 {
196 public:
197 ContentsRecord(record_type type = record_type(0), offset_t record_offset = 0)
198 : Record(type, record_offset)
199 {
200 }
201 static constexpr uint8_t DataFlag = 0x01;
202 static constexpr uint8_t PartialFlag = 0x08;
203 static constexpr uint8_t RepeatFlag = 0x10;
204
205 uint8_t flags = 0;
206 uint32_t offset = 0;
207 uint16_t repeat = 0;
208 std::shared_ptr<Linker::Contents> contents;
209
210 void ReadBody(const std::shared_ptr<Linker::Reader>& rd) override;
211 offset_t ImageSize() const override;
212 offset_t WriteFile(const std::shared_ptr<Linker::Writer>& wr) const override;
213 void Dump(Dumper::Dumper& dump, offset_t record_index) const override;
214 };
215
216 class ReferenceRecord : public Record
217 {
218 public:
219 ReferenceRecord(record_type type = record_type(0), offset_t record_offset = 0)
220 : Record(type, record_offset)
221 {
222 }
223 static constexpr uint8_t DataFlag = 0x01;
224 static constexpr uint8_t LongFlag = 0x08;
225 static constexpr uint8_t _16Flag = 0x10;
226 static constexpr uint8_t _8Flag = 0x20;
227 static constexpr uint8_t A5RelativeFlag = 0x80;
228
229 uint8_t flags = 0;
230 uint16_t id = 0;
231 uint16_t id2 = 0; // only for ComputedReference
232 uint16_t repeat = 0;
233 std::vector<uint32_t> offsets;
234
235 void ReadBody(const std::shared_ptr<Linker::Reader>& rd) override;
236 offset_t ImageSize() const override;
237 offset_t WriteFile(const std::shared_ptr<Linker::Writer>& wr) const override;
238 void Dump(Dumper::Dumper& dump, offset_t record_index) const override;
239 };
240
241 class FilenameRecord : public Record
242 {
243 public:
244 FilenameRecord(record_type type = record_type(0), offset_t record_offset = 0)
245 : Record(type, record_offset)
246 {
247 }
248 uint16_t file_id = 0;
249 ::Timestamp<Macintosh_clock> modification;
250
251 void ReadBody(const std::shared_ptr<Linker::Reader>& rd) override;
252 offset_t ImageSize() const override;
253 offset_t WriteFile(const std::shared_ptr<Linker::Writer>& wr) const override;
254 void Dump(Dumper::Dumper& dump, offset_t record_index) const override;
255 };
256
258 {
259 public:
260 SourceStatementRecord(record_type type = record_type(0), offset_t record_offset = 0)
261 : Record(type, record_offset)
262 {
263 }
264 static constexpr uint8_t CodeOffset16Flag = 0x40;
265 static constexpr uint8_t FileOffset16Flag = 0x80;
266
267 uint8_t flags = 0;
268 uint16_t parent_id = 0;
269 uint16_t file_id = 0;
270 std::set<std::tuple<uint32_t, uint32_t>> file_code_offsets;
271
272 void ReadBody(const std::shared_ptr<Linker::Reader>& rd) override;
273 offset_t ImageSize() const override;
274 offset_t WriteFile(const std::shared_ptr<Linker::Writer>& wr) const override;
275 void Dump(Dumper::Dumper& dump, offset_t record_index) const override;
276 };
277
279 {
280 public:
281 ModuleBeginRecord(record_type type = record_type(0), offset_t record_offset = 0)
282 : Record(type, record_offset)
283 {
284 }
285 static constexpr uint8_t IsDeclarationFlag = 0x04;
286 static constexpr uint8_t FileOffset16Flag = 0x80;
287
288 uint8_t flags = 0;
289 uint16_t module_id = 0;
290 uint16_t parent_id = 0;
291 uint16_t file_id = 0;
292 uint32_t file_offset = 0;
293 enum module_kind_type : uint8_t
294 {
295 None = 0,
296 Unit = 2,
297 Procedure = 3,
298 Function = 4,
299 DataModule = 5,
300 };
301 module_kind_type module_kind = module_kind_type(0);
302
303 void ReadBody(const std::shared_ptr<Linker::Reader>& rd) override;
304 offset_t ImageSize() const override;
305 offset_t WriteFile(const std::shared_ptr<Linker::Writer>& wr) const override;
306 void Dump(Dumper::Dumper& dump, offset_t record_index) const override;
307 };
308
309 class ModuleEndRecord : public Record
310 {
311 public:
312 ModuleEndRecord(record_type type = record_type(0), offset_t record_offset = 0)
313 : Record(type, record_offset)
314 {
315 }
316 static constexpr uint8_t IsDeclarationFlag = 0x04;
317
318 uint8_t flags = 0;
319 uint16_t module_id = 0;
320 uint32_t file_offset = 0;
321
322 void ReadBody(const std::shared_ptr<Linker::Reader>& rd) override;
323 offset_t ImageSize() const override;
324 offset_t WriteFile(const std::shared_ptr<Linker::Writer>& wr) const override;
325 void Dump(Dumper::Dumper& dump, offset_t record_index) const override;
326 };
327
329 {
330 public:
331 BlockBeginRecord(record_type type = record_type(0), offset_t record_offset = 0)
332 : Record(type, record_offset)
333 {
334 }
335 static constexpr uint8_t CodeOffset16Flag = 0x40;
336 static constexpr uint8_t FileOffset16Flag = 0x80;
337
338 uint8_t flags = 0;
339 uint16_t block_id = 0;
340 uint16_t parent_id = 0;
341 uint16_t file_id = 0;
342 uint16_t file_offset = 0;
343 uint16_t code_offset = 0;
344
345 void ReadBody(const std::shared_ptr<Linker::Reader>& rd) override;
346 offset_t ImageSize() const override;
347 offset_t WriteFile(const std::shared_ptr<Linker::Writer>& wr) const override;
348 void Dump(Dumper::Dumper& dump, offset_t record_index) const override;
349 };
350
351 class BlockEndRecord : public Record
352 {
353 public:
354 BlockEndRecord(record_type type = record_type(0), offset_t record_offset = 0)
355 : Record(type, record_offset)
356 {
357 }
358 uint16_t block_id = 0;
359 uint16_t file_offset = 0;
360 uint16_t code_offset = 0;
361
362 void ReadBody(const std::shared_ptr<Linker::Reader>& rd) override;
363 offset_t ImageSize() const override;
364 offset_t WriteFile(const std::shared_ptr<Linker::Writer>& wr) const override;
365 void Dump(Dumper::Dumper& dump, offset_t record_index) const override;
366 };
367
369 {
370 public:
371 LocalIdentifierRecord(record_type type = record_type(0), offset_t record_offset = 0)
372 : Record(type, record_offset)
373 {
374 }
376 {
377 uint16_t id = 0;
378 uint16_t type = 0;
379 uint8_t file_delta = 0;
380 enum storage_class_type : uint8_t
381 {
382 Register = 0,
383 A5Relative = 1,
384 A6Relative = 2,
385 A7Relative = 3,
386 Absolute = 4,
387 Constant = 5,
388 };
389 storage_class_type storage_class = storage_class_type(0);
390 bool value = false;
391 bool reference = false;
392 enum offset_size_type : uint8_t
393 {
394 NoOffset = 0,
395 Offset16 = 1,
396 Offset32 = 2,
397 VariableOffset = 3,
398 };
399 offset_size_type offset_size = offset_size_type(0);
400 std::vector<uint8_t> offset_data;
401 };
402
403 static constexpr uint8_t FileOffset16Flag = 0x80;
404
405 uint8_t flags = 0;
406 uint16_t parent_id = 0;
407 uint16_t file_id = 0;
408 uint32_t file_offset = 0;
409 std::vector<Identifier> identifiers;
410
411 void ReadBody(const std::shared_ptr<Linker::Reader>& rd) override;
412 offset_t ImageSize() const override;
413 offset_t WriteFile(const std::shared_ptr<Linker::Writer>& wr) const override;
414 void Dump(Dumper::Dumper& dump, offset_t record_index) const override;
415 };
416
418 {
419 public:
420 LocalLabelRecord(record_type type = record_type(0), offset_t record_offset = 0)
421 : Record(type, record_offset)
422 {
423 }
424
425 static constexpr uint8_t IsEntryFlag = 0x08;
426 static constexpr uint8_t CodeOffset16Flag = 0x40;
427 static constexpr uint8_t FileOffset16Flag = 0x80;
428
429 uint8_t flags = 0;
430 uint16_t parent_id = 0;
431 uint16_t file_id = 0;
432 std::map<std::tuple<uint32_t, uint32_t>, uint16_t> label_ids;
433
434 void ReadBody(const std::shared_ptr<Linker::Reader>& rd) override;
435 offset_t ImageSize() const override;
436 offset_t WriteFile(const std::shared_ptr<Linker::Writer>& wr) const override;
437 void Dump(Dumper::Dumper& dump, offset_t record_index) const override;
438 };
439
440 class LocalTypeRecord : public Record
441 {
442 public:
443 LocalTypeRecord(record_type type = record_type(0), offset_t record_offset = 0)
444 : Record(type, record_offset)
445 {
446 }
447
448 struct Fixup
449 {
450 uint8_t type : 3 = 0;
451 uint16_t data_offset : 13 = 0;
452 uint16_t id = 0;
453 };
454
456 {
457 uint32_t file_offset = 0;
458 uint32_t physical_size = 0;
459 std::vector<uint8_t> type_data;
460 std::vector<Fixup> fixups;
461 };
462
463 static constexpr uint8_t FileOffset16Flag = 0x20;
464 static constexpr uint8_t _16Flag = 0x80;
465
466 uint8_t flags = 0;
467 uint16_t parent_id = 0;
468 uint16_t first_id = 0;
469 uint16_t file_id = 0;
470 std::vector<Declaration> declarations;
471
472 void ReadBody(const std::shared_ptr<Linker::Reader>& rd) override;
473 offset_t ImageSize() const override;
474 offset_t WriteFile(const std::shared_ptr<Linker::Writer>& wr) const override;
475 void Dump(Dumper::Dumper& dump, offset_t record_index) const override;
476 };
477
478 std::vector<std::shared_ptr<Record>> records;
479
480 void ReadFile(const std::shared_ptr<Linker::Reader>& rd) override;
481 offset_t ImageSize() const override;
482 offset_t WriteFile(const std::shared_ptr<Linker::Writer>& wr) const override;
483 void Dump(Dumper::Dumper& dump) const override;
484 };
485}
486
487#endif /* _MPWOBJ_H */
An abstract interface that separates structure and presentation of the data inside a file.
Definition dumper.h:1009
A class to encode a general file format.
Definition format.h:29
Definition mpwobj.h:352
Definition mpwobj.h:96
Definition mpwobj.h:195
Definition mpwobj.h:242
Definition mpwobj.h:71
Definition mpwobj.h:441
Definition mpwobj.h:310
Definition mpwobj.h:130
Definition mpwobj.h:26
Definition mpwobj.h:217
Definition mpwobj.h:177
Definition mpwobj.h:23
offset_t ImageSize() const override
Retrieves the offset of the byte after the last one belonging to this format from the first one.
Definition mpwobj.cc:1380
void ReadFile(const std::shared_ptr< Linker::Reader > &rd) override
Loads file into memory.
Definition mpwobj.cc:1367
void Dump(Dumper::Dumper &dump) const override
Display file contents in a nice manner.
Definition mpwobj.cc:1400
offset_t WriteFile(const std::shared_ptr< Linker::Writer > &wr) const override
Stores data in memory to file.
Definition mpwobj.cc:1390