[RTL]
[reactos.git] / reactos / lib / rtl / image.c
1 /* COPYRIGHT: See COPYING in the top level directory
2 * PROJECT: ReactOS system libraries
3 * FILE: lib/rtl/image.c
4 * PURPOSE: Image handling functions
5 * Relocate functions were previously located in
6 * ntoskrnl/ldr/loader.c and
7 * dll/ntdll/ldr/utils.c files
8 * PROGRAMMER: Eric Kohl + original authors from loader.c and utils.c file
9 * Aleksey Bragin
10 */
11
12 /* INCLUDES *****************************************************************/
13
14 #include <rtl.h>
15
16 #define NDEBUG
17 #include <debug.h>
18
19 #define RVA(m, b) ((PVOID)((ULONG_PTR)(b) + (ULONG_PTR)(m)))
20
21 /* FUNCTIONS *****************************************************************/
22
23 BOOLEAN
24 NTAPI
25 LdrVerifyMappedImageMatchesChecksum(
26 IN PVOID BaseAddress,
27 IN ULONG ImageSize,
28 IN ULONG FileLength)
29 {
30 PIMAGE_NT_HEADERS Header;
31 PUSHORT Ptr;
32 ULONG Sum;
33 ULONG CalcSum;
34 ULONG HeaderSum;
35 ULONG i;
36
37 /* Get NT header to check if it's an image at all */
38 Header = RtlImageNtHeader (BaseAddress);
39 if (!Header) return FALSE;
40
41 /* Get checksum to match */
42 HeaderSum = Header->OptionalHeader.CheckSum;
43
44 /* Zero checksum seems to be accepted */
45 if (HeaderSum == 0) return TRUE;
46
47 /* Calculate the checksum */
48 Sum = 0;
49 Ptr = (PUSHORT) BaseAddress;
50 for (i = 0; i < ImageSize / sizeof (USHORT); i++)
51 {
52 Sum += (ULONG)*Ptr;
53 if (HIWORD(Sum) != 0)
54 {
55 Sum = LOWORD(Sum) + HIWORD(Sum);
56 }
57 Ptr++;
58 }
59
60 if (ImageSize & 1)
61 {
62 Sum += (ULONG)*((PUCHAR)Ptr);
63 if (HIWORD(Sum) != 0)
64 {
65 Sum = LOWORD(Sum) + HIWORD(Sum);
66 }
67 }
68
69 CalcSum = (USHORT)(LOWORD(Sum) + HIWORD(Sum));
70
71 /* Subtract image checksum from calculated checksum. */
72 /* fix low word of checksum */
73 if (LOWORD(CalcSum) >= LOWORD(HeaderSum))
74 {
75 CalcSum -= LOWORD(HeaderSum);
76 }
77 else
78 {
79 CalcSum = ((LOWORD(CalcSum) - LOWORD(HeaderSum)) & 0xFFFF) - 1;
80 }
81
82 /* Fix high word of checksum */
83 if (LOWORD(CalcSum) >= HIWORD(HeaderSum))
84 {
85 CalcSum -= HIWORD(HeaderSum);
86 }
87 else
88 {
89 CalcSum = ((LOWORD(CalcSum) - HIWORD(HeaderSum)) & 0xFFFF) - 1;
90 }
91
92 /* Add file length */
93 CalcSum += ImageSize;
94
95 if (CalcSum != HeaderSum)
96 DPRINT1("Image %p checksum mismatches! 0x%x != 0x%x\n", BaseAddress, CalcSum, HeaderSum);
97
98 return (BOOLEAN)(CalcSum == HeaderSum);
99 }
100
101 /*
102 * @implemented
103 */
104 PIMAGE_NT_HEADERS
105 NTAPI
106 RtlImageNtHeader(IN PVOID BaseAddress)
107 {
108 PIMAGE_NT_HEADERS NtHeader;
109 PIMAGE_DOS_HEADER DosHeader = (PIMAGE_DOS_HEADER)BaseAddress;
110
111 if (DosHeader && SWAPW(DosHeader->e_magic) != IMAGE_DOS_SIGNATURE)
112 {
113 DPRINT1("DosHeader->e_magic %x\n", SWAPW(DosHeader->e_magic));
114 DPRINT1("NtHeader 0x%lx\n", ((ULONG_PTR)BaseAddress + SWAPD(DosHeader->e_lfanew)));
115 }
116 else
117 {
118 NtHeader = (PIMAGE_NT_HEADERS)((ULONG_PTR)BaseAddress + SWAPD(DosHeader->e_lfanew));
119 if (SWAPD(NtHeader->Signature) == IMAGE_NT_SIGNATURE)
120 return NtHeader;
121 }
122
123 return NULL;
124 }
125
126
127 /*
128 * @implemented
129 */
130 PVOID
131 NTAPI
132 RtlImageDirectoryEntryToData(
133 PVOID BaseAddress,
134 BOOLEAN MappedAsImage,
135 USHORT Directory,
136 PULONG Size)
137 {
138 PIMAGE_NT_HEADERS NtHeader;
139 ULONG Va;
140
141 /* Magic flag for non-mapped images. */
142 if ((ULONG_PTR)BaseAddress & 1)
143 {
144 BaseAddress = (PVOID)((ULONG_PTR)BaseAddress & ~1);
145 MappedAsImage = FALSE;
146 }
147
148
149 NtHeader = RtlImageNtHeader (BaseAddress);
150 if (NtHeader == NULL)
151 return NULL;
152
153 if (Directory >= SWAPD(NtHeader->OptionalHeader.NumberOfRvaAndSizes))
154 return NULL;
155
156 Va = SWAPD(NtHeader->OptionalHeader.DataDirectory[Directory].VirtualAddress);
157 if (Va == 0)
158 return NULL;
159
160 *Size = SWAPD(NtHeader->OptionalHeader.DataDirectory[Directory].Size);
161
162 if (MappedAsImage || Va < SWAPD(NtHeader->OptionalHeader.SizeOfHeaders))
163 return (PVOID)((ULONG_PTR)BaseAddress + Va);
164
165 /* image mapped as ordinary file, we must find raw pointer */
166 return RtlImageRvaToVa (NtHeader, BaseAddress, Va, NULL);
167 }
168
169
170 /*
171 * @implemented
172 */
173 PIMAGE_SECTION_HEADER
174 NTAPI
175 RtlImageRvaToSection(
176 PIMAGE_NT_HEADERS NtHeader,
177 PVOID BaseAddress,
178 ULONG Rva)
179 {
180 PIMAGE_SECTION_HEADER Section;
181 ULONG Va;
182 ULONG Count;
183
184 Count = SWAPW(NtHeader->FileHeader.NumberOfSections);
185 Section = IMAGE_FIRST_SECTION(NtHeader);
186
187 while (Count--)
188 {
189 Va = SWAPD(Section->VirtualAddress);
190 if ((Va <= Rva) &&
191 (Rva < Va + SWAPD(Section->Misc.VirtualSize)))
192 return Section;
193 Section++;
194 }
195 return NULL;
196 }
197
198
199 /*
200 * @implemented
201 */
202 PVOID
203 NTAPI
204 RtlImageRvaToVa(
205 PIMAGE_NT_HEADERS NtHeader,
206 PVOID BaseAddress,
207 ULONG Rva,
208 PIMAGE_SECTION_HEADER *SectionHeader)
209 {
210 PIMAGE_SECTION_HEADER Section = NULL;
211
212 if (SectionHeader)
213 Section = *SectionHeader;
214
215 if (Section == NULL ||
216 Rva < SWAPD(Section->VirtualAddress) ||
217 Rva >= SWAPD(Section->VirtualAddress) + SWAPD(Section->Misc.VirtualSize))
218 {
219 Section = RtlImageRvaToSection (NtHeader, BaseAddress, Rva);
220 if (Section == NULL)
221 return 0;
222
223 if (SectionHeader)
224 *SectionHeader = Section;
225 }
226
227 return (PVOID)((ULONG_PTR)BaseAddress +
228 Rva +
229 SWAPD(Section->PointerToRawData) -
230 (ULONG_PTR)SWAPD(Section->VirtualAddress));
231 }
232
233 PIMAGE_BASE_RELOCATION
234 NTAPI
235 LdrProcessRelocationBlockLongLong(
236 IN ULONG_PTR Address,
237 IN ULONG Count,
238 IN PUSHORT TypeOffset,
239 IN LONGLONG Delta)
240 {
241 SHORT Offset;
242 USHORT Type;
243 USHORT i;
244 PUSHORT ShortPtr;
245 PULONG LongPtr;
246 PULONGLONG LongLongPtr;
247
248 for (i = 0; i < Count; i++)
249 {
250 Offset = SWAPW(*TypeOffset) & 0xFFF;
251 Type = SWAPW(*TypeOffset) >> 12;
252 ShortPtr = (PUSHORT)(RVA(Address, Offset));
253
254 /*
255 * Don't relocate within the relocation section itself.
256 * GCC/LD generates sometimes relocation records for the relocation section.
257 * This is a bug in GCC/LD.
258 * Fix for it disabled, since it was only in ntoskrnl and not in ntdll
259 */
260 /*
261 if ((ULONG_PTR)ShortPtr < (ULONG_PTR)RelocationDir ||
262 (ULONG_PTR)ShortPtr >= (ULONG_PTR)RelocationEnd)
263 {*/
264 switch (Type)
265 {
266 /* case IMAGE_REL_BASED_SECTION : */
267 /* case IMAGE_REL_BASED_REL32 : */
268 case IMAGE_REL_BASED_ABSOLUTE:
269 break;
270
271 case IMAGE_REL_BASED_HIGH:
272 *ShortPtr = HIWORD(MAKELONG(0, *ShortPtr) + (LONG)Delta);
273 break;
274
275 case IMAGE_REL_BASED_LOW:
276 *ShortPtr = SWAPW(*ShortPtr) + LOWORD(Delta);
277 break;
278
279 case IMAGE_REL_BASED_HIGHLOW:
280 LongPtr = (PULONG)RVA(Address, Offset);
281 *LongPtr = SWAPD(*LongPtr) + (ULONG)Delta;
282 break;
283
284 case IMAGE_REL_BASED_DIR64:
285 LongLongPtr = (PUINT64)RVA(Address, Offset);
286 *LongLongPtr = SWAPQ(*LongLongPtr) + Delta;
287 break;
288
289 case IMAGE_REL_BASED_HIGHADJ:
290 case IMAGE_REL_BASED_MIPS_JMPADDR:
291 default:
292 DPRINT1("Unknown/unsupported fixup type %hu.\n", Type);
293 DPRINT1("Address %x, Current %d, Count %d, *TypeOffset %x\n", Address, i, Count, SWAPW(*TypeOffset));
294 return (PIMAGE_BASE_RELOCATION)NULL;
295 }
296
297 TypeOffset++;
298 }
299
300 return (PIMAGE_BASE_RELOCATION)TypeOffset;
301 }
302
303 ULONG
304 NTAPI
305 LdrRelocateImageWithBias(
306 IN PVOID BaseAddress,
307 IN LONGLONG AdditionalBias,
308 IN PCCH LoaderName,
309 IN ULONG Success,
310 IN ULONG Conflict,
311 IN ULONG Invalid)
312 {
313 PIMAGE_NT_HEADERS NtHeaders;
314 PIMAGE_DATA_DIRECTORY RelocationDDir;
315 PIMAGE_BASE_RELOCATION RelocationDir, RelocationEnd;
316 ULONG Count;
317 ULONG_PTR Address;
318 PUSHORT TypeOffset;
319 LONGLONG Delta;
320
321 NtHeaders = RtlImageNtHeader(BaseAddress);
322
323 if (NtHeaders == NULL)
324 return Invalid;
325
326 if (SWAPW(NtHeaders->FileHeader.Characteristics) & IMAGE_FILE_RELOCS_STRIPPED)
327 {
328 return Conflict;
329 }
330
331 RelocationDDir = &NtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
332
333 if (SWAPD(RelocationDDir->VirtualAddress) == 0 || SWAPD(RelocationDDir->Size) == 0)
334 {
335 return Success;
336 }
337
338 Delta = (ULONG_PTR)BaseAddress - SWAPD(NtHeaders->OptionalHeader.ImageBase) + AdditionalBias;
339 RelocationDir = (PIMAGE_BASE_RELOCATION)((ULONG_PTR)BaseAddress + SWAPD(RelocationDDir->VirtualAddress));
340 RelocationEnd = (PIMAGE_BASE_RELOCATION)((ULONG_PTR)RelocationDir + SWAPD(RelocationDDir->Size));
341
342 while (RelocationDir < RelocationEnd &&
343 SWAPW(RelocationDir->SizeOfBlock) > 0)
344 {
345 Count = (SWAPW(RelocationDir->SizeOfBlock) - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(USHORT);
346 Address = (ULONG_PTR)RVA(BaseAddress, SWAPD(RelocationDir->VirtualAddress));
347 TypeOffset = (PUSHORT)(RelocationDir + 1);
348
349 RelocationDir = LdrProcessRelocationBlockLongLong(Address,
350 Count,
351 TypeOffset,
352 Delta);
353
354 if (RelocationDir == NULL)
355 {
356 DPRINT1("Error during call to LdrProcessRelocationBlockLongLong()!\n");
357 return Invalid;
358 }
359 }
360
361 return Success;
362 }
363
364 /* EOF */