t_linux.pas 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641
  1. {
  2. $Id$
  3. Copyright (c) 1998-2002 by Peter Vreman
  4. This unit implements support import,export,link routines
  5. for the (i386) Linux target
  6. This program is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 2 of the License, or
  9. (at your option) any later version.
  10. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with this program; if not, write to the Free Software
  16. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17. ****************************************************************************
  18. }
  19. unit t_linux;
  20. {$i fpcdefs.inc}
  21. interface
  22. uses
  23. symsym,symdef,
  24. import,export,link;
  25. type
  26. timportliblinux=class(timportlib)
  27. procedure preparelib(const s:string);override;
  28. procedure importprocedure(aprocdef:tprocdef;const module:string;index:longint;const name:string);override;
  29. procedure importvariable(vs:tglobalvarsym;const name,module:string);override;
  30. procedure generatelib;override;
  31. end;
  32. texportliblinux=class(texportlib)
  33. procedure preparelib(const s : string);override;
  34. procedure exportprocedure(hp : texported_item);override;
  35. procedure exportvar(hp : texported_item);override;
  36. procedure generatelib;override;
  37. end;
  38. tlinkerlinux=class(texternallinker)
  39. private
  40. libctype:(libc5,glibc2,glibc21,uclibc);
  41. Function WriteResponseFile(isdll:boolean) : Boolean;
  42. public
  43. constructor Create;override;
  44. procedure SetDefaultInfo;override;
  45. function MakeExecutable:boolean;override;
  46. function MakeSharedLibrary:boolean;override;
  47. end;
  48. implementation
  49. uses
  50. cutils,cclasses,
  51. verbose,systems,globtype,globals,
  52. symconst,script,
  53. fmodule,dos
  54. ,aasmbase,aasmtai,aasmcpu,cpubase,cgobj
  55. ,i_linux
  56. ;
  57. {*****************************************************************************
  58. TIMPORTLIBLINUX
  59. *****************************************************************************}
  60. procedure timportliblinux.preparelib(const s : string);
  61. begin
  62. end;
  63. procedure timportliblinux.importprocedure(aprocdef:tprocdef;const module:string;index:longint;const name:string);
  64. begin
  65. { insert sharedlibrary }
  66. current_module.linkothersharedlibs.add(SplitName(module),link_allways);
  67. end;
  68. procedure timportliblinux.importvariable(vs:tglobalvarsym;const name,module:string);
  69. begin
  70. { insert sharedlibrary }
  71. current_module.linkothersharedlibs.add(SplitName(module),link_allways);
  72. { reset the mangledname and turn off the dll_var option }
  73. vs.set_mangledname(name);
  74. exclude(vs.varoptions,vo_is_dll_var);
  75. end;
  76. procedure timportliblinux.generatelib;
  77. begin
  78. end;
  79. {*****************************************************************************
  80. TEXPORTLIBLINUX
  81. *****************************************************************************}
  82. procedure texportliblinux.preparelib(const s:string);
  83. begin
  84. end;
  85. procedure texportliblinux.exportprocedure(hp : texported_item);
  86. var
  87. hp2 : texported_item;
  88. begin
  89. { first test the index value }
  90. if (hp.options and eo_index)<>0 then
  91. begin
  92. Message1(parser_e_no_export_with_index_for_target,'linux');
  93. exit;
  94. end;
  95. { now place in correct order }
  96. hp2:=texported_item(current_module._exports.first);
  97. while assigned(hp2) and
  98. (hp.name^>hp2.name^) do
  99. hp2:=texported_item(hp2.next);
  100. { insert hp there !! }
  101. if assigned(hp2) and (hp2.name^=hp.name^) then
  102. begin
  103. { this is not allowed !! }
  104. Message1(parser_e_export_name_double,hp.name^);
  105. exit;
  106. end;
  107. if hp2=texported_item(current_module._exports.first) then
  108. current_module._exports.concat(hp)
  109. else if assigned(hp2) then
  110. begin
  111. hp.next:=hp2;
  112. hp.previous:=hp2.previous;
  113. if assigned(hp2.previous) then
  114. hp2.previous.next:=hp;
  115. hp2.previous:=hp;
  116. end
  117. else
  118. current_module._exports.concat(hp);
  119. end;
  120. procedure texportliblinux.exportvar(hp : texported_item);
  121. begin
  122. hp.is_var:=true;
  123. exportprocedure(hp);
  124. end;
  125. procedure texportliblinux.generatelib;
  126. var
  127. hp2 : texported_item;
  128. begin
  129. hp2:=texported_item(current_module._exports.first);
  130. while assigned(hp2) do
  131. begin
  132. if (not hp2.is_var) and
  133. (hp2.sym.typ=procsym) then
  134. begin
  135. { the manglednames can already be the same when the procedure
  136. is declared with cdecl }
  137. if tprocsym(hp2.sym).first_procdef.mangledname<>hp2.name^ then
  138. begin
  139. { place jump in codesegment }
  140. codesegment.concat(tai_align.create(target_info.alignment.procalign));
  141. codeSegment.concat(Tai_symbol.Createname_global(hp2.name^,AT_FUNCTION,0));
  142. cg.a_jmp_name(codesegment,tprocsym(hp2.sym).first_procdef.mangledname);
  143. codeSegment.concat(Tai_symbol_end.Createname(hp2.name^));
  144. end;
  145. end
  146. else
  147. Message1(parser_e_no_export_of_variables_for_target,'linux');
  148. hp2:=texported_item(hp2.next);
  149. end;
  150. end;
  151. {*****************************************************************************
  152. TLINKERLINUX
  153. *****************************************************************************}
  154. Constructor TLinkerLinux.Create;
  155. begin
  156. Inherited Create;
  157. if not Dontlinkstdlibpath Then
  158. LibrarySearchPath.AddPath('/lib;/usr/lib;/usr/X11R6/lib',true);
  159. end;
  160. procedure TLinkerLinux.SetDefaultInfo;
  161. {
  162. This will also detect which libc version will be used
  163. }
  164. {$ifdef m68k}
  165. var
  166. St : SearchRec;
  167. {$endif m68k}
  168. begin
  169. with Info do
  170. begin
  171. ExeCmd[1]:='ld $OPT $DYNLINK $STATIC $GCSECTIONS $STRIP -L. -o $EXE $RES';
  172. DllCmd[1]:='ld $OPT $INIT $FINI $SONAME -shared -L. -o $EXE $RES';
  173. DllCmd[2]:='strip --strip-unneeded $EXE';
  174. {$ifdef m68k}
  175. libctype:=glibc2;
  176. FindFirst('/lib/ld*',AnyFile,st);
  177. while DosError=0 do
  178. begin
  179. if copy(st.name,1,5)='ld-2.' then
  180. begin
  181. DynamicLinker:='/lib/'+St.name;
  182. if st.name[6]<>'0' then
  183. libctype:=glibc21;
  184. break;
  185. end;
  186. FindNext(St);
  187. end;
  188. FindClose(St);
  189. {$endif m68k}
  190. {$ifdef i386}
  191. { first try glibc2 }
  192. DynamicLinker:='/lib/ld-linux.so.2';
  193. if FileExists(DynamicLinker) then
  194. { Check for 2.0 files, else use the glibc 2.1 stub }
  195. if FileExists('/lib/ld-2.0.*') then
  196. libctype:=glibc2
  197. else
  198. libctype:=glibc21
  199. else
  200. if fileexists('/lib/ld-uClibc.so.0') then
  201. begin
  202. libctype:=uclibc;
  203. dynamiclinker:='/lib/ld-uClibc.so.0';
  204. end
  205. else
  206. DynamicLinker:='/lib/ld-linux.so.1';
  207. {$endif i386}
  208. {$ifdef x86_64}
  209. DynamicLinker:='/lib64/ld-linux-x86-64.so.2';
  210. libctype:=glibc2;
  211. {$endif x86_64}
  212. {$ifdef sparc}
  213. DynamicLinker:='/lib/ld-linux.so.2';
  214. libctype:=glibc2;
  215. {$endif sparc}
  216. {$ifdef powerpc}
  217. DynamicLinker:='/lib/ld.so.1';
  218. libctype:=glibc2;
  219. {$endif powerpc}
  220. {$ifdef arm}
  221. DynamicLinker:='/lib/ld-linux.so.2';
  222. libctype:=glibc2;
  223. {$endif arm}
  224. end;
  225. end;
  226. Function TLinkerLinux.WriteResponseFile(isdll:boolean) : Boolean;
  227. Var
  228. linkres : TLinkRes;
  229. i : longint;
  230. cprtobj,
  231. gprtobj,
  232. prtobj : string[80];
  233. HPath : TStringListItem;
  234. s,s1,s2 : string;
  235. found1,
  236. found2,
  237. linklibc : boolean;
  238. begin
  239. WriteResponseFile:=False;
  240. { set special options for some targets }
  241. linklibc:=(SharedLibFiles.Find('c')<>nil);
  242. if isdll then
  243. begin
  244. prtobj:='dllprt0';
  245. cprtobj:='dllprt0';
  246. gprtobj:='dllprt0';
  247. end
  248. else
  249. begin
  250. prtobj:='prt0';
  251. case libctype of
  252. glibc21:
  253. begin
  254. cprtobj:='cprt21';
  255. gprtobj:='gprt21';
  256. end;
  257. uclibc:
  258. begin
  259. cprtobj:='ucprt0';
  260. gprtobj:='ugprt0';
  261. end
  262. else
  263. cprtobj:='cprt0';
  264. gprtobj:='gprt0';
  265. end;
  266. end;
  267. if cs_profile in aktmoduleswitches then
  268. begin
  269. prtobj:=gprtobj;
  270. if not(libctype in [glibc2,glibc21]) then
  271. AddSharedLibrary('gmon');
  272. AddSharedLibrary('c');
  273. linklibc:=true;
  274. end
  275. else
  276. begin
  277. if linklibc then
  278. prtobj:=cprtobj;
  279. end;
  280. { Open link.res file }
  281. LinkRes:=TLinkRes.Create(outputexedir+Info.ResName);
  282. { Write path to search libraries }
  283. HPath:=TStringListItem(current_module.locallibrarysearchpath.First);
  284. while assigned(HPath) do
  285. begin
  286. LinkRes.Add('SEARCH_DIR('+maybequoted(HPath.Str)+')');
  287. HPath:=TStringListItem(HPath.Next);
  288. end;
  289. HPath:=TStringListItem(LibrarySearchPath.First);
  290. while assigned(HPath) do
  291. begin
  292. LinkRes.Add('SEARCH_DIR('+maybequoted(HPath.Str)+')');
  293. HPath:=TStringListItem(HPath.Next);
  294. end;
  295. LinkRes.Add('INPUT(');
  296. { add objectfiles, start with prt0 always }
  297. if prtobj<>'' then
  298. LinkRes.AddFileName(maybequoted(FindObjectFile(prtobj,'',false)));
  299. { try to add crti and crtbegin if linking to C }
  300. if linklibc then
  301. begin
  302. if librarysearchpath.FindFile('crtbegin.o',s) then
  303. LinkRes.AddFileName(s);
  304. if librarysearchpath.FindFile('crti.o',s) then
  305. LinkRes.AddFileName(s);
  306. end;
  307. { main objectfiles }
  308. while not ObjectFiles.Empty do
  309. begin
  310. s:=ObjectFiles.GetFirst;
  311. if s<>'' then
  312. LinkRes.AddFileName(maybequoted(s));
  313. end;
  314. LinkRes.Add(')');
  315. { Write staticlibraries }
  316. if not StaticLibFiles.Empty then
  317. begin
  318. LinkRes.Add('GROUP(');
  319. While not StaticLibFiles.Empty do
  320. begin
  321. S:=StaticLibFiles.GetFirst;
  322. LinkRes.AddFileName(maybequoted(s))
  323. end;
  324. LinkRes.Add(')');
  325. end;
  326. { Write sharedlibraries like -l<lib>, also add the needed dynamic linker
  327. here to be sure that it gets linked this is needed for glibc2 systems (PFV) }
  328. if not SharedLibFiles.Empty then
  329. begin
  330. LinkRes.Add('INPUT(');
  331. While not SharedLibFiles.Empty do
  332. begin
  333. S:=SharedLibFiles.GetFirst;
  334. if s<>'c' then
  335. begin
  336. i:=Pos(target_info.sharedlibext,S);
  337. if i>0 then
  338. Delete(S,i,255);
  339. LinkRes.Add('-l'+s);
  340. end
  341. else
  342. begin
  343. linklibc:=true;
  344. end;
  345. end;
  346. { be sure that libc is the last lib }
  347. if linklibc then
  348. LinkRes.Add('-lc');
  349. { when we have -static for the linker the we also need libgcc }
  350. if (cs_link_staticflag in aktglobalswitches) then
  351. LinkRes.Add('-lgcc');
  352. LinkRes.Add(')');
  353. end;
  354. { objects which must be at the end }
  355. if linklibc and (libctype<>uclibc) then
  356. begin
  357. found1:=librarysearchpath.FindFile('crtend.o',s1);
  358. found2:=librarysearchpath.FindFile('crtn.o',s2);
  359. if found1 or found2 then
  360. begin
  361. LinkRes.Add('INPUT(');
  362. if found1 then
  363. LinkRes.AddFileName(s1);
  364. if found2 then
  365. LinkRes.AddFileName(s2);
  366. LinkRes.Add(')');
  367. end;
  368. end;
  369. { Write and Close response }
  370. linkres.writetodisk;
  371. linkres.Free;
  372. WriteResponseFile:=True;
  373. end;
  374. function TLinkerLinux.MakeExecutable:boolean;
  375. var
  376. binstr : String;
  377. cmdstr : TCmdStr;
  378. success : boolean;
  379. DynLinkStr : string[60];
  380. GCSectionsStr,
  381. StaticStr,
  382. StripStr : string[40];
  383. begin
  384. if not(cs_link_extern in aktglobalswitches) then
  385. Message1(exec_i_linking,current_module.exefilename^);
  386. { Create some replacements }
  387. StaticStr:='';
  388. StripStr:='';
  389. GCSectionsStr:='';
  390. DynLinkStr:='';
  391. if (cs_link_staticflag in aktglobalswitches) then
  392. StaticStr:='-static';
  393. if (cs_link_strip in aktglobalswitches) then
  394. StripStr:='-s';
  395. if (cs_link_smart in aktglobalswitches) and
  396. (tf_smartlink_sections in target_info.flags) then
  397. GCSectionsStr:='--gc-sections';
  398. If (cs_profile in aktmoduleswitches) or
  399. ((Info.DynamicLinker<>'') and (not SharedLibFiles.Empty)) then
  400. begin
  401. DynLinkStr:='-dynamic-linker='+Info.DynamicLinker;
  402. if cshared Then
  403. DynLinkStr:='--shared ' + DynLinkStr;
  404. if rlinkpath<>'' Then
  405. DynLinkStr:='--rpath-link '+rlinkpath + ' '+ DynLinkStr;
  406. End;
  407. { Write used files and libraries }
  408. WriteResponseFile(false);
  409. { Call linker }
  410. SplitBinCmd(Info.ExeCmd[1],binstr,cmdstr);
  411. Replace(cmdstr,'$EXE',maybequoted(current_module.exefilename^));
  412. Replace(cmdstr,'$OPT',Info.ExtraOptions);
  413. Replace(cmdstr,'$RES',maybequoted(outputexedir+Info.ResName));
  414. Replace(cmdstr,'$STATIC',StaticStr);
  415. Replace(cmdstr,'$STRIP',StripStr);
  416. Replace(cmdstr,'$GCSECTIONS',GCSectionsStr);
  417. Replace(cmdstr,'$DYNLINK',DynLinkStr);
  418. success:=DoExec(FindUtil(utilsprefix+BinStr),CmdStr,true,false);
  419. { Remove ReponseFile }
  420. if (success) and not(cs_link_extern in aktglobalswitches) then
  421. RemoveFile(outputexedir+Info.ResName);
  422. MakeExecutable:=success; { otherwise a recursive call to link method }
  423. end;
  424. Function TLinkerLinux.MakeSharedLibrary:boolean;
  425. var
  426. InitStr,
  427. FiniStr,
  428. SoNameStr : string[80];
  429. binstr : String;
  430. cmdstr : TCmdStr;
  431. success : boolean;
  432. begin
  433. MakeSharedLibrary:=false;
  434. if not(cs_link_extern in aktglobalswitches) then
  435. Message1(exec_i_linking,current_module.sharedlibfilename^);
  436. { Write used files and libraries }
  437. WriteResponseFile(true);
  438. { Create some replacements }
  439. InitStr:='-init FPC_LIB_START';
  440. FiniStr:='-fini FPC_LIB_EXIT';
  441. SoNameStr:='-soname '+SplitFileName(current_module.sharedlibfilename^);
  442. { Call linker }
  443. SplitBinCmd(Info.DllCmd[1],binstr,cmdstr);
  444. Replace(cmdstr,'$EXE',maybequoted(current_module.sharedlibfilename^));
  445. Replace(cmdstr,'$OPT',Info.ExtraOptions);
  446. Replace(cmdstr,'$RES',maybequoted(outputexedir+Info.ResName));
  447. Replace(cmdstr,'$INIT',InitStr);
  448. Replace(cmdstr,'$FINI',FiniStr);
  449. Replace(cmdstr,'$SONAME',SoNameStr);
  450. success:=DoExec(FindUtil(utilsprefix+binstr),cmdstr,true,false);
  451. { Strip the library ? }
  452. if success and (cs_link_strip in aktglobalswitches) then
  453. begin
  454. SplitBinCmd(Info.DllCmd[2],binstr,cmdstr);
  455. Replace(cmdstr,'$EXE',maybequoted(current_module.sharedlibfilename^));
  456. success:=DoExec(FindUtil(utilsprefix+binstr),cmdstr,true,false);
  457. end;
  458. { Remove ReponseFile }
  459. if (success) and not(cs_link_extern in aktglobalswitches) then
  460. RemoveFile(outputexedir+Info.ResName);
  461. MakeSharedLibrary:=success; { otherwise a recursive call to link method }
  462. end;
  463. {*****************************************************************************
  464. Initialize
  465. *****************************************************************************}
  466. initialization
  467. {$ifdef i386}
  468. RegisterExternalLinker(system_i386_linux_info,TLinkerLinux);
  469. RegisterImport(system_i386_linux,timportliblinux);
  470. RegisterExport(system_i386_linux,texportliblinux);
  471. RegisterTarget(system_i386_linux_info);
  472. {$endif i386}
  473. {$ifdef m68k}
  474. RegisterExternalLinker(system_m68k_linux_info,TLinkerLinux);
  475. RegisterImport(system_m68k_linux,timportliblinux);
  476. RegisterExport(system_m68k_linux,texportliblinux);
  477. RegisterTarget(system_m68k_linux_info);
  478. {$endif m68k}
  479. {$ifdef powerpc}
  480. RegisterExternalLinker(system_powerpc_linux_info,TLinkerLinux);
  481. RegisterImport(system_powerpc_linux,timportliblinux);
  482. RegisterExport(system_powerpc_linux,texportliblinux);
  483. RegisterTarget(system_powerpc_linux_info);
  484. {$endif powerpc}
  485. {$ifdef alpha}
  486. RegisterExternalLinker(system_alpha_linux_info,TLinkerLinux);
  487. RegisterImport(system_alpha_linux,timportliblinux);
  488. RegisterExport(system_alpha_linux,texportliblinux);
  489. RegisterTarget(system_alpha_linux_info);
  490. {$endif alpha}
  491. {$ifdef x86_64}
  492. RegisterExternalLinker(system_x86_64_linux_info,TLinkerLinux);
  493. RegisterImport(system_x86_64_linux,timportliblinux);
  494. RegisterExport(system_x86_64_linux,texportliblinux);
  495. RegisterTarget(system_x86_64_linux_info);
  496. {$endif x86_64}
  497. {$ifdef SPARC}
  498. RegisterExternalLinker(system_sparc_linux_info,TLinkerLinux);
  499. RegisterImport(system_SPARC_linux,timportliblinux);
  500. RegisterExport(system_SPARC_linux,texportliblinux);
  501. RegisterTarget(system_SPARC_linux_info);
  502. {$endif SPARC}
  503. {$ifdef ARM}
  504. RegisterExternalLinker(system_arm_linux_info,TLinkerLinux);
  505. RegisterImport(system_arm_linux,timportliblinux);
  506. RegisterExport(system_arm_linux,texportliblinux);
  507. RegisterTarget(system_arm_linux_info);
  508. {$endif ARM}
  509. end.
  510. {
  511. $Log$
  512. Revision 1.32 2004-12-22 16:32:46 peter
  513. * maybequoted() added
  514. Revision 1.31 2004/12/19 14:03:16 florian
  515. * dyn. linker path fixed for x86_64
  516. Revision 1.30 2004/11/17 22:22:12 peter
  517. mangledname setting moved to place after the complete proc declaration is read
  518. import generation moved to place where body is also parsed (still gives problems with win32)
  519. Revision 1.29 2004/11/08 22:09:59 peter
  520. * tvarsym splitted
  521. Revision 1.28 2004/11/05 12:27:27 florian
  522. * fixed dyn. linker handling
  523. Revision 1.27 2004/11/05 11:04:23 florian
  524. * path of dyn. linker on arm for linux fixed
  525. Revision 1.26 2004/10/24 13:36:26 peter
  526. * gc-sections added when section smartlinking is used
  527. Revision 1.25 2004/10/14 18:16:17 mazen
  528. * USE_SYSUTILS merged successfully : cycles with and without defines
  529. * Need to be optimized in performance
  530. Revision 1.24 2004/09/25 18:44:12 florian
  531. * fixed dyn. linker name for sparc
  532. Revision 1.23 2004/09/22 15:25:14 mazen
  533. * Fix error committing : previous version must be in branch USE_SYSUTILS
  534. Revision 1.21 2004/09/21 17:25:13 peter
  535. * paraloc branch merged
  536. Revision 1.20.4.1 2004/09/20 15:24:42 peter
  537. * remove gc-sections option until it really works
  538. Revision 1.20 2004/07/08 14:42:54 daniel
  539. * Uclibc detection
  540. Revision 1.19 2004/06/20 08:55:32 florian
  541. * logs truncated
  542. Revision 1.18 2004/06/16 20:07:11 florian
  543. * dwarf branch merged
  544. Revision 1.17.2.3 2004/05/10 21:28:35 peter
  545. * section_smartlink enabled for gas under linux
  546. Revision 1.17.2.2 2004/05/03 20:18:52 peter
  547. * fixes for tprintf
  548. Revision 1.17.2.1 2004/04/08 18:33:22 peter
  549. * rewrite of TAsmSection
  550. Revision 1.17 2004/03/06 20:35:20 florian
  551. * fixed arm compilation
  552. * cleaned up code generation for exported linux procedures
  553. }