link.pas 57 KB

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