Static vs Dynamic Framework Dispatching (Part 1 of 3): Dispatching Under the Hood

Static vs Dynamic Framework Dispatching (Part 1 of 3): Dispatching Under the Hood

This is Part 1 of a 3-part series:

  • Part 1: Dispatching model — how calls into frameworks really work
  • Part 2: Hands-on experiments with SPM and Xcode frameworks
  • Part 3: Real-world edge cases — why DEBUG hides linking errors that only surface in RELEASE, and what this means for CI and App Store

TL;DR

  • A static framework is merged into the app binary at link time — the CPU calls it with a direct bl instruction, no runtime indirection.
  • A dynamic framework lives as a separate .dylib — every call goes through a stub → GOT → dyld chain.
  • dyld patches the GOT (__DATA_CONST,__got) at launch so subsequent calls hit the real address directly.
  • The dispatch mechanism is defined by the Mach-O format + linker + dyld — not by your build system.
  • SPM, Xcode, and CocoaPods are build tools. They decide how a framework is packaged — they do not change these dispatching rules.

Introduction

Every time you call MyMath.add(1, 2), your CPU executes a machine instruction that jumps from one binary into another. Something built that jump — you didn’t. The linker, dyld, and a few hundred bytes of generated stubs did it — and you’ve been trusting them without knowing exactly how.

As iOS engineers, we casually say:

  • “SPM builds statically by default.”
  • “This SDK is dynamic.”
  • “This framework is embedded.”

But very rarely do we ask the real questions:

  • How does the CPU actually jump from my app into framework(\library) code?
  • What actually Frameworks(\Libraries) Dispatching means?

This series is about that jump.
Not about marketing definitions, but about dispatching: how a symbol defined in another module becomes an actual machine instruction at runtime.

To understand this, we must go below Swift and Obj-C and talk about:

If this list already feels a bit overwhelming — that is totally fine. If you are reading this and thinking something like:

“I’ve heard some of these words before, but I don’t really understand how they fit together”

— you are exactly in the right place.

For now, treat these terms not as things we must already know,
but as characters in a story that we will introduce properly —
one by one, with pictures, commands, and evidence.


Big Picture: from source code to a real function call

Big Picture: from source code to a real function call

At a high level, every function call that crosses a module boundary goes through a long journey:

Linking → Mach-O → dyld → Symbols & Mangled Symbols → Stubs → dyld resolver (lazy binding logic)

This article is about understanding that journey.

When you write:

MyMath.add(1, 2)

you are not “calling a framework” in any abstract sense.
You are executing machine code that must somehow jump from:

your app binary  
another binary (a framework or library)  
  ↓↓  
into a concrete function implementation.

To make that jump possible, Apple’s toolchain relies on several layers:

  • the linker, which connects compiled object files together
  • the Mach-O file format, which stores symbols and relocation info
  • dyld, which loads binaries and resolves symbols at runtime
  • mangled symbols, which uniquely encode Swift/Obj-C names
  • stubs, which act as jump points in your binary
  • and the dyld resolver (lazy binding logic), which patches addresses on first use

Each of these pieces exists for a reason: performance, modularity, startup time, and memory sharing all depend on them.

Right now, this list may look intimidating.
If some of these terms are new to you — don’t rush to Google them yet.

We will walk through each concept step by step:

  • what it is,
  • why it exists,
  • and how you can see it inside a real compiled binary using terminal tools.

By the end, you should be able to look at a disassembly or a Mach-O section and say:

“Ah, this is the stub.”
“This is the GOT entry.”
“This is where dyld steps in.”

So let’s start unpacking this chain — one concept at a time.


Key Concepts Explained

Linking: What is it?

Before two object files can execute together, they need to agree on addresses. That negotiation is called linking — and it is the first thing that happens after compilation.

A linker (or link editor) takes one or more object files (produced by the compiler or assembler) and combines them into:

  • an executable (our app)
  • a library (static .a or dynamic .dylib / framework)
  • or another “object” file

Linking usually happens immediately after compilation. Even if compilation and linking are technically separate steps, we often refer to the whole process simply as building.

This step is crucial because it resolves symbols — the functions, methods, or variables used in our code — and determines how code from multiple modules or frameworks is combined into our final app binary.

Apple WWDC 2022 about Linking

Static linking

means: the code from a library or framework is copied directly into our app binary at build time. This makes the app larger, but all code is self-contained and loads faster at runtime.

Dynamic linking

means: the code lives in a separate binary (a .dylib or dynamic framework) and is loaded when the app runs. This keeps the app smaller and could allow multiple apps to share the same framework on macOS. Important to note: on iOS, each app runs in its own sandbox, so sharing doesn’t happen — but dynamic linking still adds a small runtime cost.

On the other hand, it can be useful when the app uses the same code in multiple frameworks: the code will not be duplicated and it prevents compilation errors like: duplicate symbol MY_COMMON_SYMBOL in ... FrameworkA and ... FrameworkB.

and of course, all system libraries (iOS & OSX) are Dynamic (so the same library can be uses by different module/ apps) read more #1 », read more #2 »


Why this matters ?

Understanding these two types is important because it affects app size, load time, updates, and how symbols are resolved at runtime. In later articles, we will explore how the CPU actually jumps from our app into framework code.

Before we get there, we need to be precise about what kind of binary we are dealing with.

Framework vs Library

  • Library: just a collection of compiled code (static or dynamic) that provides functions or types. Usually we don’t get any extra metadata or resources. read more »>
  • Framework: a special type of directory that includes a defined structure: compiled code, headers, resources (like images or storyboards), and Info.plist metadata,.. read more »>

Hands-on: Test Projects

But, before diving deeper into theory, we need something concrete to observe.
All concepts in this article (stubs, GOT, symbol resolution, static vs dynamic dispatching) are much easier to understand when you can see them in a real binary.

So I built two small “test sandboxes” whose only purpose is to demonstrate in practice the examples described in the series of articles.

Both projects have the same structure:

Type Test app Static framework Dynamic framework
Xcode Framework Library-linking-Test-Xcode-Framework XcodeFrameworkStatic XcodeFrameworkDynamic
SPM Library-linking-Test SDK-SPM-Static SDK-SPM-Dynamic

This configuration lets us compare:

📌 Here we verify an important idea:

SPM vs Xcode frameworks is mostly a packaging difference
the dispatching model underneath is the same.

You can clone and reproduce everything shown in this article by using this repo: Source code link »

Mach-O

Mach-O is the executable file format used by Apple platforms. read more »

It contains:

  • machine code
  • symbol tables
  • relocation info
  • dynamic loader commands

Tip: to dig deeper into our app we can use free OSX App: MachOView; (download link on Github) ~> run machoview.xcodeproj with your Xcode. Then you can use generated MachOView app.

Screenshot of our app: The Load commands section looks like this: Screenshot of our app

During this article series (1 - 3) we can (and will) use a terminal utilities that are already available on OSX: otool, nm, …

.a file extension

.a = static library (an archive of object files, not a runtime-loaded binary). A .a file is not loaded by dyld at runtime. Instead, its object files are copied directly into the final app binary at link time.

Used for:

  • static frameworks
  • internal SDK modules that must be fully embedded into the app

So at runtime:

  • there is no separate binary
  • there is no symbol lookup in another image
  • calls go directly to machine code inside the app’s Mach-O

Conceptually:

  • .a → object files (.o)
  • linker → merges them into App
  • result → one Mach-O app binary containing both app code and framework code

In our test setup, the static framework (XcodeFrameworkStatic / SDK-SPM-Static) is built as a .a archive and then merged into the main executable during the app link phase. We can verify this by checking that:

  • there is no separate .dylib for the static framework inside the app bundle
  • its symbols appear directly inside the app binary; let’s investigate:
  1. First step: we should figure out correct mangled name for our function:
nm Library-linking-Test-Xcode-Framework.debug.dylib | grep MyMath
we should see something like (click to expand)
0000000000004170 T _$s20XcodeFrameworkStatic06MyMathC0V3addyS2i_SitFZ
0000000000004278 T _$s20XcodeFrameworkStatic06MyMathC0VACycfC
0000000000005254 s _$s20XcodeFrameworkStatic06MyMathC0VMF
000000000000459c T _$s20XcodeFrameworkStatic06MyMathC0VMa
00000000000084c8 s _$s20XcodeFrameworkStatic06MyMathC0VMf
0000000000005218 S _$s20XcodeFrameworkStatic06MyMathC0VMn
00000000000084d8 S _$s20XcodeFrameworkStatic06MyMathC0VN
0000000000008470 s _$s20XcodeFrameworkStatic06MyMathC0VWV
0000000000004284 t _$s20XcodeFrameworkStatic06MyMathC0Vwet
00000000000043d4 t _$s20XcodeFrameworkStatic06MyMathC0Vwst
                 U _$s21XcodeFrameworkDynamic06MyMathC0V3addyS2i_SitFZ
0000000000004f34 s _symbolic _____ 20XcodeFrameworkStatic06MyMathC0V
  1. Second step: Let’s see how it is called:
otool -tvV Library-linking-Test-Xcode-Framework.debug.dylib | grep -A6 addyS2i_SitFZ
as a result, we should see something like (click to expand)
00000000000015dc	bl	0x4b2c ; symbol stub for: _$s21XcodeFrameworkDynamic06MyMathC0V3addyS2i_SitFZ
00000000000015e0	mov	x8, x0
00000000000015e4	sub	x0, x29, #0x28
00000000000015e8	stur	x8, [x29, #-0x28]
00000000000015ec	adrp	x1, 7 ; 0x8000
00000000000015f0	ldr	x1, [x1, #0x1c8] ; literal pool symbol address: _$sSiN
00000000000015f4	str	x1, [sp, #0x78]
--
0000000000001754	bl	_$s20XcodeFrameworkStatic06MyMathC0V3addyS2i_SitFZ
0000000000001758	ldr	x1, [sp, #0x78]
000000000000175c	ldr	x2, [sp, #0x80]
0000000000001760	mov	x8, x0
0000000000001764	sub	x0, x29, #0x40
0000000000001768	stur	x8, [x29, #-0x40]
000000000000176c	bl	0x4c40 ; symbol stub for: _$ss26DefaultStringInterpolationV06appendC0yyxs06CustomB11ConvertibleRzlF
--
_$s20XcodeFrameworkStatic06MyMathC0V3addyS2i_SitFZ:
0000000000004170	sub	sp, sp, #0x70
0000000000004174	stp	x29, x30, [sp, #0x60]
0000000000004178	add	x29, sp, #0x60
000000000000417c	stur	x0, [x29, #-0x20]
0000000000004180	stur	x1, [x29, #-0x28]
0000000000004184	stur	xzr, [x29, #-0x8]

This means:

Static linking = code duplication across binaries, but zero runtime indirection.

No dyld resolution, no GOT patching, no lazy binding — just a normal bl (branch-and-link) instruction to an address inside the same Mach-O.

We will explore the performance and architectural consequences of this in Article 2 and Article 3.

.dylib file extension

.dylib = dynamic library (a Mach-O type).

Used for:

  • dynamic frameworks
  • SwiftUI debug binaries
  • system libraries

Loaded at runtime by dyld.

e.g. Our test application creates at least one .dylib in DEBUG mode (regardless of whether we used Dynamic or Static dispatching mode for our framework ~> will be explained in detail in Article 3).

We can find that file/s somewhere there: ./Users/-OUR USER NAME-/Library/Developer/Xcode/DerivedData/Library-linking-Test-Xcode-Framework-someLetters/Build/Products/Debug-iphonesimulator/Library-linking-Test-Xcode-Framework.app/Library-linking-Test-Xcode-Framework.debug.dylib

Apple WWDC 2022 about dylibs

dyld

dyld = dynamic loader (it is an abbreviation for “Dynamic Link Editor”, an operating system component in macOS and iOS that is responsible for loading and linking dynamic libraries at runtime).

It:

Read more:


Symbol & Mangled Symbol

Mangling is the process of encoding module, type, and signature information into a symbol name so the linker can uniquely identify it.

For example, this Swift code:

public struct MyMathStatic {
    public static func add(_ a: Int, _ b: Int) -> Int {
        a + b
    }
}

After compilation, the function name is transformed into a mangled symbol:

_$s20XcodeFrameworkStatic06MyMathC0V3addyS2i_SitFZ

This string encodes:

  • the module name (XcodeFrameworkStatic)
  • the type name (MyMathC0V)
  • the function name (add)
  • the function signature (addsS2i_SitFZ)

We can inspect mangled symbols directly in a compiled binary:

nm Library-linking-Test-Xcode-Framework.debug.dylib | grep MyMath

And convert them back to a human-readable form using:

nm Library-linking-Test-Xcode-Framework.debug.dylib | grep MyMath | xcrun swift-demangle

Which produces:

static XcodeFrameworkStatic.MyMathStatic.add(Swift.Int, Swift.Int) -> Swift.Int

This is what the linker and the dynamic loader (dyld) work with internally — not Swift names, but mangled symbols.

Stub

A stub is a tiny piece of machine code generated by the linker inside our app’s binary.
Its only job is not to call the real function directly, but to redirect execution to a helper mechanism that will later resolve the real address.

Conceptually, a stub means:

“I don’t yet know where the real function lives.
Jump to a place where the dynamic loader (dyld) can figure it out.”

Stubs exist only for dynamically linked symbols. Without stubs, every call target would need to be known at link time — which is impossible for dynamic libraries. A stub is not “the call”.
It is a placeholder jump that exists so the real call can be decided later by dyld.

With static linking, the call target is known at link time and no stub is needed.

How a stub fits into the big picture

So the call chain is:

App code → Stub → Lazy pointer → dyld (first time) → Real function

After the first call, dyld patches the lazy pointer with the real address, and future calls go directly to the function without resolving again.

Where is the stub in a real binary? Let’s investigate that

We can actually see stubs in our compiled app/framework.

let’s see an example (Debug build):

otool -l Library-linking-Test-Xcode-Framework.debug.dylib | grep -A3 __stubs

we’ll see an output similar to:

  sqrtName __stubs
   segname __TEXT
      addr 0x0000000000004afc
      size 0x000000000000039c

This shows the __stubs section inside the Mach-O file.

we can also inspect symbol indirections:

otool -Iv Library-linking-Test-Xcode-Framework.debug.dylib

we’ll see an output similar to:

Symbol indirections (click to expand)
0x0000000000004afc   640 _$s21DeveloperToolsSupport13ColorResourceV4name6bundleACSS_So8NSBundleCtcfC
0x0000000000004b08   641 _$s21DeveloperToolsSupport13ColorResourceVMa
0x0000000000004b14   643 _$s21DeveloperToolsSupport13ImageResourceV4name6bundleACSS_So8NSBundleCtcfC
0x0000000000004b20   644 _$s21DeveloperToolsSupport13ImageResourceVMa
0x0000000000004b2c   646 _$s21XcodeFrameworkDynamic06MyMathC0V3addyS2i_SitFZ
0x0000000000004b38   648 _$s7SwiftUI11WindowGroupV2id5title11lazyContentACyxGSSSg_AA4TextVSgxyctcfC
0x0000000000004b44   649 _$s7SwiftUI11WindowGroupV7contentACyxGxyXE_tcfC
0x0000000000004b50   650 _$s7SwiftUI11WindowGroupVMa
0x0000000000004b5c   653 _$s7SwiftUI12SceneBuilderV10buildBlockyxxAA0C0RzlFZ
0x0000000000004b68   656 _$s7SwiftUI18LocalizedStringKeyV13stringLiteralACSS_tcfC
0x0000000000004b74   662 _$s7SwiftUI3AppPAAE4mainyyFZ
0x0000000000004b80   667 _$s7SwiftUI4TextV_9tableName6bundle7commentAcA18LocalizedStringKeyV_SSSgSo8NSBundleCSgs06StaticI0VSgtcfC
0x0000000000004b8c   668 _$s7SwiftUI4ViewPAAE8onAppear7performQryycSg_tF
0x0000000000004b98   669 _$s7SwiftUI5ColorVyAC21DeveloperToolsSupport0C8ResourceVcfC
0x0000000000004ba4   672 _$sSS10FoundationE19_bridgeToObjectiveCSo8NSStringCyF
0x0000000000004bb0   673 _$sSS11utf8CStrings15ContiguousArrayVys4Int8VGvg
0x0000000000004bbc   674 _$sSS19stringInterpolationSSs013DefaultStringB0V_tcfC
0x0000000000004bc8   675 _$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC
0x0000000000004bd4   677 _$sSaMa
0x0000000000004be0   678 _$sScA15unownedExecutorScevgTj
0x0000000000004bec   679 _$sScM6sharedScMvgZ
0x0000000000004bf8   680 _$sScMMa
0x0000000000004c04   682 _$sScP8rawValues5UInt8Vvg
0x0000000000004c10   683 _$sScPMa
0x0000000000004c1c   686 _$sSo7UIColorC5UIKitE8resourceAB21DeveloperToolsSupport13ColorResourceV_tcfC
0x0000000000004c28   687 _$sSo7UIImageC5UIKitE8resourceAB21DeveloperToolsSupport13ImageResourceV_tcfC
0x0000000000004c34   688 _$ss17_assertionFailure__4file4line5flagss5NeverOs12StaticStringV_A2HSus6UInt32VtF
0x0000000000004c40   689 _$ss26DefaultStringInterpolationV06appendC0yyxs06CustomB11ConvertibleRzlF
0x0000000000004c4c   690 _$ss26DefaultStringInterpolationV13appendLiteralyySSF
0x0000000000004c58   691 _$ss26DefaultStringInterpolationV15literalCapacity18interpolationCountABSi_SitcfC
0x0000000000004c64   692 _$ss27_allocateUninitializedArrayySayxG_BptBwlF
0x0000000000004c70   693 _$ss5print_9separator10terminatoryypd_S2StF
0x0000000000004c7c   702 ___stack_chk_fail
0x0000000000004c88   704 __availability_version_check
0x0000000000004c94   721 _dispatch_once_f
0x0000000000004ca0   722 _dlsym
0x0000000000004cac   723 _fclose
0x0000000000004cb8   724 _fopen
0x0000000000004cc4   725 _fread
0x0000000000004cd0   726 _free
0x0000000000004cdc   727 _fseek
0x0000000000004ce8   728 _ftell
0x0000000000004cf4   729 _getenv
0x0000000000004d00   730 _malloc
0x0000000000004d0c   731 _memcpy
0x0000000000004d18   732 _objc_msgSend
0x0000000000004d24   733 _objc_opt_self
0x0000000000004d30   736 _objc_retainAutoreleasedReturnValue
0x0000000000004d3c   737 _pthread_main_np
0x0000000000004d48   738 _rewind
0x0000000000004d54   739 _sscanf
0x0000000000004d60   740 _strcpy
0x0000000000004d6c   741 _strlen
0x0000000000004d78   742 _swift_allocObject
0x0000000000004d84   743 _swift_bridgeObjectRelease
0x0000000000004d90   744 _swift_bridgeObjectRetain
0x0000000000004d9c   745 _swift_deallocClassInstance
0x0000000000004da8   746 _swift_deallocObject
0x0000000000004db4   747 _swift_getObjCClassFromMetadata
0x0000000000004dc0   748 _swift_getObjCClassMetadata
0x0000000000004dcc   749 _swift_getObjectType
0x0000000000004dd8   750 _swift_getOpaqueTypeConformance2
0x0000000000004de4   751 _swift_getTypeByMangledNameInContext2
0x0000000000004df0   752 _swift_getTypeByMangledNameInContextInMetadataState2
0x0000000000004dfc   753 _swift_getWitnessTable
0x0000000000004e08   754 _swift_once
0x0000000000004e14   755 _swift_release
0x0000000000004e20   756 _swift_retain
0x0000000000004e2c   757 _swift_task_alloc
0x0000000000004e38   758 _swift_task_create
0x0000000000004e44   759 _swift_task_dealloc
0x0000000000004e50   760 _swift_task_deinitOnExecutor
0x0000000000004e5c   761 _swift_task_isCurrentExecutor
0x0000000000004e68   762 _swift_task_reportUnexpectedExecutor
0x0000000000004e74   763 _swift_task_switch
0x0000000000004e80   764 _swift_unknownObjectRelease
0x0000000000004e8c   765 _swift_unknownObjectRetain
Indirect symbols for (__DATA_CONST,__got) 97 entries
address            index name
0x0000000000008000   646 _$s21XcodeFrameworkDynamic06MyMathC0V3addyS2i_SitFZ
0x0000000000008008   672 _$sSS10FoundationE19_bridgeToObjectiveCSo8NSStringCyF
0x0000000000008010   732 _objc_msgSend
0x0000000000008018   733 _objc_opt_self
0x0000000000008020   734 _objc_release
0x0000000000008028   735 _objc_retain
0x0000000000008030   736 _objc_retainAutoreleasedReturnValue
0x0000000000008038   702 ___stack_chk_fail
0x0000000000008040   703 ___stack_chk_guard
0x0000000000008048   704 __availability_version_check
0x0000000000008050   721 _dispatch_once_f
0x0000000000008058   722 _dlsym
0x0000000000008060   723 _fclose
0x0000000000008068   724 _fopen
0x0000000000008070   725 _fread
0x0000000000008078   726 _free
0x0000000000008080   727 _fseek
0x0000000000008088   728 _ftell
0x0000000000008090   729 _getenv
0x0000000000008098   730 _malloc
0x00000000000080a0   731 _memcpy
0x00000000000080a8   737 _pthread_main_np
0x00000000000080b0   738 _rewind
0x00000000000080b8   739 _sscanf
0x00000000000080c0   740 _strcpy
0x00000000000080c8   741 _strlen
0x00000000000080d0   640 _$s21DeveloperToolsSupport13ColorResourceV4name6bundleACSS_So8NSBundleCtcfC
0x00000000000080d8   641 _$s21DeveloperToolsSupport13ColorResourceVMa
0x00000000000080e0   642 _$s21DeveloperToolsSupport13ColorResourceVMn
0x00000000000080e8   643 _$s21DeveloperToolsSupport13ImageResourceV4name6bundleACSS_So8NSBundleCtcfC
0x00000000000080f0   644 _$s21DeveloperToolsSupport13ImageResourceVMa
0x00000000000080f8   645 _$s21DeveloperToolsSupport13ImageResourceVMn
0x0000000000008100   648 _$s7SwiftUI11WindowGroupV2id5title11lazyContentACyxGSSSg_AA4TextVSgxyctcfC
0x0000000000008108   649 _$s7SwiftUI11WindowGroupV7contentACyxGxyXE_tcfC
0x0000000000008110   650 _$s7SwiftUI11WindowGroupVMa
0x0000000000008118   651 _$s7SwiftUI11WindowGroupVMn
0x0000000000008120   652 _$s7SwiftUI11WindowGroupVyxGAA5SceneAAMc
0x0000000000008128   653 _$s7SwiftUI12SceneBuilderV10buildBlockyxxAA0C0RzlFZ
0x0000000000008130   654 _$s7SwiftUI15ModifiedContentVMn
0x0000000000008138   655 _$s7SwiftUI15ModifiedContentVyxq_GAA4ViewA2aERzAA0E8ModifierR_rlMc
0x0000000000008140   656 _$s7SwiftUI18LocalizedStringKeyV13stringLiteralACSS_tcfC
0x0000000000008148   657 _$s7SwiftUI25_AppearanceActionModifierVAA04ViewE0AAWP
0x0000000000008150   658 _$s7SwiftUI25_AppearanceActionModifierVMn
0x0000000000008158   662 _$s7SwiftUI3AppPAAE4mainyyFZ
0x0000000000008160   664 _$s7SwiftUI4TextVAA4ViewAAWP
0x0000000000008168   665 _$s7SwiftUI4TextVMn
0x0000000000008170   666 _$s7SwiftUI4TextVN
0x0000000000008178   667 _$s7SwiftUI4TextV_9tableName6bundle7commentAcA18LocalizedStringKeyV_SSSgSo8NSBundleCSgs06StaticI0VSgtcfC
0x0000000000008180   668 _$s7SwiftUI4ViewPAAE8onAppear7performQryycSg_tF
0x0000000000008188   669 _$s7SwiftUI5ColorVyAC21DeveloperToolsSupport0C8ResourceVcfC
0x0000000000008190   686 _$sSo7UIColorC5UIKitE8resourceAB21DeveloperToolsSupport13ColorResourceV_tcfC
0x0000000000008198   687 _$sSo7UIImageC5UIKitE8resourceAB21DeveloperToolsSupport13ImageResourceV_tcfC
0x00000000000081a0   673 _$sSS11utf8CStrings15ContiguousArrayVys4Int8VGvg
0x00000000000081a8   674 _$sSS19stringInterpolationSSs013DefaultStringB0V_tcfC
0x00000000000081b0   675 _$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC
0x00000000000081b8   676 _$sSSN
0x00000000000081c0   677 _$sSaMa
0x00000000000081c8   684 _$sSiN
0x00000000000081d0   685 _$sSis23CustomStringConvertiblesWP
0x00000000000081d8   688 _$ss17_assertionFailure__4file4line5flagss5NeverOs12StaticStringV_A2HSus6UInt32VtF
0x00000000000081e0   689 _$ss26DefaultStringInterpolationV06appendC0yyxs06CustomB11ConvertibleRzlF
0x00000000000081e8   690 _$ss26DefaultStringInterpolationV13appendLiteralyySSF
0x00000000000081f0   691 _$ss26DefaultStringInterpolationV15literalCapacity18interpolationCountABSi_SitcfC
0x00000000000081f8   692 _$ss27_allocateUninitializedArrayySayxG_BptBwlF
0x0000000000008200   693 _$ss5print_9separator10terminatoryypd_S2StF
0x0000000000008208   694 _$sypN
0x0000000000008210   695 _$sytN
0x0000000000008218   742 _swift_allocObject
0x0000000000008220   743 _swift_bridgeObjectRelease
0x0000000000008228   744 _swift_bridgeObjectRetain
0x0000000000008230   745 _swift_deallocClassInstance
0x0000000000008238   746 _swift_deallocObject
0x0000000000008240   747 _swift_getObjCClassFromMetadata
0x0000000000008248   748 _swift_getObjCClassMetadata
0x0000000000008250   749 _swift_getObjectType
0x0000000000008258   750 _swift_getOpaqueTypeConformance2
0x0000000000008260   751 _swift_getTypeByMangledNameInContext2
0x0000000000008268   752 _swift_getTypeByMangledNameInContextInMetadataState2
0x0000000000008270   753 _swift_getWitnessTable
0x0000000000008278   754 _swift_once
0x0000000000008280   755 _swift_release
0x0000000000008288   756 _swift_retain
0x0000000000008290   764 _swift_unknownObjectRelease
0x0000000000008298   765 _swift_unknownObjectRetain
0x00000000000082a0   678 _$sScA15unownedExecutorScevgTj
0x00000000000082a8   679 _$sScM6sharedScMvgZ
0x00000000000082b0   680 _$sScMMa
0x00000000000082b8   681 _$sScMScAsMc
0x00000000000082c0   682 _$sScP8rawValues5UInt8Vvg
0x00000000000082c8   683 _$sScPMa
0x00000000000082d0   757 _swift_task_alloc
0x00000000000082d8   758 _swift_task_create
0x00000000000082e0   759 _swift_task_dealloc
0x00000000000082e8   760 _swift_task_deinitOnExecutor
0x00000000000082f0   761 _swift_task_isCurrentExecutor
0x00000000000082f8   762 _swift_task_reportUnexpectedExecutor
0x0000000000008300   763 _swift_task_switch


🔬 Let’s check out the stubs on func add(Int,Int)->Int in our dynamic framework as a REAL word example — so we can better understand how these things function.

To see a stub for our function
MyMathDynamic.add from the dynamic framework XcodeFrameworkDynamic, we need to inspect firstly the client app binary, not the framework itself.

Why?
Because stubs are generated in the caller, not in the callee.

Step 1 — find the mangled symbol

First, get the mangled name of our function from the dynamic framework:

nm Frameworks/XcodeFrameworkDynamic.framework/XcodeFrameworkDynamic | grep MyMath
we should see something like (click to expand)
0000000000000900 T _$s21XcodeFrameworkDynamic06MyMathC0V3addyS2i_SitFZ
0000000000000aa0 T _$s21XcodeFrameworkDynamic06MyMathC0VACycfC
0000000000000f0c s _$s21XcodeFrameworkDynamic06MyMathC0VMF
0000000000000dc4 T _$s21XcodeFrameworkDynamic06MyMathC0VMa
0000000000004090 s _$s21XcodeFrameworkDynamic06MyMathC0VMf
0000000000000ee8 S _$s21XcodeFrameworkDynamic06MyMathC0VMn
00000000000040a0 S _$s21XcodeFrameworkDynamic06MyMathC0VN
0000000000004038 s _$s21XcodeFrameworkDynamic06MyMathC0VWV
0000000000000aac t _$s21XcodeFrameworkDynamic06MyMathC0Vwet
0000000000000bfc t _$s21XcodeFrameworkDynamic06MyMathC0Vwst
0000000000000f04 s _symbolic _____ 21XcodeFrameworkDynamic06MyMathC0V

Let’s use this mangled symbol in the next steps.

Step 2 — find the stub in the app binary

Now inspect the app binary (not the framework) by using the mangled name from step.1:

nm Library-linking-Test-Xcode-Framework.debug.dylib | grep s21XcodeFrameworkDynamic06MyMathC0V3addyS2i_SitFZ

We should see something like:

    U _$s21XcodeFrameworkDynamic06MyMathC0V3addyS2i_SitFZ

But this is only the symbol reference. So, we made sure that these mangeln symbols exist in both the Main application and our Framework. To see the actual stub code, dump the __stubs section:

otool -tvV Library-linking-Test-Xcode-Framework.debug.dylib | grep -A6 addyS2i_SitFZ
we will get output similar to (click to expand):
00000000000015dc	bl	0x4b2c ; symbol stub for: _$s21XcodeFrameworkDynamic06MyMathC0V3addyS2i_SitFZ
00000000000015e0	mov	x8, x0
00000000000015e4	sub	x0, x29, #0x28
00000000000015e8	stur	x8, [x29, #-0x28]
00000000000015ec	adrp	x1, 7 ; 0x8000
00000000000015f0	ldr	x1, [x1, #0x1c8] ; literal pool symbol address: _$sSiN
00000000000015f4	str	x1, [sp, #0x78]

🧲️ This is our stub in Main App for our XcodeFrameworkDynamic.MyMathDynamic.add(Swift.Int, Swift.Int) -> Swift.Int function.

Apple WWDC 2022 about stub



Trampoline (aka dyld resolver (lazy binding logic))

In many classic descriptions of dynamic linking (especially outside of Apple’s ecosystem), people use the word “trampoline” to describe a small piece of intermediate code that sits between a call site and the real function:

stub
trampoline ≈⪼ "lazy binding logic"
real_function

You can find this term in:

However, Apple’s official documentation does not use the term “trampoline” for Mach-O and dyld.

Instead, Apple describes this mechanism using:

  • symbol stubs
  • lazy symbol pointers
  • dyld’s resolver (binding) logic

From Apple’s point of view, the flow is:

  • ① your code calls a stub
  • ② the stub loads an address from a lazy symbol pointer
  • dyld resolves the symbol and patches the pointer
  • ④ execution continues in the real function

Conceptually, this plays the same role as a “trampoline” in other systems —
but on Apple platforms, the work is done by dyld’s lazy binding logic, not by a named trampoline routine inside your Mach-O.

So in this series, when we say “trampoline”, we mean:

the indirection step performed by the lazy symbol pointer + dyld resolver,
which is functionally equivalent to what other ecosystems call a trampoline.



Apple-style dispatch path (conceptual)

Key idea:

  • The stub never knows the real address directly.
  • The lazy symbol pointer is what gets rewritten.
  • dyld is responsible for symbol lookup and patching.
  • After the first call, the “trampoline-like” step disappears.

This keeps startup fast (no eager binding) and moves the cost of symbol resolution to first use — which is exactly what lazy binding means on Apple platforms.

So, what is Lazy Symbol Pointer Table here?

Historically, Mach-O used a dedicated section __la_symbol_ptr for lazy binding: a table of pointers, one per imported symbol, patched by dyld at runtime on first use. Read more »

State __la_symbol_ptr
Before first call [0] = 0x0
After binding [0] = 0x104FA2130

Modern Apple binaries no longer include __la_symbol_ptr. Instead, lazy binding is implemented via:

  • stubs in __TEXT,__stubs
  • dyld’s resolver
  • Global Offset Table (__DATA_CONST,__got)

read more »

Control flow:

call site → stub → dyld → GOT → real function

Let’s take a look in our binary:

otool -v -s __DATA_CONST __got Library-linking-Test-Xcode-Framework.debug.dylib

Result in:

Contents of (__DATA_CONST,__got) section
Unknown section type (0x6)
0000000000008000	00000000 80100000 00000001 80100000
0000000000008010	00000002 80100000 00000003 80100000
0000000000008020	00000004 80100000 00000005 80100000
0000000000008030	00000006 80100000 00000007 80100000
....

and this command:

otool -tvV Library-linking-Test-Xcode-Framework.debug.dylib | grep stub
Result (click to expand):
00000000000012b8	bl	0x4b5c ; symbol stub for: _$s7SwiftUI12SceneBuilderV10buildBlockyxxAA0C0RzlFZ
0000000000001338	bl	0x4de4 ; symbol stub for: _swift_getTypeByMangledNameInContext2
000000000000138c	bl	0x4bc8 ; symbol stub for: _$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC
0000000000001390	bl	0x4b68 ; symbol stub for: _$s7SwiftUI18LocalizedStringKeyV13stringLiteralACSS_tcfC
00000000000013dc	bl	0x4b80 ; symbol stub for: _$s7SwiftUI4TextV_9tableName6bundle7commentAcA18LocalizedStringKeyV_SSSgSo8NSBundleCSgs06StaticI0VSgtcfC
00000000000012b8	bl	0x4b5c ; symbol stub for: _$s7SwiftUI12SceneBuilderV10buildBlockyxxAA0C0RzlFZ
0000000000001338	bl	0x4de4 ; symbol stub for: _swift_getTypeByMangledNameInContext2
000000000000138c	bl	0x4bc8 ; symbol stub for: _$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC
0000000000001390	bl	0x4b68 ; symbol stub for: _$s7SwiftUI18LocalizedStringKeyV13stringLiteralACSS_tcfC
00000000000013dc	bl	0x4b80 ; symbol stub for: _$s7SwiftUI4TextV_9tableName6bundle7commentAcA18LocalizedStringKeyV_SSSgSo8NSBundleCSgs06StaticI0VSgtcfC
000000000000144c	bl	0x4b8c ; symbol stub for: _$s7SwiftUI4ViewPAAE8onAppear7performQryycSg_tF
0000000000001470	bl	0x4d0c ; symbol stub for: _memcpy
0000000000001484	bl	0x4d0c ; symbol stub for: _memcpy
00000000000014d8	bl	0x4d0c ; symbol stub for: _memcpy
00000000000014f8	bl	0x4d0c ; symbol stub for: _memcpy
0000000000001568	bl	0x4c64 ; symbol stub for: _$ss27_allocateUninitializedArrayySayxG_BptBwlF
0000000000001588	bl	0x4c58 ; symbol stub for: _$ss26DefaultStringInterpolationV15literalCapacity18interpolationCountABSi_SitcfC
00000000000015b8	bl	0x4bc8 ; symbol stub for: _$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC
00000000000015c0	bl	0x4c4c ; symbol stub for: _$ss26DefaultStringInterpolationV13appendLiteralyySSF
00000000000015cc	bl	0x4d84 ; symbol stub for: _swift_bridgeObjectRelease
00000000000015dc	bl	0x4b2c ; symbol stub for: _$s21XcodeFrameworkDynamic06MyMathC0V3addyS2i_SitFZ
0000000000001604	bl	0x4c40 ; symbol stub for: _$ss26DefaultStringInterpolationV06appendC0yyxs06CustomB11ConvertibleRzlF
0000000000001628	bl	0x4bc8 ; symbol stub for: _$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC
0000000000001630	bl	0x4c4c ; symbol stub for: _$ss26DefaultStringInterpolationV13appendLiteralyySSF
0000000000001638	bl	0x4d84 ; symbol stub for: _swift_bridgeObjectRelease
000000000000164c	bl	0x4d90 ; symbol stub for: _swift_bridgeObjectRetain
0000000000001660	bl	0x4bbc ; symbol stub for: _$sSS19stringInterpolationSSs013DefaultStringB0V_tcfC
00000000000016c0	bl	0x4c70 ; symbol stub for: _$ss5print_9separator10terminatoryypd_S2StF
00000000000016c8	bl	0x4d84 ; symbol stub for: _swift_bridgeObjectRelease
00000000000016d0	bl	0x4d84 ; symbol stub for: _swift_bridgeObjectRelease
00000000000016d8	bl	0x4d84 ; symbol stub for: _swift_bridgeObjectRelease
00000000000016e4	bl	0x4c64 ; symbol stub for: _$ss27_allocateUninitializedArrayySayxG_BptBwlF
0000000000001700	bl	0x4c58 ; symbol stub for: _$ss26DefaultStringInterpolationV15literalCapacity18interpolationCountABSi_SitcfC
000000000000172c	bl	0x4bc8 ; symbol stub for: _$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC
0000000000001734	bl	0x4c4c ; symbol stub for: _$ss26DefaultStringInterpolationV13appendLiteralyySSF
0000000000001740	bl	0x4d84 ; symbol stub for: _swift_bridgeObjectRelease
000000000000176c	bl	0x4c40 ; symbol stub for: _$ss26DefaultStringInterpolationV06appendC0yyxs06CustomB11ConvertibleRzlF
0000000000001784	bl	0x4bc8 ; symbol stub for: _$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC
000000000000178c	bl	0x4c4c ; symbol stub for: _$ss26DefaultStringInterpolationV13appendLiteralyySSF
0000000000001794	bl	0x4d84 ; symbol stub for: _swift_bridgeObjectRelease
00000000000017a8	bl	0x4d90 ; symbol stub for: _swift_bridgeObjectRetain
00000000000017bc	bl	0x4bbc ; symbol stub for: _$sSS19stringInterpolationSSs013DefaultStringB0V_tcfC
0000000000001814	bl	0x4c70 ; symbol stub for: _$ss5print_9separator10terminatoryypd_S2StF
000000000000181c	bl	0x4d84 ; symbol stub for: _swift_bridgeObjectRelease
0000000000001824	bl	0x4d84 ; symbol stub for: _swift_bridgeObjectRelease
000000000000182c	bl	0x4d84 ; symbol stub for: _swift_bridgeObjectRelease
0000000000001864	bl	0x4bd4 ; symbol stub for: _$sSaMa
00000000000018a0	bl	0x4bc8 ; symbol stub for: _$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC
00000000000018cc	bl	0x4bc8 ; symbol stub for: _$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC
0000000000001998	bl	0x4b50 ; symbol stub for: _$s7SwiftUI11WindowGroupVMa
00000000000019fc	bl	0x4b44 ; symbol stub for: _$s7SwiftUI11WindowGroupV7contentACyxGxyXE_tcfC
0000000000001a08	bl	0x4e20 ; symbol stub for: _swift_retain
0000000000001a48	bl	0x4b38 ; symbol stub for: _$s7SwiftUI11WindowGroupV2id5title11lazyContentACyxGSSSg_AA4TextVSgxyctcfC
0000000000001a70	bl	0x4e14 ; symbol stub for: _swift_release
0000000000001ae0	bl	0x4dfc ; symbol stub for: _swift_getWitnessTable
0000000000001b64	bl	0x4df0 ; symbol stub for: _swift_getTypeByMangledNameInContextInMetadataState2
0000000000001c08	bl	0x4dfc ; symbol stub for: _swift_getWitnessTable
0000000000001c58	bl	0x4b74 ; symbol stub for: _$s7SwiftUI3AppPAAE4mainyyFZ
0000000000001ca4	bl	0x4dfc ; symbol stub for: _swift_getWitnessTable
0000000000001d2c	bl	0x4dd8 ; symbol stub for: _swift_getOpaqueTypeConformance2
0000000000001dc4	bl	0x4d84 ; symbol stub for: _swift_bridgeObjectRelease
0000000000001df8	bl	0x4d84 ; symbol stub for: _swift_bridgeObjectRelease
0000000000001e04	bl	0x4e14 ; symbol stub for: _swift_release
0000000000001e48	bl	0x4d84 ; symbol stub for: _swift_bridgeObjectRelease
0000000000001e64	bl	0x4e14 ; symbol stub for: _swift_release
0000000000001e84	bl	0x4e14 ; symbol stub for: _swift_release
0000000000001f04	bl	0x4d90 ; symbol stub for: _swift_bridgeObjectRetain
0000000000001f38	bl	0x4e20 ; symbol stub for: _swift_retain
0000000000001f8c	bl	0x4e20 ; symbol stub for: _swift_retain
0000000000001fec	bl	0x4d90 ; symbol stub for: _swift_bridgeObjectRetain
0000000000001ff8	bl	0x4e20 ; symbol stub for: _swift_retain
0000000000002020	bl	0x4d84 ; symbol stub for: _swift_bridgeObjectRelease
0000000000002060	bl	0x4bf8 ; symbol stub for: _$sScMMa
000000000000206c	bl	0x4bec ; symbol stub for: _$sScM6sharedScMvgZ
0000000000002084	bl	0x4be0 ; symbol stub for: _$sScA15unownedExecutorScevgTj
0000000000002090	bl	0x4e5c ; symbol stub for: _swift_task_isCurrentExecutor
00000000000020c8	bl	0x4e68 ; symbol stub for: _swift_task_reportUnexpectedExecutor
00000000000020d4	bl	0x4e14 ; symbol stub for: _swift_release
0000000000002120	bl	0x4d9c ; symbol stub for: _swift_deallocClassInstance
0000000000002158	bl	0x4bf8 ; symbol stub for: _$sScMMa
0000000000002164	bl	0x4bec ; symbol stub for: _$sScM6sharedScMvgZ
000000000000217c	bl	0x4be0 ; symbol stub for: _$sScA15unownedExecutorScevgTj
0000000000002190	bl	0x4e14 ; symbol stub for: _swift_release
0000000000002204	bl	0x4d3c ; symbol stub for: _pthread_main_np
0000000000002230	bl	0x4d78 ; symbol stub for: _swift_allocObject
0000000000002284	bl	0x4c10 ; symbol stub for: _$sScPMa
00000000000022a8	bl	0x4e20 ; symbol stub for: _swift_retain
00000000000022b0	bl	0x4bf8 ; symbol stub for: _$sScMMa
00000000000022b8	bl	0x4bec ; symbol stub for: _$sScM6sharedScMvgZ
00000000000022dc	bl	0x4d78 ; symbol stub for: _swift_allocObject
000000000000231c	bl	0x4e14 ; symbol stub for: _swift_release
0000000000002334	bl	0x4e14 ; symbol stub for: _swift_release
0000000000002360	bl	0x4e50 ; symbol stub for: _swift_task_deinitOnExecutor
0000000000002398	bl	0x4d78 ; symbol stub for: _swift_allocObject
0000000000002428	bl	0x4db4 ; symbol stub for: _swift_getObjCClassFromMetadata
0000000000002438	bl	0x4db4 ; symbol stub for: _swift_getObjCClassFromMetadata
0000000000002458	b	0x4d30 ; symbol stub for: _objc_retainAutoreleasedReturnValue
00000000000024a4	bl	0x4e08 ; symbol stub for: _swift_once
00000000000024e4	bl	0x4b08 ; symbol stub for: _$s21DeveloperToolsSupport13ColorResourceVMa
0000000000002560	bl	0x4d90 ; symbol stub for: _swift_bridgeObjectRetain
00000000000025dc	bl	0x4afc ; symbol stub for: _$s21DeveloperToolsSupport13ColorResourceV4name6bundleACSS_So8NSBundleCtcfC
0000000000002658	bl	0x4d84 ; symbol stub for: _swift_bridgeObjectRelease
00000000000026b8	bl	0x4d24 ; symbol stub for: _objc_opt_self
00000000000026bc	bl	0x4dc0 ; symbol stub for: _swift_getObjCClassMetadata
0000000000002708	bl	0x4ba4 ; symbol stub for: _$sSS10FoundationE19_bridgeToObjectiveCSo8NSStringCyF
0000000000002718	bl	0x4db4 ; symbol stub for: _swift_getObjCClassFromMetadata
0000000000002738	bl	0x4d30 ; symbol stub for: _objc_retainAutoreleasedReturnValue
0000000000002778	bl	0x4d84 ; symbol stub for: _swift_bridgeObjectRelease
0000000000002818	bl	0x4b08 ; symbol stub for: _$s21DeveloperToolsSupport13ColorResourceVMa
00000000000028f8	bl	0x4c1c ; symbol stub for: _$sSo7UIColorC5UIKitE8resourceAB21DeveloperToolsSupport13ColorResourceV_tcfC
0000000000002978	bl	0x4b08 ; symbol stub for: _$s21DeveloperToolsSupport13ColorResourceVMa
0000000000002a04	bl	0x4d0c ; symbol stub for: _memcpy
0000000000002a30	bl	0x4b08 ; symbol stub for: _$s21DeveloperToolsSupport13ColorResourceVMa
0000000000002adc	bl	0x4b08 ; symbol stub for: _$s21DeveloperToolsSupport13ColorResourceVMa
0000000000002bb8	bl	0x4b98 ; symbol stub for: _$s7SwiftUI5ColorVyAC21DeveloperToolsSupport0C8ResourceVcfC
0000000000002bc0	bl	0x4e20 ; symbol stub for: _swift_retain
0000000000002c28	bl	0x4e14 ; symbol stub for: _swift_release
0000000000002c94	bl	0x4b08 ; symbol stub for: _$s21DeveloperToolsSupport13ColorResourceVMa
0000000000002d70	bl	0x4b98 ; symbol stub for: _$s7SwiftUI5ColorVyAC21DeveloperToolsSupport0C8ResourceVcfC
0000000000002d78	bl	0x4e20 ; symbol stub for: _swift_retain
0000000000002e04	bl	0x4b20 ; symbol stub for: _$s21DeveloperToolsSupport13ImageResourceVMa
0000000000002e80	bl	0x4d90 ; symbol stub for: _swift_bridgeObjectRetain
0000000000002efc	bl	0x4b14 ; symbol stub for: _$s21DeveloperToolsSupport13ImageResourceV4name6bundleACSS_So8NSBundleCtcfC
0000000000002f78	bl	0x4d84 ; symbol stub for: _swift_bridgeObjectRelease
0000000000002fd8	bl	0x4d24 ; symbol stub for: _objc_opt_self
0000000000002fdc	bl	0x4dc0 ; symbol stub for: _swift_getObjCClassMetadata
0000000000003028	bl	0x4ba4 ; symbol stub for: _$sSS10FoundationE19_bridgeToObjectiveCSo8NSStringCyF
0000000000003038	bl	0x4db4 ; symbol stub for: _swift_getObjCClassFromMetadata
0000000000003058	bl	0x4d30 ; symbol stub for: _objc_retainAutoreleasedReturnValue
0000000000003098	bl	0x4d84 ; symbol stub for: _swift_bridgeObjectRelease
0000000000003138	bl	0x4b20 ; symbol stub for: _$s21DeveloperToolsSupport13ImageResourceVMa
0000000000003218	bl	0x4c28 ; symbol stub for: _$sSo7UIImageC5UIKitE8resourceAB21DeveloperToolsSupport13ImageResourceV_tcfC
0000000000003298	bl	0x4b20 ; symbol stub for: _$s21DeveloperToolsSupport13ImageResourceVMa
0000000000003324	bl	0x4d0c ; symbol stub for: _memcpy
0000000000003350	bl	0x4b20 ; symbol stub for: _$s21DeveloperToolsSupport13ImageResourceVMa
00000000000033b8	bl	0x4d24 ; symbol stub for: _objc_opt_self
00000000000033f4	bl	0x4bf8 ; symbol stub for: _$sScMMa
0000000000003408	bl	0x4dfc ; symbol stub for: _swift_getWitnessTable
0000000000003448	bl	0x4e80 ; symbol stub for: _swift_unknownObjectRelease
0000000000003460	bl	0x4da8 ; symbol stub for: _swift_deallocObject
0000000000003498	bl	0x4bf8 ; symbol stub for: _$sScMMa
00000000000034a4	bl	0x4bec ; symbol stub for: _$sScM6sharedScMvgZ
00000000000034c0	bl	0x4be0 ; symbol stub for: _$sScA15unownedExecutorScevgTj
00000000000034e8	b	0x4e74 ; symbol stub for: _swift_task_switch
0000000000003564	bl	0x4e14 ; symbol stub for: _swift_release
00000000000035d8	bl	0x4c34 ; symbol stub for: _$ss17_assertionFailure__4file4line5flagss5NeverOs12StaticStringV_A2HSus6UInt32VtF
0000000000003600	bl	0x4e80 ; symbol stub for: _swift_unknownObjectRelease
0000000000003608	bl	0x4e14 ; symbol stub for: _swift_release
0000000000003620	bl	0x4da8 ; symbol stub for: _swift_deallocObject
0000000000003694	bl	0x4e2c ; symbol stub for: _swift_task_alloc
0000000000003730	bl	0x4e44 ; symbol stub for: _swift_task_dealloc
00000000000037e0	bl	0x4c10 ; symbol stub for: _$sScPMa
0000000000003828	bl	0x4c04 ; symbol stub for: _$sScP8rawValues5UInt8Vvg
000000000000387c	bl	0x4e8c ; symbol stub for: _swift_unknownObjectRetain
00000000000038d4	bl	0x4dcc ; symbol stub for: _swift_getObjectType
00000000000038e0	bl	0x4be0 ; symbol stub for: _$sScA15unownedExecutorScevgTj
0000000000003900	bl	0x4e80 ; symbol stub for: _swift_unknownObjectRelease
0000000000003988	bl	0x4bb0 ; symbol stub for: _$sSS11utf8CStrings15ContiguousArrayVys4Int8VGvg
00000000000039a8	bl	0x4e20 ; symbol stub for: _swift_retain
00000000000039c8	bl	0x4d78 ; symbol stub for: _swift_allocObject
0000000000003a90	bl	0x4e38 ; symbol stub for: _swift_task_create
0000000000003aa8	bl	0x4e14 ; symbol stub for: _swift_release
0000000000003ae4	bl	0x4e14 ; symbol stub for: _swift_release
0000000000003b04	bl	0x4d78 ; symbol stub for: _swift_allocObject
0000000000003bb0	bl	0x4e38 ; symbol stub for: _swift_task_create
0000000000003c2c	bl	0x4c34 ; symbol stub for: _$ss17_assertionFailure__4file4line5flagss5NeverOs12StaticStringV_A2HSus6UInt32VtF
0000000000003c4c	bl	0x4e14 ; symbol stub for: _swift_release
0000000000003c90	bl	0x4c10 ; symbol stub for: _$sScPMa
0000000000003cfc	bl	0x4c10 ; symbol stub for: _$sScPMa
0000000000003d88	bl	0x4d0c ; symbol stub for: _memcpy
0000000000003de4	bl	0x4e2c ; symbol stub for: _swift_task_alloc
0000000000003e64	bl	0x4e44 ; symbol stub for: _swift_task_dealloc
0000000000003e9c	bl	0x4e14 ; symbol stub for: _swift_release
0000000000003eb4	bl	0x4da8 ; symbol stub for: _swift_deallocObject
0000000000003f18	bl	0x4e2c ; symbol stub for: _swift_task_alloc
0000000000003fac	bl	0x4e44 ; symbol stub for: _swift_task_dealloc
0000000000003fe0	bl	0x4e14 ; symbol stub for: _swift_release
0000000000003ff8	bl	0x4da8 ; symbol stub for: _swift_deallocObject
000000000000405c	bl	0x4e2c ; symbol stub for: _swift_task_alloc
00000000000040f0	bl	0x4e44 ; symbol stub for: _swift_task_dealloc
000000000000413c	bl	0x4d24 ; symbol stub for: _objc_opt_self
0000000000004140	bl	0x4dc0 ; symbol stub for: _swift_getObjCClassMetadata
00000000000041ac	bl	0x4c64 ; symbol stub for: _$ss27_allocateUninitializedArrayySayxG_BptBwlF
00000000000041d0	bl	0x4bc8 ; symbol stub for: _$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC
000000000000422c	bl	0x4c70 ; symbol stub for: _$ss5print_9separator10terminatoryypd_S2StF
0000000000004234	bl	0x4d84 ; symbol stub for: _swift_bridgeObjectRelease
000000000000423c	bl	0x4d84 ; symbol stub for: _swift_bridgeObjectRelease
0000000000004244	bl	0x4d84 ; symbol stub for: _swift_bridgeObjectRelease
000000000000460c	bl	0x4c88 ; symbol stub for: __availability_version_check
000000000000470c	bl	0x4c7c ; symbol stub for: ___stack_chk_fail
00000000000047b8	bl	0x4ca0 ; symbol stub for: _dlsym
00000000000047d0	bl	0x4ca0 ; symbol stub for: _dlsym
00000000000047e8	bl	0x4ca0 ; symbol stub for: _dlsym
00000000000047fc	bl	0x4ca0 ; symbol stub for: _dlsym
0000000000004818	bl	0x4ca0 ; symbol stub for: _dlsym
0000000000004830	bl	0x4ca0 ; symbol stub for: _dlsym
0000000000004848	bl	0x4ca0 ; symbol stub for: _dlsym
0000000000004860	bl	0x4ca0 ; symbol stub for: _dlsym
0000000000004878	bl	0x4ca0 ; symbol stub for: _dlsym
0000000000004890	bl	0x4ca0 ; symbol stub for: _dlsym
00000000000048a4	bl	0x4cf4 ; symbol stub for: _getenv
00000000000048b4	bl	0x4d6c ; symbol stub for: _strlen
00000000000048dc	bl	0x4d60 ; symbol stub for: _strcpy
00000000000048e0	bl	0x4d6c ; symbol stub for: _strlen
0000000000004910	bl	0x4cb8 ; symbol stub for: _fopen
0000000000004924	bl	0x4cdc ; symbol stub for: _fseek
000000000000492c	bl	0x4ce8 ; symbol stub for: _ftell
000000000000493c	bl	0x4d48 ; symbol stub for: _rewind
0000000000004944	bl	0x4d00 ; symbol stub for: _malloc
000000000000495c	bl	0x4cc4 ; symbol stub for: _fread
0000000000004a5c	bl	0x4d54 ; symbol stub for: _sscanf
0000000000004a7c	bl	0x4cd0 ; symbol stub for: _free
0000000000004a84	bl	0x4cac ; symbol stub for: _fclose
0000000000004ac8	bl	0x4c7c ; symbol stub for: ___stack_chk_fail
0000000000004ad0	b	0x4c94 ; symbol stub for: _dispatch_once_f

So, conceptually, the Lazy Symbol Pointer Table still exists — it’s just implemented differently now. The stub + GOT + dyld resolver is the modern equivalent.


Dispatching Model (Full Picture)

So, we’ve approved that modern Apple platforms no longer use a separate LazyPointerTable or an explicit Trampoline inside the app binary.
Lazy binding is implemented through a combination of:

  • stubs (__TEXT,__stubs)
  • GOT (__DATA_CONST,__got)
  • dyld resolver logic

So the real dispatch chain today looks like this:

Static frameworks skip this chain entirely.


What Comes Next

The mental model is complete. You know what a stub is, what dyld does, and why a static call looks different from a dynamic one — on paper.

But there is a gap between knowing the model and being able to confirm it in a real binary.

Can you open a compiled app and point to the stub? Can you find the GOT entry? Can you run a single terminal command and prove whether dyld is involved at all?

In Article 2, that gap closes.


Further Reading

Last updated on