我正在使用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}}可解决问题。对不起。
答案 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。