IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 5.C调用约定 -> 正文阅读

[C++知识库]5.C调用约定

前言

在不同的语言中,

  • 变量存储
  • 传递参数
  • 返回值
    的方式有所不同,这种差异成为语言的调用约定,因为它表述了在调用函数时函数预期得到什么样的数据。
    使用最广泛的是C语言调用约定,它也是Linux平台的标准。

知识点

一般,栈顶的地址要小于栈底的地址,所以说栈是向下增长的(向地址减小的方向。)

  • 栈寄存器%esp总是包含一个指向当前栈顶的指针(地址),无论栈顶在何处。
    • 如果我们只想访问栈顶的值,而不想移除它,可以这样:movl (%esp), %eax
    • 访问栈顶的下一个值:movl 4(%esp), %eax

规则

执行函数之前:

  • 程序将函数的所有参数按逆序压入栈中
  • 接着,程序发出一条call指令,表明程序希望开始执行的函数。
  • call指令会做两件事:
    • 首先,将下一条指令的地址,即返回地址压入栈中。
    • 然后,修改指令指针(%eip),以指向函数起始处。

执行函数时:

  • 首先,函数通过push %ebp指令保存当前的基址指针寄存器%ebp
    • 基址指针寄存器时一个特殊的寄存器,用来访问函数的参数和局部变量。
  • 然后,它会用movl %esp, %ebp将栈指针%ebp复制到%esp
    • 这使得你能够把函数参数作为相对于基址指针的固定索引进行访问。
  • 接下来,函数为其所需要的局部变量预留栈空间,只需将栈指针向外移动即可实现。
    • 例如需要两个字的内存,只需要将栈指针向下移动两个字即可预留空间:subl $8, %esp,这样,就可以将栈用于变量存储。

函数执行完毕:

  • 将其返回值存储到%eax
  • 将栈恢复到调用函数时的状态(移除当前栈帧,并使调用代码的栈帧重新生效)
  • 将控制权交给调用它的程序。
    • 这是通过ret指令实现的,该指令将栈顶的值弹出,并将指令寄存器%eip设置为该弹出值。

因此,当函数返回给调用它的代码时,必须恢复前一个栈帧。
如果不这样,ret将无法正常工作,

因此,从函数返回,你必须使用如下指令:

movl	%ebp, %esp
popl	%ebp
ret

至此,函数调用完成。

  • 调用代码可以检查%eax中的返回值。
  • 调用代码也需要弹出其入栈的所有参数,以将栈指针复位至其原先的位置
    • 如果不再需要参数值,可以用addl指令将4*参数个数加到%esp即可。

关于更详细的C语言调用约定(也称为ABI,即应用程序二进制接口),请查询
System V Application Binary Interface — Intel386 Architecture Processor Supplement

代码示例

#目的:	展示函数如何工作的程序
#		本程序将计算	2^3 + 5^2
#

#主程序所有内容都存储在寄存器中,因此数据段不含任何内容

.section	.data

.section	.text

.globl	_start

_start:
	pushl	$3		#压入第二个参数
	pushl	$2		#压入第一个参数
	call	power
	addl	$8, %esp	#恢复栈指针
	pushl	%eax		#在调用下一个函数前,保存第一个答案

	pushl	$2
	pushl	$5
	call	power
	addl	$8, %esp
	
	popl	%ebx
	addl	%eax, %ebx

	movl	$1, %eax
	int		$0x80

#目的:	用于计算一个数的幂
#
#输入:	第一个参数	底数
#		第二个参数	底数的指数
#
#输出:	以返回值的形式给出结果
#
#注意:	直属必须大于等于1
#
#变量:
#		%ebx保存底数
#		%ecx保存指数
#			-4(%ebp)保存当前结果
#			%eax用于暂时存储

.type	power, @function
power:
		pushl	%ebp
		movl	%esp, %ebp
		subl	$4, %esp		#为本地存储保留空间
		movl	8(%ebp), %ebx	#第一个参数放入%eax
		movl	12(%ebp), %ecx	#第二个参数放入%ecx
		movl	%ebx, -4(%ebp)	#存储当前结果
	power_loop_start:
		cmpl	$1, %ecx	#如果是1次方,就已经获得结果
		je		end_power
		movl	-4(%ebp), %eax	#将当前结果放入%eax
		imull	%ebx, %eax		#将当前结果与底数相乘
		movl	%eax, -4(%ebp)	#保存当前结果
		decl	%ecx
		jmp		power_loop_start
	end_power:
		movl	-4(%ebp), %eax	#返回值移入%eax
		movl	%ebp,	%esp
		popl	%ebp
		ret
  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-04-09 18:05:39  更:2022-04-09 18:08:37 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 0:36:38-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码