Symbols, string tables and dynamic linking
Mach-O separates several related ideas that beginners often collapse into “the symbol table.”
LC_SYMTAB points to two regions:
- an array of symbol records;
- a string table containing symbol names.
Each symbol record stores an index into the string table rather than embedding a full name.
Static relocations and runtime fixups are different things
Object files and some linked images can carry relocation records associated with sections. In a section record, fields such as reloff and nreloc locate those relocation entries.
There is not a generic Mach-O load command named LC_RELOC.
Modern dynamic loading uses additional dyld metadata. Depending on the image and toolchain generation, you may encounter:
LC_DYLD_INFOorLC_DYLD_INFO_ONLY, which point to encoded rebase, bind, weak-bind, lazy-bind, and export information;LC_DYLD_EXPORTS_TRIE, which points to an export trie;LC_DYLD_CHAINED_FIXUPS, which points to modern chained-fixup data.
Do not assume one historical representation. Follow the load commands actually present in the file.
A symbol is not necessarily a function
A name in a symbol table can represent different kinds of entities. Likewise, executable code can exist without a helpful exported symbol name.
Use symbols as evidence, not as ground truth for function boundaries.
Imports are relationships
When you see an imported API, ask:
- which dependency provides it;
- which dyld metadata describes the reference;
- where the call or data-reference site lives;
- whether compiler-generated stubs or wrappers are involved;
- whether stripping changed what names remain visible.
Stripping changes convenience, not executable meaning
Removing many symbols can make human analysis harder, but the loader still needs enough structural information to load and fix up the image. This is why dyld metadata often remains useful when a binary has few conventional symbols.