Tập 44: ABI là luật ngầm của thế giới máy

Lập trình viên viết code thường sống trong thế giới của các khái niệm trừu tượng: kiểu dữ liệu, interface, module. Máy tính thì thô thiển hơn: nó chỉ biết đến các thanh ghi, ô nhớ và các byte liên tiếp. ABI (Application Binary Interface) chính là bản dịch cam kết ranh giới giữa hai thế giới đó.

Khi DUY muốn gọi một hàm viết bằng C (FFI), hoặc ngược lại, C muốn gọi một hàm DUY, cả hai phải đồng ý với nhau về calling convention.

Ai sẽ đặt tham số thứ nhất vào thanh ghi rdi, tham số thứ hai vào rsi? Ai có trách nhiệm dọn dẹp stack khi hàm trả về? Nếu struct của DUY chứa một trường u8 và một trường i32, nó chiếm 5 byte hay sẽ được compiler tự động căn lề thành 8 byte để khớp với phần cứng?

Sprint 71-75 (Phase K) buộc tôi phải viết các quy tắc căn lề chi tiết (struct alignment) cho LLVM backend. Nếu layout của struct bị lệch dù chỉ một byte so với quy ước của hệ điều hành, mọi lời gọi API hệ thống hoặc thư viện ngoài đều sẽ dẫn đến crash hoặc đọc sai dữ liệu.

Đó là một công việc cực kỳ tẻ nhạt: đọc hàng trăm trang đặc tả ABI của x86_64, viết các test case kiểm tra kích thước bộ nhớ của từng struct, và debug khi thấy địa chỉ bộ nhớ bị lệch. Một lần, do tính sai padding của một struct chứa enum lồng nhau, compiler đã sinh mã đọc nhầm dữ liệu của biến kế cận, làm biến đó biến đổi giá trị ngẫu nhiên lúc runtime. Tìm ra lỗi đó mất của tôi hai ngày dùng debugger gỡ từng dòng asm.

Chúng tôi cũng phải học cách cấu hình target triplet (ví dụ: x86_64-unknown-linux-gnu) để LLVM sinh mã đúng định dạng cho từng hệ điều hành. ABI dạy tôi rằng compiler không thể hoạt động độc lập như một vị thần; nó là một thực thể xã hội phải học cách nói chuyện và tuân thủ các quy ước có sẵn của cộng đồng hệ thống xung quanh.


Bình luận (0)

Đang tải bình luận...