Преглед изворни кода

* use the extern and public assembler symbol lists stored in the units to resolve those symbols to a used package that don't have a corresponding Pascal symbol

git-svn-id: trunk@34179 -
svenbarth пре 9 година
родитељ
комит
022df814c2
1 измењених фајлова са 156 додато и 1 уклоњено
  1. 156 1
      compiler/pkgutil.pas

+ 156 - 1
compiler/pkgutil.pas

@@ -45,8 +45,10 @@ implementation
     globtype,systems,
     cutils,
     globals,verbose,
+    aasmbase,aasmdata,
     symtype,symconst,symsym,symdef,symbase,symtable,
-    psub,
+    psub,pdecsub,
+    ncgutil,
     ppu,entfile,fpcp,
     export;
 
@@ -540,10 +542,149 @@ implementation
 
 
   procedure createimportlibfromexternals;
+    type
+      tcacheentry=record
+        pkg:tpackage;
+        sym:tasmsymbol;
+      end;
+      pcacheentry=^tcacheentry;
     var
+      cache : tfphashlist;
       alreadyloaded : tfpobjectlist;
 
 
+      function findpackagewithsym(symname:tsymstr):tcacheentry;
+        var
+          i,j : longint;
+          pkgentry : ppackageentry;
+          unitentry : pcontainedunit;
+        begin
+          for i:=0 to packagelist.count-1 do
+            begin
+              pkgentry:=ppackageentry(packagelist[i]);
+              for j:=0 to pkgentry^.package.containedmodules.count-1 do
+                begin
+                  unitentry:=pcontainedunit(pkgentry^.package.containedmodules[j]);
+                  if not assigned(unitentry^.module) then
+                    { the unit is not loaded }
+                    continue;
+                  result.sym:=tasmsymbol(tmodule(unitentry^.module).publicasmsyms.find(symname));
+                  if assigned(result.sym) then
+                    begin
+                      { completely ignore other external symbols }
+                      if result.sym.bind in [ab_external,ab_weak_external] then
+                        begin
+                          result.sym:=nil;
+                          continue;
+                        end;
+                      { only accept global symbols of the used unit }
+                      if result.sym.bind<>ab_global then
+                        begin
+                          result.sym:=nil;
+                          result.pkg:=nil;
+                        end
+                      else
+                        result.pkg:=pkgentry^.package;
+                      exit;
+                    end;
+                end;
+            end;
+          result.sym:=nil;
+          result.pkg:=nil;
+        end;
+
+
+    procedure processasmsyms(symlist:tfphashobjectlist);
+      var
+        i,j,k : longint;
+        sym : tasmsymbol;
+        cacheentry : pcacheentry;
+        list : TAsmList;
+        labind : tasmsymbol;
+        psym : tsymentry;
+        pd : tprocdef;
+        found : boolean;
+        impname,symname : TSymStr;
+        suffixidx : longint;
+      begin
+        for i:=0 to symlist.count-1 do
+          begin
+            sym:=tasmsymbol(symlist[i]);
+            if not (sym.bind in [ab_external,ab_external_indirect]) then
+              continue;
+
+            { remove the indirect suffix }
+            symname:=sym.name;
+            if sym.bind=ab_external_indirect then
+              begin
+                suffixidx:=pos(suffix_indirect,symname);
+                if suffixidx=length(symname)-length(suffix_indirect)+1 then
+                  symname:=copy(symname,1,suffixidx-1)
+                else
+                  internalerror(2016062401);
+              end;
+
+            { did we already import the symbol? }
+            cacheentry:=pcacheentry(cache.find(symname));
+            if assigned(cacheentry) then
+              continue;
+
+            { was the symbol already imported in the previous pass? }
+            found:=false;
+            for j:=0 to alreadyloaded.count-1 do
+              begin
+                psym:=tsymentry(alreadyloaded[j]);
+                case psym.typ of
+                  procsym:
+                    for k:=0 to tprocsym(psym).procdeflist.count-1 do
+                      begin
+                        pd:=tprocdef(tprocsym(psym).procdeflist[k]);
+                        if has_alias_name(pd,symname) or
+                            (
+                              ([po_external,po_has_importdll]*pd.procoptions=[po_external,po_has_importdll]) and
+                              (symname=proc_get_importname(pd))
+                            ) then
+                          begin
+                            found:=true;
+                            break;
+                          end;
+                      end;
+                  staticvarsym:
+                    if tstaticvarsym(psym).mangledname=symname then
+                      found:=true;
+                  else
+                    internalerror(2014101005);
+                end;
+                if found then
+                  break;
+              end;
+            if found then begin
+              { add a dummy entry }
+              new(cacheentry);
+              cacheentry^.pkg:=nil;
+              cacheentry^.sym:=sym;
+              cache.add(symname,cacheentry);
+              continue;
+            end;
+
+            new(cacheentry);
+            cacheentry^:=findpackagewithsym(symname);
+            cache.add(symname,cacheentry);
+
+            { use cacheentry^.sym instead of sym, because for the later typ
+              is always at_none in case of an external symbol }
+            if assigned(cacheentry^.pkg) then
+              begin
+                impname:=symname;
+                if cacheentry^.sym.typ=AT_DATA then
+                  { import as the $indirect symbol if it as a variable }
+                  impname:=symname+suffix_indirect;
+                current_module.addexternalimport(cacheentry^.pkg.pplfilename,symname,impname,0,cacheentry^.sym.typ=at_data,false);
+              end;
+          end;
+      end;
+
+
     procedure import_proc_symbol(pd:tprocdef;pkg:tpackage);
       var
         item : TCmdStrListItem;
@@ -636,7 +777,9 @@ implementation
     var
       unitentry : pcontainedunit;
       module : tmodule;
+      i : longint;
     begin
+      cache:=tfphashlist.create;
       { check each external asm symbol of each unit of the package whether it is
         contained in the unit of a loaded package (and thus an import entry
         is needed) }
@@ -651,7 +794,19 @@ implementation
           module:=tmodule(module.next);
         end;
 
+      { second pass to find all symbols that were loaded by asm name }
+      module:=tmodule(loaded_units.first);
+      while assigned(module) do
+        begin
+          if not assigned(module.package) then
+            processasmsyms(module.externasmsyms);
+          module:=tmodule(module.next);
+        end;
+
       alreadyloaded.free;
+      for i:=0 to cache.count-1 do
+        dispose(pcacheentry(cache[i]));
+      cache.free;
     end;