link.pas 51 KB

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