link.pas 41 KB

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