2012年10月4日木曜日

record helper を逆アセンブル

record helper が、どんなコードにコンパイルされるのか、興味があって試してみました。
program Project1;
uses
  System.SysUtils;

type
  TIntegerHelper = record helper for Integer
    function ToString: String;
  end;

function TIntegerHelper.ToString: String;
begin
  Result := IntToStr(Self);
end;

var
  i: Integer;
begin
  i := $ff
  Writeln(i.ToString); // ここ
end.

上記のコード "ここ" とコメントしている部分は

lea eax, [iのアドレス]
call TIntegerHelpder.ToString

こんな風になってるかなと思ったのですが、さて。

mov  [$00423ed8], $000000ff
lea  edx, [ebp - $14]
mov  eax, $00423ed8           // ここ
call TIntegerHelper.ToString
mov  edx, [ebp - $14]
mov  eax, [$0041e618]
call @Write0UString
call @WriteLn
call @_IOTest

こうなっていました。
lea ではなく、普通に eax にアドレスを代入していました。
これは、 i がグローバル変数だからだと思います。多分。(実効アドレスを計算する必要がない)

↓こんな風に procedure を呼ぶようにしてやると

procedure Test;
var
  i: Integer;
begin
  i := $ff;
  Writeln(i.ToString);
end;

begin
  Test;
end.

こうなってました。

lea  eax, [ebp - $04]         // ここ
call TIntegerHelper.ToString

大体予想通りです。
ただ、これらの結果は全部 debug ビルドなので、release にすると少し変わってるかもしれません。

ということで、record helper は Self (= eax) に、変数の値を入れて、関数を呼んでいる、という実装でした。

0 件のコメント:

コメントを投稿