OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [uClibc/] [ldso/] [ldso/] [readelflib1.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1325 phoenix
/* 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
/* Ugly, ugly.  Some versions of the SVr4 linker fail to generate COPY
739
   relocations for global variables that are present both in the image and
740
   the shared library.  Go through and do it manually.  If the images
741
   are guaranteed to be generated by a trustworthy linker, then this
742
   step can be skipped. */
743
 
744
int _dl_copy_fixups(struct dyn_elf *rpnt)
745
{
746
        int goof = 0;
747
        struct elf_resolve *tpnt;
748
 
749
        if (rpnt->next)
750
                goof += _dl_copy_fixups(rpnt->next);
751
        else
752
                return 0;
753
 
754
        tpnt = rpnt->dyn;
755
 
756
        if (tpnt->init_flag & COPY_RELOCS_DONE)
757
                return goof;
758
        tpnt->init_flag |= COPY_RELOCS_DONE;
759
 
760
#if defined (__SUPPORT_LD_DEBUG__)
761
        if(_dl_debug) _dl_dprintf(_dl_debug_file,"\nrelocation copy fixups: %s", tpnt->libname);
762
#endif    
763
 
764
#ifdef ELF_USES_RELOCA
765
        goof += _dl_parse_copy_information(rpnt,
766
                tpnt->dynamic_info[DT_RELA], tpnt->dynamic_info[DT_RELASZ], 0);
767
 
768
#else
769
        goof += _dl_parse_copy_information(rpnt, tpnt->dynamic_info[DT_REL],
770
                tpnt->dynamic_info[DT_RELSZ], 0);
771
 
772
#endif
773
#if defined (__SUPPORT_LD_DEBUG__)
774
        if(_dl_debug) _dl_dprintf(_dl_debug_file,"\nrelocation copy fixups: %s; finished\n\n", tpnt->libname);
775
#endif    
776
        return goof;
777
}
778
 
779
/* Minimal printf which handles only %s, %d, and %x */
780
void _dl_dprintf(int fd, const char *fmt, ...)
781
{
782
        int num;
783
        va_list args;
784
        char *start, *ptr, *string;
785
        static char *buf;
786
 
787
        buf = _dl_mmap((void *) 0, PAGE_SIZE, PROT_READ | PROT_WRITE,
788
                MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
789
        if (_dl_mmap_check_error(buf)) {
790
                        _dl_write(fd, "mmap of a spare page failed!\n", 29);
791
                        _dl_exit(20);
792
        }
793
 
794
        start = ptr = buf;
795
 
796
        if (!fmt)
797
                return;
798
 
799
        if (_dl_strlen(fmt) >= (PAGE_SIZE - 1)) {
800
                _dl_write(fd, "overflow\n", 11);
801
                _dl_exit(20);
802
        }
803
 
804
        _dl_strcpy(buf, fmt);
805
        va_start(args, fmt);
806
 
807
        while (start) {
808
                while (*ptr != '%' && *ptr) {
809
                        ptr++;
810
                }
811
 
812
                if (*ptr == '%') {
813
                        *ptr++ = '\0';
814
                        _dl_write(fd, start, _dl_strlen(start));
815
 
816
                        switch (*ptr++) {
817
                        case 's':
818
                                string = va_arg(args, char *);
819
 
820
                                if (!string)
821
                                        _dl_write(fd, "(null)", 6);
822
                                else
823
                                        _dl_write(fd, string, _dl_strlen(string));
824
                                break;
825
 
826
                        case 'i':
827
                        case 'd':
828
                        {
829
                                char tmp[22];
830
                                num = va_arg(args, int);
831
 
832
                                string = _dl_simple_ltoa(tmp, num);
833
                                _dl_write(fd, string, _dl_strlen(string));
834
                                break;
835
                        }
836
                        case 'x':
837
                        case 'X':
838
                        {
839
                                char tmp[22];
840
                                num = va_arg(args, int);
841
 
842
                                string = _dl_simple_ltoahex(tmp, num);
843
                                _dl_write(fd, string, _dl_strlen(string));
844
                                break;
845
                        }
846
                        default:
847
                                _dl_write(fd, "(null)", 6);
848
                                break;
849
                        }
850
 
851
                        start = ptr;
852
                } else {
853
                        _dl_write(fd, start, _dl_strlen(start));
854
                        start = NULL;
855
                }
856
        }
857
        _dl_munmap(buf, PAGE_SIZE);
858
        return;
859
}
860
 
861
char *_dl_strdup(const char *string)
862
{
863
        char *retval;
864
        int len;
865
 
866
        len = _dl_strlen(string);
867
        retval = _dl_malloc(len + 1);
868
        _dl_strcpy(retval, string);
869
        return retval;
870
}
871
 
872
void *(*_dl_malloc_function) (size_t size) = NULL;
873
void *_dl_malloc(int size)
874
{
875
        void *retval;
876
 
877
#if 0
878
#ifdef __SUPPORT_LD_DEBUG_EARLY__
879
        _dl_dprintf(2, "malloc: request for %d bytes\n", size);
880
#endif
881
#endif
882
 
883
        if (_dl_malloc_function)
884
                return (*_dl_malloc_function) (size);
885
 
886
        if (_dl_malloc_addr - _dl_mmap_zero + size > PAGE_SIZE) {
887
#ifdef __SUPPORT_LD_DEBUG_EARLY__
888
                _dl_dprintf(2, "malloc: mmapping more memory\n");
889
#endif
890
                _dl_mmap_zero = _dl_malloc_addr = _dl_mmap((void *) 0, size,
891
                                PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
892
                if (_dl_mmap_check_error(_dl_mmap_zero)) {
893
                        _dl_dprintf(2, "%s: mmap of a spare page failed!\n", _dl_progname);
894
                        _dl_exit(20);
895
                }
896
        }
897
        retval = _dl_malloc_addr;
898
        _dl_malloc_addr += size;
899
 
900
        /*
901
         * Align memory to 4 byte boundary.  Some platforms require this, others
902
         * simply get better performance.
903
         */
904
        _dl_malloc_addr = (char *) (((unsigned long) _dl_malloc_addr + 3) & ~(3));
905
        return retval;
906
}
907
 
908
int _dl_fixup(struct elf_resolve *tpnt, int flag)
909
{
910
        int goof = 0;
911
 
912
        if (tpnt->next)
913
                goof += _dl_fixup(tpnt->next, flag);
914
#if defined (__SUPPORT_LD_DEBUG__)
915
        if(_dl_debug) _dl_dprintf(_dl_debug_file,"\nrelocation processing: %s", tpnt->libname);
916
#endif    
917
 
918
        if (tpnt->dynamic_info[DT_REL]) {
919
#ifdef ELF_USES_RELOCA
920
#if defined (__SUPPORT_LD_DEBUG__)
921
                if(_dl_debug) _dl_dprintf(2, "%s: can't handle REL relocation records\n", _dl_progname);
922
#endif    
923
                goof++;
924
                return goof;
925
#else
926
                if (tpnt->init_flag & RELOCS_DONE)
927
                        return goof;
928
                tpnt->init_flag |= RELOCS_DONE;
929
                goof += _dl_parse_relocation_information(tpnt,
930
                                tpnt->dynamic_info[DT_REL],
931
                                tpnt->dynamic_info[DT_RELSZ], 0);
932
#endif
933
        }
934
        if (tpnt->dynamic_info[DT_RELA]) {
935
#ifndef ELF_USES_RELOCA
936
#if defined (__SUPPORT_LD_DEBUG__)
937
                if(_dl_debug) _dl_dprintf(2, "%s: can't handle RELA relocation records\n", _dl_progname);
938
#endif    
939
                goof++;
940
                return goof;
941
#else
942
                if (tpnt->init_flag & RELOCS_DONE)
943
                        return goof;
944
                tpnt->init_flag |= RELOCS_DONE;
945
                goof += _dl_parse_relocation_information(tpnt,
946
                                tpnt->dynamic_info[DT_RELA],
947
                                tpnt->dynamic_info[DT_RELASZ], 0);
948
#endif
949
        }
950
        if (tpnt->dynamic_info[DT_JMPREL]) {
951
                if (tpnt->init_flag & JMP_RELOCS_DONE)
952
                        return goof;
953
                tpnt->init_flag |= JMP_RELOCS_DONE;
954
                if (flag & RTLD_LAZY) {
955
                        _dl_parse_lazy_relocation_information(tpnt,
956
                                        tpnt->dynamic_info[DT_JMPREL],
957
                                        tpnt->dynamic_info [DT_PLTRELSZ], 0);
958
                } else {
959
                        goof += _dl_parse_relocation_information(tpnt,
960
                                        tpnt->dynamic_info[DT_JMPREL],
961
                                        tpnt->dynamic_info[DT_PLTRELSZ], 0);
962
                }
963
        }
964
#if defined (__SUPPORT_LD_DEBUG__)
965
        if(_dl_debug) {
966
                _dl_dprintf(_dl_debug_file,"\nrelocation processing: %s", tpnt->libname);
967
                _dl_dprintf(_dl_debug_file,"; finished\n\n");
968
        }
969
#endif    
970
        return goof;
971
}
972
 
973
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.