link.pas 56 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721
  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. ldscript,
  28. ogbase,
  29. owbase;
  30. Type
  31. TLinkerInfo=record
  32. ExeCmd,
  33. DllCmd,
  34. ExtDbgCmd : array[1..3] of string;
  35. ResName : string[100];
  36. ScriptName : string[100];
  37. ExtraOptions : TCmdStr;
  38. DynamicLinker : string[100];
  39. end;
  40. TLinker = class(TObject)
  41. public
  42. HasResources,
  43. HasExports : boolean;
  44. SysInitUnit : string[20];
  45. ObjectFiles,
  46. SharedLibFiles,
  47. StaticLibFiles,
  48. FrameworkFiles,
  49. OrderedSymbols: TCmdStrList;
  50. Constructor Create;virtual;
  51. Destructor Destroy;override;
  52. procedure AddModuleFiles(hp:tmodule);
  53. Procedure AddObject(const S,unitpath : TPathStr;isunit:boolean);
  54. Procedure AddStaticLibrary(const S : TCmdStr);
  55. Procedure AddSharedLibrary(S : TCmdStr);
  56. Procedure AddStaticCLibrary(const S : TCmdStr);
  57. Procedure AddSharedCLibrary(S : TCmdStr);
  58. Procedure AddFramework(S : TCmdStr);
  59. Procedure AddOrderedSymbol(const s: TCmdStr);
  60. procedure AddImportSymbol(const libname,symname,symmangledname:TCmdStr;OrdNr: longint;isvar:boolean);virtual;
  61. Procedure InitSysInitUnitName;virtual;
  62. Function MakeExecutable:boolean;virtual;
  63. Function MakeSharedLibrary:boolean;virtual;
  64. Function MakeStaticLibrary:boolean;virtual;
  65. procedure ExpandAndApplyOrder(var Src:TCmdStrList);
  66. procedure LoadPredefinedLibraryOrder;virtual;
  67. function ReOrderEntries : boolean;
  68. end;
  69. TExternalLinker = class(TLinker)
  70. public
  71. Info : TLinkerInfo;
  72. Constructor Create;override;
  73. Destructor Destroy;override;
  74. Function FindUtil(const s:TCmdStr):TCmdStr;
  75. Function CatFileContent(para:TCmdStr):TCmdStr;
  76. Function DoExec(const command:TCmdStr; para:TCmdStr;showinfo,useshell:boolean):boolean;
  77. procedure SetDefaultInfo;virtual;
  78. Function MakeStaticLibrary:boolean;override;
  79. end;
  80. TBooleanArray = array [1..1024] of boolean;
  81. PBooleanArray = ^TBooleanArray;
  82. TInternalLinker = class(TLinker)
  83. private
  84. FCExeOutput : TExeOutputClass;
  85. FCObjInput : TObjInputClass;
  86. FCArObjectReader : TObjectReaderClass;
  87. { Libraries }
  88. FStaticLibraryList : TFPObjectList;
  89. FImportLibraryList : TFPHashObjectList;
  90. FGroupStack : TFPObjectList;
  91. procedure Load_ReadObject(const para:TCmdStr);
  92. procedure Load_ReadStaticLibrary(const para:TCmdStr;asneededflag:boolean=false);
  93. procedure Load_Group;
  94. procedure Load_EndGroup;
  95. procedure ParseScript_Handle;
  96. procedure ParseScript_PostCheck;
  97. procedure ParseScript_Load;
  98. function ParsePara(const para : string) : string;
  99. procedure ParseScript_Order;
  100. procedure ParseScript_MemPos;
  101. procedure ParseScript_DataPos;
  102. procedure PrintLinkerScript;
  103. function RunLinkScript(const outputname:TCmdStr):boolean;
  104. procedure ParseLdScript(src:TScriptLexer);
  105. protected
  106. linkscript : TCmdStrList;
  107. ScriptCount : longint;
  108. IsHandled : PBooleanArray;
  109. property CArObjectReader:TObjectReaderClass read FCArObjectReader write FCArObjectReader;
  110. property CObjInput:TObjInputClass read FCObjInput write FCObjInput;
  111. property CExeOutput:TExeOutputClass read FCExeOutput write FCExeOutput;
  112. property StaticLibraryList:TFPObjectList read FStaticLibraryList;
  113. property ImportLibraryList:TFPHashObjectList read FImportLibraryList;
  114. procedure DefaultLinkScript;virtual;abstract;
  115. procedure ScriptAddGenericSections(secnames:string);
  116. procedure ScriptAddSourceStatements(AddSharedAsStatic:boolean);virtual;
  117. function GetCodeSize(aExeOutput: TExeOutput): QWord;virtual;
  118. function GetDataSize(aExeOutput: TExeOutput): QWord;virtual;
  119. function GetBssSize(aExeOutput: TExeOutput): QWord;virtual;
  120. public
  121. IsSharedLibrary : boolean;
  122. UseStabs : boolean;
  123. Constructor Create;override;
  124. Destructor Destroy;override;
  125. Function MakeExecutable:boolean;override;
  126. Function MakeSharedLibrary:boolean;override;
  127. procedure AddImportSymbol(const libname,symname,symmangledname:TCmdStr;OrdNr: longint;isvar:boolean);override;
  128. end;
  129. TLinkerClass = class of Tlinker;
  130. var
  131. Linker : TLinker;
  132. function FindObjectFile(s : TCmdStr;const unitpath:TCmdStr;isunit:boolean) : TCmdStr;
  133. function FindLibraryFile(s:TCmdStr;const prefix,ext:TCmdStr;var foundfile : TCmdStr) : boolean;
  134. function FindDLL(const s:TCmdStr;var founddll:TCmdStr):boolean;
  135. procedure RegisterLinker(id:tlink;c:TLinkerClass);
  136. procedure InitLinker;
  137. procedure DoneLinker;
  138. Implementation
  139. uses
  140. cutils,cfileutl,cstreams,
  141. {$ifdef hasUnix}
  142. baseunix,
  143. {$endif hasUnix}
  144. cscript,globals,verbose,comphook,ppu,fpccrc,
  145. aasmbase,aasmcpu,
  146. ogmap;
  147. var
  148. CLinker : array[tlink] of TLinkerClass;
  149. {*****************************************************************************
  150. Helpers
  151. *****************************************************************************}
  152. function GetFileCRC(const fn:TPathStr):cardinal;
  153. var
  154. fs : TCStream;
  155. bufcount,
  156. bufsize : Integer;
  157. buf : pbyte;
  158. begin
  159. result:=0;
  160. bufsize:=64*1024;
  161. fs:=CFileStreamClass.Create(fn,fmOpenRead or fmShareDenyNone);
  162. if CStreamError<>0 then
  163. begin
  164. fs.Free;
  165. Comment(V_Error,'Can''t open file: '+fn);
  166. exit;
  167. end;
  168. getmem(buf,bufsize);
  169. repeat
  170. bufcount:=fs.Read(buf^,bufsize);
  171. result:=UpdateCrc32(result,buf^,bufcount);
  172. until bufcount<bufsize;
  173. freemem(buf);
  174. fs.Free;
  175. end;
  176. { searches an object file }
  177. function FindObjectFile(s:TCmdStr;const unitpath:TCmdStr;isunit:boolean) : TCmdStr;
  178. var
  179. found : boolean;
  180. foundfile : TCmdStr;
  181. begin
  182. findobjectfile:='';
  183. if s='' then
  184. exit;
  185. {When linking on target, the units has not been assembled yet,
  186. so there is no object files to look for at
  187. the host. Look for the corresponding assembler file instead,
  188. because it will be assembled to object file on the target.}
  189. if isunit and (cs_link_on_target in current_settings.globalswitches) then
  190. s:=ChangeFileExt(s,target_info.asmext);
  191. { when it does not belong to the unit then check if
  192. the specified file exists without searching any paths }
  193. if not isunit then
  194. begin
  195. if FileExists(FixFileName(s),false) then
  196. begin
  197. foundfile:=ScriptFixFileName(s);
  198. found:=true;
  199. end;
  200. end;
  201. if pos('.',s)=0 then
  202. s:=s+target_info.objext;
  203. { find object file
  204. 1. output unit path
  205. 2. output exe path
  206. 3. specified unit path (if specified)
  207. 4. cwd
  208. 5. unit search path
  209. 6. local object path
  210. 7. global object path
  211. 8. exepath (not when linking on target)
  212. for all finds don't use the directory caching }
  213. found:=false;
  214. if isunit and (OutputUnitDir<>'') then
  215. found:=FindFile(s,OutPutUnitDir,false,foundfile)
  216. else
  217. if OutputExeDir<>'' then
  218. found:=FindFile(s,OutPutExeDir,false,foundfile);
  219. if (not found) and (unitpath<>'') then
  220. found:=FindFile(s,unitpath,false,foundfile);
  221. if (not found) then
  222. found:=FindFile(s, CurDirRelPath(source_info),false,foundfile);
  223. if (not found) then
  224. found:=UnitSearchPath.FindFile(s,false,foundfile);
  225. if (not found) then
  226. found:=current_module.localobjectsearchpath.FindFile(s,false,foundfile);
  227. if (not found) then
  228. found:=objectsearchpath.FindFile(s,false,foundfile);
  229. if not(cs_link_on_target in current_settings.globalswitches) and (not found) then
  230. found:=FindFile(s,exepath,false,foundfile);
  231. if not(cs_link_nolink in current_settings.globalswitches) and (not found) then
  232. Message1(exec_w_objfile_not_found,s);
  233. {Restore file extension}
  234. if isunit and (cs_link_on_target in current_settings.globalswitches) then
  235. foundfile:= ChangeFileExt(foundfile,target_info.objext);
  236. findobjectfile:=ScriptFixFileName(foundfile);
  237. end;
  238. { searches a (windows) DLL file }
  239. function FindDLL(const s:TCmdStr;var founddll:TCmdStr):boolean;
  240. var
  241. sysdir : TCmdStr;
  242. Found : boolean;
  243. begin
  244. Found:=false;
  245. { Look for DLL in:
  246. 1. Current dir
  247. 2. Library Path
  248. 3. windir,windir/system,windir/system32 }
  249. Found:=FindFile(s,'.'+source_info.DirSep,false,founddll);
  250. if (not found) then
  251. Found:=librarysearchpath.FindFile(s,false,founddll);
  252. { when cross compiling, it is pretty useless to search windir etc. for dlls }
  253. if (not found) and (source_info.system=target_info.system) then
  254. begin
  255. sysdir:=FixPath(GetEnvironmentVariable('windir'),false);
  256. Found:=FindFile(s,sysdir+';'+sysdir+'system'+source_info.DirSep+';'+sysdir+'system32'+source_info.DirSep,false,founddll);
  257. end;
  258. if (not found) then
  259. begin
  260. message1(exec_w_libfile_not_found,s);
  261. FoundDll:=s;
  262. end;
  263. FindDll:=Found;
  264. end;
  265. { searches an library file }
  266. function FindLibraryFile(s:TCmdStr;const prefix,ext:TCmdStr;var foundfile : TCmdStr) : boolean;
  267. var
  268. found : boolean;
  269. paths : TCmdStr;
  270. begin
  271. findlibraryfile:=false;
  272. foundfile:=s;
  273. if s='' then
  274. exit;
  275. { split path from filename }
  276. paths:=ExtractFilePath(s);
  277. s:=ExtractFileName(s);
  278. { add prefix 'lib' }
  279. if (prefix<>'') and (Copy(s,1,length(prefix))<>prefix) then
  280. s:=prefix+s;
  281. { add extension }
  282. if (ext<>'') and (Copy(s,length(s)-length(ext)+1,length(ext))<>ext) then
  283. s:=s+ext;
  284. { readd the split path }
  285. s:=paths+s;
  286. if FileExists(s,false) then
  287. begin
  288. foundfile:=ScriptFixFileName(s);
  289. FindLibraryFile:=true;
  290. exit;
  291. end;
  292. { find libary
  293. 1. cwd
  294. 2. local libary dir
  295. 3. global libary dir
  296. 4. exe path of the compiler (not when linking on target)
  297. for all searches don't use the directory cache }
  298. found:=FindFile(s, CurDirRelPath(source_info), false,foundfile);
  299. if (not found) and (current_module.outputpath<>'') then
  300. found:=FindFile(s,current_module.outputpath,false,foundfile);
  301. if (not found) then
  302. found:=current_module.locallibrarysearchpath.FindFile(s,false,foundfile);
  303. if (not found) then
  304. found:=librarysearchpath.FindFile(s,false,foundfile);
  305. if not(cs_link_on_target in current_settings.globalswitches) and (not found) then
  306. found:=FindFile(s,exepath,false,foundfile);
  307. foundfile:=ScriptFixFileName(foundfile);
  308. findlibraryfile:=found;
  309. end;
  310. {*****************************************************************************
  311. TLINKER
  312. *****************************************************************************}
  313. Constructor TLinker.Create;
  314. begin
  315. Inherited Create;
  316. ObjectFiles:=TCmdStrList.Create_no_double;
  317. SharedLibFiles:=TCmdStrList.Create_no_double;
  318. StaticLibFiles:=TCmdStrList.Create_no_double;
  319. FrameworkFiles:=TCmdStrList.Create_no_double;
  320. OrderedSymbols:=TCmdStrList.Create;
  321. end;
  322. Destructor TLinker.Destroy;
  323. begin
  324. ObjectFiles.Free;
  325. SharedLibFiles.Free;
  326. StaticLibFiles.Free;
  327. FrameworkFiles.Free;
  328. OrderedSymbols.Free;
  329. inherited;
  330. end;
  331. procedure TLinker.AddModuleFiles(hp:tmodule);
  332. var
  333. mask : longint;
  334. i,j : longint;
  335. ImportLibrary : TImportLibrary;
  336. ImportSymbol : TImportSymbol;
  337. cmdstritem: TCmdStrListItem;
  338. begin
  339. with hp do
  340. begin
  341. if mf_has_resourcefiles in moduleflags then
  342. HasResources:=true;
  343. if mf_has_exports in moduleflags then
  344. HasExports:=true;
  345. { link unit files }
  346. if (headerflags and uf_no_link)=0 then
  347. begin
  348. { create mask which unit files need linking }
  349. mask:=link_always;
  350. { lto linking ?}
  351. if (cs_lto in current_settings.moduleswitches) and
  352. ((headerflags and uf_lto_linked)<>0) and
  353. (not(cs_lto_nosystem in init_settings.globalswitches) or
  354. (hp.modulename^<>'SYSTEM')) then
  355. begin
  356. mask:=mask or link_lto;
  357. end
  358. else
  359. begin
  360. { static linking ? }
  361. if (cs_link_static in current_settings.globalswitches) then
  362. begin
  363. if (headerflags and uf_static_linked)=0 then
  364. begin
  365. { if static not avail then try smart linking }
  366. if (headerflags and uf_smart_linked)<>0 then
  367. begin
  368. Message1(exec_t_unit_not_static_linkable_switch_to_smart,modulename^);
  369. mask:=mask or link_smart;
  370. end
  371. else
  372. Message1(exec_e_unit_not_smart_or_static_linkable,modulename^);
  373. end
  374. else
  375. mask:=mask or link_static;
  376. end;
  377. { smart linking ? }
  378. if (cs_link_smart in current_settings.globalswitches) then
  379. begin
  380. if (headerflags and uf_smart_linked)=0 then
  381. begin
  382. { if smart not avail then try static linking }
  383. if (headerflags and uf_static_linked)<>0 then
  384. begin
  385. { if not create_smartlink_library, then smart linking happens using the
  386. regular object files
  387. }
  388. if create_smartlink_library then
  389. Message1(exec_t_unit_not_smart_linkable_switch_to_static,modulename^);
  390. mask:=mask or link_static;
  391. end
  392. else
  393. Message1(exec_e_unit_not_smart_or_static_linkable,modulename^);
  394. end
  395. else
  396. mask:=mask or link_smart;
  397. end;
  398. { shared linking }
  399. if (cs_link_shared in current_settings.globalswitches) then
  400. begin
  401. if (headerflags and uf_shared_linked)=0 then
  402. begin
  403. { if shared not avail then try static linking }
  404. if (headerflags and uf_static_linked)<>0 then
  405. begin
  406. Message1(exec_t_unit_not_shared_linkable_switch_to_static,modulename^);
  407. mask:=mask or link_static;
  408. end
  409. else
  410. Message1(exec_e_unit_not_shared_or_static_linkable,modulename^);
  411. end
  412. else
  413. mask:=mask or link_shared;
  414. end;
  415. end;
  416. { unit files }
  417. while not linkunitofiles.empty do
  418. AddObject(linkunitofiles.getusemask(mask),path,true);
  419. while not linkunitstaticlibs.empty do
  420. AddStaticLibrary(linkunitstaticlibs.getusemask(mask));
  421. while not linkunitsharedlibs.empty do
  422. AddSharedLibrary(linkunitsharedlibs.getusemask(mask));
  423. end;
  424. { Other needed .o and libs, specified using $L,$LINKLIB,external }
  425. mask:=link_always;
  426. while not linkotherofiles.empty do
  427. AddObject(linkotherofiles.Getusemask(mask),path,false);
  428. while not linkotherstaticlibs.empty do
  429. AddStaticCLibrary(linkotherstaticlibs.Getusemask(mask));
  430. while not linkothersharedlibs.empty do
  431. AddSharedCLibrary(linkothersharedlibs.Getusemask(mask));
  432. while not linkotherframeworks.empty do
  433. AddFramework(linkotherframeworks.Getusemask(mask));
  434. { Known Library/DLL Imports }
  435. for i:=0 to ImportLibraryList.Count-1 do
  436. begin
  437. ImportLibrary:=TImportLibrary(ImportLibraryList[i]);
  438. for j:=0 to ImportLibrary.ImportSymbolList.Count-1 do
  439. begin
  440. ImportSymbol:=TImportSymbol(ImportLibrary.ImportSymbolList[j]);
  441. AddImportSymbol(ImportLibrary.Name,ImportSymbol.Name,
  442. ImportSymbol.MangledName,ImportSymbol.OrdNr,ImportSymbol.IsVar);
  443. end;
  444. end;
  445. { ordered symbols }
  446. OrderedSymbols.concatList(linkorderedsymbols);
  447. end;
  448. end;
  449. procedure TLinker.AddImportSymbol(const libname,symname,symmangledname:TCmdStr;OrdNr: longint;isvar:boolean);
  450. begin
  451. end;
  452. Procedure TLinker.AddObject(const S,unitpath : TPathStr;isunit:boolean);
  453. begin
  454. ObjectFiles.Concat(FindObjectFile(s,unitpath,isunit))
  455. end;
  456. Procedure TLinker.AddSharedLibrary(S:TCmdStr);
  457. begin
  458. if s='' then
  459. exit;
  460. { remove prefix 'lib' }
  461. if Copy(s,1,length(target_info.sharedlibprefix))=target_info.sharedlibprefix then
  462. Delete(s,1,length(target_info.sharedlibprefix));
  463. { remove extension if any }
  464. if Copy(s,length(s)-length(target_info.sharedlibext)+1,length(target_info.sharedlibext))=target_info.sharedlibext then
  465. Delete(s,length(s)-length(target_info.sharedlibext)+1,length(target_info.sharedlibext)+1);
  466. { ready to be added }
  467. SharedLibFiles.Concat(S);
  468. end;
  469. Procedure TLinker.AddStaticLibrary(const S:TCmdStr);
  470. var
  471. ns : TCmdStr;
  472. found : boolean;
  473. begin
  474. if s='' then
  475. exit;
  476. found:=FindLibraryFile(s,target_info.staticlibprefix,target_info.staticlibext,ns);
  477. if not(cs_link_nolink in current_settings.globalswitches) and (not found) then
  478. Message1(exec_w_libfile_not_found,s);
  479. StaticLibFiles.Concat(ns);
  480. end;
  481. Procedure TLinker.AddSharedCLibrary(S:TCmdStr);
  482. begin
  483. if s='' then
  484. exit;
  485. { remove prefix 'lib' }
  486. if Copy(s,1,length(target_info.sharedclibprefix))=target_info.sharedclibprefix then
  487. Delete(s,1,length(target_info.sharedclibprefix));
  488. { remove extension if any }
  489. if Copy(s,length(s)-length(target_info.sharedclibext)+1,length(target_info.sharedclibext))=target_info.sharedclibext then
  490. Delete(s,length(s)-length(target_info.sharedclibext)+1,length(target_info.sharedclibext)+1);
  491. { ready to be added }
  492. SharedLibFiles.Concat(S);
  493. end;
  494. Procedure TLinker.AddFramework(S:TCmdStr);
  495. begin
  496. if s='' then
  497. exit;
  498. { ready to be added }
  499. FrameworkFiles.Concat(S);
  500. end;
  501. procedure TLinker.AddOrderedSymbol(const s: TCmdStr);
  502. begin
  503. OrderedSymbols.Concat(s);
  504. end;
  505. Procedure TLinker.AddStaticCLibrary(const S:TCmdStr);
  506. var
  507. ns : TCmdStr;
  508. found : boolean;
  509. begin
  510. if s='' then
  511. exit;
  512. found:=FindLibraryFile(s,target_info.staticclibprefix,target_info.staticclibext,ns);
  513. if not(cs_link_nolink in current_settings.globalswitches) and (not found) then
  514. Message1(exec_w_libfile_not_found,s);
  515. StaticLibFiles.Concat(ns);
  516. end;
  517. procedure TLinker.InitSysInitUnitName;
  518. begin
  519. end;
  520. function TLinker.MakeExecutable:boolean;
  521. begin
  522. MakeExecutable:=false;
  523. Message(exec_e_exe_not_supported);
  524. end;
  525. Function TLinker.MakeSharedLibrary:boolean;
  526. begin
  527. MakeSharedLibrary:=false;
  528. Message(exec_e_dll_not_supported);
  529. end;
  530. Function TLinker.MakeStaticLibrary:boolean;
  531. begin
  532. MakeStaticLibrary:=false;
  533. Message(exec_e_static_lib_not_supported);
  534. end;
  535. Procedure TLinker.ExpandAndApplyOrder(var Src:TCmdStrList);
  536. var
  537. p : TLinkStrMap;
  538. i : longint;
  539. begin
  540. // call Virtual TLinker method to initialize
  541. LoadPredefinedLibraryOrder;
  542. // something to do?
  543. if (LinkLibraryAliases.count=0) and (LinkLibraryOrder.Count=0) Then
  544. exit;
  545. p:=TLinkStrMap.Create;
  546. // expand libaliases, clears src
  547. LinkLibraryAliases.expand(src,p);
  548. // writeln(src.count,' ',p.count,' ',linklibraryorder.count,' ',linklibraryaliases.count);
  549. // apply order
  550. p.UpdateWeights(LinkLibraryOrder);
  551. p.SortOnWeight;
  552. // put back in src
  553. for i:=0 to p.count-1 do
  554. src.insert(p[i].Key);
  555. p.free;
  556. end;
  557. procedure TLinker.LoadPredefinedLibraryOrder;
  558. begin
  559. end;
  560. function TLinker.ReOrderEntries : boolean;
  561. begin
  562. result:=(LinkLibraryOrder.count>0) or (LinkLibraryAliases.count>0);
  563. end;
  564. {*****************************************************************************
  565. TEXTERNALLINKER
  566. *****************************************************************************}
  567. Constructor TExternalLinker.Create;
  568. begin
  569. inherited Create;
  570. { set generic defaults }
  571. FillChar(Info,sizeof(Info),0);
  572. if cs_link_on_target in current_settings.globalswitches then
  573. begin
  574. Info.ResName:=ChangeFileExt(inputfilename,'_link.res');
  575. Info.ScriptName:=ChangeFileExt(inputfilename,'_script.res');
  576. end
  577. else
  578. begin
  579. if GetProcessID>0 then
  580. begin
  581. Info.ResName:='link'+tostr(GetProcessID)+'.res';
  582. Info.ScriptName:='script'+tostr(GetProcessID)+'.res';
  583. end
  584. else
  585. begin
  586. Info.ResName:='link.res';
  587. Info.ScriptName:='script.res';
  588. end;
  589. end;
  590. { set the linker specific defaults }
  591. SetDefaultInfo;
  592. { Allow Parameter overrides for linker info }
  593. with Info do
  594. begin
  595. if ParaLinkOptions<>'' then
  596. ExtraOptions:=ParaLinkOptions;
  597. if ParaDynamicLinker<>'' then
  598. DynamicLinker:=ParaDynamicLinker;
  599. end;
  600. end;
  601. Destructor TExternalLinker.Destroy;
  602. begin
  603. inherited destroy;
  604. end;
  605. Procedure TExternalLinker.SetDefaultInfo;
  606. begin
  607. end;
  608. Function TExternalLinker.FindUtil(const s:TCmdStr):TCmdStr;
  609. var
  610. Found : boolean;
  611. FoundBin : TCmdStr;
  612. UtilExe : TCmdStr;
  613. begin
  614. if cs_link_on_target in current_settings.globalswitches then
  615. begin
  616. { If linking on target, don't add any path PM }
  617. { change extension only on platforms that use an exe extension, otherwise on OpenBSD 'ld.bfd' gets
  618. converted to 'ld' }
  619. if target_info.exeext<>'' then
  620. FindUtil:=ChangeFileExt(s,target_info.exeext)
  621. else
  622. FindUtil:=s;
  623. exit;
  624. end;
  625. { change extension only on platforms that use an exe extension, otherwise on OpenBSD 'ld.bfd' gets converted
  626. to 'ld' }
  627. if source_info.exeext<>'' then
  628. UtilExe:=ChangeFileExt(s,source_info.exeext)
  629. else
  630. UtilExe:=s;
  631. FoundBin:='';
  632. Found:=false;
  633. if utilsdirectory<>'' then
  634. Found:=FindFile(utilexe,utilsdirectory,false,Foundbin);
  635. if (not Found) then
  636. Found:=FindExe(utilexe,false,Foundbin);
  637. if (not Found) and not(cs_link_nolink in current_settings.globalswitches) then
  638. begin
  639. Message1(exec_e_util_not_found,utilexe);
  640. current_settings.globalswitches:=current_settings.globalswitches+[cs_link_nolink];
  641. end;
  642. if (FoundBin<>'') then
  643. Message1(exec_t_using_util,FoundBin);
  644. FindUtil:=FoundBin;
  645. end;
  646. Function TExternalLinker.CatFileContent(para : TCmdStr) : TCmdStr;
  647. var
  648. filecontent : TCmdStr;
  649. f : text;
  650. st : TCmdStr;
  651. begin
  652. if not (tf_no_backquote_support in source_info.flags) or
  653. (cs_link_on_target in current_settings.globalswitches) then
  654. begin
  655. CatFileContent:='`cat '+MaybeQuoted(para)+'`';
  656. Exit;
  657. end;
  658. assign(f,para);
  659. filecontent:='';
  660. {$push}{$I-}
  661. reset(f);
  662. {$pop}
  663. if IOResult<>0 then
  664. begin
  665. Message1(exec_n_backquote_cat_file_not_found,para);
  666. end
  667. else
  668. begin
  669. while not eof(f) do
  670. begin
  671. readln(f,st);
  672. if st<>'' then
  673. filecontent:=filecontent+' '+st;
  674. end;
  675. close(f);
  676. end;
  677. CatFileContent:=filecontent;
  678. end;
  679. Function TExternalLinker.DoExec(const command:TCmdStr; para:TCmdStr;showinfo,useshell:boolean):boolean;
  680. var
  681. exitcode: longint;
  682. begin
  683. DoExec:=true;
  684. if not(cs_link_nolink in current_settings.globalswitches) then
  685. begin
  686. FlushOutput;
  687. if useshell then
  688. exitcode:=shell(maybequoted(command)+' '+para)
  689. else
  690. try
  691. exitcode:=RequotedExecuteProcess(command,para);
  692. except on E:EOSError do
  693. begin
  694. Message(exec_e_cant_call_linker);
  695. current_settings.globalswitches:=current_settings.globalswitches+[cs_link_nolink];
  696. DoExec:=false;
  697. end;
  698. end;
  699. if (exitcode<>0) then
  700. begin
  701. Message(exec_e_error_while_linking);
  702. current_settings.globalswitches:=current_settings.globalswitches+[cs_link_nolink];
  703. DoExec:=false;
  704. end;
  705. end;
  706. { Update asmres when externmode is set }
  707. if cs_link_nolink in current_settings.globalswitches then
  708. begin
  709. if showinfo then
  710. begin
  711. if current_module.islibrary then
  712. AsmRes.AddLinkCommand(Command,Para,current_module.sharedlibfilename)
  713. else
  714. AsmRes.AddLinkCommand(Command,Para,current_module.exefilename);
  715. end
  716. else
  717. AsmRes.AddLinkCommand(Command,Para,'');
  718. end;
  719. end;
  720. Function TExternalLinker.MakeStaticLibrary:boolean;
  721. function GetNextFiles(const maxCmdLength : Longint; var item : TCmdStrListItem; const addfilecmd : string) : TCmdStr;
  722. begin
  723. result := '';
  724. while (assigned(item) and ((length(result) + length(item.str) + 1) < maxCmdLength)) do begin
  725. result := result + ' ' + addfilecmd + item.str;
  726. item := TCmdStrListItem(item.next);
  727. end;
  728. end;
  729. var
  730. binstr, firstbinstr, scriptfile : TCmdStr;
  731. cmdstr, firstcmd, nextcmd, smartpath : TCmdStr;
  732. current : TCmdStrListItem;
  733. script: Text;
  734. scripted_ar : boolean;
  735. ar_creates_different_output_file : boolean;
  736. success : boolean;
  737. first : boolean;
  738. begin
  739. MakeStaticLibrary:=false;
  740. { remove the library, to be sure that it is rewritten }
  741. DeleteFile(current_module.staticlibfilename);
  742. { Call AR }
  743. smartpath:=FixPath(ChangeFileExt(current_module.asmfilename,target_info.smartext),false);
  744. SplitBinCmd(target_ar.arcmd,binstr,cmdstr);
  745. binstr := FindUtil(utilsprefix + binstr);
  746. if target_ar.arfirstcmd<>'' then
  747. begin
  748. SplitBinCmd(target_ar.arfirstcmd,firstbinstr,firstcmd);
  749. firstbinstr := FindUtil(utilsprefix + firstbinstr);
  750. end
  751. else
  752. begin
  753. firstbinstr:=binstr;
  754. firstcmd:=cmdstr;
  755. end;
  756. scripted_ar:=(target_ar.id=ar_gnu_ar_scripted) or
  757. (target_ar.id=ar_watcom_wlib_omf_scripted);
  758. if scripted_ar then
  759. begin
  760. scriptfile := FixFileName(smartpath+'arscript.txt');
  761. Replace(cmdstr,'$SCRIPT',maybequoted(scriptfile));
  762. Assign(script, scriptfile);
  763. Rewrite(script);
  764. try
  765. if (target_ar.id=ar_gnu_ar_scripted) then
  766. writeln(script, 'CREATE ' + current_module.staticlibfilename)
  767. else { wlib case }
  768. writeln(script,'-q -fo -c -b '+
  769. maybequoted(current_module.staticlibfilename));
  770. current := TCmdStrListItem(SmartLinkOFiles.First);
  771. while current <> nil do
  772. begin
  773. if (target_ar.id=ar_gnu_ar_scripted) then
  774. writeln(script, 'ADDMOD ' + current.str)
  775. else
  776. writeln(script,'+' + current.str);
  777. current := TCmdStrListItem(current.next);
  778. end;
  779. if (target_ar.id=ar_gnu_ar_scripted) then
  780. begin
  781. writeln(script, 'SAVE');
  782. writeln(script, 'END');
  783. end;
  784. finally
  785. Close(script);
  786. end;
  787. success:=DoExec(binstr,cmdstr,false,true);
  788. end
  789. else
  790. begin
  791. ar_creates_different_output_file:=(Pos('$OUTPUTLIB',cmdstr)>0) or (Pos('$OUTPUTLIB',firstcmd)>0);
  792. Replace(cmdstr,'$LIB',maybequoted(current_module.staticlibfilename));
  793. Replace(firstcmd,'$LIB',maybequoted(current_module.staticlibfilename));
  794. Replace(cmdstr,'$OUTPUTLIB',maybequoted(current_module.staticlibfilename+'.tmp'));
  795. Replace(firstcmd,'$OUTPUTLIB',maybequoted(current_module.staticlibfilename+'.tmp'));
  796. { create AR commands }
  797. success := true;
  798. current := TCmdStrListItem(SmartLinkOFiles.First);
  799. first := true;
  800. repeat
  801. if first then
  802. nextcmd := firstcmd
  803. else
  804. nextcmd := cmdstr;
  805. Replace(nextcmd,'$FILES',GetNextFiles(2047, current, target_ar.addfilecmd));
  806. if first then
  807. success:=DoExec(firstbinstr,nextcmd,false,true)
  808. else
  809. success:=DoExec(binstr,nextcmd,false,true);
  810. if ar_creates_different_output_file then
  811. begin
  812. if FileExists(current_module.staticlibfilename,false) then
  813. DeleteFile(current_module.staticlibfilename);
  814. if FileExists(current_module.staticlibfilename+'.tmp',false) then
  815. RenameFile(current_module.staticlibfilename+'.tmp',current_module.staticlibfilename);
  816. end;
  817. first := false;
  818. until (not assigned(current)) or (not success);
  819. end;
  820. if (target_ar.arfinishcmd <> '') then
  821. begin
  822. SplitBinCmd(target_ar.arfinishcmd,binstr,cmdstr);
  823. binstr := FindUtil(utilsprefix + binstr);
  824. Replace(cmdstr,'$LIB',maybequoted(current_module.staticlibfilename));
  825. success:=DoExec(binstr,cmdstr,false,true);
  826. end;
  827. { Clean up }
  828. if not(cs_asm_leave in current_settings.globalswitches) then
  829. if not(cs_link_nolink in current_settings.globalswitches) then
  830. begin
  831. while not SmartLinkOFiles.Empty do
  832. DeleteFile(SmartLinkOFiles.GetFirst);
  833. if scripted_ar then
  834. DeleteFile(scriptfile);
  835. RemoveDir(smartpath);
  836. end
  837. else
  838. begin
  839. while not SmartLinkOFiles.Empty do
  840. AsmRes.AddDeleteCommand(SmartLinkOFiles.GetFirst);
  841. if scripted_ar then
  842. AsmRes.AddDeleteCommand(scriptfile);
  843. AsmRes.AddDeleteDirCommand(smartpath);
  844. end;
  845. MakeStaticLibrary:=success;
  846. end;
  847. {*****************************************************************************
  848. TINTERNALLINKER
  849. *****************************************************************************}
  850. Constructor TInternalLinker.Create;
  851. begin
  852. inherited Create;
  853. linkscript:=TCmdStrList.Create;
  854. FStaticLibraryList:=TFPObjectList.Create(true);
  855. FImportLibraryList:=TFPHashObjectList.Create(true);
  856. FGroupStack:=TFPObjectList.Create(false);
  857. exemap:=nil;
  858. exeoutput:=nil;
  859. UseStabs:=false;
  860. CObjInput:=TObjInput;
  861. ScriptCount:=0;
  862. IsHandled:=nil;
  863. end;
  864. Destructor TInternalLinker.Destroy;
  865. begin
  866. FGroupStack.Free;
  867. linkscript.free;
  868. StaticLibraryList.Free;
  869. ImportLibraryList.Free;
  870. if assigned(IsHandled) then
  871. begin
  872. FreeMem(IsHandled,sizeof(boolean)*ScriptCount);
  873. IsHandled:=nil;
  874. ScriptCount:=0;
  875. end;
  876. if assigned(exeoutput) then
  877. begin
  878. exeoutput.free;
  879. exeoutput:=nil;
  880. end;
  881. if assigned(exemap) then
  882. begin
  883. exemap.free;
  884. exemap:=nil;
  885. end;
  886. inherited destroy;
  887. end;
  888. procedure TInternalLinker.AddImportSymbol(const libname,symname,symmangledname:TCmdStr;OrdNr: longint;isvar:boolean);
  889. var
  890. ImportLibrary : TImportLibrary;
  891. ImportSymbol : TFPHashObject;
  892. begin
  893. ImportLibrary:=TImportLibrary(ImportLibraryList.Find(libname));
  894. if not assigned(ImportLibrary) then
  895. ImportLibrary:=TImportLibrary.Create(ImportLibraryList,libname);
  896. ImportSymbol:=TFPHashObject(ImportLibrary.ImportSymbolList.Find(symname));
  897. if not assigned(ImportSymbol) then
  898. ImportSymbol:=TImportSymbol.Create(ImportLibrary.ImportSymbolList,symname,symmangledname,OrdNr,isvar);
  899. end;
  900. procedure TInternalLinker.ScriptAddSourceStatements(AddSharedAsStatic:boolean);
  901. var
  902. s,s2: TCmdStr;
  903. begin
  904. while not ObjectFiles.Empty do
  905. begin
  906. s:=ObjectFiles.GetFirst;
  907. if s<>'' then
  908. LinkScript.Concat('READOBJECT '+MaybeQuoted(s));
  909. end;
  910. while not StaticLibFiles.Empty do
  911. begin
  912. s:=StaticLibFiles.GetFirst;
  913. if s<>'' then
  914. LinkScript.Concat('READSTATICLIBRARY '+MaybeQuoted(s));
  915. end;
  916. if not AddSharedAsStatic then
  917. exit;
  918. while not SharedLibFiles.Empty do
  919. begin
  920. S:=SharedLibFiles.GetFirst;
  921. if FindLibraryFile(s,target_info.staticClibprefix,target_info.staticClibext,s2) then
  922. LinkScript.Concat('READSTATICLIBRARY '+MaybeQuoted(s2))
  923. else
  924. Comment(V_Error,'Import library not found for '+S);
  925. end;
  926. end;
  927. function TInternalLinker.GetCodeSize(aExeOutput: TExeOutput): QWord;
  928. begin
  929. Result:=aExeOutput.findexesection('.text').size;
  930. end;
  931. function TInternalLinker.GetDataSize(aExeOutput: TExeOutput): QWord;
  932. begin
  933. Result:=aExeOutput.findexesection('.data').size;
  934. end;
  935. function TInternalLinker.GetBssSize(aExeOutput: TExeOutput): QWord;
  936. var
  937. bsssec: TExeSection;
  938. begin
  939. bsssec:=aExeOutput.findexesection('.bss');
  940. if assigned(bsssec) then
  941. Result:=bsssec.size
  942. else
  943. Result:=0;
  944. end;
  945. procedure TInternalLinker.ParseLdScript(src:TScriptLexer);
  946. var
  947. asneeded: boolean;
  948. group: TStaticLibrary;
  949. procedure ParseInputList;
  950. var
  951. saved_asneeded: boolean;
  952. begin
  953. src.Expect('(');
  954. repeat
  955. if src.CheckForIdent('AS_NEEDED') then
  956. begin
  957. saved_asneeded:=asneeded;
  958. asneeded:=true;
  959. ParseInputList;
  960. asneeded:=saved_asneeded;
  961. end
  962. else if src.token in [tkIDENT,tkLITERAL] then
  963. begin
  964. Load_ReadStaticLibrary(src.tokenstr,asneeded);
  965. src.nextToken;
  966. end
  967. else if src.CheckFor('-') then
  968. begin
  969. { TODO: no whitespace between '-' and name;
  970. name must begin with 'l' }
  971. src.nextToken;
  972. end
  973. else { syntax error, no input_list_element term }
  974. Break;
  975. if src.CheckFor(',') then
  976. Continue;
  977. until src.CheckFor(')');
  978. end;
  979. begin
  980. asneeded:=false;
  981. src.nextToken;
  982. repeat
  983. if src.CheckForIdent('OUTPUT_FORMAT') then
  984. begin
  985. src.Expect('(');
  986. //writeln('output_format(',src.tokenstr,')');
  987. src.nextToken;
  988. src.Expect(')');
  989. end
  990. else if src.CheckForIdent('GROUP') then
  991. begin
  992. group:=TStaticLibrary.create_group;
  993. TFPObjectList(FGroupStack.Last).Add(group);
  994. FGroupStack.Add(group.GroupMembers);
  995. ParseInputList;
  996. FGroupStack.Delete(FGroupStack.Count-1);
  997. end
  998. else if src.CheckFor(';') then
  999. {skip semicolon};
  1000. until src.token in [tkEOF,tkINVALID];
  1001. end;
  1002. procedure TInternalLinker.Load_ReadObject(const para:TCmdStr);
  1003. var
  1004. objdata : TObjData;
  1005. objinput : TObjinput;
  1006. objreader : TObjectReader;
  1007. fn : TCmdStr;
  1008. begin
  1009. fn:=FindObjectFile(para,'',false);
  1010. Comment(V_Tried,'Reading object '+fn);
  1011. objinput:=CObjInput.Create;
  1012. objreader:=TObjectreader.create;
  1013. if objreader.openfile(fn) then
  1014. begin
  1015. if objinput.ReadObjData(objreader,objdata) then
  1016. exeoutput.addobjdata(objdata);
  1017. end;
  1018. { release input object }
  1019. objinput.free;
  1020. objreader.free;
  1021. end;
  1022. procedure TInternalLinker.Load_ReadStaticLibrary(const para:TCmdStr;asneededflag:boolean);
  1023. var
  1024. objreader : TObjectReader;
  1025. objinput: TObjInput;
  1026. objdata: TObjData;
  1027. ScriptLexer: TScriptLexer;
  1028. stmt:TStaticLibrary;
  1029. begin
  1030. { TODO: Cleanup ignoring of FPC generated libimp*.a files}
  1031. { Don't load import libraries }
  1032. if copy(ExtractFileName(para),1,6)='libimp' then
  1033. exit;
  1034. Comment(V_Tried,'Opening library '+para);
  1035. objreader:=CArObjectreader.createAr(para,true);
  1036. if ErrorCount>0 then
  1037. exit;
  1038. if objreader.isarchive then
  1039. TFPObjectList(FGroupStack.Last).Add(TStaticLibrary.Create(para,objreader,CObjInput))
  1040. else
  1041. if CObjInput.CanReadObjData(objreader) then
  1042. begin
  1043. { may be a regular object as well as a dynamic one }
  1044. objinput:=CObjInput.Create;
  1045. if objinput.ReadObjData(objreader,objdata) then
  1046. begin
  1047. stmt:=TStaticLibrary.create_object(objdata);
  1048. stmt.AsNeeded:=asneededflag;
  1049. TFPObjectList(FGroupStack.Last).Add(stmt);
  1050. end;
  1051. objinput.Free;
  1052. objreader.Free;
  1053. end
  1054. else { try parsing as script }
  1055. begin
  1056. Comment(V_Tried,'Interpreting '+para+' as ld script');
  1057. ScriptLexer:=TScriptLexer.Create(objreader);
  1058. ParseLdScript(ScriptLexer);
  1059. ScriptLexer.Free;
  1060. objreader.Free;
  1061. end;
  1062. end;
  1063. procedure TInternalLinker.Load_Group;
  1064. var
  1065. group: TStaticLibrary;
  1066. begin
  1067. group:=TStaticLibrary.create_group;
  1068. TFPObjectList(FGroupStack.Last).Add(group);
  1069. FGroupStack.Add(group.GroupMembers);
  1070. end;
  1071. procedure TInternalLinker.Load_EndGroup;
  1072. begin
  1073. FGroupStack.Delete(FGroupStack.Count-1);
  1074. end;
  1075. procedure TInternalLinker.ParseScript_Handle;
  1076. var
  1077. s{, para}, keyword : String;
  1078. hp : TCmdStrListItem;
  1079. i : longint;
  1080. begin
  1081. hp:=TCmdStrListItem(linkscript.first);
  1082. i:=0;
  1083. while assigned(hp) do
  1084. begin
  1085. inc(i);
  1086. s:=hp.str;
  1087. if (s='') or (s[1]='#') then
  1088. begin
  1089. hp:=TCmdStrListItem(hp.next);
  1090. continue;
  1091. end;
  1092. keyword:=Upper(GetToken(s,' '));
  1093. {para:=}GetToken(s,' ');
  1094. if Trim(s)<>'' then
  1095. Comment(V_Warning,'Unknown part "'+s+'" in "'+hp.str+'" internal linker script');
  1096. if (keyword<>'SYMBOL') and
  1097. (keyword<>'SYMBOLS') and
  1098. (keyword<>'STABS') and
  1099. (keyword<>'PROVIDE') and
  1100. (keyword<>'ZEROS') and
  1101. (keyword<>'BYTE') and
  1102. (keyword<>'WORD') and
  1103. (keyword<>'LONG') and
  1104. (keyword<>'QUAD') and
  1105. (keyword<>'ENTRYNAME') and
  1106. (keyword<>'ISSHAREDLIBRARY') and
  1107. (keyword<>'IMAGEBASE') and
  1108. (keyword<>'READOBJECT') and
  1109. (keyword<>'READSTATICLIBRARY') and
  1110. (keyword<>'EXESECTION') and
  1111. (keyword<>'ENDEXESECTION') and
  1112. (keyword<>'OBJSECTION') and
  1113. (keyword<>'HEADER') and
  1114. (keyword<>'GROUP') and
  1115. (keyword<>'ENDGROUP')
  1116. then
  1117. Comment(V_Warning,'Unknown keyword "'+keyword+'" in "'+hp.str
  1118. +'" internal linker script');
  1119. hp:=TCmdStrListItem(hp.next);
  1120. end;
  1121. ScriptCount:=i;
  1122. if ScriptCount>0 then
  1123. begin
  1124. GetMem(IsHandled,sizeof(boolean)*ScriptCount);
  1125. Fillchar(IsHandled^,sizeof(boolean)*ScriptCount,#0);
  1126. end;
  1127. end;
  1128. procedure TInternalLinker.ParseScript_PostCheck;
  1129. var
  1130. hp : TCmdStrListItem;
  1131. i : longint;
  1132. begin
  1133. hp:=TCmdStrListItem(linkscript.first);
  1134. i:=0;
  1135. while assigned(hp) do
  1136. begin
  1137. inc(i);
  1138. if not IsHandled^[i] then
  1139. begin
  1140. Comment(V_Warning,'"'+hp.str+
  1141. '" internal linker script not handled');
  1142. end;
  1143. hp:=TCmdStrListItem(hp.next);
  1144. end;
  1145. end;
  1146. function TInternalLinker.ParsePara(const para : string) : string;
  1147. var
  1148. res : string;
  1149. begin
  1150. res:=trim(para);
  1151. { Remove enclosing braces }
  1152. if (length(res)>0) and (res[1]='(') and
  1153. (res[length(res)]=')') then
  1154. res:=trim(copy(res,2,length(res)-2));
  1155. result:=res;
  1156. end;
  1157. procedure TInternalLinker.ParseScript_Load;
  1158. var
  1159. s,
  1160. para,
  1161. keyword : String;
  1162. hp : TCmdStrListItem;
  1163. i : longint;
  1164. handled : boolean;
  1165. begin
  1166. exeoutput.Load_Start;
  1167. hp:=TCmdStrListItem(linkscript.first);
  1168. i:=0;
  1169. while assigned(hp) do
  1170. begin
  1171. inc(i);
  1172. s:=hp.str;
  1173. if (s='') or (s[1]='#') then
  1174. begin
  1175. IsHandled^[i]:=true;
  1176. hp:=TCmdStrListItem(hp.next);
  1177. continue;
  1178. end;
  1179. handled:=true;
  1180. keyword:=Upper(GetToken(s,' '));
  1181. para:=ParsePara(GetToken(s,' '));
  1182. if keyword='SYMBOL' then
  1183. ExeOutput.Load_Symbol(para)
  1184. else if keyword='PROVIDE' then
  1185. ExeOutput.Load_ProvideSymbol(para)
  1186. else if keyword='ENTRYNAME' then
  1187. ExeOutput.Load_EntryName(para)
  1188. else if keyword='ISSHAREDLIBRARY' then
  1189. ExeOutput.Load_IsSharedLibrary
  1190. else if keyword='IMAGEBASE' then
  1191. ExeOutput.Load_ImageBase(para)
  1192. else if keyword='READOBJECT' then
  1193. Load_ReadObject(para)
  1194. else if keyword='STABS' then
  1195. UseStabs:=true
  1196. else if keyword='READSTATICLIBRARY' then
  1197. Load_ReadStaticLibrary(para)
  1198. else if keyword='GROUP' then
  1199. Load_Group
  1200. else if keyword='ENDGROUP' then
  1201. Load_EndGroup
  1202. else
  1203. handled:=false;
  1204. if handled then
  1205. IsHandled^[i]:=true;
  1206. hp:=TCmdStrListItem(hp.next);
  1207. end;
  1208. end;
  1209. procedure TInternalLinker.ParseScript_Order;
  1210. var
  1211. s,
  1212. para,
  1213. keyword : String;
  1214. hp : TCmdStrListItem;
  1215. i : longint;
  1216. handled : boolean;
  1217. begin
  1218. exeoutput.Order_Start;
  1219. hp:=TCmdStrListItem(linkscript.first);
  1220. i:=0;
  1221. while assigned(hp) do
  1222. begin
  1223. inc(i);
  1224. s:=hp.str;
  1225. if (s='') or (s[1]='#') then
  1226. begin
  1227. hp:=TCmdStrListItem(hp.next);
  1228. continue;
  1229. end;
  1230. handled:=true;
  1231. keyword:=Upper(GetToken(s,' '));
  1232. para:=ParsePara(GetToken(s,' '));
  1233. if keyword='EXESECTION' then
  1234. ExeOutput.Order_ExeSection(para)
  1235. else if keyword='ENDEXESECTION' then
  1236. ExeOutput.Order_EndExeSection
  1237. else if keyword='OBJSECTION' then
  1238. ExeOutput.Order_ObjSection(para)
  1239. else if keyword='ZEROS' then
  1240. ExeOutput.Order_Zeros(para)
  1241. else if keyword='BYTE' then
  1242. ExeOutput.Order_Values(1,para)
  1243. else if keyword='WORD' then
  1244. ExeOutput.Order_Values(2,para)
  1245. else if keyword='LONG' then
  1246. ExeOutput.Order_Values(4,para)
  1247. else if keyword='QUAD' then
  1248. ExeOutput.Order_Values(8,para)
  1249. else if keyword='SYMBOL' then
  1250. ExeOutput.Order_Symbol(para)
  1251. else if keyword='PROVIDE' then
  1252. ExeOutput.Order_ProvideSymbol(para)
  1253. else
  1254. handled:=false;
  1255. if handled then
  1256. IsHandled^[i]:=true;
  1257. hp:=TCmdStrListItem(hp.next);
  1258. end;
  1259. exeoutput.Order_End;
  1260. end;
  1261. procedure TInternalLinker.ParseScript_MemPos;
  1262. var
  1263. s,
  1264. para,
  1265. keyword : String;
  1266. hp : TCmdStrListItem;
  1267. i : longint;
  1268. handled : boolean;
  1269. begin
  1270. exeoutput.MemPos_Start;
  1271. hp:=TCmdStrListItem(linkscript.first);
  1272. i:=0;
  1273. while assigned(hp) do
  1274. begin
  1275. inc(i);
  1276. s:=hp.str;
  1277. if (s='') or (s[1]='#') then
  1278. begin
  1279. hp:=TCmdStrListItem(hp.next);
  1280. continue;
  1281. end;
  1282. handled:=true;
  1283. keyword:=Upper(GetToken(s,' '));
  1284. para:=ParsePara(GetToken(s,' '));
  1285. if keyword='EXESECTION' then
  1286. ExeOutput.MemPos_ExeSection(para)
  1287. else if keyword='ENDEXESECTION' then
  1288. ExeOutput.MemPos_EndExeSection
  1289. else if keyword='HEADER' then
  1290. ExeOutput.MemPos_Header
  1291. else
  1292. handled:=false;
  1293. if handled then
  1294. IsHandled^[i]:=true;
  1295. hp:=TCmdStrListItem(hp.next);
  1296. end;
  1297. end;
  1298. procedure TInternalLinker.ParseScript_DataPos;
  1299. var
  1300. s,
  1301. para,
  1302. keyword : String;
  1303. hp : TCmdStrListItem;
  1304. i : longint;
  1305. handled : boolean;
  1306. begin
  1307. exeoutput.DataPos_Start;
  1308. hp:=TCmdStrListItem(linkscript.first);
  1309. i:=0;
  1310. while assigned(hp) do
  1311. begin
  1312. inc(i);
  1313. s:=hp.str;
  1314. if (s='') or (s[1]='#') then
  1315. begin
  1316. hp:=TCmdStrListItem(hp.next);
  1317. continue;
  1318. end;
  1319. handled:=true;
  1320. keyword:=Upper(GetToken(s,' '));
  1321. para:=ParsePara(GetToken(s,' '));
  1322. if keyword='EXESECTION' then
  1323. ExeOutput.DataPos_ExeSection(para)
  1324. else if keyword='ENDEXESECTION' then
  1325. ExeOutput.DataPos_EndExeSection
  1326. else if keyword='HEADER' then
  1327. ExeOutput.DataPos_Header
  1328. else if keyword='SYMBOLS' then
  1329. ExeOutput.DataPos_Symbols
  1330. else
  1331. handled:=false;
  1332. if handled then
  1333. IsHandled^[i]:=true;
  1334. hp:=TCmdStrListItem(hp.next);
  1335. end;
  1336. end;
  1337. procedure TInternalLinker.PrintLinkerScript;
  1338. var
  1339. hp : TCmdStrListItem;
  1340. begin
  1341. if not assigned(exemap) then
  1342. exit;
  1343. exemap.Add('Used linker script');
  1344. exemap.Add('');
  1345. hp:=TCmdStrListItem(linkscript.first);
  1346. while assigned(hp) do
  1347. begin
  1348. exemap.Add(hp.str);
  1349. hp:=TCmdStrListItem(hp.next);
  1350. end;
  1351. end;
  1352. function TInternalLinker.RunLinkScript(const outputname:TCmdStr):boolean;
  1353. label
  1354. myexit;
  1355. var
  1356. bsssize : aword;
  1357. dbgname : TCmdStr;
  1358. begin
  1359. result:=false;
  1360. Message1(exec_i_linking,outputname);
  1361. FlushOutput;
  1362. exeoutput:=CExeOutput.Create;
  1363. { TODO: Load custom linker script}
  1364. DefaultLinkScript;
  1365. if (cs_link_map in current_settings.globalswitches) then
  1366. exemap:=texemap.create(current_module.mapfilename);
  1367. PrintLinkerScript;
  1368. { Check that syntax is OK }
  1369. ParseScript_Handle;
  1370. { Load .o files and resolve symbols }
  1371. FGroupStack.Add(FStaticLibraryList);
  1372. ParseScript_Load;
  1373. if ErrorCount>0 then
  1374. goto myexit;
  1375. exeoutput.ResolveSymbols(StaticLibraryList);
  1376. { Generate symbols and code to do the importing }
  1377. exeoutput.GenerateLibraryImports(ImportLibraryList);
  1378. { Fill external symbols data }
  1379. exeoutput.FixupSymbols;
  1380. if ErrorCount>0 then
  1381. goto myexit;
  1382. { parse linker options specific for output format }
  1383. exeoutput.ParseScript (linkscript);
  1384. { Create .exe sections and add .o sections }
  1385. ParseScript_Order;
  1386. exeoutput.RemoveUnreferencedSections;
  1387. { if UseStabs then, this would remove
  1388. STABS for empty linker scripts }
  1389. exeoutput.MergeStabs;
  1390. exeoutput.MarkEmptySections;
  1391. exeoutput.AfterUnusedSectionRemoval;
  1392. if ErrorCount>0 then
  1393. goto myexit;
  1394. { Calc positions in mem }
  1395. ParseScript_MemPos;
  1396. exeoutput.FixupRelocations;
  1397. exeoutput.RemoveUnusedExeSymbols;
  1398. exeoutput.PrintMemoryMap;
  1399. if ErrorCount>0 then
  1400. goto myexit;
  1401. if cs_link_separate_dbg_file in current_settings.globalswitches then
  1402. begin
  1403. { create debuginfo, which is an executable without data on disk }
  1404. dbgname:=ChangeFileExt(outputname,'.dbg');
  1405. exeoutput.ExeWriteMode:=ewm_dbgonly;
  1406. ParseScript_DataPos;
  1407. exeoutput.WriteExeFile(dbgname);
  1408. { create executable with link to just created debuginfo file }
  1409. exeoutput.ExeWriteMode:=ewm_exeonly;
  1410. exeoutput.RemoveDebugInfo;
  1411. exeoutput.GenerateDebugLink(ExtractFileName(dbgname),GetFileCRC(dbgname));
  1412. ParseScript_MemPos;
  1413. ParseScript_DataPos;
  1414. exeoutput.WriteExeFile(outputname);
  1415. end
  1416. else
  1417. begin
  1418. exeoutput.ExeWriteMode:=ewm_exefull;
  1419. ParseScript_DataPos;
  1420. exeoutput.WriteExeFile(outputname);
  1421. end;
  1422. { Post check that everything was handled }
  1423. ParseScript_PostCheck;
  1424. status.codesize:=GetCodeSize(exeoutput);
  1425. status.datasize:=GetDataSize(exeoutput);
  1426. bsssize:=GetBssSize(exeoutput);
  1427. { Executable info }
  1428. Message1(execinfo_x_codesize,tostr(status.codesize));
  1429. Message1(execinfo_x_initdatasize,tostr(status.datasize));
  1430. Message1(execinfo_x_uninitdatasize,tostr(bsssize));
  1431. Message1(execinfo_x_stackreserve,tostr(stacksize));
  1432. myexit:
  1433. { close map }
  1434. if assigned(exemap) then
  1435. begin
  1436. exemap.free;
  1437. exemap:=nil;
  1438. end;
  1439. { close exe }
  1440. exeoutput.free;
  1441. exeoutput:=nil;
  1442. result:=true;
  1443. end;
  1444. function TInternalLinker.MakeExecutable:boolean;
  1445. begin
  1446. IsSharedLibrary:=false;
  1447. result:=RunLinkScript(current_module.exefilename);
  1448. {$ifdef hasUnix}
  1449. fpchmod(current_module.exefilename,493);
  1450. {$endif hasUnix}
  1451. end;
  1452. function TInternalLinker.MakeSharedLibrary:boolean;
  1453. begin
  1454. IsSharedLibrary:=true;
  1455. result:=RunLinkScript(current_module.sharedlibfilename);
  1456. end;
  1457. procedure TInternalLinker.ScriptAddGenericSections(secnames:string);
  1458. var
  1459. secname:string;
  1460. begin
  1461. repeat
  1462. secname:=gettoken(secnames,',');
  1463. if secname='' then
  1464. break;
  1465. linkscript.Concat('EXESECTION '+secname);
  1466. linkscript.Concat(' OBJSECTION '+secname+'*');
  1467. linkscript.Concat('ENDEXESECTION');
  1468. until false;
  1469. end;
  1470. {*****************************************************************************
  1471. Init/Done
  1472. *****************************************************************************}
  1473. procedure RegisterLinker(id:tlink;c:TLinkerClass);
  1474. begin
  1475. CLinker[id]:=c;
  1476. end;
  1477. procedure InitLinker;
  1478. begin
  1479. if (cs_link_extern in current_settings.globalswitches) and
  1480. assigned(CLinker[target_info.linkextern]) then
  1481. begin
  1482. linker:=CLinker[target_info.linkextern].Create;
  1483. end
  1484. else
  1485. if assigned(CLinker[target_info.link]) then
  1486. begin
  1487. linker:=CLinker[target_info.link].Create;
  1488. end
  1489. else
  1490. linker:=Tlinker.Create;
  1491. end;
  1492. procedure DoneLinker;
  1493. begin
  1494. if assigned(linker) then
  1495. Linker.Free;
  1496. end;
  1497. {*****************************************************************************
  1498. Initialize
  1499. *****************************************************************************}
  1500. const
  1501. ar_gnu_ar_info : tarinfo =
  1502. (
  1503. id : ar_gnu_ar;
  1504. addfilecmd : '';
  1505. arfirstcmd : '';
  1506. arcmd : 'ar qS $LIB $FILES';
  1507. arfinishcmd : 'ar s $LIB'
  1508. );
  1509. ar_gnu_ar_scripted_info : tarinfo =
  1510. (
  1511. id : ar_gnu_ar_scripted;
  1512. addfilecmd : '';
  1513. arfirstcmd : '';
  1514. arcmd : 'ar -M < $SCRIPT';
  1515. arfinishcmd : ''
  1516. );
  1517. ar_gnu_gar_info : tarinfo =
  1518. ( id : ar_gnu_gar;
  1519. addfilecmd : '';
  1520. arfirstcmd : '';
  1521. arcmd : 'gar qS $LIB $FILES';
  1522. arfinishcmd : 'gar s $LIB'
  1523. );
  1524. ar_watcom_wlib_omf_info : tarinfo =
  1525. ( id : ar_watcom_wlib_omf;
  1526. addfilecmd : '+';
  1527. arfirstcmd : 'wlib -q -fo -c -b -n -o=$OUTPUTLIB $LIB $FILES';
  1528. arcmd : 'wlib -q -fo -c -b -o=$OUTPUTLIB $LIB $FILES';
  1529. arfinishcmd : ''
  1530. );
  1531. ar_watcom_wlib_omf_scripted_info : tarinfo =
  1532. (
  1533. id : ar_watcom_wlib_omf_scripted;
  1534. addfilecmd : '+';
  1535. arfirstcmd : '';
  1536. arcmd : 'wlib @$SCRIPT';
  1537. arfinishcmd : ''
  1538. );
  1539. initialization
  1540. RegisterAr(ar_gnu_ar_info);
  1541. RegisterAr(ar_gnu_ar_scripted_info);
  1542. RegisterAr(ar_gnu_gar_info);
  1543. RegisterAr(ar_watcom_wlib_omf_info);
  1544. RegisterAr(ar_watcom_wlib_omf_scripted_info);
  1545. end.