汇编:函数以及函数参数传递

汇编语言中的函数(或过程)是指一段可以被调用和执行的代码块;它们用于组织和重用代码,并使程序结构更加清晰;由于汇编语言没有高层次语言的语法糖,编写和调用函数涉及直接的堆栈操作和寄存器管理;以下详细介绍汇编函数的定义、调用、参数传递、返回值处理及一些最佳实践。

汇编语言中的函数调用和高层语言类似,但需要手动处理参数传递、堆栈管理和返回值。

函数的定义

函数在汇编中被定义为一个带有标签的代码块,通常使用 procendp 关键字来定义函数的开始和结束。

my_function proc; 函数体
my_function endp
示例:计算两个整数的和
assume cs:code
​
code segment//函数readd proc    add si,dimov ax,siretreadd endp
​
start:mov si,5 mov di,6//函数调用call readd//终止程序并返回dosmov ax,4c00hint 21h
code ends
end start

这段汇编代码展示了一个简单的程序,其中包含一个名为 readd 的函数,用于将两个寄存器 SIDI 中的值相加,并将结果存储在 AX 寄存器中。然后在程序的开始部分调用该函数,最后终止程序。

start:为程序的入口点,mov si, 5:将立即数 5 存储到 SI 寄存器中;mov di, 6:将立即数 6 存储到 DI 寄存器中;call readd:调用 readd 函数;调用 readd 函数后,SI 中的值变为 11(16进制B),并且 AX 也将包含 B

上述函数是通过寄存器传递参数;在这个示例中,参数 56 被分别存储在寄存器 SIDI 中,然后调用 readd 函数进行处理。

start:mov si,5        ; 将 5 存储到 SI 寄存器中mov di,6        ; 将 6 存储到 DI 寄存器中call readd      ; 调用 readd 函数

通过寄存器传递参数虽然有速度快、效率高的优点,但是由于寄存器数量有限,只适合参数数量较少的情况。

堆栈传参

堆栈传参相对于寄存器传参是一个更通用和灵活的方式,尤其是在需要传递大量参数、处理复杂调用关系或编写递归函数时可以使用这种传参方式。

1.堆栈的基本结构

要了解堆栈传参首先我们需要理解堆栈帧(stack frame)的结构及其在函数调用中的变化;堆栈是一个后进先出(LIFO)数据结构,用于存储函数调用的返回地址、局部变量、参数等;当一个函数被调用时,会创建一个新的堆栈帧,用于存储该函数的局部变量和传递的参数。堆栈帧通常包括以下内容:

调用函数的返回地址
保存的基指针(BP)
函数参数
局部变量

下面是一个简单的堆栈帧结构示意图:

(高地址)High Address、+----------------+|   局部变量1     |+----------------+|   局部变量2     |+----------------+|   ...          |+----------------+|   参数1         |+----------------+|   参数2         |+----------------+|   参数3         |+----------------+|   ...          |+----------------+|   函数的返回地址 |  <- 堆栈顶 (SP)+----------------+|   保存的基指针   |  <- 当前基指针 (BP)+----------------+
(低地址)Low Address
​

堆栈从高地址向低地址增长,SP 指向堆栈顶部,BP 用于定位局部变量和参数的位置。

以下是一个简单的堆栈传参示例:

assume cs:code
​
code segmentadd_numbers procpush bp          mov bp, sp        mov ax, [bp+4]    //参数取出 add ax, [bp+6]   //结果存放在ax中pop bp          retadd_numbers endp
​
start:mov ax,10mov bx,5//参数传入push ax         ; 将ax寄存器中的值压入栈中push bx         ; 将bx寄存器中的值压入栈中call add_numbers     ;函数调用add sp, 4     mov ax, 4C00hint 21h
code ends
end start

add_numbers procadd_numbers endp:定义了一个名为add_numbers的过程,该过程用于计算两个数的和。

push bp:保存当前函数调用前的基址指针值。

保存当前函数调用前的基址指针值通常是为了确保在函数执行期间能够正确访问调用该函数的上一级函数的栈帧信息。这是因为函数调用时,会产生一个新的栈帧,新的栈帧通常需要访问上一级函数的栈帧信息,比如参数、局部变量和返回地址等。

mov bp, sp:将栈顶指针赋值给基址指针,以便访问函数参数和局部变量。

mov ax, [bp+4]:将第一个参数(位于偏移量为4的位置)加载到寄存器ax中。

add ax, [bp+6]:将第二个参数(位于偏移量为6的位置)加到寄存器ax中。

pop bp:恢复基址指针的原始值。

ret:函数返回。

start:程序的入口点。

mov ax,10:将常数10加载到寄存器ax中。

mov bx,5:将常数5加载到寄存器bx中。

push axpush bx:将axbx中的值分别推送到堆栈中,作为add_numbers函数的参数。

call add_numbers:调用add_numbers函数。

add sp, 4:将堆栈指针移动4个字节,以清除函数调用时推送的参数。

mov ax, 4C00h:将退出程序的DOS功能号加载到寄存器ax中。

int 21h:调用DOS中断,终止程序。

解释了上述的汇编程序的后,我们将目光聚焦到函数参数传递中。
2. 堆栈帧的创建和销毁

此处补充:参数的压栈顺序是由调用约定(calling convention)决定的。在一些常见的调用约定中,如 cdecl、stdcall 等,参数的压栈顺序一般是从右往左的,即先压入的参数在内存中的地址更高,后压入的参数在内存中的地址更低。

假设我们有一个调用 add_numbers 函数的过程,如下所示:

start:mov ax,10mov bx,5push ax         ; 将ax寄存器中的值压入栈中push bx          ; 将bx寄存器中的值压入栈中call add_numbers ; 调用 add_numbers 函数add sp, 4        ; 清理堆栈

函数调用前,堆栈帧的图示

函数调用前堆栈的内容(从高地址到低地址):

high
|-------------|
| 参数 10      |
|-------------| 
| 参数 5       |<-- SP (堆栈指针)
|-------------|
low

执行call add_numbers指令后,即函数调用后,堆栈帧的图示:

|-------------|
| 参数 10      |
|-------------|
| 参数 5       |
|-------------|
| 返回地址      | <-- SP
|-------------|

此时我们转入函数代码中;

函数 add_numbers 的代码
add_numbers procpush bp           mov bp, sp        mov ax, [bp+4]    add ax, [bp+6]   pop bp            ret
add_numbers endp

执行 push bp 指令时,堆栈变化:

|-------------|
| 参数 10      |
|-------------|
| 参数 5       |
|-------------|
| BP 的旧值    |
|-------------|
| 返回地址     | <-- SP
|-------------|

执行 mov bp, sp 指令时,BP 指向 SP

|-------------|
| 参数 10      |
|-------------|
| 参数 5       |
|-------------|
| 返回地址     |
|-------------|
| BP 的旧值    | <-- BP, SP
|-------------|
获取参数的过程:

在计算机体系结构中,堆栈单元的大小通常由体系结构和编译器的约定确定。在x86架构中,包括16位、32位和64位模式,堆栈单元的大小通常是以字节为单位来计算的。

以下是几种常见情况下堆栈单元大小的概述:

①16位模式:在16位模式下,堆栈单元大小通常为2个字节。这意味着每个压入堆栈的元素都占用2个字节的空间。
这种模式下,CPU指令使用基于16位的地址和数据操作。
​
②32位模式:在32位模式下,堆栈单元大小通常为4个字节。每个压入堆栈的元素占用4个字节的空间。
这种模式下,CPU指令使用32位的地址和数据操作。
​
③64位模式:在64位模式下,堆栈单元大小通常为8个字节。每个压入堆栈的元素占用8个字节的空间。
这种模式下,CPU指令使用64位的地址和数据操作。

16位汇编函数获取第一个参数

    指令:mov ax, [bp+4]BP 指向 BP 的旧值,[BP+4] 即为第一个参数的位置(参数 5)。

16位汇编函数获取第二个参数

    指令:add ax, [bp+6]

  BP 指向 BP 的旧值,[BP+6] 即为第二个参数的位置(参数 10)。

BP+4表示相对于基址寄存器(Base Pointer,通常是BP)的偏移地址,即BP中的地址加上4(字节)为第一个参数,BP中的地址+6(字节)获得第二个参数;

至此函数参数传递/调用完毕。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/14626.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

c++网络开发笔记

1、第一节 1、阻塞模型 2、非阻塞IO 1)忙等待 2)IO复用模式(select,管理多个文件描述符号) 3)信号驱动IO,通过信号的方式 4)异步模型aio_read 3、select模型 int select(int nfds, fd_set *readfds, fd_set* writefds,fd_set* exceptfds, struct timeval* timeout);n…

Docker打包nginx镜像丢失挂载的配置文件

一般来说&#xff0c;Docker镜像构建过程中&#xff0c;如果没有正确地将配置文件复制到镜像中&#xff0c;那么在运行容器时就会丢失挂载的配置文件。 所以有2种解决办法&#xff1a; 第一种: 将挂载在宿主机上的配置文件复制到镜像中&#xff0c;可以参考这位老铁的文章《D…

多项式重构的平滑和法线估计-------PCL

多项式重构的平滑和法线估计 /// <summary> /// 多项式重构的平滑和法线估计 /// </summary> /// <param name"cloud"></param> /// <returns>输出一个包含平滑后的点云数据以及相应法线信息的数据结构</returns> pcl::PointCl…

28v电源 28V电源系统 28v航空电源系统概述

28V电源是指一种工作电压为28V的直流电源系统&#xff0c;主要用于航空电子、航天、J事和高端工业应用中。它通常用于为复杂的电子设备和系统供电&#xff0c;如飞机上的导航、通信、控制面板、计算机系统等。这些设备需要稳定的电压输入&#xff0c;而28V电压既能够保证电力供…

Docker 存储路径修改教程

简介 Docker 在长时间使用后&#xff0c;可能会因为镜像和容器的积累导致默认存储空间不足。本技术文档将指导您如何安全地将 Docker 的镜像和容器存放路径修改至挂载的磁盘中&#xff0c;以解决空间不足的问题。请确保在操作前&#xff0c;您的目标磁盘已经成功挂载。 查看 …

双向长短期记忆网络(BiLSTM)简介

双向长短期记忆网络&#xff08;Bidirectional Long Short-Term Memory, BiLSTM&#xff09;是一种改进的循环神经网络&#xff08;Recurrent Neural Network, RNN&#xff09;&#xff0c;专门设计用于处理序列数据。BiLSTM 能够通过结合前向和后向两个 LSTM 网络的输出来捕捉…

第12周作业--HLS入门

目录 一、HLS入门 二、HLS入门程序编程 创建项目 1、点击Vivado HLS 中的Create New Project 2、设置项目名 3、加入文件 4、仿真 3、综合 一、HLS入门 1. HLS是什么&#xff1f;与VHDL/Verilog编程技术有什么关系? HLS&#xff08;High-Level Synthesis&#xff0c…

(Askchat.ai、360智脑、鱼聪明、天工AI、DeepSeek)

目录 1、Askchat.ai - 梦想为蓝图&#xff0c;ChatGPT为笔。 2、360智脑 — 以人为本&#xff0c;安全可信 3、鱼聪明AI - 做您强大的AI助手 (yucongming.com) 4、天工AI-搜索、对话、写作、文档分析、画画、做PPT的全能AI助手 (tiangong.cn) 5、DeepSeek | 深度求索 1、Askch…

基于STM32实现智能风扇控制系统

目录 文章主题环境准备智能风扇控制系统基础代码示例&#xff1a;实现智能风扇控制系统 PWM控制风扇速度温度传感器数据读取串口通信控制应用场景&#xff1a;智能家居与环境调节问题解决方案与优化收尾与总结 1. 文章主题与命名 文章主题 本教程将详细介绍如何在STM32嵌入式…

Docker Desktop安装和如何在WSL2中使用Docker

最近在使用WSL的过程中&#xff0c;想使用docker遇到了一些问题&#xff0c;在WSL中安装Linux版本的docker&#xff0c;启动镜像之后不能从Windows机器的端口映射出来&#xff0c;查了一圈之后&#xff0c;发现应该使用Docker Desktop软件&#xff0c;下面是安装和使用的方式 …

[源码+搭建教程]西游伏妖篇手游_GM_单机+和朋友玩

为了学习和研究软件内含的设计思想和原理&#xff0c;本人花心血和汗水带来了搭建教程&#xff01;&#xff01;&#xff01; 教程不适于服架设&#xff0c;严禁服架设&#xff01;&#xff01;&#xff01;请牢记&#xff01;&#xff01;&#xff01; 教程仅限学习使用&…

深入解析自注意力机制(Self-Attention):深度学习中的关键创新

Self-Attention 深入解析自注意力机制&#xff08;Self-Attention&#xff09;&#xff1a;深度学习中的关键创新自注意力机制的起源自注意力机制的工作原理关键组件公式表达 自注意力机制的应用结论 深入解析自注意力机制&#xff08;Self-Attention&#xff09;&#xff1a;深…

26条提示词工程策略

#原则中文原则1No need to be polite with LLM so there is no need to add phrases like “please”, “if you don’t mind”, “thank you”, “I would like to”, etc., and get straight to the point.不需要对 LLM 使用礼貌用语&#xff0c;因此无需添加诸如“请”、“如…

springboot集成达梦数据库8

springboot集成达梦数据库8 官方文档&#xff1a;[https://eco.dameng.com/document/dm/zh-cn/start/java-development.html](https://eco.dameng.com/document/dm/zh-cn/start/java-development.html) 引入maven依赖 <!--添加数据库驱动安装包--> <dependency> …

Threejs路径规划_基于A*算法案例完整版

上节利用了A*实现了基础的路径规划&#xff0c;这节把整个功能完善好&#xff0c;A*算法一方面是基于当前点找到可以到达的点&#xff0c;计算从出发点到此点&#xff0c;以及此点到目的地的总成本&#xff0c;比较出最小的那个&#xff0c;再用最小成本的点继续找到它可以到达…

明天(周六)下午!武汉Linux爱好者线下沙龙,我们在华中科技大学等你!

2024 年 5月 25 日&#xff08;周六&#xff09;下午&#xff0c;我们将在「武汉市洪山区」 珞喻路 1037 号华中科技大学南五楼 613 室举办武汉 Linux 爱好者线下沙龙&#xff08;WHLUG&#xff09;&#xff0c;欢迎广大 Linux 爱好者来到现场&#xff0c;与我们一同交流技术&a…

git分支开发主干合并流程

文章目录 一、分支开发二、主干合并三、删除合并过的分支 一、分支开发 创建分支git branch <分支名> # git branch my_new_branch开发后提交代码git commit -m 本次开发内容 # git commit -m 增加登录保持功能同步远端仓库git push origin <分支名> # git push o…

Kubernetes——资源调度与Pod探针

目录 前言 一、资源调度策略 1.默认调度器&#xff08;Default Scheduler&#xff09; 2.自定义调度器&#xff08;Custom Scheduler&#xff09; 3.亲和性与反亲和性&#xff08;Affinity and Anti-Affinity&#xff09; 4.污点与容忍&#xff08;Taints and Toleration…

单体应用与微服务的优缺点

单体应用与微服务的优缺点 单体应用&#xff08;monolith application&#xff09;就是将应用程序的所有功能都打包成一个独立的单元&#xff0c;可以是 JAR、WAR、EAR 或其它归档格式。 随着业务需求的快速发展变化&#xff0c;敏捷性、灵活性和可扩展性需求不断增长&#x…

Window GDI+ API有BUG?GetBounds测不准?

文章目录 GraphicsPath的GetBounds测不准&#xff1f;方法一&#xff1a;GetBounds ()实战 方法二&#xff1a;GetBounds(Matrix)实战 GraphicsPath的GetBounds测不准?实战 .NET 版本的问题&#xff1f;C也一样&#xff0c;不是.NET的问题怀疑人生MiterLimit惹得祸完美结果结束…