1 /* vi: set sw=4 ts=4: */
2 /* Program to load an ELF binary on a linux system, and run it
3 * after resolving ELF shared library symbols
5 * Copyright (c) 1994-2000 Eric Youngdale, Peter MacDonald,
6 * David Engel, Hongjiu Lu and Mitch D'Souza
7 * Copyright (C) 2001-2002, Erik Andersen
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. The name of the above contributors may not be
17 * used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 // Support a list of library preloads in /etc/ld.so.preload
34 //#define SUPPORT_LDSO_PRELOAD_FILE
37 /* Disclaimer: I have never seen any AT&T source code for SVr4, nor have
38 I ever taken any courses on internals. This program was developed using
39 information available through the book "UNIX SYSTEM V RELEASE 4,
40 Programmers guide: Ansi C and Programming Support Tools", which did
41 a more than adequate job of explaining everything required to get this
45 * The main trick with this program is that initially, we ourselves are
46 * not dynamicly linked. This means that we cannot access any global
47 * variables or call any functions. No globals initially, since the
48 * Global Offset Table (GOT) is initialized by the linker assuming a
49 * virtual address of 0, and no function calls initially since the
50 * Procedure Linkage Table (PLT) is not yet initialized.
52 * There are additional initial restrictions - we cannot use large
53 * switch statements, since the compiler generates tables of addresses
54 * and jumps through them. We can use inline functions, because these
55 * do not transfer control to a new address, but they must be static so
56 * that they are not exported from the modules. We cannot use normal
57 * syscall stubs, because these all reference the errno global variable
58 * which is not yet initialized. We can use all of the local stack
59 * variables that we want.
61 * Life is further complicated by the fact that initially we do not
62 * want to do a complete dynamic linking. We want to allow the user to
63 * supply new functions to override symbols (i.e. weak symbols and/or
64 * LD_PRELOAD). So initially, we only perform relocations for
65 * variables that start with "_dl_" since ANSI specifies that the user
66 * is not supposed to redefine any of these variables.
68 * Fortunately, the linker itself leaves a few clues lying around, and
69 * when the kernel starts the image, there are a few further clues.
70 * First of all, there is Auxiliary Vector Table information sitting on
71 * which is provided to us by the kernel, and which includes
72 * information about the load address that the program interpreter was
73 * loaded at, the number of sections, the address the application was
74 * loaded at and so forth. Here this information is stored in the
75 * array auxvt. For details see linux/fs/binfmt_elf.c where it calls
76 * NEW_AUX_ENT() a bunch of time....
78 * Next, we need to find the GOT. On most arches there is a register
79 * pointing to the GOT, but just in case (and for new ports) I've added
80 * some (slow) C code to locate the GOT for you.
82 * This code was originally written for SVr4, and there the kernel
83 * would load all text pages R/O, so they needed to call mprotect a
84 * zillion times to mark all text pages as writable so dynamic linking
85 * would succeed. Then when they were done, they would change the
86 * protections for all the pages back again. Well, under Linux
87 * everything is loaded writable (since Linux does copy on write
88 * anyways) so all the mprotect stuff has been disabled.
90 * Initially, we do not have access to _dl_malloc since we can't yet
91 * make function calls, so we mmap one page to use as scratch space.
92 * Later on, when we can call _dl_malloc we reuse this this memory.
93 * This is also beneficial, since we do not want to use the same memory
94 * pool as malloc anyway - esp if the user redefines malloc to do
97 * Our first task is to perform a minimal linking so that we can call
98 * other portions of the dynamic linker. Once we have done this, we
99 * then build the list of modules that the application requires, using
100 * LD_LIBRARY_PATH if this is not a suid program (/usr/lib otherwise).
101 * Once this is done, we can do the dynamic linking as required, and we
102 * must omit the things we did to get the dynamic linker up and running
103 * in the first place. After we have done this, we just have a few
104 * housekeeping chores and we can transfer control to the user's
108 #include "ld_syscall.h"
109 #include "linuxelf.h"
111 #include "ld_string.h"
113 #include "../config.h"
115 #define ALLOW_ZERO_PLTGOT
117 /* Some arches may need to override this in boot1_arch.h */
118 #define ELFMAGIC ELFMAG
120 /* This is a poor man's malloc, used prior to resolving our internal poor man's malloc */
121 #define LD_MALLOC(SIZE) ((void *) (malloc_buffer += SIZE, malloc_buffer - SIZE)) ; REALIGN();
123 * Make sure that the malloc buffer is aligned on 4 byte boundary. For 64 bit
124 * platforms we may need to increase this to 8, but this is good enough for
125 * now. This is typically called after LD_MALLOC.
127 #define REALIGN() malloc_buffer = (char *) (((unsigned long) malloc_buffer + 3) & ~(3))
129 char *_dl_library_path = 0; /* Where we look for libraries */
130 char *_dl_preload = 0; /* Things to be loaded before the libs. */
131 char *_dl_ldsopath = 0;
132 static char *_dl_not_lazy = 0;
133 #ifdef __SUPPORT_LD_DEBUG__
134 static char *_dl_debug = 0;
135 static char *_dl_debug_symbols = 0;
136 static char *_dl_debug_move = 0;
137 static char *_dl_debug_reloc = 0;
138 static char *_dl_debug_detail = 0;
139 static char *_dl_debug_nofixups = 0;
140 static char *_dl_debug_bindings = 0;
141 static int _dl_debug_file = 2;
143 #define _dl_debug_file 2
145 static char *_dl_malloc_addr, *_dl_mmap_zero;
147 static char *_dl_trace_loaded_objects = 0;
148 static int (*_dl_elf_main) (int, char **, char **);
149 static int (*_dl_elf_init) (void);
150 struct r_debug *_dl_debug_addr = NULL;
151 unsigned long *_dl_brkp;
152 unsigned long *_dl_envp;
153 int _dl_fixup(struct elf_resolve *tpnt);
154 void _dl_debug_state(void);
155 char *_dl_get_last_path_component(char *path);
156 static void _dl_get_ready_to_run(struct elf_resolve *tpnt, struct elf_resolve *app_tpnt,
157 unsigned long load_addr, unsigned long *hash_addr, Elf32_auxv_t auxvt[AT_EGID + 1],
158 char **envp, struct r_debug *debug_addr);
159 #include "boot1_arch.h"
160 #include "ldso.h" /* Pull in the name of ld.so */
163 /* When we enter this piece of code, the program stack looks like this:
164 argc argument counter (integer)
165 argv[0] program name (pointer)
166 argv[1...N] program args (pointers)
167 argv[argc-1] end of args (integer)
169 env[0...N] environment variables (pointers)
171 auxvt[0...N] Auxiliary Vector Table elements (mixed types)
174 #ifdef __SUPPORT_LD_DEBUG_EARLY__
175 /* Debugging is especially tricky on PowerPC, since string literals
176 * require relocations. Thus, you can't use _dl_dprintf() for
177 * anything until the bootstrap relocations are finished. */
178 static inline void hexprint(unsigned long x)
183 for (i = 0; i < 8; i++) {
184 c = ((x >> 28) + '0');
195 LD_BOOT(unsigned long args) __attribute__ ((unused));
197 LD_BOOT(unsigned long args)
201 unsigned long load_addr;
203 unsigned long *aux_dat;
206 struct elf_resolve *tpnt;
207 struct elf_resolve *app_tpnt;
208 Elf32_auxv_t auxvt[AT_EGID + 1];
209 unsigned char *malloc_buffer, *mmap_zero;
211 unsigned long *hash_addr;
212 struct r_debug *debug_addr = NULL;
217 /* WARNING! -- we cannot make _any_ funtion calls until we have
218 * taken care of fixing up our own relocations. Making static
219 * inline calls is ok, but _no_ function calls. Not yet
222 /* First obtain the information on the stack that tells us more about
223 what binary is loaded, where it is loaded, etc, etc */
224 GET_ARGV(aux_dat, args);
225 #if defined (__arm__) || defined (__mips__)
228 argc = *(aux_dat - 1);
229 argv = (char **) aux_dat;
230 aux_dat += argc; /* Skip over the argv pointers */
231 aux_dat++; /* Skip over NULL at end of argv */
232 envp = (char **) aux_dat;
234 aux_dat++; /* Skip over the envp pointers */
235 aux_dat++; /* Skip over NULL at end of envp */
237 /* Place -1 here as a checkpoint. We later check if it was changed
238 * when we read in the auxvt */
239 auxvt[AT_UID].a_type = -1;
241 /* The junk on the stack immediately following the environment is
242 * the Auxiliary Vector Table. Read out the elements of the auxvt,
243 * sort and store them in auxvt for later use. */
245 Elf32_auxv_t *auxv_entry = (Elf32_auxv_t *) aux_dat;
247 if (auxv_entry->a_type <= AT_EGID) {
248 _dl_memcpy(&(auxvt[auxv_entry->a_type]), auxv_entry, sizeof(Elf32_auxv_t));
253 /* locate the ELF header. We need this done as soon as possible
254 * (esp since SEND_STDERR() needs this on some platforms... */
255 load_addr = auxvt[AT_BASE].a_un.a_val;
256 header = (elfhdr *) auxvt[AT_BASE].a_un.a_ptr;
258 /* Check the ELF header to make sure everything looks ok. */
259 if (!header || header->e_ident[EI_CLASS] != ELFCLASS32 ||
260 header->e_ident[EI_VERSION] != EV_CURRENT
261 #if !defined(__powerpc__) && !defined(__mips__) && !defined(__sh__)
262 || _dl_strncmp((void *) header, ELFMAGIC, SELFMAG) != 0
264 || header->e_ident[EI_MAG0] != ELFMAG0
265 || header->e_ident[EI_MAG1] != ELFMAG1
266 || header->e_ident[EI_MAG2] != ELFMAG2
267 || header->e_ident[EI_MAG3] != ELFMAG3
270 SEND_STDERR("Invalid ELF header\n");
273 #ifdef __SUPPORT_LD_DEBUG_EARLY__
274 SEND_STDERR("ELF header=");
275 SEND_ADDRESS_STDERR(load_addr, 1);
279 /* Locate the global offset table. Since this code must be PIC
280 * we can take advantage of the magic offset register, if we
281 * happen to know what that is for this architecture. If not,
282 * we can always read stuff out of the ELF file to find it... */
283 #if defined(__i386__)
284 __asm__("\tmovl %%ebx,%0\n\t":"=a"(got));
285 #elif defined(__m68k__)
286 __asm__("movel %%a5,%0":"=g"(got))
287 #elif defined(__sparc__)
288 __asm__("\tmov %%l7,%0\n\t":"=r"(got))
289 #elif defined(__arm__)
290 __asm__("\tmov %0, r10\n\t":"=r"(got));
291 #elif defined(__powerpc__)
292 __asm__("\tbl _GLOBAL_OFFSET_TABLE_-4@local\n\t":"=l"(got));
293 #elif defined(__mips__)
294 __asm__("\tmove %0, $28\n\tsubu %0,%0,0x7ff0\n\t":"=r"(got));
295 #elif defined(__sh__)
302 "1: .long _GLOBAL_OFFSET_TABLE_\n"
303 "2:" : "=r" (got) : : "r0");
304 #elif defined(__cris__)
305 __asm__("\tmove.d $pc,%0\n\tsub.d .:GOTOFF,%0\n\t":"=r"(got));
307 /* Do things the slow way in C */
309 unsigned long tx_reloc;
310 Elf32_Dyn *dynamic = NULL;
314 #ifdef __SUPPORT_LD_DEBUG_EARLY__
315 SEND_STDERR("Finding the GOT using C code to read the ELF file\n");
317 /* Find where the dynamic linking information section is hiding */
318 shdr = (Elf32_Shdr *) (header->e_shoff + (char *) header);
319 for (indx = header->e_shnum; --indx >= 0; ++shdr) {
320 if (shdr->sh_type == SHT_DYNAMIC) {
324 SEND_STDERR("missing dynamic linking information section \n");
328 dynamic = (Elf32_Dyn *) (shdr->sh_offset + (char *) header);
330 /* Find where PT_LOAD is hiding */
331 pt_load = (Elf32_Phdr *) (header->e_phoff + (char *) header);
332 for (indx = header->e_phnum; --indx >= 0; ++pt_load) {
333 if (pt_load->p_type == PT_LOAD) {
337 SEND_STDERR("missing loadable program segment\n");
341 /* Now (finally) find where DT_PLTGOT is hiding */
342 tx_reloc = pt_load->p_vaddr - pt_load->p_offset;
343 for (; DT_NULL != dynamic->d_tag; ++dynamic) {
344 if (dynamic->d_tag == DT_PLTGOT) {
348 SEND_STDERR("missing global offset table\n");
352 got = (unsigned long *) (dynamic->d_un.d_val - tx_reloc +
357 /* Now, finally, fix up the location of the dynamic stuff */
358 dpnt = (Elf32_Dyn *) (*got + load_addr);
359 #ifdef __SUPPORT_LD_DEBUG_EARLY__
360 SEND_STDERR("First Dynamic section entry=");
361 SEND_ADDRESS_STDERR(dpnt, 1);
365 /* Call mmap to get a page of writable memory that can be used
366 * for _dl_malloc throughout the shared lib loader. */
367 mmap_zero = malloc_buffer = _dl_mmap((void *) 0, 4096,
368 PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
369 if (_dl_mmap_check_error(mmap_zero)) {
370 SEND_STDERR("dl_boot: mmap of a spare page failed!\n");
374 tpnt = LD_MALLOC(sizeof(struct elf_resolve));
375 _dl_memset(tpnt, 0, sizeof(struct elf_resolve));
376 app_tpnt = LD_MALLOC(sizeof(struct elf_resolve));
377 _dl_memset(app_tpnt, 0, sizeof(struct elf_resolve));
380 * This is used by gdb to locate the chain of shared libraries that are currently loaded.
382 debug_addr = LD_MALLOC(sizeof(struct r_debug));
383 _dl_memset(debug_addr, 0, sizeof(struct r_debug));
385 /* OK, that was easy. Next scan the DYNAMIC section of the image.
386 We are only doing ourself right now - we will have to do the rest later */
387 #ifdef __SUPPORT_LD_DEBUG_EARLY__
388 SEND_STDERR("scanning DYNAMIC section\n");
390 while (dpnt->d_tag) {
391 #if defined(__mips__)
392 if (dpnt->d_tag == DT_MIPS_GOTSYM)
393 tpnt->mips_gotsym = (unsigned long) dpnt->d_un.d_val;
394 if (dpnt->d_tag == DT_MIPS_LOCAL_GOTNO)
395 tpnt->mips_local_gotno = (unsigned long) dpnt->d_un.d_val;
396 if (dpnt->d_tag == DT_MIPS_SYMTABNO)
397 tpnt->mips_symtabno = (unsigned long) dpnt->d_un.d_val;
399 if (dpnt->d_tag < 24) {
400 tpnt->dynamic_info[dpnt->d_tag] = dpnt->d_un.d_val;
401 if (dpnt->d_tag == DT_TEXTREL) {
402 tpnt->dynamic_info[DT_TEXTREL] = 1;
412 ppnt = (elf_phdr *) auxvt[AT_PHDR].a_un.a_ptr;
413 for (i = 0; i < auxvt[AT_PHNUM].a_un.a_val; i++, ppnt++)
414 if (ppnt->p_type == PT_DYNAMIC) {
415 dpnt = (Elf32_Dyn *) ppnt->p_vaddr;
416 while (dpnt->d_tag) {
417 #if defined(__mips__)
418 if (dpnt->d_tag == DT_MIPS_GOTSYM)
419 app_tpnt->mips_gotsym =
420 (unsigned long) dpnt->d_un.d_val;
421 if (dpnt->d_tag == DT_MIPS_LOCAL_GOTNO)
422 app_tpnt->mips_local_gotno =
423 (unsigned long) dpnt->d_un.d_val;
424 if (dpnt->d_tag == DT_MIPS_SYMTABNO)
425 app_tpnt->mips_symtabno =
426 (unsigned long) dpnt->d_un.d_val;
428 if (dpnt->d_tag > DT_JMPREL) {
432 app_tpnt->dynamic_info[dpnt->d_tag] = dpnt->d_un.d_val;
433 #if !defined(__mips__)
434 if (dpnt->d_tag == DT_DEBUG) {
435 dpnt->d_un.d_val = (unsigned long) debug_addr;
438 #warning "Debugging threads on mips won't work till someone fixes this..."
440 if (dpnt->d_tag == DT_TEXTREL)
441 app_tpnt->dynamic_info[DT_TEXTREL] = 1;
447 #ifdef __SUPPORT_LD_DEBUG_EARLY__
448 SEND_STDERR("done scanning DYNAMIC section\n");
451 /* Get some more of the information that we will need to dynamicly link
452 this module to itself */
454 hash_addr = (unsigned long *) (tpnt->dynamic_info[DT_HASH] + load_addr);
455 tpnt->nbucket = *hash_addr++;
456 tpnt->nchain = *hash_addr++;
457 tpnt->elf_buckets = hash_addr;
458 hash_addr += tpnt->nbucket;
460 #ifdef __SUPPORT_LD_DEBUG_EARLY__
461 SEND_STDERR("done grabbing link information\n");
464 #ifndef FORCE_SHAREABLE_TEXT_SEGMENTS
465 /* Ugly, ugly. We need to call mprotect to change the protection of
466 the text pages so that we can do the dynamic linking. We can set the
467 protection back again once we are done */
473 #ifdef __SUPPORT_LD_DEBUG_EARLY__
474 SEND_STDERR("calling mprotect on the shared library/dynamic linker\n");
477 /* First cover the shared library/dynamic linker. */
478 if (tpnt->dynamic_info[DT_TEXTREL]) {
479 header = (elfhdr *) auxvt[AT_BASE].a_un.a_ptr;
480 ppnt = (elf_phdr *) ((int)auxvt[AT_BASE].a_un.a_ptr +
482 for (i = 0; i < header->e_phnum; i++, ppnt++) {
483 if (ppnt->p_type == PT_LOAD && !(ppnt->p_flags & PF_W)) {
484 _dl_mprotect((void *) (load_addr + (ppnt->p_vaddr & PAGE_ALIGN)),
485 (ppnt->p_vaddr & ADDR_ALIGN) + (unsigned long) ppnt->p_filesz,
486 PROT_READ | PROT_WRITE | PROT_EXEC);
491 #ifdef __SUPPORT_LD_DEBUG_EARLY__
492 SEND_STDERR("calling mprotect on the application program\n");
494 /* Now cover the application program. */
495 if (app_tpnt->dynamic_info[DT_TEXTREL]) {
496 ppnt = (elf_phdr *) auxvt[AT_PHDR].a_un.a_ptr;
497 for (i = 0; i < auxvt[AT_PHNUM].a_un.a_val; i++, ppnt++) {
498 if (ppnt->p_type == PT_LOAD && !(ppnt->p_flags & PF_W))
499 _dl_mprotect((void *) (ppnt->p_vaddr & PAGE_ALIGN),
500 (ppnt->p_vaddr & ADDR_ALIGN) +
501 (unsigned long) ppnt->p_filesz,
502 PROT_READ | PROT_WRITE | PROT_EXEC);
508 #if defined(__mips__)
509 #ifdef __SUPPORT_LD_DEBUG_EARLY__
510 SEND_STDERR("About to do MIPS specific GOT bootstrap\n");
512 /* For MIPS we have to do stuff to the GOT before we do relocations. */
513 PERFORM_BOOTSTRAP_GOT(got);
516 /* OK, now do the relocations. We do not do a lazy binding here, so
517 that once we are done, we have considerably more flexibility. */
518 #ifdef __SUPPORT_LD_DEBUG_EARLY__
519 SEND_STDERR("About to do library loader relocations\n");
523 for (indx = 0; indx < 2; indx++) {
526 unsigned long *reloc_addr;
527 unsigned long symbol_addr;
529 unsigned long rel_addr, rel_size;
532 #ifdef ELF_USES_RELOCA
533 rel_addr = (indx ? tpnt->dynamic_info[DT_JMPREL] : tpnt->
534 dynamic_info[DT_RELA]);
535 rel_size = (indx ? tpnt->dynamic_info[DT_PLTRELSZ] : tpnt->
536 dynamic_info[DT_RELASZ]);
538 rel_addr = (indx ? tpnt->dynamic_info[DT_JMPREL] : tpnt->
539 dynamic_info[DT_REL]);
540 rel_size = (indx ? tpnt->dynamic_info[DT_PLTRELSZ] : tpnt->
541 dynamic_info[DT_RELSZ]);
547 /* Now parse the relocation information */
548 rpnt = (ELF_RELOC *) (rel_addr + load_addr);
549 for (i = 0; i < rel_size; i += sizeof(ELF_RELOC), rpnt++) {
550 reloc_addr = (unsigned long *) (load_addr + (unsigned long) rpnt->r_offset);
551 symtab_index = ELF32_R_SYM(rpnt->r_info);
557 symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + load_addr);
558 strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + load_addr);
560 /* We only do a partial dynamic linking right now. The user
561 is not supposed to redefine any symbols that start with
562 a '_', so we can do this with confidence. */
563 if (!_dl_symbol(strtab + symtab[symtab_index].st_name))
565 symbol_addr = load_addr + symtab[symtab_index].st_value;
568 /* This will segfault - you cannot call a function until
569 * we have finished the relocations.
571 SEND_STDERR("ELF dynamic loader - unable to self-bootstrap - symbol ");
572 SEND_STDERR(strtab + symtab[symtab_index].st_name);
573 SEND_STDERR(" undefined.\n");
576 #ifdef __SUPPORT_LD_DEBUG_EARLY__
577 SEND_STDERR("About to fixup symbol: ");
578 SEND_STDERR(strtab + symtab[symtab_index].st_name);
583 * Use this machine-specific macro to perform the actual relocation.
585 PERFORM_BOOTSTRAP_RELOC(rpnt, reloc_addr, symbol_addr, load_addr);
592 #ifdef __SUPPORT_LD_DEBUG_EARLY__
594 _dl_dprintf(_dl_debug_file, "Done relocating library loader, so we can now\n\tuse globals and make function calls!\n");
598 _dl_progname = argv[0];
601 /* Start to build the tables of the modules that are required for
602 * this beast to run. We start with the basic executable, and then
603 * go from there. Eventually we will run across ourself, and we
604 * will need to properly deal with that as well. */
606 /* Make it so _dl_malloc can use the page of memory we have already
607 * allocated, so we shouldn't need to grab any more memory */
608 _dl_malloc_addr = malloc_buffer;
609 _dl_mmap_zero = mmap_zero;
613 /* Now we have done the mandatory linking of some things. We are now
614 free to start using global variables, since these things have all been
615 fixed up by now. Still no function calls outside of this library ,
616 since the dynamic resolver is not yet ready. */
617 _dl_get_ready_to_run(tpnt, app_tpnt, load_addr, hash_addr, auxvt, envp, debug_addr);
620 /* Notify the debugger that all objects are now mapped in. */
621 _dl_debug_addr->r_state = RT_CONSISTENT;
625 /* OK we are done here. Turn out the lights, and lock up. */
626 _dl_elf_main = (int (*)(int, char **, char **)) auxvt[AT_ENTRY].a_un.a_fcn;
629 * Transfer control to the application.
631 status = 0; /* Used on x86, but not on other arches */
632 #if defined (__SUPPORT_LD_DEBUG__)
633 if(_dl_debug) _dl_dprintf(_dl_debug_file,"\ntransfering control: %s\n\n", _dl_progname);
638 #if defined (__SUPPORT_LD_DEBUG__)
639 static void debug_fini (int status, void *arg)
642 _dl_dprintf(_dl_debug_file,"\ncalling fini: %s\n\n", (const char*)arg);
646 static void _dl_get_ready_to_run(struct elf_resolve *tpnt, struct elf_resolve *app_tpnt,
647 unsigned long load_addr, unsigned long *hash_addr, Elf32_auxv_t auxvt[AT_EGID + 1],
648 char **envp, struct r_debug *debug_addr)
652 int i, _dl_secure, goof = 0;
653 struct dyn_elf *rpnt;
654 struct elf_resolve *tcurr;
655 struct elf_resolve *tpnt1;
656 unsigned long brk_addr, *lpnt;
657 int (*_dl_atexit) (void *);
658 #if defined (__SUPPORT_LD_DEBUG__)
659 int (*_dl_on_exit) (void (*FUNCTION)(int STATUS, void *ARG),void*);
662 /* Now we have done the mandatory linking of some things. We are now
663 free to start using global variables, since these things have all been
664 fixed up by now. Still no function calls outside of this library ,
665 since the dynamic resolver is not yet ready. */
666 lpnt = (unsigned long *) (tpnt->dynamic_info[DT_PLTGOT] + load_addr);
668 tpnt->chains = hash_addr;
671 tpnt->libtype = program_interpreter;
672 tpnt->loadaddr = (char *) load_addr;
674 #ifdef ALLOW_ZERO_PLTGOT
675 if (tpnt->dynamic_info[DT_PLTGOT])
678 INIT_GOT(lpnt, tpnt);
679 #ifdef __SUPPORT_LD_DEBUG_EARLY__
680 _dl_dprintf(_dl_debug_file, "GOT found at %x\n", lpnt);
684 /* OK, this was a big step, now we need to scan all of the user images
685 and load them properly. */
692 epnt = (elfhdr *) auxvt[AT_BASE].a_un.a_ptr;
693 tpnt->n_phent = epnt->e_phnum;
694 tpnt->ppnt = myppnt = (elf_phdr *) (load_addr + epnt->e_phoff);
695 for (j = 0; j < epnt->e_phnum; j++, myppnt++) {
696 if (myppnt->p_type == PT_DYNAMIC) {
697 tpnt->dynamic_addr = myppnt->p_vaddr + load_addr;
698 #if defined(__mips__)
701 Elf32_Dyn *dpnt = (Elf32_Dyn *) tpnt->dynamic_addr;
707 tpnt->dynamic_size = k * sizeof(Elf32_Dyn);
710 tpnt->dynamic_size = myppnt->p_filesz;
719 /* At this point we are now free to examine the user application,
720 and figure out which libraries are supposed to be called. Until
721 we have this list, we will not be completely ready for dynamic linking */
723 ppnt = (elf_phdr *) auxvt[AT_PHDR].a_un.a_ptr;
724 for (i = 0; i < auxvt[AT_PHNUM].a_un.a_val; i++, ppnt++) {
725 if (ppnt->p_type == PT_LOAD) {
726 if (ppnt->p_vaddr + ppnt->p_memsz > brk_addr)
727 brk_addr = ppnt->p_vaddr + ppnt->p_memsz;
729 if (ppnt->p_type == PT_DYNAMIC) {
730 #ifndef ALLOW_ZERO_PLTGOT
731 /* make sure it's really there. */
732 if (app_tpnt->dynamic_info[DT_PLTGOT] == 0)
735 /* OK, we have what we need - slip this one into the list. */
736 #if defined(__mips__)
739 Elf32_Dyn *dpnt = (Elf32_Dyn *) tpnt->dynamic_addr;
745 app_tpnt = _dl_add_elf_hash_table("", 0,
746 app_tpnt->dynamic_info, ppnt->p_vaddr,
747 (i * sizeof(Elf32_Dyn)));
750 app_tpnt = _dl_add_elf_hash_table("", 0,
751 app_tpnt->dynamic_info, ppnt->p_vaddr, ppnt->p_filesz);
753 _dl_loaded_modules->libtype = elf_executable;
754 _dl_loaded_modules->ppnt = (elf_phdr *) auxvt[AT_PHDR].a_un.a_ptr;
755 _dl_loaded_modules->n_phent = auxvt[AT_PHNUM].a_un.a_val;
756 _dl_symbol_tables = rpnt = (struct dyn_elf *) _dl_malloc(sizeof(struct dyn_elf));
757 _dl_memset(rpnt, 0, sizeof(struct dyn_elf));
758 rpnt->dyn = _dl_loaded_modules;
759 app_tpnt->usage_count++;
760 app_tpnt->symbol_scope = _dl_symbol_tables;
761 lpnt = (unsigned long *) (app_tpnt->dynamic_info[DT_PLTGOT]);
762 #ifdef ALLOW_ZERO_PLTGOT
765 INIT_GOT(lpnt, _dl_loaded_modules);
768 /* OK, fill this in - we did not have this before */
769 if (ppnt->p_type == PT_INTERP) {
771 char *pnt, *pnt1, buf[1024];
772 tpnt->libname = _dl_strdup((char *) ppnt->p_offset +
773 (auxvt[AT_PHDR].a_un.a_val & PAGE_ALIGN));
775 /* Determine if the shared lib loader is a symlink */
776 _dl_memset(buf, 0, sizeof(buf));
777 readsize = _dl_readlink(tpnt->libname, buf, sizeof(buf));
778 if (readsize > 0 && readsize < (int)(sizeof(buf)-1)) {
779 pnt1 = _dl_strrchr(buf, '/');
780 if (pnt1 && buf != pnt1) {
781 #ifdef __SUPPORT_LD_DEBUG_EARLY__
782 _dl_dprintf(_dl_debug_file, "changing tpnt->libname from '%s' to '%s'\n", tpnt->libname, buf);
784 tpnt->libname = _dl_strdup(buf);
788 /* Store the path where the shared lib loader was found for
790 pnt = _dl_strdup(tpnt->libname);
791 pnt1 = _dl_strrchr(pnt, '/');
796 _dl_ldsopath = tpnt->libname;
798 #ifdef __SUPPORT_LD_DEBUG_EARLY__
799 _dl_dprintf(_dl_debug_file, "Lib Loader:\t(%x) %s\n", tpnt->loadaddr, tpnt->libname);
805 /* Now we need to figure out what kind of options are selected.
806 Note that for SUID programs we ignore the settings in LD_LIBRARY_PATH */
808 _dl_not_lazy = _dl_getenv("LD_BIND_NOW", envp);
810 if ((auxvt[AT_UID].a_un.a_val == -1 && _dl_suid_ok()) ||
811 (auxvt[AT_UID].a_un.a_val != -1 &&
812 auxvt[AT_UID].a_un.a_val == auxvt[AT_EUID].a_un.a_val
813 && auxvt[AT_GID].a_un.a_val== auxvt[AT_EGID].a_un.a_val)) {
815 _dl_preload = _dl_getenv("LD_PRELOAD", envp);
816 _dl_library_path = _dl_getenv("LD_LIBRARY_PATH", envp);
819 _dl_preload = _dl_getenv("LD_PRELOAD", envp);
820 _dl_unsetenv("LD_AOUT_PRELOAD", envp);
821 _dl_unsetenv("LD_LIBRARY_PATH", envp);
822 _dl_unsetenv("LD_AOUT_LIBRARY_PATH", envp);
823 _dl_library_path = NULL;
827 #ifdef __SUPPORT_LD_DEBUG__
828 _dl_debug = _dl_getenv("LD_DEBUG", envp);
831 if (_dl_strstr(_dl_debug, "all")) {
832 _dl_debug_detail = _dl_debug_move = _dl_debug_symbols
833 = _dl_debug_reloc = _dl_debug_bindings = _dl_debug_nofixups = _dl_strstr(_dl_debug, "all");
836 _dl_debug_detail = _dl_strstr(_dl_debug, "detail");
837 _dl_debug_move = _dl_strstr(_dl_debug, "move");
838 _dl_debug_symbols = _dl_strstr(_dl_debug, "sym");
839 _dl_debug_reloc = _dl_strstr(_dl_debug, "reloc");
840 _dl_debug_nofixups = _dl_strstr(_dl_debug, "nofix");
841 _dl_debug_bindings = _dl_strstr(_dl_debug, "bind");
845 const char *dl_debug_output;
847 dl_debug_output = _dl_getenv("LD_DEBUG_OUTPUT", envp);
851 char tmp[22], *tmp1, *filename;
854 _dl_memset(tmp, 0, sizeof(tmp));
855 tmp1=_dl_simple_ltoa( tmp, (unsigned long)_dl_getpid());
857 len1 = _dl_strlen(dl_debug_output);
858 len2 = _dl_strlen(tmp1);
860 filename = _dl_malloc(len1+len2+2);
864 _dl_strcpy (filename, dl_debug_output);
865 filename[len1] = '.';
866 _dl_strcpy (&filename[len1+1], tmp1);
868 _dl_debug_file= _dl_open (filename, O_WRONLY|O_CREAT);
869 if (_dl_debug_file<0)
872 _dl_dprintf (2, "can't open file: '%s'\n",filename);
880 _dl_trace_loaded_objects = _dl_getenv("LD_TRACE_LOADED_OBJECTS", envp);
881 #ifndef __LDSO_LDD_SUPPORT__
882 if (_dl_trace_loaded_objects) {
883 _dl_dprintf(_dl_debug_file, "Use the ldd provided by uClibc\n");
889 * OK, fix one more thing - set up debug_addr so it will point
890 * to our chain. Later we may need to fill in more fields, but this
891 * should be enough for now.
893 debug_addr->r_map = (struct link_map *) _dl_loaded_modules;
894 debug_addr->r_version = 1;
895 debug_addr->r_ldbase = load_addr;
896 debug_addr->r_brk = (unsigned long) &_dl_debug_state;
897 _dl_debug_addr = debug_addr;
899 /* Notify the debugger we are in a consistant state */
900 _dl_debug_addr->r_state = RT_CONSISTENT;
903 /* OK, we now have the application in the list, and we have some
904 basic stuff in place. Now search through the list for other shared
905 libraries that should be loaded, and insert them on the list in the
918 while (*str == ':' || *str == ' ' || *str == '\t')
923 while (*str2 && *str2 != ':' && *str2 != ' ' && *str2 != '\t')
927 if (!_dl_secure || _dl_strchr(str, '/') == NULL)
929 tpnt1 = _dl_load_shared_library(_dl_secure, &rpnt, NULL, str);
931 #ifdef __LDSO_LDD_SUPPORT__
932 if (_dl_trace_loaded_objects)
933 _dl_dprintf(1, "\t%s => not found\n", str);
937 _dl_dprintf(2, "%s: can't load " "library '%s'\n", _dl_progname, str);
941 #ifdef __SUPPORT_LD_DEBUG_EARLY__
942 _dl_dprintf(_dl_debug_file, "Loading:\t(%x) %s\n", tpnt1->loadaddr, tpnt1->libname);
944 #ifdef __LDSO_LDD_SUPPORT__
945 if (_dl_trace_loaded_objects && tpnt1->usage_count==1) {
946 /* this is a real hack to make ldd not print
947 * the library itself when run on a library. */
948 if (_dl_strcmp(_dl_progname, str) != 0)
949 _dl_dprintf(1, "\t%s => %s (%x)\n", str, tpnt1->libname,
950 (unsigned) tpnt1->loadaddr);
957 while (*str == ':' || *str == ' ' || *str == '\t')
962 #ifdef SUPPORT_LDSO_PRELOAD_FILE
967 if (!_dl_stat(LDSO_PRELOAD, &st) && st.st_size > 0) {
968 if ((fd = _dl_open(LDSO_PRELOAD, O_RDONLY)) < 0) {
969 _dl_dprintf(2, "%s: can't open file '%s'\n",
970 _dl_progname, LDSO_PRELOAD);
972 preload = (caddr_t) _dl_mmap(0, st.st_size + 1,
973 PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
975 if (preload == (caddr_t) - 1) {
976 _dl_dprintf(2, "%s: can't map file '%s'\n",
977 _dl_progname, LDSO_PRELOAD);
981 /* convert all separators and comments to spaces */
982 for (cp = preload; *cp; /*nada */ ) {
983 if (*cp == ':' || *cp == '\t' || *cp == '\n') {
985 } else if (*cp == '#') {
988 while (*cp != '\n' && *cp != '\0');
994 /* find start of first library */
995 for (cp = preload; *cp && *cp == ' '; cp++)
999 /* find end of library */
1000 for (cp2 = cp; *cp && *cp != ' '; cp++)
1005 tpnt1 = _dl_load_shared_library(0, &rpnt, NULL, cp2);
1007 #ifdef __LDSO_LDD_SUPPORT__
1008 if (_dl_trace_loaded_objects)
1009 _dl_dprintf(1, "\t%s => not found\n", cp2);
1013 _dl_dprintf(2, "%s: can't load library '%s'\n", _dl_progname, cp2);
1017 #ifdef __SUPPORT_LD_DEBUG_EARLY__
1018 _dl_dprintf(_dl_debug_file, "Loading:\t(%x) %s\n", tpnt1->loadaddr, tpnt1->libname);
1020 #ifdef __LDSO_LDD_SUPPORT__
1021 if (_dl_trace_loaded_objects && tpnt1->usage_count==1) {
1022 _dl_dprintf(1, "\t%s => %s (%x)\n", cp2,
1023 tpnt1->libname, (unsigned) tpnt1->loadaddr);
1028 /* find start of next library */
1030 for ( /*nada */ ; *cp && *cp == ' '; cp++)
1034 _dl_munmap(preload, st.st_size + 1);
1041 for (tcurr = _dl_loaded_modules; tcurr; tcurr = tcurr->next) {
1043 for (dpnt = (Elf32_Dyn *) tcurr->dynamic_addr; dpnt->d_tag;
1045 if (dpnt->d_tag == DT_NEEDED) {
1046 lpntstr = tcurr->loadaddr + tcurr->dynamic_info[DT_STRTAB] +
1048 if (_dl_strcmp(lpntstr, "libc.so.6") == 0) {
1050 name = tcurr->libname;
1053 if (_dl_trace_loaded_objects) {
1058 _dl_dprintf(2, "\t%s: %s is linked with GNU libc!\n", msg, --name);
1059 /* If all we are doing is ldd, then we don't need to freak out... */
1060 if (_dl_trace_loaded_objects) {
1063 /* Time to freak out. Make sure glibc linked libraries are not loaded */
1066 if (tpnt && _dl_strcmp(lpntstr, _dl_get_last_path_component(tpnt->libname)) == 0)
1068 struct elf_resolve *ttmp;
1070 #ifdef __LDSO_LDD_SUPPORT__
1071 if (_dl_trace_loaded_objects && tpnt->usage_count==1) {
1073 name = tpnt->libname;
1076 _dl_dprintf(1, "\t%s => %s (%x)\n",
1077 lpntstr, --name, (unsigned) tpnt->loadaddr);
1080 ttmp = _dl_loaded_modules;
1086 rpnt->next = (struct dyn_elf *) _dl_malloc(sizeof(struct dyn_elf));
1087 _dl_memset(rpnt->next, 0, sizeof(struct dyn_elf));
1088 rpnt->next->prev = rpnt;
1091 tpnt->usage_count++;
1092 tpnt->symbol_scope = _dl_symbol_tables;
1096 if (!(tpnt1 = _dl_load_shared_library(0, &rpnt, tcurr, lpntstr)))
1098 #ifdef __LDSO_LDD_SUPPORT__
1099 if (_dl_trace_loaded_objects)
1100 _dl_dprintf(1, "\t%s => not found\n", lpntstr);
1104 _dl_dprintf(2, "%s: can't load library '%s'\n", _dl_progname, lpntstr);
1108 #ifdef __SUPPORT_LD_DEBUG_EARLY__
1109 _dl_dprintf(_dl_debug_file, "Loading:\t(%x) %s\n", tpnt1->loadaddr, tpnt1->libname);
1111 #ifdef __LDSO_LDD_SUPPORT__
1112 if (_dl_trace_loaded_objects && tpnt1->usage_count==1) {
1114 name = tpnt1->libname;
1117 _dl_dprintf(1, "\t%s => %s (%x)\n", lpntstr, --name,
1118 (unsigned) tpnt1->loadaddr);
1132 * If the program interpreter is not in the module chain, add it. This will
1133 * be required for dlopen to be able to access the internal functions in the
1137 tcurr = _dl_loaded_modules;
1140 tcurr = tcurr->next;
1142 tpnt->usage_count++;
1148 _dl_loaded_modules = tpnt;
1152 rpnt->next = (struct dyn_elf *) _dl_malloc(sizeof(struct dyn_elf));
1153 _dl_memset(rpnt->next, 0, sizeof(struct dyn_elf));
1154 rpnt->next->prev = rpnt;
1157 rpnt = (struct dyn_elf *) _dl_malloc(sizeof(struct dyn_elf));
1158 _dl_memset(rpnt, 0, sizeof(struct dyn_elf));
1164 #ifdef __LDSO_LDD_SUPPORT__
1165 /* End of the line for ldd.... */
1166 if (_dl_trace_loaded_objects) {
1167 _dl_dprintf(1, "\t%s => %s (%x)\n", rpnt->dyn->libname + (_dl_strlen(_dl_ldsopath)) + 1,
1168 rpnt->dyn->libname, rpnt->dyn->loadaddr);
1176 * Relocation of the GOT entries for MIPS have to be done
1177 * after all the libraries have been loaded.
1179 _dl_perform_mips_global_got_relocations(_dl_loaded_modules);
1182 #ifdef __SUPPORT_LD_DEBUG_EARLY__
1183 _dl_dprintf(_dl_debug_file, "Beginning relocation fixups\n");
1186 * OK, now all of the kids are tucked into bed in their proper addresses.
1187 * Now we go through and look for REL and RELA records that indicate fixups
1188 * to the GOT tables. We need to do this in reverse order so that COPY
1189 * directives work correctly */
1190 goof = _dl_loaded_modules ? _dl_fixup(_dl_loaded_modules) : 0;
1193 /* Some flavors of SVr4 do not generate the R_*_COPY directive,
1194 and we have to manually search for entries that require fixups.
1195 Solaris gets this one right, from what I understand. */
1197 #ifdef __SUPPORT_LD_DEBUG_EARLY__
1198 _dl_dprintf(_dl_debug_file, "Beginning copy fixups\n");
1200 if (_dl_symbol_tables)
1201 goof += _dl_copy_fixups(_dl_symbol_tables);
1203 /* OK, at this point things are pretty much ready to run. Now we
1204 need to touch up a few items that are required, and then
1205 we can let the user application have at it. Note that
1206 the dynamic linker itself is not guaranteed to be fully
1207 dynamicly linked if we are using ld.so.1, so we have to look
1208 up each symbol individually. */
1211 _dl_brkp = (unsigned long *) (intptr_t) _dl_find_hash("___brk_addr", NULL, NULL, symbolrel);
1214 *_dl_brkp = brk_addr;
1216 _dl_envp = (unsigned long *) (intptr_t) _dl_find_hash("__environ", NULL, NULL, symbolrel);
1219 *_dl_envp = (unsigned long) envp;
1222 #ifndef FORCE_SHAREABLE_TEXT_SEGMENTS
1227 /* We had to set the protections of all pages to R/W for dynamic linking.
1228 Set text pages back to R/O */
1229 for (tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next) {
1230 for (myppnt = tpnt->ppnt, j = 0; j < tpnt->n_phent; j++, myppnt++) {
1231 if (myppnt->p_type == PT_LOAD && !(myppnt->p_flags & PF_W) && tpnt->dynamic_info[DT_TEXTREL]) {
1232 _dl_mprotect((void *) (tpnt->loadaddr + (myppnt->p_vaddr & PAGE_ALIGN)),
1233 (myppnt->p_vaddr & ADDR_ALIGN) + (unsigned long) myppnt->p_filesz, LXFLAGS(myppnt->p_flags));
1240 _dl_atexit = (int (*)(void *)) (intptr_t) _dl_find_hash("atexit", NULL, NULL, symbolrel);
1241 #if defined (__SUPPORT_LD_DEBUG__)
1242 _dl_on_exit = (int (*)(void (*)(int, void *),void*))
1243 (intptr_t) _dl_find_hash("on_exit", NULL, NULL, symbolrel);
1246 /* Notify the debugger we have added some objects. */
1247 _dl_debug_addr->r_state = RT_ADD;
1250 for (rpnt = _dl_symbol_tables; rpnt!=NULL&& rpnt->next!=NULL; rpnt=rpnt->next)
1253 for (;rpnt!=NULL; rpnt=rpnt->prev)
1257 if (tpnt->libtype == program_interpreter)
1260 /* Apparently crt0/1 for the application is responsible for handling this.
1261 * We only need to run the init/fini for shared libraries
1263 if (tpnt->libtype == elf_executable)
1264 break; /* at this point all shared libs are initialized !! */
1266 if (tpnt->init_flag & INIT_FUNCS_CALLED)
1268 tpnt->init_flag |= INIT_FUNCS_CALLED;
1270 if (tpnt->dynamic_info[DT_INIT]) {
1271 _dl_elf_init = (int (*)(void)) (intptr_t) (tpnt->loadaddr + tpnt->dynamic_info[DT_INIT]);
1273 #if defined (__SUPPORT_LD_DEBUG__)
1274 if(_dl_debug) _dl_dprintf(_dl_debug_file,"\ncalling init: %s\n\n", tpnt->libname);
1278 if (_dl_atexit && tpnt->dynamic_info[DT_FINI]) {
1279 (*_dl_atexit) (tpnt->loadaddr + tpnt->dynamic_info[DT_FINI]);
1280 #if defined (__SUPPORT_LD_DEBUG__)
1281 if(_dl_debug && _dl_on_exit)
1283 (*_dl_on_exit)(debug_fini, tpnt->libname);
1287 #if defined (__SUPPORT_LD_DEBUG__)
1290 _dl_dprintf(_dl_debug_file, "%s: The address of atexit () is 0x0.\n", tpnt->libname);
1292 if (!tpnt->dynamic_info[DT_FINI])
1293 _dl_dprintf(_dl_debug_file, "%s: Invalid .fini section.\n", tpnt->libname);
1301 * This stub function is used by some debuggers. The idea is that they
1302 * can set an internal breakpoint on it, so that we are notified when the
1303 * address mapping is changed in some way.
1305 void _dl_debug_state(void)
1309 int _dl_fixup(struct elf_resolve *tpnt)
1314 goof += _dl_fixup(tpnt->next);
1315 #if defined (__SUPPORT_LD_DEBUG__)
1316 if(_dl_debug) _dl_dprintf(_dl_debug_file,"\nrelocation processing: %s", tpnt->libname);
1319 if (tpnt->dynamic_info[DT_REL]) {
1320 #ifdef ELF_USES_RELOCA
1321 _dl_dprintf(2, "%s: can't handle REL relocation records\n",
1325 if (tpnt->init_flag & RELOCS_DONE)
1327 tpnt->init_flag |= RELOCS_DONE;
1328 goof += _dl_parse_relocation_information(tpnt, tpnt->dynamic_info[DT_REL],
1329 tpnt->dynamic_info[DT_RELSZ], 0);
1332 if (tpnt->dynamic_info[DT_RELA]) {
1333 #ifdef ELF_USES_RELOCA
1334 if (tpnt->init_flag & RELOCS_DONE)
1336 tpnt->init_flag |= RELOCS_DONE;
1337 goof += _dl_parse_relocation_information(tpnt, tpnt->dynamic_info[DT_RELA],
1338 tpnt->dynamic_info[DT_RELASZ], 0);
1340 _dl_dprintf(2, "%s: can't handle RELA relocation records\n",
1345 if (tpnt->dynamic_info[DT_JMPREL]) {
1346 if (tpnt->init_flag & JMP_RELOCS_DONE)
1348 tpnt->init_flag |= JMP_RELOCS_DONE;
1349 if (!_dl_not_lazy || *_dl_not_lazy == 0)
1350 _dl_parse_lazy_relocation_information(tpnt, tpnt->dynamic_info[DT_JMPREL],
1351 tpnt->dynamic_info [DT_PLTRELSZ], 0);
1353 goof += _dl_parse_relocation_information(tpnt, tpnt->dynamic_info[DT_JMPREL],
1354 tpnt->dynamic_info[DT_PLTRELSZ], 0);
1356 #if defined (__SUPPORT_LD_DEBUG__)
1358 _dl_dprintf(_dl_debug_file,"\nrelocation processing: %s", tpnt->libname);
1359 _dl_dprintf(_dl_debug_file,"; finished\n\n");
1365 char *_dl_getenv(const char *symbol, char **envp)
1370 while ((pnt = *envp++)) {
1372 while (*pnt && *pnt == *pnt1)
1374 if (!*pnt || *pnt != '=' || *pnt1)
1381 void _dl_unsetenv(const char *symbol, char **envp)
1385 char **newenvp = envp;
1387 for (pnt = *envp; pnt; pnt = *++envp) {
1389 while (*pnt && *pnt == *pnt1)
1391 if (!*pnt || *pnt != '=' || *pnt1)
1399 #include "readelflib1.c"