link.pas 50 KB

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