RetroLinker
Linker for several 8-bit, 16-bit and 32-bit formats
Loading...
Searching...
No Matches
macos.h
1#ifndef MACOS_H
2#define MACOS_H
3
4#include <cstring>
5#include <filesystem>
6#include <optional>
7#include <set>
8#include <vector>
9#include "apple.h"
10#include "../dumper/dumper.h"
11#include "../linker/module.h"
12#include "../linker/options.h"
13#include "../linker/segment.h"
14#include "../linker/segment_manager.h"
15#include "../linker/writer.h"
16#include "../runtime/resource.h"
17
18/* Classic 68000 Mac OS file formats */
19
20namespace Apple
21{
22 typedef char OSType[4];
23
24 static constexpr uint32_t OSTypeToUInt32(char type0, char type1, char type2, char type3)
25 {
26 return
27 (uint32_t(uint8_t(type0)) << 24)
28 | (uint32_t(uint8_t(type1)) << 16)
29 | (uint32_t(uint8_t(type2)) << 8)
30 | uint32_t(uint8_t(type3));
31 }
32
33 uint32_t OSTypeToUInt32(const OSType& type);
34 void UInt32ToOSType(OSType& type, uint32_t value);
35
36 /* TODO: rework with Linker::Format */
37
47 {
48 public:
49 bool FormatSupportsResources() const override;
50 bool FormatSupportsEntryTable() const override; // TODO: not yet implemented
51
59 memory_model_t memory_model = MODEL_DEFAULT;
60
62 {
63 public:
64 Linker::Option<bool> _32{"32", "Make 32-bit clean"};
65 Linker::Option<bool> far{"far", "Far code and data (32-bit Everything) [not implemented]"}; // TODO: not implemented
66
68 {
69 InitializeFields(_32, far);
70 }
71 };
72
73 std::shared_ptr<Linker::OptionCollector> GetOptions() override;
74 void SetOptions(std::map<std::string, std::string>& options) override;
75
76 static std::vector<Linker::OptionDescription<void>> MemoryModelNames;
77 std::vector<Linker::OptionDescription<void>> GetMemoryModelNames() override;
78 void SetModel(std::string model) override;
79
83 class Resource : public Linker::Format
84 {
85 public:
87 virtual void ReadFile(const std::shared_ptr<Linker::Reader>& rd, offset_t length) = 0;
88 void Dump(Dumper::Dumper& dump) const override;
89 virtual int GetDisplayOptions() const;
90 virtual void Dump(Dumper::Dumper& dump, offset_t file_offset) const;
91 virtual void AddFields(Dumper::Dumper& dump, Dumper::Region& region, offset_t file_offset) const;
92 virtual std::unique_ptr<Dumper::Region> CreateRegion(std::string name, offset_t offset, offset_t length, unsigned display_width) const;
94 virtual void EffectFormat(MacintoshResourceFileFormat& format, const std::shared_ptr<Linker::Reader>& rd);
95
96 protected:
97 Resource(const char type[4], uint16_t id, uint8_t attributes = 0)
98 : id(id), attributes(attributes)
99 {
100 memcpy(this->type, type, 4);
101 }
102
103 Resource(const char type[4], uint16_t id, std::optional<std::string> name, uint8_t attributes = 0)
104 : id(id), name(name), attributes(attributes)
105 {
106 memcpy(this->type, type, 4);
107 }
108
109 public:
110 char type[4];
111 uint16_t id;
112
113 std::optional<std::string> name;
114 uint8_t attributes;
115
116 offset_t ImageSize() const override = 0;
117
118 virtual void CalculateValues() = 0;
119 };
120
125 {
126 public:
127 GenericResource(const char type[4], uint16_t id)
128 : Resource(type, id)
129 {
130 }
131
133 std::shared_ptr<Linker::Contents> image;
134
135 void CalculateValues() override;
136
137 offset_t ImageSize() const override;
138
139 void ReadFile(const std::shared_ptr<Linker::Reader>& rd) override;
140 void ReadFile(const std::shared_ptr<Linker::Reader>& rd, offset_t length) override;
141
143 offset_t WriteFile(const std::shared_ptr<Linker::Writer>& wr) const override;
144 using Resource::Dump;
145 std::unique_ptr<Dumper::Region> CreateRegion(std::string name, offset_t offset, offset_t length, unsigned display_width) const override;
146 };
147
149 struct Location
150 {
161
162 uint16_t segment = 0;
163 uint32_t section = 0;
164 uint32_t offset = 0;
165
166 bool IsSegmented() const
167 {
168 return type == segmented;
169 }
170
171 bool IsSectioned() const
172 {
173 return type == sectioned;
174 }
175
176 bool IsAbsolute() const
177 {
178 return type == absolute;
179 }
180
182 static Location Segmented(uint16_t segment, uint32_t offset)
183 {
184 return Location{segmented, segment, 0, offset};
185 }
186
188 static Location Sectioned(uint32_t section, uint32_t offset)
189 {
190 return Location{sectioned, 0, section, offset};
191 }
192
193 bool operator ==(const Location& other) const
194 {
195 if(type != other.type)
196 return false;
197 switch(type)
198 {
199 case segmented:
200 return offset == other.offset && segment == other.segment;
201 case sectioned:
202 return offset == other.offset && section == other.section;
203 case absolute:
204 return offset == other.offset;
205 default:
206 assert(false);
207 }
208 }
209
210 bool operator <(const Location& other) const
211 {
212 // should not compare locations of different types, but this will do as a fallback
213 if(type < other.type)
214 return true;
215 else if(type > other.type)
216 return false;
217
218 switch(type)
219 {
220 case segmented:
221 return segment < other.segment || (segment == other.segment && offset < other.offset);
222 case sectioned:
223 return section < other.section || (section == other.section && offset < other.offset);
224 case absolute:
225 return offset < other.offset;
226 default:
227 assert(false);
228 }
229 }
230 };
231
234 {
235 public:
237 struct Entry
238 {
239 uint16_t segment;
240 uint32_t offset;
242 std::optional<uint32_t> section;
243 };
244
247 {
248 std::optional<uint32_t> seg_loader_section;
249 uint32_t seg_loader_offset;
250 std::optional<uint32_t> a5_section;
251 uint32_t a5_offset;
252 uint16_t segment;
253 std::optional<uint32_t> section;
254 uint32_t offset;
255 };
256
257 uint32_t above_a5 = 0;
258 uint32_t below_a5 = 0;
259 uint32_t jump_table_size = 0;
260 uint32_t jump_table_offset = 32; // seems to be fixed for Macintosh programs
262 std::vector<Entry> legacy_entries;
264 std::vector<Entry> extended_entries;
265 std::vector<TransitionVector> transition_vectors;
266
271 {
272 assert(entry.IsSegmented());
273 legacy_entries.push_back(Entry{entry.segment, entry.offset});
274 }
275
282 {
283 assert(entry.IsSegmented());
284 extended_entries.push_back(Entry{entry.segment, entry.offset});
285 }
286
293 {
294 assert(entry.IsSectioned());
295 extended_entries.push_back(Entry{0, entry.offset, entry.section});
296 }
297
304 {
305 assert(seg_loader.IsSectioned());
306 assert(a5_world.IsSectioned());
307 assert(entry.IsSegmented());
308 transition_vectors.push_back(TransitionVector{seg_loader.section, seg_loader.offset, a5_world.section, a5_world.offset, entry.segment, {}, entry.offset});
309 }
310
317 {
318 assert(a5_world.IsSectioned());
319 assert(entry.IsSegmented());
320 transition_vectors.push_back(TransitionVector{{}, 0, a5_world.section, a5_world.offset, entry.segment, {}, entry.offset});
321 }
322
329 {
330 assert(a5_world.IsSectioned());
331 assert(entry.IsSectioned());
332 transition_vectors.push_back(TransitionVector{{}, 0, a5_world.section, a5_world.offset, 0, entry.section, entry.offset});
333 }
334 };
335
338 {
339 public:
340 std::shared_ptr<JumpTable> jump_table;
341
342 JumpTableCodeResource(std::shared_ptr<JumpTable> jump_table)
343 : Resource("CODE", 0), jump_table(jump_table)
344 {
345 }
346
348 : JumpTableCodeResource(std::make_shared<JumpTable>())
349 {
350 }
351
373 JumpTableFormat jump_table_format = Near;
374
375 bool IsResource() const
376 {
377 switch(jump_table_format)
378 {
379 case Near:
380 case Far:
381 case CFM_68K_StartUp:
382 return true;
383 default:
384 return false;
385 }
386 }
387
388 void CalculateValues() override;
389
390 offset_t JumpTableSize() const;
391
392 offset_t ImageSize() const override;
393
394 enum
395 {
396 MOVE_DATA_SP = 0x3F3C,
397 LOADSEG = 0xA9F0,
398 JMP_ABS_L = 0x4EF9,
399
400 FAR_VERSION_MARK = 0xFFFF,
401 CFM_68K_VERSION_MARK = 0xFFFD,
402 };
403
404 void ReadFile(const std::shared_ptr<Linker::Reader>& rd) override;
405 void ReadFile(const std::shared_ptr<Linker::Reader>& rd, offset_t length) override;
406
417
428 void ReadJumpTable(const std::shared_ptr<Linker::Reader>& rd, offset_t length, jump_table_parse_mode mode, std::map<offset_t, offset_t> section_relocations = {});
429
431 void CollectRelocations(std::map<offset_t, offset_t>& section_relocations);
432
434 offset_t WriteFile(const std::shared_ptr<Linker::Writer>& wr) const override;
436 int GetDisplayOptions() const override;
437 void Dump(Dumper::Dumper& dump, offset_t file_offset) const override;
438 void AddFields(Dumper::Dumper& dump, Dumper::Region& region, offset_t file_offset) const override;
439 std::unique_ptr<Dumper::Region> CreateRegion(std::string name, offset_t offset, offset_t length, unsigned display_width) const override;
440 };
441
443 class CodeResource : public Resource
444 {
445 public:
446 static constexpr uint32_t OSType = OSTypeToUInt32('C', 'O', 'D', 'E');
447
448 static constexpr uint32_t NearSegmentHeaderSize = 0x4;
449 static constexpr uint32_t FarSegmentHeaderSize = 0x28;
450
451 std::shared_ptr<JumpTableCodeResource> jump_table;
452 std::shared_ptr<Linker::Contents> image;
453 uint32_t zero_fill = 0; // used for code generation
454
455 CodeResource(uint16_t id, std::shared_ptr<JumpTableCodeResource> jump_table = nullptr)
456 : Resource("CODE", id), jump_table(jump_table)/*, image("code")*/
457 {
458 }
459
469 HeaderFormat header_format = Near;
470 uint32_t a5_address = 0; /* TODO: meaning */
471 uint32_t base_address = 0;
472
473 // used for generation
474 std::set<uint32_t> near_entries;
475 uint16_t near_entry_count = 0;
476 std::set<uint32_t> far_entries;
477 uint16_t far_entry_count = 0;
478 std::set<uint32_t> a5_relocations;
479 std::set<uint32_t> segment_relocations;
482 {
483 uint32_t offset = 0;
484 Location a5_world { Location::segmented };
485
486 bool operator ==(const TransitionVector& other) const
487 {
488 return offset == other.offset && a5_world == other.a5_world;
489 }
490
491 bool operator <(const TransitionVector& other) const
492 {
493 // TODO: normally we could expect two transition vectors with identical offsets to have the same A5 world (is this true?),
494 // but technically it is possible to have separate ones, so we need to compare them as well
495 return offset < other.offset || (offset == other.offset && a5_world < other.a5_world);
496 }
497 };
498 std::set<TransitionVector> transition_vectors;
499 uint32_t transition_vector_count = 0;
500 // stored when processing a module, which offsets require a jump table entry
501 std::map<uint32_t, std::vector<Linker::Relocation>> entry_relocations;
502 std::map<TransitionVector, std::vector<Linker::Relocation>> tvector_relocations;
503
504 /* filled in after calculation */
505 uint32_t first_near_entry_offset;
506 uint32_t first_far_entry_offset;
507 uint32_t first_transition_vector_offset;
508 uint32_t a5_relocation_offset;
509 uint32_t segment_relocation_offset;
510 uint32_t resource_size;
511
520 std::shared_ptr<JumpTableCodeResource> jump_table,
521 uint32_t& jump_table_offset,
522 std::optional<uint32_t> starting_entry = {});
523
532 std::shared_ptr<JumpTableCodeResource> jump_table,
533 uint32_t& jump_table_offset,
534 std::optional<uint32_t> starting_entry = {});
535
543 std::shared_ptr<JumpTableCodeResource> jump_table,
544 uint32_t& jump_table_offset);
545
555 std::shared_ptr<JumpTableCodeResource> jump_table,
556 uint32_t& jump_table_offset,
557 Location seg_loader,
558 std::optional<TransitionVector> starting_tvector = {});
559
560 void CalculateValues() override;
561
562 offset_t ImageSize() const override;
563
564 void ReadFile(const std::shared_ptr<Linker::Reader>& rd) override;
565 void ReadFile(const std::shared_ptr<Linker::Reader>& rd, offset_t length) override;
566
567 uint32_t MeasureRelocations(std::set<uint32_t>& relocations) const;
568
569 void ReadRelocations(const std::shared_ptr<Linker::Reader>& rd, std::set<uint32_t>& relocations) const;
570 void WriteRelocations(const std::shared_ptr<Linker::Writer>& wr, const std::set<uint32_t>& relocations) const;
571
573 offset_t WriteFile(const std::shared_ptr<Linker::Writer>& wr) const override;
575 int GetDisplayOptions() const override;
576 void Dump(Dumper::Dumper& dump, offset_t file_offset) const override;
577 void AddFields(Dumper::Dumper& dump, Dumper::Region& region, offset_t file_offset) const override;
578 };
579
581 class SizeResource : public Resource
582 {
583 public:
584 static constexpr uint32_t OSType = OSTypeToUInt32('S', 'I', 'Z', 'E');
585 static constexpr uint32_t ExpectedLength = 10;
586
587 enum target_type
588 {
589 Classic24,
590 Classic32,
591 AUX32,
592 Carbon,
593 };
594
596 static constexpr uint16_t SaveScreen = 0x8000;
597 static constexpr uint16_t AcceptSuspendResumeEvents = 0x4000;
599 static constexpr uint16_t DisableOptionSwitch = 0x2000;
600 static constexpr uint16_t CanBackground = 0x1000;
601 static constexpr uint16_t MultiFinderAware = 0x0800;
602 static constexpr uint16_t OnlyBackground = 0x0400;
603 static constexpr uint16_t GetFrontClicks = 0x0200;
604 static constexpr uint16_t AcceptChildDiedEvents = 0x0100;
605 static constexpr uint16_t Is32BitCompatible = 0x0080;
606 static constexpr uint16_t IsHighLevelEventAware = 0x0040;
607 static constexpr uint16_t LocalAndRemoteHLEvents = 0x0020;
608 static constexpr uint16_t IsStationaryAware = 0x0010;
609 static constexpr uint16_t UseTextEditServices = 0x0008;
610 static constexpr uint16_t DisplayManagerAware = 0x0004;
611
612 uint16_t flags = 0;
613 uint32_t preferred_memory = 0;
614 uint32_t minimum_memory = 0;
615
616 static constexpr uint16_t GetDefaultFlags(target_type target)
617 {
618 switch(target)
619 {
620 default:
621 case Classic24:
622 return 0;
623 case Classic32:
624 return Is32BitCompatible;
625 case AUX32:
626 // based on A/UX tools
627 return AcceptSuspendResumeEvents | MultiFinderAware | GetFrontClicks | Is32BitCompatible;
628 case Carbon:
629 // based on libretro flags
630 return AcceptSuspendResumeEvents | CanBackground | MultiFinderAware | IsHighLevelEventAware;
631 }
632 }
633
634 static constexpr uint32_t GetDefaultMemory(target_type target)
635 {
636 switch(target)
637 {
638 case Classic24:
639 case Classic32:
640 return 100 * 1024;
641 case AUX32:
642 // based on A/UX tools
643 return 32 * 1024;
644 default:
645 case Carbon:
646 // according to Wolfgang Thaller (wdefshell.r)
647 return 500 * 1024;
648 }
649 }
650
651 SizeResource()
652 : Resource("SIZE", 0xFFFF)
653 {
654 }
655
656 SizeResource(target_type target)
657 : Resource("SIZE", 0xFFFF),
658 flags(GetDefaultFlags(target)),
659 preferred_memory(GetDefaultMemory(target)),
660 minimum_memory(GetDefaultMemory(target))
661 {
662 }
663
664 void CalculateValues() override;
665
666 offset_t ImageSize() const override;
667
668 void ReadFile(const std::shared_ptr<Linker::Reader>& rd) override;
669 void ReadFile(const std::shared_ptr<Linker::Reader>& rd, offset_t length) override;
670
672 offset_t WriteFile(const std::shared_ptr<Linker::Writer>& wr) const override;
673 int GetDisplayOptions() const override;
674 //using Linker::Format::Dump;
675 //void Dump(Dumper::Dumper& dump, offset_t file_offset) const override;
676 void AddFields(Dumper::Dumper& dump, Dumper::Region& region, offset_t file_offset) const override;
677 //std::unique_ptr<Dumper::Region> CreateRegion(std::string name, offset_t offset, offset_t length, unsigned display_width) const override;
678 };
679
682 {
683 public:
684 static constexpr uint32_t OSType = OSTypeToUInt32('c', 'f', 'r', 'g');
685
686 class Member
687 {
688 public:
689 enum architecture_type : uint32_t
690 {
691 PowerPC = OSTypeToUInt32('p', 'w', 'p', 'c'),
692 Motorola68K = OSTypeToUInt32('m', '6', '8', 'k'),
693 //Compiled // not an actual architecture but a compiler macro
694 };
695 architecture_type architecture;
696 enum update_level_type : uint8_t
697 {
698 FullLib = 0,
699 UpdateLib = 1,
700 };
701 update_level_type update_level = FullLib;
702 uint32_t current_version = 0;
703 uint32_t old_def_version = 0;
704 static constexpr uint32_t DefaultStackSize = 0;
705 uint32_t app_stack_size = 0;
706 static constexpr int16_t NoAppSubFolder = 0;
707 int16_t app_subdir_id = 0;
708 enum usage_type : uint8_t
709 {
710 ImportLibrary = 0,
711 Application = 1,
712 DropInAddition = 2,
713 StubLibrary = 3,
714 WeakStubLibrary = 4,
715 };
716 usage_type usage;
717 enum where_type : uint8_t
718 {
719 Memory = 0,
720 DataFork = 1,
721 Resource = 2,
722 NamedFragment = 3, // reserved
723 CFBundle = 4,
724 CFBundleInt = 5,
725 };
726 where_type where = DataFork;
727 static constexpr uint32_t RSEG = OSTypeToUInt32('r', 's', 'e', 'g');
728 uint32_t offset = 0;
729 static constexpr uint32_t CFragGoesToEOF = 0;
730 uint32_t length = 0;
731 uint32_t space_id = 0;
732 uint16_t extension_count = 0;
733 uint16_t member_size = 0x38;
734 std::string name;
735
736 Member(architecture_type architecture)
737 : architecture(architecture)
738 {
739 }
740
741 offset_t ImageSize() const;
742 static std::shared_ptr<Member> ReadFile(const std::shared_ptr<Linker::Reader>& rd);
743 offset_t WriteFile(const std::shared_ptr<Linker::Writer>& wr) const;
744
745 static std::shared_ptr<Member> CreateEmpty()
746 {
747 return std::make_shared<Member>(architecture_type(0));
748 }
749
751 static std::shared_ptr<Member> CreateApplication(architecture_type architecture, std::string name)
752 {
753 std::shared_ptr<Member> member = std::make_shared<Member>(architecture);
754 member->update_level = FullLib;
755 member->current_version = 0;
756 member->old_def_version = 0;
757 member->app_stack_size = DefaultStackSize;
758 member->app_subdir_id = NoAppSubFolder;
759 member->usage = Application;
760 if(architecture == Motorola68K)
761 {
762 member->where = Resource;
763 member->offset = RSEG;
764 member->length = 0;
765 }
766 else
767 {
768 member->where = DataFork;
769 member->offset = 0;
770 member->length = CFragGoesToEOF;
771 }
772 member->name = name;
773 if(member->name.size() > 15)
774 {
775 member->name = member->name.substr(0, 15);
776 }
777 return member;
778 }
779
781 static std::shared_ptr<Member> CreateLibrary(architecture_type architecture, std::string name, uint32_t current_version, uint32_t old_def_version)
782 {
783 std::shared_ptr<Member> member = std::make_shared<Member>(architecture);
784 member->update_level = FullLib;
785 member->current_version = current_version;
786 member->old_def_version = old_def_version;
787 member->app_stack_size = DefaultStackSize;
788 member->app_subdir_id = NoAppSubFolder;
789 member->usage = ImportLibrary;
790 member->where = DataFork;
791 member->offset = 0;
792 member->length = CFragGoesToEOF;
793 member->name = name;
794 if(member->name.size() > 15)
795 {
796 member->name = member->name.substr(0, 15);
797 }
798 return member;
799 }
800 };
801
802 uint16_t version = 1;
803 std::vector<std::shared_ptr<Member>> members;
804
806 : Resource("cfrg", 0x0000)
807 {
808 }
809
810 void CalculateValues() override;
811
812 offset_t ImageSize() const override;
813
814 void ReadFile(const std::shared_ptr<Linker::Reader>& rd) override;
815 void ReadFile(const std::shared_ptr<Linker::Reader>& rd, offset_t length) override;
816
818 offset_t WriteFile(const std::shared_ptr<Linker::Writer>& wr) const override;
819 int GetDisplayOptions() const override;
821 void Dump(Dumper::Dumper& dump, offset_t file_offset) const override;
822 void AddFields(Dumper::Dumper& dump, Dumper::Region& region, offset_t file_offset) const override;
823 //std::unique_ptr<Dumper::Region> CreateRegion(std::string name, offset_t offset, offset_t length, unsigned display_width) const override;
824
825 void EffectFormat(MacintoshResourceFileFormat& format, const std::shared_ptr<Linker::Reader>& rd) override;
826 };
827
828 MacintoshResourceFileFormat()
829 /*: a5world(".bss")*/
830 {
831 }
832
834 {
835 uint16_t id = 0;
836 uint16_t name_offset = 0xFFFF;
837 std::optional<std::string> name;
838 uint8_t attributes = 0;
839 uint32_t data_offset = 0;
840 std::shared_ptr<Resource> data;
841 };
842
844 {
845 OSType type { 0, 0, 0, 0 };
846 uint32_t count = 0;
847 uint16_t offset = 0;
848 std::vector<ResourceReference> references;
849 };
850
851 static std::shared_ptr<Resource> ReadResource(const std::shared_ptr<Linker::Reader>& rd, const ResourceType& type, const ResourceReference& reference);
852
853 uint16_t attributes = 0; /* TODO: parametrize */
854 /* command line parameter */
855 bool use_far_segments = false;
857 std::vector<ResourceType> resource_types;
859 std::vector<std::string> resource_names;
860
862 std::map<uint32_t, std::map<uint16_t, std::shared_ptr<Resource>>> resources;
863
864 /* these will be calculated */
865 uint32_t data_offset = 0, data_length = 0, map_offset = 0, map_length = 0;
866 uint16_t resource_type_list_offset = 28;
867 uint16_t name_list_offset = 0;
868
869 /* filled in during generation */
870 std::shared_ptr<JumpTableCodeResource> jump_table;
871 std::vector<std::shared_ptr<CodeResource>> codes;
872 std::map<std::shared_ptr<Linker::Segment>, std::shared_ptr<CodeResource>> segment_to_resource_map;
873 std::shared_ptr<Linker::Segment> a5world;
874 std::shared_ptr<SizeResource> size_resource = nullptr;
875
876 void AddResource(std::shared_ptr<Resource> resource);
877 std::shared_ptr<Resource> FindResource(const OSType& type, uint16_t id);
878 ResourceReference * FindResourceReference(const OSType& type, uint16_t id);
879
880 void OnNewSegment(std::shared_ptr<Linker::Segment> segment) override;
881
882 std::unique_ptr<Script::List> GetScript(Linker::Module& module);
883
884 void Link(Linker::Module& module);
885
887 static bool CheckA5Relative(Linker::Relocation& rel);
888
889 void ProcessRelocations(Linker::Module& module);
890
891 void AllocateJumpTableEntries(JumpTableCodeResource::JumpTableFormat format);
892 void AllocateTransitionVectors(JumpTableCodeResource::JumpTableFormat format);
893
894 void BuildNearModelJumpTable(std::shared_ptr<CodeResource> entry_segment, uint32_t entry_offset);
895 void BuildFarModelJumpTable(std::shared_ptr<CodeResource> init_segment, uint32_t init_offset, std::shared_ptr<CodeResource> entry_segment, uint32_t entry_offset);
896 void BuildCFM68KJumpTable(std::shared_ptr<CodeResource> init_segment, uint32_t init_offset, std::shared_ptr<CodeResource> entry_segment, uint32_t entry_offset, std::optional<uint32_t> seg_loader_section, uint32_t seg_loader_offset, std::optional<uint32_t> a5_section, uint32_t a5_offset);
897
898 void ProcessModule(Linker::Module& module) override;
899
900 void CalculateValues() override;
901
902 offset_t ImageSize() const override;
903
904 void ReadFile(const std::shared_ptr<Linker::Reader>& rd) override;
905
907 offset_t WriteFile(const std::shared_ptr<Linker::Writer>& wr) const override;
908
909 void Dump(Dumper::Dumper& dump) const override;
910
911 void GenerateFile(std::string filename, Linker::Module& module) override;
912
914 std::string GetDefaultExtension(Linker::Module& module) const override;
915
916
919 {
920 public:
921 ResourceType resource_type;
922 ResourceReference resource_reference;
923
924 ResourceInformation(ResourceType resource_type, ResourceReference resource_reference)
925 : resource_type(resource_type), resource_reference(resource_reference)
926 {
927 }
928
929 Runtime::Value GetProperties() const override;
930 };
931
933 {
934 public:
935 std::vector<ResourceType>& resource_types;
936 mutable std::vector<ResourceType>::iterator resource_types_iterator;
937 mutable std::vector<ResourceReference>::iterator resource_references_iterator;
938
940 std::vector<ResourceType>& resource_types,
941 std::vector<ResourceType>::iterator resource_types_iterator,
942 std::vector<ResourceReference>::iterator resource_references_iterator)
943 : resource_types(resource_types), resource_types_iterator(resource_types_iterator), resource_references_iterator(resource_references_iterator)
944 {
945 }
946
947 void Step() const override;
948 std::shared_ptr<const Runtime::Resource> Get() const override;
949 bool SameAs(const Runtime::ResourceIterator * other) const override;
950 void Erase() override;
951 };
952
953 Runtime::ResourceIterable& Iterate() override;
954 std::shared_ptr<Runtime::ResourceIterator> BeginIteration() override;
955 std::shared_ptr<Runtime::ResourceIterator> EndOfIteration() override;
956 std::shared_ptr<Runtime::ResourceIterator> FindResource(const Runtime::Value& value) override;
957 bool UpdateResource(std::shared_ptr<Runtime::Resource> resource) override;
958 };
959
968 {
969 public:
986
999
1000 /* Typical combinations:
1001 * - Executor: Generate a data fork and an AppleDouble with % prefix
1002 * - Basilisk: Generate a data fork, a resource fork (under .rsrc) and a Finder Info file (under .finf)
1003 * - Generate a MacBinary with .mbin extension
1004 * - Generate an AppleSingle
1005 */
1006
1011 : produce_format_t(0)))
1012 {
1013 }
1014
1015 MacintoshOutputDriver(target_format_t target, int produce)
1016 : OutputDriver(OutputDriver::target_format_t(target), OutputDriver::produce_format_t(produce))
1017 {
1018 }
1019
1021 std::shared_ptr<MacintoshResourceFileFormat> resource_fork;
1022
1023 protected:
1024 bool SupportedSupplementaryFormat(OutputDriver::produce_format_t produce) override;
1025
1027 void GenerateFiles(std::string filename, std::shared_ptr<Contents> data_fork, std::shared_ptr<Contents> resource_fork);
1028 };
1029
1034 {
1035 public:
1038 {
1039 }
1040
1043 {
1044 }
1045
1046 bool FormatSupportsResources() const override;
1047 bool FormatSupportsEntryTable() const override; // TODO: not yet implemented
1048
1049 private:
1050 std::shared_ptr<FinderInfo> finder_info;
1051
1052 std::map<std::string, std::string> options;
1053 std::string model;
1054 std::string script_file;
1055 std::map<std::string, std::string> script_options;
1056
1057 public:
1058 // TODO: extend OutputDriver::DriverOptionCollector
1060 {
1061 public:
1062 class MacBinaryVersionEnumerator : public Linker::Enumeration<MacBinary::version_t>
1063 {
1064 public:
1066 : Enumeration(
1067 "1", MacBinary::MACBIN1,
1068 "GETINFO", MacBinary::MACBIN1_GETINFO,
1069 "2", MacBinary::MACBIN2,
1070 "3", MacBinary::MACBIN3)
1071 {
1072 descriptions = {
1073 { MacBinary::MACBIN1, "Revision 1 (1985)" },
1074 { MacBinary::MACBIN1_GETINFO, "Revision 1 (1985) with Get Info extension" },
1075 { MacBinary::MACBIN2, "MacBinary II, Revision 2 (1987)" },
1076 { MacBinary::MACBIN3, "MacBinary III, Revision 3 (1987)" },
1077 };
1078 }
1079 };
1080
1081 Linker::Option<std::optional<offset_t>> asver{"asver", "Version of the AppleSingle/AppleDouble container (recognized values: 1, 2)"};
1082 Linker::Option<std::optional<offset_t>> adver{"adver", "Version of the AppleSingle/AppleDouble container (recognized values: 1, 2)"};
1083 Linker::Option<std::optional<Linker::ItemOf<MacBinaryVersionEnumerator>>> mbinver{"mbinver", "Version of the MacBinary container"};
1084 Linker::Option<std::optional<Linker::ItemOf<MacBinaryVersionEnumerator>>> minmbinver{"minmbinver", "Minimum required version for the MacBinary container"};
1085
1086 DriverOptionCollector()
1087 : MacintoshOptionCollector()
1088 // TODO: if OutputDriver::DriverOptionCollector is created, call its too constructor
1089 {
1090 InitializeFields(asver, adver, mbinver, minmbinver);
1091 }
1092 };
1093
1094 std::shared_ptr<Linker::OptionCollector> GetOptions() override;
1095 void SetOptions(std::map<std::string, std::string>& options) override;
1096
1097 std::vector<Linker::OptionDescription<void>> GetMemoryModelNames() override;
1098 void SetModel(std::string model) override;
1099
1100 void SetLinkScript(std::string script_file, std::map<std::string, std::string>& options) override;
1101
1102 void CalculateValues() override;
1103 void GenerateFile(std::string filename, Linker::Module& module) override;
1104
1105 protected:
1106 void OnContainerCreated() override;
1107 void OnReadFile(const std::shared_ptr<Linker::Reader>& rd) override;
1108 offset_t OnWriteFile(const std::shared_ptr<Linker::Writer>& wr) const override;
1109 void OnDump(Dumper::Dumper& dump) const override;
1110
1111 public:
1112 void ReadFile(const std::shared_ptr<Linker::Reader>& rd) override;
1113
1114 std::string GetDefaultExtension(Linker::Module& module) const override;
1115 std::string GetDefaultExtension(Linker::Module& module, std::string filename) const override;
1116 };
1117}
1118
1119#endif /* MACOS_H */
Interface to generate files required for the Classic 68K Mac OS runtime.
Definition macos.h:1034
void GenerateFile(std::string filename, Linker::Module &module) override
The main function that handles processing, calculating and generating the final image.
Definition macos.cc:2593
void ReadFile(const std::shared_ptr< Linker::Reader > &rd) override
Loads file into memory.
Definition macos.cc:2651
std::shared_ptr< Linker::OptionCollector > GetOptions() override
Returns object containing a sequence of option fields provided with the -S command line flag.
Definition macos.cc:2499
void CalculateValues() override
Intermediate step between processing module and generating output file to set up headers and manageme...
Definition macos.cc:2622
void OnContainerCreated() override
Called after the container is created.
Definition macos.cc:2610
void SetLinkScript(std::string script_file, std::map< std::string, std::string > &options) override
Selects a script file to use for linking.
Definition macos.cc:2587
void SetModel(std::string model) override
Sets the way memory is organized, typically modifying a built-in script.
Definition macos.cc:2582
bool FormatSupportsEntryTable() const override
Whether the format supports a structure containing addresses of methods.
Definition macos.cc:2494
bool FormatSupportsResources() const override
Whether the format supports resources.
Definition macos.cc:2489
void OnDump(Dumper::Dumper &dump) const override
Called if there is no container allocated.
Definition macos.cc:2646
offset_t OnWriteFile(const std::shared_ptr< Linker::Writer > &wr) const override
Called if there is no container allocated.
Definition macos.cc:2641
std::string GetDefaultExtension(Linker::Module &module) const override
Provides a default filename for the output file.
Definition macos.cc:2661
void SetOptions(std::map< std::string, std::string > &options) override
Passes command line parameters as settings over to format object.
Definition macos.cc:2504
std::vector< Linker::OptionDescription< void > > GetMemoryModelNames() override
Returns a list of the supported memory models, used for documentation.
Definition macos.cc:2576
void OnReadFile(const std::shared_ptr< Linker::Reader > &rd) override
Called if there is no container allocated.
Definition macos.cc:2627
This is not actually a file format, but an interface to permit generating multiple binary outputs for...
Definition macos.h:968
std::shared_ptr< MacintoshResourceFileFormat > resource_fork
Definition macos.h:1021
target_format_t
Represents the file type of the main file.
Definition macos.h:972
@ TARGET_DATA_FORK
Main file is a data fork, typically empty.
Definition macos.h:976
@ TARGET_NONE
Do not generate main file.
Definition macos.h:974
@ TARGET_MAC_BINARY
Main file as a MacBinary.
Definition macos.h:984
@ TARGET_APPLE_SINGLE
Main file is an AppleSingle.
Definition macos.h:980
@ TARGET_APPLE_DOUBLE
Main file is an AppleDouble.
Definition macos.h:982
@ TARGET_RESOURCE_FORK
Main file is a resource fork.
Definition macos.h:978
produce_format_t
Represents what additional files should be generated.
Definition macos.h:989
@ PRODUCE_MAC_BINARY
Creates a MacBinary with the .mbin extension.
Definition macos.h:997
@ PRODUCE_FINDER_INFO
Places a Finder Information file under the directory .finf.
Definition macos.h:993
@ PRODUCE_APPLE_DOUBLE
Creates an AppleDouble binary with the '' prefix.
Definition macos.h:995
@ PRODUCE_RESOURCE_FORK
Places a Macintosh format resource file under the directory .rsrc.
Definition macos.h:991
void GenerateFiles(std::string filename, std::shared_ptr< Contents > data_fork, std::shared_ptr< Contents > resource_fork)
Tasked to create all the requested files.
Definition macos.cc:2482
static std::shared_ptr< Member > CreateLibrary(architecture_type architecture, std::string name, uint32_t current_version, uint32_t old_def_version)
Initialize with default settings.
Definition macos.h:781
static std::shared_ptr< Member > CreateApplication(architecture_type architecture, std::string name)
Initialize with default settings.
Definition macos.h:751
Stores a 'cfrg'0 resource, used to store PowerPC and CFM-68K code fragments.
Definition macos.h:682
offset_t ImageSize() const override
Retrieves the offset of the byte after the last one belonging to this format from the first one.
Definition macos.cc:1336
void ReadFile(const std::shared_ptr< Linker::Reader > &rd) override
Loads file into memory.
Definition macos.cc:1346
offset_t WriteFile(const std::shared_ptr< Linker::Writer > &wr) const override
Stores data in memory to file.
Definition macos.cc:1366
void EffectFormat(MacintoshResourceFileFormat &format, const std::shared_ptr< Linker::Reader > &rd) override
Apply some changes to the format after parsing.
Definition macos.cc:1513
Stores as 68K code segment, found in 'CODE' resources.
Definition macos.h:444
void StoreTransitionVectorEntries(std::shared_ptr< JumpTableCodeResource > jump_table, uint32_t &jump_table_offset, Location seg_loader, std::optional< TransitionVector > starting_tvector={})
For CFM-68K applications, stores all transition vectors into the jump table.
Definition macos.cc:809
offset_t ImageSize() const override
Retrieves the offset of the byte after the last one belonging to this format from the first one.
Definition macos.cc:908
void StoreFarSegmentFarEntries(std::shared_ptr< JumpTableCodeResource > jump_table, uint32_t &jump_table_offset)
For far segments, stores all far entries into the jump table.
Definition macos.cc:849
void StoreNearSegmentEntries(std::shared_ptr< JumpTableCodeResource > jump_table, uint32_t &jump_table_offset, std::optional< uint32_t > starting_entry={})
For near segments, stores all entries into the jump table.
Definition macos.cc:739
offset_t WriteFile(const std::shared_ptr< Linker::Writer > &wr) const override
Stores data in memory to file.
Definition macos.cc:1049
void ReadFile(const std::shared_ptr< Linker::Reader > &rd) override
Loads file into memory.
Definition macos.cc:986
void StoreFarSegmentNearEntries(std::shared_ptr< JumpTableCodeResource > jump_table, uint32_t &jump_table_offset, std::optional< uint32_t > starting_entry={})
For far segments, stores all near entries into the jump table.
Definition macos.cc:774
@ CFM_68K
CFM-68K segment, segment starts with a 40-byte header.
Definition macos.h:467
@ Near
Near model segment, segment starts with a 4-byte header.
Definition macos.h:463
@ Far
Far model segment, segment starts with a 40-byte header and potentially followed by segment based and...
Definition macos.h:465
Stores a resource with no specific format, as as sequence of raw bytes.
Definition macos.h:125
offset_t WriteFile(const std::shared_ptr< Linker::Writer > &wr) const override
Stores data in memory to file.
Definition macos.cc:152
void ReadFile(const std::shared_ptr< Linker::Reader > &rd) override
Loads file into memory.
Definition macos.cc:142
std::shared_ptr< Linker::Contents > image
The raw contents of the resource.
Definition macos.h:133
offset_t ImageSize() const override
Retrieves the offset of the byte after the last one belonging to this format from the first one.
Definition macos.cc:137
Stores a 68K jump table, found in 'CODE'0 resources.
Definition macos.h:338
void CollectRelocations(std::map< offset_t, offset_t > &section_relocations)
Generate the section relocations in a PEF container data section.
Definition macos.cc:412
@ Far
Far model jump table, with a single near model format entries and several far model format entries.
Definition macos.h:357
@ CFM_68K_Library
CFM-68K shared library jump table as stored in the PEF container, with a single classic format entry.
Definition macos.h:366
@ CFM_68K_StartUp
CFM-68K startup jump table as stored in the 'CODE'0 resource, with a single classic format entry.
Definition macos.h:361
@ Near
Near model jump table, with only near model format entries.
Definition macos.h:355
@ CFM_68K_Unflattened_Library
CFM-68K shared library jump table as stored in the PEF container, with a single classic format entry.
Definition macos.h:371
@ CFM_68K
CFM-68K jump table as stored in the PEF container, with a single classic format entries and several r...
Definition macos.h:359
offset_t ImageSize() const override
Retrieves the offset of the byte after the last one belonging to this format from the first one.
Definition macos.cc:188
void ReadJumpTable(const std::shared_ptr< Linker::Reader > &rd, offset_t length, jump_table_parse_mode mode, std::map< offset_t, offset_t > section_relocations={})
Read full jump table.
Definition macos.cc:219
jump_table_parse_mode
Describes how a jump table should be handled.
Definition macos.h:409
@ FromUnknown
No information, try to make the best out of it (untested)
Definition macos.h:411
@ FromResource
The jump table is found inside a 'CODE' resource.
Definition macos.h:413
@ FromPEFContainer
The jump table is found inside a PEF container data section.
Definition macos.h:415
offset_t WriteFile(const std::shared_ptr< Linker::Writer > &wr) const override
Stores data in memory to file.
Definition macos.cc:475
void ReadFile(const std::shared_ptr< Linker::Reader > &rd) override
Loads file into memory.
Definition macos.cc:206
Represents the information stored in a jump table.
Definition macos.h:234
void AddUnflattenedTransitionVector(Location a5_world, Location entry)
Attaches an unflattened library transition vector, consisting of a location of A5 world,...
Definition macos.h:316
std::vector< Entry > extended_entries
Entries with a 32-bit segment offset, used for far model format entries in far model jump tables and ...
Definition macos.h:264
void AddApplicationTransitionVector(Location seg_loader, Location a5_world, Location entry)
Attaches a transition vector to an application, consisting of a location of the segLoader routine,...
Definition macos.h:303
std::vector< Entry > legacy_entries
Entries with a 16-bit segment offset, used for near model jump tables, for near model format entries ...
Definition macos.h:262
void AddFlattenedEntry(Location entry)
Attaches a flattened entry type, consisting of a 32-bit relocated address value.
Definition macos.h:292
void AddExtendedEntry(Location entry)
Attaches an extended entry type, consisting of a 16-bit segment value and a 32-bit offset value.
Definition macos.h:281
void AddLegacyEntry(Location entry)
Attaches a legacy entry type, consisting of a 16-bit segment value and a 16-bit offset value.
Definition macos.h:270
void AddFlattenedTransitionVector(Location a5_world, Location entry)
Attaches a (flattened) library transition vector, consisting of a location of A5 world,...
Definition macos.h:328
Interface for the resource manager.
Definition macos.h:919
A single resource in the resource file.
Definition macos.h:84
virtual void EffectFormat(MacintoshResourceFileFormat &format, const std::shared_ptr< Linker::Reader > &rd)
Apply some changes to the format after parsing.
Definition macos.cc:124
void Dump(Dumper::Dumper &dump) const override
Display file contents in a nice manner.
Definition macos.cc:96
offset_t ImageSize() const override=0
Retrieves the offset of the byte after the last one belonging to this format from the first one.
Stores a 'SIZE'-1 resource, containing information related to program behavior, such as being able to...
Definition macos.h:582
void ReadFile(const std::shared_ptr< Linker::Reader > &rd) override
Loads file into memory.
Definition macos.cc:1190
static constexpr uint16_t SaveScreen
Definition macos.h:596
offset_t ImageSize() const override
Retrieves the offset of the byte after the last one belonging to this format from the first one.
Definition macos.cc:1185
static constexpr uint16_t DisableOptionSwitch
Definition macos.h:599
offset_t WriteFile(const std::shared_ptr< Linker::Writer > &wr) const override
Stores data in memory to file.
Definition macos.cc:1210
A Macintosh resource fork.
Definition macos.h:47
memory_model_t
Definition macos.h:53
@ MODEL_TINY
Create a single CODE segment containing all executable, non-zero filled and zero filled data,...
Definition macos.h:57
@ MODEL_DEFAULT
Each non-zero section becomes its own CODE segment, except .code/.text/.data/.rodata becomes its own ...
Definition macos.h:55
void GenerateFile(std::string filename, Linker::Module &module) override
The main function that handles processing, calculating and generating the final image.
Definition macos.cc:2423
offset_t ImageSize() const override
Retrieves the offset of the byte after the last one belonging to this format from the first one.
Definition macos.cc:2196
void ReadFile(const std::shared_ptr< Linker::Reader > &rd) override
Loads file into memory.
Definition macos.cc:2201
std::map< uint32_t, std::map< uint16_t, std::shared_ptr< Resource > > > resources
A convenient collection of resources.
Definition macos.h:862
std::shared_ptr< Linker::OptionCollector > GetOptions() override
Returns object containing a sequence of option fields provided with the -S command line flag.
Definition macos.cc:42
void OnNewSegment(std::shared_ptr< Linker::Segment > segment) override
Callback function when allocating a new segment When the linker script runs, it creates segments cons...
Definition macos.cc:1614
void SetOptions(std::map< std::string, std::string > &options) override
Passes command line parameters as settings over to format object.
Definition macos.cc:47
void SetModel(std::string model) override
Sets the way memory is organized, typically modifying a built-in script.
Definition macos.cc:77
bool FormatSupportsEntryTable() const override
Whether the format supports a structure containing addresses of methods.
Definition macos.cc:37
static bool CheckA5Relative(Linker::Relocation &rel)
Checks if this relocation belongs to an A5-relative addressing mode.
Definition macos.cc:1758
offset_t WriteFile(const std::shared_ptr< Linker::Writer > &wr) const override
Stores data in memory to file.
Definition macos.cc:2284
std::vector< ResourceType > resource_types
A list of all resource types, as stored in the file.
Definition macos.h:857
bool FormatSupportsResources() const override
Whether the format supports resources.
Definition macos.cc:32
void Dump(Dumper::Dumper &dump) const override
Display file contents in a nice manner.
Definition macos.cc:2344
std::vector< Linker::OptionDescription< void > > GetMemoryModelNames() override
Returns a list of the supported memory models, used for documentation.
Definition macos.cc:72
std::string GetDefaultExtension(Linker::Module &module) const override
Provides a default filename for the output file.
Definition macos.cc:2433
void CalculateValues() override
Intermediate step between processing module and generating output file to set up headers and manageme...
Definition macos.cc:2145
std::vector< std::string > resource_names
A list of all resource names, as stored in the file.
Definition macos.h:859
void ProcessModule(Linker::Module &module) override
Processes the module object and initializes format fields.
Definition macos.cc:2077
This is not actually a file format, but an interface to permit generating multiple binary outputs for...
Definition apple.h:709
produce_format_t
Represents what additional files should be generated.
Definition apple.h:731
@ PRODUCE_FINDER_INFO
Places a Finder Information file under the directory .finf (Macintosh only)
Definition apple.h:735
@ PRODUCE_MAC_BINARY
Creates a MacBinary with the .mbin extension (Macintosh only)
Definition apple.h:739
@ PRODUCE_RESOURCE_FORK
Places a GS/OS format resource file under the directory .rsrc.
Definition apple.h:733
@ PRODUCE_APPLE_DOUBLE
Creates an AppleDouble binary with the '' prefix.
Definition apple.h:737
target_format_t target
Format of "filename".
Definition apple.h:746
@ TARGET_DATA_FORK
Main file is a data fork, typically empty.
Definition apple.h:717
@ TARGET_RESOURCE_FORK
Main file is a resource fork.
Definition apple.h:719
@ TARGET_APPLE_SINGLE
Main file is an AppleSingle.
Definition apple.h:721
@ TARGET_NONE
Do not generate main file.
Definition apple.h:715
@ TARGET_APPLE_DOUBLE
Main file is an AppleDouble.
Definition apple.h:723
@ TARGET_MAC_BINARY
Main file as a MacBinary (Macintosh only)
Definition apple.h:725
produce_format_t produce
Bitset of other files to produce.
Definition apple.h:749
An abstract interface that separates structure and presentation of the data inside a file.
Definition dumper.h:1009
A record that represents a region within the file.
Definition dumper.h:902
A representation of an enumeration with associated string representations for each value.
Definition options.h:15
std::map< value_type, std::string > descriptions
An empty dictionary that explains the value types in detail.
Definition options.h:20
A class to encode a general file format.
Definition format.h:29
virtual void Dump(Dumper::Dumper &dump) const
Display file contents in a nice manner.
Definition format.cc:11
offset_t WriteFile(const std::shared_ptr< Writer > &wr) const override=0
Stores data in memory to file.
offset_t file_offset
The offset of the first byte used by this format in the file it is stored in.
Definition format.h:34
virtual void ReadFile(const std::shared_ptr< Reader > &rd)=0
Loads file into memory.
Encodes an object module file as a collection of sections, symbols and relocations.
Definition module.h:24
Helper class that contains the options interpreted by the format.
Definition options.h:499
Documents and handles command line options.
Definition options.h:306
virtual std::string GetDefaultExtension(Module &module, std::string filename) const
Appends a default extension to the filename.
A representation of a value within some binary data that has to be fixed up once the exact position o...
Definition relocation.h:28
A helper class to collect sections into segments.
Definition segment_manager.h:32
Definition resource.h:31
Definition resource.h:17
Definition resource.h:108
Definition resource.h:10
A YAML/JSON-like data format.
Definition value.h:16
Convenience structure to handle transition vectors belonging to this segment.
Definition macos.h:482
Describes a single jump table entry.
Definition macos.h:238
std::optional< uint32_t > section
Section number: only in PEF flattened shared libraries.
Definition macos.h:242
Describes a single transition vector entry.
Definition macos.h:247
Convenience structure to handle locations occuring in Macintosh 68K binaries.
Definition macos.h:150
static Location Sectioned(uint32_t section, uint32_t offset)
Create a location inside a PEF section, containing a section number and an offset.
Definition macos.h:188
static Location Segmented(uint16_t segment, uint32_t offset)
Create a location inside a CODE segment resource, containing a segment number (resource ID) and an of...
Definition macos.h:182
@ absolute
Both the segment and section fields should be ignored (not used, only included for completeness's sak...
Definition macos.h:158
@ sectioned
Contains a section and offset, the segment field should be ignored.
Definition macos.h:156
@ segmented
Contains a segment and offset, the section field should be ignored.
Definition macos.h:154