A fixup is a place in a page that the loader must patch: with the address of something in another object, which depends on where the objects are loaded, or with the address of a procedure imported from another module. Fixups are kept per page, so that the loader can patch each page as it reads it. Two tables in the fixup section hold them: the fixup page table and the fixup records.
Fixup page table
At the header’s fixup page table offset (0x68, from the start of the LX
header) there is one 32-bit offset for each page, and one more at the end: the number
of pages plus 1 entries. Each is an offset into the fixup record table. The records of
page p (from 1) run from entry p − 1 to entry p, so a
page whose two entries are equal has no fixups, and the last entry is the size of the
fixup record table.
00000198 00 00 00 00 18 01 00 00 6A 05 00 00 B2 08 00 00
000001A8 C6 0A 00 00
0x118, page 2’s from 0x118 to 0x56A, page 3’s to 0x8B2 and page 4’s to 0xAC6Fixup records
The fixup record table is at the header’s offset 0x6C. A record is
built from these parts, in order:
| Size | Field | Meaning |
|---|---|---|
| 1 | Source | The kind of value to patch, and whether a source list follows. |
| 1 | Flags | The kind of target, and the sizes of the fields that follow. |
| 2 or 1 | Source offset, or count | The offset in the page of the place to patch, a signed 16-bit number; or, when the source byte has 0x20, the 8-bit number of source offsets in the list at the end. |
| varies | Target | What to patch it with. |
| 0, 2 or 4 | Additive value | Present when the flags have 0x04: a value added to the target, 32-bit when the flags have 0x20. |
| 2 × count | Source list | With the source list bit: the 16-bit offsets in the page of each place to patch. |
A value that crosses into the next page gets a record in each page; the record in the second page has a negative source offset. The explorer splits the records by page, shows every field, and uses the imported targets to label the code.
Source types
| Source byte | Meaning |
|---|---|
0x00 | A byte. |
0x02 | A 16-bit selector. |
0x03 | A 16:16 pointer: a 16-bit offset and a selector. |
0x05 | A 16-bit offset. |
0x06 | A 16:32 pointer: a 32-bit offset and a selector. |
0x07 | A 32-bit offset. |
0x08 | A 32-bit offset relative to the place itself, as in a near call or jmp. |
0x10 bit | A fixup to a 16:16 alias. |
0x20 bit | A source list follows the target. |
The type is the low four bits; 1 and 4 are undefined.
Target flags
| Bits | Meaning |
|---|---|
0x03 | The target type: 0 internal reference, 1 imported by ordinal, 2 imported by name, 3 internal reference through the entry table. |
0x04 | An additive value is present. |
0x08 | Internal chaining, in Open Watcom’s name; IBM’s 1992 text calls it reserved. |
0x10 | The target offset (or ordinal, or procedure name offset) is 32 bits, not 16. |
0x20 | The additive value is 32 bits, not 16. |
0x40 | The object number or module ordinal is 16 bits, not 8. |
0x80 | The import ordinal is 8 bits. |
Targets
| Target type | Target data |
|---|---|
| 0, internal | The object number, 1 or 2 bytes, then the offset in it, 2 or 4 bytes. A 16-bit selector fixup has no offset. |
| 1, by ordinal | The module ordinal in the import module table, 1 or 2 bytes, then the procedure’s ordinal, 1, 2 or 4 bytes. |
| 2, by name | The module ordinal, 1 or 2 bytes, then the offset of the procedure’s name in the import procedure table, 2 or 4 bytes. |
| 3, through the entry table | An ordinal in this module’s entry table, 1 or 2 bytes. |
Worked example
000001AC 07 00 5B 01 01 1E 16 07 00 53 01 01 C5 15 07 00
Source 0x07, a 32-bit offset; flags 0, an internal reference with an
8-bit object number and a 16-bit offset; source offset 0x015B in the page;
object 1, offset 0x161E. Page 1 is the start of object 1, which is linked at
0x10000, so the 32-bit value at 0x1015B is set to the address
of 0x161E in object 1: 0x1161E if the object is loaded where it
was linked. The next record patches the value at 0x0153 with object 1 +
0x15C5.