ARMv7 与 ARMv8 中的 asmlinkage 作用及使用
asmlinkage
是一个宏,通常在内核代码中使用,用于定义调用约定,特别是指定函数的参数是通过栈传递而不是通过寄存器。它主要用于内核与汇编之间的接口函数,使得参数传递更加一致和明确。
ARMv7 和 ARMv8 中的 asmlinkage
在 ARM 架构中,函数参数通常通过寄存器传递,而不是通过栈。asmlinkage
强制参数通过栈传递,而不是通过寄存器。这对于某些特殊的内核函数是必要的,特别是那些需要和汇编代码直接交互的函数。
使用注意事项
- 性能问题: 由于参数传递通过栈而不是寄存器,性能可能会受到影响。因此,只有在确有必要时才使用
asmlinkage
。 - 一致性: 确保函数定义和调用方式的一致性,避免因为调用约定不同而导致的问题。
- 内核与汇编代码的接口: 特别是内核与汇编代码交互时,需要明确传递参数的方式。
汇编例子说明
以下是一个简单的汇编例子,说明如何通过栈传递参数,并在处理函数中获取参数值。
ARMv7 汇编例子
.section .text
.global do_IPI
.type do_IPI, %functiondo_IPI:// 保存寄存器到栈push {r4, lr}// 获取栈上的参数// r0 - ipinr// r1 - regsldr r0, [sp, #8]ldr r1, [sp, #12]// 调用 C 函数 handle_IPIbl handle_IPI// 恢复寄存器pop {r4, lr}bx lr
ARMv8 汇编例子
.section .text
.global do_IPI
.type do_IPI, %functiondo_IPI:// 保存寄存器到栈stp x29, x30, [sp, #-16]!mov x29, sp// 获取栈上的参数// x0 - ipinr// x1 - regsldr x0, [sp, #16]ldr x1, [sp, #24]// 调用 C 函数 handle_IPIbl handle_IPI// 恢复寄存器ldp x29, x30, [sp], #16ret
原C代码
633 asmlinkage void __exception_irq_entry do_IPI(int ipinr, struct pt_regs *regs)
634 {
635 handle_IPI(ipinr, regs);
636 }
参数传递和获取
在上述汇编代码中,参数是通过栈传递的。具体步骤如下:
- 调用函数时,将参数压入栈中。例如,
ipinr
和regs
被依次压入栈中。 - 在函数中,通过调整栈指针和加载指令,从栈中读取参数到寄存器中。
- 调用 C 函数,将参数从寄存器传递给 C 函数。
总结
asmlinkage
在 ARMv7 和 ARMv8 中用于指定参数通过栈传递,适用于内核与汇编代码交互的场景。使用时需要注意性能问题和调用约定的一致性。通过汇编代码,我们可以清晰地看到参数是如何通过栈传递和获取的。