diff options
Diffstat (limited to 'bfd/elf64-ppc.c')
-rw-r--r-- | bfd/elf64-ppc.c | 282 |
1 files changed, 163 insertions, 119 deletions
diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c index ca2dd4c..2b9b07e 100644 --- a/bfd/elf64-ppc.c +++ b/bfd/elf64-ppc.c @@ -11894,7 +11894,8 @@ static const unsigned char glink_eh_frame_cie[] = 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. */ + DW_CFA_def_cfa, 1, 0, /* def_cfa: r1 offset 0. */ + 0, 0, 0, 0 }; /* Stripping output sections is normally done before dynamic section @@ -12326,7 +12327,7 @@ ppc64_elf_size_stubs (struct bfd_link_info *info) stub_sec != NULL; stub_sec = stub_sec->next) if ((stub_sec->flags & SEC_LINKER_CREATED) == 0) - size += 20; + size += 24; if (htab->glink != NULL && htab->glink->size != 0) size += 24; if (size != 0) @@ -12366,6 +12367,89 @@ ppc64_elf_size_stubs (struct bfd_link_info *info) (*htab->params->layout_sections_again) (); } + if (htab->glink_eh_frame != NULL + && htab->glink_eh_frame->size != 0) + { + bfd_vma val; + bfd_byte *p, *last_fde; + size_t last_fde_len, size, align, pad; + asection *stub_sec; + + p = bfd_zalloc (htab->glink_eh_frame->owner, htab->glink_eh_frame->size); + if (p == NULL) + return FALSE; + htab->glink_eh_frame->contents = p; + last_fde = p; + + memcpy (p, glink_eh_frame_cie, sizeof (glink_eh_frame_cie)); + /* CIE length (rewrite in case little-endian). */ + last_fde_len = sizeof (glink_eh_frame_cie) - 4; + bfd_put_32 (htab->elf.dynobj, last_fde_len, p); + p += sizeof (glink_eh_frame_cie); + + for (stub_sec = htab->params->stub_bfd->sections; + stub_sec != NULL; + stub_sec = stub_sec->next) + if ((stub_sec->flags & SEC_LINKER_CREATED) == 0) + { + last_fde = p; + last_fde_len = 20; + /* 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 stub section, written later. */ + p += 4; + /* stub section size. */ + bfd_put_32 (htab->elf.dynobj, stub_sec->size, p); + p += 4; + /* Augmentation. */ + p += 1; + /* Pad. */ + p += 7; + } + if (htab->glink != NULL && htab->glink->size != 0) + { + last_fde = p; + last_fde_len = 20; + /* 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, written later. */ + p += 4; + /* .glink size. */ + bfd_put_32 (htab->elf.dynobj, htab->glink->size - 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; + } + /* Subsume any padding into the last FDE if user .eh_frame + sections are aligned more than glink_eh_frame. Otherwise any + zero padding will be seen as a terminator. */ + size = p - htab->glink_eh_frame->contents; + align = 1; + align <<= htab->glink_eh_frame->output_section->alignment_power; + align -= 1; + pad = ((size + align) & ~align) - size; + htab->glink_eh_frame->size = size + pad; + bfd_put_32 (htab->elf.dynobj, last_fde_len + pad, last_fde); + } + maybe_strip_output (info, htab->brlt); if (htab->glink_eh_frame != NULL) maybe_strip_output (info, htab->glink_eh_frame); @@ -12723,117 +12807,6 @@ ppc64_elf_build_stubs (struct bfd_link_info *info, return FALSE; } - if (htab->glink_eh_frame != NULL - && htab->glink_eh_frame->size != 0) - { - bfd_vma val; - bfd_byte *last_fde; - size_t last_fde_len, size, align, pad; - - p = bfd_zalloc (htab->glink_eh_frame->owner, htab->glink_eh_frame->size); - if (p == NULL) - return FALSE; - htab->glink_eh_frame->contents = p; - last_fde = 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). */ - last_fde_len = sizeof (glink_eh_frame_cie) - 4; - bfd_put_32 (htab->elf.dynobj, last_fde_len, p); - p += sizeof (glink_eh_frame_cie); - - for (stub_sec = htab->params->stub_bfd->sections; - stub_sec != NULL; - stub_sec = stub_sec->next) - if ((stub_sec->flags & SEC_LINKER_CREATED) == 0) - { - last_fde = p; - last_fde_len = 16; - /* 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 - (_("%P: %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) - { - last_fde = p; - last_fde_len = 20; - /* 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 - (_("%P: %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->size - 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; - } - /* Subsume any padding into the last FDE if user .eh_frame - sections are aligned more than glink_eh_frame. Otherwise any - zero padding will be seen as a terminator. */ - size = p - htab->glink_eh_frame->contents; - align = 1; - align <<= htab->glink_eh_frame->output_section->alignment_power; - align -= 1; - pad = ((size + align) & ~align) - size; - htab->glink_eh_frame->size = size + pad; - bfd_put_32 (htab->elf.dynobj, last_fde_len + pad, last_fde); - } - /* Build the stubs as directed by the stub hash table. */ bfd_hash_traverse (&htab->stub_hash_table, ppc_build_one_stub, info); @@ -12859,6 +12832,9 @@ ppc64_elf_build_stubs (struct bfd_link_info *info, break; } + /* Note that the glink_eh_frame check here is not only testing that + the generated size matched the calculated size but also that + bfd_elf_discard_info didn't make any changes to the section. */ if (stub_sec != NULL || (htab->glink_eh_frame != NULL && htab->glink_eh_frame->rawsize != htab->glink_eh_frame->size)) @@ -15126,13 +15102,81 @@ ppc64_elf_finish_dynamic_sections (bfd *output_bfd, NULL)) return FALSE; - if (htab->glink_eh_frame != NULL - && htab->glink_eh_frame->sec_info_type == SEC_INFO_TYPE_EH_FRAME - && !_bfd_elf_write_section_eh_frame (output_bfd, info, - htab->glink_eh_frame, - htab->glink_eh_frame->contents)) - return FALSE; + && htab->glink_eh_frame->size != 0) + { + bfd_vma val; + bfd_byte *p; + asection *stub_sec; + + p = htab->glink_eh_frame->contents + sizeof (glink_eh_frame_cie); + for (stub_sec = htab->params->stub_bfd->sections; + stub_sec != NULL; + stub_sec = stub_sec->next) + if ((stub_sec->flags & SEC_LINKER_CREATED) == 0) + { + /* FDE length. */ + p += 4; + /* CIE pointer. */ + 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 + + (p - htab->glink_eh_frame->contents)); + if (val + 0x80000000 > 0xffffffff) + { + info->callbacks->einfo + (_("%P: %s offset too large for .eh_frame sdata4 encoding"), + stub_sec->name); + return FALSE; + } + bfd_put_32 (dynobj, val, p); + p += 4; + /* stub section size. */ + p += 4; + /* Augmentation. */ + p += 1; + /* Pad. */ + p += 7; + } + if (htab->glink != NULL && htab->glink->size != 0) + { + /* FDE length. */ + p += 4; + /* CIE pointer. */ + 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 + + (p - htab->glink_eh_frame->contents)); + if (val + 0x80000000 > 0xffffffff) + { + info->callbacks->einfo + (_("%P: %s offset too large for .eh_frame sdata4 encoding"), + htab->glink->name); + return FALSE; + } + bfd_put_32 (dynobj, val, p); + p += 4; + /* .glink size. */ + p += 4; + /* Augmentation. */ + p += 1; + /* Ops. */ + p += 7; + } + + if (htab->glink_eh_frame->sec_info_type == SEC_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 |