6

我在使用 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.

这只是为了示例(moving [asdf]intoeax没有多大作用,但它适用于示例)。如果您查看该程序的程序集,您会看到

mov eax, [asdf]

已经变成

mov eax, ds:[4]

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

var
    temp: TAsdf;
begin
    temp := asdf;

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

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

编辑:是的,就是这样。更改mov eax, [asdf]mov eax, [Self.asdf]解决问题。对于那个很抱歉。

4

2 回答 2

12

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

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

于 2011-02-09T22:11:58.740 回答
10

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

mov ebx, TBlah[eax].asdf

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

于 2011-02-09T22:11:34.947 回答