Fundamentals 11 min read

Common Misconceptions in iOS15 Dynamic Linking and Mach‑O Fixup Chains

This article clarifies three frequent misunderstandings about iOS15+ dynamic linking—namely the encoding of b/bl instructions, the need for rebase/bind in __TEXT segments, and the mismatch between Mach‑O segment VM size and file size—by explaining the underlying ARM64 architecture, PIC concepts, and providing concrete dyld tool examples.

ByteDance Terminal Technology
ByteDance Terminal Technology
ByteDance Terminal Technology
Common Misconceptions in iOS15 Dynamic Linking and Mach‑O Fixup Chains

Background – The performance‑oriented iOS15 dynamic linking fixup chain analysis sparked interest in the Mach‑O compilation and linking process, prompting a review of three typical beginner misconceptions.

Misconception 1: b/bl instructions contain absolute addresses

In Xcode’s disassembly view, the bl 0x10239e3a4 line appears to show an absolute address, but the ARM64 specification defines the low 26 bits of the instruction as a signed offset (imm26) relative to the program counter. The high 6 bits are reserved. By reading the raw bytes ( 0x9b010094 → little‑endian 0x9400019b ) and extracting imm26 = 0x19b , the absolute target address is computed as 0x10239dd38 + 0x19b * 4 = 0x10239e3a4 , matching Xcode’s output. The reachable range of b/bl is ±128 MiB.

(lldb) memory read 0x10239dd38
0x10239dd38: 9b 01 00 94 fd 7b 42 a9 ff c3 00 91 c0 03 5f d6  .....{B......._.
0x10239dd48: ff 43 00 d1 e0 07 00 f9 e1 03 00 f9 e8 07 40 f9  .C............@.

Conclusion – b/bl store a PC‑relative offset, not an absolute address.

Insight – Disassembly tools may present optimized views; understanding the underlying encoding prevents being misled.

Misconception 2: b/bl addresses in the __TEXT segment require rebase/bind

The belief stems from assuming that all addresses need runtime fix‑ups. However, the __TEXT segment is marked r‑x (read‑execute, not writable), so it cannot be modified at runtime. Only symbols residing in __DATA or __DATA_CONST need rebase or bind, following the PIC model used by Mach‑O.

External symbols are stored in __got (non‑lazy) or __la_symbos_ptr (lazy) sections, and the dyld tool dyld_info -fixups can list them. Example usage:

./dyld_info -fixups ./machoName > fixups.txt

Filtering for rebase or bind:

./dyld_info -fixups ./machoName | grep 'rebase' > rebase.txt ./dyld_info -fixups ./machoName | grep 'bind' > bind.txt

Conclusion – Only __DATA and __DATA_CONST segments contain addresses that require runtime fix‑ups.

Insight – The root cause is a misunderstanding of Mach‑O symbol resolution and the role of PIC, which also appears in Linux PLT/GOT mechanisms.

Misconception 3: Mach‑O segment VM size always equals file size

Observing that __TEXT and __DATA_CONST segments have matching sizes leads to the false generalisation that all segments behave similarly. In reality, file offsets are packed without alignment gaps, while VM addresses must be 4 KB aligned, causing possible size differences.

Illustrative code from the “deep‑understanding Mach‑O” blog shows how to compute the base of the __LINKEDIT segment and locate symbol tables:

// Find __LINKEDIT base address
uintptr_t linkedit_base = (uintptr_t)slide + linkedit_segment->vmaddr - linkedit_segment->fileoff;
// Locate symbol table
nlist_t *symtab = (nlist_t *)(linkedit_base + symtab_cmd->symoff);
// Locate string table
char *strtab = (char *)(linkedit_base + symtab_cmd->stroff);
// Indirect symbol table
uint32_t *indirect_symtab = (uint32_t *)(linkedit_base + dysymtab_cmd->indirectsymoff);

From these equations, the relationship between VM address and file offset can be expressed as:

symtab.vmaddr - __LINKEDIT.vmaddr = symtab.fileoff - __LINKEDIT.fileoff

Including ASLR (slide) yields:

symtab_base = linkedit_base + symtab.fileoff

Conclusion – VM size may be larger due to 4 KB alignment, while file size has no such requirement.

Insight – Relying solely on empirical observations without understanding the underlying alignment rules can lead to incorrect assumptions.

References

[1] "iOS15 Dynamic Linking Fixup Chain Detailed Explanation"

[2] ARM64 BL instruction encoding

[3] "iOS Programmer's Self‑Cultivation – Mach‑O Dynamic Linking (Part 4)"

[4] "Deep Understanding of Mach‑O Structure and Runtime System"

[5] StackOverflow answer on Mach‑O rebasing

[6] dyld4 source code (dyld_info.cpp)

[7] Zhihu discussion on Linux PLT/GOT

iOSMach-ODynamic LinkingassemblyBinary Analysisfixup
ByteDance Terminal Technology
Written by

ByteDance Terminal Technology

Official account of ByteDance Terminal Technology, sharing technical insights and team updates.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.