t_nwm.pas 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640
  1. {
  2. $Id$
  3. Copyright (c) 1998-2000 by Peter Vreman
  4. This unit implements support import,export,link routines
  5. for the (i386) Netware 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. First Implementation 10 Sept 2000 Armin Diehl
  18. Currently generating NetWare-NLM's only work under Linux and win32.
  19. (see http://home.arcor.de/armin.diehl/fpcnw for binutils working
  20. with win32) while not included in fpc-releases.
  21. The following compiler-swiches are supported for NetWare:
  22. $DESCRIPTION : NLM-Description, will be displayed at load-time
  23. $M : For Stack-Size, Heap-Size will be ignored
  24. $VERSION x.x.x : Sets Major, Minor and Revision
  25. $SCREENNAME : Sets the ScreenName
  26. $THREADNAME : Sets cirrent threadname
  27. Sorry, Displaying copyright does not work with nlmconv from gnu bunutils
  28. but there is a patch available.
  29. Exports will be handled like in win32:
  30. procedure bla;
  31. begin
  32. end;
  33. exports bla name 'bla';
  34. Without Name 'bla' this will be exported in upper-case.
  35. The path to the import-Files (from netware-sdk, see developer.novell.com)
  36. must be specified by the library-path. All external modules are defined
  37. as autoload. (Note: the import-files have to be in unix-format for exe2nlm)
  38. i.e. Procedure ConsolePrintf (p:pchar); cdecl; external 'clib.nlm';
  39. sets IMPORT @clib.imp and MODULE clib.
  40. If you dont have nlmconv, compile gnu-binutils with
  41. ./configure --enable-targets=i386-linux,i386-netware
  42. make all
  43. Debugging is currently only possible at assembler level with nwdbg, written
  44. by Jan Beulich. (or with my modified RDebug) Nwdbg supports symbols but it's
  45. not a source-level debugger. You can get nwdbg from developer.novell.com.
  46. To enter the debugger from your program, call _EnterDebugger (defined in unit system).
  47. A sample program:
  48. Program Hello;
  49. (*$DESCRIPTION HelloWorldNlm*)
  50. (*$VERSION 1.2.3*)
  51. (*$ScreenName Hello*)
  52. (*$M 8192,8192*)
  53. begin
  54. writeLn ('hello world');
  55. end.
  56. compile with:
  57. ppc386 -Tnetware hello
  58. ToDo:
  59. - No duplicate imports and autoloads
  60. - No debug symbols
  61. - libc support (needs new target)
  62. - prelude support (needs new compiler switch)
  63. - make threadvars in the compiler working
  64. - a lot of additional units from nwsdk
  65. ****************************************************************************
  66. }
  67. unit t_nwm;
  68. {$i defines.inc}
  69. interface
  70. implementation
  71. uses
  72. cutils,
  73. verbose,systems,globtype,globals,
  74. symconst,script,
  75. fmodule,aasm,cpuasm,cpubase,symsym,
  76. import,export,link;
  77. type
  78. timportlibnetware=class(timportlib)
  79. procedure preparelib(const s:string);override;
  80. procedure importprocedure(const func,module:string;index:longint;const name:string);override;
  81. procedure importvariable(const varname,module:string;const name:string);override;
  82. procedure generatelib;override;
  83. end;
  84. texportlibnetware=class(texportlib)
  85. procedure preparelib(const s : string);override;
  86. procedure exportprocedure(hp : texported_item);override;
  87. procedure exportvar(hp : texported_item);override;
  88. procedure generatelib;override;
  89. end;
  90. tlinkernetware=class(tlinker)
  91. private
  92. Function WriteResponseFile(isdll:boolean) : Boolean;
  93. public
  94. constructor Create;override;
  95. procedure SetDefaultInfo;override;
  96. function MakeExecutable:boolean;override;
  97. end;
  98. {*****************************************************************************
  99. TIMPORTLIBNETWARE
  100. *****************************************************************************}
  101. procedure timportlibnetware.preparelib(const s : string);
  102. begin
  103. end;
  104. procedure timportlibnetware.importprocedure(const func,module : string;index : longint;const name : string);
  105. begin
  106. { insert sharedlibrary }
  107. current_module.linkothersharedlibs.add(SplitName(module),link_allways);
  108. { do nothing with the procedure, only set the mangledname }
  109. if name<>'' then
  110. begin
  111. aktprocdef.setmangledname(name);
  112. aktprocdef.has_mangledname:=true;
  113. end
  114. else
  115. message(parser_e_empty_import_name);
  116. end;
  117. procedure timportlibnetware.importvariable(const varname,module:string;const name:string);
  118. begin
  119. { insert sharedlibrary }
  120. current_module.linkothersharedlibs.add(SplitName(module),link_allways);
  121. { reset the mangledname and turn off the dll_var option }
  122. aktvarsym.setmangledname(name);
  123. exclude(aktvarsym.varoptions,vo_is_dll_var);
  124. end;
  125. procedure timportlibnetware.generatelib;
  126. begin
  127. end;
  128. {*****************************************************************************
  129. TEXPORTLIBNETWARE
  130. *****************************************************************************}
  131. procedure texportlibnetware.preparelib(const s:string);
  132. begin
  133. end;
  134. procedure texportlibnetware.exportprocedure(hp : texported_item);
  135. var
  136. hp2 : texported_item;
  137. begin
  138. { first test the index value }
  139. if (hp.options and eo_index)<>0 then
  140. begin
  141. Comment(V_Error,'can''t export with index under netware');
  142. exit;
  143. end;
  144. { use pascal name is none specified }
  145. if (hp.options and eo_name)=0 then
  146. begin
  147. hp.name:=stringdup(hp.sym.name);
  148. hp.options:=hp.options or eo_name;
  149. end;
  150. { now place in correct order }
  151. hp2:=texported_item(current_module._exports.first);
  152. while assigned(hp2) and
  153. (hp.name^>hp2.name^) do
  154. hp2:=texported_item(hp2.next);
  155. { insert hp there !! }
  156. if assigned(hp2) and (hp2.name^=hp.name^) then
  157. begin
  158. { this is not allowed !! }
  159. Message1(parser_e_export_name_double,hp.name^);
  160. exit;
  161. end;
  162. if hp2=texported_item(current_module._exports.first) then
  163. current_module._exports.insert(hp)
  164. else if assigned(hp2) then
  165. begin
  166. hp.next:=hp2;
  167. hp.previous:=hp2.previous;
  168. if assigned(hp2.previous) then
  169. hp2.previous.next:=hp;
  170. hp2.previous:=hp;
  171. end
  172. else
  173. current_module._exports.concat(hp);
  174. end;
  175. procedure texportlibnetware.exportvar(hp : texported_item);
  176. begin
  177. hp.is_var:=true;
  178. exportprocedure(hp);
  179. end;
  180. procedure texportlibnetware.generatelib;
  181. var
  182. hp2 : texported_item;
  183. begin
  184. hp2:=texported_item(current_module._exports.first);
  185. while assigned(hp2) do
  186. begin
  187. if (not hp2.is_var) and
  188. (hp2.sym.typ=procsym) then
  189. begin
  190. { the manglednames can already be the same when the procedure
  191. is declared with cdecl }
  192. if tprocsym(hp2.sym).defs^.def.mangledname<>hp2.name^ then
  193. begin
  194. {$ifdef i386}
  195. { place jump in codesegment }
  196. codesegment.concat(Tai_align.Create_op(4,$90));
  197. codeSegment.concat(Tai_symbol.Createname_global(hp2.name^,0));
  198. codeSegment.concat(Taicpu.Op_sym(A_JMP,S_NO,newasmsymbol(tprocsym(hp2.sym).defs^.def.mangledname)));
  199. codeSegment.concat(Tai_symbol_end.Createname(hp2.name^));
  200. {$endif i386}
  201. end;
  202. end
  203. else
  204. Comment(V_Error,'Exporting of variables is not supported under netware');
  205. hp2:=texported_item(hp2.next);
  206. end;
  207. end;
  208. {*****************************************************************************
  209. TLINKERNETWARE
  210. *****************************************************************************}
  211. Constructor TLinkerNetware.Create;
  212. begin
  213. Inherited Create;
  214. end;
  215. procedure TLinkerNetware.SetDefaultInfo;
  216. begin
  217. with Info do
  218. begin
  219. ExeCmd[1]:='nlmconv -T$RES';
  220. {DllCmd[1]:='ld $OPT -shared -L. -o $EXE $RES';}
  221. DllCmd[2]:='strip --strip-unneeded $EXE';
  222. end;
  223. end;
  224. Function TLinkerNetware.WriteResponseFile(isdll:boolean) : Boolean;
  225. Var
  226. linkres : TLinkRes;
  227. i : longint;
  228. s,s2 : string;
  229. ProgNam : string [80];
  230. NlmNam : string [80];
  231. hp2 : texported_item; { for exports }
  232. p : byte;
  233. begin
  234. WriteResponseFile:=False;
  235. ProgNam := current_module.exefilename^;
  236. i:=Pos(target_info.exeext,ProgNam);
  237. if i>0 then
  238. Delete(ProgNam,i,255);
  239. NlmNam := ProgNam + target_info.exeext;
  240. { Open link.res file }
  241. LinkRes:=TLinkRes.Create(outputexedir+Info.ResName);
  242. p := Pos ('"', Description);
  243. while (p > 0) do
  244. begin
  245. delete (Description,p,1);
  246. p := Pos ('"', Description);
  247. end;
  248. if Description <> '' then
  249. LinkRes.Add('DESCRIPTION "' + Description + '"');
  250. LinkRes.Add('VERSION '+tostr(dllmajor)+','+tostr(dllminor)+','+tostr(dllrevision));
  251. {if nwscreenname = '' then nwscreenname := ProgNam;
  252. if nwthreadname = '' then nwthreadname := ProgNam;}
  253. p := Pos ('"', nwscreenname);
  254. while (p > 0) do
  255. begin
  256. delete (nwscreenname,p,1);
  257. p := Pos ('"', nwscreenname);
  258. end;
  259. p := Pos ('"', nwthreadname);
  260. while (p > 0) do
  261. begin
  262. delete (nwthreadname,p,1);
  263. p := Pos ('"', nwthreadname);
  264. end;
  265. p := Pos ('"', nwcopyright);
  266. while (p > 0) do
  267. begin
  268. delete (nwcopyright,p,1);
  269. p := Pos ('"', nwcopyright);
  270. end;
  271. if nwscreenname <> '' then
  272. LinkRes.Add('SCREENNAME "' + nwscreenname + '"');
  273. if nwthreadname <> '' then
  274. LinkRes.Add('THREADNAME "' + nwthreadname + '"');
  275. if nwcopyright <> '' then
  276. LinkRes.Add('COPYRIGHT "' + nwcopyright + '"');
  277. if stacksize > 1024 then
  278. begin
  279. str (stacksize, s);
  280. LinkRes.Add ('STACKSIZE '+s);
  281. end;
  282. { add objectfiles, start with nwpre always }
  283. LinkRes.Add ('INPUT '+FindObjectFile('nwpre',''));
  284. { main objectfiles }
  285. while not ObjectFiles.Empty do
  286. begin
  287. s:=ObjectFiles.GetFirst;
  288. if s<>'' then
  289. LinkRes.Add ('INPUT ' + FindObjectFile (s,''));
  290. end;
  291. { output file (nlm) }
  292. LinkRes.Add ('OUTPUT ' + NlmNam);
  293. { start and stop-procedures }
  294. LinkRes.Add ('START _Prelude'); { defined in rtl/netware/nwpre.pp }
  295. LinkRes.Add ('EXIT _Stop');
  296. //if not (cs_link_strip in aktglobalswitches) then
  297. { ahhhggg: how do i detect if we have debug-symbols ? }
  298. LinkRes.Add ('DEBUG');
  299. { Write staticlibraries, is that correct ? }
  300. if not StaticLibFiles.Empty then
  301. begin
  302. While not StaticLibFiles.Empty do
  303. begin
  304. S:=lower (StaticLibFiles.GetFirst);
  305. if s<>'' then
  306. begin
  307. {ad: that's a hack !
  308. whith -XX we get the .a files as static libs (in addition to the
  309. imported libraries}
  310. if (pos ('.a',s) <> 0) OR (pos ('.A', s) <> 0) then
  311. begin
  312. LinkRes.Add ('INPUT '+FindObjectFile(s,''));
  313. end else
  314. begin
  315. i:=Pos(target_info.staticlibext,S);
  316. if i>0 then
  317. Delete(S,i,255);
  318. S := S + '.imp';
  319. librarysearchpath.FindFile(S,s);
  320. LinkRes.Add('IMPORT @'+s);
  321. end;
  322. end
  323. end;
  324. end;
  325. if not SharedLibFiles.Empty then
  326. begin
  327. While not SharedLibFiles.Empty do
  328. begin
  329. {becuase of upper/lower case mix, we may get duplicate
  330. names but nlmconv ignores that.
  331. Here we are setting the import-files for nlmconv. I.e. for
  332. the module clib or clib.nlm we add IMPORT @clib.imp and also
  333. the module clib.nlm (autoload)
  334. ? may it be better to set autoload's via StaticLibFiles ? }
  335. S:=lower (SharedLibFiles.GetFirst);
  336. if s<>'' then
  337. begin
  338. s2:=s;
  339. i:=Pos(target_info.sharedlibext,S);
  340. if i>0 then
  341. Delete(S,i,255);
  342. S := S + '.imp';
  343. librarysearchpath.FindFile(S,s);
  344. LinkRes.Add('IMPORT @'+s);
  345. LinkRes.Add('MODULE '+s2);
  346. end
  347. end;
  348. end;
  349. { write exports }
  350. hp2:=texported_item(current_module._exports.first);
  351. while assigned(hp2) do
  352. begin
  353. if not hp2.is_var then
  354. begin
  355. { Export the Symbol
  356. Warning: The Symbol is converted to upper-case if not explicitly
  357. specified by >>Exports BlaBla NAME 'BlaBla';<< }
  358. Comment(V_Debug,'Exporting '+hp2.name^);
  359. LinkRes.Add ('EXPORT '+hp2.name^);
  360. end
  361. else
  362. { really ? }
  363. Comment(V_Error,'Exporting of variables is not supported under netware');
  364. hp2:=texported_item(hp2.next);
  365. end;
  366. { Write and Close response }
  367. linkres.writetodisk;
  368. LinkRes.Free;
  369. WriteResponseFile:=True;
  370. end;
  371. function TLinkerNetware.MakeExecutable:boolean;
  372. var
  373. binstr,
  374. cmdstr : string;
  375. success : boolean;
  376. DynLinkStr : string[60];
  377. StaticStr,
  378. StripStr : string[40];
  379. begin
  380. if not(cs_link_extern in aktglobalswitches) then
  381. Message1(exec_i_linking,current_module.exefilename^);
  382. { Create some replacements }
  383. StaticStr:='';
  384. StripStr:='';
  385. DynLinkStr:='';
  386. { Write used files and libraries }
  387. WriteResponseFile(false);
  388. { Call linker }
  389. SplitBinCmd(Info.ExeCmd[1],binstr,cmdstr);
  390. Replace(cmdstr,'$EXE',current_module.exefilename^);
  391. Replace(cmdstr,'$OPT',Info.ExtraOptions);
  392. Replace(cmdstr,'$RES',outputexedir+Info.ResName);
  393. Replace(cmdstr,'$STATIC',StaticStr);
  394. Replace(cmdstr,'$STRIP',StripStr);
  395. Replace(cmdstr,'$DYNLINK',DynLinkStr);
  396. success:=DoExec(FindUtil(BinStr),CmdStr,true,false);
  397. { Remove ReponseFile }
  398. if (success) and not(cs_link_extern in aktglobalswitches) then
  399. RemoveFile(outputexedir+Info.ResName);
  400. MakeExecutable:=success; { otherwise a recursive call to link method }
  401. end;
  402. {*****************************************************************************
  403. Initialize
  404. *****************************************************************************}
  405. const
  406. target_i386_netware_info : ttargetinfo =
  407. (
  408. target : target_i386_NETWARE;
  409. name : 'Netware for i386';
  410. shortname : 'Netware';
  411. flags : [];
  412. cpu : i386;
  413. unit_env : 'NETWAREUNITS';
  414. extradefines : '';
  415. sourceext : '.pp';
  416. pasext : '.pas';
  417. exeext : '.nlm';
  418. defext : '.def';
  419. scriptext : '.sh';
  420. smartext : '.sl';
  421. unitext : '.ppn';
  422. unitlibext : '.ppl';
  423. asmext : '.s';
  424. objext : '.on';
  425. resext : '.res';
  426. resobjext : '.or';
  427. sharedlibext : '.nlm';
  428. staticlibext : '.a';
  429. staticlibprefix : '';
  430. sharedlibprefix : '';
  431. sharedClibext : '.nlm';
  432. staticClibext : '.a';
  433. staticClibprefix : '';
  434. sharedClibprefix : '';
  435. Cprefix : '';
  436. newline : #13#10;
  437. dirsep : '\';
  438. files_case_relevent : false;
  439. assem : as_i386_elf32;
  440. assemextern : as_i386_as;
  441. link : ld_i386_netware;
  442. linkextern : ld_i386_netware;
  443. ar : ar_gnu_ar;
  444. res : res_none;
  445. script : script_unix;
  446. endian : endian_little;
  447. alignment :
  448. (
  449. procalign : 4;
  450. loopalign : 4;
  451. jumpalign : 0;
  452. constalignmin : 0;
  453. constalignmax : 1;
  454. varalignmin : 0;
  455. varalignmax : 1;
  456. localalignmin : 0;
  457. localalignmax : 1;
  458. paraalign : 4;
  459. recordalignmin : 0;
  460. recordalignmax : 2;
  461. maxCrecordalign : 4
  462. );
  463. size_of_pointer : 4;
  464. size_of_longint : 4;
  465. heapsize : 256*1024;
  466. maxheapsize : 32768*1024;
  467. stacksize : 8192;
  468. DllScanSupported:false;
  469. use_bound_instruction : false;
  470. use_function_relative_addresses : true
  471. );
  472. initialization
  473. RegisterLinker(ld_i386_netware,TLinkerNetware);
  474. RegisterImport(target_i386_netware,TImportLibNetware);
  475. RegisterExport(target_i386_netware,TExportLibNetware);
  476. RegisterTarget(target_i386_netware_info);
  477. end.
  478. {
  479. $Log$
  480. Revision 1.15 2002-03-19 20:23:57 armin
  481. + smart linking now works with netware
  482. Revision 1.14 2002/03/04 17:54:59 peter
  483. * allow oridinal labels again
  484. Revision 1.13 2002/03/03 13:00:39 hajny
  485. * importprocedure fix by Armin Diehl
  486. Revision 1.12 2001/11/02 22:58:12 peter
  487. * procsym definition rewrite
  488. Revision 1.11 2001/09/18 11:32:00 michael
  489. * Fixes win32 linking problems with import libraries
  490. * LINKLIB Libraries are now looked for using C file extensions
  491. * get_exepath fix
  492. Revision 1.10 2001/09/17 21:29:16 peter
  493. * merged netbsd, fpu-overflow from fixes branch
  494. Revision 1.9 2001/08/07 18:47:15 peter
  495. * merged netbsd start
  496. * profile for win32
  497. Revision 1.8 2001/07/01 20:16:20 peter
  498. * alignmentinfo record added
  499. * -Oa argument supports more alignment settings that can be specified
  500. per type: PROC,LOOP,VARMIN,VARMAX,CONSTMIN,CONSTMAX,RECORDMIN
  501. RECORDMAX,LOCALMIN,LOCALMAX. It is possible to set the mimimum
  502. required alignment and the maximum usefull alignment. The final
  503. alignment will be choosen per variable size dependent on these
  504. settings
  505. Revision 1.7 2001/06/28 19:46:25 peter
  506. * added override and virtual for constructors
  507. Revision 1.6 2001/06/03 15:15:32 peter
  508. * dllprt0 stub for linux shared libs
  509. * pass -init and -fini for linux shared libs
  510. * libprefix splitted into staticlibprefix and sharedlibprefix
  511. Revision 1.5 2001/06/02 19:22:44 peter
  512. * extradefines field added
  513. Revision 1.4 2001/05/30 21:35:49 peter
  514. * netware patches for copyright, screenname, threadname directives
  515. Revision 1.3 2001/04/18 22:02:04 peter
  516. * registration of targets and assemblers
  517. Revision 1.2 2001/04/13 01:22:21 peter
  518. * symtable change to classes
  519. * range check generation and errors fixed, make cycle DEBUG=1 works
  520. * memory leaks fixed
  521. Revision 1.1 2001/02/26 19:43:11 peter
  522. * moved target units to subdir
  523. Revision 1.6 2001/02/20 21:41:16 peter
  524. * new fixfilename, findfile for unix. Look first for lowercase, then
  525. NormalCase and last for UPPERCASE names.
  526. Revision 1.5 2000/12/25 00:07:30 peter
  527. + new tlinkedlist class (merge of old tstringqueue,tcontainer and
  528. tlinkedlist objects)
  529. Revision 1.4 2000/11/29 00:30:42 florian
  530. * unused units removed from uses clause
  531. * some changes for widestrings
  532. Revision 1.3 2000/10/31 22:02:55 peter
  533. * symtable splitted, no real code changes
  534. Revision 1.2 2000/09/24 15:06:31 peter
  535. * use defines.inc
  536. Revision 1.1 2000/09/11 17:00:23 florian
  537. + first implementation of Netware Module support, thanks to
  538. Armin Diehl ([email protected]) for providing the patches
  539. }