汇编:函数以及函数参数传递
汇编语言中的函数(或过程)是指一段可以被调用和执行的代码块;它们用于组织和重用代码,并使程序结构更加清晰;由于汇编语言没有高层次语言的语法糖,编写和调用函数涉及直接的堆栈操作和寄存器管理;以下详细介绍汇编函数的定义、调用、参数传递、返回值处理及一些最佳实践。
汇编语言中的函数调用和高层语言类似,但需要手动处理参数传递、堆栈管理和返回值。
函数的定义
函数在汇编中被定义为一个带有标签的代码块,通常使用 proc
和 endp
关键字来定义函数的开始和结束。
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
的函数,用于将两个寄存器 SI
和 DI
中的值相加,并将结果存储在 AX
寄存器中。然后在程序的开始部分调用该函数,最后终止程序。
start:
为程序的入口点,mov si, 5
:将立即数 5 存储到 SI
寄存器中;mov di, 6
:将立即数 6 存储到 DI
寄存器中;call readd
:调用 readd
函数;调用 readd
函数后,SI
中的值变为 11
(16进制B),并且 AX
也将包含 B
。
上述函数是通过寄存器传递参数;在这个示例中,参数 5
和 6
被分别存储在寄存器 SI
和 DI
中,然后调用 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 proc
和 add_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 ax
和 push bx
:将ax
和bx
中的值分别推送到堆栈中,作为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(字节)获得第二个参数;
至此函数参数传递/调用完毕。
相关文章:

汇编:函数以及函数参数传递
汇编语言中的函数(或过程)是指一段可以被调用和执行的代码块;它们用于组织和重用代码,并使程序结构更加清晰;由于汇编语言没有高层次语言的语法糖,编写和调用函数涉及直接的堆栈操作和寄存器管理࿱…...
linux-ftp服务器搭建简介
安装ftp服务器: vsftpd全称为“very secure FTP daemon”,是一个在UNIX类操作系统上运行的服务,可以提供高安全性的FTP服务。 vsftpd是一个免费和开放源代码的FTP服务器软件,它提供了许多其他FTP服务器不支持的特性,例…...

二十一、openlayers官网示例Custom Controls解析——自定义控件扩展Control类
官网demo地址: Custom Controls 这个示例讲的是如何自定义控件 首先创建了一个新的类继承了原本的Control,新增了一个button元素,然后调用了super方法将参数传给了父类。 const button document.createElement("button");button.…...

【博主推荐】HTML5实现520表白、情人节表白模板源码
文章目录 1.设计来源1.1 表白首页1.2 甜蜜瞬间11.3 甜蜜瞬间21.4 甜蜜瞬间31.5 甜蜜瞬间41.6 甜蜜瞬间51.7 甜蜜瞬间61.8 永久珍藏 2.效果和源码2.1 页面动态效果2.2 页面源代码2.3 源码目录2.4 更多为爱表白源码 3.源码下载地址 作者:xcLeigh 文章地址:…...

【YOLOv5/v7改进系列】替换激活函数为SiLU、ReLU、LeakyReLU、FReLU、PReLU、Hardswish、Mish、ELU等
一、导言 激活函数在目标检测中的作用至关重要,它们主要服务于以下几个关键目的: 引入非线性:神经网络的基本构建块(如卷积层、全连接层等)本质上是线性变换,而激活函数通过引入非线性,使得网络…...
修改MySQL root用户密码
ALTER USER ‘root’‘localhost’ IDENTIFIED BY ‘new_password’; ALTER USER ‘root’‘%’ IDENTIFIED BY ‘new_password’; 》 SET GLOBAL read_only OFF; select * from mysql.user;...

力扣刷题---409. 最长回文串【简单】
题目描述 给定一个包含大写字母和小写字母的字符串 s ,返回 通过这些字母构造成的 最长的回文串 。 在构造过程中,请注意 区分大小写 。比如 “Aa” 不能当做一个回文字符串。 示例 1: 输入:s “abccccdd” 输出:7 解释: 我们可以构造的最长的回文串…...

百度智能云参与信通院多项边缘计算标准编制,「大模型时代下云边端协同 AI 发展研讨会」成功召开
1 中国信通院联合业界制定、发布多项标准化成果,推动产业发展 大模型开启了 AI 原生时代,云边端协同 AI 构建了「集中式大规模训练」、「边缘分布式协同推理」新范式,有效降低推理时延和成本,提升数据安全和隐私性,也…...
前后端联调
网关 网关作用(认证授权、流量控制、路由转发等)网关如何工作(类似前端的路由守卫,访问服务前都经过网关) http状态码 3xx:重定向 301:永久重定向 302:临时重定向 304:…...
根据配置的mode环境显示不同的index模板
引言:在项目开发中,遇到了开发环境和生产环境使用模板不同的情况,配置如下: 一、vue.config.js const path require(path) function resolve(dir){return path.join(__dirname,dir) } module.exports {chainWebpack: config &g…...

hls.js实现分片播放视频
前言:hls.js官网:hls.js - npm 一、demo——在HTML中使用 <audio id"audio" controls></audio><script src"https://cdn.jsdelivr.net/npm/hls.jslatest"></script> <script>document.addEventList…...
K8s 运维架构师实战课程
阿良课程收益 掌握Kubernetes企业运维管理 掌握部署、运维、存储、网络、监控、日志、CICD、服务网格等实战全面搞定! 独立将公司任何项目容器化迁移到K8s平台 生产环境真实案例 大厂企业实战经验 学习最新版、最佳实践 K8s 运维架构师实战【初中级】:ht…...

AIGC基础教学:AI+建筑设计,一场划时代变革的序幕已经拉开
2015年9月,美的集团本着把艺术融入民间的理念,邀请了安藤忠雄设计正在筹建中的美术馆。 在历经长达近120天的设计工作之后,美术馆于同年12月动工。这座具有岭南建筑文化意境的美术馆,后来荣获2020年美国建筑大师奖(Architecture …...

领域知识 | 智能驾驶安全领域部分常见概论
Hi,早。 最近想买个新能源车,这个车吧相比于之前的内燃车,新能源车与外界的交互多了很多。比如娱乐的第三方应用,OTA升级等应用。 交互带来的便利越多,暴露的风险自然也就越大,相比于手机等消费者终端设备…...

力扣刷题---返回word中所有不重复的单词
当需要从一个数据集合中去除重复元素时,set是一个很好的选择。由于其不允许存储重复的元素,因此可以很容易地实现去重功能。这在处理原始数据或进行数据分析时特别有用。 题目: 给定一个字符串数组 words,请返回一个由 words 中所…...

正点原子LWIP学习笔记(一)lwIP入门
lwIP入门 一、lwIP简介(了解)二、lwIP结构框图(了解)三、如何学习lwIP(熟悉) 一、lwIP简介(了解) lwIP是一个小型开源的TCP/IP协议栈 阉割的TCP/IP协议 TCP/IP协议栈结构࿰…...
16、设计模式之迭代器模式
迭代器模式 迭代器模式(Iterator Pattern)是 Java 和 .Net 编程环境中非常常用的设计模式。这种模式用于顺序访问集合对象的元素,不需要知道集合对象的底层表示。 迭代器模式属于行为型模式。 介绍 意图: 提供一种方法顺序访问…...

自然语言处理实战项目29-深度上下文相关的词嵌入语言模型ELMo的搭建与NLP任务的实战
大家好,我是微学AI,今天给大家介绍一下自然语言处理实战项目29-深度上下文相关的词嵌入语言模型ELMo的搭建与NLP任务的实战,ELMo(Embeddings from Language Models)是一种深度上下文相关的词嵌入语言模型,它采用了多层双向LSTM编码器构建语言模型,并通过各层LSTM的隐藏状…...
TCP/IP体系模型简介
一、TCP/IP 概念 TCP(Transmission Control Protocol 传输控制协议): 是一种面向连接的、可靠的传输层协议。通过三次握手建立连接,确保连接的可靠建立。对数据进行有序传输,并具有确认机制和重传机制来保证数据的完整…...

【ZYNQ】AXI-Quad-SPI SDK 开发记录 测试
前人工作 如前人工作,在Navigate to BSP Settings中找到历例程 file:///F:/Xilinx/Vitis/2019.2/data/embeddedsw/XilinxProcessorIPLib/drivers/spi_v4_5/doc/html/api/example.html使用XSpi_LowLevelExample例子,源代码的AI解析 int XSpi_LowLeve…...
云计算——弹性云计算器(ECS)
弹性云服务器:ECS 概述 云计算重构了ICT系统,云计算平台厂商推出使得厂家能够主要关注应用管理而非平台管理的云平台,包含如下主要概念。 ECS(Elastic Cloud Server):即弹性云服务器,是云计算…...
多场景 OkHttpClient 管理器 - Android 网络通信解决方案
下面是一个完整的 Android 实现,展示如何创建和管理多个 OkHttpClient 实例,分别用于长连接、普通 HTTP 请求和文件下载场景。 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas…...
拉力测试cuda pytorch 把 4070显卡拉满
import torch import timedef stress_test_gpu(matrix_size16384, duration300):"""对GPU进行压力测试,通过持续的矩阵乘法来最大化GPU利用率参数:matrix_size: 矩阵维度大小,增大可提高计算复杂度duration: 测试持续时间(秒&…...

UR 协作机器人「三剑客」:精密轻量担当(UR7e)、全能协作主力(UR12e)、重型任务专家(UR15)
UR协作机器人正以其卓越性能在现代制造业自动化中扮演重要角色。UR7e、UR12e和UR15通过创新技术和精准设计满足了不同行业的多样化需求。其中,UR15以其速度、精度及人工智能准备能力成为自动化领域的重要突破。UR7e和UR12e则在负载规格和市场定位上不断优化…...
React---day11
14.4 react-redux第三方库 提供connect、thunk之类的函数 以获取一个banner数据为例子 store: 我们在使用异步的时候理应是要使用中间件的,但是configureStore 已经自动集成了 redux-thunk,注意action里面要返回函数 import { configureS…...
Xen Server服务器释放磁盘空间
disk.sh #!/bin/bashcd /run/sr-mount/e54f0646-ae11-0457-b64f-eba4673b824c # 全部虚拟机物理磁盘文件存储 a$(ls -l | awk {print $NF} | cut -d. -f1) # 使用中的虚拟机物理磁盘文件 b$(xe vm-disk-list --multiple | grep uuid | awk {print $NF})printf "%s\n"…...
【Go语言基础【13】】函数、闭包、方法
文章目录 零、概述一、函数基础1、函数基础概念2、参数传递机制3、返回值特性3.1. 多返回值3.2. 命名返回值3.3. 错误处理 二、函数类型与高阶函数1. 函数类型定义2. 高阶函数(函数作为参数、返回值) 三、匿名函数与闭包1. 匿名函数(Lambda函…...

人机融合智能 | “人智交互”跨学科新领域
本文系统地提出基于“以人为中心AI(HCAI)”理念的人-人工智能交互(人智交互)这一跨学科新领域及框架,定义人智交互领域的理念、基本理论和关键问题、方法、开发流程和参与团队等,阐述提出人智交互新领域的意义。然后,提出人智交互研究的三种新范式取向以及它们的意义。最后,总结…...

AI+无人机如何守护濒危物种?YOLOv8实现95%精准识别
【导读】 野生动物监测在理解和保护生态系统中发挥着至关重要的作用。然而,传统的野生动物观察方法往往耗时耗力、成本高昂且范围有限。无人机的出现为野生动物监测提供了有前景的替代方案,能够实现大范围覆盖并远程采集数据。尽管具备这些优势…...

并发编程 - go版
1.并发编程基础概念 进程和线程 A. 进程是程序在操作系统中的一次执行过程,系统进行资源分配和调度的一个独立单位。B. 线程是进程的一个执行实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。C.一个进程可以创建和撤销多个线程;同一个进程中…...