reverseenengineering:соглашения

Это старая версия документа!


Соглашения - Calling Conventions на x86 и x64 с примерами и схемами

Convention Порядок аргументовКак передаютсяКто чистит стекВозврат значенияИмя функцииГде применяется
cdecl |Cправа налево |Стек |Caller |EAX |_func |C/varargs | |stdcall Cправа налево Стек Callee EAX _func@N WinAPI
__fastcall R→L, 1 ECX, 2 EDX, потом стекРегистр+стекCalleeEAX@func@N Оптимизация
thiscall this via ECX, потом стекECX/стек Caller EAX манглинг C++ методы
Win64 N/A RCX/RDX/R8/R9/StackCaller RAX/XMM0 func Windows x64

; До входа в функцию (cdecl/stdcall):
; (Сверху вниз — адреса растут)
[ esp+12 ]   b
[ esp+8 ]    a
[ esp+4 ]    return address
[ esp ]      сохранённый ebp
[ esp-4 ]    локальная переменная 1
[ esp-8 ]    локальная переменная 2

; Сразу после sub rsp,28h до вызова функции:
[ rsp+40 ]   6-й аргумент (если он есть)
[ rsp+38 ]   5-й аргумент (если он есть)
[ rsp+30 ]   shadow r9
[ rsp+28 ]   shadow r8
[ rsp+20 ]   shadow rdx
[ rsp+18 ]   shadow rcx
[ rsp+10 ]   выравнивание/локалки
[ rsp ]      нижняя граница stack frame

; rcx, rdx, r8, r9 — содержат первые 4 аргумента

// Функция: вычисляет сумму и произведение трёх чисел, возвращает сумму
int example(int a, int b, int c) {
    int prod = a * b * c;
    int sum  = a + b + c;
    if (prod > 100)
        return sum * 2;
    else
        return sum;
}
example:
    push    ebp
    mov     ebp, esp
    sub     esp, 8        ; 2 локалки: prod ([ebp-4]), sum ([ebp-8])
 
    mov     eax, [ebp+8]  ; a
    imul    eax, [ebp+12] ; a*b
    imul    eax, [ebp+16] ; *c
    mov     [ebp-4], eax  ; prod
 
    mov     eax, [ebp+8]
    add     eax, [ebp+12]
    add     eax, [ebp+16]
    mov     [ebp-8], eax  ; sum
 
    mov     eax, [ebp-4]
    cmp     eax, 100
    jle     short .Lelse
 
    mov     eax, [ebp-8]
    add     eax, [ebp-8]  ; sum*2
    jmp     short .Lend
 
.Lelse:
    mov     eax, [ebp-8]  ; sum
.Lend:
    mov     esp, ebp
    pop     ebp
    ret

// Функция: возвращает среднее арифметическое 6 аргументов
int avg6(int a, int b, int c, int d, int e, int f) {
    return (a + b + c + d + e + f) / 6;
}
avg6:
    sub     rsp, 28h            ; Shadow Space
    mov     eax, ecx            ; a
    add     eax, edx            ; b
    add     eax, r8d            ; c
    add     eax, r9d            ; d
    add     eax, [rsp+40h]      ; e (5-й)
    add     eax, [rsp+48h]      ; f (6-й)
    mov     ecx, 6
    cdq
    idiv    ecx                 ; eax = сумма / 6
    add     rsp, 28h
    ret

ASCII-графика: схема памятных мест после входа в avg6

                +----------------------+
[ rsp+48 ] ---> | f (6-й аргумент)     |
[ rsp+40 ] ---> | e (5-й аргумент)     |
[ rsp+28 ] ---> | shadow r9            |
[ rsp+20 ] ---> | shadow r8            |
[ rsp+18 ] ---> | shadow rdx           |
[ rsp+10 ] ---> | shadow rcx           |
[ rsp ]    ---> | (--- нижний rsp ---) |
                +----------------------+

Если функция делает вызовы других функций, ей иногда нужно сохранять свои аргументы из rcx/rdx/r8/r9 в shadow space (например, для их восстановления после вызова, который мог бы их затереть):

func:
    sub     rsp, 28h
    mov     [rsp], rcx          ; сохранить rcx в shadow space
    mov     [rsp+8], rdx
    mov     [rsp+16], r8
    mov     [rsp+24], r9
    ...
    ; вызовы других функций, которые могут менять rcx, rdx, r8, r9
    ...
    ; можно восстановить оригинальные аргументы отсюда
    add     rsp, 28h
    ret

RCX 1st           RDX 2nd
     |                |
   +----------+---------------+
   |R8 3rd    |R9 4th         |        5-й и далее — только на стеке!
   +----------+---------------+

Минимум 32 байта shadow space до любого вызова (для callee).


  • x64dbg: Если сразу после call идёт add rsp, 28h — это Win64 calling convention.
  • Если стек выделяется через sub esp, X и используются push — классическая x86.
  • При анализе vararg-функций (printf) всегда смотрите стек выше shadow space — там аргументы!
  • Если не виден frame pointer (rbp/ebp), локальные обычно через rsp/esp и смещение.
  • Проверяйте стек на выравнивание по 16 байтам в x64.

  • reverseenengineering/соглашения.1752677150.txt.gz
  • Последнее изменение: 2025/07/16 21:45
  • Lex