ppc476 icache bug workaround
This implements a work-around for an icache bug on 476 that can cause execution of stale instructions when control falls through from one page to the next. The idea is to prevent such fall-through by replacing the last instruction on a page with a branch to a patch area containing the instruction, then branch to the next page. The patch also fixes a number of bugs in the existing support for long branch trampolines. bfd/ * elf32-ppc.c (struct ppc_elf_link_hash_table): Add params. Delete emit_stub_syms, no_tls_get_addr_opt. Update all uses. (ppc_elf_link_params): New function. (ppc_elf_create_glink): Align .glink to 64 bytes for ppc476 workaround. (ppc_elf_select_plt_layout): Remove plt_style and emit_stub_syms parameters. Use htab->params instead. (ppc_elf_tls_setup): Remove no_tls_get_addr_opt parameter. (ppc_elf_size_dynamic_sections): Align __glink_PLTresolve to 64 bytes for ppc476 workaround. (struct ppc_elf_relax_info): New. (ppc_elf_relax_section): Exclude linker created sections and those too small to hold one instruction. Don't add another branch around trampolines on later relax passes. Don't generate trampolines for undefined symbols when !relocatable, nor for plugin symbols. Allocate space for ppc476 workaround patch area. Free fixups on error return path. (ppc_elf_relocate_section): Handle ppc476 workaround patching. * elf32-ppc.h (struct ppc_elf_params): New. (ppc_elf_select_plt_layout, ppc_elf_tls_setup): Update prototype. (ppc_elf_link_params): Declare. * section.c (SEC_INFO_TYPE_TARGET): Define. * bfd-in2.h: Regenerate. ld/ * emultempl/ppc32elf.em (no_tls_get_addr_opt, emit_stub_syms) plt_style): Delete. Adjust all refs to instead use.. (params): ..this. New variable. (ppc_after_open_output): New function. Tweak params and pass to ppc_elf_link_params. (ppc_after_open): Adjust ppc_elf_select_plt_layout call. (ppc_before_allocation): Adjust ppc_elf_tls_setup call. Enable relaxation for ppc476 workaround. (PARSE_AND_LIST_*): Add --{no-,}ppc476-workaround support. (LDEMUL_CREATE_OUTPUT_SECTION_STATEMENTS): Define.
This commit is contained in:
parent
8effdc96dc
commit
5446cbdf82
7 changed files with 696 additions and 363 deletions
|
@ -1,3 +1,29 @@
|
||||||
|
2014-02-03 Alan Modra <amodra@gmail.com>
|
||||||
|
|
||||||
|
* elf32-ppc.c (struct ppc_elf_link_hash_table): Add params.
|
||||||
|
Delete emit_stub_syms, no_tls_get_addr_opt. Update all uses.
|
||||||
|
(ppc_elf_link_params): New function.
|
||||||
|
(ppc_elf_create_glink): Align .glink to 64 bytes for ppc476
|
||||||
|
workaround.
|
||||||
|
(ppc_elf_select_plt_layout): Remove plt_style and emit_stub_syms
|
||||||
|
parameters. Use htab->params instead.
|
||||||
|
(ppc_elf_tls_setup): Remove no_tls_get_addr_opt parameter.
|
||||||
|
(ppc_elf_size_dynamic_sections): Align __glink_PLTresolve to
|
||||||
|
64 bytes for ppc476 workaround.
|
||||||
|
(struct ppc_elf_relax_info): New.
|
||||||
|
(ppc_elf_relax_section): Exclude linker created sections and
|
||||||
|
those too small to hold one instruction. Don't add another
|
||||||
|
branch around trampolines on later relax passes. Don't
|
||||||
|
generate trampolines for undefined symbols when !relocatable,
|
||||||
|
nor for plugin symbols. Allocate space for ppc476 workaround
|
||||||
|
patch area. Free fixups on error return path.
|
||||||
|
(ppc_elf_relocate_section): Handle ppc476 workaround patching.
|
||||||
|
* elf32-ppc.h (struct ppc_elf_params): New.
|
||||||
|
(ppc_elf_select_plt_layout, ppc_elf_tls_setup): Update prototype.
|
||||||
|
(ppc_elf_link_params): Declare.
|
||||||
|
* section.c (SEC_INFO_TYPE_TARGET): Define.
|
||||||
|
* bfd-in2.h: Regenerate.
|
||||||
|
|
||||||
2014-02-02 Sandra Loosemore <sandra@codesourcery.com>
|
2014-02-02 Sandra Loosemore <sandra@codesourcery.com>
|
||||||
|
|
||||||
* elf32-nios2.c (struct elf32_nios2_link_hash_table): Add
|
* elf32-nios2.c (struct elf32_nios2_link_hash_table): Add
|
||||||
|
|
|
@ -1437,6 +1437,7 @@ typedef struct bfd_section
|
||||||
#define SEC_INFO_TYPE_MERGE 2
|
#define SEC_INFO_TYPE_MERGE 2
|
||||||
#define SEC_INFO_TYPE_EH_FRAME 3
|
#define SEC_INFO_TYPE_EH_FRAME 3
|
||||||
#define SEC_INFO_TYPE_JUST_SYMS 4
|
#define SEC_INFO_TYPE_JUST_SYMS 4
|
||||||
|
#define SEC_INFO_TYPE_TARGET 5
|
||||||
|
|
||||||
/* Nonzero if this section uses RELA relocations, rather than REL. */
|
/* Nonzero if this section uses RELA relocations, rather than REL. */
|
||||||
unsigned int use_rela_p:1;
|
unsigned int use_rela_p:1;
|
||||||
|
|
362
bfd/elf32-ppc.c
362
bfd/elf32-ppc.c
|
@ -3139,6 +3139,9 @@ struct ppc_elf_link_hash_table
|
||||||
{
|
{
|
||||||
struct elf_link_hash_table elf;
|
struct elf_link_hash_table elf;
|
||||||
|
|
||||||
|
/* Various options passed from the linker. */
|
||||||
|
struct ppc_elf_params *params;
|
||||||
|
|
||||||
/* Short-cuts to get to dynamic linker sections. */
|
/* Short-cuts to get to dynamic linker sections. */
|
||||||
asection *got;
|
asection *got;
|
||||||
asection *relgot;
|
asection *relgot;
|
||||||
|
@ -3184,12 +3187,6 @@ struct ppc_elf_link_hash_table
|
||||||
/* The type of PLT we have chosen to use. */
|
/* The type of PLT we have chosen to use. */
|
||||||
enum ppc_elf_plt_type plt_type;
|
enum ppc_elf_plt_type plt_type;
|
||||||
|
|
||||||
/* Set if we should emit symbols for stubs. */
|
|
||||||
unsigned int emit_stub_syms:1;
|
|
||||||
|
|
||||||
/* Set if __tls_get_addr optimization should not be done. */
|
|
||||||
unsigned int no_tls_get_addr_opt:1;
|
|
||||||
|
|
||||||
/* True if the target system is VxWorks. */
|
/* True if the target system is VxWorks. */
|
||||||
unsigned int is_vxworks:1;
|
unsigned int is_vxworks:1;
|
||||||
|
|
||||||
|
@ -3289,6 +3286,17 @@ ppc_elf_link_hash_table_create (bfd *abfd)
|
||||||
return &ret->elf.root;
|
return &ret->elf.root;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Hook linker params into hash table. */
|
||||||
|
|
||||||
|
void
|
||||||
|
ppc_elf_link_params (struct bfd_link_info *info, struct ppc_elf_params *params)
|
||||||
|
{
|
||||||
|
struct ppc_elf_link_hash_table *htab = ppc_elf_hash_table (info);
|
||||||
|
|
||||||
|
if (htab)
|
||||||
|
htab->params = params;
|
||||||
|
}
|
||||||
|
|
||||||
/* Create .got and the related sections. */
|
/* Create .got and the related sections. */
|
||||||
|
|
||||||
static bfd_boolean
|
static bfd_boolean
|
||||||
|
@ -3341,7 +3349,8 @@ ppc_elf_create_glink (bfd *abfd, struct bfd_link_info *info)
|
||||||
s = bfd_make_section_anyway_with_flags (abfd, ".glink", flags);
|
s = bfd_make_section_anyway_with_flags (abfd, ".glink", flags);
|
||||||
htab->glink = s;
|
htab->glink = s;
|
||||||
if (s == NULL
|
if (s == NULL
|
||||||
|| !bfd_set_section_alignment (abfd, s, 4))
|
|| !bfd_set_section_alignment (abfd, s,
|
||||||
|
htab->params->ppc476_workaround ? 6 : 4))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
if (!info->no_ld_generated_unwind_info)
|
if (!info->no_ld_generated_unwind_info)
|
||||||
|
@ -4801,22 +4810,18 @@ ppc_elf_vle_split16 (bfd *output_bfd, bfd_byte *contents,
|
||||||
Returns -1 on error, 0 for old PLT, 1 for new PLT. */
|
Returns -1 on error, 0 for old PLT, 1 for new PLT. */
|
||||||
int
|
int
|
||||||
ppc_elf_select_plt_layout (bfd *output_bfd ATTRIBUTE_UNUSED,
|
ppc_elf_select_plt_layout (bfd *output_bfd ATTRIBUTE_UNUSED,
|
||||||
struct bfd_link_info *info,
|
struct bfd_link_info *info)
|
||||||
enum ppc_elf_plt_type plt_style,
|
|
||||||
int emit_stub_syms)
|
|
||||||
{
|
{
|
||||||
struct ppc_elf_link_hash_table *htab;
|
struct ppc_elf_link_hash_table *htab;
|
||||||
flagword flags;
|
flagword flags;
|
||||||
|
|
||||||
htab = ppc_elf_hash_table (info);
|
htab = ppc_elf_hash_table (info);
|
||||||
|
|
||||||
htab->emit_stub_syms = emit_stub_syms;
|
|
||||||
|
|
||||||
if (htab->plt_type == PLT_UNSET)
|
if (htab->plt_type == PLT_UNSET)
|
||||||
{
|
{
|
||||||
struct elf_link_hash_entry *h;
|
struct elf_link_hash_entry *h;
|
||||||
|
|
||||||
if (plt_style == PLT_OLD)
|
if (htab->params->plt_style == PLT_OLD)
|
||||||
htab->plt_type = PLT_OLD;
|
htab->plt_type = PLT_OLD;
|
||||||
else if (info->shared
|
else if (info->shared
|
||||||
&& htab->elf.dynamic_sections_created
|
&& htab->elf.dynamic_sections_created
|
||||||
|
@ -4838,7 +4843,7 @@ ppc_elf_select_plt_layout (bfd *output_bfd ATTRIBUTE_UNUSED,
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
bfd *ibfd;
|
bfd *ibfd;
|
||||||
enum ppc_elf_plt_type plt_type = plt_style;
|
enum ppc_elf_plt_type plt_type = htab->params->plt_style;
|
||||||
|
|
||||||
/* Look through the reloc flags left by ppc_elf_check_relocs.
|
/* Look through the reloc flags left by ppc_elf_check_relocs.
|
||||||
Use the old style bss plt if a file makes plt calls
|
Use the old style bss plt if a file makes plt calls
|
||||||
|
@ -4861,7 +4866,7 @@ ppc_elf_select_plt_layout (bfd *output_bfd ATTRIBUTE_UNUSED,
|
||||||
htab->plt_type = plt_type;
|
htab->plt_type = plt_type;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (htab->plt_type == PLT_OLD && plt_style == PLT_NEW)
|
if (htab->plt_type == PLT_OLD && htab->params->plt_style == PLT_NEW)
|
||||||
{
|
{
|
||||||
if (htab->old_bfd != NULL)
|
if (htab->old_bfd != NULL)
|
||||||
info->callbacks->einfo (_("%P: bss-plt forced due to %B\n"),
|
info->callbacks->einfo (_("%P: bss-plt forced due to %B\n"),
|
||||||
|
@ -5097,16 +5102,14 @@ ppc_elf_gc_sweep_hook (bfd *abfd,
|
||||||
generic ELF tls_setup function. */
|
generic ELF tls_setup function. */
|
||||||
|
|
||||||
asection *
|
asection *
|
||||||
ppc_elf_tls_setup (bfd *obfd,
|
ppc_elf_tls_setup (bfd *obfd, struct bfd_link_info *info)
|
||||||
struct bfd_link_info *info,
|
|
||||||
int no_tls_get_addr_opt)
|
|
||||||
{
|
{
|
||||||
struct ppc_elf_link_hash_table *htab;
|
struct ppc_elf_link_hash_table *htab;
|
||||||
|
|
||||||
htab = ppc_elf_hash_table (info);
|
htab = ppc_elf_hash_table (info);
|
||||||
htab->tls_get_addr = elf_link_hash_lookup (&htab->elf, "__tls_get_addr",
|
htab->tls_get_addr = elf_link_hash_lookup (&htab->elf, "__tls_get_addr",
|
||||||
FALSE, FALSE, TRUE);
|
FALSE, FALSE, TRUE);
|
||||||
if (!no_tls_get_addr_opt)
|
if (!htab->params->no_tls_get_addr_opt)
|
||||||
{
|
{
|
||||||
struct elf_link_hash_entry *opt, *tga;
|
struct elf_link_hash_entry *opt, *tga;
|
||||||
opt = elf_link_hash_lookup (&htab->elf, "__tls_get_addr_opt",
|
opt = elf_link_hash_lookup (&htab->elf, "__tls_get_addr_opt",
|
||||||
|
@ -5151,9 +5154,8 @@ ppc_elf_tls_setup (bfd *obfd,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
no_tls_get_addr_opt = TRUE;
|
htab->params->no_tls_get_addr_opt = TRUE;
|
||||||
}
|
}
|
||||||
htab->no_tls_get_addr_opt = no_tls_get_addr_opt;
|
|
||||||
if (htab->plt_type == PLT_NEW
|
if (htab->plt_type == PLT_NEW
|
||||||
&& htab->plt != NULL
|
&& htab->plt != NULL
|
||||||
&& htab->plt->output_section != NULL)
|
&& htab->plt->output_section != NULL)
|
||||||
|
@ -5784,7 +5786,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
|
||||||
glink_offset = s->size;
|
glink_offset = s->size;
|
||||||
s->size += GLINK_ENTRY_SIZE;
|
s->size += GLINK_ENTRY_SIZE;
|
||||||
if (h == htab->tls_get_addr
|
if (h == htab->tls_get_addr
|
||||||
&& !htab->no_tls_get_addr_opt)
|
&& !htab->params->no_tls_get_addr_opt)
|
||||||
s->size += TLS_GET_ADDR_GLINK_SIZE - GLINK_ENTRY_SIZE;
|
s->size += TLS_GET_ADDR_GLINK_SIZE - GLINK_ENTRY_SIZE;
|
||||||
}
|
}
|
||||||
if (!doneone
|
if (!doneone
|
||||||
|
@ -5797,7 +5799,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
|
||||||
}
|
}
|
||||||
ent->glink_offset = glink_offset;
|
ent->glink_offset = glink_offset;
|
||||||
|
|
||||||
if (htab->emit_stub_syms
|
if (htab->params->emit_stub_syms
|
||||||
&& !add_stub_sym (ent, h, info))
|
&& !add_stub_sym (ent, h, info))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
@ -6339,10 +6341,11 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
|
||||||
/* Space for the branch table. */
|
/* Space for the branch table. */
|
||||||
htab->glink->size += htab->glink->size / (GLINK_ENTRY_SIZE / 4) - 4;
|
htab->glink->size += htab->glink->size / (GLINK_ENTRY_SIZE / 4) - 4;
|
||||||
/* Pad out to align the start of PLTresolve. */
|
/* Pad out to align the start of PLTresolve. */
|
||||||
htab->glink->size += -htab->glink->size & 15;
|
htab->glink->size += -htab->glink->size & (htab->params->ppc476_workaround
|
||||||
|
? 63 : 15);
|
||||||
htab->glink->size += GLINK_PLTRESOLVE;
|
htab->glink->size += GLINK_PLTRESOLVE;
|
||||||
|
|
||||||
if (htab->emit_stub_syms)
|
if (htab->params->emit_stub_syms)
|
||||||
{
|
{
|
||||||
struct elf_link_hash_entry *sh;
|
struct elf_link_hash_entry *sh;
|
||||||
sh = elf_link_hash_lookup (&htab->elf, "__glink",
|
sh = elf_link_hash_lookup (&htab->elf, "__glink",
|
||||||
|
@ -6501,7 +6504,7 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
|
||||||
{
|
{
|
||||||
if (!add_dynamic_entry (DT_PPC_GOT, 0))
|
if (!add_dynamic_entry (DT_PPC_GOT, 0))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
if (!htab->no_tls_get_addr_opt
|
if (!htab->params->no_tls_get_addr_opt
|
||||||
&& htab->tls_get_addr != NULL
|
&& htab->tls_get_addr != NULL
|
||||||
&& htab->tls_get_addr->plt.plist != NULL
|
&& htab->tls_get_addr->plt.plist != NULL
|
||||||
&& !add_dynamic_entry (DT_PPC_OPT, PPC_OPT_TLS))
|
&& !add_dynamic_entry (DT_PPC_OPT, PPC_OPT_TLS))
|
||||||
|
@ -6634,6 +6637,19 @@ static const int stub_entry[] =
|
||||||
0x4e800420, /* bctr */
|
0x4e800420, /* bctr */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ppc_elf_relax_info
|
||||||
|
{
|
||||||
|
unsigned int workaround_size;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* This function implements long branch trampolines, and the ppc476
|
||||||
|
icache bug workaround. Any section needing trampolines or patch
|
||||||
|
space for the workaround has its size extended so that we can
|
||||||
|
add trampolines at the end of the section. FIXME: We write out
|
||||||
|
trampoline templates here and later modify them in
|
||||||
|
relocate_section. We'd save a realloc if we left writing the
|
||||||
|
templates to relocate_section. */
|
||||||
|
|
||||||
static bfd_boolean
|
static bfd_boolean
|
||||||
ppc_elf_relax_section (bfd *abfd,
|
ppc_elf_relax_section (bfd *abfd,
|
||||||
asection *isec,
|
asection *isec,
|
||||||
|
@ -6654,22 +6670,23 @@ ppc_elf_relax_section (bfd *abfd,
|
||||||
bfd_byte *contents = NULL;
|
bfd_byte *contents = NULL;
|
||||||
Elf_Internal_Sym *isymbuf = NULL;
|
Elf_Internal_Sym *isymbuf = NULL;
|
||||||
Elf_Internal_Rela *internal_relocs = NULL;
|
Elf_Internal_Rela *internal_relocs = NULL;
|
||||||
Elf_Internal_Rela *irel, *irelend;
|
Elf_Internal_Rela *irel, *irelend = NULL;
|
||||||
struct one_fixup *fixups = NULL;
|
struct one_fixup *fixups = NULL;
|
||||||
|
struct ppc_elf_relax_info *relax_info = NULL;
|
||||||
unsigned changes = 0;
|
unsigned changes = 0;
|
||||||
|
bfd_boolean workaround_change;
|
||||||
struct ppc_elf_link_hash_table *htab;
|
struct ppc_elf_link_hash_table *htab;
|
||||||
bfd_size_type trampoff;
|
bfd_size_type trampbase, trampoff, newsize;
|
||||||
asection *got2;
|
asection *got2;
|
||||||
bfd_boolean maybe_pasted;
|
bfd_boolean maybe_pasted;
|
||||||
|
|
||||||
*again = FALSE;
|
*again = FALSE;
|
||||||
|
|
||||||
/* Nothing to do if there are no relocations, and no need to do
|
/* No need to do anything with non-alloc or non-code sections. */
|
||||||
anything with non-alloc or non-code sections. */
|
|
||||||
if ((isec->flags & SEC_ALLOC) == 0
|
if ((isec->flags & SEC_ALLOC) == 0
|
||||||
|| (isec->flags & SEC_CODE) == 0
|
|| (isec->flags & SEC_CODE) == 0
|
||||||
|| (isec->flags & SEC_RELOC) == 0
|
|| (isec->flags & SEC_LINKER_CREATED) != 0
|
||||||
|| isec->reloc_count == 0)
|
|| isec->size < 4)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
/* We cannot represent the required PIC relocs in the output, so don't
|
/* We cannot represent the required PIC relocs in the output, so don't
|
||||||
|
@ -6678,22 +6695,50 @@ ppc_elf_relax_section (bfd *abfd,
|
||||||
if (link_info->relocatable && link_info->shared)
|
if (link_info->relocatable && link_info->shared)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
trampoff = (isec->size + 3) & (bfd_vma) -4;
|
htab = ppc_elf_hash_table (link_info);
|
||||||
|
if (htab == NULL)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
isec->size = (isec->size + 3) & -4;
|
||||||
|
if (isec->rawsize == 0)
|
||||||
|
isec->rawsize = isec->size;
|
||||||
|
trampbase = isec->size;
|
||||||
|
|
||||||
|
if (htab->params->ppc476_workaround)
|
||||||
|
{
|
||||||
|
if (elf_section_data (isec)->sec_info == NULL)
|
||||||
|
{
|
||||||
|
BFD_ASSERT (isec->sec_info_type == SEC_INFO_TYPE_NONE);
|
||||||
|
isec->sec_info_type = SEC_INFO_TYPE_TARGET;
|
||||||
|
elf_section_data (isec)->sec_info
|
||||||
|
= bfd_zalloc (abfd, sizeof (struct ppc_elf_relax_info));
|
||||||
|
if (elf_section_data (isec)->sec_info == NULL)
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
relax_info = elf_section_data (isec)->sec_info;
|
||||||
|
trampbase -= relax_info->workaround_size;
|
||||||
|
}
|
||||||
|
|
||||||
maybe_pasted = (strcmp (isec->output_section->name, ".init") == 0
|
maybe_pasted = (strcmp (isec->output_section->name, ".init") == 0
|
||||||
|| strcmp (isec->output_section->name, ".fini") == 0);
|
|| strcmp (isec->output_section->name, ".fini") == 0);
|
||||||
/* Space for a branch around any trampolines. */
|
/* Space for a branch around any trampolines. */
|
||||||
if (maybe_pasted)
|
trampoff = trampbase;
|
||||||
|
if (maybe_pasted && trampbase == isec->rawsize)
|
||||||
trampoff += 4;
|
trampoff += 4;
|
||||||
|
|
||||||
symtab_hdr = &elf_symtab_hdr (abfd);
|
symtab_hdr = &elf_symtab_hdr (abfd);
|
||||||
|
|
||||||
|
if (htab->params->branch_trampolines)
|
||||||
|
{
|
||||||
/* Get a copy of the native relocations. */
|
/* Get a copy of the native relocations. */
|
||||||
|
if (isec->reloc_count != 0)
|
||||||
|
{
|
||||||
internal_relocs = _bfd_elf_link_read_relocs (abfd, isec, NULL, NULL,
|
internal_relocs = _bfd_elf_link_read_relocs (abfd, isec, NULL, NULL,
|
||||||
link_info->keep_memory);
|
link_info->keep_memory);
|
||||||
if (internal_relocs == NULL)
|
if (internal_relocs == NULL)
|
||||||
goto error_return;
|
goto error_return;
|
||||||
|
}
|
||||||
|
|
||||||
htab = ppc_elf_hash_table (link_info);
|
|
||||||
got2 = bfd_get_section_by_name (abfd, ".got2");
|
got2 = bfd_get_section_by_name (abfd, ".got2");
|
||||||
|
|
||||||
irelend = internal_relocs + isec->reloc_count;
|
irelend = internal_relocs + isec->reloc_count;
|
||||||
|
@ -6868,7 +6913,8 @@ ppc_elf_relax_section (bfd *abfd,
|
||||||
if (sym_type == STT_SECTION)
|
if (sym_type == STT_SECTION)
|
||||||
toff += irel->r_addend;
|
toff += irel->r_addend;
|
||||||
|
|
||||||
toff = _bfd_merged_section_offset (abfd, &tsec,
|
toff
|
||||||
|
= _bfd_merged_section_offset (abfd, &tsec,
|
||||||
elf_section_data (tsec)->sec_info,
|
elf_section_data (tsec)->sec_info,
|
||||||
toff);
|
toff);
|
||||||
|
|
||||||
|
@ -6880,7 +6926,11 @@ ppc_elf_relax_section (bfd *abfd,
|
||||||
toff += irel->r_addend;
|
toff += irel->r_addend;
|
||||||
|
|
||||||
/* Attempted -shared link of non-pic code loses. */
|
/* Attempted -shared link of non-pic code loses. */
|
||||||
if (tsec->output_section == NULL)
|
if ((!link_info->relocatable
|
||||||
|
&& tsec == bfd_und_section_ptr)
|
||||||
|
|| tsec->output_section == NULL
|
||||||
|
|| (tsec->owner != NULL
|
||||||
|
&& (tsec->owner->flags & BFD_PLUGIN) != 0))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
roff = irel->r_offset;
|
roff = irel->r_offset;
|
||||||
|
@ -6896,7 +6946,8 @@ ppc_elf_relax_section (bfd *abfd,
|
||||||
|
|
||||||
symaddr = tsec->output_section->vma + tsec->output_offset + toff;
|
symaddr = tsec->output_section->vma + tsec->output_offset + toff;
|
||||||
reladdr = isec->output_section->vma + isec->output_offset + roff;
|
reladdr = isec->output_section->vma + isec->output_offset + roff;
|
||||||
if (symaddr - reladdr + max_branch_offset < 2 * max_branch_offset)
|
if (symaddr - reladdr + max_branch_offset
|
||||||
|
< 2 * max_branch_offset)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6971,13 +7022,10 @@ ppc_elf_relax_section (bfd *abfd,
|
||||||
/* Get cached copy if it exists. */
|
/* Get cached copy if it exists. */
|
||||||
if (elf_section_data (isec)->this_hdr.contents != NULL)
|
if (elf_section_data (isec)->this_hdr.contents != NULL)
|
||||||
contents = elf_section_data (isec)->this_hdr.contents;
|
contents = elf_section_data (isec)->this_hdr.contents;
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Go get them off disk. */
|
/* Go get them off disk. */
|
||||||
if (!bfd_malloc_and_get_section (abfd, isec, &contents))
|
else if (!bfd_malloc_and_get_section (abfd, isec, &contents))
|
||||||
goto error_return;
|
goto error_return;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/* Fix up the existing branch to hit the trampoline. */
|
/* Fix up the existing branch to hit the trampoline. */
|
||||||
hit_addr = contents + roff;
|
hit_addr = contents + roff;
|
||||||
|
@ -7003,35 +7051,75 @@ ppc_elf_relax_section (bfd *abfd,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Write out the trampolines. */
|
while (fixups != NULL)
|
||||||
if (fixups != NULL)
|
|
||||||
{
|
|
||||||
const int *stub;
|
|
||||||
bfd_byte *dest;
|
|
||||||
int i, size;
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
struct one_fixup *f = fixups;
|
struct one_fixup *f = fixups;
|
||||||
fixups = fixups->next;
|
fixups = fixups->next;
|
||||||
free (f);
|
free (f);
|
||||||
}
|
}
|
||||||
while (fixups);
|
}
|
||||||
|
|
||||||
contents = bfd_realloc_or_free (contents, trampoff);
|
workaround_change = FALSE;
|
||||||
|
newsize = trampoff;
|
||||||
|
if (htab->params->ppc476_workaround)
|
||||||
|
{
|
||||||
|
bfd_vma addr, end_addr;
|
||||||
|
unsigned int crossings;
|
||||||
|
unsigned int pagesize = htab->params->pagesize;
|
||||||
|
|
||||||
|
addr = isec->output_section->vma + isec->output_offset;
|
||||||
|
end_addr = addr + trampoff - 1;
|
||||||
|
addr &= -pagesize;
|
||||||
|
crossings = ((end_addr & -pagesize) - addr) / pagesize;
|
||||||
|
if (crossings != 0)
|
||||||
|
{
|
||||||
|
/* Keep space aligned, to ensure the patch code itself does
|
||||||
|
not cross a page. Don't decrease size calculated on a
|
||||||
|
previous pass as otherwise we might never settle on a layout. */
|
||||||
|
newsize = 15 - (end_addr & 15);
|
||||||
|
newsize += crossings * 16;
|
||||||
|
if (relax_info->workaround_size < newsize)
|
||||||
|
{
|
||||||
|
relax_info->workaround_size = newsize;
|
||||||
|
workaround_change = TRUE;
|
||||||
|
if (contents == NULL)
|
||||||
|
{
|
||||||
|
if (elf_section_data (isec)->this_hdr.contents != NULL)
|
||||||
|
contents = elf_section_data (isec)->this_hdr.contents;
|
||||||
|
else if (!bfd_malloc_and_get_section (abfd, isec, &contents))
|
||||||
|
goto error_return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Ensure relocate_section is called. */
|
||||||
|
isec->flags |= SEC_RELOC;
|
||||||
|
}
|
||||||
|
newsize = trampoff + relax_info->workaround_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (changes || workaround_change)
|
||||||
|
{
|
||||||
|
contents = bfd_realloc_or_free (contents, newsize);
|
||||||
if (contents == NULL)
|
if (contents == NULL)
|
||||||
goto error_return;
|
goto error_return;
|
||||||
|
|
||||||
isec->size = (isec->size + 3) & (bfd_vma) -4;
|
|
||||||
dest = contents + isec->size;
|
|
||||||
/* Branch around the trampolines. */
|
/* Branch around the trampolines. */
|
||||||
if (maybe_pasted)
|
if (maybe_pasted)
|
||||||
{
|
{
|
||||||
bfd_vma val = B + trampoff - isec->size;
|
bfd_vma val = B + newsize - isec->rawsize;
|
||||||
bfd_put_32 (abfd, val, dest);
|
bfd_put_32 (abfd, val, contents + isec->rawsize);
|
||||||
dest += 4;
|
|
||||||
}
|
}
|
||||||
isec->size = trampoff;
|
}
|
||||||
|
|
||||||
|
/* Write out the trampolines. */
|
||||||
|
if (changes)
|
||||||
|
{
|
||||||
|
const int *stub;
|
||||||
|
bfd_byte *dest;
|
||||||
|
int i, size;
|
||||||
|
|
||||||
|
dest = contents + trampbase;
|
||||||
|
if (maybe_pasted && trampbase == isec->rawsize)
|
||||||
|
dest += 4;
|
||||||
|
|
||||||
if (link_info->shared)
|
if (link_info->shared)
|
||||||
{
|
{
|
||||||
|
@ -7056,6 +7144,9 @@ ppc_elf_relax_section (bfd *abfd,
|
||||||
BFD_ASSERT (i == 0);
|
BFD_ASSERT (i == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (changes || workaround_change)
|
||||||
|
isec->size = newsize;
|
||||||
|
|
||||||
if (isymbuf != NULL
|
if (isymbuf != NULL
|
||||||
&& symtab_hdr->contents != (unsigned char *) isymbuf)
|
&& symtab_hdr->contents != (unsigned char *) isymbuf)
|
||||||
{
|
{
|
||||||
|
@ -7071,7 +7162,7 @@ ppc_elf_relax_section (bfd *abfd,
|
||||||
if (contents != NULL
|
if (contents != NULL
|
||||||
&& elf_section_data (isec)->this_hdr.contents != contents)
|
&& elf_section_data (isec)->this_hdr.contents != contents)
|
||||||
{
|
{
|
||||||
if (!changes && !link_info->keep_memory)
|
if (!changes && !workaround_change && !link_info->keep_memory)
|
||||||
free (contents);
|
free (contents);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -7106,11 +7197,12 @@ ppc_elf_relax_section (bfd *abfd,
|
||||||
rel_hdr = _bfd_elf_single_rel_hdr (isec);
|
rel_hdr = _bfd_elf_single_rel_hdr (isec);
|
||||||
rel_hdr->sh_size += changes * rel_hdr->sh_entsize;
|
rel_hdr->sh_size += changes * rel_hdr->sh_entsize;
|
||||||
}
|
}
|
||||||
else if (elf_section_data (isec)->relocs != internal_relocs)
|
else if (internal_relocs != NULL
|
||||||
|
&& elf_section_data (isec)->relocs != internal_relocs)
|
||||||
free (internal_relocs);
|
free (internal_relocs);
|
||||||
|
|
||||||
*again = changes != 0;
|
*again = changes != 0 || workaround_change;
|
||||||
if (!*again && link_info->relocatable)
|
if (!*again && link_info->relocatable && htab->params->branch_trampolines)
|
||||||
{
|
{
|
||||||
/* Convert the internal relax relocs to external form. */
|
/* Convert the internal relax relocs to external form. */
|
||||||
for (irel = internal_relocs; irel < irelend; irel++)
|
for (irel = internal_relocs; irel < irelend; irel++)
|
||||||
|
@ -7134,6 +7226,12 @@ ppc_elf_relax_section (bfd *abfd,
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
error_return:
|
error_return:
|
||||||
|
while (fixups != NULL)
|
||||||
|
{
|
||||||
|
struct one_fixup *f = fixups;
|
||||||
|
fixups = fixups->next;
|
||||||
|
free (f);
|
||||||
|
}
|
||||||
if (isymbuf != NULL && (unsigned char *) isymbuf != symtab_hdr->contents)
|
if (isymbuf != NULL && (unsigned char *) isymbuf != symtab_hdr->contents)
|
||||||
free (isymbuf);
|
free (isymbuf);
|
||||||
if (contents != NULL
|
if (contents != NULL
|
||||||
|
@ -9076,6 +9174,144 @@ ppc_elf_relocate_section (bfd *output_bfd,
|
||||||
fprintf (stderr, "\n");
|
fprintf (stderr, "\n");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (htab->params->ppc476_workaround
|
||||||
|
&& input_section->sec_info_type == SEC_INFO_TYPE_TARGET)
|
||||||
|
{
|
||||||
|
struct ppc_elf_relax_info *relax_info;
|
||||||
|
bfd_vma start_addr, end_addr, addr;
|
||||||
|
unsigned int pagesize = htab->params->pagesize;
|
||||||
|
|
||||||
|
relax_info = elf_section_data (input_section)->sec_info;
|
||||||
|
if (relax_info->workaround_size != 0)
|
||||||
|
memset (contents + input_section->size - relax_info->workaround_size,
|
||||||
|
0, relax_info->workaround_size);
|
||||||
|
|
||||||
|
/* The idea is: Replace the last instruction on a page with a
|
||||||
|
branch to a patch area. Put the insn there followed by a
|
||||||
|
branch back to the next page. Complicated a little by
|
||||||
|
needing to handle moved conditional branches, and by not
|
||||||
|
wanting to touch data-in-text. */
|
||||||
|
|
||||||
|
start_addr = (input_section->output_section->vma
|
||||||
|
+ input_section->output_offset);
|
||||||
|
end_addr = (start_addr + input_section->size
|
||||||
|
- relax_info->workaround_size);
|
||||||
|
for (addr = ((start_addr & -pagesize) + pagesize - 4);
|
||||||
|
addr < end_addr;
|
||||||
|
addr += pagesize)
|
||||||
|
{
|
||||||
|
bfd_vma offset = addr - start_addr;
|
||||||
|
Elf_Internal_Rela *lo, *hi;
|
||||||
|
bfd_boolean is_data;
|
||||||
|
bfd_vma patch_off, patch_addr;
|
||||||
|
unsigned int insn;
|
||||||
|
|
||||||
|
/* Do we have a data reloc at this offset? If so, leave
|
||||||
|
the word alone. */
|
||||||
|
is_data = FALSE;
|
||||||
|
lo = relocs;
|
||||||
|
hi = lo + input_section->reloc_count;
|
||||||
|
while (lo < hi)
|
||||||
|
{
|
||||||
|
rel = lo + (hi - lo) / 2;
|
||||||
|
if (rel->r_offset < offset)
|
||||||
|
lo = rel + 1;
|
||||||
|
else if (rel->r_offset > offset)
|
||||||
|
hi = rel;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch (ELF32_R_TYPE (rel->r_info))
|
||||||
|
{
|
||||||
|
case R_PPC_ADDR32:
|
||||||
|
case R_PPC_UADDR32:
|
||||||
|
case R_PPC_REL32:
|
||||||
|
case R_PPC_ADDR30:
|
||||||
|
is_data = TRUE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (is_data)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Some instructions can be left alone too. In this
|
||||||
|
category are most insns that unconditionally change
|
||||||
|
control flow, and isync. Of these, some *must* be left
|
||||||
|
alone, for example, the "bcl 20, 31, label" used in pic
|
||||||
|
sequences to give the address of the next insn. twui
|
||||||
|
and twu apparently are not safe. */
|
||||||
|
insn = bfd_get_32 (input_bfd, contents + offset);
|
||||||
|
if (insn == 0
|
||||||
|
|| (insn & (0x3f << 26)) == (18u << 26) /* b */
|
||||||
|
|| ((insn & (0x3f << 26)) == (16u << 26) /* bc always */
|
||||||
|
&& (insn & (0x14 << 21)) == (0x14 << 21))
|
||||||
|
|| ((insn & (0x3f << 26)) == (19u << 26) /* blr, bctr */
|
||||||
|
&& (insn & (0x14 << 21)) == (0x14 << 21)
|
||||||
|
&& (insn & (0x1ff << 1)) == (16u << 1))
|
||||||
|
|| (insn & (0x3f << 26)) == (17u << 26) /* sc */
|
||||||
|
|| ((insn & (0x3f << 26)) == (19u << 26)
|
||||||
|
&& ((insn & (0x3ff << 1)) == (38u << 1) /* rfmci */
|
||||||
|
|| (insn & (0x3ff << 1)) == (50u << 1) /* rfi */
|
||||||
|
|| (insn & (0x3ff << 1)) == (51u << 1) /* rfci */
|
||||||
|
|| (insn & (0x3ff << 1)) == (82u << 1) /* rfsvc */
|
||||||
|
|| (insn & (0x3ff << 1)) == (150u << 1))) /* isync */)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
patch_addr = (start_addr + input_section->size
|
||||||
|
- relax_info->workaround_size);
|
||||||
|
patch_addr = (patch_addr + 15) & -16;
|
||||||
|
patch_off = patch_addr - start_addr;
|
||||||
|
bfd_put_32 (input_bfd, B + patch_off - offset, contents + offset);
|
||||||
|
if ((insn & (0x3f << 26)) == (16u << 26) /* bc */
|
||||||
|
&& (insn & 2) == 0 /* relative */)
|
||||||
|
{
|
||||||
|
bfd_vma delta = ((insn & 0xfffc) ^ 0x8000) - 0x8000;
|
||||||
|
|
||||||
|
delta += offset - patch_off;
|
||||||
|
if (delta + 0x8000 < 0x10000)
|
||||||
|
{
|
||||||
|
bfd_put_32 (input_bfd,
|
||||||
|
(insn & ~0xfffc) | (delta & 0xfffc),
|
||||||
|
contents + patch_off);
|
||||||
|
patch_off += 4;
|
||||||
|
bfd_put_32 (input_bfd,
|
||||||
|
B | ((offset + 4 - patch_off) & 0x3fffffc),
|
||||||
|
contents + patch_off);
|
||||||
|
patch_off += 4;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bfd_put_32 (input_bfd,
|
||||||
|
(insn & ~0xfffc) | 8,
|
||||||
|
contents + patch_off);
|
||||||
|
patch_off += 4;
|
||||||
|
bfd_put_32 (input_bfd,
|
||||||
|
B | ((offset + 4 - patch_off) & 0x3fffffc),
|
||||||
|
contents + patch_off);
|
||||||
|
patch_off += 4;
|
||||||
|
bfd_put_32 (input_bfd,
|
||||||
|
B | ((delta - 8) & 0x3fffffc),
|
||||||
|
contents + patch_off);
|
||||||
|
patch_off += 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bfd_put_32 (input_bfd, insn, contents + patch_off);
|
||||||
|
patch_off += 4;
|
||||||
|
bfd_put_32 (input_bfd,
|
||||||
|
B | ((offset + 4 - patch_off) & 0x3fffffc),
|
||||||
|
contents + patch_off);
|
||||||
|
patch_off += 4;
|
||||||
|
}
|
||||||
|
BFD_ASSERT (patch_off <= input_section->size);
|
||||||
|
relax_info->workaround_size = input_section->size - patch_off;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9350,7 +9586,7 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
|
||||||
|
|
||||||
p = (unsigned char *) htab->glink->contents + ent->glink_offset;
|
p = (unsigned char *) htab->glink->contents + ent->glink_offset;
|
||||||
|
|
||||||
if (h == htab->tls_get_addr && !htab->no_tls_get_addr_opt)
|
if (h == htab->tls_get_addr && !htab->params->no_tls_get_addr_opt)
|
||||||
{
|
{
|
||||||
bfd_put_32 (output_bfd, LWZ_11_3, p);
|
bfd_put_32 (output_bfd, LWZ_11_3, p);
|
||||||
p += 4;
|
p += 4;
|
||||||
|
|
|
@ -26,9 +26,29 @@ enum ppc_elf_plt_type
|
||||||
PLT_VXWORKS
|
PLT_VXWORKS
|
||||||
};
|
};
|
||||||
|
|
||||||
int ppc_elf_select_plt_layout (bfd *, struct bfd_link_info *,
|
/* Various options passed from the linker to bfd backend. */
|
||||||
enum ppc_elf_plt_type, int);
|
struct ppc_elf_params
|
||||||
asection *ppc_elf_tls_setup (bfd *, struct bfd_link_info *, int);
|
{
|
||||||
|
/* Chooses the type of .plt. */
|
||||||
|
enum ppc_elf_plt_type plt_style;
|
||||||
|
|
||||||
|
/* Whether to emit symbols for stubs. */
|
||||||
|
int emit_stub_syms;
|
||||||
|
|
||||||
|
/* Whether to emit special stub for __tls_get_addr calls. */
|
||||||
|
int no_tls_get_addr_opt;
|
||||||
|
|
||||||
|
/* Insert trampolines for branches that won't reach their destination. */
|
||||||
|
int branch_trampolines;
|
||||||
|
|
||||||
|
/* Avoid execution falling into new page. */
|
||||||
|
int ppc476_workaround;
|
||||||
|
int pagesize;
|
||||||
|
};
|
||||||
|
|
||||||
|
void ppc_elf_link_params (struct bfd_link_info *, struct ppc_elf_params *);
|
||||||
|
int ppc_elf_select_plt_layout (bfd *, struct bfd_link_info *);
|
||||||
|
asection *ppc_elf_tls_setup (bfd *, struct bfd_link_info *);
|
||||||
bfd_boolean ppc_elf_tls_optimize (bfd *, struct bfd_link_info *);
|
bfd_boolean ppc_elf_tls_optimize (bfd *, struct bfd_link_info *);
|
||||||
void ppc_elf_set_sdata_syms (bfd *, struct bfd_link_info *);
|
void ppc_elf_set_sdata_syms (bfd *, struct bfd_link_info *);
|
||||||
extern bfd_boolean ppc_elf_modify_segment_map (bfd *,
|
extern bfd_boolean ppc_elf_modify_segment_map (bfd *,
|
||||||
|
|
|
@ -388,6 +388,7 @@ CODE_FRAGMENT
|
||||||
.#define SEC_INFO_TYPE_MERGE 2
|
.#define SEC_INFO_TYPE_MERGE 2
|
||||||
.#define SEC_INFO_TYPE_EH_FRAME 3
|
.#define SEC_INFO_TYPE_EH_FRAME 3
|
||||||
.#define SEC_INFO_TYPE_JUST_SYMS 4
|
.#define SEC_INFO_TYPE_JUST_SYMS 4
|
||||||
|
.#define SEC_INFO_TYPE_TARGET 5
|
||||||
.
|
.
|
||||||
. {* Nonzero if this section uses RELA relocations, rather than REL. *}
|
. {* Nonzero if this section uses RELA relocations, rather than REL. *}
|
||||||
. unsigned int use_rela_p:1;
|
. unsigned int use_rela_p:1;
|
||||||
|
|
13
ld/ChangeLog
13
ld/ChangeLog
|
@ -1,3 +1,16 @@
|
||||||
|
2014-02-03 Alan Modra <amodra@gmail.com>
|
||||||
|
|
||||||
|
* emultempl/ppc32elf.em (no_tls_get_addr_opt, emit_stub_syms)
|
||||||
|
plt_style): Delete. Adjust all refs to instead use..
|
||||||
|
(params): ..this. New variable.
|
||||||
|
(ppc_after_open_output): New function. Tweak params and pass to
|
||||||
|
ppc_elf_link_params.
|
||||||
|
(ppc_after_open): Adjust ppc_elf_select_plt_layout call.
|
||||||
|
(ppc_before_allocation): Adjust ppc_elf_tls_setup call. Enable
|
||||||
|
relaxation for ppc476 workaround.
|
||||||
|
(PARSE_AND_LIST_*): Add --{no-,}ppc476-workaround support.
|
||||||
|
(LDEMUL_CREATE_OUTPUT_SECTION_STATEMENTS): Define.
|
||||||
|
|
||||||
2014-02-02 Sebastian Huber <sebastian.huber@embedded-brains.de>
|
2014-02-02 Sebastian Huber <sebastian.huber@embedded-brains.de>
|
||||||
|
|
||||||
* ld/ld.texinfo: Change ALIGN_WITH_INPUT documentation.
|
* ld/ld.texinfo: Change ALIGN_WITH_INPUT documentation.
|
||||||
|
|
|
@ -35,15 +35,24 @@ fragment <<EOF
|
||||||
|
|
||||||
/* Whether to run tls optimization. */
|
/* Whether to run tls optimization. */
|
||||||
static int notlsopt = 0;
|
static int notlsopt = 0;
|
||||||
static int no_tls_get_addr_opt = 0;
|
|
||||||
|
|
||||||
/* Whether to emit symbols for stubs. */
|
/* Choose the correct place for .got. */
|
||||||
static int emit_stub_syms = -1;
|
|
||||||
|
|
||||||
/* Chooses the correct place for .plt and .got. */
|
|
||||||
static enum ppc_elf_plt_type plt_style = PLT_UNSET;
|
|
||||||
static int old_got = 0;
|
static int old_got = 0;
|
||||||
|
|
||||||
|
static struct ppc_elf_params params = { PLT_UNSET, -1, 0, 0, 0, 0 };
|
||||||
|
|
||||||
|
static void
|
||||||
|
ppc_after_open_output (void)
|
||||||
|
{
|
||||||
|
if (params.emit_stub_syms < 0)
|
||||||
|
params.emit_stub_syms = link_info.emitrelocations || link_info.shared;
|
||||||
|
if (params.pagesize == 0)
|
||||||
|
params.pagesize = config.commonpagesize;
|
||||||
|
if (link_info.relocatable)
|
||||||
|
params.ppc476_workaround = 0;
|
||||||
|
ppc_elf_link_params (&link_info, ¶ms);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ppc_after_open (void)
|
ppc_after_open (void)
|
||||||
{
|
{
|
||||||
|
@ -57,10 +66,7 @@ ppc_after_open (void)
|
||||||
lang_output_section_statement_type *plt_os[2];
|
lang_output_section_statement_type *plt_os[2];
|
||||||
lang_output_section_statement_type *got_os[2];
|
lang_output_section_statement_type *got_os[2];
|
||||||
|
|
||||||
if (emit_stub_syms < 0)
|
new_plt = ppc_elf_select_plt_layout (link_info.output_bfd, &link_info);
|
||||||
emit_stub_syms = link_info.emitrelocations || link_info.shared;
|
|
||||||
new_plt = ppc_elf_select_plt_layout (link_info.output_bfd, &link_info,
|
|
||||||
plt_style, emit_stub_syms);
|
|
||||||
if (new_plt < 0)
|
if (new_plt < 0)
|
||||||
einfo ("%X%P: select_plt_layout problem %E\n");
|
einfo ("%X%P: select_plt_layout problem %E\n");
|
||||||
|
|
||||||
|
@ -107,8 +113,7 @@ ppc_before_allocation (void)
|
||||||
{
|
{
|
||||||
if (is_ppc_elf (link_info.output_bfd))
|
if (is_ppc_elf (link_info.output_bfd))
|
||||||
{
|
{
|
||||||
if (ppc_elf_tls_setup (link_info.output_bfd, &link_info,
|
if (ppc_elf_tls_setup (link_info.output_bfd, &link_info)
|
||||||
no_tls_get_addr_opt)
|
|
||||||
&& !notlsopt)
|
&& !notlsopt)
|
||||||
{
|
{
|
||||||
if (!ppc_elf_tls_optimize (link_info.output_bfd, &link_info))
|
if (!ppc_elf_tls_optimize (link_info.output_bfd, &link_info))
|
||||||
|
@ -121,9 +126,12 @@ ppc_before_allocation (void)
|
||||||
|
|
||||||
gld${EMULATION_NAME}_before_allocation ();
|
gld${EMULATION_NAME}_before_allocation ();
|
||||||
|
|
||||||
|
if (RELAXATION_ENABLED)
|
||||||
|
params.branch_trampolines = 1;
|
||||||
|
|
||||||
/* Turn on relaxation if executable sections have addresses that
|
/* Turn on relaxation if executable sections have addresses that
|
||||||
might make branches overflow. */
|
might make branches overflow. */
|
||||||
if (RELAXATION_DISABLED_BY_DEFAULT)
|
else if (!RELAXATION_DISABLED_BY_USER)
|
||||||
{
|
{
|
||||||
bfd_vma low = (bfd_vma) -1;
|
bfd_vma low = (bfd_vma) -1;
|
||||||
bfd_vma high = 0;
|
bfd_vma high = 0;
|
||||||
|
@ -150,8 +158,11 @@ ppc_before_allocation (void)
|
||||||
high = o->vma + o->rawsize - 1;
|
high = o->vma + o->rawsize - 1;
|
||||||
}
|
}
|
||||||
if (high > low && high - low > (1 << 25) - 1)
|
if (high > low && high - low > (1 << 25) - 1)
|
||||||
ENABLE_RELAXATION;
|
params.branch_trampolines = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (params.ppc476_workaround || params.branch_trampolines)
|
||||||
|
ENABLE_RELAXATION;
|
||||||
}
|
}
|
||||||
|
|
||||||
EOF
|
EOF
|
||||||
|
@ -186,6 +197,8 @@ PARSE_AND_LIST_PROLOGUE=${PARSE_AND_LIST_PROLOGUE}'
|
||||||
#define OPTION_OLD_GOT (OPTION_OLD_PLT + 1)
|
#define OPTION_OLD_GOT (OPTION_OLD_PLT + 1)
|
||||||
#define OPTION_STUBSYMS (OPTION_OLD_GOT + 1)
|
#define OPTION_STUBSYMS (OPTION_OLD_GOT + 1)
|
||||||
#define OPTION_NO_STUBSYMS (OPTION_STUBSYMS + 1)
|
#define OPTION_NO_STUBSYMS (OPTION_STUBSYMS + 1)
|
||||||
|
#define OPTION_PPC476_WORKAROUND (OPTION_NO_STUBSYMS + 1)
|
||||||
|
#define OPTION_NO_PPC476_WORKAROUND (OPTION_PPC476_WORKAROUND + 1)
|
||||||
'
|
'
|
||||||
|
|
||||||
PARSE_AND_LIST_LONGOPTS=${PARSE_AND_LIST_LONGOPTS}'
|
PARSE_AND_LIST_LONGOPTS=${PARSE_AND_LIST_LONGOPTS}'
|
||||||
|
@ -196,6 +209,8 @@ PARSE_AND_LIST_LONGOPTS=${PARSE_AND_LIST_LONGOPTS}'
|
||||||
{ "secure-plt", no_argument, NULL, OPTION_NEW_PLT },
|
{ "secure-plt", no_argument, NULL, OPTION_NEW_PLT },
|
||||||
{ "bss-plt", no_argument, NULL, OPTION_OLD_PLT },
|
{ "bss-plt", no_argument, NULL, OPTION_OLD_PLT },
|
||||||
{ "sdata-got", no_argument, NULL, OPTION_OLD_GOT },
|
{ "sdata-got", no_argument, NULL, OPTION_OLD_GOT },
|
||||||
|
{ "ppc476-workaround", optional_argument, NULL, OPTION_PPC476_WORKAROUND },
|
||||||
|
{ "no-ppc476-workaround", no_argument, NULL, OPTION_NO_PPC476_WORKAROUND },
|
||||||
'
|
'
|
||||||
|
|
||||||
PARSE_AND_LIST_OPTIONS=${PARSE_AND_LIST_OPTIONS}'
|
PARSE_AND_LIST_OPTIONS=${PARSE_AND_LIST_OPTIONS}'
|
||||||
|
@ -206,17 +221,20 @@ PARSE_AND_LIST_OPTIONS=${PARSE_AND_LIST_OPTIONS}'
|
||||||
--no-tls-get-addr-optimize Don'\''t use a special __tls_get_addr call.\n\
|
--no-tls-get-addr-optimize Don'\''t use a special __tls_get_addr call.\n\
|
||||||
--secure-plt Use new-style PLT if possible.\n\
|
--secure-plt Use new-style PLT if possible.\n\
|
||||||
--bss-plt Force old-style BSS PLT.\n\
|
--bss-plt Force old-style BSS PLT.\n\
|
||||||
--sdata-got Force GOT location just before .sdata.\n"
|
--sdata-got Force GOT location just before .sdata.\n\
|
||||||
|
--ppc476-workaround [=pagesize]\n\
|
||||||
|
Avoid a cache bug on ppc476.\n\
|
||||||
|
--no-ppc476-workaround Disable workaround.\n"
|
||||||
));
|
));
|
||||||
'
|
'
|
||||||
|
|
||||||
PARSE_AND_LIST_ARGS_CASES=${PARSE_AND_LIST_ARGS_CASES}'
|
PARSE_AND_LIST_ARGS_CASES=${PARSE_AND_LIST_ARGS_CASES}'
|
||||||
case OPTION_STUBSYMS:
|
case OPTION_STUBSYMS:
|
||||||
emit_stub_syms = 1;
|
params.emit_stub_syms = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OPTION_NO_STUBSYMS:
|
case OPTION_NO_STUBSYMS:
|
||||||
emit_stub_syms = 0;
|
params.emit_stub_syms = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OPTION_NO_TLS_OPT:
|
case OPTION_NO_TLS_OPT:
|
||||||
|
@ -224,15 +242,15 @@ PARSE_AND_LIST_ARGS_CASES=${PARSE_AND_LIST_ARGS_CASES}'
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OPTION_NO_TLS_GET_ADDR_OPT:
|
case OPTION_NO_TLS_GET_ADDR_OPT:
|
||||||
no_tls_get_addr_opt = 1;
|
params.no_tls_get_addr_opt = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OPTION_NEW_PLT:
|
case OPTION_NEW_PLT:
|
||||||
plt_style = PLT_NEW;
|
params.plt_style = PLT_NEW;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OPTION_OLD_PLT:
|
case OPTION_OLD_PLT:
|
||||||
plt_style = PLT_OLD;
|
params.plt_style = PLT_OLD;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OPTION_OLD_GOT:
|
case OPTION_OLD_GOT:
|
||||||
|
@ -241,11 +259,29 @@ PARSE_AND_LIST_ARGS_CASES=${PARSE_AND_LIST_ARGS_CASES}'
|
||||||
|
|
||||||
case OPTION_TRADITIONAL_FORMAT:
|
case OPTION_TRADITIONAL_FORMAT:
|
||||||
notlsopt = 1;
|
notlsopt = 1;
|
||||||
no_tls_get_addr_opt = 1;
|
params.no_tls_get_addr_opt = 1;
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
|
case OPTION_PPC476_WORKAROUND:
|
||||||
|
params.ppc476_workaround = 1;
|
||||||
|
if (optarg != NULL)
|
||||||
|
{
|
||||||
|
char *end;
|
||||||
|
params.pagesize = strtoul (optarg, &end, 0);
|
||||||
|
if (*end
|
||||||
|
|| (params.pagesize < 4096 && params.pagesize != 0)
|
||||||
|
|| params.pagesize != (params.pagesize & -params.pagesize))
|
||||||
|
einfo (_("%P%F: invalid pagesize `%s'\''\n"), optarg);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OPTION_NO_PPC476_WORKAROUND:
|
||||||
|
params.ppc476_workaround = 0;
|
||||||
|
break;
|
||||||
'
|
'
|
||||||
|
|
||||||
# Put these extra ppc32elf routines in ld_${EMULATION_NAME}_emulation
|
# Put these extra ppc32elf routines in ld_${EMULATION_NAME}_emulation
|
||||||
#
|
#
|
||||||
|
LDEMUL_CREATE_OUTPUT_SECTION_STATEMENTS=ppc_after_open_output
|
||||||
LDEMUL_AFTER_OPEN=ppc_after_open
|
LDEMUL_AFTER_OPEN=ppc_after_open
|
||||||
LDEMUL_BEFORE_ALLOCATION=ppc_before_allocation
|
LDEMUL_BEFORE_ALLOCATION=ppc_before_allocation
|
||||||
|
|
Loading…
Add table
Reference in a new issue