Chọn bốn thanh ghi đối số trên x64 - chung cho UN * X / Win64
Một trong những điều cần lưu ý về x86 là tên đăng ký để mã hóa "số đăng ký" không rõ ràng; về mã hóa lệnh ( byte MOD R / M , xem http://www.c-jump.com/CIS77/CPU/x86/X77_0060_mod_reg_r_m_byte.htm ), số đăng ký 0 ... 7 - theo thứ tự đó - ?AX
, ?CX
, ?DX
, ?BX
, ?SP
, ?BP
, ?SI
, ?DI
.
Do đó, việc chọn A / C / D (regs 0..2) cho giá trị trả về và hai đối số đầu tiên (là __fastcall
quy ước 32bit "cổ điển" ) là một lựa chọn hợp lý. Liên quan đến việc chuyển sang 64bit, các reg "cao hơn" được sắp xếp theo thứ tự, và cả Microsoft và UN * X / Linux đều chọn R8
/ R9
là những người đầu tiên.
Giữ ý nghĩ đó, lựa chọn của Microsoft RAX
(giá trị trả về) và RCX
, RDX
, R8
, R9
(arg [0..3]) là một lựa chọn dễ hiểu nếu bạn chọn Bốn thanh ghi cho các đối số.
Tôi không biết tại sao AMD64 UN * X ABI lại chọn RDX
trước đây RCX
.
Chọn sáu thanh ghi đối số trên x64 - UN * X cụ thể
UN * X, trên các kiến trúc RISC, theo truyền thống thực hiện truyền đối số trong các thanh ghi - cụ thể là đối với sáu đối số đầu tiên (ít nhất là như vậy trên PPC, SPARC, MIPS). Đó có thể là một trong những lý do chính tại sao các nhà thiết kế AMD64 (UN * X) ABI cũng chọn sử dụng sáu thanh ghi trên kiến trúc đó.
Vì vậy, nếu bạn muốn Sáu thanh ghi để vượt qua đối số trong, và đó là logic để lựa chọn RCX
, RDX
, R8
và R9
cho bốn người trong số họ, mà khác hai bạn nên chọn?
Các reg "cao hơn" yêu cầu thêm byte tiền tố lệnh để chọn chúng và do đó có kích thước lệnh lớn hơn, vì vậy bạn sẽ không muốn chọn bất kỳ lệnh nào trong số đó nếu bạn có tùy chọn. Trong số các thanh ghi cổ điển, do ý nghĩa ẩn của RBP
và RSP
chúng không có sẵn, và RBX
theo truyền thống có một công dụng đặc biệt trên UN * X (bảng bù toàn cục) mà dường như các nhà thiết kế AMD64 ABI không muốn trở nên không tương thích với.
Ergo, sự lựa chọn duy nhất là RSI
/ RDI
.
Vì vậy, nếu bạn phải lấy RSI
/ RDI
làm thanh ghi đối số, chúng sẽ là đối số nào?
Làm cho chúng arg[0]
và arg[1]
có một số lợi thế. Xem bình luận của cHao.
?SI
và ?DI
là các toán hạng nguồn / đích của lệnh chuỗi và như cHao đã đề cập, việc sử dụng chúng làm thanh ghi đối số có nghĩa là với các quy ước gọi AMD64 UN * X strcpy()
, ví dụ, hàm đơn giản nhất có thể chỉ bao gồm hai lệnh CPU repz movsb; ret
vì nguồn / đích địa chỉ đã được người gọi đưa vào đúng thanh ghi. Có, đặc biệt là trong mã "keo" cấp thấp và do trình biên dịch tạo ra (ví dụ: một số trình phân bổ heap C ++ có các đối tượng không lấp đầy trên cấu trúc hoặc các trang heap không lấp đầy hạt nhân trênsbrk()
hoặc mặc định trang copy-on-write) một lượng lớn bản sao / điền khối, do đó nó sẽ hữu ích cho mã thường được sử dụng để lưu hai hoặc ba lệnh CPU mà nếu không sẽ tải các đối số địa chỉ nguồn / đích như vậy vào thanh ghi "đúng".
Vì vậy, trong một cách, UN * X và Win64 chỉ khác nhau ở chỗ UN * X "prepends" hai đối số bổ sung, trong mục đích lựa chọn RSI
/ RDI
đăng ký, với sự lựa chọn tự nhiên của bốn đối số trong RCX
, RDX
, R8
và R9
.
Ngoài ra ...
Có nhiều sự khác biệt giữa ABI UN * X và Windows x64 hơn là chỉ ánh xạ các đối số tới các thanh ghi cụ thể. Để biết tổng quan về Win64, hãy kiểm tra:
http://msdn.microsoft.com/en-us/library/7kcdt6fy.aspx
Win64 và AMD64 UN * X cũng có sự khác biệt đáng kể về cách sử dụng không gian ngăn xếp; trên Win64, ví dụ, người gọi phải cấp phát không gian ngăn xếp cho các đối số của hàm mặc dù các args 0 ... 3 được chuyển vào các thanh ghi. Mặt khác, trên UN * X, một hàm lá (tức là một hàm không gọi các hàm khác) thậm chí không cần phải cấp phát không gian ngăn xếp nếu nó cần không quá 128 Byte (vâng, bạn sở hữu và có thể sử dụng một số lượng ngăn xếp nhất định mà không phân bổ nó ... tốt, trừ khi bạn là mã hạt nhân, một nguồn của các lỗi tiện lợi). Tất cả những lựa chọn này đều là những lựa chọn tối ưu hóa cụ thể, hầu hết lý do của những điều đó được giải thích trong tài liệu tham khảo ABI đầy đủ mà tham chiếu wikipedia của người đăng ban đầu trỏ đến.