view gcc/ada/vxlink-bind.adb @ 131:84e7813d76e9

gcc-8.2
author mir3636
date Thu, 25 Oct 2018 07:37:49 +0900
parents
children
line wrap: on
line source

------------------------------------------------------------------------------
--                                                                          --
--                         GNAT COMPILER COMPONENTS                         --
--                                                                          --
--                          V X L I N K . B I N D                           --
--                                                                          --
--                                 B o d y                                  --
--                                                                          --
--                     Copyright (C) 2018, AdaCore                          --
--                                                                          --
-- GNAT is free software;  you can  redistribute it  and/or modify it under --
-- terms of the  GNU General Public License as published  by the Free Soft- --
-- ware  Foundation;  either version 3,  or (at your option) any later ver- --
-- sion.  GNAT is distributed in the hope that it will be useful, but WITH- --
-- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
-- or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License --
-- for  more details.  You should have  received  a copy of the GNU General --
-- Public License  distributed with GNAT; see file COPYING3.  If not, go to --
-- http://www.gnu.org/licenses for a complete copy of the license.          --
--                                                                          --
-- GNAT was originally developed  by the GNAT team at  New York University. --
-- Extensive contributions were provided by Ada Core Technologies Inc.      --
--                                                                          --
------------------------------------------------------------------------------

pragma Ada_2012;

with Ada.Text_IO;       use Ada.Text_IO;
with Ada.IO_Exceptions;
with Ada.Strings.Fixed;

with GNAT.Regpat;       use GNAT.Regpat;

package body VxLink.Bind is

   function Split_Lines (S : String) return Strings_List.Vector;

   function Split (S : String; C : Character) return Strings_List.Vector;

   function Parse_Nm_Output (S : String) return Symbol_Sets.Set;

   procedure Emit_Module_Dtor
     (FP : File_Type);

   procedure Emit_CDtor
     (FP  : File_Type;
      Var : String;
      Set : Symbol_Sets.Set);

   -----------------
   -- Split_Lines --
   -----------------

   function Split_Lines (S : String) return Strings_List.Vector
   is
      Last : Natural := S'First;
      Ret  : Strings_List.Vector;
   begin
      for J in S'Range loop
         if S (J) = ASCII.CR
           and then J < S'Last
           and then S (J + 1) = ASCII.LF
         then
            Ret.Append (S (Last .. J - 1));
            Last := J + 2;
         elsif S (J) = ASCII.LF then
            Ret.Append (S (Last .. J - 1));
            Last := J + 1;
         end if;
      end loop;

      if Last <= S'Last then
         Ret.Append (S (Last .. S'Last));
      end if;

      return Ret;
   end Split_Lines;

   -----------
   -- Split --
   -----------

   function Split (S : String; C : Character) return Strings_List.Vector
   is
      Last : Natural := S'First;
      Ret  : Strings_List.Vector;
   begin
      for J in S'Range loop
         if S (J) = C then
            if J > Last then
               Ret.Append (S (Last .. J - 1));
            end if;

            Last := J + 1;
         end if;
      end loop;

      if Last <= S'Last then
         Ret.Append (S (Last .. S'Last));
      end if;

      return Ret;
   end Split;

   ---------------------
   -- Parse_Nm_Output --
   ---------------------

   function Parse_Nm_Output (S : String) return Symbol_Sets.Set
   is
      Nm_Regexp        : constant Pattern_Matcher :=
                           Compile ("^[0-9A-Za-z]* ([a-zA-Z]) (.*)$");
      type CDTor_Type is
        (CTOR_Diab,
         CTOR_Gcc,
         DTOR_Diab,
         DTOR_Gcc);
      subtype CTOR_Type is CDTor_Type range CTOR_Diab .. CTOR_Gcc;
      CTOR_DIAB_Regexp : aliased constant Pattern_Matcher :=
                           Compile ("^__?STI__*([0-9]+)_");
      CTOR_GCC_Regexp  : aliased constant Pattern_Matcher :=
                           Compile ("^__?GLOBAL_.I._*([0-9]+)_");
      DTOR_DIAB_Regexp : aliased constant Pattern_Matcher :=
                           Compile ("^__?STD__*([0-9]+)_");
      DTOR_GCC_Regexp  : aliased constant Pattern_Matcher :=
                           Compile ("^__?GLOBAL_.D._*([0-9]+)_");
      type Regexp_Access is access constant Pattern_Matcher;
      CDTor_Regexps    : constant array (CDTor_Type) of Regexp_Access :=
                           (CTOR_Diab => CTOR_DIAB_Regexp'Access,
                            CTOR_Gcc  => CTOR_GCC_Regexp'Access,
                            DTOR_Diab => DTOR_DIAB_Regexp'Access,
                            DTOR_Gcc  => DTOR_GCC_Regexp'Access);
      Result           : Symbol_Sets.Set;

   begin
      for Line of Split_Lines (S) loop
         declare
            Sym     : Symbol;
            Nm_Grps : Match_Array (0 .. 2);
            Ctor_Grps : Match_Array (0 .. 1);
         begin
            Match (Nm_Regexp, Line, Nm_Grps);

            if Nm_Grps (0) /= No_Match then
               declare
                  Sym_Type : constant Character :=
                               Line (Nm_Grps (1).First);
                  Sym_Name : constant String :=
                               Line (Nm_Grps (2).First .. Nm_Grps (2).Last);
               begin
                  Sym :=
                    (Name     => To_Unbounded_String (Sym_Name),
                     Cat      => Sym_Type,
                     Internal => False,
                     Kind     => Sym_Other,
                     Priority => -1);

                  for J in CDTor_Regexps'Range loop
                     Match (CDTor_Regexps (J).all, Sym_Name, Ctor_Grps);

                     if Ctor_Grps (0) /= No_Match then
                        if J in CTOR_Type then
                           Sym.Kind := Sym_Ctor;
                        else
                           Sym.Kind := Sym_Dtor;
                        end if;

                        Sym.Priority := Integer'Value
                          (Line (Ctor_Grps (1).First .. Ctor_Grps (1).Last));

                        exit;
                     end if;
                  end loop;

                  Result.Include (Sym);
               end;
            end if;
         end;
      end loop;

      return Result;
   end Parse_Nm_Output;

   ----------------
   -- Initialize --
   ----------------

   procedure Initialize
     (Binder      : out VxLink_Binder;
      Object_File : String)
   is
      Args                   : Arguments_List;
      Module_Dtor_Not_Needed : Boolean := False;
      Module_Dtor_Needed     : Boolean := False;

   begin
      Args.Append (Nm);
      Args.Append (Object_File);

      declare
         Output  : constant String := Run (Args);
         Symbols : Symbol_Sets.Set;
      begin
         if Is_Error_State then
            return;
         end if;

         Symbols := Parse_Nm_Output (Output);

         for Sym of Symbols loop
            if Sym.Kind = Sym_Ctor then
               Binder.Constructors.Insert (Sym);
            elsif Sym.Kind = Sym_Dtor then
               Binder.Destructors.Insert (Sym);
            elsif Match ("_?__.*_atexit$", To_String (Sym.Name)) then
               if Sym.Cat = 'T' then
                  Module_Dtor_Not_Needed := True;
               elsif Sym.Cat = 'U' then
                  Module_Dtor_Needed := True;
               end if;
            end if;
         end loop;

         Binder.Module_Dtor_Needed :=
           not Module_Dtor_Not_Needed and then Module_Dtor_Needed;
      end;
   end Initialize;

   --------------------
   -- Parse_Tag_File --
   --------------------

   procedure Parse_Tag_File
     (Binder : in out VxLink_Binder;
      File   : String)
   is
      FP   : Ada.Text_IO.File_Type;

   begin
      Open
        (FP,
         Mode => In_File,
         Name => File);
      loop
         declare
            Line   : constant String :=
                      Ada.Strings.Fixed.Trim
                        (Get_Line (FP), Ada.Strings.Both);
            Tokens : Strings_List.Vector;

         begin
            if Line'Length = 0 then
               --  Skip empty lines
               null;

            elsif Line (Line'First) = '#' then
               --  Skip comment
               null;

            else
               Tokens := Split (Line, ' ');
               if Tokens.First_Element = "section" then
                  --  Sections are not used for tags, only when building
                  --  kernels. So skip for now
                  null;
               else
                  Binder.Tags_List.Append (Line);
               end if;
            end if;
         end;
      end loop;

   exception
      when Ada.IO_Exceptions.End_Error =>
         Close (FP);
      when others =>
         Log_Error ("Cannot open file " & File &
                      ". DKM tags won't be generated");
   end Parse_Tag_File;

   ----------------------
   -- Emit_Module_Dtor --
   ----------------------

   procedure Emit_Module_Dtor
     (FP : File_Type)
   is
      Dtor_Name : constant String := "_GLOBAL__D_65536_0_cxa_finalize";
   begin
      Put_Line (FP, "extern void __cxa_finalize(void *);");
      Put_Line (FP, "static void " & Dtor_Name & "()");
      Put_Line (FP, "{");
      Put_Line (FP, "  __cxa_finalize(&__dso_handle);");
      Put_Line (FP, "}");
      Put_Line (FP, "");
   end Emit_Module_Dtor;

   ----------------
   -- Emit_CDtor --
   ----------------

   procedure Emit_CDtor
     (FP  : File_Type;
      Var : String;
      Set : Symbol_Sets.Set)
   is
   begin
      for Sym of Set loop
         if not Sym.Internal then
            Put_Line (FP, "extern void " & To_String (Sym.Name) & "();");
         end if;
      end loop;

      New_Line (FP);

      Put_Line (FP, "extern void (*" & Var & "[])();");
      Put_Line (FP, "void (*" & Var & "[])() =");
      Put_Line (FP, "  {");
      for Sym of Set loop
         Put_Line (FP, "  " & To_String (Sym.Name) & ",");
      end loop;
      Put_Line (FP, "  0};");
      New_Line (FP);
   end Emit_CDtor;

   ---------------
   -- Emit_CTDT --
   ---------------

   procedure Emit_CTDT
     (Binder    : in out VxLink_Binder;
      Namespace : String)
   is
      FP         : Ada.Text_IO.File_Type;
      CDtor_File : constant String := Namespace & "-cdtor.c";
   begin
      Binder.CTDT_File := To_Unbounded_String (CDtor_File);
      Create
        (File => FP,
         Name => CDtor_File);
      Put_Line (FP, "#if defined(_HAVE_TOOL_XTORS)");
      Put_Line (FP, "#include <vxWorks.h>");
      if Binder.Module_Dtor_Needed then
         Put_Line (FP, "#define _WRS_NEED_CALL_CXA_FINALIZE");
      end if;
      Put_Line (FP, "#include TOOL_HEADER (toolXtors.h)");
      Put_Line (FP, "#else");
      Put_Line (FP, "");

      if Binder.Module_Dtor_Needed then
         Emit_Module_Dtor (FP);
      end if;

      Emit_CDtor (FP, "_ctors", Binder.Constructors);
      Emit_CDtor (FP, "_dtors", Binder.Destructors);

      Put_Line (FP, "#endif");

      if not Binder.Tags_List.Is_Empty then
         New_Line (FP);
         Put_Line (FP, "/* build variables */");
         Put_Line (FP, "__asm(""  .section \"".wrs_build_vars\"",\""a\"""");");
         for Tag of Binder.Tags_List loop
            Put_Line (FP, "__asm(""  .ascii \""" & Tag & "\"""");");
            Put_Line (FP, "__asm(""  .byte 0"");");
         end loop;
         Put_Line (FP, "__asm(""  .ascii \""end\"""");");
         Put_Line (FP, "__asm(""  .byte 0"");");
      end if;

      Close (FP);

   exception
      when others =>
         Close (FP);
         Set_Error_State ("Internal error");
         raise;
   end Emit_CTDT;

   ---------------
   -- CTDT_File --
   ---------------

   function CTDT_File (Binder : VxLink_Binder) return String
   is
   begin
      return To_String (Binder.CTDT_File);
   end CTDT_File;

end VxLink.Bind;