[英]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.