You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

155 lines
4.5 KiB

/*
* Copyright 2002-2019 Intel Corporation.
*
* This software is provided to you as Sample Source Code as defined in the accompanying
* End User License Agreement for the Intel(R) Software Development Products ("Agreement")
* section 1.L.
*
* This software and the related documents are provided as is, with no express or implied
* warranties, other than those that are expressly stated in the License.
*/
#define _GNU_SOURCE
#include <dlfcn.h>
#include <link.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
// The highest bit value in a pointer
#define HIGHEST_BIT ((uintptr_t)1 << (8 * sizeof(void*) - 1))
// Turn on the highest bit in a pointer
#define MK_PTR(ptr) ((void*)(((uintptr_t)ptr) | HIGHEST_BIT))
// Turn off the highest bit in a pointer
#define STRIP_PTR(ptr) ((void*)((uintptr_t)ptr & ~HIGHEST_BIT))
// Initial allocator buffer (see below for explnaition).
static char initial_buf[1024*1024];
static size_t initial_buf_idx = 0;
static void* (*libc_malloc)(size_t) = NULL;
static void* (*libc_calloc)(size_t, size_t) = NULL;
static void* (*libc_realloc)(void *ptr, size_t) = NULL;
static void (*libc_free)(void*) = NULL;
/*
* Initialize all malloc related symbols from libc
*/
void __attribute__((constructor)) init()
{
libc_malloc = dlsym(RTLD_NEXT, "malloc");
libc_calloc = dlsym(RTLD_NEXT, "calloc");
libc_realloc = dlsym(RTLD_NEXT, "realloc");
libc_free = dlsym(RTLD_NEXT, "free");
}
/*********************************************************
* Below we implement an initial allocator.
* The first allocated bytes cannot be allocate with libc's
* memory allocation function.
* This is merely because calling dlsym() in the loader, to
* get the address of libc's memory allocation function,
* causes the loader to call calloc() (the overriden version
* of calloc()) and if we call dlsym() in calloc() it will
* eventually cause an infinite recursion.
* To overcome this, we implement a simple allocator here
* that allocates the first bytes of the program from
* the static buffer initial_buf[].
*********************************************************/
void *initial_malloc(size_t size)
{
void* ret;
if (sizeof(initial_buf) < initial_buf_idx + size + sizeof(size_t))
{
return NULL;
}
*((size_t*)&initial_buf[initial_buf_idx]) = size;
ret = (void*)&initial_buf[initial_buf_idx + sizeof(size_t)];
initial_buf_idx += ((size + 2 * sizeof(size_t) - 1) / sizeof(size_t)) * sizeof(size_t);
return ret;
}
size_t initial_free(void* ptr)
{
if ((ptr >= (void*)initial_buf) && (ptr < (void*)&initial_buf[initial_buf_idx]))
{
return *((size_t*)ptr - 1);
}
return 0;
}
/*********************************************************
* Wrapper functions for libc memory allocation functions.
* Here we translate the memory addresses in and out of
* memory allocation function so the highest bit in the
* memory address will be turn on.
*********************************************************/
void *malloc(size_t size)
{
void* ret;
if (NULL != (ret = initial_malloc(size)))
{
return MK_PTR(ret);
}
return MK_PTR(libc_malloc(size));
}
void *calloc(size_t nmemb, size_t size)
{
void* ret;
if (NULL != (ret = initial_malloc(nmemb*size)))
{
return MK_PTR(ret);
}
return MK_PTR(libc_calloc(nmemb, size));
}
void *realloc(void *ptr, size_t size)
{
size_t old_size;
if (0 != (old_size = initial_free(STRIP_PTR(ptr))))
{
void* new_ptr = malloc(size);
memcpy(STRIP_PTR(new_ptr), STRIP_PTR(ptr), size<old_size?size:old_size);
return new_ptr;
}
return MK_PTR(libc_realloc(STRIP_PTR(ptr), size));
}
void free(void *ptr)
{
if (0 < initial_free(STRIP_PTR(ptr)))
{
return;
}
return libc_free(STRIP_PTR(ptr));
}
/*
* This simple program just loads the library which its filename was
* provided ain the command line arguments
*/
int main(int argc, char* argv[])
{
if (argc != 2)
{
fprintf(stderr, "Usage: %s <path to dynamic library>\n", argv[0]);
exit(1);
}
const char* file = argv[1];
printf("Loading shared object %s\n", file);
fflush(stdout);
void *handle = dlopen(file, RTLD_NOW | RTLD_LOCAL);
if (NULL == handle)
{
fprintf(stderr,"Failed to load %s - %s\n", file, dlerror());
exit(1);
}
printf("Unloading shared object %s\n", file);
fflush(stdout);
dlclose(handle);
printf("Application finished successfully!\n");
return 0;
}