Chương 41 · Nền tảng thư viện dùng chung Chapter 41 · Fundamentals of Shared Libraries
Một bản mã, chia sẻ cho mọi chương trình — giải phẫu thư viện dùng chung Một bản mã dùng chung cho nhiều chương trình One copy of the code, shared by every program — the anatomy of shared libraries
Kerrisk mở đầu bằng thư viện đối tượng (object library) — một tập hợp các mô-đun đối tượng đã biên dịch, gom lại thành một đơn vị để nhiều chương trình liên kết tới. Linux có hai loại: thư viện tĩnh (static library, hay archive, tên dạng libname.a) và thư viện dùng chung (shared library, tên dạng libname.so).1 Chương đi qua: vì sao thư viện tĩnh lãng phí; ý tưởng cốt lõi của thư viện dùng chung; cách tạo và dùng nó (mã độc lập vị trí với -fPIC, dựng bằng cc -shared, liên kết với -l/-L, cách tìm thư viện lúc chạy); soname cùng tên thật và tên liên kết; cài đặt và chạy ldconfig; biến LD_LIBRARY_PATH với trình liên kết động ld.so; và các công cụ ldd, objdump, readelf, nm.1
Hãy hình dung một công thức nấu ăn mà nhiều đầu bếp cùng cần. Thay vì ai cũng chép lại cả cuốn vào sổ của mình (tốn giấy, khó sửa), ta treo một tấm bảng công thức chung giữa bếp để mọi người cùng nhìn. Thư viện dùng chung là tấm bảng ấy: một bản mã nằm trong bộ nhớ, mọi chương trình cùng dùng. Nhớ nhé: thư viện dùng chung là một bản mã treo chung cho nhiều chương trình.
Kerrisk opens with the object library — a collection of compiled object modules gathered into one unit that many programs can link against. Linux provides two types: the static library (or archive, named libname.a) and the shared library (named libname.so).1 The chapter covers: why static libraries are wasteful; the core idea of a shared library; how to create and use one (position-independent code with -fPIC, building with cc -shared, linking with -l/-L, the run-time search); the soname together with the real name and the linker name; installing and running ldconfig; the LD_LIBRARY_PATH variable and the dynamic linker ld.so; and the tools ldd, objdump, readelf, and nm.1
Điểm mấu chốt để cả chương sáng tỏ: khi liên kết với thư viện tĩnh, bản sao các mô-đun đối tượng được chép thẳng vào tệp thực thi; khi liên kết với thư viện dùng chung, tệp thực thi chỉ ghi lại tên thư viện nó cần (thẻ DT_NEEDED trong ELF), còn một bản duy nhất của thư viện được trình liên kết động nạp vào bộ nhớ lúc chạy, khi chương trình đầu tiên cần tới nó khởi động.16The hinge that makes the whole chapter cohere: linking against a static library copies the object modules straight into the executable; linking against a shared library records only the name of the library the executable needs (the DT_NEEDED tag in ELF), while a single copy of the library is loaded into memory at run time by the dynamic linker, when the first program needing it starts.16
Luận đề của chương: một thư viện dùng chung tách mã khỏi tệp thực thi — thay vì chép mã vào từng chương trình, ta để một bản duy nhất trong bộ nhớ và cho mọi chương trình dùng chung lúc chạy. Hiểu được -fPIC, bộ ba tên (tên thật / soname / tên liên kết), cách ld.so tìm thư viện, và vai trò của ldconfig — là nắm được cơ chế liên kết động làm nền cho gần như mọi phần mềm Linux hiện đại.1
Ý chính: đừng chép mã vào từng chương trình; hãy để một bản dùng chung và cho mọi chương trình mượn lúc chạy. Vừa tiết kiệm đĩa và bộ nhớ, vừa dễ vá lỗi. Nhớ nhé: một bản mã, nhiều người dùng, sửa một chỗ là xong.
The chapter's thesis: a shared library separates the code from the executable — instead of copying code into each program, a single copy lives in memory and every program shares it at run time. Grasping -fPIC, the triad of names (real name / soname / linker name), how ld.so finds libraries, and the role of ldconfig — is grasping the dynamic-linking machinery that underpins nearly all modern Linux software.1
Cụm khái niệm 03 Concept cluster 03
Một thư viện, ba cái tên: tên thật, soname, và tên liên kết Một thư viện có ba cái tên khác nhau One library, three names: real name, soname, and linker name
Cơ chế đặt tên theo quy ước là phần tinh tế nhất của chương. Một thư viện dùng chung có thể mang một bí danh gọi là soname (thẻ DT_SONAME trong ELF). Khi thư viện có soname, lúc liên kết tĩnh chính soname — chứ không phải tên tệp thật — được nhúng vào tệp thực thi, rồi dùng để tìm thư viện lúc chạy. Soname tạo một lớp gián tiếp: tệp thực thi gắn với soname, còn soname lại là một liên kết tượng trưng trỏ tới tên tệp thật hiện hành.16
Đây là phần tinh tế nhất. Một thư viện có thể có một "biệt danh" (soname). Khi dựng chương trình, ta ghi vào chương trình cái biệt danh ấy, chứ không ghi tên tệp cụ thể. Lúc chạy, biệt danh đó chỉ đường tới tệp thật đang dùng. Nhớ nhé: chương trình nhớ biệt danh, biệt danh chỉ tới tệp thật.
The conventional naming scheme is the subtlest part of the chapter. A shared library may carry an alias called a soname (the DT_SONAME tag in ELF). When a library has a soname, at static-link time the soname — not the real filename — is embedded in the executable, then used to find the library at run time. The soname provides a level of indirection: the executable binds to the soname, while the soname is itself a symbolic link pointing to the current real filename.16
Định nghĩa. Theo quy ước phiên bản: tên thật (real name) có dạng libname.so.major.minor — tệp chứa mã, mỗi phiên bản major+minor một bản. Soname có dạng libname.so.major — mỗi major một bản, nhúng vào tệp thực thi, và là liên kết trỏ tới tên thật mới nhất. Tên liên kết (linker name) có dạng libname.so — không số phiên bản, dùng khi liên kết, là liên kết trỏ tới tên thật hoặc (thường hơn) tới soname mới nhất.1
Nói đơn giản. Ba cái tên: tên thật có đủ số (libfoo.so.1.0.1) là tệp mã thật; soname chỉ có số lớn (libfoo.so.1) là biệt danh theo phiên bản lớn; tên liên kết không có số (libfoo.so) dùng lúc dựng chương trình. Nhớ nhé: càng nhiều số thì càng cụ thể, không số thì để dựng.
Definition. By the versioning convention: the real name has the form libname.so.major.minor — the file holding the code, one per major+minor version. The soname has the form libname.so.major — one per major version, embedded in the executable, and a symbolic link pointing to the latest real name. The linker name has the form libname.so — no version numbers, used when linking, a link to the real name or (more usually) the latest soname.1
# dựng với soname
$ gcc -g -shared -Wl,-soname,libdemo.so.1 \
-o libdemo.so.1.0.1 mod1.o mod2.o mod3.o
# chuỗi liên kết tượng trưng
$ ln -s libdemo.so.1.0.1 libdemo.so.1 # soname
$ ln -s libdemo.so.1 libdemo.so # linker
$ gcc -g -o prog prog.c -L. -ldemo
libdemo.so --> libdemo.so.1
libdemo.so.1 --> libdemo.so.1.0.1
libdemo.so.1.0.1 (tệp mã thật)
# build with a soname
$ gcc -g -shared -Wl,-soname,libdemo.so.1 \
-o libdemo.so.1.0.1 mod1.o mod2.o mod3.o
# the symbolic-link chain
$ ln -s libdemo.so.1.0.1 libdemo.so.1 # soname
$ ln -s libdemo.so.1 libdemo.so # linker
$ gcc -g -o prog prog.c -L. -ldemo
-
-Wl,-soname
Gắn soname lúc dựng, kiểm tra bằng objdump/readelf Đặt biệt danh cho thư viện khi dựng Set the soname at build, check with objdump/readelf
Để gắn soname, truyền tùy chọn
-Wl,-soname,libbar.so— một chỉ thị cho trình liên kếtldđánh dấu thư viện với soname đó. Có thể đọc soname của một thư viện có sẵn bằngobjdump -p libfoo.so | grep SONAMEhoặcreadelf -d libfoo.so | grep SONAME.151011Khi dựng, thêm
-Wl,-soname,...để đặt biệt danh cho thư viện. Muốn xem biệt danh của một thư viện có sẵn, dùngobjdump -phayreadelf -drồi tìm dòng SONAME. Nhớ nhé: -Wl,-soname để đặt, grep SONAME để xem.To set a soname, pass the option
-Wl,-soname,libbar.so— an instruction to the linkerldto mark the library with that soname. You can read an existing library's soname withobjdump -p libfoo.so | grep SONAMEorreadelf -d libfoo.so | grep SONAME.151011Bạn gặp nó ở đâuWhere you meet it Khi dùng soname, cần thêm một bước: tạo liên kết tượng trưng từ soname tới tên thật, nếu không trình liên kết động sẽ không tìm thấy thư viện lúc chạy.1 Dùng soname thì phải tạo một liên kết trỏ từ biệt danh sang tệp thật, nếu không lúc chạy sẽ không tìm được. When using a soname, one more step is required: create a symbolic link from the soname to the real name, or the dynamic linker will not find the library at run time.1 -
real / soname / linker
Chuỗi liên kết: tên liên kết → soname → tên thật Dây chuyền: tên không số → biệt danh → tệp thật The chain: linker name → soname → real name
Ba cái tên được xâu thành một chuỗi liên kết tượng trưng: tên liên kết
libdemo.sotrỏ tới sonamelibdemo.so.1, soname trỏ tới tên thậtlibdemo.so.1.0.1. Nhờ tên liên kết (không số phiên bản), lệnh liên kết trở nên độc lập phiên bản:gcc -o prog prog.c -L. -ldemokhông hề nhắc tới số phiên bản.1Ba cái tên móc nối nhau như dây chuyền: tên không số chỉ tới biệt danh, biệt danh chỉ tới tệp thật. Nhờ vậy khi dựng chương trình ta chỉ cần gọi
-ldemo, không phải nhớ số phiên bản. Nhớ nhé: dây chuyền tên giúp dựng mà khỏi lo số phiên bản.The three names form a chain of symbolic links: the linker name
libdemo.sopoints to the sonamelibdemo.so.1, which points to the real namelibdemo.so.1.0.1. Thanks to the linker name (no version numbers), the link command becomes version-independent:gcc -o prog prog.c -L. -ldemomentions no version number.1Bạn gặp nó ở đâuWhere you meet it Chạyls -l libdemo.so*trên một máy Linux: bạn sẽ thấy đúng chuỗi này — hai liên kết tượng trưng và một tệp thật, ví dụlibreadline.so -> libreadline.so.5.1 Gõls -ltrong thư mục thư viện, bạn sẽ thấy các mũi tên nối tên này sang tên kia — đó chính là dây chuyền. Runls -l libdemo.so*on a Linux box: you will see exactly this chain — two symbolic links and one real file, e.g.libreadline.so -> libreadline.so.5.1Vì sao tên liên kết nên trỏ tới sonameWhy the linker name should point at the soname
Tên liên kết thường được tạo trong cùng thư mục với tệp nó trỏ tới, và nên trỏ tới soname (chứ không phải thẳng tên thật), để khi soname đổi thì tên liên kết tự động phản ánh theo — một việc mà
ldconfigtự lo nếu ta theo đúng quy ước.13The linker name is usually created in the same directory as the file it refers to, and should point at the soname (not straight at the real name), so that changes to the soname are automatically reflected in the linker name — a jobldconfighandles for us if we follow the convention.13Liên kết với phiên bản major cũLinking against an older major version
Nếu muốn liên kết với một phiên bản major cũ, không dùng được tên liên kết; phải chỉ rõ một tên thật hoặc soname cụ thể trong lệnh liên kết.1If you want to link against an older major version, you cannot use the linker name; you must name a specific real name or soname in the link command.1
-
compatible vs incompatible
Major đổi khi phá vỡ tương thích, minor đổi khi vẫn tương thích Số lớn đổi khi "vỡ", số nhỏ đổi khi vẫn hợp Major changes break compatibility, minor keeps it
Sơ đồ phiên bản cho phép chương trình tự động dùng phiên bản minor mới nhất của thư viện mà không cần liên kết lại, đồng thời cho nhiều phiên bản major không tương thích cùng tồn tại. Một thay đổi là tương thích (chỉ tăng minor) nếu ngữ nghĩa mọi hàm/biến công khai giữ nguyên, không xóa hàm/biến nào khỏi API công khai, và các cấu trúc công khai không đổi; ngược lại phải định nghĩa một major mới.1
Khi sửa thư viện mà không làm hỏng cách dùng cũ, chỉ tăng số nhỏ (minor). Khi sửa làm thay đổi cách dùng, phải tăng số lớn (major) và coi như một phiên bản khác hẳn. Nhớ nhé: còn dùng được như cũ thì tăng số nhỏ, không thì tăng số lớn.
The versioning scheme lets a program automatically use the latest minor version without relinking, while letting multiple incompatible major versions coexist. A change is compatible (only the minor rises) if the semantics of every public function/variable stay the same, no public function/variable is removed, and public structures are unchanged; otherwise a new major version must be defined.1
Bạn gặp nó ở đâuWhere you meet it Có thể nâng cấp lên phiên bản minor hoặc major mới ngay cả khi các chương trình đang chạy vẫn dùng phiên bản cũ; chúng chỉ chuyển sang bản mới khi được khởi động lại.1 Có thể cài phiên bản mới ngay cả khi chương trình cũ đang chạy; chương trình chỉ dùng bản mới sau khi khởi động lại. You can upgrade to a new minor or major version even while running programs use the old one; they switch to the new version only when restarted.1
Cụm khái niệm 04 Concept cluster 04
Cài đặt đúng chỗ, để ldconfig và ld.so lo phần còn lại Cài đúng chỗ, dùng ldconfig, và các công cụ soi thư viện Install in the right place, let ldconfig and ld.so do the rest
Ở các ví dụ trước, thư viện nằm trong thư mục riêng của người dùng và được tìm thấy nhờ LD_LIBRARY_PATH — tiện cho học tập nhưng không nên dùng cho ứng dụng thật. Thông thường, thư viện cùng các liên kết tượng trưng của nó được cài vào một thư mục chuẩn: /usr/lib (phần lớn thư viện chuẩn), /lib (thư viện cần lúc khởi động hệ thống), /usr/local/lib (thư viện phi chuẩn hay thử nghiệm), hoặc một thư mục liệt kê trong /etc/ld.so.conf.12 Thường cần quyền siêu người dùng để chép vào các thư mục này.1
Trước đó ta để thư viện ở thư mục riêng và dùng LD_LIBRARY_PATH để máy tìm thấy — cách này tiện để học nhưng không dùng cho sản phẩm thật. Cách đúng là chép thư viện vào các thư mục chuẩn như /usr/lib hay /lib (cần quyền quản trị). Nhớ nhé: học thì dùng LD_LIBRARY_PATH, làm thật thì cài vào thư mục chuẩn.
In earlier examples the library sat in a user-private directory and was found via LD_LIBRARY_PATH — handy for learning but not for production applications. Normally the library and its symbolic links are installed in a standard directory: /usr/lib (most standard libraries), /lib (libraries needed at system startup), /usr/local/lib (nonstandard or experimental libraries), or a directory listed in /etc/ld.so.conf.12 Copying into these directories usually requires superuser privilege.1
Định nghĩa. ldconfig(8) giải hai vấn đề của thư viện dùng chung. (1) Nó duyệt một tập thư mục chuẩn và tạo/cập nhật tệp bộ đệm /etc/ld.so.cache — danh sách các phiên bản major mới nhất — để trình liên kết động tra cứu nhanh lúc chạy. (2) Nó xét phiên bản minor mới nhất của mỗi major, đọc soname nhúng trong đó, rồi tạo/cập nhật liên kết tượng trưng cho mỗi soname trong cùng thư mục.13
Nói đơn giản. ldconfig làm hai việc: lập một danh bạ để máy tìm thư viện cho nhanh, và tự dựng/sửa các "mũi tên" soname cho đúng. Chạy nó mỗi khi cài, cập nhật hay gỡ một thư viện. Nhớ nhé: cài xong thư viện thì chạy ldconfig để máy nhận ra.
Definition. ldconfig(8) solves two problems of shared libraries. (1) It scans a standard set of directories and creates/updates the cache file /etc/ld.so.cache — a list of the latest major versions — so the dynamic linker can resolve names quickly at run time. (2) It examines the latest minor version of each major, reads the embedded soname, and creates/updates a symbolic link for each soname in the same directory.13
# cập nhật bộ đệm + soname symlinks
$ sudo ldconfig -v | grep libdemo
$ ldconfig -p # xem /etc/ld.so.cache
# tìm thư viện (cách tạm cho học)
$ LD_LIBRARY_PATH=. ./prog
# xem phụ thuộc động
$ ldd prog
ldconfig --> cập nhật danh bạ
ldconfig -p --> xem danh bạ
ldd prog --> xem thư viện cần
# update cache + soname symlinks
$ sudo ldconfig -v | grep libdemo
$ ldconfig -p # view /etc/ld.so.cache
# find the library (learning shortcut)
$ LD_LIBRARY_PATH=. ./prog
# view dynamic dependencies
$ ldd prog
-
ldconfig
ldconfig: danh bạ bộ đệm cộng với các soname symlink ldconfig lập danh bạ và dựng mũi tên soname ldconfig: the cache plus the soname symlinks
Để dựng bộ đệm,
ldconfigduyệt các thư mục trong/etc/ld.so.confrồi tới/libvà/usr/lib. Nên chạy nó mỗi khi cài, cập nhật hay gỡ thư viện, hoặc khi danh sách thư mục thay đổi. Các cờ:-vhiện chi tiết,-Nkhông dựng lại bộ đệm,-Xkhông tạo soname symlink, và-nchỉ xử lý thư mục trên dòng lệnh (hữu ích cho thư viện riêng, không chạm bộ đệm).13ldconfigđi khắp các thư mục thư viện chuẩn để cập nhật danh bạ và dựng các mũi tên soname. Nhớ chạy nó sau mỗi lần cài hay gỡ thư viện. Thêm-vđể xem nó làm gì. Nhớ nhé: cài/gỡ thư viện xong là chạy ldconfig.To build the cache,
ldconfigscans the directories in/etc/ld.so.conf, then/liband/usr/lib. Run it whenever you install, update, or remove a library, or when the directory list changes. Flags:-vfor verbose output,-Nto skip rebuilding the cache,-Xto skip creating soname symlinks, and-nto process only command-line directories (useful for a private library, leaving the cache untouched).13Bạn gặp nó ở đâuWhere you meet it Vì tên liên kết trỏ tới soname mới nhất, khi cài một bản minor 2.x mới,ldconfigcập nhật soname và nhờ đó cũng giữ tên liên kết đúng — nhưng tên liên kết cho một major mới vẫn phải tạo tay.1 Khi lên bản minor mới, ldconfig tự lo giúp; nhưng lên một phiên bản lớn mới thì bạn phải tự tạo lại mũi tên tên liên kết. Because the linker name points at the latest soname, installing a new 2.x minor letsldconfigupdate the soname and thereby keep the linker name correct too — but the linker name for a new major must still be created by hand.1 -
LD_LIBRARY_PATH / ld.so
LD_LIBRARY_PATH và thứ tự tìm kiếm của ld.so Nơi máy đi tìm thư viện lúc chạy LD_LIBRARY_PATH and ld.so's search order
Biến
LD_LIBRARY_PATHlà danh sách thư mục ngăn cách bằng dấu hai chấm; nếu được đặt, trình liên kết động tìm trong các thư mục này trước các thư mục chuẩn. Thứ tự tìm củald.solúc chạy: (1) danh sáchDT_RPATHtrong tệp (nếu không cóDT_RUNPATH); (2)LD_LIBRARY_PATH; (3) danh sáchDT_RUNPATH; (4)/etc/ld.so.cache; (5)/librồi/usr/lib.12LD_LIBRARY_PATHlà cách nói với máy "tìm thư viện trong các thư mục này trước". Lúc chạy, máy lần lượt soi theo một thứ tự cố định cho tới khi thấy thư viện. Nhớ nhé: LD_LIBRARY_PATH được soi trước các thư mục hệ thống.The
LD_LIBRARY_PATHvariable is a colon-separated list of directories; if set, the dynamic linker searches them before the standard directories. The run-time search order ofld.so: (1) theDT_RPATHlist in the file (if there is noDT_RUNPATH); (2)LD_LIBRARY_PATH; (3) theDT_RUNPATHlist; (4)/etc/ld.so.cache; (5)/libthen/usr/lib.12Bạn gặp nó ở đâuWhere you meet it Một lý do an toàn khiến không nên dựa vàoLD_LIBRARY_PATHtrong sản phẩm: với chương trình set-user-ID hay set-group-ID, trình liên kết động bỏ qua biến này, để người dùng không lừa nó nạp một thư viện giả cùng tên.12 Với các chương trình đặc quyền (set-UID), máy cố tình bỏ qua LD_LIBRARY_PATH để tránh bị lừa nạp thư viện giả. A security reason not to rely onLD_LIBRARY_PATHin production: for set-user-ID or set-group-ID programs, the dynamic linker ignores it, so users cannot trick it into loading a fake library of the same name.12rpath nhúng trong tệprpath embedded in the file
Có thể nhúng sẵn thư mục tìm kiếm vào tệp thực thi bằng tùy chọn liên kết
-rpath, tạo danh sách rpath. Đặc tả ELF cũ dùng thẻDT_RPATH(ưu tiên cao hơnLD_LIBRARY_PATH); đặc tả mới dùngDT_RUNPATH(ưu tiên thấp hơn), bật bằng--enable-new-dtags. Hỗ trợDT_RUNPATHđược thêm từ glibc 2.2.15Search directories can be embedded in the executable with the-rpathlinker option, forming an rpath list. The old ELF spec used theDT_RPATHtag (higher precedence thanLD_LIBRARY_PATH); newer specs useDT_RUNPATH(lower precedence), enabled with--enable-new-dtags. Support forDT_RUNPATHwas added in glibc 2.2.15$ORIGIN cho ứng dụng "cắm là chạy"$ORIGIN for turn-key apps
Trình liên kết động hiểu chuỗi đặc biệt
$ORIGINtrong rpath, nghĩa là "thư mục chứa ứng dụng". Nhờ đó, dựng với-Wl,-rpath,'$ORIGIN'/libcho phép người dùng giải nén và chạy ứng dụng ở bất kỳ đâu mà không phải cài thư viện vào thư mục chuẩn.12The dynamic linker understands the special string$ORIGINin an rpath, meaning "the directory containing the application." So building with-Wl,-rpath,'$ORIGIN'/liblets a user unpack and run the application anywhere without installing libraries into a standard directory.12 -
ldd / nm / objdump / readelf
Bộ công cụ soi thư viện: ldd, nm, objdump, readelf Công cụ để xem bên trong thư viện The inspection toolkit: ldd, nm, objdump, readelf
ldd(1)(list dynamic dependencies) liệt kê các thư viện dùng chung mà một chương trình cần, giải mỗi tên thành đường dẫn theo đúng quy ước tìm của trình liên kết động; với phần lớn tệp ELF, nó liệt kê ít nhấtld-linux.so.2vàlibc.so.6.18nm(1)liệt kê ký hiệu định nghĩa trong một thư viện hay chương trình — ví dụ tìm thư viện nào định nghĩacrypt().objdumpvàreadelfhiển thị thông tin từ các section ELF (vàobjdumpcòn gỡ hợp ngữ), mỗi lệnh một định dạng khác nhau.191011Bốn công cụ để "soi" thư viện:
lddcho biết một chương trình cần những thư viện nào;nmcho biết thư viện nào chứa một hàm; cònobjdumpvàreadelfcho xem các phần bên trong tệp ELF. Nhớ nhé: ldd xem cần gì, nm xem có gì, objdump/readelf xem bên trong.ldd(1)(list dynamic dependencies) lists the shared libraries a program requires, resolving each name to a path using the same conventions as the dynamic linker; for most ELF files it lists at leastld-linux.so.2andlibc.so.6.18nm(1)lists the symbols defined in a library or program — for example, to find which library definescrypt().objdumpandreadelfdisplay information from the ELF sections (andobjdumpcan disassemble), each in a different format.191011Bạn gặp nó ở đâuWhere you meet it Khi một chương trình báo thiếu thư viện,ldd proglà lệnh đầu tiên nên chạy: những dòngnot foundchỉ ra đúng thư viện mà trình liên kết động không giải được.18 Khi chương trình kêu thiếu thư viện, chạyldd progđể xem nó đang thiếu thư viện nào. When a program complains about a missing library,ldd progis the first command to run: thenot foundlines point to exactly the library the dynamic linker could not resolve.18Mẹo dùng nmAn nm tip
Cờ
-Acủanmin tên thư viện ở đầu mỗi dòng ký hiệu — cần thiết để lọc, ví dụnm -A /usr/lib/lib*.so 2> /dev/null | grep ' crypt$'cho thấycrypt()được định nghĩa tronglibcrypt.19The-Aflag tonmprints the library name at the start of each symbol line — needed for filtering, e.g.nm -A /usr/lib/lib*.so 2> /dev/null | grep ' crypt$'shows thatcrypt()is defined inlibcrypt.19Đọc thêmFurther reading
Phần "Further information" của chương dẫn tới các trang man
ar(1),gcc(1),ld(1),ldconfig(8),ld.so(8),dlopen(3),objdump(1)cùng tài liệu info củaldvàreadelf— đúng bộ nguồn sơ cấp cho mọi chi tiết ở đây.112The chapter's "Further information" points to thear(1),gcc(1),ld(1),ldconfig(8),ld.so(8),dlopen(3),objdump(1)manual pages and the info documentation forldandreadelf— exactly the primary sources for every detail here.112
Ba ngộ nhận thường gặp Three common misconceptions
“Dùng chung nghĩa là các tiến trình chia sẻ cả biến” “Sharing means processes share the variables too”
Ngộ nhận: nếu nhiều tiến trình dùng chung một thư viện thì chúng cũng dùng chung các biến của thư viện đó.
Thực tế: chỉ mã được chia sẻ; mỗi tiến trình có bản sao riêng của các biến toàn cục và tĩnh định nghĩa trong thư viện.1
Myth: if several processes share a library, they also share that library's variables.
Reality: only the code is shared; each process has its own copies of the global and static variables defined in the library.1
“Tên nhúng trong tệp thực thi là tên tệp thật” “The name embedded in the executable is the real filename”
Ngộ nhận: tệp thực thi luôn ghi tên tệp thật của thư viện (libfoo.so.1.0.1).
Thực tế: khi thư viện có soname, chính soname (libfoo.so.1) được nhúng vào — đó là lớp gián tiếp cho phép đổi bản minor mà không liên kết lại.16
Myth: the executable always records the library's real filename (libfoo.so.1.0.1).
Reality: when the library has a soname, the soname (libfoo.so.1) is embedded instead — the indirection that lets the minor version change without relinking.16
“LD_LIBRARY_PATH là cách đúng để tìm thư viện trong sản phẩm” “LD_LIBRARY_PATH is the right way to find libraries in production”
Ngộ nhận: cứ đặt LD_LIBRARY_PATH là xong, dùng mãi cũng được.
Thực tế: ứng dụng sản phẩm không nên dựa vào nó; nó bị bỏ qua với chương trình set-UID/GID. Hãy cài vào thư mục chuẩn và chạy ldconfig.12
Myth: just set LD_LIBRARY_PATH and you are done, forever.
Reality: production applications should not rely on it; it is ignored for set-UID/GID programs. Install into a standard directory and run ldconfig.12
Tự kiểm Self-check
Năm câu hỏi để biết bạn đã nắm cơ chế thư viện dùng chung Năm câu hỏi kiểm tra nhanh Five questions to check you grasped shared libraries
Trả lời được những câu này nghĩa là bạn đã nắm vì sao có thư viện dùng chung, cách dựng và dùng nó, cùng cơ chế tên và tìm kiếm lúc chạy — nền cho các chủ đề nâng cao như nạp động với dlopen().
Nếu trả lời được, nghĩa là bạn đã hiểu chương này.
Answering these means you grasp why shared libraries exist, how to build and use them, and the naming and run-time search machinery — the groundwork for advanced topics such as dynamic loading with dlopen().
-
Phân biệt thư viện tĩnh và thư viện dùng chung. Nêu ba nhược điểm của sự dư thừa trong liên kết tĩnh.
Gợi ý sâu hơn: khi liên kết dùng chung, thứ gì được ghi vào tệp thực thi thay cho bản sao mã, và thẻ ELF nào biểu diễn nó?
-
-fPIClàm gì, và vì sao mã độc lập vị trí lại cần cho thư viện dùng chung? Làm sao kiểm tra một tệp đã dùng-fPICchưa?Gợi ý sâu hơn: phí tổn của mã độc lập vị trí là gì, và chuỗi TEXTREL cho biết điều gì?
-
Phân biệt liên kết tĩnh và liên kết động. Trình liên kết động là ai và nằm ở đâu?
Gợi ý sâu hơn: vì sao mọi chương trình đều qua pha liên kết tĩnh, nhưng chỉ chương trình dùng thư viện dùng chung mới qua pha liên kết động?
-
Nêu ba cái tên của một thư viện (tên thật, soname, tên liên kết) và vai trò từng cái. Cái nào được nhúng vào tệp thực thi?
Gợi ý sâu hơn: vì sao tên liên kết nên trỏ tới soname chứ không trỏ thẳng tên thật?
-
ldconfiglàm hai việc gì? Vì sao không nên dựa vàoLD_LIBRARY_PATHcho ứng dụng sản phẩm?Gợi ý sâu hơn: nêu thứ tự năm bước mà
ld.sodùng để tìm một thư viện lúc chạy.
Thư viện tĩnh và thư viện dùng chung khác nhau chỗ nào?
Cờ
-fPICdùng để làm gì?Khi chạy, ai đi tìm và nạp thư viện cho chương trình?
Một thư viện có ba cái tên nào?
Chạy lệnh gì sau khi cài một thư viện mới?
Distinguish static from shared libraries. Give the three drawbacks of static-linking redundancy.
What does
-fPICdo, and why does a shared library need position-independent code? How do you check whether a file used-fPIC?Distinguish static from dynamic linking. Who is the dynamic linker and where does it live?
Name a library's three names (real name, soname, linker name) and each one's role. Which is embedded in the executable?
What two tasks does
ldconfigperform? Why should production applications not rely onLD_LIBRARY_PATH?
Khép lại chương Closing the chapter
Một thư viện dùng chung là một bản mã duy nhất, nạp một lần, dùng chung bởi mọi chương trình: tệp thực thi chỉ ghi tên nó cần, và trình liên kết động tìm rồi nạp thư viện lúc chạy. Bộ ba tên — tên thật, soname, tên liên kết — cùng
ldconfigđiều phối việc chọn phiên bản và nâng cấp không cần liên kết lại. Nắm được nền tảng này, bạn đã sẵn sàng cho các tính năng nâng cao — nạp thư viện tùy ý lúc chạy bằngdlopen().112Thư viện dùng chung là một bản mã treo chung cho nhiều chương trình: chương trình chỉ nhớ tên, còn máy đi tìm và nạp lúc chạy. Ba cái tên và
ldconfiglo chuyện phiên bản. Nhớ nhé: một bản mã, nhiều người dùng, máy tự tìm.A shared library is a single copy of the code, loaded once, shared by every program: the executable records only the name it needs, and the dynamic linker finds and loads the library at run time. The triad of names — real name, soname, linker name — together with
ldconfiggoverns version selection and relink-free upgrades. Grasp this foundation and you are ready for the advanced features — loading libraries on demand at run time withdlopen().112