📄 tc-arm.c
字号:
#define INST_IMMEDIATE 0x02000000#define OFFSET_REG 0x02000000#define HWOFFSET_IMM 0x00400000#define SHIFT_BY_REG 0x00000010#define PRE_INDEX 0x01000000#define INDEX_UP 0x00800000#define WRITE_BACK 0x00200000#define LDM_TYPE_2_OR_3 0x00400000#define LITERAL_MASK 0xf000f000#define COND_MASK 0xf0000000#define OPCODE_MASK 0xfe1fffff#define DATA_OP_SHIFT 21/* Codes to distinguish the arithmetic instructions. */#define OPCODE_AND 0#define OPCODE_EOR 1#define OPCODE_SUB 2#define OPCODE_RSB 3#define OPCODE_ADD 4#define OPCODE_ADC 5#define OPCODE_SBC 6#define OPCODE_RSC 7#define OPCODE_TST 8#define OPCODE_TEQ 9#define OPCODE_CMP 10#define OPCODE_CMN 11#define OPCODE_ORR 12#define OPCODE_MOV 13#define OPCODE_BIC 14#define OPCODE_MVN 15static void do_t_nop PARAMS ((char *));static void do_t_arit PARAMS ((char *));static void do_t_add PARAMS ((char *));static void do_t_asr PARAMS ((char *));static void do_t_branch9 PARAMS ((char *));static void do_t_branch12 PARAMS ((char *));static void do_t_branch23 PARAMS ((char *));static void do_t_bx PARAMS ((char *));static void do_t_compare PARAMS ((char *));static void do_t_ldmstm PARAMS ((char *));static void do_t_ldr PARAMS ((char *));static void do_t_ldrb PARAMS ((char *));static void do_t_ldrh PARAMS ((char *));static void do_t_lds PARAMS ((char *));static void do_t_lsl PARAMS ((char *));static void do_t_lsr PARAMS ((char *));static void do_t_mov PARAMS ((char *));static void do_t_push_pop PARAMS ((char *));static void do_t_str PARAMS ((char *));static void do_t_strb PARAMS ((char *));static void do_t_strh PARAMS ((char *));static void do_t_sub PARAMS ((char *));static void do_t_swi PARAMS ((char *));static void do_t_adr PARAMS ((char *));#define T_OPCODE_MUL 0x4340#define T_OPCODE_TST 0x4200#define T_OPCODE_CMN 0x42c0#define T_OPCODE_NEG 0x4240#define T_OPCODE_MVN 0x43c0#define T_OPCODE_ADD_R3 0x1800#define T_OPCODE_SUB_R3 0x1a00#define T_OPCODE_ADD_HI 0x4400#define T_OPCODE_ADD_ST 0xb000#define T_OPCODE_SUB_ST 0xb080#define T_OPCODE_ADD_SP 0xa800#define T_OPCODE_ADD_PC 0xa000#define T_OPCODE_ADD_I8 0x3000#define T_OPCODE_SUB_I8 0x3800#define T_OPCODE_ADD_I3 0x1c00#define T_OPCODE_SUB_I3 0x1e00#define T_OPCODE_ASR_R 0x4100#define T_OPCODE_LSL_R 0x4080#define T_OPCODE_LSR_R 0x40c0#define T_OPCODE_ASR_I 0x1000#define T_OPCODE_LSL_I 0x0000#define T_OPCODE_LSR_I 0x0800#define T_OPCODE_MOV_I8 0x2000#define T_OPCODE_CMP_I8 0x2800#define T_OPCODE_CMP_LR 0x4280#define T_OPCODE_MOV_HR 0x4600#define T_OPCODE_CMP_HR 0x4500#define T_OPCODE_LDR_PC 0x4800#define T_OPCODE_LDR_SP 0x9800#define T_OPCODE_STR_SP 0x9000#define T_OPCODE_LDR_IW 0x6800#define T_OPCODE_STR_IW 0x6000#define T_OPCODE_LDR_IH 0x8800#define T_OPCODE_STR_IH 0x8000#define T_OPCODE_LDR_IB 0x7800#define T_OPCODE_STR_IB 0x7000#define T_OPCODE_LDR_RW 0x5800#define T_OPCODE_STR_RW 0x5000#define T_OPCODE_LDR_RH 0x5a00#define T_OPCODE_STR_RH 0x5200#define T_OPCODE_LDR_RB 0x5c00#define T_OPCODE_STR_RB 0x5400#define T_OPCODE_PUSH 0xb400#define T_OPCODE_POP 0xbc00#define T_OPCODE_BRANCH 0xe7festatic int thumb_reg PARAMS ((char ** str, int hi_lo));#define THUMB_SIZE 2 /* Size of thumb instruction. */#define THUMB_REG_LO 0x1#define THUMB_REG_HI 0x2#define THUMB_REG_ANY 0x3#define THUMB_H1 0x0080#define THUMB_H2 0x0040#define THUMB_ASR 0#define THUMB_LSL 1#define THUMB_LSR 2#define THUMB_MOVE 0#define THUMB_COMPARE 1#define THUMB_LOAD 0#define THUMB_STORE 1#define THUMB_PP_PC_LR 0x0100/* These three are used for immediate shifts, do not alter. */#define THUMB_WORD 2#define THUMB_HALFWORD 1#define THUMB_BYTE 0struct thumb_opcode{ /* Basic string to match. */ CONST char * template; /* Basic instruction code. */ unsigned long value; int size; /* Which CPU variants this exists for. */ unsigned long variants; /* Function to call to parse args. */ void (* parms) PARAMS ((char *));};static CONST struct thumb_opcode tinsns[] ={ {"adc", 0x4140, 2, ARM_EXT_THUMB, do_t_arit}, {"add", 0x0000, 2, ARM_EXT_THUMB, do_t_add}, {"and", 0x4000, 2, ARM_EXT_THUMB, do_t_arit}, {"asr", 0x0000, 2, ARM_EXT_THUMB, do_t_asr}, {"b", T_OPCODE_BRANCH, 2, ARM_EXT_THUMB, do_t_branch12}, {"beq", 0xd0fe, 2, ARM_EXT_THUMB, do_t_branch9}, {"bne", 0xd1fe, 2, ARM_EXT_THUMB, do_t_branch9}, {"bcs", 0xd2fe, 2, ARM_EXT_THUMB, do_t_branch9}, {"bhs", 0xd2fe, 2, ARM_EXT_THUMB, do_t_branch9}, {"bcc", 0xd3fe, 2, ARM_EXT_THUMB, do_t_branch9}, {"bul", 0xd3fe, 2, ARM_EXT_THUMB, do_t_branch9}, {"blo", 0xd3fe, 2, ARM_EXT_THUMB, do_t_branch9}, {"bmi", 0xd4fe, 2, ARM_EXT_THUMB, do_t_branch9}, {"bpl", 0xd5fe, 2, ARM_EXT_THUMB, do_t_branch9}, {"bvs", 0xd6fe, 2, ARM_EXT_THUMB, do_t_branch9}, {"bvc", 0xd7fe, 2, ARM_EXT_THUMB, do_t_branch9}, {"bhi", 0xd8fe, 2, ARM_EXT_THUMB, do_t_branch9}, {"bls", 0xd9fe, 2, ARM_EXT_THUMB, do_t_branch9}, {"bge", 0xdafe, 2, ARM_EXT_THUMB, do_t_branch9}, {"blt", 0xdbfe, 2, ARM_EXT_THUMB, do_t_branch9}, {"bgt", 0xdcfe, 2, ARM_EXT_THUMB, do_t_branch9}, {"ble", 0xddfe, 2, ARM_EXT_THUMB, do_t_branch9}, {"bal", 0xdefe, 2, ARM_EXT_THUMB, do_t_branch9}, {"bic", 0x4380, 2, ARM_EXT_THUMB, do_t_arit}, {"bl", 0xf7fffffe, 4, ARM_EXT_THUMB, do_t_branch23}, {"blx", 0, 0, ARM_EXT_V5, do_t_blx}, {"bkpt", 0xbe00, 2, ARM_EXT_V5, do_t_bkpt}, {"bx", 0x4700, 2, ARM_EXT_THUMB, do_t_bx}, {"cmn", T_OPCODE_CMN, 2, ARM_EXT_THUMB, do_t_arit}, {"cmp", 0x0000, 2, ARM_EXT_THUMB, do_t_compare}, {"eor", 0x4040, 2, ARM_EXT_THUMB, do_t_arit}, {"ldmia", 0xc800, 2, ARM_EXT_THUMB, do_t_ldmstm}, {"ldr", 0x0000, 2, ARM_EXT_THUMB, do_t_ldr}, {"ldrb", 0x0000, 2, ARM_EXT_THUMB, do_t_ldrb}, {"ldrh", 0x0000, 2, ARM_EXT_THUMB, do_t_ldrh}, {"ldrsb", 0x5600, 2, ARM_EXT_THUMB, do_t_lds}, {"ldrsh", 0x5e00, 2, ARM_EXT_THUMB, do_t_lds}, {"ldsb", 0x5600, 2, ARM_EXT_THUMB, do_t_lds}, {"ldsh", 0x5e00, 2, ARM_EXT_THUMB, do_t_lds}, {"lsl", 0x0000, 2, ARM_EXT_THUMB, do_t_lsl}, {"lsr", 0x0000, 2, ARM_EXT_THUMB, do_t_lsr}, {"mov", 0x0000, 2, ARM_EXT_THUMB, do_t_mov}, {"mul", T_OPCODE_MUL, 2, ARM_EXT_THUMB, do_t_arit}, {"mvn", T_OPCODE_MVN, 2, ARM_EXT_THUMB, do_t_arit}, {"neg", T_OPCODE_NEG, 2, ARM_EXT_THUMB, do_t_arit}, {"orr", 0x4300, 2, ARM_EXT_THUMB, do_t_arit}, {"pop", 0xbc00, 2, ARM_EXT_THUMB, do_t_push_pop}, {"push", 0xb400, 2, ARM_EXT_THUMB, do_t_push_pop}, {"ror", 0x41c0, 2, ARM_EXT_THUMB, do_t_arit}, {"sbc", 0x4180, 2, ARM_EXT_THUMB, do_t_arit}, {"stmia", 0xc000, 2, ARM_EXT_THUMB, do_t_ldmstm}, {"str", 0x0000, 2, ARM_EXT_THUMB, do_t_str}, {"strb", 0x0000, 2, ARM_EXT_THUMB, do_t_strb}, {"strh", 0x0000, 2, ARM_EXT_THUMB, do_t_strh}, {"swi", 0xdf00, 2, ARM_EXT_THUMB, do_t_swi}, {"sub", 0x0000, 2, ARM_EXT_THUMB, do_t_sub}, {"tst", T_OPCODE_TST, 2, ARM_EXT_THUMB, do_t_arit}, /* Pseudo ops: */ {"adr", 0x0000, 2, ARM_EXT_THUMB, do_t_adr}, {"nop", 0x46C0, 2, ARM_EXT_THUMB, do_t_nop}, /* mov r8,r8 */};struct reg_entry{ CONST char * name; int number;};#define int_register(reg) ((reg) >= 0 && (reg) <= 15)#define cp_register(reg) ((reg) >= 32 && (reg) <= 47)#define fp_register(reg) ((reg) >= 16 && (reg) <= 23)#define REG_PC 15#define REG_LR 14#define REG_SP 13/* These are the standard names. Users can add aliases with .req. */static CONST struct reg_entry reg_table[] ={ /* Processor Register Numbers. */ {"r0", 0}, {"r1", 1}, {"r2", 2}, {"r3", 3}, {"r4", 4}, {"r5", 5}, {"r6", 6}, {"r7", 7}, {"r8", 8}, {"r9", 9}, {"r10", 10}, {"r11", 11}, {"r12", 12}, {"r13", REG_SP},{"r14", REG_LR},{"r15", REG_PC}, /* APCS conventions. */ {"a1", 0}, {"a2", 1}, {"a3", 2}, {"a4", 3}, {"v1", 4}, {"v2", 5}, {"v3", 6}, {"v4", 7}, {"v5", 8}, {"v6", 9}, {"sb", 9}, {"v7", 10}, {"sl", 10}, {"fp", 11}, {"ip", 12}, {"sp", REG_SP},{"lr", REG_LR},{"pc", REG_PC}, /* ATPCS additions to APCS conventions. */ {"wr", 7}, {"v8", 11}, /* FP Registers. */ {"f0", 16}, {"f1", 17}, {"f2", 18}, {"f3", 19}, {"f4", 20}, {"f5", 21}, {"f6", 22}, {"f7", 23}, {"c0", 32}, {"c1", 33}, {"c2", 34}, {"c3", 35}, {"c4", 36}, {"c5", 37}, {"c6", 38}, {"c7", 39}, {"c8", 40}, {"c9", 41}, {"c10", 42}, {"c11", 43}, {"c12", 44}, {"c13", 45}, {"c14", 46}, {"c15", 47}, {"cr0", 32}, {"cr1", 33}, {"cr2", 34}, {"cr3", 35}, {"cr4", 36}, {"cr5", 37}, {"cr6", 38}, {"cr7", 39}, {"cr8", 40}, {"cr9", 41}, {"cr10", 42}, {"cr11", 43}, {"cr12", 44}, {"cr13", 45}, {"cr14", 46}, {"cr15", 47}, /* ATPCS additions to float register names. */ {"s0",16}, {"s1",17}, {"s2",18}, {"s3",19}, {"s4",20}, {"s5",21}, {"s6",22}, {"s7",23}, {"d0",16}, {"d1",17}, {"d2",18}, {"d3",19}, {"d4",20}, {"d5",21}, {"d6",22}, {"d7",23}, /* FIXME: At some point we need to add VFP register names. */ /* Array terminator. */ {NULL, 0}};#define BAD_ARGS _("Bad arguments to instruction")#define BAD_PC _("r15 not allowed here")#define BAD_FLAGS _("Instruction should not have flags")#define BAD_COND _("Instruction is not conditional")#define ERR_NO_ACCUM _("acc0 expected")static struct hash_control * arm_ops_hsh = NULL;static struct hash_control * arm_tops_hsh = NULL;static struct hash_control * arm_cond_hsh = NULL;static struct hash_control * arm_shift_hsh = NULL;static struct hash_control * arm_reg_hsh = NULL;static struct hash_control * arm_psr_hsh = NULL;/* This table describes all the machine specific pseudo-ops the assembler has to support. The fields are: pseudo-op name without dot function to call to execute this pseudo-op Integer arg to pass to the function. */static void s_req PARAMS ((int));static void s_align PARAMS ((int));static void s_bss PARAMS ((int));static void s_even PARAMS ((int));static void s_ltorg PARAMS ((int));static void s_arm PARAMS ((int));static void s_thumb PARAMS ((int));static void s_code PARAMS ((int));static void s_force_thumb PARAMS ((int));static void s_thumb_func PARAMS ((int));static void s_thumb_set PARAMS ((int));static void arm_s_text PARAMS ((int));static void arm_s_data PARAMS ((int));#ifdef OBJ_ELFstatic void arm_s_section PARAMS ((int));static void s_arm_elf_cons PARAMS ((int));#endifstatic int my_get_expression PARAMS ((expressionS *, char **));CONST pseudo_typeS md_pseudo_table[] ={ /* Never called becasue '.req' does not start line. */ { "req", s_req, 0 }, { "bss", s_bss, 0 }, { "align", s_align, 0 }, { "arm", s_arm, 0 }, { "thumb", s_thumb, 0 }, { "code", s_code, 0 }, { "force_thumb", s_force_thumb, 0 }, { "thumb_func", s_thumb_func, 0 }, { "thumb_set", s_thumb_set, 0 }, { "even", s_even, 0 }, { "ltorg", s_ltorg, 0 }, { "pool", s_ltorg, 0 }, /* Allow for the effect of section changes. */ { "text", arm_s_text, 0 }, { "data", arm_s_data, 0 },#ifdef OBJ_ELF { "section", arm_s_section, 0 }, { "section.s", arm_s_section, 0 }, { "sect", arm_s_section, 0 }, { "sect.s", arm_s_section, 0 }, { "word", s_arm_elf_cons, 4 }, { "long", s_arm_elf_cons, 4 }, { "file", dwarf2_directive_file, 0 }, { "loc", dwarf2_directive_loc, 0 },#else { "word", cons, 4},#endif { "extend", float_cons, 'x' }, { "ldouble", float_cons, 'x' }, { "packed", float_cons, 'p' }, { 0, 0, 0 }};/* Stuff needed to resolve the label ambiguity As: ... label: <insn> may differ from: ... label: <insn>*/symbolS * last_label_seen;static int label_is_thumb_function_name = false;/* Literal stuff. */#define MAX_LITERAL_POOL_SIZE 1024typedef struct literalS{ struct expressionS exp; struct arm_it * inst;} literalT;literalT literals[MAX_LITERAL_POOL_SIZE];/* Next free entry in the pool. */int next_literal_pool_place = 0;/* Next literal pool number. */int lit_pool_num = 1;symbolS * current_poolP = NULL;static intadd_to_lit_pool (){ int lit_count = 0; if (current_poolP == NULL) current_poolP = symbol_create (FAKE_LABEL_NAME, undefined_section, (valueT) 0, &zero_address_frag); /* Check if this literal value is already in the pool: */ while (lit_count < next_literal_pool_place) { if (literals[lit_count].exp.X_op == inst.reloc.exp.X_op && inst.reloc.exp.X_op == O_constant && (literals[lit_count].exp.X_add_number == inst.reloc.exp.X_add_number) && literals[lit_count].exp.X_unsigned == inst.reloc.exp.X_unsigned) break; if (literals[lit_count].exp.X_op == inst.reloc.exp.X_op && inst.reloc.exp.X_op == O_symbol && (literals[lit_count].exp.X_add_number == inst.reloc.exp.X_add_number) && (literals[lit_count].exp.X_add_symbol == inst.reloc.exp.X_add_symbol) && (literals[lit_count].exp.X_op_symbol == inst.reloc.exp.X_op_symbol)) break; lit_count++; } if (lit_count == next_literal_pool_place) /* New entry. */ { if (next_literal_pool_place >= MAX_LITERAL_POOL_SIZE) { inst.error = _("Literal Pool Overflow"); return FAIL; } literals[next_literal_pool_place].exp = inst.reloc.exp; lit_count = next_literal_pool_place++; } inst.reloc.exp.X_op = O_symbol; inst.reloc.exp.X_add_number = (lit_count) * 4 - 8; inst.reloc.exp.X_add_symbol = current_poolP; return SUCCESS;}/* Can't use symbol_new here, so have to create a symbol and then at a later date assign it a value. Thats what these functions do. */static voidsymbol_locate (symbolP, name, segment, valu, frag) symbolS * symbolP; CONST char * name; /* It is copied, the caller can modify. */ segT segment; /* Segment identifier (SEG_<something>). */ valueT valu; /* Symbol value. */ fragS * frag; /* Associated fragment. */{ unsigned int name_length; char * preserved_copy_of_name; name_length = strlen (name) + 1; /* +1 for \0. */ obstack_grow (¬es, name, name_length); preserved_copy_of_name = obstack_finish (¬es);#ifdef STRIP_UNDERSCORE
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -