mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-08-18 03:49:20 +02:00
llvm: generalised sanitizer linking support
Also enabled automatic detection of sanitizer library + setting rpath to Linux
This commit is contained in:
parent
75c16b6126
commit
7ef33cf4b2
@ -82,7 +82,8 @@ interface
|
|||||||
TExternalLinker = class(TLinker)
|
TExternalLinker = class(TLinker)
|
||||||
protected
|
protected
|
||||||
Function WriteSymbolOrderFile: TCmdStr;
|
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
|
public
|
||||||
Info : TLinkerInfo;
|
Info : TLinkerInfo;
|
||||||
Constructor Create;override;
|
Constructor Create;override;
|
||||||
@ -174,7 +175,7 @@ Implementation
|
|||||||
{$ifdef hasUnix}
|
{$ifdef hasUnix}
|
||||||
baseunix,
|
baseunix,
|
||||||
{$endif hasUnix}
|
{$endif hasUnix}
|
||||||
cscript,globals,verbose,comphook,ppu,fpchash,triplet,
|
cscript,globals,verbose,comphook,ppu,fpchash,triplet,tripletcpu,
|
||||||
aasmbase,aasmcpu,
|
aasmbase,aasmcpu,
|
||||||
ogmap;
|
ogmap;
|
||||||
|
|
||||||
@ -679,16 +680,50 @@ Implementation
|
|||||||
end;
|
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
|
var
|
||||||
clang,
|
clang,
|
||||||
clangsearchdirs,
|
clangsearchdirs,
|
||||||
textline,
|
textline,
|
||||||
clangsearchdirspath: TCmdStr;
|
clangsearchdirspath,
|
||||||
|
sanitizerlibname,
|
||||||
|
sanitizerlibrarypath: TCmdStr;
|
||||||
|
sanitizerlibraryfiles: TCmdStrList;
|
||||||
searchrec: TSearchRec;
|
searchrec: TSearchRec;
|
||||||
searchres: longint;
|
searchres: longint;
|
||||||
clangsearchdirsfile: text;
|
clangsearchdirsfile: text;
|
||||||
begin
|
begin
|
||||||
|
sanitizerlibraryfiles:=TCmdStrList.Create;
|
||||||
result:=false;
|
result:=false;
|
||||||
if (cs_sanitize_address in current_settings.moduleswitches) and
|
if (cs_sanitize_address in current_settings.moduleswitches) and
|
||||||
not(cs_link_on_target in current_settings.globalswitches) then
|
not(cs_link_on_target in current_settings.globalswitches) then
|
||||||
@ -708,15 +743,33 @@ Implementation
|
|||||||
if ioresult=0 then
|
if ioresult=0 then
|
||||||
begin
|
begin
|
||||||
readln(clangsearchdirsfile,textline);
|
readln(clangsearchdirsfile,textline);
|
||||||
sanitizerLibraryDir:=FixFileName(textline+'/'+platformname);
|
sanitizerlibrarydir:=FixFileName(textline+'/'+platformname);
|
||||||
asanLibraryPath:=FixFileName(sanitizerLibraryDir+'/')+target_info.sharedClibprefix+'clang_rt.asan_'+asanlibinfix+'_dynamic'+target_info.sharedClibext;
|
sanitizerlibrarypath:=FixFileName(sanitizerlibrarydir+'/');
|
||||||
result:=FileExists(asanLibraryPath,false);
|
{ 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;
|
||||||
end;
|
end;
|
||||||
if FileExists(clangsearchdirspath,false) then
|
if FileExists(clangsearchdirspath,false) then
|
||||||
DeleteFile(clangsearchdirspath);
|
DeleteFile(clangsearchdirspath);
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
if result then
|
||||||
|
ObjectFiles.concatList(sanitizerlibraryfiles);
|
||||||
|
sanitizerlibraryfiles.free;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
@ -61,7 +61,6 @@ implementation
|
|||||||
function GetLibSearchPath: TCmdStr;
|
function GetLibSearchPath: TCmdStr;
|
||||||
function GetLibraries: TCmdStr;
|
function GetLibraries: TCmdStr;
|
||||||
|
|
||||||
function GetSanitizerLibraryInfix: TCmdStr;
|
|
||||||
public
|
public
|
||||||
constructor Create;override;
|
constructor Create;override;
|
||||||
procedure SetDefaultInfo;override;
|
procedure SetDefaultInfo;override;
|
||||||
@ -443,19 +442,6 @@ implementation
|
|||||||
end;
|
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;
|
function tlinkerdarwin.WriteFileList: TCmdStr;
|
||||||
Var
|
Var
|
||||||
FilesList : TScript;
|
FilesList : TScript;
|
||||||
@ -502,7 +488,6 @@ implementation
|
|||||||
GCSectionsStr,
|
GCSectionsStr,
|
||||||
StaticStr,
|
StaticStr,
|
||||||
StripStr,
|
StripStr,
|
||||||
asanLibraryName,
|
|
||||||
sanitizerLibraryDir: TCmdStr;
|
sanitizerLibraryDir: TCmdStr;
|
||||||
success : boolean;
|
success : boolean;
|
||||||
begin
|
begin
|
||||||
@ -532,7 +517,7 @@ implementation
|
|||||||
if (cs_lto in current_settings.moduleswitches) and
|
if (cs_lto in current_settings.moduleswitches) and
|
||||||
not(cs_link_on_target in current_settings.globalswitches) and
|
not(cs_link_on_target in current_settings.globalswitches) and
|
||||||
(utilsdirectory<>'') and
|
(utilsdirectory<>'') and
|
||||||
FileExists(utilsdirectory+'/../lib/libLTO.dylib',true) then
|
FileExists(utilsdirectory+'/../lib/libLTO.dylib',false) then
|
||||||
begin
|
begin
|
||||||
ltostr:='-lto_library '+maybequoted(utilsdirectory+'/../lib/libLTO.dylib');
|
ltostr:='-lto_library '+maybequoted(utilsdirectory+'/../lib/libLTO.dylib');
|
||||||
end;
|
end;
|
||||||
@ -553,10 +538,11 @@ implementation
|
|||||||
else
|
else
|
||||||
Replace(cmdstr,'$ORDERSYMS','');
|
Replace(cmdstr,'$ORDERSYMS','');
|
||||||
|
|
||||||
if GetSanitizersLibraryNameAndPath('darwin',GetSanitizerLibraryInfix,sanitizerLibraryDir,asanLibraryName) then
|
if AddSanitizerLibrariesAndGetSearchDir('darwin',sanitizerLibraryDir) then
|
||||||
begin
|
begin
|
||||||
ObjectFiles.Concat(asanLibraryName);
|
{ also add the executable path as search path in case the asan
|
||||||
Replace(cmdstr,'$RPATH','-rpath '+sanitizerLibraryDir)
|
library gets copied into the application bundle }
|
||||||
|
Replace(cmdstr,'$RPATH','-rpath @executable_path -rpath '+maybequoted(sanitizerLibraryDir))
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
begin
|
begin
|
||||||
@ -624,8 +610,7 @@ implementation
|
|||||||
extdbgcmdstr,
|
extdbgcmdstr,
|
||||||
linkfiles,
|
linkfiles,
|
||||||
GCSectionsStr,
|
GCSectionsStr,
|
||||||
sanitizerLibraryDir,
|
sanitizerLibraryDir: TCmdStr;
|
||||||
asanLibraryName: TCmdStr;
|
|
||||||
exportedsyms: text;
|
exportedsyms: text;
|
||||||
success : boolean;
|
success : boolean;
|
||||||
begin
|
begin
|
||||||
@ -649,7 +634,7 @@ implementation
|
|||||||
if (cs_lto in current_settings.moduleswitches) and
|
if (cs_lto in current_settings.moduleswitches) and
|
||||||
not(cs_link_on_target in current_settings.globalswitches) and
|
not(cs_link_on_target in current_settings.globalswitches) and
|
||||||
(utilsdirectory<>'') and
|
(utilsdirectory<>'') and
|
||||||
FileExists(utilsdirectory+'/../lib/libLTO.dylib',true) then
|
FileExists(utilsdirectory+'/../lib/libLTO.dylib',false) then
|
||||||
begin
|
begin
|
||||||
ltostr:='-lto_library '+maybequoted(utilsdirectory+'/../lib/libLTO.dylib');
|
ltostr:='-lto_library '+maybequoted(utilsdirectory+'/../lib/libLTO.dylib');
|
||||||
end;
|
end;
|
||||||
@ -675,10 +660,11 @@ implementation
|
|||||||
else
|
else
|
||||||
Replace(cmdstr,'$ORDERSYMS','');
|
Replace(cmdstr,'$ORDERSYMS','');
|
||||||
{ add asan library if known }
|
{ add asan library if known }
|
||||||
if GetSanitizersLibraryNameAndPath('darwin',GetSanitizerLibraryInfix,sanitizerLibraryDir,asanLibraryName) then
|
if AddSanitizerLibrariesAndGetSearchDir('darwin',sanitizerLibraryDir) then
|
||||||
begin
|
begin
|
||||||
ObjectFiles.Concat(asanLibraryName);
|
{ also add the executable path as search path in case the asan
|
||||||
Replace(cmdstr,'$RPATH','-rpath '+sanitizerLibraryDir)
|
library gets copied into the application bundle }
|
||||||
|
Replace(cmdstr,'$RPATH','-rpath @executable_path -rpath '+maybequoted(sanitizerLibraryDir))
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
begin
|
begin
|
||||||
|
@ -398,8 +398,8 @@ begin
|
|||||||
|
|
||||||
with Info do
|
with Info do
|
||||||
begin
|
begin
|
||||||
ExeCmd[1]:='ld '+platform_select+platformopt+' $OPT $DYNLINK $STATIC $GCSECTIONS $STRIP $MAP $LTO -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 -shared $GCSECTIONS -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 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
|
when targeting binutils 2.19 or later, we use the "INSERT" command to
|
||||||
augment the default linkerscript, which also requires -T (normally that
|
augment the default linkerscript, which also requires -T (normally that
|
||||||
@ -740,7 +740,9 @@ var
|
|||||||
binstr,
|
binstr,
|
||||||
cmdstr,
|
cmdstr,
|
||||||
mapstr,
|
mapstr,
|
||||||
ltostr : TCmdStr;
|
ltostr,
|
||||||
|
rpathstr,
|
||||||
|
sanitizerLibraryDir: TCmdStr;
|
||||||
success : boolean;
|
success : boolean;
|
||||||
DynLinkStr : ansistring;
|
DynLinkStr : ansistring;
|
||||||
GCSectionsStr,
|
GCSectionsStr,
|
||||||
@ -757,6 +759,7 @@ begin
|
|||||||
DynLinkStr:='';
|
DynLinkStr:='';
|
||||||
mapstr:='';
|
mapstr:='';
|
||||||
ltostr:='';
|
ltostr:='';
|
||||||
|
rpathstr:='';
|
||||||
if (cs_link_staticflag in current_settings.globalswitches) then
|
if (cs_link_staticflag in current_settings.globalswitches) then
|
||||||
StaticStr:='-static';
|
StaticStr:='-static';
|
||||||
if (cs_link_strip in current_settings.globalswitches) and
|
if (cs_link_strip in current_settings.globalswitches) and
|
||||||
@ -786,6 +789,11 @@ begin
|
|||||||
ltostr:='-plugin '+maybequoted(utilsdirectory+'/../lib/LLVMgold.so ');
|
ltostr:='-plugin '+maybequoted(utilsdirectory+'/../lib/LLVMgold.so ');
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
if AddSanitizerLibrariesAndGetSearchDir('linux',sanitizerLibraryDir) then
|
||||||
|
begin
|
||||||
|
rpathstr:='-rpath '+maybequoted(sanitizerLibraryDir);
|
||||||
|
end;
|
||||||
|
|
||||||
{ Write used files and libraries }
|
{ Write used files and libraries }
|
||||||
WriteResponseFile(false);
|
WriteResponseFile(false);
|
||||||
|
|
||||||
@ -800,6 +808,7 @@ begin
|
|||||||
Replace(cmdstr,'$DYNLINK',DynLinkStr);
|
Replace(cmdstr,'$DYNLINK',DynLinkStr);
|
||||||
Replace(cmdstr,'$MAP',mapstr);
|
Replace(cmdstr,'$MAP',mapstr);
|
||||||
Replace(cmdstr,'$LTO',ltostr);
|
Replace(cmdstr,'$LTO',ltostr);
|
||||||
|
Replace(cmdstr,'$RPATH',rpathstr);
|
||||||
|
|
||||||
{ create dynamic symbol table? }
|
{ create dynamic symbol table? }
|
||||||
if HasExports then
|
if HasExports then
|
||||||
@ -853,7 +862,9 @@ var
|
|||||||
binstr,
|
binstr,
|
||||||
cmdstr,
|
cmdstr,
|
||||||
mapstr,
|
mapstr,
|
||||||
ltostr : TCmdStr;
|
ltostr,
|
||||||
|
rpathstr,
|
||||||
|
sanitizerLibraryDir: TCmdStr;
|
||||||
success : boolean;
|
success : boolean;
|
||||||
begin
|
begin
|
||||||
MakeSharedLibrary:=false;
|
MakeSharedLibrary:=false;
|
||||||
@ -887,7 +898,12 @@ begin
|
|||||||
ltostr:='-plugin '+maybequoted(utilsdirectory+'/../lib/LLVMgold.so ');
|
ltostr:='-plugin '+maybequoted(utilsdirectory+'/../lib/LLVMgold.so ');
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ Call linker }
|
if AddSanitizerLibrariesAndGetSearchDir('linux',sanitizerLibraryDir) then
|
||||||
|
begin
|
||||||
|
rpathstr:='-rpath '+maybequoted(sanitizerLibraryDir)
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ Call linker }
|
||||||
SplitBinCmd(Info.DllCmd[1],binstr,cmdstr);
|
SplitBinCmd(Info.DllCmd[1],binstr,cmdstr);
|
||||||
Replace(cmdstr,'$EXE',maybequoted(current_module.sharedlibfilename));
|
Replace(cmdstr,'$EXE',maybequoted(current_module.sharedlibfilename));
|
||||||
Replace(cmdstr,'$OPT',Info.ExtraOptions);
|
Replace(cmdstr,'$OPT',Info.ExtraOptions);
|
||||||
@ -897,6 +913,7 @@ begin
|
|||||||
Replace(cmdstr,'$SONAME',SoNameStr);
|
Replace(cmdstr,'$SONAME',SoNameStr);
|
||||||
Replace(cmdstr,'$MAP',mapstr);
|
Replace(cmdstr,'$MAP',mapstr);
|
||||||
Replace(cmdstr,'$LTO',ltostr);
|
Replace(cmdstr,'$LTO',ltostr);
|
||||||
|
Replace(cmdstr,'$RPATH',rpathstr);
|
||||||
Replace(cmdstr,'$GCSECTIONS',GCSectionsStr);
|
Replace(cmdstr,'$GCSECTIONS',GCSectionsStr);
|
||||||
success:=DoExec(FindUtil(utilsprefix+binstr),cmdstr,true,false);
|
success:=DoExec(FindUtil(utilsprefix+binstr),cmdstr,true,false);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user