RetroLinker
Linker for several 8-bit, 16-bit and 32-bit formats
Loading...
Searching...
No Matches
mzexe.h
1#ifndef MZEXE_H
2#define MZEXE_H
3
4#include <array>
5#include <iomanip>
6#include <set>
7#include <string>
8#include <vector>
9#include "../common.h"
10#include "../linker/format.h"
11#include "../linker/module.h"
12#include "../linker/options.h"
13#include "../linker/reader.h"
14#include "../linker/section.h"
15#include "../linker/segment.h"
16#include "../linker/segment_manager.h"
17#include "../linker/writer.h"
18#include "../dumper/dumper.h"
19
20namespace Microsoft
21{
107 class MZFormat : public virtual Linker::SegmentManager
108 {
109 public:
110 /* * * General members * * */
111
122
124 char signature[2] = { 'M', 'Z' }; /* TODO: make parameter */
125
127 uint16_t last_block_size = 0;
129 uint16_t file_size_blocks = 0; /* TODO: consider making file size a parameter */
130
131 offset_t ImageSize() const override;
132
134 uint16_t relocation_count = 0;
136 uint16_t header_size_paras = 0; /* TODO: make header size a parameter */
138 uint16_t min_extra_paras = 0;
140 uint16_t max_extra_paras = 0;
142 uint16_t ss = 0;
144 uint16_t sp = 0;
146 uint16_t checksum = 0; /* TODO: fill when writing */
148 uint16_t ip = 0;
150 uint16_t cs = 0;
152 uint16_t relocation_offset = 0; /* TODO: make parameter */
153
155 uint16_t overlay_number = 0;
157 uint16_t data_segment = 0;
158
160 uint16_t behavior_bits = 0;
162 uint16_t oem_id = 0;
164 uint16_t oem_info = 0;
166 uint32_t new_header_offset = 0;
169
176 {
178 uint16_t segment;
180 uint16_t offset;
181
182 Relocation(uint16_t segment, uint16_t offset)
184 {
185 }
186
187 static Relocation FromLinear(uint32_t address);
188
189 uint32_t GetOffset() const;
190
191 bool operator ==(const Relocation& other) const;
192
193 bool operator <(const Relocation& other) const;
194 };
195
197 std::vector<Relocation> relocations;
198
200 struct PIF
201 {
202 static constexpr uint32_t MAGIC_BEGIN = 0x0013EDC1;
203 static constexpr uint32_t MAGIC_END = 0xEDC10013;
204 static constexpr size_t SIZE = 19;
205
206 /* TODO: requires testing */
207 uint16_t maximum_extra_paragraphs;
208 uint16_t minimum_extra_paragraphs;
209 uint8_t flags;
210 uint8_t lowest_used_interrupt;
211 uint8_t highest_used_interrupt;
212 uint8_t com_port_usage;
213 uint8_t lpt_port_usage;
214 uint8_t screen_usage;
215
216 void SetDefaults();
217
218 void ReadFile(const std::shared_ptr<Linker::Reader>& rd);
219
220 void WriteFile(const std::shared_ptr<Linker::Writer>& wr) const;
221
222 void Dump(Dumper::Dumper& dump, offset_t file_offset) const;
223 };
224
226 std::unique_ptr<PIF> pif;
227
229 std::shared_ptr<Linker::Contents> image;
230
231 magic_type GetSignature() const;
232
233 void SetSignature(magic_type magic);
234
235 void Clear() override;
236
237 ~MZFormat()
238 {
239 Clear();
240 }
241
242 void SetFileSize(uint32_t size);
243
244 uint32_t GetHeaderSize() const;
245
246 uint32_t GetPifOffset() const;
247
248 void ReadFile(const std::shared_ptr<Linker::Reader>& rd) override;
249
251 offset_t WriteFile(const std::shared_ptr<Linker::Writer>& wr) const override;
252
253 void Dump(Dumper::Dumper& dump) const override;
254
255 void CalculateValues() override;
256
257 /* * * Writer members * * */
258
260 {
261 public:
262 Linker::Option<std::optional<offset_t>> header_align{"header_align", "Aligns the end of the header to a specific boundary, must be power of 2"};
263 Linker::Option<std::optional<offset_t>> file_align{"file_align", "Aligns the end of the file to a specific boundary, must be power of 2"};
264 Linker::Option<offset_t> stack{"stack", "Specify the stack size"};
265
267 {
268 InitializeFields(header_align, file_align, stack);
269 }
270 };
271
288
289 /* filled in automatically */
291 uint16_t stack_size = 0;
292
294 uint16_t extra_paras = 0;
295
297 uint32_t zero_fill = 0;
298
300 uint32_t option_header_align = 0x10;
301
303 uint32_t option_file_align = 1;
304
305 bool FormatSupportsSegmentation() const override;
306
307 bool FormatIs16bit() const override;
308
309 bool FormatIsProtectedMode() const override;
310
311 unsigned FormatAdditionalSectionFlags(std::string section_name) const override;
312
313 static std::vector<Linker::OptionDescription<void>> MemoryModelNames;
314
315 std::vector<Linker::OptionDescription<void>> GetMemoryModelNames() override;
316
317 void SetModel(std::string model) override;
318
319 std::shared_ptr<Linker::OptionCollector> GetOptions() override;
320
321 void SetOptions(std::map<std::string, std::string>& options) override;
322
323 void OnNewSegment(std::shared_ptr<Linker::Segment> segment) override;
324
330
331 std::unique_ptr<Script::List> GetScript(Linker::Module& module);
332
336 void Link(Linker::Module& module);
337
338#if 0
342 void LinkLarge(Linker::Module& module);
343#endif
344
345 void ProcessModule(Linker::Module& module) override;
346
347 uint32_t GetDataSize() const;
348
349 void GenerateFile(std::string filename, Linker::Module& module) override;
350
352 std::string GetDefaultExtension(Linker::Module& module, std::string filename) const override;
353 };
354
356 {
357 public:
358 std::string filename;
359 bool valid = true;
360 std::ifstream stream;
361
362 MZSimpleStubWriter(std::string filename = "")
363 : filename(filename)
364 {
365 }
366
367 offset_t size = -1;
368
369 bool OpenAndCheckValidFile();
370
371 offset_t GetStubImageSize();
372
373 void WriteStubImage(std::ostream& out);
374
375 void WriteStubImage(const std::shared_ptr<Linker::Writer>& wr);
376
378 {
379 if(stream.is_open())
380 {
381 stream.close();
382 }
383 }
384 };
385
387 {
388 public:
389 std::string filename;
390 bool valid = true;
391 std::ifstream stream;
392
393 MZStubWriter(std::string filename = "")
394 : filename(filename)
395 {
396 }
397
398 uint32_t original_file_size = -1;
399 uint32_t stub_file_size = 0;
400 uint16_t stub_reloc_count = 0;
401 uint32_t original_header_size = 0;
402 uint32_t stub_header_size = 0;
403 uint16_t original_reloc_offset = 0;
404 uint16_t stub_reloc_offset = 0;
405
406 bool OpenAndCheckValidFile();
407
408 offset_t GetStubImageSize();
409
410 void WriteStubImage(std::ostream& out);
411
412 void WriteStubImage(const std::shared_ptr<Linker::Writer>& wr);
413
415 {
416 if(stream.is_open())
417 {
418 stream.close();
419 }
420 }
421 };
422
423 template <typename T, size_t N, typename Predicate>
424 offset_t FindActualSignature(const std::shared_ptr<Linker::Reader>& rd, std::array<T, N>& signature, Predicate predicate, bool search_win386_offset = false)
425 {
426 offset_t file_offset = rd->Tell();
427 rd->ReadData(signature);
428 if(file_offset == 0 && !predicate(signature))
429 {
430 // try to find real file offset
431 offset_t file_end = rd->GetImageEnd();
432
433 rd->Seek(2);
434 uint32_t mz_image_end = rd->ReadUnsigned(2, ::LittleEndian);
435 mz_image_end = (uint32_t(rd->ReadUnsigned(2, ::LittleEndian)) << 9) - (-mz_image_end & 0x1FF);
436
437 uint32_t win386_header_offset = 0;
438 uint32_t ne_header_offset = 0;
439 if(file_end >= 0x40)
440 {
441 if(search_win386_offset)
442 {
443 rd->Seek(0x38);
444 win386_header_offset = rd->ReadUnsigned(4, ::LittleEndian);
445 }
446
447 rd->Seek(0x3C);
448 ne_header_offset = rd->ReadUnsigned(4, ::LittleEndian);
449 }
450
451 if(ne_header_offset != 0 && ne_header_offset + N < file_end)
452 {
453 rd->Seek(ne_header_offset);
454 rd->ReadData(signature);
455 }
456
457 if(predicate(signature))
458 {
459 file_offset = rd->Tell() - N;
460 }
461 else
462 {
463 if(mz_image_end != 0 && mz_image_end != ne_header_offset && mz_image_end + N < file_end)
464 {
465 rd->Seek(mz_image_end);
466 rd->ReadData(signature);
467 }
468
469 if(predicate(signature))
470 {
471 file_offset = rd->Tell() - N;
472 }
473 else
474 {
475 if(win386_header_offset != 0 && win386_header_offset != ne_header_offset && win386_header_offset != mz_image_end && win386_header_offset + N < file_end)
476 {
477 rd->Seek(win386_header_offset);
478 rd->ReadData(signature);
479 }
480
481 if(predicate(signature))
482 {
483 file_offset = rd->Tell() - N;
484 }
485 else
486 {
487 rd->Seek(N);
488 }
489 }
490 }
491 }
492
493 return file_offset;
494 }
495
496 template <typename T, size_t N>
497 offset_t FindActualSignature(const std::shared_ptr<Linker::Reader>& rd, std::array<T, N>& signature, const char * expected_signature, bool search_win386_offset = false)
498 {
499 return FindActualSignature(
500 rd,
501 signature,
502 [expected_signature](std::array<T, N>& signature) { return memcmp(signature.data(), expected_signature, N) == 0; },
503 search_win386_offset);
504 }
505
506 template <typename T, size_t N>
507 offset_t FindActualSignature(const std::shared_ptr<Linker::Reader>& rd, std::array<T, N>& signature, const char * expected_signature1, const char * expected_signature2, bool search_win386_offset = false)
508 {
509 return FindActualSignature(
510 rd,
511 signature,
512 [expected_signature1, expected_signature2](std::array<T, N>& signature) { return memcmp(signature.data(), expected_signature1, N) == 0 || memcmp(signature.data(), expected_signature2, N) == 0; },
513 search_win386_offset);
514 }
515
516 template <typename T, size_t N>
517 offset_t FindActualSignature(const std::shared_ptr<Linker::Reader>& rd, std::array<T, N>& signature, const char * expected_signature1, const char * expected_signature2, const char * expected_signature3)
518 {
519 return FindActualSignature(
520 rd,
521 signature,
522 [expected_signature1, expected_signature2, expected_signature3](std::array<T, N>& signature) { return memcmp(signature.data(), expected_signature1, N) == 0 || memcmp(signature.data(), expected_signature2, N) == 0 || memcmp(signature.data(), expected_signature3, N) == 0; },
523 false);
524 }
525}
526
527#endif /* MZEXE_H */
An abstract interface that separates structure and presentation of the data inside a file.
Definition dumper.h:1009
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
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 helper class to collect sections into segments.
Definition segment_manager.h:32
MZ .EXE format for MS-DOS.
Definition mzexe.h:108
uint32_t win386_new_header_offset
Offset to new executable file header for Win386.
Definition mzexe.h:168
uint16_t stack_size
Stack size requested at the command line.
Definition mzexe.h:291
void CreateDefaultSegments()
Create the required segments, if they have not already been allocated. The MZ format uses a single se...
Definition mzexe.cc:530
offset_t ImageSize() const override
Retrieves the offset of the byte after the last one belonging to this format from the first one.
Definition mzexe.cc:10
uint16_t relocation_offset
Offset to first relocation. Updated by CalculateValues.
Definition mzexe.h:152
uint16_t cs
Initial value for the code segment (CS)
Definition mzexe.h:150
uint16_t behavior_bits
Field with undocumented semantics used for 'NE' files.
Definition mzexe.h:160
uint16_t min_extra_paras
Minimum required extra memory, in paragraphs.
Definition mzexe.h:138
std::shared_ptr< Linker::OptionCollector > GetOptions() override
Returns object containing a sequence of option fields provided with the -S command line flag.
Definition mzexe.cc:490
uint16_t oem_info
Field with undocumented semantics used for 'LE'/'LX'/'PE' files.
Definition mzexe.h:164
magic_type
Type of magic number, usually "MZ".
Definition mzexe.h:114
@ MAGIC_DL
HP 100LX/200LX System Manager modules (.exm) use the magic number "DL".
Definition mzexe.h:120
@ MAGIC_ZM
According to some sources such as Ralf Brown's interrupt list, some early excutables started with the...
Definition mzexe.h:118
@ MAGIC_MZ
The most common magic number "MZ".
Definition mzexe.h:116
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 mzexe.cc:510
void Link(Linker::Module &module)
Link application according to script or memory model.
Definition mzexe.cc:614
uint16_t checksum
Checksum.
Definition mzexe.h:146
void GenerateFile(std::string filename, Linker::Module &module) override
The main function that handles processing, calculating and generating the final image.
Definition mzexe.cc:755
uint16_t last_block_size
Size of last 512 byte block, 0 if full. Set by CalculateValues.
Definition mzexe.h:127
bool FormatSupportsSegmentation() const override
Whether the format supports multiple segments.
Definition mzexe.cc:415
uint16_t oem_id
Field with undocumented semantics used for 'LE'/'LX'/'PE' files.
Definition mzexe.h:162
uint16_t extra_paras
Required maximum extra paragraphs after bss.
Definition mzexe.h:294
uint32_t option_file_align
User provided alignment value for file align.
Definition mzexe.h:303
uint16_t header_size_paras
Size of MZ header. Updated by CalculateValues.
Definition mzexe.h:136
void CalculateValues() override
Intermediate step between processing module and generating output file to set up headers and manageme...
Definition mzexe.cc:364
uint16_t file_size_blocks
Size of MZ image in 512 blocks, rounded up. Set by CalculateValues.
Definition mzexe.h:129
void SetModel(std::string model) override
Sets the way memory is organized, typically modifying a built-in script.
Definition mzexe.cc:461
std::vector< Linker::OptionDescription< void > > GetMemoryModelNames() override
Returns a list of the supported memory models, used for documentation.
Definition mzexe.cc:456
uint32_t zero_fill
Total size of bss and stack.
Definition mzexe.h:297
bool FormatIsProtectedMode() const override
Whether the format is in protected mode or not (x86 only)
Definition mzexe.cc:425
uint16_t relocation_count
Number of relocations. Updated by CalculateValues.
Definition mzexe.h:134
void Clear() override
Resets all fields to their default values, deallocate memory.
Definition mzexe.cc:150
void Dump(Dumper::Dumper &dump) const override
Display file contents in a nice manner.
Definition mzexe.cc:307
uint16_t data_segment
Starting paragraph of program data, only required for .exm files.
Definition mzexe.h:157
memory_model_t
Represents the memory model of the running executable, which is the way in which the segments are set...
Definition mzexe.h:274
@ MODEL_LARGE
Large model, every section is a separate segment.
Definition mzexe.h:284
@ MODEL_SMALL
Small model, separate code and data segments.
Definition mzexe.h:280
@ MODEL_DEFAULT
Default model, same as small.
Definition mzexe.h:276
@ MODEL_TINY
Tiny model, code and data segment are the same.
Definition mzexe.h:278
@ MODEL_COMPACT
Compact model, separate code and multiple data segments.
Definition mzexe.h:282
std::shared_ptr< Linker::Contents > image
The program image, placed after the MZ header.
Definition mzexe.h:229
uint16_t ip
Entry point initial value for IP.
Definition mzexe.h:148
memory_model_t memory_model
Memory model of generated executable.
Definition mzexe.h:287
uint16_t sp
Initial value for the stack (SP)
Definition mzexe.h:144
offset_t WriteFile(const std::shared_ptr< Linker::Writer > &wr) const override
Stores data in memory to file.
Definition mzexe.cc:256
char signature[2]
The magic number at the start of the executable file, usually "MZ".
Definition mzexe.h:124
std::vector< Relocation > relocations
Address relocation offsets to paragraph fixups.
Definition mzexe.h:197
void ReadFile(const std::shared_ptr< Linker::Reader > &rd) override
Loads file into memory.
Definition mzexe.cc:176
uint32_t option_header_align
User provided alignment value for header size.
Definition mzexe.h:300
bool FormatIs16bit() const override
Whether the format is 16-bit or not.
Definition mzexe.cc:420
uint32_t new_header_offset
Offset to new executable file header, usually 'NE'/'LE'/'LX'/'PE'.
Definition mzexe.h:166
uint16_t ss
Initial value for the stack segment (SS)
Definition mzexe.h:142
std::string GetDefaultExtension(Linker::Module &module, std::string filename) const override
Appends a default extension to the filename.
Definition mzexe.cc:765
uint16_t overlay_number
Overlay number, should be 0 for main programs, not used for .exm files.
Definition mzexe.h:155
uint16_t max_extra_paras
Maximum required extra memory, in paragraphs. Set by CalculateValues using extra_paras.
Definition mzexe.h:140
std::unique_ptr< PIF > pif
Concurrent DOS program information entry, allocated only if present.
Definition mzexe.h:226
void ProcessModule(Linker::Module &module) override
Processes the module object and initializes format fields.
Definition mzexe.cc:655
void SetOptions(std::map< std::string, std::string > &options) override
Passes command line parameters as settings over to format object.
Definition mzexe.cc:495
Definition mzexe.h:356
Definition mzexe.h:387
Concurrent DOS embedded program information, produced by PIFED.
Definition mzexe.h:201
Represents a relocation entry in the header, as a pair of 16-bit words.
Definition mzexe.h:176
uint16_t segment
Segment of relocation.
Definition mzexe.h:178
uint16_t offset
Offset of relocation within segment.
Definition mzexe.h:180