I need to write asm function in Delphi to search for max array element. So that wat I wrote.
Got few prolbems here.
First – mov ecx, len just dosen’t work in right way here. Actually it replaces value in ECX but not with value in len! And if I just wirte an example mov ecx, 5 there appears 5 in ecx.
Second – i test this function on array of 5 elements (using mov ecx, 5 ofc ) it returns some strange result. I think maybe because of I do someting worng when trying to read arrays 0 element like this
mov edx, arr
lea ebx, dword ptr [edx]
But if I read it like this
lea ebx, arr
it says that operation is invalid and if I try like this
lea bx, arr
it says that sizes mismatch.
How could I solve this problem? Full code here:
program Project2;
{$APPTYPE CONSOLE}
uses
SysUtils;
Type
TMyArray = Array [0..255] Of Byte;
function randArrCreate(len:Integer):TMyArray;
var temp:TMyArray; i:Integer;
begin
Randomize;
for i:=0 to len-1 do
temp[i]:=Random(100);
Result:= temp;
end;
procedure arrLoop(arr:TMyArray; len:Integer);
var i:integer;
begin
for i:=0 to len-1 do begin
Write(' ');
Write(arr[i]);
Write(' ');
end;
end;
function arrMaxAsm(arr:TMyArray; len:integer):Word; assembler;
asm
mov edx, arr
lea ebx, dword ptr [edx]
mov ecx, len
xor ax,ax //0
mov ax, [ebx] //max
@cycle:
mov dx, [ebx]
cmp dx, ax
jg @change
jmp @cont
@change:
mov ax, dx
@cont:
inc ebx
loop @cycle
mov result, ax
end;
var massive:TMyArray; n,res:Integer;
begin
Readln(n);
massive:=randArrCreate(n);//just create random array
arrLoop(massive,n);//just to show what in it
res:=arrMaxAsm(massive, n);
Writeln(res);
Readln(n);
end.
First off, calling conventions: what data is sent to the function and where?
According to the documentation, arrays are passed as 32-bit pointers to the data, and integers are passed as values.
According to the same documentation, multiple calling conventions are supported. Unfortunately, the default one isn’t documented – explicitly specifying one would be a good idea.
Based on your description that
mov ecx, lendoesn’t work, I’m guessing the compiler used theregisterconvention by default, and the arguments were already placed inecxandedx, then your code went and mixed them up. You can either change your code to work with that convention, or tell the compiler to pass the arguments using the stack – use thestdcallconvention. I arbitrarily picked the second option. Whichever one you pick, make sure to specify the calling convention explicitly.Next, actual function logic.
lea ebx, dword ptr [edx]is the same asmov ebx, edx. You’re just introducing another temporary variable.loop.ebxneeds to be preserved – because the function usesebx, its original value needs to be saved at the start and restored afterwards.This is how I rewrote your function (using Lazarus, because I haven’t touched Delphi in about 8 years – no compiler within reach):
It might be possible to optimize it further by reorganizing the loop jumps – YMMV.
Note: this will only work correctly for byte-sized unsigned values. To adapt it to values of different size/signedness, some changes need to be made:
Data size:
Mind that this reading is done in two places. If you’re dealing with dwords, you’ll also need to change the result from
axtoeax.Dealing with signed values:
The value extension, if it’s applied, needs to be changed from
movzxtomovsx.The conditional jump before setting new maximum needs to be adjusted: