/**************************** cof2elf.cpp ******************************** * Author: Agner Fog * Date created: 2006-07-20 * Last modified: 2008-05-22 * Project: objconv * Module: cof2elf.cpp * Description: * Module for converting PE/COFF file to ELF file * * Copyright 2006-2008 GNU General Public License http://www.gnu.org/licenses *****************************************************************************/ #include "stdafx.h" template CCOF2ELF::CCOF2ELF () { // Constructor memset(this, 0, sizeof(*this)); } template void CCOF2ELF::Convert() { // Do the conversion NumSectionsNew = 5; // Number of sections generated so far // Allocate variable size buffers MaxSectionsNew = NumSectionsNew + 2 * NSections; // Max number of sections needed NewSections.SetNum(MaxSectionsNew); // Allocate buffers for each section NewSections.SetZero(); // Initialize NewSectionHeaders.SetNum(MaxSectionsNew); // Allocate array for temporary section headers NewSectionHeaders.SetZero(); // Initialize NewSectIndex.SetNum(NSections); // Array for translating old section index (0-based) to new section index NewSectIndex.SetZero(); // Initialize NewSymbolIndex.SetNum(NumberOfSymbols); // Array of new symbol indices NewSymbolIndex.SetZero(); // Initialize // Call the subfunctions ToFile.SetFileType(FILETYPE_ELF); // Set type of to file MakeSegments(); // Make segment headers and code/data segments MakeSymbolTable(); // Symbol table and string tables MakeRelocationTables(); // Relocation tables MakeBinaryFile(); // Putting sections together *this << ToFile; // Take over new file buffer } template void CCOF2ELF::MakeSegments() { // Convert subfunction: Make segment headers and code/data segments TELF_SectionHeader NewSecHeader; // New section header int oldsec; // Section index in old file int newsec; // Section index in new file uint32 SecNameIndex; // Section name index into shstrtab char const * SecName; // Name of new section const int WordSize = sizeof(NewFileHeader.e_entry) * 8; // word size 32 or 64 bits // Special segment names static const char * SpecialSegmentNames[] = { "Null", ".symtab", ".shstrtab", ".strtab", ".stabstr" }; // Indexes to these are: symtab = 1; // Symbol table section number shstrtab = 2; // Section name string table section number strtab = 3; // Object name string table section number stabstr = 4; // Debug string table section number // Number of special segments = number of names in SpecialSegmentNames: const int NumSpecialSegments = sizeof(SpecialSegmentNames)/sizeof(SpecialSegmentNames[0]); // Make first section header string table entry empty NewSections[shstrtab].PushString(""); // Loop through special sections, except the first Null section: for (newsec = 0; newsec < NumSpecialSegments; newsec++) { // Put data into new section header: // Initialize to zero memset(&NewSecHeader, 0, sizeof(NewSecHeader)); if (newsec > 0) { // Put name into section header string table SecName = SpecialSegmentNames[newsec]; SecNameIndex = NewSections[shstrtab].PushString(SecName); // Put name into new section header NewSecHeader.sh_name = SecNameIndex; } // Put section header into temporary buffer NewSectionHeaders[newsec] = NewSecHeader; } // Put type, flags, etc. into special segments: NewSectionHeaders[symtab] .sh_type = SHT_SYMTAB; NewSectionHeaders[symtab] .sh_entsize = sizeof(TELF_Symbol); NewSectionHeaders[symtab] .sh_link = strtab; NewSectionHeaders[shstrtab].sh_type = SHT_STRTAB; NewSectionHeaders[shstrtab].sh_flags = SHF_STRINGS; NewSectionHeaders[shstrtab].sh_addralign = 1; NewSectionHeaders[strtab] .sh_type = SHT_STRTAB; NewSectionHeaders[strtab] .sh_flags = SHF_STRINGS; NewSectionHeaders[strtab] .sh_addralign = 1; NewSectionHeaders[stabstr] .sh_type = SHT_STRTAB; NewSectionHeaders[stabstr] .sh_flags = SHF_STRINGS; NewSectionHeaders[stabstr] .sh_addralign = 1; if (newsec != NumSectionsNew) { // Check my program for internal consistency // If you get this error then change the value of NumSectionsNew in // the constructor CCOF2ELF::CCOF2ELF to equal the number of entries in // SpecialSegmentNames, including the Null segment err.submit(9000); } // Loop through source file sections for (oldsec = 0; oldsec < this->NSections; oldsec++) { // Pointer to old section header SCOFF_SectionHeader * SectionHeader = &this->SectionHeaders[oldsec]; // Get section name SecName = this->GetSectionName(SectionHeader->Name); if (strnicmp(SecName,"debug",5) == 0 || strnicmp(SecName+1,"debug",5) == 0) { // This is a debug section if (cmd.DebugInfo == CMDL_DEBUG_STRIP) { // Remove debug info NewSectIndex[oldsec] = COFF_SECTION_REMOVE_ME; // Remember that this section is removed cmd.CountDebugRemoved(); continue; } else if (cmd.InputType != cmd.OutputType) { err.submit(1029); // Warn that debug information is incompatible } } if (strnicmp(SecName,".drectve",8) == 0 || (SectionHeader->Flags & (PE_SCN_LNK_INFO | PE_SCN_LNK_REMOVE))) { // This is a directive section if (cmd.ExeptionInfo) { // Remove directive section NewSectIndex[oldsec] = COFF_SECTION_REMOVE_ME; // Remember that this section is removed cmd.CountExceptionRemoved(); continue; } } if (strnicmp(SecName,".pdata", 6) == 0) { // This section has exception information if (cmd.ExeptionInfo == CMDL_EXCEPTION_STRIP) { // Remove exception info NewSectIndex[oldsec] = COFF_SECTION_REMOVE_ME; // Remember that this section is removed cmd.CountExceptionRemoved(); continue; } else if (cmd.InputType != cmd.OutputType) { err.submit(1030); // Warn that exception information is incompatible } } if (strnicmp(SecName,".cormeta", 8) == 0) { // This is a .NET Common Language Runtime section err.submit(2014); } if (strnicmp(SecName,".rsrc", 5) == 0) { // This section has Windows resource information err.submit(1031); } // Store section index in index translation table (zero-based index) NewSectIndex[oldsec] = newsec; // Store section data if (SectionHeader->SizeOfRawData > 0) { NewSections[newsec].Push(Buf()+SectionHeader->PRawData, SectionHeader->SizeOfRawData); } // Put data into new section header: // Initialize to zero memset(&NewSecHeader, 0, sizeof(NewSecHeader)); // Section type if (!(SectionHeader->Flags & PE_SCN_LNK_REMOVE)) { NewSecHeader.sh_type = SHT_PROGBITS; // Program code or data NewSecHeader.sh_flags |= SHF_ALLOC; // Occupies memory during execution } if (SectionHeader->Flags & PE_SCN_CNT_UNINIT_DATA) { NewSecHeader.sh_type = SHT_NOBITS; // BSS } // Section flags if (SectionHeader->Flags & PE_SCN_MEM_WRITE) { NewSecHeader.sh_flags |= SHF_WRITE; } if (SectionHeader->Flags & PE_SCN_MEM_EXECUTE) { NewSecHeader.sh_flags |= SHF_EXECINSTR; } // Check for special sections if (strcmp(SecName, COFF_CONSTRUCTOR_NAME)==0) { // Constructors segment SecName = ELF_CONSTRUCTOR_NAME; NewSecHeader.sh_flags = SHF_WRITE | SHF_ALLOC; } // Put name into section header string table SecNameIndex = NewSections[shstrtab].PushString(SecName); // Put name into new section header NewSecHeader.sh_name = SecNameIndex; // Section virtual memory address NewSecHeader.sh_addr = SectionHeader->VirtualAddress; // Section size in memory NewSecHeader.sh_size = SectionHeader->VirtualSize; // Section alignment if (SectionHeader->Flags & PE_SCN_ALIGN_MASK) { NewSecHeader.sh_addralign = uint32(1 << (((SectionHeader->Flags & PE_SCN_ALIGN_MASK) / PE_SCN_ALIGN_1) - 1)); } // Put section header into temporary buffer NewSectionHeaders[newsec] = NewSecHeader; // Increment section number newsec++; if (SectionHeader->NRelocations > 0) { // Source section has relocations. // Make a relocation section in destination file // Put data into relocation section header: // Initialize to zero memset(&NewSecHeader, 0, sizeof(NewSecHeader)); // Name for relocation section = ".rel" or ".rela" + name of section const int MAXSECTIONNAMELENGTH = 256; char RelocationSectionName[MAXSECTIONNAMELENGTH] = ".rel"; if (WordSize == 64) strcat(RelocationSectionName, "a"); // 32-bit: .rel, 64-bit: .rela strncat(RelocationSectionName, SecName, MAXSECTIONNAMELENGTH-5); RelocationSectionName[MAXSECTIONNAMELENGTH-1] = 0; // Put name into section header string table uint32 SecNameIndex = NewSections[shstrtab].PushString(RelocationSectionName); // Put name into new section header NewSecHeader.sh_name = SecNameIndex; // Section type NewSecHeader.sh_type = (WordSize == 32) ? SHT_REL : SHT_RELA; // Relocation section // Put section header into temporary buffer NewSectionHeaders[newsec] = NewSecHeader; // Increment section number newsec++; } } // Number of sections generated NumSectionsNew = newsec; } template void CCOF2ELF::MakeSymbolTable() { // Convert subfunction: Make symbol table and string tables int isym; // current symbol table entry int numaux; // Number of auxiliary entries in source record int OldSectionIndex; // Index into old section table. 1-based int NewSectionIndex; // Index into new section table. 0-based //const int WordSize = sizeof(NewFileHeader.e_entry) * 8; // word size 32 or 64 bits TELF_Symbol sym; // Temporary symbol table record const char * name1; // Name of section or main record // Pointer to old symbol table union { SCOFF_SymTableEntry * p; // Symtab entry pointer int8 * b; // Used for increment } OldSymtab; // Make the first record empty NewSections[symtab].Push(0, sizeof(TELF_Symbol)); // Make first string table entries empty NewSections[strtab] .PushString(""); NewSections[stabstr].PushString(""); // Loop twice through source symbol table to get local symbols first, global symbols last // Loop 1: Look for local symbols only OldSymtab.p = SymbolTable; // Pointer to source symbol table for (isym = 0; isym < this->NumberOfSymbols; isym += numaux+1, OldSymtab.b += SIZE_SCOFF_SymTableEntry*(numaux+1)) { if (OldSymtab.b >= Buf() + DataSize) { err.submit(2040); break; } // Number of auxiliary records belonging to same symbol numaux = OldSymtab.p->s.NumAuxSymbols; if (numaux < 0) numaux = 0; if (OldSymtab.p->s.StorageClass != COFF_CLASS_EXTERNAL && OldSymtab.p->s.StorageClass != COFF_CLASS_WEAK_EXTERNAL) { // Symbol is local // Reset destination entry memset(&sym, 0, sizeof(sym)); // Binding sym.st_bind = STB_LOCAL; // Get first aux record if numaux > 0 //SCOFF_SymTableEntryAux * sa = (SCOFF_SymTableEntryAux *)(OldSymtab.b + SIZE_SCOFF_SymTableEntry); // Symbol name name1 = this->GetSymbolName(OldSymtab.p->s.Name); // Symbol value sym.st_value = OldSymtab.p->s.Value; // Get section OldSectionIndex = OldSymtab.p->s.SectionNumber; // 1-based index into old section table NewSectionIndex = 0; // 0-based index into old section table if (OldSectionIndex > 0 && OldSectionIndex <= this->NSections) { // Subtract 1 from OldSectionIndex because NewSectIndex[] is zero-based while OldSectionIndex is 1-based // Get new section index from translation table NewSectionIndex = NewSectIndex[OldSectionIndex-1]; } if (NewSectionIndex == COFF_SECTION_REMOVE_ME) { continue; // Section has been removed. Remove symbol too } sym.st_shndx = (uint16)NewSectionIndex; // Check symbol type if (OldSymtab.p->s.StorageClass == COFF_CLASS_FILE) { // This is a filename record if (numaux > 0 && numaux < 20) { // Get filename from subsequent Aux records. // Remove path from filename because the path makes no sense on a different platform. const char * filename = GetShortFileName(OldSymtab.p); // Put file name into string table and debug string table sym.st_name = NewSections[strtab].PushString(filename); NewSections[stabstr].PushString(filename); } // Attributes for filename record sym.st_shndx = (uint16)SHN_ABS; sym.st_type = STT_FILE; sym.st_bind = STB_LOCAL; sym.st_value = 0; } else if (numaux && OldSymtab.p->s.StorageClass == COFF_CLASS_STATIC && OldSymtab.p->s.Value == 0 && OldSymtab.p->s.Type != 0x20) { // This is a section definition record sym.st_name = 0; name1 = 0; sym.st_type = STT_SECTION; sym.st_bind = STB_LOCAL; sym.st_value = 0; // aux record contains length and number of relocations. Ignore aux record } else if (OldSymtab.p->s.SectionNumber < 0) { // This is an absolute or debug symbol sym.st_type = STT_NOTYPE; sym.st_shndx = (uint16)SHN_ABS; } else if (OldSymtab.p->s.Type == 0 && OldSymtab.p->s.StorageClass == COFF_CLASS_FUNCTION) { // This is a .bf, .lf, or .ef record following a function record // Contains line number information etc. Ignore this record continue; } else if (OldSymtab.p->s.SectionNumber <= 0) { // Unknown sym.st_type = STT_NOTYPE; } else { // This is a local data definition record sym.st_type = STT_OBJECT; // The size is not specified in COFF record, // so we may give it an arbitrary size: // sym.size = 4; } // Put symbol name into string table if we have not already done so if (sym.st_name == 0 && name1) { sym.st_name = NewSections[strtab].PushString(name1); } // Put record into new symbol table NewSections[symtab].Push(&sym, sizeof(sym)); // Insert into symbol translation table NewSymbolIndex[isym] = NewSections[symtab].GetLastIndex(); } // End if not external } // End loop 1 // Finished with local symbols // Make index to first global symbol NewSectionHeaders[symtab].sh_info = NewSections[symtab].GetLastIndex() + 1; // Loop 2: Look for global symbols only OldSymtab.p = SymbolTable; // Pointer to source symbol table for (isym = 0; isym < NumberOfSymbols; isym += numaux+1, OldSymtab.b += SIZE_SCOFF_SymTableEntry*(numaux+1)) { // Number of auxiliary records belonging to same symbol numaux = OldSymtab.p->s.NumAuxSymbols; if (numaux < 0) numaux = 0; if (OldSymtab.p->s.StorageClass == COFF_CLASS_EXTERNAL || OldSymtab.p->s.StorageClass == COFF_CLASS_WEAK_EXTERNAL) { // Symbol is global (public or external) // Reset destination entry memset(&sym, 0, sizeof(sym)); // Binding sym.st_bind = STB_GLOBAL; if (OldSymtab.p->s.StorageClass == COFF_CLASS_WEAK_EXTERNAL) sym.st_bind = STB_WEAK; // Get first aux record if numaux > 0 SCOFF_SymTableEntry * sa = (SCOFF_SymTableEntry*)(OldSymtab.b + SIZE_SCOFF_SymTableEntry); // Symbol name name1 = GetSymbolName(OldSymtab.p->s.Name); // Symbol value sym.st_value = OldSymtab.p->s.Value; // Get section OldSectionIndex = OldSymtab.p->s.SectionNumber; // 1-based index into old section table NewSectionIndex = 0; // 0-based index into old section table if (OldSectionIndex > 0 && OldSectionIndex <= NSections) { // Subtract 1 from OldSectionIndex because NewSectIndex[] is zero-based while OldSectionIndex is 1-based // Get new section index from translation table NewSectionIndex = NewSectIndex[OldSectionIndex-1]; } if (NewSectionIndex == COFF_SECTION_REMOVE_ME) { continue; // Section has been removed. Remove symbol too } if ((int16)OldSectionIndex == COFF_SECTION_ABSOLUTE) { NewSectionIndex = SHN_ABS; } sym.st_shndx = (uint16)NewSectionIndex; // Check symbol type if (OldSymtab.p->s.SectionNumber < 0) { // This is an absolute or debug symbol sym.st_type = STT_NOTYPE; } else if (OldSymtab.p->s.Type == COFF_TYPE_FUNCTION && OldSymtab.p->s.SectionNumber > 0) { // This is a function definition record sym.st_type = STT_FUNC; if (numaux) { // Get size from aux record sym.st_size = sa->func.TotalSize; } if (sym.st_size == 0) { // The size is not specified in the COFF file. // We may give it an arbitrary size: // sym.size = 1; } } else if (OldSymtab.p->s.SectionNumber <= 0) { // This is an external symbol sym.st_type = STT_NOTYPE; } else { // This is a data definition record sym.st_type = STT_OBJECT; // Symbol must have a size. The size is not specified in COFF record, // so we just give it an arbitrary size sym.st_size = 4; } // Put symbol name into string table if we have not already done so if (sym.st_name == 0 && name1) { sym.st_name = NewSections[strtab].PushString(name1); } // Put record into new symbol table NewSections[symtab].Push(&sym, sizeof(sym)); // Insert into symbol translation table NewSymbolIndex[isym] = NewSections[symtab].GetLastIndex(); } // End if external } // End loop 2 } template void CCOF2ELF::MakeRelocationTables() { // Convert subfunction: Relocation tables int32 oldsec; // Relocated section number in source file int32 newsec; // Relocated section number in destination file int32 newsecr; // Relocation table section number in destination file TELF_SectionHeader * NewRelTableSecHeader; // Section header for new relocation table char TempText[32]; // Temporary text buffer const int WordSize = sizeof(NewFileHeader.e_entry) * 8; // word size 32 or 64 bits // Loop through source file sections for (oldsec = 0; oldsec < NSections; oldsec++) { // New section index newsec = NewSectIndex[oldsec]; if (newsec == COFF_SECTION_REMOVE_ME) { continue; // This is a debug or exception handler section which has been removed } // Pointer to old section header SCOFF_SectionHeader * SectionHeader = &this->SectionHeaders[oldsec]; if (SectionHeader->NRelocations > 0) { // This section has relocations // Finc new relocation table section newsecr = newsec + 1; // Check that we have allocated a relocation section if (oldsec+1 < this->NSections && NewSectIndex[oldsec+1] == newsecr) err.submit(9000); if (newsecr >= NumSectionsNew) err.submit(9000); // New relocation table section header NewRelTableSecHeader = &NewSectionHeaders[newsecr]; // Insert header info NewRelTableSecHeader->sh_type = (WordSize == 32) ? SHT_REL : SHT_RELA; NewRelTableSecHeader->sh_flags = 0; NewRelTableSecHeader->sh_addralign = WordSize / 8; // Alignment NewRelTableSecHeader->sh_link = symtab; // Point to symbol table NewRelTableSecHeader->sh_info = newsec; // Point to relocated section // Entry size: NewRelTableSecHeader->sh_entsize = (WordSize == 32) ? sizeof(Elf32_Rel) : sizeof(Elf64_Rela); // Pointer to old relocation entry union { SCOFF_Relocation * p; // pointer to record int8 * b; // used for address calculation and incrementing } OldReloc; // Loop through relocations OldReloc.b = Buf() + SectionHeader->PRelocations; for (int i = 0; i < SectionHeader->NRelocations; i++, OldReloc.b += SIZE_SCOFF_Relocation) { // Make new relocation entry and set to zero TELF_Relocation NewRelocEntry; memset(&NewRelocEntry, 0, sizeof(NewRelocEntry)); // Section offset of relocated address NewRelocEntry.r_offset = OldReloc.p->VirtualAddress; // Target symbol uint32 TargetSymbol = OldReloc.p->SymbolTableIndex; if (TargetSymbol >= (uint32)NumberOfSymbols) { err.submit(2031); // Symbol not in table } else { // Translate symbol number NewRelocEntry.r_sym = NewSymbolIndex[TargetSymbol]; } if (WordSize == 32) { // Interpret 32-bit COFF relocation types switch (OldReloc.p->Type) { case COFF32_RELOC_ABS: // Ignored NewRelocEntry.r_type = R_386_NONE; break; case COFF32_RELOC_TOKEN: // .NET common language runtime token err.submit(2014); // Error message // Continue in next case and insert absolute address as token: case COFF32_RELOC_DIR32: // 32-bit absolute virtual address NewRelocEntry.r_type = R_386_32; break; case COFF32_RELOC_IMGREL: // 32-bit image relative address // Image-relative relocation not supported in ELF if (cmd.OutputType == FILETYPE_MACHO_LE) { // Intermediate during conversion to MachO NewRelocEntry.r_type = R_UNSUPPORTED_IMAGEREL; break; } // Work-around unsupported image-relative relocation // Convert to absolute NewRelocEntry.r_type = R_386_32; // Absolute relocation if (cmd.ImageBase == 0) { // Default image base for 32-bit Linux cmd.ImageBase = 0x8048000; // 0x400000 ? } NewRelocEntry.r_addend -= cmd.ImageBase; // Warn that image base must be set to the specified value sprintf(TempText, "%X", cmd.ImageBase); // write value as hexadecimal err.submit(1301, TempText); err.ClearError(1301); break; case COFF32_RELOC_REL32: // 32-bit self-relative NewRelocEntry.r_type = R_386_PC32; // Difference between EIP-relative and self-relative relocation = size of address field NewRelocEntry.r_addend = -4; break; /* !! error if self-relative relocation with offset !! test data that fails = testpic32.obj */ case COFF32_RELOC_SECTION: // 16-bit section index in file case COFF32_RELOC_SECREL: // 32-bit section-relative case COFF32_RELOC_SECREL7: // 8-bit section-relative // These fixup types are not supported in ELF files if (cmd.DebugInfo != CMDL_DEBUG_STRIP) { // Issue warning. Ignore if stripping debug info err.submit(1010); } break; default: err.submit(2030, OldReloc.p->Type); break; // Error: Unknown relocation type (%i) ignored } } else { // Interpret 64-bit COFF relocation types switch (OldReloc.p->Type) { case COFF64_RELOC_ABS: // Ignored NewRelocEntry.r_type = R_X86_64_NONE; break; case COFF64_RELOC_TOKEN: // .NET common language runtime token err.submit(2014); // Error message // Continue in next case and insert absolute address as token: case COFF64_RELOC_ABS64: // 64 bit absolute virtual address NewRelocEntry.r_type = R_X86_64_64; break; case COFF64_RELOC_PPC_TOKEN: err.submit(2014); // Error message // Continue in next case and insert absolute address as token: case COFF64_RELOC_ABS32: // 32 bit absolute address NewRelocEntry.r_type = R_X86_64_32S; break; case COFF64_RELOC_IMGREL: // 32 bit image-relative // Image-relative relocation not supported in ELF if (cmd.OutputType == FILETYPE_MACHO_LE) { // Intermediate during conversion to MachO NewRelocEntry.r_type = R_UNSUPPORTED_IMAGEREL; break; } // Work-around unsupported image-relative relocation // Convert to absolute NewRelocEntry.r_type = R_X86_64_32S; // Absolute 32-bit relocation if (cmd.ImageBase == 0) { // Default image base for 64-bit Linux cmd.ImageBase = 0x400000; } NewRelocEntry.r_addend -= cmd.ImageBase; // Warn that image base must be set to the specified value sprintf(TempText, "%X", cmd.ImageBase); // write value as hexadecimal err.submit(1301, TempText); err.ClearError(1301); break; case COFF64_RELOC_REL32: // 32 bit, RIP-relative case COFF64_RELOC_REL32_1: // 32 bit, relative to RIP - 1. For instruction with immediate byte operand case COFF64_RELOC_REL32_2: // 32 bit, relative to RIP - 2. For instruction with immediate word operand case COFF64_RELOC_REL32_3: // 32 bit, relative to RIP - 3. (useless) case COFF64_RELOC_REL32_4: // 32 bit, relative to RIP - 4. For instruction with immediate dword operand case COFF64_RELOC_REL32_5: // 32 bit, relative to RIP - 5. (useless) NewRelocEntry.r_type = R_X86_64_PC32; // Note: // The microprocessor calculates RIP-relative addresses // relative to the value of the instruction pointer AFTER // the instruction. This is equal to the address of the // relocated field plus the size of the relocated field // itself plus the size of any immediate operand coming // after the relocated field. // The COFF format makes the correction for this offset in // the linker by using a differet relocation type for // immediate operand size = 0, 1, 2 or 4. // The ELF format makes the same correction by an explicit // addend, which is -4, -5, -6 or -8, respectively. // The difference between RIP-relative and self-relative // relocation is equal to the size of the address field plus // the size of any immediate operand: NewRelocEntry.r_addend = -(4 + OldReloc.p->Type - COFF64_RELOC_REL32); break; case COFF64_RELOC_SECTION: // 16-bit section index in file case COFF64_RELOC_SECREL: // 32-bit section-relative case COFF64_RELOC_SECREL7: // 8-bit section-relative // These fixup types are not supported in ELF files if (cmd.DebugInfo != CMDL_DEBUG_STRIP) { // Issue warning. Ignore if stripping debug info err.submit(1010); } break; default: err.submit(2030, OldReloc.p->Type); break; // Error: Unknown relocation type (%i) ignored } } // Find inline addend int32 * paddend = 0; if (OldReloc.p->VirtualAddress + 4 > NewSections[newsec].GetDataSize() || NewSectionHeaders[newsec].sh_type == SHT_NOBITS) { // Address of relocation is invalid err.submit(2032); } else { // Make pointer to inline addend paddend = (int32*)(NewSections[newsec].Buf() + NewSectionHeaders[newsec].sh_offset + OldReloc.p->VirtualAddress); } // Put relocation record into table if (WordSize == 32) { if (NewRelocEntry.r_addend != 0) { // Use inline addends in 32 bit ELF (SHT_REL) // Put addend inline * paddend += uint32(NewRelocEntry.r_addend); NewRelocEntry.r_addend = 0; } // Save 32-bit relocation record Elf32_Rel, not Elf32_Rela if (NewRelocEntry.r_addend) err.submit(9000); NewSections[newsecr].Push(&NewRelocEntry, sizeof(Elf32_Rel)); } else { // 64 bit /* if (*paddend != 0) { // Use explicit addend in 64 bit ELF (SHT_RELA) // Explicit addend may cause link error if it appears to point outside section NewRelocEntry.r_addend += *paddend; *paddend = 0; }*/ // Save 64-bit relocation record. Must be Elf64_Rela NewSections[newsecr].Push(&NewRelocEntry, sizeof(Elf64_Rela)); } } } } } template void CCOF2ELF::MakeBinaryFile() { // Convert subfunction: Make section headers and file header, // and combine everything into a single memory buffer. int32 newsec; // Section index uint32 SecOffset; // Section offset in file uint32 SecSize; // Section size in file uint32 SectionHeaderOffset; // File offset to section headers // Set file type in ToFile ToFile.SetFileType(FILETYPE_ELF); // Make space for file header in ToFile, but don't fill data into it yet ToFile.Push(0, sizeof(TELF_Header)); // Loop through new section buffers for (newsec = 0; newsec < NumSectionsNew; newsec++) { // Size of section SecSize = NewSections[newsec].GetDataSize(); // Put section into ToFile SecOffset = ToFile.Push(NewSections[newsec].Buf(), SecSize); // Put size and offset into section header NewSectionHeaders[newsec].sh_offset = SecOffset; NewSectionHeaders[newsec].sh_size = SecSize; // Align before next entry ToFile.Align(16); } // Start offset of section headers SectionHeaderOffset = ToFile.GetDataSize(); // Loop through new section headers for (newsec = 0; newsec < NumSectionsNew; newsec++) { // Put section header into ToFile ToFile.Push(&NewSectionHeaders[newsec], sizeof(TELF_SectionHeader)); } // Make file header TELF_Header FileHeader; memset(&FileHeader, 0, sizeof(FileHeader)); // Initialize to 0 // Put file type magic number in strcpy((char*)(FileHeader.e_ident), ELFMAG); // File class FileHeader.e_ident[EI_CLASS] = (WordSize == 32) ? ELFCLASS32 : ELFCLASS64; // Data Endian-ness FileHeader.e_ident[EI_DATA] = ELFDATA2LSB; // ELF version FileHeader.e_ident[EI_VERSION] = EV_CURRENT; // ABI FileHeader.e_ident[EI_OSABI] = ELFOSABI_SYSV; // ABI version FileHeader.e_ident[EI_ABIVERSION] = 0; // File type FileHeader.e_type = ET_REL; // Machine architecture FileHeader.e_machine = (WordSize == 32) ? EM_386 : EM_X86_64; // Version FileHeader.e_version = EV_CURRENT; // Flags FileHeader.e_flags = 0; // Section header table offset FileHeader.e_shoff = SectionHeaderOffset; // File header size FileHeader.e_ehsize = sizeof(TELF_Header); // Section header size FileHeader.e_shentsize = sizeof(TELF_SectionHeader); // Number of section headers FileHeader.e_shnum = (uint16)NumSectionsNew; // Section header string table index FileHeader.e_shstrndx = (uint16)shstrtab; // Put file header into beginning of ToFile where we made space for it memcpy(ToFile.Buf(), &FileHeader, sizeof(FileHeader)); } // Make template instances for 32 and 64 bits template class CCOF2ELF; template class CCOF2ELF;