Использование call
/ret
, не делая кадр стека либо enter
/leave
или push&pop rbp/mov rbp, rsp
. gcc (со значением по умолчанию) создает только стек стека в функциях, которые выполняют распределение по размеру в стеке. This may make debugging slightly more difficult, так как gcc обычно испускает информацию об удалении стека при компиляции с , но у вашего рукописного asm этого не будет. Обычно имеет смысл писать листовые функции в asm или, по крайней мере, те, которые не называют многими другими функциями.
Кадры стека означают, что вам не нужно отслеживать, насколько указатель стека изменился с момента ввода функции для доступа к материалам в стеке (например, функции args и spill slots для местных жителей). Оба Windows и Linux/Unix 64-битные ABI передают первые несколько аргументов в регистрах, и часто бывает достаточно регр, которые вам не нужно разливать в стек. В большинстве случаев стоп-кадры являются пустой тратой инструкций. В 32-битном коде, имеющем ebp
(от 6 до 7 GP regs, не считая указателя стека), большая разница, чем от 14 до 15. Конечно, вам все равно нужно push/pop
rbp, если вы используете do, хотя, поскольку в обоих ABI это зарегистрированный пользователем реестр, функции не допускаются к clobber.
Если вы оптимизируете x86-64 asm, вы должны прочитать Agner Fog's guides, а также проверить некоторые другие ссылки в вики-файле x86.
Лучшая реализация вашей функции, вероятно:
align 16
global Add
Add:
lea eax, [rdi + rsi]
ret
; the high 32 of either reg doesn't affect the low32 of the result
; so we don't need to zero-extend or use a 32bit address-size prefix
; like lea eax, [edi, esi]
; even if we're called with non-zeroed upper32 in rdi/rsi.
align 16
global main
main:
mov edi, 1 ; 1st arg in SysV ABI
mov esi, 3 ; 2nd arg in SysV ABI
call Add
; return value in eax in all ABIs
ret
align 16
OPmain: ; This is what you get if you don't return anything from main to use the result of Add
xor eax, eax
ret
Это на самом деле what gcc emits для Add()
, но она по-прежнему оказывается основной в пустой функции, или в return 4
, если вы return i
. clang 3.7 уважает -fno-inline-functions
, даже если результатом является константа времени компиляции. Это превосходит мой asm, делая оптимизацию хвостового вызова, и jmp
ing до Add
.
Обратите внимание, что Windows 64bit ABI использует разные регистры для функций args. См. Ссылки в вики-теге x86 или руководстве ABI Agner Fog. Assembler macros может помочь для написания функций в asm, которые используют правильные регистры для своих аргументов, в зависимости от платформы, на которую вы нацеливаете.
Я думаю, что функция 'main' неверна. Для другой функции возвращение без явного 'return' будет ошибкой,' main' является специальной. Неявный возврат из 'main' эквивалентен возврату значения' 0'. Здесь вы возвращаете всякий мусор, найденный в 'eax', а именно 4, которого вы не должны. –
@JensGustedt: Мой asm соответствует моему модифицированному C, который возвращает 'i', чтобы оптимизировать компиляторы, чтобы по-прежнему вызывать' Add' (при использовании '-fno-inline-functions'). Основной пункт OP просто компилируется в 'xor eax, eax/ret', как вы правильно указываете. –