简介
上一篇(https://forum.eepw.com.cn/thread/388462/1)基于RISC-V架构的GCC内嵌汇编的验证测试,我们基于前一篇的RISC-V 的基础上按照ARM的汇编的加载、存储的代码运行在ARM 架构的芯片,内存拷贝函数只要简短的几条存储加载指令即可实现,按照RISC-V 上实现的代码逻辑,本次试验在arm cortex-m33 芯片上验证,代码实现如下:
static __attribute__((noinline)) int my_memcpy(void * src,void * dst,int len) { unsigned int tmp = 0; unsigned int end = (char *)src + len; asm volatile ( "1: ldr %1, [%2] , #4\n" "str %1, [%0], #4\n" "cmp %2, %3 \n" "bcc 1b" : "+r" (dst), "+r" (tmp), "+r" (src) : "r" (end) : "memory"); return len; }
代码中添加如下测试代码,验证函数功能,对应测试代码如下:
static int cmd_mymemcpy_test(int argc, char **argv) { int src[8] = {0x11111111,0x22222222,0x33333333,0x44444444, 0x55555555,0x66666666,0x77777777,0x88888888}; int dst[8] = {}; rt_kprintf("my memcpy test ret = %d\r\n",my_memcpy(src,dst,sizeof(src))); if(memcmp(src,dst,sizeof(src)) == 0) rt_kprintf("my memcpy test ok.\r\n"); int src1[32] = {0x11111111,0x22222222,0x33333333,0x44444444, 0x55555555,0x66666666,0x77777777,0x88888888}; int dst1[32] = {}; rt_kprintf("my memcpy test ret = %d\r\n",my_memcpy(src1,dst1,sizeof(src1))); if(memcmp(src1,dst1,sizeof(src1)) == 0) rt_kprintf("my memcpy test ok.\r\n"); return 0; } MSH_CMD_EXPORT_ALIAS(cmd_mymemcpy_test, mymemcpy, my memcpy test);
上述代码对应的反汇编代码如下,汇编代码主要先将函数形参压栈,然后重新分配r0-r3 寄存器内嵌汇编代码中指定的变量,按照内嵌汇编代码分配寄存器。
00005c80 <my_memcpy>: 5c80: b480 push {r7} 5c82: b087 sub sp, #28 5c84: af00 add r7, sp, #0 5c86: 60f8 str r0, [r7, #12] 5c88: 60b9 str r1, [r7, #8] 5c8a: 607a str r2, [r7, #4] 5c8c: 2300 movs r3, #0 5c8e: 617b str r3, [r7, #20] 5c90: 687b ldr r3, [r7, #4] 5c92: 68fa ldr r2, [r7, #12] 5c94: 4413 add r3, r2 5c96: 613b str r3, [r7, #16] 5c98: 6938 ldr r0, [r7, #16] 5c9a: 68b9 ldr r1, [r7, #8] 5c9c: 697a ldr r2, [r7, #20] 5c9e: 68fb ldr r3, [r7, #12] 5ca0: f853 2b04 ldr.w r2, [r3], #4 5ca4: f841 2b04 str.w r2, [r1], #4 5ca8: 4283 cmp r3, r0 5caa: d3f9 bcc.n 5ca0 <my_memcpy+0x20> 5cac: 60b9 str r1, [r7, #8] 5cae: 617a str r2, [r7, #20] 5cb0: 60fb str r3, [r7, #12] 5cb2: 687b ldr r3, [r7, #4] 5cb4: 4618 mov r0, r3 5cb6: 371c adds r7, #28 5cb8: 46bd mov sp, r7 5cba: f85d 7b04 ldr.w r7, [sp], #4 5cbe: 4770 bx lr
代码运行后运行结果也是正确的完成拷贝。
msh >mymemcpy my memcpy test ret = 32 my memcpy test ok. my memcpy test ret = 128 my memcpy test ok.
从上述反汇编的如下代码,对比可以看出 tmp 编译器分配r2 寄存器,dst 分配r0 寄存器,src 分配寄存器r3寄存器,end 分配r3寄存器
5ca0: f853 2b04 ldr.w r2, [r3], #4 5ca4: f841 2b04 str.w r2, [r1], #4 5ca8: 4283 cmp r3, r0 5caa: d3f9 bcc.n 5ca0 <my_memcpy+0x20> asm volatile ( "1: ldr %1, [%2] , #4\n" "str %1, [%0], #4\n" "cmp %2, %3 \n" "bcc 1b" : "+r" (dst), "+r" (tmp), "+r" (src) : "r" (end) : "memory");
在此基础上修改代码为,修改代码为符号的方式替代%0 %1 的方式,修改代码如下:
static __attribute__((noinline)) int my_memcpy(void * src,void * dst,int len) { unsigned int tmp = 0; unsigned int end = (char *)src + len; asm volatile ( "1: ldr %[tmp], [%[src]] , #4\n" "str %[tmp], [%[dst]], #4\n" "cmp %[src], %[end] \n" "bcc 1b" : [dst] "+r" (dst), [tmp] "+r" (tmp), [src] "+r" (src) : [end] "r" (end) : "memory"); return len; }
修改后生成的反汇编代码和之前也是一致的,运行测试代码也是ok的。