Search code examples
delphiassemblyinstance-variablesbasm

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.


Solution

  • 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.