赞
踩
__attribute__((always_inline)) void svc_service_add(uint32_t x, uint32_t y, uint32_t* res)
{
register unsigned r0 __asm("r0") = x;
register unsigned r1 __asm("r1") = y;
register unsigned r2 __asm("r2") = (uint32_t)res;
__asm volatile("SVC #4" :: "r" (r0), "r" (r1), "r" (r2));
__asm volatile("STR R0, [R2]");
}
上述是一段调用svc 4服务的接口,期望功能是 res = x + y.
针对 __asm volatile("SVC #4" :: "r" (r0), "r" (r1), "r" (r2));
解释。
"SVC #4"
是触发SVC中断,设置服务号为4:
后面一般跟随可以从汇编指令中反赋值到C代码变量中:
后面一般跟随仅从C代码输入到汇编指令的的变量"r" (r0)
中的 "r"
目测没什么特殊含义,更换成其他字符也是可以的上述代码在运行第一段内嵌汇编时,会将SVC机器码(包含服务号)、r0、r1、r2压入栈中,同时触发SVC中断,进入内核服务中
举个例子:
void testASM(void)
{
register uint32_t val = 12, res;
__ASM volatile (
".syntax unified\n"
"mov %[val],%[res]"
: [res] "=&l" (res)
: [val] "l" (val)
);
printf("res = %d\n", res);
}
// 结果 res = 12
.syntax unified ;使用GNU语法 .section ".rodata" ;定义只读数据段 ;这里没有定义只读数据,如有需要,可在此处定义 .thumb ;使用thumb指令集 .section ".text" ;定义代码段 .align 2 ;定义字节对齐为 2^2 = 4 .eabi_attribute Tag_ABI_align_preserved, 1 ;不知道,这样抄过来的 .thumb_func ;不知道,抄过来的,目测定义函数需要 .type SVC_Handler, %function ;不知道,抄过来的,目测定义为 (一个类型名为SVC_Handler, 描述为函数) .global SVC_Handler ;不知道,抄过来的,目测允许此函数对外声明 .fnstart ;不知道,抄过来的,目测为函数的开始标志,和 .fnend 成对使用 .cantunwind ;不知道,抄过来的,目测定义函数需要 SVC_Handler: ;标号,在此处范围内获取lr寄存器的值,判断SVC服务的触发在主堆栈还是线程堆栈下 mov r0, lr lsrs r0, r0, #3 bcc SVC_MSP ;合成指令,为B + CC,跳转和识别C符号的混合使用,意为当C标号为0时跳转 mrs r0, psp SVC_Number: push {r0,lr} // Save EXC_RETURN bl SVC_Handler_C ;此时r0里的内容时sp指针,调用C函数,同时r0会成为第一个入口参数参与解析 pop {r0,r1} // Restore EXC_RETURN ;不是很理解,压栈时时r0,lr,出栈时时r0,r1 mov lr,r1 bx lr SVC_MSP: mrs r0, msp b SVC_Number .fnend ;不知道,抄过来的,目测为函数的结束标志,和 .fnstart 成对使用 .size SVC_Handler, .-SVC_Handler ;不知道,抄过来的,目测定义函数需要 .end ;汇编文件的截至
void SVC_Handler_C(uint32_t* svc_args) { uint32_t svc_number; svc_number = ((uint8_t*)svc_args[6])[-2]; switch(svc_number) { case 4: printf("SVC 4\r\n"); break; case 5: printf("SVC 5\r\n"); break; default: break; } return; }
svc_args
是传入的sp堆栈地址,由于压栈顺序依次是从左到右(R0, R1, R2, R3, R12, LR, PC, xPSR),因此,svc_args[6]
= PC,即保存机器指令码在flash上的地址,又由于在取指令后PC自动偏移,因此此处的PC指向即将运行的指令,而我们需要的指令在 当前PC - 4
的地址上。由于SVC机器码为 0xDF00 | 服务号
(服务号是8bit的数据),因此 ((uint8_t*)svc_args[6])[-2]
为当前实际触发的服务号。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。