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:
When the code starts executing,
eaxis indeed the self pointer. But the compiler has chosen to save it away toebp-$0cand then zeroiseeax. 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.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
eaxto 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:
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
ShowMessagecauses quite a large preamble. Consider this code instead:In this case the code is simple enough for the compiler to leave
eaxalone. The optimised release build code forSumis: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.