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