t_linux.pas 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606
  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. import,export,link;
  24. type
  25. timportliblinux=class(timportlib)
  26. procedure preparelib(const s:string);override;
  27. procedure importprocedure(const func,module:string;index:longint;const name:string);override;
  28. procedure importvariable(const varname,module:string;const name:string);override;
  29. procedure generatelib;override;
  30. end;
  31. texportliblinux=class(texportlib)
  32. procedure preparelib(const s : string);override;
  33. procedure exportprocedure(hp : texported_item);override;
  34. procedure exportvar(hp : texported_item);override;
  35. procedure generatelib;override;
  36. end;
  37. tlinkerlinux=class(texternallinker)
  38. private
  39. Glibc2,
  40. Glibc21 : boolean;
  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,symsym
  54. {$ifdef i386}
  55. ,aasmbase,aasmtai,aasmcpu,cpubase
  56. {$endif i386}
  57. ,i_linux
  58. ;
  59. {*****************************************************************************
  60. TIMPORTLIBLINUX
  61. *****************************************************************************}
  62. procedure timportliblinux.preparelib(const s : string);
  63. begin
  64. end;
  65. procedure timportliblinux.importprocedure(const func,module : string;index : longint;const name : string);
  66. begin
  67. { insert sharedlibrary }
  68. current_module.linkothersharedlibs.add(SplitName(module),link_allways);
  69. { do nothing with the procedure, only set the mangledname }
  70. if name<>'' then
  71. begin
  72. aktprocdef.setmangledname(name);
  73. aktprocdef.has_mangledname:=true;
  74. end
  75. else
  76. message(parser_e_empty_import_name);
  77. end;
  78. procedure timportliblinux.importvariable(const varname,module:string;const name:string);
  79. begin
  80. { insert sharedlibrary }
  81. current_module.linkothersharedlibs.add(SplitName(module),link_allways);
  82. { reset the mangledname and turn off the dll_var option }
  83. aktvarsym.set_mangledname(name);
  84. exclude(aktvarsym.varoptions,vo_is_dll_var);
  85. end;
  86. procedure timportliblinux.generatelib;
  87. begin
  88. end;
  89. {*****************************************************************************
  90. TEXPORTLIBLINUX
  91. *****************************************************************************}
  92. procedure texportliblinux.preparelib(const s:string);
  93. begin
  94. end;
  95. procedure texportliblinux.exportprocedure(hp : texported_item);
  96. var
  97. hp2 : texported_item;
  98. begin
  99. { first test the index value }
  100. if (hp.options and eo_index)<>0 then
  101. begin
  102. Message1(parser_e_no_export_with_index_for_target,'linux');
  103. exit;
  104. end;
  105. { now place in correct order }
  106. hp2:=texported_item(current_module._exports.first);
  107. while assigned(hp2) and
  108. (hp.name^>hp2.name^) do
  109. hp2:=texported_item(hp2.next);
  110. { insert hp there !! }
  111. if assigned(hp2) and (hp2.name^=hp.name^) then
  112. begin
  113. { this is not allowed !! }
  114. Message1(parser_e_export_name_double,hp.name^);
  115. exit;
  116. end;
  117. if hp2=texported_item(current_module._exports.first) then
  118. current_module._exports.concat(hp)
  119. else if assigned(hp2) then
  120. begin
  121. hp.next:=hp2;
  122. hp.previous:=hp2.previous;
  123. if assigned(hp2.previous) then
  124. hp2.previous.next:=hp;
  125. hp2.previous:=hp;
  126. end
  127. else
  128. current_module._exports.concat(hp);
  129. end;
  130. procedure texportliblinux.exportvar(hp : texported_item);
  131. begin
  132. hp.is_var:=true;
  133. exportprocedure(hp);
  134. end;
  135. procedure texportliblinux.generatelib;
  136. var
  137. hp2 : texported_item;
  138. begin
  139. hp2:=texported_item(current_module._exports.first);
  140. while assigned(hp2) do
  141. begin
  142. if (not hp2.is_var) and
  143. (hp2.sym.typ=procsym) then
  144. begin
  145. { the manglednames can already be the same when the procedure
  146. is declared with cdecl }
  147. if tprocsym(hp2.sym).first_procdef.mangledname<>hp2.name^ then
  148. begin
  149. {$ifdef i386}
  150. { place jump in codesegment }
  151. codesegment.concat(Tai_align.Create_op(4,$90));
  152. codeSegment.concat(Tai_symbol.Createname_global(hp2.name^,0));
  153. codeSegment.concat(Taicpu.Op_sym(A_JMP,S_NO,objectlibrary.newasmsymbol(tprocsym(hp2.sym).first_procdef.mangledname)));
  154. codeSegment.concat(Tai_symbol_end.Createname(hp2.name^));
  155. {$endif i386}
  156. end;
  157. end
  158. else
  159. Message1(parser_e_no_export_of_variables_for_target,'linux');
  160. hp2:=texported_item(hp2.next);
  161. end;
  162. end;
  163. {*****************************************************************************
  164. TLINKERLINUX
  165. *****************************************************************************}
  166. Constructor TLinkerLinux.Create;
  167. begin
  168. Inherited Create;
  169. LibrarySearchPath.AddPath('/lib;/usr/lib;/usr/X11R6/lib',true);
  170. end;
  171. procedure TLinkerLinux.SetDefaultInfo;
  172. {
  173. This will also detect which libc version will be used
  174. }
  175. begin
  176. Glibc2:=false;
  177. Glibc21:=false;
  178. with Info do
  179. begin
  180. ExeCmd[1]:='ld $OPT $DYNLINK $STATIC $STRIP -L. -o $EXE $RES';
  181. DllCmd[1]:='ld $OPT $INIT $FINI $SONAME -shared -L. -o $EXE $RES';
  182. DllCmd[2]:='strip --strip-unneeded $EXE';
  183. { first try glibc2 }
  184. DynamicLinker:='/lib/ld-linux.so.2';
  185. if FileExists(DynamicLinker) then
  186. begin
  187. Glibc2:=true;
  188. { Check for 2.0 files, else use the glibc 2.1 stub }
  189. if FileExists('/lib/ld-2.0.*') then
  190. Glibc21:=false
  191. else
  192. Glibc21:=true;
  193. end
  194. else
  195. DynamicLinker:='/lib/ld-linux.so.1';
  196. end;
  197. end;
  198. Function TLinkerLinux.WriteResponseFile(isdll:boolean) : Boolean;
  199. Var
  200. linkres : TLinkRes;
  201. i : longint;
  202. cprtobj,
  203. gprtobj,
  204. prtobj : string[80];
  205. HPath : TStringListItem;
  206. s,s1,s2 : string;
  207. found1,
  208. found2,
  209. linkdynamic,
  210. linklibc : boolean;
  211. begin
  212. WriteResponseFile:=False;
  213. { set special options for some targets }
  214. linkdynamic:=not(SharedLibFiles.empty);
  215. linklibc:=(SharedLibFiles.Find('c')<>nil);
  216. if isdll then
  217. begin
  218. prtobj:='dllprt0';
  219. cprtobj:='dllprt0';
  220. gprtobj:='dllprt0';
  221. end
  222. else
  223. begin
  224. prtobj:='prt0';
  225. cprtobj:='cprt0';
  226. gprtobj:='gprt0';
  227. if glibc21 then
  228. begin
  229. cprtobj:='cprt21';
  230. gprtobj:='gprt21';
  231. end;
  232. end;
  233. if cs_profile in aktmoduleswitches then
  234. begin
  235. prtobj:=gprtobj;
  236. if not glibc2 then
  237. AddSharedLibrary('gmon');
  238. AddSharedLibrary('c');
  239. linklibc:=true;
  240. end
  241. else
  242. begin
  243. if linklibc then
  244. prtobj:=cprtobj;
  245. end;
  246. { Open link.res file }
  247. LinkRes:=TLinkRes.Create(outputexedir+Info.ResName);
  248. { Write path to search libraries }
  249. HPath:=TStringListItem(current_module.locallibrarysearchpath.First);
  250. while assigned(HPath) do
  251. begin
  252. LinkRes.Add('SEARCH_DIR('+HPath.Str+')');
  253. HPath:=TStringListItem(HPath.Next);
  254. end;
  255. HPath:=TStringListItem(LibrarySearchPath.First);
  256. while assigned(HPath) do
  257. begin
  258. LinkRes.Add('SEARCH_DIR('+HPath.Str+')');
  259. HPath:=TStringListItem(HPath.Next);
  260. end;
  261. LinkRes.Add('INPUT(');
  262. { add objectfiles, start with prt0 always }
  263. if prtobj<>'' then
  264. LinkRes.AddFileName(FindObjectFile(prtobj,''));
  265. { try to add crti and crtbegin if linking to C }
  266. if linklibc then
  267. begin
  268. if librarysearchpath.FindFile('crtbegin.o',s) then
  269. LinkRes.AddFileName(s);
  270. if librarysearchpath.FindFile('crti.o',s) then
  271. LinkRes.AddFileName(s);
  272. end;
  273. { main objectfiles }
  274. while not ObjectFiles.Empty do
  275. begin
  276. s:=ObjectFiles.GetFirst;
  277. if s<>'' then
  278. LinkRes.AddFileName(s);
  279. end;
  280. LinkRes.Add(')');
  281. { Write staticlibraries }
  282. if not StaticLibFiles.Empty then
  283. begin
  284. LinkRes.Add('GROUP(');
  285. While not StaticLibFiles.Empty do
  286. begin
  287. S:=StaticLibFiles.GetFirst;
  288. LinkRes.AddFileName(s)
  289. end;
  290. LinkRes.Add(')');
  291. end;
  292. { Write sharedlibraries like -l<lib>, also add the needed dynamic linker
  293. here to be sure that it gets linked this is needed for glibc2 systems (PFV) }
  294. if not SharedLibFiles.Empty then
  295. begin
  296. LinkRes.Add('INPUT(');
  297. While not SharedLibFiles.Empty do
  298. begin
  299. S:=SharedLibFiles.GetFirst;
  300. if s<>'c' then
  301. begin
  302. i:=Pos(target_info.sharedlibext,S);
  303. if i>0 then
  304. Delete(S,i,255);
  305. LinkRes.Add('-l'+s);
  306. end
  307. else
  308. begin
  309. linklibc:=true;
  310. linkdynamic:=false; { libc will include the ld-linux for us }
  311. end;
  312. end;
  313. { be sure that libc is the last lib }
  314. if linklibc then
  315. LinkRes.Add('-lc');
  316. { when we have -static for the linker the we also need libgcc }
  317. if (cs_link_staticflag in aktglobalswitches) then
  318. LinkRes.Add('-lgcc');
  319. if linkdynamic and (Info.DynamicLinker<>'') then
  320. LinkRes.AddFileName(Info.DynamicLinker);
  321. LinkRes.Add(')');
  322. end;
  323. { objects which must be at the end }
  324. if linklibc then
  325. begin
  326. found1:=librarysearchpath.FindFile('crtend.o',s1);
  327. found2:=librarysearchpath.FindFile('crtn.o',s2);
  328. if found1 or found2 then
  329. begin
  330. LinkRes.Add('INPUT(');
  331. if found1 then
  332. LinkRes.AddFileName(s1);
  333. if found2 then
  334. LinkRes.AddFileName(s2);
  335. LinkRes.Add(')');
  336. end;
  337. end;
  338. { Write and Close response }
  339. linkres.writetodisk;
  340. linkres.Free;
  341. WriteResponseFile:=True;
  342. end;
  343. function TLinkerLinux.MakeExecutable:boolean;
  344. var
  345. binstr,
  346. cmdstr : string;
  347. success : boolean;
  348. DynLinkStr : string[60];
  349. StaticStr,
  350. StripStr : string[40];
  351. begin
  352. if not(cs_link_extern in aktglobalswitches) then
  353. Message1(exec_i_linking,current_module.exefilename^);
  354. { Create some replacements }
  355. StaticStr:='';
  356. StripStr:='';
  357. DynLinkStr:='';
  358. if (cs_link_staticflag in aktglobalswitches) then
  359. StaticStr:='-static';
  360. if (cs_link_strip in aktglobalswitches) then
  361. StripStr:='-s';
  362. If (cs_profile in aktmoduleswitches) or
  363. ((Info.DynamicLinker<>'') and (not SharedLibFiles.Empty)) then
  364. DynLinkStr:='-dynamic-linker='+Info.DynamicLinker;
  365. { Write used files and libraries }
  366. WriteResponseFile(false);
  367. { Call linker }
  368. SplitBinCmd(Info.ExeCmd[1],binstr,cmdstr);
  369. Replace(cmdstr,'$EXE',current_module.exefilename^);
  370. Replace(cmdstr,'$OPT',Info.ExtraOptions);
  371. Replace(cmdstr,'$RES',outputexedir+Info.ResName);
  372. Replace(cmdstr,'$STATIC',StaticStr);
  373. Replace(cmdstr,'$STRIP',StripStr);
  374. Replace(cmdstr,'$DYNLINK',DynLinkStr);
  375. success:=DoExec(FindUtil(BinStr),CmdStr,true,false);
  376. { Remove ReponseFile }
  377. if (success) and not(cs_link_extern in aktglobalswitches) then
  378. RemoveFile(outputexedir+Info.ResName);
  379. MakeExecutable:=success; { otherwise a recursive call to link method }
  380. end;
  381. Function TLinkerLinux.MakeSharedLibrary:boolean;
  382. var
  383. InitStr,
  384. FiniStr,
  385. SoNameStr : string[80];
  386. binstr,
  387. cmdstr : string;
  388. success : boolean;
  389. begin
  390. MakeSharedLibrary:=false;
  391. if not(cs_link_extern in aktglobalswitches) then
  392. Message1(exec_i_linking,current_module.sharedlibfilename^);
  393. { Write used files and libraries }
  394. WriteResponseFile(true);
  395. { Create some replacements }
  396. InitStr:='-init FPC_LIB_START';
  397. FiniStr:='-fini FPC_LIB_EXIT';
  398. SoNameStr:='-soname '+SplitFileName(current_module.sharedlibfilename^);
  399. { Call linker }
  400. SplitBinCmd(Info.DllCmd[1],binstr,cmdstr);
  401. Replace(cmdstr,'$EXE',current_module.sharedlibfilename^);
  402. Replace(cmdstr,'$OPT',Info.ExtraOptions);
  403. Replace(cmdstr,'$RES',outputexedir+Info.ResName);
  404. Replace(cmdstr,'$INIT',InitStr);
  405. Replace(cmdstr,'$FINI',FiniStr);
  406. Replace(cmdstr,'$SONAME',SoNameStr);
  407. success:=DoExec(FindUtil(binstr),cmdstr,true,false);
  408. { Strip the library ? }
  409. if success and (cs_link_strip in aktglobalswitches) then
  410. begin
  411. SplitBinCmd(Info.DllCmd[2],binstr,cmdstr);
  412. Replace(cmdstr,'$EXE',current_module.sharedlibfilename^);
  413. success:=DoExec(FindUtil(binstr),cmdstr,true,false);
  414. end;
  415. { Remove ReponseFile }
  416. if (success) and not(cs_link_extern in aktglobalswitches) then
  417. RemoveFile(outputexedir+Info.ResName);
  418. MakeSharedLibrary:=success; { otherwise a recursive call to link method }
  419. end;
  420. {*****************************************************************************
  421. Initialize
  422. *****************************************************************************}
  423. initialization
  424. {$ifdef i386}
  425. RegisterExternalLinker(system_i386_linux_info,TLinkerLinux);
  426. RegisterImport(system_i386_linux,timportliblinux);
  427. RegisterExport(system_i386_linux,texportliblinux);
  428. RegisterTarget(system_i386_linux_info);
  429. {$endif i386}
  430. {$ifdef m68k}
  431. RegisterExternalLinker(system_m68k_linux_info,TLinkerLinux);
  432. RegisterImport(system_m68k_linux,timportliblinux);
  433. RegisterExport(system_m68k_linux,texportliblinux);
  434. RegisterTarget(system_m68k_linux_info);
  435. {$endif m68k}
  436. {$ifdef powerpc}
  437. RegisterExternalLinker(system_powerpc_linux_info,TLinkerLinux);
  438. RegisterImport(system_powerpc_linux,timportliblinux);
  439. RegisterExport(system_powerpc_linux,texportliblinux);
  440. RegisterTarget(system_powerpc_linux_info);
  441. {$endif powerpc}
  442. {$ifdef alpha}
  443. RegisterExternalLinker(system_alpha_linux_info,TLinkerLinux);
  444. RegisterImport(system_alpha_linux,timportliblinux);
  445. RegisterExport(system_alpha_linux,texportliblinux);
  446. RegisterTarget(system_alpha_linux_info);
  447. {$endif alpha}
  448. {$ifdef x86_64}
  449. RegisterExternalLinker(system_x86_64_linux_info,TLinkerLinux);
  450. RegisterImport(system_x86_64_linux,timportliblinux);
  451. RegisterExport(system_x86_64_linux,texportliblinux);
  452. RegisterTarget(system_x86_64_linux_info);
  453. {$endif x86_64}
  454. {$ifdef SPARC}
  455. RegisterExternalLinker(system_sparc_linux_info,TLinkerLinux);
  456. RegisterImport(system_SPARC_linux,timportliblinux);
  457. RegisterExport(system_SPARC_linux,texportliblinux);
  458. RegisterTarget(system_SPARC_linux_info);
  459. {$endif SPARC}
  460. end.
  461. {
  462. $Log$
  463. Revision 1.1 2002-09-06 15:03:51 carl
  464. * moved files to systems directory
  465. Revision 1.33 2002/09/03 16:26:28 daniel
  466. * Make Tprocdef.defs protected
  467. Revision 1.32 2002/08/12 15:08:44 carl
  468. + stab register indexes for powerpc (moved from gdb to cpubase)
  469. + tprocessor enumeration moved to cpuinfo
  470. + linker in target_info is now a class
  471. * many many updates for m68k (will soon start to compile)
  472. - removed some ifdef or correct them for correct cpu
  473. Revision 1.31 2002/08/11 14:32:32 peter
  474. * renamed current_library to objectlibrary
  475. Revision 1.30 2002/08/11 13:24:19 peter
  476. * saving of asmsymbols in ppu supported
  477. * asmsymbollist global is removed and moved into a new class
  478. tasmlibrarydata that will hold the info of a .a file which
  479. corresponds with a single module. Added librarydata to tmodule
  480. to keep the library info stored for the module. In the future the
  481. objectfiles will also be stored to the tasmlibrarydata class
  482. * all getlabel/newasmsymbol and friends are moved to the new class
  483. Revision 1.29 2002/07/26 21:15:46 florian
  484. * rewrote the system handling
  485. Revision 1.28 2002/07/04 20:43:02 florian
  486. * first x86-64 patches
  487. Revision 1.27 2002/07/01 18:46:35 peter
  488. * internal linker
  489. * reorganized aasm layer
  490. Revision 1.26 2002/05/18 13:34:26 peter
  491. * readded missing revisions
  492. Revision 1.25 2002/05/16 19:46:53 carl
  493. + defines.inc -> fpcdefs.inc to avoid conflicts if compiling by hand
  494. + try to fix temp allocation (still in ifdef)
  495. + generic constructor calls
  496. + start of tassembler / tmodulebase class cleanup
  497. Revision 1.22 2002/05/06 19:46:36 carl
  498. + added more patches from Mazen for SPARC port
  499. Revision 1.21 2002/04/22 18:19:22 carl
  500. - remove use_bound_instruction field
  501. Revision 1.20 2002/04/20 21:43:18 carl
  502. * fix stack size for some targets
  503. + add offset to parameters from frame pointer info.
  504. - remove some unused stuff
  505. Revision 1.19 2002/04/19 15:46:05 peter
  506. * mangledname rewrite, tprocdef.mangledname is now created dynamicly
  507. in most cases and not written to the ppu
  508. * add mangeledname_prefix() routine to generate the prefix of
  509. manglednames depending on the current procedure, object and module
  510. * removed static procprefix since the mangledname is now build only
  511. on demand from tprocdef.mangledname
  512. Revision 1.18 2002/04/15 19:44:23 peter
  513. * fixed stackcheck that would be called recursively when a stack
  514. error was found
  515. * generic changeregsize(reg,size) for i386 register resizing
  516. * removed some more routines from cga unit
  517. * fixed returnvalue handling
  518. * fixed default stacksize of linux and go32v2, 8kb was a bit small :-)
  519. Revision 1.17 2002/04/15 19:16:57 carl
  520. - remove size_of_pointer field
  521. Revision 1.16 2002/01/29 21:27:34 peter
  522. * default alignment changed to 4 bytes for locals and static const,var
  523. Revision 1.15 2002/01/09 07:38:37 michael
  524. + Patch from Peter for library imports
  525. }