📄 rtld.c
字号:
/* * This source code is a product of Sun Microsystems, Inc. and is provided * for unrestricted use provided that this legend is included on all tape * media and as a part of the software program in whole or part. Users * may copy or modify this source code without charge, but are not authorized * to license or distribute it to anyone else except as part of a product or * program developed by the user. * * THIS PROGRAM CONTAINS SOURCE CODE COPYRIGHTED BY SUN MICROSYSTEMS, INC. * SUN MICROSYSTEMS, INC., MAKES NO REPRESENTATIONS ABOUT THE SUITABLITY * OF SUCH SOURCE CODE FOR ANY PURPOSE. IT IS PROVIDED "AS IS" WITHOUT * EXPRESS OR IMPLIED WARRANTY OF ANY KIND. SUN MICROSYSTEMS, INC. DISCLAIMS * ALL WARRANTIES WITH REGARD TO SUCH SOURCE CODE, INCLUDING ALL IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN * NO EVENT SHALL SUN MICROSYSTEMS, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT, * INCIDENTAL, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING * FROM USE OF SUCH SOURCE CODE, REGARDLESS OF THE THEORY OF LIABILITY. * * This source code is provided with no support and without any obligation on * the part of Sun Microsystems, Inc. to assist in its use, correction, * modification or enhancement. * * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS * SOURCE CODE OR ANY PART THEREOF. * * Sun Microsystems, Inc. * 2550 Garcia Avenue * Mountain View, California 94043 *//* @(#)rtld.c 1.60 91/04/02 SMI *//* * Run-time link editor. *//* * Copyright (c) 1989, 1990, 1991 by Sun Microsystems, Inc. */#include <sys/param.h>#include <sys/file.h>#include <sys/time.h>#include <sys/resource.h>#include <sys/mman.h>#include <sys/errno.h>#include <a.out.h>#include <link.h>#include "dynamic.h"#include "reloc_info.h"#include "rtld.h"#include <strings.h>#include "cache.h"#include <sysexits.h>#define VERSION2 2/* * Code collapsing macros. */#define JMPOFF(x) (x)->v2->ld_plt#define RELOCOFF(x) (x)->v2->ld_rel#define HASHOFF(x) (x)->v2->ld_hash#define SYMOFF(x) (x)->v2->ld_stab#define STROFF(x) (x)->v2->ld_symbols#define DONTAPPEND 0#define APPEND 1#if TARGET==SUN4# define MASK(n) ((1<<(n))-1)# define IN_RANGE(v,n) ((-(1<<((n)-1))) <=(v) && (v) < (1<<((n)-1)))#define isitpcrel(rp) (rp->r_type == RELOC_DISP8 || rp->r_type == RELOC_DISP16\ || rp->r_type == RELOC_DISP32 || rp->r_type == RELOC_WDISP30 \ || rp->r_type == RELOC_WDISP22)#endif/* * What we do: * - crt0 will pass in the pointer to dynamic structure of main prog. * - relocate ourselves. * - version checking: get the libraries, * check the version and mmap them in. * - relocate the _GOT_ for both user and shared libraries. * - relocate _PLT_ to the binder. * - go back to crt0. *//* * Interface between crt0 & ld.so. */struct crt_i1 { int crt_baseaddr; /* Address ld.so is at */ int crt_dzfd; /* /dev/zero file descriptor */ int crt_rlfd; /* ld.so file descriptor */ struct link_dynamic *crt_udp; /* "main_" dynamic */ char **crt_ep; /* environment strings */ caddr_t crt_breakp; /* place to put initial breakpoint */};/* * Global declarations. */int devzero_fd; /* cache for file descriptor */struct rtc_symb *rtcp; /* allocated commons */struct link_map *hlmp = NULL; /* head of link_map chain */struct link_map *plmp = NULL; /* first public link_map */struct link_map *mlmp; /* link map for "main" */struct link_map *ld_lmp; /* link map for runtime linker */struct link_object ld_lo; /* dummy link object for linker */struct link_map **plmpp; /* insertion point for new lm's */struct link_map *flmp = NULL; /* head of link_map free chain */struct dl_object *hdlp = NULL; /* head of dl_object chain */struct dl_object **pdlpp; /* insertion point for new dl's */struct dl_object *fdlp = NULL; /* head of dl_object free chain */caddr_t top_of_stack; /* top of stack (+1) */char *dl_error; /* last dynamic linking error */char *tracing; /* tracing or running? */char *preload; /* other shared object to preload */char *profile; /* activate profiling */char *symbols_public; /* show ld.so symbols to debuggers */char *library_path; /* alternate path for library search */char **environ; /* root of environment strings */char *main_program; /* string identifying lmp of "main" */char *ldso_program; /* string identifying lmp of "ld.so" */char *cached_symbol = NULL; /* last string cached by lookup */int use_cache = 1; /* tell lo_lookup ok to use cache */int version_no; /* link dynamic version number */caddr_t rtmalloc();static struct nlist *lookup();static struct nlist *findsb();static struct nlist *ldsofindsb();static struct link_map *have_we_got_it();static struct link_map *new_lmp();static struct link_map *map_so();static void map_error();static struct dl_object *new_dlp();static void relocate();static void upd_reloc();static struct link_map *pc_to_lmp();static void free_dlp();static struct dl_object *dlopen_worker();extern int errno;extern void rtbinder(); /* declare the binding function */extern caddr_t caller(); /* function to return our caller's pc *//* * Option storage. */#ifdef PROFint prof_fd;char *prof_buf;#endif#ifdef WHOAMIchar *progname;#endif#ifdef HRC_TIMEextern void hrc_init();extern int hrc_time();int ftime;int stime;int etime;int time1;int time2;int time3;int time4;int time5;#endif/* * Dummies for LD_PRELOAD. */static struct link_dynamic_2 pld_ld2; /* dummy structure for preloads */static struct link_dynamic pld_ld = /* dummy __DYNAMIC */ {2, (struct ld_debug *)0};/* * Run-time link editor bootstrap entry point. Called by program requiring * initial link editing at startup (generally, crt0). */rtld(version, iptr, dp) int version; /* interface version */ caddr_t iptr; /* interface passed from program */ register struct link_dynamic *dp; /* ld.so dynamic pointer */{ register struct crt_i1 *ip; /* crt0 version 1 interface structure */ register int reloc; /* count of internal relocations */ register /* scratch relocation entry pointer */ struct relocation_info *rp; int i; /* integer temporaries */ char *bp, *cp; /* character pointer temporaries */ char *buf; /* temporary storage pointers */ struct link_object *lop; /* work pointer */ struct link_object **lopp; /* preloaded object insertion point */ struct link_map *lmp; /* work pointer */ struct link_map *nlmp; /* newly allocated link_map */ /* * Determine interface format. A prototype interface once existed * that passed an address as the first argument. We assume this * address is greater than the size of a page, and thus use this * to test for it. Eventually, support for this will be deleted. */ if (version < PAGSIZ) { /* version 1 of new interface */ ip = (struct crt_i1 *) iptr; if (version != 1) panic( "ld.so: unsupported crt interface version of %d\n", version); } else /* old interface */ panic("ld.so: obsolete crt interface\n"); /* * ld.so must itself be relocated, take care of this now. * We can not refer to global data before this step is * complete. Perform the relocation by stepping over all * entries in the relocation table and turn them into * absolute addresses. * * N.B. We have the assumption here that there are no * symbolic relocations which need to be performed. */ (int) dp->v2 += ip->crt_baseaddr;#if TARGET==SUN4 /* * SPARC does not have a divide instruction, but we can not * call support routine until we have finished relocating the * loader. */#define RELOC_SIZE sizeof (struct relocation_info) reloc = 0; i = GETRELSZ(dp); while (i != 0) { i -= RELOC_SIZE; reloc++; }#endif#if TARGET==SUN3 || TARGET==SUN2 reloc = GETRELSZ(dp) / sizeof (struct relocation_info);#endif rp = (struct relocation_info *) (RELOCOFF(dp) + (dp->ld_version < VERSION2 ? (int) dp : ip->crt_baseaddr)); for (i = 0; i < reloc; i++) {#if TARGET==SUN4 upd_reloc(rp, (long *)(rp->r_address + ip->crt_baseaddr), ip->crt_baseaddr);#endif#if TARGET==SUN3 || TARGET==SUN2 *(long *)(rp->r_address + ip->crt_baseaddr) = *(long *)(rp->r_address + ip->crt_baseaddr) + ip->crt_baseaddr;#endif rp++; } /* * Relocation is completed. Update any global data necessary * to continue. */ environ = ip->crt_ep; rtgetenv(); devzero_fd = ip->crt_dzfd; pld_ld.ld_un.ld_2 = &pld_ld2; /* C bug with initializing unions */ /* * Initialize link maps. Create a link map for ld.so -- however * do not put it on the "public list" unless we are making its * symbols available to the debugger. */ pdlpp = &hdlp; plmpp = &hlmp; ldso_program = "/usr/lib/ld.so"; ld_lo.lo_name = (long)ldso_program - ip->crt_baseaddr; ld_lmp = new_lmp(ldso_program, &ld_lo, ip->crt_baseaddr, ip->crt_baseaddr, dp, findsb); if (!symbols_public) hlmp = NULL; plmpp = &hlmp; db_malloc = heap_malloc = rtmalloc; is_secure = secure_objects; main_program = "main_$main_";#ifdef PROF /* * If profiling features are turned on, then see if the profiling * file exists. If so, map in the file and use it as our profile * buffer. */ if ((prof_fd = open("/tmp/ld.so.profile_buffer", O_RDWR)) != -1) { if ((prof_buf = mmap(0, 0x2000, PROT_READ | PROT_WRITE, MAP_SHARED, prof_fd, 0)) == (caddr_t)-1) panic("ld.so: mmap failure (%d) for profile buffer\n", errno); profil(prof_buf, 0x2000, ip->crt_baseaddr, 0x4000); close(prof_fd); }#endif PROF#ifdef HRC_TIME hrc_init(); ftime = stime = hrc_time();#endif /* * Free descriptor on ld.so. */ close(ip->crt_rlfd); /* * If we're letting the user freelance, then see if the user has * specified any files to be dynamically loaded. If so, build * link-object data structures for them and get them. * N.B. THIS IS FOR DEBUGGING ONLY. IT IS NOT SUPPORTED NOR * IS IT TO BE DOCUMENTED! */ if ((cp = preload)) if (!secure_objects()) { int f = 0; /* flag for scanning */ lopp = &(struct link_object *)pld_ld2.ld_need; bp = buf = rtmalloc(strlen(cp) + 1); do { *bp = *cp; if (isspace(*bp) || (*bp == '\0')) { *bp = '\0'; if (f) { f = 0; lop = (struct link_object *) rtmalloc(sizeof (struct link_object)); lop->lo_name = (long)buf; lop->lo_library = 0; lop->lo_next = NULL; *lopp = lop; lopp = &(struct link_object *) lop->lo_next; } } else if (!f) { f = 1; buf = bp; } bp++; } while (*cp++); /* * Have list of objects. Go add them. */ (void) new_lmp("ld_$preload_", NULL, (caddr_t)0, NULL, &pld_ld, findsb); } /* * Insert link_map for "main". */ mlmp = new_lmp(main_program, NULL, MAIN_BASE, (caddr_t)0, ip->crt_udp, findsb);#ifdef HRC_TIME etime = hrc_time(); time1 = etime - stime; stime = etime;#endif /* * Walk map of loaded objects, loading their requisite objects as * necessary. Note that the first one we load in this loop is the * first one we hand back to the debugger (see use of plmp). */ for (lmp = hlmp; lmp; lmp = lmp->lm_next) if (lmp->lm_ld) { for (lop = (struct link_object *) &TEXTBASE(lmp)[lmp->lm_ld->v2->ld_need]; lop != (struct link_object *)&TEXTBASE(lmp)[0]; lop = (struct link_object *) &TEXTBASE(lmp)[lop->lo_next]) if (!have_we_got_it(lop, TEXTBASE(lmp))) if (nlmp = map_so(lmp, lop)) if (!plmp) plmp = nlmp; } /* * If we've just been asked to describe what we would load, * describe what we did load, and terminate the process. */ if (tracing) { for (lmp = plmp; lmp; lmp = lmp->lm_next) if (lmp->lm_lop->lo_library) printf("\t-l%s.%d => %s\n", &lmp->lm_lob[lmp->lm_lop->lo_name], lmp->lm_lop->lo_major, lmp->lm_name ? lmp->lm_name : "not found"); else printf("\t%s%s\n", &lmp->lm_lob[lmp->lm_lop->lo_name], lmp->lm_name ? "" : " (not found)"); _exit(0); }#ifdef HRC_TIME etime = hrc_time(); time2 = etime - stime; stime = etime; /* +++ time in mmap loop */#endif /* * Relocate all loaded objects. */ for (lmp = hlmp; lmp; lmp = lmp->lm_next) if (lmp != ld_lmp) relocate(lmp, mlmp);#ifdef HRC_TIME etime = hrc_time(); time3 = etime - stime; stime = etime; /* +++ time in relocate loop */#endif /* * Store in the "main" link_dynamic the list of objects we * loaded. Also return any commons that were allocated. */ ip->crt_udp->v2->ld_loaded = plmp; if (rtcp) ip->crt_udp->ldd->ldd_cp = rtcp; /* * If we're running under a debugger, let it know we've * done our loader thing. */ if (ip->crt_udp->ldd->ldd_in_debugger) { ip->crt_udp->ldd->ldd_bp_addr = ip->crt_breakp; if (!mlmp->lm_rwt) if (mprotect(PAGEMASK & (int)ip->crt_breakp, PAGESIZE, PROT_READ | PROT_WRITE | PROT_EXEC) == -1) map_error("text write-enable", "main"); ip->crt_udp->ldd->ldd_sym_loaded = 1; ip->crt_udp->ldd->ldd_bp_inst = *(int *)(ip->crt_breakp);#if TARGET==SUN4 *(long *)(ip->crt_breakp) = TRAP;#endif#if TARGET==SUN3 || TARGET==SUN2 *(short *)(ip->crt_breakp) = TRAP;#endif if (!mlmp->lm_rwt) if (mprotect(PAGEMASK & (int)ip->crt_breakp, PAGESIZE, PROT_READ | PROT_EXEC) == -1) panic( "ld.so: error %d on main text write-protect\n", errno); } /* * Turn write-protect back on for text segments. */ for (lmp = hlmp; lmp; lmp = lmp->lm_next) if (lmp->lm_rwt) { if (mprotect(TEXTBASE(lmp),
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -