diff options
Diffstat (limited to 'bfd/elf32-ppc.c')
-rw-r--r-- | bfd/elf32-ppc.c | 1272 |
1 files changed, 927 insertions, 345 deletions
diff --git a/bfd/elf32-ppc.c b/bfd/elf32-ppc.c index 2e1353fdf7e..dff4126e155 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,6 +203,7 @@ struct ppc_elf_link_hash_table asection *relsbss; elf_linker_section_t *sdata; elf_linker_section_t *sdata2; + asection *sbss; /* Short-cut to first output tls section. */ asection *tls_sec; @@ -175,6 +247,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 +262,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 +273,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; } @@ -1476,6 +1534,21 @@ static reloc_howto_type ppc_elf_howto_raw[] = { 0xffff, /* dst_mask */ FALSE), /* pcrel_offset */ + /* Phony reloc 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 */ + /* GNU extension to record C++ vtable hierarchy. */ HOWTO (R_PPC_GNU_VTINHERIT, /* type */ 0, /* rightshift */ @@ -1541,286 +1614,423 @@ ppc_elf_howto_init (void) } } -/* This function handles relaxing for the PPC with option --mpc860c0[=<n>]. - - The MPC860, revision C0 or earlier contains a bug in the die. - If all of the following conditions are true, the next instruction - to be executed *may* be treated as a no-op. - 1/ A forward branch is executed. - 2/ The branch is predicted as not taken. - 3/ The branch is taken. - 4/ The branch is located in the last 5 words of a page. - (The EOP limit is 5 by default but may be specified as any value - from 1-10.) - - Our software solution is to detect these problematic branches in a - linker pass and modify them as follows: - 1/ Unconditional branches - Since these are always predicted taken, - there is no problem and no action is required. - 2/ Conditional backward branches - No problem, no action required. - 3/ Conditional forward branches - Ensure that the "inverse prediction - bit" is set (ensure it is predicted taken). - 4/ Conditional register branches - Ensure that the "y bit" is set - (ensure it is predicted taken). */ - -/* Sort sections by address. */ - -static int -ppc_elf_sort_rela (const void *arg1, const void *arg2) +static bfd_reloc_status_type +ppc_elf_install_value (bfd *abfd, + bfd_byte *hit_addr, + bfd_vma v, + unsigned int r_type) { - const Elf_Internal_Rela * const *rela1 = arg1; - const Elf_Internal_Rela * const *rela2 = arg2; + bfd_vma t0, t1; +#ifdef BFD_HOST_U_64_BIT + BFD_HOST_U_64_BIT val = (BFD_HOST_U_64_BIT) v; +#else + bfd_vma val = v; +#endif + + switch (r_type) + { + case R_PPC_RELAX32: + /* Do stuff here. */ + t0 = bfd_get_32 (abfd, hit_addr); + t1 = bfd_get_32 (abfd, hit_addr + 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 */ + t0 |= ((val + 0x8000) >> 16) & 0xffff; + t1 |= val & 0xffff; + + bfd_put_32 (abfd, t0, hit_addr); + bfd_put_32 (abfd, t1, hit_addr + 4); + break; + + case R_PPC_REL24: + 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; - /* Sort by offset. */ - return ((*rela1)->r_offset - (*rela2)->r_offset); + 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; + + default: + return bfd_reloc_notsupported; + } + + return bfd_reloc_ok; } +static const bfd_byte shared_stub_entry[] = + { + 0x48, 0x00, 0x00, 0x24, /* b .+36 */ + 0x7c, 0x08, 0x02, 0xa6, /* mflr 0 */ + 0x42, 0x9f, 0x00, 0x05, /* bcl 20, 31, .Lxxx */ + 0x7d, 0x68, 0x02, 0xa6, /* mflr 11 */ + 0x3d, 0x60, 0x00, 0x00, /* addis 11, 11, (xxx-.Lxxx)@ha */ + 0x39, 0x6b, 0x00, 0x18, /* addi 11, 11, (xxx-.Lxxx)@l */ + 0x7c, 0x08, 0x03, 0xa6, /* mtlr 0 */ + 0x7d, 0x69, 0x03, 0xa6, /* mtctr 11 */ + 0x4e, 0x80, 0x04, 0x20, /* bctr */ + }; + +static const bfd_byte stub_entry[] = + { + 0x48, 0x00, 0x00, 0x14, /* b .+20 */ + 0x3d, 0x60, 0x00, 0x00, /* lis 11,xxx@ha */ + 0x39, 0x6b, 0x00, 0x00, /* addi 11,11,xxx@l */ + 0x7d, 0x69, 0x03, 0xa6, /* mtctr 11 */ + 0x4e, 0x80, 0x04, 0x20, /* bctr */ + }; + + static bfd_boolean ppc_elf_relax_section (bfd *abfd, asection *isec, 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_contents = FALSE; + bfd_boolean changed_relocs = FALSE; + struct ppc_elf_link_hash_table *ppc_info; - /* We never have to do this more than once per input section. */ *again = FALSE; + /* Nothing to do if there are no relocations and no need for + the relax finalize pass. */ + if ((isec->flags & SEC_RELOC) == 0 + || isec->reloc_count == 0 + || link_info->relax_finalizing) + 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) + 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, trampoff, toff, roff; + asection *tsec; + bfd_size_type amt; + struct one_fixup *f; + size_t insn_offset = 0; + bfd_vma max_branch_offset; + + switch (r_type) { - /* Go get them off disk. */ - contents = bfd_malloc (isec->_raw_size); - if (contents == NULL) - goto error_return; - free_contents = contents; + case R_PPC_REL24: + case R_PPC_LOCAL24PC: + case R_PPC_REL14: + case R_PPC_REL14_BRTAKEN: + case R_PPC_REL14_BRNTAKEN: + case R_PPC_PLTREL24: + break; - if (! bfd_get_section_contents (abfd, isec, contents, - (file_ptr) 0, isec->_raw_size)) - goto error_return; + 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; - - /* 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; - } } - if (comb_count > 1) - qsort (rela_comb, (size_t) comb_count, sizeof (int), - ppc_elf_sort_rela); - } + isym = isymbuf + ELF32_R_SYM (irel->r_info); + if (isym->st_shndx == SHN_UNDEF) + continue; /* We can't do anthing 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); - /* 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) + toff = isym->st_value; + } + else { - /* Check each word in this EOP region. */ - for (; dot < end_page; dot += 4) + /* Need dynamic 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) { - 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; + Elf_Internal_Sym *isym; - 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) + if (h->plt.offset == (bfd_vma) -1 + || ppc_info->plt == NULL) { - /* 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)) + + /* Read this BFD's local symbols. */ + if (isymbuf == NULL) { - /* 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; + 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) + /* We can't do anthing with undefined symbols. */ + continue; + 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 = h->root.u.def.section; + + toff = h->root.u.def.value; } -#undef BO0 -#undef BO2 -#undef BO4 - if (modified) + else { - bfd_put_32 (abfd, insn, contents + isec_offset); - section_modified = TRUE; + tsec = ppc_info->plt; + toff = h->plt.offset; } } + else if (h->root.type == bfd_link_hash_undefined + || h->root.type == bfd_link_hash_undefweak) + continue; + + else + { + tsec = h->root.u.def.section; + toff = h->root.u.def.value; + } } - if (section_modified) + + if (tsec->sec_info_type == ELF_INFO_TYPE_MERGE) + toff = _bfd_merged_section_offset (abfd, &tsec, + elf_section_data (tsec)->sec_info, + toff + irel->r_addend, 0); + else + toff += irel->r_addend; + + symaddr = tsec->output_section->vma + tsec->output_offset + toff; + + roff = irel->r_offset; + + reladdr = (isec->output_section->vma + + isec->output_offset + + roff) & (bfd_vma) -4; + + /* If the branch is in range, no need to do anything. */ + max_branch_offset = 1 << 25; + if (r_type != R_PPC_REL24 + && r_type != R_PPC_LOCAL24PC + && r_type != R_PPC_PLTREL24) + max_branch_offset = 1 << 15; + + if ((bfd_vma) (symaddr - reladdr) + max_branch_offset + <= 2 * max_branch_offset) + continue; + + /* If the branch and target are in the same section, you have + no hope. We'll error out later. */ + if (tsec == isec) + 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) { - elf_section_data (isec)->this_hdr.contents = contents; - free_contents = NULL; + size_t size; + + if (link_info->shared + || tsec == ppc_info->plt + || r_type == R_PPC_LOCAL24PC) + { + size = sizeof (shared_stub_entry); + insn_offset = 16; + } + else + { + size = sizeof (stub_entry); + insn_offset = 4; + } + + /* Resize the current section to make room for the new branch. */ + trampoff = (isec->_cooked_size + 3) & (bfd_vma) - 4; + amt = trampoff + size; + contents = bfd_realloc (contents, amt); + if (contents == NULL) + abort (); + + isec->_cooked_size = amt; + + if (link_info->shared + || tsec == ppc_info->plt + || r_type == R_PPC_LOCAL24PC) + memcpy (contents + trampoff, shared_stub_entry, size); + else + memcpy (contents + trampoff, stub_entry, size); + + /* 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), + R_PPC_RELAX32); + 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; + } + else + { + /* 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. Hope like + hell this doesn't overflow too. */ + if (ppc_elf_install_value (abfd, contents + roff, + f->trampoff - (roff & (bfd_vma) -3) + 4, + r_type) != bfd_reloc_ok) + abort (); + + changed_contents = TRUE; + changed_relocs = TRUE; } - if (rela_comb != NULL) + /* Clean up. */ + while (fixups) { - free (rela_comb); - rela_comb = NULL; + struct one_fixup *f = fixups; + fixups = fixups->next; + free (f); } - - 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_contents && !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_relocs) + free (internal_relocs); + else + elf_section_data (isec)->relocs = internal_relocs; + } + + *again = changed_contents || changed_relocs; 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,71 +2379,359 @@ ppc_elf_fake_sections (bfd *abfd ATTRIBUTE_UNUSED, return TRUE; } +/* 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; +} + +/* 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; +} + +#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; + struct elf_backend_data *bed = get_elf_backend_data (output_bfd); + unsigned int i; + + BFD_ASSERT (srel != NULL); + + 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; +} + /* 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; + + 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; + + amt = sizeof (elf_linker_section_t); + lsect = bfd_zalloc (htab->elf.dynobj, amt); - /* Record the first bfd section that needs the special section. */ - if (!dynobj) - dynobj = elf_hash_table (info)->dynobj = abfd; + lsect->sym_offset = sym_offset; - /* If this is the first time, create the section. */ - lsect = elf_linker_section (dynobj, which); - if (!lsect) + /* 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; @@ -2318,7 +2816,10 @@ ppc_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info) 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)) @@ -2327,7 +2828,6 @@ ppc_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *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 @@ -3103,20 +3603,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; } @@ -3220,8 +3716,8 @@ ppc_elf_check_relocs (bfd *abfd, 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; @@ -3232,8 +3728,8 @@ ppc_elf_check_relocs (bfd *abfd, 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; @@ -3916,42 +4412,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; } @@ -4272,7 +4751,7 @@ ppc_elf_relocate_section (bfd *output_bfd, } else if (h->root.type == bfd_link_hash_undefweak) ; - else if (info->shared + else if (!info->executable && !info->no_undefined && ELF_ST_VISIBILITY (h->other) == STV_DEFAULT) ; @@ -4848,9 +5327,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 */ @@ -4880,8 +5358,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 @@ -4936,8 +5413,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); @@ -5004,24 +5480,95 @@ ppc_elf_relocate_section (bfd *output_bfd, } break; + case R_PPC_RELAX32: + { + unsigned long r_symndx; + Elf_Internal_Sym *sym; + asection *sym_sec; + bfd_byte *hit_addr = 0; + bfd_vma value = 0; + + r_symndx = ELF32_R_SYM (rel->r_info); + + if (r_symndx < symtab_hdr->sh_info) + { + sym = local_syms + r_symndx; + sym_sec = local_sections[r_symndx]; + + value = _bfd_elf_rela_local_sym (output_bfd, sym, sym_sec, rel); + } + else + { + long indx; + + indx = r_symndx - symtab_hdr->sh_info; + h = elf_sym_hashes (input_bfd)[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; + + value = 0; + if (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak) + { + sym_sec = h->root.u.def.section; + + /* Detect the cases that sym_sec->output_section is + expected to be NULL -- all cases in which the symbol + is defined in another shared module. This includes + PLT relocs for which we've created a PLT entry and + other relocs for which we're prepared to create + dynamic relocations. */ + /* ??? Just accept it NULL and continue. */ + + if (sym_sec->output_section != NULL) + { + value = (h->root.u.def.value + + sym_sec->output_section->vma + + sym_sec->output_offset); + } + } + 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; + continue; + } + } + hit_addr = contents + rel->r_offset; + value += rel->r_addend; + + r = ppc_elf_install_value (output_bfd, hit_addr, value, r_type); + if (r != bfd_reloc_ok) + break; + else + 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 @@ -5694,6 +6241,35 @@ 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", 0, NULL, 0, + SHT_ORDERED, SHF_ALLOC }, + { ".sdata", 0, NULL, 0, + SHT_PROGBITS, SHF_ALLOC + SHF_WRITE }, + { ".sbss", 0, NULL, 0, + SHT_NOBITS, SHF_ALLOC + SHF_WRITE }, + { ".sdata2", 0, NULL, 0, + SHT_PROGBITS, SHF_ALLOC }, + { ".sbss2", 0, NULL, 0, + SHT_PROGBITS, SHF_ALLOC }, + { ".PPC.EMB.apuinfo", 0, NULL, 0, + SHT_NOTE, 0 }, + { ".PPC.EMB.sdata0", 0, NULL, 0, + SHT_PROGBITS, SHF_ALLOC }, + { ".PPC.EMB.sbss0", 0, NULL, 0, + SHT_PROGBITS, SHF_ALLOC }, + { ".plt", 0, NULL, 0, + SHT_NOBITS, 0 }, + { NULL, 0, NULL, 0, + 0, 0 } +}; #define TARGET_LITTLE_SYM bfd_elf32_powerpcle_vec #define TARGET_LITTLE_NAME "elf32-powerpcle" @@ -5701,7 +6277,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 @@ -5720,6 +6300,7 @@ ppc_elf_final_write_processing (bfd *abfd, bfd_boolean linker ATTRIBUTE_UNUSED) #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 @@ -5748,5 +6329,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" |