Đầu tiên của tất cả các câu hỏi #include
không liên quan gì đến linking
. Hãy nhớ bất cứ điều gì với một #
ở phía trước trong C
có nghĩa là cho bộ tiền xử lý, không phải trình biên dịch hoặc trình liên kết.
Nhưng điều đó cho biết chức năng phải được liên kết phải không?
Hãy thực hiện các bước theo các bước riêng biệt.
$ gcc -c -Werror --std=c99 st.c
st.c: In function ‘main’:
st.c:5:22: error: implicit declaration of function ‘isdigit’ [-Werror=implicit-function-declaration]
printf("%d %d\n",isdigit(48),isdigit(48.4));
^
cc1: all warnings being treated as errors
Cũng như bạn thấy lint của gcc (máy phân tích tĩnh) đang hoạt động!
Dù chúng tôi sẽ tiến hành bỏ qua nó ...
$ gcc -c --std=c99 st.c
st.c: In function ‘main’:
st.c:5:22: warning: implicit declaration of function ‘isdigit’ [-Wimplicit-function-declaration]
printf("%d %d\n",isdigit(48),isdigit(48.4));
này thời gian chỉ là một cảnh báo. Bây giờ chúng ta có một tệp đối tượng tại thư mục hiện tại. Hãy kiểm tra nó ...
$ nm st.o
U isdigit
0000000000000000 T main
U printf
Như bạn có thể thấy cả hai printf
và isdigit
được liệt kê là không xác định. Vì vậy, mã phải đến từ đâu đó phải không?
hãy tiếp tục liên kết nó ...
$ gcc st.o
$ nm a.out | grep 'printf\|isdigit'
U [email protected]@GLIBC_2.2.5
U [email protected]@GLIBC_2.2.5
Cũng như bạn có thể thấy tình hình được cải thiện nhẹ. Là isdigit
và printf
không phải là những người cô đơn bất lực như họ đang ở trong số st.o
. Bạn có thể thấy cả hai chức năng được cung cấp bởi GLIBC_2.2.5
. Nhưng đâu là GLIBC
?
Vâng chúng ta hãy xem xét thực thi chính thức hơn một chút ...
$ ldd a.out
linux-vdso.so.1 => (0x00007ffe58d70000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fb66f299000)
/lib64/ld-linux-x86-64.so.2 (0x000055b26631d000)
AHA ... có mà libc
. Vì vậy, nó quay ra, mặc dù bạn đã không đưa ra bất kỳ hướng dẫn, liên kết là liên kết với 3 thư viện theo mặc định, một trong số họ là libc
có chứa cả hai printf
và isdigit
.
Bạn có thể thấy hành vi mặc định của mối liên kết bởi:
$gcc -dumpspec
*link:
%{!r:--build-id} %{!static:--eh-frame-hdr} %{!mandroid|tno-android-ld:%{m16|m32|mx32:;:-m elf_x86_64} %{m16|m32:-m elf_i386} %{mx32:-m elf32_x86_64} --hash-style=gnu --as-needed %{shared:-shared} %{!shared: %{!static: %{rdynamic:-export-dynamic} %{m16|m32:-dynamic-linker %{muclibc:/lib/ld-uClibc.so.0;:%{mbionic:/system/bin/linker;:/lib/ld-linux.so.2}}} %{m16|m32|mx32:;:-dynamic-linker %{muclibc:/lib/ld64-uClibc.so.0;:%{mbionic:/system/bin/linker64;:/lib64/ld-linux-x86-64.so.2}}} %{mx32:-dynamic-linker %{muclibc:/lib/ldx32-uClibc.so.0;:%{mbionic:/system/bin/linkerx32;:/libx32/ld-linux-x32.so.2}}}} %{static:-static}};:%{m16|m32|mx32:;:-m elf_x86_64} %{m16|m32:-m elf_i386} %{mx32:-m elf32_x86_64} --hash-style=gnu --as-needed %{shared:-shared} %{!shared: %{!static: %{rdynamic:-export-dynamic} %{m16|m32:-dynamic-linker %{muclibc:/lib/ld-uClibc.so.0;:%{mbionic:/system/bin/linker;:/lib/ld-linux.so.2}}} %{m16|m32|mx32:;:-dynamic-linker %{muclibc:/lib/ld64-uClibc.so.0;:%{mbionic:/system/bin/linker64;:/lib64/ld-linux-x86-64.so.2}}} %{mx32:-dynamic-linker %{muclibc:/lib/ldx32-uClibc.so.0;:%{mbionic:/system/bin/linkerx32;:/libx32/ld-linux-x32.so.2}}}} %{static:-static}} %{shared: -Bsymbolic}}
hai thư viện khác là gì?
Hãy nhớ khi bạn đào vào a.out
, cả printf
và isdigit
vẫn được hiển thị là U
có nghĩa là không xác định. Nói cách khác, không có địa chỉ memory
được liên kết với các biểu tượng này.
Thực tế đây là nơi ma thuật nằm. Các thư viện này thực sự được nạp trong thời gian chạy, không phải trong thời gian liên kết như các hệ thống cũ hơn.
Cách triển khai? Vâng, nó có một biệt ngữ liên kết với, giống như liên kết lười biếng. Những gì nó làm, là khi quá trình gọi một hàm, nếu không có địa chỉ bộ nhớ (phần TEXT), nó tạo ra một Trap
(Giống như một Ngoại lệ trong thuật ngữ ngôn ngữ cấp cao, khi điều khiển được chuyển giao cho công cụ ngôn ngữ). Hạt nhân chặn Trap
và đưa nó cho bộ tải động tải thư viện và trả về địa chỉ bộ nhớ liên quan đến quá trình người gọi.
Có nhiều lý do lý thuyết, lý do tại sao làm mọi thứ dễ dàng hơn là làm điều đó trước. Tôi đoán đó là một chủ đề hoàn toàn mới, mà chúng ta sẽ thảo luận vào một thời điểm khác.
Có thể là examplepe.h redefines isdigit dưới dạng macro không? –
@WouterHuysentruit nope, tôi không giấu bất cứ điều gì. Hơn nữa, nếu bạn chỉ cần sao chép chương trình và dán vào ideone có vẻ như biên dịch và liên kết tốt trên GCC 5.1, nhưng nó bị treo. – user1537366