Module Stacklayout


Machine- and ABI-dependent layout information for activation records.

Require Import Coqlib.
Require Import Bounds.

The general shape of activation records is as follows, from bottom (lowest offsets) to top: The frame_env compilation environment records the positions of the boundaries between these areas of the activation record.

Definition fe_ofs_arg := 0.

Record frame_env : Type := mk_frame_env {
  fe_size: Z;
  fe_ofs_link: Z;
  fe_ofs_retaddr: Z;
  fe_ofs_local: Z;
  fe_ofs_int_callee_save: Z;
  fe_num_int_callee_save: Z;
  fe_ofs_float_callee_save: Z;
  fe_num_float_callee_save: Z;
  fe_stack_data: Z
}.

Computation of the frame environment from the bounds of the current function.

Definition make_env (b: bounds) :=
  let olink := 4 * b.(bound_outgoing) in
  let oics := olink + 4 in
  let ofcs := align (oics + 4 * b.(bound_int_callee_save)) 8 in
  let ol := ofcs + 8 * b.(bound_float_callee_save) in
  let ostkdata := align (ol + 4 * b.(bound_local)) 8 in
  let oretaddr := align (ostkdata + b.(bound_stack_data)) 4 in
  let sz := oretaddr + 4 in
  mk_frame_env sz olink oretaddr
                  ol
                  oics b.(bound_int_callee_save)
                  ofcs b.(bound_float_callee_save)
                  ostkdata.

Separation property

Remark frame_env_separated:
  forall b,
  let fe := make_env b in
  0 <= fe_ofs_arg
  /\ fe_ofs_arg + 4 * b.(bound_outgoing) <= fe.(fe_ofs_link)
  /\ fe.(fe_ofs_link) + 4 <= fe.(fe_ofs_int_callee_save)
  /\ fe.(fe_ofs_int_callee_save) + 4 * b.(bound_int_callee_save) <= fe.(fe_ofs_float_callee_save)
  /\ fe.(fe_ofs_float_callee_save) + 8 * b.(bound_float_callee_save) <= fe.(fe_ofs_local)
  /\ fe.(fe_ofs_local) + 4 * b.(bound_local) <= fe.(fe_stack_data)
  /\ fe.(fe_stack_data) + b.(bound_stack_data) <= fe.(fe_ofs_retaddr)
  /\ fe.(fe_ofs_retaddr) + 4 <= fe.(fe_size).
Proof.
  intros.
  generalize (align_le (fe.(fe_ofs_int_callee_save) + 4 * b.(bound_int_callee_save)) 8 (refl_equal _)).
  generalize (align_le (fe.(fe_ofs_local) + 4 * b.(bound_local)) 8 (refl_equal _)).
  generalize (align_le (fe.(fe_stack_data) + b.(bound_stack_data)) 4 (refl_equal _)).
  unfold fe, make_env, fe_size, fe_ofs_link, fe_ofs_retaddr,
    fe_ofs_local, fe_ofs_int_callee_save, fe_num_int_callee_save,
    fe_ofs_float_callee_save, fe_num_float_callee_save,
    fe_stack_data, fe_ofs_arg.
  intros.
  generalize (bound_local_pos b); intro;
  generalize (bound_int_callee_save_pos b); intro;
  generalize (bound_float_callee_save_pos b); intro;
  generalize (bound_outgoing_pos b); intro;
  generalize (bound_stack_data_pos b); intro.
  omega.
Qed.

Alignment property

Remark frame_env_aligned:
  forall b,
  let fe := make_env b in
  (4 | fe.(fe_ofs_link))
  /\ (4 | fe.(fe_ofs_int_callee_save))
  /\ (8 | fe.(fe_ofs_float_callee_save))
  /\ (8 | fe.(fe_ofs_local))
  /\ (8 | fe.(fe_stack_data))
  /\ (4 | fe.(fe_ofs_retaddr))
  /\ (4 | fe.(fe_size)).
Proof.
  intros.
  unfold fe, make_env, fe_size, fe_ofs_link, fe_ofs_retaddr,
    fe_ofs_local, fe_ofs_int_callee_save,
    fe_num_int_callee_save,
    fe_ofs_float_callee_save, fe_num_float_callee_save,
    fe_stack_data.
  set (x1 := 4 * bound_outgoing b).
  assert (4 | x1). unfold x1; exists (bound_outgoing b); ring.
  set (x2 := x1 + 4).
  assert (4 | x2). unfold x2; apply Zdivide_plus_r; auto. exists 1; auto.
  set (x3 := x2 + 4 * bound_int_callee_save b).
  set (x4 := align x3 8).
  assert (8 | x4). unfold x4. apply align_divides. omega.
  set (x5 := x4 + 8 * bound_float_callee_save b).
  assert (8 | x5). unfold x5; apply Zdivide_plus_r; auto. exists (bound_float_callee_save b); ring.
  set (x6 := align (x5 + 4 * bound_local b) 8).
  assert (8 | x6). unfold x6; apply align_divides; omega.
  set (x7 := align (x6 + bound_stack_data b) 4).
  assert (4 | x7). unfold x7; apply align_divides; omega.
  set (x8 := x7 + 4).
  assert (4 | x8). unfold x8; apply Zdivide_plus_r; auto. exists 1; auto.
  tauto.
Qed.