From 4c52953f842d38d197bc283e1f6b635bd8050bf2 Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Thu, 6 Jan 2005 09:03:56 +0000 Subject: [PATCH] bfd/ * elf64-ppc.c (struct ppc_link_hash_table): Add no_multi_toc and multi_toc_needed. (has_toc_reloc, makes_toc_func_call, call_check_in_progress): Define. (ppc64_elf_check_relocs): Update references to has_gp_reloc. (ppc64_elf_setup_section_lists): Add no_multi_toc parm, set htab bit. (ppc64_elf_next_toc_section): Heed no_multi_toc. (ppc64_elf_reinit_toc): Set multi_toc_needed. (toc_adjusting_stub_needed): Rewrite. (ppc64_elf_next_input_section): Use multi_toc_needed to shortcut toc tests. Adjust for toc_adjusting_stub_needed changes. (ppc64_elf_size_stubs): Update references to has_gp_reloc. * elf64-ppc.h (ppc64_elf_setup_section_lists): Update prototype. * section.c: Expand comment on backend bits. * bfd-in2.h: Regenerate. * libbfd.h: Regenerate. ld/ * emultempl/ppc64elf.em (no_multi_toc): New var. (gld${EMULATION_NAME}_finish): Pass to ppc64_elf_setup_section_lists. (OPTION_NO_MULTI_TOC): Define. (PARSE_AND_LIST_LONGOPTS): Add --no-multi-toc support. (PARSE_AND_LIST_OPTIONS, PARSE_AND_LIST_ARGS_CASES): Likewise. --- bfd/ChangeLog | 20 ++- bfd/bfd-in2.h | 3 +- bfd/elf64-ppc.c | 268 +++++++++++++++++++++++++++++++-------- bfd/elf64-ppc.h | 2 +- bfd/libbfd.h | 3 + bfd/section.c | 3 +- ld/ChangeLog | 12 +- ld/emultempl/ppc64elf.em | 17 ++- 8 files changed, 266 insertions(+), 62 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index f2fc03471ee..343d6d00e6d 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,21 @@ +2005-01-06 Alan Modra + + * elf64-ppc.c (struct ppc_link_hash_table): Add no_multi_toc and + multi_toc_needed. + (has_toc_reloc, makes_toc_func_call, call_check_in_progress): Define. + (ppc64_elf_check_relocs): Update references to has_gp_reloc. + (ppc64_elf_setup_section_lists): Add no_multi_toc parm, set htab bit. + (ppc64_elf_next_toc_section): Heed no_multi_toc. + (ppc64_elf_reinit_toc): Set multi_toc_needed. + (toc_adjusting_stub_needed): Rewrite. + (ppc64_elf_next_input_section): Use multi_toc_needed to shortcut + toc tests. Adjust for toc_adjusting_stub_needed changes. + (ppc64_elf_size_stubs): Update references to has_gp_reloc. + * elf64-ppc.h (ppc64_elf_setup_section_lists): Update prototype. + * section.c: Expand comment on backend bits. + * bfd-in2.h: Regenerate. + * libbfd.h: Regenerate. + 2005-01-06 Alan Modra * elf64-ppc.c (ppc64_elf_size_stubs): When determining need for @@ -36,7 +54,7 @@ Add 'base' argument for constructing register sections. Reformat. (elfcore_grok_nto_note): Call elfcore_grok_nto_regs for both gp and fp regs. Reformat. - + 2004-12-22 Klaus Rudolph * reloc.c: Add new relocs R_AVR_LDI, R_AVR_6, R_AVR_6_ADIW. diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h index dd1a7eef144..bc497ca6f3d 100644 --- a/bfd/bfd-in2.h +++ b/bfd/bfd-in2.h @@ -1269,7 +1269,8 @@ typedef struct bfd_section /* Nonzero if this section uses RELA relocations, rather than REL. */ unsigned int use_rela_p:1; - /* Bits used by various backends. */ + /* Bits used by various backends. The generic code doesn't touch + these fields. */ /* Nonzero if this section has TLS related relocations. */ unsigned int has_tls_reloc:1; diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c index 6366141f5fb..982c0894032 100644 --- a/bfd/elf64-ppc.c +++ b/bfd/elf64-ppc.c @@ -3301,6 +3301,10 @@ struct ppc_link_hash_table /* Set if we should emit symbols for stubs. */ unsigned int emit_stub_syms:1; + /* Support for multiple toc sections. */ + unsigned int no_multi_toc:1; + unsigned int multi_toc_needed:1; + /* Set on error. */ unsigned int stub_error:1; @@ -3318,6 +3322,12 @@ struct ppc_link_hash_table struct sym_sec_cache sym_sec; }; +/* Rename some of the generic section flags to better document how they + are used here. */ +#define has_toc_reloc has_gp_reloc +#define makes_toc_func_call need_finalize_relax +#define call_check_in_progress reloc_done + /* Get the ppc64 ELF linker hash table from a link_info structure. */ #define ppc_hash_table(p) \ @@ -4285,7 +4295,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, case R_PPC64_GOT16_LO: case R_PPC64_GOT16_LO_DS: /* This symbol requires a global offset table entry. */ - sec->has_gp_reloc = 1; + sec->has_toc_reloc = 1; if (ppc64_elf_tdata (abfd)->got == NULL && !create_got_section (abfd, info)) return FALSE; @@ -4375,7 +4385,7 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, case R_PPC64_TOC16_HA: case R_PPC64_TOC16_DS: case R_PPC64_TOC16_LO_DS: - sec->has_gp_reloc = 1; + sec->has_toc_reloc = 1; break; /* This relocation describes the C++ object vtable hierarchy. @@ -8131,7 +8141,9 @@ ppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) 0 when no stubs will be needed, and 1 on success. */ int -ppc64_elf_setup_section_lists (bfd *output_bfd, struct bfd_link_info *info) +ppc64_elf_setup_section_lists (bfd *output_bfd, + struct bfd_link_info *info, + int no_multi_toc) { bfd *input_bfd; int top_id, top_index, id; @@ -8140,6 +8152,8 @@ ppc64_elf_setup_section_lists (bfd *output_bfd, struct bfd_link_info *info) bfd_size_type amt; struct ppc_link_hash_table *htab = ppc_hash_table (info); + htab->no_multi_toc = no_multi_toc; + if (htab->brlt == NULL) return 0; @@ -8199,25 +8213,30 @@ void ppc64_elf_next_toc_section (struct bfd_link_info *info, asection *isec) { struct ppc_link_hash_table *htab = ppc_hash_table (info); - bfd_vma addr = isec->output_offset + isec->output_section->vma; - bfd_vma off = addr - htab->toc_curr; - if (off + isec->size > 0x10000) - htab->toc_curr = addr; + if (!htab->no_multi_toc) + { + bfd_vma addr = isec->output_offset + isec->output_section->vma; + bfd_vma off = addr - htab->toc_curr; + + if (off + isec->size > 0x10000) + htab->toc_curr = addr; - elf_gp (isec->owner) = (htab->toc_curr - - elf_gp (isec->output_section->owner) - + TOC_BASE_OFF); + elf_gp (isec->owner) = (htab->toc_curr + - elf_gp (isec->output_section->owner) + + TOC_BASE_OFF); + } } /* Called after the last call to the above function. */ void -ppc64_elf_reinit_toc (bfd *output_bfd ATTRIBUTE_UNUSED, - struct bfd_link_info *info) +ppc64_elf_reinit_toc (bfd *output_bfd, struct bfd_link_info *info) { struct ppc_link_hash_table *htab = ppc_hash_table (info); + htab->multi_toc_needed = htab->toc_curr != elf_gp (output_bfd); + /* toc_curr tracks the TOC offset used for code sections below in ppc64_elf_next_input_section. Start off at 0x8000. */ htab->toc_curr = TOC_BASE_OFF; @@ -8226,15 +8245,18 @@ ppc64_elf_reinit_toc (bfd *output_bfd ATTRIBUTE_UNUSED, /* No toc references were found in ISEC. If the code in ISEC makes no calls, then there's no need to use toc adjusting stubs when branching into ISEC. Actually, indirect calls from ISEC are OK as they will - load r2. */ + load r2. Returns -1 on error, 0 for no stub needed, 1 for stub + needed, and 2 if a cyclical call-graph was found but no other reason + for a stub was detected. If called from the top level, a return of + 2 means the same as a return of 0. */ static int toc_adjusting_stub_needed (struct bfd_link_info *info, asection *isec) { - bfd_byte *contents; - bfd_size_type i; + Elf_Internal_Rela *relstart, *rel; + Elf_Internal_Sym *local_syms; int ret; - int branch_ok; + struct ppc_link_hash_table *htab; /* We know none of our code bearing sections will need toc stubs. */ if ((isec->flags & SEC_LINKER_CREATED) != 0) @@ -8243,44 +8265,175 @@ toc_adjusting_stub_needed (struct bfd_link_info *info, asection *isec) if (isec->size == 0) return 0; + if (isec->output_section == NULL) + return 0; + /* Hack for linux kernel. .fixup contains branches, but only back to the function that hit an exception. */ - branch_ok = strcmp (isec->name, ".fixup") == 0; + if (strcmp (isec->name, ".fixup") == 0) + return 0; - contents = elf_section_data (isec)->this_hdr.contents; - if (contents == NULL) + if (isec->reloc_count == 0) + return 0; + + relstart = _bfd_elf_link_read_relocs (isec->owner, isec, NULL, NULL, + info->keep_memory); + if (relstart == NULL) + return -1; + + /* Look for branches to outside of this section. */ + local_syms = NULL; + ret = 0; + htab = ppc_hash_table (info); + for (rel = relstart; rel < relstart + isec->reloc_count; ++rel) { - if (!bfd_malloc_and_get_section (isec->owner, isec, &contents)) + enum elf_ppc64_reloc_type r_type; + unsigned long r_symndx; + struct elf_link_hash_entry *h; + Elf_Internal_Sym *sym; + asection *sym_sec; + long *opd_adjust; + bfd_vma sym_value; + bfd_vma dest; + + r_type = ELF64_R_TYPE (rel->r_info); + if (r_type != R_PPC64_REL24 + && r_type != R_PPC64_REL14 + && r_type != R_PPC64_REL14_BRTAKEN + && r_type != R_PPC64_REL14_BRNTAKEN) + continue; + + r_symndx = ELF64_R_SYM (rel->r_info); + if (!get_sym_h (&h, &sym, &sym_sec, NULL, &local_syms, r_symndx, + isec->owner)) { - if (contents != NULL) - free (contents); - return -1; + ret = -1; + break; } - if (info->keep_memory) - elf_section_data (isec)->this_hdr.contents = contents; - } - /* Code scan, because we don't necessarily have relocs on calls to - static functions. */ - ret = 0; - for (i = 0; i < isec->size; i += 4) - { - unsigned long insn = bfd_get_32 (isec->owner, contents + i); - /* Is this a branch? */ - if ((insn & (0x3f << 26)) == (18 << 26) - /* If branch and link, it's a function call. */ - && ((insn & 1) != 0 - /* Sibling calls use a plain branch. I don't know a way - of deciding whether a branch is really a sibling call. */ - || !branch_ok)) + /* Ignore branches to undefined syms. */ + if (sym_sec == NULL) + continue; + + /* Calls to dynamic lib functions go through a plt call stub + that uses r2. Assume branches to other sections not included + in the link need stubs too, to cover -R and absolute syms. */ + if (sym_sec->output_section == NULL) + { + ret = 1; + break; + } + + if (h == NULL) + sym_value = sym->st_value; + else + { + if (h->root.type != bfd_link_hash_defined + && h->root.type != bfd_link_hash_defweak) + abort (); + sym_value = h->root.u.def.value; + } + sym_value += rel->r_addend; + + /* If this branch reloc uses an opd sym, find the code section. */ + opd_adjust = get_opd_info (sym_sec); + if (opd_adjust != NULL) + { + + if (h == NULL) + { + long adjust; + + adjust = opd_adjust[sym->st_value / 8]; + if (adjust == -1) + /* Assume deleted functions won't ever be called. */ + continue; + sym_value += adjust; + } + + dest = opd_entry_value (sym_sec, sym_value, &sym_sec, NULL); + if (dest == (bfd_vma) -1) + continue; + } + else + dest = (sym_value + + sym_sec->output_offset + + sym_sec->output_section->vma); + + /* Ignore branch to self. */ + if (sym_sec == isec) + continue; + + /* If the called function uses the toc, we need a stub. */ + if (sym_sec->has_toc_reloc + || sym_sec->makes_toc_func_call) { ret = 1; break; } + + /* Assume any branch that needs a long branch stub might in fact + need a plt_branch stub. A plt_branch stub uses r2. */ + else if (dest - (isec->output_offset + + isec->output_section->vma + + rel->r_offset) + (1 << 25) >= (2 << 25)) + { + ret = 1; + break; + } + + /* If calling back to a section in the process of being tested, we + can't say for sure that no toc adjusting stubs are needed, so + don't return zero. */ + else if (sym_sec->call_check_in_progress) + ret = 2; + + /* Branches to another section that itself doesn't have any TOC + references are OK. Recursively call ourselves to check. */ + else if (sym_sec->id <= htab->top_id + && htab->stub_group[sym_sec->id].toc_off == 0) + { + int recur; + + /* Mark current section as indeterminate, so that other + sections that call back to current won't be marked as + known. */ + isec->call_check_in_progress = 1; + recur = toc_adjusting_stub_needed (info, sym_sec); + isec->call_check_in_progress = 0; + + if (recur < 0) + { + /* An error. Exit. */ + ret = -1; + break; + } + else if (recur <= 1) + { + /* Known result. Mark as checked and set section flag. */ + htab->stub_group[sym_sec->id].toc_off = 1; + if (recur != 0) + { + sym_sec->makes_toc_func_call = 1; + ret = 1; + break; + } + } + else + { + /* Unknown result. Continue checking. */ + ret = 2; + } + } } - if (elf_section_data (isec)->this_hdr.contents != contents) - free (contents); + if (local_syms != NULL + && (elf_tdata (isec->owner)->symtab_hdr.contents + != (unsigned char *) local_syms)) + free (local_syms); + if (elf_section_data (isec)->relocs != relstart) + free (relstart); + return ret; } @@ -8293,7 +8446,6 @@ bfd_boolean ppc64_elf_next_input_section (struct bfd_link_info *info, asection *isec) { struct ppc_link_hash_table *htab = ppc_hash_table (info); - int ret; if ((isec->output_section->flags & SEC_CODE) != 0 && isec->output_section->index <= htab->top_index) @@ -8307,19 +8459,26 @@ ppc64_elf_next_input_section (struct bfd_link_info *info, asection *isec) *list = isec; } - /* If a code section has a function that uses the TOC then we need - to use the right TOC (obviously). Also, make sure that .opd gets - the correct TOC value for R_PPC64_TOC relocs that don't have or - can't find their function symbol (shouldn't ever happen now). */ - if (isec->has_gp_reloc || (isec->flags & SEC_CODE) == 0) + if (htab->multi_toc_needed) { - if (elf_gp (isec->owner) != 0) - htab->toc_curr = elf_gp (isec->owner); + /* If a code section has a function that uses the TOC then we need + to use the right TOC (obviously). Also, make sure that .opd gets + the correct TOC value for R_PPC64_TOC relocs that don't have or + can't find their function symbol (shouldn't ever happen now). */ + if (isec->has_toc_reloc || (isec->flags & SEC_CODE) == 0) + { + if (elf_gp (isec->owner) != 0) + htab->toc_curr = elf_gp (isec->owner); + } + else if (htab->stub_group[isec->id].toc_off == 0) + { + int ret = toc_adjusting_stub_needed (info, isec); + if (ret < 0) + return FALSE; + else + isec->makes_toc_func_call = ret & 1; + } } - else if ((ret = toc_adjusting_stub_needed (info, isec)) < 0) - return FALSE; - else - isec->has_gp_reloc = ret; /* Functions that don't use the TOC can belong in any TOC group. Use the last TOC base. This happens to make _init and _fini @@ -8643,7 +8802,8 @@ ppc64_elf_size_stubs (bfd *output_bfd, && code_sec->output_section != NULL && (htab->stub_group[code_sec->id].toc_off != htab->stub_group[section->id].toc_off) - && code_sec->has_gp_reloc) + && (code_sec->has_toc_reloc + || code_sec->makes_toc_func_call)) stub_type = ppc_stub_long_branch_r2off; } diff --git a/bfd/elf64-ppc.h b/bfd/elf64-ppc.h index 0e5a0e2e7af..7a39961edfc 100644 --- a/bfd/elf64-ppc.h +++ b/bfd/elf64-ppc.h @@ -30,7 +30,7 @@ bfd_boolean ppc64_elf_edit_toc bfd_vma ppc64_elf_toc (bfd *); int ppc64_elf_setup_section_lists - (bfd *, struct bfd_link_info *); + (bfd *, struct bfd_link_info *, int); void ppc64_elf_next_toc_section (struct bfd_link_info *, asection *); void ppc64_elf_reinit_toc diff --git a/bfd/libbfd.h b/bfd/libbfd.h index 8dbbd84d255..c53fcda7504 100644 --- a/bfd/libbfd.h +++ b/bfd/libbfd.h @@ -1362,6 +1362,9 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@", "BFD_RELOC_AVR_HI8_LDI_PM_NEG", "BFD_RELOC_AVR_HH8_LDI_PM_NEG", "BFD_RELOC_AVR_CALL", + "BFD_RELOC_AVR_LDI", + "BFD_RELOC_AVR_6", + "BFD_RELOC_AVR_6_ADIW", "BFD_RELOC_390_12", "BFD_RELOC_390_GOT12", "BFD_RELOC_390_PLT32", diff --git a/bfd/section.c b/bfd/section.c index b368c2aa842..9ed0ae12ce8 100644 --- a/bfd/section.c +++ b/bfd/section.c @@ -373,7 +373,8 @@ CODE_FRAGMENT . {* Nonzero if this section uses RELA relocations, rather than REL. *} . unsigned int use_rela_p:1; . -. {* Bits used by various backends. *} +. {* Bits used by various backends. The generic code doesn't touch +. these fields. *} . . {* Nonzero if this section has TLS related relocations. *} . unsigned int has_tls_reloc:1; diff --git a/ld/ChangeLog b/ld/ChangeLog index 8e5207b2922..6a969e3a3fa 100644 --- a/ld/ChangeLog +++ b/ld/ChangeLog @@ -1,8 +1,16 @@ +2005-01-06 Alan Modra + + * emultempl/ppc64elf.em (no_multi_toc): New var. + (gld${EMULATION_NAME}_finish): Pass to ppc64_elf_setup_section_lists. + (OPTION_NO_MULTI_TOC): Define. + (PARSE_AND_LIST_LONGOPTS): Add --no-multi-toc support. + (PARSE_AND_LIST_OPTIONS, PARSE_AND_LIST_ARGS_CASES): Likewise. + 2005-01-05 Nick Clifton PR binutils/614 * ldmisc.c (vfinfo): Alter output to conform to the GNU Coding - Standard's specification for parsable error messages. + Standard's specification for parsable error messages. 2005-01-04 Paul Brook @@ -89,7 +97,7 @@ * ld/ldlex.l: Allow ORIGIN and LENGTH in EXPRESSION. * ld/ldgram.y: Add ORIGIN and LENGTH expressions. - * ld/ldexp.c (fold_name): Implement LENGTH() and ORIGIN() functions + * ld/ldexp.c (fold_name): Implement LENGTH() and ORIGIN() functions which return the length and origin of a memory. * ld/ld.texinfo: Document LENGTH() and ORIGIN() functions. * NEWS: Mention support for ORIGIN and LENGTH operators. diff --git a/ld/emultempl/ppc64elf.em b/ld/emultempl/ppc64elf.em index 3713fd32e7b..338e090eb77 100644 --- a/ld/emultempl/ppc64elf.em +++ b/ld/emultempl/ppc64elf.em @@ -52,6 +52,9 @@ static int no_opd_opt = 0; /* Whether to run toc optimization. */ static int no_toc_opt = 0; +/* Whether to allow multiple toc sections. */ +static int no_multi_toc = 0; + /* Whether to emit symbols for stubs. */ static int emit_stub_syms = 0; @@ -337,7 +340,8 @@ gld${EMULATION_NAME}_finish (void) stubs. */ if (stub_file != NULL && !link_info.relocatable) { - int ret = ppc64_elf_setup_section_lists (output_bfd, &link_info); + int ret = ppc64_elf_setup_section_lists (output_bfd, &link_info, + no_multi_toc); if (ret != 0) { if (ret < 0) @@ -484,7 +488,8 @@ PARSE_AND_LIST_PROLOGUE=' #define OPTION_NO_TLS_OPT (OPTION_NO_DOTSYMS + 1) #define OPTION_NO_OPD_OPT (OPTION_NO_TLS_OPT + 1) #define OPTION_NO_TOC_OPT (OPTION_NO_OPD_OPT + 1) -#define OPTION_NON_OVERLAPPING_OPD (OPTION_NO_TOC_OPT + 1) +#define OPTION_NO_MULTI_TOC (OPTION_NO_TOC_OPT + 1) +#define OPTION_NON_OVERLAPPING_OPD (OPTION_NO_MULTI_TOC + 1) ' PARSE_AND_LIST_LONGOPTS=' @@ -495,6 +500,7 @@ PARSE_AND_LIST_LONGOPTS=' { "no-tls-optimize", no_argument, NULL, OPTION_NO_TLS_OPT }, { "no-opd-optimize", no_argument, NULL, OPTION_NO_OPD_OPT }, { "no-toc-optimize", no_argument, NULL, OPTION_NO_TOC_OPT }, + { "no-multi-toc", no_argument, NULL, OPTION_NO_MULTI_TOC }, { "non-overlapping-opd", no_argument, NULL, OPTION_NON_OVERLAPPING_OPD }, ' @@ -530,6 +536,9 @@ PARSE_AND_LIST_OPTIONS=' --no-toc-optimize Don'\''t optimize the TOC section.\n" )); fprintf (file, _("\ + --no-multi-toc Disallow automatic multiple toc sections.\n" + )); + fprintf (file, _("\ --non-overlapping-opd Canonicalize .opd, so that there are no overlapping\n\ .opd entries.\n" )); @@ -569,6 +578,10 @@ PARSE_AND_LIST_ARGS_CASES=' no_toc_opt = 1; break; + case OPTION_NO_MULTI_TOC: + no_multi_toc = 1; + break; + case OPTION_NON_OVERLAPPING_OPD: non_overlapping_opd = 1; break; -- 2.30.2