linkers-lto

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Linkers and LTO

链接器与LTO

Purpose

用途

Guide agents through linker selection, common linker flags, link-order issues, LTO setup, and symbol-visibility management.
指导开发者完成链接器选择、常用链接器参数配置、链接顺序问题排查、LTO设置以及符号可见性管理。

Triggers

触发场景

  • "I'm getting
    undefined reference
    at link time"
  • "How do I enable LTO for a real project?"
  • "Which linker should I use: ld, gold, or lld?"
  • "How do I reduce binary size with
    --gc-sections
    ?"
  • "How do I write or understand a linker script?"
  • "I have duplicate symbol or weak symbol issues"
  • "我在链接时遇到了
    undefined reference
    错误"
  • "如何在实际项目中启用LTO?"
  • "应该使用哪个链接器:ld、gold还是lld?"
  • "如何通过
    --gc-sections
    减小二进制文件大小?"
  • "如何编写或理解链接器脚本?"
  • "我遇到了重复符号或弱符号问题"

Workflow

操作流程

1. Linker selection

1. 链接器选择

LinkerInvocationStrengths
GNU ld (BFD)default on LinuxUniversal, stable
gold
-fuse-ld=gold
Faster than ld for C++; supports LTO plugins
lld (LLVM)
-fuse-ld=lld
Fastest, parallel, required for Clang LTO
bash
undefined
链接器调用方式优势
GNU ld (BFD)Linux默认链接器通用、稳定
gold
-fuse-ld=gold
比ld处理C++时更快;支持LTO插件
lld (LLVM)
-fuse-ld=lld
速度最快、支持并行处理;Clang LTO必需
bash
undefined

Use lld with GCC or Clang

Use lld with GCC or Clang

gcc -fuse-ld=lld -o prog ... clang -fuse-ld=lld -o prog ...
gcc -fuse-ld=lld -o prog ... clang -fuse-ld=lld -o prog ...

Check which linker is used

Check which linker is used

gcc -v -o prog main.c 2>&1 | grep 'Invoking'
undefined
gcc -v -o prog main.c 2>&1 | grep 'Invoking'
undefined

2. Essential linker flags

2. 核心链接器参数

bash
undefined
bash
undefined

Pass linker flags via compiler driver:

通过编译器驱动传递链接器参数:

-Wl,flag1,flag2 (comma-separated, no spaces)

-Wl,flag1,flag2 (逗号分隔,无空格)

-Wl,flag1 -Wl,flag2 (separate -Wl options)

-Wl,flag1 -Wl,flag2 (分开的-Wl选项)

gcc main.c -o prog
-Wl,-rpath,/opt/mylibs/lib \ # runtime library search path -Wl,--as-needed \ # only link libraries that are actually used -Wl,--gc-sections \ # remove unused sections (requires -ffunction-sections -fdata-sections) -Wl,-z,relro \ # mark relocations read-only after startup -Wl,-z,now \ # resolve all symbols at startup (full RELRO) -L/opt/mylibs/lib -lfoo
undefined
gcc main.c -o prog
-Wl,-rpath,/opt/mylibs/lib \ # 运行时库搜索路径 -Wl,--as-needed \ # 仅链接实际用到的库 -Wl,--gc-sections \ # 移除未使用的段(需配合-ffunction-sections -fdata-sections) -Wl,-z,relro \ # 启动后将重定位标记为只读 -Wl,-z,now \ # 启动时解析所有符号(完全RELRO) -L/opt/mylibs/lib -lfoo
undefined

3. Link order matters (GNU ld)

3. 链接顺序很重要(GNU ld)

GNU ld processes archives left-to-right. A library must come after the objects that need it.
bash
undefined
GNU ld按从左到右的顺序处理归档文件。库必须放在需要它的目标文件之后。
bash
undefined

Wrong: libfoo provides symbols needed by main.o

错误:libfoo提供了main.o需要的符号

gcc main.o -lfoo libdep.a -o prog # can fail if libdep.a needs libfoo
gcc main.o -lfoo libdep.a -o prog # 如果libdep.a依赖libfoo,可能会失败

Correct: dependencies after dependents

正确:依赖项放在被依赖项之后

gcc main.o -lfoo -ldep -o prog
gcc main.o -lfoo -ldep -o prog

If there are circular deps between archives:

如果归档文件之间存在循环依赖:

gcc main.o -Wl,--start-group -lfoo -lbar -Wl,--end-group -o prog
gcc main.o -Wl,--start-group -lfoo -lbar -Wl,--end-group -o prog

--start-group/--end-group: repeat search until no new symbols resolved

--start-group/--end-group:重复搜索直到没有新符号被解析

undefined
undefined

4. LTO with GCC

4. GCC下的LTO

bash
undefined
bash
undefined

Compile

编译

gcc -O2 -flto -ffunction-sections -fdata-sections -c foo.c -o foo.o gcc -O2 -flto -ffunction-sections -fdata-sections -c bar.c -o bar.o
gcc -O2 -flto -ffunction-sections -fdata-sections -c foo.c -o foo.o gcc -O2 -flto -ffunction-sections -fdata-sections -c bar.c -o bar.o

Link (must pass -flto again)

链接(必须再次传递-flto)

gcc -O2 -flto -Wl,--gc-sections foo.o bar.o -o prog
gcc -O2 -flto -Wl,--gc-sections foo.o bar.o -o prog

Archives: must use gcc-ar / gcc-ranlib, not plain ar

归档文件:必须使用gcc-ar / gcc-ranlib,而非普通的ar

gcc-ar rcs libfoo.a foo.o gcc-ranlib libfoo.a

Parallel LTO:

```bash
gcc -O2 -flto=auto foo.o bar.o -o prog   # uses jobserver
gcc -O2 -flto=4   foo.o bar.o -o prog    # 4 parallel jobs
gcc-ar rcs libfoo.a foo.o gcc-ranlib libfoo.a

并行LTO:

```bash
gcc -O2 -flto=auto foo.o bar.o -o prog   # 使用jobserver
gcc -O2 -flto=4   foo.o bar.o -o prog    # 4个并行任务

5. LTO with Clang / lld

5. Clang / lld下的LTO

bash
undefined
bash
undefined

Full LTO

完整LTO

clang -O2 -flto -fuse-ld=lld foo.c bar.c -o prog
clang -O2 -flto -fuse-ld=lld foo.c bar.c -o prog

ThinLTO (faster, nearly same quality)

ThinLTO(更快,质量几乎相同)

clang -O2 -flto=thin -fuse-ld=lld foo.c bar.c -o prog
clang -O2 -flto=thin -fuse-ld=lld foo.c bar.c -o prog

LTO with cmake: set globally

CMake中启用LTO:全局设置

set(CMAKE_INTERPROCEDURAL_OPTIMIZATION ON) # enables -flto

ThinLTO caches work: subsequent builds that reuse unchanged modules are faster.
Cache location: specify with `-Wl,--thinlto-cache-dir=/tmp/thinlto-cache`.
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION ON) # 启用-flto

ThinLTO会缓存工作成果:后续构建中复用未修改的模块时速度更快。
缓存位置:通过`-Wl,--thinlto-cache-dir=/tmp/thinlto-cache`指定。

6. Dead-code stripping

6. 死代码剥离

bash
undefined
bash
undefined

Compile with per-function/per-data sections

按函数/数据段编译

gcc -O2 -ffunction-sections -fdata-sections -c foo.c -o foo.o
gcc -O2 -ffunction-sections -fdata-sections -c foo.c -o foo.o

Link with garbage collection

链接时启用垃圾回收

gcc -Wl,--gc-sections foo.o -o prog
gcc -Wl,--gc-sections foo.o -o prog

Verify what was removed

验证哪些内容被移除

gcc -Wl,--gc-sections -Wl,--print-gc-sections foo.o -o prog 2>&1 | head -20

On macOS, the linker strips dead code by default (`-dead_strip`).
gcc -Wl,--gc-sections -Wl,--print-gc-sections foo.o -o prog 2>&1 | head -20

在macOS上,链接器默认会剥离死代码(`-dead_strip`)。

7. Symbol visibility

7. 符号可见性

Controlling visibility reduces DSO size and enables better LTO:
bash
undefined
控制符号可见性可以减小DSO大小并提升LTO效果:
bash
undefined

Hide all symbols by default, export explicitly

默认隐藏所有符号,显式导出指定符号

gcc -fvisibility=hidden -O2 -shared -fPIC foo.c -o libfoo.so
gcc -fvisibility=hidden -O2 -shared -fPIC foo.c -o libfoo.so

In source, mark exports:

在源码中标记导出符号:

attribute((visibility("default"))) int my_public_function(void);

Or use a version script:

```text
attribute((visibility("default"))) int my_public_function(void);

也可以使用版本脚本:

```text

foo.ver

foo.ver

{ global: my_public_function; my_other_public; local: *; };

```bash
gcc -Wl,--version-script=foo.ver -shared -fPIC -o libfoo.so foo.o
{ global: my_public_function; my_other_public; local: *; };

```bash
gcc -Wl,--version-script=foo.ver -shared -fPIC -o libfoo.so foo.o

8. Common linker errors

8. 常见链接器错误

ErrorCauseFix
undefined reference to 'foo'
Missing library or wrong orderAdd
-lfoo
; move after the object that needs it
multiple definition of 'foo'
Symbol defined in two TUsRemove duplicate; use
static
or
extern
cannot find -lfoo
Library not in search pathAdd
-L/path/to/lib
; install dev package
relocation truncated
Address overflow in relocationUse
-mcmodel=large
; restructure image
version 'GLIBC_2.33' not found
Binary needs newer glibcLink statically or rebuild on older host
circular reference
Archives mutually dependUse
--start-group
/
--end-group
错误原因解决方法
undefined reference to 'foo'
缺少库或链接顺序错误添加
-lfoo
;将库移至需要它的目标文件之后
multiple definition of 'foo'
符号在两个翻译单元中定义移除重复定义;使用
static
extern
cannot find -lfoo
库不在搜索路径中添加
-L/path/to/lib
;安装开发包
relocation truncated
重定位时地址溢出使用
-mcmodel=large
;调整镜像结构
version 'GLIBC_2.33' not found
二进制文件需要更新版本的glibc静态链接或在旧版本主机上重新构建
circular reference
归档文件之间相互依赖使用
--start-group
/
--end-group

9. Linker map file

9. 链接器映射文件

bash
undefined
bash
undefined

Generate a map file (shows symbol → section → file)

生成映射文件(显示符号→段→文件的对应关系)

gcc -Wl,-Map=prog.map -o prog foo.o bar.o less prog.map

Useful for debugging binary size and symbol placement.

For a comprehensive linker and LTO flags reference, see [references/flags.md](references/flags.md).
gcc -Wl,-Map=prog.map -o prog foo.o bar.o less prog.map

映射文件可用于调试二进制文件大小和符号位置。

关于链接器和LTO参数的完整参考,请查看[references/flags.md](references/flags.md)。

Related skills

相关技能

  • Use
    skills/binaries/elf-inspection
    for examining the resulting binary
  • Use
    skills/compilers/gcc
    or
    skills/compilers/clang
    for compile-phase LTO flags
  • Use
    skills/binaries/binutils
    for
    ar
    ,
    strip
    ,
    objcopy
  • 使用
    skills/binaries/elf-inspection
    检查生成的二进制文件
  • 使用
    skills/compilers/gcc
    skills/compilers/clang
    获取编译阶段的LTO参数
  • 使用
    skills/binaries/binutils
    操作
    ar
    strip
    objcopy