link.pas 51 KB

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