核心提示:进几天一直在研究在delphi中使用汇编的问题。上回说了一点。今天再把我刚刚弄出来的一点东西写上来。EBP、ESP、BP和SP都称为指针寄存器,主要用于存放堆栈内存储单元的偏移量,用它们可实现多种存储...
进几天一直在研究在delphi中使用汇编的问题。上回说了一点。今天再把我刚刚弄出来的一点东西写上来。EBP、ESP、BP和SP都称为指针寄存器,主要用于存放堆栈内存储单元的偏移量,用它们可实现多种存储器操作数的寻址方式。
现在我们来说一说EBP:
EBP是基址指针寄存器:一般用来确认堆栈帧的起始位置,也就是指向栈底。也就是说,一般一个函数入口的地址也就存放在EBP中(所以一般在进入函数的时候将ebp寄存器内容压栈,即保存其函数的上级调用函数的栈基地址,以便于以后返回调用)。
比如,我们要实现点一个Form1上的按扭Button1实现弹出对话框。我们一般是
procedure TForm1.Button1Click(Sender: TObject);
var ss: string;
begin
ss := 'BASM测试';
showmessage(ss);
end;
那么换成汇编的写法如下:
procedure TForm1.Button1Click(Sender: TObject);
var ss: string;
begin
ss := 'BASM测试';
asm
mov eax,[ebp-$04]
call showmessage
end;
end; //说明:Ebp通过上面我们知道应该是用来指定Button1Click过程的入口地址,将其减4用来空一点空间出来用来存放局部变量 ,则此时[ebp-04]中存放的则是字符串 ss 的地址,所以此时 eax中存放的则是 'BASM测试' 的地址
然后 Call Showmessage,调用Showmessage函数,而Delphi默认的调用方式是寄存器方式,其1,2,3个参数分别对应着EAX,EDX,ECX, 而 EAX中已经存放了我们的局部变量地址。该函数则获得了字符串参数。
上面的是用在过程里面,直接使用赋值后的字符串的地址传递给Showmessage函数调用。下面我们使用另一个方法来使用局部变量:
通过查看CPU View我们可以知道,在上面的字符串赋值过程的汇编代码如下:
lea eax, [ebp-$04]{这是留出一个空位,用来给局部变量中转使用}
mov edx, $2342342{这里是一个随机的值,也就是字符串指针的值}
然后下面调用了一个系统函数LstrLAsg
Call LstrLAsg
该函数将EDX指向的地址内容复制到EAX指向的地址中去。所以由此可见,Delphi中的字符串赋值是通过拷贝实现的。
所以我们可以通过一个过程传递一个字符串地址值来得实现上面的方法,代码如下:
procedure Test(prAddress: integer);
asm
mov edx, eax //先将prAddress地址值存入Edx,便于调用LstrLAsg函数
lea eax, [ebp-$04] //将使用一个局部变量周转,(偏移地址)
Call System.@LstrLAsg //调用系统的LstrLAsg函数实现字串复制
mov eax, [ebp-$04] //将实际的局部变量地址传递给Eax让Showmessage调用
Call Showmessage //调用Showmessage函数
end;
然后我们在ButtonClick中调用如下:
procedure TForm1.Button1Click(Sender: TObject);
var ss: string;
begin
ss := 'BASM测试';
Test(integer(ss));
end;