link.pas 56 KB

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