:pserver:cvsanon@mok.lvcm.com:/CVS/ReactOS reactos
[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 PIMAGE_NT_HEADERS STDCALL 
27 RtlImageNtHeader (IN PVOID BaseAddress)
28 {
29    PIMAGE_DOS_HEADER DosHeader;
30    PIMAGE_NT_HEADERS NTHeaders;
31    
32    DosHeader = (PIMAGE_DOS_HEADER)BaseAddress;
33    NTHeaders = (PIMAGE_NT_HEADERS)(BaseAddress + DosHeader->e_lfanew);
34    if ((DosHeader->e_magic != IMAGE_DOS_MAGIC)
35        || (DosHeader->e_lfanew == 0L)
36        || (*(PULONG) NTHeaders != IMAGE_PE_MAGIC))
37      {
38         return(NULL);
39      }
40    return(NTHeaders);
41 }
42
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)(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)(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)(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(BaseAddress, ExportDir->AddressOfFunctions);
170    if (Name && Name->Length)
171      {
172        ULONG minn, maxn;
173
174         /* by name */
175        OrdinalPtr = 
176          (PUSHORT)RVA(BaseAddress, ExportDir->AddressOfNameOrdinals);
177        NamePtr = (PULONG)RVA(BaseAddress, ExportDir->AddressOfNames);
178
179         minn = 0; maxn = ExportDir->NumberOfNames;
180         while (minn <= maxn)
181           {
182             ULONG mid;
183             LONG res;
184
185             mid = (minn + maxn) / 2;
186             res = _strnicmp(Name->Buffer, (PCH)RVA(BaseAddress, NamePtr[mid]),
187                             Name->Length);
188             if (res == 0)
189               {
190                 *ProcedureAddress = 
191                   (PVOID)RVA(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*)(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 */