16

Phân tích this question Tôi đã tìm hiểu một số điều về hành vi của độ phân giải biểu tượng yếu trong bối cảnh tải động (dlopen) trên Linux. Bây giờ tôi đang tìm kiếm các thông số kỹ thuật điều chỉnh này.Độ phân giải biểu tượng tải động và yếu

Hãy lấy an example. Giả sử có một chương trình a tự động tải thư viện b.soc.so, theo thứ tự đó. Nếu c.so tùy thuộc vào hai thư viện khác foo.so (thực tế là libgcc.so trong ví dụ đó) và bar.so (thực tế là libpthread.so), thì các ký hiệu được xuất bar.so có thể được sử dụng để đáp ứng các liên kết biểu tượng yếu trong foo.so. Nhưng nếu b.so cũng tùy thuộc vào foo.so nhưng không phụ thuộc vào bar.so, thì những biểu tượng yếu này dường như sẽ không được liên kết với bar.so. Dường như chỉ foo.so các lần nhập chỉ tìm các biểu tượng từ ab.so và tất cả các phụ thuộc của chúng. Điều này có ý nghĩa, ở một mức độ nào đó, vì nếu không tải c.so có thể thay đổi hành vi của foo.so tại một số thời điểm mà b.so đã sử dụng thư viện. Mặt khác, trong câu hỏi khiến tôi bắt đầu điều này gây ra khá nhiều rắc rối, vì vậy tôi tự hỏi liệu có cách nào giải quyết vấn đề này không. Và để tìm những cách xung quanh, trước tiên tôi cần hiểu rõ về các chi tiết chính xác về độ phân giải biểu tượng trong những trường hợp này được chỉ định.

Đặc điểm kỹ thuật hoặc tài liệu kỹ thuật khác để xác định hành vi chính xác trong các trường hợp này là gì?

+0

Bạn có xem [PDF này] (http://refspecs.linuxbase.org/elf/elf.pdf) không? Rất nhiều dữ liệu thú vị, nhưng không chắc chắn nếu nó bao gồm những gì bạn tìm kiếm. – rodrigo

+0

@rodrigo: Không chắc nó là cái gì hay tương tự, nhưng cho đến nay tất cả các tài liệu ELF tôi tìm thấy chỉ mô tả liên kết động trước khi thực thi nhị phân, không liên kết trong các đối tượng được nạp động. Nó là một tài liệu dài, và tôi có thể đã nhìn vào những nơi sai, nhưng cho đến nay nó có vẻ không phải là những gì tôi đang tìm kiếm. – MvG

+0

Và điều gì về [bài đăng Drepper] này (http://www.sourceware.org/ml/libc-hacker/2000-06/msg00029.html) và ít hơn [tài liệu liên quan] của nó (http: // www. akkadia.org/drepper/dsohowto.pdf) (xem phần 1.5.2)? Khi tôi diễn giải nó, các ký hiệu yếu chỉ được sử dụng cho liên kết tĩnh. Vì vậy, 'dlopen() 'sẽ không tạo ra sự khác biệt giữa các ký hiệu yếu và mạnh. – rodrigo

Trả lời

11

Thật không may, tài liệu có thẩm quyền là mã nguồn. Hầu hết các bản phân phối Linux sử dụng glibc hoặc ngã ba của nó, eglibc. Trong mã nguồn cho cả hai, các tập tin đó nên tài liệu dlopen() đọc như sau:

bằng tay/libdl.texi

@c FIXME these are undocumented: 
@c dladdr 
@c dladdr1 
@c dlclose 
@c dlerror 
@c dlinfo 
@c dlmopen 
@c dlopen 
@c dlsym 
@c dlvsym 

gì đặc tả kỹ thuật có được có thể được rút ra từ ELF specification và tiêu chuẩn POSIX . Đặc điểm kỹ thuật ELF là những gì làm cho một biểu tượng yếu có ý nghĩa. POSIX là chính bản thân số specification for dlopen().

Đây là những gì tôi thấy là phần có liên quan nhất của đặc tả ELF.

Khi trình chỉnh sửa liên kết tìm kiếm thư viện lưu trữ, nó trích xuất lưu trữ thành viên chứa định nghĩa về ký hiệu toàn cầu không xác định. Định nghĩa của thành viên có thể là biểu tượng toàn cầu hoặc yếu.

Đặc điểm ELF không tham chiếu đến tải động nên phần còn lại của đoạn này là cách diễn giải của riêng tôi. Lý do tôi tìm thấy ở trên có liên quan là các biểu tượng giải quyết xảy ra tại một "khi". Trong ví dụ bạn đưa ra, khi chương trình a tải động b.so, trình tải động sẽ cố gắng giải quyết các ký hiệu không xác định. Nó có thể kết thúc làm như vậy với một trong hai biểu tượng toàn cầu hoặc yếu. Khi chương trình tự động tải c.so, trình tải động sẽ cố gắng giải quyết các ký hiệu không xác định. Trong trường hợp bạn mô tả, các ký hiệu trong b.so được giải quyết bằng các ký hiệu yếu. Sau khi giải quyết, những biểu tượng đó không còn được xác định. Nó không quan trọng nếu các biểu tượng toàn cầu hoặc yếu được sử dụng để xác định chúng. Chúng đã không còn được xác định trước khi tải c.so.

Đặc tả ELF không có định nghĩa chính xác về trình soạn thảo liên kết là gì hoặc khi trình chỉnh sửa liên kết phải kết hợp các tệp đối tượng. Có lẽ đó là một vấn đề không phải vì tài liệu có liên kết động trong tâm trí.

POSIX mô tả một số chức năng dlopen() nhưng để lại nhiều việc thực hiện, bao gồm cả chất của câu hỏi của bạn. POSIX không tham chiếu đến định dạng ELF hoặc các ký hiệu yếu nói chung. Đối với các hệ thống triển khai dlopen(), không cần phải có bất kỳ khái niệm nào về các ký hiệu yếu.

http://pubs.opengroup.org/onlinepubs/9699919799/functions/dlopen.html

POSIX tuân thủ là một phần của tiêu chuẩn khác, tiêu chuẩn cơ sở Linux. Các bản phân phối Linux có thể hoặc không thể chọn tuân thủ các tiêu chuẩn này và có thể hoặc không thể gặp rắc rối khi được chứng nhận. Ví dụ, tôi hiểu rằng một chứng nhận Unix chính thức của Open Group khá đắt tiền - do đó sự phong phú của các hệ thống "giống Unix".

Một điểm thú vị về việc tuân thủ các tiêu chuẩn của dlopen() được thực hiện trên Wikipedia article for dynamic loading. dlopen(), theo yêu cầu của POSIX, trả về một khoảng trống *, nhưng C, theo yêu cầu của ISO, nói rằng void * là một con trỏ tới một đối tượng và con trỏ đó không nhất thiết phải tương thích với một con trỏ hàm.

Sự thật vẫn là bất kỳ chuyển đổi giữa chức năng và đối tượng con trỏ phải được coi là một (vốn đã không cầm tay) gia hạn thực hiện, và rằng không có cách nào "đúng" cho một chuyển đổi trực tiếp tồn tại, vì trong điều này liên quan đến tiêu chuẩn POSIX và ISO mâu thuẫn với nhau.

Các tiêu chuẩn tồn tại mâu thuẫn và tài liệu chuẩn nào có thể không có ý nghĩa đặc biệt nào. Đây là Ulrich Drepper viết về thái độ khinh thị của mình cho Open Group và "thông số kỹ thuật" của họ.

http://udrepper.livejournal.com/8511.html

tình cảm tương tự được diễn tả trong bài được liên kết bởi Rodrigo.

Lý do tôi đã thực hiện sự thay đổi này là không thực sự được tuân thủ QTI hơn (đó là tốt đẹp, nhưng không có lý do vì không ai phàn nàn về hành vi cũ).

Sau khi xem xét, tôi tin câu trả lời đúng cho câu hỏi như bạn đã hỏi đó là không có hành vi đúng hay sai cho dlopen() về vấn đề này. Có thể cho rằng, khi tìm kiếm đã giải quyết một biểu tượng, nó không còn được xác định và trong các lần tìm kiếm tiếp theo, trình tải động sẽ không cố gắng giải quyết biểu tượng đã được xác định.

Cuối cùng, khi bạn nêu trong phần nhận xét, nội dung bạn mô tả trong bài đăng gốc không chính xác. Thư viện chia sẻ được tải động có thể được sử dụng để giải quyết các ký hiệu không xác định trong các thư viện được tải động trước đó. Trong thực tế, điều này không giới hạn đối với các ký hiệu không xác định trong mã được nạp động. Đây là một ví dụ trong đó bản thân thực thi có một biểu tượng không xác định được giải quyết thông qua tải động.

main.c

#include <dlfcn.h> 

void say_hi(void); 

int main(void) { 
    void* symbols_b = dlopen("./dyload.so", RTLD_NOW | RTLD_GLOBAL); 
    /* uh-oh, forgot to define this function */ 
    /* better remember to define it in dyload.so */ 
    say_hi(); 
    return 0; 
} 

dyload.c

#include <stdio.h> 
void say_hi(void) { 
    puts("dyload.so: hi"); 
} 

Biên dịch và chạy.

gcc-4.8 main -fpic -ldl -Wl,--unresolved-symbols=ignore-all -o main 
gcc-4.8 dyload.c -shared -fpic -o dyload.so 
$ ./main 
dyload.so: hi 

Lưu ý rằng chính tệp thi hành chính được biên dịch là PIC.

+0

Đây là những gì tôi gọi là một câu trả lời xuất sắc! – paulotorrens

Các vấn đề liên quan