OSDN Git Service

Modify interfaces for _dl_parse_relocation_information()
[uclinux-h8/uClibc.git] / ldso / ldso / dl-elf.c
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
4  *
5  * Copyright (c) 1994-2000 Eric Youngdale, Peter MacDonald, 
6  *                              David Engel, Hongjiu Lu and Mitch D'Souza
7  * Copyright (C) 2001-2003, Erik Andersen
8  *
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
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.
19  *
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
30  * SUCH DAMAGE.
31  */
32
33
34 /* This file contains the helper routines to load an ELF sharable
35    library into memory and add the symbol table info to the chain. */
36
37 #ifdef USE_CACHE
38
39 static caddr_t _dl_cache_addr = NULL;
40 static size_t _dl_cache_size = 0;
41
42 int _dl_map_cache(void)
43 {
44         int fd;
45         struct stat st;
46         header_t *header;
47         libentry_t *libent;
48         int i, strtabsize;
49
50         if (_dl_cache_addr == (caddr_t) - 1)
51                 return -1;
52         else if (_dl_cache_addr != NULL)
53                 return 0;
54
55         if (_dl_stat(LDSO_CACHE, &st)
56                 || (fd = _dl_open(LDSO_CACHE, O_RDONLY)) < 0) {
57                 _dl_dprintf(2, "%s: can't open cache '%s'\n", _dl_progname, LDSO_CACHE);
58                 _dl_cache_addr = (caddr_t) - 1; /* so we won't try again */
59                 return -1;
60         }
61
62         _dl_cache_size = st.st_size;
63         _dl_cache_addr = (caddr_t) _dl_mmap(0, _dl_cache_size, PROT_READ, MAP_SHARED, fd, 0);
64         _dl_close(fd);
65         if (_dl_mmap_check_error(_dl_cache_addr)) {
66                 _dl_dprintf(2, "%s: can't map cache '%s'\n", 
67                         _dl_progname, LDSO_CACHE);
68                 return -1;
69         }
70
71         header = (header_t *) _dl_cache_addr;
72
73         if (_dl_cache_size < sizeof(header_t) ||
74                 _dl_memcmp(header->magic, LDSO_CACHE_MAGIC, LDSO_CACHE_MAGIC_LEN)
75                 || _dl_memcmp(header->version, LDSO_CACHE_VER, LDSO_CACHE_VER_LEN)
76                 || _dl_cache_size <
77                 (sizeof(header_t) + header->nlibs * sizeof(libentry_t))
78                 || _dl_cache_addr[_dl_cache_size - 1] != '\0') 
79         {
80                 _dl_dprintf(2, "%s: cache '%s' is corrupt\n", _dl_progname, 
81                         LDSO_CACHE);
82                 goto fail;
83         }
84
85         strtabsize = _dl_cache_size - sizeof(header_t) -
86                 header->nlibs * sizeof(libentry_t);
87         libent = (libentry_t *) & header[1];
88
89         for (i = 0; i < header->nlibs; i++) {
90                 if (libent[i].sooffset >= strtabsize || 
91                         libent[i].liboffset >= strtabsize) 
92                 {
93                         _dl_dprintf(2, "%s: cache '%s' is corrupt\n", _dl_progname, LDSO_CACHE);
94                         goto fail;
95                 }
96         }
97
98         return 0;
99
100   fail:
101         _dl_munmap(_dl_cache_addr, _dl_cache_size);
102         _dl_cache_addr = (caddr_t) - 1;
103         return -1;
104 }
105
106 int _dl_unmap_cache(void)
107 {
108         if (_dl_cache_addr == NULL || _dl_cache_addr == (caddr_t) - 1)
109                 return -1;
110
111 #if 1
112         _dl_munmap(_dl_cache_addr, _dl_cache_size);
113         _dl_cache_addr = NULL;
114 #endif
115
116         return 0;
117 }
118
119 #endif
120
121 /* This function's behavior must exactly match that 
122  * in uClibc/ldso/util/ldd.c */
123 static struct elf_resolve * 
124 search_for_named_library(const char *name, int secure, const char *path_list,
125         struct dyn_elf **rpnt)
126 {
127         int i, count = 1;
128         char *path, *path_n;
129         char mylibname[2050];
130         struct elf_resolve *tpnt1;
131         
132         if (path_list==NULL)
133                 return NULL;
134
135         /* We need a writable copy of this string */
136         path = _dl_strdup(path_list);
137         if (!path) {
138                 _dl_dprintf(2, "Out of memory!\n");
139                 _dl_exit(0);
140         }
141         
142
143         /* Unlike ldd.c, don't bother to eliminate double //s */
144
145
146         /* Replace colons with zeros in path_list and count them */
147         for(i=_dl_strlen(path); i > 0; i--) {
148                 if (path[i]==':') {
149                         path[i]=0;
150                         count++;
151                 }
152         }
153
154         path_n = path;
155         for (i = 0; i < count; i++) {
156                 _dl_strcpy(mylibname, path_n); 
157                 _dl_strcat(mylibname, "/"); 
158                 _dl_strcat(mylibname, name);
159                 if ((tpnt1 = _dl_load_elf_shared_library(secure, rpnt, mylibname)) != NULL)
160                 {
161                         return tpnt1;
162                 }
163                 path_n += (_dl_strlen(path_n) + 1);
164         }
165         return NULL;
166 }
167
168 /* Check if the named library is already loaded... */
169 struct elf_resolve *_dl_check_if_named_library_is_loaded(const char *full_libname)
170 {
171         const char *pnt, *pnt1;
172         struct elf_resolve *tpnt1;
173         const char *libname, *libname2;
174         static const char *libc = "libc.so.";
175         static const char *aborted_wrong_lib = "%s: aborted attempt to load %s!\n";
176
177         pnt = libname = full_libname;
178
179 #if defined (__SUPPORT_LD_DEBUG__)
180         if(_dl_debug) 
181                 _dl_dprintf(_dl_debug_file, "Checking if '%s' is already loaded\n", full_libname);
182 #endif
183         /* quick hack to ensure mylibname buffer doesn't overflow.  don't 
184            allow full_libname or any directory to be longer than 1024. */
185         if (_dl_strlen(full_libname) > 1024)
186                 return NULL;
187
188         /* Skip over any initial initial './' and '/' stuff to 
189          * get the short form libname with no path garbage */ 
190         pnt1 = _dl_strrchr(pnt, '/');
191         if (pnt1) {
192                 libname = pnt1 + 1;
193         }
194
195         /* Make sure they are not trying to load the wrong C library!
196          * This sometimes happens esp with shared libraries when the
197          * library path is somehow wrong! */
198 #define isdigit(c)  (c >= '0' && c <= '9')
199         if ((_dl_strncmp(libname, libc, 8) == 0) &&  _dl_strlen(libname) >=8 &&
200                         isdigit(libname[8]))
201         {
202                 /* Abort attempts to load glibc, libc5, etc */
203                 if ( libname[8]!='0') {
204                         if (!_dl_trace_loaded_objects) {
205                                 _dl_dprintf(2, aborted_wrong_lib, libname, _dl_progname);
206                                 _dl_exit(1);
207                         }
208                         return NULL;
209                 }
210         }
211
212         /* Critical step!  Weed out duplicates early to avoid
213          * function aliasing, which wastes memory, and causes
214          * really bad things to happen with weaks and globals. */
215         for (tpnt1 = _dl_loaded_modules; tpnt1; tpnt1 = tpnt1->next) {
216
217                 /* Skip over any initial initial './' and '/' stuff to 
218                  * get the short form libname with no path garbage */ 
219                 libname2 = tpnt1->libname;
220                 pnt1 = _dl_strrchr(libname2, '/');
221                 if (pnt1) {
222                         libname2 = pnt1 + 1;
223                 }
224
225                 if (_dl_strcmp(libname2, libname) == 0) {
226                         /* Well, that was certainly easy */
227                         return tpnt1;
228                 }
229         }
230
231         return NULL;
232 }
233         
234
235
236 /*
237  * Used to return error codes back to dlopen et. al.
238  */
239
240 unsigned long _dl_error_number;
241 unsigned long _dl_internal_error_number;
242 extern char *_dl_ldsopath;
243
244 struct elf_resolve *_dl_load_shared_library(int secure, struct dyn_elf **rpnt,
245         struct elf_resolve *tpnt, char *full_libname)
246 {
247         char *pnt, *pnt1;
248         struct elf_resolve *tpnt1;
249         char *libname;
250
251         _dl_internal_error_number = 0;
252         libname = full_libname;
253
254         /* quick hack to ensure mylibname buffer doesn't overflow.  don't 
255            allow full_libname or any directory to be longer than 1024. */
256         if (_dl_strlen(full_libname) > 1024)
257                 goto goof;
258
259         /* Skip over any initial initial './' and '/' stuff to 
260          * get the short form libname with no path garbage */ 
261         pnt1 = _dl_strrchr(libname, '/');
262         if (pnt1) {
263                 libname = pnt1 + 1;
264         }
265
266         /* Critical step!  Weed out duplicates early to avoid
267          * function aliasing, which wastes memory, and causes
268          * really bad things to happen with weaks and globals. */
269         if ((tpnt1=_dl_check_if_named_library_is_loaded(libname))!=NULL)
270                 return tpnt1;
271
272 #if defined (__SUPPORT_LD_DEBUG__)
273         if(_dl_debug) _dl_dprintf(_dl_debug_file, "\tfind library='%s'; searching\n", libname);
274 #endif
275         /* If the filename has any '/', try it straight and leave it at that.
276            For IBCS2 compatibility under linux, we substitute the string 
277            /usr/i486-sysv4/lib for /usr/lib in library names. */
278
279         if (libname != full_libname) {
280 #if defined (__SUPPORT_LD_DEBUG__)
281                 if(_dl_debug) _dl_dprintf(_dl_debug_file, "\ttrying file='%s'\n", full_libname);
282 #endif
283                 tpnt1 = _dl_load_elf_shared_library(secure, rpnt, full_libname);
284                 if (tpnt1) {
285                         return tpnt1;
286                 }
287                 //goto goof;
288         }
289
290         /*
291          * The ABI specifies that RPATH is searched before LD_*_PATH or
292          * the default path of /usr/lib.  Check in rpath directories.
293          */
294         for (tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next) {
295                 if (tpnt->libtype == elf_executable) {
296                         pnt = (char *) tpnt->dynamic_info[DT_RPATH];
297                         if (pnt) {
298                                 pnt += (unsigned long) tpnt->loadaddr + tpnt->dynamic_info[DT_STRTAB];
299 #if defined (__SUPPORT_LD_DEBUG__)
300                                 if(_dl_debug) _dl_dprintf(_dl_debug_file, "\tsearching RPATH='%s'\n", pnt);
301 #endif
302                                 if ((tpnt1 = search_for_named_library(libname, secure, pnt, rpnt)) != NULL) 
303                                 {
304                                     return tpnt1;
305                                 }
306                         }
307                 }
308         }
309
310         /* Check in LD_{ELF_}LIBRARY_PATH, if specified and allowed */
311         if (_dl_library_path) {
312 #if defined (__SUPPORT_LD_DEBUG__)
313                 if(_dl_debug) _dl_dprintf(_dl_debug_file, "\tsearching LD_LIBRARY_PATH='%s'\n", _dl_library_path);
314 #endif
315             if ((tpnt1 = search_for_named_library(libname, secure, _dl_library_path, rpnt)) != NULL) 
316             {
317                 return tpnt1;
318             }
319         }
320
321         /*
322          * Where should the cache be searched?  There is no such concept in the
323          * ABI, so we have some flexibility here.  For now, search it before
324          * the hard coded paths that follow (i.e before /lib and /usr/lib).
325          */
326 #ifdef USE_CACHE
327         if (_dl_cache_addr != NULL && _dl_cache_addr != (caddr_t) - 1) {
328                 int i;
329                 header_t *header = (header_t *) _dl_cache_addr;
330                 libentry_t *libent = (libentry_t *) & header[1];
331                 char *strs = (char *) &libent[header->nlibs];
332
333 #if defined (__SUPPORT_LD_DEBUG__)
334                 if(_dl_debug) _dl_dprintf(_dl_debug_file, "\tsearching cache='%s'\n", LDSO_CACHE);
335 #endif
336                 for (i = 0; i < header->nlibs; i++) {
337                         if ((libent[i].flags == LIB_ELF ||
338                                  libent[i].flags == LIB_ELF_LIBC5) &&
339                                 _dl_strcmp(libname, strs + libent[i].sooffset) == 0 &&
340                                 (tpnt1 = _dl_load_elf_shared_library(secure, 
341                                      rpnt, strs + libent[i].liboffset)))
342                                 return tpnt1;
343                 }
344         }
345 #endif
346
347         /* Look for libraries wherever the shared library loader
348          * was installed */
349 #if defined (__SUPPORT_LD_DEBUG__)
350                 if(_dl_debug) _dl_dprintf(_dl_debug_file, "\tsearching ldso dir='%s'\n", _dl_ldsopath);
351 #endif
352         if ((tpnt1 = search_for_named_library(libname, secure, _dl_ldsopath, rpnt)) != NULL) 
353         {
354             return tpnt1;
355         }
356
357
358         /* Lastly, search the standard list of paths for the library.
359            This list must exactly match the list in uClibc/ldso/util/ldd.c */
360 #if defined (__SUPPORT_LD_DEBUG__)
361         if(_dl_debug) _dl_dprintf(_dl_debug_file, "\tsearching full lib path list\n");
362 #endif
363         if ((tpnt1 = search_for_named_library(libname, secure, 
364                         UCLIBC_RUNTIME_PREFIX "usr/X11R6/lib:"
365                         UCLIBC_RUNTIME_PREFIX "usr/lib:"
366                         UCLIBC_RUNTIME_PREFIX "lib:"
367                         "/usr/lib:"
368                         "/lib", rpnt)
369                     ) != NULL) 
370         {
371             return tpnt1;
372         }
373
374 goof:
375         /* Well, we shot our wad on that one.  All we can do now is punt */
376         if (_dl_internal_error_number)
377                 _dl_error_number = _dl_internal_error_number;
378         else
379                 _dl_error_number = LD_ERROR_NOFILE;
380 #if defined (__SUPPORT_LD_DEBUG__)
381         if(_dl_debug) _dl_dprintf(2, "Bummer: could not find '%s'!\n", libname);
382 #endif
383         return NULL;
384 }
385
386
387 /*
388  * Read one ELF library into memory, mmap it into the correct locations and
389  * add the symbol info to the symbol chain.  Perform any relocations that
390  * are required.
391  */
392
393 struct elf_resolve *_dl_load_elf_shared_library(int secure,
394         struct dyn_elf **rpnt, char *libname)
395 {
396         ElfW(Ehdr) *epnt;
397         unsigned long dynamic_addr = 0;
398         unsigned long dynamic_size = 0;
399         Elf32_Dyn *dpnt;
400         struct elf_resolve *tpnt;
401         ElfW(Phdr) *ppnt;
402         char *status, *header;
403         unsigned long dynamic_info[24];
404         unsigned long *lpnt;
405         unsigned long libaddr;
406         unsigned long minvma = 0xffffffff, maxvma = 0;
407         int i, flags, piclib, infile;
408
409         /* If this file is already loaded, skip this step */
410         tpnt = _dl_check_hashed_files(libname);
411         if (tpnt) {
412                 if (*rpnt) {
413                         (*rpnt)->next = (struct dyn_elf *) _dl_malloc(sizeof(struct dyn_elf));
414                         _dl_memset((*rpnt)->next, 0, sizeof(struct dyn_elf));
415                         (*rpnt)->next->prev = (*rpnt);
416                         *rpnt = (*rpnt)->next;
417                         (*rpnt)->dyn = tpnt;
418                         tpnt->symbol_scope = _dl_symbol_tables;
419                 }
420                 tpnt->usage_count++;
421                 tpnt->libtype = elf_lib;
422 #if defined (__SUPPORT_LD_DEBUG__)
423                 if(_dl_debug) _dl_dprintf(2, "file='%s';  already loaded\n", libname);
424 #endif
425                 return tpnt;
426         }
427
428         /* If we are in secure mode (i.e. a setu/gid binary using LD_PRELOAD),
429            we don't load the library if it isn't setuid. */
430
431         if (secure) {
432                 struct stat st;
433
434                 if (_dl_stat(libname, &st) || !(st.st_mode & S_ISUID))
435                         return NULL;
436         }
437
438         libaddr = 0;
439         infile = _dl_open(libname, O_RDONLY);
440         if (infile < 0) {
441 #if 0
442                 /*
443                  * NO!  When we open shared libraries we may search several paths.
444                  * it is inappropriate to generate an error here.
445                  */
446                 _dl_dprintf(2, "%s: can't open '%s'\n", _dl_progname, libname);
447 #endif
448                 _dl_internal_error_number = LD_ERROR_NOFILE;
449                 return NULL;
450         }
451
452          header = _dl_mmap((void *) 0, PAGE_SIZE, PROT_READ | PROT_WRITE,
453                 MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
454         if (_dl_mmap_check_error(header)) {
455                 _dl_dprintf(2, "%s: can't map '%s'\n", _dl_progname, libname);
456                 _dl_internal_error_number = LD_ERROR_MMAP_FAILED;
457                 _dl_close(infile);
458                 return NULL;
459         };
460         
461         _dl_read(infile, header, PAGE_SIZE);
462         epnt = (ElfW(Ehdr) *) (intptr_t) header;
463         if (epnt->e_ident[0] != 0x7f ||
464                 epnt->e_ident[1] != 'E' || 
465                 epnt->e_ident[2] != 'L' || 
466                 epnt->e_ident[3] != 'F') 
467         {
468                 _dl_dprintf(2, "%s: '%s' is not an ELF file\n", _dl_progname,
469                                          libname);
470                 _dl_internal_error_number = LD_ERROR_NOTELF;
471                 _dl_close(infile);
472                 _dl_munmap(header, PAGE_SIZE);
473                 return NULL;
474         };
475
476         if ((epnt->e_type != ET_DYN) || (epnt->e_machine != MAGIC1 
477 #ifdef MAGIC2
478                     && epnt->e_machine != MAGIC2
479 #endif
480                 )) 
481         {
482                 _dl_internal_error_number = 
483                     (epnt->e_type != ET_DYN ? LD_ERROR_NOTDYN : LD_ERROR_NOTMAGIC);
484                 _dl_dprintf(2, "%s: '%s' is not an ELF executable for " ELF_TARGET 
485                         "\n", _dl_progname, libname);
486                 _dl_close(infile);
487                 _dl_munmap(header, PAGE_SIZE);
488                 return NULL;
489         };
490
491         ppnt = (ElfW(Phdr) *)(intptr_t) & header[epnt->e_phoff];
492
493         piclib = 1;
494         for (i = 0; i < epnt->e_phnum; i++) {
495
496                 if (ppnt->p_type == PT_DYNAMIC) {
497                         if (dynamic_addr)
498                                 _dl_dprintf(2, "%s: '%s' has more than one dynamic section\n", 
499                                         _dl_progname, libname);
500                         dynamic_addr = ppnt->p_vaddr;
501                         dynamic_size = ppnt->p_filesz;
502                 };
503
504                 if (ppnt->p_type == PT_LOAD) {
505                         /* See if this is a PIC library. */
506                         if (i == 0 && ppnt->p_vaddr > 0x1000000) {
507                                 piclib = 0;
508                                 minvma = ppnt->p_vaddr;
509                         }
510                         if (piclib && ppnt->p_vaddr < minvma) {
511                                 minvma = ppnt->p_vaddr;
512                         }
513                         if (((unsigned long) ppnt->p_vaddr + ppnt->p_memsz) > maxvma) {
514                                 maxvma = ppnt->p_vaddr + ppnt->p_memsz;
515                         }
516                 }
517                 ppnt++;
518         };
519
520         maxvma = (maxvma + ADDR_ALIGN) & ~ADDR_ALIGN;
521         minvma = minvma & ~0xffffU;
522
523         flags = MAP_PRIVATE /*| MAP_DENYWRITE */ ;
524         if (!piclib)
525                 flags |= MAP_FIXED;
526
527         status = (char *) _dl_mmap((char *) (piclib ? 0 : minvma), 
528                 maxvma - minvma, PROT_NONE, flags | MAP_ANONYMOUS, -1, 0);
529         if (_dl_mmap_check_error(status)) {
530                 _dl_dprintf(2, "%s: can't map %s\n", _dl_progname, libname);
531                 _dl_internal_error_number = LD_ERROR_MMAP_FAILED;
532                 _dl_close(infile);
533                 _dl_munmap(header, PAGE_SIZE);
534                 return NULL;
535         };
536         libaddr = (unsigned long) status;
537         flags |= MAP_FIXED;
538
539         /* Get the memory to store the library */
540         ppnt = (ElfW(Phdr) *)(intptr_t) & header[epnt->e_phoff];
541
542         for (i = 0; i < epnt->e_phnum; i++) {
543                 if (ppnt->p_type == PT_LOAD) {
544
545                         /* See if this is a PIC library. */
546                         if (i == 0 && ppnt->p_vaddr > 0x1000000) {
547                                 piclib = 0;
548                                 /* flags |= MAP_FIXED; */
549                         }
550
551
552
553                         if (ppnt->p_flags & PF_W) {
554                                 unsigned long map_size;
555                                 char *cpnt;
556
557                                 status = (char *) _dl_mmap((char *) ((piclib ? libaddr : 0) + 
558                                         (ppnt->p_vaddr & PAGE_ALIGN)), (ppnt->p_vaddr & ADDR_ALIGN) 
559                                         + ppnt->p_filesz, LXFLAGS(ppnt->p_flags), flags, infile, 
560                                         ppnt->p_offset & OFFS_ALIGN);
561
562                                 if (_dl_mmap_check_error(status)) {
563                                         _dl_dprintf(2, "%s: can't map '%s'\n", 
564                                                 _dl_progname, libname);
565                                         _dl_internal_error_number = LD_ERROR_MMAP_FAILED;
566                                         _dl_munmap((char *) libaddr, maxvma - minvma);
567                                         _dl_close(infile);
568                                         _dl_munmap(header, PAGE_SIZE);
569                                         return NULL;
570                                 };
571
572                                 /* Pad the last page with zeroes. */
573                                 cpnt = (char *) (status + (ppnt->p_vaddr & ADDR_ALIGN) +
574                                                           ppnt->p_filesz);
575                                 while (((unsigned long) cpnt) & ADDR_ALIGN)
576                                         *cpnt++ = 0;
577
578                                 /* I am not quite sure if this is completely
579                                  * correct to do or not, but the basic way that
580                                  * we handle bss segments is that we mmap
581                                  * /dev/zero if there are any pages left over
582                                  * that are not mapped as part of the file */
583
584                                 map_size = (ppnt->p_vaddr + ppnt->p_filesz + ADDR_ALIGN) & PAGE_ALIGN;
585
586                                 if (map_size < ppnt->p_vaddr + ppnt->p_memsz)
587                                         status = (char *) _dl_mmap((char *) map_size + 
588                                                 (piclib ? libaddr : 0), 
589                                                 ppnt->p_vaddr + ppnt->p_memsz - map_size, 
590                                                 LXFLAGS(ppnt->p_flags), flags | MAP_ANONYMOUS, -1, 0);
591                         } else
592                                 status = (char *) _dl_mmap((char *) (ppnt->p_vaddr & PAGE_ALIGN) 
593                                         + (piclib ? libaddr : 0), (ppnt->p_vaddr & ADDR_ALIGN) + 
594                                         ppnt->p_filesz, LXFLAGS(ppnt->p_flags), flags, 
595                                         infile, ppnt->p_offset & OFFS_ALIGN);
596                         if (_dl_mmap_check_error(status)) {
597                                 _dl_dprintf(2, "%s: can't map '%s'\n", _dl_progname, libname);
598                                 _dl_internal_error_number = LD_ERROR_MMAP_FAILED;
599                                 _dl_munmap((char *) libaddr, maxvma - minvma);
600                                 _dl_close(infile);
601                                 _dl_munmap(header, PAGE_SIZE);
602                                 return NULL;
603                         };
604
605                         /* if(libaddr == 0 && piclib) {
606                            libaddr = (unsigned long) status;
607                            flags |= MAP_FIXED;
608                            }; */
609                 };
610                 ppnt++;
611         };
612         _dl_close(infile);
613
614         /* For a non-PIC library, the addresses are all absolute */
615         if (piclib) {
616                 dynamic_addr += (unsigned long) libaddr;
617         }
618
619         /* 
620          * OK, the ELF library is now loaded into VM in the correct locations
621          * The next step is to go through and do the dynamic linking (if needed).
622          */
623
624         /* Start by scanning the dynamic section to get all of the pointers */
625
626         if (!dynamic_addr) {
627                 _dl_internal_error_number = LD_ERROR_NODYNAMIC;
628                 _dl_dprintf(2, "%s: '%s' is missing a dynamic section\n", 
629                         _dl_progname, libname);
630                         _dl_munmap(header, PAGE_SIZE);
631                 return NULL;
632         }
633
634         dpnt = (Elf32_Dyn *) dynamic_addr;
635
636         dynamic_size = dynamic_size / sizeof(Elf32_Dyn);
637         _dl_memset(dynamic_info, 0, sizeof(dynamic_info));
638
639 #if defined(__mips__)
640         {
641                 
642                 int indx = 1;
643                 Elf32_Dyn *dpnt = (Elf32_Dyn *) dynamic_addr;
644
645                 while(dpnt->d_tag) {
646                         dpnt++;
647                         indx++;
648                 }
649                 dynamic_size = indx;
650         }
651 #endif
652
653         {
654                 unsigned long indx;
655
656                 for (indx = 0; indx < dynamic_size; indx++) 
657                 {
658                         if (dpnt->d_tag > DT_JMPREL) {
659                                 dpnt++;
660                                 continue;
661                         }
662                         dynamic_info[dpnt->d_tag] = dpnt->d_un.d_val;
663                         if (dpnt->d_tag == DT_TEXTREL)
664                                 dynamic_info[DT_TEXTREL] = 1;
665                         dpnt++;
666                 };
667         }
668
669         /* If the TEXTREL is set, this means that we need to make the pages
670            writable before we perform relocations.  Do this now. They get set
671            back again later. */
672
673         if (dynamic_info[DT_TEXTREL]) {
674 #ifndef FORCE_SHAREABLE_TEXT_SEGMENTS
675                 ppnt = (ElfW(Phdr) *)(intptr_t) & header[epnt->e_phoff];
676                 for (i = 0; i < epnt->e_phnum; i++, ppnt++) {
677                         if (ppnt->p_type == PT_LOAD && !(ppnt->p_flags & PF_W))
678                                 _dl_mprotect((void *) ((piclib ? libaddr : 0) + 
679                                             (ppnt->p_vaddr & PAGE_ALIGN)), 
680                                         (ppnt->p_vaddr & ADDR_ALIGN) + (unsigned long) ppnt->p_filesz, 
681                                         PROT_READ | PROT_WRITE | PROT_EXEC);
682                 }
683 #else
684                 _dl_dprintf(_dl_debug_file, "Can't modify %s's text section. Use GCC option -fPIC for shared objects, please.\n",libname);
685                 _dl_exit(1);
686 #endif          
687         }
688
689         tpnt = _dl_add_elf_hash_table(libname, (char *) libaddr, dynamic_info, 
690                 dynamic_addr, dynamic_size);
691
692         tpnt->ppnt = (ElfW(Phdr) *)(intptr_t) (tpnt->loadaddr + epnt->e_phoff);
693         tpnt->n_phent = epnt->e_phnum;
694
695         /*
696          * Add this object into the symbol chain
697          */
698         if (*rpnt) {
699                 (*rpnt)->next = (struct dyn_elf *) _dl_malloc(sizeof(struct dyn_elf));
700                 _dl_memset((*rpnt)->next, 0, sizeof(struct dyn_elf));
701                 (*rpnt)->next->prev = (*rpnt);
702                 *rpnt = (*rpnt)->next;
703                 (*rpnt)->dyn = tpnt;
704                 tpnt->symbol_scope = _dl_symbol_tables;
705         }
706         tpnt->usage_count++;
707         tpnt->libtype = elf_lib;
708
709         /*
710          * OK, the next thing we need to do is to insert the dynamic linker into
711          * the proper entry in the GOT so that the PLT symbols can be properly
712          * resolved. 
713          */
714
715         lpnt = (unsigned long *) dynamic_info[DT_PLTGOT];
716
717         if (lpnt) {
718                 lpnt = (unsigned long *) (dynamic_info[DT_PLTGOT] +
719                         ((int) libaddr));
720                 INIT_GOT(lpnt, tpnt);
721         };
722
723 #if defined (__SUPPORT_LD_DEBUG__)
724         if(_dl_debug) {
725                 _dl_dprintf(2, "\n\tfile='%s';  generating link map\n", libname);
726                 _dl_dprintf(2, "\t\tdynamic: %x  base: %x   size: %x\n", 
727                                 dynamic_addr, libaddr, dynamic_size);
728                 _dl_dprintf(2, "\t\t  entry: %x  phdr: %x  phnum: %d\n\n", 
729                                 epnt->e_entry + libaddr, tpnt->ppnt, tpnt->n_phent);
730
731         }
732 #endif
733         _dl_munmap(header, PAGE_SIZE);
734
735         return tpnt;
736 }
737
738 /* Minimal printf which handles only %s, %d, and %x */
739 void _dl_dprintf(int fd, const char *fmt, ...)
740 {
741         int num;
742         va_list args;
743         char *start, *ptr, *string;
744         static char *buf;
745
746         buf = _dl_mmap((void *) 0, PAGE_SIZE, PROT_READ | PROT_WRITE,
747                 MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
748         if (_dl_mmap_check_error(buf)) {
749                         _dl_write(fd, "mmap of a spare page failed!\n", 29); 
750                         _dl_exit(20);
751         }
752
753         start = ptr = buf;
754
755         if (!fmt)
756                 return;
757
758         if (_dl_strlen(fmt) >= (PAGE_SIZE - 1)) {
759                 _dl_write(fd, "overflow\n", 11);
760                 _dl_exit(20);
761         }
762
763         _dl_strcpy(buf, fmt);
764         va_start(args, fmt);
765
766         while (start) {
767                 while (*ptr != '%' && *ptr) {
768                         ptr++;
769                 }
770
771                 if (*ptr == '%') {
772                         *ptr++ = '\0';
773                         _dl_write(fd, start, _dl_strlen(start));
774
775                         switch (*ptr++) {
776                         case 's':
777                                 string = va_arg(args, char *);
778
779                                 if (!string)
780                                         _dl_write(fd, "(null)", 6);
781                                 else
782                                         _dl_write(fd, string, _dl_strlen(string));
783                                 break;
784
785                         case 'i':
786                         case 'd':
787                         {
788                                 char tmp[22];
789                                 num = va_arg(args, int);
790
791                                 string = _dl_simple_ltoa(tmp, num);
792                                 _dl_write(fd, string, _dl_strlen(string));
793                                 break;
794                         }
795                         case 'x':
796                         case 'X':
797                         {
798                                 char tmp[22];
799                                 num = va_arg(args, int);
800
801                                 string = _dl_simple_ltoahex(tmp, num);
802                                 _dl_write(fd, string, _dl_strlen(string));
803                                 break;
804                         }
805                         default:
806                                 _dl_write(fd, "(null)", 6);
807                                 break;
808                         }
809
810                         start = ptr;
811                 } else {
812                         _dl_write(fd, start, _dl_strlen(start));
813                         start = NULL;
814                 }
815         }
816         _dl_munmap(buf, PAGE_SIZE);
817         return;
818 }
819
820 char *_dl_strdup(const char *string)
821 {
822         char *retval;
823         int len;
824
825         len = _dl_strlen(string);
826         retval = _dl_malloc(len + 1);
827         _dl_strcpy(retval, string);
828         return retval;
829 }
830
831 void *(*_dl_malloc_function) (size_t size) = NULL;
832 void *_dl_malloc(int size)
833 {
834         void *retval;
835
836 #if 0
837 #ifdef __SUPPORT_LD_DEBUG_EARLY__
838         _dl_dprintf(2, "malloc: request for %d bytes\n", size);
839 #endif
840 #endif
841
842         if (_dl_malloc_function)
843                 return (*_dl_malloc_function) (size);
844
845         if (_dl_malloc_addr - _dl_mmap_zero + size > PAGE_SIZE) {
846 #ifdef __SUPPORT_LD_DEBUG_EARLY__
847                 _dl_dprintf(2, "malloc: mmapping more memory\n");
848 #endif
849                 _dl_mmap_zero = _dl_malloc_addr = _dl_mmap((void *) 0, size, 
850                                 PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
851                 if (_dl_mmap_check_error(_dl_mmap_zero)) {
852                         _dl_dprintf(2, "%s: mmap of a spare page failed!\n", _dl_progname);
853                         _dl_exit(20);
854                 }
855         }
856         retval = _dl_malloc_addr;
857         _dl_malloc_addr += size;
858
859         /*
860          * Align memory to 4 byte boundary.  Some platforms require this, others
861          * simply get better performance.
862          */
863         _dl_malloc_addr = (char *) (((unsigned long) _dl_malloc_addr + 3) & ~(3));
864         return retval;
865 }
866
867 int _dl_fixup(struct dyn_elf *rpnt, int flag)
868 {
869         int goof = 0;
870         struct elf_resolve *tpnt;
871
872         if (rpnt->next)
873                 goof += _dl_fixup(rpnt->next, flag);
874         tpnt = rpnt->dyn;
875
876 #if defined (__SUPPORT_LD_DEBUG__)
877         if(_dl_debug) _dl_dprintf(_dl_debug_file,"\nrelocation processing: %s", tpnt->libname);
878 #endif
879
880         if (unlikely(tpnt->dynamic_info[UNSUPPORTED_RELOC_TYPE])) {
881 #if defined (__SUPPORT_LD_DEBUG__)
882                 if(_dl_debug) {
883                         _dl_dprintf(2, "%s: can't handle %s relocation records\n",
884                                         _dl_progname, UNSUPPORTED_RELOC_STR);
885                 }
886 #endif
887                 goof++;
888                 return goof;
889         }
890
891         if (tpnt->dynamic_info[DT_RELOC_TABLE_ADDR]) {
892                 if (tpnt->init_flag & RELOCS_DONE)
893                         return goof;
894                 tpnt->init_flag |= RELOCS_DONE;
895                 goof += _dl_parse_relocation_information(rpnt,
896                                 tpnt->dynamic_info[DT_RELOC_TABLE_ADDR],
897                                 tpnt->dynamic_info[DT_RELOC_TABLE_SIZE], 0);
898         }
899
900         if (tpnt->dynamic_info[DT_JMPREL]) {
901                 if (tpnt->init_flag & JMP_RELOCS_DONE)
902                         return goof;
903                 tpnt->init_flag |= JMP_RELOCS_DONE;
904                 if (flag & RTLD_LAZY) {
905                         _dl_parse_lazy_relocation_information(rpnt,
906                                         tpnt->dynamic_info[DT_JMPREL],
907                                         tpnt->dynamic_info [DT_PLTRELSZ], 0);
908                 } else {
909                         goof += _dl_parse_relocation_information(rpnt,
910                                         tpnt->dynamic_info[DT_JMPREL],
911                                         tpnt->dynamic_info[DT_PLTRELSZ], 0);
912                 }
913         }
914
915         if (tpnt->init_flag & COPY_RELOCS_DONE)
916                 return goof;
917         tpnt->init_flag |= COPY_RELOCS_DONE;
918         goof += _dl_parse_copy_information(rpnt,
919                 tpnt->dynamic_info[DT_RELOC_TABLE_ADDR],
920                 tpnt->dynamic_info[DT_RELOC_TABLE_SIZE], 0);
921
922 #if defined (__SUPPORT_LD_DEBUG__)
923         if(_dl_debug) {
924                 _dl_dprintf(_dl_debug_file,"\nrelocation processing: %s", tpnt->libname);
925                 _dl_dprintf(_dl_debug_file,"; finished\n\n");
926         }
927 #endif
928
929         return goof;
930 }
931