End LINKER_PROG.
Program Instance Linker_prog (F V: Type) {LF: Linker F} {LV: Linker V} : Linker (program F V) := {
link := link_prog;
linkorder := fun p1 p2 =>
p1.(prog_main) = p2.(prog_main)
/\ incl p1.(prog_public) p2.(prog_public)
/\ forall id gd1,
(prog_defmap p1)!id = Some gd1 ->
exists gd2,
(prog_defmap p2)!id = Some gd2
/\ linkorder gd1 gd2
/\ (~In id p2.(prog_public) -> gd2 = gd1)
}.
Next Obligation.
split; auto. split. apply incl_refl. intros.
exists gd1; split; auto. split; auto. apply linkorder_refl.
Defined.
Next Obligation.
split. congruence. split. red; eauto.
intros. exploit H4; eauto. intros (gd2 & P & Q & R).
exploit H2; eauto. intros (gd3 & U & X & Y).
exists gd3. split; auto. split. eapply linkorder_trans; eauto.
intros. transitivity gd2. apply Y. auto. apply R. red; intros; elim H0; auto.
Defined.
Next Obligation.
apply link_prog_inv in H. destruct H as (L1 & L2 & L3).
subst z; simpl. intuition auto.
+ red; intros; apply in_app_iff; auto.
+ rewrite prog_defmap_elements, PTree.gcombine, H by auto.
destruct (prog_defmap y)!id as [gd2|] eqn:GD2; simpl.
* exploit L2; eauto. intros (P & Q & gd & R).
exists gd; split. auto. split. apply link_linkorder in R; tauto.
rewrite in_app_iff; tauto.
* exists gd1; split; auto. split. apply linkorder_refl. auto.
+ red; intros; apply in_app_iff; auto.
+ rewrite prog_defmap_elements, PTree.gcombine, H by auto.
destruct (prog_defmap x)!id as [gd2|] eqn:GD2; simpl.
* exploit L2; eauto. intros (P & Q & gd & R).
exists gd; split. auto. split. apply link_linkorder in R; tauto.
rewrite in_app_iff; tauto.
* exists gd1; split; auto. split. apply linkorder_refl. auto.
Defined.

(* Specifications: *)
Lemma prog_defmap_linkorder:
forall {F V: Type} {LF: Linker F} {LV: Linker V} (p1 p2: program F V) id gd1,
linkorder p1 p2 ->
(prog_defmap p1)!id = Some gd1 ->
exists gd2, (prog_defmap p2)!id = Some gd2 /\ linkorder gd1 gd2.