Add DOS MZ and COM test inputs for the cle loader - #232
Conversation
Before this change every file here that starts with the MZ magic is a PE image whose MZ header belongs to a stub, so nothing in the repository exercises a loader for MS-DOS executables, and 99 of those 106 stubs declare no relocations at all. tests/i386/dos/hello.exe is an ordinary real-mode MZ program: three content segments plus a stack of its own, an entry point away from the start of the load module, and five relocations -- two far pointers held in data, the segment word of a far call, and two segment values loaded into a register. tests/i386/dos/hello_tiny.exe is the same program in the .COM memory model, where the header's CS and SS wrap below the load module to name the Program Segment Prefix, and its SP puts the unwrapped reading of SS:SP exactly on the 1 MiB ceiling. tests/i386/dos/hello.com is a flat .COM image with no header and no magic. tests_src/dos carries the assembly for all three and a build script that rebuilds them in place from a pinned nixpkgs revision, using nasm, Open Watcom and fasm. No header field is written by hand. All three run under DOSBox.
|
THIS MESSAGE WAS GENERATED BY AN AUTOMATED PROCESS Validation record for head The build script reproduces the committed bytesThe four files in All three match the committed files, and Tools resolved from the pinned nixpkgs revision A byte-for-byte match only means something if the build could have produced a All three are DOS programs that runOne headless DOSBox 0.74-3 invocation, all three in the same batch, each program's A 5-byte probe that does
hello_tiny.exe's stack sits in the PSP, and that was measuredIt starts with Header fields, read back out of the committed bytes
The consumerA DOS MZ loader backend for On No workspace-gate result is claimed for this change: the diff is three binaries, What did not runNo hosted check is expected here. The check-runs API returns Two workflows are registered. |
|
THIS MESSAGE WAS GENERATED BY AN AUTOMATED PROCESS What a consumer sees when it opens these three fixtures, before and after the Before — cle master 0e77ade3The control is there so the three refusals mean something: the same After — the two with the consumer changeAfter — with the consumer change |
THIS MESSAGE WAS GENERATED BY AN AUTOMATED PROCESS
Problem
clecannot load an MS-DOS executable. It refuses one outright:That is angr/angr#48, open since December 2015, and this
repository has no input a fix for it could be tested against. Before this change
106 tracked files start with the
MZmagic; readinge_lfanewat offset0x3cfrom each and the four bytes it points at gives
PE\0\0106 times out of 106.Every one is a PE image whose MZ header belongs to a stub, and 99 of the 106
declare no relocations at all, so none of them exercises the one thing a DOS
loader has to do.
Root cause
Nothing in the ecosystem has ever loaded a real-mode DOS program, so no DOS
fixture was needed.
Fix
Three fixtures, built from assembly written for this purpose, plus the sources and
the build script that produce them. Every header value below is read back out of
the committed bytes.
tests/i386/dos/hello.exe, 794 bytes, sha256157b8cb060ae2ab393fa0b2d02edc321fca003a80bdb6023a529ffc6570af22b. An ordinaryreal-mode MZ executable: a 64-byte header, a 730-byte load module, and an entry
point at
0028:0032rather than at the start of the load module. The linker put itin four segments -- data at
0000, a 512-byte stack at0008, and two codesegments sharing frame
0028-- which is a fact about the link map rather thanabout the file, because MZ has no segment table and a loader sees one flat load
module.
Its five relocations are what make it worth having. The table at
e_lfarlcholdsthem as
segment:offsetpairs; the load-module offset each one resolves to, andthe word stored there, are:
A loader that applies them puts the image at some paragraph and adds it to each of
those five words; one that ignores the table leaves all five at their file values,
so every far call and far pointer in the program points at the wrong segment.
tests/i386/dos/hello_tiny.exe, 160 bytes, sha256758b1946baba075466f137b9725d466124b8bcbadc28c94bd1f6dde1a98fef0b. The sameprogram in the
.COMmemory model, where the header's segment fields wrap:DOS adds those to the run-time load segment in 16-bit arithmetic, so
0xfff0meansthe paragraph sixteen below the load module -- the Program Segment Prefix -- and
both the entry point and the top of the stack land on offset 0 of the image. Read
as plain unsigned paragraph counts they would be a megabyte past a 160-byte file.
e_spis0x0100rather than something larger on purpose:0xfff0 * 16 + 0x100isexactly
0x100000, so a loader whose upper bound is inclusive accepts both readingsand has nothing to choose between them.
tests/i386/dos/hello.com, 108 bytes, sha2565bab2c65c03eff9853f3ca74ed52881e37a043873fa15e769fc1dac0ade358f5. A flat.COMimage: no header, no magic -- its first two bytes are
ba 2d-- andorg 0x100.It is the negative control, a DOS program that a DOS executable loader must not
claim.
tests_src/dos/carriesdos_mz.asm,dos_mz_tiny.asm,dos_com.asmandbuild.sh, which builds all three in place. Every tool comes from nixpkgs pinnedat
42f17a57f4f6e33b3de3dca0a2a5ea5233169d02:nasmfor the.COM, Open Watcom'swasmandwlinkforhello.exe, andfasmforhello_tiny.exe, whoseformat MZwriter is what turnsentry code_seg-10h:startintoe_cs = 0xfff0.No header byte is written by hand. Open Watcom is unfree in nixpkgs under the
Sybase Open Watcom Public License, so that one step sets
NIXPKGS_ALLOW_UNFREE=1;the assembly is ours and links no Watcom runtime library.
Testing
build.shwas run from a clean extraction of the committed sources and rewrote allthree fixtures byte-identically. All three are real DOS programs: they print
through
INT 21h, exit throughINT 21h/4Ch, and run under DOSBox.What a DOS MZ loader makes of each of the three, before and after, is in a comment
below.
Validation: #232 (comment)
session: sharpen