The symbol table belongs to COFF object files, where it names every function and variable for the linker. Microsoft’s specification calls it deprecated in images, and Microsoft’s linker leaves it out, putting debug information in a PDB instead. GNU ld keeps it: programs and DLLs built with MinGW, Cygwin or Wine often still have it, with the long section names of their DWARF debug information in its string table. The COFF file header locates it: PointerToSymbolTable is its file offset and NumberOfSymbols the number of records. Like the certificate table, it lies after the sections and is not loaded.
Symbol records
IMAGE_SYMBOL, 18 bytes, with no padding between records:
| Offset | Size | Type | Field | Meaning |
|---|---|---|---|---|
| 0 | 8 | char[8] or u32 × 2 | Name | The name, zero-padded, when it fits in 8 bytes. Otherwise 4 zero bytes, then the offset of the name in the string table. |
| 8 | 4 | u32 | Value | Depends on the storage class: for a function or variable, its offset in its section. |
| 12 | 2 | i16 | SectionNumber | The section it is in, counting from 1. 0: undefined (external); −1: an absolute value, not an address; −2: a debugging symbol. |
| 14 | 2 | u16 | Type | The symbol’s type. A value of 0x20 (function) in bits 4–7 marks a function; the other bits are rarely used. |
| 16 | 1 | u8 | StorageClass | See Storage classes. |
| 17 | 1 | u8 | NumberOfAuxSymbols | The number of auxiliary records that follow this one. |
The explorer names code in the disassembly from this table: every symbol in a code section that is marked a function or has the EXTERNAL class, at the section’s address plus Value, unless that address already has a name.
Storage classes
| Value | Name | Value | Name |
|---|---|---|---|
| 0 | NULL | 13 | TYPE_DEFINITION |
| 1 | AUTOMATIC | 14 | UNDEFINED_STATIC |
| 2 | EXTERNAL | 15 | ENUM_TAG |
| 3 | STATIC | 16 | MEMBER_OF_ENUM |
| 4 | REGISTER | 17 | REGISTER_PARAM |
| 5 | EXTERNAL_DEF | 18 | BIT_FIELD |
| 6 | LABEL | 100 | BLOCK (.bb and .eb) |
| 7 | UNDEFINED_LABEL | 101 | FUNCTION (.bf and .ef) |
| 8 | MEMBER_OF_STRUCT | 102 | END_OF_STRUCT |
| 9 | ARGUMENT | 103 | FILE |
| 10 | STRUCT_TAG | 104 | SECTION |
| 11 | MEMBER_OF_UNION | 105 | WEAK_EXTERNAL |
| 12 | UNION_TAG | 107 | CLR_TOKEN |
| 255 | END_OF_FUNCTION |
The ones met in images are mainly EXTERNAL (2) for global functions and variables, STATIC (3) for local ones and for section symbols, and FILE (103) for the names of the source files.
Auxiliary records
A symbol can be followed by auxiliary records, 18 bytes each, counted in the record numbering. Their layout depends on the symbol before them:
- Function definitions (an EXTERNAL function): the tag index, the function’s size, pointers to its line numbers and to the next function.
.bfand.ef(FUNCTION class): line numbers of the start and end of a function.- Weak externals: TagIndex (4), the symbol to use instead, and Characteristics (4), how to search for it.
- Files (FILE class): the source file’s name in the record’s 18 bytes, continuing over as many records as it needs.
- Section definitions (a STATIC symbol named after a section): Length (4), NumberOfRelocations (2), NumberOfLinenumbers (2), CheckSum (4), Number (2), Selection (1) and 3 unused bytes.
The string table
The string table follows the last symbol record at once, at PointerToSymbolTable +
18 × NumberOfSymbols. It starts with its size, 4 bytes, which counts those 4 bytes;
then come the strings, each ending in a zero byte. A symbol or section name refers to
a string by its offset from the start of the table, so the first string is at offset
4. A section named /4 in the section
table has its real name, often .debug_info, at offset 4 here.