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