ソースを参照

llvm: generalised sanitizer linking support

Also enabled automatic detection of sanitizer library + setting rpath to Linux
Jonas Maebe 3 年 前
コミット
7ef33cf4b2
3 ファイル変更93 行追加37 行削除
  1. 60 7
      compiler/link.pas
  2. 11 25
      compiler/systems/t_darwin.pas
  3. 22 5
      compiler/systems/t_linux.pas

+ 60 - 7
compiler/link.pas

@@ -82,7 +82,8 @@ interface
       TExternalLinker = class(TLinker)
       protected
          Function WriteSymbolOrderFile: TCmdStr;
-         Function GetSanitizersLibraryNameAndPath(const platformname, asanlibinfix: TCmdStr; out sanitizerLibraryDir, asanLibraryPath: TCmdStr): boolean;
+         Function GetSanitizerLibName(const basename: TCmdStr; withArch: boolean): TCmdStr;
+         Function AddSanitizerLibrariesAndGetSearchDir(const platformname: TCmdStr; out sanitizerlibrarydir: TCmdStr): boolean;
       public
          Info : TLinkerInfo;
          Constructor Create;override;
@@ -174,7 +175,7 @@ Implementation
 {$ifdef hasUnix}
       baseunix,
 {$endif hasUnix}
-      cscript,globals,verbose,comphook,ppu,fpchash,triplet,
+      cscript,globals,verbose,comphook,ppu,fpchash,triplet,tripletcpu,
       aasmbase,aasmcpu,
       ogmap;
 
@@ -679,16 +680,50 @@ Implementation
       end;
 
 
-    Function TExternalLinker.GetSanitizersLibraryNameAndPath(const platformname, asanlibinfix: TCmdStr; out sanitizerLibraryDir, asanLibraryPath: TCmdStr): boolean;
+    Function TExternalLinker.GetSanitizerLibName(const basename: TCmdStr; withArch: boolean): TCmdStr;
+      begin
+        result:=target_info.sharedClibprefix+'clang_rt.'+basename;
+        if target_info.system in systems_darwin then
+          begin
+            { Darwin never adds the arch, it uses fat binaries. But it has the
+              extra '_dynamic' for some reason, and also adds the platform type
+            }
+            if target_info.system in systems_macosx then
+              result:=result+'_osx_dynamic'
+            else if target_info.system in systems_ios then
+              result:='_ios_dynamic'
+            else if target_info.system in systems_iphonesym then
+              result:='_iossim_dynamic'
+            else
+              internalerror(2022071010);
+          end
+        else
+          begin
+            if withArch then
+              begin
+                result:=result+'-'+tripletcpustr(triplet_llvmrt);
+                if target_info.system in systems_android then
+                  result:=result+'-android';
+              end;
+          end;
+        result:=result+target_info.sharedClibext;
+      end;
+
+
+    function TExternalLinker.AddSanitizerLibrariesAndGetSearchDir(const platformname: TCmdStr; out sanitizerlibrarydir: TCmdStr): boolean;
       var
         clang,
         clangsearchdirs,
         textline,
-        clangsearchdirspath: TCmdStr;
+        clangsearchdirspath,
+        sanitizerlibname,
+        sanitizerlibrarypath: TCmdStr;
+        sanitizerlibraryfiles: TCmdStrList;
         searchrec: TSearchRec;
         searchres: longint;
         clangsearchdirsfile: text;
       begin
+        sanitizerlibraryfiles:=TCmdStrList.Create;
         result:=false;
         if (cs_sanitize_address in current_settings.moduleswitches) and
            not(cs_link_on_target in current_settings.globalswitches) then
@@ -708,15 +743,33 @@ Implementation
                   if ioresult=0 then
                     begin
                       readln(clangsearchdirsfile,textline);
-                      sanitizerLibraryDir:=FixFileName(textline+'/'+platformname);
-                      asanLibraryPath:=FixFileName(sanitizerLibraryDir+'/')+target_info.sharedClibprefix+'clang_rt.asan_'+asanlibinfix+'_dynamic'+target_info.sharedClibext;
-                      result:=FileExists(asanLibraryPath,false);
+                      sanitizerlibrarydir:=FixFileName(textline+'/'+platformname);
+                      sanitizerlibrarypath:=FixFileName(sanitizerlibrarydir+'/');
+                      { from clang:
+                        Check for runtime files in the new layout without the architecture first.
+                      }
+                      sanitizerlibname:=GetSanitizerLibName('asan',false);
+                      result:=FileExists(sanitizerlibrarypath+sanitizerlibname,false);
+                      if result then
+                        begin
+                          sanitizerlibraryfiles.Concat(sanitizerlibrarypath+sanitizerlibname);
+                        end
+                      else
+                        begin
+                          sanitizerlibname:=GetSanitizerLibName('asan',true);
+                          result:=FileExists(sanitizerlibrarypath+sanitizerlibname,false);
+                          if result then
+                            sanitizerlibraryfiles.Concat(sanitizerlibrarypath+sanitizerlibname);
+                        end;
                     end;
                 end;
               if FileExists(clangsearchdirspath,false) then
                 DeleteFile(clangsearchdirspath);
             end;
           end;
+        if result then
+          ObjectFiles.concatList(sanitizerlibraryfiles);
+        sanitizerlibraryfiles.free;
       end;
 
 

+ 11 - 25
compiler/systems/t_darwin.pas

@@ -61,7 +61,6 @@ implementation
       function GetLibSearchPath: TCmdStr;
       function GetLibraries: TCmdStr;
 
-      function GetSanitizerLibraryInfix: TCmdStr;
     public
       constructor Create;override;
       procedure SetDefaultInfo;override;
@@ -443,19 +442,6 @@ implementation
       end;
 
 
-    function tlinkerdarwin.GetSanitizerLibraryInfix: TCmdStr;
-      begin
-        if target_info.system in systems_macosx then
-          result:='osx'
-        else if target_info.system in systems_ios then
-          result:='ios'
-        else if target_info.system in systems_iphonesym then
-          result:='iossim'
-        else
-          internalerror(2022071010);
-      end;
-
-
     function tlinkerdarwin.WriteFileList: TCmdStr;
     Var
       FilesList    : TScript;
@@ -502,7 +488,6 @@ implementation
       GCSectionsStr,
       StaticStr,
       StripStr,
-      asanLibraryName,
       sanitizerLibraryDir: TCmdStr;
       success : boolean;
     begin
@@ -532,7 +517,7 @@ implementation
       if (cs_lto in current_settings.moduleswitches) and
          not(cs_link_on_target in current_settings.globalswitches) and
          (utilsdirectory<>'') and
-         FileExists(utilsdirectory+'/../lib/libLTO.dylib',true) then
+         FileExists(utilsdirectory+'/../lib/libLTO.dylib',false) then
         begin
           ltostr:='-lto_library '+maybequoted(utilsdirectory+'/../lib/libLTO.dylib');
         end;
@@ -553,10 +538,11 @@ implementation
       else
         Replace(cmdstr,'$ORDERSYMS','');
 
-      if GetSanitizersLibraryNameAndPath('darwin',GetSanitizerLibraryInfix,sanitizerLibraryDir,asanLibraryName) then
+      if AddSanitizerLibrariesAndGetSearchDir('darwin',sanitizerLibraryDir) then
         begin
-          ObjectFiles.Concat(asanLibraryName);
-          Replace(cmdstr,'$RPATH','-rpath '+sanitizerLibraryDir)
+          { also add the executable path as search path in case the asan
+            library gets copied into the application bundle }
+          Replace(cmdstr,'$RPATH','-rpath @executable_path -rpath '+maybequoted(sanitizerLibraryDir))
         end
       else
         begin
@@ -624,8 +610,7 @@ implementation
       extdbgcmdstr,
       linkfiles,
       GCSectionsStr,
-      sanitizerLibraryDir,
-      asanLibraryName: TCmdStr;
+      sanitizerLibraryDir: TCmdStr;
       exportedsyms: text;
       success : boolean;
     begin
@@ -649,7 +634,7 @@ implementation
       if (cs_lto in current_settings.moduleswitches) and
          not(cs_link_on_target in current_settings.globalswitches) and
          (utilsdirectory<>'') and
-         FileExists(utilsdirectory+'/../lib/libLTO.dylib',true) then
+         FileExists(utilsdirectory+'/../lib/libLTO.dylib',false) then
         begin
           ltostr:='-lto_library '+maybequoted(utilsdirectory+'/../lib/libLTO.dylib');
         end;
@@ -675,10 +660,11 @@ implementation
       else
         Replace(cmdstr,'$ORDERSYMS','');
       { add asan library if known }
-      if GetSanitizersLibraryNameAndPath('darwin',GetSanitizerLibraryInfix,sanitizerLibraryDir,asanLibraryName) then
+      if AddSanitizerLibrariesAndGetSearchDir('darwin',sanitizerLibraryDir) then
         begin
-          ObjectFiles.Concat(asanLibraryName);
-          Replace(cmdstr,'$RPATH','-rpath '+sanitizerLibraryDir)
+          { also add the executable path as search path in case the asan
+            library gets copied into the application bundle }
+          Replace(cmdstr,'$RPATH','-rpath @executable_path -rpath '+maybequoted(sanitizerLibraryDir))
         end
       else
         begin

+ 22 - 5
compiler/systems/t_linux.pas

@@ -398,8 +398,8 @@ begin
 
   with Info do
    begin
-     ExeCmd[1]:='ld '+platform_select+platformopt+' $OPT $DYNLINK $STATIC $GCSECTIONS $STRIP $MAP $LTO -L. -o $EXE';
-     DllCmd[1]:='ld '+platform_select+platformopt+' $OPT $INIT $FINI $SONAME $MAP $LTO -shared $GCSECTIONS -L. -o $EXE';
+     ExeCmd[1]:='ld '+platform_select+platformopt+' $OPT $DYNLINK $STATIC $GCSECTIONS $STRIP $MAP $LTO $RPATH -L. -o $EXE';
+     DllCmd[1]:='ld '+platform_select+platformopt+' $OPT $INIT $FINI $SONAME $MAP $LTO $RPATH -shared $GCSECTIONS -L. -o $EXE';
      { when we want to cross-link we need to override default library paths;
        when targeting binutils 2.19 or later, we use the "INSERT" command to
        augment the default linkerscript, which also requires -T (normally that
@@ -740,7 +740,9 @@ var
   binstr,
   cmdstr,
   mapstr,
-  ltostr  : TCmdStr;
+  ltostr,
+  rpathstr,
+  sanitizerLibraryDir: TCmdStr;
   success : boolean;
   DynLinkStr : ansistring;
   GCSectionsStr,
@@ -757,6 +759,7 @@ begin
   DynLinkStr:='';
   mapstr:='';
   ltostr:='';
+  rpathstr:='';
   if (cs_link_staticflag in current_settings.globalswitches) then
    StaticStr:='-static';
   if (cs_link_strip in current_settings.globalswitches) and
@@ -786,6 +789,11 @@ begin
       ltostr:='-plugin '+maybequoted(utilsdirectory+'/../lib/LLVMgold.so ');
     end;
 
+  if AddSanitizerLibrariesAndGetSearchDir('linux',sanitizerLibraryDir) then
+    begin
+      rpathstr:='-rpath '+maybequoted(sanitizerLibraryDir);
+    end;
+
 { Write used files and libraries }
   WriteResponseFile(false);
 
@@ -800,6 +808,7 @@ begin
   Replace(cmdstr,'$DYNLINK',DynLinkStr);
   Replace(cmdstr,'$MAP',mapstr);
   Replace(cmdstr,'$LTO',ltostr);
+  Replace(cmdstr,'$RPATH',rpathstr);
 
   { create dynamic symbol table? }
   if HasExports then
@@ -853,7 +862,9 @@ var
   binstr,
   cmdstr,
   mapstr,
-  ltostr : TCmdStr;
+  ltostr,
+  rpathstr,
+  sanitizerLibraryDir: TCmdStr;
   success : boolean;
 begin
   MakeSharedLibrary:=false;
@@ -887,7 +898,12 @@ begin
       ltostr:='-plugin '+maybequoted(utilsdirectory+'/../lib/LLVMgold.so ');
     end;
 
-{ Call linker }
+  if AddSanitizerLibrariesAndGetSearchDir('linux',sanitizerLibraryDir) then
+    begin
+      rpathstr:='-rpath '+maybequoted(sanitizerLibraryDir)
+    end;
+
+ { Call linker }
   SplitBinCmd(Info.DllCmd[1],binstr,cmdstr);
   Replace(cmdstr,'$EXE',maybequoted(current_module.sharedlibfilename));
   Replace(cmdstr,'$OPT',Info.ExtraOptions);
@@ -897,6 +913,7 @@ begin
   Replace(cmdstr,'$SONAME',SoNameStr);
   Replace(cmdstr,'$MAP',mapstr);
   Replace(cmdstr,'$LTO',ltostr);
+  Replace(cmdstr,'$RPATH',rpathstr);
   Replace(cmdstr,'$GCSECTIONS',GCSectionsStr);
   success:=DoExec(FindUtil(utilsprefix+binstr),cmdstr,true,false);