An NE module’s code and data are segments of up to 64 KB. The segment table lists them, numbered from 1: where each one’s bytes are in the file, how large it is in the file and in memory, and how Windows should treat it. Everything else in the file refers to a segment by its number.
Segment entries
The table has ne_cseg
entries of 8 bytes, at ne_segtab
from the start of the NE header:
| Offset | Size | Field | Meaning |
|---|---|---|---|
| 0 | 2 | sector | Where the segment’s data starts, in units of 2ne_align bytes; 0 means it has no data in the file. |
| 2 | 2 | length | The number of bytes of data in the file; 0 means 65,536 when the sector is not 0. |
| 4 | 2 | flags | See Flags. |
| 6 | 2 | minalloc | The size of the segment in memory; 0 means 65,536. |
A segment can be larger in memory than in the file. The bytes the file does not store, such as uninitialised data, are not stored at all. A segment with sector 0 has nothing in the file and only takes memory.
Flags
The names below are Wine’s (NE_SEGFLAGS_* in winedump), unless the table
says otherwise.
| Bits | Meaning |
|---|---|
0x0007 | The type: 0 code, 1 data. |
0x0008 | Iterated data. |
0x0010 | Movable; otherwise fixed. |
0x0020 | Shareable. |
0x0040 | Preload; otherwise loaded when first called. |
0x0080 | Execute-only for a code segment, read-only for a data segment. |
0x0100 | Relocation records follow the data; see Segment data. |
0x1000 | Discardable: Windows may throw the segment away and load it again from the file. |
0x2000 | 32-bit. |
Wine also names 0x0002 “allocated” and 0x0004 “loaded”,
which are the loader’s own marks in memory, and 0x0800 “self-load”. OSDev
gives 0xF000 as a mask for the discard priority. The bits
0x0C00 are set in many ordinary files, as in the flags
0x0D50 below; what they mean was not confirmed, and the explorer leaves
them unnamed.
Segment data
A segment’s bytes are at file offset sector × 2ne_align, length
bytes of them. When flag 0x0100 is set, a 16-bit count follows the data,
then that many 8-byte relocation
records. Linkers pad between segments to the next sector.
The explorer shows each segment with its relocation records under it, and lists every
segment in its Segments table with its type, file offset, sizes, flags and number of
relocations. It disassembles every code segment that has data in the file, as 16-bit
code, or 32-bit when flag 0x2000 is set, with addresses counted from 0 in
the segment; see the x86 instruction reference. In
OS/2 files the last ne_cres segments are resources, not code or data; see
The resource table.
A segment whose relocation count would run into the next block, or past the end of the file, is shown with only the records that fit, and a note.
Worked example
TEST1.EXE has 4 segments, an alignment shift of 8 (256-byte sectors) and its segment
table at 0x140:
00000140 03 00 6D 0A 50 0D 6D 0A 13 00 B5 0E 50 0D B5 0E ..m.P.m.....P...
00000150 25 00 C1 0D 50 0D C1 0D 34 00 38 03 41 0D 18 07 %...P...4.8.A...
| Segment | Sector | File offset | In the file | Flags | In memory |
|---|---|---|---|---|---|
| 1 | 0x0003 | 0x300 | 2,669 bytes | 0x0D50: code, movable, preload, has relocations | 2,669 bytes |
| 2 | 0x0013 | 0x1300 | 3,765 bytes | 0x0D50: the same | 3,765 bytes |
| 3 | 0x0025 | 0x2500 | 3,521 bytes | 0x0D50: the same | 3,521 bytes |
| 4 | 0x0034 | 0x3400 | 824 bytes | 0x0D41: data, fixed, preload, has relocations | 1,816 bytes |
Segment 4 is the automatic data segment (ne_autodata 4): 824 bytes are
stored, and the rest of its 1,816 bytes in memory are not. Segment 1’s data runs from
0x300 to 0xD6D; there the count 96 00 says 150
relocation records follow, 1,200 bytes, to 0x121F. The file is padded
with zeros to segment 2 at 0x1300.