aboutsummaryrefslogtreecommitdiff
path: root/gas/scfi.c
diff options
context:
space:
mode:
Diffstat (limited to 'gas/scfi.c')
-rw-r--r--gas/scfi.c205
1 files changed, 117 insertions, 88 deletions
diff --git a/gas/scfi.c b/gas/scfi.c
index 744822d..6c59a8e 100644
--- a/gas/scfi.c
+++ b/gas/scfi.c
@@ -223,11 +223,12 @@ scfi_state_restore_reg (scfi_stateS *state, unsigned int reg)
gas_assert (state->regs[reg].state == CFI_ON_STACK);
gas_assert (state->regs[reg].base == REG_CFA);
- state->regs[reg].base = reg;
+ /* PS: the register may still be on stack much after the restore. Reset the
+ SCFI state to CFI_UNDEFINED, however, to indicate that the most updated
+ source of value is register itself from here onwards. */
+ state->regs[reg].base = 0;
state->regs[reg].offset = 0;
- /* PS: the register may still be on stack much after the restore, but the
- SCFI state keeps the state as 'in register'. */
- state->regs[reg].state = CFI_IN_REG;
+ state->regs[reg].state = CFI_UNDEFINED;
}
/* Identify if the given GAS instruction GINSN saves a register
@@ -477,14 +478,29 @@ verify_heuristic_traceable_reg_fp (ginsnS *ginsn, scfi_stateS *state)
{
/* The function uses this variable to issue error to user right away. */
int fp_traceable_p = 0;
- struct ginsn_dst *dst;
+ enum ginsn_type gtype;
struct ginsn_src *src1;
struct ginsn_src *src2;
+ struct ginsn_dst *dst;
+ unsigned int src1_reg;
+ unsigned int dst_reg;
+ enum ginsn_src_type src1_type;
+ enum ginsn_src_type src2_type;
+ enum ginsn_dst_type dst_type;
+
+ gtype = ginsn->type;
src1 = ginsn_get_src1 (ginsn);
src2 = ginsn_get_src2 (ginsn);
dst = ginsn_get_dst (ginsn);
+ src1_reg = ginsn_get_src_reg (src1);
+ dst_reg = ginsn_get_dst_reg (dst);
+
+ src1_type = ginsn_get_src_type (src1);
+ src2_type = ginsn_get_src_type (src2);
+ dst_type = ginsn_get_dst_type (dst);
+
/* Stack manipulation can be done in a variety of ways. A program may
allocate stack statically or may perform dynamic stack allocation in
the prologue.
@@ -497,25 +513,26 @@ verify_heuristic_traceable_reg_fp (ginsnS *ginsn, scfi_stateS *state)
/* Check all applicable instructions with dest REG_FP, when the CFA base
register is REG_FP. */
- if (state->regs[REG_CFA].base == REG_FP && ginsn_get_dst_reg (dst) == REG_FP)
+ if (state->regs[REG_CFA].base == REG_FP
+ && (dst_type == GINSN_DST_REG || dst_type == GINSN_DST_INDIRECT)
+ && dst_reg == REG_FP)
{
/* Excuse the add/sub with imm usage: They are OK. */
- if ((ginsn->type == GINSN_TYPE_ADD || ginsn->type == GINSN_TYPE_SUB)
- && ginsn_get_src_reg (src1) == REG_FP
- && ginsn_get_src_type (src2) == GINSN_SRC_IMM)
+ if ((gtype == GINSN_TYPE_ADD || gtype == GINSN_TYPE_SUB)
+ && src1_type == GINSN_SRC_REG && src1_reg == REG_FP
+ && src2_type == GINSN_SRC_IMM)
fp_traceable_p = 0;
/* REG_FP restore is OK too. */
else if (ginsn->type == GINSN_TYPE_LOAD)
fp_traceable_p = 0;
/* mov's to memory with REG_FP base do not make REG_FP untraceable. */
- else if (ginsn_get_dst_type (dst) == GINSN_DST_INDIRECT
- && (ginsn->type == GINSN_TYPE_MOV
- || ginsn->type == GINSN_TYPE_STORE))
+ else if (dst_type == GINSN_DST_INDIRECT
+ && (gtype == GINSN_TYPE_MOV || gtype == GINSN_TYPE_STORE))
fp_traceable_p = 0;
/* Manipulations of the values possibly on stack are OK too. */
- else if ((ginsn->type == GINSN_TYPE_ADD || ginsn->type == GINSN_TYPE_SUB
- || ginsn->type == GINSN_TYPE_AND)
- && ginsn_get_dst_type (dst) == GINSN_DST_INDIRECT)
+ else if ((gtype == GINSN_TYPE_ADD || gtype == GINSN_TYPE_SUB
+ || gtype == GINSN_TYPE_AND)
+ && dst_type == GINSN_DST_INDIRECT)
fp_traceable_p = 0;
/* All other ginsns with REG_FP as destination make REG_FP not
traceable. */
@@ -537,14 +554,29 @@ verify_heuristic_traceable_stack_manipulation (ginsnS *ginsn,
/* The function uses this variable to issue error to user right away. */
int sp_untraceable_p = 0;
bool possibly_untraceable = false;
+ enum ginsn_type gtype;
struct ginsn_dst *dst;
struct ginsn_src *src1;
struct ginsn_src *src2;
+ unsigned int src1_reg;
+ unsigned int dst_reg;
+ enum ginsn_src_type src1_type;
+ enum ginsn_src_type src2_type;
+ enum ginsn_dst_type dst_type;
+
+ gtype = ginsn->type;
src1 = ginsn_get_src1 (ginsn);
src2 = ginsn_get_src2 (ginsn);
dst = ginsn_get_dst (ginsn);
+ src1_reg = ginsn_get_src_reg (src1);
+ dst_reg = ginsn_get_dst_reg (dst);
+
+ src1_type = ginsn_get_src_type (src1);
+ src2_type = ginsn_get_src_type (src2);
+ dst_type = ginsn_get_dst_type (dst);
+
/* Stack manipulation can be done in a variety of ways. A program may
allocate stack statically in prologue or may need to do dynamic stack
allocation.
@@ -558,31 +590,24 @@ verify_heuristic_traceable_stack_manipulation (ginsnS *ginsn,
amount of stack usage (and hence, the value of rsp) must be known at
all times. */
- if (ginsn->type == GINSN_TYPE_MOV
- && ginsn_get_dst_type (dst) == GINSN_DST_REG
- && ginsn_get_dst_reg (dst) == REG_SP
- && ginsn_get_src_type (src1) == GINSN_SRC_REG
+ if (gtype == GINSN_TYPE_MOV
+ && dst_type == GINSN_DST_REG && dst_reg == REG_SP
/* Exclude mov %rbp, %rsp from this check. */
- && ginsn_get_src_reg (src1) != REG_FP)
+ && src1_type == GINSN_SRC_REG && src1_reg != REG_FP)
{
- /* mov %reg, %rsp. */
/* A previous mov %rsp, %reg must have been seen earlier for this to be
an OK for stack manipulation. */
- if (state->scratch[ginsn_get_src_reg (src1)].base != REG_CFA
- || state->scratch[ginsn_get_src_reg (src1)].state != CFI_IN_REG)
- {
- possibly_untraceable = true;
- }
+ if (state->scratch[src1_reg].base != REG_CFA
+ || state->scratch[src1_reg].state != CFI_IN_REG)
+ possibly_untraceable = true;
}
/* Check add/sub/and insn usage when CFA base register is REG_SP.
Any stack size manipulation, including stack realignment is not allowed
if CFA base register is REG_SP. */
- else if (ginsn_get_dst_type (dst) == GINSN_DST_REG
- && ginsn_get_dst_reg (dst) == REG_SP
- && (((ginsn->type == GINSN_TYPE_ADD || ginsn->type == GINSN_TYPE_SUB)
- && ginsn_get_src_type (src2) != GINSN_SRC_IMM)
- || ginsn->type == GINSN_TYPE_AND
- || ginsn->type == GINSN_TYPE_OTHER))
+ else if (dst_type == GINSN_DST_REG && dst_reg == REG_SP
+ && (((gtype == GINSN_TYPE_ADD || gtype == GINSN_TYPE_SUB)
+ && src2_type != GINSN_SRC_IMM)
+ || gtype == GINSN_TYPE_AND || gtype == GINSN_TYPE_OTHER))
possibly_untraceable = true;
/* If a register save operation is seen when REG_SP is untraceable,
CFI cannot be synthesized for register saves, hence bail out. */
@@ -592,19 +617,15 @@ verify_heuristic_traceable_stack_manipulation (ginsnS *ginsn,
/* If, however, the register save is an REG_FP-based, indirect mov
like: mov reg, disp(%rbp) and CFA base register is REG_BP,
untraceable REG_SP is not a problem. */
- if (ginsn->type == GINSN_TYPE_MOV
- && ginsn_get_dst_type (dst) == GINSN_DST_INDIRECT
- && (ginsn_get_dst_reg (dst) == REG_FP
- && state->regs[REG_CFA].base == REG_FP))
+ if (gtype == GINSN_TYPE_MOV && state->regs[REG_CFA].base == REG_FP
+ && dst_type == GINSN_DST_INDIRECT && dst_reg == REG_FP)
sp_untraceable_p = 0;
}
else if (ginsn_scfi_restore_reg_p (ginsn, state) && !state->traceable_p)
{
- if (ginsn->type == GINSN_TYPE_MOV
- && ginsn_get_dst_type (dst) == GINSN_DST_INDIRECT
- && (ginsn_get_src_reg (src1) == REG_SP
- || (ginsn_get_src_reg (src1) == REG_FP
- && state->regs[REG_CFA].base != REG_FP)))
+ if (gtype == GINSN_TYPE_MOV && dst_type == GINSN_DST_INDIRECT
+ && (src1_reg == REG_SP
+ || (src1_reg == REG_FP && state->regs[REG_CFA].base != REG_FP)))
sp_untraceable_p = 1;
}
@@ -705,6 +726,11 @@ gen_scfi_ops (ginsnS *ginsn, scfi_stateS *state)
struct ginsn_src *src1;
struct ginsn_src *src2;
struct ginsn_dst *dst;
+ unsigned int src1_reg;
+ unsigned int dst_reg;
+ enum ginsn_src_type src1_type;
+ enum ginsn_src_type src2_type;
+ enum ginsn_dst_type dst_type;
if (!ginsn || !state)
ret = 1;
@@ -723,6 +749,13 @@ gen_scfi_ops (ginsnS *ginsn, scfi_stateS *state)
src2 = ginsn_get_src2 (ginsn);
dst = ginsn_get_dst (ginsn);
+ src1_reg = ginsn_get_src_reg (src1);
+ dst_reg = ginsn_get_dst_reg (dst);
+
+ src1_type = ginsn_get_src_type (src1);
+ src2_type = ginsn_get_src_type (src2);
+ dst_type = ginsn_get_dst_type (dst);
+
ret = verify_heuristic_traceable_stack_manipulation (ginsn, state);
if (ret)
return ret;
@@ -731,68 +764,63 @@ gen_scfi_ops (ginsnS *ginsn, scfi_stateS *state)
if (ret)
return ret;
- switch (ginsn->dst.type)
+ switch (dst_type)
{
case GINSN_DST_REG:
switch (ginsn->type)
{
case GINSN_TYPE_MOV:
- if (ginsn_get_src_type (src1) == GINSN_SRC_REG
- && ginsn_get_src_reg (src1) == REG_SP
- && ginsn_get_dst_reg (dst) == REG_FP
+ if (src1_type == GINSN_SRC_REG && src1_reg == REG_SP
+ && dst_type == GINSN_DST_REG && dst_reg == REG_FP
&& state->regs[REG_CFA].base == REG_SP)
{
/* mov %rsp, %rbp. */
- scfi_op_add_def_cfa_reg (state, ginsn, ginsn_get_dst_reg (dst));
+ scfi_op_add_def_cfa_reg (state, ginsn, dst_reg);
}
- else if (ginsn_get_src_type (src1) == GINSN_SRC_REG
- && ginsn_get_src_reg (src1) == REG_FP
- && ginsn_get_dst_reg (dst) == REG_SP
+ else if (src1_type == GINSN_SRC_REG && src1_reg == REG_FP
+ && dst_type == GINSN_DST_REG && dst_reg == REG_SP
&& state->regs[REG_CFA].base == REG_FP)
{
/* mov %rbp, %rsp. */
state->stack_size = -state->regs[REG_FP].offset;
- scfi_op_add_def_cfa_reg (state, ginsn, ginsn_get_dst_reg (dst));
+ scfi_op_add_def_cfa_reg (state, ginsn, dst_reg);
state->traceable_p = true;
}
- else if (ginsn_get_src_type (src1) == GINSN_SRC_INDIRECT
- && (ginsn_get_src_reg (src1) == REG_SP
- || ginsn_get_src_reg (src1) == REG_FP)
- && ginsn_track_reg_p (ginsn_get_dst_reg (dst), GINSN_GEN_SCFI))
+ else if (src1_type == GINSN_SRC_INDIRECT
+ && (src1_reg == REG_SP || src1_reg == REG_FP)
+ && ginsn_track_reg_p (dst_reg, GINSN_GEN_SCFI))
{
/* mov disp(%rsp), reg. */
/* mov disp(%rbp), reg. */
if (verify_heuristic_symmetrical_restore_reg (state, ginsn))
{
- scfi_state_restore_reg (state, ginsn_get_dst_reg (dst));
- scfi_op_add_cfa_restore (ginsn, ginsn_get_dst_reg (dst));
+ scfi_state_restore_reg (state, dst_reg);
+ scfi_op_add_cfa_restore (ginsn, dst_reg);
}
else
as_warn_where (ginsn->file, ginsn->line,
_("SCFI: asymetrical register restore"));
}
- else if (ginsn_get_src_type (src1) == GINSN_SRC_REG
- && ginsn_get_dst_type (dst) == GINSN_DST_REG
- && ginsn_get_src_reg (src1) == REG_SP)
+ else if (src1_type == GINSN_SRC_REG && src1_reg == REG_SP
+ && dst_type == GINSN_DST_REG)
{
/* mov %rsp, %reg. */
/* The value of rsp is taken directly from state->stack_size.
IMP: The workflow in gen_scfi_ops must keep it updated.
PS: Not taking the value from state->scratch[REG_SP] is
intentional. */
- state->scratch[ginsn_get_dst_reg (dst)].base = REG_CFA;
- state->scratch[ginsn_get_dst_reg (dst)].offset = -state->stack_size;
- state->scratch[ginsn_get_dst_reg (dst)].state = CFI_IN_REG;
+ state->scratch[dst_reg].base = REG_CFA;
+ state->scratch[dst_reg].offset = -state->stack_size;
+ state->scratch[dst_reg].state = CFI_IN_REG;
}
- else if (ginsn_get_src_type (src1) == GINSN_SRC_REG
- && ginsn_get_dst_type (dst) == GINSN_DST_REG
- && ginsn_get_dst_reg (dst) == REG_SP)
+ else if (src1_type == GINSN_SRC_REG
+ && dst_type == GINSN_DST_REG && dst_reg == REG_SP)
{
/* mov %reg, %rsp. */
/* Keep the value of REG_SP updated. */
- if (state->scratch[ginsn_get_src_reg (src1)].state == CFI_IN_REG)
+ if (state->scratch[src1_reg].state == CFI_IN_REG)
{
- state->stack_size = -state->scratch[ginsn_get_src_reg (src1)].offset;
+ state->stack_size = -state->scratch[src1_reg].offset;
state->traceable_p = true;
}
# if 0
@@ -804,8 +832,9 @@ gen_scfi_ops (ginsnS *ginsn, scfi_stateS *state)
}
break;
case GINSN_TYPE_SUB:
- if (ginsn_get_src_reg (src1) == REG_SP
- && ginsn_get_dst_reg (dst) == REG_SP)
+ if (src1_type == GINSN_SRC_REG && src1_reg == REG_SP
+ && dst_type == GINSN_DST_REG && dst_reg == REG_SP
+ && src2_type == GINSN_SRC_IMM)
{
/* Stack inc/dec offset, when generated due to stack push and pop is
target-specific. Use the value encoded in the ginsn. */
@@ -818,8 +847,9 @@ gen_scfi_ops (ginsnS *ginsn, scfi_stateS *state)
}
break;
case GINSN_TYPE_ADD:
- if (ginsn_get_src_reg (src1) == REG_SP
- && ginsn_get_dst_reg (dst) == REG_SP)
+ if (src1_type == GINSN_SRC_REG && src1_reg == REG_SP
+ && dst_type == GINSN_DST_REG && dst_reg == REG_SP
+ && src2_type == GINSN_SRC_IMM)
{
/* Stack inc/dec offset is target-specific. Use the value
encoded in the ginsn. */
@@ -831,8 +861,8 @@ gen_scfi_ops (ginsnS *ginsn, scfi_stateS *state)
scfi_op_add_cfa_offset_inc (state, ginsn, ginsn_get_src_imm (src2));
}
}
- else if (ginsn_get_src_reg (src1) == REG_FP
- && ginsn_get_dst_reg (dst) == REG_SP
+ else if (src1_type == GINSN_SRC_REG && src1_reg == REG_FP
+ && dst_type == GINSN_DST_REG && dst_reg == REG_SP
&& state->regs[REG_CFA].base == REG_FP)
{
/* FIXME - what is this for ? */
@@ -841,26 +871,25 @@ gen_scfi_ops (ginsnS *ginsn, scfi_stateS *state)
break;
case GINSN_TYPE_LOAD:
/* If this is a load from stack. */
- if (ginsn_get_src_type (src1) == GINSN_SRC_INDIRECT
- && (ginsn_get_src_reg (src1) == REG_SP
- || (ginsn_get_src_reg (src1) == REG_FP
- && state->regs[REG_CFA].base == REG_FP)))
+ if (src1_type == GINSN_SRC_INDIRECT
+ && ((src1_reg == REG_FP && state->regs[REG_CFA].base == REG_FP)
+ || src1_reg == REG_SP))
+
{
/* pop %rbp when CFA tracking is REG_FP based. */
- if (ginsn_get_dst_reg (dst) == REG_FP
- && state->regs[REG_CFA].base == REG_FP)
+ if (dst_reg == REG_FP && state->regs[REG_CFA].base == REG_FP)
{
scfi_op_add_def_cfa_reg (state, ginsn, REG_SP);
if (state->regs[REG_CFA].offset != state->stack_size)
scfi_op_add_cfa_offset_inc (state, ginsn,
(state->regs[REG_CFA].offset - state->stack_size));
}
- if (ginsn_track_reg_p (ginsn_get_dst_reg (dst), GINSN_GEN_SCFI))
+ if (ginsn_track_reg_p (dst_reg, GINSN_GEN_SCFI))
{
if (verify_heuristic_symmetrical_restore_reg (state, ginsn))
{
- scfi_state_restore_reg (state, ginsn_get_dst_reg (dst));
- scfi_op_add_cfa_restore (ginsn, ginsn_get_dst_reg (dst));
+ scfi_state_restore_reg (state, dst_reg);
+ scfi_op_add_cfa_restore (ginsn, dst_reg);
}
else
as_warn_where (ginsn->file, ginsn->line,
@@ -889,20 +918,20 @@ gen_scfi_ops (ginsnS *ginsn, scfi_stateS *state)
/* mov reg, disp(%rsp) */
if (ginsn_scfi_save_reg_p (ginsn, state))
{
- if (ginsn_get_dst_reg (dst) == REG_SP)
+ if (dst_reg == REG_SP)
{
/* mov reg, disp(%rsp) */
offset = 0 - state->stack_size + ginsn_get_dst_disp (dst);
- scfi_state_save_reg (state, ginsn_get_src_reg (src1), REG_CFA, offset);
- scfi_op_add_cfi_offset (state, ginsn, ginsn_get_src_reg (src1));
+ scfi_state_save_reg (state, src1_reg, REG_CFA, offset);
+ scfi_op_add_cfi_offset (state, ginsn, src1_reg);
}
- else if (ginsn_get_dst_reg (dst) == REG_FP)
+ else if (dst_reg == REG_FP)
{
gas_assert (state->regs[REG_CFA].base == REG_FP);
/* mov reg, disp(%rbp) */
offset = 0 - state->regs[REG_CFA].offset + ginsn_get_dst_disp (dst);
- scfi_state_save_reg (state, ginsn_get_src_reg (src1), REG_CFA, offset);
- scfi_op_add_cfi_offset (state, ginsn, ginsn_get_src_reg (src1));
+ scfi_state_save_reg (state, src1_reg, REG_CFA, offset);
+ scfi_op_add_cfi_offset (state, ginsn, src1_reg);
}
}
break;