我正在尝试编写一个汇编程序,该程序在 c 中调用一个函数,假设 char 数组中的当前字符符合某些条件,它将用预定义的字符替换字符串中的某些字符。
我的 c 文件:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
//display *((char *) $edi)
// These functions will be implemented in assembly:
//
int strrepl(char *str, int c, int (* isinsubset) (int c) ) ;
int isvowel (int c) {
if (c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u')
return 1 ;
if (c == 'A' || c == 'E' || c == 'I' || c == 'O' || c == 'U')
return 1 ;
return 0 ;
}
int main(){
char *str1;
int r;
// I ran my code through a debugger again, and it seems that when displaying
// the character stored in ecx is listed as "A" (correct) right before the call
// to "add ecx, 1" at which point ecx somehow resets to 0 when it should be "B"
str1 = strdup("ABC 123 779 Hello World") ;
r = strrepl(str1, '#', &isdigit) ;
printf("str1 = \"%s\"\n", str1) ;
printf("%d chararcters were replaced\n", r) ;
free(str1) ;
return 0;
}
还有我的 .asm 文件:
; File: strrepl.asm
; Implements a C function with the prototype:
;
; int strrepl(char *str, int c, int (* isinsubset) (int c) ) ;
;
;
; Result: chars in string are replaced with the replacement character and string is returned.
SECTION .text
global strrepl
_strrepl: nop
strrepl:
push ebp ; set up stack frame
mov ebp, esp
push esi ; save registers
push ebx
xor eax, eax
mov ecx, [ebp + 8] ;load string (char array) into ecx
jecxz end ;jump if [ecx] is zero
mov esi, [ebp + 12] ;move the replacement character into esi
mov edx, [ebp + 16] ;move function pointer into edx
xor bl, bl ;bl will be our counter
firstLoop:
add bl, 1 ;inc bl would work too
add ecx, 1
mov eax, [ecx]
cmp eax, 0
jz end
push eax ; parameter for (*isinsubset)
;BREAK
call edx ; execute (*isinsubset)
add esp, 4 ; "pop off" the parameter
mov ebx, eax ; store return value
end:
pop ebx ; restore registers
pop esi
mov esp, ebp ; take down stack frame
pop ebp
ret
当通过 gdb 运行它并在 ;BREAK 处放置断点时,在我对 call 命令采取步骤后,它会出现段错误,并出现以下错误:
Program received signal SIGSEGV, Segmentation fault.
0x0081320f in isdigit () from /lib/libc.so.6
isdigit 是我的 c 文件中包含的标准 c 库的一部分,所以我不知道该怎么做。
编辑:我已经编辑了我的 firstLoop 并包含了一个 secondLoop,它应该用“#”替换任何数字,但它似乎替换了整个数组。
firstLoop:
xor eax, eax
mov edi, [ecx]
cmp edi, 0
jz end
mov edi, ecx ; save array
movzx eax, byte [ecx] ;load single byte into eax
mov ebp, edx ; save function pointer
push eax ; parameter for (*isinsubset)
call edx ; execute (*isinsubset)
;cmp eax, 0
;jne end
mov ecx, edi ; restore array
cmp eax, 0
jne secondLoop
mov edx, ebp ; restore function pointer
add esp, 4 ; "pop off" the parameter
mov ebx, eax ; store return value
add ecx, 1
jmp firstLoop
secondLoop:
mov [ecx], esi
mov edx, ebp
add esp, 4
mov ebx, eax
add ecx, 1
jmp firstLoop
使用 gdb,当代码进入 secondloop 时,一切正常。ecx 显示为“1”,这是从 .c 文件传入的字符串中的第一个数字。Esi 应显示为“#”。但是,在我执行 mov [ecx] 之后,esi 它似乎分崩离析。ecx 此时显示为“#”,但是一旦我增加 1 以到达数组中的下一个字符,它就会被列为“/000”并显示。1 之后的每个字符被“#”替换为“/000”并显示。在我让 secondLoop 尝试用“#”替换字符之前,我只是让 firstLoop 用它自己循环,看看它是否可以在不崩溃的情况下通过整个数组。确实如此,并且在每次增加 ecx 后都显示为正确的字符。