*** ../binutils-2.21.53.0.1.orig/bfd/elf64-ppc.c 2011-08-05 12:43:25.596878997 +0100 --- bfd/elf64-ppc.c 2011-08-05 12:44:58.485878988 +0100 *************** *** 34,39 **** --- 34,40 ---- #include "elf-bfd.h" #include "elf/ppc64.h" #include "elf64-ppc.h" + #include "dwarf2.h" static bfd_reloc_status_type ppc64_elf_ha_reloc (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); *************** struct ppc_link_hash_table *** 3720,3725 **** --- 3721,3727 ---- asection *sfpr; asection *brlt; asection *relbrlt; + asection *glink_eh_frame; /* Shortcut to .__tls_get_addr and __tls_get_addr. */ struct ppc_link_hash_entry *tls_get_addr; *************** create_linkage_sections (bfd *dynobj, st *** 4170,4175 **** --- 4172,4189 ---- || ! bfd_set_section_alignment (dynobj, htab->glink, 3)) return FALSE; + if (!info->no_ld_generated_unwind_info) + { + flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_HAS_CONTENTS + | SEC_IN_MEMORY | SEC_LINKER_CREATED); + htab->glink_eh_frame = bfd_make_section_anyway_with_flags (dynobj, + ".eh_frame", + flags); + if (htab->glink_eh_frame == NULL + || !bfd_set_section_alignment (abfd, htab->glink_eh_frame, 2)) + return FALSE; + } + flags = SEC_ALLOC | SEC_LINKER_CREATED; htab->iplt = bfd_make_section_anyway_with_flags (dynobj, ".iplt", flags); if (htab->iplt == NULL *************** ppc64_elf_size_dynamic_sections (bfd *ou *** 9025,9030 **** --- 9039,9050 ---- /* Strip this section if we don't need it; see the comment below. */ } + else if (s == htab->glink_eh_frame) + { + if (!bfd_is_abs_section (s->output_section)) + /* Not sized yet. */ + continue; + } else if (CONST_STRNEQ (s->name, ".rela")) { if (s->size != 0) *************** build_plt_stub (bfd *obfd, bfd_byte *p, *** 9271,9277 **** r[1].r_offset = r[0].r_offset + 8; r[1].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_LO_DS); r[1].r_addend = r[0].r_addend; ! if (PPC_HA (offset + 16) != PPC_HA (offset)) { r[2].r_offset = r[1].r_offset + 4; r[2].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_LO); --- 9291,9297 ---- r[1].r_offset = r[0].r_offset + 8; r[1].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_LO_DS); r[1].r_addend = r[0].r_addend; ! if (PPC_HA (offset + 8 + 8 * plt_static_chain) != PPC_HA (offset)) { r[2].r_offset = r[1].r_offset + 4; r[2].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_LO); *************** build_plt_stub (bfd *obfd, bfd_byte *p, *** 9282,9290 **** r[2].r_offset = r[1].r_offset + 8; r[2].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_LO_DS); r[2].r_addend = r[0].r_addend + 8; ! r[3].r_offset = r[2].r_offset + 4; ! r[3].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_LO_DS); ! r[3].r_addend = r[0].r_addend + 16; } } bfd_put_32 (obfd, ADDIS_R12_R2 | PPC_HA (offset), p), p += 4; --- 9302,9313 ---- r[2].r_offset = r[1].r_offset + 8; r[2].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_LO_DS); r[2].r_addend = r[0].r_addend + 8; ! if (plt_static_chain) ! { ! r[3].r_offset = r[2].r_offset + 4; ! r[3].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_LO_DS); ! r[3].r_addend = r[0].r_addend + 16; ! } } } bfd_put_32 (obfd, ADDIS_R12_R2 | PPC_HA (offset), p), p += 4; *************** build_plt_stub (bfd *obfd, bfd_byte *p, *** 9307,9313 **** { r[0].r_offset += 4; r[0].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_DS); ! if (PPC_HA (offset + 16) != PPC_HA (offset)) { r[1].r_offset = r[0].r_offset + 4; r[1].r_info = ELF64_R_INFO (0, R_PPC64_TOC16); --- 9330,9336 ---- { r[0].r_offset += 4; r[0].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_DS); ! if (PPC_HA (offset + 8 + 8 * plt_static_chain) != PPC_HA (offset)) { r[1].r_offset = r[0].r_offset + 4; r[1].r_info = ELF64_R_INFO (0, R_PPC64_TOC16); *************** build_plt_stub (bfd *obfd, bfd_byte *p, *** 9317,9326 **** { r[1].r_offset = r[0].r_offset + 8; r[1].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_DS); ! r[1].r_addend = r[0].r_addend + 16; ! r[2].r_offset = r[1].r_offset + 4; ! r[2].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_DS); ! r[2].r_addend = r[0].r_addend + 8; } } bfd_put_32 (obfd, STD_R2_40R1, p), p += 4; --- 9340,9352 ---- { r[1].r_offset = r[0].r_offset + 8; r[1].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_DS); ! r[1].r_addend = r[0].r_addend + 8 + 8 * plt_static_chain; ! if (plt_static_chain) ! { ! r[2].r_offset = r[1].r_offset + 4; ! r[2].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_DS); ! r[2].r_addend = r[0].r_addend + 8; ! } } } bfd_put_32 (obfd, STD_R2_40R1, p), p += 4; *************** ppc_build_one_stub (struct bfd_hash_entr *** 9788,9795 **** if (info->emitrelocations) { r = get_relocs (stub_entry->stub_sec, ! (2 + (PPC_HA (off) != 0) ! + (PPC_HA (off + 16) == PPC_HA (off)))); if (r == NULL) return FALSE; r[0].r_offset = loc - stub_entry->stub_sec->contents; --- 9814,9823 ---- if (info->emitrelocations) { r = get_relocs (stub_entry->stub_sec, ! (2 ! + (PPC_HA (off) != 0) ! + (htab->plt_static_chain ! && PPC_HA (off + 16) == PPC_HA (off)))); if (r == NULL) return FALSE; r[0].r_offset = loc - stub_entry->stub_sec->contents; *************** ppc_size_one_stub (struct bfd_hash_entry *** 9896,9902 **** size -= 4; if (PPC_HA (off) == 0) size -= 4; ! if (PPC_HA (off + 16) != PPC_HA (off)) size += 4; if (stub_entry->h != NULL && (stub_entry->h == htab->tls_get_addr_fd --- 9924,9930 ---- size -= 4; if (PPC_HA (off) == 0) size -= 4; ! if (PPC_HA (off + 8 + 8 * htab->plt_static_chain) != PPC_HA (off)) size += 4; if (stub_entry->h != NULL && (stub_entry->h == htab->tls_get_addr_fd *************** ppc_size_one_stub (struct bfd_hash_entry *** 9906,9912 **** if (info->emitrelocations) { stub_entry->stub_sec->reloc_count ! += 2 + (PPC_HA (off) != 0) + (PPC_HA (off + 16) == PPC_HA (off)); stub_entry->stub_sec->flags |= SEC_RELOC; } } --- 9934,9943 ---- if (info->emitrelocations) { stub_entry->stub_sec->reloc_count ! += (2 ! + (PPC_HA (off) != 0) ! + (htab->plt_static_chain ! && PPC_HA (off + 16) == PPC_HA (off))); stub_entry->stub_sec->flags |= SEC_RELOC; } } *************** group_sections (struct ppc_link_hash_tab *** 10826,10831 **** --- 10857,10896 ---- #undef PREV_SEC } + static const unsigned char glink_eh_frame_cie[] = + { + 0, 0, 0, 16, /* length. */ + 0, 0, 0, 0, /* id. */ + 1, /* CIE version. */ + 'z', 'R', 0, /* Augmentation string. */ + 4, /* Code alignment. */ + 0x78, /* Data alignment. */ + 65, /* RA reg. */ + 1, /* Augmentation size. */ + DW_EH_PE_pcrel | DW_EH_PE_sdata4, /* FDE encoding. */ + DW_CFA_def_cfa, 1, 0 /* def_cfa: r1 offset 0. */ + }; + + /* Stripping output sections is normally done before dynamic section + symbols have been allocated. This function is called later, and + handles cases like htab->brlt which is mapped to its own output + section. */ + + static void + maybe_strip_output (struct bfd_link_info *info, asection *isec) + { + if (isec->size == 0 + && isec->output_section->size == 0 + && !bfd_section_removed_from_list (info->output_bfd, + isec->output_section) + && elf_section_data (isec->output_section)->dynindx == 0) + { + isec->output_section->flags |= SEC_EXCLUDE; + bfd_section_list_remove (info->output_bfd, isec->output_section); + info->output_bfd->section_count--; + } + } + /* Determine and set the size of the stub section for a final link. The basic idea here is to examine all the relocations looking for *************** ppc64_elf_size_stubs (struct bfd_link_in *** 11169,11174 **** --- 11234,11258 ---- htab->glink->flags |= SEC_RELOC; } + if (htab->glink_eh_frame != NULL + && !bfd_is_abs_section (htab->glink_eh_frame->output_section) + && (htab->glink_eh_frame->flags & SEC_EXCLUDE) == 0) + { + bfd_size_type size = 0; + + for (stub_sec = htab->stub_bfd->sections; + stub_sec != NULL; + stub_sec = stub_sec->next) + if ((stub_sec->flags & SEC_LINKER_CREATED) == 0) + size += 20; + if (htab->glink != NULL && htab->glink->size != 0) + size += 24; + if (size != 0) + size += sizeof (glink_eh_frame_cie); + htab->glink_eh_frame->rawsize = htab->glink_eh_frame->size; + htab->glink_eh_frame->size = size; + } + for (stub_sec = htab->stub_bfd->sections; stub_sec != NULL; stub_sec = stub_sec->next) *************** ppc64_elf_size_stubs (struct bfd_link_in *** 11178,11194 **** /* Exit from this loop when no stubs have been added, and no stubs have changed size. */ ! if (stub_sec == NULL) break; /* Ask the linker to do its stuff. */ (*htab->layout_sections_again) (); } ! /* It would be nice to strip htab->brlt from the output if the ! section is empty, but it's too late. If we strip sections here, ! the dynamic symbol table is corrupted since the section symbol ! for the stripped section isn't written. */ return TRUE; } --- 11262,11279 ---- /* Exit from this loop when no stubs have been added, and no stubs have changed size. */ ! if (stub_sec == NULL ! && (htab->glink_eh_frame == NULL ! || htab->glink_eh_frame->rawsize == htab->glink_eh_frame->size)) break; /* Ask the linker to do its stuff. */ (*htab->layout_sections_again) (); } ! maybe_strip_output (info, htab->brlt); ! if (htab->glink_eh_frame != NULL) ! maybe_strip_output (info, htab->glink_eh_frame); return TRUE; } *************** ppc64_elf_build_stubs (bfd_boolean emit_ *** 11393,11398 **** --- 11478,11577 ---- return FALSE; } + if (htab->glink_eh_frame != NULL + && htab->glink_eh_frame->size != 0) + { + bfd_vma val; + + p = bfd_zalloc (htab->glink_eh_frame->owner, htab->glink_eh_frame->size); + if (p == NULL) + return FALSE; + htab->glink_eh_frame->contents = p; + + htab->glink_eh_frame->rawsize = htab->glink_eh_frame->size; + + memcpy (p, glink_eh_frame_cie, sizeof (glink_eh_frame_cie)); + /* CIE length (rewrite in case little-endian). */ + bfd_put_32 (htab->elf.dynobj, sizeof (glink_eh_frame_cie) - 4, p); + p += sizeof (glink_eh_frame_cie); + + for (stub_sec = htab->stub_bfd->sections; + stub_sec != NULL; + stub_sec = stub_sec->next) + if ((stub_sec->flags & SEC_LINKER_CREATED) == 0) + { + /* FDE length. */ + bfd_put_32 (htab->elf.dynobj, 16, p); + p += 4; + /* CIE pointer. */ + val = p - htab->glink_eh_frame->contents; + bfd_put_32 (htab->elf.dynobj, val, p); + p += 4; + /* Offset to stub section. */ + val = (stub_sec->output_section->vma + + stub_sec->output_offset); + val -= (htab->glink_eh_frame->output_section->vma + + htab->glink_eh_frame->output_offset); + val -= p - htab->glink_eh_frame->contents; + if (val + 0x80000000 > 0xffffffff) + { + info->callbacks->einfo + (_("%s offset too large for .eh_frame sdata4 encoding"), + stub_sec->name); + return FALSE; + } + bfd_put_32 (htab->elf.dynobj, val, p); + p += 4; + /* stub section size. */ + bfd_put_32 (htab->elf.dynobj, stub_sec->rawsize, p); + p += 4; + /* Augmentation. */ + p += 1; + /* Pad. */ + p += 3; + } + if (htab->glink != NULL && htab->glink->size != 0) + { + /* FDE length. */ + bfd_put_32 (htab->elf.dynobj, 20, p); + p += 4; + /* CIE pointer. */ + val = p - htab->glink_eh_frame->contents; + bfd_put_32 (htab->elf.dynobj, val, p); + p += 4; + /* Offset to .glink. */ + val = (htab->glink->output_section->vma + + htab->glink->output_offset + + 8); + val -= (htab->glink_eh_frame->output_section->vma + + htab->glink_eh_frame->output_offset); + val -= p - htab->glink_eh_frame->contents; + if (val + 0x80000000 > 0xffffffff) + { + info->callbacks->einfo + (_("%s offset too large for .eh_frame sdata4 encoding"), + htab->glink->name); + return FALSE; + } + bfd_put_32 (htab->elf.dynobj, val, p); + p += 4; + /* .glink size. */ + bfd_put_32 (htab->elf.dynobj, htab->glink->rawsize - 8, p); + p += 4; + /* Augmentation. */ + p += 1; + + *p++ = DW_CFA_advance_loc + 1; + *p++ = DW_CFA_register; + *p++ = 65; + *p++ = 12; + *p++ = DW_CFA_advance_loc + 4; + *p++ = DW_CFA_restore_extended; + *p++ = 65; + } + htab->glink_eh_frame->size = p - htab->glink_eh_frame->contents; + } + /* Build the stubs as directed by the stub hash table. */ bfd_hash_traverse (&htab->stub_hash_table, ppc_build_one_stub, info); *************** ppc64_elf_build_stubs (bfd_boolean emit_ *** 11410,11416 **** } if (stub_sec != NULL ! || htab->glink->rawsize != htab->glink->size) { htab->stub_error = TRUE; info->callbacks->einfo (_("stubs don't match calculated size\n")); --- 11589,11597 ---- } if (stub_sec != NULL ! || htab->glink->rawsize != htab->glink->size ! || (htab->glink_eh_frame != NULL ! && htab->glink_eh_frame->rawsize != htab->glink_eh_frame->size)) { htab->stub_error = TRUE; info->callbacks->einfo (_("stubs don't match calculated size\n")); *************** ppc64_elf_relocate_section (bfd *output_ *** 12842,12853 **** else if (!SYMBOL_CALLS_LOCAL (info, &h->elf) && !is_opd && r_type != R_PPC64_TOC) ! { ! outrel.r_info = ELF64_R_INFO (h->elf.dynindx, r_type); ! if (h->elf.dynindx == -1 ! && h->elf.root.type == bfd_link_hash_undefweak) ! memset (&outrel, 0, sizeof outrel); ! } else { /* This symbol is local, or marked to become local, --- 13021,13027 ---- else if (!SYMBOL_CALLS_LOCAL (info, &h->elf) && !is_opd && r_type != R_PPC64_TOC) ! outrel.r_info = ELF64_R_INFO (h->elf.dynindx, r_type); else { /* This symbol is local, or marked to become local, *************** ppc64_elf_finish_dynamic_sections (bfd * *** 13566,13571 **** --- 13740,13753 ---- NULL)) return FALSE; + + if (htab->glink_eh_frame != NULL + && htab->glink_eh_frame->sec_info_type == ELF_INFO_TYPE_EH_FRAME + && !_bfd_elf_write_section_eh_frame (output_bfd, info, + htab->glink_eh_frame, + htab->glink_eh_frame->contents)) + return FALSE; + /* We need to handle writing out multiple GOT sections ourselves, since we didn't add them to DYNOBJ. We know dynobj is the first bfd. */