t_linux.pas 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522
  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, they are normally not required, but
  278. adding can sometimes be usefull }
  279. s:=librarysearchpath.FindFile('crtbegin.o',found)+'crtbegin.o';
  280. if found then
  281. LinkRes.AddFileName(s);
  282. s:=librarysearchpath.FindFile('crti.o',found)+'crti.o';
  283. if found then
  284. LinkRes.AddFileName(s);
  285. { main objectfiles }
  286. while not ObjectFiles.Empty do
  287. begin
  288. s:=ObjectFiles.Get;
  289. if s<>'' then
  290. LinkRes.AddFileName(s);
  291. end;
  292. { objects which must be at the end }
  293. s:=librarysearchpath.FindFile('crtend.o',found)+'crtend.o';
  294. if found then
  295. LinkRes.AddFileName(s);
  296. s:=librarysearchpath.FindFile('crtn.o',found)+'crtn.o';
  297. if found then
  298. LinkRes.AddFileName(s);
  299. LinkRes.Add(')');
  300. { Write staticlibraries }
  301. if not StaticLibFiles.Empty then
  302. begin
  303. LinkRes.Add('GROUP(');
  304. While not StaticLibFiles.Empty do
  305. begin
  306. S:=StaticLibFiles.Get;
  307. LinkRes.AddFileName(s)
  308. end;
  309. LinkRes.Add(')');
  310. end;
  311. { Write sharedlibraries like -l<lib>, also add the needed dynamic linker
  312. here to be sure that it gets linked this is needed for glibc2 systems (PFV) }
  313. if not SharedLibFiles.Empty then
  314. begin
  315. LinkRes.Add('INPUT(');
  316. While not SharedLibFiles.Empty do
  317. begin
  318. S:=SharedLibFiles.Get;
  319. if s<>'c' then
  320. begin
  321. i:=Pos(target_os.sharedlibext,S);
  322. if i>0 then
  323. Delete(S,i,255);
  324. LinkRes.Add('-l'+s);
  325. end
  326. else
  327. begin
  328. linklibc:=true;
  329. linkdynamic:=false; { libc will include the ld-linux for us }
  330. end;
  331. end;
  332. { be sure that libc is the last lib }
  333. if linklibc then
  334. LinkRes.Add('-lc');
  335. { when we have -static for the linker the we also need libgcc }
  336. if (cs_link_staticflag in aktglobalswitches) then
  337. LinkRes.Add('-lgcc');
  338. if linkdynamic and (Info.DynamicLinker<>'') then
  339. LinkRes.AddFileName(Info.DynamicLinker);
  340. LinkRes.Add(')');
  341. end;
  342. { Write and Close response }
  343. linkres.writetodisk;
  344. linkres.done;
  345. WriteResponseFile:=True;
  346. end;
  347. function TLinkerLinux.MakeExecutable:boolean;
  348. var
  349. binstr,
  350. cmdstr : string;
  351. success : boolean;
  352. DynLinkStr : string[60];
  353. StaticStr,
  354. StripStr : string[40];
  355. begin
  356. if not(cs_link_extern in aktglobalswitches) then
  357. Message1(exec_i_linking,current_module^.exefilename^);
  358. { Create some replacements }
  359. StaticStr:='';
  360. StripStr:='';
  361. DynLinkStr:='';
  362. if (cs_link_staticflag in aktglobalswitches) then
  363. StaticStr:='-static';
  364. if (cs_link_strip in aktglobalswitches) then
  365. StripStr:='-s';
  366. If (cs_profile in aktmoduleswitches) or
  367. ((Info.DynamicLinker<>'') and (not SharedLibFiles.Empty)) then
  368. DynLinkStr:='-dynamic-linker='+Info.DynamicLinker;
  369. { Write used files and libraries }
  370. WriteResponseFile(false);
  371. { Call linker }
  372. SplitBinCmd(Info.ExeCmd[1],binstr,cmdstr);
  373. Replace(cmdstr,'$EXE',current_module^.exefilename^);
  374. Replace(cmdstr,'$OPT',Info.ExtraOptions);
  375. Replace(cmdstr,'$RES',outputexedir+Info.ResName);
  376. Replace(cmdstr,'$STATIC',StaticStr);
  377. Replace(cmdstr,'$STRIP',StripStr);
  378. Replace(cmdstr,'$DYNLINK',DynLinkStr);
  379. success:=DoExec(FindUtil(BinStr),CmdStr,true,false);
  380. { Remove ReponseFile }
  381. if (success) and not(cs_link_extern in aktglobalswitches) then
  382. RemoveFile(outputexedir+Info.ResName);
  383. MakeExecutable:=success; { otherwise a recursive call to link method }
  384. end;
  385. Function TLinkerLinux.MakeSharedLibrary:boolean;
  386. var
  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. { Call linker }
  397. SplitBinCmd(Info.DllCmd[1],binstr,cmdstr);
  398. Replace(cmdstr,'$EXE',current_module^.sharedlibfilename^);
  399. Replace(cmdstr,'$OPT',Info.ExtraOptions);
  400. Replace(cmdstr,'$RES',outputexedir+Info.ResName);
  401. success:=DoExec(FindUtil(binstr),cmdstr,true,false);
  402. { Strip the library ? }
  403. if success and (cs_link_strip in aktglobalswitches) then
  404. begin
  405. SplitBinCmd(Info.DllCmd[2],binstr,cmdstr);
  406. Replace(cmdstr,'$EXE',current_module^.sharedlibfilename^);
  407. success:=DoExec(FindUtil(binstr),cmdstr,true,false);
  408. end;
  409. { Remove ReponseFile }
  410. if (success) and not(cs_link_extern in aktglobalswitches) then
  411. RemoveFile(outputexedir+Info.ResName);
  412. MakeSharedLibrary:=success; { otherwise a recursive call to link method }
  413. end;
  414. end.
  415. {
  416. $Log$
  417. Revision 1.13 2000-03-12 08:24:03 daniel
  418. * Modification for new symtable
  419. Revision 1.12 2000/03/02 13:12:37 daniel
  420. * Removed a comment to fix gtk.
  421. Revision 1.11 2000/02/28 17:23:57 daniel
  422. * Current work of symtable integration committed. The symtable can be
  423. activated by defining 'newst', but doesn't compile yet. Changes in type
  424. checking and oop are completed. What is left is to write a new
  425. symtablestack and adapt the parser to use it.
  426. Revision 1.10 2000/02/27 14:46:04 peter
  427. * check for ld-so.2.0.* then no glibc21 is used, else glibc21 is used
  428. Revision 1.9 2000/02/09 10:35:48 peter
  429. * -Xt option to link staticly against c libs
  430. Revision 1.8 2000/01/11 09:52:07 peter
  431. * fixed placing of .sl directories
  432. * use -b again for base-file selection
  433. * fixed group writing for linux with smartlinking
  434. Revision 1.7 2000/01/09 00:55:51 pierre
  435. * GROUP of smartlink units put before the C libraries
  436. to allow for smartlinking code that uses C code.
  437. Revision 1.6 2000/01/07 01:14:42 peter
  438. * updated copyright to 2000
  439. Revision 1.5 1999/11/16 23:39:04 peter
  440. * use outputexedir for link.res location
  441. Revision 1.4 1999/11/12 11:03:50 peter
  442. * searchpaths changed to stringqueue object
  443. Revision 1.3 1999/11/05 13:15:00 florian
  444. * some fixes to get the new cg compiling again
  445. Revision 1.2 1999/11/04 10:55:31 peter
  446. * TSearchPathString for the string type of the searchpaths, which is
  447. ansistring under FPC/Delphi
  448. Revision 1.1 1999/10/21 14:29:38 peter
  449. * redesigned linker object
  450. + library support for linux (only procedures can be exported)
  451. }