简介 内嵌汇编代码是指在C语言中嵌入汇编代码(Inline Assembly Language in C Code),可以在对代码时间要求比较高,及在C语言中访问某些汇编指令来实现特殊功能,内嵌汇编代码主要有两种形式:基础内嵌汇编代码(basic asm):不带任何参数扩展内嵌汇编代码(extended asm):可以带输入/输出参数,一下是使用内嵌汇编实现的memcpy函数 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的。
|