link.pas 70 KB

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