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