t_nwm.pas 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605
  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. Currently generating NetWare-NLM's only work under Linux and win32.
  18. (see http://home.arcor.de/armin.diehl/fpcnw for binutils working
  19. with win32) while not included in fpc-releases.
  20. The following compiler-swiches are supported for NetWare:
  21. $DESCRIPTION : NLM-Description, will be displayed at load-time
  22. $M : For Stack-Size, Heap-Size will be ignored
  23. 32K is the accepted minimum
  24. $VERSION x.x.x : Sets Major, Minor and Revision
  25. $SCREENNAME : Sets the ScreenName
  26. $THREADNAME : Sets current threadname
  27. Displaying copyright does not work with nlmconv from gnu bunutils
  28. version less that 2.13
  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 must be specified by the library-path.
  35. All external modules are defined as autoload. (Note: the import-files have
  36. 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. Function simply defined as external work without generating autoload but
  41. you will get a warnung from nlmconv.
  42. If you dont have nlmconv, compile gnu-binutils with
  43. ./configure --enable-targets=i386-linux,i386-netware
  44. make all
  45. Debugging is possible with gdb and a converter from gdb to ndi available
  46. at http://home.arcor.de/armin.diehl/gdbnw
  47. A sample program:
  48. Program Hello;
  49. (*$DESCRIPTION HelloWorldNlm*)
  50. (*$VERSION 1.2.3*)
  51. (*$ScreenName Hello*)
  52. (*$M 60000,60000*)
  53. begin
  54. writeLn ('hello world');
  55. end.
  56. compile with:
  57. ppc386 -Tnetware hello
  58. ToDo:
  59. - No duplicate imports and autoloads
  60. - libc support (needs new target)
  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. NLMConvLinkFile: TLinkRes; {for second pass, fist pass is ld}
  89. Function WriteResponseFile(isdll:boolean) : Boolean;
  90. public
  91. constructor Create;override;
  92. procedure SetDefaultInfo;override;
  93. function MakeExecutable:boolean;override;
  94. end;
  95. Const tmpLinkFileName = 'link~tmp._o_';
  96. minStackSize = 32768;
  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. end
  112. else
  113. message(parser_e_empty_import_name);
  114. end;
  115. procedure timportlibnetware.importvariable(vs:tvarsym;const name,module:string);
  116. begin
  117. { insert sharedlibrary }
  118. current_module.linkothersharedlibs.add(SplitName(module),link_allways);
  119. { reset the mangledname and turn off the dll_var option }
  120. vs.set_mangledname(name);
  121. exclude(vs.varoptions,vo_is_dll_var);
  122. end;
  123. procedure timportlibnetware.generatelib;
  124. begin
  125. end;
  126. {*****************************************************************************
  127. TEXPORTLIBNETWARE
  128. *****************************************************************************}
  129. procedure texportlibnetware.preparelib(const s:string);
  130. begin
  131. end;
  132. procedure texportlibnetware.exportprocedure(hp : texported_item);
  133. var
  134. hp2 : texported_item;
  135. begin
  136. { first test the index value }
  137. if (hp.options and eo_index)<>0 then
  138. begin
  139. Comment(V_Error,'can''t export with index under netware');
  140. exit;
  141. end;
  142. { use pascal name is none specified }
  143. if (hp.options and eo_name)=0 then
  144. begin
  145. hp.name:=stringdup(hp.sym.name);
  146. hp.options:=hp.options or eo_name;
  147. end;
  148. { now place in correct order }
  149. hp2:=texported_item(current_module._exports.first);
  150. while assigned(hp2) and
  151. (hp.name^>hp2.name^) do
  152. hp2:=texported_item(hp2.next);
  153. { insert hp there !! }
  154. if assigned(hp2) and (hp2.name^=hp.name^) then
  155. begin
  156. { this is not allowed !! }
  157. Message1(parser_e_export_name_double,hp.name^);
  158. exit;
  159. end;
  160. if hp2=texported_item(current_module._exports.first) then
  161. current_module._exports.insert(hp)
  162. else if assigned(hp2) then
  163. begin
  164. hp.next:=hp2;
  165. hp.previous:=hp2.previous;
  166. if assigned(hp2.previous) then
  167. hp2.previous.next:=hp;
  168. hp2.previous:=hp;
  169. end
  170. else
  171. current_module._exports.concat(hp);
  172. end;
  173. procedure texportlibnetware.exportvar(hp : texported_item);
  174. begin
  175. hp.is_var:=true;
  176. exportprocedure(hp);
  177. end;
  178. procedure texportlibnetware.generatelib;
  179. var
  180. hp2 : texported_item;
  181. begin
  182. hp2:=texported_item(current_module._exports.first);
  183. while assigned(hp2) do
  184. begin
  185. if (not hp2.is_var) and
  186. (hp2.sym.typ=procsym) then
  187. begin
  188. { the manglednames can already be the same when the procedure
  189. is declared with cdecl }
  190. if tprocsym(hp2.sym).first_procdef.mangledname<>hp2.name^ then
  191. begin
  192. {$ifdef i386}
  193. { place jump in codesegment }
  194. codesegment.concat(Tai_align.Create_op(4,$90));
  195. codeSegment.concat(Tai_symbol.Createname_global(hp2.name^,0));
  196. codeSegment.concat(Taicpu.Op_sym(A_JMP,S_NO,objectlibrary.newasmsymbol(tprocsym(hp2.sym).first_procdef.mangledname)));
  197. codeSegment.concat(Tai_symbol_end.Createname(hp2.name^));
  198. {$endif i386}
  199. end;
  200. end
  201. else
  202. //Comment(V_Error,'Exporting of variables is not supported under netware');
  203. Message1(parser_e_no_export_of_variables_for_target,'netware');
  204. hp2:=texported_item(hp2.next);
  205. end;
  206. end;
  207. {*****************************************************************************
  208. TLINKERNETWARE
  209. *****************************************************************************}
  210. Constructor TLinkerNetware.Create;
  211. begin
  212. Inherited Create;
  213. end;
  214. procedure TLinkerNetware.SetDefaultInfo;
  215. begin
  216. with Info do
  217. begin
  218. ExeCmd[1]:= 'ld -Ur -T $RES $STRIP -o $TMPOBJ';
  219. ExeCmd[2]:='nlmconv -T$RES';
  220. end;
  221. end;
  222. Function TLinkerNetware.WriteResponseFile(isdll:boolean) : Boolean;
  223. Var
  224. linkres : TLinkRes;
  225. i : longint;
  226. s,s2,s3 : string;
  227. ProgNam : string [80];
  228. NlmNam : string [80];
  229. hp2 : texported_item; { for exports }
  230. p : byte;
  231. begin
  232. WriteResponseFile:=False;
  233. ProgNam := current_module.exefilename^;
  234. i:=Pos(target_info.exeext,ProgNam);
  235. if i>0 then
  236. Delete(ProgNam,i,255);
  237. NlmNam := ProgNam + target_info.exeext;
  238. { Open link.res file }
  239. LinkRes:=TLinkRes.Create(outputexedir+Info.ResName); {for ld}
  240. NLMConvLinkFile:=TLinkRes.Create(outputexedir+Info.ResName); {for nlmconv, written in CreateExeFile}
  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. NLMConvLinkFile.Add('DESCRIPTION "' + Description + '"');
  249. NLMConvLinkFile.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. NLMConvLinkFile.Add('SCREENNAME "' + nwscreenname + '"');
  270. if nwthreadname <> '' then
  271. NLMConvLinkFile.Add('THREADNAME "' + nwthreadname + '"');
  272. if nwcopyright <> '' then
  273. NLMConvLinkFile.Add('COPYRIGHT "' + nwcopyright + '"');
  274. if stacksize < minStackSize then stacksize := minStackSize;
  275. str (stacksize, s);
  276. NLMConvLinkFile.Add ('STACKSIZE '+s);
  277. NLMConvLinkFile.Add ('INPUT '+tmpLinkFileName);
  278. { add objectfiles, start with nwpre always }
  279. LinkRes.Add ('INPUT (');
  280. LinkRes.Add (FindObjectFile('nwpre',''));
  281. { main objectfiles, add to linker input }
  282. while not ObjectFiles.Empty do
  283. begin
  284. s:=ObjectFiles.GetFirst;
  285. if s<>'' then
  286. LinkRes.Add (FindObjectFile (s,''));
  287. end;
  288. { output file (nlm), add to nlmconv }
  289. NLMConvLinkFile.Add ('OUTPUT ' + NlmNam);
  290. { start and stop-procedures }
  291. NLMConvLinkFile.Add ('START _Prelude'); { defined in rtl/netware/nwpre.as }
  292. NLMConvLinkFile.Add ('EXIT _Stop'); { nwpre.as }
  293. NLMConvLinkFile.Add ('CHECK FPC_NW_CHECKFUNCTION'); { system.pp }
  294. if not (cs_link_strip in aktglobalswitches) then
  295. begin
  296. NLMConvLinkFile.Add ('DEBUG');
  297. Comment(V_Debug,'DEBUG');
  298. end;
  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. S2 := FindObjectFile(s,'');
  313. LinkRes.Add (S2);
  314. Comment(V_Debug,'INPUT '+S2);
  315. end else
  316. begin
  317. i:=Pos(target_info.staticlibext,S);
  318. if i>0 then
  319. Delete(S,i,255);
  320. S := S + '.imp'; S2 := '';
  321. librarysearchpath.FindFile(S,S2);
  322. NLMConvLinkFile.Add('IMPORT @'+S2);
  323. Comment(V_Debug,'IMPORT @'+s2);
  324. end;
  325. end
  326. end;
  327. end;
  328. if not SharedLibFiles.Empty then
  329. begin
  330. While not SharedLibFiles.Empty do
  331. begin
  332. {becuase of upper/lower case mix, we may get duplicate
  333. names but nlmconv ignores that.
  334. Here we are setting the import-files for nlmconv. I.e. for
  335. the module clib or clib.nlm we add IMPORT @clib.imp and also
  336. the module clib.nlm (autoload)
  337. ? may it be better to set autoload's via StaticLibFiles ? }
  338. S:=lower (SharedLibFiles.GetFirst);
  339. if s<>'' then
  340. begin
  341. s2:=s;
  342. i:=Pos(target_info.sharedlibext,S);
  343. if i>0 then
  344. Delete(S,i,255);
  345. S := S + '.imp';
  346. librarysearchpath.FindFile(S,S3);
  347. NLMConvLinkFile.Add('IMPORT @'+S3);
  348. NLMConvLinkFile.Add('MODULE '+s2);
  349. Comment(V_Debug,'MODULE '+S2);
  350. Comment(V_Debug,'IMPORT @'+S3);
  351. end
  352. end;
  353. end;
  354. { write exports }
  355. hp2:=texported_item(current_module._exports.first);
  356. while assigned(hp2) do
  357. begin
  358. if not hp2.is_var then
  359. begin
  360. { Export the Symbol }
  361. Comment(V_Debug,'EXPORT '+hp2.name^);
  362. NLMConvLinkFile.Add ('EXPORT '+hp2.name^);
  363. end
  364. else
  365. { really, i think it is possible }
  366. Comment(V_Error,'Exporting of variables is not supported under netware');
  367. hp2:=texported_item(hp2.next);
  368. end;
  369. { Write and Close response for ld, response for nlmconv is in NLMConvLinkFile(not written) }
  370. linkres.Add (')');
  371. linkres.writetodisk;
  372. LinkRes.Free;
  373. WriteResponseFile:=True;
  374. end;
  375. function TLinkerNetware.MakeExecutable:boolean;
  376. var
  377. binstr,
  378. cmdstr : string;
  379. success : boolean;
  380. StripStr : string[2];
  381. begin
  382. if not(cs_link_extern in aktglobalswitches) then
  383. Message1(exec_i_linking,current_module.exefilename^);
  384. { Create some replacements }
  385. StripStr:='';
  386. if (cs_link_strip in aktglobalswitches) then
  387. StripStr:='-s';
  388. { Write used files and libraries and create Headerfile for
  389. nlmconv in NLMConvLinkFile }
  390. WriteResponseFile(false);
  391. { Call linker, this will generate a new object file that will be passed
  392. to nlmconv. Otherwise we could not create nlms without debug info }
  393. SplitBinCmd(Info.ExeCmd[1],binstr,cmdstr);
  394. Replace(cmdstr,'$EXE',current_module.exefilename^);
  395. Replace(cmdstr,'$RES',outputexedir+Info.ResName);
  396. Replace(cmdstr,'$STRIP',StripStr);
  397. Replace(cmdstr,'$TMPOBJ',outputexedir+tmpLinkFileName);
  398. Comment (v_debug,'Executing '+BinStr+' '+cmdstr);
  399. success:=DoExec(FindUtil(BinStr),CmdStr,true,false);
  400. { Remove ReponseFile }
  401. if (success) and not(cs_link_extern in aktglobalswitches) then
  402. RemoveFile(outputexedir+Info.ResName);
  403. { Call nlmconv }
  404. if success then
  405. begin
  406. NLMConvLinkFile.writetodisk;
  407. NLMConvLinkFile.Free;
  408. SplitBinCmd(Info.ExeCmd[2],binstr,cmdstr);
  409. Replace(cmdstr,'$RES',outputexedir+Info.ResName);
  410. Comment (v_debug,'Executing '+BinStr+' '+cmdstr);
  411. success:=DoExec(FindUtil(BinStr),CmdStr,true,false);
  412. if success then
  413. RemoveFile(outputexedir+Info.ResName);
  414. {always remove the temp object file}
  415. RemoveFile(outputexedir+tmpLinkFileName);
  416. end;
  417. MakeExecutable:=success; { otherwise a recursive call to link method }
  418. end;
  419. {*****************************************************************************
  420. Initialize
  421. *****************************************************************************}
  422. initialization
  423. RegisterExternalLinker(system_i386_netware_info,TLinkerNetware);
  424. RegisterImport(system_i386_netware,TImportLibNetware);
  425. RegisterExport(system_i386_netware,TExportLibNetware);
  426. RegisterTarget(system_i386_netware_info);
  427. end.
  428. {
  429. $Log$
  430. Revision 1.5 2003-03-21 22:36:42 armin
  431. * changed linking: now we will link all objects to a single one and call nlmconv with that one object file. This makes it possible to create nlms without debug info.
  432. Revision 1.4 2003/03/21 19:19:51 armin
  433. * search of .imp files was broken, debug only if -gg was specified
  434. Revision 1.3 2002/11/17 16:32:04 carl
  435. * memory optimization (3-4%) : cleanup of tai fields,
  436. cleanup of tdef and tsym fields.
  437. * make it work for m68k
  438. Revision 1.2 2002/09/09 17:34:17 peter
  439. * tdicationary.replace added to replace and item in a dictionary. This
  440. is only allowed for the same name
  441. * varsyms are inserted in symtable before the types are parsed. This
  442. fixes the long standing "var longint : longint" bug
  443. - consume_idlist and idstringlist removed. The loops are inserted
  444. at the callers place and uses the symtable for duplicate id checking
  445. Revision 1.1 2002/09/06 15:03:50 carl
  446. * moved files to systems directory
  447. Revision 1.30 2002/09/03 16:26:29 daniel
  448. * Make Tprocdef.defs protected
  449. Revision 1.29 2002/08/12 15:08:44 carl
  450. + stab register indexes for powerpc (moved from gdb to cpubase)
  451. + tprocessor enumeration moved to cpuinfo
  452. + linker in target_info is now a class
  453. * many many updates for m68k (will soon start to compile)
  454. - removed some ifdef or correct them for correct cpu
  455. Revision 1.28 2002/08/11 14:32:32 peter
  456. * renamed current_library to objectlibrary
  457. Revision 1.27 2002/08/11 13:24:20 peter
  458. * saving of asmsymbols in ppu supported
  459. * asmsymbollist global is removed and moved into a new class
  460. tasmlibrarydata that will hold the info of a .a file which
  461. corresponds with a single module. Added librarydata to tmodule
  462. to keep the library info stored for the module. In the future the
  463. objectfiles will also be stored to the tasmlibrarydata class
  464. * all getlabel/newasmsymbol and friends are moved to the new class
  465. Revision 1.26 2002/07/26 21:15:46 florian
  466. * rewrote the system handling
  467. Revision 1.25 2002/07/01 18:46:35 peter
  468. * internal linker
  469. * reorganized aasm layer
  470. Revision 1.24 2002/05/18 13:34:27 peter
  471. * readded missing revisions
  472. Revision 1.23 2002/05/16 19:46:53 carl
  473. + defines.inc -> fpcdefs.inc to avoid conflicts if compiling by hand
  474. + try to fix temp allocation (still in ifdef)
  475. + generic constructor calls
  476. + start of tassembler / tmodulebase class cleanup
  477. Revision 1.21 2002/04/22 18:19:22 carl
  478. - remove use_bound_instruction field
  479. Revision 1.20 2002/04/20 21:43:18 carl
  480. * fix stack size for some targets
  481. + add offset to parameters from frame pointer info.
  482. - remove some unused stuff
  483. Revision 1.19 2002/04/19 15:46:05 peter
  484. * mangledname rewrite, tprocdef.mangledname is now created dynamicly
  485. in most cases and not written to the ppu
  486. * add mangeledname_prefix() routine to generate the prefix of
  487. manglednames depending on the current procedure, object and module
  488. * removed static procprefix since the mangledname is now build only
  489. on demand from tprocdef.mangledname
  490. Revision 1.18 2002/04/15 19:16:57 carl
  491. - remove size_of_pointer field
  492. Revision 1.17 2002/03/30 09:09:47 armin
  493. + support check-function for netware
  494. Revision 1.16 2002/03/29 17:19:51 armin
  495. + allow exports for netware
  496. Revision 1.15 2002/03/19 20:23:57 armin
  497. + smart linking now works with netware
  498. Revision 1.14 2002/03/04 17:54:59 peter
  499. * allow oridinal labels again
  500. Revision 1.13 2002/03/03 13:00:39 hajny
  501. * importprocedure fix by Armin Diehl
  502. }