-/* Given a register number BASE, the lowest of a group of registers, update
- regsets IN and OUT with the registers that should be avoided in input
- and output operands respectively when trying to avoid generating a modr/m
- byte for -mmitigate-rop. */
-
-static void
-set_rop_modrm_reg_bits (int base, HARD_REG_SET &in, HARD_REG_SET &out)
-{
- SET_HARD_REG_BIT (out, base);
- SET_HARD_REG_BIT (out, base + 1);
- SET_HARD_REG_BIT (in, base + 2);
- SET_HARD_REG_BIT (in, base + 3);
-}
-
-/* Called if -mmitigate-rop is in effect. Try to rewrite instructions so
- that certain encodings of modr/m bytes do not occur. */
-static void
-ix86_mitigate_rop (void)
-{
- HARD_REG_SET input_risky;
- HARD_REG_SET output_risky;
- HARD_REG_SET inout_risky;
-
- CLEAR_HARD_REG_SET (output_risky);
- CLEAR_HARD_REG_SET (input_risky);
- SET_HARD_REG_BIT (output_risky, AX_REG);
- SET_HARD_REG_BIT (output_risky, CX_REG);
- SET_HARD_REG_BIT (input_risky, BX_REG);
- SET_HARD_REG_BIT (input_risky, DX_REG);
- set_rop_modrm_reg_bits (FIRST_SSE_REG, input_risky, output_risky);
- set_rop_modrm_reg_bits (FIRST_REX_INT_REG, input_risky, output_risky);
- set_rop_modrm_reg_bits (FIRST_REX_SSE_REG, input_risky, output_risky);
- set_rop_modrm_reg_bits (FIRST_EXT_REX_SSE_REG, input_risky, output_risky);
- set_rop_modrm_reg_bits (FIRST_MASK_REG, input_risky, output_risky);
- COPY_HARD_REG_SET (inout_risky, input_risky);
- IOR_HARD_REG_SET (inout_risky, output_risky);
-
- df_note_add_problem ();
- /* Fix up what stack-regs did. */
- df_insn_rescan_all ();
- df_analyze ();
-
- regrename_init (true);
- regrename_analyze (NULL);
-
- auto_vec<du_head_p> cands;
-
- for (rtx_insn *insn = get_insns (); insn; insn = NEXT_INSN (insn))
- {
- if (!NONDEBUG_INSN_P (insn))
- continue;
-
- if (GET_CODE (PATTERN (insn)) == USE
- || GET_CODE (PATTERN (insn)) == CLOBBER)
- continue;
-
- extract_insn (insn);
-
- int opno0, opno1;
- int modrm = ix86_get_modrm_for_rop (insn, recog_data.operand,
- recog_data.n_operands, &opno0,
- &opno1);
-
- if (!ix86_rop_should_change_byte_p (modrm))
- continue;
-
- insn_rr_info *info = &insn_rr[INSN_UID (insn)];
-
- /* This happens when regrename has to fail a block. */
- if (!info->op_info)
- continue;
-
- if (info->op_info[opno0].n_chains != 0)
- {
- gcc_assert (info->op_info[opno0].n_chains == 1);
- du_head_p op0c;
- op0c = regrename_chain_from_id (info->op_info[opno0].heads[0]->id);
- if (op0c->target_data_1 + op0c->target_data_2 == 0
- && !op0c->cannot_rename)
- cands.safe_push (op0c);
-
- op0c->target_data_1++;
- }
- if (info->op_info[opno1].n_chains != 0)
- {
- gcc_assert (info->op_info[opno1].n_chains == 1);
- du_head_p op1c;
- op1c = regrename_chain_from_id (info->op_info[opno1].heads[0]->id);
- if (op1c->target_data_1 + op1c->target_data_2 == 0
- && !op1c->cannot_rename)
- cands.safe_push (op1c);
-
- op1c->target_data_2++;
- }
- }
-
- int i;
- du_head_p head;
- FOR_EACH_VEC_ELT (cands, i, head)
- {
- int old_reg, best_reg;
- HARD_REG_SET unavailable;
-
- CLEAR_HARD_REG_SET (unavailable);
- if (head->target_data_1)
- IOR_HARD_REG_SET (unavailable, output_risky);
- if (head->target_data_2)
- IOR_HARD_REG_SET (unavailable, input_risky);
-
- int n_uses;
- reg_class superclass = regrename_find_superclass (head, &n_uses,
- &unavailable);
- old_reg = head->regno;
- best_reg = find_rename_reg (head, superclass, &unavailable,
- old_reg, false);
- bool ok = regrename_do_replace (head, best_reg);
- gcc_assert (ok);
- if (dump_file)
- fprintf (dump_file, "Chain %d renamed as %s in %s\n", head->id,
- reg_names[best_reg], reg_class_names[superclass]);
-
- }
-
- regrename_finish ();
-
- df_analyze ();
-
- basic_block bb;
- regset_head live;
-
- INIT_REG_SET (&live);
-
- FOR_EACH_BB_FN (bb, cfun)
- {
- rtx_insn *insn;
-
- COPY_REG_SET (&live, DF_LR_OUT (bb));
- df_simulate_initialize_backwards (bb, &live);
-
- FOR_BB_INSNS_REVERSE (bb, insn)
- {
- if (!NONDEBUG_INSN_P (insn))
- continue;
-
- df_simulate_one_insn_backwards (bb, insn, &live);
-
- if (GET_CODE (PATTERN (insn)) == USE
- || GET_CODE (PATTERN (insn)) == CLOBBER)
- continue;
-
- extract_insn (insn);
- constrain_operands_cached (insn, reload_completed);
- int opno0, opno1;
- int modrm = ix86_get_modrm_for_rop (insn, recog_data.operand,
- recog_data.n_operands, &opno0,
- &opno1);
- if (modrm < 0
- || !ix86_rop_should_change_byte_p (modrm)
- || opno0 == opno1)
- continue;
-
- rtx oldreg = recog_data.operand[opno1];
- preprocess_constraints (insn);
- const operand_alternative *alt = which_op_alt ();
-
- int i;
- for (i = 0; i < recog_data.n_operands; i++)
- if (i != opno1
- && alt[i].earlyclobber
- && reg_overlap_mentioned_p (recog_data.operand[i],
- oldreg))
- break;
-
- if (i < recog_data.n_operands)
- continue;
-
- if (dump_file)
- fprintf (dump_file,
- "attempting to fix modrm byte in insn %d:"
- " reg %d class %s", INSN_UID (insn), REGNO (oldreg),
- reg_class_names[alt[opno1].cl]);
-
- HARD_REG_SET unavailable;
- REG_SET_TO_HARD_REG_SET (unavailable, &live);
- SET_HARD_REG_BIT (unavailable, REGNO (oldreg));
- IOR_COMPL_HARD_REG_SET (unavailable, call_used_reg_set);
- IOR_HARD_REG_SET (unavailable, fixed_reg_set);
- IOR_HARD_REG_SET (unavailable, output_risky);
- IOR_COMPL_HARD_REG_SET (unavailable,
- reg_class_contents[alt[opno1].cl]);
-
- for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
- if (!TEST_HARD_REG_BIT (unavailable, i))
- break;
- if (i == FIRST_PSEUDO_REGISTER)
- {
- if (dump_file)
- fprintf (dump_file, ", none available\n");
- continue;
- }
- if (dump_file)
- fprintf (dump_file, " -> %d\n", i);
- rtx newreg = gen_rtx_REG (recog_data.operand_mode[opno1], i);
- validate_change (insn, recog_data.operand_loc[opno1], newreg, false);
- insn = emit_insn_before (gen_move_insn (newreg, oldreg), insn);
- }
- }
-}
-