Понимание концепции STDCALL против CDECL с очисткой EBP и ESP - PullRequest
2 голосов
/ 18 октября 2019

Мне кажется, я понимаю разницу между STDCALL и CDECL, но мне интересно, смогу ли я найти какое-то пояснение в этом коде.

Я понимаю, что в STDCALL CALLEE отвечает за очистку стека, иЯ понимаю, что в CDECL CALLER отвечает за очистку стека.

Я также понимаю, что "очистка стека" в основном означает переустановку указателя стека, но я предполагаю, что моя путаница появляется в этой строке кода, где значение esp перемещается в базовый указатель ebp. Если эта функция происходит, это то же самое, что «очистка стека»? Или это должно быть что-то особенное в ESP?

Вот код, на который я смотрю

main PROC
    push 4
    push 5
    call sub_12
    push 5
    call sub_48
    add esp, 4
    INVOKE ExitProcess, 0
main endp

sub_12 PROC
    push ebp
    mov ebp, esp
    mov eax, 10
    mul DWORD PTR [ebp+12]
    pop ebp
    ret 8
sub_12 endp

sub_48 PROC
    push ebp
    mov ebp, esp
    mov eax, [ebp+8]
    mul DWORD PTR [ebp+8]
    pop ebp
    ret
sub_48 endp

Мой первоначальный ответ заключается в том, что sub_12 и sub_48 оба являются CDECL, потому что вызывающий абонентотвечает за очистку стека. Но теперь я продолжаю смотреть на инструкции [mov ebp, esp], и мне интересно, действительно ли это пример STDCALL.

У кого-нибудь есть намеки на меня или какая-то дополнительная информация, которой мне может показаться не хватать?

1 Ответ

1 голос
/ 18 октября 2019

Вот хорошее обсуждение CDECL против STDCALL:

Независимо от соглашения о вызовах вызываемый, как правило, сохраняет текущий указатель стека на указатель кадра (EBP), чтобы он мог по своему желанию выгружать и извлекать локальные переменные в / из стека.

Когда он готов вернуться, вызываемый ДОЛЖЕН затем восстановить указатель стека (ESP), чтобы "возврат" завершился успешно.

В: Имеет смысл? Это отвечает на ваш вопрос?

ДОПОЛНИТЕЛЬНАЯ ИНФОРМАЦИЯ:

Есть две проблемы: 1) вызов подпрограммы (эта часть "stdcall" против "cdecl" (среди других - те, которые не 'только два варианта) и 2) возврат из подпрограммы.

Основное различие между CDECL и STDCALL заключается в том, кто отвечает за очистку стека для локальных переменных после «возврата».

Вызываемый объект ВСЕГДА восстанавливает указатель стека,Это единственный способ, которым «return» может работать правильно.

Для STDCALL вызываемый объект ТАКЖЕ очищает стек своих локальных переменных.

Грубо говоря:

  • STDCALL может использовать немного меньше места, потому что «код очистки» находится только в одном месте: в вызываемом объекте. Для вызовов CDECL очистка должна повторяться везде, где вызывается подпрограмма. Ваш пример sub_12 - «STDCALL».

  • CDECL более гибок: он позволяет передавать переменное число параметров в подпрограмму. Ваш пример sub_48 - "CDECL".

'Надеюсь, это поможет ...

...