link.pas 76 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243
  1. {
  2. Copyright (c) 1998-2002 by Peter Vreman
  3. This unit handles the linker and binder calls for programs and
  4. libraries
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. ****************************************************************************
  17. }
  18. unit link;
  19. {$i fpcdefs.inc}
  20. { $define DEBUG_MACHO_INFO}
  21. interface
  22. uses
  23. sysutils,
  24. cclasses,
  25. systems,
  26. fmodule,
  27. globtype,
  28. ldscript,
  29. ogbase,
  30. owbase;
  31. Type
  32. TLinkerInfo=record
  33. ExeCmd,
  34. DllCmd,
  35. ExtDbgCmd : array[1..3] of ansistring;
  36. ResName : string[100];
  37. ScriptName : string[100];
  38. ExtraOptions : TCmdStr;
  39. DynamicLinker : string[100];
  40. end;
  41. TLinker = class(TObject)
  42. public
  43. HasResources,
  44. HasExports : boolean;
  45. SysInitUnit : string[20];
  46. ObjectFiles,
  47. SharedLibFiles,
  48. StaticLibFiles,
  49. FrameworkFiles,
  50. OrderedSymbols: TCmdStrList;
  51. Constructor Create;virtual;
  52. Destructor Destroy;override;
  53. procedure AddModuleFiles(hp:tmodule);
  54. Procedure AddObject(const S,unitpath : TPathStr;isunit:boolean);
  55. Procedure AddStaticLibrary(const S : TCmdStr);
  56. Procedure AddSharedLibrary(S : TCmdStr);
  57. Procedure AddStaticCLibrary(const S : TCmdStr);
  58. Procedure AddSharedCLibrary(S : TCmdStr);
  59. Procedure AddFramework(S : TCmdStr);
  60. Procedure AddOrderedSymbol(const s: TCmdStr);
  61. procedure AddImportSymbol(const libname,symname,symmangledname:TCmdStr;OrdNr: longint;isvar:boolean);virtual;
  62. Procedure InitSysInitUnitName;virtual;
  63. Function MakeExecutable:boolean;virtual;
  64. Function MakeSharedLibrary:boolean;virtual;
  65. Function MakeStaticLibrary:boolean;virtual;
  66. procedure ExpandAndApplyOrder(var Src:TCmdStrList);
  67. procedure LoadPredefinedLibraryOrder;virtual;
  68. function ReOrderEntries : boolean;
  69. end;
  70. TExternalLinker = class(TLinker)
  71. protected
  72. Function WriteSymbolOrderFile: TCmdStr;
  73. Function GetSanitizersLibraryNameAndPath(const platformname, asanlibinfix: TCmdStr; out sanitizerLibraryDir, asanLibraryPath: TCmdStr): boolean;
  74. public
  75. Info : TLinkerInfo;
  76. Constructor Create;override;
  77. Destructor Destroy;override;
  78. Function FindUtil(const s:TCmdStr):TCmdStr;
  79. Function CatFileContent(para:TCmdStr):TCmdStr;
  80. Function DoExec(const command:TCmdStr; para:TCmdStr;showinfo,useshell:boolean):boolean;
  81. procedure SetDefaultInfo;virtual;
  82. Function MakeStaticLibrary:boolean;override;
  83. Function UniqueName(const str:TCmdStr): TCmdStr;
  84. function PostProcessELFExecutable(const fn: string; isdll: boolean): boolean;
  85. function PostProcessMachExecutable(const fn: string; isdll: boolean): boolean;
  86. end;
  87. TBooleanArray = array [1..100000] of boolean;
  88. PBooleanArray = ^TBooleanArray;
  89. TInternalLinker = class(TLinker)
  90. private
  91. FCExeOutput : TExeOutputClass;
  92. FCObjInput : TObjInputClass;
  93. FCArObjectReader : TObjectReaderClass;
  94. { Libraries }
  95. FStaticLibraryList : TFPObjectList;
  96. FImportLibraryList : TFPHashObjectList;
  97. FGroupStack : TFPObjectList;
  98. procedure Load_ReadObject(const para:TCmdStr);
  99. procedure Load_ReadStaticLibrary(const para:TCmdStr;asneededflag:boolean=false);
  100. procedure Load_Group;
  101. procedure Load_EndGroup;
  102. procedure ParseScript_Handle;
  103. procedure ParseScript_PostCheck;
  104. procedure ParseScript_Load;
  105. function ParsePara(const para : string) : string;
  106. procedure ParseScript_Order;
  107. procedure ParseScript_MemPos;
  108. procedure ParseScript_DataPos;
  109. procedure PrintLinkerScript;
  110. function RunLinkScript(const outputname:TCmdStr):boolean;
  111. procedure ParseLdScript(src:TScriptLexer);
  112. protected
  113. linkscript : TCmdStrList;
  114. ScriptCount : longint;
  115. IsHandled : PBooleanArray;
  116. property CArObjectReader:TObjectReaderClass read FCArObjectReader write FCArObjectReader;
  117. property CObjInput:TObjInputClass read FCObjInput write FCObjInput;
  118. property CExeOutput:TExeOutputClass read FCExeOutput write FCExeOutput;
  119. property StaticLibraryList:TFPObjectList read FStaticLibraryList;
  120. property ImportLibraryList:TFPHashObjectList read FImportLibraryList;
  121. procedure DefaultLinkScript;virtual;abstract;
  122. procedure ScriptAddGenericSections(secnames:string);
  123. procedure ScriptAddSourceStatements(AddSharedAsStatic:boolean);virtual;
  124. function GetCodeSize(aExeOutput: TExeOutput): QWord;virtual;
  125. function GetDataSize(aExeOutput: TExeOutput): QWord;virtual;
  126. function GetBssSize(aExeOutput: TExeOutput): QWord;virtual;
  127. function ExecutableFilename:String;virtual;
  128. function SharedLibFilename:String;virtual;
  129. public
  130. IsSharedLibrary : boolean;
  131. UseStabs : boolean;
  132. Constructor Create;override;
  133. Destructor Destroy;override;
  134. Function MakeExecutable:boolean;override;
  135. Function MakeSharedLibrary:boolean;override;
  136. procedure AddImportSymbol(const libname,symname,symmangledname:TCmdStr;OrdNr: longint;isvar:boolean);override;
  137. end;
  138. TLinkerClass = class of Tlinker;
  139. var
  140. Linker : TLinker;
  141. function FindObjectFile(s : TCmdStr;const unitpath:TCmdStr;isunit:boolean) : TCmdStr;
  142. function FindLibraryFile(s:TCmdStr;const prefix,ext:TCmdStr;var foundfile : TCmdStr) : boolean;
  143. function FindDLL(const s:TCmdStr;var founddll:TCmdStr):boolean;
  144. procedure RegisterLinker(id:tlink;c:TLinkerClass);
  145. procedure InitLinker;
  146. procedure DoneLinker;
  147. Implementation
  148. uses
  149. cutils,cfileutl,cstreams,
  150. {$ifdef hasUnix}
  151. baseunix,
  152. {$endif hasUnix}
  153. cscript,globals,verbose,comphook,ppu,fpchash,triplet,
  154. aasmbase,aasmcpu,
  155. ogmap;
  156. var
  157. CLinker : array[tlink] of TLinkerClass;
  158. {*****************************************************************************
  159. Helpers
  160. *****************************************************************************}
  161. function GetFileCRC(const fn:TPathStr):cardinal;
  162. var
  163. fs : TCStream;
  164. bufcount,
  165. bufsize : Integer;
  166. buf : pbyte;
  167. begin
  168. result:=0;
  169. bufsize:=64*1024;
  170. fs:=CFileStreamClass.Create(fn,fmOpenRead or fmShareDenyNone);
  171. if CStreamError<>0 then
  172. begin
  173. fs.Free;
  174. Comment(V_Error,'Can''t open file: '+fn);
  175. exit;
  176. end;
  177. getmem(buf,bufsize);
  178. repeat
  179. bufcount:=fs.Read(buf^,bufsize);
  180. result:=UpdateCrc32(result,buf^,bufcount);
  181. until bufcount<bufsize;
  182. freemem(buf);
  183. fs.Free;
  184. end;
  185. { searches an object file }
  186. function FindObjectFile(s:TCmdStr;const unitpath:TCmdStr;isunit:boolean) : TCmdStr;
  187. var
  188. found : boolean;
  189. foundfile : TCmdStr;
  190. begin
  191. findobjectfile:='';
  192. if s='' then
  193. exit;
  194. {When linking on target, the units has not been assembled yet,
  195. if assembling is also done on target,
  196. so there is no object files to look for at
  197. the host. Look for the corresponding assembler file instead,
  198. because it will be assembled to object file on the target.}
  199. if isunit and (cs_assemble_on_target in current_settings.globalswitches) then
  200. s:=ChangeFileExt(s,target_info.asmext);
  201. { when it does not belong to the unit then check if
  202. the specified file exists without searching any paths }
  203. if not isunit then
  204. begin
  205. if FileExists(FixFileName(s),false) then
  206. begin
  207. foundfile:=ScriptFixFileName(s);
  208. found:=true;
  209. end;
  210. end;
  211. if pos('.',s)=0 then
  212. s:=s+target_info.objext;
  213. { find object file
  214. 1. output unit path
  215. 2. output exe path
  216. 3. specified unit path (if specified)
  217. 4. cwd
  218. 5. unit search path
  219. 6. local object path
  220. 7. global object path
  221. 8. exepath (not when linking on target)
  222. for all finds don't use the directory caching }
  223. found:=false;
  224. if isunit and (OutputUnitDir<>'') then
  225. found:=FindFile(s,OutPutUnitDir,false,foundfile)
  226. else
  227. if OutputExeDir<>'' then
  228. found:=FindFile(s,OutPutExeDir,false,foundfile);
  229. if (not found) and (unitpath<>'') then
  230. found:=FindFile(s,unitpath,false,foundfile);
  231. if (not found) then
  232. found:=FindFile(s, CurDirRelPath(source_info),false,foundfile);
  233. if (not found) then
  234. found:=UnitSearchPath.FindFile(s,false,foundfile);
  235. if (not found) then
  236. found:=current_module.localobjectsearchpath.FindFile(s,false,foundfile);
  237. if (not found) then
  238. found:=objectsearchpath.FindFile(s,false,foundfile);
  239. if not(cs_link_on_target in current_settings.globalswitches) and (not found) then
  240. found:=FindFile(s,exepath,false,foundfile);
  241. if not(cs_link_nolink in current_settings.globalswitches) and (not found) then
  242. Message1(exec_w_objfile_not_found,s);
  243. {Restore file extension}
  244. if isunit and (cs_assemble_on_target in current_settings.globalswitches) then
  245. foundfile:= ChangeFileExt(foundfile,target_info.objext);
  246. findobjectfile:=ScriptFixFileName(foundfile);
  247. end;
  248. { searches a (windows) DLL file }
  249. function FindDLL(const s:TCmdStr;var founddll:TCmdStr):boolean;
  250. var
  251. sysdir : TCmdStr;
  252. Found : boolean;
  253. begin
  254. Found:=false;
  255. { Look for DLL in:
  256. 1. Current dir
  257. 2. Library Path
  258. 3. windir,windir/system,windir/system32 }
  259. Found:=FindFile(s,'.'+source_info.DirSep,false,founddll);
  260. if (not found) then
  261. Found:=librarysearchpath.FindFile(s,false,founddll);
  262. { when cross compiling, it is pretty useless to search windir etc. for dlls }
  263. if (not found) and (source_info.system=target_info.system) then
  264. begin
  265. sysdir:=FixPath(GetEnvironmentVariable('windir'),false);
  266. Found:=FindFile(s,sysdir+';'+sysdir+'system'+source_info.DirSep+';'+sysdir+'system32'+source_info.DirSep,false,founddll);
  267. end;
  268. if (not found) then
  269. begin
  270. message1(exec_w_libfile_not_found,s);
  271. FoundDll:=s;
  272. end;
  273. FindDll:=Found;
  274. end;
  275. { searches an library file }
  276. function FindLibraryFile(s:TCmdStr;const prefix,ext:TCmdStr;var foundfile : TCmdStr) : boolean;
  277. var
  278. found : boolean;
  279. paths : TCmdStr;
  280. begin
  281. findlibraryfile:=false;
  282. foundfile:=s;
  283. if s='' then
  284. exit;
  285. { split path from filename }
  286. paths:=ExtractFilePath(s);
  287. s:=ExtractFileName(s);
  288. { add prefix 'lib' }
  289. if (prefix<>'') and (Copy(s,1,length(prefix))<>prefix) then
  290. s:=prefix+s;
  291. { add extension }
  292. if (ext<>'') and (Copy(s,length(s)-length(ext)+1,length(ext))<>ext) then
  293. s:=s+ext;
  294. { readd the split path }
  295. s:=paths+s;
  296. if FileExists(s,false) then
  297. begin
  298. foundfile:=ScriptFixFileName(s);
  299. FindLibraryFile:=true;
  300. exit;
  301. end;
  302. { find libary
  303. 1. cwd
  304. 2. local libary dir
  305. 3. global libary dir
  306. 4. exe path of the compiler (not when linking on target)
  307. for all searches don't use the directory cache }
  308. found:=FindFile(s, CurDirRelPath(source_info), false,foundfile);
  309. if (not found) and (current_module.outputpath<>'') then
  310. found:=FindFile(s,current_module.outputpath,false,foundfile);
  311. if (not found) then
  312. found:=current_module.locallibrarysearchpath.FindFile(s,false,foundfile);
  313. if (not found) then
  314. found:=librarysearchpath.FindFile(s,false,foundfile);
  315. if not(cs_link_on_target in current_settings.globalswitches) and (not found) then
  316. found:=FindFile(s,exepath,false,foundfile);
  317. foundfile:=ScriptFixFileName(foundfile);
  318. findlibraryfile:=found;
  319. end;
  320. {*****************************************************************************
  321. TLINKER
  322. *****************************************************************************}
  323. Constructor TLinker.Create;
  324. begin
  325. Inherited Create;
  326. ObjectFiles:=TCmdStrList.Create_no_double;
  327. SharedLibFiles:=TCmdStrList.Create_no_double;
  328. StaticLibFiles:=TCmdStrList.Create_no_double;
  329. FrameworkFiles:=TCmdStrList.Create_no_double;
  330. OrderedSymbols:=TCmdStrList.Create;
  331. end;
  332. Destructor TLinker.Destroy;
  333. begin
  334. ObjectFiles.Free;
  335. SharedLibFiles.Free;
  336. StaticLibFiles.Free;
  337. FrameworkFiles.Free;
  338. OrderedSymbols.Free;
  339. inherited;
  340. end;
  341. procedure TLinker.AddModuleFiles(hp:tmodule);
  342. var
  343. mask : longint;
  344. i,j : longint;
  345. ImportLibrary : TImportLibrary;
  346. ImportSymbol : TImportSymbol;
  347. begin
  348. with hp do
  349. begin
  350. if mf_has_resourcefiles in moduleflags then
  351. HasResources:=true;
  352. if mf_has_exports in moduleflags then
  353. HasExports:=true;
  354. { link unit files }
  355. if (headerflags and uf_no_link)=0 then
  356. begin
  357. { create mask which unit files need linking }
  358. mask:=link_always;
  359. { lto linking ?}
  360. if (cs_lto in current_settings.moduleswitches) and
  361. ((headerflags and uf_lto_linked)<>0) and
  362. (not(cs_lto_nosystem in init_settings.globalswitches) or
  363. (hp.modulename^<>'SYSTEM')) then
  364. begin
  365. mask:=mask or link_lto;
  366. end
  367. else
  368. begin
  369. { static linking ? }
  370. if (cs_link_static in current_settings.globalswitches) then
  371. begin
  372. if (headerflags and uf_static_linked)=0 then
  373. begin
  374. { if static not avail then try smart linking }
  375. if (headerflags and uf_smart_linked)<>0 then
  376. begin
  377. Message1(exec_t_unit_not_static_linkable_switch_to_smart,modulename^);
  378. mask:=mask or link_smart;
  379. end
  380. else
  381. Message1(exec_e_unit_not_smart_or_static_linkable,modulename^);
  382. end
  383. else
  384. mask:=mask or link_static;
  385. end;
  386. { smart linking ? }
  387. if (cs_link_smart in current_settings.globalswitches) then
  388. begin
  389. if (headerflags and uf_smart_linked)=0 then
  390. begin
  391. { if smart not avail then try static linking }
  392. if (headerflags and uf_static_linked)<>0 then
  393. begin
  394. { if not create_smartlink_library, then smart linking happens using the
  395. regular object files
  396. }
  397. if create_smartlink_library then
  398. Message1(exec_t_unit_not_smart_linkable_switch_to_static,modulename^);
  399. mask:=mask or link_static;
  400. end
  401. else
  402. Message1(exec_e_unit_not_smart_or_static_linkable,modulename^);
  403. end
  404. else
  405. mask:=mask or link_smart;
  406. end;
  407. { shared linking }
  408. if (cs_link_shared in current_settings.globalswitches) then
  409. begin
  410. if (headerflags and uf_shared_linked)=0 then
  411. begin
  412. { if shared not avail then try static linking }
  413. if (headerflags and uf_static_linked)<>0 then
  414. begin
  415. Message1(exec_t_unit_not_shared_linkable_switch_to_static,modulename^);
  416. mask:=mask or link_static;
  417. end
  418. else
  419. Message1(exec_e_unit_not_shared_or_static_linkable,modulename^);
  420. end
  421. else
  422. mask:=mask or link_shared;
  423. end;
  424. end;
  425. { unit files }
  426. while not linkunitofiles.empty do
  427. AddObject(linkunitofiles.getusemask(mask),path,true);
  428. while not linkunitstaticlibs.empty do
  429. AddStaticLibrary(linkunitstaticlibs.getusemask(mask));
  430. while not linkunitsharedlibs.empty do
  431. AddSharedLibrary(linkunitsharedlibs.getusemask(mask));
  432. end;
  433. { Other needed .o and libs, specified using $L,$LINKLIB,external }
  434. mask:=link_always;
  435. while not linkotherofiles.empty do
  436. AddObject(linkotherofiles.Getusemask(mask),path,false);
  437. while not linkotherstaticlibs.empty do
  438. AddStaticCLibrary(linkotherstaticlibs.Getusemask(mask));
  439. while not linkothersharedlibs.empty do
  440. AddSharedCLibrary(linkothersharedlibs.Getusemask(mask));
  441. while not linkotherframeworks.empty do
  442. AddFramework(linkotherframeworks.Getusemask(mask));
  443. { Known Library/DLL Imports }
  444. for i:=0 to ImportLibraryList.Count-1 do
  445. begin
  446. ImportLibrary:=TImportLibrary(ImportLibraryList[i]);
  447. for j:=0 to ImportLibrary.ImportSymbolList.Count-1 do
  448. begin
  449. ImportSymbol:=TImportSymbol(ImportLibrary.ImportSymbolList[j]);
  450. AddImportSymbol(ImportLibrary.Name,ImportSymbol.Name,
  451. ImportSymbol.MangledName,ImportSymbol.OrdNr,ImportSymbol.IsVar);
  452. end;
  453. end;
  454. { ordered symbols }
  455. OrderedSymbols.concatList(linkorderedsymbols);
  456. end;
  457. end;
  458. procedure TLinker.AddImportSymbol(const libname,symname,symmangledname:TCmdStr;OrdNr: longint;isvar:boolean);
  459. begin
  460. end;
  461. Procedure TLinker.AddObject(const S,unitpath : TPathStr;isunit:boolean);
  462. begin
  463. ObjectFiles.Concat(FindObjectFile(s,unitpath,isunit))
  464. end;
  465. Procedure TLinker.AddSharedLibrary(S:TCmdStr);
  466. begin
  467. if s='' then
  468. exit;
  469. { remove prefix 'lib' }
  470. if Copy(s,1,length(target_info.sharedlibprefix))=target_info.sharedlibprefix then
  471. Delete(s,1,length(target_info.sharedlibprefix));
  472. { remove extension if any }
  473. if Copy(s,length(s)-length(target_info.sharedlibext)+1,length(target_info.sharedlibext))=target_info.sharedlibext then
  474. Delete(s,length(s)-length(target_info.sharedlibext)+1,length(target_info.sharedlibext)+1);
  475. { ready to be added }
  476. SharedLibFiles.Concat(S);
  477. end;
  478. Procedure TLinker.AddStaticLibrary(const S:TCmdStr);
  479. var
  480. ns : TCmdStr;
  481. found : boolean;
  482. begin
  483. if s='' then
  484. exit;
  485. found:=FindLibraryFile(s,target_info.staticlibprefix,target_info.staticlibext,ns);
  486. if not(cs_link_nolink in current_settings.globalswitches) and (not found) then
  487. Message1(exec_w_libfile_not_found,s);
  488. StaticLibFiles.Concat(ns);
  489. end;
  490. Procedure TLinker.AddSharedCLibrary(S:TCmdStr);
  491. begin
  492. if s='' then
  493. exit;
  494. { remove prefix 'lib' }
  495. if Copy(s,1,length(target_info.sharedclibprefix))=target_info.sharedclibprefix then
  496. Delete(s,1,length(target_info.sharedclibprefix));
  497. { remove extension if any }
  498. if Copy(s,length(s)-length(target_info.sharedclibext)+1,length(target_info.sharedclibext))=target_info.sharedclibext then
  499. Delete(s,length(s)-length(target_info.sharedclibext)+1,length(target_info.sharedclibext)+1);
  500. { ready to be added }
  501. SharedLibFiles.Concat(S);
  502. end;
  503. Procedure TLinker.AddFramework(S:TCmdStr);
  504. begin
  505. if s='' then
  506. exit;
  507. { ready to be added }
  508. FrameworkFiles.Concat(S);
  509. end;
  510. procedure TLinker.AddOrderedSymbol(const s: TCmdStr);
  511. begin
  512. OrderedSymbols.Concat(s);
  513. end;
  514. Procedure TLinker.AddStaticCLibrary(const S:TCmdStr);
  515. var
  516. ns : TCmdStr;
  517. found : boolean;
  518. begin
  519. if s='' then
  520. exit;
  521. found:=FindLibraryFile(s,target_info.staticclibprefix,target_info.staticclibext,ns);
  522. if not(cs_link_nolink in current_settings.globalswitches) and (not found) then
  523. Message1(exec_w_libfile_not_found,s);
  524. StaticLibFiles.Concat(ns);
  525. end;
  526. procedure TLinker.InitSysInitUnitName;
  527. begin
  528. end;
  529. function TLinker.MakeExecutable:boolean;
  530. begin
  531. MakeExecutable:=false;
  532. Message(exec_e_exe_not_supported);
  533. end;
  534. Function TLinker.MakeSharedLibrary:boolean;
  535. begin
  536. MakeSharedLibrary:=false;
  537. Message(exec_e_dll_not_supported);
  538. end;
  539. Function TLinker.MakeStaticLibrary:boolean;
  540. begin
  541. MakeStaticLibrary:=false;
  542. Message(exec_e_static_lib_not_supported);
  543. end;
  544. Procedure TLinker.ExpandAndApplyOrder(var Src:TCmdStrList);
  545. var
  546. p : TLinkStrMap;
  547. i : longint;
  548. begin
  549. // call Virtual TLinker method to initialize
  550. LoadPredefinedLibraryOrder;
  551. // something to do?
  552. if (LinkLibraryAliases.count=0) and (LinkLibraryOrder.Count=0) Then
  553. exit;
  554. p:=TLinkStrMap.Create;
  555. // expand libaliases, clears src
  556. LinkLibraryAliases.expand(src,p);
  557. // writeln(src.count,' ',p.count,' ',linklibraryorder.count,' ',linklibraryaliases.count);
  558. // apply order
  559. p.UpdateWeights(LinkLibraryOrder);
  560. p.SortOnWeight;
  561. // put back in src
  562. for i:=0 to p.count-1 do
  563. src.insert(p[i].Key);
  564. p.free;
  565. end;
  566. procedure TLinker.LoadPredefinedLibraryOrder;
  567. begin
  568. end;
  569. function TLinker.ReOrderEntries : boolean;
  570. begin
  571. result:=(LinkLibraryOrder.count>0) or (LinkLibraryAliases.count>0);
  572. end;
  573. {*****************************************************************************
  574. TEXTERNALLINKER
  575. *****************************************************************************}
  576. Function TExternalLinker.WriteSymbolOrderFile: TCmdStr;
  577. var
  578. item: TCmdStrListItem;
  579. symfile: TScript;
  580. begin
  581. result:='';
  582. { only for darwin for now; can also enable for other platforms when using
  583. the LLVM linker }
  584. if (OrderedSymbols.Empty) or
  585. not(tf_supports_symbolorderfile in target_info.flags) then
  586. exit;
  587. symfile:=TScript.Create(outputexedir+UniqueName('symbol_order')+'.fpc');
  588. item:=TCmdStrListItem(OrderedSymbols.First);
  589. while assigned(item) do
  590. begin
  591. symfile.add(item.str);
  592. item:=TCmdStrListItem(item.next);
  593. end;
  594. symfile.WriteToDisk;
  595. result:=symfile.fn;
  596. symfile.Free;
  597. end;
  598. Function TExternalLinker.GetSanitizersLibraryNameAndPath(const platformname, asanlibinfix: TCmdStr; out sanitizerLibraryDir, asanLibraryPath: TCmdStr): boolean;
  599. var
  600. clang,
  601. clangsearchdirs,
  602. textline,
  603. clangsearchdirspath: TCmdStr;
  604. searchrec: TSearchRec;
  605. searchres: longint;
  606. clangsearchdirsfile: text;
  607. begin
  608. result:=false;
  609. if (cs_sanitize_address in current_settings.moduleswitches) and
  610. not(cs_link_on_target in current_settings.globalswitches) then
  611. begin
  612. { ask clang }
  613. clang:=FindUtil('clang'+llvmutilssuffix);
  614. if clang<>'' then
  615. begin
  616. clangsearchdirspath:=outputexedir+UniqueName('clangsearchdirs');
  617. searchres:=shell(maybequoted(clang)+' -target '+targettriplet(triplet_llvm)+' -print-file-name=lib > '+maybequoted(clangsearchdirspath));
  618. if searchres=0 then
  619. begin
  620. AssignFile(clangsearchdirsfile,clangsearchdirspath);
  621. {$push}{$i-}
  622. reset(clangsearchdirsfile);
  623. {$pop}
  624. if ioresult=0 then
  625. begin
  626. readln(clangsearchdirsfile,textline);
  627. sanitizerLibraryDir:=FixFileName(textline+'/'+platformname);
  628. asanLibraryPath:=FixFileName(sanitizerLibraryDir+'/')+target_info.sharedClibprefix+'clang_rt.asan_'+asanlibinfix+'_dynamic'+target_info.sharedClibext;
  629. result:=FileExists(asanLibraryPath,false);
  630. end;
  631. end;
  632. if FileExists(clangsearchdirspath,false) then
  633. DeleteFile(clangsearchdirspath);
  634. end;
  635. end;
  636. end;
  637. Constructor TExternalLinker.Create;
  638. begin
  639. inherited Create;
  640. { set generic defaults }
  641. FillChar(Info,sizeof(Info),0);
  642. if cs_link_on_target in current_settings.globalswitches then
  643. begin
  644. Info.ResName:=ChangeFileExt(inputfilename,'_link.res');
  645. Info.ScriptName:=ChangeFileExt(inputfilename,'_script.res');
  646. end
  647. else
  648. begin
  649. Info.ResName:=UniqueName('link')+'.res';
  650. Info.ScriptName:=UniqueName('script')+'.res';
  651. end;
  652. { set the linker specific defaults }
  653. SetDefaultInfo;
  654. { Allow Parameter overrides for linker info }
  655. with Info do
  656. begin
  657. if ParaLinkOptions<>'' then
  658. ExtraOptions:=ParaLinkOptions;
  659. if ParaDynamicLinker<>'' then
  660. DynamicLinker:=ParaDynamicLinker;
  661. end;
  662. end;
  663. Destructor TExternalLinker.Destroy;
  664. begin
  665. inherited destroy;
  666. end;
  667. Procedure TExternalLinker.SetDefaultInfo;
  668. begin
  669. end;
  670. Function TExternalLinker.FindUtil(const s:TCmdStr):TCmdStr;
  671. var
  672. Found : boolean;
  673. FoundBin : TCmdStr;
  674. UtilExe : TCmdStr;
  675. begin
  676. if cs_link_on_target in current_settings.globalswitches then
  677. begin
  678. { If linking on target, don't add any path PM }
  679. { change extension only on platforms that use an exe extension, otherwise on OpenBSD 'ld.bfd' gets
  680. converted to 'ld' }
  681. if target_info.exeext<>'' then
  682. FindUtil:=ChangeFileExt(s,target_info.exeext)
  683. else
  684. FindUtil:=s;
  685. exit;
  686. end;
  687. { change extension only on platforms that use an exe extension, otherwise on OpenBSD 'ld.bfd' gets converted
  688. to 'ld' }
  689. if source_info.exeext<>'' then
  690. UtilExe:=ChangeFileExt(s,source_info.exeext)
  691. else
  692. UtilExe:=s;
  693. FoundBin:='';
  694. Found:=false;
  695. if utilsdirectory<>'' then
  696. Found:=FindFile(utilexe,utilsdirectory,false,Foundbin);
  697. if (not Found) then
  698. Found:=FindExe(utilexe,false,Foundbin);
  699. if (not Found) and not(cs_link_nolink in current_settings.globalswitches) then
  700. begin
  701. Message1(exec_e_util_not_found,utilexe);
  702. current_settings.globalswitches:=current_settings.globalswitches+[cs_link_nolink];
  703. end;
  704. if (FoundBin<>'') then
  705. Message1(exec_t_using_util,FoundBin);
  706. FindUtil:=FoundBin;
  707. end;
  708. Function TExternalLinker.CatFileContent(para : TCmdStr) : TCmdStr;
  709. var
  710. filecontent : TCmdStr;
  711. f : text;
  712. st : TCmdStr;
  713. begin
  714. if not (tf_no_backquote_support in source_info.flags) or
  715. (cs_link_on_target in current_settings.globalswitches) then
  716. begin
  717. CatFileContent:='`cat '+MaybeQuoted(para)+'`';
  718. Exit;
  719. end;
  720. assign(f,para);
  721. filecontent:='';
  722. {$push}{$I-}
  723. reset(f);
  724. {$pop}
  725. if IOResult<>0 then
  726. begin
  727. Message1(exec_n_backquote_cat_file_not_found,para);
  728. end
  729. else
  730. begin
  731. while not eof(f) do
  732. begin
  733. readln(f,st);
  734. if st<>'' then
  735. filecontent:=filecontent+' '+st;
  736. end;
  737. close(f);
  738. end;
  739. CatFileContent:=filecontent;
  740. end;
  741. Function TExternalLinker.DoExec(const command:TCmdStr; para:TCmdStr;showinfo,useshell:boolean):boolean;
  742. var
  743. exitcode: longint;
  744. begin
  745. DoExec:=true;
  746. if not(cs_link_nolink in current_settings.globalswitches) then
  747. begin
  748. FlushOutput;
  749. if useshell then
  750. exitcode:=shell(maybequoted(command)+' '+para)
  751. else
  752. try
  753. exitcode:=RequotedExecuteProcess(command,para);
  754. except on E:EOSError do
  755. begin
  756. Message(exec_e_cant_call_linker);
  757. current_settings.globalswitches:=current_settings.globalswitches+[cs_link_nolink];
  758. DoExec:=false;
  759. end;
  760. end;
  761. if (exitcode<>0) then
  762. begin
  763. Message(exec_e_error_while_linking);
  764. current_settings.globalswitches:=current_settings.globalswitches+[cs_link_nolink];
  765. DoExec:=false;
  766. end;
  767. end;
  768. { Update asmres when externmode is set }
  769. if cs_link_nolink in current_settings.globalswitches then
  770. begin
  771. if showinfo then
  772. begin
  773. if current_module.islibrary then
  774. AsmRes.AddLinkCommand(Command,Para,current_module.sharedlibfilename)
  775. else
  776. AsmRes.AddLinkCommand(Command,Para,current_module.exefilename);
  777. end
  778. else
  779. AsmRes.AddLinkCommand(Command,Para,'');
  780. end;
  781. end;
  782. Function TExternalLinker.MakeStaticLibrary:boolean;
  783. function GetNextFiles(const maxCmdLength : Longint; var item : TCmdStrListItem; const addfilecmd : string) : TCmdStr;
  784. begin
  785. result := '';
  786. while (assigned(item) and ((length(result) + length(item.str) + 1) < maxCmdLength)) do begin
  787. result := result + ' ' + addfilecmd + item.str;
  788. item := TCmdStrListItem(item.next);
  789. end;
  790. end;
  791. function get_wlib_record_size: integer;
  792. begin
  793. result:=align(align(SmartLinkOFiles.Count,128) div 128,16);
  794. end;
  795. var
  796. binstr, firstbinstr, scriptfile : TCmdStr;
  797. cmdstr, firstcmd, nextcmd, smartpath : TCmdStr;
  798. current : TCmdStrListItem;
  799. script: Text;
  800. scripted_ar : boolean;
  801. ar_creates_different_output_file : boolean;
  802. success : boolean;
  803. first : boolean;
  804. begin
  805. MakeStaticLibrary:=false;
  806. { remove the library, to be sure that it is rewritten }
  807. DeleteFile(current_module.staticlibfilename);
  808. { Call AR }
  809. smartpath:=FixPath(ChangeFileExt(current_module.asmfilename,target_info.smartext),false);
  810. SplitBinCmd(target_ar.arcmd,binstr,cmdstr);
  811. binstr := FindUtil(utilsprefix + binstr);
  812. if target_ar.arfirstcmd<>'' then
  813. begin
  814. SplitBinCmd(target_ar.arfirstcmd,firstbinstr,firstcmd);
  815. firstbinstr := FindUtil(utilsprefix + firstbinstr);
  816. end
  817. else
  818. begin
  819. firstbinstr:=binstr;
  820. firstcmd:=cmdstr;
  821. end;
  822. scripted_ar:=(target_ar.id=ar_gnu_ar_scripted) or
  823. (target_ar.id=ar_watcom_wlib_omf_scripted) or
  824. (target_ar.id=ar_sdcc_sdar_scripted);
  825. if scripted_ar then
  826. begin
  827. scriptfile := FixFileName(smartpath+'arscript.txt');
  828. Replace(cmdstr,'$SCRIPT',maybequoted(scriptfile));
  829. Assign(script, scriptfile);
  830. Rewrite(script);
  831. try
  832. if (target_ar.id in [ar_gnu_ar_scripted,ar_sdcc_sdar_scripted]) then
  833. writeln(script, 'CREATE ' + current_module.staticlibfilename)
  834. else { wlib case }
  835. writeln(script,'-q -p=',get_wlib_record_size,' -fo -c -b '+
  836. maybequoted(current_module.staticlibfilename));
  837. current := TCmdStrListItem(SmartLinkOFiles.First);
  838. while current <> nil do
  839. begin
  840. if (target_ar.id in [ar_gnu_ar_scripted,ar_sdcc_sdar_scripted]) then
  841. writeln(script, 'ADDMOD ' + current.str)
  842. else
  843. writeln(script,'+' + current.str);
  844. current := TCmdStrListItem(current.next);
  845. end;
  846. if (target_ar.id in [ar_gnu_ar_scripted,ar_sdcc_sdar_scripted]) then
  847. begin
  848. writeln(script, 'SAVE');
  849. writeln(script, 'END');
  850. end;
  851. finally
  852. Close(script);
  853. end;
  854. success:=DoExec(binstr,cmdstr,false,true);
  855. end
  856. else
  857. begin
  858. ar_creates_different_output_file:=(Pos('$OUTPUTLIB',cmdstr)>0) or (Pos('$OUTPUTLIB',firstcmd)>0);
  859. Replace(cmdstr,'$LIB',maybequoted(current_module.staticlibfilename));
  860. Replace(firstcmd,'$LIB',maybequoted(current_module.staticlibfilename));
  861. Replace(cmdstr,'$OUTPUTLIB',maybequoted(current_module.staticlibfilename+'.tmp'));
  862. Replace(firstcmd,'$OUTPUTLIB',maybequoted(current_module.staticlibfilename+'.tmp'));
  863. if target_ar.id=ar_watcom_wlib_omf then
  864. begin
  865. Replace(cmdstr,'$RECSIZE','-p='+IntToStr(get_wlib_record_size));
  866. Replace(firstcmd,'$RECSIZE','-p='+IntToStr(get_wlib_record_size));
  867. end;
  868. { create AR commands }
  869. success := true;
  870. current := TCmdStrListItem(SmartLinkOFiles.First);
  871. first := true;
  872. repeat
  873. if first then
  874. nextcmd := firstcmd
  875. else
  876. nextcmd := cmdstr;
  877. Replace(nextcmd,'$FILES',GetNextFiles(2047, current, target_ar.addfilecmd));
  878. if first then
  879. success:=DoExec(firstbinstr,nextcmd,false,true)
  880. else
  881. success:=DoExec(binstr,nextcmd,false,true);
  882. if ar_creates_different_output_file then
  883. begin
  884. if FileExists(current_module.staticlibfilename,false) then
  885. DeleteFile(current_module.staticlibfilename);
  886. if FileExists(current_module.staticlibfilename+'.tmp',false) then
  887. RenameFile(current_module.staticlibfilename+'.tmp',current_module.staticlibfilename);
  888. end;
  889. first := false;
  890. until (not assigned(current)) or (not success);
  891. end;
  892. if (target_ar.arfinishcmd <> '') then
  893. begin
  894. SplitBinCmd(target_ar.arfinishcmd,binstr,cmdstr);
  895. binstr := FindUtil(utilsprefix + binstr);
  896. Replace(cmdstr,'$LIB',maybequoted(current_module.staticlibfilename));
  897. success:=DoExec(binstr,cmdstr,false,true);
  898. end;
  899. { Clean up }
  900. if not(cs_asm_leave in current_settings.globalswitches) then
  901. if not(cs_link_nolink in current_settings.globalswitches) then
  902. begin
  903. while not SmartLinkOFiles.Empty do
  904. DeleteFile(SmartLinkOFiles.GetFirst);
  905. if scripted_ar then
  906. DeleteFile(scriptfile);
  907. RemoveDir(smartpath);
  908. end
  909. else
  910. begin
  911. while not SmartLinkOFiles.Empty do
  912. AsmRes.AddDeleteCommand(SmartLinkOFiles.GetFirst);
  913. if scripted_ar then
  914. AsmRes.AddDeleteCommand(scriptfile);
  915. AsmRes.AddDeleteDirCommand(smartpath);
  916. end;
  917. MakeStaticLibrary:=success;
  918. end;
  919. function TExternalLinker.UniqueName(const str: TCmdStr): TCmdStr;
  920. const
  921. pid: SizeUInt = 0;
  922. begin
  923. if pid=0 then
  924. pid:=GetProcessID;
  925. if pid>0 then
  926. result:=str+tostr(pid)
  927. else
  928. result:=str;
  929. end;
  930. function TExternalLinker.PostProcessELFExecutable(const fn : string;isdll:boolean):boolean;
  931. type
  932. TElf32header=packed record
  933. magic0123 : array[0..3] of char;
  934. file_class : byte;
  935. data_encoding : byte;
  936. file_version : byte;
  937. padding : array[$07..$0f] of byte;
  938. e_type : word;
  939. e_machine : word;
  940. e_version : longint;
  941. e_entry : longint; { entrypoint }
  942. e_phoff : longint; { program header offset }
  943. e_shoff : longint; { sections header offset }
  944. e_flags : longint;
  945. e_ehsize : word; { elf header size in bytes }
  946. e_phentsize : word; { size of an entry in the program header array }
  947. e_phnum : word; { 0..e_phnum-1 of entrys }
  948. e_shentsize : word; { size of an entry in sections header array }
  949. e_shnum : word; { 0..e_shnum-1 of entrys }
  950. e_shstrndx : word; { index of string section header }
  951. end;
  952. TElf32sechdr=packed record
  953. sh_name : longint;
  954. sh_type : longint;
  955. sh_flags : longint;
  956. sh_addr : longint;
  957. sh_offset : longint;
  958. sh_size : longint;
  959. sh_link : longint;
  960. sh_info : longint;
  961. sh_addralign : longint;
  962. sh_entsize : longint;
  963. end;
  964. telf64header=packed record
  965. magic0123 : array[0..3] of char;
  966. file_class : byte;
  967. data_encoding : byte;
  968. file_version : byte;
  969. padding : array[$07..$0f] of byte;
  970. e_type : word;
  971. e_machine : word;
  972. e_version : longword;
  973. e_entry : qword; { entrypoint }
  974. e_phoff : qword; { program header offset }
  975. e_shoff : qword; { sections header offset }
  976. e_flags : longword;
  977. e_ehsize : word; { elf header size in bytes }
  978. e_phentsize : word; { size of an entry in the program header array }
  979. e_phnum : word; { 0..e_phnum-1 of entrys }
  980. e_shentsize : word; { size of an entry in sections header array }
  981. e_shnum : word; { 0..e_shnum-1 of entrys }
  982. e_shstrndx : word; { index of string section header }
  983. end;
  984. TElf64sechdr=packed record
  985. sh_name : longword;
  986. sh_type : longword;
  987. sh_flags : qword;
  988. sh_addr : qword;
  989. sh_offset : qword;
  990. sh_size : qword;
  991. sh_link : longword;
  992. sh_info : longword;
  993. sh_addralign : qword;
  994. sh_entsize : qword;
  995. end;
  996. function MayBeSwapHeader(h : telf32header) : telf32header;
  997. begin
  998. result:=h;
  999. if source_info.endian<>target_info.endian then
  1000. with h do
  1001. begin
  1002. result.e_type:=swapendian(e_type);
  1003. result.e_machine:=swapendian(e_machine);
  1004. result.e_version:=swapendian(e_version);
  1005. result.e_entry:=swapendian(e_entry);
  1006. result.e_phoff:=swapendian(e_phoff);
  1007. result.e_shoff:=swapendian(e_shoff);
  1008. result.e_flags:=swapendian(e_flags);
  1009. result.e_ehsize:=swapendian(e_ehsize);
  1010. result.e_phentsize:=swapendian(e_phentsize);
  1011. result.e_phnum:=swapendian(e_phnum);
  1012. result.e_shentsize:=swapendian(e_shentsize);
  1013. result.e_shnum:=swapendian(e_shnum);
  1014. result.e_shstrndx:=swapendian(e_shstrndx);
  1015. end;
  1016. end;
  1017. function MayBeSwapHeader(h : telf64header) : telf64header;
  1018. begin
  1019. result:=h;
  1020. if source_info.endian<>target_info.endian then
  1021. with h do
  1022. begin
  1023. result.e_type:=swapendian(e_type);
  1024. result.e_machine:=swapendian(e_machine);
  1025. result.e_version:=swapendian(e_version);
  1026. result.e_entry:=swapendian(e_entry);
  1027. result.e_phoff:=swapendian(e_phoff);
  1028. result.e_shoff:=swapendian(e_shoff);
  1029. result.e_flags:=swapendian(e_flags);
  1030. result.e_ehsize:=swapendian(e_ehsize);
  1031. result.e_phentsize:=swapendian(e_phentsize);
  1032. result.e_phnum:=swapendian(e_phnum);
  1033. result.e_shentsize:=swapendian(e_shentsize);
  1034. result.e_shnum:=swapendian(e_shnum);
  1035. result.e_shstrndx:=swapendian(e_shstrndx);
  1036. end;
  1037. end;
  1038. function MaybeSwapSecHeader(h : telf32sechdr) : telf32sechdr;
  1039. begin
  1040. result:=h;
  1041. if source_info.endian<>target_info.endian then
  1042. with h do
  1043. begin
  1044. result.sh_name:=swapendian(sh_name);
  1045. result.sh_type:=swapendian(sh_type);
  1046. result.sh_flags:=swapendian(sh_flags);
  1047. result.sh_addr:=swapendian(sh_addr);
  1048. result.sh_offset:=swapendian(sh_offset);
  1049. result.sh_size:=swapendian(sh_size);
  1050. result.sh_link:=swapendian(sh_link);
  1051. result.sh_info:=swapendian(sh_info);
  1052. result.sh_addralign:=swapendian(sh_addralign);
  1053. result.sh_entsize:=swapendian(sh_entsize);
  1054. end;
  1055. end;
  1056. function MaybeSwapSecHeader(h : telf64sechdr) : telf64sechdr;
  1057. begin
  1058. result:=h;
  1059. if source_info.endian<>target_info.endian then
  1060. with h do
  1061. begin
  1062. result.sh_name:=swapendian(sh_name);
  1063. result.sh_type:=swapendian(sh_type);
  1064. result.sh_flags:=swapendian(sh_flags);
  1065. result.sh_addr:=swapendian(sh_addr);
  1066. result.sh_offset:=swapendian(sh_offset);
  1067. result.sh_size:=swapendian(sh_size);
  1068. result.sh_link:=swapendian(sh_link);
  1069. result.sh_info:=swapendian(sh_info);
  1070. result.sh_addralign:=swapendian(sh_addralign);
  1071. result.sh_entsize:=swapendian(sh_entsize);
  1072. end;
  1073. end;
  1074. var
  1075. f : file;
  1076. function ReadSectionName(pos : longint) : String;
  1077. var
  1078. oldpos : longint;
  1079. c : char;
  1080. begin
  1081. oldpos:=filepos(f);
  1082. seek(f,pos);
  1083. Result:='';
  1084. while true do
  1085. begin
  1086. blockread(f,c,1);
  1087. if c=#0 then
  1088. break;
  1089. Result:=Result+c;
  1090. end;
  1091. seek(f,oldpos);
  1092. end;
  1093. var
  1094. elfheader32 : TElf32header;
  1095. secheader32 : TElf32sechdr;
  1096. elfheader64 : TElf64header;
  1097. secheader64 : TElf64sechdr;
  1098. i : longint;
  1099. stringoffset : longint;
  1100. secname : string;
  1101. begin
  1102. Result:=false;
  1103. { open file }
  1104. assign(f,fn);
  1105. {$push}{$I-}
  1106. reset(f,1);
  1107. if ioresult<>0 then
  1108. Message1(execinfo_f_cant_open_executable,fn);
  1109. { read header }
  1110. blockread(f,elfheader32,sizeof(tElf32header));
  1111. with elfheader32 do
  1112. if not((magic0123[0]=#$7f) and (magic0123[1]='E') and (magic0123[2]='L') and (magic0123[3]='F')) then
  1113. Exit;
  1114. case elfheader32.file_class of
  1115. 1:
  1116. begin
  1117. elfheader32:=MayBeSwapHeader(elfheader32);
  1118. seek(f,elfheader32.e_shoff);
  1119. { read string section header }
  1120. seek(f,elfheader32.e_shoff+sizeof(TElf32sechdr)*elfheader32.e_shstrndx);
  1121. blockread(f,secheader32,sizeof(secheader32));
  1122. secheader32:=MaybeSwapSecHeader(secheader32);
  1123. stringoffset:=secheader32.sh_offset;
  1124. seek(f,elfheader32.e_shoff);
  1125. status.datasize:=0;
  1126. for i:=0 to elfheader32.e_shnum-1 do
  1127. begin
  1128. blockread(f,secheader32,sizeof(secheader32));
  1129. secheader32:=MaybeSwapSecHeader(secheader32);
  1130. secname:=ReadSectionName(stringoffset+secheader32.sh_name);
  1131. case secname of
  1132. '.text':
  1133. begin
  1134. Message1(execinfo_x_codesize,tostr(secheader32.sh_size));
  1135. status.codesize:=secheader32.sh_size;
  1136. end;
  1137. '.fpcdata',
  1138. '.rodata',
  1139. '.data':
  1140. begin
  1141. Message1(execinfo_x_initdatasize,tostr(secheader32.sh_size));
  1142. inc(status.datasize,secheader32.sh_size);
  1143. end;
  1144. '.bss':
  1145. begin
  1146. Message1(execinfo_x_uninitdatasize,tostr(secheader32.sh_size));
  1147. inc(status.datasize,secheader32.sh_size);
  1148. end;
  1149. end;
  1150. end;
  1151. end;
  1152. 2:
  1153. begin
  1154. seek(f,0);
  1155. blockread(f,elfheader64,sizeof(tElf64header));
  1156. with elfheader64 do
  1157. if not((magic0123[0]=#$7f) and (magic0123[1]='E') and (magic0123[2]='L') and (magic0123[3]='F')) then
  1158. Exit;
  1159. elfheader64:=MayBeSwapHeader(elfheader64);
  1160. seek(f,elfheader64.e_shoff);
  1161. { read string section header }
  1162. seek(f,elfheader64.e_shoff+sizeof(TElf64sechdr)*elfheader64.e_shstrndx);
  1163. blockread(f,secheader64,sizeof(secheader64));
  1164. secheader64:=MaybeSwapSecHeader(secheader64);
  1165. stringoffset:=secheader64.sh_offset;
  1166. seek(f,elfheader64.e_shoff);
  1167. status.datasize:=0;
  1168. for i:=0 to elfheader64.e_shnum-1 do
  1169. begin
  1170. blockread(f,secheader64,sizeof(secheader64));
  1171. secheader64:=MaybeSwapSecHeader(secheader64);
  1172. secname:=ReadSectionName(stringoffset+secheader64.sh_name);
  1173. case secname of
  1174. '.text':
  1175. begin
  1176. Message1(execinfo_x_codesize,tostr(secheader64.sh_size));
  1177. status.codesize:=secheader64.sh_size;
  1178. end;
  1179. '.fpcdata',
  1180. '.rodata',
  1181. '.data':
  1182. begin
  1183. Message1(execinfo_x_initdatasize,tostr(secheader64.sh_size));
  1184. inc(status.datasize,secheader64.sh_size);
  1185. end;
  1186. '.bss':
  1187. begin
  1188. Message1(execinfo_x_uninitdatasize,tostr(secheader64.sh_size));
  1189. inc(status.datasize,secheader64.sh_size);
  1190. end;
  1191. end;
  1192. end;
  1193. end;
  1194. else
  1195. exit;
  1196. end;
  1197. close(f);
  1198. {$pop}
  1199. if ioresult<>0 then
  1200. ;
  1201. Result:=true;
  1202. end;
  1203. function TExternalLinker.PostProcessMachExecutable(const fn : string;isdll:boolean):boolean;
  1204. type
  1205. TMachHeader=record
  1206. magic : longword;
  1207. cputype : integer;
  1208. cpusubtype : integer;
  1209. filetype : longword;
  1210. ncmds : longword;
  1211. sizeofcmds : longword;
  1212. flags : longword;
  1213. reserved : longword;
  1214. end;
  1215. TMachLoadCommand = record
  1216. cmd : longword;
  1217. cmdsize : longword;
  1218. end;
  1219. TMachSegmentCommand64 = record
  1220. segname : array[0..15] of char;
  1221. vmaddr : qword;
  1222. vmsize : qword;
  1223. fileoff : qword;
  1224. filesize : qword;
  1225. maxprot : integer;
  1226. initprot : integer;
  1227. nsects : dword;
  1228. flags : dword;
  1229. end;
  1230. var
  1231. f : file;
  1232. machheader : TMachHeader;
  1233. machloadcmd : TMachLoadCommand;
  1234. machsegmentcommand64 :TMachSegmentCommand64;
  1235. i : longint;
  1236. begin
  1237. Result:=false;
  1238. { open file }
  1239. assign(f,fn);
  1240. {$push}{$I-}
  1241. reset(f,1);
  1242. if ioresult<>0 then
  1243. Message1(execinfo_f_cant_open_executable,fn);
  1244. {$ifdef DEBUG_MACHO_INFO}
  1245. writeln('Start reading Mach-O file');
  1246. {$endif DEBUG_MACHO_INFO}
  1247. blockread(f,machheader,sizeof(TMachHeader));
  1248. if machheader.magic<>$feedfacf then
  1249. Exit;
  1250. {$ifdef DEBUG_MACHO_INFO}
  1251. writeln('Magic header recognized (64 Bit, Little Endian)');
  1252. writeln('Reading ',machheader.ncmds,' commands');
  1253. {$endif DEBUG_MACHO_INFO}
  1254. for i:=1 to machheader.ncmds do
  1255. begin
  1256. blockread(f,machloadcmd,sizeof(machloadcmd));
  1257. case machloadcmd.cmd of
  1258. $19:
  1259. begin
  1260. blockread(f,machsegmentcommand64,sizeof(machsegmentcommand64));
  1261. {$ifdef DEBUG_MACHO_INFO}
  1262. writeln('Found SegmentCommand64: Name = ',StrPas(@machsegmentcommand64.segname),
  1263. '; VMSize = $',hexstr(machsegmentcommand64.vmsize,8),
  1264. '; FileSize = $',hexstr(machsegmentcommand64.filesize,8));
  1265. {$endif DEBUG_MACHO_INFO}
  1266. case StrPas(@machsegmentcommand64.segname) of
  1267. '__TEXT':
  1268. begin
  1269. Message1(execinfo_x_codesize,tostr(machsegmentcommand64.vmsize));
  1270. status.codesize:=machsegmentcommand64.vmsize;
  1271. end;
  1272. '__DATA_CONST':
  1273. begin
  1274. Message1(execinfo_x_initdatasize,tostr(machsegmentcommand64.vmsize));
  1275. inc(status.datasize,machsegmentcommand64.vmsize);
  1276. end;
  1277. '__DATA':
  1278. begin
  1279. Message1(execinfo_x_uninitdatasize,tostr(machsegmentcommand64.vmsize));
  1280. inc(status.datasize,machsegmentcommand64.vmsize);
  1281. end;
  1282. end;
  1283. Seek(f,FilePos(f)+machloadcmd.cmdsize-sizeof(machloadcmd)-sizeof(machsegmentcommand64));
  1284. end;
  1285. else
  1286. begin
  1287. {$ifdef DEBUG_MACHO_INFO}
  1288. writeln('Found Load Command: $',hexstr(machloadcmd.cmd,4),', skipping');
  1289. {$endif DEBUG_MACHO_INFO}
  1290. Seek(f,FilePos(f)+machloadcmd.cmdsize-sizeof(machloadcmd));
  1291. end;
  1292. end;
  1293. end;
  1294. close(f);
  1295. {$pop}
  1296. if ioresult<>0 then
  1297. ;
  1298. Result:=true;
  1299. end;
  1300. {*****************************************************************************
  1301. TINTERNALLINKER
  1302. *****************************************************************************}
  1303. Constructor TInternalLinker.Create;
  1304. begin
  1305. inherited Create;
  1306. linkscript:=TCmdStrList.Create;
  1307. FStaticLibraryList:=TFPObjectList.Create(true);
  1308. FImportLibraryList:=TFPHashObjectList.Create(true);
  1309. FGroupStack:=TFPObjectList.Create(false);
  1310. exemap:=nil;
  1311. exeoutput:=nil;
  1312. UseStabs:=false;
  1313. CObjInput:=TObjInput;
  1314. ScriptCount:=0;
  1315. IsHandled:=nil;
  1316. end;
  1317. Destructor TInternalLinker.Destroy;
  1318. begin
  1319. FGroupStack.Free;
  1320. linkscript.free;
  1321. StaticLibraryList.Free;
  1322. ImportLibraryList.Free;
  1323. if assigned(IsHandled) then
  1324. begin
  1325. FreeMem(IsHandled,sizeof(boolean)*ScriptCount);
  1326. IsHandled:=nil;
  1327. ScriptCount:=0;
  1328. end;
  1329. if assigned(exeoutput) then
  1330. begin
  1331. exeoutput.free;
  1332. exeoutput:=nil;
  1333. end;
  1334. if assigned(exemap) then
  1335. begin
  1336. exemap.free;
  1337. exemap:=nil;
  1338. end;
  1339. inherited destroy;
  1340. end;
  1341. procedure TInternalLinker.AddImportSymbol(const libname,symname,symmangledname:TCmdStr;OrdNr: longint;isvar:boolean);
  1342. var
  1343. ImportLibrary : TImportLibrary;
  1344. ImportSymbol : TFPHashObject;
  1345. begin
  1346. ImportLibrary:=TImportLibrary(ImportLibraryList.Find(libname));
  1347. if not assigned(ImportLibrary) then
  1348. ImportLibrary:=TImportLibrary.Create(ImportLibraryList,libname);
  1349. ImportSymbol:=TFPHashObject(ImportLibrary.ImportSymbolList.Find(symname));
  1350. if not assigned(ImportSymbol) then
  1351. ImportSymbol:=TImportSymbol.Create(ImportLibrary.ImportSymbolList,symname,symmangledname,OrdNr,isvar);
  1352. end;
  1353. procedure TInternalLinker.ScriptAddSourceStatements(AddSharedAsStatic:boolean);
  1354. var
  1355. s,s2: TCmdStr;
  1356. begin
  1357. while not ObjectFiles.Empty do
  1358. begin
  1359. s:=ObjectFiles.GetFirst;
  1360. if s<>'' then
  1361. LinkScript.Concat('READOBJECT '+MaybeQuoted(s));
  1362. end;
  1363. while not StaticLibFiles.Empty do
  1364. begin
  1365. s:=StaticLibFiles.GetFirst;
  1366. if s<>'' then
  1367. LinkScript.Concat('READSTATICLIBRARY '+MaybeQuoted(s));
  1368. end;
  1369. if not AddSharedAsStatic then
  1370. exit;
  1371. while not SharedLibFiles.Empty do
  1372. begin
  1373. S:=SharedLibFiles.GetFirst;
  1374. if FindLibraryFile(s,target_info.staticClibprefix,target_info.staticClibext,s2) then
  1375. LinkScript.Concat('READSTATICLIBRARY '+MaybeQuoted(s2))
  1376. else
  1377. Comment(V_Error,'Import library not found for '+S);
  1378. end;
  1379. end;
  1380. function TInternalLinker.GetCodeSize(aExeOutput: TExeOutput): QWord;
  1381. begin
  1382. Result:=aExeOutput.findexesection('.text').size;
  1383. end;
  1384. function TInternalLinker.GetDataSize(aExeOutput: TExeOutput): QWord;
  1385. begin
  1386. Result:=aExeOutput.findexesection('.data').size;
  1387. end;
  1388. function TInternalLinker.GetBssSize(aExeOutput: TExeOutput): QWord;
  1389. var
  1390. bsssec: TExeSection;
  1391. begin
  1392. bsssec:=aExeOutput.findexesection('.bss');
  1393. if assigned(bsssec) then
  1394. Result:=bsssec.size
  1395. else
  1396. Result:=0;
  1397. end;
  1398. procedure TInternalLinker.ParseLdScript(src:TScriptLexer);
  1399. var
  1400. asneeded: boolean;
  1401. group: TStaticLibrary;
  1402. procedure ParseInputList;
  1403. var
  1404. saved_asneeded: boolean;
  1405. begin
  1406. src.Expect('(');
  1407. repeat
  1408. if src.CheckForIdent('AS_NEEDED') then
  1409. begin
  1410. saved_asneeded:=asneeded;
  1411. asneeded:=true;
  1412. ParseInputList;
  1413. asneeded:=saved_asneeded;
  1414. end
  1415. else if src.token in [tkIDENT,tkLITERAL] then
  1416. begin
  1417. Load_ReadStaticLibrary(src.tokenstr,asneeded);
  1418. src.nextToken;
  1419. end
  1420. else if src.CheckFor('-') then
  1421. begin
  1422. { TODO: no whitespace between '-' and name;
  1423. name must begin with 'l' }
  1424. src.nextToken;
  1425. end
  1426. else { syntax error, no input_list_element term }
  1427. Break;
  1428. if src.CheckFor(',') then
  1429. Continue;
  1430. until src.CheckFor(')');
  1431. end;
  1432. begin
  1433. asneeded:=false;
  1434. src.nextToken;
  1435. repeat
  1436. if src.CheckForIdent('OUTPUT_FORMAT') then
  1437. begin
  1438. src.Expect('(');
  1439. //writeln('output_format(',src.tokenstr,')');
  1440. src.nextToken;
  1441. src.Expect(')');
  1442. end
  1443. else if src.CheckForIdent('GROUP') then
  1444. begin
  1445. group:=TStaticLibrary.create_group;
  1446. TFPObjectList(FGroupStack.Last).Add(group);
  1447. FGroupStack.Add(group.GroupMembers);
  1448. ParseInputList;
  1449. FGroupStack.Delete(FGroupStack.Count-1);
  1450. end
  1451. else if src.CheckFor(';') then
  1452. {skip semicolon};
  1453. until src.token in [tkEOF,tkINVALID];
  1454. end;
  1455. procedure TInternalLinker.Load_ReadObject(const para:TCmdStr);
  1456. var
  1457. objdata : TObjData;
  1458. objinput : TObjinput;
  1459. objreader : TObjectReader;
  1460. fn : TCmdStr;
  1461. begin
  1462. fn:=FindObjectFile(para,'',false);
  1463. Comment(V_Tried,'Reading object '+fn);
  1464. objinput:=CObjInput.Create;
  1465. objreader:=TObjectreader.create;
  1466. if objreader.openfile(fn) then
  1467. begin
  1468. if objinput.ReadObjData(objreader,objdata) then
  1469. exeoutput.addobjdata(objdata);
  1470. end;
  1471. { release input object }
  1472. objinput.free;
  1473. objreader.free;
  1474. end;
  1475. procedure TInternalLinker.Load_ReadStaticLibrary(const para:TCmdStr;asneededflag:boolean);
  1476. var
  1477. objreader : TObjectReader;
  1478. objinput: TObjInput;
  1479. objdata: TObjData;
  1480. ScriptLexer: TScriptLexer;
  1481. stmt:TStaticLibrary;
  1482. begin
  1483. { TODO: Cleanup ignoring of FPC generated libimp*.a files}
  1484. { Don't load import libraries }
  1485. if copy(ExtractFileName(para),1,6)='libimp' then
  1486. exit;
  1487. Comment(V_Tried,'Opening library '+para);
  1488. objreader:=CArObjectreader.createAr(para,true);
  1489. if ErrorCount>0 then
  1490. exit;
  1491. if objreader.isarchive then
  1492. TFPObjectList(FGroupStack.Last).Add(TStaticLibrary.Create(para,objreader,CObjInput))
  1493. else
  1494. if CObjInput.CanReadObjData(objreader) then
  1495. begin
  1496. { may be a regular object as well as a dynamic one }
  1497. objinput:=CObjInput.Create;
  1498. if objinput.ReadObjData(objreader,objdata) then
  1499. begin
  1500. stmt:=TStaticLibrary.create_object(objdata);
  1501. stmt.AsNeeded:=asneededflag;
  1502. TFPObjectList(FGroupStack.Last).Add(stmt);
  1503. end;
  1504. objinput.Free;
  1505. objreader.Free;
  1506. end
  1507. else { try parsing as script }
  1508. begin
  1509. Comment(V_Tried,'Interpreting '+para+' as ld script');
  1510. ScriptLexer:=TScriptLexer.Create(objreader);
  1511. ParseLdScript(ScriptLexer);
  1512. ScriptLexer.Free;
  1513. objreader.Free;
  1514. end;
  1515. end;
  1516. procedure TInternalLinker.Load_Group;
  1517. var
  1518. group: TStaticLibrary;
  1519. begin
  1520. group:=TStaticLibrary.create_group;
  1521. TFPObjectList(FGroupStack.Last).Add(group);
  1522. FGroupStack.Add(group.GroupMembers);
  1523. end;
  1524. procedure TInternalLinker.Load_EndGroup;
  1525. begin
  1526. FGroupStack.Delete(FGroupStack.Count-1);
  1527. end;
  1528. procedure TInternalLinker.ParseScript_Handle;
  1529. var
  1530. s{, para}, keyword : String;
  1531. hp : TCmdStrListItem;
  1532. i : longint;
  1533. begin
  1534. hp:=TCmdStrListItem(linkscript.first);
  1535. i:=0;
  1536. while assigned(hp) do
  1537. begin
  1538. inc(i);
  1539. s:=hp.str;
  1540. if (s='') or (s[1]='#') then
  1541. begin
  1542. hp:=TCmdStrListItem(hp.next);
  1543. continue;
  1544. end;
  1545. keyword:=Upper(GetToken(s,' '));
  1546. {para:=}GetToken(s,' ');
  1547. if Trim(s)<>'' then
  1548. Comment(V_Warning,'Unknown part "'+s+'" in "'+hp.str+'" internal linker script');
  1549. if (keyword<>'SYMBOL') and
  1550. (keyword<>'SYMBOLS') and
  1551. (keyword<>'STABS') and
  1552. (keyword<>'PROVIDE') and
  1553. (keyword<>'ZEROS') and
  1554. (keyword<>'BYTE') and
  1555. (keyword<>'WORD') and
  1556. (keyword<>'LONG') and
  1557. (keyword<>'QUAD') and
  1558. (keyword<>'ENTRYNAME') and
  1559. (keyword<>'ISSHAREDLIBRARY') and
  1560. (keyword<>'IMAGEBASE') and
  1561. (keyword<>'READOBJECT') and
  1562. (keyword<>'READSTATICLIBRARY') and
  1563. (keyword<>'EXESECTION') and
  1564. (keyword<>'ENDEXESECTION') and
  1565. (keyword<>'OBJSECTION') and
  1566. (keyword<>'HEADER') and
  1567. (keyword<>'GROUP') and
  1568. (keyword<>'ENDGROUP')
  1569. then
  1570. Comment(V_Warning,'Unknown keyword "'+keyword+'" in "'+hp.str
  1571. +'" internal linker script');
  1572. hp:=TCmdStrListItem(hp.next);
  1573. end;
  1574. ScriptCount:=i;
  1575. if ScriptCount>0 then
  1576. begin
  1577. GetMem(IsHandled,sizeof(boolean)*ScriptCount);
  1578. Fillchar(IsHandled^,sizeof(boolean)*ScriptCount,#0);
  1579. end;
  1580. end;
  1581. procedure TInternalLinker.ParseScript_PostCheck;
  1582. var
  1583. hp : TCmdStrListItem;
  1584. i : longint;
  1585. begin
  1586. hp:=TCmdStrListItem(linkscript.first);
  1587. i:=0;
  1588. while assigned(hp) do
  1589. begin
  1590. inc(i);
  1591. if not IsHandled^[i] then
  1592. begin
  1593. Comment(V_Warning,'"'+hp.str+
  1594. '" internal linker script not handled');
  1595. end;
  1596. hp:=TCmdStrListItem(hp.next);
  1597. end;
  1598. end;
  1599. function TInternalLinker.ParsePara(const para : string) : string;
  1600. var
  1601. res : string;
  1602. begin
  1603. res:=trim(para);
  1604. { Remove enclosing braces }
  1605. if (length(res)>0) and (res[1]='(') and
  1606. (res[length(res)]=')') then
  1607. res:=trim(copy(res,2,length(res)-2));
  1608. result:=res;
  1609. end;
  1610. procedure TInternalLinker.ParseScript_Load;
  1611. var
  1612. s,
  1613. para,
  1614. keyword : String;
  1615. hp : TCmdStrListItem;
  1616. i : longint;
  1617. handled : boolean;
  1618. begin
  1619. exeoutput.Load_Start;
  1620. hp:=TCmdStrListItem(linkscript.first);
  1621. i:=0;
  1622. while assigned(hp) do
  1623. begin
  1624. inc(i);
  1625. s:=hp.str;
  1626. if (s='') or (s[1]='#') then
  1627. begin
  1628. IsHandled^[i]:=true;
  1629. hp:=TCmdStrListItem(hp.next);
  1630. continue;
  1631. end;
  1632. handled:=true;
  1633. keyword:=Upper(GetToken(s,' '));
  1634. para:=ParsePara(GetToken(s,' '));
  1635. if keyword='SYMBOL' then
  1636. ExeOutput.Load_Symbol(para)
  1637. else if keyword='PROVIDE' then
  1638. ExeOutput.Load_ProvideSymbol(para)
  1639. else if keyword='ENTRYNAME' then
  1640. ExeOutput.Load_EntryName(para)
  1641. else if keyword='ISSHAREDLIBRARY' then
  1642. ExeOutput.Load_IsSharedLibrary
  1643. else if keyword='IMAGEBASE' then
  1644. ExeOutput.Load_ImageBase(para)
  1645. else if keyword='READOBJECT' then
  1646. Load_ReadObject(para)
  1647. else if keyword='STABS' then
  1648. UseStabs:=true
  1649. else if keyword='READSTATICLIBRARY' then
  1650. Load_ReadStaticLibrary(para)
  1651. else if keyword='GROUP' then
  1652. Load_Group
  1653. else if keyword='ENDGROUP' then
  1654. Load_EndGroup
  1655. else
  1656. handled:=false;
  1657. if handled then
  1658. IsHandled^[i]:=true;
  1659. hp:=TCmdStrListItem(hp.next);
  1660. end;
  1661. end;
  1662. procedure TInternalLinker.ParseScript_Order;
  1663. var
  1664. s,
  1665. para,
  1666. keyword : String;
  1667. hp : TCmdStrListItem;
  1668. i : longint;
  1669. handled : boolean;
  1670. begin
  1671. exeoutput.Order_Start;
  1672. hp:=TCmdStrListItem(linkscript.first);
  1673. i:=0;
  1674. while assigned(hp) do
  1675. begin
  1676. inc(i);
  1677. s:=hp.str;
  1678. if (s='') or (s[1]='#') then
  1679. begin
  1680. hp:=TCmdStrListItem(hp.next);
  1681. continue;
  1682. end;
  1683. handled:=true;
  1684. keyword:=Upper(GetToken(s,' '));
  1685. para:=ParsePara(GetToken(s,' '));
  1686. if keyword='EXESECTION' then
  1687. ExeOutput.Order_ExeSection(para)
  1688. else if keyword='ENDEXESECTION' then
  1689. ExeOutput.Order_EndExeSection
  1690. else if keyword='OBJSECTION' then
  1691. ExeOutput.Order_ObjSection(para)
  1692. else if keyword='ZEROS' then
  1693. ExeOutput.Order_Zeros(para)
  1694. else if keyword='BYTE' then
  1695. ExeOutput.Order_Values(1,para)
  1696. else if keyword='WORD' then
  1697. ExeOutput.Order_Values(2,para)
  1698. else if keyword='LONG' then
  1699. ExeOutput.Order_Values(4,para)
  1700. else if keyword='QUAD' then
  1701. ExeOutput.Order_Values(8,para)
  1702. else if keyword='SYMBOL' then
  1703. ExeOutput.Order_Symbol(para)
  1704. else if keyword='PROVIDE' then
  1705. ExeOutput.Order_ProvideSymbol(para)
  1706. else
  1707. handled:=false;
  1708. if handled then
  1709. IsHandled^[i]:=true;
  1710. hp:=TCmdStrListItem(hp.next);
  1711. end;
  1712. exeoutput.Order_End;
  1713. end;
  1714. procedure TInternalLinker.ParseScript_MemPos;
  1715. var
  1716. s,
  1717. para,
  1718. keyword : String;
  1719. hp : TCmdStrListItem;
  1720. i : longint;
  1721. handled : boolean;
  1722. begin
  1723. exeoutput.MemPos_Start;
  1724. hp:=TCmdStrListItem(linkscript.first);
  1725. i:=0;
  1726. while assigned(hp) do
  1727. begin
  1728. inc(i);
  1729. s:=hp.str;
  1730. if (s='') or (s[1]='#') then
  1731. begin
  1732. hp:=TCmdStrListItem(hp.next);
  1733. continue;
  1734. end;
  1735. handled:=true;
  1736. keyword:=Upper(GetToken(s,' '));
  1737. para:=ParsePara(GetToken(s,' '));
  1738. if keyword='EXESECTION' then
  1739. ExeOutput.MemPos_ExeSection(para)
  1740. else if keyword='ENDEXESECTION' then
  1741. ExeOutput.MemPos_EndExeSection
  1742. else if keyword='HEADER' then
  1743. ExeOutput.MemPos_Header
  1744. else
  1745. handled:=false;
  1746. if handled then
  1747. IsHandled^[i]:=true;
  1748. hp:=TCmdStrListItem(hp.next);
  1749. end;
  1750. end;
  1751. procedure TInternalLinker.ParseScript_DataPos;
  1752. var
  1753. s,
  1754. para,
  1755. keyword : String;
  1756. hp : TCmdStrListItem;
  1757. i : longint;
  1758. handled : boolean;
  1759. begin
  1760. exeoutput.DataPos_Start;
  1761. hp:=TCmdStrListItem(linkscript.first);
  1762. i:=0;
  1763. while assigned(hp) do
  1764. begin
  1765. inc(i);
  1766. s:=hp.str;
  1767. if (s='') or (s[1]='#') then
  1768. begin
  1769. hp:=TCmdStrListItem(hp.next);
  1770. continue;
  1771. end;
  1772. handled:=true;
  1773. keyword:=Upper(GetToken(s,' '));
  1774. para:=ParsePara(GetToken(s,' '));
  1775. if keyword='EXESECTION' then
  1776. ExeOutput.DataPos_ExeSection(para)
  1777. else if keyword='ENDEXESECTION' then
  1778. ExeOutput.DataPos_EndExeSection
  1779. else if keyword='HEADER' then
  1780. ExeOutput.DataPos_Header
  1781. else if keyword='SYMBOLS' then
  1782. ExeOutput.DataPos_Symbols
  1783. else
  1784. handled:=false;
  1785. if handled then
  1786. IsHandled^[i]:=true;
  1787. hp:=TCmdStrListItem(hp.next);
  1788. end;
  1789. end;
  1790. procedure TInternalLinker.PrintLinkerScript;
  1791. var
  1792. hp : TCmdStrListItem;
  1793. begin
  1794. if not assigned(exemap) then
  1795. exit;
  1796. exemap.Add('Used linker script');
  1797. exemap.Add('');
  1798. hp:=TCmdStrListItem(linkscript.first);
  1799. while assigned(hp) do
  1800. begin
  1801. exemap.Add(hp.str);
  1802. hp:=TCmdStrListItem(hp.next);
  1803. end;
  1804. end;
  1805. function TInternalLinker.RunLinkScript(const outputname:TCmdStr):boolean;
  1806. label
  1807. myexit;
  1808. var
  1809. bsssize : qword;
  1810. dbgname : TCmdStr;
  1811. begin
  1812. result:=false;
  1813. Message1(exec_i_linking,outputname);
  1814. FlushOutput;
  1815. exeoutput:=CExeOutput.Create;
  1816. { TODO: Load custom linker script}
  1817. DefaultLinkScript;
  1818. if (cs_link_map in current_settings.globalswitches) then
  1819. exemap:=texemap.create(current_module.mapfilename);
  1820. PrintLinkerScript;
  1821. { Check that syntax is OK }
  1822. ParseScript_Handle;
  1823. { Load .o files and resolve symbols }
  1824. FGroupStack.Add(FStaticLibraryList);
  1825. ParseScript_Load;
  1826. if ErrorCount>0 then
  1827. goto myexit;
  1828. exeoutput.ResolveSymbols(StaticLibraryList);
  1829. { Generate symbols and code to do the importing }
  1830. exeoutput.GenerateLibraryImports(ImportLibraryList);
  1831. { Fill external symbols data }
  1832. exeoutput.FixupSymbols;
  1833. if ErrorCount>0 then
  1834. goto myexit;
  1835. { parse linker options specific for output format }
  1836. exeoutput.ParseScript (linkscript);
  1837. { Create .exe sections and add .o sections }
  1838. ParseScript_Order;
  1839. exeoutput.RemoveUnreferencedSections;
  1840. { if UseStabs then, this would remove
  1841. STABS for empty linker scripts }
  1842. exeoutput.MergeStabs;
  1843. exeoutput.MarkEmptySections;
  1844. exeoutput.AfterUnusedSectionRemoval;
  1845. if ErrorCount>0 then
  1846. goto myexit;
  1847. { Calc positions in mem }
  1848. ParseScript_MemPos;
  1849. exeoutput.FixupRelocations;
  1850. exeoutput.RemoveUnusedExeSymbols;
  1851. exeoutput.PrintMemoryMap;
  1852. if ErrorCount>0 then
  1853. goto myexit;
  1854. if cs_link_separate_dbg_file in current_settings.globalswitches then
  1855. begin
  1856. { create debuginfo, which is an executable without data on disk }
  1857. dbgname:=ChangeFileExt(outputname,'.dbg');
  1858. exeoutput.ExeWriteMode:=ewm_dbgonly;
  1859. ParseScript_DataPos;
  1860. exeoutput.WriteExeFile(dbgname);
  1861. { create executable with link to just created debuginfo file }
  1862. exeoutput.ExeWriteMode:=ewm_exeonly;
  1863. exeoutput.RemoveDebugInfo;
  1864. exeoutput.GenerateDebugLink(ExtractFileName(dbgname),GetFileCRC(dbgname));
  1865. ParseScript_MemPos;
  1866. ParseScript_DataPos;
  1867. exeoutput.WriteExeFile(outputname);
  1868. end
  1869. else
  1870. begin
  1871. exeoutput.ExeWriteMode:=ewm_exefull;
  1872. ParseScript_DataPos;
  1873. exeoutput.WriteExeFile(outputname);
  1874. end;
  1875. { Post check that everything was handled }
  1876. ParseScript_PostCheck;
  1877. status.codesize:=GetCodeSize(exeoutput);
  1878. status.datasize:=GetDataSize(exeoutput);
  1879. bsssize:=GetBssSize(exeoutput);
  1880. { Executable info }
  1881. Message1(execinfo_x_codesize,tostr(status.codesize));
  1882. Message1(execinfo_x_initdatasize,tostr(status.datasize));
  1883. Message1(execinfo_x_uninitdatasize,tostr(bsssize));
  1884. Message1(execinfo_x_stackreserve,tostr(stacksize));
  1885. myexit:
  1886. { close map }
  1887. if assigned(exemap) then
  1888. begin
  1889. exemap.free;
  1890. exemap:=nil;
  1891. end;
  1892. { close exe }
  1893. exeoutput.free;
  1894. exeoutput:=nil;
  1895. result:=true;
  1896. end;
  1897. function TInternalLinker.ExecutableFilename:String;
  1898. begin
  1899. result:=current_module.exefilename;
  1900. end;
  1901. function TInternalLinker.SharedLibFilename:String;
  1902. begin
  1903. result:=current_module.sharedlibfilename;
  1904. end;
  1905. function TInternalLinker.MakeExecutable:boolean;
  1906. begin
  1907. IsSharedLibrary:=false;
  1908. result:=RunLinkScript(ExecutableFilename);
  1909. {$ifdef hasUnix}
  1910. fpchmod(current_module.exefilename,493);
  1911. {$endif hasUnix}
  1912. end;
  1913. function TInternalLinker.MakeSharedLibrary:boolean;
  1914. begin
  1915. IsSharedLibrary:=true;
  1916. result:=RunLinkScript(SharedLibFilename);
  1917. end;
  1918. procedure TInternalLinker.ScriptAddGenericSections(secnames:string);
  1919. var
  1920. secname:string;
  1921. begin
  1922. repeat
  1923. secname:=gettoken(secnames,',');
  1924. if secname='' then
  1925. break;
  1926. linkscript.Concat('EXESECTION '+secname);
  1927. linkscript.Concat(' OBJSECTION '+secname+'*');
  1928. linkscript.Concat('ENDEXESECTION');
  1929. until false;
  1930. end;
  1931. {*****************************************************************************
  1932. Init/Done
  1933. *****************************************************************************}
  1934. procedure RegisterLinker(id:tlink;c:TLinkerClass);
  1935. begin
  1936. CLinker[id]:=c;
  1937. end;
  1938. procedure InitLinker;
  1939. begin
  1940. if (cs_link_extern in current_settings.globalswitches) and
  1941. assigned(CLinker[target_info.linkextern]) then
  1942. begin
  1943. linker:=CLinker[target_info.linkextern].Create;
  1944. end
  1945. else
  1946. if assigned(CLinker[target_info.link]) then
  1947. begin
  1948. linker:=CLinker[target_info.link].Create;
  1949. end
  1950. else
  1951. linker:=Tlinker.Create;
  1952. end;
  1953. procedure DoneLinker;
  1954. begin
  1955. if assigned(linker) then
  1956. Linker.Free;
  1957. end;
  1958. {*****************************************************************************
  1959. Initialize
  1960. *****************************************************************************}
  1961. const
  1962. ar_gnu_ar_info : tarinfo =
  1963. (
  1964. id : ar_gnu_ar;
  1965. addfilecmd : '';
  1966. arfirstcmd : '';
  1967. arcmd : 'ar qS $LIB $FILES';
  1968. arfinishcmd : 'ar s $LIB'
  1969. );
  1970. ar_gnu_ar_scripted_info : tarinfo =
  1971. (
  1972. id : ar_gnu_ar_scripted;
  1973. addfilecmd : '';
  1974. arfirstcmd : '';
  1975. arcmd : 'ar -M < $SCRIPT';
  1976. arfinishcmd : ''
  1977. );
  1978. ar_gnu_gar_info : tarinfo =
  1979. ( id : ar_gnu_gar;
  1980. addfilecmd : '';
  1981. arfirstcmd : '';
  1982. arcmd : 'gar qS $LIB $FILES';
  1983. arfinishcmd : 'gar s $LIB'
  1984. );
  1985. ar_watcom_wlib_omf_info : tarinfo =
  1986. ( id : ar_watcom_wlib_omf;
  1987. addfilecmd : '+';
  1988. arfirstcmd : 'wlib -q $RECSIZE -fo -c -b -n -o=$OUTPUTLIB $LIB $FILES';
  1989. arcmd : 'wlib -q $RECSIZE -fo -c -b -o=$OUTPUTLIB $LIB $FILES';
  1990. arfinishcmd : ''
  1991. );
  1992. ar_watcom_wlib_omf_scripted_info : tarinfo =
  1993. (
  1994. id : ar_watcom_wlib_omf_scripted;
  1995. addfilecmd : '+';
  1996. arfirstcmd : '';
  1997. arcmd : 'wlib @$SCRIPT';
  1998. arfinishcmd : ''
  1999. );
  2000. ar_sdcc_sdar_info : tarinfo =
  2001. ( id : ar_sdcc_sdar;
  2002. addfilecmd : '';
  2003. arfirstcmd : '';
  2004. arcmd : 'sdar qS $LIB $FILES';
  2005. arfinishcmd : 'sdar s $LIB'
  2006. );
  2007. ar_sdcc_sdar_scripted_info : tarinfo =
  2008. (
  2009. id : ar_sdcc_sdar_scripted;
  2010. addfilecmd : '';
  2011. arfirstcmd : '';
  2012. arcmd : 'sdar -M < $SCRIPT';
  2013. arfinishcmd : ''
  2014. );
  2015. initialization
  2016. RegisterAr(ar_gnu_ar_info);
  2017. RegisterAr(ar_gnu_ar_scripted_info);
  2018. RegisterAr(ar_gnu_gar_info);
  2019. RegisterAr(ar_watcom_wlib_omf_info);
  2020. RegisterAr(ar_watcom_wlib_omf_scripted_info);
  2021. RegisterAr(ar_sdcc_sdar_info);
  2022. RegisterAr(ar_sdcc_sdar_scripted_info);
  2023. end.