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

相关文章

  • Golang中的错误处理的示例详解

    Golang中的错误处理的示例详解 为什么需要错误处理 在编程中,无论我们的语言是什么,都会遇到各种错误。为了避免出现错误后程序崩溃或者无法正常工作,我们需要考虑错误的处理方法。Golang官方鼓励使用错误来处理问题,而不是抛出异常或者在程序中使用错误的标记。因此,学习如何使用Golang来处理错误显得尤为必要。 错误类型 在Golang中,错误是一个内置接…

    C 2023年5月22日
    00
  • C语言一维数组

    下面是关于 C 语言一维数组的完整使用攻略。 一维数组定义 在C语言中定义一维数组需要指定数组的类型和数组的长度,例如: int arr1[10]; //声明一个长度为10的整型数组 char arr2[5]; //声明一个长度为5的字符型数组 double arr3[8]; //声明一个长度为8的双浮点型数组 在上述代码中分别定义了三个不同类型的数组,并指…

    C 2023年5月9日
    00
  • C语言实现返回字符串函数的四种方法

    下面为你详细展开C语言实现返回字符串函数的四种方法的完整攻略。 1. 使用字符串指针 步骤: 定义一个函数,函数返回值为 char * 类型,表示返回一个字符串指针; 在函数内部申请一个指针指向堆内存区域,并在该区域中保存返回的字符串; 返回指针。 示例: #include <stdio.h> #include <stdlib.h> …

    C 2023年5月23日
    00
  • C语言 循环

    C语言循环的使用攻略 在C语言编程中,循环结构是一类非常重要的语法工具。它能够帮助程序员快速高效地处理重复性质的任务,以及操作数组等数据结构。本文将详细介绍C语言中的循环结构,包括语法、使用技巧、常见应用场景以及示例说明。 语法实现 C语言的循环结构有三种:for、while和do…while,它们的语法实现分别如下: for循环 for(循环变量的初始…

    C 2023年5月9日
    00
  • C语言实现三子棋的示例代码

    以下是“C语言实现三子棋的示例代码”的完整攻略: C语言实现三子棋的示例代码 简介 三子棋是一种简单的两人游戏,游戏过程中两个选手分别执黑白两色棋子,轮流落子于棋盘上,先将自己的棋子在横、竖、斜方向上连成三个直线即获胜。 本篇文章将以C语言编写三子棋游戏为例,为大家详细讲解示例代码和相关思路。 示例代码实现思路 本示例代码中,我们将采用控制台输出的方式进行界…

    C 2023年5月23日
    00
  • 荣耀畅玩8c手机如何录屏?荣耀畅玩8c录屏教程

    针对您的问题,“荣耀畅玩8c手机如何录屏?荣耀畅玩8c录屏教程”,我为您提供以下完整攻略,希望能帮到您。 荣耀畅玩8c手机录屏 荣耀畅玩8c手机自带录屏功能,可以通过系统自带工具实现录屏。 步骤: 打开手机,确保进入主界面。 打开需要录制的APP,例如微信或者游戏。 下拉状态栏,点击“录屏”按钮,开始录屏。 在录制期间,可以进行操作,并进行操作演示。 可以在…

    C 2023年5月23日
    00
  • C语言从代码中加载动态链接库过程解析

    C语言从代码中加载动态链接库过程解析 什么是动态链接库 动态链接库,又被称为DLL(动态链接库文件),是一个可被多个应用程序同时使用的代码和数据集合。这些库在程序运行时动态地被加载到内存中,使得程序运行更加高效和节省内存。与之相反的是静态链接库,静态链接库是在编译链接期间就已经被链接到可执行文件中,这种方式可以使得程序更独立且安全,但也会降低程序运行的效率。…

    C 2023年5月23日
    00
  • 一篇文章带你入门C语言:函数

    一篇文章带你入门C语言: 函数 函数的定义 函数是 C 语言中组织代码的一种主要方式。在 C 中,函数是由一系列语句组成的代码块,这些语句被命名并可以通过一个函数名来调用。 返回类型 函数名(参数列表) { // 函数体 } 返回类型:函数执行后返回的数据类型,例如 int、float 等。 函数名:函数的名称,可以根据函数的功能进行命名。 参数列表:函数执…

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