X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gas%2Fconfig%2Ftc-m32r.c;h=207ac0194335843729c1c9db5ccbade3295bf098;hb=097f809a197dcb5f2c1b878c0604be5c185c4db8;hp=90fb28d67d755dc7f48837874a7afd14f438bad3;hpb=b145f546d404da31c1ae51e7462ee8ec75e61929;p=deliverable%2Fbinutils-gdb.git diff --git a/gas/config/tc-m32r.c b/gas/config/tc-m32r.c index 90fb28d67d..207ac01943 100644 --- a/gas/config/tc-m32r.c +++ b/gas/config/tc-m32r.c @@ -1,5 +1,5 @@ /* tc-m32r.c -- Assembler for the Renesas M32R. - Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 + Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. This file is part of GAS, the GNU Assembler. @@ -70,6 +70,9 @@ static m32r_insn prev_insn; alignment request. */ static int seen_relaxable_p = 0; +/* Non-zero if we are generating PIC code. */ +int pic_code; + /* Non-zero if -relax specified, in which case sufficient relocs are output for the linker to do relaxing. We do simple forms of relaxing internally, but they are always done. @@ -106,7 +109,7 @@ static int enable_special = 0; /* Non-zero if -bitinst has been specified, in which case support for extended M32R bit-field instruction set should be enabled. */ -static int enable_special_m32r = 0; +static int enable_special_m32r = 1; /* Non-zero if -float has been specified, in which case support for extended M32R floating point instruction set should be enabled. */ @@ -194,7 +197,7 @@ allow_m32rx (int on) gas_cgen_cpu_desc->machs = mach_table[on].mach_flags; } -#define M32R_SHORTOPTS "O" +#define M32R_SHORTOPTS "O::K:" const char *md_shortopts = M32R_SHORTOPTS; @@ -213,7 +216,8 @@ struct option md_longopts[] = #define OPTION_NO_IGNORE_PARALLEL (OPTION_IGNORE_PARALLEL + 1) #define OPTION_SPECIAL (OPTION_NO_IGNORE_PARALLEL + 1) #define OPTION_SPECIAL_M32R (OPTION_SPECIAL + 1) -#define OPTION_SPECIAL_FLOAT (OPTION_SPECIAL_M32R + 1) +#define OPTION_NO_SPECIAL_M32R (OPTION_SPECIAL_M32R + 1) +#define OPTION_SPECIAL_FLOAT (OPTION_NO_SPECIAL_M32R + 1) #define OPTION_WARN_UNMATCHED (OPTION_SPECIAL_FLOAT + 1) #define OPTION_NO_WARN_UNMATCHED (OPTION_WARN_UNMATCHED + 1) {"m32r", no_argument, NULL, OPTION_M32R}, @@ -235,6 +239,7 @@ struct option md_longopts[] = {"nIp", no_argument, NULL, OPTION_NO_IGNORE_PARALLEL}, {"hidden", no_argument, NULL, OPTION_SPECIAL}, {"bitinst", no_argument, NULL, OPTION_SPECIAL_M32R}, + {"no-bitinst", no_argument, NULL, OPTION_NO_SPECIAL_M32R}, {"float", no_argument, NULL, OPTION_SPECIAL_FLOAT}, /* Sigh. I guess all warnings must now have both variants. */ {"warn-unmatched-high", no_argument, NULL, OPTION_WARN_UNMATCHED}, @@ -350,6 +355,10 @@ md_parse_option (c, arg) enable_special_m32r = 1; break; + case OPTION_NO_SPECIAL_M32R: + enable_special_m32r = 0; + break; + case OPTION_SPECIAL_FLOAT: enable_special_float = 1; break; @@ -362,6 +371,13 @@ md_parse_option (c, arg) warn_unmatched_high = 0; break; + case 'K': + if (strcmp (arg, "PIC") != 0) + as_warn (_("Unrecognized option following -K")); + else + pic_code = 1; + break; + #if 0 /* Not supported yet. */ case OPTION_RELAX: @@ -400,6 +416,8 @@ md_show_usage (stream) fprintf (stream, _("\ -no-parallel disable -parallel\n")); fprintf (stream, _("\ + -no-bitinst disallow the M32R2's extended bit-field instructions\n")); + fprintf (stream, _("\ -O try to optimize code. Implies -parallel\n")); fprintf (stream, _("\ @@ -436,6 +454,9 @@ md_show_usage (stream) fprintf (stream, _("\ -Wnuh synonym for -no-warn-unmatched-high\n")); + fprintf (stream, _("\ + -KPIC generate PIC\n")); + #if 0 fprintf (stream, _("\ -relax create linker relaxable code\n")); @@ -468,6 +489,69 @@ const pseudo_typeS md_pseudo_table[] = { NULL, NULL, 0 } }; +#define GOT_NAME "_GLOBAL_OFFSET_TABLE_" +symbolS * GOT_symbol; + +static inline int +m32r_PIC_related_p (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 + || exp->X_md == BFD_RELOC_M32R_26_PLTREL + || m32r_PIC_related_p (exp->X_add_symbol) + || m32r_PIC_related_p (exp->X_op_symbol)); +} + +static inline int +m32r_check_fixup (expressionS *main_exp, bfd_reloc_code_real_type *r_type_p) +{ + expressionS *exp = main_exp; + + if (exp->X_op == O_add && m32r_PIC_related_p (exp->X_op_symbol)) + return 1; + + if (exp->X_op == O_symbol && exp->X_add_symbol) + { + if (exp->X_add_symbol == GOT_symbol) + { + *r_type_p = BFD_RELOC_M32R_GOTPC24; + return 0; + } + } + else if (exp->X_op == O_add) + { + exp = symbol_get_value_expression (exp->X_add_symbol); + if (! exp) + return 0; + } + + if (exp->X_op == O_PIC_reloc || exp->X_md != BFD_RELOC_UNUSED) + { + *r_type_p = exp->X_md; + if (exp == main_exp) + exp->X_op = O_symbol; + else + { + main_exp->X_add_symbol = exp->X_add_symbol; + main_exp->X_add_number += exp->X_add_number; + } + } + else + return (m32r_PIC_related_p (exp->X_add_symbol) + || m32r_PIC_related_p (exp->X_op_symbol)); + + return 0; +} + /* FIXME: Should be machine generated. */ #define NOP_INSN 0x7000 #define PAR_NOP_INSN 0xf000 /* Can only be used in 2nd slot. */ @@ -558,7 +642,9 @@ debug_sym (ignore) } symbol_table_insert (symbolP); - if (S_IS_DEFINED (symbolP) && S_GET_SEGMENT (symbolP) != reg_section) + if (S_IS_DEFINED (symbolP) && (S_GET_SEGMENT (symbolP) != reg_section + || S_IS_EXTERNAL (symbolP) + || S_IS_WEAK (symbolP))) /* xgettext:c-format */ as_bad (_("symbol `%s' already defined"), S_GET_NAME (symbolP)); @@ -1359,6 +1445,14 @@ md_assemble (str) prev_insn.insn is NULL when we're on a 32 bit boundary. */ on_32bit_boundary_p = prev_insn.insn == NULL; + /* Change a frag to, if each insn to swap is in a different frag. + It must keep only one instruction in a frag. */ + if (parallel() && on_32bit_boundary_p) + { + frag_wane (frag_now); + frag_new (0); + } + /* Look to see if this instruction can be combined with the previous instruction to make one, parallel, 32 bit instruction. If the previous instruction (potentially) changed the flow of @@ -1419,13 +1513,25 @@ md_assemble (str) else if (insn.frag->fr_opcode == insn.addr) insn.frag->fr_opcode = prev_insn.addr; - /* Update the addresses in any fixups. - Note that we don't have to handle the case where each insn is in - a different frag as we ensure they're in the same frag above. */ - for (i = 0; i < prev_insn.num_fixups; ++i) - prev_insn.fixups[i]->fx_where += 2; - for (i = 0; i < insn.num_fixups; ++i) - insn.fixups[i]->fx_where -= 2; + /* Change a frag to, if each insn is in a different frag. + It must keep only one instruction in a frag. */ + if (prev_insn.frag != insn.frag) + { + for (i = 0; i < prev_insn.num_fixups; ++i) + prev_insn.fixups[i]->fx_frag = insn.frag; + for (i = 0; i < insn.num_fixups; ++i) + insn.fixups[i]->fx_frag = prev_insn.frag; + } + else + { + /* Update the addresses in any fixups. + Note that we don't have to handle the case where each insn is in + a different frag as we ensure they're in the same frag above. */ + for (i = 0; i < prev_insn.num_fixups; ++i) + prev_insn.fixups[i]->fx_where += 2; + for (i = 0; i < insn.num_fixups; ++i) + insn.fixups[i]->fx_where -= 2; + } } /* Keep track of whether we've seen a pair of 16 bit insns. @@ -1710,7 +1816,9 @@ md_estimate_size_before_relax (fragP, segment) However, we can't finish the fragment here and emit the reloc as insn alignment requirements may move the insn about. */ - if (S_GET_SEGMENT (fragP->fr_symbol) != segment) + if (S_GET_SEGMENT (fragP->fr_symbol) != segment + || S_IS_EXTERNAL (fragP->fr_symbol) + || S_IS_WEAK (fragP->fr_symbol)) { #if 0 int old_fr_fix = fragP->fr_fix; @@ -1816,12 +1924,18 @@ md_convert_frag (abfd, sec, fragP) abort (); } - if (S_GET_SEGMENT (fragP->fr_symbol) != sec) + if (S_GET_SEGMENT (fragP->fr_symbol) != sec + || S_IS_EXTERNAL (fragP->fr_symbol) + || S_IS_WEAK (fragP->fr_symbol)) { /* Symbol must be resolved by linker. */ if (fragP->fr_offset & 3) as_warn (_("Addend to unresolved symbol not on word boundary.")); - addend = fragP->fr_offset >> 2; +#ifdef USE_M32R_OLD_RELOC + addend = fragP->fr_offset >> 2; /* Old M32R used USE_REL. */ +#else + addend = 0; +#endif } else { @@ -1833,25 +1947,32 @@ md_convert_frag (abfd, sec, fragP) /* Create a relocation for symbols that must be resolved by the linker. Otherwise output the completed insn. */ - if (S_GET_SEGMENT (fragP->fr_symbol) != sec) + if (S_GET_SEGMENT (fragP->fr_symbol) != sec + || S_IS_EXTERNAL (fragP->fr_symbol) + || S_IS_WEAK (fragP->fr_symbol)) { + fixS *fixP; + assert (fragP->fr_subtype != 1); assert (fragP->fr_cgen.insn != 0); - gas_cgen_record_fixup (fragP, - /* Offset of branch insn in frag. */ - fragP->fr_fix + extension - 4, - fragP->fr_cgen.insn, - 4 /* Length. */, - /* FIXME: quick hack. */ + + fixP = gas_cgen_record_fixup (fragP, + /* Offset of branch insn in frag. */ + fragP->fr_fix + extension - 4, + fragP->fr_cgen.insn, + 4 /* Length. */, + /* FIXME: quick hack. */ #if 0 - cgen_operand_lookup_by_num (gas_cgen_cpu_desc, - fragP->fr_cgen.opindex), + cgen_operand_lookup_by_num (gas_cgen_cpu_desc, + fragP->fr_cgen.opindex), #else - cgen_operand_lookup_by_num (gas_cgen_cpu_desc, - M32R_OPERAND_DISP24), + cgen_operand_lookup_by_num (gas_cgen_cpu_desc, + M32R_OPERAND_DISP24), #endif - fragP->fr_cgen.opinfo, - fragP->fr_symbol, fragP->fr_offset); + fragP->fr_cgen.opinfo, + fragP->fr_symbol, fragP->fr_offset); + if (fragP->fr_cgen.opinfo) + fixP->fx_r_type = fragP->fr_cgen.opinfo; } #define SIZE_FROM_RELAX_STATE(n) ((n) == 1 ? 1 : 3) @@ -1874,7 +1995,9 @@ md_pcrel_from_section (fixP, sec) { if (fixP->fx_addsy != (symbolS *) NULL && (! S_IS_DEFINED (fixP->fx_addsy) - || S_GET_SEGMENT (fixP->fx_addsy) != sec)) + || S_GET_SEGMENT (fixP->fx_addsy) != sec + || S_IS_EXTERNAL (fixP->fx_addsy) + || S_IS_WEAK (fixP->fx_addsy))) { /* The symbol is undefined (or is defined but not in this section). Let the linker figure it out. */ @@ -1951,8 +2074,14 @@ m32r_cgen_record_fixup_exp (frag, where, insn, length, operand, opinfo, exp) int opinfo; expressionS *exp; { - fixS *fixP = gas_cgen_record_fixup_exp (frag, where, insn, length, - operand, opinfo, exp); + fixS *fixP; + bfd_reloc_code_real_type r_type = BFD_RELOC_UNUSED; + + if (m32r_check_fixup (exp, &r_type)) + as_bad (_("Invalid PIC expression.")); + + fixP = gas_cgen_record_fixup_exp (frag, where, insn, length, + operand, opinfo, exp); switch (operand->type) { @@ -1962,11 +2091,49 @@ m32r_cgen_record_fixup_exp (frag, where, insn, length, operand, opinfo, exp) || fixP->fx_cgen.opinfo == BFD_RELOC_M32R_HI16_ULO) m32r_record_hi16 (fixP->fx_cgen.opinfo, fixP, now_seg); break; + default: - /* Avoid -Wall warning */ + /* Avoid -Wall warning. */ break; } + switch (r_type) + { + case BFD_RELOC_UNUSED: + default: + return fixP; + + case BFD_RELOC_M32R_GOTPC24: + if (fixP->fx_cgen.opinfo == BFD_RELOC_M32R_HI16_SLO) + r_type = BFD_RELOC_M32R_GOTPC_HI_SLO; + else if (fixP->fx_cgen.opinfo == BFD_RELOC_M32R_HI16_ULO) + r_type = BFD_RELOC_M32R_GOTPC_HI_ULO; + else if (fixP->fx_cgen.opinfo == BFD_RELOC_M32R_LO16) + r_type = BFD_RELOC_M32R_GOTPC_LO; + break; + case BFD_RELOC_M32R_GOT24: + if (fixP->fx_cgen.opinfo == BFD_RELOC_M32R_HI16_SLO) + r_type = BFD_RELOC_M32R_GOT16_HI_SLO; + else if (fixP->fx_cgen.opinfo == BFD_RELOC_M32R_HI16_ULO) + r_type = BFD_RELOC_M32R_GOT16_HI_ULO; + else if (fixP->fx_cgen.opinfo == BFD_RELOC_M32R_LO16) + r_type = BFD_RELOC_M32R_GOT16_LO; + break; + case BFD_RELOC_M32R_GOTOFF: + if (fixP->fx_cgen.opinfo == BFD_RELOC_M32R_HI16_SLO) + r_type = BFD_RELOC_M32R_GOTOFF_HI_SLO; + else if (fixP->fx_cgen.opinfo == BFD_RELOC_M32R_HI16_ULO) + r_type = BFD_RELOC_M32R_GOTOFF_HI_ULO; + else if (fixP->fx_cgen.opinfo == BFD_RELOC_M32R_LO16) + r_type = BFD_RELOC_M32R_GOTOFF_LO; + break; + case BFD_RELOC_M32R_26_PLTREL: + as_bad (_("Invalid PIC expression.")); + break; + } + + fixP->fx_r_type = r_type; + return fixP; } @@ -2189,6 +2356,33 @@ m32r_fix_adjustable (fixP) else reloc_type = fixP->fx_r_type; + if (fixP->fx_addsy == NULL) + return 1; + + /* Prevent all adjustments to global symbols. */ + if (S_IS_EXTERN (fixP->fx_addsy)) + return 0; + if (S_IS_WEAK (fixP->fx_addsy)) + return 0; + + if (pic_code + && (reloc_type == BFD_RELOC_M32R_24 + || reloc_type == BFD_RELOC_M32R_26_PCREL + || reloc_type == BFD_RELOC_M32R_HI16_SLO + || reloc_type == BFD_RELOC_M32R_HI16_ULO + || reloc_type == BFD_RELOC_M32R_LO16)) + return 0; + + if (reloc_type == BFD_RELOC_M32R_GOT24 + || reloc_type == BFD_RELOC_M32R_26_PLTREL + || reloc_type == BFD_RELOC_M32R_GOTPC_HI_SLO + || reloc_type == BFD_RELOC_M32R_GOTPC_HI_ULO + || reloc_type == BFD_RELOC_M32R_GOTPC_LO + || reloc_type == BFD_RELOC_M32R_GOT16_HI_SLO + || reloc_type == BFD_RELOC_M32R_GOT16_HI_ULO + || reloc_type == BFD_RELOC_M32R_GOT16_LO) + return 0; + /* We need the symbol name for the VTABLE entries. */ if (reloc_type == BFD_RELOC_VTABLE_INHERIT || reloc_type == BFD_RELOC_VTABLE_ENTRY) @@ -2198,9 +2392,207 @@ m32r_fix_adjustable (fixP) } void -m32r_elf_final_processing () +m32r_elf_final_processing (void) { if (use_parallel) m32r_flags |= E_M32R_HAS_PARALLEL; elf_elfheader (stdoutput)->e_flags |= m32r_flags; } + +/* Translate internal representation of relocation info to BFD target + format. */ + +arelent * +tc_gen_reloc (section, fixP) + asection * section; + fixS * fixP; +{ + arelent * reloc; + bfd_reloc_code_real_type code; + + reloc = (arelent *) xmalloc (sizeof (arelent)); + + reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *)); + *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixP->fx_addsy); + reloc->address = fixP->fx_frag->fr_address + fixP->fx_where; + + code = fixP->fx_r_type; + if (pic_code) + { +#ifdef DEBUG_PIC +printf("%s",bfd_get_reloc_code_name(code)); +#endif + switch (code) + { + case BFD_RELOC_M32R_26_PCREL: + code = BFD_RELOC_M32R_26_PLTREL; + break; + case BFD_RELOC_M32R_24: + if (fixP->fx_addsy != NULL + && strcmp (S_GET_NAME (fixP->fx_addsy), GOT_NAME) == 0) + code = BFD_RELOC_M32R_GOTPC24; + else + code = BFD_RELOC_M32R_GOT24; + break; + case BFD_RELOC_M32R_HI16_ULO: + if (fixP->fx_addsy != NULL + && strcmp (S_GET_NAME (fixP->fx_addsy), GOT_NAME) == 0) + code = BFD_RELOC_M32R_GOTPC_HI_ULO; + else + code = BFD_RELOC_M32R_GOT16_HI_ULO; + break; + case BFD_RELOC_M32R_HI16_SLO: + if (fixP->fx_addsy != NULL + && strcmp (S_GET_NAME (fixP->fx_addsy), GOT_NAME) == 0) + code = BFD_RELOC_M32R_GOTPC_HI_SLO; + else + code = BFD_RELOC_M32R_GOT16_HI_SLO; + break; + case BFD_RELOC_M32R_LO16: + if (fixP->fx_addsy != NULL + && strcmp (S_GET_NAME (fixP->fx_addsy), GOT_NAME) == 0) + code = BFD_RELOC_M32R_GOTPC_LO; + else + code = BFD_RELOC_M32R_GOT16_LO; + break; + default: + break; + } +#ifdef DEBUG_PIC +printf(" => %s",bfd_get_reloc_code_name(code)); +#endif + } + + reloc->howto = bfd_reloc_type_lookup (stdoutput, code); +#ifdef DEBUG_PIC +printf(" => %s\n",reloc->howto->name); +#endif + if (reloc->howto == (reloc_howto_type *) NULL) + { + as_bad_where (fixP->fx_file, fixP->fx_line, + _("internal error: can't export reloc type %d (`%s')"), + fixP->fx_r_type, bfd_get_reloc_code_name (code)); + return NULL; + } + + /* Use fx_offset for these cases. */ + if ( fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY + || fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT) + reloc->addend = fixP->fx_offset; + else if ((!pic_code + && code != BFD_RELOC_M32R_26_PLTREL) + && fixP->fx_pcrel + && fixP->fx_addsy != NULL + && (S_GET_SEGMENT(fixP->fx_addsy) != section) + && S_IS_DEFINED (fixP->fx_addsy) + && ! S_IS_EXTERNAL(fixP->fx_addsy) + && ! S_IS_WEAK(fixP->fx_addsy)) + /* Already used fx_offset in the opcode field itseld. */ + reloc->addend = 0; + else + reloc->addend = fixP->fx_addnumber; + + return reloc; +} + +inline static char * +m32r_end_of_match (char *cont, char *what) +{ + int len = strlen (what); + + if (strncasecmp (cont, what, strlen (what)) == 0 + && ! is_part_of_name (cont[len])) + return cont + len; + + return NULL; +} + +int +m32r_parse_name (char const *name, expressionS *exprP, char *nextcharP) +{ + char *next = input_line_pointer; + char *next_end; + int reloc_type; + operatorT op_type; + segT segment; + + exprP->X_op_symbol = NULL; + exprP->X_md = BFD_RELOC_UNUSED; + + if (strcmp (name, GOT_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 = m32r_end_of_match (next + 1, "GOTOFF"))) + { + reloc_type = BFD_RELOC_M32R_GOTOFF; + op_type = O_PIC_reloc; + } + else if ((next_end = m32r_end_of_match (next + 1, "GOT"))) + { + reloc_type = BFD_RELOC_M32R_GOT24; + op_type = O_PIC_reloc; + } + else if ((next_end = m32r_end_of_match (next + 1, "PLT"))) + { + reloc_type = BFD_RELOC_M32R_26_PLTREL; + op_type = O_PIC_reloc; + } + else + goto no_suffix; + + *input_line_pointer = *nextcharP; + input_line_pointer = next_end; + *nextcharP = *input_line_pointer; + *input_line_pointer = '\0'; + + exprP->X_op = op_type; + exprP->X_add_number = 0; + exprP->X_md = reloc_type; + + return 1; +} + +int +m32r_cgen_parse_fix_exp(int opinfo, expressionS *exp) +{ + if (exp->X_op == O_PIC_reloc + && exp->X_md == BFD_RELOC_M32R_26_PLTREL) + { + exp->X_op = O_symbol; + opinfo = exp->X_md; + } + + return opinfo; +}