动态库与静态库

请下载下列示例程序:

构建静态库:

gcc -o mylib.o -c mylib.c
# 要构建静态库,请使用归档器 (`ar`):
ar -rcs libmylib.a mylib.o

构建动态库:

gcc -fPIC -o mylib.o -c mylib.c
gcc -shared -o libmylib.so mylib.o

linux 混合使用动态库与静态库

如果混合使用静态库和静态库. 动态库使用 -lxxx (也就是libxxx.so文件), 静态库直接将 .o 或者 .a 文件放在命令选项中.

gcc myprog.c -L. -Wl,-Bdynamic -lc libmylib.a 
gcc myprog.c -L. -Wl,-Bdynamic -lc -l:libmylib.a

目前, 在 ubuntu 22.04 上, -Bstatic 似乎无法被 ld 执行, 缺少 -lgcc_s 动态库.

$ gcc myprog.c -L. -Wl,-Bdynamic -lc -Wl,-Bstatic -lmylib 
/usr/bin/ld: 找不到 -lgcc_s: 没有那个文件或目录
/usr/bin/ld: 找不到 -lgcc_s: 没有那个文件或目录
collect2: error: ld returned 1 exit status

$ gcc myprog.c -L. -Wl,-Bstatic -lmylib 
/usr/bin/ld: 找不到 -lgcc_s: 没有那个文件或目录
/usr/bin/ld: 找不到 -lgcc_s: 没有那个文件或目录
collect2: error: ld returned 1 exit status

混合动态库与静态库:

  • 方法1: -l 默认优先链接动态库, 如果要链接静态库,请指定 -l:libxxx.a 即可. 或者直接在命令行使用 libxxx.a 文件即可.
  • 方法2: 使用-Wl,-Bstatic -lxxx 链接静态库
gcc ... -Wl,-Bstatic -lfirst -Wl,-Bdynamic -lsecond ...
这个命令使用静态链接链接 first 库, 使用动态链接链接 second 库.
$ gcc myprog.c -L. -Wl,-Bstatic -lmylib
$ ldd a.out 
        linux-vdso.so.1 (0x00007ffca859d000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x0000717456000000)
        /lib64/ld-linux-x86-64.so.2 (0x0000717456420000)
$ ./a.out 
Enter two float values: 1
2
1.000000 and 2.000000
2.000000 is the biggest

windows 混合使用动态库与静态库

windows上可以运行:

$ gcc myprog.c -L. -l:libmylib.a
$ gcc myprog.c -L. -Wl,-Bstatic -l:libmylib.a
$ gcc myprog.c -L. -Wl,-Bstatic -lmylib
$ gcc myprog.c -L. -lmylib

$ ./myprog.out 
Enter two float values: 1
2
1.000000 and 2.000000
2.000000 is the biggest

这个windows上无法执行.

$ gcc myprog.c -lc -L. -l:libmylib.a
$ ldd a.out 
        linux-vdso.so.1 (0x00007ffca859d000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x0000717456000000)
        /lib64/ld-linux-x86-64.so.2 (0x0000717456420000)
$ ./a.out 
Enter two float values: 1
2
1.000000 and 2.000000
2.000000 is the biggest

完全静态链接

将整个可执行文件静态编译:

$ gcc myprog.c -lmylib -L. -static
$ ldd a.out 
        不是动态可执行文件
$ readelf -d a.out 

There is no dynamic section in this file.

$ ./a.out 
Enter two float values: 1
2
1.000000 and 2.000000
2.000000 is the biggest

python wheel musl

manylinux 支持新的 musl libc.

PEP 656 – Platform Tag for Linux Distributions Using Musl
Wheels for musl (Alpine)

gcc && ld

gcc docs
GNU linker ld (GNU Binutils)

ELF

ELF: From The Programmer's Perspective
hacker news ELF: From The Programmer's Perspective
Notes on the Flat-Text Transcription
ELF_Format

A Whirlwind Tutorial on Creating Really Teensy ELF Executables for Linux
“Shared libraries are not a good thing in general”

静态库与动态库

pdf: Red Hat Enterprise Linux 7 Developer Guide
html: Red Hat Enterprise Linux 7 Developer Guide 可以翻译这个文档: Program Library HOWTO

符号链接

GCC 共享库 - 强制导入依赖库中的符号
Use of shared library is good in c but same code is bad in c++?

gcc -fPIC

静态库, 动态库与 -fPIC 编译细节探索:

$ gcc -o mylib.o -c mylib.c
$ ar -rcs libmylib.a mylib.o
$ gcc myprog.c -lmylib -L.
$ ./a.out 
Enter two float values: 1
2
1.000000 and 2.000000
2.000000 is the biggest

静态库使用 -fPIC 也可以运行, 有什么区别?

$ gcc -fPIC -o mylib.o -c mylib.c
$ ar -rcs libmylib.a mylib.o
$ gcc myprog.c  -lmylib -L.
$ ./a.out 
Enter two float values: 1
2
1.000000 and 2.000000
2.000000 is the biggest

编译动态库不使用 -fPIC 会有明确的错误提示:

$ gcc -o mylib.o -c mylib.c
$ gcc -shared -o libmylib.so mylib.o
/usr/bin/ld: mylib.o: warning: relocation against `total_times' in read-only section `.text'
/usr/bin/ld: mylib.o: relocation R_X86_64_PC32 against symbol `total_times' can not be used when making a shared object; recompile with -fPIC
/usr/bin/ld: final link failed: bad value
collect2: error: ld returned 1 exit status

动态库的正确使用模式:

$ gcc -fPIC -o mylib.o -c mylib.c
$ gcc -shared -o libmylib.so mylib.o

libc

C_standard_library Implementations
Writing C software without the standard library
forcing-elf-binary-to-use-another-libc-so
Multiple glibc libraries on a single host
how-to-run-new-software-without-updating-glibc
how-to-chroot-to-provide-a-new-glibc-version-to-an-app
glibc-improvements-and-what-to-expect-in-future-linux-distributions
https://news.ycombinator.com/item?id=29479769

glibc

Working with glibc

glibc backward compatibility

how-the-gnu-c-library-handles-backward-compatibility how-compatible-are-different-versions-of-glibc ABI_checker Creating and using chroots and containers

Dynamically load library from chroot with glibc dependency

chroot

通过 chroot 重新设置 root 密码

obtain libc version

ldd

root@ub18:~# ldd --version  | head -n1
ldd (Ubuntu GLIBC 2.27-3ubuntu1.6) 2.27

features.h

GCC_FEATURES=$(gcc -dM -E - <<< "#include <features.h>")

if grep -q __UCLIBC__ <<< "${GCC_FEATURES}"; then
    echo "uClibc"
    grep "#define __UCLIBC_MAJOR__" <<< "${GCC_FEATURES}"
    grep "#define __UCLIBC_MINOR__" <<< "${GCC_FEATURES}"
    grep "#define __UCLIBC_SUBLEVEL__" <<< "${GCC_FEATURES}"
elif grep -q __GLIBC__ <<< "${GCC_FEATURES}"; then
    echo "glibc"
    grep "#define __GLIBC__" <<< "${GCC_FEATURES}"
    grep "#define __GLIBC_MINOR__" <<< "${GCC_FEATURES}"
else
    echo "something else"
fi

/lib/x86_64-linux-gnu/libc.so.6

/lib/x86_64-linux-gnu/libc.so.6

How to update libc version on major Linux distros

In case you find your installed libc to be out of date, it is simple enough to bring it up to date on any Linux system. You can use the appropriate command below to update libc with your system’s package manager. To update libc on UbuntuDebian, and Linux Mint:

$ sudo apt update
$ sudo apt install libc-bin

To update libc on FedoraCentOSAlmaLinux, and Red Hat:

$ sudo dnf install glibc

To update libc on Arch Linux and Manjaro:

$ sudo pacman -Syu glibc

How can I specify the GLIBC version in cargo build for Rust?

static_linking_with_nim

glibc heap

Arm Heap Exploitation

UNDERSTANDING THE GLIBC HEAP IMPLEMENTATION

asm

x86_64

System Calls On x86_64 from User Space

编译链接参考资料

https://tldp.org/HOWTO/Program-Library-HOWTO/shared-libraries.html
https://www.akkadia.org/drepper/dsohowto.pdf

-fPIC

Why does gcc not implicitly supply the -fPIC flag when compiling static libraries on x86_64
What, if any, are the implications of compiling objects with gcc -fPIC flag if they get used in executables?
Is -fPIC implied on modern platforms
Is -fPIC for shared libraries ONLY?

Does one still need to use -fPIC when compiling with GCC?
What does -fPIC mean when building a shared library?
What is the -fPIE option for position-independent executables in gcc and ld?
How can I tell, with something like objdump, if an object file has been built with -fPIC?

https://stackoverflow.com/questions/1340402/how-can-i-tell-with-something-like-objdump-if-an-object-file-has-been-built-wi

runpath

https://ziggit.dev/t/why-zig-adds-dynamic-library-path-into-final-executable/4688