作者:罗宇哲,中国科学院软件研究所智能软件研究中心

上一期中我们介绍了一些ARM汇编语言的编程方法,这一期我们介绍一下ARM内嵌汇编器并尝试分析一下openEuler中的一段汇编代码。

一、内嵌汇编器1

C/C++编译器中包含了内嵌汇编器,使用这些内嵌汇编器可以在C或C++代码中使用大部分ARM指令和Thumb指令。内嵌汇编指令中,作为操作数的寄存器和常量可以是C或C++表达式,其类型包含char、short和int型。汇编器将这些量视为无符号数,也就是说如果要使用有符号数其符号位需要程序员自己处理。

在使用内嵌汇编指令时,一般不需要指定物理寄存器,编译器一般会作自动分配。若在内嵌汇编指令中使用物理寄存器,那么编译器会在使用前后保存和恢复这些物理寄存器中的值,从而使得这些物理寄存器表现得像被内嵌汇编指令临时使用而不影响其他程序运行。但物理寄存器的使用也是有限制的,例如有一些寄存器如sp在做特定用途时编译器不能恢复它的值,再如不能直接向pc寄存器中写入值,程序的跳转只能通过b和bl指令实现。汇编指令使用的寄存器数目不要过多,否则可能会在分配物理寄存器时造成冲突,编译器发现冲突时会报错。

内嵌汇编器会对一些指令进行展开操作,如一些乘法指令可能会被展开为一系列加法和移位指令。内嵌汇编器不支持内存分配操作,内存分配操作需要用C/C++语句完成。

在ARM C语言中,内嵌汇编指令的一般格式如下图所示:
第二十六期-openEuler汇编语言(2)
而在ARM C++程序中,除了上述格式,还可以使用如下格式:
第二十六期-openEuler汇编语言(2)
这种格式不支持在字符串中携带注释。下图展示了一个使用ARM C语言内嵌汇编的例子。在这个例子中,函数中变量x被汇编指令ADD自加一并返回,编译器为x自动分配了物理寄存器,1前面的#表示立即数。
第二十六期-openEuler汇编语言(2)

二、openEuler汇编代码分析举例

下面我们来尝试具体分析一段openEuler中的汇编代码。这段代码在openEuler代码仓库的kernel/arch/arm64/kernel/entry.S文件中可以找到。
第二十六期-openEuler汇编语言(2)
上图中这段代码用于task_struct切换时寄存器的保存与恢复,x0寄存器保存了切换前task_struct结构体的地址,x1保存了切换后结构体的地址。我们可以看到这段代码首先设置保存切换前寄存器的内存地址(x8寄存器),然后将切换前寄存器编号为x19-x29的寄存器以及lr寄存器都保存到了以x8中地址为栈底的栈中,其中还包含了切换前sp寄存器中的栈指针。然后代码找到了保存下一个task_struct相关状态的栈的栈底地址(也保存在x8中),将栈中的内容恢复到对应的寄存器中,包括lr寄存器和sp寄存器。在这段代码中,load和store指令都使用的是post-indexed寻址方式,也就是先使用x8寄存器中的内存地址,再将这个地址加上立即数16。

三、结语

本期我们考察了ARM内嵌汇编器和C/C++与ARM汇编指令混合编程的方法,在下一期我们将进入一个新的话题:操作系统的中断。
第二十六期-openEuler汇编语言(2)


  1. 《ARM体系结构编程(第二版)》,杜春雷著 ↩︎

相关文章:

  • 2022-12-23
  • 2021-04-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
猜你喜欢
  • 2021-06-05
  • 2021-11-27
  • 2022-02-15
  • 2021-12-07
  • 2021-12-15
  • 2022-12-23
相关资源
相似解决方案