XFree86® server 4.x Design (DRAFT) : The Loader
Previous: The XFree86 X Video Extension (Xv) Device Dependent Layer
Next: Helper Functions

## 17. The Loader

This section describes the interfaces to the module loader. The loader interfaces can be divided into two groups: those that are only available to the XFree86 common layer, and those that are also available to modules.

### 17.1. Loader Overview

The loader is capable of loading modules in a range of object formats, and knowledge of these formats is built in to the loader. Knowledge of new object formats can be added to the loader in a straightforward manner. This makes it possible to provide OS-independent modules (for a given CPU architecture type). In addition to this, the loader can load modules via the OS-provided `dlopen(3)` service where available. Such modules are not platform independent, and the semantics of `dlopen()` on most systems results in significant limitations in the use of modules of this type. Support for `dlopen()` modules in the loader is primarily for experimental and development purposes.

Symbols exported by the loader (on behalf of the core X server) to modules are determined at compile time. Only those symbols explicitly exported are available to modules. All external symbols of loaded modules are exported to other modules, and to the core X server. The loader can be requested to check for unresolved symbols at any time, and the action to be taken for unresolved symbols can be controlled by the caller of the loader. Typically the caller identifies which symbols can safely remain unresolved and which cannot.

NOTE: Now that ISO-C allows pointers to functions and pointers to data to have different internal representations, some of the following interfaces will need to be revisited.

### 17.2. Semi-private Loader Interface

The following is the semi-private loader interface that is available to the XFree86 common layer.

> `void LoaderInit(void)`

> > The `LoaderInit()` function initialises the loader, and it must be called once before calling any other loader functions. This function initialises the tables of exported symbols, and anything else that might need to be initialised.

> `void LoaderSetPath(const char *path)`

> > The `LoaderSetPath()` function initialises a default module search path. This must be called if calls to other functions are to be made without explicitly specifying a module search path. The search path `path` must be a string of one or more comma separated absolute paths. Modules are expected to be located below these paths, possibly in subdirectories of these paths.

> `pointer LoadModule(const char *module, const char *path,
> const char **subdirlist, const char **patternlist,
> pointer options, const XF86ModReqInfo * modreq,
> int *errmaj, int *errmin)`

> > The `LoadModule()` function loads the module called `module`. The return value is a module handle, and may be used in future calls to the loader that require a reference to a loaded module. The module name `module` is normally the module's canonical name, which doesn't contain any directory path information, or any object/library file prefixes of suffixes. Currently a full pathname and/or filename is also accepted. This might change. The other parameters are:

> > `path`

> > > An optional comma-separated list of module search paths. When `NULL`, the default search path is used.

> > `subdirlist`

> > > An optional `NULL` terminated list of subdirectories to search. When `NULL`, the default built-in list is used (refer to `stdSubdirs` in `loadmod.c`). The default list is also substituted for entries in `subdirlist` with the value `DEFAULT_LIST`. This makes is possible to augment the default list instead of replacing it. Subdir elements must be relative, and must not contain `".."`. If any violate this requirement, the load fails.

> > `patternlist`

> > > An optional `NULL` terminated list of POSIX regular expressions used to connect module filenames with canonical module names. Each regex should contain exactly one subexpression that corresponds to the canonical module name. When `NULL`, the default built-in list is used (refer to `stdPatterns` in `loadmod.c`). The default list is also substituted for entries in `patternlist` with the value `DEFAULT_LIST`. This makes it possible to augment the default list instead of replacing it.

> > `options`

> > > An optional parameter that is passed to the newly loaded module's `SetupProc` function (if it has one). This argument is normally a `NULL` terminated list of `Options`, and must be interpreted that way by modules loaded directly by the XFree86 common layer. However, it may be used for application-specific parameter passing in other situations.

> > > When loading ``external'' modules (modules that don't have the standard entry point, for example a special shared library) the options parameter can be set to `EXTERN_MODULE` to tell the loader not to reject the module when it doesn't find the standard entry point.

> > `modreq`

> > > An optional `XF86ModReqInfo*` containing version/ABI/vendor information specifying requirements to check the newly loaded module against. The main purpose of this is to allow the loader to verify that a module of the correct type/version before running its `SetupProc` function.

> > > The `XF86ModReqInfo` struct is defined as follows:

> > >     typedef struct {
> > >     	CARD8        majorversion;  /* MAJOR_UNSPEC */
> > >     	CARD8        minorversion;  /* MINOR_UNSPEC */
> > >     	CARD16       patchlevel;    /* PATCH_UNSPEC */
> > >     	const char * abiclass;      /* ABI_CLASS_NONE */
> > >     	CARD32       abiversion;    /* ABI_VERS_UNSPEC */
> > >     	const char * moduleclass;   /* MOD_CLASS_NONE */
> > >     } XF86ModReqInfo;

> > > The information here is compared against the equivalent information in the module's `XF86ModuleVersionInfo` record (which is described below). The values in comments above indicate ``don't care'' settings for each of the fields. The comparisons made are as follows:

> > > `majorversion`

> > > > Must match the module's majorversion exactly.

> > > `minorversion`

> > > > The module's minor version must be no less than this value. This comparison is only made if `majorversion` is specified and matches.

> > > `patchlevel`

> > > > The module's patchlevel must be no less than this value. This comparison is only made if `minorversion` is specified and matches.

> > > `abiclass`

> > > > String must match the module's abiclass string.

> > > `abiversion`

> > > > Must be consistent with the module's abiversion (major equal, minor no older).

> > > `moduleclass`

> > > > String must match the module's moduleclass string.

> > `errmaj`

> > > An optional pointer to a variable holding the major part or the error code. When provided, `*errmaj` is filled in when `LoadModule()` fails.

> > `errmin`

> > > Like `errmaj`, but for the minor part of the error code.

> `void UnloadModule(pointer mod)`

> > This function unloads the module referred to by the handle mod. All child modules are also unloaded recursively. This function must not be used to directly unload modules that are child modules (i.e., those that have been loaded with the `LoadSubModule()` described below).

### 17.3. Module Requirements

Modules must provide information about themselves to the loader, and may optionally provide entry points for "setup" and "teardown" functions (those two functions are referred to here as `SetupProc` and `TearDownProc`).

The module information is contained in the `XF86ModuleVersionInfo` struct, which is defined as follows:

>     typedef struct {
>         const char * modname;      /* name of module, e.g. "foo" */
>         const char * vendor;       /* vendor specific string */
>         CARD32       _modinfo1_;   /* constant MODINFOSTRING1/2 to find */
>         CARD32       _modinfo2_;   /* infoarea with a binary editor/sign tool */
>         CARD32       xf86version;  /* contains XF86_VERSION_CURRENT */
>         CARD8        majorversion; /* module-specific major version */
>         CARD8        minorversion; /* module-specific minor version */
>         CARD16       patchlevel;   /* module-specific patch level */
>         const char * abiclass;     /* ABI class that the module uses */
>         CARD32       abiversion;   /* ABI version */
>         const char * moduleclass;  /* module class */
>         CARD32       checksum[4];  /* contains a digital signature of the */
>                                    /* version info structure */
>     } XF86ModuleVersionInfo;

> The fields are used as follows:

> `modname`

> > The module's name. This field is currently only for informational purposes, but the loader may be modified in future to require it to match the module's canonical name.

> `vendor`

> > The module vendor. This field is for informational purposes only.

> `_modinfo1_`

> > This field holds the first part of a signature that can be used to locate this structure in the binary. It should always be initialised to `MODINFOSTRING1`.

> `_modinfo2_`

> > This field holds the second part of a signature that can be used to locate this structure in the binary. It should always be initialised to `MODINFOSTRING2`.

> `xf86version`

> > The XFree86 version against which the module was compiled. This is mostly for informational/diagnostic purposes. It should be initialised to `XF86_VERSION_CURRENT`, which is defined in `xf86Version.h`.

> `majorversion`

> > The module-specific major version. For modules where this version is used for more than simply informational purposes, the major version should only change (be incremented) when ABI incompatibilities are introduced, or ABI components are removed.

> `minorversion`

> > The module-specific minor version. For modules where this version is used for more than simply informational purposes, the minor version should only change (be incremented) when ABI additions are made in a backward compatible way. It should be reset to zero when the major version is increased.

> `patchlevel`

> > The module-specific patch level. The patch level should increase with new revisions of the module where there are no ABI changes, and it should be reset to zero when the minor version is increased.

> `abiclass`

> > The ABI class that the module requires. The class is specified as a string for easy extensibility. It should indicate which (if any) of the X server's built-in ABI classes that the module relies on, or a third-party ABI if appropriate. Built-in ABI classes currently defined are:

> > > `ABI_CLASS_NONE`

> > > > no class

> > > `ABI_CLASS_ANSIC`

> > > > only requires the ANSI C interfaces

> > > `ABI_CLASS_VIDEODRV`

> > > > requires the video driver ABI

> > > `ABI_CLASS_XINPUT`

> > > > requires the XInput driver ABI

> > > `ABI_CLASS_EXTENSION`

> > > > requires the extension module ABI

> > > `ABI_CLASS_FONT`

> > > > requires the font module ABI

> `abiversion`

> > The version of abiclass that the module requires. The version consists of major and minor components. The major version must match and the minor version must be no newer than that provided by the server or parent module. Version identifiers for the built-in classes currently defined are:

> > > `ABI_ANSIC_VERSION
> > > ABI_VIDEODRV_VERSION
> > > ABI_XINPUT_VERSION
> > > ABI_EXTENSION_VERSION
> > > ABI_FONT_VERSION`

> `moduleclass`

> > This is similar to the abiclass field, except that it defines the type of module rather than the ABI it requires. For example, although all video drivers require the video driver ABI, not all modules that require the video driver ABI are video drivers. This distinction can be made with the moduleclass. Currently pre-defined module classes are:

> > > `MOD_CLASS_NONE
> > > MOD_CLASS_VIDEODRV
> > > MOD_CLASS_XINPUT
> > > MOD_CLASS_FONT
> > > MOD_CLASS_EXTENSION`

> `checksum`

> > Not currently used.

The module version information, and the optional `SetupProc` and `TearDownProc` entry points are found by the loader by locating a data object in the module called "modnameModuleData", where "modname" is the canonical name of the module. Modules must contain such a data object, and it must be declared with global scope, be compile-time initialised, and is of the following type:

>     typedef struct {
>         XF86ModuleVersionInfo *     vers;
>         ModuleSetupProc             setup;
>         ModuleTearDownProc          teardown;
>     } XF86ModuleData;

The vers parameter must be initialised to a pointer to a correctly initialised `XF86ModuleVersionInfo` struct. The other two parameters are optional, and should be initialised to `NULL` when not required. The other parameters are defined as

> `typedef pointer (*ModuleSetupProc)(pointer, pointer, int *, int *)`

> `typedef void (*ModuleTearDownProc)(pointer)`

> `pointer SetupProc(pointer module, pointer options,
> int *errmaj, int *errmin)`

> > When defined, this function is called by the loader after successfully loading a module. module is a handle for the newly loaded module, and maybe used by the `SetupProc` if it calls other loader functions that require a reference to it. The remaining arguments are those that were passed to the `LoadModule()` (or `LoadSubModule()`), and are described above. When the `SetupProc` is successful it must return a non-`NULL` value. The loader checks this, and if it is `NULL` it unloads the module and reports the failure to the caller of `LoadModule()`. If the `SetupProc` does things that need to be undone when the module is unloaded, it should define a `TearDownProc`, and return a pointer that the `TearDownProc` can use to undo what has been done.

> > When a module is loaded multiple times, the `SetupProc` is called once for each time it is loaded.

> `void TearDownProc(pointer tearDownData)`

> > When defined, this function is called when the loader unloads a module. The `tearDownData` parameter is the return value of the `SetupProc()` that was called when the module was loaded. The purpose of this function is to clean up before the module is unloaded (for example, by freeing allocated resources).

### 17.4. Public Loader Interface

The following is the Loader interface that is available to any part of the server, and may also be used from within modules.

Some of these have `xf86*` wrappers with simpler interfaces declared in `"xf86.h"`. These wrappers are the preferred interface for modules, given that they are also available in a statically built server, whereas the functions below are not.

> `pointer LoadSubModule(pointer parent, const char *module,
> const char **subdirlist, const char **patternlist,
> pointer options, const XF86ModReqInfo * modreq,
> int *errmaj, int *errmin)`

> > This function is like the `LoadModule()` function described above, except that the module loaded is registered as a child of the calling module. The `parent` parameter is the calling module's handle. Modules loaded with this function are automatically unloaded when the parent module is unloaded. The other difference is that the path parameter may not be specified. The module search path used for modules loaded with this function is the default search path as initialised with `LoaderSetPath()`.

> `void UnloadSubModule(pointer module)`

> > This function unloads the module with handle `module`. If that module itself has children, they are also unloaded. It is like `UnloadModule()`, except that it is safe to use for unloading child modules.

> `pointer LoaderSymbol(const char *symbol)`

> > This function returns the address of the symbol with name `symbol`. This may be used to locate a module entry point with a known name.

> `char **LoaderlistDirs(const char **subdirlist,
> const char **patternlist)`

> > This function returns a `NULL` terminated list of canonical modules names for modules found in the default module search path. The `subdirlist` and `patternlist` parameters are as described above, and can be used to control the locations and names that are searched. If no modules are found, the return value is `NULL`. The returned list should be freed by calling `LoaderFreeDirList()` when it is no longer needed.

> `void LoaderFreeDirList(char **list)`

> > This function frees a module list created by `LoaderlistDirs()`.

> `void LoaderReqSymLists(const char **list0, ...)`

> > This function allows the registration of required symbols with the loader. It is normally used by a caller of `LoadSubModule()`. If any symbols registered in this way are found to be unresolved when `LoaderCheckUnresolved()` is called then `LoaderCheckUnresolved()` will report a failure. The function takes one or more `NULL` terminated lists of symbols. The end of the argument list is indicated by a `NULL` argument.

> `void LoaderReqSymbols(const char *sym0, ...)`

> > This function is like `LoaderReqSymLists()` except that its arguments are symbols rather than lists of symbols. This function is more convenient when single functions are to be registered, especially when the single function might depend on runtime factors. The end of the argument list is indicated by a `NULL` argument.

> `void LoaderRefSymLists(const char **list0, ...)`

> > This function allows the registration of possibly unresolved symbols with the loader. When `LoaderCheckUnresolved()` is run it won't generate warnings for symbols registered in this way unless they were also registered as required symbols. The function takes one or more `NULL` terminated lists of symbols. The end of the argument list is indicated by a `NULL` argument.

> `void LoaderRefSymbols(const char *sym0, ...)`

> > This function is like `LoaderRefSymLists()` except that its arguments are symbols rather than lists of symbols. This function is more convenient when single functions are to be registered, especially when the single function might depend on runtime factors. The end of the argument list is indicated by a `NULL` argument.

> `int LoaderCheckUnresolved(int dummy)`

> > This function checks for unresolved symbols. It generates warnings for unresolved symbols that have not been registered with `LoaderRefSymLists()`. All such symbols are automatically mapped to a dummy function. If unresolved symbols are found that have been registered with `LoaderReqSymLists()` or `LoaderReqSymbols()` then this function returns a non-zero value. If none of these symbols are unresolved the return value is zero, indicating success.

> > The `dummy` parameter is not used, and should be set to `0`. It is kept only for compatibility purposes.

> `LoaderErrorMsg(const char *name, const char *modname,
> int errmaj, int errmin)`

> > This function prints an error message that includes the text ``Failed to load module'', the module name `modname`, a message specific to the `errmaj` value, and the value if `errmin`. If `name` is non-`NULL`, it is printed as an identifying prefix to the message (followed by a `:').

> `LoaderSetParentModuleRequirements(pointer module,
> pointer req);`

> > This function is intended to be called from a module's `Setup` function. It associates an `XF86ModReqInfo` structure occurrence (addressed by `req`) with the module being loaded (specified by `module`). This structure occurrence will then be used to check this module's parent modules against. This mechanism allows a module to ensure its callers are compatible.

### 17.5. Special Registration Functions

The loader contains some functions for registering some classes of modules. These may be moved out of the loader at some point.

> `void LoadExtension(ExtensionModule *ext)`

> > This registers the entry points for the extension identified by `ext`. The `ExtensionModule` struct is defined as:

> > >     typedef struct {
> > >         InitExtension       initFunc;
> > >         char *              name;
> > >         Bool                *disablePtr;
> > >         InitExtension       setupFunc;
> > >     } ExtensionModule;

> `void LoadFont(FontModule *font)`

> > This registers the entry points for the font rasteriser module identified by `font`. The `FontModule` struct is defined as:

> > >     typedef struct {
> > >         InitFont    initFunc;
> > >         char *      name;
> > >         pointer     module;
> > >     } FontModule;

XFree86® server 4.x Design (DRAFT) : The Loader
Previous: The XFree86 X Video Extension (Xv) Device Dependent Layer
Next: Helper Functions