link.pas 56 KB

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