link.pas 55 KB

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