diff options
author | Alan Modra <amodra@gmail.com> | 2019-02-21 17:41:47 +1030 |
---|---|---|
committer | Alan Modra <amodra@gmail.com> | 2019-02-21 18:05:05 +1030 |
commit | 160eba9301df423116377113f2d4189d785c7dde (patch) | |
tree | 4d7ea53d3c4c1622c7b8caeec879c639690c7a1d /gas | |
parent | 56b80d4c4c24c6acacad15530a3a7b483b6e0f3f (diff) | |
download | gdb-160eba9301df423116377113f2d4189d785c7dde.zip gdb-160eba9301df423116377113f2d4189d785c7dde.tar.gz gdb-160eba9301df423116377113f2d4189d785c7dde.tar.bz2 |
PowerPC __tls_get_addr arg parsing
The syntax we ended up with for -m32 -fPIC calls to __tls_get_addr is
rather weird.
bl __tls_get_addr+0x8000(gd0@tlsgd)@plt
This came about by accident, probably due to requiring the arg reloc
before the call reloc.
Of course the @plt really belongs with __tls_get_addr since it affects
the call rather than the call arg, and it isn't a great deal of
trouble to ensure the relocs are emitted in the correct order. This
patch supports a newer syntax, like so:
bl __tls_get_addr+0x8000@plt(gd0@tlsgd)
gas/
* config/tc-ppc.c (parse_tls_arg): New function, extracted..
(md_assembler): ..from here. Call it after parsing other
suffix modifiers too.
ld/
* testsuite/ld-powerpc/tls32.s: Test new @plt syntax.
Diffstat (limited to 'gas')
-rw-r--r-- | gas/config/tc-ppc.c | 92 |
1 files changed, 52 insertions, 40 deletions
diff --git a/gas/config/tc-ppc.c b/gas/config/tc-ppc.c index e8deb32..35d85a4 100644 --- a/gas/config/tc-ppc.c +++ b/gas/config/tc-ppc.c @@ -2999,6 +2999,43 @@ fixup_size (bfd_reloc_code_real_type reloc, bfd_boolean *pc_relative) return size; } +/* If we have parsed a call to __tls_get_addr, parse an argument like + (gd0@tlsgd). *STR is the leading parenthesis on entry. If an arg + is successfully parsed, *STR is updated past the trailing + parenthesis and trailing white space, and *TLS_FIX contains the + reloc and arg expression. */ + +static int +parse_tls_arg (char **str, const expressionS *exp, struct ppc_fixup *tls_fix) +{ + const char *sym_name = S_GET_NAME (exp->X_add_symbol); + if (sym_name[0] == '.') + ++sym_name; + + tls_fix->reloc = BFD_RELOC_NONE; + if (strcasecmp (sym_name, "__tls_get_addr") == 0) + { + char *hold = input_line_pointer; + input_line_pointer = *str + 1; + expression (&tls_fix->exp); + if (tls_fix->exp.X_op == O_symbol) + { + if (strncasecmp (input_line_pointer, "@tlsgd)", 7) == 0) + tls_fix->reloc = BFD_RELOC_PPC_TLSGD; + else if (strncasecmp (input_line_pointer, "@tlsld)", 7) == 0) + tls_fix->reloc = BFD_RELOC_PPC_TLSLD; + if (tls_fix->reloc != BFD_RELOC_NONE) + { + input_line_pointer += 7; + SKIP_WHITESPACE (); + *str = input_line_pointer; + } + } + input_line_pointer = hold; + } + return tls_fix->reloc != BFD_RELOC_NONE; +} + /* This routine is called for each instruction to be assembled. */ void @@ -3388,47 +3425,12 @@ md_assemble (char *str) { bfd_reloc_code_real_type reloc = BFD_RELOC_NONE; #ifdef OBJ_ELF - if (ex.X_op == O_symbol && str[0] == '(') + /* Look for a __tls_get_addr arg using the insane old syntax. */ + if (ex.X_op == O_symbol && *str == '(' && fc < MAX_INSN_FIXUPS + && parse_tls_arg (&str, &ex, &fixups[fc])) { - const char *sym_name = S_GET_NAME (ex.X_add_symbol); - if (sym_name[0] == '.') - ++sym_name; - - if (strcasecmp (sym_name, "__tls_get_addr") == 0) - { - expressionS tls_exp; - - hold = input_line_pointer; - input_line_pointer = str + 1; - expression (&tls_exp); - if (tls_exp.X_op == O_symbol) - { - reloc = BFD_RELOC_NONE; - if (strncasecmp (input_line_pointer, "@tlsgd)", 7) == 0) - { - reloc = BFD_RELOC_PPC_TLSGD; - input_line_pointer += 7; - } - else if (strncasecmp (input_line_pointer, "@tlsld)", 7) == 0) - { - reloc = BFD_RELOC_PPC_TLSLD; - input_line_pointer += 7; - } - if (reloc != BFD_RELOC_NONE) - { - SKIP_WHITESPACE (); - str = input_line_pointer; - - if (fc >= MAX_INSN_FIXUPS) - as_fatal (_("too many fixups")); - fixups[fc].exp = tls_exp; - fixups[fc].opindex = *opindex_ptr; - fixups[fc].reloc = reloc; - ++fc; - } - } - input_line_pointer = hold; - } + fixups[fc].opindex = *opindex_ptr; + ++fc; } if ((reloc = ppc_elf_suffix (&str, &ex)) != BFD_RELOC_NONE) @@ -3703,6 +3705,16 @@ md_assemble (char *str) break; } } + + /* Look for a __tls_get_addr arg after any __tls_get_addr + modifiers like @plt. This fixup must be emitted before + the usual call fixup. */ + if (ex.X_op == O_symbol && *str == '(' && fc < MAX_INSN_FIXUPS + && parse_tls_arg (&str, &ex, &fixups[fc])) + { + fixups[fc].opindex = *opindex_ptr; + ++fc; + } #endif /* We need to generate a fixup for this expression. */ |