Traditional MIPS targets support added by Koundinya.K, Dansk Data
Elektronik & Operations Research Group. <kk@ddeorg.soft.net>
-This file is part of BFD, the Binary File Descriptor library.
+ 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 2 of the License, or
-(at your option) any later version.
+ 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 2 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.
+ 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+ 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
/* This file handles functionality common to the different MIPS ABI's. */
};
#define mips_elf_section_data(sec) \
- ((struct _mips_elf_section_data *) (sec)->used_by_bfd)
+ ((struct _mips_elf_section_data *) elf_section_data (sec))
/* This structure is passed to mips_elf_sort_hash_table_f when sorting
the dynamic symbols. */
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. */
loader for use by the static exception system. */
typedef struct runtime_pdr {
- bfd_vma adr; /* memory address of start of procedure */
- long regmask; /* save register mask */
- long regoffset; /* save register offset */
- long fregmask; /* save floating point register mask */
- long fregoffset; /* save floating point register offset */
- long frameoffset; /* frame size */
- short framereg; /* frame pointer register */
- short pcreg; /* offset or reg of return pc */
- long irpss; /* index into the runtime string table */
+ bfd_vma adr; /* Memory address of start of procedure. */
+ long regmask; /* Save register mask. */
+ long regoffset; /* Save register offset. */
+ long fregmask; /* Save floating point register mask. */
+ long fregoffset; /* Save floating point register offset. */
+ long frameoffset; /* Frame size. */
+ short framereg; /* Frame pointer register. */
+ short pcreg; /* Offset or reg of return pc. */
+ long irpss; /* Index into the runtime string table. */
long reserved;
- struct exception_info *exception_info;/* pointer to exception array */
+ struct exception_info *exception_info;/* Pointer to exception array. */
} RPDR, *pRPDR;
#define cbRPDR sizeof (RPDR)
#define rpdNil ((pRPDR) 0)
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
/* 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) \
{
const struct mips_got_entry *entry = (struct mips_got_entry *)entry_;
- return entry->abfd->id + entry->symndx
+ return entry->symndx
+ (! entry->abfd ? mips_elf_hash_bfd_vma (entry->d.address)
- : entry->symndx >= 0 ? mips_elf_hash_bfd_vma (entry->d.addend)
- : entry->d.h->root.root.root.hash);
+ : entry->abfd->id
+ + (entry->symndx >= 0 ? mips_elf_hash_bfd_vma (entry->d.addend)
+ : entry->d.h->root.root.root.hash));
}
static int
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. */
if (g->bfd2got && ibfd)
{
struct mips_got_entry e, *p;
-
+
BFD_ASSERT (h->dynindx >= 0);
g = mips_elf_got_for_ibfd (g, ibfd);
if (!entry)
return MINUS_ONE;
-
+
index = entry->gotidx;
if (offsetp)
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;
}
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)
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
if (! *loc)
return FALSE;
-
+
entry.gotidx = -1;
memcpy (*loc, &entry, sizeof entry);
if (! *loc)
return FALSE;
-
+
memcpy (*loc, &entry, sizeof entry);
return TRUE;
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;
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)
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)
{
bfd2got->g->next = arg->current;
arg->current = bfd2got->g;
-
+
arg->current_count = lcount + gcount;
}
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
/* 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;
}
BFD_ASSERT (g->next);
g = g->next;
-
+
return (g->local_gotno + g->global_gotno) * MIPS_ELF_GOT_SIZE (abfd);
}
{
struct mips_elf_bfd2got_hash *bfdgot;
void **bfdgotp;
-
+
bfdgot = (struct mips_elf_bfd2got_hash *)bfd_alloc
(abfd, sizeof (struct mips_elf_bfd2got_hash));
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
got->_raw_size = (gg->next->local_gotno
+ gg->next->global_gotno) * MIPS_ELF_GOT_SIZE (abfd);
-
+
return TRUE;
}
-
+
\f
/* Returns the first relocation of type r_type found, beginning with
RELOCATION. RELEND is one-past-the-end of the relocation table. */
addresses. */
symbol = 0;
else if (info->shared
- && (!info->symbolic || info->allow_shlib_undefined)
&& !info->no_undefined
&& ELF_ST_VISIBILITY (h->root.other) == STV_DEFAULT)
symbol = 0;
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:
/* 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);
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)
/* Fall through. */
case R_MIPS_GOT_DISP:
+ got_disp:
value = g;
overflowed_p = mips_elf_overflow_p (value, 16);
break;
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;
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;
else
{
long indx;
- bfd_vma section_offset;
/* We must now calculate the dynamic symbol table index to use
in the relocation. */
abort ();
}
- /* Figure out how far the target of the relocation is from
- the beginning of its section. */
- section_offset = symbol - sec->output_section->vma;
- /* The relocation we're building is section-relative.
- Therefore, the original addend must be adjusted by the
- section offset. */
- *addendp += section_offset;
- /* Now, the relocation is just against the section. */
- symbol = sec->output_section->vma;
+ /* Instead of generating a relocation using the section
+ symbol, we may as well make it a fully relative
+ relocation. We want to avoid generating relocations to
+ local symbols because we used to generate them
+ incorrectly, without adding the original symbol value,
+ which is mandated by the ABI for section symbols. In
+ order to give dynamic loaders and applications time to
+ phase out the incorrect use, we refrain from emitting
+ section-relative relocations. It's not like they're
+ useful, after all. This should be a bit more efficient
+ as well. */
+ indx = 0;
}
/* If the relocation was previously an absolute relocation and
know where the shared library will wind up at load-time. */
outrel[0].r_info = ELF_R_INFO (output_bfd, (unsigned long) indx,
R_MIPS_REL32);
+ /* For strict adherence to the ABI specification, we should
+ generate a R_MIPS_64 relocation record by itself before the
+ _REL32/_64 record as well, such that the addend is read in as
+ a 64-bit value (REL32 is a 32-bit relocation, after all).
+ However, since none of the existing ELF64 MIPS dynamic
+ loaders seems to care, we don't waste space with these
+ artificial relocations. If this turns out to not be true,
+ mips_elf_allocate_dynamic_relocation() should be tweaked so
+ as to make room for a pair of dynamic relocations per
+ invocation if ABI_64_P, and here we should generate an
+ additional relocation record with R_MIPS_64 by itself for a
+ NULL symbol before this relocation record. */
outrel[1].r_info = ELF_R_INFO (output_bfd, (unsigned long) 0,
ABI_64_P (output_bfd)
? R_MIPS_64
esd->rel_hdr2 = (Elf_Internal_Shdr *) bfd_zalloc (abfd, amt);
if (!esd->rel_hdr2)
return FALSE;
- _bfd_elf_init_reloc_shdr (abfd, esd->rel_hdr2, sec,
- !elf_section_data (sec)->use_rela_p);
+ _bfd_elf_init_reloc_shdr (abfd, esd->rel_hdr2, sec, !sec->use_rela_p);
}
return TRUE;
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;
}
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:
return TRUE;
}
\f
+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 <reg>, turn it into bgezal $zero, <target>. */
+ if ((instruction & 0xfc1fffff) == 0x0000f809)
+ instruction = 0x04110000;
+ /* If it was jr <reg>, turn it into b <target>. */
+ 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;
+}
+\f
/* 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
if (dynobj == NULL)
/* Relocatable links don't have it. */
return TRUE;
-
+
g = mips_elf_got_info (dynobj, &s);
if (s == NULL)
return TRUE;
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);
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)
h = (struct mips_elf_link_hash_entry *) entry;
if (h->forced_local)
return;
- h->forced_local = TRUE;
+ h->forced_local = force_local;
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 && force_local)
{
- 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);
}
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);
cookie->rel = cookie->rels;
cookie->relend = cookie->rels + o->reloc_count;
- for (i = 0, skip = 0; i < o->_raw_size; i ++)
+ for (i = 0, skip = 0; i < o->_raw_size / PDR_SIZE; i ++)
{
if (MNAME(abfd,_bfd_elf,reloc_symbol_deleted_p) (i * PDR_SIZE, cookie))
{
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
/* 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;
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))