t_linux.pas 14 KB

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