📄 dl-load.c
字号:
init_val = cp[0] != '/' ? existing : unknown; for (cnt = 0; cnt < ncapstr; ++cnt) dirp->status[cnt] = init_val; dirp->what = what; if (__builtin_expect (where != NULL, 1)) dirp->where = memcpy ((char *) dirp + sizeof (*dirp) + len + 1 + ncapstr * sizeof (enum r_dir_status), where, where_len); else dirp->where = NULL; dirp->next = _dl_all_dirs; _dl_all_dirs = dirp; /* Put it in the result array. */ result[nelems++] = dirp; } } /* Terminate the array. */ result[nelems] = NULL; return result;}static voidinternal_functiondecompose_rpath (struct r_search_path_struct *sps, const char *rpath, struct link_map *l, const char *what){ /* Make a copy we can work with. */ const char *where = l->l_name; char *copy; char *cp; struct r_search_path_elem **result; size_t nelems; /* Initialize to please the compiler. */ const char *errstring = NULL; /* First see whether we must forget the RUNPATH and RPATH from this object. */ if (__builtin_expect (_dl_inhibit_rpath != NULL, 0)) { const char *found = strstr (_dl_inhibit_rpath, where); if (found != NULL) { size_t len = strlen (where); if ((found == _dl_inhibit_rpath || found[-1] == ':') && (found[len] == '\0' || found[len] == ':')) { /* This object is on the list of objects for which the RUNPATH and RPATH must not be used. */ result = (struct r_search_path_elem **) malloc (sizeof (*result)); if (result == NULL) { signal_error_cache: errstring = N_("cannot create cache for search path"); signal_error: _dl_signal_error (ENOMEM, NULL, NULL, errstring); } result[0] = NULL; sps->dirs = result; sps->malloced = 1; return; } } } /* Make a writable copy. At the same time expand possible dynamic string tokens. */ copy = expand_dynamic_string_token (l, rpath); if (copy == NULL) { errstring = N_("cannot create RUNPATH/RPATH copy"); goto signal_error; } /* Count the number of necessary elements in the result array. */ nelems = 0; for (cp = copy; *cp != '\0'; ++cp) if (*cp == ':') ++nelems; /* Allocate room for the result. NELEMS + 1 is an upper limit for the number of necessary entries. */ result = (struct r_search_path_elem **) malloc ((nelems + 1 + 1) * sizeof (*result)); if (result == NULL) goto signal_error_cache; fillin_rpath (copy, result, ":", 0, what, where); /* Free the copied RPATH string. `fillin_rpath' make own copies if necessary. */ free (copy); sps->dirs = result; /* The caller will change this value if we haven't used a real malloc. */ sps->malloced = 1;}voidinternal_function_dl_init_paths (const char *llp){ size_t idx; const char *strp; struct r_search_path_elem *pelem, **aelem; size_t round_size;#ifdef SHARED struct link_map *l;#endif /* Initialize to please the compiler. */ const char *errstring = NULL; /* Fill in the information about the application's RPATH and the directories addressed by the LD_LIBRARY_PATH environment variable. */ /* Get the capabilities. */ capstr = _dl_important_hwcaps (_dl_platform, _dl_platformlen, &ncapstr, &max_capstrlen); /* First set up the rest of the default search directory entries. */ aelem = rtld_search_dirs.dirs = (struct r_search_path_elem **) malloc ((nsystem_dirs_len + 1) * sizeof (struct r_search_path_elem *)); if (rtld_search_dirs.dirs == NULL) { errstring = N_("cannot create search path array"); signal_error: _dl_signal_error (ENOMEM, NULL, NULL, errstring); } round_size = ((2 * sizeof (struct r_search_path_elem) - 1 + ncapstr * sizeof (enum r_dir_status)) / sizeof (struct r_search_path_elem)); rtld_search_dirs.dirs[0] = (struct r_search_path_elem *) malloc ((sizeof (system_dirs) / sizeof (system_dirs[0])) * round_size * sizeof (struct r_search_path_elem)); if (rtld_search_dirs.dirs[0] == NULL) { errstring = N_("cannot create cache for search path"); goto signal_error; } rtld_search_dirs.malloced = 0; pelem = _dl_all_dirs = rtld_search_dirs.dirs[0]; strp = system_dirs; idx = 0; do { size_t cnt; *aelem++ = pelem; pelem->what = "system search path"; pelem->where = NULL; pelem->dirname = strp; pelem->dirnamelen = system_dirs_len[idx]; strp += system_dirs_len[idx] + 1; /* System paths must be absolute. */ assert (pelem->dirname[0] == '/'); for (cnt = 0; cnt < ncapstr; ++cnt) pelem->status[cnt] = unknown; pelem->next = (++idx == nsystem_dirs_len ? NULL : (pelem + round_size)); pelem += round_size; } while (idx < nsystem_dirs_len); max_dirnamelen = SYSTEM_DIRS_MAX_LEN; *aelem = NULL;#ifdef SHARED /* This points to the map of the main object. */ l = _dl_loaded; if (l != NULL) { assert (l->l_type != lt_loaded); if (l->l_info[DT_RUNPATH]) { /* Allocate room for the search path and fill in information from RUNPATH. */ decompose_rpath (&l->l_runpath_dirs, (const void *) (D_PTR (l, l_info[DT_STRTAB]) + l->l_info[DT_RUNPATH]->d_un.d_val), l, "RUNPATH"); /* The RPATH is ignored. */ l->l_rpath_dirs.dirs = (void *) -1; } else { l->l_runpath_dirs.dirs = (void *) -1; if (l->l_info[DT_RPATH]) { /* Allocate room for the search path and fill in information from RPATH. */ decompose_rpath (&l->l_rpath_dirs, (const void *) (D_PTR (l, l_info[DT_STRTAB]) + l->l_info[DT_RPATH]->d_un.d_val), l, "RPATH"); l->l_rpath_dirs.malloced = 0; } else l->l_rpath_dirs.dirs = (void *) -1; } }#endif /* SHARED */ if (llp != NULL && *llp != '\0') { size_t nllp; const char *cp = llp; const char *old = llp; size_t len = strlen (old) + 1; char *new = alloca(len); char *llp_tmp; llp_tmp = memcpy (new, old, len); /* Decompose the LD_LIBRARY_PATH contents. First determine how many elements it has. */ nllp = 1; while (*cp) { if (*cp == ':' || *cp == ';') ++nllp; ++cp; } env_path_list.dirs = (struct r_search_path_elem **) malloc ((nllp + 1) * sizeof (struct r_search_path_elem *)); if (env_path_list.dirs == NULL) { errstring = N_("cannot create cache for search path"); goto signal_error; } (void) fillin_rpath (llp_tmp, env_path_list.dirs, ":;", 0, "LD_LIBRARY_PATH", NULL); if (env_path_list.dirs[0] == NULL) { free (env_path_list.dirs); env_path_list.dirs = (void *) -1; } env_path_list.malloced = 0; } else env_path_list.dirs = (void *) -1; /* Remember the last search directory added at startup. */ _dl_init_all_dirs = _dl_all_dirs;}/* Think twice before changing anything in this function. It is placed here and prepared using the `alloca' magic to prevent it from being inlined. The function is only called in case of an error. But then performance does not count. The function used to be "inlinable" and the compiled did so all the time. This increased the code size for absolutely no good reason. */static void__attribute__ ((noreturn))lose (int code, int fd, const char *name, char *realname, struct link_map *l, const char *msg){ /* The use of `alloca' here looks ridiculous but it helps. The goal is to avoid the function from being inlined. There is no official way to do this so we use this trick. gcc never inlines functions which use `alloca'. */ int *a = (int *) alloca (sizeof (int)); a[0] = fd; /* The file might already be closed. */ if (a[0] != -1) (void) close (a[0]); if (l != NULL) { /* Remove the stillborn object from the list and free it. */ assert (l->l_next == NULL);#ifndef SHARED if (l->l_prev == NULL) /* No other module loaded. */ _dl_loaded = NULL; else#endif l->l_prev->l_next = NULL; --_dl_nloaded; free (l); } free (realname); _dl_signal_error (code, name, NULL, msg);}/* Map in the shared object NAME, actually located in REALNAME, and already opened on FD. */#ifndef EXTERNAL_MAP_FROM_FDstatic#endifstruct link_map *_dl_map_object_from_fd (const char *name, int fd, struct filebuf *fbp, char *realname, struct link_map *loader, int l_type, int mode){ struct link_map *l = NULL; const ElfW(Ehdr) *header; const ElfW(Phdr) *phdr; const ElfW(Phdr) *ph; size_t maplength; int type; struct stat64 st; /* Initialize to keep the compiler happy. */ const char *errstring = NULL; int errval = 0; /* Get file information. */ if (__builtin_expect (fstat64 (fd, &st) < 0, 0)) { errstring = N_("cannot stat shared object"); call_lose_errno: errval = errno; call_lose: fprintf (stderr, "%s\n", errstring); lose (errval, fd, name, realname, l, errstring); } /* Look again to see if the real name matched another already loaded. */ for (l = _dl_loaded; l; l = l->l_next) if (l->l_ino == st.st_ino && l->l_dev == st.st_dev) { /* The object is already loaded. Just bump its reference count and return it. */ close (fd); /* If the name is not in the list of names for this object add it. */ free (realname); add_name_to_object (l, name); return l; } if (mode & RTLD_NOLOAD) /* We are not supposed to load the object unless it is already loaded. So return now. */ return NULL; /* Print debugging message. */ if (__builtin_expect (_dl_debug_mask & DL_DEBUG_FILES, 0)) _dl_debug_printf ("file=%s; generating link map\n", name); /* This is the ELF header. We read it in `open_verify'. */ header = (void *) fbp->buf;#ifndef MAP_ANON# define MAP_ANON 0 if (_dl_zerofd == -1) { _dl_zerofd = _dl_sysdep_open_zero_fill (); if (_dl_zerofd == -1) { close (fd); _dl_signal_error (errno, NULL, NULL, N_("cannot open zero fill device")); } }#endif /* Enter the new object in the list of loaded objects. */ l = _dl_new_object (realname, name, l_type, loader); if (__builtin_expect (! l, 0)) { errstring = N_("cannot create shared object descriptor"); goto call_lose_errno; } /* Extract the remaining details we need from the ELF header and then read in the program header table. */ l->l_entry = header->e_entry; type = header->e_type; l->l_phnum = header->e_phnum; maplength = header->e_phnum * sizeof (ElfW(Phdr)); if (header->e_phoff + maplength <= fbp->len) phdr = (void *) (fbp->buf + header->e_phoff); else { phdr = alloca (maplength); lseek (fd, SEEK_SET, header->e_phoff); if (__libc_read (fd, (void *) phdr, maplength) != maplength) { errstring = N_("cannot read file data"); goto call_lose_errno; } } { /* Scan the program header table, collecting its load commands. */ struct loadcmd { ElfW(Addr) mapstart, mapend, dataend, allocend; off_t mapoff; int prot; } loadcmds[l->l_phnum], *c; size_t nloadcmds = 0; /* The struct is initialized to zero so this is not necessary: l->l_ld = 0; l->l_phdr = 0; l->l_addr = 0; */ for (ph = phdr; ph < &phdr[l->l_phnum]; ++ph) switch (ph->p_type) { /* These entries tell us where to find things once the file's segments are mapped in. We record the addresses it says verbatim, and later correct for the run-time load address. */ case PT_DYNAMIC: l->l_ld = (void *) ph->p_vaddr; l->l_ldnum = ph->p_memsz / sizeof (ElfW(Dyn)); break; case PT_PHDR: l->l_phdr = (void *) ph->p_vaddr; break; case PT_LOAD: /* A load command tells us to map in part of the file. We record the load commands and process them all later. */ if ((ph->p_align & (_dl_pagesize - 1)) != 0) { errstring = N_("ELF load command alignment not page-aligned"); goto call_lose; } if (((ph->p_vaddr - ph->p_offset) & (ph->p_align - 1)) != 0) { errstring = N_("ELF load command address/offset not properly aligned"); goto call_lose; } {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -