X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gas%2Fconfig%2Ftc-sh.c;h=acf62aef21d643947ecf64ef2cf22934a130a23f;hb=7f3dfb9cf74da197cfe71fb0490a90613269ca0f;hp=f33925bb5e402b8acb98cb9da0eef9c185314073;hpb=871ec8960924f477379d520fd477c1958cad4e33;p=deliverable%2Fbinutils-gdb.git diff --git a/gas/config/tc-sh.c b/gas/config/tc-sh.c index f33925bb5e..acf62aef21 100644 --- a/gas/config/tc-sh.c +++ b/gas/config/tc-sh.c @@ -1,6 +1,6 @@ /* tc-sh.c -- Assemble code for the Renesas / SuperH SH Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, - 2003, 2004 Free Software Foundation, Inc. + 2003, 2004, 2005 Free Software Foundation, Inc. This file is part of GAS, the GNU Assembler. @@ -16,8 +16,8 @@ You should have received a copy of the GNU General Public License along with GAS; see the file COPYING. If not, write to - the Free Software Foundation, 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ + the Free Software Foundation, 51 Franklin Street - Fifth Floor, + Boston, MA 02110-1301, USA. */ /* Written By Steve Chamberlain */ @@ -124,8 +124,6 @@ const pseudo_typeS md_pseudo_table[] = {0, 0, 0} }; -/*int md_reloc_size; */ - int sh_relax; /* set if -relax seen */ /* Whether -small was seen. */ @@ -136,7 +134,11 @@ int sh_small; static int dont_adjust_reloc_32; -/* preset architecture set, if given; zero otherwise. */ +/* Flag to indicate that '$' is allowed as a register prefix. */ + +static int allow_dollar_register_prefix; + +/* Preset architecture set, if given; zero otherwise. */ static unsigned int preset_target_arch; @@ -839,7 +841,7 @@ md_begin (void) unsigned int target_arch; target_arch - = preset_target_arch ? preset_target_arch : arch_sh1_up & ~arch_sh_has_dsp; + = preset_target_arch ? preset_target_arch : arch_sh_up & ~arch_sh_has_dsp; valid_arch = target_arch; #ifdef HAVE_SH64 @@ -871,8 +873,8 @@ static int reg_b; /* Try to parse a reg name. Return the number of chars consumed. */ -static int -parse_reg (char *src, int *mode, int *reg) +static unsigned int +parse_reg_without_prefix (char *src, int *mode, int *reg) { char l0 = TOLOWER (src[0]); char l1 = l0 ? TOLOWER (src[1]) : 0; @@ -1098,6 +1100,12 @@ parse_reg (char *src, int *mode, int *reg) return 3; } + if (l0 == 't' && l1 == 'b' && TOLOWER (src[2]) == 'r' + && ! IDENT_CHAR ((unsigned char) src[3])) + { + *mode = A_TBR; + return 3; + } if (l0 == 'm' && l1 == 'a' && TOLOWER (src[2]) == 'c' && ! IDENT_CHAR ((unsigned char) src[4])) { @@ -1221,6 +1229,36 @@ parse_reg (char *src, int *mode, int *reg) return 0; } +/* Like parse_reg_without_prefix, but this version supports + $-prefixed register names if enabled by the user. */ + +static unsigned int +parse_reg (char *src, int *mode, int *reg) +{ + unsigned int prefix; + unsigned int consumed; + + if (src[0] == '$') + { + if (allow_dollar_register_prefix) + { + src ++; + prefix = 1; + } + else + return 0; + } + else + prefix = 0; + + consumed = parse_reg_without_prefix (src, mode, reg); + + if (consumed == 0) + return 0; + + return consumed + prefix; +} + static char * parse_exp (char *s, sh_operand_info *op) { @@ -1268,7 +1306,15 @@ parse_at (char *src, sh_operand_info *op) int len; int mode; src++; - if (src[0] == '-') + if (src[0] == '@') + { + src = parse_at (src, op); + if (op->type == A_DISP_TBR) + op->type = A_DISP2_TBR; + else + as_bad (_("illegal double indirection")); + } + else if (src[0] == '-') { /* Must be predecrement. */ src++; @@ -1341,6 +1387,10 @@ parse_at (char *src, sh_operand_info *op) { op->type = A_DISP_GBR; } + else if (mode == A_TBR) + { + op->type = A_DISP_TBR; + } else if (mode == A_PC) { /* We want @(expr, pc) to uniformly address . + expr, @@ -1542,6 +1592,36 @@ get_specific (sh_opcode_info *opcode, sh_operand_info *operands) sh_operand_info *user = operands + n; sh_arg_type arg = this_try->arg[n]; + if (SH_MERGE_ARCH_SET_VALID (valid_arch, arch_sh2a_nofpu_up) + && ( arg == A_DISP_REG_M + || arg == A_DISP_REG_N)) + { + /* Check a few key IMM* fields for overflow. */ + int opf; + long val = user->immediate.X_add_number; + + for (opf = 0; opf < 4; opf ++) + switch (this_try->nibbles[opf]) + { + case IMM0_4: + case IMM1_4: + if (val < 0 || val > 15) + goto fail; + break; + case IMM0_4BY2: + case IMM1_4BY2: + if (val < 0 || val > 15 * 2) + goto fail; + break; + case IMM0_4BY4: + case IMM1_4BY4: + if (val < 0 || val > 15 * 4) + goto fail; + break; + default: + break; + } + } switch (arg) { case A_DISP_PC: @@ -1552,6 +1632,7 @@ get_specific (sh_opcode_info *opcode, sh_operand_info *operands) case A_BDISP12: case A_BDISP8: case A_DISP_GBR: + case A_DISP2_TBR: case A_MACH: case A_PR: case A_MACL: @@ -1596,6 +1677,7 @@ get_specific (sh_opcode_info *opcode, sh_operand_info *operands) reg_n = user->reg; break; case A_GBR: + case A_TBR: case A_SR: case A_VBR: case A_DSR: @@ -1616,6 +1698,22 @@ get_specific (sh_opcode_info *opcode, sh_operand_info *operands) reg_b = user->reg; break; + case A_INC_R15: + if (user->type != A_INC_N) + goto fail; + if (user->reg != 15) + goto fail; + reg_n = user->reg; + break; + + case A_DEC_R15: + if (user->type != A_DEC_N) + goto fail; + if (user->reg != 15) + goto fail; + reg_n = user->reg; + break; + case A_REG_M: case A_INC_M: case A_DEC_M: @@ -2040,6 +2138,16 @@ insert (char *where, int how, int pcrel, sh_operand_info *op) how); } +static void +insert4 (char * where, int how, int pcrel, sh_operand_info * op) +{ + fix_new_exp (frag_now, + where - frag_now->fr_literal, + 4, + & op->immediate, + pcrel, + how); +} static void build_relax (sh_opcode_info *opcode, sh_operand_info *op) { @@ -2126,16 +2234,31 @@ static unsigned int build_Mytes (sh_opcode_info *opcode, sh_operand_info *operand) { int index; - char nbuf[4]; - char *output = frag_more (2); + char nbuf[8]; + char *output; unsigned int size = 2; int low_byte = target_big_endian ? 1 : 0; + int max_index = 4; + nbuf[0] = 0; nbuf[1] = 0; nbuf[2] = 0; nbuf[3] = 0; + nbuf[4] = 0; + nbuf[5] = 0; + nbuf[6] = 0; + nbuf[7] = 0; - for (index = 0; index < 4; index++) + if (SH_MERGE_ARCH_SET (opcode->arch, arch_op32)) + { + output = frag_more (4); + size = 4; + max_index = 8; + } + else + output = frag_more (2); + + for (index = 0; index < max_index; index++) { sh_nibble_type i = opcode->nibbles[index]; if (i < 16) @@ -2167,6 +2290,48 @@ build_Mytes (sh_opcode_info *opcode, sh_operand_info *operand) case REG_N_B01: nbuf[index] = reg_n | 0x01; break; + case IMM0_3s: + nbuf[index] |= 0x08; + case IMM0_3c: + insert (output + low_byte, BFD_RELOC_SH_IMM3, 0, operand); + break; + case IMM0_3Us: + nbuf[index] |= 0x80; + case IMM0_3Uc: + insert (output + low_byte, BFD_RELOC_SH_IMM3U, 0, operand); + break; + case DISP0_12: + insert (output + 2, BFD_RELOC_SH_DISP12, 0, operand); + break; + case DISP0_12BY2: + insert (output + 2, BFD_RELOC_SH_DISP12BY2, 0, operand); + break; + case DISP0_12BY4: + insert (output + 2, BFD_RELOC_SH_DISP12BY4, 0, operand); + break; + case DISP0_12BY8: + insert (output + 2, BFD_RELOC_SH_DISP12BY8, 0, operand); + break; + case DISP1_12: + insert (output + 2, BFD_RELOC_SH_DISP12, 0, operand+1); + break; + case DISP1_12BY2: + insert (output + 2, BFD_RELOC_SH_DISP12BY2, 0, operand+1); + break; + case DISP1_12BY4: + insert (output + 2, BFD_RELOC_SH_DISP12BY4, 0, operand+1); + break; + case DISP1_12BY8: + insert (output + 2, BFD_RELOC_SH_DISP12BY8, 0, operand+1); + break; + case IMM0_20_4: + break; + case IMM0_20: + insert4 (output, BFD_RELOC_SH_DISP20, 0, operand); + break; + case IMM0_20BY8: + insert4 (output, BFD_RELOC_SH_DISP20BY8, 0, operand); + break; case IMM0_4BY4: insert (output + low_byte, BFD_RELOC_SH_IMM4BY4, 0, operand); break; @@ -2231,6 +2396,19 @@ build_Mytes (sh_opcode_info *opcode, sh_operand_info *operand) output[0] = (nbuf[0] << 4) | (nbuf[1]); output[1] = (nbuf[2] << 4) | (nbuf[3]); } + if (SH_MERGE_ARCH_SET (opcode->arch, arch_op32)) + { + if (!target_big_endian) + { + output[3] = (nbuf[4] << 4) | (nbuf[5]); + output[2] = (nbuf[6] << 4) | (nbuf[7]); + } + else + { + output[2] = (nbuf[4] << 4) | (nbuf[5]); + output[3] = (nbuf[6] << 4) | (nbuf[7]); + } + } return size; } @@ -2254,7 +2432,7 @@ find_cooked_opcode (char **str_p) The pre-processor will eliminate whitespace in front of any '@' after the first argument; we may be called from assemble_ppi, so the opcode might be terminated by an '@'. */ - for (op_start = op_end = (unsigned char *) (str); + for (op_start = op_end = (unsigned char *) str; *op_end && nlen < 20 && !is_end_of_line[*op_end] && *op_end != ' ' && *op_end != '@'; @@ -2273,7 +2451,7 @@ find_cooked_opcode (char **str_p) } name[nlen] = 0; - *str_p = op_end; + *str_p = (char *) op_end; if (nlen == 0) as_bad (_("can't find opcode ")); @@ -2588,7 +2766,7 @@ assemble_ppi (char *op_end, sh_opcode_info *opcode) void md_assemble (char *str) { - unsigned char *op_end; + char *op_end; sh_operand_info operand[3]; sh_opcode_info *opcode; unsigned int size = 0; @@ -2725,16 +2903,14 @@ md_assemble (char *str) } } -#ifdef BFD_ASSEMBLER dwarf2_emit_insn (size); -#endif } /* This routine is called each time a label definition is seen. It emits a BFD_RELOC_SH_LABEL reloc if necessary. */ void -sh_frob_label (void) +sh_frob_label (symbolS *sym) { static fragS *last_label_frag; static int last_label_offset; @@ -2753,6 +2929,8 @@ sh_frob_label (void) last_label_offset = offset; } } + + dwarf2_emit_label (sym); } /* This routine is called when the assembler is about to output some @@ -2776,24 +2954,6 @@ md_undefined_symbol (char *name ATTRIBUTE_UNUSED) return 0; } -#ifdef OBJ_COFF -#ifndef BFD_ASSEMBLER - -void -tc_crawl_symbol_chain (object_headers *headers ATTRIBUTE_UNUSED) -{ - printf (_("call to tc_crawl_symbol_chain \n")); -} - -void -tc_headers_hook (object_headers *headers ATTRIBUTE_UNUSED) -{ - printf (_("call to tc_headers_hook \n")); -} - -#endif -#endif - /* Various routines to kill one day. */ /* Equal to MAX_PRECISION in atof-ieee.c. */ #define MAX_LITTLENUMS 6 @@ -2879,31 +3039,39 @@ s_uses (int ignore ATTRIBUTE_UNUSED) demand_empty_rest_of_line (); } +enum options +{ + OPTION_RELAX = OPTION_MD_BASE, + OPTION_BIG, + OPTION_LITTLE, + OPTION_SMALL, + OPTION_DSP, + OPTION_ISA, + OPTION_RENESAS, + OPTION_ALLOW_REG_PREFIX, +#ifdef HAVE_SH64 + OPTION_ABI, + OPTION_NO_MIX, + OPTION_SHCOMPACT_CONST_CRANGE, + OPTION_NO_EXPAND, + OPTION_PT32, +#endif + OPTION_DUMMY /* Not used. This is just here to make it easy to add and subtract options from this enum. */ +}; + const char *md_shortopts = ""; struct option md_longopts[] = { -#define OPTION_RELAX (OPTION_MD_BASE) -#define OPTION_BIG (OPTION_MD_BASE + 1) -#define OPTION_LITTLE (OPTION_BIG + 1) -#define OPTION_SMALL (OPTION_LITTLE + 1) -#define OPTION_DSP (OPTION_SMALL + 1) -#define OPTION_ISA (OPTION_DSP + 1) -#define OPTION_RENESAS (OPTION_ISA + 1) - {"relax", no_argument, NULL, OPTION_RELAX}, {"big", no_argument, NULL, OPTION_BIG}, {"little", no_argument, NULL, OPTION_LITTLE}, {"small", no_argument, NULL, OPTION_SMALL}, {"dsp", no_argument, NULL, OPTION_DSP}, - {"isa", required_argument, NULL, OPTION_ISA}, + {"isa", required_argument, NULL, OPTION_ISA}, {"renesas", no_argument, NULL, OPTION_RENESAS}, + {"allow-reg-prefix", no_argument, NULL, OPTION_ALLOW_REG_PREFIX}, #ifdef HAVE_SH64 -#define OPTION_ABI (OPTION_RENESAS + 1) -#define OPTION_NO_MIX (OPTION_ABI + 1) -#define OPTION_SHCOMPACT_CONST_CRANGE (OPTION_NO_MIX + 1) -#define OPTION_NO_EXPAND (OPTION_SHCOMPACT_CONST_CRANGE + 1) -#define OPTION_PT32 (OPTION_NO_EXPAND + 1) {"abi", required_argument, NULL, OPTION_ABI}, {"no-mix", no_argument, NULL, OPTION_NO_MIX}, {"shcompact-const-crange", no_argument, NULL, OPTION_SHCOMPACT_CONST_CRANGE}, @@ -2937,20 +3105,24 @@ md_parse_option (int c, char *arg ATTRIBUTE_UNUSED) break; case OPTION_DSP: - preset_target_arch = arch_sh1_up & ~(arch_sh_sp_fpu|arch_sh_dp_fpu); + preset_target_arch = arch_sh_up & ~(arch_sh_sp_fpu|arch_sh_dp_fpu); break; case OPTION_RENESAS: dont_adjust_reloc_32 = 1; break; + case OPTION_ALLOW_REG_PREFIX: + allow_dollar_register_prefix = 1; + break; + case OPTION_ISA: if (strcasecmp (arg, "dsp") == 0) - preset_target_arch = arch_sh1_up & ~(arch_sh_sp_fpu|arch_sh_dp_fpu); + preset_target_arch = arch_sh_up & ~(arch_sh_sp_fpu|arch_sh_dp_fpu); else if (strcasecmp (arg, "fp") == 0) - preset_target_arch = arch_sh1_up & ~arch_sh_has_dsp; + preset_target_arch = arch_sh_up & ~arch_sh_has_dsp; else if (strcasecmp (arg, "any") == 0) - preset_target_arch = arch_sh1_up; + preset_target_arch = arch_sh_up; #ifdef HAVE_SH64 else if (strcasecmp (arg, "shmedia") == 0) { @@ -2971,6 +3143,7 @@ md_parse_option (int c, char *arg ATTRIBUTE_UNUSED) { extern const bfd_arch_info_type bfd_sh_arch; bfd_arch_info_type const *bfd_arch = &bfd_sh_arch; + preset_target_arch = 0; for (; bfd_arch; bfd_arch=bfd_arch->next) { @@ -3047,19 +3220,21 @@ md_show_usage (FILE *stream) { fprintf (stream, _("\ SH options:\n\ --little generate little endian code\n\ --big generate big endian code\n\ --relax alter jump instructions for long displacements\n\ --renesas disable optimization with section symbol for\n\ +--little generate little endian code\n\ +--big generate big endian code\n\ +--relax alter jump instructions for long displacements\n\ +--renesas disable optimization with section symbol for\n\ compatibility with Renesas assembler.\n\ --small align sections to 4 byte boundaries, not 16\n\ --dsp enable sh-dsp insns, and disable floating-point ISAs.\n\ --isa=[any use most appropriate isa\n\ +--small align sections to 4 byte boundaries, not 16\n\ +--dsp enable sh-dsp insns, and disable floating-point ISAs.\n\ +--allow-reg-prefix allow '$' as a register name prefix.\n\ +--isa=[any use most appropriate isa\n\ | dsp same as '-dsp'\n\ | fp")); { extern const bfd_arch_info_type bfd_sh_arch; bfd_arch_info_type const *bfd_arch = &bfd_sh_arch; + for (; bfd_arch; bfd_arch=bfd_arch->next) if (bfd_arch->mach != bfd_mach_sh5) { @@ -3070,19 +3245,19 @@ SH options:\n\ fprintf (stream, "]\n"); #ifdef HAVE_SH64 fprintf (stream, _("\ --isa=[shmedia set as the default instruction set for SH64\n\ +--isa=[shmedia set as the default instruction set for SH64\n\ | SHmedia\n\ | shcompact\n\ | SHcompact]\n")); fprintf (stream, _("\ --abi=[32|64] set size of expanded SHmedia operands and object\n\ +--abi=[32|64] set size of expanded SHmedia operands and object\n\ file type\n\ --shcompact-const-crange emit code-range descriptors for constants in\n\ +--shcompact-const-crange emit code-range descriptors for constants in\n\ SHcompact code sections\n\ --no-mix disallow SHmedia code in the same section as\n\ +--no-mix disallow SHmedia code in the same section as\n\ constants and SHcompact code\n\ --no-expand do not expand MOVI, PT, PTA or PTB instructions\n\ --expand-pt32 with -abi=64, expand PT, PTA and PTB instructions\n\ +--no-expand do not expand MOVI, PT, PTA or PTB instructions\n\ +--expand-pt32 with -abi=64, expand PT, PTA and PTB instructions\n\ to 32 bits only\n")); #endif /* HAVE_SH64 */ } @@ -3099,8 +3274,7 @@ struct sh_count_relocs }; /* Count the number of fixups in a section which refer to a particular - symbol. When using BFD_ASSEMBLER, this is called via - bfd_map_over_sections. */ + symbol. This is called via bfd_map_over_sections. */ static void sh_count_relocs (bfd *abfd ATTRIBUTE_UNUSED, segT sec, void *data) @@ -3125,8 +3299,8 @@ sh_count_relocs (bfd *abfd ATTRIBUTE_UNUSED, segT sec, void *data) } } -/* Handle the count relocs for a particular section. When using - BFD_ASSEMBLER, this is called via bfd_map_over_sections. */ +/* Handle the count relocs for a particular section. + This is called via bfd_map_over_sections. */ static void sh_frob_section (bfd *abfd ATTRIBUTE_UNUSED, segT sec, @@ -3156,9 +3330,6 @@ sh_frob_section (bfd *abfd ATTRIBUTE_UNUSED, segT sec, || fix->fx_subsy != NULL || fix->fx_addnumber != 0 || S_GET_SEGMENT (sym) != sec -#if ! defined (BFD_ASSEMBLER) && defined (OBJ_COFF) - || S_GET_STORAGE_CLASS (sym) == C_EXT -#endif || S_IS_EXTERNAL (sym)) { as_warn_where (fix->fx_file, fix->fx_line, @@ -3198,9 +3369,6 @@ sh_frob_section (bfd *abfd ATTRIBUTE_UNUSED, segT sec, || fscan->fx_subsy != NULL || fscan->fx_addnumber != 0 || S_GET_SEGMENT (sym) != sec -#if ! defined (BFD_ASSEMBLER) && defined (OBJ_COFF) - || S_GET_STORAGE_CLASS (sym) == C_EXT -#endif || S_IS_EXTERNAL (sym)) { as_warn_where (fix->fx_file, fix->fx_line, @@ -3212,16 +3380,7 @@ sh_frob_section (bfd *abfd ATTRIBUTE_UNUSED, segT sec, counting the number of times we find a reference to sym. */ info.sym = sym; info.count = 0; -#ifdef BFD_ASSEMBLER bfd_map_over_sections (stdoutput, sh_count_relocs, &info); -#else - { - int iscan; - - for (iscan = SEG_E0; iscan < SEG_UNKNOWN; iscan++) - sh_count_relocs ((bfd *) NULL, iscan, &info); - } -#endif if (info.count < 1) abort (); @@ -3256,28 +3415,14 @@ sh_frob_file (void) if (! sh_relax) return; -#ifdef BFD_ASSEMBLER bfd_map_over_sections (stdoutput, sh_frob_section, NULL); -#else - { - int iseg; - - for (iseg = SEG_E0; iseg < SEG_UNKNOWN; iseg++) - sh_frob_section ((bfd *) NULL, iseg, NULL); - } -#endif } /* Called after relaxing. Set the correct sizes of the fragments, and - create relocs so that md_apply_fix3 will fill in the correct values. */ + create relocs so that md_apply_fix will fill in the correct values. */ void -#ifdef BFD_ASSEMBLER md_convert_frag (bfd *headers ATTRIBUTE_UNUSED, segT seg, fragS *fragP) -#else -md_convert_frag (object_headers *headers ATTRIBUTE_UNUSED, segT seg, - fragS *fragP) -#endif { int donerelax = 0; @@ -3350,12 +3495,7 @@ md_convert_frag (object_headers *headers ATTRIBUTE_UNUSED, segT seg, /* Build a relocation to six / four bytes farther on. */ subseg_change (seg, 0); - fix_new (fragP, fragP->fr_fix, 2, -#ifdef BFD_ASSEMBLER - section_symbol (seg), -#else - seg_info (seg)->dot, -#endif + fix_new (fragP, fragP->fr_fix, 2, section_symbol (seg), fragP->fr_address + fragP->fr_fix + (delay ? 4 : 6), 1, BFD_RELOC_SH_PCDISP8BY2); @@ -3422,17 +3562,12 @@ md_convert_frag (object_headers *headers ATTRIBUTE_UNUSED, segT seg, valueT md_section_align (segT seg ATTRIBUTE_UNUSED, valueT size) { -#ifdef BFD_ASSEMBLER #ifdef OBJ_ELF return size; #else /* ! OBJ_ELF */ return ((size + (1 << bfd_get_section_alignment (stdoutput, seg)) - 1) & (-1 << bfd_get_section_alignment (stdoutput, seg))); #endif /* ! OBJ_ELF */ -#else /* ! BFD_ASSEMBLER */ - return ((size + (1 << section_alignment[(int) seg]) - 1) - & (-1 << section_alignment[(int) seg])); -#endif /* ! BFD_ASSEMBLER */ } /* This static variable is set by s_uacons to tell sh_cons_align that @@ -3629,6 +3764,14 @@ sh_elf_final_processing (void) if (sh64_isa_mode != sh64_isa_unspecified) val = EF_SH5; else +#elif defined TARGET_SYMBIAN + if (1) + { + extern int sh_symbian_find_elf_flags (unsigned int); + + val = sh_symbian_find_elf_flags (valid_arch); + } + else #endif /* HAVE_SH64 */ val = sh_find_elf_flags (valid_arch); @@ -3640,7 +3783,7 @@ sh_elf_final_processing (void) /* Apply a fixup to the object file. */ void -md_apply_fix3 (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED) +md_apply_fix (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED) { char *buf = fixP->fx_where + fixP->fx_frag->fr_literal; int lowbyte = target_big_endian ? 1 : 0; @@ -3649,7 +3792,6 @@ md_apply_fix3 (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED) long max, min; int shift; -#ifdef BFD_ASSEMBLER /* A difference between two symbols, the second of which is in the current section, is transformed in a PC-relative relocation to the other symbol. We have to adjust the relocation type here. */ @@ -3695,29 +3837,65 @@ md_apply_fix3 (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED) && fixP->fx_addsy != NULL && S_IS_WEAK (fixP->fx_addsy)) val -= S_GET_VALUE (fixP->fx_addsy); -#endif -#ifdef BFD_ASSEMBLER if (SWITCH_TABLE (fixP)) val -= S_GET_VALUE (fixP->fx_subsy); -#else - if (fixP->fx_r_type == 0) - { - if (fixP->fx_size == 2) - fixP->fx_r_type = BFD_RELOC_16; - else if (fixP->fx_size == 4) - fixP->fx_r_type = BFD_RELOC_32; - else if (fixP->fx_size == 1) - fixP->fx_r_type = BFD_RELOC_8; - else - abort (); - } -#endif max = min = 0; shift = 0; switch (fixP->fx_r_type) { + case BFD_RELOC_SH_IMM3: + max = 0x7; + * buf = (* buf & 0xf8) | (val & 0x7); + break; + case BFD_RELOC_SH_IMM3U: + max = 0x7; + * buf = (* buf & 0x8f) | ((val & 0x7) << 4); + break; + case BFD_RELOC_SH_DISP12: + max = 0xfff; + buf[lowbyte] = val & 0xff; + buf[highbyte] |= (val >> 8) & 0x0f; + break; + case BFD_RELOC_SH_DISP12BY2: + max = 0xfff; + shift = 1; + buf[lowbyte] = (val >> 1) & 0xff; + buf[highbyte] |= (val >> 9) & 0x0f; + break; + case BFD_RELOC_SH_DISP12BY4: + max = 0xfff; + shift = 2; + buf[lowbyte] = (val >> 2) & 0xff; + buf[highbyte] |= (val >> 10) & 0x0f; + break; + case BFD_RELOC_SH_DISP12BY8: + max = 0xfff; + shift = 3; + buf[lowbyte] = (val >> 3) & 0xff; + buf[highbyte] |= (val >> 11) & 0x0f; + break; + case BFD_RELOC_SH_DISP20: + if (! target_big_endian) + abort(); + max = 0x7ffff; + min = -0x80000; + buf[1] = (buf[1] & 0x0f) | ((val >> 12) & 0xf0); + buf[2] = (val >> 8) & 0xff; + buf[3] = val & 0xff; + break; + case BFD_RELOC_SH_DISP20BY8: + if (!target_big_endian) + abort(); + max = 0x7ffff; + min = -0x80000; + shift = 8; + buf[1] = (buf[1] & 0x0f) | ((val >> 20) & 0xf0); + buf[2] = (val >> 16) & 0xff; + buf[3] = (val >> 8) & 0xff; + break; + case BFD_RELOC_SH_IMM4: max = 0xf; *buf = (*buf & 0xf0) | (val & 0xf); @@ -3810,7 +3988,7 @@ md_apply_fix3 (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED) break; case BFD_RELOC_SH_USES: - /* Pass the value into sh_coff_reloc_mangle. */ + /* Pass the value into sh_reloc(). */ fixP->fx_addnumber = val; break; @@ -3885,7 +4063,7 @@ md_apply_fix3 (fixS *fixP, valueT *valP, segT seg ATTRIBUTE_UNUSED) default: #ifdef HAVE_SH64 - shmedia_md_apply_fix3 (fixP, valP); + shmedia_md_apply_fix (fixP, valP); return; #else abort (); @@ -4002,8 +4180,7 @@ md_number_to_chars (char *ptr, valueT use, int nbytes) number_to_chars_bigendian (ptr, use, nbytes); } -/* This version is used in obj-coff.c when not using BFD_ASSEMBLER. - eg for the sh-hms target. */ +/* This version is used in obj-coff.c eg. for the sh-hms target. */ long md_pcrel_from (fixS *fixP) @@ -4029,167 +4206,6 @@ md_pcrel_from_section (fixS *fixP, segT sec) return md_pcrel_from (fixP); } -#ifdef OBJ_COFF - -int -tc_coff_sizemachdep (fragS *frag) -{ - return md_relax_table[frag->fr_subtype].rlx_length; -} - -#endif /* OBJ_COFF */ - -#ifndef BFD_ASSEMBLER -#ifdef OBJ_COFF - -/* Map BFD relocs to SH COFF relocs. */ - -struct reloc_map -{ - bfd_reloc_code_real_type bfd_reloc; - int sh_reloc; -}; - -static const struct reloc_map coff_reloc_map[] = -{ - { BFD_RELOC_32, R_SH_IMM32 }, - { BFD_RELOC_16, R_SH_IMM16 }, - { BFD_RELOC_8, R_SH_IMM8 }, - { BFD_RELOC_SH_PCDISP8BY2, R_SH_PCDISP8BY2 }, - { BFD_RELOC_SH_PCDISP12BY2, R_SH_PCDISP }, - { BFD_RELOC_SH_IMM4, R_SH_IMM4 }, - { BFD_RELOC_SH_IMM4BY2, R_SH_IMM4BY2 }, - { BFD_RELOC_SH_IMM4BY4, R_SH_IMM4BY4 }, - { BFD_RELOC_SH_IMM8, R_SH_IMM8 }, - { BFD_RELOC_SH_IMM8BY2, R_SH_IMM8BY2 }, - { BFD_RELOC_SH_IMM8BY4, R_SH_IMM8BY4 }, - { BFD_RELOC_SH_PCRELIMM8BY2, R_SH_PCRELIMM8BY2 }, - { BFD_RELOC_SH_PCRELIMM8BY4, R_SH_PCRELIMM8BY4 }, - { BFD_RELOC_8_PCREL, R_SH_SWITCH8 }, - { BFD_RELOC_SH_SWITCH16, R_SH_SWITCH16 }, - { BFD_RELOC_SH_SWITCH32, R_SH_SWITCH32 }, - { BFD_RELOC_SH_USES, R_SH_USES }, - { BFD_RELOC_SH_COUNT, R_SH_COUNT }, - { BFD_RELOC_SH_ALIGN, R_SH_ALIGN }, - { BFD_RELOC_SH_CODE, R_SH_CODE }, - { BFD_RELOC_SH_DATA, R_SH_DATA }, - { BFD_RELOC_SH_LABEL, R_SH_LABEL }, - { BFD_RELOC_UNUSED, 0 } -}; - -/* Adjust a reloc for the SH. This is similar to the generic code, - but does some minor tweaking. */ - -void -sh_coff_reloc_mangle (segment_info_type *seg, fixS *fix, - struct internal_reloc *intr, unsigned int paddr) -{ - symbolS *symbol_ptr = fix->fx_addsy; - symbolS *dot; - - intr->r_vaddr = paddr + fix->fx_frag->fr_address + fix->fx_where; - - if (! SWITCH_TABLE (fix)) - { - const struct reloc_map *rm; - - for (rm = coff_reloc_map; rm->bfd_reloc != BFD_RELOC_UNUSED; rm++) - if (rm->bfd_reloc == (bfd_reloc_code_real_type) fix->fx_r_type) - break; - if (rm->bfd_reloc == BFD_RELOC_UNUSED) - as_bad_where (fix->fx_file, fix->fx_line, - _("Can not represent %s relocation in this object file format"), - bfd_get_reloc_code_name (fix->fx_r_type)); - intr->r_type = rm->sh_reloc; - intr->r_offset = 0; - } - else - { - know (sh_relax); - - if (fix->fx_r_type == BFD_RELOC_16) - intr->r_type = R_SH_SWITCH16; - else if (fix->fx_r_type == BFD_RELOC_8) - intr->r_type = R_SH_SWITCH8; - else if (fix->fx_r_type == BFD_RELOC_32) - intr->r_type = R_SH_SWITCH32; - else - abort (); - - /* For a switch reloc, we set r_offset to the difference between - the reloc address and the subtrahend. When the linker is - doing relaxing, it can use the determine the starting and - ending points of the switch difference expression. */ - intr->r_offset = intr->r_vaddr - S_GET_VALUE (fix->fx_subsy); - } - - /* PC relative relocs are always against the current section. */ - if (symbol_ptr == NULL) - { - switch (fix->fx_r_type) - { - case BFD_RELOC_SH_PCRELIMM8BY2: - case BFD_RELOC_SH_PCRELIMM8BY4: - case BFD_RELOC_SH_PCDISP8BY2: - case BFD_RELOC_SH_PCDISP12BY2: - case BFD_RELOC_SH_USES: - symbol_ptr = seg->dot; - break; - default: - break; - } - } - - if (fix->fx_r_type == BFD_RELOC_SH_USES) - { - /* We can't store the offset in the object file, since this - reloc does not take up any space, so we store it in r_offset. - The fx_addnumber field was set in md_apply_fix3. */ - intr->r_offset = fix->fx_addnumber; - } - else if (fix->fx_r_type == BFD_RELOC_SH_COUNT) - { - /* We can't store the count in the object file, since this reloc - does not take up any space, so we store it in r_offset. The - fx_offset field was set when the fixup was created in - sh_coff_frob_file. */ - intr->r_offset = fix->fx_offset; - /* This reloc is always absolute. */ - symbol_ptr = NULL; - } - else if (fix->fx_r_type == BFD_RELOC_SH_ALIGN) - { - /* Store the alignment in the r_offset field. */ - intr->r_offset = fix->fx_offset; - /* This reloc is always absolute. */ - symbol_ptr = NULL; - } - else if (fix->fx_r_type == BFD_RELOC_SH_CODE - || fix->fx_r_type == BFD_RELOC_SH_DATA - || fix->fx_r_type == BFD_RELOC_SH_LABEL) - { - /* These relocs are always absolute. */ - symbol_ptr = NULL; - } - - /* Turn the segment of the symbol into an offset. */ - if (symbol_ptr != NULL) - { - dot = segment_info[S_GET_SEGMENT (symbol_ptr)].dot; - if (dot != NULL) - intr->r_symndx = dot->sy_number; - else - intr->r_symndx = symbol_ptr->sy_number; - } - else - intr->r_symndx = -1; -} - -#endif /* OBJ_COFF */ -#endif /* ! BFD_ASSEMBLER */ - -#ifdef BFD_ASSEMBLER - /* Create a reloc. */ arelent * @@ -4279,7 +4295,10 @@ sh_end_of_match (char *cont, char *what) } int -sh_parse_name (char const *name, expressionS *exprP, char *nextcharP) +sh_parse_name (char const *name, + expressionS *exprP, + enum expr_mode mode, + char *nextcharP) { char *next = input_line_pointer; char *next_end; @@ -4296,15 +4315,15 @@ sh_parse_name (char const *name, expressionS *exprP, char *nextcharP) exprP->X_add_symbol = GOT_symbol; no_suffix: /* If we have an absolute symbol or a reg, then we know its - value now. */ + value now. */ segment = S_GET_SEGMENT (exprP->X_add_symbol); - if (segment == absolute_section) + if (mode != expr_defer && 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) + else if (mode != expr_defer && segment == reg_section) { exprP->X_op = O_register; exprP->X_add_number = S_GET_VALUE (exprP->X_add_symbol); @@ -4355,7 +4374,6 @@ sh_parse_name (char const *name, expressionS *exprP, char *nextcharP) return 1; } -#endif void sh_cfi_frame_initial_instructions (void) @@ -4405,4 +4423,4 @@ sh_regname_to_dw2regnum (const char *regname) } return regnum; } -#endif /* BFD_ASSEMBLER */ +#endif /* OBJ_ELF */