0,0 → 1,1267 |
/**************************** mac2elf.cpp ********************************* |
* Author: Agner Fog |
* Date created: 2008-05-15 |
* Last modified: 2009-05-19 |
* Project: objconv |
* Module: mac2elf.cpp |
* Description: |
* Module for converting Mach-O file to ELF file |
* |
* Copyright 2008 GNU General Public License http://www.gnu.org/licenses |
*****************************************************************************/ |
|
#include "stdafx.h" |
|
|
template <class TMAC_header, class TMAC_segment_command, class TMAC_section, class TMAC_nlist, class MInt, |
class TELF_Header, class TELF_SectionHeader, class TELF_Symbol, class TELF_Relocation> |
CMAC2ELF<MACSTRUCTURES,ELFSTRUCTURES>::CMAC2ELF () { |
// Constructor |
memset(this, 0, sizeof(*this)); // Reset everything |
} |
|
|
template <class TMAC_header, class TMAC_segment_command, class TMAC_section, class TMAC_nlist, class MInt, |
class TELF_Header, class TELF_SectionHeader, class TELF_Symbol, class TELF_Relocation> |
void CMAC2ELF<MACSTRUCTURES,ELFSTRUCTURES>::Convert() { |
// Do the conversion |
// Some compilers require this-> for accessing members of template base class, |
// according to the so-called two-phase lookup rule. |
|
NumSectionsNew = 5; // Number of sections generated so far |
|
// Allocate variable size buffers |
MaxSectionsNew = NumSectionsNew + 2 * this->NumSections + 2;// Max number of sections needed |
NewSections.SetNum(MaxSectionsNew+1); // Allocate buffers for each section |
NewSections.SetZero(); // Initialize |
NewSectionHeaders.SetNum(MaxSectionsNew+1); // Allocate array for temporary section headers |
NewSectionHeaders.SetZero(); // Initialize |
NewSectIndex.SetNum(this->NumSections+1); // Array for translating old section index to new section index |
NewSectIndex.SetZero(); // Initialize |
SectionSymbols.SetNum(this->MaxSectionsNew+1); // Array of new symbol indices for sections |
SectionSymbols.SetZero(); // Initialize |
NewSymbolIndex.SetNum(this->SymTabNumber); // 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(this->FileHeader); // Make relocation tables |
MakeImportTables(); // Fill import tables |
MakeGOT(); // Make fake Global Offset Table |
MakeBinaryFile(); // Putting sections together |
*this << ToFile; // Take over new file buffer |
} |
|
|
template <class TMAC_header, class TMAC_segment_command, class TMAC_section, class TMAC_nlist, class MInt, |
class TELF_Header, class TELF_SectionHeader, class TELF_Symbol, class TELF_Relocation> |
void CMAC2ELF<MACSTRUCTURES,ELFSTRUCTURES>::MakeSegments() { |
// Convert subfunction: Make segment headers and code/data segments |
TELF_SectionHeader NewSecHeader; // New section header |
uint32 oldsec; // Section index in old file |
uint32 newsec; // Section index in new file |
uint32 SecNameIndex; // Section name index into shstrtab |
char const * SecName; // Name of new section |
const int MAXSECTIONNAMELENGTH = 256; |
char RelocationSectionName[MAXSECTIONNAMELENGTH]; |
const int WordSize = sizeof(MInt) * 8; |
|
// 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 uint32 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 to equal the number of entries in |
// SpecialSegmentNames, including the Null segment |
err.submit(9000); |
} |
|
// Find sections in old file |
uint32 icmd; // Current load command |
uint32 command; // Load command |
uint32 cmdsize = 0; // Command size |
|
// Pointer to current position in old file |
uint8 * currentp = (uint8*)(this->Buf() + sizeof(TMAC_header)); |
|
// Loop through file commands |
for (icmd = 1; icmd <= this->FileHeader.ncmds; icmd++, currentp += cmdsize) { |
command = ((MAC_load_command*)currentp) -> cmd; |
cmdsize = ((MAC_load_command*)currentp) -> cmdsize; |
|
if (command == MAC_LC_SEGMENT || command == MAC_LC_SEGMENT_64) { |
// This is the segment command (there should be only one) |
if ((command == MAC_LC_SEGMENT) ^ (WordSize == 32)) { |
// 32-bit segment in 64-bit file or vice versa |
err.submit(2320); return; |
} |
if (cmdsize < sizeof(TMAC_segment_command)) { |
// Zero cmdsize or too small |
err.submit(2321); return; |
} |
// Point to segment command |
TMAC_segment_command * sh = (TMAC_segment_command*)currentp; |
|
if (stricmp(sh->segname, MAC_SEG_OBJC) == 0) { |
// objective-C runtime segment |
err.submit(2021); continue; |
} |
|
// Find first section header |
TMAC_section * sectp = (TMAC_section*)(currentp + sizeof(TMAC_segment_command)); |
|
// Loop through section headers |
for (oldsec = 1; oldsec <= this->NumSections; oldsec++, sectp++) { |
|
// Get section name |
SecName = sectp->sectname; |
|
// Check for special section names |
if (stricmp(SecName,"__eh_frame") == 0) { |
// This is an exception handler section |
if (cmd.ExeptionInfo == CMDL_EXCEPTION_STRIP) { |
// Remove exception handler section |
cmd.CountExceptionRemoved(); |
continue; |
} |
else if (cmd.InputType != cmd.OutputType) { |
err.submit(1030); // Warn that exception information is incompatible |
} |
} |
if (sectp->flags & MAC_S_ATTR_DEBUG) { |
// This section has debug information |
if (cmd.DebugInfo == CMDL_DEBUG_STRIP) { |
// Remove debug info |
cmd.CountDebugRemoved(); |
continue; |
} |
else if (cmd.InputType != cmd.OutputType) { |
err.submit(1029); // Warn that debug information is incompatible |
} |
} |
|
// Store section index in index translation table |
NewSectIndex[oldsec] = newsec; |
|
// Store section data |
if (sectp->size > 0 && !((sectp->flags & MAC_SECTION_TYPE) == MAC_S_ZEROFILL || (sectp->flags & MAC_SECTION_TYPE)==MAC_S_GB_ZEROFILL)) { |
NewSections[newsec].Push(this->Buf()+sectp->offset, uint32(sectp->size)); |
} |
|
// Put data into new section header: |
// Initialize to zero |
memset(&NewSecHeader, 0, sizeof(NewSecHeader)); |
|
uint32 type = sectp->flags & MAC_SECTION_TYPE; |
uint32 attributes = sectp->flags & MAC_SECTION_ATTRIBUTES; |
|
// Section type |
if (type == MAC_S_ZEROFILL || type == MAC_S_GB_ZEROFILL) { |
// BSS section |
NewSecHeader.sh_type = SHT_NOBITS; // BSS |
} |
else { |
// Normal code or data section |
NewSecHeader.sh_type = SHT_PROGBITS; // Program code or data |
} |
|
// Section flags |
NewSecHeader.sh_flags |= SHF_ALLOC; // Occupies memory during execution |
if (attributes & (MAC_S_ATTR_SOME_INSTRUCTIONS | MAC_S_ATTR_PURE_INSTRUCTIONS)) { |
// Executable |
NewSecHeader.sh_flags |= SHF_EXECINSTR; |
} |
else { |
switch (type) { |
case MAC_S_CSTRING_LITERALS: |
case MAC_S_4BYTE_LITERALS: |
case MAC_S_8BYTE_LITERALS: |
case MAC_S_16BYTE_LITERALS: |
case MAC_S_LITERAL_POINTERS: |
// not writeable |
break; |
default: |
// writeable |
NewSecHeader.sh_flags |= SHF_WRITE; |
break; |
} |
} |
|
// Check for special sections |
if (strcmp(SecName, MAC_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 = sectp->addr; |
|
// Section size in memory |
NewSecHeader.sh_size = sectp->size; |
|
// Section alignment |
NewSecHeader.sh_addralign = uint32(1 << sectp->align); |
|
// Put section header into temporary buffer |
NewSectionHeaders[newsec] = NewSecHeader; |
|
// Increment section number |
newsec++; |
|
// Check if section is import table |
int SectionType = sectp->flags & MAC_SECTION_TYPE; |
int IsImportTable = SectionType >= MAC_S_NON_LAZY_SYMBOL_POINTERS && SectionType <= MAC_S_SYMBOL_STUBS; |
|
if (sectp->nreloc > 0 || IsImportTable) { |
// 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 |
if (WordSize == 32) { |
strcpy(RelocationSectionName, ".rel"); |
} |
else { |
strcpy(RelocationSectionName, ".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 |
|
// Entry size |
NewSecHeader.sh_entsize = (WordSize == 32) ? sizeof(Elf32_Rel) : sizeof(Elf64_Rela); // Relocation section |
|
// Section alignment |
NewSecHeader.sh_addralign = WordSize / 8; |
|
// Link to the section it relocates for |
NewSecHeader.sh_info = newsec - 1; |
|
// Put section header into temporary buffer |
NewSectionHeaders[newsec] = NewSecHeader; |
|
// Increment section number |
newsec++; |
|
// Check if there are any GOT relocations |
// Pointer to old relocation entry |
if (sectp->reloff >= this->GetDataSize()) {err.submit(2035); break;} |
MAC_relocation_info * relp = (MAC_relocation_info*)(this->Buf() + sectp->reloff); |
// Loop through old relocations |
for (uint32 oldr = 1; oldr <= sectp->nreloc; oldr++, relp++) { |
uint32 RType = relp->r_type; // relocation type |
// No scattered relocation in 64-bit mode. GOT only in 64-bit mode |
if (WordSize == 64 && (RType == MAC64_RELOC_GOT_LOAD || RType == MAC64_RELOC_GOT)) { |
HasGOT++; |
} |
} |
} |
} |
|
// Check if GOT needed |
if (HasGOT && WordSize == 64) { |
// Make a fake Global Offset Table |
FakeGOTSection = newsec; |
|
// Put name and data into section header |
memset(&NewSecHeader, 0, sizeof(NewSecHeader)); |
SecNameIndex = NewSections[shstrtab].PushString("_fakeGOT"); |
NewSecHeader.sh_name = SecNameIndex; |
NewSecHeader.sh_type = SHT_PROGBITS; // Type |
NewSecHeader.sh_flags = SHF_ALLOC; // Flags |
NewSecHeader.sh_addralign = 8; // Alignment |
|
// Put section header into temporary buffer |
NewSectionHeaders[newsec++] = NewSecHeader; |
|
// Make relocation section for fake GOT |
memset(&NewSecHeader, 0, sizeof(NewSecHeader)); |
// Put name and data into section header |
SecNameIndex = NewSections[shstrtab].PushString("_rela.fakeGOT"); |
NewSecHeader.sh_name = SecNameIndex; |
NewSecHeader.sh_type = SHT_RELA; // Type |
NewSecHeader.sh_flags = 0; // Flags |
NewSecHeader.sh_addralign = 8; // Alignment |
NewSecHeader.sh_entsize = sizeof(Elf64_Rela); // Entry size |
NewSecHeader.sh_info = newsec - 1; // Link to the section it relocates for |
NewSecHeader.sh_link = symtab; // Link to symbol table |
// Put section header into temporary buffer |
NewSectionHeaders[newsec++] = NewSecHeader; |
} |
// Number of sections generated |
NumSectionsNew = newsec; |
} |
} |
} |
|
|
template <class TMAC_header, class TMAC_segment_command, class TMAC_section, class TMAC_nlist, class MInt, |
class TELF_Header, class TELF_SectionHeader, class TELF_Symbol, class TELF_Relocation> |
void CMAC2ELF<MACSTRUCTURES,ELFSTRUCTURES>::MakeSymbolTable() { |
// Convert subfunction: Make symbol table and string tables |
uint32 isym; // current old symbol table entry |
uint32 OldSectionIndex; // Index into old section table. 1-based |
uint32 NewSectionIndex; // Index into new section table. 0-based |
const char * name1; // Name of symbol |
TELF_Symbol sym; // Temporary symbol table record |
uint32 DebugRemoved = 0;// Debug symbols removed |
|
// pointer to old string table |
char * oldstringtab = (char*)(this->Buf() + this->StringTabOffset); |
|
// pointer to old symbol table |
TMAC_nlist * symp0, *symp; |
symp0 = (TMAC_nlist*)(this->Buf() + this->SymTabOffset); |
|
// Check within range |
if (this->SymTabOffset + this->SymTabNumber * sizeof(TMAC_nlist) > this->DataSize) { |
err.submit(2040); return; |
} |
|
// Make the first symbol record empty |
NewSections[symtab].Push(0, sizeof(TELF_Symbol)); |
|
// Make first string table entries empty |
NewSections[strtab] .PushString(""); |
NewSections[stabstr].PushString(""); |
|
// Make symbol records for the start of each section in case they are needed |
// by section-relative relocations (r_extern = 0 in MAC_relocation_info) |
for (uint32 sec = 1; sec < NumSectionsNew; sec++) { |
uint32 type = NewSectionHeaders[sec].sh_type; |
if (type == SHT_PROGBITS || type == SHT_NOBITS) { |
// Make unnamed symbol table entry for this section |
memset(&sym, 0, sizeof(sym)); |
sym.st_shndx = sec; |
sym.st_type = STT_SECTION; |
// Put record into new symbol table |
NewSections[symtab].Push(&sym, sizeof(sym)); |
// Insert into section symbol translation table |
SectionSymbols[sec] = NewSections[symtab].GetLastIndex(); |
} |
} |
|
// Loop through old symbol table. Local symbols first, global symbols last |
for (isym = 0, symp = symp0; isym < this->SymTabNumber; isym++, symp++) { |
|
if ((symp->n_type & MAC_N_STAB) && (cmd.DebugInfo & CMDL_DEBUG_STRIP)) { |
// Debug symbol should be removed |
DebugRemoved++; continue; |
} |
|
// Reset destination entry |
memset(&sym, 0, sizeof(sym)); |
|
// Get binding |
if (isym < this->iextdefsym) { |
// Local |
sym.st_bind = STB_LOCAL; |
} |
else if (symp->n_desc & (MAC_N_WEAK_REF | MAC_N_WEAK_DEF)) { |
// Weak public or weak external |
sym.st_bind = STB_WEAK; |
} |
else { |
// Global (public or external) |
sym.st_bind = STB_GLOBAL; |
} |
|
// Symbol name |
if (symp->n_strx < this->StringTabSize) { |
name1 = oldstringtab + symp->n_strx; |
} |
else { |
err.submit(2112); break; |
} |
|
// Symbol value |
sym.st_value = symp->n_value; |
|
// Get section |
OldSectionIndex = symp->n_sect; |
if (OldSectionIndex > this->NumSections) { |
err.submit(2016); break; |
} |
// Get new section index |
NewSectionIndex = 0; |
if (OldSectionIndex > 0) { |
// Get new section index from translation table |
NewSectionIndex = NewSectIndex[OldSectionIndex]; |
// Change symbol address to section-relative |
// (Also in 64-bit mode) |
sym.st_value -= NewSectionHeaders[NewSectionIndex].sh_addr; |
} |
sym.st_shndx = (uint16)NewSectionIndex; |
|
if (OldSectionIndex && !NewSectionIndex) { |
// Section has been removed. Remove symbol also |
continue; |
} |
|
// Check symbol type |
int32 RefType = symp->n_desc & MAC_REF_TYPE; |
if (RefType == MAC_REF_FLAG_UNDEFINED_LAZY || RefType == MAC_REF_FLAG_PRIVATE_UNDEFINED_LAZY) { |
// Lazy binding |
err.submit(1061, name1); |
} |
else if ((symp->n_type & MAC_N_TYPE) == MAC_N_ABS) { |
// Absolute symbol |
sym.st_type = STT_NOTYPE; |
sym.st_shndx = (uint16)SHN_ABS; |
if (sym.st_bind == STB_LOCAL) { |
continue; // Remove absolute local symbol (not allowed in COFF) |
} |
} |
else if (sym.st_shndx == 0) { // added by Vladimir 'phcoder' Serbinenko: |
// This is an external |
sym.st_type = STT_NOTYPE; |
} |
else { |
// This is a data definition record |
if (NewSectionHeaders[NewSectionIndex].sh_flags & SHF_EXECINSTR) { |
// Code section, assume this is a function |
sym.st_type = STT_FUNC; |
} |
else { |
// This is a data object |
sym.st_type = STT_OBJECT; |
} |
if (sym.st_bind == STB_GLOBAL && NewSectionIndex) { |
// Symbol is public |
// The size is not specified in Mac record, |
// so we may give it an arbitrary size: |
sym.st_size = 4; |
} |
} |
|
// Put symbol name into string table |
if (name1 && *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(); |
|
// Make index to first global symbol |
if (isym >= this->iextdefsym && !NewSectionHeaders[symtab].sh_info) { |
// This is the first global symbol |
NewSectionHeaders[symtab].sh_info = NewSymbolIndex[isym]; |
} |
} |
} |
|
|
template <class TMAC_header, class TMAC_segment_command, class TMAC_section, class TMAC_nlist, class MInt, |
class TELF_Header, class TELF_SectionHeader, class TELF_Symbol, class TELF_Relocation> |
void CMAC2ELF<MACSTRUCTURES,ELFSTRUCTURES>::MakeRelocationTables(MAC_header_32&) { |
// Convert subfunction: Relocation tables, 32-bit version |
|
uint32 oldsec; // Relocated section number in source file |
uint32 newsec; // Relocated section number in destination file |
uint32 newsecr; // Relocation table section number in destination file |
MInt SectAddr; // Section address of relocation source |
MInt SourceAddress; // Address of relocation source including section address |
MInt TargetAddress; // Target address including section address |
uint32 TargetSection; // New section index of relocation target |
uint32 TargetOffset; // Section-relative offset of relocation target |
uint32 RefAddress; // Reference point address including section address |
uint32 RefSection; // New section index of reference point |
uint32 RefOffset; // Section-relative offset of reference point |
int32 * inlinep = 0; // Pointer to inline addend |
//const int WordSize = sizeof(MInt) * 8; |
|
TELF_SectionHeader * NewRelTableSecHeader; // Section header for new relocation table |
|
// Number of symbols |
uint32 NumSymbols = NewSections[symtab].GetNumEntries(); |
|
// New symbol table |
//Elf32_Sym * NewSymbolTable = (Elf32_Sym *)(NewSections[symtab].Buf()); |
|
// Find first section header |
MAC_section_32 * sectp = (MAC_section_32*)(this->Buf() + this->SectionHeaderOffset); |
|
// Loop through section headers |
for (oldsec = 1; oldsec <= this->NumSections; oldsec++, sectp++) { |
|
if (sectp->nreloc > 0) { |
// Source section has relocations |
|
// New section index |
newsec = NewSectIndex[oldsec]; |
|
// Check that section has not been deleted |
if (newsec > 0) { |
|
// Section address |
SectAddr = NewSectionHeaders[newsec].sh_addr; |
|
// Finc new relocation table section |
newsecr = newsec + 1; |
if (newsecr >= NewSectionHeaders.GetNumEntries()) { |
err.submit(9000); return;} |
|
// New relocation table section header |
NewRelTableSecHeader = &NewSectionHeaders[newsecr]; |
|
// Check that we have allocated this as a relocation section |
if (NewRelTableSecHeader->sh_info != newsec) { |
err.submit(9000); return; |
} |
|
// Insert header info |
NewRelTableSecHeader->sh_type = SHT_REL; |
NewRelTableSecHeader->sh_flags = 0; |
NewRelTableSecHeader->sh_addralign = 4; |
NewRelTableSecHeader->sh_link = symtab; // Point to symbol table |
NewRelTableSecHeader->sh_info = newsec; // Point to relocated section |
NewRelTableSecHeader->sh_entsize = sizeof(Elf32_Rel); // Entry size: |
|
// Pointer to old relocation entry |
if (sectp->reloff >= this->GetDataSize()) {err.submit(2035); break;} |
MAC_relocation_info * relp = (MAC_relocation_info*)(this->Buf() + sectp->reloff); |
|
// Loop through old relocations |
for (uint32 oldr = 1; oldr <= sectp->nreloc; oldr++, relp++) { |
|
// Make new relocation entry and set to zero |
Elf32_Rel NewRelocEntry; |
|
memset(&NewRelocEntry, 0, sizeof(NewRelocEntry)); |
|
if (relp->r_address & R_SCATTERED) { |
// scattered relocation into |
MAC_scattered_relocation_info * scatp = (MAC_scattered_relocation_info*)relp; |
|
// Address of source |
NewRelocEntry.r_offset = scatp->r_address; |
if (NewRelocEntry.r_offset >= NewSections[newsec].GetDataSize()) { |
err.submit(2035); continue; // Out of range |
} |
// Pointer to inline addend |
inlinep = (int32*)(NewSections[newsec].Buf() + NewRelocEntry.r_offset); |
if (scatp->r_pcrel) { |
// Self-relative scattered |
if (scatp->r_type != MAC32_RELOC_VANILLA) { |
err.submit(2030, scatp->r_type); continue; // Unexpected type |
} |
// Scattered, self-relative, vanilla |
// Note: I have never seen this relocation method, so I have not |
// been able to test it. I don't know for sure how it works and |
// the documentation is poor. |
SourceAddress = SectAddr + scatp->r_address; |
|
// Target address |
TargetAddress = SourceAddress + *inlinep; |
TranslateAddress(TargetAddress, TargetSection, TargetOffset); |
if (TargetSection == 0) {err.submit(2031); continue;} // not found |
NewRelocEntry.r_sym = SectionSymbols[TargetSection]; |
if (NewRelocEntry.r_sym == 0) { |
err.submit(2031); continue; // refers to non-program section |
} |
|
// inline contains full relative address |
// compensate by subtracting relative address to target section |
*inlinep -= int32(NewSectionHeaders[TargetSection].sh_addr - SourceAddress); |
// Relocation type |
NewRelocEntry.r_type = R_386_PC32; |
} |
else if (scatp->r_type == MAC32_RELOC_VANILLA) { |
// Scattered, absolute |
TargetAddress = *inlinep; |
TranslateAddress(TargetAddress, TargetSection, TargetOffset); |
if (TargetSection == 0) { |
err.submit(2031); continue;} // Target not found |
NewRelocEntry.r_sym = SectionSymbols[TargetSection]; |
*inlinep = TargetOffset; |
NewRelocEntry.r_type = R_386_32; |
if (scatp->r_length != 2) { |
err.submit(2030, scatp->r_type); continue; // Only 32-bit supported |
} |
} |
else if (scatp->r_type == MAC32_RELOC_SECTDIFF || scatp->r_type == MAC32_RELOC_LOCAL_SECTDIFF) { |
// relative to arbitrary reference point |
// check that next record is MAC32_RELOC_PAIR |
if (oldr == sectp->nreloc || (scatp+1)->r_type != MAC32_RELOC_PAIR || scatp->r_length != 2) { |
err.submit(2050); continue; |
} |
// Find target address and reference point |
RefAddress = (scatp+1)->r_value; |
TranslateAddress(RefAddress, RefSection, RefOffset); |
TargetAddress = RefAddress + *inlinep; |
TranslateAddress(TargetAddress, TargetSection, TargetOffset); |
// Check that both points are found |
if (RefSection == 0 || TargetSection == 0) { |
err.submit(2031); oldr++; relp++; continue; |
} |
// Address relative to arbitrary reference point can be translated |
// to self-relative address if reference point is in same section as source |
if (RefSection != newsec) { |
err.submit(2044); oldr++; relp++; continue; |
} |
// Translation is possible |
// Get symbol for target section |
NewRelocEntry.r_sym = SectionSymbols[TargetSection]; |
// Make self-relative relocation |
NewRelocEntry.r_type = R_386_PC32; |
// Calculate compensating addend |
*inlinep = TargetOffset + scatp->r_address - RefOffset; |
// Linker will add (target section) - (source full address) to *inlinep, which gives |
// (target full address) - (reference point full address) |
// Advance pointers because we have used two records |
oldr++; relp++; |
} |
else if (scatp->r_type == MAC32_RELOC_PB_LA_PTR) { |
// procedure linkage table. Not supported |
NewRelocEntry.r_type = R_386_PLT32; |
err.submit(2043); |
} |
else { |
// unknown scattered relocation type |
err.submit(2030, scatp->r_type); continue; |
} |
} |
else { |
// Non scattered relocation info |
// Section offset of relocated address |
NewRelocEntry.r_offset = relp->r_address; |
if (NewRelocEntry.r_offset >= NewSections[newsec].GetDataSize()) { |
err.submit(2035); continue; // Out of range |
} |
// Pointer to inline addend |
inlinep = (int32*)(NewSections[newsec].Buf() + NewRelocEntry.r_offset); |
|
if (relp->r_extern) { |
// r_extern = 1: target indicated by symbol index |
uint32 symold = relp->r_symbolnum; |
if (symold >= this->SymTabNumber) { |
err.submit(2031); continue; // index out of range |
} |
NewRelocEntry.r_sym = NewSymbolIndex[symold]; |
if (relp->r_pcrel) { |
// Self-relative. |
// Inline contains -(source address) |
// Add (source address) to compensate |
*inlinep += int32(SectAddr + relp->r_address); |
} |
} |
else { |
// r_extern = 0. Target indicated by section + offset |
// Old section number |
uint32 secold = relp->r_symbolnum; |
if (secold > this->NumSections) { |
err.submit(2031); continue; // index out of range |
} |
TargetSection = NewSectIndex[secold]; |
NewRelocEntry.r_sym = SectionSymbols[TargetSection]; |
if (NewRelocEntry.r_sym == 0 || NewRelocEntry.r_sym > NumSymbols) { |
err.submit(2031); continue; // refers to non-program section |
} |
if (relp->r_pcrel) { |
// Self-relative. |
// Inline contains (target address)-(source address) |
// Subtract this to compensate |
|
// Target section address |
TargetOffset = uint32(NewSectionHeaders[TargetSection].sh_addr); |
SourceAddress = SectAddr + relp->r_address; |
*inlinep -= int32(TargetOffset - SourceAddress); |
} |
else { |
// Absolute reference |
// Inline contains target address, convert to section:offset address |
TranslateAddress(*inlinep, TargetSection, TargetOffset); |
if (TargetSection == 0) { // Target not found |
err.submit(2035); continue; |
} |
// Translate to section-relative address by subtracting target section address |
*inlinep -= int32(NewSectionHeaders[TargetSection].sh_addr); |
} |
} |
// relocation type (32-bit non-scattered) |
switch (relp->r_type) { |
case MAC32_RELOC_VANILLA: |
// Normal relocation |
if (relp->r_pcrel) { // self relative |
NewRelocEntry.r_type = R_386_PC32; |
} |
else { // direct |
NewRelocEntry.r_type = R_386_32; |
} |
break; |
default: |
err.submit(2030, relp->r_type); // unknown type |
continue; |
} |
// size |
if (relp->r_length != 2) { // wrong size |
err.submit(2030,relp->r_type); |
} |
} |
// Put relocation record into table |
NewSections[newsecr].Push(&NewRelocEntry, sizeof(NewRelocEntry)); |
} |
} |
} |
} |
} |
|
|
template <class TMAC_header, class TMAC_segment_command, class TMAC_section, class TMAC_nlist, class MInt, |
class TELF_Header, class TELF_SectionHeader, class TELF_Symbol, class TELF_Relocation> |
void CMAC2ELF<MACSTRUCTURES,ELFSTRUCTURES>::MakeRelocationTables(MAC_header_64&) { |
// Convert subfunction: Relocation tables, 64-bit version |
|
uint32 oldsec; // Relocated section number in source file |
uint32 newsec; // Relocated section number in destination file |
uint32 newsecr; // Relocation table section number in destination file |
uint32 symold; // Old index of symbol |
uint32 TargetSym; // Target symbol |
uint32 TargetSection; // New section index of relocation target |
uint32 RefSym; // Reference symbol |
uint32 RefSection; // New section index of reference point |
int64 RefOffset; // Section-relative offset of reference point |
int64 SectAddr; // Address of current section |
//const int WordSize = sizeof(MInt) * 8; // Word size, 32 or 64 bits |
|
TELF_SectionHeader * NewRelTableSecHeader; // Section header for new relocation table |
|
// Number of symbols |
//uint32 NumSymbols = NewSections[symtab].GetNumEntries(); |
|
// New symbol table |
Elf64_Sym * NewSymbolTable = (Elf64_Sym *)(NewSections[symtab].Buf()); |
|
// Find first section header |
MAC_section_64 * sectp = (MAC_section_64*)(this->Buf() + this->SectionHeaderOffset); |
|
// Loop through section headers |
for (oldsec = 1; oldsec <= this->NumSections; oldsec++, sectp++) { |
|
if (sectp->nreloc > 0) { |
// Source section has relocations |
|
// New section index |
newsec = NewSectIndex[oldsec]; |
|
// Check that section has not been deleted |
if (newsec > 0) { |
|
// Section address |
SectAddr = NewSectionHeaders[newsec].sh_addr; |
|
// Finc new relocation table section |
newsecr = newsec + 1; |
if (newsecr > NewSectionHeaders.GetNumEntries()) { |
err.submit(9000); return; |
} |
|
// New relocation table section header |
NewRelTableSecHeader = &NewSectionHeaders[newsecr]; |
|
// Check that we have allocated this as a relocation section |
if (NewRelTableSecHeader->sh_info != newsec) { |
err.submit(9000); return; |
} |
|
// Insert header info |
NewRelTableSecHeader->sh_type = SHT_RELA; |
NewRelTableSecHeader->sh_flags = 0; |
NewRelTableSecHeader->sh_addralign = 8; |
NewRelTableSecHeader->sh_link = symtab; // Point to symbol table |
NewRelTableSecHeader->sh_info = newsec; // Point to relocated section |
// Entry size: |
NewRelTableSecHeader->sh_entsize = sizeof(Elf64_Rela); |
|
// Pointer to old relocation entry |
if (sectp->reloff >= this->GetDataSize()) {err.submit(2035); break;} |
MAC_relocation_info * relp = (MAC_relocation_info*)(this->Buf() + sectp->reloff); |
|
// Loop through old relocations |
for (uint32 oldr = 1; oldr <= sectp->nreloc; oldr++, relp++) { |
|
// Make new relocation entry and set to zero |
Elf64_Rela NewRelocEntry; |
memset(&NewRelocEntry, 0, sizeof(NewRelocEntry)); |
|
// Pointer to inline addend |
int32 * inlinep = 0; |
|
if (relp->r_address & R_SCATTERED) { |
// scattered not allowed in 64-bit |
err.submit(2030, ((MAC_scattered_relocation_info*)relp)->r_type); continue; |
} |
else { |
// Non scattered relocation info |
// Section offset of relocated address |
NewRelocEntry.r_offset = relp->r_address; |
if (NewRelocEntry.r_offset >= NewSections[newsec].GetDataSize()) { |
err.submit(2035); continue; // Out of range |
} |
// Pointer to inline addend |
inlinep = (int32*)(NewSections[newsec].Buf() + NewRelocEntry.r_offset); |
|
// Symbol index of target |
symold = relp->r_symbolnum; |
if (relp->r_extern) { |
if (symold >= this->SymTabNumber) { |
err.submit(2031); continue; // index out of range |
} |
NewRelocEntry.r_sym = NewSymbolIndex[symold]; |
} |
else { |
// r_extern = 0, r_symbolnum = section |
if (symold > NumSectionsNew) {err.submit(2031); continue;} |
TargetSection = NewSectIndex[symold]; |
NewRelocEntry.r_sym = SectionSymbols[TargetSection]; |
if (relp->r_pcrel) { |
// Self-relative. |
// Inline contains (target address)-(source address) |
// Subtract this to compensate |
// Target section address |
uint64 TargetSectAddr = NewSectionHeaders[TargetSection].sh_addr; |
uint64 SourceAddress = SectAddr + relp->r_address; |
*inlinep -= int32(TargetSectAddr - SourceAddress); |
*inlinep += 4; // Compensate for subtracting 4 below |
} |
} |
|
// Find relocation type |
switch (relp->r_type) { |
case MAC64_RELOC_UNSIGNED: // absolute address, 32 or 64 bits |
if (relp->r_length == 2) { |
NewRelocEntry.r_type = R_X86_64_32S; // 32 bit signed |
} |
else if (relp->r_length == 3) { |
NewRelocEntry.r_type = R_X86_64_64; // 64 bit |
} |
else { |
err.submit(2030,relp->r_type); continue; |
} |
break; |
case MAC64_RELOC_SIGNED: // rip-relative, implicit addend = -4 |
case MAC64_RELOC_BRANCH: // rip-relative, implicit addend = -4 |
case MAC64_RELOC_SIGNED_1: // implicit addend = -4, not -5 |
case MAC64_RELOC_SIGNED_2: // implicit addend = -4, not -6 |
case MAC64_RELOC_SIGNED_4: // implicit addend = -4, not -8 |
// These are all the same: |
// signed 32-bit rip-relative with implicit -4 addend |
if (relp->r_length != 2) { // wrong size |
err.submit(2030,relp->r_type); continue; |
} |
NewRelocEntry.r_type = R_X86_64_PC32; |
// ELF = self-relative, Mac64 = rip-relative. Compensate for difference |
*inlinep -= 4; |
break; |
case MAC64_RELOC_SUBTRACTOR: |
// relative to arbitrary reference point |
// must be followed by a X86_64_RELOC_UNSIGNED |
// check that next record is MAC64_RELOC_UNSIGNED |
if (oldr == sectp->nreloc || (relp+1)->r_type != MAC64_RELOC_UNSIGNED) { |
err.submit(2050); continue; |
} |
// Reference symbol |
RefSym = NewRelocEntry.r_sym; |
RefSection = NewSymbolTable[RefSym].st_shndx; |
RefOffset = NewSymbolTable[RefSym].st_value; |
|
// Target symbol |
symold = (relp+1)->r_symbolnum; |
if (symold >= this->SymTabNumber) { |
err.submit(2031); continue; // index out of range |
} |
TargetSym = NewSymbolIndex[symold]; |
NewRelocEntry.r_sym = TargetSym; |
|
// Address relative to arbitrary reference point can be translated |
// to self-relative address if reference point is in same section as source |
if (RefSection != newsec) { |
err.submit(2044); oldr++; relp++; continue; |
} |
if (relp->r_length == 2) { |
*inlinep += int32(NewRelocEntry.r_offset) - int32(RefOffset); |
} |
else if (relp->r_length == 3) { |
*(int64*)inlinep += NewRelocEntry.r_offset - RefOffset; |
// there is no 64-bit self-relative relocation in ELF, |
// use 32-bit self-relative and hope there is no carry |
err.submit(1302); // Warn. This will fail if inline value changes sign |
} |
else { |
err.submit(2044); // wrong size |
} |
// self-relative type |
NewRelocEntry.r_type = R_X86_64_PC32; |
|
// increment counters because we used two records |
relp++; oldr++; |
break; |
|
case MAC64_RELOC_GOT_LOAD: // a rip-relative load of a GOT entry |
*inlinep = -4; |
// Continue into next case |
case MAC64_RELOC_GOT: // other GOT references |
// Make fake GOT entry |
//NewRelocEntry.r_addend = MakeGOTEntry(NewRelocEntry.r_sym) - 4; |
*inlinep += MakeGOTEntry(NewRelocEntry.r_sym); |
NewRelocEntry.r_sym = FakeGOTSymbol; |
NewRelocEntry.r_type = R_X86_64_PC32; |
break; |
} |
} |
|
// Put relocation record into table |
NewSections[newsecr].Push(&NewRelocEntry, sizeof(NewRelocEntry)); |
} |
} |
} |
} |
} |
|
|
template <class TMAC_header, class TMAC_segment_command, class TMAC_section, class TMAC_nlist, class MInt, |
class TELF_Header, class TELF_SectionHeader, class TELF_Symbol, class TELF_Relocation> |
void CMAC2ELF<MACSTRUCTURES,ELFSTRUCTURES>::MakeBinaryFile() { |
// Convert subfunction: Make section headers and file header, |
// and combine everything into a single memory buffer. |
uint32 newsec; // Section index |
uint32 SecOffset; // Section offset in file |
uint32 SecSize; // Section size in file |
uint32 SectionHeaderOffset; // File offset to section headers |
const int WordSize = sizeof(MInt) * 8; |
|
// 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; |
if (SecSize) { // Don't set size of BSS sections to zero |
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)); |
} |
|
template <class TMAC_header, class TMAC_segment_command, class TMAC_section, class TMAC_nlist, class MInt, |
class TELF_Header, class TELF_SectionHeader, class TELF_Symbol, class TELF_Relocation> |
void CMAC2ELF<MACSTRUCTURES,ELFSTRUCTURES>::MakeImportTables() { |
// Convert subfunction: Fill import tables |
uint32 oldsec; // Old section number |
uint32 Type; // Old section type |
uint32 NumEntries; // Number of entries in import table |
uint32 EntrySize; // Entry size of import table |
uint32 NewSec1; // New section number of import table |
uint32 NewSec2; // New section number of relocation for import table |
uint32 Offset; // Offset of relocation source |
uint32 OldSymbol; // Old symbol number of import |
uint32 i; // Loop counter |
uint32 * IndSymTab; // Pointer to indirect symbol table |
uint32 IndSymi; // Index into indirect symbol table |
uint32 IndSymNum; // Number of entries in indirect symbol table |
TELF_Relocation NewRelocEntry; // New relocation entry |
const int WordSize = sizeof(MInt) * 8; |
|
// Machine code of jmp instruction |
static const int8 JmpInstruction[5] = {int8(0xE9), int8(0xFC), int8(0xFF), int8(0xFF), int8(0xFF)}; |
|
// Number of indirect symbols |
IndSymNum = this->IndirectSymTabNumber; |
if (IndSymNum == 0) { |
return; // No indirect symbols |
} |
// Find indirect symbol table |
IndSymTab = (uint32*)(this->Buf() + this->IndirectSymTabOffset); |
|
// Find first section header |
TMAC_section * sectp = (TMAC_section*)(this->Buf() + this->SectionHeaderOffset); |
|
// Loop through section headers |
for (oldsec = 1; oldsec <= this->NumSections; oldsec++, sectp++) { |
// Search for import tables |
Type = sectp->flags & MAC_SECTION_TYPE; |
if (Type >= MAC_S_NON_LAZY_SYMBOL_POINTERS && Type <= MAC_S_SYMBOL_STUBS) { |
// This is an import table |
|
// Indirect symbol table first entry |
IndSymi = sectp->reserved1; |
|
// Entry size: |
EntrySize = sectp->reserved2; |
if (EntrySize == 0) EntrySize = WordSize / 8; |
|
// Find new section |
NewSec1 = NewSectIndex[oldsec]; |
NumEntries = uint32(NewSectionHeaders[NewSec1].sh_size) / EntrySize; |
|
// Find new relocation section |
NewSec2 = NewSec1 + 1; |
if (NewSectionHeaders[NewSec2].sh_type != SHT_REL && NewSectionHeaders[NewSec2].sh_type != SHT_RELA) { |
err.submit(9000); // This should be a relocation section |
} |
NewSectionHeaders[NewSec2].sh_link = symtab; // Point to symbol table |
|
// Offset of first relocation |
Offset = EntrySize & 1; // 1 if EntrySize = 5, otherwise 0 |
|
// Loop through entries |
for (i = 0; i < NumEntries; i++, Offset += EntrySize) { |
// Find symbol |
if (IndSymi >= IndSymNum) { |
err.submit(1303); break; // Import symbol table exhausted |
} |
OldSymbol = IndSymTab[IndSymi]; |
if (OldSymbol >= this->SymTabNumber) { |
err.submit(1052); break; |
} |
// Increment pointer to import symbol table |
IndSymi++; |
|
// Make relocation record |
memset(&NewRelocEntry, 0, sizeof(NewRelocEntry)); |
NewRelocEntry.r_offset = Offset; |
if (WordSize == 32) { |
if (EntrySize == 4) { |
NewRelocEntry.r_type = R_386_32; |
} |
else if (EntrySize == 5) { |
NewRelocEntry.r_type = R_386_PC32; |
} |
else { |
err.submit(2045); |
} |
} |
else { // 64 bit |
if (EntrySize == 8) { |
NewRelocEntry.r_type = R_X86_64_64; |
} |
else if (EntrySize == 5) { |
NewRelocEntry.r_type = R_X86_64_PC32; |
} |
else { |
err.submit(2045); |
} |
} |
NewRelocEntry.r_sym = NewSymbolIndex[OldSymbol]; |
|
// Store relocation record |
NewSections[NewSec2].Push(&NewRelocEntry, (WordSize==32) ? sizeof(Elf32_Rel) : sizeof(Elf64_Rela)); |
|
// Insert jmp instruction if EntrySize = 5 |
if (EntrySize == 5) { |
if (Offset -1 + EntrySize > NewSections[NewSec1].GetDataSize()) { |
err.submit(9000); // Outside section |
} |
memcpy(NewSections[NewSec1].Buf()+Offset-1, JmpInstruction, 5); |
} |
} |
} |
} |
} |
|
|
template <class TMAC_header, class TMAC_segment_command, class TMAC_section, class TMAC_nlist, class MInt, |
class TELF_Header, class TELF_SectionHeader, class TELF_Symbol, class TELF_Relocation> |
void CMAC2ELF<MACSTRUCTURES,ELFSTRUCTURES>::TranslateAddress(MInt addr, uint32 & section, uint32 & offset) { |
// Translate 32-bit address to section + offset |
// (Sections are not necessarily ordered by address) |
uint32 sec; |
MInt secstart; |
for (sec = 1; sec < NumSectionsNew; sec++) { |
secstart = NewSectionHeaders[sec].sh_addr; |
if (addr >= secstart && addr < secstart + MInt(NewSectionHeaders[sec].sh_size)) { |
// Section found |
section = sec; |
offset = uint32(addr - secstart); |
return; |
} |
} |
// Not found |
section = offset = 0; |
} |
|
template <class TMAC_header, class TMAC_segment_command, class TMAC_section, class TMAC_nlist, class MInt, |
class TELF_Header, class TELF_SectionHeader, class TELF_Symbol, class TELF_Relocation> |
uint32 CMAC2ELF<MACSTRUCTURES,ELFSTRUCTURES>::MakeGOTEntry(int symbol) { |
// Make entry in fake GOT for symbol |
uint32 NumGOTEntries = GOTSymbols.GetNumEntries(); |
uint32 symi; // Symbol index |
const int WordSize = sizeof(MInt) * 8; |
|
// Get symbol for start of GOT |
FakeGOTSymbol = SectionSymbols[FakeGOTSection]; |
|
// Search for symbol in previous entries |
for (symi = 0; symi < NumGOTEntries; symi++) { |
if (GOTSymbols[symi] == symbol) break; |
} |
if (symi == NumGOTEntries) { |
// Not found. Make new entry |
GOTSymbols.Push(symbol); |
} |
return symi * (WordSize / 8); |
} |
|
|
template <class TMAC_header, class TMAC_segment_command, class TMAC_section, class TMAC_nlist, class MInt, |
class TELF_Header, class TELF_SectionHeader, class TELF_Symbol, class TELF_Relocation> |
void CMAC2ELF<MACSTRUCTURES,ELFSTRUCTURES>::MakeGOT() { |
// Make fake Global Offset Table |
const int WordSize = sizeof(MInt) * 8; |
if (!HasGOT) return; |
|
uint32 NumEntries = GOTSymbols.GetNumEntries(); |
NewSections[FakeGOTSection].Push(0, NumEntries*(WordSize/8)); |
|
// Make relocations for GOT |
Elf64_Rela NewRelocEntry; |
memset(&NewRelocEntry, 0, sizeof(NewRelocEntry)); |
|
for (uint32 i = 0; i < NumEntries; i++) { |
NewRelocEntry.r_offset = i * (WordSize/8); |
NewRelocEntry.r_sym = GOTSymbols[i]; |
NewRelocEntry.r_type = R_X86_64_64; |
NewSections[FakeGOTSection+1].Push(&NewRelocEntry, sizeof(NewRelocEntry)); |
} |
} |
|
|
// Make template instances for 32 and 64 bits |
template class CMAC2ELF<MAC32STRUCTURES,ELF32STRUCTURES>; |
template class CMAC2ELF<MAC64STRUCTURES,ELF64STRUCTURES>; |