Вибір чотирьох регістрів аргументів на x64 - загальний для UN * X / Win64
Однією з речей, про які слід пам’ятати про x86, є те, що ім’я регістру для кодування «reg reg number» не очевидно; з точки зору кодування інструкцій ( байт MOD R / M , див. http://www.c-jump.com/CIS77/CPU/x86/X77_0060_mod_reg_r_m_byte.htm ), регістрові номери 0 ... 7 знаходяться - у такому порядку - ?AX, ?CX, ?DX, ?BX, ?SP, ?BP, ?SI, ?DI.
Отже, вибір A / C / D (рег. 0..2) для значення повернення, і перші два аргументи (що є "класичною" 32-бітовою умовою __fastcall) є логічним вибором. Що стосується переходу на 64-бітну, то впорядковані "вищі" регістри, і Microsoft і UN * X / Linux пішли на R8/ R9як перші.
Маючи це у вигляді, вибір Microsoft по RAX(яке значення) і RCX, RDX, R8, R9(Arg [0..3]) є зрозумілим вибором , якщо ви вибираєте чотири регістра для аргументів.
Я не знаю, чому AMD64 UN * X ABI вибирав RDXраніше RCX.
Вибір шести регістрів аргументів на x64 - UN * X
UN * X, в архітектурах RISC, традиційно робив аргументи, передаючи регістри - конкретно, для перших шести аргументів (саме так це стосується PPC, SPARC, MIPS). Що може бути однією з головних причин, чому дизайнери AMI64 (UN * X) ABI вирішили також використовувати шість регістрів для цієї архітектури.
Так що якщо ви хочете шість регістрів для передачі аргументів на, і це логічно вибрати RCX, RDX, R8і R9чотири з них, які інших двох ви повинні вибрати?
Для "вищих" регістрів потрібен додатковий байт префікса інструкції, щоб вибрати їх, і тому вони мають більший розмір розміру інструкції, тому ви не хочете вибирати жоден із них, якщо у вас є варіанти. З класичних регістрів, з-за неявного значення RBPта RSPїх немає, і RBXтрадиційно він має особливе застосування на UN * X (глобальна таблиця зміщення), з якою дизайнери AMD64 ABI, схоже, не хотіли б непотрібно ставати несумісними.
Ерго, єдиним вибором були RSI/ RDI.
Тож якщо вам доведеться приймати RSI/ RDIяк регістри аргументів, якими вони повинні бути?
Виготовлення їх arg[0]і arg[1]має деякі переваги. Дивіться коментар cHao.
?SIі ?DIє рядковими операндами джерела / призначення, і, як згадував cHao, їх використання в якості регістрів аргументів означає, що згідно з умовами виклику AMD64 UN * X найпростіша можлива strcpy()функція, наприклад, складається лише з двох інструкцій процесора, repz movsb; retоскільки джерело / ціль адреси були внесені абонентом у правильні регістри. Існує, особливо, в "клеєвому" коді, створеному низьким рівнем і створеним компілятором (подумайте, наприклад, деякі C ++ купи-розподільники об'єктів, що заповнюють нуль, на будівництві, або ж сторпинки з нульовим заповненням ядра наsbrk()або скопіюйте за допомогою запису сторінок) величезну кількість блокової копії / заповнення, отже, це буде корисно для коду, який часто використовується для збереження двох-трьох інструкцій ЦП, які інакше завантажують такі аргументи джерела / цільової адреси в "правильні" регістри.
Таким чином , в певному сенсі, UN * X і Win64 відрізняються тільки тим , що UN * X «поміщає» два додаткових аргументу, в цілеспрямовано обраних RSI/ RDIрегістрів, до природного вибору чотирьох аргументів в RCX, RDX, R8та R9.
Поза цим ...
Існує більше відмінностей між ABI UN * X та Windows x64, ніж просто відображення аргументів на конкретні регістри. Для огляду Win64 перевірте:
http://msdn.microsoft.com/en-us/library/7kcdt6fy.aspx
Win64 та AMD64 UN * X також разюче відрізняються за способом використання стекових просторів; Наприклад, на Win64, абонент повинен виділити стекову область для аргументів функції, навіть якщо в регістри передаються аргументи 0 ... 3. Для UN * X, з іншого боку, функції аркуша (тобто тієї, яка не викликає інших функцій) навіть не потрібно взагалі виділяти стекову область, якщо їй потрібно не більше 128 байт (так, ви володієте і можете використовувати певна кількість стека, не виділяючи його ... ну, якщо ви не код ядра, джерело чудових помилок). Все це є особливим варіантом оптимізації, більша частина обґрунтування цього пояснюється в повних посиланнях ABI, на які посилається оригінальна вікіпедія оригінального афіші.