1. Adjust might be 64bit, so we need to typecast it to UINT32 firstly.
[mirror_edk2.git] / MdePkg / Library / BasePeCoffLib / BasePeCoff.c
CommitLineData
878ddf1f 1/** @file\r
2 Tiano PE/COFF loader.\r
3\r
2ce31132 4 This PE/COFF loader supports loading any PE32 or PE32+ image type, but\r
5 only supports relocating IA32, X64, IPF, and EBC images.\r
6\r
878ddf1f 7 Copyright (c) 2006, Intel Corporation\r
8 All rights reserved. This program and the accompanying materials\r
9 are licensed and made available under the terms and conditions of the BSD License\r
10 which accompanies this distribution. The full text of the license may be found at\r
11 http://opensource.org/licenses/bsd-license.php\r
12\r
13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
14 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
15\r
16 Module Name: PeCoffLoader.c\r
17\r
18**/\r
19\r
2ce31132 20\r
4ba61e5e 21/**\r
2ce31132 22 Performs an Itanium-based specific relocation fixup and is a no-op on other\r
23 instruction sets.\r
878ddf1f 24\r
4ba61e5e 25 @param Reloc Pointer to the relocation record.\r
26 @param Fixup Pointer to the address to fix up.\r
27 @param FixupData Pointer to a buffer to log the fixups.\r
28 @param Adjust The offset to adjust the fixup.\r
878ddf1f 29\r
4ba61e5e 30 @return Status code.\r
878ddf1f 31\r
4ba61e5e 32**/\r
878ddf1f 33RETURN_STATUS\r
34PeCoffLoaderRelocateImageEx (\r
35 IN UINT16 *Reloc,\r
36 IN OUT CHAR8 *Fixup,\r
37 IN OUT CHAR8 **FixupData,\r
38 IN UINT64 Adjust\r
39 );\r
40\r
41\r
2ce31132 42/**\r
43 Performs an Itanium-based specific re-relocation fixup and is a no-op on other\r
44 instruction sets. This is used to re-relocated the image into the EFI virtual\r
45 space for runtime calls.\r
46\r
47 @param Reloc Pointer to the relocation record.\r
48 @param Fixup Pointer to the address to fix up.\r
49 @param FixupData Pointer to a buffer to log the fixups.\r
50 @param Adjust The offset to adjust the fixup.\r
51\r
52 @return Status code.\r
53\r
54**/\r
55RETURN_STATUS\r
56PeHotRelocateImageEx (\r
57 IN UINT16 *Reloc,\r
58 IN OUT CHAR8 *Fixup,\r
59 IN OUT CHAR8 **FixupData,\r
60 IN UINT64 Adjust\r
61 );\r
62\r
63\r
64/**\r
9c7790d2 65 Returns TRUE if the machine type of PE/COFF image is supported. Supported\r
2ce31132 66 does not mean the image can be executed it means the PE/COFF loader supports\r
67 loading and relocating of the image type. It's up to the caller to support\r
9c7790d2 68 the entry point.\r
2ce31132 69\r
70 @param Machine Machine type from the PE Header.\r
71\r
72 @return TRUE if this PE/COFF loader can load the image\r
73\r
74**/\r
75BOOLEAN\r
76PeCoffLoaderImageFormatSupported (\r
77 IN UINT16 Machine\r
78 );\r
79\r
80\r
878ddf1f 81\r
82/**\r
83 Retrieves the PE or TE Header from a PE/COFF or TE image.\r
84\r
cd14fe3d 85 @param ImageContext The context of the image being loaded.\r
2ce31132 86 @param Hdr The buffer in which to return the PE32, PE32+, or TE header.\r
878ddf1f 87\r
cd14fe3d 88 @retval RETURN_SUCCESS The PE or TE Header is read.\r
89 @retval Other The error status from reading the PE/COFF or TE image using the ImageRead function.\r
878ddf1f 90\r
91**/\r
878ddf1f 92RETURN_STATUS\r
93PeCoffLoaderGetPeHeader (\r
2ce31132 94 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,\r
95 OUT EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr\r
878ddf1f 96 )\r
97{\r
cd14fe3d 98 RETURN_STATUS Status;\r
878ddf1f 99 EFI_IMAGE_DOS_HEADER DosHdr;\r
100 UINTN Size;\r
101\r
878ddf1f 102 //\r
2ce31132 103 // Read the DOS image header to check for it's existance\r
878ddf1f 104 //\r
105 Size = sizeof (EFI_IMAGE_DOS_HEADER);\r
106 Status = ImageContext->ImageRead (\r
cd14fe3d 107 ImageContext->Handle,\r
108 0,\r
109 &Size,\r
110 &DosHdr\r
111 );\r
878ddf1f 112 if (RETURN_ERROR (Status)) {\r
113 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
114 return Status;\r
115 }\r
116\r
117 ImageContext->PeCoffHeaderOffset = 0;\r
118 if (DosHdr.e_magic == EFI_IMAGE_DOS_SIGNATURE) {\r
119 //\r
9c7790d2 120 // DOS image header is present, so read the PE header after the DOS image\r
2ce31132 121 // header\r
878ddf1f 122 //\r
123 ImageContext->PeCoffHeaderOffset = DosHdr.e_lfanew;\r
124 }\r
2ce31132 125\r
878ddf1f 126 //\r
9c7790d2 127 // Read the PE/COFF Header. For PE32 (32-bit) this will read in too much\r
2ce31132 128 // data, but that should not hurt anythine. Hdr.Pe32->OptionalHeader.Magic\r
9c7790d2 129 // determins if this is a PE32 or PE32+ image. The magic is in the same\r
2ce31132 130 // location in both images.\r
878ddf1f 131 //\r
2ce31132 132 Size = sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION);\r
878ddf1f 133 Status = ImageContext->ImageRead (\r
cd14fe3d 134 ImageContext->Handle,\r
135 ImageContext->PeCoffHeaderOffset,\r
136 &Size,\r
2ce31132 137 Hdr.Pe32\r
cd14fe3d 138 );\r
878ddf1f 139 if (RETURN_ERROR (Status)) {\r
140 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
141 return Status;\r
142 }\r
2ce31132 143\r
878ddf1f 144 //\r
2ce31132 145 // Use Signature to figure out if we understand the image format\r
878ddf1f 146 //\r
c941b270 147 if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {\r
2ce31132 148 ImageContext->IsTeImage = TRUE;\r
149 ImageContext->Machine = Hdr.Te->Machine;\r
150 ImageContext->ImageType = (UINT16)(Hdr.Te->Subsystem);\r
151 ImageContext->ImageSize = 0;\r
152 ImageContext->SectionAlignment = 4096;\r
153 ImageContext->SizeOfHeaders = sizeof (EFI_TE_IMAGE_HEADER) + (UINTN)Hdr.Te->BaseOfCode - (UINTN)Hdr.Te->StrippedSize;\r
878ddf1f 154\r
2ce31132 155 } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) {\r
156 ImageContext->IsTeImage = FALSE;\r
157 ImageContext->Machine = Hdr.Pe32->FileHeader.Machine;\r
9c7790d2 158\r
2ce31132 159 if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
160 //\r
161 // Use PE32 offset\r
162 //\r
163 ImageContext->ImageType = Hdr.Pe32->OptionalHeader.Subsystem;\r
164 ImageContext->ImageSize = (UINT64)Hdr.Pe32->OptionalHeader.SizeOfImage;\r
165 ImageContext->SectionAlignment = Hdr.Pe32->OptionalHeader.SectionAlignment;\r
166 ImageContext->SizeOfHeaders = Hdr.Pe32->OptionalHeader.SizeOfHeaders;\r
878ddf1f 167\r
2ce31132 168 } else if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {\r
169 //\r
170 // Use PE32+ offset\r
171 //\r
172 ImageContext->ImageType = Hdr.Pe32Plus->OptionalHeader.Subsystem;\r
173 ImageContext->ImageSize = (UINT64) Hdr.Pe32Plus->OptionalHeader.SizeOfImage;\r
174 ImageContext->SectionAlignment = Hdr.Pe32Plus->OptionalHeader.SectionAlignment;\r
175 ImageContext->SizeOfHeaders = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders;\r
176 } else {\r
177 ImageContext->ImageError = IMAGE_ERROR_INVALID_MACHINE_TYPE;\r
9c7790d2 178 return RETURN_UNSUPPORTED;\r
2ce31132 179 }\r
878ddf1f 180 } else {\r
878ddf1f 181 ImageContext->ImageError = IMAGE_ERROR_INVALID_MACHINE_TYPE;\r
182 return RETURN_UNSUPPORTED;\r
183 }\r
184\r
2ce31132 185 if (!PeCoffLoaderImageFormatSupported (ImageContext->Machine)) {\r
186 //\r
187 // If the PE/COFF loader does not support the image type return\r
188 // unsupported. This library can suport lots of types of images\r
189 // this does not mean the user of this library can call the entry\r
9c7790d2 190 // point of the image.\r
2ce31132 191 //\r
192 return RETURN_UNSUPPORTED;\r
878ddf1f 193 }\r
194\r
878ddf1f 195 return RETURN_SUCCESS;\r
196}\r
197\r
2ce31132 198\r
878ddf1f 199/**\r
cd14fe3d 200 Retrieves information about a PE/COFF image.\r
201\r
202 Computes the PeCoffHeaderOffset, ImageAddress, ImageSize, DestinationAddress, CodeView,\r
203 PdbPointer, RelocationsStripped, SectionAlignment, SizeOfHeaders, and DebugDirectoryEntryRva\r
204 fields of the ImageContext structure. If ImageContext is NULL, then return RETURN_INVALID_PARAMETER.\r
205 If the PE/COFF image accessed through the ImageRead service in the ImageContext structure is not\r
206 a supported PE/COFF image type, then return RETURN_UNSUPPORTED. If any errors occur while\r
207 computing the fields of ImageContext, then the error status is returned in the ImageError field of\r
9c7790d2 208 ImageContext.\r
878ddf1f 209\r
cd14fe3d 210 @param ImageContext Pointer to the image context structure that describes the PE/COFF\r
211 image that needs to be examined by this function.\r
878ddf1f 212\r
4ba61e5e 213 @retval RETURN_SUCCESS The information on the PE/COFF image was collected.\r
214 @retval RETURN_INVALID_PARAMETER ImageContext is NULL.\r
215 @retval RETURN_UNSUPPORTED The PE/COFF image is not supported.\r
878ddf1f 216\r
217**/\r
218RETURN_STATUS\r
219EFIAPI\r
220PeCoffLoaderGetImageInfo (\r
221 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext\r
222 )\r
223{\r
2ce31132 224 RETURN_STATUS Status;\r
225 EFI_IMAGE_OPTIONAL_HEADER_UNION HdrData;\r
226 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;\r
227 EFI_IMAGE_DATA_DIRECTORY *DebugDirectoryEntry;\r
228 UINTN Size;\r
229 UINTN Index;\r
230 UINTN DebugDirectoryEntryRva;\r
231 UINTN DebugDirectoryEntryFileOffset;\r
232 UINTN SectionHeaderOffset;\r
233 EFI_IMAGE_SECTION_HEADER SectionHeader;\r
234 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY DebugEntry;\r
235 UINT32 NumberOfRvaAndSizes;\r
878ddf1f 236\r
237 if (NULL == ImageContext) {\r
238 return RETURN_INVALID_PARAMETER;\r
239 }\r
240 //\r
241 // Assume success\r
242 //\r
243 ImageContext->ImageError = IMAGE_ERROR_SUCCESS;\r
244\r
2ce31132 245 Hdr.Union = &HdrData;\r
246 Status = PeCoffLoaderGetPeHeader (ImageContext, Hdr);\r
878ddf1f 247 if (RETURN_ERROR (Status)) {\r
248 return Status;\r
249 }\r
2ce31132 250\r
878ddf1f 251 //\r
252 // Retrieve the base address of the image\r
253 //\r
254 if (!(ImageContext->IsTeImage)) {\r
2ce31132 255 if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
256 //\r
257 // Use PE32 offset\r
258 //\r
259 ImageContext->ImageAddress = Hdr.Pe32->OptionalHeader.ImageBase;\r
260 } else {\r
261 //\r
262 // Use PE32+ offset\r
263 //\r
264 ImageContext->ImageAddress = Hdr.Pe32Plus->OptionalHeader.ImageBase;\r
265 }\r
878ddf1f 266 } else {\r
2ce31132 267 ImageContext->ImageAddress = (PHYSICAL_ADDRESS)(Hdr.Te->ImageBase);\r
878ddf1f 268 }\r
2ce31132 269\r
878ddf1f 270 //\r
271 // Initialize the alternate destination address to 0 indicating that it\r
272 // should not be used.\r
273 //\r
274 ImageContext->DestinationAddress = 0;\r
275\r
276 //\r
277 // Initialize the codeview pointer.\r
278 //\r
279 ImageContext->CodeView = NULL;\r
280 ImageContext->PdbPointer = NULL;\r
281\r
282 //\r
283 // Three cases with regards to relocations:\r
284 // - Image has base relocs, RELOCS_STRIPPED==0 => image is relocatable\r
285 // - Image has no base relocs, RELOCS_STRIPPED==1 => Image is not relocatable\r
286 // - Image has no base relocs, RELOCS_STRIPPED==0 => Image is relocatable but\r
287 // has no base relocs to apply\r
288 // Obviously having base relocations with RELOCS_STRIPPED==1 is invalid.\r
289 //\r
290 // Look at the file header to determine if relocations have been stripped, and\r
291 // save this info in the image context for later use.\r
292 //\r
2ce31132 293 if ((!(ImageContext->IsTeImage)) && ((Hdr.Pe32->FileHeader.Characteristics & EFI_IMAGE_FILE_RELOCS_STRIPPED) != 0)) {\r
878ddf1f 294 ImageContext->RelocationsStripped = TRUE;\r
295 } else {\r
296 ImageContext->RelocationsStripped = FALSE;\r
297 }\r
298\r
299 if (!(ImageContext->IsTeImage)) {\r
2ce31132 300 if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
9c7790d2 301 //\r
2ce31132 302 // Use PE32 offset\r
303 //\r
304 NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;\r
305 DebugDirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);\r
306 } else {\r
9c7790d2 307 //\r
2ce31132 308 // Use PE32+ offset\r
309 //\r
310 NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;\r
311 DebugDirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);\r
9c7790d2 312 }\r
313\r
2ce31132 314 if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_DEBUG) {\r
878ddf1f 315\r
316 DebugDirectoryEntryRva = DebugDirectoryEntry->VirtualAddress;\r
317\r
318 //\r
319 // Determine the file offset of the debug directory... This means we walk\r
320 // the sections to find which section contains the RVA of the debug\r
321 // directory\r
322 //\r
323 DebugDirectoryEntryFileOffset = 0;\r
324\r
325 SectionHeaderOffset = (UINTN)(\r
326 ImageContext->PeCoffHeaderOffset +\r
9c7790d2 327 sizeof (UINT32) +\r
328 sizeof (EFI_IMAGE_FILE_HEADER) +\r
2ce31132 329 Hdr.Pe32->FileHeader.SizeOfOptionalHeader\r
878ddf1f 330 );\r
331\r
2ce31132 332 for (Index = 0; Index < Hdr.Pe32->FileHeader.NumberOfSections; Index++) {\r
878ddf1f 333 //\r
334 // Read section header from file\r
335 //\r
336 Size = sizeof (EFI_IMAGE_SECTION_HEADER);\r
337 Status = ImageContext->ImageRead (\r
338 ImageContext->Handle,\r
339 SectionHeaderOffset,\r
340 &Size,\r
341 &SectionHeader\r
342 );\r
343 if (RETURN_ERROR (Status)) {\r
344 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
345 return Status;\r
346 }\r
347\r
348 if (DebugDirectoryEntryRva >= SectionHeader.VirtualAddress &&\r
349 DebugDirectoryEntryRva < SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize) {\r
2ce31132 350\r
351 DebugDirectoryEntryFileOffset = DebugDirectoryEntryRva - SectionHeader.VirtualAddress + SectionHeader.PointerToRawData;\r
878ddf1f 352 break;\r
353 }\r
354\r
355 SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);\r
356 }\r
357\r
358 if (DebugDirectoryEntryFileOffset != 0) {\r
359 for (Index = 0; Index < DebugDirectoryEntry->Size; Index++) {\r
360 //\r
361 // Read next debug directory entry\r
362 //\r
363 Size = sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);\r
364 Status = ImageContext->ImageRead (\r
365 ImageContext->Handle,\r
366 DebugDirectoryEntryFileOffset,\r
367 &Size,\r
368 &DebugEntry\r
369 );\r
370 if (RETURN_ERROR (Status)) {\r
371 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
372 return Status;\r
373 }\r
374\r
375 if (DebugEntry.Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) {\r
376 ImageContext->DebugDirectoryEntryRva = (UINT32) (DebugDirectoryEntryRva + Index * sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY));\r
377 if (DebugEntry.RVA == 0 && DebugEntry.FileOffset != 0) {\r
378 ImageContext->ImageSize += DebugEntry.SizeOfData;\r
379 }\r
380\r
381 return RETURN_SUCCESS;\r
382 }\r
383 }\r
384 }\r
385 }\r
386 } else {\r
878ddf1f 387\r
2ce31132 388 DebugDirectoryEntry = &Hdr.Te->DataDirectory[1];\r
878ddf1f 389 DebugDirectoryEntryRva = DebugDirectoryEntry->VirtualAddress;\r
2ce31132 390 SectionHeaderOffset = (UINTN)(sizeof (EFI_TE_IMAGE_HEADER));\r
878ddf1f 391\r
392 DebugDirectoryEntryFileOffset = 0;\r
393\r
2ce31132 394 for (Index = 0; Index < Hdr.Te->NumberOfSections;) {\r
878ddf1f 395 //\r
396 // Read section header from file\r
397 //\r
cd14fe3d 398 Size = sizeof (EFI_IMAGE_SECTION_HEADER);\r
878ddf1f 399 Status = ImageContext->ImageRead (\r
400 ImageContext->Handle,\r
401 SectionHeaderOffset,\r
402 &Size,\r
403 &SectionHeader\r
404 );\r
405 if (RETURN_ERROR (Status)) {\r
406 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
407 return Status;\r
408 }\r
409\r
410 if (DebugDirectoryEntryRva >= SectionHeader.VirtualAddress &&\r
411 DebugDirectoryEntryRva < SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize) {\r
412 DebugDirectoryEntryFileOffset = DebugDirectoryEntryRva -\r
cd14fe3d 413 SectionHeader.VirtualAddress +\r
414 SectionHeader.PointerToRawData +\r
415 sizeof (EFI_TE_IMAGE_HEADER) -\r
2ce31132 416 Hdr.Te->StrippedSize;\r
878ddf1f 417\r
418 //\r
419 // File offset of the debug directory was found, if this is not the last\r
420 // section, then skip to the last section for calculating the image size.\r
421 //\r
2ce31132 422 if (Index < (UINTN) Hdr.Te->NumberOfSections - 1) {\r
423 SectionHeaderOffset += (Hdr.Te->NumberOfSections - 1 - Index) * sizeof (EFI_IMAGE_SECTION_HEADER);\r
424 Index = Hdr.Te->NumberOfSections - 1;\r
878ddf1f 425 continue;\r
426 }\r
427 }\r
428\r
429 //\r
430 // In Te image header there is not a field to describe the ImageSize.\r
9c7790d2 431 // Actually, the ImageSize equals the RVA plus the VirtualSize of\r
432 // the last section mapped into memory (Must be rounded up to\r
878ddf1f 433 // a mulitple of Section Alignment). Per the PE/COFF specification, the\r
434 // section headers in the Section Table must appear in order of the RVA\r
435 // values for the corresponding sections. So the ImageSize can be determined\r
436 // by the RVA and the VirtualSize of the last section header in the\r
437 // Section Table.\r
438 //\r
2ce31132 439 if ((++Index) == (UINTN)Hdr.Te->NumberOfSections) {\r
878ddf1f 440 ImageContext->ImageSize = (SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize +\r
441 ImageContext->SectionAlignment - 1) & ~(ImageContext->SectionAlignment - 1);\r
442 }\r
443\r
444 SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);\r
445 }\r
446\r
447 if (DebugDirectoryEntryFileOffset != 0) {\r
448 for (Index = 0; Index < DebugDirectoryEntry->Size; Index++) {\r
449 //\r
450 // Read next debug directory entry\r
451 //\r
452 Size = sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);\r
453 Status = ImageContext->ImageRead (\r
454 ImageContext->Handle,\r
455 DebugDirectoryEntryFileOffset,\r
456 &Size,\r
457 &DebugEntry\r
458 );\r
459 if (RETURN_ERROR (Status)) {\r
460 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
461 return Status;\r
462 }\r
463\r
464 if (DebugEntry.Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) {\r
465 ImageContext->DebugDirectoryEntryRva = (UINT32) (DebugDirectoryEntryRva + Index * sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY));\r
466 return RETURN_SUCCESS;\r
467 }\r
468 }\r
469 }\r
470 }\r
471\r
472 return RETURN_SUCCESS;\r
473}\r
474\r
2ce31132 475\r
878ddf1f 476/**\r
477 Converts an image address to the loaded address.\r
478\r
cd14fe3d 479 @param ImageContext The context of the image being loaded.\r
480 @param Address The address to be converted to the loaded address.\r
878ddf1f 481\r
cd14fe3d 482 @return The converted address or NULL if the address can not be converted.\r
878ddf1f 483\r
484**/\r
878ddf1f 485VOID *\r
486PeCoffLoaderImageAddress (\r
487 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,\r
488 IN UINTN Address\r
489 )\r
490{\r
236877a6 491 //\r
9c7790d2 492 // @bug Check to make sure ImageSize is correct for the relocated image.\r
236877a6 493 // it may only work for the file we start with and not the relocated image\r
494 //\r
495 if (Address >= ImageContext->ImageSize) {\r
496 ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_ADDRESS;\r
497 return NULL;\r
498 }\r
499\r
2ce31132 500 return (CHAR8 *)((UINTN) ImageContext->ImageAddress + Address);\r
878ddf1f 501}\r
502\r
503/**\r
cd14fe3d 504 Applies relocation fixups to a PE/COFF image that was loaded with PeCoffLoaderLoadImage().\r
878ddf1f 505\r
cd14fe3d 506 If the DestinationAddress field of ImageContext is 0, then use the ImageAddress field of\r
507 ImageContext as the relocation base address. Otherwise, use the DestinationAddress field\r
508 of ImageContext as the relocation base address. The caller must allocate the relocation\r
9c7790d2 509 fixup log buffer and fill in the FixupData field of ImageContext prior to calling this function.\r
cd14fe3d 510 If ImageContext is NULL, then ASSERT().\r
511\r
512 @param ImageContext Pointer to the image context structure that describes the PE/COFF\r
513 image that is being relocated.\r
878ddf1f 514\r
cd14fe3d 515 @retval RETURN_SUCCESS The PE/COFF image was relocated.\r
516 Extended status information is in the ImageError field of ImageContext.\r
517 @retval RETURN_LOAD_ERROR The image in not a valid PE/COFF image.\r
518 Extended status information is in the ImageError field of ImageContext.\r
519 @retval RETURN_UNSUPPORTED A relocation record type is not supported.\r
520 Extended status information is in the ImageError field of ImageContext.\r
878ddf1f 521\r
522**/\r
523RETURN_STATUS\r
524EFIAPI\r
525PeCoffLoaderRelocateImage (\r
526 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext\r
527 )\r
528{\r
2ce31132 529 RETURN_STATUS Status;\r
530 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;\r
531 EFI_IMAGE_DATA_DIRECTORY *RelocDir;\r
532 UINT64 Adjust;\r
533 EFI_IMAGE_BASE_RELOCATION *RelocBase;\r
534 EFI_IMAGE_BASE_RELOCATION *RelocBaseEnd;\r
535 UINT16 *Reloc;\r
536 UINT16 *RelocEnd;\r
537 CHAR8 *Fixup;\r
538 CHAR8 *FixupBase;\r
539 UINT16 *F16;\r
9c7790d2 540 UINT32 *F32;\r
2ce31132 541 UINT64 *F64;\r
542 CHAR8 *FixupData;\r
543 PHYSICAL_ADDRESS BaseAddress;\r
544 UINT32 NumberOfRvaAndSizes;\r
878ddf1f 545\r
cd14fe3d 546 ASSERT (ImageContext != NULL);\r
547\r
878ddf1f 548 //\r
549 // Assume success\r
550 //\r
551 ImageContext->ImageError = IMAGE_ERROR_SUCCESS;\r
552\r
553 //\r
554 // If there are no relocation entries, then we are done\r
555 //\r
556 if (ImageContext->RelocationsStripped) {\r
557 return RETURN_SUCCESS;\r
558 }\r
559\r
560 //\r
561 // If the destination address is not 0, use that rather than the\r
562 // image address as the relocation target.\r
563 //\r
cd14fe3d 564 if (ImageContext->DestinationAddress != 0) {\r
878ddf1f 565 BaseAddress = ImageContext->DestinationAddress;\r
566 } else {\r
567 BaseAddress = ImageContext->ImageAddress;\r
568 }\r
569\r
570 if (!(ImageContext->IsTeImage)) {\r
2ce31132 571 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN)ImageContext->ImageAddress + ImageContext->PeCoffHeaderOffset);\r
572 if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
573 //\r
574 // Use PE32 offset\r
575 //\r
576 Adjust = (UINT64)BaseAddress - Hdr.Pe32->OptionalHeader.ImageBase;\r
577 Hdr.Pe32->OptionalHeader.ImageBase = (UINT32)BaseAddress;\r
9c7790d2 578\r
2ce31132 579 NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;\r
580 RelocDir = &Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];\r
581 } else {\r
582 //\r
583 // Use PE32+ offset\r
584 //\r
585 Adjust = (UINT64) BaseAddress - Hdr.Pe32Plus->OptionalHeader.ImageBase;\r
586 Hdr.Pe32Plus->OptionalHeader.ImageBase = (UINT64)BaseAddress;\r
587\r
588 NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;\r
589 RelocDir = &Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];\r
590 }\r
878ddf1f 591\r
592 //\r
593 // Find the relocation block\r
878ddf1f 594 // Per the PE/COFF spec, you can't assume that a given data directory\r
595 // is present in the image. You have to check the NumberOfRvaAndSizes in\r
596 // the optional header to verify a desired directory entry is there.\r
597 //\r
2ce31132 598\r
599 if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {\r
878ddf1f 600 RelocBase = PeCoffLoaderImageAddress (ImageContext, RelocDir->VirtualAddress);\r
601 RelocBaseEnd = PeCoffLoaderImageAddress (\r
602 ImageContext,\r
603 RelocDir->VirtualAddress + RelocDir->Size - 1\r
604 );\r
605 } else {\r
606 //\r
607 // Set base and end to bypass processing below.\r
608 //\r
609 RelocBase = RelocBaseEnd = 0;\r
610 }\r
611 } else {\r
2ce31132 612 Hdr.Te = (EFI_TE_IMAGE_HEADER *)(UINTN)(ImageContext->ImageAddress);\r
317f832e 613 Adjust = (UINT64) (BaseAddress - Hdr.Te->ImageBase);\r
2ce31132 614 Hdr.Te->ImageBase = (UINT64) (BaseAddress);\r
878ddf1f 615\r
616 //\r
617 // Find the relocation block\r
618 //\r
2ce31132 619 RelocDir = &Hdr.Te->DataDirectory[0];\r
878ddf1f 620 RelocBase = (EFI_IMAGE_BASE_RELOCATION *)(UINTN)(\r
9c7790d2 621 ImageContext->ImageAddress +\r
24e25d11 622 RelocDir->VirtualAddress +\r
9c7790d2 623 sizeof(EFI_TE_IMAGE_HEADER) -\r
2ce31132 624 Hdr.Te->StrippedSize\r
24e25d11 625 );\r
878ddf1f 626 RelocBaseEnd = (EFI_IMAGE_BASE_RELOCATION *) ((UINTN) RelocBase + (UINTN) RelocDir->Size - 1);\r
627 }\r
9c7790d2 628\r
878ddf1f 629 //\r
630 // Run the relocation information and apply the fixups\r
631 //\r
632 FixupData = ImageContext->FixupData;\r
633 while (RelocBase < RelocBaseEnd) {\r
634\r
635 Reloc = (UINT16 *) ((CHAR8 *) RelocBase + sizeof (EFI_IMAGE_BASE_RELOCATION));\r
636 RelocEnd = (UINT16 *) ((CHAR8 *) RelocBase + RelocBase->SizeOfBlock);\r
637 if (!(ImageContext->IsTeImage)) {\r
638 FixupBase = PeCoffLoaderImageAddress (ImageContext, RelocBase->VirtualAddress);\r
639 } else {\r
640 FixupBase = (CHAR8 *)(UINTN)(ImageContext->ImageAddress +\r
24e25d11 641 RelocBase->VirtualAddress +\r
9c7790d2 642 sizeof(EFI_TE_IMAGE_HEADER) -\r
2ce31132 643 Hdr.Te->StrippedSize\r
24e25d11 644 );\r
878ddf1f 645 }\r
646\r
647 if ((CHAR8 *) RelocEnd < (CHAR8 *) ((UINTN) ImageContext->ImageAddress) ||\r
9c7790d2 648 (CHAR8 *) RelocEnd > (CHAR8 *)((UINTN)ImageContext->ImageAddress +\r
878ddf1f 649 (UINTN)ImageContext->ImageSize)) {\r
650 ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;\r
651 return RETURN_LOAD_ERROR;\r
652 }\r
653\r
654 //\r
655 // Run this relocation record\r
656 //\r
657 while (Reloc < RelocEnd) {\r
658\r
659 Fixup = FixupBase + (*Reloc & 0xFFF);\r
660 switch ((*Reloc) >> 12) {\r
661 case EFI_IMAGE_REL_BASED_ABSOLUTE:\r
662 break;\r
663\r
664 case EFI_IMAGE_REL_BASED_HIGH:\r
665 F16 = (UINT16 *) Fixup;\r
9c7790d2 666 *F16 = (UINT16) (*F16 + ((UINT16) ((UINT32) Adjust >> 16)));\r
878ddf1f 667 if (FixupData != NULL) {\r
668 *(UINT16 *) FixupData = *F16;\r
669 FixupData = FixupData + sizeof (UINT16);\r
670 }\r
671 break;\r
672\r
673 case EFI_IMAGE_REL_BASED_LOW:\r
674 F16 = (UINT16 *) Fixup;\r
675 *F16 = (UINT16) (*F16 + (UINT16) Adjust);\r
676 if (FixupData != NULL) {\r
677 *(UINT16 *) FixupData = *F16;\r
678 FixupData = FixupData + sizeof (UINT16);\r
679 }\r
680 break;\r
681\r
682 case EFI_IMAGE_REL_BASED_HIGHLOW:\r
683 F32 = (UINT32 *) Fixup;\r
684 *F32 = *F32 + (UINT32) Adjust;\r
685 if (FixupData != NULL) {\r
686 FixupData = ALIGN_POINTER (FixupData, sizeof (UINT32));\r
2ce31132 687 *(UINT32 *)FixupData = *F32;\r
878ddf1f 688 FixupData = FixupData + sizeof (UINT32);\r
689 }\r
690 break;\r
691\r
2ce31132 692 case EFI_IMAGE_REL_BASED_DIR64:\r
693 F64 = (UINT64 *) Fixup;\r
694 *F64 = *F64 + (UINT64) Adjust;\r
695 if (FixupData != NULL) {\r
696 FixupData = ALIGN_POINTER (FixupData, sizeof(UINT64));\r
697 *(UINT64 *)(FixupData) = *F64;\r
698 FixupData = FixupData + sizeof(UINT64);\r
699 }\r
700 break;\r
878ddf1f 701\r
702 default:\r
2ce31132 703 //\r
704 // The common code does not handle some of the stranger IPF relocations\r
705 // PeCoffLoaderRelocateImageEx () addes support for these complex fixups\r
706 // on IPF and is a No-Op on other archtiectures.\r
707 //\r
878ddf1f 708 Status = PeCoffLoaderRelocateImageEx (Reloc, Fixup, &FixupData, Adjust);\r
709 if (RETURN_ERROR (Status)) {\r
710 ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;\r
711 return Status;\r
712 }\r
713 }\r
714\r
715 //\r
716 // Next relocation record\r
717 //\r
718 Reloc += 1;\r
719 }\r
720\r
721 //\r
722 // Next reloc block\r
723 //\r
724 RelocBase = (EFI_IMAGE_BASE_RELOCATION *) RelocEnd;\r
725 }\r
726\r
727 return RETURN_SUCCESS;\r
728}\r
729\r
730/**\r
731 Loads a PE/COFF image into memory.\r
732\r
cd14fe3d 733 Loads the PE/COFF image accessed through the ImageRead service of ImageContext into the buffer\r
734 specified by the ImageAddress and ImageSize fields of ImageContext. The caller must allocate\r
735 the load buffer and fill in the ImageAddress and ImageSize fields prior to calling this function.\r
736 The EntryPoint, FixupDataSize, CodeView, and PdbPointer fields of ImageContext are computed.\r
4ba61e5e 737 If ImageContext is NULL, then ASSERT().\r
cd14fe3d 738\r
739 @param ImageContext Pointer to the image context structure that describes the PE/COFF\r
740 image that is being loaded.\r
878ddf1f 741\r
cd14fe3d 742 @retval RETURN_SUCCESS The PE/COFF image was loaded into the buffer specified by\r
743 the ImageAddress and ImageSize fields of ImageContext.\r
744 Extended status information is in the ImageError field of ImageContext.\r
745 @retval RETURN_BUFFER_TOO_SMALL The caller did not provide a large enough buffer.\r
746 Extended status information is in the ImageError field of ImageContext.\r
747 @retval RETURN_LOAD_ERROR The PE/COFF image is an EFI Runtime image with no relocations.\r
748 Extended status information is in the ImageError field of ImageContext.\r
749 @retval RETURN_INVALID_PARAMETER The image address is invalid.\r
750 Extended status information is in the ImageError field of ImageContext.\r
878ddf1f 751\r
752**/\r
753RETURN_STATUS\r
754EFIAPI\r
755PeCoffLoaderLoadImage (\r
756 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext\r
757 )\r
758{\r
cd14fe3d 759 RETURN_STATUS Status;\r
2ce31132 760 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;\r
cd14fe3d 761 PE_COFF_LOADER_IMAGE_CONTEXT CheckContext;\r
878ddf1f 762 EFI_IMAGE_SECTION_HEADER *FirstSection;\r
763 EFI_IMAGE_SECTION_HEADER *Section;\r
764 UINTN NumberOfSections;\r
765 UINTN Index;\r
766 CHAR8 *Base;\r
767 CHAR8 *End;\r
768 CHAR8 *MaxEnd;\r
769 EFI_IMAGE_DATA_DIRECTORY *DirectoryEntry;\r
770 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *DebugEntry;\r
771 UINTN Size;\r
772 UINT32 TempDebugEntryRva;\r
2ce31132 773 UINT32 NumberOfRvaAndSizes;\r
878ddf1f 774\r
4ba61e5e 775 ASSERT (ImageContext != NULL);\r
776\r
878ddf1f 777 //\r
778 // Assume success\r
779 //\r
780 ImageContext->ImageError = IMAGE_ERROR_SUCCESS;\r
781\r
782 //\r
783 // Copy the provided context info into our local version, get what we\r
784 // can from the original image, and then use that to make sure everything\r
785 // is legit.\r
786 //\r
787 CopyMem (&CheckContext, ImageContext, sizeof (PE_COFF_LOADER_IMAGE_CONTEXT));\r
788\r
789 Status = PeCoffLoaderGetImageInfo (&CheckContext);\r
790 if (RETURN_ERROR (Status)) {\r
791 return Status;\r
792 }\r
793\r
794 //\r
795 // Make sure there is enough allocated space for the image being loaded\r
796 //\r
797 if (ImageContext->ImageSize < CheckContext.ImageSize) {\r
798 ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_SIZE;\r
799 return RETURN_BUFFER_TOO_SMALL;\r
800 }\r
4ba61e5e 801 if (ImageContext->ImageAddress == 0) {\r
802 //\r
803 // Image cannot be loaded into 0 address.\r
804 //\r
805 ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_ADDRESS;\r
806 return RETURN_INVALID_PARAMETER;\r
807 }\r
878ddf1f 808 //\r
809 // If there's no relocations, then make sure it's not a runtime driver,\r
810 // and that it's being loaded at the linked address.\r
811 //\r
812 if (CheckContext.RelocationsStripped) {\r
813 //\r
814 // If the image does not contain relocations and it is a runtime driver\r
815 // then return an error.\r
816 //\r
817 if (CheckContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) {\r
818 ImageContext->ImageError = IMAGE_ERROR_INVALID_SUBSYSTEM;\r
819 return RETURN_LOAD_ERROR;\r
820 }\r
821 //\r
822 // If the image does not contain relocations, and the requested load address\r
823 // is not the linked address, then return an error.\r
824 //\r
825 if (CheckContext.ImageAddress != ImageContext->ImageAddress) {\r
826 ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_ADDRESS;\r
827 return RETURN_INVALID_PARAMETER;\r
828 }\r
829 }\r
830 //\r
831 // Make sure the allocated space has the proper section alignment\r
832 //\r
833 if (!(ImageContext->IsTeImage)) {\r
834 if ((ImageContext->ImageAddress & (CheckContext.SectionAlignment - 1)) != 0) {\r
835 ImageContext->ImageError = IMAGE_ERROR_INVALID_SECTION_ALIGNMENT;\r
836 return RETURN_INVALID_PARAMETER;\r
837 }\r
838 }\r
839 //\r
840 // Read the entire PE/COFF or TE header into memory\r
841 //\r
842 if (!(ImageContext->IsTeImage)) {\r
843 Status = ImageContext->ImageRead (\r
844 ImageContext->Handle,\r
845 0,\r
846 &ImageContext->SizeOfHeaders,\r
847 (VOID *) (UINTN) ImageContext->ImageAddress\r
848 );\r
849\r
2ce31132 850 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN)ImageContext->ImageAddress + ImageContext->PeCoffHeaderOffset);\r
878ddf1f 851\r
852 FirstSection = (EFI_IMAGE_SECTION_HEADER *) (\r
853 (UINTN)ImageContext->ImageAddress +\r
854 ImageContext->PeCoffHeaderOffset +\r
9c7790d2 855 sizeof(UINT32) +\r
856 sizeof(EFI_IMAGE_FILE_HEADER) +\r
2ce31132 857 Hdr.Pe32->FileHeader.SizeOfOptionalHeader\r
878ddf1f 858 );\r
2ce31132 859 NumberOfSections = (UINTN) (Hdr.Pe32->FileHeader.NumberOfSections);\r
878ddf1f 860 } else {\r
861 Status = ImageContext->ImageRead (\r
862 ImageContext->Handle,\r
863 0,\r
864 &ImageContext->SizeOfHeaders,\r
2ce31132 865 (void *)(UINTN)ImageContext->ImageAddress\r
878ddf1f 866 );\r
867\r
2ce31132 868 Hdr.Te = (EFI_TE_IMAGE_HEADER *)(UINTN)(ImageContext->ImageAddress);\r
878ddf1f 869\r
870 FirstSection = (EFI_IMAGE_SECTION_HEADER *) (\r
2ce31132 871 (UINTN)ImageContext->ImageAddress +\r
872 sizeof(EFI_TE_IMAGE_HEADER)\r
873 );\r
874 NumberOfSections = (UINTN) (Hdr.Te->NumberOfSections);\r
878ddf1f 875\r
876 }\r
877\r
878 if (RETURN_ERROR (Status)) {\r
879 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
880 return RETURN_LOAD_ERROR;\r
881 }\r
882\r
883 //\r
884 // Load each section of the image\r
885 //\r
886 Section = FirstSection;\r
887 for (Index = 0, MaxEnd = NULL; Index < NumberOfSections; Index++) {\r
888\r
889 //\r
890 // Compute sections address\r
891 //\r
892 Base = PeCoffLoaderImageAddress (ImageContext, Section->VirtualAddress);\r
893 End = PeCoffLoaderImageAddress (\r
894 ImageContext,\r
895 Section->VirtualAddress + Section->Misc.VirtualSize - 1\r
896 );\r
897 if (ImageContext->IsTeImage) {\r
2ce31132 898 Base = (CHAR8 *)((UINTN) Base + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN)Hdr.Te->StrippedSize);\r
899 End = (CHAR8 *)((UINTN) End + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN)Hdr.Te->StrippedSize);\r
878ddf1f 900 }\r
901\r
902 if (End > MaxEnd) {\r
903 MaxEnd = End;\r
904 }\r
905 //\r
906 // If the base start or end address resolved to 0, then fail.\r
907 //\r
908 if ((Base == NULL) || (End == NULL)) {\r
909 ImageContext->ImageError = IMAGE_ERROR_SECTION_NOT_LOADED;\r
910 return RETURN_LOAD_ERROR;\r
911 }\r
912\r
913 //\r
914 // Read the section\r
915 //\r
916 Size = (UINTN) Section->Misc.VirtualSize;\r
917 if ((Size == 0) || (Size > Section->SizeOfRawData)) {\r
918 Size = (UINTN) Section->SizeOfRawData;\r
919 }\r
920\r
921 if (Section->SizeOfRawData) {\r
922 if (!(ImageContext->IsTeImage)) {\r
923 Status = ImageContext->ImageRead (\r
924 ImageContext->Handle,\r
925 Section->PointerToRawData,\r
926 &Size,\r
927 Base\r
928 );\r
929 } else {\r
930 Status = ImageContext->ImageRead (\r
931 ImageContext->Handle,\r
2ce31132 932 Section->PointerToRawData + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN)Hdr.Te->StrippedSize,\r
878ddf1f 933 &Size,\r
934 Base\r
935 );\r
936 }\r
937\r
938 if (RETURN_ERROR (Status)) {\r
939 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
940 return Status;\r
941 }\r
942 }\r
943\r
944 //\r
945 // If raw size is less then virt size, zero fill the remaining\r
946 //\r
947\r
948 if (Size < Section->Misc.VirtualSize) {\r
949 ZeroMem (Base + Size, Section->Misc.VirtualSize - Size);\r
950 }\r
951\r
952 //\r
953 // Next Section\r
954 //\r
955 Section += 1;\r
956 }\r
957\r
958 //\r
959 // Get image's entry point\r
960 //\r
961 if (!(ImageContext->IsTeImage)) {\r
2ce31132 962 //\r
963 // Sizes of AddressOfEntryPoint are different so we need to do this safely\r
964 //\r
965 if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
966 //\r
967 // Use PE32 offset\r
9c7790d2 968 //\r
2ce31132 969 ImageContext->EntryPoint = (PHYSICAL_ADDRESS)(UINTN)PeCoffLoaderImageAddress (\r
970 ImageContext,\r
971 (UINTN)Hdr.Pe32->OptionalHeader.AddressOfEntryPoint\r
972 );\r
973 } else {\r
974 //\r
975 // Use PE32+ offset\r
976 //\r
977 ImageContext->EntryPoint = (PHYSICAL_ADDRESS)(UINTN)PeCoffLoaderImageAddress (\r
978 ImageContext,\r
979 (UINTN)Hdr.Pe32Plus->OptionalHeader.AddressOfEntryPoint\r
980 );\r
981 }\r
878ddf1f 982 } else {\r
983 ImageContext->EntryPoint = (PHYSICAL_ADDRESS) (\r
2ce31132 984 (UINTN)ImageContext->ImageAddress +\r
985 (UINTN)Hdr.Te->AddressOfEntryPoint +\r
986 (UINTN)sizeof(EFI_TE_IMAGE_HEADER) -\r
987 (UINTN)Hdr.Te->StrippedSize\r
988 );\r
878ddf1f 989 }\r
990\r
991 //\r
992 // Determine the size of the fixup data\r
993 //\r
994 // Per the PE/COFF spec, you can't assume that a given data directory\r
995 // is present in the image. You have to check the NumberOfRvaAndSizes in\r
996 // the optional header to verify a desired directory entry is there.\r
997 //\r
998 if (!(ImageContext->IsTeImage)) {\r
2ce31132 999 if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
1000 //\r
1001 // Use PE32 offset\r
1002 //\r
1003 NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;\r
1004 DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];\r
1005 } else {\r
1006 //\r
1007 // Use PE32+ offset\r
1008 //\r
1009 NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;\r
1010 DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];\r
1011 }\r
9c7790d2 1012\r
2ce31132 1013 if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {\r
878ddf1f 1014 ImageContext->FixupDataSize = DirectoryEntry->Size / sizeof (UINT16) * sizeof (UINTN);\r
1015 } else {\r
1016 ImageContext->FixupDataSize = 0;\r
1017 }\r
1018 } else {\r
2ce31132 1019 DirectoryEntry = &Hdr.Te->DataDirectory[0];\r
878ddf1f 1020 ImageContext->FixupDataSize = DirectoryEntry->Size / sizeof (UINT16) * sizeof (UINTN);\r
1021 }\r
1022 //\r
1023 // Consumer must allocate a buffer for the relocation fixup log.\r
1024 // Only used for runtime drivers.\r
1025 //\r
1026 ImageContext->FixupData = NULL;\r
1027\r
1028 //\r
1029 // Load the Codeview info if present\r
1030 //\r
1031 if (ImageContext->DebugDirectoryEntryRva != 0) {\r
1032 if (!(ImageContext->IsTeImage)) {\r
1033 DebugEntry = PeCoffLoaderImageAddress (\r
1034 ImageContext,\r
1035 ImageContext->DebugDirectoryEntryRva\r
1036 );\r
1037 } else {\r
1038 DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *)(UINTN)(\r
2ce31132 1039 ImageContext->ImageAddress +\r
1040 ImageContext->DebugDirectoryEntryRva +\r
1041 sizeof(EFI_TE_IMAGE_HEADER) -\r
1042 Hdr.Te->StrippedSize\r
1043 );\r
878ddf1f 1044 }\r
1045\r
1046 if (DebugEntry != NULL) {\r
1047 TempDebugEntryRva = DebugEntry->RVA;\r
1048 if (DebugEntry->RVA == 0 && DebugEntry->FileOffset != 0) {\r
1049 Section--;\r
2ce31132 1050 if ((UINTN)Section->SizeOfRawData < Section->Misc.VirtualSize) {\r
878ddf1f 1051 TempDebugEntryRva = Section->VirtualAddress + Section->Misc.VirtualSize;\r
1052 } else {\r
1053 TempDebugEntryRva = Section->VirtualAddress + Section->SizeOfRawData;\r
1054 }\r
1055 }\r
1056\r
1057 if (TempDebugEntryRva != 0) {\r
1058 if (!(ImageContext->IsTeImage)) {\r
1059 ImageContext->CodeView = PeCoffLoaderImageAddress (ImageContext, TempDebugEntryRva);\r
1060 } else {\r
1061 ImageContext->CodeView = (VOID *)(\r
2ce31132 1062 (UINTN)ImageContext->ImageAddress +\r
1063 (UINTN)TempDebugEntryRva +\r
1064 (UINTN)sizeof (EFI_TE_IMAGE_HEADER) -\r
1065 (UINTN) Hdr.Te->StrippedSize\r
1066 );\r
878ddf1f 1067 }\r
1068\r
1069 if (ImageContext->CodeView == NULL) {\r
1070 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
1071 return RETURN_LOAD_ERROR;\r
1072 }\r
1073\r
1074 if (DebugEntry->RVA == 0) {\r
1075 Size = DebugEntry->SizeOfData;\r
1076 if (!(ImageContext->IsTeImage)) {\r
1077 Status = ImageContext->ImageRead (\r
1078 ImageContext->Handle,\r
1079 DebugEntry->FileOffset,\r
1080 &Size,\r
1081 ImageContext->CodeView\r
1082 );\r
1083 } else {\r
1084 Status = ImageContext->ImageRead (\r
1085 ImageContext->Handle,\r
2ce31132 1086 DebugEntry->FileOffset + sizeof (EFI_TE_IMAGE_HEADER) - Hdr.Te->StrippedSize,\r
878ddf1f 1087 &Size,\r
1088 ImageContext->CodeView\r
1089 );\r
1090 //\r
1091 // Should we apply fix up to this field according to the size difference between PE and TE?\r
1092 // Because now we maintain TE header fields unfixed, this field will also remain as they are\r
1093 // in original PE image.\r
1094 //\r
1095 }\r
1096\r
1097 if (RETURN_ERROR (Status)) {\r
1098 ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;\r
1099 return RETURN_LOAD_ERROR;\r
1100 }\r
1101\r
1102 DebugEntry->RVA = TempDebugEntryRva;\r
1103 }\r
1104\r
1105 switch (*(UINT32 *) ImageContext->CodeView) {\r
1106 case CODEVIEW_SIGNATURE_NB10:\r
2ce31132 1107 ImageContext->PdbPointer = (CHAR8 *)ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY);\r
878ddf1f 1108 break;\r
1109\r
1110 case CODEVIEW_SIGNATURE_RSDS:\r
2ce31132 1111 ImageContext->PdbPointer = (CHAR8 *)ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY);\r
878ddf1f 1112 break;\r
1113\r
1114 default:\r
1115 break;\r
1116 }\r
1117 }\r
1118 }\r
1119 }\r
1120\r
1121 return Status;\r
1122}\r
2ce31132 1123\r
1124\r
1125/**\r
1126 Reapply fixups on a fixed up PE32/PE32+ image to allow virutal calling at EFI\r
9c7790d2 1127 runtime.\r
1128\r
2ce31132 1129 PE_COFF_LOADER_IMAGE_CONTEXT.FixupData stores information needed to reapply\r
1130 the fixups with a virtual mapping.\r
1131\r
1132\r
1133 @param ImageBase Base address of relocated image\r
1134 @param VirtImageBase Virtual mapping for ImageBase\r
1135 @param ImageSize Size of the image to relocate\r
1136 @param RelocationData Location to place results of read\r
9c7790d2 1137\r
2ce31132 1138**/\r
1139VOID\r
1140EFIAPI\r
1141PeCoffLoaderRelocateImageForRuntime (\r
1142 IN PHYSICAL_ADDRESS ImageBase,\r
1143 IN PHYSICAL_ADDRESS VirtImageBase,\r
1144 IN UINTN ImageSize,\r
1145 IN VOID *RelocationData\r
1146 )\r
1147{\r
1148 CHAR8 *OldBase;\r
1149 CHAR8 *NewBase;\r
1150 EFI_IMAGE_DOS_HEADER *DosHdr;\r
1151 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;\r
1152 UINT32 NumberOfRvaAndSizes;\r
1153 EFI_IMAGE_DATA_DIRECTORY *DataDirectory;\r
1154 EFI_IMAGE_DATA_DIRECTORY *RelocDir;\r
1155 EFI_IMAGE_BASE_RELOCATION *RelocBase;\r
1156 EFI_IMAGE_BASE_RELOCATION *RelocBaseEnd;\r
1157 UINT16 *Reloc;\r
1158 UINT16 *RelocEnd;\r
1159 CHAR8 *Fixup;\r
1160 CHAR8 *FixupBase;\r
1161 UINT16 *F16;\r
1162 UINT32 *F32;\r
1163 UINT64 *F64;\r
1164 CHAR8 *FixupData;\r
1165 UINTN Adjust;\r
1166 RETURN_STATUS Status;\r
1167\r
1168 OldBase = (CHAR8 *)((UINTN)ImageBase);\r
1169 NewBase = (CHAR8 *)((UINTN)VirtImageBase);\r
1170 Adjust = (UINTN) NewBase - (UINTN) OldBase;\r
1171\r
1172 //\r
1173 // Find the image's relocate dir info\r
1174 //\r
1175 DosHdr = (EFI_IMAGE_DOS_HEADER *)OldBase;\r
1176 if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {\r
1177 //\r
1178 // Valid DOS header so get address of PE header\r
1179 //\r
1180 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)(((CHAR8 *)DosHdr) + DosHdr->e_lfanew);\r
1181 } else {\r
1182 //\r
1183 // No Dos header so assume image starts with PE header.\r
1184 //\r
1185 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)OldBase;\r
1186 }\r
1187\r
1188 if (Hdr.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) {\r
1189 //\r
1190 // Not a valid PE image so Exit\r
1191 //\r
1192 return ;\r
1193 }\r
1194\r
1195 //\r
1196 // Get some data from the PE type dependent data\r
1197 //\r
1198 if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
9c7790d2 1199 //\r
2ce31132 1200 // Use PE32 offset\r
1201 //\r
1202 NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;\r
317f832e 1203 DataDirectory = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32->OptionalHeader.DataDirectory[0]);\r
2ce31132 1204 } else {\r
9c7790d2 1205 //\r
2ce31132 1206 // Use PE32+ offset\r
1207 //\r
1208 NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;\r
317f832e 1209 DataDirectory = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32Plus->OptionalHeader.DataDirectory[0]);\r
9c7790d2 1210 }\r
2ce31132 1211\r
1212 //\r
1213 // Find the relocation block\r
1214 //\r
1215 // Per the PE/COFF spec, you can't assume that a given data directory\r
1216 // is present in the image. You have to check the NumberOfRvaAndSizes in\r
1217 // the optional header to verify a desired directory entry is there.\r
9c7790d2 1218 //\r
2ce31132 1219 if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {\r
1220 RelocDir = DataDirectory + EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC;\r
1221 RelocBase = (EFI_IMAGE_BASE_RELOCATION *)(UINTN)(ImageBase + RelocDir->VirtualAddress);\r
1222 RelocBaseEnd = (EFI_IMAGE_BASE_RELOCATION *)(UINTN)(ImageBase + RelocDir->VirtualAddress + RelocDir->Size);\r
1223 } else {\r
1224 //\r
1225 // Cannot find relocations, cannot continue\r
1226 //\r
1227 ASSERT (FALSE);\r
1228 return ;\r
1229 }\r
1230\r
1231 ASSERT (RelocBase != NULL && RelocBaseEnd != NULL);\r
1232\r
1233 //\r
1234 // Run the whole relocation block. And re-fixup data that has not been\r
1235 // modified. The FixupData is used to see if the image has been modified\r
1236 // since it was relocated. This is so data sections that have been updated\r
1237 // by code will not be fixed up, since that would set them back to\r
1238 // defaults.\r
1239 //\r
1240 FixupData = RelocationData;\r
1241 while (RelocBase < RelocBaseEnd) {\r
1242\r
1243 Reloc = (UINT16 *) ((UINT8 *) RelocBase + sizeof (EFI_IMAGE_BASE_RELOCATION));\r
1244 RelocEnd = (UINT16 *) ((UINT8 *) RelocBase + RelocBase->SizeOfBlock);\r
1245 FixupBase = (CHAR8 *) ((UINTN)ImageBase) + RelocBase->VirtualAddress;\r
1246\r
1247 //\r
1248 // Run this relocation record\r
1249 //\r
1250 while (Reloc < RelocEnd) {\r
1251\r
1252 Fixup = FixupBase + (*Reloc & 0xFFF);\r
1253 switch ((*Reloc) >> 12) {\r
1254\r
1255 case EFI_IMAGE_REL_BASED_ABSOLUTE:\r
1256 break;\r
1257\r
1258 case EFI_IMAGE_REL_BASED_HIGH:\r
1259 F16 = (UINT16 *) Fixup;\r
1260 if (*(UINT16 *) FixupData == *F16) {\r
9c7790d2 1261 *F16 = (UINT16) (*F16 + ((UINT16) ((UINT32) Adjust >> 16)));\r
2ce31132 1262 }\r
1263\r
1264 FixupData = FixupData + sizeof (UINT16);\r
1265 break;\r
1266\r
1267 case EFI_IMAGE_REL_BASED_LOW:\r
1268 F16 = (UINT16 *) Fixup;\r
1269 if (*(UINT16 *) FixupData == *F16) {\r
1270 *F16 = (UINT16) (*F16 + ((UINT16) Adjust & 0xffff));\r
1271 }\r
1272\r
1273 FixupData = FixupData + sizeof (UINT16);\r
1274 break;\r
1275\r
1276 case EFI_IMAGE_REL_BASED_HIGHLOW:\r
1277 F32 = (UINT32 *) Fixup;\r
1278 FixupData = ALIGN_POINTER (FixupData, sizeof (UINT32));\r
1279 if (*(UINT32 *) FixupData == *F32) {\r
1280 *F32 = *F32 + (UINT32) Adjust;\r
1281 }\r
1282\r
1283 FixupData = FixupData + sizeof (UINT32);\r
1284 break;\r
1285\r
1286 case EFI_IMAGE_REL_BASED_DIR64:\r
1287 F64 = (UINT64 *)Fixup;\r
1288 FixupData = ALIGN_POINTER (FixupData, sizeof (UINT64));\r
317f832e 1289 if (*(UINT64 *) FixupData == *F64) {\r
2ce31132 1290 *F64 = *F64 + (UINT64)Adjust;\r
1291 }\r
317f832e 1292\r
1293 FixupData = FixupData + sizeof (UINT64);\r
2ce31132 1294 break;\r
1295\r
1296 case EFI_IMAGE_REL_BASED_HIGHADJ:\r
1297 //\r
1298 // Not implemented, but not used in EFI 1.0\r
1299 //\r
1300 ASSERT (FALSE);\r
1301 break;\r
1302\r
1303 default:\r
1304 //\r
1305 // Only Itanium requires ConvertPeImage_Ex\r
1306 //\r
1307 Status = PeHotRelocateImageEx (Reloc, Fixup, &FixupData, Adjust);\r
1308 if (RETURN_ERROR (Status)) {\r
1309 return ;\r
1310 }\r
1311 }\r
1312 //\r
1313 // Next relocation record\r
1314 //\r
1315 Reloc += 1;\r
1316 }\r
1317 //\r
1318 // next reloc block\r
1319 //\r
1320 RelocBase = (EFI_IMAGE_BASE_RELOCATION *) RelocEnd;\r
1321 }\r
1322}\r
1323\r
1324\r
1325/**\r
1326 ImageRead function that operates on a memory buffer whos base is passed into\r
9c7790d2 1327 FileHandle.\r
2ce31132 1328\r
1329 @param FileHandle Ponter to baes of the input stream\r
1330 @param FileOffset Offset to the start of the buffer\r
1331 @param ReadSize Number of bytes to copy into the buffer\r
1332 @param Buffer Location to place results of read\r
1333\r
9c7790d2 1334 @retval RETURN_SUCCESS Data is read from FileOffset from the Handle into\r
2ce31132 1335 the buffer.\r
1336**/\r
1337RETURN_STATUS\r
1338EFIAPI\r
1339PeCoffLoaderImageReadFromMemory (\r
1340 IN VOID *FileHandle,\r
1341 IN UINTN FileOffset,\r
1342 IN OUT UINTN *ReadSize,\r
1343 OUT VOID *Buffer\r
1344 )\r
1345{\r
1346 CopyMem (Buffer, ((UINT8 *)FileHandle) + FileOffset, *ReadSize);\r
1347 return RETURN_SUCCESS;\r
1348}\r
1349\r