More LDR constants changes.
[reactos.git] / reactos / ntoskrnl / ldr / rtl.c
1 /* $Id$
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/ldr/loader.c
6 * PURPOSE: Loader utilities
7 * PROGRAMMERS: Jean Michault
8 * Rex Jolliff (rex@lvcablemodem.com)
9 */
10
11 /* INCLUDES *****************************************************************/
12
13 #include <ntoskrnl.h>
14 #define NDEBUG
15 #include <internal/debug.h>
16
17 /* FUNCTIONS ****************************************************************/
18
19
20 /*
21 * @implemented
22 */
23 PIMAGE_NT_HEADERS STDCALL
24 RtlImageNtHeader (IN PVOID BaseAddress)
25 {
26 PIMAGE_DOS_HEADER DosHeader;
27 PIMAGE_NT_HEADERS NTHeaders;
28
29 DosHeader = (PIMAGE_DOS_HEADER)BaseAddress;
30 NTHeaders = (PIMAGE_NT_HEADERS)((char*)BaseAddress + DosHeader->e_lfanew);
31 if ((DosHeader->e_magic != IMAGE_DOS_SIGNATURE)
32 || (DosHeader->e_lfanew == 0L)
33 || (*(PULONG) NTHeaders != IMAGE_NT_SIGNATURE))
34 {
35 return(NULL);
36 }
37 return(NTHeaders);
38 }
39
40
41 /*
42 * @implemented
43 */
44 PVOID STDCALL
45 RtlImageDirectoryEntryToData (IN PVOID BaseAddress,
46 IN BOOLEAN ImageLoaded,
47 IN ULONG Directory,
48 OUT PULONG Size)
49 {
50 PIMAGE_NT_HEADERS NtHeader;
51 PIMAGE_SECTION_HEADER SectionHeader;
52 ULONG Va;
53 ULONG Count;
54
55 NtHeader = RtlImageNtHeader (BaseAddress);
56 if (NtHeader == NULL)
57 return NULL;
58
59 if (Directory >= NtHeader->OptionalHeader.NumberOfRvaAndSizes)
60 return NULL;
61
62 Va = NtHeader->OptionalHeader.DataDirectory[Directory].VirtualAddress;
63 if (Va == 0)
64 return NULL;
65
66 if (Size)
67 *Size = NtHeader->OptionalHeader.DataDirectory[Directory].Size;
68
69 if (ImageLoaded)
70 return (PVOID)((char*)BaseAddress + Va);
71
72 /* image mapped as ordinary file, we must find raw pointer */
73 SectionHeader = (PIMAGE_SECTION_HEADER)(NtHeader + 1);
74 Count = NtHeader->FileHeader.NumberOfSections;
75 while (Count--)
76 {
77 if (SectionHeader->VirtualAddress == Va)
78 return (PVOID)((char*)BaseAddress + SectionHeader->PointerToRawData);
79 SectionHeader++;
80 }
81
82 return NULL;
83 }
84
85
86 PIMAGE_SECTION_HEADER
87 STDCALL
88 RtlImageRvaToSection (
89 PIMAGE_NT_HEADERS NtHeader,
90 PVOID BaseAddress,
91 ULONG Rva
92 )
93 {
94 PIMAGE_SECTION_HEADER Section;
95 ULONG Va;
96 ULONG Count;
97
98 Count = NtHeader->FileHeader.NumberOfSections;
99 Section = (PIMAGE_SECTION_HEADER)((ULONG)&NtHeader->OptionalHeader +
100 NtHeader->FileHeader.SizeOfOptionalHeader);
101 while (Count)
102 {
103 Va = Section->VirtualAddress;
104 if ((Va <= Rva) &&
105 (Rva < Va + Section->SizeOfRawData))
106 return Section;
107 Section++;
108 }
109 return NULL;
110 }
111
112
113 ULONG
114 STDCALL
115 RtlImageRvaToVa (
116 PIMAGE_NT_HEADERS NtHeader,
117 PVOID BaseAddress,
118 ULONG Rva,
119 PIMAGE_SECTION_HEADER *SectionHeader
120 )
121 {
122 PIMAGE_SECTION_HEADER Section = NULL;
123
124 if (SectionHeader)
125 Section = *SectionHeader;
126
127 if (Section == NULL ||
128 Rva < Section->VirtualAddress ||
129 Rva >= Section->VirtualAddress + Section->SizeOfRawData)
130 {
131 Section = RtlImageRvaToSection (NtHeader, BaseAddress, Rva);
132 if (Section == NULL)
133 return 0;
134
135 if (SectionHeader)
136 *SectionHeader = Section;
137 }
138
139 return (ULONG)((char*)BaseAddress +
140 Rva +
141 Section->PointerToRawData -
142 Section->VirtualAddress);
143 }
144
145 #define RVA(m, b) ((ULONG)b + m)
146
147 NTSTATUS STDCALL
148 LdrGetProcedureAddress (IN PVOID BaseAddress,
149 IN PANSI_STRING Name,
150 IN ULONG Ordinal,
151 OUT PVOID *ProcedureAddress)
152 {
153 PIMAGE_EXPORT_DIRECTORY ExportDir;
154 PUSHORT OrdinalPtr;
155 PULONG NamePtr;
156 PULONG AddressPtr;
157 ULONG i = 0;
158
159 /* get the pointer to the export directory */
160 ExportDir = (PIMAGE_EXPORT_DIRECTORY)
161 RtlImageDirectoryEntryToData (BaseAddress, TRUE,
162 IMAGE_DIRECTORY_ENTRY_EXPORT, &i);
163
164 if (!ExportDir || !i || !ProcedureAddress)
165 {
166 return(STATUS_INVALID_PARAMETER);
167 }
168
169 AddressPtr = (PULONG)RVA((char*)BaseAddress, ExportDir->AddressOfFunctions);
170 if (Name && Name->Length)
171 {
172 LONG minn, maxn;
173
174 /* by name */
175 OrdinalPtr =
176 (PUSHORT)RVA((char*)BaseAddress, ExportDir->AddressOfNameOrdinals);
177 NamePtr = (PULONG)RVA((char*)BaseAddress, ExportDir->AddressOfNames);
178
179 minn = 0; maxn = ExportDir->NumberOfNames;
180 while (minn <= maxn)
181 {
182 LONG mid;
183 LONG res;
184
185 mid = (minn + maxn) / 2;
186 res = _strnicmp(Name->Buffer, (PCH)RVA((char*)BaseAddress, NamePtr[mid]),
187 Name->Length);
188 if (res == 0)
189 {
190 *ProcedureAddress =
191 (PVOID)RVA((char*)BaseAddress, AddressPtr[OrdinalPtr[mid]]);
192 return(STATUS_SUCCESS);
193 }
194 else if (res > 0)
195 {
196 maxn = mid - 1;
197 }
198 else
199 {
200 minn = mid + 1;
201 }
202 }
203
204 for (i = 0; i < ExportDir->NumberOfNames; i++, NamePtr++, OrdinalPtr++)
205 {
206 if (!_strnicmp(Name->Buffer,
207 (char*)((char*)BaseAddress + *NamePtr), Name->Length))
208 {
209 *ProcedureAddress =
210 (PVOID)((ULONG)BaseAddress +
211 (ULONG)AddressPtr[*OrdinalPtr]);
212 return STATUS_SUCCESS;
213 }
214 }
215 CPRINT("LdrGetProcedureAddress: Can't resolve symbol '%Z'\n", Name);
216 }
217 else
218 {
219 /* by ordinal */
220 Ordinal &= 0x0000FFFF;
221 if (Ordinal - ExportDir->Base < ExportDir->NumberOfFunctions)
222 {
223 *ProcedureAddress =
224 (PVOID)((ULONG)BaseAddress +
225 (ULONG)AddressPtr[Ordinal - ExportDir->Base]);
226 return STATUS_SUCCESS;
227 }
228 CPRINT("LdrGetProcedureAddress: Can't resolve symbol @%d\n",
229 Ordinal);
230 }
231
232 return STATUS_PROCEDURE_NOT_FOUND;
233 }
234
235 /* EOF */