Liên kết động - Linux Vs. các cửa sổ


10

Trong Windows, khi tôi biên dịch mã C / C ++ trong dự án DLL trong MSVC, tôi nhận được 2 tệp:

  1. MyDll.dll
  2. MyDll.lib

theo như tôi hiểu MyDll.libcó chứa một số loại bảng con trỏ chỉ các vị trí hàm trong dll. Khi sử dụng dll này, hãy nói trong một tệp exe,MyDll.lib được nhúng vào tệp exe trong khi liên kết để trong thời gian chạy, nó "biết" vị trí của các chức năng MyDll.dllvà có thể sử dụng chúng.

Nhưng nếu tôi biên dịch cùng một mã trong Linux, tôi chỉ nhận được một tệp MySo.somà không có MySo.a(tương đương với libtệp trong Linux), vậy làm thế nào để một tệp thực thi trong Linux biết các hàm được đặt ở đâu MySo.sonếu không có gì được nhúng vào trong khi liên kết?

Câu trả lời:


1

Trên Linux, trình liên kết (không phải trình liên kết động) tìm kiếm thông qua các thư viện dùng chung được chỉ định tại thời điểm liên kết và tạo các tham chiếu đến chúng bên trong tệp thực thi. Khi trình liên kết động tải các tệp thực thi này, nó sẽ tải các thư viện dùng chung mà chúng yêu cầu vào bộ nhớ và giải quyết các ký hiệu, cho phép các nhị phân được chạy.

MySo.a, nếu được tạo, thực sự sẽ bao gồm các ký hiệu được liên kết trực tiếp vào nhị phân thay vì "bảng tra cứu biểu tượng" được sử dụng trên Windows.

Câu trả lời của rustyx giải thích quá trình trên Windows kỹ lưỡng hơn tôi có thể; đã được một thời gian dài kể từ khi tôi sử dụng Windows.


1
"Windows có một cách tiếp cận khác ... chỉ định cho hệ điều hành chính xác vị trí của các ký hiệu trong DLL" - điều này mâu thuẫn với wiki , nói rằng tên hàm vẫn được giải quyết (khi khởi động hoặc trong lần gọi đầu tiên đến chức năng thư viện) ngay cả khi bạn sử dụng các lệnh (trừ khi liên kết địa chỉ trực tiếp được sử dụng mà không ai sẽ làm vì nó buộc người dùng thư viện biên dịch lại và triển khai lại mã của họ bất cứ khi nào thư viện thay đổi).
yugr

@yugr Đã xóa phần đó, dù sao tôi cũng đang cầm ống hút.
SS Anne

4

Trình liên kết MSVC có thể liên kết các tệp đối tượng (.obj) và thư viện đối tượng (.lib) để tạo ra một .EXE hoặc .DLL.

Để liên kết với một DLL, quá trình trong MSVC là sử dụng một thư viện được gọi là thư viện nhập khẩu (.LIB) hoạt động như một chất kết dính giữa các tên hàm C và bảng xuất của DLL (trong một DLL, một hàm có thể được xuất theo tên hoặc theo thứ tự - cái sau thường được sử dụng cho các API không có giấy tờ).

Tuy nhiên, trong hầu hết các trường hợp, bảng xuất DLL có tất cả các tên hàm và do đó thư viện nhập (.LIB) chứa thông tin dư thừa (" hàm nhập ABC -> hàm xuất ABC ", v.v.).
Nó thậm chí có thể tạo ra .LIB từ .DLL hiện có.

Trình liên kết trên các nền tảng khác không có "tính năng" này và có thể liên kết trực tiếp với các thư viện động.


"Trình liên kết trên các nền tảng khác không có tính năng này" - thật dễ dàng để thực hiện (ví dụ: Implib.so thực hiện điều này cho Linux) để đạt được tải chậm và các tính năng khác.
yugr

@yugr: đó là lý do tại sao "tính năng" được trích dẫn - đó không phải là điều bạn thường muốn làm và là công việc bổ sung bạn phải làm trên Windows.
Chris Dodd

1

Sự khác biệt mà bạn đang thấy là chi tiết triển khai nhiều hơn - trong cả hệ điều hành cả Linux và Windows đều hoạt động tương tự nhau - mã của bạn gọi một hàm còn sơ khai được liên kết tĩnh trong tệp thực thi của bạn và cuống này sẽ tải DLL / shlib nếu cần (trong trường hợp bị trì hoãn đang tải , nếu không thư viện sẽ được tải khi chương trình bắt đầu) và (trong cuộc gọi đầu tiên) giải quyết biểu tượng thông qua GetProcAddress/dlsym .

Sự khác biệt duy nhất là trên Linux, các hàm sơ khai này (được gọi là sơ khai PLT) được tạo động khi bạn liên kết ứng dụng của mình với thư viện động (thư viện chứa đủ thông tin để tạo chúng), trong khi đó trên Linux chúng được tạo khi chính DLL được tạo ra, trong một riêng biệt.lib tập tin .

Hai cách tiếp cận tương tự nhau đến mức thực sự có thể bắt chước các thư viện nhập khẩu Windows trên Linux (xem dự án Implib.so ).


0

Trên Linux, bạn chuyển MySo.sođến trình liên kết và nó chỉ có thể trích xuất những gì cần thiết cho giai đoạn liên kết, đưa vào một tham chiếu MySo.socần thiết trong thời gian chạy.


-3

.dllhoặc .sođược chia sẻ libs (được liên kết trong thời gian chạy), trong khi .a.lib là một thư viện tĩnh (được liên kết trong thời gian biên dịch). Điều này không có sự khác biệt giữa Windows và Linux.

Sự khác biệt là, chúng được xử lý như thế nào. Lưu ý: sự khác biệt chỉ có ở hải quan, chúng được sử dụng như thế nào. Sẽ không quá khó để làm cho Linux xây dựng theo cách của Windows và ngược lại, ngoại trừ việc thực tế không ai làm điều này.

Nếu chúng ta sử dụng một dll, hoặc chúng ta gọi một hàm thậm chí từ nhị phân của chính chúng ta, có một cách đơn giản và rõ ràng. Ví dụ: trong C, chúng ta thấy rằng:

int example(int x) {
  ...do_something...
}

int ret = example(42);

Tuy nhiên, ở cấp độ asm, có thể có nhiều sự khác biệt. Ví dụ, trên x86, một callopcode được thực thi và 42được đưa ra trên ngăn xếp. Hoặc trong một số đăng ký. Hoặc bất cứ nơi nào. Không ai biết rằng trước khi viết dll , nó sẽ được sử dụng như thế nào. Hoặc làm thế nào các dự án sẽ muốn sử dụng nó, có thể được viết bằng trình biên dịch (hoặc bằng ngôn ngữ!) Mà thậm chí không tồn tại ngay bây giờ (hoặc chưa biết đối với các nhà phát triển của dll).

Ví dụ, theo mặc định, cả C và Pascal đều đặt các đối số (và nhận các giá trị trả về) từ ngăn xếp - nhưng chúng đang thực hiện theo thứ tự khác nhau . Bạn cũng có thể trao đổi các đối số giữa các chức năng của mình trong các thanh ghi bằng một số - tối ưu hóa phụ thuộc vào trình biên dịch.

Như bạn thấy chính xác, tùy chỉnh Windows là xây dựng một dll, chúng tôi cũng tạo ra một mức tối thiểu .a/ .libvới nó. Thư viện tĩnh tối thiểu này chỉ là một trình bao bọc, các ký hiệu (hàm) của dll được tiếp cận thông qua nó. Điều này làm cho các chuyển đổi cuộc gọi cấp asm cần thiết.

Ưu điểm của nó là khả năng tương thích. Nhược điểm của nó là nếu bạn chỉ có một dll, bạn có thể gặp khó khăn để tìm hiểu xem các chức năng của nó muốn được gọi như thế nào. Điều này làm cho việc sử dụng dlls trở thành một nhiệm vụ hack, nếu nhà phát triển của dll không cung cấp cho bạn.a . Do đó, nó phục vụ chủ yếu cho các mục đích đóng cửa, ví dụ như vậy để có thêm tiền mặt cho SDK dễ dàng hơn.

Một nhược điểm khác của nó là ngay cả khi bạn sử dụng một thư viện động, bạn cần phải biên dịch trình bao bọc nhỏ này một cách tĩnh.

Trong Linux, giao diện nhị phân của các dll là tiêu chuẩn và tuân theo quy ước C. Do đó, không .abắt buộc và có sự tương thích nhị phân giữa các lib được chia sẻ, đổi lại chúng ta không có những lợi thế của tùy chỉnh microsoft.


1
Vui lòng cung cấp một bằng chứng rằng các hàm còn sơ khai có thể thay đổi thứ tự đối số. Tôi chưa bao giờ nghe về điều này trước đây và thật khó tin, vì chi phí hoạt động lớn như thế nào.
yugr

@yugr Sắp xếp lại đăng ký / ngăn xếp đơn giản không phải là chi phí hiệu năng. Nếu bạn sử dụng các dll được biên dịch msvc từ các nhị phân được biên dịch msvc, thì rõ ràng sẽ không có quá nhiều điều xảy ra, nhưng nó có thể.
peterh - Phục hồi Monica

1
Chúng tôi có thể tranh luận về vấn đề này nhưng trong trường hợp bạn đúng, thật dễ dàng để cung cấp bằng chứng rằng các hàm còn sơ khai có khả năng xử lý các đối số không tầm thường (và không chỉ là các trampolines giả).
yugr

@yugr Các sơ khai có quyền truy cập vào các chữ ký chức năng của dll, điều đó làm cho việc xử lý không tầm thường trở nên tầm thường.
peterh - Phục hồi Monica

1
Tôi chỉ đề nghị bạn hoàn thành câu trả lời của mình với một vài bằng chứng liên quan đến việc thư viện nhập khẩu làm gì (vì một số khiếu nại là nghi vấn).
yugr
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.