我想在函数里用汇编,可delphi如何知道传递的参数。(200分)

  • 主题发起人 主题发起人 BraveWolf
  • 开始时间 开始时间
那要看调用协定了, stdcall参数在堆栈中, register方式参数在寄存器里。
delphi调用汇编过程或函数的话它当然知道参数类型和数量(你得在interface中定义,
不是吗?)
所以, delphi是通过你的函数或过程的申明知道传递的参数的, 就象c中的头文件,
只是告诉编译器这个函数调用的格式。
如果是你的汇编函数或过程调用delphi的函数,delphi函数写的时候不是已经定下参数
了吗? 它当然也知道传递的参数了。 只要你的汇编过程用delphi规定的格式实现参数
的压栈或者寄存器的指定, delphi就能取得正确的参数值。
 
我总是不放心在高级语言和汇编语言编程时使用REGISTER传递参数,好象只用到2
个寄存器(记不清了),反正不放心,虽然速度快,但是好象没感觉,
用STDCALL吧,出/入栈就可以了,至于类型,定义在过程/函数处就可以使用,
(注意长度,小心在汇编代码中可能越界,系统好象不检查:(()
 
如果参数类型不是太复杂,应该不需要说明为stdcall,直接用参数名即可。
另外,Delphi对参数的传递有一些默认地规定,如16位整型返回值用AX等,应注意。
并且自Delphi 2可是,汇编都是32位的,因此应尽量使用32位指令。
 
给你一个小小的示例程序,希望能有帮助。

unit Unit1;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls;

type
TForm1 = class(TForm)
Button1: TButton;
Label1: TLabel;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.DFM}
function TestFunc(AInt: Integer): Integer
assembler;
asm
MOV EBX, AInt
INC EBX
MOV EAX, EBX
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
LABEL1.CAPTION := IntToStr(TestFunc(1));
end;

end.
 
建议你用Delphi的嵌入式汇编,给你一个例子:
function Sum(X,Y:Integer):Integer;
begin
asm
Push EAX
Mov EAX,X
Add EAX,Y
Mov Result,EAX
Pop EAX
end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
Caption:=IntToStr(Sum(10,20));
end;

注意以下问题:
1、调用和返回的所有问题都由Delphi处理,如参数进栈、参数退栈、寄存器保存、寄存器恢复等等,你自己的工作可以少很多。
2、最好在代码开始处保存将要使用的寄存器,结束前恢复,以免不测
3、不要修改EBX和EBP寄存器,这两个寄存器被用于读取参数。
 
function ReadPort(PortAdress:word) : byte
pascal;
begin
asm
mov dx,PortAdress
in al,dx
mov @result,al
end;
end;
这样返回参数,就可以了
 
建议你尽量不要使用汇编,除非你一定要且必须要,有时你用汇编编写出的程序
未必见得比经过优化过的DELPHI程序快。
 
汇编是可以使用的,只要使用得当,将会起到事半功倍的效果。这有一个前提,即
你对形参、实参的传递结构有着深刻地理解。
对于Pascal来说,调用汇编的参数是从右向左压栈的,这与C语言不同. ....
 
上面这么多答案还不对吗!
 
另外还有一个问题就是,delphi对代码进行了优化,使得有好多标准的函数接口被破坏,也就是说如果你使用了优化那么函数调用不是按照标准的压栈出站的模式,传入函数的参数将直接存在edx和ecx寄存器,如果你用优化模式并传参数小于等于两个那么参数可以直接写到这两个寄存器里,你用跟踪调试代码就可以看到具体的传参过程。如果你用非标准模式那么就可以在汇编函数里直接写参数名。
 
请继续讨论或结束此问题。
 
in MASM, you can use PROTO/INVOKE,
TASM has the same feature I think.

 
多人接受答案了。
 
后退
顶部