• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

stdcall函数调用过程(以delphi为例),还有负数的补码

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

以delphi下调用stdcall 函数为例,从右往左压栈:
procedure TForm1.Button2Click(Sender: TObject);
var
i:integer;
begin
i:=Add3(10,20);
end;
翻译成汇编:
push $14
push $0a;
call Add3;

function Add3(a: Integer; b: Integer): Integer; stdcall;
var
i: integer;
begin
i:=a+b;
result:=i;
end;
翻译成汇编:
push ebp;
mov ebp,esp;
mov eax,[ebp+$08];
add eax,[ebp+$0c];
pop ebp;
ret $0008;
lea eax,[eax+$00]

前提:堆栈,上面高地址,下面低地址,即所谓向下生长。
所以假设堆栈在上面的起始高地址ebp为100,push $14之后esp变成96,push $0a之后esp变成92。call Add3之后进入一个新的阶段,但计算机总体内存的地址是连续使用的。ebp地址变成92,但push ebp之后esp的地址变88,mov ebp,esp之后ebp的地址也变88。此时,想要取到两个实参的值,应该是ebp+08=88+08=96所代表的地址存储着a的值,ebp+12=88+12存=100储着b的值。(表达式从左往右计算,通过传4个参数的方式验证过)。最后别忘了回复ebp的值,并且跳转返回的时候要 ret $0008,即恢复两个被压栈的实参所占的地方。

个人猜测1,起始状态下,堆栈地址ebp,esp都为100的时候,随时等候着存储新的值。执行一条push语句以后,其存储地址为上一个esp地址,即为100。此时ebp不变仍为100,而新的esp变为96,但96地址代表的内存不存储任何东西。
个人猜测2,为什么使用ebp计算查找实参的值,而不是使用esp?虽然esp此时也等于88,也可以88+8=96得到实参a的值,但在函数内esp的值是随时会变的,因为会随时调用push。而ebp一旦进入函数后,通过push ebp保存它的值以后,反而不再需要了,是空闲的,所以使用它更保险。

 

=========另外,把Add3函数改成运算表达式,且无返回值:=======================
function Add3(a: Integer; b,c,d: Integer): Integer; stdcall;
var
i: integer;
begin
i:=a+b+c*5+d;
end;

则发现如下结果:
begin不管3721被翻译成:
push ebp;
mov ebp,esp;
end不管3721被翻译成:
pop ebp;
ret $0010; // 这个0010根据实参所占区域而定
nop
可见的push ebp是惯例,不需要理由的。而表达式计算过程被优化掉了,因为不需要返回值。

======================关于负数的补码=============================

VC6.0里的实验:

int add(int a, int b)
{
return a + b;
}

int main()
{
int c = add(0, -10);
return c;
}
在VC6.0里被翻译成:
push 0F6h;
push 0;
call add

其中-10=0F6h=11110110,假设最高位是符号位:
那么去掉符号位,得到 1110110,已经是补码。
如果减一:1110101
再取反:和 0001010 = 10
不过最奇怪的是,明明是int,但是最高位只是在第八位?

 

Delphi里也是一样:

push $f6
push $00

如果是 -128 ,则被表示成 80h = 128 = 10000000,正好是8位数情况下的补码
如果是 -129 ,则被表示成 0FFFFFF7Fh = 11111111111111111111111101111111 = 去掉最高位符号,再减1, 再取反 = 10000001 = 129
如果是 -32768 ,则被表示成 0FFFF8000h = 11111111111111111000000000000000 = 去掉最高位符号,再减1 = 0111111111111111 (16位表示,如果是32位表示则完全不正确)= 再取反 = 100000000000000 = 正好是16位情况下-32768的补码。

 


鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
(转)linux ubuntu 安装 matlab 2010 及破解 详细图解 - i活着发布时间:2022-07-18
下一篇:
DELPHI解析JSON发布时间:2022-07-18
热门推荐
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap