| /* POWER/PowerPC XCOFF linker support. |
| Copyright (C) 1995-2024 Free Software Foundation, Inc. |
| Written by Ian Lance Taylor <ian@cygnus.com>, 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. */ |
| |
| #include "sysdep.h" |
| #include "bfd.h" |
| #include "bfdlink.h" |
| #include "libbfd.h" |
| #include "coff/internal.h" |
| #include "coff/xcoff.h" |
| #include "libcoff.h" |
| #include "libxcoff.h" |
| #include "libiberty.h" |
| #include "xcofflink.h" |
| |
| /* This file holds the XCOFF linker code. */ |
| |
| #undef STRING_SIZE_SIZE |
| #define STRING_SIZE_SIZE 4 |
| |
| /* The list of import files. */ |
| |
| struct xcoff_import_file |
| { |
| /* The next entry in the list. */ |
| struct xcoff_import_file *next; |
| /* The path. */ |
| const char *path; |
| /* The file name. */ |
| const char *file; |
| /* The member name. */ |
| const char *member; |
| }; |
| |
| /* Information we keep for each section in the output file during the |
| final link phase. */ |
| |
| struct xcoff_link_section_info |
| { |
| /* The relocs to be output. */ |
| struct internal_reloc *relocs; |
| /* For each reloc against a global symbol whose index was not known |
| when the reloc was handled, the global hash table entry. */ |
| struct xcoff_link_hash_entry **rel_hashes; |
| /* If there is a TOC relative reloc against a global symbol, and the |
| index of the TOC symbol is not known when the reloc was handled, |
| an entry is added to this linked list. This is not an array, |
| like rel_hashes, because this case is quite uncommon. */ |
| struct xcoff_toc_rel_hash |
| { |
| struct xcoff_toc_rel_hash *next; |
| struct xcoff_link_hash_entry *h; |
| struct internal_reloc *rel; |
| } *toc_rel_hashes; |
| }; |
| |
| /* Information that the XCOFF linker collects about an archive. */ |
| struct xcoff_archive_info |
| { |
| /* The archive described by this entry. */ |
| bfd *archive; |
| |
| /* The import path and import filename to use when referring to |
| this archive in the .loader section. */ |
| const char *imppath; |
| const char *impfile; |
| |
| /* True if the archive contains a dynamic object. */ |
| unsigned int contains_shared_object_p : 1; |
| |
| /* True if the previous field is valid. */ |
| unsigned int know_contains_shared_object_p : 1; |
| }; |
| |
| struct xcoff_link_hash_table |
| { |
| struct bfd_link_hash_table root; |
| |
| /* The stub hash table. */ |
| struct bfd_hash_table stub_hash_table; |
| |
| /* Info passed by the linker. */ |
| struct bfd_xcoff_link_params *params; |
| |
| /* The .debug string hash table. We need to compute this while |
| reading the input files, so that we know how large the .debug |
| section will be before we assign section positions. */ |
| struct bfd_strtab_hash *debug_strtab; |
| |
| /* The .debug section we will use for the final output. */ |
| asection *debug_section; |
| |
| /* The .loader section we will use for the final output. */ |
| asection *loader_section; |
| |
| /* The structure holding information about the .loader section. */ |
| struct xcoff_loader_info ldinfo; |
| |
| /* The .loader section header. */ |
| struct internal_ldhdr ldhdr; |
| |
| /* The .gl section we use to hold global linkage code. */ |
| asection *linkage_section; |
| |
| /* The .tc section we use to hold toc entries we build for global |
| linkage code. */ |
| asection *toc_section; |
| |
| /* The .ds section we use to hold function descriptors which we |
| create for exported symbols. */ |
| asection *descriptor_section; |
| |
| /* The list of import files. */ |
| struct xcoff_import_file *imports; |
| |
| /* Required alignment of sections within the output file. */ |
| unsigned long file_align; |
| |
| /* Whether the .text section must be read-only. */ |
| bool textro; |
| |
| /* Whether -brtl was specified. */ |
| bool rtld; |
| |
| /* Whether garbage collection was done. */ |
| bool gc; |
| |
| /* A linked list of symbols for which we have size information. */ |
| struct xcoff_link_size_list |
| { |
| struct xcoff_link_size_list *next; |
| struct xcoff_link_hash_entry *h; |
| bfd_size_type size; |
| } |
| *size_list; |
| |
| /* Information about archives. */ |
| htab_t archive_info; |
| |
| /* Magic sections: _text, _etext, _data, _edata, _end, end. */ |
| asection *special_sections[XCOFF_NUMBER_OF_SPECIAL_SECTIONS]; |
| }; |
| |
| /* Information that we pass around while doing the final link step. */ |
| |
| struct xcoff_final_link_info |
| { |
| /* General link information. */ |
| struct bfd_link_info *info; |
| /* Output BFD. */ |
| bfd *output_bfd; |
| /* Hash table for long symbol names. */ |
| struct bfd_strtab_hash *strtab; |
| /* Array of information kept for each output section, indexed by the |
| target_index field. */ |
| struct xcoff_link_section_info *section_info; |
| /* Symbol index of last C_FILE symbol (-1 if none). */ |
| long last_file_index; |
| /* Contents of last C_FILE symbol. */ |
| struct internal_syment last_file; |
| /* Symbol index of TOC symbol. */ |
| long toc_symindx; |
| /* Start of .loader symbols. */ |
| bfd_byte *ldsym; |
| /* Next .loader reloc to swap out. */ |
| bfd_byte *ldrel; |
| /* File position of start of line numbers. */ |
| file_ptr line_filepos; |
| /* Buffer large enough to hold swapped symbols of any input file. */ |
| struct internal_syment *internal_syms; |
| /* Buffer large enough to hold output indices of symbols of any |
| input file. */ |
| long *sym_indices; |
| /* Buffer large enough to hold output symbols for any input file. */ |
| bfd_byte *outsyms; |
| /* Buffer large enough to hold external line numbers for any input |
| section. */ |
| bfd_byte *linenos; |
| /* Buffer large enough to hold any input section. */ |
| bfd_byte *contents; |
| /* Buffer large enough to hold external relocs of any input section. */ |
| bfd_byte *external_relocs; |
| }; |
| |
| #define xcoff_stub_hash_entry(ent) \ |
| ((struct xcoff_stub_hash_entry *)(ent)) |
| |
| #define xcoff_stub_hash_lookup(table, string, create, copy) \ |
| ((struct xcoff_stub_hash_entry *) \ |
| bfd_hash_lookup ((table), (string), (create), (copy))) |
| |
| static bool xcoff_mark (struct bfd_link_info *, asection *); |
| |
| |
| |
| /* Routines to read XCOFF dynamic information. This don't really |
| belong here, but we already have the ldsym manipulation routines |
| here. */ |
| |
| /* Read the contents of a section. */ |
| |
| static bfd_byte * |
| xcoff_get_section_contents (bfd *abfd, asection *sec) |
| { |
| if (coff_section_data (abfd, sec) == NULL) |
| { |
| size_t amt = sizeof (struct coff_section_tdata); |
| |
| sec->used_by_bfd = bfd_zalloc (abfd, amt); |
| if (sec->used_by_bfd == NULL) |
| return NULL; |
| } |
| |
| bfd_byte *contents = coff_section_data (abfd, sec)->contents; |
| if (contents == NULL) |
| { |
| if (bfd_malloc_and_get_section (abfd, sec, &contents)) |
| coff_section_data (abfd, sec)->contents = contents; |
| else |
| { |
| free (contents); |
| contents = NULL; |
| } |
| } |
| |
| return contents; |
| } |
| |
| /* Get the size required to hold the dynamic symbols. */ |
| |
| long |
| _bfd_xcoff_get_dynamic_symtab_upper_bound (bfd *abfd) |
| { |
| asection *lsec; |
| bfd_byte *contents; |
| struct internal_ldhdr ldhdr; |
| |
| if ((abfd->flags & DYNAMIC) == 0) |
| { |
| bfd_set_error (bfd_error_invalid_operation); |
| return -1; |
| } |
| |
| lsec = bfd_get_section_by_name (abfd, ".loader"); |
| if (lsec == NULL || (lsec->flags & SEC_HAS_CONTENTS) == 0) |
| { |
| bfd_set_error (bfd_error_no_symbols); |
| return -1; |
| } |
| |
| contents = xcoff_get_section_contents (abfd, lsec); |
| if (!contents) |
| return -1; |
| |
| bfd_xcoff_swap_ldhdr_in (abfd, (void *) contents, &ldhdr); |
| |
| return (ldhdr.l_nsyms + 1) * sizeof (asymbol *); |
| } |
| |
| /* Get the dynamic symbols. */ |
| |
| long |
| _bfd_xcoff_canonicalize_dynamic_symtab (bfd *abfd, asymbol **psyms) |
| { |
| asection *lsec; |
| bfd_byte *contents; |
| struct internal_ldhdr ldhdr; |
| const char *strings; |
| bfd_byte *elsym, *elsymend; |
| coff_symbol_type *symbuf; |
| |
| if ((abfd->flags & DYNAMIC) == 0) |
| { |
| bfd_set_error (bfd_error_invalid_operation); |
| return -1; |
| } |
| |
| lsec = bfd_get_section_by_name (abfd, ".loader"); |
| if (lsec == NULL || (lsec->flags & SEC_HAS_CONTENTS) == 0) |
| { |
| bfd_set_error (bfd_error_no_symbols); |
| return -1; |
| } |
| |
| contents = xcoff_get_section_contents (abfd, lsec); |
| if (!contents) |
| return -1; |
| |
| bfd_xcoff_swap_ldhdr_in (abfd, contents, &ldhdr); |
| |
| strings = (char *) contents + ldhdr.l_stoff; |
| |
| symbuf = bfd_zalloc (abfd, ldhdr.l_nsyms * sizeof (* symbuf)); |
| if (symbuf == NULL) |
| return -1; |
| |
| elsym = contents + bfd_xcoff_loader_symbol_offset(abfd, &ldhdr); |
| |
| elsymend = elsym + ldhdr.l_nsyms * bfd_xcoff_ldsymsz(abfd); |
| for (; elsym < elsymend; elsym += bfd_xcoff_ldsymsz(abfd), symbuf++, psyms++) |
| { |
| struct internal_ldsym ldsym; |
| |
| bfd_xcoff_swap_ldsym_in (abfd, elsym, &ldsym); |
| |
| symbuf->symbol.the_bfd = abfd; |
| |
| if (ldsym._l._l_l._l_zeroes == 0) |
| symbuf->symbol.name = strings + ldsym._l._l_l._l_offset; |
| else |
| { |
| char *c; |
| |
| c = bfd_alloc (abfd, (bfd_size_type) SYMNMLEN + 1); |
| if (c == NULL) |
| return -1; |
| memcpy (c, ldsym._l._l_name, SYMNMLEN); |
| c[SYMNMLEN] = '\0'; |
| symbuf->symbol.name = c; |
| } |
| |
| if (ldsym.l_smclas == XMC_XO) |
| symbuf->symbol.section = bfd_abs_section_ptr; |
| else |
| symbuf->symbol.section = coff_section_from_bfd_index (abfd, |
| ldsym.l_scnum); |
| symbuf->symbol.value = ldsym.l_value - symbuf->symbol.section->vma; |
| |
| symbuf->symbol.flags = BSF_NO_FLAGS; |
| if ((ldsym.l_smtype & L_EXPORT) != 0) |
| { |
| if ((ldsym.l_smtype & L_WEAK) != 0) |
| symbuf->symbol.flags |= BSF_WEAK; |
| else |
| symbuf->symbol.flags |= BSF_GLOBAL; |
| } |
| |
| /* FIXME: We have no way to record the other information stored |
| with the loader symbol. */ |
| *psyms = (asymbol *) symbuf; |
| } |
| |
| *psyms = NULL; |
| |
| return ldhdr.l_nsyms; |
| } |
| |
| /* Get the size required to hold the dynamic relocs. */ |
| |
| long |
| _bfd_xcoff_get_dynamic_reloc_upper_bound (bfd *abfd) |
| { |
| asection *lsec; |
| bfd_byte *contents; |
| struct internal_ldhdr ldhdr; |
| |
| if ((abfd->flags & DYNAMIC) == 0) |
| { |
| bfd_set_error (bfd_error_invalid_operation); |
| return -1; |
| } |
| |
| lsec = bfd_get_section_by_name (abfd, ".loader"); |
| if (lsec == NULL || (lsec->flags & SEC_HAS_CONTENTS) == 0) |
| { |
| bfd_set_error (bfd_error_no_symbols); |
| return -1; |
| } |
| |
| contents = xcoff_get_section_contents (abfd, lsec); |
| if (!contents) |
| return -1; |
| |
| bfd_xcoff_swap_ldhdr_in (abfd, (struct external_ldhdr *) contents, &ldhdr); |
| |
| return (ldhdr.l_nreloc + 1) * sizeof (arelent *); |
| } |
| |
| /* Get the dynamic relocs. */ |
| |
| long |
| _bfd_xcoff_canonicalize_dynamic_reloc (bfd *abfd, |
| arelent **prelocs, |
| asymbol **syms) |
| { |
| asection *lsec; |
| bfd_byte *contents; |
| struct internal_ldhdr ldhdr; |
| arelent *relbuf; |
| bfd_byte *elrel, *elrelend; |
| |
| if ((abfd->flags & DYNAMIC) == 0) |
| { |
| bfd_set_error (bfd_error_invalid_operation); |
| return -1; |
| } |
| |
| lsec = bfd_get_section_by_name (abfd, ".loader"); |
| if (lsec == NULL || (lsec->flags & SEC_HAS_CONTENTS) == 0) |
| { |
| bfd_set_error (bfd_error_no_symbols); |
| return -1; |
| } |
| |
| contents = xcoff_get_section_contents (abfd, lsec); |
| if (!contents) |
| return -1; |
| |
| bfd_xcoff_swap_ldhdr_in (abfd, contents, &ldhdr); |
| |
| relbuf = bfd_alloc (abfd, ldhdr.l_nreloc * sizeof (arelent)); |
| if (relbuf == NULL) |
| return -1; |
| |
| elrel = contents + bfd_xcoff_loader_reloc_offset(abfd, &ldhdr); |
| |
| elrelend = elrel + ldhdr.l_nreloc * bfd_xcoff_ldrelsz(abfd); |
| for (; elrel < elrelend; elrel += bfd_xcoff_ldrelsz(abfd), relbuf++, |
| prelocs++) |
| { |
| struct internal_ldrel ldrel; |
| |
| bfd_xcoff_swap_ldrel_in (abfd, elrel, &ldrel); |
| |
| if (ldrel.l_symndx >= 3) |
| relbuf->sym_ptr_ptr = syms + (ldrel.l_symndx - 3); |
| else |
| { |
| const char *name; |
| asection *sec; |
| |
| switch (ldrel.l_symndx) |
| { |
| case 0: |
| name = ".text"; |
| break; |
| case 1: |
| name = ".data"; |
| break; |
| case 2: |
| name = ".bss"; |
| break; |
| default: |
| abort (); |
| break; |
| } |
| |
| sec = bfd_get_section_by_name (abfd, name); |
| if (sec == NULL) |
| { |
| bfd_set_error (bfd_error_bad_value); |
| return -1; |
| } |
| |
| relbuf->sym_ptr_ptr = sec->symbol_ptr_ptr; |
| } |
| |
| relbuf->address = ldrel.l_vaddr; |
| relbuf->addend = 0; |
| |
| /* Most dynamic relocs have the same type. FIXME: This is only |
| correct if ldrel.l_rtype == 0. In other cases, we should use |
| a different howto. */ |
| relbuf->howto = bfd_xcoff_dynamic_reloc_howto(abfd); |
| |
| /* FIXME: We have no way to record the l_rsecnm field. */ |
| |
| *prelocs = relbuf; |
| } |
| |
| *prelocs = NULL; |
| |
| return ldhdr.l_nreloc; |
| } |
| |
| /* Hash functions for xcoff_link_hash_table's archive_info. */ |
| |
| static hashval_t |
| xcoff_archive_info_hash (const void *data) |
| { |
| const struct xcoff_archive_info *info; |
| |
| info = (const struct xcoff_archive_info *) data; |
| return htab_hash_pointer (info->archive); |
| } |
| |
| static int |
| xcoff_archive_info_eq (const void *data1, const void *data2) |
| { |
| const struct xcoff_archive_info *info1; |
| const struct xcoff_archive_info *info2; |
| |
| info1 = (const struct xcoff_archive_info *) data1; |
| info2 = (const struct xcoff_archive_info *) data2; |
| return info1->archive == info2->archive; |
| } |
| |
| /* Return information about archive ARCHIVE. Return NULL on error. */ |
| |
| static struct xcoff_archive_info * |
| xcoff_get_archive_info (struct bfd_link_info *info, bfd *archive) |
| { |
| struct xcoff_link_hash_table *htab; |
| struct xcoff_archive_info *entryp, entry; |
| void **slot; |
| |
| htab = xcoff_hash_table (info); |
| entry.archive = archive; |
| slot = htab_find_slot (htab->archive_info, &entry, INSERT); |
| if (!slot) |
| return NULL; |
| |
| entryp = *slot; |
| if (!entryp) |
| { |
| entryp = bfd_zalloc (info->output_bfd, sizeof (entry)); |
| if (!entryp) |
| return NULL; |
| |
| entryp->archive = archive; |
| *slot = entryp; |
| } |
| return entryp; |
| } |
| |
| |
| /* Initialize an entry in the stub hash table. */ |
| static struct bfd_hash_entry * |
| stub_hash_newfunc (struct bfd_hash_entry *entry, |
| struct bfd_hash_table *table, |
| const char *string) |
| { |
| /* Allocate the structure if it has not already been allocated by a |
| subclass. */ |
| if (entry == NULL) |
| { |
| entry = bfd_hash_allocate (table, |
| sizeof (struct xcoff_stub_hash_entry)); |
| if (entry == NULL) |
| return entry; |
| } |
| |
| /* Call the allocation method of the superclass. */ |
| entry = bfd_hash_newfunc (entry, table, string); |
| if (entry != NULL) |
| { |
| struct xcoff_stub_hash_entry *hsh; |
| |
| /* Initialize the local fields. */ |
| hsh = (struct xcoff_stub_hash_entry *) entry; |
| hsh->stub_type = xcoff_stub_none; |
| hsh->hcsect = NULL; |
| hsh->stub_offset = 0; |
| hsh->target_section = NULL; |
| hsh->htarget = NULL; |
| } |
| |
| return entry; |
| } |
| |
| /* Routine to create an entry in an XCOFF link hash table. */ |
| |
| static struct bfd_hash_entry * |
| xcoff_link_hash_newfunc (struct bfd_hash_entry *entry, |
| struct bfd_hash_table *table, |
| const char *string) |
| { |
| struct xcoff_link_hash_entry *ret = (struct xcoff_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 xcoff_link_hash_entry *) |
| _bfd_link_hash_newfunc ((struct bfd_hash_entry *) ret, |
| table, string)); |
| if (ret != NULL) |
| { |
| /* Set local fields. */ |
| ret->indx = -1; |
| ret->toc_section = NULL; |
| ret->u.toc_indx = -1; |
| ret->descriptor = NULL; |
| ret->ldsym = NULL; |
| ret->ldindx = -1; |
| ret->flags = 0; |
| ret->smclas = XMC_UA; |
| } |
| |
| return (struct bfd_hash_entry *) ret; |
| } |
| |
| /* Destroy an XCOFF link hash table. */ |
| |
| static void |
| _bfd_xcoff_bfd_link_hash_table_free (bfd *obfd) |
| { |
| struct xcoff_link_hash_table *ret; |
| |
| ret = (struct xcoff_link_hash_table *) obfd->link.hash; |
| if (ret->archive_info) |
| htab_delete (ret->archive_info); |
| if (ret->debug_strtab) |
| _bfd_stringtab_free (ret->debug_strtab); |
| |
| bfd_hash_table_free (&ret->stub_hash_table); |
| _bfd_generic_link_hash_table_free (obfd); |
| } |
| |
| /* Create an XCOFF link hash table. */ |
| |
| struct bfd_link_hash_table * |
| _bfd_xcoff_bfd_link_hash_table_create (bfd *abfd) |
| { |
| struct xcoff_link_hash_table *ret; |
| bool isxcoff64 = false; |
| size_t amt = sizeof (* ret); |
| |
| ret = bfd_zmalloc (amt); |
| if (ret == NULL) |
| return NULL; |
| if (!_bfd_link_hash_table_init (&ret->root, abfd, xcoff_link_hash_newfunc, |
| sizeof (struct xcoff_link_hash_entry))) |
| { |
| free (ret); |
| return NULL; |
| } |
| |
| /* Init the stub hash table too. */ |
| if (!bfd_hash_table_init (&ret->stub_hash_table, stub_hash_newfunc, |
| sizeof (struct xcoff_stub_hash_entry))) |
| { |
| _bfd_xcoff_bfd_link_hash_table_free (abfd); |
| return NULL; |
| } |
| |
| isxcoff64 = bfd_coff_debug_string_prefix_length (abfd) == 4; |
| |
| ret->debug_strtab = _bfd_xcoff_stringtab_init (isxcoff64); |
| ret->archive_info = htab_create (37, xcoff_archive_info_hash, |
| xcoff_archive_info_eq, NULL); |
| if (!ret->debug_strtab || !ret->archive_info) |
| { |
| _bfd_xcoff_bfd_link_hash_table_free (abfd); |
| return NULL; |
| } |
| ret->root.hash_table_free = _bfd_xcoff_bfd_link_hash_table_free; |
| |
| /* The linker will always generate a full a.out header. We need to |
| record that fact now, before the sizeof_headers routine could be |
| called. */ |
| xcoff_data (abfd)->full_aouthdr = true; |
| |
| return &ret->root; |
| } |
| |
| /* Read internal relocs for an XCOFF csect. This is a wrapper around |
| _bfd_coff_read_internal_relocs which tries to take advantage of any |
| relocs which may have been cached for the enclosing section. */ |
| |
| static struct internal_reloc * |
| xcoff_read_internal_relocs (bfd *abfd, |
| asection *sec, |
| bool cache, |
| bfd_byte *external_relocs, |
| bool require_internal, |
| struct internal_reloc *internal_relocs) |
| { |
| if (coff_section_data (abfd, sec) != NULL |
| && coff_section_data (abfd, sec)->relocs == NULL |
| && xcoff_section_data (abfd, sec) != NULL) |
| { |
| asection *enclosing; |
| |
| enclosing = xcoff_section_data (abfd, sec)->enclosing; |
| |
| if (enclosing != NULL |
| && (coff_section_data (abfd, enclosing) == NULL |
| || coff_section_data (abfd, enclosing)->relocs == NULL) |
| && cache |
| && enclosing->reloc_count > 0) |
| { |
| if (_bfd_coff_read_internal_relocs (abfd, enclosing, true, |
| external_relocs, false, NULL) |
| == NULL) |
| return NULL; |
| } |
| |
| if (enclosing != NULL |
| && coff_section_data (abfd, enclosing) != NULL |
| && coff_section_data (abfd, enclosing)->relocs != NULL) |
| { |
| size_t off; |
| |
| off = ((sec->rel_filepos - enclosing->rel_filepos) |
| / bfd_coff_relsz (abfd)); |
| |
| if (! require_internal) |
| return coff_section_data (abfd, enclosing)->relocs + off; |
| memcpy (internal_relocs, |
| coff_section_data (abfd, enclosing)->relocs + off, |
| sec->reloc_count * sizeof (struct internal_reloc)); |
| return internal_relocs; |
| } |
| } |
| |
| return _bfd_coff_read_internal_relocs (abfd, sec, cache, external_relocs, |
| require_internal, internal_relocs); |
| } |
| |
| /* Split FILENAME into an import path and an import filename, |
| storing them in *IMPPATH and *IMPFILE respectively. */ |
| |
| bool |
| bfd_xcoff_split_import_path (bfd *abfd, const char *filename, |
| const char **imppath, const char **impfile) |
| { |
| const char *base; |
| size_t length; |
| char *path; |
| |
| base = lbasename (filename); |
| length = base - filename; |
| if (length == 0) |
| /* The filename has no directory component, so use an empty path. */ |
| *imppath = ""; |
| else if (length == 1) |
| /* The filename is in the root directory. */ |
| *imppath = "/"; |
| else |
| { |
| /* Extract the (non-empty) directory part. Note that we don't |
| need to strip duplicate directory separators from any part |
| of the string; the native linker doesn't do that either. */ |
| path = bfd_alloc (abfd, length); |
| if (path == NULL) |
| return false; |
| memcpy (path, filename, length - 1); |
| path[length - 1] = 0; |
| *imppath = path; |
| } |
| *impfile = base; |
| return true; |
| } |
| |
| /* Set ARCHIVE's import path as though its filename had been given |
| as FILENAME. */ |
| |
| bool |
| bfd_xcoff_set_archive_import_path (struct bfd_link_info *info, |
| bfd *archive, const char *filename) |
| { |
| struct xcoff_archive_info *archive_info; |
| |
| archive_info = xcoff_get_archive_info (info, archive); |
| return (archive_info != NULL |
| && bfd_xcoff_split_import_path (archive, filename, |
| &archive_info->imppath, |
| &archive_info->impfile)); |
| } |
| |
| /* H is an imported symbol. Set the import module's path, file and member |
| to IMPATH, IMPFILE and IMPMEMBER respectively. All three are null if |
| no specific import module is specified. */ |
| |
| static bool |
| xcoff_set_import_path (struct bfd_link_info *info, |
| struct xcoff_link_hash_entry *h, |
| const char *imppath, const char *impfile, |
| const char *impmember) |
| { |
| unsigned int c; |
| struct xcoff_import_file **pp; |
| |
| /* We overload the ldindx field to hold the l_ifile value for this |
| symbol. */ |
| BFD_ASSERT (h->ldsym == NULL); |
| BFD_ASSERT ((h->flags & XCOFF_BUILT_LDSYM) == 0); |
| if (imppath == NULL) |
| h->ldindx = -1; |
| else |
| { |
| /* We start c at 1 because the first entry in the import list is |
| reserved for the library search path. */ |
| for (pp = &xcoff_hash_table (info)->imports, c = 1; |
| *pp != NULL; |
| pp = &(*pp)->next, ++c) |
| { |
| if (filename_cmp ((*pp)->path, imppath) == 0 |
| && filename_cmp ((*pp)->file, impfile) == 0 |
| && filename_cmp ((*pp)->member, impmember) == 0) |
| break; |
| } |
| |
| if (*pp == NULL) |
| { |
| struct xcoff_import_file *n; |
| size_t amt = sizeof (*n); |
| |
| n = bfd_alloc (info->output_bfd, amt); |
| if (n == NULL) |
| return false; |
| n->next = NULL; |
| n->path = imppath; |
| n->file = impfile; |
| n->member = impmember; |
| *pp = n; |
| } |
| h->ldindx = c; |
| } |
| return true; |
| } |
| |
| /* H is the bfd symbol associated with exported .loader symbol LDSYM. |
| Return true if LDSYM defines H. */ |
| |
| static bool |
| xcoff_dynamic_definition_p (struct xcoff_link_hash_entry *h, |
| struct internal_ldsym *ldsym) |
| { |
| /* If we didn't know about H before processing LDSYM, LDSYM |
| definitely defines H. */ |
| if (h->root.type == bfd_link_hash_new) |
| return true; |
| |
| /* If H is currently a weak dynamic symbol, and if LDSYM is a strong |
| dynamic symbol, LDSYM trumps the current definition of H. */ |
| if ((ldsym->l_smtype & L_WEAK) == 0 |
| && (h->flags & XCOFF_DEF_DYNAMIC) != 0 |
| && (h->flags & XCOFF_DEF_REGULAR) == 0 |
| && (h->root.type == bfd_link_hash_defweak |
| || h->root.type == bfd_link_hash_undefweak)) |
| return true; |
| |
| /* If H is currently undefined, LDSYM defines it. |
| However, if H has a hidden visibility, LDSYM must not |
| define it. */ |
| if ((h->flags & XCOFF_DEF_DYNAMIC) == 0 |
| && (h->root.type == bfd_link_hash_undefined |
| || h->root.type == bfd_link_hash_undefweak) |
| && (h->visibility != SYM_V_HIDDEN |
| && h->visibility != SYM_V_INTERNAL)) |
| return true; |
| |
| return false; |
| } |
| |
| /* This function is used to add symbols from a dynamic object to the |
| global symbol table. */ |
| |
| static bool |
| xcoff_link_add_dynamic_symbols (bfd *abfd, struct bfd_link_info *info) |
| { |
| asection *lsec; |
| bfd_byte *contents; |
| struct internal_ldhdr ldhdr; |
| const char *strings; |
| bfd_byte *elsym, *elsymend; |
| struct xcoff_import_file *n; |
| unsigned int c; |
| struct xcoff_import_file **pp; |
| |
| /* We can only handle a dynamic object if we are generating an XCOFF |
| output file. */ |
| if (info->output_bfd->xvec != abfd->xvec) |
| { |
| _bfd_error_handler |
| (_("%pB: XCOFF shared object when not producing XCOFF output"), |
| abfd); |
| bfd_set_error (bfd_error_invalid_operation); |
| return false; |
| } |
| |
| /* The symbols we use from a dynamic object are not the symbols in |
| the normal symbol table, but, rather, the symbols in the export |
| table. If there is a global symbol in a dynamic object which is |
| not in the export table, the loader will not be able to find it, |
| so we don't want to find it either. Also, on AIX 4.1.3, shr.o in |
| libc.a has symbols in the export table which are not in the |
| symbol table. */ |
| |
| /* Read in the .loader section. FIXME: We should really use the |
| o_snloader field in the a.out header, rather than grabbing the |
| section by name. */ |
| lsec = bfd_get_section_by_name (abfd, ".loader"); |
| if (lsec == NULL || (lsec->flags & SEC_HAS_CONTENTS) == 0) |
| { |
| _bfd_error_handler |
| (_("%pB: dynamic object with no .loader section"), |
| abfd); |
| bfd_set_error (bfd_error_no_symbols); |
| return false; |
| } |
| |
| contents = xcoff_get_section_contents (abfd, lsec); |
| if (!contents) |
| return false; |
| |
| /* Remove the sections from this object, so that they do not get |
| included in the link. */ |
| bfd_section_list_clear (abfd); |
| |
| bfd_xcoff_swap_ldhdr_in (abfd, contents, &ldhdr); |
| |
| strings = (char *) contents + ldhdr.l_stoff; |
| |
| elsym = contents + bfd_xcoff_loader_symbol_offset(abfd, &ldhdr); |
| |
| elsymend = elsym + ldhdr.l_nsyms * bfd_xcoff_ldsymsz(abfd); |
| |
| for (; elsym < elsymend; elsym += bfd_xcoff_ldsymsz(abfd)) |
| { |
| struct internal_ldsym ldsym; |
| char nambuf[SYMNMLEN + 1]; |
| const char *name; |
| struct xcoff_link_hash_entry *h; |
| |
| bfd_xcoff_swap_ldsym_in (abfd, elsym, &ldsym); |
| |
| /* We are only interested in exported symbols. */ |
| if ((ldsym.l_smtype & L_EXPORT) == 0) |
| continue; |
| |
| if (ldsym._l._l_l._l_zeroes == 0) |
| name = strings + ldsym._l._l_l._l_offset; |
| else |
| { |
| memcpy (nambuf, ldsym._l._l_name, SYMNMLEN); |
| nambuf[SYMNMLEN] = '\0'; |
| name = nambuf; |
| } |
| |
| /* Normally we could not call xcoff_link_hash_lookup in an add |
| symbols routine, since we might not be using an XCOFF hash |
| table. However, we verified above that we are using an XCOFF |
| hash table. */ |
| |
| h = xcoff_link_hash_lookup (xcoff_hash_table (info), name, true, |
| true, true); |
| if (h == NULL) |
| return false; |
| |
| if (!xcoff_dynamic_definition_p (h, &ldsym)) |
| continue; |
| |
| h->flags |= XCOFF_DEF_DYNAMIC; |
| h->smclas = ldsym.l_smclas; |
| if (h->smclas == XMC_XO) |
| { |
| /* This symbol has an absolute value. */ |
| if ((ldsym.l_smtype & L_WEAK) != 0) |
| h->root.type = bfd_link_hash_defweak; |
| else |
| h->root.type = bfd_link_hash_defined; |
| h->root.u.def.section = bfd_abs_section_ptr; |
| h->root.u.def.value = ldsym.l_value; |
| } |
| else |
| { |
| /* Otherwise, we don't bother to actually define the symbol, |
| since we don't have a section to put it in anyhow. |
| We assume instead that an undefined XCOFF_DEF_DYNAMIC symbol |
| should be imported from the symbol's undef.abfd. */ |
| if ((ldsym.l_smtype & L_WEAK) != 0) |
| h->root.type = bfd_link_hash_undefweak; |
| else |
| h->root.type = bfd_link_hash_undefined; |
| h->root.u.undef.abfd = abfd; |
| } |
| |
| /* If this symbol defines a function descriptor, then it |
| implicitly defines the function code as well. */ |
| if (h->smclas == XMC_DS |
| || (h->smclas == XMC_XO && name[0] != '.')) |
| h->flags |= XCOFF_DESCRIPTOR; |
| if ((h->flags & XCOFF_DESCRIPTOR) != 0) |
| { |
| struct xcoff_link_hash_entry *hds; |
| |
| hds = h->descriptor; |
| if (hds == NULL) |
| { |
| char *dsnm; |
| |
| dsnm = bfd_malloc ((bfd_size_type) strlen (name) + 2); |
| if (dsnm == NULL) |
| return false; |
| dsnm[0] = '.'; |
| strcpy (dsnm + 1, name); |
| hds = xcoff_link_hash_lookup (xcoff_hash_table (info), dsnm, |
| true, true, true); |
| free (dsnm); |
| if (hds == NULL) |
| return false; |
| |
| hds->descriptor = h; |
| h->descriptor = hds; |
| } |
| |
| if (xcoff_dynamic_definition_p (hds, &ldsym)) |
| { |
| hds->root.type = h->root.type; |
| hds->flags |= XCOFF_DEF_DYNAMIC; |
| if (h->smclas == XMC_XO) |
| { |
| /* An absolute symbol appears to actually define code, not a |
| function descriptor. This is how some math functions are |
| implemented on AIX 4.1. */ |
| hds->smclas = XMC_XO; |
| hds->root.u.def.section = bfd_abs_section_ptr; |
| hds->root.u.def.value = ldsym.l_value; |
| } |
| else |
| { |
| hds->smclas = XMC_PR; |
| hds->root.u.undef.abfd = abfd; |
| /* We do not want to add this to the undefined |
| symbol list. */ |
| } |
| } |
| } |
| } |
| |
| free (contents); |
| coff_section_data (abfd, lsec)->contents = NULL; |
| |
| /* Record this file in the import files. */ |
| n = bfd_alloc (abfd, (bfd_size_type) sizeof (struct xcoff_import_file)); |
| if (n == NULL) |
| return false; |
| n->next = NULL; |
| |
| if (abfd->my_archive == NULL || bfd_is_thin_archive (abfd->my_archive)) |
| { |
| if (!bfd_xcoff_split_import_path (abfd, bfd_get_filename (abfd), |
| &n->path, &n->file)) |
| return false; |
| n->member = ""; |
| } |
| else |
| { |
| struct xcoff_archive_info *archive_info; |
| |
| archive_info = xcoff_get_archive_info (info, abfd->my_archive); |
| if (!archive_info->impfile) |
| { |
| if (!bfd_xcoff_split_import_path (archive_info->archive, |
| bfd_get_filename (archive_info |
| ->archive), |
| &archive_info->imppath, |
| &archive_info->impfile)) |
| return false; |
| } |
| n->path = archive_info->imppath; |
| n->file = archive_info->impfile; |
| n->member = bfd_get_filename (abfd); |
| } |
| |
| /* We start c at 1 because the first import file number is reserved |
| for LIBPATH. */ |
| for (pp = &xcoff_hash_table (info)->imports, c = 1; |
| *pp != NULL; |
| pp = &(*pp)->next, ++c) |
| ; |
| *pp = n; |
| |
| xcoff_data (abfd)->import_file_id = c; |
| |
| return true; |
| } |
| |
| /* xcoff_link_create_extra_sections |
| |
| Takes care of creating the .loader, .gl, .ds, .debug and sections. */ |
| |
| static bool |
| xcoff_link_create_extra_sections (bfd * abfd, struct bfd_link_info *info) |
| { |
| bool return_value = false; |
| |
| if (info->output_bfd->xvec == abfd->xvec) |
| { |
| /* We need to build a .loader section, so we do it here. This |
| won't work if we're producing an XCOFF output file with no |
| XCOFF input files. FIXME. */ |
| |
| if (!bfd_link_relocatable (info) |
| && xcoff_hash_table (info)->loader_section == NULL) |
| { |
| asection *lsec; |
| flagword flags = SEC_HAS_CONTENTS | SEC_IN_MEMORY; |
| |
| lsec = bfd_make_section_anyway_with_flags (abfd, ".loader", flags); |
| if (lsec == NULL) |
| goto end_return; |
| |
| xcoff_hash_table (info)->loader_section = lsec; |
| } |
| |
| /* Likewise for the linkage section. */ |
| if (xcoff_hash_table (info)->linkage_section == NULL) |
| { |
| asection *lsec; |
| flagword flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS |
| | SEC_IN_MEMORY); |
| |
| lsec = bfd_make_section_anyway_with_flags (abfd, ".gl", flags); |
| if (lsec == NULL) |
| goto end_return; |
| |
| xcoff_hash_table (info)->linkage_section = lsec; |
| lsec->alignment_power = 2; |
| } |
| |
| /* Likewise for the TOC section. */ |
| if (xcoff_hash_table (info)->toc_section == NULL) |
| { |
| asection *tsec; |
| flagword flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS |
| | SEC_IN_MEMORY); |
| |
| tsec = bfd_make_section_anyway_with_flags (abfd, ".tc", flags); |
| if (tsec == NULL) |
| goto end_return; |
| |
| xcoff_hash_table (info)->toc_section = tsec; |
| tsec->alignment_power = 2; |
| } |
| |
| /* Likewise for the descriptor section. */ |
| if (xcoff_hash_table (info)->descriptor_section == NULL) |
| { |
| asection *dsec; |
| flagword flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS |
| | SEC_IN_MEMORY); |
| |
| dsec = bfd_make_section_anyway_with_flags (abfd, ".ds", flags); |
| if (dsec == NULL) |
| goto end_return; |
| |
| xcoff_hash_table (info)->descriptor_section = dsec; |
| dsec->alignment_power = 2; |
| } |
| |
| /* Likewise for the .debug section. */ |
| if (xcoff_hash_table (info)->debug_section == NULL |
| && info->strip != strip_all) |
| { |
| asection *dsec; |
| flagword flags = SEC_HAS_CONTENTS | SEC_IN_MEMORY; |
| |
| dsec = bfd_make_section_anyway_with_flags (abfd, ".debug", flags); |
| if (dsec == NULL) |
| goto end_return; |
| |
| xcoff_hash_table (info)->debug_section = dsec; |
| } |
| } |
| |
| return_value = true; |
| |
| end_return: |
| |
| return return_value; |
| } |
| |
| /* Returns the index of reloc in RELOCS with the least address greater |
| than or equal to ADDRESS. The relocs are sorted by address. */ |
| |
| static bfd_size_type |
| xcoff_find_reloc (struct internal_reloc *relocs, |
| bfd_size_type count, |
| bfd_vma address) |
| { |
| bfd_size_type min, max, this; |
| |
| if (count < 2) |
| { |
| if (count == 1 && relocs[0].r_vaddr < address) |
| return 1; |
| else |
| return 0; |
| } |
| |
| min = 0; |
| max = count; |
| |
| /* Do a binary search over (min,max]. */ |
| while (min + 1 < max) |
| { |
| bfd_vma raddr; |
| |
| this = (max + min) / 2; |
| raddr = relocs[this].r_vaddr; |
| if (raddr > address) |
| max = this; |
| else if (raddr < address) |
| min = this; |
| else |
| { |
| min = this; |
| break; |
| } |
| } |
| |
| if (relocs[min].r_vaddr < address) |
| return min + 1; |
| |
| while (min > 0 |
| && relocs[min - 1].r_vaddr == address) |
| --min; |
| |
| return min; |
| } |
| |
| /* Return true if the symbol has to be added to the linker hash |
| table. */ |
| static bool |
| xcoff_link_add_symbols_to_hash_table (struct internal_syment sym, |
| union internal_auxent aux) |
| { |
| /* External symbols must be added. */ |
| if (EXTERN_SYM_P (sym.n_sclass)) |
| return true; |
| |
| /* Hidden TLS symbols must be added to verify TLS relocations |
| in xcoff_reloc_type_tls. */ |
| if (sym.n_sclass == C_HIDEXT |
| && ((aux.x_csect.x_smclas == XMC_TL |
| || aux.x_csect.x_smclas == XMC_UL))) |
| return true; |
| |
| return false; |
| } |
| |
| /* Add all the symbols from an object file to the hash table. |
| |
| XCOFF is a weird format. A normal XCOFF .o files will have three |
| COFF sections--.text, .data, and .bss--but each COFF section will |
| contain many csects. These csects are described in the symbol |
| table. From the linker's point of view, each csect must be |
| considered a section in its own right. For example, a TOC entry is |
| handled as a small XMC_TC csect. The linker must be able to merge |
| different TOC entries together, which means that it must be able to |
| extract the XMC_TC csects from the .data section of the input .o |
| file. |
| |
| From the point of view of our linker, this is, of course, a hideous |
| nightmare. We cope by actually creating sections for each csect, |
| and discarding the original sections. We then have to handle the |
| relocation entries carefully, since the only way to tell which |
| csect they belong to is to examine the address. */ |
| |
| static bool |
| xcoff_link_add_symbols (bfd *abfd, struct bfd_link_info *info) |
| { |
| unsigned int n_tmask; |
| unsigned int n_btshft; |
| bool default_copy; |
| bfd_size_type symcount; |
| struct xcoff_link_hash_entry **sym_hash; |
| asection **csect_cache; |
| unsigned int *lineno_counts; |
| bfd_size_type linesz; |
| asection *o; |
| asection *last_real; |
| bool keep_syms; |
| asection *csect; |
| unsigned int csect_index; |
| asection *first_csect; |
| bfd_size_type symesz; |
| bfd_byte *esym; |
| bfd_byte *esym_end; |
| struct reloc_info_struct |
| { |
| struct internal_reloc *relocs; |
| asection **csects; |
| bfd_byte *linenos; |
| } *reloc_info = NULL; |
| bfd_size_type amt; |
| unsigned short visibility; |
| |
| keep_syms = obj_coff_keep_syms (abfd); |
| |
| if ((abfd->flags & DYNAMIC) != 0 |
| && ! info->static_link) |
| { |
| if (! xcoff_link_add_dynamic_symbols (abfd, info)) |
| return false; |
| } |
| |
| /* Create the loader, toc, gl, ds and debug sections, if needed. */ |
| if (! xcoff_link_create_extra_sections (abfd, info)) |
| goto error_return; |
| |
| if ((abfd->flags & DYNAMIC) != 0 |
| && ! info->static_link) |
| return true; |
| |
| n_tmask = coff_data (abfd)->local_n_tmask; |
| n_btshft = coff_data (abfd)->local_n_btshft; |
| |
| /* Define macros so that ISFCN, et. al., macros work correctly. */ |
| #define N_TMASK n_tmask |
| #define N_BTSHFT n_btshft |
| |
| if (info->keep_memory) |
| default_copy = false; |
| else |
| default_copy = true; |
| |
| symcount = obj_raw_syment_count (abfd); |
| |
| /* We keep a list of the linker hash table entries that correspond |
| to each external symbol. */ |
| amt = symcount * sizeof (struct xcoff_link_hash_entry *); |
| sym_hash = bfd_zalloc (abfd, amt); |
| if (sym_hash == NULL && symcount != 0) |
| goto error_return; |
| coff_data (abfd)->sym_hashes = (struct coff_link_hash_entry **) sym_hash; |
| |
| /* Because of the weird stuff we are doing with XCOFF csects, we can |
| not easily determine which section a symbol is in, so we store |
| the information in the tdata for the input file. */ |
| amt = symcount * sizeof (asection *); |
| csect_cache = bfd_zalloc (abfd, amt); |
| if (csect_cache == NULL && symcount != 0) |
| goto error_return; |
| xcoff_data (abfd)->csects = csect_cache; |
| |
| /* We garbage-collect line-number information on a symbol-by-symbol |
| basis, so we need to have quick access to the number of entries |
| per symbol. */ |
| amt = symcount * sizeof (unsigned int); |
| lineno_counts = bfd_zalloc (abfd, amt); |
| if (lineno_counts == NULL && symcount != 0) |
| goto error_return; |
| xcoff_data (abfd)->lineno_counts = lineno_counts; |
| |
| /* While splitting sections into csects, we need to assign the |
| relocs correctly. The relocs and the csects must both be in |
| order by VMA within a given section, so we handle this by |
| scanning along the relocs as we process the csects. We index |
| into reloc_info using the section target_index. */ |
| amt = abfd->section_count + 1; |
| amt *= sizeof (struct reloc_info_struct); |
| reloc_info = bfd_zmalloc (amt); |
| if (reloc_info == NULL) |
| goto error_return; |
| |
| /* Read in the relocs and line numbers for each section. */ |
| linesz = bfd_coff_linesz (abfd); |
| last_real = NULL; |
| for (o = abfd->sections; o != NULL; o = o->next) |
| { |
| last_real = o; |
| |
| if ((o->flags & SEC_RELOC) != 0) |
| { |
| reloc_info[o->target_index].relocs = |
| xcoff_read_internal_relocs (abfd, o, true, NULL, false, NULL); |
| amt = o->reloc_count; |
| amt *= sizeof (asection *); |
| reloc_info[o->target_index].csects = bfd_zmalloc (amt); |
| if (reloc_info[o->target_index].csects == NULL) |
| goto error_return; |
| } |
| |
| if ((info->strip == strip_none || info->strip == strip_some) |
| && o->lineno_count > 0) |
| { |
| bfd_byte *linenos; |
| |
| if (bfd_seek (abfd, o->line_filepos, SEEK_SET) != 0) |
| goto error_return; |
| if (_bfd_mul_overflow (linesz, o->lineno_count, &amt)) |
| { |
| bfd_set_error (bfd_error_file_too_big); |
| goto error_return; |
| } |
| linenos = _bfd_malloc_and_read (abfd, amt, amt); |
| if (linenos == NULL) |
| goto error_return; |
| reloc_info[o->target_index].linenos = linenos; |
| } |
| } |
| |
| /* Don't let the linker relocation routines discard the symbols. */ |
| obj_coff_keep_syms (abfd) = true; |
| |
| csect = NULL; |
| csect_index = 0; |
| first_csect = NULL; |
| |
| symesz = bfd_coff_symesz (abfd); |
| BFD_ASSERT (symesz == bfd_coff_auxesz (abfd)); |
| esym = (bfd_byte *) obj_coff_external_syms (abfd); |
| esym_end = esym + symcount * symesz; |
| |
| while (esym < esym_end) |
| { |
| struct internal_syment sym; |
| union internal_auxent aux; |
| const char *name; |
| char buf[SYMNMLEN + 1]; |
| int smtyp; |
| asection *section; |
| bfd_vma value; |
| struct xcoff_link_hash_entry *set_toc; |
| |
| bfd_coff_swap_sym_in (abfd, (void *) esym, (void *) &sym); |
| |
| /* In this pass we are only interested in symbols with csect |
| information. */ |
| if (!CSECT_SYM_P (sym.n_sclass)) |
| { |
| /* Set csect_cache, |
| Normally csect is a .pr, .rw etc. created in the loop |
| If C_FILE or first time, handle special |
| |
| Advance esym, sym_hash, csect_hash ptrs. */ |
| if (sym.n_sclass == C_FILE || sym.n_sclass == C_DWARF) |
| csect = NULL; |
| if (csect != NULL) |
| *csect_cache = csect; |
| else if (first_csect == NULL |
| || sym.n_sclass == C_FILE || sym.n_sclass == C_DWARF) |
| *csect_cache = coff_section_from_bfd_index (abfd, sym.n_scnum); |
| else |
| *csect_cache = NULL; |
| esym += (sym.n_numaux + 1) * symesz; |
| sym_hash += sym.n_numaux + 1; |
| csect_cache += sym.n_numaux + 1; |
| lineno_counts += sym.n_numaux + 1; |
| |
| continue; |
| } |
| |
| name = _bfd_coff_internal_syment_name (abfd, &sym, buf); |
| |
| if (name == NULL) |
| goto error_return; |
| |
| /* If this symbol has line number information attached to it, |
| and we're not stripping it, count the number of entries and |
| add them to the count for this csect. In the final link pass |
| we are going to attach line number information by symbol, |
| rather than by section, in order to more easily handle |
| garbage collection. */ |
| if ((info->strip == strip_none || info->strip == strip_some) |
| && sym.n_numaux > 1 |
| && csect != NULL |
| && ISFCN (sym.n_type)) |
| { |
| union internal_auxent auxlin; |
| |
| bfd_coff_swap_aux_in (abfd, (void *) (esym + symesz), |
| sym.n_type, sym.n_sclass, |
| 0, sym.n_numaux, (void *) &auxlin); |
| |
| if (auxlin.x_sym.x_fcnary.x_fcn.x_lnnoptr != 0) |
| { |
| asection *enclosing; |
| bfd_signed_vma linoff; |
| |
| enclosing = xcoff_section_data (abfd, csect)->enclosing; |
| if (enclosing == NULL) |
| { |
| _bfd_error_handler |
| /* xgettext:c-format */ |
| (_("%pB: `%s' has line numbers but no enclosing section"), |
| abfd, name); |
| bfd_set_error (bfd_error_bad_value); |
| goto error_return; |
| } |
| linoff = (auxlin.x_sym.x_fcnary.x_fcn.x_lnnoptr |
| - enclosing->line_filepos); |
| /* Explicit cast to bfd_signed_vma for compiler. */ |
| if (linoff < (bfd_signed_vma) (enclosing->lineno_count * linesz)) |
| { |
| struct internal_lineno lin; |
| bfd_byte *linpstart; |
| |
| linpstart = (reloc_info[enclosing->target_index].linenos |
| + linoff); |
| bfd_coff_swap_lineno_in (abfd, (void *) linpstart, (void *) &lin); |
| if (lin.l_lnno == 0 |
| && ((bfd_size_type) lin.l_addr.l_symndx |
| == ((esym |
| - (bfd_byte *) obj_coff_external_syms (abfd)) |
| / symesz))) |
| { |
| bfd_byte *linpend, *linp; |
| |
| linpend = (reloc_info[enclosing->target_index].linenos |
| + enclosing->lineno_count * linesz); |
| for (linp = linpstart + linesz; |
| linp < linpend; |
| linp += linesz) |
| { |
| bfd_coff_swap_lineno_in (abfd, (void *) linp, |
| (void *) &lin); |
| if (lin.l_lnno == 0) |
| break; |
| } |
| *lineno_counts = (linp - linpstart) / linesz; |
| /* The setting of line_filepos will only be |
| useful if all the line number entries for a |
| csect are contiguous; this only matters for |
| error reporting. */ |
| if (csect->line_filepos == 0) |
| csect->line_filepos = |
| auxlin.x_sym.x_fcnary.x_fcn.x_lnnoptr; |
| } |
| } |
| } |
| } |
| |
| /* Record visibility. */ |
| visibility = sym.n_type & SYM_V_MASK; |
| |
| /* Pick up the csect auxiliary information. */ |
| if (sym.n_numaux == 0) |
| { |
| _bfd_error_handler |
| /* xgettext:c-format */ |
| (_("%pB: class %d symbol `%s' has no aux entries"), |
| abfd, sym.n_sclass, name); |
| bfd_set_error (bfd_error_bad_value); |
| goto error_return; |
| } |
| |
| bfd_coff_swap_aux_in (abfd, |
| (void *) (esym + symesz * sym.n_numaux), |
| sym.n_type, sym.n_sclass, |
| sym.n_numaux - 1, sym.n_numaux, |
| (void *) &aux); |
| |
| smtyp = SMTYP_SMTYP (aux.x_csect.x_smtyp); |
| |
| section = NULL; |
| value = 0; |
| set_toc = NULL; |
| |
| switch (smtyp) |
| { |
| default: |
| _bfd_error_handler |
| /* xgettext:c-format */ |
| (_("%pB: symbol `%s' has unrecognized csect type %d"), |
| abfd, name, smtyp); |
| bfd_set_error (bfd_error_bad_value); |
| goto error_return; |
| |
| case XTY_ER: |
| /* This is an external reference. */ |
| if (sym.n_sclass == C_HIDEXT |
| || sym.n_scnum != N_UNDEF |
| || aux.x_csect.x_scnlen.u64 != 0) |
| { |
| _bfd_error_handler |
| /* xgettext:c-format */ |
| (_("%pB: bad XTY_ER symbol `%s': class %d scnum %d " |
| "scnlen %" PRId64), |
| abfd, name, sym.n_sclass, sym.n_scnum, |
| aux.x_csect.x_scnlen.u64); |
| bfd_set_error (bfd_error_bad_value); |
| goto error_return; |
| } |
| |
| /* An XMC_XO external reference is actually a reference to |
| an absolute location. */ |
| if (aux.x_csect.x_smclas != XMC_XO) |
| section = bfd_und_section_ptr; |
| else |
| { |
| section = bfd_abs_section_ptr; |
| value = sym.n_value; |
| } |
| break; |
| |
| case XTY_SD: |
| csect = NULL; |
| csect_index = -(unsigned) 1; |
| |
| /* When we see a TOC anchor, we record the TOC value. */ |
| if (aux.x_csect.x_smclas == XMC_TC0) |
| { |
| if (sym.n_sclass != C_HIDEXT |
| || aux.x_csect.x_scnlen.u64 != 0) |
| { |
| _bfd_error_handler |
| /* xgettext:c-format */ |
| (_("%pB: XMC_TC0 symbol `%s' is class %d scnlen %" PRIu64), |
| abfd, name, sym.n_sclass, aux.x_csect.x_scnlen.u64); |
| bfd_set_error (bfd_error_bad_value); |
| goto error_return; |
| } |
| xcoff_data (abfd)->toc = sym.n_value; |
| } |
| |
| /* We must merge TOC entries for the same symbol. We can |
| merge two TOC entries if they are both C_HIDEXT, they |
| both have the same name, they are both 4 or 8 bytes long, and |
| they both have a relocation table entry for an external |
| symbol with the same name. Unfortunately, this means |
| that we must look through the relocations. Ick. |
| |
| Logic for 32 bit vs 64 bit. |
| 32 bit has a csect length of 4 for TOC |
| 64 bit has a csect length of 8 for TOC |
| |
| An exception is made for TOC entries with a R_TLSML |
| relocation. This relocation is made for the loader. |
| We must check that the referenced symbol is the TOC entry |
| itself. |
| |
| The conditions to get past the if-check are not that bad. |
| They are what is used to create the TOC csects in the first |
| place. */ |
| if (aux.x_csect.x_smclas == XMC_TC |
| && sym.n_sclass == C_HIDEXT |
| && info->output_bfd->xvec == abfd->xvec |
| && ((bfd_xcoff_is_xcoff32 (abfd) |
| && aux.x_csect.x_scnlen.u64 == 4) |
| || (bfd_xcoff_is_xcoff64 (abfd) |
| && aux.x_csect.x_scnlen.u64 == 8))) |
| { |
| asection *enclosing; |
| struct internal_reloc *relocs; |
| bfd_size_type relindx; |
| struct internal_reloc *rel; |
| |
| enclosing = coff_section_from_bfd_index (abfd, sym.n_scnum); |
| if (enclosing == NULL) |
| goto error_return; |
| |
| relocs = reloc_info[enclosing->target_index].relocs; |
| amt = enclosing->reloc_count; |
| relindx = xcoff_find_reloc (relocs, amt, sym.n_value); |
| rel = relocs + relindx; |
| |
| /* 32 bit R_POS r_size is 31 |
| 64 bit R_POS r_size is 63 */ |
| if (relindx < enclosing->reloc_count |
| && rel->r_vaddr == (bfd_vma) sym.n_value |
| && (rel->r_type == R_POS || |
| rel->r_type == R_TLSML) |
| && ((bfd_xcoff_is_xcoff32 (abfd) |
| && rel->r_size == 31) |
| || (bfd_xcoff_is_xcoff64 (abfd) |
| && rel->r_size == 63))) |
| { |
| bfd_byte *erelsym; |
| |
| struct internal_syment relsym; |
| |
| erelsym = ((bfd_byte *) obj_coff_external_syms (abfd) |
| + rel->r_symndx * symesz); |
| bfd_coff_swap_sym_in (abfd, (void *) erelsym, (void *) &relsym); |
| if (EXTERN_SYM_P (relsym.n_sclass)) |
| { |
| const char *relname; |
| char relbuf[SYMNMLEN + 1]; |
| bool copy; |
| struct xcoff_link_hash_entry *h; |
| |
| /* At this point we know that the TOC entry is |
| for an externally visible symbol. */ |
| relname = _bfd_coff_internal_syment_name (abfd, &relsym, |
| relbuf); |
| if (relname == NULL) |
| goto error_return; |
| |
| /* We only merge TOC entries if the TC name is |
| the same as the symbol name. This handles |
| the normal case, but not common cases like |
| SYM.P4 which gcc generates to store SYM + 4 |
| in the TOC. FIXME. */ |
| if (strcmp (name, relname) == 0) |
| { |
| copy = (! info->keep_memory |
| || relsym._n._n_n._n_zeroes != 0 |
| || relsym._n._n_n._n_offset == 0); |
| h = xcoff_link_hash_lookup (xcoff_hash_table (info), |
| relname, true, copy, |
| false); |
| if (h == NULL) |
| goto error_return; |
| |
| /* At this point h->root.type could be |
| bfd_link_hash_new. That should be OK, |
| since we know for sure that we will come |
| across this symbol as we step through the |
| file. */ |
| |
| /* We store h in *sym_hash for the |
| convenience of the relocate_section |
| function. */ |
| *sym_hash = h; |
| |
| if (h->toc_section != NULL) |
| { |
| asection **rel_csects; |
| |
| /* We already have a TOC entry for this |
| symbol, so we can just ignore this |
| one. */ |
| rel_csects = |
| reloc_info[enclosing->target_index].csects; |
| rel_csects[relindx] = bfd_und_section_ptr; |
| break; |
| } |
| |
| /* We are about to create a TOC entry for |
| this symbol. */ |
| set_toc = h; |
| } |
| } |
| else if (rel->r_type == R_TLSML) |
| { |
| csect_index = ((esym |
| - (bfd_byte *) obj_coff_external_syms (abfd)) |
| / symesz); |
| if (((unsigned long) rel->r_symndx) != csect_index) |
| { |
| _bfd_error_handler |
| /* xgettext:c-format */ |
| (_("%pB: TOC entry `%s' has a R_TLSML" |
| "relocation not targeting itself"), |
| abfd, name); |
| bfd_set_error (bfd_error_bad_value); |
| goto error_return; |
| } |
| } |
| } |
| } |
| |
| { |
| asection *enclosing; |
| |
| /* We need to create a new section. We get the name from |
| the csect storage mapping class, so that the linker can |
| accumulate similar csects together. */ |
| |
| csect = bfd_xcoff_create_csect_from_smclas(abfd, &aux, name); |
| if (NULL == csect) |
| goto error_return; |
| |
| /* The enclosing section is the main section : .data, .text |
| or .bss that the csect is coming from. */ |
| enclosing = coff_section_from_bfd_index (abfd, sym.n_scnum); |
| if (enclosing == NULL) |
| goto error_return; |
| |
| if (! bfd_is_abs_section (enclosing) |
| && ((bfd_vma) sym.n_value < enclosing->vma |
| || (sym.n_value + aux.x_csect.x_scnlen.u64 |
| > enclosing->vma + enclosing->size))) |
| { |
| _bfd_error_handler |
| /* xgettext:c-format */ |
| (_("%pB: csect `%s' not in enclosing section"), |
| abfd, name); |
| bfd_set_error (bfd_error_bad_value); |
| goto error_return; |
| } |
| csect->vma = sym.n_value; |
| csect->filepos = (enclosing->filepos |
| + sym.n_value |
| - enclosing->vma); |
| csect->size = aux.x_csect.x_scnlen.u64; |
| csect->rawsize = aux.x_csect.x_scnlen.u64; |
| csect->flags |= SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS; |
| csect->alignment_power = SMTYP_ALIGN (aux.x_csect.x_smtyp); |
| |
| /* Record the enclosing section in the tdata for this new |
| section. */ |
| amt = sizeof (struct coff_section_tdata); |
| csect->used_by_bfd = bfd_zalloc (abfd, amt); |
| if (csect->used_by_bfd == NULL) |
| goto error_return; |
| amt = sizeof (struct xcoff_section_tdata); |
| coff_section_data (abfd, csect)->tdata = bfd_zalloc (abfd, amt); |
| if (coff_section_data (abfd, csect)->tdata == NULL) |
| goto error_return; |
| xcoff_section_data (abfd, csect)->enclosing = enclosing; |
| xcoff_section_data (abfd, csect)->lineno_count = |
| enclosing->lineno_count; |
| |
| if (enclosing->owner == abfd) |
| { |
| struct internal_reloc *relocs; |
| bfd_size_type relindx; |
| struct internal_reloc *rel; |
| asection **rel_csect; |
| |
| relocs = reloc_info[enclosing->target_index].relocs; |
| amt = enclosing->reloc_count; |
| relindx = xcoff_find_reloc (relocs, amt, csect->vma); |
| |
| rel = relocs + relindx; |
| rel_csect = (reloc_info[enclosing->target_index].csects |
| + relindx); |
| |
| csect->rel_filepos = (enclosing->rel_filepos |
| + relindx * bfd_coff_relsz (abfd)); |
| while (relindx < enclosing->reloc_count |
| && *rel_csect == NULL |
| && rel->r_vaddr < csect->vma + csect->size) |
| { |
| |
| *rel_csect = csect; |
| csect->flags |= SEC_RELOC; |
| ++csect->reloc_count; |
| ++relindx; |
| ++rel; |
| ++rel_csect; |
| } |
| } |
| |
| /* There are a number of other fields and section flags |
| which we do not bother to set. */ |
| |
| csect_index = ((esym |
| - (bfd_byte *) obj_coff_external_syms (abfd)) |
| / symesz); |
| |
| xcoff_section_data (abfd, csect)->first_symndx = csect_index; |
| |
| if (first_csect == NULL) |
| first_csect = csect; |
| |
| /* If this symbol must be added to the linker hash table, |
| we treat it as starting at the beginning of the newly |
| created section. */ |
| if (xcoff_link_add_symbols_to_hash_table (sym, aux)) |
| { |
| section = csect; |
| value = 0; |
| } |
| |
| /* If this is a TOC section for a symbol, record it. */ |
| if (set_toc != NULL) |
| set_toc->toc_section = csect; |
| } |
| break; |
| |
| case XTY_LD: |
| /* This is a label definition. The x_scnlen field is the |
| symbol index of the csect. Usually the XTY_LD symbol will |
| follow its appropriate XTY_SD symbol. The .set pseudo op can |
| cause the XTY_LD to not follow the XTY_SD symbol. */ |
| { |
| bool bad; |
| |
| bad = false; |
| if (aux.x_csect.x_scnlen.u64 |
| >= (size_t) (esym - (bfd_byte *) obj_coff_external_syms (abfd))) |
| bad = true; |
| if (! bad) |
| { |
| section = xcoff_data (abfd)->csects[aux.x_csect.x_scnlen.u64]; |
| if (section == NULL |
| || (section->flags & SEC_HAS_CONTENTS) == 0) |
| bad = true; |
| } |
| if (bad) |
| { |
| _bfd_error_handler |
| /* xgettext:c-format */ |
| (_("%pB: misplaced XTY_LD `%s'"), |
| abfd, name); |
| bfd_set_error (bfd_error_bad_value); |
| goto error_return; |
| } |
| csect = section; |
| value = sym.n_value - csect->vma; |
| } |
| break; |
| |
| case XTY_CM: |
| /* This is an unitialized csect. We could base the name on |
| the storage mapping class, but we don't bother except for |
| an XMC_TD symbol. If this csect is externally visible, |
| it is a common symbol. We put XMC_TD symbols in sections |
| named .tocbss, and rely on the linker script to put that |
| in the TOC area. */ |
| |
| if (aux.x_csect.x_smclas == XMC_TD) |
| { |
| /* The linker script puts the .td section in the data |
| section after the .tc section. */ |
| csect = bfd_make_section_anyway_with_flags (abfd, ".td", |
| SEC_ALLOC); |
| } |
| else if (aux.x_csect.x_smclas == XMC_UL) |
| { |
| /* This is a thread-local unitialized csect. */ |
| csect = bfd_make_section_anyway_with_flags (abfd, ".tbss", |
| SEC_ALLOC | SEC_THREAD_LOCAL); |
| } |
| else |
| csect = bfd_make_section_anyway_with_flags (abfd, ".bss", |
| SEC_ALLOC); |
| |
| if (csect == NULL) |
| goto error_return; |
| csect->vma = sym.n_value; |
| csect->size = aux.x_csect.x_scnlen.u64; |
| csect->alignment_power = SMTYP_ALIGN (aux.x_csect.x_smtyp); |
| /* There are a number of other fields and section flags |
| which we do not bother to set. */ |
| |
| csect_index = ((esym |
| - (bfd_byte *) obj_coff_external_syms (abfd)) |
| / symesz); |
| |
| amt = sizeof (struct coff_section_tdata); |
| csect->used_by_bfd = bfd_zalloc (abfd, amt); |
| if (csect->used_by_bfd == NULL) |
| goto error_return; |
| amt = sizeof (struct xcoff_section_tdata); |
| coff_section_data (abfd, csect)->tdata = bfd_zalloc (abfd, amt); |
| if (coff_section_data (abfd, csect)->tdata == NULL) |
| goto error_return; |
| xcoff_section_data (abfd, csect)->first_symndx = csect_index; |
| |
| if (first_csect == NULL) |
| first_csect = csect; |
| |
| if (xcoff_link_add_symbols_to_hash_table (sym, aux)) |
| { |
| csect->flags |= SEC_IS_COMMON; |
| csect->size = 0; |
| section = csect; |
| value = aux.x_csect.x_scnlen.u64; |
| } |
| |
| break; |
| } |
| |
| /* Check for magic symbol names. */ |
| if ((smtyp == XTY_SD || smtyp == XTY_CM) |
| && aux.x_csect.x_smclas != XMC_TC |
| && aux.x_csect.x_smclas != XMC_TD) |
| { |
| int i = -1; |
| |
| if (name[0] == '_') |
| { |
| if (strcmp (name, "_text") == 0) |
| i = XCOFF_SPECIAL_SECTION_TEXT; |
| else if (strcmp (name, "_etext") == 0) |
| i = XCOFF_SPECIAL_SECTION_ETEXT; |
| else if (strcmp (name, "_data") == 0) |
| i = XCOFF_SPECIAL_SECTION_DATA; |
| else if (strcmp (name, "_edata") == 0) |
| i = XCOFF_SPECIAL_SECTION_EDATA; |
| else if (strcmp (name, "_end") == 0) |
| i = XCOFF_SPECIAL_SECTION_END; |
| } |
| else if (name[0] == 'e' && strcmp (name, "end") == 0) |
| i = XCOFF_SPECIAL_SECTION_END2; |
| |
| if (i != -1) |
| xcoff_hash_table (info)->special_sections[i] = csect; |
| } |
| |
| /* Now we have enough information to add the symbol to the |
| linker hash table. */ |
| |
| if (xcoff_link_add_symbols_to_hash_table (sym, aux)) |
| { |
| bool copy, ok; |
| flagword flags; |
| |
| BFD_ASSERT (section != NULL); |
| |
| /* We must copy the name into memory if we got it from the |
| syment itself, rather than the string table. */ |
| copy = default_copy; |
| if (sym._n._n_n._n_zeroes != 0 |
| || sym._n._n_n._n_offset == 0) |
| copy = true; |
| |
| /* Ignore global linkage code when linking statically. */ |
| if (info->static_link |
| && (smtyp == XTY_SD || smtyp == XTY_LD) |
| && aux.x_csect.x_smclas == XMC_GL) |
| { |
| section = bfd_und_section_ptr; |
| value = 0; |
| } |
| |
| /* The AIX linker appears to only detect multiple symbol |
| definitions when there is a reference to the symbol. If |
| a symbol is defined multiple times, and the only |
| references are from the same object file, the AIX linker |
| appears to permit it. It does not merge the different |
| definitions, but handles them independently. On the |
| other hand, if there is a reference, the linker reports |
| an error. |
| |
| This matters because the AIX <net/net_globals.h> header |
| file actually defines an initialized array, so we have to |
| actually permit that to work. |
| |
| Just to make matters even more confusing, the AIX linker |
| appears to permit multiple symbol definitions whenever |
| the second definition is in an archive rather than an |
| object file. This may be a consequence of the manner in |
| which it handles archives: I think it may load the entire |
| archive in as separate csects, and then let garbage |
| collection discard symbols. |
| |
| We also have to handle the case of statically linking a |
| shared object, which will cause symbol redefinitions, |
| although this is an easier case to detect. */ |
| else if (info->output_bfd->xvec == abfd->xvec) |
| { |
| if (! bfd_is_und_section (section)) |
| *sym_hash = xcoff_link_hash_lookup (xcoff_hash_table (info), |
| name, true, copy, false); |
| else |
| /* Make a copy of the symbol name to prevent problems with |
| merging symbols. */ |
| *sym_hash = ((struct xcoff_link_hash_entry *) |
| bfd_wrapped_link_hash_lookup (abfd, info, name, |
| true, true, false)); |
| |
| if (*sym_hash == NULL) |
| goto error_return; |
| if (((*sym_hash)->root.type == bfd_link_hash_defined |
| || (*sym_hash)->root.type == bfd_link_hash_defweak) |
| && ! bfd_is_und_section (section) |
| && ! bfd_is_com_section (section)) |
| { |
| /* This is a second definition of a defined symbol. */ |
| if (((*sym_hash)->flags & XCOFF_DEF_REGULAR) == 0 |
| && ((*sym_hash)->flags & XCOFF_DEF_DYNAMIC) != 0) |
| { |
| /* The existing symbol is from a shared library. |
| Replace it. */ |
| (*sym_hash)->root.type = bfd_link_hash_undefined; |
| (*sym_hash)->root.u.undef.abfd = |
| (*sym_hash)->root.u.def.section->owner; |
| } |
| else if (abfd->my_archive != NULL) |
| { |
| /* This is a redefinition in an object contained |
| in an archive. Just ignore it. See the |
| comment above. */ |
| section = bfd_und_section_ptr; |
| value = 0; |
| } |
| else if (sym.n_sclass == C_AIX_WEAKEXT |
| || (*sym_hash)->root.type == bfd_link_hash_defweak) |
| { |
| /* At least one of the definitions is weak. |
| Allow the normal rules to take effect. */ |
| } |
| else if ((*sym_hash)->root.u.undef.next != NULL |
| || info->hash->undefs_tail == &(*sym_hash)->root) |
| { |
| /* This symbol has been referenced. In this |
| case, we just continue and permit the |
| multiple definition error. See the comment |
| above about the behaviour of the AIX linker. */ |
| } |
| else if ((*sym_hash)->smclas == aux.x_csect.x_smclas) |
| { |
| /* The symbols are both csects of the same |
| class. There is at least a chance that this |
| is a semi-legitimate redefinition. */ |
| section = bfd_und_section_ptr; |
| value = 0; |
| (*sym_hash)->flags |= XCOFF_MULTIPLY_DEFINED; |
| } |
| } |
| else if (((*sym_hash)->flags & XCOFF_MULTIPLY_DEFINED) != 0 |
| && (*sym_hash)->root.type == bfd_link_hash_defined |
| && (bfd_is_und_section (section) |
| || bfd_is_com_section (section))) |
| { |
| /* This is a reference to a multiply defined symbol. |
| Report the error now. See the comment above |
| about the behaviour of the AIX linker. We could |
| also do this with warning symbols, but I'm not |
| sure the XCOFF linker is wholly prepared to |
| handle them, and that would only be a warning, |
| not an error. */ |
| (*info->callbacks->multiple_definition) (info, |
| &(*sym_hash)->root, |
| NULL, NULL, |
| (bfd_vma) 0); |
| /* Try not to give this error too many times. */ |
| (*sym_hash)->flags &= ~XCOFF_MULTIPLY_DEFINED; |
| } |
| |
| |
| /* If the symbol is hidden or internal, completely undo |
| any dynamic link state. */ |
| if ((*sym_hash)->flags & XCOFF_DEF_DYNAMIC |
| && (visibility == SYM_V_HIDDEN |
| || visibility == SYM_V_INTERNAL)) |
| (*sym_hash)->flags &= ~XCOFF_DEF_DYNAMIC; |
| else |
| { |
| /* Keep the most constraining visibility. */ |
| unsigned short hvis = (*sym_hash)->visibility; |
| if (visibility && ( !hvis || visibility < hvis)) |
| (*sym_hash)->visibility = visibility; |
| } |
| |
| } |
| |
| /* _bfd_generic_link_add_one_symbol may call the linker to |
| generate an error message, and the linker may try to read |
| the symbol table to give a good error. Right now, the |
| line numbers are in an inconsistent state, since they are |
| counted both in the real sections and in the new csects. |
| We need to leave the count in the real sections so that |
| the linker can report the line number of the error |
| correctly, so temporarily clobber the link to the csects |
| so that the linker will not try to read the line numbers |
| a second time from the csects. */ |
| BFD_ASSERT (last_real->next == first_csect); |
| last_real->next = NULL; |
| flags = (sym.n_sclass == C_EXT ? BSF_GLOBAL : BSF_WEAK); |
| ok = (_bfd_generic_link_add_one_symbol |
| (info, abfd, name, flags, section, value, NULL, copy, true, |
| (struct bfd_link_hash_entry **) sym_hash)); |
| last_real->next = first_csect; |
| if (!ok) |
| goto error_return; |
| |
| if (smtyp == XTY_CM) |
| { |
| if ((*sym_hash)->root.type != bfd_link_hash_common |
| || (*sym_hash)->root.u.c.p->section != csect) |
| /* We don't need the common csect we just created. */ |
| csect->size = 0; |
| else |
| (*sym_hash)->root.u.c.p->alignment_power |
| = csect->alignment_power; |
| } |
| |
| if (info->output_bfd->xvec == abfd->xvec) |
| { |
| int flag; |
| |
| if (smtyp == XTY_ER |
| || smtyp == XTY_CM |
| || section == bfd_und_section_ptr) |
| flag = XCOFF_REF_REGULAR; |
| else |
| flag = XCOFF_DEF_REGULAR; |
| (*sym_hash)->flags |= flag; |
| |
| if ((*sym_hash)->smclas == XMC_UA |
| || flag == XCOFF_DEF_REGULAR) |
| (*sym_hash)->smclas = aux.x_csect.x_smclas; |
| } |
| } |
| |
| if (smtyp == XTY_ER) |
| *csect_cache = section; |
| else |
| { |
| *csect_cache = csect; |
| if (csect != NULL) |
| xcoff_section_data (abfd, csect)->last_symndx |
| = (esym - (bfd_byte *) obj_coff_external_syms (abfd)) / symesz; |
| } |
| |
| esym += (sym.n_numaux + 1) * symesz; |
| sym_hash += sym.n_numaux + 1; |
| csect_cache += sym.n_numaux + 1; |
| lineno_counts += sym.n_numaux + 1; |
| } |
| |
| BFD_ASSERT (last_real == NULL || last_real->next == first_csect); |
| |
| /* Make sure that we have seen all the relocs. */ |
| for (o = abfd->sections; o != first_csect; o = o->next) |
| { |
| /* Debugging sections have no csects. */ |
| if (bfd_section_flags (o) & SEC_DEBUGGING) |
| continue; |
| |
| /* Reset the section size and the line number count, since the |
| data is now attached to the csects. Don't reset the size of |
| the .debug section, since we need to read it below in |
| bfd_xcoff_size_dynamic_sections. */ |
| if (strcmp (bfd_section_name (o), ".debug") != 0) |
| o->size = 0; |
| o->lineno_count = 0; |
| |
| if ((o->flags & SEC_RELOC) != 0) |
| { |
| bfd_size_type i; |
| struct internal_reloc *rel; |
| asection **rel_csect; |
| |
| rel = reloc_info[o->target_index].relocs; |
| rel_csect = reloc_info[o->target_index].csects; |
| |
| for (i = 0; i < o->reloc_count; i++, rel++, rel_csect++) |
| { |
| if (*rel_csect == NULL) |
| { |
| _bfd_error_handler |
| /* xgettext:c-format */ |
| (_("%pB: reloc %s:%" PRId64 " not in csect"), |
| abfd, o->name, (int64_t) i); |
| bfd_set_error (bfd_error_bad_value); |
| goto error_return; |
| } |
| |
| /* We identify all function symbols that are the target |
| of a relocation, so that we can create glue code for |
| functions imported from dynamic objects. */ |
| if (info->output_bfd->xvec == abfd->xvec |
| && *rel_csect != bfd_und_section_ptr |
| && obj_xcoff_sym_hashes (abfd)[rel->r_symndx] != NULL) |
| { |
| struct xcoff_link_hash_entry *h; |
| |
| h = obj_xcoff_sym_hashes (abfd)[rel->r_symndx]; |
| /* If the symbol name starts with a period, it is |
| the code of a function. If the symbol is |
| currently undefined, then add an undefined symbol |
| for the function descriptor. This should do no |
| harm, because any regular object that defines the |
| function should also define the function |
| descriptor. It helps, because it means that we |
| will identify the function descriptor with a |
| dynamic object if a dynamic object defines it. */ |
| if (h->root.root.string[0] == '.' |
| && h->descriptor == NULL) |
| { |
| struct xcoff_link_hash_entry *hds; |
| struct bfd_link_hash_entry *bh; |
| |
| hds = xcoff_link_hash_lookup (xcoff_hash_table (info), |
| h->root.root.string + 1, |
| true, false, true); |
| if (hds == NULL) |
| goto error_return; |
| if (hds->root.type == bfd_link_hash_new) |
| { |
| bh = &hds->root; |
| if (! (_bfd_generic_link_add_one_symbol |
| (info, abfd, hds->root.root.string, |
| (flagword) 0, bfd_und_section_ptr, |
| (bfd_vma) 0, NULL, false, |
| true, &bh))) |
| goto error_return; |
| hds = (struct xcoff_link_hash_entry *) bh; |
| } |
| hds->flags |= XCOFF_DESCRIPTOR; |
| BFD_ASSERT ((h->flags & XCOFF_DESCRIPTOR) == 0); |
| hds->descriptor = h; |
| h->descriptor = hds; |
| } |
| if (h->root.root.string[0] == '.') |
| h->flags |= XCOFF_CALLED; |
| } |
| } |
| |
| free (reloc_info[o->target_index].csects); |
| reloc_info[o->target_index].csects = NULL; |
| |
| /* Reset SEC_RELOC and the reloc_count, since the reloc |
| information is now attached to the csects. */ |
| o->flags &=~ SEC_RELOC; |
| o->reloc_count = 0; |
| |
| /* If we are not keeping memory, free the reloc information. */ |
| if (! info->keep_memory |
| && coff_section_data (abfd, o) != NULL) |
| { |
| free (coff_section_data (abfd, o)->relocs); |
| coff_section_data (abfd, o)->relocs = NULL; |
| } |
| } |
| |
| /* Free up the line numbers. FIXME: We could cache these |
| somewhere for the final link, to avoid reading them again. */ |
| free (reloc_info[o->target_index].linenos); |
| reloc_info[o->target_index].linenos = NULL; |
| } |
| |
| free (reloc_info); |
| |
| obj_coff_keep_syms (abfd) = keep_syms; |
| |
| return true; |
| |
| error_return: |
| if (reloc_info != NULL) |
| { |
| for (o = abfd->sections; o != NULL; o = o->next) |
| { |
| free (reloc_info[o->target_index].csects); |
| free (reloc_info[o->target_index].linenos); |
| } |
| free (reloc_info); |
| } |
| obj_coff_keep_syms (abfd) = keep_syms; |
| return false; |
| } |
| |
| #undef N_TMASK |
| #undef N_BTSHFT |
| |
| /* Add symbols from an XCOFF object file. */ |
| |
| static bool |
| xcoff_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info) |
| { |
| if (! _bfd_coff_get_external_symbols (abfd)) |
| return false; |
| if (! xcoff_link_add_symbols (abfd, info)) |
| return false; |
| if (! info->keep_memory) |
| { |
| if (! _bfd_coff_free_symbols (abfd)) |
| return false; |
| } |
| return true; |
| } |
| |
| /* Look through the loader symbols to see if this dynamic object |
| should be included in the link. The native linker uses the loader |
| symbols, not the normal symbol table, so we do too. */ |
| |
| static bool |
| xcoff_link_check_dynamic_ar_symbols (bfd *abfd, |
| struct bfd_link_info *info, |
| bool *pneeded, |
| bfd **subsbfd) |
| { |
| asection *lsec; |
| bfd_byte *contents; |
| struct internal_ldhdr ldhdr; |
| const char *strings; |
| bfd_byte *elsym, *elsymend; |
| |
| *pneeded = false; |
| |
| lsec = bfd_get_section_by_name (abfd, ".loader"); |
| if (lsec == NULL || (lsec->flags & SEC_HAS_CONTENTS) == 0) |
| /* There are no symbols, so don't try to include it. */ |
| return true; |
| |
| contents = xcoff_get_section_contents (abfd, lsec); |
| if (!contents) |
| return false; |
| |
| bfd_xcoff_swap_ldhdr_in (abfd, contents, &ldhdr); |
| |
| strings = (char *) contents + ldhdr.l_stoff; |
| |
| elsym = contents + bfd_xcoff_loader_symbol_offset (abfd, &ldhdr); |
| |
| elsymend = elsym + ldhdr.l_nsyms * bfd_xcoff_ldsymsz (abfd); |
| for (; elsym < elsymend; elsym += bfd_xcoff_ldsymsz (abfd)) |
| { |
| struct internal_ldsym ldsym; |
| char nambuf[SYMNMLEN + 1]; |
| const char *name; |
| struct bfd_link_hash_entry *h; |
| |
| bfd_xcoff_swap_ldsym_in (abfd, elsym, &ldsym); |
| |
| /* We are only interested in exported symbols. */ |
| if ((ldsym.l_smtype & L_EXPORT) == 0) |
| continue; |
| |
| if (ldsym._l._l_l._l_zeroes == 0) |
| name = strings + ldsym._l._l_l._l_offset; |
| else |
| { |
| memcpy (nambuf, ldsym._l._l_name, SYMNMLEN); |
| nambuf[SYMNMLEN] = '\0'; |
| name = nambuf; |
| } |
| |
| h = bfd_link_hash_lookup (info->hash, name, false, false, true); |
| |
| /* We are only interested in symbols that are currently |
| undefined. At this point we know that we are using an XCOFF |
| hash table. */ |
| if (h != NULL |
| && h->type == bfd_link_hash_undefined |
| && (((struct xcoff_link_hash_entry *) h)->flags |
| & XCOFF_DEF_DYNAMIC) == 0) |
| { |
| if (!(*info->callbacks |
| ->add_archive_element) (info, abfd, name, subsbfd)) |
| continue; |
| *pneeded = true; |
| return true; |
| } |
| } |
| |
| /* We do not need this shared object's .loader section. */ |
| free (contents); |
| coff_section_data (abfd, lsec)->contents = NULL; |
| |
| return true; |
| } |
| |
| /* Look through the symbols to see if this object file should be |
| included in the link. */ |
| |
| static bool |
| xcoff_link_check_ar_symbols (bfd *abfd, |
| struct bfd_link_info *info, |
| bool *pneeded, |
| bfd **subsbfd) |
| { |
| bfd_size_type symesz; |
| bfd_byte *esym; |
| bfd_byte *esym_end; |
| |
| *pneeded = false; |
| |
| if ((abfd->flags & DYNAMIC) != 0 |
| && ! info->static_link |
| && info->output_bfd->xvec == abfd->xvec) |
| return xcoff_link_check_dynamic_ar_symbols (abfd, info, pneeded, subsbfd); |
| |
| symesz = bfd_coff_symesz (abfd); |
| esym = (bfd_byte *) obj_coff_external_syms (abfd); |
| esym_end = esym + obj_raw_syment_count (abfd) * symesz; |
| while (esym < esym_end) |
| { |
| struct internal_syment sym; |
| |
| bfd_coff_swap_sym_in (abfd, (void *) esym, (void *) &sym); |
| esym += (sym.n_numaux + 1) * symesz; |
| |
| if (EXTERN_SYM_P (sym.n_sclass) && sym.n_scnum != N_UNDEF) |
| { |
| const char *name; |
| char buf[SYMNMLEN + 1]; |
| struct bfd_link_hash_entry *h; |
| |
| /* This symbol is externally visible, and is defined by this |
| object file. */ |
| name = _bfd_coff_internal_syment_name (abfd, &sym, buf); |
| |
| if (name == NULL) |
| return false; |
| h = bfd_link_hash_lookup (info->hash, name, false, false, true); |
| |
| /* We are only interested in symbols that are currently |
| undefined. If a symbol is currently known to be common, |
| XCOFF linkers do not bring in an object file which |
| defines it. We also don't bring in symbols to satisfy |
| undefined references in shared objects. */ |
| if (h != NULL |
| && h->type == bfd_link_hash_undefined |
| && (info->output_bfd->xvec != abfd->xvec |
| || (((struct xcoff_link_hash_entry *) h)->flags |
| & XCOFF_DEF_DYNAMIC) == 0)) |
| { |
| if (!(*info->callbacks |
| ->add_archive_element) (info, abfd, name, subsbfd)) |
| continue; |
| *pneeded = true; |
| return true; |
| } |
| } |
| } |
| |
| /* We do not need this object file. */ |
| return true; |
| } |
| |
| /* Check a single archive element to see if we need to include it in |
| the link. *PNEEDED is set according to whether this element is |
| needed in the link or not. This is called via |
| _bfd_generic_link_add_archive_symbols. */ |
| |
| static bool |
| xcoff_link_check_archive_element (bfd *abfd, |
| struct bfd_link_info *info, |
| struct bfd_link_hash_entry *h ATTRIBUTE_UNUSED, |
| const char *name ATTRIBUTE_UNUSED, |
| bool *pneeded) |
| { |
| bool keep_syms_p; |
| bfd *oldbfd; |
| |
| keep_syms_p = (obj_coff_external_syms (abfd) != NULL); |
| if (!_bfd_coff_get_external_symbols (abfd)) |
| return false; |
| |
| oldbfd = abfd; |
| if (!xcoff_link_check_ar_symbols (abfd, info, pneeded, &abfd)) |
| return false; |
| |
| if (*pneeded) |
| { |
| /* Potentially, the add_archive_element hook may have set a |
| substitute BFD for us. */ |
| if (abfd != oldbfd) |
| { |
| if (!keep_syms_p |
| && !_bfd_coff_free_symbols (oldbfd)) |
| return false; |
| keep_syms_p = (obj_coff_external_syms (abfd) != NULL); |
| if (!_bfd_coff_get_external_symbols (abfd)) |
| return false; |
| } |
| if (!xcoff_link_add_symbols (abfd, info)) |
| return false; |
| if (info->keep_memory) |
| keep_syms_p = true; |
| } |
| |
| if (!keep_syms_p) |
| { |
| if (!_bfd_coff_free_symbols (abfd)) |
| return false; |
| } |
| |
| return true; |
| } |
| |
| /* Given an XCOFF BFD, add symbols to the global hash table as |
| appropriate. */ |
| |
| bool |
| _bfd_xcoff_bfd_link_add_symbols (bfd *abfd, struct bfd_link_info *info) |
| { |
| switch (bfd_get_format (abfd)) |
| { |
| case bfd_object: |
| return xcoff_link_add_object_symbols (abfd, info); |
| |
| case bfd_archive: |
| /* If the archive has a map, do the usual search. We then need |
| to check the archive for dynamic objects, because they may not |
| appear in the archive map even though they should, perhaps, be |
| included. If the archive has no map, we just consider each object |
| file in turn, since that apparently is what the AIX native linker |
| does. */ |
| if (bfd_has_map (abfd)) |
| { |
| if (! (_bfd_generic_link_add_archive_symbols |
| (abfd, info, xcoff_link_check_archive_element))) |
| return false; |
| } |
| |
| { |
| bfd *member; |
| |
| member = bfd_openr_next_archived_file (abfd, NULL); |
| while (member != NULL) |
| { |
| if (bfd_check_format (member, bfd_object) |
| && (info->output_bfd->xvec == member->xvec) |
| && (! bfd_has_map (abfd) || (member->flags & DYNAMIC) != 0)) |
| { |
| bool needed; |
| |
| if (! xcoff_link_check_archive_element (member, info, |
| NULL, NULL, &needed)) |
| return false; |
| if (needed) |
| member->archive_pass = -1; |
| } |
| member = bfd_openr_next_archived_file (abfd, member); |
| } |
| } |
| |
| return true; |
| |
| default: |
| bfd_set_error (bfd_error_wrong_format); |
| return false; |
| } |
| } |
| |
| bool |
| _bfd_xcoff_define_common_symbol (bfd *output_bfd ATTRIBUTE_UNUSED, |
| struct bfd_link_info *info ATTRIBUTE_UNUSED, |
| struct bfd_link_hash_entry *harg) |
| { |
| struct xcoff_link_hash_entry *h; |
| |
| if (!bfd_generic_define_common_symbol (output_bfd, info, harg)) |
| return false; |
| |
| h = (struct xcoff_link_hash_entry *) harg; |
| h->flags |= XCOFF_DEF_REGULAR; |
| return true; |
| } |
| |
| /* If symbol H has not been interpreted as a function descriptor, |
| see whether it should be. Set up its descriptor information if so. */ |
| |
| static bool |
| xcoff_find_function (struct bfd_link_info *info, |
| struct xcoff_link_hash_entry *h) |
| { |
| if ((h->flags & XCOFF_DESCRIPTOR) == 0 |
| && h->root.root.string[0] != '.') |
| { |
| char *fnname; |
| struct xcoff_link_hash_entry *hfn; |
| size_t amt; |
| |
| amt = strlen (h->root.root.string) + 2; |
| fnname = bfd_malloc (amt); |
| if (fnname == NULL) |
| return false; |
| fnname[0] = '.'; |
| strcpy (fnname + 1, h->root.root.string); |
| hfn = xcoff_link_hash_lookup (xcoff_hash_table (info), |
| fnname, false, false, true); |
| free (fnname); |
| if (hfn != NULL |
| && hfn->smclas == XMC_PR |
| && (hfn->root.type == bfd_link_hash_defined |
| || hfn->root.type == bfd_link_hash_defweak)) |
| { |
| h->flags |= XCOFF_DESCRIPTOR; |
| h->descriptor = hfn; |
| hfn->descriptor = h; |
| } |
| } |
| return true; |
| } |
| |
| /* Return true if the given bfd contains at least one shared object. */ |
| |
| static bool |
| xcoff_archive_contains_shared_object_p (struct bfd_link_info *info, |
| bfd *archive) |
| { |
| struct xcoff_archive_info *archive_info; |
| bfd *member; |
| |
| archive_info = xcoff_get_archive_info (info, archive); |
| if (!archive_info->know_contains_shared_object_p) |
| { |
| member = bfd_openr_next_archived_file (archive, NULL); |
| while (member != NULL && (member->flags & DYNAMIC) == 0) |
| member = bfd_openr_next_archived_file (archive, member); |
| |
| archive_info->contains_shared_object_p = (member != NULL); |
| archive_info->know_contains_shared_object_p = 1; |
| } |
| return archive_info->contains_shared_object_p; |
| } |
| |
| /* Symbol H qualifies for export by -bexpfull. Return true if it also |
| qualifies for export by -bexpall. */ |
| |
| static bool |
| xcoff_covered_by_expall_p (struct xcoff_link_hash_entry *h) |
| { |
| /* Exclude symbols beginning with '_'. */ |
| if (h->root.root.string[0] == '_') |
| return false; |
| |
| /* Exclude archive members that would otherwise be unreferenced. */ |
| if ((h->flags & XCOFF_MARK) == 0 |
| && (h->root.type == bfd_link_hash_defined |
| || h->root.type == bfd_link_hash_defweak) |
| && h->root.u.def.section->owner != NULL |
| && h->root.u.def.section->owner->my_archive != NULL) |
| return false; |
| |
| return true; |
| } |
| |
| /* Return true if symbol H qualifies for the forms of automatic export |
| specified by AUTO_EXPORT_FLAGS. */ |
| |
| static bool |
| xcoff_auto_export_p (struct bfd_link_info *info, |
| struct xcoff_link_hash_entry *h, |
| unsigned int auto_export_flags) |
| { |
| /* Don't automatically export things that were explicitly exported. */ |
| if ((h->flags & XCOFF_EXPORT) != 0) |
| return false; |
| |
| /* Don't export things that we don't define. */ |
| if ((h->flags & XCOFF_DEF_REGULAR) == 0) |
| return false; |
| |
| /* Don't export functions; export their descriptors instead. */ |
| if (h->root.root.string[0] == '.') |
| return false; |
| |
| /* Don't export hidden or internal symbols. */ |
| if (h->visibility == SYM_V_HIDDEN |
| || h->visibility == SYM_V_INTERNAL) |
| return false; |
| |
| /* We don't export a symbol which is being defined by an object |
| included from an archive which contains a shared object. The |
| rationale is that if an archive contains both an unshared and |
| a shared object, then there must be some reason that the |
| unshared object is unshared, and we don't want to start |
| providing a shared version of it. In particular, this solves |
| a bug involving the _savefNN set of functions. gcc will call |
| those functions without providing a slot to restore the TOC, |
| so it is essential that these functions be linked in directly |
| and not from a shared object, which means that a shared |
| object which also happens to link them in must not export |
| them. This is confusing, but I haven't been able to think of |
| a different approach. Note that the symbols can, of course, |
| be exported explicitly. */ |
| if (h->root.type == bfd_link_hash_defined |
| || h->root.type == bfd_link_hash_defweak) |
| { |
| bfd *owner; |
| |
| owner = h->root.u.def.section->owner; |
| if (owner != NULL |
| && owner->my_archive != NULL |
| && xcoff_archive_contains_shared_object_p (info, owner->my_archive)) |
| return false; |
| } |
| |
| /* Otherwise, all symbols are exported by -bexpfull. */ |
| if ((auto_export_flags & XCOFF_EXPFULL) != 0) |
| return true; |
| |
| /* Despite its name, -bexpall exports most but not all symbols. */ |
| if ((auto_export_flags & XCOFF_EXPALL) != 0 |
| && xcoff_covered_by_expall_p (h)) |
| return true; |
| |
| return false; |
| } |
| |
| /* Return true if relocation REL needs to be copied to the .loader section. |
| If REL is against a global symbol, H is that symbol, otherwise it |
| is null. */ |
| |
| static bool |
| xcoff_need_ldrel_p (struct bfd_link_info *info, struct internal_reloc *rel, |
| struct xcoff_link_hash_entry *h, asection *ssec) |
| { |
| if (!xcoff_hash_table (info)->loader_section) |
| return false; |
| |
| switch (rel->r_type) |
| { |
| case R_TOC: |
| case R_GL: |
| case R_TCL: |
| case R_TRL: |
| case R_TRLA: |
| /* We should never need a .loader reloc for a TOC-relative reloc. */ |
| return false; |
| |
| default: |
| /* In this case, relocations against defined symbols can be resolved |
| statically. */ |
| if (h == NULL |
| || h->root.type == bfd_link_hash_defined |
| || h->root.type == bfd_link_hash_defweak |
| || h->root.type == bfd_link_hash_common) |
| return false; |
| |
| /* We will always provide a local definition of function symbols, |
| even if we don't have one yet. */ |
| if ((h->flags & XCOFF_CALLED) != 0) |
| return false; |
| |
| return true; |
| |
| case R_POS: |
| case R_NEG: |
| case R_RL: |
| case R_RLA: |
| /* Absolute relocations against absolute symbols can be |
| resolved statically. */ |
| if (h != NULL |
| && (h->root.type == bfd_link_hash_defined |
| || h->root.type == bfd_link_hash_defweak) |
| && !h->root.rel_from_abs) |
| { |
| asection *sec = h->root.u.def.section; |
| if (bfd_is_abs_section (sec) |
| || (sec != NULL |
| && bfd_is_abs_section (sec->output_section))) |
| return false; |
| } |
| |
| /* Absolute relocations from read-only sections are forbidden |
| by AIX loader. However, they can appear in their section's |
| relocations. */ |
| if (ssec != NULL |
| && (ssec->output_section->flags & SEC_READONLY) != 0) |
| return false; |
| |
| return true; |
| |
| case R_TLS: |
| case R_TLS_LE: |
| case R_TLS_IE: |
| case R_TLS_LD: |
| case R_TLSM: |
| case R_TLSML: |
| return true; |
| } |
| } |
| |
| /* Mark a symbol as not being garbage, including the section in which |
| it is defined. */ |
| |
| static inline bool |
| xcoff_mark_symbol (struct bfd_link_info *info, struct xcoff_link_hash_entry *h) |
| { |
| if ((h->flags & XCOFF_MARK) != 0) |
| return true; |
| |
| h->flags |= XCOFF_MARK; |
| |
| /* If we're marking an undefined symbol, try find some way of |
| defining it. */ |
| if (!bfd_link_relocatable (info) |
| && (h->flags & XCOFF_IMPORT) == 0 |
| && (h->flags & XCOFF_DEF_REGULAR) == 0 |
| && (h->root.type == bfd_link_hash_undefined |
| || h->root.type == bfd_link_hash_undefweak)) |
| { |
| /* First check whether this symbol can be interpreted as an |
| undefined function descriptor for a defined function symbol. */ |
| if (!xcoff_find_function (info, h)) |
| return false; |
| |
| if ((h->flags & XCOFF_DESCRIPTOR) != 0 |
| && (h->descriptor->root.type == bfd_link_hash_defined |
| || h->descriptor->root.type == bfd_link_hash_defweak)) |
| { |
| /* This is a descriptor for a defined symbol, but the input |
| objects have not defined the descriptor itself. Fill in |
| the definition automatically. |
| |
| Note that we do this even if we found a dynamic definition |
| of H. The local function definition logically overrides |
| the dynamic one. */ |
| asection *sec; |
| |
| sec = xcoff_hash_table (info)->descriptor_section; |
| h->root.type = bfd_link_hash_defined; |
| h->root.u.def.section = sec; |
| h->root.u.def.value = sec->size; |
| h->smclas = XMC_DS; |
| h->flags |= XCOFF_DEF_REGULAR; |
| |
| /* The size of the function descriptor depends on whether this |
| is xcoff32 (12) or xcoff64 (24). */ |
| sec->size += bfd_xcoff_function_descriptor_size (sec->owner); |
| |
| /* A function descriptor uses two relocs: one for the |
| associated code, and one for the TOC address. */ |
| xcoff_hash_table (info)->ldinfo.ldrel_count += 2; |
| sec->reloc_count += 2; |
| |
| /* Mark the function itself. */ |
| if (!xcoff_mark_symbol (info, h->descriptor)) |
| return false; |
| |
| /* Mark the TOC section, so that we get an anchor |
| to relocate against. */ |
| if (!xcoff_mark (info, xcoff_hash_table (info)->toc_section)) |
| return false; |
| |
| /* We handle writing out the contents of the descriptor in |
| xcoff_write_global_symbol. */ |
| } |
| else if (info->static_link) |
| /* We can't get a symbol value dynamically, so just assume |
| that it's undefined. */ |
| h->flags |= XCOFF_WAS_UNDEFINED; |
| else if ((h->flags & XCOFF_CALLED) != 0) |
| { |
| /* This is a function symbol for which we need to create |
| linkage code. */ |
| asection *sec; |
| struct xcoff_link_hash_entry *hds; |
| |
| /* Mark the descriptor (and its TOC section). */ |
| hds = h->descriptor; |
| BFD_ASSERT ((hds->root.type == bfd_link_hash_undefined |
| || hds->root.type == bfd_link_hash_undefweak) |
| && (hds->flags & XCOFF_DEF_REGULAR) == 0); |
| if (!xcoff_mark_symbol (info, hds)) |
| return false; |
| |
| /* Treat this symbol as undefined if the descriptor was. */ |
| if ((hds->flags & XCOFF_WAS_UNDEFINED) != 0) |
| h->flags |= XCOFF_WAS_UNDEFINED; |
| |
| /* Allocate room for the global linkage code itself. */ |
| sec = xcoff_hash_table (info)->linkage_section; |
| h->root.type = bfd_link_hash_defined; |
| h->root.u.def.section = sec; |
| h->root.u.def.value = sec->size; |
| h->smclas = XMC_GL; |
| h->flags |= XCOFF_DEF_REGULAR; |
| sec->size += bfd_xcoff_glink_code_size (info->output_bfd); |
| |
| /* The global linkage code requires a TOC entry for the |
| descriptor. */ |
| if (hds->toc_section == NULL) |
| { |
| int byte_size; |
| |
| /* 32 vs 64 |
| xcoff32 uses 4 bytes in the toc. |
| xcoff64 uses 8 bytes in the toc. */ |
| if (bfd_xcoff_is_xcoff64 (info->output_bfd)) |
| byte_size = 8; |
| else if (bfd_xcoff_is_xcoff32 (info->output_bfd)) |
| byte_size = 4; |
| else |
| return false; |
| |
| /* Allocate room in the fallback TOC section. */ |
| hds->toc_section = xcoff_hash_table (info)->toc_section; |
| hds->u.toc_offset = hds->toc_section->size; |
| hds->toc_section->size += byte_size; |
| if (!xcoff_mark (info, hds->toc_section)) |
| return false; |
| |
| /* Allocate room for a static and dynamic R_TOC |
| relocation. */ |
| ++xcoff_hash_table (info)->ldinfo.ldrel_count; |
| ++hds->toc_section->reloc_count; |
| |
| /* Set the index to -2 to force this symbol to |
| get written out. */ |
| hds->indx = -2; |
| hds->flags |= XCOFF_SET_TOC | XCOFF_LDREL; |
| } |
| } |
| else if ((h->flags & XCOFF_DEF_DYNAMIC) == 0) |
| { |
| /* Record that the symbol was undefined, then import it. |
| -brtl links use a special fake import file. */ |
| h->flags |= XCOFF_WAS_UNDEFINED | XCOFF_IMPORT; |
| if (xcoff_hash_table (info)->rtld) |
| { |
| if (!xcoff_set_import_path (info, h, "", "..", "")) |
| return false; |
| } |
| else |
| { |
| if (!xcoff_set_import_path (info, h, NULL, NULL, NULL)) |
| return false; |
| } |
| } |
| } |
| |
| if (h->root.type == bfd_link_hash_defined |
| || h->root.type == bfd_link_hash_defweak) |
| { |
| asection *hsec; |
| |
| hsec = h->root.u.def.section; |
| if (! bfd_is_abs_section (hsec) |
| && hsec->gc_mark == 0) |
| { |
| if (! xcoff_mark (info, hsec)) |
| return false; |
| } |
| } |
| |
| if (h->toc_section != NULL |
| && h->toc_section->gc_mark == 0) |
| { |
| if (! xcoff_mark (info, h->toc_section)) |
| return false; |
| } |
| |
| return true; |
| } |
| |
| /* Look for a symbol called NAME. If the symbol is defined, mark it. |
| If the symbol exists, set FLAGS. */ |
| |
| static bool |
| xcoff_mark_symbol_by_name (struct bfd_link_info *info, |
| const char *name, unsigned int flags) |
| { |
| struct xcoff_link_hash_entry *h; |
| |
| h = xcoff_link_hash_lookup (xcoff_hash_table (info), name, |
| false, false, true); |
| if (h != NULL) |
| { |
| h->flags |= flags; |
| if (h->root.type == bfd_link_hash_defined |
| || h->root.type == bfd_link_hash_defweak) |
| { |
| if (!xcoff_mark (info, h->root.u.def.section)) |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| /* The mark phase of garbage collection. For a given section, mark |
| it, and all the sections which define symbols to which it refers. |
| Because this function needs to look at the relocs, we also count |
| the number of relocs which need to be copied into the .loader |
| section. */ |
| |
| static bool |
| xcoff_mark (struct bfd_link_info *info, asection *sec) |
| { |
| if (bfd_is_const_section (sec) |
| || sec->gc_mark != 0) |
| return true; |
| |
| sec->gc_mark = 1; |
| |
| if (sec->owner->xvec != info->output_bfd->xvec) |
| return true; |
| |
| if (coff_section_data (sec->owner, sec) == NULL) |
| return true; |
| |
| |
| if (xcoff_section_data (sec->owner, sec) != NULL) |
| { |
| struct xcoff_link_hash_entry **syms; |
| asection **csects; |
| unsigned long i, first, last; |
| |
| /* Mark all the symbols in this section. */ |
| syms = obj_xcoff_sym_hashes (sec->owner); |
| csects = xcoff_data (sec->owner)->csects; |
| first = xcoff_section_data (sec->owner, sec)->first_symndx; |
| last = xcoff_section_data (sec->owner, sec)->last_symndx; |
| for (i = first; i <= last; i++) |
| if (csects[i] == sec |
| && syms[i] != NULL |
| && (syms[i]->flags & XCOFF_MARK) == 0) |
| { |
| if (!xcoff_mark_symbol (info, syms[i])) |
| return false; |
| } |
| } |
| |
| /* Look through the section relocs. */ |
| if ((sec->flags & SEC_RELOC) != 0 |
| && sec->reloc_count > 0) |
| { |
| struct internal_reloc *rel, *relend; |
| |
| rel = xcoff_read_internal_relocs (sec->owner, sec, true, |
| NULL, false, NULL); |
| if (rel == NULL) |
| return false; |
| relend = rel + sec->reloc_count; |
| for (; rel < relend; rel++) |
| { |
| struct xcoff_link_hash_entry *h; |
| |
| if ((unsigned int) rel->r_symndx |
| > obj_raw_syment_count (sec->owner)) |
| continue; |
| |
| h = obj_xcoff_sym_hashes (sec->owner)[rel->r_symndx]; |
| if (h != NULL) |
| { |
| if ((h->flags & XCOFF_MARK) == 0) |
| { |
| if (!xcoff_mark_symbol (info, h)) |
| return false; |
| } |
| } |
| else |
| { |
| asection *rsec; |
| |
| rsec = xcoff_data (sec->owner)->csects[rel->r_symndx]; |
| if (rsec != NULL |
| && rsec->gc_mark == 0) |
| { |
| if (!xcoff_mark (info
|