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