浅析ARM架构下的函数的调用过程

浅析ARM架构下的函数的调用过程

ARM函数调用基本流程

ARM函数调用的基本流程如下:

  1. 调用者保存寄存器(Callee saved registers):在调用函数之前,调用者需要保存被调用者需要用到的寄存器,否则这些值会被调用函数所覆盖,导致逻辑错误。在ARM架构中,callee saved registers 都是 r4-r11,他们将被保存在当前堆栈帧中。

  2. 传递参数:函数调用需要传递参数给函数,ARM架构中使用寄存器 r0-r3 来传递前4个参数,超出4个参数时需要通过栈来传递。

  3. 跳转到被调用函数:使用 bl 指令跳转到被调用函数入口地址。

  4. 被调用函数处理:被调用函数处理时需要处理参数,所以需要使用 r0-r3 从调用函数中读取参数,然后在处理过程中需要保存callee 保存寄存器,然后完成处理。

  5. 返回结果:函数返回时将在r0中放置返回值,然后使用 bx lr指令跳转回调用函数的地址,同时恢复callee saved registers。

例子1

下面是一个简单的C函数,实现对传入参数x和y的加法运算。它的伪代码如下:

void add(int x, int y){
  return x + y;
}

我们编写如下的ARM汇编代码来实现它:

    // Definition of function 'add'
    add:
        //保存callee saved registers
        push    {r4-r7, lr}

        //将参数保存到r4和r5中
        mov     r4, r0
        mov     r5, r1

        //调用add函数进行加法运算
        add     r0, r4, r5

        //恢复callee saved registers
        pop     {r4-r7, lr}

        //返回
        bx      lr

在这个例子中,我们使用了 r4 和 r5 寄存器来保存传入的参数,使用了 r0 来存储函数的返回值。

例子2

下面是一个更加复杂的函数调用例子。我们假设有两个函数 foo 和 bar,其中 foo 调用了 bar 函数。 伪代码如下:

int bar(int x, int y) {
    return x * y;
}

int foo(int x, int y, int z) {
    int val = bar(x, y);
    return val + z;
}

我们编写如下的ARM汇编代码来实现这两个函数:

    // Definition of function 'bar'
    bar:
        //保存callee saved registers
        push    {r4-r7, lr}

        //参数保存
        mov     r4, r0
        mov     r5, r1

        //运算
        mul     r0, r4, r5

        //callee saved registers 恢复
        pop     {r4-r7, lr}

        bx      lr

    // Definition of function 'foo'
    foo:
        //callee saved registers 保存
        push    {r4-r7, lr}

        //bar函数的第一个参数
        mov     r4, r0
        mov     r5, r1

        //bar函数的调用
        bl      bar

        //bar函数的返回值的存在的地址
        mov     r6, r0

        //将第三个参数保存到r0中
        mov     r0, r2

        //callee saved registers 恢复
        pop     {r4-r7, lr}

        //返回最终值,r6 存储了 bar(x,y) 的返回值
        add     r0, r6, r0
        bx      lr

在这个例子中,我们使用了 r4 - r7 的寄存器来保存callee saved registers,使用了 r0 - r5 来传递参数,使用了 r6 来保存 bar 函数的返回值。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:浅析ARM架构下的函数的调用过程 - Python技术站

(0)
上一篇 2023年5月23日
下一篇 2023年5月23日

相关文章

  • C语言实现文件操作实例(简单图示讲解)

    下面是关于“C语言实现文件操作实例(简单图示讲解)”的完整攻略。 操作流程 打开文件 用fopen函数打开文件,语法如下: FILE *fopen(const char *filename, const char *mode) 其中,filename是要打开的文件名,mode是打开文件的模式(例如读取、写入、追加等),返回值是文件指针,用于后续操作。 读取文…

    C 2023年5月23日
    00
  • windows下在vim中搭建c语言开发环境的详细过程

    一、安装vim 下载vim安装包:从vim官方网站(https://www.vim.org/download.php)下载适合你的操作系统版本的vim安装包,将其保存到本地。 安装vim:双击安装包进行安装,选择安装路径,并勾选”Add to PATH”选项,让vim能够在命令行中被调用。 验证安装:打开命令行窗口,输入”vim”命令,如果出现vim编辑器界…

    C 2023年5月23日
    00
  • 详解Python 协程的详细用法使用和例子

    详解Python 协程的详细用法使用和例子 简介 协程(Coroutine)是一种能够暂停执行并保存状态以便之后恢复执行的函数。在Python中,协程可用于高效的异步编程。通过使用async/await语法,我们可以创建协程对象并通过事件循环(Event Loop)的调度运行它们。 协程的基本使用 定义一个协程函数的标准语法如下: async def cor…

    C 2023年5月23日
    00
  • Linux下g++编译与使用静态库和动态库的方法

    下面是针对“Linux下g++编译与使用静态库和动态库的方法”的完整攻略: 1. 编译静态库 1.1 静态库介绍 静态库是在程序编译阶段将库文件的代码全部加入到生成的可执行文件中,因此在程序运行时不需要再去加载这些库文件。另外,同一份静态库可以同时被多个程序使用,节省系统资源。 1.2 编译静态库的方法 编写样例程序如下: // test.cpp #incl…

    C 2023年5月23日
    00
  • JSON在Java中的使用方法实例

    下面是JSON在Java中的使用方法实例的详细攻略: 什么是JSON JSON是一种轻量级的数据交换格式,全称为JavaScript Object Notation。它是一种易于读写的文本格式,可与几乎所有编程语言一起使用,包括Java。 Java中的JSON库 Java中有多个库可以用于处理JSON,其中最流行的库是GSON和Jackson。这里我们以GS…

    C 2023年5月23日
    00
  • 关于C++中sort()函数的用法,你搞明白了没

    介绍C++中sort()函数的用法,有以下几点要点: sort()函数介绍 sort()函数是C++标准模板库(STL)中的一个常用算法,用于对数组或容器元素进行排序,其函数原型如下: template <class RandomAccessIterator> void sort ( RandomAccessIterator first, Ran…

    C 2023年5月22日
    00
  • 如何在C++中实现按位存取

    在C++中,我们可以使用位运算符实现按位存取操作,包括位与、位或、异或、左移、右移等。 使用位与操作实现按位存取 位与操作符 & 可以用来获取一个数字的特定位。假设我们要获取数字 5 的二进制表示中的第二位,可以将其与二进制表示为 00000100 的数字进行位与运算。代码示例如下: int num = 5; int bit = 1 <<…

    C 2023年5月23日
    00
  • C++设计模式之简单工厂模式实例

    C++设计模式之简单工厂模式实例详解 简单工厂模式(Simple Factory Pattern)是一种创建型设计模式,它提供了一种创建对象的最佳方式。简单工厂模式定义了一个工厂类,它可以根据所传递的参数或配置文件的不同,返回不同类的实例。简单工厂模式具有简单易懂,适用范围广等特点,在实际开发中也得到了广泛应用。 简单工厂模式的结构 简单工厂模式包含三个主要…

    C 2023年5月22日
    00
合作推广
合作推广
分享本页
返回顶部