我正在尝试编写一个c程序,它将调用汇编函数来反转字符串。然而,我很难让汇编代码遍历字符串以找到结束字符"0“。
我的C代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
// These functions will be implemented in assembly:
//
void strrev(char *str) ;
int main(){
char *str1;
str1 = strdup("Hello World");
strrev(str1);
printf("str1 reversed: \"%s\"\n", str1) ;
free(str1);
return 0;
}我的任何汇编代码都很简单:
; File: strrev.asm
; A subroutine called from C programs.
; Parameters: string A
; Result: String is reversed and returned.
SECTION .text
global strrev
_strrev: nop
strrev:
push ebp
mov ebp, esp
; registers ebx,esi, and edi must be saved if used
push ebx
push edi
xor esi, esi
xor eax, eax
lea ecx, [esp+8] ; load the start of the array into ecx
jecxz end ; jump if [ecx] is zero
mov edi, ecx
reverseLoop:
cmp byte[edi], 0
je end
inc edi
inc eax
jmp reverseLoop
end:
pop edi ; restore registers
pop ebx
mov esp, ebp ; take down stack frame
pop ebp
ret我现在要做的就是简单地遍历字符串,直到它在reverseLoop中找到结尾。但是,如果我尝试使用gdb并逐步执行程序,在查看第一个字符"H“后似乎立即失败。
在使用GDB运行时,在第25行中断,同时使用"display/c $edi“显示edi寄存器,将产生以下输出:
(gdb)
reverseLoop () at strrev.asm:25
25 cmp byte[edi], 0
1: /c $edi = 72 'H'这是正确的,但如果我深入到inc edi,edi立即变得不正确。它应该是"e“,因为"Hello World”中的第二个字符是"E“。但是,gdb输出将其列为"I":
27 inc edi
1: /c $edi = 72 'H'
(gdb)
28 inc eax
1: /c $edi = 73 'I'当我迭代edi寄存器时,我做错了什么吗?
发布于 2013-05-06 20:00:31
您将edi寄存器的内容打印为字符,但其内容实际上是一个地址。您真正想要的是显示edi中的地址指向的内容。
也许可以试一下
display *((char *) $edi)发布于 2013-05-06 20:00:41
用mov cl, [ebp+8]代替lea ecx, [esp+8]怎么样?
发布于 2013-05-06 20:29:51
在函数prologue设置EBP之后,第一个参数是[ebp + 8] [esp + 8]。自从进入strrev()以来,您已经推送了EBP、EBX、EDI,因此在您想要访问函数的第一个参数时移动了ESP。你也应该使用MOV而不是LEA,否则你会得到((char*)$ebp + 8)而不是(*(char**)($ebp + 8))。
最初的mainLoop试图通过一次处理4个字节来实现strlen(),但是只有在一次处理一个字节的情况下,检测'\0'字节和维护字符串长度计数的方法才是正确的。
另一个不相关的错误是,您在EAX中存储(字符串长度/ 2),但在交换字符时也使用AL作为临时存储。AL是EAX的最低字节,字符串长度被破坏,字符交换循环在正确的迭代次数后不会终止。
请看下面的补丁,其中我修复了您问题的早期版本的代码:
--- strrev.asm.orig 2013-05-06 20:25:58.000497875 +0800
+++ strrev.asm 2013-05-06 20:26:29.583835308 +0800
@@ -17,16 +17,37 @@
xor esi, esi
xor eax, eax
- lea ecx, [esp+8] ; load the start of the array into ecx
+ mov ecx, [ebp+8] ; load the start of the array into ecx
jecxz end ; jump if [ecx] is zero
- mov edi, ecx
+
+mainLoop:
+ add eax, 1 ; icn eax would work as well
+ add ecx, 1
+ mov dl, [ecx] ; load ecx
+ cmp dl, 0 ; compare with 0
+ je reverseLoop ; if ecx is zero, we're done
+ jmp mainLoop ; if ecx isn't zero, keep looping
+
reverseLoop:
- cmp byte[edi], 0
- je end
- inc edi
- inc eax
- jmp reverseLoop
+ mov ecx, [ebp + 8] ; reload the start of the array into ecx
+ mov esi, ecx ; esi points to start of array
+ add ecx, eax
+ mov edi, ecx
+ dec edi ;edi points to end of array
+ shr eax, 1 ;eax is the count
+ jz end ; if string is 0 or 1 chars long, jump to end
+
+reverseLoop_1:
+
+ mov cl, [esi] ;load initial array
+ mov bl, [edi] ;load end of array
+ mov [esi], bl ;swap
+ mov [edi], cl
+ inc esi
+ dec edi
+ dec eax ;loop
+ jnz reverseLoop_1
end:
pop edi ; restore registershttps://stackoverflow.com/questions/16398208
复制相似问题