X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=bfd%2Fsunos.c;h=5fec6f91d7d1dbf75e7a7534ac2d8f408ba2ee60;hb=1448fa32275a8686debba9323308841480c33fc7;hp=d0b87970bed1714a91b0d00af0ffbe1ff6ccc8d0;hpb=fe6fc35fdb89b493421742b290e86142b910ee85;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/sunos.c b/bfd/sunos.c index d0b87970be..5fec6f91d7 100644 --- a/bfd/sunos.c +++ b/bfd/sunos.c @@ -1,5 +1,7 @@ /* BFD backend for SunOS binaries. - Copyright (C) 1990, 91, 92, 93, 94, 95, 1996 Free Software Foundation, Inc. + Copyright 1990, 1991, 1992, 1994, 1995, 1996, 1997, 1998, 2000, 2001, + 2002 + Free Software Foundation, Inc. Written by Cygnus Support. This file is part of BFD, the Binary File Descriptor library. @@ -19,7 +21,11 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #define TARGETNAME "a.out-sunos-big" -#define MY(OP) CAT(sunos_big_,OP) + +/* 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 (sunos_big_,OP) #include "bfd.h" #include "bfdlink.h" @@ -78,9 +84,22 @@ static boolean sunos_finish_dynamic_link #define MY_check_dynamic_reloc sunos_check_dynamic_reloc #define MY_finish_dynamic_link sunos_finish_dynamic_link +/* ??? 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)) + /* 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). */ @@ -128,6 +147,7 @@ sunos_read_dynamic_info (abfd) struct external_sun4_dynamic dyninfo; unsigned long dynver; struct external_sun4_dynamic_link linkinfo; + bfd_size_type amt; if (obj_aout_dynamic_info (abfd) != (PTR) NULL) return true; @@ -138,8 +158,8 @@ sunos_read_dynamic_info (abfd) return false; } - info = ((struct sunos_dynamic_info *) - bfd_zalloc (abfd, sizeof (struct sunos_dynamic_info))); + amt = sizeof (struct sunos_dynamic_info); + info = (struct sunos_dynamic_info *) bfd_zalloc (abfd, amt); if (!info) return false; info->valid = false; @@ -160,7 +180,8 @@ sunos_read_dynamic_info (abfd) if ((abfd->flags & DYNAMIC) == 0) return true; if (! bfd_get_section_contents (abfd, obj_datasec (abfd), (PTR) &dyninfo, - (file_ptr) 0, sizeof dyninfo)) + (file_ptr) 0, + (bfd_size_type) sizeof dyninfo)) return true; dynver = GET_WORD (abfd, dyninfo.ld_version); @@ -181,7 +202,8 @@ sunos_read_dynamic_info (abfd) /* This executable appears to be dynamically linked in a way that we can understand. */ - if (! bfd_get_section_contents (abfd, dynsec, (PTR) &linkinfo, dynoff, + if (! bfd_get_section_contents (abfd, dynsec, (PTR) &linkinfo, + (file_ptr) dynoff, (bfd_size_type) sizeof linkinfo)) return true; @@ -263,6 +285,7 @@ sunos_slurp_dynamic_symtab (abfd) bfd *abfd; { struct sunos_dynamic_info *info; + bfd_size_type amt; /* Get the general dynamic information. */ if (obj_aout_dynamic_info (abfd) == NULL) @@ -281,16 +304,12 @@ sunos_slurp_dynamic_symtab (abfd) /* Get the dynamic nlist structures. */ if (info->dynsym == (struct external_nlist *) NULL) { - info->dynsym = ((struct external_nlist *) - bfd_alloc (abfd, - (info->dynsym_count - * EXTERNAL_NLIST_SIZE))); + amt = (bfd_size_type) info->dynsym_count * EXTERNAL_NLIST_SIZE; + info->dynsym = (struct external_nlist *) bfd_alloc (abfd, amt); if (info->dynsym == NULL && info->dynsym_count != 0) return false; - if (bfd_seek (abfd, info->dyninfo.ld_stab, SEEK_SET) != 0 - || (bfd_read ((PTR) info->dynsym, info->dynsym_count, - EXTERNAL_NLIST_SIZE, abfd) - != info->dynsym_count * EXTERNAL_NLIST_SIZE)) + if (bfd_seek (abfd, (file_ptr) info->dyninfo.ld_stab, SEEK_SET) != 0 + || bfd_bread ((PTR) info->dynsym, amt, abfd) != amt) { if (info->dynsym != NULL) { @@ -304,13 +323,12 @@ sunos_slurp_dynamic_symtab (abfd) /* Get the dynamic strings. */ if (info->dynstr == (char *) NULL) { - info->dynstr = (char *) bfd_alloc (abfd, info->dyninfo.ld_symb_size); + amt = info->dyninfo.ld_symb_size; + info->dynstr = (char *) bfd_alloc (abfd, amt); if (info->dynstr == NULL && info->dyninfo.ld_symb_size != 0) return false; - if (bfd_seek (abfd, info->dyninfo.ld_symbols, SEEK_SET) != 0 - || (bfd_read ((PTR) info->dynstr, 1, info->dyninfo.ld_symb_size, - abfd) - != info->dyninfo.ld_symb_size)) + if (bfd_seek (abfd, (file_ptr) info->dyninfo.ld_symbols, SEEK_SET) != 0 + || bfd_bread ((PTR) info->dynstr, amt, abfd) != amt) { if (info->dynstr != NULL) { @@ -353,8 +371,8 @@ sunos_canonicalize_dynamic_symtab (abfd, storage) table = (bfd_byte *) bfd_malloc (table_size); if (table == NULL && table_size != 0) abort (); - if (bfd_seek (abfd, info->dyninfo.ld_hash, SEEK_SET) != 0 - || bfd_read ((PTR) table, 1, table_size, abfd) != table_size) + if (bfd_seek (abfd, (file_ptr) info->dyninfo.ld_hash, SEEK_SET) != 0 + || bfd_bread ((PTR) table, table_size, abfd) != table_size) abort (); for (i = 0; i < info->dynsym_count; i++) { @@ -384,18 +402,18 @@ sunos_canonicalize_dynamic_symtab (abfd, storage) structures. */ if (info->canonical_dynsym == (aout_symbol_type *) NULL) { - info->canonical_dynsym = ((aout_symbol_type *) - bfd_alloc (abfd, - (info->dynsym_count - * sizeof (aout_symbol_type)))); + 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 = (aout_symbol_type *) 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, info->dynsym_count, - info->dynstr, - info->dyninfo.ld_symb_size, - true)) + info->dynsym, + (bfd_size_type) info->dynsym_count, + info->dynstr, strsize, true)) { if (info->canonical_dynsym != NULL) { @@ -445,6 +463,7 @@ sunos_canonicalize_dynamic_reloc (abfd, storage, syms) { struct sunos_dynamic_info *info; unsigned long i; + bfd_size_type size; /* Get the general dynamic information. */ if (obj_aout_dynamic_info (abfd) == (PTR) NULL) @@ -463,15 +482,12 @@ sunos_canonicalize_dynamic_reloc (abfd, storage, syms) /* Get the dynamic reloc information. */ if (info->dynrel == NULL) { - info->dynrel = (PTR) bfd_alloc (abfd, - (info->dynrel_count - * obj_reloc_entry_size (abfd))); - if (info->dynrel == NULL && info->dynrel_count != 0) + size = (bfd_size_type) info->dynrel_count * obj_reloc_entry_size (abfd); + info->dynrel = (PTR) bfd_alloc (abfd, size); + if (info->dynrel == NULL && size != 0) return -1; - if (bfd_seek (abfd, info->dyninfo.ld_rel, SEEK_SET) != 0 - || (bfd_read ((PTR) info->dynrel, info->dynrel_count, - obj_reloc_entry_size (abfd), abfd) - != info->dynrel_count * obj_reloc_entry_size (abfd))) + if (bfd_seek (abfd, (file_ptr) info->dyninfo.ld_rel, SEEK_SET) != 0 + || bfd_bread ((PTR) info->dynrel, size, abfd) != size) { if (info->dynrel != NULL) { @@ -488,13 +504,11 @@ sunos_canonicalize_dynamic_reloc (abfd, storage, syms) { arelent *to; - info->canonical_dynrel = ((arelent *) - bfd_alloc (abfd, - (info->dynrel_count - * sizeof (arelent)))); + size = (bfd_size_type) info->dynrel_count * sizeof (arelent); + info->canonical_dynrel = (arelent *) 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) @@ -506,7 +520,7 @@ sunos_canonicalize_dynamic_reloc (abfd, storage, syms) pend = p + info->dynrel_count; for (; p < pend; p++, to++) NAME(aout,swap_ext_reloc_in) (abfd, p, to, syms, - info->dynsym_count); + (bfd_size_type) info->dynsym_count); } else { @@ -517,7 +531,7 @@ sunos_canonicalize_dynamic_reloc (abfd, storage, syms) pend = p + info->dynrel_count; for (; p < pend; p++, to++) NAME(aout,swap_std_reloc_in) (abfd, p, to, syms, - info->dynsym_count); + (bfd_size_type) info->dynsym_count); } } @@ -550,21 +564,21 @@ static const bfd_byte sparc_plt_first_entry[SPARC_PLT_ENTRY_SIZE] = }; /* save %sp, -96, %sp */ -#define SPARC_PLT_ENTRY_WORD0 0x9de3bfa0 +#define SPARC_PLT_ENTRY_WORD0 ((bfd_vma) 0x9de3bfa0) /* call; address filled in later. */ -#define SPARC_PLT_ENTRY_WORD1 0x40000000 +#define SPARC_PLT_ENTRY_WORD1 ((bfd_vma) 0x40000000) /* sethi; reloc index filled in later. */ -#define SPARC_PLT_ENTRY_WORD2 0x01000000 +#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
, %g1 */ -#define SPARC_PLT_PIC_WORD0 0x03000000 +#define SPARC_PLT_PIC_WORD0 ((bfd_vma) 0x03000000) /* jmp %g1 +
*/ -#define SPARC_PLT_PIC_WORD1 0x81c06000 +#define SPARC_PLT_PIC_WORD1 ((bfd_vma) 0x81c06000) /* nop */ -#define SPARC_PLT_PIC_WORD2 0x01000000 +#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 @@ -584,7 +598,7 @@ static const bfd_byte m68k_plt_first_entry[M68K_PLT_ENTRY_SIZE] = }; /* bsrl */ -#define M68K_PLT_ENTRY_WORD0 (0x61ff) +#define M68K_PLT_ENTRY_WORD0 ((bfd_vma) 0x61ff) /* Remaining words filled in later. */ /* An entry in the SunOS linker hash table. */ @@ -642,6 +656,9 @@ struct sunos_link_hash_table /* Whether we need the dynamic sections. */ boolean dynamic_sections_needed; + /* Whether we need the .got table. */ + boolean got_needed; + /* The number of dynamic symbols. */ size_t dynsymcount; @@ -651,6 +668,9 @@ struct sunos_link_hash_table /* 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. */ @@ -695,24 +715,26 @@ sunos_link_hash_table_create (abfd) bfd *abfd; { struct sunos_link_hash_table *ret; + bfd_size_type amt = sizeof (struct sunos_link_hash_table); - ret = ((struct sunos_link_hash_table *) - bfd_alloc (abfd, sizeof (struct sunos_link_hash_table))); + ret = (struct sunos_link_hash_table *) bfd_malloc (amt); if (ret == (struct sunos_link_hash_table *) NULL) return (struct bfd_link_hash_table *) NULL; if (! NAME(aout,link_hash_table_init) (&ret->root, abfd, sunos_link_hash_newfunc)) { - bfd_release (abfd, ret); + free (ret); return (struct bfd_link_hash_table *) NULL; } ret->dynobj = NULL; ret->dynamic_sections_created = false; ret->dynamic_sections_needed = false; + ret->got_needed = false; ret->dynsymcount = 0; ret->bucketcount = 0; ret->needed = NULL; + ret->got_base = 0; return &ret->root.root; } @@ -761,7 +783,8 @@ sunos_create_dynamic_sections (abfd, info, needed) sunos_hash_table (info)->dynobj = abfd; - flags = SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY; + 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 @@ -823,24 +846,26 @@ sunos_create_dynamic_sections (abfd, info, needed) sunos_hash_table (info)->dynamic_sections_created = true; } - if (needed && ! sunos_hash_table (info)->dynamic_sections_needed) + if ((needed && ! sunos_hash_table (info)->dynamic_sections_needed) + || info->shared) { bfd *dynobj; dynobj = sunos_hash_table (info)->dynobj; s = bfd_get_section_by_name (dynobj, ".got"); - s->_raw_size = BYTES_IN_WORD; + if (s->_raw_size == 0) + s->_raw_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 when it encounters an object with the DYNAMIC flag - set. */ + backend linker for each object it encounters. */ static boolean sunos_add_dynamic_symbols (abfd, info, symsp, sym_countp, stringsp) @@ -850,18 +875,42 @@ sunos_add_dynamic_symbols (abfd, info, symsp, sym_countp, stringsp) bfd_size_type *sym_countp; char **stringsp; { - asection *s; bfd *dynobj; struct sunos_dynamic_info *dinfo; unsigned long need; + asection **ps; + + /* Make sure we have all the required sections. */ + if (info->hash->creator == abfd->xvec) + { + if (! sunos_create_dynamic_sections (abfd, info, + (((abfd->flags & DYNAMIC) != 0 + && ! info->relocateable) + ? true + : false))) + 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. */ - abfd->sections = NULL; + space in the output file. If this is the first object we have + seen, we must preserve the dynamic sections we just created. */ + for (ps = &abfd->sections; *ps != NULL; ) + { + if (abfd != dynobj || ((*ps)->flags & SEC_LINKER_CREATED) == 0) + bfd_section_list_remove (abfd, ps); + else + ps = &(*ps)->next; + } /* The native linker seems to just ignore dynamic objects when -r is used. */ @@ -876,20 +925,15 @@ sunos_add_dynamic_symbols (abfd, info, symsp, sym_countp, stringsp) return false; } - /* Make sure we have all the required information. */ - if (! sunos_create_dynamic_sections (abfd, info, true)) - 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. */ - dynobj = sunos_hash_table (info)->dynobj; 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. */ - s = bfd_make_section (dynobj, ".need"); + asection *s = bfd_make_section (dynobj, ".need"); if (s == NULL || ! bfd_set_section_flags (dynobj, s, (SEC_ALLOC @@ -906,7 +950,7 @@ sunos_add_dynamic_symbols (abfd, info, symsp, sym_countp, stringsp) /* The .rules section holds the path to search for shared objects. The address of this section is put in the ld_rules field. */ - s = bfd_make_section (dynobj, ".rules"); + asection *s = bfd_make_section (dynobj, ".rules"); if (s == NULL || ! bfd_set_section_flags (dynobj, s, (SEC_ALLOC @@ -935,10 +979,13 @@ sunos_add_dynamic_symbols (abfd, info, symsp, sym_countp, stringsp) 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, need, SEEK_SET) != 0 - || bfd_read (buf, 1, 16, abfd) != 16) + 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 @@ -946,43 +993,102 @@ sunos_add_dynamic_symbols (abfd, info, symsp, sym_countp, stringsp) name = bfd_get_32 (abfd, buf); flags = bfd_get_32 (abfd, buf + 4); - major_vno = bfd_get_16 (abfd, buf + 8); - minor_vno = bfd_get_16 (abfd, buf + 10); + 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); - needed = (struct bfd_link_needed_list *) bfd_alloc (abfd, sizeof (struct bfd_link_needed_list)); + alc = sizeof (struct bfd_link_needed_list); + needed = (struct bfd_link_needed_list *) bfd_alloc (abfd, alc); if (needed == NULL) return false; needed->by = abfd; /* We return the name as [-l]name[.maj][.min]. */ + alc = 30; + namebuf = (char *) bfd_malloc (alc + 1); + if (namebuf == NULL) + return false; + p = namebuf; if ((flags & 0x80000000) != 0) - bfd_alloc_grow (abfd, "-l", 2); - if (bfd_seek (abfd, name, SEEK_SET) != 0) - return false; + { + *p++ = '-'; + *p++ = 'l'; + } + if (bfd_seek (abfd, (file_ptr) name, SEEK_SET) != 0) + { + free (namebuf); + return false; + } + do { - if (bfd_read (&b, 1, 1, abfd) != 1) - return false; - bfd_alloc_grow (abfd, &b, 1); + 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 = (char *) 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) + + if (major_vno == 0) + *p = '\0'; + else { - char verbuf[30]; + char majbuf[30]; + char minbuf[30]; + + sprintf (majbuf, ".%d", major_vno); + if (minor_vno == 0) + minbuf[0] = '\0'; + else + sprintf (minbuf, ".%d", minor_vno); - sprintf (verbuf, ".%d", major_vno); - bfd_alloc_grow (abfd, verbuf, strlen (verbuf)); - if (minor_vno != 0) + if ((p - namebuf) + strlen (majbuf) + strlen (minbuf) >= alc) { - sprintf (verbuf, ".%d", minor_vno); - bfd_alloc_grow (abfd, verbuf, strlen (verbuf)); + char *n; + + alc = (p - namebuf) + strlen (majbuf) + strlen (minbuf); + n = (char *) bfd_realloc (namebuf, alc + 1); + if (n == NULL) + { + free (namebuf); + return false; + } + p = n + (p - namebuf); + namebuf = n; } + + strcpy (p, majbuf); + strcat (p, minbuf); } - needed->name = bfd_alloc_finish (abfd); - if (needed->name == NULL) - return false; + + 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; @@ -1017,19 +1123,13 @@ sunos_add_one_symbol (info, abfd, name, flags, section, value, string, struct sunos_link_hash_entry *h; int new_flag; - if (! sunos_hash_table (info)->dynamic_sections_created) - { - /* We must create the dynamic sections while reading the input - files, even though at this point we don't know if any of the - sections will be needed. This will ensure that the dynamic - sections are mapped to the right output section. It does no - harm to create these sections if they are not needed. */ - if (! sunos_create_dynamic_sections (abfd, info, false)) - return false; - } - - h = sunos_link_hash_lookup (sunos_hash_table (info), name, true, copy, - false); + 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; @@ -1065,7 +1165,8 @@ sunos_add_one_symbol (info, abfd, name, flags, section, value, string, /* 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_new; + 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) @@ -1151,7 +1252,7 @@ sunos_add_one_symbol (info, abfd, name, flags, section, value, string, /*ARGSUSED*/ struct bfd_link_needed_list * bfd_sunos_get_needed_list (abfd, info) - bfd *abfd; + bfd *abfd ATTRIBUTE_UNUSED; struct bfd_link_info *info; { if (info->hash->creator != &MY(vec)) @@ -1216,11 +1317,11 @@ bfd_sunos_size_dynamic_sections (output_bfd, info, sdynptr, sneedptr, asection **srulesptr; { bfd *dynobj; - size_t dynsymcount; + bfd_size_type dynsymcount; struct sunos_link_hash_entry *h; asection *s; size_t bucketcount; - size_t hashalloc; + bfd_size_type hashalloc; size_t i; bfd *sub; @@ -1228,6 +1329,9 @@ bfd_sunos_size_dynamic_sections (output_bfd, info, sdynptr, sneedptr, *sneedptr = NULL; *srulesptr = NULL; + if (info->relocateable) + return true; + if (output_bfd->xvec != &MY(vec)) return true; @@ -1254,7 +1358,8 @@ bfd_sunos_size_dynamic_sections (output_bfd, info, sdynptr, sneedptr, /* 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) + if (! sunos_hash_table (info)->dynamic_sections_needed + && ! sunos_hash_table (info)->got_needed) return true; /* If __GLOBAL_OFFSET_TABLE_ was mentioned, define it. */ @@ -1270,83 +1375,102 @@ bfd_sunos_size_dynamic_sections (output_bfd, info, sdynptr, sneedptr, } h->root.root.type = bfd_link_hash_defined; h->root.root.u.def.section = bfd_get_section_by_name (dynobj, ".got"); - h->root.root.u.def.value = 0; + + /* 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. */ + s = bfd_get_section_by_name (dynobj, ".got"); + BFD_ASSERT (s != NULL); + if (s->_raw_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; } - /* The .dynamic section is always the same size. */ - s = bfd_get_section_by_name (dynobj, ".dynamic"); - BFD_ASSERT (s != NULL); - s->_raw_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_section_by_name (dynobj, ".dynsym"); - BFD_ASSERT (s != NULL); - s->_raw_size = dynsymcount * sizeof (struct external_nlist); - s->contents = (bfd_byte *) bfd_alloc (output_bfd, s->_raw_size); - if (s->contents == NULL && s->_raw_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_section_by_name (dynobj, ".hash"); - BFD_ASSERT (s != NULL); - hashalloc = (dynsymcount + bucketcount - 1) * HASH_ENTRY_SIZE; - s->contents = (bfd_byte *) bfd_alloc (dynobj, hashalloc); - if (s->contents == NULL && dynsymcount > 0) - return false; - memset (s->contents, 0, hashalloc); - for (i = 0; i < bucketcount; i++) - PUT_WORD (output_bfd, (bfd_vma) -1, s->contents + i * HASH_ENTRY_SIZE); - s->_raw_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, - (PTR) 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_section_by_name (dynobj, ".dynstr"); - BFD_ASSERT (s != NULL); - if ((s->_raw_size & 7) != 0) + /* 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) { - bfd_size_type add; - bfd_byte *contents; + *sdynptr = bfd_get_section_by_name (dynobj, ".dynamic"); - add = 8 - (s->_raw_size & 7); - contents = (bfd_byte *) bfd_realloc (s->contents, - (size_t) (s->_raw_size + add)); - if (contents == NULL) + /* The .dynamic section is always the same size. */ + s = *sdynptr; + BFD_ASSERT (s != NULL); + s->_raw_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_section_by_name (dynobj, ".dynsym"); + BFD_ASSERT (s != NULL); + s->_raw_size = dynsymcount * sizeof (struct external_nlist); + s->contents = (bfd_byte *) bfd_alloc (output_bfd, s->_raw_size); + if (s->contents == NULL && s->_raw_size != 0) return false; - memset (contents + s->_raw_size, 0, (size_t) add); - s->contents = contents; - s->_raw_size += add; + + /* 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_section_by_name (dynobj, ".hash"); + BFD_ASSERT (s != NULL); + hashalloc = (dynsymcount + bucketcount - 1) * HASH_ENTRY_SIZE; + s->contents = (bfd_byte *) 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->_raw_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, + (PTR) 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_section_by_name (dynobj, ".dynstr"); + BFD_ASSERT (s != NULL); + if ((s->_raw_size & 7) != 0) + { + bfd_size_type add; + bfd_byte *contents; + + add = 8 - (s->_raw_size & 7); + contents = (bfd_byte *) bfd_realloc (s->contents, + s->_raw_size + add); + if (contents == NULL) + return false; + memset (contents + s->_raw_size, 0, (size_t) add); + s->contents = contents; + s->_raw_size += add; + } } /* Now that we have worked out the sizes of the procedure linkage @@ -1392,7 +1516,6 @@ bfd_sunos_size_dynamic_sections (output_bfd, info, sdynptr, sneedptr, if (s->contents == NULL) return false; - *sdynptr = bfd_get_section_by_name (dynobj, ".dynamic"); *sneedptr = bfd_get_section_by_name (dynobj, ".need"); *srulesptr = bfd_get_section_by_name (dynobj, ".rules"); @@ -1415,19 +1538,19 @@ sunos_scan_relocs (info, abfd, sec, rel_size) return true; if (! info->keep_memory) - relocs = free_relocs = bfd_malloc ((size_t) rel_size); + 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 = ((struct aout_section_data_struct *) - bfd_alloc (abfd, sizeof (struct aout_section_data_struct))); + n = (struct aout_section_data_struct *) bfd_alloc (abfd, amt); if (n == NULL) relocs = NULL; else { set_aout_section_data (sec, n); - relocs = bfd_malloc ((size_t) rel_size); + relocs = bfd_malloc (rel_size); aout_section_data (sec)->relocs = relocs; } } @@ -1435,7 +1558,7 @@ sunos_scan_relocs (info, abfd, sec, rel_size) return false; if (bfd_seek (abfd, sec->rel_filepos, SEEK_SET) != 0 - || bfd_read (relocs, 1, rel_size, abfd) != rel_size) + || bfd_bread (relocs, rel_size, abfd) != rel_size) goto error_return; if (obj_reloc_entry_size (abfd) == RELOC_STD_SIZE) @@ -1478,7 +1601,7 @@ static boolean sunos_scan_std_relocs (info, abfd, sec, relocs, rel_size) struct bfd_link_info *info; bfd *abfd; - asection *sec; + asection *sec ATTRIBUTE_UNUSED; const struct reloc_std_external *relocs; bfd_size_type rel_size; { @@ -1552,12 +1675,20 @@ sunos_scan_std_relocs (info, abfd, sec, relocs, rel_size) if (dynobj == NULL) { - if (! sunos_create_dynamic_sections (abfd, info, true)) + asection *sgot; + + if (! sunos_create_dynamic_sections (abfd, info, false)) return false; dynobj = sunos_hash_table (info)->dynobj; splt = bfd_get_section_by_name (dynobj, ".plt"); srel = bfd_get_section_by_name (dynobj, ".dynrel"); BFD_ASSERT (splt != NULL && srel != NULL); + + sgot = bfd_get_section_by_name (dynobj, ".got"); + BFD_ASSERT (sgot != NULL); + if (sgot->_raw_size == 0) + sgot->_raw_size = BYTES_IN_WORD; + sunos_hash_table (info)->got_needed = true; } BFD_ASSERT ((h->flags & SUNOS_REF_REGULAR) != 0); @@ -1630,7 +1761,7 @@ static boolean sunos_scan_ext_relocs (info, abfd, sec, relocs, rel_size) struct bfd_link_info *info; bfd *abfd; - asection *sec; + asection *sec ATTRIBUTE_UNUSED; const struct reloc_ext_external *relocs; bfd_size_type rel_size; { @@ -1640,6 +1771,7 @@ sunos_scan_ext_relocs (info, abfd, sec, relocs, rel_size) 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) @@ -1699,13 +1831,18 @@ sunos_scan_ext_relocs (info, abfd, sec, relocs, rel_size) { if (dynobj == NULL) { - if (! sunos_create_dynamic_sections (abfd, info, true)) + if (! sunos_create_dynamic_sections (abfd, info, false)) return false; dynobj = sunos_hash_table (info)->dynobj; splt = bfd_get_section_by_name (dynobj, ".plt"); sgot = bfd_get_section_by_name (dynobj, ".got"); srel = bfd_get_section_by_name (dynobj, ".dynrel"); BFD_ASSERT (splt != NULL && sgot != NULL && srel != NULL); + + /* Make sure we have an initial entry in the .got table. */ + if (sgot->_raw_size == 0) + sgot->_raw_size = BYTES_IN_WORD; + sunos_hash_table (info)->got_needed = true; } if (r_extern) @@ -1726,10 +1863,10 @@ sunos_scan_ext_relocs (info, abfd, sec, relocs, rel_size) if (adata (abfd).local_got_offsets == NULL) { + amt = bfd_get_symcount (abfd); + amt *= sizeof (bfd_vma); adata (abfd).local_got_offsets = - (bfd_vma *) bfd_zalloc (abfd, - (bfd_get_symcount (abfd) - * sizeof (bfd_vma))); + (bfd_vma *) bfd_zalloc (abfd, amt); if (adata (abfd).local_got_offsets == NULL) return false; } @@ -1796,18 +1933,34 @@ sunos_scan_ext_relocs (info, abfd, sec, relocs, rel_size) || (h->flags & SUNOS_DEF_REGULAR) != 0)) continue; + if (r_type == RELOC_JMP_TBL + && ! info->shared + && (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, true)) + if (! sunos_create_dynamic_sections (abfd, info, false)) return false; dynobj = sunos_hash_table (info)->dynobj; splt = bfd_get_section_by_name (dynobj, ".plt"); sgot = bfd_get_section_by_name (dynobj, ".got"); srel = bfd_get_section_by_name (dynobj, ".dynrel"); BFD_ASSERT (splt != NULL && sgot != NULL && srel != NULL); + + /* Make sure we have an initial entry in the .got table. */ + if (sgot->_raw_size == 0) + sgot->_raw_size = BYTES_IN_WORD; + sunos_hash_table (info)->got_needed = true; } BFD_ASSERT (r_type == RELOC_JMP_TBL @@ -1898,6 +2051,9 @@ sunos_scan_dynamic_symbol (h, data) { struct bfd_link_info *info = (struct bfd_link_info *) data; + if (h->root.root.type == bfd_link_hash_warning) + h = (struct sunos_link_hash_entry *) h->root.root.u.i.link; + /* 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 @@ -1973,7 +2129,7 @@ sunos_scan_dynamic_symbol (h, data) s->contents = contents; h->dynstr_index = s->_raw_size; - strcpy (contents + s->_raw_size, h->root.root.root.string); + strcpy ((char *) contents + s->_raw_size, h->root.root.root.string); s->_raw_size += len + 1; /* Add it to the dynamic hash table. */ @@ -2015,8 +2171,8 @@ sunos_scan_dynamic_symbol (h, data) /*ARGSUSED*/ static boolean sunos_link_dynamic_object (info, abfd) - struct bfd_link_info *info; - bfd *abfd; + struct bfd_link_info *info ATTRIBUTE_UNUSED; + bfd *abfd ATTRIBUTE_UNUSED; { return true; } @@ -2036,92 +2192,6 @@ sunos_write_dynamic_symbol (output_bfd, info, harg) asection *s; struct external_nlist *outsym; - 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_section_by_name (sunos_hash_table (info)->dynobj, ".dynsym"); - BFD_ASSERT (s != NULL); - outsym = ((struct external_nlist *) - (s->contents + h->dynindx * EXTERNAL_NLIST_SIZE)); - - bfd_h_put_8 (output_bfd, type, outsym->e_type); - bfd_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. */ - bfd_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); - /* If this symbol is in the procedure linkage table, fill in the table entry. */ if (h->plt_offset != 0) @@ -2129,7 +2199,6 @@ sunos_write_dynamic_symbol (output_bfd, info, harg) bfd *dynobj; asection *splt; bfd_byte *p; - asection *s; bfd_vma r_address; dynobj = sunos_hash_table (info)->dynobj; @@ -2158,8 +2227,6 @@ sunos_write_dynamic_symbol (output_bfd, info, harg) } else { - bfd_vma val; - val = (h->root.root.u.def.section->output_section->vma + h->root.root.u.def.section->output_offset + h->root.root.u.def.value); @@ -2178,7 +2245,7 @@ sunos_write_dynamic_symbol (output_bfd, info, harg) 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, s->reloc_count, p + 6); + bfd_put_16 (output_bfd, (bfd_vma) s->reloc_count, p + 6); r_address += 2; break; @@ -2190,6 +2257,7 @@ sunos_write_dynamic_symbol (output_bfd, info, harg) result of a JMP_TBL reloc from PIC compiled code. */ if (info->shared || (h->flags & SUNOS_DEF_REGULAR) == 0) { + BFD_ASSERT (h->dynindx >= 0); BFD_ASSERT (s->reloc_count * obj_reloc_entry_size (dynobj) < s->_raw_size); p = s->contents + s->reloc_count * obj_reloc_entry_size (output_bfd); @@ -2201,17 +2269,17 @@ sunos_write_dynamic_symbol (output_bfd, info, harg) PUT_WORD (output_bfd, r_address, srel->r_address); if (bfd_header_big_endian (output_bfd)) { - srel->r_index[0] = h->dynindx >> 16; - srel->r_index[1] = h->dynindx >> 8; - srel->r_index[2] = h->dynindx; + 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] = h->dynindx >> 16; - srel->r_index[1] = h->dynindx >> 8; - srel->r_index[0] = h->dynindx; + 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); } @@ -2224,18 +2292,18 @@ sunos_write_dynamic_symbol (output_bfd, info, harg) PUT_WORD (output_bfd, r_address, erel->r_address); if (bfd_header_big_endian (output_bfd)) { - erel->r_index[0] = h->dynindx >> 16; - erel->r_index[1] = h->dynindx >> 8; - erel->r_index[2] = h->dynindx; + 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] = h->dynindx >> 16; - erel->r_index[1] = h->dynindx >> 8; - erel->r_index[0] = h->dynindx; + 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)); @@ -2247,6 +2315,96 @@ sunos_write_dynamic_symbol (output_bfd, info, harg) } } + /* 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_section_by_name (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; } @@ -2264,7 +2422,7 @@ sunos_check_dynamic_reloc (info, input_bfd, input_section, harg, reloc, asection *input_section; struct aout_link_hash_entry *harg; PTR reloc; - bfd_byte *contents; + bfd_byte *contents ATTRIBUTE_UNUSED; boolean *skip; bfd_vma *relocationp; { @@ -2272,6 +2430,7 @@ sunos_check_dynamic_reloc (info, input_bfd, input_section, harg, reloc, bfd *dynobj; boolean baserel; boolean jmptbl; + boolean pcrel; asection *s; bfd_byte *p; long indx; @@ -2280,7 +2439,10 @@ sunos_check_dynamic_reloc (info, input_bfd, input_section, harg, reloc, dynobj = sunos_hash_table (info)->dynobj; - if (h != NULL && h->plt_offset != 0) + if (h != NULL + && h->plt_offset != 0 + && (info->shared + || (h->flags & SUNOS_DEF_REGULAR) == 0)) { asection *splt; @@ -2300,11 +2462,13 @@ sunos_check_dynamic_reloc (info, input_bfd, input_section, harg, reloc, { 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 @@ -2323,6 +2487,13 @@ sunos_check_dynamic_reloc (info, input_bfd, input_section, harg, reloc, || 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) @@ -2418,9 +2589,9 @@ sunos_check_dynamic_reloc (info, input_bfd, input_section, harg, reloc, srel->r_address); if (bfd_header_big_endian (dynobj)) { - srel->r_index[0] = indx >> 16; - srel->r_index[1] = indx >> 8; - srel->r_index[2] = indx; + 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 @@ -2432,9 +2603,9 @@ sunos_check_dynamic_reloc (info, input_bfd, input_section, harg, reloc, } else { - srel->r_index[2] = indx >> 16; - srel->r_index[1] = indx >> 8; - srel->r_index[0] = indx; + 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 @@ -2457,9 +2628,9 @@ sunos_check_dynamic_reloc (info, input_bfd, input_section, harg, reloc, erel->r_address); if (bfd_header_big_endian (dynobj)) { - erel->r_index[0] = indx >> 16; - erel->r_index[1] = indx >> 8; - erel->r_index[2] = indx; + 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; @@ -2470,9 +2641,9 @@ sunos_check_dynamic_reloc (info, input_bfd, input_section, harg, reloc, } else { - erel->r_index[2] = indx >> 16; - erel->r_index[1] = indx >> 8; - erel->r_index[0] = indx; + 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; @@ -2491,7 +2662,9 @@ sunos_check_dynamic_reloc (info, input_bfd, input_section, harg, reloc, *got_offsetp |= 1; } - *relocationp = sgot->vma + (*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; @@ -2548,16 +2721,18 @@ sunos_check_dynamic_reloc (info, input_bfd, input_section, harg, reloc, srel->r_address); if (bfd_header_big_endian (dynobj)) { - srel->r_index[0] = indx >> 16; - srel->r_index[1] = indx >> 8; - srel->r_index[2] = indx; + 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] = indx >> 16; - srel->r_index[1] = indx >> 8; - srel->r_index[0] = indx; + 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 { @@ -2571,15 +2746,25 @@ sunos_check_dynamic_reloc (info, input_bfd, input_section, harg, reloc, erel->r_address); if (bfd_header_big_endian (dynobj)) { - erel->r_index[0] = indx >> 16; - erel->r_index[1] = indx >> 8; - erel->r_index[2] = indx; + 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] = indx >> 16; - erel->r_index[1] = indx >> 8; - erel->r_index[0] = indx; + 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); } } @@ -2602,10 +2787,9 @@ sunos_finish_dynamic_link (abfd, info) asection *o; asection *s; asection *sdyn; - struct external_sun4_dynamic esd; - struct external_sun4_dynamic_link esdl; - if (! sunos_hash_table (info)->dynamic_sections_needed) + if (! sunos_hash_table (info)->dynamic_sections_needed + && ! sunos_hash_table (info)->got_needed) return true; dynobj = sunos_hash_table (info)->dynobj; @@ -2642,7 +2826,7 @@ sunos_finish_dynamic_link (abfd, info) dynamic information, unless this is a shared library. */ s = bfd_get_section_by_name (dynobj, ".got"); BFD_ASSERT (s != NULL); - if (info->shared) + if (info->shared || sdyn->_raw_size == 0) PUT_WORD (dynobj, 0, s->contents); else PUT_WORD (dynobj, sdyn->output_section->vma + sdyn->output_offset, @@ -2656,96 +2840,106 @@ sunos_finish_dynamic_link (abfd, info) BFD_ASSERT (o->output_section != NULL && o->output_section->owner == abfd); if (! bfd_set_section_contents (abfd, o->output_section, - o->contents, o->output_offset, + o->contents, + (file_ptr) o->output_offset, o->_raw_size)) return false; } } - /* 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, - sdyn->output_offset, sizeof esd)) - return false; + if (sdyn->_raw_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); + PUT_WORD (dynobj, (bfd_vma) 0, esdl.ld_loaded); - s = bfd_get_section_by_name (dynobj, ".need"); - if (s == NULL || s->_raw_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, ".need"); + if (s == NULL || s->_raw_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->_raw_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_section_by_name (dynobj, ".rules"); + if (s == NULL || s->_raw_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_section_by_name (dynobj, ".got"); - BFD_ASSERT (s != NULL); - PUT_WORD (dynobj, s->output_section->vma + s->output_offset, esdl.ld_got); + s = bfd_get_section_by_name (dynobj, ".got"); + BFD_ASSERT (s != NULL); + PUT_WORD (dynobj, s->output_section->vma + s->output_offset, + esdl.ld_got); - s = bfd_get_section_by_name (dynobj, ".plt"); - BFD_ASSERT (s != NULL); - PUT_WORD (dynobj, s->output_section->vma + s->output_offset, esdl.ld_plt); - PUT_WORD (dynobj, s->_raw_size, esdl.ld_plt_sz); + s = bfd_get_section_by_name (dynobj, ".plt"); + BFD_ASSERT (s != NULL); + PUT_WORD (dynobj, s->output_section->vma + s->output_offset, + esdl.ld_plt); + PUT_WORD (dynobj, s->_raw_size, esdl.ld_plt_sz); - s = bfd_get_section_by_name (dynobj, ".dynrel"); - BFD_ASSERT (s != NULL); - BFD_ASSERT (s->reloc_count * obj_reloc_entry_size (dynobj) == s->_raw_size); - PUT_WORD (dynobj, s->output_section->filepos + s->output_offset, - esdl.ld_rel); + s = bfd_get_section_by_name (dynobj, ".dynrel"); + BFD_ASSERT (s != NULL); + BFD_ASSERT (s->reloc_count * obj_reloc_entry_size (dynobj) + == s->_raw_size); + PUT_WORD (dynobj, s->output_section->filepos + s->output_offset, + esdl.ld_rel); - s = bfd_get_section_by_name (dynobj, ".hash"); - BFD_ASSERT (s != NULL); - PUT_WORD (dynobj, s->output_section->filepos + s->output_offset, - esdl.ld_hash); + s = bfd_get_section_by_name (dynobj, ".hash"); + BFD_ASSERT (s != NULL); + PUT_WORD (dynobj, s->output_section->filepos + s->output_offset, + esdl.ld_hash); - s = bfd_get_section_by_name (dynobj, ".dynsym"); - BFD_ASSERT (s != NULL); - PUT_WORD (dynobj, s->output_section->filepos + s->output_offset, - esdl.ld_stab); + s = bfd_get_section_by_name (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) 0, esdl.ld_stab_hash); - PUT_WORD (dynobj, (bfd_vma) sunos_hash_table (info)->bucketcount, - esdl.ld_buckets); + PUT_WORD (dynobj, (bfd_vma) sunos_hash_table (info)->bucketcount, + esdl.ld_buckets); - s = bfd_get_section_by_name (dynobj, ".dynstr"); - BFD_ASSERT (s != NULL); - PUT_WORD (dynobj, s->output_section->filepos + s->output_offset, - esdl.ld_symbols); - PUT_WORD (dynobj, s->_raw_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)->_raw_size, 0x2000), - esdl.ld_text); - - if (! bfd_set_section_contents (abfd, sdyn->output_section, &esdl, - (sdyn->output_offset - + sizeof esd - + EXTERNAL_SUN4_DYNAMIC_DEBUGGER_SIZE), - sizeof esdl)) - return false; + s = bfd_get_section_by_name (dynobj, ".dynstr"); + BFD_ASSERT (s != NULL); + PUT_WORD (dynobj, s->output_section->filepos + s->output_offset, + esdl.ld_symbols); + PUT_WORD (dynobj, s->_raw_size, esdl.ld_symb_size); - abfd->flags |= DYNAMIC; + /* 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)->_raw_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; }