Почему в соглашении о вызовах x86-64 System V аргументы передаются в регистры, а не только в стек?
Почему 32-битный C помещает все аргументы функций прямо в стек, а 64-битный C помещает первые 6 аргументов в регистры, а остальные - в стек?
Таким образом, 32-битный стек будет выглядеть так:
...
arg2
arg1
return address
old %rbp
Хотя 64-битный стек будет выглядеть так:
...
arg8
arg7
return address
old %rbp
arg6
arg5
arg4
arg3
arg2
arg1
Так почему же 64-битный C это делает? Не проще ли просто поместить все в стек вместо того, чтобы поместить первые 6 аргументов в регистры, чтобы просто переместить их в стек в прологе функции?
1 ответ
вместо того, чтобы поместить первые 6 аргументов в регистры, просто чтобы переместить их в стек в прологе функции?
Я искал код, сгенерированный gcc, и это то, что он всегда делал.
Тогда вы забыли включить оптимизацию. gcc -O0
выливает все в память, чтобы вы могли изменять их с помощью отладчика при пошаговом выполнении. Это явно ужасно для производительности, поэтому компиляторы не сделают этого, если вы не заставите их с помощью -O0
,
x86-64 System V позволяет int add(int x, int y) { return x+y; }
скомпилировать вlea eax, [rdi + rsi]
/ ret
Это то, что на самом деле делают компиляторы, как вы можете видеть в проводнике компилятора Godbolt.
Соглашения о вызовах стековых аргументов являются медленными и устаревшими. RISC-машины используют соглашения о вызовах register-args еще до появления x86-64, а в ОС, которые все еще заботятся о 32-битном x86 (то есть Windows), существуют лучшие соглашения о вызовах, такие как __vectorcall
которые передают первые 2 целочисленных аргумента в регистрах.
i386 System V не был заменен, потому что люди в основном не заботятся о 32-битной производительности в других ОС; мы просто используем 64-битный код с хорошо разработанным соглашением о вызовах System86 для x86-64.
Для получения дополнительной информации о компромиссе между аргументами регистров и регистрами с сохранением вызовов и с регистрами вызовов в разработке соглашения о вызовах см. Почему бы не сохранять параметры функции в плавающих регистрах? а также Почему Windows64 использует соглашение о вызовах, отличное от всех других ОС на x86-64?,