Changes from Paul Kranenburg which bring us into sync with his sources:
[unix-history] / gnu / usr.bin / ld / rrs.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
6a61ea88 17 * derived from this software without specific prior written permission
1136f72d
PR
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 *
1c8a0fd5 30 * $Id: rrs.c,v 1.11 1994/02/13 20:41:40 jkh Exp $
1136f72d
PR
31 */
32
33#include <sys/param.h>
1136f72d
PR
34#include <sys/types.h>
35#include <sys/stat.h>
36#include <sys/file.h>
37#include <sys/time.h>
38#include <sys/resource.h>
1c8a0fd5
PR
39#include <stdio.h>
40#include <stdlib.h>
41#include <unistd.h>
42#include <err.h>
1136f72d
PR
43#include <fcntl.h>
44#include <ar.h>
45#include <ranlib.h>
46#include <a.out.h>
47#include <stab.h>
48#include <string.h>
1136f72d
PR
49
50#include "ld.h"
51
6a61ea88
JH
52static struct _dynamic rrs_dyn; /* defined in link.h */
53static struct so_debug rrs_so_debug; /* defined in link.h */
54static struct section_dispatch_table rrs_sdt; /* defined in link.h */
1136f72d
PR
55static got_t *rrs_got;
56static jmpslot_t *rrs_plt; /* defined in md.h */
57static struct relocation_info *rrs_reloc;
58static struct nzlist *rrs_symbols; /* RRS symbol table */
59static char *rrs_strtab; /* RRS strings */
60static struct rrs_hash *rrs_hashtab; /* RT hash table */
61static struct shobj *rrs_shobjs;
62
63static int reserved_rrs_relocs;
64static int claimed_rrs_relocs;
65
66static int number_of_gotslots;
67static int number_of_jmpslots;
68static int number_of_rrs_hash_entries;
69static int number_of_rrs_symbols;
70static int rrs_strtab_size;
71static int rrs_symbol_size;
72
73static int current_jmpslot_offset;
74static int current_got_offset;
75static int current_reloc_offset;
76static int current_hash_index;
6a61ea88 77int number_of_shobjs;
1136f72d
PR
78
79struct shobj {
80 struct shobj *next;
81 struct file_entry *entry;
82};
83
84/*
85RRS text segment:
6a61ea88 86 +-------------------+ <-- sdt_rel (rrs_text_start)
1136f72d
PR
87 | |
88 | relocation |
89 | |
6a61ea88 90 +-------------------+ <-- <sdt>.sdt_hash
1136f72d
PR
91 | |
92 | hash buckets |
93 | |
6a61ea88 94 +-------------------+ <-- <sdt>.sdt_nzlist
1136f72d
PR
95 | |
96 | symbols |
97 | |
6a61ea88 98 +-------------------+ <-- <sdt>.sdt_strings
1136f72d
PR
99 | |
100 | strings |
101 | |
6a61ea88 102 +-------------------+ <-- <sdt>.sdt_sods
1136f72d
PR
103 | |
104 | shobjs |
105 | |
106 +-------------------+
107 | |
6a61ea88 108 | shobjs strings | <-- <shobj>.sod_name
1136f72d
PR
109 | |
110 +-------------------+
111
112
113RRS data segment:
114
115 +-------------------+ <-- __DYNAMIC (rrs_data_start)
116 | |
6a61ea88 117 | _dymamic |
1136f72d 118 | |
6a61ea88 119 +-------------------+ <-- __DYNAMIC.d_debug
1136f72d 120 | |
6a61ea88 121 | so_debug |
1136f72d 122 | |
6a61ea88 123 +-------------------+ <-- __DYNAMIC.d_un.d_sdt
1136f72d 124 | |
6a61ea88 125 | sdt |
1136f72d 126 | |
6a61ea88 127 +-------------------+ <-- _GLOBAL_OFFSET_TABLE_ (sdt_got)
1136f72d
PR
128 | |
129 | _GOT_ |
130 | |
6a61ea88 131 +-------------------+ <-- sdt_plt
1136f72d
PR
132 | |
133 | PLT |
134 | |
135 +-------------------+
136*/
137
138/*
139 * Initialize RRS
140 */
141
142void
143init_rrs()
144{
145 reserved_rrs_relocs = 0;
146 claimed_rrs_relocs = 0;
147
148 number_of_rrs_symbols = 0;
149 rrs_strtab_size = 0;
150
151 /* First jmpslot reserved for run-time binder */
152 current_jmpslot_offset = sizeof(jmpslot_t);
153 number_of_jmpslots = 1;
154
155 /* First gotslot reserved for __DYNAMIC */
156 current_got_offset = sizeof(got_t);
157 number_of_gotslots = 1;
158
159 current_reloc_offset = 0;
160}
161
162/*
163 * Add NAME to the list of needed run-time objects.
80f25b52 164 * Return 1 if ENTRY was added to the list.
1136f72d 165 */
80f25b52 166int
1136f72d
PR
167rrs_add_shobj(entry)
168struct file_entry *entry;
169{
170 struct shobj **p;
171
80f25b52
JH
172 for (p = &rrs_shobjs; *p != NULL; p = &(*p)->next)
173 if (strcmp((*p)->entry->filename, entry->filename) == 0)
174 return 0;
1136f72d
PR
175 *p = (struct shobj *)xmalloc(sizeof(struct shobj));
176 (*p)->next = NULL;
177 (*p)->entry = entry;
178
179 number_of_shobjs++;
80f25b52 180 return 1;
1136f72d
PR
181}
182
183void
27b6ced7
JH
184alloc_rrs_reloc(entry, sp)
185struct file_entry *entry;
1136f72d
PR
186symbol *sp;
187{
188#ifdef DEBUG
27b6ced7 189printf("alloc_rrs_reloc: %s in %s\n", sp->name, get_file_name(entry));
1136f72d
PR
190#endif
191 reserved_rrs_relocs++;
192}
193
194void
27b6ced7
JH
195alloc_rrs_segment_reloc(entry, r)
196struct file_entry *entry;
1136f72d
PR
197struct relocation_info *r;
198{
199#ifdef DEBUG
27b6ced7
JH
200printf("alloc_rrs_segment_reloc at %#x in %s\n",
201 r->r_address, get_file_name(entry));
1136f72d
PR
202#endif
203 reserved_rrs_relocs++;
204}
205
206void
27b6ced7
JH
207alloc_rrs_jmpslot(entry, sp)
208struct file_entry *entry;
1136f72d
PR
209symbol *sp;
210{
211 if (sp->jmpslot_offset == -1) {
212 sp->jmpslot_offset = current_jmpslot_offset;
213 current_jmpslot_offset += sizeof(jmpslot_t);
214 number_of_jmpslots++;
215 if (!(link_mode & SYMBOLIC) || JMPSLOT_NEEDS_RELOC) {
216 reserved_rrs_relocs++;
217 }
218 }
219}
220
221void
27b6ced7
JH
222alloc_rrs_gotslot(entry, r, lsp)
223struct file_entry *entry;
1136f72d
PR
224struct relocation_info *r;
225struct localsymbol *lsp;
226{
227 symbol *sp = lsp->symbol;
228
229 if (!RELOC_EXTERN_P(r)) {
230
27b6ced7 231 if (sp != NULL) {
1c8a0fd5 232 warnx("%s: relocation for internal symbol expected at %#x",
27b6ced7
JH
233 get_file_name(entry), RELOC_ADDRESS(r));
234 return;
235 }
1136f72d
PR
236
237 if (!RELOC_STATICS_THROUGH_GOT_P(r))
238 /* No need for a GOT slot */
239 return;
240
241 if (lsp->gotslot_offset == -1) {
242 lsp->gotslot_offset = current_got_offset;
243 current_got_offset += sizeof(got_t);
244 number_of_gotslots++;
245 /*
246 * Now, see if slot needs run-time fixing
247 * If the load address is known (entry_symbol), this
248 * slot will have its final value set by `claim_got'
249 */
250 if ((link_mode & SHAREABLE) || (link_mode & SYMBOLIC))
251 reserved_rrs_relocs++;
252 }
253
27b6ced7
JH
254 } else {
255
256 if (sp == NULL) {
1c8a0fd5 257 warnx("%s: relocation must refer to global symbol at %#x",
27b6ced7
JH
258 get_file_name(entry), RELOC_ADDRESS(r));
259 return;
260 }
1136f72d
PR
261
262 if (sp->alias)
263 sp = sp->alias;
264
27b6ced7
JH
265 if (sp->gotslot_offset != -1)
266 return;
267
1136f72d
PR
268 /*
269 * External symbols always get a relocation entry
270 */
271 sp->gotslot_offset = current_got_offset;
272 reserved_rrs_relocs++;
273 current_got_offset += sizeof(got_t);
274 number_of_gotslots++;
275 }
276
277}
278
279void
27b6ced7
JH
280alloc_rrs_cpy_reloc(entry, sp)
281struct file_entry *entry;
1136f72d
PR
282symbol *sp;
283{
6a61ea88 284 if (sp->flags & GS_CPYRELOCRESERVED)
1136f72d
PR
285 return;
286#ifdef DEBUG
27b6ced7 287printf("alloc_rrs_copy: %s in %s\n", sp->name, get_file_name(entry));
1136f72d 288#endif
6a61ea88 289 sp->flags |= GS_CPYRELOCRESERVED;
1136f72d
PR
290 reserved_rrs_relocs++;
291}
292
293static struct relocation_info *
294rrs_next_reloc()
295{
296 struct relocation_info *r;
297
298 r = rrs_reloc + claimed_rrs_relocs++;
299 if (claimed_rrs_relocs > reserved_rrs_relocs)
1c8a0fd5 300 errx(1, "internal error: RRS relocs exceed allocation %d",
1136f72d
PR
301 reserved_rrs_relocs);
302 return r;
303}
304
305/*
306 * Claim a RRS relocation as a result of a regular (ie. non-PIC)
307 * relocation record in a rel file.
308 *
309 * Return 1 if the output file needs no further updating.
310 * Return 0 if the relocation value pointed to by RELOCATION must
311 * written to a.out.
312 */
313int
27b6ced7
JH
314claim_rrs_reloc(entry, rp, sp, relocation)
315struct file_entry *entry;
1136f72d
PR
316struct relocation_info *rp;
317symbol *sp;
318long *relocation;
319{
320 struct relocation_info *r = rrs_next_reloc();
80f25b52 321
1136f72d 322 if (rp->r_address < text_start + text_size)
1c8a0fd5 323 warnx("%s: RRS text relocation at %#x for \"%s\"",
27b6ced7 324 get_file_name(entry), rp->r_address, sp->name);
80f25b52 325
6a61ea88 326#ifdef DEBUG
27b6ced7 327printf("claim_rrs_reloc: %s in %s\n", sp->name, get_file_name(entry));
1136f72d
PR
328#endif
329 r->r_address = rp->r_address;
330 r->r_symbolnum = sp->rrs_symbolnum;
331
332 if (link_mode & SYMBOLIC) {
333 if (!sp->defined)
1c8a0fd5 334 warnx("Cannot reduce symbol \"%s\" in %s",
27b6ced7 335 sp->name, get_file_name(entry));
1136f72d
PR
336 RELOC_EXTERN_P(r) = 0;
337 *relocation += sp->value;
338 (void) md_make_reloc(rp, r, RELTYPE_RELATIVE);
339 return 0;
340 } else {
341 RELOC_EXTERN_P(r) = 1;
342 return md_make_reloc(rp, r, RELTYPE_EXTERN);
343 }
344}
345
346/*
347 * Claim a jmpslot. Setup RRS relocation if claimed for the first time.
348 */
349long
27b6ced7
JH
350claim_rrs_jmpslot(entry, rp, sp, addend)
351struct file_entry *entry;
1136f72d
PR
352struct relocation_info *rp;
353symbol *sp;
354long addend;
355{
356 struct relocation_info *r;
357
6a61ea88
JH
358 if (sp->flags & GS_JMPSLOTCLAIMED)
359 return rrs_sdt.sdt_plt + sp->jmpslot_offset;
1136f72d
PR
360
361#ifdef DEBUG
1c8a0fd5 362printf("claim_rrs_jmpslot: %s: %s(%d) -> offset %x\n",
27b6ced7 363 get_file_name(entry),
1c8a0fd5 364 sp->name, sp->rrs_symbolnum, sp->jmpslot_offset);
1136f72d
PR
365#endif
366
367 if (sp->jmpslot_offset == -1)
1c8a0fd5 368 errx(1,
27b6ced7
JH
369 "internal error: %s: claim_rrs_jmpslot: %s: jmpslot_offset == -1\n",
370 get_file_name(entry),
1136f72d
PR
371 sp->name);
372
373 if ((link_mode & SYMBOLIC) || rrs_section_type == RRS_PARTIAL) {
374 if (!sp->defined)
1c8a0fd5 375 warnx("Cannot reduce symbol \"%s\" in %s",
27b6ced7 376 sp->name, get_file_name(entry));
1136f72d
PR
377
378 md_fix_jmpslot( rrs_plt + sp->jmpslot_offset/sizeof(jmpslot_t),
6a61ea88 379 rrs_sdt.sdt_plt + sp->jmpslot_offset,
1136f72d
PR
380 sp->value);
381 if (!JMPSLOT_NEEDS_RELOC) {
6a61ea88 382 return rrs_sdt.sdt_plt + sp->jmpslot_offset;
1136f72d
PR
383 }
384 } else {
6a61ea88 385 md_make_jmpslot(rrs_plt + sp->jmpslot_offset/sizeof(jmpslot_t),
1136f72d
PR
386 sp->jmpslot_offset,
387 claimed_rrs_relocs);
388 }
389
390 if (rrs_section_type == RRS_PARTIAL)
391 /* PLT is self-contained */
6a61ea88 392 return rrs_sdt.sdt_plt + sp->jmpslot_offset;
1136f72d
PR
393
394 /*
395 * Install a run-time relocation for this PLT entry.
396 */
397 r = rrs_next_reloc();
6a61ea88 398 sp->flags |= GS_JMPSLOTCLAIMED;
1136f72d
PR
399
400 RELOC_SYMBOL(r) = sp->rrs_symbolnum;
401
6a61ea88 402 r->r_address = (long)rrs_sdt.sdt_plt + sp->jmpslot_offset;
1136f72d
PR
403
404 if (link_mode & SYMBOLIC) {
405 RELOC_EXTERN_P(r) = 0;
406 md_make_jmpreloc(rp, r, RELTYPE_RELATIVE);
407 } else {
408 RELOC_EXTERN_P(r) = 1;
409 md_make_jmpreloc(rp, r, 0);
410 }
411
6a61ea88 412 return rrs_sdt.sdt_plt + sp->jmpslot_offset;
1136f72d
PR
413}
414
415/*
416 * Claim GOT entry for a global symbol. If this is the first relocation
417 * claiming the entry, setup a RRS relocation for it.
418 * Return offset into the GOT allocated to this symbol.
419 */
420long
27b6ced7
JH
421claim_rrs_gotslot(entry, rp, lsp, addend)
422struct file_entry *entry;
1136f72d
PR
423struct relocation_info *rp;
424struct localsymbol *lsp;
425long addend;
426{
427 struct relocation_info *r;
428 symbol *sp = lsp->symbol;
429 int reloc_type = 0;
430
27b6ced7
JH
431 if (sp == NULL) {
432 return 0;
433 }
434
1136f72d
PR
435 if (sp->alias)
436 sp = sp->alias;
437
438#ifdef DEBUG
439printf("claim_rrs_gotslot: %s(%d) slot offset %#x, addend %#x\n",
440 sp->name, sp->rrs_symbolnum, sp->gotslot_offset, addend);
441#endif
442 if (sp->gotslot_offset == -1)
1c8a0fd5 443 errx(1,
27b6ced7
JH
444 "internal error: %s: claim_rrs_gotslot: %s: gotslot_offset == -1\n",
445 get_file_name(entry), sp->name);
1136f72d 446
6a61ea88 447 if (sp->flags & GS_GOTSLOTCLAIMED)
1136f72d
PR
448 /* This symbol already passed here before. */
449 return sp->gotslot_offset;
450
451 if (sp->defined &&
452 (!(link_mode & SHAREABLE) || (link_mode & SYMBOLIC))) {
453
454 /*
455 * Reduce to just a base-relative translation.
456 */
457
458 *(got_t *)((long)rrs_got + sp->gotslot_offset) =
459 sp->value + addend;
460 reloc_type = RELTYPE_RELATIVE;
461
462 } else if ((link_mode & SYMBOLIC) || rrs_section_type == RRS_PARTIAL) {
463 /*
464 * SYMBOLIC: all symbols must be known.
465 * RRS_PARTIAL: we don't link against shared objects,
466 * so again all symbols must be known.
467 */
1c8a0fd5 468 warnx("Cannot reduce symbol \"%s\" in %s",
27b6ced7 469 sp->name, get_file_name(entry));
1136f72d
PR
470
471 } else {
472
473 /*
474 * This gotslot will be updated with symbol value at run-rime.
475 */
476
477 *(got_t *)((long)rrs_got + sp->gotslot_offset) = addend;
478 }
479
480 if (rrs_section_type == RRS_PARTIAL) {
481 /*
482 * Base address is known, gotslot should be fully
483 * relocated by now.
484 * NOTE: RRS_PARTIAL implies !SHAREABLE.
485 */
486 if (!sp->defined)
1c8a0fd5 487 warnx("Cannot reduce symbol \"%s\" in %s",
27b6ced7 488 sp->name, get_file_name(entry));
1136f72d
PR
489 return sp->gotslot_offset;
490 }
491
492 /*
493 * Claim a relocation entry.
494 * If symbol is defined and in "main" (!SHAREABLE)
495 * we still put out a relocation as we cannot easily
496 * undo the allocation.
497 * `RELTYPE_RELATIVE' relocations have the external bit off
498 * as no symbol need be looked up at run-time.
499 */
500 r = rrs_next_reloc();
6a61ea88
JH
501 sp->flags |= GS_GOTSLOTCLAIMED;
502 r->r_address = rrs_sdt.sdt_got + sp->gotslot_offset;
1136f72d
PR
503 RELOC_SYMBOL(r) = sp->rrs_symbolnum;
504 RELOC_EXTERN_P(r) = !(reloc_type == RELTYPE_RELATIVE);
505 md_make_gotreloc(rp, r, reloc_type);
506
507 return sp->gotslot_offset;
508}
509
510/*
511 * Claim a GOT entry for a static symbol. Return offset of the
512 * allocated GOT entry. If RELOC_STATICS_THROUGH_GOT_P is in effect
513 * return the offset of the symbol with respect to the *location* of
514 * the GOT.
515 */
516long
517claim_rrs_internal_gotslot(entry, rp, lsp, addend)
518struct file_entry *entry;
519struct relocation_info *rp;
520struct localsymbol *lsp;
521long addend;
522{
523 struct relocation_info *r;
524
525 addend += lsp->nzlist.nz_value;
526
527 if (!RELOC_STATICS_THROUGH_GOT_P(r))
6a61ea88 528 return addend - rrs_sdt.sdt_got;
1136f72d
PR
529
530#ifdef DEBUG
27b6ced7
JH
531printf("claim_rrs_internal_gotslot: %s: slot offset %#x, addend = %#x\n",
532 get_file_name(entry), lsp->gotslot_offset, addend);
1136f72d
PR
533#endif
534
535 if (lsp->gotslot_offset == -1)
1c8a0fd5 536 errx(1,
27b6ced7
JH
537 "internal error: %s: claim_rrs_internal_gotslot at %#x: slot_offset == -1\n",
538 get_file_name(entry), RELOC_ADDRESS(rp));
1136f72d 539
6a61ea88 540 if (lsp->flags & LS_GOTSLOTCLAIMED)
1136f72d
PR
541 /* Already done */
542 return lsp->gotslot_offset;
543
544 *(long *)((long)rrs_got + lsp->gotslot_offset) = addend;
545
546 if (!(link_mode & SHAREABLE))
547 return lsp->gotslot_offset;
548
549 /*
550 * Relocation entry needed for this static GOT entry.
551 */
552 r = rrs_next_reloc();
6a61ea88
JH
553 lsp->flags |= LS_GOTSLOTCLAIMED;
554 r->r_address = rrs_sdt.sdt_got + lsp->gotslot_offset;
1136f72d
PR
555 RELOC_EXTERN_P(r) = 0;
556 md_make_gotreloc(rp, r, RELTYPE_RELATIVE);
557 return lsp->gotslot_offset;
558}
559
560void
27b6ced7
JH
561claim_rrs_cpy_reloc(entry, rp, sp)
562struct file_entry *entry;
1136f72d
PR
563struct relocation_info *rp;
564symbol *sp;
565{
566 struct relocation_info *r;
567
6a61ea88 568 if (sp->flags & GS_CPYRELOCCLAIMED)
1136f72d
PR
569 return;
570
6a61ea88 571 if (!(sp->flags & GS_CPYRELOCRESERVED))
1c8a0fd5
PR
572 errx(1,
573 "internal error: %s: claim_cpy_reloc: %s: no reservation\n",
27b6ced7 574 get_file_name(entry), sp->name);
1136f72d
PR
575
576#ifdef DEBUG
27b6ced7
JH
577printf("claim_rrs_copy: %s: %s -> %x\n",
578 get_file_name(entry), sp->name, sp->so_defined);
1136f72d
PR
579#endif
580
581 r = rrs_next_reloc();
6a61ea88 582 sp->flags |= GS_CPYRELOCCLAIMED;
1136f72d
PR
583 r->r_address = rp->r_address;
584 RELOC_SYMBOL(r) = sp->rrs_symbolnum;
585 RELOC_EXTERN_P(r) = RELOC_EXTERN_P(rp);
586 md_make_cpyreloc(rp, r);
587}
588
589void
27b6ced7
JH
590claim_rrs_segment_reloc(entry, rp)
591struct file_entry *entry;
1136f72d
PR
592struct relocation_info *rp;
593{
594 struct relocation_info *r = rrs_next_reloc();
595
596#ifdef DEBUG
27b6ced7
JH
597printf("claim_rrs_segment_reloc: %s at %#x\n",
598 get_file_name(entry), rp->r_address);
1136f72d
PR
599#endif
600 r->r_address = rp->r_address;
601 RELOC_TYPE(r) = RELOC_TYPE(rp);
602 RELOC_EXTERN_P(r) = 0;
603 md_make_reloc(rp, r, RELTYPE_RELATIVE);
604
605}
606
607/*
608 * Fill the RRS hash table for the given symbol name.
609 * NOTE: the hash value computation must match the one in rtld.
610 */
611void
612rrs_insert_hash(cp, index)
613char *cp;
614int index;
615{
616 int hashval = 0;
617 struct rrs_hash *hp;
618
619 for (; *cp; cp++)
620 hashval = (hashval << 1) + *cp;
621
6a61ea88 622 hashval = (hashval & 0x7fffffff) % rrs_sdt.sdt_buckets;
1136f72d
PR
623
624 /* Get to the bucket */
625 hp = rrs_hashtab + hashval;
626 if (hp->rh_symbolnum == -1) {
627 /* Empty bucket, use it */
628 hp->rh_symbolnum = index;
629 hp->rh_next = 0;
630 return;
631 }
632
633 while (hp->rh_next != 0)
634 hp = rrs_hashtab + hp->rh_next;
635
636 hp->rh_next = current_hash_index++;
637 hp = rrs_hashtab + hp->rh_next;
638 hp->rh_symbolnum = index;
639 hp->rh_next = 0;
640}
641
642/*
643 * There are two interesting cases to consider here.
644 *
645 * 1) No shared objects were loaded, but there were PIC input rel files.
646 * In this case we must output a _GLOBAL_OFFSET_TABLE_ but no other
647 * RRS data. Also, the entries in the GOT must be fully resolved.
648 *
649 * 2) It's a genuine dynamically linked program, so the whole RRS scoop
650 * goes into a.out.
651 */
652void
653consider_rrs_section_lengths()
654{
655 int n;
6a61ea88 656 struct shobj *shp, **shpp;
1136f72d 657
6a61ea88
JH
658#ifdef notyet
659/* We run into trouble with this as long as shared object symbols
660 are not checked for definitions */
661 /*
662 * First, determine the real number of shared objects we need.
663 */
664 for (shpp = &rrs_shobjs; *shpp; shpp = &(*shpp)->next) {
665 while (*shpp && !((*shpp)->entry->flags & E_SYMBOLS_USED)) {
666 if (--number_of_shobjs < 0)
1c8a0fd5 667 errx(1, "internal error: number_of_shobjs < 0");
6a61ea88
JH
668 *shpp = (*shpp)->next;
669 }
670 if (*shpp == NULL)
671 break;
672 }
673#endif
1136f72d 674
6a61ea88 675 /* First, determine what of the RRS we want */
1136f72d
PR
676 if (relocatable_output)
677 rrs_section_type = RRS_NONE;
678 else if (link_mode & SHAREABLE)
679 rrs_section_type = RRS_FULL;
680 else if (number_of_shobjs == 0 /*&& !(link_mode & DYNAMIC)*/) {
681 /*
682 * First slots in both tables are reserved
683 * hence the "> 1" condition
684 */
685 if (number_of_gotslots > 1 || number_of_jmpslots > 1)
686 rrs_section_type = RRS_PARTIAL;
687 else
688 rrs_section_type = RRS_NONE;
689 } else
690 rrs_section_type = RRS_FULL;
691
692 if (rrs_section_type == RRS_NONE) {
693 got_symbol->defined = 0;
694 return;
695 }
696
697 rrs_symbol_size = LD_VERSION_NZLIST_P(soversion) ?
698 sizeof(struct nzlist) : sizeof(struct nlist);
699
700 /*
701 * If there is an entry point, __DYNAMIC must be referenced (usually
702 * from crt0), as this is the method used to determine whether the
703 * run-time linker must be called.
704 */
6a61ea88
JH
705 if (!(link_mode & SHAREABLE) &&
706 !(dynamic_symbol->flags & GS_REFERENCED))
1c8a0fd5 707 errx(1, "No reference to __DYNAMIC");
1136f72d 708
6a61ea88 709 dynamic_symbol->flags |= GS_REFERENCED;
1136f72d
PR
710
711 if (number_of_gotslots > 1)
6a61ea88 712 got_symbol->flags |= GS_REFERENCED;
1136f72d
PR
713
714
715 /* Next, allocate relocs, got and plt */
716 n = reserved_rrs_relocs * sizeof(struct relocation_info);
717 rrs_reloc = (struct relocation_info *)xmalloc(n);
718 bzero(rrs_reloc, n);
719
720 n = number_of_gotslots * sizeof(got_t);
721 rrs_got = (got_t *)xmalloc(n);
722 bzero(rrs_got, n);
723
724 n = number_of_jmpslots * sizeof(jmpslot_t);
725 rrs_plt = (jmpslot_t *)xmalloc(n);
726 bzero(rrs_plt, n);
727
728 /* Initialize first jmpslot */
729 md_fix_jmpslot(rrs_plt, 0, 0);
730
731 if (rrs_section_type == RRS_PARTIAL) {
732 rrs_data_size = number_of_gotslots * sizeof(got_t);
733 rrs_data_size += number_of_jmpslots * sizeof(jmpslot_t);
734 return;
735 }
736
737 /*
738 * Walk the symbol table, assign RRS symbol numbers
739 * Assign number 0 to __DYNAMIC (!! Sun compatibility)
740 */
741 dynamic_symbol->rrs_symbolnum = number_of_rrs_symbols++;
742 FOR_EACH_SYMBOL(i ,sp) {
6a61ea88 743 if (sp->flags & GS_REFERENCED) {
1136f72d
PR
744 rrs_strtab_size += 1 + strlen(sp->name);
745 if (sp != dynamic_symbol)
746 sp->rrs_symbolnum = number_of_rrs_symbols++;
0f052032
JH
747 if (sp->alias) {
748 /*
749 * (sigh) Always allocate space to hold the
750 * indirection. At this point there's not
751 * enough information to decide whether it's
752 * actually needed or not.
753 */
754 number_of_rrs_symbols++;
755 rrs_strtab_size += 1 + strlen(sp->alias->name);
756 }
1136f72d
PR
757 }
758 } END_EACH_SYMBOL;
759
760 /*
761 * Now that we know how many RRS symbols there are going to be,
762 * allocate and initialize the RRS symbol hash table.
763 */
6a61ea88
JH
764 rrs_sdt.sdt_buckets = number_of_rrs_symbols/4;
765 if (rrs_sdt.sdt_buckets < 4)
766 rrs_sdt.sdt_buckets = 4;
1136f72d 767
6a61ea88 768 number_of_rrs_hash_entries = rrs_sdt.sdt_buckets + number_of_rrs_symbols;
1136f72d
PR
769 rrs_hashtab = (struct rrs_hash *)xmalloc(
770 number_of_rrs_hash_entries * sizeof(struct rrs_hash));
6a61ea88 771 for (n = 0; n < rrs_sdt.sdt_buckets; n++)
1136f72d 772 rrs_hashtab[n].rh_symbolnum = -1;
6a61ea88 773 current_hash_index = rrs_sdt.sdt_buckets;
1136f72d
PR
774
775 /*
776 * Get symbols into hash table now, so we can fine tune the size
777 * of the latter. We adjust the value of `number_of_rrs_hash_entries'
778 * to the number of hash link slots actually used.
779 */
780 FOR_EACH_SYMBOL(i ,sp) {
6a61ea88 781 if (sp->flags & GS_REFERENCED)
1136f72d
PR
782 rrs_insert_hash(sp->name, sp->rrs_symbolnum);
783 } END_EACH_SYMBOL;
784 number_of_rrs_hash_entries = current_hash_index;
785
786 /*
787 * Calculate RRS section sizes.
788 */
6a61ea88
JH
789 rrs_data_size = sizeof(struct _dynamic);
790 rrs_data_size += sizeof(struct so_debug);
791 rrs_data_size += sizeof(struct section_dispatch_table);
1136f72d
PR
792 rrs_data_size += number_of_gotslots * sizeof(got_t);
793 rrs_data_size += number_of_jmpslots * sizeof(jmpslot_t);
794 rrs_data_size = MALIGN(rrs_data_size);
795
796 rrs_text_size = reserved_rrs_relocs * sizeof(struct relocation_info);
797 rrs_text_size += number_of_rrs_hash_entries * sizeof(struct rrs_hash);
798 rrs_text_size += number_of_rrs_symbols * rrs_symbol_size;
799
800 /* Align strings size */
801 rrs_strtab_size = MALIGN(rrs_strtab_size);
802 rrs_text_size += rrs_strtab_size;
803
804 /* Process needed shared objects */
805 for (shp = rrs_shobjs; shp; shp = shp->next) {
806 char *name = shp->entry->local_sym_name;
807
808 if (*name == '-' && *(name+1) == 'l')
809 name += 2;
810
6a61ea88 811 rrs_text_size += sizeof(struct sod);
1136f72d
PR
812 rrs_text_size += 1 + strlen(name);
813 }
814
815 /* Finally, align size */
816 rrs_text_size = MALIGN(rrs_text_size);
817}
818
819void
820relocate_rrs_addresses()
821{
822
823 dynamic_symbol->value = 0;
824
825 if (rrs_section_type == RRS_NONE)
826 return;
827
828 if (rrs_section_type == RRS_PARTIAL) {
6a61ea88
JH
829 got_symbol->value = rrs_sdt.sdt_got = rrs_data_start;
830 rrs_sdt.sdt_plt = rrs_sdt.sdt_got +
1136f72d
PR
831 number_of_gotslots * sizeof(got_t);
832 return;
833 }
834
835 /*
836 * RRS data relocations.
837 */
6a61ea88
JH
838 rrs_dyn.d_version = soversion;
839 rrs_dyn.d_debug = (struct so_debug *)
840 (rrs_data_start + sizeof(struct _dynamic));
841 rrs_dyn.d_un.d_sdt = (struct section_dispatch_table *)
842 ((long)rrs_dyn.d_debug + sizeof(struct so_debug));
1136f72d 843
6a61ea88
JH
844 rrs_sdt.sdt_got = (long)rrs_dyn.d_un.d_sdt +
845 sizeof(struct section_dispatch_table);
846 rrs_sdt.sdt_plt = rrs_sdt.sdt_got + number_of_gotslots*sizeof(got_t);
1136f72d
PR
847
848 /*
849 * RRS text relocations.
850 */
6a61ea88 851 rrs_sdt.sdt_rel = rrs_text_start;
1136f72d
PR
852 /*
853 * Sun BUG compatibility alert.
854 * Main program's RRS text values are relative to TXTADDR? WHY??
855 */
856#ifdef SUN_COMPAT
857 if (soversion == LD_VERSION_SUN && !(link_mode & SHAREABLE))
6a61ea88 858 rrs_sdt.sdt_rel -= N_TXTADDR(outheader);
1136f72d
PR
859#endif
860
6a61ea88 861 rrs_sdt.sdt_hash = rrs_sdt.sdt_rel +
1136f72d 862 reserved_rrs_relocs * sizeof(struct relocation_info);
6a61ea88 863 rrs_sdt.sdt_nzlist = rrs_sdt.sdt_hash +
1136f72d 864 number_of_rrs_hash_entries * sizeof(struct rrs_hash);
6a61ea88 865 rrs_sdt.sdt_strings = rrs_sdt.sdt_nzlist +
1136f72d 866 number_of_rrs_symbols * rrs_symbol_size;
6a61ea88
JH
867 rrs_sdt.sdt_str_sz = rrs_strtab_size;
868 rrs_sdt.sdt_text_sz = text_size;
869 rrs_sdt.sdt_plt_sz = number_of_jmpslots * sizeof(jmpslot_t);
1136f72d 870
6a61ea88
JH
871 rrs_sdt.sdt_sods = rrs_shobjs ? rrs_sdt.sdt_strings+rrs_strtab_size : 0;
872 rrs_sdt.sdt_filler1 = 0;
873 rrs_sdt.sdt_filler2 = 0;
1136f72d
PR
874
875 /*
876 * Assign addresses to _GLOBAL_OFFSET_TABLE_ and __DYNAMIC
877 * &__DYNAMIC is also in the first GOT entry.
878 */
6a61ea88 879 got_symbol->value = rrs_sdt.sdt_got;
1136f72d
PR
880
881 *rrs_got = dynamic_symbol->value = rrs_data_start;
882
883}
884
885void
886write_rrs_data()
887{
888 long pos;
889
890 if (rrs_section_type == RRS_NONE)
891 return;
892
893 pos = rrs_data_start + (N_DATOFF(outheader) - DATA_START(outheader));
894 if (lseek(outdesc, pos, L_SET) != pos)
1c8a0fd5 895 err(1, "write_rrs_data: lseek");
1136f72d
PR
896
897 if (rrs_section_type == RRS_PARTIAL) {
898 /*
899 * Only a GOT and PLT are needed.
900 */
901 if (number_of_gotslots <= 1)
1c8a0fd5 902 errx(1, "write_rrs_data: # gotslots <= 1");
1136f72d
PR
903
904 md_swapout_got(rrs_got, number_of_gotslots);
905 mywrite(rrs_got, number_of_gotslots,
906 sizeof(got_t), outdesc);
907
908 if (number_of_jmpslots <= 1)
1c8a0fd5 909 errx(1, "write_rrs_data: # jmpslots <= 1");
1136f72d
PR
910
911 md_swapout_jmpslot(rrs_plt, number_of_jmpslots);
912 mywrite(rrs_plt, number_of_jmpslots,
913 sizeof(jmpslot_t), outdesc);
914 return;
915 }
916
6a61ea88
JH
917 md_swapout__dynamic(&rrs_dyn);
918 mywrite(&rrs_dyn, 1, sizeof(struct _dynamic), outdesc);
1136f72d 919
6a61ea88
JH
920 md_swapout_so_debug(&rrs_so_debug);
921 mywrite(&rrs_so_debug, 1, sizeof(struct so_debug), outdesc);
1136f72d 922
6a61ea88
JH
923 md_swapout_section_dispatch_table(&rrs_sdt);
924 mywrite(&rrs_sdt, 1, sizeof(struct section_dispatch_table), outdesc);
1136f72d
PR
925
926 md_swapout_got(rrs_got, number_of_gotslots);
927 mywrite(rrs_got, number_of_gotslots, sizeof(got_t), outdesc);
928
929 md_swapout_jmpslot(rrs_plt, number_of_jmpslots);
930 mywrite(rrs_plt, number_of_jmpslots, sizeof(jmpslot_t), outdesc);
931}
932
933void
934write_rrs_text()
935{
936 long pos;
937 int i;
938 int symsize;
939 struct nzlist *nlp;
940 int offset = 0;
941 struct shobj *shp;
6a61ea88 942 struct sod *sodp;
1136f72d
PR
943
944 if (rrs_section_type == RRS_PARTIAL)
945 return;
946
947 pos = rrs_text_start + (N_TXTOFF(outheader) - TEXT_START(outheader));
948 if (lseek(outdesc, pos, L_SET) != pos)
1c8a0fd5 949 err(1, "write_rrs_text: lseek");
1136f72d
PR
950
951 /* Write relocation records */
952 md_swapout_reloc(rrs_reloc, reserved_rrs_relocs);
953 mywrite(rrs_reloc, reserved_rrs_relocs,
954 sizeof(struct relocation_info), outdesc);
955
956 /* Write the RRS symbol hash tables */
957 md_swapout_rrs_hash(rrs_hashtab, number_of_rrs_hash_entries);
958 mywrite(rrs_hashtab, number_of_rrs_hash_entries, sizeof(struct rrs_hash), outdesc);
959
960 /*
961 * Determine size of an RRS symbol entry, allocate space
962 * to collect them in.
963 */
964 symsize = number_of_rrs_symbols * rrs_symbol_size;
965 nlp = rrs_symbols = (struct nzlist *)alloca(symsize);
966 rrs_strtab = (char *)alloca(rrs_strtab_size);
967
968#define INCR_NLP(p) ((p) = (struct nzlist *)((long)(p) + rrs_symbol_size))
969
970 /* __DYNAMIC symbol *must* be first for Sun compatibility */
971 nlp->nz_desc = nlp->nz_other = 0;
972 if (LD_VERSION_NZLIST_P(soversion))
973 nlp->nz_size = 0;
974 nlp->nz_type = dynamic_symbol->defined;
975 nlp->nz_value = dynamic_symbol->value;
976 nlp->nz_value = dynamic_symbol->value;
977 nlp->nz_strx = offset;
978 strcpy(rrs_strtab + offset, dynamic_symbol->name);
979 offset += 1 + strlen(dynamic_symbol->name);
980 INCR_NLP(nlp);
981
982 /*
983 * Now, for each global symbol, construct a nzlist element
984 * for inclusion in the RRS symbol table.
985 */
986 FOR_EACH_SYMBOL(i, sp) {
987
6a61ea88 988 if (!(sp->flags & GS_REFERENCED) || sp == dynamic_symbol)
1136f72d
PR
989 continue;
990
991 if ((long)nlp - (long)rrs_symbols >=
992 number_of_rrs_symbols * rrs_symbol_size)
1c8a0fd5 993 errx(1,
1136f72d
PR
994 "internal error: rrs symbols exceed allocation %d ",
995 number_of_rrs_symbols);
996
997 nlp->nz_desc = 0;
998 nlp->nz_other = 0;
999 if (LD_VERSION_NZLIST_P(soversion))
1000 nlp->nz_size = 0;
1001
1002 if (sp->defined > 1) {
1003 /* defined with known type */
0f052032
JH
1004 if (!(link_mode & SHAREABLE) &&
1005 sp->alias && sp->alias->defined > 1) {
1006 /*
1007 * If the target of an indirect symbol has
1008 * been defined and we are outputting an
1009 * executable, resolve the indirection; it's
1010 * no longer needed.
1011 */
1012 nlp->nz_type = sp->alias->defined;
1013 nlp->nz_value = sp->alias->value;
6a61ea88 1014 nlp->nz_other = N_OTHER(0, sp->alias->aux);
0f052032 1015 } else if (sp->defined == N_SIZE) {
1136f72d
PR
1016 /*
1017 * Make sure this symbol isn't going
1018 * to define anything.
1019 */
1020 nlp->nz_type = N_UNDF;
1021 nlp->nz_value = 0;
1022 } else {
1023 nlp->nz_type = sp->defined;
1024 nlp->nz_value = sp->value;
6a61ea88 1025 nlp->nz_other = N_OTHER(0, sp->aux);
1136f72d
PR
1026 }
1027 if (LD_VERSION_NZLIST_P(soversion))
1028 nlp->nz_size = sp->size;
6a61ea88 1029 } else if (sp->common_size) {
1136f72d
PR
1030 /*
1031 * a common definition
1032 */
1033 nlp->nz_type = N_UNDF | N_EXT;
6a61ea88 1034 nlp->nz_value = sp->common_size;
1136f72d
PR
1035 } else if (!sp->defined) {
1036 /* undefined */
1037 nlp->nz_type = N_UNDF | N_EXT;
1038 nlp->nz_value = 0;
6a61ea88
JH
1039 if (sp->so_defined && sp->jmpslot_offset != -1) {
1040 /*
1041 * Define a "weak" function symbol.
1042 */
1043 if (sp->aux != AUX_FUNC)
1c8a0fd5 1044 errx(1, "%s: non-function jmpslot",
6a61ea88
JH
1045 sp->name);
1046 nlp->nz_other = N_OTHER(0, sp->aux);
1047 nlp->nz_value =
1048 rrs_sdt.sdt_plt + sp->jmpslot_offset;
1049 }
1136f72d 1050 } else
1c8a0fd5 1051 errx(1,
1136f72d
PR
1052 "internal error: %s defined in mysterious way",
1053 sp->name);
1054
80f25b52 1055 /* Set symbol's name */
1136f72d
PR
1056 nlp->nz_strx = offset;
1057 strcpy(rrs_strtab + offset, sp->name);
1058 offset += 1 + strlen(sp->name);
1059
0f052032
JH
1060 if (sp->alias) {
1061 /*
1062 * Write an extra symbol for indirections (possibly
1063 * just a dummy).
1064 */
1065 int t = (nlp->nz_type == N_INDR + N_EXT);
1066
1067 INCR_NLP(nlp);
1068 nlp->nz_type = N_UNDF + t?N_EXT:0;
1069 nlp->nz_un.n_strx = offset;
1070 nlp->nz_value = 0;
1071 nlp->nz_other = 0;
1072 nlp->nz_desc = 0;
1073 nlp->nz_size = 0;
1074 strcpy(rrs_strtab + offset, sp->alias->name);
1075 offset += 1 + strlen(sp->alias->name);
1076 }
1077
1136f72d
PR
1078 INCR_NLP(nlp);
1079
1080 } END_EACH_SYMBOL;
1081
1082 if (MALIGN(offset) != rrs_strtab_size)
1c8a0fd5 1083 errx(1,
0f052032
JH
1084 "internal error: inconsistent RRS string table length: %d, expected %d",
1085 offset, rrs_strtab_size);
1136f72d
PR
1086
1087 /* Write the symbol table */
1088 if (rrs_symbol_size == sizeof(struct nlist))
1089 md_swapout_symbols(rrs_symbols, number_of_rrs_symbols);
1090 else
1091 md_swapout_zsymbols(rrs_symbols, number_of_rrs_symbols);
1092 mywrite(rrs_symbols, symsize, 1, outdesc);
1093
1094 /* Write the strings */
1095 mywrite(rrs_strtab, rrs_strtab_size, 1, outdesc);
1096
1097 /*
1098 * Write the names of the shared objects needed at run-time
1099 */
6a61ea88
JH
1100 pos = rrs_sdt.sdt_sods + number_of_shobjs * sizeof(struct sod);
1101 sodp = (struct sod *)alloca( number_of_shobjs * sizeof(struct sod));
1136f72d
PR
1102
1103 for (i = 0, shp = rrs_shobjs; shp; i++, shp = shp->next) {
1104 char *name = shp->entry->local_sym_name;
1105
0f052032 1106 if (i >= number_of_shobjs)
1c8a0fd5 1107 errx(1, "internal error: # of link objects exceeds %d",
0f052032 1108 number_of_shobjs);
1136f72d 1109
6a61ea88
JH
1110 sodp[i].sod_name = pos;
1111 sodp[i].sod_major = shp->entry->lib_major;
1112 sodp[i].sod_minor = shp->entry->lib_minor;
1136f72d
PR
1113
1114 if (*name == '-' && *(name+1) == 'l') {
1115 name += 2;
6a61ea88 1116 sodp[i].sod_library = 1;
1136f72d 1117 } else
6a61ea88 1118 sodp[i].sod_library = 0;
1136f72d
PR
1119
1120 pos += 1 + strlen(name);
6a61ea88
JH
1121 sodp[i].sod_next = (i == number_of_shobjs - 1) ? 0 :
1122 (rrs_sdt.sdt_sods + (i+1)*sizeof(struct sod));
1558d71a 1123 }
0f052032
JH
1124
1125 if (i < number_of_shobjs)
1c8a0fd5
PR
1126 errx(1,
1127 "internal error: # of link objects less then expected %d",
0f052032 1128 number_of_shobjs);
1136f72d 1129
6a61ea88
JH
1130 md_swapout_sod(sodp, number_of_shobjs);
1131 mywrite(sodp, number_of_shobjs, sizeof(struct sod), outdesc);
1136f72d
PR
1132
1133 for (i = 0, shp = rrs_shobjs; shp; i++, shp = shp->next) {
1134 char *name = shp->entry->local_sym_name;
1135
1136 if (*name == '-' && *(name+1) == 'l') {
1137 name += 2;
1138 }
1139
1140 mywrite(name, strlen(name) + 1, 1, outdesc);
1141 }
1142}
1143
1144void
1145write_rrs()
1146{
1147
1148 /*
1149 * First, do some consistency checks on the RRS segment.
1150 */
1151 if (rrs_section_type == RRS_NONE) {
1152 if (reserved_rrs_relocs > 1)
1c8a0fd5 1153 errx(1,
1136f72d
PR
1154 "internal error: RRS relocs in static program: %d",
1155 reserved_rrs_relocs-1);
1156 return;
1157 }
1158
1159#ifdef DEBUG
1160printf("rrs_relocs %d, gotslots %d, jmpslots %d\n",
1161 reserved_rrs_relocs, number_of_gotslots-1, number_of_jmpslots-1);
1162#endif
1163
1c8a0fd5
PR
1164#if 0
1165 /* Must fix this check: misses out when linking PIC code but no
1166 shared object involved: reserved relocs are never claimed!
1167 */
1136f72d 1168 if (claimed_rrs_relocs != reserved_rrs_relocs) {
1c8a0fd5 1169 errx(1, "internal error: reserved relocs(%d) != claimed(%d)",
1136f72d 1170 reserved_rrs_relocs, claimed_rrs_relocs);
1136f72d
PR
1171 printf("FIX:internal error: reserved relocs(%d) != claimed(%d)\n",
1172 reserved_rrs_relocs, claimed_rrs_relocs);
1173 }
1c8a0fd5 1174#endif
1136f72d
PR
1175
1176 /* Write the RRS segments. */
1177 write_rrs_text ();
1178 write_rrs_data ();
1179}