OSDN Git Service

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