static int i386_intel_simplify (expressionS *e) { const reg_entry *reg = this_operand >= 0 ? i.op[this_operand].regs : NULL; const reg_entry *base = intel_state.base; const reg_entry *index = intel_state.index; int ret; if (!intel_syntax) return 1; switch (e->X_op) { case O_index: if (e->X_add_symbol) { if (!i386_intel_simplify_symbol (e->X_add_symbol) || !i386_intel_check(reg, intel_state.base, intel_state.index)) return 0;; } if (!intel_state.in_offset) ++intel_state.in_bracket; ret = i386_intel_simplify_symbol (e->X_op_symbol); if (!intel_state.in_offset) --intel_state.in_bracket; if (!ret) return 0; if (e->X_add_symbol) e->X_op = O_add; else i386_intel_fold (e, e->X_op_symbol); break; case O_offset: ++intel_state.in_offset; ret = i386_intel_simplify_symbol (e->X_add_symbol); --intel_state.in_offset; if (!ret || !i386_intel_check(reg, base, index)) return 0; i386_intel_fold (e, e->X_add_symbol); return ret; case O_byte_ptr: case O_word_ptr: case O_dword_ptr: case O_fword_ptr: case O_qword_ptr: case O_tbyte_ptr: case O_oword_ptr: case O_xmmword_ptr: case O_ymmword_ptr: case O_near_ptr: case O_far_ptr: if (intel_state.op_modifier == O_absent) intel_state.op_modifier = e->X_op; /* FALLTHROUGH */ case O_short: if (symbol_get_value_expression (e->X_add_symbol)->X_op == O_register) { as_bad (_("invalid use of register")); return 0; } if (!i386_intel_simplify_symbol (e->X_add_symbol)) return 0; i386_intel_fold (e, e->X_add_symbol); break; case O_full_ptr: if (symbol_get_value_expression (e->X_op_symbol)->X_op == O_register) { as_bad (_("invalid use of register")); return 0; } if (!i386_intel_simplify_symbol (e->X_op_symbol) || !i386_intel_check(reg, intel_state.base, intel_state.index)) return 0; if (!intel_state.in_offset) intel_state.seg = e->X_add_symbol; i386_intel_fold (e, e->X_op_symbol); break; case O_register: if (this_operand < 0 || intel_state.in_offset) { as_bad (_("invalid use of register")); return 0; } if (!intel_state.in_bracket) { if (i.op[this_operand].regs) { as_bad (_("invalid use of register")); return 0; } if (i386_regtab[e->X_add_number].reg_type.bitfield.sreg3 && i386_regtab[e->X_add_number].reg_num == RegFlat) { as_bad (_("invalid use of pseudo-register")); return 0; } i.op[this_operand].regs = i386_regtab + e->X_add_number; } else if (!intel_state.base && !intel_state.in_scale) intel_state.base = i386_regtab + e->X_add_number; else if (!intel_state.index) intel_state.index = i386_regtab + e->X_add_number; else { /* esp is invalid as index */ intel_state.index = i386_regtab + REGNAM_EAX + 4; } e->X_op = O_constant; e->X_add_number = 0; return 2; case O_multiply: if (this_operand >= 0 && intel_state.in_bracket) { expressionS *scale = NULL; if (intel_state.index) --scale; if (!intel_state.in_scale++) intel_state.scale_factor = 1; ret = i386_intel_simplify_symbol (e->X_add_symbol); if (ret && !scale && intel_state.index) scale = symbol_get_value_expression (e->X_op_symbol); if (ret) ret = i386_intel_simplify_symbol (e->X_op_symbol); if (ret && !scale && intel_state.index) scale = symbol_get_value_expression (e->X_add_symbol); if (ret && scale && (scale + 1)) { resolve_expression (scale); if (scale->X_op != O_constant || intel_state.index->reg_type.bitfield.reg16) scale->X_add_number = 0; intel_state.scale_factor *= scale->X_add_number; } --intel_state.in_scale; if (!ret) return 0; if (!intel_state.in_scale) switch (intel_state.scale_factor) { case 1: i.log2_scale_factor = 0; break; case 2: i.log2_scale_factor = 1; break; case 4: i.log2_scale_factor = 2; break; case 8: i.log2_scale_factor = 3; break; default: /* esp is invalid as index */ intel_state.index = i386_regtab + REGNAM_EAX + 4; break; } break; } /* FALLTHROUGH */ default: if (e->X_add_symbol && !i386_intel_simplify_symbol (e->X_add_symbol)) return 0; if (e->X_op == O_add || e->X_op == O_subtract) { base = intel_state.base; index = intel_state.index; } if (!i386_intel_check (reg, base, index) || (e->X_op_symbol && !i386_intel_simplify_symbol (e->X_op_symbol)) || !i386_intel_check (reg, e->X_op != O_add ? base : intel_state.base, e->X_op != O_add ? index : intel_state.index)) return 0; break; } if (this_operand >= 0 && e->X_op == O_symbol && !intel_state.in_offset) { segT seg = S_GET_SEGMENT (e->X_add_symbol); if (seg != absolute_section && seg != reg_section && seg != expr_section) intel_state.is_mem |= 2 - !intel_state.in_bracket; } return 1; }
static int i386_intel_simplify (expressionS *e) { const reg_entry *the_reg = (this_operand >= 0 ? i.op[this_operand].regs : NULL); const reg_entry *base = intel_state.base; const reg_entry *state_index = intel_state.index; int ret; if (!intel_syntax) return 1; switch (e->X_op) { case O_index: if (e->X_add_symbol) { if (!i386_intel_simplify_symbol (e->X_add_symbol) || !i386_intel_check(the_reg, intel_state.base, intel_state.index)) return 0; } if (!intel_state.in_offset) ++intel_state.in_bracket; ret = i386_intel_simplify_symbol (e->X_op_symbol); if (!intel_state.in_offset) --intel_state.in_bracket; if (!ret) return 0; if (e->X_add_symbol) e->X_op = O_add; else i386_intel_fold (e, e->X_op_symbol); break; case O_offset: intel_state.has_offset = 1; ++intel_state.in_offset; ret = i386_intel_simplify_symbol (e->X_add_symbol); --intel_state.in_offset; if (!ret || !i386_intel_check(the_reg, base, state_index)) return 0; i386_intel_fold (e, e->X_add_symbol); return ret; case O_byte_ptr: case O_word_ptr: case O_dword_ptr: case O_fword_ptr: case O_qword_ptr: case O_tbyte_ptr: case O_oword_ptr: case O_xmmword_ptr: case O_ymmword_ptr: case O_zmmword_ptr: case O_near_ptr: case O_far_ptr: if (intel_state.op_modifier == O_absent) intel_state.op_modifier = e->X_op; /* FALLTHROUGH */ case O_short: if (symbol_get_value_expression (e->X_add_symbol)->X_op == O_register) { as_bad (_("invalid use of register")); return 0; } if (!i386_intel_simplify_symbol (e->X_add_symbol)) return 0; i386_intel_fold (e, e->X_add_symbol); break; case O_full_ptr: if (symbol_get_value_expression (e->X_op_symbol)->X_op == O_register) { as_bad (_("invalid use of register")); return 0; } if (!i386_intel_simplify_symbol (e->X_op_symbol) || !i386_intel_check(the_reg, intel_state.base, intel_state.index)) return 0; if (!intel_state.in_offset) intel_state.seg = e->X_add_symbol; i386_intel_fold (e, e->X_op_symbol); break; case O_multiply: if (this_operand >= 0 && intel_state.in_bracket) { expressionS *scale = NULL; int has_index = (intel_state.index != NULL); if (!intel_state.in_scale++) intel_state.scale_factor = 1; ret = i386_intel_simplify_symbol (e->X_add_symbol); if (ret && !has_index && intel_state.index) scale = symbol_get_value_expression (e->X_op_symbol); if (ret) ret = i386_intel_simplify_symbol (e->X_op_symbol); if (ret && !scale && !has_index && intel_state.index) scale = symbol_get_value_expression (e->X_add_symbol); if (ret && scale) { resolve_expression (scale); if (scale->X_op != O_constant || intel_state.index->reg_type.bitfield.reg16) scale->X_add_number = 0; intel_state.scale_factor *= scale->X_add_number; } --intel_state.in_scale; if (!ret) return 0; if (!intel_state.in_scale) switch (intel_state.scale_factor) { case 1: i.log2_scale_factor = 0; break; case 2: i.log2_scale_factor = 1; break; case 4: i.log2_scale_factor = 2; break; case 8: i.log2_scale_factor = 3; break; default: /* esp is invalid as index */ intel_state.index = i386_regtab + REGNAM_EAX + ESP_REG_NUM; break; } break; } goto fallthrough; case O_register: ret = i386_intel_simplify_register (e); if (ret == 2) { gas_assert (e->X_add_number < (unsigned short) -1); e->X_md = (unsigned short) e->X_add_number + 1; e->X_op = O_constant; e->X_add_number = 0; } return ret; case O_constant: if (e->X_md) return i386_intel_simplify_register (e); /* FALLTHROUGH */ default: fallthrough: if (e->X_add_symbol && !i386_intel_simplify_symbol (e->X_add_symbol)) return 0; if (e->X_op == O_add || e->X_op == O_subtract) { base = intel_state.base; state_index = intel_state.index; } if (!i386_intel_check (the_reg, base, state_index) || (e->X_op_symbol && !i386_intel_simplify_symbol (e->X_op_symbol)) || !i386_intel_check (the_reg, (e->X_op != O_add ? base : intel_state.base), (e->X_op != O_add ? state_index : intel_state.index))) return 0; break; } if (this_operand >= 0 && e->X_op == O_symbol && !intel_state.in_offset) { segT seg = S_GET_SEGMENT (e->X_add_symbol); if (seg != absolute_section && seg != reg_section && seg != expr_section) intel_state.is_mem |= 2 - !intel_state.in_bracket; } return 1; }