diff options
Diffstat (limited to 'bfd/sunos.c')
-rw-r--r-- | bfd/sunos.c | 2845 |
1 files changed, 0 insertions, 2845 deletions
diff --git a/bfd/sunos.c b/bfd/sunos.c deleted file mode 100644 index 5985384..0000000 --- a/bfd/sunos.c +++ /dev/null @@ -1,2845 +0,0 @@ -/* BFD backend for SunOS binaries. - Copyright (C) 1990-2018 Free Software Foundation, Inc. - Written by Cygnus Support. - - This file is part of BFD, the Binary File Descriptor library. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#define TARGETNAME "a.out-sunos-big" - -/* Do not "beautify" the CONCAT* macro args. Traditional C will not - remove whitespace added here, and thus will fail to concatenate - the tokens. */ -#define MY(OP) CONCAT2 (sparc_aout_sunos_be_,OP) - -#include "sysdep.h" -#include "bfd.h" -#include "bfdlink.h" -#include "libaout.h" - -/* ??? Where should this go? */ -#define MACHTYPE_OK(mtype) \ - (((mtype) == M_SPARC && bfd_lookup_arch (bfd_arch_sparc, 0) != NULL) \ - || ((mtype) == M_SPARCLET \ - && bfd_lookup_arch (bfd_arch_sparc, bfd_mach_sparc_sparclet) != NULL) \ - || ((mtype) == M_SPARCLITE_LE \ - && bfd_lookup_arch (bfd_arch_sparc, bfd_mach_sparc_sparclet) != NULL) \ - || (((mtype) == M_UNKNOWN || (mtype) == M_68010 || (mtype) == M_68020) \ - && bfd_lookup_arch (bfd_arch_m68k, 0) != NULL)) - -#define MY_get_dynamic_symtab_upper_bound sunos_get_dynamic_symtab_upper_bound -#define MY_canonicalize_dynamic_symtab sunos_canonicalize_dynamic_symtab -#define MY_get_synthetic_symtab _bfd_nodynamic_get_synthetic_symtab -#define MY_get_dynamic_reloc_upper_bound sunos_get_dynamic_reloc_upper_bound -#define MY_canonicalize_dynamic_reloc sunos_canonicalize_dynamic_reloc -#define MY_bfd_link_hash_table_create sunos_link_hash_table_create -#define MY_add_dynamic_symbols sunos_add_dynamic_symbols -#define MY_add_one_symbol sunos_add_one_symbol -#define MY_link_dynamic_object sunos_link_dynamic_object -#define MY_write_dynamic_symbol sunos_write_dynamic_symbol -#define MY_check_dynamic_reloc sunos_check_dynamic_reloc -#define MY_finish_dynamic_link sunos_finish_dynamic_link - -static bfd_boolean sunos_add_dynamic_symbols (bfd *, struct bfd_link_info *, struct external_nlist **, bfd_size_type *, char **); -static bfd_boolean sunos_add_one_symbol (struct bfd_link_info *, bfd *, const char *, flagword, asection *, bfd_vma, const char *, bfd_boolean, bfd_boolean, struct bfd_link_hash_entry **); -static bfd_boolean sunos_link_dynamic_object (struct bfd_link_info *, bfd *); -static bfd_boolean sunos_write_dynamic_symbol (bfd *, struct bfd_link_info *, struct aout_link_hash_entry *); -static bfd_boolean sunos_check_dynamic_reloc (struct bfd_link_info *, bfd *, asection *, struct aout_link_hash_entry *, void *, bfd_byte *, bfd_boolean *, bfd_vma *); -static bfd_boolean sunos_finish_dynamic_link (bfd *, struct bfd_link_info *); -static struct bfd_link_hash_table *sunos_link_hash_table_create (bfd *); -static long sunos_get_dynamic_symtab_upper_bound (bfd *); -static long sunos_canonicalize_dynamic_symtab (bfd *, asymbol **); -static long sunos_get_dynamic_reloc_upper_bound (bfd *); -static long sunos_canonicalize_dynamic_reloc (bfd *, arelent **, asymbol **); - -/* Include the usual a.out support. */ -#include "aoutf1.h" - -/* The SunOS 4.1.4 /usr/include/locale.h defines valid as a macro. */ -#undef valid - -/* SunOS shared library support. We store a pointer to this structure - in obj_aout_dynamic_info (abfd). */ - -struct sunos_dynamic_info -{ - /* Whether we found any dynamic information. */ - bfd_boolean valid; - /* Dynamic information. */ - struct internal_sun4_dynamic_link dyninfo; - /* Number of dynamic symbols. */ - unsigned long dynsym_count; - /* Read in nlists for dynamic symbols. */ - struct external_nlist *dynsym; - /* asymbol structures for dynamic symbols. */ - aout_symbol_type *canonical_dynsym; - /* Read in dynamic string table. */ - char *dynstr; - /* Number of dynamic relocs. */ - unsigned long dynrel_count; - /* Read in dynamic relocs. This may be reloc_std_external or - reloc_ext_external. */ - void * dynrel; - /* arelent structures for dynamic relocs. */ - arelent *canonical_dynrel; -}; - -/* The hash table of dynamic symbols is composed of two word entries. - See include/aout/sun4.h for details. */ - -#define HASH_ENTRY_SIZE (2 * BYTES_IN_WORD) - -/* Read in the basic dynamic information. This locates the __DYNAMIC - structure and uses it to find the dynamic_link structure. It - creates and saves a sunos_dynamic_info structure. If it can't find - __DYNAMIC, it sets the valid field of the sunos_dynamic_info - structure to FALSE to avoid doing this work again. */ - -static bfd_boolean -sunos_read_dynamic_info (bfd *abfd) -{ - struct sunos_dynamic_info *info; - asection *dynsec; - bfd_vma dynoff; - struct external_sun4_dynamic dyninfo; - unsigned long dynver; - struct external_sun4_dynamic_link linkinfo; - bfd_size_type amt; - - if (obj_aout_dynamic_info (abfd) != NULL) - return TRUE; - - if ((abfd->flags & DYNAMIC) == 0) - { - bfd_set_error (bfd_error_invalid_operation); - return FALSE; - } - - amt = sizeof (struct sunos_dynamic_info); - info = bfd_zalloc (abfd, amt); - if (!info) - return FALSE; - info->valid = FALSE; - info->dynsym = NULL; - info->dynstr = NULL; - info->canonical_dynsym = NULL; - info->dynrel = NULL; - info->canonical_dynrel = NULL; - obj_aout_dynamic_info (abfd) = (void *) info; - - /* This code used to look for the __DYNAMIC symbol to locate the dynamic - linking information. - However this inhibits recovering the dynamic symbols from a - stripped object file, so blindly assume that the dynamic linking - information is located at the start of the data section. - We could verify this assumption later by looking through the dynamic - symbols for the __DYNAMIC symbol. */ - if ((abfd->flags & DYNAMIC) == 0) - return TRUE; - if (! bfd_get_section_contents (abfd, obj_datasec (abfd), (void *) &dyninfo, - (file_ptr) 0, - (bfd_size_type) sizeof dyninfo)) - return TRUE; - - dynver = GET_WORD (abfd, dyninfo.ld_version); - if (dynver != 2 && dynver != 3) - return TRUE; - - dynoff = GET_WORD (abfd, dyninfo.ld); - - /* dynoff is a virtual address. It is probably always in the .data - section, but this code should work even if it moves. */ - if (dynoff < bfd_get_section_vma (abfd, obj_datasec (abfd))) - dynsec = obj_textsec (abfd); - else - dynsec = obj_datasec (abfd); - dynoff -= bfd_get_section_vma (abfd, dynsec); - if (dynoff > dynsec->size) - return TRUE; - - /* This executable appears to be dynamically linked in a way that we - can understand. */ - if (! bfd_get_section_contents (abfd, dynsec, (void *) &linkinfo, - (file_ptr) dynoff, - (bfd_size_type) sizeof linkinfo)) - return TRUE; - - /* Swap in the dynamic link information. */ - info->dyninfo.ld_loaded = GET_WORD (abfd, linkinfo.ld_loaded); - info->dyninfo.ld_need = GET_WORD (abfd, linkinfo.ld_need); - info->dyninfo.ld_rules = GET_WORD (abfd, linkinfo.ld_rules); - info->dyninfo.ld_got = GET_WORD (abfd, linkinfo.ld_got); - info->dyninfo.ld_plt = GET_WORD (abfd, linkinfo.ld_plt); - info->dyninfo.ld_rel = GET_WORD (abfd, linkinfo.ld_rel); - info->dyninfo.ld_hash = GET_WORD (abfd, linkinfo.ld_hash); - info->dyninfo.ld_stab = GET_WORD (abfd, linkinfo.ld_stab); - info->dyninfo.ld_stab_hash = GET_WORD (abfd, linkinfo.ld_stab_hash); - info->dyninfo.ld_buckets = GET_WORD (abfd, linkinfo.ld_buckets); - info->dyninfo.ld_symbols = GET_WORD (abfd, linkinfo.ld_symbols); - info->dyninfo.ld_symb_size = GET_WORD (abfd, linkinfo.ld_symb_size); - info->dyninfo.ld_text = GET_WORD (abfd, linkinfo.ld_text); - info->dyninfo.ld_plt_sz = GET_WORD (abfd, linkinfo.ld_plt_sz); - - /* Reportedly the addresses need to be offset by the size of the - exec header in an NMAGIC file. */ - if (adata (abfd).magic == n_magic) - { - unsigned long exec_bytes_size = adata (abfd).exec_bytes_size; - - info->dyninfo.ld_need += exec_bytes_size; - info->dyninfo.ld_rules += exec_bytes_size; - info->dyninfo.ld_rel += exec_bytes_size; - info->dyninfo.ld_hash += exec_bytes_size; - info->dyninfo.ld_stab += exec_bytes_size; - info->dyninfo.ld_symbols += exec_bytes_size; - } - - /* The only way to get the size of the symbol information appears to - be to determine the distance between it and the string table. */ - info->dynsym_count = ((info->dyninfo.ld_symbols - info->dyninfo.ld_stab) - / EXTERNAL_NLIST_SIZE); - BFD_ASSERT (info->dynsym_count * EXTERNAL_NLIST_SIZE - == (unsigned long) (info->dyninfo.ld_symbols - - info->dyninfo.ld_stab)); - - /* Similarly, the relocs end at the hash table. */ - info->dynrel_count = ((info->dyninfo.ld_hash - info->dyninfo.ld_rel) - / obj_reloc_entry_size (abfd)); - BFD_ASSERT (info->dynrel_count * obj_reloc_entry_size (abfd) - == (unsigned long) (info->dyninfo.ld_hash - - info->dyninfo.ld_rel)); - - info->valid = TRUE; - - return TRUE; -} - -/* Return the amount of memory required for the dynamic symbols. */ - -static long -sunos_get_dynamic_symtab_upper_bound (bfd *abfd) -{ - struct sunos_dynamic_info *info; - - if (! sunos_read_dynamic_info (abfd)) - return -1; - - info = (struct sunos_dynamic_info *) obj_aout_dynamic_info (abfd); - if (! info->valid) - { - bfd_set_error (bfd_error_no_symbols); - return -1; - } - - return (info->dynsym_count + 1) * sizeof (asymbol *); -} - -/* Read the external dynamic symbols. */ - -static bfd_boolean -sunos_slurp_dynamic_symtab (bfd *abfd) -{ - struct sunos_dynamic_info *info; - bfd_size_type amt; - - /* Get the general dynamic information. */ - if (obj_aout_dynamic_info (abfd) == NULL) - { - if (! sunos_read_dynamic_info (abfd)) - return FALSE; - } - - info = (struct sunos_dynamic_info *) obj_aout_dynamic_info (abfd); - if (! info->valid) - { - bfd_set_error (bfd_error_no_symbols); - return FALSE; - } - - /* Get the dynamic nlist structures. */ - if (info->dynsym == NULL) - { - amt = (bfd_size_type) info->dynsym_count * EXTERNAL_NLIST_SIZE; - info->dynsym = bfd_alloc (abfd, amt); - if (info->dynsym == NULL && info->dynsym_count != 0) - return FALSE; - if (bfd_seek (abfd, (file_ptr) info->dyninfo.ld_stab, SEEK_SET) != 0 - || bfd_bread ((void *) info->dynsym, amt, abfd) != amt) - { - if (info->dynsym != NULL) - { - bfd_release (abfd, info->dynsym); - info->dynsym = NULL; - } - return FALSE; - } - } - - /* Get the dynamic strings. */ - if (info->dynstr == NULL) - { - amt = info->dyninfo.ld_symb_size; - info->dynstr = bfd_alloc (abfd, amt); - if (info->dynstr == NULL && info->dyninfo.ld_symb_size != 0) - return FALSE; - if (bfd_seek (abfd, (file_ptr) info->dyninfo.ld_symbols, SEEK_SET) != 0 - || bfd_bread ((void *) info->dynstr, amt, abfd) != amt) - { - if (info->dynstr != NULL) - { - bfd_release (abfd, info->dynstr); - info->dynstr = NULL; - } - return FALSE; - } - } - - return TRUE; -} - -/* Read in the dynamic symbols. */ - -static long -sunos_canonicalize_dynamic_symtab (bfd *abfd, asymbol **storage) -{ - struct sunos_dynamic_info *info; - unsigned long i; - - if (! sunos_slurp_dynamic_symtab (abfd)) - return -1; - - info = (struct sunos_dynamic_info *) obj_aout_dynamic_info (abfd); - -#ifdef CHECK_DYNAMIC_HASH - /* Check my understanding of the dynamic hash table by making sure - that each symbol can be located in the hash table. */ - { - bfd_size_type table_size; - bfd_byte *table; - bfd_size_type i; - - if (info->dyninfo.ld_buckets > info->dynsym_count) - abort (); - table_size = info->dyninfo.ld_stab - info->dyninfo.ld_hash; - table = bfd_malloc (table_size); - if (table == NULL && table_size != 0) - abort (); - if (bfd_seek (abfd, (file_ptr) info->dyninfo.ld_hash, SEEK_SET) != 0 - || bfd_bread ((void *) table, table_size, abfd) != table_size) - abort (); - for (i = 0; i < info->dynsym_count; i++) - { - unsigned char *name; - unsigned long hash; - - name = ((unsigned char *) info->dynstr - + GET_WORD (abfd, info->dynsym[i].e_strx)); - hash = 0; - while (*name != '\0') - hash = (hash << 1) + *name++; - hash &= 0x7fffffff; - hash %= info->dyninfo.ld_buckets; - while (GET_WORD (abfd, table + hash * HASH_ENTRY_SIZE) != i) - { - hash = GET_WORD (abfd, - table + hash * HASH_ENTRY_SIZE + BYTES_IN_WORD); - if (hash == 0 || hash >= table_size / HASH_ENTRY_SIZE) - abort (); - } - } - free (table); - } -#endif /* CHECK_DYNAMIC_HASH */ - - /* Get the asymbol structures corresponding to the dynamic nlist - structures. */ - if (info->canonical_dynsym == NULL) - { - bfd_size_type size; - bfd_size_type strsize = info->dyninfo.ld_symb_size; - - size = (bfd_size_type) info->dynsym_count * sizeof (aout_symbol_type); - info->canonical_dynsym = bfd_alloc (abfd, size); - if (info->canonical_dynsym == NULL && info->dynsym_count != 0) - return -1; - - if (! aout_32_translate_symbol_table (abfd, info->canonical_dynsym, - info->dynsym, - (bfd_size_type) info->dynsym_count, - info->dynstr, strsize, TRUE)) - { - if (info->canonical_dynsym != NULL) - { - bfd_release (abfd, info->canonical_dynsym); - info->canonical_dynsym = NULL; - } - return -1; - } - } - - /* Return pointers to the dynamic asymbol structures. */ - for (i = 0; i < info->dynsym_count; i++) - *storage++ = (asymbol *) (info->canonical_dynsym + i); - *storage = NULL; - - return info->dynsym_count; -} - -/* Return the amount of memory required for the dynamic relocs. */ - -static long -sunos_get_dynamic_reloc_upper_bound (bfd *abfd) -{ - struct sunos_dynamic_info *info; - - if (! sunos_read_dynamic_info (abfd)) - return -1; - - info = (struct sunos_dynamic_info *) obj_aout_dynamic_info (abfd); - if (! info->valid) - { - bfd_set_error (bfd_error_no_symbols); - return -1; - } - - return (info->dynrel_count + 1) * sizeof (arelent *); -} - -/* Read in the dynamic relocs. */ - -static long -sunos_canonicalize_dynamic_reloc (bfd *abfd, arelent **storage, asymbol **syms) -{ - struct sunos_dynamic_info *info; - unsigned long i; - bfd_size_type size; - - /* Get the general dynamic information. */ - if (obj_aout_dynamic_info (abfd) == NULL) - { - if (! sunos_read_dynamic_info (abfd)) - return -1; - } - - info = (struct sunos_dynamic_info *) obj_aout_dynamic_info (abfd); - if (! info->valid) - { - bfd_set_error (bfd_error_no_symbols); - return -1; - } - - /* Get the dynamic reloc information. */ - if (info->dynrel == NULL) - { - size = (bfd_size_type) info->dynrel_count * obj_reloc_entry_size (abfd); - info->dynrel = bfd_alloc (abfd, size); - if (info->dynrel == NULL && size != 0) - return -1; - if (bfd_seek (abfd, (file_ptr) info->dyninfo.ld_rel, SEEK_SET) != 0 - || bfd_bread ((void *) info->dynrel, size, abfd) != size) - { - if (info->dynrel != NULL) - { - bfd_release (abfd, info->dynrel); - info->dynrel = NULL; - } - return -1; - } - } - - /* Get the arelent structures corresponding to the dynamic reloc - information. */ - if (info->canonical_dynrel == NULL) - { - arelent *to; - - size = (bfd_size_type) info->dynrel_count * sizeof (arelent); - info->canonical_dynrel = bfd_alloc (abfd, size); - if (info->canonical_dynrel == NULL && info->dynrel_count != 0) - return -1; - - to = info->canonical_dynrel; - - if (obj_reloc_entry_size (abfd) == RELOC_EXT_SIZE) - { - struct reloc_ext_external *p; - struct reloc_ext_external *pend; - - p = (struct reloc_ext_external *) info->dynrel; - pend = p + info->dynrel_count; - for (; p < pend; p++, to++) - NAME (aout, swap_ext_reloc_in) (abfd, p, to, syms, - (bfd_size_type) info->dynsym_count); - } - else - { - struct reloc_std_external *p; - struct reloc_std_external *pend; - - p = (struct reloc_std_external *) info->dynrel; - pend = p + info->dynrel_count; - for (; p < pend; p++, to++) - NAME (aout, swap_std_reloc_in) (abfd, p, to, syms, - (bfd_size_type) info->dynsym_count); - } - } - - /* Return pointers to the dynamic arelent structures. */ - for (i = 0; i < info->dynrel_count; i++) - *storage++ = info->canonical_dynrel + i; - *storage = NULL; - - return info->dynrel_count; -} - -/* Code to handle linking of SunOS shared libraries. */ - -/* A SPARC procedure linkage table entry is 12 bytes. The first entry - in the table is a jump which is filled in by the runtime linker. - The remaining entries are branches back to the first entry, - followed by an index into the relocation table encoded to look like - a sethi of %g0. */ - -#define SPARC_PLT_ENTRY_SIZE (12) - -static const bfd_byte sparc_plt_first_entry[SPARC_PLT_ENTRY_SIZE] = -{ - /* sethi %hi(0),%g1; address filled in by runtime linker. */ - 0x3, 0, 0, 0, - /* jmp %g1; offset filled in by runtime linker. */ - 0x81, 0xc0, 0x60, 0, - /* nop */ - 0x1, 0, 0, 0 -}; - -/* save %sp, -96, %sp */ -#define SPARC_PLT_ENTRY_WORD0 ((bfd_vma) 0x9de3bfa0) -/* call; address filled in later. */ -#define SPARC_PLT_ENTRY_WORD1 ((bfd_vma) 0x40000000) -/* sethi; reloc index filled in later. */ -#define SPARC_PLT_ENTRY_WORD2 ((bfd_vma) 0x01000000) - -/* This sequence is used when for the jump table entry to a defined - symbol in a complete executable. It is used when linking PIC - compiled code which is not being put into a shared library. */ -/* sethi <address to be filled in later>, %g1 */ -#define SPARC_PLT_PIC_WORD0 ((bfd_vma) 0x03000000) -/* jmp %g1 + <address to be filled in later> */ -#define SPARC_PLT_PIC_WORD1 ((bfd_vma) 0x81c06000) -/* nop */ -#define SPARC_PLT_PIC_WORD2 ((bfd_vma) 0x01000000) - -/* An m68k procedure linkage table entry is 8 bytes. The first entry - in the table is a jump which is filled in the by the runtime - linker. The remaining entries are branches back to the first - entry, followed by a two byte index into the relocation table. */ - -#define M68K_PLT_ENTRY_SIZE (8) - -static const bfd_byte m68k_plt_first_entry[M68K_PLT_ENTRY_SIZE] = -{ - /* jmps @# */ - 0x4e, 0xf9, - /* Filled in by runtime linker with a magic address. */ - 0, 0, 0, 0, - /* Not used? */ - 0, 0 -}; - -/* bsrl */ -#define M68K_PLT_ENTRY_WORD0 ((bfd_vma) 0x61ff) -/* Remaining words filled in later. */ - -/* An entry in the SunOS linker hash table. */ - -struct sunos_link_hash_entry -{ - struct aout_link_hash_entry root; - - /* If this is a dynamic symbol, this is its index into the dynamic - symbol table. This is initialized to -1. As the linker looks at - the input files, it changes this to -2 if it will be added to the - dynamic symbol table. After all the input files have been seen, - the linker will know whether to build a dynamic symbol table; if - it does build one, this becomes the index into the table. */ - long dynindx; - - /* If this is a dynamic symbol, this is the index of the name in the - dynamic symbol string table. */ - long dynstr_index; - - /* The offset into the global offset table used for this symbol. If - the symbol does not require a GOT entry, this is 0. */ - bfd_vma got_offset; - - /* The offset into the procedure linkage table used for this symbol. - If the symbol does not require a PLT entry, this is 0. */ - bfd_vma plt_offset; - - /* Some linker flags. */ - unsigned char flags; - /* Symbol is referenced by a regular object. */ -#define SUNOS_REF_REGULAR 01 - /* Symbol is defined by a regular object. */ -#define SUNOS_DEF_REGULAR 02 - /* Symbol is referenced by a dynamic object. */ -#define SUNOS_REF_DYNAMIC 04 - /* Symbol is defined by a dynamic object. */ -#define SUNOS_DEF_DYNAMIC 010 - /* Symbol is a constructor symbol in a regular object. */ -#define SUNOS_CONSTRUCTOR 020 -}; - -/* The SunOS linker hash table. */ - -struct sunos_link_hash_table -{ - struct aout_link_hash_table root; - - /* The object which holds the dynamic sections. */ - bfd *dynobj; - - /* Whether we have created the dynamic sections. */ - bfd_boolean dynamic_sections_created; - - /* Whether we need the dynamic sections. */ - bfd_boolean dynamic_sections_needed; - - /* Whether we need the .got table. */ - bfd_boolean got_needed; - - /* The number of dynamic symbols. */ - size_t dynsymcount; - - /* The number of buckets in the hash table. */ - size_t bucketcount; - - /* The list of dynamic objects needed by dynamic objects included in - the link. */ - struct bfd_link_needed_list *needed; - - /* The offset of __GLOBAL_OFFSET_TABLE_ into the .got section. */ - bfd_vma got_base; -}; - -/* Routine to create an entry in an SunOS link hash table. */ - -static struct bfd_hash_entry * -sunos_link_hash_newfunc (struct bfd_hash_entry *entry, - struct bfd_hash_table *table, - const char *string) -{ - struct sunos_link_hash_entry *ret = (struct sunos_link_hash_entry *) entry; - - /* Allocate the structure if it has not already been allocated by a - subclass. */ - if (ret == NULL) - ret = bfd_hash_allocate (table, sizeof (* ret)); - if (ret == NULL) - return NULL; - - /* Call the allocation method of the superclass. */ - ret = ((struct sunos_link_hash_entry *) - NAME (aout, link_hash_newfunc) ((struct bfd_hash_entry *) ret, - table, string)); - if (ret != NULL) - { - /* Set local fields. */ - ret->dynindx = -1; - ret->dynstr_index = -1; - ret->got_offset = 0; - ret->plt_offset = 0; - ret->flags = 0; - } - - return (struct bfd_hash_entry *) ret; -} - -/* Create a SunOS link hash table. */ - -static struct bfd_link_hash_table * -sunos_link_hash_table_create (bfd *abfd) -{ - struct sunos_link_hash_table *ret; - bfd_size_type amt = sizeof (struct sunos_link_hash_table); - - ret = bfd_zmalloc (amt); - if (ret == NULL) - return NULL; - if (!NAME (aout, link_hash_table_init) (&ret->root, abfd, - sunos_link_hash_newfunc, - sizeof (struct sunos_link_hash_entry))) - { - free (ret); - return NULL; - } - - return &ret->root.root; -} - -/* Look up an entry in an SunOS link hash table. */ - -#define sunos_link_hash_lookup(table, string, create, copy, follow) \ - ((struct sunos_link_hash_entry *) \ - aout_link_hash_lookup (&(table)->root, (string), (create), (copy),\ - (follow))) - -/* Traverse a SunOS link hash table. */ - -#define sunos_link_hash_traverse(table, func, info) \ - (aout_link_hash_traverse \ - (&(table)->root, \ - (bfd_boolean (*) (struct aout_link_hash_entry *, void *)) (func), \ - (info))) - -/* Get the SunOS link hash table from the info structure. This is - just a cast. */ - -#define sunos_hash_table(p) ((struct sunos_link_hash_table *) ((p)->hash)) - -/* Create the dynamic sections needed if we are linking against a - dynamic object, or if we are linking PIC compiled code. ABFD is a - bfd we can attach the dynamic sections to. The linker script will - look for these special sections names and put them in the right - place in the output file. See include/aout/sun4.h for more details - of the dynamic linking information. */ - -static bfd_boolean -sunos_create_dynamic_sections (bfd *abfd, - struct bfd_link_info *info, - bfd_boolean needed) -{ - asection *s; - - if (! sunos_hash_table (info)->dynamic_sections_created) - { - flagword flags; - - sunos_hash_table (info)->dynobj = abfd; - - flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY - | SEC_LINKER_CREATED); - - /* The .dynamic section holds the basic dynamic information: the - sun4_dynamic structure, the dynamic debugger information, and - the sun4_dynamic_link structure. */ - s = bfd_make_section_anyway_with_flags (abfd, ".dynamic", flags); - if (s == NULL - || ! bfd_set_section_alignment (abfd, s, 2)) - return FALSE; - - /* The .got section holds the global offset table. The address - is put in the ld_got field. */ - s = bfd_make_section_anyway_with_flags (abfd, ".got", flags); - if (s == NULL - || ! bfd_set_section_alignment (abfd, s, 2)) - return FALSE; - - /* The .plt section holds the procedure linkage table. The - address is put in the ld_plt field. */ - s = bfd_make_section_anyway_with_flags (abfd, ".plt", flags | SEC_CODE); - if (s == NULL - || ! bfd_set_section_alignment (abfd, s, 2)) - return FALSE; - - /* The .dynrel section holds the dynamic relocs. The address is - put in the ld_rel field. */ - s = bfd_make_section_anyway_with_flags (abfd, ".dynrel", - flags | SEC_READONLY); - if (s == NULL - || ! bfd_set_section_alignment (abfd, s, 2)) - return FALSE; - - /* The .hash section holds the dynamic hash table. The address - is put in the ld_hash field. */ - s = bfd_make_section_anyway_with_flags (abfd, ".hash", - flags | SEC_READONLY); - if (s == NULL - || ! bfd_set_section_alignment (abfd, s, 2)) - return FALSE; - - /* The .dynsym section holds the dynamic symbols. The address - is put in the ld_stab field. */ - s = bfd_make_section_anyway_with_flags (abfd, ".dynsym", - flags | SEC_READONLY); - if (s == NULL - || ! bfd_set_section_alignment (abfd, s, 2)) - return FALSE; - - /* The .dynstr section holds the dynamic symbol string table. - The address is put in the ld_symbols field. */ - s = bfd_make_section_anyway_with_flags (abfd, ".dynstr", - flags | SEC_READONLY); - if (s == NULL - || ! bfd_set_section_alignment (abfd, s, 2)) - return FALSE; - - sunos_hash_table (info)->dynamic_sections_created = TRUE; - } - - if ((needed && ! sunos_hash_table (info)->dynamic_sections_needed) - || bfd_link_pic (info)) - { - bfd *dynobj; - - dynobj = sunos_hash_table (info)->dynobj; - - s = bfd_get_linker_section (dynobj, ".got"); - if (s->size == 0) - s->size = BYTES_IN_WORD; - - sunos_hash_table (info)->dynamic_sections_needed = TRUE; - sunos_hash_table (info)->got_needed = TRUE; - } - - return TRUE; -} - -/* Add dynamic symbols during a link. This is called by the a.out - backend linker for each object it encounters. */ - -static bfd_boolean -sunos_add_dynamic_symbols (bfd *abfd, - struct bfd_link_info *info, - struct external_nlist **symsp, - bfd_size_type *sym_countp, - char **stringsp) -{ - bfd *dynobj; - struct sunos_dynamic_info *dinfo; - unsigned long need; - - /* Make sure we have all the required sections. */ - if (info->output_bfd->xvec == abfd->xvec) - { - if (! sunos_create_dynamic_sections (abfd, info, - ((abfd->flags & DYNAMIC) != 0 - && !bfd_link_relocatable (info)))) - return FALSE; - } - - /* There is nothing else to do for a normal object. */ - if ((abfd->flags & DYNAMIC) == 0) - return TRUE; - - dynobj = sunos_hash_table (info)->dynobj; - - /* We do not want to include the sections in a dynamic object in the - output file. We hack by simply clobbering the list of sections - in the BFD. This could be handled more cleanly by, say, a new - section flag; the existing SEC_NEVER_LOAD flag is not the one we - want, because that one still implies that the section takes up - space in the output file. If this is the first object we have - seen, we must preserve the dynamic sections we just created. */ - if (abfd != dynobj) - abfd->sections = NULL; - else - { - asection *s; - - for (s = abfd->sections; s != NULL; s = s->next) - { - if ((s->flags & SEC_LINKER_CREATED) == 0) - bfd_section_list_remove (abfd, s); - } - } - - /* The native linker seems to just ignore dynamic objects when -r is - used. */ - if (bfd_link_relocatable (info)) - return TRUE; - - /* There's no hope of using a dynamic object which does not exactly - match the format of the output file. */ - if (info->output_bfd->xvec != abfd->xvec) - { - bfd_set_error (bfd_error_invalid_operation); - return FALSE; - } - - /* Make sure we have a .need and a .rules sections. These are only - needed if there really is a dynamic object in the link, so they - are not added by sunos_create_dynamic_sections. */ - if (bfd_get_section_by_name (dynobj, ".need") == NULL) - { - /* The .need section holds the list of names of shared objets - which must be included at runtime. The address of this - section is put in the ld_need field. */ - flagword flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS - | SEC_IN_MEMORY | SEC_READONLY); - asection *s = bfd_make_section_with_flags (dynobj, ".need", flags); - if (s == NULL - || ! bfd_set_section_alignment (dynobj, s, 2)) - return FALSE; - } - - if (bfd_get_section_by_name (dynobj, ".rules") == NULL) - { - /* The .rules section holds the path to search for shared - objects. The address of this section is put in the ld_rules - field. */ - flagword flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS - | SEC_IN_MEMORY | SEC_READONLY); - asection *s = bfd_make_section_with_flags (dynobj, ".rules", flags); - if (s == NULL - || ! bfd_set_section_alignment (dynobj, s, 2)) - return FALSE; - } - - /* Pick up the dynamic symbols and return them to the caller. */ - if (! sunos_slurp_dynamic_symtab (abfd)) - return FALSE; - - dinfo = (struct sunos_dynamic_info *) obj_aout_dynamic_info (abfd); - *symsp = dinfo->dynsym; - *sym_countp = dinfo->dynsym_count; - *stringsp = dinfo->dynstr; - - /* Record information about any other objects needed by this one. */ - need = dinfo->dyninfo.ld_need; - while (need != 0) - { - bfd_byte buf[16]; - unsigned long name, flags; - unsigned short major_vno, minor_vno; - struct bfd_link_needed_list *needed, **pp; - char *namebuf, *p; - bfd_size_type alc; - bfd_byte b; - char *namecopy; - - if (bfd_seek (abfd, (file_ptr) need, SEEK_SET) != 0 - || bfd_bread (buf, (bfd_size_type) 16, abfd) != 16) - return FALSE; - - /* For the format of an ld_need entry, see aout/sun4.h. We - should probably define structs for this manipulation. */ - name = bfd_get_32 (abfd, buf); - flags = bfd_get_32 (abfd, buf + 4); - major_vno = (unsigned short) bfd_get_16 (abfd, buf + 8); - minor_vno = (unsigned short) bfd_get_16 (abfd, buf + 10); - need = bfd_get_32 (abfd, buf + 12); - - alc = sizeof (struct bfd_link_needed_list); - needed = bfd_alloc (abfd, alc); - if (needed == NULL) - return FALSE; - needed->by = abfd; - - /* We return the name as [-l]name[.maj][.min]. */ - alc = 30; - namebuf = bfd_malloc (alc + 1); - if (namebuf == NULL) - return FALSE; - p = namebuf; - - if ((flags & 0x80000000) != 0) - { - *p++ = '-'; - *p++ = 'l'; - } - if (bfd_seek (abfd, (file_ptr) name, SEEK_SET) != 0) - { - free (namebuf); - return FALSE; - } - - do - { - if (bfd_bread (&b, (bfd_size_type) 1, abfd) != 1) - { - free (namebuf); - return FALSE; - } - - if ((bfd_size_type) (p - namebuf) >= alc) - { - char *n; - - alc *= 2; - n = bfd_realloc (namebuf, alc + 1); - if (n == NULL) - { - free (namebuf); - return FALSE; - } - p = n + (p - namebuf); - namebuf = n; - } - - *p++ = b; - } - while (b != '\0'); - - if (major_vno == 0) - *p = '\0'; - else - { - char majbuf[30]; - char minbuf[30]; - - sprintf (majbuf, ".%d", major_vno); - if (minor_vno == 0) - minbuf[0] = '\0'; - else - sprintf (minbuf, ".%d", minor_vno); - - if ((p - namebuf) + strlen (majbuf) + strlen (minbuf) >= alc) - { - char *n; - - alc = (p - namebuf) + strlen (majbuf) + strlen (minbuf); - n = bfd_realloc (namebuf, alc + 1); - if (n == NULL) - { - free (namebuf); - return FALSE; - } - p = n + (p - namebuf); - namebuf = n; - } - - strcpy (p, majbuf); - strcat (p, minbuf); - } - - namecopy = bfd_alloc (abfd, (bfd_size_type) strlen (namebuf) + 1); - if (namecopy == NULL) - { - free (namebuf); - return FALSE; - } - strcpy (namecopy, namebuf); - free (namebuf); - needed->name = namecopy; - - needed->next = NULL; - - for (pp = &sunos_hash_table (info)->needed; - *pp != NULL; - pp = &(*pp)->next) - ; - *pp = needed; - } - - return TRUE; -} - -/* Function to add a single symbol to the linker hash table. This is - a wrapper around _bfd_generic_link_add_one_symbol which handles the - tweaking needed for dynamic linking support. */ - -static bfd_boolean -sunos_add_one_symbol (struct bfd_link_info *info, - bfd *abfd, - const char *name, - flagword flags, - asection *section, - bfd_vma value, - const char *string, - bfd_boolean copy, - bfd_boolean collect, - struct bfd_link_hash_entry **hashp) -{ - struct sunos_link_hash_entry *h; - int new_flag; - - if ((flags & (BSF_INDIRECT | BSF_WARNING | BSF_CONSTRUCTOR)) != 0 - || ! bfd_is_und_section (section)) - h = sunos_link_hash_lookup (sunos_hash_table (info), name, TRUE, copy, - FALSE); - else - h = ((struct sunos_link_hash_entry *) - bfd_wrapped_link_hash_lookup (abfd, info, name, TRUE, copy, FALSE)); - if (h == NULL) - return FALSE; - - if (hashp != NULL) - *hashp = (struct bfd_link_hash_entry *) h; - - /* Treat a common symbol in a dynamic object as defined in the .bss - section of the dynamic object. We don't want to allocate space - for it in our process image. */ - if ((abfd->flags & DYNAMIC) != 0 - && bfd_is_com_section (section)) - section = obj_bsssec (abfd); - - if (! bfd_is_und_section (section) - && h->root.root.type != bfd_link_hash_new - && h->root.root.type != bfd_link_hash_undefined - && h->root.root.type != bfd_link_hash_defweak) - { - /* We are defining the symbol, and it is already defined. This - is a potential multiple definition error. */ - if ((abfd->flags & DYNAMIC) != 0) - { - /* The definition we are adding is from a dynamic object. - We do not want this new definition to override the - existing definition, so we pretend it is just a - reference. */ - section = bfd_und_section_ptr; - } - else if (h->root.root.type == bfd_link_hash_defined - && h->root.root.u.def.section->owner != NULL - && (h->root.root.u.def.section->owner->flags & DYNAMIC) != 0) - { - /* The existing definition is from a dynamic object. We - want to override it with the definition we just found. - Clobber the existing definition. */ - h->root.root.type = bfd_link_hash_undefined; - h->root.root.u.undef.abfd = h->root.root.u.def.section->owner; - } - else if (h->root.root.type == bfd_link_hash_common - && (h->root.root.u.c.p->section->owner->flags & DYNAMIC) != 0) - { - /* The existing definition is from a dynamic object. We - want to override it with the definition we just found. - Clobber the existing definition. We can't set it to new, - because it is on the undefined list. */ - h->root.root.type = bfd_link_hash_undefined; - h->root.root.u.undef.abfd = h->root.root.u.c.p->section->owner; - } - } - - if ((abfd->flags & DYNAMIC) != 0 - && abfd->xvec == info->output_bfd->xvec - && (h->flags & SUNOS_CONSTRUCTOR) != 0) - /* The existing symbol is a constructor symbol, and this symbol - is from a dynamic object. A constructor symbol is actually a - definition, although the type will be bfd_link_hash_undefined - at this point. We want to ignore the definition from the - dynamic object. */ - section = bfd_und_section_ptr; - else if ((flags & BSF_CONSTRUCTOR) != 0 - && (abfd->flags & DYNAMIC) == 0 - && h->root.root.type == bfd_link_hash_defined - && h->root.root.u.def.section->owner != NULL - && (h->root.root.u.def.section->owner->flags & DYNAMIC) != 0) - /* The existing symbol is defined by a dynamic object, and this - is a constructor symbol. As above, we want to force the use - of the constructor symbol from the regular object. */ - h->root.root.type = bfd_link_hash_new; - - /* Do the usual procedure for adding a symbol. */ - if (! _bfd_generic_link_add_one_symbol (info, abfd, name, flags, section, - value, string, copy, collect, - hashp)) - return FALSE; - - if (abfd->xvec == info->output_bfd->xvec) - { - /* Set a flag in the hash table entry indicating the type of - reference or definition we just found. Keep a count of the - number of dynamic symbols we find. A dynamic symbol is one - which is referenced or defined by both a regular object and a - shared object. */ - if ((abfd->flags & DYNAMIC) == 0) - { - if (bfd_is_und_section (section)) - new_flag = SUNOS_REF_REGULAR; - else - new_flag = SUNOS_DEF_REGULAR; - } - else - { - if (bfd_is_und_section (section)) - new_flag = SUNOS_REF_DYNAMIC; - else - new_flag = SUNOS_DEF_DYNAMIC; - } - h->flags |= new_flag; - - if (h->dynindx == -1 - && (h->flags & (SUNOS_DEF_REGULAR | SUNOS_REF_REGULAR)) != 0) - { - ++sunos_hash_table (info)->dynsymcount; - h->dynindx = -2; - } - - if ((flags & BSF_CONSTRUCTOR) != 0 - && (abfd->flags & DYNAMIC) == 0) - h->flags |= SUNOS_CONSTRUCTOR; - } - - return TRUE; -} - -extern const bfd_target MY (vec); - -/* Return the list of objects needed by BFD. */ - -struct bfd_link_needed_list * -bfd_sunos_get_needed_list (bfd *abfd ATTRIBUTE_UNUSED, - struct bfd_link_info *info) -{ - if (info->output_bfd->xvec != &MY (vec)) - return NULL; - return sunos_hash_table (info)->needed; -} - -/* Record an assignment made to a symbol by a linker script. We need - this in case some dynamic object refers to this symbol. */ - -bfd_boolean -bfd_sunos_record_link_assignment (bfd *output_bfd, - struct bfd_link_info *info, - const char *name) -{ - struct sunos_link_hash_entry *h; - - if (output_bfd->xvec != &MY(vec)) - return TRUE; - - /* This is called after we have examined all the input objects. If - the symbol does not exist, it merely means that no object refers - to it, and we can just ignore it at this point. */ - h = sunos_link_hash_lookup (sunos_hash_table (info), name, - FALSE, FALSE, FALSE); - if (h == NULL) - return TRUE; - - /* In a shared library, the __DYNAMIC symbol does not appear in the - dynamic symbol table. */ - if (! bfd_link_pic (info) || strcmp (name, "__DYNAMIC") != 0) - { - h->flags |= SUNOS_DEF_REGULAR; - - if (h->dynindx == -1) - { - ++sunos_hash_table (info)->dynsymcount; - h->dynindx = -2; - } - } - - return TRUE; -} - -/* Scan the relocs for an input section using standard relocs. We - need to figure out what to do for each reloc against a dynamic - symbol. If the symbol is in the .text section, an entry is made in - the procedure linkage table. Note that this will do the wrong - thing if the symbol is actually data; I don't think the Sun 3 - native linker handles this case correctly either. If the symbol is - not in the .text section, we must preserve the reloc as a dynamic - reloc. FIXME: We should also handle the PIC relocs here by - building global offset table entries. */ - -static bfd_boolean -sunos_scan_std_relocs (struct bfd_link_info *info, - bfd *abfd, - asection *sec ATTRIBUTE_UNUSED, - const struct reloc_std_external *relocs, - bfd_size_type rel_size) -{ - bfd *dynobj; - asection *splt = NULL; - asection *srel = NULL; - struct sunos_link_hash_entry **sym_hashes; - const struct reloc_std_external *rel, *relend; - - /* We only know how to handle m68k plt entries. */ - if (bfd_get_arch (abfd) != bfd_arch_m68k) - { - bfd_set_error (bfd_error_invalid_target); - return FALSE; - } - - dynobj = NULL; - - sym_hashes = (struct sunos_link_hash_entry **) obj_aout_sym_hashes (abfd); - - relend = relocs + rel_size / RELOC_STD_SIZE; - for (rel = relocs; rel < relend; rel++) - { - int r_index; - struct sunos_link_hash_entry *h; - - /* We only want relocs against external symbols. */ - if (bfd_header_big_endian (abfd)) - { - if ((rel->r_type[0] & RELOC_STD_BITS_EXTERN_BIG) == 0) - continue; - } - else - { - if ((rel->r_type[0] & RELOC_STD_BITS_EXTERN_LITTLE) == 0) - continue; - } - - /* Get the symbol index. */ - if (bfd_header_big_endian (abfd)) - r_index = ((rel->r_index[0] << 16) - | (rel->r_index[1] << 8) - | rel->r_index[2]); - else - r_index = ((rel->r_index[2] << 16) - | (rel->r_index[1] << 8) - | rel->r_index[0]); - - /* Get the hash table entry. */ - h = sym_hashes[r_index]; - if (h == NULL) - /* This should not normally happen, but it will in any case - be caught in the relocation phase. */ - continue; - - /* At this point common symbols have already been allocated, so - we don't have to worry about them. We need to consider that - we may have already seen this symbol and marked it undefined; - if the symbol is really undefined, then SUNOS_DEF_DYNAMIC - will be zero. */ - if (h->root.root.type != bfd_link_hash_defined - && h->root.root.type != bfd_link_hash_defweak - && h->root.root.type != bfd_link_hash_undefined) - continue; - - if ((h->flags & SUNOS_DEF_DYNAMIC) == 0 - || (h->flags & SUNOS_DEF_REGULAR) != 0) - continue; - - if (dynobj == NULL) - { - asection *sgot; - - if (! sunos_create_dynamic_sections (abfd, info, FALSE)) - return FALSE; - dynobj = sunos_hash_table (info)->dynobj; - splt = bfd_get_linker_section (dynobj, ".plt"); - srel = bfd_get_linker_section (dynobj, ".dynrel"); - BFD_ASSERT (splt != NULL && srel != NULL); - - sgot = bfd_get_linker_section (dynobj, ".got"); - BFD_ASSERT (sgot != NULL); - if (sgot->size == 0) - sgot->size = BYTES_IN_WORD; - sunos_hash_table (info)->got_needed = TRUE; - } - - BFD_ASSERT ((h->flags & SUNOS_REF_REGULAR) != 0); - BFD_ASSERT (h->plt_offset != 0 - || ((h->root.root.type == bfd_link_hash_defined - || h->root.root.type == bfd_link_hash_defweak) - ? (h->root.root.u.def.section->owner->flags - & DYNAMIC) != 0 - : (h->root.root.u.undef.abfd->flags & DYNAMIC) != 0)); - - /* This reloc is against a symbol defined only by a dynamic - object. */ - if (h->root.root.type == bfd_link_hash_undefined) - /* Presumably this symbol was marked as being undefined by - an earlier reloc. */ - srel->size += RELOC_STD_SIZE; - else if ((h->root.root.u.def.section->flags & SEC_CODE) == 0) - { - bfd *sub; - - /* This reloc is not in the .text section. It must be - copied into the dynamic relocs. We mark the symbol as - being undefined. */ - srel->size += RELOC_STD_SIZE; - sub = h->root.root.u.def.section->owner; - h->root.root.type = bfd_link_hash_undefined; - h->root.root.u.undef.abfd = sub; - } - else - { - /* This symbol is in the .text section. We must give it an - entry in the procedure linkage table, if we have not - already done so. We change the definition of the symbol - to the .plt section; this will cause relocs against it to - be handled correctly. */ - if (h->plt_offset == 0) - { - if (splt->size == 0) - splt->size = M68K_PLT_ENTRY_SIZE; - h->plt_offset = splt->size; - - if ((h->flags & SUNOS_DEF_REGULAR) == 0) - { - h->root.root.u.def.section = splt; - h->root.root.u.def.value = splt->size; - } - - splt->size += M68K_PLT_ENTRY_SIZE; - - /* We may also need a dynamic reloc entry. */ - if ((h->flags & SUNOS_DEF_REGULAR) == 0) - srel->size += RELOC_STD_SIZE; - } - } - } - - return TRUE; -} - -/* Scan the relocs for an input section using extended relocs. We - need to figure out what to do for each reloc against a dynamic - symbol. If the reloc is a WDISP30, and the symbol is in the .text - section, an entry is made in the procedure linkage table. - Otherwise, we must preserve the reloc as a dynamic reloc. */ - -static bfd_boolean -sunos_scan_ext_relocs (struct bfd_link_info *info, - bfd *abfd, - asection *sec ATTRIBUTE_UNUSED, - const struct reloc_ext_external *relocs, - bfd_size_type rel_size) -{ - bfd *dynobj; - struct sunos_link_hash_entry **sym_hashes; - const struct reloc_ext_external *rel, *relend; - asection *splt = NULL; - asection *sgot = NULL; - asection *srel = NULL; - bfd_size_type amt; - - /* We only know how to handle SPARC plt entries. */ - if (bfd_get_arch (abfd) != bfd_arch_sparc) - { - bfd_set_error (bfd_error_invalid_target); - return FALSE; - } - - dynobj = NULL; - - sym_hashes = (struct sunos_link_hash_entry **) obj_aout_sym_hashes (abfd); - - relend = relocs + rel_size / RELOC_EXT_SIZE; - for (rel = relocs; rel < relend; rel++) - { - unsigned int r_index; - int r_extern; - int r_type; - struct sunos_link_hash_entry *h = NULL; - - /* Swap in the reloc information. */ - if (bfd_header_big_endian (abfd)) - { - r_index = ((rel->r_index[0] << 16) - | (rel->r_index[1] << 8) - | rel->r_index[2]); - r_extern = (0 != (rel->r_type[0] & RELOC_EXT_BITS_EXTERN_BIG)); - r_type = ((rel->r_type[0] & RELOC_EXT_BITS_TYPE_BIG) - >> RELOC_EXT_BITS_TYPE_SH_BIG); - } - else - { - r_index = ((rel->r_index[2] << 16) - | (rel->r_index[1] << 8) - | rel->r_index[0]); - r_extern = (0 != (rel->r_type[0] & RELOC_EXT_BITS_EXTERN_LITTLE)); - r_type = ((rel->r_type[0] & RELOC_EXT_BITS_TYPE_LITTLE) - >> RELOC_EXT_BITS_TYPE_SH_LITTLE); - } - - if (r_extern) - { - h = sym_hashes[r_index]; - if (h == NULL) - { - /* This should not normally happen, but it will in any - case be caught in the relocation phase. */ - continue; - } - } - - /* If this is a base relative reloc, we need to make an entry in - the .got section. */ - if (r_type == RELOC_BASE10 - || r_type == RELOC_BASE13 - || r_type == RELOC_BASE22) - { - if (dynobj == NULL) - { - if (! sunos_create_dynamic_sections (abfd, info, FALSE)) - return FALSE; - dynobj = sunos_hash_table (info)->dynobj; - splt = bfd_get_linker_section (dynobj, ".plt"); - sgot = bfd_get_linker_section (dynobj, ".got"); - srel = bfd_get_linker_section (dynobj, ".dynrel"); - BFD_ASSERT (splt != NULL && sgot != NULL && srel != NULL); - - /* Make sure we have an initial entry in the .got table. */ - if (sgot->size == 0) - sgot->size = BYTES_IN_WORD; - sunos_hash_table (info)->got_needed = TRUE; - } - - if (r_extern) - { - if (h->got_offset != 0) - continue; - - h->got_offset = sgot->size; - } - else - { - if (r_index >= bfd_get_symcount (abfd)) - /* This is abnormal, but should be caught in the - relocation phase. */ - continue; - - if (adata (abfd).local_got_offsets == NULL) - { - amt = bfd_get_symcount (abfd); - amt *= sizeof (bfd_vma); - adata (abfd).local_got_offsets = bfd_zalloc (abfd, amt); - if (adata (abfd).local_got_offsets == NULL) - return FALSE; - } - - if (adata (abfd).local_got_offsets[r_index] != 0) - continue; - - adata (abfd).local_got_offsets[r_index] = sgot->size; - } - - sgot->size += BYTES_IN_WORD; - - /* If we are making a shared library, or if the symbol is - defined by a dynamic object, we will need a dynamic reloc - entry. */ - if (bfd_link_pic (info) - || (h != NULL - && (h->flags & SUNOS_DEF_DYNAMIC) != 0 - && (h->flags & SUNOS_DEF_REGULAR) == 0)) - srel->size += RELOC_EXT_SIZE; - - continue; - } - - /* Otherwise, we are only interested in relocs against symbols - defined in dynamic objects but not in regular objects. We - only need to consider relocs against external symbols. */ - if (! r_extern) - { - /* But, if we are creating a shared library, we need to - generate an absolute reloc. */ - if (bfd_link_pic (info)) - { - if (dynobj == NULL) - { - if (! sunos_create_dynamic_sections (abfd, info, TRUE)) - return FALSE; - dynobj = sunos_hash_table (info)->dynobj; - splt = bfd_get_linker_section (dynobj, ".plt"); - sgot = bfd_get_linker_section (dynobj, ".got"); - srel = bfd_get_linker_section (dynobj, ".dynrel"); - BFD_ASSERT (splt != NULL && sgot != NULL && srel != NULL); - } - - srel->size += RELOC_EXT_SIZE; - } - - continue; - } - - /* At this point common symbols have already been allocated, so - we don't have to worry about them. We need to consider that - we may have already seen this symbol and marked it undefined; - if the symbol is really undefined, then SUNOS_DEF_DYNAMIC - will be zero. */ - if (h->root.root.type != bfd_link_hash_defined - && h->root.root.type != bfd_link_hash_defweak - && h->root.root.type != bfd_link_hash_undefined) - continue; - - if (r_type != RELOC_JMP_TBL - && ! bfd_link_pic (info) - && ((h->flags & SUNOS_DEF_DYNAMIC) == 0 - || (h->flags & SUNOS_DEF_REGULAR) != 0)) - continue; - - if (r_type == RELOC_JMP_TBL - && ! bfd_link_pic (info) - && (h->flags & SUNOS_DEF_DYNAMIC) == 0 - && (h->flags & SUNOS_DEF_REGULAR) == 0) - { - /* This symbol is apparently undefined. Don't do anything - here; just let the relocation routine report an undefined - symbol. */ - continue; - } - - if (strcmp (h->root.root.root.string, "__GLOBAL_OFFSET_TABLE_") == 0) - continue; - - if (dynobj == NULL) - { - if (! sunos_create_dynamic_sections (abfd, info, FALSE)) - return FALSE; - dynobj = sunos_hash_table (info)->dynobj; - splt = bfd_get_linker_section (dynobj, ".plt"); - sgot = bfd_get_linker_section (dynobj, ".got"); - srel = bfd_get_linker_section (dynobj, ".dynrel"); - BFD_ASSERT (splt != NULL && sgot != NULL && srel != NULL); - - /* Make sure we have an initial entry in the .got table. */ - if (sgot->size == 0) - sgot->size = BYTES_IN_WORD; - sunos_hash_table (info)->got_needed = TRUE; - } - - BFD_ASSERT (r_type == RELOC_JMP_TBL - || bfd_link_pic (info) - || (h->flags & SUNOS_REF_REGULAR) != 0); - BFD_ASSERT (r_type == RELOC_JMP_TBL - || bfd_link_pic (info) - || h->plt_offset != 0 - || ((h->root.root.type == bfd_link_hash_defined - || h->root.root.type == bfd_link_hash_defweak) - ? (h->root.root.u.def.section->owner->flags - & DYNAMIC) != 0 - : (h->root.root.u.undef.abfd->flags & DYNAMIC) != 0)); - - /* This reloc is against a symbol defined only by a dynamic - object, or it is a jump table reloc from PIC compiled code. */ - - if (r_type != RELOC_JMP_TBL - && h->root.root.type == bfd_link_hash_undefined) - /* Presumably this symbol was marked as being undefined by - an earlier reloc. */ - srel->size += RELOC_EXT_SIZE; - - else if (r_type != RELOC_JMP_TBL - && (h->root.root.u.def.section->flags & SEC_CODE) == 0) - { - bfd *sub; - - /* This reloc is not in the .text section. It must be - copied into the dynamic relocs. We mark the symbol as - being undefined. */ - srel->size += RELOC_EXT_SIZE; - if ((h->flags & SUNOS_DEF_REGULAR) == 0) - { - sub = h->root.root.u.def.section->owner; - h->root.root.type = bfd_link_hash_undefined; - h->root.root.u.undef.abfd = sub; - } - } - else - { - /* This symbol is in the .text section. We must give it an - entry in the procedure linkage table, if we have not - already done so. We change the definition of the symbol - to the .plt section; this will cause relocs against it to - be handled correctly. */ - if (h->plt_offset == 0) - { - if (splt->size == 0) - splt->size = SPARC_PLT_ENTRY_SIZE; - h->plt_offset = splt->size; - - if ((h->flags & SUNOS_DEF_REGULAR) == 0) - { - if (h->root.root.type == bfd_link_hash_undefined) - h->root.root.type = bfd_link_hash_defined; - h->root.root.u.def.section = splt; - h->root.root.u.def.value = splt->size; - } - - splt->size += SPARC_PLT_ENTRY_SIZE; - - /* We will also need a dynamic reloc entry, unless this - is a JMP_TBL reloc produced by linking PIC compiled - code, and we are not making a shared library. */ - if (bfd_link_pic (info) || (h->flags & SUNOS_DEF_REGULAR) == 0) - srel->size += RELOC_EXT_SIZE; - } - - /* If we are creating a shared library, we need to copy over - any reloc other than a jump table reloc. */ - if (bfd_link_pic (info) && r_type != RELOC_JMP_TBL) - srel->size += RELOC_EXT_SIZE; - } - } - - return TRUE; -} - -/* Scan the relocs for an input section. */ - -static bfd_boolean -sunos_scan_relocs (struct bfd_link_info *info, - bfd *abfd, - asection *sec, - bfd_size_type rel_size) -{ - void * relocs; - void * free_relocs = NULL; - - if (rel_size == 0) - return TRUE; - - if (! info->keep_memory) - relocs = free_relocs = bfd_malloc (rel_size); - else - { - struct aout_section_data_struct *n; - bfd_size_type amt = sizeof (struct aout_section_data_struct); - - n = bfd_alloc (abfd, amt); - if (n == NULL) - relocs = NULL; - else - { - set_aout_section_data (sec, n); - relocs = bfd_malloc (rel_size); - aout_section_data (sec)->relocs = relocs; - } - } - if (relocs == NULL) - return FALSE; - - if (bfd_seek (abfd, sec->rel_filepos, SEEK_SET) != 0 - || bfd_bread (relocs, rel_size, abfd) != rel_size) - goto error_return; - - if (obj_reloc_entry_size (abfd) == RELOC_STD_SIZE) - { - if (! sunos_scan_std_relocs (info, abfd, sec, - (struct reloc_std_external *) relocs, - rel_size)) - goto error_return; - } - else - { - if (! sunos_scan_ext_relocs (info, abfd, sec, - (struct reloc_ext_external *) relocs, - rel_size)) - goto error_return; - } - - if (free_relocs != NULL) - free (free_relocs); - - return TRUE; - - error_return: - if (free_relocs != NULL) - free (free_relocs); - return FALSE; -} - -/* Build the hash table of dynamic symbols, and to mark as written all - symbols from dynamic objects which we do not plan to write out. */ - -static bfd_boolean -sunos_scan_dynamic_symbol (struct sunos_link_hash_entry *h, void * data) -{ - struct bfd_link_info *info = (struct bfd_link_info *) data; - - /* Set the written flag for symbols we do not want to write out as - part of the regular symbol table. This is all symbols which are - not defined in a regular object file. For some reason symbols - which are referenced by a regular object and defined by a dynamic - object do not seem to show up in the regular symbol table. It is - possible for a symbol to have only SUNOS_REF_REGULAR set here, it - is an undefined symbol which was turned into a common symbol - because it was found in an archive object which was not included - in the link. */ - if ((h->flags & SUNOS_DEF_REGULAR) == 0 - && (h->flags & SUNOS_DEF_DYNAMIC) != 0 - && strcmp (h->root.root.root.string, "__DYNAMIC") != 0) - h->root.written = TRUE; - - /* If this symbol is defined by a dynamic object and referenced by a - regular object, see whether we gave it a reasonable value while - scanning the relocs. */ - if ((h->flags & SUNOS_DEF_REGULAR) == 0 - && (h->flags & SUNOS_DEF_DYNAMIC) != 0 - && (h->flags & SUNOS_REF_REGULAR) != 0) - { - if ((h->root.root.type == bfd_link_hash_defined - || h->root.root.type == bfd_link_hash_defweak) - && ((h->root.root.u.def.section->owner->flags & DYNAMIC) != 0) - && h->root.root.u.def.section->output_section == NULL) - { - bfd *sub; - - /* This symbol is currently defined in a dynamic section - which is not being put into the output file. This - implies that there is no reloc against the symbol. I'm - not sure why this case would ever occur. In any case, we - change the symbol to be undefined. */ - sub = h->root.root.u.def.section->owner; - h->root.root.type = bfd_link_hash_undefined; - h->root.root.u.undef.abfd = sub; - } - } - - /* If this symbol is defined or referenced by a regular file, add it - to the dynamic symbols. */ - if ((h->flags & (SUNOS_DEF_REGULAR | SUNOS_REF_REGULAR)) != 0) - { - asection *s; - size_t len; - bfd_byte *contents; - unsigned char *name; - unsigned long hash; - bfd *dynobj; - - BFD_ASSERT (h->dynindx == -2); - - dynobj = sunos_hash_table (info)->dynobj; - - h->dynindx = sunos_hash_table (info)->dynsymcount; - ++sunos_hash_table (info)->dynsymcount; - - len = strlen (h->root.root.root.string); - - /* We don't bother to construct a BFD hash table for the strings - which are the names of the dynamic symbols. Using a hash - table for the regular symbols is beneficial, because the - regular symbols includes the debugging symbols, which have - long names and are often duplicated in several object files. - There are no debugging symbols in the dynamic symbols. */ - s = bfd_get_linker_section (dynobj, ".dynstr"); - BFD_ASSERT (s != NULL); - contents = bfd_realloc (s->contents, s->size + len + 1); - if (contents == NULL) - return FALSE; - s->contents = contents; - - h->dynstr_index = s->size; - strcpy ((char *) contents + s->size, h->root.root.root.string); - s->size += len + 1; - - /* Add it to the dynamic hash table. */ - name = (unsigned char *) h->root.root.root.string; - hash = 0; - while (*name != '\0') - hash = (hash << 1) + *name++; - hash &= 0x7fffffff; - hash %= sunos_hash_table (info)->bucketcount; - - s = bfd_get_linker_section (dynobj, ".hash"); - BFD_ASSERT (s != NULL); - - if (GET_SWORD (dynobj, s->contents + hash * HASH_ENTRY_SIZE) == -1) - PUT_WORD (dynobj, h->dynindx, s->contents + hash * HASH_ENTRY_SIZE); - else - { - bfd_vma next; - - next = GET_WORD (dynobj, - (s->contents - + hash * HASH_ENTRY_SIZE - + BYTES_IN_WORD)); - PUT_WORD (dynobj, s->size / HASH_ENTRY_SIZE, - s->contents + hash * HASH_ENTRY_SIZE + BYTES_IN_WORD); - PUT_WORD (dynobj, h->dynindx, s->contents + s->size); - PUT_WORD (dynobj, next, s->contents + s->size + BYTES_IN_WORD); - s->size += HASH_ENTRY_SIZE; - } - } - - return TRUE; -} - -/* Set up the sizes and contents of the dynamic sections created in - sunos_add_dynamic_symbols. This is called by the SunOS linker - emulation before_allocation routine. We must set the sizes of the - sections before the linker sets the addresses of the various - sections. This unfortunately requires reading all the relocs so - that we can work out which ones need to become dynamic relocs. If - info->keep_memory is TRUE, we keep the relocs in memory; otherwise, - we discard them, and will read them again later. */ - -bfd_boolean -bfd_sunos_size_dynamic_sections (bfd *output_bfd, - struct bfd_link_info *info, - asection **sdynptr, - asection **sneedptr, - asection **srulesptr) -{ - bfd *dynobj; - bfd_size_type dynsymcount; - struct sunos_link_hash_entry *h; - asection *s; - size_t bucketcount; - bfd_size_type hashalloc; - size_t i; - bfd *sub; - - *sdynptr = NULL; - *sneedptr = NULL; - *srulesptr = NULL; - - if (bfd_link_relocatable (info)) - return TRUE; - - if (output_bfd->xvec != &MY(vec)) - return TRUE; - - /* Look through all the input BFD's and read their relocs. It would - be better if we didn't have to do this, but there is no other way - to determine the number of dynamic relocs we need, and, more - importantly, there is no other way to know which symbols should - get an entry in the procedure linkage table. */ - for (sub = info->input_bfds; sub != NULL; sub = sub->link.next) - { - if ((sub->flags & DYNAMIC) == 0 - && sub->xvec == output_bfd->xvec) - { - if (! sunos_scan_relocs (info, sub, obj_textsec (sub), - exec_hdr (sub)->a_trsize) - || ! sunos_scan_relocs (info, sub, obj_datasec (sub), - exec_hdr (sub)->a_drsize)) - return FALSE; - } - } - - dynobj = sunos_hash_table (info)->dynobj; - dynsymcount = sunos_hash_table (info)->dynsymcount; - - /* If there were no dynamic objects in the link, and we don't need - to build a global offset table, there is nothing to do here. */ - if (! sunos_hash_table (info)->dynamic_sections_needed - && ! sunos_hash_table (info)->got_needed) - return TRUE; - - /* If __GLOBAL_OFFSET_TABLE_ was mentioned, define it. */ - h = sunos_link_hash_lookup (sunos_hash_table (info), - "__GLOBAL_OFFSET_TABLE_", FALSE, FALSE, FALSE); - if (h != NULL && (h->flags & SUNOS_REF_REGULAR) != 0) - { - h->flags |= SUNOS_DEF_REGULAR; - if (h->dynindx == -1) - { - ++sunos_hash_table (info)->dynsymcount; - h->dynindx = -2; - } - s = bfd_get_linker_section (dynobj, ".got"); - BFD_ASSERT (s != NULL); - h->root.root.type = bfd_link_hash_defined; - h->root.root.u.def.section = s; - - /* If the .got section is more than 0x1000 bytes, we set - __GLOBAL_OFFSET_TABLE_ to be 0x1000 bytes into the section, - so that 13 bit relocations have a greater chance of working. */ - if (s->size >= 0x1000) - h->root.root.u.def.value = 0x1000; - else - h->root.root.u.def.value = 0; - - sunos_hash_table (info)->got_base = h->root.root.u.def.value; - } - - /* If there are any shared objects in the link, then we need to set - up the dynamic linking information. */ - if (sunos_hash_table (info)->dynamic_sections_needed) - { - *sdynptr = bfd_get_linker_section (dynobj, ".dynamic"); - - /* The .dynamic section is always the same size. */ - s = *sdynptr; - BFD_ASSERT (s != NULL); - s->size = (sizeof (struct external_sun4_dynamic) - + EXTERNAL_SUN4_DYNAMIC_DEBUGGER_SIZE - + sizeof (struct external_sun4_dynamic_link)); - - /* Set the size of the .dynsym and .hash sections. We counted - the number of dynamic symbols as we read the input files. We - will build the dynamic symbol table (.dynsym) and the hash - table (.hash) when we build the final symbol table, because - until then we do not know the correct value to give the - symbols. We build the dynamic symbol string table (.dynstr) - in a traversal of the symbol table using - sunos_scan_dynamic_symbol. */ - s = bfd_get_linker_section (dynobj, ".dynsym"); - BFD_ASSERT (s != NULL); - s->size = dynsymcount * sizeof (struct external_nlist); - s->contents = bfd_alloc (output_bfd, s->size); - if (s->contents == NULL && s->size != 0) - return FALSE; - - /* The number of buckets is just the number of symbols divided - by four. To compute the final size of the hash table, we - must actually compute the hash table. Normally we need - exactly as many entries in the hash table as there are - dynamic symbols, but if some of the buckets are not used we - will need additional entries. In the worst case, every - symbol will hash to the same bucket, and we will need - BUCKETCOUNT - 1 extra entries. */ - if (dynsymcount >= 4) - bucketcount = dynsymcount / 4; - else if (dynsymcount > 0) - bucketcount = dynsymcount; - else - bucketcount = 1; - s = bfd_get_linker_section (dynobj, ".hash"); - BFD_ASSERT (s != NULL); - hashalloc = (dynsymcount + bucketcount - 1) * HASH_ENTRY_SIZE; - s->contents = bfd_zalloc (dynobj, hashalloc); - if (s->contents == NULL && dynsymcount > 0) - return FALSE; - for (i = 0; i < bucketcount; i++) - PUT_WORD (output_bfd, (bfd_vma) -1, s->contents + i * HASH_ENTRY_SIZE); - s->size = bucketcount * HASH_ENTRY_SIZE; - - sunos_hash_table (info)->bucketcount = bucketcount; - - /* Scan all the symbols, place them in the dynamic symbol table, - and build the dynamic hash table. We reuse dynsymcount as a - counter for the number of symbols we have added so far. */ - sunos_hash_table (info)->dynsymcount = 0; - sunos_link_hash_traverse (sunos_hash_table (info), - sunos_scan_dynamic_symbol, - (void *) info); - BFD_ASSERT (sunos_hash_table (info)->dynsymcount == dynsymcount); - - /* The SunOS native linker seems to align the total size of the - symbol strings to a multiple of 8. I don't know if this is - important, but it can't hurt much. */ - s = bfd_get_linker_section (dynobj, ".dynstr"); - BFD_ASSERT (s != NULL); - if ((s->size & 7) != 0) - { - bfd_size_type add; - bfd_byte *contents; - - add = 8 - (s->size & 7); - contents = bfd_realloc (s->contents, s->size + add); - if (contents == NULL) - return FALSE; - memset (contents + s->size, 0, (size_t) add); - s->contents = contents; - s->size += add; - } - } - - /* Now that we have worked out the sizes of the procedure linkage - table and the dynamic relocs, allocate storage for them. */ - s = bfd_get_linker_section (dynobj, ".plt"); - BFD_ASSERT (s != NULL); - if (s->size != 0) - { - s->contents = bfd_alloc (dynobj, s->size); - if (s->contents == NULL) - return FALSE; - - /* Fill in the first entry in the table. */ - switch (bfd_get_arch (dynobj)) - { - case bfd_arch_sparc: - memcpy (s->contents, sparc_plt_first_entry, SPARC_PLT_ENTRY_SIZE); - break; - - case bfd_arch_m68k: - memcpy (s->contents, m68k_plt_first_entry, M68K_PLT_ENTRY_SIZE); - break; - - default: - abort (); - } - } - - s = bfd_get_linker_section (dynobj, ".dynrel"); - if (s->size != 0) - { - s->contents = bfd_alloc (dynobj, s->size); - if (s->contents == NULL) - return FALSE; - } - /* We use the reloc_count field to keep track of how many of the - relocs we have output so far. */ - s->reloc_count = 0; - - /* Make space for the global offset table. */ - s = bfd_get_linker_section (dynobj, ".got"); - s->contents = bfd_alloc (dynobj, s->size); - if (s->contents == NULL) - return FALSE; - - *sneedptr = bfd_get_section_by_name (dynobj, ".need"); - *srulesptr = bfd_get_section_by_name (dynobj, ".rules"); - - return TRUE; -} - -/* Link a dynamic object. We actually don't have anything to do at - this point. This entry point exists to prevent the regular linker - code from doing anything with the object. */ - -static bfd_boolean -sunos_link_dynamic_object (struct bfd_link_info *info ATTRIBUTE_UNUSED, - bfd *abfd ATTRIBUTE_UNUSED) -{ - return TRUE; -} - -/* Write out a dynamic symbol. This is called by the final traversal - over the symbol table. */ - -static bfd_boolean -sunos_write_dynamic_symbol (bfd *output_bfd, - struct bfd_link_info *info, - struct aout_link_hash_entry *harg) -{ - struct sunos_link_hash_entry *h = (struct sunos_link_hash_entry *) harg; - int type; - bfd_vma val; - asection *s; - struct external_nlist *outsym; - - /* If this symbol is in the procedure linkage table, fill in the - table entry. */ - if (h->plt_offset != 0) - { - bfd *dynobj; - asection *splt; - bfd_byte *p; - bfd_vma r_address; - - dynobj = sunos_hash_table (info)->dynobj; - splt = bfd_get_linker_section (dynobj, ".plt"); - p = splt->contents + h->plt_offset; - - s = bfd_get_linker_section (dynobj, ".dynrel"); - - r_address = (splt->output_section->vma - + splt->output_offset - + h->plt_offset); - - switch (bfd_get_arch (output_bfd)) - { - case bfd_arch_sparc: - if (bfd_link_pic (info) || (h->flags & SUNOS_DEF_REGULAR) == 0) - { - bfd_put_32 (output_bfd, SPARC_PLT_ENTRY_WORD0, p); - bfd_put_32 (output_bfd, - (SPARC_PLT_ENTRY_WORD1 - + (((- (h->plt_offset + 4) >> 2) - & 0x3fffffff))), - p + 4); - bfd_put_32 (output_bfd, SPARC_PLT_ENTRY_WORD2 + s->reloc_count, - p + 8); - } - else - { - val = (h->root.root.u.def.section->output_section->vma - + h->root.root.u.def.section->output_offset - + h->root.root.u.def.value); - bfd_put_32 (output_bfd, - SPARC_PLT_PIC_WORD0 + ((val >> 10) & 0x3fffff), - p); - bfd_put_32 (output_bfd, - SPARC_PLT_PIC_WORD1 + (val & 0x3ff), - p + 4); - bfd_put_32 (output_bfd, SPARC_PLT_PIC_WORD2, p + 8); - } - break; - - case bfd_arch_m68k: - if (! bfd_link_pic (info) && (h->flags & SUNOS_DEF_REGULAR) != 0) - abort (); - bfd_put_16 (output_bfd, M68K_PLT_ENTRY_WORD0, p); - bfd_put_32 (output_bfd, (- (h->plt_offset + 2)), p + 2); - bfd_put_16 (output_bfd, (bfd_vma) s->reloc_count, p + 6); - r_address += 2; - break; - - default: - abort (); - } - - /* We also need to add a jump table reloc, unless this is the - result of a JMP_TBL reloc from PIC compiled code. */ - if (bfd_link_pic (info) || (h->flags & SUNOS_DEF_REGULAR) == 0) - { - BFD_ASSERT (h->dynindx >= 0); - BFD_ASSERT (s->reloc_count * obj_reloc_entry_size (dynobj) - < s->size); - p = s->contents + s->reloc_count * obj_reloc_entry_size (output_bfd); - if (obj_reloc_entry_size (output_bfd) == RELOC_STD_SIZE) - { - struct reloc_std_external *srel; - - srel = (struct reloc_std_external *) p; - PUT_WORD (output_bfd, r_address, srel->r_address); - if (bfd_header_big_endian (output_bfd)) - { - srel->r_index[0] = (bfd_byte) (h->dynindx >> 16); - srel->r_index[1] = (bfd_byte) (h->dynindx >> 8); - srel->r_index[2] = (bfd_byte) (h->dynindx); - srel->r_type[0] = (RELOC_STD_BITS_EXTERN_BIG - | RELOC_STD_BITS_JMPTABLE_BIG); - } - else - { - srel->r_index[2] = (bfd_byte) (h->dynindx >> 16); - srel->r_index[1] = (bfd_byte) (h->dynindx >> 8); - srel->r_index[0] = (bfd_byte)h->dynindx; - srel->r_type[0] = (RELOC_STD_BITS_EXTERN_LITTLE - | RELOC_STD_BITS_JMPTABLE_LITTLE); - } - } - else - { - struct reloc_ext_external *erel; - - erel = (struct reloc_ext_external *) p; - PUT_WORD (output_bfd, r_address, erel->r_address); - if (bfd_header_big_endian (output_bfd)) - { - erel->r_index[0] = (bfd_byte) (h->dynindx >> 16); - erel->r_index[1] = (bfd_byte) (h->dynindx >> 8); - erel->r_index[2] = (bfd_byte)h->dynindx; - erel->r_type[0] = - (RELOC_EXT_BITS_EXTERN_BIG - | (RELOC_JMP_SLOT << RELOC_EXT_BITS_TYPE_SH_BIG)); - } - else - { - erel->r_index[2] = (bfd_byte) (h->dynindx >> 16); - erel->r_index[1] = (bfd_byte) (h->dynindx >> 8); - erel->r_index[0] = (bfd_byte)h->dynindx; - erel->r_type[0] = - (RELOC_EXT_BITS_EXTERN_LITTLE - | (RELOC_JMP_SLOT << RELOC_EXT_BITS_TYPE_SH_LITTLE)); - } - PUT_WORD (output_bfd, (bfd_vma) 0, erel->r_addend); - } - - ++s->reloc_count; - } - } - - /* If this is not a dynamic symbol, we don't have to do anything - else. We only check this after handling the PLT entry, because - we can have a PLT entry for a nondynamic symbol when linking PIC - compiled code from a regular object. */ - if (h->dynindx < 0) - return TRUE; - - switch (h->root.root.type) - { - default: - case bfd_link_hash_new: - abort (); - /* Avoid variable not initialized warnings. */ - return TRUE; - case bfd_link_hash_undefined: - type = N_UNDF | N_EXT; - val = 0; - break; - case bfd_link_hash_defined: - case bfd_link_hash_defweak: - { - asection *sec; - asection *output_section; - - sec = h->root.root.u.def.section; - output_section = sec->output_section; - BFD_ASSERT (bfd_is_abs_section (output_section) - || output_section->owner == output_bfd); - if (h->plt_offset != 0 - && (h->flags & SUNOS_DEF_REGULAR) == 0) - { - type = N_UNDF | N_EXT; - val = 0; - } - else - { - if (output_section == obj_textsec (output_bfd)) - type = (h->root.root.type == bfd_link_hash_defined - ? N_TEXT - : N_WEAKT); - else if (output_section == obj_datasec (output_bfd)) - type = (h->root.root.type == bfd_link_hash_defined - ? N_DATA - : N_WEAKD); - else if (output_section == obj_bsssec (output_bfd)) - type = (h->root.root.type == bfd_link_hash_defined - ? N_BSS - : N_WEAKB); - else - type = (h->root.root.type == bfd_link_hash_defined - ? N_ABS - : N_WEAKA); - type |= N_EXT; - val = (h->root.root.u.def.value - + output_section->vma - + sec->output_offset); - } - } - break; - case bfd_link_hash_common: - type = N_UNDF | N_EXT; - val = h->root.root.u.c.size; - break; - case bfd_link_hash_undefweak: - type = N_WEAKU; - val = 0; - break; - case bfd_link_hash_indirect: - case bfd_link_hash_warning: - /* FIXME: Ignore these for now. The circumstances under which - they should be written out are not clear to me. */ - return TRUE; - } - - s = bfd_get_linker_section (sunos_hash_table (info)->dynobj, ".dynsym"); - BFD_ASSERT (s != NULL); - outsym = ((struct external_nlist *) - (s->contents + h->dynindx * EXTERNAL_NLIST_SIZE)); - - H_PUT_8 (output_bfd, type, outsym->e_type); - H_PUT_8 (output_bfd, 0, outsym->e_other); - - /* FIXME: The native linker doesn't use 0 for desc. It seems to use - one less than the desc value in the shared library, although that - seems unlikely. */ - H_PUT_16 (output_bfd, 0, outsym->e_desc); - - PUT_WORD (output_bfd, h->dynstr_index, outsym->e_strx); - PUT_WORD (output_bfd, val, outsym->e_value); - - return TRUE; -} - -/* This is called for each reloc against an external symbol. If this - is a reloc which are going to copy as a dynamic reloc, then - copy it over, and tell the caller to not bother processing this - reloc. */ - -static bfd_boolean -sunos_check_dynamic_reloc (struct bfd_link_info *info, - bfd *input_bfd, - asection *input_section, - struct aout_link_hash_entry *harg, - void * reloc, - bfd_byte *contents ATTRIBUTE_UNUSED, - bfd_boolean *skip, - bfd_vma *relocationp) -{ - struct sunos_link_hash_entry *h = (struct sunos_link_hash_entry *) harg; - bfd *dynobj; - bfd_boolean baserel; - bfd_boolean jmptbl; - bfd_boolean pcrel; - asection *s; - bfd_byte *p; - long indx; - - *skip = FALSE; - - dynobj = sunos_hash_table (info)->dynobj; - - if (h != NULL - && h->plt_offset != 0 - && (bfd_link_pic (info) - || (h->flags & SUNOS_DEF_REGULAR) == 0)) - { - asection *splt; - - /* Redirect the relocation to the PLT entry. */ - splt = bfd_get_linker_section (dynobj, ".plt"); - *relocationp = (splt->output_section->vma - + splt->output_offset - + h->plt_offset); - } - - if (obj_reloc_entry_size (input_bfd) == RELOC_STD_SIZE) - { - struct reloc_std_external *srel; - - srel = (struct reloc_std_external *) reloc; - if (bfd_header_big_endian (input_bfd)) - { - baserel = (0 != (srel->r_type[0] & RELOC_STD_BITS_BASEREL_BIG)); - jmptbl = (0 != (srel->r_type[0] & RELOC_STD_BITS_JMPTABLE_BIG)); - pcrel = (0 != (srel->r_type[0] & RELOC_STD_BITS_PCREL_BIG)); - } - else - { - baserel = (0 != (srel->r_type[0] & RELOC_STD_BITS_BASEREL_LITTLE)); - jmptbl = (0 != (srel->r_type[0] & RELOC_STD_BITS_JMPTABLE_LITTLE)); - pcrel = (0 != (srel->r_type[0] & RELOC_STD_BITS_PCREL_LITTLE)); - } - } - else - { - struct reloc_ext_external *erel; - int r_type; - - erel = (struct reloc_ext_external *) reloc; - if (bfd_header_big_endian (input_bfd)) - r_type = ((erel->r_type[0] & RELOC_EXT_BITS_TYPE_BIG) - >> RELOC_EXT_BITS_TYPE_SH_BIG); - else - r_type = ((erel->r_type[0] & RELOC_EXT_BITS_TYPE_LITTLE) - >> RELOC_EXT_BITS_TYPE_SH_LITTLE); - baserel = (r_type == RELOC_BASE10 - || r_type == RELOC_BASE13 - || r_type == RELOC_BASE22); - jmptbl = r_type == RELOC_JMP_TBL; - pcrel = (r_type == RELOC_DISP8 - || r_type == RELOC_DISP16 - || r_type == RELOC_DISP32 - || r_type == RELOC_WDISP30 - || r_type == RELOC_WDISP22); - /* We don't consider the PC10 and PC22 types to be PC relative, - because they are pcrel_offset. */ - } - - if (baserel) - { - bfd_vma *got_offsetp; - asection *sgot; - - if (h != NULL) - got_offsetp = &h->got_offset; - else if (adata (input_bfd).local_got_offsets == NULL) - got_offsetp = NULL; - else - { - struct reloc_std_external *srel; - int r_index; - - srel = (struct reloc_std_external *) reloc; - if (obj_reloc_entry_size (input_bfd) == RELOC_STD_SIZE) - { - if (bfd_header_big_endian (input_bfd)) - r_index = ((srel->r_index[0] << 16) - | (srel->r_index[1] << 8) - | srel->r_index[2]); - else - r_index = ((srel->r_index[2] << 16) - | (srel->r_index[1] << 8) - | srel->r_index[0]); - } - else - { - struct reloc_ext_external *erel; - - erel = (struct reloc_ext_external *) reloc; - if (bfd_header_big_endian (input_bfd)) - r_index = ((erel->r_index[0] << 16) - | (erel->r_index[1] << 8) - | erel->r_index[2]); - else - r_index = ((erel->r_index[2] << 16) - | (erel->r_index[1] << 8) - | erel->r_index[0]); - } - - got_offsetp = adata (input_bfd).local_got_offsets + r_index; - } - - BFD_ASSERT (got_offsetp != NULL && *got_offsetp != 0); - - sgot = bfd_get_linker_section (dynobj, ".got"); - - /* We set the least significant bit to indicate whether we have - already initialized the GOT entry. */ - if ((*got_offsetp & 1) == 0) - { - if (h == NULL - || (! bfd_link_pic (info) - && ((h->flags & SUNOS_DEF_DYNAMIC) == 0 - || (h->flags & SUNOS_DEF_REGULAR) != 0))) - PUT_WORD (dynobj, *relocationp, sgot->contents + *got_offsetp); - else - PUT_WORD (dynobj, 0, sgot->contents + *got_offsetp); - - if (bfd_link_pic (info) - || (h != NULL - && (h->flags & SUNOS_DEF_DYNAMIC) != 0 - && (h->flags & SUNOS_DEF_REGULAR) == 0)) - { - /* We need to create a GLOB_DAT or 32 reloc to tell the - dynamic linker to fill in this entry in the table. */ - - s = bfd_get_linker_section (dynobj, ".dynrel"); - BFD_ASSERT (s != NULL); - BFD_ASSERT (s->reloc_count * obj_reloc_entry_size (dynobj) - < s->size); - - p = (s->contents - + s->reloc_count * obj_reloc_entry_size (dynobj)); - - if (h != NULL) - indx = h->dynindx; - else - indx = 0; - - if (obj_reloc_entry_size (dynobj) == RELOC_STD_SIZE) - { - struct reloc_std_external *srel; - - srel = (struct reloc_std_external *) p; - PUT_WORD (dynobj, - (*got_offsetp - + sgot->output_section->vma - + sgot->output_offset), - srel->r_address); - if (bfd_header_big_endian (dynobj)) - { - srel->r_index[0] = (bfd_byte) (indx >> 16); - srel->r_index[1] = (bfd_byte) (indx >> 8); - srel->r_index[2] = (bfd_byte)indx; - if (h == NULL) - srel->r_type[0] = 2 << RELOC_STD_BITS_LENGTH_SH_BIG; - else - srel->r_type[0] = - (RELOC_STD_BITS_EXTERN_BIG - | RELOC_STD_BITS_BASEREL_BIG - | RELOC_STD_BITS_RELATIVE_BIG - | (2 << RELOC_STD_BITS_LENGTH_SH_BIG)); - } - else - { - srel->r_index[2] = (bfd_byte) (indx >> 16); - srel->r_index[1] = (bfd_byte) (indx >> 8); - srel->r_index[0] = (bfd_byte)indx; - if (h == NULL) - srel->r_type[0] = 2 << RELOC_STD_BITS_LENGTH_SH_LITTLE; - else - srel->r_type[0] = - (RELOC_STD_BITS_EXTERN_LITTLE - | RELOC_STD_BITS_BASEREL_LITTLE - | RELOC_STD_BITS_RELATIVE_LITTLE - | (2 << RELOC_STD_BITS_LENGTH_SH_LITTLE)); - } - } - else - { - struct reloc_ext_external *erel; - - erel = (struct reloc_ext_external *) p; - PUT_WORD (dynobj, - (*got_offsetp - + sgot->output_section->vma - + sgot->output_offset), - erel->r_address); - if (bfd_header_big_endian (dynobj)) - { - erel->r_index[0] = (bfd_byte) (indx >> 16); - erel->r_index[1] = (bfd_byte) (indx >> 8); - erel->r_index[2] = (bfd_byte)indx; - if (h == NULL) - erel->r_type[0] = - RELOC_32 << RELOC_EXT_BITS_TYPE_SH_BIG; - else - erel->r_type[0] = - (RELOC_EXT_BITS_EXTERN_BIG - | (RELOC_GLOB_DAT << RELOC_EXT_BITS_TYPE_SH_BIG)); - } - else - { - erel->r_index[2] = (bfd_byte) (indx >> 16); - erel->r_index[1] = (bfd_byte) (indx >> 8); - erel->r_index[0] = (bfd_byte)indx; - if (h == NULL) - erel->r_type[0] = - RELOC_32 << RELOC_EXT_BITS_TYPE_SH_LITTLE; - else - erel->r_type[0] = - (RELOC_EXT_BITS_EXTERN_LITTLE - | (RELOC_GLOB_DAT - << RELOC_EXT_BITS_TYPE_SH_LITTLE)); - } - PUT_WORD (dynobj, 0, erel->r_addend); - } - - ++s->reloc_count; - } - - *got_offsetp |= 1; - } - - *relocationp = (sgot->vma - + (*got_offsetp &~ (bfd_vma) 1) - - sunos_hash_table (info)->got_base); - - /* There is nothing else to do for a base relative reloc. */ - return TRUE; - } - - if (! sunos_hash_table (info)->dynamic_sections_needed) - return TRUE; - if (! bfd_link_pic (info)) - { - if (h == NULL - || h->dynindx == -1 - || h->root.root.type != bfd_link_hash_undefined - || (h->flags & SUNOS_DEF_REGULAR) != 0 - || (h->flags & SUNOS_DEF_DYNAMIC) == 0 - || (h->root.root.u.undef.abfd->flags & DYNAMIC) == 0) - return TRUE; - } - else - { - if (h != NULL - && (h->dynindx == -1 - || jmptbl - || strcmp (h->root.root.root.string, - "__GLOBAL_OFFSET_TABLE_") == 0)) - return TRUE; - } - - /* It looks like this is a reloc we are supposed to copy. */ - - s = bfd_get_linker_section (dynobj, ".dynrel"); - BFD_ASSERT (s != NULL); - BFD_ASSERT (s->reloc_count * obj_reloc_entry_size (dynobj) < s->size); - - p = s->contents + s->reloc_count * obj_reloc_entry_size (dynobj); - - /* Copy the reloc over. */ - memcpy (p, reloc, obj_reloc_entry_size (dynobj)); - - if (h != NULL) - indx = h->dynindx; - else - indx = 0; - - /* Adjust the address and symbol index. */ - if (obj_reloc_entry_size (dynobj) == RELOC_STD_SIZE) - { - struct reloc_std_external *srel; - - srel = (struct reloc_std_external *) p; - PUT_WORD (dynobj, - (GET_WORD (dynobj, srel->r_address) - + input_section->output_section->vma - + input_section->output_offset), - srel->r_address); - if (bfd_header_big_endian (dynobj)) - { - srel->r_index[0] = (bfd_byte) (indx >> 16); - srel->r_index[1] = (bfd_byte) (indx >> 8); - srel->r_index[2] = (bfd_byte)indx; - } - else - { - srel->r_index[2] = (bfd_byte) (indx >> 16); - srel->r_index[1] = (bfd_byte) (indx >> 8); - srel->r_index[0] = (bfd_byte)indx; - } - /* FIXME: We may have to change the addend for a PC relative - reloc. */ - } - else - { - struct reloc_ext_external *erel; - - erel = (struct reloc_ext_external *) p; - PUT_WORD (dynobj, - (GET_WORD (dynobj, erel->r_address) - + input_section->output_section->vma - + input_section->output_offset), - erel->r_address); - if (bfd_header_big_endian (dynobj)) - { - erel->r_index[0] = (bfd_byte) (indx >> 16); - erel->r_index[1] = (bfd_byte) (indx >> 8); - erel->r_index[2] = (bfd_byte)indx; - } - else - { - erel->r_index[2] = (bfd_byte) (indx >> 16); - erel->r_index[1] = (bfd_byte) (indx >> 8); - erel->r_index[0] = (bfd_byte)indx; - } - if (pcrel && h != NULL) - { - /* Adjust the addend for the change in address. */ - PUT_WORD (dynobj, - (GET_WORD (dynobj, erel->r_addend) - - (input_section->output_section->vma - + input_section->output_offset - - input_section->vma)), - erel->r_addend); - } - } - - ++s->reloc_count; - - if (h != NULL) - *skip = TRUE; - - return TRUE; -} - -/* Finish up the dynamic linking information. */ - -static bfd_boolean -sunos_finish_dynamic_link (bfd *abfd, struct bfd_link_info *info) -{ - bfd *dynobj; - asection *o; - asection *s; - asection *sdyn; - - if (! sunos_hash_table (info)->dynamic_sections_needed - && ! sunos_hash_table (info)->got_needed) - return TRUE; - - dynobj = sunos_hash_table (info)->dynobj; - - sdyn = bfd_get_linker_section (dynobj, ".dynamic"); - BFD_ASSERT (sdyn != NULL); - - /* Finish up the .need section. The linker emulation code filled it - in, but with offsets from the start of the section instead of - real addresses. Now that we know the section location, we can - fill in the final values. */ - s = bfd_get_section_by_name (dynobj, ".need"); - if (s != NULL && s->size != 0) - { - file_ptr filepos; - bfd_byte *p; - - filepos = s->output_section->filepos + s->output_offset; - p = s->contents; - while (1) - { - bfd_vma val; - - PUT_WORD (dynobj, GET_WORD (dynobj, p) + filepos, p); - val = GET_WORD (dynobj, p + 12); - if (val == 0) - break; - PUT_WORD (dynobj, val + filepos, p + 12); - p += 16; - } - } - - /* The first entry in the .got section is the address of the - dynamic information, unless this is a shared library. */ - s = bfd_get_linker_section (dynobj, ".got"); - BFD_ASSERT (s != NULL); - if (bfd_link_pic (info) || sdyn->size == 0) - PUT_WORD (dynobj, 0, s->contents); - else - PUT_WORD (dynobj, sdyn->output_section->vma + sdyn->output_offset, - s->contents); - - for (o = dynobj->sections; o != NULL; o = o->next) - { - if ((o->flags & SEC_HAS_CONTENTS) != 0 - && o->contents != NULL) - { - BFD_ASSERT (o->output_section != NULL - && o->output_section->owner == abfd); - if (! bfd_set_section_contents (abfd, o->output_section, - o->contents, - (file_ptr) o->output_offset, - o->size)) - return FALSE; - } - } - - if (sdyn->size > 0) - { - struct external_sun4_dynamic esd; - struct external_sun4_dynamic_link esdl; - file_ptr pos; - - /* Finish up the dynamic link information. */ - PUT_WORD (dynobj, (bfd_vma) 3, esd.ld_version); - PUT_WORD (dynobj, - sdyn->output_section->vma + sdyn->output_offset + sizeof esd, - esd.ldd); - PUT_WORD (dynobj, - (sdyn->output_section->vma - + sdyn->output_offset - + sizeof esd - + EXTERNAL_SUN4_DYNAMIC_DEBUGGER_SIZE), - esd.ld); - - if (! bfd_set_section_contents (abfd, sdyn->output_section, &esd, - (file_ptr) sdyn->output_offset, - (bfd_size_type) sizeof esd)) - return FALSE; - - PUT_WORD (dynobj, (bfd_vma) 0, esdl.ld_loaded); - - s = bfd_get_section_by_name (dynobj, ".need"); - if (s == NULL || s->size == 0) - PUT_WORD (dynobj, (bfd_vma) 0, esdl.ld_need); - else - PUT_WORD (dynobj, s->output_section->filepos + s->output_offset, - esdl.ld_need); - - s = bfd_get_section_by_name (dynobj, ".rules"); - if (s == NULL || s->size == 0) - PUT_WORD (dynobj, (bfd_vma) 0, esdl.ld_rules); - else - PUT_WORD (dynobj, s->output_section->filepos + s->output_offset, - esdl.ld_rules); - - s = bfd_get_linker_section (dynobj, ".got"); - BFD_ASSERT (s != NULL); - PUT_WORD (dynobj, s->output_section->vma + s->output_offset, - esdl.ld_got); - - s = bfd_get_linker_section (dynobj, ".plt"); - BFD_ASSERT (s != NULL); - PUT_WORD (dynobj, s->output_section->vma + s->output_offset, - esdl.ld_plt); - PUT_WORD (dynobj, s->size, esdl.ld_plt_sz); - - s = bfd_get_linker_section (dynobj, ".dynrel"); - BFD_ASSERT (s != NULL); - BFD_ASSERT (s->reloc_count * obj_reloc_entry_size (dynobj) - == s->size); - PUT_WORD (dynobj, s->output_section->filepos + s->output_offset, - esdl.ld_rel); - - s = bfd_get_linker_section (dynobj, ".hash"); - BFD_ASSERT (s != NULL); - PUT_WORD (dynobj, s->output_section->filepos + s->output_offset, - esdl.ld_hash); - - s = bfd_get_linker_section (dynobj, ".dynsym"); - BFD_ASSERT (s != NULL); - PUT_WORD (dynobj, s->output_section->filepos + s->output_offset, - esdl.ld_stab); - - PUT_WORD (dynobj, (bfd_vma) 0, esdl.ld_stab_hash); - - PUT_WORD (dynobj, (bfd_vma) sunos_hash_table (info)->bucketcount, - esdl.ld_buckets); - - s = bfd_get_linker_section (dynobj, ".dynstr"); - BFD_ASSERT (s != NULL); - PUT_WORD (dynobj, s->output_section->filepos + s->output_offset, - esdl.ld_symbols); - PUT_WORD (dynobj, s->size, esdl.ld_symb_size); - - /* The size of the text area is the size of the .text section - rounded up to a page boundary. FIXME: Should the page size be - conditional on something? */ - PUT_WORD (dynobj, - BFD_ALIGN (obj_textsec (abfd)->size, 0x2000), - esdl.ld_text); - - pos = sdyn->output_offset; - pos += sizeof esd + EXTERNAL_SUN4_DYNAMIC_DEBUGGER_SIZE; - if (! bfd_set_section_contents (abfd, sdyn->output_section, &esdl, - pos, (bfd_size_type) sizeof esdl)) - return FALSE; - - abfd->flags |= DYNAMIC; - } - - return TRUE; -} |