(* *********************************************************************)
(*                                                                     *)
(*              The Compcert verified compiler                         *)
(*                                                                     *)
(*          Xavier Leroy, INRIA Paris-Rocquencourt                     *)
(*                                                                     *)
(*  Copyright Institut National de Recherche en Informatique et en     *)
(*  Automatique.  All rights reserved.  This file is distributed       *)
(*  under the terms of the GNU General Public License as published by  *)
(*  the Free Software Foundation, either version 2 of the License, or  *)
(*  (at your option) any later version.  This file is also distributed *)
(*  under the terms of the INRIA Non-Commercial License Agreement.     *)
(*                                                                     *)
(* *********************************************************************)
(** Global environments are a component of the dynamic semantics of all languages involved in the compiler.  A global environment maps symbol names (names of functions and of global variables) to the corresponding memory addresses.  It also maps memory addresses of functions to the corresponding function descriptions.  Global environments, along with the initial memory state at the beginning of program execution, are built from the program of interest, as follows: - A distinct memory address is assigned to each function of the program. These function addresses use negative numbers to distinguish them from addresses of memory blocks.  The associations of function name to function address and function address to function description are recorded in the global environment. - For each global variable, a memory block is allocated and associated to the name of the variable.  These operations reflect (at a high level of abstraction) what takes place during program linking and program loading in a real operating system. *)
Notation "s #1" := (fst s) (at level 9, format "s '#1'") : pair_scope.
Notation "s #2" := (snd s) (at level 9, format "s '#2'") : pair_scope.
Local Open Scope pair_scope.
Local Open Scope error_monad_scope.
Set Implicit Arguments.
(** Auxiliary function for initialization of global variables. *)
Function store_zeros (m: mem) (b: block) (p: Z) (n: Z) {wf (Zwf 0) n}: option mem :=
if zle n 0 then Some m else
match Mem.store Mint8unsigned m b p Vzero with
| Some m' => store_zeros m' b (p + 1) (n - 1)
| None => None
end.
(* To avoid useless definitions of inductors in extracted code. *)
Local Unset Elimination Schemes.
Local Unset Case Analysis Schemes.
(** * Symbol environments *)
(** Symbol environments are a restricted view of global environments, focusing on symbol names and their associated blocks.  They do not contain mappings from blocks to function or variable definitions. *)
Module Senv.
Record t: Type := mksenv {
(** Operations *)
find_symbol: ident -> option block;
public_symbol: ident -> bool;
invert_symbol: block -> option ident;
block_is_volatile: block -> bool;
nextblock: block;
(** Properties *)
find_symbol_injective:
forall id1 id2 b, find_symbol id1 = Some b -> find_symbol id2 = Some b -> id1 = id2;
invert_find_symbol:
forall id b, invert_symbol b = Some id -> find_symbol id = Some b;
find_invert_symbol:
forall id b, find_symbol id = Some b -> invert_symbol b = Some id;
public_symbol_exists:
forall id, public_symbol id = true -> exists b, find_symbol id = Some b;
find_symbol_below:
forall id b, find_symbol id = Some b -> Plt b nextblock;
block_is_volatile_below:
forall b, block_is_volatile b = true -> Plt b nextblock
}.
Definition symbol_address (ge: t) (id: ident) (ofs: ptrofs) : val :=
match find_symbol ge id with
| Some b => Vptr b ofs
| None => Vundef
end.

(* Specifications: *)
Theorem shift_symbol_address:
forall ge id ofs delta,
symbol_address ge id (Ptrofs.add ofs delta) = Val.offset_ptr (symbol_address ge id ofs) delta.
Theorem shift_symbol_address_32:
forall ge id ofs n,
Archi.ptr64 = false ->
symbol_address ge id (Ptrofs.add ofs (Ptrofs.of_int n)) = Val.add (symbol_address ge id ofs) (Vint n).
Theorem shift_symbol_address_64:
forall ge id ofs n,
Archi.ptr64 = true ->
symbol_address ge id (Ptrofs.add ofs (Ptrofs.of_int64 n)) = Val.addl (symbol_address ge id ofs) (Vlong n).
Theorem shift_symbol_address:
forall ge id ofs delta,
symbol_address ge id (Ptrofs.add ofs delta) = Val.offset_ptr (symbol_address ge id ofs) delta.
Theorem shift_symbol_address_32:
forall ge id ofs n,
Archi.ptr64 = false ->
symbol_address ge id (Ptrofs.add ofs (Ptrofs.of_int n)) = Val.add (symbol_address ge id ofs) (Vint n).
Theorem shift_symbol_address_64:
forall ge id ofs n,
Archi.ptr64 = true ->
symbol_address ge id (Ptrofs.add ofs (Ptrofs.of_int64 n)) = Val.addl (symbol_address ge id ofs) (Vlong n).