Why eax gives zero if it contains self? - delphi

According to the "Using Assembler in Delphi", eax will contain Self. However, the content of eax is 0 as shown. I wonder what is wrong ?
procedure TForm1.FormCreate(Sender: TObject);
var
X, Y: Pointer;
begin
asm
mov X, eax
mov Y, edx
end;
ShowMessage(IntToStr(NativeInt(X)) + ' ; ' + IntToStr(NativeInt(Y)));
end;

The code generated when I compile this, under debug settings, is like so:
begin
005A9414 55 push ebp
005A9415 8BEC mov ebp,esp
005A9417 83C4E4 add esp,-$1c
005A941A 33C9 xor ecx,ecx
005A941C 894DEC mov [ebp-$14],ecx
005A941F 894DE8 mov [ebp-$18],ecx
005A9422 894DE4 mov [ebp-$1c],ecx
005A9425 8955F0 mov [ebp-$10],edx
005A9428 8945F4 mov [ebp-$0c],eax
005A942B 33C0 xor eax,eax
005A942D 55 push ebp
005A942E 6890945A00 push $005a9490
005A9433 64FF30 push dword ptr fs:[eax]
005A9436 648920 mov fs:[eax],esp
mov X, eax
005A9439 8945FC mov [ebp-$04],eax
mov Y, edx
005A943C 8955F8 mov [ebp-$08],edx
When the code starts executing, eax is indeed the self pointer. But the compiler has chosen to save it away to ebp-$0c and then zeroise eax. That's really up to the compiler.
The code under release settings is quite similar. The compiler still chooses to zeroise eax. Of course, you cannot rely on the compiler doing that.
begin
005A82A4 55 push ebp
005A82A5 8BEC mov ebp,esp
005A82A7 33C9 xor ecx,ecx
005A82A9 51 push ecx
005A82AA 51 push ecx
005A82AB 51 push ecx
005A82AC 51 push ecx
005A82AD 51 push ecx
005A82AE 33C0 xor eax,eax
005A82B0 55 push ebp
005A82B1 6813835A00 push $005a8313
005A82B6 64FF30 push dword ptr fs:[eax]
005A82B9 648920 mov fs:[eax],esp
mov X, eax
005A82BC 8945FC mov [ebp-$04],eax
mov Y, edx
005A82BF 8955F8 mov [ebp-$08],edx
Remember that parameter passing defines the state of registers and stack when the function starts executing. What happens next, how the function decodes the parameters is down to the compiler. It is under no obligation to leave untouched the registers and stack that were used for parameter passing.
If you inject asm into the middle of a function, you cannot expect the volatile registers like eax to have particular values. They will hold whatever the compiler happened to put in them most recently.
If you want to examine the registers at the very beginning of the execution of the function, you need to use a pure asm function to be sure to avoid having the compiler modify the registers that were used for parameter passing:
var
X, Y: Pointer;
asm
mov X, eax
mov Y, edx
// .... do something with X and Y
end;
The compiler will make its choices very much dependent on the code in the rest of the function. For your code, the complexity of assembling the string to pass to ShowMessage causes quite a large preamble. Consider this code instead:
type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
private
i: Integer;
function Sum(j: Integer): Integer;
end;
....
procedure TForm1.FormCreate(Sender: TObject);
begin
i := 624;
Caption := IntToStr(Sum(42));
end;
function TForm1.Sum(j: Integer): Integer;
var
X: Pointer;
begin
asm
mov X, eax
end;
Result := TForm1(X).i + j;
end;
In this case the code is simple enough for the compiler to leave eax alone. The optimised release build code for Sum is:
begin
005A8298 55 push ebp
005A8299 8BEC mov ebp,esp
005A829B 51 push ecx
mov X, eax
005A829C 8945FC mov [ebp-$04],eax
Result := TForm4(X).i + j;
005A829F 8B45FC mov eax,[ebp-$04]
005A82A2 8B80A0030000 mov eax,[eax+$000003a0]
005A82A8 03C2 add eax,edx
end;
005A82AA 59 pop ecx
005A82AB 5D pop ebp
005A82AC C3 ret
And when you run the code, the form's caption is changed to the expected value.
To be perfectly honest, inline assembly, placed as an asm block inside a Pascal function, is not very useful. The thing about writing assembly is that you need to fully understand the state of the registers and the stack. that is well defined at the beginning and end of a function, defined by the ABI.
But in the middle of a function, that state depends entirely on the decisions made by the compiler. Injecting asm blocks in there requires you to know the decisions the compiler made. It also means that the compiler cannot understand the decisions that you made. This is usually impractical. Indeed for the x64 compiler Embarcadero banned such inline asm blocks. I personally have never used an inline asm block in my code. If ever I write asm I always write pure asm functions.

Just use the Push/Pop to get the pointer of SELF, and then use properties freely, like this:
asm
push Self
pop edx //Now, [edx] is the pointer to Self
mov ecx, [edx].FItems //ecx = FItems
mov eax, [edx].FCount //eax = FCount
dec eax //test zero count!
js #Exit //if count was 0 then exit as -1
#Loop: //and so on...
......

Related

converting ASM instruction RDRand to Win64

I have this function (RDRand - written by David Heffernan) that seam to work ok in 32 bit, but failed in 64 bit :
function TryRdRand(out Value: Cardinal): Boolean;
{$IF defined(CPU64BITS)}
asm .noframe
{$else}
asm
{$ifend}
db $0f
db $c7
db $f1
jc #success
xor eax,eax
ret
#success:
mov [eax],ecx
mov eax,1
end;
doc of the function is here: https://software.intel.com/en-us/articles/intel-digital-random-number-generator-drng-software-implementation-guide
Especially it's written :
Essentially, developers invoke this instruction with a single operand:
the destination register where the random value will be stored. Note
that this register must be a general purpose register, and the size of
the register (16, 32, or 64 bits) will determine the size of the
random value returned.
After invoking the RDRAND instruction, the caller must examine the
carry flag (CF) to determine whether a random value was available at
the time the RDRAND instruction was executed. As Table 3 shows, a
value of 1 indicates that a random value was available and placed in
the destination register provided in the invocation. A value of 0
indicates that a random value was not available. In current
architectures the destination register will also be zeroed as a side
effect of this condition.
My knowledge of ASM is quite low, what did I miss ?
Also I do not quite understand this instruction :
...
xor eax,eax
ret
...
What it's does exactly ?
If you want a function that performs exactly the same then I think that looks like this:
function TryRdRand(out Value: Cardinal): Boolean;
asm
{$if defined(WIN64)}
.noframe
// rdrand eax
db $0f
db $c7
db $f0
jnc #fail
mov [rcx],eax
{$elseif defined(WIN32)}
// rdrand ecx
db $0f
db $c7
db $f1
jnc #fail
mov [eax],ecx
{$else}
{$Message Fatal 'TryRdRand not implemented for this platform'}
{$endif}
mov eax,1
ret
#fail:
xor eax,eax
end;
The suggestion made by Peter Cordes of implementing a retry loop in the asm looks sensible to me. I will not attempt to implement that here, since I think it is somewhat outside the scope of your question.
Also, Peter points out that in x64 you can read a 64 bit random value with the REX.W=1 prefix. That would look like this:
function TryRdRand(out Value: NativeUInt): Boolean;
asm
{$if defined(WIN64)}
.noframe
// rdrand rax
db $48 // REX.W = 1
db $0f
db $c7
db $f0
jnc #fail
mov [rcx],rax
{$elseif defined(WIN32)}
// rdrand ecx
db $0f
db $c7
db $f1
jnc #fail
mov [eax],ecx
{$else}
{$Message Fatal 'TryRdRand not implemented for this platform'}
{$endif}
mov eax,1
ret
#fail:
xor eax,eax
end;

Testing string length generates more code than comparing to empty string?

In Delphi, string <> '' seems to generate less code than Length(string) > 0.
Comparing for empty string, defined in TMyClass.UpdateString(const strMyString : String):
MyClassU.pas.31: begin
005CE6A0 55 push ebp
005CE6A1 8BEC mov ebp,esp
005CE6A3 83C4F8 add esp,-$08
005CE6A6 8955F8 mov [ebp-$08],edx
005CE6A9 8945FC mov [ebp-$04],eax
MyClassU.pas.32: if (strMyString <> '') then
005CE6AC 837DF800 cmp dword ptr [ebp-$08],$00
005CE6B0 740E jz $005ce6c0
As I understand it, this is comparing the address of the dynamically allocated string ([ebp-$08]) to zero. Makes sense, since empty strings point to nil.
Comparing for length, defined in TMyClass.UpdateString2(const strMyString : String):
MyClassU.pas.25: begin
005CE664 55 push ebp
005CE665 8BEC mov ebp,esp
005CE667 83C4F4 add esp,-$0c
005CE66A 8955F8 mov [ebp-$08],edx
005CE66D 8945FC mov [ebp-$04],eax
005CE670 8B45F8 mov eax,[ebp-$08]
MyClassU.pas.26: if (Length(strMyString) > 0) then
005CE673 8945F4 mov [ebp-$0c],eax
005CE676 837DF400 cmp dword ptr [ebp-$0c],$00
005CE67A 740B jz $005ce687
005CE67C 8B45F4 mov eax,[ebp-$0c]
005CE67F 83E804 sub eax,$04
005CE682 8B00 mov eax,[eax]
005CE684 8945F4 mov [ebp-$0c],eax
005CE687 837DF400 cmp dword ptr [ebp-$0c],$00
005CE68B 7E0E jle $005ce69b
What? Should't it just be cmp dword ptr [ebp-$04],$00, as the string length is stored at offset -$04 within the string?
My guess is it's because optimizations were off and the compiler did not optimize Lenght (boils down to PInteger(PByte(S) - 4)^), but I don't understand why there are two comparisons. In fact both comparisons are present even with optimizations turned on:
MyClassU.pas.27: if (Length(strMyString) > 0) then
005CE6B1 8BC6 mov eax,esi
005CE6B3 85C0 test eax,eax
005CE6B5 7405 jz $005ce6bc
005CE6B7 83E804 sub eax,$04
005CE6BA 8B00 mov eax,[eax]
005CE6BC 85C0 test eax,eax
005CE6BE 7E0A jle $005ce6ca
vs
MyClassU.pas.33: if (strMyString <> '') then
005CE6D9 85F6 test esi,esi
005CE6DB 740A jz $005ce6e7
The second block of code does more work, and not surprisingly that takes more code.
In the first block of code you simply compare against the empty string. The compiler knows that is equivalent to comparing the pointer against nil and generates that code.
The second block of code first obtains the length of the string. That involves checking whether the pointer is nil. If it is, then the length is zero. Otherwise the length is read from the string meta data record.
The compiler simply does not know that every time the pointer is not nil, the length must be positive and so is not able to optimise.
As for why Length doesn't read from the string record directly, that should be obvious now. An empty string is implemented as the nil pointer and so has no string record. In order to find the length you need to deal with two different cases:
String is empty, length is 0.
String is not empty, length is read from the string record.

How to receive string as function result while calling Delphi code with asm? [duplicate]

I am trying to learn inline assembly programming in Delphi, and to this end I have found this article highly helpful.
Now I wish to write an assembly function returning a long string, specifically an AnsiString (for simplicity). I have written
function myfunc: AnsiString;
asm
// eax = #result
mov edx, 3
mov ecx, 1252
call System.#LStrSetLength
mov [eax + 0], ord('A')
mov [eax + 1], ord('B')
mov [eax + 2], ord('C')
end;
Explanation:
A function returning a string has an invisible var result: AnsiString (in this case) parameter, so, at the beginning of the function, eax should hold the address of the resulting string. I then set edx and ecx to 3 and 1252, respectively, and then call System._LStrSetLength. In effect, I do
_LStrSetLength(#result, 3, 1252)
where 3 is the new length of the string (in characters = bytes) and 1252 is the standard windows-1252 codepage.
Then, knowing that eax is the address of the first character of the string, I simply set the string to "ABC". But it does not work - it gives me nonsense data or EAccessViolation. What is the problem?
Update
Now we have two seemingly working implementations of myfunc, one employing NewAnsiString and one employing LStrSetLength. I cannot help but wonder if both of them are correct, in the sense that they do not mess upp Delphi's internal handling of strings (reference counting, automatic freeing, etc.).
You have to use some kind of:
function myfunc: AnsiString;
asm
push eax // save #result
call system.#LStrClr
mov eax,3 {Length}
{$ifdef UNICODE}
mov edx,1252 // code page for Delphi 2009/2010
{$endif}
call system.#NewAnsiString
pop edx
mov [edx],eax
mov [eax],$303132
end;
It will return a '210' string...
And it's always a good idea of putting a {$ifdef UNICODE} block to have your code compatible with version of Delphi prior to 2009.
With the excellent aid of A.Bouchez, I managed to correct my own code, employing LStrSetLength:
function myfunc: AnsiString;
asm
push eax
// eax = #result
mov edx, 3
mov ecx, 1252
call System.#LStrSetLength
pop eax
mov ecx, [eax]
mov [ecx], 'A'
mov [ecx] + 1, 'B'
mov [ecx] + 2, 'C'
end;

What is the Delphi equivalent to the C __builtin_clz()?

Quoted from https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html,
— Built-in Function: int __builtin_clz (unsigned int x)
Returns the number of leading 0-bits in x, starting at the most significant bit position. If x is 0, the result is undefined.
What is the Delphi equivalent to the C __builtin_clz() ? If there isn't, how to implement it efficiently in Delphi?
Actually, I want to use it to calculate the base-2 logarithm of an integer.
If you only care about 32 bit code then it goes like this:
function __builtin_clz(x: Cardinal): Cardinal;
asm
BSR EAX,EAX
NEG EAX
ADD EAX,32
end;
Or if you want to support 64 bit code as well then it would be:
function __builtin_clz(x: Cardinal): Cardinal;
{$IF Defined(CPUX64)}
asm
BSR ECX,ECX
NEG ECX
ADD ECX,31
MOV EAX,ECX
{$ENDIF}
{$IF Defined(CPUX86)}
asm
BSR EAX,EAX
NEG EAX
ADD EAX,31
{$ENDIF}
end;
It's likely that an asm guru could trim this down a little, but BSR (bit scan reverse) is the key instruction.
For the mobile compilers, I don't know how to do this efficiently.

unusual behaviour in delphi assembly block

I am running into some weird behaviour with Delphi's inline assembly, as demonstrated in this very short and simple program:
program test;
{$APPTYPE CONSOLE}
uses
SysUtils;
type
TAsdf = class
public
int: Integer;
end;
TBlah = class
public
asdf: TAsdf;
constructor Create(a: TAsdf);
procedure Test;
end;
constructor TBlah.Create(a: TAsdf);
begin
asdf := a;
end;
procedure TBlah.Test;
begin
asm
mov eax, [asdf]
end;
end;
var
asdf: TAsdf;
blah: TBlah;
begin
asdf := TAsdf.Create;
blah := TBlah.Create(asdf);
blah.Test;
readln;
end.
It's just for the sake of example (moving [asdf] into eax doesn't do much, but it works for the example). If you look at the assembly for this program, you'll see that
mov eax, [asdf]
has been turned into
mov eax, ds:[4]
(as represented by OllyDbg) which obviously crashes. However, if you do this:
var
temp: TAsdf;
begin
temp := asdf;
asm
int 3;
mov eax, [temp];
end;
It changes to
mov eax, [ebp-4]
which works. Why is this? I'm usually working with C++ and I'm used to using instance vars like that, it may be that I'm using instance variables wrong.
EDIT: Yep, that was it. Changing mov eax, [asdf] to mov eax, [Self.asdf] fixes the problem. Sorry about that.
In the first case, mov eax,[asdf], the assembler will look up asdf and discover it is a field of offset 4 in the instance. Because you used an indirect addressing mode without a base address, it will only encode the offset (it looks like 0 + asdf to the assembler). Had you written it like this: mov eax, [eax].asdf, it would have been encoded as mov eax, [eax+4]. (here eax contains Self as passed in from the caller).
In the second case, the assembler will look up Temp and see that it is a local variable indexed by EBP. Because it knows the base address register to use, it can decide to encode it as [EBP-4].
A method receives the Self pointer in the EAX register. You have to use that value as the base value for accessing the object. So your code would be something like:
mov ebx, TBlah[eax].asdf
See http://www.delphi3000.com/articles/article_3770.asp for an example.

Resources