5

私がやりたいのは、アセンブリを使用して、クラスインスタンスを作成し、そのメソッドの1つを呼び出してから、インスタンスを解放することです。

非常に重要でおそらく非常に単純なものが欠けていることは知っていますが、何がわからないのです。

program Project2;

{$APPTYPE CONSOLE}

uses
  SysUtils;

type
  TSomeClass = class(TObject)
  private
    FCreateDateTime: string;
  public
    constructor Create;
    procedure SayYeah;
  end;

constructor TSomeClass.Create;
begin
  FCreateDateTime := DateTimeToStr(Now);
end;

procedure TSomeClass.SayYeah;
begin
  Writeln('yeah @ ' + FCreateDateTime);
end;

procedure Doit;
asm
  CALL TSomeClass.Create; // <= Access Violation
  CALL TSomeClass.SayYeah;
  CALL TSomeClass.Free;
end;

begin
  try
    Doit;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
  Readln;
end.

参考:これを低レベルで達成する方法を理解したいのですが、別の方法ではありません。

更新

Andreas Rejbrandのおかげで、私は何とか犯人を見つけることができました:

Update2

PUSH /POPEAXではなくEBXを使用して欠陥を見つけてくれたArnaudに感謝します

var
  TSomeClass_TypeInfo: Pointer;

procedure Doit;
asm
  MOV DL, $01;
  MOV EAX, TSomeClass_TypeInfo;
  CALL TSomeClass.Create;
  PUSH EAX;
  CALL TSomeClass.SayYeah; // call method
  POP EAX;
  MOV DL, $01;
  CALL TSomeClass.Free; // pointer to instance(Self) is expected in EAX
end;

begin
  TSomeClass_TypeInfo := TSomeClass;
  try
    Doit;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
  Readln;
end.
4

2 に答える 2

10

asmコードが正しくありません。

ebxレジスターをオーバーロードしていますが、これは保持する必要があります。そして、グローバル変数のトリックは意味がありません。

より良いコーディングは次のようになります。

procedure Doit(ClassType: pointer);
asm // eax=TList
  mov dl,true // hidden boolean 2nd parameter
  call TObject.Create
  push eax
  call TList.Pack
  pop eax
  call TObject.Free
end;

DoIt(TList);

ただし、インスタンスを。で保護することはできませんtry...finally。:)

mov dl,trueパラメータについては、EMBwikiの次の公式ページを参照してください。

コンストラクタとデストラクタは、他のメソッドと同じ呼び出し規約を使用しますが、コンストラクタまたはデストラクタの呼び出しのコンテキストを示すために追加のブールフラグパラメータが渡される点が異なります。

コンストラクター呼び出しのflagパラメーターのFalseの値は、コンストラクターがインスタンスオブジェクトを介して、または継承されたキーワードを使用して呼び出されたことを示します。この場合、コンストラクターは通常のメソッドのように動作します。コンストラクター呼び出しのflagパラメーターのTrueの値は、コンストラクターがクラス参照を介して呼び出されたことを示します。この場合、コンストラクターはSelfによって指定されたクラスのインスタンスを作成し、EAXで新しく作成されたオブジェクトへの参照を返します。

デストラクタ呼び出しのフラグパラメータの値Falseは、継承されたキーワードを使用してデストラクタが呼び出されたことを示します。この場合、デストラクタは通常の方法のように動作します。デストラクタ呼び出しのフラグパラメータのTrueの値は、デストラクタがインスタンスオブジェクトを介して呼び出されたことを示します。この場合、デストラクタは、戻る直前にSelfによって指定されたインスタンスの割り当てを解除します。

フラグパラメータは、他のすべてのパラメータの前に宣言されたかのように動作します。レジスタの規則では、DLレジスタに渡されます。パスカル規則では、他のすべてのパラメーターの前にプッシュされます。cdecl、stdcall、およびsafecallの規則では、Selfパラメーターの直前にプッシュされます。

DLレジスタは、コンストラクタまたはデストラクタがコールスタックの最も外側にあるかどうかを示すため、BeforeDestructionまたはAfterConstructionを適切に呼び出すことができるように、終了する前にDLの値を復元する必要があります。

したがって、別の有効なコーディングは、eaxオブジェクトがそうではないため、デストラクタを直接nil呼び出すことができるため、次のようになります。

procedure Doit(ClassType: pointer);
asm // eax=TList
  mov dl,true
  call TObject.Create
  push eax
  call TList.Pack
  pop eax
  mov dl,true
  call TList.Destroy
end;

いずれの場合も、からのオブジェクトアクセスasmはこの方法で行われることを意図していません。タイプ情報に直接アクセスできないため、操作が非常に難しい場合があります。既存のインスタンスを使用すると、メソッドを使用classしてやりたいことが何でもできます。asmしかし、インスタンスを作成し、クラスタイプで遊ぶことasmは、間違いなく自然な方法ではありません。

于 2012-05-16T15:46:16.007 に答える
2

これについては、元々ここにあるDelphiアセンブリプログラミングの優れたガイドで読むことができます。残念ながら、サイトはダウンしていますが、アーカイブされたバージョンはここにあります。特に5ページをご覧ください。

于 2012-05-16T15:16:58.717 に答える