From: Matthew Dillon Date: Tue, 20 Jan 2004 21:14:00 +0000 (+0000) Subject: Resident executable support stage 3/4: Cleanup rtld-elf and augment and X-Git-Tag: v2.0.1~12305 X-Git-Url: https://gitweb.dragonflybsd.org/dragonfly.git/commitdiff_plain/8ca15ec8cebb4ebe8b367853f5f3ec3e5a7bdd4d Resident executable support stage 3/4: Cleanup rtld-elf and augment and document the 'resident' utility. rtld-elf should startup a bit faster now. I'm sure I can skip additional code but I am being somewhat conservative here. --- diff --git a/libexec/rtld-elf/rtld.c b/libexec/rtld-elf/rtld.c index db0ce6d1cc..77d69d971d 100644 --- a/libexec/rtld-elf/rtld.c +++ b/libexec/rtld-elf/rtld.c @@ -24,7 +24,7 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD: src/libexec/rtld-elf/rtld.c,v 1.43.2.15 2003/02/20 20:42:46 kan Exp $ - * $DragonFly: src/libexec/rtld-elf/rtld.c,v 1.5 2004/01/20 18:46:20 dillon Exp $ + * $DragonFly: src/libexec/rtld-elf/rtld.c,v 1.6 2004/01/20 21:13:57 dillon Exp $ */ /* @@ -40,6 +40,7 @@ #include #include #include +#include #include #include @@ -56,6 +57,7 @@ #define END_SYM "_end" #define PATH_RTLD "/usr/libexec/ld-elf.so.1" +#define LD_ARY_CACHE 16 /* Types. */ typedef void (*func_ptr_type)(); @@ -76,6 +78,7 @@ typedef struct Struct_DoneList { */ static void die(void); static void digest_dynamic(Obj_Entry *); +static const char *_getenv_ld(const char *id); static Obj_Entry *digest_phdr(const Elf_Phdr *, int, caddr_t, const char *); static Obj_Entry *dlcheck(void *); static int do_search_info(const Obj_Entry *obj, int, struct dl_serinfo *); @@ -133,19 +136,22 @@ void r_debug_state(struct r_debug*, struct link_map*); static char *error_message; /* Message for dlerror(), or NULL */ struct r_debug r_debug; /* for GDB; */ static bool trust; /* False for setuid and setgid programs */ -static char *ld_bind_now; /* Environment variable for immediate binding */ -static char *ld_debug; /* Environment variable for debugging */ -static char *ld_library_path; /* Environment variable for search path */ +static const char *ld_bind_now; /* Environment variable for immediate binding */ +static const char *ld_debug; /* Environment variable for debugging */ +static const char *ld_library_path; /* Environment variable for search path */ static char *ld_preload; /* Environment variable for libraries to load first */ -static char *ld_tracing; /* Called from ldd(1) to print libs */ -static char *ld_prebind; /* Called from prebind(1) to prebind libs */ +static const char *ld_tracing; /* Called from ldd(1) to print libs */ +static const char *ld_prebind; /* Called from prebind(1) to prebind libs */ static Obj_Entry *obj_list; /* Head of linked list of shared objects */ static Obj_Entry **obj_tail; /* Link field of last object in list */ +static Obj_Entry **preload_tail; static Obj_Entry *obj_main; /* The main program shared object */ static Obj_Entry obj_rtld; /* The dynamic linker shared object */ static unsigned int obj_count; /* Number of objects in obj_list */ static int ld_resident; /* Non-zero if resident */ +static const char *ld_ary[LD_ARY_CACHE]; +static int ld_index; static Objlist list_global = /* Objects dlopened with RTLD_GLOBAL */ STAILQ_HEAD_INITIALIZER(list_global); @@ -256,10 +262,11 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp) Elf_Auxinfo *auxp; const char *argv0; Obj_Entry *obj; - Obj_Entry **preload_tail; Objlist initlist; int prebind_disable = 0; + ld_index = 0; /* don't use old env cache in case we are resident */ + /* * On entry, the dynamic linker itself has not been relocated yet. * Be very careful not to reference any global data until after @@ -299,20 +306,20 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp) argv0 = argv[0] != NULL ? argv[0] : "(null)"; environ = env; - trust = geteuid() == getuid() && getegid() == getgid(); + trust = (geteuid() == getuid()) && (getegid() == getgid()); - prebind_disable = getenv("LD_PREBIND_DISABLE") != NULL; + prebind_disable = _getenv_ld("LD_PREBIND_DISABLE") != NULL; - ld_bind_now = getenv("LD_BIND_NOW"); + ld_bind_now = _getenv_ld("LD_BIND_NOW"); if (trust) { - ld_debug = getenv("LD_DEBUG"); - ld_library_path = getenv("LD_LIBRARY_PATH"); - ld_preload = getenv("LD_PRELOAD"); + ld_debug = _getenv_ld("LD_DEBUG"); + ld_library_path = _getenv_ld("LD_LIBRARY_PATH"); + ld_preload = (char *)_getenv_ld("LD_PRELOAD"); } - ld_tracing = getenv("LD_TRACE_LOADED_OBJECTS"); + ld_tracing = _getenv_ld("LD_TRACE_LOADED_OBJECTS"); if (trust) { - ld_prebind = getenv("LD_PREBIND"); + ld_prebind = _getenv_ld("LD_PREBIND"); if (ld_prebind != NULL && *ld_prebind != '\0') { ld_bind_now = ld_prebind; prebind_disable = 1; @@ -332,10 +339,8 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp) * when running from a resident image, and the static globals setup * between here and resident_skip will have already been setup. */ - if (ld_resident) { /* XXX clean this up! */ - preload_tail = obj_tail; + if (ld_resident) goto resident_skip1; - } /* * Load the main program, or process its program header if it is @@ -436,17 +441,7 @@ resident_skip2: if (ld_prebind != NULL && *ld_prebind != '\0') exit (prebind_save(&obj_rtld, obj_main)); - if (getenv("LD_RESIDENT_REGISTER_NOW")) { - extern void resident_start(void); - ld_resident = 1; - if (exec_sys_register(resident_start) < 0) { - dbg("exec_sys_register failed %d\n", errno); - exit(errno); - } - dbg("exec_sys_register success\n"); - exit(0); - } - if (getenv("LD_RESIDENT_UNREGISTER_NOW")) { + if (_getenv_ld("LD_RESIDENT_UNREGISTER_NOW")) { if (exec_sys_unregister(-1) < 0) { dbg("exec_sys_unregister failed %d\n", errno); exit(errno); @@ -459,6 +454,17 @@ resident_skip2: set_program_var("__progname", argv[0] != NULL ? basename(argv[0]) : ""); set_program_var("environ", env); + if (_getenv_ld("LD_RESIDENT_REGISTER_NOW")) { + extern void resident_start(void); + ld_resident = 1; + if (exec_sys_register(resident_start) < 0) { + dbg("exec_sys_register failed %d\n", errno); + exit(errno); + } + dbg("exec_sys_register success\n"); + exit(0); + } + dbg("initializing thread locks"); lockdflt_init(&lockinfo); lockinfo.thelock = lockinfo.lock_create(lockinfo.context); @@ -474,6 +480,8 @@ resident_skip2: objlist_clear(&initlist); wlock_release(); + + dbg("transferring control to program entry point = %p", obj_main->entry); /* Return the exit procedure and the program entry point. */ @@ -1719,7 +1727,7 @@ dlopen(const char *name, int mode) if (obj) { obj->dl_refcount++; - if (mode & RTLD_GLOBAL && objlist_find(&list_global, obj) == NULL) + if ((mode & RTLD_GLOBAL) && objlist_find(&list_global, obj) == NULL) objlist_push_tail(&list_global, obj); mode &= RTLD_MODEMASK; if (*old_obj_tail != NULL) { /* We loaded something new. */ @@ -2171,6 +2179,36 @@ set_program_var(const char *name, const void *value) } } +/* + * This is a special version of getenv which is far more efficient + * at finding LD_ environment vars. + */ +static +const char * +_getenv_ld(const char *id) +{ + const char *envp; + int i, j; + int idlen = strlen(id); + + if (ld_index == LD_ARY_CACHE) + return(getenv(id)); + if (ld_index == 0) { + for (i = j = 0; (envp = environ[i]) != NULL && j < LD_ARY_CACHE; ++i) { + if (envp[0] == 'L' && envp[1] == 'D' && envp[2] == '_') + ld_ary[j++] = envp; + } + if (j == 0) + ld_ary[j++] = ""; + ld_index = j; + } + for (i = ld_index - 1; i >= 0; --i) { + if (strncmp(ld_ary[i], id, idlen) == 0 && ld_ary[i][idlen] == '=') + return(ld_ary[i] + idlen + 1); + } + return(NULL); +} + /* * Given a symbol name in a referencing object, find the corresponding * definition of the symbol. Returns a pointer to the symbol, or NULL if @@ -2321,16 +2359,16 @@ symlook_obj(const char *name, unsigned long hash, const Obj_Entry *obj, static void trace_loaded_objects(Obj_Entry *obj) { - char *fmt1, *fmt2, *fmt, *main_local; + const char *fmt1, *fmt2, *fmt, *main_local; int c; - if ((main_local = getenv("LD_TRACE_LOADED_OBJECTS_PROGNAME")) == NULL) + if ((main_local = _getenv_ld("LD_TRACE_LOADED_OBJECTS_PROGNAME")) == NULL) main_local = ""; - if ((fmt1 = getenv("LD_TRACE_LOADED_OBJECTS_FMT1")) == NULL) + if ((fmt1 = _getenv_ld("LD_TRACE_LOADED_OBJECTS_FMT1")) == NULL) fmt1 = "\t%o => %p (%x)\n"; - if ((fmt2 = getenv("LD_TRACE_LOADED_OBJECTS_FMT2")) == NULL) + if ((fmt2 = _getenv_ld("LD_TRACE_LOADED_OBJECTS_FMT2")) == NULL) fmt2 = "\t%o (%x)\n"; for (; obj; obj = obj->next) { diff --git a/usr.sbin/resident/resident.8 b/usr.sbin/resident/resident.8 index cbc0249acd..b0c936d482 100644 --- a/usr.sbin/resident/resident.8 +++ b/usr.sbin/resident/resident.8 @@ -1,15 +1,46 @@ -.\" $DragonFly: src/usr.sbin/resident/resident.8,v 1.1 2004/01/20 18:46:22 dillon Exp $ +.\" $DragonFly: src/usr.sbin/resident/resident.8,v 1.2 2004/01/20 21:14:00 dillon Exp $ .\" .Dd May 21, 2003 -.Dt RESIDENT 1 +.Dt RESIDENT 8 .Os .Sh NAME .Nm resident .Nd Make a dynamic binary resident. .Sh SYNOPSIS .Nm -.Ar program ... +.Op Fl f +.Op Fl x Ar id +.Op Fl d +.Op Fl R +.Ar [program ...] .Sh DESCRIPTION +The +.Nm +utility may be used to make a dynamic binary memory-resident. This works +by running the binary just past its DLL mmap's and relocation and then +making a copy of its vmspace. The copy is registered in the kernel and later +exec's of the program will cause a copy of the copy to be used. When +ld-elf.so detects that it is running resident, it skips all initial library +loads (because they are already loaded). +.Pp +Care must be taken when using this program. It is recommended that you +delete all resident registrations when updating the system shared libraries +and binaries. +.Pp +The following options are available: +.Bl -tag -width indent +.It Fl f +Force mode, even if the binary does not appear to be a dynamic binary. This +way you can run resident through statically compiled wrappers. The first +dynamic binary encountered in the exec chain will be operated on. +.It Fl x Ar id +Delete a registration by id. +.It Fl d +Delete a registration by program name. If neither of the above two options +are specified a new registration is created. +.It Fl R +Delete all registrations in the kernel. +.El .Sh SEE ALSO .Xr ld 1 , .Xr ldd 1 , diff --git a/usr.sbin/resident/resident.c b/usr.sbin/resident/resident.c index 4d96f4b208..a170ea27ea 100644 --- a/usr.sbin/resident/resident.c +++ b/usr.sbin/resident/resident.c @@ -23,13 +23,14 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $DragonFly: src/usr.sbin/resident/resident.c,v 1.1 2004/01/20 18:46:22 dillon Exp $ + * $DragonFly: src/usr.sbin/resident/resident.c,v 1.2 2004/01/20 21:14:00 dillon Exp $ */ #include #include #include +#include #include #include @@ -66,7 +67,11 @@ main(int argc, char *argv[]) doreg = 0; break; case 'x': - c = exec_sys_unregister(strtol(optarg, NULL, 0)); + case 'R': + if (c == 'x') + c = exec_sys_unregister(-2); + else + c = exec_sys_unregister(strtol(optarg, NULL, 0)); if (c < 0) printf("unregister: %s\n", strerror(errno)); else