|
|
33.1 Introduction
Most of the UDI specification documents (see Chapter 2, "Document Organization") define programming interfaces and conventions that are applicable to any processor or platform architecture; these specifications, referred to as source-level specifications, provide source-level portability of UDI drivers from one platform or operating environment to another. There is a class of UDI specifications, called ABI Bindings, that define binary bindings to specific processor architectures; these specifications provide binary-level portability of UDI driver modules, allowing the driver to be compiled once for a target architecture and distributed to any platform or operating system which conforms to the ABI specification. The ABI Binding specifications are also refered to as binary-level specifications.
A UDI ABI binding consists of the following components:
- A processor architecture, instruction set definition, and endianness. This defines the supported instruction sets, and endianness of the compiled UDI driver, as well as corresponding subdirectory names for the UDI packaging format.
- Runtime architecture. This defines the procedure calling conventions, register usage, stack conventions, data layouts, etc.
- Binary bindings to the source-level UDI specifications. This specifies the sizes of fundamental UDI data types, the binary-portability requirements of implementation-dependent UDI macros and functional interfaces, and other miscellaneous binary bindings related to the source-level specifications.
- Building the driver object. This specifies the object file format, and the encapsulation of the static driver properties in the object files.
33.2 Processor Architecture
Each ABI binding specification must specify a processor architecture with its associated instruction set(s) as well as supported endianness modes. For example, separate ABI bindings will be specified for IA-32 (little endian), IA-64 (both big and little endian), PowerPC (big endian), etc.
Second, each ABI binding must specify the specific subclasses of processor architectures that are supported; e.g., an IA-32 binding might specify support for 386, 486, P1, P2, and P3 processors.
Third, the ABI binding must specify the <abi> subdirectory names for use in the UDI packaging format specification (see Section 31.2.1, "Directory Structure"); there should generally be one generic subdirectory defined for driver binaries that are useable across the ABI's processor subclasses, and an additional subdirectory for each processor subclass. For example, an IA-32 binding might specify a subdirectory named IA32 for generic IA-32 binaries, and might specify additional subdirectories named IA32_386, IA32_486, IA32_P1, IA32_P2, and IA32_P3 for binaries specific to a given IA-32 processor subclass.
33.3 Runtime Architecture
Associated with a given processor architecture is a set of conventions for executing software on that processor called the runtime architecture. This includes such things as the procedure calling conventions, register usage, stack conventions, data layouts, etc. The runtime architecture definition is typically defined in a separate non-UDI specification for a particular processor architecture, and is simply referenced by the UDI ABI specification.
33.4 Binary Bindings to the Source-Level Specifications
A few aspects of the source-level specifications are implementation-dependent and thus require additional specification for binary portability. These fall into four general categories: (1) the sizes of fundamental UDI data types, (2) the binary-portability requirements of implementation-dependent UDI macros, (3) the specification of UDI functional interfaces (other than the UDI utility functions) that are allowed to be implemented as macros, and (4) other miscellaneous binary bindings related to the source-level specifications.
Only the UDI Core Specification and the UDI Physical I/O Specification are allowed to contain fundamental UDI data types and implementation-dependent macros. Furthermore, only these two Specifications are allowed to have functional interfaces that can be implemented as macros, or to have any other aspects that require binary bindings to source-level specifications. Therefore, the only two source-level specifications which require bindings for binary portability are the UDI Core Specification and the UDI Physical I/O Specification. This allows the ABI bindings to be specified independently from the existence or the evolution of other source-level specifications such as metalanguages and bus bindings.
Utility functions in UDI can always be implemented as macros without breaking binary portability; see the Utility Functions Chapter for details.
Note - The values for symbolic constants are all defined in the source-level specifications, and thus require no specification in the ABI bindings.
33.4.1 Sizes of UDI Data Types
As part of its C language binding, UDI defines a set of fundamental data types (see Chapter 9, "Fundamental Types"). The UDI interfaces, in any of the UDI specifications, use only these fundamental types or types derived therefrom. The fundamental types include only a few standard ISO C types, namely char, void, and the varargs types; all the other fundamental types are UDI-defined and include a set of specific-length types, abstract types, and opaque types. Of these fundamental types, only the abstract types, opaque types, and pointer types ("void *" as well as specific pointer types) have implementation-dependent sizes. Thus an ABI specification only needs to specify the sizes of UDI's abstract types, opaque types, and pointer types, which are listed in the table below.
All pointer types have the same size, represented by the "void *" row in the table. The only fundamental types not defined in the Core Specification are the handle types defined in the Physical I/O Specification. For convenience and completeness, the physical I/O fundamental types are included here.
Note - Only the UDI Core Specification and the UDI Physical I/O Specification are allowed to define UDI fundamental data types.
33.4.2 Implementation-Dependent Macros
In UDI, an implementation-dependent macro is an interface that is defined to be a macro in a source-level specification (other than utility macros), but whose macro expansion definition is implementation-specific. Such macros may contain environment and platform dependencies which, to provide binary portability, must be hidden behind an external function call; any such external symbol references must be specified in the ABI.
Only the UDI Core Specification and the UDI Physical I/O Specification are allowed to specify implementation-dependent macros. In the 1.01 version of these Specifications two implementation-dependent macros are specified: the UDI_HANDLE_ID macro and UDI_HANDLE_IS_NULL macro.
Each ABI must specify the binary-portability requirements of each macro. This means that the ABI must specify whether or not the macro produces any external symbol references and, if so, the names and semantics of those external symbols. The ABI must also specify the behavior of the inline portion of the macro, in an environment-neutral fashion.
33.4.3 UDI Functions implemented as macros
As previously noted, utility functions in UDI can always be implemented as macros without breaking binary portability. However, ABI bindings must require each other UDI functional interface to be implemented in one of two ways. One way is to implement the UDI functional interface as an external function call. Another way is to optionally implement the interface as a macro with any environment or platform dependencies hidden behind an external function call. This external function call is specified by the ABI as part of the macro expansion.
A common example of a UDI functional interface that is implemented as a macro is the udi_assert interface. When udi_assert is implemented as a macro, any environment or platform dependencies must be hidden behind a call to an external function specified in the ABI. This allows the performance path to be done inline, only taking the overhead of a function call in the exception case.
33.4.4 Miscellaneous Binary Bindings
Each ABI must specify the following binary bindings related to the source-level specifications or the UDI architectural model:
- Maximum stack usage per call into the driver.
- Maximum instruction (code) size per driver object module, and per driver.
- Maximum static data size per driver object module, and per driver.
- Maximum binary object file size per driver object module.
33.5 Building the Driver Object
The Core Specification defines the generic aspects of building UDI driver object code. Each ABI specification defines the binary bindings of building the driver object code: i.e., the object file format, and the encapsulation of the static driver properties in the driver's object files.
33.5.1 Object File Format
Each ABI specifies an applicable object file format. Typically this is defined in a non-UDI specification, and is simply referenced in the UDI ABI specification.
33.5.2 Static Driver Properties Encapsulation
Each ABI needs to specify how the static driver properties (provided by the driver in its udiprops.txt configuration file - see Chapter 30, "Static Driver Properties") are attached to the driver's object files.