2
0

link.pas 52 KB

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