|
||
A Dynamic Link Library (DLL) contains executable code which can be shared by many processes in a system at any one time. A program can link against a DLL at compile time, meaning that the linker will match the DLL's symbols (such as function names and variables) with references from the program and ascertain the address within the DLL of the functions or variables.
Alternatively a program can dynamically load a DLL into memory during execution, locate the address of a symbol, use it and then unload the DLL.
Traditionally and for greater memory efficiency, Symbian OS links by ordinal, whereas Unix-like operating systems link by name. The following sections provide example code to illustrate how the DLL loader works with each operating system.
The following code shows how a shared library is dynamically loaded and used in a Unix-like environment using the 'dl' interface.
int main(int argc, char *argv[])
{
//Handle
void* dll_handle;
//Function prototype
void (*printSum)(int a, int b);
//Error message
const char* errorMsg;
//Filename of dll to load
char dllFileName[] = "/root/PortDoc/Example6/dll/shareddll";
//Load the dll
dll_handle = dlopen(dllFileName, RTLD_LAZY);
if (!dll_handle)
{
fprintf(stderr, "Error during load of library: %s\n", dlerror());
return EXIT_FAILURE;
}
//Find the symbol
printSum = dlsym(dll_handle, "printSum");
//Get the error message
errorMsg = dlerror();
if (errorMsg)
{
fprintf(stderr, "Error during symbol lookup: %s\n", errorMsg);
return EXIT_FAILURE;
}
//Now call the function
printSum(4, 6);
//Dispose of the DLL
dlclose(dll_handle);
return EXIT_SUCCESS;
}
As an example, the shareddll
might have a function such
as:
void printSum(int a, int b)
{
printf("Result is : %d\n", a + b);
}
Symbian OS programs uses the function or variable's ordinal position within a DLL to link with DLLs. For example, implementing a shared DLL on Symbian OS could look like this:
EXPORT_C void printSum(int a, int b)
{
printf("Result is : %d\n", a + b);
}
Compiling this will generate a .def
file, which contains
the ordinals of each symbol in the DLL. For instance,
EXPORTS
printSum @ 1 NONAME
where the .def
shows that the ordinal for the
printSum()
function is 1
. The following code
shows how the main()
program is now changed in P.I.P.S..
int main(int argc, char *argv[])
{
//Handle
void* dll_handle;
//Function prototype
void (*printSum)(int a, int b);
//Error message
const char* errorMsg;
//Filename of dll to load
char dllFileName[] = "/root/PortDoc/Example6/dll/shareddll";
//Load the dll
dll_handle = dlopen(dllFileName, RTLD_LAZY);
if (!dll_handle)
{
fprintf(stderr, "Error during load of library: %s\n", dlerror());
return EXIT_FAILURE;
}
//Find the symbol, using the ordinal
printSum = dlsym(dll_handle, "1");
//Get the error message
errorMsg = dlerror();
if (errorMsg)
{
fprintf(stderr, "Error during symbol lookup: %s\n", errorMsg);
return EXIT_FAILURE;
}
//Now call the function
printSum(4, 6);
//Dispose of the DLL
dlclose(dll_handle);
return EXIT_SUCCESS;
}
Note that for the Symbian library loader, the mode parameter for the
dlopen()
function is irrelevant and the library will be
loaded immediately. So although RTLD_LAZY
is the mode
parameter in the example, it will behave just as RTLD_NOW
.
Also note that there is no facility to call any library constructor and
destructor functions using __attribute((constructor))
or
__attribute((destructor))
.
P.I.P.S. provides APIs from libdl
to support dynamic
lookup by name, which is used in Unix-like platforms, instead of the native
Symbian OS lookup by ordinal mechanism. Lookup by name is possible thanks to
the new libdl
, which in turn uses the existing
RLibrary
functions to load and unload DLLs.
A symbol name lookup version of the dlsym()
function is provided, similar to UNIX®, which does not need any special
treatment (the example shown in Shared libraries in a Unix-like environment will suffice). However, it is still
necessary to generate the .def
file for the DLL.
libdl
APIs
The libdl
APIs, which support dynamic lookup by name,
are described in the following sections.
void *dlopen (const char *path, int mode)
Call dlopen()
to gain access to symbols of any
shared library or DLL. If dlopen()
fails for any reason, it will
return a NULL
. The default search path for the library can be
provided in the environment variable LD_LIBRARY_PATH
.
void *dlsym(void *handle, const char
*symbol)
The dlsym()
function returns the address
binding of the symbol described in the null-terminated character string
'symbol
', as it occurs in the shared object identified by
'handle
'.
int dlclose(void *handle)
Call dlclose()
with a valid
dlopen
-ed handle to remove it from the cache list maintained by
dlopen()
. If it fails, dlclose()
will return
-1
; otherwise, it will return 0
.
char *dlerror(void)
Call dlerror()
to obtain the most recent error
that occurred due to any of the dl
routines, that is,
dlopen()
, dlsym()
, or dlclose()
.