Second attempt to integrate Paul K's changes.
[unix-history] / gnu / usr.bin / ld / rtld / rtld.c
CommitLineData
1136f72d
PR
1/*
2 * Copyright (c) 1993 Paul Kranenburg
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by Paul Kranenburg.
16 * 4. The name of the author may not be used to endorse or promote products
17 * derived from this software withough specific prior written permission
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 *
a9817baa 30 * $Id: rtld.c,v 1.4 1993/11/22 19:05:27 jkh Exp $
1136f72d
PR
31 */
32
b6458905 33#include <machine/vmparam.h>
1136f72d
PR
34#include <sys/param.h>
35#include <stdio.h>
36#include <stdlib.h>
37#include <sys/types.h>
38#include <sys/stat.h>
39#include <sys/file.h>
40#include <sys/time.h>
41#include <sys/resource.h>
42#include <sys/mman.h>
43#ifndef BSD
44#define MAP_COPY MAP_PRIVATE
45#define MAP_FILE 0
46#define MAP_ANON 0
47#endif
48#include <fcntl.h>
49#include <a.out.h>
50#include <stab.h>
51#include <string.h>
52#if __STDC__
53#include <stdarg.h>
54#else
55#include <varargs.h>
56#endif
57
58#include "ld.h"
59
60#ifndef BSD /* Need do better than this */
61#define NEED_DEV_ZERO 1
62#endif
63
64/*
65 * Loader private data, hung off link_map->lm_lpd
66 */
67struct lm_private {
68 int lpd_version;
69 struct link_map *lpd_parent;
70#ifdef SUN_COMPAT
71 long lpd_offset; /* Correction for Sun main programs */
72#endif
73};
74
75#ifdef SUN_COMPAT
76#define LM_OFFSET(lmp) (((struct lm_private *)((lmp)->lm_lpd))->lpd_offset)
77#else
78#define LM_OFFSET(lmp) (0)
79#endif
80
81/* Base address for link_dynamic_2 entries */
82#define LM_LDBASE(lmp) (lmp->lm_addr + LM_OFFSET(lmp))
83
84/* Start of text segment */
85#define LM_TXTADDR(lmp) (lmp->lm_addr == (caddr_t)0 ? PAGSIZ : 0)
86
87/* Start of run-time relocation_info */
88#define LM_REL(lmp) ((struct relocation_info *) \
89 (lmp->lm_addr + LM_OFFSET(lmp) + LD_REL((lmp)->lm_ld)))
90
91/* Start of symbols */
92#define LM_SYMBOL(lmp, i) ((struct nzlist *) \
93 (lmp->lm_addr + LM_OFFSET(lmp) + LD_SYMBOL((lmp)->lm_ld) + \
94 i * (LD_VERSION_NZLIST_P(lmp->lm_ld->ld_version) ? \
95 sizeof(struct nzlist) : sizeof(struct nlist))))
96
97/* Start of hash table */
98#define LM_HASH(lmp) ((struct rrs_hash *) \
99 (lmp->lm_addr + LM_OFFSET(lmp) + LD_HASH((lmp)->lm_ld)))
100
101/* Start of strings */
102#define LM_STRINGS(lmp) ((char *) \
103 (lmp->lm_addr + LM_OFFSET(lmp) + LD_STRINGS((lmp)->lm_ld)))
104
105/* End of text */
106#define LM_ETEXT(lmp) ((char *) \
107 (lmp->lm_addr + LM_TXTADDR(lmp) + LD_TEXTSZ((lmp)->lm_ld)))
108
109/* PLT is in data segment, so don't use LM_OFFSET here */
110#define LM_PLT(lmp) ((jmpslot_t *) \
111 (lmp->lm_addr + LD_PLT((lmp)->lm_ld)))
112
113/* Parent of link map */
114#define LM_PARENT(lmp) (((struct lm_private *)((lmp)->lm_lpd))->lpd_parent)
115
116char **environ;
117int errno;
118uid_t uid, euid;
119gid_t gid, egid;
120int careful;
121
122struct link_map *link_map_head, *main_map;
123struct link_map **link_map_tail = &link_map_head;
124struct rt_symbol *rt_symbol_head;
125
126static int dlopen(), dlclose(), dlsym();
127
128static struct ld_entry ld_entry = {
129 dlopen, dlclose, dlsym
130};
131
132static void xprintf __P((char *, ...));
133static void init_brk __P((void));
134static void load_maps __P((struct crt_ldso *));
135static void map_object __P((struct link_object *, struct link_map *));
136static void alloc_link_map __P(( char *, struct link_object *,
137 struct link_map *, caddr_t,
138 struct link_dynamic *));
139static void check_text_reloc __P(( struct relocation_info *,
140 struct link_map *,
141 caddr_t));
142static void reloc_maps __P((void));
143static void reloc_copy __P((void));
144static char *rtfindlib __P((char *, int, int, int *));
145void binder_entry __P((void));
146long binder __P((jmpslot_t *));
80f25b52 147static struct nzlist *lookup __P((char *, struct link_map **, int));
1136f72d
PR
148static struct rt_symbol *lookup_rts __P((char *));
149static struct rt_symbol *enter_rts __P((char *, long, int, caddr_t, long));
150
151#include "md-static-funcs.c"
152
153/*
154 * Called from assembler stub that has set up crtp (passed from crt0)
155 * and dp (our __DYNAMIC).
156 */
157void
158rtld(version, crtp, dp)
159int version;
160struct crt_ldso *crtp;
161struct link_dynamic *dp;
162{
163 int n;
164 int nreloc; /* # of ld.so relocations */
165 struct relocation_info *reloc;
166 char **envp;
80f25b52 167 struct ld_debug *ldp;
1136f72d
PR
168
169 /* Check version */
170 if (version != CRT_VERSION_BSD && version != CRT_VERSION_SUN)
171 return;
172
173 /* Fixup __DYNAMIC structure */
174 (long)dp->ld_un.ld_2 += crtp->crt_ba;
175
176 /* Be careful not to use .div routine from library */
177 for ( nreloc = 0, n = LD_RELSZ(dp);
178 n > 0;
179 n -= sizeof(struct relocation_info) ) nreloc++;
180
181
182 /* Relocate ourselves */
183 for ( reloc = (struct relocation_info *)
184 (dp->ld_un.ld_2->ld_rel + crtp->crt_ba);
185 nreloc;
186 nreloc--, reloc++) {
187
188 register long addr = reloc->r_address + crtp->crt_ba;
189
190 md_relocate_simple(reloc, crtp->crt_ba, addr);
191 }
192
193 progname = "ld.so";
194
195 /* Setup out (private) environ variable */
196 environ = crtp->crt_ep;
197
198 /* Get user and group identifiers */
199 uid = getuid(); euid = geteuid();
200 gid = getgid(); egid = getegid();
201
202 careful = (uid != euid) || (gid != egid);
203
204 if (careful) {
205 unsetenv("LD_LIBRARY_PATH");
206 unsetenv("LD_PRELOAD");
207 unsetenv("LD_RUN_PATH"); /* In case we ever implement this */
208 }
209
210 /* Setup directory search */
211 std_search_dirs(getenv("LD_LIBRARY_PATH"));
212
213 /* Load required objects into the process address space */
214 load_maps(crtp);
215
216 /* Relocate all loaded objects according to their RRS segments */
217 reloc_maps();
218 reloc_copy();
219
220 /* Fill in some field in main's __DYNAMIC structure */
221 crtp->crt_dp->ld_entry = &ld_entry;
80f25b52
JH
222
223 ldp = crtp->crt_dp->ldd;
224 ldp->ldd_cp = rt_symbol_head;
225 if (ldp->ldd_in_debugger) {
226 caddr_t addr = (caddr_t)((long)crtp->crt_bp & (~(PAGSIZ - 1)));
227
228 /* Set breakpoint for the benefit of debuggers */
229 if (mprotect(addr, PAGSIZ,
230 PROT_READ|PROT_WRITE|PROT_EXEC) == -1) {
231 perror("mprotect"),
232 fatal("Cannot set breakpoint\n");
233 }
234 md_set_breakpoint(crtp->crt_bp, &ldp->ldd_bp_inst);
235 if (mprotect(addr, PAGSIZ, PROT_READ|PROT_EXEC) == -1) {
236 perror("mprotect");
237 }
238
239 ldp->ldd_bp_addr = crtp->crt_bp;
240 if (link_map_head)
241 ldp->ldd_sym_loaded = 1;
242 }
27b6ced7
JH
243
244 /* Close our file descriptor */
245 (void)close(crtp->crt_ldfd);
1136f72d
PR
246}
247
248
249static void
250load_maps(crtp)
251struct crt_ldso *crtp;
252{
253 struct link_map *lmp;
254 int tracing = (int)getenv("LD_TRACE_LOADED_OBJECTS");
255
256 /* Handle LD_PRELOAD's here */
257
258 /* Make an entry for the main program */
259 alloc_link_map("main", (struct link_object *)0, (struct link_map *)0,
260 (caddr_t)0, crtp->crt_dp);
261
262 for (lmp = link_map_head; lmp; lmp = lmp->lm_next) {
263 struct link_object *lop;
264 long next = 0;
265
266 if (lmp->lm_ld)
267 next = LD_NEED(lmp->lm_ld);
268
269 while (next) {
270 lop = (struct link_object *) (LM_LDBASE(lmp) + next);
271 map_object(lop, lmp);
272 next = lop->lo_next;
273 }
274 }
275
276 if (! tracing)
277 return;
278
279 for (lmp = link_map_head; lmp; lmp = lmp->lm_next) {
280 struct link_object *lop;
281 char *name, *path;
282
283 if ((lop = lmp->lm_lop) == NULL)
284 continue;
285
286 name = lop->lo_name + LM_LDBASE(LM_PARENT(lmp));
287
288 if ((path = lmp->lm_name) == NULL)
289 path = "not found";
290
291 if (lop->lo_library)
80f25b52
JH
292 printf("\t-l%s.%d => %s (%#x)\n", name,
293 lop->lo_major, path, lmp->lm_addr);
1136f72d 294 else
80f25b52 295 printf("\t%s => %s (%#x)\n", name, path, lmp->lm_addr);
1136f72d
PR
296 }
297
298 _exit(0);
299}
300
301/*
302 * Allocate a new link map for an shared object NAME loaded at ADDR as a
303 * result of the presence of link object LOP in the link map PARENT.
304 */
305static void
306alloc_link_map(name, lop, parent, addr, dp)
307char *name;
308struct link_map *parent;
309struct link_object *lop;
310caddr_t addr;
311struct link_dynamic *dp;
312{
313 struct link_map *lmp;
314 struct lm_private *lmpp;
315
316 lmpp = (struct lm_private *)xmalloc(sizeof(struct lm_private));
317 lmp = (struct link_map *)xmalloc(sizeof(struct link_map));
318 lmp->lm_next = NULL;
319 *link_map_tail = lmp;
320 link_map_tail = &lmp->lm_next;
321
322 lmp->lm_addr = addr;
323 lmp->lm_name = name;
324 lmp->lm_lop = lop;
325 lmp->lm_ld = dp;
326 lmp->lm_lpd = (caddr_t)lmpp;
327
328/*XXX*/ if (addr == 0) main_map = lmp;
329
330 lmpp->lpd_parent = parent;
331
332#ifdef SUN_COMPAT
333 lmpp->lpd_offset =
334 (addr == 0 && dp->ld_version == LD_VERSION_SUN) ? PAGSIZ : 0;
335#endif
336}
337
338/*
339 * Map object identified by link object LOP which was found
340 * in link map LMP.
341 */
342static void
343map_object(lop, lmp)
344struct link_object *lop;
345struct link_map *lmp;
346{
347 struct link_dynamic *dp;
348 char *path, *name = (char *)(lop->lo_name + LM_LDBASE(lmp));
349 int fd;
350 caddr_t addr;
351 struct exec hdr;
352 int usehints = 0;
353
354 if (lop->lo_library) {
355 usehints = 1;
356again:
357 path = rtfindlib(name, lop->lo_major, lop->lo_minor, &usehints);
358 if (path == NULL)
359 fatal("Cannot find lib%s.so.%d.%d\n",
360 name, lop->lo_major, lop->lo_minor);
361 } else {
362 path = name;
363 }
364
365 fd = open(path, O_RDONLY, 0);
366 if (fd == -1) {
367 if (usehints) {
368 usehints = 0;
369 goto again;
370 }
371 fatal("%s not found", path);
372 }
373
374 if (read(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) {
375 fatal("%s: Cannot read exec header", path);
376 }
377
378 if (N_BADMAG(hdr))
379 fatal("%s: Incorrect format", path);
380
381 if ((addr = mmap(0, hdr.a_text + hdr.a_data,
382 PROT_READ|PROT_EXEC,
383 MAP_FILE|MAP_COPY, fd, 0)) == (caddr_t)-1)
384 fatal("Cannot map %s text\n", path);
385
386 if (mmap(addr + hdr.a_text, hdr.a_data,
387 PROT_READ|PROT_WRITE|PROT_EXEC,
388 MAP_FILE|MAP_FIXED|MAP_COPY,
389 fd, hdr.a_text) == (caddr_t)-1)
390 fatal("Cannot map %s data", path);
391
392 close(fd);
393
394 fd = -1;
395#ifdef NEED_DEV_ZERO
396 if ((fd = open("/dev/zero", O_RDWR, 0)) == -1)
397 perror("/dev/zero");
398#endif
399 if (hdr.a_bss && mmap(addr + hdr.a_text + hdr.a_data, hdr.a_bss,
400 PROT_READ|PROT_WRITE|PROT_EXEC,
401 MAP_ANON|MAP_FIXED|MAP_COPY,
402 fd, hdr.a_text + hdr.a_data) == (caddr_t)-1)
403 fatal("Cannot map %s bss", path);
404
405#ifdef NEED_DEV_ZERO
406 close(fd);
407#endif
408
409 /* Assume _DYNAMIC is the first data item */
410 dp = (struct link_dynamic *)(addr+hdr.a_text);
411
412 /* Fixup __DYNAMIC structure */
413 (long)dp->ld_un.ld_2 += (long)addr;
414
415 alloc_link_map(path, lop, lmp, addr, dp);
416
417}
418
419static void
420reloc_maps()
421{
422 struct link_map *lmp;
423
424 for (lmp = link_map_head; lmp; lmp = lmp->lm_next) {
425
426 struct link_dynamic *dp = lmp->lm_ld;
427 struct relocation_info *r = LM_REL(lmp);
428 struct relocation_info *rend = r + LD_RELSZ(dp)/sizeof(*r);
429
430 if (LD_PLTSZ(dp))
431 md_fix_jmpslot(LM_PLT(lmp),
432 (long)LM_PLT(lmp), (long)binder_entry);
433
434 for (; r < rend; r++) {
435 char *sym;
436 caddr_t addr = lmp->lm_addr + r->r_address;
437
438 check_text_reloc(r, lmp, addr);
439
440 if (RELOC_EXTERN_P(r)) {
441 struct link_map *src_map;
442 struct nzlist *np;
443 long relocation = md_get_addend(r, addr);
444
445 if (RELOC_LAZY_P(r))
446 continue;
447
448 sym = LM_STRINGS(lmp) +
449 LM_SYMBOL(lmp,RELOC_SYMBOL(r))->nz_strx;
450
80f25b52 451 np = lookup(sym, &src_map, 0/*XXX-jumpslots!*/);
1136f72d 452 if (np == NULL)
80f25b52
JH
453 fatal("Undefined symbol \"%s\" in %s\n",
454 sym, lmp->lm_name);
1136f72d
PR
455
456 /*
457 * Found symbol definition.
458 * If it's in a link map, adjust value
459 * according to the load address of that map.
460 * Otherwise it's a run-time allocated common
461 * whose value is already up-to-date.
462 */
463 relocation += np->nz_value;
464 if (src_map)
465 relocation += (long)src_map->lm_addr;
466
467 if (RELOC_PCREL_P(r))
468 relocation -= (long)lmp->lm_addr;
469
470 if (RELOC_COPY_P(r) && src_map) {
471#if DEBUG
472xprintf("RELOCATE(%s) copy: from %s at %#x(%#x+%#x) to %s at %#x, reloc = %#x, size %d\n",
473lmp->lm_name, src_map->lm_name, src_map->lm_addr + np->nz_value,
474src_map->lm_addr, np->nz_value, sym, addr, relocation, np->nz_size);
475#endif
476 (void)enter_rts(sym,
477 (long)addr,
478 N_DATA + N_EXT,
479 src_map->lm_addr + np->nz_value,
480 np->nz_size);
481 continue;
482 }
483#if DEBUG
484xprintf("RELOCATE(%s) external: %s at %#x, reloc = %#x\n", lmp->lm_name, sym, addr, relocation);
485#endif
486 md_relocate(r, relocation, addr, 0);
487
488 } else {
489#if DEBUG
490xprintf("RELOCATE(%s) internal at %#x, reloc = %#x\n", lmp->lm_name, addr, md_get_rt_segment_addend(r,addr));
491#endif
492 md_relocate(r,
493#ifdef SUN_COMPAT
494 md_get_rt_segment_addend(r, addr)
495#else
496 md_get_addend(r, addr)
497#endif
498 + (long)lmp->lm_addr, addr, 0);
499 }
500
501 }
502
80f25b52
JH
503 if (lmp->lm_rwt) {
504 if (mprotect(lmp->lm_addr + LM_TXTADDR(lmp),
505 LD_TEXTSZ(lmp->lm_ld),
506 PROT_READ|PROT_EXEC) == -1) {
507
508 perror("mprotect"),
509 fatal("Cannot disable writes to %s\n", lmp->lm_name);
510 }
511 lmp->lm_rwt = 0;
512 }
513
1136f72d
PR
514 }
515}
516
517static void
518reloc_copy()
519{
520 struct rt_symbol *rtsp;
521
522 for (rtsp = rt_symbol_head; rtsp; rtsp = rtsp->rt_next)
523 if (rtsp->rt_sp->nz_type == N_DATA + N_EXT) {
524#ifdef DEBUG
525xprintf("reloc_copy: from %#x to %#x, size %d\n",
526rtsp->rt_srcaddr, rtsp->rt_sp->nz_value, rtsp->rt_sp->nz_size);
527#endif
528 bcopy(rtsp->rt_srcaddr, (caddr_t)rtsp->rt_sp->nz_value,
529 rtsp->rt_sp->nz_size);
530 }
531}
532
533static void
534check_text_reloc(r, lmp, addr)
535struct relocation_info *r;
536struct link_map *lmp;
537caddr_t addr;
538{
539 char *sym;
540
541 if (addr >= LM_ETEXT(lmp))
542 return;
543
544 if (RELOC_EXTERN_P(r))
545 sym = LM_STRINGS(lmp) +
546 LM_SYMBOL(lmp, RELOC_SYMBOL(r))->nz_strx;
547 else
548 sym = "";
549
550#ifdef DEBUG
551 fprintf(stderr, "ld.so: warning: non pure code in %s at %x (%s)\n",
552 lmp->lm_name, r->r_address, sym);
553#endif
554
80f25b52
JH
555 if (lmp->lm_rwt == 0 &&
556 mprotect(lmp->lm_addr + LM_TXTADDR(lmp),
557 LD_TEXTSZ(lmp->lm_ld),
558 PROT_READ|PROT_WRITE|PROT_EXEC) == -1) {
1136f72d
PR
559
560 perror("mprotect"),
561 fatal("Cannot enable writes to %s\n", lmp->lm_name);
562 }
563
564 lmp->lm_rwt = 1;
565}
566
80f25b52
JH
567/*
568 * Lookup NAME in the link maps. The link map producing a definition
569 * is returned in SRC_MAP. If STRONG is set, the symbol returned must
570 * have a proper type (used by binder()).
571 */
1136f72d 572static struct nzlist *
80f25b52
JH
573lookup(name, src_map, strong)
574char *name;
1136f72d 575struct link_map **src_map;
80f25b52 576int strong;
1136f72d
PR
577{
578 long common_size = 0;
579 struct link_map *lmp;
580 struct rt_symbol *rtsp;
581
582 *src_map = NULL;
583
584 if ((rtsp = lookup_rts(name)) != NULL)
585 return rtsp->rt_sp;
586
587 /*
588 * Search all maps for a definition of NAME
589 */
590 for (lmp = link_map_head; lmp; lmp = lmp->lm_next) {
591 int buckets = LD_BUCKETS(lmp->lm_ld);
592 long hashval = 0;
593 struct rrs_hash *hp;
594 char *cp;
595 struct nzlist *np;
596
597 /*
598 * Compute bucket in which the symbol might be found.
599 */
600 for (cp = name; *cp; cp++)
601 hashval = (hashval << 1) + *cp;
602
603 hashval = (hashval & 0x7fffffff) % buckets;
604
605 hp = LM_HASH(lmp) + hashval;
606 if (hp->rh_symbolnum == -1)
607 /* Nothing in this bucket */
608 continue;
609
610 while (hp) {
611 np = LM_SYMBOL(lmp, hp->rh_symbolnum);
612 cp = LM_STRINGS(lmp) + np->nz_strx;
613 if (strcmp(cp, name) == 0)
614 break;
615 if (hp->rh_next == 0)
616 hp = NULL;
617 else
618 hp = LM_HASH(lmp) + hp->rh_next;
619 }
620 if (hp == NULL)
621 /* Nothing in this bucket */
622 continue;
623
624 /*
625 * We have a symbol with the name we're looking for.
626 */
627
628 if (np->nz_value == 0)
629 /* It's not a definition */
630 continue;
631
632 if (np->nz_type == N_UNDF+N_EXT && np->nz_value != 0) {
80f25b52
JH
633 if (np->nz_other == RRS_FUNC) {
634 /* It's a weak function definition */
635 if (strong)
636 continue;
637 } else {
638 /* It's a common, note value and continue search */
639 if (common_size < np->nz_value)
640 common_size = np->nz_value;
641 continue;
642 }
1136f72d
PR
643 }
644
645 *src_map = lmp;
646 return np;
647 }
648
649 if (common_size == 0)
650 /* Not found */
651 return NULL;
652
653 /*
654 * It's a common, enter into run-time common symbol table.
655 */
656 rtsp = enter_rts(name, (long)calloc(1, common_size),
657 N_UNDF + N_EXT, 0, common_size);
658
659#if DEBUG
660xprintf("Allocating common: %s size %d at %#x\n", name, common_size, rtsp->rt_sp->nz_value);
661#endif
662
663 return rtsp->rt_sp;
664}
665
666
667/*
668 * This routine is called from the jumptable to resolve
669 * procedure calls to shared objects.
670 */
671long
672binder(jsp)
673jmpslot_t *jsp;
674{
675 struct link_map *lmp, *src_map;
676 long addr;
677 char *sym;
678 struct nzlist *np;
679 int index;
680
681 /*
682 * Find the PLT map that contains JSP.
683 */
684 for (lmp = link_map_head; lmp; lmp = lmp->lm_next) {
685 if (LM_PLT(lmp) < jsp &&
686 jsp < LM_PLT(lmp) + LD_PLTSZ(lmp->lm_ld)/sizeof(*jsp))
687 break;
688 }
689
690 if (lmp == NULL)
691 fatal("Call to binder from unknown location: %#x\n", jsp);
692
693 index = jsp->reloc_index & JMPSLOT_RELOC_MASK;
694
695 /* Get the local symbol this jmpslot refers to */
696 sym = LM_STRINGS(lmp) +
697 LM_SYMBOL(lmp,RELOC_SYMBOL(&LM_REL(lmp)[index]))->nz_strx;
698
80f25b52 699 np = lookup(sym, &src_map, 1);
1136f72d
PR
700 if (np == NULL)
701 fatal("Undefined symbol \"%s\" called from %s at %#x", sym,
702 lmp->lm_name, jsp);
703
704 /* Fixup jmpslot so future calls transfer directly to target */
705 addr = np->nz_value;
706 if (src_map)
707 addr += (long)src_map->lm_addr;
708
709 md_fix_jmpslot(jsp, (long)jsp, addr);
710
711#if DEBUG
712xprintf(" BINDER: %s located at = %#x in %s\n", sym, addr, src_map->lm_name);
713#endif
714 return addr;
715}
716
717
718/*
719 * Run-time common symbol table.
720 */
721
722#define RTC_TABSIZE 57
723static struct rt_symbol *rt_symtab[RTC_TABSIZE];
724
725/*
726 * Compute hash value for run-time symbol table
727 */
728static int
729hash_string(key)
730 char *key;
731{
732 register char *cp;
733 register int k;
734
735 cp = key;
736 k = 0;
737 while (*cp)
738 k = (((k << 1) + (k >> 14)) ^ (*cp++)) & 0x3fff;
739
740 return k;
741}
742
743/*
744 * Lookup KEY in the run-time common symbol table.
745 */
746
747static struct rt_symbol *
748lookup_rts(key)
749 char *key;
750{
751 register int hashval;
752 register struct rt_symbol *rtsp;
753
754 /* Determine which bucket. */
755
756 hashval = hash_string(key) % RTC_TABSIZE;
757
758 /* Search the bucket. */
759
760 for (rtsp = rt_symtab[hashval]; rtsp; rtsp = rtsp->rt_link)
761 if (strcmp(key, rtsp->rt_sp->nz_name) == 0)
762 return rtsp;
763
764 return NULL;
765}
766
767static struct rt_symbol *
768enter_rts(name, value, type, srcaddr, size)
769 char *name;
770 long value;
771 int type;
772 caddr_t srcaddr;
773 long size;
774{
775 register int hashval;
776 register struct rt_symbol *rtsp, **rpp;
777
778 /* Determine which bucket */
779 hashval = hash_string(name) % RTC_TABSIZE;
780
781 /* Find end of bucket */
782 for (rpp = &rt_symtab[hashval]; *rpp; rpp = &(*rpp)->rt_link)
783 ;
784
785 /* Allocate new common symbol */
786 rtsp = (struct rt_symbol *)malloc(sizeof(struct rt_symbol));
787 rtsp->rt_sp = (struct nzlist *)malloc(sizeof(struct nzlist));
788 rtsp->rt_sp->nz_name = strdup(name);
789 rtsp->rt_sp->nz_value = value;
790 rtsp->rt_sp->nz_type = type;
791 rtsp->rt_sp->nz_size = size;
792 rtsp->rt_srcaddr = srcaddr;
793 rtsp->rt_link = NULL;
794
795 /* Link onto linear list as well */
796 rtsp->rt_next = rt_symbol_head;
797 rt_symbol_head = rtsp;
798
799 *rpp = rtsp;
800
801 return rtsp;
802}
803
804static struct hints_header *hheader;
805static struct hints_bucket *hbuckets;
806static char *hstrtab;
807
808#define HINTS_VALID (hheader != NULL && hheader != (struct hints_header *)-1)
809
810static void
811maphints()
812{
813 caddr_t addr;
814 long msize;
815 int fd;
816
817 if ((fd = open(_PATH_LD_HINTS, O_RDONLY, 0)) == -1) {
818 hheader = (struct hints_header *)-1;
819 return;
820 }
821
822 msize = PAGSIZ;
823 addr = mmap(0, msize, PROT_READ, MAP_FILE|MAP_COPY, fd, 0);
824
825 if (addr == (caddr_t)-1) {
826 hheader = (struct hints_header *)-1;
827 return;
828 }
829
830 hheader = (struct hints_header *)addr;
831 if (HH_BADMAG(*hheader)) {
832 munmap(addr, msize);
833 hheader = (struct hints_header *)-1;
834 return;
835 }
836
837 if (hheader->hh_version != LD_HINTS_VERSION_1) {
838 munmap(addr, msize);
839 hheader = (struct hints_header *)-1;
840 return;
841 }
842
843 if (hheader->hh_ehints > msize) {
844 if (mmap(addr+msize, hheader->hh_ehints - msize,
845 PROT_READ, MAP_FILE|MAP_COPY|MAP_FIXED,
846 fd, msize) != (caddr_t)(addr+msize)) {
847
848 munmap((caddr_t)hheader, msize);
849 hheader = (struct hints_header *)-1;
850 return;
851 }
852 }
853 close(fd);
854
855 hbuckets = (struct hints_bucket *)(addr + hheader->hh_hashtab);
856 hstrtab = (char *)(addr + hheader->hh_strtab);
857}
858
859int
860hinthash(cp, vmajor, vminor)
861char *cp;
862int vmajor, vminor;
863{
864 int k = 0;
865
866 while (*cp)
867 k = (((k << 1) + (k >> 14)) ^ (*cp++)) & 0x3fff;
868
869 k = (((k << 1) + (k >> 14)) ^ (vmajor*257)) & 0x3fff;
870 k = (((k << 1) + (k >> 14)) ^ (vminor*167)) & 0x3fff;
871
872 return k;
873}
874
875#undef major
876#undef minor
877
878static char *
879findhint(name, major, minor, preferred_path)
880char *name;
881int major, minor;
882char *preferred_path;
883{
884 struct hints_bucket *bp;
885
886 bp = hbuckets + (hinthash(name, major, minor) % hheader->hh_nbucket);
887
888 while (1) {
889 /* Sanity check */
890 if (bp->hi_namex >= hheader->hh_strtab_sz) {
891 fprintf(stderr, "Bad name index: %#x\n", bp->hi_namex);
892 break;
893 }
894 if (bp->hi_pathx >= hheader->hh_strtab_sz) {
895 fprintf(stderr, "Bad path index: %#x\n", bp->hi_pathx);
896 break;
897 }
898
899 if (strcmp(name, hstrtab + bp->hi_namex) == 0) {
900 /* It's `name', check version numbers */
901 if (bp->hi_major == major &&
902 (bp->hi_ndewey < 2 || bp->hi_minor == minor)) {
903 if (preferred_path == NULL ||
904 strcmp(preferred_path,
905 hstrtab + bp->hi_pathx) == 0) {
906 return hstrtab + bp->hi_pathx;
907 }
908 }
909 }
910
911 if (bp->hi_next == -1)
912 break;
913
914 /* Move on to next in bucket */
915 bp = &hbuckets[bp->hi_next];
916 }
917
918 /* No hints available for name */
919 return NULL;
920}
921
922static char *
923rtfindlib(name, major, minor, usehints)
924char *name;
925int major, minor;
926int *usehints;
927{
928 char *hint;
929 char *cp, *ld_path = getenv("LD_LIBRARY_PATH");
930
931 if (hheader == NULL)
932 maphints();
933
934 if (!HINTS_VALID || !(*usehints)) {
935 *usehints = 0;
a1d2977e 936 return (char *)findshlib(name, &major, &minor, 1);
1136f72d
PR
937 }
938
939 if (ld_path != NULL) {
940 /* Prefer paths from LD_LIBRARY_PATH */
80f25b52 941 while ((cp = strsep(&ld_path, ":")) != NULL) {
1136f72d 942
1136f72d 943 hint = findhint(name, major, minor, cp);
80f25b52
JH
944 if (ld_path)
945 *(ld_path-1) = ':';
1136f72d
PR
946 if (hint)
947 return hint;
948 }
949 } else {
950 /* No LD_LIBRARY_PATH, check default */
951 hint = findhint(name, major, minor, NULL);
952 if (hint)
953 return hint;
954 }
955
956 /* No hints available for name */
957 *usehints = 0;
a1d2977e 958 return (char *)findshlib(name, &major, &minor, 1);
1136f72d
PR
959}
960
961static int
962dlopen(name, mode)
963char *name;
964int mode;
965{
966 xprintf("dlopen(%s, %x)\n", name, mode);
967 return -1;
968}
969
970static int
971dlclose(fd)
972int fd;
973{
974 xprintf("dlclose(%d)\n", fd);
975 return -1;
976}
977
978static int
979dlsym(fd, sym)
980int fd;
981char *sym;
982{
983 xprintf("dlsym(%d, %s)\n", fd, sym);
984 return 0;
985}
986
987/*
988 * Private heap functions.
989 */
990
991static caddr_t curbrk;
992
993static void
994init_brk()
995{
996 struct rlimit rlim;
997 char *cp, **cpp = environ;
998
999 if (getrlimit(RLIMIT_STACK, &rlim) < 0) {
1000 xprintf("ld.so: brk: getrlimit failure\n");
1001 _exit(1);
1002 }
1003
b6458905
PR
1004 if (environ < USRSTACK - MAXSSIZ) {
1005 curbrk = (caddr_t)
1006 (((long)(USRSTACK - MAXSSIZ - rlim.rlim_cur) + PAGSIZ) & ~(PAGSIZ - 1));
1007 } else {
1008 curbrk = (caddr_t)
1009 (((long)(USRSTACK - rlim.rlim_cur) + PAGSIZ) & ~(PAGSIZ - 1)) ;
1010 }
1136f72d
PR
1011}
1012
1013void
1014#if __STDC__
1015xprintf(char *fmt, ...)
1016#else
1017xprintf(fmt, va_alist)
1018char *fmt;
1019#endif
1020{
1021 char buf[256];
1022 va_list ap;
1023#if __STDC__
1024 va_start(ap, fmt);
1025#else
1026 va_start(ap);
1027#endif
1028
1029 vsprintf(buf, fmt, ap);
1030 (void)write(1, buf, strlen(buf));
1031 va_end(ap);
1032}
1033
a9817baa 1034#if 1
1136f72d
PR
1035caddr_t
1036sbrk(incr)
1037int incr;
1038{
1039 int fd = -1;
1040 caddr_t oldbrk;
1041
1042 if (curbrk == 0)
1043 init_brk();
1044
1045#if DEBUG
1046xprintf("sbrk: incr = %#x, curbrk = %#x\n", incr, curbrk);
1047#endif
1048 if (incr == 0)
1049 return curbrk;
1050
1051 incr = (incr + PAGSIZ - 1) & ~(PAGSIZ - 1);
1052
1053#ifdef NEED_DEV_ZERO
1054 fd = open("/dev/zero", O_RDWR, 0);
1055 if (fd == -1)
1056 perror("/dev/zero");
1057#endif
1058
1059 if (mmap(curbrk, incr,
1060 PROT_READ|PROT_WRITE,
1061 MAP_ANON|MAP_FIXED|MAP_COPY, fd, 0) == (caddr_t)-1) {
27b6ced7
JH
1062 xprintf("Cannot map anonymous memory");
1063 _exit(1);
1064 }
1065
1066#ifdef NEED_DEV_ZERO
1067 close(fd);
1068#endif
1069
1070 oldbrk = curbrk;
1071#if TRY_THIS_FOR_A_CHANGE
1072 curbrk -= incr;
1073#else
1074 curbrk += incr;
1075#endif
1076
1077 return oldbrk;
1078}
a9817baa
JH
1079
1080#else
1081
1082caddr_t
1083sbrk(incr)
1084int incr;
1085{
1086 int fd = -1;
1087 caddr_t oldbrk;
1088
1089xprintf("sbrk: incr = %#x, curbrk = %#x\n", incr, curbrk);
1090#if DEBUG
1091xprintf("sbrk: incr = %#x, curbrk = %#x\n", incr, curbrk);
1092#endif
1093 if (curbrk == 0 && (curbrk = mmap(0, PAGSIZ,
1094 PROT_READ|PROT_WRITE,
1095 MAP_ANON|MAP_COPY, fd, 0)) == (caddr_t)-1) {
1096 xprintf("Cannot map anonymous memory");
1097 _exit(1);
1098 }
1099
1100 /* There's valid memory from `curbrk' to next page boundary */
1101 if ((long)curbrk + incr <= (((long)curbrk + PAGSIZ) & ~(PAGSIZ - 1))) {
1102 oldbrk = curbrk;
1103 curbrk += incr;
1104 return oldbrk;
1105 }
1106 /*
1107 * If asking for than currently left in this chunk,
1108 * go somewhere completely different.
1109 */
1110
1111#ifdef NEED_DEV_ZERO
1112 fd = open("/dev/zero", O_RDWR, 0);
1113 if (fd == -1)
1114 perror("/dev/zero");
1115#endif
1116
1117 if ((curbrk = mmap(0, incr,
1118 PROT_READ|PROT_WRITE,
1119 MAP_ANON|MAP_COPY, fd, 0)) == (caddr_t)-1) {
1120 perror("Cannot map anonymous memory");
1121 }
1122
1123#ifdef NEED_DEV_ZERO
1124 close(fd);
1125#endif
1126
1127 oldbrk = curbrk;
1128 curbrk += incr;
1129
1130 return oldbrk;
1131}
1132#endif