Хенрик Хеллстрем прав в своем ответе , и я замечаю, что ваш вопрос помечен Delphi 2010 и, таким образом, касается только Win32.Однако вам может быть интересно посмотреть, как будет выглядеть ситуация, если вы перейдете к Win64 (Delphi> = XE2), поэтому я добавил пример версии Win64 в код Хенрика:
procedure CallObjMeth(AInstance, ACode: Pointer; const AStrValue: string; const AIntValue: Integer); stdcall;
asm
{$IFDEF CPU386}
MOV EAX, AInstance;
MOV EDX, DWORD PTR AStrValue;
MOV ECX, DWORD PTR AIntValue;
{$IFDEF MACOS}
//On MacOSX32 ESP = #######Ch here
SUB ESP, 0Ch
{$ENDIF}
CALL ACode;
{$IFDEF MACOS}
ADD ESP, 0Ch // restoring stack
{$ENDIF}
{$ENDIF}
{$IFDEF CPUX64}{$IFDEF WIN64} // <- see comments
.NOFRAME //Disable stack frame generation
//MOV RCX, AInstance {RCX} //<- not necessary because AInstance already is in RCX
MOV R10, ACode {RDX}
MOV RDX, AStrValue {R8}
MOV R8D, AIntValue {R9D}
SUB RSP, 28h //Set up stack shadow space and align stack: 4*8 bytes for 4 params + 8 bytes bytes for alignment
{$IFNDEF DO_NOT_TEST_STACK_ALIGNMENT}
MOVDQA XMM5, [RSP] //Ensure that RSP is aligned to DQWORD boundary -> exception otherwise
{$ENDIF}
CALL R10 //ACode
ADD RSP, 28h //Restore stack
{$ENDIF}{$ENDIF}
end;
Необходимо сделать несколько пояснительных замечаний:
1) ASM
оператор : в Delphi XE2 x64 нет смешивания кода на языке pascal и asm, поэтому единственный способ написатьассемблерный код находится в подпрограмме, которая состоит из одного блока asm..end
, а не begin..end
.Обратите внимание, что begin..end
вокруг вашего 32-битного кода ASM также имеет эффект.В частности, вы заставляете генерацию стекового фрейма и позволяете компилятору делать локальные копии параметров функции.(Если вы прибегаете к использованию ассемблера, вы, возможно, не захотите, чтобы компилятор делал это.)
2) Соглашение о вызовах : В Win64 существует только один вызовусловность.Такие вещи, как register
и stdcall
, фактически бессмысленны;это все то же самое, Соглашение Microsoft о вызовах Win64 .По сути, это так: параметры передаются в регистры RCX
, RDX
, R8
и R9
(и / или XMM0-XMM4
, возвращаемые значения в RAX/XMM0
. Через 64-битные значения передаются по ссылке.
Вызываемые функции могут использовать: RAX, RCX, RDX, R8-R11, ST(0)-ST(7), XMM0-XMM5, YMM0-YMM5, YMM6H-YMM15H
и должны сохранять RBX, RSI, RDI, RBP, R12-R15, XMM6-XMM15
. При необходимости вызываемые функции должны выдавать CLD
/ EMMS
/ VZEROUPPER
инструкции для восстановления ожидаемого ЦПstate.
3) Выравнивание и теневое пространство Важно, что каждая функция имеет свое собственное теневое пространство в стеке, которое равно как минимум 4 параметрам QWORD стекового пространства, даже если их нетparams и независимо от того, касается ли вызываемая функция этого.Более того, на месте каждого вызова функции (в каждом операторе CALL
) ожидается, что RSP
будет выровнен на 16 байт (то же самое для ESP
в MacOSX32, кстати).Это часто приводит к таким вещам, как: sub rsp, ##; call $$; add rsp, ##
конструкции, в которых ## будет суммой параметров (QWORD), с которыми должна вызываться функция, плюс дополнительные 8 байтов для выравнивания RSP
.Обратите внимание, что выравнивание RSP
на сайте CALL
приводит к RSP = ###8h
при входе в функцию (поскольку CALL
помещает адрес возврата в стек), поэтому, если никто не помешает с RSP
, прежде чем вы это сделаете, вы можетеожидайте, что это так.
В приведенном примере инструкция SSE2 MOVDQA
используется для проверки выравнивания RSP
.(XMM5
используется как регистр назначения, потому что он может быть свободно изменен, но не может содержать никаких данных параметров функции).
4) Допущения Код здесь предполагает, что компилятор не вставляет кодизменить RSP
.Могут быть ситуации, в которых это может быть неверно, поэтому остерегайтесь делать это предположение.
5) Обработка исключений Обработка исключений в Win64 немного сложна и должна быть правильно выполненакомпилятор (пример кода выше не делает этого).Чтобы компилятор мог это сделать, в идеале ваш код должен использовать новые директивы / псевдоинструкции BASM .PARAMS
, .PUSHNV
и .SAVENV
, обозначенные здесь Алленом Бауэром .При правильной (неправильной) ситуации в противном случае могут произойти плохие вещи.