德尔福装配块中的异常行为

时间:2011-02-09 22:01:30

标签: delphi assembly instance-variables basm

我正在使用Delphi的内联汇编遇到一些奇怪的行为,正如这个非常简短的程序所示:

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.

这仅仅是为了举例(mov [asdf] eax mov eax, [asdf] 并没有做太多,但它适用于示例)。如果你看一下这个程序的程序集,你会看到

mov eax, ds:[4]

已变成

var
    temp: TAsdf;
begin
    temp := asdf;

    asm
        int 3;
        mov eax, [temp];
    end;

(由OllyDbg代表)显然崩溃了。但是,如果你这样做:

mov eax, [asdf]

它改为     mov eax,[ebp-4] 哪个有效。为什么是这样?我通常使用C ++而且我习惯使用像这样的实例变量,可能是因为我使用的是实例变量错误。

编辑:是的,就是这样。将mov eax, [Self.asdf]更改为{{1}}可解决问题。对不起。

2 个答案:

答案 0 :(得分:12)

在第一种情况下,mov eax,[asdf],汇编程序将查找asdf并发现它是实例中偏移4的字段。因为您使用了没有基址的间接寻址模式,所以它只会对偏移进行编码(它看起来像是汇编程序的0 + asdf)。如果你这样写:mov eax,[eax] .asdf,它将被编码为mov eax,[eax + 4]。 (这里eax包含从调用者传入的Self)。

在第二种情况下,汇编程序将查找Temp并查看它是由EBP索引的局部变量。因为它知道要使用的基地址寄存器,所以它可以决定将其编码为[EBP-4]。

答案 1 :(得分:10)

方法接收EAX寄存器中的Self指针。您必须使用该值作为访问对象的基值。所以你的代码应该是这样的:

mov ebx, TBlah[eax].asdf

有关示例,请参阅http://www.delphi3000.com/articles/article_3770.asp