- Merge to trunk r37270.
[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 /* FUNCTIONS *****************************************************************/
20
21 BOOLEAN
22 NTAPI
23 LdrVerifyMappedImageMatchesChecksum(IN PVOID BaseAddress,
24 IN ULONG NumberOfBytes,
25 IN ULONG FileLength)
26 {
27 /* FIXME: TODO */
28 return TRUE;
29 }
30
31 /*
32 * @implemented
33 */
34 PIMAGE_NT_HEADERS NTAPI
35 RtlImageNtHeader (IN PVOID BaseAddress)
36 {
37 PIMAGE_NT_HEADERS NtHeader;
38 PIMAGE_DOS_HEADER DosHeader = (PIMAGE_DOS_HEADER)BaseAddress;
39
40 if (DosHeader && SWAPW(DosHeader->e_magic) != IMAGE_DOS_SIGNATURE)
41 {
42 DPRINT1("DosHeader->e_magic %x\n", SWAPW(DosHeader->e_magic));
43 DPRINT1("NtHeader 0x%lx\n", ((ULONG_PTR)BaseAddress + SWAPD(DosHeader->e_lfanew)));
44 }
45
46 if (DosHeader && SWAPW(DosHeader->e_magic) == IMAGE_DOS_SIGNATURE)
47 {
48 NtHeader = (PIMAGE_NT_HEADERS)((ULONG_PTR)BaseAddress + SWAPD(DosHeader->e_lfanew));
49 if (SWAPD(NtHeader->Signature) == IMAGE_NT_SIGNATURE)
50 return NtHeader;
51 }
52
53 return NULL;
54 }
55
56
57 /*
58 * @implemented
59 */
60 PVOID
61 NTAPI
62 RtlImageDirectoryEntryToData(PVOID BaseAddress,
63 BOOLEAN MappedAsImage,
64 USHORT Directory,
65 PULONG Size)
66 {
67 PIMAGE_NT_HEADERS NtHeader;
68 ULONG Va;
69
70 /* Magic flag for non-mapped images. */
71 if ((ULONG_PTR)BaseAddress & 1)
72 {
73 BaseAddress = (PVOID)((ULONG_PTR)BaseAddress & ~1);
74 MappedAsImage = FALSE;
75 }
76
77
78 NtHeader = RtlImageNtHeader (BaseAddress);
79 if (NtHeader == NULL)
80 return NULL;
81
82 if (Directory >= SWAPD(NtHeader->OptionalHeader.NumberOfRvaAndSizes))
83 return NULL;
84
85 Va = SWAPD(NtHeader->OptionalHeader.DataDirectory[Directory].VirtualAddress);
86 if (Va == 0)
87 return NULL;
88
89 *Size = SWAPD(NtHeader->OptionalHeader.DataDirectory[Directory].Size);
90
91 if (MappedAsImage || Va < SWAPD(NtHeader->OptionalHeader.SizeOfHeaders))
92 return (PVOID)((ULONG_PTR)BaseAddress + Va);
93
94 /* image mapped as ordinary file, we must find raw pointer */
95 return RtlImageRvaToVa (NtHeader, BaseAddress, Va, NULL);
96 }
97
98
99 /*
100 * @implemented
101 */
102 PIMAGE_SECTION_HEADER
103 NTAPI
104 RtlImageRvaToSection (
105 PIMAGE_NT_HEADERS NtHeader,
106 PVOID BaseAddress,
107 ULONG Rva
108 )
109 {
110 PIMAGE_SECTION_HEADER Section;
111 ULONG Va;
112 ULONG Count;
113
114 Count = SWAPW(NtHeader->FileHeader.NumberOfSections);
115 Section = IMAGE_FIRST_SECTION(NtHeader);
116
117 while (Count--)
118 {
119 Va = SWAPD(Section->VirtualAddress);
120 if ((Va <= Rva) &&
121 (Rva < Va + SWAPD(Section->Misc.VirtualSize)))
122 return Section;
123 Section++;
124 }
125 return NULL;
126 }
127
128
129 /*
130 * @implemented
131 */
132 PVOID
133 NTAPI
134 RtlImageRvaToVa (
135 PIMAGE_NT_HEADERS NtHeader,
136 PVOID BaseAddress,
137 ULONG Rva,
138 PIMAGE_SECTION_HEADER *SectionHeader
139 )
140 {
141 PIMAGE_SECTION_HEADER Section = NULL;
142
143 if (SectionHeader)
144 Section = *SectionHeader;
145
146 if (Section == NULL ||
147 Rva < SWAPD(Section->VirtualAddress) ||
148 Rva >= SWAPD(Section->VirtualAddress) + SWAPD(Section->Misc.VirtualSize))
149 {
150 Section = RtlImageRvaToSection (NtHeader, BaseAddress, Rva);
151 if (Section == NULL)
152 return 0;
153
154 if (SectionHeader)
155 *SectionHeader = Section;
156 }
157
158 return (PVOID)((ULONG_PTR)BaseAddress +
159 Rva +
160 SWAPD(Section->PointerToRawData) -
161 (ULONG_PTR)SWAPD(Section->VirtualAddress));
162 }
163
164 PIMAGE_BASE_RELOCATION
165 NTAPI
166 LdrProcessRelocationBlockLongLong(
167 IN ULONG_PTR Address,
168 IN ULONG Count,
169 IN PUSHORT TypeOffset,
170 IN LONGLONG Delta
171 )
172 {
173 SHORT Offset;
174 USHORT Type;
175 USHORT i;
176 PUSHORT ShortPtr;
177 PULONG LongPtr;
178 PULONGLONG LongLongPtr;
179
180 for (i = 0; i < Count; i++)
181 {
182 Offset = SWAPW(*TypeOffset) & 0xFFF;
183 Type = SWAPW(*TypeOffset) >> 12;
184 ShortPtr = (PUSHORT)(RVA(Address, Offset));
185
186 /*
187 * Don't relocate within the relocation section itself.
188 * GCC/LD generates sometimes relocation records for the relocation section.
189 * This is a bug in GCC/LD.
190 * Fix for it disabled, since it was only in ntoskrnl and not in ntdll
191 */
192 /*
193 if ((ULONG_PTR)ShortPtr < (ULONG_PTR)RelocationDir ||
194 (ULONG_PTR)ShortPtr >= (ULONG_PTR)RelocationEnd)
195 {*/
196 switch (Type)
197 {
198 /* case IMAGE_REL_BASED_SECTION : */
199 /* case IMAGE_REL_BASED_REL32 : */
200 case IMAGE_REL_BASED_ABSOLUTE:
201 break;
202
203 case IMAGE_REL_BASED_HIGH:
204 *ShortPtr = HIWORD(MAKELONG(0, *ShortPtr) + (LONG)Delta);
205 break;
206
207 case IMAGE_REL_BASED_LOW:
208 *ShortPtr = SWAPW(*ShortPtr) + LOWORD(Delta);
209 break;
210
211 case IMAGE_REL_BASED_HIGHLOW:
212 LongPtr = (PULONG)RVA(Address, Offset);
213 *LongPtr = SWAPD(*LongPtr) + (ULONG)Delta;
214 break;
215
216 case IMAGE_REL_BASED_DIR64:
217 LongLongPtr = (PUINT64)RVA(Address, Offset);
218 *LongLongPtr = SWAPQ(*LongLongPtr) + Delta;
219 break;
220
221 case IMAGE_REL_BASED_HIGHADJ:
222 case IMAGE_REL_BASED_MIPS_JMPADDR:
223 default:
224 DPRINT1("Unknown/unsupported fixup type %hu.\n", Type);
225 DPRINT1("Address %x, Current %d, Count %d, *TypeOffset %x\n", Address, i, Count, SWAPW(*TypeOffset));
226 return (PIMAGE_BASE_RELOCATION)NULL;
227 }
228
229 TypeOffset++;
230 }
231
232 return (PIMAGE_BASE_RELOCATION)TypeOffset;
233 }
234
235 ULONG
236 NTAPI
237 LdrRelocateImageWithBias(
238 IN PVOID BaseAddress,
239 IN LONGLONG AdditionalBias,
240 IN PCCH LoaderName,
241 IN ULONG Success,
242 IN ULONG Conflict,
243 IN ULONG Invalid
244 )
245 {
246 PIMAGE_NT_HEADERS NtHeaders;
247 PIMAGE_DATA_DIRECTORY RelocationDDir;
248 PIMAGE_BASE_RELOCATION RelocationDir, RelocationEnd;
249 ULONG Count;
250 ULONG_PTR Address;
251 PUSHORT TypeOffset;
252 LONGLONG Delta;
253
254 NtHeaders = RtlImageNtHeader(BaseAddress);
255
256 if (NtHeaders == NULL)
257 return Invalid;
258
259 if (SWAPW(NtHeaders->FileHeader.Characteristics) & IMAGE_FILE_RELOCS_STRIPPED)
260 {
261 return Conflict;
262 }
263
264 RelocationDDir = &NtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
265
266 if (SWAPD(RelocationDDir->VirtualAddress) == 0 || SWAPD(RelocationDDir->Size) == 0)
267 {
268 return Success;
269 }
270
271 Delta = (ULONG_PTR)BaseAddress - SWAPD(NtHeaders->OptionalHeader.ImageBase) + AdditionalBias;
272 RelocationDir = (PIMAGE_BASE_RELOCATION)((ULONG_PTR)BaseAddress + SWAPD(RelocationDDir->VirtualAddress));
273 RelocationEnd = (PIMAGE_BASE_RELOCATION)((ULONG_PTR)RelocationDir + SWAPD(RelocationDDir->Size));
274
275 while (RelocationDir < RelocationEnd &&
276 SWAPW(RelocationDir->SizeOfBlock) > 0)
277 {
278 Count = (SWAPW(RelocationDir->SizeOfBlock) - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(USHORT);
279 Address = (ULONG_PTR)RVA(BaseAddress, SWAPD(RelocationDir->VirtualAddress));
280 TypeOffset = (PUSHORT)(RelocationDir + 1);
281
282 RelocationDir = LdrProcessRelocationBlockLongLong(Address,
283 Count,
284 TypeOffset,
285 Delta);
286
287 if (RelocationDir == NULL)
288 {
289 DPRINT1("Error during call to LdrProcessRelocationBlockLongLong()!\n");
290 return Invalid;
291 }
292 }
293
294 return Success;
295 }
296 /* EOF */