link.pas 51 KB

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