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 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* 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* 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 223 CoffAlign ( 224 UINT32 Offset 225 ) 226 { 227 return (Offset + mCoffAlignment - 1) & ~(mCoffAlignment - 1); 228 } 229 230 STATIC 231 UINT32 232 DebugRvaAlign ( 233 UINT32 Offset 234 ) 235 { 236 return (Offset + 3) & ~3; 237 } 238 239 // 240 // filter functions 241 // 242 STATIC 243 BOOLEAN 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 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 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 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 * 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 * 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 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 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 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 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 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 1162 CleanUp32 ( 1163 VOID 1164 ) 1165 { 1166 if (mCoffSectionsOffset != NULL) { 1167 free (mCoffSectionsOffset); 1168 } 1169 } 1170 1171 1172