t_linux.pas 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530
  1. {
  2. $Id$
  3. Copyright (c) 1998-2000 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. interface
  21. uses
  22. import,export,link;
  23. type
  24. pimportliblinux=^timportliblinux;
  25. timportliblinux=object(timportlib)
  26. procedure preparelib(const s:string);virtual;
  27. procedure importprocedure(const func,module:string;index:longint;const name:string);virtual;
  28. procedure importvariable(const varname,module:string;const name:string);virtual;
  29. procedure generatelib;virtual;
  30. end;
  31. pexportliblinux=^texportliblinux;
  32. texportliblinux=object(texportlib)
  33. procedure preparelib(const s : string);virtual;
  34. procedure exportprocedure(hp : pexported_item);virtual;
  35. procedure exportvar(hp : pexported_item);virtual;
  36. procedure generatelib;virtual;
  37. end;
  38. plinkerlinux=^tlinkerlinux;
  39. tlinkerlinux=object(tlinker)
  40. private
  41. Glibc2,
  42. Glibc21 : boolean;
  43. Function WriteResponseFile(isdll:boolean) : Boolean;
  44. public
  45. constructor Init;
  46. procedure SetDefaultInfo;virtual;
  47. function MakeExecutable:boolean;virtual;
  48. function MakeSharedLibrary:boolean;virtual;
  49. end;
  50. implementation
  51. uses
  52. verbose,strings,cobjects,systems,globtype,globals,
  53. symconst,script,
  54. files,aasm,cpuasm,cpubase,symtable{$IFDEF NEWST},symbols{$ENDIF NEWST};
  55. {*****************************************************************************
  56. TIMPORTLIBLINUX
  57. *****************************************************************************}
  58. procedure timportliblinux.preparelib(const s : string);
  59. begin
  60. end;
  61. procedure timportliblinux.importprocedure(const func,module : string;index : longint;const name : string);
  62. begin
  63. { insert sharedlibrary }
  64. {$IFDEF NEWST}
  65. current_module^.linkothersharedlibs.
  66. insert(new(Plinkitem,init(SplitName(module),link_allways)));
  67. { do nothing with the procedure, only set the mangledname }
  68. if name<>'' then
  69. aktprocdef^.setmangledname(name)
  70. else
  71. message(parser_e_empty_import_name);
  72. {$ELSE}
  73. current_module^.linkothersharedlibs.
  74. insert(SplitName(module),link_allways);
  75. { do nothing with the procedure, only set the mangledname }
  76. if name<>'' then
  77. aktprocsym^.definition^.setmangledname(name)
  78. else
  79. message(parser_e_empty_import_name);
  80. {$ENDIF NEWST}
  81. end;
  82. procedure timportliblinux.importvariable(const varname,module:string;const name:string);
  83. begin
  84. { insert sharedlibrary }
  85. {$IFDEF NEWST}
  86. current_module^.linkothersharedlibs.
  87. insert(new(Plinkitem,init(SplitName(module),link_allways)));
  88. {$ELSE}
  89. current_module^.linkothersharedlibs.
  90. insert(SplitName(module),link_allways);
  91. {$ENDIF NEWST}
  92. { reset the mangledname and turn off the dll_var option }
  93. aktvarsym^.setmangledname(name);
  94. {$IFDEF NEWST}
  95. exclude(aktvarsym^.properties,vo_is_dll_var);
  96. {$ELSE}
  97. {$ifdef INCLUDEOK}
  98. exclude(aktvarsym^.varoptions,vo_is_dll_var);
  99. {$else}
  100. aktvarsym^.varoptions:=aktvarsym^.varoptions-[vo_is_dll_var];
  101. {$endif}
  102. {$ENDIF NEWST}
  103. end;
  104. procedure timportliblinux.generatelib;
  105. begin
  106. end;
  107. {*****************************************************************************
  108. TEXPORTLIBLINUX
  109. *****************************************************************************}
  110. procedure texportliblinux.preparelib(const s:string);
  111. begin
  112. end;
  113. procedure texportliblinux.exportprocedure(hp : pexported_item);
  114. var
  115. hp2 : pexported_item;
  116. begin
  117. { first test the index value }
  118. if (hp^.options and eo_index)<>0 then
  119. begin
  120. Comment(V_Error,'can''t export with index under linux');
  121. exit;
  122. end;
  123. { use pascal name is none specified }
  124. if (hp^.options and eo_name)=0 then
  125. begin
  126. hp^.name:=stringdup(hp^.sym^.name);
  127. hp^.options:=hp^.options or eo_name;
  128. end;
  129. { now place in correct order }
  130. hp2:=pexported_item(current_module^._exports^.first);
  131. while assigned(hp2) and
  132. (hp^.name^>hp2^.name^) do
  133. hp2:=pexported_item(hp2^.next);
  134. { insert hp there !! }
  135. if assigned(hp2) and (hp2^.name^=hp^.name^) then
  136. begin
  137. { this is not allowed !! }
  138. Message1(parser_e_export_name_double,hp^.name^);
  139. exit;
  140. end;
  141. if hp2=pexported_item(current_module^._exports^.first) then
  142. current_module^._exports^.insert(hp)
  143. else if assigned(hp2) then
  144. begin
  145. hp^.next:=hp2;
  146. hp^.previous:=hp2^.previous;
  147. if assigned(hp2^.previous) then
  148. hp2^.previous^.next:=hp;
  149. hp2^.previous:=hp;
  150. end
  151. else
  152. current_module^._exports^.concat(hp);
  153. end;
  154. procedure texportliblinux.exportvar(hp : pexported_item);
  155. begin
  156. hp^.is_var:=true;
  157. exportprocedure(hp);
  158. end;
  159. procedure texportliblinux.generatelib;
  160. var
  161. hp2 : pexported_item;
  162. begin
  163. hp2:=pexported_item(current_module^._exports^.first);
  164. while assigned(hp2) do
  165. begin
  166. if not hp2^.is_var then
  167. begin
  168. {$ifdef i386}
  169. { place jump in codesegment }
  170. codesegment^.concat(new(pai_align,init_op(4,$90)));
  171. codesegment^.concat(new(pai_symbol,initname_global(hp2^.name^,0)));
  172. codesegment^.concat(new(paicpu,op_sym(A_JMP,S_NO,newasmsymbol(hp2^.sym^.mangledname))));
  173. codesegment^.concat(new(pai_symbol_end,initname(hp2^.name^)));
  174. {$endif i386}
  175. end
  176. else
  177. Comment(V_Error,'Exporting of variables is not supported under linux');
  178. hp2:=pexported_item(hp2^.next);
  179. end;
  180. end;
  181. {*****************************************************************************
  182. TLINKERLINUX
  183. *****************************************************************************}
  184. Constructor TLinkerLinux.Init;
  185. begin
  186. Inherited Init;
  187. LibrarySearchPath.AddPath('/lib;/usr/lib;/usr/X11R6/lib',true);
  188. end;
  189. procedure TLinkerLinux.SetDefaultInfo;
  190. {
  191. This will also detect which libc version will be used
  192. }
  193. begin
  194. Glibc2:=false;
  195. Glibc21:=false;
  196. with Info do
  197. begin
  198. ExeCmd[1]:='ld $OPT $DYNLINK $STATIC $STRIP -L. -o $EXE $RES';
  199. DllCmd[1]:='ld $OPT -shared -L. -o $EXE $RES';
  200. DllCmd[2]:='strip --strip-unneeded $EXE';
  201. { first try glibc2 }
  202. DynamicLinker:='/lib/ld-linux.so.2';
  203. if FileExists(DynamicLinker) then
  204. begin
  205. Glibc2:=true;
  206. { Check for 2.0 files, else use the glibc 2.1 stub }
  207. if FileExists('/lib/ld-2.0.*') then
  208. Glibc21:=false
  209. else
  210. Glibc21:=true;
  211. end
  212. else
  213. DynamicLinker:='/lib/ld-linux.so.1';
  214. end;
  215. end;
  216. Function TLinkerLinux.WriteResponseFile(isdll:boolean) : Boolean;
  217. Var
  218. linkres : TLinkRes;
  219. i : longint;
  220. cprtobj,
  221. gprtobj,
  222. prtobj : string[80];
  223. {$IFDEF NEWST}
  224. HPath : PStringItem;
  225. {$ELSE}
  226. HPath : PStringQueueItem;
  227. {$ENDIF NEWST}
  228. s : string;
  229. found,
  230. linkdynamic,
  231. linklibc : boolean;
  232. begin
  233. WriteResponseFile:=False;
  234. { set special options for some targets }
  235. linkdynamic:=not(SharedLibFiles.empty);
  236. linklibc:=SharedLibFiles.Find('c');
  237. prtobj:='prt0';
  238. cprtobj:='cprt0';
  239. gprtobj:='gprt0';
  240. if glibc21 then
  241. begin
  242. cprtobj:='cprt21';
  243. gprtobj:='gprt21';
  244. end;
  245. if cs_profile in aktmoduleswitches then
  246. begin
  247. prtobj:=gprtobj;
  248. if not glibc2 then
  249. AddSharedLibrary('gmon');
  250. AddSharedLibrary('c');
  251. linklibc:=true;
  252. end
  253. else
  254. begin
  255. if linklibc then
  256. prtobj:=cprtobj;
  257. end;
  258. { Open link.res file }
  259. LinkRes.Init(outputexedir+Info.ResName);
  260. { Write path to search libraries }
  261. HPath:=current_module^.locallibrarysearchpath.First;
  262. while assigned(HPath) do
  263. begin
  264. LinkRes.Add('SEARCH_DIR('+HPath^.Data^+')');
  265. HPath:=HPath^.Next;
  266. end;
  267. HPath:=LibrarySearchPath.First;
  268. while assigned(HPath) do
  269. begin
  270. LinkRes.Add('SEARCH_DIR('+HPath^.Data^+')');
  271. HPath:=HPath^.Next;
  272. end;
  273. LinkRes.Add('INPUT(');
  274. { add objectfiles, start with prt0 always }
  275. if prtobj<>'' then
  276. LinkRes.AddFileName(FindObjectFile(prtobj));
  277. { try to add crti and crtbegin if linking to C }
  278. if linklibc then
  279. begin
  280. s:=librarysearchpath.FindFile('crtbegin.o',found)+'crtbegin.o';
  281. if found then
  282. LinkRes.AddFileName(s);
  283. s:=librarysearchpath.FindFile('crti.o',found)+'crti.o';
  284. if found then
  285. LinkRes.AddFileName(s);
  286. end;
  287. { main objectfiles }
  288. while not ObjectFiles.Empty do
  289. begin
  290. s:=ObjectFiles.Get;
  291. if s<>'' then
  292. LinkRes.AddFileName(s);
  293. end;
  294. { objects which must be at the end }
  295. if linklibc then
  296. begin
  297. s:=librarysearchpath.FindFile('crtend.o',found)+'crtend.o';
  298. if found then
  299. LinkRes.AddFileName(s);
  300. s:=librarysearchpath.FindFile('crtn.o',found)+'crtn.o';
  301. if found then
  302. LinkRes.AddFileName(s);
  303. end;
  304. LinkRes.Add(')');
  305. { Write staticlibraries }
  306. if not StaticLibFiles.Empty then
  307. begin
  308. LinkRes.Add('GROUP(');
  309. While not StaticLibFiles.Empty do
  310. begin
  311. S:=StaticLibFiles.Get;
  312. LinkRes.AddFileName(s)
  313. end;
  314. LinkRes.Add(')');
  315. end;
  316. { Write sharedlibraries like -l<lib>, also add the needed dynamic linker
  317. here to be sure that it gets linked this is needed for glibc2 systems (PFV) }
  318. if not SharedLibFiles.Empty then
  319. begin
  320. LinkRes.Add('INPUT(');
  321. While not SharedLibFiles.Empty do
  322. begin
  323. S:=SharedLibFiles.Get;
  324. if s<>'c' then
  325. begin
  326. i:=Pos(target_os.sharedlibext,S);
  327. if i>0 then
  328. Delete(S,i,255);
  329. LinkRes.Add('-l'+s);
  330. end
  331. else
  332. begin
  333. linklibc:=true;
  334. linkdynamic:=false; { libc will include the ld-linux for us }
  335. end;
  336. end;
  337. { be sure that libc is the last lib }
  338. if linklibc then
  339. LinkRes.Add('-lc');
  340. { when we have -static for the linker the we also need libgcc }
  341. if (cs_link_staticflag in aktglobalswitches) then
  342. LinkRes.Add('-lgcc');
  343. if linkdynamic and (Info.DynamicLinker<>'') then
  344. LinkRes.AddFileName(Info.DynamicLinker);
  345. LinkRes.Add(')');
  346. end;
  347. { Write and Close response }
  348. linkres.writetodisk;
  349. linkres.done;
  350. WriteResponseFile:=True;
  351. end;
  352. function TLinkerLinux.MakeExecutable:boolean;
  353. var
  354. binstr,
  355. cmdstr : string;
  356. success : boolean;
  357. DynLinkStr : string[60];
  358. StaticStr,
  359. StripStr : string[40];
  360. begin
  361. if not(cs_link_extern in aktglobalswitches) then
  362. Message1(exec_i_linking,current_module^.exefilename^);
  363. { Create some replacements }
  364. StaticStr:='';
  365. StripStr:='';
  366. DynLinkStr:='';
  367. if (cs_link_staticflag in aktglobalswitches) then
  368. StaticStr:='-static';
  369. if (cs_link_strip in aktglobalswitches) then
  370. StripStr:='-s';
  371. If (cs_profile in aktmoduleswitches) or
  372. ((Info.DynamicLinker<>'') and (not SharedLibFiles.Empty)) then
  373. DynLinkStr:='-dynamic-linker='+Info.DynamicLinker;
  374. { Write used files and libraries }
  375. WriteResponseFile(false);
  376. { Call linker }
  377. SplitBinCmd(Info.ExeCmd[1],binstr,cmdstr);
  378. Replace(cmdstr,'$EXE',current_module^.exefilename^);
  379. Replace(cmdstr,'$OPT',Info.ExtraOptions);
  380. Replace(cmdstr,'$RES',outputexedir+Info.ResName);
  381. Replace(cmdstr,'$STATIC',StaticStr);
  382. Replace(cmdstr,'$STRIP',StripStr);
  383. Replace(cmdstr,'$DYNLINK',DynLinkStr);
  384. success:=DoExec(FindUtil(BinStr),CmdStr,true,false);
  385. { Remove ReponseFile }
  386. if (success) and not(cs_link_extern in aktglobalswitches) then
  387. RemoveFile(outputexedir+Info.ResName);
  388. MakeExecutable:=success; { otherwise a recursive call to link method }
  389. end;
  390. Function TLinkerLinux.MakeSharedLibrary:boolean;
  391. var
  392. binstr,
  393. cmdstr : string;
  394. success : boolean;
  395. begin
  396. MakeSharedLibrary:=false;
  397. if not(cs_link_extern in aktglobalswitches) then
  398. Message1(exec_i_linking,current_module^.sharedlibfilename^);
  399. { Write used files and libraries }
  400. WriteResponseFile(true);
  401. { Call linker }
  402. SplitBinCmd(Info.DllCmd[1],binstr,cmdstr);
  403. Replace(cmdstr,'$EXE',current_module^.sharedlibfilename^);
  404. Replace(cmdstr,'$OPT',Info.ExtraOptions);
  405. Replace(cmdstr,'$RES',outputexedir+Info.ResName);
  406. success:=DoExec(FindUtil(binstr),cmdstr,true,false);
  407. { Strip the library ? }
  408. if success and (cs_link_strip in aktglobalswitches) then
  409. begin
  410. SplitBinCmd(Info.DllCmd[2],binstr,cmdstr);
  411. Replace(cmdstr,'$EXE',current_module^.sharedlibfilename^);
  412. success:=DoExec(FindUtil(binstr),cmdstr,true,false);
  413. end;
  414. { Remove ReponseFile }
  415. if (success) and not(cs_link_extern in aktglobalswitches) then
  416. RemoveFile(outputexedir+Info.ResName);
  417. MakeSharedLibrary:=success; { otherwise a recursive call to link method }
  418. end;
  419. end.
  420. {
  421. $Log$
  422. Revision 1.14 2000-03-21 21:36:52 peter
  423. * only include crtbegin when linking to libc
  424. Revision 1.13 2000/03/12 08:24:03 daniel
  425. * Modification for new symtable
  426. Revision 1.12 2000/03/02 13:12:37 daniel
  427. * Removed a comment to fix gtk.
  428. Revision 1.11 2000/02/28 17:23:57 daniel
  429. * Current work of symtable integration committed. The symtable can be
  430. activated by defining 'newst', but doesn't compile yet. Changes in type
  431. checking and oop are completed. What is left is to write a new
  432. symtablestack and adapt the parser to use it.
  433. Revision 1.10 2000/02/27 14:46:04 peter
  434. * check for ld-so.2.0.* then no glibc21 is used, else glibc21 is used
  435. Revision 1.9 2000/02/09 10:35:48 peter
  436. * -Xt option to link staticly against c libs
  437. Revision 1.8 2000/01/11 09:52:07 peter
  438. * fixed placing of .sl directories
  439. * use -b again for base-file selection
  440. * fixed group writing for linux with smartlinking
  441. Revision 1.7 2000/01/09 00:55:51 pierre
  442. * GROUP of smartlink units put before the C libraries
  443. to allow for smartlinking code that uses C code.
  444. Revision 1.6 2000/01/07 01:14:42 peter
  445. * updated copyright to 2000
  446. Revision 1.5 1999/11/16 23:39:04 peter
  447. * use outputexedir for link.res location
  448. Revision 1.4 1999/11/12 11:03:50 peter
  449. * searchpaths changed to stringqueue object
  450. Revision 1.3 1999/11/05 13:15:00 florian
  451. * some fixes to get the new cg compiling again
  452. Revision 1.2 1999/11/04 10:55:31 peter
  453. * TSearchPathString for the string type of the searchpaths, which is
  454. ansistring under FPC/Delphi
  455. Revision 1.1 1999/10/21 14:29:38 peter
  456. * redesigned linker object
  457. + library support for linux (only procedures can be exported)
  458. }