link.pas 57 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752
  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 ansistring;
  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. begin
  341. with hp do
  342. begin
  343. if mf_has_resourcefiles in moduleflags then
  344. HasResources:=true;
  345. if mf_has_exports in moduleflags then
  346. HasExports:=true;
  347. { link unit files }
  348. if (headerflags and uf_no_link)=0 then
  349. begin
  350. { create mask which unit files need linking }
  351. mask:=link_always;
  352. { lto linking ?}
  353. if (cs_lto in current_settings.moduleswitches) and
  354. ((headerflags and uf_lto_linked)<>0) and
  355. (not(cs_lto_nosystem in init_settings.globalswitches) or
  356. (hp.modulename^<>'SYSTEM')) then
  357. begin
  358. mask:=mask or link_lto;
  359. end
  360. else
  361. begin
  362. { static linking ? }
  363. if (cs_link_static in current_settings.globalswitches) then
  364. begin
  365. if (headerflags and uf_static_linked)=0 then
  366. begin
  367. { if static not avail then try smart linking }
  368. if (headerflags and uf_smart_linked)<>0 then
  369. begin
  370. Message1(exec_t_unit_not_static_linkable_switch_to_smart,modulename^);
  371. mask:=mask or link_smart;
  372. end
  373. else
  374. Message1(exec_e_unit_not_smart_or_static_linkable,modulename^);
  375. end
  376. else
  377. mask:=mask or link_static;
  378. end;
  379. { smart linking ? }
  380. if (cs_link_smart in current_settings.globalswitches) then
  381. begin
  382. if (headerflags and uf_smart_linked)=0 then
  383. begin
  384. { if smart not avail then try static linking }
  385. if (headerflags and uf_static_linked)<>0 then
  386. begin
  387. { if not create_smartlink_library, then smart linking happens using the
  388. regular object files
  389. }
  390. if create_smartlink_library then
  391. Message1(exec_t_unit_not_smart_linkable_switch_to_static,modulename^);
  392. mask:=mask or link_static;
  393. end
  394. else
  395. Message1(exec_e_unit_not_smart_or_static_linkable,modulename^);
  396. end
  397. else
  398. mask:=mask or link_smart;
  399. end;
  400. { shared linking }
  401. if (cs_link_shared in current_settings.globalswitches) then
  402. begin
  403. if (headerflags and uf_shared_linked)=0 then
  404. begin
  405. { if shared not avail then try static linking }
  406. if (headerflags and uf_static_linked)<>0 then
  407. begin
  408. Message1(exec_t_unit_not_shared_linkable_switch_to_static,modulename^);
  409. mask:=mask or link_static;
  410. end
  411. else
  412. Message1(exec_e_unit_not_shared_or_static_linkable,modulename^);
  413. end
  414. else
  415. mask:=mask or link_shared;
  416. end;
  417. end;
  418. { unit files }
  419. while not linkunitofiles.empty do
  420. AddObject(linkunitofiles.getusemask(mask),path,true);
  421. while not linkunitstaticlibs.empty do
  422. AddStaticLibrary(linkunitstaticlibs.getusemask(mask));
  423. while not linkunitsharedlibs.empty do
  424. AddSharedLibrary(linkunitsharedlibs.getusemask(mask));
  425. end;
  426. { Other needed .o and libs, specified using $L,$LINKLIB,external }
  427. mask:=link_always;
  428. while not linkotherofiles.empty do
  429. AddObject(linkotherofiles.Getusemask(mask),path,false);
  430. while not linkotherstaticlibs.empty do
  431. AddStaticCLibrary(linkotherstaticlibs.Getusemask(mask));
  432. while not linkothersharedlibs.empty do
  433. AddSharedCLibrary(linkothersharedlibs.Getusemask(mask));
  434. while not linkotherframeworks.empty do
  435. AddFramework(linkotherframeworks.Getusemask(mask));
  436. { Known Library/DLL Imports }
  437. for i:=0 to ImportLibraryList.Count-1 do
  438. begin
  439. ImportLibrary:=TImportLibrary(ImportLibraryList[i]);
  440. for j:=0 to ImportLibrary.ImportSymbolList.Count-1 do
  441. begin
  442. ImportSymbol:=TImportSymbol(ImportLibrary.ImportSymbolList[j]);
  443. AddImportSymbol(ImportLibrary.Name,ImportSymbol.Name,
  444. ImportSymbol.MangledName,ImportSymbol.OrdNr,ImportSymbol.IsVar);
  445. end;
  446. end;
  447. { ordered symbols }
  448. OrderedSymbols.concatList(linkorderedsymbols);
  449. end;
  450. end;
  451. procedure TLinker.AddImportSymbol(const libname,symname,symmangledname:TCmdStr;OrdNr: longint;isvar:boolean);
  452. begin
  453. end;
  454. Procedure TLinker.AddObject(const S,unitpath : TPathStr;isunit:boolean);
  455. begin
  456. ObjectFiles.Concat(FindObjectFile(s,unitpath,isunit))
  457. end;
  458. Procedure TLinker.AddSharedLibrary(S:TCmdStr);
  459. begin
  460. if s='' then
  461. exit;
  462. { remove prefix 'lib' }
  463. if Copy(s,1,length(target_info.sharedlibprefix))=target_info.sharedlibprefix then
  464. Delete(s,1,length(target_info.sharedlibprefix));
  465. { remove extension if any }
  466. if Copy(s,length(s)-length(target_info.sharedlibext)+1,length(target_info.sharedlibext))=target_info.sharedlibext then
  467. Delete(s,length(s)-length(target_info.sharedlibext)+1,length(target_info.sharedlibext)+1);
  468. { ready to be added }
  469. SharedLibFiles.Concat(S);
  470. end;
  471. Procedure TLinker.AddStaticLibrary(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.staticlibprefix,target_info.staticlibext,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.AddSharedCLibrary(S:TCmdStr);
  484. begin
  485. if s='' then
  486. exit;
  487. { remove prefix 'lib' }
  488. if Copy(s,1,length(target_info.sharedclibprefix))=target_info.sharedclibprefix then
  489. Delete(s,1,length(target_info.sharedclibprefix));
  490. { remove extension if any }
  491. if Copy(s,length(s)-length(target_info.sharedclibext)+1,length(target_info.sharedclibext))=target_info.sharedclibext then
  492. Delete(s,length(s)-length(target_info.sharedclibext)+1,length(target_info.sharedclibext)+1);
  493. { ready to be added }
  494. SharedLibFiles.Concat(S);
  495. end;
  496. Procedure TLinker.AddFramework(S:TCmdStr);
  497. begin
  498. if s='' then
  499. exit;
  500. { ready to be added }
  501. FrameworkFiles.Concat(S);
  502. end;
  503. procedure TLinker.AddOrderedSymbol(const s: TCmdStr);
  504. begin
  505. OrderedSymbols.Concat(s);
  506. end;
  507. Procedure TLinker.AddStaticCLibrary(const S:TCmdStr);
  508. var
  509. ns : TCmdStr;
  510. found : boolean;
  511. begin
  512. if s='' then
  513. exit;
  514. found:=FindLibraryFile(s,target_info.staticclibprefix,target_info.staticclibext,ns);
  515. if not(cs_link_nolink in current_settings.globalswitches) and (not found) then
  516. Message1(exec_w_libfile_not_found,s);
  517. StaticLibFiles.Concat(ns);
  518. end;
  519. procedure TLinker.InitSysInitUnitName;
  520. begin
  521. end;
  522. function TLinker.MakeExecutable:boolean;
  523. begin
  524. MakeExecutable:=false;
  525. Message(exec_e_exe_not_supported);
  526. end;
  527. Function TLinker.MakeSharedLibrary:boolean;
  528. begin
  529. MakeSharedLibrary:=false;
  530. Message(exec_e_dll_not_supported);
  531. end;
  532. Function TLinker.MakeStaticLibrary:boolean;
  533. begin
  534. MakeStaticLibrary:=false;
  535. Message(exec_e_static_lib_not_supported);
  536. end;
  537. Procedure TLinker.ExpandAndApplyOrder(var Src:TCmdStrList);
  538. var
  539. p : TLinkStrMap;
  540. i : longint;
  541. begin
  542. // call Virtual TLinker method to initialize
  543. LoadPredefinedLibraryOrder;
  544. // something to do?
  545. if (LinkLibraryAliases.count=0) and (LinkLibraryOrder.Count=0) Then
  546. exit;
  547. p:=TLinkStrMap.Create;
  548. // expand libaliases, clears src
  549. LinkLibraryAliases.expand(src,p);
  550. // writeln(src.count,' ',p.count,' ',linklibraryorder.count,' ',linklibraryaliases.count);
  551. // apply order
  552. p.UpdateWeights(LinkLibraryOrder);
  553. p.SortOnWeight;
  554. // put back in src
  555. for i:=0 to p.count-1 do
  556. src.insert(p[i].Key);
  557. p.free;
  558. end;
  559. procedure TLinker.LoadPredefinedLibraryOrder;
  560. begin
  561. end;
  562. function TLinker.ReOrderEntries : boolean;
  563. begin
  564. result:=(LinkLibraryOrder.count>0) or (LinkLibraryAliases.count>0);
  565. end;
  566. {*****************************************************************************
  567. TEXTERNALLINKER
  568. *****************************************************************************}
  569. Function TExternalLinker.WriteSymbolOrderFile: TCmdStr;
  570. var
  571. item: TCmdStrListItem;
  572. symfile: TScript;
  573. begin
  574. result:='';
  575. { only for darwin for now; can also enable for other platforms when using
  576. the LLVM linker }
  577. if (OrderedSymbols.Empty) or
  578. not(tf_supports_symbolorderfile in target_info.flags) then
  579. exit;
  580. symfile:=TScript.Create(outputexedir+'symbol_order.fpc');
  581. item:=TCmdStrListItem(OrderedSymbols.First);
  582. while assigned(item) do
  583. begin
  584. symfile.add(item.str);
  585. item:=TCmdStrListItem(item.next);
  586. end;
  587. symfile.WriteToDisk;
  588. result:=symfile.fn;
  589. symfile.Free;
  590. end;
  591. Constructor TExternalLinker.Create;
  592. begin
  593. inherited Create;
  594. { set generic defaults }
  595. FillChar(Info,sizeof(Info),0);
  596. if cs_link_on_target in current_settings.globalswitches then
  597. begin
  598. Info.ResName:=ChangeFileExt(inputfilename,'_link.res');
  599. Info.ScriptName:=ChangeFileExt(inputfilename,'_script.res');
  600. end
  601. else
  602. begin
  603. Info.ResName:=UniqueName('link')+'.res';
  604. Info.ScriptName:=UniqueName('script')+'.res';
  605. end;
  606. { set the linker specific defaults }
  607. SetDefaultInfo;
  608. { Allow Parameter overrides for linker info }
  609. with Info do
  610. begin
  611. if ParaLinkOptions<>'' then
  612. ExtraOptions:=ParaLinkOptions;
  613. if ParaDynamicLinker<>'' then
  614. DynamicLinker:=ParaDynamicLinker;
  615. end;
  616. end;
  617. Destructor TExternalLinker.Destroy;
  618. begin
  619. inherited destroy;
  620. end;
  621. Procedure TExternalLinker.SetDefaultInfo;
  622. begin
  623. end;
  624. Function TExternalLinker.FindUtil(const s:TCmdStr):TCmdStr;
  625. var
  626. Found : boolean;
  627. FoundBin : TCmdStr;
  628. UtilExe : TCmdStr;
  629. begin
  630. if cs_link_on_target in current_settings.globalswitches then
  631. begin
  632. { If linking on target, don't add any path PM }
  633. { change extension only on platforms that use an exe extension, otherwise on OpenBSD 'ld.bfd' gets
  634. converted to 'ld' }
  635. if target_info.exeext<>'' then
  636. FindUtil:=ChangeFileExt(s,target_info.exeext)
  637. else
  638. FindUtil:=s;
  639. exit;
  640. end;
  641. { change extension only on platforms that use an exe extension, otherwise on OpenBSD 'ld.bfd' gets converted
  642. to 'ld' }
  643. if source_info.exeext<>'' then
  644. UtilExe:=ChangeFileExt(s,source_info.exeext)
  645. else
  646. UtilExe:=s;
  647. FoundBin:='';
  648. Found:=false;
  649. if utilsdirectory<>'' then
  650. Found:=FindFile(utilexe,utilsdirectory,false,Foundbin);
  651. if (not Found) then
  652. Found:=FindExe(utilexe,false,Foundbin);
  653. if (not Found) and not(cs_link_nolink in current_settings.globalswitches) then
  654. begin
  655. Message1(exec_e_util_not_found,utilexe);
  656. current_settings.globalswitches:=current_settings.globalswitches+[cs_link_nolink];
  657. end;
  658. if (FoundBin<>'') then
  659. Message1(exec_t_using_util,FoundBin);
  660. FindUtil:=FoundBin;
  661. end;
  662. Function TExternalLinker.CatFileContent(para : TCmdStr) : TCmdStr;
  663. var
  664. filecontent : TCmdStr;
  665. f : text;
  666. st : TCmdStr;
  667. begin
  668. if not (tf_no_backquote_support in source_info.flags) or
  669. (cs_link_on_target in current_settings.globalswitches) then
  670. begin
  671. CatFileContent:='`cat '+MaybeQuoted(para)+'`';
  672. Exit;
  673. end;
  674. assign(f,para);
  675. filecontent:='';
  676. {$push}{$I-}
  677. reset(f);
  678. {$pop}
  679. if IOResult<>0 then
  680. begin
  681. Message1(exec_n_backquote_cat_file_not_found,para);
  682. end
  683. else
  684. begin
  685. while not eof(f) do
  686. begin
  687. readln(f,st);
  688. if st<>'' then
  689. filecontent:=filecontent+' '+st;
  690. end;
  691. close(f);
  692. end;
  693. CatFileContent:=filecontent;
  694. end;
  695. Function TExternalLinker.DoExec(const command:TCmdStr; para:TCmdStr;showinfo,useshell:boolean):boolean;
  696. var
  697. exitcode: longint;
  698. begin
  699. DoExec:=true;
  700. if not(cs_link_nolink in current_settings.globalswitches) then
  701. begin
  702. FlushOutput;
  703. if useshell then
  704. exitcode:=shell(maybequoted(command)+' '+para)
  705. else
  706. try
  707. exitcode:=RequotedExecuteProcess(command,para);
  708. except on E:EOSError do
  709. begin
  710. Message(exec_e_cant_call_linker);
  711. current_settings.globalswitches:=current_settings.globalswitches+[cs_link_nolink];
  712. DoExec:=false;
  713. end;
  714. end;
  715. if (exitcode<>0) then
  716. begin
  717. Message(exec_e_error_while_linking);
  718. current_settings.globalswitches:=current_settings.globalswitches+[cs_link_nolink];
  719. DoExec:=false;
  720. end;
  721. end;
  722. { Update asmres when externmode is set }
  723. if cs_link_nolink in current_settings.globalswitches then
  724. begin
  725. if showinfo then
  726. begin
  727. if current_module.islibrary then
  728. AsmRes.AddLinkCommand(Command,Para,current_module.sharedlibfilename)
  729. else
  730. AsmRes.AddLinkCommand(Command,Para,current_module.exefilename);
  731. end
  732. else
  733. AsmRes.AddLinkCommand(Command,Para,'');
  734. end;
  735. end;
  736. Function TExternalLinker.MakeStaticLibrary:boolean;
  737. function GetNextFiles(const maxCmdLength : Longint; var item : TCmdStrListItem; const addfilecmd : string) : TCmdStr;
  738. begin
  739. result := '';
  740. while (assigned(item) and ((length(result) + length(item.str) + 1) < maxCmdLength)) do begin
  741. result := result + ' ' + addfilecmd + item.str;
  742. item := TCmdStrListItem(item.next);
  743. end;
  744. end;
  745. var
  746. binstr, firstbinstr, scriptfile : TCmdStr;
  747. cmdstr, firstcmd, nextcmd, smartpath : TCmdStr;
  748. current : TCmdStrListItem;
  749. script: Text;
  750. scripted_ar : boolean;
  751. ar_creates_different_output_file : boolean;
  752. success : boolean;
  753. first : boolean;
  754. begin
  755. MakeStaticLibrary:=false;
  756. { remove the library, to be sure that it is rewritten }
  757. DeleteFile(current_module.staticlibfilename);
  758. { Call AR }
  759. smartpath:=FixPath(ChangeFileExt(current_module.asmfilename,target_info.smartext),false);
  760. SplitBinCmd(target_ar.arcmd,binstr,cmdstr);
  761. binstr := FindUtil(utilsprefix + binstr);
  762. if target_ar.arfirstcmd<>'' then
  763. begin
  764. SplitBinCmd(target_ar.arfirstcmd,firstbinstr,firstcmd);
  765. firstbinstr := FindUtil(utilsprefix + firstbinstr);
  766. end
  767. else
  768. begin
  769. firstbinstr:=binstr;
  770. firstcmd:=cmdstr;
  771. end;
  772. scripted_ar:=(target_ar.id=ar_gnu_ar_scripted) or
  773. (target_ar.id=ar_watcom_wlib_omf_scripted);
  774. if scripted_ar then
  775. begin
  776. scriptfile := FixFileName(smartpath+'arscript.txt');
  777. Replace(cmdstr,'$SCRIPT',maybequoted(scriptfile));
  778. Assign(script, scriptfile);
  779. Rewrite(script);
  780. try
  781. if (target_ar.id=ar_gnu_ar_scripted) then
  782. writeln(script, 'CREATE ' + current_module.staticlibfilename)
  783. else { wlib case }
  784. writeln(script,'-q -fo -c -b '+
  785. maybequoted(current_module.staticlibfilename));
  786. current := TCmdStrListItem(SmartLinkOFiles.First);
  787. while current <> nil do
  788. begin
  789. if (target_ar.id=ar_gnu_ar_scripted) then
  790. writeln(script, 'ADDMOD ' + current.str)
  791. else
  792. writeln(script,'+' + current.str);
  793. current := TCmdStrListItem(current.next);
  794. end;
  795. if (target_ar.id=ar_gnu_ar_scripted) then
  796. begin
  797. writeln(script, 'SAVE');
  798. writeln(script, 'END');
  799. end;
  800. finally
  801. Close(script);
  802. end;
  803. success:=DoExec(binstr,cmdstr,false,true);
  804. end
  805. else
  806. begin
  807. ar_creates_different_output_file:=(Pos('$OUTPUTLIB',cmdstr)>0) or (Pos('$OUTPUTLIB',firstcmd)>0);
  808. Replace(cmdstr,'$LIB',maybequoted(current_module.staticlibfilename));
  809. Replace(firstcmd,'$LIB',maybequoted(current_module.staticlibfilename));
  810. Replace(cmdstr,'$OUTPUTLIB',maybequoted(current_module.staticlibfilename+'.tmp'));
  811. Replace(firstcmd,'$OUTPUTLIB',maybequoted(current_module.staticlibfilename+'.tmp'));
  812. { create AR commands }
  813. success := true;
  814. current := TCmdStrListItem(SmartLinkOFiles.First);
  815. first := true;
  816. repeat
  817. if first then
  818. nextcmd := firstcmd
  819. else
  820. nextcmd := cmdstr;
  821. Replace(nextcmd,'$FILES',GetNextFiles(2047, current, target_ar.addfilecmd));
  822. if first then
  823. success:=DoExec(firstbinstr,nextcmd,false,true)
  824. else
  825. success:=DoExec(binstr,nextcmd,false,true);
  826. if ar_creates_different_output_file then
  827. begin
  828. if FileExists(current_module.staticlibfilename,false) then
  829. DeleteFile(current_module.staticlibfilename);
  830. if FileExists(current_module.staticlibfilename+'.tmp',false) then
  831. RenameFile(current_module.staticlibfilename+'.tmp',current_module.staticlibfilename);
  832. end;
  833. first := false;
  834. until (not assigned(current)) or (not success);
  835. end;
  836. if (target_ar.arfinishcmd <> '') then
  837. begin
  838. SplitBinCmd(target_ar.arfinishcmd,binstr,cmdstr);
  839. binstr := FindUtil(utilsprefix + binstr);
  840. Replace(cmdstr,'$LIB',maybequoted(current_module.staticlibfilename));
  841. success:=DoExec(binstr,cmdstr,false,true);
  842. end;
  843. { Clean up }
  844. if not(cs_asm_leave in current_settings.globalswitches) then
  845. if not(cs_link_nolink in current_settings.globalswitches) then
  846. begin
  847. while not SmartLinkOFiles.Empty do
  848. DeleteFile(SmartLinkOFiles.GetFirst);
  849. if scripted_ar then
  850. DeleteFile(scriptfile);
  851. RemoveDir(smartpath);
  852. end
  853. else
  854. begin
  855. while not SmartLinkOFiles.Empty do
  856. AsmRes.AddDeleteCommand(SmartLinkOFiles.GetFirst);
  857. if scripted_ar then
  858. AsmRes.AddDeleteCommand(scriptfile);
  859. AsmRes.AddDeleteDirCommand(smartpath);
  860. end;
  861. MakeStaticLibrary:=success;
  862. end;
  863. function TExternalLinker.UniqueName(const str: TCmdStr): TCmdStr;
  864. const
  865. pid: SizeUInt = 0;
  866. begin
  867. if pid=0 then
  868. pid:=GetProcessID;
  869. if pid>0 then
  870. result:=str+tostr(pid)
  871. else
  872. result:=str;
  873. end;
  874. {*****************************************************************************
  875. TINTERNALLINKER
  876. *****************************************************************************}
  877. Constructor TInternalLinker.Create;
  878. begin
  879. inherited Create;
  880. linkscript:=TCmdStrList.Create;
  881. FStaticLibraryList:=TFPObjectList.Create(true);
  882. FImportLibraryList:=TFPHashObjectList.Create(true);
  883. FGroupStack:=TFPObjectList.Create(false);
  884. exemap:=nil;
  885. exeoutput:=nil;
  886. UseStabs:=false;
  887. CObjInput:=TObjInput;
  888. ScriptCount:=0;
  889. IsHandled:=nil;
  890. end;
  891. Destructor TInternalLinker.Destroy;
  892. begin
  893. FGroupStack.Free;
  894. linkscript.free;
  895. StaticLibraryList.Free;
  896. ImportLibraryList.Free;
  897. if assigned(IsHandled) then
  898. begin
  899. FreeMem(IsHandled,sizeof(boolean)*ScriptCount);
  900. IsHandled:=nil;
  901. ScriptCount:=0;
  902. end;
  903. if assigned(exeoutput) then
  904. begin
  905. exeoutput.free;
  906. exeoutput:=nil;
  907. end;
  908. if assigned(exemap) then
  909. begin
  910. exemap.free;
  911. exemap:=nil;
  912. end;
  913. inherited destroy;
  914. end;
  915. procedure TInternalLinker.AddImportSymbol(const libname,symname,symmangledname:TCmdStr;OrdNr: longint;isvar:boolean);
  916. var
  917. ImportLibrary : TImportLibrary;
  918. ImportSymbol : TFPHashObject;
  919. begin
  920. ImportLibrary:=TImportLibrary(ImportLibraryList.Find(libname));
  921. if not assigned(ImportLibrary) then
  922. ImportLibrary:=TImportLibrary.Create(ImportLibraryList,libname);
  923. ImportSymbol:=TFPHashObject(ImportLibrary.ImportSymbolList.Find(symname));
  924. if not assigned(ImportSymbol) then
  925. ImportSymbol:=TImportSymbol.Create(ImportLibrary.ImportSymbolList,symname,symmangledname,OrdNr,isvar);
  926. end;
  927. procedure TInternalLinker.ScriptAddSourceStatements(AddSharedAsStatic:boolean);
  928. var
  929. s,s2: TCmdStr;
  930. begin
  931. while not ObjectFiles.Empty do
  932. begin
  933. s:=ObjectFiles.GetFirst;
  934. if s<>'' then
  935. LinkScript.Concat('READOBJECT '+MaybeQuoted(s));
  936. end;
  937. while not StaticLibFiles.Empty do
  938. begin
  939. s:=StaticLibFiles.GetFirst;
  940. if s<>'' then
  941. LinkScript.Concat('READSTATICLIBRARY '+MaybeQuoted(s));
  942. end;
  943. if not AddSharedAsStatic then
  944. exit;
  945. while not SharedLibFiles.Empty do
  946. begin
  947. S:=SharedLibFiles.GetFirst;
  948. if FindLibraryFile(s,target_info.staticClibprefix,target_info.staticClibext,s2) then
  949. LinkScript.Concat('READSTATICLIBRARY '+MaybeQuoted(s2))
  950. else
  951. Comment(V_Error,'Import library not found for '+S);
  952. end;
  953. end;
  954. function TInternalLinker.GetCodeSize(aExeOutput: TExeOutput): QWord;
  955. begin
  956. Result:=aExeOutput.findexesection('.text').size;
  957. end;
  958. function TInternalLinker.GetDataSize(aExeOutput: TExeOutput): QWord;
  959. begin
  960. Result:=aExeOutput.findexesection('.data').size;
  961. end;
  962. function TInternalLinker.GetBssSize(aExeOutput: TExeOutput): QWord;
  963. var
  964. bsssec: TExeSection;
  965. begin
  966. bsssec:=aExeOutput.findexesection('.bss');
  967. if assigned(bsssec) then
  968. Result:=bsssec.size
  969. else
  970. Result:=0;
  971. end;
  972. procedure TInternalLinker.ParseLdScript(src:TScriptLexer);
  973. var
  974. asneeded: boolean;
  975. group: TStaticLibrary;
  976. procedure ParseInputList;
  977. var
  978. saved_asneeded: boolean;
  979. begin
  980. src.Expect('(');
  981. repeat
  982. if src.CheckForIdent('AS_NEEDED') then
  983. begin
  984. saved_asneeded:=asneeded;
  985. asneeded:=true;
  986. ParseInputList;
  987. asneeded:=saved_asneeded;
  988. end
  989. else if src.token in [tkIDENT,tkLITERAL] then
  990. begin
  991. Load_ReadStaticLibrary(src.tokenstr,asneeded);
  992. src.nextToken;
  993. end
  994. else if src.CheckFor('-') then
  995. begin
  996. { TODO: no whitespace between '-' and name;
  997. name must begin with 'l' }
  998. src.nextToken;
  999. end
  1000. else { syntax error, no input_list_element term }
  1001. Break;
  1002. if src.CheckFor(',') then
  1003. Continue;
  1004. until src.CheckFor(')');
  1005. end;
  1006. begin
  1007. asneeded:=false;
  1008. src.nextToken;
  1009. repeat
  1010. if src.CheckForIdent('OUTPUT_FORMAT') then
  1011. begin
  1012. src.Expect('(');
  1013. //writeln('output_format(',src.tokenstr,')');
  1014. src.nextToken;
  1015. src.Expect(')');
  1016. end
  1017. else if src.CheckForIdent('GROUP') then
  1018. begin
  1019. group:=TStaticLibrary.create_group;
  1020. TFPObjectList(FGroupStack.Last).Add(group);
  1021. FGroupStack.Add(group.GroupMembers);
  1022. ParseInputList;
  1023. FGroupStack.Delete(FGroupStack.Count-1);
  1024. end
  1025. else if src.CheckFor(';') then
  1026. {skip semicolon};
  1027. until src.token in [tkEOF,tkINVALID];
  1028. end;
  1029. procedure TInternalLinker.Load_ReadObject(const para:TCmdStr);
  1030. var
  1031. objdata : TObjData;
  1032. objinput : TObjinput;
  1033. objreader : TObjectReader;
  1034. fn : TCmdStr;
  1035. begin
  1036. fn:=FindObjectFile(para,'',false);
  1037. Comment(V_Tried,'Reading object '+fn);
  1038. objinput:=CObjInput.Create;
  1039. objreader:=TObjectreader.create;
  1040. if objreader.openfile(fn) then
  1041. begin
  1042. if objinput.ReadObjData(objreader,objdata) then
  1043. exeoutput.addobjdata(objdata);
  1044. end;
  1045. { release input object }
  1046. objinput.free;
  1047. objreader.free;
  1048. end;
  1049. procedure TInternalLinker.Load_ReadStaticLibrary(const para:TCmdStr;asneededflag:boolean);
  1050. var
  1051. objreader : TObjectReader;
  1052. objinput: TObjInput;
  1053. objdata: TObjData;
  1054. ScriptLexer: TScriptLexer;
  1055. stmt:TStaticLibrary;
  1056. begin
  1057. { TODO: Cleanup ignoring of FPC generated libimp*.a files}
  1058. { Don't load import libraries }
  1059. if copy(ExtractFileName(para),1,6)='libimp' then
  1060. exit;
  1061. Comment(V_Tried,'Opening library '+para);
  1062. objreader:=CArObjectreader.createAr(para,true);
  1063. if ErrorCount>0 then
  1064. exit;
  1065. if objreader.isarchive then
  1066. TFPObjectList(FGroupStack.Last).Add(TStaticLibrary.Create(para,objreader,CObjInput))
  1067. else
  1068. if CObjInput.CanReadObjData(objreader) then
  1069. begin
  1070. { may be a regular object as well as a dynamic one }
  1071. objinput:=CObjInput.Create;
  1072. if objinput.ReadObjData(objreader,objdata) then
  1073. begin
  1074. stmt:=TStaticLibrary.create_object(objdata);
  1075. stmt.AsNeeded:=asneededflag;
  1076. TFPObjectList(FGroupStack.Last).Add(stmt);
  1077. end;
  1078. objinput.Free;
  1079. objreader.Free;
  1080. end
  1081. else { try parsing as script }
  1082. begin
  1083. Comment(V_Tried,'Interpreting '+para+' as ld script');
  1084. ScriptLexer:=TScriptLexer.Create(objreader);
  1085. ParseLdScript(ScriptLexer);
  1086. ScriptLexer.Free;
  1087. objreader.Free;
  1088. end;
  1089. end;
  1090. procedure TInternalLinker.Load_Group;
  1091. var
  1092. group: TStaticLibrary;
  1093. begin
  1094. group:=TStaticLibrary.create_group;
  1095. TFPObjectList(FGroupStack.Last).Add(group);
  1096. FGroupStack.Add(group.GroupMembers);
  1097. end;
  1098. procedure TInternalLinker.Load_EndGroup;
  1099. begin
  1100. FGroupStack.Delete(FGroupStack.Count-1);
  1101. end;
  1102. procedure TInternalLinker.ParseScript_Handle;
  1103. var
  1104. s{, para}, keyword : String;
  1105. hp : TCmdStrListItem;
  1106. i : longint;
  1107. begin
  1108. hp:=TCmdStrListItem(linkscript.first);
  1109. i:=0;
  1110. while assigned(hp) do
  1111. begin
  1112. inc(i);
  1113. s:=hp.str;
  1114. if (s='') or (s[1]='#') then
  1115. begin
  1116. hp:=TCmdStrListItem(hp.next);
  1117. continue;
  1118. end;
  1119. keyword:=Upper(GetToken(s,' '));
  1120. {para:=}GetToken(s,' ');
  1121. if Trim(s)<>'' then
  1122. Comment(V_Warning,'Unknown part "'+s+'" in "'+hp.str+'" internal linker script');
  1123. if (keyword<>'SYMBOL') and
  1124. (keyword<>'SYMBOLS') and
  1125. (keyword<>'STABS') and
  1126. (keyword<>'PROVIDE') and
  1127. (keyword<>'ZEROS') and
  1128. (keyword<>'BYTE') and
  1129. (keyword<>'WORD') and
  1130. (keyword<>'LONG') and
  1131. (keyword<>'QUAD') and
  1132. (keyword<>'ENTRYNAME') and
  1133. (keyword<>'ISSHAREDLIBRARY') and
  1134. (keyword<>'IMAGEBASE') and
  1135. (keyword<>'READOBJECT') and
  1136. (keyword<>'READSTATICLIBRARY') and
  1137. (keyword<>'EXESECTION') and
  1138. (keyword<>'ENDEXESECTION') and
  1139. (keyword<>'OBJSECTION') and
  1140. (keyword<>'HEADER') and
  1141. (keyword<>'GROUP') and
  1142. (keyword<>'ENDGROUP')
  1143. then
  1144. Comment(V_Warning,'Unknown keyword "'+keyword+'" in "'+hp.str
  1145. +'" internal linker script');
  1146. hp:=TCmdStrListItem(hp.next);
  1147. end;
  1148. ScriptCount:=i;
  1149. if ScriptCount>0 then
  1150. begin
  1151. GetMem(IsHandled,sizeof(boolean)*ScriptCount);
  1152. Fillchar(IsHandled^,sizeof(boolean)*ScriptCount,#0);
  1153. end;
  1154. end;
  1155. procedure TInternalLinker.ParseScript_PostCheck;
  1156. var
  1157. hp : TCmdStrListItem;
  1158. i : longint;
  1159. begin
  1160. hp:=TCmdStrListItem(linkscript.first);
  1161. i:=0;
  1162. while assigned(hp) do
  1163. begin
  1164. inc(i);
  1165. if not IsHandled^[i] then
  1166. begin
  1167. Comment(V_Warning,'"'+hp.str+
  1168. '" internal linker script not handled');
  1169. end;
  1170. hp:=TCmdStrListItem(hp.next);
  1171. end;
  1172. end;
  1173. function TInternalLinker.ParsePara(const para : string) : string;
  1174. var
  1175. res : string;
  1176. begin
  1177. res:=trim(para);
  1178. { Remove enclosing braces }
  1179. if (length(res)>0) and (res[1]='(') and
  1180. (res[length(res)]=')') then
  1181. res:=trim(copy(res,2,length(res)-2));
  1182. result:=res;
  1183. end;
  1184. procedure TInternalLinker.ParseScript_Load;
  1185. var
  1186. s,
  1187. para,
  1188. keyword : String;
  1189. hp : TCmdStrListItem;
  1190. i : longint;
  1191. handled : boolean;
  1192. begin
  1193. exeoutput.Load_Start;
  1194. hp:=TCmdStrListItem(linkscript.first);
  1195. i:=0;
  1196. while assigned(hp) do
  1197. begin
  1198. inc(i);
  1199. s:=hp.str;
  1200. if (s='') or (s[1]='#') then
  1201. begin
  1202. IsHandled^[i]:=true;
  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='SYMBOL' then
  1210. ExeOutput.Load_Symbol(para)
  1211. else if keyword='PROVIDE' then
  1212. ExeOutput.Load_ProvideSymbol(para)
  1213. else if keyword='ENTRYNAME' then
  1214. ExeOutput.Load_EntryName(para)
  1215. else if keyword='ISSHAREDLIBRARY' then
  1216. ExeOutput.Load_IsSharedLibrary
  1217. else if keyword='IMAGEBASE' then
  1218. ExeOutput.Load_ImageBase(para)
  1219. else if keyword='READOBJECT' then
  1220. Load_ReadObject(para)
  1221. else if keyword='STABS' then
  1222. UseStabs:=true
  1223. else if keyword='READSTATICLIBRARY' then
  1224. Load_ReadStaticLibrary(para)
  1225. else if keyword='GROUP' then
  1226. Load_Group
  1227. else if keyword='ENDGROUP' then
  1228. Load_EndGroup
  1229. else
  1230. handled:=false;
  1231. if handled then
  1232. IsHandled^[i]:=true;
  1233. hp:=TCmdStrListItem(hp.next);
  1234. end;
  1235. end;
  1236. procedure TInternalLinker.ParseScript_Order;
  1237. var
  1238. s,
  1239. para,
  1240. keyword : String;
  1241. hp : TCmdStrListItem;
  1242. i : longint;
  1243. handled : boolean;
  1244. begin
  1245. exeoutput.Order_Start;
  1246. hp:=TCmdStrListItem(linkscript.first);
  1247. i:=0;
  1248. while assigned(hp) do
  1249. begin
  1250. inc(i);
  1251. s:=hp.str;
  1252. if (s='') or (s[1]='#') then
  1253. begin
  1254. hp:=TCmdStrListItem(hp.next);
  1255. continue;
  1256. end;
  1257. handled:=true;
  1258. keyword:=Upper(GetToken(s,' '));
  1259. para:=ParsePara(GetToken(s,' '));
  1260. if keyword='EXESECTION' then
  1261. ExeOutput.Order_ExeSection(para)
  1262. else if keyword='ENDEXESECTION' then
  1263. ExeOutput.Order_EndExeSection
  1264. else if keyword='OBJSECTION' then
  1265. ExeOutput.Order_ObjSection(para)
  1266. else if keyword='ZEROS' then
  1267. ExeOutput.Order_Zeros(para)
  1268. else if keyword='BYTE' then
  1269. ExeOutput.Order_Values(1,para)
  1270. else if keyword='WORD' then
  1271. ExeOutput.Order_Values(2,para)
  1272. else if keyword='LONG' then
  1273. ExeOutput.Order_Values(4,para)
  1274. else if keyword='QUAD' then
  1275. ExeOutput.Order_Values(8,para)
  1276. else if keyword='SYMBOL' then
  1277. ExeOutput.Order_Symbol(para)
  1278. else if keyword='PROVIDE' then
  1279. ExeOutput.Order_ProvideSymbol(para)
  1280. else
  1281. handled:=false;
  1282. if handled then
  1283. IsHandled^[i]:=true;
  1284. hp:=TCmdStrListItem(hp.next);
  1285. end;
  1286. exeoutput.Order_End;
  1287. end;
  1288. procedure TInternalLinker.ParseScript_MemPos;
  1289. var
  1290. s,
  1291. para,
  1292. keyword : String;
  1293. hp : TCmdStrListItem;
  1294. i : longint;
  1295. handled : boolean;
  1296. begin
  1297. exeoutput.MemPos_Start;
  1298. hp:=TCmdStrListItem(linkscript.first);
  1299. i:=0;
  1300. while assigned(hp) do
  1301. begin
  1302. inc(i);
  1303. s:=hp.str;
  1304. if (s='') or (s[1]='#') then
  1305. begin
  1306. hp:=TCmdStrListItem(hp.next);
  1307. continue;
  1308. end;
  1309. handled:=true;
  1310. keyword:=Upper(GetToken(s,' '));
  1311. para:=ParsePara(GetToken(s,' '));
  1312. if keyword='EXESECTION' then
  1313. ExeOutput.MemPos_ExeSection(para)
  1314. else if keyword='ENDEXESECTION' then
  1315. ExeOutput.MemPos_EndExeSection
  1316. else if keyword='HEADER' then
  1317. ExeOutput.MemPos_Header
  1318. else
  1319. handled:=false;
  1320. if handled then
  1321. IsHandled^[i]:=true;
  1322. hp:=TCmdStrListItem(hp.next);
  1323. end;
  1324. end;
  1325. procedure TInternalLinker.ParseScript_DataPos;
  1326. var
  1327. s,
  1328. para,
  1329. keyword : String;
  1330. hp : TCmdStrListItem;
  1331. i : longint;
  1332. handled : boolean;
  1333. begin
  1334. exeoutput.DataPos_Start;
  1335. hp:=TCmdStrListItem(linkscript.first);
  1336. i:=0;
  1337. while assigned(hp) do
  1338. begin
  1339. inc(i);
  1340. s:=hp.str;
  1341. if (s='') or (s[1]='#') then
  1342. begin
  1343. hp:=TCmdStrListItem(hp.next);
  1344. continue;
  1345. end;
  1346. handled:=true;
  1347. keyword:=Upper(GetToken(s,' '));
  1348. para:=ParsePara(GetToken(s,' '));
  1349. if keyword='EXESECTION' then
  1350. ExeOutput.DataPos_ExeSection(para)
  1351. else if keyword='ENDEXESECTION' then
  1352. ExeOutput.DataPos_EndExeSection
  1353. else if keyword='HEADER' then
  1354. ExeOutput.DataPos_Header
  1355. else if keyword='SYMBOLS' then
  1356. ExeOutput.DataPos_Symbols
  1357. else
  1358. handled:=false;
  1359. if handled then
  1360. IsHandled^[i]:=true;
  1361. hp:=TCmdStrListItem(hp.next);
  1362. end;
  1363. end;
  1364. procedure TInternalLinker.PrintLinkerScript;
  1365. var
  1366. hp : TCmdStrListItem;
  1367. begin
  1368. if not assigned(exemap) then
  1369. exit;
  1370. exemap.Add('Used linker script');
  1371. exemap.Add('');
  1372. hp:=TCmdStrListItem(linkscript.first);
  1373. while assigned(hp) do
  1374. begin
  1375. exemap.Add(hp.str);
  1376. hp:=TCmdStrListItem(hp.next);
  1377. end;
  1378. end;
  1379. function TInternalLinker.RunLinkScript(const outputname:TCmdStr):boolean;
  1380. label
  1381. myexit;
  1382. var
  1383. bsssize : aword;
  1384. dbgname : TCmdStr;
  1385. begin
  1386. result:=false;
  1387. Message1(exec_i_linking,outputname);
  1388. FlushOutput;
  1389. exeoutput:=CExeOutput.Create;
  1390. { TODO: Load custom linker script}
  1391. DefaultLinkScript;
  1392. if (cs_link_map in current_settings.globalswitches) then
  1393. exemap:=texemap.create(current_module.mapfilename);
  1394. PrintLinkerScript;
  1395. { Check that syntax is OK }
  1396. ParseScript_Handle;
  1397. { Load .o files and resolve symbols }
  1398. FGroupStack.Add(FStaticLibraryList);
  1399. ParseScript_Load;
  1400. if ErrorCount>0 then
  1401. goto myexit;
  1402. exeoutput.ResolveSymbols(StaticLibraryList);
  1403. { Generate symbols and code to do the importing }
  1404. exeoutput.GenerateLibraryImports(ImportLibraryList);
  1405. { Fill external symbols data }
  1406. exeoutput.FixupSymbols;
  1407. if ErrorCount>0 then
  1408. goto myexit;
  1409. { parse linker options specific for output format }
  1410. exeoutput.ParseScript (linkscript);
  1411. { Create .exe sections and add .o sections }
  1412. ParseScript_Order;
  1413. exeoutput.RemoveUnreferencedSections;
  1414. { if UseStabs then, this would remove
  1415. STABS for empty linker scripts }
  1416. exeoutput.MergeStabs;
  1417. exeoutput.MarkEmptySections;
  1418. exeoutput.AfterUnusedSectionRemoval;
  1419. if ErrorCount>0 then
  1420. goto myexit;
  1421. { Calc positions in mem }
  1422. ParseScript_MemPos;
  1423. exeoutput.FixupRelocations;
  1424. exeoutput.RemoveUnusedExeSymbols;
  1425. exeoutput.PrintMemoryMap;
  1426. if ErrorCount>0 then
  1427. goto myexit;
  1428. if cs_link_separate_dbg_file in current_settings.globalswitches then
  1429. begin
  1430. { create debuginfo, which is an executable without data on disk }
  1431. dbgname:=ChangeFileExt(outputname,'.dbg');
  1432. exeoutput.ExeWriteMode:=ewm_dbgonly;
  1433. ParseScript_DataPos;
  1434. exeoutput.WriteExeFile(dbgname);
  1435. { create executable with link to just created debuginfo file }
  1436. exeoutput.ExeWriteMode:=ewm_exeonly;
  1437. exeoutput.RemoveDebugInfo;
  1438. exeoutput.GenerateDebugLink(ExtractFileName(dbgname),GetFileCRC(dbgname));
  1439. ParseScript_MemPos;
  1440. ParseScript_DataPos;
  1441. exeoutput.WriteExeFile(outputname);
  1442. end
  1443. else
  1444. begin
  1445. exeoutput.ExeWriteMode:=ewm_exefull;
  1446. ParseScript_DataPos;
  1447. exeoutput.WriteExeFile(outputname);
  1448. end;
  1449. { Post check that everything was handled }
  1450. ParseScript_PostCheck;
  1451. status.codesize:=GetCodeSize(exeoutput);
  1452. status.datasize:=GetDataSize(exeoutput);
  1453. bsssize:=GetBssSize(exeoutput);
  1454. { Executable info }
  1455. Message1(execinfo_x_codesize,tostr(status.codesize));
  1456. Message1(execinfo_x_initdatasize,tostr(status.datasize));
  1457. Message1(execinfo_x_uninitdatasize,tostr(bsssize));
  1458. Message1(execinfo_x_stackreserve,tostr(stacksize));
  1459. myexit:
  1460. { close map }
  1461. if assigned(exemap) then
  1462. begin
  1463. exemap.free;
  1464. exemap:=nil;
  1465. end;
  1466. { close exe }
  1467. exeoutput.free;
  1468. exeoutput:=nil;
  1469. result:=true;
  1470. end;
  1471. function TInternalLinker.MakeExecutable:boolean;
  1472. begin
  1473. IsSharedLibrary:=false;
  1474. result:=RunLinkScript(current_module.exefilename);
  1475. {$ifdef hasUnix}
  1476. fpchmod(current_module.exefilename,493);
  1477. {$endif hasUnix}
  1478. end;
  1479. function TInternalLinker.MakeSharedLibrary:boolean;
  1480. begin
  1481. IsSharedLibrary:=true;
  1482. result:=RunLinkScript(current_module.sharedlibfilename);
  1483. end;
  1484. procedure TInternalLinker.ScriptAddGenericSections(secnames:string);
  1485. var
  1486. secname:string;
  1487. begin
  1488. repeat
  1489. secname:=gettoken(secnames,',');
  1490. if secname='' then
  1491. break;
  1492. linkscript.Concat('EXESECTION '+secname);
  1493. linkscript.Concat(' OBJSECTION '+secname+'*');
  1494. linkscript.Concat('ENDEXESECTION');
  1495. until false;
  1496. end;
  1497. {*****************************************************************************
  1498. Init/Done
  1499. *****************************************************************************}
  1500. procedure RegisterLinker(id:tlink;c:TLinkerClass);
  1501. begin
  1502. CLinker[id]:=c;
  1503. end;
  1504. procedure InitLinker;
  1505. begin
  1506. if (cs_link_extern in current_settings.globalswitches) and
  1507. assigned(CLinker[target_info.linkextern]) then
  1508. begin
  1509. linker:=CLinker[target_info.linkextern].Create;
  1510. end
  1511. else
  1512. if assigned(CLinker[target_info.link]) then
  1513. begin
  1514. linker:=CLinker[target_info.link].Create;
  1515. end
  1516. else
  1517. linker:=Tlinker.Create;
  1518. end;
  1519. procedure DoneLinker;
  1520. begin
  1521. if assigned(linker) then
  1522. Linker.Free;
  1523. end;
  1524. {*****************************************************************************
  1525. Initialize
  1526. *****************************************************************************}
  1527. const
  1528. ar_gnu_ar_info : tarinfo =
  1529. (
  1530. id : ar_gnu_ar;
  1531. addfilecmd : '';
  1532. arfirstcmd : '';
  1533. arcmd : 'ar qS $LIB $FILES';
  1534. arfinishcmd : 'ar s $LIB'
  1535. );
  1536. ar_gnu_ar_scripted_info : tarinfo =
  1537. (
  1538. id : ar_gnu_ar_scripted;
  1539. addfilecmd : '';
  1540. arfirstcmd : '';
  1541. arcmd : 'ar -M < $SCRIPT';
  1542. arfinishcmd : ''
  1543. );
  1544. ar_gnu_gar_info : tarinfo =
  1545. ( id : ar_gnu_gar;
  1546. addfilecmd : '';
  1547. arfirstcmd : '';
  1548. arcmd : 'gar qS $LIB $FILES';
  1549. arfinishcmd : 'gar s $LIB'
  1550. );
  1551. ar_watcom_wlib_omf_info : tarinfo =
  1552. ( id : ar_watcom_wlib_omf;
  1553. addfilecmd : '+';
  1554. arfirstcmd : 'wlib -q -fo -c -b -n -o=$OUTPUTLIB $LIB $FILES';
  1555. arcmd : 'wlib -q -fo -c -b -o=$OUTPUTLIB $LIB $FILES';
  1556. arfinishcmd : ''
  1557. );
  1558. ar_watcom_wlib_omf_scripted_info : tarinfo =
  1559. (
  1560. id : ar_watcom_wlib_omf_scripted;
  1561. addfilecmd : '+';
  1562. arfirstcmd : '';
  1563. arcmd : 'wlib @$SCRIPT';
  1564. arfinishcmd : ''
  1565. );
  1566. initialization
  1567. RegisterAr(ar_gnu_ar_info);
  1568. RegisterAr(ar_gnu_ar_scripted_info);
  1569. RegisterAr(ar_gnu_gar_info);
  1570. RegisterAr(ar_watcom_wlib_omf_info);
  1571. RegisterAr(ar_watcom_wlib_omf_scripted_info);
  1572. end.