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{
36 class MZFormat : public virtual Linker::SegmentManager
37 {
38 public:
39 /* * * General members * * */
40
51
53 char signature[2] = { 'M', 'Z' }; /* TODO: make parameter */
54
56 uint16_t last_block_size = 0;
58 uint16_t file_size_blocks = 0; /* TODO: consider making file size a parameter */
59
60 offset_t ImageSize() const override;
61
63 uint16_t relocation_count = 0;
65 uint16_t header_size_paras = 0; /* TODO: make header size a parameter */
67 uint16_t min_extra_paras = 0;
69 uint16_t max_extra_paras = 0;
71 uint16_t ss = 0;
73 uint16_t sp = 0;
75 uint16_t checksum = 0; /* TODO: fill when writing */
77 uint16_t ip = 0;
79 uint16_t cs = 0;
81 uint16_t relocation_offset = 0; /* TODO: make parameter */
82
84 uint16_t overlay_number = 0;
86 uint16_t data_segment = 0;
87
94 {
96 uint16_t segment;
98 uint16_t offset;
99
100 Relocation(uint16_t segment, uint16_t offset)
102 {
103 }
104
105 static Relocation FromLinear(uint32_t address);
106
107 uint32_t GetOffset() const;
108
109 bool operator ==(const Relocation& other) const;
110
111 bool operator <(const Relocation& other) const;
112 };
113
115 std::vector<Relocation> relocations;
116
118 struct PIF
119 {
120 static constexpr uint32_t MAGIC_BEGIN = 0x0013EDC1;
121 static constexpr uint32_t MAGIC_END = 0xEDC10013;
122 static constexpr size_t SIZE = 19;
123
124 /* TODO: requires testing */
125 uint16_t maximum_extra_paragraphs;
126 uint16_t minimum_extra_paragraphs;
127 uint8_t flags;
128 uint8_t lowest_used_interrupt;
129 uint8_t highest_used_interrupt;
130 uint8_t com_port_usage;
131 uint8_t lpt_port_usage;
132 uint8_t screen_usage;
133
134 void SetDefaults();
135
136 void ReadFile(Linker::Reader& rd);
137
138 void WriteFile(Linker::Writer& wr) const;
139
140 void Dump(Dumper::Dumper& dump, offset_t file_offset) const;
141 };
142
144 std::unique_ptr<PIF> pif;
145
147 std::shared_ptr<Linker::Contents> image;
148
149 magic_type GetSignature() const;
150
151 void SetSignature(magic_type magic);
152
153 void Clear() override;
154
155 ~MZFormat()
156 {
157 Clear();
158 }
159
160 void SetFileSize(uint32_t size);
161
162 uint32_t GetHeaderSize() const;
163
164 uint32_t GetPifOffset() const;
165
166 void ReadFile(Linker::Reader& rd) override;
167
169 offset_t WriteFile(Linker::Writer& wr) const override;
170
171 void Dump(Dumper::Dumper& dump) const override;
172
173 void CalculateValues() override;
174
175 /* * * Writer members * * */
176
178 {
179 public:
180 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"};
181 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"};
182 Linker::Option<offset_t> stack{"stack", "Specify the stack size"};
183
185 {
186 InitializeFields(header_align, file_align, stack);
187 }
188 };
189
206
207 /* filled in automatically */
209 uint16_t stack_size = 0;
210
212 uint16_t extra_paras = 0;
213
215 uint32_t zero_fill = 0;
216
218 uint32_t option_header_align = 0x10;
219
221 uint32_t option_file_align = 1;
222
223 bool FormatSupportsSegmentation() const override;
224
225 bool FormatIs16bit() const override;
226
227 bool FormatIsProtectedMode() const override;
228
229 unsigned FormatAdditionalSectionFlags(std::string section_name) const override;
230
231 static std::vector<Linker::OptionDescription<void>> MemoryModelNames;
232
233 std::vector<Linker::OptionDescription<void>> GetMemoryModelNames() override;
234
235 void SetModel(std::string model) override;
236
237 std::shared_ptr<Linker::OptionCollector> GetOptions() override;
238
239 void SetOptions(std::map<std::string, std::string>& options) override;
240
241 void OnNewSegment(std::shared_ptr<Linker::Segment> segment) override;
242
248
249 std::unique_ptr<Script::List> GetScript(Linker::Module& module);
250
254 void Link(Linker::Module& module);
255
256#if 0
260 void LinkLarge(Linker::Module& module);
261#endif
262
263 void ProcessModule(Linker::Module& module) override;
264
265 uint32_t GetDataSize() const;
266
267 void GenerateFile(std::string filename, Linker::Module& module) override;
268
270 std::string GetDefaultExtension(Linker::Module& module, std::string filename) const override;
271 };
272
274 {
275 public:
276 std::string filename;
277 bool valid = true;
278 std::ifstream stream;
279
280 MZSimpleStubWriter(std::string filename = "")
281 : filename(filename)
282 {
283 }
284
285 offset_t size = -1;
286
287 bool OpenAndCheckValidFile();
288
289 offset_t GetStubImageSize();
290
291 void WriteStubImage(std::ostream& out);
292
293 void WriteStubImage(Linker::Writer& wr);
294
296 {
297 if(stream.is_open())
298 {
299 stream.close();
300 }
301 }
302 };
303
305 {
306 public:
307 std::string filename;
308 bool valid = true;
309 std::ifstream stream;
310
311 MZStubWriter(std::string filename = "")
312 : filename(filename)
313 {
314 }
315
316 uint32_t original_file_size = -1;
317 uint32_t stub_file_size = 0;
318 uint16_t stub_reloc_count = 0;
319 uint32_t original_header_size = 0;
320 uint32_t stub_header_size = 0;
321 uint16_t original_reloc_offset = 0;
322 uint16_t stub_reloc_offset = 0;
323
324 bool OpenAndCheckValidFile();
325
326 offset_t GetStubImageSize();
327
328 void WriteStubImage(std::ostream& out);
329
330 void WriteStubImage(Linker::Writer& wr);
331
333 {
334 if(stream.is_open())
335 {
336 stream.close();
337 }
338 }
339 };
340
341 template <typename T, size_t N, typename Predicate>
342 offset_t FindActualSignature(Linker::Reader& rd, std::array<T, N>& signature, Predicate predicate, bool search_win386_offset = false)
343 {
344 offset_t file_offset = rd.Tell();
345 rd.ReadData(signature);
346 if(file_offset == 0 && !predicate(signature))
347 {
348 // try to find real file offset
349 offset_t file_end = rd.GetImageEnd();
350
351 rd.Seek(2);
352 uint32_t mz_image_end = rd.ReadUnsigned(2, ::LittleEndian);
353 mz_image_end = (uint32_t(rd.ReadUnsigned(2, ::LittleEndian)) << 9) - (-mz_image_end & 0x1FF);
354
355 uint32_t win386_header_offset = 0;
356 uint32_t ne_header_offset = 0;
357 if(file_end >= 0x40)
358 {
359 if(search_win386_offset)
360 {
361 rd.Seek(0x38);
362 win386_header_offset = rd.ReadUnsigned(4, ::LittleEndian);
363 }
364
365 rd.Seek(0x3C);
366 ne_header_offset = rd.ReadUnsigned(4, ::LittleEndian);
367 }
368
369 if(ne_header_offset != 0 && ne_header_offset + N < file_end)
370 {
371 rd.Seek(ne_header_offset);
372 rd.ReadData(signature);
373 }
374
375 if(predicate(signature))
376 {
377 file_offset = rd.Tell() - N;
378 }
379 else
380 {
381 if(mz_image_end != 0 && mz_image_end != ne_header_offset && mz_image_end + N < file_end)
382 {
383 rd.Seek(mz_image_end);
384 rd.ReadData(signature);
385 }
386
387 if(predicate(signature))
388 {
389 file_offset = rd.Tell() - N;
390 }
391 else
392 {
393 if(win386_header_offset != 0 && win386_header_offset != ne_header_offset && win386_header_offset != mz_image_end && win386_header_offset + N < file_end)
394 {
395 rd.Seek(win386_header_offset);
396 rd.ReadData(signature);
397 }
398
399 if(predicate(signature))
400 {
401 file_offset = rd.Tell() - N;
402 }
403 else
404 {
405 rd.Seek(N);
406 }
407 }
408 }
409 }
410
411 return file_offset;
412 }
413
414 template <typename T, size_t N>
415 offset_t FindActualSignature(Linker::Reader& rd, std::array<T, N>& signature, const char * expected_signature, bool search_win386_offset = false)
416 {
417 return FindActualSignature(
418 rd,
419 signature,
420 [expected_signature](std::array<T, N>& signature) { return memcmp(signature.data(), expected_signature, N) == 0; },
421 search_win386_offset);
422 }
423
424 template <typename T, size_t N>
425 offset_t FindActualSignature(Linker::Reader& rd, std::array<T, N>& signature, const char * expected_signature1, const char * expected_signature2, bool search_win386_offset = false)
426 {
427 return FindActualSignature(
428 rd,
429 signature,
430 [expected_signature1, expected_signature2](std::array<T, N>& signature) { return memcmp(signature.data(), expected_signature1, N) == 0 || memcmp(signature.data(), expected_signature2, N) == 0; },
431 search_win386_offset);
432 }
433
434 template <typename T, size_t N>
435 offset_t FindActualSignature(Linker::Reader& rd, std::array<T, N>& signature, const char * expected_signature1, const char * expected_signature2, const char * expected_signature3)
436 {
437 return FindActualSignature(
438 rd,
439 signature,
440 [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; },
441 false);
442 }
443}
444
445#endif /* MZEXE_H */
An abstract interface that separates structure and presentation of the data inside a file.
Definition dumper.h:773
offset_t WriteFile(Writer &wr) const override=0
Stores data in memory to file.
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:474
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, encapsulating functionality needed to import binary data.
Definition reader.h:20
void Seek(offset_t offset)
Jump to a specific location in the input stream.
Definition reader.cc:181
offset_t GetImageEnd()
Returns the last location that can be read.
Definition reader.cc:267
void ReadData(size_t count, void *data)
Read in a sequence of bytes.
Definition reader.cc:30
offset_t Tell()
Retrieve the current location.
Definition reader.cc:238
uint64_t ReadUnsigned(size_t bytes, EndianType endiantype)
Read an unsigned word.
Definition reader.cc:157
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
MZ .EXE format for MS-DOS.
Definition mzexe.h:37
uint16_t stack_size
Stack size requested at the command line.
Definition mzexe.h:209
offset_t WriteFile(Linker::Writer &wr) const override
Stores data in memory to file.
Definition mzexe.cc:243
void CreateDefaultSegments()
Create the required segments, if they have not already been allocated. The MZ format uses a single se...
Definition mzexe.cc:498
offset_t ImageSize() const override
Retrieves size of stored data.
Definition mzexe.cc:10
uint16_t relocation_offset
Offset to first relocation. Updated by CalculateValues.
Definition mzexe.h:81
uint16_t cs
Initial value for the code segment (CS)
Definition mzexe.h:79
void ReadFile(Linker::Reader &rd) override
Loads file into memory.
Definition mzexe.cc:176
uint16_t min_extra_paras
Minimum required extra memory, in paragraphs.
Definition mzexe.h:67
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:458
magic_type
Type of magic number, usually "MZ".
Definition mzexe.h:43
@ MAGIC_DL
HP 100LX/200LX System Manager modules (.exm) use the magic number "DL".
Definition mzexe.h:49
@ MAGIC_ZM
According to some sources such as Ralf Brown's interrupt list, some early excutables started with the...
Definition mzexe.h:47
@ MAGIC_MZ
The most common magic number "MZ".
Definition mzexe.h:45
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:478
void Link(Linker::Module &module)
Link application according to script or memory model.
Definition mzexe.cc:582
uint16_t checksum
Checksum.
Definition mzexe.h:75
void GenerateFile(std::string filename, Linker::Module &module) override
The main function that handles processing, calculating and generating the final image.
Definition mzexe.cc:723
uint16_t last_block_size
Size of last 512 byte block, 0 if full. Set by CalculateValues.
Definition mzexe.h:56
bool FormatSupportsSegmentation() const override
Whether the format supports multiple segments.
Definition mzexe.cc:383
uint16_t extra_paras
Required maximum extra paragraphs after bss.
Definition mzexe.h:212
uint32_t option_file_align
User provided alignment value for file align.
Definition mzexe.h:221
uint16_t header_size_paras
Size of MZ header. Updated by CalculateValues.
Definition mzexe.h:65
void CalculateValues() override
Intermediate step between processing module and generating output file to set up headers and manageme...
Definition mzexe.cc:332
uint16_t file_size_blocks
Size of MZ image in 512 blocks, rounded up. Set by CalculateValues.
Definition mzexe.h:58
void SetModel(std::string model) override
Sets the way memory is organized, typically modifying a built-in script.
Definition mzexe.cc:429
std::vector< Linker::OptionDescription< void > > GetMemoryModelNames() override
Returns a list of the supported memory models, used for documentation.
Definition mzexe.cc:424
uint32_t zero_fill
Total size of bss and stack.
Definition mzexe.h:215
bool FormatIsProtectedMode() const override
Whether the format is in protected mode or not (x86 only)
Definition mzexe.cc:393
uint16_t relocation_count
Number of relocations. Updated by CalculateValues.
Definition mzexe.h:63
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:280
uint16_t data_segment
Starting paragraph of program data, only required for .exm files.
Definition mzexe.h:86
memory_model_t
Represents the memory model of the running executable, which is the way in which the segments are set...
Definition mzexe.h:192
@ MODEL_LARGE
Large model, every section is a separate segment.
Definition mzexe.h:202
@ MODEL_SMALL
Small model, separate code and data segments.
Definition mzexe.h:198
@ MODEL_DEFAULT
Default model, same as small.
Definition mzexe.h:194
@ MODEL_TINY
Tiny model, code and data segment are the same.
Definition mzexe.h:196
@ MODEL_COMPACT
Compact model, separate code and multiple data segments.
Definition mzexe.h:200
std::shared_ptr< Linker::Contents > image
The program image, placed after the MZ header.
Definition mzexe.h:147
uint16_t ip
Entry point initial value for IP.
Definition mzexe.h:77
memory_model_t memory_model
Memory model of generated executable.
Definition mzexe.h:205
uint16_t sp
Initial value for the stack (SP)
Definition mzexe.h:73
char signature[2]
The magic number at the start of the executable file, usually "MZ".
Definition mzexe.h:53
std::vector< Relocation > relocations
Address relocation offsets to paragraph fixups.
Definition mzexe.h:115
uint32_t option_header_align
User provided alignment value for header size.
Definition mzexe.h:218
bool FormatIs16bit() const override
Whether the format is 16-bit or not.
Definition mzexe.cc:388
uint16_t ss
Initial value for the stack segment (SS)
Definition mzexe.h:71
std::string GetDefaultExtension(Linker::Module &module, std::string filename) const override
Appends a default extension to the filename.
Definition mzexe.cc:733
uint16_t overlay_number
Overlay number, should be 0 for main programs, not used for .exm files.
Definition mzexe.h:84
uint16_t max_extra_paras
Maximum required extra memory, in paragraphs. Set by CalculateValues using extra_paras.
Definition mzexe.h:69
std::unique_ptr< PIF > pif
Concurrent DOS program information entry, allocated only if present.
Definition mzexe.h:144
void ProcessModule(Linker::Module &module) override
Processes the module object and initializes format fields.
Definition mzexe.cc:623
void SetOptions(std::map< std::string, std::string > &options) override
Passes command line parameters as settings over to format object.
Definition mzexe.cc:463
Definition mzexe.h:274
Definition mzexe.h:305
Concurrent DOS embedded program information, produced by PIFED.
Definition mzexe.h:119
Represents a relocation entry in the header, as a pair of 16-bit words.
Definition mzexe.h:94
uint16_t segment
Segment of relocation.
Definition mzexe.h:96
uint16_t offset
Offset of relocation within segment.
Definition mzexe.h:98