Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[libc] Reduce overall code size by externalising memmove()
Typical saving is 15-20 bytes in each file using memmove().

Signed-off-by: Michael Brown <mcb30@ipxe.org>
  • Loading branch information
mcb30 committed Nov 12, 2012
1 parent 7cbac68 commit fc30b13
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 24 deletions.
50 changes: 49 additions & 1 deletion src/arch/x86/core/x86_string.c
Expand Up @@ -35,7 +35,8 @@ FILE_LICENCE ( GPL2_OR_LATER );
* @v len Length
* @ret dest Destination address
*/
void * __memcpy ( void *dest, const void *src, size_t len ) {
void * __attribute__ (( noinline )) __memcpy ( void *dest, const void *src,
size_t len ) {
void *edi = dest;
const void *esi = src;
int discard_ecx;
Expand All @@ -56,3 +57,50 @@ void * __memcpy ( void *dest, const void *src, size_t len ) {
: "memory" );
return dest;
}

/**
* Copy memory area backwards
*
* @v dest Destination address
* @v src Source address
* @v len Length
* @ret dest Destination address
*/
void * __attribute__ (( noinline )) __memcpy_reverse ( void *dest,
const void *src,
size_t len ) {
void *edi = ( dest + len - 1 );
const void *esi = ( src + len - 1 );
int discard_ecx;

/* Assume memmove() is not performance-critical, and perform a
* bytewise copy for simplicity.
*/
__asm__ __volatile__ ( "std\n\t"
"rep movsb\n\t"
"cld\n\t"
: "=&D" ( edi ), "=&S" ( esi ),
"=&c" ( discard_ecx )
: "0" ( edi ), "1" ( esi ),
"2" ( len )
: "memory" );
return dest;
}


/**
* Copy (possibly overlapping) memory area
*
* @v dest Destination address
* @v src Source address
* @v len Length
* @ret dest Destination address
*/
void * __memmove ( void *dest, const void *src, size_t len ) {

if ( dest <= src ) {
return __memcpy ( dest, src, len );
} else {
return __memcpy_reverse ( dest, src, len );
}
}
48 changes: 25 additions & 23 deletions src/arch/x86/include/bits/string.h
Expand Up @@ -26,6 +26,7 @@ FILE_LICENCE ( PUBLIC_DOMAIN );
#define __HAVE_ARCH_MEMCPY

extern void * __memcpy ( void *dest, const void *src, size_t len );
extern void * __memcpy_reverse ( void *dest, const void *src, size_t len );

static inline __attribute__ (( always_inline )) void *
__constant_memcpy ( void *dest, const void *src, size_t len ) {
Expand Down Expand Up @@ -144,29 +145,30 @@ __constant_memcpy ( void *dest, const void *src, size_t len ) {
__memcpy ( (dest), (src), (len) ) )

#define __HAVE_ARCH_MEMMOVE
static inline void * memmove(void * dest,const void * src, size_t n)
{
int d0, d1, d2;
if (dest<src)
__asm__ __volatile__(
"cld\n\t"
"rep\n\t"
"movsb"
: "=&c" (d0), "=&S" (d1), "=&D" (d2)
:"0" (n),"1" (src),"2" (dest)
: "memory");
else
__asm__ __volatile__(
"std\n\t"
"rep\n\t"
"movsb\n\t"
"cld"
: "=&c" (d0), "=&S" (d1), "=&D" (d2)
:"0" (n),
"1" (n-1+(const char *)src),
"2" (n-1+(char *)dest)
:"memory");
return dest;

extern void * __memmove ( void *dest, const void *src, size_t len );

/**
* Copy (possibly overlapping) memory area
*
* @v dest Destination address
* @v src Source address
* @v len Length
* @ret dest Destination address
*/
static inline __attribute__ (( always_inline )) void *
memmove ( void *dest, const void *src, size_t len ) {
ssize_t offset = ( dest - src );

if ( __builtin_constant_p ( offset ) ) {
if ( offset <= 0 ) {
return memcpy ( dest, src, len );
} else {
return __memcpy_reverse ( dest, src, len );
}
} else {
return __memmove ( dest, src, len );
}
}

#define __HAVE_ARCH_MEMSET
Expand Down

0 comments on commit fc30b13

Please sign in to comment.