am 3bb62578: am 0be1819b: Merge "Dynamically allocate soinfo-structs in linker"

* commit '3bb62578beb36a35d3b1d2fbe18bd34a9d4ecca4':
  Dynamically allocate soinfo-structs in linker
This commit is contained in:
Elliott Hughes 2012-11-01 11:47:31 -07:00 committed by Android Git Automerger
commit 00fe4a20d7
2 changed files with 60 additions and 38 deletions

View File

@ -51,8 +51,6 @@
#include "linker_format.h" #include "linker_format.h"
#include "linker_phdr.h" #include "linker_phdr.h"
#define SO_MAX 128
/* Assume average path length of 64 and max 8 paths */ /* Assume average path length of 64 and max 8 paths */
#define LDPATH_BUFSIZE 512 #define LDPATH_BUFSIZE 512
#define LDPATH_MAX 8 #define LDPATH_MAX 8
@ -76,16 +74,22 @@
* and NOEXEC * and NOEXEC
* - linker hardcodes PAGE_SIZE and PAGE_MASK because the kernel * - linker hardcodes PAGE_SIZE and PAGE_MASK because the kernel
* headers provide versions that are negative... * headers provide versions that are negative...
* - allocate space for soinfo structs dynamically instead of
* having a hard limit (SO_MAX)
*/ */
static bool soinfo_link_image(soinfo* si); static bool soinfo_link_image(soinfo* si);
static int socount = 0; // We can't use malloc(3) in the dynamic linker. We use a linked list of anonymous
static soinfo sopool[SO_MAX]; // maps, each a single page in size. The pages are broken up into as many struct soinfo
static soinfo *freelist = NULL; // objects as will fit, and they're all threaded together on a free list.
#define SOINFO_PER_POOL ((PAGE_SIZE - sizeof(soinfo_pool_t*)) / sizeof(soinfo))
struct soinfo_pool_t {
soinfo_pool_t* next;
soinfo info[SOINFO_PER_POOL];
};
static struct soinfo_pool_t* gSoInfoPools = NULL;
static soinfo* gSoInfoFreeList = NULL;
static soinfo *solist = &libdl_info; static soinfo *solist = &libdl_info;
static soinfo *sonext = &libdl_info; static soinfo *sonext = &libdl_info;
static soinfo *somain; /* main process, always the one after libdl_info */ static soinfo *somain; /* main process, always the one after libdl_info */
@ -263,38 +267,57 @@ void notify_gdb_of_libraries() {
rtld_db_dlactivity(); rtld_db_dlactivity();
} }
static soinfo *soinfo_alloc(const char *name) static bool ensure_free_list_non_empty() {
{ if (gSoInfoFreeList != NULL) {
if (strlen(name) >= SOINFO_NAME_LEN) { return true;
DL_ERR("library name \"%s\" too long", name); }
return NULL;
}
/* The freelist is populated when we call soinfo_free(), which in turn is // Allocate a new pool.
done only by dlclose(), which is not likely to be used. soinfo_pool_t* pool = reinterpret_cast<soinfo_pool_t*>(mmap(NULL, sizeof(*pool),
*/ PROT_READ|PROT_WRITE,
if (!freelist) { MAP_PRIVATE|MAP_ANONYMOUS, 0, 0));
if (socount == SO_MAX) { if (pool == MAP_FAILED) {
DL_ERR("too many libraries when loading \"%s\"", name); return false;
return NULL; }
}
freelist = sopool + socount++;
freelist->next = NULL;
}
soinfo* si = freelist; // Add the pool to our list of pools.
freelist = freelist->next; pool->next = gSoInfoPools;
gSoInfoPools = pool;
/* Make sure we get a clean block of soinfo */ // Chain the entries in the new pool onto the free list.
memset(si, 0, sizeof(soinfo)); gSoInfoFreeList = &pool->info[0];
strlcpy((char*) si->name, name, sizeof(si->name)); soinfo* next = NULL;
sonext->next = si; for (int i = SOINFO_PER_POOL - 1; i >= 0; --i) {
si->next = NULL; pool->info[i].next = next;
si->refcount = 0; next = &pool->info[i];
sonext = si; }
TRACE("%5d name %s: allocated soinfo @ %p\n", pid, name, si); return true;
return si; }
static soinfo* soinfo_alloc(const char* name) {
if (strlen(name) >= SOINFO_NAME_LEN) {
DL_ERR("library name \"%s\" too long", name);
return NULL;
}
if (!ensure_free_list_non_empty()) {
DL_ERR("out of memory when loading \"%s\"", name);
return NULL;
}
// Take the head element off the free list.
soinfo* si = gSoInfoFreeList;
gSoInfoFreeList = gSoInfoFreeList->next;
// Initialize the new element.
memset(si, 0, sizeof(soinfo));
strlcpy(si->name, name, sizeof(si->name));
sonext->next = si;
sonext = si;
TRACE("%5d name %s: allocated soinfo @ %p\n", pid, name, si);
return si;
} }
static void soinfo_free(soinfo* si) static void soinfo_free(soinfo* si)
@ -323,8 +346,8 @@ static void soinfo_free(soinfo* si)
*/ */
prev->next = si->next; prev->next = si->next;
if (si == sonext) sonext = prev; if (si == sonext) sonext = prev;
si->next = freelist; si->next = gSoInfoFreeList;
freelist = si; gSoInfoFreeList = si;
} }
#ifdef ANDROID_ARM_LINKER #ifdef ANDROID_ARM_LINKER

View File

@ -165,7 +165,6 @@ struct soinfo {
bool has_DT_SYMBOLIC; bool has_DT_SYMBOLIC;
}; };
extern soinfo libdl_info; extern soinfo libdl_info;