参数值传递的汇编实质,就是在堆栈上创建存储区,看看以下实现:

先来看看Delphi代码,传一个数组参数进去

1 procedure SortIt(a: array of Integer);
2 var
3   i, j: Integer;
4 begin
5   j := Length(a);
6   for i:=1 to j do
7     a[i-1] := i;
8 end;

调用代码为:

procedure TForm1.btn1Click(Sender: TObject);
var
  a: array[0..1] of Integer;
begin
  SortIt(a);
  ShowMessage('a[0]: ' + IntToStr(a[0]) + #13#10 + 'a[1]: ' + IntToStr(a[1]));
end;

看看汇编代码是怎样干的:

Unit1.pas.44: SortIt(a);
;调用前准备
lea eax,[ebp-$08]  ;定义的局部变量放在堆栈里,2个数组元素,32位系统里占8字节,
                      ;根据定义的局部变量顺序压栈,这儿只定义了数组A,所以堆栈里
                      ;就只有8字节,此句的意思是,把ebp-8的值放到eax中,这个值是
                      ;指向a[1]的内存地址,所以执行后eax中为a[0]元素的内存地址
mov edx,$00000001
call SortIt

 函数入口:

 1 ;函数入口处代码
 2 00452688 55               push ebp             ;这两行为堆栈框架,函数开始前必这样做以保存调用前
 3 00452689 8BEC             mov ebp,esp          ;的堆栈数据,同时为同时为函数创造干净的堆栈环境
 4 0045268B 53               push ebx             ;要用到ebp,先保存原值,不要破坏它
 5 0045268C 8BCA             mov ecx,edx          ;edx值为1,看起来用于下面的循环,ecx一般用于计数
 6 0045268E 85C9             test ecx,ecx         ;test和and类似,不同的是,只影响标志寄存器,不影响结果
 7 00452690 7807             js +$07              ;如果sf为1,这是符号位,如果ecx为ffff ffff,数组就爆了,不能是大于这个值
 8 00452692 8B1C88           mov ebx,[eax+ecx*4]  ; 记得eax为a[0]吧,此处ecx为1, eax+4刚好为a[1]地址,把a[1]的值取到ebx
 9 00452695 49               dec ecx
10 00452696 53               push ebx     ; 把a[1]值入栈
11 00452697 79F9             jns -$07     ;返回上面的mov ebx,[eax+ecx*4],再来一次,这样的话又能把a[0]值入栈
12 00452699 8BC4             mov eax,esp  ;这个时候堆栈里从低地址到高地址已形成a[0]、a[1]的结构,把堆栈指针指向a[0],
13                                        ;一个新的临时参数环境就构造好了,后面对数组的存取就只在这儿进行,不会影响
14                                        ;原值,高明呀,原来是这样实现的!

函数退出时:

1 ;函数结束堆栈要恢复到入来前的状态,这叫堆栈平衡
2 004526B5 8BE5             mov esp,ebp   ;记得函数进来前ebp指向栈顶吧,这一下直接回到进来前状态
3 004526B7 5D               pop ebp       ;是push ebp和mov ebp,esp的倒过来,就恢复了。
4 004526B8 C3               ret 

 

 

 

posted on 2013-05-10 19:13  斑马猪  阅读(353)  评论(0编辑  收藏  举报