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