link.pas 55 KB

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