rtld: Set foundation to use aux vectors to get osreldate
authorJohn Marino <draco@marino.st>
Sat, 21 Jan 2012 13:13:17 +0000 (14:13 +0100)
committerJohn Marino <draco@marino.st>
Mon, 23 Jan 2012 16:13:17 +0000 (17:13 +0100)
__getosreldate isn't used by rtld currently.  The FreeBSD dynamic linker
does use it indirectly in libc's mmap wrapper.  The capability is included
here both to ease the task to synchronizing with FreeBSD, and to quickly
obtain the capability in the future if necessary.  It's currently disabled
with the undefined ENABLE_OSRELDATE macro.

The splitting of digest_dynamic required to use aux vectors also has the
benefit of avoiding the use of malloc at startup.

libexec/rtld-elf/rtld.c

index 6f62700..c41e684 100644 (file)
@@ -41,6 +41,7 @@
 #include <sys/mount.h>
 #include <sys/mman.h>
 #include <sys/stat.h>
+#include <sys/sysctl.h>
 #include <sys/uio.h>
 #include <sys/utsname.h>
 #include <sys/ktrace.h>
@@ -85,6 +86,9 @@ typedef struct Struct_DoneList {
  */
 static const char *_getenv_ld(const char *id);
 static void die(void) __dead2;
+static void digest_dynamic1(Obj_Entry *, int, const Elf_Dyn **,
+    const Elf_Dyn **);
+static void digest_dynamic2(Obj_Entry *, const Elf_Dyn *, const Elf_Dyn *);
 static void digest_dynamic(Obj_Entry *, int);
 static Obj_Entry *digest_phdr(const Elf_Phdr *, int, caddr_t, const char *);
 static Obj_Entry *dlcheck(void *);
@@ -98,7 +102,7 @@ static char *find_library(const char *, const Obj_Entry *);
 static const char *gethints(void);
 static void init_dag(Obj_Entry *);
 static void init_dag1(Obj_Entry *, Obj_Entry *, DoneList *);
-static void init_rtld(caddr_t);
+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 *);
 static bool is_exported(const Elf_Sym *);
@@ -165,13 +169,13 @@ static const char *ld_library_path; /* Environment variable for search path */
 static char *ld_preload;       /* Environment variable for libraries to
                                   load first */
 static const char *ld_elf_hints_path; /* Environment variable for alternative hints path */
-static const char *ld_tracing; /* Called from ldd(1) to print libs */
-                               /* Optional function call tracing hook */
+static const char *ld_tracing; /* Called from ldd to print libs */
 static const char *ld_utrace;  /* Use utrace() to log events. */
-static int (*rtld_functrace)(const char *caller_obj,
-                            const char *callee_obj,
-                            const char *callee_func,
-                            void *stack);
+static int (*rtld_functrace)(   /* Optional function call tracing hook */
+       const char *caller_obj,
+       const char *callee_obj,
+       const char *callee_func,
+       void *stack);
 static Obj_Entry *rtld_functrace_obj;  /* Object thereof */
 static Obj_Entry *obj_list;    /* Head of linked list of shared objects */
 static Obj_Entry **obj_tail;   /* Link field of last object in list */
@@ -203,6 +207,10 @@ extern Elf_Dyn _DYNAMIC;
 #define        RTLD_IS_DYNAMIC()       (&_DYNAMIC != NULL)
 #endif
 
+#ifdef ENABLE_OSRELDATE
+int osreldate;
+#endif
+
 /*
  * These are the functions the dynamic linker exports to application
  * programs.  They are the only symbols the dynamic linker is willing
@@ -380,7 +388,7 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp)
 
        /* Initialize and relocate ourselves. */
        assert(aux_info[AT_BASE] != NULL);
-       init_rtld((caddr_t) aux_info[AT_BASE]->a_un.a_ptr);
+       init_rtld((caddr_t) aux_info[AT_BASE]->a_un.a_ptr, aux_info);
     }
 
     ld_index = 0;      /* don't use old env cache in case we are resident */
@@ -623,6 +631,7 @@ resident_skip2:
     dbg("initializing key program variables");
     set_program_var("__progname", argv[0] != NULL ? basename(argv[0]) : "");
     set_program_var("environ", env);
+    set_program_var("__elf_aux_vector", aux);
 
     if (_getenv_ld("LD_RESIDENT_REGISTER_NOW")) {
        extern void resident_start(void);
@@ -862,14 +871,16 @@ die(void)
  * information in its Obj_Entry structure.
  */
 static void
-digest_dynamic(Obj_Entry *obj, int early)
+digest_dynamic1(Obj_Entry *obj, int early, const Elf_Dyn **dyn_rpath,
+    const Elf_Dyn **dyn_soname)
 {
     const Elf_Dyn *dynp;
     Needed_Entry **needed_tail = &obj->needed;
-    const Elf_Dyn *dyn_rpath = NULL;
-    const Elf_Dyn *dyn_soname = NULL;
     int plttype = DT_REL;
 
+    *dyn_rpath = NULL;
+    *dyn_soname = NULL;
+
     obj->bind_now = false;
     for (dynp = obj->dynamic;  dynp->d_tag != DT_NULL;  dynp++) {
        switch (dynp->d_tag) {
@@ -993,11 +1004,11 @@ digest_dynamic(Obj_Entry *obj, int early)
             * We have to wait until later to process this, because we
             * might not have gotten the address of the string table yet.
             */
-           dyn_rpath = dynp;
+           *dyn_rpath = dynp;
            break;
 
        case DT_SONAME:
-           dyn_soname = dynp;
+           *dyn_soname = dynp;
            break;
 
        case DT_INIT:
@@ -1058,6 +1069,12 @@ digest_dynamic(Obj_Entry *obj, int early)
        obj->pltrelasize = obj->pltrelsize;
        obj->pltrelsize = 0;
     }
+}
+
+static void
+digest_dynamic2(Obj_Entry *obj, const Elf_Dyn *dyn_rpath,
+    const Elf_Dyn *dyn_soname)
+{
 
     if (obj->z_origin && obj->origin_path == NULL) {
        obj->origin_path = xmalloc(PATH_MAX);
@@ -1075,6 +1092,16 @@ digest_dynamic(Obj_Entry *obj, int early)
        object_add_name(obj, obj->strtab + dyn_soname->d_un.d_val);
 }
 
+static void
+digest_dynamic(Obj_Entry *obj, int early)
+{
+       const Elf_Dyn *dyn_rpath;
+       const Elf_Dyn *dyn_soname;
+
+       digest_dynamic1(obj, early, &dyn_rpath, &dyn_soname);
+       digest_dynamic2(obj, dyn_rpath, dyn_soname);
+}
+
 /*
  * Process a shared object's program header.  This is used only for the
  * main program, when the kernel has already loaded the main program
@@ -1410,9 +1437,11 @@ init_dag1(Obj_Entry *root, Obj_Entry *obj, DoneList *dlp)
  * this function is to relocate the dynamic linker.
  */
 static void
-init_rtld(caddr_t mapbase)
+init_rtld(caddr_t mapbase, Elf_Auxinfo **aux_info)
 {
     Obj_Entry objtmp;  /* Temporary rtld object */
+    const Elf_Dyn *dyn_rpath;
+    const Elf_Dyn *dyn_soname;
 
     /*
      * Conjure up an Obj_Entry structure for the dynamic linker.
@@ -1429,7 +1458,7 @@ init_rtld(caddr_t mapbase)
 #endif
     if (RTLD_IS_DYNAMIC()) {
        objtmp.dynamic = rtld_dynamic(&objtmp);
-       digest_dynamic(&objtmp, 1);
+       digest_dynamic1(&objtmp, 1, &dyn_rpath, &dyn_soname);
        assert(objtmp.needed == NULL);
        assert(!objtmp.textrel);
 
@@ -1447,6 +1476,13 @@ init_rtld(caddr_t mapbase)
     /* Now that non-local variables can be accesses, copy out obj_rtld. */
     memcpy(&obj_rtld, &objtmp, sizeof(obj_rtld));
 
+#ifdef ENABLE_OSRELDATE
+    if (aux_info[AT_OSRELDATE] != NULL)
+           osreldate = aux_info[AT_OSRELDATE]->a_un.a_val;
+#endif
+
+    digest_dynamic2(&obj_rtld, dyn_rpath, dyn_soname);
+
     /* Replace the path with a dynamically allocated copy. */
     obj_rtld.path = xstrdup(PATH_RTLD);
 
@@ -3741,6 +3777,28 @@ fetch_ventry(const Obj_Entry *obj, unsigned long symnum)
     return NULL;
 }
 
+#ifdef ENABLE_OSRELDATE
+int
+__getosreldate(void)
+{
+       size_t len;
+       int oid[2];
+       int error, osrel;
+
+       if (osreldate != 0)
+               return (osreldate);
+
+       oid[0] = CTL_KERN;
+       oid[1] = KERN_OSRELDATE;
+       osrel = 0;
+       len = sizeof(osrel);
+       error = sysctl(oid, 2, &osrel, &len, NULL, 0);
+       if (error == 0 && osrel > 0 && len == sizeof(osrel))
+               osreldate = osrel;
+       return (osreldate);
+}
+#endif
+
 /*
  * No unresolved symbols for rtld.
  */