Delphi 汇编块中的异常行为
我在使用 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
ing [asdf]
into eax
没有做太多事情,但它适用于示例)。如果您查看该程序的程序集,您会发现它
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]
可以解决该问题。对此感到抱歉。
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 (mov
ing [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.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
在第一种情况下,mov eax,[asdf],汇编器将查找asdf并发现它是实例中偏移量4的字段。因为您使用了没有基址的间接寻址模式,所以它只会对偏移量进行编码(对于汇编器来说,它看起来像 0 + asdf)。如果你这样写:mov eax, [eax].asdf,它会被编码为 mov eax, [eax+4]。 (这里 eax 包含从调用者传入的 Self)。
在第二种情况下,汇编器将查找 Temp 并发现它是一个由 EBP 索引的局部变量。因为它知道要使用的基地址寄存器,所以它可以决定将其编码为[EBP-4]。
In the first case, mov eax,[asdf], the assembler will look up asdf and discover it is a field of offset 4 in the instance. Because you used an indirect addressing mode without a base address, it will only encode the offset (it looks like 0 + asdf to the assembler). Had you written it like this: mov eax, [eax].asdf, it would have been encoded as mov eax, [eax+4]. (here eax contains Self as passed in from the caller).
In the second case, the assembler will look up Temp and see that it is a local variable indexed by EBP. Because it knows the base address register to use, it can decide to encode it as [EBP-4].
方法接收 EAX 寄存器中的 Self 指针。您必须使用该值作为访问该对象的基值。因此,您的代码将类似于:
请参阅 http://www.delphi3000.com/articles/article_3770。以 .asp 为例。
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:See http://www.delphi3000.com/articles/article_3770.asp for an example.