Inductive match_states: state -> state -> Prop :=
| match_states_regular: forall s f sp pc rs m ts tsp trs tm j
(STACKS: match_stacks j s ts sp tsp)
(KEPT: forall id, ref_function f id -> kept id)
(SPINJ: j sp = Some(tsp, 0))
(REGINJ: regset_inject j rs trs)
(MEMINJ: Mem.inject j m tm),
match_states (State s f (Vptr sp Ptrofs.zero) pc rs m)
(State ts f (Vptr tsp Ptrofs.zero) pc trs tm)
| match_states_call: forall s fd args m ts targs tm j
(STACKS: match_stacks j s ts (Mem.nextblock m) (Mem.nextblock tm))
(KEPT: forall id, ref_fundef fd id -> kept id)
(ARGINJ: Val.inject_list j args targs)
(MEMINJ: Mem.inject j m tm),
match_states (Callstate s fd args m)
(Callstate ts fd targs tm)
| match_states_return: forall s res m ts tres tm j
(STACKS: match_stacks j s ts (Mem.nextblock m) (Mem.nextblock tm))
(RESINJ: Val.inject j res tres)
(MEMINJ: Mem.inject j m tm),
match_states (Returnstate s res m)
(Returnstate ts tres tm).

(* Specifications: *)
Lemma external_call_inject:
forall ef vargs m1 t vres m2 f m1' vargs',
meminj_preserves_globals f ->
external_call ef ge vargs m1 t vres m2 ->
Mem.inject f m1 m1' ->
Val.inject_list f vargs vargs' ->
exists f', exists vres', exists m2',
external_call ef tge vargs' m1' t vres' m2'
/\ Val.inject f' vres vres'
/\ Mem.inject f' m2 m2'
/\ Mem.unchanged_on (loc_unmapped f) m1 m2
/\ Mem.unchanged_on (loc_out_of_reach f m1) m1' m2'
/\ inject_incr f f'
/\ inject_separated f f' m1 m1'.
Lemma find_function_inject:
forall j ros rs fd trs,
meminj_preserves_globals j ->
find_function ge ros rs = Some fd ->
match ros with inl r => regset_inject j rs trs | inr id => kept id end ->
find_function tge ros trs = Some fd /\ (forall id, ref_fundef fd id -> kept id).
Lemma eval_builtin_arg_inject:
forall rs sp m j rs' sp' m' a v,
eval_builtin_arg ge (fun r => rs#r) (Vptr sp Ptrofs.zero) m a v ->
j sp = Some(sp', 0) ->
meminj_preserves_globals j ->
regset_inject j rs rs' ->
Mem.inject j m m' ->
(forall id, In id (globals_of_builtin_arg a) -> kept id) ->
exists v',
eval_builtin_arg tge (fun r => rs'#r) (Vptr sp' Ptrofs.zero) m' a v'
/\ Val.inject j v v'.
Lemma eval_builtin_args_inject:
forall rs sp m j rs' sp' m' al vl,
eval_builtin_args ge (fun r => rs#r) (Vptr sp Ptrofs.zero) m al vl ->
j sp = Some(sp', 0) ->
meminj_preserves_globals j ->
regset_inject j rs rs' ->
Mem.inject j m m' ->
(forall id, In id (globals_of_builtin_args al) -> kept id) ->
exists vl',
eval_builtin_args tge (fun r => rs'#r) (Vptr sp' Ptrofs.zero) m' al vl'
/\ Val.inject_list j vl vl'.
Theorem step_simulation:
forall S1 t S2, step ge S1 t S2 ->
forall S1' (MS: match_states S1 S1'),
exists S2', step tge S1' t S2' /\ match_states S2 S2'.