openEuler汇编语言(2)
一、内核汇编器[1]
在使用内嵌汇编指令时,一般不需要指定物理寄存器,编译器一般会作自动分配。若在内嵌汇编指令中使用物理寄存器,那么编译器会在使用前后保存和恢复这些物理寄存器中的值,从而使得这些物理寄存器表现得像被内嵌汇编指令临时使用而不影响其他程序运行。但物理寄存器的使用也是有限制的,例如有一些寄存器如sp在做特定用途时编译器不能恢复它的值,再如不能直接向 pc 寄存器中写入值,程序的跳转只能通过 b 和 bl 指令实现。汇编指令使用的寄存器数目不要过多,否则可能会在分配物理寄存器时造成冲突,编译器发现冲突时会报错。
内嵌汇编器会对一些指令进行展开操作,如一些乘法指令可能会被展开为一系列加法和移位指令。内嵌汇编器不支持内存分配操作,内存分配操作需要用 C/C++ 语句完成。
在 ARM C 语言中,内嵌汇编指令的一般格式如下图所示:
而在 ARM C++ 程序中,除了上述格式,还可以使用如下格式:
这种格式不支持在字符串中携带注释。下图展示了一个使用 ARM C 语言内嵌汇编的例子。在这个例子中,函数中变量x被汇编指令 ADD 自加一并返回,编译器为 x 自动分配了物理寄存器,1前面的#表示立即数。
二、openEuler 汇编代码分析举例
下面我们来尝试具体分析一段 openEuler 中的汇编代码。这段代码在 openEuler 代码仓库的 kernel/arch/arm64/kernel/entry.S 文件中可以找到。
上图中这段代码用于 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 汇编指令混合编程的方法,在下一期我们将进入一个新的话题:操作系统的中断。
[1]《ARM体系结构编程(第二版)》,杜春雷著。
- 点赞
- 收藏
- 关注作者
评论(0)