Bring back ext2 code from branch
[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 = (PIMAGE_SECTION_HEADER)((ULONG)&NtHeader->OptionalHeader +
116 SWAPW(NtHeader->FileHeader.SizeOfOptionalHeader));
117 while (Count)
118 {
119 Va = SWAPD(Section->VirtualAddress);
120 if ((Va <= Rva) &&
121 (Rva < Va + SWAPD(Section->SizeOfRawData)))
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->SizeOfRawData))
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
179 for (i = 0; i < Count; i++)
180 {
181 Offset = SWAPW(*TypeOffset) & 0xFFF;
182 Type = SWAPW(*TypeOffset) >> 12;
183 ShortPtr = (PUSHORT)(RVA(Address, Offset));
184
185 /*
186 * Don't relocate within the relocation section itself.
187 * GCC/LD generates sometimes relocation records for the relocation section.
188 * This is a bug in GCC/LD.
189 * Fix for it disabled, since it was only in ntoskrnl and not in ntdll
190 */
191 /*
192 if ((ULONG_PTR)ShortPtr < (ULONG_PTR)RelocationDir ||
193 (ULONG_PTR)ShortPtr >= (ULONG_PTR)RelocationEnd)
194 {*/
195 switch (Type)
196 {
197 /* case IMAGE_REL_BASED_SECTION : */
198 /* case IMAGE_REL_BASED_REL32 : */
199 case IMAGE_REL_BASED_ABSOLUTE:
200 break;
201
202 case IMAGE_REL_BASED_HIGH:
203 *ShortPtr = HIWORD(MAKELONG(0, *ShortPtr) + (LONG)Delta);
204 break;
205
206 case IMAGE_REL_BASED_LOW:
207 *ShortPtr = SWAPW(*ShortPtr) + LOWORD(Delta);
208 break;
209
210 case IMAGE_REL_BASED_HIGHLOW:
211 LongPtr = (PULONG)RVA(Address, Offset);
212 *LongPtr = SWAPD(*LongPtr) + (ULONG)Delta;
213 break;
214
215 case IMAGE_REL_BASED_HIGHADJ:
216 case IMAGE_REL_BASED_MIPS_JMPADDR:
217 default:
218 DPRINT1("Unknown/unsupported fixup type %hu.\n", Type);
219 DPRINT1("Address %x, Current %d, Count %d, *TypeOffset %x\n", Address, i, Count, SWAPW(*TypeOffset));
220 return (PIMAGE_BASE_RELOCATION)NULL;
221 }
222
223 TypeOffset++;
224 }
225
226 return (PIMAGE_BASE_RELOCATION)TypeOffset;
227 }
228
229 ULONG
230 NTAPI
231 LdrRelocateImageWithBias(
232 IN PVOID BaseAddress,
233 IN LONGLONG AdditionalBias,
234 IN PCCH LoaderName,
235 IN ULONG Success,
236 IN ULONG Conflict,
237 IN ULONG Invalid
238 )
239 {
240 PIMAGE_NT_HEADERS NtHeaders;
241 PIMAGE_DATA_DIRECTORY RelocationDDir;
242 PIMAGE_BASE_RELOCATION RelocationDir, RelocationEnd;
243 ULONG Count;
244 ULONG_PTR Address;
245 PUSHORT TypeOffset;
246 LONGLONG Delta;
247
248 NtHeaders = RtlImageNtHeader(BaseAddress);
249
250 if (NtHeaders == NULL)
251 return Invalid;
252
253 if (SWAPW(NtHeaders->FileHeader.Characteristics) & IMAGE_FILE_RELOCS_STRIPPED)
254 {
255 return Conflict;
256 }
257
258 RelocationDDir = &NtHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
259
260 if (SWAPD(RelocationDDir->VirtualAddress) == 0 || SWAPD(RelocationDDir->Size) == 0)
261 {
262 return Success;
263 }
264
265 Delta = (ULONG_PTR)BaseAddress - SWAPD(NtHeaders->OptionalHeader.ImageBase) + AdditionalBias;
266 RelocationDir = (PIMAGE_BASE_RELOCATION)((ULONG_PTR)BaseAddress + SWAPD(RelocationDDir->VirtualAddress));
267 RelocationEnd = (PIMAGE_BASE_RELOCATION)((ULONG_PTR)RelocationDir + SWAPD(RelocationDDir->Size));
268
269 while (RelocationDir < RelocationEnd &&
270 SWAPW(RelocationDir->SizeOfBlock) > 0)
271 {
272 Count = (SWAPW(RelocationDir->SizeOfBlock) - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(USHORT);
273 Address = (ULONG_PTR)RVA(BaseAddress, SWAPD(RelocationDir->VirtualAddress));
274 TypeOffset = (PUSHORT)(RelocationDir + 1);
275
276 RelocationDir = LdrProcessRelocationBlockLongLong(Address,
277 Count,
278 TypeOffset,
279 Delta);
280
281 if (RelocationDir == NULL)
282 {
283 DPRINT1("Error during call to LdrProcessRelocationBlockLongLong()!\n");
284 return Invalid;
285 }
286 }
287
288 return Success;
289 }
290 /* EOF */