繁体   English   中英

在 x86 NASM 中使用堆栈反转字符串

[英]Reversing a string using stack in x86 NASM

我正在尝试在 x86 NASM 程序集中编写一个函数,该函数反转作为参数传递的字符串中字符的顺序。 我尝试使用堆栈实现它但最终收到错误消息
*** stack smashing detected ***: <unknown> terminated
Aborted (core dumped)
代码如下:

section .text
global reverse
reverse:
        push ebp                ; epilogue
        mov ebp, esp
        mov eax, [ebp+8]
        xor ecx, ecx            ; ecx = 0
        push ebx                ; saved register
push_eax:
        mov edx, [eax]          ; edx = char at eax
        test edx, edx
        jz inc_eax              ; if edx == 0, move eax pointer back and pop eax
        push edx
        inc eax         
        inc ecx                 ; counter + 1
        jmp push_eax
inc_eax:
        sub eax, ecx            ; move eax back to beginning of string
        mov ebx, ecx            ; to move eax back at the end of function                         
pop_eax:      
        test ecx, ecx           ; loop counter == 0
        jz end  
        pop edx                 
        mov [eax], edx          ; char at eax = edx
        inc eax                 ; eax++
        dec ecx                 ; ecx--
        jmp pop_eax
end:
        sub eax, ebx
        pop ebx                 ; saved register
        mov esp, ebp
        pop ebp
        ret

C声明:

extern char* reverse(char*);

我在某个地方读到过,当您尝试在一个比分配的长的数组中写入一些东西时会遇到此错误,但我不知道该函数将如何执行?

另外,当我没有在末尾使用ebx时,我手动将eax中的指针向后移动(长度为 9 的 C 中的字符串 -> sub eax, 9 ),我在输出中得到了反转的字符串,后跟第 2、第 3 和第 4 个字符。 (无论我在 C 中声明的字符串的长度如何)。 例如
input: "123456789" output: "987654321234"
但这只有在我手动移动eax时才会发生,像上面的代码一样使用ebx会输出一些垃圾。

彼得的回答就是您正在寻找的答案。 但是,我可以评论该技术吗? 你必须使用堆栈吗? 您是否已经知道字符串的长度,还是必须自己计算/找到?

例如,如果您已经知道字符串的长度,是否可以将一个指针放在第一个,另一个放在最后并简单地交换字符,将每个指针向中心移动直到它们相遇? 这样做的好处是不假设堆栈上有足够的空间用于字符串。 事实上,除了序言和结语之外,您甚至不需要接触堆栈。 (请注意,当它是一个“结束”术语时,您评论说结语位于顶部。)

如果您不知道字符串的长度,要使用上述技术,您必须先找到空字符。 通过这样做,您甚至在开始之前就已经触及了字符串中的每个字符。 优势,它现在被加载到缓存中。 缺点,你必须再次触摸每个字符,本质上是读取字符串两次。 但是,由于您使用的是汇编,因此重复的scasb指令相当快,并且具有自动神奇地将指针放置在字符串末尾附近的额外优势。

我不希望通过问这些问题得到答案。 我只是根据任务的某些标准建议一种不同的技术。 当我阅读这个问题时,立即想到以下内容:

  p[i] <-> p[n-1]
  i++, n--
  loop until n <= i

请注意,在您迈出第一步之前,您需要检查“n”实际上是否大于“i”。 即:它不是零长度字符串。

如果这是一个 1 字节字符的字符串,您需要movzx edx, byte [eax]字节加载和mov [eax], dl字节存储。

您正在执行 4 字节存储,这可能会超出数组末尾的字节。 你也可能读过头了,直到你在堆栈中找到一个全为零的双字。 test edx, edx是好的,但加载整个单词可能会导致过度读取。

使用调试器查看您对输入 arg周围的内存所做的操作。

(即确保你没有写到数组的末尾,这可能是这里发生的,踩到缓冲区溢出检测 cookie。)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM