Đọc thêm cho bất kỳ chủ đề nào ở đây: Hướng dẫn dứt khoát cho các cuộc gọi hệ thống Linux
Tôi đã xác minh những thứ này bằng cách sử dụng GNU Assembler (gas) trên Linux.
Giao diện hạt nhân
x86-32 aka i386 Quy ước cuộc gọi hệ thống Linux:
Trong x86-32 tham số cho cuộc gọi hệ thống Linux được thông qua bằng cách sử dụng các thanh ghi. %eax
cho syscall_number. % ebx,% ecx,% edx,% esi,% edi,% ebp được sử dụng để truyền 6 tham số cho các cuộc gọi hệ thống.
Giá trị trả về là trong %eax
. Tất cả các thanh ghi khác (bao gồm EFLAGS) được bảo toàn trên int $0x80
.
Tôi đã theo đoạn trích từ Hướng dẫn lắp ráp Linux nhưng tôi nghi ngờ về điều này. Nếu bất kỳ ai có thể đưa ra một ví dụ, nó sẽ là tuyệt vời.
Nếu có nhiều hơn sáu đối số,
%ebx
phải chứa vị trí bộ nhớ nơi lưu danh sách các đối số - nhưng đừng lo lắng về điều này bởi vì không chắc là bạn sẽ sử dụng một tòa nhà có nhiều hơn sáu đối số.
Để biết ví dụ và đọc thêm một chút, hãy tham khảo http://www.int80h.org/bsdasm/#alternate-calling-convent . Một ví dụ khác về Hello World cho i386 Linux bằng cách sử dụng int 0x80
: Xin chào, thế giới trong ngôn ngữ lắp ráp với các cuộc gọi hệ thống Linux?
Có một cách nhanh hơn để thực hiện các cuộc gọi hệ thống 32 bit: sử dụng sysenter
. Hạt nhân ánh xạ một trang bộ nhớ vào mọi tiến trình (vDSO), với phía không gian người dùng của sysenter
điệu nhảy, phải hợp tác với hạt nhân để có thể tìm thấy địa chỉ trả về. Arg để đăng ký ánh xạ giống như cho int $0x80
. Thông thường bạn nên gọi vào vDSO thay vì sử dụng sysenter
trực tiếp. (Xem Hướng dẫn dứt khoát cho các cuộc gọi hệ thống Linux để biết thông tin về liên kết và gọi vào vDSO, và để biết thêm thông tin về sysenter
và mọi thứ khác liên quan đến các cuộc gọi hệ thống.)
x86-32 [Miễn phí | Mở | Net | DragonFly] Quy ước cuộc gọi hệ thống UNIX BSD:
Các thông số được truyền vào ngăn xếp. Đẩy các tham số (tham số cuối cùng được đẩy trước) vào ngăn xếp. Sau đó đẩy thêm 32 bit dữ liệu giả (Dữ liệu không thực sự là dữ liệu giả. Tham khảo liên kết sau để biết thêm thông tin) và sau đó đưa ra hướng dẫn gọi hệ thốngint $0x80
http://www.int80h.org/bsdasm/#default-calling-convent
x86-64 Quy ước cuộc gọi hệ thống Linux:
x86-64 Mac OS X tương tự nhưng khác nhau . TODO: kiểm tra xem * BSD làm gì.
Tham khảo phần: "A.2 AMD64 Linux Kernel Conventions" của System V Application Binary Interface AMD64 Architecture Processor Bổ sung . Các phiên bản mới nhất của psABI i386 và x86-64 System V có thể được tìm thấy được liên kết từ trang này trong repo của người bảo trì ABI . (Xem thêmx86 thẻ wiki cho các liên kết ABI cập nhật và nhiều nội dung hay khác về x86 asm.)
Đây là đoạn trích từ phần này:
- Các ứng dụng cấp người dùng sử dụng làm các thanh ghi số nguyên để truyền chuỗi% rdi,% rsi,% rdx,% rcx,% r8 và% r9. Giao diện kernel sử dụng% rdi,% rsi,% rdx,% r10,% r8 và% r9.
- Một cuộc gọi hệ thống được thực hiện thông qua
syscall
hướng dẫn . Điều này ghi lại % RCx và% r11 cũng như giá trị trả về% rax, nhưng các thanh ghi khác được giữ nguyên.
- Số lượng tòa nhà phải được thông qua trong đăng ký% rax.
- Các cuộc gọi hệ thống được giới hạn trong sáu đối số, không có đối số nào được truyền trực tiếp trên ngăn xếp.
- Trở về từ tòa nhà, đăng ký% rax chứa kết quả của cuộc gọi hệ thống. Một giá trị trong phạm vi từ -4095 đến -1 chỉ ra lỗi
-errno
.
- Chỉ các giá trị của lớp INTEGER hoặc MEM MEM class được truyền vào kernel.
Hãy nhớ điều này là từ phụ lục dành riêng cho Linux cho ABI và ngay cả đối với Linux, thông tin này không mang tính quy phạm. (Nhưng thực tế nó chính xác.)
int $0x80
ABI 32 bit này có thể sử dụng được trong mã 64 bit (nhưng không được khuyến khích). Điều gì xảy ra nếu bạn sử dụng 32-bit int 0x80 Linux ABI trong mã 64 bit? Nó vẫn cắt các đầu vào của nó thành 32 bit, do đó, nó không phù hợp với các con trỏ và nó không có giá trị r8-r11.
Giao diện người dùng: chức năng gọi
Quy ước gọi hàm x86-32:
Trong x86-32 tham số được truyền vào ngăn xếp. Tham số cuối cùng được đẩy đầu tiên vào ngăn xếp cho đến khi tất cả các tham số được thực hiện và sau đó call
lệnh được thực thi. Điều này được sử dụng để gọi các hàm thư viện C (libc) trên Linux từ lắp ráp.
Các phiên bản hiện đại của i386 System V ABI (được sử dụng trên Linux) yêu cầu căn chỉnh 16 byte %esp
trước a call
, như Hệ thống V ABI x86-64 luôn luôn được yêu cầu. Callees được phép giả định rằng và sử dụng tải / lưu trữ 16 byte SSE có lỗi khi không được chỉ định. Nhưng trong lịch sử, Linux chỉ yêu cầu căn chỉnh ngăn xếp 4 byte, do đó, phải mất thêm công sức để dự trữ không gian được căn chỉnh tự nhiên ngay cả đối với 8 byte double
hoặc thứ gì đó.
Một số hệ thống 32 bit hiện đại khác vẫn không yêu cầu căn chỉnh ngăn xếp hơn 4 byte.
x86-64 Quy ước gọi chức năng không gian người dùng System V:
x86-64 System V vượt qua các đối số trong các thanh ghi, hiệu quả hơn so với quy ước đối số ngăn xếp của i System System V. Nó tránh được độ trễ và các hướng dẫn bổ sung về việc lưu trữ args vào bộ nhớ (bộ đệm) và sau đó tải lại chúng trong callee. Điều này hoạt động tốt bởi vì có nhiều thanh ghi có sẵn hơn và tốt hơn cho các CPU hiệu suất cao hiện đại, nơi có độ trễ và vấn đề thực thi không theo thứ tự. (ABI i386 rất cũ).
Trong cơ chế mới này : Đầu tiên các tham số được chia thành các lớp. Lớp của mỗi tham số xác định cách thức mà nó được truyền cho hàm được gọi.
Để biết thông tin đầy đủ, hãy tham khảo: "Trình tự gọi chức năng 3.2" của Giao diện nhị phân ứng dụng System V Bổ sung bộ xử lý kiến trúc AMD64 , phần đọc:
Khi các đối số được phân loại, các thanh ghi được gán (theo thứ tự từ trái sang phải) để truyền như sau:
- Nếu lớp là NHỚ, truyền đối số trên ngăn xếp.
- Nếu lớp là INTEGER, thì thanh ghi có sẵn tiếp theo của chuỗi% rdi,% rsi,% rdx,% rcx,% r8 và% r9 được sử dụng
Vì vậy, %rdi, %rsi, %rdx, %rcx, %r8 and %r9
các thanh ghi theo thứ tự được sử dụng để truyền tham số nguyên / con trỏ (tức là lớp INTEGER) cho bất kỳ hàm libc nào từ assembly. % rdi được sử dụng cho tham số INTEGER đầu tiên. % rsi cho thứ 2,% rdx cho thứ 3, v.v. Sau đó, call
hướng dẫn nên được đưa ra. Ngăn xếp ( %rsp
) phải được căn chỉnh 16B khi call
thực thi.
Nếu có nhiều hơn 6 tham số INTEGER, tham số INTEGER thứ 7 và sau đó được truyền vào ngăn xếp. (Người gọi bật lên, giống như x86-32.)
8 đối số dấu phẩy động đầu tiên được truyền vào% xmm0-7, sau đó trên ngăn xếp. Không có thanh ghi vector bảo tồn cuộc gọi. (Một hàm có kết hợp các đối số FP và số nguyên có thể có hơn 8 đối số thanh ghi tổng.)
Các hàm biến thể ( nhưprintf
) luôn luôn cần %al
= số lượng thanh ghi FP args.
Có các quy tắc về thời điểm đóng gói cấu trúc vào các thanh ghi ( rdx:rax
khi trả về) so với trong bộ nhớ. Xem ABI để biết chi tiết và kiểm tra đầu ra của trình biên dịch để đảm bảo mã của bạn đồng ý với các trình biên dịch về cách một cái gì đó sẽ được chuyển / trả lại.
Lưu ý rằng quy ước gọi hàm Windows x64 có nhiều khác biệt đáng kể so với x86-64 System V, giống như không gian bóng phải được người gọi dành riêng (thay vì vùng đỏ) và xmm6-xmm15 được bảo toàn cuộc gọi. Và các quy tắc rất khác nhau mà arg đi trong đăng ký nào.