Mobile Development 31 min read

Understanding Fixup Chain: Apple’s New Dynamic Linking Technique in iOS 15

Fixup chain, introduced in iOS 15, replaces the previous compressed‑byte‑stream rebase/bind format with a linked‑list style structure that stores dynamic‑link information more compactly, improves space locality, reduces binary size, and speeds up app launch by allowing a single pass rebase and bind process.

ByteDance Terminal Technology
ByteDance Terminal Technology
ByteDance Terminal Technology
Understanding Fixup Chain: Apple’s New Dynamic Linking Technique in iOS 15

What is Fixup Chain?

Fixup chain is a new dynamic‑linking mechanism used by Apple on iOS 15 and later. It first appeared in Xcode 13’s release notes and is described briefly in the WWDC 21 session.

All programs and dylibs built with a deployment target of macOS 12 or iOS 15 or later now use the chained fixups format. This uses different load commands and LINKEDIT data, and won’t run or load on older OS versions. (49851380)

The Mach‑O file generated with fixup chain stores rebase and bind information as a chain of nodes, similar to a linked list, rather than the previous compressed opcode streams.

Advantages Over the Compressed Byte‑Stream Scheme

More compact storage reduces the final binary size.

Better spatial locality leads to faster application start‑up.

Spatial locality means that memory pages accessed close together in time are likely to be near each other, allowing the CPU cache to work more efficiently.

Background: Dynamic Linking Basics

When an app uses symbols from a dynamic library (dylib, framework, etc.), the static linker records those symbols as “unbound”. At launch, the operating system’s dynamic linker dyld loads the required libraries, resolves the symbols, and patches the unbound addresses.

Dynamic linking involves two kinds of symbols:

Lazy symbols – resolved on first use.

Non‑lazy symbols – resolved during program load.

dyld performs two core steps: rebase (adjusting addresses for ASLR) and binding (resolving external symbols).

Rebase Phase

ASLR (Address Space Layout Randomization) randomizes the load address of a Mach‑O image. Rebase updates every address that depends on the original load address by adding the slide value.

Binding Phase

Binding replaces placeholder pointers in the __la_symbol_ptr (lazy) and __nl_symbol_ptr (non‑lazy) sections with the actual addresses of symbols in the loaded libraries, using the helper dyld_stub_binder .

Compressed Byte‑Stream Scheme (Pre‑iOS 15)

Before iOS 15, rebase and bind information were stored as opcode streams inside the LC_DYLD_INFO_ONLY load command. The streams include Rebase info, Bind info, Lazy info, Weak info, and Export info.

Problems with the Byte‑Stream Approach

Two separate passes (rebase then bind) cause redundant page accesses, hurting spatial locality.

The opcode streams remain in the binary after linking, wasting space.

Fixup Chain Scheme

Fixup chain stores each rebase or bind operation in a node that also points to the next node, forming a linked list. dyld walks the list, performs the operation, and overwrites the node with the final 64‑bit address, reusing the same memory.

The chain is described by several structures placed in the __LINKEDIT segment:

linkedit_data_command – load command for LC_DYLD_CHAINED_FIXUPS .

dyld_chained_fixups_header – header of the fixup data.

dyld_chained_starts_in_image – describes per‑segment fixup starts.

dyld_chained_starts_in_segment – per‑segment page information.

dyld_chained_import – import table entries (library ordinal, name offset, etc.).

dyld_chained_ptr_64_rebase / dyld_chained_ptr_64_bind – node formats for rebase and bind.

During loading, dyld builds a targetAddrs array from the import table, then walks each segment’s pages according to dyld_chained_starts_in_segment , processing nodes until the chain ends.

Benefits of Fixup Chain

Approximately 50 % reduction in space used for dynamic‑link information, leading to smaller app bundles.

Single‑pass rebase/bind eliminates redundant page faults and compression‑decompression cycles, resulting in faster app launch on iOS 15 and later.

In summary, fixup chain simplifies the Mach‑O layout, reuses the 64‑bit pointer space for both metadata and final addresses, and provides measurable performance and size improvements for iOS applications.

iOSMach-ODynamic LinkingrebaseBINDfixup chain
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.