Intel defined the format in its Hexadecimal Object File Format Specification, Revision A (6 January 1988), which describes 8-bit, 16-bit and 32-bit forms. The format itself is older: Intel designed it in 1973 to load programs into its Intellec MDS development systems from paper tape, and added the 8086 segment records around 1978.
Record layout
A file is a sequence of records. Each record is ASCII text: a colon, then pairs of hexadecimal digits, each pair one byte, in upper case. Records are normally one per line, ending in CR LF or LF, but the colon alone marks where a record starts, and anything before the colon is ignored. Addresses are big-endian (most significant byte first).
| Characters | Bytes | Field (Intel’s name) | Meaning |
|---|---|---|---|
| 1 | — | Record mark | : (0x3A). |
| 2 | 1 | Record length (RECLEN) | Number of bytes in the data field, 00 to FF. 8, 16 and 32 are common; not all software copes with more than 16. |
| 4 | 2 | Load offset (LOAD OFFSET) | For data records, the 16-bit address of the first data byte, relative to the current base address. 0000 in every other record type. |
| 2 | 1 | Record type (RECTYP) | 00 to 05; see record types. |
2 × RECLEN | RECLEN | Data (INFO or DATA) | The bytes the record carries. |
| 2 | 1 | Checksum (CHKSUM) | Makes the eight-bit sum of every byte from RECLEN to the checksum zero; see checksum. |
Record types
| Type | Name | RECLEN | Load offset | Data |
|---|---|---|---|---|
00 | Data record | 0–255 | address of the first byte | The bytes to load. |
01 | End of file record | 00 | 0000 | None. It must be the last record and appear exactly once; it is always :00000001FF. |
02 | Extended segment address record | 02 | 0000 | A 16-bit segment base (USBA). Bits 4–19 of the address of the data records that follow. |
03 | Start segment address record | 04 | 0000 | The 8086 start address: two bytes of CS, then two bytes of IP. |
04 | Extended linear address record | 02 | 0000 | A 16-bit upper linear base (ULBA). Bits 16–31 of the address of the data records that follow. |
05 | Start linear address record | 04 | 0000 | The 32-bit start address (the 80386 EIP), big-endian. |
No other record types are defined.
The three forms
| Form | Other names | Record types | Address space |
|---|---|---|---|
| 8-bit | I8HEX, HEX-80 | 00, 01 | 64 KiB: the load offset is the address. |
| 16-bit | I16HEX, HEX-86 | 00–03 | 1 MiB, 8086 segments. |
| 32-bit | I32HEX, HEX-386 | 00, 01, 04, 05 | 4 GiB, flat. |
The file does not say which form it uses; a reader learns it from the record types it meets.
Working out addresses
A base address starts at zero and is changed by each type 02 or
04 record; it applies to every data record until the next such record. For
data byte number DRI (counting from 0) of a record whose load offset is
DRLO:
| After | Address of the byte |
|---|---|
| no address record | (DRLO + DRI) MOD 64K |
type 02 | USBA × 16 + ((DRLO + DRI) MOD 64K) |
type 04 | (ULBA × 65536 + DRLO + DRI) MOD 4G |
So in the segment form the offset wraps around inside the 64 KiB segment: a record at
offset FFFE with four bytes puts the last two at offsets
0000 and 0001 of the same segment, not in the next one. In the
linear form the address simply carries into the upper 16 bits. Writers avoid relying
on either and start a new address record at each 64 KiB boundary.
Checksum
Add every byte of the record from RECLEN to the last data byte, keep the
lowest eight bits, and take the two’s complement (256 minus the sum, or 0 when the sum
is 0). A reader can check a record by adding all its bytes including the checksum: the
lowest eight bits must be zero.
:0300300002337A1E
03 + 00 + 30 + 00 + 02 + 33 + 7A = E2
0x100 − 0xE2 = 0x1E checksum 1E
check: E2 + 1E = 100, low byte 00
02 33 7A at 0x0030) and its checksum.Examples of every record type
| Record | Meaning |
|---|---|
:10010000214601360121470136007EFE09D2190140 | Type 00: sixteen bytes 21 46 01 … at offset 0x0100. 10 + 01 + 00 + 00 = 0x11 and the data bytes add up to 0x3AF; the total 0x3C0 has low byte C0, so the checksum is 40. |
:00000001FF | Type 01: end of file. The only byte that is not zero is the type, so the checksum is 0x100 − 0x01 = FF. |
:020000021200EA | Type 02: segment base 0x1200, so later data records load at 0x12000 + offset. 02 + 02 + 12 = 0x16; checksum EA. |
:0400000300003800C1 | Type 03: start at CS:IP = 0000:3800. 04 + 03 + 38 = 0x3F; checksum C1. |
:020000040800F2 | Type 04: upper address 0x0800, so later data records load at 0x08000000 + offset. 02 + 04 + 08 = 0x0E; checksum F2. |
:04000005000000CD2A | Type 05: start address 0x000000CD. 04 + 05 + CD = 0xD6; checksum 2A. |
A whole file
:020000040800F2
:10000000000002200D010008110100081301000882
:040000050800010DE1
:00000001FF
0x08000000, sixteen bytes at 0x08000000, start address 0x0800010D, end.The data line: 10 + 00 + 00 + 00 = 0x10, and the data bytes
00 00 02 20 0D 01 00 08 11 01 00 08 13 01 00 08 add up to
0x6E; 0x10 + 0x6E = 0x7E, so the checksum is
0x100 − 0x7E = 82. The start line:
04 + 05 + 08 + 01 + 0D = 0x1F; checksum E1.
Gaps between data records are simply memory the file does not describe; a tool that converts the file to a flat binary has to choose a value to fill them with. Early Intel documents also asked for a leader and trailer of at least 25 NUL characters around the records, for paper tape; many programs ignore that requirement.
Sources
- Hexadecimal Object File Format Specification, Revision A – Intel, 6 January 1988; read through the quotations below, not opened directly
- srec_intel(5) – the SRecord package’s description of the format, which quotes Intel’s address formulas (
MOD 64K,MOD 4G) - Intel HEX – Wikipedia: record fields, the six types, the three forms, the checksum example, history and the NUL leader
The checksums in the examples were worked out by hand for this page.