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