• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /** @file
2 Elf32 Convert solution
3 
4 Copyright (c) 2010 - 2016, Intel Corporation. All rights reserved.<BR>
5 Portions copyright (c) 2013, ARM Ltd. All rights reserved.<BR>
6 
7 This program and the accompanying materials are licensed and made available
8 under the terms and conditions of the BSD License which accompanies this
9 distribution.  The full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
11 
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14 
15 **/
16 
17 #include "WinNtInclude.h"
18 
19 #ifndef __GNUC__
20 #include <windows.h>
21 #include <io.h>
22 #endif
23 #include <assert.h>
24 #include <stdbool.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <time.h>
29 #include <ctype.h>
30 
31 #include <Common/UefiBaseTypes.h>
32 #include <IndustryStandard/PeImage.h>
33 
34 #include "PeCoffLib.h"
35 #include "EfiUtilityMsgs.h"
36 
37 #include "GenFw.h"
38 #include "ElfConvert.h"
39 #include "Elf32Convert.h"
40 
41 STATIC
42 VOID
43 ScanSections32 (
44   VOID
45   );
46 
47 STATIC
48 BOOLEAN
49 WriteSections32 (
50   SECTION_FILTER_TYPES  FilterType
51   );
52 
53 STATIC
54 VOID
55 WriteRelocations32 (
56   VOID
57   );
58 
59 STATIC
60 VOID
61 WriteDebug32 (
62   VOID
63   );
64 
65 STATIC
66 VOID
67 SetImageSize32 (
68   VOID
69   );
70 
71 STATIC
72 VOID
73 CleanUp32 (
74   VOID
75   );
76 
77 //
78 // Rename ELF32 strucutres to common names to help when porting to ELF64.
79 //
80 typedef Elf32_Shdr Elf_Shdr;
81 typedef Elf32_Ehdr Elf_Ehdr;
82 typedef Elf32_Rel Elf_Rel;
83 typedef Elf32_Sym Elf_Sym;
84 typedef Elf32_Phdr Elf_Phdr;
85 typedef Elf32_Dyn Elf_Dyn;
86 #define ELFCLASS ELFCLASS32
87 #define ELF_R_TYPE(r) ELF32_R_TYPE(r)
88 #define ELF_R_SYM(r) ELF32_R_SYM(r)
89 
90 //
91 // Well known ELF structures.
92 //
93 STATIC Elf_Ehdr *mEhdr;
94 STATIC Elf_Shdr *mShdrBase;
95 STATIC Elf_Phdr *mPhdrBase;
96 
97 //
98 // Coff information
99 //
100 STATIC UINT32 mCoffAlignment = 0x20;
101 
102 //
103 // PE section alignment.
104 //
105 STATIC const UINT16 mCoffNbrSections = 4;
106 
107 //
108 // ELF sections to offset in Coff file.
109 //
110 STATIC UINT32 *mCoffSectionsOffset = NULL;
111 
112 //
113 // Offsets in COFF file
114 //
115 STATIC UINT32 mNtHdrOffset;
116 STATIC UINT32 mTextOffset;
117 STATIC UINT32 mDataOffset;
118 STATIC UINT32 mHiiRsrcOffset;
119 STATIC UINT32 mRelocOffset;
120 STATIC UINT32 mDebugOffset;
121 
122 //
123 // Initialization Function
124 //
125 BOOLEAN
InitializeElf32(UINT8 * FileBuffer,ELF_FUNCTION_TABLE * ElfFunctions)126 InitializeElf32 (
127   UINT8               *FileBuffer,
128   ELF_FUNCTION_TABLE  *ElfFunctions
129   )
130 {
131   //
132   // Initialize data pointer and structures.
133   //
134   mEhdr = (Elf_Ehdr*) FileBuffer;
135 
136   //
137   // Check the ELF32 specific header information.
138   //
139   if (mEhdr->e_ident[EI_CLASS] != ELFCLASS32) {
140     Error (NULL, 0, 3000, "Unsupported", "ELF EI_DATA not ELFCLASS32");
141     return FALSE;
142   }
143   if (mEhdr->e_ident[EI_DATA] != ELFDATA2LSB) {
144     Error (NULL, 0, 3000, "Unsupported", "ELF EI_DATA not ELFDATA2LSB");
145     return FALSE;
146   }
147   if ((mEhdr->e_type != ET_EXEC) && (mEhdr->e_type != ET_DYN)) {
148     Error (NULL, 0, 3000, "Unsupported", "ELF e_type not ET_EXEC or ET_DYN");
149     return FALSE;
150   }
151   if (!((mEhdr->e_machine == EM_386) || (mEhdr->e_machine == EM_ARM))) {
152     Error (NULL, 0, 3000, "Unsupported", "ELF e_machine not EM_386 or EM_ARM");
153     return FALSE;
154   }
155   if (mEhdr->e_version != EV_CURRENT) {
156     Error (NULL, 0, 3000, "Unsupported", "ELF e_version (%u) not EV_CURRENT (%d)", (unsigned) mEhdr->e_version, EV_CURRENT);
157     return FALSE;
158   }
159 
160   //
161   // Update section header pointers
162   //
163   mShdrBase  = (Elf_Shdr *)((UINT8 *)mEhdr + mEhdr->e_shoff);
164   mPhdrBase = (Elf_Phdr *)((UINT8 *)mEhdr + mEhdr->e_phoff);
165 
166   //
167   // Create COFF Section offset buffer and zero.
168   //
169   mCoffSectionsOffset = (UINT32 *)malloc(mEhdr->e_shnum * sizeof (UINT32));
170   if (mCoffSectionsOffset == NULL) {
171     Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");
172     return FALSE;
173   }
174   memset(mCoffSectionsOffset, 0, mEhdr->e_shnum * sizeof(UINT32));
175 
176   //
177   // Fill in function pointers.
178   //
179   ElfFunctions->ScanSections = ScanSections32;
180   ElfFunctions->WriteSections = WriteSections32;
181   ElfFunctions->WriteRelocations = WriteRelocations32;
182   ElfFunctions->WriteDebug = WriteDebug32;
183   ElfFunctions->SetImageSize = SetImageSize32;
184   ElfFunctions->CleanUp = CleanUp32;
185 
186   return TRUE;
187 }
188 
189 
190 //
191 // Header by Index functions
192 //
193 STATIC
194 Elf_Shdr*
GetShdrByIndex(UINT32 Num)195 GetShdrByIndex (
196   UINT32 Num
197   )
198 {
199   if (Num >= mEhdr->e_shnum) {
200     Error (NULL, 0, 3000, "Invalid", "GetShdrByIndex: Index %u is too high.", Num);
201     exit(EXIT_FAILURE);
202   }
203 
204   return (Elf_Shdr*)((UINT8*)mShdrBase + Num * mEhdr->e_shentsize);
205 }
206 
207 STATIC
208 Elf_Phdr*
GetPhdrByIndex(UINT32 num)209 GetPhdrByIndex (
210   UINT32 num
211   )
212 {
213   if (num >= mEhdr->e_phnum) {
214     Error (NULL, 0, 3000, "Invalid", "GetPhdrByIndex: Index %u is too high.", num);
215     exit(EXIT_FAILURE);
216   }
217 
218   return (Elf_Phdr *)((UINT8*)mPhdrBase + num * mEhdr->e_phentsize);
219 }
220 
221 STATIC
222 UINT32
CoffAlign(UINT32 Offset)223 CoffAlign (
224   UINT32 Offset
225   )
226 {
227   return (Offset + mCoffAlignment - 1) & ~(mCoffAlignment - 1);
228 }
229 
230 STATIC
231 UINT32
DebugRvaAlign(UINT32 Offset)232 DebugRvaAlign (
233   UINT32 Offset
234   )
235 {
236   return (Offset + 3) & ~3;
237 }
238 
239 //
240 // filter functions
241 //
242 STATIC
243 BOOLEAN
IsTextShdr(Elf_Shdr * Shdr)244 IsTextShdr (
245   Elf_Shdr *Shdr
246   )
247 {
248   return (BOOLEAN) ((Shdr->sh_flags & (SHF_WRITE | SHF_ALLOC)) == SHF_ALLOC);
249 }
250 
251 STATIC
252 BOOLEAN
IsHiiRsrcShdr(Elf_Shdr * Shdr)253 IsHiiRsrcShdr (
254   Elf_Shdr *Shdr
255   )
256 {
257   Elf_Shdr *Namedr = GetShdrByIndex(mEhdr->e_shstrndx);
258 
259   return (BOOLEAN) (strcmp((CHAR8*)mEhdr + Namedr->sh_offset + Shdr->sh_name, ELF_HII_SECTION_NAME) == 0);
260 }
261 
262 STATIC
263 BOOLEAN
IsDataShdr(Elf_Shdr * Shdr)264 IsDataShdr (
265   Elf_Shdr *Shdr
266   )
267 {
268   if (IsHiiRsrcShdr(Shdr)) {
269     return FALSE;
270   }
271   return (BOOLEAN) (Shdr->sh_flags & (SHF_WRITE | SHF_ALLOC)) == (SHF_ALLOC | SHF_WRITE);
272 }
273 
274 STATIC
275 BOOLEAN
IsStrtabShdr(Elf_Shdr * Shdr)276 IsStrtabShdr (
277   Elf_Shdr *Shdr
278   )
279 {
280   Elf_Shdr *Namedr = GetShdrByIndex(mEhdr->e_shstrndx);
281 
282   return (BOOLEAN) (strcmp((CHAR8*)mEhdr + Namedr->sh_offset + Shdr->sh_name, ELF_STRTAB_SECTION_NAME) == 0);
283 }
284 
285 STATIC
286 Elf_Shdr *
FindStrtabShdr(VOID)287 FindStrtabShdr (
288   VOID
289   )
290 {
291   UINT32 i;
292   for (i = 0; i < mEhdr->e_shnum; i++) {
293     Elf_Shdr *shdr = GetShdrByIndex(i);
294     if (IsStrtabShdr(shdr)) {
295       return shdr;
296     }
297   }
298   return NULL;
299 }
300 
301 STATIC
302 const UINT8 *
GetSymName(Elf_Sym * Sym)303 GetSymName (
304   Elf_Sym *Sym
305   )
306 {
307   if (Sym->st_name == 0) {
308     return NULL;
309   }
310 
311   Elf_Shdr *StrtabShdr = FindStrtabShdr();
312   if (StrtabShdr == NULL) {
313     return NULL;
314   }
315 
316   assert(Sym->st_name < StrtabShdr->sh_size);
317 
318   UINT8* StrtabContents = (UINT8*)mEhdr + StrtabShdr->sh_offset;
319 
320   bool foundEnd = false;
321   UINT32 i;
322   for (i = Sym->st_name; (i < StrtabShdr->sh_size) && !foundEnd; i++) {
323     foundEnd = StrtabContents[i] == 0;
324   }
325   assert(foundEnd);
326 
327   return StrtabContents + Sym->st_name;
328 }
329 
330 //
331 // Elf functions interface implementation
332 //
333 
334 STATIC
335 VOID
ScanSections32(VOID)336 ScanSections32 (
337   VOID
338   )
339 {
340   UINT32                          i;
341   EFI_IMAGE_DOS_HEADER            *DosHdr;
342   EFI_IMAGE_OPTIONAL_HEADER_UNION *NtHdr;
343   UINT32                          CoffEntry;
344   UINT32                          SectionCount;
345   BOOLEAN                         FoundSection;
346 
347   CoffEntry = 0;
348   mCoffOffset = 0;
349 
350   //
351   // Coff file start with a DOS header.
352   //
353   mCoffOffset = sizeof(EFI_IMAGE_DOS_HEADER) + 0x40;
354   mNtHdrOffset = mCoffOffset;
355   switch (mEhdr->e_machine) {
356   case EM_386:
357   case EM_ARM:
358     mCoffOffset += sizeof (EFI_IMAGE_NT_HEADERS32);
359   break;
360   default:
361     VerboseMsg ("%s unknown e_machine type. Assume IA-32", (UINTN)mEhdr->e_machine);
362     mCoffOffset += sizeof (EFI_IMAGE_NT_HEADERS32);
363   break;
364   }
365 
366   mTableOffset = mCoffOffset;
367   mCoffOffset += mCoffNbrSections * sizeof(EFI_IMAGE_SECTION_HEADER);
368 
369   //
370   // Set mCoffAlignment to the maximum alignment of the input sections
371   // we care about
372   //
373   for (i = 0; i < mEhdr->e_shnum; i++) {
374     Elf_Shdr *shdr = GetShdrByIndex(i);
375     if (shdr->sh_addralign <= mCoffAlignment) {
376       continue;
377     }
378     if (IsTextShdr(shdr) || IsDataShdr(shdr) || IsHiiRsrcShdr(shdr)) {
379       mCoffAlignment = (UINT32)shdr->sh_addralign;
380     }
381   }
382 
383   //
384   // Move the PE/COFF header right before the first section. This will help us
385   // save space when converting to TE.
386   //
387   if (mCoffAlignment > mCoffOffset) {
388     mNtHdrOffset += mCoffAlignment - mCoffOffset;
389     mTableOffset += mCoffAlignment - mCoffOffset;
390     mCoffOffset = mCoffAlignment;
391   }
392 
393   //
394   // First text sections.
395   //
396   mCoffOffset = CoffAlign(mCoffOffset);
397   mTextOffset = mCoffOffset;
398   FoundSection = FALSE;
399   SectionCount = 0;
400   for (i = 0; i < mEhdr->e_shnum; i++) {
401     Elf_Shdr *shdr = GetShdrByIndex(i);
402     if (IsTextShdr(shdr)) {
403       if ((shdr->sh_addralign != 0) && (shdr->sh_addralign != 1)) {
404         // the alignment field is valid
405         if ((shdr->sh_addr & (shdr->sh_addralign - 1)) == 0) {
406           // if the section address is aligned we must align PE/COFF
407           mCoffOffset = (mCoffOffset + shdr->sh_addralign - 1) & ~(shdr->sh_addralign - 1);
408         } else {
409           Error (NULL, 0, 3000, "Invalid", "Section address not aligned to its own alignment.");
410         }
411       }
412 
413       /* Relocate entry.  */
414       if ((mEhdr->e_entry >= shdr->sh_addr) &&
415           (mEhdr->e_entry < shdr->sh_addr + shdr->sh_size)) {
416         CoffEntry = mCoffOffset + mEhdr->e_entry - shdr->sh_addr;
417       }
418 
419       //
420       // Set mTextOffset with the offset of the first '.text' section
421       //
422       if (!FoundSection) {
423         mTextOffset = mCoffOffset;
424         FoundSection = TRUE;
425       }
426 
427       mCoffSectionsOffset[i] = mCoffOffset;
428       mCoffOffset += shdr->sh_size;
429       SectionCount ++;
430     }
431   }
432 
433   if (!FoundSection) {
434     Error (NULL, 0, 3000, "Invalid", "Did not find any '.text' section.");
435     assert (FALSE);
436   }
437 
438   mDebugOffset = DebugRvaAlign(mCoffOffset);
439   mCoffOffset = CoffAlign(mCoffOffset);
440 
441   if (SectionCount > 1 && mOutImageType == FW_EFI_IMAGE) {
442     Warning (NULL, 0, 0, NULL, "Mulitple sections in %s are merged into 1 text section. Source level debug might not work correctly.", mInImageName);
443   }
444 
445   //
446   //  Then data sections.
447   //
448   mDataOffset = mCoffOffset;
449   FoundSection = FALSE;
450   SectionCount = 0;
451   for (i = 0; i < mEhdr->e_shnum; i++) {
452     Elf_Shdr *shdr = GetShdrByIndex(i);
453     if (IsDataShdr(shdr)) {
454       if ((shdr->sh_addralign != 0) && (shdr->sh_addralign != 1)) {
455         // the alignment field is valid
456         if ((shdr->sh_addr & (shdr->sh_addralign - 1)) == 0) {
457           // if the section address is aligned we must align PE/COFF
458           mCoffOffset = (mCoffOffset + shdr->sh_addralign - 1) & ~(shdr->sh_addralign - 1);
459         } else {
460           Error (NULL, 0, 3000, "Invalid", "Section address not aligned to its own alignment.");
461         }
462       }
463 
464       //
465       // Set mDataOffset with the offset of the first '.data' section
466       //
467       if (!FoundSection) {
468         mDataOffset = mCoffOffset;
469         FoundSection = TRUE;
470       }
471 
472       mCoffSectionsOffset[i] = mCoffOffset;
473       mCoffOffset += shdr->sh_size;
474       SectionCount ++;
475     }
476   }
477 
478   if (SectionCount > 1 && mOutImageType == FW_EFI_IMAGE) {
479     Warning (NULL, 0, 0, NULL, "Mulitple sections in %s are merged into 1 data section. Source level debug might not work correctly.", mInImageName);
480   }
481 
482   //
483   // Make room for .debug data in .data (or .text if .data is empty) instead of
484   // putting it in a section of its own. This is explicitly allowed by the
485   // PE/COFF spec, and prevents bloat in the binary when using large values for
486   // section alignment.
487   //
488   if (SectionCount > 0) {
489     mDebugOffset = DebugRvaAlign(mCoffOffset);
490   }
491   mCoffOffset = mDebugOffset + sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY) +
492                 sizeof(EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY) +
493                 strlen(mInImageName) + 1;
494 
495   mCoffOffset = CoffAlign(mCoffOffset);
496   if (SectionCount == 0) {
497     mDataOffset = mCoffOffset;
498   }
499 
500   //
501   //  The HII resource sections.
502   //
503   mHiiRsrcOffset = mCoffOffset;
504   for (i = 0; i < mEhdr->e_shnum; i++) {
505     Elf_Shdr *shdr = GetShdrByIndex(i);
506     if (IsHiiRsrcShdr(shdr)) {
507       if ((shdr->sh_addralign != 0) && (shdr->sh_addralign != 1)) {
508         // the alignment field is valid
509         if ((shdr->sh_addr & (shdr->sh_addralign - 1)) == 0) {
510           // if the section address is aligned we must align PE/COFF
511           mCoffOffset = (mCoffOffset + shdr->sh_addralign - 1) & ~(shdr->sh_addralign - 1);
512         } else {
513           Error (NULL, 0, 3000, "Invalid", "Section address not aligned to its own alignment.");
514         }
515       }
516       if (shdr->sh_size != 0) {
517         mHiiRsrcOffset = mCoffOffset;
518         mCoffSectionsOffset[i] = mCoffOffset;
519         mCoffOffset += shdr->sh_size;
520         mCoffOffset = CoffAlign(mCoffOffset);
521         SetHiiResourceHeader ((UINT8*) mEhdr + shdr->sh_offset, mHiiRsrcOffset);
522       }
523       break;
524     }
525   }
526 
527   mRelocOffset = mCoffOffset;
528 
529   //
530   // Allocate base Coff file.  Will be expanded later for relocations.
531   //
532   mCoffFile = (UINT8 *)malloc(mCoffOffset);
533   if (mCoffFile == NULL) {
534     Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");
535   }
536   assert (mCoffFile != NULL);
537   memset(mCoffFile, 0, mCoffOffset);
538 
539   //
540   // Fill headers.
541   //
542   DosHdr = (EFI_IMAGE_DOS_HEADER *)mCoffFile;
543   DosHdr->e_magic = EFI_IMAGE_DOS_SIGNATURE;
544   DosHdr->e_lfanew = mNtHdrOffset;
545 
546   NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION*)(mCoffFile + mNtHdrOffset);
547 
548   NtHdr->Pe32.Signature = EFI_IMAGE_NT_SIGNATURE;
549 
550   switch (mEhdr->e_machine) {
551   case EM_386:
552     NtHdr->Pe32.FileHeader.Machine = EFI_IMAGE_MACHINE_IA32;
553     NtHdr->Pe32.OptionalHeader.Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC;
554     break;
555   case EM_ARM:
556     NtHdr->Pe32.FileHeader.Machine = EFI_IMAGE_MACHINE_ARMT;
557     NtHdr->Pe32.OptionalHeader.Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC;
558     break;
559   default:
560     VerboseMsg ("%s unknown e_machine type %hu. Assume IA-32", mInImageName, mEhdr->e_machine);
561     NtHdr->Pe32.FileHeader.Machine = EFI_IMAGE_MACHINE_IA32;
562     NtHdr->Pe32.OptionalHeader.Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC;
563   }
564 
565   NtHdr->Pe32.FileHeader.NumberOfSections = mCoffNbrSections;
566   NtHdr->Pe32.FileHeader.TimeDateStamp = (UINT32) time(NULL);
567   mImageTimeStamp = NtHdr->Pe32.FileHeader.TimeDateStamp;
568   NtHdr->Pe32.FileHeader.PointerToSymbolTable = 0;
569   NtHdr->Pe32.FileHeader.NumberOfSymbols = 0;
570   NtHdr->Pe32.FileHeader.SizeOfOptionalHeader = sizeof(NtHdr->Pe32.OptionalHeader);
571   NtHdr->Pe32.FileHeader.Characteristics = EFI_IMAGE_FILE_EXECUTABLE_IMAGE
572     | EFI_IMAGE_FILE_LINE_NUMS_STRIPPED
573     | EFI_IMAGE_FILE_LOCAL_SYMS_STRIPPED
574     | EFI_IMAGE_FILE_32BIT_MACHINE;
575 
576   NtHdr->Pe32.OptionalHeader.SizeOfCode = mDataOffset - mTextOffset;
577   NtHdr->Pe32.OptionalHeader.SizeOfInitializedData = mRelocOffset - mDataOffset;
578   NtHdr->Pe32.OptionalHeader.SizeOfUninitializedData = 0;
579   NtHdr->Pe32.OptionalHeader.AddressOfEntryPoint = CoffEntry;
580 
581   NtHdr->Pe32.OptionalHeader.BaseOfCode = mTextOffset;
582 
583   NtHdr->Pe32.OptionalHeader.BaseOfData = mDataOffset;
584   NtHdr->Pe32.OptionalHeader.ImageBase = 0;
585   NtHdr->Pe32.OptionalHeader.SectionAlignment = mCoffAlignment;
586   NtHdr->Pe32.OptionalHeader.FileAlignment = mCoffAlignment;
587   NtHdr->Pe32.OptionalHeader.SizeOfImage = 0;
588 
589   NtHdr->Pe32.OptionalHeader.SizeOfHeaders = mTextOffset;
590   NtHdr->Pe32.OptionalHeader.NumberOfRvaAndSizes = EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES;
591 
592   //
593   // Section headers.
594   //
595   if ((mDataOffset - mTextOffset) > 0) {
596     CreateSectionHeader (".text", mTextOffset, mDataOffset - mTextOffset,
597             EFI_IMAGE_SCN_CNT_CODE
598             | EFI_IMAGE_SCN_MEM_EXECUTE
599             | EFI_IMAGE_SCN_MEM_READ);
600   } else {
601     // Don't make a section of size 0.
602     NtHdr->Pe32.FileHeader.NumberOfSections--;
603   }
604 
605   if ((mHiiRsrcOffset - mDataOffset) > 0) {
606     CreateSectionHeader (".data", mDataOffset, mHiiRsrcOffset - mDataOffset,
607             EFI_IMAGE_SCN_CNT_INITIALIZED_DATA
608             | EFI_IMAGE_SCN_MEM_WRITE
609             | EFI_IMAGE_SCN_MEM_READ);
610   } else {
611     // Don't make a section of size 0.
612     NtHdr->Pe32.FileHeader.NumberOfSections--;
613   }
614 
615   if ((mRelocOffset - mHiiRsrcOffset) > 0) {
616     CreateSectionHeader (".rsrc", mHiiRsrcOffset, mRelocOffset - mHiiRsrcOffset,
617             EFI_IMAGE_SCN_CNT_INITIALIZED_DATA
618             | EFI_IMAGE_SCN_MEM_READ);
619 
620     NtHdr->Pe32.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = mRelocOffset - mHiiRsrcOffset;
621     NtHdr->Pe32.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = mHiiRsrcOffset;
622   } else {
623     // Don't make a section of size 0.
624     NtHdr->Pe32.FileHeader.NumberOfSections--;
625   }
626 
627 }
628 
629 STATIC
630 BOOLEAN
WriteSections32(SECTION_FILTER_TYPES FilterType)631 WriteSections32 (
632   SECTION_FILTER_TYPES  FilterType
633   )
634 {
635   UINT32      Idx;
636   Elf_Shdr    *SecShdr;
637   UINT32      SecOffset;
638   BOOLEAN     (*Filter)(Elf_Shdr *);
639 
640   //
641   // Initialize filter pointer
642   //
643   switch (FilterType) {
644     case SECTION_TEXT:
645       Filter = IsTextShdr;
646       break;
647     case SECTION_HII:
648       Filter = IsHiiRsrcShdr;
649       break;
650     case SECTION_DATA:
651       Filter = IsDataShdr;
652       break;
653     default:
654       return FALSE;
655   }
656 
657   //
658   // First: copy sections.
659   //
660   for (Idx = 0; Idx < mEhdr->e_shnum; Idx++) {
661     Elf_Shdr *Shdr = GetShdrByIndex(Idx);
662     if ((*Filter)(Shdr)) {
663       switch (Shdr->sh_type) {
664       case SHT_PROGBITS:
665         /* Copy.  */
666         memcpy(mCoffFile + mCoffSectionsOffset[Idx],
667               (UINT8*)mEhdr + Shdr->sh_offset,
668               Shdr->sh_size);
669         break;
670 
671       case SHT_NOBITS:
672         memset(mCoffFile + mCoffSectionsOffset[Idx], 0, Shdr->sh_size);
673         break;
674 
675       default:
676         //
677         //  Ignore for unkown section type.
678         //
679         VerboseMsg ("%s unknown section type %x. We directly copy this section into Coff file", mInImageName, (unsigned)Shdr->sh_type);
680         break;
681       }
682     }
683   }
684 
685   //
686   // Second: apply relocations.
687   //
688   for (Idx = 0; Idx < mEhdr->e_shnum; Idx++) {
689     //
690     // Determine if this is a relocation section.
691     //
692     Elf_Shdr *RelShdr = GetShdrByIndex(Idx);
693     if ((RelShdr->sh_type != SHT_REL) && (RelShdr->sh_type != SHT_RELA)) {
694       continue;
695     }
696 
697     //
698     // Relocation section found.  Now extract section information that the relocations
699     // apply to in the ELF data and the new COFF data.
700     //
701     SecShdr = GetShdrByIndex(RelShdr->sh_info);
702     SecOffset = mCoffSectionsOffset[RelShdr->sh_info];
703 
704     //
705     // Only process relocations for the current filter type.
706     //
707     if (RelShdr->sh_type == SHT_REL && (*Filter)(SecShdr)) {
708       UINT32 RelOffset;
709 
710       //
711       // Determine the symbol table referenced by the relocation data.
712       //
713       Elf_Shdr *SymtabShdr = GetShdrByIndex(RelShdr->sh_link);
714       UINT8 *Symtab = (UINT8*)mEhdr + SymtabShdr->sh_offset;
715 
716       //
717       // Process all relocation entries for this section.
718       //
719       for (RelOffset = 0; RelOffset < RelShdr->sh_size; RelOffset += RelShdr->sh_entsize) {
720         //
721         // Set pointer to relocation entry
722         //
723         Elf_Rel *Rel = (Elf_Rel *)((UINT8*)mEhdr + RelShdr->sh_offset + RelOffset);
724 
725         //
726         // Set pointer to symbol table entry associated with the relocation entry.
727         //
728         Elf_Sym *Sym = (Elf_Sym *)(Symtab + ELF_R_SYM(Rel->r_info) * SymtabShdr->sh_entsize);
729 
730         Elf_Shdr *SymShdr;
731         UINT8 *Targ;
732         UINT16 Address;
733 
734         //
735         // Check section header index found in symbol table and get the section
736         // header location.
737         //
738         if (Sym->st_shndx == SHN_UNDEF
739             || Sym->st_shndx >= mEhdr->e_shnum) {
740           const UINT8 *SymName = GetSymName(Sym);
741           if (SymName == NULL) {
742             SymName = (const UINT8 *)"<unknown>";
743           }
744 
745           Error (NULL, 0, 3000, "Invalid",
746                  "%s: Bad definition for symbol '%s'@%#x or unsupported symbol type.  "
747                  "For example, absolute and undefined symbols are not supported.",
748                  mInImageName, SymName, Sym->st_value);
749 
750           exit(EXIT_FAILURE);
751         }
752         SymShdr = GetShdrByIndex(Sym->st_shndx);
753 
754         //
755         // Convert the relocation data to a pointer into the coff file.
756         //
757         // Note:
758         //   r_offset is the virtual address of the storage unit to be relocated.
759         //   sh_addr is the virtual address for the base of the section.
760         //
761         Targ = mCoffFile + SecOffset + (Rel->r_offset - SecShdr->sh_addr);
762 
763         //
764         // Determine how to handle each relocation type based on the machine type.
765         //
766         if (mEhdr->e_machine == EM_386) {
767           switch (ELF_R_TYPE(Rel->r_info)) {
768           case R_386_NONE:
769             break;
770           case R_386_32:
771             //
772             // Absolute relocation.
773             //  Converts Targ from a absolute virtual address to the absolute
774             //  COFF address.
775             //
776             *(UINT32 *)Targ = *(UINT32 *)Targ - SymShdr->sh_addr
777               + mCoffSectionsOffset[Sym->st_shndx];
778             break;
779           case R_386_PC32:
780             //
781             // Relative relocation: Symbol - Ip + Addend
782             //
783             *(UINT32 *)Targ = *(UINT32 *)Targ
784               + (mCoffSectionsOffset[Sym->st_shndx] - SymShdr->sh_addr)
785               - (SecOffset - SecShdr->sh_addr);
786             break;
787           default:
788             Error (NULL, 0, 3000, "Invalid", "%s unsupported ELF EM_386 relocation 0x%x.", mInImageName, (unsigned) ELF_R_TYPE(Rel->r_info));
789           }
790         } else if (mEhdr->e_machine == EM_ARM) {
791           switch (ELF32_R_TYPE(Rel->r_info)) {
792           case R_ARM_RBASE:
793             // No relocation - no action required
794             // break skipped
795 
796           case R_ARM_PC24:
797           case R_ARM_REL32:
798           case R_ARM_XPC25:
799           case R_ARM_THM_PC22:
800           case R_ARM_THM_JUMP19:
801           case R_ARM_CALL:
802           case R_ARM_JMP24:
803           case R_ARM_THM_JUMP24:
804           case R_ARM_PREL31:
805           case R_ARM_MOVW_PREL_NC:
806           case R_ARM_MOVT_PREL:
807           case R_ARM_THM_MOVW_PREL_NC:
808           case R_ARM_THM_MOVT_PREL:
809           case R_ARM_THM_JMP6:
810           case R_ARM_THM_ALU_PREL_11_0:
811           case R_ARM_THM_PC12:
812           case R_ARM_REL32_NOI:
813           case R_ARM_ALU_PC_G0_NC:
814           case R_ARM_ALU_PC_G0:
815           case R_ARM_ALU_PC_G1_NC:
816           case R_ARM_ALU_PC_G1:
817           case R_ARM_ALU_PC_G2:
818           case R_ARM_LDR_PC_G1:
819           case R_ARM_LDR_PC_G2:
820           case R_ARM_LDRS_PC_G0:
821           case R_ARM_LDRS_PC_G1:
822           case R_ARM_LDRS_PC_G2:
823           case R_ARM_LDC_PC_G0:
824           case R_ARM_LDC_PC_G1:
825           case R_ARM_LDC_PC_G2:
826           case R_ARM_GOT_PREL:
827           case R_ARM_THM_JUMP11:
828           case R_ARM_THM_JUMP8:
829           case R_ARM_TLS_GD32:
830           case R_ARM_TLS_LDM32:
831           case R_ARM_TLS_IE32:
832             // Thease are all PC-relative relocations and don't require modification
833             // GCC does not seem to have the concept of a application that just needs to get relocated.
834             break;
835 
836           case R_ARM_THM_MOVW_ABS_NC:
837             // MOVW is only lower 16-bits of the addres
838             Address = (UINT16)(Sym->st_value - SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx]);
839             ThumbMovtImmediatePatch ((UINT16 *)Targ, Address);
840             break;
841 
842           case R_ARM_THM_MOVT_ABS:
843             // MOVT is only upper 16-bits of the addres
844             Address = (UINT16)((Sym->st_value - SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx]) >> 16);
845             ThumbMovtImmediatePatch ((UINT16 *)Targ, Address);
846             break;
847 
848           case R_ARM_ABS32:
849           case R_ARM_RABS32:
850             //
851             // Absolute relocation.
852             //
853             *(UINT32 *)Targ = *(UINT32 *)Targ - SymShdr->sh_addr + mCoffSectionsOffset[Sym->st_shndx];
854             break;
855 
856           default:
857             Error (NULL, 0, 3000, "Invalid", "WriteSections (): %s unsupported ELF EM_ARM relocation 0x%x.", mInImageName, (unsigned) ELF32_R_TYPE(Rel->r_info));
858           }
859         }
860       }
861     }
862   }
863 
864   return TRUE;
865 }
866 
867 UINTN gMovwOffset = 0;
868 
869 STATIC
870 VOID
WriteRelocations32(VOID)871 WriteRelocations32 (
872   VOID
873   )
874 {
875   UINT32                           Index;
876   EFI_IMAGE_OPTIONAL_HEADER_UNION  *NtHdr;
877   EFI_IMAGE_DATA_DIRECTORY         *Dir;
878   BOOLEAN                          FoundRelocations;
879   Elf_Dyn                          *Dyn;
880   Elf_Rel                          *Rel;
881   UINTN                            RelElementSize;
882   UINTN                            RelSize;
883   UINTN                            RelOffset;
884   UINTN                            K;
885   Elf32_Phdr                       *DynamicSegment;
886 
887   for (Index = 0, FoundRelocations = FALSE; Index < mEhdr->e_shnum; Index++) {
888     Elf_Shdr *RelShdr = GetShdrByIndex(Index);
889     if ((RelShdr->sh_type == SHT_REL) || (RelShdr->sh_type == SHT_RELA)) {
890       Elf_Shdr *SecShdr = GetShdrByIndex (RelShdr->sh_info);
891       if (IsTextShdr(SecShdr) || IsDataShdr(SecShdr)) {
892         UINT32 RelIdx;
893 
894         FoundRelocations = TRUE;
895         for (RelIdx = 0; RelIdx < RelShdr->sh_size; RelIdx += RelShdr->sh_entsize) {
896           Rel = (Elf_Rel *)((UINT8*)mEhdr + RelShdr->sh_offset + RelIdx);
897 
898           if (mEhdr->e_machine == EM_386) {
899             switch (ELF_R_TYPE(Rel->r_info)) {
900             case R_386_NONE:
901             case R_386_PC32:
902               //
903               // No fixup entry required.
904               //
905               break;
906             case R_386_32:
907               //
908               // Creates a relative relocation entry from the absolute entry.
909               //
910               CoffAddFixup(mCoffSectionsOffset[RelShdr->sh_info]
911               + (Rel->r_offset - SecShdr->sh_addr),
912               EFI_IMAGE_REL_BASED_HIGHLOW);
913               break;
914             default:
915               Error (NULL, 0, 3000, "Invalid", "%s unsupported ELF EM_386 relocation 0x%x.", mInImageName, (unsigned) ELF_R_TYPE(Rel->r_info));
916             }
917           } else if (mEhdr->e_machine == EM_ARM) {
918             switch (ELF32_R_TYPE(Rel->r_info)) {
919             case R_ARM_RBASE:
920               // No relocation - no action required
921               // break skipped
922 
923             case R_ARM_PC24:
924             case R_ARM_REL32:
925             case R_ARM_XPC25:
926             case R_ARM_THM_PC22:
927             case R_ARM_THM_JUMP19:
928             case R_ARM_CALL:
929             case R_ARM_JMP24:
930             case R_ARM_THM_JUMP24:
931             case R_ARM_PREL31:
932             case R_ARM_MOVW_PREL_NC:
933             case R_ARM_MOVT_PREL:
934             case R_ARM_THM_MOVW_PREL_NC:
935             case R_ARM_THM_MOVT_PREL:
936             case R_ARM_THM_JMP6:
937             case R_ARM_THM_ALU_PREL_11_0:
938             case R_ARM_THM_PC12:
939             case R_ARM_REL32_NOI:
940             case R_ARM_ALU_PC_G0_NC:
941             case R_ARM_ALU_PC_G0:
942             case R_ARM_ALU_PC_G1_NC:
943             case R_ARM_ALU_PC_G1:
944             case R_ARM_ALU_PC_G2:
945             case R_ARM_LDR_PC_G1:
946             case R_ARM_LDR_PC_G2:
947             case R_ARM_LDRS_PC_G0:
948             case R_ARM_LDRS_PC_G1:
949             case R_ARM_LDRS_PC_G2:
950             case R_ARM_LDC_PC_G0:
951             case R_ARM_LDC_PC_G1:
952             case R_ARM_LDC_PC_G2:
953             case R_ARM_GOT_PREL:
954             case R_ARM_THM_JUMP11:
955             case R_ARM_THM_JUMP8:
956             case R_ARM_TLS_GD32:
957             case R_ARM_TLS_LDM32:
958             case R_ARM_TLS_IE32:
959               // Thease are all PC-relative relocations and don't require modification
960               break;
961 
962             case R_ARM_THM_MOVW_ABS_NC:
963               CoffAddFixup (
964                 mCoffSectionsOffset[RelShdr->sh_info]
965                 + (Rel->r_offset - SecShdr->sh_addr),
966                 EFI_IMAGE_REL_BASED_ARM_MOV32T
967                 );
968 
969               // PE/COFF treats MOVW/MOVT relocation as single 64-bit instruction
970               // Track this address so we can log an error for unsupported sequence of MOVW/MOVT
971               gMovwOffset = mCoffSectionsOffset[RelShdr->sh_info] + (Rel->r_offset - SecShdr->sh_addr);
972               break;
973 
974             case R_ARM_THM_MOVT_ABS:
975               if ((gMovwOffset + 4) !=  (mCoffSectionsOffset[RelShdr->sh_info] + (Rel->r_offset - SecShdr->sh_addr))) {
976                 Error (NULL, 0, 3000, "Not Supported", "PE/COFF requires MOVW+MOVT instruction sequence %x +4 != %x.", gMovwOffset, mCoffSectionsOffset[RelShdr->sh_info] + (Rel->r_offset - SecShdr->sh_addr));
977               }
978               break;
979 
980             case R_ARM_ABS32:
981             case R_ARM_RABS32:
982               CoffAddFixup (
983                 mCoffSectionsOffset[RelShdr->sh_info]
984                 + (Rel->r_offset - SecShdr->sh_addr),
985                 EFI_IMAGE_REL_BASED_HIGHLOW
986                 );
987               break;
988 
989            default:
990               Error (NULL, 0, 3000, "Invalid", "WriteRelocations(): %s unsupported ELF EM_ARM relocation 0x%x.", mInImageName, (unsigned) ELF32_R_TYPE(Rel->r_info));
991             }
992           } else {
993             Error (NULL, 0, 3000, "Not Supported", "This tool does not support relocations for ELF with e_machine %u (processor type).", (unsigned) mEhdr->e_machine);
994           }
995         }
996       }
997     }
998   }
999 
1000   if (!FoundRelocations && (mEhdr->e_machine == EM_ARM)) {
1001     /* Try again, but look for PT_DYNAMIC instead of SHT_REL */
1002 
1003     for (Index = 0; Index < mEhdr->e_phnum; Index++) {
1004       RelElementSize = 0;
1005       RelSize = 0;
1006       RelOffset = 0;
1007 
1008       DynamicSegment = GetPhdrByIndex (Index);
1009 
1010       if (DynamicSegment->p_type == PT_DYNAMIC) {
1011         Dyn = (Elf32_Dyn *) ((UINT8 *)mEhdr + DynamicSegment->p_offset);
1012 
1013         while (Dyn->d_tag != DT_NULL) {
1014           switch (Dyn->d_tag) {
1015             case  DT_REL:
1016               RelOffset = Dyn->d_un.d_val;
1017               break;
1018 
1019             case  DT_RELSZ:
1020               RelSize = Dyn->d_un.d_val;
1021               break;
1022 
1023             case  DT_RELENT:
1024               RelElementSize = Dyn->d_un.d_val;
1025               break;
1026 
1027             default:
1028               break;
1029           }
1030           Dyn++;
1031         }
1032         if (( RelOffset == 0 ) || ( RelSize == 0 ) || ( RelElementSize == 0 )) {
1033           Error (NULL, 0, 3000, "Invalid", "%s bad ARM dynamic relocations.", mInImageName);
1034         }
1035 
1036         for (Index = 0; Index < mEhdr->e_shnum; Index++) {
1037           Elf_Shdr *shdr = GetShdrByIndex(Index);
1038 
1039           //
1040           // The PT_DYNAMIC section contains DT_REL relocations whose r_offset
1041           // field is relative to the base of a segment (or the entire image),
1042           // and not to the base of an ELF input section as is the case for
1043           // SHT_REL sections. This means that we cannot fix up such relocations
1044           // unless we cross-reference ELF sections and segments, considering
1045           // that the output placement recorded in mCoffSectionsOffset[] is
1046           // section based, not segment based.
1047           //
1048           // Fortunately, there is a simple way around this: we require that the
1049           // in-memory layout of the ELF and PE/COFF versions of the binary is
1050           // identical. That way, r_offset will retain its validity as a PE/COFF
1051           // image offset, and we can record it in the COFF fixup table
1052           // unmodified.
1053           //
1054           if (shdr->sh_addr != mCoffSectionsOffset[Index]) {
1055             Error (NULL, 0, 3000,
1056               "Invalid", "%s: PT_DYNAMIC relocations require identical ELF and PE/COFF section offsets.",
1057               mInImageName);
1058           }
1059         }
1060 
1061         for (K = 0; K < RelSize; K += RelElementSize) {
1062 
1063           if (DynamicSegment->p_paddr == 0) {
1064             // Older versions of the ARM ELF (SWS ESPC 0003 B-02) specification define DT_REL
1065             // as an offset in the dynamic segment. p_paddr is defined to be zero for ARM tools
1066             Rel = (Elf32_Rel *) ((UINT8 *) mEhdr + DynamicSegment->p_offset + RelOffset + K);
1067           } else {
1068             // This is how it reads in the generic ELF specification
1069             Rel = (Elf32_Rel *) ((UINT8 *) mEhdr + RelOffset + K);
1070           }
1071 
1072           switch (ELF32_R_TYPE (Rel->r_info)) {
1073           case  R_ARM_RBASE:
1074             break;
1075 
1076           case  R_ARM_RABS32:
1077             CoffAddFixup (Rel->r_offset, EFI_IMAGE_REL_BASED_HIGHLOW);
1078             break;
1079 
1080           default:
1081             Error (NULL, 0, 3000, "Invalid", "%s bad ARM dynamic relocations, unkown type %d.", mInImageName, ELF32_R_TYPE (Rel->r_info));
1082             break;
1083           }
1084         }
1085         break;
1086       }
1087     }
1088   }
1089 
1090   //
1091   // Pad by adding empty entries.
1092   //
1093   while (mCoffOffset & (mCoffAlignment - 1)) {
1094     CoffAddFixupEntry(0);
1095   }
1096 
1097   NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(mCoffFile + mNtHdrOffset);
1098   Dir = &NtHdr->Pe32.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
1099   Dir->Size = mCoffOffset - mRelocOffset;
1100   if (Dir->Size == 0) {
1101     // If no relocations, null out the directory entry and don't add the .reloc section
1102     Dir->VirtualAddress = 0;
1103     NtHdr->Pe32.FileHeader.NumberOfSections--;
1104   } else {
1105     Dir->VirtualAddress = mRelocOffset;
1106     CreateSectionHeader (".reloc", mRelocOffset, mCoffOffset - mRelocOffset,
1107             EFI_IMAGE_SCN_CNT_INITIALIZED_DATA
1108             | EFI_IMAGE_SCN_MEM_DISCARDABLE
1109             | EFI_IMAGE_SCN_MEM_READ);
1110   }
1111 
1112 }
1113 
1114 STATIC
1115 VOID
WriteDebug32(VOID)1116 WriteDebug32 (
1117   VOID
1118   )
1119 {
1120   UINT32                              Len;
1121   EFI_IMAGE_OPTIONAL_HEADER_UNION     *NtHdr;
1122   EFI_IMAGE_DATA_DIRECTORY            *DataDir;
1123   EFI_IMAGE_DEBUG_DIRECTORY_ENTRY     *Dir;
1124   EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY *Nb10;
1125 
1126   Len = strlen(mInImageName) + 1;
1127 
1128   Dir = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY*)(mCoffFile + mDebugOffset);
1129   Dir->Type = EFI_IMAGE_DEBUG_TYPE_CODEVIEW;
1130   Dir->SizeOfData = sizeof(EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY) + Len;
1131   Dir->RVA = mDebugOffset + sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);
1132   Dir->FileOffset = mDebugOffset + sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);
1133 
1134   Nb10 = (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY*)(Dir + 1);
1135   Nb10->Signature = CODEVIEW_SIGNATURE_NB10;
1136   strcpy ((char *)(Nb10 + 1), mInImageName);
1137 
1138 
1139   NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(mCoffFile + mNtHdrOffset);
1140   DataDir = &NtHdr->Pe32.OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG];
1141   DataDir->VirtualAddress = mDebugOffset;
1142   DataDir->Size = Dir->SizeOfData + sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);
1143 }
1144 
1145 STATIC
1146 VOID
SetImageSize32(VOID)1147 SetImageSize32 (
1148   VOID
1149   )
1150 {
1151   EFI_IMAGE_OPTIONAL_HEADER_UNION *NtHdr;
1152 
1153   //
1154   // Set image size
1155   //
1156   NtHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(mCoffFile + mNtHdrOffset);
1157   NtHdr->Pe32.OptionalHeader.SizeOfImage = mCoffOffset;
1158 }
1159 
1160 STATIC
1161 VOID
CleanUp32(VOID)1162 CleanUp32 (
1163   VOID
1164   )
1165 {
1166   if (mCoffSectionsOffset != NULL) {
1167     free (mCoffSectionsOffset);
1168   }
1169 }
1170 
1171 
1172