]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - BaseTools/Source/C/GenFw/Elf64Convert.c
BaseTools GCC: introduce GCC5 toolchain to support GCC v5.x in LTO mode
[mirror_edk2.git] / BaseTools / Source / C / GenFw / Elf64Convert.c
... / ...
CommitLineData
1/** @file\r
2Elf64 convert solution\r
3\r
4Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR>\r
5Portions copyright (c) 2013-2014, ARM Ltd. All rights reserved.<BR>\r
6\r
7This program and the accompanying materials are licensed and made available\r
8under the terms and conditions of the BSD License which accompanies this\r
9distribution. The full text of the license may be found at\r
10http://opensource.org/licenses/bsd-license.php\r
11\r
12THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
13WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
14\r
15**/\r
16\r
17#include "WinNtInclude.h"\r
18\r
19#ifndef __GNUC__\r
20#include <windows.h>\r
21#include <io.h>\r
22#endif\r
23#include <assert.h>\r
24#include <stdbool.h>\r
25#include <stdio.h>\r
26#include <stdlib.h>\r
27#include <string.h>\r
28#include <time.h>\r
29#include <ctype.h>\r
30\r
31#include <Common/UefiBaseTypes.h>\r
32#include <IndustryStandard/PeImage.h>\r
33\r
34#include "PeCoffLib.h"\r
35#include "EfiUtilityMsgs.h"\r
36\r
37#include "GenFw.h"\r
38#include "ElfConvert.h"\r
39#include "Elf64Convert.h"\r
40\r
41STATIC\r
42VOID\r
43ScanSections64 (\r
44 VOID\r
45 );\r
46\r
47STATIC\r
48BOOLEAN\r
49WriteSections64 (\r
50 SECTION_FILTER_TYPES FilterType\r
51 );\r
52\r
53STATIC\r
54VOID\r
55WriteRelocations64 (\r
56 VOID\r
57 );\r
58\r
59STATIC\r
60VOID\r
61WriteDebug64 (\r
62 VOID\r
63 );\r
64\r
65STATIC\r
66VOID\r
67SetImageSize64 (\r
68 VOID\r
69 );\r
70\r
71STATIC\r
72VOID\r
73CleanUp64 (\r
74 VOID\r
75 );\r
76\r
77//\r
78// Rename ELF32 strucutres to common names to help when porting to ELF64.\r
79//\r
80typedef Elf64_Shdr Elf_Shdr;\r
81typedef Elf64_Ehdr Elf_Ehdr;\r
82typedef Elf64_Rel Elf_Rel;\r
83typedef Elf64_Rela Elf_Rela;\r
84typedef Elf64_Sym Elf_Sym;\r
85typedef Elf64_Phdr Elf_Phdr;\r
86typedef Elf64_Dyn Elf_Dyn;\r
87#define ELFCLASS ELFCLASS64\r
88#define ELF_R_TYPE(r) ELF64_R_TYPE(r)\r
89#define ELF_R_SYM(r) ELF64_R_SYM(r)\r
90\r
91//\r
92// Well known ELF structures.\r
93//\r
94STATIC Elf_Ehdr *mEhdr;\r
95STATIC Elf_Shdr *mShdrBase;\r
96STATIC Elf_Phdr *mPhdrBase;\r
97\r
98//\r
99// Coff information\r
100//\r
101STATIC UINT32 mCoffAlignment = 0x20;\r
102\r
103//\r
104// PE section alignment.\r
105//\r
106STATIC const UINT16 mCoffNbrSections = 4;\r
107\r
108//\r
109// ELF sections to offset in Coff file.\r
110//\r
111STATIC UINT32 *mCoffSectionsOffset = NULL;\r
112\r
113//\r
114// Offsets in COFF file\r
115//\r
116STATIC UINT32 mNtHdrOffset;\r
117STATIC UINT32 mTextOffset;\r
118STATIC UINT32 mDataOffset;\r
119STATIC UINT32 mHiiRsrcOffset;\r
120STATIC UINT32 mRelocOffset;\r
121STATIC UINT32 mDebugOffset;\r
122\r
123//\r
124// Initialization Function\r
125//\r
126BOOLEAN\r
127InitializeElf64 (\r
128 UINT8 *FileBuffer,\r
129 ELF_FUNCTION_TABLE *ElfFunctions\r
130 )\r
131{\r
132 //\r
133 // Initialize data pointer and structures.\r
134 //\r
135 VerboseMsg ("Set EHDR");\r
136 mEhdr = (Elf_Ehdr*) FileBuffer;\r
137\r
138 //\r
139 // Check the ELF64 specific header information.\r
140 //\r
141 VerboseMsg ("Check ELF64 Header Information");\r
142 if (mEhdr->e_ident[EI_CLASS] != ELFCLASS64) {\r
143 Error (NULL, 0, 3000, "Unsupported", "ELF EI_DATA not ELFCLASS64");\r
144 return FALSE;\r
145 }\r
146 if (mEhdr->e_ident[EI_DATA] != ELFDATA2LSB) {\r
147 Error (NULL, 0, 3000, "Unsupported", "ELF EI_DATA not ELFDATA2LSB");\r
148 return FALSE;\r
149 }\r
150 if ((mEhdr->e_type != ET_EXEC) && (mEhdr->e_type != ET_DYN)) {\r
151 Error (NULL, 0, 3000, "Unsupported", "ELF e_type not ET_EXEC or ET_DYN");\r
152 return FALSE;\r
153 }\r
154 if (!((mEhdr->e_machine == EM_X86_64) || (mEhdr->e_machine == EM_AARCH64))) {\r
155 Error (NULL, 0, 3000, "Unsupported", "ELF e_machine not EM_X86_64 or EM_AARCH64");\r
156 return FALSE;\r
157 }\r
158 if (mEhdr->e_version != EV_CURRENT) {\r
159 Error (NULL, 0, 3000, "Unsupported", "ELF e_version (%u) not EV_CURRENT (%d)", (unsigned) mEhdr->e_version, EV_CURRENT);\r
160 return FALSE;\r
161 }\r
162\r
163 //\r
164 // Update section header pointers\r
165 //\r
166 VerboseMsg ("Update Header Pointers");\r
167 mShdrBase = (Elf_Shdr *)((UINT8 *)mEhdr + mEhdr->e_shoff);\r
168 mPhdrBase = (Elf_Phdr *)((UINT8 *)mEhdr + mEhdr->e_phoff);\r
169\r
170 //\r
171 // Create COFF Section offset buffer and zero.\r
172 //\r
173 VerboseMsg ("Create COFF Section Offset Buffer");\r
174 mCoffSectionsOffset = (UINT32 *)malloc(mEhdr->e_shnum * sizeof (UINT32));\r
175 memset(mCoffSectionsOffset, 0, mEhdr->e_shnum * sizeof(UINT32));\r
176\r
177 //\r
178 // Fill in function pointers.\r
179 //\r
180 VerboseMsg ("Fill in Function Pointers");\r
181 ElfFunctions->ScanSections = ScanSections64;\r
182 ElfFunctions->WriteSections = WriteSections64;\r
183 ElfFunctions->WriteRelocations = WriteRelocations64;\r
184 ElfFunctions->WriteDebug = WriteDebug64;\r
185 ElfFunctions->SetImageSize = SetImageSize64;\r
186 ElfFunctions->CleanUp = CleanUp64;\r
187\r
188 return TRUE;\r
189}\r
190\r
191\r
192//\r
193// Header by Index functions\r
194//\r
195STATIC\r
196Elf_Shdr*\r
197GetShdrByIndex (\r
198 UINT32 Num\r
199 )\r
200{\r
201 if (Num >= mEhdr->e_shnum) {\r
202 Error (NULL, 0, 3000, "Invalid", "GetShdrByIndex: Index %u is too high.", Num);\r
203 exit(EXIT_FAILURE);\r
204 }\r
205\r
206 return (Elf_Shdr*)((UINT8*)mShdrBase + Num * mEhdr->e_shentsize);\r
207}\r
208\r
209STATIC\r
210UINT32\r
211CoffAlign (\r
212 UINT32 Offset\r
213 )\r
214{\r
215 return (Offset + mCoffAlignment - 1) & ~(mCoffAlignment - 1);\r
216}\r
217\r
218STATIC\r
219UINT32\r
220DebugRvaAlign (\r
221 UINT32 Offset\r
222 )\r
223{\r
224 return (Offset + 3) & ~3;\r
225}\r
226\r
227//\r
228// filter functions\r
229//\r
230STATIC\r
231BOOLEAN\r
232IsTextShdr (\r
233 Elf_Shdr *Shdr\r
234 )\r
235{\r
236 return (BOOLEAN) ((Shdr->sh_flags & (SHF_WRITE | SHF_ALLOC)) == SHF_ALLOC);\r
237}\r
238\r
239STATIC\r
240BOOLEAN\r
241IsHiiRsrcShdr (\r
242 Elf_Shdr *Shdr\r
243 )\r
244{\r
245 Elf_Shdr *Namedr = GetShdrByIndex(mEhdr->e_shstrndx);\r
246\r
247 return (BOOLEAN) (strcmp((CHAR8*)mEhdr + Namedr->sh_offset + Shdr->sh_name, ELF_HII_SECTION_NAME) == 0);\r
248}\r
249\r
250STATIC\r
251BOOLEAN\r
252IsDataShdr (\r
253 Elf_Shdr *Shdr\r
254 )\r
255{\r
256 if (IsHiiRsrcShdr(Shdr)) {\r
257 return FALSE;\r
258 }\r
259 return (BOOLEAN) (Shdr->sh_flags & (SHF_WRITE | SHF_ALLOC)) == (SHF_ALLOC | SHF_WRITE);\r
260}\r
261\r
262STATIC\r
263BOOLEAN\r
264IsStrtabShdr (\r
265 Elf_Shdr *Shdr\r
266 )\r
267{\r
268 Elf_Shdr *Namedr = GetShdrByIndex(mEhdr->e_shstrndx);\r
269\r
270 return (BOOLEAN) (strcmp((CHAR8*)mEhdr + Namedr->sh_offset + Shdr->sh_name, ELF_STRTAB_SECTION_NAME) == 0);\r
271}\r
272\r
273STATIC\r
274Elf_Shdr *\r
275FindStrtabShdr (\r
276 VOID\r
277 )\r
278{\r
279 UINT32 i;\r
280 for (i = 0; i < mEhdr->e_shnum; i++) {\r
281 Elf_Shdr *shdr = GetShdrByIndex(i);\r
282 if (IsStrtabShdr(shdr)) {\r
283 return shdr;\r
284 }\r
285 }\r
286 return NULL;\r
287}\r
288\r
289STATIC\r
290const UINT8 *\r
291GetSymName (\r
292 Elf_Sym *Sym\r
293 )\r
294{\r
295 if (Sym->st_name == 0) {\r
296 return NULL;\r
297 }\r
298\r
299 Elf_Shdr *StrtabShdr = FindStrtabShdr();\r
300 if (StrtabShdr == NULL) {\r
301 return NULL;\r
302 }\r
303\r
304 assert(Sym->st_name < StrtabShdr->sh_size);\r
305\r
306 UINT8* StrtabContents = (UINT8*)mEhdr + StrtabShdr->sh_offset;\r
307\r
308 bool foundEnd = false;\r
309 UINT32 i;\r
310 for (i= Sym->st_name; (i < StrtabShdr->sh_size) && !foundEnd; i++) {\r
311 foundEnd = StrtabContents[i] == 0;\r
312 }\r
313 assert(foundEnd);\r
314\r
315 return StrtabContents + Sym->st_name;\r
316}\r
317\r
318//\r
319// Elf functions interface implementation\r
320//\r
321\r
322STATIC\r
323VOID\r
324ScanSections64 (\r
325 VOID\r
326 )\r
327{\r
328 UINT32 i;\r
329 EFI_IMAGE_DOS_HEADER *DosHdr;\r
330 EFI_IMAGE_OPTIONAL_HEADER_UNION *NtHdr;\r
331 UINT32 CoffEntry;\r
332 UINT32 SectionCount;\r
333 BOOLEAN FoundSection;\r
334\r
335 CoffEntry = 0;\r
336 mCoffOffset = 0;\r
337\r
338 //\r
339 // Coff file start with a DOS header.\r
340 //\r
341 mCoffOffset = sizeof(EFI_IMAGE_DOS_HEADER) + 0x40;\r
342 mNtHdrOffset = mCoffOffset;\r
343 switch (mEhdr->e_machine) {\r
344 case EM_X86_64:\r
345 case EM_IA_64:\r
346 case EM_AARCH64:\r
347 mCoffOffset += sizeof (EFI_IMAGE_NT_HEADERS64);\r
348 break;\r
349 default:\r
350 VerboseMsg ("%s unknown e_machine type %hu. Assume X64", mInImageName, mEhdr->e_machine);\r
351 mCoffOffset += sizeof (EFI_IMAGE_NT_HEADERS64);\r
352 break;\r
353 }\r
354\r
355 mTableOffset = mCoffOffset;\r
356 mCoffOffset += mCoffNbrSections * sizeof(EFI_IMAGE_SECTION_HEADER);\r
357\r
358 //\r
359 // Set mCoffAlignment to the maximum alignment of the input sections\r
360 // we care about\r
361 //\r
362 for (i = 0; i < mEhdr->e_shnum; i++) {\r
363 Elf_Shdr *shdr = GetShdrByIndex(i);\r
364 if (shdr->sh_addralign <= mCoffAlignment) {\r
365 continue;\r
366 }\r
367 if (IsTextShdr(shdr) || IsDataShdr(shdr) || IsHiiRsrcShdr(shdr)) {\r
368 mCoffAlignment = (UINT32)shdr->sh_addralign;\r
369 }\r
370 }\r
371\r
372 //\r
373 // Move the PE/COFF header right before the first section. This will help us\r
374 // save space when converting to TE.\r
375 //\r
376 if (mCoffAlignment > mCoffOffset) {\r
377 mNtHdrOffset += mCoffAlignment - mCoffOffset;\r
378 mTableOffset += mCoffAlignment - mCoffOffset;\r
379 mCoffOffset = mCoffAlignment;\r
380 }\r
381\r
382 //\r
383 // First text sections.\r
384 //\r
385 mCoffOffset = CoffAlign(mCoffOffset);\r
386 mTextOffset = mCoffOffset;\r
387 FoundSection = FALSE;\r
388 SectionCount = 0;\r
389 for (i = 0; i < mEhdr->e_shnum; i++) {\r
390 Elf_Shdr *shdr = GetShdrByIndex(i);\r
391 if (IsTextShdr(shdr)) {\r
392 if ((shdr->sh_addralign != 0) && (shdr->sh_addralign != 1)) {\r
393 // the alignment field is valid\r
394 if ((shdr->sh_addr & (shdr->sh_addralign - 1)) == 0) {\r
395 // if the section address is aligned we must align PE/COFF\r
396 mCoffOffset = (UINT32) ((mCoffOffset + shdr->sh_addralign - 1) & ~(shdr->sh_addralign - 1));\r
397 } else {\r
398 Error (NULL, 0, 3000, "Invalid", "Section address not aligned to its own alignment.");\r
399 }\r
400 }\r
401\r
402 /* Relocate entry. */\r
403 if ((mEhdr->e_entry >= shdr->sh_addr) &&\r
404 (mEhdr->e_entry < shdr->sh_addr + shdr->sh_size)) {\r
405 CoffEntry = (UINT32) (mCoffOffset + mEhdr->e_entry - shdr->sh_addr);\r
406 }\r
407\r
408 //\r
409 // Set mTextOffset with the offset of the first '.text' section\r
410 //\r
411 if (!FoundSection) {\r
412 mTextOffset = mCoffOffset;\r
413 FoundSection = TRUE;\r
414 }\r
415\r
416 mCoffSectionsOffset[i] = mCoffOffset;\r
417 mCoffOffset += (UINT32) shdr->sh_size;\r
418 SectionCount ++;\r
419 }\r
420 }\r
421\r
422 if (!FoundSection) {\r
423 Error (NULL, 0, 3000, "Invalid", "Did not find any '.text' section.");\r
424 assert (FALSE);\r
425 }\r
426\r
427 mDebugOffset = DebugRvaAlign(mCoffOffset);\r
428 mCoffOffset = CoffAlign(mCoffOffset);\r
429\r
430 if (SectionCount > 1 && mOutImageType == FW_EFI_IMAGE) {\r
431 Warning (NULL, 0, 0, NULL, "Mulitple sections in %s are merged into 1 text section. Source level debug might not work correctly.", mInImageName);\r
432 }\r
433\r
434 //\r
435 // Then data sections.\r
436 //\r
437 mDataOffset = mCoffOffset;\r
438 FoundSection = FALSE;\r
439 SectionCount = 0;\r
440 for (i = 0; i < mEhdr->e_shnum; i++) {\r
441 Elf_Shdr *shdr = GetShdrByIndex(i);\r
442 if (IsDataShdr(shdr)) {\r
443 if ((shdr->sh_addralign != 0) && (shdr->sh_addralign != 1)) {\r
444 // the alignment field is valid\r
445 if ((shdr->sh_addr & (shdr->sh_addralign - 1)) == 0) {\r
446 // if the section address is aligned we must align PE/COFF\r
447 mCoffOffset = (UINT32) ((mCoffOffset + shdr->sh_addralign - 1) & ~(shdr->sh_addralign - 1));\r
448 } else {\r
449 Error (NULL, 0, 3000, "Invalid", "Section address not aligned to its own alignment.");\r
450 }\r
451 }\r
452\r
453 //\r
454 // Set mDataOffset with the offset of the first '.data' section\r
455 //\r
456 if (!FoundSection) {\r
457 mDataOffset = mCoffOffset;\r
458 FoundSection = TRUE;\r
459 }\r
460 mCoffSectionsOffset[i] = mCoffOffset;\r
461 mCoffOffset += (UINT32) shdr->sh_size;\r
462 SectionCount ++;\r
463 }\r
464 }\r
465\r
466 //\r
467 // Make room for .debug data in .data (or .text if .data is empty) instead of\r
468 // putting it in a section of its own. This is explicitly allowed by the\r
469 // PE/COFF spec, and prevents bloat in the binary when using large values for\r
470 // section alignment.\r
471 //\r
472 if (SectionCount > 0) {\r
473 mDebugOffset = DebugRvaAlign(mCoffOffset);\r
474 }\r
475 mCoffOffset = mDebugOffset + sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY) +\r
476 sizeof(EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY) +\r
477 strlen(mInImageName) + 1;\r
478\r
479 mCoffOffset = CoffAlign(mCoffOffset);\r
480 if (SectionCount == 0) {\r
481 mDataOffset = mCoffOffset;\r
482 }\r
483\r
484 if (SectionCount > 1 && mOutImageType == FW_EFI_IMAGE) {\r
485 Warning (NULL, 0, 0, NULL, "Mulitple sections in %s are merged into 1 data section. Source level debug might not work correctly.", mInImageName);\r
486 }\r
487\r
488 //\r
489 // The HII resource sections.\r
490 //\r
491 mHiiRsrcOffset = mCoffOffset;\r
492 for (i = 0; i < mEhdr->e_shnum; i++) {\r
493 Elf_Shdr *shdr = GetShdrByIndex(i);\r
494 if (IsHiiRsrcShdr(shdr)) {\r
495 if ((shdr->sh_addralign != 0) && (shdr->sh_addralign != 1)) {\r
496 // the alignment field is valid\r
497 if ((shdr->sh_addr & (shdr->sh_addralign - 1)) == 0) {\r
498 // if the section address is aligned we must align PE/COFF\r
499 mCoffOffset = (UINT32) ((mCoffOffset + shdr->sh_addralign - 1) & ~(shdr->sh_addralign - 1));\r
500 } else {\r
501 Error (NULL, 0, 3000, "Invalid", "Section address not aligned to its own alignment.");\r
502 }\r
503 }\r
504 if (shdr->sh_size != 0) {\r
505 mHiiRsrcOffset = mCoffOffset;\r
506 mCoffSectionsOffset[i] = mCoffOffset;\r
507 mCoffOffset += (UINT32) shdr->sh_size;\r
508 mCoffOffset = CoffAlign(mCoffOffset);\r
509 SetHiiResourceHeader ((UINT8*) mEhdr + shdr->sh_offset, mHiiRsrcOffset);\r
510 }\r
511 break;\r
512 }\r
513 }\r
514\r
515 mRelocOffset = mCoffOffset;\r
516\r
517 //\r
518 // Allocate base Coff file. Will be expanded later for relocations.\r
519 //\r
520 mCoffFile = (UINT8 *)malloc(mCoffOffset);\r
521 memset(mCoffFile, 0, mCoffOffset);\r
522\r
523 //\r
524 // Fill headers.\r
525 //\r
526 DosHdr = (EFI_IMAGE_DOS_HEADER *)mCoffFile;\r
527 DosHdr->e_magic = EFI_IMAGE_DOS_SIGNATURE;\r
528 DosHdr->e_lfanew = mNtHdrOffset;\r
529\r
530 NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION*)(mCoffFile + mNtHdrOffset);\r
531\r
532 NtHdr->Pe32Plus.Signature = EFI_IMAGE_NT_SIGNATURE;\r
533\r
534 switch (mEhdr->e_machine) {\r
535 case EM_X86_64:\r
536 NtHdr->Pe32Plus.FileHeader.Machine = EFI_IMAGE_MACHINE_X64;\r
537 NtHdr->Pe32Plus.OptionalHeader.Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
538 break;\r
539 case EM_IA_64:\r
540 NtHdr->Pe32Plus.FileHeader.Machine = EFI_IMAGE_MACHINE_IPF;\r
541 NtHdr->Pe32Plus.OptionalHeader.Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
542 break;\r
543 case EM_AARCH64:\r
544 NtHdr->Pe32Plus.FileHeader.Machine = EFI_IMAGE_MACHINE_AARCH64;\r
545 NtHdr->Pe32Plus.OptionalHeader.Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
546 break;\r
547 default:\r
548 VerboseMsg ("%s unknown e_machine type. Assume X64", (UINTN)mEhdr->e_machine);\r
549 NtHdr->Pe32Plus.FileHeader.Machine = EFI_IMAGE_MACHINE_X64;\r
550 NtHdr->Pe32Plus.OptionalHeader.Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
551 }\r
552\r
553 NtHdr->Pe32Plus.FileHeader.NumberOfSections = mCoffNbrSections;\r
554 NtHdr->Pe32Plus.FileHeader.TimeDateStamp = (UINT32) time(NULL);\r
555 mImageTimeStamp = NtHdr->Pe32Plus.FileHeader.TimeDateStamp;\r
556 NtHdr->Pe32Plus.FileHeader.PointerToSymbolTable = 0;\r
557 NtHdr->Pe32Plus.FileHeader.NumberOfSymbols = 0;\r
558 NtHdr->Pe32Plus.FileHeader.SizeOfOptionalHeader = sizeof(NtHdr->Pe32Plus.OptionalHeader);\r
559 NtHdr->Pe32Plus.FileHeader.Characteristics = EFI_IMAGE_FILE_EXECUTABLE_IMAGE\r
560 | EFI_IMAGE_FILE_LINE_NUMS_STRIPPED\r
561 | EFI_IMAGE_FILE_LOCAL_SYMS_STRIPPED\r
562 | EFI_IMAGE_FILE_LARGE_ADDRESS_AWARE;\r
563\r
564 NtHdr->Pe32Plus.OptionalHeader.SizeOfCode = mDataOffset - mTextOffset;\r
565 NtHdr->Pe32Plus.OptionalHeader.SizeOfInitializedData = mRelocOffset - mDataOffset;\r
566 NtHdr->Pe32Plus.OptionalHeader.SizeOfUninitializedData = 0;\r
567 NtHdr->Pe32Plus.OptionalHeader.AddressOfEntryPoint = CoffEntry;\r
568\r
569 NtHdr->Pe32Plus.OptionalHeader.BaseOfCode = mTextOffset;\r
570\r
571 NtHdr->Pe32Plus.OptionalHeader.ImageBase = 0;\r
572 NtHdr->Pe32Plus.OptionalHeader.SectionAlignment = mCoffAlignment;\r
573 NtHdr->Pe32Plus.OptionalHeader.FileAlignment = mCoffAlignment;\r
574 NtHdr->Pe32Plus.OptionalHeader.SizeOfImage = 0;\r
575\r
576 NtHdr->Pe32Plus.OptionalHeader.SizeOfHeaders = mTextOffset;\r
577 NtHdr->Pe32Plus.OptionalHeader.NumberOfRvaAndSizes = EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES;\r
578\r
579 //\r
580 // Section headers.\r
581 //\r
582 if ((mDataOffset - mTextOffset) > 0) {\r
583 CreateSectionHeader (".text", mTextOffset, mDataOffset - mTextOffset,\r
584 EFI_IMAGE_SCN_CNT_CODE\r
585 | EFI_IMAGE_SCN_MEM_EXECUTE\r
586 | EFI_IMAGE_SCN_MEM_READ);\r
587 } else {\r
588 // Don't make a section of size 0.\r
589 NtHdr->Pe32Plus.FileHeader.NumberOfSections--;\r
590 }\r
591\r
592 if ((mHiiRsrcOffset - mDataOffset) > 0) {\r
593 CreateSectionHeader (".data", mDataOffset, mHiiRsrcOffset - mDataOffset,\r
594 EFI_IMAGE_SCN_CNT_INITIALIZED_DATA\r
595 | EFI_IMAGE_SCN_MEM_WRITE\r
596 | EFI_IMAGE_SCN_MEM_READ);\r
597 } else {\r
598 // Don't make a section of size 0.\r
599 NtHdr->Pe32Plus.FileHeader.NumberOfSections--;\r
600 }\r
601\r
602 if ((mRelocOffset - mHiiRsrcOffset) > 0) {\r
603 CreateSectionHeader (".rsrc", mHiiRsrcOffset, mRelocOffset - mHiiRsrcOffset,\r
604 EFI_IMAGE_SCN_CNT_INITIALIZED_DATA\r
605 | EFI_IMAGE_SCN_MEM_READ);\r
606\r
607 NtHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = mRelocOffset - mHiiRsrcOffset;\r
608 NtHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = mHiiRsrcOffset;\r
609 } else {\r
610 // Don't make a section of size 0.\r
611 NtHdr->Pe32Plus.FileHeader.NumberOfSections--;\r
612 }\r
613\r
614}\r
615\r
616STATIC\r
617BOOLEAN\r
618WriteSections64 (\r
619 SECTION_FILTER_TYPES FilterType\r
620 )\r
621{\r
622 UINT32 Idx;\r
623 Elf_Shdr *SecShdr;\r
624 UINT32 SecOffset;\r
625 BOOLEAN (*Filter)(Elf_Shdr *);\r
626\r
627 //\r
628 // Initialize filter pointer\r
629 //\r
630 switch (FilterType) {\r
631 case SECTION_TEXT:\r
632 Filter = IsTextShdr;\r
633 break;\r
634 case SECTION_HII:\r
635 Filter = IsHiiRsrcShdr;\r
636 break;\r
637 case SECTION_DATA:\r
638 Filter = IsDataShdr;\r
639 break;\r
640 default:\r
641 return FALSE;\r
642 }\r
643\r
644 //\r
645 // First: copy sections.\r
646 //\r
647 for (Idx = 0; Idx < mEhdr->e_shnum; Idx++) {\r
648 Elf_Shdr *Shdr = GetShdrByIndex(Idx);\r
649 if ((*Filter)(Shdr)) {\r
650 switch (Shdr->sh_type) {\r
651 case SHT_PROGBITS:\r
652 /* Copy. */\r
653 memcpy(mCoffFile + mCoffSectionsOffset[Idx],\r
654 (UINT8*)mEhdr + Shdr->sh_offset,\r
655 (size_t) Shdr->sh_size);\r
656 break;\r
657\r
658 case SHT_NOBITS:\r
659 memset(mCoffFile + mCoffSectionsOffset[Idx], 0, (size_t) Shdr->sh_size);\r
660 break;\r
661\r
662 default:\r
663 //\r
664 // Ignore for unkown section type.\r
665 //\r
666 VerboseMsg ("%s unknown section type %x. We directly copy this section into Coff file", mInImageName, (unsigned)Shdr->sh_type);\r
667 break;\r
668 }\r
669 }\r
670 }\r
671\r
672 //\r
673 // Second: apply relocations.\r
674 //\r
675 VerboseMsg ("Applying Relocations...");\r
676 for (Idx = 0; Idx < mEhdr->e_shnum; Idx++) {\r
677 //\r
678 // Determine if this is a relocation section.\r
679 //\r
680 Elf_Shdr *RelShdr = GetShdrByIndex(Idx);\r
681 if ((RelShdr->sh_type != SHT_REL) && (RelShdr->sh_type != SHT_RELA)) {\r
682 continue;\r
683 }\r
684\r
685 //\r
686 // Relocation section found. Now extract section information that the relocations\r
687 // apply to in the ELF data and the new COFF data.\r
688 //\r
689 SecShdr = GetShdrByIndex(RelShdr->sh_info);\r
690 SecOffset = mCoffSectionsOffset[RelShdr->sh_info];\r
691\r
692 //\r
693 // Only process relocations for the current filter type.\r
694 //\r
695 if (RelShdr->sh_type == SHT_RELA && (*Filter)(SecShdr)) {\r
696 UINT64 RelIdx;\r
697\r
698 //\r
699 // Determine the symbol table referenced by the relocation data.\r
700 //\r
701 Elf_Shdr *SymtabShdr = GetShdrByIndex(RelShdr->sh_link);\r
702 UINT8 *Symtab = (UINT8*)mEhdr + SymtabShdr->sh_offset;\r
703\r
704 //\r
705 // Process all relocation entries for this section.\r
706 //\r
707 for (RelIdx = 0; RelIdx < RelShdr->sh_size; RelIdx += (UINT32) RelShdr->sh_entsize) {\r
708\r
709 //\r
710 // Set pointer to relocation entry\r
711 //\r
712 Elf_Rela *Rel = (Elf_Rela *)((UINT8*)mEhdr + RelShdr->sh_offset + RelIdx);\r
713\r
714 //\r
715 // Set pointer to symbol table entry associated with the relocation entry.\r
716 //\r
717 Elf_Sym *Sym = (Elf_Sym *)(Symtab + ELF_R_SYM(Rel->r_info) * SymtabShdr->sh_entsize);\r
718\r
719 Elf_Shdr *SymShdr;\r
720 UINT8 *Targ;\r
721\r
722 //\r
723 // Check section header index found in symbol table and get the section\r
724 // header location.\r
725 //\r
726 if (Sym->st_shndx == SHN_UNDEF\r
727 || Sym->st_shndx >= mEhdr->e_shnum) {\r
728 const UINT8 *SymName = GetSymName(Sym);\r
729 if (SymName == NULL) {\r
730 SymName = (const UINT8 *)"<unknown>";\r
731 }\r
732\r
733 Error (NULL, 0, 3000, "Invalid",\r
734 "%s: Bad definition for symbol '%s'@%#llx or unsupported symbol type. "\r
735 "For example, absolute and undefined symbols are not supported.",\r
736 mInImageName, SymName, Sym->st_value);\r
737\r
738 exit(EXIT_FAILURE);\r
739 }\r
740 SymShdr = GetShdrByIndex(Sym->st_shndx);\r
741\r
742 //\r
743 // Convert the relocation data to a pointer into the coff file.\r
744 //\r
745 // Note:\r
746 // r_offset is the virtual address of the storage unit to be relocated.\r
747 // sh_addr is the virtual address for the base of the section.\r
748 //\r
749 // r_offset in a memory address.\r
750 // Convert it to a pointer in the coff file.\r
751 //\r
752 Targ = mCoffFile + SecOffset + (Rel->r_offset - SecShdr->sh_addr);\r
753\r
754 //\r
755 // Determine how to handle each relocation type based on the machine type.\r
756 //\r
757 if (mEhdr->e_machine == EM_X86_64) {\r
758 switch (ELF_R_TYPE(Rel->r_info)) {\r
759 case R_X86_64_NONE:\r
760 break;\r
761 case R_X86_64_64:\r
762 //\r
763 // Absolute relocation.\r
764 //\r
765 VerboseMsg ("R_X86_64_64");\r
766 VerboseMsg ("Offset: 0x%08X, Addend: 0x%016LX", \r
767 (UINT32)(SecOffset + (Rel->r_offset - SecShdr->sh_addr)), \r
768 *(UINT64 *)Targ);\r
769 *(UINT64 *)Targ = *(UINT64 *)Targ - SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx];\r
770 VerboseMsg ("Relocation: 0x%016LX", *(UINT64*)Targ);\r
771 break;\r
772 case R_X86_64_32:\r
773 VerboseMsg ("R_X86_64_32");\r
774 VerboseMsg ("Offset: 0x%08X, Addend: 0x%08X", \r
775 (UINT32)(SecOffset + (Rel->r_offset - SecShdr->sh_addr)), \r
776 *(UINT32 *)Targ);\r
777 *(UINT32 *)Targ = (UINT32)((UINT64)(*(UINT32 *)Targ) - SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx]);\r
778 VerboseMsg ("Relocation: 0x%08X", *(UINT32*)Targ);\r
779 break;\r
780 case R_X86_64_32S:\r
781 VerboseMsg ("R_X86_64_32S");\r
782 VerboseMsg ("Offset: 0x%08X, Addend: 0x%08X", \r
783 (UINT32)(SecOffset + (Rel->r_offset - SecShdr->sh_addr)), \r
784 *(UINT32 *)Targ);\r
785 *(INT32 *)Targ = (INT32)((INT64)(*(INT32 *)Targ) - SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx]);\r
786 VerboseMsg ("Relocation: 0x%08X", *(UINT32*)Targ);\r
787 break;\r
788 case R_X86_64_PC32:\r
789 //\r
790 // Relative relocation: Symbol - Ip + Addend\r
791 //\r
792 VerboseMsg ("R_X86_64_PC32");\r
793 VerboseMsg ("Offset: 0x%08X, Addend: 0x%08X", \r
794 (UINT32)(SecOffset + (Rel->r_offset - SecShdr->sh_addr)), \r
795 *(UINT32 *)Targ);\r
796 *(UINT32 *)Targ = (UINT32) (*(UINT32 *)Targ\r
797 + (mCoffSectionsOffset[Sym->st_shndx] - SymShdr->sh_addr)\r
798 - (SecOffset - SecShdr->sh_addr));\r
799 VerboseMsg ("Relocation: 0x%08X", *(UINT32 *)Targ);\r
800 break;\r
801 default:\r
802 Error (NULL, 0, 3000, "Invalid", "%s unsupported ELF EM_X86_64 relocation 0x%x.", mInImageName, (unsigned) ELF_R_TYPE(Rel->r_info));\r
803 }\r
804 } else if (mEhdr->e_machine == EM_AARCH64) {\r
805\r
806 switch (ELF_R_TYPE(Rel->r_info)) {\r
807\r
808 case R_AARCH64_ADR_PREL_PG_HI21:\r
809 case R_AARCH64_ADD_ABS_LO12_NC:\r
810 case R_AARCH64_LDST8_ABS_LO12_NC:\r
811 case R_AARCH64_LDST16_ABS_LO12_NC:\r
812 case R_AARCH64_LDST32_ABS_LO12_NC:\r
813 case R_AARCH64_LDST64_ABS_LO12_NC:\r
814 case R_AARCH64_LDST128_ABS_LO12_NC:\r
815 //\r
816 // AArch64 PG_H21 relocations are typically paired with ABS_LO12\r
817 // relocations, where a PC-relative reference with +/- 4 GB range is\r
818 // split into a relative high part and an absolute low part. Since\r
819 // the absolute low part represents the offset into a 4 KB page, we\r
820 // have to make sure that the 4 KB relative offsets of both the\r
821 // section containing the reference as well as the section to which\r
822 // it refers have not been changed during PE/COFF conversion (i.e.,\r
823 // in ScanSections64() above).\r
824 //\r
825 if (((SecShdr->sh_addr ^ SecOffset) & 0xfff) != 0 ||\r
826 ((SymShdr->sh_addr ^ mCoffSectionsOffset[Sym->st_shndx]) & 0xfff) != 0 ||\r
827 mCoffAlignment < 0x1000) {\r
828 Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s AARCH64 small code model requires 4 KB section alignment.",\r
829 mInImageName);\r
830 break;\r
831 }\r
832 /* fall through */\r
833\r
834 case R_AARCH64_ADR_PREL_LO21:\r
835 case R_AARCH64_CONDBR19:\r
836 case R_AARCH64_LD_PREL_LO19:\r
837 case R_AARCH64_CALL26:\r
838 case R_AARCH64_JUMP26:\r
839 case R_AARCH64_PREL64:\r
840 case R_AARCH64_PREL32:\r
841 case R_AARCH64_PREL16:\r
842 //\r
843 // The GCC toolchains (i.e., binutils) may corrupt section relative\r
844 // relocations when emitting relocation sections into fully linked\r
845 // binaries. More specifically, they tend to fail to take into\r
846 // account the fact that a '.rodata + XXX' relocation needs to have\r
847 // its addend recalculated once .rodata is merged into the .text\r
848 // section, and the relocation emitted into the .rela.text section.\r
849 //\r
850 // We cannot really recover from this loss of information, so the\r
851 // only workaround is to prevent having to recalculate any relative\r
852 // relocations at all, by using a linker script that ensures that\r
853 // the offset between the Place and the Symbol is the same in both\r
854 // the ELF and the PE/COFF versions of the binary.\r
855 //\r
856 if ((SymShdr->sh_addr - SecShdr->sh_addr) !=\r
857 (mCoffSectionsOffset[Sym->st_shndx] - SecOffset)) {\r
858 Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s AARCH64 relative relocations require identical ELF and PE/COFF section offsets",\r
859 mInImageName);\r
860 }\r
861 break;\r
862\r
863 // Absolute relocations.\r
864 case R_AARCH64_ABS64:\r
865 *(UINT64 *)Targ = *(UINT64 *)Targ - SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx];\r
866 break;\r
867\r
868 default:\r
869 Error (NULL, 0, 3000, "Invalid", "WriteSections64(): %s unsupported ELF EM_AARCH64 relocation 0x%x.", mInImageName, (unsigned) ELF_R_TYPE(Rel->r_info));\r
870 }\r
871 } else {\r
872 Error (NULL, 0, 3000, "Invalid", "Not a supported machine type");\r
873 }\r
874 }\r
875 }\r
876 }\r
877\r
878 return TRUE;\r
879}\r
880\r
881STATIC\r
882VOID\r
883WriteRelocations64 (\r
884 VOID\r
885 )\r
886{\r
887 UINT32 Index;\r
888 EFI_IMAGE_OPTIONAL_HEADER_UNION *NtHdr;\r
889 EFI_IMAGE_DATA_DIRECTORY *Dir;\r
890\r
891 for (Index = 0; Index < mEhdr->e_shnum; Index++) {\r
892 Elf_Shdr *RelShdr = GetShdrByIndex(Index);\r
893 if ((RelShdr->sh_type == SHT_REL) || (RelShdr->sh_type == SHT_RELA)) {\r
894 Elf_Shdr *SecShdr = GetShdrByIndex (RelShdr->sh_info);\r
895 if (IsTextShdr(SecShdr) || IsDataShdr(SecShdr)) {\r
896 UINT64 RelIdx;\r
897\r
898 for (RelIdx = 0; RelIdx < RelShdr->sh_size; RelIdx += RelShdr->sh_entsize) {\r
899 Elf_Rela *Rel = (Elf_Rela *)((UINT8*)mEhdr + RelShdr->sh_offset + RelIdx);\r
900\r
901 if (mEhdr->e_machine == EM_X86_64) {\r
902 switch (ELF_R_TYPE(Rel->r_info)) {\r
903 case R_X86_64_NONE:\r
904 case R_X86_64_PC32:\r
905 break;\r
906 case R_X86_64_64:\r
907 VerboseMsg ("EFI_IMAGE_REL_BASED_DIR64 Offset: 0x%08X", \r
908 mCoffSectionsOffset[RelShdr->sh_info] + (Rel->r_offset - SecShdr->sh_addr));\r
909 CoffAddFixup(\r
910 (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info]\r
911 + (Rel->r_offset - SecShdr->sh_addr)),\r
912 EFI_IMAGE_REL_BASED_DIR64);\r
913 break;\r
914 case R_X86_64_32S:\r
915 case R_X86_64_32:\r
916 VerboseMsg ("EFI_IMAGE_REL_BASED_HIGHLOW Offset: 0x%08X", \r
917 mCoffSectionsOffset[RelShdr->sh_info] + (Rel->r_offset - SecShdr->sh_addr));\r
918 CoffAddFixup(\r
919 (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info]\r
920 + (Rel->r_offset - SecShdr->sh_addr)),\r
921 EFI_IMAGE_REL_BASED_HIGHLOW);\r
922 break;\r
923 default:\r
924 Error (NULL, 0, 3000, "Invalid", "%s unsupported ELF EM_X86_64 relocation 0x%x.", mInImageName, (unsigned) ELF_R_TYPE(Rel->r_info));\r
925 }\r
926 } else if (mEhdr->e_machine == EM_AARCH64) {\r
927\r
928 switch (ELF_R_TYPE(Rel->r_info)) {\r
929 case R_AARCH64_ADR_PREL_LO21:\r
930 case R_AARCH64_CONDBR19:\r
931 case R_AARCH64_LD_PREL_LO19:\r
932 case R_AARCH64_CALL26:\r
933 case R_AARCH64_JUMP26:\r
934 case R_AARCH64_PREL64:\r
935 case R_AARCH64_PREL32:\r
936 case R_AARCH64_PREL16:\r
937 case R_AARCH64_ADR_PREL_PG_HI21:\r
938 case R_AARCH64_ADD_ABS_LO12_NC:\r
939 case R_AARCH64_LDST8_ABS_LO12_NC:\r
940 case R_AARCH64_LDST16_ABS_LO12_NC:\r
941 case R_AARCH64_LDST32_ABS_LO12_NC:\r
942 case R_AARCH64_LDST64_ABS_LO12_NC:\r
943 case R_AARCH64_LDST128_ABS_LO12_NC:\r
944 //\r
945 // No fixups are required for relative relocations, provided that\r
946 // the relative offsets between sections have been preserved in\r
947 // the ELF to PE/COFF conversion. We have already asserted that\r
948 // this is the case in WriteSections64 ().\r
949 //\r
950 break;\r
951\r
952 case R_AARCH64_ABS64:\r
953 CoffAddFixup(\r
954 (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info]\r
955 + (Rel->r_offset - SecShdr->sh_addr)),\r
956 EFI_IMAGE_REL_BASED_DIR64);\r
957 break;\r
958\r
959 case R_AARCH64_ABS32:\r
960 CoffAddFixup(\r
961 (UINT32) ((UINT64) mCoffSectionsOffset[RelShdr->sh_info]\r
962 + (Rel->r_offset - SecShdr->sh_addr)),\r
963 EFI_IMAGE_REL_BASED_HIGHLOW);\r
964 break;\r
965\r
966 default:\r
967 Error (NULL, 0, 3000, "Invalid", "WriteRelocations64(): %s unsupported ELF EM_AARCH64 relocation 0x%x.", mInImageName, (unsigned) ELF_R_TYPE(Rel->r_info));\r
968 }\r
969 } else {\r
970 Error (NULL, 0, 3000, "Not Supported", "This tool does not support relocations for ELF with e_machine %u (processor type).", (unsigned) mEhdr->e_machine);\r
971 }\r
972 }\r
973 }\r
974 }\r
975 }\r
976\r
977 //\r
978 // Pad by adding empty entries.\r
979 //\r
980 while (mCoffOffset & (mCoffAlignment - 1)) {\r
981 CoffAddFixupEntry(0);\r
982 }\r
983\r
984 NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(mCoffFile + mNtHdrOffset);\r
985 Dir = &NtHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];\r
986 Dir->Size = mCoffOffset - mRelocOffset;\r
987 if (Dir->Size == 0) {\r
988 // If no relocations, null out the directory entry and don't add the .reloc section\r
989 Dir->VirtualAddress = 0;\r
990 NtHdr->Pe32Plus.FileHeader.NumberOfSections--;\r
991 } else {\r
992 Dir->VirtualAddress = mRelocOffset;\r
993 CreateSectionHeader (".reloc", mRelocOffset, mCoffOffset - mRelocOffset,\r
994 EFI_IMAGE_SCN_CNT_INITIALIZED_DATA\r
995 | EFI_IMAGE_SCN_MEM_DISCARDABLE\r
996 | EFI_IMAGE_SCN_MEM_READ);\r
997 }\r
998}\r
999\r
1000STATIC\r
1001VOID\r
1002WriteDebug64 (\r
1003 VOID\r
1004 )\r
1005{\r
1006 UINT32 Len;\r
1007 EFI_IMAGE_OPTIONAL_HEADER_UNION *NtHdr;\r
1008 EFI_IMAGE_DATA_DIRECTORY *DataDir;\r
1009 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *Dir;\r
1010 EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY *Nb10;\r
1011\r
1012 Len = strlen(mInImageName) + 1;\r
1013\r
1014 Dir = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY*)(mCoffFile + mDebugOffset);\r
1015 Dir->Type = EFI_IMAGE_DEBUG_TYPE_CODEVIEW;\r
1016 Dir->SizeOfData = sizeof(EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY) + Len;\r
1017 Dir->RVA = mDebugOffset + sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);\r
1018 Dir->FileOffset = mDebugOffset + sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);\r
1019\r
1020 Nb10 = (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY*)(Dir + 1);\r
1021 Nb10->Signature = CODEVIEW_SIGNATURE_NB10;\r
1022 strcpy ((char *)(Nb10 + 1), mInImageName);\r
1023\r
1024\r
1025 NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(mCoffFile + mNtHdrOffset);\r
1026 DataDir = &NtHdr->Pe32Plus.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG];\r
1027 DataDir->VirtualAddress = mDebugOffset;\r
1028 DataDir->Size = Dir->SizeOfData + sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);\r
1029}\r
1030\r
1031STATIC\r
1032VOID\r
1033SetImageSize64 (\r
1034 VOID\r
1035 )\r
1036{\r
1037 EFI_IMAGE_OPTIONAL_HEADER_UNION *NtHdr;\r
1038\r
1039 //\r
1040 // Set image size\r
1041 //\r
1042 NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(mCoffFile + mNtHdrOffset);\r
1043 NtHdr->Pe32Plus.OptionalHeader.SizeOfImage = mCoffOffset;\r
1044}\r
1045\r
1046STATIC\r
1047VOID\r
1048CleanUp64 (\r
1049 VOID\r
1050 )\r
1051{\r
1052 if (mCoffSectionsOffset != NULL) {\r
1053 free (mCoffSectionsOffset);\r
1054 }\r
1055}\r
1056\r
1057\r