link.pas 54 KB

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