WARNING! WARNING! WARNING! WARNING! WARNING! WARNING!
-----------------------------------------------------
THIS DOCS ARE OUTDATED! I have no time to write down
precise docs, so please be patient.
-----------------------------------------------------

============================================================================
		     DYNAMIC LINK MODULES MANUAL
============================================================================

     This file contains almost all information you will need to work
 with DLMs. If you need to know internals, please look in source and
 techinfo.txt

 AUTHOR    : Ilya P. Ryzhenkov
 E-MAIL    : orangy@inetlab.com

 Internet locations :

 HTTP page : http://solo.iis.nsk.su/orangy/dlm
 FTP site  : ftp://solo.iis.nsk.su/pub/djgpp/dlm

 Table of Contents
 =================
 1. What is DLM ?
 2. What do I need to use DLMs ?
 3. DLM Manager
    3.1 How to use DLM Manager.
    3.2 List of DLM Manager features
 4. DLM Stub
    4.1 How to use DLM Stub API ?
    4.2 Using Extra Symbols
 5. API Reference
 6. Notes on using DLMs with C++ programms
    6.1 Named Classes
 7. Making DLM projects (Sample Makefile)

==========================================================================
 1. What is DLM ?
==========================================================================
     DLM  stands  for  "Dynamic  Link  Module".  DLM  engine creates
 environment,  which allow you to link different modules together at
 run-time.  The  way  it  works  is  similar  to  the  static linker
 functionality,  but  is  performed  during  program execution. Many
 popular  systems,  that  allow dynamic loading and using of modules
 (or  libraries)  use  the  "ask-me-for-a-pointer"  scheme.  In such
 environments  you  must first load module, than ask for pointer and
 then  reference  data	and/or code via pointer. Also you can't have
 unreferenced symbols left in your code in this systems (for example
 Windows DLL and so on).
     Unlike  all  of  this  DLM environment allows you to write your
 source code as if there would be static linkage (and you really can
 use  the  same  source  code  without	ANY changes for DLM-oriented
 version and static linked version by creating some #defines).
     There is no special syntax for calling functions or referencing
 data  from  other  DLMs.  For	example,  let  func()  be defined in
 some.dlm. You can use it like :

   if ( ! LoadDLM( "some.dlm" ) )
     printf( "Can't load DLM some.dlm\n" );
    else
     func();

===========================================================================
 2. What do I need to use DLMs ?
===========================================================================
 DLM package consist of 3 parts :
  1: DLM Manager   -- The program designed to create/manage DLMs
  2: DLM Stub	   -- DLM Engine, used at run-time
  3: DLM Libraries -- Set of DLMs, which are used except libc,
		      libgpp, etc

     Usually  you  will  need  all of them to produce a program, but
 you can't produce anything runnable without DLM Manager and DLM Stub.

==========================================================================
 3. DLM Manager
==========================================================================
 DLM Manager is a command-line program, which allows you to produce DLMs
 from object files, edit AutoLoad list, dump various information from
 DLM (like export or import list) and many other. DLM Manager is usually
 used in Makefile.

==========================================================================
 3.1 How to use DLM Manager.
==========================================================================
 DLM Manager can manage two types of input files ;
  1: .dlm   Files of DLM format, native files in DLM System
	    Most operations are allowed only on .dlm files.
  2: .o     COFF files, native files for DJGPP. They are produced
	    by compiler or linker (using -r option) and can be
	    converted to .dlm files with DLM Manager.

 DLM Manager can be started without parameters for quick help.
 Syntax of envoking DLM Manager is :
 dlmman <inputfile> [options ...]

 <inputfile> must be present and it's type (COFF or DLM) is known from
 the option's list.

 This is the brief description of the options, as DLMMAN types beeing
 envoked without parameters :

  -q			  print only fatal messages
  -e <exename>		  create executable from given DLM
  -ec <exename> 	  create executable from given obj
  -d <dumpfile> 	  dump DLM structure to <dumpfile>
  -dx <exportfilename>	  generate list of import symbols
  -di <importfilename>	  generate list of export symbols
  -da <fname>		  append list of export with DLM name to file
  -dl <fname>[,<dalname>] generate DAL - list of needed DLMs
			  uses DLM's import and <fname> file as input data
  -c <dlmname>		  convert object file to DLM
  -s <symbolname>=<fname> add extra symbol to DLM with the contents of file
  -rs <symbolname>	  remove extra symbol
  -a <stubname> 	  use alternate stubfile
  -l <dlmname>|<&dalname> add an Auto-Load DLM
			  & at begining of filename means file contains list
  -rl <dlmname> 	  remove an Auto-Load DLM
  -u <exportfilename>	  use export list file instead of implicit rules

 Input file is assumed to be COFF if options -c or -ec was given and to
 be DLM in other cases. Options can be combined in most cases, except
 the following rules :
  -e	can't be combined with	  -ec, -c, -da
  -dx	can't be combined with	  -u

 All options (except -q) can be followed by output filename. This file
 name is used only for preceding option. If file name is ommited, implicit
 rules are used and output file name is generated from input file name by
 changing the suffix. For example :

  dlmman myfile.o -c		    // will create myfile.dlm
  dlmman myfile.o -c super.dlm	    // will create super.dlm from myfile.o
  dlmman super.dlm -d -da total.exp // will dump information about super.dlm
				       to file super.dmp and append list
				       of it's exports to file total.exp

 Standart suffix replaces are :
  .DLM for -c and -s
  .EXE for -ec and -e
  .DMP for -d
  .EXP for -u and -dx
  .IMP for -di
  .LST for -da
  .DAL for -dl

 Next section will describe all features in details.

==========================================================================
 3.2 List of DLM Manager features
==========================================================================
  -q
      This options was intended for use in batch files, scripts and
      Makefiles. It disables printout of normal process indication
      messages. Fatal errors and warnings still will be displayed.

  -e <exename>
      This one instruct DLM Manager to create EXE file from DLM file,
      using the DLM Stub. The stub must be :
       - explicitly defined by -a option
       - defined by an environment variable DLMSTUBNAME which must be
	 a full path to Stub file. For example :
	  SET DLMSTUBNAME=w:\djgpp\dlm\dlmstub.exe
       - dlmstub.exe in the current directory.
      All other operations in command line are performed on temporary
      DLM image in memory *before* converting, so the input DLM will not
      be affected, but EXE file will contain DLM with operations performed.

  -a <stubname>
      Explicitly specify Stub file name.

  -ec <exename>
      This is similar to -e option, instead of the fact, that input COFF
      file is first converted to temporary DLM in memory.

  -d <dumpfile>
      This option writes information about DLM in the dumpfile :
       - Section list :
	 name,virtual address, size of section, offset in DLM file, flags
       - Relocation list :
	 reloc place, type, value at reloc place, symbol index,
	 symbol value, symbol name
       - Symbol list :
	 seq number, flags, value, name
	 FLAGS are: E=Export, I=Import, S=Section, C=Common.

  -dx <exportfilename>
	 Dumps list of EXPORT names to specified file. File is overwritten.

  -di <importfilename>
	 Dumps list of IMPORT names to specified file. File is overwritten.

  -da <fname>
	 Appends list of EXPORT names together with DLM name to specified
	 file. Intended for use with -dl options.

  -c <dlmname>
	 This option converts input COFF file to DLM file. Remaining options
	 are performed before writing output DLM.

  -s <symbolname>=<filename>
	 This option will add contents of the file <filename> to the DLM
	 and define an EXPORT symbol, which will be the representation
	 of the file during runtime. Don't forget about leading underscore.
	 Such symbol is called Extra Symbol.

  -rs <symbolname>
	 This one will remove Extra Symbol.

  -l <dlmname>
  -l &<dalname>
	 Add <dlmname> or all filenames from the file <dalname> to the
	 AutoLoad list. This DLMs will be treated as REQUIRED for DLM,
	 they will be loaded *after* loading DLM, but *before* calling
	 to constructors. If any AutoLoad DLM was failed to load
	 succesfully (either internal DLM error, or constructor
	 returned 0), the original DLM will not be loaded. If you
	 want flexible control of what is happening - use constructors
	 and LoadDLM(char *) function.

  -dl <fname>[,<dalname>]
	This option helps in creating list of autoload DLMs and organizing
	project. <fname> must be a file created by several usage of -da
	option. <dalname> is output file, which will contain list of DLMs
	needed by current one. The list is generated using IMPORT
	information of current DLM. Say, current DLM contains IMPORT
	symbol `_malloc'. DLM Manager will search through <fname> for
	that symbol and find, for example, that `_malloc' is defined in
	libc.dlm. Than libc.dlm will be added to the output list.

  -rl <dlmname>
	Remove specified DLM from AutoLoad list.

  -u <exportfilename>
	Usually all names, that are not local or static will go to the
	EXPORT list. If you want to hide out some of them - you will
	use this option. If this options is specified, only those symbols
	that appear in file <exportfilename> will be exported. The best
	way is to use -dx option to get the complete list of available
	EXPORT symbols, edit it, and use -u option to update EXPORT list.

 Uhhh, that's all ! ;-)

==========================================================================
 4. DLM Stub
==========================================================================
     DLM  Stub	is the run-time engine, which will be started before
 your  program and will service all the stuff and features. It is an
 EXE  program,	which starts, initialize itself and attempts to load
 Main  DLM  from  the  EXE file (argv[0]). Main DLM is the first DLM
 which	is  loaded  and  it  must either contain main() or load (via
 autoload or in constructor) DLM which contains this function. After
 Main DLM is loaded function main() is called.
     If  constructor()	of  Main  DLM or any of it's autoloaded DLMs
 return  0,  or some DLM which must be autoloaded doesn't exists, or
 even  if  there  is  no  DLM  in  EXE	(i.e.  you  attempt to start
 dlmstub.exe itself) -- DLM Stub exits with the message
       "FATAL: DLMStub was failed to load DLM from executable"

     Another reason of fault can be absence of main() function after
 loading sequence completed.

 After main() was called, your programm continues execution in normal way.
 You can call some libc functions without loading any DLM, as they are
 already used in DLM Stub and are exported implicitly. If you need other
 you have to load libc.dlm. List of implicitly exported functions can be
 found in file impl_exp.txt

==========================================================================
 4.2 How to use DLM Stub API ?
==========================================================================
     Simple!  Call  appropriate  functions and that's all ! See next
 section for the complete list of API functions.

==========================================================================
 4.2 Using Extra Symbols
==========================================================================
 Extra Symbols are special symbols, that are placed to DLM using
 DLM Manager -s option. They handle contents of some file, that was
 placed into DLM. Note, symbol is NOT a pointer to file contents, it IS
 file contents. For example :

 --- begin DLM source test.c ---
 #include <stdio.h>
 char text;
 void main()
 {
  // printf is exported implicitly, see section 4.
  printf("%s",&text); // You need here pointer to string.
 };
 --- end DLM source test.c ---
 Commands :

 gcc -o test.o -c test.c
 dlmman test.o -ec -s _text=somefile.txt
 // Note: leading underscore must be present !
 // Note: somefile.txt must be null-terminated !
 test
 // will print contents of somefile.txt

 You can obtain size of data referenced by such symbol by using
 SizeofDLMSymbol() function. See section 5.

==========================================================================
 5. API Reference
==========================================================================
 A list of DLM Engine functions and their descriptions. Brief info
 is also available in dlmlib.h file.

 int LoadDLM(char *path);
 ------------------------
    This function will load DLM from file pointed by path.
    If path is a single filename (i.e. filename.ext) then additional
    DLMPATH search is perfomed. Refer to description of SetDLMSearchPath
    for more information.
    Return value is 1 on success, 0 on fail.
    On fail dlmerrno is set to DLM Engine error code. (Described below)

 int UnloadDLM(char *path);
 --------------------------
    This function will unload DLM, specified by path. Path must be
    *exactly* the same, as was given to LoadDLM function.
    Return value is 1 on success, 0 on fail.
    On fail dlmerrno is set to DLM Engine error code. (Described below)

 int isLoadedDLM(char *path);
 ---------------------------
    Return 1 if DLM is loaded, 0 otherwise.

 void SetDLMSearchPath(char *searchpath);
 ----------------------------------------
	Set  DLM  Engine's  internal  string, which is used when you
    give  single  filename  (i.e. filename.ext) to LoadDLM function.
    Format  is	list  of  directories  (trailing  backslash  must be
    present) separated by ';'. For example :
    "w:\\djgpp\\dlm\\dlms\\;w:\\djgpp\\dlm\\project\\dlms\\;.\\"
	If  search  path is set, LoadDLM doesn't attempt to load DLM
    from   current   directory.  It  instead  loops  through  listed
    directories,  appends  given filename to everyone and checks for
    file existense. When file was found it loads it.
	At  startup  DLM  search  path	initialized with environment
    variable DLMPATH, if it doesn't exists search path is NULL (i.e.
    only current directory).

 void *LookupDLMSymbol(char *name);
 ----------------------------------
	If  EXPORT  symbol with the given name exists, this function
    returns it's address, otherwise it returns NULL.

 unsigned long SizeofDLMSymbol(char *name);
 ------------------------------------------
	This  function	returns  size  of the symbol, that was added
    using  DLM	Manager's  -s  option.	See  section  4.2  for	more
    information about Extra Symbols.

 extern int dlmerrno;
 --------------------
   This variable contains DLM Error code, which describes what happened,
   if LoadDLM or UnloadDLM returns 0
   This is the list of available Error Codes :

   DLM_ENOERR  No error
   DLM_ENOMEM  Not enough memory
   DLM_EFILE   File I/O error (check errno)
   DLM_EALOAD  DLM Already loaded
   DLM_ENODLM  DLM was not loaded
   DLM_ECTOR   DLM's constructor() returned zero
   DLM_EINVF   Not DLM file
   DLM_EAUTO   DLM Auto-Loading failed

 extern int dlmflags;
 --------------------
   This variable controls overall DLM engine behavior
   DLMFLAG_DUP	 Mask for dlmflags to get/set behavior concerning
		 duplicate symbols

   DLMFLAG_DUP_IGNORE	Ignore symbols already exists in EXPORT table
   DLMFLAG_DUP_OVRIDE	New symbol will override those already exists,
			refixup will be performed. All subsequent
			calls/references to export symbol will go to
			the last one.
   DLMFLAG_DUP_FUTURE	New symbol will override those already exists,
			refixup will NOT be performed. All
			calls/references already fixuped will stay as
			they are. All subsequent requests for the symbol
			will return new value.
   DLMFLAG_DUP_FAIL	Any duplicate symbol will result in program
			exit with appropriate message.

   Default value is DLMFLAG_DUP_OVRIDE

 int ExportDLMSymbol(char *name,void *address);
 ----------------------------------------------
   This function is a wrap to internal symbol processing, so
   use EXTREMLY careful! For Expert's use only !
   
   It explicitly adds name:address pair to EXPORT table and
   refixups all references in usual way.

 int RemoveDLMSymbol(char *name);
 --------------------------------
   This function is a wrap to internal symbol processing, so
   use EXTREMLY careful! For Expert's use only !

   It explicitly removes name from EXPORT table and
   refixups all references in usual way.


 For explanation of DLM_USE_NAMEDCLASS and DLM_EXP_NAMEDCLASS(name)
 macros refer to Section 6.1
 
==========================================================================
 6. Notes on using DLMs with C++ programms
==========================================================================
     DLM engine support all common C++ mechanisms, like inheritance,
 virtual  functions, etc. It doesn't require any special syntax. You
 can  use  static  class  instances,  dynamic  objects	(via new and
 delete), and so on. But in some situations DLM engine will not have
 enough  information  to  succesfully  manage  your  programm if you
 will  not  follow some rules, described below. You also must either
 auto-load CPP.DLM or load it explicitly in DLM's constructor().

 What to have in mind, while using DLMs and C++ :
 1. Avoid using inline methods and NEVER use inline constructors.
    They will possibly not work in some situations.
 2. Static objects are created AFTER call to constructor(), so
    don't use them in constructor. Functions with `constructor'
    attribute are called like static object's constructors ...
 3. If you are using NAMED CLASSES feature (later about it)
    NEVER call Named New from the same file, where constructor
    is DEFINED. Named New will surely fail in this case
    and produce SIGSEGV...

 SUMMARY : To have less trouble with C++ use the following scheme
 in defining classes :
 1. Create class declaration and put in .h file
 2. Create SEPARATE file, in which ONLY ONE class will be DEFINED.
    You also can put many class definitions in one file, if you are
    not using named classes in that module.

==========================================================================
 6.1 Named Classes
==========================================================================
 NAMED CLASS - what the beast is it ?

 DLMs give your unique feature - create an instance of a class if you
 have the following information :
 1. You know it's name as a string (char *)
 2. You know (i.e. have a DECLARATION of) the class, which is
    higher in the hierarhy (i.e. any of parent class). You will
    need this to able to call virtual functions and construct objects.
 3. Someone who knows (have a DECLARATION of) this class used special
    macro to make this class available for others.

 The syntax is the following :
 In the EXPORTER module, i.e. where the class was DEFINED.
   DLM_EXP_NAMEDCLASS(class_identifier)
 This one is needed to obtain sizeof(class_identifier) at run-time.

 In the IMPORTER module, i.e. where you want to create instance of such
 class.
   DLM_USE_NAMEDCLASS /* No name here! This macro allows usage of any class */

 To create instance :
  new("class_identifier") Known_Base_Class_identifier( parameters );

 This command will call class_indetifier's (NOT Base's!) constructor with the
 given parameters. It's obvious, that you must HAVE constructor with
 such prototype.

==========================================================================
 7. Making DLM projects (Sample Makefile)
==========================================================================
     Here  is  sample Makefile for compiling DLM-based project. It's
 quite simple and was putted here for those, who don't want to do it
 themselfs.

--- Makefile start ---

# Options passed to GCC when creating .o files
# We don't need options for GCC linkage stage, as we don't need
# any linkage
CC_OPT=-O3 -Il:\djgpp\include -Wall

# This is name of file, which will became an EXE instead of DLM
MAINFILE=program

# This is a list of space separated file names for DLMs
DLMLIST=mydlm

# BUILD is a list of files to create
# It is generated from DLMLIST by appending .dlm and
# from MAINFILE by appending .exe
BUILD=$(foreach name, $(DLMLIST), $(name).dlm) $(MAINFILE).exe

# REMOVE is a list of files to remove, when you type 'make clean'
REMOVE=$(foreach name, $(DLMLIST), $(name).dep $(name).o $(name).dlm) $(MAINFILE).o $(MAINFILE).exe $(MAINFILE).dep

# SOURCES is a list of source files. Change it if you use .c instead of .cc
# It is used when creating dependencies
SOURCES=$(foreach name, $(DLMLIST), $(name).cc) $(MAINFILE).cc

# DEPLIST is a list of dependency files
DEPLIST = $(foreach name, $(DLMLIST), $(name).dep) $(MAINFILE).dep

# Command line to create one .dep file from .cc file
MAKEDEPS=$(CC) -MM $< | sed -e 's/\($*\.o\)[ :]*/\1 $@ : /g' >$@

all : start $(BUILD) done

start :
	@echo Building : $(BUILD)

done :
	@echo Done.

clean :
	@echo Removing rebuildable files :
	@echo $(REMOVE)
	@rm -f $(REMOVE)

%.dep: %.cc
	@echo Creating dependencies for $<
	@$(MAKEDEPS)

deps : $(DEPLIST)
include $(SOURCES:.cc=.dep)

# This rule is used when .dal file exists.
# Refer to DLM Manager description for -l option

%.dlm: %.o %.dal
	@echo Creating $@ : $^
	dlmman $*.o -q -c -l &$*.dal

# This rule is used when .dal file not exists.
%.dlm: %.o
	@echo Creating $@ : $^
	dlmman $*.o -q -c

%.exe: %.o %.dal
	@echo Creating $@ : $^
	dlmman $*.o -q -ec -l &$*.dal

%.exe: %.o
	@echo Creating $@ : $^
	dlmman $*.o -q -ec

%.o: %.cc
	@echo Creating $@ : $^
	gcc $(CC_OPT) -c $< -o $@
--- Makefile end ---

==========================================================================
 To be continued ...

 Have a fun !			DLMs was given to you by Ilya P. Ryzhenkov
				Contact me by e-mail : orangy@inetlab.com
