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

yizhihongxing

浅析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日

相关文章

  • QT中对Mat类的一些操作详解

    QT中对Mat类的一些操作详解 Mat类简介 Mat类是OpenCV图像处理库中常用的一个类,它可以用来存储图像数据信息,并提供了很多对图像进行操作的方法。在QT中,可以使用OpenCV库中的Mat类来进行图像处理操作。 Mat类的创建与初始化 Mat类提供了很多构造函数,可以根据不同的参数来创建不同的Mat对象。下面是一些常用的构造函数: // 创建一个空…

    C 2023年5月23日
    00
  • C++中的对象初始化操作代码

    下面就来详细讲解一下 C++ 中的对象初始化操作代码的完整攻略。 什么是对象初始化 在 C++ 中,定义一个对象后不仅要申请存储空间,还需要对对象进行赋值或初始化,以便使其具备正确的初始值和状态。对象初始化即是给刚申请的存储空间一个初始值和状态的过程,其作用是为了确保程序的正确性和安全性。因此,在使用对象之前应确保其已被正确初始化。 对象初始化方式 在 C+…

    C 2023年5月23日
    00
  • 用函数模板,写一个简单高效的 JSON 查询器的方法介绍

    使用函数模板来写一个简单高效的 JSON 查询器,需要以下步骤: 1. 定义 JSON 数据结构 首先需要定义一个JSON数据结构,以便对其进行查询。这里我们将使用一个基于std::map的存储结构来表示JSON对象。其中,每个JSON对象的键值对都将被存储为std::map中的一对键-值。对于嵌套的JSON对象,我们可以将其表示为std::map的嵌套结构…

    C 2023年5月23日
    00
  • PHP使用JSON和将json还原成数组

    关于PHP使用JSON和将JSON还原成数组的攻略,可以分为以下几个步骤: 1. PHP使用JSON 1.1 创建JSON字符串 在PHP中使用json_encode()函数可以将数组转换为JSON格式的字符串。例如: $array = array( ‘name’ => ‘Tom’, ‘age’ => 25, ‘sex’ => ‘male’…

    C 2023年5月23日
    00
  • C++实现的链表类实例

    以下是C++实现的链表类实例的完整攻略。 1. 什么是链表 链表是计算机中常用的一种动态数据结构,它通过节点之间的指针连接,可以比较方便地增、删、改、查数据。链表的节点结构一般包含两部分:数据域和指针域,数据域存储节点所存储的数据,指针域存储下一个节点的位置信息。 2. C++中实现链表类的关键 在C++中,我们可以通过定义一个链表类来实现链表的操作。链表类…

    C 2023年5月23日
    00
  • 教你使用MySQL Shell连接数据库的方法

    下面是关于“教你使用MySQL Shell连接数据库的方法”的完整攻略。 1. 下载和安装 MySQL Shell MySQL Shell可以从Mysql官网下载,下载完成后,根据操作系统类型进行安装。 2. 连接服务器 使用MySQL Shell连接数据库需要以下信息: IP地址或主机名 端口 用户名 密码 下面是连接服务器的示例: mysqlsh roo…

    C 2023年5月23日
    00
  • python基础教程之popen函数操作其它程序的输入和输出示例

    Python基础教程之popen函数操作其他程序的输入和输出示例 什么是popen函数? popen函数是Python中一个用于打开一个进程作为管道的函数。通过它,你可以利用子进程的标准输入、输出、错误流和父进程之间的通信。popen函数本质上使用子进程来读取、写入或处理数据。 如何使用popen函数? 使用popen函数可以通过以下步骤来完成: 导入sub…

    C 2023年5月22日
    00
  • Win7安装程序遇到错误代码0xc8000222怎么办

    Win7安装程序遇到错误代码0xc8000222 的解决方法 在安装Windows 7的时候,有时会遇到错误代码0xc8000222,导致安装失败。该错误代码是由于Windows Update组件的某些问题引起的,不过该问题并不是很难解决。下面是一些解决方法: 方法1: 检查Windows Update服务 首先,我们需要检查Windows Update服务…

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