(** Separation logic assertions describing the stack frame at [sp]. It must contain: - the values of the [Local] stack slots of [ls], as per [contains_locations] - the values of the [Outgoing] stack slots of [ls], as per [contains_locations] - the [parent] pointer representing the back link to the caller's frame - the [retaddr] pointer representing the saved return address - the initial values of the used callee-save registers as given by [ls0], as per [contains_callee_saves].  In addition, we use a nonseparating conjunction to record the fact that we have full access rights on the stack frame, except the part that represents the Linear stack data. *)
Definition frame_contents_1 (j: meminj) (sp: block) (ls ls0: locset) (parent retaddr: val) :=
contains_locations j sp fe.(fe_ofs_local) b.(bound_local) Local ls
** contains_locations j sp fe_ofs_arg b.(bound_outgoing) Outgoing ls
** hasvalue Mptr sp fe.(fe_ofs_link) parent
** hasvalue Mptr sp fe.(fe_ofs_retaddr) retaddr
** contains_callee_saves j sp fe.(fe_ofs_callee_save) b.(used_callee_save) ls0.
Definition frame_contents (j: meminj) (sp: block) (ls ls0: locset) (parent retaddr: val) :=
mconj (frame_contents_1 j sp ls ls0 parent retaddr)
(range sp 0 fe.(fe_stack_data) **
range sp (fe.(fe_stack_data) + b.(bound_stack_data)) fe.(fe_size)).
(** Accessing components of the frame. *)

Lemma frame_get_local:
forall ofs ty j sp ls ls0 parent retaddr m P,
m |= frame_contents j sp ls ls0 parent retaddr ** P ->
slot_within_bounds b Local ofs ty -> slot_valid f Local ofs ty = true ->
exists v,
load_stack m (Vptr sp Ptrofs.zero) ty (Ptrofs.repr (offset_local fe ofs)) = Some v
/\ Val.inject j (ls (S Local ofs ty)) v.