2

I'm trying to put this Memmove C code to assembly and don't get the supposed result.

I'm using x86-64 assembly on xubuntu and after debugging for 2 hours, I don't see where I'm wrong.

C memmove code:

#include <stdio.h> 

extern void * memmove(void *dest, void *src, size_t n);

int main () { 
  char str1[] = "Geeks";  // Array of size 6
  char str2[] = "Quiz";   // Array of size 5 

  puts("str1 before memmove "); 
  puts(str1); 

  /* Copies contents of str2 to sr1 */
  memmove(str1, str2, sizeof(str2));

  puts("\nstr1 after memmove "); 
  puts(str1); 

  return 0; 
} 
/*

void * memmove(void *dest, void *src, size_t n) { 

    char *d = (char *) dest; 
    char *s = (char *) src; 

    if(s == d)
        return dest;

    if(s < d) { 
        //copy from back 
        s=s+n-1; 
        d=d+n-1; 
        while(n--) { 
            *d-- = *s--; 
        } 
    } 
    else { 
        //copy from front 
        while(n--) 
            *d++ = *s++; 
    } 
    return dest; 
} */

Assembly code:

.globl memmove

# RDI = dest
# RSI = src
# RDX = n

# R8 = d
# R9 = s

memmove:
    mov     %rdi, %r8       # d = dest
    mov     %rsi, %r9       # s = src
    jmp     if_equal

if_equal:
    cmp     %r8, %r9        # s == d
    jz      retDest
    ja      else            # s > d
    jb      if_s_minor      # s < d

if_s_minor:
    add     %rdx, %r9       # s = s + n
    sub     $1, %r9         # s = s - 1

    add     %rdx, %r8       # d = d + n
    sub     $1, %r8         # d = d - 1

    jmp     while1

while1:
    cmp     $0, %rdx        # n > 0 ?
    jna     retDest         # if n <= 0 go to retDest
    sub     $1, %rdx        # n--

    movb    (%rsi), %cl     # *dst-- = *src--
    movb    %cl, (%rdi) 

    leaq    -1(%r8), %r8    # *d--
    leaq    -1(%r9), %r9    # *s--
    jmp     while1

else:
    jmp     while2

while2:
    cmp     $0, %rdx        # n > 0 ?
    jna     retDest
    sub     $1, %rdx        # n--

    movb    (%rsi), %cl     # *dst = *src
    movb    %cl, (%rdi) 

    leaq    1(%r8), %r8 # *d++
    leaq    1(%r9), %r9 # *s++
    jmp     while2

retDest:
    mov     %rdi, %rax
    ret

.end

It was supposed to show "Quiz" on the second print but it shows this:

str1 before memmove Geeks

str1 after memmove Qeeks

  • *`char str1[] = "Geeks"; // Array of size 100`* - Nope. && I don't know what `memove()` is. Do you mean `memmove()`? – Swordfish Dec 02 '18 at 15:27
  • Yeah the array of size 100 is wrong. I misplaced the comment. And yes I meam memmove(), I changed it because i previously had a memmove function on the same file. –  Dec 02 '18 at 15:30
  • Edited now the post –  Dec 02 '18 at 15:32
  • Do you care about efficiency at all here? Copying 1 byte at a time is very slow vs. using `movups` to copy 16 bytes at a time. (x86-64 guarantees that SSE2 is available). Or better AVX, or `rep movsb` if AVX isn't available. Look at glibc's memcpy implementation for a good example. https://code.woboq.org/userspace/glibc/sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S.html#19 (glibc memcpy just uses memmove.) – Peter Cordes Dec 02 '18 at 16:23
  • This is my "homework" for college and I'm supposed to move 8 bytes at all times if possible but as that's not always possible. And by the way, that link is full of stuff I can't use. –  Dec 02 '18 at 16:30
  • I'm not very worried with the efficiency. I just want it to work at first –  Dec 02 '18 at 16:30
  • @rkhb I only have the .c and .s files in the folder. –  Dec 02 '18 at 16:46
  • @rkhb: `memmove` behaviour is specified by ISO C and thus gcc is allowed to optimize accordingly. If you want gcc to always use your custom implementation, use `gcc -fno-builtin-memmove`. Or call your function something else. – Peter Cordes Dec 02 '18 at 17:34
  • @rkhb: `extern void * memmove(void *dest, void *src, size_t n);` is the correct prototype for ISO C `memmove`, other than missing a `const` qualifier on `src`. It's not an "override". gcc expects ISO C functions to be declared before use, except `__builtin_` funcs. Normally that's in a header (like `string.h`), but after the preprocessor runs, the compiler doesn't know what came from where. e.g. commenting it gives https://godbolt.org/z/jP9uj3 `warning: implicitly declaring library function 'memmove' with type 'void *(void *, const void *, unsigned long)' [-Wimplicit-function-declaration]` – Peter Cordes Dec 02 '18 at 18:51

1 Answers1

1
movb    (%rsi), %cl     # *dst = *src
movb    %cl, (%rdi) 
leaq    1(%r8), %r8 # *d++
leaq    1(%r9), %r9 # *s++
jmp     while2

The problem here is that your code changes the %r8 and %r9 registers, but the %rdi and %rsi registers that are used in the actual move stay the same, thus repeating copying the same byte again and again!

Same problem of course in the while1 code.

Sep Roland
  • 33,889
  • 7
  • 43
  • 76