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