(** Preservation of a global environment by a memory injection *)
Inductive globalenv_preserved {F V: Type} (ge: Genv.t F V) (j: meminj) (bound: block) : Prop :=
| globalenv_preserved_intro
(DOMAIN: forall b, Plt b bound -> j b = Some(b, 0))
(IMAGE: forall b1 b2 delta, j b1 = Some(b2, delta) -> Plt b2 bound -> b1 = b2)
(SYMBOLS: forall id b, Genv.find_symbol ge id = Some b -> Plt b bound)
(FUNCTIONS: forall b fd, Genv.find_funct_ptr ge b = Some fd -> Plt b bound)
(VARINFOS: forall b gv, Genv.find_var_info ge b = Some gv -> Plt b bound).
Program Definition globalenv_inject {F V: Type} (ge: Genv.t F V) (j: meminj) : massert := {|
m_pred := fun m => exists bound, Ple bound (Mem.nextblock m) /\ globalenv_preserved ge j bound;
m_footprint := fun b ofs => False
|}.
Next Obligation.
rename H into bound. exists bound; split; auto. eapply Ple_trans; eauto. eapply Mem.unchanged_on_nextblock; eauto.
Qed.
Next Obligation.
tauto.
Qed.

Lemma external_call_parallel_rule:
forall (F V: Type) ef (ge: Genv.t F V) vargs1 m1 t vres1 m1' m2 j P vargs2,
external_call ef ge vargs1 m1 t vres1 m1' ->
injection_full j m1 ->
m2 |= minjection j m1 ** globalenv_inject ge j ** P ->
Val.inject_list j vargs1 vargs2 ->
exists j' vres2 m2' t',
external_call ef ge vargs2 m2 t' vres2 m2'
/\ Val.inject j' vres1 vres2
/\ m2' |= minjection j' m1' ** globalenv_inject ge j' ** P
/\ inject_incr j j'
/\ inject_separated j j' m1 m2
/\ inject_trace j' t t' /\
injection_full j m1 .