The optional header ends with an array of data directories, starting at its offset 96 in a PE32 file. Each one locates a table that Windows or a tool needs: the imports, the exports, the resources, the relocations and the rest. Most of these tables lie inside sections, so the address is an RVA; the section table turns it into a file offset.
The entries
Each entry is 8 bytes, IMAGE_DATA_DIRECTORY:
| Offset | Size | Type | Field | Meaning |
|---|---|---|---|---|
| 0 | 4 | u32 | VirtualAddress | The RVA of the table, or 0 when there is none. For entry 4 it is a file offset. |
| 4 | 4 | u32 | Size | The size of the table in bytes. |
The entries, in order:
| # | Directory | Notes |
|---|---|---|
| 0 | Export table | The export directory, often in .edata or .rdata. |
| 1 | Import table | The import descriptors. |
| 2 | Resource table | The root of the resource tree, the start of .rsrc. |
| 3 | Exception table | The function table in .pdata. x86 programs have none. |
| 4 | Certificate table | A file offset, not an RVA: the table is not loaded. |
| 5 | Base relocation table | The relocation blocks, usually .reloc. |
| 6 | Debug | The debug directory, 28 bytes an entry. |
| 7 | Architecture | Reserved, 0. |
| 8 | Global pointer | The value for the global pointer register; size 0. |
| 9 | TLS table | The thread-local storage directory. |
| 10 | Load config table | The load configuration directory. |
| 11 | Bound import | Usually in the headers, after the section table. |
| 12 | IAT | The import address tables, together, so that the loader can make them writable while it fills them. |
| 13 | Delay import descriptor | The delay-load descriptors. |
| 14 | CLR runtime header | Present in .NET assemblies. |
| 15 | Reserved | 0. |
Windows reads at most 16 entries. NumberOfRvaAndSizes says how many there are, and SizeOfOptionalHeader how much room they have; the explorer reads the smaller of NumberOfRvaAndSizes and the number that fit. It shows where each table lies, by section, and reports one that lies outside every section, or one whose size runs past the end of its section.
00000170 90 A4 00 00 E0 09 00 00
00000180 70 AE 00 00 F0 00 00 00 00 D0 00 00 B4 01 00 00
00000190 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
000001A0 00 E0 00 00 6C 08 00 00 70 A1 00 00 1C 00 00 00
000001B0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
000001C0 00 00 00 00 00 00 00 00 90 A1 00 00 40 00 00 00
000001D0 00 00 00 00 00 00 00 00 00 90 00 00 10 02 00 00
000001E0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
000001F0 00 00 00 00 00 00 00 00
0x178| # | Directory | RVA | Size | In |
|---|---|---|---|---|
| 0 | Export table | 0xA490 | 2,528 bytes | .rdata |
| 1 | Import table | 0xAE70 | 240 bytes | .rdata |
| 2 | Resource table | 0xD000 | 436 bytes | .rsrc |
| 5 | Base relocation table | 0xE000 | 2,156 bytes | .reloc |
| 6 | Debug | 0xA170 | 28 bytes | .rdata |
| 10 | Load config table | 0xA190 | 64 bytes | .rdata |
| 12 | IAT | 0x9000 | 528 bytes | .rdata |
The other nine entries are zero. The import descriptors take 240 bytes: eleven DLLs and the zero descriptor that ends them, 20 bytes each.
Architecture
Entry 7 is reserved and must be 0. A few of the files examined for this site, made by old or unusual linkers, have something there; the explorer shows the entry and does not read what it points at.
Global pointer
Entry 8 holds the RVA of the value to be stored in the global pointer register, on processors that have one, such as MIPS and Itanium; its size must be 0. x86 has no global pointer register, and x86 programs leave the entry 0.
Reserved
Entry 15 is reserved and must be 0. As with entry 7, a few old or unusual files have something there, which the explorer shows but does not read.