Пытаюсь освоить заполнение параметров стека при вызове функции, логика не ясна Нашёл информацию, что стек должен быть выравнен на 16 байт, но этого мало Вот простой пример: Код (Text): procedure Test(rcx, rdx, r8, r9: Integer; Address: Pointer); begin PInteger(Address)^ := rcx; end; В дизасме вижу это: Код (Text): mov rax, [rsp+$28] mov [rax], ecx ret 1. Не понимаю, почему смещение $28, а не 8 2. Стек чистится вызывающей функцией?
DevilDevil, Нормально дефейнится прототип процедуры, в нём указывается конвенция вызова и число аргументов, но ни как не какие то регистры. Это какой то полускрипт, вроде как прототип, но в дефейне регистры. Пусть аргументы передаются через них, тогда получается что стек пуст(fastcall). Но тогда к чему происходит обращение rsp[28] и далее не очистка стека, а прямой возврат ? Это глючный скрипт - дельфя; он считается позором в коденге из за изврат конструкций и говно компилем из за мусора на выхлопе. Поэтому удалите это недоразумение и используйте си/асм.
Indy_, В Delphi x64 используется стандартное соглашение о вызове. И я работаю в нём, ассемблер в нём - это вещь второстепенная. Можешь попробовать в сях, дизасм должен быть идентичный Код (C): void Test(int x, int y, int z, void* address) { *((int*)address) = x; }
Прошу прощения Код (C): void Test(int x, int y, int z, int u, void* address) { *((int*)address) = x; }
DevilDevil, Код (C): void Test(int x, int y, int z, int u, void* address) { *((int*)address) = x; } Код (ASM): sub rsp,30h<-- перед функцией у которой от 5 до 6 параметров mov rax,address mov [rsp+20h],rax mov r9,u mov r8,z mov rdx,y mov rcx,x call Test add rsp,30h . . . . . . . . . Test proc x:qword,y:qword,z:qword,u:qword,address:qword ;[rsp] <-- адрес возврата из Test ; для дальнейшего использования сохраняем x, y, z, u ; хотя если x, y, z, u далее не нужны, то можем это и не делать mov x,rcx; mov [rsp+8],rcx mov y,rdx; mov [rsp+10h],rdx mov z,r8; ; mov [rsp+18h],r8 mov u,r9; mov [rsp+20h],r9 mov rax, [rsp+28h]; значение из address mov [rax],ecx; значение из х *((int*)address) = x retn Test endp
Mikl___, Хочешь сказать, независимо от параметров, на стеке будет выделено 32 байта? И предоставляет этот стек вызывающая функция?
DevilDevil, Да. Первые 4 параметра передаются в регистрах, но для них все равно резервируется место на стеке (даже если параметров меньше четырех, например - 0)
DevilDevil, да, иногда эти 32 байта используются для сохранения параметров передаваемых через регистры rcx, rdx, r8, r9. Иногда, в этих 32 байтах функции сохраняют первоначальные значения, используемых внутри функции rdi, rsi, rbx, rbp. Иногда, например для MessageBox, эти 32 байта не используются. Но, на всякий случай, минимум 32 байта резервируют. Посмотри Сказки дядюшки Римуса Нет, ни система, ни функция эти 32 байта не выделяет, но пятый, шестой и т.д. параметры функции передаются так Код (ASM): sub rsp,8 <-- в начале программы . . . . . sub rsp,((N+1)>>1)*10h<-- это делает программист перед функцией с N параметрами mov rcx,param1 mov rdx,param2 mov r8,param3 mov r9,param4 mov [rsp+20h],param5 mov [rsp+28h],param6 . . . . mov [rsp+(N-1)*8],paramN call foo add rsp,((N+1)>>1)*10h<-- чистим за собой Все, что нужно знать, чтобы начать программировать для 64-разрядных версий Windows Программные соглашения x64