Liên kết động trong Linux và Windows (Phần 1)
Phần I
Bài báo này thảo luận vkhái nim thư viện chia sẻ trong cả Windows
Linux. Đồng thời lướt qua các kiểu cấu trúc dữ liệu để giải thích liên kết
động làm việc như thế nào trong các hệ điu hành này. Bài này rất hữu ích
cho các nhà phát triển hứng thú nghiên cứu vấn đề về các hàm ẩn bảo mật,
liên quan tới tốc độ liên kết động. Và cũng khẳng định một số kiến thức cơ
bản về liên kết động đã được đưa ra trước đây.
Phần một giới thiệu các khái niệm cho cả Linux và Windows, nhưng cơ bản
tập trung trên Linux. Lần tới, trong phần hai chúng ta sẽ thảo luận chúng làm
việc trong Windows như thế nào và sau đó là so sánh hai môi trường với
nhau.
Thư viện tĩnh và thư viện động
Thư viện là một tập hợp các chương trình con cho phép mã chương trình
được chia sẻ và thay đổi theo kiu modul. Các chương trình chạy và thư viện
liên hệ với nhau theo một tiến trình gọi linking (liên kết), làm việc qua
mt cầu nối (linker).
Thư viện có thể chia thành hai loại: thư viện tĩnh và thư vin chia sẻ.
Thư viện tĩnh là một tập hợp các file kiểu đối tượng. Theo quy ước, các file
này có đuôi kết thúc là “.a” trong UNIX và “.libtrong Windows. Khi mt
chương trình được liên kết ngược với một thư viện tĩnh, mã máy từ các file
đối tượng cho bất kì hàm mở rng dùng trong chương trình sẽ được sao chép
từ thư viện vào chương trình chạy cui cùng.
Ngược lại vi thư viện tĩnh, mã lnh trong tvin chia sẻ không giới hạn
chương trình chạy tại thời gian liên kết. Phụ thuộc vào việc ghép đa chỉ lúc
nào và như thế nào, tiến trình liên kết có thể phân loại là prelinking, load
time linking, implicit run-time linking explicit run-time linking.
Mã độc lập vị trí ( hay Win32 DDLs với “.SO” )
Các mã độc lập vị tríthể được sao chép từ bất khu vực bộ nhớ nào, sau
đó chạy mà không cần thêm chỉnh sửa . Không giống như mã định vị lại vị
trí đòi hi phải có một tiến trình đặc biệt là các cầu nối để có được vị trí và
sự thực thi phù hợp.
Win32 DLLs không độc lập vị trí. Chúng cần định vị lại suốt trong quá trình
tải, trừ phi phần cơ sở được sửa chữa để không cần dùng. Định vị lại để các
địa chỉ ging nhau có thể được chia sẻ. Nhưng nếu các tiến trình khác nhau
xung đột trong dàn xếp bộ nhớ, bộ nạp cần tạo ra các bản “đa sao chép” của
DDL trong bộ nhớ. Khi bộ nạp Windows vẽ bản đồ DDL vào bộ nhớ, m
file và cố gắng nạp chúng vào các địa chỉ cơ bản trước. Tại các trang trong
bản đồ đã được vẽ, hệ thng phân trang sẽ xem xét liu các trang này đã
được thể hin trong bộ nhớ chưa. Nếu đã có thì chỉ cần vlại các trang cho
tiến trình mới, khi việc định vị lại vị trí đã được bộ nạp thực hiện xong tại
các địa chỉ cơ sở. Nếu không thì các trang vẫn đang được lấy về từ ổ đĩa.
Nếu phạm vi địa chỉ xác định cho DDL không phù hợp, bộ nạp vẽ lại bản đồ
trang vào khu vực tự do trong không gian địa chỉ chương trinh. Trong
trường hợp này, nó đánh dấu trang mã lnh như là COW (copy-on-write: sao
chép để ghi) mà trước đó đã được đánh dấu là read + execute (đọc và thực
thi). Từ đó, các cầu nối phải thể hin mã lnh đã sửa chữa tại thời gian định
vị lại vị trí, bắt buộc các trang phi được phục hồi theo kiu file phân trang.
Linux giải quyết vấn đề y bằng cách dùng PIC (Position Independent
Codemã độc lập vị trí). Các đối tượng chia sẻ trong Linux thường có PIC
để tránh phi định vị li vị trí thư viện trong thời gian tải. Tất cả các trang
mã lệnh có thể được chia sẻ giữa toàn bộ tiến trình dùng cùng một thư vin
và có thể được lập trang tới (hoặc từ) hệ thống file. Trong dòng x86, không
có cách đơn giản nào để định địa chỉ dữ liệu liên quan tới khu vực hiện tại,
kể từ khi tất cả các jump và các call là kiu liên hệ cấu trúc con trỏ. Do đó,
tất cả các tham chiếu tới khu vực địa chỉ tĩnh mở rộng được thực hiện trực
tiếp qua mt bảng, gọi là bảng GOT (Global Offset Table).
Liên kết động trong Linux
Cấu trúc dữ liệu ELF
Vì đây không phải là bài báo đặe tả định dạng kiểu ELF, chúng ta sẽ chỉ
thảo luận về các cấu trúc dữ liệu, liên quan tới ni dung mà chúng ta đang
xem xét. Đối với liên kết động, các cầu nối ELF cơ bản dùng hai bảng đặc
trưng theo bộ xử lý: Global Offset Table (GOT) và Procedure Linkage Table
(PLT).
Global Offset Table (GOT) - Bảng địa chỉ Offset mở rộng
Các mi liên kết ELF hỗ trợ PIC qua bảng GOT trong từng thư viện
chia sẻ. GOT chỉ chứa địa chỉ của tất cả các dữ liệu tĩnh dùng trong chương
trình. Địa chỉ của GOT thông thường được lưu trữ trong một thanh ghi
(EBX), trong đó một địa chỉ quan hệ ca lnh được dùng.
Procedure Linkage Table (PLT) - Bảng ln kết các chương trình con
Cả chương trình chạy sử dụng thư viện chia sẻ và chính bản thân thư viện
chia sẻ đều có một bảng PLT. Tương tự như cách bảng GOT gửi lại các tính
toán địa chỉ độc lập vị trí tới khu vực địa chỉ tuyệt đối, PLT cũng gửi li các
hàm gọi địa chỉ tuyết đối tới khu vực địa chỉ tuyệt đối.
Ngoài hai bảng trên, các mối liên kết còn có trong.dinsym(chứa tất cả
biu tượng xuất khu và quan trọng ca file), “.dynstr” (xâun cho biểu
tượng), “.hash” (bảng hash - bảng cầu nối chạy thực, có thể dùng để tra tìm
các biu tượng một cách nhanh chóng) và “.dynamic” (danh sách các kiểu
đuôi và con trỏ).
Trong phần .dynamic, các kiểu đuôi quan trọng gồm:
+ DT NEEDED: giữ bảng kí tự offset của mt xâu kết thúc là null, đưa ra
tên thư viện cần thiết. Offset một chỉ mc trong bảng, được ghi li trong
danh sách DT_STRTAB.
+ 3DT HASH: giữ địa chỉ của bảng ký tự hash, trỏ tới bảng ký tự phần tử
trong DT_SYMTAB.
+ DT STRTAB: giữ địa chỉ của bảng xâu
+ DT SYMTAB: giữ địa chỉ của bảng biu tượng
Bảng ký tự Hash