diff mbox

[Ada] Fix elab counter handling when preserving control flow

Message ID 20170425104719.GA53786@adacore.com
State New
Headers show

Commit Message

Arnaud Charlet April 25, 2017, 10:47 a.m. UTC
When control flow preservation is requested, we want to be explicit about the
units elaboration order in a partition, and we want to have in the executable
an object file for all the units involved in the partition.

This requires special processing for units which wouldn't produce any
object code in normal circumstances, e.g. lone specs only defining simple
types and marked with a No_Elaboration_Code pragma.

Our scheme involves two parts:

1) make sure that all the units compiled with
  -fpreserve-control-flow have an elaboration counter, including lone specs
  with pragma No_Elaboration_Code.

2) arrange to have that elaboration counter updated by the binder generated
  code, even though there's no elab subprogram called. This materializes the
  unit elaboration explicitly and introduces a variable reference which will
  drag the unit object file in the link closure.

So far, we were building an elaboration counter entity but were not
advertising it in the ALI information and were not referencing it from the
binder generated code. This change fixes this.

For this set of sources:

In subdir mylib/

library project mylib is

 for Languages use ("Ada");
 for Source_Dirs use (".");

 for Library_Name use Project'Name;
 for Library_Dir use "lib";
 for Library_Kind use "static";

end mylib;

package Types is
  type R is range 1 .. 500;
end;

And one level up:

with "mylib/mylib.gpr";
project p is
end p;

with Types;
procedure P is
  V : Types.R;
  pragma Volatile (V);
begin
  null;
end;

Out of this build command:

gprbuild -f -g -p -Pp.gpr p.adb -cargs -fpreserve-control-flow

We expect b__p.adb to feature something like:

  E04 : Short_Integer; pragma Import (Ada, E04, "types_E");

  procedure adainit
  ...
     E04 := E04 + 1;
  end adainit;

and the final executable to include types.o.

Tested on x86_64-pc-linux-gnu, committed on trunk

2017-04-25  Olivier Hainque  <hainque@adacore.com>

	* bindgen.adb (Gen_Elab_Calls): Also update counter of lone
	specs without elaboration code that have an elaboration counter
	nevertheless, e.g.  when compiled with -fpreserve-control-flow.
	* sem_ch10.adb (Analyze_Compilation_Unit):
	Set_Elaboration_Entity_Required when requested to preserve
	control flow, to ensure the unit elaboration is materialized at
	bind time, resulting in the inclusion of the unit object file
	in the executable closure at link time.
diff mbox

Patch

Index: sem_ch10.adb
===================================================================
--- sem_ch10.adb	(revision 247177)
+++ sem_ch10.adb	(working copy)
@@ -1204,32 +1204,38 @@ 
             --  where the elaboration routine might otherwise be called more
             --  than once.
 
-            --  Case of units which do not require elaboration checks
+            --  They are also needed to ensure explicit visibility from the
+            --  binder generated code of all the units involved in a partition
+            --  when control-flow preservation is requested.
 
-            if
-              --  Pure units do not need checks
+            --  Case of units which do not require an elaboration entity
 
-              Is_Pure (Spec_Id)
+            if not Opt.Suppress_Control_Flow_Optimizations
+              and then
+              ( --  Pure units do not need checks
 
-              --  Preelaborated units do not need checks
+                Is_Pure (Spec_Id)
 
-              or else Is_Preelaborated (Spec_Id)
+                --  Preelaborated units do not need checks
 
-              --  No checks needed if pragma Elaborate_Body present
+                or else Is_Preelaborated (Spec_Id)
 
-              or else Has_Pragma_Elaborate_Body (Spec_Id)
+                --  No checks needed if pragma Elaborate_Body present
 
-              --  No checks needed if unit does not require a body
+                or else Has_Pragma_Elaborate_Body (Spec_Id)
 
-              or else not Unit_Requires_Body (Spec_Id)
+                --  No checks needed if unit does not require a body
 
-              --  No checks needed for predefined files
+                or else not Unit_Requires_Body (Spec_Id)
 
-              or else Is_Predefined_File_Name (Unit_File_Name (Unum))
+                --  No checks needed for predefined files
 
-              --  No checks required if no separate spec
+                or else Is_Predefined_File_Name (Unit_File_Name (Unum))
 
-              or else Acts_As_Spec (N)
+                --  No checks required if no separate spec
+
+                or else Acts_As_Spec (N)
+              )
             then
                --  This is a case where we only need the entity for
                --  checking to prevent multiple elaboration checks.
Index: bindgen.adb
===================================================================
--- bindgen.adb	(revision 247177)
+++ bindgen.adb	(working copy)
@@ -1117,9 +1117,13 @@ 
             then
                --  In the case of a body with a separate spec, where the
                --  separate spec has an elaboration entity defined, this is
-               --  where we increment the elaboration entity if one exists
+               --  where we increment the elaboration entity if one exists.
 
-               if U.Utype = Is_Body
+               --  Likewise for lone specs with an elaboration entity defined
+               --  despite No_Elaboration_Code, e.g. when requested to
+               --  preserve control flow.
+
+               if (U.Utype = Is_Body or else U.Utype = Is_Spec_Only)
                  and then Units.Table (Unum_Spec).Set_Elab_Entity
                  and then not CodePeer_Mode
                then