diff options
Diffstat (limited to 'bfd/elf64-ppc.c')
-rw-r--r-- | bfd/elf64-ppc.c | 721 |
1 files changed, 429 insertions, 292 deletions
diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c index 33327f44cba9..0e4f725d1ffd 100644 --- a/bfd/elf64-ppc.c +++ b/bfd/elf64-ppc.c @@ -1,5 +1,5 @@ /* PowerPC64-specific support for 64-bit ELF. - Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 + Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc. Written by Linus Nordberg, Swox AB <info@swox.com>, based on elf32-ppc.c by Ian Lance Taylor. @@ -25,8 +25,9 @@ http://www.linuxbase.org/spec/ELF/ppc64/PPC-elf64abi.txt, and http://www.linuxbase.org/spec/ELF/ppc64/spec/book1.html */ -#include "bfd.h" #include "sysdep.h" +#include <stdarg.h> +#include "bfd.h" #include "bfdlink.h" #include "libbfd.h" #include "elf-bfd.h" @@ -61,6 +62,7 @@ static bfd_vma opd_entry_value #define ELF_ARCH bfd_arch_powerpc #define ELF_MACHINE_CODE EM_PPC64 #define ELF_MAXPAGESIZE 0x10000 +#define ELF_COMMONPAGESIZE 0x1000 #define elf_info_to_howto ppc64_elf_info_to_howto #define elf_backend_want_got_sym 0 @@ -71,9 +73,11 @@ static bfd_vma opd_entry_value #define elf_backend_can_gc_sections 1 #define elf_backend_can_refcount 1 #define elf_backend_rela_normal 1 +#define elf_backend_default_execstack 0 #define bfd_elf64_mkobject ppc64_elf_mkobject #define bfd_elf64_bfd_reloc_type_lookup ppc64_elf_reloc_type_lookup +#define bfd_elf64_bfd_reloc_name_lookup ppc64_elf_reloc_name_lookup #define bfd_elf64_bfd_merge_private_bfd_data ppc64_elf_merge_private_bfd_data #define bfd_elf64_new_section_hook ppc64_elf_new_section_hook #define bfd_elf64_bfd_link_hash_table_create ppc64_elf_link_hash_table_create @@ -83,10 +87,12 @@ static bfd_vma opd_entry_value #define elf_backend_object_p ppc64_elf_object_p #define elf_backend_grok_prstatus ppc64_elf_grok_prstatus #define elf_backend_grok_psinfo ppc64_elf_grok_psinfo +#define elf_backend_write_core_note ppc64_elf_write_core_note #define elf_backend_create_dynamic_sections ppc64_elf_create_dynamic_sections #define elf_backend_copy_indirect_symbol ppc64_elf_copy_indirect_symbol #define elf_backend_add_symbol_hook ppc64_elf_add_symbol_hook #define elf_backend_check_directives ppc64_elf_check_directives +#define elf_backend_as_needed_cleanup ppc64_elf_as_needed_cleanup #define elf_backend_archive_symbol_lookup ppc64_elf_archive_symbol_lookup #define elf_backend_check_relocs ppc64_elf_check_relocs #define elf_backend_gc_mark_dynamic_ref ppc64_elf_gc_mark_dynamic_ref @@ -96,6 +102,7 @@ static bfd_vma opd_entry_value #define elf_backend_hide_symbol ppc64_elf_hide_symbol #define elf_backend_always_size_sections ppc64_elf_func_desc_adjust #define elf_backend_size_dynamic_sections ppc64_elf_size_dynamic_sections +#define elf_backend_init_index_section _bfd_elf_init_2_index_sections #define elf_backend_action_discarded ppc64_elf_action_discarded #define elf_backend_relocate_section ppc64_elf_relocate_section #define elf_backend_finish_dynamic_symbol ppc64_elf_finish_dynamic_symbol @@ -134,30 +141,29 @@ static bfd_vma opd_entry_value #define BCTR 0x4e800420 /* bctr */ +#define ADDIS_R12_R12 0x3d8c0000 /* addis %r12,%r12,off@ha */ #define ADDIS_R2_R2 0x3c420000 /* addis %r2,%r2,off@ha */ #define ADDI_R2_R2 0x38420000 /* addi %r2,%r2,off@l */ #define LD_R2_40R1 0xe8410028 /* ld %r2,40(%r1) */ -/* glink call stub instructions. We enter with the index in R0, and the - address of glink entry in CTR. From that, we can calculate PLT0. */ +/* glink call stub instructions. We enter with the index in R0. */ #define GLINK_CALL_STUB_SIZE (16*4) -#define MFCTR_R12 0x7d8902a6 /* mfctr %r12 */ -#define SLDI_R11_R0_3 0x780b1f24 /* sldi %r11,%r0,3 */ -#define ADDIC_R2_R0_32K 0x34408000 /* addic. %r2,%r0,-32768 */ -#define SUB_R12_R12_R11 0x7d8b6050 /* sub %r12,%r12,%r11 */ -#define SRADI_R2_R2_63 0x7c42fe76 /* sradi %r2,%r2,63 */ -#define SLDI_R11_R0_2 0x780b1764 /* sldi %r11,%r0,2 */ -#define AND_R2_R2_R11 0x7c425838 /* and %r2,%r2,%r11 */ - /* sub %r12,%r12,%r11 */ -#define ADD_R12_R12_R2 0x7d8c1214 /* add %r12,%r12,%r2 */ -#define ADDIS_R12_R12 0x3d8c0000 /* addis %r12,%r12,xxx@ha */ - /* ld %r11,xxx@l(%r12) */ -#define ADDI_R12_R12 0x398c0000 /* addi %r12,%r12,xxx@l */ - /* ld %r2,8(%r12) */ - /* mtctr %r11 */ - /* ld %r11,16(%r12) */ - /* bctr */ + /* 0: */ + /* .quad plt0-1f */ + /* __glink: */ +#define MFLR_R12 0x7d8802a6 /* mflr %12 */ +#define BCL_20_31 0x429f0005 /* bcl 20,31,1f */ + /* 1: */ +#define MFLR_R11 0x7d6802a6 /* mflr %11 */ +#define LD_R2_M16R11 0xe84bfff0 /* ld %2,(0b-1b)(%11) */ +#define MTLR_R12 0x7d8803a6 /* mtlr %12 */ +#define ADD_R12_R2_R11 0x7d825a14 /* add %12,%2,%11 */ + /* ld %11,0(%12) */ + /* ld %2,8(%12) */ + /* mtctr %11 */ + /* ld %11,16(%12) */ + /* bctr */ /* Pad with this. */ #define NOP 0x60000000 @@ -1193,7 +1199,7 @@ static reloc_howto_type ppc64_elf_howto_raw[] = { /* Like R_PPC64_PLTGOT16, but for instructions with a DS field. */ /* FIXME: R_PPC64_PLTGOT16_DS not implemented. */ - HOWTO (R_PPC64_PLTGOT16_DS, /* type */ + HOWTO (R_PPC64_PLTGOT16_DS, /* type */ 0, /* rightshift */ 1, /* size (0 = byte, 1 = short, 2 = long) */ 16, /* bitsize */ @@ -2106,6 +2112,22 @@ ppc64_elf_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, return ppc64_elf_howto_table[r]; }; +static reloc_howto_type * +ppc64_elf_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, + const char *r_name) +{ + unsigned int i; + + for (i = 0; + i < sizeof (ppc64_elf_howto_raw) / sizeof (ppc64_elf_howto_raw[0]); + i++) + if (ppc64_elf_howto_raw[i].name != NULL + && strcasecmp (ppc64_elf_howto_raw[i].name, r_name) == 0) + return &ppc64_elf_howto_raw[i]; + + return NULL; +} + /* Set the howto pointer for a PowerPC ELF reloc. */ static void @@ -2376,14 +2398,9 @@ struct ppc64_elf_obj_tdata asection *got; asection *relgot; - union { - /* Used during garbage collection. We attach global symbols defined - on removed .opd entries to this section so that the sym is removed. */ - asection *deleted_section; - - /* Used when adding symbols. */ - bfd_boolean has_dotsym; - } u; + /* Used during garbage collection. We attach global symbols defined + on removed .opd entries to this section so that the sym is removed. */ + asection *deleted_section; /* TLS local dynamic got entry handling. Suppose for multiple GOT sections means we potentially need one of these for each input bfd. */ @@ -2407,11 +2424,14 @@ struct ppc64_elf_obj_tdata static bfd_boolean ppc64_elf_mkobject (bfd *abfd) { - bfd_size_type amt = sizeof (struct ppc64_elf_obj_tdata); - abfd->tdata.any = bfd_zalloc (abfd, amt); if (abfd->tdata.any == NULL) - return FALSE; - return TRUE; + { + bfd_size_type amt = sizeof (struct ppc64_elf_obj_tdata); + abfd->tdata.any = bfd_zalloc (abfd, amt); + if (abfd->tdata.any == NULL) + return FALSE; + } + return bfd_elf_mkobject (abfd); } /* Return 1 if target is one of ours. */ @@ -2484,6 +2504,53 @@ ppc64_elf_grok_psinfo (bfd *abfd, Elf_Internal_Note *note) return TRUE; } +static char * +ppc64_elf_write_core_note (bfd *abfd, char *buf, int *bufsiz, int note_type, + ...) +{ + switch (note_type) + { + default: + return NULL; + + case NT_PRPSINFO: + { + char data[136]; + va_list ap; + + va_start (ap, note_type); + memset (data, 0, 40); + strncpy (data + 40, va_arg (ap, const char *), 16); + strncpy (data + 56, va_arg (ap, const char *), 80); + va_end (ap); + return elfcore_write_note (abfd, buf, bufsiz, + "CORE", note_type, data, sizeof (data)); + } + + case NT_PRSTATUS: + { + char data[504]; + va_list ap; + long pid; + int cursig; + const void *greg; + + va_start (ap, note_type); + memset (data, 0, 112); + pid = va_arg (ap, long); + bfd_put_32 (abfd, pid, data + 32); + cursig = va_arg (ap, int); + bfd_put_16 (abfd, cursig, data + 12); + greg = va_arg (ap, const void *); + memcpy (data + 112, greg, 384); + memset (data + 496, 0, 8); + va_end (ap); + return elfcore_write_note (abfd, buf, bufsiz, + "CORE", note_type, data, sizeof (data)); + } + } +} + /* Merge backend specific data from an object file to the output object file when linking. */ @@ -2517,13 +2584,19 @@ ppc64_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd) static const struct bfd_elf_special_section ppc64_elf_special_sections[]= { - { ".plt", 4, 0, SHT_NOBITS, 0 }, - { ".sbss", 5, -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE }, - { ".sdata", 6, -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE }, - { ".toc", 4, 0, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE }, - { ".toc1", 5, 0, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE }, - { ".tocbss", 7, 0, SHT_NOBITS, SHF_ALLOC + SHF_WRITE }, - { NULL, 0, 0, 0, 0 } + { STRING_COMMA_LEN (".plt"), 0, SHT_NOBITS, 0 }, + { STRING_COMMA_LEN (".sbss"), -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE }, + { STRING_COMMA_LEN (".sdata"), -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE }, + { STRING_COMMA_LEN (".toc"), 0, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE }, + { STRING_COMMA_LEN (".toc1"), 0, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE }, + { STRING_COMMA_LEN (".tocbss"), 0, SHT_NOBITS, SHF_ALLOC + SHF_WRITE }, + { NULL, 0, 0, 0, 0 } +}; + +enum _ppc64_sec_type { + sec_normal = 0, + sec_opd = 1, + sec_toc = 2 }; struct _ppc64_elf_section_data @@ -2534,14 +2607,20 @@ struct _ppc64_elf_section_data union { /* Points to the function code section for local opd entries. */ - asection **func_sec; + asection **opd_func_sec; /* After editing .opd, adjust references to opd local syms. */ - long *adjust; - } opd; + long *opd_adjust; - /* An array for toc sections, indexed by offset/8. - Specifies the relocation symbol index used at a given toc offset. */ - unsigned *t_symndx; + /* An array for toc sections, indexed by offset/8. + Specifies the relocation symbol index used at a given toc offset. */ + unsigned *t_symndx; + } u; + + enum _ppc64_sec_type sec_type:2; + + /* Flag set when small branches are detected. Used to + select suitable defaults for the stub group size. */ + unsigned int has_14bit_branch:1; }; #define ppc64_elf_section_data(sec) \ @@ -2550,13 +2629,16 @@ struct _ppc64_elf_section_data static bfd_boolean ppc64_elf_new_section_hook (bfd *abfd, asection *sec) { - struct _ppc64_elf_section_data *sdata; - bfd_size_type amt = sizeof (*sdata); + if (!sec->used_by_bfd) + { + struct _ppc64_elf_section_data *sdata; + bfd_size_type amt = sizeof (*sdata); - sdata = bfd_zalloc (abfd, amt); - if (sdata == NULL) - return FALSE; - sec->used_by_bfd = sdata; + sdata = bfd_zalloc (abfd, amt); + if (sdata == NULL) + return FALSE; + sec->used_by_bfd = sdata; + } return _bfd_elf_new_section_hook (abfd, sec); } @@ -2566,8 +2648,8 @@ get_opd_info (asection * sec) { if (sec != NULL && ppc64_elf_section_data (sec) != NULL - && ppc64_elf_section_data (sec)->opd.adjust != NULL) - return ppc64_elf_section_data (sec)->opd.adjust; + && ppc64_elf_section_data (sec)->sec_type == sec_opd) + return ppc64_elf_section_data (sec)->u.opd_adjust; return NULL; } @@ -3234,9 +3316,14 @@ struct ppc_link_hash_entry { struct elf_link_hash_entry elf; - /* A pointer to the most recently used stub hash entry against this - symbol. */ - struct ppc_stub_hash_entry *stub_cache; + union { + /* A pointer to the most recently used stub hash entry against this + symbol. */ + struct ppc_stub_hash_entry *stub_cache; + + /* A pointer to the next symbol starting with a '.' */ + struct ppc_link_hash_entry *next_dot_sym; + } u; /* Track dynamic relocs copied for this symbol. */ struct ppc_dyn_relocs *dyn_relocs; @@ -3314,6 +3401,9 @@ struct ppc_link_hash_table /* Highest output section index. */ int top_index; + /* Used when adding symbols. */ + struct ppc_link_hash_entry *dot_syms; + /* List of input sections for each output section. */ asection **input_list; @@ -3348,10 +3438,6 @@ struct ppc_link_hash_table /* Set on error. */ unsigned int stub_error:1; - /* Flag set when small branches are detected. Used to - select suitable defaults for the stub group size. */ - unsigned int has_14bit_branch:1; - /* Temp used by ppc64_elf_check_directives. */ unsigned int twiddled_syms:1; @@ -3470,9 +3556,34 @@ link_hash_newfunc (struct bfd_hash_entry *entry, { struct ppc_link_hash_entry *eh = (struct ppc_link_hash_entry *) entry; - memset (&eh->stub_cache, 0, + memset (&eh->u.stub_cache, 0, (sizeof (struct ppc_link_hash_entry) - - offsetof (struct ppc_link_hash_entry, stub_cache))); + - offsetof (struct ppc_link_hash_entry, u.stub_cache))); + + /* When making function calls, old ABI code references function entry + points (dot symbols), while new ABI code references the function + descriptor symbol. We need to make any combination of reference and + definition work together, without breaking archive linking. + + For a defined function "foo" and an undefined call to "bar": + An old object defines "foo" and ".foo", references ".bar" (possibly + "bar" too). + A new object defines "foo" and references "bar". + + A new object thus has no problem with its undefined symbols being + satisfied by definitions in an old object. On the other hand, the + old object won't have ".bar" satisfied by a new object. + + Keep a list of newly added dot-symbols. */ + + if (string[0] == '.') + { + struct ppc_link_hash_table *htab; + + htab = (struct ppc_link_hash_table *) table; + eh->u.next_dot_sym = htab->dot_syms; + htab->dot_syms = eh; + } } return entry; @@ -3618,11 +3729,11 @@ ppc_get_stub_entry (const asection *input_section, distinguish between them. */ id_sec = htab->stub_group[input_section->id].link_sec; - if (h != NULL && h->stub_cache != NULL - && h->stub_cache->h == h - && h->stub_cache->id_sec == id_sec) + if (h != NULL && h->u.stub_cache != NULL + && h->u.stub_cache->h == h + && h->u.stub_cache->id_sec == id_sec) { - stub_entry = h->stub_cache; + stub_entry = h->u.stub_cache; } else { @@ -3635,7 +3746,7 @@ ppc_get_stub_entry (const asection *input_section, stub_entry = ppc_stub_hash_lookup (&htab->stub_hash_table, stub_name, FALSE, FALSE); if (h != NULL) - h->stub_cache = stub_entry; + h->u.stub_cache = stub_entry; free (stub_name); } @@ -3721,49 +3832,26 @@ create_linkage_sections (bfd *dynobj, struct bfd_link_info *info) htab->glink = bfd_make_section_anyway_with_flags (dynobj, ".glink", flags); if (htab->glink == NULL - || ! bfd_set_section_alignment (dynobj, htab->glink, 2)) + || ! bfd_set_section_alignment (dynobj, htab->glink, 3)) return FALSE; /* Create branch lookup table for plt_branch stubs. */ - if (info->shared) - { - flags = (SEC_ALLOC | SEC_LOAD - | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED); - htab->brlt - = bfd_make_section_anyway_with_flags (dynobj, ".data.rel.ro.brlt", - flags); - } - else - { - flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY - | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED); - htab->brlt - = bfd_make_section_anyway_with_flags (dynobj, ".rodata.brlt", flags); - } - + flags = (SEC_ALLOC | SEC_LOAD + | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED); + htab->brlt = bfd_make_section_anyway_with_flags (dynobj, ".branch_lt", + flags); if (htab->brlt == NULL || ! bfd_set_section_alignment (dynobj, htab->brlt, 3)) return FALSE; - if (info->shared) - { - flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY - | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED); - htab->relbrlt - = bfd_make_section_anyway_with_flags (dynobj, ".rela.data.rel.ro.brlt", - flags); - } - else if (info->emitrelocations) - { - flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY - | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED); - htab->relbrlt - = bfd_make_section_anyway_with_flags (dynobj, ".rela.rodata.brlt", - flags); - } - else + if (!info->shared) return TRUE; + flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY + | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED); + htab->relbrlt = bfd_make_section_anyway_with_flags (dynobj, + ".rela.branch_lt", + flags); if (!htab->relbrlt || ! bfd_set_section_alignment (dynobj, htab->relbrlt, 3)) return FALSE; @@ -4044,29 +4132,14 @@ make_fdh (struct bfd_link_info *info, return fdh; } -/* Hacks to support old ABI code. - When making function calls, old ABI code references function entry - points (dot symbols), while new ABI code references the function - descriptor symbol. We need to make any combination of reference and - definition work together, without breaking archive linking. - - For a defined function "foo" and an undefined call to "bar": - An old object defines "foo" and ".foo", references ".bar" (possibly - "bar" too). - A new object defines "foo" and references "bar". - - A new object thus has no problem with its undefined symbols being - satisfied by definitions in an old object. On the other hand, the - old object won't have ".bar" satisfied by a new object. */ - /* Fix function descriptor symbols defined in .opd sections to be function type. */ static bfd_boolean -ppc64_elf_add_symbol_hook (bfd *ibfd, +ppc64_elf_add_symbol_hook (bfd *ibfd ATTRIBUTE_UNUSED, struct bfd_link_info *info ATTRIBUTE_UNUSED, Elf_Internal_Sym *isym, - const char **name, + const char **name ATTRIBUTE_UNUSED, flagword *flags ATTRIBUTE_UNUSED, asection **sec, bfd_vma *value ATTRIBUTE_UNUSED) @@ -4075,12 +4148,6 @@ ppc64_elf_add_symbol_hook (bfd *ibfd, && strcmp (bfd_get_section_name (ibfd, *sec), ".opd") == 0) isym->st_info = ELF_ST_INFO (ELF_ST_BIND (isym->st_info), STT_FUNC); - if ((*name)[0] == '.' - && ELF_ST_BIND (isym->st_info) == STB_GLOBAL - && ELF_ST_TYPE (isym->st_info) < STT_SECTION - && is_ppc64_elf_target (ibfd->xvec)) - ppc64_elf_tdata (ibfd)->u.has_dotsym = 1; - return TRUE; } @@ -4129,35 +4196,25 @@ ppc64_elf_archive_symbol_lookup (bfd *abfd, most restrictive visibility of the function descriptor and the function entry symbol is used. */ -struct add_symbol_adjust_data -{ - struct bfd_link_info *info; - bfd_boolean ok; -}; - static bfd_boolean -add_symbol_adjust (struct elf_link_hash_entry *h, void *inf) +add_symbol_adjust (struct ppc_link_hash_entry *eh, struct bfd_link_info *info) { - struct add_symbol_adjust_data *data; struct ppc_link_hash_table *htab; - struct ppc_link_hash_entry *eh; struct ppc_link_hash_entry *fdh; - if (h->root.type == bfd_link_hash_indirect) + if (eh->elf.root.type == bfd_link_hash_indirect) return TRUE; - if (h->root.type == bfd_link_hash_warning) - h = (struct elf_link_hash_entry *) h->root.u.i.link; + if (eh->elf.root.type == bfd_link_hash_warning) + eh = (struct ppc_link_hash_entry *) eh->elf.root.u.i.link; - if (h->root.root.string[0] != '.') - return TRUE; + if (eh->elf.root.root.string[0] != '.') + abort (); - data = inf; - htab = ppc_hash_table (data->info); - eh = (struct ppc_link_hash_entry *) h; + htab = ppc_hash_table (info); fdh = get_fdh (eh, htab); if (fdh == NULL - && !data->info->relocatable + && !info->relocatable && (eh->elf.root.type == bfd_link_hash_undefined || eh->elf.root.type == bfd_link_hash_undefweak) && eh->elf.ref_regular) @@ -4165,9 +4222,9 @@ add_symbol_adjust (struct elf_link_hash_entry *h, void *inf) /* Make an undefweak function descriptor sym, which is enough to pull in an --as-needed shared lib, but won't cause link errors. Archives are handled elsewhere. */ - fdh = make_fdh (data->info, eh); + fdh = make_fdh (info, eh); if (fdh == NULL) - data->ok = FALSE; + return FALSE; else fdh->elf.ref_regular = 1; } @@ -4193,26 +4250,37 @@ add_symbol_adjust (struct elf_link_hash_entry *h, void *inf) return TRUE; } +/* Process list of dot-symbols we made in link_hash_newfunc. */ + static bfd_boolean -ppc64_elf_check_directives (bfd *abfd, struct bfd_link_info *info) +ppc64_elf_check_directives (bfd *ibfd, struct bfd_link_info *info) { struct ppc_link_hash_table *htab; - struct add_symbol_adjust_data data; - - if (!is_ppc64_elf_target (abfd->xvec)) - return TRUE; - - if (!ppc64_elf_tdata (abfd)->u.has_dotsym) - return TRUE; - ppc64_elf_tdata (abfd)->u.deleted_section = NULL; + struct ppc_link_hash_entry **p, *eh; htab = ppc_hash_table (info); if (!is_ppc64_elf_target (htab->elf.root.creator)) return TRUE; - data.info = info; - data.ok = TRUE; - elf_link_hash_traverse (&htab->elf, add_symbol_adjust, &data); + if (is_ppc64_elf_target (ibfd->xvec)) + { + p = &htab->dot_syms; + while ((eh = *p) != NULL) + { + *p = NULL; + if (!add_symbol_adjust (eh, info)) + return FALSE; + p = &eh->u.next_dot_sym; + } + } + + /* Clear the list for non-ppc64 input files. */ + p = &htab->dot_syms; + while ((eh = *p) != NULL) + { + *p = NULL; + p = &eh->u.next_dot_sym; + } /* We need to fix the undefs list for any syms we have twiddled to undef_weak. */ @@ -4221,7 +4289,18 @@ ppc64_elf_check_directives (bfd *abfd, struct bfd_link_info *info) bfd_link_repair_undef_list (&htab->elf.root); htab->twiddled_syms = 0; } - return data.ok; + return TRUE; +} + +/* Undo hash table changes when an --as-needed input file is determined + not to be needed. */ + +static bfd_boolean +ppc64_elf_as_needed_cleanup (bfd *ibfd ATTRIBUTE_UNUSED, + struct bfd_link_info *info) +{ + ppc_hash_table (info)->dot_syms = NULL; + return TRUE; } static bfd_boolean @@ -4358,7 +4437,9 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, opd_sym_map = bfd_zalloc (abfd, amt); if (opd_sym_map == NULL) return FALSE; - ppc64_elf_section_data (sec)->opd.func_sec = opd_sym_map; + ppc64_elf_section_data (sec)->u.opd_func_sec = opd_sym_map; + BFD_ASSERT (ppc64_elf_section_data (sec)->sec_type == sec_normal); + ppc64_elf_section_data (sec)->sec_type = sec_opd; } if (htab->sfpr == NULL @@ -4372,6 +4453,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, struct elf_link_hash_entry *h; enum elf_ppc64_reloc_type r_type; int tls_type = 0; + struct _ppc64_elf_section_data *ppc64_sec; r_symndx = ELF64_R_SYM (rel->r_info); if (r_symndx < symtab_hdr->sh_info) @@ -4553,7 +4635,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, dest = bfd_section_from_r_symndx (abfd, &htab->sym_sec, sec, r_symndx); if (dest != sec) - htab->has_14bit_branch = 1; + ppc64_elf_section_data (sec)->has_14bit_branch = 1; } /* Fall through. */ @@ -4569,7 +4651,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, || h == &htab->tls_get_addr_fd->elf) sec->has_tls_reloc = 1; else if (htab->tls_get_addr == NULL - && !strncmp (h->root.root.string, ".__tls_get_addr", 15) + && CONST_STRNEQ (h->root.root.string, ".__tls_get_addr") && (h->root.root.string[15] == 0 || h->root.root.string[15] == '@')) { @@ -4577,7 +4659,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, sec->has_tls_reloc = 1; } else if (htab->tls_get_addr_fd == NULL - && !strncmp (h->root.root.string, "__tls_get_addr", 14) + && CONST_STRNEQ (h->root.root.string, "__tls_get_addr") && (h->root.root.string[14] == 0 || h->root.root.string[14] == '@')) { @@ -4624,23 +4706,26 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, rel->r_addend, tls_type)) return FALSE; - if (ppc64_elf_section_data (sec)->t_symndx == NULL) + ppc64_sec = ppc64_elf_section_data (sec); + if (ppc64_sec->sec_type != sec_toc) { /* One extra to simplify get_tls_mask. */ bfd_size_type amt = sec->size * sizeof (unsigned) / 8 + 1; - ppc64_elf_section_data (sec)->t_symndx = bfd_zalloc (abfd, amt); - if (ppc64_elf_section_data (sec)->t_symndx == NULL) + ppc64_sec->u.t_symndx = bfd_zalloc (abfd, amt); + if (ppc64_sec->u.t_symndx == NULL) return FALSE; + BFD_ASSERT (ppc64_sec->sec_type == sec_normal); + ppc64_sec->sec_type = sec_toc; } BFD_ASSERT (rel->r_offset % 8 == 0); - ppc64_elf_section_data (sec)->t_symndx[rel->r_offset / 8] = r_symndx; + ppc64_sec->u.t_symndx[rel->r_offset / 8] = r_symndx; /* Mark the second slot of a GD or LD entry. -1 to indicate GD and -2 to indicate LD. */ if (tls_type == (TLS_EXPLICIT | TLS_TLS | TLS_GD)) - ppc64_elf_section_data (sec)->t_symndx[rel->r_offset / 8 + 1] = -1; + ppc64_sec->u.t_symndx[rel->r_offset / 8 + 1] = -1; else if (tls_type == (TLS_EXPLICIT | TLS_TLS | TLS_LD)) - ppc64_elf_section_data (sec)->t_symndx[rel->r_offset / 8 + 1] = -2; + ppc64_sec->u.t_symndx[rel->r_offset / 8 + 1] = -2; goto dodyn; case R_PPC64_TPREL16: @@ -4770,7 +4855,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, if (name == NULL) return FALSE; - if (strncmp (name, ".rela", 5) != 0 + if (! CONST_STRNEQ (name, ".rela") || strcmp (bfd_get_section_name (abfd, sec), name + 5) != 0) { @@ -5714,7 +5799,6 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info, { struct ppc_link_hash_table *htab; asection *s; - unsigned int power_of_two; htab = ppc_hash_table (info); @@ -5766,6 +5850,10 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info, if (!h->non_got_ref) return TRUE; + /* Don't generate a copy reloc for symbols defined in the executable. */ + if (!h->def_dynamic || !h->ref_regular || h->def_regular) + return TRUE; + if (ELIMINATE_COPY_RELOCS) { struct ppc_link_hash_entry * eh; @@ -5831,29 +5919,9 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info, h->needs_copy = 1; } - /* We need to figure out the alignment required for this symbol. I - have no idea how ELF linkers handle this. */ - power_of_two = bfd_log2 (h->size); - if (power_of_two > 4) - power_of_two = 4; - - /* Apply the required alignment. */ s = htab->dynbss; - s->size = BFD_ALIGN (s->size, (bfd_size_type) (1 << power_of_two)); - if (power_of_two > bfd_get_section_alignment (htab->elf.dynobj, s)) - { - if (! bfd_set_section_alignment (htab->elf.dynobj, s, power_of_two)) - return FALSE; - } - /* Define the symbol as being at this point in the section. */ - h->root.u.def.section = s; - h->root.u.def.value = s->size; - - /* Increment the section size to make room for the symbol. */ - s->size += h->size; - - return TRUE; + return _bfd_elf_adjust_dynamic_copy (h, s); } /* If given a function descriptor symbol, hide both the function code @@ -6036,7 +6104,7 @@ get_tls_mask (char **tls_maskp, unsigned long *toc_symndx, if ((*tls_maskp != NULL && **tls_maskp != 0) || sec == NULL - || ppc64_elf_section_data (sec)->t_symndx == NULL) + || ppc64_elf_section_data (sec)->sec_type != sec_toc) return 1; /* Look inside a TOC section too. */ @@ -6049,8 +6117,8 @@ get_tls_mask (char **tls_maskp, unsigned long *toc_symndx, off = sym->st_value; off += rel->r_addend; BFD_ASSERT (off % 8 == 0); - r_symndx = ppc64_elf_section_data (sec)->t_symndx[off / 8]; - next_r = ppc64_elf_section_data (sec)->t_symndx[off / 8 + 1]; + r_symndx = ppc64_elf_section_data (sec)->u.t_symndx[off / 8]; + next_r = ppc64_elf_section_data (sec)->u.t_symndx[off / 8 + 1]; if (!get_sym_h (&h, &sym, &sec, tls_maskp, locsymsp, r_symndx, ibfd)) return 0; if (toc_symndx != NULL) @@ -6096,13 +6164,13 @@ adjust_opd_syms (struct elf_link_hash_entry *h, void *inf ATTRIBUTE_UNUSED) if (adjust == -1) { /* This entry has been deleted. */ - asection *dsec = ppc64_elf_tdata (sym_sec->owner)->u.deleted_section; + asection *dsec = ppc64_elf_tdata (sym_sec->owner)->deleted_section; if (dsec == NULL) { for (dsec = sym_sec->owner->sections; dsec; dsec = dsec->next) if (elf_discarded_section (dsec)) { - ppc64_elf_tdata (sym_sec->owner)->u.deleted_section = dsec; + ppc64_elf_tdata (sym_sec->owner)->deleted_section = dsec; break; } } @@ -6291,7 +6359,9 @@ ppc64_elf_edit_opd (bfd *obfd, struct bfd_link_info *info, opd_adjust = bfd_alloc (obfd, amt); if (opd_adjust == NULL) return FALSE; - ppc64_elf_section_data (sec)->opd.adjust = opd_adjust; + ppc64_elf_section_data (sec)->u.opd_adjust = opd_adjust; + BFD_ASSERT (ppc64_elf_section_data (sec)->sec_type == sec_normal); + ppc64_elf_section_data (sec)->sec_type = sec_opd; } memset (opd_adjust, 0, amt); @@ -6601,7 +6671,7 @@ ppc64_elf_edit_opd (bfd *obfd, struct bfd_link_info *info, sec->contents = new_contents; } - /* Fudge the size too, as this is used later in + /* Fudge the header size too, as this is used later in elf_bfd_final_link if we are emitting relocs. */ elf_section_data (sec)->rel_hdr.sh_size = sec->reloc_count * elf_section_data (sec)->rel_hdr.sh_entsize; @@ -7907,7 +7977,7 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, /* Strip this section if we don't need it; see the comment below. */ } - else if (strncmp (bfd_get_section_name (dynobj, s), ".rela", 5) == 0) + else if (CONST_STRNEQ (bfd_get_section_name (dynobj, s), ".rela")) { if (s->size != 0) { @@ -8302,6 +8372,33 @@ ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) rl += htab->relbrlt->reloc_count++ * sizeof (Elf64_External_Rela); bfd_elf64_swap_reloca_out (htab->relbrlt->owner, &rela, rl); } + else if (info->emitrelocations) + { + Elf_Internal_Rela *relocs, *r; + struct bfd_elf_section_data *elfsec_data; + + elfsec_data = elf_section_data (htab->brlt); + relocs = elfsec_data->relocs; + if (relocs == NULL) + { + bfd_size_type relsize; + relsize = htab->brlt->reloc_count * sizeof (*relocs); + relocs = bfd_alloc (htab->brlt->owner, relsize); + if (relocs == NULL) + return FALSE; + elfsec_data->relocs = relocs; + elfsec_data->rel_hdr.sh_size = relsize; + elfsec_data->rel_hdr.sh_entsize = 24; + htab->brlt->reloc_count = 0; + } + r = relocs + htab->brlt->reloc_count; + htab->brlt->reloc_count += 1; + r->r_offset = (br_entry->offset + + htab->brlt->output_offset + + htab->brlt->output_section->vma); + r->r_info = ELF64_R_INFO (0, R_PPC64_RELATIVE); + r->r_addend = off; + } off = (br_entry->offset + htab->brlt->output_offset @@ -8531,6 +8628,11 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) if (htab->relbrlt != NULL) htab->relbrlt->size += sizeof (Elf64_External_Rela); + else if (info->emitrelocations) + { + htab->brlt->reloc_count += 1; + htab->brlt->flags |= SEC_RELOC; + } } stub_entry->stub_type += ppc_stub_plt_branch - ppc_stub_long_branch; @@ -8538,11 +8640,11 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) if (stub_entry->stub_type != ppc_stub_plt_branch) size = 28; } - - if (info->emitrelocations - && (stub_entry->stub_type == ppc_stub_long_branch - || stub_entry->stub_type == ppc_stub_long_branch_r2off)) - stub_entry->stub_sec->reloc_count += 1; + else if (info->emitrelocations) + { + stub_entry->stub_sec->reloc_count += 1; + stub_entry->stub_sec->flags |= SEC_RELOC; + } } stub_entry->stub_sec->size += size; @@ -8925,7 +9027,29 @@ group_sections (struct ppc_link_hash_table *htab, bfd_size_type stub_group_size, bfd_boolean stubs_always_before_branch) { - asection **list = htab->input_list + htab->top_index; + asection **list; + bfd_size_type stub14_group_size; + bfd_boolean suppress_size_errors; + + suppress_size_errors = FALSE; + stub14_group_size = stub_group_size; + if (stub_group_size == 1) + { + /* Default values. */ + if (stubs_always_before_branch) + { + stub_group_size = 0x1e00000; + stub14_group_size = 0x7800; + } + else + { + stub_group_size = 0x1c00000; + stub14_group_size = 0x7000; + } + suppress_size_errors = TRUE; + } + + list = htab->input_list + htab->top_index; do { asection *tail = *list; @@ -8939,15 +9063,17 @@ group_sections (struct ppc_link_hash_table *htab, curr = tail; total = tail->size; - big_sec = total > stub_group_size; - if (big_sec) + big_sec = total > (ppc64_elf_section_data (tail)->has_14bit_branch + ? stub14_group_size : stub_group_size); + if (big_sec && !suppress_size_errors) (*_bfd_error_handler) (_("%B section %A exceeds stub group size"), tail->owner, tail); curr_toc = htab->stub_group[tail->id].toc_off; while ((prev = PREV_SEC (curr)) != NULL && ((total += curr->output_offset - prev->output_offset) - < stub_group_size) + < (ppc64_elf_section_data (prev)->has_14bit_branch + ? stub14_group_size : stub_group_size)) && htab->stub_group[prev->id].toc_off == curr_toc) curr = prev; @@ -8979,7 +9105,8 @@ group_sections (struct ppc_link_hash_table *htab, total = 0; while (prev != NULL && ((total += tail->output_offset - prev->output_offset) - < stub_group_size) + < (ppc64_elf_section_data (prev)->has_14bit_branch + ? stub14_group_size : stub_group_size)) && htab->stub_group[prev->id].toc_off == curr_toc) { tail = prev; @@ -9020,22 +9147,6 @@ ppc64_elf_size_stubs (bfd *output_bfd, stub_group_size = -group_size; else stub_group_size = group_size; - if (stub_group_size == 1) - { - /* Default values. */ - if (stubs_always_before_branch) - { - stub_group_size = 0x1e00000; - if (htab->has_14bit_branch) - stub_group_size = 0x7800; - } - else - { - stub_group_size = 0x1c00000; - if (htab->has_14bit_branch) - stub_group_size = 0x7000; - } - } group_sections (htab, stub_group_size, stubs_always_before_branch); @@ -9073,6 +9184,9 @@ ppc64_elf_size_stubs (bfd *output_bfd, /* If there aren't any relocs, then there's nothing more to do. */ if ((section->flags & SEC_RELOC) == 0 + || (section->flags & SEC_ALLOC) == 0 + || (section->flags & SEC_LOAD) == 0 + || (section->flags & SEC_CODE) == 0 || section->reloc_count == 0) continue; @@ -9322,9 +9436,12 @@ ppc64_elf_size_stubs (bfd *output_bfd, stub_sec->rawsize = stub_sec->size; stub_sec->size = 0; stub_sec->reloc_count = 0; + stub_sec->flags &= ~SEC_RELOC; } htab->brlt->size = 0; + htab->brlt->reloc_count = 0; + htab->brlt->flags &= ~SEC_RELOC; if (htab->relbrlt != NULL) htab->relbrlt->size = 0; @@ -9442,24 +9559,12 @@ ppc64_elf_build_stubs (bfd_boolean emit_stub_syms, stub_sec->size = 0; } - if (htab->plt != NULL) + if (htab->glink != NULL && htab->glink->size != 0) { unsigned int indx; bfd_vma plt0; /* Build the .glink plt call stub. */ - plt0 = (htab->plt->output_section->vma - + htab->plt->output_offset - - (htab->glink->output_section->vma - + htab->glink->output_offset - + GLINK_CALL_STUB_SIZE)); - if (plt0 + 0x80008000 > 0xffffffff) - { - (*_bfd_error_handler) (_(".glink and .plt too far apart")); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } - if (htab->emit_stub_syms) { struct elf_link_hash_entry *h; @@ -9470,7 +9575,7 @@ ppc64_elf_build_stubs (bfd_boolean emit_stub_syms, { h->root.type = bfd_link_hash_defined; h->root.u.def.section = htab->glink; - h->root.u.def.value = 0; + h->root.u.def.value = 8; h->ref_regular = 1; h->def_regular = 1; h->ref_regular_nonweak = 1; @@ -9479,29 +9584,26 @@ ppc64_elf_build_stubs (bfd_boolean emit_stub_syms, } } p = htab->glink->contents; - bfd_put_32 (htab->glink->owner, MFCTR_R12, p); - p += 4; - bfd_put_32 (htab->glink->owner, SLDI_R11_R0_3, p); - p += 4; - bfd_put_32 (htab->glink->owner, ADDIC_R2_R0_32K, p); - p += 4; - bfd_put_32 (htab->glink->owner, SUB_R12_R12_R11, p); - p += 4; - bfd_put_32 (htab->glink->owner, SRADI_R2_R2_63, p); - p += 4; - bfd_put_32 (htab->glink->owner, SLDI_R11_R0_2, p); + plt0 = (htab->plt->output_section->vma + + htab->plt->output_offset + - (htab->glink->output_section->vma + + htab->glink->output_offset + + 16)); + bfd_put_64 (htab->glink->owner, plt0, p); + p += 8; + bfd_put_32 (htab->glink->owner, MFLR_R12, p); p += 4; - bfd_put_32 (htab->glink->owner, AND_R2_R2_R11, p); + bfd_put_32 (htab->glink->owner, BCL_20_31, p); p += 4; - bfd_put_32 (htab->glink->owner, SUB_R12_R12_R11, p); + bfd_put_32 (htab->glink->owner, MFLR_R11, p); p += 4; - bfd_put_32 (htab->glink->owner, ADD_R12_R12_R2, p); + bfd_put_32 (htab->glink->owner, LD_R2_M16R11, p); p += 4; - bfd_put_32 (htab->glink->owner, ADDIS_R12_R12 | PPC_HA (plt0), p); + bfd_put_32 (htab->glink->owner, MTLR_R12, p); p += 4; - bfd_put_32 (htab->glink->owner, LD_R11_0R12 | PPC_LO (plt0), p); + bfd_put_32 (htab->glink->owner, ADD_R12_R2_R11, p); p += 4; - bfd_put_32 (htab->glink->owner, ADDI_R12_R12 | PPC_LO (plt0), p); + bfd_put_32 (htab->glink->owner, LD_R11_0R12, p); p += 4; bfd_put_32 (htab->glink->owner, LD_R2_0R12 | 8, p); p += 4; @@ -9511,6 +9613,11 @@ ppc64_elf_build_stubs (bfd_boolean emit_stub_syms, p += 4; bfd_put_32 (htab->glink->owner, BCTR, p); p += 4; + while (p - htab->glink->contents < GLINK_CALL_STUB_SIZE) + { + bfd_put_32 (htab->glink->owner, NOP, p); + p += 4; + } /* Build the .glink lazy link call stubs. */ indx = 0; @@ -9529,7 +9636,7 @@ ppc64_elf_build_stubs (bfd_boolean emit_stub_syms, p += 4; } bfd_put_32 (htab->glink->owner, - B_DOT | ((htab->glink->contents - p) & 0x3fffffc), p); + B_DOT | ((htab->glink->contents - p + 8) & 0x3fffffc), p); indx++; p += 4; } @@ -9554,6 +9661,9 @@ ppc64_elf_build_stubs (bfd_boolean emit_stub_syms, /* Build the stubs as directed by the stub hash table. */ bfd_hash_traverse (&htab->stub_hash_table, ppc_build_one_stub, info); + if (htab->relbrlt != NULL) + htab->relbrlt->reloc_count = 0; + for (stub_sec = htab->stub_bfd->sections; stub_sec != NULL; stub_sec = stub_sec->next) @@ -9695,6 +9805,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, bfd_boolean is_opd; /* Disabled until we sort out how ld should choose 'y' vs 'at'. */ bfd_boolean is_power4 = FALSE; + bfd_vma d_offset = (bfd_big_endian (output_bfd) ? 2 : 0); /* Initialize howto table if needed. */ if (!ppc64_elf_howto_table[R_PPC64_ADDR32]) @@ -9710,7 +9821,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, TOCstart = elf_gp (output_bfd); symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; sym_hashes = elf_sym_hashes (input_bfd); - is_opd = ppc64_elf_section_data (input_section)->opd.adjust != NULL; + is_opd = ppc64_elf_section_data (input_section)->sec_type == sec_opd; rel = relocs; relend = relocs + input_section->reloc_count; @@ -9785,13 +9896,9 @@ ppc64_elf_relocate_section (bfd *output_bfd, relocation += adjust; } } - if (info->relocatable) - continue; } else { - if (info->relocatable) - continue; RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, r_symndx, symtab_hdr, sym_hashes, h_elf, sec, relocation, @@ -9801,6 +9908,21 @@ ppc64_elf_relocate_section (bfd *output_bfd, } h = (struct ppc_link_hash_entry *) h_elf; + if (sec != NULL && elf_discarded_section (sec)) + { + /* For relocs against symbols from removed linkonce sections, + or sections discarded by a linker script, we just want the + section contents zeroed. Avoid any special processing. */ + _bfd_clear_contents (ppc64_elf_howto_table[r_type], input_bfd, + contents + rel->r_offset); + rel->r_info = 0; + rel->r_addend = 0; + continue; + } + + if (info->relocatable) + continue; + /* TLS optimizations. Replace instruction sequences and relocs based on information we collected in tls_optimize. We edit RELOCS so that --emit-relocs will output something sensible @@ -9924,10 +10046,10 @@ ppc64_elf_relocate_section (bfd *output_bfd, && (tls_mask & TLS_TPREL) == 0) { toctprel: - insn = bfd_get_32 (output_bfd, contents + rel->r_offset - 2); + insn = bfd_get_32 (output_bfd, contents + rel->r_offset - d_offset); insn &= 31 << 21; insn |= 0x3c0d0000; /* addis 0,13,0 */ - bfd_put_32 (output_bfd, insn, contents + rel->r_offset - 2); + bfd_put_32 (output_bfd, insn, contents + rel->r_offset - d_offset); r_type = R_PPC64_TPREL16_HA; if (toc_symndx != 0) { @@ -9979,8 +10101,8 @@ ppc64_elf_relocate_section (bfd *output_bfd, insn |= rtra; bfd_put_32 (output_bfd, insn, contents + rel->r_offset); /* Was PPC64_TLS which sits on insn boundary, now - PPC64_TPREL16_LO which is at insn+2. */ - rel->r_offset += 2; + PPC64_TPREL16_LO which is at low-order half-word. */ + rel->r_offset += d_offset; r_type = R_PPC64_TPREL16_LO; if (toc_symndx != 0) { @@ -10013,7 +10135,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, else { bfd_put_32 (output_bfd, NOP, contents + rel->r_offset); - rel->r_offset -= 2; + rel->r_offset -= d_offset; r_type = R_PPC64_NONE; } rel->r_info = ELF64_R_INFO (r_symndx, r_type); @@ -10062,7 +10184,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, /* OK, it checks out. Replace the call. */ offset = rel[1].r_offset; insn1 = bfd_get_32 (output_bfd, - contents + rel->r_offset - 2); + contents + rel->r_offset - d_offset); insn3 = bfd_get_32 (output_bfd, contents + offset + 4); if ((tls_mask & tls_gd) != 0) @@ -10097,7 +10219,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, rel->r_info = ELF64_R_INFO (r_symndx, r_type); rel[1].r_info = ELF64_R_INFO (r_symndx, R_PPC64_TPREL16_LO); - rel[1].r_offset += 2; + rel[1].r_offset += d_offset; } if (insn3 == NOP || insn3 == CROR_151515 || insn3 == CROR_313131) @@ -10106,7 +10228,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, insn2 = NOP; rel[1].r_offset += 4; } - bfd_put_32 (output_bfd, insn1, contents + rel->r_offset - 2); + bfd_put_32 (output_bfd, insn1, contents + rel->r_offset - d_offset); bfd_put_32 (output_bfd, insn2, contents + offset); bfd_put_32 (output_bfd, insn3, contents + offset + 4); if (tls_gd == 0 || toc_symndx != 0) @@ -10620,7 +10742,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, relocation += htab->stub_group[sec->id].toc_off; else unresolved_reloc = TRUE; - goto dodyn2; + goto dodyn; /* TOC16 relocs. We want the offset relative to the TOC base, which is the address of the start of the TOC plus 0x8000. @@ -10720,15 +10842,7 @@ ppc64_elf_relocate_section (bfd *output_bfd, case R_PPC64_UADDR16: case R_PPC64_UADDR32: case R_PPC64_UADDR64: - /* r_symndx will be zero only for relocs against symbols - from removed linkonce sections, or sections discarded by - a linker script. */ dodyn: - if (r_symndx == 0) - break; - /* Fall thru. */ - - dodyn2: if ((input_section->flags & SEC_ALLOC) == 0) break; @@ -10838,6 +10952,17 @@ ppc64_elf_relocate_section (bfd *output_bfd, osec = sec->output_section; indx = elf_section_data (osec)->dynindx; + if (indx == 0) + { + if ((osec->flags & SEC_READONLY) == 0 + && htab->elf.data_index_section != NULL) + osec = htab->elf.data_index_section; + else + osec = htab->elf.text_index_section; + indx = elf_section_data (osec)->dynindx; + } + BFD_ASSERT (indx != 0); + /* We are turning this relocation into one against a section symbol, so subtract out the output section's address but not the @@ -10926,17 +11051,10 @@ ppc64_elf_relocate_section (bfd *output_bfd, case R_PPC64_ADDR16_HA: case R_PPC64_ADDR16_HIGHERA: case R_PPC64_ADDR16_HIGHESTA: - case R_PPC64_GOT16_HA: - case R_PPC64_PLTGOT16_HA: - case R_PPC64_PLT16_HA: case R_PPC64_TOC16_HA: case R_PPC64_SECTOFF_HA: case R_PPC64_TPREL16_HA: case R_PPC64_DTPREL16_HA: - case R_PPC64_GOT_TLSGD16_HA: - case R_PPC64_GOT_TLSLD16_HA: - case R_PPC64_GOT_TPREL16_HA: - case R_PPC64_GOT_DTPREL16_HA: case R_PPC64_TPREL16_HIGHER: case R_PPC64_TPREL16_HIGHERA: case R_PPC64_TPREL16_HIGHEST: @@ -10949,10 +11067,20 @@ ppc64_elf_relocate_section (bfd *output_bfd, that's not actually defined anywhere. In that case, 'sec' would be NULL, and we should leave the symbol alone (it will be set to zero elsewhere in the link). */ - if (sec != NULL) - /* Add 0x10000 if sign bit in 0:15 is set. - Bits 0:15 are not used. */ - addend += 0x8000; + if (sec == NULL) + break; + /* Fall thru */ + + case R_PPC64_GOT16_HA: + case R_PPC64_PLTGOT16_HA: + case R_PPC64_PLT16_HA: + case R_PPC64_GOT_TLSGD16_HA: + case R_PPC64_GOT_TLSLD16_HA: + case R_PPC64_GOT_TPREL16_HA: + case R_PPC64_GOT_DTPREL16_HA: + /* Add 0x10000 if sign bit in 0:15 is set. + Bits 0:15 are not used. */ + addend += 0x8000; break; case R_PPC64_ADDR16_DS: @@ -11125,13 +11253,11 @@ ppc64_elf_finish_dynamic_symbol (bfd *output_bfd, Elf_Internal_Sym *sym) { struct ppc_link_hash_table *htab; - bfd *dynobj; struct plt_entry *ent; Elf_Internal_Rela rela; bfd_byte *loc; htab = ppc_hash_table (info); - dynobj = htab->elf.dynobj; for (ent = h->plt.plist; ent != NULL; ent = ent->next) if (ent->plt.offset != (bfd_vma) -1) @@ -11328,6 +11454,17 @@ ppc64_elf_finish_dynamic_sections (bfd *output_bfd, = PLT_ENTRY_SIZE; } + /* brlt is SEC_LINKER_CREATED, so we need to write out relocs for + brlt ourselves if emitrelocations. */ + if (htab->brlt != NULL + && htab->brlt->reloc_count != 0 + && !_bfd_elf_link_output_relocs (output_bfd, + htab->brlt, + &elf_section_data (htab->brlt)->rel_hdr, + elf_section_data (htab->brlt)->relocs, + NULL)) + 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. */ |