OSDN Git Service

Rework file naming, aiming for at least a vague level of consistancy
[uclinux-h8/uClibc.git] / ldso / ldso / dl-startup.c
1 /* vi: set sw=4 ts=4: */
2 /*
3  * Program to load an ELF binary on a linux system, and run it
4  * after resolving ELF shared library symbols
5  *
6  * Copyright (C) 2000-2004 by Erik Andersen <andersen@codpoet.org>
7  * Copyright (c) 1994-2000 Eric Youngdale, Peter MacDonald,
8  *                              David Engel, Hongjiu Lu and Mitch D'Souza
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. The name of the above contributors may not be
16  *    used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31
32 /*
33  * The main trick with this program is that initially, we ourselves are not
34  * dynamicly linked.  This means that we cannot access any global variables or
35  * call any functions.  No globals initially, since the Global Offset Table
36  * (GOT) is initialized by the linker assuming a virtual address of 0, and no
37  * function calls initially since the Procedure Linkage Table (PLT) is not yet
38  * initialized.
39  *
40  * There are additional initial restrictions - we cannot use large switch
41  * statements, since the compiler generates tables of addresses and jumps
42  * through them.  We cannot use normal syscall stubs, because these all
43  * reference the errno global variable which is not yet initialized.  We _can_
44  * use all of the local stack variables that we want.  We _can_ use inline
45  * functions, because these do not transfer control to a new address, but they
46  * must be static so that they are not exported from the modules.
47  *
48  * Life is further complicated by the fact that initially we do not want to do
49  * a complete dynamic linking.  We want to allow the user to supply new
50  * functions to override symbols (i.e. weak symbols and/or LD_PRELOAD).  So
51  * initially, we only perform relocations for variables that start with "_dl_"
52  * since ANSI specifies that the user is not supposed to redefine any of these
53  * variables.
54  *
55  * Fortunately, the linker itself leaves a few clues lying around, and when the
56  * kernel starts the image, there are a few further clues.  First of all, there
57  * is Auxiliary Vector Table information sitting on which is provided to us by
58  * the kernel, and which includes information about the load address that the
59  * program interpreter was loaded at, the number of sections, the address the
60  * application was loaded at and so forth.  Here this information is stored in
61  * the array auxvt.  For details see linux/fs/binfmt_elf.c where it calls
62  * NEW_AUX_ENT() a bunch of time....
63  *
64  * Next, we need to find the GOT.  On most arches there is a register pointing
65  * to the GOT, but just in case (and for new ports) I've added some (slow) C
66  * code to locate the GOT for you.
67  *
68  * This code was originally written for SVr4, and there the kernel would load
69  * all text pages R/O, so they needed to call mprotect a zillion times to mark
70  * all text pages as writable so dynamic linking would succeed.  Then when they
71  * were done, they would change the protections for all the pages back again.
72  * Well, under Linux everything is loaded writable (since Linux does copy on
73  * write anyways) so all the mprotect stuff has been disabled.
74  *
75  * Initially, we do not have access to _dl_malloc since we can't yet make
76  * function calls, so we mmap one page to use as scratch space.  Later on, when
77  * we can call _dl_malloc we reuse this this memory.  This is also beneficial,
78  * since we do not want to use the same memory pool as malloc anyway - esp if
79  * the user redefines malloc to do something funky.
80  *
81  * Our first task is to perform a minimal linking so that we can call other
82  * portions of the dynamic linker.  Once we have done this, we then build the
83  * list of modules that the application requires, using LD_LIBRARY_PATH if this
84  * is not a suid program (/usr/lib otherwise).  Once this is done, we can do
85  * the dynamic linking as required, and we must omit the things we did to get
86  * the dynamic linker up and running in the first place.  After we have done
87  * this, we just have a few housekeeping chores and we can transfer control to
88  * the user's application.
89  */
90
91 #include "ldso.h"
92
93 /*  Some arches may need to override this in dl-startup.h */
94 #define ELFMAGIC ELFMAG
95
96 /* This is a poor man's malloc, used prior to resolving our internal poor man's malloc */
97 #define LD_MALLOC(SIZE) ((void *) (malloc_buffer += SIZE, malloc_buffer - SIZE)) ;  REALIGN();
98
99 /* Make sure that the malloc buffer is aligned on 4 byte boundary.  For 64 bit
100  * platforms we may need to increase this to 8, but this is good enough for
101  * now.  This is typically called after LD_MALLOC.  */
102 #define REALIGN() malloc_buffer = (char *) (((unsigned long) malloc_buffer + 3) & ~(3))
103
104 /* Pull in all the arch specific stuff */
105 #include "dl-startup.h"
106
107 /* Static declarations */
108 int (*_dl_elf_main) (int, char **, char **);
109
110
111
112
113 /* When we enter this piece of code, the program stack looks like this:
114         argc            argument counter (integer)
115         argv[0]         program name (pointer)
116         argv[1...N]     program args (pointers)
117         argv[argc-1]    end of args (integer)
118                 NULL
119         env[0...N]      environment variables (pointers)
120         NULL
121                 auxvt[0...N]   Auxiliary Vector Table elements (mixed types)
122 */
123 DL_BOOT(unsigned long args)
124 {
125         unsigned int argc;
126         char **argv, **envp;
127         unsigned long load_addr;
128         unsigned long *got;
129         unsigned long *aux_dat;
130         int goof = 0;
131         ElfW(Ehdr) *header;
132         struct elf_resolve *tpnt;
133         struct elf_resolve *app_tpnt;
134         Elf32_auxv_t auxvt[AT_EGID + 1];
135         unsigned char *malloc_buffer, *mmap_zero;
136         Elf32_Dyn *dpnt;
137         unsigned long *hash_addr;
138         struct r_debug *debug_addr = NULL;
139         int indx;
140 #if defined(__i386__)
141         int status = 0;
142 #endif
143
144
145         /* WARNING! -- we cannot make _any_ funtion calls until we have
146          * taken care of fixing up our own relocations.  Making static
147          * inline calls is ok, but _no_ function calls.  Not yet
148          * anyways. */
149
150         /* First obtain the information on the stack that tells us more about
151            what binary is loaded, where it is loaded, etc, etc */
152         GET_ARGV(aux_dat, args);
153 #if defined (__arm__) || defined (__mips__) || defined (__cris__)
154         aux_dat += 1;
155 #endif
156         argc = *(aux_dat - 1);
157         argv = (char **) aux_dat;
158         aux_dat += argc;                        /* Skip over the argv pointers */
159         aux_dat++;                                      /* Skip over NULL at end of argv */
160         envp = (char **) aux_dat;
161         while (*aux_dat)
162                 aux_dat++;                              /* Skip over the envp pointers */
163         aux_dat++;                                      /* Skip over NULL at end of envp */
164
165         /* Place -1 here as a checkpoint.  We later check if it was changed
166          * when we read in the auxvt */
167         auxvt[AT_UID].a_type = -1;
168
169         /* The junk on the stack immediately following the environment is
170          * the Auxiliary Vector Table.  Read out the elements of the auxvt,
171          * sort and store them in auxvt for later use. */
172         while (*aux_dat) {
173                 Elf32_auxv_t *auxv_entry = (Elf32_auxv_t *) aux_dat;
174
175                 if (auxv_entry->a_type <= AT_EGID) {
176                         _dl_memcpy(&(auxvt[auxv_entry->a_type]), auxv_entry, sizeof(Elf32_auxv_t));
177                 }
178                 aux_dat += 2;
179         }
180
181         /* locate the ELF header.   We need this done as soon as possible
182          * (esp since SEND_STDERR() needs this on some platforms... */
183         load_addr = auxvt[AT_BASE].a_un.a_val;
184         header = (ElfW(Ehdr) *) auxvt[AT_BASE].a_un.a_ptr;
185
186         /* Check the ELF header to make sure everything looks ok.  */
187         if (!header || header->e_ident[EI_CLASS] != ELFCLASS32 ||
188                         header->e_ident[EI_VERSION] != EV_CURRENT
189 #if !defined(__powerpc__) && !defined(__mips__) && !defined(__sh__)
190                         || _dl_strncmp((void *) header, ELFMAGIC, SELFMAG) != 0
191 #else
192                         || header->e_ident[EI_MAG0] != ELFMAG0
193                         || header->e_ident[EI_MAG1] != ELFMAG1
194                         || header->e_ident[EI_MAG2] != ELFMAG2
195                         || header->e_ident[EI_MAG3] != ELFMAG3
196 #endif
197            ) {
198                 SEND_STDERR("Invalid ELF header\n");
199                 _dl_exit(0);
200         }
201 #ifdef __SUPPORT_LD_DEBUG_EARLY__
202         SEND_STDERR("ELF header=");
203         SEND_ADDRESS_STDERR(load_addr, 1);
204 #endif
205
206
207         /* Locate the global offset table.  Since this code must be PIC
208          * we can take advantage of the magic offset register, if we
209          * happen to know what that is for this architecture.  If not,
210          * we can always read stuff out of the ELF file to find it... */
211 #if defined(__i386__)
212         __asm__("\tmovl %%ebx,%0\n\t":"=a"(got));
213 #elif defined(__m68k__)
214         __asm__("movel %%a5,%0":"=g"(got));
215 #elif defined(__sparc__)
216         __asm__("\tmov %%l7,%0\n\t":"=r"(got));
217 #elif defined(__arm__)
218         __asm__("\tmov %0, r10\n\t":"=r"(got));
219 #elif defined(__powerpc__)
220         __asm__("\tbl _GLOBAL_OFFSET_TABLE_-4@local\n\t":"=l"(got));
221 #elif defined(__mips__)
222         __asm__("\tmove %0, $28\n\tsubu %0,%0,0x7ff0\n\t":"=r"(got));
223 #elif defined(__sh__) && !defined(__SH5__)
224         __asm__(
225                         "       mov.l    1f, %0\n"
226                         "       mova     1f, r0\n"
227                         "       bra      2f\n"
228                         "       add r0,  %0\n"
229                         "       .balign  4\n"
230                         "1:     .long    _GLOBAL_OFFSET_TABLE_\n"
231                         "2:" : "=r" (got) : : "r0");
232 #elif defined(__cris__)
233         __asm__("\tmove.d $pc,%0\n\tsub.d .:GOTOFF,%0\n\t":"=r"(got));
234 #else
235         /* Do things the slow way in C */
236         {
237                 unsigned long tx_reloc;
238                 Elf32_Dyn *dynamic = NULL;
239                 Elf32_Shdr *shdr;
240                 Elf32_Phdr *pt_load;
241
242 #ifdef __SUPPORT_LD_DEBUG_EARLY__
243                 SEND_STDERR("Finding the GOT using C code to read the ELF file\n");
244 #endif
245                 /* Find where the dynamic linking information section is hiding */
246                 shdr = (Elf32_Shdr *) (header->e_shoff + (char *) header);
247                 for (indx = header->e_shnum; --indx >= 0; ++shdr) {
248                         if (shdr->sh_type == SHT_DYNAMIC) {
249                                 goto found_dynamic;
250                         }
251                 }
252                 SEND_STDERR("missing dynamic linking information section \n");
253                 _dl_exit(0);
254
255 found_dynamic:
256                 dynamic = (Elf32_Dyn *) (shdr->sh_offset + (char *) header);
257
258                 /* Find where PT_LOAD is hiding */
259                 pt_load = (Elf32_Phdr *) (header->e_phoff + (char *) header);
260                 for (indx = header->e_phnum; --indx >= 0; ++pt_load) {
261                         if (pt_load->p_type == PT_LOAD) {
262                                 goto found_pt_load;
263                         }
264                 }
265                 SEND_STDERR("missing loadable program segment\n");
266                 _dl_exit(0);
267
268 found_pt_load:
269                 /* Now (finally) find where DT_PLTGOT is hiding */
270                 tx_reloc = pt_load->p_vaddr - pt_load->p_offset;
271                 for (; DT_NULL != dynamic->d_tag; ++dynamic) {
272                         if (dynamic->d_tag == DT_PLTGOT) {
273                                 goto found_got;
274                         }
275                 }
276                 SEND_STDERR("missing global offset table\n");
277                 _dl_exit(0);
278
279 found_got:
280                 got = (unsigned long *) (dynamic->d_un.d_val - tx_reloc +
281                                 (char *) header);
282         }
283 #endif
284
285         /* Now, finally, fix up the location of the dynamic stuff */
286         dpnt = (Elf32_Dyn *) (*got + load_addr);
287 #ifdef __SUPPORT_LD_DEBUG_EARLY__
288         SEND_STDERR("First Dynamic section entry=");
289         SEND_ADDRESS_STDERR(dpnt, 1);
290 #endif
291
292
293         /* Call mmap to get a page of writable memory that can be used
294          * for _dl_malloc throughout the shared lib loader. */
295         mmap_zero = malloc_buffer = _dl_mmap((void *) 0, PAGE_SIZE,
296                         PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
297         if (_dl_mmap_check_error(mmap_zero)) {
298                 SEND_STDERR("dl_boot: mmap of a spare page failed!\n");
299                 _dl_exit(13);
300         }
301
302         tpnt = LD_MALLOC(sizeof(struct elf_resolve));
303         _dl_memset(tpnt, 0, sizeof(struct elf_resolve));
304         app_tpnt = LD_MALLOC(sizeof(struct elf_resolve));
305         _dl_memset(app_tpnt, 0, sizeof(struct elf_resolve));
306
307 #ifdef __UCLIBC_PIE_SUPPORT__
308         /* Find the runtime load address of the main executable, this may be
309          * different from what the ELF header says for ET_DYN/PIE executables.
310          */
311         {
312                 ElfW(Phdr) *ppnt;
313                 int i;
314
315                 ppnt = (ElfW(Phdr) *) auxvt[AT_PHDR].a_un.a_ptr;
316                 for (i = 0; i < auxvt[AT_PHNUM].a_un.a_val; i++, ppnt++)
317                         if (ppnt->p_type == PT_PHDR) {
318                                 app_tpnt->loadaddr = (ElfW(Addr)) (auxvt[AT_PHDR].a_un.a_val - ppnt->p_vaddr);
319                                 break;
320                         }
321         }
322
323 #ifdef __SUPPORT_LD_DEBUG_EARLY__
324         SEND_STDERR("app_tpnt->loadaddr=");
325         SEND_ADDRESS_STDERR(app_tpnt->loadaddr, 1);
326 #endif
327 #endif
328
329         /*
330          * This is used by gdb to locate the chain of shared libraries that are currently loaded.
331          */
332         debug_addr = LD_MALLOC(sizeof(struct r_debug));
333         _dl_memset(debug_addr, 0, sizeof(struct r_debug));
334
335         /* OK, that was easy.  Next scan the DYNAMIC section of the image.
336            We are only doing ourself right now - we will have to do the rest later */
337 #ifdef __SUPPORT_LD_DEBUG_EARLY__
338         SEND_STDERR("scanning DYNAMIC section\n");
339 #endif
340         while (dpnt->d_tag) {
341 #if defined(__mips__)
342                 if (dpnt->d_tag == DT_MIPS_GOTSYM)
343                         tpnt->mips_gotsym = (unsigned long) dpnt->d_un.d_val;
344                 if (dpnt->d_tag == DT_MIPS_LOCAL_GOTNO)
345                         tpnt->mips_local_gotno = (unsigned long) dpnt->d_un.d_val;
346                 if (dpnt->d_tag == DT_MIPS_SYMTABNO)
347                         tpnt->mips_symtabno = (unsigned long) dpnt->d_un.d_val;
348 #endif
349                 if (dpnt->d_tag < 24) {
350                         tpnt->dynamic_info[dpnt->d_tag] = dpnt->d_un.d_val;
351                         if (dpnt->d_tag == DT_TEXTREL) {
352                                 tpnt->dynamic_info[DT_TEXTREL] = 1;
353                         }
354                 }
355                 dpnt++;
356         }
357
358         {
359                 ElfW(Phdr) *ppnt;
360                 int i;
361
362                 ppnt = (ElfW(Phdr) *) auxvt[AT_PHDR].a_un.a_ptr;
363                 for (i = 0; i < auxvt[AT_PHNUM].a_un.a_val; i++, ppnt++)
364                         if (ppnt->p_type == PT_DYNAMIC) {
365 #ifndef __UCLIBC_PIE_SUPPORT__
366                                 dpnt = (Elf32_Dyn *) ppnt->p_vaddr;
367 #else
368                                 dpnt = (Elf32_Dyn *) (ppnt->p_vaddr + app_tpnt->loadaddr);
369 #endif
370                                 while (dpnt->d_tag) {
371 #if defined(__mips__)
372                                         if (dpnt->d_tag == DT_MIPS_GOTSYM)
373                                                 app_tpnt->mips_gotsym =
374                                                         (unsigned long) dpnt->d_un.d_val;
375                                         if (dpnt->d_tag == DT_MIPS_LOCAL_GOTNO)
376                                                 app_tpnt->mips_local_gotno =
377                                                         (unsigned long) dpnt->d_un.d_val;
378                                         if (dpnt->d_tag == DT_MIPS_SYMTABNO)
379                                                 app_tpnt->mips_symtabno =
380                                                         (unsigned long) dpnt->d_un.d_val;
381                                         if (dpnt->d_tag > DT_JMPREL) {
382                                                 dpnt++;
383                                                 continue;
384                                         }
385                                         app_tpnt->dynamic_info[dpnt->d_tag] = dpnt->d_un.d_val;
386
387 #warning "Debugging threads on mips won't work till someone fixes this..."
388 #if 0
389                                         if (dpnt->d_tag == DT_DEBUG) {
390                                                 dpnt->d_un.d_val = (unsigned long) debug_addr;
391                                         }
392 #endif
393
394 #else
395                                         if (dpnt->d_tag > DT_JMPREL) {
396                                                 dpnt++;
397                                                 continue;
398                                         }
399                                         app_tpnt->dynamic_info[dpnt->d_tag] = dpnt->d_un.d_val;
400                                         if (dpnt->d_tag == DT_DEBUG) {
401                                                 dpnt->d_un.d_val = (unsigned long) debug_addr;
402                                         }
403 #endif
404                                         if (dpnt->d_tag == DT_TEXTREL)
405                                                 app_tpnt->dynamic_info[DT_TEXTREL] = 1;
406                                         dpnt++;
407                                 }
408                         }
409         }
410
411 #ifdef __SUPPORT_LD_DEBUG_EARLY__
412         SEND_STDERR("done scanning DYNAMIC section\n");
413 #endif
414
415         /* Get some more of the information that we will need to dynamicly link
416            this module to itself */
417
418         hash_addr = (unsigned long *) (tpnt->dynamic_info[DT_HASH] + load_addr);
419         tpnt->nbucket = *hash_addr++;
420         tpnt->nchain = *hash_addr++;
421         tpnt->elf_buckets = hash_addr;
422         hash_addr += tpnt->nbucket;
423
424 #ifdef __SUPPORT_LD_DEBUG_EARLY__
425         SEND_STDERR("done grabbing link information\n");
426 #endif
427
428 #ifndef FORCE_SHAREABLE_TEXT_SEGMENTS
429         /* Ugly, ugly.  We need to call mprotect to change the protection of
430            the text pages so that we can do the dynamic linking.  We can set the
431            protection back again once we are done */
432
433         {
434                 ElfW(Phdr) *ppnt;
435                 int i;
436
437 #ifdef __SUPPORT_LD_DEBUG_EARLY__
438                 SEND_STDERR("calling mprotect on the shared library/dynamic linker\n");
439 #endif
440
441                 /* First cover the shared library/dynamic linker. */
442                 if (tpnt->dynamic_info[DT_TEXTREL]) {
443                         header = (ElfW(Ehdr) *) auxvt[AT_BASE].a_un.a_ptr;
444                         ppnt = (ElfW(Phdr) *) ((int)auxvt[AT_BASE].a_un.a_ptr +
445                                         header->e_phoff);
446                         for (i = 0; i < header->e_phnum; i++, ppnt++) {
447                                 if (ppnt->p_type == PT_LOAD && !(ppnt->p_flags & PF_W)) {
448                                         _dl_mprotect((void *) (load_addr + (ppnt->p_vaddr & PAGE_ALIGN)),
449                                                         (ppnt->p_vaddr & ADDR_ALIGN) + (unsigned long) ppnt->p_filesz,
450                                                         PROT_READ | PROT_WRITE | PROT_EXEC);
451                                 }
452                         }
453                 }
454
455 #ifdef __SUPPORT_LD_DEBUG_EARLY__
456                 SEND_STDERR("calling mprotect on the application program\n");
457 #endif
458                 /* Now cover the application program. */
459                 if (app_tpnt->dynamic_info[DT_TEXTREL]) {
460                         ppnt = (ElfW(Phdr) *) auxvt[AT_PHDR].a_un.a_ptr;
461                         for (i = 0; i < auxvt[AT_PHNUM].a_un.a_val; i++, ppnt++) {
462                                 if (ppnt->p_type == PT_LOAD && !(ppnt->p_flags & PF_W))
463 #ifndef __UCLIBC_PIE_SUPPORT__
464                                         _dl_mprotect((void *) (ppnt->p_vaddr & PAGE_ALIGN),
465                                                         (ppnt->p_vaddr & ADDR_ALIGN) +
466                                                         (unsigned long) ppnt->p_filesz,
467                                                         PROT_READ | PROT_WRITE | PROT_EXEC);
468 #else
469                                 _dl_mprotect((void *) ((ppnt->p_vaddr + app_tpnt->loadaddr) & PAGE_ALIGN),
470                                                 ((ppnt->p_vaddr + app_tpnt->loadaddr) & ADDR_ALIGN) +
471                                                 (unsigned long) ppnt->p_filesz,
472                                                 PROT_READ | PROT_WRITE | PROT_EXEC);
473 #endif
474                         }
475                 }
476         }
477 #endif
478
479 #if defined(__mips__)
480 #ifdef __SUPPORT_LD_DEBUG_EARLY__
481         SEND_STDERR("About to do MIPS specific GOT bootstrap\n");
482 #endif
483         /* For MIPS we have to do stuff to the GOT before we do relocations.  */
484         PERFORM_BOOTSTRAP_GOT(got);
485 #endif
486
487         /* OK, now do the relocations.  We do not do a lazy binding here, so
488            that once we are done, we have considerably more flexibility. */
489 #ifdef __SUPPORT_LD_DEBUG_EARLY__
490         SEND_STDERR("About to do library loader relocations\n");
491 #endif
492
493         goof = 0;
494         for (indx = 0; indx < 2; indx++) {
495                 unsigned int i;
496                 ELF_RELOC *rpnt;
497                 unsigned long *reloc_addr;
498                 unsigned long symbol_addr;
499                 int symtab_index;
500                 unsigned long rel_addr, rel_size;
501
502
503                 rel_addr = (indx ? tpnt->dynamic_info[DT_JMPREL] : tpnt->
504                                 dynamic_info[DT_RELOC_TABLE_ADDR]);
505                 rel_size = (indx ? tpnt->dynamic_info[DT_PLTRELSZ] : tpnt->
506                                 dynamic_info[DT_RELOC_TABLE_SIZE]);
507
508                 if (!rel_addr)
509                         continue;
510
511                 /* Now parse the relocation information */
512                 rpnt = (ELF_RELOC *) (rel_addr + load_addr);
513                 for (i = 0; i < rel_size; i += sizeof(ELF_RELOC), rpnt++) {
514                         reloc_addr = (unsigned long *) (load_addr + (unsigned long) rpnt->r_offset);
515                         symtab_index = ELF32_R_SYM(rpnt->r_info);
516                         symbol_addr = 0;
517                         if (symtab_index) {
518                                 char *strtab;
519                                 char *symname;
520                                 Elf32_Sym *symtab;
521
522                                 symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + load_addr);
523                                 strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + load_addr);
524                                 symname = strtab + symtab[symtab_index].st_name;
525
526                                 /* We only do a partial dynamic linking right now.  The user
527                                    is not supposed to define any symbols that start with a
528                                    '_dl', so we can do this with confidence. */
529                                 if (!symname || symname[0] != '_' ||
530                                                 symname[1] != 'd' || symname[2] != 'l' || symname[3] != '_')
531                                 {
532                                         continue;
533                                 }
534                                 symbol_addr = load_addr + symtab[symtab_index].st_value;
535
536                                 if (!symbol_addr) {
537                                         /* This will segfault - you cannot call a function until
538                                          * we have finished the relocations.
539                                          */
540                                         SEND_STDERR("ELF dynamic loader - unable to self-bootstrap - symbol ");
541                                         SEND_STDERR(symname);
542                                         SEND_STDERR(" undefined.\n");
543                                         goof++;
544                                 }
545 #ifdef __SUPPORT_LD_DEBUG_EARLY__
546                                 SEND_STDERR("relocating symbol: ");
547                                 SEND_STDERR(symname);
548                                 SEND_STDERR("\n");
549 #endif
550                                 PERFORM_BOOTSTRAP_RELOC(rpnt, reloc_addr, symbol_addr, load_addr, &symtab[symtab_index]);
551                         } else {
552                                 /* Use this machine-specific macro to perform the actual relocation.  */
553                                 PERFORM_BOOTSTRAP_RELOC(rpnt, reloc_addr, symbol_addr, load_addr, NULL);
554                         }
555                 }
556         }
557
558         if (goof) {
559                 _dl_exit(14);
560         }
561
562 #ifdef __SUPPORT_LD_DEBUG_EARLY__
563         /* Wahoo!!! */
564         SEND_STDERR("Done relocating library loader, so we can now\n"
565                         "\tuse globals and make function calls!\n");
566 #endif
567
568         /* Now we have done the mandatory linking of some things.  We are now
569            free to start using global variables, since these things have all been
570            fixed up by now.  Still no function calls outside of this library ,
571            since the dynamic resolver is not yet ready. */
572         _dl_get_ready_to_run(tpnt, app_tpnt, load_addr, hash_addr,
573                         auxvt, envp, debug_addr, malloc_buffer, mmap_zero, argv);
574
575
576         /* Transfer control to the application.  */
577 #ifdef __SUPPORT_LD_DEBUG_EARLY__
578         SEND_STDERR("transfering control to application\n");
579 #endif
580         _dl_elf_main = (int (*)(int, char **, char **)) auxvt[AT_ENTRY].a_un.a_fcn;
581         START();
582 }
583