Làm thế nào để số SO (đối tượng chia sẻ) hoạt động?


123

Tôi biết rằng các đối tượng được chia sẻ trong Linux sử dụng "số", cụ thể là các phiên bản khác nhau của đối tượng được chia sẻ được cung cấp các tiện ích mở rộng khác nhau, ví dụ:

  • example.so.1
  • example.so.2

Tôi hiểu ý tưởng là có hai tệp riêng biệt sao cho hai phiên bản của thư viện có thể tồn tại trên một hệ thống (trái ngược với "DLL Hell" trên Windows). Tôi muốn biết làm thế nào điều này hoạt động trong thực tế? Thông thường, tôi thấy rằng example.sotrên thực tế đó là một liên kết tượng trưng đến example.so.2đâu .2là phiên bản mới nhất. Làm thế nào để một ứng dụng phụ thuộc vào một phiên bản cũ hơn example.soxác định chính xác nó? Có quy định nào về những con số người ta phải sử dụng không? Hay đây chỉ đơn giản là quy ước? Có phải là trường hợp, không giống như trong Windows khi các nhị phân phần mềm được chuyển giữa các hệ thống, nếu một hệ thống có phiên bản mới hơn của một đối tượng dùng chung, nó sẽ tự động được liên kết với phiên bản cũ hơn khi biên dịch từ nguồn?

Tôi nghi ngờ điều này có liên quan đến ldconfignhưng tôi không biết làm thế nào.

Câu trả lời:


87

Bản thân Binaries biết phiên bản nào của thư viện dùng chung mà họ phụ thuộc và yêu cầu cụ thể. Bạn có thể sử dụng lddđể hiển thị các phụ thuộc; của tôi lslà:

$ ldd /bin/ls
    linux-gate.so.1 =>  (0xb784e000)
    librt.so.1 => /lib/librt.so.1 (0xb782c000)
    libacl.so.1 => /lib/libacl.so.1 (0xb7824000)
    libc.so.6 => /lib/libc.so.6 (0xb76dc000)
    libpthread.so.0 => /lib/libpthread.so.0 (0xb76c3000)
    /lib/ld-linux.so.2 (0xb784f000)
    libattr.so.1 => /lib/libattr.so.1 (0xb76bd000)

Như bạn có thể thấy, nó trỏ đến ví dụ libpthread.so.0, không chỉ libpthread.so.


Lý do cho các liên kết tượng trưng là cho các liên kết. Khi bạn muốn liên kết libpthread.sotrực tiếp, bạn đưa gcccờ -lpthreadvà nó tự động thêm vào libtiền tố và .sohậu tố. Bạn không thể yêu cầu nó thêm vào .so.0hậu tố, vì vậy liên kết tượng trưng chỉ đến phiên bản mới nhất của lib để tạo điều kiện cho nó


Không nên có dấu bằng "= ls". Chỉ cần sử dụng "ldd ls"
bmacnaughton

1
@bmacnaughton Điều đó có thể sẽ gây ra lỗi cho bạn vì lddyêu cầu đường dẫn đầy đủ để thực thi. =lsthực hiện điều đó trong zsh, nhưng tôi đã thay đổi nó vì không phải ai cũng sử dụng shell đó
Michael Mrozek

Hấp dẫn. Tôi đang chạy bash trên Ubuntu và nó dường như hoạt động mà không có đường dẫn đầy đủ. Cảm ơn đã giải thích - Tôi không sử dụng zsh.
bmacnaughton

60

Các số trong các thư viện dùng chung là quy ước được sử dụng trong Linux để xác định API của thư viện. Thông thường định dạng là:

libFOO.so.MAJOR.MINOR

Và như bạn nhận thấy thường có một liên kết tượng trưng từ libFOO.so đến libFOO.so.MAJOR.MINOR. ldconfig chịu trách nhiệm cập nhật liên kết này lên phiên bản mới nhất.

MAJOR thường được tăng lên khi API thay đổi (điểm nhập mới bị xóa hoặc các tham số hoặc loại thay đổi). MINOR thường được tăng lên cho các bản phát hành sửa lỗi hoặc khi các API mới được giới thiệu mà không phá vỡ các API hiện có.

Một cuộc thảo luận rộng rãi hơn có thể được tìm thấy ở đây: Phân tích các thư viện chia sẻ


Xin chào Miguel, cảm ơn vì điều đó, thật xấu hổ vì tôi không thể chấp nhận hai câu trả lời vì điều đó bổ sung cho những điều trên một cách độc đáo. +1 từ tôi, liên kết tuyệt vời quá, cảm ơn một lần nữa!

4
Điều đó gần như đúng, nhưng nó thực sự libFOO.so.MAJOR.MINOR(vì vậy không phải ở cuối)
JonnyJD

6
Câu trả lời này là sai . Đầu tiên, những con số bạn thấy không liên quan gì đến API, đây hoàn toàn là ABI. Thứ hai, quy ước ở đây không phải là phiên bản ngữ nghĩa TẠI TẤT CẢ như bạn trả lời gợi ý. Thay vào đó, đó là một quy ước libtool có đặc tính tốt là ánh xạ tới một số phiên bản thư viện duy nhất mà ld.so có thể so sánh (xem gnu.org/software/libtool/manual/html_node/ trộm để biết thêm thông tin)
NewbiZ

23

Thư viện dùng chung nên được phiên bản theo sơ đồ sau:

blah.so.X.Y.Z

Ở đâu

  • X = phát hành ABI không tương thích ngược
  • Y = phát hành ABI tương thích ngược
  • Z = Chỉ thay đổi nội bộ - không thay đổi đối với ABI

Thông thường bạn chỉ thấy chữ số đầu tiên như thế hello.so.1bởi vì chữ số đầu tiên là thứ duy nhất cần thiết để xác định "phiên bản" của thư viện vì tất cả các chữ số khác đều tương thích ngược.

ldconfigduy trì một bảng các thư viện chia sẻ có sẵn trên một hệ thống và nơi đường dẫn đến thư viện đó tồn tại. Bạn có thể xác minh điều này bằng cách chạy:

ldconfig -p

Khi một gói được xây dựng cho một cái gì đó như Red Hat, các thư viện chia sẻ được gọi ra trong hệ nhị phân sẽ được tra cứu và thêm vào dưới dạng các phụ thuộc của gói tại thời điểm xây dựng RPM. Do đó, khi bạn đi cài đặt gói, trình cài đặt sẽ tìm kiếm xem có hello.so.1được cài đặt trên hệ thống hay không bằng cách kiểm tra ldconfig.

Bạn có thể thấy sự phụ thuộc của gói bằng cách thực hiện một số thứ như:

rpm -qpR hello.rpm

Hệ thống này (không giống như Windows) cho phép nhiều phiên bản hello.sođược cài đặt trên một hệ thống và được sử dụng bởi các ứng dụng khác nhau cùng một lúc.


Tôi nghĩ rằng đây là câu trả lời tốt nhất.
Kemin Zhou

1
Các thư viện dùng chung nên được phiên bản theo sơ đồ sau (Hoài) - Bạn có thể vui lòng cung cấp tài liệu tham khảo cho tuyên bố này không?
Piotr Dobrogost

19

libNAME.so là tên tệp được trình biên dịch / trình liên kết sử dụng khi lần đầu tiên tìm kiếm một thư viện được chỉ định bởi -lNAME. Bên trong tệp thư viện dùng chung là một trường có tên SONAME. Trường này được đặt khi chính thư viện được liên kết đầu tiên thành một đối tượng dùng chung (vì vậy) bởi quá trình xây dựng. SONAME này thực sự là những gì một trình liên kết lưu trữ trong một tệp thực thi tùy thuộc vào đối tượng được chia sẻ đó được liên kết với nó. Thông thường SONAME ở dạng libNAME.so.MAJOR và được thay đổi bất cứ lúc nào thư viện không tương thích với các tệp thực thi hiện có được liên kết với nó và cả hai phiên bản chính của thư viện có thể được cài đặt khi cần (mặc dù chỉ có một phiên bản sẽ được phát triển như libNAME.so) Ngoài ra, để hỗ trợ dễ dàng nâng cấp giữa các phiên bản nhỏ của thư viện, libNAME.so.MAJOR thường là một liên kết đến một tệp như libNAME.so.MAJOR.MINOR. Một phiên bản nhỏ mới có thể được cài đặt và sau khi hoàn thành, liên kết đến phiên bản phụ cũ bị lỗi để chỉ đến phiên bản nhỏ mới ngay lập tức nâng cấp tất cả các thực thi mới để sử dụng thư viện được nâng cấp. Ngoài ra, xem câu trả lời của tôi choLinux, GNU GCC, ld, script script và định dạng nhị phân ELF - Nó hoạt động như thế nào?

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.