summaryrefslogtreecommitdiffstats
path: root/libexec/rtld-elf/rtld.c
diff options
context:
space:
mode:
Diffstat (limited to 'libexec/rtld-elf/rtld.c')
-rw-r--r--libexec/rtld-elf/rtld.c53
1 files changed, 50 insertions, 3 deletions
diff --git a/libexec/rtld-elf/rtld.c b/libexec/rtld-elf/rtld.c
index 24e56b7..f96b8e7 100644
--- a/libexec/rtld-elf/rtld.c
+++ b/libexec/rtld-elf/rtld.c
@@ -97,6 +97,7 @@ static void *fill_search_info(const char *, size_t, void *);
static char *find_library(const char *, const Obj_Entry *);
static const char *gethints(bool);
static void init_dag(Obj_Entry *);
+static void init_pagesizes(Elf_Auxinfo **aux_info);
static void init_rtld(caddr_t, Elf_Auxinfo **);
static void initlist_add_neededs(Needed_Entry *, Objlist *);
static void initlist_add_objects(Obj_Entry *, Obj_Entry **, Objlist *);
@@ -205,7 +206,8 @@ extern Elf_Dyn _DYNAMIC;
#define RTLD_IS_DYNAMIC() (&_DYNAMIC != NULL)
#endif
-int osreldate, pagesize;
+int npagesizes, osreldate;
+size_t *pagesizes;
long __stack_chk_guard[8] = {0, 0, 0, 0, 0, 0, 0, 0};
@@ -1822,8 +1824,9 @@ init_rtld(caddr_t mapbase, Elf_Auxinfo **aux_info)
/* Now that non-local variables can be accesses, copy out obj_rtld. */
memcpy(&obj_rtld, &objtmp, sizeof(obj_rtld));
- if (aux_info[AT_PAGESZ] != NULL)
- pagesize = aux_info[AT_PAGESZ]->a_un.a_val;
+ /* The page size is required by the dynamic memory allocator. */
+ init_pagesizes(aux_info);
+
if (aux_info[AT_OSRELDATE] != NULL)
osreldate = aux_info[AT_OSRELDATE]->a_un.a_val;
@@ -1837,6 +1840,50 @@ init_rtld(caddr_t mapbase, Elf_Auxinfo **aux_info)
}
/*
+ * Retrieve the array of supported page sizes. The kernel provides the page
+ * sizes in increasing order.
+ */
+static void
+init_pagesizes(Elf_Auxinfo **aux_info)
+{
+ static size_t psa[MAXPAGESIZES];
+ int mib[2];
+ size_t len, size;
+
+ if (aux_info[AT_PAGESIZES] != NULL && aux_info[AT_PAGESIZESLEN] !=
+ NULL) {
+ size = aux_info[AT_PAGESIZESLEN]->a_un.a_val;
+ pagesizes = aux_info[AT_PAGESIZES]->a_un.a_ptr;
+ } else {
+ len = 2;
+ if (sysctlnametomib("hw.pagesizes", mib, &len) == 0)
+ size = sizeof(psa);
+ else {
+ /* As a fallback, retrieve the base page size. */
+ size = sizeof(psa[0]);
+ if (aux_info[AT_PAGESZ] != NULL) {
+ psa[0] = aux_info[AT_PAGESZ]->a_un.a_val;
+ goto psa_filled;
+ } else {
+ mib[0] = CTL_HW;
+ mib[1] = HW_PAGESIZE;
+ len = 2;
+ }
+ }
+ if (sysctl(mib, len, psa, &size, NULL, 0) == -1) {
+ _rtld_error("sysctl for hw.pagesize(s) failed");
+ die();
+ }
+psa_filled:
+ pagesizes = psa;
+ }
+ npagesizes = size / sizeof(pagesizes[0]);
+ /* Discard any invalid entries at the end of the array. */
+ while (npagesizes > 0 && pagesizes[npagesizes - 1] == 0)
+ npagesizes--;
+}
+
+/*
* Add the init functions from a needed object list (and its recursive
* needed objects) to "list". This is not used directly; it is a helper
* function for initlist_add_objects(). The write lock must be held
OpenPOWER on IntegriCloud