/* PowerPC-specific support for 32-bit ELF
- Copyright 1994, 1995, 1996, 1997, 1998 Free Software Foundation, Inc.
+ Copyright 1994, 95, 96, 97, 98, 1999 Free Software Foundation, Inc.
Written by Ian Lance Taylor, Cygnus Support.
This file is part of BFD, the Binary File Descriptor library.
static boolean ppc_elf_adjust_dynamic_symbol PARAMS ((struct bfd_link_info *,
struct elf_link_hash_entry *));
-static boolean ppc_elf_adjust_dynindx PARAMS ((struct elf_link_hash_entry *, PTR));
-
static boolean ppc_elf_size_dynamic_sections PARAMS ((bfd *, struct bfd_link_info *));
static boolean ppc_elf_relocate_section PARAMS ((bfd *,
#define ELF_DYNAMIC_INTERPRETER "/usr/lib/ld.so.1"
-/* The size in bytes of an entry in the procedure linkage table, and of the initial size
- of the plt reserved for the dynamic linker. */
-
+/* The size in bytes of an entry in the procedure linkage table. */
#define PLT_ENTRY_SIZE 12
+/* The initial size of the plt reserved for the dynamic linker. */
#define PLT_INITIAL_ENTRY_SIZE 72
+/* The size of the gap between entries in the PLT. */
+#define PLT_SLOT_SIZE 8
+/* The number of single-slot PLT entries (the rest use two slots). */
+#define PLT_NUM_SINGLE_ENTRIES 8192
\f
static reloc_howto_type *ppc_elf_howto_table[ (int)R_PPC_max ];
16, /* bitsize */
false, /* pc_relative */
0, /* bitpos */
- complain_overflow_bitfield, /* complain_on_overflow */
+ complain_overflow_dont, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_GOT16_LO", /* name */
false, /* partial_inplace */
16, /* bitsize */
false, /* pc_relative */
0, /* bitpos */
- complain_overflow_bitfield, /* complain_on_overflow */
+ complain_overflow_dont, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_PLT16_LO", /* name */
false, /* partial_inplace */
false), /* pcrel_offset */
/* Like R_PPC_ADDR16_HA, but referring to the PLT table entry for
- the symbol. FIXME: Not supported. */
+ the symbol. */
HOWTO (R_PPC_PLT16_HA, /* type */
- 0, /* rightshift */
+ 16, /* rightshift */
1, /* size (0 = byte, 1 = short, 2 = long) */
16, /* bitsize */
false, /* pc_relative */
0, /* bitpos */
complain_overflow_bitfield, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
+ ppc_elf_addr16_ha_reloc, /* special_function */
"R_PPC_PLT16_HA", /* name */
false, /* partial_inplace */
0, /* src_mask */
16, /* bitsize */
false, /* pc_relative */
0, /* bitpos */
- complain_overflow_bitfield, /* complain_on_overflow */
+ complain_overflow_dont, /* complain_on_overflow */
bfd_elf_generic_reloc, /* special_function */
"R_PPC_SECTOFF_LO", /* name */
false, /* partial_inplace */
/* 16-bit upper half adjusted section relative relocation. */
HOWTO (R_PPC_SECTOFF_HA, /* type */
- 0, /* rightshift */
+ 16, /* rightshift */
1, /* size (0 = byte, 1 = short, 2 = long) */
16, /* bitsize */
false, /* pc_relative */
0, /* bitpos */
complain_overflow_bitfield, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
+ ppc_elf_addr16_ha_reloc, /* special_function */
"R_PPC_SECTOFF_HA", /* name */
false, /* partial_inplace */
0, /* src_mask */
false, /* pc_relative */
0, /* bitpos */
complain_overflow_dont, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
+ ppc_elf_addr16_ha_reloc, /* special_function */
"R_PPC_EMB_NADDR16_HA", /* name */
false, /* partial_inplace */
0, /* src_mask */
}
}
+\f
+/* This function handles relaxing for the PPC with option --mpc860c0[=<n>].
+
+ The MPC860, revision C0 or earlier contains a bug in the die.
+ If all of the following conditions are true, the next instruction
+ to be executed *may* be treated as a no-op.
+ 1/ A forward branch is executed.
+ 2/ The branch is predicted as not taken.
+ 3/ The branch is taken.
+ 4/ The branch is located in the last 5 words of a page.
+ (The EOP limit is 5 by default but may be specified as any value from 1-10.)
+
+ Our software solution is to detect these problematic branches in a
+ linker pass and modify them as follows:
+ 1/ Unconditional branches - Since these are always predicted taken,
+ there is no problem and no action is required.
+ 2/ Conditional backward branches - No problem, no action required.
+ 3/ Conditional forward branches - Ensure that the "inverse prediction
+ bit" is set (ensure it is predicted taken).
+ 4/ Conditional register branches - Ensure that the "y bit" is set
+ (ensure it is predicted taken).
+*/
+
+/* Sort sections by address. */
+
+static int
+ppc_elf_sort_rela (arg1, arg2)
+ const void *arg1;
+ const void *arg2;
+{
+ const Elf_Internal_Rela **rela1 = (const Elf_Internal_Rela**) arg1;
+ const Elf_Internal_Rela **rela2 = (const Elf_Internal_Rela**) arg2;
+
+ /* Sort by offset. */
+ return ((*rela1)->r_offset - (*rela2)->r_offset);
+}
+
+static boolean
+ppc_elf_relax_section (abfd, isec, link_info, again)
+ bfd *abfd;
+ asection *isec;
+ struct bfd_link_info *link_info;
+ boolean *again;
+{
+#define PAGESIZE 0x1000
+
+ bfd_byte *contents = NULL;
+ bfd_byte *free_contents = NULL;
+ Elf_Internal_Rela *internal_relocs = NULL;
+ Elf_Internal_Rela *free_relocs = NULL;
+ Elf_Internal_Rela **rela_comb = NULL;
+ int comb_curr, comb_count;
+
+ /* We never have to do this more than once per input section. */
+ *again = false;
+
+ /* If needed, initialize this section's cooked size. */
+ if (isec->_cooked_size == 0)
+ isec->_cooked_size = isec->_raw_size;
+
+ /* We're only interested in text sections which overlap the
+ troublesome area at the end of a page. */
+ if (link_info->mpc860c0 && (isec->flags & SEC_CODE) && isec->_cooked_size)
+ {
+ bfd_vma dot, end_page, end_section;
+ boolean section_modified;
+
+ /* Get the section contents. */
+ /* Get cached copy if it exists. */
+ if (elf_section_data (isec)->this_hdr.contents != NULL)
+ contents = elf_section_data (isec)->this_hdr.contents;
+ else
+ {
+ /* Go get them off disk. */
+ contents = (bfd_byte *) bfd_malloc (isec->_raw_size);
+ if (contents == NULL)
+ goto error_return;
+ free_contents = contents;
+
+ if (! bfd_get_section_contents (abfd, isec, contents,
+ (file_ptr) 0, isec->_raw_size))
+ goto error_return;
+ }
+
+ comb_curr = 0;
+ comb_count = 0;
+ if (isec->reloc_count)
+ {
+ unsigned n;
+
+ /* Get a copy of the native relocations. */
+ internal_relocs = _bfd_elf32_link_read_relocs (
+ abfd, isec, (PTR) NULL, (Elf_Internal_Rela *) NULL,
+ link_info->keep_memory);
+ if (internal_relocs == NULL)
+ goto error_return;
+ if (! link_info->keep_memory)
+ free_relocs = internal_relocs;
+
+ /* Setup a faster access method for the reloc info we need. */
+ rela_comb = (Elf_Internal_Rela**)
+ bfd_malloc (isec->reloc_count*sizeof(Elf_Internal_Rela*));
+ if (rela_comb == NULL)
+ goto error_return;
+ for (n=0; n<isec->reloc_count; ++n)
+ {
+ long r_type;
+
+ r_type = ELF32_R_TYPE (internal_relocs[n].r_info);
+ if (r_type < 0 || r_type >= (int)R_PPC_max)
+ goto error_return;
+
+ /* Prologue constants are sometimes present in the ".text"
+ sections and they can be identified by their associated relocation.
+ We don't want to process those words and some others which
+ can also be identified by their relocations. However, not all
+ conditional branches will have a relocation so we will
+ only ignore words that 1) have a reloc, and 2) the reloc
+ is not applicable to a conditional branch.
+ The array rela_comb is built here for use in the EOP scan loop. */
+ switch (r_type)
+ {
+ case R_PPC_ADDR14_BRNTAKEN: /* absolute, predicted not taken */
+ case R_PPC_REL14: /* relative cond. br. */
+ case R_PPC_REL14_BRNTAKEN: /* rel. cond. br., predicted not taken */
+ /* We should check the instruction. */
+ break;
+ default:
+ /* The word is not a conditional branch - ignore it. */
+ rela_comb[comb_count++] = &internal_relocs[n];
+ break;
+ }
+ }
+ if (comb_count > 1)
+ qsort (rela_comb, (size_t) comb_count, sizeof (int), ppc_elf_sort_rela);
+ }
+
+ /* Enumerate each EOP region that overlaps this section. */
+ end_section = isec->vma + isec->_cooked_size;
+ dot = end_page = (isec->vma | (PAGESIZE - 1)) + 1;
+ dot -= link_info->mpc860c0;
+ section_modified = false;
+ if (dot < isec->vma) /* Increment the start position if this section */
+ dot = isec->vma; /* begins in the middle of its first EOP region. */
+ for (;
+ dot < end_section;
+ dot += PAGESIZE, end_page += PAGESIZE)
+ {
+
+ /* Check each word in this EOP region. */
+ for (; dot < end_page; dot += 4)
+ {
+ bfd_vma isec_offset;
+ unsigned long insn;
+ boolean skip, modified;
+
+ /* Don't process this word if there is a relocation for it and
+ the relocation indicates the word is not a conditional branch. */
+ skip = false;
+ isec_offset = dot - isec->vma;
+ for (; comb_curr<comb_count; ++comb_curr)
+ {
+ bfd_vma r_offset;
+
+ r_offset = rela_comb[comb_curr]->r_offset;
+ if (r_offset >= isec_offset)
+ {
+ if (r_offset == isec_offset) skip = true;
+ break;
+ }
+ }
+ if (skip) continue;
+
+ /* Check the current word for a problematic conditional branch. */
+#define BO0(insn) ((insn) & 0x02000000)
+#define BO2(insn) ((insn) & 0x00800000)
+#define BO4(insn) ((insn) & 0x00200000)
+ insn = (unsigned long) bfd_get_32 (abfd, contents + isec_offset);
+ modified = false;
+ if ((insn & 0xFc000000) == 0x40000000)
+ {
+ /* Instruction is BCx */
+ if ((!BO0(insn) || !BO2(insn)) && !BO4(insn))
+ {
+ bfd_vma target;
+ /* This branch is predicted as "normal".
+ If this is a forward branch, it is problematic. */
+
+ target = insn & 0x0000Fffc; /*extract*/
+ target = (target ^ 0x8000) - 0x8000; /*sign extend*/
+ if ((insn & 0x00000002) == 0)
+ target += dot; /*convert to abs*/
+ if (target > dot)
+ {
+ insn |= 0x00200000; /* set the prediction bit */
+ modified = true;
+ }
+ }
+ }
+ else if ((insn & 0xFc00Fffe) == 0x4c000420)
+ {
+ /* Instruction is BCCTRx */
+ if ((!BO0(insn) || !BO2(insn)) && !BO4(insn))
+ {
+ /* This branch is predicted as not-taken.
+ If this is a forward branch, it is problematic.
+ Since we can't tell statically if it will branch forward,
+ always set the prediction bit. */
+ insn |= 0x00200000; /* set the prediction bit */
+ modified = true;
+ }
+ }
+ else if ((insn & 0xFc00Fffe) == 0x4c000020)
+ {
+ /* Instruction is BCLRx */
+ if ((!BO0(insn) || !BO2(insn)) && !BO4(insn))
+ {
+ /* This branch is predicted as not-taken.
+ If this is a forward branch, it is problematic.
+ Since we can't tell statically if it will branch forward,
+ always set the prediction bit. */
+ insn |= 0x00200000; /* set the prediction bit */
+ modified = true;
+ }
+ }
+#undef BO0
+#undef BO2
+#undef BO4
+ if (modified)
+ {
+ bfd_put_32 (abfd, insn, contents + isec_offset);
+ section_modified = true;
+ }
+ }
+ }
+ if (section_modified)
+ {
+ elf_section_data (isec)->this_hdr.contents = contents;
+ free_contents = NULL;
+ }
+ }
+
+ if (rela_comb != NULL)
+ {
+ free (rela_comb);
+ rela_comb = NULL;
+ }
+
+ if (free_relocs != NULL)
+ {
+ free (free_relocs);
+ free_relocs = NULL;
+ }
+
+ if (free_contents != NULL)
+ {
+ if (! link_info->keep_memory)
+ free (free_contents);
+ else
+ {
+ /* Cache the section contents for elf_link_input_bfd. */
+ elf_section_data (isec)->this_hdr.contents = contents;
+ }
+ free_contents = NULL;
+ }
+
+ return true;
+
+error_return:
+ if (rela_comb != NULL)
+ free (rela_comb);
+ if (free_relocs != NULL)
+ free (free_relocs);
+ if (free_contents != NULL)
+ free (free_contents);
+ return false;
+}
+
\f
static reloc_howto_type *
ppc_elf_reloc_type_lookup (abfd, code)
- bfd *abfd;
+ bfd *abfd ATTRIBUTE_UNUSED;
bfd_reloc_code_real_type code;
{
enum elf_ppc_reloc_type ppc_reloc = R_PPC_NONE;
static void
ppc_elf_info_to_howto (abfd, cache_ptr, dst)
- bfd *abfd;
+ bfd *abfd ATTRIBUTE_UNUSED;
arelent *cache_ptr;
Elf32_Internal_Rela *dst;
{
static bfd_reloc_status_type
ppc_elf_addr16_ha_reloc (abfd, reloc_entry, symbol, data, input_section,
output_bfd, error_message)
- bfd *abfd;
+ bfd *abfd ATTRIBUTE_UNUSED;
arelent *reloc_entry;
asymbol *symbol;
- PTR data;
+ PTR data ATTRIBUTE_UNUSED;
asection *input_section;
bfd *output_bfd;
- char **error_message;
+ char **error_message ATTRIBUTE_UNUSED;
{
bfd_vma relocation;
boolean error;
/* Check if we have the same endianess */
- if (ibfd->xvec->byteorder != obfd->xvec->byteorder
- && obfd->xvec->byteorder != BFD_ENDIAN_UNKNOWN)
- {
- const char *msg;
-
- if (bfd_big_endian (ibfd))
- msg = _("%s: compiled for a big endian system and target is little endian");
- else
- msg = _("%s: compiled for a little endian system and target is big endian");
-
- (*_bfd_error_handler) (msg, bfd_get_filename (ibfd));
-
- bfd_set_error (bfd_error_wrong_format);
- return false;
- }
+ if (_bfd_generic_verify_endian_match (ibfd, obfd) == false)
+ return false;
if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
|| bfd_get_flavour (obfd) != bfd_target_elf_flavour)
(_("%s: compiled normally and linked with modules compiled with -mrelocatable"),
bfd_get_filename (ibfd));
}
- /* If -mrelocatable-lib is linked with an object without -mrelocatable-lib, turn off
- the -mrelocatable-lib, since at least one module isn't relocatable. */
- else if ((old_flags & EF_PPC_RELOCATABLE_LIB) != 0
- && (new_flags & EF_PPC_RELOCATABLE_LIB) == 0)
+
+ /* The output is -mrelocatable-lib iff both the input files are. */
+ if (! (new_flags & EF_PPC_RELOCATABLE_LIB))
elf_elfheader (obfd)->e_flags &= ~EF_PPC_RELOCATABLE_LIB;
+ /* The output is -mrelocatable iff it can't be -mrelocatable-lib,
+ but each input file is either -mrelocatable or -mrelocatable-lib. */
+ if (! (elf_elfheader (obfd)->e_flags & EF_PPC_RELOCATABLE_LIB)
+ && (new_flags & (EF_PPC_RELOCATABLE_LIB | EF_PPC_RELOCATABLE))
+ && (old_flags & (EF_PPC_RELOCATABLE_LIB | EF_PPC_RELOCATABLE)))
+ elf_elfheader (obfd)->e_flags |= EF_PPC_RELOCATABLE;
/* Do not warn about eabi vs. V.4 mismatch, just or in the bit if any module uses it */
elf_elfheader (obfd)->e_flags |= (new_flags & EF_PPC_EMB);
static boolean
ppc_elf_fake_sections (abfd, shdr, asect)
- bfd *abfd;
+ bfd *abfd ATTRIBUTE_UNUSED;
Elf32_Internal_Shdr *shdr;
asection *asect;
{
static boolean
ppc_elf_modify_segment_map (abfd)
- bfd *abfd;
+ bfd *abfd ATTRIBUTE_UNUSED;
{
return true;
}
is 2 words (for a load and a jump), and then there is a remaining
word available at the end. */
plt_offset = (PLT_INITIAL_ENTRY_SIZE
- + 8 * ((s->_raw_size - PLT_INITIAL_ENTRY_SIZE) / PLT_ENTRY_SIZE));
+ + (PLT_SLOT_SIZE
+ * ((s->_raw_size - PLT_INITIAL_ENTRY_SIZE)
+ / PLT_ENTRY_SIZE)));
/* If this symbol is not defined in a regular file, and we are
not generating a shared library, then set the symbol to this
h->plt.offset = plt_offset;
- /* Make room for this entry. */
- s->_raw_size += PLT_ENTRY_SIZE;
+ /* Make room for this entry. After the 8192nd entry, room
+ for two entries is allocated. */
+ if ((s->_raw_size - PLT_INITIAL_ENTRY_SIZE) / PLT_ENTRY_SIZE
+ >= PLT_NUM_SINGLE_ENTRIES)
+ s->_raw_size += 2 * PLT_ENTRY_SIZE;
+ else
+ s->_raw_size += PLT_ENTRY_SIZE;
/* We also need to make an entry in the .rela.plt section. */
s = bfd_get_section_by_name (dynobj, ".rela.plt");
return true;
}
-\f
-/* Increment the index of a dynamic symbol by a given amount. Called
- via elf_link_hash_traverse. */
-
-static boolean
-ppc_elf_adjust_dynindx (h, cparg)
- struct elf_link_hash_entry *h;
- PTR cparg;
-{
- int *cp = (int *) cparg;
-
-#ifdef DEBUG
- fprintf (stderr, "ppc_elf_adjust_dynindx called, h->dynindx = %d, *cp = %d\n", h->dynindx, *cp);
-#endif
-
- if (h->dynindx != -1)
- h->dynindx += *cp;
-
- return true;
-}
-
\f
/* Set the sizes of the dynamic sections. */
if (strip)
{
- asection **spp;
-
- for (spp = &s->output_section->owner->sections;
- *spp != s->output_section;
- spp = &(*spp)->next)
- ;
- *spp = s->output_section->next;
- --s->output_section->owner->section_count;
-
+ _bfd_strip_section_from_output (info, s);
continue;
}
{
if (! bfd_elf32_add_dynamic_entry (info, DT_TEXTREL, 0))
return false;
+ info->flags |= DF_TEXTREL;
}
}
- /* If we are generating a shared library, we generate a section
- symbol for each output section. These are local symbols, which
- means that they must come first in the dynamic symbol table.
- That means we must increment the dynamic symbol index of every
- other dynamic symbol.
-
- FIXME: We assume that there will never be relocations to
- locations in linker-created sections that do not have
- externally-visible names. Instead, we should work out precisely
- which sections relocations are targetted at. */
- if (info->shared)
- {
- int c;
-
- for (c = 0, s = output_bfd->sections; s != NULL; s = s->next)
- {
- if ((s->flags & SEC_LINKER_CREATED) != 0
- || (s->flags & SEC_ALLOC) == 0)
- {
- elf_section_data (s)->dynindx = -1;
- continue;
- }
-
- /* These symbols will have no names, so we don't need to
- fiddle with dynstr_index. */
-
- elf_section_data (s)->dynindx = c + 1;
-
- c++;
- }
-
- elf_link_hash_traverse (elf_hash_table (info),
- ppc_elf_adjust_dynindx,
- (PTR) &c);
- elf_hash_table (info)->dynsymcount += c;
- }
-
return true;
}
if (local_got_refcounts == NULL)
{
size_t size;
- register unsigned int i;
size = symtab_hdr->sh_info * sizeof (bfd_signed_vma);
local_got_refcounts = (bfd_signed_vma *)
static asection *
ppc_elf_gc_mark_hook (abfd, info, rel, h, sym)
bfd *abfd;
- struct bfd_link_info *info;
+ struct bfd_link_info *info ATTRIBUTE_UNUSED;
Elf_Internal_Rela *rel;
struct elf_link_hash_entry *h;
Elf_Internal_Sym *sym;
case bfd_link_hash_common:
return h->root.u.c.p->section;
+
+ default:
+ break;
}
}
}
static boolean
ppc_elf_gc_sweep_hook (abfd, info, sec, relocs)
bfd *abfd;
- struct bfd_link_info *info;
+ struct bfd_link_info *info ATTRIBUTE_UNUSED;
asection *sec;
const Elf_Internal_Rela *relocs;
{
if (h->got.refcount > 0)
h->got.refcount--;
}
- else
+ else if (local_got_refcounts != NULL)
{
if (local_got_refcounts[r_symndx] > 0)
local_got_refcounts[r_symndx]--;
bfd *abfd;
struct bfd_link_info *info;
const Elf_Internal_Sym *sym;
- const char **namep;
- flagword *flagsp;
+ const char **namep ATTRIBUTE_UNUSED;
+ flagword *flagsp ATTRIBUTE_UNUSED;
asection **secp;
bfd_vma *valp;
{
asection *splt;
asection *srela;
Elf_Internal_Rela rela;
+ bfd_vma reloc_index;
#ifdef DEBUG
fprintf (stderr, ", plt_offset = %d", h->plt.offset);
+ h->plt.offset);
rela.r_info = ELF32_R_INFO (h->dynindx, R_PPC_JMP_SLOT);
rela.r_addend = 0;
+
+ reloc_index = (h->plt.offset - PLT_INITIAL_ENTRY_SIZE) / PLT_SLOT_SIZE;
+ if (reloc_index > PLT_NUM_SINGLE_ENTRIES)
+ reloc_index -= (reloc_index - PLT_NUM_SINGLE_ENTRIES) / 2;
bfd_elf32_swap_reloca_out (output_bfd, &rela,
((Elf32_External_Rela *) srela->contents
- + ((h->plt.offset - PLT_INITIAL_ENTRY_SIZE) / 8)));
+ + reloc_index));
if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)
{
elf_section_data (sgot->output_section)->this_hdr.sh_entsize = 4;
}
- if (info->shared)
- {
- asection *sdynsym;
- asection *s;
- Elf_Internal_Sym sym;
- int maxdindx = 0;
-
- /* Set up the section symbols for the output sections. */
-
- sdynsym = bfd_get_section_by_name (dynobj, ".dynsym");
- BFD_ASSERT (sdynsym != NULL);
-
- sym.st_size = 0;
- sym.st_name = 0;
- sym.st_info = ELF_ST_INFO (STB_LOCAL, STT_SECTION);
- sym.st_other = 0;
-
- for (s = output_bfd->sections; s != NULL; s = s->next)
- {
- int indx, dindx;
-
- sym.st_value = s->vma;
-
- indx = elf_section_data (s)->this_idx;
- dindx = elf_section_data (s)->dynindx;
- if (dindx != -1)
- {
- BFD_ASSERT(indx > 0);
- BFD_ASSERT(dindx > 0);
-
- if (dindx > maxdindx)
- maxdindx = dindx;
-
- sym.st_shndx = indx;
-
- bfd_elf32_swap_symbol_out (output_bfd, &sym,
- (PTR) (((Elf32_External_Sym *)
- sdynsym->contents)
- + dindx));
- }
- }
-
- /* Set the sh_info field of the output .dynsym section to the
- index of the first global symbol. */
- elf_section_data (sdynsym->output_section)->this_hdr.sh_info =
- maxdindx + 1;
- }
-
return true;
}
{
sec = h->root.u.def.section;
if ((r_type == R_PPC_PLT32
+ && splt != NULL
&& h->plt.offset != (bfd_vma) -1)
|| (r_type == R_PPC_LOCAL24PC
&& sec->output_section == NULL)
&& ((! info->symbolic && h->dynindx != -1)
|| (h->elf_link_hash_flags
& ELF_LINK_HASH_DEF_REGULAR) == 0)
- && (input_section->flags & SEC_ALLOC) != 0
+ && ((input_section->flags & SEC_ALLOC) != 0
+ /* Testing SEC_DEBUGGING here may be wrong.
+ It's here to avoid a crash when
+ generating a shared library with DWARF
+ debugging information. */
+ || ((input_section->flags & SEC_DEBUGGING) != 0
+ && (h->elf_link_hash_flags
+ & ELF_LINK_HASH_DEF_DYNAMIC) != 0))
&& (r_type == R_PPC_ADDR32
|| r_type == R_PPC_ADDR24
|| r_type == R_PPC_ADDR16
obscure cases sec->output_section will be NULL. */
relocation = 0;
}
+ else if (sec->output_section == NULL)
+ {
+ (*_bfd_error_handler)
+ (_("%s: warning: unresolvable relocation against symbol `%s' from %s section"),
+ bfd_get_filename (input_bfd), h->root.root.string,
+ bfd_get_section_name (input_bfd, input_section));
+ relocation = 0;
+ }
else
relocation = (h->root.u.def.value
+ sec->output_section->vma
}
else if (h->root.type == bfd_link_hash_undefweak)
relocation = 0;
- else if (info->shared)
+ else if (info->shared && !info->symbolic
+ && !info->no_undefined
+ && ELF_ST_VISIBILITY (h->other) == STV_DEFAULT)
relocation = 0;
else
{
- (*info->callbacks->undefined_symbol)(info,
- h->root.root.string,
- input_bfd,
- input_section,
- rel->r_offset);
- ret = false;
- continue;
+ if (! (*info->callbacks->undefined_symbol)(info,
+ h->root.root.string,
+ input_bfd,
+ input_section,
+ rel->r_offset,
+ (!info->shared
+ || info->no_undefined
+ || ELF_ST_VISIBILITY (h->other))))
+ return false;
+ relocation = 0;
}
}
|| h->root.type == bfd_link_hash_defweak)
&& sec->output_section == NULL)
{
- (*info->callbacks->undefined_symbol) (info,
- h->root.root.string,
- input_bfd,
- input_section,
- rel->r_offset);
- ret = false;
+ if (! (*info->callbacks->undefined_symbol) (info,
+ h->root.root.string,
+ input_bfd,
+ input_section,
+ rel->r_offset,
+ true))
+ return false;
continue;
}
break;
relocation,
addend);
- if (r != bfd_reloc_ok)
+ if (r == bfd_reloc_ok)
+ ;
+ else if (r == bfd_reloc_overflow)
{
- ret = false;
- switch (r)
+ const char *name;
+
+ if (h != NULL)
{
- default:
- break;
+ if (h->root.type == bfd_link_hash_undefweak
+ && howto->pc_relative)
+ {
+ /* Assume this is a call protected by other code that
+ detect the symbol is undefined. If this is the case,
+ we can safely ignore the overflow. If not, the
+ program is hosed anyway, and a little warning isn't
+ going to help. */
- case bfd_reloc_overflow:
- {
- const char *name;
-
- if (h != NULL)
- name = h->root.root.string;
- else
- {
- name = bfd_elf_string_from_elf_section (input_bfd,
- symtab_hdr->sh_link,
- sym->st_name);
- if (name == NULL)
- break;
-
- if (*name == '\0')
- name = bfd_section_name (input_bfd, sec);
- }
-
- (*info->callbacks->reloc_overflow)(info,
+ continue;
+ }
+
+ name = h->root.root.string;
+ }
+ else
+ {
+ name = bfd_elf_string_from_elf_section (input_bfd,
+ symtab_hdr->sh_link,
+ sym->st_name);
+ if (name == NULL)
+ continue;
+ if (*name == '\0')
+ name = bfd_section_name (input_bfd, sec);
+ }
+
+ if (! (*info->callbacks->reloc_overflow)(info,
name,
howto->name,
(bfd_vma) 0,
input_bfd,
input_section,
- offset);
- }
- break;
-
- }
+ offset))
+ return false;
}
+ else
+ ret = false;
}
-
#ifdef DEBUG
fprintf (stderr, "\n");
#endif
#define bfd_elf32_bfd_copy_private_bfd_data ppc_elf_copy_private_bfd_data
#define bfd_elf32_bfd_merge_private_bfd_data ppc_elf_merge_private_bfd_data
-#define bfd_elf32_bfd_set_private_flags ppc_elf_set_private_flags
+#define bfd_elf32_bfd_relax_section ppc_elf_relax_section
#define bfd_elf32_bfd_reloc_type_lookup ppc_elf_reloc_type_lookup
+#define bfd_elf32_bfd_set_private_flags ppc_elf_set_private_flags
#define bfd_elf32_bfd_final_link _bfd_elf32_gc_common_final_link
#define elf_backend_gc_mark_hook ppc_elf_gc_mark_hook