t_nwm.pas 19 KB

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