X-Git-Url: http://drtracing.org/?a=blobdiff_plain;ds=sidebyside;f=gas%2Fconfig%2Ftc-sh.c;h=3e410e303850c429e770a862961e44051b9aa3ec;hb=6a5709a5a18aabe5b4f7f14ddfd758af3eaa9a31;hp=8bb72bd146ab8ad9e526d1ae7ea8040a3ee8a283;hpb=5d6255fea654e42fc10353d52f60cf56970744d5;p=deliverable%2Fbinutils-gdb.git diff --git a/gas/config/tc-sh.c b/gas/config/tc-sh.c index 8bb72bd146..3e410e3038 100644 --- a/gas/config/tc-sh.c +++ b/gas/config/tc-sh.c @@ -1,5 +1,5 @@ -/* tc-sh.c -- Assemble code for the Hitachi Super-H - Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002 +/* tc-sh.c -- Assemble code for the Renesas / SuperH SH + Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. This file is part of GAS, the GNU Assembler. @@ -48,43 +48,17 @@ const char comment_chars[] = "!"; const char line_separator_chars[] = ";"; const char line_comment_chars[] = "!#"; -static void s_uses PARAMS ((int)); - -static void sh_count_relocs PARAMS ((bfd *, segT, PTR)); -static void sh_frob_section PARAMS ((bfd *, segT, PTR)); - -static void s_uacons PARAMS ((int)); -static sh_opcode_info *find_cooked_opcode PARAMS ((char **)); -static unsigned int assemble_ppi PARAMS ((char *, sh_opcode_info *)); -static void little PARAMS ((int)); -static void big PARAMS ((int)); -static int parse_reg PARAMS ((char *, int *, int *)); -static char *parse_exp PARAMS ((char *, sh_operand_info *)); -static char *parse_at PARAMS ((char *, sh_operand_info *)); -static void get_operand PARAMS ((char **, sh_operand_info *)); -static char *get_operands - PARAMS ((sh_opcode_info *, char *, sh_operand_info *)); -static sh_opcode_info *get_specific - PARAMS ((sh_opcode_info *, sh_operand_info *)); -static void insert PARAMS ((char *, int, int, sh_operand_info *)); -static void build_relax PARAMS ((sh_opcode_info *, sh_operand_info *)); -static char *insert_loop_bounds PARAMS ((char *, sh_operand_info *)); -static unsigned int build_Mytes - PARAMS ((sh_opcode_info *, sh_operand_info *)); +static void s_uses (int); +static void s_uacons (int); #ifdef OBJ_ELF -static void sh_elf_cons PARAMS ((int)); - -inline static int sh_PIC_related_p PARAMS ((symbolS *)); -static int sh_check_fixup PARAMS ((expressionS *, bfd_reloc_code_real_type *)); -inline static char *sh_end_of_match PARAMS ((char *, char *)); +static void sh_elf_cons (int); symbolS *GOT_symbol; /* Pre-defined "_GLOBAL_OFFSET_TABLE_" */ #endif static void -big (ignore) - int ignore ATTRIBUTE_UNUSED; +big (int ignore ATTRIBUTE_UNUSED) { if (! target_big_endian) as_bad (_("directive .big encountered when option -big required")); @@ -94,8 +68,7 @@ big (ignore) } static void -little (ignore) - int ignore ATTRIBUTE_UNUSED; +little (int ignore ATTRIBUTE_UNUSED) { if (target_big_endian) as_bad (_("directive .little encountered when option -little required")); @@ -135,10 +108,6 @@ const pseudo_typeS md_pseudo_table[] = {"2byte", s_uacons, 2}, {"4byte", s_uacons, 4}, {"8byte", s_uacons, 8}, -#ifdef BFD_ASSEMBLER - {"file", dwarf2_directive_file, 0 }, - {"loc", dwarf2_directive_loc, 0 }, -#endif #ifdef HAVE_SH64 {"mode", s_sh64_mode, 0 }, @@ -162,12 +131,12 @@ int sh_relax; /* set if -relax seen */ int sh_small; -/* Whether -dsp was seen. */ +/* preset architecture set, if given; zero otherwise. */ -static int sh_dsp; +static int preset_target_arch; /* The bit mask of architectures that could - accomodate the insns seen so far. */ + accommodate the insns seen so far. */ static int valid_arch; const char EXP_CHARS[] = "eE"; @@ -182,7 +151,7 @@ const char FLT_CHARS[] = "rRsSfFdDxXpP"; #define ENCODE_RELAX(what,length) (((what) << 4) + (length)) #define GET_WHAT(x) ((x>>4)) -/* These are the three types of relaxable instrction. */ +/* These are the three types of relaxable instruction. */ /* These are the types of relaxable instructions; except for END which is a marker. */ #define COND_JUMP 1 @@ -513,8 +482,7 @@ static struct hash_control *opcode_hash_control; /* Opcode mnemonics */ /* Determinet whether the symbol needs any kind of PIC relocation. */ inline static int -sh_PIC_related_p (sym) - symbolS *sym; +sh_PIC_related_p (symbolS *sym) { expressionS *exp; @@ -540,9 +508,7 @@ sh_PIC_related_p (sym) expression, that may be rearranged. */ static int -sh_check_fixup (main_exp, r_type_p) - expressionS *main_exp; - bfd_reloc_code_real_type *r_type_p; +sh_check_fixup (expressionS *main_exp, bfd_reloc_code_real_type *r_type_p) { expressionS *exp = main_exp; @@ -768,10 +734,7 @@ sh_check_fixup (main_exp, r_type_p) /* Add expression EXP of SIZE bytes to offset OFF of fragment FRAG. */ void -sh_cons_fix_new (frag, off, size, exp) - fragS *frag; - int off, size; - expressionS *exp; +sh_cons_fix_new (fragS *frag, int off, int size, expressionS *exp) { bfd_reloc_code_real_type r_type = BFD_RELOC_UNUSED; @@ -816,16 +779,16 @@ sh_cons_fix_new (frag, off, size, exp) suffixes such as @GOT, @GOTOFF and @PLT, that generate machine-specific relocation types. So we must define it here. */ /* Clobbers input_line_pointer, checks end-of-line. */ +/* NBYTES 1=.byte, 2=.word, 4=.long */ static void -sh_elf_cons (nbytes) - register int nbytes; /* 1=.byte, 2=.word, 4=.long */ +sh_elf_cons (register int nbytes) { expressionS exp; #ifdef HAVE_SH64 /* Update existing range to include a previous insn, if there was one. */ - sh64_update_contents_mark (true); + sh64_update_contents_mark (TRUE); /* We need to make sure the contents type is set to data. */ sh64_flag_output (); @@ -838,6 +801,10 @@ sh_elf_cons (nbytes) return; } +#ifdef md_cons_align + md_cons_align (nbytes); +#endif + do { expression (&exp); @@ -860,13 +827,14 @@ sh_elf_cons (nbytes) set up all the tables, etc that the MD part of the assembler needs. */ void -md_begin () +md_begin (void) { - sh_opcode_info *opcode; + const sh_opcode_info *opcode; char *prev_name = ""; int target_arch; - target_arch = arch_sh1_up & ~(sh_dsp ? arch_sh3e_up : arch_sh_dsp_up); + target_arch + = preset_target_arch ? preset_target_arch : arch_sh1_up & ~arch_sh_dsp_up; valid_arch = target_arch; #ifdef HAVE_SH64 @@ -878,19 +846,13 @@ md_begin () /* Insert unique names into hash table. */ for (opcode = sh_table; opcode->name; opcode++) { - if (strcmp (prev_name, opcode->name)) + if (strcmp (prev_name, opcode->name) != 0) { if (! (opcode->arch & target_arch)) continue; prev_name = opcode->name; hash_insert (opcode_hash_control, opcode->name, (char *) opcode); } - else - { - /* Make all the opcodes with the same name point to the same - string. */ - opcode->name = prev_name; - } } } @@ -905,10 +867,7 @@ static int reg_b; /* Try to parse a reg name. Return the number of chars consumed. */ static int -parse_reg (src, mode, reg) - char *src; - int *mode; - int *reg; +parse_reg (char *src, int *mode, int *reg) { char l0 = TOLOWER (src[0]); char l1 = l0 ? TOLOWER (src[1]) : 0; @@ -1258,9 +1217,7 @@ parse_reg (src, mode, reg) } static char * -parse_exp (s, op) - char *s; - sh_operand_info *op; +parse_exp (char *s, sh_operand_info *op) { char *save; char *new; @@ -1301,9 +1258,7 @@ parse_exp (s, op) */ static char * -parse_at (src, op) - char *src; - sh_operand_info *op; +parse_at (char *src, sh_operand_info *op) { int len; int mode; @@ -1383,10 +1338,33 @@ parse_at (src, op) } else if (mode == A_PC) { - op->type = A_DISP_PC_ABS; - /* Such operands don't get corrected for PC==.+4, so - make the correction here. */ - op->immediate.X_add_number -= 4; + /* We want @(expr, pc) to uniformly address . + expr, + no matter if expr is a constant, or a more complex + expression, e.g. sym-. or sym1-sym2. + However, we also used to accept @(sym,pc) + as addressing sym, i.e. meaning the same as plain sym. + Some existing code does use the @(sym,pc) syntax, so + we give it the old semantics for now, but warn about + its use, so that users have some time to fix their code. + + Note that due to this backward compatibility hack, + we'll get unexpected results when @(offset, pc) is used, + and offset is a symbol that is set later to an an address + difference, or an external symbol that is set to an + address difference in another source file, so we want to + eventually remove it. */ + if (op->immediate.X_op == O_symbol) + { + op->type = A_DISP_PC; + as_warn (_("Deprecated syntax.")); + } + else + { + op->type = A_DISP_PC_ABS; + /* Such operands don't get corrected for PC==.+4, so + make the correction here. */ + op->immediate.X_add_number -= 4; + } } else { @@ -1422,13 +1400,13 @@ parse_at (src, op) || (l0 == 'i' && (l1 == 'x' || l1 == 's'))) { src += 2; - op->type = A_PMOD_N; + op->type = AX_PMOD_N; } else if ( (l0 == 'r' && l1 == '9') || (l0 == 'i' && l1 == 'y')) { src += 2; - op->type = A_PMODY_N; + op->type = AY_PMOD_N; } else op->type = A_INC_N; @@ -1440,9 +1418,7 @@ parse_at (src, op) } static void -get_operand (ptr, op) - char **ptr; - sh_operand_info *op; +get_operand (char **ptr, sh_operand_info *op) { char *src = *ptr; int mode = -1; @@ -1478,10 +1454,7 @@ get_operand (ptr, op) } static char * -get_operands (info, args, operand) - sh_opcode_info *info; - char *args; - sh_operand_info *operand; +get_operands (sh_opcode_info *info, char *args, sh_operand_info *operand) { char *ptr = args; if (info->arg[0]) @@ -1539,9 +1512,7 @@ get_operands (info, args, operand) provided. */ static sh_opcode_info * -get_specific (opcode, operands) - sh_opcode_info *opcode; - sh_operand_info *operands; +get_specific (sh_opcode_info *opcode, sh_operand_info *operands) { sh_opcode_info *this_try = opcode; char *name = opcode->name; @@ -1550,7 +1521,7 @@ get_specific (opcode, operands) while (opcode->name) { this_try = opcode++; - if (this_try->name != name) + if ((this_try->name != name) && (strcmp (this_try->name, name) != 0)) { /* We've looked so far down the table that we've run out of opcodes with the same name. */ @@ -1566,27 +1537,6 @@ get_specific (opcode, operands) sh_operand_info *user = operands + n; sh_arg_type arg = this_try->arg[n]; - /* If this is a parallel insn check to see if both - parts have the same destination register. */ - if ((n == 2) && (this_try->nibbles[0] == PPI)) - { - static boolean bIsPPI = false; - static int nLastDestReg; - - if (!bIsPPI) - { - bIsPPI = true; - nLastDestReg = user->reg; - } - else /* Second insn. */ - { - if (nLastDestReg == user->reg) - as_warn (_("destination register is same for parallel insns")); - - bIsPPI = false; - } - } - switch (arg) { case A_DISP_PC: @@ -1629,8 +1579,6 @@ get_specific (opcode, operands) case V_REG_N: case FPUL_N: case FPSCR_N: - case A_PMOD_N: - case A_PMODY_N: case DSP_REG_N: /* Opcode needs rn */ if (user->type != arg) @@ -1676,6 +1624,237 @@ get_specific (opcode, operands) reg_m = user->reg; break; + case AS_DEC_N: + if (user->type != A_DEC_N) + goto fail; + if (user->reg < 2 || user->reg > 5) + goto fail; + reg_n = user->reg; + break; + + case AS_INC_N: + if (user->type != A_INC_N) + goto fail; + if (user->reg < 2 || user->reg > 5) + goto fail; + reg_n = user->reg; + break; + + case AS_IND_N: + if (user->type != A_IND_N) + goto fail; + if (user->reg < 2 || user->reg > 5) + goto fail; + reg_n = user->reg; + break; + + case AS_PMOD_N: + if (user->type != AX_PMOD_N) + goto fail; + if (user->reg < 2 || user->reg > 5) + goto fail; + reg_n = user->reg; + break; + + case AX_INC_N: + if (user->type != A_INC_N) + goto fail; + if (user->reg < 4 || user->reg > 5) + goto fail; + reg_n = user->reg; + break; + + case AX_IND_N: + if (user->type != A_IND_N) + goto fail; + if (user->reg < 4 || user->reg > 5) + goto fail; + reg_n = user->reg; + break; + + case AX_PMOD_N: + if (user->type != AX_PMOD_N) + goto fail; + if (user->reg < 4 || user->reg > 5) + goto fail; + reg_n = user->reg; + break; + + case AXY_INC_N: + if (user->type != A_INC_N) + goto fail; + if ((user->reg < 4 || user->reg > 5) + && (user->reg < 0 || user->reg > 1)) + goto fail; + reg_n = user->reg; + break; + + case AXY_IND_N: + if (user->type != A_IND_N) + goto fail; + if ((user->reg < 4 || user->reg > 5) + && (user->reg < 0 || user->reg > 1)) + goto fail; + reg_n = user->reg; + break; + + case AXY_PMOD_N: + if (user->type != AX_PMOD_N) + goto fail; + if ((user->reg < 4 || user->reg > 5) + && (user->reg < 0 || user->reg > 1)) + goto fail; + reg_n = user->reg; + break; + + case AY_INC_N: + if (user->type != A_INC_N) + goto fail; + if (user->reg < 6 || user->reg > 7) + goto fail; + reg_n = user->reg; + break; + + case AY_IND_N: + if (user->type != A_IND_N) + goto fail; + if (user->reg < 6 || user->reg > 7) + goto fail; + reg_n = user->reg; + break; + + case AY_PMOD_N: + if (user->type != AY_PMOD_N) + goto fail; + if (user->reg < 6 || user->reg > 7) + goto fail; + reg_n = user->reg; + break; + + case AYX_INC_N: + if (user->type != A_INC_N) + goto fail; + if ((user->reg < 6 || user->reg > 7) + && (user->reg < 2 || user->reg > 3)) + goto fail; + reg_n = user->reg; + break; + + case AYX_IND_N: + if (user->type != A_IND_N) + goto fail; + if ((user->reg < 6 || user->reg > 7) + && (user->reg < 2 || user->reg > 3)) + goto fail; + reg_n = user->reg; + break; + + case AYX_PMOD_N: + if (user->type != AY_PMOD_N) + goto fail; + if ((user->reg < 6 || user->reg > 7) + && (user->reg < 2 || user->reg > 3)) + goto fail; + reg_n = user->reg; + break; + + case DSP_REG_A_M: + if (user->type != DSP_REG_N) + goto fail; + if (user->reg != A_A0_NUM + && user->reg != A_A1_NUM) + goto fail; + reg_m = user->reg; + break; + + case DSP_REG_AX: + if (user->type != DSP_REG_N) + goto fail; + switch (user->reg) + { + case A_A0_NUM: + reg_x = 0; + break; + case A_A1_NUM: + reg_x = 2; + break; + case A_X0_NUM: + reg_x = 1; + break; + case A_X1_NUM: + reg_x = 3; + break; + default: + goto fail; + } + break; + + case DSP_REG_XY: + if (user->type != DSP_REG_N) + goto fail; + switch (user->reg) + { + case A_X0_NUM: + reg_x = 0; + break; + case A_X1_NUM: + reg_x = 2; + break; + case A_Y0_NUM: + reg_x = 1; + break; + case A_Y1_NUM: + reg_x = 3; + break; + default: + goto fail; + } + break; + + case DSP_REG_AY: + if (user->type != DSP_REG_N) + goto fail; + switch (user->reg) + { + case A_A0_NUM: + reg_y = 0; + break; + case A_A1_NUM: + reg_y = 1; + break; + case A_Y0_NUM: + reg_y = 2; + break; + case A_Y1_NUM: + reg_y = 3; + break; + default: + goto fail; + } + break; + + case DSP_REG_YX: + if (user->type != DSP_REG_N) + goto fail; + switch (user->reg) + { + case A_Y0_NUM: + reg_y = 0; + break; + case A_Y1_NUM: + reg_y = 1; + break; + case A_X0_NUM: + reg_y = 2; + break; + case A_X1_NUM: + reg_y = 3; + break; + default: + goto fail; + } + break; + case DSP_REG_X: if (user->type != DSP_REG_N) goto fail; @@ -1846,11 +2025,7 @@ get_specific (opcode, operands) } static void -insert (where, how, pcrel, op) - char *where; - int how; - int pcrel; - sh_operand_info *op; +insert (char *where, int how, int pcrel, sh_operand_info *op) { fix_new_exp (frag_now, where - frag_now->fr_literal, @@ -1861,9 +2036,7 @@ insert (where, how, pcrel, op) } static void -build_relax (opcode, op) - sh_opcode_info *opcode; - sh_operand_info *op; +build_relax (sh_opcode_info *opcode, sh_operand_info *op) { int high_byte = target_big_endian ? 0 : 1; char *p; @@ -1897,9 +2070,7 @@ build_relax (opcode, op) /* Insert ldrs & ldre with fancy relocations that relaxation can recognize. */ static char * -insert_loop_bounds (output, operand) - char *output; - sh_operand_info *operand; +insert_loop_bounds (char *output, sh_operand_info *operand) { char *name; symbolS *end_sym; @@ -1947,9 +2118,7 @@ insert_loop_bounds (output, operand) /* Now we know what sort of opcodes it is, let's build the bytes. */ static unsigned int -build_Mytes (opcode, operand) - sh_opcode_info *opcode; - sh_operand_info *operand; +build_Mytes (sh_opcode_info *opcode, sh_operand_info *operand) { int index; char nbuf[4]; @@ -1973,6 +2142,7 @@ build_Mytes (opcode, operand) switch (i) { case REG_N: + case REG_N_D: nbuf[index] = reg_n; break; case REG_M: @@ -1989,6 +2159,9 @@ build_Mytes (opcode, operand) case REG_B: nbuf[index] = reg_b | 0x08; break; + case REG_N_B01: + nbuf[index] = reg_n | 0x01; + break; case IMM0_4BY4: insert (output + low_byte, BFD_RELOC_SH_IMM4BY4, 0, operand); break; @@ -2060,8 +2233,7 @@ build_Mytes (opcode, operand) *STR_P to the first character after the last one read. */ static sh_opcode_info * -find_cooked_opcode (str_p) - char **str_p; +find_cooked_opcode (char **str_p) { char *str = *str_p; unsigned char *op_start; @@ -2108,9 +2280,7 @@ find_cooked_opcode (str_p) #define DDT_BASE 0xf000 /* Base value for double data transfer insns */ static unsigned int -assemble_ppi (op_end, opcode) - char *op_end; - sh_opcode_info *opcode; +assemble_ppi (char *op_end, sh_opcode_info *opcode) { int movx = 0; int movy = 0; @@ -2120,17 +2290,19 @@ assemble_ppi (op_end, opcode) int move_code; unsigned int size; - /* Some insn ignore one or more register fields, e.g. psts machl,a0. - Make sure we encode a defined insn pattern. */ - reg_x = 0; - reg_y = 0; - for (;;) { sh_operand_info operand[3]; + /* Some insn ignore one or more register fields, e.g. psts machl,a0. + Make sure we encode a defined insn pattern. */ + reg_x = 0; + reg_y = 0; + reg_n = 0; + if (opcode->arg[0] != A_END) op_end = get_operands (opcode, op_end, operand); + try_another_opcode: opcode = get_specific (opcode, operand); if (opcode == 0) { @@ -2161,9 +2333,43 @@ assemble_ppi (op_end, opcode) movy = DDT_BASE; break; + case MOVX_NOPY: + if (movx) + as_bad (_("multiple movx specifications")); + if ((reg_n < 4 || reg_n > 5) + && (reg_n < 0 || reg_n > 1)) + as_bad (_("invalid movx address register")); + if (movy && movy != DDT_BASE) + as_bad (_("insn cannot be combined with non-nopy")); + movx = ((((reg_n & 1) != 0) << 9) + + (((reg_n & 4) == 0) << 8) + + (reg_x << 6) + + (opcode->nibbles[2] << 4) + + opcode->nibbles[3] + + DDT_BASE); + break; + + case MOVY_NOPX: + if (movy) + as_bad (_("multiple movy specifications")); + if ((reg_n < 6 || reg_n > 7) + && (reg_n < 2 || reg_n > 3)) + as_bad (_("invalid movy address register")); + if (movx && movx != DDT_BASE) + as_bad (_("insn cannot be combined with non-nopx")); + movy = ((((reg_n & 1) != 0) << 8) + + (((reg_n & 4) == 0) << 9) + + (reg_y << 6) + + (opcode->nibbles[2] << 4) + + opcode->nibbles[3] + + DDT_BASE); + break; + case MOVX: if (movx) as_bad (_("multiple movx specifications")); + if (movy & 0x2ac) + as_bad (_("previous movy requires nopx")); if (reg_n < 4 || reg_n > 5) as_bad (_("invalid movx address register")); if (opcode->nibbles[2] & 8) @@ -2185,6 +2391,8 @@ assemble_ppi (op_end, opcode) case MOVY: if (movy) as_bad (_("multiple movy specifications")); + if (movx & 0x153) + as_bad (_("previous movx requires nopy")); if (opcode->nibbles[2] & 8) { /* Bit 3 in nibbles[2] is intended for bit 4 of the opcode, @@ -2213,11 +2421,31 @@ assemble_ppi (op_end, opcode) | (operand[0].immediate.X_add_number & 127) << 4 | reg_n); break; + case PPI3NC: + if (cond) + { + opcode++; + goto try_another_opcode; + } + /* Fall through. */ case PPI3: if (field_b) as_bad (_("multiple parallel processing specifications")); field_b = ((opcode->nibbles[2] << 12) + (opcode->nibbles[3] << 8) + (reg_x << 6) + (reg_y << 4) + reg_n); + switch (opcode->nibbles[4]) + { + case HEX_0: + case HEX_XX00: + case HEX_00YY: + break; + case HEX_1: + case HEX_4: + field_b += opcode->nibbles[4] << 4; + break; + default: + abort (); + } break; case PDC: if (cond) @@ -2232,13 +2460,34 @@ assemble_ppi (op_end, opcode) field_b = ((opcode->nibbles[2] << 12) + (opcode->nibbles[3] << 8) + cond + (reg_x << 6) + (reg_y << 4) + reg_n); cond = 0; + switch (opcode->nibbles[4]) + { + case HEX_0: + case HEX_XX00: + case HEX_00YY: + break; + case HEX_1: + case HEX_4: + field_b += opcode->nibbles[4] << 4; + break; + default: + abort (); + } break; case PMUL: if (field_b) { - if ((field_b & 0xef00) != 0xa100) + if ((field_b & 0xef00) == 0xa100) + field_b -= 0x8100; + /* pclr Dz pmuls Se,Sf,Dg */ + else if ((field_b & 0xff00) == 0x8d00 + && (valid_arch & arch_sh4al_dsp_up)) + { + valid_arch &= arch_sh4al_dsp_up; + field_b -= 0x8cf0; + } + else as_bad (_("insn cannot be combined with pmuls")); - field_b -= 0x8100; switch (field_b & 0xf) { case A_X0_NUM: @@ -2254,8 +2503,17 @@ assemble_ppi (op_end, opcode) field_b += 3 - A_A1_NUM; break; default: - as_bad (_("bad padd / psub pmuls output operand")); + as_bad (_("bad combined pmuls output operand")); } + /* Generate warning if the destination register for padd / psub + and pmuls is the same ( only for A0 or A1 ). + If the last nibble is 1010 then A0 is used in both + padd / psub and pmuls. If it is 1111 then A1 is used + as destination register in both padd / psub and pmuls. */ + + if ((((field_b | reg_efg) & 0x000F) == 0x000A) + || (((field_b | reg_efg) & 0x000F) == 0x000F)) + as_warn (_("destination register is same for parallel insns")); } field_b += 0x4000 + reg_efg; break; @@ -2323,8 +2581,7 @@ assemble_ppi (op_end, opcode) the frags/bytes it assembles to. */ void -md_assemble (str) - char *str; +md_assemble (char *str) { unsigned char *op_end; sh_operand_info operand[3]; @@ -2341,13 +2598,13 @@ md_assemble (str) { /* If we've seen pseudo-directives, make sure any emitted data or frags are marked as data. */ - if (seen_insn == false) + if (!seen_insn) { - sh64_update_contents_mark (true); + sh64_update_contents_mark (TRUE); sh64_set_contents_type (CRT_SH5_ISA16); } - seen_insn = true; + seen_insn = TRUE; } #endif /* HAVE_SH64 */ @@ -2379,6 +2636,12 @@ md_assemble (str) if (opcode->arg[0] == A_BDISP12 || opcode->arg[0] == A_BDISP8) { + /* Since we skip get_specific here, we have to check & update + valid_arch now. */ + if (valid_arch & opcode->arch) + valid_arch &= opcode->arch; + else + as_bad (_("Delayed branches not available on SH1")); parse_exp (op_end + 1, &operand[0]); build_relax (opcode, &operand[0]); } @@ -2426,7 +2689,7 @@ md_assemble (str) emits a BFD_RELOC_SH_LABEL reloc if necessary. */ void -sh_frob_label () +sh_frob_label (void) { static fragS *last_label_frag; static int last_label_offset; @@ -2451,7 +2714,7 @@ sh_frob_label () data. It emits a BFD_RELOC_SH_DATA reloc if necessary. */ void -sh_flush_pending_output () +sh_flush_pending_output (void) { if (sh_relax && seg_info (now_seg)->tc_segment_info_data.in_code) @@ -2463,8 +2726,7 @@ sh_flush_pending_output () } symbolS * -md_undefined_symbol (name) - char *name ATTRIBUTE_UNUSED; +md_undefined_symbol (char *name ATTRIBUTE_UNUSED) { return 0; } @@ -2473,15 +2735,13 @@ md_undefined_symbol (name) #ifndef BFD_ASSEMBLER void -tc_crawl_symbol_chain (headers) - object_headers *headers; +tc_crawl_symbol_chain (object_headers *headers ATTRIBUTE_UNUSED) { printf (_("call to tc_crawl_symbol_chain \n")); } void -tc_headers_hook (headers) - object_headers *headers; +tc_headers_hook (object_headers *headers ATTRIBUTE_UNUSED) { printf (_("call to tc_headers_hook \n")); } @@ -2499,10 +2759,7 @@ tc_headers_hook (headers) returned, or NULL on OK. */ char * -md_atof (type, litP, sizeP) - int type; - char *litP; - int *sizeP; +md_atof (int type, char *litP, int *sizeP) { int prec; LITTLENUM_TYPE words[4]; @@ -2556,8 +2813,7 @@ md_atof (type, litP, sizeP) special reloc for the linker. */ static void -s_uses (ignore) - int ignore ATTRIBUTE_UNUSED; +s_uses (int ignore ATTRIBUTE_UNUSED) { expressionS ex; @@ -2578,7 +2834,7 @@ s_uses (ignore) demand_empty_rest_of_line (); } -CONST char *md_shortopts = ""; +const char *md_shortopts = ""; struct option md_longopts[] = { #define OPTION_RELAX (OPTION_MD_BASE) @@ -2586,20 +2842,20 @@ struct option md_longopts[] = #define OPTION_LITTLE (OPTION_BIG + 1) #define OPTION_SMALL (OPTION_LITTLE + 1) #define OPTION_DSP (OPTION_SMALL + 1) +#define OPTION_ISA (OPTION_DSP + 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}, #ifdef HAVE_SH64 -#define OPTION_ISA (OPTION_DSP + 1) #define OPTION_ABI (OPTION_ISA + 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) - {"isa", required_argument, NULL, OPTION_ISA}, {"abi", required_argument, NULL, OPTION_ABI}, {"no-mix", no_argument, NULL, OPTION_NO_MIX}, {"shcompact-const-crange", no_argument, NULL, OPTION_SHCOMPACT_CONST_CRANGE}, @@ -2612,9 +2868,7 @@ struct option md_longopts[] = size_t md_longopts_size = sizeof (md_longopts); int -md_parse_option (c, arg) - int c; - char *arg ATTRIBUTE_UNUSED; +md_parse_option (int c, char *arg ATTRIBUTE_UNUSED) { switch (c) { @@ -2635,12 +2889,22 @@ md_parse_option (c, arg) break; case OPTION_DSP: - sh_dsp = 1; + preset_target_arch = arch_sh1_up & ~arch_sh2e_up; break; -#ifdef HAVE_SH64 case OPTION_ISA: - if (strcasecmp (arg, "shmedia") == 0) + if (strcasecmp (arg, "sh4") == 0) + preset_target_arch = arch_sh4; + else if (strcasecmp (arg, "sh4a") == 0) + preset_target_arch = arch_sh4a; + else if (strcasecmp (arg, "dsp") == 0) + preset_target_arch = arch_sh1_up & ~arch_sh2e_up; + else if (strcasecmp (arg, "fp") == 0) + preset_target_arch = arch_sh2e_up; + else if (strcasecmp (arg, "any") == 0) + preset_target_arch = arch_sh1_up; +#ifdef HAVE_SH64 + else if (strcasecmp (arg, "shmedia") == 0) { if (sh64_isa_mode == sh64_isa_shcompact) as_bad (_("Invalid combination: --isa=SHcompact with --isa=SHmedia")); @@ -2654,10 +2918,12 @@ md_parse_option (c, arg) as_bad (_("Invalid combination: --abi=64 with --isa=SHcompact")); sh64_isa_mode = sh64_isa_shcompact; } +#endif /* HAVE_SH64 */ else as_bad ("Invalid argument to --isa option: %s", arg); break; +#ifdef HAVE_SH64 case OPTION_ABI: if (strcmp (arg, "32") == 0) { @@ -2678,19 +2944,19 @@ md_parse_option (c, arg) break; case OPTION_NO_MIX: - sh64_mix = false; + sh64_mix = FALSE; break; case OPTION_SHCOMPACT_CONST_CRANGE: - sh64_shcompact_const_crange = true; + sh64_shcompact_const_crange = TRUE; break; case OPTION_NO_EXPAND: - sh64_expand = false; + sh64_expand = FALSE; break; case OPTION_PT32: - sh64_pt32 = true; + sh64_pt32 = TRUE; break; #endif /* HAVE_SH64 */ @@ -2702,8 +2968,7 @@ md_parse_option (c, arg) } void -md_show_usage (stream) - FILE *stream; +md_show_usage (FILE *stream) { fprintf (stream, _("\ SH options:\n\ @@ -2711,13 +2976,18 @@ SH options:\n\ -big generate big endian code\n\ -relax alter jump instructions for long displacements\n\ -small align sections to 4 byte boundaries, not 16\n\ --dsp enable sh-dsp insns, and disable sh3e / sh4 insns.\n")); +-dsp enable sh-dsp insns, and disable floating-point ISAs.\n")); #ifdef HAVE_SH64 fprintf (stream, _("\ --isa=[shmedia set default instruction set for SH64\n\ - | SHmedia\n\ - | shcompact\n\ - | SHcompact]\n\ +-isa=[sh4\n\ + | sh4a\n\ + | dsp same as '-dsp'\n\ + | fp\n\ + | 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\ file type\n\ -shcompact-const-crange emit code-range descriptors for constants in\n\ @@ -2726,7 +2996,14 @@ SH options:\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\ - to 32 bits only")); + to 32 bits only\n")); +#else + fprintf (stream, _("\ +-isa=[sh4\n\ + | sh4a\n\ + | dsp same as '-dsp'\n\ + | fp\n\ + | any]\n")); #endif /* HAVE_SH64 */ } @@ -2746,10 +3023,7 @@ struct sh_count_relocs bfd_map_over_sections. */ static void -sh_count_relocs (abfd, sec, data) - bfd *abfd ATTRIBUTE_UNUSED; - segT sec; - PTR data; +sh_count_relocs (bfd *abfd ATTRIBUTE_UNUSED, segT sec, void *data) { struct sh_count_relocs *info = (struct sh_count_relocs *) data; segment_info_type *seginfo; @@ -2775,10 +3049,8 @@ sh_count_relocs (abfd, sec, data) BFD_ASSEMBLER, this is called via bfd_map_over_sections. */ static void -sh_frob_section (abfd, sec, ignore) - bfd *abfd ATTRIBUTE_UNUSED; - segT sec; - PTR ignore ATTRIBUTE_UNUSED; +sh_frob_section (bfd *abfd ATTRIBUTE_UNUSED, segT sec, + void *ignore ATTRIBUTE_UNUSED) { segment_info_type *seginfo; fixS *fix; @@ -2861,13 +3133,13 @@ sh_frob_section (abfd, sec, ignore) info.sym = sym; info.count = 0; #ifdef BFD_ASSEMBLER - bfd_map_over_sections (stdoutput, sh_count_relocs, (PTR) &info); + 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, (PTR) &info); + sh_count_relocs ((bfd *) NULL, iscan, &info); } #endif @@ -2895,7 +3167,7 @@ sh_frob_section (abfd, sec, ignore) the stored function address entirely. */ void -sh_frob_file () +sh_frob_file (void) { #ifdef HAVE_SH64 shmedia_frob_file_before_adjust (); @@ -2905,13 +3177,13 @@ sh_frob_file () return; #ifdef BFD_ASSEMBLER - bfd_map_over_sections (stdoutput, sh_frob_section, (PTR) NULL); + 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, (PTR) NULL); + sh_frob_section ((bfd *) NULL, iseg, NULL); } #endif } @@ -2920,14 +3192,12 @@ sh_frob_file () create relocs so that md_apply_fix3 will fill in the correct values. */ void -md_convert_frag (headers, seg, fragP) #ifdef BFD_ASSEMBLER - bfd *headers ATTRIBUTE_UNUSED; +md_convert_frag (bfd *headers ATTRIBUTE_UNUSED, segT seg, fragS *fragP) #else - object_headers *headers; +md_convert_frag (object_headers *headers ATTRIBUTE_UNUSED, segT seg, + fragS *fragP) #endif - segT seg; - fragS *fragP; { int donerelax = 0; @@ -3055,7 +3325,7 @@ md_convert_frag (headers, seg, fragP) default: #ifdef HAVE_SH64 - shmedia_md_convert_frag (headers, seg, fragP, true); + shmedia_md_convert_frag (headers, seg, fragP, TRUE); #else abort (); #endif @@ -3070,9 +3340,7 @@ md_convert_frag (headers, seg, fragP) } valueT -md_section_align (seg, size) - segT seg ATTRIBUTE_UNUSED; - valueT size; +md_section_align (segT seg ATTRIBUTE_UNUSED, valueT size) { #ifdef BFD_ASSEMBLER #ifdef OBJ_ELF @@ -3088,7 +3356,7 @@ md_section_align (seg, size) } /* This static variable is set by s_uacons to tell sh_cons_align that - the expession does not need to be aligned. */ + the expression does not need to be aligned. */ static int sh_no_align_cons = 0; @@ -3097,8 +3365,7 @@ static int sh_no_align_cons = 0; to be aligned. */ static void -s_uacons (bytes) - int bytes; +s_uacons (int bytes) { /* Tell sh_cons_align not to align this value. */ sh_no_align_cons = 1; @@ -3112,8 +3379,7 @@ s_uacons (bytes) enable this warning? */ void -sh_cons_align (nbytes) - int nbytes; +sh_cons_align (int nbytes) { int nalign; char *p; @@ -3153,8 +3419,7 @@ sh_cons_align (nbytes) also where we check for misaligned data. */ void -sh_handle_align (frag) - fragS *frag; +sh_handle_align (fragS *frag) { int bytes = frag->fr_next->fr_address - frag->fr_address - frag->fr_fix; @@ -3199,44 +3464,42 @@ sh_handle_align (frag) BFD_RELOC_SH_ALIGN); } -/* This macro decides whether a particular reloc is an entry in a - switch table. It is used when relaxing, because the linker needs - to know about all such entries so that it can adjust them if - necessary. */ +/* See whether the relocation should be resolved locally. */ -#ifdef BFD_ASSEMBLER -#define SWITCH_TABLE_CONS(fix) (0) -#else -#define SWITCH_TABLE_CONS(fix) \ - ((fix)->fx_r_type == 0 \ - && ((fix)->fx_size == 2 \ - || (fix)->fx_size == 1 \ - || (fix)->fx_size == 4)) -#endif - -#define SWITCH_TABLE(fix) \ - ((fix)->fx_addsy != NULL \ - && (fix)->fx_subsy != NULL \ - && S_GET_SEGMENT ((fix)->fx_addsy) == text_section \ - && S_GET_SEGMENT ((fix)->fx_subsy) == text_section \ - && ((fix)->fx_r_type == BFD_RELOC_32 \ - || (fix)->fx_r_type == BFD_RELOC_16 \ - || (fix)->fx_r_type == BFD_RELOC_8 \ - || SWITCH_TABLE_CONS (fix))) +static bfd_boolean +sh_local_pcrel (fixS *fix) +{ + return (! sh_relax + && (fix->fx_r_type == BFD_RELOC_SH_PCDISP8BY2 + || fix->fx_r_type == BFD_RELOC_SH_PCDISP12BY2 + || fix->fx_r_type == BFD_RELOC_SH_PCRELIMM8BY2 + || fix->fx_r_type == BFD_RELOC_SH_PCRELIMM8BY4 + || fix->fx_r_type == BFD_RELOC_8_PCREL + || fix->fx_r_type == BFD_RELOC_SH_SWITCH16 + || fix->fx_r_type == BFD_RELOC_SH_SWITCH32)); +} /* See whether we need to force a relocation into the output file. This is used to force out switch and PC relative relocations when relaxing. */ int -sh_force_relocation (fix) - fixS *fix; +sh_force_relocation (fixS *fix) { + /* These relocations can't make it into a DSO, so no use forcing + them for global symbols. */ + if (sh_local_pcrel (fix)) + return 0; - if (fix->fx_r_type == BFD_RELOC_VTABLE_INHERIT - || fix->fx_r_type == BFD_RELOC_VTABLE_ENTRY - || fix->fx_r_type == BFD_RELOC_SH_LOOP_START - || fix->fx_r_type == BFD_RELOC_SH_LOOP_END) + /* Make sure some relocations get emitted. */ + if (fix->fx_r_type == BFD_RELOC_SH_LOOP_START + || fix->fx_r_type == BFD_RELOC_SH_LOOP_END + || fix->fx_r_type == BFD_RELOC_SH_TLS_GD_32 + || fix->fx_r_type == BFD_RELOC_SH_TLS_LD_32 + || fix->fx_r_type == BFD_RELOC_SH_TLS_IE_32 + || fix->fx_r_type == BFD_RELOC_SH_TLS_LDO_32 + || fix->fx_r_type == BFD_RELOC_SH_TLS_LE_32 + || generic_force_reloc (fix)) return 1; if (! sh_relax) @@ -3255,24 +3518,12 @@ sh_force_relocation (fix) } #ifdef OBJ_ELF -boolean -sh_fix_adjustable (fixP) - fixS *fixP; +bfd_boolean +sh_fix_adjustable (fixS *fixP) { - - if (fixP->fx_addsy == NULL) - return 1; - - if (fixP->fx_r_type == BFD_RELOC_SH_PCDISP8BY2 - || fixP->fx_r_type == BFD_RELOC_SH_PCDISP12BY2 - || fixP->fx_r_type == BFD_RELOC_SH_PCRELIMM8BY2 - || fixP->fx_r_type == BFD_RELOC_SH_PCRELIMM8BY4 - || fixP->fx_r_type == BFD_RELOC_8_PCREL - || fixP->fx_r_type == BFD_RELOC_SH_SWITCH16 - || fixP->fx_r_type == BFD_RELOC_SH_SWITCH32) - return 1; - - if (! TC_RELOC_RTSYM_LOC_FIXUP (fixP) + if (fixP->fx_r_type == BFD_RELOC_32_PLT_PCREL + || fixP->fx_r_type == BFD_RELOC_32_GOT_PCREL + || fixP->fx_r_type == BFD_RELOC_SH_GOTPC || fixP->fx_r_type == BFD_RELOC_RVA) return 0; @@ -3285,12 +3536,12 @@ sh_fix_adjustable (fixP) } void -sh_elf_final_processing () +sh_elf_final_processing (void) { int val; /* Set file-specific flags to indicate if this code needs - a processor with the sh-dsp / sh3e ISA to execute. */ + a processor with the sh-dsp / sh2e ISA to execute. */ #ifdef HAVE_SH64 /* SH5 and above don't know about the valid_arch arch_sh* bits defined in sh-opc.h, so check SH64 mode before checking valid_arch. */ @@ -3302,16 +3553,26 @@ sh_elf_final_processing () val = EF_SH1; else if (valid_arch & arch_sh2) val = EF_SH2; + else if (valid_arch & arch_sh2e) + val = EF_SH2E; else if (valid_arch & arch_sh_dsp) val = EF_SH_DSP; else if (valid_arch & arch_sh3) val = EF_SH3; else if (valid_arch & arch_sh3_dsp) - val = EF_SH_DSP; + val = EF_SH3_DSP; else if (valid_arch & arch_sh3e) val = EF_SH3E; + else if (valid_arch & arch_sh4_nofpu) + val = EF_SH4_NOFPU; else if (valid_arch & arch_sh4) val = EF_SH4; + else if (valid_arch & arch_sh4a_nofpu) + val = EF_SH4A_NOFPU; + else if (valid_arch & arch_sh4a) + val = EF_SH4A; + else if (valid_arch & arch_sh4al_dsp) + val = EF_SH4AL_DSP; else abort (); @@ -3323,10 +3584,7 @@ sh_elf_final_processing () /* Apply a fixup to the object file. */ void -md_apply_fix3 (fixP, valP, seg) - fixS * fixP; - valueT * valP; - segT seg ATTRIBUTE_UNUSED; +md_apply_fix3 (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; @@ -3383,7 +3641,10 @@ md_apply_fix3 (fixP, valP, seg) val -= S_GET_VALUE (fixP->fx_addsy); #endif -#ifndef BFD_ASSEMBLER +#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) @@ -3444,7 +3705,7 @@ md_apply_fix3 (fixP, valP, seg) case BFD_RELOC_SH_PCRELIMM8BY4: /* The lower two bits of the PC are cleared before the displacement is added in. We can assume that the destination - is on a 4 byte bounday. If this instruction is also on a 4 + is on a 4 byte boundary. If this instruction is also on a 4 byte boundary, then we want (target - here) / 4 and target - here is a multiple of 4. @@ -3518,9 +3779,10 @@ md_apply_fix3 (fixP, valP, seg) /* Make the jump instruction point to the address of the operand. At runtime we merely add the offset to the actual PLT entry. */ * valP = 0xfffffffc; - val = fixP->fx_addnumber; + val = fixP->fx_offset; if (fixP->fx_subsy) val -= S_GET_VALUE (fixP->fx_subsy); + fixP->fx_addnumber = val; md_number_to_chars (buf, val, 4); break; @@ -3545,12 +3807,21 @@ md_apply_fix3 (fixP, valP, seg) md_number_to_chars (buf, val, 4); break; + case BFD_RELOC_SH_TLS_GD_32: + case BFD_RELOC_SH_TLS_LD_32: + case BFD_RELOC_SH_TLS_IE_32: + S_SET_THREAD_LOCAL (fixP->fx_addsy); + /* Fallthrough */ case BFD_RELOC_32_GOT_PCREL: case BFD_RELOC_SH_GOTPLT32: * valP = 0; /* Fully resolved at runtime. No addend. */ md_number_to_chars (buf, 0, 4); break; + case BFD_RELOC_SH_TLS_LDO_32: + case BFD_RELOC_SH_TLS_LE_32: + S_SET_THREAD_LOCAL (fixP->fx_addsy); + /* Fallthrough */ case BFD_RELOC_32_GOTOFF: md_number_to_chars (buf, val, 4); break; @@ -3586,9 +3857,7 @@ md_apply_fix3 (fixP, valP, seg) by which a fragment must grow to reach it's destination. */ int -md_estimate_size_before_relax (fragP, segment_type) - register fragS *fragP; - register segT segment_type; +md_estimate_size_before_relax (fragS *fragP, segT segment_type) { int what; @@ -3664,10 +3933,7 @@ md_estimate_size_before_relax (fragP, segment_type) /* Put number into target byte order. */ void -md_number_to_chars (ptr, use, nbytes) - char *ptr; - valueT use; - int nbytes; +md_number_to_chars (char *ptr, valueT use, int nbytes) { #ifdef HAVE_SH64 /* We might need to set the contents type to data. */ @@ -3680,15 +3946,21 @@ md_number_to_chars (ptr, use, 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. */ + +long +md_pcrel_from (fixS *fixP) +{ + return fixP->fx_size + fixP->fx_where + fixP->fx_frag->fr_address + 2; +} + long -md_pcrel_from_section (fixP, sec) - fixS *fixP; - segT sec; +md_pcrel_from_section (fixS *fixP, segT sec) { - if (fixP->fx_addsy != (symbolS *) NULL - && (! S_IS_DEFINED (fixP->fx_addsy) - || S_IS_EXTERN (fixP->fx_addsy) - || S_IS_WEAK (fixP->fx_addsy) + if (! sh_local_pcrel (fixP) + && fixP->fx_addsy != (symbolS *) NULL + && (generic_force_reloc (fixP) || S_GET_SEGMENT (fixP->fx_addsy) != sec)) { /* The symbol is undefined (or is defined but not in this section, @@ -3698,14 +3970,13 @@ md_pcrel_from_section (fixP, sec) return fixP->fx_subsy ? fixP->fx_where + fixP->fx_frag->fr_address : 0; } - return fixP->fx_size + fixP->fx_where + fixP->fx_frag->fr_address + 2; + return md_pcrel_from (fixP); } #ifdef OBJ_COFF int -tc_coff_sizemachdep (frag) - fragS *frag; +tc_coff_sizemachdep (fragS *frag) { return md_relax_table[frag->fr_subtype].rlx_length; } @@ -3754,11 +4025,8 @@ static const struct reloc_map coff_reloc_map[] = but does some minor tweaking. */ void -sh_coff_reloc_mangle (seg, fix, intr, paddr) - segment_info_type *seg; - fixS *fix; - struct internal_reloc *intr; - unsigned int paddr; +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; @@ -3869,9 +4137,7 @@ sh_coff_reloc_mangle (seg, fix, intr, paddr) /* Create a reloc. */ arelent * -tc_gen_reloc (section, fixp) - asection *section ATTRIBUTE_UNUSED; - fixS *fixp; +tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp) { arelent *rel; bfd_reloc_code_real_type r_type; @@ -3881,18 +4147,12 @@ tc_gen_reloc (section, fixp) *rel->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy); rel->address = fixp->fx_frag->fr_address + fixp->fx_where; - if (fixp->fx_subsy - && S_GET_SEGMENT (fixp->fx_subsy) == absolute_section) - { - fixp->fx_addnumber -= S_GET_VALUE (fixp->fx_subsy); - fixp->fx_subsy = 0; - } - r_type = fixp->fx_r_type; if (SWITCH_TABLE (fixp)) { - rel->addend = rel->address - S_GET_VALUE (fixp->fx_subsy); + *rel->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_subsy); + rel->addend = 0; if (r_type == BFD_RELOC_16) r_type = BFD_RELOC_SH_SWITCH16; else if (r_type == BFD_RELOC_8) @@ -3931,7 +4191,11 @@ tc_gen_reloc (section, fixp) rel->addend = 0; rel->howto = bfd_reloc_type_lookup (stdoutput, r_type); - if (rel->howto == NULL || fixp->fx_subsy) +#ifdef OBJ_ELF + if (rel->howto->type == R_SH_IND12W) + rel->addend += fixp->fx_offset - 4; +#endif + if (rel->howto == NULL) { as_bad_where (fixp->fx_file, fixp->fx_line, _("Cannot represent relocation type %s"), @@ -3946,8 +4210,7 @@ tc_gen_reloc (section, fixp) #ifdef OBJ_ELF inline static char * -sh_end_of_match (cont, what) - char *cont, *what; +sh_end_of_match (char *cont, char *what) { int len = strlen (what); @@ -3959,10 +4222,7 @@ sh_end_of_match (cont, what) } int -sh_parse_name (name, exprP, nextcharP) - char const *name; - expressionS *exprP; - char *nextcharP; +sh_parse_name (char const *name, expressionS *exprP, char *nextcharP) { char *next = input_line_pointer; char *next_end; @@ -4014,6 +4274,16 @@ sh_parse_name (name, exprP, nextcharP) reloc_type = BFD_RELOC_32_GOT_PCREL; else if ((next_end = sh_end_of_match (next + 1, "PLT"))) reloc_type = BFD_RELOC_32_PLT_PCREL; + else if ((next_end = sh_end_of_match (next + 1, "TLSGD"))) + reloc_type = BFD_RELOC_SH_TLS_GD_32; + else if ((next_end = sh_end_of_match (next + 1, "TLSLDM"))) + reloc_type = BFD_RELOC_SH_TLS_LD_32; + else if ((next_end = sh_end_of_match (next + 1, "GOTTPOFF"))) + reloc_type = BFD_RELOC_SH_TLS_IE_32; + else if ((next_end = sh_end_of_match (next + 1, "TPOFF"))) + reloc_type = BFD_RELOC_SH_TLS_LE_32; + else if ((next_end = sh_end_of_match (next + 1, "DTPOFF"))) + reloc_type = BFD_RELOC_SH_TLS_LDO_32; else goto no_suffix;