Page 1 of 1

memcpy function (interfacing C & nasm)

Posted: Fri Apr 09, 2004 7:52 am
by ich_will
hi I wrote a memcpy function but doesn't work, but I think it have to work:

Code: Select all

[global _memcpy]; void *memcpy(void *dest, const void *src, unsigned int count);

;after three pushes
;ebp + 8  = dest
;ebp + 12 = src
;ebp + 16 = count

_memcpy:
   push ebp
   push esi
   push edi

   mov edi, [ebp+8]   ; edi = dest
   mov esi, [ebp+12]   ; esi = src
   mov ecx, [ebp+16]   ; ecx = count
   rep movsb   ; for(i = 0; i < ecx; i++){edi[i]=esi[i]}
   pop edi
   pop esi
   pop ebp
   mov eax, [ebp]      ; eax = return value = dest
   ret
it seems that the function does nothing

Re:memcpy function (nasm)

Posted: Fri Apr 09, 2004 8:06 am
by DennisCGc
What about setting up DS and ES ?

Code: Select all

[global _memcpy]; void *memcpy(void *dest, const void *src, unsigned int count);

;after three pushes
;ebp + 8  = dest
;ebp + 12 = src
;ebp + 16 = count

_memcpy:
   push ebp
   push esi
   push edi
   push ds
   push es
   push ax
   mov ax, 16 ;source segment
   mov ds, ax ;source segment to DS (also source ;) )
   mov ax, 24 ;destination segment
   mov es, ax ;dest. segment to ES (also dest. ;) )
   mov edi, [ebp+8]   ; edi = dest
   mov esi, [ebp+12]   ; esi = src
   mov ecx, [ebp+16]   ; ecx = count
   rep movsb   ; for(i = 0; i < ecx; i++){edi[i]=esi[i]}
   pop edi
   pop esi
   pop ebp
   mov eax, [ebp]      ; eax = return value = dest
   ret
And what another problem could be is some invalid pushes and pops, which means wrong edi and esi.. but I don't know sure.

Re:memcpy function (nasm)

Posted: Fri Apr 09, 2004 8:27 am
by Adek336
try setting the direction flag. perhaps it copies memory downwards? i think the opcodes were cld and std

Re:memcpy function (nasm)

Posted: Fri Apr 09, 2004 9:10 am
by Pype.Clicker

Code: Select all

    push ebp
    mov ebp, esp
should be a better start ;)

Re:memcpy function (nasm)

Posted: Fri Apr 09, 2004 10:40 am
by Schol-R-LEA
It's actually very simple: while you save the old EBP, you aren't setting it to the current ESP, so it's trying to use the stack frame from the calling function (EDIT: Looks like Pype beat me to the punch on this one; I spent too much time writing the test code, I guess). There's also a bug in the return value; not only is it using the wrong offset when setting the return value, it sets the return value after restoring the frame buffer, which means it would have the wrong value entirely. Try this:

Code: Select all

[global _kmemcpy]  ; void *kmemcpy(void *dest, const void *src, unsigned int count);

;after three pushes
;ebp + 8  = dest
;ebp + 12 = src
;ebp + 16 = count

_kmemcpy:
   push ebp

   ; set the frame pointer to the current stack pointer
   mov ebp, esp

   push esi
   push edi


   mov edi, [ebp + 8]       ; edi = dest

   ; since the return value is invariant, set it now
   mov eax, edi             ; eax = return value = dest

   mov esi, [ebp + 12]      ; esi = src
   mov ecx, [ebp + 16]      ; ecx = count
   rep movsb                ; for(i = 0; i < ecx; i++){edi[i]=esi[i]}

   pop edi
   pop esi
   pop ebp
   ret
The 'k' prefix is simply to avoid a conflict with the default memcpy() in the existing standard library while testing. I am assuming that you are using COFF, PE or a.out format, also, as the underscores are not needed in ELF. I've test the following code with this (or rather, with the GAS equivalent, in order to simplify some compiler issues), and it works correctly:

Code: Select all

#include <stdio.h>

void *kmemcpy(void *dest, const void *src, unsigned int count);
 
 main()
 {
  int i; 
   
  char alphabet[26] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
                       'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
                       'Q', 'R', 'S', 'T', 'U', 'W', 'X', 'Y', 'Z'};
                       
  char numerals[10] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
  
  char* p;
  
  p =  kmemcpy((void *)(alphabet + 7), (void *)numerals, 6);
  
  if(p == (alphabet + 7))
    {
      for (i = 0; i < 26; i++)
          putchar(alphabet[i]);
    }
  else
    {
      puts("Incorrect return value.");
    }
}
This prints "ABCDEFG012345NOPQRSTUVWXYZ". The actual AT&T code which I tested was:

Code: Select all

.globl _kmemcpy

/* void *kmemcpy(void *dest, const void *src, unsigned int count);

the GAS version of the kmemcpy() function */

/*
 after three pushes
 ebp + 8  = dest
 ebp + 12 = src
 ebp + 16 = count
*/

_kmemcpy:
   pushl %ebp

   /* set the frame pointer to the current stack pointer */
   movl %esp, %ebp

   pushl %esi
   pushl %edi

   movl 8(%ebp),  %eax         /* eax = return value = dest */???
   movl %eax,     %edi         /* edi = dest */
   movl 12(%ebp), %esi         /* esi = src */
   movl 16(%ebp), %ecx         /* ecx = count */
   rep
   movsb                   /* for(i = 0; i < ecx; i++){edi[i]=esi[i]} */

   popl %edi
   popl %esi
   popl %ebp
   
   ret
HTH. C&CW.

Re:memcpy function (nasm)

Posted: Fri Apr 09, 2004 11:37 am
by ich_will
thanks, now it works.