2
0

link.pas 55 KB

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