t_linux.pas 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645
  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,symdef,
  24. import,export,link;
  25. type
  26. timportliblinux=class(timportlib)
  27. procedure preparelib(const s:string);override;
  28. procedure importprocedure(aprocdef:tprocdef;const module:string;index:longint;const name:string);override;
  29. procedure importvariable(vs:tglobalvarsym;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. libctype:(libc5,glibc2,glibc21,uclibc);
  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,dos
  54. ,aasmbase,aasmtai,aasmcpu,cpubase,cgobj
  55. ,i_linux
  56. ;
  57. {*****************************************************************************
  58. TIMPORTLIBLINUX
  59. *****************************************************************************}
  60. procedure timportliblinux.preparelib(const s : string);
  61. begin
  62. end;
  63. procedure timportliblinux.importprocedure(aprocdef:tprocdef;const module:string;index:longint;const name:string);
  64. begin
  65. { insert sharedlibrary }
  66. current_module.linkothersharedlibs.add(SplitName(module),link_allways);
  67. end;
  68. procedure timportliblinux.importvariable(vs:tglobalvarsym;const name,module:string);
  69. begin
  70. { insert sharedlibrary }
  71. current_module.linkothersharedlibs.add(SplitName(module),link_allways);
  72. { reset the mangledname and turn off the dll_var option }
  73. vs.set_mangledname(name);
  74. exclude(vs.varoptions,vo_is_dll_var);
  75. end;
  76. procedure timportliblinux.generatelib;
  77. begin
  78. end;
  79. {*****************************************************************************
  80. TEXPORTLIBLINUX
  81. *****************************************************************************}
  82. procedure texportliblinux.preparelib(const s:string);
  83. begin
  84. end;
  85. procedure texportliblinux.exportprocedure(hp : texported_item);
  86. var
  87. hp2 : texported_item;
  88. begin
  89. { first test the index value }
  90. if (hp.options and eo_index)<>0 then
  91. begin
  92. Message1(parser_e_no_export_with_index_for_target,'linux');
  93. exit;
  94. end;
  95. { now place in correct order }
  96. hp2:=texported_item(current_module._exports.first);
  97. while assigned(hp2) and
  98. (hp.name^>hp2.name^) do
  99. hp2:=texported_item(hp2.next);
  100. { insert hp there !! }
  101. if assigned(hp2) and (hp2.name^=hp.name^) then
  102. begin
  103. { this is not allowed !! }
  104. Message1(parser_e_export_name_double,hp.name^);
  105. exit;
  106. end;
  107. if hp2=texported_item(current_module._exports.first) then
  108. current_module._exports.concat(hp)
  109. else if assigned(hp2) then
  110. begin
  111. hp.next:=hp2;
  112. hp.previous:=hp2.previous;
  113. if assigned(hp2.previous) then
  114. hp2.previous.next:=hp;
  115. hp2.previous:=hp;
  116. end
  117. else
  118. current_module._exports.concat(hp);
  119. end;
  120. procedure texportliblinux.exportvar(hp : texported_item);
  121. begin
  122. hp.is_var:=true;
  123. exportprocedure(hp);
  124. end;
  125. procedure texportliblinux.generatelib;
  126. var
  127. hp2 : texported_item;
  128. begin
  129. new_section(codesegment,sec_code,'',0);
  130. hp2:=texported_item(current_module._exports.first);
  131. while assigned(hp2) do
  132. begin
  133. if (not hp2.is_var) and
  134. (hp2.sym.typ=procsym) then
  135. begin
  136. { the manglednames can already be the same when the procedure
  137. is declared with cdecl }
  138. if tprocsym(hp2.sym).first_procdef.mangledname<>hp2.name^ then
  139. begin
  140. { place jump in codesegment }
  141. codesegment.concat(tai_align.create(target_info.alignment.procalign));
  142. codeSegment.concat(Tai_symbol.Createname_global(hp2.name^,AT_FUNCTION,0));
  143. cg.a_jmp_name(codesegment,tprocsym(hp2.sym).first_procdef.mangledname);
  144. codeSegment.concat(Tai_symbol_end.Createname(hp2.name^));
  145. end;
  146. end
  147. else
  148. Message1(parser_e_no_export_of_variables_for_target,'linux');
  149. hp2:=texported_item(hp2.next);
  150. end;
  151. end;
  152. {*****************************************************************************
  153. TLINKERLINUX
  154. *****************************************************************************}
  155. Constructor TLinkerLinux.Create;
  156. begin
  157. Inherited Create;
  158. if not Dontlinkstdlibpath Then
  159. LibrarySearchPath.AddPath('/lib;/usr/lib;/usr/X11R6/lib',true);
  160. end;
  161. procedure TLinkerLinux.SetDefaultInfo;
  162. {
  163. This will also detect which libc version will be used
  164. }
  165. {$ifdef m68k}
  166. var
  167. St : SearchRec;
  168. {$endif m68k}
  169. begin
  170. with Info do
  171. begin
  172. ExeCmd[1]:='ld $OPT $DYNLINK $STATIC $GCSECTIONS $STRIP -L. -o $EXE $RES';
  173. DllCmd[1]:='ld $OPT $INIT $FINI $SONAME -shared -L. -o $EXE $RES';
  174. DllCmd[2]:='strip --strip-unneeded $EXE';
  175. {$ifdef m68k}
  176. libctype:=glibc2;
  177. FindFirst('/lib/ld*',AnyFile,st);
  178. while DosError=0 do
  179. begin
  180. if copy(st.name,1,5)='ld-2.' then
  181. begin
  182. DynamicLinker:='/lib/'+St.name;
  183. if st.name[6]<>'0' then
  184. libctype:=glibc21;
  185. break;
  186. end;
  187. FindNext(St);
  188. end;
  189. FindClose(St);
  190. {$endif m68k}
  191. {$ifdef i386}
  192. { first try glibc2 }
  193. DynamicLinker:='/lib/ld-linux.so.2';
  194. if FileExists(DynamicLinker) then
  195. { Check for 2.0 files, else use the glibc 2.1 stub }
  196. if FileExists('/lib/ld-2.0.*') then
  197. libctype:=glibc2
  198. else
  199. libctype:=glibc21
  200. else
  201. if fileexists('/lib/ld-uClibc.so.0') then
  202. begin
  203. libctype:=uclibc;
  204. dynamiclinker:='/lib/ld-uClibc.so.0';
  205. end
  206. else
  207. DynamicLinker:='/lib/ld-linux.so.1';
  208. {$endif i386}
  209. {$ifdef x86_64}
  210. DynamicLinker:='/lib64/ld-linux-x86-64.so.2';
  211. libctype:=glibc2;
  212. {$endif x86_64}
  213. {$ifdef sparc}
  214. DynamicLinker:='/lib/ld-linux.so.2';
  215. libctype:=glibc2;
  216. {$endif sparc}
  217. {$ifdef powerpc}
  218. DynamicLinker:='/lib/ld.so.1';
  219. libctype:=glibc2;
  220. {$endif powerpc}
  221. {$ifdef arm}
  222. DynamicLinker:='/lib/ld-linux.so.2';
  223. libctype:=glibc2;
  224. {$endif arm}
  225. end;
  226. end;
  227. Function TLinkerLinux.WriteResponseFile(isdll:boolean) : Boolean;
  228. Var
  229. linkres : TLinkRes;
  230. i : longint;
  231. cprtobj,
  232. gprtobj,
  233. prtobj : string[80];
  234. HPath : TStringListItem;
  235. s,s1,s2 : string;
  236. found1,
  237. found2,
  238. linklibc : boolean;
  239. begin
  240. WriteResponseFile:=False;
  241. { set special options for some targets }
  242. linklibc:=(SharedLibFiles.Find('c')<>nil);
  243. if isdll then
  244. begin
  245. prtobj:='dllprt0';
  246. cprtobj:='dllprt0';
  247. gprtobj:='dllprt0';
  248. end
  249. else
  250. begin
  251. prtobj:='prt0';
  252. case libctype of
  253. glibc21:
  254. begin
  255. cprtobj:='cprt21';
  256. gprtobj:='gprt21';
  257. end;
  258. uclibc:
  259. begin
  260. cprtobj:='ucprt0';
  261. gprtobj:='ugprt0';
  262. end
  263. else
  264. cprtobj:='cprt0';
  265. gprtobj:='gprt0';
  266. end;
  267. end;
  268. if cs_profile in aktmoduleswitches then
  269. begin
  270. prtobj:=gprtobj;
  271. if not(libctype in [glibc2,glibc21]) then
  272. AddSharedLibrary('gmon');
  273. AddSharedLibrary('c');
  274. linklibc:=true;
  275. end
  276. else
  277. begin
  278. if linklibc then
  279. prtobj:=cprtobj;
  280. end;
  281. { Open link.res file }
  282. LinkRes:=TLinkRes.Create(outputexedir+Info.ResName);
  283. { Write path to search libraries }
  284. HPath:=TStringListItem(current_module.locallibrarysearchpath.First);
  285. while assigned(HPath) do
  286. begin
  287. LinkRes.Add('SEARCH_DIR('+maybequoted(HPath.Str)+')');
  288. HPath:=TStringListItem(HPath.Next);
  289. end;
  290. HPath:=TStringListItem(LibrarySearchPath.First);
  291. while assigned(HPath) do
  292. begin
  293. LinkRes.Add('SEARCH_DIR('+maybequoted(HPath.Str)+')');
  294. HPath:=TStringListItem(HPath.Next);
  295. end;
  296. LinkRes.Add('INPUT(');
  297. { add objectfiles, start with prt0 always }
  298. if prtobj<>'' then
  299. LinkRes.AddFileName(maybequoted(FindObjectFile(prtobj,'',false)));
  300. { try to add crti and crtbegin if linking to C }
  301. if linklibc then
  302. begin
  303. if librarysearchpath.FindFile('crtbegin.o',s) then
  304. LinkRes.AddFileName(s);
  305. if librarysearchpath.FindFile('crti.o',s) then
  306. LinkRes.AddFileName(s);
  307. end;
  308. { main objectfiles }
  309. while not ObjectFiles.Empty do
  310. begin
  311. s:=ObjectFiles.GetFirst;
  312. if s<>'' then
  313. LinkRes.AddFileName(maybequoted(s));
  314. end;
  315. LinkRes.Add(')');
  316. { Write staticlibraries }
  317. if not StaticLibFiles.Empty then
  318. begin
  319. LinkRes.Add('GROUP(');
  320. While not StaticLibFiles.Empty do
  321. begin
  322. S:=StaticLibFiles.GetFirst;
  323. LinkRes.AddFileName(maybequoted(s))
  324. end;
  325. LinkRes.Add(')');
  326. end;
  327. { Write sharedlibraries like -l<lib>, also add the needed dynamic linker
  328. here to be sure that it gets linked this is needed for glibc2 systems (PFV) }
  329. if not SharedLibFiles.Empty then
  330. begin
  331. LinkRes.Add('INPUT(');
  332. While not SharedLibFiles.Empty do
  333. begin
  334. S:=SharedLibFiles.GetFirst;
  335. if s<>'c' then
  336. begin
  337. i:=Pos(target_info.sharedlibext,S);
  338. if i>0 then
  339. Delete(S,i,255);
  340. LinkRes.Add('-l'+s);
  341. end
  342. else
  343. begin
  344. linklibc:=true;
  345. end;
  346. end;
  347. { be sure that libc is the last lib }
  348. if linklibc then
  349. LinkRes.Add('-lc');
  350. { when we have -static for the linker the we also need libgcc }
  351. if (cs_link_staticflag in aktglobalswitches) then
  352. LinkRes.Add('-lgcc');
  353. LinkRes.Add(')');
  354. end;
  355. { objects which must be at the end }
  356. if linklibc and (libctype<>uclibc) then
  357. begin
  358. found1:=librarysearchpath.FindFile('crtend.o',s1);
  359. found2:=librarysearchpath.FindFile('crtn.o',s2);
  360. if found1 or found2 then
  361. begin
  362. LinkRes.Add('INPUT(');
  363. if found1 then
  364. LinkRes.AddFileName(s1);
  365. if found2 then
  366. LinkRes.AddFileName(s2);
  367. LinkRes.Add(')');
  368. end;
  369. end;
  370. { Write and Close response }
  371. linkres.writetodisk;
  372. linkres.Free;
  373. WriteResponseFile:=True;
  374. end;
  375. function TLinkerLinux.MakeExecutable:boolean;
  376. var
  377. binstr : String;
  378. cmdstr : TCmdStr;
  379. success : boolean;
  380. DynLinkStr : string[60];
  381. GCSectionsStr,
  382. StaticStr,
  383. StripStr : string[40];
  384. begin
  385. if not(cs_link_extern in aktglobalswitches) then
  386. Message1(exec_i_linking,current_module.exefilename^);
  387. { Create some replacements }
  388. StaticStr:='';
  389. StripStr:='';
  390. GCSectionsStr:='';
  391. DynLinkStr:='';
  392. if (cs_link_staticflag in aktglobalswitches) then
  393. StaticStr:='-static';
  394. if (cs_link_strip in aktglobalswitches) then
  395. StripStr:='-s';
  396. if (cs_link_smart in aktglobalswitches) and
  397. (tf_smartlink_sections in target_info.flags) then
  398. GCSectionsStr:='--gc-sections';
  399. If (cs_profile in aktmoduleswitches) or
  400. ((Info.DynamicLinker<>'') and (not SharedLibFiles.Empty)) then
  401. begin
  402. DynLinkStr:='-dynamic-linker='+Info.DynamicLinker;
  403. if cshared Then
  404. DynLinkStr:='--shared ' + DynLinkStr;
  405. if rlinkpath<>'' Then
  406. DynLinkStr:='--rpath-link '+rlinkpath + ' '+ DynLinkStr;
  407. End;
  408. { Write used files and libraries }
  409. WriteResponseFile(false);
  410. { Call linker }
  411. SplitBinCmd(Info.ExeCmd[1],binstr,cmdstr);
  412. Replace(cmdstr,'$EXE',maybequoted(current_module.exefilename^));
  413. Replace(cmdstr,'$OPT',Info.ExtraOptions);
  414. Replace(cmdstr,'$RES',maybequoted(outputexedir+Info.ResName));
  415. Replace(cmdstr,'$STATIC',StaticStr);
  416. Replace(cmdstr,'$STRIP',StripStr);
  417. Replace(cmdstr,'$GCSECTIONS',GCSectionsStr);
  418. Replace(cmdstr,'$DYNLINK',DynLinkStr);
  419. success:=DoExec(FindUtil(utilsprefix+BinStr),CmdStr,true,false);
  420. { Remove ReponseFile }
  421. if (success) and not(cs_link_extern in aktglobalswitches) then
  422. RemoveFile(outputexedir+Info.ResName);
  423. MakeExecutable:=success; { otherwise a recursive call to link method }
  424. end;
  425. Function TLinkerLinux.MakeSharedLibrary:boolean;
  426. var
  427. InitStr,
  428. FiniStr,
  429. SoNameStr : string[80];
  430. binstr : String;
  431. cmdstr : TCmdStr;
  432. success : boolean;
  433. begin
  434. MakeSharedLibrary:=false;
  435. if not(cs_link_extern in aktglobalswitches) then
  436. Message1(exec_i_linking,current_module.sharedlibfilename^);
  437. { Write used files and libraries }
  438. WriteResponseFile(true);
  439. { Create some replacements }
  440. InitStr:='-init FPC_LIB_START';
  441. FiniStr:='-fini FPC_LIB_EXIT';
  442. SoNameStr:='-soname '+SplitFileName(current_module.sharedlibfilename^);
  443. { Call linker }
  444. SplitBinCmd(Info.DllCmd[1],binstr,cmdstr);
  445. Replace(cmdstr,'$EXE',maybequoted(current_module.sharedlibfilename^));
  446. Replace(cmdstr,'$OPT',Info.ExtraOptions);
  447. Replace(cmdstr,'$RES',maybequoted(outputexedir+Info.ResName));
  448. Replace(cmdstr,'$INIT',InitStr);
  449. Replace(cmdstr,'$FINI',FiniStr);
  450. Replace(cmdstr,'$SONAME',SoNameStr);
  451. success:=DoExec(FindUtil(utilsprefix+binstr),cmdstr,true,false);
  452. { Strip the library ? }
  453. if success and (cs_link_strip in aktglobalswitches) then
  454. begin
  455. SplitBinCmd(Info.DllCmd[2],binstr,cmdstr);
  456. Replace(cmdstr,'$EXE',maybequoted(current_module.sharedlibfilename^));
  457. success:=DoExec(FindUtil(utilsprefix+binstr),cmdstr,true,false);
  458. end;
  459. { Remove ReponseFile }
  460. if (success) and not(cs_link_extern in aktglobalswitches) then
  461. RemoveFile(outputexedir+Info.ResName);
  462. MakeSharedLibrary:=success; { otherwise a recursive call to link method }
  463. end;
  464. {*****************************************************************************
  465. Initialize
  466. *****************************************************************************}
  467. initialization
  468. {$ifdef i386}
  469. RegisterExternalLinker(system_i386_linux_info,TLinkerLinux);
  470. RegisterImport(system_i386_linux,timportliblinux);
  471. RegisterExport(system_i386_linux,texportliblinux);
  472. RegisterTarget(system_i386_linux_info);
  473. {$endif i386}
  474. {$ifdef m68k}
  475. RegisterExternalLinker(system_m68k_linux_info,TLinkerLinux);
  476. RegisterImport(system_m68k_linux,timportliblinux);
  477. RegisterExport(system_m68k_linux,texportliblinux);
  478. RegisterTarget(system_m68k_linux_info);
  479. {$endif m68k}
  480. {$ifdef powerpc}
  481. RegisterExternalLinker(system_powerpc_linux_info,TLinkerLinux);
  482. RegisterImport(system_powerpc_linux,timportliblinux);
  483. RegisterExport(system_powerpc_linux,texportliblinux);
  484. RegisterTarget(system_powerpc_linux_info);
  485. {$endif powerpc}
  486. {$ifdef alpha}
  487. RegisterExternalLinker(system_alpha_linux_info,TLinkerLinux);
  488. RegisterImport(system_alpha_linux,timportliblinux);
  489. RegisterExport(system_alpha_linux,texportliblinux);
  490. RegisterTarget(system_alpha_linux_info);
  491. {$endif alpha}
  492. {$ifdef x86_64}
  493. RegisterExternalLinker(system_x86_64_linux_info,TLinkerLinux);
  494. RegisterImport(system_x86_64_linux,timportliblinux);
  495. RegisterExport(system_x86_64_linux,texportliblinux);
  496. RegisterTarget(system_x86_64_linux_info);
  497. {$endif x86_64}
  498. {$ifdef SPARC}
  499. RegisterExternalLinker(system_sparc_linux_info,TLinkerLinux);
  500. RegisterImport(system_SPARC_linux,timportliblinux);
  501. RegisterExport(system_SPARC_linux,texportliblinux);
  502. RegisterTarget(system_SPARC_linux_info);
  503. {$endif SPARC}
  504. {$ifdef ARM}
  505. RegisterExternalLinker(system_arm_linux_info,TLinkerLinux);
  506. RegisterImport(system_arm_linux,timportliblinux);
  507. RegisterExport(system_arm_linux,texportliblinux);
  508. RegisterTarget(system_arm_linux_info);
  509. {$endif ARM}
  510. end.
  511. {
  512. $Log$
  513. Revision 1.33 2005-01-10 15:56:13 peter
  514. * generate export jmps in .text section
  515. Revision 1.32 2004/12/22 16:32:46 peter
  516. * maybequoted() added
  517. Revision 1.31 2004/12/19 14:03:16 florian
  518. * dyn. linker path fixed for x86_64
  519. Revision 1.30 2004/11/17 22:22:12 peter
  520. mangledname setting moved to place after the complete proc declaration is read
  521. import generation moved to place where body is also parsed (still gives problems with win32)
  522. Revision 1.29 2004/11/08 22:09:59 peter
  523. * tvarsym splitted
  524. Revision 1.28 2004/11/05 12:27:27 florian
  525. * fixed dyn. linker handling
  526. Revision 1.27 2004/11/05 11:04:23 florian
  527. * path of dyn. linker on arm for linux fixed
  528. Revision 1.26 2004/10/24 13:36:26 peter
  529. * gc-sections added when section smartlinking is used
  530. Revision 1.25 2004/10/14 18:16:17 mazen
  531. * USE_SYSUTILS merged successfully : cycles with and without defines
  532. * Need to be optimized in performance
  533. Revision 1.24 2004/09/25 18:44:12 florian
  534. * fixed dyn. linker name for sparc
  535. Revision 1.23 2004/09/22 15:25:14 mazen
  536. * Fix error committing : previous version must be in branch USE_SYSUTILS
  537. Revision 1.21 2004/09/21 17:25:13 peter
  538. * paraloc branch merged
  539. Revision 1.20.4.1 2004/09/20 15:24:42 peter
  540. * remove gc-sections option until it really works
  541. Revision 1.20 2004/07/08 14:42:54 daniel
  542. * Uclibc detection
  543. Revision 1.19 2004/06/20 08:55:32 florian
  544. * logs truncated
  545. Revision 1.18 2004/06/16 20:07:11 florian
  546. * dwarf branch merged
  547. Revision 1.17.2.3 2004/05/10 21:28:35 peter
  548. * section_smartlink enabled for gas under linux
  549. Revision 1.17.2.2 2004/05/03 20:18:52 peter
  550. * fixes for tprintf
  551. Revision 1.17.2.1 2004/04/08 18:33:22 peter
  552. * rewrite of TAsmSection
  553. Revision 1.17 2004/03/06 20:35:20 florian
  554. * fixed arm compilation
  555. * cleaned up code generation for exported linux procedures
  556. }