t_nwm.pas 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580
  1. {
  2. $Id$
  3. Copyright (c) 1998-2002 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 possible with gdb and a converter from gdb to ndi available
  44. at http://home.arcor.de/armin.diehl/gdbnw (you have to compile with -gg)
  45. A sample program:
  46. Program Hello;
  47. (*$DESCRIPTION HelloWorldNlm*)
  48. (*$VERSION 1.2.3*)
  49. (*$ScreenName Hello*)
  50. (*$M 60000,60000*)
  51. begin
  52. writeLn ('hello world');
  53. end.
  54. compile with:
  55. ppc386 -Tnetware hello
  56. ToDo:
  57. - No duplicate imports and autoloads
  58. - No debug symbols
  59. - libc support (needs new target)
  60. - prelude support (needs new compiler switch)
  61. ****************************************************************************
  62. }
  63. unit t_nwm;
  64. {$i fpcdefs.inc}
  65. interface
  66. implementation
  67. uses
  68. cutils,
  69. verbose,systems,globtype,globals,
  70. symconst,script,
  71. fmodule,aasmbase,aasmtai,aasmcpu,cpubase,symsym,
  72. import,export,link,i_nwm;
  73. type
  74. timportlibnetware=class(timportlib)
  75. procedure preparelib(const s:string);override;
  76. procedure importprocedure(const func,module:string;index:longint;const name:string);override;
  77. procedure importvariable(vs:tvarsym;const name,module:string);override;
  78. procedure generatelib;override;
  79. end;
  80. texportlibnetware=class(texportlib)
  81. procedure preparelib(const s : string);override;
  82. procedure exportprocedure(hp : texported_item);override;
  83. procedure exportvar(hp : texported_item);override;
  84. procedure generatelib;override;
  85. end;
  86. tlinkernetware=class(texternallinker)
  87. private
  88. Function WriteResponseFile(isdll:boolean) : Boolean;
  89. public
  90. constructor Create;override;
  91. procedure SetDefaultInfo;override;
  92. function MakeExecutable:boolean;override;
  93. end;
  94. {*****************************************************************************
  95. TIMPORTLIBNETWARE
  96. *****************************************************************************}
  97. procedure timportlibnetware.preparelib(const s : string);
  98. begin
  99. end;
  100. procedure timportlibnetware.importprocedure(const func,module : string;index : longint;const name : string);
  101. begin
  102. { insert sharedlibrary }
  103. current_module.linkothersharedlibs.add(SplitName(module),link_allways);
  104. { do nothing with the procedure, only set the mangledname }
  105. if name<>'' then
  106. begin
  107. aktprocdef.setmangledname(name);
  108. end
  109. else
  110. message(parser_e_empty_import_name);
  111. end;
  112. procedure timportlibnetware.importvariable(vs:tvarsym;const name,module:string);
  113. begin
  114. { insert sharedlibrary }
  115. current_module.linkothersharedlibs.add(SplitName(module),link_allways);
  116. { reset the mangledname and turn off the dll_var option }
  117. vs.set_mangledname(name);
  118. exclude(vs.varoptions,vo_is_dll_var);
  119. end;
  120. procedure timportlibnetware.generatelib;
  121. begin
  122. end;
  123. {*****************************************************************************
  124. TEXPORTLIBNETWARE
  125. *****************************************************************************}
  126. procedure texportlibnetware.preparelib(const s:string);
  127. begin
  128. end;
  129. procedure texportlibnetware.exportprocedure(hp : texported_item);
  130. var
  131. hp2 : texported_item;
  132. begin
  133. { first test the index value }
  134. if (hp.options and eo_index)<>0 then
  135. begin
  136. Comment(V_Error,'can''t export with index under netware');
  137. exit;
  138. end;
  139. { use pascal name is none specified }
  140. if (hp.options and eo_name)=0 then
  141. begin
  142. hp.name:=stringdup(hp.sym.name);
  143. hp.options:=hp.options or eo_name;
  144. end;
  145. { now place in correct order }
  146. hp2:=texported_item(current_module._exports.first);
  147. while assigned(hp2) and
  148. (hp.name^>hp2.name^) do
  149. hp2:=texported_item(hp2.next);
  150. { insert hp there !! }
  151. if assigned(hp2) and (hp2.name^=hp.name^) then
  152. begin
  153. { this is not allowed !! }
  154. Message1(parser_e_export_name_double,hp.name^);
  155. exit;
  156. end;
  157. if hp2=texported_item(current_module._exports.first) then
  158. current_module._exports.insert(hp)
  159. else if assigned(hp2) then
  160. begin
  161. hp.next:=hp2;
  162. hp.previous:=hp2.previous;
  163. if assigned(hp2.previous) then
  164. hp2.previous.next:=hp;
  165. hp2.previous:=hp;
  166. end
  167. else
  168. current_module._exports.concat(hp);
  169. end;
  170. procedure texportlibnetware.exportvar(hp : texported_item);
  171. begin
  172. hp.is_var:=true;
  173. exportprocedure(hp);
  174. end;
  175. procedure texportlibnetware.generatelib;
  176. var
  177. hp2 : texported_item;
  178. begin
  179. hp2:=texported_item(current_module._exports.first);
  180. while assigned(hp2) do
  181. begin
  182. if (not hp2.is_var) and
  183. (hp2.sym.typ=procsym) then
  184. begin
  185. { the manglednames can already be the same when the procedure
  186. is declared with cdecl }
  187. if tprocsym(hp2.sym).first_procdef.mangledname<>hp2.name^ then
  188. begin
  189. {$ifdef i386}
  190. { place jump in codesegment }
  191. codesegment.concat(Tai_align.Create_op(4,$90));
  192. codeSegment.concat(Tai_symbol.Createname_global(hp2.name^,0));
  193. codeSegment.concat(Taicpu.Op_sym(A_JMP,S_NO,objectlibrary.newasmsymbol(tprocsym(hp2.sym).first_procdef.mangledname)));
  194. codeSegment.concat(Tai_symbol_end.Createname(hp2.name^));
  195. {$endif i386}
  196. end;
  197. end
  198. else
  199. //Comment(V_Error,'Exporting of variables is not supported under netware');
  200. Message1(parser_e_no_export_of_variables_for_target,'netware');
  201. hp2:=texported_item(hp2.next);
  202. end;
  203. end;
  204. {*****************************************************************************
  205. TLINKERNETWARE
  206. *****************************************************************************}
  207. Constructor TLinkerNetware.Create;
  208. begin
  209. Inherited Create;
  210. end;
  211. procedure TLinkerNetware.SetDefaultInfo;
  212. begin
  213. with Info do
  214. begin
  215. ExeCmd[1]:='nlmconv -T$RES';
  216. end;
  217. end;
  218. Function TLinkerNetware.WriteResponseFile(isdll:boolean) : Boolean;
  219. Var
  220. linkres : TLinkRes;
  221. i : longint;
  222. s,s2,s3 : string;
  223. ProgNam : string [80];
  224. NlmNam : string [80];
  225. hp2 : texported_item; { for exports }
  226. p : byte;
  227. begin
  228. WriteResponseFile:=False;
  229. ProgNam := current_module.exefilename^;
  230. i:=Pos(target_info.exeext,ProgNam);
  231. if i>0 then
  232. Delete(ProgNam,i,255);
  233. NlmNam := ProgNam + target_info.exeext;
  234. { Open link.res file }
  235. LinkRes:=TLinkRes.Create(outputexedir+Info.ResName);
  236. p := Pos ('"', Description);
  237. while (p > 0) do
  238. begin
  239. delete (Description,p,1);
  240. p := Pos ('"', Description);
  241. end;
  242. if Description <> '' then
  243. LinkRes.Add('DESCRIPTION "' + Description + '"');
  244. LinkRes.Add('VERSION '+tostr(dllmajor)+','+tostr(dllminor)+','+tostr(dllrevision));
  245. p := Pos ('"', nwscreenname);
  246. while (p > 0) do
  247. begin
  248. delete (nwscreenname,p,1);
  249. p := Pos ('"', nwscreenname);
  250. end;
  251. p := Pos ('"', nwthreadname);
  252. while (p > 0) do
  253. begin
  254. delete (nwthreadname,p,1);
  255. p := Pos ('"', nwthreadname);
  256. end;
  257. p := Pos ('"', nwcopyright);
  258. while (p > 0) do
  259. begin
  260. delete (nwcopyright,p,1);
  261. p := Pos ('"', nwcopyright);
  262. end;
  263. if nwscreenname <> '' then
  264. LinkRes.Add('SCREENNAME "' + nwscreenname + '"');
  265. if nwthreadname <> '' then
  266. LinkRes.Add('THREADNAME "' + nwthreadname + '"');
  267. if nwcopyright <> '' then
  268. LinkRes.Add('COPYRIGHT "' + nwcopyright + '"');
  269. if stacksize < 32768 then stacksize := 32768;
  270. str (stacksize, s);
  271. LinkRes.Add ('STACKSIZE '+s);
  272. { add objectfiles, start with nwpre always }
  273. LinkRes.Add ('INPUT '+FindObjectFile('nwpre',''));
  274. { main objectfiles }
  275. while not ObjectFiles.Empty do
  276. begin
  277. s:=ObjectFiles.GetFirst;
  278. if s<>'' then
  279. LinkRes.Add ('INPUT ' + FindObjectFile (s,''));
  280. end;
  281. { output file (nlm) }
  282. LinkRes.Add ('OUTPUT ' + NlmNam);
  283. { start and stop-procedures }
  284. LinkRes.Add ('START _Prelude'); { defined in rtl/netware/nwpre.as }
  285. LinkRes.Add ('EXIT _Stop');
  286. LinkRes.Add ('CHECK FPC_NW_CHECKFUNCTION');
  287. if (cs_gdb_dbx in aktglobalswitches) or
  288. (cs_gdb_gsym in aktglobalswitches) then
  289. begin
  290. LinkRes.Add ('DEBUG');
  291. Comment(V_Debug,'DEBUG');
  292. end;
  293. { Write staticlibraries, is that correct ? }
  294. if not StaticLibFiles.Empty then
  295. begin
  296. While not StaticLibFiles.Empty do
  297. begin
  298. S:=lower (StaticLibFiles.GetFirst);
  299. if s<>'' then
  300. begin
  301. {ad: that's a hack !
  302. whith -XX we get the .a files as static libs (in addition to the
  303. imported libraries}
  304. if (pos ('.a',s) <> 0) OR (pos ('.A', s) <> 0) then
  305. begin
  306. S2 := FindObjectFile(s,'');
  307. LinkRes.Add ('INPUT '+S2);
  308. Comment(V_Debug,'INPUT '+S2);
  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'; S2 := '';
  315. librarysearchpath.FindFile(S,S2);
  316. LinkRes.Add('IMPORT @'+S2);
  317. Comment(V_Debug,'IMPORT @'+s2);
  318. end;
  319. end
  320. end;
  321. end;
  322. if not SharedLibFiles.Empty then
  323. begin
  324. While not SharedLibFiles.Empty do
  325. begin
  326. {becuase of upper/lower case mix, we may get duplicate
  327. names but nlmconv ignores that.
  328. Here we are setting the import-files for nlmconv. I.e. for
  329. the module clib or clib.nlm we add IMPORT @clib.imp and also
  330. the module clib.nlm (autoload)
  331. ? may it be better to set autoload's via StaticLibFiles ? }
  332. S:=lower (SharedLibFiles.GetFirst);
  333. if s<>'' then
  334. begin
  335. s2:=s;
  336. i:=Pos(target_info.sharedlibext,S);
  337. if i>0 then
  338. Delete(S,i,255);
  339. S := S + '.imp';
  340. librarysearchpath.FindFile(S,S3);
  341. LinkRes.Add('IMPORT @'+S3);
  342. LinkRes.Add('MODULE '+s2);
  343. Comment(V_Debug,'MODULE '+S2);
  344. Comment(V_Debug,'IMPORT @'+S3);
  345. end
  346. end;
  347. end;
  348. { write exports }
  349. hp2:=texported_item(current_module._exports.first);
  350. while assigned(hp2) do
  351. begin
  352. if not hp2.is_var then
  353. begin
  354. { Export the Symbol }
  355. Comment(V_Debug,'EXPORT '+hp2.name^);
  356. LinkRes.Add ('EXPORT '+hp2.name^);
  357. end
  358. else
  359. { really, i think it is possible }
  360. Comment(V_Error,'Exporting of variables is not supported under netware');
  361. hp2:=texported_item(hp2.next);
  362. end;
  363. { Write and Close response }
  364. linkres.writetodisk;
  365. LinkRes.Free;
  366. WriteResponseFile:=True;
  367. end;
  368. function TLinkerNetware.MakeExecutable:boolean;
  369. var
  370. binstr,
  371. cmdstr : string;
  372. success : boolean;
  373. DynLinkStr : string[60];
  374. StaticStr,
  375. StripStr : string[40];
  376. begin
  377. if not(cs_link_extern in aktglobalswitches) then
  378. Message1(exec_i_linking,current_module.exefilename^);
  379. { Create some replacements }
  380. StaticStr:='';
  381. StripStr:='';
  382. DynLinkStr:='';
  383. { Write used files and libraries }
  384. WriteResponseFile(false);
  385. { Call linker }
  386. SplitBinCmd(Info.ExeCmd[1],binstr,cmdstr);
  387. Replace(cmdstr,'$EXE',current_module.exefilename^);
  388. Replace(cmdstr,'$OPT',Info.ExtraOptions);
  389. Replace(cmdstr,'$RES',outputexedir+Info.ResName);
  390. Replace(cmdstr,'$STATIC',StaticStr);
  391. Replace(cmdstr,'$STRIP',StripStr);
  392. Replace(cmdstr,'$DYNLINK',DynLinkStr);
  393. success:=DoExec(FindUtil(BinStr),CmdStr,true,false);
  394. { Remove ReponseFile }
  395. if (success) and not(cs_link_extern in aktglobalswitches) then
  396. RemoveFile(outputexedir+Info.ResName);
  397. MakeExecutable:=success; { otherwise a recursive call to link method }
  398. end;
  399. {*****************************************************************************
  400. Initialize
  401. *****************************************************************************}
  402. initialization
  403. RegisterExternalLinker(system_i386_netware_info,TLinkerNetware);
  404. RegisterImport(system_i386_netware,TImportLibNetware);
  405. RegisterExport(system_i386_netware,TExportLibNetware);
  406. RegisterTarget(system_i386_netware_info);
  407. end.
  408. {
  409. $Log$
  410. Revision 1.4 2003-03-21 19:19:51 armin
  411. * search of .imp files was broken, debug only if -gg was specified
  412. Revision 1.3 2002/11/17 16:32:04 carl
  413. * memory optimization (3-4%) : cleanup of tai fields,
  414. cleanup of tdef and tsym fields.
  415. * make it work for m68k
  416. Revision 1.2 2002/09/09 17:34:17 peter
  417. * tdicationary.replace added to replace and item in a dictionary. This
  418. is only allowed for the same name
  419. * varsyms are inserted in symtable before the types are parsed. This
  420. fixes the long standing "var longint : longint" bug
  421. - consume_idlist and idstringlist removed. The loops are inserted
  422. at the callers place and uses the symtable for duplicate id checking
  423. Revision 1.1 2002/09/06 15:03:50 carl
  424. * moved files to systems directory
  425. Revision 1.30 2002/09/03 16:26:29 daniel
  426. * Make Tprocdef.defs protected
  427. Revision 1.29 2002/08/12 15:08:44 carl
  428. + stab register indexes for powerpc (moved from gdb to cpubase)
  429. + tprocessor enumeration moved to cpuinfo
  430. + linker in target_info is now a class
  431. * many many updates for m68k (will soon start to compile)
  432. - removed some ifdef or correct them for correct cpu
  433. Revision 1.28 2002/08/11 14:32:32 peter
  434. * renamed current_library to objectlibrary
  435. Revision 1.27 2002/08/11 13:24:20 peter
  436. * saving of asmsymbols in ppu supported
  437. * asmsymbollist global is removed and moved into a new class
  438. tasmlibrarydata that will hold the info of a .a file which
  439. corresponds with a single module. Added librarydata to tmodule
  440. to keep the library info stored for the module. In the future the
  441. objectfiles will also be stored to the tasmlibrarydata class
  442. * all getlabel/newasmsymbol and friends are moved to the new class
  443. Revision 1.26 2002/07/26 21:15:46 florian
  444. * rewrote the system handling
  445. Revision 1.25 2002/07/01 18:46:35 peter
  446. * internal linker
  447. * reorganized aasm layer
  448. Revision 1.24 2002/05/18 13:34:27 peter
  449. * readded missing revisions
  450. Revision 1.23 2002/05/16 19:46:53 carl
  451. + defines.inc -> fpcdefs.inc to avoid conflicts if compiling by hand
  452. + try to fix temp allocation (still in ifdef)
  453. + generic constructor calls
  454. + start of tassembler / tmodulebase class cleanup
  455. Revision 1.21 2002/04/22 18:19:22 carl
  456. - remove use_bound_instruction field
  457. Revision 1.20 2002/04/20 21:43:18 carl
  458. * fix stack size for some targets
  459. + add offset to parameters from frame pointer info.
  460. - remove some unused stuff
  461. Revision 1.19 2002/04/19 15:46:05 peter
  462. * mangledname rewrite, tprocdef.mangledname is now created dynamicly
  463. in most cases and not written to the ppu
  464. * add mangeledname_prefix() routine to generate the prefix of
  465. manglednames depending on the current procedure, object and module
  466. * removed static procprefix since the mangledname is now build only
  467. on demand from tprocdef.mangledname
  468. Revision 1.18 2002/04/15 19:16:57 carl
  469. - remove size_of_pointer field
  470. Revision 1.17 2002/03/30 09:09:47 armin
  471. + support check-function for netware
  472. Revision 1.16 2002/03/29 17:19:51 armin
  473. + allow exports for netware
  474. Revision 1.15 2002/03/19 20:23:57 armin
  475. + smart linking now works with netware
  476. Revision 1.14 2002/03/04 17:54:59 peter
  477. * allow oridinal labels again
  478. Revision 1.13 2002/03/03 13:00:39 hajny
  479. * importprocedure fix by Armin Diehl
  480. }