Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

729 lines
22 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. blbind.c
  5. Abstract:
  6. This module contains the code that implements the funtions required
  7. to relocate an image and bind DLL entry points.
  8. Author:
  9. David N. Cutler (davec) 21-May-1991
  10. Revision History:
  11. Forrest Foltz (forrestf) 10-Jun-2000
  12. Broke out x86 32/64 code into this module
  13. --*/
  14. ARC_STATUS
  15. BlAllocateDataTableEntry (
  16. IN PCHAR BaseDllName,
  17. IN PCHAR FullDllName,
  18. IN PVOID Base,
  19. OUT PKLDR_DATA_TABLE_ENTRY *AllocatedEntry
  20. )
  21. /*++
  22. Routine Description:
  23. This routine allocates a data table entry for the specified image
  24. and inserts the entry in the loaded module list.
  25. Arguments:
  26. BaseDllName - Supplies a pointer to a zero terminated base DLL name.
  27. FullDllName - Supplies a pointer to a zero terminated full DLL name.
  28. Base - Supplies a pointer to the base of the DLL image.
  29. AllocatedEntry - Supplies a pointer to a variable that receives a
  30. pointer to the allocated data table entry.
  31. Return Value:
  32. ESUCCESS is returned if a data table entry is allocated. Otherwise,
  33. return a unsuccessful status.
  34. --*/
  35. {
  36. PWSTR Buffer;
  37. PKLDR_DATA_TABLE_ENTRY DataTableEntry;
  38. PIMAGE_NT_HEADERS NtHeaders;
  39. USHORT Length;
  40. //
  41. // Allocate a data table entry.
  42. //
  43. DataTableEntry =
  44. (PKLDR_DATA_TABLE_ENTRY)BlAllocateHeap(sizeof(KLDR_DATA_TABLE_ENTRY));
  45. if (DataTableEntry == NULL) {
  46. return ENOMEM;
  47. }
  48. //
  49. // Initialize the address of the DLL image file header and the entry
  50. // point address.
  51. //
  52. NtHeaders = RtlImageNtHeader(Base);
  53. DataTableEntry->DllBase = Base;
  54. DataTableEntry->SizeOfImage = NtHeaders->OptionalHeader.SizeOfImage;
  55. DataTableEntry->EntryPoint = (PVOID)((ULONG_PTR)Base +
  56. NtHeaders->OptionalHeader.AddressOfEntryPoint);
  57. DataTableEntry->SectionPointer = 0;
  58. DataTableEntry->CheckSum = NtHeaders->OptionalHeader.CheckSum;
  59. //
  60. // Compute the length of the base DLL name, allocate a buffer to hold
  61. // the name, copy the name into the buffer, and initialize the base
  62. // DLL string descriptor.
  63. //
  64. Length = (USHORT)(strlen(BaseDllName) * sizeof(WCHAR));
  65. Buffer = (PWSTR)BlAllocateHeap(Length);
  66. if (Buffer == NULL) {
  67. return ENOMEM;
  68. }
  69. DataTableEntry->BaseDllName.Length = Length;
  70. DataTableEntry->BaseDllName.MaximumLength = Length;
  71. DataTableEntry->BaseDllName.Buffer = Buffer;
  72. while (*BaseDllName != 0) {
  73. *Buffer++ = *BaseDllName++;
  74. }
  75. //
  76. // Compute the length of the full DLL name, allocate a buffer to hold
  77. // the name, copy the name into the buffer, and initialize the full
  78. // DLL string descriptor.
  79. //
  80. Length = (USHORT)(strlen(FullDllName) * sizeof(WCHAR));
  81. Buffer = (PWSTR)BlAllocateHeap(Length);
  82. if (Buffer == NULL) {
  83. return ENOMEM;
  84. }
  85. DataTableEntry->FullDllName.Length = Length;
  86. DataTableEntry->FullDllName.MaximumLength = Length;
  87. DataTableEntry->FullDllName.Buffer = Buffer;
  88. while (*FullDllName != 0) {
  89. *Buffer++ = *FullDllName++;
  90. }
  91. //
  92. // Initialize the flags, load count, and insert the data table entry
  93. // in the loaded module list.
  94. //
  95. DataTableEntry->Flags = LDRP_ENTRY_PROCESSED;
  96. DataTableEntry->LoadCount = 1;
  97. InsertTailList(&BlLoaderBlock->LoadOrderListHead,
  98. &DataTableEntry->InLoadOrderLinks);
  99. *AllocatedEntry = DataTableEntry;
  100. return ESUCCESS;
  101. }
  102. ARC_STATUS
  103. BlpBindImportName (
  104. IN PVOID DllBase,
  105. IN PVOID ImageBase,
  106. IN PIMAGE_THUNK_DATA ThunkEntry,
  107. IN PIMAGE_EXPORT_DIRECTORY ExportDirectory,
  108. IN ULONG ExportSize,
  109. IN BOOLEAN SnapForwarder
  110. )
  111. /*++
  112. Routine Description:
  113. This routine binds an import table reference with an exported entry
  114. point and fills in the thunk data.
  115. Arguments:
  116. DllBase - Supplies the base address of the DLL image that contains
  117. the export directory. On x86 systems, a NULL DllBase binds the
  118. import table reference to the OsLoader's exported entry points.
  119. ImageBase - Supplies the base address of the image that contains
  120. the import thunk table.
  121. ThunkEntry - Supplies a pointer to a thunk table entry.
  122. ExportDirectory - Supplies a pointer to the export directory of the
  123. DLL from which references are to be resolved.
  124. SnapForwarder - determine if the snap is for a forwarder, and therefore
  125. Address of Data is already setup.
  126. Return Value:
  127. ESUCCESS is returned if the specified thunk is bound. Otherwise, an
  128. return an unsuccessful status.
  129. --*/
  130. {
  131. PULONG FunctionTable;
  132. LONG High;
  133. ULONG HintIndex;
  134. LONG Low;
  135. LONG Middle;
  136. PULONG NameTable;
  137. ULONG Ordinal;
  138. PUSHORT OrdinalTable;
  139. LONG Result;
  140. PUCHAR Temp;
  141. #if defined(_X86_)
  142. if(DllBase == NULL) {
  143. DllBase = (PVOID)OsLoaderBase;
  144. }
  145. #endif
  146. //
  147. // If the reference is by ordinal, then compute the ordinal number.
  148. // Otherwise, lookup the import name in the export directory.
  149. //
  150. if (IMAGE_SNAP_BY_ORDINAL(ThunkEntry->u1.Ordinal) && !SnapForwarder) {
  151. //
  152. // Compute the ordinal.
  153. //
  154. Ordinal = (ULONG)(IMAGE_ORDINAL(ThunkEntry->u1.Ordinal) - ExportDirectory->Base);
  155. } else {
  156. if (!SnapForwarder) {
  157. //
  158. // Change AddressOfData from an RVA to a VA.
  159. //
  160. ThunkEntry->u1.AddressOfData = ((ULONG_PTR)ImageBase + ThunkEntry->u1.AddressOfData);
  161. }
  162. //
  163. // Lookup the import name in the export table to determine the
  164. // ordinal.
  165. //
  166. NameTable = (PULONG)((ULONG_PTR)DllBase +
  167. ExportDirectory->AddressOfNames);
  168. OrdinalTable = (PUSHORT)((ULONG_PTR)DllBase +
  169. ExportDirectory->AddressOfNameOrdinals);
  170. //
  171. // If the hint index is within the limits of the name table and the
  172. // import and export names match, then the ordinal number can be
  173. // obtained directly from the ordinal table. Otherwise, the name
  174. // table must be searched for the specified name.
  175. //
  176. HintIndex = ((PIMAGE_IMPORT_BY_NAME)ThunkEntry->u1.AddressOfData)->Hint;
  177. if ((HintIndex < ExportDirectory->NumberOfNames) &&
  178. (strcmp(&((PIMAGE_IMPORT_BY_NAME)ThunkEntry->u1.AddressOfData)->Name[0],
  179. (PCHAR)((ULONG_PTR)DllBase + NameTable[HintIndex])) == 0)) {
  180. //
  181. // Get the ordinal number from the ordinal table.
  182. //
  183. Ordinal = OrdinalTable[HintIndex];
  184. } else {
  185. //
  186. // Lookup the import name in the name table using a binary search.
  187. //
  188. Low = 0;
  189. High = ExportDirectory->NumberOfNames - 1;
  190. while (High >= Low) {
  191. //
  192. // Compute the next probe index and compare the import name
  193. // with the export name entry.
  194. //
  195. Middle = (Low + High) >> 1;
  196. Result = strcmp(&((PIMAGE_IMPORT_BY_NAME)ThunkEntry->u1.AddressOfData)->Name[0],
  197. (PCHAR)((ULONG_PTR)DllBase + NameTable[Middle]));
  198. if (Result < 0) {
  199. High = Middle - 1;
  200. } else if (Result > 0) {
  201. Low = Middle + 1;
  202. } else {
  203. break;
  204. }
  205. }
  206. //
  207. // If the high index is less than the low index, then a matching
  208. // table entry was not found. Otherwise, get the ordinal number
  209. // from the ordinal table.
  210. //
  211. if (High < Low) {
  212. return EINVAL;
  213. } else {
  214. Ordinal = OrdinalTable[Middle];
  215. }
  216. }
  217. }
  218. //
  219. // If the ordinal number is valid, then bind the import reference and
  220. // return success. Otherwise, return an unsuccessful status.
  221. //
  222. if (Ordinal >= ExportDirectory->NumberOfFunctions) {
  223. return EINVAL;
  224. } else {
  225. FunctionTable = (PULONG)((ULONG_PTR)DllBase + ExportDirectory->AddressOfFunctions);
  226. ThunkEntry->u1.Function = ((ULONG_PTR)DllBase + FunctionTable[Ordinal]);
  227. //
  228. // Check for a forwarder.
  229. //
  230. if ( ((ULONG_PTR)ThunkEntry->u1.Function > (ULONG_PTR)ExportDirectory) &&
  231. ((ULONG_PTR)ThunkEntry->u1.Function < ((ULONG_PTR)ExportDirectory + ExportSize)) ) {
  232. CHAR ForwardDllName[10];
  233. PKLDR_DATA_TABLE_ENTRY DataTableEntry;
  234. ULONG TargetExportSize;
  235. PIMAGE_EXPORT_DIRECTORY TargetExportDirectory;
  236. RtlCopyMemory(ForwardDllName,
  237. (PCHAR)ThunkEntry->u1.Function,
  238. sizeof(ForwardDllName));
  239. Temp = strchr(ForwardDllName,'.');
  240. ASSERT(Temp != NULL); // Malformed name, stop here and debug why.
  241. if (Temp != NULL) {
  242. *Temp = '\0';
  243. }
  244. if (!BlCheckForLoadedDll(ForwardDllName,&DataTableEntry)) {
  245. //
  246. // Should load the referenced DLL here, just return failure for now.
  247. //
  248. return(EINVAL);
  249. }
  250. TargetExportDirectory = (PIMAGE_EXPORT_DIRECTORY)
  251. RtlImageDirectoryEntryToData(DataTableEntry->DllBase,
  252. TRUE,
  253. IMAGE_DIRECTORY_ENTRY_EXPORT,
  254. &TargetExportSize);
  255. if (TargetExportDirectory) {
  256. IMAGE_THUNK_DATA thunkData;
  257. PIMAGE_IMPORT_BY_NAME addressOfData;
  258. UCHAR Buffer[128];
  259. ULONG length;
  260. PCHAR ImportName;
  261. ARC_STATUS Status;
  262. ImportName = strchr((PCHAR)ThunkEntry->u1.Function, '.') + 1;
  263. addressOfData = (PIMAGE_IMPORT_BY_NAME)Buffer;
  264. RtlCopyMemory(&addressOfData->Name[0], ImportName, strlen(ImportName)+1);
  265. addressOfData->Hint = 0;
  266. thunkData.u1.AddressOfData = (ULONG_PTR)addressOfData;
  267. Status = BlpBindImportName(DataTableEntry->DllBase,
  268. ImageBase,
  269. &thunkData,
  270. TargetExportDirectory,
  271. TargetExportSize,
  272. TRUE);
  273. ThunkEntry->u1 = thunkData.u1;
  274. return(Status);
  275. } else {
  276. return(EINVAL);
  277. }
  278. }
  279. return ESUCCESS;
  280. }
  281. }
  282. ARC_STATUS
  283. BlpScanImportAddressTable(
  284. IN PVOID DllBase,
  285. IN PVOID ImageBase,
  286. IN PIMAGE_THUNK_DATA ThunkTable
  287. )
  288. /*++
  289. Routine Description:
  290. This routine scans the import address table for the specified image
  291. file and snaps each reference.
  292. Arguments:
  293. DllBase - Supplies the base address of the specified DLL.
  294. If NULL, then references in the image's import table are to
  295. be resolved against the osloader's export table.
  296. ImageBase - Supplies the base address of the image.
  297. ThunkTable - Supplies a pointer to the import thunk table.
  298. Return Value:
  299. ESUCCESS is returned in the scan is successful. Otherwise, return an
  300. unsuccessful status.
  301. --*/
  302. {
  303. PIMAGE_EXPORT_DIRECTORY ExportDirectory;
  304. ULONG ExportTableSize;
  305. ARC_STATUS Status;
  306. //
  307. // Locate the export table in the image specified by the DLL base
  308. // address.
  309. //
  310. #if i386
  311. if (DllBase == NULL) {
  312. ExportDirectory = (PIMAGE_EXPORT_DIRECTORY)OsLoaderExports;
  313. ExportTableSize = 0; // this is OK as this is only used to bind forwarded exports and osloader does not have any
  314. } else {
  315. ExportDirectory =
  316. (PIMAGE_EXPORT_DIRECTORY)RtlImageDirectoryEntryToData(DllBase,
  317. TRUE,
  318. IMAGE_DIRECTORY_ENTRY_EXPORT,
  319. &ExportTableSize);
  320. }
  321. #else
  322. ExportDirectory =
  323. (PIMAGE_EXPORT_DIRECTORY)RtlImageDirectoryEntryToData(DllBase,
  324. TRUE,
  325. IMAGE_DIRECTORY_ENTRY_EXPORT,
  326. &ExportTableSize);
  327. #endif
  328. if (ExportDirectory == NULL) {
  329. return EBADF;
  330. }
  331. //
  332. // Scan the thunk table and bind each import reference.
  333. //
  334. while (ThunkTable->u1.AddressOfData) {
  335. Status = BlpBindImportName(DllBase,
  336. ImageBase,
  337. ThunkTable++,
  338. ExportDirectory,
  339. ExportTableSize,
  340. FALSE);
  341. if (Status != ESUCCESS) {
  342. return Status;
  343. }
  344. }
  345. return ESUCCESS;
  346. }
  347. ARC_STATUS
  348. BlScanImportDescriptorTable(
  349. IN PPATH_SET PathSet,
  350. IN PKLDR_DATA_TABLE_ENTRY ScanEntry,
  351. IN TYPE_OF_MEMORY MemoryType
  352. )
  353. /*++
  354. Routine Description:
  355. This routine scans the import descriptor table for the specified image
  356. file and loads each DLL that is referenced.
  357. Arguments:
  358. PathSet - Supplies a pointer to a set of paths to scan when searching
  359. for DLL's.
  360. ScanEntry - Supplies a pointer to the data table entry for the
  361. image whose import table is to be scanned.
  362. MemoryType - Supplies the type of memory to to be assigned to any DLL's
  363. referenced.
  364. Return Value:
  365. ESUCCESS is returned in the scan is successful. Otherwise, return an
  366. unsuccessful status.
  367. --*/
  368. {
  369. PKLDR_DATA_TABLE_ENTRY DataTableEntry;
  370. CHAR FullDllName[256];
  371. PVOID Base;
  372. PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor;
  373. ULONG ImportTableSize;
  374. ARC_STATUS Status;
  375. PSZ ImportName;
  376. ULONG Index;
  377. PPATH_SOURCE PathSource;
  378. //
  379. // Locate the import table in the image specified by the data table entry.
  380. //
  381. ImportDescriptor =
  382. (PIMAGE_IMPORT_DESCRIPTOR)RtlImageDirectoryEntryToData(ScanEntry->DllBase,
  383. TRUE,
  384. IMAGE_DIRECTORY_ENTRY_IMPORT,
  385. &ImportTableSize);
  386. //
  387. // If the image has an import directory, then scan the import table and
  388. // load the specified DLLs.
  389. //
  390. if (ImportDescriptor != NULL) {
  391. while ((ImportDescriptor->Name != 0) &&
  392. (ImportDescriptor->FirstThunk != 0)) {
  393. //
  394. // Change the name from an RVA to a VA.
  395. //
  396. ImportName = (PSZ)((ULONG_PTR)ScanEntry->DllBase + ImportDescriptor->Name);
  397. //
  398. // If the DLL references itself, then skip the import entry.
  399. //
  400. if (BlpCompareDllName((PCHAR)ImportName,
  401. &ScanEntry->BaseDllName) == FALSE) {
  402. //
  403. // If the DLL is not already loaded, then load the DLL and
  404. // scan its import table.
  405. //
  406. if (BlCheckForLoadedDll((PCHAR)ImportName,
  407. &DataTableEntry) == FALSE) {
  408. //
  409. // Start walking our list of DevicePaths. If the list is
  410. // empty (bad caller!) we fail with ENOENT.
  411. //
  412. Status = ENOENT;
  413. for(Index=0; Index < PathSet->PathCount; Index++) {
  414. PathSource = &PathSet->Source[Index];
  415. strcpy(&FullDllName[0], PathSource->DirectoryPath);
  416. strcat(&FullDllName[0], PathSet->PathOffset);
  417. strcat(&FullDllName[0], (PCHAR)ImportName);
  418. Status = BlLoadImage(
  419. PathSource->DeviceId,
  420. MemoryType,
  421. &FullDllName[0],
  422. TARGET_IMAGE,
  423. &Base
  424. );
  425. if (Status == ESUCCESS) {
  426. BlOutputLoadMessage(
  427. (PCHAR) PathSource->DeviceName,
  428. &FullDllName[0],
  429. NULL
  430. );
  431. break;
  432. }
  433. }
  434. if (Status != ESUCCESS) {
  435. return Status;
  436. }
  437. //
  438. // ISSUE - 2000/29/03 - ADRIAO: Existant namespace polution
  439. // For the FullDllName field We should really be passing
  440. // in AliasName\PathOffset\ImportName.
  441. //
  442. Status = BlAllocateDataTableEntry((PCHAR)ImportName,
  443. &FullDllName[0],
  444. Base,
  445. &DataTableEntry);
  446. if (Status != ESUCCESS) {
  447. return Status;
  448. }
  449. DataTableEntry->Flags |= (ScanEntry->Flags & LDRP_DRIVER_DEPENDENT_DLL);
  450. Status = BlScanImportDescriptorTable(PathSet,
  451. DataTableEntry,
  452. MemoryType);
  453. if (Status != ESUCCESS) {
  454. return Status;
  455. }
  456. //
  457. // BlAllocateDataTableEntry inserts the data table entry into the load order
  458. // linked list in the order the dlls were found. We want the order to be the
  459. // order of dependency. For example if driver A needed Dll B which needed Dll C
  460. // we want the order to be ACB and not ABC. So here we remove this DLLs entry
  461. // and add it at the end. This way when IoInitializeBootDrivers calls DllInitialize
  462. // it will call them in the right order.
  463. //
  464. if (DataTableEntry->Flags &LDRP_DRIVER_DEPENDENT_DLL) {
  465. RemoveEntryList(&(DataTableEntry)->InLoadOrderLinks);
  466. InsertTailList(&BlLoaderBlock->LoadOrderListHead,
  467. &DataTableEntry->InLoadOrderLinks);
  468. }
  469. } else {
  470. //
  471. // Dll already exists but it might not be marked as a driver dependent DLL.
  472. // For example it might be a driver. So mark it now.
  473. //
  474. DataTableEntry->Flags |= (ScanEntry->Flags & LDRP_DRIVER_DEPENDENT_DLL);
  475. }
  476. //
  477. // Scan the import address table and snap links.
  478. //
  479. Status = BlpScanImportAddressTable(DataTableEntry->DllBase,
  480. ScanEntry->DllBase,
  481. (PIMAGE_THUNK_DATA)((ULONG_PTR)ScanEntry->DllBase +
  482. ImportDescriptor->FirstThunk));
  483. if (Status != ESUCCESS) {
  484. return Status;
  485. }
  486. }
  487. ImportDescriptor += 1;
  488. }
  489. }
  490. return ESUCCESS;
  491. }
  492. ARC_STATUS
  493. BlScanOsloaderBoundImportTable (
  494. IN PKLDR_DATA_TABLE_ENTRY ScanEntry
  495. )
  496. /*++
  497. Routine Description:
  498. This routine scans the import descriptor table for the specified image
  499. file and loads each DLL that is referenced.
  500. Arguments:
  501. DataTableEntry - Supplies a pointer to the data table entry for the
  502. image whose import table is to be scanned.
  503. Return Value:
  504. ESUCCESS is returned in the scan is successful. Otherwise, return an
  505. unsuccessful status.
  506. --*/
  507. {
  508. PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor;
  509. ULONG ImportTableSize;
  510. ARC_STATUS Status;
  511. PSZ ImportName;
  512. //
  513. // Locate the import table in the image specified by the data table entry.
  514. //
  515. ImportDescriptor =
  516. (PIMAGE_IMPORT_DESCRIPTOR)RtlImageDirectoryEntryToData(ScanEntry->DllBase,
  517. TRUE,
  518. IMAGE_DIRECTORY_ENTRY_IMPORT,
  519. &ImportTableSize);
  520. //
  521. // If the image has an import directory, then scan the import table.
  522. //
  523. if (ImportDescriptor != NULL) {
  524. while ((ImportDescriptor->Name != 0) &&
  525. (ImportDescriptor->FirstThunk != 0)) {
  526. //
  527. // Change the name from an RVA to a VA.
  528. //
  529. ImportName = (PSZ)((ULONG_PTR)ScanEntry->DllBase + ImportDescriptor->Name);
  530. //
  531. // If the DLL references itself, then skip the import entry.
  532. //
  533. if (BlpCompareDllName((PCHAR)ImportName,
  534. &ScanEntry->BaseDllName) == FALSE) {
  535. //
  536. // Scan the import address table and snap links.
  537. //
  538. Status = BlpScanImportAddressTable(NULL,
  539. ScanEntry->DllBase,
  540. (PIMAGE_THUNK_DATA)((ULONG_PTR)ScanEntry->DllBase +
  541. ImportDescriptor->FirstThunk));
  542. if (Status != ESUCCESS) {
  543. return Status;
  544. }
  545. }
  546. ImportDescriptor += 1;
  547. }
  548. }
  549. return ESUCCESS;
  550. }