0

我正在完成一个汇编程序,它用给定的替换字符替换字符串中的字符。汇编代码调用 C 函数,而汇编程序本身是从我的 .c 文件中的 main 调用的。但是,我试图找到一个合适的寄存器来存储某种计数器来计算字符被替换的次数。最终,我会在返回调用 c 函数之前将该值放入 eax(在这种情况下,它将将该值返回给 r)。

编辑:固定!我意识到我不需要将通过汇编调用的 c 函数的返回值实际存储在 ebx 寄存器中。这释放了 bl 用作计数器,然后我将 al 分配给 bl。由于 al 是 eax 的 16 位版本,所以我可以返回 eax,它将包含更改的字符数!

我的 [固定] 汇编代码是:

 ; 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 al, [ebp + 12]      ;move the replacement character into esi
    mov edx, [ebp + 16]     ;move function pointer into edx
    xor bl, bl
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  
    push    eax         ; parameter for (*isinsubset)
    mov edx, [ebp + 16]         
    call    edx         ; execute (*isinsubset)

    mov ecx, edi        ; restore array
    cmp eax, 0
    jne secondLoop  
    add esp, 4          ; "pop off" the parameter
    add ecx, 1
    jmp firstLoop

secondLoop:
    mov eax, [ebp+12]
    mov [ecx], al
    inc bl
    mov edx, [ebp+16]
    add esp, 4
    add ecx, 1
    jmp     firstLoop

end:
    xor eax, eax
    mov al, bl
    pop ebx         ; restore registers
    pop esi
    mov esp, ebp        ; take down stack frame
    pop ebp
    ret
4

1 回答 1

1

这里仍然有一些问题:-

  1. 确保您没有破坏需要保留的寄存器!在 Win32 上,必须保留以下内容:edi、esi、ebp 和 ebx(您正在破坏 edi)。其他操作系统可能需要保留不同的寄存器。

  2. 您调用的函数也是如此,因此您调用的函数必须保留这些寄存器,但可以自由更改剩余的寄存器。

  3. 您正在对字符串的结尾进行双字零检查,它应该是字节检查。

  4. 寄存器使用 - 每个寄存器都有一个定义的使用模式,一些指令使用隐式寄存器(例如循环,mul等)

  5. 你的评论是错误的。返回的是替换字符的数量,而不是输入的字符串,除非代码错误且注释正确。

以下是我如何实现它,用 VS2010 编写并使用 MS 特定的内联汇编格式:-

int __declspec (naked) my_strrepl (char *string, int c, int (*isinsubset) (int c))
{
  __asm
  {
    push ebp
    mov ebp, esp
    push esi
    push ebx

    xor ebx,ebx
    mov esi,string
    or esi,esi
    jz null_string

check_loop:
    lodsb
    and eax,0xff
    jz null_string
    push eax
    mov edx,isinsubset
    call edx
    add sp,4
    or eax,eax
    jz check_loop
    inc ebx
    mov eax,c
    mov [esi-1],al
    jmp check_loop

null_string:
    mov eax,ebx
    pop ebx
    pop esi
    mov esp,ebp
    pop ebp
    ret
  }
}
于 2013-05-08T10:21:56.023 回答