Section INITMEM.
Variable ge: t.
Definition store_init_data (m: mem) (b: block) (p: Z) (id: init_data) : option mem :=
match id with
| Init_int8 n => Mem.store Mint8unsigned m b p (Vint n)
| Init_int16 n => Mem.store Mint16unsigned m b p (Vint n)
| Init_int32 n => Mem.store Mint32 m b p (Vint n)
| Init_int64 n => Mem.store Mint64 m b p (Vlong n)
| Init_float32 n => Mem.store Mfloat32 m b p (Vsingle n)
| Init_float64 n => Mem.store Mfloat64 m b p (Vfloat n)
| Init_addrof symb ofs =>
match find_symbol ge symb with
| None => None
| Some b' => Mem.store Mptr m b p (Vptr b' ofs)
end
| Init_space n => Some m
end.
Fixpoint store_init_data_list (m: mem) (b: block) (p: Z) (idl: list init_data)
{struct idl}: option mem :=
match idl with
| nil => Some m
| id :: idl' =>
match store_init_data m b p id with
| None => None
| Some m' => store_init_data_list m' b (p + init_data_size id) idl'
end
end.
Definition perm_globvar (gv: globvar V) : permission :=
if gv.(gvar_volatile) then Nonempty
else if gv.(gvar_readonly) then Readable
else Writable.
Definition alloc_global (m: mem) (idg: ident * globdef F V): option mem :=
match idg with
| (id, Gfun f) =>
let (m1, b) := Mem.alloc m 0 1 in
Mem.drop_perm m1 b 0 1 Nonempty
| (id, Gvar v) =>
let init := v.(gvar_init) in
let sz := init_data_list_size init in
let (m1, b) := Mem.alloc m 0 sz in
match store_zeros m1 b 0 sz with
| None => None
| Some m2 =>
match store_init_data_list m2 b 0 init with
| None => None
| Some m3 => Mem.drop_perm m3 b 0 sz (perm_globvar v)
end
end
end.
Fixpoint alloc_globals (m: mem) (gl: list (ident * globdef F V))
{struct gl} : option mem :=
match gl with
| nil => Some m
| g :: gl' =>
match alloc_global m g with
| None => None
| Some m' => alloc_globals m' gl'
end
end.
(** Next-block properties *)
Remark store_zeros_nextblock:
forall m b p n m', store_zeros m b p n = Some m' -> Mem.nextblock m' = Mem.nextblock m.
Remark store_init_data_list_nextblock:
forall idl b m p m',
store_init_data_list m b p idl = Some m' ->
Mem.nextblock m' = Mem.nextblock m.
Remark alloc_global_nextblock:
forall g m m',
alloc_global m g = Some m' ->
Mem.nextblock m' = Pos.succ(Mem.nextblock m).
Remark alloc_globals_nextblock:
forall gl m m',
alloc_globals m gl = Some m' ->
Mem.nextblock m' = advance_next gl (Mem.nextblock m).
(** Permissions *)
Remark store_zeros_perm:
forall k prm b' q m b p n m',
store_zeros m b p n = Some m' ->
(Mem.perm m b' q k prm <-> Mem.perm m' b' q k prm).
Remark store_init_data_perm:
forall k prm b' q i b m p m',
store_init_data m b p i = Some m' ->
(Mem.perm m b' q k prm <-> Mem.perm m' b' q k prm).
Remark store_init_data_list_perm:
forall k prm b' q idl b m p m',
store_init_data_list m b p idl = Some m' ->
(Mem.perm m b' q k prm <-> Mem.perm m' b' q k prm).
Remark alloc_global_perm:
forall k prm b' q idg m m',
alloc_global m idg = Some m' ->
Mem.valid_block m b' ->
(Mem.perm m b' q k prm <-> Mem.perm m' b' q k prm).
Remark alloc_globals_perm:
forall k prm b' q gl m m',
alloc_globals m gl = Some m' ->
Mem.valid_block m b' ->
(Mem.perm m b' q k prm <-> Mem.perm m' b' q k prm).
(** Data preservation properties *)
Remark store_zeros_unchanged:
forall (P: block -> Z -> Prop) m b p n m',
store_zeros m b p n = Some m' ->
(forall i, p <= i < p + n -> ~ P b i) ->
Mem.unchanged_on P m m'.
Remark store_init_data_unchanged:
forall (P: block -> Z -> Prop) b i m p m',
store_init_data m b p i = Some m' ->
(forall ofs, p <= ofs < p + init_data_size i -> ~ P b ofs) ->
Mem.unchanged_on P m m'.
Remark store_init_data_list_unchanged:
forall (P: block -> Z -> Prop) b il m p m',
store_init_data_list m b p il = Some m' ->
(forall ofs, p <= ofs -> ~ P b ofs) ->
Mem.unchanged_on P m m'.
(** Properties related to [loadbytes] *)
Definition readbytes_as_zero (m: mem) (b: block) (ofs len: Z) : Prop :=
forall p n,
ofs <= p -> p + Z.of_nat n <= ofs + len ->
Mem.loadbytes m b p (Z.of_nat n) = Some (list_repeat n (Byte Byte.zero)).
Definition bytes_of_init_data (i: init_data): list memval :=
match i with
| Init_int8 n => inj_bytes (encode_int 1%nat (Int.unsigned n))
| Init_int16 n => inj_bytes (encode_int 2%nat (Int.unsigned n))
| Init_int32 n => inj_bytes (encode_int 4%nat (Int.unsigned n))
| Init_int64 n => inj_bytes (encode_int 8%nat (Int64.unsigned n))
| Init_float32 n => inj_bytes (encode_int 4%nat (Int.unsigned (Float32.to_bits n)))
| Init_float64 n => inj_bytes (encode_int 8%nat (Int64.unsigned (Float.to_bits n)))
| Init_space n => list_repeat (Z.to_nat n) (Byte Byte.zero)
| Init_addrof id ofs =>
match find_symbol ge id with
| Some b => inj_value (if Archi.ptr64 then Q64 else Q32) (Vptr b ofs)
| None   => list_repeat (if Archi.ptr64 then 8%nat else 4%nat) Undef
end
end.
Remark init_data_size_addrof:
forall id ofs, init_data_size (Init_addrof id ofs) = size_chunk Mptr.
Fixpoint bytes_of_init_data_list (il: list init_data): list memval :=
match il with
| nil => nil
| i :: il => bytes_of_init_data i ++ bytes_of_init_data_list il
end.
(** Properties related to [load] *)
Definition read_as_zero (m: mem) (b: block) (ofs len: Z) : Prop :=
forall chunk p,
ofs <= p -> p + size_chunk chunk <= ofs + len ->
(align_chunk chunk | p) ->
Mem.load chunk m b p =
Some (match chunk with
| Mint8unsigned | Mint8signed | Mint16unsigned | Mint16signed | Mint32 => Vint Int.zero
| Mint64 => Vlong Int64.zero
| Mfloat32 => Vsingle Float32.zero
| Mfloat64 => Vfloat Float.zero
| Many32 | Many64 => Vundef
end).
Remark read_as_zero_unchanged:
forall (P: block -> Z -> Prop) m b ofs len m',
read_as_zero m b ofs len ->
Mem.unchanged_on P m m' ->
(forall i, ofs <= i < ofs + len -> P b i) ->
read_as_zero m' b ofs len.
Fixpoint load_store_init_data (m: mem) (b: block) (p: Z) (il: list init_data) {struct il} : Prop :=
match il with
| nil => True
| Init_int8 n :: il' =>
Mem.load Mint8unsigned m b p = Some(Vint(Int.zero_ext 8 n))
/\ load_store_init_data m b (p + 1) il'
| Init_int16 n :: il' =>
Mem.load Mint16unsigned m b p = Some(Vint(Int.zero_ext 16 n))
/\ load_store_init_data m b (p + 2) il'
| Init_int32 n :: il' =>
Mem.load Mint32 m b p = Some(Vint n)
/\ load_store_init_data m b (p + 4) il'
| Init_int64 n :: il' =>
Mem.load Mint64 m b p = Some(Vlong n)
/\ load_store_init_data m b (p + 8) il'
| Init_float32 n :: il' =>
Mem.load Mfloat32 m b p = Some(Vsingle n)
/\ load_store_init_data m b (p + 4) il'
| Init_float64 n :: il' =>
Mem.load Mfloat64 m b p = Some(Vfloat n)
/\ load_store_init_data m b (p + 8) il'
| Init_addrof symb ofs :: il' =>
(exists b', find_symbol ge symb = Some b' /\ Mem.load Mptr m b p = Some(Vptr b' ofs))
/\ load_store_init_data m b (p + size_chunk Mptr) il'
| Init_space n :: il' =>
read_as_zero m b p n
/\ load_store_init_data m b (p + Z.max n 0) il'
end.
Remark alloc_global_unchanged:
forall (P: block -> Z -> Prop) m id g m',
alloc_global m (id, g) = Some m' ->
Mem.unchanged_on P m m'.
Remark alloc_globals_unchanged:
forall (P: block -> Z -> Prop) gl m m',
alloc_globals m gl = Some m' ->
Mem.unchanged_on P m m'.
Remark load_store_init_data_invariant:
forall m m' b,
(forall chunk ofs, Mem.load chunk m' b ofs = Mem.load chunk m b ofs) ->
forall il p,
load_store_init_data m b p il -> load_store_init_data m' b p il.
Definition globals_initialized (g: t) (m: mem) :=
forall b gd,
find_def g b = Some gd ->
match gd with
| Gfun f =>
Mem.perm m b 0 Cur Nonempty
/\ (forall ofs k p, Mem.perm m b ofs k p -> ofs = 0 /\ p = Nonempty)
| Gvar v =>
Mem.range_perm m b 0 (init_data_list_size v.(gvar_init)) Cur (perm_globvar v)
/\ (forall ofs k p, Mem.perm m b ofs k p ->
0 <= ofs < init_data_list_size v.(gvar_init) /\ perm_order (perm_globvar v) p)
/\ (v.(gvar_volatile) = false -> load_store_init_data m b 0 v.(gvar_init))
/\ (v.(gvar_volatile) = false -> Mem.loadbytes m b 0 (init_data_list_size v.(gvar_init)) = Some (bytes_of_init_data_list v.(gvar_init)))
end.
End INITMEM.
Definition init_mem (p: program F V) :=
alloc_globals (globalenv p) Mem.empty p.(prog_defs).

Theorem init_mem_characterization:
forall p b gv m,
find_var_info (globalenv p) b = Some gv ->
init_mem p = Some m ->
Mem.range_perm m b 0 (init_data_list_size gv.(gvar_init)) Cur (perm_globvar gv)
/\ (forall ofs k p, Mem.perm m b ofs k p ->
0 <= ofs < init_data_list_size gv.(gvar_init) /\ perm_order (perm_globvar gv) p)
/\ (gv.(gvar_volatile) = false ->
load_store_init_data (globalenv p) m b 0 gv.(gvar_init))
/\ (gv.(gvar_volatile) = false ->
Mem.loadbytes m b 0 (init_data_list_size gv.(gvar_init)) = Some (bytes_of_init_data_list (globalenv p) gv.(gvar_init))).