Go Back to the Home pageEnhanced Dynamic Linking Library
for MinGW under MS-Windows

Reference Manual (Version 0.6)


Introduction

The edll is a C library with only a few functions you can use to load modules dynamically under MS-Windows. It requires you to have the BFD library for the final linking.


Summary

License

Requirements

Versioning your application and modules

#define's
EDLL_ADDLIB
EDLL_VERSION
Typedef's
edll_check_version
edll_errno_t
edll_module
edll_mutex_geterror
edll_mutex_lock
edll_mutex_seterror
edll_mutex_unlock
edll_ptr
Functions
edll_alloc
edll_callback_register
edll_close
edll_exit
edll_free
edll_geterror
edll_getsearchpath
edll_getversion
edll_init
edll_module_version
edll_msym
edll_mutex_register
edll_open
edll_realloc
edll_seterror
edll_setsearchpath
edll_setunixsearchpath
edll_set_self_version
edll_strerror
edll_sym
Undefined Symbols and Unresolved Symbols

Known Bugs & Limitations


License

This document is covered by the GNU documentation license.

Copyright (c) 2005-2006  Alexis Wilke.
Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.1
or any later version published by the Free Software Foundation;
with the Invariant Sections being "Introduction" and "License",
with no Front-Cover Texts, and with no Back-Cover Texts.
A copy of the license is included in the section entitled "GNU
Free Documentation License".


The edll library is covered by the LGPL plus the following paragraph:

I hereby authorize anyone to use this library in closed source
software. However, if you make any modification to the library,
you must make these changes available to everyone (preferably
sent to me, but this is not a requirement.)


Different files included in this package are covered by different licenses as explained in the Project Licenses page.



Requirements

The following is what you need to use the edll project.

I added some version information. Older versions may still work with edll. Since version 0.3, edll uses a GNU Compatible configure script. For this reason, you will need the MSYS environment in order to create the library.

A quick How To Install MinGW and edll

There is an ltdl.c/h set of files from some old binutils (binutils-2.13.90-20030111-1.tar.gz). It still compiles and works fine. If you have an application written in Unix which uses the ltdl to load modules, then you should not have to change anything to use edll. It is otherwise not required to use ltdl.

See the README file for more information about the options available to the edll configure script.

If you have any problems with some older versions of some of these tools, update them first. Note that newer versions may also break the library. It is very sensitive to the BFD library...


Versioning your application and modules

WARNING: in order for the version feature to be available you have to make sure you configured the library with the --enable-versioncheck option; if not you will need to recompile it (you do not need to reconfigure, you can just edit the configuration file and change the #undef VERSION_CHECK by #define VERSION_CHECK 1)

The edll library can now read the .version section of you executable and modules. For this feature to work, you need to have a .version section. However, by default, your linker will remove the .version section since it does not know anything about and it will assume that once linked, the program does not need it.

I offer two solutions to this problem.
  1. The simplest one is to make a call to the edll_set_self_version() function. This function saves a version string for later use by the edll library to check the modules.
  2. The slightly more complicated solution is to modify the linker scripts. The GNU linker from the binutils uses a script to describe how the linker is supposed to handle the different sections. There are different scripts and it could be that you need to include that in different scripts. At this time, I tried and it worked by only changing the i386pe.x script. I include a patch in the edll package (dev/version.patch) that you can apply to that file. Though you can easilly fix any problems by reinstalling the binutils if something goes wrong, I suggest you make a copy of the file before you apply the patch.
The second solution is of course the neatest since you will have nothing more than to use EDLL_VERSION() in your source file to print the version in your application.

The other problem with the versioning is that by default the library will compare versions with strcmp(). They need to be strictly equal for the module to be acceptable and thus loaded. If that fails, you will not be able to load that plugin. You can, however, create your own function to compare two versions. The function will be called each time a module is loaded. You define that function with a call to the edll_callback_register() function.


LIBRARY

edll

NAME

EDLL_ADDLIB — add a library reference in a plug-in
EDLL_VERSION — define the version of a module

SYNOPSIS

#define EDLL_ADDLIB(name) ...
#define EDLL_VERSION(version) ...

PARAMETERS

name — the name of the library to load so the plug-in symbols can be resolved
version — a string representing the library version (i.e. "1.0")

DESCRIPTION

The EDLL_ADDLIB() macro was created to enable the users to create a .load section with the names of the libraries and other plug-ins to load before this plug-in symbols can all be resolved. It is strongly recommended that only the libraries and other plug-ins which are required be included in this section. The edll always loads all of the dependencies defined in a .load section and it can use a lot of memory to specify too many entries here.

The EDLL_VERSION() macro is a helper to define the version of a module. At this time, the macro creates a string that it saves in a section named .version. When an application or a module attempts to load a module and the versions do not match, then an error is generated and the loading fails. With edll_callback_register, the user can specify the comparison function if a strictly equal algorightm would be to stringent.

NOTES

The EDLL_ADDLIB() will ultimatly be replaced by the use of the -l option on the linker command line as it would be expected. Also, at that time, the linker could test whether a library is used to resolve any symbol. If not, it could then be removed from the list of dependencies.

RETURN VALUE

These macros declare data. There is no returned value.

BUGS

The EDLL_VERSION() macro works, but by default the linker will remove the .version section when linking an executable. Thus your application can find itself without a version and in that case no comparison will take place. You have two ways to fix that problem: (a) you apply the dev/version.patch to your ldscripts/i386pe.x file. This will prevent the loader from losing the .version section and (b) you can use the edll_set_self_version() function to define the version of the application.

SEE ALSO

edll_open, edll_check_version, edll_callback_register, edll_set_self_version


LIBRARY

edll

NAME

edll_module — the edll module handle

SYNOPSIS

typedef struct edll_module_struct edll_module;

DESCRIPTION

The edll_module type defines an edll module. The structure itself is private. You will only be able to use pointers to edll modules.

You get a new pointer whenever you call the edll_open() function. You get rid of the pointer whenever you call the edll_close() or edll_exit() functions.

SEE ALSO

edll_open, edll_close, edll_exit


LIBRARY

edll

NAME

edll_ptr — edll non-specific pointers

SYNOPSIS

typedef void *edll_ptr;

DESCRIPTION

The edll_ptr type defines a non-specific data pointer.

This type is used to return symbol address pointers. Also the different memory functions use it.

SEE ALSO

edll_sym, edll_msym, edll_alloc, edll_realloc, edll_free


LIBRARY

edll

NAME

edll_check_version — function used to compare two versions for validity

SYNOPSIS

typedef int (*edll_check_version)(const char *self_version, const char *module_version);

DESCRIPTION

The edll_check_version type is used whenever a version is defined in a module being loaded. When this function is not defined, the system uses strcmp() and both versions need to be exactly equal. If you need a better test so as to allow older or newer versions too, then you will need to write your own.

The function is called with two strings. The self version which represents the version of the application. And the module version which is the one version you want to validate.

The function needs to return zero (0) if the versions do not match (i.e. you want to refuse this module) and return any other values to say that the version is valid (the loading of the module will proceed.)

SEE ALSO

edll_callback_register


LIBRARY

edll

NAME

edll_errno_t — edll error type

SYNOPSIS

typedef enum edll_errno_num { ... } edll_errno_t;

DESCRIPTION

The edll_errno_t type is used by the edll library to define error numbers.

Whenever a function returns a value which represents an error (-1 when int is returned and NULL when a pointer is returned), an error is set in the edll library. The type of this error is always edll_errno_t.

The errors are handled by the edll_geterror(), edll_seterror() and edll_strerror() functions.

SEE ALSO

edll_geterror, edll_seterror, edll_strerror


LIBRARY

edll

NAME

edll_mutex_geterror — a function used to rerieve the last error set  in the current thread
edll_mutex_lock — a function used to prevent multiple threads from using the library at the same time
edll_mutex_seterror — function used to change the error code in the current thread
edll_mutex_unlock — the function to undo a lock

SYNOPSIS

typedef void (*edll_mutex_lock)(edll_ptr userdata);
typedef void (*edll_mutex_seterror)(edll_ptr userdata, edll_errno_t err);
typedef void (*edll_mutex_unlock)(edll_ptr userdata);

PARAMETERS

userdata — a pointer to some data you specify to the registration function
err — the error number representing what just happened

DESCRIPTION

The edll_mutex_lock type defines a function used to protect areas of code in the library so multiple threads can use it safely. All the common data managed calling these functions. The way the lock itself is done it not specified in the edll library.

The edll_mutex_unlock type defines the function which undoes the lock created with the edll_mutex_lock.

The edll_mutex_seterror type defines a function used to save an error code specific to a thread. Note that you do not have to save the error code, you may use it right away. In that case you do not have to define an edll_mutex_geterror since it would not be in sync anyway. The function receives the error code as its second parameter.

The edll_mutex_geterror type defines a function used to retrieve an error previously saved calling the edll_mutex_seterror function. Note that the library doesn't test whether you set one or both of the error functions. It is suggested that you set either only the set or both. Defining only the get would not make sense.

Note that all of these functions can't fail. The userdata is the same as the one passed to the registration function edll_mutex_register().

EXAMPLE

If you are using the pthread library, then the lock and unlock can be as simple as follow:
my_mutex_lock(edll_ptr mutex)
{
pthread_mutex_lock((pthread_mutex_t *) mutex);
}

my_mutex_unlock(edll_ptr mutex)
{
pthread_mutex_unlock((pthread_mutex_t *) mutex);
}
Note that this code assumes you register the lock & unlock functions using the pthread mutex variable as the userdata pointer.

RETURN VALUE

Note that none of these functions can fail.

Only the edll_mutex_geterror function returns a value which has to be the last error set with edll_mutex_seterror.

SEE ALSO

edll_mutex_register, edll_errno_t, edll_ptr, edll_geterror, edll_seterror


LIBRARY

edll

NAME

edll_getversion — retrieve the library version
edll_init — the library initialization function
edll_exit — the library clean up function

SYNOPSIS

extern const char *edll_getversion(void);
extern int edll_init(void);
extern int edll_exit(void);

DESCRIPTION

If you want to make sure that the proper version of the edll library is available at runtime, then call edll_getversion() and test the returned string version. The latest version string is "0.6". (See the Internet version of this documentation for a valid version string here.)

Before to use the edll library, you must call the edll_init() function. Some functions will fail if the library wasn't first initialized.

Once you are finished with the edll library, call the edll_exit() to release all the resources used by the library. This function has the side effect of closing all the plug-ins. This means you need to make sure you won't use any of the plug-ins after this call and also that the function isn't being called from a plug-in.

For your information, the initialization call will initialize the BFD library as well. Note that there are no function to clean up the BFD library. I do not know whether there is a need to clean up anything though.

You can call the edll_init() multiple times. For each time you called the initialization function, you need to call the edll_exit() function. The last call to edll_exit() will release the plugins. The other calls merely decrement a reference counter.

RETURN VALUE

edll_init returns 0 when the initialization succeeds
edll_exit returns 0 when it can properly close the library, -1 otherwise; the function returns 0 even if the plugins are not removed (i.e. the reference counter didn't reach 0 yet)
edll_getversion returns a read-only string with the current version of the library

BUGS

You have to make sure that you do not use DLLs and plug-ins which have been loaded with the edll library after you called the edll_exit() function.

SEE ALSO

edll_close


LIBRARY

edll

NAME

edll_alloc — allocate a block of memory
edll_realloc — reallocate a block of memory (usually to resize it)
edll_free — free a block of memory allocated with edll_alloc or edll_realloc

SYNOPSIS

extern edll_ptr edll_alloc(int size, int clear);
extern
edll_ptr edll_realloc(edll_ptr rptr, int size, int oldsize);
extern void edll_free(edll_ptr ptr);

PARAMETERS

size — the size in bytes of the block of memory to be allocated
clear — whether to clear the allocated buffer
rptr — the pointer to the buffer to resize
oldsize — the size of the buffer before this allocation happens
ptr — a memory buffer pointer to free

DESCRIPTION

The edll library manages memory using the edll commands edll_alloc(), edll_realloc() and edll_free().

There is one exception: the memory used to load the section content directly calls the VirtualAlloc(). However, this shouldn't be a problem since you don't have direct access to section start pointers.

All memory pointers allocated by the edll library and returned to you need to be freed using the edll_free() function.

The edll_alloc() function allocates a buffer of at least size bytes. Whenever the parameter clear is true (non-zero), the buffer is cleared before the function returns.

The edll_realloc() function is very similar to the edll_alloc() function. It will allocate a new buffer of memory if the rptr parameter is zero. The new size is specified in the size parameter. If the new size is larger than the old size of the buffer (and the old size parameter is specified) then the memory area used to enlarge the buffer will be cleared. Use an old size of -1 to avoid this effect.

The edll_free() function frees a buffer of memory which has been allocated with either of edll_alloc() and edll_realloc().

NOTES

The memory management functions are currently available before you call the edll_init() function. This may change in the future.

SEE ALSO

VirtualAlloc, VirtualProtect, edll_getsearchpath


LIBRARY

edll

NAME

edll_callback_register — register a set of callbacks

SYNOPSIS

extern void edll_callback_register(edll_check_version check_version_func);

PARAMETERS

check_version_func — the version function to call to compare versions

DESCRIPTION

The edll supports some callbacks which are explained here.
The edll library can determine the version of your application and of each module that it loads.

If the application has no version, then no version will ever be checked.

By default, the edll will compare the version strings with strcmp() and if not strictly equal, it will fail the loading of the module.

In order to make the comparison more complex, you can write your own function to, for instance, accept any older or any newer version of the module.

Please, see the definition of the callback function edll_check_version for more information on how you can define your own function.

NOTES

The version feature is optional. You have to make sure that your edll library was configured with the --enable-versioncheck option. You can look in the edll-config.h file and seach for #undef VERSION_CHECK (no version support) or #define VERSION_CHECK 1 (version support enabled).

BUGS

By default, the version of the application will not stick to your .exe file. This is because the linker removes the .version section when it creates the .exe file. You have two solutions to fix the problem: (a) you can call the edll_set_self_version() function to define the version at run time or (b) apply dev/version.patch to your ldscripts/i386pe.x file.

SEE ALSO

edll_check_version, edll_set_self_version()


LIBRARY

edll

NAME

edll_open — load a plug-in in memory and reallocate it
edll_close — close a module which has previously been opened with edll_open

SYNOPSIS

extern edll_module *edll_open(const char *filename);
extern int
edll_close(edll_module *module);

PARAMETERS

filename — the name of the plug-in or DLL to load with edll
module — the module to be closed

DESCRIPTION

The edll library loads modules with the edll_open() function. That function searches for the filename in the different directories as specified by the search path. The edll_open() function returns a module pointer. You should always call the edll_close() with all the modules that you open with edll_open(). The close is automatically called whenever you exit the library (see edll_exit())

SEE ALSO

edll_setsearchpath


LIBRARY

edll

NAME

edll_sym — search for a symbol in the specified module
edll_msym — search for a symbol in all the module

SYNOPSIS

extern edll_ptr *edll_sym(edll_module *module, const char *name);
extern edll_ptr *
edll_msym(edll_module **module_ptr, const char *name);

PARAMETERS

name — the name of the symbol to search
module — the module where the symbol is searched (dependency modules can't be reached from this variable); if NULL, search all the modules
module_ptr — a pointer to a module pointer; if NULL, does not return the pointer to the module found and search all the modules

DESCRIPTION

The edll library loads all the modules in a list which is globally managed. When you need to find a symbol you can either specify the module in which you want to search or use NULL as the module pointer (i.e. search in all modules).

Note that edll keeps a single list with all the symbols. This means is does a single binary search to find the symbol (the symbols are kept in alphabetical order.) Also, since we have that unique list, even when you request a search in a single module, it will still take the same amount of time to find the symbol (it can actually be slightly slower to search a single module.)

The edll_sym() function searches for the specified symbol in the list of symbols of the specified module. Note that if the module is a DLL, the names are not currently being cached by the edll.

The edll_msym() function (it could have been called: edll_module_sym()) uses a pointer to a module which is filled by the lower level search function. It specifies in which module the symbol can be found.

Note that both functions can be used with the module pointer set to zero (0 or NULL). In that case, it will return a pointer to the symbol that it finds searching all the DLLs and plug-ins already loaded by the application.

RETURN VALUE

Both functions will return a NULL pointer when an error occurs (usually, symbol not found.)

BUGS

Symbols should be unique among all the modules compositing one application. The edll won't fail loading such applications, however, there is no guarantee that the same symbol will be returned by the edll_sym() and edll_msym() functions unless you force which module needs to be searched.

There is a potential bug with symbols: their value can change without your knowledge. [if I think about it later, I will elaborate about this one...]

SEE ALSO

edll_open


LIBRARY

edll

NAME

edll_seterror — set the current edll error
edll_geterror — get the current edll error
edll_strerror — get a string for the current edll error

SYNOPSIS

extern edll_ptr *edll_seterror(edll_errno_t err);
extern edll_errno_t *
edll_geterror(void);
extern const char *edll_strerror(void);

PARAMETERS

err — a valid edll error number

DESCRIPTION

The edll library maintains its own private error number variable.

The error number can be set with edll_seterror() and checked out by the edll_geterror().

A string corresponding to the error number can also be queried for. This is done using the edll_strerror() function.

In multi-thread application you need to specify a function to set errors and one to get errors (see edll_mutex_register() for more information about how to define these functions.) You can either act immediately on errors when your set function is called, or save the error in a thread specific array of some sort. If you act immediately, you will certainly not need to have a get function. Otherwise, the get function needs to retrieve the error specific to the running thread.

RETURN VALUE

The edll_seterror() function doesn't return anything.
The edll_geterror() function returns the current error number
The edll_strerror() function returns a static const string from

SEE ALSO

edll_errno_t, edll_mutex_register(), edll_mutex_seterror, edll_mutex_geterror


LIBRARY

edll

NAME

edll_setunixsearchpath — set a Unix like set of paths to use to find the specified modules
edll_setsearchpath — set a MS-Windows set of paths to use to find the specified modules
edll_getsearchpath — get a copy of the current search path

SYNOPSIS

extern int edll_setunixsearchpath(const char *unix_paths);
extern int
edll_setsearchpath(const char *paths);
extern char *edll_getsearchpath(void);

PARAMETERS

unix_paths — a list of paths separated by colons (:)
paths — a list of paths separated by semi-colons (;)

DESCRIPTION

The edll library accepts a search path that will be used to search for modules.

By default the edll determine the search path as the current environment variable %PATH% with "." prepended as in:".;%PATH%".

RETURN VALUE

The edll_setunixpath() function returns 0 on success
The edll_setpath() function returns 0 on success
The edll_getsearchpath() function returns a string pointer that you will need to free (edll_free) once you're done

BUGS

The search path is unique on a per process basis. This means in a multi-threads environment changing it in one thread, changes it for all threads. It is strongly adviced that you set it once at the start and do not change it.

SEE ALSO

edll_mutex_register


LIBRARY

edll

NAME

edll_set_self_version — set the version of the application (.exe file)

SYNOPSIS

extern void edll_set_self_version(const char *version);

PARAMETERS

version — the application version (i.e. "1.0", "0.3.1c", etc.)

DESCRIPTION

The edll library is now capable of retrieving a version in a module by reading the section named .version.

Because by default the .version section cannot be kept in the .exe file (i.e. the linker drops it,) edll has a function for your application version to be given to the lower level functions. Another solution is to patch the linker script (see the dev/version.patch file.)

The version of the application is later checked against the version of any loaded modules. This is done with strcmp() by default. If you want, you can specify a callback so as to be able to write your own comparison function. See the edll_callback_register function to know how to register your version function and edll_check_version typedef describes what your function declaration is expected to look like.

BUGS

You MUST define the version of the application before you call any of the edll functions. It is a bug not to do so. At this time the library doesn't enforce it though.

The version defined on the very first call is the only one kept (also assuming no module was loaded before this call.)

The linker loses sections it does not know about when creating a .exe file. This is certainly the normal behavior for the linker. To circumvent that problem with the .version section, you can apply the dev/version.patch to your ldscripts/i386pe.x file. You may want to edit the patch or your script file and do the pacthing by hand if you do not have the same version of ld.

SEE ALSO

edll_callback_register, edll_check_version


LIBRARY

edll

NAME

edll_module_version — returns the version string of the specified module

SYNOPSIS

extern const char *edll_module_version(edll_module *module);

PARAMETERS

module — the module you want the version from or NULL for the self module version

DESCRIPTION

The edll library recognizes a section named .version which includes a null terminated version string.

The library will automatically compare each module version against the version of the application. Once a module was loaded, you can further check the version string of a module by calling this function.

Note that you get in return the actual string saved in the module. Do not change nor free that pointer. It will crash your application.

Passing NULL as the module pointer returns the application version (also called self module.)

RETURN VALUE

The edll_module_version() function returns 0 if the module has no version, a constant nul terminated C string otherwise

BUGS

The version of the application will not be loaded until you load that module or some other module. Querying for that version will return a NULL pointer until that happens. This may get fixed in later versions.

SEE ALSO

edll_set_self_version, edll_check_version, edll_callback_register


LIBRARY

edll

NAME

edll_mutex_register — register mutex information for multi-thread usage

SYNOPSIS

extern int edll_mutex_register(edll_mutex_lock lock_func,
                    edll_mutex_unlock unlock_func,

                    edll_mutex_seterror seterror_func,

                    edll_mutex_geterror geterror_func,

                    edll_ptr userdata);

PARAMETERS

lock_func — the function to call to lock resources
unlock_func — the function to release resources
seterror_func — the function to set thread specific errors
geterror_func — the function to get thread specific errors
userdata — a pointer to some user data

DESCRIPTION

The edll library can be used in a multi-thread environment. For that, you need to setup a lock and an unlock function.

The library doesn't itself try to lock/unlock anything (thus we avoid dependencies to any threading system).

The error handling was added also to make sure that the library doesn't have any dependency on any threading system. It makes you responsible to save error numbers and to be capable of retrieving them later.

Any of these functions should be setup once by one thread before any others access the library and then it should never be changed.

It is legal to set any of these functions to NULL.

RETURN VALUE

The edll_mutex_register() function returns 0 on success

BUGS

Changing the function pointers while another thread is using the library can cause crashes and deadlocks.

SEE ALSO

edll_mutex_lock, edll_mutex_unlock, edll_seterror, edll_geterror


Undefined Symbols and Unresolved Symbols

The edll does link your plug-ins at runtime. This means you may get errors of symbols that it can't define. This will especially happens when you run a C program and try to load C++ plug-ins because C++ needs a wealth of symbols and these symbols are not all too clearly named.

The following table is an attempt to define different symbols you most certainly will have problems with at some point. Note that you can use the list.sh script (under the dev sub-directory) to generate a list of all the symbols in all the libraries available on your platform.

Symbol Name
Purpose
Comment
__imp__<name>
compiler introducer
For some reason, gcc/g++ will add __imp__ in front of some symbols. The library is supposed to search for these and report them as equal to symbols without the __imp__ introducer. I searched the linker and I could not find anything like this, so I do not have any real ground to believe that this is correct other than the fact that it actually works. If you see a symbol starting with __imp__... failing, then it can come from a mistake in the comparison with that symbol and some system symbol.
__CRT_MT
Multi-thread availability
This is a flag which tells the pthread library whether the process was linked with the proper support or not (i.e. the pthread library will leak without the proper support). This is part of the mtcrt.o file.
_Znaj, _Zdaj
New and delete array
These are the new and delete operators used with the square brackets:
array = new int[256];
This is part of the stdlibc++.a file.


Known Bugs & Limitations

The following list shows you what I know can cause problems with the edll library.









This file was last modified on September 17, 2007 at 20:38
Copyright (c) 2005-2006  Alexis Wilke