vitaly_l писал(а):bormant писал(а):На ошибку компиляции внимания не обращаем... Смотрим на тела процедур и на вызов в одном и другом случае.
У меня получилось вот это:
Assembler masm.exe not found, Fatal...
Да, именно на неё не обращаем внимания, нам нужен был ассемблерный листинг, мы его получили в файле с расширением .s, например, если исходник назывался test.pas, то в файле test.s.
Немного поменял исходник для иллюстрации fascall, cdecl, pascal, stdcall:
- Код: Выделить всё
type
PChunkRec = ^TChunkRec;
TChunkRec = record
id: string;
size: integer;
data: Pointer;
end;
procedure Proc1(Chunk: TChunkRec; Data: Pointer);
begin
end;
procedure Proc2(Chunk: TChunkRec; Data: Pointer); cdecl;
begin
end;
procedure Proc3(Chunk: TChunkRec; Data: Pointer); pascal;
begin
end;
procedure Proc4(Chunk: TChunkRec; Data: Pointer); stdcall;
begin
end;
var
c: TChunkRec;
begin
Proc1(c, nil);
Proc2(c, nil);
Proc3(c, nil);
Proc4(c, nil);
end.
Смотрим на тела процедур и на код вызова, обращаем внимание на то, кто корректирует стек по завершении вызова.
Добавлено спустя 9 минут 18 секунд:Proc1, тело:
- Код: Выделить всё
PUBLIC P$PROGRAM_PROC1$TCHUNKREC$POINTER
P$PROGRAM_PROC1$TCHUNKREC$POINTER:
; Temps allocated between ebp-280 and ebp-8
; [test.pas]
; [10] begin
push ebp
mov ebp,esp
sub esp,280
mov dword ptr [ebp-280],esi
mov dword ptr [ebp-276],edi
; Var Chunk located at ebp-4
; Var Data located at ebp-8
mov dword ptr [ebp-4],eax
mov dword ptr [ebp-8],edx
mov esi,dword ptr [ebp-4]
lea edi,dword ptr [ebp-272]
cld
mov ecx,66
rep movsd
; [11] end;
mov esi,dword ptr [ebp-280]
mov edi,dword ptr [ebp-276]
leave
ret
Proc2, тело:
- Код: Выделить всё
PUBLIC P$PROGRAM_PROC2$TCHUNKREC$POINTER
P$PROGRAM_PROC2$TCHUNKREC$POINTER:
; Temps allocated between ebp+0 and ebp+0
; [14] begin
push ebp
mov ebp,esp
; Var Chunk located at ebp+8
; Var Data located at ebp+272
; [15] end;
leave
ret
Proc3, тело:
- Код: Выделить всё
PUBLIC P$PROGRAM_PROC3$TCHUNKREC$POINTER
P$PROGRAM_PROC3$TCHUNKREC$POINTER:
; Temps allocated between ebp-272 and ebp+0
; [18] begin
push ebp
mov ebp,esp
sub esp,272
mov dword ptr [ebp-272],esi
mov dword ptr [ebp-268],edi
; Var Chunk located at ebp+12
; Var Data located at ebp+8
mov esi,dword ptr [ebp+12]
lea edi,dword ptr [ebp-264]
cld
mov ecx,66
rep movsd
; [19] end;
mov esi,dword ptr [ebp-272]
mov edi,dword ptr [ebp-268]
leave
ret 8
Proc4, тело:
- Код: Выделить всё
PUBLIC P$PROGRAM_PROC4$TCHUNKREC$POINTER
P$PROGRAM_PROC4$TCHUNKREC$POINTER:
; Temps allocated between ebp+0 and ebp+0
; [22] begin
push ebp
mov ebp,esp
; Var Chunk located at ebp+8
; Var Data located at ebp+272
; [23] end;
leave
ret 268
Proc1, вызов:
- Код: Выделить всё
; [29] Proc1(c, nil);
mov eax,offset U_P$PROGRAM_C
mov edx,0
call P$PROGRAM_PROC1$TCHUNKREC$POINTER
Proc2, вызов:
- Код: Выделить всё
; [30] Proc2(c, nil);
push 0
sub esp,264
mov edi,esp
mov esi,offset U_P$PROGRAM_C
cld
mov ecx,66
rep movsd
call P$PROGRAM_PROC2$TCHUNKREC$POINTER
add esp,268
Proc3, вызов:
- Код: Выделить всё
; [31] Proc3(c, nil);
push offset U_P$PROGRAM_C
push 0
call P$PROGRAM_PROC3$TCHUNKREC$POINTER
Proc4, вызов:
- Код: Выделить всё
; [32] Proc4(c, nil);
push 0
sub esp,264
mov edi,esp
mov esi,offset U_P$PROGRAM_C
cld
mov ecx,66
rep movsd
call P$PROGRAM_PROC4$TCHUNKREC$POINTER
Добавлено спустя 44 минуты 29 секунд:Proc1, по умолчанию fastcall.
Вызывающий код в регистре eax передаёт указатель на C, в регистре edx передаёт Data.
Выполняется вызов процедуры.
Сгенерированная компилятором преамбула Proc1:
-- сохраняет в ebp указатель стека;
-- резервирует на стеке место для копий Chunk и Data;
-- копирует содержимое в локальные копии Chunk и Data.
Далее исполняется код процедуры (у нас пусто).
Перед возвратом из процедуры стек приводится в исходное значение.
Proc2, cdecl.
В стек укладываются параметры справа налево, сначала значение Data (nil, он же 0), затем в стек из C копируется содержимое Chunk.
Выполняется вызов процедуры.
Сгенерированная компилятором преамбула Proc1:
-- сохраняет в ebp указатель стека.
Далее исполняется код процедуры (у нас пусто).
Перед возвратом из процедуры стек приводится в значение перед вызовом.
Вызывающий код корректирует содержимое стека на размер Chunk и Data (268 байт).
Proc3, pascal.
В стек укаладываются параметры слева направо, сначала указатель на C, затем значние Data (nil, он же 0).
Выполняется вызов процедуры.
Сгенерированная компилятором преамбула Proc3:
-- сохраняет в ebp указатель стека;
-- резервирует на стеке место для копий Chunk и Data;
-- копирует содержимое в локальные копии Chunk и Data.
Далее исполняется код процедуры (у нас пусто).
Перед возвратом из процедуры стек приводится в исходное значение, дополнительно из него удаляются полученые параметры (8 байт, указатель на Chunk и Data).
Proc4, stdcall.
В стек укладываются параметры справа налево, сначала значение Data (nil, он же 0), затем в стек из C копируется содержимое локальной Chunk (66 двойных слов, 264 байта).
Выполняется вызов процедуры.
Сгенерированная компилятором преамбула Proc4:
-- сохраняет в ebp указатель стека.
Далее исполняется код процедуры (у нас пусто).
Перед возвратом из процедуры стек приводится в исходное значение, дополнительно из него удаляются полученые копии параметров, помещённые вызывающим кодом (268 байт).