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.

575 lines
16 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. peldrt.c
  5. Abstract:
  6. This module implements the code to load a PE format image into memory
  7. and relocate it if necessary.
  8. Author:
  9. David N. Cutler (davec) 10-May-1991
  10. Environment:
  11. Kernel mode only.
  12. Revision History:
  13. Forrest Foltz (forrestf) 10-Jun-2000
  14. Broke out x86 32/64 code into this module
  15. --*/
  16. extern BOOLEAN BlBootingFromNet;
  17. ARC_STATUS
  18. BlLoadImageEx(
  19. IN ULONG DeviceId,
  20. IN TYPE_OF_MEMORY MemoryType,
  21. IN PCHAR LoadFile,
  22. IN USHORT ImageType,
  23. IN OPTIONAL ULONG PreferredAlignment,
  24. IN OPTIONAL ULONG PreferredBasePage,
  25. OUT PVOID *ImageBase
  26. )
  27. /*++
  28. Routine Description:
  29. This routine attempts to load the specified file from the specified
  30. device.
  31. Arguments:
  32. DeviceId - Supplies the file table index of the device to load the
  33. specified image file from.
  34. MemoryType - Supplies the type of memory to to be assigned to the
  35. allocated memory descriptor.
  36. BootFile - Supplies a pointer to string descriptor for the name of
  37. the file to load.
  38. ImageType - Supplies the type of image that is expected.
  39. PreferredAlignment - If present, supplies the preferred image alignment.
  40. PreferredBasePage - If present, supplies the preferred base page which will
  41. override the image base address
  42. ImageBase - Supplies a pointer to a variable that receives the
  43. address of the image base.
  44. Return Value:
  45. ESUCCESS is returned if the specified image file is loaded
  46. successfully. Otherwise, an unsuccessful status is returned
  47. that describes the reason for failure.
  48. --*/
  49. {
  50. ULONG ActualBase;
  51. ULONG BasePage;
  52. ULONG Count;
  53. ULONG FileId;
  54. ULONG_PTR NewImageBase;
  55. ULONG Index;
  56. UCHAR LocalBuffer[(SECTOR_SIZE * 2) + 256];
  57. PUCHAR LocalPointer;
  58. ULONG NumberOfSections;
  59. ULONG PageCount;
  60. USHORT MachineType;
  61. ARC_STATUS Status;
  62. PIMAGE_NT_HEADERS NtHeaders;
  63. PIMAGE_SECTION_HEADER SectionHeader;
  64. LARGE_INTEGER SeekPosition;
  65. ULONG RelocSize;
  66. PIMAGE_BASE_RELOCATION RelocDirectory;
  67. ULONG RelocPage;
  68. ULONG RelocPageCount;
  69. PMEMORY_ALLOCATION_DESCRIPTOR MemoryDescriptor;
  70. FILE_INFORMATION FileInfo;
  71. PUSHORT AdjustSum;
  72. USHORT PartialSum;
  73. ULONG CheckSum;
  74. ULONG VirtualSize;
  75. ULONG SizeOfRawData;
  76. BOOLEAN bCloseFile = FALSE;
  77. BOOLEAN bFreeCache = FALSE;
  78. IMAGE_PREFETCH_CACHE ImgCache = {0};
  79. if (PreferredAlignment == 0) {
  80. PreferredAlignment = 1;
  81. }
  82. //
  83. // Align the buffer on a Dcache fill boundary.
  84. //
  85. LocalPointer = ALIGN_BUFFER(LocalBuffer);
  86. //
  87. // Attempt to open the image file.
  88. //
  89. Status = BlOpen(DeviceId, LoadFile, ArcOpenReadOnly, &FileId);
  90. if (Status != ESUCCESS) {
  91. goto cleanup;
  92. }
  93. bCloseFile = TRUE;
  94. //
  95. // Try to prefetch the whole file into a prefetch buffer. The file
  96. // must have been opened read-only and must not be modified until
  97. // the cache is freed by the BlImageFreeCache call. The file position
  98. // of FileId is reset to the beginning of the file.
  99. //
  100. if ((BlBootingFromNet) || (BlImageInitCache(&ImgCache, FileId) != ESUCCESS) ) {
  101. //
  102. // Make sure file position is at the beginning of the file.
  103. // BlImageInitCache leaves file position undefined under failure.
  104. //
  105. SeekPosition.QuadPart = 0;
  106. Status = BlSeek(FileId, &SeekPosition, SeekAbsolute);
  107. if (Status != ESUCCESS) {
  108. goto cleanup;
  109. }
  110. } else {
  111. //
  112. // We got a cache. Make a note to free it.
  113. //
  114. bFreeCache = TRUE;
  115. }
  116. //
  117. // Read the first two sectors of the image header from the file.
  118. //
  119. Status = BlImageRead(&ImgCache, FileId, LocalPointer, SECTOR_SIZE * 2, &Count);
  120. if (Status != ESUCCESS) {
  121. goto cleanup;
  122. }
  123. //
  124. // If the image file is not the specified type, is not executable, or is
  125. // not a NT image, then return bad image type status.
  126. //
  127. NtHeaders = RtlImageNtHeader(LocalPointer);
  128. if (NtHeaders == NULL) {
  129. Status = EBADF;
  130. goto cleanup;
  131. }
  132. MachineType = NtHeaders->FileHeader.Machine;
  133. if ((MachineType != ImageType) ||
  134. ((NtHeaders->FileHeader.Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE) == 0)) {
  135. Status = EBADF;
  136. goto cleanup;
  137. }
  138. //
  139. // Compute the starting page and the number of pages that are consumed
  140. // by the entire image, and then allocate a memory descriptor for the
  141. // allocated region.
  142. //
  143. NumberOfSections = NtHeaders->FileHeader.NumberOfSections;
  144. SectionHeader = IMAGE_FIRST_SECTION( NtHeaders );
  145. //
  146. // If a preferred alignment was specified or the image is not located in KSEG0,
  147. // then don't bother trying to put it at its specified image base.
  148. //
  149. if (PreferredBasePage != 0) {
  150. BasePage = PreferredBasePage;
  151. } else if ((PreferredAlignment != 1) ||
  152. ((NtHeaders->OptionalHeader.ImageBase & KSEG0_BASE) == 0)) {
  153. BasePage = 0;
  154. } else {
  155. BasePage = (ULONG)((NtHeaders->OptionalHeader.ImageBase & 0x1fffffff) >> PAGE_SHIFT);
  156. }
  157. if (strcmp((PCHAR)&SectionHeader[NumberOfSections - 1].Name, ".debug") == 0) {
  158. NumberOfSections -= 1;
  159. PageCount = (NtHeaders->OptionalHeader.SizeOfImage -
  160. SectionHeader[NumberOfSections].SizeOfRawData + PAGE_SIZE - 1) >> PAGE_SHIFT;
  161. } else {
  162. PageCount =
  163. (NtHeaders->OptionalHeader.SizeOfImage + PAGE_SIZE - 1) >> PAGE_SHIFT;
  164. }
  165. //
  166. // If we fail to allocate memory descriptor here, we will try again
  167. // below after freeing the cache if we have one.
  168. //
  169. Status = BlAllocateAlignedDescriptor(MemoryType,
  170. BasePage,
  171. PageCount,
  172. PreferredAlignment,
  173. &ActualBase);
  174. if (Status != ESUCCESS) {
  175. //
  176. // Free the memory we have allocated for caching the image and
  177. // try again.
  178. //
  179. if (bFreeCache) {
  180. BlImageFreeCache(&ImgCache, FileId);
  181. bFreeCache = FALSE;
  182. Status = BlAllocateDescriptor(MemoryType,
  183. BasePage,
  184. PageCount,
  185. &ActualBase);
  186. }
  187. //
  188. // Check to see if we were able to allocate memory after freeing
  189. // cache if we had one.
  190. //
  191. if (Status != ESUCCESS) {
  192. Status = ENOMEM;
  193. goto cleanup;
  194. }
  195. }
  196. //
  197. // Compute the address of the file header.
  198. //
  199. NewImageBase = KSEG0_BASE | (ActualBase << PAGE_SHIFT);
  200. //
  201. // Read the entire image header from the file.
  202. //
  203. SeekPosition.QuadPart = 0;
  204. Status = BlImageSeek(&ImgCache, FileId, &SeekPosition, SeekAbsolute);
  205. if (Status != ESUCCESS) {
  206. goto cleanup;
  207. }
  208. Status = BlImageRead(&ImgCache,
  209. FileId,
  210. (PVOID)NewImageBase,
  211. NtHeaders->OptionalHeader.SizeOfHeaders,
  212. &Count);
  213. if (Status != ESUCCESS) {
  214. goto cleanup;
  215. BlClose(FileId);
  216. return Status;
  217. }
  218. NtHeaders = RtlImageNtHeader((PVOID)NewImageBase);
  219. //
  220. // Compute the address of the section headers, set the image base address.
  221. //
  222. SectionHeader = IMAGE_FIRST_SECTION(NtHeaders);
  223. //
  224. // Compute the check sum on the image.
  225. //
  226. PartialSum = ChkSum(0,
  227. (PVOID)NewImageBase,
  228. NtHeaders->OptionalHeader.SizeOfHeaders / sizeof(USHORT));
  229. //
  230. // Scan through the sections and either read them into memory or clear
  231. // the memory as appropriate.
  232. //
  233. for (Index = 0; Index < NumberOfSections; Index += 1) {
  234. VirtualSize = SectionHeader->Misc.VirtualSize;
  235. SizeOfRawData = SectionHeader->SizeOfRawData;
  236. VirtualSize = (VirtualSize + 1) & ~1;
  237. SizeOfRawData = (SizeOfRawData + 1) & ~1;
  238. if (VirtualSize == 0) {
  239. VirtualSize = SizeOfRawData;
  240. }
  241. //
  242. // Compute the size of the raw data.
  243. //
  244. // N.B. The size ofthe raw data can be non-zero even when the pointer
  245. // to the raw data is zero. The size of the raw data can also be
  246. // larger than the virtual size.
  247. //
  248. if (SectionHeader->PointerToRawData == 0) {
  249. SizeOfRawData = 0;
  250. } else if (SizeOfRawData > VirtualSize) {
  251. SizeOfRawData = VirtualSize;
  252. }
  253. //
  254. // If the size of the raw data is not zero, then load the raw data
  255. // into memory.
  256. //
  257. if (SizeOfRawData != 0) {
  258. SeekPosition.LowPart = SectionHeader->PointerToRawData;
  259. Status = BlImageSeek(&ImgCache,
  260. FileId,
  261. &SeekPosition,
  262. SeekAbsolute);
  263. if (Status != ESUCCESS) {
  264. break;
  265. }
  266. Status = BlImageRead(&ImgCache,
  267. FileId,
  268. (PVOID)(SectionHeader->VirtualAddress + NewImageBase),
  269. SizeOfRawData,
  270. &Count);
  271. if (Status != ESUCCESS) {
  272. break;
  273. }
  274. //
  275. // Remember how far we have read.
  276. //
  277. RelocSize = SectionHeader->PointerToRawData + SizeOfRawData;
  278. //
  279. // Compute the check sum on the section.
  280. //
  281. PartialSum = ChkSum(PartialSum,
  282. (PVOID)(SectionHeader->VirtualAddress + NewImageBase),
  283. SizeOfRawData / sizeof(USHORT));
  284. }
  285. //
  286. // If the size of the raw data is less than the virtual size, then zero
  287. // the remaining memory.
  288. //
  289. if (SizeOfRawData < VirtualSize) {
  290. RtlZeroMemory((PVOID)(KSEG0_BASE | SectionHeader->VirtualAddress + NewImageBase + SizeOfRawData),
  291. VirtualSize - SizeOfRawData);
  292. }
  293. SectionHeader += 1;
  294. }
  295. //
  296. // Only do the check sum if the image loaded properly and is stripped.
  297. //
  298. if ((Status == ESUCCESS) &&
  299. (NtHeaders->FileHeader.Characteristics & IMAGE_FILE_DEBUG_STRIPPED)) {
  300. //
  301. // Get the length of the file for check sum validation.
  302. //
  303. Status = BlGetFileInformation(FileId, &FileInfo);
  304. if (Status != ESUCCESS) {
  305. //
  306. // Set the length to current end of file.
  307. //
  308. Count = RelocSize;
  309. FileInfo.EndingAddress.LowPart = RelocSize;
  310. } else {
  311. Count = FileInfo.EndingAddress.LowPart;
  312. }
  313. Count -= RelocSize;
  314. while (Count != 0) {
  315. ULONG Length;
  316. //
  317. // Read in the rest of the image and check sum it.
  318. //
  319. Length = Count < SECTOR_SIZE * 2 ? Count : SECTOR_SIZE * 2;
  320. if (BlImageRead(&ImgCache, FileId, LocalBuffer, Length, &Length) != ESUCCESS) {
  321. break;
  322. }
  323. if (Length == 0) {
  324. break;
  325. }
  326. PartialSum = ChkSum(PartialSum, (PUSHORT) LocalBuffer, Length / 2);
  327. Count -= Length;
  328. }
  329. AdjustSum = (PUSHORT)(&NtHeaders->OptionalHeader.CheckSum);
  330. PartialSum -= (PartialSum < AdjustSum[0]);
  331. PartialSum -= AdjustSum[0];
  332. PartialSum -= (PartialSum < AdjustSum[1]);
  333. PartialSum -= AdjustSum[1];
  334. CheckSum = (ULONG)PartialSum + FileInfo.EndingAddress.LowPart;
  335. if (CheckSum != NtHeaders->OptionalHeader.CheckSum) {
  336. Status = EBADF;
  337. }
  338. }
  339. //
  340. // If the specified image was successfully loaded, then perform image
  341. // relocation if necessary.
  342. //
  343. if (Status == ESUCCESS) {
  344. //
  345. // If a virtual bias is specified, then attempt to relocate the
  346. // image to its biased address. If the image cannot be relocated,
  347. // then turn off the virtual bias, and attempt to relocate the
  348. // image again as its allocated base. Otherwise, just attempt to
  349. // relocate the image to its allocated base.
  350. //
  351. // N.B. The loaded image is double mapped at the biased address.
  352. //
  353. // N.B. It is assumed that the only possibly nonrelocatable image
  354. // is the kernel image which is the first image that is loaded.
  355. // Therefore, if a biased address is specified and the kernel
  356. // cannot be relocated, then the biased loading of the kernel
  357. // image is turned off.
  358. //
  359. if (BlVirtualBias != 0) {
  360. Status = LdrRelocateImage((PVOID)(NewImageBase + BlVirtualBias),
  361. "OS Loader",
  362. ESUCCESS,
  363. 0xffff0000 + EBADF,
  364. EBADF);
  365. if (Status == (0xffff0000 + EBADF)) {
  366. BlVirtualBias = 0;
  367. if (NewImageBase != NtHeaders->OptionalHeader.ImageBase) {
  368. Status = (ARC_STATUS)LdrRelocateImage((PVOID)NewImageBase,
  369. "OS Loader",
  370. ESUCCESS,
  371. EBADF,
  372. EBADF);
  373. } else {
  374. Status = ESUCCESS;
  375. }
  376. }
  377. } else {
  378. if (NewImageBase != NtHeaders->OptionalHeader.ImageBase) {
  379. Status = (ARC_STATUS)LdrRelocateImage((PVOID)NewImageBase,
  380. "OS Loader",
  381. ESUCCESS,
  382. EBADF,
  383. EBADF);
  384. }
  385. }
  386. *ImageBase = (PVOID)(NewImageBase + BlVirtualBias);
  387. if(BdDebuggerEnabled) {
  388. DbgPrint("BD: %s base address %p\n", LoadFile, *ImageBase);
  389. {
  390. STRING string;
  391. RtlInitString(&string, LoadFile);
  392. DbgLoadImageSymbols(&string, *ImageBase, (ULONG_PTR)-1);
  393. }
  394. }
  395. }
  396. #if 0
  397. //
  398. // Mark the pages from the relocation information to the end of the
  399. // image as MemoryFree and adjust the size of the image so table
  400. // based structured exception handling will work properly.
  401. //
  402. // Relocation sections are no longer deleted here because memory
  403. // management will be relocating them again in Phase 0.
  404. //
  405. RelocDirectory = (PIMAGE_BASE_RELOCATION)
  406. RtlImageDirectoryEntryToData((PVOID)NewImageBase,
  407. TRUE,
  408. IMAGE_DIRECTORY_ENTRY_BASERELOC,
  409. &RelocSize );
  410. if (RelocDirectory != NULL) {
  411. RelocPage = (ULONG)(((ULONG_PTR)RelocDirectory + PAGE_SIZE - 1) >> PAGE_SHIFT);
  412. RelocPage &= ~(KSEG0_BASE >> PAGE_SHIFT);
  413. MemoryDescriptor = BlFindMemoryDescriptor(RelocPage);
  414. if ((MemoryDescriptor != NULL) && (RelocPage < (ActualBase + PageCount))) {
  415. RelocPageCount = MemoryDescriptor->PageCount +
  416. MemoryDescriptor->BasePage -
  417. RelocPage;
  418. NtHeaders->OptionalHeader.SizeOfImage =
  419. (RelocPage - ActualBase) << PAGE_SHIFT;
  420. BlGenerateDescriptor(MemoryDescriptor,
  421. MemoryFree,
  422. RelocPage,
  423. RelocPageCount );
  424. }
  425. }
  426. #endif
  427. #if defined(_GAMBIT_)
  428. {
  429. SSC_IMAGE_INFO ImageInfo;
  430. ImageInfo.LoadBase = *ImageBase;
  431. ImageInfo.ImageSize = NtHeaders->OptionalHeader.SizeOfImage;
  432. ImageInfo.ImageType = NtHeaders->FileHeader.Machine;
  433. ImageInfo.ProcessID.QuadPart = 0;
  434. ImageInfo.LoadCount = 1;
  435. if (memcmp(LoadFile, "\\ntdetect.exe", 13) != 0) {
  436. SscLoadImage64( LoadFile,
  437. &ImageInfo );
  438. }
  439. }
  440. #endif // _GAMBIT_
  441. cleanup:
  442. if (bFreeCache) {
  443. BlImageFreeCache(&ImgCache, FileId);
  444. }
  445. if (bCloseFile) {
  446. BlClose(FileId);
  447. }
  448. return Status;
  449. }