The optional header ends with an array of data directories, starting at its offset 112 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, which x64 and ARM64 images rely on. |
| 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 70 C0 00 00 E0 09 00 00
00000180 50 CA 00 00 F0 00 00 00 00 10 01 00 B4 01 00 00
00000190 00 00 01 00 34 0B 00 00 00 00 00 00 00 00 00 00
000001A0 00 20 01 00 20 00 00 00 10 B4 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 30 B4 00 00 94 00 00 00
000001D0 00 00 00 00 00 00 00 00 00 A0 00 00 30 04 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: offset 112 of the optional header, which starts at 0x108| # | Directory | RVA | Size | In |
|---|---|---|---|---|
| 0 | Export table | 0xC070 | 2,528 bytes | .rdata |
| 1 | Import table | 0xCA50 | 240 bytes | .rdata |
| 2 | Resource table | 0x11000 | 436 bytes | .rsrc |
| 3 | Exception table | 0x10000 | 2,868 bytes | .pdata |
| 5 | Base relocation table | 0x12000 | 32 bytes | .reloc |
| 6 | Debug | 0xB410 | 28 bytes | .rdata |
| 10 | Load config table | 0xB430 | 148 bytes | .rdata |
| 12 | IAT | 0xA000 | 1,072 bytes | .rdata |
The other eight entries are zero. The exception table holds 239 functions, 12 bytes each. 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; its size must be 0. Of the PE32+ machines only Itanium has one. x64 and ARM64 images 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.