First version of DLL preloader.
[wincetools.git] / loader / README
1 HiMemCE\r
2 =======\r
3 \r
4 HiMemCE is a high memory loader for Windows CE.  It softens the 32 MB\r
5 process limit by allowing the EXE to load in the large file area\r
6 reserved for file mappings.  This way, the EXE can be as large as free\r
7 unfragmented virtual memory in that region, or free physical memory\r
8 (whatever is smaller).  By linking libraries statically to the\r
9 program, problems with too large or too many DLLs can be avoided.\r
10 \r
11 The usage of the loader is very simple.\r
12 \r
13 1. First, the program to be loaded has to be linked with the option\r
14 /FIXED:NO (in MSVS, this setting can be found under Properties,\r
15 Configuration Properties, Linker, Advanced, Fixed Base Address, choose\r
16 "Generate a relocation section").  Here is a CMake example:\r
17 \r
18 SET_TARGET_PROPERTIES(foo PROPERTIES LINK_FLAGS " /FIXED:NO")\r
19 \r
20 2. Install the program "foo" under foo-real.exe, and copy the loader's\r
21 himemce.exe side-by-side to it as foo.exe.  Then the loader (as\r
22 foo.exe) transparently proxies all start ups of the foo program.  It\r
23 will automatically look for foo-real.exe and load that into high\r
24 memory, continueing execution there.\r
25 \r
26 Contained in this package is a himemce-real.exe, that serves as an\r
27 example/test program.  In the special case of "himemce.exe", verbose\r
28 output is on by default.\r
29 \r
30 How it works\r
31 ------------\r
32 \r
33 HiMemCE allocates a virtual memory region with VirtulAlloc\r
34 (MEM_RESERVE, PAGE_NOACCESS) large enough to cover the whole image\r
35 (SizeOfImage).  If that is larger than 2 MB, Windows CE automatically\r
36 uses the large memory area for the allocation.  Then HiMemCE loads the\r
37 sections into the designated place.  This immediately commits all\r
38 pages[1].\r
39 \r
40 The image is then relocated (this is why /FIXED:NO is required).\r
41 Although an attempt is made to honor the preferred base address, once\r
42 all pages are copied, there is no big advantage to avoiding\r
43 relocating, so setting a preferred base address (without a way to also\r
44 use MapViewOfFile) is currently not recommended.\r
45 \r
46 The next step is to resolve imports.  For this, the import section is\r
47 processed, and for each DLL listed there, we use LoadLibrary to pass\r
48 off the load request to the system loader.  We don't do any DLL\r
49 loading ourselves[1].  For every DLL loaded this way, we resolve\r
50 references by GetProcAddress, which supports lookup by name as well as\r
51 by ordinal.\r
52 \r
53 Finally, pass execution to the loaded program.  Because the entry\r
54 point is a normal C function, we can reuse the current thread and all\r
55 its state.  The first argument is the module handle of the started\r
56 image.  As we constructed this ourselve, there is no valid module\r
57 handle for it, so we reuse the module handle of the loader as well.[3]\r
58 Because this affects argv[0], we give the loader the same name as the\r
59 executable we want to load (and rename the loaded executable to\r
60 foo-real.exe).\r
61 \r
62 \r
63 Footnotes\r
64 \r
65 [1] This is a pessimization, but because only MapViewOfFile and\r
66 not MapVieOfFileEx is available, mapping in the read only sections of\r
67 the file directly is difficult, and when relocating the image, many\r
68 pages end up being dirty anyway.  See Optimization options.\r
69 \r
70 [2] This avoids the complexity of sharing DLLs across applications as\r
71 well as walking the dependency chain.  A more complex loader, that can\r
72 also load DLLs and thus effectively extend the slot 61 and 60 by\r
73 further slots is feasible, but quite a bit of work.  The only benefit\r
74 over static linking this has is code sharing, but if we are only\r
75 talking about a couple of MB, then code duplication across a small\r
76 number of programs is not a big problem.  And the number of processes\r
77 in Windows CE is necessarily small!\r
78 \r
79 [3] Note that this could confuse some programs that do deep\r
80 introspection and want to manually load custom sections or do other\r
81 magic.\r
82 \r
83 \r
84 TODO\r
85 ----\r
86 \r
87 * Switch off verbose output for non-himemce.exe named copies of\r
88 the loader (but allow a switch --himemce-log to switch it back on).\r
89 \r
90 * Show load errors in a diagnostic window for the user.\r
91 \r
92 * Handle DISCARDABLE flag?\r
93 \r
94 \r
95 Optimization options\r
96 --------------------\r
97 \r
98 * Physical memory pressure can be relieved by trying to use\r
99   MapViewOfFile opportunistically (create relocated image, save to\r
100   temporary file, map it).\r
101 \r
102 * Handle DISCARDABLE sections (if any).\r
103 \r
104 \r
105 How it works (DLL version)\r
106 --------------------------\r
107 \r
108 The preloader (himemce-pre) should be run when the device starts up,\r
109 and must be run before any program is loaded high with himemce.  It\r
110 preloads the DLLs that should be loaded high.\r
111 \r
112 Note that these DLLs are unknown to the system and can only be used by\r
113 himemce.  This means that any program resp. DLL that depends on a high\r
114 loaded DLL must be loaded by himemce resp. himemce-pre as well.\r
115 Further note that himemce can not generate stub code for ARM, so ARM\r
116 DLLs such as gpgme, gpg-error etc can not be preloaded and should be\r
117 exempted.\r
118 \r
119 The himemce-pre program looks for all .dll files in its directory and\r
120 preloads them, unless they are in the blacklist (FIXME: implement and\r
121 document blacklist mechanism).\r
122 \r
123 The preloader performs the following steps:\r
124 \r
125 1. For all preloaded DLLs, map them to high memory without resolving\r
126 their references.\r
127 \r
128 2. For all preloaded DLLs, identify sections that are writable and\r
129 thus need to be allocated per process.  For these DLLs, reserve some\r
130 memory in a continuous range at the bottom of the process address\r
131 space (_HIMEMCE_MAP_LOW_BASE == 2 MB).  Also rewrite all base\r
132 relocations that point into these sections to point to the low memory\r
133 instead.\r
134 \r
135 3. For all preloaded DLLs, import their dependencies.  For DLLs\r
136 managed by himemce-pre, this will resolve to the entry points in the\r
137 high loaded DLLs (adjusting entry points into writable section to\r
138 their low memory variant).  For system managed DLLs, use the normal\r
139 LoadLibrary/GetProcAddressA mechanism.\r
140 \r
141 4. Map the data structures describing all this to a shared memory\r
142 region named HIMEMCE_MAP_NAME == L"himemcemap".  This can be accessed\r
143 by himemce.\r
144 \r
145 5. Sleep forever.  It is important that this process does not exit,\r
146 because if this was the last user of HIMEMCE_MAP_NAME, the preloaded\r
147 libraries will be deallocated.\r
148 \r
149 These steps must be executed for programs that run with preloaded\r
150 DLLs (done by himemce):\r
151 \r
152 1. At startup, reserve the low memory sections.\r
153 \r
154 2. For each preloaded DLL, copy its writable sections to the process\r
155 memory reserved in step 1.\r
156 \r
157 3. For each system DLL that is used by preloaded DLLs, call\r
158 LoadLibrary to copy their writable sections into the process memory.\r
159 \r
160 4. For each preloaded DLL, call DllMain (their entry point).\r
161 \r
162 [5. TODO: Load a himemce.dll library that calls these DllMain's for\r
163 each Thread in its DllMain.]\r
164 \r
165 \r
166  Copyright 2010 g10 Code GmbH\r
167 \r
168  This file is free software; as a special exception the author gives\r
169  unlimited permission to copy and/or distribute it, with or without\r
170  modifications, as long as this notice is preserved.\r
171 \r
172  This file is distributed in the hope that it will be useful, but\r
173  WITHOUT ANY WARRANTY, to the extent permitted by law; without even the\r
174  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\r