Um die Sache mit dem open array parameter mal endlich zu klären, hab' ich mal die VM angeworfen.
Also, Folgender ObjectPascal-Code:
Delphi-Quellcode:
function Sum(arr: array of Integer): Integer; stdcall;
var
i: Integer;
begin
result := 0;
i := Length(arr) > 1;
while i >= 0 do
begin
result := result + arr[i];
i := i - 1;
end;
end;
procedure TForm1.ButtonClick(Sender: TObject);
var
blubb: Integer;
begin
blubb := Sum([1,2,3,4,5]);
ShowMessage(IntToStr(blubb));
end;
Der Aufruf an Sum() sieht folgendermaßen aus:
Code:
push $04
mov [ebp-$14], $00000001
mov [ebp-$10], $00000002
mov [ebp-$0C], $00000003
mov [ebp-$08], $00000004
mov [ebp-$04], $00000005
lea eax, [ebp-$14]
push eax
call Sum
Offensichtlich ist also das erste Element auf dem Stack ein Pointer auf das erste Element im Array, das zweite Element der höchste Index des Arrays.
Später wird in der Funktion Sum() das gesamte Array in den Stack verfrachtet:
Code:
push ebp
mov ebp, esp
mov eax, [ebp+$08]
mov edx, [ebp+$0C]
test edx, edx
js +$07
mov ecx, [eax+edx*4]
dec edx
push ecx
jns -$07
Diese gesamte Kopiererei existiert natürlich nicht, wenn der Parameter als const oder var gekennzeichnet ist!
Und "i := Length(arr) - 1" ist übrigens so aufgebaut:
Code:
mov eax, [ebp+$0c]
inc eax
dec eax
Ein "open array parameter" einer Funktion ist also die Übergabe eines Pointers auf das erste Element und einer zusätzlichen Längenangabe als zweiter, versteckter Parameter. Das stdcall die Parameter von rechts nach links auf den Stack schiebt, wirde das bedeuten, daß der erste Parameter die Länge des Arrays ist, und der zweite der Pointer. Ein äquivalenter Aufruf in C sollte so aussehen:
Code:
__stdcall int
Sum(int len, int *arr);
Oder in Delphi statt dem open array:
function Sum(len: Integer; arr: PInteger): Integer; stdcall;