blob: 9f456944506d67bfe606e6dc008d1980f2f3ce96 [file] [log] [blame]
------------------------------------------------------------------------------
-- --
-- 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;