Выбор четырех регистров аргументов на x64 - общий для UN * X / Win64
Одна из вещей, о которых следует помнить о x86, это то, что имя регистра в кодировке "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 (regs 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) , Это может быть одной из основных причин, по которой разработчики AMD64 (UN * X) ABI также решили использовать шесть регистров в этой архитектуре.
Итак, если вы хотите, чтобы шесть регистров передавали аргументы, и логично выбрать RCX
, RDX
, R8
и R9
для четырех из них Какие еще два вы должны выбрать?
«Более высокие» регистры требуют дополнительного байта префикса инструкции для их выбора и, следовательно, имеют больший размер инструкции, поэтому вы не захотите выбирать ни одну из них, если у вас есть варианты. Из классических регистров, из-за неявного значения RBP
и RSP
они недоступны, и RBX
традиционно имеет специальное использование для UN * X (глобальная таблица смещений), которая, по-видимому, дизайнеры AMD64 ABI не захотели без необходимости становиться несовместимыми.
Ergo, единственный выбор были RSI
/ RDI
.
Так что, если вам нужно принять RSI
/ RDI
в качестве регистров аргументов, какими аргументами они должны быть?
Создание их arg[0]
и arg[1]
имеет некоторые преимущества. См. Комментарий cHao.
?SI
и ?DI
являются операндами источника / назначения строковых инструкций, и, как упомянул cHao, их использование в качестве регистров аргументов означает, что с соглашениями о вызовах AMD64 UN * X, например, самая простая из возможных функций strcpy()
состоит только из две инструкции ЦП repz movsb; ret
, поскольку вызывающая сторона поместила адреса источника / цели в правильные регистры. Существует, в частности, в низкоуровневом и сгенерированном компилятором «склеивающем» коде (например, некоторые объекты распределителя кучи C ++ при заполнении нулями при конструировании, или страницы кучи ядра с нулевым заполнением в sbrk()
, или копирование на -записать pagefaults) огромное количество блоков копирования / заполнения, следовательно, это будет полезно для кода, который так часто используется для сохранения двух или трех инструкций ЦП, которые в противном случае загружали бы такие аргументы адреса источника / цели в «правильные» регистры.
Таким образом, 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, на которые указывает ссылка на википедию оригинального плаката.