汇编调用c函数设置栈的原因

2024-09-01 02:18

本文主要是介绍汇编调用c函数设置栈的原因,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一.栈的整体作用
(1)保存现场/上下文
(2)传递参数:汇编代码调用c函数时,需传递参数

(3)保存临时变量:包括函数的非静态局部变量以及编译器自动生成的其他临时变量。

1.保存现场/上下文
在函数调用之前,应该将这些寄存器等现场,暂时保持起来(入栈push),等调用函数执行完毕返回后(出栈pop),再恢复现场。这样CPU就可以正确的继续执行了。

保存寄存器的值,一般用的是push指令,将对应的某些寄存器的。

C语言函数调用时通常会传递参数,这里使用二种传递参数的方法:
(1)本身传递的参数不多于4个,就可以通过寄存器传送参数。

(2)参数多于4个时,就得用栈了。

3.临时变量保存在栈中

包括函数的非静态局部变量以及编译器自动生成的其他临时变量。

4.举例分析C语言函数调用是如何使用栈的

arm-inux-objdump –d u-boot >dump_u-boot.txt可以得到dump_u-boot.txt文件。
该文件就是中,包含了u-boot中的程序的可执行的汇编代码.
例子:一个是clock_init,另外一个函数CopyCode2Ram:

33d0091c<CopyCode2Ram>:

33d0091c:  e92d4070  push   {r4, r5, r6, lr}
33d00920:  e1a06000  mov r6, r0
33d00924:  e1a05001  mov r5, r1

33d00928:  e1a04002  mov r4, r2

33d0092c:  ebffffef  bl  33d008f0 <bBootFrmNORFlash>
......
33d00984:  ebffff14  bl  33d005dc <nand_read_ll>
......

33d009a8:  e3a00000  mov r0, #0 ; 0x0
33d009ac:  e8bd8070  pop {r4, r5, r6, pc}

33d009b0<clock_init>:

33d009b0:  e3a02313  mov r2, #1275068416   ;0x4c000000
33d009b4:  e3a03005  mov r3, #5 ; 0x5
33d009b8:  e5823014  str r3,

......
33d009f8:  e1a0f00e  mov pc, lr

(1)clock_init部分的代码可以看到该函数第一行:

33d009b0:  e3a02313  mov r2, #1275068416   ;0x4c000000所用到的r2,r3等等寄存器,和前面调用clock_init之前所用到的寄存器r0,没有冲突,所以此处可以不用push去保存这类寄存器的值,不过有个寄存器要注意,那就是r14,即lr,其是在前面调用clock_init的时候,用的是bl指令,所以会自动把跳转时候的pc的值赋值给lr。

而clock_init的代码的最后一行:
33d009f8:e1a0f00e mov pc, lr把lr的值,即之前保存的函数调用时候的PC值,赋值给现在的PC,这样就实现了函数的正确的返回,即返回到了函数调用时候下一个指令的位置。

(2)CopyCode2Ram部分的代码其第一行:
33d0091c:e92d4070 push {r4, r5, r6, lr}用push指令,保存了r4,r5,r以及lr。而用push去保存lr,那是因为此函数里面,还有其他函数调用:

33d0092c:  ebffffef  bl  33d008f0 <bBootFrmNORFlash>
......
33d00984:  ebffff14  bl  33d005dc <nand_read_ll>

......

也用到了bl指令,会改变我们最开始进入clock_init时候的lr的值,所以我们要用push也暂时保存起来。

而对应地,CopyCode2Ram的最后一行:

33d009ac:e8bd8070 pop {r4, r5, r6,pc}就是把之前push的值,给pop出来,还给对应的寄存器,

其中最后一个是将开始push的lr的值,pop出来给赋给PC,因为实现了函数的返回。

另外,在CopyCode2Ram的倒数第二行是:
33d009a8:e3a00000 mov r0, #0 ;0x0是把0赋值给r0寄存器,这个就是我们所谓返回值的传递,是通过r0寄存器的。此处的返回值是0,也对应着C语言的源码中的“return0”.

对于使用哪个寄存器来传递返回值:

当然你也可以用其他暂时空闲没有用到的寄存器来传递返回值,但是这些处理方式,本身是根据ARM的APCS的寄存器的使用的约定而设计的,你最好不要随便改变使用方式,最好还是按照其约定的来处理,这样程序更加符合规范。








这篇关于汇编调用c函数设置栈的原因的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1125666

相关文章

Linux中chmod权限设置方式

《Linux中chmod权限设置方式》本文介绍了Linux系统中文件和目录权限的设置方法,包括chmod、chown和chgrp命令的使用,以及权限模式和符号模式的详细说明,通过这些命令,用户可以灵活... 目录设置基本权限命令:chmod1、权限介绍2、chmod命令常见用法和示例3、文件权限详解4、ch

Java调用Python代码的几种方法小结

《Java调用Python代码的几种方法小结》Python语言有丰富的系统管理、数据处理、统计类软件包,因此从java应用中调用Python代码的需求很常见、实用,本文介绍几种方法从java调用Pyt... 目录引言Java core使用ProcessBuilder使用Java脚本引擎总结引言python

Java汇编源码如何查看环境搭建

《Java汇编源码如何查看环境搭建》:本文主要介绍如何在IntelliJIDEA开发环境中搭建字节码和汇编环境,以便更好地进行代码调优和JVM学习,首先,介绍了如何配置IntelliJIDEA以方... 目录一、简介二、在IDEA开发环境中搭建汇编环境2.1 在IDEA中搭建字节码查看环境2.1.1 搭建步

SpringBoot项目引入token设置方式

《SpringBoot项目引入token设置方式》本文详细介绍了JWT(JSONWebToken)的基本概念、结构、应用场景以及工作原理,通过动手实践,展示了如何在SpringBoot项目中实现JWT... 目录一. 先了解熟悉JWT(jsON Web Token)1. JSON Web Token是什么鬼

使用Spring Cache时设置缓存键的注意事项详解

《使用SpringCache时设置缓存键的注意事项详解》在现代的Web应用中,缓存是提高系统性能和响应速度的重要手段之一,Spring框架提供了强大的缓存支持,通过​​@Cacheable​​、​​... 目录引言1. 缓存键的基本概念2. 默认缓存键生成器3. 自定义缓存键3.1 使用​​@Cacheab

java如何调用kettle设置变量和参数

《java如何调用kettle设置变量和参数》文章简要介绍了如何在Java中调用Kettle,并重点讨论了变量和参数的区别,以及在Java代码中如何正确设置和使用这些变量,避免覆盖Kettle中已设置... 目录Java调用kettle设置变量和参数java代码中变量会覆盖kettle里面设置的变量总结ja

Spring中Bean有关NullPointerException异常的原因分析

《Spring中Bean有关NullPointerException异常的原因分析》在Spring中使用@Autowired注解注入的bean不能在静态上下文中访问,否则会导致NullPointerE... 目录Spring中Bean有关NullPointerException异常的原因问题描述解决方案总结

MySQL的索引失效的原因实例及解决方案

《MySQL的索引失效的原因实例及解决方案》这篇文章主要讨论了MySQL索引失效的常见原因及其解决方案,它涵盖了数据类型不匹配、隐式转换、函数或表达式、范围查询、LIKE查询、OR条件、全表扫描、索引... 目录1. 数据类型不匹配2. 隐式转换3. 函数或表达式4. 范围查询之后的列5. like 查询6

使用Vue.js报错:ReferenceError: “Vue is not defined“ 的原因与解决方案

《使用Vue.js报错:ReferenceError:“Vueisnotdefined“的原因与解决方案》在前端开发中,ReferenceError:Vueisnotdefined是一个常见... 目录一、错误描述二、错误成因分析三、解决方案1. 检查 vue.js 的引入方式2. 验证 npm 安装3.

C++11的函数包装器std::function使用示例

《C++11的函数包装器std::function使用示例》C++11引入的std::function是最常用的函数包装器,它可以存储任何可调用对象并提供统一的调用接口,以下是关于函数包装器的详细讲解... 目录一、std::function 的基本用法1. 基本语法二、如何使用 std::function