Upgrade to Pro — share decks privately, control downloads, hide ads and more …

The new linker in Xcode 15

The new linker in Xcode 15

Yuta Saito

July 14, 2023
Tweet

More Decks by Yuta Saito

Other Decks in Programming

Transcript

  1. The new linker in Xcode 15
    WWDC Recap
    Yuta Saito (@kateinoigakukun)
    1

    View full-size slide

  2. Agenda
    1. man page diff
    2. What is ld-prime?
    3. Faster Linking
    4. Mergeable Library
    5. Mergeable Library Internals
    2

    View full-size slide

  3. 1. man page diff
    Changes
    1. Two linker binaries: ld and
    ld-prime
    2. New options for ld-prime
    3. ld-prime drops support
    for armv7k and i386
    Rarely used Options
    + -ld64 Override the choice of linker, and force the use of ld64 to link
    + the binary. This is incompatible with options such as -merge*,
    + used to build/merge libraries.
    +
    + -ld_prime
    + Override the choice of linker, and force the use of ld-prime to
    + link the binary. This is incompatible with older architectures
    + such as armv7k and i386.
    +
    + Mergeable Library Options
    + -make_mergeable
    + Adds additional metadata to a dylib which makes it a mergeable
    + library. It can still be used as a dylib, or can be merged into
    + other binaries when they link it with a -merge* option.
    +
    + -merge-lx
    + This is the same as the -lx option but means to merge the
    + contents of the library x into this binary.
    +
    + -merge_library path_to_library
    + This is the same as listing a file name path to a library on the
    + link line but also merges the contents of the library into this
    + binary.
    +
    + -merge_framework name[,suffix]
    + This is the same as the -framework name[,suffix] but means that
    + the contents of the framework should be merged into this binary.
    +
    3

    View full-size slide

  4. 2. What is ld-prime?
    From Platforms State of the Union
    • The linker has been redesigned from the ground up
    • Linking is up to 5 times faster!
    • Size of debug binaries are up to 30% smaller!
    4

    View full-size slide

  5. 3. Faster Linking
    5

    View full-size slide

  6. 3. Faster Linking
    ld-prime utilizes parallelism to speed up linking.
    6

    View full-size slide

  7. 4. Mergeable Library
    7

    View full-size slide

  8. Trade off between static linking and dynamic linking
    Static Linking Dynamic Linking
    Launch Time Fast Slow
    Linking Time Slow Fast
    8

    View full-size slide

  9. Before Xcode 15
    • Two targets are needed to
    achieve the best build-
    time and launch-time.
    • Pre-compiled framework
    authors need to ship both
    static and dynamic
    frameworks to support
    both use cases.
    9

    View full-size slide

  10. Mergeable Library
    • Mergeable Library is a new concept introduced in Xcode
    15
    • A dynamic library with additional metadata
    • Designed to be able to defer the decision of link-strategy
    until the final link step.
    10

    View full-size slide

  11. .xcodeproj settings
    • MERGED_BINARY_TYPE
    • Automatic: Static link for Debug, Dynamic link for
    Release
    • Manual: Static link targets whose MERGEABLE_LIBRARY is
    set to YES for Debug.
    • MERGEABLE_LIBRARY
    • YES: The target is built as a mergeable library
    11

    View full-size slide

  12. See https://developer.apple.com/videos/play/
    wwdc2023/10268/
    12

    View full-size slide

  13. 5. Mergeable Library Internals
    13

    View full-size slide

  14. Debug
    $ otool -L Debug-iphonesimulator/MyApp.app/MyApp | grep @rpath
    @rpath/MyUI.framework/MyUI
    Release
    $ otool -L Release-iphonesimulator/MyApp.app/MyApp | grep @rpath
    # empty
    14

    View full-size slide

  15. Debug
    $ tree -h -L 3 Debug-iphonesimulator/MyApp.app
    ├── [ 96] Frameworks
    │ └── [ 192] MyUI.framework
    │ ├── [ 22K] Assets.car
    │ ├── [ 716] Info.plist
    │ ├── [ 34K] MyUI
    │ └── [ 96] _CodeSignature
    ├── [1.2K] Info.plist
    ├── [106K] MyApp
    ├── [ 8] PkgInfo
    ├── [ 96] ReexportedBinaries
    │ └── [ 160] MyUI.framework
    │ ├── [ 716] Info.plist
    │ ├── [106K] MyUI
    │ └── [ 96] _CodeSignature
    └── [ 96] _CodeSignature
    └── [3.7K] CodeResources
    Release
    $ tree -h -L 3 Release-iphonesimulator/MyApp.app
    ├── [ 96] Frameworks
    │ └── [ 192] MyUI.framework
    │ ├── [ 22K] Assets.car
    │ ├── [ 716] Info.plist
    │ ├── [ 34K] MyUI
    │ └── [ 96] _CodeSignature
    ├── [1.2K] Info.plist
    ├── [231K] MyApp
    ├── [ 8] PkgInfo
    └── [ 96] _CodeSignature
    └── [2.9K] CodeResources
    15

    View full-size slide

  16. Bundle(for: AnyClass) hook for statically linked
    Mergeable Library
    • Bundle(for: AnyClass) finds a bundle path which
    contains the given class code
    • If a library is statically linked, its code is in the merged binary
    but bundle resources are not.
    • ld-prime inserts a hook to find the correct bundle path
    when merging a framework.
    16

    View full-size slide

  17. /**
    * Returns the dynamic library name a class originated from.
    *
    * @param cls The class you are inquiring about.
    *
    * @return The name of the library containing this class.
    */
    OBJC_EXPORT const char * _Nullable
    class_getImageName(Class _Nullable cls)
    /**
    * Install a hook for class_getImageName().
    *
    * @param newValue The hook function to install.
    * @param outOldValue The address of a function pointer variable. On return,
    * the old hook function is stored in the variable.
    *
    * @note The store to *outOldValue is thread-safe: the variable will be
    * updated before class_getImageName() calls your new hook to read it,
    * even if your new hook is called from another thread before this
    * setter completes.
    * @note The first hook in the chain is the native implementation of
    * class_getImageName(). Your hook should call the previous hook for
    * classes that you do not recognize.
    *
    * @see class_getImageName
    * @see objc_hook_getImageName
    */
    OBJC_EXPORT void objc_setHook_getImageName(objc_hook_getImageName _Nonnull newValue,
    objc_hook_getImageName _Nullable * _Nonnull outOldValue)
    https://github.com/apple-oss-distributions/objc4/blob/689525d556eb3dee1ffb700423bccf5ecc501dbf/runtime/runtime.h#L1454-L1462 17

    View full-size slide

  18. Wrap up
    1. Xcode 15 ships a blazingly fast new linker ld-prime
    2. ld-prime introduces a new concept called Mergeable
    Library
    3. Mergeable Library achieves best developer/user experience
    4. See my research notes for more details:
    https://github.com/kateinoigakukun/
    MergeableLibraryInternals
    19

    View full-size slide