




免费预览已结束,剩余3页可下载查看
下载本文档
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
作者:RoBa标题:关于Delphi中参数的传递和函数值的返回 关于Delphi中参数的传递和函数值的返回前言:高手们应该早知道了,不屑于写出来而已。真正的高手一个比一个潜的深,只剩下偶这样的小菜写些菜文给更小的菜。高手看时还请捂好大牙,多多指点。不知各位小菜同胞对破解DELPHI程序有什么看法,反正我的感觉就一个字:怪。各位最先遇到的问题恐怕都是:我下了GetDlgItemInt、GetDlgItemText、GetWindowText.怎么什么也断不下来,甚至连Hmemcpy都不起作用?呵呵,从这里就能看出宝蓝的那批人成心想跟M$对着干,非搞出些新鲜的东东不可。这回我们就来看看DLEPHI中对函数(过程)参数的传递是如何进行的。我们知道WinAPI采用的调用约定是StdCall,也就是调用一个函数Func(arg1,agr2,agr3,arg4),你需要pusharg4,pusharg3,pusharg2,pusharg1,callFunc。在VC+里也是这种形式,所以一个函数有几个参数,可以非常直观地看出来。可是在DELPHI中就很奇怪了,在一个CALL前面你可能一个PUSH也看不到,怎么回事呢?听我慢慢道来。DELPHI中的调用约定有StdCall,Cdecl,Safecall,Pascal和Register等几种方式,而DELPHI的默认方式是Register(为什么不是Pascal?)Register方式就是尽可能地使用寄存器来传递参数,减少堆栈的操作来提高速度。具体情况是怎样呢,看个例子先:在FORM上放一个BUTTON,双击写代码如下: 代码:functionadd1(a:Integer):Integer;/一个参数beginadd1:=a+a;end;functionadd2(a,b:Integer):Integer;/两个参数beginadd2:=a+b;end;functionadd3(a,b,c:Integer):Integer;/三个参数beginadd3:=a+b+c;end;functionadd4(a,b,c,d:Integer):Integer;/四个参数beginadd4:=a+b+c+d;end;functionadd5(a,b,c,d,e:Integer):Integer;/五个参数beginadd5:=a+b+c+d+e;end;functionadd6:Integer;/加入一些局部变量varlocal1,local2,local3,local4,local5:Integer;beginlocal1:=1;local2:=2;local3:=3;local4:=4;local5:=5;add6:=local1+local2+local3+local4+local5;end;functionadd7(a,b,c,d,e:Integer):Integer;/利用result来返回beginresult:=a+b+c+d+e;end;functionadd8(a,b,c,d,e:Integer):Integer;StdCall;/StdCall调用方式beginadd8:=a+b+c+d+e;end;procedureTForm1.Button1Click(Sender:TObject);vara,b,c,d,e:Integer;s1,s2,s3,s4,s5,s6,s7,s8,s:Integer;begina:=1;b:=2;c:=3;d:=4;e:=5;s1:=add1(a);s2:=add2(a,b);s3:=add3(a,b,c);s4:=add4(a,b,c,d);s5:=add5(a,b,c,d,e);s6:=add6;s7:=add7(a,b,c,d,e);s8:=add8(a,b,c,d,e);s:=s1+s2+s3+s4+s5+s6+s7+s8;/必须要有这么几句MessageDlg(IntToStr(s),mtConfirmation,mbOK,0);/不然编译器根本不去处理返回值end;用DEDE反一下看看,这个Button1Click的内容: 代码:004403EC55pushebp004403ED8BECmovebp,esp004403EF83C4D8addesp,-$28;空出地方放局部变量004403F253pushebx004403F356pushesi004403F457pushedi004403F533C9xorecx,ecx004403F7894DD8movebp-$28,ecx004403FA33C0xoreax,eax004403FC55pushebp*PossibleStringReferenceto:関-?腽_嬪?|004403FD68E9044400push$004404E9*TRY|0044040264FF30pushdwordptrfs:eax;这是DELPHI的例行公事00440405648920movfs:eax,esp;据我观察只要调用VCL库的都要SEH00440408BB01000000movebx,$00000001;a:=10044040DBE02000000movesi,$00000002;b:=200440412BF03000000movedi,$00000003;c:=300440417C745FC04000000movdwordptrebp-$04,$00000004;d:=40044041EC745F805000000movdwordptrebp-$08,$00000005;e:=5可以看出DELPHI的确不一样,把EBX,ESI,EDI能用的寄存器全都用上了,实在不行了才用ebp-xx,从下面的分析中也能看出这一点,DELPHI在能用寄存器时决不用堆栈。004404258BC3moveax,ebx;这是add1的参数啦,不用PUSH的*Referenceto:TForm1.Proc_00440360()|00440427E834FFFFFFcall00440360;CALLadd10044036003C0addeax,eax00440362C3ret;这样的确很快哟0044042C8945F4movebp-$0C,eax;s1:=add1(a)0044042F8BD6movedx,esi;add2的参数EDX=2004404318BC3moveax,ebx;add2的参数EAX=1*Referenceto:TForm1.Proc_00440364()|00440433E82CFFFFFFcall00440364;CALLadd20044036403D0addedx,eax004403668BC2moveax,edx00440368C3ret004404388945F0movebp-$10,eax;s2:=add2(a,b)0044043B8BCFmovecx,edi;add3的参数ECX=30044043D8BD6movedx,esi;EDX=20044043F8BC3moveax,ebx;EAX=1*Referenceto:TForm1.Proc_0044036C()|00440441E826FFFFFFcall0044036C;CALLadd30044036C03D0addedx,eax0044036E03CAaddecx,edx004403708BC1moveax,ecx00440372C3ret004404468945ECmovebp-$14,eax;s3:=add3(a,b,c)004404498B45FCmoveax,ebp-$04;EBP-4=40044044C50pusheax;终于看见PUSH了噢0044044D8BCFmovecx,edi;ECX=30044044F8BD6movedx,esi;EDX=2004404518BC3moveax,ebx;EAX=1*Referenceto:TForm1.Proc_00440374()|00440453E81CFFFFFFcall00440374;CALLadd40044037455pushebp004403758BECmovebp,esp;这是C里面的方式啦0044037703D0addedx,eax0044037903CAaddecx,edx0044037B034D08addecx,ebp+$08;EBP+8本来是第一个参数的0044037E8BC1moveax,ecx;这里EBP+8是第四个参数004403805Dpopebp00440381C20400ret$0004004404588945E8movebp-$18,eax;s4:=add4(a,b,c,d)0044045B8B45FCmoveax,ebp-$04;EBP-4=40044045E50pusheax;注意:先压进去的是第四个参数0044045F8B45F8moveax,ebp-$08;EBP-8=50044046250pusheax;再压进第五个参数,Pascal从左至右004404638BCFmovecx,edi;ECX=3004404658BD6movedx,esi;EDX=2004404678BC3moveax,ebx;EAX=1*Referenceto:TForm1.Proc_00440384()|00440469E816FFFFFFcall00440384;CALLadd5(a,b,c,d,e)0044046E8945E4movebp-$1C,eax;s5=add5(a,b,c,d,e)*Referenceto:TForm1.Proc_00440398()|00440471E822FFFFFFcall00440398;add6看看DLEPHI怎么处理局部变量0044039853pushebx0044039956pushesi0044039AB801000000moveax,$000000010044039FBA02000000movedx,$00000002004403A4B903000000movecx,$00000003004403A9BB04000000movebx,$00000004004403AEBE05000000movesi,$00000005;哈哈,果然不出所料004403B303D0addedx,eax;它用上了一切能用的寄存器004403B503CAaddecx,edx;各位可以试试加上十来个局部变量004403B703D9addebx,ecx;看它能坚持到几时004403B903F3addesi,ebx004403BB8BC6moveax,esi004403BD5Epopesi004403BE5Bpopebx004403BFC3ret004404768945E0movebp-$20,eax004404798B45FCmoveax,ebp-$040044047C50pusheax0044047D8B45F8moveax,ebp-$080044048050pusheax004404818BCFmovecx,edi004404838BD6movedx,esi004404858BC3moveax,ebx*Referenceto:TForm1.Proc_004403C0();我想看看用result是不是有不同|00440487E834FFFFFFcall004403C0;其实和add5一样的,不写了0044048C8945DCmovebp-$24,eax0044048F8B45F8moveax,ebp-$080044049250pusheax;PUSH5004404938B45FCmoveax,ebp-$040044049650pusheax;PUSH40044049757pushedi;PUSH30044049856pushesi;PUSH20044049953pushebx;PUSH1*Referenceto:TForm1.Proc_004403D4()|0044049AE835FFFFFFcall004403D4;这个眼熟的吧,从右至左的StdCall方式004403D455pushebp004403D58BECmovebp,esp004403D78B4508moveax,ebp+$08004403DA03450Caddeax,ebp+$0C004403DD034510addeax,ebp+$10004403E0034514addeax,ebp+$14004403E3034518addeax,ebp+$18004403E65Dpopebp004403E7C21400ret$0014;我还是觉得这样好看一些*ReferencetoForm1|0044049F8B5DF4movebx,ebp-$0C004404A2035DF0addebx,ebp-$10004404A5035DECaddebx,ebp-$14004404A8035DE8addebx,ebp-$18004404AB035DE4addebx,ebp-$1C004404AE035DE0addebx,ebp-$20004404B1035DDCaddebx,ebp-$24004404B403D8addebx,eax;加起来.下面的不写了,还值得一提的是在最后DELPHI总要弄出两个RET来,跳来跳去的,也算是DELPHI的特色吧。上面讲的是自己定义的函数,要是用VCL库的东东,有时候更加莫名其妙一些。看例子:建一个FORM,放一个BUTTON,一个EDIT,代码如下: 代码:procedureTForm1.Button1Click(Sender:TObject);beginMessageDlg(edit1.text,mtConfirmation,mbOK,0);end;呵呵太简单了是不是,用DEDE反下:(只写了关键部分) 代码:004417BE6A00push$00;这是下面MessageDlg的第四个参数,找到没004417C08D55FCleaedx,ebp-$04;?这是什么?*ReferencetocontrolTForm1.Edit1:TEdit|004417C38B83C8020000moveax,ebx+$02C8;这是下面GetText的参数TControl吧;看上面的Reference*Referenceto:controls.TControl.GetText(TControl):TCaption;|004417C9E8D619FEFFcall004231A4;得到EDIT的文本004417CE8B45FCmoveax,ebp-$04;这是参数一要显示的字串放入EAX004417D1668B0D00184400movcx,wordptr$00441800;这应该是参数二mtConfirmation004417D8B203movdl,$03;这是参数三mbOK*Referenceto:Dialogs.Proc_00441380|004417DAE8A1FBFFFFcall00441380;这个是MessageDlg004417DF33C0xoreax,eax如果按照上面的分析,看到GetText这里应该只有一个参数就是放入EAX的那个ebx+02c8,从参考也可以看到这就是EDIT1,可是函数的返回值呢?刚执行完这个CALL后EAX中是没有的,moveax,ebp-04后才出现了,返回值原来在ebp-4中。再向上找有一个莫名其妙的leaedx,ebp-04,按照我上面的分析这应该表示GetText的第二个参数。可是GetText只有一个参数呀这种需要返回一个比较大的结构的函数,在VC中常用的方法是把一个指针当参数传递过去,而DLEPHI中我猜是不是做成一个隐藏的参数,像上面的GetText表面上看是返回一个TCaption,实际这个并不是放在EAX里返回来的。总结一下:DELPHI对参数的传递是尽可能多地利用寄存器,一般第一个参数用EAX,第二个参数用EDX,第三个参数用ECX,多于三个参数的时候,对多出来的参数按照从左至右的PASCAL方式来压栈。对于函数的返回值,有时尽管声明中说它的返回值是TCaption之类等,实际上并没有在EAX中返回,而是在保存一个隐藏的参数中,等需要时再复制过来。(这一点是猜想而已,如果哪位高人知道的话还请指点。反正我以前都是糊里糊涂地跟,结果出来就算了。其实仔细一分析还有点意思。)回复:Jimmy4willRoba老大小的不才,斗胆给你解释一下最后一段的疑惑引用: 004417BE6A00push$00;这是下面MessageDlg的第四个参数,找到没004417C08D55FCleaedx,ebp-$04;?这是什么?*ReferencetocontrolTForm1.Edit1:TEdit|004417C38B83C8020000moveax,ebx+$02C8;这是下面GetText的参数TControl吧;看上面的Reference*Refer
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025年房地产行业招聘面试技巧大解密预测问题与答案参考
- 2025年物流经理高级面试必-备知识点与预测题详解
- 2025年注册验船师资格考试(B级船舶检验法律法规)综合练习题及答案一
- 2025年监理工程师之交通工程目标控制题库含答案(能力提升)
- 特种设备事故应急救援预案和演练方案(模板及记录表)
- 2025年初中地理模拟试卷(地理环境与可持续发展)及答案详解
- 桃花源记全文朗诵课件
- 2025年能源企业环保主管岗位培训与实操考核试题
- 2025年民政领域公务员面试高频考点公共突发事件应对
- 2025年招聘考试中的行业热点与趋势预测
- 韦莱韬悦-东方明珠新媒体职位职级体系咨询项目建议书-2017
- 中国心力衰竭诊断和治疗指南2024解读(完整版)
- 八上外研版英语书单词表
- 高标准农田建设项目施工合同
- 腹内高压综合征
- 识别界限 拒绝性骚扰 课件 2024-2025学年人教版(2024)初中体育与健康七年级全一册
- 2024年秋季新人教版八年级上册物理全册教案(2024年新教材)
- 污水处理托管服务 投标方案(技术方案)
- 压疮护理质量改进一等奖(有稿)
- 深基坑施工验收要求
- 环境事故调查报告
评论
0/150
提交评论