_EXAMINING OS/2 2.1 EXECUTABLE FILE FORMATS_ by John Rodley Listing One // NE and LX Header structures and structures of all fixed size table entry // types. Dummy struct that gets you file offset of "new" exe header. Ignores // MZ header items other than ID word and lfanew. Read at offset 0 of file. typedef struct { unsigned short magic; // MUST BE ASCII "MZ" char useless_bytes[34]; // Ignore these bytes unsigned long lfanew; // Here's the file offset of new exe header. } SIMPLE_MZ_EXE; // structure of NE header. Follows magic bytes "NE" in file. typedef struct { unsigned char ver; // Version. unsigned char rev; // Revision unsigned short enttab; // File offset of Entry Table from lfanew. unsigned short cbenttab; // Entry Table byte count. long crc; // CRC checksum of entire file. unsigned short flags; // Exe flags (such as ERROR ...) unsigned short autodata; // Segment num of Auto-DS seg, 1-based. unsigned short heap; // Segment number of heap, 1-based. unsigned short stack; // Segment number of stack, 1-based. unsigned short ip; // Initial value of IP register. unsigned short cs; // Initial value of CS register. unsigned short sp; // Initial value of SP register. unsigned short ss; // Initial value of SS register. unsigned short cseg; // # of segments in Segment Table. unsigned short cmod; // # of modules in Module Reference Table. unsigned short cbnrestab; // Byte count of Non-Res Name Table. unsigned short segtab; // Offset of Segment Table from lfanew. unsigned short rsrctab; // Offset of Resource Table from lfanew. unsigned short restab; // Offset of Res Name Table from lfanew. unsigned short modtab; // Offset of Module Ref Table from lfanew. unsigned short imptab; // Offset of Imp Name Table from lfanew. unsigned long nrestab; // Offset of Non-Resident Name Table from // beginning of file. unsigned short cmovent; // Number of movable entries. unsigned short align; // File sector size, Segments are aligned // on boundaries of this value. unsigned short cres; // Item count of Resource Table. char resv[10]; // reserved. } NE_EXE; // an entry in the NE Segment Table struct SEG { unsigned short ns_sector; // The file sector segment starts at. unsigned short ns_cbseg; // # of bytes in segment image. unsigned short ns_flags; // Type of segment (code,data ...) unsigned short ns_minalloc; // Minimum size in memory. }; // an entry in NE Module Reference Table. struct MOD_REF { unsigned index; // An index into the Imported Name Table. unsigned uModNum; // Module number used by Fixup Records // trying to use this Module Reference. }; // an entry in a NE Fixup Record Table struct NEW_REL { unsigned char target; // Type of target (see targets below) unsigned char source; // Type of source (see sources below) unsigned offset; // Offset in this segment of target. unsigned module_num; // Module number (see Mod Reference entry) if // source = 1 or 2, segment number if source = 0 unsigned ordinal; // target offset if source=0, function ordinal if // source=1 and function name, offset in Imported // Name Table if source=2 }; // Possible values for target #define NE_TARG_16SEG 2 // 16-bit segment #define NE_TARG_16SEGOFS 3 // 16-bit segment, 16-bit offset. #define NE_TARG_16OFS 5 // 16-bit offset. #define NE_TARG_16SEG32OFS 11 // 16-bit segment, 32-bit offset. #define NE_TARG_32OFS 13 // 32-bit offset. // Possible values for source #define NE_DEST_THISEXE 0 // Source is in this exe. #define NE_DEST_DLLBYORDINAL 1 // Source is imported by ordinal. #define NE_DEST_DLLBYNAME 2 // Source is imported by name. // Structure that defines the LX exe header. Follows the two magic bytes "LX". typedef struct { UCHAR ByteOrder; // LITTLE_ENDIAN or BIG_ENDIAN UCHAR WordOrder; // LITTLE_ENDIAN or BIG_ENDIAN ULONG FormatLevel; // Loader format level, currently 0 USHORT CpuType; // 286 through Pentium+ USHORT OSType; // DOS, Win, OS/2 ... ULONG ModVersion; // Version of this exe ULONG ModFlags; // Program/Library ... ULONG ModNumPgs; // Number of non-zero-fill or invalid pages ULONG EIPObjNum; // Initial code object ULONG EIP; // Start address within EIPObjNum ULONG ESPObjNum; // Initial stack object ULONG Esp; // Top of stack within ESPObjNum ULONG PgSize; // Page size, fixed at 4k ULONG PgOfsShift; // Page alignment shift ULONG FixupSectionSize; // Size of fixup information in file ULONG FixupCksum; // Checksum of FixupSection ULONG LdrSecSize; // Size of Loader Section ULONG LdrSecCksum; // Loader Section checksum ULONG ObjTblOfs; // File offset of Object Table ULONG NumObjects; // Number of Objects ULONG ObjPgTblOfs; // File offset of Object Page Table ULONG ObjIterPgsOfs; // File offset of Iterated Data Pages ULONG RscTblOfs; // File offset of Resource Table ULONG NumRscTblEnt; // # of entries in Resource Table ULONG ResNameTblOfs; // File offset of Resident Name Table ULONG EntryTblOfs; // File offset of Entry Table ULONG ModDirOfs; // File offset of Module Directives ULONG NumModDirs; // Number of Module Directives ULONG FixupPgTblOfs; // File offset of Fixup Page Table ULONG FixupRecTblOfs; // File offset of Fixup Record Table ULONG ImpModTblOfs; // File offset of Imp Module Table ULONG NumImpModEnt; // Number of Imported Modules ULONG ImpProcTblOfs; // File offset of Imported Proc Table ULONG PerPgCksumOfs; // File offset of Per-Page // Checksum Table ULONG DataPgOfs; // File offset of Data Pages ULONG NumPreloadPg; // Number of Preload Pages ULONG NResNameTblOfs; // File offset of Non Resident // Name Table from beginning of file! ULONG NResNameTblLen; // Length in bytes of Non Resident // Name Table; table is also NULL // terminated. ULONG NResNameTblCksum; // Non Resident Name Table checksum ULONG AutoDSObj; // Object number of auto data ULONG DebugInfoOfs; // File offset of debugging info ULONG DebugInfoLen; // Length of Debugging Info ULONG NumInstPreload; // Number of instance-preload pages ULONG NumInstDemand; // Number of instance-demand pages ULONG HeapSize; // Heap size ULONG StackSize; // Stack size } LX_EXE; // An entry in the LX object table typedef struct { ULONG size; // Load-time size of object ULONG reloc_base_addr; // Address the object wants to be loaded at. ULONG obj_flags; // Read/Write/Execute, Resource, // Zero-fill ... ULONG pg_tbl_index; // Index in Object Page Table at which this // object's first page is located. ULONG num_pg_tbl_entries; // Number of consecutive Object // Page Table entries that belong to this object. ULONG reserved; // reserved. } LX_OBJ; // An entry in the LX Object Page Table. typedef struct { ULONG offset; // File offset of this pages data. Relative to // beginning of Iterated or Preload Pages USHORT size; // Size of this page. <= 4096 USHORT flags; // Iterated, Zero-filled, Invalid ... } LX_PG; // An entry in the LX Fixup Page Table is a single 32-bit value. // possible values for LX Object Page Table flags member typedef enum pg_types { LX_DATA_PHYSICAL = 0, // Legal Physical Page, file offset // relative to Preload Pages LX_DATA_ITERATED, // Iterated Data Page, file offset relative to // Iterated Pages LX_DATA_INVALID, // Invalid page. LX_DATA_ZEROFILL, // Zero-filled page. LX_DATA_RANGE // Range of pages. }; // An entry in the LX Resource Table typedef struct { USHORT type_id; // one of rsc_types USHORT name_id; // ID application uses to load this resource ULONG size; // size of the resource USHORT object; // which object is this resource located in? ULONG offset; // resource offset within the object } LX_RSC; Listing Two // TwoArray.C - Two almost-64k arrays, with one reference to each. // NE builds 3 segments for this, LX one object with 64 4k-pages. #include int array1[32767]; int array2[32767]; int main(){ array1[0] = 1; array2[0] = 2; return( 0 ); } Listing Three // SixRef.C - Three almost-64k arrays, with two references to each. // NE uses 3 fixups for the references, LX 6. #include int array1[32767], array2[32767], array3[32767]; int main(){ array1[0] = 1; array1[1] = 2; array2[0] = 1; array2[1] = 2; array3[0] = 1; array3[1] = 2; return( 0 ); } Listing Four // ThreeExt.C - Three DLL calls. NE uses 1 fixup record with the three targets // chained together. LX uses three fixups, no chain. #define INCL_DOSPROCESS #include int main(){ DosSleep( 2 ); DosSleep( 2 ); DosSleep( 2 ); return( 0 ); } Listing Five 000F:0001 8BEC MOV BP,SP 000F:0003 B80000 MOV AX,0000 000F:0006 9A72020F00 CALL 000F:0272 000F:000B 57 PUSH DI 000F:000C 56 PUSH SI 7: DosSleep( 2 ); DosSleep( 2 ); DosSleep( 2 ); 000F:000D 6A00 PUSH 00 000F:000F 6A02 PUSH 02 000F:0011 9A1B000000 CALL 0000:001B 000F:0016 6A00 PUSH 00 000F:0018 6A02 PUSH 02 000F:001A 9A24000000 CALL 0000:0024 000F:001F 6A00 PUSH 00 000F:0021 6A02 PUSH 02 000F:0023 9AFFFF0000 CALL 0000:FFFF 8: return( 0 ); } 000F:0028 B80000 MOV AX,0000 000F:002B E90000 JMP 002E 000F:002E 5E POP SI 000F:002F 5F POP DI 000F:0030 C9 LEAVE