I am having a problem to access an element of an array in assembly(delphi).
The code is:
procedure TMaskBit.AllocBuffer;
begin
SetLength(DataIn, 6); //array of integer
DataIn[0] := 1 ;
DataIn[1] := 2 ;
DataIn[2] := 3 ;
DataIn[3] := 4 ;
DataIn[4] :=5 ;
DataIn[5] := 6 ;
end;
procedure TMaskBit.SetValue();
asm
lea edx, [eax].TMaskBit.DataIn //indice
mov ecx, [edx+8] //second ement
mov [EAX].TMaskBit.Z, ecx
end;
What might be wrong?
Thanks!
Dynamic Array is a pointer, so you should use mov instead of lea:
type
TIntArray = array of Integer;
TMaskBit = class
Z: Integer;
DataIn: TIntArray;
procedure AllocBuffer;
procedure SetValue();
end;
procedure TMaskBit.AllocBuffer;
begin
SetLength(DataIn, 6); //array of integer
DataIn[0] := 1 ;
DataIn[1] := 2 ;
DataIn[2] := 3 ;
DataIn[3] := 4 ;
DataIn[4] :=5 ;
DataIn[5] := 6 ;
end;
procedure TMaskBit.SetValue();
asm
mov edx, [eax].TMaskBit.DataIn // edx references DataIn[0] !!!
mov ecx, [edx+8] // DataIn[2]
mov [EAX].TMaskBit.Z, ecx
end;
procedure TForm7.Button3Click(Sender: TObject);
var
MB: TMaskBit;
begin
MB:= TMaskBit.Create;
MB.AllocBuffer;
MB.SetValue;
ShowMessage(IntToStr(MB.Z));
end;
Related
Executing following code:
function ABCD32(Value: Cardinal): Single; register;
asm
BSWAP EAX
end;
function HexToFloat(hexValue: string; fmt: THexFloatFormat): Single;
var
c: Cardinal;
Err: Integer;
begin
Result := NaN;
c := HexToCardinal(hexValue, Err); //DCBA format
if Err <> 0 then Exit();
case fmt of
hfABCD: Result := ABCD32(c); //Here, after return from ABCD32
hfBADC: Result := BADC32(c);
hfCDAB: Result := CDAB32(c);
hfDCBA: Result := DCBA32(c);
end;
end;
causes a run-time errror:
Project HexFloat.exe raised exception class $C0000092 with message 'floating point stack check at 0x004e9903'.
What is this and how to handle it?
Update
Here is the CPU window output:
HexFloat.dpr.162: hfABCD: Result := ABCD32(c);
004E98F8 8B45F0 mov eax,[ebp-$10]
004E98FB E894FFFFFF call ABCD32
004E9900 D95DF4 fstp dword ptr [ebp-$0c] //WTF?
004E9903 9B wait //Exception happens here
004E9904 EB28 jmp $004e992e
Your function does not respect the ABI. Floating point values should be returned in ST(0) on the x87 unit.
function ABCD32(Value: Cardinal): Single; register;
asm
BSWAP EAX
PUSH EAX
FLD [ESP]
ADD ESP,4
end;
I present you a bug in the Delphi 5 compiler. I know there's not going to be any fix for it; but a workaround would be super
program Project1;
uses
Dialogs, SysUtils;
{$R *.RES}
type
IFoo = interface
['{D68DA49A-F870-433D-9343-4964BFECFF27}']
procedure Grob(a: Integer; b: Integer);
end;
TFoo = class(TInterfacedObject, IFoo)
public
procedure Grob(a: Integer; b: Integer); virtual;
end;
procedure TFoo.Grob(a: Integer; b: Integer);
begin
end;
function DoStuff(): Integer;
var
foo: IFoo;
begin
foo := TFoo.Create;
try
Result := 1;
Exit;
finally
foo.Grob(0, 0);
end;
Result := 2;
end;
var
n: Integer;
begin
n := DoStuff;
if n <> 0 then
ShowMessage('Failed: '+IntToStr(n))
else
ShowMessage('Passed: '+IntToStr(n));
end.
The real guts is the function DoStuff which should return one:
function DoStuff(): Integer;
var
foo: IFoo;
begin
foo := TFoo.Create;
try
Result := 1;
Exit;
finally
foo.Grob(0, 0);
end;
Result := 2;
end;
The function should return one. Instead it returns the address of the interfaced object:
The assembly
The code actually does start to set the result to one:
Project1.dpr.30: Result := 1;
mov ebx,$00000001 ; place return value 1 in EBX
Project1.dpr.31: Exit;
call #TryFinallyExit ; call the finally block
jmp DoStuff + $6E
and as the function is about to return, it does copy EBX into EAX in order to return it:
mov eax,ebx ;EBX into EAX for return
But finally block (calling the interfaced method) is the problem. It blows away the return value stored in EBX:
We arrive here from the call #TryFinallyExit
Project1.dpr.33: foo.Grob(0, 0);
xor ecx,ecx
xor edx,edx
mov eax,[ebp-$04]
mov ebx,[eax] <----- overwriting ebx with interface address
call dword ptr [ebx+$0c]
ret
After the "call" to the finally block, it returns to a jump, which sends it to:
Project1.dpr.36: Result := 2;
...
xor eax,eax
pop edx
pop ecx
pop ecx
mov fs:[eax],edx
push $00442e1f
lea eax,[ebp-$04]
call #IntfClear
ret
...
mov eax,ebx <----- places overwritten EBX into EAX for return
Project1.dpr.37: end;
pop ebx
pop ecx
pop ebp
ret
The return value rather than being one, or two, is the address of the interface pointer.
I know none of you have Delphi 5. And even if you did,
"What would you like me to say?"
I know the difficulty. What i actually need is some sort of workaround.
As you observed, the compiler is storing the result into EBX, but then overwriting it before it subsequently copies EBX into EAX to return the result to the caller.
The compiler should be doing one of the following:
Using a different register to store the result value temporarily, so that its use of EBX does not destroy the result value, or
Not using EBX in the call to Grob, or
Storing the result value in something more persistent than a register, like on the stack.
Obviously options 1 and 2 are not readily available to you, but the latter is the workaround that you need to implement in this example – use a local variable to hold your intended Result value until you are ready to return it:
function DoStuff(): Integer;
var
foo: IFoo;
MyResult: Integer;
begin
foo := TFoo.Create;
try
try
MyResult := 1;
Exit;
finally
foo.Grob(0, 0);
end;
MyResult := 2;
finally
Result := MyResult;
end;
end;
I'm so new to Delphi 7, also in this forum and I've questions.
I have successfully converted an url string to hex using Jorlen Young's function StrToHex - Advanced Encryption Standard (AES) Interface Unit v1.3!.
But, when I implement his function EncryptString, then I got error at the very bottom of my code: Encrypt := EncryptString('www.website.com'); with the following messsage:
[Hint] Unit1.pas(xx): Variable 'st' is declared but never used in 'EncryptString'
[Error] Unit1.pas(xx): Not enough actual parameters
[Fatal Error] Project1.dpr(5): Could not compile used unit 'Unit1.pas'
Could you give me some tips in how to implement the "Key" and "KeyBit" option into my syntax: Encrypt := EncryptString('www.website.com'); ?
I would appreciate any help.
...here is my code :
.....................
.....................
type
TKeyBit = (kb128, kb192, kb256);
.....................
.....................
procedure IdMappedPortTCP1Execute(AThread: TIdMappedPortThread);
private
{ Private declarations }
public
{ Public declarations }
end;
implementation
function StrToHex(Const str: Ansistring): Ansistring;
asm
push ebx
push esi
push edi
test eax,eax
jz ##Exit
mov esi,edx
mov edi,eax
mov edx,[eax-4]
test edx,edx
je ##Exit {Length(S) = 0}
mov ecx,edx
Push ecx
shl edx,1
mov eax,esi
{$IFDEF VER210}
movzx ecx, word ptr [edi-12]
{$ENDIF}
call System.#LStrSetLength
mov eax,esi
Call UniqueString
Pop ecx
##SetHex:
xor edx,edx
mov dl, [edi]
mov ebx,edx
shr edx,4
mov dl,byte ptr[edx+##HexChar]
mov [eax],dl
and ebx,$0F
mov dl,byte ptr[ebx+##HexChar]
inc eax
mov [eax],dl
inc edi
inc eax
loop ##SetHex
##Exit:
pop edi
pop esi
pop ebx
ret
##HexChar: db '0123456789ABCDEF'
end;
function EncryptString(Value: AnsiString; Key: AnsiString; KeyBit: TKeyBit = kb128): AnsiString;
var
{$IFDEF VER210}
SS,DS: TMemoryStream;
{$ELSE}
SS, DS: TStringStream;
{$ENDIF}
Size: Int64;
AESKey128: TAESKey128;
AESKey192: TAESKey192;
AESKey256: TAESKey256;
st: AnsiString;
begin
Result := '';
{$IFDEF VER210}
ss := TMemoryStream.Create;
SS.WriteBuffer(PAnsiChar(Value)^,Length(Value));
DS := TMemoryStream.Create;
{$ELSE}
SS := TStringStream.Create(Value);
DS := TStringStream.Create('');
{$ENDIF}
try
Size := SS.Size;
DS.WriteBuffer(Size, SizeOf(Size));
if KeyBit = kb128 then
begin
FillChar(AESKey128, SizeOf(AESKey128), 0 );
Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key)));
EncryptAESStreamECB(SS, 0, AESKey128, DS);
end;
if KeyBit = kb192 then
begin
FillChar(AESKey192, SizeOf(AESKey192), 0 );
Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key)));
EncryptAESStreamECB(SS, 0, AESKey192, DS);
end;
if KeyBit = kb256 then
begin
FillChar(AESKey256, SizeOf(AESKey256), 0 );
Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key)));
EncryptAESStreamECB(SS, 0, AESKey256, DS);
end;
{$IFDEF VER210}
SetLength(st,Ds.Size);
DS.Position := 0;
DS.ReadBuffer(PAnsiChar(st)^,DS.Size);
Result := StrToHex(st);
{$ELSE}
Result := StrToHex(DS.DataString);
{$ENDIF}
finally
SS.Free;
DS.Free;
end;
end;
procedure TForm1.IdMappedPortTCP1Execute(AThread: TIdMappedPortThread);
var Payload, Encrypt:String;
begin
Encrypt := EncryptString('www.website.com');
if Pos('CONNECT',AThread.NetData)<>0 then
begin
if host.Text = 'Operator' then
begin
Athread.OutboundClient.Write(Athread.NetData+#13#10);
Payload := 'GET http://'+Encrypt+'/ HTTP/1.1'+#13#10;
Athread.NetData:= Athread.NetData+Payload;
end;
end;
end.
Cheers,
RzV
EncryptString has 2 required and one optional parameter. You need at least to provide the key.
I am trying to rewrite the TList.IndexOf method in assembler (XE3). Here is my code
function TFastList.IndexOfAsm(Item: Pointer): Integer;
{var
P: PPointer;
begin
P := Pointer(FList);
for Result := 0 to FCount - 1 do
begin
if P^ = Item then
Exit;
Inc(P);
end;
Result := -1;}
var
FCnt, rslt: Integer;
FData: Pointer;
begin
FCnt := Count;
FData := List;
asm
push edi
mov ecx, FCnt
mov edi, FData
mov eax, Item
repne scasd
mov eax, FCnt
sub eax, ecx
dec eax
mov rslt, eax
pop edi
end;
Result := rslt;
end;
Naturally I would like to use the properties like Count or List directly. I understand why the compiler refuses to give access to private fields FCount and FList, but how do I access the corresponding properties? Count, Self.Count, and [eax].Count all give the inline assembler error.
JIC: I don't handle the not found situation here by intent
You can't access the object property via Delphi assembler!
Delphi compiler is good and Delphi compiled code I belive is also very fast.
Your code has mistake because doesn't test zero count velue what should cause memory access violation!
Do not use repne scasd because it is slow.
However you can hack code manualy to make test... :)
function TFastList.IndexOfAsm(Item: Pointer): Integer;
//eax = self
//edx = Item
{var
P: PPointer;
begin
P := Pointer(FList);
for Result := 0 to FCount - 1 do
begin
if P^ = Item then
Exit;
Inc(P);
end;
Result := -1;}
const
FItems = 4; //data offset of FItems
FCount = 8; //data offset of FCount
asm
mov ecx, [eax].FItems //ecx = #FItems
mov eax, [eax].FCount //eax = FCount
dec eax //test zero count!
js #Exit //if count was 0 then exit as -1
#Loop: //repeat
cmp Item, [ecx + eax * 4]
jz #Exit
dec eax
jns #Loop //until eax < 0 (actually -1)
#Exit:
end;
I am trying to implement FNV hash from http://isthe.com/chongo/tech/comp/fnv/
I converted the PowerBasic's inline asm on that page into Delphi.
function ReadFileToMem(sPath:string):Pointer;
var
hFile: THandle;
pBuffer: Pointer;
dSize: DWORD;
dRead: DWORD;
begin
hFile := CreateFile(PChar(sPath), GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, 0, 0);
if hFile <> 0 then
dSize := GetFileSize(hFile, nil);
if dSize <> 0 then
begin
SetFilePointer(hFile, 0, nil, FILE_BEGIN);
GetMem(Result, dSize);
ReadFile(hFile, Result^, dSize, dRead, nil);
if dRead = 0 then
MessageBox(0, PChar('Error reading file.'), PChar('Read Error'), MB_ICONEXCLAMATION)
end;
CloseHandle(hFile);
end;
function GetPointerSize(lpBuffer: Pointer): Cardinal; // Function by ErazerZ
begin
if lpBuffer = nil then
Result := Cardinal(-1)
else
Result := Cardinal(Pointer(Cardinal(lpBuffer) -4)^) and $7FFFFFFC -4;
end;
FUNCTION FNV32( dwOffset : Pointer; dwLen : DWORD; offset_basis : DWORD) : DWORD ;
asm
mov esi, dwOffset //;esi = ptr to buffer
mov ecx, dwLen //;ecx = length of buffer (counter)
mov eax, offset_basis //;set to 2166136261 for FNV-1
mov edi, 16777619//&h01000193 //;FNV_32_PRIME = 16777619
xor ebx, ebx //;ebx = 0
#nextbyte:
mul edi //;eax = eax * FNV_32_PRIME
mov bl, [esi] //;bl = byte from esi
xor eax, ebx //;al = al xor bl
inc esi //;esi = esi + 1 (buffer pos)
dec ecx //;ecx = ecx - 1 (counter)
jnz #nextbyte //;if ecx is 0, jmp to NextByte
mov #result, eax //;else, function = eax
end;
procedure TForm1.Button1Click(Sender: TObject);
var
pFile : Pointer;
hFile : Cardinal;
begin
//Profiler1['Test'].Start;
pFile := ReadFileToMem(fn);
hFile := FNV32(pFile,GetPointerSize(pFile),2166136261);
//Profiler1['Test'].Stop;
//OutputDebugString(pchar(Profiler1['Test'].AsText[tiAll]));
OutputDebugString(pchar(inttostr(hFile)));
end;
If a size of given file is more that 200KB, the output is random (hash) number. Am I missing something?
Your asm code is somewhat buggy, IMHO. It will crash your application, as it is written.
You need to preseve esi/edi/ebx registers
parameters are passed in eax,ecx,edx registers
result is the eax register
Correct way to do it could be (not tested, just written here there):
function fnv32(dwOffset : Pointer; dwLen : DWORD; offset_basis: DWORD) : DWORD ;
asm // eax=dwOffset ecx=dwLen edx=offset_basis -> result in eax
push esi
push edi
mov esi,eax
mov eax,edx
or ecx,ecx
je #z
mov edi,16777619
xor edx,edx
#1:
mul edi
mov dl,[esi]
xor eax,edx
inc esi
dec ecx
jnz #1
#z:
pop edi
pop esi
end;
So to read and hash any file, in a pure Delphi way (don't use Windows API like you did):
function fnv32file(const aFileName: TFileName): DWORD;
begin
with TMemoryStream.Create do
try
LoadFromFile(aFileName);
result := fnv32(Memory,Size,0);
finally
Free;
end;
end;
A pure pascal version won't be much slower IMHO (the bottleneck is definitively reading the data from the hard drive):
function fnv32(dwOffset : PByteArray; dwLen : DWORD; offset_basis: DWORD): DWORD ;
var i: integer;
begin
result := offset_basis;
for i := 0 to dwLen-1 do
result := (result*16777619) xor DWORD(dwOffset^[i]);
end;
Where should I start ...
1) CreateFile returns INVALID_HANDLE_VALUE on failure, not 0.
2) SetFilePointer is not necessary.
3) What if you have to hash 16 GB file?
4) You are not releasing allocated memory - FreeMem(pFile).
5) GetPointerSize is a total hack. You could just return file size from ReadFileToMem.
The following code is a rewrite of your approach. It still loads complete file into the memory but is implemented "the Delphi way".
function ReadFileToMem(const sPath: string; var buffer: TMemoryStream): boolean;
var
fileStr: TFileStream;
begin
Result := false;
try
fileStr := TFileStream.Create(sPath, fmOpenRead);
try
buffer.Size := 0;
buffer.CopyFrom(fileStr, 0);
finally FreeAndNil(fileStr); end;
Result := true;
except
on E: EFOpenError do
ShowMessage('Error reading file. ' + E.Message);
end;
end;
function FNV32(dwOffset: pointer; dwLen: cardinal; offset_basis: cardinal): cardinal;
asm
mov esi, dwOffset //;esi = ptr to buffer
mov ecx, dwLen //;ecx = length of buffer (counter)
mov eax, offset_basis //;set to 2166136261 for FNV-1
mov edi, 16777619//&h01000193 //;FNV_32_PRIME = 16777619
xor ebx, ebx //;ebx = 0
#nextbyte:
mul edi //;eax = eax * FNV_32_PRIME
mov bl, [esi] //;bl = byte from esi
xor eax, ebx //;al = al xor bl
inc esi //;esi = esi + 1 (buffer pos)
dec ecx //;ecx = ecx - 1 (counter)
jnz #nextbyte //;if ecx is 0, jmp to NextByte
mov #result, eax //;else, function = eax
end;
procedure TForm16.Button1Click(Sender: TObject);
var
hFile : cardinal;
memBuf: TMemoryStream;
begin
memBuf := TMemoryStream.Create;
try
if ReadFileToMem('SomeFile', memBuf) then begin
hFile := FNV32(memBuf.Memory, memBuf.Size, 2166136261);
ShowMessageFmt('Hash = %d', [hFile]);
end;
finally FreeAndNil(memBuf); end;
end;
Enjoy
function fnv(dwOffset : Pointer; dwLen : NativeUInt; offset_basis: NativeUInt) : NativeUInt ;
//
// http://find.fnvhash.com/ - FNV Hash Calculator Online
// http://www.isthe.com/chongo/tech/comp/fnv/
//
// The offset_basis for FNV-1 is dependent on n, the size of the hash:
// 32 bit offset_basis = 2166136261
// 64 bit offset_basis = 14695981039346656037
//
{$IF Defined(CPUX86)}
asm
push ebp
push edi
push ebx // statement must preserve the EDI, ESI, ESP, EBP, and EBX registers
mov ebp, edx
mov edx, ecx // but can freely modify the EAX, ECX, and EDX registers
mov ecx, eax
mov eax, edx
mov edi, 01000193h
xor ebx, ebx
##nexta:
mov bl, byte ptr [ecx]
xor eax, ebx
mul edi
inc ecx
dec ebp
jnz ##nexta
pop ebx
pop edi
pop ebp
end;
{$ELSEIF Defined(CPUX64)}
asm
mov rax, R8
mov r8, rdx
mov r9, 100000001b3h
xor r10, r10
##nexta:
mov r10b, byte ptr [rcx]
xor rax, r10
mul r9
inc rcx
dec r8
jnz ##nexta
end;
{$IFEND}