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