aboutsummaryrefslogtreecommitdiff
path: root/ld/emultempl
diff options
context:
space:
mode:
authorAlan Modra <amodra@gmail.com>2014-01-30 08:26:02 +1030
committerAlan Modra <amodra@gmail.com>2014-02-03 20:24:20 +1030
commit5446cbdf82892a800ed7eef563a795e75223ec52 (patch)
tree5abcadcfcfd715515d8c13b7905a03626004ef2c /ld/emultempl
parent8effdc96dc110ef0bcd256bdc026d56d373c2e11 (diff)
downloadgdb-5446cbdf82892a800ed7eef563a795e75223ec52.zip
gdb-5446cbdf82892a800ed7eef563a795e75223ec52.tar.gz
gdb-5446cbdf82892a800ed7eef563a795e75223ec52.tar.bz2
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.
Diffstat (limited to 'ld/emultempl')
-rw-r--r--ld/emultempl/ppc32elf.em78
1 files changed, 57 insertions, 21 deletions
diff --git a/ld/emultempl/ppc32elf.em b/ld/emultempl/ppc32elf.em
index 6843770..afa85ff 100644
--- a/ld/emultempl/ppc32elf.em
+++ b/ld/emultempl/ppc32elf.em
@@ -35,15 +35,24 @@ fragment <<EOF
/* Whether to run tls optimization. */
static int notlsopt = 0;
-static int no_tls_get_addr_opt = 0;
-/* Whether to emit symbols for stubs. */
-static int emit_stub_syms = -1;
-
-/* Chooses the correct place for .plt and .got. */
-static enum ppc_elf_plt_type plt_style = PLT_UNSET;
+/* Choose the correct place for .got. */
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, &params);
+}
+
static 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 *got_os[2];
- if (emit_stub_syms < 0)
- 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);
+ new_plt = ppc_elf_select_plt_layout (link_info.output_bfd, &link_info);
if (new_plt < 0)
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 (ppc_elf_tls_setup (link_info.output_bfd, &link_info,
- no_tls_get_addr_opt)
+ if (ppc_elf_tls_setup (link_info.output_bfd, &link_info)
&& !notlsopt)
{
if (!ppc_elf_tls_optimize (link_info.output_bfd, &link_info))
@@ -121,9 +126,12 @@ ppc_before_allocation (void)
gld${EMULATION_NAME}_before_allocation ();
+ if (RELAXATION_ENABLED)
+ params.branch_trampolines = 1;
+
/* Turn on relaxation if executable sections have addresses that
might make branches overflow. */
- if (RELAXATION_DISABLED_BY_DEFAULT)
+ else if (!RELAXATION_DISABLED_BY_USER)
{
bfd_vma low = (bfd_vma) -1;
bfd_vma high = 0;
@@ -150,8 +158,11 @@ ppc_before_allocation (void)
high = o->vma + o->rawsize - 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
@@ -186,6 +197,8 @@ PARSE_AND_LIST_PROLOGUE=${PARSE_AND_LIST_PROLOGUE}'
#define OPTION_OLD_GOT (OPTION_OLD_PLT + 1)
#define OPTION_STUBSYMS (OPTION_OLD_GOT + 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}'
@@ -196,6 +209,8 @@ PARSE_AND_LIST_LONGOPTS=${PARSE_AND_LIST_LONGOPTS}'
{ "secure-plt", no_argument, NULL, OPTION_NEW_PLT },
{ "bss-plt", no_argument, NULL, OPTION_OLD_PLT },
{ "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}'
@@ -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\
--secure-plt Use new-style PLT if possible.\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}'
case OPTION_STUBSYMS:
- emit_stub_syms = 1;
+ params.emit_stub_syms = 1;
break;
case OPTION_NO_STUBSYMS:
- emit_stub_syms = 0;
+ params.emit_stub_syms = 0;
break;
case OPTION_NO_TLS_OPT:
@@ -224,15 +242,15 @@ PARSE_AND_LIST_ARGS_CASES=${PARSE_AND_LIST_ARGS_CASES}'
break;
case OPTION_NO_TLS_GET_ADDR_OPT:
- no_tls_get_addr_opt = 1;
+ params.no_tls_get_addr_opt = 1;
break;
case OPTION_NEW_PLT:
- plt_style = PLT_NEW;
+ params.plt_style = PLT_NEW;
break;
case OPTION_OLD_PLT:
- plt_style = PLT_OLD;
+ params.plt_style = PLT_OLD;
break;
case OPTION_OLD_GOT:
@@ -241,11 +259,29 @@ PARSE_AND_LIST_ARGS_CASES=${PARSE_AND_LIST_ARGS_CASES}'
case OPTION_TRADITIONAL_FORMAT:
notlsopt = 1;
- no_tls_get_addr_opt = 1;
+ params.no_tls_get_addr_opt = 1;
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
#
+LDEMUL_CREATE_OUTPUT_SECTION_STATEMENTS=ppc_after_open_output
LDEMUL_AFTER_OPEN=ppc_after_open
LDEMUL_BEFORE_ALLOCATION=ppc_before_allocation