t_linux.pas 18 KB

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