forked from KolibriOS/kolibrios
Added objconv port.
git-svn-id: svn://kolibrios.org@9683 a494cfbc-eb01-0410-851d-a64ba20cac60
This commit is contained in:
702
programs/develop/objconv/elf2cof.cpp
Normal file
702
programs/develop/objconv/elf2cof.cpp
Normal file
@@ -0,0 +1,702 @@
|
||||
/**************************** elf2cof.cpp *********************************
|
||||
* Author: Agner Fog
|
||||
* Date created: 2006-08-19
|
||||
* Last modified: 2013-11-27
|
||||
* Project: objconv
|
||||
* Module: elf2cof.cpp
|
||||
* Description:
|
||||
* Module for converting ELF file to PE/COFF file
|
||||
*
|
||||
* Copyright 2006-2013 GNU General Public License http://www.gnu.org/licenses
|
||||
*****************************************************************************/
|
||||
#include "stdafx.h"
|
||||
// All functions in this module are templated to make two versions: 32 and 64 bits.
|
||||
// See instantiations at the end of this file.
|
||||
|
||||
|
||||
// Constructor
|
||||
template <class TELF_Header, class TELF_SectionHeader, class TELF_Symbol, class TELF_Relocation>
|
||||
CELF2COF<ELFSTRUCTURES>::CELF2COF() {
|
||||
// Reset all
|
||||
memset(this, 0, sizeof(*this));
|
||||
}
|
||||
|
||||
|
||||
// Convert(): Do the conversion
|
||||
template <class TELF_Header, class TELF_SectionHeader, class TELF_Symbol, class TELF_Relocation>
|
||||
void CELF2COF<ELFSTRUCTURES>::Convert() {
|
||||
|
||||
// Some compilers require this-> for accessing members of template base class,
|
||||
// according to the so-called two-phase lookup rule.
|
||||
|
||||
// Allocate variable size buffers
|
||||
NewSectIndex.SetNum(this->NSections);// Allocate section translation table
|
||||
NewSectIndex.SetZero(); // Initialize
|
||||
|
||||
// Call the subfunctions
|
||||
ToFile.SetFileType(FILETYPE_COFF); // Set type of to file
|
||||
MakeFileHeader(); // Make file header
|
||||
MakeSectionsIndex(); // Make sections index translation table
|
||||
MakeSymbolTable(); // Make symbol table and string tables
|
||||
MakeSections(); // Make sections and relocation tables
|
||||
HideUnusedSymbols(); // Hide unused symbols
|
||||
MakeBinaryFile(); // Put sections together
|
||||
*this << ToFile; // Take over new file buffer
|
||||
}
|
||||
|
||||
|
||||
// MakeFileHeader(): Convert subfunction to make file header
|
||||
template <class TELF_Header, class TELF_SectionHeader, class TELF_Symbol, class TELF_Relocation>
|
||||
void CELF2COF<ELFSTRUCTURES>::MakeFileHeader() {
|
||||
|
||||
// Make PE file header
|
||||
NewFileHeader.Machine = (this->WordSize == 32) ? PE_MACHINE_I386 : PE_MACHINE_X8664;
|
||||
NewFileHeader.TimeDateStamp = (uint32)time(0);
|
||||
NewFileHeader.SizeOfOptionalHeader = 0;
|
||||
NewFileHeader.Flags = 0;
|
||||
|
||||
// Values inserted later:
|
||||
NewFileHeader.NumberOfSections = 0;
|
||||
NewFileHeader.PSymbolTable = 0;
|
||||
NewFileHeader.NumberOfSymbols = 0;
|
||||
|
||||
// Put file header into file
|
||||
ToFile.Push(&NewFileHeader, sizeof(NewFileHeader));
|
||||
}
|
||||
|
||||
|
||||
// MakeSectionsIndex(): Make sections index translation table
|
||||
template <class TELF_Header, class TELF_SectionHeader, class TELF_Symbol, class TELF_Relocation>
|
||||
void CELF2COF<ELFSTRUCTURES>::MakeSectionsIndex() {
|
||||
// We must make this table before the segments, because it is needed for the
|
||||
// symbol table, and we must make the symbol table before the relocation table,
|
||||
// and we must make the relocation table together with the sections.
|
||||
|
||||
uint32 oldsec; // Section number in old file
|
||||
uint32 newsec = 0; // Section number in new file
|
||||
|
||||
// Loop through old sections
|
||||
for (oldsec = 0; oldsec < this->NSections; oldsec++) {
|
||||
|
||||
// Get section name
|
||||
const char * sname = "";
|
||||
uint32 namei = this->SectionHeaders[oldsec].sh_name;
|
||||
if (namei >= this->SecStringTableLen) err.submit(2112);
|
||||
else sname = this->SecStringTable + namei;
|
||||
|
||||
if (cmd.DebugInfo == CMDL_DEBUG_STRIP) {
|
||||
// Check for debug section names
|
||||
if (strncmp(sname, ".note", 5) == 0
|
||||
|| strncmp(sname, ".comment", 8) == 0
|
||||
|| strncmp(sname, ".stab", 5) == 0
|
||||
|| strncmp(sname, ".debug", 6) == 0) {
|
||||
// Remove this section
|
||||
this->SectionHeaders[oldsec].sh_type = SHT_REMOVE_ME;
|
||||
cmd.CountDebugRemoved();
|
||||
}
|
||||
}
|
||||
|
||||
if (cmd.ExeptionInfo == CMDL_EXCEPTION_STRIP) {
|
||||
// Check for exception section name
|
||||
if (strncmp(sname, ".eh_frame", 9) == 0) {
|
||||
// Remove this section
|
||||
this->SectionHeaders[oldsec].sh_type = SHT_REMOVE_ME;
|
||||
cmd.CountExceptionRemoved();
|
||||
}
|
||||
}
|
||||
|
||||
// Search for program data sections only
|
||||
if (this->SectionHeaders[oldsec].sh_type == SHT_PROGBITS
|
||||
|| this->SectionHeaders[oldsec].sh_type == SHT_NOBITS) {
|
||||
// Section index translation table
|
||||
NewSectIndex[oldsec] = newsec++;
|
||||
}
|
||||
else {
|
||||
NewSectIndex[oldsec] = 0;
|
||||
}
|
||||
}
|
||||
// Store number of sections in new file
|
||||
NumSectionsNew = newsec;
|
||||
|
||||
// Calculate file offset of raw data
|
||||
RawDataOffset = sizeof(SCOFF_FileHeader) + NumSectionsNew * sizeof(SCOFF_SectionHeader);
|
||||
}
|
||||
|
||||
|
||||
// MakeSections(): Convert subfunction to make sections and relocation tables
|
||||
template <class TELF_Header, class TELF_SectionHeader, class TELF_Symbol, class TELF_Relocation>
|
||||
void CELF2COF<ELFSTRUCTURES>::MakeSections() {
|
||||
uint32 oldsec; // Section number in old file
|
||||
uint32 relsec; // Relocation section in old file
|
||||
SCOFF_SectionHeader NewHeader; // New section header
|
||||
TELF_SectionHeader OldHeader; // Old section header
|
||||
TELF_SectionHeader OldRelHeader; // Old relocation section header
|
||||
TELF_Relocation OldRelocation; // Old relocation table entry
|
||||
SCOFF_Relocation NewRelocation; // New relocation table entry
|
||||
|
||||
// Loop through old sections
|
||||
for (oldsec = 0; oldsec < this->NSections; oldsec++) {
|
||||
|
||||
// Copy old header for convenience
|
||||
OldHeader = this->SectionHeaders[oldsec];
|
||||
|
||||
// Search for program data sections only
|
||||
if (OldHeader.sh_type == SHT_PROGBITS || OldHeader.sh_type == SHT_NOBITS) {
|
||||
|
||||
// Reset new section header
|
||||
memset(&NewHeader, 0, sizeof(NewHeader));
|
||||
|
||||
// Section name
|
||||
const char * sname = "";
|
||||
uint32 namei = OldHeader.sh_name;
|
||||
if (namei >= this->SecStringTableLen) err.submit(2112);
|
||||
else sname = this->SecStringTable + namei;
|
||||
|
||||
// Check for special names
|
||||
if (strcmp(sname, ELF_CONSTRUCTOR_NAME)==0) {
|
||||
// This is the constructors segment
|
||||
sname = COFF_CONSTRUCTOR_NAME;
|
||||
OldHeader.sh_flags &= ~ SHF_WRITE;
|
||||
}
|
||||
|
||||
// Store name in section header
|
||||
COFF_PutNameInSectionHeader(NewHeader, sname, NewStringTable);
|
||||
|
||||
// Raw data
|
||||
NewHeader.SizeOfRawData = uint32(OldHeader.sh_size); // section size in file
|
||||
if (OldHeader.sh_size && OldHeader.sh_type != SHT_NOBITS) {
|
||||
// File to raw data for section
|
||||
NewHeader.PRawData = NewRawData.GetDataSize() + RawDataOffset;
|
||||
|
||||
// Copy raw data
|
||||
NewRawData.Push(this->Buf()+(uint32)(OldHeader.sh_offset), (uint32)(OldHeader.sh_size));
|
||||
NewRawData.Align(4);
|
||||
}
|
||||
|
||||
// Section flags
|
||||
NewHeader.Flags = PE_SCN_MEM_READ;
|
||||
if (OldHeader.sh_flags & SHF_WRITE) NewHeader.Flags |= PE_SCN_MEM_WRITE;
|
||||
if (OldHeader.sh_flags & SHF_EXECINSTR) {
|
||||
NewHeader.Flags |= PE_SCN_MEM_EXECUTE | PE_SCN_CNT_CODE;
|
||||
}
|
||||
else {
|
||||
NewHeader.Flags |= (OldHeader.sh_type == SHT_PROGBITS) ?
|
||||
PE_SCN_CNT_INIT_DATA : PE_SCN_CNT_UNINIT_DATA;
|
||||
}
|
||||
// Alignment
|
||||
int NewAlign = FloorLog2(uint32(OldHeader.sh_addralign)) + 1;
|
||||
if (NewAlign > 14) NewAlign = 14; // limit for highest alignment
|
||||
NewHeader.Flags |= PE_SCN_ALIGN_1 * NewAlign;
|
||||
|
||||
// Find relocation table for this section by searching through all sections
|
||||
for (relsec = 1; relsec < this->NSections; relsec++) {
|
||||
|
||||
// Get section header
|
||||
OldRelHeader = this->SectionHeaders[relsec];
|
||||
|
||||
// Check if this is a relocations section referring to oldsec
|
||||
if ((OldRelHeader.sh_type == SHT_REL || OldRelHeader.sh_type == SHT_RELA) // if section is relocation
|
||||
&& OldRelHeader.sh_info == oldsec) { // and if section refers to current section
|
||||
|
||||
// Found the right relocation table. Get pointer
|
||||
int8 * reltab = this->Buf() + uint32(OldRelHeader.sh_offset);
|
||||
int8 * reltabend = reltab + uint32(OldRelHeader.sh_size);
|
||||
|
||||
// Get entry size
|
||||
int entrysize = uint32(OldRelHeader.sh_entsize);
|
||||
int expectedentrysize = (OldRelHeader.sh_type == SHT_RELA) ?
|
||||
sizeof(TELF_Relocation) : // Elf32_Rela, Elf64_Rela
|
||||
sizeof(TELF_Relocation) - this->WordSize/8; // Elf32_Rel, Elf64_Rel
|
||||
if (entrysize < expectedentrysize) {err.submit(2033); entrysize = expectedentrysize;}
|
||||
|
||||
// File pointer for new relocations
|
||||
NewHeader.PRelocations = NewRawData.GetDataSize() + RawDataOffset; // file to relocation entries
|
||||
|
||||
// Loop through relocation table entries
|
||||
for (; reltab < reltabend; reltab += entrysize) {
|
||||
|
||||
// Copy relocation table entry with or without addend
|
||||
OldRelocation.r_addend = 0;
|
||||
memcpy(&OldRelocation, reltab, entrysize);
|
||||
|
||||
// Find inline addend
|
||||
uint32 InlinePosition = (uint32)(NewHeader.PRawData - RawDataOffset + OldRelocation.r_offset);
|
||||
|
||||
// Check that address is valid
|
||||
if (InlinePosition >= this->GetDataSize()) {
|
||||
// Address is invalid
|
||||
err.submit(2032);
|
||||
break;
|
||||
}
|
||||
|
||||
// Pointer to inline addend
|
||||
int32 * piaddend = (int32*)(NewRawData.Buf() + InlinePosition);
|
||||
|
||||
// Symbol offset
|
||||
NewRelocation.VirtualAddress = uint32(OldRelocation.r_offset);
|
||||
|
||||
// Symbol table index
|
||||
if (OldRelocation.r_sym < NewSymbolIndex.GetNumEntries()) {
|
||||
NewRelocation.SymbolTableIndex = NewSymbolIndex[OldRelocation.r_sym];
|
||||
}
|
||||
else {
|
||||
NewRelocation.SymbolTableIndex = 0; // Symbol table index out of range
|
||||
}
|
||||
|
||||
// Get relocation type and fix addend
|
||||
if (this->WordSize == 32) {
|
||||
switch(OldRelocation.r_type) {
|
||||
case R_386_NONE: // Ignored
|
||||
NewRelocation.Type = COFF32_RELOC_ABS; break;
|
||||
|
||||
case R_386_IRELATIVE:
|
||||
err.submit(1063); // Warning: Gnu indirect function cannot be converted
|
||||
// continue in next case?:
|
||||
case R_386_32: // 32-bit absolute virtual address
|
||||
NewRelocation.Type = COFF32_RELOC_DIR32;
|
||||
*piaddend += uint32(OldRelocation.r_addend);
|
||||
break;
|
||||
|
||||
case R_386_PC32: // 32-bit self-relative
|
||||
NewRelocation.Type = COFF32_RELOC_REL32;
|
||||
// Difference between EIP-relative and self-relative relocation = size of address field
|
||||
// Adjust inline addend for different relocation method:
|
||||
*piaddend += 4 + uint32(OldRelocation.r_addend);
|
||||
break;
|
||||
|
||||
case R_386_GOT32: case R_386_GLOB_DAT: case R_386_GOTOFF: case R_386_GOTPC:
|
||||
// Global offset table
|
||||
err.submit(2042); // cannot convert position-independent code
|
||||
err.ClearError(2042); // report this error only once
|
||||
NewRelocation.Type = 0;
|
||||
break;
|
||||
|
||||
case R_386_PLT32: case R_386_JMP_SLOT:
|
||||
// procedure linkage table
|
||||
err.submit(2043); // cannot convert import table
|
||||
err.ClearError(2043); // report this error only once
|
||||
NewRelocation.Type = 0;
|
||||
break;
|
||||
|
||||
case R_386_RELATIVE: // adjust by program base
|
||||
default: // Unknown or unsupported relocation method
|
||||
err.submit(2030, OldRelocation.r_type);
|
||||
err.ClearError(2030); // report this error only once
|
||||
NewRelocation.Type = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else { // WordSize == 64
|
||||
switch(OldRelocation.r_type) {
|
||||
case R_X86_64_NONE: // Ignored
|
||||
NewRelocation.Type = COFF64_RELOC_ABS;
|
||||
break;
|
||||
|
||||
case R_X86_64_64: // 64 bit absolute virtual addres
|
||||
NewRelocation.Type = COFF64_RELOC_ABS64;
|
||||
*(int64*)piaddend += OldRelocation.r_addend;
|
||||
break;
|
||||
|
||||
case R_X86_64_IRELATIVE:
|
||||
err.submit(1063); // Warning: Gnu indirect function cannot be converted
|
||||
// continue in next case?:
|
||||
case R_X86_64_32S: // 32 bit absolute virtual address, sign extended
|
||||
case R_X86_64_32: // 32 bit absolute virtual address, zero extended
|
||||
NewRelocation.Type = COFF64_RELOC_ABS32;
|
||||
*piaddend += uint32(OldRelocation.r_addend);
|
||||
break;
|
||||
|
||||
case R_X86_64_PC32: // 32 bit, self-relative
|
||||
// See COFF2ELF.cpp for an explanation of the difference between
|
||||
// COFF and ELF relative relocation methods
|
||||
*piaddend += uint32(OldRelocation.r_addend);
|
||||
if (*piaddend >= -8 && *piaddend <= -4) {
|
||||
NewRelocation.Type = (uint16)(COFF64_RELOC_REL32 - *piaddend - 4);
|
||||
*piaddend = 0;
|
||||
}
|
||||
else {
|
||||
NewRelocation.Type = COFF64_RELOC_REL32;
|
||||
*piaddend += 4;
|
||||
}
|
||||
break;
|
||||
|
||||
case R_X86_64_RELATIVE: // Adjust by program base
|
||||
err.submit(2030, OldRelocation.r_type);
|
||||
err.ClearError(2030); // report this error only once
|
||||
NewRelocation.Type = 0;
|
||||
break;
|
||||
|
||||
case R_X86_64_GOT32: case R_X86_64_GLOB_DAT: case R_X86_64_GOTPCREL:
|
||||
// Global offset table
|
||||
err.submit(2042); // cannot convert position-independent code
|
||||
err.ClearError(2042); // report this error only once
|
||||
NewRelocation.Type = 0;
|
||||
break;
|
||||
|
||||
case R_X86_64_PLT32: case R_X86_64_JUMP_SLOT:
|
||||
// procedure linkage table
|
||||
err.submit(2042); // cannot convert import table
|
||||
err.ClearError(2043); // report this error only once
|
||||
NewRelocation.Type = 0;
|
||||
break;
|
||||
|
||||
default: // Unknown or unsupported relocation method
|
||||
err.submit(2030, OldRelocation.r_type);
|
||||
err.ClearError(2030); // report this error only once
|
||||
NewRelocation.Type = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Store relocation entry
|
||||
NewRawData.Push(&NewRelocation, SIZE_SCOFF_Relocation);
|
||||
NewHeader.NRelocations++;
|
||||
|
||||
// Remember that symbol is used
|
||||
if (OldRelocation.r_type) {
|
||||
SymbolsUsed[NewRelocation.SymbolTableIndex]++;
|
||||
}
|
||||
|
||||
} // End of relocations loop
|
||||
|
||||
} // End of if right relocation table
|
||||
|
||||
} // End of search for relocation table
|
||||
|
||||
// Align raw data for next section
|
||||
NewRawData.Align(4);
|
||||
|
||||
// Store section header in file
|
||||
ToFile.Push(&NewHeader, sizeof(NewHeader));
|
||||
|
||||
} // End of if section has program data
|
||||
|
||||
} // End of loop through old sections
|
||||
|
||||
} // End of function MakeSections
|
||||
|
||||
|
||||
// Check for overflow when converting 64 bit symbol value to 32 bits.
|
||||
// Value may be signed or unsigned
|
||||
static int SymbolOverflow(uint64 x) {
|
||||
uint32 Upper = HighDWord(x); // Upper 32 bits of 64 bit value
|
||||
if (Upper == 0xFFFFFFFF) { // Check for signed overflow
|
||||
return int32(x) >= 0; // Overflow if not signed
|
||||
}
|
||||
return Upper != 0; // Check for unsigned overflow
|
||||
}
|
||||
static int SymbolOverflow(uint32 x) { // Overloaded 32 bit version
|
||||
return 0; // Cannot overflow if already 32 bits
|
||||
}
|
||||
|
||||
|
||||
// MakeSymbolTable(): Convert subfunction to make symbol table and string tables
|
||||
template <class TELF_Header, class TELF_SectionHeader, class TELF_Symbol, class TELF_Relocation>
|
||||
void CELF2COF<ELFSTRUCTURES>::MakeSymbolTable() {
|
||||
uint32 oldsec; // Section number in old file
|
||||
TELF_SectionHeader OldHeader; // Old section header
|
||||
int FoundSymTab = 0; // Found symbol table
|
||||
int8 * strtab; // Old symbol string table
|
||||
int8 * symtab; // Old symbol table
|
||||
uint32 symtabsize; // Size of old symbol table
|
||||
uint32 stringtabsize; // Size of old string table
|
||||
int8 * symtabend; // End of old symbol table
|
||||
uint32 entrysize; // Size of each entry in old symbol table
|
||||
uint32 OldSymI; // Symbol index in old symbol table
|
||||
uint32 NewSymI = 0; // Symbol index in new symbol table
|
||||
const char * symname = 0; // Symbol name
|
||||
TELF_Symbol OldSym; // Old symbol table record
|
||||
SCOFF_SymTableEntry NewSym; // New symbol table record
|
||||
SCOFF_SymTableEntry AuxSym; // Auxiliary symbol table entry
|
||||
uint32 numaux; // Number of auxiliary records for new entry
|
||||
|
||||
// Initialize new string table. make space for 4-bytes size
|
||||
NewStringTable.Push(0, 4);
|
||||
|
||||
// Loop through old sections to find symbol table
|
||||
for (oldsec = 0; oldsec < this->NSections; oldsec++) {
|
||||
|
||||
// Search for program data sections only
|
||||
if (this->SectionHeaders[oldsec].sh_type == SHT_SYMTAB
|
||||
|| this->SectionHeaders[oldsec].sh_type==SHT_DYNSYM) {
|
||||
FoundSymTab++; numaux = 0;
|
||||
|
||||
// Copy symbol table header for convenience
|
||||
OldHeader = this->SectionHeaders[oldsec];
|
||||
|
||||
// Find associated string table
|
||||
if (OldHeader.sh_link >= this->NSections) {err.submit(2035); OldHeader.sh_link = 0;}
|
||||
strtab = this->Buf() + uint32(this->SectionHeaders[OldHeader.sh_link].sh_offset);
|
||||
stringtabsize = uint32(this->SectionHeaders[OldHeader.sh_link].sh_size);
|
||||
|
||||
|
||||
// Find old symbol table
|
||||
entrysize = uint32(OldHeader.sh_entsize);
|
||||
if (entrysize < sizeof(TELF_Symbol)) {err.submit(2033); entrysize = sizeof(TELF_Symbol);}
|
||||
|
||||
symtab = this->Buf() + uint32(OldHeader.sh_offset);
|
||||
symtabsize = uint32(OldHeader.sh_size);
|
||||
symtabend = symtab + symtabsize;
|
||||
|
||||
// Loop through old symbol table
|
||||
for (OldSymI = 0; symtab < symtabend; symtab += entrysize, OldSymI++) {
|
||||
|
||||
// Copy old symbol table entry
|
||||
OldSym = *(TELF_Symbol*)symtab;
|
||||
|
||||
// Reset new symbol table entry
|
||||
memset(&NewSym, 0, sizeof(NewSym));
|
||||
|
||||
// New symbol index
|
||||
NewSymI = NewSymbolTable.GetNumEntries();
|
||||
|
||||
// Symbol type
|
||||
int type = OldSym.st_type;
|
||||
|
||||
// Symbol storage class = binding
|
||||
int binding = OldSym.st_bind;
|
||||
|
||||
// Get symbol name
|
||||
if (OldSym.st_name < stringtabsize) {
|
||||
symname = strtab + OldSym.st_name;
|
||||
|
||||
if (symname && *symname && type != STT_FILE) {
|
||||
// Symbol has a name that we want to store
|
||||
COFF_PutNameInSymbolTable(NewSym, symname, NewStringTable);
|
||||
}
|
||||
}
|
||||
else { // points outside string table
|
||||
err.submit(2112); continue;
|
||||
}
|
||||
|
||||
// Value
|
||||
NewSym.s.Value = uint32(OldSym.st_value);
|
||||
// Check for overflow if converting 64 bit symbol value to 32 bits
|
||||
if (SymbolOverflow(OldSym.st_value)) err.submit(2020, symname);
|
||||
|
||||
// Section
|
||||
if (OldSym.st_shndx == SHN_UNDEF) {
|
||||
NewSym.s.SectionNumber = COFF_SECTION_UNDEF; // External
|
||||
}
|
||||
else if ((int16)(OldSym.st_shndx) == SHN_ABS) {
|
||||
NewSym.s.SectionNumber = COFF_SECTION_ABSOLUTE; // Absolute symbol
|
||||
}
|
||||
else if (OldSym.st_shndx >= this->NSections) {
|
||||
err.submit(2036, OldSym.st_shndx); // Special/unknown section index or out of range
|
||||
}
|
||||
else {
|
||||
// Normal section index.
|
||||
// Look up in section index translation table and add 1 because it is 1-based
|
||||
NewSym.s.SectionNumber = (int16)(NewSectIndex[OldSym.st_shndx] + 1);
|
||||
}
|
||||
|
||||
// Convert binding/storage class
|
||||
switch (binding) {
|
||||
case STB_LOCAL:
|
||||
NewSym.s.StorageClass = COFF_CLASS_STATIC; break;
|
||||
|
||||
case STB_GLOBAL:
|
||||
NewSym.s.StorageClass = COFF_CLASS_EXTERNAL; break;
|
||||
|
||||
case STB_WEAK:
|
||||
err.submit(1051, symname); // Weak public symbol not supported
|
||||
NewSym.s.StorageClass = COFF_CLASS_WEAK_EXTERNAL; break;
|
||||
|
||||
default:
|
||||
err.submit(2037, binding); // Other. Not supported
|
||||
}
|
||||
|
||||
// Make record depending on type
|
||||
switch (type) {
|
||||
case STT_OBJECT: case STT_NOTYPE:
|
||||
// Data object
|
||||
NewSym.s.Type = COFF_TYPE_NOT_FUNCTION;
|
||||
if (OldSymI > 0) { // First symbol entry in ELF file is unused
|
||||
NewSymbolTable.Push(&NewSym, SIZE_SCOFF_SymTableEntry);
|
||||
}
|
||||
break;
|
||||
|
||||
case STT_GNU_IFUNC:
|
||||
err.submit(1063); // Warning: Gnu indirect function cannot be converted
|
||||
// continue in next case:
|
||||
case STT_FUNC:
|
||||
// Function
|
||||
NewSym.s.Type = COFF_TYPE_FUNCTION;
|
||||
NewSymbolTable.Push(&NewSym, SIZE_SCOFF_SymTableEntry);
|
||||
// Aux records needed only if debug information included
|
||||
break;
|
||||
|
||||
case STT_FILE: {
|
||||
// File name record
|
||||
memset(&NewSym, 0, sizeof(NewSym));
|
||||
strcpy(NewSym.s.Name, ".file");
|
||||
NewSym.s.StorageClass = COFF_CLASS_FILE;
|
||||
NewSym.s.SectionNumber = COFF_SECTION_DEBUG;
|
||||
// Remove path from file name
|
||||
const char * shortname = symname;
|
||||
uint32 len = (uint32)strlen(symname);
|
||||
if (len > 1) {
|
||||
// Scan backwards for last '/'
|
||||
for (int scan = len-2; scan >= 0; scan--) {
|
||||
if (symname[scan] == '/' || symname[scan] == '\\') {
|
||||
// Path found. Short name starts after this character
|
||||
shortname = symname + scan + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
len = (uint32)strlen(shortname);
|
||||
if (len > 35) len = 35; // arbitrary limit to file name length
|
||||
|
||||
// Number of auxiliary records for storing file name
|
||||
numaux = (len + SIZE_SCOFF_SymTableEntry - 1) / SIZE_SCOFF_SymTableEntry;
|
||||
NewSym.s.NumAuxSymbols = (uint8)numaux;
|
||||
// Store regular record
|
||||
NewSymbolTable.Push(&NewSym, SIZE_SCOFF_SymTableEntry);
|
||||
// Store numaux auxiliary records for file name
|
||||
for (uint32 i = 0; i < numaux; i++) { // Can't push all in one operation because NumEntries will be wrong
|
||||
NewSymbolTable.Push(0, SIZE_SCOFF_SymTableEntry);
|
||||
}
|
||||
// copy name into NewSymbolTable aux records
|
||||
int8 * PointAux = NewSymbolTable.Buf() + NewSymbolTable.GetDataSize();
|
||||
memcpy(PointAux - numaux*SIZE_SCOFF_SymTableEntry, shortname, len);
|
||||
break;}
|
||||
|
||||
case STT_SECTION: {
|
||||
// Section name record
|
||||
NewSym.s.Value = 0;
|
||||
NewSym.s.Type = 0;
|
||||
NewSym.s.StorageClass = COFF_CLASS_STATIC;
|
||||
NewSym.s.NumAuxSymbols = (uint8)(numaux = 1);
|
||||
|
||||
// Find corresponding section header
|
||||
TELF_SectionHeader * OldSecHdr = 0;
|
||||
if (OldSym.st_shndx < this->NSections) {
|
||||
OldSecHdr = &(this->SectionHeaders[OldSym.st_shndx]);
|
||||
|
||||
// Find section name
|
||||
char * sname;
|
||||
if (OldSecHdr->sh_name < this->SecStringTableLen) {
|
||||
sname = this->SecStringTable + OldSecHdr->sh_name;
|
||||
// Put into symbol table
|
||||
COFF_PutNameInSymbolTable(NewSym, sname, NewStringTable);
|
||||
}
|
||||
}
|
||||
|
||||
// Store regular record
|
||||
NewSymbolTable.Push(&NewSym, SIZE_SCOFF_SymTableEntry);
|
||||
|
||||
// Make auxiliary record
|
||||
memset(&AuxSym, 0, sizeof(AuxSym));
|
||||
if (OldSecHdr) {
|
||||
AuxSym.section.Length = uint32(OldSecHdr->sh_size);
|
||||
// Find corresponding relocation section header
|
||||
// Assume that relocation section comes immediately after section record
|
||||
if ((uint32)OldSym.st_shndx + 1 < this->NSections // if not last section
|
||||
&& (OldSecHdr[1].sh_type == SHT_REL || OldSecHdr[1].sh_type == SHT_RELA) // and if next section is relocation
|
||||
&& OldSecHdr[1].sh_info == OldSym.st_shndx // and if next section refers to current section
|
||||
&& OldSecHdr[1].sh_entsize > 0) { // Avoid division by 0
|
||||
// Calculate number of relocations
|
||||
AuxSym.section.NumberOfRelocations = (uint16)(uint32(OldSecHdr[1].sh_size) / uint32(OldSecHdr[1].sh_entsize));
|
||||
}
|
||||
}
|
||||
// Store auxiliary record
|
||||
NewSymbolTable.Push(&AuxSym, SIZE_SCOFF_SymTableEntry);
|
||||
break;}
|
||||
|
||||
case STT_COMMON:
|
||||
default:
|
||||
err.submit(2038, type); // Symbol type not supported
|
||||
}
|
||||
|
||||
if (FoundSymTab == 1) {
|
||||
// Make translation table from old symbol index to new symbol index,
|
||||
// assuming there is only one symbol table.
|
||||
// Make sure all old symbols have an entry in the NewSymbolIndex table,
|
||||
// even if they are discarded.
|
||||
NewSymbolIndex.Push(NewSymI);
|
||||
}
|
||||
} // End OldSymI loop
|
||||
}
|
||||
} // End search for symbol table
|
||||
if (FoundSymTab == 0) err.submit(2034); // Symbol table not found
|
||||
if (FoundSymTab > 1) err.submit(1032); // More than one symbol table found
|
||||
|
||||
// Allocate space for SymbolsUsed table
|
||||
SymbolsUsed.SetNum(NewSymI+1);
|
||||
SymbolsUsed.SetZero(); // Initialize
|
||||
}
|
||||
|
||||
|
||||
// HideUnusedSymbols(): Hide unused symbols if stripping debug info or exception info
|
||||
template <class TELF_Header, class TELF_SectionHeader, class TELF_Symbol, class TELF_Relocation>
|
||||
void CELF2COF<ELFSTRUCTURES>::HideUnusedSymbols() {
|
||||
|
||||
if (cmd.DebugInfo != CMDL_DEBUG_STRIP && cmd.ExeptionInfo != CMDL_EXCEPTION_STRIP) {
|
||||
// No sections removed. Do nothing
|
||||
return;
|
||||
}
|
||||
|
||||
// Pointer to new symbol table
|
||||
union {
|
||||
SCOFF_SymTableEntry * p; // Symtab entry pointer
|
||||
int8 * b; // Used for increment
|
||||
} NewSymtab;
|
||||
NewSymtab.b = NewSymbolTable.Buf();
|
||||
int numaux = 0, isym;
|
||||
int NumberOfSymbols = NewSymbolTable.GetNumEntries();
|
||||
|
||||
// Loop through new symbol table
|
||||
for (isym = 0; isym < NumberOfSymbols; isym += numaux+1, NewSymtab.b += SIZE_SCOFF_SymTableEntry*(numaux+1)) {
|
||||
|
||||
// Number of auxiliary records belonging to same symbol
|
||||
numaux = NewSymtab.p->s.NumAuxSymbols; if (numaux < 0) numaux = 0;
|
||||
|
||||
if (NewSymtab.p->s.StorageClass == COFF_CLASS_EXTERNAL
|
||||
|| NewSymtab.p->s.StorageClass == COFF_CLASS_WEAK_EXTERNAL) {
|
||||
if (NewSymtab.p->s.SectionNumber == COFF_SECTION_UNDEF) {
|
||||
// External symbol. Check if it is used
|
||||
if (!SymbolsUsed[isym]) {
|
||||
// Symbol is unused. Hide it to prevent linking errors
|
||||
NewSymtab.p->s.StorageClass = COFF_CLASS_NULL;
|
||||
NewSymtab.p->s.SectionNumber = COFF_SECTION_UNDEF;
|
||||
NewSymtab.p->s.Type = COFF_TYPE_NOT_FUNCTION;
|
||||
cmd.CountSymbolsHidden();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MakeBinaryFile(): Convert subfunction to put all sections together
|
||||
template <class TELF_Header, class TELF_SectionHeader, class TELF_Symbol, class TELF_Relocation>
|
||||
void CELF2COF<ELFSTRUCTURES>::MakeBinaryFile() {
|
||||
|
||||
// Insert string table size
|
||||
//NewStringTable.Get<uint32>(0) = NewStringTable.GetDataSize();
|
||||
// Some compilers fail with the double template here. Avoid the template:
|
||||
*(uint32*)(NewStringTable.Buf()) = NewStringTable.GetDataSize();
|
||||
|
||||
// Update file header
|
||||
NewFileHeader.NumberOfSections = (uint16)NumSectionsNew;
|
||||
NewFileHeader.PSymbolTable = RawDataOffset + NewRawData.GetDataSize();
|
||||
NewFileHeader.NumberOfSymbols = NewSymbolTable.GetNumEntries();
|
||||
|
||||
// Replace file header in new file with updated version
|
||||
memcpy(ToFile.Buf(), &NewFileHeader, sizeof(NewFileHeader));
|
||||
|
||||
// Section headers have already been inserted.
|
||||
// Insert raw data in file
|
||||
ToFile.Push(NewRawData.Buf(), NewRawData.GetDataSize());
|
||||
|
||||
// Insert symbol table
|
||||
ToFile.Push(NewSymbolTable.Buf(), NewSymbolTable.GetDataSize());
|
||||
|
||||
// Insert string table
|
||||
ToFile.Push(NewStringTable.Buf(), NewStringTable.GetDataSize());
|
||||
}
|
||||
|
||||
|
||||
// Make template instances for 32 and 64 bits
|
||||
template class CELF2COF<ELF32STRUCTURES>;
|
||||
template class CELF2COF<ELF64STRUCTURES>;
|
||||
Reference in New Issue
Block a user