Notation val_inject:= Val.inject.
(* A minimal preservation property we sometimes require. *)
(* Definition readonly {F V} (ge: Genv.t F V) m1 b m2 := forall gv, Genv.find_var_info ge b = Some gv -> gvar_readonly gv && negb (gvar_volatile gv) = true -> forall ch ofs, Mem.load ch m2 b ofs = Mem.load ch m1 b ofs. *)
Definition readonlyLD m1 b m2 :=
forall chunk ofs
(NWR: forall ofs', ofs <= ofs' < ofs + size_chunk chunk ->
~(Mem.perm m1 b ofs' Cur Writable)),
Mem.load chunk m2 b ofs = Mem.load chunk m1 b ofs /\
(forall ofs', ofs <= ofs' < ofs + size_chunk chunk ->
(forall k p, Mem.perm m1 b ofs' k p <-> Mem.perm m2 b ofs' k p)).
Definition readonly m1 b m2 :=
forall n ofs
(NWR: forall i, 0 <= i < n ->
~(Mem.perm m1 b (ofs + i) Cur Writable)),
Mem.loadbytes m2 b ofs n = Mem.loadbytes m1 b ofs n /\
(forall i, 0 <= i < n ->
(forall k p, Mem.perm m1 b (ofs+i) k p <-> Mem.perm m2 b (ofs+i) k p)).
Definition max_readonlyLD m1 b m2 :=
forall chunk ofs
(NWR: forall ofs', ofs <= ofs' < ofs + size_chunk chunk ->
~(Mem.perm m1 b ofs' Max Writable)),
Mem.load chunk m2 b ofs = Mem.load chunk m1 b ofs /\
(forall ofs', ofs <= ofs' < ofs + size_chunk chunk ->
(forall k p, Mem.perm m1 b ofs' k p <-> Mem.perm m2 b ofs' k p)).
Definition max_readonly m1 b m2 :=
forall n ofs
(NWR: forall i, 0 <= i < n ->
~(Mem.perm m1 b (ofs + i) Max Writable)),
Mem.loadbytes m2 b ofs n = Mem.loadbytes m1 b ofs n /\
(forall i, 0 <= i < n ->
(forall k p, Mem.perm m1 b (ofs+i) k p <-> Mem.perm m2 b (ofs+i) k p)).
Definition mem_forward (m1 m2:mem) :=
forall b, Mem.valid_block m1 b ->
(Mem.valid_block m2 b
/\ (forall ofs p, Mem.perm m2 b ofs Max p -> Mem.perm m1 b ofs Max p)
(* Lemma store_forward: forall m b ofs v ch m' (M:Mem.store ch m b ofs v = Some m'), mem_forward m m'.  Lemma storebytes_forward: forall m b ofs bytes m' (M: Mem.storebytes m b ofs bytes = Some m'), mem_forward m m'. *)
(* Lemma unchanged_on_sym P m m' b: Mem.unchanged_on P m m' -> Mem.valid_block m b -> Mem.unchanged_on (fun bb z => P bb z /\ bb=b) m' m. *)
Definition genvs_domain_eq {F1 F2 V1 V2: Type}
(ge1: Genv.t F1 V1) (ge2: Genv.t F2 V2) :=
(forall b, fst (genv2blocks ge1) b <-> fst (genv2blocks ge2) b) /\
(forall b, snd (genv2blocks ge1) b <-> snd (genv2blocks ge2) b) /\
(forall b, (exists f, Genv.find_funct_ptr ge1 b = Some f)
<-> (exists f, Genv.find_funct_ptr ge2 b = Some f)).

Lemma meminj_preserves_globals_ind_compose:
forall {F1 V1 F2 V2} (ge1: Genv.t F1 V1) (ge2: Genv.t F2 V2)
j1 j2 (G: genvs_domain_eq ge1 ge2)
(PG1: meminj_preserves_globals_ind (genv2blocks ge1) j1)
(PG2: meminj_preserves_globals_ind (genv2blocks ge2) j2),
meminj_preserves_globals_ind (genv2blocks ge1) (compose_meminj j1 j2).