目录一、基础概念1. 全称与作用2. 动态库 vs 静态库.so vs .a二、文件结构与格式三、常见使用场景1. Linux 服务 / 程序2. Android 开发最常接触场景3. 嵌入式 Linux四、核心工作原理动态链接两种加载方式五、常用命令Linux/Android adb 调试 so1. 查看依赖库2. 查看内部符号函数 / 变量3. 查看 ELF 段、架构、信息4. 瘦身 / 去除调试符号发布常用5. Android 专用adb六、常见问题与坑1. error while loading shared libraries: xxx.so: cannot open shared object file2. 架构不匹配3. 符号未导出JNI 常见4. 版本冲突七、Android 端补充开发重点八、总结.so是Linux/Android/Unix 系统下的动态共享库文件Shared Object对应 Windows 的.dll、macOS 的.dylib是二进制可执行文件存放编译后的代码、函数、变量、资源。一、基础概念1. 全称与作用全称Shared Object共享目标文件核心特点运行时动态加载、多个程序共享一份库代码区别于.a静态库编译时打包进程序。后缀惯例标准libxxx.soLinux 库命名规范前缀lib带版本libxxx.so.1.2.3主版本。次版本。修订版通常用软链接指向最新版2. 动态库 vs 静态库.so vs .a特性.so 动态库.a 静态库链接时机程序运行时加载编译链接阶段打包进可执行文件体积可执行文件小库单独存在可执行文件体积大占用空间多程序共用一份省磁盘 / 内存每个程序都拷贝一份冗余大更新方式替换 .so 文件即可无需重新编译主程序必须重新编译链接整个程序依赖运行环境必须存在对应 .so无外部库依赖独立运行二、文件结构与格式.so本质是ELF 格式文件Executable and Linkable FormatLinux 下所有可执行、库文件基本都是 ELF。 主要分段Section.text编译后的机器指令函数代码只读.data已初始化全局变量.bss未初始化全局变量不占文件空间运行时分配内存.rodata只读常量字符串、const 变量.symtab / .dynsym符号表函数名、变量名供链接 / 调用.dynstr动态符号字符串表.rel重定位段动态链接时修正内存地址关键动态符号表 (.dynsym)是外部程序调用库函数的核心被strip瘦身的 so 会丢失调试符号但保留动态调用符号。三、常见使用场景1. Linux 服务 / 程序系统底层、第三方组件、中间件大量使用.soC/C 程序依赖系统库libc.so标准 C 库、libpthread.so线程库Nginx、MySQL、Redis 等都会加载各类动态库2. Android 开发最常接触场景Android 基于 Linux 内核Native 层完全使用 .so架构区分不同 CPU 架构不能通用armeabi-v7a32 位 ARM 老设备arm64-v8a64 位 ARM 主流安卓机x86/x86_64模拟器、Intel 平板用途JNI 调用Java ↔ C/C把 C 代码编译成 so 给 App 调用音视频FFmpeg、OpenCV、加解密、渲染、逆向、插件等核心能力代码保护so 是二进制反编译难度远高于 Java 字节码3. 嵌入式 Linux路由器、机顶盒、工控机、物联网设备普遍依赖.so库。四、核心工作原理动态链接编译阶段主程序只记录「需要调用哪个 so 的哪个函数」不拷贝代码只留符号引用。运行阶段OS 的动态链接器 ld-linux.so工作加载可执行文件到内存根据依赖列表查找并加载对应.so到进程地址空间重定位修正函数内存地址完成符号绑定多个进程可共享同一份 so 内存副本仅数据段私有两种加载方式隐式加载编译链接时指定依赖编译程序时-lxxx链接 so程序启动自动加载最常用。显式加载运行时手动加载代码中主动调用 API 加载、卸载 soLinux/Android Cdlopen()→dlsym()→dlclose()适用插件化、动态按需加载、版本热更新五、常用命令Linux/Android adb 调试 so1. 查看依赖库ldd 可执行文件/xxx.so # 作用列出当前 so/程序 依赖的所有 .so排查 找不到库 问题2. 查看内部符号函数 / 变量# 查看所有符号含调试符号 nm xxx.so # 只看动态导出符号外部可调用的函数重点 nm -D xxx.so3. 查看 ELF 段、架构、信息# 查看文件架构、类型、位数 file xxx.so # 详细 ELF 信息 readelf -h xxx.so # 查看所有段 readelf -S xxx.so4. 瘦身 / 去除调试符号发布常用strip xxx.so # 作用删除调试符号、注释大幅减小文件体积不影响正常调用5. Android 专用adb# 进入手机 shell adb shell # 查看进程加载的所有 so cat /proc/[PID]/maps六、常见问题与坑1.error while loading shared libraries: xxx.so: cannot open shared object file原因系统找不到依赖的 so解决把 so 放到系统库路径/lib、/usr/lib配置环境变量export LD_LIBRARY_PATH/你的so目录:$LD_LIBRARY_PATH更新系统库缓存ldconfig2. 架构不匹配现象文件存在但加载失败、Exec format error原因32 位 / 64 位、ARM/x86 架构不兼容arm64-v8a so 不能在 32 位 ARM 设备运行x86 so 不能在真机 ARM 上运行3. 符号未导出JNI 常见现象dlsym找不到函数Java JNI 报UnsatisfiedLinkError原因C/C 函数没加extern CC 名字会被篡改名字改编编译脚本CMake/Android.mk未指定导出符号4. 版本冲突系统已有同名但版本不同的 so导致符号冲突、崩溃。七、Android 端补充开发重点编译工具旧版Android.mk主流CMake NDK将 C/C 源码编译为对应架构.so调用流程Java (JNI) → 加载 so → 调用 C/C 函数安全相关so 属于原生二进制可被IDA、Ghidra逆向分析加固手段加壳、混淆、字符串加密、ollvm 控制流平坦化八、总结.soLinux/Android 动态共享库对应 Windows.dllELF 二进制格式。优势体积小、易更新、多程序共享是 Linux 生态的基础组件。两大核心场景Linux C/C 服务、Android NDK 原生开发。日常排错重点依赖缺失、架构不匹配、符号未导出、库路径问题。
详细介绍 .so 文件(Linux 动态链接库)
发布时间:2026/6/9 10:09:05
目录一、基础概念1. 全称与作用2. 动态库 vs 静态库.so vs .a二、文件结构与格式三、常见使用场景1. Linux 服务 / 程序2. Android 开发最常接触场景3. 嵌入式 Linux四、核心工作原理动态链接两种加载方式五、常用命令Linux/Android adb 调试 so1. 查看依赖库2. 查看内部符号函数 / 变量3. 查看 ELF 段、架构、信息4. 瘦身 / 去除调试符号发布常用5. Android 专用adb六、常见问题与坑1. error while loading shared libraries: xxx.so: cannot open shared object file2. 架构不匹配3. 符号未导出JNI 常见4. 版本冲突七、Android 端补充开发重点八、总结.so是Linux/Android/Unix 系统下的动态共享库文件Shared Object对应 Windows 的.dll、macOS 的.dylib是二进制可执行文件存放编译后的代码、函数、变量、资源。一、基础概念1. 全称与作用全称Shared Object共享目标文件核心特点运行时动态加载、多个程序共享一份库代码区别于.a静态库编译时打包进程序。后缀惯例标准libxxx.soLinux 库命名规范前缀lib带版本libxxx.so.1.2.3主版本。次版本。修订版通常用软链接指向最新版2. 动态库 vs 静态库.so vs .a特性.so 动态库.a 静态库链接时机程序运行时加载编译链接阶段打包进可执行文件体积可执行文件小库单独存在可执行文件体积大占用空间多程序共用一份省磁盘 / 内存每个程序都拷贝一份冗余大更新方式替换 .so 文件即可无需重新编译主程序必须重新编译链接整个程序依赖运行环境必须存在对应 .so无外部库依赖独立运行二、文件结构与格式.so本质是ELF 格式文件Executable and Linkable FormatLinux 下所有可执行、库文件基本都是 ELF。 主要分段Section.text编译后的机器指令函数代码只读.data已初始化全局变量.bss未初始化全局变量不占文件空间运行时分配内存.rodata只读常量字符串、const 变量.symtab / .dynsym符号表函数名、变量名供链接 / 调用.dynstr动态符号字符串表.rel重定位段动态链接时修正内存地址关键动态符号表 (.dynsym)是外部程序调用库函数的核心被strip瘦身的 so 会丢失调试符号但保留动态调用符号。三、常见使用场景1. Linux 服务 / 程序系统底层、第三方组件、中间件大量使用.soC/C 程序依赖系统库libc.so标准 C 库、libpthread.so线程库Nginx、MySQL、Redis 等都会加载各类动态库2. Android 开发最常接触场景Android 基于 Linux 内核Native 层完全使用 .so架构区分不同 CPU 架构不能通用armeabi-v7a32 位 ARM 老设备arm64-v8a64 位 ARM 主流安卓机x86/x86_64模拟器、Intel 平板用途JNI 调用Java ↔ C/C把 C 代码编译成 so 给 App 调用音视频FFmpeg、OpenCV、加解密、渲染、逆向、插件等核心能力代码保护so 是二进制反编译难度远高于 Java 字节码3. 嵌入式 Linux路由器、机顶盒、工控机、物联网设备普遍依赖.so库。四、核心工作原理动态链接编译阶段主程序只记录「需要调用哪个 so 的哪个函数」不拷贝代码只留符号引用。运行阶段OS 的动态链接器 ld-linux.so工作加载可执行文件到内存根据依赖列表查找并加载对应.so到进程地址空间重定位修正函数内存地址完成符号绑定多个进程可共享同一份 so 内存副本仅数据段私有两种加载方式隐式加载编译链接时指定依赖编译程序时-lxxx链接 so程序启动自动加载最常用。显式加载运行时手动加载代码中主动调用 API 加载、卸载 soLinux/Android Cdlopen()→dlsym()→dlclose()适用插件化、动态按需加载、版本热更新五、常用命令Linux/Android adb 调试 so1. 查看依赖库ldd 可执行文件/xxx.so # 作用列出当前 so/程序 依赖的所有 .so排查 找不到库 问题2. 查看内部符号函数 / 变量# 查看所有符号含调试符号 nm xxx.so # 只看动态导出符号外部可调用的函数重点 nm -D xxx.so3. 查看 ELF 段、架构、信息# 查看文件架构、类型、位数 file xxx.so # 详细 ELF 信息 readelf -h xxx.so # 查看所有段 readelf -S xxx.so4. 瘦身 / 去除调试符号发布常用strip xxx.so # 作用删除调试符号、注释大幅减小文件体积不影响正常调用5. Android 专用adb# 进入手机 shell adb shell # 查看进程加载的所有 so cat /proc/[PID]/maps六、常见问题与坑1.error while loading shared libraries: xxx.so: cannot open shared object file原因系统找不到依赖的 so解决把 so 放到系统库路径/lib、/usr/lib配置环境变量export LD_LIBRARY_PATH/你的so目录:$LD_LIBRARY_PATH更新系统库缓存ldconfig2. 架构不匹配现象文件存在但加载失败、Exec format error原因32 位 / 64 位、ARM/x86 架构不兼容arm64-v8a so 不能在 32 位 ARM 设备运行x86 so 不能在真机 ARM 上运行3. 符号未导出JNI 常见现象dlsym找不到函数Java JNI 报UnsatisfiedLinkError原因C/C 函数没加extern CC 名字会被篡改名字改编编译脚本CMake/Android.mk未指定导出符号4. 版本冲突系统已有同名但版本不同的 so导致符号冲突、崩溃。七、Android 端补充开发重点编译工具旧版Android.mk主流CMake NDK将 C/C 源码编译为对应架构.so调用流程Java (JNI) → 加载 so → 调用 C/C 函数安全相关so 属于原生二进制可被IDA、Ghidra逆向分析加固手段加壳、混淆、字符串加密、ollvm 控制流平坦化八、总结.soLinux/Android 动态共享库对应 Windows.dllELF 二进制格式。优势体积小、易更新、多程序共享是 Linux 生态的基础组件。两大核心场景Linux C/C 服务、Android NDK 原生开发。日常排错重点依赖缺失、架构不匹配、符号未导出、库路径问题。