MacOS 下的动态链接

深入解析dyld:macOS/iOS动态链接器原理、优化与实战 动态链接是现代操作系统的核心技术,它通过共享库机制解决了代码复用和资源浪费问题。其核心原理是在程序运行时,由动态链接器负责将可执行文件与所需的共享库进行连接,完成符号解析和地址重定位。这项技术的核心价值在于显著节省内存和磁盘空间,支持模块化更新,并提升系统安全性。在macOS和iOS生态中,动态链接器dyld扮演着关键角色,负责管理Mach-O文件的加载、符号绑定和初始化流程。dyld 3引入的启动闭包机制,通过预计算链接信息大幅优化了启动性能,同时增强了安全性。理解dyld的搜索路径规则、两级命名空间和符 阅读详情

本文主要讲解 MacOS 下的链接,是与 MacOS 和 iOS 开发相关的内容,其他平台可能也会有类似的操作。

本文大部分篇幅都是讲动态链接,静态链接也简单讲了一下,很多不错的参考文章列在文末,感兴趣可以看下。

1、ld manual

Libraries

A static library (aka static archive) is a collection of .o files with a table of contents that lists the global symbols in the .o files. ld will only pull .o files out of a static library if needed to resolve some symbol reference. Unlike traditional linkers, ld will continually search a static library while linking. There is no need to specify a static library multiple times on the command line.

A dynamic library (aka dylib or framework) is a final linked image. Putting a dynamic library on the command line causes two things: 1) The generated final linked image will have encoded that it depends on that dynamic library. 2) Exported symbols from the dynamic library are used to resolve references.

Both dynamic and static libraries are searched as they appear on the command line.

2、动态链接

2.1、动态库符号查找

链接器发现 program1.o 中引用的外部符号在一个动态库(动态库中保存由其到处的符号信息)中,此时链接器并不会对该符号进行重定位,而是标记其为动态链接符号,把真正的链接过程保留到装载时执行。

image.png

如果存在未定义符号,编译链接时一样是会报错的。

这时候,可以利用本文 2.4 介绍的方法,把符号查找推迟给 dyld 查找。

2.2、案例

通过例子来分析:

// add.h
extern int add(int num);

// add.c
#include "add.h"

int add(int num){
  return num + 8;
}

// main.c
#include"add.h"

int main(){
  int tmp = 10;
  tmp = add(tmp);
  return 0;
}
  • 生成动态链接库:

动态库需要为地址无关代码,这样不论它在内存哪里被加载,都可以正常使用,所以得加上 -fPIC 参数。

gcc -fPIC -shared add.c -o share

使用 MachOView 观摩下这个动态库:

image.png

解析一下这个 LC_ID_DYLIB 字段:

Any clients that link against the dylib record the path specified in the LC_ID_DYLIB load command as the path at which to find the dylib at runtime.

This is useful as the path where the dylib lives at build time is often not where it will be found at runtime.

简单来说就是:This is the path that will be copied into the binaries that link to it.

  • 链接动态库生成最终可执行文件:
gcc main.c share -o main

image.png

The LC_LOAD_DYLIB header in a Mach-O binary tells macOS and OS X which dynamic libraries (dylibs) to load during execution time.

2.3、汇编分析

对于以动态库链接的符号,是在程序加载进内存时或者运行时才进行链接,因此这些符号在 MachO 里被特殊对待。

image.png

这里的 dyld_stub_binder 不是 lazy symbol,启动时,dyld 就直接给绑定好了。

像上面 1.1 案例中,add 符号被当作延迟绑定的了,因为这个符号不会马上被用到:

image.png

通过汇编代码来看看整个过程是怎么处理的:

  • __TEXT,__text
                     _main:
0000000100003f60         push       rbp                         ; 保存栈帧指针,标识当前栈底
0000000100003f61         mov        rbp, rsp                    ; rbp 更新为当前栈顶 rsp
0000000100003f64         sub        rsp, 0x10                   ; 开辟 16 字节的栈空间
0000000100003f68         mov        dword [rbp-4], 0x0          ; double word,前 4 字节初始化为 0
0000000100003f6f         mov        dword [rbp-8], 0xa          ; 后 4 字节初始化为 10,对应源码:int tmp = 10;
0000000100003f76         mov        edi, dword [rbp-8]          ; 把这个变量交给 edi
0000000100003f79         call       imp___stubs__add            ; add 方法的延迟绑定处理
0000000100003f7e         xor        ecx, ecx                    ; 异或自身,即把 ecx 赋为 0
0000000100003f80         mov        dword [rbp-8], eax          ; eax 保存 add 方法的返回值,赋回给变量
0000000100003f83         mov        eax, ecx                    ; 把 eax 清理为 0
0000000100003f85         add        rsp, 0x10                   ; 归还栈空间
0000000100003f89         pop        rbp                         ; 取回栈帧指针
0000000100003f8a         ret                                    ; 返回
                        ; endp
  • __TEXT,__stubs
                     imp___stubs__add:        // add
0000000100003f8c         jmp        qword [_add_ptr]            ; 直接跳转到另一个地址 (void *)0x0000000100003fa4
                        ; endp
  • __TEXT,__stub_helper
0000000100003f94         lea        r11, qword [__dyld_private] ; Load Effective Address
0000000100003f9b         push       r11                         ; 0x0000000100008008  _dyld_private 在 data 段
0000000100003f9d         jmp        qword [dyld_stub_binder_100004000]
																; (void *)0x00007fff6d355578: dyld_stub_binder 我这标的是运行时地址
0000000100003fa3         nop
0000000100003fa4         push       0x0                         ; add 绑定先跳到了这里,入栈 0x0
0000000100003fa9         jmp        0x100003f94                 ; 直接跳转到 0x100003f94,即这里的第一条指令
  • __DATA_CONST,__got

dyld_stub_binder 这个符号来自于 libdyld.dylib,由于已经绑定好了,所以上面跳转到其运行时地址 0x00007fff6d355578

                     dyld_stub_binder_100004000:        // dyld_stub_binder
0000000100004000         extern     dyld_stub_binder                            ; DATA XREF=0x100003f9d

这个函数非常长,这里就不展开了。

这个函数结束后,add 函数在内存中就已经有了,而且 dyld_stub_binder 最后一条指令会通过寄存器跳转到 add 函数。

image.png

再回去看 imp___stubs__add,看看现在的指令跳转是否被修正了:

image.png

之后就会直接跳转到 add 函数了。

实际上当程序启动时,相关的库或者函数已经被加载到内存里了,dyld_stub_binder 只是一个查找并绑定的操作。

image.png

2.4、-undefined dynamic_lookup

如果依赖了其他地方的符号,可能会报 undefined 错误,静态库的话可以直接用 -c 参数处理,即不链接。

gcc -c add.c -o add.o
ar rcs libadd.a add.o
gcc main.c libadd.a -o main

如果是动态库用了 -c 就没法编成动态库了:

image.png

image.png

可以采用标题的 -undefined dynamic_lookup 参数,把符号查找推迟到运行时:

(对静态库的 undefined 符号同样有用)

image.png

image.png

这种符号在动态库中会被变成 indirect symbol,由 dyld 代为查找。

但如果 dyld 在装载时或者运行时还找不到符号,则会导致 crash,所以最好还是把问题提前到编译链接期暴露,慎用!

image.png

Note that -undefined dynamic_lookup is OSX-specific. Linux shared libraries behave as if -undefined dynamic_lookup was enabled all the time.

I don’t recommend to enable global dynamic lookup:

-undefined dynamic_lookup which will mark all undefined symbols as having to be looked up at runtime.

Much more safe way to resolve it for specific symbols:

-Wl,-U,symbol_name, which only does so for the given symbol (note: you have to prepend an underscore to the symbol name)

You could also use weak dynamic linking:

extern int SayHello() __attribute__((weak));

链接器发现同时存在弱符号和强符号,有限选择强符号,如果发现不存在强符号,只存在弱符号,则选择弱符号。如果都不存在:静态链接,恭喜,编译时报错,动态链接:对不起,系统无法启动。

// strong.c  // 生成libstrong.so
#include <stdio.h>
void real_func()
{
    printf("int real func\n");
}
 
// weak.c // 生成libweak.so
#include <stdio.h>
void real_func() __attribute__((weak));
void real_func()
{
    printf("fake func\n");
}
 
// main.c //
#include <stdio.h>
extern void real_func();
void main()
{
        real_func();
}

2.5、无用代码

由于动态库无法判断哪些符号会被外部引用,即其所有 .o 都会被保留,那么就会占用内存空间和包大小。

image.png

如上图,我写了一个没用到的函数,它也被加载到内存空间了。

3、静态链接

根据苹果文档的描述,其并不支持静态链接:

  • A static library is a library of code that can be linked into a binary that will, eventually, be dynamically linked to the system libraries and frameworks.

  • A statically linked binary is one that does not import system libraries and frameworks dynamically, but instead makes direct system calls into the kernel.

Apple fully supports static libraries; if you want to create one, just start with the appropriate Xcode project or target template.

Apple does not support statically linked binaries on Mac OS X. A statically linked binary assumes binary compatibility at the kernel system call interface, and we do not make any guarantees on that front. Rather, we strive to ensure binary compatibility in each dynamically linked system library and framework.

这里需要区分静态库和静态链接。

-static     Produces a mach-o file that does not use the dyld.  Only used building the kernel.

所以我们在 MacOS 上对于静态库只是链接操作,不能称之为静态链接。

image.png

硬是想弄出来也行,参考文章:https://oao.moe/archives/937/

参考&推荐阅读

LC_ID_DYLIB:https://stackoverflow.com/questions/42210767/what-is-the-significance-of-a-macos-mach-o-dylib-lc-id-dylib-name-or-install-na

Statically linked binaries on Mac OS X:_https://developer.apple.com/library/archive/qa/qa1118/index.html

动态链接:https://www.jianshu.com/p/5deed1bf82b4

Clang and undefined symbols when building a library:https://stackoverflow.com/questions/25421479/clang-and-undefined-symbols-when-building-a-library

attribute((weak)) 用法:https://blog.youkuaiyun.com/sea_snow/article/details/83650519

基于Simulink的无线充电系统LCC补偿网络建模与控制 本文详细介绍了基于Simulink的无线充电系统LCC补偿网络建模与控制方法。首先分析了无线充电系统面临的核心挑战,提出LCC补偿网络解决方案,阐述了其恒流输出和输入阻抗解耦原理。通过Simulink分步演示了系统建模过程,包括松耦合变压器、LCC+LC补偿网络、功率变换级搭建以及频率跟踪控制实现。仿真结果表明,LCC补偿系统在气隙变化和负载跳变下能保持输出电压稳定(波动±3%),效率达89%。文章还总结了工程实现要点,并探讨了动态充电、多负载系统等扩展应用。该教程为开发高效智能的无线充电系统提供了实用指导 阅读详情

相关推荐

DeepSeek Harness桌面版安装教程:从零配置到实用插件推荐

在AI编程工具逐步普及的今天,开发者越来越关注如何将大模型能力无缝融入日常编码流程。这类工具的核心在于构建一个连接模型服务与本地开发环境的中间层,通过项目级上下文理解、终端指令执行和插件机制,让AI真正成为能动手干活的编程副驾驶。安装配置过程中,环境准备、模型服务连接与工具权限设置是三个关键环节。完成基础搭建后,选择合适的插件能显著提升代码质量与问题排查效率,例如基于代码审查的规范对齐和安全扫描,以及面向运行时日志关联分析与性能告警的诊断工具。本文以DeepSeek Harness桌面版为例,从环境自查、安

weixin_31286719的博客 310

undefined reference to错误的解决方法

对于动态链接库,实际的符号定位是在运行期进行的.在编译.so的时候,如果没有把它需要的库和他一起进行联编,比如libx.so 需要使用uldict, 但是忘记在编译libx.so的时候加上-luldict的话,在编译libx.so的时候不会报错,因为这个时候libx.so被认为是一个库,它里面存在一些不知道具体实现的符号是合法的,是可以在运行期指定或者编译另外的二进制程序的时候指定。一般情况链接的时候我们采用-L的方式指定查找路径,调用动态链接库的时候采用LD_LIBRARY_PATH的方式指定链接路径。

顺其自然~专栏 2万+

ENVI学习总结(十二)——基于改进的 CASA 模型反演 NPP

基于改进的 CASA 模型反演 NPP 数据为地理空间数据云提供的 TM 影像,其具体信息如图 1 所示。该实验中所使用的 TM 数据已进行过 QUAC 快速大气校正,来消除大气和光照等因素对地物反射的影响。Landsat 主题成像仪(TM)是 Landsat4 和 Landsat5 携带的传感器,每 16 天扫描同一地区,即 16 天覆盖全球一次。 TM 影像包含 7 个波段,波段 1-5 ...

Arcgiser的博客 3万+

阅读笔记-程序员的自我修养3

elf文件格式 3.2段 file header 描述文件属性 是否可执行、 是静态链接还是动态链接及入口地址(如果是可执行文件) 目标硬件、目标操作系统 段表(Section Table),是一个描述文件中各个段的数组。段表描述了文件中各个段在文件中的偏移位置及段的属性等,从段表里面可以得到每个段的所有信息 全局变量和局部静态变量 已初始化的 . data段; 未初始化的 .“bss”段。 未初始化的全局变量和局部静态变量默认值都为0, 在.data段分配空间并且存放数据0是没有必要的。 程序运行的时候它

wangruiqics的博客 296

Xilinx System Generator多速率系统(Multi-Rate Systems)的使用

在本实验练习中,您将学习在System Generator中如何使用多个时钟域有效地实现具有多个数据速率的设计。

白码王子小张的博客 1093

Xilinx Chip2Chip IP核实战:Aurora PHY通信配置与仿真避坑指南

本文深入解析Xilinx Chip2Chip IP核与Aurora PHY的通信配置与仿真优化,提供实战避坑指南。通过AXI协议转换桥实现FPGA间高速数据传输,详细讲解Aurora PHY参数设置、仿真加速技巧及常见问题解决方案,帮助工程师快速部署稳定高效的芯片间通信系统。

g5h6i7j的博客 1006

undefined reference问题总结

<br />最近在Linux下编程发现一个诡异的现象,就是在链接一个静态库的时候总是报错,类似下面这样的错误: (.text+0x13): undefined reference to `func' <br />    关于undefined reference这样的问题,网上也有很多的说法,在此,我以详细地示例给出其中的各种原因说明以及解决方法,然后再给出我所遇到的与大家均不同的问题。<br />1.  链接时缺失了相关目标文件(.o)<br />    测试代码如下:<br />  <br />  

Listening_music的专栏 1万+

三菱A800变频器矢量控制实战:从速度控制到位置控制的PLG参数设置全解析

本文深入解析了三菱A800变频器结合FR-A8AP选件板与PLG(脉冲编码器)实现高精度矢量控制的实战应用。详细阐述了从速度控制、转矩控制到位置控制三种高级模式的切换逻辑、核心参数设置及硬件接线要点,帮助工程师充分发挥A800变频器的闭环控制潜力,应对复杂工业自动化场景。

weixin_28308325的博客 326

C++学习零

C++和C的关系 从概念上来说,C语言是一种面向过程的编程语言,而C++是一种面向对象编程的语言。 一句话总结起来C++和C的关系-----C++=C+类+泛型编程+stl容器算法,这是贯穿C++整个学习的一条主线路。 C++代码怎么跑起来呢 上面就是一个C++代码基本的流程,通常会经历源代码->预处理->编译->汇编->链接->可执行文件 在此给出linux平台下C++代码源文件命令行:g++ source.cpp -o exefile ,然后回车键,然后./exefil

zjyhyrl123的博客 249

【EPICS学习记录】根据官方教程创建一个IOC应用

参照官网给出的IOC创建教程逐步操作完成了一个IOC应用的创建,官网教程中有部分过程表述的不清晰,自己摸索之后完成了IOC的创建,并把流程记录下来。其中有一些操作不是很理解,有问题或者建议欢迎指正。

yifeng_H的博客 3661

某知名系统漏洞挖掘与利用思路探索

本文以安全研究为目的,分享对该套系统的代码审计和漏洞挖掘过程,文中所提到的漏洞均已提交给CNVD&CITIVD,请勿用做非法用途。

C20220511的博客 1904

“undefined reference to“ 问题汇总及解决方法 ------非常非常好的一篇文章

转载地址:https://segmentfault.com/a/1190000006049907?utm_source=tuicool&utm_medium=referral 在实际编译代码的过程中,我们经常会遇到"undefined reference to"的问题,简单的可以轻易地解决,但有些却隐藏得很深,需要花费大量的时间去排查。工作中遇到了各色各样类似的问题,按照以下几

认知 行动 坚持 23万+

别再用LabelImg了!我手搓了一个C#“一站式”YOLO工具箱,标注训练推理全搞定

这个工具箱目前已经在两个小型产线项目中试用,反馈非常好。效率提升:原本需要 2 天完成的“数据准备 - 训练 - 验证”循环,现在缩短到了 2 小时。门槛降低:产线技术员经过 10 分钟培训,就能独立完成新产品的模型迭代。当然,它还有改进空间未来计划集成主动学习功能:自动筛选出置信度低的图片,推荐优先标注。支持多模型管理:方便在不同产品型号间快速切换。增加PLC 通信模块:直接在推理界面配置 IO 信号,实现真正的软硬联动。最后想说工具的本质是服务于人。

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 441

解决MacOS上的动态链接库问题(dyld相关)

但是unset了之后,操作psql又报错了(之前临时设置的。,而不是 Git 编译时预期的 Homebrew。解释:将需要的目录添加进可执行文件的。

osmanthuspeace的博客 2280

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

MacOS平台下@rpath在动态链接库中的应用

@rpath. framework 配置

VictorZhang 1526

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

深度揭秘 macOS/iOS 动态链接库 dylib:结构、机制、使用与安全防范

dylib的核心作用是为多个程序提供可共享的代码和资源,实现代码复用、减少内存占用,并支持程序的模块化更新。这使得开发者可以更高效地开发和维护应用程序。

VBP_2025的博客 2004

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

ld 链接器 undefined reference to `__main_MacOS 下的动态链接

本文主要讲解 MacOS 下的链接,是与 MacOS 和 iOS 开发相关的内容,其他平台可能也会有类似的操作。本文大部分篇幅都是讲动态链接,静态链接也简单讲了一下,很多不错的参考文章列在文末,感兴趣可以看下。1、ld manualLibrariesA static library (aka static archive) is a collection of .o files with...

weixin_32632831的博客 393

如何把Windows,Linux和macOS的动态链接库封装到一个Java Jar包中

2019独角兽企业重金招聘Python工程师标准>>> ...

weixin_33816611的博客 353

cmake中添加引用动态链接_macos - CMake:MacOS上动态链接资源的运行时错误(dyld:未加载库) - SO中文参考 - www.soinside.com...

问题在MacOS上,我在运行时为依赖于动态链接资源的CMake项目获取链接问题 - 但仅在安装项目之后!当我只构建二进制文件而不安装它时,不会发生这个问题。$ ./testappHello world!$ $INSTALLDIR/testappdyld: Library not loaded: @rpath/libvtkDomainsChemistryOpenGL2-7.1.1.dylibRefe...

weixin_39735509的博客 501

MacOS静态链接和动态链接

上一篇文章已经讲过了window系统下如何制作使用静态链接库和动态链接库, 这篇文章我们来看一下在Mac系统(Linux系统也是一样)下面如何制作静态链接库和动态链接库 太长不看版 假设我们有一个util.cpp文件和main.cpp文件,在main文件中调用util.cpp文件中定义的函数。我们把util.cpp文件制作成静态库和动态库。 生成目标文件 g++ -c util.cpp -o util.o 打包静态库 ar crv libutil.a util.o 生成动态库 g++ -sh

Vincent的专栏 1468

[原创](现代Delphi 12指南):[macOS 64bit App开发]: [1]如何加载动态链接库, 并无缝支持原生底层开发?

对于macOS平台来说, 动态链接库以.dylib文件形式存在, 广泛用于实现模块化设计和代码复用. 可以通过动态加载这些库, 在运行时调用其中的函数, 而无需将所有代码静态链接到应用程序中. Delphi 12作为一款强大的跨平台开发工具, 支持macOS 64位应用程序的开发. 它提供了与操作系统底层交互的能力, 可以轻松加载和使用macOS的动态链接库, 进而实现对原生功能的调用.

其实我不是代码教父,我只是猪头三 1452

深入解析DYLD:macOS/iOS动态链接器原理与实战优化

动态链接是现代操作系统的核心技术,它通过共享库代码解决了静态链接带来的内存浪费和程序体积膨胀问题。其核心原理是在程序运行时,由动态链接器负责将可执行文件与所需的共享库进行连接,完成符号解析和地址重定位。这项技术的核心价值在于提升系统资源利用效率、支持模块化开发,并成为应用热更新、插件化等高级特性的基础。在macOS和iOS生态中,动态链接器DYLD扮演着这一关键角色,它管理着应用启动时的库加载、符号绑定和初始化流程。理解DYLD的工作机制,特别是其搜索路径策略和符号绑定过程,对于解决常见的'Library

weixin_34090562的博客 423

关于MACOS与Linux中动态链接库的一些异同(踩坑)

动态链接库在两个系统中的作用是一样的,只是在生成方面和调用方面有一些不同点,下面进行比较: 动态链接库后缀 Mac Linux(Ubuntu) .dylib .so 生成方式 以下的.o文件均为于位置无关的文件生成方式为 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;g++ -fPIC -c + [所需要的文...

Zephyr的博客 2274

新版 MacOS 无法从 /usr/local/lib 加载动态链接库的解决办法

自己编写的动态链接库在Unix规范下一般位于/usr/local/lib,在2023年及之前的MacOS版本中,直接将动态库安装到该位置即可在程序运行时加载,可是升级MacOS版本后,ld就报错。

星空千代 1012
上一篇: MacOS 链接特性:Two-Level Namespace
下一篇: MacOS:多架构产物如何融合?
流左沙
博客等级 码龄11年 46粉丝 55原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值