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