From 2dc782f67fd7b32fae0e7e7d0ed4ed6052fabcb5 Mon Sep 17 00:00:00 2001 From: Alexandre Oliva Date: Thu, 10 Jul 2003 03:20:14 +0000 Subject: [PATCH] 2003-02-25 Alexandre Oliva * config/tc-mn10300.c (mn10300_check_fixup): Set GOT_PCREL type for subtracts from GLOBAL_OFFSET_TABLE that could not be simplified. 2002-07-18 Alexandre Oliva * config/tc-mn10300.c (mn10300_check_fixup): Accept subtracts that could not be simplified. (tc_gen_reloc): Turn an absolute fx_subsy into part of fx_offset. 2001-11-04 Alexandre Oliva * config/tc-mn10300.h (TC_RELOC_RTSYM_LOC_FIXUP): Don't adjust BDF_RELOC_MN10300_GOT32. * config/tc-mn10300.c (mn10300_fix_adjustable): If TC_RELOC_RTSYM_LOC_FIXUP doesn't hold, it's not adjustable. 2001-05-09 Alexandre Oliva * config/tc-mn10300.c (mn10300_parse_name): Don't return a symbol if we know its value. 2001-05-09 Alexandre Oliva * config/tc-mn10300.h (GLOBAL_OFFSET_TABLE_NAME): Remove duplicate underscore prefix. 2001-05-09 Alexandre Oliva * config/tc-mn10300.c (mn10300_parse_name): Store relocation type in X_md, not X_add_number. Zero X_add_number. (mn10300_check_fixup): Extract relocation type from X_md. * config/tc-mn10300.h: Update comment. 2001-04-14 Alexandre Oliva * config/tc-mn10300.h (O_GOTOFF, O_PLT, O_GOT): Replace with... (O_PIC_reloc): this. * config/tc-mn10300.c (mn10300_PIC_related_p): Use it. (mn10300_check_fixup): Likewise. (mn10300_parse_name): Set X_add_number to relocation type. * config/tc-mn10300.h (DIFF_EXPR_OK, GLOBAL_OFFSET_TABLE_NAME, TC_RELOC_RTSYM_LOC_FIXUP, md_parse_name, TC_CONS_FIX_NEW, O_GOTOFF, O_PLT, O_GOT): Define. * config/tc-mn10300.c (mn10300_PIC_related_p): New fn. (mn10300_check_fixup): New fn. (md_assemble): Call it. Check for PIC-related relocs. (mn10300_cons_fix_new): Likewise. New fn. (mn10300_end_of_match): New fn. (mn10300_md_parse_name_cont): New fn. --- gas/ChangeLog | 42 +++++++++ gas/config/tc-mn10300.c | 244 +++++++++++++++++++++++++++++++++++++++++++++++- gas/config/tc-mn10300.h | 25 +++++ 3 files changed, 309 insertions(+), 2 deletions(-) diff --git a/gas/ChangeLog b/gas/ChangeLog index d7ee712a3b..ddfe1a50f6 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,5 +1,47 @@ 2003-07-09 Alexandre Oliva + 2003-02-25 Alexandre Oliva + * config/tc-mn10300.c (mn10300_check_fixup): Set GOT_PCREL type + for subtracts from GLOBAL_OFFSET_TABLE that could not be + simplified. + 2002-07-18 Alexandre Oliva + * config/tc-mn10300.c (mn10300_check_fixup): Accept subtracts that + could not be simplified. + (tc_gen_reloc): Turn an absolute fx_subsy into part of fx_offset. + 2001-11-04 Alexandre Oliva + * config/tc-mn10300.h (TC_RELOC_RTSYM_LOC_FIXUP): Don't adjust + BDF_RELOC_MN10300_GOT32. + * config/tc-mn10300.c (mn10300_fix_adjustable): If + TC_RELOC_RTSYM_LOC_FIXUP doesn't hold, it's not adjustable. + 2001-05-09 Alexandre Oliva + * config/tc-mn10300.c (mn10300_parse_name): Don't return a + symbol if we know its value. + 2001-05-09 Alexandre Oliva + * config/tc-mn10300.h (GLOBAL_OFFSET_TABLE_NAME): Remove + duplicate underscore prefix. + 2001-05-09 Alexandre Oliva + * config/tc-mn10300.c (mn10300_parse_name): Store relocation + type in X_md, not X_add_number. Zero X_add_number. + (mn10300_check_fixup): Extract relocation type from X_md. + * config/tc-mn10300.h: Update comment. + 2001-04-14 Alexandre Oliva + * config/tc-mn10300.h (O_GOTOFF, O_PLT, O_GOT): Replace with... + (O_PIC_reloc): this. + * config/tc-mn10300.c (mn10300_PIC_related_p): Use it. + (mn10300_check_fixup): Likewise. + (mn10300_parse_name): Set X_add_number to relocation type. + * config/tc-mn10300.h (DIFF_EXPR_OK, GLOBAL_OFFSET_TABLE_NAME, + TC_RELOC_RTSYM_LOC_FIXUP, md_parse_name, TC_CONS_FIX_NEW, + O_GOTOFF, O_PLT, O_GOT): Define. + * config/tc-mn10300.c (mn10300_PIC_related_p): New fn. + (mn10300_check_fixup): New fn. + (md_assemble): Call it. Check for PIC-related relocs. + (mn10300_cons_fix_new): Likewise. New fn. + (mn10300_end_of_match): New fn. + (mn10300_md_parse_name_cont): New fn. + +2003-07-09 Alexandre Oliva + 2000-05-25 Alexandre Oliva * config/tc-mn10300.c (mn10300_insert_operand): Negate negative accumulator's shift. diff --git a/gas/config/tc-mn10300.c b/gas/config/tc-mn10300.c index ff2fffa148..e36d0f9ada 100644 --- a/gas/config/tc-mn10300.c +++ b/gas/config/tc-mn10300.c @@ -1219,6 +1219,140 @@ md_begin () current_machine = MN103; } +static symbolS *GOT_symbol; + +static inline int mn10300_check_fixup PARAMS ((struct mn10300_fixup *)); +static inline int mn10300_PIC_related_p PARAMS ((symbolS *)); + +static inline int +mn10300_PIC_related_p (sym) + symbolS *sym; +{ + expressionS *exp; + + if (! sym) + return 0; + + if (sym == GOT_symbol) + return 1; + + exp = symbol_get_value_expression (sym); + + return (exp->X_op == O_PIC_reloc + || mn10300_PIC_related_p (exp->X_add_symbol) + || mn10300_PIC_related_p (exp->X_op_symbol)); +} + +static inline int +mn10300_check_fixup (fixup) + struct mn10300_fixup *fixup; +{ + expressionS *exp = &fixup->exp; + + repeat: + switch (exp->X_op) + { + case O_add: + case O_subtract: /* If we're sufficiently unlucky that the label + and the expression that references it happen + to end up in different frags, the subtract + won't be simplified within expression(). */ + /* The PIC-related operand must be the first operand of a sum. */ + if (exp != &fixup->exp || mn10300_PIC_related_p (exp->X_op_symbol)) + return 1; + + if (exp->X_add_symbol && exp->X_add_symbol == GOT_symbol) + fixup->reloc = BFD_RELOC_32_GOT_PCREL; + + exp = symbol_get_value_expression (exp->X_add_symbol); + goto repeat; + + case O_symbol: + if (exp->X_add_symbol && exp->X_add_symbol == GOT_symbol) + fixup->reloc = BFD_RELOC_32_GOT_PCREL; + break; + + case O_PIC_reloc: + fixup->reloc = exp->X_md; + exp->X_op = O_symbol; + if (fixup->reloc == BFD_RELOC_32_PLT_PCREL + && fixup->opindex >= 0 + && (mn10300_operands[fixup->opindex].flags + & MN10300_OPERAND_RELAX)) + return 1; + break; + + default: + return (mn10300_PIC_related_p (exp->X_add_symbol) + || mn10300_PIC_related_p (exp->X_op_symbol)); + } + + return 0; +} + +void +mn10300_cons_fix_new (frag, off, size, exp) + fragS *frag; + int off, size; + expressionS *exp; +{ + struct mn10300_fixup fixup; + + fixup.opindex = -1; + fixup.exp = *exp; + fixup.reloc = BFD_RELOC_UNUSED; + + mn10300_check_fixup (&fixup); + + if (fixup.reloc == BFD_RELOC_MN10300_GOT32) + switch (size) + { + case 2: + fixup.reloc = BFD_RELOC_MN10300_GOT16; + break; + + case 3: + fixup.reloc = BFD_RELOC_MN10300_GOT24; + break; + + case 4: + break; + + default: + goto error; + } + else if (fixup.reloc == BFD_RELOC_UNUSED) + switch (size) + { + case 1: + fixup.reloc = BFD_RELOC_8; + break; + + case 2: + fixup.reloc = BFD_RELOC_16; + break; + + case 3: + fixup.reloc = BFD_RELOC_24; + break; + + case 4: + fixup.reloc = BFD_RELOC_32; + break; + + default: + goto error; + } + else if (size != 4) + { + error: + as_bad (_("unsupported BFD relocation size %u"), size); + fixup.reloc = BFD_RELOC_UNUSED; + } + + fix_new_exp (frag, off, size, &fixup.exp, 0, fixup.reloc); +} + void md_assemble (str) char *str; @@ -1748,6 +1882,8 @@ md_assemble (str) fixups[fc].exp = ex; fixups[fc].opindex = *opindex_ptr; fixups[fc].reloc = BFD_RELOC_UNUSED; + if (mn10300_check_fixup (& fixups[fc])) + goto error; ++fc; break; } @@ -2042,7 +2178,11 @@ keep_going: const struct mn10300_operand *operand; operand = &mn10300_operands[fixups[i].opindex]; - if (fixups[i].reloc != BFD_RELOC_UNUSED) + if (fixups[i].reloc != BFD_RELOC_UNUSED + && fixups[i].reloc != BFD_RELOC_32_GOT_PCREL + && fixups[i].reloc != BFD_RELOC_32_GOTOFF + && fixups[i].reloc != BFD_RELOC_32_PLT_PCREL + && fixups[i].reloc != BFD_RELOC_MN10300_GOT32) { reloc_howto_type *reloc_howto; int size; @@ -2072,6 +2212,8 @@ keep_going: fixS *fixP; reloc = BFD_RELOC_NONE; + if (fixups[i].reloc != BFD_RELOC_UNUSED) + reloc = fixups[i].reloc; /* How big is the reloc? Remember SPLIT relocs are implicitly 32bits. */ if ((operand->flags & MN10300_OPERAND_SPLIT) != 0) @@ -2083,11 +2225,15 @@ keep_going: /* Is the reloc pc-relative? */ pcrel = (operand->flags & MN10300_OPERAND_PCREL) != 0; + if (reloc != BFD_RELOC_NONE) + pcrel = bfd_reloc_type_lookup (stdoutput, reloc)->pc_relative; offset = size - (reloc_size + operand->shift) / 8; /* Choose a proper BFD relocation type. */ - if (pcrel) + if (reloc != BFD_RELOC_NONE) + ; + else if (pcrel) { if (reloc_size == 32) reloc = BFD_RELOC_32_PCREL; @@ -2153,6 +2299,13 @@ tc_gen_reloc (seg, fixp) } reloc->address = fixp->fx_frag->fr_address + fixp->fx_where; + if (fixp->fx_subsy + && S_GET_SEGMENT (fixp->fx_subsy) == absolute_section) + { + fixp->fx_offset -= S_GET_VALUE (fixp->fx_subsy); + fixp->fx_subsy = 0; + } + if (fixp->fx_addsy && fixp->fx_subsy) { reloc->sym_ptr_ptr = NULL; @@ -2368,6 +2521,9 @@ bfd_boolean mn10300_fix_adjustable (fixp) struct fix *fixp; { + if (! TC_RELOC_RTSYM_LOC_FIXUP (fixp)) + return 0; + if (fixp->fx_r_type == BFD_RELOC_VTABLE_INHERIT || fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY) return 0; @@ -2560,3 +2716,87 @@ set_arch_mach (mach) current_machine = mach; } + +static inline char * mn10300_end_of_match PARAMS ((char *, char *)); + +static inline char * +mn10300_end_of_match (cont, what) + char *cont, *what; +{ + int len = strlen (what); + + if (strncmp (cont, what, strlen (what)) == 0 + && ! is_part_of_name (cont[len])) + return cont + len; + + return NULL; +} + +int +mn10300_parse_name (name, exprP, nextcharP) + char const *name; + expressionS *exprP; + char *nextcharP; +{ + char *next = input_line_pointer; + char *next_end; + int reloc_type; + segT segment; + + exprP->X_op_symbol = NULL; + + if (strcmp (name, GLOBAL_OFFSET_TABLE_NAME) == 0) + { + if (! GOT_symbol) + GOT_symbol = symbol_find_or_make (name); + + exprP->X_add_symbol = GOT_symbol; + no_suffix: + /* If we have an absolute symbol or a reg, + then we know its value now. */ + segment = S_GET_SEGMENT (exprP->X_add_symbol); + if (segment == absolute_section) + { + exprP->X_op = O_constant; + exprP->X_add_number = S_GET_VALUE (exprP->X_add_symbol); + exprP->X_add_symbol = NULL; + } + else if (segment == reg_section) + { + exprP->X_op = O_register; + exprP->X_add_number = S_GET_VALUE (exprP->X_add_symbol); + exprP->X_add_symbol = NULL; + } + else + { + exprP->X_op = O_symbol; + exprP->X_add_number = 0; + } + + return 1; + } + + exprP->X_add_symbol = symbol_find_or_make (name); + + if (*nextcharP != '@') + goto no_suffix; + else if ((next_end = mn10300_end_of_match (next + 1, "GOTOFF"))) + reloc_type = BFD_RELOC_32_GOTOFF; + else if ((next_end = mn10300_end_of_match (next + 1, "GOT"))) + reloc_type = BFD_RELOC_MN10300_GOT32; + else if ((next_end = mn10300_end_of_match (next + 1, "PLT"))) + reloc_type = BFD_RELOC_32_PLT_PCREL; + else + goto no_suffix; + + *input_line_pointer = *nextcharP; + input_line_pointer = next_end; + *nextcharP = *input_line_pointer; + *input_line_pointer = '\0'; + + exprP->X_op = O_PIC_reloc; + exprP->X_add_number = 0; + exprP->X_md = reloc_type; + + return 1; +} diff --git a/gas/config/tc-mn10300.h b/gas/config/tc-mn10300.h index 736f93b299..955165236d 100644 --- a/gas/config/tc-mn10300.h +++ b/gas/config/tc-mn10300.h @@ -27,6 +27,31 @@ #error MN10300 support requires BFD_ASSEMBLER #endif +#define DIFF_EXPR_OK +#define GLOBAL_OFFSET_TABLE_NAME "_GLOBAL_OFFSET_TABLE_" + +#define TC_RELOC_RTSYM_LOC_FIXUP(FIX) \ + ((FIX)->fx_r_type != BFD_RELOC_32_PLT_PCREL \ + && (FIX)->fx_r_type != BFD_RELOC_MN10300_GOT32 \ + && (FIX)->fx_r_type != BFD_RELOC_32_GOT_PCREL \ + && ((FIX)->fx_addsy == NULL \ + || (! S_IS_EXTERNAL ((FIX)->fx_addsy) \ + && ! S_IS_WEAK ((FIX)->fx_addsy) \ + && S_IS_DEFINED ((FIX)->fx_addsy) \ + && ! S_IS_COMMON ((FIX)->fx_addsy)))) + +#define md_parse_name(name, exprP, nextcharP) \ + mn10300_parse_name ((name), (exprP), (nextcharP)) +int mn10300_parse_name PARAMS ((char const *, expressionS *, char *)); + +#define TC_CONS_FIX_NEW(FRAG, OFF, LEN, EXP) \ + mn10300_cons_fix_new ((FRAG), (OFF), (LEN), (EXP)) +void mn10300_cons_fix_new PARAMS ((fragS *, int, int, expressionS *)); + +/* This is used to construct expressions out of @GOTOFF, @PLT and @GOT + symbols. The relocation type is stored in X_md. */ +#define O_PIC_reloc O_md1 + /* The target BFD architecture. */ #define TARGET_ARCH bfd_arch_mn10300 -- 2.11.0