Search code examples
cldglibc

how LD_PRELOAD works in my code


LD_PRELOAD can be used to link a shared object before the other.So I try to override memcpy in glibc.

I define my memcpy which will reverse the byte order of src and return NULL to distinguish with glibc's memcpy

mymem.c

#include <string.h>

void *memcpy(void *dest, const void *src, size_t n) {
    char *dest_c = dest;
    const char *src_c = src;
    size_t i = 0;

    //reverse the byte order in src
    for(i = 0; i < n; i++)
        dest_c[i] = src_c[n-i-1];

    return NULL;
}

test.c

#include <stdio.h>
#include <string.h>

int main() {
    char str[] = "hello";
    char str2[100] = {};
    char *ret;

    //print the address of str2
    printf("str2: %p\n", str2);

    //print str2, address of memcpy, return value of memcpy
    ret = memcpy(str2, str, 6);
    printf("%s %p %p\n", str2, memcpy, ret);

    //the same
    ret = memcpy(str2, str, 3);
    printf("%s %p %p\n", str2, memcpy, ret);

    //the same
    ret = memcpy(str2, str, 8);
    printf("%s %p %p\n", str2, memcpy, ret);

    return 0;
}

compile & run:

$gcc -shared -o libmem.so mymem.c
$gcc test.c -o test
$export LD_PRELOAD="./libmem.so"
$./test

the result:

str2: 0x7fff0297e710
hello 0x400470 0x7fff0297e710
lehlo 0x400470 (nil)
 0x400470 (nil)

the output is not as I expected when the third param equals the size of the char array(In this case, sizeof str is 6).

after the first memcpy, I think str2[0] should be '\0', so str2 is an empty string, but the output is "hello". and the return value of memcpy should be NULL, but the output is the address of str2. It looks like the glic's memcpy works(I am not sure).

the other two memcpy works as I expected.

I haved test it in debian 8 and ubuntu 14.04.

Can someone explain it?


Solution

  • It's because for some reason GCC decides to use an inlined version of memcpy in for the first call to memcpy. To avoid that you could use the -fno-builtin option.

    Also note that if for some reason memcpy gets statically linked into the executable, it could result in that memcpy being resolved statically. As memcpy is such a low-level function it's not impossible that the implementation could have been provided by CRT-startup code (which is linked statically).