diff options
Diffstat (limited to 'gas')
-rw-r--r-- | gas/ChangeLog | 18 | ||||
-rw-r--r-- | gas/config/tc-tic6x.c | 73 | ||||
-rw-r--r-- | gas/config/tc-tic6x.h | 6 |
3 files changed, 92 insertions, 5 deletions
diff --git a/gas/ChangeLog b/gas/ChangeLog index 660daad..5ad2e43 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,21 @@ +2010-04-20 Joseph Myers <joseph@codesourcery.com> + + * config/tc-tic6x.c (OPTION_MGENERATE_REL): New. + (md_longopts): Add -mgenerate-rel. + (tic6x_generate_rela): New. + (md_parse_option): Handle -mgenerate-rel. + (md_show_usage): Add comment that -mgenerate-rel is undocumented. + (tic6x_init_after_args): New. + (md_apply_fix): Correct shift calculations for SB-relative + relocations. + (md_pcrel_from): Change to tic6x_pcrel_from_section. Do not + adjust addresses for relocations referencing symbols in other + sections. + (tc_gen_reloc): Adjust addend calculations for REL relocations. + * config/tc-tic6x.h (MD_PCREL_FROM_SECTION, + tic6x_pcrel_from_section, tc_init_after_args, + tic6x_init_after_args): New. + 2010-04-20 Nick Clifton <nickc@redhat.com> PR gas/11507 diff --git a/gas/config/tc-tic6x.c b/gas/config/tc-tic6x.c index 730b786..d746f94 100644 --- a/gas/config/tc-tic6x.c +++ b/gas/config/tc-tic6x.c @@ -24,6 +24,7 @@ #include "safe-ctype.h" #include "subsegs.h" #include "opcode/tic6x.h" +#include "elf32-tic6x.h" /* Truncate and sign-extend at 32 bits, so that building on a 64-bit host gives identical results to a 32-bit host. */ @@ -45,7 +46,8 @@ enum OPTION_MATOMIC, OPTION_MNO_ATOMIC, OPTION_MBIG_ENDIAN, - OPTION_MLITTLE_ENDIAN + OPTION_MLITTLE_ENDIAN, + OPTION_MGENERATE_REL }; struct option md_longopts[] = @@ -55,6 +57,7 @@ struct option md_longopts[] = { "mno-atomic", no_argument, NULL, OPTION_MNO_ATOMIC }, { "mbig-endian", no_argument, NULL, OPTION_MBIG_ENDIAN }, { "mlittle-endian", no_argument, NULL, OPTION_MLITTLE_ENDIAN }, + { "mgenerate-rel", no_argument, NULL, OPTION_MGENERATE_REL }, { NULL, no_argument, NULL, 0 } }; size_t md_longopts_size = sizeof (md_longopts); @@ -95,6 +98,9 @@ static bfd_boolean tic6x_long_data_constraints; /* Whether compact instructions are available. */ static bfd_boolean tic6x_compact_insns; +/* Whether to generate RELA relocations. */ +static bfd_boolean tic6x_generate_rela = TRUE; + /* Table of supported architecture variants. */ typedef struct { @@ -162,6 +168,10 @@ md_parse_option (int c, char *arg) target_big_endian = 0; break; + case OPTION_MGENERATE_REL: + tic6x_generate_rela = FALSE; + break; + default: return 0; } @@ -180,6 +190,8 @@ md_show_usage (FILE *stream ATTRIBUTE_UNUSED) fprintf (stream, _(" -mno-atomic disable atomic operation instructions\n")); fprintf (stream, _(" -mbig-endian generate big-endian code\n")); fprintf (stream, _(" -mlittle-endian generate little-endian code\n")); + /* -mgenerate-rel is only for testsuite use and is deliberately + undocumented. */ fputc ('\n', stream); fprintf (stream, _("Supported ARCH values are:")); @@ -512,6 +524,15 @@ tic6x_cleanup (void) tic6x_end_of_line (); } +/* Do target-specific initialization after arguments have been + processed and the output file created. */ + +void +tic6x_init_after_args (void) +{ + elf32_tic6x_set_use_rela_p (stdoutput, tic6x_generate_rela); +} + /* Handle a data alignment of N bytes. */ void @@ -3111,8 +3132,25 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED) if (fixP->fx_done || !seg->use_rela_p) { offsetT newval = md_chars_to_number (buf, 4); + int shift; + + switch (fixP->fx_r_type) + { + case BFD_RELOC_C6000_SBR_L16_H: + shift = 1; + break; + + case BFD_RELOC_C6000_SBR_L16_W: + case BFD_RELOC_C6000_SBR_GOT_L16_W: + shift = 2; + break; + + default: + shift = 0; + break; + } - MODIFY_VALUE (newval, value, 0, 7, 16); + MODIFY_VALUE (newval, value, shift, 7, 16); if ((value < -0x8000 || value > 0x7fff) && (fixP->fx_r_type == BFD_RELOC_C6000_ABS_S16 || fixP->fx_r_type == BFD_RELOC_C6000_SBR_S16)) @@ -3135,8 +3173,25 @@ md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED) if (fixP->fx_done || !seg->use_rela_p) { offsetT newval = md_chars_to_number (buf, 4); + int shift; + + switch (fixP->fx_r_type) + { + case BFD_RELOC_C6000_SBR_H16_H: + shift = 17; + break; + + case BFD_RELOC_C6000_SBR_H16_W: + case BFD_RELOC_C6000_SBR_GOT_H16_W: + shift = 18; + break; - MODIFY_VALUE (newval, value, 16, 7, 16); + default: + shift = 16; + break; + } + + MODIFY_VALUE (newval, value, shift, 7, 16); md_number_to_chars (buf, newval, 4); } @@ -3348,8 +3403,12 @@ md_operand (expressionS *op ATTRIBUTE_UNUSED) packet. */ long -md_pcrel_from (fixS *fixp) +tic6x_pcrel_from_section (fixS *fixp, segT sec) { + if (fixp->fx_addsy != NULL + && (!S_IS_DEFINED (fixp->fx_addsy) + || S_GET_SEGMENT (fixp->fx_addsy) != sec)) + return 0; return (fixp->fx_where + fixp->fx_frag->fr_address) & ~(long) 0x1f; } @@ -3386,7 +3445,7 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp) reloc->sym_ptr_ptr = xmalloc (sizeof (asymbol *)); *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy); reloc->address = fixp->fx_frag->fr_address + fixp->fx_where; - reloc->addend = fixp->fx_offset; + reloc->addend = (tic6x_generate_rela ? fixp->fx_offset : 0); r_type = fixp->fx_r_type; reloc->howto = bfd_reloc_type_lookup (stdoutput, r_type); @@ -3398,5 +3457,9 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp) return NULL; } + /* Correct for adjustments bfd_install_relocation will make. */ + if (reloc->howto->pcrel_offset && reloc->howto->partial_inplace) + reloc->addend += reloc->address; + return reloc; } diff --git a/gas/config/tc-tic6x.h b/gas/config/tc-tic6x.h index 05c3db8..087b9e9 100644 --- a/gas/config/tc-tic6x.h +++ b/gas/config/tc-tic6x.h @@ -96,6 +96,9 @@ extern void tic6x_cons_align (int n); extern int tic6x_parse_name (const char *name, expressionS *exprP, enum expr_mode mode, char *nextchar); +#define MD_PCREL_FROM_SECTION(FIX, SEC) tic6x_pcrel_from_section (FIX, SEC) +extern long tic6x_pcrel_from_section (struct fix *fixp, segT sec); + #define md_start_line_hook() tic6x_start_line_hook () extern void tic6x_start_line_hook (void); @@ -107,5 +110,8 @@ extern void tic6x_cons_fix_new (fragS *frag, int where, int size, #define tc_frob_label(sym) tic6x_frob_label (sym) extern void tic6x_frob_label (symbolS *sym); +#define tc_init_after_args() tic6x_init_after_args () +extern void tic6x_init_after_args (void); + #define tc_unrecognized_line(c) tic6x_unrecognized_line (c) extern int tic6x_unrecognized_line (int c); |