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