当前位置: 首页 > news >正文

【ARM64 常见汇编指令学习 12 -- ARM 汇编函数 的学习】

文章目录

    • 1.1 ARM 汇编函数简介
      • 1.1.1 ARM 汇编标签 Label
      • 1.1.2 ARM 汇编函数属性指令
      • 1.1.3 UEFI 中的函数宏:ASM_FUNC
        • 1.1.3.1 UEFI ASM_FUNC 实现汇编函数
      • 1.1.4 UEFI 预编译前缀宏 ASM_PFX

上篇文章:ARM64 常见汇编指令学习 11 – ARM 汇编宏 .macro 的学习

1.1 ARM 汇编函数简介

ARM汇编中的函数定义并不像高级语言那样有特定的语法,但通常可以通过 标签(label)子程序调用指令 (如BL,BLX) 来实现类似于函数的功能。

例如,下面的代码定义了一个名为 my_function 的 “函数”,它接受一个参数(通过寄存器r0传递),将其值增加 1后返回:

my_function: add r0, r0, #1 bx lr

在这里,my_function 是一个标签,表示这个函数的入口点。add r0, r0, #1是函数的主体,它将寄存器 r0 的值增加 1。最后,bx lr是函数的退出语句,它将执行权返回给调用者。

这个函数可以通过 BL 指令来调用,例如:

mov r0, #5 
bl my_function

在这里,mov r0, #5 将值5加载到寄存器r0中,然后bl my_function跳转到my_function标签处执行代码,同时将返回地址(即下一条指令的地址)保存到链接寄存器lr中。

需要注意的是,这只是最基本的情况。在实际的ARM汇编代码中,函数可能会更复杂,包括更多的寄存器操作、保存和恢复现场、处理函数调用堆栈等。

1.1.1 ARM 汇编标签 Label

在ARM汇编中,标签(Label)是用来标记代码中某一位置的一种机制。标签后面通常跟着一个冒号(:),然后在其后可以是一条或多条汇编指令。我们可以使用标签来作为跳转指令(如b,beq等)的目标,或者作为数据的引用。

例如下面的代码:

start: mov r0, #10 add r1, r0, #5 loop: subs r0, r0, #1 bne loop

在这个代码中,"start"和"loop"就是两个标签。我们可以看到,在"loop"标签后面,有一个循环,它会一直执行,直到r0的值为0为止。

注意,不能在两个不同的地方定义相同名字的标签。而且,标签名是大小写敏感的,也就是说,"Loop"和"loop"是两个不同的标签。

1.1.2 ARM 汇编函数属性指令

在 ARM 汇编中,“.global”,“.section”,".type"都是汇编器指令,它们用于指示汇编器如何处理随后的汇编代码。

  • .global”:它用于声明一个全局标签,也就是说这个标签可以在其他的汇编文件中引用。例如,".global my_func"声明了一个名为my_func的全局标签。

  • .section”:它用于指定接下来的代码或数据应该放在哪个段(section)中。例如,“.section .text"指定接下来的代码应该放在名为".text"的段中。在链接过程中,链接器会将同名的段合并在一起。在”.section"指令后面通常会跟着一个段名,以及一些可选的段属性,如 ,“ax” 段属性,表示这个段是可以执行的(‘x’)和可以读写的(‘a’)。

  • .type”:它用于指定一个符号(通常是一个标签)的类型,这对链接器解析符号的方式有所影响。例如,“.type my_func, %function"指定 my_func 是一个函数类型的符号。”%function"是 GNU汇编器的一个预定义符号类型,表示这个符号是一个函数。这对链接器以及某些调试工具是有用的,它们可以通过这个类型信息来正确地处理这个符号

以下是一个简单的函数定义的例子:

.global    my_func 
.type      my_func, %function 
.section   .text my_func: mov r0, #1 bx lr

在这个例子中,我们定义了一个名为 my_func 的全局函数,这个函数在.text段中,函数的功能是将1放入r0寄存器,然后返回。

1.1.3 UEFI 中的函数宏:ASM_FUNC

见:edk2/ArmPkg/Include/AsmMacroIoLibV8.h

#define _ASM_FUNC(Name, Section)    \.global   Name                  ; \.section  #Section, "ax"        ; \.type     Name, %function       ; \Name:#define ASM_FUNC(Name)  _ASM_FUNC(ASM_PFX(Name), .text. ## Name)

#Section 中的 # 的作用是讲将 Section 字符串化,就是将 _ASM_FUNC 中的 .text 转换成字符串;

1.1.3.1 UEFI ASM_FUNC 实现汇编函数

//x0 postcode value
ASM_FUNC (PostCode_S)mov x24, x1mov x1, #0x87000000str x0,[x1]mov x1, x24ret

1.1.4 UEFI 预编译前缀宏 ASM_PFX

关于宏 ASM_PFX 的定义如下(edk2/MdePkg/Include/Base.h):

//
// For symbol name in assembly code, an extra "_" is sometimes necessary
/////
/// Private worker functions for ASM_PFX()
///
#define _CONCATENATE(a, b)   __CONCATENATE(a, b)
#define __CONCATENATE(a, b)  a ## b///
/// The __USER_LABEL_PREFIX__ macro predefined by GNUC represents the prefix
/// on symbols in assembly language.
///
#define ASM_PFX(name)  _CONCATENATE (__USER_LABEL_PREFIX__, name)

从上面的定义可以看出最后是给 ASM_PFX(name) 中的 name 加了一个 __USER_LABEL_PREFIX__ 前缀。

GNU C中,“__USER_LABEL_PREFIX__” 是一个预定义宏,它的值代表了在该编译环境中用户定义的标签前缀。

在某些平台和编译器中,用户定义的函数和变量在汇编层面需要添加一个前缀。例如,在许多 UNIX 系统中,用户定义的标签需要添加一个下划线"_"作为前缀。

例如,如果你在 C 代码中定义了一个函数"my_function",那么在生成的汇编代码中,这个函数的名称会变成"_my_function"。

在这种情况下,“__USER_LABEL_PREFIX__“的值就会被定义为”_”。然而,在不需要添加前缀的环境中,"__USER_LABEL_PREFIX__"的值就会被定义为空。

这个宏在处理跨平台代码时很有用,特别是需要直接编写汇编代码时,可以通过这个宏来正确地引用C函数或变量,避免平台差异带来的问题。

例如:

void my_function(void); 
asm(".global " __user_label_prefix__ "my_function");

这段代码在需要添加前缀的环境中会被扩展为".global _my_function",而在不需要添加前缀的环境中会被扩展为".global my_function"。

在 UEFI 的代码edk2/MdePkg/Include/AArch64/ProcessorBind.h中可以看到 __USER_LABEL_PREFIX__ 定义为空:

#ifndef __USER_LABEL_PREFIX__
#define __USER_LABEL_PREFIX__
#endif

上篇文章:ARM64 常见汇编指令学习 11 – ARM 汇编宏 .macro 的学习

http://www.lryc.cn/news/109897.html

相关文章:

  • linux下软件安装 - 与GPT对话
  • idea 2023 新版ui中git的相关操作
  • vue3—SCSS的安装、配置与使用
  • Godot 4 源码分析 - Path2D与PathFollow2D
  • ardupilot 中坐标变换矩阵和坐标系变换矩阵区别
  • VR内容研发公司 | VR流感病毒实验虚拟现实课件
  • python——案例10:认识if、elif、else
  • Hadoop中命令检查hdfs的文件是否存在
  • 计算机网络用户接入层设计
  • 全志F1C200S嵌入式驱动开发(应用程序开发)
  • 人工智能学习07--pytorch23--目标检测:Deformable-DETR训练自己的数据集
  • Statefulset 实战 1
  • 没有jodatime,rust怎么方便高效的操作时间呢?
  • 如何把pdf转成cad版本?这种转换方法非常简单
  • MySQL常用函数方法
  • Linux命令200例专栏导读:实用指南助你成为Linux大师
  • ICN6202 MIPIDSI转LVDS桥接芯片的功能及特征 调试文档资料
  • vscode 格式问题
  • OPENCV C++(三)二值化灰度函数+调用摄像头+鼠标响应+肤色检测
  • zabbix简易入门:基本的网络监控、WEB监控
  • 51单片机学习--DS1302可调时钟
  • Matlab统计字符串中共有多少种字符以及每种字符出现次数的功能实现(Matlab R2021a)
  • HTTPS文件传输
  • LOL-v2数据集和VE-LOL数据集的区别
  • RabbitMQ(一) - 基本结构、SpringBoot整合RabbitMQ、工作队列、发布订阅、直接、主题交换机模式
  • 涉及IMU的专业术语
  • 二维数组对角线判断
  • 数据可视化(六)多个子图及seaborn使用
  • opencv-34 图像平滑处理-双边滤波cv2.bilateralFilter()
  • Leetcode 268. Missing Number