📄 tc-sh.c
字号:
name[nlen] = 0; *str_p = op_end; if (nlen == 0) as_bad (_("can't find opcode ")); return (sh_opcode_info *) hash_find (opcode_hash_control, name);}/* Assemble a parallel processing insn. */#define DDT_BASE 0xf000 /* Base value for double data transfer insns */static unsigned intassemble_ppi (op_end, opcode) char *op_end; sh_opcode_info *opcode;{ int movx = 0; int movy = 0; int cond = 0; int field_b = 0; char *output; 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]; if (opcode->arg[0] != A_END) op_end = get_operands (opcode, op_end, operand); opcode = get_specific (opcode, operand); if (opcode == 0) { /* Couldn't find an opcode which matched the operands. */ char *where = frag_more (2); size = 2; where[0] = 0x0; where[1] = 0x0; as_bad (_("invalid operands for opcode")); return size; } if (opcode->nibbles[0] != PPI) as_bad (_("insn can't be combined with parallel processing insn")); switch (opcode->nibbles[1]) { case NOPX: if (movx) as_bad (_("multiple movx specifications")); movx = DDT_BASE; break; case NOPY: if (movy) as_bad (_("multiple movy specifications")); movy = DDT_BASE; break; case MOVX: if (movx) as_bad (_("multiple movx specifications")); if (reg_n < 4 || reg_n > 5) as_bad (_("invalid movx address register")); if (opcode->nibbles[2] & 8) { if (reg_m == A_A1_NUM) movx = 1 << 7; else if (reg_m != A_A0_NUM) as_bad (_("invalid movx dsp register")); } else { if (reg_x > 1) as_bad (_("invalid movx dsp register")); movx = reg_x << 7; } movx += ((reg_n - 4) << 9) + (opcode->nibbles[2] << 2) + DDT_BASE; break; case MOVY: if (movy) as_bad (_("multiple movy specifications")); if (opcode->nibbles[2] & 8) { /* Bit 3 in nibbles[2] is intended for bit 4 of the opcode, so add 8 more. */ movy = 8; if (reg_m == A_A1_NUM) movy += 1 << 6; else if (reg_m != A_A0_NUM) as_bad (_("invalid movy dsp register")); } else { if (reg_y > 1) as_bad (_("invalid movy dsp register")); movy = reg_y << 6; } if (reg_n < 6 || reg_n > 7) as_bad (_("invalid movy address register")); movy += ((reg_n - 6) << 8) + opcode->nibbles[2] + DDT_BASE; break; case PSH: if (operand[0].immediate.X_op != O_constant) as_bad (_("dsp immediate shift value not constant")); field_b = ((opcode->nibbles[2] << 12) | (operand[0].immediate.X_add_number & 127) << 4 | reg_n); break; 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); break; case PDC: if (cond) as_bad (_("multiple condition specifications")); cond = opcode->nibbles[2] << 8; if (*op_end) goto skip_cond_check; break; case PPIC: if (field_b) as_bad (_("multiple parallel processing specifications")); field_b = ((opcode->nibbles[2] << 12) + (opcode->nibbles[3] << 8) + cond + (reg_x << 6) + (reg_y << 4) + reg_n); cond = 0; break; case PMUL: if (field_b) { if ((field_b & 0xef00) != 0xa100) as_bad (_("insn cannot be combined with pmuls")); field_b -= 0x8100; switch (field_b & 0xf) { case A_X0_NUM: field_b += 0 - A_X0_NUM; break; case A_Y0_NUM: field_b += 1 - A_Y0_NUM; break; case A_A0_NUM: field_b += 2 - A_A0_NUM; break; case A_A1_NUM: field_b += 3 - A_A1_NUM; break; default: as_bad (_("bad padd / psub pmuls output operand")); } } field_b += 0x4000 + reg_efg; break; default: abort (); } if (cond) { as_bad (_("condition not followed by conditionalizable insn")); cond = 0; } if (! *op_end) break; skip_cond_check: opcode = find_cooked_opcode (&op_end); if (opcode == NULL) { (as_bad (_("unrecognized characters at end of parallel processing insn"))); break; } } move_code = movx | movy; if (field_b) { /* Parallel processing insn. */ unsigned long ppi_code = (movx | movy | 0xf800) << 16 | field_b; output = frag_more (4); size = 4; if (! target_big_endian) { output[3] = ppi_code >> 8; output[2] = ppi_code; } else { output[2] = ppi_code >> 8; output[3] = ppi_code; } move_code |= 0xf800; } else { /* Just a double data transfer. */ output = frag_more (2); size = 2; } if (! target_big_endian) { output[1] = move_code >> 8; output[0] = move_code; } else { output[0] = move_code >> 8; output[1] = move_code; } return size;}/* This is the guts of the machine-dependent assembler. STR points to a machine dependent instruction. This function is supposed to emit the frags/bytes it assembles to. */voidmd_assemble (str) char *str;{ unsigned char *op_end; sh_operand_info operand[3]; sh_opcode_info *opcode; unsigned int size = 0; opcode = find_cooked_opcode (&str); op_end = str; if (opcode == NULL) { as_bad (_("unknown opcode")); return; } if (sh_relax && ! seg_info (now_seg)->tc_segment_info_data.in_code) { /* Output a CODE reloc to tell the linker that the following bytes are instructions, not data. */ fix_new (frag_now, frag_now_fix (), 2, &abs_symbol, 0, 0, BFD_RELOC_SH_CODE); seg_info (now_seg)->tc_segment_info_data.in_code = 1; } if (opcode->nibbles[0] == PPI) { size = assemble_ppi (op_end, opcode); } else { if (opcode->arg[0] == A_BDISP12 || opcode->arg[0] == A_BDISP8) { parse_exp (op_end + 1, &operand[0]); build_relax (opcode, &operand[0]); } else { if (opcode->arg[0] == A_END) { /* Ignore trailing whitespace. If there is any, it has already been compressed to a single space. */ if (*op_end == ' ') op_end++; } else { op_end = get_operands (opcode, op_end, operand); } opcode = get_specific (opcode, operand); if (opcode == 0) { /* Couldn't find an opcode which matched the operands. */ char *where = frag_more (2); size = 2; where[0] = 0x0; where[1] = 0x0; as_bad (_("invalid operands for opcode")); } else { if (*op_end) as_bad (_("excess operands: '%s'"), op_end); size = build_Mytes (opcode, operand); } } }#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. */voidsh_frob_label (){ static fragS *last_label_frag; static int last_label_offset; if (sh_relax && seg_info (now_seg)->tc_segment_info_data.in_code) { int offset; offset = frag_now_fix (); if (frag_now != last_label_frag || offset != last_label_offset) { fix_new (frag_now, offset, 2, &abs_symbol, 0, 0, BFD_RELOC_SH_LABEL); last_label_frag = frag_now; last_label_offset = offset; } }}/* This routine is called when the assembler is about to output some data. It emits a BFD_RELOC_SH_DATA reloc if necessary. */voidsh_flush_pending_output (){ if (sh_relax && seg_info (now_seg)->tc_segment_info_data.in_code) { fix_new (frag_now, frag_now_fix (), 2, &abs_symbol, 0, 0, BFD_RELOC_SH_DATA); seg_info (now_seg)->tc_segment_info_data.in_code = 0; }}symbolS *md_undefined_symbol (name) char *name;{#ifdef OBJ_ELF /* Under ELF we need to default _GLOBAL_OFFSET_TABLE. Otherwise we have no need to default values of symbols. */ if (strcmp (name, GLOBAL_OFFSET_TABLE_NAME) == 0) { if (!GOT_symbol) { if (symbol_find (name)) as_bad ("GOT already in the symbol table"); GOT_symbol = symbol_new (name, undefined_section, (valueT)0, & zero_address_frag); } return GOT_symbol; }#endif /* OBJ_ELF */ return 0;}#ifdef OBJ_COFF#ifndef BFD_ASSEMBLERvoidtc_crawl_symbol_chain (headers) object_headers *headers;{ printf (_("call to tc_crawl_symbol_chain \n"));}voidtc_headers_hook (headers) object_headers *headers;{ 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/* Turn a string in input_line_pointer into a floating point constant of type TYPE, and store the appropriate bytes in *LITP. The number of LITTLENUMS emitted is stored in *SIZEP . An error message is returned, or NULL on OK. */char *md_atof (type, litP, sizeP) int type; char *litP; int *sizeP;{ int prec; LITTLENUM_TYPE words[4]; char *t; int i; switch (type) { case 'f': prec = 2; break; case 'd': prec = 4; break; default: *sizeP = 0; return _("bad call to md_atof"); } t = atof_ieee (input_line_pointer, type, words); if (t) input_line_pointer = t; *sizeP = prec * 2; if (! target_big_endian) { for (i = prec - 1; i >= 0; i--) { md_number_to_chars (litP, (valueT) words[i], 2); litP += 2; } } else { for (i = 0; i < prec; i++) { md_number_to_chars (litP, (valueT) words[i], 2); litP += 2; } } return NULL;}/* Handle the .uses pseudo-op. This pseudo-op is used just before a call instruction. It refers to a label of the instruction which loads the register which the call uses. We use it to generate a special reloc for the linker. */static voids_uses (ignore) int ignore ATTRIBUTE_UNUSED;{ expressionS ex; if (! sh_relax) as_warn (_(".uses pseudo-op seen when not relaxing")); expression (&ex); if (ex.X_op != O_symbol || ex.X_add_number != 0) { as_bad (_("bad .uses format")); ignore_rest_of_line (); return; } fix_new_exp (frag_now, frag_now_fix (), 2, &ex, 1, BFD_RELOC_SH_USES); demand_empty_rest_of_line ();}CONST char *md_shortopts = "";struct option md_longopts[] ={#define OPTION_RELAX (OPTION_MD_BASE)#define OPTION_LITTLE (OPTION_MD_BASE + 1)#define OPTION_SMALL (OPTION_LITTLE + 1)#define OPTION_DSP (OPTION_SMALL + 1) {"relax", no_argument, NULL, OPTION_RELAX}, {"little", no_argument, NULL, OPTION_LITTLE}, {"small", no_argument, NULL, OPTION_SMALL}, {"dsp", no_argument, NULL, OPTION_DSP}, {NULL, no_argument, NULL, 0}};size_t md_longopts_size = sizeof (md_longopts);intmd_parse_option (c, arg) int c; char *arg ATTRIBUTE_UNUSED;{ switch (c) { case OPTION_RELAX: sh_relax = 1; break; case OPTION_LITTLE: shl = 1; target_big_endian = 0; break; case OPTION_SMALL: sh_small = 1; break; case OPTION_DSP: sh_dsp = 1; break; default: return 0; } return 1;}voidmd_show_usage (stream) FILE *stream;{ fprintf (stream, _("\SH options:\n\-little generate little 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"));}voidtc_Nout_fix_to_chars (){ printf (_("call to tc_Nout_fix_to_chars \n")); abort ();}/* This struct is used to pass arguments to sh_count_relocs through bfd_map_over_sections. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -