An LE module’s code and data are held in objects, the 32-bit successors of segments.
The object table lists them: for each one its size and address in memory, its flags, and
which entries of the object page table hold its pages. It is at the header’s object table
offset (0x40, from the start of the LE header), with as many entries as the
header’s object count (0x44). Objects are numbered from 1.
Object entry
Each entry is 24 bytes:
| Offset | Size | Field | Meaning |
|---|---|---|---|
| 0 | 4 | Virtual size | The size of the object in memory. |
| 4 | 4 | Relocation base | The address the object is linked to run at. |
| 8 | 4 | Flags | Access, residency and the 32-bit flag. |
| 12 | 4 | Page table index | Its first entry in the object page table, from 1. |
| 16 | 4 | Page table entries | How many pages it has. |
| 20 | 4 | Reserved | See below. |
The object’s pages are entries index to index + entries − 1 of the page table; page j of the object (from 0) is loaded at the relocation base plus j × the page size.
In Windows VxDs built with Microsoft’s linker, the reserved word holds four letters,
such as LCOD and ICOD. They look like the class of the
segments the object was made from (locked code, initialisation code), but that is an
inference; no description of the field was found. The explorer shows them when all
four bytes are printable.
Object flags
The bits are IBM’s, from the LX description, with Open Watcom’s names where LE differs:
| Bit | Meaning |
|---|---|
0x0001 | Readable. |
0x0002 | Writable. |
0x0004 | Executable: the object holds code. |
0x0008 | Resource object. |
0x0010 | Discardable. |
0x0020 | Shared. |
0x0040 | Has preload pages. |
0x0080 | Has invalid pages. |
0x0700 | Residency: 0x100 permanent and swappable (Open Watcom’s name for LE; in LX the same value means zero-filled pages), 0x200 resident, 0x300 resident and contiguous, 0x400 resident and long-lockable. |
0x1000 | 16:16 alias required. |
0x2000 | Big/default: a 32-bit object. In code, the default operand and address size is 32 bits. |
0x4000 | Conforming, for code. |
0x8000 | I/O privilege. |
The explorer disassembles executable objects (0x0004) as 32-bit code
when 0x2000 is set and as 16-bit code otherwise. A 32-bit object’s
addresses count from its relocation base; a 16-bit object’s count from 0, as offsets in
its segment. See the x86 instruction reference.
Worked example
00000144 68 2A 00 00 00 00 00 00 45 20 00 00 01 00 00 00
00000154 16 00 00 00 4C 43 4F 44 5B 00 00 00 00 00 00 00 ....LCOD[.......
00000164 15 20 00 00 17 00 00 00 01 00 00 00 49 43 4F 44 . ..........ICOD
0xC4 from its LE header| Object | Size | Base | Flags | Pages | Reserved |
|---|---|---|---|---|---|
| 1 | 0x2A68 | 0 | 0x2045: readable, executable, has preload pages, 32-bit | 1 to 22 | LCOD |
| 2 | 0x5B | 0 | 0x2015: readable, executable, discardable, 32-bit | 23 | ICOD |
Both objects are 32-bit code linked at address 0. The second, small and
discardable, fits the initialisation code that Windows throws away once the driver has
started; that reading of ICOD is again an inference.