Параметры на стеке

Тема в разделе "WASM.X64", создана пользователем DevilDevil, 15 авг 2017.

  1. DevilDevil

    DevilDevil Member

    Публикаций:
    0
    Регистрация:
    14 ноя 2007
    Сообщения:
    101
    Пытаюсь освоить заполнение параметров стека при вызове функции, логика не ясна
    Нашёл информацию, что стек должен быть выравнен на 16 байт, но этого мало

    Вот простой пример:
    Код (Text):
    1. procedure Test(rcx, rdx, r8, r9: Integer; Address: Pointer);
    2. begin
    3.   PInteger(Address)^ := rcx;
    4. end;
    В дизасме вижу это:
    Код (Text):
    1.  
    2. mov rax, [rsp+$28]
    3. mov [rax], ecx
    4. ret
    1. Не понимаю, почему смещение $28, а не 8
    2. Стек чистится вызывающей функцией?
     
  2. Indy_

    Indy_ Well-Known Member

    Публикаций:
    4
    Регистрация:
    29 апр 2011
    Сообщения:
    4.775
    DevilDevil,

    Нормально дефейнится прототип процедуры, в нём указывается конвенция вызова и число аргументов, но ни как не какие то регистры. Это какой то полускрипт, вроде как прототип, но в дефейне регистры. Пусть аргументы передаются через них, тогда получается что стек пуст(fastcall). Но тогда к чему происходит обращение rsp[28] и далее не очистка стека, а прямой возврат ?

    Это глючный скрипт - дельфя; он считается позором в коденге из за изврат конструкций и говно компилем из за мусора на выхлопе.

    Поэтому удалите это недоразумение и используйте си/асм.
     
  3. DevilDevil

    DevilDevil Member

    Публикаций:
    0
    Регистрация:
    14 ноя 2007
    Сообщения:
    101
    Indy_,

    В Delphi x64 используется стандартное соглашение о вызове. И я работаю в нём, ассемблер в нём - это вещь второстепенная.
    Можешь попробовать в сях, дизасм должен быть идентичный

    Код (C):
    1. void Test(int x, int y, int z, void* address)
    2. {
    3.   *((int*)address) = x;
    4. }
     
  4. DevilDevil

    DevilDevil Member

    Публикаций:
    0
    Регистрация:
    14 ноя 2007
    Сообщения:
    101
    Прошу прощения

    Код (C):
    1. void Test(int x, int y, int z, int u, void* address)
    2. {
    3.   *((int*)address) = x;
    4. }
     
  5. Mikl___

    Mikl___ Супермодератор Команда форума

    Публикаций:
    14
    Регистрация:
    25 июн 2008
    Сообщения:
    3.709
    DevilDevil,
    Код (C):
    1. void Test(int x, int y, int z, int u, void* address)
    2. {
    3.     *((int*)address) = x;
    4. }
    Код (ASM):
    1.          sub rsp,30h<-- перед функцией у которой от 5 до 6 параметров
    2.          mov rax,address
    3.          mov [rsp+20h],rax
    4.          mov r9,u
    5.          mov r8,z
    6.          mov rdx,y
    7.          mov rcx,x
    8.          call Test
    9.          add rsp,30h
    10.       . . . . . . . . .
    11. Test proc x:qword,y:qword,z:qword,u:qword,address:qword
    12. ;[rsp] <-- адрес возврата из Test
    13. ; для дальнейшего использования сохраняем  x, y, z, u
    14. ; хотя если  x, y, z, u далее не нужны, то можем это и не делать
    15.               mov x,rcx; mov [rsp+8],rcx
    16.               mov y,rdx; mov [rsp+10h],rdx
    17.               mov z,r8; ; mov [rsp+18h],r8
    18.               mov u,r9; mov [rsp+20h],r9
    19.  
    20.               mov rax, [rsp+28h]; значение из address
    21.               mov [rax],ecx; значение из х    *((int*)address) = x
    22.               retn
    23. Test endp
     
  6. rmn

    rmn Well-Known Member

    Публикаций:
    0
    Регистрация:
    23 ноя 2004
    Сообщения:
    2.329
  7. DevilDevil

    DevilDevil Member

    Публикаций:
    0
    Регистрация:
    14 ноя 2007
    Сообщения:
    101
    Mikl___,

    Хочешь сказать, независимо от параметров, на стеке будет выделено 32 байта? И предоставляет этот стек вызывающая функция?
     
  8. rmn

    rmn Well-Known Member

    Публикаций:
    0
    Регистрация:
    23 ноя 2004
    Сообщения:
    2.329
    DevilDevil,
    Да. Первые 4 параметра передаются в регистрах, но для них все равно резервируется место на стеке (даже если параметров меньше четырех, например - 0)
     
  9. Mikl___

    Mikl___ Супермодератор Команда форума

    Публикаций:
    14
    Регистрация:
    25 июн 2008
    Сообщения:
    3.709
    DevilDevil,
    1. да, иногда эти 32 байта используются для сохранения параметров передаваемых через регистры rcx, rdx, r8, r9.
    2. Иногда, в этих 32 байтах функции сохраняют первоначальные значения, используемых внутри функции rdi, rsi, rbx, rbp.
    3. Иногда, например для MessageBox, эти 32 байта не используются.
    4. Но, на всякий случай, минимум 32 байта резервируют.
    Посмотри Сказки дядюшки Римуса :)
    Нет, ни система, ни функция эти 32 байта не выделяет, но пятый, шестой и т.д. параметры функции передаются так
    Код (ASM):
    1.      sub rsp,8 <-- в начале программы
    2.     . . . . .
    3.      sub rsp,((N+1)>>1)*10h<-- это делает программист перед функцией с N параметрами
    4.      mov rcx,param1
    5.      mov rdx,param2
    6.      mov r8,param3
    7.      mov r9,param4
    8.      mov [rsp+20h],param5
    9.      mov [rsp+28h],param6
    10.      . . . .
    11.      mov [rsp+(N-1)*8],paramN
    12.      call foo
    13.      add rsp,((N+1)>>1)*10h<-- чистим за собой
    1. Все, что нужно знать, чтобы начать программировать для 64-разрядных версий Windows
    2. Программные соглашения x64
     
    DevilDevil нравится это.
  10. DevilDevil

    DevilDevil Member

    Публикаций:
    0
    Регистрация:
    14 ноя 2007
    Сообщения:
    101
    Mikl___,

    Спасибо большое!
    Вопрос теперь закрыт