X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=bfd%2Felfxx-mips.c;h=bede3e61293a05110410d9d1d4b51e3ded510dd7;hb=9e4aeb93074936ab70c362cacd61bf5e737b95a6;hp=2b2f615934a10296367e37320a7153ec1d4b8961;hpb=0b25d3e680e7631033d5cce5dd4d797dbc0b039c;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/elfxx-mips.c b/bfd/elfxx-mips.c index 2b2f615934..bede3e6129 100644 --- a/bfd/elfxx-mips.c +++ b/bfd/elfxx-mips.c @@ -163,8 +163,7 @@ struct mips_elf_hash_sort_data long min_got_dynindx; /* The greatest dynamic symbol table index corresponding to a symbol with a GOT entry that is not referenced (e.g., a dynamic symbol - with dynamic relocations pointing to it from non-primary - GOTs). */ + with dynamic relocations pointing to it from non-primary GOTs). */ long max_unref_got_dynindx; /* The greatest dynamic symbol table index not corresponding to a symbol without a GOT entry. */ @@ -408,6 +407,7 @@ static asection * mips_elf_rel_dyn_section PARAMS ((bfd *, bfd_boolean)); static asection * mips_elf_got_section PARAMS ((bfd *, bfd_boolean)); static struct mips_got_info *mips_elf_got_info PARAMS ((bfd *, asection **)); +static long mips_elf_get_global_gotsym_index PARAMS ((bfd *abfd)); static bfd_vma mips_elf_local_got_index PARAMS ((bfd *, bfd *, struct bfd_link_info *, bfd_vma)); static bfd_vma mips_elf_global_got_index @@ -541,7 +541,7 @@ static bfd *reldyn_sorting_bfd; /* The default alignment for sections, as a power of two. */ #define MIPS_ELF_LOG_FILE_ALIGN(abfd) \ - (get_elf_backend_data (abfd)->s->file_align == 8 ? 3 : 2) + (get_elf_backend_data (abfd)->s->log_file_align) /* Get word-sized data. */ #define MIPS_ELF_GET_WORD(abfd, ptr) \ @@ -1707,6 +1707,29 @@ mips_elf_got_info (abfd, sgotp) return g; } +/* Obtain the lowest dynamic index of a symbol that was assigned a + global GOT entry. */ +static long +mips_elf_get_global_gotsym_index (abfd) + bfd *abfd; +{ + asection *sgot; + struct mips_got_info *g; + + if (abfd == NULL) + return 0; + + sgot = mips_elf_got_section (abfd, TRUE); + if (sgot == NULL || mips_elf_section_data (sgot) == NULL) + return 0; + + g = mips_elf_section_data (sgot)->u.got_info; + if (g == NULL || g->global_gotsym == NULL) + return 0; + + return g->global_gotsym->dynindx; +} + /* Returns the GOT offset at which the indicated address can be found. If there is not yet a GOT entry for this value, create one. Returns -1 if no satisfactory GOT offset can be found. */ @@ -1746,7 +1769,7 @@ mips_elf_global_got_index (abfd, ibfd, h) if (g->bfd2got && ibfd) { struct mips_got_entry e, *p; - + BFD_ASSERT (h->dynindx >= 0); g = mips_elf_got_for_ibfd (g, ibfd); @@ -1804,7 +1827,7 @@ mips_elf_got_page (abfd, ibfd, info, value, offsetp) if (!entry) return MINUS_ONE; - + index = entry->gotidx; if (offsetp) @@ -1862,7 +1885,7 @@ mips_elf_got_offset_from_index (dynobj, output_bfd, input_bfd, index) g = mips_elf_got_info (dynobj, &sgot); gp = _bfd_get_gp_value (output_bfd) + mips_elf_adjust_gp (output_bfd, g, input_bfd); - + return sgot->output_section->vma + sgot->output_offset + index - gp; } @@ -1894,14 +1917,14 @@ mips_elf_create_local_got_entry (abfd, ibfd, gg, sgot, value) INSERT); if (*loc) return *loc; - + entry.gotidx = MIPS_ELF_GOT_SIZE (abfd) * g->assigned_gotno++; *loc = (struct mips_got_entry *)bfd_alloc (abfd, sizeof entry); if (! *loc) return NULL; - + memcpy (*loc, &entry, sizeof entry); if (g->assigned_gotno >= g->local_gotno) @@ -1941,7 +1964,7 @@ mips_elf_sort_hash_table (info, max_local) g = mips_elf_got_info (dynobj, NULL); hsd.low = NULL; - hsd.max_unref_got_dynindx = + hsd.max_unref_got_dynindx = hsd.min_got_dynindx = elf_hash_table (info)->dynsymcount /* In the multi-got case, assigned_gotno of the master got_info indicate the number of entries that aren't referenced in the @@ -2055,7 +2078,7 @@ mips_elf_record_global_got_symbol (h, abfd, info, g) if (! *loc) return FALSE; - + entry.gotidx = -1; memcpy (*loc, &entry, sizeof entry); @@ -2097,7 +2120,7 @@ mips_elf_record_local_got_symbol (abfd, symndx, addend, g) if (! *loc) return FALSE; - + memcpy (*loc, &entry, sizeof entry); return TRUE; @@ -2163,7 +2186,7 @@ mips_elf_make_got_per_bfd (entryp, p) struct mips_got_info *g; struct mips_elf_bfd2got_hash bfdgot_entry, *bfdgot; void **bfdgotp; - + /* Find the got_info for this GOT entry's input bfd. Create one if none exists. */ bfdgot_entry.bfd = entry->abfd; @@ -2215,7 +2238,7 @@ mips_elf_make_got_per_bfd (entryp, p) entryp = htab_find_slot (g->got_entries, entry, INSERT); if (*entryp != NULL) return 1; - + *entryp = entry; if (entry->symndx >= 0 || entry->d.h->forced_local) @@ -2244,7 +2267,7 @@ mips_elf_merge_gots (bfd2got_, p) unsigned int lcount = bfd2got->g->local_gotno; unsigned int gcount = bfd2got->g->global_gotno; unsigned int maxcnt = arg->max_count; - + /* If we don't have a primary GOT and this is not too big, use it as a starting point for the primary GOT. */ if (! arg->primary && lcount + gcount <= maxcnt) @@ -2312,7 +2335,7 @@ mips_elf_merge_gots (bfd2got_, p) { bfd2got->g->next = arg->current; arg->current = bfd2got->g; - + arg->current_count = lcount + gcount; } @@ -2393,7 +2416,7 @@ mips_elf_resolve_final_got_entry (entryp, p) if (entry->d.h == h) return 1; - + entry->d.h = h; /* If we can't find this entry with the new bfd hash, re-insert @@ -2413,7 +2436,7 @@ mips_elf_resolve_final_got_entry (entryp, p) /* We might want to decrement the global_gotno count, but it's either too early or too late for that at this point. */ } - + return 1; } @@ -2454,7 +2477,7 @@ mips_elf_adjust_gp (abfd, g, ibfd) BFD_ASSERT (g->next); g = g->next; - + return (g->local_gotno + g->global_gotno) * MIPS_ELF_GOT_SIZE (abfd); } @@ -2542,7 +2565,7 @@ mips_elf_multi_got (abfd, info, g, got, pages) { struct mips_elf_bfd2got_hash *bfdgot; void **bfdgotp; - + bfdgot = (struct mips_elf_bfd2got_hash *)bfd_alloc (abfd, sizeof (struct mips_elf_bfd2got_hash)); @@ -2568,7 +2591,7 @@ mips_elf_multi_got (abfd, info, g, got, pages) the cache. Also, knowing that every external symbol has a GOT helps speed up the resolution of local symbols too, so GNU/Linux follows IRIX's practice. - + The number 2 is used by mips_elf_sort_hash_table_f to count global GOT symbols that are unreferenced in the primary GOT, with an initial dynamic index computed from gg->assigned_gotno, where @@ -2641,10 +2664,10 @@ mips_elf_multi_got (abfd, info, g, got, pages) got->_raw_size = (gg->next->local_gotno + gg->next->global_gotno) * MIPS_ELF_GOT_SIZE (abfd); - + return TRUE; } - + /* Returns the first relocation of type r_type found, beginning with RELOCATION. RELEND is one-past-the-end of the relocation table. */ @@ -3196,6 +3219,18 @@ mips_elf_calculate_relocation (abfd, input_bfd, input_section, info, and we're going to need it, get it now. */ switch (r_type) { + case R_MIPS_GOT_PAGE: + case R_MIPS_GOT_OFST: + /* If this symbol got a global GOT entry, we have to decay + GOT_PAGE/GOT_OFST to GOT_DISP/addend. */ + local_p = local_p || ! h + || (h->root.dynindx + < mips_elf_get_global_gotsym_index (elf_hash_table (info) + ->dynobj)); + if (local_p || r_type == R_MIPS_GOT_OFST) + break; + /* Fall through. */ + case R_MIPS_CALL16: case R_MIPS_GOT16: case R_MIPS_GOT_DISP: @@ -3206,7 +3241,11 @@ mips_elf_calculate_relocation (abfd, input_bfd, input_section, info, /* Find the index into the GOT where this value is located. */ if (!local_p) { - BFD_ASSERT (addend == 0); + /* GOT_PAGE may take a non-zero addend, that is ignored in a + GOT_PAGE relocation that decays to GOT_DISP because the + symbol turns out to be global. The addend is then added + as GOT_OFST. */ + BFD_ASSERT (addend == 0 || r_type == R_MIPS_GOT_PAGE); g = mips_elf_global_got_index (elf_hash_table (info)->dynobj, input_bfd, (struct elf_link_hash_entry *) h); @@ -3220,7 +3259,7 @@ mips_elf_calculate_relocation (abfd, input_bfd, input_section, info, We must initialize this entry in the GOT. */ bfd *tmpbfd = elf_hash_table (info)->dynobj; asection *sgot = mips_elf_got_section (tmpbfd, FALSE); - MIPS_ELF_PUT_WORD (tmpbfd, symbol + addend, sgot->contents + g); + MIPS_ELF_PUT_WORD (tmpbfd, symbol, sgot->contents + g); } } else if (r_type == R_MIPS_GOT16 || r_type == R_MIPS_CALL16) @@ -3439,6 +3478,7 @@ mips_elf_calculate_relocation (abfd, input_bfd, input_section, info, /* Fall through. */ case R_MIPS_GOT_DISP: + got_disp: value = g; overflowed_p = mips_elf_overflow_p (value, 16); break; @@ -3470,6 +3510,11 @@ mips_elf_calculate_relocation (abfd, input_bfd, input_section, info, break; case R_MIPS_GOT_PAGE: + /* GOT_PAGE relocations that reference non-local symbols decay + to GOT_DISP. The corresponding GOT_OFST relocation decays to + 0. */ + if (! local_p) + goto got_disp; value = mips_elf_got_page (abfd, input_bfd, info, symbol + addend, NULL); if (value == MINUS_ONE) return bfd_reloc_outofrange; @@ -3479,7 +3524,10 @@ mips_elf_calculate_relocation (abfd, input_bfd, input_section, info, break; case R_MIPS_GOT_OFST: - mips_elf_got_page (abfd, input_bfd, info, symbol + addend, &value); + if (local_p) + mips_elf_got_page (abfd, input_bfd, info, symbol + addend, &value); + else + value = addend; overflowed_p = mips_elf_overflow_p (value, 16); break; @@ -5057,10 +5105,10 @@ _bfd_mips_elf_check_relocs (abfd, info, sec, relocs) sizeof CALL_FP_STUB - 1) == 0) continue; - sec_relocs = (MNAME(abfd,_bfd_elf,link_read_relocs) - (abfd, o, (PTR) NULL, - (Elf_Internal_Rela *) NULL, - info->keep_memory)); + sec_relocs + = _bfd_elf_link_read_relocs (abfd, o, (PTR) NULL, + (Elf_Internal_Rela *) NULL, + info->keep_memory); if (sec_relocs == NULL) return FALSE; @@ -5312,6 +5360,44 @@ _bfd_mips_elf_check_relocs (abfd, info, sec, relocs) } break; + case R_MIPS_GOT_PAGE: + /* If this is a global, overridable symbol, GOT_PAGE will + decay to GOT_DISP, so we'll need a GOT entry for it. */ + if (h == NULL) + break; + else + { + struct mips_elf_link_hash_entry *hmips = + (struct mips_elf_link_hash_entry *) h; + + while (hmips->root.root.type == bfd_link_hash_indirect + || hmips->root.root.type == bfd_link_hash_warning) + hmips = (struct mips_elf_link_hash_entry *) + hmips->root.root.u.i.link; + + if ((hmips->root.root.type == bfd_link_hash_defined + || hmips->root.root.type == bfd_link_hash_defweak) + && hmips->root.root.u.def.section + && ! (info->shared && ! info->symbolic + && ! (hmips->root.elf_link_hash_flags + & ELF_LINK_FORCED_LOCAL)) + /* If we've encountered any other relocation + referencing the symbol, we'll have marked it as + dynamic, and, even though we might be able to get + rid of the GOT entry should we know for sure all + previous relocations were GOT_PAGE ones, at this + point we can't tell, so just keep using the + symbol as dynamic. This is very important in the + multi-got case, since we don't decide whether to + decay GOT_PAGE to GOT_DISP on a per-GOT basis: if + the symbol is dynamic, we'll need a GOT entry for + every GOT in which the symbol is referenced with + a GOT_PAGE relocation. */ + && hmips->root.dynindx == -1) + break; + } + /* Fall through. */ + case R_MIPS_GOT16: case R_MIPS_GOT_HI16: case R_MIPS_GOT_LO16: @@ -5451,6 +5537,185 @@ _bfd_mips_elf_check_relocs (abfd, info, sec, relocs) return TRUE; } +bfd_boolean +_bfd_mips_relax_section (abfd, sec, link_info, again) + bfd *abfd; + asection *sec; + struct bfd_link_info *link_info; + bfd_boolean *again; +{ + Elf_Internal_Rela *internal_relocs; + Elf_Internal_Rela *irel, *irelend; + Elf_Internal_Shdr *symtab_hdr; + bfd_byte *contents = NULL; + bfd_byte *free_contents = NULL; + size_t extsymoff; + bfd_boolean changed_contents = FALSE; + bfd_vma sec_start = sec->output_section->vma + sec->output_offset; + Elf_Internal_Sym *isymbuf = NULL; + + /* We are not currently changing any sizes, so only one pass. */ + *again = FALSE; + + if (link_info->relocateable) + return TRUE; + + internal_relocs = _bfd_elf_link_read_relocs (abfd, sec, (PTR) NULL, + (Elf_Internal_Rela *) NULL, + link_info->keep_memory); + if (internal_relocs == NULL) + return TRUE; + + irelend = internal_relocs + sec->reloc_count + * get_elf_backend_data (abfd)->s->int_rels_per_ext_rel; + symtab_hdr = &elf_tdata (abfd)->symtab_hdr; + extsymoff = (elf_bad_symtab (abfd)) ? 0 : symtab_hdr->sh_info; + + for (irel = internal_relocs; irel < irelend; irel++) + { + bfd_vma symval; + bfd_signed_vma sym_offset; + unsigned int r_type; + unsigned long r_symndx; + asection *sym_sec; + unsigned long instruction; + + /* Turn jalr into bgezal, and jr into beq, if they're marked + with a JALR relocation, that indicate where they jump to. + This saves some pipeline bubbles. */ + r_type = ELF_R_TYPE (abfd, irel->r_info); + if (r_type != R_MIPS_JALR) + continue; + + r_symndx = ELF_R_SYM (abfd, irel->r_info); + /* Compute the address of the jump target. */ + if (r_symndx >= extsymoff) + { + struct mips_elf_link_hash_entry *h + = ((struct mips_elf_link_hash_entry *) + elf_sym_hashes (abfd) [r_symndx - extsymoff]); + + while (h->root.root.type == bfd_link_hash_indirect + || h->root.root.type == bfd_link_hash_warning) + h = (struct mips_elf_link_hash_entry *) h->root.root.u.i.link; + + /* If a symbol is undefined, or if it may be overridden, + skip it. */ + if (! ((h->root.root.type == bfd_link_hash_defined + || h->root.root.type == bfd_link_hash_defweak) + && h->root.root.u.def.section) + || (link_info->shared && ! link_info->symbolic + && ! (h->root.elf_link_hash_flags & ELF_LINK_FORCED_LOCAL))) + continue; + + sym_sec = h->root.root.u.def.section; + if (sym_sec->output_section) + symval = (h->root.root.u.def.value + + sym_sec->output_section->vma + + sym_sec->output_offset); + else + symval = h->root.root.u.def.value; + } + else + { + Elf_Internal_Sym *isym; + + /* Read this BFD's symbols if we haven't done so already. */ + if (isymbuf == NULL && symtab_hdr->sh_info != 0) + { + isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents; + if (isymbuf == NULL) + isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr, + symtab_hdr->sh_info, 0, + NULL, NULL, NULL); + if (isymbuf == NULL) + goto relax_return; + } + + isym = isymbuf + r_symndx; + if (isym->st_shndx == SHN_UNDEF) + continue; + else if (isym->st_shndx == SHN_ABS) + sym_sec = bfd_abs_section_ptr; + else if (isym->st_shndx == SHN_COMMON) + sym_sec = bfd_com_section_ptr; + else + sym_sec + = bfd_section_from_elf_index (abfd, isym->st_shndx); + symval = isym->st_value + + sym_sec->output_section->vma + + sym_sec->output_offset; + } + + /* Compute branch offset, from delay slot of the jump to the + branch target. */ + sym_offset = (symval + irel->r_addend) + - (sec_start + irel->r_offset + 4); + + /* Branch offset must be properly aligned. */ + if ((sym_offset & 3) != 0) + continue; + + sym_offset >>= 2; + + /* Check that it's in range. */ + if (sym_offset < -0x8000 || sym_offset >= 0x8000) + continue; + + /* Get the section contents if we haven't done so already. */ + if (contents == NULL) + { + /* Get cached copy if it exists. */ + if (elf_section_data (sec)->this_hdr.contents != NULL) + contents = elf_section_data (sec)->this_hdr.contents; + else + { + contents = (bfd_byte *) bfd_malloc (sec->_raw_size); + if (contents == NULL) + goto relax_return; + + free_contents = contents; + if (! bfd_get_section_contents (abfd, sec, contents, + (file_ptr) 0, sec->_raw_size)) + goto relax_return; + } + } + + instruction = bfd_get_32 (abfd, contents + irel->r_offset); + + /* If it was jalr , turn it into bgezal $zero, . */ + if ((instruction & 0xfc1fffff) == 0x0000f809) + instruction = 0x04110000; + /* If it was jr , turn it into b . */ + else if ((instruction & 0xfc1fffff) == 0x00000008) + instruction = 0x10000000; + else + continue; + + instruction |= (sym_offset & 0xffff); + bfd_put_32 (abfd, instruction, contents + irel->r_offset); + changed_contents = TRUE; + } + + if (contents != NULL + && elf_section_data (sec)->this_hdr.contents != contents) + { + if (!changed_contents && !link_info->keep_memory) + free (contents); + else + { + /* Cache the section contents for elf_link_input_bfd. */ + elf_section_data (sec)->this_hdr.contents = contents; + } + } + return TRUE; + + relax_return: + if (free_contents != NULL) + free (free_contents); + return FALSE; +} + /* Adjust a symbol defined by a dynamic object and referenced by a regular object. The current definition is in some section of the dynamic object, but we're not including those sections. We have to @@ -5591,7 +5856,7 @@ _bfd_mips_elf_always_size_sections (output_bfd, info) if (dynobj == NULL) /* Relocatable links don't have it. */ return TRUE; - + g = mips_elf_got_info (dynobj, &s); if (s == NULL) return TRUE; @@ -5756,7 +6021,7 @@ _bfd_mips_elf_size_dynamic_sections (output_bfd, info) struct mips_got_info *g = gg; struct mips_elf_set_global_got_offset_arg set_got_offset_arg; unsigned int needed_relocs = 0; - + if (gg->next) { set_got_offset_arg.value = MIPS_ELF_GOT_SIZE (output_bfd); @@ -6516,7 +6781,7 @@ _bfd_mips_elf_finish_dynamic_symbol (output_bfd, info, h, sym) e.abfd = output_bfd; e.symndx = -1; e.d.h = (struct mips_elf_link_hash_entry *)h; - + if (info->shared || h->root.type == bfd_link_hash_undefined || h->root.type == bfd_link_hash_undefweak) @@ -7537,55 +7802,58 @@ _bfd_mips_elf_hide_symbol (info, entry, force_local) h->forced_local = TRUE; dynobj = elf_hash_table (info)->dynobj; - got = mips_elf_got_section (dynobj, FALSE); - g = mips_elf_section_data (got)->u.got_info; - - if (g->next) + if (dynobj != NULL) { - struct mips_got_entry e; - struct mips_got_info *gg = g; + got = mips_elf_got_section (dynobj, FALSE); + g = mips_elf_section_data (got)->u.got_info; - /* Since we're turning what used to be a global symbol into a - local one, bump up the number of local entries of each GOT - that had an entry for it. This will automatically decrease - the number of global entries, since global_gotno is actually - the upper limit of global entries. */ - e.abfd = dynobj; - e.symndx = -1; - e.d.h = h; + if (g->next) + { + struct mips_got_entry e; + struct mips_got_info *gg = g; + + /* Since we're turning what used to be a global symbol into a + local one, bump up the number of local entries of each GOT + that had an entry for it. This will automatically decrease + the number of global entries, since global_gotno is actually + the upper limit of global entries. */ + e.abfd = dynobj; + e.symndx = -1; + e.d.h = h; - for (g = g->next; g != gg; g = g->next) - if (htab_find (g->got_entries, &e)) - { - BFD_ASSERT (g->global_gotno > 0); - g->local_gotno++; - g->global_gotno--; - } + for (g = g->next; g != gg; g = g->next) + if (htab_find (g->got_entries, &e)) + { + BFD_ASSERT (g->global_gotno > 0); + g->local_gotno++; + g->global_gotno--; + } - /* If this was a global symbol forced into the primary GOT, we - no longer need an entry for it. We can't release the entry - at this point, but we must at least stop counting it as one - of the symbols that required a forced got entry. */ - if (h->root.got.offset == 2) + /* If this was a global symbol forced into the primary GOT, we + no longer need an entry for it. We can't release the entry + at this point, but we must at least stop counting it as one + of the symbols that required a forced got entry. */ + if (h->root.got.offset == 2) + { + BFD_ASSERT (gg->assigned_gotno > 0); + gg->assigned_gotno--; + } + } + else if (g->global_gotno == 0 && g->global_gotsym == NULL) + /* If we haven't got through GOT allocation yet, just bump up the + number of local entries, as this symbol won't be counted as + global. */ + g->local_gotno++; + else if (h->root.got.offset == 1) { - BFD_ASSERT (gg->assigned_gotno > 0); - gg->assigned_gotno--; + /* If we're past non-multi-GOT allocation and this symbol had + been marked for a global got entry, give it a local entry + instead. */ + BFD_ASSERT (g->global_gotno > 0); + g->local_gotno++; + g->global_gotno--; } } - else if (g->global_gotno == 0 && g->global_gotsym == NULL) - /* If we haven't got through GOT allocation yet, just bump up the - number of local entries, as this symbol won't be counted as - global. */ - g->local_gotno++; - else if (h->root.got.offset == 1) - { - /* If we're past non-multi-GOT allocation and this symbol had - been marked for a global got entry, give it a local entry - instead. */ - BFD_ASSERT (g->global_gotno > 0); - g->local_gotno++; - g->global_gotno--; - } _bfd_elf_link_hash_hide_symbol (info, &h->root, force_local); } @@ -7618,10 +7886,9 @@ _bfd_mips_elf_discard_info (abfd, cookie, info) if (! tdata) return FALSE; - cookie->rels = (MNAME(abfd,_bfd_elf,link_read_relocs) - (abfd, o, (PTR) NULL, - (Elf_Internal_Rela *) NULL, - info->keep_memory)); + cookie->rels = _bfd_elf_link_read_relocs (abfd, o, (PTR) NULL, + (Elf_Internal_Rela *) NULL, + info->keep_memory); if (!cookie->rels) { free (tdata); @@ -8112,17 +8379,6 @@ _bfd_mips_elf_final_link (abfd, info) scRData, scSData, scSBss, scBss }; - /* If all the things we linked together were PIC, but we're - producing an executable (rather than a shared object), then the - resulting file is CPIC (i.e., it calls PIC code.) */ - if (!info->shared - && !info->relocateable - && elf_elfheader (abfd)->e_flags & EF_MIPS_PIC) - { - elf_elfheader (abfd)->e_flags &= ~EF_MIPS_PIC; - elf_elfheader (abfd)->e_flags |= EF_MIPS_CPIC; - } - /* We'd carefully arranged the dynamic symbol indices, and then the generic size_dynamic_sections renumbered them out from under us. Rather than trying somehow to prevent the renumbering, just do @@ -8905,12 +9161,25 @@ _bfd_mips_elf_merge_private_bfd_data (ibfd, obfd) /* Check if we have the same endianess */ if (! _bfd_generic_verify_endian_match (ibfd, obfd)) - return FALSE; + { + (*_bfd_error_handler) + (_("%s: endianness incompatible with that of the selected emulation"), + bfd_archive_filename (ibfd)); + return FALSE; + } if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour || bfd_get_flavour (obfd) != bfd_target_elf_flavour) return TRUE; + if (strcmp (bfd_get_target (ibfd), bfd_get_target (obfd)) != 0) + { + (*_bfd_error_handler) + (_("%s: ABI is incompatible with that of the selected emulation"), + bfd_archive_filename (ibfd)); + return FALSE; + } + new_flags = elf_elfheader (ibfd)->e_flags; elf_elfheader (obfd)->e_flags |= new_flags & EF_MIPS_NOREORDER; old_flags = elf_elfheader (obfd)->e_flags; @@ -8969,25 +9238,22 @@ _bfd_mips_elf_merge_private_bfd_data (ibfd, obfd) ok = TRUE; - if ((new_flags & EF_MIPS_PIC) != (old_flags & EF_MIPS_PIC)) + if (((new_flags & (EF_MIPS_PIC | EF_MIPS_CPIC)) != 0) + != ((old_flags & (EF_MIPS_PIC | EF_MIPS_CPIC)) != 0)) { - new_flags &= ~EF_MIPS_PIC; - old_flags &= ~EF_MIPS_PIC; (*_bfd_error_handler) - (_("%s: linking PIC files with non-PIC files"), + (_("%s: warning: linking PIC files with non-PIC files"), bfd_archive_filename (ibfd)); - ok = FALSE; + ok = TRUE; } - if ((new_flags & EF_MIPS_CPIC) != (old_flags & EF_MIPS_CPIC)) - { - new_flags &= ~EF_MIPS_CPIC; - old_flags &= ~EF_MIPS_CPIC; - (*_bfd_error_handler) - (_("%s: linking abicalls files with non-abicalls files"), - bfd_archive_filename (ibfd)); - ok = FALSE; - } + if (new_flags & (EF_MIPS_PIC | EF_MIPS_CPIC)) + elf_elfheader (obfd)->e_flags |= EF_MIPS_CPIC; + if (! (new_flags & EF_MIPS_PIC)) + elf_elfheader (obfd)->e_flags &= ~EF_MIPS_PIC; + + new_flags &= ~ (EF_MIPS_PIC | EF_MIPS_CPIC); + old_flags &= ~ (EF_MIPS_PIC | EF_MIPS_CPIC); /* Compare the ISAs. */ if (mips_32bit_flags_p (old_flags) != mips_32bit_flags_p (new_flags))