From b998ae0611fc9abb6b093209a6c67aeb833e46ad Mon Sep 17 00:00:00 2001
From: Eric Andersen <andersen@codepoet.org>
Date: Wed, 14 Jul 2004 12:27:03 +0000
Subject: Based on a patch from Alexandre Oliva, make sure _dl_malloc returns a
 nicely aligned pointer that may be aligned up to page_size.  Also add
 _dl_free,

---
 ldso/include/ldso.h |  1 +
 ldso/ldso/dl-elf.c  | 52 ++++++++++++++++++++++++++++++++++++++++++++--------
 ldso/ldso/dl-hash.c |  4 ++--
 ldso/ldso/ldso.c    |  8 ++++----
 ldso/libdl/libdl.c  |  3 +++
 5 files changed, 54 insertions(+), 14 deletions(-)

(limited to 'ldso')

diff --git a/ldso/include/ldso.h b/ldso/include/ldso.h
index 6c01cebc1..b415a5024 100644
--- a/ldso/include/ldso.h
+++ b/ldso/include/ldso.h
@@ -65,6 +65,7 @@ extern int   _dl_debug_file;
 #endif
 
 extern void *_dl_malloc(int 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/dl-elf.c b/ldso/ldso/dl-elf.c
index d27e4ccb3..7f0f76c35 100644
--- a/ldso/ldso/dl-elf.c
+++ b/ldso/ldso/dl-elf.c
@@ -31,6 +31,7 @@
 
 
 #include "ldso.h"
+void *(*_dl_malloc_function) (size_t size) = NULL;
 
 #ifdef USE_CACHE
 
@@ -405,7 +406,7 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure,
 	tpnt = _dl_check_hashed_files(libname);
 	if (tpnt) {
 		if (*rpnt) {
-			(*rpnt)->next = (struct dyn_elf *) _dl_malloc(sizeof(struct dyn_elf));
+			(*rpnt)->next = (struct dyn_elf *) _dl_malloc_function(sizeof(struct dyn_elf));
 			_dl_memset((*rpnt)->next, 0, sizeof(struct dyn_elf));
 			(*rpnt)->next->prev = (*rpnt);
 			*rpnt = (*rpnt)->next;
@@ -691,7 +692,7 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure,
 	 * Add this object into the symbol chain
 	 */
 	if (*rpnt) {
-		(*rpnt)->next = (struct dyn_elf *) _dl_malloc(sizeof(struct dyn_elf));
+		(*rpnt)->next = (struct dyn_elf *) _dl_malloc_function(sizeof(struct dyn_elf));
 		_dl_memset((*rpnt)->next, 0, sizeof(struct dyn_elf));
 		(*rpnt)->next->prev = (*rpnt);
 		*rpnt = (*rpnt)->next;
@@ -883,12 +884,21 @@ char *_dl_strdup(const char *string)
 	int len;
 
 	len = _dl_strlen(string);
-	retval = _dl_malloc(len + 1);
+	retval = _dl_malloc_function(len + 1);
 	_dl_strcpy(retval, string);
 	return retval;
 }
 
-void *(*_dl_malloc_function) (size_t size) = NULL;
+union __align_type
+{
+  void *p;
+  void (*fp)(void);
+  long long ll;
+#if defined __UCLIBC_HAS_FLOATS__ && ! defined __UCLIBC_HAS_SOFT_FLOAT__
+  double d;
+#endif
+};
+
 void *_dl_malloc(int size)
 {
 	void *retval;
@@ -902,11 +912,29 @@ void *_dl_malloc(int size)
 	if (_dl_malloc_function)
 		return (*_dl_malloc_function) (size);
 
-	if (_dl_malloc_addr - _dl_mmap_zero + size > _dl_pagesize) {
+	if ((int)(_dl_malloc_addr - _dl_mmap_zero + size) > (int)_dl_pagesize) {
+		int 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 < (int)_dl_pagesize)
+			rounded_size = (size + _dl_pagesize - 1) & _dl_pagesize;
+		else
+			rounded_size = size;
+
+
 #ifdef __SUPPORT_LD_DEBUG_EARLY__
 		_dl_dprintf(2, "malloc: mmapping more memory\n");
 #endif
-		_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);
@@ -920,8 +948,16 @@ void *_dl_malloc(int size)
 	 * Align memory to 4 byte boundary.  Some platforms require this, others
 	 * simply get better performance.
 	 */
-	_dl_malloc_addr = (unsigned char *) (((unsigned long) _dl_malloc_addr + 3) & ~(3));
+	_dl_malloc_addr = (unsigned char *)
+		(((unsigned long) _dl_malloc_addr +
+		  __alignof__(union __align_type) - 1)
+		 & ~(__alignof__(union __align_type) - 1));
 	return retval;
 }
 
-
+void (*_dl_free_function) (void *p) = NULL;
+void
+_dl_free (void *p) {
+	if (_dl_free_function)
+		(*_dl_free_function) (p);
+}
diff --git a/ldso/ldso/dl-hash.c b/ldso/ldso/dl-hash.c
index 251ab6466..c6d4f1233 100644
--- a/ldso/ldso/dl-hash.c
+++ b/ldso/ldso/dl-hash.c
@@ -100,13 +100,13 @@ struct elf_resolve *_dl_add_elf_hash_table(const char *libname,
 	int i;
 
 	if (!_dl_loaded_modules) {
-		tpnt = _dl_loaded_modules = (struct elf_resolve *) _dl_malloc(sizeof(struct elf_resolve));
+		tpnt = _dl_loaded_modules = (struct elf_resolve *) _dl_malloc_function(sizeof(struct elf_resolve));
 		_dl_memset(tpnt, 0, sizeof(struct elf_resolve));
 	} else {
 		tpnt = _dl_loaded_modules;
 		while (tpnt->next)
 			tpnt = tpnt->next;
-		tpnt->next = (struct elf_resolve *) _dl_malloc(sizeof(struct elf_resolve));
+		tpnt->next = (struct elf_resolve *) _dl_malloc_function(sizeof(struct elf_resolve));
 		_dl_memset(tpnt->next, 0, sizeof(struct elf_resolve));
 		tpnt->next->prev = tpnt;
 		tpnt = tpnt->next;
diff --git a/ldso/ldso/ldso.c b/ldso/ldso/ldso.c
index 9b7c7380e..1af167985 100644
--- a/ldso/ldso/ldso.c
+++ b/ldso/ldso/ldso.c
@@ -191,7 +191,7 @@ void _dl_get_ready_to_run(struct elf_resolve *tpnt, struct elf_resolve *app_tpnt
 			_dl_loaded_modules->libtype = elf_executable;
 			_dl_loaded_modules->ppnt = (ElfW(Phdr) *) auxvt[AT_PHDR].a_un.a_ptr;
 			_dl_loaded_modules->n_phent = auxvt[AT_PHNUM].a_un.a_val;
-			_dl_symbol_tables = rpnt = (struct dyn_elf *) _dl_malloc(sizeof(struct dyn_elf));
+			_dl_symbol_tables = rpnt = (struct dyn_elf *) _dl_malloc_function(sizeof(struct dyn_elf));
 			_dl_memset(rpnt, 0, sizeof(struct dyn_elf));
 			rpnt->dyn = _dl_loaded_modules;
 			app_tpnt->usage_count++;
@@ -296,7 +296,7 @@ void _dl_get_ready_to_run(struct elf_resolve *tpnt, struct elf_resolve *app_tpnt
 			len1 = _dl_strlen(dl_debug_output);
 			len2 = _dl_strlen(tmp1);
 
-			filename = _dl_malloc(len1+len2+2);
+			filename = _dl_malloc_function(len1+len2+2);
 
 			if (filename)
 			{
@@ -563,12 +563,12 @@ void _dl_get_ready_to_run(struct elf_resolve *tpnt, struct elf_resolve *app_tpnt
 			tpnt->prev = NULL;
 		}
 		if (rpnt) {
-			rpnt->next = (struct dyn_elf *) _dl_malloc(sizeof(struct dyn_elf));
+			rpnt->next = (struct dyn_elf *) _dl_malloc_function(sizeof(struct dyn_elf));
 			_dl_memset(rpnt->next, 0, sizeof(struct dyn_elf));
 			rpnt->next->prev = rpnt;
 			rpnt = rpnt->next;
 		} else {
-			rpnt = (struct dyn_elf *) _dl_malloc(sizeof(struct dyn_elf));
+			rpnt = (struct dyn_elf *) _dl_malloc_function(sizeof(struct dyn_elf));
 			_dl_memset(rpnt, 0, sizeof(struct dyn_elf));
 		}
 		rpnt->dyn = tpnt;
diff --git a/ldso/libdl/libdl.c b/ldso/libdl/libdl.c
index ca39473f1..d7cbed733 100644
--- a/ldso/libdl/libdl.c
+++ b/ldso/libdl/libdl.c
@@ -54,6 +54,7 @@ extern struct elf_resolve *_dl_loaded_modules __attribute__ ((__weak__));
 extern struct r_debug *_dl_debug_addr __attribute__ ((__weak__));
 extern unsigned long _dl_error_number __attribute__ ((__weak__));
 extern void *(*_dl_malloc_function)(size_t) __attribute__ ((__weak__));
+extern void (*_dl_free_function) (void *p) __attribute__ ((__weak__));
 #ifdef USE_CACHE
 int _dl_map_cache(void) __attribute__ ((__weak__));
 int _dl_unmap_cache(void) __attribute__ ((__weak__));
@@ -95,6 +96,7 @@ struct r_debug *_dl_debug_addr = NULL;
 static unsigned char *_dl_malloc_addr, *_dl_mmap_zero;
 void *(*_dl_malloc_function) (size_t size);
 int _dl_errno = 0;
+void (*_dl_free_function) (void *p);
 int _dl_fixup(struct dyn_elf *rpnt, int lazy);
 #include "../ldso/dl-progname.h"               /* Pull in the name of ld.so */
 #include "../ldso/dl-hash.c"
@@ -164,6 +166,7 @@ void *_dlopen(const char *libname, int flag)
 	if (!dl_init) {
 		dl_init++;
 		_dl_malloc_function = malloc;
+		_dl_free_function = free;
 	}
 
 	/* Cover the trivial case first */
-- 
cgit v1.2.3