String 字符串反转函数x86 NASM程序集

String 字符串反转函数x86 NASM程序集,string,x86,nasm,String,X86,Nasm,我正在尝试编写一个函数,该函数使用x86 NASM汇编语言反转字符串中的字符顺序。我试着使用寄存器(我知道使用堆栈更有效),但我一直遇到分段错误,c声明如下 extern char* reverse(char*); 大会部分: section .text global reverse reverse: push ebp ; prologue mov ebp, esp mov eax, [ebp+8] ; ea

我正在尝试编写一个函数,该函数使用x86 NASM汇编语言反转字符串中的字符顺序。我试着使用寄存器(我知道使用堆栈更有效),但我一直遇到分段错误,c声明如下

extern char* reverse(char*);
大会部分:

section .text
global reverse
reverse:
        push ebp           ; prologue
        mov ebp, esp       
        mov eax, [ebp+8]   ; eax <- points to string
        mov edx, eax
look_for_last:
        mov ch, [edx]      ; put char from edx in ch
        inc edx
        test ch, ch        
        jnz look_for_last  ; if char != 0 loop
        sub edx, 2         ; found last
swap:                      ; eax = first, edx = last (characters in string)
        test eax, edx       
        jg end             ; if eax > edx reverse is done
        mov cl, [eax]      ; put char from eax in cl
        mov ch, [edx]      ; put char from edx in ch
        mov [edx], cl      ; put cl in edx
        mov [eax], ch      ; put ch in eax
        inc eax
        dec edx
        jmp swap            
end:
        mov eax, [ebp+8]   ; move char pointer to eax (func return)
        pop ebp            ; epilogue
        ret

为什么会这样?在我的理解中,eax从不超出字符串的界限,所以[eax]中总是有一些东西。我怎么会出现分段错误?

好吧,我弄明白了,我错误地使用了
测试eax,edx
而不是我应该使用的
cmp eax,edx
。它现在可以工作了。

我知道使用堆栈更有效不,它不是!就地反转比对字符串的每一个字节执行4字节的
push
更有效。您的具体实现没有得到优化,但可能仍然更快。(例如,您不使用
bswap
一次反转4个字节,在某些CPU(AMD)上,单独写入cl和ch将对ECX和循环结构产生错误依赖)。当然,您也可以使用SIMD for
strlen
(您称之为
查找最后一个
)使用SSE2一次反转16个字节,或者至少是一次4字节的比特黑客。在您开始交换之前就必须完成这项工作会让一些人感到痛苦,而push/pop实现可以同时完成这项工作。但是push/pop也需要两个循环,它们都可以复制和触摸5倍于只读和就地循环的内存。如果您要倒进一个大的bufAnyway,您甚至可以跳过strlen,使用SSSE3 for
pshufb
您可以在现代x86 CPU上每时钟周期倒16字节,而您的CPU为1字节。我不认为AVX2会有帮助,直到冰湖;其他CPU将成为洗牌吞吐量的瓶颈。不过,IceLake上的AVX512VBMI
vpermb
还是不错的:一次64字节的单uop。另请参见-GCC在自动矢量化单词(aka
short
)反向循环中错过了优化。(我知道这比您可能已经准备好消化的优化更多,但其中一些可能会很有趣。另请参见其他指南、文档和性能链接。)
mov cl, [eax]