0

I am finishing up an assembly program that replaces characters in a string with a given replacement character. The assembly code calls C functions and the assembly program itself is called from main in my .c file. However, I am trying to find a proper register to store some sort of counter to count the number of times a character is replaced. Eventually I will place that value into eax before returning to the calling c function (which in this case would return that value to r).

Edit: Fixed! I realized I didnt need to actually store the return value of the c function that I was calling through assembly in the ebx register. This freed up bl for use as a counter, and then later I assigned al to bl. Since al is the 16bit version of eax, I can return eax and it will contain the number of characters changed!

My [fixed] assembly code is:

 ; 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
Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
user2357446
  • 656
  • 6
  • 25
  • Your assembly code still contains the same bug as your last questions did – Tony The Lion May 08 '13 at 08:48
  • 1
    Are you asking same question? May be duplicate of http://stackoverflow.com/questions/16435888/assembly-return-int-to-c-function-segfaults – Rohan May 08 '13 at 08:48
  • @Rohan OP has a different question, but has done a bad job of asking. – Tony The Lion May 08 '13 at 08:49
  • @TonyTheLion woops! sorry about that, I copy-pasted the post and forgot to include the changes I made. I have edited my post to show I have fixed that bug – user2357446 May 08 '13 at 08:49
  • @user2357446 its still there `mov eax, 9 push eax ;test` – Tony The Lion May 08 '13 at 08:50
  • @TonyTheLion hmm, edit seems to have taken a second to propagate. try refreshing – user2357446 May 08 '13 at 08:51
  • Also you're using `bl` as a counter in `secondLoop` but then later you move `eax` into `ebx`, which is the 32bit version of your 16bit `bl` – Tony The Lion May 08 '13 at 08:51
  • @TonyTheLion thats my issue really, is that no matter what 16bit counter I try to use for a counter, its 32bit counterpart is already in use somewhere else and cannot be changed – user2357446 May 08 '13 at 08:52
  • @user2357446 I suppose the best thing to do then is to reconsider the design of your program carefully. – Tony The Lion May 08 '13 at 08:56
  • 1
    @TonyTheLion fixed! I realized that I didnt actually need to store the return value of the c function I called through assembly into ebx in firstLoop and secondLoop. This freed up bl for use as a counter and later allowed me to assign al to bl, and since al is the 16bit version of eax, I can simply return back to the calling c function knowing that eax now contains the correct count! – user2357446 May 08 '13 at 08:58
  • 1
    Just a heads up. If you manage to fix the original problem and it didn't turn out to be a completely stupid error then you can answer your own question. This way it is nice and clear for anyone who comes across this later. – Will May 08 '13 at 09:20

1 Answers1

1

There's still a few things wrong here:-

  1. Make sure you're not corrupting registers that need to be preserved! On Win32, the following must be preserved: edi, esi, ebp and ebx (you're trashing edi). Other operating systems may require different registers to be preserved.

  2. The same goes for functions you call, so the function you call must preserve those registers but free to alter the remaining registers.

  3. You're doing a dword zero check for the end of the string, it should be a byte check.

  4. Register usage - each register has a defined usage pattern and some instructions use implicit registers (e.g. loop, mul, etc)

  5. Your comment is wrong. The return is the number of replaced characters, not the input string, unless the code is wrong and the comment is right.

Here's how I'd implement this, written in VS2010 and using MS specific inline assembly format:-

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
  }
}
Skizz
  • 69,698
  • 10
  • 71
  • 108