eax:通用寄存器,保留临时数据,常用于返回值熟悉相关汇编下令
ecx:通用寄存器,保留临时数据,常用于返回值
ebx:通用寄存器,保留临时数据
ebp:栈底寄存器
esp:栈顶寄存器
eip:指令寄存器,生存当前指令的下一条指令的地址
mov:数据转移指令查看函数调用堆栈
push:数据入栈,同时esp栈顶寄存器也要发生改变
pop:数据弹出至指定位置,同时esp栈顶寄存器也要发生改变
sub:减法下令
add:加法下令
call:函数调用,1. 压入返回地址 2. 转入目标函数
jump:通过修改eip,转入目标函数,进行调用
ret:恢复返回地址,压入eip,类似pop eip下令
lea: 取地址指令,和mov的区别是取得是地址不是数据
因此,调用函数是有本钱的,本钱体现在时间和空间上,本质是形成和开释栈帧有本钱末了的ret,恢复返回地址,压入eip,类似pop eip下令;即指令寄存器,恢复到主调函数要实行的下一条指令
在进程中,堆栈地址是从高到低分配的.当实行一个函数的时候,将参数列表入栈,压入堆栈的高地址部分,然后入栈函数的返回地址,接着入栈函数的实行代码,这个入栈过程,堆栈地址不断递减,一些黑客就是在堆栈中修改函数返回地址,实行自己的代码来达到实行自己插入的代码段的目的.可变参数列表
在C语言中,可变参数函数设计上要求至少有一个固定参数的原因重要有以下几点:原理是这样,但如果要我们手动去做,显然是一件非常麻烦的事情.
简而言之,这个固定的参数不仅是逻辑上的必要,也是技能实现上的必要条件,它帮助程序精确地识别和处理随后的可变数目的参数。在实际应用中,通常会联合头文件中定义的宏(如va_start, va_arg, va_end等)来遍历和处理可变参数列表。
- 标示参数开始:可变参数函数至少必要一个非可变参数作为“标记”,这是因为编译器必要知道从那里开始解析可变参数列表。这个固定参数通常用于传递关于可变参数的信息,比如参数的数目大概某种类型的标识符。比方,在printf函数中,第一个固定参数(格式化字符串)就告诉函数接下来的可变参数应该怎样被解释和处理。
- 获取参数信息:通过这个固定的参数,可以在运行时决定怎样访问和解析后面的可变参数。比方,通太过析格式化字符串,printf可以确定必要读取多少个参数以及它们的类型。
- 定位参数地址:在实现上,可变参数是通过栈传递的,第一个固定参数的地址可以帮助确定可变参数在栈上的起始位置。这样,通过指针算术,我们可以从这个已知位置开始访问后续的可变参数。
- 类型安全与边界界定:虽然C语言本身并不直接支持类型安全检查,但至少有一个固定参数可以作为编写安全、有效的可变参数处理逻辑的底子。这个参数可以辅助进行根本的参数验证,尽管更复杂的类型检查通常必要在函数内部手动实现。
复制代码
- 如有不足的地方欢迎大家评论区留言指正。
欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) | Powered by Discuz! X3.4 |