am 3bb62578: am 0be1819b: Merge "Dynamically allocate soinfo-structs in linker"
* commit '3bb62578beb36a35d3b1d2fbe18bd34a9d4ecca4': Dynamically allocate soinfo-structs in linker
This commit is contained in:
commit
00fe4a20d7
@ -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
|
||||||
|
@ -165,7 +165,6 @@ struct soinfo {
|
|||||||
bool has_DT_SYMBOLIC;
|
bool has_DT_SYMBOLIC;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
extern soinfo libdl_info;
|
extern soinfo libdl_info;
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user