diff options
Diffstat (limited to 'ldso')
-rw-r--r-- | ldso/include/ldso.h | 3 | ||||
-rw-r--r-- | ldso/ldso/ldso.c | 30 | ||||
-rw-r--r-- | ldso/libdl/libdl.c | 15 |
3 files changed, 43 insertions, 5 deletions
diff --git a/ldso/include/ldso.h b/ldso/include/ldso.h index 97f54b72c..88c1116e7 100644 --- a/ldso/include/ldso.h +++ b/ldso/include/ldso.h @@ -99,7 +99,8 @@ extern int _dl_debug_file; #define NULL ((void *) 0) #endif -extern void *_dl_malloc(int size); +extern void *_dl_malloc(size_t size); +extern void _dl_free(void *); extern char *_dl_getenv(const char *symbol, char **envp); extern void _dl_unsetenv(const char *symbol, char **envp); extern char *_dl_strdup(const char *string); diff --git a/ldso/ldso/ldso.c b/ldso/ldso/ldso.c index 3a5fc14f5..89d9bbd56 100644 --- a/ldso/ldso/ldso.c +++ b/ldso/ldso/ldso.c @@ -50,6 +50,7 @@ int _dl_errno = 0; /* We can't use the real errno in ldso */ size_t _dl_pagesize = 0; /* Store the page size for use later */ struct r_debug *_dl_debug_addr = NULL; /* Used to communicate with the gdb debugger */ void *(*_dl_malloc_function) (size_t size) = NULL; +void (*_dl_free_function) (void *p) = NULL; #ifdef __SUPPORT_LD_DEBUG__ char *_dl_debug = 0; @@ -884,7 +885,7 @@ static int _dl_suid_ok(void) return 0; } -void *_dl_malloc(int size) +void *_dl_malloc(size_t size) { void *retval; @@ -895,9 +896,26 @@ void *_dl_malloc(int size) if (_dl_malloc_function) return (*_dl_malloc_function) (size); - if (_dl_malloc_addr - _dl_mmap_zero + (unsigned)size > _dl_pagesize) { + if (_dl_malloc_addr - _dl_mmap_zero + size > _dl_pagesize) { + size_t rounded_size; + + /* Since the above assumes we get a full page even if + we request less than that, make sure we request a + full page, since uClinux may give us less than than + a full page. We might round even + larger-than-a-page sizes, but we end up never + reusing _dl_mmap_zero/_dl_malloc_addr in that case, + so we don't do it. + + The actual page size doesn't really matter; as long + as we're self-consistent here, we're safe. */ + if (size < _dl_pagesize) + rounded_size = (size + _dl_pagesize - 1) & _dl_pagesize; + else + rounded_size = size; + _dl_debug_early("mmapping more memory\n"); - _dl_mmap_zero = _dl_malloc_addr = _dl_mmap((void *) 0, size, + _dl_mmap_zero = _dl_malloc_addr = _dl_mmap((void *) 0, rounded_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (_dl_mmap_check_error(_dl_mmap_zero)) { _dl_dprintf(2, "%s: mmap of a spare page failed!\n", _dl_progname); @@ -916,5 +934,11 @@ void *_dl_malloc(int size) return retval; } +void _dl_free (void *p) +{ + if (_dl_free_function) + (*_dl_free_function) (p); +} + #include "dl-hash.c" #include "dl-elf.c" diff --git a/ldso/libdl/libdl.c b/ldso/libdl/libdl.c index f018c0a0d..f2303c52e 100644 --- a/ldso/libdl/libdl.c +++ b/ldso/libdl/libdl.c @@ -32,6 +32,7 @@ #include <ldso.h> #include <stdio.h> +#include <string.h> #ifdef SHARED @@ -51,6 +52,7 @@ extern struct elf_resolve *_dl_loaded_modules; extern struct r_debug *_dl_debug_addr; extern unsigned long _dl_error_number; extern void *(*_dl_malloc_function)(size_t); +extern void (*_dl_free_function) (void *p); extern void _dl_run_init_array(struct elf_resolve *); extern void _dl_run_fini_array(struct elf_resolve *); #ifdef __LDSO_CACHE_SUPPORT__ @@ -67,6 +69,9 @@ extern char *_dl_debug; #else /* SHARED */ +#define _dl_malloc malloc +#define _dl_free free + /* When libdl is linked as a static library, we need to replace all * the symbols that otherwise would have been loaded in from ldso... */ @@ -83,13 +88,15 @@ char *_dl_debug_bindings = 0; int _dl_debug_file = 2; #endif const char *_dl_progname = ""; /* Program name */ +void *(*_dl_malloc_function)(size_t); +void (*_dl_free_function) (void *p); char *_dl_library_path = 0; /* Where we look for libraries */ char *_dl_ldsopath = 0; /* Location of the shared lib loader */ int _dl_errno = 0; /* We can't use the real errno in ldso */ size_t _dl_pagesize = PAGE_SIZE; /* Store the page size for use later */ /* This global variable is also to communicate with debuggers such as gdb. */ struct r_debug *_dl_debug_addr = NULL; -#define _dl_malloc malloc + #include "../ldso/dl-array.c" #include "../ldso/dl-debug.c" #include LDSO_ELFINTERP @@ -157,6 +164,7 @@ void *dlopen(const char *libname, int flag) struct init_fini_list *tmp, *runp, *runp2, *dep_list; unsigned int nlist, i; struct elf_resolve **init_fini_list; + static int _dl_init = 0; /* A bit of sanity checking... */ if (!(flag & (RTLD_LAZY|RTLD_NOW))) { @@ -166,6 +174,11 @@ void *dlopen(const char *libname, int flag) from = (ElfW(Addr)) __builtin_return_address(0); + if (!_dl_init) { + _dl_init++; + _dl_malloc_function = malloc; + _dl_free_function = free; + } /* Cover the trivial case first */ if (!libname) return _dl_symbol_tables; |