link.pas 51 KB

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