link.pas 41 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259
  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,symmangledname: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,symmangledname: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,
  399. ImportSymbol.MangledName,ImportSymbol.OrdNr,ImportSymbol.IsVar);
  400. end;
  401. end;
  402. end;
  403. end;
  404. procedure TLinker.AddImportSymbol(const libname,symname,symmangledname:TCmdStr;OrdNr: longint;isvar:boolean);
  405. begin
  406. end;
  407. Procedure TLinker.AddObject(const S,unitpath : TCmdStr;isunit:boolean);
  408. begin
  409. ObjectFiles.Concat(FindObjectFile(s,unitpath,isunit));
  410. end;
  411. Procedure TLinker.AddSharedLibrary(S:TCmdStr);
  412. begin
  413. if s='' then
  414. exit;
  415. { remove prefix 'lib' }
  416. if Copy(s,1,length(target_info.sharedlibprefix))=target_info.sharedlibprefix then
  417. Delete(s,1,length(target_info.sharedlibprefix));
  418. { remove extension if any }
  419. if Copy(s,length(s)-length(target_info.sharedlibext)+1,length(target_info.sharedlibext))=target_info.sharedlibext then
  420. Delete(s,length(s)-length(target_info.sharedlibext)+1,length(target_info.sharedlibext)+1);
  421. { ready to be added }
  422. SharedLibFiles.Concat(S);
  423. end;
  424. Procedure TLinker.AddStaticLibrary(const S:TCmdStr);
  425. var
  426. ns : TCmdStr;
  427. found : boolean;
  428. begin
  429. if s='' then
  430. exit;
  431. found:=FindLibraryFile(s,target_info.staticlibprefix,target_info.staticlibext,ns);
  432. if not(cs_link_nolink in current_settings.globalswitches) and (not found) then
  433. Message1(exec_w_libfile_not_found,s);
  434. StaticLibFiles.Concat(ns);
  435. end;
  436. Procedure TLinker.AddSharedCLibrary(S:TCmdStr);
  437. begin
  438. if s='' then
  439. exit;
  440. { remove prefix 'lib' }
  441. if Copy(s,1,length(target_info.sharedclibprefix))=target_info.sharedclibprefix then
  442. Delete(s,1,length(target_info.sharedclibprefix));
  443. { remove extension if any }
  444. if Copy(s,length(s)-length(target_info.sharedclibext)+1,length(target_info.sharedclibext))=target_info.sharedclibext then
  445. Delete(s,length(s)-length(target_info.sharedclibext)+1,length(target_info.sharedclibext)+1);
  446. { ready to be added }
  447. SharedLibFiles.Concat(S);
  448. end;
  449. Procedure TLinker.AddFramework(S:TCmdStr);
  450. begin
  451. if s='' then
  452. exit;
  453. { ready to be added }
  454. FrameworkFiles.Concat(S);
  455. end;
  456. Procedure TLinker.AddStaticCLibrary(const S:TCmdStr);
  457. var
  458. ns : TCmdStr;
  459. found : boolean;
  460. begin
  461. if s='' then
  462. exit;
  463. found:=FindLibraryFile(s,target_info.staticclibprefix,target_info.staticclibext,ns);
  464. if not(cs_link_nolink in current_settings.globalswitches) and (not found) then
  465. Message1(exec_w_libfile_not_found,s);
  466. StaticLibFiles.Concat(ns);
  467. end;
  468. procedure AddImportSymbol(const libname,symname,symmangledname:TCmdStr;OrdNr: longint;isvar:boolean);
  469. begin
  470. end;
  471. procedure TLinker.InitSysInitUnitName;
  472. begin
  473. end;
  474. function TLinker.MakeExecutable:boolean;
  475. begin
  476. MakeExecutable:=false;
  477. Message(exec_e_exe_not_supported);
  478. end;
  479. Function TLinker.MakeSharedLibrary:boolean;
  480. begin
  481. MakeSharedLibrary:=false;
  482. Message(exec_e_dll_not_supported);
  483. end;
  484. Function TLinker.MakeStaticLibrary:boolean;
  485. begin
  486. MakeStaticLibrary:=false;
  487. Message(exec_e_dll_not_supported);
  488. end;
  489. Procedure TLinker.ExpandAndApplyOrder(var Src:TCmdStrList);
  490. var
  491. p : TLinkStrMap;
  492. i : longint;
  493. begin
  494. // call Virtual TLinker method to initialize
  495. LoadPredefinedLibraryOrder;
  496. // something to do?
  497. if (LinkLibraryAliases.count=0) and (LinkLibraryOrder.Count=0) Then
  498. exit;
  499. p:=TLinkStrMap.Create;
  500. // expand libaliases, clears src
  501. LinkLibraryAliases.expand(src,p);
  502. // writeln(src.count,' ',p.count,' ',linklibraryorder.count,' ',linklibraryaliases.count);
  503. // apply order
  504. p.UpdateWeights(LinkLibraryOrder);
  505. p.SortOnWeight;
  506. // put back in src
  507. for i:=0 to p.count-1 do
  508. src.insert(p[i].Key);
  509. p.free;
  510. end;
  511. procedure TLinker.LoadPredefinedLibraryOrder;
  512. begin
  513. end;
  514. function TLinker.ReOrderEntries : boolean;
  515. begin
  516. result:=(LinkLibraryOrder.count>0) or (LinkLibraryAliases.count>0);
  517. end;
  518. {*****************************************************************************
  519. TEXTERNALLINKER
  520. *****************************************************************************}
  521. Constructor TExternalLinker.Create;
  522. begin
  523. inherited Create;
  524. { set generic defaults }
  525. FillChar(Info,sizeof(Info),0);
  526. if cs_link_on_target in current_settings.globalswitches then
  527. begin
  528. Info.ResName:=outputexedir+ChangeFileExt(inputfilename,'_link.res');
  529. Info.ScriptName:=outputexedir+ChangeFileExt(inputfilename,'_script.res');
  530. end
  531. else
  532. begin
  533. Info.ResName:='link.res';
  534. Info.ScriptName:='script.res';
  535. end;
  536. { set the linker specific defaults }
  537. SetDefaultInfo;
  538. { Allow Parameter overrides for linker info }
  539. with Info do
  540. begin
  541. if ParaLinkOptions<>'' then
  542. ExtraOptions:=ParaLinkOptions;
  543. if ParaDynamicLinker<>'' then
  544. DynamicLinker:=ParaDynamicLinker;
  545. end;
  546. end;
  547. Destructor TExternalLinker.Destroy;
  548. begin
  549. inherited destroy;
  550. end;
  551. Procedure TExternalLinker.SetDefaultInfo;
  552. begin
  553. end;
  554. Function TExternalLinker.FindUtil(const s:TCmdStr):TCmdStr;
  555. var
  556. Found : boolean;
  557. FoundBin : TCmdStr;
  558. UtilExe : TCmdStr;
  559. begin
  560. if cs_link_on_target in current_settings.globalswitches then
  561. begin
  562. { If linking on target, don't add any path PM }
  563. FindUtil:=ChangeFileExt(s,target_info.exeext);
  564. exit;
  565. end;
  566. UtilExe:=ChangeFileExt(s,source_info.exeext);
  567. FoundBin:='';
  568. Found:=false;
  569. if utilsdirectory<>'' then
  570. Found:=FindFile(utilexe,utilsdirectory,false,Foundbin);
  571. if (not Found) then
  572. Found:=FindExe(utilexe,false,Foundbin);
  573. if (not Found) and not(cs_link_nolink in current_settings.globalswitches) then
  574. begin
  575. Message1(exec_e_util_not_found,utilexe);
  576. current_settings.globalswitches:=current_settings.globalswitches+[cs_link_nolink];
  577. end;
  578. if (FoundBin<>'') then
  579. Message1(exec_t_using_util,FoundBin);
  580. FindUtil:=FoundBin;
  581. end;
  582. Function TExternalLinker.DoExec(const command:TCmdStr; para:TCmdStr;showinfo,useshell:boolean):boolean;
  583. var
  584. exitcode: longint;
  585. begin
  586. DoExec:=true;
  587. if not(cs_link_nolink in current_settings.globalswitches) then
  588. begin
  589. FlushOutput;
  590. if useshell then
  591. exitcode:=shell(maybequoted(command)+' '+para)
  592. else
  593. try
  594. exitcode:=ExecuteProcess(command,para);
  595. except on E:EOSError do
  596. begin
  597. Message(exec_e_cant_call_linker);
  598. current_settings.globalswitches:=current_settings.globalswitches+[cs_link_nolink];
  599. DoExec:=false;
  600. end;
  601. end;
  602. if (exitcode<>0) then
  603. begin
  604. Message(exec_e_error_while_linking);
  605. current_settings.globalswitches:=current_settings.globalswitches+[cs_link_nolink];
  606. DoExec:=false;
  607. end;
  608. end;
  609. { Update asmres when externmode is set }
  610. if cs_link_nolink in current_settings.globalswitches then
  611. begin
  612. if showinfo then
  613. begin
  614. if DLLsource then
  615. AsmRes.AddLinkCommand(Command,Para,current_module.sharedlibfilename^)
  616. else
  617. AsmRes.AddLinkCommand(Command,Para,current_module.exefilename^);
  618. end
  619. else
  620. AsmRes.AddLinkCommand(Command,Para,'');
  621. end;
  622. end;
  623. Function TExternalLinker.MakeStaticLibrary:boolean;
  624. function GetNextFiles(const maxCmdLength : Longint; var item : TCmdStrListItem) : TCmdStr;
  625. begin
  626. result := '';
  627. while (assigned(item) and ((length(result) + length(item.str) + 1) < maxCmdLength)) do begin
  628. result := result + ' ' + item.str;
  629. item := TCmdStrListItem(item.next);
  630. end;
  631. end;
  632. var
  633. binstr, scriptfile : TCmdStr;
  634. cmdstr, nextcmd, smartpath : TCmdStr;
  635. current : TCmdStrListItem;
  636. script: Text;
  637. scripted_ar : boolean;
  638. success : boolean;
  639. begin
  640. MakeStaticLibrary:=false;
  641. { remove the library, to be sure that it is rewritten }
  642. DeleteFile(current_module.staticlibfilename^);
  643. { Call AR }
  644. smartpath:=FixPath(ChangeFileExt(current_module.asmfilename^,target_info.smartext),false);
  645. SplitBinCmd(target_ar.arcmd,binstr,cmdstr);
  646. binstr := FindUtil(utilsprefix + binstr);
  647. scripted_ar:=target_ar.id=ar_gnu_ar_scripted;
  648. if scripted_ar then
  649. begin
  650. scriptfile := FixFileName(smartpath+'arscript.txt');
  651. Replace(cmdstr,'$SCRIPT',maybequoted(scriptfile));
  652. Assign(script, scriptfile);
  653. Rewrite(script);
  654. try
  655. writeln(script, 'CREATE ' + current_module.staticlibfilename^);
  656. current := TCmdStrListItem(SmartLinkOFiles.First);
  657. while current <> nil do
  658. begin
  659. writeln(script, 'ADDMOD ' + current.str);
  660. current := TCmdStrListItem(current.next);
  661. end;
  662. writeln(script, 'SAVE');
  663. writeln(script, 'END');
  664. finally
  665. Close(script);
  666. end;
  667. success:=DoExec(binstr,cmdstr,false,true);
  668. end
  669. else
  670. begin
  671. Replace(cmdstr,'$LIB',maybequoted(current_module.staticlibfilename^));
  672. { create AR commands }
  673. success := true;
  674. current := TCmdStrListItem(SmartLinkOFiles.First);
  675. repeat
  676. nextcmd := cmdstr;
  677. Replace(nextcmd,'$FILES',GetNextFiles(2047, current));
  678. success:=DoExec(binstr,nextcmd,false,true);
  679. until (not assigned(current)) or (not success);
  680. end;
  681. if (target_ar.arfinishcmd <> '') then
  682. begin
  683. SplitBinCmd(target_ar.arfinishcmd,binstr,cmdstr);
  684. binstr := FindUtil(utilsprefix + binstr);
  685. Replace(cmdstr,'$LIB',maybequoted(current_module.staticlibfilename^));
  686. success:=DoExec(binstr,cmdstr,false,true);
  687. end;
  688. { Clean up }
  689. if not(cs_asm_leave in current_settings.globalswitches) then
  690. if not(cs_link_nolink in current_settings.globalswitches) then
  691. begin
  692. while not SmartLinkOFiles.Empty do
  693. DeleteFile(SmartLinkOFiles.GetFirst);
  694. if scripted_ar then
  695. DeleteFile(scriptfile);
  696. RemoveDir(smartpath);
  697. end
  698. else
  699. begin
  700. AsmRes.AddDeleteCommand(FixFileName(smartpath+current_module.asmprefix^+'*'+target_info.objext));
  701. if scripted_ar then
  702. AsmRes.AddDeleteCommand(scriptfile);
  703. AsmRes.AddDeleteDirCommand(smartpath);
  704. end;
  705. MakeStaticLibrary:=success;
  706. end;
  707. {*****************************************************************************
  708. TINTERNALLINKER
  709. *****************************************************************************}
  710. Constructor TInternalLinker.Create;
  711. begin
  712. inherited Create;
  713. linkscript:=TCmdStrList.Create;
  714. FStaticLibraryList:=TFPHashObjectList.Create(true);
  715. FImportLibraryList:=TFPHashObjectList.Create(true);
  716. exemap:=nil;
  717. exeoutput:=nil;
  718. CObjInput:=TObjInput;
  719. end;
  720. Destructor TInternalLinker.Destroy;
  721. begin
  722. linkscript.free;
  723. StaticLibraryList.Free;
  724. ImportLibraryList.Free;
  725. if assigned(exeoutput) then
  726. begin
  727. exeoutput.free;
  728. exeoutput:=nil;
  729. end;
  730. if assigned(exemap) then
  731. begin
  732. exemap.free;
  733. exemap:=nil;
  734. end;
  735. inherited destroy;
  736. end;
  737. procedure TInternalLinker.AddImportSymbol(const libname,symname,symmangledname:TCmdStr;OrdNr: longint;isvar:boolean);
  738. var
  739. ImportLibrary : TImportLibrary;
  740. ImportSymbol : TFPHashObject;
  741. begin
  742. ImportLibrary:=TImportLibrary(ImportLibraryList.Find(libname));
  743. if not assigned(ImportLibrary) then
  744. ImportLibrary:=TImportLibrary.Create(ImportLibraryList,libname);
  745. ImportSymbol:=TFPHashObject(ImportLibrary.ImportSymbolList.Find(symname));
  746. if not assigned(ImportSymbol) then
  747. ImportSymbol:=TImportSymbol.Create(ImportLibrary.ImportSymbolList,symname,symmangledname,OrdNr,isvar);
  748. end;
  749. procedure TInternalLinker.Load_ReadObject(const para:TCmdStr);
  750. var
  751. objdata : TObjData;
  752. objinput : TObjinput;
  753. objreader : TObjectReader;
  754. fn : TCmdStr;
  755. begin
  756. fn:=FindObjectFile(para,'',false);
  757. Comment(V_Tried,'Reading object '+fn);
  758. objinput:=CObjInput.Create;
  759. objdata:=objinput.newObjData(para);
  760. objreader:=TObjectreader.create;
  761. if objreader.openfile(fn) then
  762. begin
  763. if objinput.ReadObjData(objreader,objdata) then
  764. exeoutput.addobjdata(objdata);
  765. end;
  766. { release input object }
  767. objinput.free;
  768. objreader.free;
  769. end;
  770. procedure TInternalLinker.Load_ReadStaticLibrary(const para:TCmdStr);
  771. var
  772. objreader : TObjectReader;
  773. begin
  774. { TODO: Cleanup ignoring of FPC generated libimp*.a files}
  775. { Don't load import libraries }
  776. if copy(ExtractFileName(para),1,6)='libimp' then
  777. exit;
  778. Comment(V_Tried,'Opening library '+para);
  779. objreader:=TArObjectreader.create(para);
  780. TStaticLibrary.Create(StaticLibraryList,para,objreader,CObjInput);
  781. end;
  782. procedure TInternalLinker.ParseScript_Handle;
  783. var
  784. s,
  785. para,
  786. keyword : String;
  787. hp : TCmdStrListItem;
  788. begin
  789. exeoutput.Load_Start;
  790. hp:=TCmdStrListItem(linkscript.first);
  791. while assigned(hp) do
  792. begin
  793. s:=hp.str;
  794. if (s='') or (s[1]='#') then
  795. continue;
  796. keyword:=Upper(GetToken(s,' '));
  797. para:=GetToken(s,' ');
  798. if Trim(s)<>'' then
  799. Comment(V_Warning,'Unknown part "'+s+'" in "'+hp.str+'" internal linker script');
  800. if (keyword<>'SYMBOL') and
  801. (keyword<>'PROVIDE') and
  802. (keyword<>'ZEROES') and
  803. (keyword<>'BYTE') and
  804. (keyword<>'WORD') and
  805. (keyword<>'LONG') and
  806. (keyword<>'QUAD') and
  807. (keyword<>'ENTRYNAME') and
  808. (keyword<>'ISSHAREDLIBRARY') and
  809. (keyword<>'IMAGEBASE') and
  810. (keyword<>'READOBJECT') and
  811. (keyword<>'READSTATICLIBRARY') and
  812. (keyword<>'EXESECTION') and
  813. (keyword<>'ENDEXESECTION') and
  814. (keyword<>'OBJSECTION') and
  815. (keyword<>'HEADER')
  816. then
  817. Comment(V_Warning,'Unknown keyword "'+keyword+'" in "'+hp.str
  818. +'" internal linker script');
  819. hp:=TCmdStrListItem(hp.next);
  820. end;
  821. end;
  822. procedure TInternalLinker.ParseScript_Load;
  823. var
  824. s,
  825. para,
  826. keyword : String;
  827. hp : TCmdStrListItem;
  828. begin
  829. exeoutput.Load_Start;
  830. hp:=TCmdStrListItem(linkscript.first);
  831. while assigned(hp) do
  832. begin
  833. s:=hp.str;
  834. if (s='') or (s[1]='#') then
  835. continue;
  836. keyword:=Upper(GetToken(s,' '));
  837. para:=GetToken(s,' ');
  838. if keyword='SYMBOL' then
  839. ExeOutput.Load_Symbol(para)
  840. else if keyword='PROVIDE' then
  841. ExeOutput.Load_ProvideSymbol(para)
  842. else if keyword='ENTRYNAME' then
  843. ExeOutput.Load_EntryName(para)
  844. else if keyword='ISSHAREDLIBRARY' then
  845. ExeOutput.Load_IsSharedLibrary
  846. else if keyword='IMAGEBASE' then
  847. ExeOutput.Load_ImageBase(para)
  848. else if keyword='READOBJECT' then
  849. Load_ReadObject(para)
  850. else if keyword='READSTATICLIBRARY' then
  851. Load_ReadStaticLibrary(para);
  852. hp:=TCmdStrListItem(hp.next);
  853. end;
  854. end;
  855. procedure TInternalLinker.ParseScript_Order;
  856. var
  857. s,
  858. para,
  859. keyword : String;
  860. hp : TCmdStrListItem;
  861. begin
  862. exeoutput.Order_Start;
  863. hp:=TCmdStrListItem(linkscript.first);
  864. while assigned(hp) do
  865. begin
  866. s:=hp.str;
  867. if (s='') or (s[1]='#') then
  868. continue;
  869. keyword:=Upper(GetToken(s,' '));
  870. para:=GetToken(s,' ');
  871. if keyword='EXESECTION' then
  872. ExeOutput.Order_ExeSection(para)
  873. else if keyword='ENDEXESECTION' then
  874. ExeOutput.Order_EndExeSection
  875. else if keyword='OBJSECTION' then
  876. ExeOutput.Order_ObjSection(para)
  877. else if keyword='ZEROS' then
  878. ExeOutput.Order_Zeros(para)
  879. else if keyword='BYTE' then
  880. ExeOutput.Order_Values(1,para)
  881. else if keyword='WORD' then
  882. ExeOutput.Order_Values(2,para)
  883. else if keyword='LONG' then
  884. ExeOutput.Order_Values(4,para)
  885. else if keyword='QUAD' then
  886. ExeOutput.Order_Values(8,para)
  887. else if keyword='SYMBOL' then
  888. ExeOutput.Order_Symbol(para)
  889. else if keyword='PROVIDE' then
  890. ExeOutput.Order_ProvideSymbol(para);
  891. hp:=TCmdStrListItem(hp.next);
  892. end;
  893. exeoutput.Order_End;
  894. end;
  895. procedure TInternalLinker.ParseScript_MemPos;
  896. var
  897. s,
  898. para,
  899. keyword : String;
  900. hp : TCmdStrListItem;
  901. begin
  902. exeoutput.MemPos_Start;
  903. hp:=TCmdStrListItem(linkscript.first);
  904. while assigned(hp) do
  905. begin
  906. s:=hp.str;
  907. if (s='') or (s[1]='#') then
  908. continue;
  909. keyword:=Upper(GetToken(s,' '));
  910. para:=GetToken(s,' ');
  911. if keyword='EXESECTION' then
  912. ExeOutput.MemPos_ExeSection(para)
  913. else if keyword='ENDEXESECTION' then
  914. ExeOutput.MemPos_EndExeSection
  915. else if keyword='HEADER' then
  916. ExeOutput.MemPos_Header;
  917. hp:=TCmdStrListItem(hp.next);
  918. end;
  919. end;
  920. procedure TInternalLinker.ParseScript_DataPos;
  921. var
  922. s,
  923. para,
  924. keyword : String;
  925. hp : TCmdStrListItem;
  926. begin
  927. exeoutput.DataPos_Start;
  928. hp:=TCmdStrListItem(linkscript.first);
  929. while assigned(hp) do
  930. begin
  931. s:=hp.str;
  932. if (s='') or (s[1]='#') then
  933. continue;
  934. keyword:=Upper(GetToken(s,' '));
  935. para:=GetToken(s,' ');
  936. if keyword='EXESECTION' then
  937. ExeOutput.DataPos_ExeSection(para)
  938. else if keyword='ENDEXESECTION' then
  939. ExeOutput.DataPos_EndExeSection
  940. else if keyword='HEADER' then
  941. ExeOutput.DataPos_Header
  942. else if keyword='SYMBOLS' then
  943. ExeOutput.DataPos_Symbols;
  944. hp:=TCmdStrListItem(hp.next);
  945. end;
  946. end;
  947. procedure TInternalLinker.PrintLinkerScript;
  948. var
  949. hp : TCmdStrListItem;
  950. begin
  951. if not assigned(exemap) then
  952. exit;
  953. exemap.Add('Used linker script');
  954. exemap.Add('');
  955. hp:=TCmdStrListItem(linkscript.first);
  956. while assigned(hp) do
  957. begin
  958. exemap.Add(hp.str);
  959. hp:=TCmdStrListItem(hp.next);
  960. end;
  961. end;
  962. function TInternalLinker.RunLinkScript(const outputname:TCmdStr):boolean;
  963. label
  964. myexit;
  965. var
  966. bsssize : aword;
  967. bsssec : TExeSection;
  968. dbgname : TCmdStr;
  969. begin
  970. result:=false;
  971. Message1(exec_i_linking,outputname);
  972. FlushOutput;
  973. { TODO: Load custom linker script}
  974. DefaultLinkScript;
  975. exeoutput:=CExeOutput.Create;
  976. if (cs_link_map in current_settings.globalswitches) then
  977. exemap:=texemap.create(current_module.mapfilename^);
  978. PrintLinkerScript;
  979. { Load .o files and resolve symbols }
  980. ParseScript_Load;
  981. exeoutput.ResolveSymbols(StaticLibraryList);
  982. { Generate symbols and code to do the importing }
  983. exeoutput.GenerateLibraryImports(ImportLibraryList);
  984. { Fill external symbols data }
  985. exeoutput.FixupSymbols;
  986. if ErrorCount>0 then
  987. goto myexit;
  988. { parse linker options specific for output format }
  989. exeoutput.ParseScript (linkscript);
  990. { Create .exe sections and add .o sections }
  991. ParseScript_Order;
  992. exeoutput.RemoveUnreferencedSections;
  993. exeoutput.MergeStabs;
  994. exeoutput.RemoveEmptySections;
  995. if ErrorCount>0 then
  996. goto myexit;
  997. { Calc positions in mem }
  998. ParseScript_MemPos;
  999. exeoutput.FixupRelocations;
  1000. exeoutput.PrintMemoryMap;
  1001. if ErrorCount>0 then
  1002. goto myexit;
  1003. if cs_link_separate_dbg_file in current_settings.globalswitches then
  1004. begin
  1005. { create debuginfo, which is an executable without data on disk }
  1006. dbgname:=ChangeFileExt(outputname,'.dbg');
  1007. exeoutput.ExeWriteMode:=ewm_dbgonly;
  1008. ParseScript_DataPos;
  1009. exeoutput.WriteExeFile(dbgname);
  1010. { create executable with link to just created debuginfo file }
  1011. exeoutput.ExeWriteMode:=ewm_exeonly;
  1012. exeoutput.RemoveDebugInfo;
  1013. exeoutput.GenerateDebugLink(ExtractFileName(dbgname),GetFileCRC(dbgname));
  1014. ParseScript_MemPos;
  1015. ParseScript_DataPos;
  1016. exeoutput.WriteExeFile(outputname);
  1017. end
  1018. else
  1019. begin
  1020. exeoutput.ExeWriteMode:=ewm_exefull;
  1021. ParseScript_DataPos;
  1022. exeoutput.WriteExeFile(outputname);
  1023. end;
  1024. { TODO: fixed section names}
  1025. status.codesize:=exeoutput.findexesection('.text').size;
  1026. status.datasize:=exeoutput.findexesection('.data').size;
  1027. bsssec:=exeoutput.findexesection('.bss');
  1028. if assigned(bsssec) then
  1029. bsssize:=bsssec.size
  1030. else
  1031. bsssize:=0;
  1032. { Executable info }
  1033. Message1(execinfo_x_codesize,tostr(status.codesize));
  1034. Message1(execinfo_x_initdatasize,tostr(status.datasize));
  1035. Message1(execinfo_x_uninitdatasize,tostr(bsssize));
  1036. Message1(execinfo_x_stackreserve,tostr(stacksize));
  1037. myexit:
  1038. { close map }
  1039. if assigned(exemap) then
  1040. begin
  1041. exemap.free;
  1042. exemap:=nil;
  1043. end;
  1044. { close exe }
  1045. exeoutput.free;
  1046. exeoutput:=nil;
  1047. result:=true;
  1048. end;
  1049. function TInternalLinker.MakeExecutable:boolean;
  1050. begin
  1051. IsSharedLibrary:=false;
  1052. result:=RunLinkScript(current_module.exefilename^);
  1053. end;
  1054. function TInternalLinker.MakeSharedLibrary:boolean;
  1055. begin
  1056. IsSharedLibrary:=true;
  1057. result:=RunLinkScript(current_module.sharedlibfilename^);
  1058. end;
  1059. {*****************************************************************************
  1060. Init/Done
  1061. *****************************************************************************}
  1062. procedure InitLinker;
  1063. var
  1064. lk : TlinkerClass;
  1065. begin
  1066. if (cs_link_extern in current_settings.globalswitches) and
  1067. assigned(target_info.linkextern) then
  1068. begin
  1069. lk:=TlinkerClass(target_info.linkextern);
  1070. linker:=lk.Create;
  1071. end
  1072. else
  1073. if assigned(target_info.link) then
  1074. begin
  1075. lk:=TLinkerClass(target_info.link);
  1076. linker:=lk.Create;
  1077. end
  1078. else
  1079. linker:=Tlinker.Create;
  1080. end;
  1081. procedure DoneLinker;
  1082. begin
  1083. if assigned(linker) then
  1084. Linker.Free;
  1085. end;
  1086. {*****************************************************************************
  1087. Initialize
  1088. *****************************************************************************}
  1089. const
  1090. ar_gnu_ar_info : tarinfo =
  1091. (
  1092. id : ar_gnu_ar;
  1093. arcmd : 'ar qS $LIB $FILES';
  1094. arfinishcmd : 'ar s $LIB'
  1095. );
  1096. ar_gnu_ar_scripted_info : tarinfo =
  1097. (
  1098. id : ar_gnu_ar_scripted;
  1099. arcmd : 'ar -M < $SCRIPT';
  1100. arfinishcmd : ''
  1101. );
  1102. ar_gnu_gar_info : tarinfo =
  1103. ( id : ar_gnu_gar;
  1104. arcmd : 'gar qS $LIB $FILES';
  1105. arfinishcmd : 'gar s $LIB'
  1106. );
  1107. initialization
  1108. RegisterAr(ar_gnu_ar_info);
  1109. RegisterAr(ar_gnu_ar_scripted_info);
  1110. RegisterAr(ar_gnu_gar_info);
  1111. end.