RetroLinker
Linker for several 8-bit, 16-bit and 32-bit formats
Loading...
Searching...
No Matches
leexe.h
1#ifndef LEEXE_H
2#define LEEXE_H
3
4#include <array>
5#include <vector>
6#include "mzexe.h"
7#include "../common.h"
8#include "../dumper/dumper.h"
9#include "../linker/module.h"
10#include "../linker/options.h"
11#include "../linker/segment.h"
12#include "../linker/segment_manager.h"
13#include "../linker/writer.h"
14
15namespace Microsoft
16{
28 class LEFormat : public virtual Linker::SegmentManager, public std::enable_shared_from_this<LEFormat>
29 {
30 public:
31 /* * * General members * * */
32
33 enum compatibility_type
34 {
35 CompatibleNone,
36 CompatibleWatcom,
37 CompatibleMicrosoft, /* TODO??? */
38 CompatibleGNU, /* TODO: emx extender */
39 };
40
41 class Object
42 {
43 public:
44 std::shared_ptr<Linker::Image> image;
45 enum flag_type
46 {
47 Readable = 0x0001,
48 Writable = 0x0002,
49 Executable = 0x0004,
50 Resource = 0x0008,
51 Discardable = 0x0010,
52 Shared = 0x0020,
53 PreloadPages = 0x0040,
54 InvalidPages = 0x0080,
55 ZeroFilledPages = 0x0100,
56 Resident = 0x0200,
57 ResidentContiguous = 0x0300,
58 ResidentLongLockable = 0x0400,
59 Alias16_16 = 0x1000, /* x86 */
60 BigSegment = 0x2000, /* x86 */
61 Conforming = 0x4000, /* x86 */
62 IOPrivilege = 0x8000, /* x86 */
63 };
64 uint32_t size = 0;
65 uint32_t address = 0;
66 flag_type flags = flag_type(0);
67 uint32_t page_table_index = 0;
68 uint32_t page_entry_count = 0;
69 uint32_t data_pages_offset = 0;
70
71 Object()
72 {
73 }
74
75 Object(std::shared_ptr<Linker::Segment> segment, unsigned flags)
76 : image(segment), flags(flag_type(flags))
77 {
78 }
79 };
80
82 class PageSet : public Linker::Image
83 {
84 public:
85 std::vector<std::shared_ptr<Linker::Image>> pages;
86
87 offset_t ImageSize() const override;
89 offset_t WriteFile(Linker::Writer& wr, offset_t count, offset_t offset = 0) const override;
90 };
91
94 {
95 public:
96 std::shared_ptr<Linker::Image> image;
97 offset_t offset = 0;
98 offset_t size = 0;
99
100 SegmentPage(std::shared_ptr<Linker::Image> image, offset_t offset, offset_t size)
101 : image(image), offset(offset), size(size)
102 {
103 }
104
105 offset_t ImageSize() const override;
107 offset_t WriteFile(Linker::Writer& wr, offset_t count, offset_t offset = 0) const override;
108 std::shared_ptr<const Linker::ActualImage> AsImage() const override;
109 };
110
112 {
113 public:
115 {
116 uint16_t count = 0;
117 std::vector<uint8_t> data;
118 };
119 std::vector<IterationRecord> records;
120
121 offset_t ImageSize() const override;
123 offset_t WriteFile(Linker::Writer& wr, offset_t count, offset_t offset = 0) const override;
124
125 class View : public Linker::Image
126 {
127 public:
128 IteratedPage& iterated_page;
129
130 View(IteratedPage& iterated_page)
131 : iterated_page(iterated_page)
132 {
133 }
134
135 offset_t ImageSize() const override;
137 offset_t WriteFile(Linker::Writer& wr, offset_t count, offset_t offset = 0) const override;
138 };
139 };
140
141 class Page
142 {
143 public:
144 union
145 {
146 struct
147 {
148 uint32_t fixup_table_index;
149 uint8_t type;
150 } le;
151 struct
152 {
153 uint32_t offset;
154 uint16_t size;
155 uint16_t flags;
156 } lx;
157 };
158
159 enum
160 {
161 /* LE types */
162 NoRelocations = 0,
163 Relocations = 3,
164
165 /* LX flags */
166 Preload = 0,
167 Iterated,
168 Invalid,
169 ZeroFilled,
170 Range,
171 };
172
173 uint32_t fixup_offset = 0;
174
176 {
177 public:
178 enum source_type
179 {
180 Offset8 = 0,
181 Selector16 = 2,
182 Pointer32 = 3,
183 Offset16 = 5,
184 Pointer48 = 6,
185 Offset32 = 7,
186 Relative32 = 8,
187
188 SourceTypeMask = 0x0F,
189
190 Alias = 0x10,
191 SourceList = 0x20,
192 };
193 source_type type = source_type(0);
194 enum flag_type
195 {
196 Internal = 0,
197 ImportOrdinal = 1,
198 ImportName = 2,
199 Entry = 3,
200
201 FlagTypeMask = 3,
202
203 Additive = 4,
204 Chained = 8,
205 Target32 = 0x10,
206 Additive32 = 0x20,
207 Module16 = 0x40,
208 Ordinal8 = 0x80,
209 };
210 flag_type flags = flag_type(0);
211 uint16_t module = 0;
212 uint32_t target = 0;
213 uint32_t addition = 0;
214
215 Relocation()
216 : Writer(::LittleEndian)
217 {
218 }
219
220 Relocation(unsigned type, unsigned flags, uint16_t offset, uint16_t module, uint32_t target = 0, uint32_t addition = 0)
221 : Writer(::LittleEndian), type(source_type(type)), flags(flag_type(flags)), module(module), target(target), addition(addition)
222 {
223 sources.push_back(Chain{offset});
224 }
225
226 static source_type GetType(Linker::Relocation& rel);
227
228 bool IsExternal() const;
229
230 bool IsSelectorOrOffset() const;
231
232 bool ComesBefore() const;
233
234 size_t GetSourceSize() const;
235
236 private:
237 struct ChainLink
238 {
239 uint32_t target = 0;
240 uint16_t source = 0;
241 };
242
243 struct Chain
244 {
245 uint16_t source = 0;
246 std::vector<ChainLink> chains;
247 };
248
249 std::vector<Chain> sources;
250
251 public:
252 /* do not call this */
253 void DecrementSingleSourceOffset(size_t amount);
254
255 bool IsSelector() const;
256 bool IsSourceList() const;
257 bool IsAdditive() const;
258 size_t GetTargetSize() const;
259 size_t GetAdditiveSize() const;
260 size_t GetModuleSize() const;
261 size_t GetOrdinalSize() const;
262
263 uint16_t GetFirstSource() const;
264
265 void CalculateSizes(compatibility_type compatibility);
266
267 size_t GetSize() const;
268
269 static Relocation ReadFile(Linker::Reader& rd);
270 void WriteFile(Linker::Writer& wr) const;
271 };
272 std::map<uint16_t, Relocation> relocations;
273 uint32_t checksum = 0;
274 std::shared_ptr<Linker::Image> image;
275
276 Page()
277 : lx{0, 0, 0}
278 {
279 }
280
281 protected:
282 Page(uint16_t fixup_table_index, uint8_t type)
283 : le{fixup_table_index, type}
284 {
285 }
286
287 Page(uint32_t offset, uint16_t size, uint8_t flags)
288 : lx{offset, size, flags}
289 {
290 }
291
292 public:
293 static Page LEPage(uint16_t fixup_table_index, uint8_t type);
294
295 static Page LXPage(uint32_t offset, uint16_t size, uint8_t flags);
296 };
297
299 {
300 public:
301 uint16_t type = 0, name = 0;
302 uint32_t size = 0;
303 uint16_t object = 0;
304 uint32_t offset = 0;
305 };
306
307 struct Name
308 {
309 public:
310 std::string name;
311 uint16_t ordinal = 0;
312 };
313
314 class Entry : public Linker::Writer
315 {
316 public:
317 enum entry_type
318 {
319 Unused,
320 Entry16,
321 CallGate286,
322 Entry32,
323 Forwarder,
324 };
325 entry_type type = Unused;
326 uint16_t object = 0;
327 enum flag_type
328 {
329 Exported = 1,
330 SharedData = 2,
331 };
332 flag_type flags = flag_type(0);
333 uint32_t offset = 0;
334
335 Entry()
336 : Writer(::LittleEndian)
337 {
338 }
339
340 Entry(unsigned type, uint16_t object, unsigned flags, uint32_t offset)
341 : Writer(::LittleEndian), type(entry_type(type)), object(object), flags(flag_type(flags)), offset(offset)
342 {
343 }
344
345 mutable bool same_bundle = false; // mutable because this isn't actually part of the entry state but the entire entry table
346
347 bool SameBundle(const Entry& other) const;
348
349 offset_t GetEntryHeadSize() const;
350
351 offset_t GetEntryBodySize() const;
352
353 static Entry ReadEntryHead(Linker::Reader& rd, uint8_t type);
354 static Entry ReadEntry(Linker::Reader& rd, uint8_t type, LEFormat::Entry& head);
355
356 void WriteEntryHead(Linker::Writer& wr) const;
357
358 void WriteEntryBody(Linker::Writer& wr) const;
359 };
360
362 {
363 public:
364 enum directive_number : uint16_t
365 {
366 VerifyRecordDirective = 0x8001,
367 LanguageInformationDirective = 0x0002,
368 CoProcessorRequiredSupportTable = 0x0003,
369 ThreadStateInitializationDirective = 0x0004,
370 CSetBrowseInformation = 0x0005,
371 };
372 static constexpr uint16_t ResidentFlagMask = 0x8000;
373 directive_number directive = directive_number(0);
374 uint16_t length = 0;
375 offset_t offset = 0;
376
377 bool IsResident() const;
378 };
379
380 ::EndianType endiantype = ::LittleEndian;
381
383 std::array<char, 2> signature{'L', 'E'};
384
385 bool IsExtendedFormat() const;
386
387 uint32_t format_level = 0;
388
389 /* https://faydoc.tripod.com/formats/exe-LE.htm */
390 enum cpu_type
391 {
392 I286 = 0x01,
393 I386 = 0x02, /* only value used */
394 I486 = 0x03,
395 I586 = 0x04,
396 I860_N10 = 0x20,
397 I860_N11 = 0x21,
398 MIPS1 = 0x40,
399 MIPS2 = 0x41,
400 MIPS3 = 0x42,
401 };
402 cpu_type cpu = I386;
403
404 enum system_type
405 {
406 OS2 = 1, /* OS/2 2.0+ */
407 Windows, /* Windows 386 */
408 MSDOS4, /* ? */
409 Windows386, /* ? */
410
411 DOS4G = -1, /* not a real system type */
412 };
413 system_type system = system_type(0);
414
415 uint32_t module_version = 0;
416
417 enum
418 {
419 PreProcessInitialization = 0x00000004,
420 NoInternalFixup = 0x00000010,
421 NoExternalFixup = 0x00000020,
422 FullScreen = 0x00000100,
423 GUIAware = 0x00000200,
424 GUI = 0x00000300,
425 ErrorInImage = 0x00002000,
426 Library = 0x00008000,
427 ProtectedMemoryLibrary = 0x00018000,
428 PhysicalDriver = 0x00020000,
429 VirtualDriver = 0x00028000,
430 PerProcessTermination = 0x40000000,
431 };
432 uint32_t module_flags = 0;
433
434 uint32_t page_count = 0, page_size = 0x1000;
435 uint32_t eip_object = 0, eip_value = 0, esp_object = 0, esp_value = 0;
436 union
437 {
438 uint32_t last_page_size; /* LE */
439 uint32_t page_offset_shift; /* LX */
440 };
441 uint32_t fixup_section_size = 0, fixup_section_checksum = 0;
442 uint32_t loader_section_size = 0, loader_section_checksum = 0;
443 uint32_t object_table_offset = 0, object_page_table_offset = 0, object_iterated_pages_offset = 0;
444 uint32_t resource_table_offset = 0, resource_table_entry_count = 0, resident_name_table_offset = 0;
445 uint32_t entry_table_offset = 0, module_directives_offset = 0, fixup_page_table_offset = 0, fixup_record_table_offset = 0;
446 uint32_t imported_module_table_offset = 0, imported_procedure_table_offset = 0;
447 uint32_t per_page_checksum_offset = 0;
448 uint32_t data_pages_offset = 0, preload_page_count = 0;
449 uint32_t nonresident_name_table_offset = 0, nonresident_name_table_size = 0, nonresident_name_table_checksum = 0;
450 uint32_t automatic_data = 0;
451 uint32_t debug_info_offset = 0, debug_info_size = 0, instance_preload_page_count = 0, instance_demand_page_count = 0;
452 uint32_t stack_size = 0, heap_size = 0;
453
454 uint32_t vxd_version_info_resource_offset = 0;
455 uint32_t vxd_version_info_resource_length = 0;
456 uint16_t vxd_device_id = 0;
457 uint16_t vxd_ddk_version = 0;
458
459 std::vector<Object> objects;
460 std::vector<ModuleDirective> module_directives;
461
462 std::vector<Page> pages;
463 std::map<uint16_t, std::map<uint16_t, Resource>> resources;
464 std::vector<Name> resident_names, nonresident_names;
465 std::vector<Entry> entries;
466 std::vector<std::string> imported_modules, imported_procedures;
467
468 offset_t file_size = offset_t(-1);
469
470 explicit LEFormat()
471 : last_page_size(0)
472 {
473 }
474
475 LEFormat(unsigned system, unsigned module_flags, bool extended_format)
476 : system(system_type(system)), module_flags(module_flags), last_page_size(0)
477 {
478 if(extended_format)
479 signature[1] = 'X';
480 }
481
482 bool IsLibrary() const;
483
484 bool IsDriver() const;
485
486 bool IsOS2() const;
487
488 void ReadFile(Linker::Reader& rd) override;
489
490 offset_t ImageSize() const override;
491
493 offset_t WriteFile(Linker::Writer& wr) const override;
494 void Dump(Dumper::Dumper& dump) const override;
495
496 offset_t GetPageOffset(uint32_t index) const;
497 offset_t GetPageSize(uint32_t index) const;
498
499 /* * * Writer members * * */
500
502 {
503 public:
504 Linker::Option<std::string> stub{"stub", "Filename for stub that gets prepended to executable"};
505
507 {
508 InitializeFields(stub);
509 }
510 };
511
512 static std::shared_ptr<LEFormat> CreateConsoleApplication(system_type system = OS2);
513
514 static std::shared_ptr<LEFormat> CreateGUIApplication(system_type system = OS2);
515
516 static std::shared_ptr<LEFormat> CreateLibraryModule(system_type system = OS2);
517
518 std::shared_ptr<LEFormat> SimulateLinker(compatibility_type compatibility);
519
520 mutable MZStubWriter stub;
521
522 compatibility_type compatibility = CompatibleNone;
523
524 /*std::string stub_file;*/
525 std::string program_name, module_name;
526
527 bool FormatSupportsSegmentation() const override;
528
529 bool FormatSupportsLibraries() const override;
530
531 unsigned FormatAdditionalSectionFlags(std::string section_name) const override;
532
533 Resource& AddResource(Resource& resource);
534
535 void GetRelocationOffset(Object& object, size_t offset, size_t& page_index, uint16_t& page_offset);
536 void AddRelocation(Object& object, unsigned type, unsigned flags, size_t offset, uint16_t module, uint32_t target = 0, uint32_t addition = 0);
537
538 std::shared_ptr<Linker::Segment> stack, heap;
539 std::map<std::shared_ptr<Linker::Segment>, size_t> object_index;
540 std::map<std::string, uint32_t> imported_procedure_name_offsets;
541 offset_t imported_procedure_names_length = 0;
542
543 unsigned GetDefaultObjectFlags() const;
544 void AddObject(const Object& object);
545 uint16_t FetchImportedModuleName(std::string name);
546 uint16_t FetchImportedProcedureName(std::string name);
547 uint16_t MakeEntry(Linker::Position value);
548 uint16_t MakeEntry(uint16_t index, Linker::Position value);
549 uint8_t CountBundles(size_t entry_index) const;
550
551 static std::vector<Linker::OptionDescription<void> *> ParameterNames;
552 std::vector<Linker::OptionDescription<void> *> GetLinkerScriptParameterNames() override;
553 std::shared_ptr<Linker::OptionCollector> GetOptions() override;
554 void SetOptions(std::map<std::string, std::string>& options) override;
555 void OnNewSegment(std::shared_ptr<Linker::Segment> segment) override;
556 std::unique_ptr<Script::List> GetScript(Linker::Module& module);
557 void Link(Linker::Module& module);
558 void ProcessModule(Linker::Module& module) override;
559 void CalculateValues() override;
560 void GenerateFile(std::string filename, Linker::Module& module) override;
562 std::string GetDefaultExtension(Linker::Module& module, std::string filename) const override;
563
564 };
565
566}
567
568#endif /* LEEXE_H */
An abstract interface that separates structure and presentation of the data inside a file.
Definition dumper.h:586
offset_t WriteFile(Writer &wr) const override=0
Stores data in memory to file.
Represents an abstract data image whose data can be written to a file.
Definition image.h:17
virtual offset_t WriteFile(Writer &wr, offset_t count, offset_t offset=0) const =0
Writes data of non-zero filled sections.
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:308
Documents and handles command line options.
Definition options.h:196
virtual std::string GetDefaultExtension(Module &module, std::string filename) const
Appends a default extension to the filename.
Stores an absolute address along with the containing segment or address space.
Definition position.h:17
A helper class, encapsulating functionality needed to import binary data.
Definition reader.h:16
A representation of a value within some binary data that has to be fixed up once the exact position o...
Definition relocation.h:27
A helper class to collect sections into segments.
Definition segment_manager.h:32
A helper class, encapsulating functionality needed to export binary data.
Definition writer.h:15
Definition leexe.h:315
offset_t ImageSize() const override
Retrieves size of stored data.
offset_t WriteFile(Linker::Writer &wr, offset_t count, offset_t offset=0) const override
Writes data of non-zero filled sections.
Definition leexe.h:112
offset_t WriteFile(Linker::Writer &wr, offset_t count, offset_t offset=0) const override
Writes data of non-zero filled sections.
offset_t ImageSize() const override
Retrieves size of stored data.
Definition leexe.h:42
An image instance that is a collection of other images, conceptually pages.
Definition leexe.h:83
offset_t ImageSize() const override
Retrieves size of stored data.
Definition leexe.cc:10
offset_t WriteFile(Linker::Writer &wr, offset_t count, offset_t offset=0) const override
Writes data of non-zero filled sections.
Definition leexe.cc:20
Definition leexe.h:142
Definition leexe.h:299
An image instance for a single page within a complete object image.
Definition leexe.h:94
offset_t WriteFile(Linker::Writer &wr, offset_t count, offset_t offset=0) const override
Writes data of non-zero filled sections.
Definition leexe.cc:47
offset_t ImageSize() const override
Retrieves size of stored data.
Definition leexe.cc:42
std::shared_ptr< const Linker::ActualImage > AsImage() const override
Retrieves a randomly accessible image.
Definition leexe.cc:61
LE/LX .EXE linear executable file format.
Definition leexe.h:29
void Dump(Dumper::Dumper &dump) const override
Display file contents in a nice manner.
Definition leexe.cc:1216
void CalculateValues() override
Intermediate step between processing module and generating output file to set up headers and manageme...
Definition leexe.cc:2074
void SetOptions(std::map< std::string, std::string > &options) override
Passes command line parameters as settings over to format object.
Definition leexe.cc:1739
std::vector< Linker::OptionDescription< void > * > GetLinkerScriptParameterNames() override
Returns a list of the parameters used in the linker scripts, used for documentation.
Definition leexe.cc:1729
std::shared_ptr< Linker::OptionCollector > GetOptions() override
Returns object containing a sequence of option fields provided with the -S command line flag.
Definition leexe.cc:1734
void GenerateFile(std::string filename, Linker::Module &module) override
The main function that handles processing, calculating and generating the final image.
Definition leexe.cc:2228
offset_t ImageSize() const override
Retrieves size of stored data.
Definition leexe.cc:924
std::string GetDefaultExtension(Linker::Module &module, std::string filename) const override
Appends a default extension to the filename.
Definition leexe.cc:2244
void ReadFile(Linker::Reader &rd) override
Loads file into memory.
Definition leexe.cc:549
bool FormatSupportsSegmentation() const override
Whether the format supports multiple segments.
Definition leexe.cc:1566
void ProcessModule(Linker::Module &module) override
Processes the module object and initializes format fields.
Definition leexe.cc:1825
std::array< char, 2 > signature
The signature, almost always "LE" or "LX".
Definition leexe.h:383
offset_t WriteFile(Linker::Writer &wr) const override
Stores data in memory to file.
Definition leexe.cc:929
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 leexe.cc:1747
bool FormatSupportsLibraries() const override
Whether the format supports libraries.
Definition leexe.cc:1571
Definition mzexe.h:300
Definition leexe.h:308