X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=bfd%2Felf32-ppc.c;h=4467eec5d975aff45d6a270bcbd325a4abb35df8;hb=ca9a79a174a35d35d26724cdc223facb1c913700;hp=68d83e3014e4a5b9ac06edeedb9c811e6870b074;hpb=9203ba999ff3620ef277840e1cd5344e37cec8ee;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/elf32-ppc.c b/bfd/elf32-ppc.c index 68d83e3014..4467eec5d9 100644 --- a/bfd/elf32-ppc.c +++ b/bfd/elf32-ppc.c @@ -70,6 +70,72 @@ static bfd_reloc_status_type ppc_elf_unhandled_reloc #define DTP_OFFSET 0x8000 +/* 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 @@ -96,6 +162,11 @@ struct ppc_elf_link_hash_entry { 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; @@ -132,9 +203,7 @@ struct ppc_elf_link_hash_table 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; @@ -175,6 +244,7 @@ ppc_elf_link_hash_newfunc (struct bfd_hash_entry *entry, 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; } @@ -189,7 +259,7 @@ ppc_elf_link_hash_table_create (bfd *abfd) { 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; @@ -200,21 +270,6 @@ ppc_elf_link_hash_table_create (bfd *abfd) 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; } @@ -227,7 +282,7 @@ ppc_elf_link_hash_table_create (bfd *abfd) /* 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) { @@ -281,7 +336,8 @@ ppc_elf_copy_indirect_symbol (struct elf_backend_data *bed, 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); } @@ -1476,6 +1532,35 @@ static reloc_howto_type ppc_elf_howto_raw[] = { 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 */ @@ -1541,39 +1626,28 @@ ppc_elf_howto_init (void) } } -/* This function handles relaxing for the PPC with option --mpc860c0[=]. - - 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, @@ -1581,246 +1655,351 @@ 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_currr_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; } @@ -2169,127 +2348,16 @@ ppc_elf_fake_sections (bfd *abfd ATTRIBUTE_UNUSED, return TRUE; } -/* Create a special linker section, or return a pointer to a linker - section already created */ - -static elf_linker_section_t * -elf_create_linker_section (bfd *abfd, - struct bfd_link_info *info, - enum elf_linker_section_enum which, - elf_linker_section_t *defaults) -{ - bfd *dynobj = elf_hash_table (info)->dynobj; - elf_linker_section_t *lsect; - - /* Record the first bfd section that needs the special section */ - if (!dynobj) - dynobj = elf_hash_table (info)->dynobj = abfd; - - /* If this is the first time, create the section */ - lsect = elf_linker_section (dynobj, which); - if (!lsect) - { - asection *s; - bfd_size_type amt = sizeof (elf_linker_section_t); - - lsect = bfd_alloc (dynobj, amt); - - *lsect = *defaults; - elf_linker_section (dynobj, which) = lsect; - lsect->which = which; - lsect->hole_written_p = FALSE; - - /* See if the sections already exist */ - lsect->section = s = bfd_get_section_by_name (dynobj, lsect->name); - if (!s || (s->flags & defaults->flags) != defaults->flags) - { - lsect->section = s = bfd_make_section_anyway (dynobj, lsect->name); - - if (s == NULL) - return NULL; - - bfd_set_section_flags (dynobj, s, defaults->flags); - bfd_set_section_alignment (dynobj, s, lsect->alignment); - } - else if (bfd_get_section_alignment (dynobj, s) < lsect->alignment) - bfd_set_section_alignment (dynobj, s, lsect->alignment); - - s->_raw_size = align_power (s->_raw_size, lsect->alignment); - - /* Is there a hole we have to provide? If so check whether the - segment is too big already */ - if (lsect->hole_size) - { - lsect->hole_offset = s->_raw_size; - s->_raw_size += lsect->hole_size; - if (lsect->hole_offset > lsect->max_hole_offset) - { - (*_bfd_error_handler) - (_("%s: Section %s is too large to add hole of %ld bytes"), - bfd_get_filename (abfd), - lsect->name, - (long) lsect->hole_size); - - bfd_set_error (bfd_error_bad_value); - return NULL; - } - } - -#ifdef DEBUG - fprintf (stderr, "Creating section %s, current size = %ld\n", - lsect->name, (long) s->_raw_size); -#endif - - if (lsect->sym_name) - { - struct elf_link_hash_entry *h; - struct bfd_link_hash_entry *bh; - -#ifdef DEBUG - fprintf (stderr, "Adding %s to section %s\n", - lsect->sym_name, - lsect->name); -#endif - bh = bfd_link_hash_lookup (info->hash, lsect->sym_name, - FALSE, FALSE, FALSE); - - if ((bh == NULL || bh->type == bfd_link_hash_undefined) - && !(_bfd_generic_link_add_one_symbol - (info, abfd, lsect->sym_name, BSF_GLOBAL, s, - (lsect->hole_size - ? s->_raw_size - lsect->hole_size + lsect->sym_offset - : lsect->sym_offset), - NULL, FALSE, - get_elf_backend_data (abfd)->collect, &bh))) - return NULL; - h = (struct elf_link_hash_entry *) bh; - - if ((defaults->which != LINKER_SECTION_SDATA) - && (defaults->which != LINKER_SECTION_SDATA2)) - h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_DYNAMIC; - - h->type = STT_OBJECT; - lsect->sym_hash = h; - - if (info->shared - && ! _bfd_elf_link_record_dynamic_symbol (info, h)) - return NULL; - } - } - - return lsect; -} - /* 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_enum_t which) + elf_linker_section_t *lsect) { for ( ; linker_pointers != NULL; linker_pointers = linker_pointers->next) - if (which == linker_pointers->which && addend == linker_pointers->addend) + if (lsect == linker_pointers->lsect && addend == linker_pointers->addend) return linker_pointers; return NULL; @@ -2314,13 +2382,16 @@ elf_create_pointer_linker_section (bfd *abfd, /* 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. */ - if (elf_find_pointer_linker_section (h->linker_section_pointer, + eh = (struct ppc_elf_link_hash_entry *) h; + if (elf_find_pointer_linker_section (eh->linker_section_pointer, rel->r_addend, - lsect->which)) + lsect)) return TRUE; - ptr_linker_section_ptr = &h->linker_section_pointer; + ptr_linker_section_ptr = &eh->linker_section_pointer; /* Make sure this symbol is output as a dynamic symbol. */ if (h->dynindx == -1) { @@ -2340,24 +2411,21 @@ elf_create_pointer_linker_section (bfd *abfd, if (!ptr) { unsigned int num_symbols = elf_tdata (abfd)->symtab_hdr.sh_info; - register unsigned int i; amt = num_symbols; amt *= sizeof (elf_linker_section_pointers_t *); - ptr = bfd_alloc (abfd, amt); + ptr = bfd_zalloc (abfd, amt); if (!ptr) return FALSE; elf_local_ptr_offsets (abfd) = ptr; - for (i = 0; i < num_symbols; i++) - ptr[i] = NULL; } /* 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->which)) + lsect)) return TRUE; ptr_linker_section_ptr = &ptr[r_symndx]; @@ -2383,7 +2451,7 @@ elf_create_pointer_linker_section (bfd *abfd, linker_section_ptr->next = *ptr_linker_section_ptr; linker_section_ptr->addend = rel->r_addend; - linker_section_ptr->which = lsect->which; + linker_section_ptr->lsect = lsect; linker_section_ptr->written_address_p = FALSE; *ptr_linker_section_ptr = linker_section_ptr; @@ -2421,10 +2489,13 @@ elf_finish_pointer_linker_section (bfd *output_bfd, 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 (h->linker_section_pointer, + = elf_find_pointer_linker_section (eh->linker_section_pointer, rel->r_addend, - lsect->which); + lsect); BFD_ASSERT (linker_section_ptr != NULL); @@ -2460,7 +2531,7 @@ elf_finish_pointer_linker_section (bfd *output_bfd, linker_section_ptr = (elf_find_pointer_linker_section (elf_local_ptr_offsets (input_bfd)[r_symndx], rel->r_addend, - lsect->which)); + lsect)); BFD_ASSERT (linker_section_ptr != NULL); @@ -2473,23 +2544,18 @@ elf_finish_pointer_linker_section (bfd *output_bfd, 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; - struct elf_backend_data *bed = get_elf_backend_data (output_bfd); + const struct elf_backend_data *bed; unsigned int i; - /* We need to generate a relative reloc for the dynamic - linker. */ - if (!srel) - { - srel = bfd_get_section_by_name (elf_hash_table (info)->dynobj, - lsect->rel_name); - lsect->rel_section = srel; - } - 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 @@ -2509,7 +2575,6 @@ elf_finish_pointer_linker_section (bfd *output_bfd, relocation = (lsect->section->output_offset + linker_section_ptr->offset - - lsect->hole_offset - lsect->sym_offset); #ifdef DEBUG @@ -2529,65 +2594,114 @@ 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; + + case LINKER_SECTION_SDATA2: /* .sdata2/.sbss2 section */ + name = ".sdata2"; + rel_name = ".rela.sdata2"; + sym_name = "_SDA2_BASE_"; + flags |= SEC_READONLY; + break; + } + + /* Record the first bfd that needs the special sections. */ + if (!htab->elf.dynobj) + htab->elf.dynobj = abfd; - /* Record the first bfd section that needs the special section. */ - if (!dynobj) - dynobj = elf_hash_table (info)->dynobj = abfd; + amt = sizeof (elf_linker_section_t); + lsect = bfd_zalloc (htab->elf.dynobj, amt); - /* If this is the first time, create the section. */ - lsect = elf_linker_section (dynobj, which); - if (!lsect) + 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); + +#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); - lsect = elf_create_linker_section (abfd, info, which, &defaults); + 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; @@ -2622,7 +2736,8 @@ ppc_elf_additional_program_headers (bfd *abfd) /* 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; } @@ -3459,20 +3574,16 @@ ppc_elf_check_relocs (bfd *abfd, 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; } @@ -4043,25 +4154,18 @@ ppc_elf_gc_sweep_hook (bfd *abfd, 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 @@ -4272,42 +4376,25 @@ ppc_elf_add_symbol_hook (bfd *abfd, 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; } @@ -4594,54 +4681,23 @@ ppc_elf_relocate_section (bfd *output_bfd, 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 (h, sym_hashes, r_symndx, + symtab_hdr, relocation, sec, + unresolved_reloc, info, + 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->executable - && !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 @@ -4824,8 +4880,8 @@ ppc_elf_relocate_section (bfd *output_bfd, { /* 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); @@ -4860,7 +4916,7 @@ ppc_elf_relocate_section (bfd *output_bfd, 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); @@ -5063,7 +5119,7 @@ ppc_elf_relocate_section (bfd *output_bfd, { 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++ @@ -5081,7 +5137,7 @@ ppc_elf_relocate_section (bfd *output_bfd, 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; @@ -5169,7 +5225,7 @@ ppc_elf_relocate_section (bfd *output_bfd, 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 @@ -5178,18 +5234,18 @@ ppc_elf_relocate_section (bfd *output_bfd, 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: @@ -5204,9 +5260,8 @@ ppc_elf_relocate_section (bfd *output_bfd, 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 */ @@ -5236,8 +5291,7 @@ ppc_elf_relocate_section (bfd *output_bfd, || 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 @@ -5292,8 +5346,7 @@ ppc_elf_relocate_section (bfd *output_bfd, 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); @@ -5360,6 +5413,34 @@ ppc_elf_relocate_section (bfd *output_bfd, } 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); @@ -6048,6 +6129,25 @@ ppc_elf_final_write_processing (bfd *abfd, bfd_boolean linker ATTRIBUTE_UNUSED) apuinfo_list_finish (); } + +/* 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 } +}; #define TARGET_LITTLE_SYM bfd_elf32_powerpcle_vec #define TARGET_LITTLE_NAME "elf32-powerpcle" @@ -6055,7 +6155,11 @@ ppc_elf_final_write_processing (bfd *abfd, bfd_boolean linker ATTRIBUTE_UNUSED) #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 @@ -6071,9 +6175,9 @@ ppc_elf_final_write_processing (bfd *abfd, bfd_boolean linker ATTRIBUTE_UNUSED) #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 @@ -6102,5 +6206,6 @@ ppc_elf_final_write_processing (bfd *abfd, bfd_boolean linker ATTRIBUTE_UNUSED) #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 #include "elf32-target.h"