Wiley.Symbian.OS.Internals.Real.time.Kernel.Programming.Dec.2005.eBook-DDU (779891), страница 83
Текст из файла (страница 83)
In this scheme, importreferences state the version number of each dependency. This makes itpossible for us to make changes to an executable that are not binarycompatible with the previous version, since we can now place both thenew and old versions on the device simultaneously. The import sectionof any preexisting binary that has a dependency on this executable willindicate that it was built against the old version, allowing the loader tolink it to that version. At the same time, the loader links new or re-builtbinaries to the new version. In some cases, rather than have two entireversions of the same DLL, the old version can be re-implemented as ashim DLL, using the functionality in the new DLL, but presenting theoriginal DLL interface.The EKA2 tools tag each executable with a 32-bit version number, which is stored in the image file header (see Appendix 2, TheE32ImageHeader and Appendix 3, The TRomImageHeader, for details).This number is made up of a 16-bit major and a 16-bit minor number.Regarding linkage, each entry in an executable’s import table now specifies the required version number of the DLL concerned (see Section 10.1for details).
Where two or more versions of an executable exist on adevice, both will generally reside in the same directory to save the loadersearching additional directories. (Indeed, if platform security is enabled,they must reside in the same restricted system directory.) To preventfile name clashes, older versions have the version number appendedto the file name (for example, efsrv{00010000}.dll), whereas thelatest version has an unadorned name (for example, efsrv.dll). Whensearching for a candidate executable to load, the loader ignores anyversion number in the file name – but subsequently checks the versionnumber in the header.The EKA2 tools tag an executable with a default version number ofeither 1.0 (for GCC98r2 binaries) or 10.0 (for binaries built with an EABIcompliant compiler).
The same applies for the default version specified inTHE LOADER SERVER395each element of the import table. This allows inter-working with binariesbuilt with pre-EKA2 versions of the tools, which are assumed to havethe version 0.0. (Executables which pre-date versioning can only ever beintroduced on non-XIP media. This is because all ROM resident binariesin EKA2-based systems will be built with the new tools.)We assign a new version number to a DLL each time its publishedAPI is changed.
If the change is backward compatible (for example, justadding new APIs) and all executables that worked with the original willcontinue to work with the new version, then we only increment the minornumber.When the new version removes or breaks an existing API, then weincrement the major number and reset the minor number to zero. Weassign modified APIs a new ordinal number, and remove the originalordinal (leaving a hole). This means that, whether an API is removed ormodified, it appears that it has been removed. Of course, it will generallybe the case that we break compatibility for just a small number of APIsand the majority of APIs will remain compatible. Executables that don’tuse removed APIs can then continue to run successfully against the newversion.
So, whenever APIs are removed, we include information in theimage header to indicate which exports are affected (see Appendix 2, TheE32ImageHeader, for more details).When it is loading an executable and resolving import dependencies,if the loader finds more than one DLL in the search path that matches therequested name, UID and security capabilities, but has differing versionnumbers, then it employs the following selection algorithm:1. If there is a DLL in this set with the requested major version numberand a minor version number greater than or equal to the requestedminor version number, then it uses that one. If there is more than oneof these, then it uses the one with the highest minor version number2.
If no DLL exists satisfying (1), the loader looks for a DLL with a highermajor version number than the one requested. If there is more thanone of these, then it selects the one with the lowest major versionnumber and the highest minor version number. If the executabledoes not request any exports that no longer exist in this DLL, then theloader uses it3. If no DLL exists satisfying (1) or (2), the loader looks for a DLL withthe requested major version number. If there is more than one ofthese, it finds the one with the highest minor version number. If theexecutable currently being loaded does not request any exports thatare not present in this DLL, then the loader uses it4. If no DLL exists satisfying either (1), (2) or (3) then the load fails.An implication of the previous algorithm is that as the loader searches foran executable across multiple drives (and multiple paths in non-secure396THE LOADERmode), it can’t afford to stop at the first match.
Instead it has to continueto the end of the search and then evaluate the best match. Fortunately,platform security cuts down the number of paths which have to besearched. The loader cache, which I describe in Section 10.3.3, alsoreduces the impact of this searching.10.3.2 Searching for an executableThe EKA2 version of F32 is normally built with platform securityenabled – see Chapter 8, Platform Security, for more on this.
In thissecure version, the loader will only load executables from the restrictedsystem area, which is located in the ‘‘\sys \bin’’ directory of a givendrive.In non-secure mode, the loader will load executables from any directory. However, there are a default set of directories where executables aregenerally located and the loader scans these directories when searchingfor an executable to load.10.3.2.1 Search rules on loading a processWhen a client calls RProcess::Create() to start a new process, itspecifies the filename of the executable (and optionally the UID type).If the filename includes the drive and path, then the task of locating theexecutable is straightforward.
When either of these is not supplied, theloader has a fixed set of locations that it searches. This set is much morelimited when platform security is enabled. The search rules that it usesare as follows:1.If the filename includes a path but no drive letter, then the loadersearches only that path, but it does this for all 26 drives2.If the filename doesn’t contain a path, then instead the loader searcheseach of the paths that I will now list, in the order given. (Again, foreach of these, if a drive letter was supplied then the loader searchesthese paths only on this specified drive. However, if no drive wassupplied either, then it checks all listed paths on all 26 drives)◦ sys\bin◦ system\bin (non-secure mode only)◦ system\programs (non-secure mode only)◦ system\libs (non-secure mode only).When searching all 26 drives, the search order starts with drive Y: andthen works backwards through to drive A:, followed finally by the Z:drive.
Searching the Z: drive last makes it possible for us to over-ride aTHE LOADER SERVER397particular EXE in the ROM drive by replacing it with an updated versionon an alternative drive that is checked earlier in the search order, forexample, the C: drive.When loading a process, the loader follows these rules to select whichexecutable to load:• Check that the filename and extension match• Check that the UID type matches (if specified)• Out of all possible matches, select the one with the highest version number. (Remember, the selection algorithm I described inSection 10.3.1 applies only when resolving import dependencies.)Once the process executable is loaded, the loader goes on to resolveall its import dependencies. For a non-XIP executable, the name of eachDLL that it statically links to is contained in the import data section ofthe image.
The module version and third UID are included in the DLLname (as I discussed in Section 10.1) – but the path and drive are not.Therefore the loader again has to search a fixed set of locations for eachdependency:1. The drive and path that the process executable was loaded from2. All of the paths listed, in the order given, on all 26 drives in turn:◦ sys\bin◦ system\bin (non-secure mode only)◦ system\libs (non-secure mode only).When loading DLL dependencies, the properties that the loader checkswhen searching for a match are more substantial:• Check that the filename and extension match• Check that the third UIDs match• Check that the candidate DLL has sufficient platform security capabilities compared with the importing executable.
Refer to Section 8.4.2.1for precise details of this capability check• Check that the module versions are compatible. This could potentiallyinclude checking the export table bitmap in the image header of acandidate DLL to ensure that an export hasn’t been removed.As I mentioned in Section 10.3.1, when resolving import dependencies,the version numbering selection scheme means that the loader mustcontinue to the end of the search and evaluate the best match.398THE LOADER10.3.2.2 Search rules when loading a libraryWhen a client calls RLibrary::Load() to dynamically load a library,it may provide a path list as well as the filename of the DLL. Again, ifthe filename includes the drive and path, the loader loads the DLL fromthat location. However, if it does not, then the loader searches each ofthe paths specified in the path list before searching the standard paths forDLL loading, which I listed in the previous paragraph.