t_nwm.pas 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449
  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. This is
  19. because nlmconf from binutils does not work with i.e. win32 coff
  20. object files. It works fine with ELF-Objects.
  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. Sorry, Displaying copyright does not work with nlmconv from gnu bunutils.
  26. Exports will be handled like in win32:
  27. procedure bla;
  28. begin
  29. end;
  30. exports bla name 'bla';
  31. Without Name 'bla' this will be exported in upper-case.
  32. The path to the import-Files (from netware-sdk, see developer.novell.com)
  33. must be specified by the library-path. All external modules are defined
  34. as autoload.
  35. i.e. Procedure ConsolePrintf (p:pchar); cdecl; external 'clib.nlm';
  36. sets IMPORT @clib.imp and MODULE clib.
  37. If you dont have nlmconv, compile gnu-binutils with
  38. ./configure --enable-targets=i386-linux,i386-netware
  39. make all
  40. Debugging is currently only possible at assembler level with nwdbg, written
  41. by Jan Beulich. Nwdbg supports symbols but it's not a source-level
  42. debugger. You can get nwdbg from developer.novell.com. To enter the
  43. debugger from your program, define "EnterDebugger" as external cdecl and
  44. call it. Int3 will not work with Netware 5.
  45. A sample program:
  46. Program Hello;
  47. (*$DESCRIPTION HelloWorldNlm*)
  48. (*$VERSION 1.2.2*)
  49. (*$M 8192,8192*)
  50. begin
  51. writeLn ('hello world');
  52. end.
  53. compile with:
  54. ppc386 -Tnetware hello
  55. ToDo:
  56. - No duplicate imports and autoloads
  57. - Screen and Thread-Names
  58. ****************************************************************************
  59. }
  60. unit t_nwm;
  61. interface
  62. uses
  63. import,export,link;
  64. type
  65. pimportlibnetware=^timportlibnetware;
  66. timportlibnetware=object(timportlib)
  67. procedure preparelib(const s:string);virtual;
  68. procedure importprocedure(const func,module:string;index:longint;const name:string);virtual;
  69. procedure importvariable(const varname,module:string;const name:string);virtual;
  70. procedure generatelib;virtual;
  71. end;
  72. pexportlibnetware=^texportlibnetware;
  73. texportlibnetware=object(texportlib)
  74. procedure preparelib(const s : string);virtual;
  75. procedure exportprocedure(hp : pexported_item);virtual;
  76. procedure exportvar(hp : pexported_item);virtual;
  77. procedure generatelib;virtual;
  78. end;
  79. plinkernetware=^tlinkernetware;
  80. tlinkernetware=object(tlinker)
  81. private
  82. Function WriteResponseFile(isdll:boolean) : Boolean;
  83. public
  84. constructor Init;
  85. procedure SetDefaultInfo;virtual;
  86. function MakeExecutable:boolean;virtual;
  87. end;
  88. implementation
  89. uses
  90. cutils,verbose,strings,cobjects,systems,globtype,globals,
  91. symconst,script,
  92. fmodule,aasm,cpuasm,cpubase,symtable{$IFDEF NEWST},symbols{$ENDIF NEWST};
  93. {*****************************************************************************
  94. TIMPORTLIBNETWARE
  95. *****************************************************************************}
  96. procedure timportlibnetware.preparelib(const s : string);
  97. begin
  98. end;
  99. procedure timportlibnetware.importprocedure(const func,module : string;index : longint;const name : string);
  100. begin
  101. { insert sharedlibrary }
  102. {$IFDEF NEWST}
  103. current_module^.linkothersharedlibs.
  104. insert(new(Plinkitem,init(SplitName(module),link_allways)));
  105. { do nothing with the procedure, only set the mangledname }
  106. if name<>'' then
  107. aktprocdef^.setmangledname(name)
  108. else
  109. message(parser_e_empty_import_name);
  110. {$ELSE}
  111. current_module^.linkothersharedlibs.
  112. insert(SplitName(module),link_allways);
  113. { do nothing with the procedure, only set the mangledname }
  114. if name<>'' then
  115. aktprocsym^.definition^.setmangledname(name)
  116. else
  117. message(parser_e_empty_import_name);
  118. {$ENDIF NEWST}
  119. end;
  120. procedure timportlibnetware.importvariable(const varname,module:string;const name:string);
  121. begin
  122. { insert sharedlibrary }
  123. {$IFDEF NEWST}
  124. current_module^.linkothersharedlibs.
  125. insert(new(Plinkitem,init(SplitName(module),link_allways)));
  126. {$ELSE}
  127. current_module^.linkothersharedlibs.
  128. insert(SplitName(module),link_allways);
  129. {$ENDIF NEWST}
  130. { reset the mangledname and turn off the dll_var option }
  131. aktvarsym^.setmangledname(name);
  132. {$IFDEF NEWST}
  133. exclude(aktvarsym^.properties,vo_is_dll_var);
  134. {$ELSE}
  135. exclude(aktvarsym^.varoptions,vo_is_dll_var);
  136. {$ENDIF NEWST}
  137. end;
  138. procedure timportlibnetware.generatelib;
  139. begin
  140. end;
  141. {*****************************************************************************
  142. TEXPORTLIBNETWARE
  143. *****************************************************************************}
  144. procedure texportlibnetware.preparelib(const s:string);
  145. begin
  146. end;
  147. procedure texportlibnetware.exportprocedure(hp : pexported_item);
  148. var
  149. hp2 : pexported_item;
  150. begin
  151. { first test the index value }
  152. if (hp^.options and eo_index)<>0 then
  153. begin
  154. Comment(V_Error,'can''t export with index under netware');
  155. exit;
  156. end;
  157. { use pascal name is none specified }
  158. if (hp^.options and eo_name)=0 then
  159. begin
  160. hp^.name:=stringdup(hp^.sym^.name);
  161. hp^.options:=hp^.options or eo_name;
  162. end;
  163. { now place in correct order }
  164. hp2:=pexported_item(current_module^._exports^.first);
  165. while assigned(hp2) and
  166. (hp^.name^>hp2^.name^) do
  167. hp2:=pexported_item(hp2^.next);
  168. { insert hp there !! }
  169. if assigned(hp2) and (hp2^.name^=hp^.name^) then
  170. begin
  171. { this is not allowed !! }
  172. Message1(parser_e_export_name_double,hp^.name^);
  173. exit;
  174. end;
  175. if hp2=pexported_item(current_module^._exports^.first) then
  176. current_module^._exports^.insert(hp)
  177. else if assigned(hp2) then
  178. begin
  179. hp^.next:=hp2;
  180. hp^.previous:=hp2^.previous;
  181. if assigned(hp2^.previous) then
  182. hp2^.previous^.next:=hp;
  183. hp2^.previous:=hp;
  184. end
  185. else
  186. current_module^._exports^.concat(hp);
  187. end;
  188. procedure texportlibnetware.exportvar(hp : pexported_item);
  189. begin
  190. hp^.is_var:=true;
  191. exportprocedure(hp);
  192. end;
  193. procedure texportlibnetware.generatelib;
  194. var
  195. hp2 : pexported_item;
  196. begin
  197. hp2:=pexported_item(current_module^._exports^.first);
  198. while assigned(hp2) do
  199. begin
  200. if not hp2^.is_var then
  201. begin
  202. {$ifdef i386}
  203. { place jump in codesegment }
  204. codesegment^.concat(new(pai_align,init_op(4,$90)));
  205. codesegment^.concat(new(pai_symbol,initname_global(hp2^.name^,0)));
  206. codesegment^.concat(new(paicpu,op_sym(A_JMP,S_NO,newasmsymbol(hp2^.sym^.mangledname))));
  207. codesegment^.concat(new(pai_symbol_end,initname(hp2^.name^)));
  208. {$endif i386}
  209. end
  210. else
  211. Comment(V_Error,'Exporting of variables is not supported under netware');
  212. hp2:=pexported_item(hp2^.next);
  213. end;
  214. end;
  215. {*****************************************************************************
  216. TLINKERNETWARE
  217. *****************************************************************************}
  218. Constructor TLinkerNetware.Init;
  219. begin
  220. Inherited Init;
  221. end;
  222. procedure TLinkerNetware.SetDefaultInfo;
  223. begin
  224. with Info do
  225. begin
  226. ExeCmd[1]:='nlmconv -T$RES';
  227. {DllCmd[1]:='ld $OPT -shared -L. -o $EXE $RES';}
  228. DllCmd[2]:='strip --strip-unneeded $EXE';
  229. end;
  230. end;
  231. Function TLinkerNetware.WriteResponseFile(isdll:boolean) : Boolean;
  232. Var
  233. linkres : TLinkRes;
  234. i : longint;
  235. s,s2 : string;
  236. found : boolean;
  237. ProgNam : string [80];
  238. NlmNam : string [80];
  239. hp2 : pexported_item; { for exports }
  240. begin
  241. WriteResponseFile:=False;
  242. ProgNam := current_module^.exefilename^;
  243. i:=Pos(target_os.exeext,ProgNam);
  244. if i>0 then
  245. Delete(ProgNam,i,255);
  246. NlmNam := ProgNam + target_os.exeext;
  247. { Open link.res file }
  248. LinkRes.Init(outputexedir+Info.ResName);
  249. if Description <> '' then
  250. LinkRes.Add('DESCRIPTION "' + Description + '"');
  251. LinkRes.Add('VERSION '+tostr(dllmajor)+','+tostr(dllminor)+','+tostr(dllrevision));
  252. LinkRes.Add('SCREENNAME "' + ProgNam + '"'); { for that, we have }
  253. LinkRes.Add('THREADNAME "' + ProgNam + '"'); { to add comiler directives }
  254. if stacksize > 1024 then
  255. begin
  256. str (stacksize, s);
  257. LinkRes.Add ('STACKSIZE '+s);
  258. end;
  259. { add objectfiles, start with nwpre always }
  260. LinkRes.Add ('INPUT '+FindObjectFile('nwpre',''));
  261. { main objectfiles }
  262. while not ObjectFiles.Empty do
  263. begin
  264. s:=ObjectFiles.Get;
  265. if s<>'' then
  266. LinkRes.Add ('INPUT ' + FindObjectFile (s,''));
  267. end;
  268. { output file (nlm) }
  269. LinkRes.Add ('OUTPUT ' + NlmNam);
  270. { start and stop-procedures }
  271. LinkRes.Add ('START _Prelude'); { defined in rtl/netware/nwpre.pp }
  272. LinkRes.Add ('EXIT _Stop');
  273. //if not (cs_link_strip in aktglobalswitches) then
  274. { ahhhggg: how do i detect if we have debug-symbols ? }
  275. LinkRes.Add ('DEBUG');
  276. { Write staticlibraries, is that correct ? }
  277. if not StaticLibFiles.Empty then
  278. begin
  279. While not StaticLibFiles.Empty do
  280. begin
  281. S:=lower (StaticLibFiles.Get);
  282. if s<>'' then
  283. begin
  284. i:=Pos(target_os.staticlibext,S);
  285. if i>0 then
  286. Delete(S,i,255);
  287. S := S + '.imp';
  288. S := librarysearchpath.FindFile(S,found)+S;
  289. LinkRes.Add('IMPORT @'+s);
  290. end
  291. end;
  292. end;
  293. if not SharedLibFiles.Empty then
  294. begin
  295. While not SharedLibFiles.Empty do
  296. begin
  297. {becuase of upper/lower case mix, we may get duplicate
  298. names but nlmconv ignores that.
  299. Here we are setting the import-files for nlmconv. I.e. for
  300. the module clib or clib.nlm we add IMPORT @clib.imp and also
  301. the module clib.nlm (autoload)
  302. ? may it be better to set autoload's via StaticLibFiles ? }
  303. S:=lower (SharedLibFiles.Get);
  304. if s<>'' then
  305. begin
  306. s2:=s;
  307. i:=Pos(target_os.sharedlibext,S);
  308. if i>0 then
  309. Delete(S,i,255);
  310. S := S + '.imp';
  311. S := librarysearchpath.FindFile(S,found)+S;
  312. LinkRes.Add('IMPORT @'+s);
  313. LinkRes.Add('MODULE '+s2);
  314. end
  315. end;
  316. end;
  317. { write exports }
  318. hp2:=pexported_item(current_module^._exports^.first);
  319. while assigned(hp2) do
  320. begin
  321. if not hp2^.is_var then
  322. begin
  323. { Export the Symbol
  324. Warning: The Symbol is converted to upper-case if not explicitly
  325. specified by >>Exports BlaBla NAME 'BlaBla';<< }
  326. Comment(V_Debug,'Exporting '+hp2^.name^);
  327. LinkRes.Add ('EXPORT '+hp2^.name^);
  328. end
  329. else
  330. { really ? }
  331. Comment(V_Error,'Exporting of variables is not supported under netware');
  332. hp2:=pexported_item(hp2^.next);
  333. end;
  334. { Write and Close response }
  335. linkres.writetodisk;
  336. linkres.done;
  337. WriteResponseFile:=True;
  338. end;
  339. function TLinkerNetware.MakeExecutable:boolean;
  340. var
  341. binstr,
  342. cmdstr : string;
  343. success : boolean;
  344. DynLinkStr : string[60];
  345. StaticStr,
  346. StripStr : string[40];
  347. begin
  348. if not(cs_link_extern in aktglobalswitches) then
  349. Message1(exec_i_linking,current_module^.exefilename^);
  350. { Create some replacements }
  351. StaticStr:='';
  352. StripStr:='';
  353. DynLinkStr:='';
  354. { Write used files and libraries }
  355. WriteResponseFile(false);
  356. { Call linker }
  357. SplitBinCmd(Info.ExeCmd[1],binstr,cmdstr);
  358. Replace(cmdstr,'$EXE',current_module^.exefilename^);
  359. Replace(cmdstr,'$OPT',Info.ExtraOptions);
  360. Replace(cmdstr,'$RES',outputexedir+Info.ResName);
  361. Replace(cmdstr,'$STATIC',StaticStr);
  362. Replace(cmdstr,'$STRIP',StripStr);
  363. Replace(cmdstr,'$DYNLINK',DynLinkStr);
  364. success:=DoExec(FindUtil(BinStr),CmdStr,true,false);
  365. { Remove ReponseFile }
  366. if (success) and not(cs_link_extern in aktglobalswitches) then
  367. RemoveFile(outputexedir+Info.ResName);
  368. MakeExecutable:=success; { otherwise a recursive call to link method }
  369. end;
  370. end.
  371. {
  372. $Log$
  373. Revision 1.1 2000-09-11 17:00:23 florian
  374. + first implementation of Netware Module support, thanks to
  375. Armin Diehl ([email protected]) for providing the patches
  376. }