stdcall 函数调用过程(以delphi为例),还有负数的补码
以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的补码。
stdcall 函数调用过程(以delphi为例),还有负数的补码的更多相关文章
- Linux驱动调试-根据oops的栈信息,确定函数调用过程
上章链接入口: http://www.cnblogs.com/lifexy/p/8006748.html 在上章里,我们分析了oops的PC值在哪个函数出错的,那如何通过栈信息来查看出错函数的整个调用 ...
- 37.Linux驱动调试-根据oops的栈信息,确定函数调用过程
上章链接入口: http://www.cnblogs.com/lifexy/p/8006748.html 在上章里,我们分析了oops的PC值在哪个函数出错的 本章便通过栈信息来分析函数调用过程 1. ...
- 从一个新手容易混淆的例子简单分析C语言中函数调用过程
某天,王尼玛写了段C程序: #include <stdio.h> void input() { int i; ]; ; i < ; i++) { array[i] = i; } } ...
- c函数调用过程原理及函数栈帧分析
转载自地址:http://blog.csdn.net/zsy2020314/article/details/9429707 今天突然想分析一下函数在相互调用过程中栈帧的变化,还是想尽量以比 ...
- 函数调用过程&生成器解释
摘自马哥解答,感谢. 函数调用过程: 假设程序是单进程,单执行流,在某一时刻,能运行的程序流只能有一个.但函数调用会打开新的执行上下文,因此,为了确保main函数可以恢复现场,在main函数调用其它函 ...
- C语言的函数调用过程
从汇编的角度解析函数调用过程 看看下面这个简单函数的调用过程: int Add(int x,int y) { ; sum = x + y; return sum; } int main () { ; ...
- 汇编 cdecl 函数调用约定,stdcall 函数调用约定
知识点: cdecl 函数调用约定 stdcall 函数调用约定 CALL堆栈平衡 配置属性--> c/c++ -->高级-->调用约定 一.cdecl调用约定 VC++ ...
- 深入理解C语言的函数调用过程 【转】
转自:http://blog.chinaunix.net/uid-25909619-id-4240084.html 原文地址:深入理解C语言的函数调用过程 作者:wjlkoorey258 本文 ...
- C语言的函数调用过程(栈帧的创建与销毁)
从汇编的角度解析函数调用过程 看看下面这个简单函数的调用过程: int Add(int x,int y) { ; sum = x + y; return sum; } int main () { ; ...
随机推荐
- 观察者模式------《Head First 设计模式》
第二章---观察者模式 xzmxddx 学习方式:书籍<Head First 设计模式>,这本书通俗易懂,所有知识点全部取自本书. 面向对象设计原则 封装变化 多用组合,少用继承 针对接口 ...
- 'utf-8' codec can't decode byte 0xd0 in position 0问题
今天利用pd.read_csv(url)从网络上读取数据时出现了如下错误: 'utf-8' codec can't decode byte 0xd0 in position 0 问题原因:网络上的这个 ...
- Hive分析窗口函数(一) SUM,AVG,MIN,MAX
Hive分析窗口函数(一) SUM,AVG,MIN,MAX Hive分析窗口函数(一) SUM,AVG,MIN,MAX Hive中提供了越来越多的分析函数,用于完成负责的统计分析.抽时间将所有的分析窗 ...
- Linux下服务器开发的必要准备
一.Windows下安装Xshell 二.Linux开启SSH 可以先查询有没有SSH服务 sudo ps -e |grep ssh 没有安装SSH的服务器 sudo apt-get install ...
- 和他人一起管理GitHub仓库
和他人一起管理 GitHub 仓库方法 打开一个项目的仓库 同意好之后在项目中要添加 README.md 文件(重要) 要让别人也可以使用 master 主线 在上传代码前,一定要使用 git 指令 ...
- ps - 按进程消耗内存多少排序
https://www.cnblogs.com/JemBai/archive/2011/06/21/2086184.html https://www.cnblogs.com/jiqing9006/p/ ...
- git跟yum一样 linux下的命令使用和思想是类似的
git跟yum一样 linux下的命令使用和思想是类似的
- Linux_指令杂烩
目录 目录 指令集合 常用于脚本的指令 查看变量的指令 监控命令 除了root用户的其他用户不能login 重定向 grep 过滤文件内容 vim预设定 系统在启动时要依次运行4个脚本 归档压缩文件互 ...
- delphi 每英寸相素点取值偏差
在所有资料中,每英寸相素点之比一般是这两个值,即:0.0393700788 25.399999961392 但是在GDI编程中,却遇到LOGPIXELSX LOGPIXELSY 在取值为96DPI ...
- Delphi XE2 之 FireMonkey 入门(37) - 控件基础: TControl 概览
Delphi XE2 之 FireMonkey 入门(37) - 控件基础: TControl 概览 { TControl } public constructor Create(...); ov ...