Size: a a a

2020 March 04

DV

Dmitrij V in pro.asm
#book #manual #x86_64 #abi #win64

Соглашения о вызовах в x86_64 Windows OS:

Первые четыре параметра помещаются в регистрах: rcx, rdx, r8, и r9 соответственно.
Остальные параметры идут через стек, справа налево.

Перед вызовом функции, стек должен быть уменьшен на 32байта + 8байт для каждого параметра которые идут через стек (+16 для long double ?).

Если передавать числа с плавающей точкой, то первые четыре помещаются в регистры XMM0-XMM3. Пример:

void my_func(int a, double b, int c, float d);
Arguments a in RCX, b in XMM1, c in R8, and d in XMM3.

PS: эту инфу прикрепил под тэгом win64
источник

ЕК

Евгений Красников (Jin X) in pro.asm
Ещё важно, что стек должен быть выровнен по границе 16 байт перед вызовом функции (т.е. перед call).
Таким образом, внутри функции структура стека будет такова:
адрес возврата (1 qword = 8 байт)
буфер для сохранения параметров (4 qword = 32 байта)
параметр 5
параметр 6
параметр 7
...
выравнивание (при необходимости 1 qword = 8 байт)
Сразу после вызова функции младшая тетрада esp (esp and 0x0F) = 8.
источник

DV

Dmitrij V in pro.asm
Евгений Красников (Jin X)
Ещё важно, что стек должен быть выровнен по границе 16 байт перед вызовом функции (т.е. перед call).
Таким образом, внутри функции структура стека будет такова:
адрес возврата (1 qword = 8 байт)
буфер для сохранения параметров (4 qword = 32 байта)
параметр 5
параметр 6
параметр 7
...
выравнивание (при необходимости 1 qword = 8 байт)
Сразу после вызова функции младшая тетрада esp (esp and 0x0F) = 8.
Да, я это делаю после пролога, у меня для этого есть макрос:

.macro ALIGN_STACK
 .if __address_size__ == 8
   andq $0xfffffffffffffff0, %rsp
 .elseif __address_size__ == 4
   andl $0xfffffff0, %esp
 .else
   andw $0xfff0, %sp
 .endif
.endm /*; ALIGN_STACK */

PS
: наверное придётся фрейм после выравнивания корректировать тоже ...
источник

ЕК

Евгений Красников (Jin X) in pro.asm
Да, но если у тебя будет передаваться нечётное кол-во параметров >= 5, то нужно будет ещё на 8 байт скидывать.
источник

ЕК

Евгений Красников (Jin X) in pro.asm
Потому что ты сделаешь 1, 3, 5... push'ей и будет опять 8 на конце.
источник

DV

Dmitrij V in pro.asm
Евгений Красников (Jin X)
Да, но если у тебя будет передаваться нечётное кол-во параметров >= 5, то нужно будет ещё на 8 байт скидывать.
Точно, посмотрел только что: у меня в invoke реализован подсчёт аргументов передаваемых через стек, и на этой основе делается выравнивание ...
источник

ЕК

Евгений Красников (Jin X) in pro.asm
Причём, т.к. у тебя на входе должна быть 8-ка, то после того как ты сделаешь and esp, 8 байт откусишь, а потом для выравнивания ещё 8 байт откусишь, т.о. лишние 16 байт стека у тебя будут выброшены за зря.
источник

DV

Dmitrij V in pro.asm
Евгений Красников (Jin X)
Причём, т.к. у тебя на входе должна быть 8-ка, то после того как ты сделаешь and esp, 8 байт откусишь, а потом для выравнивания ещё 8 байт откусишь, т.о. лишние 16 байт стека у тебя будут выброшены за зря.
да, ALIGN_STACK у меня вызывется после входа в main/_start (после пролога).

а в invoke что-то такое:

.if __address_size__ == 8
   COUNT_ARGS \s1, \s2, \s3, \s4, \s5, \s6
   .if aligning != 0
     .set __aligned_sp__, __count_number_args__*__address_size__
     CALCULATE_ALIGNMENT __aligned_sp__, __aligning_sp__
   .endif
 .else
   COUNT_ARGS \rdi, \rsi, \rdx, \rcx, \r8, \r9, \s1, \s2, \s3, \s4, \s5, \s6
   .set __aligned_sp__, __count_number_args__*__address_size__
   .set __index_number_args__, 0
 .endif
источник

ЕК

Евгений Красников (Jin X) in pro.asm
Хотя, если сделать пролог
push %rbp
mov %rsp,%rbp
то после and ничего не должно измениться (собственно, можно его и не делать даже).
источник

ЕК

Евгений Красников (Jin X) in pro.asm
Я не понял, мы про Винду говорим или про Линукс?
источник

DV

Dmitrij V in pro.asm
в линухе требование тоже выравнивать по границе 16байт...
источник

ЕК

Евгений Красников (Jin X) in pro.asm
Просто ты скинул сначала про винду, а последний пример — про линуск (судя по списку регистров).
Кол-во параметров в регистрах разное (4 и 6).
источник

ЕК

Евгений Красников (Jin X) in pro.asm
Dmitrij V
в линухе требование тоже выравнивать по границе 16байт...
А буфер там делается или нет (48 байт, судя по всему должен быть тогда, если есть)?
источник

DV

Dmitrij V in pro.asm
это изначально под x64 было, имена аргументов макроса не стал менять, но реализован invoke у меня под 16/32/64
источник

DV

Dmitrij V in pro.asm
Евгений Красников (Jin X)
А буфер там делается или нет (48 байт, судя по всему должен быть тогда, если есть)?
RED ZONE ?
источник

ЕК

Евгений Красников (Jin X) in pro.asm
Да не, 32 байта которые между параметрами и адресом возврата.
источник

DV

Dmitrij V in pro.asm
а, под линух нет...
источник

ЕК

Евгений Красников (Jin X) in pro.asm
Ща ищу инфу как раз про это.
источник

ЕК

Евгений Красников (Jin X) in pro.asm
Dmitrij V
а, под линух нет...
Ага, нашёл тоже :)
источник

DV

Dmitrij V in pro.asm
и да, я писал: andw $0xfff0, %sp

это не прокатит, там для адресации ограничения:
SP can't be used as a base or index register in the 16-bit addressing modes.

https://stackoverflow.com/a/34345858
источник