我是ARM装配的新手,对我来说很光鲜。我正在为Android编写音乐可视化应用程序。我正处于我想要优化的地方,所以现在我正在尝试。下面是我对8位memset混合ASM和C实现的尝试。
某处导致崩溃。我无法将gdb附加到进程,因为该应用程序 在gdb启动之前退出,因此我无法单步执行操作。
这看起来不错吗?我从来没有完全围绕内存对齐,但我知道ARM是4字节对齐。我不确定这是否是对解决方案的暗示。我认为混合方法是在一个汇编循环中堆叠大部分操作,然后每次传递8个字节完成它,可以解决任何对齐问题。我在想这个是正确的吗?我对于出了什么问题感到困惑。这与memcpy函数非常类似,我当时唯一的问题是clobber列表是空的。将这些寄存器添加到clobber列表完成了该函数,我无法弄清楚这个memset函数我缺少什么。
任何提示?
* Memset functions, 1 byte memset */
static void *mem_set8_arm (void *dest, int c, visual_size_t n)
{
uint32_t *d = dest;
uint8_t *dc = dest;
uint32_t setflag32 =
(c & 0xff) |
((c << 8) & 0xff00) |
((c << 16) & 0xff0000) |
((c << 24) & 0xff000000);
uint8_t setflag8 = c & 0xff;
#if defined(VISUAL_ARCH_ARM)
while (n >= 64) {
__asm __volatile
(
"\n\t mov r4, %[flag]"
"\n\t mov r5, r4"
"\n\t mov r6, r4"
"\n\t mov r7, r4"
"\n\t stmia %[dst]!,{r4-r7}"
"\n\t stmia %[dst]!,{r4-r7}"
:: [dst] "r" (d), [flag] "r" (&setflag32) : "r4", "r4", "r6", "r7");
d += 16;
n -= 64;
}
#endif /* VISUAL_ARCH_ARM */
while (n >= 4) {
*d++ = setflag32;
n -= 4;
}
dc = (uint8_t *) d;
while (n--)
*dc++ = setflag8;
return dest;
}
答案 0 :(得分:2)
stmia
写入16个字节,因此两次写入写入32个字节。你正在向一个指向32位值的指针添加16,每次有效地增加64,所以会有漏洞。
此外,ARM没有32位立即数,但很多汇编程序通过在函数后面的特殊区域生成数据字段并将mov
转换为PC相对{{1}来解决这个问题。 }。检查生成的汇编器输出是否可能在指令流的中间生成该字段。
此外,您只需在汇编程序中生成32位值:
ldr
由于这是一个8位立即数,它适合,并且不需要生成mov r4, %[mask]
orr r4, r4, r4 lsl #16
orr r4, r4, r4 lsl #8
。
当你在它时,只需将整个循环拉入汇编程序,这样你就可以重用地址寄存器。 gcc在优化包含内联汇编程序的例程方面非常糟糕。
答案 1 :(得分:1)
这是一个错字:
:: [dst] "r" (d), [flag] "r" (&setflag32) : "r4", "r4", "r6", "r7");
你的意思不是"r4", "r5", "r6" ...
吗?
你的自制memset会不会比原来的memset更快?