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 [options ...] 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 create executable from given DLM -ec create executable from given obj -d dump DLM structure to -dx generate list of import symbols -di generate list of export symbols -da append list of export with DLM name to file -dl [,] generate DAL - list of needed DLMs uses DLM's import and file as input data -c convert object file to DLM -s = add extra symbol to DLM with the contents of file -rs remove extra symbol -a use alternate stubfile -l |<&dalname> add an Auto-Load DLM & at begining of filename means file contains list -rl remove an Auto-Load DLM -u 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 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 Explicitly specify Stub file name. -ec This is similar to -e option, instead of the fact, that input COFF file is first converted to temporary DLM in memory. -d 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 Dumps list of EXPORT names to specified file. File is overwritten. -di Dumps list of IMPORT names to specified file. File is overwritten. -da Appends list of EXPORT names together with DLM name to specified file. Intended for use with -dl options. -c This option converts input COFF file to DLM file. Remaining options are performed before writing output DLM. -s = This option will add contents of the file 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 This one will remove Extra Symbol. -l -l & Add or all filenames from the file 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 [,] This option helps in creating list of autoload DLMs and organizing project. must be a file created by several usage of -da option. 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 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 Remove specified DLM from AutoLoad list. -u 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 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 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