From 867d923d18ef7eed7d016fdc04e8cf494d3c5db4 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Thu, 26 Oct 1995 18:25:13 +0000 Subject: [PATCH] * xcofflink.c: Numerous changes to get closer to a working XCOFF linker. * libcoff-in.h (struct xcoff_tdata): Add full_aouthdr, toc_section, and entry_section fields. (struct xcoff_section_tdata): Remove ldrel_count field. * libcoff.h: Rebuild. * coffcode.h (coff_mkobject_hook): Initialize new xcoff_data fields. (coff_compute_section_file_positions): If RS6000COFF_C, generate full a.out header if full_aouthdr is set in xcoff_data. (coff_write_object_contents): Likewise. Set o_snentry and o_sntoc based on sections stored in xcoff_data. * coff-rs6000.c (xcoff_copy_private_bfd_data): Copy new xcoff_data fields. * coffgen.c (coff_get_symbol_info): If fix_value is set, fix the value stored in ret rather than returning a pointer value. --- bfd/ChangeLog | 19 +++ bfd/coff-rs6000.c | 9 ++ bfd/coffcode.h | 66 +++++--- bfd/coffgen.c | 152 +++++++++++++++++- bfd/libcoff-in.h | 11 +- bfd/libcoff.h | 11 +- bfd/xcofflink.c | 381 +++++++++++++++++++++++++++------------------- 7 files changed, 466 insertions(+), 183 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index f3cfd6d81e7..963176aef03 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,22 @@ +Thu Oct 26 14:16:47 1995 Ian Lance Taylor + + * xcofflink.c: Numerous changes to get closer to a working XCOFF + linker. + * libcoff-in.h (struct xcoff_tdata): Add full_aouthdr, + toc_section, and entry_section fields. + (struct xcoff_section_tdata): Remove ldrel_count field. + * libcoff.h: Rebuild. + * coffcode.h (coff_mkobject_hook): Initialize new xcoff_data + fields. + (coff_compute_section_file_positions): If RS6000COFF_C, generate + full a.out header if full_aouthdr is set in xcoff_data. + (coff_write_object_contents): Likewise. Set o_snentry and o_sntoc + based on sections stored in xcoff_data. + * coff-rs6000.c (xcoff_copy_private_bfd_data): Copy new xcoff_data + fields. + * coffgen.c (coff_get_symbol_info): If fix_value is set, fix the + value stored in ret rather than returning a pointer value. + Wed Oct 25 23:10:39 1995 Michael Meissner * config.bfd (powerpc{,le}-{elf,sysv4,eabi,solaris2}): Remove MAC diff --git a/bfd/coff-rs6000.c b/bfd/coff-rs6000.c index 10d5450bf02..f837a08414a 100644 --- a/bfd/coff-rs6000.c +++ b/bfd/coff-rs6000.c @@ -102,7 +102,16 @@ xcoff_copy_private_bfd_data (ibfd, obfd) return true; ix = xcoff_data (ibfd); ox = xcoff_data (obfd); + ox->full_aouthdr = ix->full_aouthdr; ox->toc = ix->toc; + if (ix->toc_section == NULL) + ox->toc_section = NULL; + else + ox->toc_section = ix->toc_section->output_section; + if (ix->entry_section == NULL) + ox->entry_section = NULL; + else + ox->entry_section = ix->entry_section->output_section; ox->text_align_power = ix->text_align_power; ox->data_align_power = ix->data_align_power; ox->modtype = ix->modtype; diff --git a/bfd/coffcode.h b/bfd/coffcode.h index e3eeb13c068..ff1406aa428 100644 --- a/bfd/coffcode.h +++ b/bfd/coffcode.h @@ -1002,7 +1002,18 @@ coff_mkobject_hook (abfd, filehdr, aouthdr) struct xcoff_tdata *xcoff; xcoff = xcoff_data (abfd); + xcoff->full_aouthdr = true; xcoff->toc = internal_a->o_toc; + if (internal_a->o_sntoc == 0) + xcoff->toc_section = NULL; + else + xcoff->toc_section = + coff_section_from_bfd_index (abfd, internal_a->o_sntoc); + if (internal_a->o_snentry == 0) + xcoff->entry_section = NULL; + else + xcoff->entry_section = + coff_section_from_bfd_index (abfd, internal_a->o_snentry); xcoff->text_align_power = internal_a->o_algntext; xcoff->data_align_power = internal_a->o_algndata; xcoff->modtype = internal_a->o_modtype; @@ -1764,6 +1775,8 @@ coff_compute_section_file_positions (abfd) if (abfd->flags & EXEC_P) sofar += AOUTSZ; #ifdef RS6000COFF_C + else if (xcoff_data (abfd)->full_aouthdr) + sofar += AOUTSZ; else sofar += SMALL_AOUTSZ; #endif @@ -2003,7 +2016,10 @@ coff_write_object_contents (abfd) { scn_base = FILHSZ; #ifdef RS6000COFF_C - scn_base += SMALL_AOUTSZ; + if (xcoff_data (abfd)->full_aouthdr) + scn_base += AOUTSZ; + else + scn_base += SMALL_AOUTSZ; #endif } @@ -2135,8 +2151,10 @@ coff_write_object_contents (abfd) { internal_f.f_opthdr = 0; #ifdef RS6000COFF_C - /* XCOFF seems to always write at least a small a.out header. */ - internal_f.f_opthdr = SMALL_AOUTSZ; + if (xcoff_data (abfd)->full_aouthdr) + internal_f.f_opthdr = AOUTSZ; + else + internal_f.f_opthdr = SMALL_AOUTSZ; #endif } @@ -2311,22 +2329,20 @@ coff_write_object_contents (abfd) internal_f.f_nsyms = obj_raw_syment_count (abfd); #ifdef RS6000COFF_C - if ((abfd->flags & EXEC_P) != 0) + if (xcoff_data (abfd)->full_aouthdr) { - bfd_vma entry, toc; + bfd_vma toc; asection *loader_sec; - entry = bfd_get_start_address (abfd); - if (text_sec != NULL - && entry >= text_sec->vma - && entry < text_sec->vma + bfd_section_size (abfd, text_sec)) - internal_a.o_snentry = text_sec->target_index; - else if (data_sec != NULL - && entry >= data_sec->vma - && entry < data_sec->vma + bfd_section_size (abfd, data_sec)) - internal_a.o_snentry = data_sec->target_index; + if (xcoff_data (abfd)->entry_section != NULL) + internal_a.o_snentry = xcoff_data (abfd)->entry_section->target_index; else - internal_a.o_snentry = 0; + { + internal_a.o_snentry = 0; + if (internal_a.entry == 0) + internal_a.entry = (bfd_vma) -1; + } + if (text_sec != NULL) { internal_a.o_sntext = text_sec->target_index; @@ -2359,16 +2375,10 @@ coff_write_object_contents (abfd) toc = xcoff_data (abfd)->toc; internal_a.o_toc = toc; - if (text_sec != NULL - && toc >= text_sec->vma - && toc < text_sec->vma + bfd_section_size (abfd, text_sec)) - internal_a.o_sntoc = text_sec->target_index; - else if (data_sec != NULL - && toc >= data_sec->vma - && toc < data_sec->vma + bfd_section_size (abfd, data_sec)) - internal_a.o_sntoc = data_sec->target_index; - else + if (xcoff_data (abfd)->toc_section == NULL) internal_a.o_sntoc = 0; + else + internal_a.o_sntoc = xcoff_data (abfd)->toc_section->target_index; internal_a.o_modtype = xcoff_data (abfd)->modtype; if (xcoff_data (abfd)->cputype != -1) @@ -2415,9 +2425,15 @@ coff_write_object_contents (abfd) else { AOUTHDR buff; + size_t size; + /* XCOFF seems to always write at least a small a.out header. */ coff_swap_aouthdr_out (abfd, (PTR) &internal_a, (PTR) &buff); - if (bfd_write ((PTR) &buff, 1, SMALL_AOUTSZ, abfd) != SMALL_AOUTSZ) + if (xcoff_data (abfd)->full_aouthdr) + size = AOUTSZ; + else + size = SMALL_AOUTSZ; + if (bfd_write ((PTR) &buff, 1, size, abfd) != size) return false; } #endif diff --git a/bfd/coffgen.c b/bfd/coffgen.c index a65776de918..9ccd2b7e804 100644 --- a/bfd/coffgen.c +++ b/bfd/coffgen.c @@ -329,6 +329,147 @@ coff_get_symtab (abfd, alocation) return bfd_get_symcount (abfd); } +/* Get the name of a symbol. The caller must pass in a buffer of size + >= SYMNMLEN + 1. */ + +const char * +_bfd_coff_internal_syment_name (abfd, sym, buf) + bfd *abfd; + const struct internal_syment *sym; + char *buf; +{ + /* FIXME: It's not clear this will work correctly if sizeof + (_n_zeroes) != 4. */ + if (sym->_n._n_n._n_zeroes != 0 + || sym->_n._n_n._n_offset == 0) + { + memcpy (buf, sym->_n._n_name, SYMNMLEN); + buf[SYMNMLEN] = '\0'; + return buf; + } + else + { + const char *strings; + + BFD_ASSERT (sym->_n._n_n._n_offset >= STRING_SIZE_SIZE); + strings = obj_coff_strings (abfd); + if (strings == NULL) + { + strings = _bfd_coff_read_string_table (abfd); + if (strings == NULL) + return NULL; + } + return strings + sym->_n._n_n._n_offset; + } +} + +/* Read in and swap the relocs. This returns a buffer holding the + relocs for section SEC in file ABFD. If CACHE is true and + INTERNAL_RELOCS is NULL, the relocs read in will be saved in case + the function is called again. If EXTERNAL_RELOCS is not NULL, it + is a buffer large enough to hold the unswapped relocs. If + INTERNAL_RELOCS is not NULL, it is a buffer large enough to hold + the swapped relocs. If REQUIRE_INTERNAL is true, then the return + value must be INTERNAL_RELOCS. The function returns NULL on error. */ + +struct internal_reloc * +_bfd_coff_read_internal_relocs (abfd, sec, cache, external_relocs, + require_internal, internal_relocs) + bfd *abfd; + asection *sec; + boolean cache; + bfd_byte *external_relocs; + boolean require_internal; + struct internal_reloc *internal_relocs; +{ + bfd_size_type relsz; + bfd_byte *free_external = NULL; + struct internal_reloc *free_internal = NULL; + bfd_byte *erel; + bfd_byte *erel_end; + struct internal_reloc *irel; + + if (coff_section_data (abfd, sec) != NULL + && coff_section_data (abfd, sec)->relocs != NULL) + { + if (! require_internal) + return coff_section_data (abfd, sec)->relocs; + memcpy (internal_relocs, coff_section_data (abfd, sec)->relocs, + sec->reloc_count * sizeof (struct internal_reloc)); + return internal_relocs; + } + + relsz = bfd_coff_relsz (abfd); + + if (external_relocs == NULL) + { + free_external = (bfd_byte *) malloc (sec->reloc_count * relsz); + if (free_external == NULL && sec->reloc_count > 0) + { + bfd_set_error (bfd_error_no_memory); + goto error_return; + } + external_relocs = free_external; + } + + if (bfd_seek (abfd, sec->rel_filepos, SEEK_SET) != 0 + || (bfd_read (external_relocs, relsz, sec->reloc_count, abfd) + != relsz * sec->reloc_count)) + goto error_return; + + if (internal_relocs == NULL) + { + free_internal = ((struct internal_reloc *) + malloc (sec->reloc_count + * sizeof (struct internal_reloc))); + if (free_internal == NULL && sec->reloc_count > 0) + { + bfd_set_error (bfd_error_no_memory); + goto error_return; + } + internal_relocs = free_internal; + } + + /* Swap in the relocs. */ + erel = external_relocs; + erel_end = erel + relsz * sec->reloc_count; + irel = internal_relocs; + for (; erel < erel_end; erel += relsz, irel++) + bfd_coff_swap_reloc_in (abfd, (PTR) erel, (PTR) irel); + + if (free_external != NULL) + { + free (free_external); + free_external = NULL; + } + + if (cache && free_internal != NULL) + { + if (coff_section_data (abfd, sec) == NULL) + { + sec->used_by_bfd = + (PTR) bfd_zalloc (abfd, + sizeof (struct coff_section_tdata)); + if (sec->used_by_bfd == NULL) + { + bfd_set_error (bfd_error_no_memory); + goto error_return; + } + coff_section_data (abfd, sec)->contents = NULL; + } + coff_section_data (abfd, sec)->relocs = free_internal; + } + + return internal_relocs; + + error_return: + if (free_external != NULL) + free (free_external); + if (free_internal != NULL) + free (free_internal); + return NULL; +} + /* Set lineno_count for the output sections of a COFF file. */ int @@ -1688,6 +1829,15 @@ coff_get_symbol_info (abfd, symbol, ret) symbol_info *ret; { bfd_symbol_info (symbol, ret); + if (coffsymbol (symbol)->native != NULL + && coffsymbol (symbol)->native->fix_value) + { + combined_entry_type *psym; + + psym = ((combined_entry_type *) + coffsymbol (symbol)->native->u.syment.n_value); + ret->value = (bfd_vma) (psym - obj_raw_syments (abfd)); + } } /* Print out information about COFF symbol. */ @@ -1974,7 +2124,7 @@ coff_find_nearest_line (abfd, section, ignore_symbols, offset, filename_ptr, section->used_by_bfd = ((PTR) bfd_zalloc (abfd, sizeof (struct coff_section_tdata))); - sec_data = section->used_by_bfd; + sec_data = (struct coff_section_tdata *) section->used_by_bfd; } if (sec_data != NULL) { diff --git a/bfd/libcoff-in.h b/bfd/libcoff-in.h index 0dd01846b01..7b818aa413b 100644 --- a/bfd/libcoff-in.h +++ b/bfd/libcoff-in.h @@ -105,9 +105,18 @@ struct xcoff_tdata /* Basic COFF information. */ coff_data_type coff; + /* True if a large a.out header should be generated. */ + boolean full_aouthdr; + /* TOC value. */ bfd_vma toc; + /* Section holding TOC. */ + asection *toc_section; + + /* Section holding entry point. */ + asection *entry_section; + /* .text alignment from optional header. */ int text_align_power; @@ -178,8 +187,6 @@ struct xcoff_section_tdata by this csect. */ unsigned long first_symndx; unsigned long last_symndx; - /* The number of .loader relocs in this csect. */ - size_t ldrel_count; }; /* An accessor macro the xcoff_section_tdata structure. */ diff --git a/bfd/libcoff.h b/bfd/libcoff.h index ebdcdfbb0d8..f75c42b92a4 100644 --- a/bfd/libcoff.h +++ b/bfd/libcoff.h @@ -105,9 +105,18 @@ struct xcoff_tdata /* Basic COFF information. */ coff_data_type coff; + /* True if a large a.out header should be generated. */ + boolean full_aouthdr; + /* TOC value. */ bfd_vma toc; + /* Section holding TOC. */ + asection *toc_section; + + /* Section holding entry point. */ + asection *entry_section; + /* .text alignment from optional header. */ int text_align_power; @@ -178,8 +187,6 @@ struct xcoff_section_tdata by this csect. */ unsigned long first_symndx; unsigned long last_symndx; - /* The number of .loader relocs in this csect. */ - size_t ldrel_count; }; /* An accessor macro the xcoff_section_tdata structure. */ diff --git a/bfd/xcofflink.c b/bfd/xcofflink.c index 60396207df4..0e272f5d24e 100644 --- a/bfd/xcofflink.c +++ b/bfd/xcofflink.c @@ -25,10 +25,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "coff/internal.h" #include "libcoff.h" -/* This file holds the XCOFF linker code. A lot of it is very similar - to the COFF linker code. However, it is different enough that I - chose to avoid trying to hack up the COFF code to support XCOFF. - That leads to a certain amount of duplicated code, alas. */ +/* This file holds the XCOFF linker code. */ #define STRING_SIZE_SIZE (4) @@ -1216,34 +1213,47 @@ xcoff_link_add_symbols (abfd, info) relbuf); if (relname == NULL) goto error_return; - 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) + /* 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) { - /* We already have a TOC entry for this - symbol, so we can just ignore this one. */ - *rel_csect = bfd_und_section_ptr; - break; - } + 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) + { + /* We already have a TOC entry for this + symbol, so we can just ignore this + one. */ + *rel_csect = bfd_und_section_ptr; + break; + } - /* We are about to create a TOC entry for this - symbol. */ - set_toc = h; + /* We are about to create a TOC entry for + this symbol. */ + set_toc = h; + } } } } @@ -1431,7 +1441,7 @@ xcoff_link_add_symbols (abfd, info) csect = bfd_make_section_anyway (abfd, ".bss"); if (csect == NULL) goto error_return; - csect->vma = 0; + csect->vma = sym.n_value; csect->_raw_size = aux.x_csect.x_scnlen.l; csect->flags |= SEC_ALLOC; csect->alignment_power = SMTYP_ALIGN (aux.x_csect.x_smtyp); @@ -1524,6 +1534,21 @@ xcoff_link_add_symbols (abfd, info) (struct bfd_link_hash_entry **) sym_hash))) 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->_raw_size = 0; + } + else + { + (*sym_hash)->root.u.c.p->alignment_power + = csect->alignment_power; + } + } + if (info->hash->creator == abfd->xvec) { int flag; @@ -1574,75 +1599,49 @@ xcoff_link_add_symbols (abfd, info) goto error_return; } - /* We need to copy all relocs which are not PC relative - and not TOC relative into the .loader section. - - We also identify all symbols which are called, so - that we can create glue code for calls to functions - imported from dynamic objects. */ - + /* We identify all symbols which are called, so that we + can create glue code for calls to functions imported + from dynamic objects. */ if (info->hash->creator == abfd->xvec - && *rel_csect != bfd_und_section_ptr) + && *rel_csect != bfd_und_section_ptr + && (rel->r_type == R_BR + || rel->r_type == R_RBR) + && obj_xcoff_sym_hashes (abfd)[rel->r_symndx] != NULL) { struct xcoff_link_hash_entry *h; - switch (rel->r_type) + h = obj_xcoff_sym_hashes (abfd)[rel->r_symndx]; + h->flags |= XCOFF_CALLED; + /* 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) { - default: - break; - case R_POS: - case R_NEG: - case R_RL: - case R_RLA: - ++xcoff_hash_table (info)->ldrel_count; - ++xcoff_section_data (abfd, *rel_csect)->ldrel_count; - h = obj_xcoff_sym_hashes (abfd)[rel->r_symndx]; - if (h != NULL) - h->flags |= XCOFF_LDREL; - break; - case R_BR: - case R_RBR: - h = obj_xcoff_sym_hashes (abfd)[rel->r_symndx]; - if (h != NULL) + struct xcoff_link_hash_entry *hds; + + 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) { - h->flags |= XCOFF_CALLED; - /* 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; - - 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) - { - if (! (_bfd_generic_link_add_one_symbol - (info, abfd, hds->root.root.string, - (flagword) 0, bfd_und_section_ptr, - (bfd_vma) 0, (const char *) NULL, - false, false, - ((struct bfd_link_hash_entry **) - NULL)))) - goto error_return; - } - h->descriptor = hds; - } + if (! (_bfd_generic_link_add_one_symbol + (info, abfd, hds->root.root.string, + (flagword) 0, bfd_und_section_ptr, + (bfd_vma) 0, (const char *) NULL, false, + false, + (struct bfd_link_hash_entry **) NULL))) + goto error_return; } - break; + h->descriptor = hds; } } } @@ -1773,10 +1772,12 @@ xcoff_link_add_dynamic_symbols (abfd, info) /* If the symbol is undefined, and the current BFD is not a dynamic object, change the BFD to this dynamic - object, so that we can get the import file ID - correctly. */ - if (h->root.u.undef.abfd == NULL - || (h->root.u.undef.abfd->flags & DYNAMIC) == 0) + object, so that we can get the correct import file + ID. */ + if ((h->root.type == bfd_link_hash_undefined + || h->root.type == bfd_link_hash_undefweak) + && (h->root.u.undef.abfd == NULL + || (h->root.u.undef.abfd->flags & DYNAMIC) == 0)) h->root.u.undef.abfd = abfd; if (h->smclas == XMC_UA @@ -2024,7 +2025,13 @@ bfd_xcoff_size_dynamic_sections (output_bfd, info, libpath, entry, hentry = xcoff_link_hash_lookup (xcoff_hash_table (info), entry, false, false, true); if (hentry != NULL) - hentry->flags |= XCOFF_ENTRY; + { + hentry->flags |= XCOFF_ENTRY; + if (hentry->root.type == bfd_link_hash_defined + || hentry->root.type == bfd_link_hash_defweak) + xcoff_data (output_bfd)->entry_section = + hentry->root.u.def.section->output_section; + } /* Garbage collect unused sections. */ if (info->relocateable @@ -2035,6 +2042,22 @@ bfd_xcoff_size_dynamic_sections (output_bfd, info, libpath, entry, { gc = false; xcoff_hash_table (info)->gc = false; + + /* We still need to call xcoff_mark, in order to set ldrel_count + correctly. */ + for (sub = info->input_bfds; sub != NULL; sub = sub->link_next) + { + asection *o; + + for (o = sub->sections; o != NULL; o = o->next) + { + if ((o->flags & SEC_MARK) == 0) + { + if (! xcoff_mark (info, o)) + goto error_return; + } + } + } } else { @@ -2284,7 +2307,10 @@ bfd_xcoff_size_dynamic_sections (output_bfd, info, libpath, entry, } /* The mark phase of garbage collection. For a given section, mark - it, and all the sections which define symbols to which it refers. */ + 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 boolean xcoff_mark (info, sec) @@ -2393,6 +2419,35 @@ xcoff_mark (info, sec) if (! xcoff_mark (info, rsec)) return false; } + + /* See if this reloc needs to be copied into the .loader + section. */ + switch (rel->r_type) + { + default: + if (h == NULL + || h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak + || h->root.type == bfd_link_hash_common) + break; + /* Fall through. */ + case R_POS: + case R_NEG: + case R_RL: + case R_RLA: + ++xcoff_hash_table (info)->ldrel_count; + if (h != NULL) + h->flags |= XCOFF_LDREL; + break; + 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. */ + break; + } } if (! info->keep_memory @@ -2441,10 +2496,6 @@ xcoff_sweep (info) o->_raw_size = 0; o->reloc_count = 0; o->lineno_count = 0; - if (coff_section_data (sub, o) != NULL - && xcoff_section_data (sub, o) != NULL) - xcoff_hash_table (info)->ldrel_count -= - xcoff_section_data (sub, o)->ldrel_count; } } } @@ -2520,11 +2571,12 @@ xcoff_build_ldsyms (h, p) /* We need to add a symbol to the .loader section if it is mentioned in a reloc which we are copying to the .loader section and it was - not defined, or if it is the entry point. */ + not defined or common, or if it is the entry point. */ if (((h->flags & XCOFF_LDREL) == 0 || h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) + || h->root.type == bfd_link_hash_defweak + || h->root.type == bfd_link_hash_common) && (h->flags & XCOFF_ENTRY) == 0) { h->ldsym = NULL; @@ -2660,6 +2712,7 @@ _bfd_xcoff_bfd_final_link (abfd, info) + xcoff_hash_table (info)->ldhdr.l_nsyms * LDSYMSZ)); xcoff_data (abfd)->coff.link_info = info; + xcoff_data (abfd)->full_aouthdr = true; finfo.strtab = _bfd_stringtab_init (); if (finfo.strtab == NULL) @@ -2728,13 +2781,7 @@ _bfd_xcoff_bfd_final_link (abfd, info) code knows what compute_section_file_positions is going to do. */ sofar = bfd_coff_filhsz (abfd); - if ((abfd->flags & EXEC_P) != 0) - sofar += bfd_coff_aoutsz (abfd); - else - { - /* FIXME. */ - sofar += 28; - } + sofar += bfd_coff_aoutsz (abfd); sofar += abfd->section_count * bfd_coff_scnhsz (abfd); for (o = abfd->sections; o != NULL; o = o->next) @@ -3420,6 +3467,8 @@ xcoff_link_input_bfd (finfo, input_bfd) + (*csectpp)->output_offset + isym.n_value - (*csectpp)->vma); + xcoff_data (finfo->output_bfd)->toc_section = + (*csectpp)->output_section; require = true; } } @@ -3441,7 +3490,7 @@ xcoff_link_input_bfd (finfo, input_bfd) if (! skip && isym.n_sclass == C_EXT && smtyp == XTY_CM - && ((*sym_hash)->flags & XCOFF_DEF_REGULAR) != 0) + && (*sym_hash)->root.type != bfd_link_hash_common) skip = true; /* Skip local symbols if we are discarding them. */ @@ -3531,26 +3580,9 @@ xcoff_link_input_bfd (finfo, input_bfd) } } - if (isym.n_sclass == C_BSTAT) - { - unsigned long indx; - - /* The value of a C_BSTAT symbol is the symbol table - index of the containing csect. */ - - indx = isym.n_value; - if (indx < obj_raw_syment_count (input_bfd)) - { - long symindx; - - symindx = finfo->sym_indices[indx]; - if (symindx < 0) - isym.n_value = 0; - else - isym.n_value = symindx; - } - } - else if (isym.n_scnum > 0) + if (isym.n_sclass != C_BSTAT + && isym.n_sclass != C_ESTAT + && isym.n_scnum > 0) { isym.n_scnum = (*csectpp)->output_section->target_index; isym.n_value += ((*csectpp)->output_section->vma @@ -3635,9 +3667,10 @@ xcoff_link_input_bfd (finfo, input_bfd) *indexp++ = -1; } - /* Fix up the aux entries. This must be done in a separate pass, - because we don't know the correct symbol indices until we have - already decided which symbols we are going to keep. */ + /* Fix up the aux entries and the C_BSTAT symbols. This must be + done in a separate pass, because we don't know the correct symbol + indices until we have already decided which symbols we are going + to keep. */ esym = (bfd_byte *) obj_coff_external_syms (input_bfd); esym_end = esym + obj_raw_syment_count (input_bfd) * isymesz; @@ -3657,6 +3690,27 @@ xcoff_link_input_bfd (finfo, input_bfd) { int i; + if (isymp->n_sclass == C_BSTAT) + { + unsigned long indx; + + /* The value of a C_BSTAT symbol is the symbol table + index of the containing csect. */ + indx = isymp->n_value; + if (indx < obj_raw_syment_count (input_bfd)) + { + long symindx; + + symindx = finfo->sym_indices[indx]; + if (symindx < 0) + isymp->n_value = 0; + else + isymp->n_value = symindx; + bfd_coff_swap_sym_out (output_bfd, (PTR) isymp, + (PTR) outsym); + } + } + esym += isymesz; outsym += osymesz; @@ -4066,7 +4120,12 @@ xcoff_link_input_bfd (finfo, input_bfd) switch (irel->r_type) { default: - break; + if (h == NULL + || h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak + || h->root.type == bfd_link_hash_common) + break; + /* Fall through. */ case R_POS: case R_NEG: case R_RL: @@ -4076,30 +4135,36 @@ xcoff_link_input_bfd (finfo, input_bfd) ldrel.l_vaddr = irel->r_vaddr; if (r_symndx == -1) ldrel.l_symndx = -1; - else if (h == NULL) + else if (h == NULL + || (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak + || h->root.type == bfd_link_hash_common)) { asection *sec; - sec = xcoff_data (input_bfd)->csects[r_symndx]; - if ((sec->flags & SEC_CODE) != 0) - ldrel.l_symndx = 0; - else if ((sec->flags & SEC_HAS_CONTENTS) != 0) - ldrel.l_symndx = 1; + if (h == NULL) + sec = xcoff_data (input_bfd)->csects[r_symndx]; + else if (h->root.type == bfd_link_hash_common) + sec = h->root.u.c.p->section; else - ldrel.l_symndx = 2; - } - else if (h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) - { - asection *sec; + sec = h->root.u.def.section; + sec = sec->output_section; - sec = h->root.u.def.section->output_section; - if ((sec->flags & SEC_CODE) != 0) + if (strcmp (sec->name, ".text") == 0) ldrel.l_symndx = 0; - else if ((sec->flags & SEC_HAS_CONTENTS) != 0) + else if (strcmp (sec->name, ".data") == 0) ldrel.l_symndx = 1; - else + else if (strcmp (sec->name, ".bss") == 0) ldrel.l_symndx = 2; + else + { + (*_bfd_error_handler) + ("%s: loader reloc in unrecognized section `%s'", + bfd_get_filename (input_bfd), + sec->name); + bfd_set_error (bfd_error_nonrepresentable_section); + return false; + } } else { @@ -4117,7 +4182,7 @@ xcoff_link_input_bfd (finfo, input_bfd) ldrel.l_rtype = (irel->r_size << 8) | irel->r_type; ldrel.l_rsecnm = o->output_section->target_index; if (xcoff_hash_table (finfo->info)->textro - && (o->output_section->flags & SEC_CODE) != 0) + && strcmp (o->output_section->name, ".text") == 0) { (*_bfd_error_handler) ("%s: loader reloc in read-only section %s", @@ -4131,6 +4196,16 @@ xcoff_link_input_bfd (finfo, input_bfd) finfo->ldrel); BFD_ASSERT (sizeof (struct external_ldrel) == LDRELSZ); ++finfo->ldrel; + break; + + 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. */ + break; } } -- 2.30.2