我是汇编语言的新手,我试图将一个字符串从输入字符const char* source
复制到输入参数char* destination
中给定的另一个字符串中,我必须通过x86来实现,下面是我的代码:
注意:volatile标记变量/代码区域可以从外部源意外更改。
void samestring(const char* start, char* end) {
asm volatile (
"mov %[src], %%rsi\n"
"mov %[dest], %%rdi\n"
"xor %%al, %%al\n"
"inc %%rdi\n"
"cmpb $0, %%dl\n"
"jne copy_loop\n"
:
: "memory", "%rsi", "%rdi", "%rax", "%rdx"
);
}
字符串
这是我从reddit上找到的关于类似问题的代码,由于我是汇编新手,我真的不知道这种方法是否有效,或者是否有方法可以改进这段代码,所以我想咨询汇编Maven,帮助告诉我我可以和应该在上面的代码中编辑什么,以减少时间消耗,
任何帮助都将不胜感激。
1条答案
按热度按时间eagi6jfj1#
这是非常低效的,包括它将操作数放入
asm
语句的方式,以及循环本身一次复制1个字节。如果您关心x86-64的效率,您应该使用SSE 2一次加载和检查16个字节,就像glibc为
strcpy
编写的手工asm一样。(或32字节的AVX 2)。https://codebrowser.dev/glibc/glibc/sysdeps/x86_64/strcpy.S.html-注意,它必须首先到达对准边界,例如检查指针不在页面的最后16个字节中,然后执行一个未对齐的vec,as with strlen除非你优化的字符串长度可能是0到5个字节,而根本不关心长字符串的性能。使用AVX-512掩码存储(在Intel上高效,在AMD Zen 4上非常慢),向量可能是处理短字符串的有效方法,没有基于不同短长度的分支错误预测的风险,因为每个小于32字节的字符串都以相同的方式分支。
内联asm详情
这迫使编译器将指针存储到内存(
"m"
约束),以便asm模板可以重新加载它们,而不是在"+S"
(RSI)和"+D"
(RDI)寄存器中请求它们,或者更好地是编译器选择的寄存器[src] "+r"(source)
等。它还无缘无故地无效地将AL归零,并且通过加载
movb
而不是movzbl (%[src]), %%edx
(How to load a single byte from address in assembly)来对RDX具有虚假的依赖性。test %dl, %dl
是一种比cmpb $0, %dl
更有效的设置FLAGS的方法。除此之外,循环本身是幼稚的,但如果你想保持简单,作为一个初学者练习,一次只复制1个字节,也不算太坏。