【问题标题】:Translate a code using pointer, to Assembly in Pascal - Delphi使用指针将代码转换为 Pascal 中的程序集 - Delphi
【发布时间】:2011-01-11 12:40:15
【问题描述】:

我在下面有这段代码,我想把它翻译成 ASM,也可以在 Delphi 中使用。

var
    FunctionAddressList: Array of Integer;

type TFunction = function(parameter: Integer): Integer; cdecl;

function Function(parameter: Integer): Integer;
var
    ExternFunction: TFunction;
begin
    ExternFunction := TFunction(FunctionAddressList[5]);
    Result := ExternFunction(parameter);
end;

它工作正常,但是当我尝试它的汇编版本时:

function Function(parameter: Integer): Integer; cdecl;
asm
  mov eax, FunctionAddressList
  jmp dword ptr [eax + 5 * 4]
end;

它应该可以工作,因为在 C++ 中它以两种方式工作:

void *FunctionAddressList;

_declspec(naked) int Function(int parameter)
{
    _asm mov eax, FunctionAddressList;
    _asm jmp dword ptr [eax + 5 * 4];
}

typedef int (*TFunction)(int parameter);
int Function(int parameter)
{
    TFunction ExternFunction = ((TFunction *)FunctionAddressList)[5];
    return ExternFunction(parameter);
}

但它在 Delphi 中不起作用。

在Assembly版本中,它将数组乘以4,因为它是数组每个元素之间的偏移大小,所以两个版本是等价的。

所以,我想知道为什么它不适用于 Delphi。在Delphi中,数组中整数值之间的偏移大小与C++不同?

我已经尝试了很多偏移量,如 1、2、4、6、8 等。以及许多类型的数组(指针数组;仅指针;整数数组等),我尝试了很多调用约定,并且 cdecl 是唯一适用于非 asm 版本的,但对于 ASM,所有测试都不起作用。

谢谢。

【问题讨论】:

    标签: c++ arrays delphi assembly basm


    【解决方案1】:

    第一个重现错误的测试应用:

    var
      FunctionAddressList: Array of Integer;
    
    function Bar(parameter: Integer): Integer; cdecl;
    begin
      ShowMessage('Bar '+IntToStr(parameter));
    end;
    
    function Foo(parameter: Integer): Integer; cdecl;
    asm
      mov eax, FunctionAddressList
      jmp dword ptr [eax + 5 * 4]
    end;
    
    procedure TForm1.Button1Click(Sender: TObject);
    begin
      SetLength(FunctionAddressList, 6);
      FunctionAddressList[5]:= Integer(@Bar);
      Foo(25);
    end;
    

    Bar地址定义正确,但问题是Delphi编译器为Foo生成prologue和epilog,所以真正的Foo代码是

    0046CD30 55               push ebp
    0046CD31 8BEC             mov ebp,esp
    Unit1.pas.46:             mov eax, FunctionAddressList
    Unit1.pas.47:             jmp dword ptr [eax + 5 * 4]
    0046CD3B 5D               pop ebp
    0046CD3C C3               ret
    

    结果堆栈损坏,参数错误,Bar返回地址错误。如果您仍然想这样做,请使用

    function Foo(parameter: Integer): Integer; cdecl;
    asm
      pop ebp
      mov eax, FunctionAddressList
      jmp dword ptr [eax + 5 * 4]
    end;
    

    【讨论】:

    • 我现在不使用 C++,但我认为裸函数的 C++(我假设您使用 Visual C++)代码也假定堆栈上的参数。您必须自己编写序言和结语(在 asm 中)才能到达使用 cdecl 调用约定的裸函数中的参数。您不需要这样做,因为您不需要此处的参数并将其通过堆栈传递给地址列表中的函数。
    【解决方案2】:

    Array of Integer 不是你想的那样。它是一个自动管理的动态数组。

    您应该使用FunctionAddressList: ^Pointer; 尝试相同的操作——但请注意,您必须手动分配和解除分配。

    【讨论】:

    • 我已经分配了FunctionAddressList,但是还是不行,我需要把'* 4'的值改成另一个吗?
    • @Edward - 不要使用 4,使用 SizeOf(Pointer)。如果您使用的是 64 位系统,则不会是 4。
    猜你喜欢
    • 2023-04-06
    • 2021-11-21
    • 1970-01-01
    • 2011-09-08
    • 1970-01-01
    • 1970-01-01
    • 2017-06-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多