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