/* PowerPC-specific support for 32-bit ELF
- Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
- Free Software Foundation, Inc.
+ Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
+ 2004 Free Software Foundation, Inc.
Written by Ian Lance Taylor, Cygnus Support.
This file is part of BFD, the Binary File Descriptor library.
#define DTP_OFFSET 0x8000
\f
+/* Enumeration to specify the special section. */
+enum elf_linker_section_enum
+{
+ LINKER_SECTION_SDATA,
+ LINKER_SECTION_SDATA2
+};
+
+/* Sections created by the linker. */
+
+typedef struct elf_linker_section
+{
+ /* pointer to the section */
+ asection *section;
+ /* pointer to the relocations needed for this section */
+ asection *rel_section;
+ /* pointer to the created symbol hash value */
+ struct elf_link_hash_entry *sym_hash;
+ /* offset of symbol from beginning of section */
+ bfd_vma sym_offset;
+} elf_linker_section_t;
+
+/* Linked list of allocated pointer entries. This hangs off of the
+ symbol lists, and provides allows us to return different pointers,
+ based on different addend's. */
+
+typedef struct elf_linker_section_pointers
+{
+ /* next allocated pointer for this symbol */
+ struct elf_linker_section_pointers *next;
+ /* offset of pointer from beginning of section */
+ bfd_vma offset;
+ /* addend used */
+ bfd_vma addend;
+ /* which linker section this is */
+ elf_linker_section_t *lsect;
+ /* whether address was written yet */
+ bfd_boolean written_address_p;
+} elf_linker_section_pointers_t;
+
+struct ppc_elf_obj_tdata
+{
+ struct elf_obj_tdata elf;
+
+ /* A mapping from local symbols to offsets into the various linker
+ sections added. This is index by the symbol index. */
+ elf_linker_section_pointers_t **linker_section_pointers;
+};
+
+#define ppc_elf_tdata(bfd) \
+ ((struct ppc_elf_obj_tdata *) (bfd)->tdata.any)
+
+#define elf_local_ptr_offsets(bfd) \
+ (ppc_elf_tdata (bfd)->linker_section_pointers)
+
+/* Override the generic function because we store some extras. */
+
+static bfd_boolean
+ppc_elf_mkobject (bfd *abfd)
+{
+ bfd_size_type amt = sizeof (struct ppc_elf_obj_tdata);
+ abfd->tdata.any = bfd_zalloc (abfd, amt);
+ if (abfd->tdata.any == NULL)
+ return FALSE;
+ return TRUE;
+}
+
/* The PPC linker needs to keep track of the number of relocs that it
decides to copy as dynamic relocs in check_relocs for each symbol.
This is so that it can later discard them if they are found to be
{
struct elf_link_hash_entry elf;
+ /* If this symbol is used in the linker created sections, the processor
+ specific backend uses this field to map the field into the offset
+ from the beginning of the section. */
+ elf_linker_section_pointers_t *linker_section_pointer;
+
/* Track dynamic relocs copied for this symbol. */
struct ppc_elf_dyn_relocs *dyn_relocs;
asection *relsbss;
elf_linker_section_t *sdata;
elf_linker_section_t *sdata2;
-
- /* Short-cut to first output tls section. */
- asection *tls_sec;
+ asection *sbss;
/* Shortcut to .__tls_get_addr. */
struct elf_link_hash_entry *tls_get_addr;
entry = _bfd_elf_link_hash_newfunc (entry, table, string);
if (entry != NULL)
{
+ ppc_elf_hash_entry (entry)->linker_section_pointer = NULL;
ppc_elf_hash_entry (entry)->dyn_relocs = NULL;
ppc_elf_hash_entry (entry)->tls_mask = 0;
}
{
struct ppc_elf_link_hash_table *ret;
- ret = bfd_malloc (sizeof (struct ppc_elf_link_hash_table));
+ ret = bfd_zmalloc (sizeof (struct ppc_elf_link_hash_table));
if (ret == NULL)
return NULL;
return NULL;
}
- ret->got = NULL;
- ret->relgot = NULL;
- ret->plt = NULL;
- ret->relplt = NULL;
- ret->dynbss = NULL;
- ret->relbss = NULL;
- ret->dynsbss = NULL;
- ret->relsbss = NULL;
- ret->sdata = NULL;
- ret->sdata2 = NULL;
- ret->tls_sec = NULL;
- ret->tls_get_addr = NULL;
- ret->tlsld_got.refcount = 0;
- ret->sym_sec.abfd = NULL;
-
return &ret->elf.root;
}
/* Copy the extra info we tack onto an elf_link_hash_entry. */
static void
-ppc_elf_copy_indirect_symbol (struct elf_backend_data *bed,
+ppc_elf_copy_indirect_symbol (const struct elf_backend_data *bed,
struct elf_link_hash_entry *dir,
struct elf_link_hash_entry *ind)
{
dir->elf_link_hash_flags |=
(ind->elf_link_hash_flags & (ELF_LINK_HASH_REF_DYNAMIC
| ELF_LINK_HASH_REF_REGULAR
- | ELF_LINK_HASH_REF_REGULAR_NONWEAK));
+ | ELF_LINK_HASH_REF_REGULAR_NONWEAK
+ | ELF_LINK_HASH_NEEDS_PLT));
else
_bfd_elf_link_hash_copy_indirect (bed, dir, ind);
}
0xffff, /* dst_mask */
FALSE), /* pcrel_offset */
+ /* Phony relocs to handle branch stubs. */
+ HOWTO (R_PPC_RELAX32, /* type */
+ 0, /* rightshift */
+ 0, /* size */
+ 0, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_PPC_RELAX32", /* name */
+ FALSE, /* partial_inplace */
+ 0, /* src_mask */
+ 0, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ HOWTO (R_PPC_RELAX32PC, /* type */
+ 0, /* rightshift */
+ 0, /* size */
+ 0, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_PPC_RELAX32PC", /* name */
+ FALSE, /* partial_inplace */
+ 0, /* src_mask */
+ 0, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
/* GNU extension to record C++ vtable hierarchy. */
HOWTO (R_PPC_GNU_VTINHERIT, /* type */
0, /* rightshift */
}
}
\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. */
+#define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0]))
-static int
-ppc_elf_sort_rela (const void *arg1, const void *arg2)
-{
- const Elf_Internal_Rela * const *rela1 = arg1;
- const Elf_Internal_Rela * const *rela2 = arg2;
+static const int shared_stub_entry[] =
+ {
+ 0x7c0802a6, /* mflr 0 */
+ 0x429f0005, /* bcl 20, 31, .Lxxx */
+ 0x7d6802a6, /* mflr 11 */
+ 0x3d6b0000, /* addis 11, 11, (xxx-.Lxxx)@ha */
+ 0x396b0018, /* addi 11, 11, (xxx-.Lxxx)@l */
+ 0x7c0803a6, /* mtlr 0 */
+ 0x7d6903a6, /* mtctr 11 */
+ 0x4e800420, /* bctr */
+ };
+
+static const int stub_entry[] =
+ {
+ 0x3d600000, /* lis 11,xxx@ha */
+ 0x396b0000, /* addi 11,11,xxx@l */
+ 0x7d6903a6, /* mtctr 11 */
+ 0x4e800420, /* bctr */
+ };
- /* Sort by offset. */
- return ((*rela1)->r_offset - (*rela2)->r_offset);
-}
static bfd_boolean
ppc_elf_relax_section (bfd *abfd,
struct bfd_link_info *link_info,
bfd_boolean *again)
{
-#define PAGESIZE 0x1000
+ struct one_fixup
+ {
+ struct one_fixup *next;
+ asection *tsec;
+ bfd_vma toff;
+ bfd_vma trampoff;
+ };
+ Elf_Internal_Shdr *symtab_hdr;
bfd_byte *contents = NULL;
- bfd_byte *free_contents = NULL;
+ Elf_Internal_Sym *isymbuf = NULL;
Elf_Internal_Rela *internal_relocs = NULL;
- Elf_Internal_Rela *free_relocs = NULL;
- Elf_Internal_Rela **rela_comb = NULL;
- int comb_curr, comb_count;
+ Elf_Internal_Rela *irel, *irelend;
+ struct one_fixup *fixups = NULL;
+ bfd_boolean changed;
+ struct ppc_elf_link_hash_table *ppc_info;
+ bfd_size_type trampoff;
- /* We never have to do this more than once per input section. */
*again = FALSE;
+ /* Nothing to do if there are no relocations. */
+ if ((isec->flags & SEC_RELOC) == 0 || isec->reloc_count == 0)
+ return TRUE;
+
/* 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)
+ trampoff = (isec->_cooked_size + 3) & (bfd_vma) -4;
+ /* Space for a branch around any trampolines. */
+ trampoff += 4;
+
+ symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
+
+ /* Get a copy of the native relocations. */
+ internal_relocs = _bfd_elf_link_read_relocs (abfd, isec, NULL, NULL,
+ link_info->keep_memory);
+ if (internal_relocs == NULL)
+ goto error_return;
+
+ ppc_info = ppc_elf_hash_table (link_info);
+ irelend = internal_relocs + isec->reloc_count;
+
+ /* 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
{
- bfd_vma dot, end_page, end_section;
- bfd_boolean section_modified;
+ /* Go get them off disk. */
+ contents = bfd_malloc (isec->_raw_size);
+ if (contents == NULL)
+ goto error_return;
- /* 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
+ if (!bfd_get_section_contents (abfd, isec, contents, 0, isec->_raw_size))
+ goto error_return;
+ }
+
+ for (irel = internal_relocs; irel < irelend; irel++)
+ {
+ unsigned long r_type = ELF32_R_TYPE (irel->r_info);
+ bfd_vma symaddr, reladdr, toff, roff;
+ asection *tsec;
+ struct one_fixup *f;
+ size_t insn_offset = 0;
+ bfd_vma max_branch_offset, val;
+ bfd_byte *hit_addr;
+ unsigned long t0;
+
+ switch (r_type)
{
- /* Go get them off disk. */
- contents = 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;
+ case R_PPC_REL24:
+ case R_PPC_LOCAL24PC:
+ case R_PPC_PLTREL24:
+ max_branch_offset = 1 << 25;
+ break;
+
+ case R_PPC_REL14:
+ case R_PPC_REL14_BRTAKEN:
+ case R_PPC_REL14_BRNTAKEN:
+ max_branch_offset = 1 << 15;
+ break;
+
+ default:
+ continue;
}
- comb_curr = 0;
- comb_count = 0;
- if (isec->reloc_count)
+ /* Get the value of the symbol referred to by the reloc. */
+ if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info)
{
- unsigned n;
- bfd_size_type amt;
-
- /* Get a copy of the native relocations. */
- internal_relocs
- = _bfd_elf_link_read_relocs (abfd, isec, NULL, 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. */
- amt = isec->reloc_count;
- amt *= sizeof (Elf_Internal_Rela*);
- rela_comb = bfd_malloc (amt);
- if (rela_comb == NULL)
- goto error_return;
- for (n = 0; n < isec->reloc_count; ++n)
- {
- enum elf_ppc_reloc_type r_type;
+ /* A local symbol. */
+ Elf_Internal_Sym *isym;
- r_type = ELF32_R_TYPE (internal_relocs[n].r_info);
- if (r_type >= R_PPC_max)
+ /* Read this BFD's local symbols. */
+ if (isymbuf == NULL)
+ {
+ 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 == 0)
goto error_return;
+ }
+ isym = isymbuf + ELF32_R_SYM (irel->r_info);
+ if (isym->st_shndx == SHN_UNDEF)
+ continue; /* We can't do anything with undefined symbols. */
+ else if (isym->st_shndx == SHN_ABS)
+ tsec = bfd_abs_section_ptr;
+ else if (isym->st_shndx == SHN_COMMON)
+ tsec = bfd_com_section_ptr;
+ else
+ tsec = bfd_section_from_elf_index (abfd, isym->st_shndx);
- /* 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:
- case R_PPC_REL14:
- case R_PPC_REL14_BRNTAKEN:
- /* We should check the instruction. */
- break;
- default:
- /* The word is not a conditional branch - ignore it. */
- rela_comb[comb_count++] = &internal_relocs[n];
- break;
- }
+ toff = isym->st_value;
+ }
+ else
+ {
+ /* Global symbol handling. */
+ unsigned long indx;
+ struct elf_link_hash_entry *h;
+
+ indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info;
+ h = elf_sym_hashes (abfd)[indx];
+
+ while (h->root.type == bfd_link_hash_indirect
+ || h->root.type == bfd_link_hash_warning)
+ h = (struct elf_link_hash_entry *) h->root.u.i.link;
+
+ if (r_type == R_PPC_PLTREL24
+ && ppc_info->plt != NULL
+ && h->plt.offset != (bfd_vma) -1)
+ {
+ tsec = ppc_info->plt;
+ toff = h->plt.offset;
+ }
+ else if (h->root.type == bfd_link_hash_defined
+ || h->root.type == bfd_link_hash_defweak)
+ {
+ tsec = h->root.u.def.section;
+ toff = h->root.u.def.value;
}
- if (comb_count > 1)
- qsort (rela_comb, (size_t) comb_count, sizeof (int),
- ppc_elf_sort_rela);
+ else
+ continue;
}
- /* 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;
- /* Increment the start position if this section begins in the
- middle of its first EOP region. */
- if (dot < isec->vma)
- dot = isec->vma;
- for (;
- dot < end_section;
- dot += PAGESIZE, end_page += PAGESIZE)
+ /* If the branch and target are in the same section, you have
+ no hope of adding stubs. We'll error out later should the
+ branch overflow. */
+ if (tsec == isec)
+ continue;
+
+ toff += irel->r_addend;
+ if (tsec->sec_info_type == ELF_INFO_TYPE_MERGE)
+ toff = _bfd_merged_section_offset (abfd, &tsec,
+ elf_section_data (tsec)->sec_info,
+ toff, 0);
+
+ symaddr = tsec->output_section->vma + tsec->output_offset + toff;
+
+ roff = irel->r_offset;
+ reladdr = isec->output_section->vma + isec->output_offset + roff;
+
+ /* If the branch is in range, no need to do anything. */
+ if (symaddr - reladdr + max_branch_offset < 2 * max_branch_offset)
+ continue;
+
+ /* Look for an existing fixup to this address. */
+ for (f = fixups; f ; f = f->next)
+ if (f->tsec == tsec && f->toff == toff)
+ break;
+
+ if (f == NULL)
{
- /* Check each word in this EOP region. */
- for (; dot < end_page; dot += 4)
- {
- bfd_vma isec_offset;
- unsigned long insn;
- bfd_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;
+ size_t size;
+ unsigned long stub_rtype;
- 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;
- target = (target ^ 0x8000) - 0x8000;
- if ((insn & 0x00000002) == 0)
- /* Convert to abs. */
- target += dot;
- if (target > dot)
- {
- /* Set the prediction bit. */
- insn |= 0x00200000;
- 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;
- 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;
- modified = TRUE;
- }
- }
-#undef BO0
-#undef BO2
-#undef BO4
- if (modified)
- {
- bfd_put_32 (abfd, insn, contents + isec_offset);
- section_modified = TRUE;
- }
+ val = trampoff - roff;
+ if (val >= max_branch_offset)
+ /* Oh dear, we can't reach a trampoline. Don't try to add
+ one. We'll report an error later. */
+ continue;
+
+ if (link_info->shared)
+ {
+ size = 4 * ARRAY_SIZE (shared_stub_entry);
+ insn_offset = 12;
+ stub_rtype = R_PPC_RELAX32PC;
+ }
+ else
+ {
+ size = 4 * ARRAY_SIZE (stub_entry);
+ insn_offset = 0;
+ stub_rtype = R_PPC_RELAX32;
}
+
+ /* Hijack the old relocation. Since we need two
+ relocations for this use a "composite" reloc. */
+ irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
+ stub_rtype);
+ irel->r_offset = trampoff + insn_offset;
+
+ /* Record the fixup so we don't do it again this section. */
+ f = bfd_malloc (sizeof (*f));
+ f->next = fixups;
+ f->tsec = tsec;
+ f->toff = toff;
+ f->trampoff = trampoff;
+ fixups = f;
+
+ trampoff += size;
}
- if (section_modified)
+ else
{
- elf_section_data (isec)->this_hdr.contents = contents;
- free_contents = NULL;
+ val = f->trampoff - roff;
+ if (val >= max_branch_offset)
+ continue;
+
+ /* Nop out the reloc, since we're finalizing things here. */
+ irel->r_info = ELF32_R_INFO (0, R_PPC_NONE);
+ }
+
+ /* Fix up the existing branch to hit the trampoline. */
+ hit_addr = contents + roff;
+ switch (r_type)
+ {
+ case R_PPC_REL24:
+ case R_PPC_LOCAL24PC:
+ case R_PPC_PLTREL24:
+ t0 = bfd_get_32 (abfd, hit_addr);
+ t0 &= ~0x3fffffc;
+ t0 |= val & 0x3fffffc;
+ bfd_put_32 (abfd, t0, hit_addr);
+ break;
+
+ case R_PPC_REL14:
+ case R_PPC_REL14_BRTAKEN:
+ case R_PPC_REL14_BRNTAKEN:
+ t0 = bfd_get_32 (abfd, hit_addr);
+ t0 &= ~0xfffc;
+ t0 |= val & 0xfffc;
+ bfd_put_32 (abfd, t0, hit_addr);
+ break;
}
}
- if (rela_comb != NULL)
+ /* Write out the trampolines. */
+ changed = fixups != NULL;
+ if (fixups != NULL)
{
- free (rela_comb);
- rela_comb = NULL;
+ const int *stub;
+ bfd_byte *dest;
+ bfd_vma val;
+ int i, size;
+
+ do
+ {
+ struct one_fixup *f = fixups;
+ fixups = fixups->next;
+ free (f);
+ }
+ while (fixups);
+
+ contents = bfd_realloc (contents, trampoff);
+ if (contents == NULL)
+ goto error_return;
+
+ isec->_cooked_size = (isec->_cooked_size + 3) & (bfd_vma) -4;
+ /* Branch around the trampolines. */
+ val = trampoff - isec->_cooked_size + 0x48000000;
+ dest = contents + isec->_cooked_size;
+ isec->_cooked_size = trampoff;
+ bfd_put_32 (abfd, val, dest);
+ dest += 4;
+
+ if (link_info->shared)
+ {
+ stub = shared_stub_entry;
+ size = ARRAY_SIZE (shared_stub_entry);
+ }
+ else
+ {
+ stub = stub_entry;
+ size = ARRAY_SIZE (stub_entry);
+ }
+
+ i = 0;
+ while (dest < contents + trampoff)
+ {
+ bfd_put_32 (abfd, stub[i], dest);
+ i++;
+ if (i == size)
+ i = 0;
+ dest += 4;
+ }
+ BFD_ASSERT (i == 0);
}
- if (free_relocs != NULL)
+ if (isymbuf != NULL
+ && symtab_hdr->contents != (unsigned char *) isymbuf)
{
- free (free_relocs);
- free_relocs = NULL;
+ if (! link_info->keep_memory)
+ free (isymbuf);
+ else
+ {
+ /* Cache the symbols for elf_link_input_bfd. */
+ symtab_hdr->contents = (unsigned char *) isymbuf;
+ }
}
- if (free_contents != NULL)
+ if (contents != NULL
+ && elf_section_data (isec)->this_hdr.contents != contents)
{
- if (! link_info->keep_memory)
- free (free_contents);
+ if (!changed && !link_info->keep_memory)
+ free (contents);
else
{
/* Cache the section contents for elf_link_input_bfd. */
elf_section_data (isec)->this_hdr.contents = contents;
}
- free_contents = NULL;
}
+ if (elf_section_data (isec)->relocs != internal_relocs)
+ {
+ if (!changed)
+ free (internal_relocs);
+ else
+ elf_section_data (isec)->relocs = internal_relocs;
+ }
+
+ *again = changed;
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);
+ if (isymbuf != NULL && (unsigned char *) isymbuf != symtab_hdr->contents)
+ free (isymbuf);
+ if (contents != NULL
+ && elf_section_data (isec)->this_hdr.contents != contents)
+ free (contents);
+ if (internal_relocs != NULL
+ && elf_section_data (isec)->relocs != internal_relocs)
+ free (internal_relocs);
return FALSE;
}
\f
return TRUE;
}
\f
+/* Find a linker generated pointer with a given addend and type. */
+
+static elf_linker_section_pointers_t *
+elf_find_pointer_linker_section
+ (elf_linker_section_pointers_t *linker_pointers,
+ bfd_vma addend,
+ elf_linker_section_t *lsect)
+{
+ for ( ; linker_pointers != NULL; linker_pointers = linker_pointers->next)
+ if (lsect == linker_pointers->lsect && addend == linker_pointers->addend)
+ return linker_pointers;
+
+ return NULL;
+}
+\f
+/* Allocate a pointer to live in a linker created section. */
+
+static bfd_boolean
+elf_create_pointer_linker_section (bfd *abfd,
+ struct bfd_link_info *info,
+ elf_linker_section_t *lsect,
+ struct elf_link_hash_entry *h,
+ const Elf_Internal_Rela *rel)
+{
+ elf_linker_section_pointers_t **ptr_linker_section_ptr = NULL;
+ elf_linker_section_pointers_t *linker_section_ptr;
+ unsigned long r_symndx = ELF32_R_SYM (rel->r_info);
+ bfd_size_type amt;
+
+ BFD_ASSERT (lsect != NULL);
+
+ /* Is this a global symbol? */
+ if (h != NULL)
+ {
+ struct ppc_elf_link_hash_entry *eh;
+
+ /* Has this symbol already been allocated? If so, our work is done. */
+ eh = (struct ppc_elf_link_hash_entry *) h;
+ if (elf_find_pointer_linker_section (eh->linker_section_pointer,
+ rel->r_addend,
+ lsect))
+ return TRUE;
+
+ ptr_linker_section_ptr = &eh->linker_section_pointer;
+ /* Make sure this symbol is output as a dynamic symbol. */
+ if (h->dynindx == -1)
+ {
+ if (! bfd_elf_link_record_dynamic_symbol (info, h))
+ return FALSE;
+ }
+
+ if (lsect->rel_section)
+ lsect->rel_section->_raw_size += sizeof (Elf32_External_Rela);
+ }
+ else
+ {
+ /* Allocation of a pointer to a local symbol. */
+ elf_linker_section_pointers_t **ptr = elf_local_ptr_offsets (abfd);
+
+ /* Allocate a table to hold the local symbols if first time. */
+ if (!ptr)
+ {
+ unsigned int num_symbols = elf_tdata (abfd)->symtab_hdr.sh_info;
+
+ amt = num_symbols;
+ amt *= sizeof (elf_linker_section_pointers_t *);
+ ptr = bfd_zalloc (abfd, amt);
+
+ if (!ptr)
+ return FALSE;
+
+ elf_local_ptr_offsets (abfd) = ptr;
+ }
+
+ /* Has this symbol already been allocated? If so, our work is done. */
+ if (elf_find_pointer_linker_section (ptr[r_symndx],
+ rel->r_addend,
+ lsect))
+ return TRUE;
+
+ ptr_linker_section_ptr = &ptr[r_symndx];
+
+ if (info->shared)
+ {
+ /* If we are generating a shared object, we need to
+ output a R_<xxx>_RELATIVE reloc so that the
+ dynamic linker can adjust this GOT entry. */
+ BFD_ASSERT (lsect->rel_section != NULL);
+ lsect->rel_section->_raw_size += sizeof (Elf32_External_Rela);
+ }
+ }
+
+ /* Allocate space for a pointer in the linker section, and allocate
+ a new pointer record from internal memory. */
+ BFD_ASSERT (ptr_linker_section_ptr != NULL);
+ amt = sizeof (elf_linker_section_pointers_t);
+ linker_section_ptr = bfd_alloc (abfd, amt);
+
+ if (!linker_section_ptr)
+ return FALSE;
+
+ linker_section_ptr->next = *ptr_linker_section_ptr;
+ linker_section_ptr->addend = rel->r_addend;
+ linker_section_ptr->lsect = lsect;
+ linker_section_ptr->written_address_p = FALSE;
+ *ptr_linker_section_ptr = linker_section_ptr;
+
+ linker_section_ptr->offset = lsect->section->_raw_size;
+ lsect->section->_raw_size += 4;
+
+#ifdef DEBUG
+ fprintf (stderr,
+ "Create pointer in linker section %s, offset = %ld, section size = %ld\n",
+ lsect->name, (long) linker_section_ptr->offset,
+ (long) lsect->section->_raw_size);
+#endif
+
+ return TRUE;
+}
+\f
+#define bfd_put_ptr(BFD, VAL, ADDR) bfd_put_32 (BFD, VAL, ADDR)
+
+/* Fill in the address for a pointer generated in a linker section. */
+
+static bfd_vma
+elf_finish_pointer_linker_section (bfd *output_bfd,
+ bfd *input_bfd,
+ struct bfd_link_info *info,
+ elf_linker_section_t *lsect,
+ struct elf_link_hash_entry *h,
+ bfd_vma relocation,
+ const Elf_Internal_Rela *rel,
+ int relative_reloc)
+{
+ elf_linker_section_pointers_t *linker_section_ptr;
+
+ BFD_ASSERT (lsect != NULL);
+
+ if (h != NULL)
+ {
+ /* Handle global symbol. */
+ struct ppc_elf_link_hash_entry *eh;
+
+ eh = (struct ppc_elf_link_hash_entry *) h;
+ linker_section_ptr
+ = elf_find_pointer_linker_section (eh->linker_section_pointer,
+ rel->r_addend,
+ lsect);
+
+ BFD_ASSERT (linker_section_ptr != NULL);
+
+ if (! elf_hash_table (info)->dynamic_sections_created
+ || (info->shared
+ && info->symbolic
+ && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR)))
+ {
+ /* This is actually a static link, or it is a
+ -Bsymbolic link and the symbol is defined
+ locally. We must initialize this entry in the
+ global section.
+
+ When doing a dynamic link, we create a .rela.<xxx>
+ relocation entry to initialize the value. This
+ is done in the finish_dynamic_symbol routine. */
+ if (!linker_section_ptr->written_address_p)
+ {
+ linker_section_ptr->written_address_p = TRUE;
+ bfd_put_ptr (output_bfd,
+ relocation + linker_section_ptr->addend,
+ (lsect->section->contents
+ + linker_section_ptr->offset));
+ }
+ }
+ }
+ else
+ {
+ /* Handle local symbol. */
+ unsigned long r_symndx = ELF32_R_SYM (rel->r_info);
+ BFD_ASSERT (elf_local_ptr_offsets (input_bfd) != NULL);
+ BFD_ASSERT (elf_local_ptr_offsets (input_bfd)[r_symndx] != NULL);
+ linker_section_ptr = (elf_find_pointer_linker_section
+ (elf_local_ptr_offsets (input_bfd)[r_symndx],
+ rel->r_addend,
+ lsect));
+
+ BFD_ASSERT (linker_section_ptr != NULL);
+
+ /* Write out pointer if it hasn't been rewritten out before. */
+ if (!linker_section_ptr->written_address_p)
+ {
+ linker_section_ptr->written_address_p = TRUE;
+ bfd_put_ptr (output_bfd, relocation + linker_section_ptr->addend,
+ lsect->section->contents + linker_section_ptr->offset);
+
+ if (info->shared)
+ {
+ /* We need to generate a relative reloc for the dynamic
+ linker. */
+
+ asection *srel = lsect->rel_section;
+ Elf_Internal_Rela outrel[MAX_INT_RELS_PER_EXT_REL];
+ bfd_byte *erel;
+ const struct elf_backend_data *bed;
+ unsigned int i;
+
+ BFD_ASSERT (srel != NULL);
+
+ bed = get_elf_backend_data (output_bfd);
+ for (i = 0; i < bed->s->int_rels_per_ext_rel; i++)
+ {
+ outrel[i].r_offset = (lsect->section->output_section->vma
+ + lsect->section->output_offset
+ + linker_section_ptr->offset);
+ outrel[i].r_info = 0;
+ outrel[i].r_addend = 0;
+ }
+ outrel[0].r_info = ELF32_R_INFO (0, relative_reloc);
+ erel = lsect->section->contents;
+ erel += (elf_section_data (lsect->section)->rel_count++
+ * sizeof (Elf32_External_Rela));
+ bfd_elf32_swap_reloca_out (output_bfd, outrel, erel);
+ }
+ }
+ }
+
+ relocation = (lsect->section->output_offset
+ + linker_section_ptr->offset
+ - lsect->sym_offset);
+
+#ifdef DEBUG
+ fprintf (stderr,
+ "Finish pointer in linker section %s, offset = %ld (0x%lx)\n",
+ lsect->name, (long) relocation, (long) relocation);
+#endif
+
+ /* Subtract out the addend, because it will get added back in by the normal
+ processing. */
+ return relocation - linker_section_ptr->addend;
+}
+\f
/* Create a special linker section */
static elf_linker_section_t *
ppc_elf_create_linker_section (bfd *abfd,
struct bfd_link_info *info,
enum elf_linker_section_enum which)
{
- bfd *dynobj = elf_hash_table (info)->dynobj;
elf_linker_section_t *lsect;
+ struct ppc_elf_link_hash_table *htab = ppc_elf_hash_table (info);
+ asection *s;
+ bfd_size_type amt;
+ flagword flags;
+ const char *name;
+ const char *rel_name;
+ const char *sym_name;
+ bfd_vma sym_offset;
+
+ /* Both of these sections are (technically) created by the user
+ putting data in them, so they shouldn't be marked
+ SEC_LINKER_CREATED.
+
+ The linker creates them so it has somewhere to attach their
+ respective symbols. In fact, if they were empty it would
+ be OK to leave the symbol set to 0 (or any random number), because
+ the appropriate register should never be used. */
+ flags = SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY;
+ sym_offset = 32768;
+
+ switch (which)
+ {
+ default:
+ abort ();
+ return NULL;
+
+ case LINKER_SECTION_SDATA: /* .sdata/.sbss section */
+ name = ".sdata";
+ rel_name = ".rela.sdata";
+ sym_name = "_SDA_BASE_";
+ break;
- /* Record the first bfd section that needs the special section. */
- if (!dynobj)
- dynobj = elf_hash_table (info)->dynobj = abfd;
+ case LINKER_SECTION_SDATA2: /* .sdata2/.sbss2 section */
+ name = ".sdata2";
+ rel_name = ".rela.sdata2";
+ sym_name = "_SDA2_BASE_";
+ flags |= SEC_READONLY;
+ break;
+ }
- /* If this is the first time, create the section. */
- lsect = elf_linker_section (dynobj, which);
- if (!lsect)
+ /* Record the first bfd that needs the special sections. */
+ if (!htab->elf.dynobj)
+ htab->elf.dynobj = abfd;
+
+ amt = sizeof (elf_linker_section_t);
+ lsect = bfd_zalloc (htab->elf.dynobj, amt);
+
+ lsect->sym_offset = sym_offset;
+
+ /* See if the sections already exist. */
+ s = bfd_get_section_by_name (htab->elf.dynobj, name);
+ if (s == NULL || (s->flags & flags) != flags)
{
- elf_linker_section_t defaults;
- static elf_linker_section_t zero_section;
-
- defaults = zero_section;
- defaults.which = which;
- defaults.hole_written_p = FALSE;
- defaults.alignment = 2;
-
- /* Both of these sections are (technically) created by the user
- putting data in them, so they shouldn't be marked
- SEC_LINKER_CREATED.
-
- The linker creates them so it has somewhere to attach their
- respective symbols. In fact, if they were empty it would
- be OK to leave the symbol set to 0 (or any random number), because
- the appropriate register should never be used. */
- defaults.flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS
- | SEC_IN_MEMORY);
-
- switch (which)
- {
- default:
- (*_bfd_error_handler) (_("%s: unknown special linker type %d"),
- bfd_get_filename (abfd),
- (int) which);
+ s = bfd_make_section_anyway (htab->elf.dynobj, name);
+ if (s == NULL
+ || !bfd_set_section_flags (htab->elf.dynobj, s, flags))
+ return NULL;
+ }
+ lsect->section = s;
- bfd_set_error (bfd_error_bad_value);
- return NULL;
-
- case LINKER_SECTION_SDATA: /* .sdata/.sbss section */
- defaults.name = ".sdata";
- defaults.rel_name = ".rela.sdata";
- defaults.bss_name = ".sbss";
- defaults.sym_name = "_SDA_BASE_";
- defaults.sym_offset = 32768;
- break;
+ if (bfd_get_section_alignment (htab->elf.dynobj, s) < 2
+ && !bfd_set_section_alignment (htab->elf.dynobj, s, 2))
+ return NULL;
- case LINKER_SECTION_SDATA2: /* .sdata2/.sbss2 section */
- defaults.name = ".sdata2";
- defaults.rel_name = ".rela.sdata2";
- defaults.bss_name = ".sbss2";
- defaults.sym_name = "_SDA2_BASE_";
- defaults.sym_offset = 32768;
- defaults.flags |= SEC_READONLY;
- break;
- }
+ s->_raw_size = align_power (s->_raw_size, 2);
- lsect = _bfd_elf_create_linker_section (abfd, info, which, &defaults);
+#ifdef DEBUG
+ fprintf (stderr, "Creating section %s, current size = %ld\n",
+ name, (long) s->_raw_size);
+#endif
+
+ if (sym_name)
+ {
+ struct elf_link_hash_entry *h;
+ struct bfd_link_hash_entry *bh;
+
+#ifdef DEBUG
+ fprintf (stderr, "Adding %s to section %s\n", sym_name, name);
+#endif
+ bh = bfd_link_hash_lookup (info->hash, sym_name,
+ FALSE, FALSE, FALSE);
+
+ if ((bh == NULL || bh->type == bfd_link_hash_undefined)
+ && !(_bfd_generic_link_add_one_symbol
+ (info, abfd, sym_name, BSF_GLOBAL, s, sym_offset, NULL,
+ FALSE, get_elf_backend_data (abfd)->collect, &bh)))
+ return NULL;
+ h = (struct elf_link_hash_entry *) bh;
+
+ h->type = STT_OBJECT;
+ lsect->sym_hash = h;
+
+ if (info->shared
+ && ! bfd_elf_link_record_dynamic_symbol (info, h))
+ return NULL;
+ }
+
+ if (info->shared)
+ {
+ s = bfd_make_section_anyway (htab->elf.dynobj, rel_name);
+ lsect->rel_section = s;
+ flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
+ | SEC_LINKER_CREATED | SEC_READONLY);
+ if (s == NULL
+ || ! bfd_set_section_flags (htab->elf.dynobj, s, flags)
+ || ! bfd_set_section_alignment (htab->elf.dynobj, s, 2))
+ return NULL;
}
return lsect;
/* Modify the segment map if needed. */
static bfd_boolean
-ppc_elf_modify_segment_map (bfd *abfd ATTRIBUTE_UNUSED)
+ppc_elf_modify_segment_map (bfd *abfd ATTRIBUTE_UNUSED,
+ struct bfd_link_info *info ATTRIBUTE_UNUSED)
{
return TRUE;
}
asection *s;
flagword flags;
- if (!ppc_elf_create_got (abfd, info))
+ htab = ppc_elf_hash_table (info);
+
+ if (htab->got == NULL
+ && !ppc_elf_create_got (abfd, info))
return FALSE;
if (!_bfd_elf_create_dynamic_sections (abfd, info))
flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
| SEC_LINKER_CREATED);
- htab = ppc_elf_hash_table (info);
htab->dynbss = bfd_get_section_by_name (abfd, ".dynbss");
htab->dynsbss = s = bfd_make_section (abfd, ".dynsbss");
if (s == NULL
return TRUE;
}
\f
-/* This is the condition under which finish_dynamic_symbol will be
- called from elflink.h. If elflink.h doesn't call our
- finish_dynamic_symbol routine, we'll need to do something about
- initializing any .plt and .got entries in relocate_section. */
-#define WILL_CALL_FINISH_DYNAMIC_SYMBOL(DYN, SHARED, H) \
- ((DYN) \
- && ((SHARED) \
- || ((H)->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0) \
- && ((H)->dynindx != -1 \
- || ((H)->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) != 0))
-
/* Of those relocs that might be copied as dynamic relocs, this macro
selects those that must be copied when linking a shared library,
even when the symbol is local. */
if (h->dynindx == -1
&& (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0)
{
- if (! bfd_elf32_link_record_dynamic_symbol (info, h))
+ if (! bfd_elf_link_record_dynamic_symbol (info, h))
return FALSE;
}
if (eh->elf.dynindx == -1
&& (eh->elf.elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0)
{
- if (!bfd_elf32_link_record_dynamic_symbol (info, &eh->elf))
+ if (!bfd_elf_link_record_dynamic_symbol (info, &eh->elf))
return FALSE;
}
if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
&& h->root.type == bfd_link_hash_undefweak)
eh->dyn_relocs = NULL;
+
+ /* Make sure undefined weak symbols are output as a dynamic symbol
+ in PIEs. */
+ if (info->pie
+ && eh->dyn_relocs != NULL
+ && h->dynindx == -1
+ && h->root.type == bfd_link_hash_undefweak
+ && (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0)
+ {
+ if (! bfd_elf_link_record_dynamic_symbol (info, h))
+ return FALSE;
+ }
}
else if (ELIMINATE_COPY_RELOCS)
{
if (h->dynindx == -1
&& (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0)
{
- if (! bfd_elf64_link_record_dynamic_symbol (info, h))
+ if (! bfd_elf_link_record_dynamic_symbol (info, h))
return FALSE;
}
the .dynamic section. The DT_DEBUG entry is filled in by the
dynamic linker and used by the debugger. */
#define add_dynamic_entry(TAG, VAL) \
- bfd_elf32_add_dynamic_entry (info, (TAG), (VAL))
+ _bfd_elf_add_dynamic_entry (info, TAG, VAL)
if (info->executable)
{
htab = ppc_elf_hash_table (info);
if (htab->sdata == NULL)
{
- htab->sdata = elf_linker_section (abfd, LINKER_SECTION_SDATA);
- if (htab->sdata == NULL)
- htab->sdata = ppc_elf_create_linker_section (abfd, info,
- LINKER_SECTION_SDATA);
+ htab->sdata = ppc_elf_create_linker_section (abfd, info,
+ LINKER_SECTION_SDATA);
if (htab->sdata == NULL)
return FALSE;
}
if (htab->sdata2 == NULL)
{
- htab->sdata2 = elf_linker_section (abfd, LINKER_SECTION_SDATA2);
- if (htab->sdata2 == NULL)
- htab->sdata2 = ppc_elf_create_linker_section (abfd, info,
- LINKER_SECTION_SDATA2);
+ htab->sdata2 = ppc_elf_create_linker_section (abfd, info,
+ LINKER_SECTION_SDATA2);
if (htab->sdata2 == NULL)
return FALSE;
}
bad_shared_reloc (abfd, r_type);
return FALSE;
}
- if (!bfd_elf32_create_pointer_linker_section (abfd, info,
- htab->sdata, h, rel))
+ if (!elf_create_pointer_linker_section (abfd, info,
+ htab->sdata, h, rel))
return FALSE;
break;
bad_shared_reloc (abfd, r_type);
return FALSE;
}
- if (!bfd_elf32_create_pointer_linker_section (abfd, info,
- htab->sdata2, h, rel))
+ if (!elf_create_pointer_linker_section (abfd, info,
+ htab->sdata2, h, rel))
return FALSE;
break;
/* This relocation describes the C++ object vtable hierarchy.
Reconstruct it for later use during GC. */
case R_PPC_GNU_VTINHERIT:
- if (!_bfd_elf32_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
+ if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
return FALSE;
break;
/* This relocation describes which C++ vtable entries are actually
used. Record for later use during GC. */
case R_PPC_GNU_VTENTRY:
- if (!_bfd_elf32_gc_record_vtentry (abfd, sec, h, rel->r_addend))
+ if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend))
return FALSE;
break;
return TRUE;
}
-/* Set htab->tls_sec and htab->tls_get_addr. */
+/* Set htab->tls_get_addr and call the generic ELF tls_setup function. */
-bfd_boolean
+asection *
ppc_elf_tls_setup (bfd *obfd, struct bfd_link_info *info)
{
- asection *tls;
struct ppc_elf_link_hash_table *htab;
htab = ppc_elf_hash_table (info);
htab->tls_get_addr = elf_link_hash_lookup (&htab->elf, "__tls_get_addr",
FALSE, FALSE, TRUE);
- for (tls = obfd->sections; tls != NULL; tls = tls->next)
- if ((tls->flags & (SEC_THREAD_LOCAL | SEC_LOAD))
- == (SEC_THREAD_LOCAL | SEC_LOAD))
- break;
- htab->tls_sec = tls;
-
- return tls != NULL;
+ return _bfd_elf_tls_setup (obfd, info);
}
/* Run through all the TLS relocs looking for optimization
static bfd_boolean
ppc_elf_add_symbol_hook (bfd *abfd,
struct bfd_link_info *info,
- const Elf_Internal_Sym *sym,
+ Elf_Internal_Sym *sym,
const char **namep ATTRIBUTE_UNUSED,
flagword *flagsp ATTRIBUTE_UNUSED,
asection **secp,
if (sym->st_shndx == SHN_COMMON
&& !info->relocatable
&& sym->st_size <= elf_gp_size (abfd)
- && info->hash->creator->flavour == bfd_target_elf_flavour)
+ && (info->hash->creator == abfd->xvec
+ || info->hash->creator == abfd->xvec->alternative_target))
{
/* Common symbols less than or equal to -G nn bytes are automatically
- put into .sdata. */
- elf_linker_section_t *sdata
- = ppc_elf_create_linker_section (abfd, info, LINKER_SECTION_SDATA);
+ put into .sbss. */
+ struct ppc_elf_link_hash_table *htab;
- if (!sdata->bss_section)
+ htab = ppc_elf_hash_table (info);
+ if (htab->sbss == NULL)
{
- bfd_size_type amt;
-
- /* We don't go through bfd_make_section, because we don't
- want to attach this common section to DYNOBJ. The linker
- will move the symbols to the appropriate output section
- when it defines common symbols. */
- amt = sizeof (asection);
- sdata->bss_section = bfd_zalloc (abfd, amt);
- if (sdata->bss_section == NULL)
- return FALSE;
- sdata->bss_section->name = sdata->bss_name;
- sdata->bss_section->flags = SEC_IS_COMMON;
- sdata->bss_section->output_section = sdata->bss_section;
- amt = sizeof (asymbol);
- sdata->bss_section->symbol = bfd_zalloc (abfd, amt);
- amt = sizeof (asymbol *);
- sdata->bss_section->symbol_ptr_ptr = bfd_zalloc (abfd, amt);
- if (sdata->bss_section->symbol == NULL
- || sdata->bss_section->symbol_ptr_ptr == NULL)
+ flagword flags = SEC_IS_COMMON;
+
+ htab->sbss = bfd_make_section_anyway (abfd, ".sbss");
+ if (htab->sbss == NULL
+ || ! bfd_set_section_flags (abfd, htab->sbss, flags))
return FALSE;
- sdata->bss_section->symbol->name = sdata->bss_name;
- sdata->bss_section->symbol->flags = BSF_SECTION_SYM;
- sdata->bss_section->symbol->section = sdata->bss_section;
- *sdata->bss_section->symbol_ptr_ptr = sdata->bss_section->symbol;
}
- *secp = sdata->bss_section;
+ *secp = htab->sbss;
*valp = sym->st_size;
}
unresolved_reloc = FALSE;
warned = FALSE;
r_symndx = ELF32_R_SYM (rel->r_info);
+
if (r_symndx < symtab_hdr->sh_info)
{
sym = local_syms + r_symndx;
sec = local_sections[r_symndx];
sym_name = bfd_elf_local_sym_name (input_bfd, sym);
- relocation = _bfd_elf_rela_local_sym (output_bfd, sym, sec, rel);
+ relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
}
else
{
- h = sym_hashes[r_symndx - symtab_hdr->sh_info];
- while (h->root.type == bfd_link_hash_indirect
- || h->root.type == bfd_link_hash_warning)
- h = (struct elf_link_hash_entry *) h->root.u.i.link;
- sym_name = h->root.root.string;
+ RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
+ r_symndx, symtab_hdr, sym_hashes,
+ h, sec, relocation,
+ unresolved_reloc, warned);
- relocation = 0;
- if (h->root.type == bfd_link_hash_defined
- || h->root.type == bfd_link_hash_defweak)
- {
- sec = h->root.u.def.section;
- /* Set a flag that will be cleared later if we find a
- relocation value for this symbol. output_section
- is typically NULL for symbols satisfied by a shared
- library. */
- if (sec->output_section == NULL)
- unresolved_reloc = TRUE;
- else
- relocation = (h->root.u.def.value
- + sec->output_section->vma
- + sec->output_offset);
- }
- else if (h->root.type == bfd_link_hash_undefweak)
- ;
- else if (info->shared
- && !info->no_undefined
- && ELF_ST_VISIBILITY (h->other) == STV_DEFAULT)
- ;
- else
- {
- 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;
- warned = TRUE;
- }
+ sym_name = h->root.root.string;
}
/* TLS optimizations. Replace instruction sequences and relocs
{
/* Was an LD reloc. */
r_symndx = 0;
- rel->r_addend = htab->tls_sec->vma + DTP_OFFSET;
- rel[1].r_addend = htab->tls_sec->vma + DTP_OFFSET;
+ rel->r_addend = htab->elf.tls_sec->vma + DTP_OFFSET;
+ rel[1].r_addend = htab->elf.tls_sec->vma + DTP_OFFSET;
}
r_type = R_PPC_TPREL16_HA;
rel->r_info = ELF32_R_INFO (r_symndx, r_type);
branch_bit = BRANCH_PREDICT_BIT;
/* Fall thru */
- /* Branch not taken predicition relocations. */
+ /* Branch not taken prediction relocations. */
case R_PPC_ADDR14_BRNTAKEN:
case R_PPC_REL14_BRNTAKEN:
insn = bfd_get_32 (output_bfd, contents + rel->r_offset);
{
outrel.r_addend += relocation;
if (tls_ty & (TLS_GD | TLS_DTPREL | TLS_TPREL))
- outrel.r_addend -= htab->tls_sec->vma;
+ outrel.r_addend -= htab->elf.tls_sec->vma;
}
loc = htab->relgot->contents;
loc += (htab->relgot->reloc_count++
value = 1;
else if (tls_ty != 0)
{
- value -= htab->tls_sec->vma + DTP_OFFSET;
+ value -= htab->elf.tls_sec->vma + DTP_OFFSET;
if (tls_ty == (TLS_TLS | TLS_TPREL))
value += DTP_OFFSET - TP_OFFSET;
case R_PPC_DTPREL16_LO:
case R_PPC_DTPREL16_HI:
case R_PPC_DTPREL16_HA:
- addend -= htab->tls_sec->vma + DTP_OFFSET;
+ addend -= htab->elf.tls_sec->vma + DTP_OFFSET;
break;
/* Relocations that may need to be propagated if this is a shared
case R_PPC_TPREL16_LO:
case R_PPC_TPREL16_HI:
case R_PPC_TPREL16_HA:
- addend -= htab->tls_sec->vma + TP_OFFSET;
+ addend -= htab->elf.tls_sec->vma + TP_OFFSET;
/* The TPREL16 relocs shouldn't really be used in shared
libs as they will result in DT_TEXTREL being set, but
support them anyway. */
goto dodyn;
case R_PPC_TPREL32:
- addend -= htab->tls_sec->vma + TP_OFFSET;
+ addend -= htab->elf.tls_sec->vma + TP_OFFSET;
goto dodyn;
case R_PPC_DTPREL32:
- addend -= htab->tls_sec->vma + DTP_OFFSET;
+ addend -= htab->elf.tls_sec->vma + DTP_OFFSET;
goto dodyn;
case R_PPC_DTPMOD32:
case R_PPC_REL14_BRNTAKEN:
/* If these relocations are not to a named symbol, they can be
handled right here, no need to bother the dynamic linker. */
- if (h == NULL
- || strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0
- || SYMBOL_REFERENCES_LOCAL (info, h))
+ if (SYMBOL_REFERENCES_LOCAL (info, h)
+ || strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0)
break;
/* fall through */
|| ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
|| h->root.type != bfd_link_hash_undefweak)
&& (MUST_BE_DYN_RELOC (r_type)
- || (h != NULL
- && !SYMBOL_CALLS_LOCAL (info, h))))
+ || !SYMBOL_CALLS_LOCAL (info, h)))
|| (ELIMINATE_COPY_RELOCS
&& !info->shared
&& (input_section->flags & SEC_ALLOC) != 0
if (skip)
memset (&outrel, 0, sizeof outrel);
- else if (h != NULL
- && !SYMBOL_REFERENCES_LOCAL (info, h))
+ else if (!SYMBOL_REFERENCES_LOCAL (info, h))
{
unresolved_reloc = FALSE;
outrel.r_info = ELF32_R_INFO (h->dynindx, r_type);
}
break;
+ case R_PPC_RELAX32PC:
+ relocation -= (input_section->output_section->vma
+ + input_section->output_offset
+ + rel->r_offset - 4);
+ /* Fall thru */
+ case R_PPC_RELAX32:
+ {
+ unsigned long t0;
+ unsigned long t1;
+
+ t0 = bfd_get_32 (output_bfd, contents + rel->r_offset);
+ t1 = bfd_get_32 (output_bfd, contents + rel->r_offset + 4);
+
+ /* We're clearing the bits for R_PPC_ADDR16_HA
+ and R_PPC_ADDR16_LO here. */
+ t0 &= ~0xffff;
+ t1 &= ~0xffff;
+
+ /* t0 is HA, t1 is LO */
+ relocation += addend;
+ t0 |= ((relocation + 0x8000) >> 16) & 0xffff;
+ t1 |= relocation & 0xffff;
+
+ bfd_put_32 (output_bfd, t0, contents + rel->r_offset);
+ bfd_put_32 (output_bfd, t1, contents + rel->r_offset + 4);
+ }
+ continue;
+
/* Indirect .sdata relocation. */
case R_PPC_EMB_SDAI16:
BFD_ASSERT (htab->sdata != NULL);
relocation
- = bfd_elf32_finish_pointer_linker_section (output_bfd, input_bfd,
- info, htab->sdata, h,
- relocation, rel,
- R_PPC_RELATIVE);
+ = elf_finish_pointer_linker_section (output_bfd, input_bfd, info,
+ htab->sdata, h, relocation,
+ rel, R_PPC_RELATIVE);
break;
/* Indirect .sdata2 relocation. */
case R_PPC_EMB_SDA2I16:
BFD_ASSERT (htab->sdata2 != NULL);
relocation
- = bfd_elf32_finish_pointer_linker_section (output_bfd, input_bfd,
- info, htab->sdata2, h,
- relocation, rel,
- R_PPC_RELATIVE);
+ = elf_finish_pointer_linker_section (output_bfd, input_bfd, info,
+ htab->sdata2, h, relocation,
+ rel, R_PPC_RELATIVE);
break;
/* Handle the TOC16 reloc. We want to use the offset within the .got
apuinfo_list_finish ();
}
+
+/* Return address for Ith PLT stub in section PLT, for relocation REL
+ or (bfd_vma) -1 if it should not be included. */
+
+static bfd_vma
+ppc_elf_plt_sym_val (bfd_vma i ATTRIBUTE_UNUSED,
+ const asection *plt ATTRIBUTE_UNUSED,
+ const arelent *rel)
+{
+ return rel->address;
+}
+
+/* Add extra PPC sections -- Note, for now, make .sbss2 and
+ .PPC.EMB.sbss0 a normal section, and not a bss section so
+ that the linker doesn't crater when trying to make more than
+ 2 sections. */
+
+static struct bfd_elf_special_section const ppc_elf_special_sections[]=
+{
+ { ".tags", 5, 0, SHT_ORDERED, SHF_ALLOC },
+ { ".sdata", 6, -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE },
+ { ".sbss", 5, -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE },
+ { ".sdata2", 7, -2, SHT_PROGBITS, SHF_ALLOC },
+ { ".sbss2", 6, -2, SHT_PROGBITS, SHF_ALLOC },
+ { ".PPC.EMB.apuinfo", 16, 0, SHT_NOTE, 0 },
+ { ".PPC.EMB.sdata0", 15, 0, SHT_PROGBITS, SHF_ALLOC },
+ { ".PPC.EMB.sbss0", 14, 0, SHT_PROGBITS, SHF_ALLOC },
+ { ".plt", 4, 0, SHT_NOBITS, SHF_ALLOC + SHF_EXECINSTR },
+ { NULL, 0, 0, 0, 0 }
+};
\f
#define TARGET_LITTLE_SYM bfd_elf32_powerpcle_vec
#define TARGET_LITTLE_NAME "elf32-powerpcle"
#define TARGET_BIG_NAME "elf32-powerpc"
#define ELF_ARCH bfd_arch_powerpc
#define ELF_MACHINE_CODE EM_PPC
+#ifdef __QNXTARGET__
+#define ELF_MAXPAGESIZE 0x1000
+#else
#define ELF_MAXPAGESIZE 0x10000
+#endif
#define elf_info_to_howto ppc_elf_info_to_howto
#ifdef EM_CYGNUS_POWERPC
#define elf_backend_can_gc_sections 1
#define elf_backend_can_refcount 1
#define elf_backend_got_header_size 12
-#define elf_backend_plt_header_size PLT_INITIAL_ENTRY_SIZE
#define elf_backend_rela_normal 1
+#define bfd_elf32_mkobject ppc_elf_mkobject
#define bfd_elf32_bfd_merge_private_bfd_data ppc_elf_merge_private_bfd_data
#define bfd_elf32_bfd_relax_section ppc_elf_relax_section
#define bfd_elf32_bfd_reloc_type_lookup ppc_elf_reloc_type_lookup
#define elf_backend_begin_write_processing ppc_elf_begin_write_processing
#define elf_backend_final_write_processing ppc_elf_final_write_processing
#define elf_backend_write_section ppc_elf_write_section
+#define elf_backend_special_sections ppc_elf_special_sections
+#define elf_backend_plt_sym_val ppc_elf_plt_sym_val
#include "elf32-target.h"