【发布时间】:2013-04-30 04:14:29
【问题描述】:
我正在尝试编写一个调用汇编函数来反转字符串的 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”后似乎立即失败。
在第 25 行使用 GDB 运行,同时使用“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 寄存器时是否做错了什么?
【问题讨论】:
-
顺便问一下,这是在 32 位还是 64 位系统上?如果是 64 位系统,则删除地址的前 32 位,使指针指向内存中完全不同的位置。
-
第一个参数是 [ebp + 8] 而不是 [esp + 8]。您还应该使用 LEA 的 MOV instea,否则您会得到
((char*)$ebp + 8)而不是(*(char**)($ebp + 8))。看看我的回答
标签: c arrays assembly cpu-registers