link.pas 64 KB

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