以前主要手写汇编,今天尝试用了下内联汇编(Inline Assembly),出了点问题,特此做个总结。
=====================================================================
开发环境:Xilinx ISE 14.4 EDK
编译器版本:gcc version 4.6.3 (Sourcery CodeBench Lite 2012.03-83)
用于测试的C源代码:
void dummy1(void)
{
}
unsigned int dummy2(void)
{
}
unsigned int dummy3(void)
{
return 0x12345678;
}
unsigned int dummy4()
{
asm (
"MRC p15,0,r0,c0,c0,5\n\t"
"AND r0, r0, #3\n\t"
"BX lr\n\t"
);
}
unsigned int dummy5()
{
register int x, y;
asm (
"MRC p15,0,%[value],c0,c0,5\n\t"
"AND %[result], %[value], #3\n\t": [result] "=r" (y): [value] "r" (x)
);
return y;
}
在-O0优化级别下的编译结果:
void dummy1(void)
{
1003c0: e52db004 push {fp} ; (str fp, [sp, #-4]!)
1003c4: e28db000 add fp, sp, #0
}
1003c8: e28bd000 add sp, fp, #0
1003cc: e8bd0800 pop {fp}
1003d0: e12fff1e bx lr
001003d4 <dummy2>:
unsigned int dummy2(void)
{
1003d4: e52db004 push {fp} ; (str fp, [sp, #-4]!)
1003d8: e28db000 add fp, sp, #0
}
1003dc: e1a00003 mov r0, r3
1003e0: e28bd000 add sp, fp, #0
1003e4: e8bd0800 pop {fp}
1003e8: e12fff1e bx lr
001003ec <dummy3>:
unsigned int dummy3(void)
{
1003ec: e52db004 push {fp} ; (str fp, [sp, #-4]!)
1003f0: e28db000 add fp, sp, #0
return 0x12345678;
1003f4: e3053678 movw r3, #22136 ; 0x5678
1003f8: e3413234 movt r3, #4660 ; 0x1234
}
1003fc: e1a00003 mov r0, r3
100400: e28bd000 add sp, fp, #0
100404: e8bd0800 pop {fp}
100408: e12fff1e bx lr
0010040c <dummy4>:
unsigned int dummy4()
{
10040c: e52db004 push {fp} ; (str fp, [sp, #-4]!)
100410: e28db000 add fp, sp, #0
asm (
100414: ee100fb0 mrc 15, 0, r0, cr0, cr0, {5}
100418: e2000003 and r0, r0, #3
10041c: e12fff1e bx lr
"MRC p15,0,r0,c0,c0,5\n\t"
"AND r0, r0, #3\n\t"
"BX lr\n\t"
);
}
100420: e1a00003 mov r0, r3
100424: e28bd000 add sp, fp, #0
100428: e8bd0800 pop {fp}
10042c: e12fff1e bx lr
00100430 <dummy5>:
unsigned int dummy5()
{
100430: e92d0810 push {r4, fp}
100434: e28db004 add fp, sp, #4
register int x, y;
asm (
100438: ee104fb0 mrc 15, 0, r4, cr0, cr0, {5}
10043c: e2044003 and r4, r4, #3
"MRC p15,0,%[value],c0,c0,5\n\t"
"AND %[result], %[value], #3\n\t": [result] "=r" (y): [value] "r" (x)
);
return y;
100440: e1a03004 mov r3, r4
}
100444: e1a00003 mov r0, r3
100448: e24bd004 sub sp, fp, #4
10044c: e8bd0810 pop {r4, fp}
100450: e12fff1e bx lr
注意:
1. 函数dummy4()的编译结果运行时会出问题:首先取到的CP15寄存器的值不会被返回;fp寄存器被改写但是没有恢复;没有和push相匹配的pop,stack会完全乱掉。
2. 函数dummy5()中给两个临时变量声明了register关键字,如果不加,对这两个变量的访问会直接编译成对stack memory的访问。
3. -O0下GCC会在函数进入和退出的时候加上固定的wrapper。
在-O3优化级别下的编译结果:
void dummy1(void)
{
}
1003c0: e12fff1e bx lr
001003c4 <dummy2>:
unsigned int dummy2(void)
{
}
1003c4: e12fff1e bx lr
001003c8 <dummy3>:
unsigned int dummy3(void)
{
return 0x12345678;
}
1003c8: e3050678 movw r0, #22136 ; 0x5678
1003cc: e3410234 movt r0, #4660 ; 0x1234
1003d0: e12fff1e bx lr
001003d4 <dummy4>:
unsigned int dummy4()
{
asm (
1003d4: ee100fb0 mrc 15, 0, r0, cr0, cr0, {5}
1003d8: e2000003 and r0, r0, #3
1003dc: e12fff1e bx lr
"MRC p15,0,r0,c0,c0,5\n\t"
"AND r0, r0, #3\n\t"
"BX lr\n\t"
);
}
1003e0: e12fff1e bx lr
001003e4 <dummy5>:
unsigned int dummy5()
{
register int x, y;
asm (
1003e4: e3a00000 mov r0, #0
1003e8: ee100fb0 mrc 15, 0, r0, cr0, cr0, {5}
1003ec: e2000003 and r0, r0, #3
"MRC p15,0,%[value],c0,c0,5\n\t"
"AND %[result], %[value], #3\n\t": [result] "=r" (y): [value] "r" (x)
);
return y;
}
1003f0: e12fff1e bx lr
注意:
1. 函数dummy4():执行结果会碰巧对了,但是两条BX指令明显不对。
2. 函数dummy5():功能没有问题,但是不是最有效的,第一条指令完全没有必要。
小结:
1. 使用内联汇编(Inline Assembly)的时候没有必要加返回指令BX。
2. 不要在内联汇编中使用指定寄存器,因为编译器在不同的编译选项下对寄存器的处理方式不同。
3. 比较好的办法是在内联汇编中使用临时变量,临时变量前面最好加上register关键字,方便编译器优化。
4. 如果只是写些简单的使用特殊指令的函数,直接写汇编比使用内联汇编(Inline Assembly)方便快捷。
[END]