link.pas 36 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105
  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. interface
  21. uses
  22. sysutils,
  23. cclasses,
  24. systems,
  25. fmodule,
  26. globtype,
  27. ogbase;
  28. Type
  29. TLinkerInfo=record
  30. ExeCmd,
  31. DllCmd : array[1..3] of string;
  32. ResName : string[100];
  33. ScriptName : string[100];
  34. ExtraOptions : TCmdStr;
  35. DynamicLinker : string[100];
  36. end;
  37. TLinker = class(TAbstractLinker)
  38. public
  39. HasResources,
  40. HasExports : boolean;
  41. SysInitUnit : string[20];
  42. ObjectFiles,
  43. SharedLibFiles,
  44. StaticLibFiles : TCmdStrList;
  45. Constructor Create;virtual;
  46. Destructor Destroy;override;
  47. procedure AddModuleFiles(hp:tmodule);
  48. Procedure AddObject(const S,unitpath : TCmdStr;isunit:boolean);
  49. Procedure AddStaticLibrary(const S : TCmdStr);
  50. Procedure AddSharedLibrary(S : TCmdStr);
  51. Procedure AddStaticCLibrary(const S : TCmdStr);
  52. Procedure AddSharedCLibrary(S : TCmdStr);
  53. procedure AddImportSymbol(const libname,symname:TCmdStr;OrdNr: longint;isvar:boolean);virtual;
  54. Procedure InitSysInitUnitName;virtual;
  55. Function MakeExecutable:boolean;virtual;
  56. Function MakeSharedLibrary:boolean;virtual;
  57. Function MakeStaticLibrary:boolean;virtual;
  58. procedure ExpandAndApplyOrder(var Src:TCmdStrList);
  59. procedure LoadPredefinedLibraryOrder;virtual;
  60. function ReOrderEntries : boolean;
  61. end;
  62. TExternalLinker = class(TLinker)
  63. public
  64. Info : TLinkerInfo;
  65. Constructor Create;override;
  66. Destructor Destroy;override;
  67. Function FindUtil(const s:TCmdStr):TCmdStr;
  68. Function DoExec(const command:TCmdStr; para:TCmdStr;showinfo,useshell:boolean):boolean;
  69. procedure SetDefaultInfo;virtual;
  70. Function MakeStaticLibrary:boolean;override;
  71. end;
  72. TInternalLinker = class(TLinker)
  73. private
  74. FCExeOutput : TExeOutputClass;
  75. FCObjInput : TObjInputClass;
  76. { Libraries }
  77. FStaticLibraryList : TFPHashObjectList;
  78. FImportLibraryList : TFPHashObjectList;
  79. procedure Load_ReadObject(const para:TCmdStr);
  80. procedure Load_ReadStaticLibrary(const para:TCmdStr);
  81. procedure ParseScript_Load;
  82. procedure ParseScript_Order;
  83. procedure ParseScript_CalcPos;
  84. procedure PrintLinkerScript;
  85. function RunLinkScript(const outputname:TCmdStr):boolean;
  86. protected
  87. property CObjInput:TObjInputClass read FCObjInput write FCObjInput;
  88. property CExeOutput:TExeOutputClass read FCExeOutput write FCExeOutput;
  89. property StaticLibraryList:TFPHashObjectList read FStaticLibraryList;
  90. property ImportLibraryList:TFPHashObjectList read FImportLibraryList;
  91. procedure DefaultLinkScript;virtual;abstract;
  92. linkscript : TCmdStrList;
  93. public
  94. IsSharedLibrary : boolean;
  95. Constructor Create;override;
  96. Destructor Destroy;override;
  97. Function MakeExecutable:boolean;override;
  98. Function MakeSharedLibrary:boolean;override;
  99. procedure AddImportSymbol(const libname,symname:TCmdStr;OrdNr: longint;isvar:boolean);override;
  100. end;
  101. var
  102. Linker : TLinker;
  103. function FindObjectFile(s : TCmdStr;const unitpath:TCmdStr;isunit:boolean) : TCmdStr;
  104. function FindLibraryFile(s:TCmdStr;const prefix,ext:TCmdStr;var foundfile : TCmdStr) : boolean;
  105. function FindDLL(const s:TCmdStr;var founddll:TCmdStr):boolean;
  106. procedure InitLinker;
  107. procedure DoneLinker;
  108. Implementation
  109. uses
  110. cutils,cfileutils,
  111. script,globals,verbose,comphook,ppu,
  112. aasmbase,aasmtai,aasmdata,aasmcpu,
  113. owbase,owar,ogmap;
  114. type
  115. TLinkerClass = class of Tlinker;
  116. {*****************************************************************************
  117. Helpers
  118. *****************************************************************************}
  119. { searches an object file }
  120. function FindObjectFile(s:TCmdStr;const unitpath:TCmdStr;isunit:boolean) : TCmdStr;
  121. var
  122. found : boolean;
  123. foundfile : TCmdStr;
  124. begin
  125. findobjectfile:='';
  126. if s='' then
  127. exit;
  128. {When linking on target, the units has not been assembled yet,
  129. so there is no object files to look for at
  130. the host. Look for the corresponding assembler file instead,
  131. because it will be assembled to object file on the target.}
  132. if isunit and (cs_link_on_target in current_settings.globalswitches) then
  133. s:=ChangeFileExt(s,target_info.asmext);
  134. { when it does not belong to the unit then check if
  135. the specified file exists without searching any paths }
  136. if not isunit then
  137. begin
  138. if FileExists(FixFileName(s),false) then
  139. begin
  140. foundfile:=ScriptFixFileName(s);
  141. found:=true;
  142. end;
  143. end;
  144. if pos('.',s)=0 then
  145. s:=s+target_info.objext;
  146. { find object file
  147. 1. output unit path
  148. 2. output exe path
  149. 3. specified unit path (if specified)
  150. 4. cwd
  151. 5. unit search path
  152. 6. local object path
  153. 7. global object path
  154. 8. exepath (not when linking on target)
  155. for all finds don't use the directory caching }
  156. found:=false;
  157. if isunit and (OutputUnitDir<>'') then
  158. found:=FindFile(s,OutPutUnitDir,false,foundfile)
  159. else
  160. if OutputExeDir<>'' then
  161. found:=FindFile(s,OutPutExeDir,false,foundfile);
  162. if (not found) and (unitpath<>'') then
  163. found:=FindFile(s,unitpath,false,foundfile);
  164. if (not found) then
  165. found:=FindFile(s, CurDirRelPath(source_info),false,foundfile);
  166. if (not found) then
  167. found:=UnitSearchPath.FindFile(s,false,foundfile);
  168. if (not found) then
  169. found:=current_module.localobjectsearchpath.FindFile(s,false,foundfile);
  170. if (not found) then
  171. found:=objectsearchpath.FindFile(s,false,foundfile);
  172. if not(cs_link_on_target in current_settings.globalswitches) and (not found) then
  173. found:=FindFile(s,exepath,false,foundfile);
  174. if not(cs_link_nolink in current_settings.globalswitches) and (not found) then
  175. Message1(exec_w_objfile_not_found,s);
  176. {Restore file extension}
  177. if isunit and (cs_link_on_target in current_settings.globalswitches) then
  178. foundfile:= ChangeFileExt(foundfile,target_info.objext);
  179. findobjectfile:=ScriptFixFileName(foundfile);
  180. end;
  181. { searches a (windows) DLL file }
  182. function FindDLL(const s:TCmdStr;var founddll:TCmdStr):boolean;
  183. var
  184. sysdir : TCmdStr;
  185. Found : boolean;
  186. begin
  187. Found:=false;
  188. { Look for DLL in:
  189. 1. Current dir
  190. 2. Library Path
  191. 3. windir,windir/system,windir/system32 }
  192. Found:=FindFile(s,'.'+source_info.DirSep,false,founddll);
  193. if (not found) then
  194. Found:=librarysearchpath.FindFile(s,false,founddll);
  195. if (not found) then
  196. begin
  197. sysdir:=FixPath(GetEnvironmentVariable('windir'),false);
  198. Found:=FindFile(s,sysdir+';'+sysdir+'system'+source_info.DirSep+';'+sysdir+'system32'+source_info.DirSep,false,founddll);
  199. end;
  200. if (not found) then
  201. begin
  202. message1(exec_w_libfile_not_found,s);
  203. FoundDll:=s;
  204. end;
  205. FindDll:=Found;
  206. end;
  207. { searches an library file }
  208. function FindLibraryFile(s:TCmdStr;const prefix,ext:TCmdStr;var foundfile : TCmdStr) : boolean;
  209. var
  210. found : boolean;
  211. paths : TCmdStr;
  212. begin
  213. findlibraryfile:=false;
  214. foundfile:=s;
  215. if s='' then
  216. exit;
  217. { split path from filename }
  218. paths:=ExtractFilePath(s);
  219. s:=ExtractFileName(s);
  220. { add prefix 'lib' }
  221. if (prefix<>'') and (Copy(s,1,length(prefix))<>prefix) then
  222. s:=prefix+s;
  223. { add extension }
  224. if (ext<>'') and (Copy(s,length(s)-length(ext)+1,length(ext))<>ext) then
  225. s:=s+ext;
  226. { readd the split path }
  227. s:=paths+s;
  228. if FileExists(s,false) then
  229. begin
  230. foundfile:=ScriptFixFileName(s);
  231. FindLibraryFile:=true;
  232. exit;
  233. end;
  234. { find libary
  235. 1. cwd
  236. 2. local libary dir
  237. 3. global libary dir
  238. 4. exe path of the compiler (not when linking on target)
  239. for all searches don't use the directory cache }
  240. found:=FindFile(s, CurDirRelPath(source_info), false,foundfile);
  241. if (not found) and (current_module.outputpath^<>'') then
  242. found:=FindFile(s,current_module.outputpath^,false,foundfile);
  243. if (not found) then
  244. found:=current_module.locallibrarysearchpath.FindFile(s,false,foundfile);
  245. if (not found) then
  246. found:=librarysearchpath.FindFile(s,false,foundfile);
  247. if not(cs_link_on_target in current_settings.globalswitches) and (not found) then
  248. found:=FindFile(s,exepath,false,foundfile);
  249. foundfile:=ScriptFixFileName(foundfile);
  250. findlibraryfile:=found;
  251. end;
  252. {*****************************************************************************
  253. TLINKER
  254. *****************************************************************************}
  255. Constructor TLinker.Create;
  256. begin
  257. Inherited Create;
  258. ObjectFiles:=TCmdStrList.Create_no_double;
  259. SharedLibFiles:=TCmdStrList.Create_no_double;
  260. StaticLibFiles:=TCmdStrList.Create_no_double;
  261. end;
  262. Destructor TLinker.Destroy;
  263. begin
  264. ObjectFiles.Free;
  265. SharedLibFiles.Free;
  266. StaticLibFiles.Free;
  267. end;
  268. procedure TLinker.AddModuleFiles(hp:tmodule);
  269. var
  270. mask : longint;
  271. i,j : longint;
  272. ImportLibrary : TImportLibrary;
  273. ImportSymbol : TImportSymbol;
  274. begin
  275. with hp do
  276. begin
  277. if (flags and uf_has_resourcefiles)<>0 then
  278. HasResources:=true;
  279. if (flags and uf_has_exports)<>0 then
  280. HasExports:=true;
  281. { link unit files }
  282. if (flags and uf_no_link)=0 then
  283. begin
  284. { create mask which unit files need linking }
  285. mask:=link_always;
  286. { static linking ? }
  287. if (cs_link_static in current_settings.globalswitches) then
  288. begin
  289. if (flags and uf_static_linked)=0 then
  290. begin
  291. { if smart not avail then try static linking }
  292. if (flags and uf_smart_linked)<>0 then
  293. begin
  294. Message1(exec_t_unit_not_static_linkable_switch_to_smart,modulename^);
  295. mask:=mask or link_smart;
  296. end
  297. else
  298. Message1(exec_e_unit_not_smart_or_static_linkable,modulename^);
  299. end
  300. else
  301. mask:=mask or link_static;
  302. end;
  303. { smart linking ? }
  304. if (cs_link_smart in current_settings.globalswitches) then
  305. begin
  306. if (flags and uf_smart_linked)=0 then
  307. begin
  308. { if smart not avail then try static linking }
  309. if (flags and uf_static_linked)<>0 then
  310. begin
  311. Message1(exec_t_unit_not_smart_linkable_switch_to_static,modulename^);
  312. mask:=mask or link_static;
  313. end
  314. else
  315. Message1(exec_e_unit_not_smart_or_static_linkable,modulename^);
  316. end
  317. else
  318. mask:=mask or link_smart;
  319. end;
  320. { shared linking }
  321. if (cs_link_shared in current_settings.globalswitches) then
  322. begin
  323. if (flags and uf_shared_linked)=0 then
  324. begin
  325. { if shared not avail then try static linking }
  326. if (flags and uf_static_linked)<>0 then
  327. begin
  328. Message1(exec_t_unit_not_shared_linkable_switch_to_static,modulename^);
  329. mask:=mask or link_static;
  330. end
  331. else
  332. Message1(exec_e_unit_not_shared_or_static_linkable,modulename^);
  333. end
  334. else
  335. mask:=mask or link_shared;
  336. end;
  337. { unit files }
  338. while not linkunitofiles.empty do
  339. AddObject(linkunitofiles.getusemask(mask),path^,true);
  340. while not linkunitstaticlibs.empty do
  341. AddStaticLibrary(linkunitstaticlibs.getusemask(mask));
  342. while not linkunitsharedlibs.empty do
  343. AddSharedLibrary(linkunitsharedlibs.getusemask(mask));
  344. end;
  345. { Other needed .o and libs, specified using $L,$LINKLIB,external }
  346. mask:=link_always;
  347. while not linkotherofiles.empty do
  348. AddObject(linkotherofiles.Getusemask(mask),path^,false);
  349. while not linkotherstaticlibs.empty do
  350. AddStaticCLibrary(linkotherstaticlibs.Getusemask(mask));
  351. while not linkothersharedlibs.empty do
  352. AddSharedCLibrary(linkothersharedlibs.Getusemask(mask));
  353. { Known Library/DLL Imports }
  354. for i:=0 to ImportLibraryList.Count-1 do
  355. begin
  356. ImportLibrary:=TImportLibrary(ImportLibraryList[i]);
  357. for j:=0 to ImportLibrary.ImportSymbolList.Count-1 do
  358. begin
  359. ImportSymbol:=TImportSymbol(ImportLibrary.ImportSymbolList[j]);
  360. AddImportSymbol(ImportLibrary.Name,ImportSymbol.Name,ImportSymbol.OrdNr,ImportSymbol.IsVar);
  361. end;
  362. end;
  363. end;
  364. end;
  365. procedure TLinker.AddImportSymbol(const libname,symname:TCmdStr;OrdNr: longint;isvar:boolean);
  366. begin
  367. end;
  368. Procedure TLinker.AddObject(const S,unitpath : TCmdStr;isunit:boolean);
  369. begin
  370. ObjectFiles.Concat(FindObjectFile(s,unitpath,isunit));
  371. end;
  372. Procedure TLinker.AddSharedLibrary(S:TCmdStr);
  373. begin
  374. if s='' then
  375. exit;
  376. { remove prefix 'lib' }
  377. if Copy(s,1,length(target_info.sharedlibprefix))=target_info.sharedlibprefix then
  378. Delete(s,1,length(target_info.sharedlibprefix));
  379. { remove extension if any }
  380. if Copy(s,length(s)-length(target_info.sharedlibext)+1,length(target_info.sharedlibext))=target_info.sharedlibext then
  381. Delete(s,length(s)-length(target_info.sharedlibext)+1,length(target_info.sharedlibext)+1);
  382. { ready to be added }
  383. SharedLibFiles.Concat(S);
  384. end;
  385. Procedure TLinker.AddStaticLibrary(const S:TCmdStr);
  386. var
  387. ns : TCmdStr;
  388. found : boolean;
  389. begin
  390. if s='' then
  391. exit;
  392. found:=FindLibraryFile(s,target_info.staticlibprefix,target_info.staticlibext,ns);
  393. if not(cs_link_nolink in current_settings.globalswitches) and (not found) then
  394. Message1(exec_w_libfile_not_found,s);
  395. StaticLibFiles.Concat(ns);
  396. end;
  397. Procedure TLinker.AddSharedCLibrary(S:TCmdStr);
  398. begin
  399. if s='' then
  400. exit;
  401. { remove prefix 'lib' }
  402. if Copy(s,1,length(target_info.sharedclibprefix))=target_info.sharedclibprefix then
  403. Delete(s,1,length(target_info.sharedclibprefix));
  404. { remove extension if any }
  405. if Copy(s,length(s)-length(target_info.sharedclibext)+1,length(target_info.sharedclibext))=target_info.sharedclibext then
  406. Delete(s,length(s)-length(target_info.sharedclibext)+1,length(target_info.sharedclibext)+1);
  407. { ready to be added }
  408. SharedLibFiles.Concat(S);
  409. end;
  410. Procedure TLinker.AddStaticCLibrary(const S:TCmdStr);
  411. var
  412. ns : TCmdStr;
  413. found : boolean;
  414. begin
  415. if s='' then
  416. exit;
  417. found:=FindLibraryFile(s,target_info.staticclibprefix,target_info.staticclibext,ns);
  418. if not(cs_link_nolink in current_settings.globalswitches) and (not found) then
  419. Message1(exec_w_libfile_not_found,s);
  420. StaticLibFiles.Concat(ns);
  421. end;
  422. procedure AddImportSymbol(const libname,symname:TCmdStr;OrdNr: longint;isvar:boolean);
  423. begin
  424. end;
  425. procedure TLinker.InitSysInitUnitName;
  426. begin
  427. end;
  428. function TLinker.MakeExecutable:boolean;
  429. begin
  430. MakeExecutable:=false;
  431. Message(exec_e_exe_not_supported);
  432. end;
  433. Function TLinker.MakeSharedLibrary:boolean;
  434. begin
  435. MakeSharedLibrary:=false;
  436. Message(exec_e_dll_not_supported);
  437. end;
  438. Function TLinker.MakeStaticLibrary:boolean;
  439. begin
  440. MakeStaticLibrary:=false;
  441. Message(exec_e_dll_not_supported);
  442. end;
  443. Procedure TLinker.ExpandAndApplyOrder(var Src:TCmdStrList);
  444. var
  445. p : TLinkStrMap;
  446. i : longint;
  447. begin
  448. // call Virtual TLinker method to initialize
  449. LoadPredefinedLibraryOrder;
  450. // something to do?
  451. if (LinkLibraryAliases.count=0) and (LinkLibraryOrder.Count=0) Then
  452. exit;
  453. p:=TLinkStrMap.Create;
  454. // expand libaliases, clears src
  455. LinkLibraryAliases.expand(src,p);
  456. // writeln(src.count,' ',p.count,' ',linklibraryorder.count,' ',linklibraryaliases.count);
  457. // apply order
  458. p.UpdateWeights(LinkLibraryOrder);
  459. p.SortOnWeight;
  460. // put back in src
  461. for i:=0 to p.count-1 do
  462. src.insert(p[i].Key);
  463. p.free;
  464. end;
  465. procedure TLinker.LoadPredefinedLibraryOrder;
  466. begin
  467. end;
  468. function TLinker.ReOrderEntries : boolean;
  469. begin
  470. result:=(LinkLibraryOrder.count>0) or (LinkLibraryAliases.count>0);
  471. end;
  472. {*****************************************************************************
  473. TEXTERNALLINKER
  474. *****************************************************************************}
  475. Constructor TExternalLinker.Create;
  476. begin
  477. inherited Create;
  478. { set generic defaults }
  479. FillChar(Info,sizeof(Info),0);
  480. if cs_link_on_target in current_settings.globalswitches then
  481. begin
  482. Info.ResName:=outputexedir+ChangeFileExt(inputfilename,'_link.res');
  483. Info.ScriptName:=outputexedir+ChangeFileExt(inputfilename,'_script.res');
  484. end
  485. else
  486. begin
  487. Info.ResName:='link.res';
  488. Info.ScriptName:='script.res';
  489. end;
  490. { set the linker specific defaults }
  491. SetDefaultInfo;
  492. { Allow Parameter overrides for linker info }
  493. with Info do
  494. begin
  495. if ParaLinkOptions<>'' then
  496. ExtraOptions:=ParaLinkOptions;
  497. if ParaDynamicLinker<>'' then
  498. DynamicLinker:=ParaDynamicLinker;
  499. end;
  500. end;
  501. Destructor TExternalLinker.Destroy;
  502. begin
  503. inherited destroy;
  504. end;
  505. Procedure TExternalLinker.SetDefaultInfo;
  506. begin
  507. end;
  508. Function TExternalLinker.FindUtil(const s:TCmdStr):TCmdStr;
  509. var
  510. Found : boolean;
  511. FoundBin : TCmdStr;
  512. UtilExe : TCmdStr;
  513. begin
  514. if cs_link_on_target in current_settings.globalswitches then
  515. begin
  516. { If linking on target, don't add any path PM }
  517. FindUtil:=ChangeFileExt(s,target_info.exeext);
  518. exit;
  519. end;
  520. UtilExe:=ChangeFileExt(s,source_info.exeext);
  521. FoundBin:='';
  522. Found:=false;
  523. if utilsdirectory<>'' then
  524. Found:=FindFile(utilexe,utilsdirectory,false,Foundbin);
  525. if (not Found) then
  526. Found:=FindExe(utilexe,false,Foundbin);
  527. if (not Found) and not(cs_link_nolink in current_settings.globalswitches) then
  528. begin
  529. Message1(exec_e_util_not_found,utilexe);
  530. current_settings.globalswitches:=current_settings.globalswitches+[cs_link_nolink];
  531. end;
  532. if (FoundBin<>'') then
  533. Message1(exec_t_using_util,FoundBin);
  534. FindUtil:=FoundBin;
  535. end;
  536. Function TExternalLinker.DoExec(const command:TCmdStr; para:TCmdStr;showinfo,useshell:boolean):boolean;
  537. var
  538. exitcode: longint;
  539. begin
  540. DoExec:=true;
  541. if not(cs_link_nolink in current_settings.globalswitches) then
  542. begin
  543. FlushOutput;
  544. if useshell then
  545. exitcode:=shell(maybequoted(command)+' '+para)
  546. else
  547. try
  548. exitcode:=ExecuteProcess(command,para);
  549. except on E:EOSError do
  550. begin
  551. Message(exec_e_cant_call_linker);
  552. current_settings.globalswitches:=current_settings.globalswitches+[cs_link_nolink];
  553. DoExec:=false;
  554. end;
  555. end;
  556. if (exitcode<>0) then
  557. begin
  558. Message(exec_e_error_while_linking);
  559. current_settings.globalswitches:=current_settings.globalswitches+[cs_link_nolink];
  560. DoExec:=false;
  561. end;
  562. end;
  563. { Update asmres when externmode is set }
  564. if cs_link_nolink in current_settings.globalswitches then
  565. begin
  566. if showinfo then
  567. begin
  568. if DLLsource then
  569. AsmRes.AddLinkCommand(Command,Para,current_module.sharedlibfilename^)
  570. else
  571. AsmRes.AddLinkCommand(Command,Para,current_module.exefilename^);
  572. end
  573. else
  574. AsmRes.AddLinkCommand(Command,Para,'');
  575. end;
  576. end;
  577. Function TExternalLinker.MakeStaticLibrary:boolean;
  578. function GetNextFiles(const maxCmdLength : AInt; var item : TCmdStrListItem) : TCmdStr;
  579. begin
  580. result := '';
  581. while (assigned(item) and ((length(result) + length(item.str) + 1) < maxCmdLength)) do begin
  582. result := result + ' ' + item.str;
  583. item := TCmdStrListItem(item.next);
  584. end;
  585. end;
  586. var
  587. binstr, scriptfile : TCmdStr;
  588. cmdstr, nextcmd, smartpath : TCmdStr;
  589. current : TCmdStrListItem;
  590. script: Text;
  591. scripted_ar : boolean;
  592. success : boolean;
  593. begin
  594. MakeStaticLibrary:=false;
  595. { remove the library, to be sure that it is rewritten }
  596. DeleteFile(current_module.staticlibfilename^);
  597. { Call AR }
  598. smartpath:=FixPath(ChangeFileExt(current_module.asmfilename^,target_info.smartext),false);
  599. SplitBinCmd(target_ar.arcmd,binstr,cmdstr);
  600. binstr := FindUtil(utilsprefix + binstr);
  601. scripted_ar:=target_ar.id=ar_gnu_ar_scripted;
  602. if scripted_ar then
  603. begin
  604. scriptfile := FixFileName(smartpath+'arscript.txt');
  605. Replace(cmdstr,'$SCRIPT',maybequoted(scriptfile));
  606. Assign(script, scriptfile);
  607. Rewrite(script);
  608. try
  609. writeln(script, 'CREATE ' + current_module.staticlibfilename^);
  610. current := TCmdStrListItem(SmartLinkOFiles.First);
  611. while current <> nil do
  612. begin
  613. writeln(script, 'ADDMOD ' + current.str);
  614. current := TCmdStrListItem(current.next);
  615. end;
  616. writeln(script, 'SAVE');
  617. writeln(script, 'END');
  618. finally
  619. Close(script);
  620. end;
  621. success:=DoExec(binstr,cmdstr,false,true);
  622. end
  623. else
  624. begin
  625. Replace(cmdstr,'$LIB',maybequoted(current_module.staticlibfilename^));
  626. { create AR commands }
  627. success := true;
  628. current := TCmdStrListItem(SmartLinkOFiles.First);
  629. repeat
  630. nextcmd := cmdstr;
  631. Replace(nextcmd,'$FILES',GetNextFiles(2047, current));
  632. success:=DoExec(binstr,nextcmd,false,true);
  633. until (not assigned(current)) or (not success);
  634. end;
  635. if (target_ar.arfinishcmd <> '') then
  636. begin
  637. SplitBinCmd(target_ar.arfinishcmd,binstr,cmdstr);
  638. binstr := FindUtil(utilsprefix + binstr);
  639. Replace(cmdstr,'$LIB',maybequoted(current_module.staticlibfilename^));
  640. success:=DoExec(binstr,cmdstr,false,true);
  641. end;
  642. { Clean up }
  643. if not(cs_asm_leave in current_settings.globalswitches) then
  644. if not(cs_link_nolink in current_settings.globalswitches) then
  645. begin
  646. while not SmartLinkOFiles.Empty do
  647. DeleteFile(SmartLinkOFiles.GetFirst);
  648. if scripted_ar then
  649. DeleteFile(scriptfile);
  650. RemoveDir(smartpath);
  651. end
  652. else
  653. begin
  654. AsmRes.AddDeleteCommand(FixFileName(smartpath+current_module.asmprefix^+'*'+target_info.objext));
  655. if scripted_ar then
  656. AsmRes.AddDeleteCommand(scriptfile);
  657. AsmRes.AddDeleteDirCommand(smartpath);
  658. end;
  659. MakeStaticLibrary:=success;
  660. end;
  661. {*****************************************************************************
  662. TINTERNALLINKER
  663. *****************************************************************************}
  664. Constructor TInternalLinker.Create;
  665. begin
  666. inherited Create;
  667. linkscript:=TCmdStrList.Create;
  668. FStaticLibraryList:=TFPHashObjectList.Create(true);
  669. FImportLibraryList:=TFPHashObjectList.Create(true);
  670. exemap:=nil;
  671. exeoutput:=nil;
  672. CObjInput:=TObjInput;
  673. end;
  674. Destructor TInternalLinker.Destroy;
  675. begin
  676. linkscript.free;
  677. StaticLibraryList.Free;
  678. ImportLibraryList.Free;
  679. if assigned(exeoutput) then
  680. begin
  681. exeoutput.free;
  682. exeoutput:=nil;
  683. end;
  684. if assigned(exemap) then
  685. begin
  686. exemap.free;
  687. exemap:=nil;
  688. end;
  689. inherited destroy;
  690. end;
  691. procedure TInternalLinker.AddImportSymbol(const libname,symname:TCmdStr;OrdNr: longint;isvar:boolean);
  692. var
  693. ImportLibrary : TImportLibrary;
  694. ImportSymbol : TFPHashObject;
  695. begin
  696. ImportLibrary:=TImportLibrary(ImportLibraryList.Find(libname));
  697. if not assigned(ImportLibrary) then
  698. ImportLibrary:=TImportLibrary.Create(ImportLibraryList,libname);
  699. ImportSymbol:=TFPHashObject(ImportLibrary.ImportSymbolList.Find(symname));
  700. if not assigned(ImportSymbol) then
  701. ImportSymbol:=TImportSymbol.Create(ImportLibrary.ImportSymbolList,symname,OrdNr,isvar);
  702. end;
  703. procedure TInternalLinker.Load_ReadObject(const para:TCmdStr);
  704. var
  705. objdata : TObjData;
  706. objinput : TObjinput;
  707. objreader : TObjectReader;
  708. fn : TCmdStr;
  709. begin
  710. fn:=FindObjectFile(para,'',false);
  711. Comment(V_Tried,'Reading object '+fn);
  712. objinput:=CObjInput.Create;
  713. objdata:=objinput.newObjData(para);
  714. objreader:=TObjectreader.create;
  715. if objreader.openfile(fn) then
  716. begin
  717. if objinput.ReadObjData(objreader,objdata) then
  718. exeoutput.addobjdata(objdata);
  719. end;
  720. { release input object }
  721. objinput.free;
  722. objreader.free;
  723. end;
  724. procedure TInternalLinker.Load_ReadStaticLibrary(const para:TCmdStr);
  725. var
  726. objreader : TObjectReader;
  727. begin
  728. {$warning TODO Cleanup ignoring of FPC generated libimp*.a files}
  729. { Don't load import libraries }
  730. if copy(ExtractFileName(para),1,6)='libimp' then
  731. exit;
  732. Comment(V_Tried,'Opening library '+para);
  733. objreader:=TArObjectreader.create(para);
  734. TStaticLibrary.Create(StaticLibraryList,para,objreader,CObjInput);
  735. end;
  736. procedure TInternalLinker.ParseScript_Load;
  737. var
  738. s,
  739. para,
  740. keyword : String;
  741. hp : TCmdStrListItem;
  742. begin
  743. exeoutput.Load_Start;
  744. hp:=TCmdStrListItem(linkscript.first);
  745. while assigned(hp) do
  746. begin
  747. s:=hp.str;
  748. if (s='') or (s[1]='#') then
  749. continue;
  750. keyword:=Upper(GetToken(s,' '));
  751. para:=GetToken(s,' ');
  752. if keyword='SYMBOL' then
  753. ExeOutput.Load_Symbol(para)
  754. else if keyword='ENTRYNAME' then
  755. ExeOutput.Load_EntryName(para)
  756. else if keyword='ISSHAREDLIBRARY' then
  757. ExeOutput.Load_IsSharedLibrary
  758. else if keyword='IMAGEBASE' then
  759. ExeOutput.Load_ImageBase(para)
  760. else if keyword='READOBJECT' then
  761. Load_ReadObject(para)
  762. else if keyword='READSTATICLIBRARY' then
  763. Load_ReadStaticLibrary(para);
  764. hp:=TCmdStrListItem(hp.next);
  765. end;
  766. end;
  767. procedure TInternalLinker.ParseScript_Order;
  768. var
  769. s,
  770. para,
  771. keyword : String;
  772. hp : TCmdStrListItem;
  773. begin
  774. exeoutput.Order_Start;
  775. hp:=TCmdStrListItem(linkscript.first);
  776. while assigned(hp) do
  777. begin
  778. s:=hp.str;
  779. if (s='') or (s[1]='#') then
  780. continue;
  781. keyword:=Upper(GetToken(s,' '));
  782. para:=GetToken(s,' ');
  783. if keyword='EXESECTION' then
  784. ExeOutput.Order_ExeSection(para)
  785. else if keyword='ENDEXESECTION' then
  786. ExeOutput.Order_EndExeSection
  787. else if keyword='OBJSECTION' then
  788. ExeOutput.Order_ObjSection(para)
  789. else if keyword='ZEROS' then
  790. ExeOutput.Order_Zeros(para)
  791. else if keyword='SYMBOL' then
  792. ExeOutput.Order_Symbol(para);
  793. hp:=TCmdStrListItem(hp.next);
  794. end;
  795. exeoutput.Order_End;
  796. end;
  797. procedure TInternalLinker.ParseScript_CalcPos;
  798. var
  799. s,
  800. para,
  801. keyword : String;
  802. hp : TCmdStrListItem;
  803. begin
  804. exeoutput.CalcPos_Start;
  805. hp:=TCmdStrListItem(linkscript.first);
  806. while assigned(hp) do
  807. begin
  808. s:=hp.str;
  809. if (s='') or (s[1]='#') then
  810. continue;
  811. keyword:=Upper(GetToken(s,' '));
  812. para:=GetToken(s,' ');
  813. if keyword='EXESECTION' then
  814. ExeOutput.CalcPos_ExeSection(para)
  815. else if keyword='ENDEXESECTION' then
  816. ExeOutput.CalcPos_EndExeSection
  817. else if keyword='HEADER' then
  818. ExeOutput.CalcPos_Header
  819. else if keyword='SYMBOLS' then
  820. ExeOutput.CalcPos_Symbols;
  821. hp:=TCmdStrListItem(hp.next);
  822. end;
  823. end;
  824. procedure TInternalLinker.PrintLinkerScript;
  825. var
  826. hp : TCmdStrListItem;
  827. begin
  828. if not assigned(exemap) then
  829. exit;
  830. exemap.Add('Used linker script');
  831. exemap.Add('');
  832. hp:=TCmdStrListItem(linkscript.first);
  833. while assigned(hp) do
  834. begin
  835. exemap.Add(hp.str);
  836. hp:=TCmdStrListItem(hp.next);
  837. end;
  838. end;
  839. function TInternalLinker.RunLinkScript(const outputname:TCmdStr):boolean;
  840. label
  841. myexit;
  842. var
  843. bsssize : aint;
  844. bsssec : TExeSection;
  845. begin
  846. result:=false;
  847. Message1(exec_i_linking,outputname);
  848. FlushOutput;
  849. {$warning TODO Load custom linker script}
  850. DefaultLinkScript;
  851. exeoutput:=CExeOutput.Create;
  852. if (cs_link_map in current_settings.globalswitches) then
  853. exemap:=texemap.create(current_module.mapfilename^);
  854. PrintLinkerScript;
  855. { Load .o files and resolve symbols }
  856. ParseScript_Load;
  857. exeoutput.ResolveSymbols(StaticLibraryList);
  858. { Generate symbols and code to do the importing }
  859. exeoutput.GenerateLibraryImports(ImportLibraryList);
  860. { Fill external symbols data }
  861. exeoutput.FixupSymbols;
  862. if ErrorCount>0 then
  863. goto myexit;
  864. { Create .exe sections and add .o sections }
  865. ParseScript_Order;
  866. exeoutput.RemoveUnreferencedSections;
  867. exeoutput.MergeStabs;
  868. exeoutput.RemoveEmptySections;
  869. if ErrorCount>0 then
  870. goto myexit;
  871. { Calc positions in mem and file }
  872. ParseScript_CalcPos;
  873. exeoutput.FixupRelocations;
  874. exeoutput.PrintMemoryMap;
  875. if ErrorCount>0 then
  876. goto myexit;
  877. exeoutput.WriteExeFile(outputname);
  878. if cs_link_separate_dbg_file in current_settings.globalswitches then
  879. exeoutput.WriteDbgFile(ChangeFileExt(outputname,'.dbg'));
  880. {$warning TODO fixed section names}
  881. status.codesize:=exeoutput.findexesection('.text').size;
  882. status.datasize:=exeoutput.findexesection('.data').size;
  883. bsssec:=exeoutput.findexesection('.bss');
  884. if assigned(bsssec) then
  885. bsssize:=bsssec.size
  886. else
  887. bsssize:=0;
  888. { Executable info }
  889. Message1(execinfo_x_codesize,tostr(status.codesize));
  890. Message1(execinfo_x_initdatasize,tostr(status.datasize));
  891. Message1(execinfo_x_uninitdatasize,tostr(bsssize));
  892. Message1(execinfo_x_stackreserve,tostr(stacksize));
  893. myexit:
  894. { close map }
  895. if assigned(exemap) then
  896. begin
  897. exemap.free;
  898. exemap:=nil;
  899. end;
  900. { close exe }
  901. exeoutput.free;
  902. exeoutput:=nil;
  903. result:=true;
  904. end;
  905. function TInternalLinker.MakeExecutable:boolean;
  906. begin
  907. IsSharedLibrary:=false;
  908. result:=RunLinkScript(current_module.exefilename^);
  909. end;
  910. function TInternalLinker.MakeSharedLibrary:boolean;
  911. begin
  912. IsSharedLibrary:=true;
  913. result:=RunLinkScript(current_module.sharedlibfilename^);
  914. end;
  915. {*****************************************************************************
  916. Init/Done
  917. *****************************************************************************}
  918. procedure InitLinker;
  919. var
  920. lk : TlinkerClass;
  921. begin
  922. if (cs_link_extern in current_settings.globalswitches) and
  923. assigned(target_info.linkextern) then
  924. begin
  925. lk:=TlinkerClass(target_info.linkextern);
  926. linker:=lk.Create;
  927. end
  928. else
  929. if assigned(target_info.link) then
  930. begin
  931. lk:=TLinkerClass(target_info.link);
  932. linker:=lk.Create;
  933. end
  934. else
  935. linker:=Tlinker.Create;
  936. end;
  937. procedure DoneLinker;
  938. begin
  939. if assigned(linker) then
  940. Linker.Free;
  941. end;
  942. {*****************************************************************************
  943. Initialize
  944. *****************************************************************************}
  945. const
  946. ar_gnu_ar_info : tarinfo =
  947. (
  948. id : ar_gnu_ar;
  949. arcmd : 'ar qS $LIB $FILES';
  950. arfinishcmd : 'ar s $LIB'
  951. );
  952. ar_gnu_ar_scripted_info : tarinfo =
  953. (
  954. id : ar_gnu_ar_scripted;
  955. arcmd : 'ar -M < $SCRIPT';
  956. arfinishcmd : ''
  957. );
  958. ar_gnu_gar_info : tarinfo =
  959. ( id : ar_gnu_gar;
  960. arcmd : 'gar qS $LIB $FILES';
  961. arfinishcmd : 'gar s $LIB'
  962. );
  963. initialization
  964. RegisterAr(ar_gnu_ar_info);
  965. RegisterAr(ar_gnu_ar_scripted_info);
  966. RegisterAr(ar_gnu_gar_info);
  967. end.