llvm: generalised sanitizer linking support

Also enabled automatic detection of sanitizer library + setting rpath to Linux
This commit is contained in:
Jonas Maebe 2022-07-24 14:13:59 +02:00
parent 75c16b6126
commit 7ef33cf4b2
3 changed files with 93 additions and 37 deletions

View File

@ -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;

View File

@ -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

View File

@ -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);