(** * Memory injections *)
(** A memory injection [f] is a function from addresses to either [None] or [Some] of an address and an offset.  It defines a correspondence between the blocks of two memory states [m1] and [m2]: - if [f b = None], the block [b] of [m1] has no equivalent in [m2]; - if [f b = Some(b', ofs)], the block [b] of [m2] corresponds to a sub-block at offset [ofs] of the block [b'] in [m2].  A memory injection [f] defines a relation [Val.inject] between values that is the identity for integer and float values, and relocates pointer values as prescribed by [f].  (See module [Values].)  Likewise, a memory injection [f] defines a relation between memory states that we now axiomatize. *)
Parameter inject: meminj -> mem -> mem -> Prop.

(* Specifications: *)
Axiom valid_block_inject_1:
forall f m1 m2 b1 b2 delta,
f b1 = Some(b2, delta) ->
inject f m1 m2 ->
valid_block m1 b1.
Axiom valid_block_inject_2:
forall f m1 m2 b1 b2 delta,
f b1 = Some(b2, delta) ->
inject f m1 m2 ->
valid_block m2 b2.
Axiom perm_inject:
forall f m1 m2 b1 b2 delta ofs k p,
f b1 = Some(b2, delta) ->
inject f m1 m2 ->
perm m1 b1 ofs k p -> perm m2 b2 (ofs + delta) k p.
Axiom valid_access_inject:
forall f m1 m2 chunk b1 ofs b2 delta p,
f b1 = Some(b2, delta) ->
inject f m1 m2 ->
valid_access m1 chunk b1 ofs p ->
valid_access m2 chunk b2 (ofs + delta) p.
Axiom valid_pointer_inject:
forall f m1 m2 b1 ofs b2 delta,
f b1 = Some(b2, delta) ->
inject f m1 m2 ->
valid_pointer m1 b1 ofs = true ->
valid_pointer m2 b2 (ofs + delta) = true.
Axiom weak_valid_pointer_inject:
forall f m1 m2 b1 ofs b2 delta,
f b1 = Some(b2, delta) ->
inject f m1 m2 ->
weak_valid_pointer m1 b1 ofs = true ->
weak_valid_pointer m2 b2 (ofs + delta) = true.
Axiom address_inject:
forall f m1 m2 b1 ofs1 b2 delta p,
inject f m1 m2 ->
perm m1 b1 (Ptrofs.unsigned ofs1) Cur p ->
f b1 = Some (b2, delta) ->
Ptrofs.unsigned (Ptrofs.add ofs1 (Ptrofs.repr delta)) = Ptrofs.unsigned ofs1 + delta.
Axiom valid_pointer_inject_no_overflow:
forall f m1 m2 b ofs b' delta,
inject f m1 m2 ->
valid_pointer m1 b (Ptrofs.unsigned ofs) = true ->
f b = Some(b', delta) ->
0 <= Ptrofs.unsigned ofs + Ptrofs.unsigned (Ptrofs.repr delta) <= Ptrofs.max_unsigned.
Axiom weak_valid_pointer_inject_no_overflow:
forall f m1 m2 b ofs b' delta,
inject f m1 m2 ->
weak_valid_pointer m1 b (Ptrofs.unsigned ofs) = true ->
f b = Some(b', delta) ->
0 <= Ptrofs.unsigned ofs + Ptrofs.unsigned (Ptrofs.repr delta) <= Ptrofs.max_unsigned.
Axiom valid_pointer_inject_val:
forall f m1 m2 b ofs b' ofs',
inject f m1 m2 ->
valid_pointer m1 b (Ptrofs.unsigned ofs) = true ->
Val.inject f (Vptr b ofs) (Vptr b' ofs') ->
valid_pointer m2 b' (Ptrofs.unsigned ofs') = true.
Axiom weak_valid_pointer_inject_val:
forall f m1 m2 b ofs b' ofs',
inject f m1 m2 ->
weak_valid_pointer m1 b (Ptrofs.unsigned ofs) = true ->
Val.inject f (Vptr b ofs) (Vptr b' ofs') ->
weak_valid_pointer m2 b' (Ptrofs.unsigned ofs') = true.
Axiom inject_no_overlap:
forall f m1 m2 b1 b2 b1' b2' delta1 delta2 ofs1 ofs2,
inject f m1 m2 ->
b1 <> b2 ->
f b1 = Some (b1', delta1) ->
f b2 = Some (b2', delta2) ->
perm m1 b1 ofs1 Max Nonempty ->
perm m1 b2 ofs2 Max Nonempty ->
b1' <> b2' \/ ofs1 + delta1 <> ofs2 + delta2.
Axiom different_pointers_inject:
forall f m m' b1 ofs1 b2 ofs2 b1' delta1 b2' delta2,
inject f m m' ->
b1 <> b2 ->
valid_pointer m b1 (Ptrofs.unsigned ofs1) = true ->
valid_pointer m b2 (Ptrofs.unsigned ofs2) = true ->
f b1 = Some (b1', delta1) ->
f b2 = Some (b2', delta2) ->
b1' <> b2' \/
Ptrofs.unsigned (Ptrofs.add ofs1 (Ptrofs.repr delta1)) <>
Ptrofs.unsigned (Ptrofs.add ofs2 (Ptrofs.repr delta2)).
Axiom load_inject:
forall f m1 m2 chunk b1 ofs b2 delta v1,
inject f m1 m2 ->
load chunk m1 b1 ofs = Some v1 ->
f b1 = Some (b2, delta) ->
exists v2, load chunk m2 b2 (ofs + delta) = Some v2 /\ Val.inject f v1 v2.
Axiom loadv_inject:
forall f m1 m2 chunk a1 a2 v1,
inject f m1 m2 ->
loadv chunk m1 a1 = Some v1 ->
Val.inject f a1 a2 ->
exists v2, loadv chunk m2 a2 = Some v2 /\ Val.inject f v1 v2.
Axiom loadbytes_inject:
forall f m1 m2 b1 ofs len b2 delta bytes1,
inject f m1 m2 ->
loadbytes m1 b1 ofs len = Some bytes1 ->
f b1 = Some (b2, delta) ->
exists bytes2, loadbytes m2 b2 (ofs + delta) len = Some bytes2
/\ list_forall2 (memval_inject f) bytes1 bytes2.
Axiom store_mapped_inject:
forall f chunk m1 b1 ofs v1 n1 m2 b2 delta v2,
inject f m1 m2 ->
store chunk m1 b1 ofs v1 = Some n1 ->
f b1 = Some (b2, delta) ->
Val.inject f v1 v2 ->
exists n2,
store chunk m2 b2 (ofs + delta) v2 = Some n2
/\ inject f n1 n2.
Axiom store_unmapped_inject:
forall f chunk m1 b1 ofs v1 n1 m2,
inject f m1 m2 ->
store chunk m1 b1 ofs v1 = Some n1 ->
f b1 = None ->
inject f n1 m2.
Axiom store_outside_inject:
forall f m1 m2 chunk b ofs v m2',
inject f m1 m2 ->
(forall b' delta ofs',
f b' = Some(b, delta) ->
perm m1 b' ofs' Cur Readable ->
ofs <= ofs' + delta < ofs + size_chunk chunk -> False) ->
store chunk m2 b ofs v = Some m2' ->
inject f m1 m2'.
Axiom storev_mapped_inject:
forall f chunk m1 a1 v1 n1 m2 a2 v2,
inject f m1 m2 ->
storev chunk m1 a1 v1 = Some n1 ->
Val.inject f a1 a2 ->
Val.inject f v1 v2 ->
exists n2,
storev chunk m2 a2 v2 = Some n2 /\ inject f n1 n2.
Axiom storebytes_mapped_inject:
forall f m1 b1 ofs bytes1 n1 m2 b2 delta bytes2,
inject f m1 m2 ->
storebytes m1 b1 ofs bytes1 = Some n1 ->
f b1 = Some (b2, delta) ->
list_forall2 (memval_inject f) bytes1 bytes2 ->
exists n2,
storebytes m2 b2 (ofs + delta) bytes2 = Some n2
/\ inject f n1 n2.
Axiom storebytes_unmapped_inject:
forall f m1 b1 ofs bytes1 n1 m2,
inject f m1 m2 ->
storebytes m1 b1 ofs bytes1 = Some n1 ->
f b1 = None ->
inject f n1 m2.
Axiom storebytes_outside_inject:
forall f m1 m2 b ofs bytes2 m2',
inject f m1 m2 ->
(forall b' delta ofs',
f b' = Some(b, delta) ->
perm m1 b' ofs' Cur Readable ->
ofs <= ofs' + delta < ofs + Z.of_nat (length bytes2) -> False) ->
storebytes m2 b ofs bytes2 = Some m2' ->
inject f m1 m2'.
Axiom alloc_right_inject:
forall f m1 m2 lo hi b2 m2',
inject f m1 m2 ->
alloc m2 lo hi = (m2', b2) ->
inject f m1 m2'.
Axiom alloc_left_unmapped_inject:
forall f m1 m2 lo hi m1' b1,
inject f m1 m2 ->
alloc m1 lo hi = (m1', b1) ->
exists f',
inject f' m1' m2
/\ inject_incr f f'
/\ f' b1 = None
/\ (forall b, b <> b1 -> f' b = f b).
Axiom valid_block_inject_1:
forall f m1 m2 b1 b2 delta,
f b1 = Some(b2, delta) ->
inject f m1 m2 ->
valid_block m1 b1.
Axiom valid_block_inject_2:
forall f m1 m2 b1 b2 delta,
f b1 = Some(b2, delta) ->
inject f m1 m2 ->
valid_block m2 b2.
Axiom perm_inject:
forall f m1 m2 b1 b2 delta ofs k p,
f b1 = Some(b2, delta) ->
inject f m1 m2 ->
perm m1 b1 ofs k p -> perm m2 b2 (ofs + delta) k p.
Axiom valid_access_inject:
forall f m1 m2 chunk b1 ofs b2 delta p,
f b1 = Some(b2, delta) ->
inject f m1 m2 ->
valid_access m1 chunk b1 ofs p ->
valid_access m2 chunk b2 (ofs + delta) p.
Axiom valid_pointer_inject:
forall f m1 m2 b1 ofs b2 delta,
f b1 = Some(b2, delta) ->
inject f m1 m2 ->
valid_pointer m1 b1 ofs = true ->
valid_pointer m2 b2 (ofs + delta) = true.
Axiom weak_valid_pointer_inject:
forall f m1 m2 b1 ofs b2 delta,
f b1 = Some(b2, delta) ->
inject f m1 m2 ->
weak_valid_pointer m1 b1 ofs = true ->
weak_valid_pointer m2 b2 (ofs + delta) = true.
Axiom address_inject:
forall f m1 m2 b1 ofs1 b2 delta p,
inject f m1 m2 ->
perm m1 b1 (Ptrofs.unsigned ofs1) Cur p ->
f b1 = Some (b2, delta) ->
Ptrofs.unsigned (Ptrofs.add ofs1 (Ptrofs.repr delta)) = Ptrofs.unsigned ofs1 + delta.
Axiom valid_pointer_inject_no_overflow:
forall f m1 m2 b ofs b' delta,
inject f m1 m2 ->
valid_pointer m1 b (Ptrofs.unsigned ofs) = true ->
f b = Some(b', delta) ->
0 <= Ptrofs.unsigned ofs + Ptrofs.unsigned (Ptrofs.repr delta) <= Ptrofs.max_unsigned.
Axiom weak_valid_pointer_inject_no_overflow:
forall f m1 m2 b ofs b' delta,
inject f m1 m2 ->
weak_valid_pointer m1 b (Ptrofs.unsigned ofs) = true ->
f b = Some(b', delta) ->
0 <= Ptrofs.unsigned ofs + Ptrofs.unsigned (Ptrofs.repr delta) <= Ptrofs.max_unsigned.
Axiom valid_pointer_inject_val:
forall f m1 m2 b ofs b' ofs',
inject f m1 m2 ->
valid_pointer m1 b (Ptrofs.unsigned ofs) = true ->
Val.inject f (Vptr b ofs) (Vptr b' ofs') ->
valid_pointer m2 b' (Ptrofs.unsigned ofs') = true.
Axiom weak_valid_pointer_inject_val:
forall f m1 m2 b ofs b' ofs',
inject f m1 m2 ->
weak_valid_pointer m1 b (Ptrofs.unsigned ofs) = true ->
Val.inject f (Vptr b ofs) (Vptr b' ofs') ->
weak_valid_pointer m2 b' (Ptrofs.unsigned ofs') = true.
Axiom inject_no_overlap:
forall f m1 m2 b1 b2 b1' b2' delta1 delta2 ofs1 ofs2,
inject f m1 m2 ->
b1 <> b2 ->
f b1 = Some (b1', delta1) ->
f b2 = Some (b2', delta2) ->
perm m1 b1 ofs1 Max Nonempty ->
perm m1 b2 ofs2 Max Nonempty ->
b1' <> b2' \/ ofs1 + delta1 <> ofs2 + delta2.
Axiom different_pointers_inject:
forall f m m' b1 ofs1 b2 ofs2 b1' delta1 b2' delta2,
inject f m m' ->
b1 <> b2 ->
valid_pointer m b1 (Ptrofs.unsigned ofs1) = true ->
valid_pointer m b2 (Ptrofs.unsigned ofs2) = true ->
f b1 = Some (b1', delta1) ->
f b2 = Some (b2', delta2) ->
b1' <> b2' \/
Ptrofs.unsigned (Ptrofs.add ofs1 (Ptrofs.repr delta1)) <>
Ptrofs.unsigned (Ptrofs.add ofs2 (Ptrofs.repr delta2)).
Axiom load_inject:
forall f m1 m2 chunk b1 ofs b2 delta v1,
inject f m1 m2 ->
load chunk m1 b1 ofs = Some v1 ->
f b1 = Some (b2, delta) ->
exists v2, load chunk m2 b2 (ofs + delta) = Some v2 /\ Val.inject f v1 v2.
Axiom loadv_inject:
forall f m1 m2 chunk a1 a2 v1,
inject f m1 m2 ->
loadv chunk m1 a1 = Some v1 ->
Val.inject f a1 a2 ->
exists v2, loadv chunk m2 a2 = Some v2 /\ Val.inject f v1 v2.
Axiom loadbytes_inject:
forall f m1 m2 b1 ofs len b2 delta bytes1,
inject f m1 m2 ->
loadbytes m1 b1 ofs len = Some bytes1 ->
f b1 = Some (b2, delta) ->
exists bytes2, loadbytes m2 b2 (ofs + delta) len = Some bytes2
/\ list_forall2 (memval_inject f) bytes1 bytes2.
Axiom store_mapped_inject:
forall f chunk m1 b1 ofs v1 n1 m2 b2 delta v2,
inject f m1 m2 ->
store chunk m1 b1 ofs v1 = Some n1 ->
f b1 = Some (b2, delta) ->
Val.inject f v1 v2 ->
exists n2,
store chunk m2 b2 (ofs + delta) v2 = Some n2
/\ inject f n1 n2.
Axiom store_unmapped_inject:
forall f chunk m1 b1 ofs v1 n1 m2,
inject f m1 m2 ->
store chunk m1 b1 ofs v1 = Some n1 ->
f b1 = None ->
inject f n1 m2.
Axiom store_outside_inject:
forall f m1 m2 chunk b ofs v m2',
inject f m1 m2 ->
(forall b' delta ofs',
f b' = Some(b, delta) ->
perm m1 b' ofs' Cur Readable ->
ofs <= ofs' + delta < ofs + size_chunk chunk -> False) ->
store chunk m2 b ofs v = Some m2' ->
inject f m1 m2'.
Axiom storev_mapped_inject:
forall f chunk m1 a1 v1 n1 m2 a2 v2,
inject f m1 m2 ->
storev chunk m1 a1 v1 = Some n1 ->
Val.inject f a1 a2 ->
Val.inject f v1 v2 ->
exists n2,
storev chunk m2 a2 v2 = Some n2 /\ inject f n1 n2.
Axiom storebytes_mapped_inject:
forall f m1 b1 ofs bytes1 n1 m2 b2 delta bytes2,
inject f m1 m2 ->
storebytes m1 b1 ofs bytes1 = Some n1 ->
f b1 = Some (b2, delta) ->
list_forall2 (memval_inject f) bytes1 bytes2 ->
exists n2,
storebytes m2 b2 (ofs + delta) bytes2 = Some n2
/\ inject f n1 n2.
Axiom storebytes_unmapped_inject:
forall f m1 b1 ofs bytes1 n1 m2,
inject f m1 m2 ->
storebytes m1 b1 ofs bytes1 = Some n1 ->
f b1 = None ->
inject f n1 m2.
Axiom storebytes_outside_inject:
forall f m1 m2 b ofs bytes2 m2',
inject f m1 m2 ->
(forall b' delta ofs',
f b' = Some(b, delta) ->
perm m1 b' ofs' Cur Readable ->
ofs <= ofs' + delta < ofs + Z.of_nat (length bytes2) -> False) ->
storebytes m2 b ofs bytes2 = Some m2' ->
inject f m1 m2'.
Axiom alloc_right_inject:
forall f m1 m2 lo hi b2 m2',
inject f m1 m2 ->
alloc m2 lo hi = (m2', b2) ->
inject f m1 m2'.
Axiom alloc_left_unmapped_inject:
forall f m1 m2 lo hi m1' b1,
inject f m1 m2 ->
alloc m1 lo hi = (m1', b1) ->
exists f',
inject f' m1' m2
/\ inject_incr f f'
/\ f' b1 = None
/\ (forall b, b <> b1 -> f' b = f b).