diff options
Diffstat (limited to 'contrib/binutils/gas/config/tc-sh.c')
-rw-r--r-- | contrib/binutils/gas/config/tc-sh.c | 233 |
1 files changed, 229 insertions, 4 deletions
diff --git a/contrib/binutils/gas/config/tc-sh.c b/contrib/binutils/gas/config/tc-sh.c index 0c0bf4b..eaa6146 100644 --- a/contrib/binutils/gas/config/tc-sh.c +++ b/contrib/binutils/gas/config/tc-sh.c @@ -48,6 +48,7 @@ static void sh_frob_section PARAMS ((bfd *, segT, PTR)); void cons (); void s_align_bytes (); +static void s_uacons PARAMS ((int)); int shl = 0; @@ -70,6 +71,8 @@ const pseudo_typeS md_pseudo_table[] = {"page", listing_eject, 0}, {"program", s_ignore, 0}, {"uses", s_uses, 0}, + {"uaword", s_uacons, 2}, + {"ualong", s_uacons, 4}, {0, 0, 0} }; @@ -77,6 +80,10 @@ const pseudo_typeS md_pseudo_table[] = int sh_relax; /* set if -relax seen */ +/* Whether -small was seen. */ + +int sh_small; + const char EXP_CHARS[] = "eE"; /* Chars that mean this number is a floating point constant */ @@ -259,6 +266,18 @@ parse_reg (src, mode, reg) return 3; } + if (src[0] == 's' && src[1] == 'g' && src[2] == 'r' && ! isalnum (src[3])) + { + *mode = A_SGR; + return 3; + } + + if (src[0] == 'd' && src[1] == 'b' && src[2] == 'r' && ! isalnum (src[3])) + { + *mode = A_DBR; + return 3; + } + if (src[0] == 's' && src[1] == 'r' && ! isalnum (src[2])) { *mode = A_SR; @@ -324,6 +343,61 @@ parse_reg (src, mode, reg) return 3; } } + if (src[0] == 'd' && src[1] == 'r') + { + if (src[2] == '1') + { + if (src[3] >= '0' && src[3] <= '4' && ! ((src[3] - '0') & 1) + && ! isalnum (src[4])) + { + *mode = D_REG_N; + *reg = 10 + src[3] - '0'; + return 4; + } + } + if (src[2] >= '0' && src[2] <= '8' && ! ((src[2] - '0') & 1) + && ! isalnum (src[3])) + { + *mode = D_REG_N; + *reg = (src[2] - '0'); + return 3; + } + } + if (src[0] == 'x' && src[1] == 'd') + { + if (src[2] == '1') + { + if (src[3] >= '0' && src[3] <= '4' && ! ((src[3] - '0') & 1) + && ! isalnum (src[4])) + { + *mode = X_REG_N; + *reg = 11 + src[3] - '0'; + return 4; + } + } + if (src[2] >= '0' && src[2] <= '8' && ! ((src[2] - '0') & 1) + && ! isalnum (src[3])) + { + *mode = X_REG_N; + *reg = (src[2] - '0') + 1; + return 3; + } + } + if (src[0] == 'f' && src[1] == 'v') + { + if (src[2] == '1'&& src[3] == '2' && ! isalnum (src[4])) + { + *mode = V_REG_N; + *reg = 12; + return 4; + } + if ((src[2] == '0' || src[2] == '4' || src[2] == '8') && ! isalnum (src[3])) + { + *mode = V_REG_N; + *reg = (src[2] - '0'); + return 3; + } + } if (src[0] == 'f' && src[1] == 'p' && src[2] == 'u' && src[3] == 'l' && ! isalnum (src[4])) { @@ -338,6 +412,13 @@ parse_reg (src, mode, reg) return 5; } + if (src[0] == 'x' && src[1] == 'm' && src[2] == 't' && src[3] == 'r' + && src[4] == 'x' && ! isalnum (src[5])) + { + *mode = XMTRX_M4; + return 5; + } + return 0; } @@ -662,6 +743,9 @@ get_specific (opcode, operands) case A_IND_R0_REG_N: case A_DISP_REG_N: case F_REG_N: + case D_REG_N: + case X_REG_N: + case V_REG_N: case FPUL_N: case FPSCR_N: /* Opcode needs rn */ @@ -669,11 +753,23 @@ get_specific (opcode, operands) goto fail; reg_n = user->reg; break; + case FD_REG_N: + if (user->type != F_REG_N && user->type != D_REG_N) + goto fail; + reg_n = user->reg; + break; + case DX_REG_N: + if (user->type != D_REG_N && user->type != X_REG_N) + goto fail; + reg_n = user->reg; + break; case A_GBR: case A_SR: case A_VBR: case A_SSR: case A_SPC: + case A_SGR: + case A_DBR: if (user->type != arg) goto fail; break; @@ -697,6 +793,9 @@ get_specific (opcode, operands) break; case F_REG_M: + case D_REG_M: + case X_REG_M: + case V_REG_M: case FPUL_M: case FPSCR_M: /* Opcode needs rn */ @@ -704,6 +803,16 @@ get_specific (opcode, operands) goto fail; reg_m = user->reg; break; + case DX_REG_M: + if (user->type != D_REG_N && user->type != X_REG_N) + goto fail; + reg_m = user->reg; + break; + case XMTRX_M4: + if (user->type != XMTRX_M4) + goto fail; + reg_m = 4; + break; default: printf ("unhandled %d\n", arg); @@ -813,6 +922,9 @@ build_Mytes (opcode, operand) case REG_M: nbuf[index] = reg_m; break; + case REG_NM: + nbuf[index] = reg_n | (reg_m >> 2); + break; case REG_B: nbuf[index] = reg_b | 0x08; break; @@ -1099,10 +1211,12 @@ CONST char *md_shortopts = ""; struct option md_longopts[] = { #define OPTION_RELAX (OPTION_MD_BASE) -#define OPTION_LITTLE (OPTION_MD_BASE+1) +#define OPTION_LITTLE (OPTION_MD_BASE + 1) +#define OPTION_SMALL (OPTION_LITTLE + 1) {"relax", no_argument, NULL, OPTION_RELAX}, {"little", no_argument, NULL, OPTION_LITTLE}, + {"small", no_argument, NULL, OPTION_SMALL}, {NULL, no_argument, NULL, 0} }; size_t md_longopts_size = sizeof(md_longopts); @@ -1117,11 +1231,16 @@ md_parse_option (c, arg) case OPTION_RELAX: sh_relax = 1; break; + case OPTION_LITTLE: shl = 1; target_big_endian = 0; break; + case OPTION_SMALL: + sh_small = 1; + break; + default: return 0; } @@ -1136,7 +1255,8 @@ md_show_usage (stream) fprintf(stream, "\ SH options:\n\ -little generate little endian code\n\ --relax alter jump instructions for long displacements\n"); +-relax alter jump instructions for long displacements\n\ +-small align sections to 4 byte boundaries, not 16\n"); } int md_short_jump_size; @@ -1560,8 +1680,70 @@ DEFUN (md_section_align, (seg, size), #endif /* ! BFD_ASSEMBLER */ } +/* This static variable is set by s_uacons to tell sh_cons_align that + the expession does not need to be aligned. */ + +static int sh_no_align_cons = 0; + +/* This handles the unaligned space allocation pseudo-ops, such as + .uaword. .uaword is just like .word, but the value does not need + to be aligned. */ + +static void +s_uacons (bytes) + int bytes; +{ + /* Tell sh_cons_align not to align this value. */ + sh_no_align_cons = 1; + cons (bytes); +} + +/* If a .word, et. al., pseud-op is seen, warn if the value is not + aligned correctly. Note that this can cause warnings to be issued + when assembling initialized structured which were declared with the + packed attribute. FIXME: Perhaps we should require an option to + enable this warning? */ + +void +sh_cons_align (nbytes) + int nbytes; +{ + int nalign; + char *p; + + if (sh_no_align_cons) + { + /* This is an unaligned pseudo-op. */ + sh_no_align_cons = 0; + return; + } + + nalign = 0; + while ((nbytes & 1) == 0) + { + ++nalign; + nbytes >>= 1; + } + + if (nalign == 0) + return; + + if (now_seg == absolute_section) + { + if ((abs_section_offset & ((1 << nalign) - 1)) != 0) + as_warn ("misaligned data"); + return; + } + + p = frag_var (rs_align_code, 1, 1, (relax_substateT) 0, + (symbolS *) NULL, (offsetT) nalign, (char *) NULL); + + record_alignment (now_seg, nalign); +} + /* When relaxing, we need to output a reloc for any .align directive - that requests alignment to a four byte boundary or larger. */ + that requests alignment to a four byte boundary or larger. This is + also where we check for misaligned data. */ void sh_handle_align (frag) @@ -1574,6 +1756,10 @@ sh_handle_align (frag) && now_seg != bss_section) fix_new (frag, frag->fr_fix, 2, &abs_symbol, frag->fr_offset, 0, BFD_RELOC_SH_ALIGN); + + if (frag->fr_type == rs_align_code + && frag->fr_next->fr_address - frag->fr_address - frag->fr_fix != 0) + as_warn_where (frag->fr_file, frag->fr_line, "misaligned data"); } /* This macro decides whether a particular reloc is an entry in a @@ -1587,6 +1773,7 @@ sh_handle_align (frag) #define SWITCH_TABLE_CONS(fix) \ ((fix)->fx_r_type == 0 \ && ((fix)->fx_size == 2 \ + || (fix)->fx_size == 1 \ || (fix)->fx_size == 4)) #endif @@ -1597,6 +1784,7 @@ sh_handle_align (frag) && 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))) /* See whether we need to force a relocation into the output file. @@ -1639,6 +1827,8 @@ md_apply_fix (fixP, val) #ifdef BFD_ASSEMBLER long val = *valp; #endif + long max, min; + int shift; #ifndef BFD_ASSEMBLER if (fixP->fx_r_type == 0) @@ -1648,36 +1838,53 @@ md_apply_fix (fixP, val) 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_SH_IMM8; + fixP->fx_r_type = BFD_RELOC_8; else abort (); } #endif + max = min = 0; + shift = 0; switch (fixP->fx_r_type) { case BFD_RELOC_SH_IMM4: + max = 0xf; *buf = (*buf & 0xf0) | (val & 0xf); break; case BFD_RELOC_SH_IMM4BY2: + max = 0xf; + shift = 1; *buf = (*buf & 0xf0) | ((val >> 1) & 0xf); break; case BFD_RELOC_SH_IMM4BY4: + max = 0xf; + shift = 2; *buf = (*buf & 0xf0) | ((val >> 2) & 0xf); break; case BFD_RELOC_SH_IMM8BY2: + max = 0xff; + shift = 1; *buf = val >> 1; break; case BFD_RELOC_SH_IMM8BY4: + max = 0xff; + shift = 2; *buf = val >> 2; break; case BFD_RELOC_8: case BFD_RELOC_SH_IMM8: + /* Sometimes the 8 bit value is sign extended (e.g., add) and + sometimes it is not (e.g., and). We permit any 8 bit value. + Note that adding further restrictions may invalidate + reasonable looking assembly code, such as ``and -0x1,r0''. */ + max = 0xff; + min = - 0xff; *buf++ = val; break; @@ -1770,6 +1977,19 @@ md_apply_fix (fixP, val) abort (); } + if (shift != 0) + { + if ((val & ((1 << shift) - 1)) != 0) + as_bad_where (fixP->fx_file, fixP->fx_line, "misaligned offset"); + if (val >= 0) + val >>= shift; + else + val = ((val >> shift) + | ((long) -1 & ~ ((long) -1 >> shift))); + } + if (max != 0 && (val < min || val > max)) + as_bad_where (fixP->fx_file, fixP->fx_line, "offset out of range"); + #ifdef BFD_ASSEMBLER return 0; #endif @@ -1931,6 +2151,7 @@ static const struct reloc_map coff_reloc_map[] = { 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 }, @@ -1977,6 +2198,8 @@ sh_coff_reloc_mangle (seg, fix, intr, paddr) 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 @@ -2077,6 +2300,8 @@ tc_gen_reloc (section, fixp) rel->addend = rel->address - S_GET_VALUE (fixp->fx_subsy); if (r_type == BFD_RELOC_16) r_type = BFD_RELOC_SH_SWITCH16; + else if (r_type == BFD_RELOC_8) + r_type = BFD_RELOC_8_PCREL; else if (r_type == BFD_RELOC_32) r_type = BFD_RELOC_SH_SWITCH32; else |