2011-02-09 5 views
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. 

Это просто ради примера (mov ИНГ [asdf] в 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++, и я привык использовать такие экземпляры экземпляров, возможно, что я неправильно использую переменные экземпляра.

EDIT: Да, это было. Изменение mov eax, [asdf] до mov eax, [Self.asdf] устраняет проблему. Извини за это.

ответ

10

Метод принимает указатель Self в регистре EAX. Вы должны использовать это значение в качестве базового значения для доступа к объекту. Так что ваш код будет что-то вроде:

mov ebx, TBlah[eax].asdf 

См http://www.delphi3000.com/articles/article_3770.asp для примера.

12

В первом случае mov eax, [asdf], ассемблер будет искать asdf и обнаружить, что это поле смещения 4 в экземпляре. Поскольку вы использовали режим косвенной адресации без базового адреса, он будет кодировать только смещение (это похоже на 0 + asdf на ассемблер). Если бы вы написали это так: mov eax, [eax] .asdf, он был бы закодирован как mov eax, [eax + 4]. (здесь eax содержит «Я», как передается от вызывающего).

Во втором случае ассемблер будет искать Temp и видеть, что это локальная переменная, индексированная EBP. Поскольку он знает базовый адресный регистр для использования, он может решить кодировать его как [EBP-4].