Added objconv port.

git-svn-id: svn://kolibrios.org@9683 a494cfbc-eb01-0410-851d-a64ba20cac60
This commit is contained in:
turbocat 2022-02-06 11:09:00 +00:00
parent 2ef3c498fa
commit 60a4b1c9ef
42 changed files with 38310 additions and 0 deletions

5
programs/develop/objconv/.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
.vs
src/.vs
src/Release
src/Debug
src/x64

3
programs/develop/objconv/.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "c2nasm/nasm"]
path = c2nasm/nasm
url = https://github.com/gitGNU/nasm

View File

@ -0,0 +1,40 @@
if tup.getconfig("NO_GCC") ~= "" then return end
HELPERDIR = (tup.getconfig("HELPERDIR") == "") and "../.." or tup.getconfig("HELPERDIR")
tup.include(HELPERDIR .. "/use_gcc.lua")
tup.include(HELPERDIR .. "/use_newlib.lua")
LIBS = " -lstdc++ -lsupc++ -lgcc -lc.dll "
compile_gcc{
"elf2cof.cpp",
"macho.cpp",
"cmdline.cpp",
"elf.cpp",
"stdafx.cpp",
"error.cpp",
"omfhash.cpp",
"elf2asm.cpp",
"main.cpp",
"cof2omf.cpp",
"omf2asm.cpp",
"cof2asm.cpp",
"elf2elf.cpp",
"containers.cpp",
"mac2asm.cpp",
"mac2elf.cpp",
"opcodes.cpp",
"cof2elf.cpp",
"omf2cof.cpp",
"library.cpp",
"elf2mac.cpp",
"mac2mac.cpp",
"coff.cpp",
"cof2cof.cpp",
"omf.cpp",
"disasm2.cpp",
"disasm1.cpp",
}
link_gcc("objconv")

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,190 @@
/**************************** cmdline.h ***********************************
* Author: Agner Fog
* Date created: 2006-07-25
* Last modified: 2006-07-25
* Project: objconv
* Module: cmdline.h
* Description:
* Header file for command line interpreter cmdline.cpp
*
* Copyright 2006-2008 GNU General Public License http://www.gnu.org/licenses
*****************************************************************************/
#ifndef CMDLINE_H
#define CMDLINE_H
/************************** Define constants ******************************/
// Max number of response files on command line
#define MAX_COMMAND_FILES 10
// Constants for output file type
#define CMDL_OUTPUT_DUMP 0x80 // No output file, just dump contents
#define CMDL_OUTPUT_ELF FILETYPE_ELF // ELF file
#define CMDL_OUTPUT_PE FILETYPE_COFF // MS-COFF/PE file
#define CMDL_OUTPUT_OMF FILETYPE_OMF // OMF file
#define CMDL_OUTPUT_MACHO FILETYPE_MACHO_LE // Mach-O file, little endian
#define CMDL_OUTPUT_MASM FILETYPE_ASM // Disassembly
// Constants for subtypes
#define SUBTYPE_MASM 0 // Disassembly MASM/TASM
#define SUBTYPE_YASM 1 // Disassembly NASM/YASM
#define SUBTYPE_GASM 2 // Disassembly GAS(Intel)
// Constants for verbose or silent console output
#define CMDL_VERBOSE_NO 0 // Silent. No console output if no errors or warnings
#define CMDL_VERBOSE_YES 1 // Output messages about file names and types
#define CMDL_VERBOSE_DIAGNOSTICS 2 // Output more messages
// Constants for dump options
#define DUMP_NONE 0x0000 // Dump nothing
#define DUMP_FILEHDR 0x0001 // Dump file header
#define DUMP_SECTHDR 0x0002 // Dump section headers
#define DUMP_SYMTAB 0x0010 // Dump symbol table
#define DUMP_RELTAB 0x0020 // Dump relocation table
#define DUMP_STRINGTB 0x0040 // Dump string table
#define DUMP_COMMENT 0x0080 // Dump comment records
// Constants for stripping or converting debug information from file
#define CMDL_DEBUG_DEFAULT 0 // Remove if output is different format
#define CMDL_DEBUG_STRIP 1 // Remove debugging information from file
#define CMDL_DEBUG_PRESERVE 2 // Leave debugging information unchanged
#define CMDL_DEBUG_LINNUM 4 // Convert line number information (not supported)
#define CMDL_DEBUG_SYMBOLS 8 // Convert symbol information (not supported)
// Constants for stripping exception handler information from file
#define CMDL_EXCEPTION_DEFAULT 0 // Remove if output is different format
#define CMDL_EXCEPTION_STRIP 1 // Remove exception handler information from file
#define CMDL_EXCEPTION_PRESERVE 2 // Leave exception handler information unchanged
// Constants for adding/removing leading underscores from symbol names
#define CMDL_UNDERSCORE_NOCHANGE 0 // Don't add or remove underscores
#define CMDL_UNDERSCORE_CHANGE 1 // Change underscores to default for target
#define CMDL_UNDERSCORE_REMOVE 2 // Remove underscores from symbol names
#define CMDL_UNDERSCORE_ADD 3 // Add underscores to symbol names
#define CMDL_KEEP_ALIAS 0x100 // Keep old name as alias
// Constants for replacing leading dot with underscore or vice versa in section names
#define CMDL_SECTIONDOT_NOCHANGE 0 // Don't change section names
#define CMDL_SECTIONDOT_CHANGE 1 // Change leading character in section names to default for target
#define CMDL_SECTIONDOT_U2DOT 2 // Change underscore to dot in section names
#define CMDL_SECTIONDOT_DOT2U 3 // Change dot to underscore in unknown section names
// Constants for library options
#define CMDL_LIBRARY_DEFAULT 0 // No option specified
#define CMDL_LIBRARY_CONVERT 1 // Convert or modify library
#define CMDL_LIBRARY_ADDMEMBER 2 // Add object file to library
#define CMDL_LIBRARY_EXTRACTMEM 0x100 // Extract specified object file(s) from library
#define CMDL_LIBRARY_EXTRACTALL 0x110 // Extract all object files from library
// Constants for file input/output options
#define CMDL_FILE_INPUT 1 // Input file required
#define CMDL_FILE_IN_IF_EXISTS 2 // Read input file if it exists
#define CMDL_FILE_OUTPUT 0x10 // Write output file required
#define CMDL_FILE_IN_OUT_SAME 0x20 // Input and output files may have the same name
#define MAXSYMBOLLENGTH 1024 // Maximum length of symbols for changing underscore or dot
// Constants for symbol type as input to CCommandLineInterpreter::SymbolChange()
#define SYMT_OTHER 0 // File name or unknown symbol type
#define SYMT_SECTION 1 // Segment or section name
#define SYMT_LOCAL 2 // Local symbol (not imported or exported)
#define SYMT_PUBLIC 3 // Public or weak symbol (exported)
#define SYMT_EXTERNAL 4 // External symbol (imported)
#define SYMT_LIBRARYMEMBER 0x1000 // Name of library member
// Constants for symbol change action as defined in SSymbolChange::Action
// and output from CCommandLineInterpreter::SymbolChange()
#define SYMA_NOCHANGE 0 // Do nothing
#define SYMA_MAKE_WEAK 1 // Make symbol weak
#define SYMA_MAKE_LOCAL 2 // Make symbol local
#define SYMA_CHANGE_NAME 0x10 // Change name of symbol
#define SYMA_CHANGE_PREFIX 0x11 // Change beginning of symbol name
#define SYMA_CHANGE_SUFFIX 0x12 // Change end of symbol name
#define SYMA_ALIAS 0x100 // Make alias of public symbol and keep old name, must be combined
// with SYMA_CHANGE_NAME, SYMA_CHANGE_PREFIX or SYMA_CHANGE_SUFFIX
#define SYMA_ADD_MEMBER 0x1001 // Add member to library
#define SYMA_DELETE_MEMBER 0x1002 // Remove member from library
#define SYMA_EXTRACT_MEMBER 0x1004 // Extract member from library
// Structure for specifying desired change of a specific symbol
struct SSymbolChange {
char * Name1; // Symbol name to look for
char * Name2; // Replace with this name
int Action; // Action to take on symbol
int Done; // Count how many times this has been done
};
// Class for interpreting command line
class CCommandLineInterpreter {
public:
CCommandLineInterpreter(); // Default constructor
~CCommandLineInterpreter(); // Destructor
void ReadCommandLine(int argc, char * argv[]); // Read and interpret command line
int SymbolChange(char const * oldname, char const ** newname, int symtype); // Check if symbol has to be changed
int SymbolIsInList(char const * name); // Check if symbol is in SymbolList
int SymbolBinSearch(char const * name, int nsym, int * found);
int SymbolChangesRequested(); // Any kind of symbol change requested on command line
void ReportStatistics(); // Report statistics about name changes etc.
void CountDebugRemoved(); // Increment CountDebugSectionsRemoved
void CountExceptionRemoved(); // Increment CountExceptionSectionsRemoved
void CountSymbolsHidden(); // Increment CountUnusedSymbolsHidden
SSymbolChange const * GetMemberToAdd(); // Get names of object files to add to library
void CheckExtractSuccess(); // Check if library members to extract were found
void CheckSymbolModifySuccess(); // Check if symbols to modify were found
char * InputFile; // Input file name
char * OutputFile; // Output file name
int InputType; // Input file type (detected from file)
int OutputType; // Output type (file type or dump)
int SubType; // Subtype of output type. Assembly language dialect or library type
int MemberType; // File type of library members
int DesiredWordSize; // Desired word size for output file
uint32 Verbose; // How much diagnostics to print on screen
uint32 DumpOptions; // Options for dumping file
uint32 DebugInfo; // Strip or convert debug info
uint32 ExeptionInfo; // Strip or preserve exception handler info and other incompatible info
uint32 Underscore; // Add/remove underscores in symbol names
uint32 SegmentDot; // Change underscore/dot in beginning of segment names
uint32 LibraryOptions; // Options for manipulating library
uint32 LibrarySubtype; // Options for manipulating library
uint32 FileOptions; // Options for input and output files
uint32 ImageBase; // Specified image base
int ShowHelp; // Help screen printed
protected:
int libmode; // -lib option has been encountered
void ReadCommandItem(char *); // Read one option from command line
void ReadCommandFile(char *); // Read commands from file
void InterpretFileName(char *); // Interpret input or output filename from command line
void InterpretCommandOption(char *); // Interpret one option from command line
void InterpretOutputTypeOption(char *); // Interpret output type option from command line
void InterpretVerboseOption(char *); // Interpret silent/verbose option from command line
void InterpretDumpOption(char *); // Interpret dump option from command line
void InterpretDebugInfoOption(char *); // Interpret debug info option from command line
void InterpretExceptionInfoOption(char*); // Interpret exception handler info option from command line
void InterpretErrorOption(char *); // Interpret error option from command line
void InterpretSymbolNameChangeOption(char *); // Interpret various options for changing symbol names
void InterpretLibraryOption(char *); // Interpret options for manipulating library/archive files
void InterpretImagebaseOption(char *); // Interpret image base option
void AddObjectToLibrary(char * filename, char * membername); // Add object file to library
void Help(); // Print help message
CArrayBuf<CFileBuffer> ResponseFiles; // Array of up to 10 response file buffers
int NumBuffers; // Number of response file buffers
int SymbolChangeEntries; // Number of entries in SymbolList, except library entries
CMemoryBuffer SymbolList; // List of symbol names to change. Contains entries of type SSymbolChange. Kept in sorted order
CMemoryBuffer PrefixSuffixList; // List of prefix/suffix to change. Contains entries of type SSymbolChange
CMemoryBuffer MemberNames; // Buffer containing truncated member names
uint32 MemberNamesAllocated; // Size of buffer in MemberNames
uint32 CurrentSymbol; // Pointer into SymbolList
// Statistics counters
int CountUnderscoreConversions; // Count number of times symbol leading underscores are changed
int CountSectionDotConversions; // Count number of times leading character is changed on section names
int CountSymbolNameChanges; // Count number of times symbol names are changed at specific command
int CountSymbolNameAliases; // Count number of times symbol names are aliased at specific command or underscore command
int CountSymbolsWeakened; // Count number of times symbol names are made weak at specific command
int CountSymbolsMadeLocal; // Count number of times symbol names are made local at specific command
int CountUnusedSymbolsHidden; // Count number of times unused symbols are hidden
int CountDebugSectionsRemoved; // Count number of debug sections removed
int CountExceptionSectionsRemoved; // Count number of exception handler sections removed
};
extern CCommandLineInterpreter cmd; // Command line interpreter
#endif // #ifndef CMDLINE_H

View File

@ -0,0 +1,529 @@
/**************************** cof2asm.cpp ********************************
* Author: Agner Fog
* Date created: 2007-02-25
* Last modified: 2009-12-20
* Project: objconv
* Module: cof2asm.cpp
* Description:
* Module for disassembling PE/COFF file
*
* Copyright 2007-2009 GNU General Public License http://www.gnu.org/licenses
*****************************************************************************/
#include "stdafx.h"
CCOF2ASM::CCOF2ASM () {
// Constructor
}
void CCOF2ASM::Convert() {
// Do the conversion
if (ImageBase) Disasm.Init(2, ImageBase); // Executable file or DLL. Set image base
MakeSectionList(); // Make Sections list and Relocations list in Disasm
MakeSymbolList(); // Make Symbols list in Disasm
if (ImageBase) {
// Executable file
MakeDynamicRelocations(); // Make dynamic base relocations for executable files
MakeImportList(); // Make imported symbols for executable files
MakeExportList(); // Make exported symbols for executable files
MakeListLabels(); // Put labels on all image directory tables
}
Disasm.Go(); // Disassemble
*this << Disasm.OutFile; // Take over output file from Disasm
}
void CCOF2ASM::MakeSectionList() {
// Make Sections list and Relocations list in Disasm
uint32 isec; // Section index
uint32 irel; // Relocation index
// Loop through sections
for (isec = 0; isec < (uint32)NSections; isec++) {
// Get section header
SCOFF_SectionHeader * SectionHeader = &SectionHeaders[isec];
// Section properties
const char * Name = GetSectionName(SectionHeader->Name);
uint8 * Buffer = (uint8*)Buf() + SectionHeader->PRawData;
uint32 InitSize = SectionHeader->SizeOfRawData;
uint32 TotalSize = SectionHeader->VirtualSize;
uint32 SectionAddress = SectionHeader->VirtualAddress;
uint32 Type = (SectionHeader->Flags & PE_SCN_CNT_CODE) ? 1 : 2;
if (SectionHeader->Flags & PE_SCN_CNT_UNINIT_DATA) {
// BSS segment. No data in file
Buffer = 0;
Type = 3;
}
else if (!(SectionHeader->Flags & (PE_SCN_MEM_WRITE | PE_SCN_MEM_EXECUTE))) {
// Constant segment
Type = 4;
}
if (SectionHeader->Flags & PE_SCN_LNK_COMDAT) {
// Communal section
Type |= 0x1000;
}
if (strnicmp(Name,"debug",5) == 0 || strnicmp(Name+1,"debug",5) == 0) {
// This is a debug section
Type = 0x10;
}
if (strnicmp(Name,".pdata", 6) == 0) {
// This section has exception information
Type = 0x11;
}
uint32 Align = (SectionHeader->Flags & PE_SCN_ALIGN_MASK) / PE_SCN_ALIGN_1;
if (Align) Align--;
// Save section record
Disasm.AddSection(Buffer, InitSize, TotalSize, SectionAddress, Type, Align, WordSize, Name);
// Get relocations
// Pointer to relocation entry
union {
SCOFF_Relocation * p; // pointer to record
int8 * b; // used for address calculation and incrementing
} Reloc;
Reloc.b = Buf() + SectionHeader->PRelocations;
for (irel = 0; irel < SectionHeader->NRelocations; irel++, Reloc.b += SIZE_SCOFF_Relocation) {
// Relocation properties
int32 Section = isec + 1;
uint32 Offset = Reloc.p->VirtualAddress;
int32 Addend = 0;
uint32 TargetIndex = Reloc.p->SymbolTableIndex;
// Translate relocation type
uint32 Type = 0, Size = 0;
if (WordSize == 32) {
// 32 bit relocation types
// 0 = unknown, 1 = direct, 2 = self-relative, 3 = image-relative, 4 = segment relative
switch(Reloc.p->Type) {
case COFF32_RELOC_ABS: // Ignore
continue;
case COFF32_RELOC_DIR32: // Direct, 32 bits
Type = 1;
Size = 4;
break;
case COFF32_RELOC_REL32: // Self-relative, 32 bits
Type = 2;
Size = 4;
Addend = -4;
break;
case COFF32_RELOC_IMGREL: // Image relative, 32 bits
Type = 4;
Size = 4;
break;
case COFF32_RELOC_SECREL: // Section relative, 32 bits
Type = 8;
Size = 4;
break;
case COFF32_RELOC_SECTION: // Section index of symbol, 16 bits
Type = 0x200;
Size = 2;
break;
default: // Other/unknown
Type = 0;
Size = 4;
}
}
else { // WordSize = 64
switch(Reloc.p->Type) {
case COFF64_RELOC_ABS: // Ignore
continue;
case COFF64_RELOC_ABS32: // Absolute 32 bit
Type = 1;
Size = 4;
break;
case COFF64_RELOC_ABS64: // Absolute 64 bit
Type = 1;
Size = 8;
break;
case COFF64_RELOC_IMGREL: // Image relative 32 bit
Type = 4;
Size = 4;
break;
case COFF64_RELOC_REL32: // Self-relative, 32 bits
case COFF64_RELOC_REL32_1: // Self-relative + 1
case COFF64_RELOC_REL32_2: // Self-relative + 2
case COFF64_RELOC_REL32_3: // Self-relative + 3
case COFF64_RELOC_REL32_4: // Self-relative + 4
case COFF64_RELOC_REL32_5: // Self-relative + 5
Type = 2;
Size = 4;
Addend = - (Reloc.p->Type + 4 - COFF64_RELOC_REL32);
break;
case COFF64_RELOC_SECREL: // Section relative
Type = 8;
Size = 4;
break;
default: // Other/unknown
Type = 0;
Size = 4;
}
}
// Save relocation record
Disasm.AddRelocation(Section, Offset, Addend, Type, Size, TargetIndex);
}
}
}
void CCOF2ASM::MakeSymbolList() {
// Make Symbols list in Disasm
uint32 isym; // Symbol index
uint32 naux = 0; // Number of auxiliary entries in old symbol table
union { // Pointer to old symbol table entries
SCOFF_SymTableEntry * p; // Normal pointer
int8 * b; // Used for address calculation
} Sym, SymAux;
// Set pointer to old SymbolTable
Sym.p = SymbolTable;
// Loop through old symbol table
for (isym = 0; isym < (uint32)NumberOfSymbols; isym += 1+naux, Sym.b += (1+naux) * SIZE_SCOFF_SymTableEntry) {
// Number of auxiliary entries
naux = Sym.p->s.NumAuxSymbols;
if (Sym.p->s.SectionNumber != COFF_SECTION_ABSOLUTE
&& (Sym.p->s.SectionNumber < 0
|| (Sym.p->s.StorageClass != COFF_CLASS_EXTERNAL && Sym.p->s.StorageClass != COFF_CLASS_STATIC && Sym.p->s.StorageClass != COFF_CLASS_LABEL))) {
// Ignore irrelevant symbol table entries
continue;
}
// Symbol properties
uint32 Index = isym;
int32 Section = Sym.p->s.SectionNumber;
uint32 Offset = Sym.p->s.Value;
uint32 Size = 0;
uint32 Type = (Sym.p->s.Type == COFF_TYPE_FUNCTION) ? 0x83 : 0;
// Identify segment entries in symbol table
if (Sym.p->s.Value == 0 && Sym.p->s.StorageClass == COFF_CLASS_STATIC
&& naux && Sym.p->s.Type != 0x20) {
// Note: The official MS specification says that a symbol table entry
// is a section if the storage class is static and the value is 0,
// but I have encountered static functions that meet these criteria.
// Therefore, I am also checking Type and naux.
Type = 0x80000082;
}
const char * Name = GetSymbolName(Sym.p->s.Name);
// Get scope. Note that these values are different from the constants defined in maindef.h
uint32 Scope = 0;
if (Sym.p->s.StorageClass == COFF_CLASS_STATIC || Sym.p->s.StorageClass == COFF_CLASS_LABEL) {
Scope = 2; // Local
}
else if (Sym.p->s.SectionNumber > 0 || (Sym.p->s.SectionNumber == -1 && Sym.p->s.StorageClass == COFF_CLASS_EXTERNAL)) {
Scope = 4; // Public
}
else {
Scope = 0x20; // External
}
// Check auxiliary symbol table entries
if (naux && Sym.p->s.Type == COFF_TYPE_FUNCTION) {
// Function symbol has auxiliary entry. Get information about size
SymAux.b = Sym.b + SIZE_SCOFF_SymTableEntry;
Size = SymAux.p->func.TotalSize;
}
// Check for special section values
if (Section < 0) {
if (Section == COFF_SECTION_ABSOLUTE) {
// Symbol is an absolute constant
Section = ASM_SEGMENT_ABSOLUTE;
}
else {
// Debug symbols, etc
Section = ASM_SEGMENT_ERROR;
}
}
// Store new symbol record
Disasm.AddSymbol(Section, Offset, Size, Type, Scope, Index, Name);
}
}
void CCOF2ASM::MakeDynamicRelocations() {
// Make dynamic base relocations for executable files
// Find base relocation table
SCOFF_ImageDirAddress reldir;
if (!GetImageDir(5, &reldir)) {
// No base relocation table found
return;
}
SCOFF_BaseRelocationBlock * pBaseRelocation; // Start of dynamic base relocation section
// Beginning of .reloc section is first base relocation block
pBaseRelocation = &Get<SCOFF_BaseRelocationBlock>(reldir.FileOffset);
uint32 ROffset = 0; // Offset into .reloc section
uint32 BlockEnd; // Offset of end of current block
uint32 PageOffset; // Image-relative address of begin of page
// Make pointer to header or entry in .reloc section
union {
SCOFF_BaseRelocationBlock * header;
SCOFF_BaseRelocation * entry;
int8 * b;
} Pointer;
// Loop throung .reloc section
// while (ROffset < reldir.MaxOffset) {
while (ROffset < reldir.Size) {
// Set Pointer to current position
Pointer.header = pBaseRelocation;
Pointer.b += ROffset;
// Read base relocation block
PageOffset = Pointer.header->PageRVA;
BlockEnd = ROffset + Pointer.header->BlockSize;
// Read entries in this block
ROffset += sizeof(SCOFF_BaseRelocationBlock);
Pointer.b += sizeof(SCOFF_BaseRelocationBlock);
// Loop through entries
while (ROffset < BlockEnd) {
// Set Pointer to current position
Pointer.header = pBaseRelocation;
Pointer.b += ROffset;
if (Pointer.entry->Type == COFF_REL_BASED_HIGHLOW) {
// Add relocation record, 32 bit
// Section = ASM_SEGMENT_IMGREL means offset is image-relative
// Type = 0x20 means already relocated to image base
Disasm.AddRelocation(ASM_SEGMENT_IMGREL, Pointer.entry->Offset + PageOffset, 0, 0x21, 4, 0);
}
else if (Pointer.entry->Type == COFF_REL_BASED_DIR64) {
// Add relocation record, 64 bit
Disasm.AddRelocation(ASM_SEGMENT_IMGREL, Pointer.entry->Offset + PageOffset, 0, 0x21, 8, 0);
}
// Go to next
ROffset += sizeof(SCOFF_BaseRelocation);
if (Pointer.entry->Type == COFF_REL_BASED_HIGHADJ) ROffset += sizeof(SCOFF_BaseRelocation);
}
// Finished block. Align by 4
ROffset = (ROffset + 3) & uint32(-4);
}
}
void CCOF2ASM::MakeImportList() {
// Make imported symbols for executable files
// Find import table
SCOFF_ImageDirAddress impdir;
if (!GetImageDir(1, &impdir)) {
// No import table found
return;
}
// Beginning of import section is import directory
SCOFF_ImportDirectory * pImportDirectory = &Get<SCOFF_ImportDirectory>(impdir.FileOffset);
// Check if 64 bit
int Is64bit = OptionalHeader->h64.Magic == COFF_Magic_PE64; // 1 if 64 bit
uint32 EntrySize = Is64bit ? 8 : 4; // Size of address table entries
uint32 NameOffset; // Offset to name
const char * SymbolName; // Name of symbol
const char * DLLName; // Name of DLL containing symbol
char NameBuffer[64]; // Buffer for creating name of ordinal symbols
uint32 SectionOffset; // Section-relative address of current entry
uint32 HintNameOffset; // Section-relative address of hint/name table
uint32 FirstHintNameOffset = 0; // First HintNameOffset = start of hint/name table
uint32 AddressTableOffset; // Offset of import address table relative to import lookup table
// Pointer to current import directory entry
SCOFF_ImportDirectory * ImportEntry = pImportDirectory;
// Pointer to current import lookup table entry
int32 * LookupEntry = 0;
// Pointer to current hint/name table entry
SCOFF_ImportHintName * HintNameEntry;
// Loop through import directory until null entry
while (ImportEntry->DLLNameRVA) {
// Get DLL name
NameOffset = ImportEntry->DLLNameRVA - impdir.VirtualAddress;
if (NameOffset < impdir.MaxOffset) {
DLLName = &Get<char>(impdir.FileOffset + NameOffset);
}
else {
DLLName = "?";
}
// Get lookup table
SectionOffset = ImportEntry->ImportLookupTableRVA;
if (SectionOffset == 0) SectionOffset = ImportEntry->ImportAddressTableRVA;
if (SectionOffset == 0) continue;
// Get distance from import lookup table to import address table
AddressTableOffset = ImportEntry->ImportAddressTableRVA - SectionOffset;
// Section relative address
SectionOffset -= impdir.VirtualAddress;
if (SectionOffset >= impdir.MaxOffset) break; // Out of range
// Loop through lookup table
while (1) {
// Pointer to lookup table entry
LookupEntry = &Get<int32>(impdir.FileOffset + SectionOffset);
// End when entry is empty
if (!LookupEntry[0]) break;
if (LookupEntry[Is64bit] < 0) {
// Imported by ordinal. Give it a name
strncpy(NameBuffer, DLLName, 20);
// Remove dot from name
char * dot = strchr(NameBuffer,'.');
if (dot) *dot = 0;
// Add ordinal number to name
sprintf(NameBuffer+strlen(NameBuffer), "_Ordinal_%i", uint16(LookupEntry[0]));
SymbolName = NameBuffer;
}
else {
// Find entry in hint/name table
HintNameOffset = (LookupEntry[0] & 0x7FFFFFFF) - impdir.VirtualAddress;
if (HintNameOffset >= impdir.MaxOffset) goto LOOPNEXT; // Out of range
if (!FirstHintNameOffset) FirstHintNameOffset = HintNameOffset;
HintNameEntry = &Get<SCOFF_ImportHintName>(impdir.FileOffset + HintNameOffset);
// Get name
SymbolName = HintNameEntry->Name;
}
// Add symbol
Disasm.AddSymbol(ASM_SEGMENT_IMGREL, impdir.VirtualAddress + SectionOffset + AddressTableOffset,
EntrySize, 0xC, 0x20, 0, SymbolName, DLLName);
// Loop next
LOOPNEXT:
SectionOffset += EntrySize;
}
// Loop next
ImportEntry++;
}
// Make label for import name table
if (FirstHintNameOffset) {
Disasm.AddSymbol(ASM_SEGMENT_IMGREL, impdir.VirtualAddress + FirstHintNameOffset, 1, 1, 1, 0, "Import_name_table");
}
}
void CCOF2ASM::MakeExportList() {
// Make exported symbols for executable files
// Define entry point
if (OptionalHeader->h32.AddressOfEntryPoint) {
Disasm.AddSymbol(ASM_SEGMENT_IMGREL, OptionalHeader->h32.AddressOfEntryPoint, 0, 0x83, 4, 0, "Entry_point");
}
// Get export table directory address
SCOFF_ImageDirAddress expdir;
// Exported names
if (!GetImageDir(0, &expdir)) {
// No export directory
return;
}
// Beginning of export section is export directory
SCOFF_ExportDirectory * pExportDirectory = &Get<SCOFF_ExportDirectory>(expdir.FileOffset);
// Find ExportAddressTable
uint32 ExportAddressTableOffset = pExportDirectory->ExportAddressTableRVA - expdir.VirtualAddress;
if (ExportAddressTableOffset == 0 || ExportAddressTableOffset >= expdir.MaxOffset) {
// Points outside section
err.submit(2035); return;
}
uint32 * pExportAddressTable = &Get<uint32>(expdir.FileOffset + ExportAddressTableOffset);
// Find ExportNameTable
if (pExportDirectory->NamePointerTableRVA == 0) {
return; // I don't know why this happens
}
uint32 ExportNameTableOffset = pExportDirectory->NamePointerTableRVA - expdir.VirtualAddress;
if (ExportNameTableOffset == 0 || ExportNameTableOffset >= expdir.MaxOffset) {
// Points outside section
err.submit(2035); return;
}
uint32 * pExportNameTable = &Get<uint32>(expdir.FileOffset + ExportNameTableOffset);
// Find ExportOrdinalTable
uint32 ExportOrdinalTableOffset = pExportDirectory->OrdinalTableRVA - expdir.VirtualAddress;
if (ExportOrdinalTableOffset == 0 || ExportOrdinalTableOffset >= expdir.MaxOffset) {
// Points outside section
err.submit(2035); return;
}
uint16 * pExportOrdinalTable = &Get<uint16>(expdir.FileOffset + ExportOrdinalTableOffset);
// Get further properties
uint32 NumExports = pExportDirectory->AddressTableEntries;
uint32 NumExportNames = pExportDirectory->NamePointerEntries;
uint32 OrdinalBase = pExportDirectory->OrdinalBase;
uint32 i; // Index into pExportOrdinalTable and pExportNameTable
uint32 Ordinal; // Index into pExportAddressTable
uint32 Address; // Image-relative address of symbol
uint32 NameOffset; // Section-relative address of name
uint32 FirstName = 0; // Image-relative address of first name table entry
const char * Name = 0; // Name of symbol
char NameBuffer[64]; // Buffer for making name
// Loop through export tables
for (i = 0; i < NumExports; i++) {
Address = 0;
Name = "?";
// Get ordinal from table
Ordinal = pExportOrdinalTable[i];
// Address table is indexed by ordinal
if (Ordinal < NumExports) {
Address = pExportAddressTable[Ordinal];
}
// Find name if there is a name list entry
if (i < NumExportNames) {
NameOffset = pExportNameTable[i] - expdir.VirtualAddress;
if (NameOffset && NameOffset < expdir.MaxOffset) {
Name = &Get<char>(expdir.FileOffset + NameOffset);
if (FirstName == 0) FirstName = pExportNameTable[i];
}
}
else {
// No name. Make name from ordinal number
sprintf(NameBuffer, "Ordinal_%i", Ordinal + OrdinalBase);
Name = NameBuffer;
}
// Define symbol
Disasm.AddSymbol(ASM_SEGMENT_IMGREL, Address, 0, 0x83, 4, 0, Name);
}
// Make label for export section
Disasm.AddSymbol(ASM_SEGMENT_IMGREL, expdir.VirtualAddress, 4, 3, 2, 0, "Export_tables");
// Make labels for export tables
Disasm.AddSymbol(ASM_SEGMENT_IMGREL, ExportAddressTableOffset - expdir.FileOffset + expdir.VirtualAddress, 4, 3, 2, 0, "Export_address_table");
Disasm.AddSymbol(ASM_SEGMENT_IMGREL, ExportOrdinalTableOffset - expdir.FileOffset + expdir.VirtualAddress, 4, 3, 2, 0, "Export_ordinal_table");
Disasm.AddSymbol(ASM_SEGMENT_IMGREL, ExportNameTableOffset - expdir.FileOffset + expdir.VirtualAddress, 4, 3, 2, 0, "Export_name_pointer_table");
Disasm.AddSymbol(ASM_SEGMENT_IMGREL, FirstName, 1, 1, 2, 0, "Export_name_table");
}
void CCOF2ASM::MakeListLabels() {
// Attach names to all image directories
SCOFF_ImageDirAddress dir;
uint32 i;
for (i = 0; i < NumImageDirs; i++) {
if (GetImageDir(i, &dir)) {
// Found a directory. Make label for it
Disasm.AddSymbol(ASM_SEGMENT_IMGREL, dir.VirtualAddress, 4, 0, 1, 0, dir.Name);
}
}
}

View File

@ -0,0 +1,306 @@
/**************************** cof2cof.cpp *********************************
* Author: Agner Fog
* Date created: 2006-07-28
* Last modified: 2006-07-28
* Project: objconv
* Module: cof2cof.cpp
* Description:
* Module for changing symbol names in PE/COFF file
*
* Copyright 2006-2008 GNU General Public License http://www.gnu.org/licenses
*****************************************************************************/
#include "stdafx.h"
CCOF2COF::CCOF2COF () {
// Constructor
}
void CCOF2COF::Convert() {
// Do the conversion
// Call the subfunctions
MakeSymbolTable(); // Symbol table and string tables
MakeBinaryFile(); // Putting sections together
*this << ToFile; // Take over new file buffer
}
void CCOF2COF::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 symboltype = 0; // Symbol type
int action = 0; // Symbol change action
int isec; // Section number
const char * name1; // Old name of symbol
const char * name2; // Changed name of symbol
const char * name3; // New name to store
// Pointer to old symbol table
union {
SCOFF_SymTableEntry * p; // Symtab entry pointer
int8 * b; // Used for increment
} OldSymtab;
// Initialize new string table. Make space for size
NewStringTable.Push(0, 4);
// Loop through source symbol table
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;
// Get first aux record if numaux > 0
SCOFF_SymTableEntry * sa = (SCOFF_SymTableEntry *)(OldSymtab.b + SIZE_SCOFF_SymTableEntry);
// Check symbol type
if (numaux && OldSymtab.p->s.StorageClass == COFF_CLASS_STATIC) {
// This is a section definition record
// aux record contains length and number of relocations. Ignore aux record
symboltype = SYMT_SECTION;
name1 = GetSymbolName(OldSymtab.p->s.Name);
}
else if (OldSymtab.p->s.StorageClass == COFF_CLASS_FILE) {
// This is a filename record
symboltype = SYMT_OTHER;
name1 = GetShortFileName(OldSymtab.p);
// or long file name ?!
}
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
name1 = 0;
}
else {
// This is a symbol record
// Symbol name
name1 = GetSymbolName(OldSymtab.p->s.Name);
if (OldSymtab.p->s.StorageClass == COFF_CLASS_EXTERNAL) {
// This is a public or external symbol
if (OldSymtab.p->s.SectionNumber <= 0) {
// This is an external symbol
symboltype = SYMT_EXTERNAL;
}
else {
// This is a public symbol
symboltype = SYMT_PUBLIC;
}
}
else {
// This is a local symbol
symboltype = SYMT_LOCAL;
}
}
name3 = name1;
// Check if any change required for this symbol
action = cmd.SymbolChange(name1, &name2, symboltype);
switch (action) {
case SYMA_NOCHANGE:
// No change
break;
case SYMA_MAKE_WEAK:
// Make symbol weak
if (cmd.OutputType == FILETYPE_COFF) {
// PE/COFF format does not support weak publics. Use this only when converting to ELF
err.submit(2200);
}
// Make weak when converting to ELF
OldSymtab.p->s.StorageClass = COFF_CLASS_WEAK_EXTERNAL;
break;
case SYMA_MAKE_LOCAL:
// Make public symbol local, make external symbol ignored
OldSymtab.p->s.StorageClass = COFF_CLASS_STATIC;
break;
case SYMA_CHANGE_NAME:
// Change name of symbol
if (OldSymtab.p->s.StorageClass == COFF_CLASS_FILE) {
// File name is stored in aux records, not in symbol table
if ((uint32)strlen(name2) > (uint32)numaux * SIZE_SCOFF_SymTableEntry) {
// Name too long. I don't want to add more aux records
err.submit(2201, name2);
}
else {
// Insert new file name in aux records
memset(sa, 0, numaux * SIZE_SCOFF_SymTableEntry);
memcpy(sa, name2, strlen(name2));
}
}
else {
// Symbol name stored in normal way
name3 = name2;
}
break;
case SYMA_ALIAS: {
// Make alias and keep old name
SCOFF_SymTableEntry AliasEntry = *OldSymtab.p;
AliasEntry.s.Type = 0; // Make alias a label, not a function
AliasEntry.s.NumAuxSymbols = 0; // No auxiliary .bf and .ef records
// Put new name into AliasEntry
memset(AliasEntry.s.Name, 0, 8);
if (strlen(name2) > 8) {
// Long name. use string table
// Store string table offset
((uint32 *)(AliasEntry.s.Name))[1] = NewStringTable.GetDataSize();
// Put name into new string table
NewStringTable.PushString(name2);
}
else {
// Short name. Store in record
memcpy(AliasEntry.s.Name, name2, strlen(name2));
}
// Add new entry to extra symbol table
NewSymbolTable.Push(&AliasEntry, SIZE_SCOFF_SymTableEntry);
break;}
default:
err.submit(9000); // unknown error
}
if (name3 && OldSymtab.p->s.StorageClass != COFF_CLASS_FILE) {
// Store old or new name
if (strlen(name3) > 8) {
// Name is long. use string table
// Type-case Name field to string table entry
uint32 * LongNameStorage = (uint32 *)(OldSymtab.p->s.Name);
// Start with 0 to indicate long name
LongNameStorage[0] = 0;
// Index into new string table
LongNameStorage[1] = NewStringTable.GetDataSize();
// Put name into new string table
NewStringTable.PushString(name3);
}
else {
if (name3 != name1) {
// Store new name in Name field
memset(OldSymtab.p->s.Name, 0, 8);
memcpy(OldSymtab.p->s.Name, name3, strlen(name3));
}
}
}
} // End symbol table loop
// Loop through section headers to search for section names
uint32 SectionOffset = sizeof(SCOFF_FileHeader) + FileHeader->SizeOfOptionalHeader;
for (isec = 0; isec < NSections; isec++) {
SCOFF_SectionHeader * pSectHeader;
pSectHeader = &Get<SCOFF_SectionHeader>(SectionOffset);
SectionOffset += sizeof(SCOFF_SectionHeader);
// Get section name
name1 = GetSectionName(pSectHeader->Name);
// Check if change required
action = cmd.SymbolChange(name1, &name2, SYMT_SECTION);
if (action == SYMA_CHANGE_NAME) name1 = name2;
// Store name (changed or unchanged)
memset(pSectHeader->Name, 0, 8);
if (strlen(name1) <= 8) {
// Short name. Store in section header
memcpy(pSectHeader->Name, name1, strlen(name1));
}
else {
// Long name. Store in string table
sprintf(pSectHeader->Name, "/%i", NewStringTable.GetDataSize());
//pSectHeader->Name[0] = '/';
//itoa(NewStringTable.GetDataSize(), pSectHeader->Name+1, 10);
NewStringTable.PushString(name1);
}
}
}
void CCOF2COF::MakeBinaryFile() {
// Convert subfunction: Combine everything into the new binary file
int i;
// New file header = copy of old file header
SCOFF_FileHeader NewFileHeader = *FileHeader;
ToFile.SetFileType(FILETYPE_COFF); // Set type of output file
ToFile.WordSize = WordSize;
ToFile.FileName = FileName;
// Copy file header, section headers and sections to new file
ToFile.Push(Buf(), NewFileHeader.PSymbolTable);
// Copy symbol table
ToFile.Push(SymbolTable, NumberOfSymbols * SIZE_SCOFF_SymTableEntry);
// Additions to symbol table
int NumAddedSymbols = NewSymbolTable.GetNumEntries();
if (NumAddedSymbols) {
// Append to symbols table
ToFile.Push(NewSymbolTable.Buf(), NumAddedSymbols * SIZE_SCOFF_SymTableEntry);
// Update NumberOfSymbols in file header
NewFileHeader.NumberOfSymbols += NumAddedSymbols;
}
// Insert new string table
uint32 NewStringTableSize = NewStringTable.GetDataSize();
// First 4 bytes = size
ToFile.Push(&NewStringTableSize, sizeof(uint32));
// Then the string table itself, except the first 4 bytes
if (NewStringTableSize > 4)
ToFile.Push(NewStringTable.Buf() + 4, NewStringTableSize - 4);
// Find end of old and new string tables
uint32 EndOfOldStringTable = FileHeader->PSymbolTable
+ NumberOfSymbols * SIZE_SCOFF_SymTableEntry + StringTableSize;
uint32 EndOfNewStringTable = FileHeader->PSymbolTable
+ (NumberOfSymbols + NumAddedSymbols) * SIZE_SCOFF_SymTableEntry + NewStringTableSize;
// Check if there is anything after the string table
if (GetDataSize() > EndOfOldStringTable) {
// Old file has something after the string table
if (EndOfNewStringTable < EndOfOldStringTable) {
// New symboltable + string table smaller than old
// Fill the space with zeroes so that the data that come after the string table
// will have the same address as before
ToFile.Push(0, EndOfOldStringTable - EndOfNewStringTable);
EndOfNewStringTable = EndOfOldStringTable;
}
// Copy the data that come after the string table
ToFile.Push(Buf() + EndOfOldStringTable, GetDataSize() - EndOfOldStringTable);
if (EndOfNewStringTable > EndOfOldStringTable) {
// New symboltable + string table bigger than old
// Find all references to the data that come after the string table and fix them
// Search all section headers
uint32 SectionOffset = sizeof(SCOFF_FileHeader) + NewFileHeader.SizeOfOptionalHeader;
for (i = 0; i < NSections; i++) {
SCOFF_SectionHeader * pSectHeader;
pSectHeader = &Get<SCOFF_SectionHeader>(SectionOffset);
SectionOffset += sizeof(SCOFF_SectionHeader);
if (pSectHeader->PRawData >= EndOfOldStringTable && pSectHeader->PRawData <= GetDataSize()) {
pSectHeader->PRawData += EndOfNewStringTable - EndOfOldStringTable;
}
if (pSectHeader->PRelocations >= EndOfOldStringTable && pSectHeader->PRawData <= GetDataSize()) {
pSectHeader->PRelocations += EndOfNewStringTable - EndOfOldStringTable;
} if (pSectHeader->PLineNumbers >= EndOfOldStringTable && pSectHeader->PRawData <= GetDataSize()) {
pSectHeader->PLineNumbers += EndOfNewStringTable - EndOfOldStringTable;
}
}
}
}
// Update file header
memcpy(ToFile.Buf(), &NewFileHeader, sizeof(NewFileHeader));
// Note: The checksum in the optional header may need to be updated.
// This is relevant for DLL's only. The checksum algorithm is undisclosed and
// must be calculated with IMAGHELP.DLL. You may add a calculation of the checksum
// here if you want the program to be able to change names in a Windows DLL,
// but the program will then only be able to compile under Windows.
}

View File

@ -0,0 +1,826 @@
/**************************** 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 <class TELF_Header, class TELF_SectionHeader, class TELF_Symbol, class TELF_Relocation>
CCOF2ELF<ELFSTRUCTURES>::CCOF2ELF () {
// Constructor
memset(this, 0, sizeof(*this));
}
template <class TELF_Header, class TELF_SectionHeader, class TELF_Symbol, class TELF_Relocation>
void CCOF2ELF<ELFSTRUCTURES>::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 <class TELF_Header, class TELF_SectionHeader, class TELF_Symbol, class TELF_Relocation>
void CCOF2ELF<ELFSTRUCTURES>::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 <class TELF_Header, class TELF_SectionHeader, class TELF_Symbol, class TELF_Relocation>
void CCOF2ELF<ELFSTRUCTURES>::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 <class TELF_Header, class TELF_SectionHeader, class TELF_Symbol, class TELF_Relocation>
void CCOF2ELF<ELFSTRUCTURES>::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 <class TELF_Header, class TELF_SectionHeader, class TELF_Symbol, class TELF_Relocation>
void CCOF2ELF<ELFSTRUCTURES>::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<ELF32STRUCTURES>;
template class CCOF2ELF<ELF64STRUCTURES>;

View File

@ -0,0 +1,803 @@
/**************************** cof2omf.cpp ********************************
* Author: Agner Fog
* Date created: 2007-02-03
* Last modified: 2007-02-03
* Project: objconv
* Module: cof2omf.cpp
* Description:
* Module for converting 32 bit PE/COFF file to OMF file
*
* Copyright 2007-2008 GNU General Public License http://www.gnu.org/licenses
*****************************************************************************/
#include "stdafx.h"
CCOF2OMF::CCOF2OMF () {
// Constructor
memset(this, 0, sizeof(*this));
}
void CCOF2OMF::Convert() {
// Do the conversion
if (WordSize != 32) {
err.submit(2317, WordSize); // Wrong word size
return;
}
// Allocate variable size buffers
SectionBuffer.SetNum(NSections + 2); // Allocate buffer for section translation list
SectionBuffer.SetZero(); // Initialize
SymbolBuffer.SetNum(NumberOfSymbols + 1); // Allocate buffer for symbol translation list
SymbolBuffer.SetZero(); // Initialize
NameBuffer.Push(0, 1); // Make first entry in NameBuffer empty
// Call the subfunctions
ToFile.SetFileType(FILETYPE_OMF); // Set type of output file
MakeSegmentList(); // Make temporary segment conversion list
MakeSymbolList(); // Make temporary symbol conversion list
MakeRelocationsList(); // Make temporary list of relocations (fixups) and sort it
MakeLNAMES(); // Make THEADR and LNAMES records
MakeSEGDEF(); // Make SEGDEF and GRPDEF records
MakeEXTDEF(); // Make EXTDEF records
MakePUBDEF(); // Make PUBDEF records
MakeLEDATA(); // Make LEDATA, LIDATA and FIXUPP records
MakeMODEND(); // Finish output file
*this << ToFile; // Take over new file buffer containing the converted file
}
void CCOF2OMF::MakeSegmentList() {
// Make temporary segment conversion list
const char * oldname; // Old name of section
uint32 namei; // Name index into NameBuffer
uint32 align; // Segment alignment = 2^align
int32 align2; // align2 = 2^align
uint32 flags; // Old flags
int i, j; // Loop counters
int oldsec; // Old section number
// Loop through old sections
for (j = 0; j < NSections; j++) {
// Old section number
oldsec = j + 1;
// Get old section header
SCOFF_SectionHeader * pSectionHeader = &SectionHeaders[j];
// Get name
oldname = GetSectionName(pSectionHeader->Name);
// Check for debug sections
if (strnicmp(oldname,"debug",5) == 0 || strnicmp(oldname+1,"debug",5) == 0) {
// This is a debug section
if (cmd.DebugInfo == CMDL_DEBUG_STRIP) {
// Remove debug info
SectionBuffer[oldsec].NewNumber = 0;
cmd.CountDebugRemoved();
continue;
}
else if (cmd.InputType != cmd.OutputType) {
err.submit(1029); // Warn that debug information is incompatible
}
}
// Check for directive sections
if (strnicmp(oldname,".drectve",8) == 0 || (pSectionHeader->Flags & (PE_SCN_LNK_INFO | PE_SCN_LNK_REMOVE))) {
// This is a directive section
if (cmd.ExeptionInfo) {
// Remove directive section
SectionBuffer[oldsec].NewNumber = 0;
cmd.CountExceptionRemoved();
continue;
}
}
// Get alignment
align = (pSectionHeader->Flags & PE_SCN_ALIGN_MASK) / PE_SCN_ALIGN_1;
if (align > 0) align--; // Alignment = 2^align
align2 = 1 << align; // 2^align
// Check for previous sections with same name
for (i = 0; i < SectionBufferNum; i++) {
if (strcmp(oldname, NameBuffer.Buf() + SectionBuffer[i].OldName) == 0) break; // Found same name
}
if (i < SectionBufferNum) {
// Previous section with same name found.
// i = first section with this name, oldsec = current section with this name
SectionBuffer[oldsec] = SectionBuffer[i]; // Copy record
SectionBuffer[oldsec].NewNameI = 0; // Indicate this is not the first record
// Check if alignment is the same
if (align != SectionBuffer[i].Align) {
err.submit(1060, oldname); // Warning different alignments
if (align > SectionBuffer[i].Align) SectionBuffer[i].Align = align; // Use highest alignment
}
// Get section header
SectionBuffer[oldsec].psechdr = pSectionHeader;
// Get size of this section
SectionBuffer[oldsec].Size = pSectionHeader->SizeOfRawData;
// Get offset relative to first section with same name
SectionBuffer[oldsec].Offset = SectionBuffer[i].Offset + SectionBuffer[i].SegmentSize;
// Align this section (We are aligning each section in the segment)
SectionBuffer[oldsec].Offset = (SectionBuffer[oldsec].Offset + align2 - 1) & (- align2);
// Update total size of all sections with same name
SectionBuffer[i].SegmentSize = SectionBuffer[oldsec].Offset + SectionBuffer[oldsec].Size;
}
else {
// No previous section found with same name. Make SOMFSegmentList record
SectionBufferNum = oldsec + 1; // End of entries in SectionBuffer
// Assign a number to this segment
SectionBuffer[oldsec].NewNumber = ++NumSegments;
SectionBuffer[oldsec].NewNameI = NumSegments + OMF_LNAME_LAST;
// Point to old section header
SectionBuffer[oldsec].psechdr = pSectionHeader;
// Give it a name
namei = NameBuffer.PushString(oldname); // Save name in buffer, because it is volatile
SectionBuffer[oldsec].OldName = namei; // Index to name
// Segment names like .text and _TEXT are both common. No need to convert the name
// Only restriction is length < 256.
// Do we need a unique segment name if the alignment is different from segments
// with same name in another module?
if (strlen(oldname) > 255) {
// Segment name too long. This is very unlikely
namei = NameBuffer.Push(oldname, 255); // Make truncated name
NameBuffer.Push(0, 1); // Terminate by zero
}
SectionBuffer[oldsec].NewName = namei; // Index to name
// Size
SectionBuffer[oldsec].Size = pSectionHeader->SizeOfRawData;
SectionBuffer[oldsec].SegmentSize = pSectionHeader->SizeOfRawData;
SectionBuffer[oldsec].Offset = 0;
// Alignment
SectionBuffer[oldsec].Align = align;
// Segment type
flags = pSectionHeader->Flags;
// Get segment class
if (flags & (PE_SCN_CNT_CODE | PE_SCN_MEM_EXECUTE)) {
// Code segment
SectionBuffer[oldsec].Class = OMF_LNAME_CODE;
}
else if (flags & PE_SCN_CNT_UNINIT_DATA) {
// Uninitialized data
SectionBuffer[oldsec].Class = OMF_LNAME_BSS;
}
else if (!(flags & PE_SCN_MEM_WRITE)) {
// Read only
SectionBuffer[oldsec].Class = OMF_LNAME_CONST;
}
else {
// Normal data
SectionBuffer[oldsec].Class = OMF_LNAME_DATA;
}
}
}
// Add 1 to section count because new section numbers are 1-based
SectionBufferNum = NSections + 1;
}
void CCOF2OMF::MakeSymbolList() {
// Make temporary symbol conversion list
int isym = 0; // current symbol table entry
//int jsym = 0; // auxiliary entry number
union { // Pointer to symbol table
SCOFF_SymTableEntry * p; // Normal pointer
int8 * b; // Used for address calculation
} Symtab;
Symtab.p = SymbolTable; // Set pointer to begin of SymbolTable
// Loop through symbol table
while (isym < NumberOfSymbols) {
// Check scope
if (Symtab.p->s.StorageClass == COFF_CLASS_EXTERNAL) {
// Scope is public or external
if (Symtab.p->s.SectionNumber > 0) {
// Symbol is public
SymbolBuffer[isym].Scope = S_PUBLIC; // Scope = public
SymbolBuffer[isym].NewIndex = ++NumPublicSymbols; // Public symbol number
// Get name
SymbolBuffer[isym].Name = NameBuffer.PushString(GetSymbolName(Symtab.p->s.Name));
// Find section in SectionBuffer
uint32 OldSection = Symtab.p->s.SectionNumber;
SymbolBuffer[isym].Segment = SectionBuffer[OldSection].NewNumber; // New segment number
// Calculate offset = offset into old section + offset of old section to first section with same name
SymbolBuffer[isym].Offset = Symtab.p->s.Value + SectionBuffer[OldSection].Offset;
}
else if (Symtab.p->s.SectionNumber == 0) {
// Symbol is external
SymbolBuffer[isym].Scope = S_EXTERNAL; // Scope = external
SymbolBuffer[isym].NewIndex = ++NumExternalSymbols; // External symbol number
SymbolBuffer[isym].Name = NameBuffer.PushString(GetSymbolName(Symtab.p->s.Name));
}
else if (Symtab.p->s.SectionNumber == COFF_SECTION_ABSOLUTE) {
// Symbol is public, absolute
SymbolBuffer[isym].Scope = S_PUBLIC; // Scope = public
SymbolBuffer[isym].NewIndex = ++NumPublicSymbols; // Public symbol number
// Get name
SymbolBuffer[isym].Name = NameBuffer.PushString(GetSymbolName(Symtab.p->s.Name));
SymbolBuffer[isym].Segment = 0; // 0 indicates absolute
SymbolBuffer[isym].Offset = Symtab.p->s.Value; // Store value in Offset
}
else {
// COFF_SECTION_DEBUG, COFF_SECTION_N_TV, COFF_SECTION_P_TV
// Ignore
}
}
// Skip auxiliary symbol table entries and increment pointer
isym += Symtab.p->s.NumAuxSymbols + 1;
Symtab.b += (Symtab.p->s.NumAuxSymbols + 1) * SIZE_SCOFF_SymTableEntry;
}
}
void CCOF2OMF::MakeRelocationsList() {
// Make temporary list of relocations (fixups) and sort it
uint32 i; // Relocation number in old file
int j; // Section number of relocation source in old file
int isym; // Symbol table index in old file
//int32 * paddend = 0; // Pointer to inline addend
uint32 TargetOldSection; // Section number of relocation target in old file
SOMFRelocation NewRel; // Entry in RelocationBuffer
union { // Pointer to symbol table
SCOFF_SymTableEntry * p; // Normal pointer
int8 * b; // Used for address calculation
} Symtab;
union { // Pointer to relocation entry
SCOFF_Relocation * p; // pointer to record
int8 * b; // used for address calculation and incrementing
} Reloc;
// Loop through section headers of old file
for (j = 0; j < NSections; j++) {
SCOFF_SectionHeader * SectionHeaderp = &SectionHeaders[j];
// Pointer to first relocation entry in section
Reloc.b = Buf() + SectionHeaderp->PRelocations;
// Loop through relocations in section
for (i = 0; i < SectionHeaderp->NRelocations; i++) {
// Find symbol table entry
isym = Reloc.p->SymbolTableIndex;
if ((uint32)isym >= (uint32)NumberOfSymbols) {
err.submit(2040); // SymbolTableIndex points outside Symbol Table
isym = 0;
}
Symtab.p = SymbolTable; // Set pointer to begin of SymbolTable
Symtab.b += SIZE_SCOFF_SymTableEntry * isym; // Calculate address of entry isym
// Find inline addend
if (Reloc.p->Type < COFF32_RELOC_SEG12) {
//paddend = (int32*)(Buf()+SectionHeaderp->PRawData+Reloc.p->VirtualAddress);
}
//else paddend = 0;
// Make entry in RelocationBuffer
// Relocation type
switch (Reloc.p->Type) {
case COFF32_RELOC_DIR32: // Direct 32 bit
NewRel.Mode = 1; break; // 0 = EIP-relative, 1 = direct
case COFF32_RELOC_REL32: // 32 bit EIP relative
NewRel.Mode = 0; break; // 0 = EIP-relative, 1 = direct
case COFF32_RELOC_ABS: // Ignore
continue;
default: // Other. Not supported
NewRel.Mode = -1; // -1 = unsupported.
// Postpone error message in case it refers to a debug section that is being removed
NewRel.TargetOffset = Reloc.p->Type; // Remember relocation type
//err.submit(2030, Reloc.p->Type); continue; // Unsupported relocation type
break;
}
// Get source
NewRel.Section = j + 1; // Section number in old file
NewRel.SourceOffset = Reloc.p->VirtualAddress;// Offset of source relative to section
// Get target
if (Symtab.p->s.SectionNumber > 0) {
// Local
NewRel.Scope = S_LOCAL; // 0 = local, 2 = external
TargetOldSection = Symtab.p->s.SectionNumber; // Target section
if (TargetOldSection > uint32(NSections)) {
// SectionNumber out of range
err.submit(2035); continue;
}
// Segment index of target in new file:
NewRel.TargetSegment = SectionBuffer[TargetOldSection].NewNumber;
// Offset relative to old section
NewRel.TargetOffset = Symtab.p->s.Value;
// Add offset relative to first section with same name to get offset relative to new segment
NewRel.TargetOffset += SectionBuffer[TargetOldSection].Offset;
}
else {
// External
NewRel.Scope = S_EXTERNAL; // 0 = local, 2 = external
NewRel.TargetOffset = 0; // Any addend is inline
// Find EXTDEF index in SymbolBuffer
NewRel.TargetSegment = SymbolBuffer[isym].NewIndex;
}
// Put NewRel into RelocationBuffer
RelocationBuffer.Push(NewRel);
// Increment pointer to relocation record
Reloc.b += SIZE_SCOFF_Relocation; // Next relocation record
}
}
// Sort RelocationBuffer
RelocationBuffer.Sort();
// Store number of relocations
NumRelocations = RelocationBuffer.GetNumEntries();
// Check for overlapping relocation sources
for (uint32 i = 1; i < RelocationBuffer.GetNumEntries(); i++) {
if (RelocationBuffer[i].Section == RelocationBuffer[i-1].Section
&& RelocationBuffer[i].SourceOffset >= RelocationBuffer[i-1].SourceOffset
&& RelocationBuffer[i].SourceOffset < RelocationBuffer[i-1].SourceOffset + 4
&& (RelocationBuffer[i].Mode == 0 || RelocationBuffer[i].Mode == 1)) {
err.submit(2210); // Error: overlapping relocation sources
}
}
}
void CCOF2OMF::MakeLNAMES() {
// Make THEADR and LNAMES records
int Sec; // Loop counter
uint32 NameI; // Name index
// Make first record in output file = Translator header
ToFile.StartRecord(OMF_THEADR);
// Remove path from file name and limit length
char * ShortName = CLibrary::ShortenMemberName(OutputFileName);
ToFile.PutString(ShortName);
ToFile.EndRecord();
// Make LNAMES record containing names of segments, groups and classes
ToFile.StartRecord(OMF_LNAMES);
// Store default group and class names
ToFile.PutString("FLAT"); // 1: FLAT = group name
ToFile.PutString("CODE"); // 2: CODE = class name for code
ToFile.PutString("DATA"); // 3: DATA = class name for data segment
ToFile.PutString("BSS"); // 4: BSS = class name for uninitialized data
ToFile.PutString("CONST"); // 5: CONST = class name for readonly data
NameI = OMF_LNAME_LAST + 1; // Index of next name
// Get segment names
for (Sec = 0; Sec < SectionBufferNum; Sec++) {
if (SectionBuffer[Sec].NewNameI == NameI) {
// Found next segment name to add
// Check if current record too big
if (ToFile.GetSize() >= 1024 - 256) { // Max size = 1024
ToFile.EndRecord(); // End current record
ToFile.StartRecord(OMF_LNAMES); // Start new LNAMES record
}
// Store name of this segment
ToFile.PutString(NameBuffer.Buf() + SectionBuffer[Sec].NewName);
NameI++; // Ready for next name
}
}
// End LNAMES record
ToFile.EndRecord();
}
void CCOF2OMF::MakeSEGDEF() {
// Make SEGDEF and GRPDEF records
int Sec; // Index into SectionBuffer
uint32 SegNum = 0; // Segment number in new file
OMF_SAttrib Attr; // Segment attributes bitfield
uint32 align; // Alignment in new file
// Loop through SectionBuffer
for (Sec = 0; Sec < SectionBufferNum; Sec++) {
if (SectionBuffer[Sec].NewNumber == SegNum+1 && SectionBuffer[Sec].NewNameI) {
// New segment found
SegNum++; // Segment number
// Make a SEGDEF record for this segment
ToFile.StartRecord(OMF_SEGDEF + 1); // Odd record number = 32 bit
// Attributes bitfield
Attr.u.P = 1; // Indicate 32 bit segment
Attr.u.B = 0; // 1 indicates 4 Gbytes
Attr.u.C = 2; // Indicates public combination
// Translate alignment
switch(SectionBuffer[Sec].Align) {
case 0: // Align by 1
align = 1; break;
case 1: // Align by 2
align = 2; break;
case 2: // Align by 4
align = 5; break;
case 3: // Align by 8 not supported, use 16
case 4: // Align by 16
align = 3; break;
default: // 32 or higher. Use 'page' alignment
// Note: this gives 256 on some systems, 4096 on other systems
align = 4;
if (SectionBuffer[Sec].Align > 8) {
err.submit(1205, 1 << SectionBuffer[Sec].Align); // Warning: alignment not supported
}
}
Attr.u.A = align; // Put alignment into bitfield
ToFile.PutByte(Attr.b); // Save attributes bitfield
// Segment length
ToFile.PutNumeric(SectionBuffer[Sec].SegmentSize);
// Segment name given by index into LNAMES record
ToFile.PutIndex(SectionBuffer[Sec].NewNameI);
// Class name index
ToFile.PutIndex(SectionBuffer[Sec].Class);
// Overlay index (ignored)
ToFile.PutIndex(0);
// End SEGDEF record
ToFile.EndRecord();
}
}
// Make GRPDEF record for the FLAT group
ToFile.StartRecord(OMF_GRPDEF); // Strart GRPDEF record
ToFile.PutIndex(OMF_LNAME_FLAT); // Index of name "FLAT"
// No need to put segment indices into the GRPDEF record when group is FLAT
// End GRPDEF record
ToFile.EndRecord();
}
void CCOF2OMF::MakeEXTDEF() {
// Make EXTDEF records
uint32 j; // SymbolBuffer entry index
uint32 ExtSymNum = 0; // External symbol number
if (NumExternalSymbols > 0) { // Are there any external symbols?
// Make EXTDEF record for one or more symbols
ToFile.StartRecord(OMF_EXTDEF); // Start record
// Loop through SymbolBuffer
for (j = 0; j < SymbolBuffer.GetNumEntries(); j++) {
if (SymbolBuffer[j].Scope == S_EXTERNAL && SymbolBuffer[j].NewIndex == ExtSymNum+1) {
// Found external symbol
ExtSymNum++; // Symbol number
// Check if current record too big
if (ToFile.GetSize() >= 1024 - 257) {// Max size = 1024
ToFile.EndRecord(); // End current record
ToFile.StartRecord(OMF_EXTDEF); // Start new EXTDEF record
}
// Put symbol name in record
ToFile.PutString(NameBuffer.Buf() + SymbolBuffer[j].Name);
// Type index
ToFile.PutIndex(0); // Not used any more
}
}
ToFile.EndRecord(); // End EXTDEF record
}
}
void CCOF2OMF::MakePUBDEF() {
// Make PUBDEF records
uint32 j; // SymbolBuffer entry index
uint32 PubSymNum = 0; // Public symbol number
// Loop through SymbolBuffer
for (j = 0; j < SymbolBuffer.GetNumEntries(); j++) {
if (SymbolBuffer[j].Scope == S_PUBLIC && SymbolBuffer[j].NewIndex == PubSymNum+1) {
// Found public symbol
PubSymNum++; // Symbol number
// Make PUBDEF record for this symbol
ToFile.StartRecord(OMF_PUBDEF + 1); // Start new PUBDEF record, 32 bit
// Group index
uint32 Group = SymbolBuffer[j].Segment ? OMF_LNAME_FLAT : 0; // Group = FLAT, except for absolute symbols
ToFile.PutIndex(Group); // Group name index
// Segment index
ToFile.PutIndex(SymbolBuffer[j].Segment);
// Base frame field if segment = 0
if (SymbolBuffer[j].Segment == 0) ToFile.PutWord(0);
// Put symbol name in record
ToFile.PutString(NameBuffer.Buf() + SymbolBuffer[j].Name);
// Offset relative to segment
ToFile.PutNumeric(SymbolBuffer[j].Offset);
// Type index
ToFile.PutIndex(0); // Not used any more
// End record
ToFile.EndRecord(); // End PUBDEF record
}
}
}
void CCOF2OMF::MakeLEDATA() {
/*
This function makes both LEDATA records, containing binary data, and FIXUPP
records, containing relocations.
The function is quite complicated because the LEDATA and FIXUPP records are
mutually interdependent. Some explanation is in place here.
I am using the word segment for the collection of all sections in the old file
having the same name. A section is a record of binary data in the old file.
Each section is stored as one or more LEDATA records in the new file.
A segment may thus be split into multiple sections, which again may be split
into multiple LEDATA records. The sections must be aligned according to the
specified alignment for the segment. The LEDATA records need not be aligned,
and they may be misaligned for reasons explained below.
Each LEDATA record is followed by a FIXUPP record containing all relocations
referring to a source in the LEDATA record, if any.
The size of a LEDATA record is limited to 1024 bytes because each entry in
the FIXUPP record has only 10 bits for addressing it. Some linkers impose
the 1024 bytes size limit to all OMF records, although this limitation is
strictly necessary only for LEDATA records. If the code has many relocations
then it may be necessary to make a LEDATA record smaller than 1024 bytes
in order to avoid that the corresponding FIXUPP record becomes bigger than
1024 bytes. Furthermore, the size of a LEDATA record may need adjustment to
avoid that a relocation source crosses a LEDATA record boundary.
I have stored all relocations in a temporary list RelocationBuffer which is
sorted by relocation source address in order to make it easier to find all
relocations with a source address in the current LEDATA record.
*/
int Segment; // Segment index in new file
int OldSection; // Section index in old file
uint32 SegOffset; // Offset of section relative to segment
uint32 SectOffset; // Offset of LEDATA record relative to section
uint32 CutOff; // Size limit for splitting section into multiple LEDATA records
uint32 RelFirst; // Index into RelocationBuffer of first relocation for section/record
uint32 RelLast; // Index into RelocationBuffer of last relocation for record + 1
uint32 Rel; // Current index into RelocationBuffer
uint32 FrameDatum; // Frame datum field in FIXUPP record
uint32 TargetDatum; // Target datum field in FIXUPP record
uint32 TargetDisplacement; // Target displacement field in FIXUPP record
uint32 AlignmentFiller; // Number of unused bytes from end of one section to begin of next section due to alignment
SOMFRelocation Reloc0; // Reference relocation record for compare and search
OMF_SLocat Locat; // Locat bitfield for FIXUPP record
OMF_SFixData FixData; // FixData bitfield for FIXUPP record
// Loop through segment numbers
for (Segment = 1; Segment <= NumSegments; Segment++) {
SegOffset = 0; // SegOffset = 0 for first section in segment
// Search through SectionBuffer for old sections contributing to this segment
for (OldSection = 0; OldSection < SectionBufferNum; OldSection++) {
if (SectionBuffer[OldSection].NewNumber == (uint32)Segment && SectionBuffer[OldSection].Size) {
// This section contributes to Segment. Make LEDATA record(s)
if (SectionBuffer[OldSection].Offset > SegOffset) {
// Fillers needed for alignment after previous section
AlignmentFiller = SectionBuffer[OldSection].Offset - SegOffset;
}
else {
AlignmentFiller = 0;
}
SectOffset = 0; // Offset of LEDATA record relative to section start
if (AlignmentFiller > 0
&& AlignmentFiller < 4096 && AlignmentFiller < (1u << SectionBuffer[OldSection].Align)
&& SectionBuffer[OldSection].Class == OMF_LNAME_CODE) {
// This is a code segment and there is a space from previous section
// Fill the alignment space with NOP's
// Make LIDATA record with NOP's
ToFile.StartRecord(OMF_LIDATA); // Start new LEDATA record
ToFile.PutIndex(Segment); // Segment index
ToFile.PutNumeric(SegOffset); // Offset of LIDATA relative to segment
ToFile.PutNumeric(AlignmentFiller); // Repeat count
ToFile.PutWord(0); // Block count
ToFile.PutByte(1); // Byte count
ToFile.PutByte(0x90); // NOP opcode
ToFile.EndRecord(); // End LIDATA record
}
SegOffset = SectionBuffer[OldSection].Offset; // Offset of section to segment
// Search for relocations for this section
Reloc0.Section = OldSection;
Reloc0.SourceOffset = 0;
RelFirst = RelocationBuffer.FindFirst(Reloc0); // Points to first relocation for this section
RelLast = RelFirst;
// Loop for possibly more than one LEDATA records for this section
while (SectOffset < SectionBuffer[OldSection].Size) {
CutOff = SectionBuffer[OldSection].Size - SectOffset; // Size of rest of section
if (CutOff > 1024 && SectionBuffer[OldSection].Class != OMF_LNAME_BSS) {
CutOff = 1024; // Maximum LEDATA size
}
// Search for last relocation entry
while (RelLast < NumRelocations) {
if (RelocationBuffer[RelLast].Section != (uint32)OldSection) {
break; // Reached end of relocations for this section
}
if (RelocationBuffer[RelLast].SourceOffset >= CutOff + SectOffset) {
break; // Reached size limit of LEDATA record
}
if (RelocationBuffer[RelLast].SourceOffset + 4 > CutOff + SectOffset) {
// Relocation crosses LEDATA boundary.
// Reduce limit of LEDATA to before this relocation source
CutOff = RelocationBuffer[RelLast].SourceOffset - SectOffset;
if (CutOff == 0) {
err.submit(2302); // Relocation source extends beyond end of section.
CutOff = 4; // Prevent infinite loop
}
break;
}
if (RelLast - RelFirst > 100) {
// FIXUPP record will become too big. End LEDATA record here
CutOff = RelocationBuffer[RelLast].SourceOffset - SectOffset;
break;
}
RelLast++;
} // End of search for last relocation entry for this LEDATA
if (SectionBuffer[OldSection].Class == OMF_LNAME_BSS) {
// BSS: Unitialized data section needs no LEDATA record and no FIXUPP
if (RelLast > RelFirst) {
// Error: Relocation of uninitialized data
err.submit(2041);
}
}
else {
// Section contains initialized data. Needs LEDATA and FIXUPP records
// Make LEDATA record for section data
ToFile.StartRecord(OMF_LEDATA + 1);// Start new LEDATA record, 32 bit
// Segment index
ToFile.PutIndex(Segment);
// Offset of LEDATA relative to segment
ToFile.PutNumeric(SegOffset + SectOffset);
// Binary data
ToFile.PutBinary(Buf() + SectionBuffer[OldSection].psechdr->PRawData + SectOffset, CutOff);
// End LEDATA record
ToFile.EndRecord();
if (RelLast > RelFirst) { // If there are any relocations
// Make FIXUPP record with (RelLast-RelFirst) relocation entries
ToFile.StartRecord(OMF_FIXUPP + 1); // Start FIXUPP record, 32 bit
// Loop through relocations
for (Rel = RelFirst; Rel < RelLast; Rel++) {
if (RelocationBuffer[Rel].Mode < 0) {
// Unsupported mode. Make error message
err.submit(2030, RelocationBuffer[Rel].TargetOffset); // TargetOffset contains COFF relocation mode
continue;
}
// Make Locat word bitfield
Locat.s.one = 1; // Indicates FIXUP subrecord
Locat.s.M = RelocationBuffer[Rel].Mode; // Direct / EIP-relative
Locat.s.Location = 9; // Indicates 32-bit offset
// Offset of source relative to section (10 bits)
uint32 RelocOffset = RelocationBuffer[Rel].SourceOffset - SectOffset; // Offset of relocation source to begin of LEDATA record
if (RelocOffset >= 1024) err.submit(9000); // Check that it fits into 10 bits
Locat.s.Offset = RelocOffset;
// Make FixData byte bitfield
FixData.b = 0; // Start with all bits 0
if (RelocationBuffer[Rel].Scope == S_LOCAL) {
// Local target
FixData.s.Target = 0; // Target method T0 or T4: Target = segment
FixData.s.Frame = 1; // Frame method F1: specified by a group index (FLAT)
FrameDatum = OMF_LNAME_FLAT; // Target frame = FLAT group
TargetDatum = RelocationBuffer[Rel].TargetSegment; // Fixup target = segment
TargetDisplacement = RelocationBuffer[Rel].TargetOffset; // Displacement or addend (?)
}
else {
// External symbol target
FixData.s.Frame = 5; // Frame method F5: Frame specified by target, not here
FixData.s.Target = 2; // Target method T2 or T6: Target specified by EXTDEF index
TargetDatum = RelocationBuffer[Rel].TargetSegment; // Index into EXTDEF
TargetDisplacement = RelocationBuffer[Rel].TargetOffset; // This is zero. Any addend is inline
}
if (TargetDisplacement) {
FixData.s.P = 0; // Displacement field present
}
else {
FixData.s.P = 1; // Displacement field absent
}
// Put these data into record
// Locat bytes in reverse order:
ToFile.PutByte(Locat.bytes[1]);
ToFile.PutByte(Locat.bytes[0]);
// FixData byte
ToFile.PutByte(FixData.b);
// Frame datum field only if FixData.F = 0 and Frame < 4
if (FixData.s.Frame < 4) ToFile.PutIndex(FrameDatum);
// Target datum field if FixData.T = 0, which it is here
ToFile.PutIndex(TargetDatum);
// Target displacement field if FixData.P = 0
if (FixData.s.P == 0) ToFile.PutNumeric(TargetDisplacement);
} // End of loop through relocation for last LEDATA
// End FIXUPP record
ToFile.EndRecord();
}
}
// Update pointers to after this LEDATA
SectOffset += CutOff;
RelFirst = RelLast;
} // End of loop for multiple LEDATA records for one section
// Find end of section
SegOffset += SectionBuffer[OldSection].Size; // End of section
} // End of if section in segment
} // End of loop through multiple sections for same segment
} // End of loop through segments
}
void CCOF2OMF::MakeMODEND() {
// Make MODEND record and finish file
ToFile.StartRecord(OMF_MODEND); // Start MODEND record
ToFile.PutByte(0); // Module type field. 0 if not a startup module with start address
ToFile.EndRecord(); // End MODEND record
}

View File

@ -0,0 +1,914 @@
/**************************** coff.cpp ***********************************
* Author: Agner Fog
* Date created: 2006-07-15
* Last modified: 2009-01-22
* Project: objconv
* Module: coff.cpp
* Description:
* Module for reading PE/COFF files
*
* Class CCOFF is used for reading, interpreting and dumping PE/COFF files.
*
* Copyright 2006-2009 GNU General Public License http://www.gnu.org/licenses
*****************************************************************************/
#include "stdafx.h"
// Relocation type names
SIntTxt COFF32RelNames[] = {
{COFF32_RELOC_ABS, "Absolute"}, // Ignored
{COFF32_RELOC_DIR32, "Direct32"}, // 32-bit absolute virtual address
{COFF32_RELOC_IMGREL, "Image relative"}, // 32-bit image relative virtual address
{COFF32_RELOC_SECTION, "Section16"}, // 16-bit section index in file
{COFF32_RELOC_SECREL, "Section relative"}, // 32-bit section-relative
{COFF32_RELOC_SECREL7, "7 bit section relative"}, // 7-bit section-relative
{COFF32_RELOC_TOKEN, "CLR token"}, // CLR token
{COFF32_RELOC_REL32, "EIP relative"} // 32-bit relative to end of address field
};
SIntTxt COFF64RelNames[] = {
{COFF64_RELOC_ABS, "Ignore"}, // Ignored
{COFF64_RELOC_ABS64, "64 bit absolute"}, // 64 bit absolute virtual address
{COFF64_RELOC_ABS32, "32 bit absolute"}, // 32 bit absolute virtual address
{COFF64_RELOC_IMGREL, "Image relative"}, // 32 bit image-relative
{COFF64_RELOC_REL32, "RIP relative"}, // 32 bit, RIP-relative
{COFF64_RELOC_REL32_1, "RIP relative-1"}, // 32 bit, relative to RIP - 1. For instruction with immediate byte operand
{COFF64_RELOC_REL32_2, "RIP relative-2"}, // 32 bit, relative to RIP - 2. For instruction with immediate word operand
{COFF64_RELOC_REL32_3, "RIP relative-3"}, // 32 bit, relative to RIP - 3. Useless
{COFF64_RELOC_REL32_4, "RIP relative-4"}, // 32 bit, relative to RIP - 4. For instruction with immediate dword operand
{COFF64_RELOC_REL32_5, "RIP relative-5"}, // 32 bit, relative to RIP - 5. Useless
{COFF32_RELOC_SECTION, "Section index"}, // 16-bit section index in file
{COFF64_RELOC_SECREL, "Section relative"}, // 32-bit section-relative
{COFF64_RELOC_SECREL7, "7 bit section rel"},// 7-bit section-relative
{COFF64_RELOC_TOKEN, "CLR token"}, // 64 bit absolute virtual address without inline addend
{COFF64_RELOC_SREL32, "32b span dependent"}, //
{COFF64_RELOC_PAIR, "pair after span dependent"}, //
{COFF64_RELOC_PPC_REFHI,"high 16 of 32 bit abs"}, //
{COFF64_RELOC_PPC_REFLO,"low 16 of 32 bit abs"}, //
{COFF64_RELOC_PPC_PAIR, "pair after high 16"}, //
{COFF64_RELOC_PPC_SECRELO,"low 16 of 32 bit section relative"},
{COFF64_RELOC_PPC_GPREL, "16 bit GP relative"}, //
{COFF64_RELOC_PPC_TOKEN, "CLR token"} //
};
// Machine names
SIntTxt COFFMachineNames[] = {
{0, "Any/unknown"}, // Any machine/unknown
{0x184, "Alpha"}, // Alpha AXP
{0x1C0, "Arm"}, // Arm
{0x284, "Alpha 64 bit"}, // Alpha AXP 64 bit
{0x14C, "I386"}, // x86, 32 bit
{0x200, "IA64"}, // Intel Itanium
{0x268, "Motorola68000"}, // Motorola 68000 series
{0x266, "MIPS16"},
{0x366, "MIPSwFPU"},
{0x466, "MIPS16wFPU"},
{0x1F0, "PowerPC"},
{0x1F1, "PowerPC"},
{0x162, "R3000"},
{0x166, "R4000MIPS"},
{0x168, "R10000"},
{0x1A2, "SH3"},
{0x1A6, "SH4"},
{0x1C2, "Thumb"},
{0x8664, "x86-64"} // x86-64 / AMD64 / Intel EM64T
};
// Storage class names
SIntTxt COFFStorageClassNames[] = {
{COFF_CLASS_END_OF_FUNCTION, "EndOfFunc"},
{COFF_CLASS_AUTOMATIC, "AutoVariable"},
{COFF_CLASS_EXTERNAL, "External/Public"},
{COFF_CLASS_STATIC, "Static/Nonpublic"},
{COFF_CLASS_REGISTER, "Register"},
{COFF_CLASS_EXTERNAL_DEF, "ExternalDef"},
{COFF_CLASS_LABEL, "Label"},
{COFF_CLASS_UNDEFINED_LABEL, "UndefLabel"},
{COFF_CLASS_MEMBER_OF_STRUCTURE, "StructMem"},
{COFF_CLASS_ARGUMENT, "FuncArgument"},
{COFF_CLASS_STRUCTURE_TAG, "StructTag"},
{COFF_CLASS_MEMBER_OF_UNION, "UnionMember"},
{COFF_CLASS_UNION_TAG, "UnionTag"},
{COFF_CLASS_TYPE_DEFINITION, "TypeDef"},
{COFF_CLASS_UNDEFINED_STATIC, "UndefStatic"},
{COFF_CLASS_ENUM_TAG, "EnumTag"},
{COFF_CLASS_MEMBER_OF_ENUM, "EnumMem"},
{COFF_CLASS_REGISTER_PARAM, "RegisterParameter"},
{COFF_CLASS_BIT_FIELD, "BitField"},
{COFF_CLASS_AUTO_ARGUMENT, "AutoArgument"},
{COFF_CLASS_LASTENTRY, "DummyLastEntry"},
{COFF_CLASS_BLOCK, "bb/eb_block"},
{COFF_CLASS_FUNCTION, "Function_bf/ef"},
{COFF_CLASS_END_OF_STRUCT, "EndOfStruct"},
{COFF_CLASS_FILE, "FileName"},
{COFF_CLASS_LINE, "LineNumber"},
{COFF_CLASS_SECTION, "SectionLineNumber"},
{COFF_CLASS_ALIAS, "Alias"},
{COFF_CLASS_WEAK_EXTERNAL, "WeakExternal"},
{COFF_CLASS_HIDDEN, "Hidden"}
};
// Names of section characteristics
SIntTxt COFFSectionFlagNames[] = {
{PE_SCN_CNT_CODE, "Text"},
{PE_SCN_CNT_INIT_DATA, "Data"},
{PE_SCN_CNT_UNINIT_DATA, "BSS"},
{PE_SCN_LNK_INFO, "Comments"},
{PE_SCN_LNK_REMOVE, "Remove"},
{PE_SCN_LNK_COMDAT, "Comdat"},
/* {PE_SCN_ALIGN_1, "Align by 1"},
{PE_SCN_ALIGN_2, "Align by 2"},
{PE_SCN_ALIGN_4, "Align by 4"},
{PE_SCN_ALIGN_8, "Align by 8"},
{PE_SCN_ALIGN_16, "Align by 16"},
{PE_SCN_ALIGN_32, "Align by 32"},
{PE_SCN_ALIGN_64, "Align by 64"},
{PE_SCN_ALIGN_128, "Align by 128"},
{PE_SCN_ALIGN_256, "Align by 256"},
{PE_SCN_ALIGN_512, "Align by 512"},
{PE_SCN_ALIGN_1024, "Align by 1024"},
{PE_SCN_ALIGN_2048, "Align by 2048"},
{PE_SCN_ALIGN_4096, "Align by 4096"},
{PE_SCN_ALIGN_8192, "Align by 8192"}, */
{PE_SCN_LNK_NRELOC_OVFL, "extended relocations"},
{PE_SCN_MEM_DISCARDABLE, "Discardable"},
{PE_SCN_MEM_NOT_CACHED, "Cannot be cached"},
{PE_SCN_MEM_NOT_PAGED, "Not pageable"},
{PE_SCN_MEM_SHARED, "Can be shared"},
{PE_SCN_MEM_EXECUTE, "Executable"},
{PE_SCN_MEM_READ, "Readable"},
{PE_SCN_MEM_WRITE, "Writeable"}
};
// Names of image data directories in optional header
SIntTxt COFFImageDirNames[] = {
{0, "Export_table"},
{1, "Import_table"},
{2, "Resource_table"},
{3, "Exception_table"},
{4, "Certificate_table"},
{5, "Base_relocation_table"},
{6, "Debug_table"},
{7, "Architecture_table"},
{8, "Global_pointer"},
{9, "Thread_local_storage_table"},
{10, "Load_configuration_table"},
{11, "Bound_import_table"},
{12, "Import_address_table"},
{13, "Delay_import_descriptor"},
{14, "Common_language_runtime_header"},
{15, "Reserved_table"}
};
// Class CCOFF members:
// Constructor
CCOFF::CCOFF() {
// Set everything to zero
memset(this, 0, sizeof(*this));
}
void CCOFF::ParseFile(){
// Load and parse file buffer
// Get offset to file header
uint32 FileHeaderOffset = 0;
if ((Get<uint16>(0) & 0xFFF9) == 0x5A49) {
// File has DOS stub
uint32 Signature = Get<uint32>(0x3C);
if (Signature + 8 < DataSize && Get<uint16>(Signature) == 0x4550) {
// Executable PE file
FileHeaderOffset = Signature + 4;
}
else {
err.submit(9000);
return;
}
}
// Find file header
FileHeader = &Get<SCOFF_FileHeader>(FileHeaderOffset);
NSections = FileHeader->NumberOfSections;
// check header integrity
if ((uint64)FileHeader->PSymbolTable + FileHeader->NumberOfSymbols * SIZE_SCOFF_SymTableEntry > GetDataSize()) err.submit(2035);
// Find optional header if executable file
if (FileHeader->SizeOfOptionalHeader && FileHeaderOffset) {
OptionalHeader = &Get<SCOFF_OptionalHeader>(FileHeaderOffset + sizeof(SCOFF_FileHeader));
// Find image data directories
if (OptionalHeader) {
if (OptionalHeader->h64.Magic == COFF_Magic_PE64) {
// 64 bit version
pImageDirs = &(OptionalHeader->h64.ExportTable);
NumImageDirs = OptionalHeader->h64.NumberOfRvaAndSizes;
EntryPoint = OptionalHeader->h64.AddressOfEntryPoint;
ImageBase = OptionalHeader->h64.ImageBase;
}
else {
// 32 bit version
pImageDirs = &(OptionalHeader->h32.ExportTable);
NumImageDirs = OptionalHeader->h32.NumberOfRvaAndSizes;
EntryPoint = OptionalHeader->h32.AddressOfEntryPoint;
ImageBase = OptionalHeader->h32.ImageBase;
}
}
}
// Allocate buffer for section headers
SectionHeaders.SetNum(NSections);
SectionHeaders.SetZero();
// Find section headers
uint32 SectionOffset = FileHeaderOffset + sizeof(SCOFF_FileHeader) + FileHeader->SizeOfOptionalHeader;
for (int i = 0; i < NSections; i++) {
SectionHeaders[i] = Get<SCOFF_SectionHeader>(SectionOffset);
SectionOffset += sizeof(SCOFF_SectionHeader);
// Check for _ILDATA section
if (strcmp(SectionHeaders[i].Name, "_ILDATA") == 0) {
// This is an intermediate file for Intel compiler
err.submit(2114);
}
}
if (SectionOffset > GetDataSize()) {
err.submit(2110); return; // Section table points to outside file
}
// Find symbol table
SymbolTable = &Get<SCOFF_SymTableEntry>(FileHeader->PSymbolTable);
NumberOfSymbols = FileHeader->NumberOfSymbols;
// Find string table
StringTable = (Buf() + FileHeader->PSymbolTable + NumberOfSymbols * SIZE_SCOFF_SymTableEntry);
StringTableSize = *(int*)StringTable; // First 4 bytes of string table contains its size
}
// Debug dump
void CCOFF::Dump(int options) {
uint32 i, j;
if (options & DUMP_FILEHDR) {
// File header
printf("\nDump of PE/COFF file %s", FileName);
printf("\n-----------------------------------------------");
printf("\nFile size: %i", GetDataSize());
printf("\nFile header:");
printf("\nMachine: %s", Lookup(COFFMachineNames,FileHeader->Machine));
printf("\nTimeDate: 0x%08X", FileHeader->TimeDateStamp);
printf(" - %s", timestring(FileHeader->TimeDateStamp));
printf("\nNumber of sections: %2i", FileHeader->NumberOfSections);
printf("\nNumber of symbols: %2i", FileHeader->NumberOfSymbols);
printf("\nOptional header size: %i", FileHeader->SizeOfOptionalHeader);
printf("\nFlags: 0x%04X", FileHeader->Flags);
// May be removed:
printf("\nSymbol table offset: 0x%X", FileHeader->PSymbolTable);
printf("\nString table offset: 0x%X", FileHeader->PSymbolTable + FileHeader->NumberOfSymbols * SIZE_SCOFF_SymTableEntry);
printf("\nSection headers offset: 0x%X", (uint32)sizeof(SCOFF_FileHeader) + FileHeader->SizeOfOptionalHeader);
// Optional header
if (OptionalHeader) {
printf("\n\nOptional header:");
if (OptionalHeader->h32.Magic != COFF_Magic_PE64) {
// 32 bit optional header
printf("\nMagic number: 0x%X", OptionalHeader->h32.Magic);
printf("\nSize of code: 0x%X", OptionalHeader->h32.SizeOfCode);
printf("\nSize of uninitialized data: 0x%X", OptionalHeader->h32.SizeOfInitializedData);
printf("\nAddress of entry point: 0x%X", OptionalHeader->h32.AddressOfEntryPoint);
printf("\nBase of code: 0x%X", OptionalHeader->h32.BaseOfCode);
printf("\nBase of data: 0x%X", OptionalHeader->h32.BaseOfData);
printf("\nImage base: 0x%X", OptionalHeader->h32.ImageBase);
printf("\nSection alignment: 0x%X", OptionalHeader->h32.SectionAlignment);
printf("\nFile alignment: 0x%X", OptionalHeader->h32.FileAlignment);
printf("\nSize of image: 0x%X", OptionalHeader->h32.SizeOfImage);
printf("\nSize of headers: 0x%X", OptionalHeader->h32.SizeOfHeaders);
printf("\nDll characteristics: 0x%X", OptionalHeader->h32.DllCharacteristics);
printf("\nSize of stack reserve: 0x%X", OptionalHeader->h32.SizeOfStackReserve);
printf("\nSize of stack commit: 0x%X", OptionalHeader->h32.SizeOfStackCommit);
printf("\nSize of heap reserve: 0x%X", OptionalHeader->h32.SizeOfHeapReserve);
printf("\nSize of heap commit: 0x%X", OptionalHeader->h32.SizeOfHeapCommit);
}
else {
// 64 bit optional header
printf("\nMagic number: 0x%X", OptionalHeader->h64.Magic);
printf("\nSize of code: 0x%X", OptionalHeader->h64.SizeOfCode);
printf("\nSize of uninitialized data: 0x%X", OptionalHeader->h64.SizeOfInitializedData);
printf("\nAddress of entry point: 0x%X", OptionalHeader->h64.AddressOfEntryPoint);
printf("\nBase of code: 0x%X", OptionalHeader->h64.BaseOfCode);
printf("\nImage base: 0x%08X%08X", HighDWord(OptionalHeader->h64.ImageBase), uint32(OptionalHeader->h64.ImageBase));
printf("\nSection alignment: 0x%X", OptionalHeader->h64.SectionAlignment);
printf("\nFile alignment: 0x%X", OptionalHeader->h64.FileAlignment);
printf("\nSize of image: 0x%X", OptionalHeader->h64.SizeOfImage);
printf("\nSize of headers: 0x%X", OptionalHeader->h64.SizeOfHeaders);
printf("\nDll characteristics: 0x%X", OptionalHeader->h64.DllCharacteristics);
printf("\nSize of stack reserve: 0x%08X%08X", HighDWord(OptionalHeader->h64.SizeOfStackReserve), uint32(OptionalHeader->h64.SizeOfStackReserve));
printf("\nSize of stack commit: 0x%08X%08X", HighDWord(OptionalHeader->h64.SizeOfStackCommit), uint32(OptionalHeader->h64.SizeOfStackCommit));
printf("\nSize of heap reserve: 0x%08X%08X", HighDWord(OptionalHeader->h64.SizeOfHeapReserve), uint32(OptionalHeader->h64.SizeOfHeapReserve));
printf("\nSize of heap commit: 0x%08X%08X", HighDWord(OptionalHeader->h64.SizeOfHeapCommit), uint32(OptionalHeader->h64.SizeOfHeapCommit));
}
// Data directories
SCOFF_ImageDirAddress dir;
for (i = 0; i < NumImageDirs; i++) {
if (GetImageDir(i, &dir)) {
printf("\nDirectory %2i, %s:\n Address 0x%04X, Size 0x%04X, Section %i, Offset 0x%04X",
i, dir.Name,
dir.VirtualAddress, dir.Size, dir.Section, dir.SectionOffset);
}
}
}
}
if ((options & DUMP_STRINGTB) && FileHeader->PSymbolTable && StringTableSize > 4) {
// String table
char * p = StringTable + 4;
uint32 nread = 4, len;
printf("\n\nString table:");
while (nread < StringTableSize) {
len = (int)strlen(p);
if (len > 0) {
printf("\n>>%s<<", p);
nread += len + 1;
p += len + 1;
}
}
}
// Symbol tables
if (options & DUMP_SYMTAB) {
// Symbol table (object file)
if (NumberOfSymbols) PrintSymbolTable(-1);
// Import and export tables (executable file)
if (OptionalHeader) PrintImportExport();
}
// Section headers
if (options & (DUMP_SECTHDR | DUMP_SYMTAB | DUMP_RELTAB)) {
for (j = 0; j < (uint32)NSections; j++) {
SCOFF_SectionHeader * SectionHeader = &SectionHeaders[j];
printf("\n\n%2i Section %s", j+1, GetSectionName(SectionHeader->Name));
//printf("\nFile offset of header: 0x%X", (int)((int8*)SectionHeader-buffer));
printf("\nVirtual size: 0x%X", SectionHeader->VirtualSize);
if (SectionHeader->VirtualAddress) {
printf("\nVirtual address: 0x%X", SectionHeader->VirtualAddress);}
if (SectionHeader->PRawData || SectionHeader->SizeOfRawData) {
printf("\nSize of raw data: 0x%X", SectionHeader->SizeOfRawData);
printf("\nRaw data pointer: 0x%X", SectionHeader->PRawData);
}
printf("\nCharacteristics: ");
PrintSegmentCharacteristics(SectionHeader->Flags);
// print relocations
if ((options & DUMP_RELTAB) && SectionHeader->NRelocations > 0) {
printf("\nRelocation entries: %i", SectionHeader->NRelocations);
printf("\nRelocation entries pointer: 0x%X", SectionHeader->PRelocations);
// Pointer to relocation entry
union {
SCOFF_Relocation * p; // pointer to record
int8 * b; // used for address calculation and incrementing
} Reloc;
Reloc.b = Buf() + SectionHeader->PRelocations;
printf("\nRelocations:");
for (i = 0; i < SectionHeader->NRelocations; i++) {
printf("\nAddr: 0x%X, symi: %i, type: %s",
Reloc.p->VirtualAddress,
Reloc.p->SymbolTableIndex,
(WordSize == 32) ? Lookup(COFF32RelNames,Reloc.p->Type) : Lookup(COFF64RelNames,Reloc.p->Type));
if (Reloc.p->Type < COFF32_RELOC_SEG12)
{
// Check if address is within file
if (SectionHeader->PRawData + Reloc.p->VirtualAddress < GetDataSize()) {
int32 addend = *(int32*)(Buf() + SectionHeader->PRawData + Reloc.p->VirtualAddress);
if (addend) printf(", Implicit addend: %i", addend);
}
else {
printf(". Error: Address is outside file");
}
}
PrintSymbolTable(Reloc.p->SymbolTableIndex);
Reloc.b += SIZE_SCOFF_Relocation; // Next relocation record
}
}
// print line numbers
if (SectionHeader->NLineNumbers > 0) {
printf("\nLine number entries: %i", SectionHeader->NLineNumbers);
printf(" Line number pointer: %i\nLines:", SectionHeader->PLineNumbers);
// Pointer to line number entry
union {
SCOFF_LineNumbers * p; // pointer to record
int8 * b; // used for address calculation and incrementing
} Linnum;
Linnum.b = Buf() + SectionHeader->PLineNumbers;
for (i = 0; i < SectionHeader->NLineNumbers; i++) {
if (Linnum.p->Line) { // Record contains line number
printf(" %i:%i", Linnum.p->Line, Linnum.p->Addr);
}
else { // Record contains function name
}
Linnum.b += SIZE_SCOFF_LineNumbers; // Next line number record
}
}
}
}
}
char const * CCOFF::GetSymbolName(int8* Symbol) {
// Get symbol name from 8 byte entry
static char text[16];
if (*(uint32*)Symbol != 0) {
// Symbol name not more than 8 bytes
memcpy(text, Symbol, 8); // Copy to local buffer
text[8] = 0; // Append terminating zero
return text; // Return text
}
else {
// Longer than 8 bytes. Get offset into string table
uint32 offset = *(uint32*)(Symbol + 4);
if (offset >= StringTableSize || offset >= GetDataSize()) {err.submit(2035); return "";}
char * s = StringTable + offset;
if (*s) return s; // Return string table entry
}
return "NULL"; // String table entry was empty
}
char const * CCOFF::GetSectionName(int8* Symbol) {
// Get section name from 8 byte entry
static char text[16];
memcpy(text, Symbol, 8); // Copy to local buffer
text[8] = 0; // Append terminating zero
if (text[0] == '/') {
// Long name is in string table.
// Convert decimal ASCII number to string table index
uint32 sindex = atoi(text + 1);
// Get name from string table
if (sindex < StringTableSize) {
char * s = StringTable + sindex;
if (*s) return s;} // Return string table entry
}
else {
// Short name is in text buffer
return text;
}
return "NULL"; // In case of error
}
char const * CCOFF::GetStorageClassName(uint8 sc) {
// Get storage class name
return Lookup(COFFStorageClassNames, sc);
}
void CCOFF::PrintSegmentCharacteristics(uint32 flags) {
// Print segment characteristics
int n = 0;
// Loop through all bits of integer
for (uint32 i = 1; i != 0; i <<= 1) {
if (i & flags & ~PE_SCN_ALIGN_MASK) {
if (n++) printf(", ");
printf("%s", Lookup(COFFSectionFlagNames, i));
}
}
if (flags & PE_SCN_ALIGN_MASK) {
int a = 1 << (((flags & PE_SCN_ALIGN_MASK) / PE_SCN_ALIGN_1) - 1);
printf(", Align by 0x%X", a); n++;
}
if (n == 0) printf("None");
}
const char * CCOFF::GetFileName(SCOFF_SymTableEntry * syme) {
// Get file name from records in symbol table
if (syme->s.NumAuxSymbols < 1 || syme->s.StorageClass != COFF_CLASS_FILE) {
return ""; // No file name found
}
// Set limit to file name length = 576
const uint32 MAXCOFFFILENAMELENGTH = 32 * SIZE_SCOFF_SymTableEntry;
// Buffer to store file name. Must be static
static char text[MAXCOFFFILENAMELENGTH+1];
// length of name in record
uint32 len = syme->s.NumAuxSymbols * SIZE_SCOFF_SymTableEntry;
if (len > MAXCOFFFILENAMELENGTH) len = MAXCOFFFILENAMELENGTH;
// copy name from auxiliary records
memcpy(text, (int8*)syme + SIZE_SCOFF_SymTableEntry, len);
// Terminate string
text[len] = 0;
// Return name
return text;
}
const char * CCOFF::GetShortFileName(SCOFF_SymTableEntry * syme) {
// Same as above. Strips path before filename
// Full file name
const char * fullname = GetFileName(syme);
// Length
uint32 len = (uint32)strlen(fullname);
if (len < 1) return fullname;
// Scan backwards for '/', '\', ':'
for (int scan = len-2; scan >= 0; scan--) {
char c = fullname[scan];
if (c == '/' || c == '\\' || c == ':') {
// Path found. Short name starts after this character
return fullname + scan + 1;
}
}
// No path found. Return full name
return fullname;
}
void CCOFF::PrintSymbolTable(int symnum) {
// Print one or all public symbols for object file.
// Dump symbol table if symnum = -1, or
// Dump symbol number symnum (zero based) when symnum >= 0
int isym = 0; // current symbol table entry
int jsym = 0; // auxiliary entry number
union { // Pointer to symbol table
SCOFF_SymTableEntry * p; // Normal pointer
int8 * b; // Used for address calculation
} Symtab;
Symtab.p = SymbolTable; // Set pointer to begin of SymbolTable
if (symnum == -1) printf("\n\nSymbol table:");
if (symnum >= 0) {
// Print one symbol only
if (symnum >= NumberOfSymbols) {
printf("\nSymbol %i not found", symnum);
return;
}
isym = symnum;
Symtab.b += SIZE_SCOFF_SymTableEntry * isym;
}
while (isym < NumberOfSymbols) {
// Print symbol table entry
SCOFF_SymTableEntry *s0;
printf("\n");
if (symnum >= 0) printf(" ");
printf("Symbol %i - Name: %s\n Value=%i, ",
isym, GetSymbolName(Symtab.p->s.Name), Symtab.p->s.Value);
if (Symtab.p->s.SectionNumber > 0) {
printf("Section=%i", Symtab.p->s.SectionNumber);
}
else { // Special section numbers
switch (Symtab.p->s.SectionNumber) {
case COFF_SECTION_UNDEF:
printf("External"); break;
case COFF_SECTION_ABSOLUTE:
printf("Absolute"); break;
case COFF_SECTION_DEBUG:
printf("Debug"); break;
case COFF_SECTION_N_TV:
printf("Preload transfer"); break;
case COFF_SECTION_P_TV:
printf("Postload transfer"); break;
}
}
printf(", Type=0x%X, StorClass=%s, NumAux=%i",
Symtab.p->s.Type,
GetStorageClassName(Symtab.p->s.StorageClass), Symtab.p->s.NumAuxSymbols);
if (Symtab.p->s.StorageClass == COFF_CLASS_FILE && Symtab.p->s.NumAuxSymbols > 0) {
printf("\n File name: %s", GetFileName(Symtab.p));
}
// Increment point
s0 = Symtab.p;
Symtab.b += SIZE_SCOFF_SymTableEntry;
isym++; jsym = 0;
// Get auxiliary records
while (jsym < s0->s.NumAuxSymbols && isym + jsym < NumberOfSymbols) {
// Print auxiliary symbol table entry
SCOFF_SymTableEntry * sa = Symtab.p;
// Detect auxiliary entry type
if (s0->s.StorageClass == COFF_CLASS_EXTERNAL
&& s0->s.Type == COFF_TYPE_FUNCTION
&& s0->s.SectionNumber > 0) {
// This is a function definition aux record
printf("\n Aux function definition:");
printf("\n .bf_tag_index: 0x%X, code_size: %i, PLineNumRec: %i, PNext: %i",
sa->func.TagIndex, sa->func.TotalSize, sa->func.PointerToLineNumber,
sa->func.PointerToNextFunction);
}
else if (strcmp(s0->s.Name,".bf")==0 || strcmp(s0->s.Name,".ef")==0) {
// This is a .bf or .ef aux record
printf("\n Aux .bf/.ef definition:");
printf("\n Source line number: %i",
sa->bfef.SourceLineNumber);
if (strcmp(s0->s.Name,".bf")==0 ) {
printf(", PNext: %i", sa->bfef.PointerToNextFunction);
}
}
else if (s0->s.StorageClass == COFF_CLASS_EXTERNAL &&
s0->s.SectionNumber == COFF_SECTION_UNDEF &&
s0->s.Value == 0) {
// This is a Weak external aux record
printf("\n Aux Weak external definition:");
printf("\n Symbol2 index: %i, Characteristics: 0x%X",
sa->weak.TagIndex, sa->weak.Characteristics);
}
else if (s0->s.StorageClass == COFF_CLASS_FILE) {
// This is filename aux record. Contents has already been printed
}
else if (s0->s.StorageClass == COFF_CLASS_STATIC) {
// This is section definition aux record
printf("\n Aux section definition record:");
printf("\n Length: %i, Num. relocations: %i, Num linenums: %i, checksum 0x%X,"
"\n Number: %i, Selection: %i",
sa->section.Length, sa->section.NumberOfRelocations, sa->section.NumberOfLineNumbers,
sa->section.CheckSum, sa->section.Number, sa->section.Selection);
}
else if (s0->s.StorageClass == COFF_CLASS_ALIAS) {
// This is section definition aux record
printf("\n Aux alias definition record:");
printf("\n symbol index: %i, ", sa->weak.TagIndex);
switch (sa->weak.Characteristics) {
case IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY:
printf("no library search"); break;
case IMAGE_WEAK_EXTERN_SEARCH_LIBRARY:
printf("library search"); break;
case IMAGE_WEAK_EXTERN_SEARCH_ALIAS:
printf("alias symbol"); break;
default:
printf("unknown characteristics 0x%X", sa->weak.Characteristics);
}
}
else {
// Unknown aux record type
printf("\n Unknown Auxiliary record type %i", s0->s.StorageClass);
}
Symtab.b += SIZE_SCOFF_SymTableEntry;
jsym++;
}
isym += jsym;
if (symnum >= 0) break;
}
}
void CCOFF::PublicNames(CMemoryBuffer * Strings, CSList<SStringEntry> * Index, int m) {
// Make list of public names in object file
// Strings will receive ASCIIZ strings
// Index will receive records of type SStringEntry with Member = m
// Interpret header:
ParseFile();
int isym = 0; // current symbol table entry
union { // Pointer to symbol table
SCOFF_SymTableEntry * p; // Normal pointer
int8 * b; // Used for address calculation
} Symtab;
// Loop through symbol table
Symtab.p = SymbolTable;
while (isym < NumberOfSymbols) {
// Check within buffer
if (Symtab.b >= Buf() + DataSize) {
err.submit(2040);
break;
}
// Search for public symbol
if (Symtab.p->s.SectionNumber > 0 && Symtab.p->s.StorageClass == COFF_CLASS_EXTERNAL) {
// Public symbol found
SStringEntry se;
se.Member = m;
// Store name
se.String = Strings->PushString(GetSymbolName(Symtab.p->s.Name));
// Store name index
Index->Push(se);
}
if ((int8)Symtab.p->s.NumAuxSymbols < 0) Symtab.p->s.NumAuxSymbols = 0;
// Increment point
isym += Symtab.p->s.NumAuxSymbols + 1;
Symtab.b += (1 + Symtab.p->s.NumAuxSymbols) * SIZE_SCOFF_SymTableEntry;
}
}
int CCOFF::GetImageDir(uint32 n, SCOFF_ImageDirAddress * dir) {
// Find address of image directory for executable files
int32 Section;
uint32 FileOffset;
if (pImageDirs == 0 || n >= NumImageDirs || dir == 0) {
// Failure
return 0;
}
// Get virtual address and size of directory
dir->VirtualAddress = pImageDirs[n].VirtualAddress;
dir->Size = pImageDirs[n].Size;
dir->Name = Lookup(COFFImageDirNames, n);
// Check if nonzero
if (dir->VirtualAddress == 0 || dir->Size == 0) {
// Empty
return 0;
}
// Search for section containing this address
for (Section = 0; Section < NSections; Section++) {
if (dir->VirtualAddress >= SectionHeaders[Section].VirtualAddress
&& dir->VirtualAddress < SectionHeaders[Section].VirtualAddress + SectionHeaders[Section].SizeOfRawData) {
// Found section
dir->Section = Section + 1;
// Section-relative offset
dir->SectionOffset = dir->VirtualAddress - SectionHeaders[Section].VirtualAddress;
// Calculate file offset
FileOffset = SectionHeaders[Section].PRawData + dir->SectionOffset;
if (FileOffset == 0 || FileOffset >= DataSize) {
// points outside file
err.submit(2035);
return 0;
}
// FileOffset is within range
dir->FileOffset = FileOffset;
// Maximum allowed offset
dir->MaxOffset = SectionHeaders[Section].SizeOfRawData - dir->SectionOffset;
// Return success
return Section;
}
}
// Import section not found
return 0;
}
void CCOFF::PrintImportExport() {
// Print imported and exported symbols
// Table directory address
SCOFF_ImageDirAddress dir;
uint32 i; // Index into OrdinalTable and NamePointerTable
uint32 Ordinal; // Index into ExportAddressTable
uint32 Address; // Virtual address of exported symbol
uint32 NameOffset; // Section offset of symbol name
uint32 SectionOffset; // Section offset of table
const char * Name; // Name of symbol
// Check if 64 bit
int Is64bit = OptionalHeader->h64.Magic == COFF_Magic_PE64;
// Exported names
if (GetImageDir(0, &dir)) {
// Beginning of export section is export directory
SCOFF_ExportDirectory * pExportDirectory = &Get<SCOFF_ExportDirectory>(dir.FileOffset);
// Find ExportAddressTable
SectionOffset = pExportDirectory->ExportAddressTableRVA - dir.VirtualAddress;
if (SectionOffset == 0 || SectionOffset >= dir.MaxOffset) {
// Points outside section
err.submit(2035); return;
}
uint32 * pExportAddressTable = &Get<uint32>(dir.FileOffset + SectionOffset);
// Find ExportNameTable
SectionOffset = pExportDirectory->NamePointerTableRVA - dir.VirtualAddress;
if (SectionOffset == 0 || SectionOffset >= dir.MaxOffset) {
// Points outside section
err.submit(2035); return;
}
uint32 * pExportNameTable = &Get<uint32>(dir.FileOffset + SectionOffset);
// Find ExportOrdinalTable
SectionOffset = pExportDirectory->OrdinalTableRVA - dir.VirtualAddress;
if (SectionOffset == 0 || SectionOffset >= dir.MaxOffset) {
// Points outside section
err.submit(2035); return;
}
uint16 * pExportOrdinalTable = &Get<uint16>(dir.FileOffset + SectionOffset);
// Get further properties
uint32 NumExports = pExportDirectory->AddressTableEntries;
uint32 NumExportNames = pExportDirectory->NamePointerEntries;
uint32 OrdinalBase = pExportDirectory->OrdinalBase;
// Print exported names
printf("\n\nExported symbols:");
// Loop through export tables
for (i = 0; i < NumExports; i++) {
Address = 0;
Name = "(None)";
// Get ordinal from table
Ordinal = pExportOrdinalTable[i];
// Address table is indexed by ordinal
if (Ordinal < NumExports) {
Address = pExportAddressTable[Ordinal];
}
// Find name if there is a name list entry
if (i < NumExportNames) {
NameOffset = pExportNameTable[i] - dir.VirtualAddress;
if (NameOffset && NameOffset < dir.MaxOffset) {
Name = &Get<char>(dir.FileOffset + NameOffset);
}
}
// Print ordinal, address and name
printf("\n Ordinal %3i, Address %6X, Name %s",
Ordinal + OrdinalBase, Address, Name);
}
}
// Imported names
if (GetImageDir(1, &dir)) {
// Print imported names
printf("\n\nImported symbols:");
// Pointer to current import directory entry
SCOFF_ImportDirectory * ImportEntry = &Get<SCOFF_ImportDirectory>(dir.FileOffset);
// Pointer to current import lookup table entry
int32 * LookupEntry = 0;
// Pointer to current hint/name table entry
SCOFF_ImportHintName * HintNameEntry;
// Loop through import directory until null entry
while (ImportEntry->DLLNameRVA) {
// Get DLL name
NameOffset = ImportEntry->DLLNameRVA - dir.VirtualAddress;
if (NameOffset < dir.MaxOffset) {
Name = &Get<char>(dir.FileOffset + NameOffset);
}
else {
Name = "Error";
}
// Print DLL name
printf("\nFrom %s", Name);
// Get lookup table
SectionOffset = ImportEntry->ImportLookupTableRVA;
if (SectionOffset == 0) SectionOffset = ImportEntry->ImportAddressTableRVA;
if (SectionOffset == 0) continue;
SectionOffset -= dir.VirtualAddress;
if (SectionOffset >= dir.MaxOffset) break; // Out of range
LookupEntry = &Get<int32>(dir.FileOffset + SectionOffset);
// Loop through lookup table
while (LookupEntry[0]) {
if (LookupEntry[Is64bit] < 0) {
// Imported by ordinal
printf("\n Ordinal %i", uint16(LookupEntry[0]));
}
else {
// Find entry in hint/name table
SectionOffset = (LookupEntry[0] & 0x7FFFFFFF) - dir.VirtualAddress;;
if (SectionOffset >= dir.MaxOffset) continue; // Out of range
HintNameEntry = &Get<SCOFF_ImportHintName>(dir.FileOffset + SectionOffset);
// Print name
printf("\n %04X %s", HintNameEntry->Hint, HintNameEntry->Name);
// Check if exported
if (HintNameEntry->Hint) {
// printf(", Export entry %i", HintNameEntry->Hint);
}
}
// Loop next
LookupEntry += Is64bit ? 2 : 1;
}
// Loop next
ImportEntry++;
}
}
}
// Functions for manipulating COFF files
uint32 COFF_PutNameInSymbolTable(SCOFF_SymTableEntry & sym, const char * name, CMemoryBuffer & StringTable) {
// Function to put a name into SCOFF_SymTableEntry.
// Put name in string table if longer than 8 characters.
// Returns index into StringTable if StringTable used
int len = (int)strlen(name); // Length of name
if (len <= 8) {
// Short name. store in section header
memcpy(sym.s.Name, name, len);
// Pad with zeroes
for (; len < 8; len++) sym.s.Name[len] = 0;
}
else {
// Long name. store in string table
sym.stringindex.zeroes = 0;
sym.stringindex.offset = StringTable.PushString(name); // Second integer = entry into string table
return sym.stringindex.offset;
}
return 0;
}
void COFF_PutNameInSectionHeader(SCOFF_SectionHeader & sec, const char * name, CMemoryBuffer & StringTable) {
// Function to put a name into SCOFF_SectionHeader.
// Put name in string table if longer than 8 characters
int len = (int)strlen(name); // Length of name
if (len <= 8) {
// Short name. store in section header
memcpy(sec.Name, name, len);
// Pad with zeroes
for (; len < 8; len++) sec.Name[len] = 0;
}
else {
// Long name. store in string table
sprintf(sec.Name, "/%i", StringTable.PushString(name));
}
}

View File

@ -0,0 +1,537 @@
/**************************** coff.h *************************************
* Author: Agner Fog
* Date created: 2006-07-15
* Last modified: 2008-06-04
* Project: objconv
* Module: coff.h
* Description:
* Header file for definition of structures in MS Windows COFF Intel x86 (PE)
* object file format.
*
* Copyright 2006-2008 GNU General Public License http://www.gnu.org/licenses
* Parts (c) 1995 DJ Delorie GNU General Public License
*****************************************************************************/
/*****************************************************************************
* Note: The COFF data structures do not fit the default alignment of modern
* compilers. All structures should be compiled without any alignment padding.
* The specification of structure packing is not standardized among compilers.
* You may remove or replace the #pragma pack directives if you make sure that
* you never use the sizeof() operator or pointer arithmetics on any of the
* structures that need packing. See coff.cpp for examples.
*****************************************************************************/
#ifndef PECOFF_H
#define PECOFF_H
/********************** FILE HEADER **********************/
struct SCOFF_FileHeader {
uint16 Machine; // Machine ID (magic number)
uint16 NumberOfSections; // number of sections
uint32 TimeDateStamp; // time & date stamp
uint32 PSymbolTable; // file pointer to symbol table
uint32 NumberOfSymbols; // number of symbol table entries
uint16 SizeOfOptionalHeader; // size of optional header
uint16 Flags; // Flags indicating attributes
};
// Values of Machine:
#define PE_MACHINE_I386 0x14c
#define PE_MACHINE_X8664 0x8664
// Bits for Flags:
#define PE_F_RELFLG 0x0001 // relocation info stripped from file
#define PE_F_EXEC 0x0002 // file is executable (no unresolved external references)
#define PE_F_LNNO 0x0004 // line numbers stripped from file
#define PE_F_LSYMS 0x0008 // local symbols stripped from file
// Structure used in optional header
struct SCOFF_IMAGE_DATA_DIRECTORY {
uint32 VirtualAddress; // Image relative address of table
uint32 Size; // Size of table
};
// Extended structure used internally with virtual address translated to section:offset
struct SCOFF_ImageDirAddress : public SCOFF_IMAGE_DATA_DIRECTORY {
int32 Section; // Section containing table
uint32 SectionOffset; // Offset relative to section
uint32 FileOffset; // Offset relative to file
uint32 MaxOffset; // Section size - SectionOffset
const char * Name; // Name of table
};
// Optional header
union SCOFF_OptionalHeader {
// 32 bit version
struct {
uint16 Magic; // Magic number
uint8 LinkerMajorVersion;
uint8 LinkerMinorVersion;
uint32 SizeOfCode;
uint32 SizeOfInitializedData;
uint32 SizeOfUninitializedData;
uint32 AddressOfEntryPoint; // Entry point relative to image base
uint32 BaseOfCode;
uint32 BaseOfData;
// Windows specific fields
int32 ImageBase; // Image base
uint32 SectionAlignment;
uint32 FileAlignment;
uint16 MajorOperatingSystemVersion;
uint16 MinorOperatingSystemVersion;
uint16 MajorImageVersion;
uint16 MinorImageVersion;
uint16 MajorSubsystemVersion;
uint16 MinorSubsystemVersion;
uint32 Win32VersionValue; // must be 0
uint32 SizeOfImage;
uint32 SizeOfHeaders;
uint32 CheckSum;
uint16 Subsystem;
uint16 DllCharacteristics;
uint32 SizeOfStackReserve;
uint32 SizeOfStackCommit;
uint32 SizeOfHeapReserve;
uint32 SizeOfHeapCommit;
uint32 LoaderFlags; // 0
uint32 NumberOfRvaAndSizes;
// Data directories
SCOFF_IMAGE_DATA_DIRECTORY ExportTable;
SCOFF_IMAGE_DATA_DIRECTORY ImportTable;
SCOFF_IMAGE_DATA_DIRECTORY ResourceTable;
SCOFF_IMAGE_DATA_DIRECTORY ExceptionTable;
SCOFF_IMAGE_DATA_DIRECTORY CertificateTable;
SCOFF_IMAGE_DATA_DIRECTORY BaseRelocationTable;
SCOFF_IMAGE_DATA_DIRECTORY Debug;
SCOFF_IMAGE_DATA_DIRECTORY Architecture; // 0
SCOFF_IMAGE_DATA_DIRECTORY GlobalPtr; // 0
SCOFF_IMAGE_DATA_DIRECTORY TLSTable;
SCOFF_IMAGE_DATA_DIRECTORY LoadConfigTable;
SCOFF_IMAGE_DATA_DIRECTORY BoundImportTable;
SCOFF_IMAGE_DATA_DIRECTORY ImportAddressTable;
SCOFF_IMAGE_DATA_DIRECTORY DelayImportDescriptor;
SCOFF_IMAGE_DATA_DIRECTORY CLRRuntimeHeader;
SCOFF_IMAGE_DATA_DIRECTORY Reserved; // 0
} h32;
// 64 bit version
struct {
uint16 Magic; // Magic number
uint8 LinkerMajorVersion;
uint8 LinkerMinorVersion;
uint32 SizeOfCode;
uint32 SizeOfInitializedData;
uint32 SizeOfUninitializedData;
uint32 AddressOfEntryPoint; // Entry point relative to image base
uint32 BaseOfCode;
// Windows specific fields
int64 ImageBase; // Image base
uint32 SectionAlignment;
uint32 FileAlignment;
uint16 MajorOperatingSystemVersion;
uint16 MinorOperatingSystemVersion;
uint16 MajorImageVersion;
uint16 MinorImageVersion;
uint16 MajorSubsystemVersion;
uint16 MinorSubsystemVersion;
uint32 Win32VersionValue; // must be 0
uint32 SizeOfImage;
uint32 SizeOfHeaders;
uint32 CheckSum;
uint16 Subsystem;
uint16 DllCharacteristics;
uint64 SizeOfStackReserve;
uint64 SizeOfStackCommit;
uint64 SizeOfHeapReserve;
uint64 SizeOfHeapCommit;
uint32 LoaderFlags; // 0
uint32 NumberOfRvaAndSizes;
// Data directories
SCOFF_IMAGE_DATA_DIRECTORY ExportTable;
SCOFF_IMAGE_DATA_DIRECTORY ImportTable;
SCOFF_IMAGE_DATA_DIRECTORY ResourceTable;
SCOFF_IMAGE_DATA_DIRECTORY ExceptionTable;
SCOFF_IMAGE_DATA_DIRECTORY CertificateTable;
SCOFF_IMAGE_DATA_DIRECTORY BaseRelocationTable;
SCOFF_IMAGE_DATA_DIRECTORY Debug;
SCOFF_IMAGE_DATA_DIRECTORY Architecture; // 0
SCOFF_IMAGE_DATA_DIRECTORY GlobalPtr; // 0
SCOFF_IMAGE_DATA_DIRECTORY TLSTable;
SCOFF_IMAGE_DATA_DIRECTORY LoadConfigTable;
SCOFF_IMAGE_DATA_DIRECTORY BoundImportTable;
SCOFF_IMAGE_DATA_DIRECTORY ImportAddressTable;
SCOFF_IMAGE_DATA_DIRECTORY DelayImportDescriptor;
SCOFF_IMAGE_DATA_DIRECTORY CLRRuntimeHeader;
SCOFF_IMAGE_DATA_DIRECTORY Reserved; // 0
} h64;
};
// Value of Magic for optional header
#define COFF_Magic_PE32 0x10B
#define COFF_Magic_PE64 0x20B
// Export directory table
struct SCOFF_ExportDirectory {
uint32 Flags;
uint32 DateTime;
uint16 VersionMajor;
uint16 VersionMinor;
uint32 DLLNameRVA; // Image-relative address of DLL name
uint32 OrdinalBase; // Ordinal number of first export
uint32 AddressTableEntries; // Number of entries in export address table
uint32 NamePointerEntries; // Number of entries in name pointer table
uint32 ExportAddressTableRVA; // Image-relative address of export address table
uint32 NamePointerTableRVA; // Image-relative address of export name pointer table
uint32 OrdinalTableRVA; // Image-relative address of ordinal table
};
// Import directory table
struct SCOFF_ImportDirectory {
uint32 ImportLookupTableRVA; // Image-relative address of import lookup table
uint32 DateTime;
uint32 ForwarderChain;
uint32 DLLNameRVA; // Image-relative address of DLL name string
uint32 ImportAddressTableRVA; // Image-relative address of import address table
};
// Import hint/name table entry
struct SCOFF_ImportHintName {
uint16 Hint; // Index into export name pointer table
char Name[2]; // Variable length
};
// Base relocation block header
struct SCOFF_BaseRelocationBlock {
uint32 PageRVA; // Image-relative base to add to offset
uint32 BlockSize; // Size of SCOFF_BaseRelocationBlock plus all SCOFF_BaseRelocation
};
// Base relocation block entry
struct SCOFF_BaseRelocation {
uint16 Offset:12; // Offset relative to PageRVA
uint16 Type:4; // Base relocation type
};
// Base relocation types
#define COFF_REL_BASED_ABSOLUTE 0 // Ignore
#define COFF_REL_BASED_HIGH 1 // High 16 bits
#define COFF_REL_BASED_LOW 2 // Low 16 bits
#define COFF_REL_BASED_HIGHLOW 3 // 32 bits
#define COFF_REL_BASED_HIGHADJ 4 // Two consecutive records: 16 bits high, 16 bits low
#define COFF_REL_BASED_DIR64 10 // 64 bits
/********************** SECTION HEADER **********************/
struct SCOFF_SectionHeader {
char Name[8]; // section name
uint32 VirtualSize; // size of section when loaded. (Should be 0 for object files, but it seems to be accumulated size of all sections)
uint32 VirtualAddress; // subtracted from offsets during relocation. preferably 0
uint32 SizeOfRawData; // section size in file
uint32 PRawData; // file to raw data for section
uint32 PRelocations; // file to relocation entries
uint32 PLineNumbers; // file to line number entries
uint16 NRelocations; // number of relocation entries
uint16 NLineNumbers; // number of line number entries
uint32 Flags; // flags
};
// Section flags values
#define PE_SCN_CNT_CODE 0x00000020 // section contains executable code
#define PE_SCN_CNT_INIT_DATA 0x00000040 // section contains initialized data
#define PE_SCN_CNT_UNINIT_DATA 0x00000080 // section contains unintialized data
#define PE_SCN_LNK_INFO 0x00000200 // section contains comments or .drectve
#define PE_SCN_LNK_REMOVE 0x00000800 // will not be part of the image. object files only
#define PE_SCN_LNK_COMDAT 0x00001000 // section contains communal data
#define PE_SCN_ALIGN_1 0x00100000 // Align data by 1
#define PE_SCN_ALIGN_2 0x00200000 // Align data by 2
#define PE_SCN_ALIGN_4 0x00300000 // Align data by 4
#define PE_SCN_ALIGN_8 0x00400000 // Align data by 8
#define PE_SCN_ALIGN_16 0x00500000 // Align data by 16
#define PE_SCN_ALIGN_32 0x00600000 // Align data by 32
#define PE_SCN_ALIGN_64 0x00700000 // Align data by 64
#define PE_SCN_ALIGN_128 0x00800000 // Align data by 128
#define PE_SCN_ALIGN_256 0x00900000 // Align data by 256
#define PE_SCN_ALIGN_512 0x00a00000 // Align data by 512
#define PE_SCN_ALIGN_1024 0x00b00000 // Align data by 1024
#define PE_SCN_ALIGN_2048 0x00c00000 // Align data by 2048
#define PE_SCN_ALIGN_4096 0x00d00000 // Align data by 4096
#define PE_SCN_ALIGN_8192 0x00e00000 // Align data by 8192
#define PE_SCN_ALIGN_MASK 0x00f00000 // Mask for extracting alignment info
#define PE_SCN_LNK_NRELOC_OVFL 0x01000000 // section contains extended relocations
#define PE_SCN_MEM_DISCARDABLE 0x02000000 // section is discardable
#define PE_SCN_MEM_NOT_CACHED 0x04000000 // section cannot be cached
#define PE_SCN_MEM_NOT_PAGED 0x08000000 // section is not pageable
#define PE_SCN_MEM_SHARED 0x10000000 // section can be shared
#define PE_SCN_MEM_EXECUTE 0x20000000 // section is executable
#define PE_SCN_MEM_READ 0x40000000 // section is readable
#define PE_SCN_MEM_WRITE 0x80000000 // section is writeable
/* names of "special" sections
#define _TEXT ".text"
#define _DATA ".data"
#define _BSS ".bss"
#define _COMMENT ".comment"
#define _LIB ".lib" */
/********************** LINE NUMBERS **********************/
/* 1 line number entry for every "breakpointable" source line in a section.
* Line numbers are grouped on a per function basis; first entry in a function
* grouping will have l_lnno = 0 and in place of physical address will be the
* symbol table index of the function name.
*/
//#pragma pack(push, 1)
struct SCOFF_LineNumbers {
union {
uint32 Fname; // function name symbol table index, if Line == 0
uint32 Addr; // section-relative address of code that corresponds to line
};
uint16 Line; // line number
};
// Warning: Size does not fit standard alignment!
// Use SIZE_SCOFF_LineNumbers instead of sizeof(SCOFF_LineNumbers)
#define SIZE_SCOFF_LineNumbers 6 // Size of SCOFF_LineNumbers packed
//#pragma pack(pop)
/******** Symbol table entry and auxiliary Symbol table entry ********/
//#pragma pack(push, 1) //__attribute__((packed));
union SCOFF_SymTableEntry {
// Normal symbol table entry
struct {
char Name[8];
uint32 Value;
int16 SectionNumber;
uint16 Type;
uint8 StorageClass;
uint8 NumAuxSymbols;
} s;
// Auxiliary symbol table entry types:
// Function definition
struct {
uint32 TagIndex; // Index to .bf entry
uint32 TotalSize; // Size of function code
uint32 PointerToLineNumber; // Pointer to line number entry
uint32 PointerToNextFunction; // Symbol table index of next function
uint16 x_tvndx; // Unused
} func;
// .bf abd .ef
struct {
uint32 Unused1;
uint16 SourceLineNumber; // Line number in source file
uint16 Unused2;
uint32 Unused3; // Pointer to line number entry
uint32 PointerToNextFunction; // Symbol table index of next function
uint16 Unused4; // Unused
} bfef;
// Weak external
struct {
uint32 TagIndex; // Symbol table index of alternative symbol2
uint32 Characteristics; //
uint32 Unused1;
uint32 Unused2;
uint16 Unused3; // Unused
} weak;
// File name
struct {
char FileName[18];// File name
} filename;
// String table index
struct { // MS COFF uses multiple aux records rather than a string table entry!
uint32 zeroes; // zeroes if name file name longer than 18
uint32 offset; // string table entry
} stringindex;
// Section definition
struct {
uint32 Length;
uint16 NumberOfRelocations; // Line number in source file
uint16 NumberOfLineNumbers;
uint32 CheckSum; // Pointer to line number entry
uint16 Number; // Symbol table index of next function
uint8 Selection; // Unused
uint8 Unused1[3];
} section;
};
// Warning: Size does not fit standard alignment!
// Use SIZE_SCOFF_SymTableEntry instead of sizeof(SCOFF_SymTableEntry)
#define SIZE_SCOFF_SymTableEntry 18 // Size of SCOFF_SymTableEntry packed
// values of weak.Characteristics
#define IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY 1
#define IMAGE_WEAK_EXTERN_SEARCH_LIBRARY 2
#define IMAGE_WEAK_EXTERN_SEARCH_ALIAS 3
/*
#define N_BTMASK (0xf)
#define N_TMASK (0x30)
#define N_BTSHFT (4)
#define N_TSHIFT (2) */
//#pragma pack(pop)
/********************** Section number values for symbol table entries **********************/
#define COFF_SECTION_UNDEF ((int16)0) // external symbol
#define COFF_SECTION_ABSOLUTE ((int16)-1) // value of symbol is absolute
#define COFF_SECTION_DEBUG ((int16)-2) // debugging symbol - value is meaningless
#define COFF_SECTION_N_TV ((int16)-3) // indicates symbol needs preload transfer vector
#define COFF_SECTION_P_TV ((int16)-4) // indicates symbol needs postload transfer vector
#define COFF_SECTION_REMOVE_ME ((int16)-99)// Specific for objconv program: Debug or exception section being removed
/*
* Type of a symbol, in low N bits of the word
#define T_NULL 0
#define T_VOID 1 // function argument (only used by compiler)
#define T_CHAR 2 // character
#define T_SHORT 3 // short integer
#define T_INT 4 // integer
#define T_LONG 5 // long integer
#define T_FLOAT 6 // floating point
#define T_DOUBLE 7 // double word
#define T_STRUCT 8 // structure
#define T_UNION 9 // union
#define T_ENUM 10 // enumeration
#define T_MOE 11 // member of enumeration
#define T_UCHAR 12 // unsigned character
#define T_USHORT 13 // uint16
#define T_UINT 14 // unsigned integer
#define T_ULONG 15 // uint32
#define T_LNGDBL 16 // long double
*/
/*
* derived types, in n_type
#define DT_NON (0) // no derived type
#define DT_PTR (1) // pointer
#define DT_FCN (2) // function
#define DT_ARY (3) // array
#define BTYPE(x) ((x) & N_BTMASK)
#define ISPTR(x) (((x) & N_TMASK) == (DT_PTR << N_BTSHFT))
#define ISFCN(x) (((x) & N_TMASK) == (DT_FCN << N_BTSHFT))
#define ISARY(x) (((x) & N_TMASK) == (DT_ARY << N_BTSHFT))
#define ISTAG(x) ((x)==C_STRTAG||(x)==C_UNTAG||(x)==C_ENTAG)
#define DECREF(x) ((((x)>>N_TSHIFT)&~N_BTMASK)|((x)&N_BTMASK))
*/
/********************** Storage classes for symbol table entries **********************/
#define COFF_CLASS_NULL 0
#define COFF_CLASS_AUTOMATIC 1 // automatic variable
#define COFF_CLASS_EXTERNAL 2 // external symbol
#define COFF_CLASS_STATIC 3 // static
#define COFF_CLASS_REGISTER 4 // register variable
#define COFF_CLASS_EXTERNAL_DEF 5 // external definition
#define COFF_CLASS_LABEL 6 // label
#define COFF_CLASS_UNDEFINED_LABEL 7 // undefined label
#define COFF_CLASS_MEMBER_OF_STRUCTURE 8 // member of structure
#define COFF_CLASS_ARGUMENT 9 // function argument
#define COFF_CLASS_STRUCTURE_TAG 10 // structure tag
#define COFF_CLASS_MEMBER_OF_UNION 11 // member of union
#define COFF_CLASS_UNION_TAG 12 // union tag
#define COFF_CLASS_TYPE_DEFINITION 13 // type definition
#define COFF_CLASS_UNDEFINED_STATIC 14 // undefined static
#define COFF_CLASS_ENUM_TAG 15 // enumeration tag
#define COFF_CLASS_MEMBER_OF_ENUM 16 // member of enumeration
#define COFF_CLASS_REGISTER_PARAM 17 // register parameter
#define COFF_CLASS_BIT_FIELD 18 // bit field
#define COFF_CLASS_AUTO_ARGUMENT 19 // auto argument
#define COFF_CLASS_LASTENTRY 20 // dummy entry (end of block)
#define COFF_CLASS_BLOCK 100 // ".bb" or ".eb"
#define COFF_CLASS_FUNCTION 101 // ".bf" or ".ef"
#define COFF_CLASS_END_OF_STRUCT 102 // end of structure
#define COFF_CLASS_FILE 103 // file name
#define COFF_CLASS_LINE 104 // line # reformatted as symbol table entry
#define COFF_CLASS_SECTION 104 // line # reformatted as symbol table entry
#define COFF_CLASS_ALIAS 105 // duplicate tag
#define COFF_CLASS_WEAK_EXTERNAL 105 // duplicate tag
#define COFF_CLASS_HIDDEN 106 // ext symbol in dmert public lib
#define COFF_CLASS_END_OF_FUNCTION 0xff // physical end of function
/********************** Type for symbol table entries **********************/
#define COFF_TYPE_FUNCTION 0x20 // Symbol is function
#define COFF_TYPE_NOT_FUNCTION 0x00 // Symbol is not a function
/********************** Relocation table entry **********************/
//#pragma pack(push, 1) //__attribute__((packed));
struct SCOFF_Relocation {
uint32 VirtualAddress; // Section-relative address of relocation source
uint32 SymbolTableIndex; // Zero-based index into symbol table
uint16 Type; // Relocation type
};
#define SIZE_SCOFF_Relocation 10 // Size of SCOFF_Relocation packed
//#pragma pack(pop)
/********************** Relocation types for 32-bit COFF **********************/
#define COFF32_RELOC_ABS 0x00 // Ignored
#define COFF32_RELOC_DIR16 0x01 // Not supported
#define COFF32_RELOC_REL16 0x02 // Not supported
#define COFF32_RELOC_DIR32 0x06 // 32-bit absolute virtual address
#define COFF32_RELOC_IMGREL 0x07 // 32-bit image relative virtual address
#define COFF32_RELOC_SEG12 0x09 // not supported
#define COFF32_RELOC_SECTION 0x0A // 16-bit section index in file
#define COFF32_RELOC_SECREL 0x0B // 32-bit section-relative
#define COFF32_RELOC_SECREL7 0x0D // 7-bit section-relative
#define COFF32_RELOC_TOKEN 0x0C // CLR token
#define COFF32_RELOC_REL32 0x14 // 32-bit EIP-relative
/********************** Relocation types for 64-bit COFF **********************/
// Note: These values are obtained by my own testing.
// I haven't found any official values
#define COFF64_RELOC_ABS 0x00 // Ignored
#define COFF64_RELOC_ABS64 0x01 // 64 bit absolute virtual address
#define COFF64_RELOC_ABS32 0x02 // 32 bit absolute virtual address
#define COFF64_RELOC_IMGREL 0x03 // 32 bit image-relative
#define COFF64_RELOC_REL32 0x04 // 32 bit, RIP-relative
#define COFF64_RELOC_REL32_1 0x05 // 32 bit, relative to RIP - 1. For instruction with immediate byte operand
#define COFF64_RELOC_REL32_2 0x06 // 32 bit, relative to RIP - 2. For instruction with immediate word operand
#define COFF64_RELOC_REL32_3 0x07 // 32 bit, relative to RIP - 3. (useless)
#define COFF64_RELOC_REL32_4 0x08 // 32 bit, relative to RIP - 4. For instruction with immediate dword operand
#define COFF64_RELOC_REL32_5 0x09 // 32 bit, relative to RIP - 5. (useless)
#define COFF64_RELOC_SECTION 0x0A // 16-bit section index in file. For debug purpose
#define COFF64_RELOC_SECREL 0x0B // 32-bit section-relative
#define COFF64_RELOC_SECREL7 0x0C // 7-bit section-relative
#define COFF64_RELOC_TOKEN 0x0D // CLR token = 64 bit absolute virtual address. Inline addend ignored
#define COFF64_RELOC_SREL32 0x0E // 32 bit signed span dependent
#define COFF64_RELOC_PAIR 0x0F // pair after span dependent
#define COFF64_RELOC_PPC_REFHI 0x10 // high 16 bits of 32 bit abs addr
#define COFF64_RELOC_PPC_REFLO 0x11 // low 16 bits of 32 bit abs addr
#define COFF64_RELOC_PPC_PAIR 0x12 // pair after REFHI
#define COFF64_RELOC_PPC_SECRELO 0x13 // low 16 bits of section relative
#define COFF64_RELOC_PPC_GPREL 0x15 // 16 bit signed relative to GP
#define COFF64_RELOC_PPC_TOKEN 0x16 // CLR token
/********************** Strings **********************/
#define COFF_CONSTRUCTOR_NAME ".CRT$XCU" // Name of constructors segment
// Function prototypes
// Function to put a name into SCOFF_SymTableEntry. Put name in string table
// if longer than 8 characters
uint32 COFF_PutNameInSymbolTable(SCOFF_SymTableEntry & sym, const char * name, CMemoryBuffer & StringTable);
// Function to put a name into SCOFF_SectionHeader. Put name in string table
// if longer than 8 characters
void COFF_PutNameInSectionHeader(SCOFF_SectionHeader & sec, const char * name, CMemoryBuffer & StringTable);
#endif // #ifndef PECOFF_H

View File

@ -0,0 +1,718 @@
/**************************** containers.cpp **********************************
* Author: Agner Fog
* Date created: 2006-07-15
* Last modified: 2016-07-07
* Project: objconv
* Module: containers.cpp
* Description:
* Objconv is a portable C++ program for converting object file formats.
* Compile for console mode on any platform.
*
* This module contains container classes CMemoryBuffer and CFileBuffer for
* dynamic memory allocation and file read/write. See containers.h for
* further description.
*
* Copyright 2006-2016 GNU General Public License http://www.gnu.org/licenses
*****************************************************************************/
#include "stdafx.h"
// Names of file formats
SIntTxt FileFormatNames[] = {
{FILETYPE_COFF, "COFF"},
{FILETYPE_OMF, "OMF"},
{FILETYPE_ELF, "ELF"},
{FILETYPE_MACHO_LE, "Mach-O Little Endian"},
{FILETYPE_MACHO_BE, "Mach-O Big Endian"},
{FILETYPE_DOS, "DOS executable"},
{FILETYPE_WIN3X, "Windows 3.x executable"},
{FILETYPE_LIBRARY, "Function library"},
{FILETYPE_OMFLIBRARY, "Function library (OMF)"},
{IMPORT_LIBRARY_MEMBER, "Windows import library member"},
{FILETYPE_MAC_UNIVBIN, "MacIntosh universal binary"},
{FILETYPE_MS_WPO, "Whole program optimization intermediate file, Microsoft specific"},
{FILETYPE_INTEL_WPO, "Whole program optimization intermediate file, Intel specific"},
{FILETYPE_WIN_UNKNOWN, "Unknown subtype, Windows"},
{FILETYPE_ASM, "Disassembly"}
};
// Members of class CMemoryBuffer
CMemoryBuffer::CMemoryBuffer() {
// Constructor
buffer = 0;
NumEntries = DataSize = BufferSize = 0;
}
CMemoryBuffer::~CMemoryBuffer() {
// Destructor
SetSize(0); // De-allocate buffer
}
void CMemoryBuffer::SetSize(uint32 size) {
// Allocate, reallocate or deallocate buffer of specified size.
// DataSize is initially zero. It is increased by Push or PushString.
// Setting size > DataSize will allocate more buffer and fill it with zeroes but not increase DataSize.
// Setting size < DataSize will decrease DataSize so that some of the data are discarded.
// Setting size = 0 will discard all data and de-allocate the buffer.
if (size == 0) {
// Deallocate
if (buffer) delete[] buffer; // De-allocate buffer
buffer = 0;
NumEntries = DataSize = BufferSize = 0;
return;
}
if (size < DataSize) {
// Request to delete some data
DataSize = size;
return;
}
if (size <= BufferSize) {
// Request to reduce size but not delete it
return; // Ignore
}
// size = (size + 15) & uint32(-16); // Round up size to value divisible by 16
size = (size + BufferSize + 15) & uint32(-16); // Double size and round up to value divisible by 16
int8 * buffer2 = 0; // New buffer
buffer2 = new int8[size]; // Allocate new buffer
if (buffer2 == 0) {err.submit(9006); return;} // Error can't allocate
memset (buffer2, 0, size); // Initialize to all zeroes
if (buffer) {
// A smaller buffer is previously allocated
memcpy (buffer2, buffer, BufferSize); // Copy contents of old buffer into new
delete[] buffer; // De-allocate old buffer
}
buffer = buffer2; // Save pointer to buffer
BufferSize = size; // Save size
}
uint32 CMemoryBuffer::Push(void const * obj, uint32 size) {
// Add object to buffer, return offset
// Parameters:
// obj = pointer to object, 0 if fill with zeroes
// size = size of object to push
// Old offset will be offset to new object
uint32 OldOffset = DataSize;
// New data size will be old data size plus size of new object
uint32 NewOffset = DataSize + size;
if (NewOffset > BufferSize) {
// Buffer too small, allocate more space.
// We can use SetSize for this only if it is certain that obj is not
// pointing to an object previously allocated in the old buffer
// because it would be deallocated before copied into the new buffer:
// SetSize (NewOffset + NewOffset / 2 + 1024);
// Allocate more space without using SetSize:
// Double the size + 1 kB, and round up size to value divisible by 16
uint32 NewSize = (NewOffset * 2 + 1024 + 15) & uint32(-16);
int8 * buffer2 = 0; // New buffer
// Allocate new buffer
buffer2 = new int8[NewSize];
if (buffer2 == 0) {
// Error can't allocate
err.submit(9006); return 0;
}
// Initialize to all zeroes
memset (buffer2, 0, NewSize);
if (buffer) {
// A smaller buffer is previously allocated
// Copy contents of old buffer into new
memcpy (buffer2, buffer, BufferSize);
}
BufferSize = NewSize; // Save size
if (obj && size) {
// Copy object to new buffer
memcpy (buffer2 + OldOffset, obj, size);
obj = 0; // Prevent copying once more
}
// Delete old buffer after copying object
if (buffer) delete[] buffer;
// Save pointer to new buffer
buffer = buffer2;
}
// Copy object to buffer if nonzero
if (obj && size) {
memcpy (buffer + OldOffset, obj, size);
}
if (size) {
// Adjust new offset
DataSize = NewOffset;
NumEntries++;
}
// Return offset to allocated object
return OldOffset;
}
uint32 CMemoryBuffer::PushString(char const * s) {
// Add ASCIIZ string to buffer, return offset
return Push (s, uint32(strlen(s))+1);
}
uint32 CMemoryBuffer::GetLastIndex() {
// Index of last object pushed (zero-based)
return NumEntries - 1;
}
void CMemoryBuffer::SetDataSize(uint32 size) {
if (size > BufferSize) {
// Allocate more space
SetSize(size + 2048);
}
// Set DataSize to after alignment space
DataSize = size;
}
void CMemoryBuffer::Align(uint32 a) {
// Align next entry to address divisible by a
SetDataSize((DataSize + a - 1) / a * a);
}
// Members of class CFileBuffer
CFileBuffer::CFileBuffer() : CMemoryBuffer() {
// Default constructor
FileName = 0;
OutputFileName = 0;
FileType = WordSize = Executable = 0;
}
CFileBuffer::CFileBuffer(char const * filename) : CMemoryBuffer() {
// Constructor
FileName = filename;
FileType = WordSize = 0;
}
void CFileBuffer::Read(int IgnoreError) {
// Read file into buffer
uint32 status; // Error status
#ifdef _MSC_VER // Microsoft compiler prefers this:
int fh; // File handle
fh = _open(FileName, O_RDONLY | O_BINARY); // Open file in binary mode
if (fh == -1) {
// Cannot read file
if (!IgnoreError) err.submit(2103, FileName); // Error. Input file must be read
SetSize(0); return; // Make empty file buffer
}
DataSize = filelength(fh); // Get file size
if (DataSize <= 0) {
if (!IgnoreError) err.submit(2105, FileName); // Wrong size
return;}
SetSize(DataSize + 2048); // Allocate buffer, 2k extra
status = _read(fh, Buf(), DataSize); // Read from file
if (status != DataSize) err.submit(2103, FileName);
status = _close(fh); // Close file
if (status != 0) err.submit(2103, FileName);
#else // Works with most compilers:
FILE * fh = fopen(FileName, "rb");
if (!fh) {
// Cannot read file
if (!IgnoreError) err.submit(2103, FileName); // Error. Input file must be read
SetSize(0); return; // Make empty file buffer
}
// Find file size
fseek(fh, 0, SEEK_END);
long int fsize = ftell(fh);
if (fsize <= 0 || (unsigned long)fsize >= 0xFFFFFFFF) {
// File too big or zero size
err.submit(2105, FileName); fclose(fh); return;
}
DataSize = (uint32)fsize;
rewind(fh);
// Allocate buffer
SetSize(DataSize + 2048); // Allocate buffer, 2k extra
// Read entire file
status = (uint32)fread(Buf(), 1, DataSize, fh);
if (status != DataSize) err.submit(2103, FileName);
status = fclose(fh);
if (status != 0) err.submit(2103, FileName);
#endif
}
void CFileBuffer::Write() {
// Write buffer to file:
if (OutputFileName) FileName = OutputFileName;
// Two alternative ways to write a file:
#ifdef _MSC_VER // Microsoft compiler prefers this:
int fh; // File handle
uint32 status; // Error status
// Open file in binary mode
fh = _open(FileName, O_RDWR | O_BINARY | O_CREAT | O_TRUNC, _S_IREAD | _S_IWRITE);
// Check if error
if (fh == -1) {err.submit(2104, FileName); return;}
// Write file
status = _write(fh, Buf(), DataSize);
// Check if error
if (status != DataSize) err.submit(2104, FileName);
// Close file
status = _close(fh);
// Check if error
if (status != 0) err.submit(2104, FileName);
#else // Works with most compilers:
// Open file in binary mode
FILE * ff = fopen(FileName, "wb");
// Check if error
if (!ff) {err.submit(2104, FileName); return;}
// Write file
uint32 n = (uint32)fwrite(Buf(), 1, DataSize, ff);
// Check if error
if (n != DataSize) err.submit(2104, FileName);
// Close file
n = fclose(ff);
// Check if error
if (n) {err.submit(2104, FileName); return;}
#endif
}
int CFileBuffer::GetFileType() {
// Detect file type
if (FileType) return FileType; // File type already known
if (!DataSize) return 0; // No file
if (!Buf()) return 0; // No contents
uint32 namelen = FileName ? (uint32)strlen(FileName) : 0;
if (strncmp(Buf(),"!<arch>",7) == 0) {
// UNIX style library. Contains members of file type COFF, ELF or MACHO
FileType = FILETYPE_LIBRARY;
}
else if (strncmp(Buf(),ELFMAG,4) == 0) {
// ELF file
FileType = FILETYPE_ELF;
Executable = Get<Elf32_Ehdr>(0).e_type != ET_REL;
switch (Buf()[EI_CLASS]) {
case ELFCLASS32:
WordSize = 32; break;
case ELFCLASS64:
WordSize = 64; break;
}
}
else if (Get<uint32>(0) == MAC_MAGIC_32) {
// Mach-O 32 little endian
FileType = FILETYPE_MACHO_LE;
WordSize = 32;
Executable = Get<MAC_header_32>(0).filetype != MAC_OBJECT;
}
else if (Get<uint32>(0) == MAC_MAGIC_64) {
// Mach-O 64 little endian
FileType = FILETYPE_MACHO_LE;
WordSize = 64;
Executable = Get<MAC_header_64>(0).filetype != MAC_OBJECT;
}
else if (Get<uint32>(0) == MAC_CIGAM_32) {
// Mach-O 32 big endian
FileType = FILETYPE_MACHO_BE;
WordSize = 32;
}
else if (Get<uint32>(0) == MAC_CIGAM_64) {
// Mach-O 64 big endian
FileType = FILETYPE_MACHO_BE;
WordSize = 64;
}
else if (Get<uint32>(0) == MAC_CIGAM_UNIV) {
// MacIntosh universal binary
FileType = FILETYPE_MAC_UNIVBIN;
WordSize = 0;
}
else if (Get<uint32>(0) == 0xFFFF0000 || Get<uint32>(0) == 0x10000) {
// Windows subtypes:
if (Get<uint16>(4) == 0) {
// This type only occurs when attempting to extract a member from an import library
FileType = IMPORT_LIBRARY_MEMBER;
}
else if (Get<uint16>(4) == 1) {
// Whole program optimization intermediate file for MS compiler. Undocumented
FileType = FILETYPE_MS_WPO;
}
else {
// Other subtypes not known
FileType = FILETYPE_WIN_UNKNOWN;
}
// Get word size
if (Get<uint16>(6) == PE_MACHINE_I386) {
WordSize = 32;
}
else if (Get<uint16>(6) == PE_MACHINE_X8664) {
WordSize = 64;
}
else {
WordSize = 0;
}
}
else if (Get<uint16>(0) == PE_MACHINE_I386) {
// COFF/PE 32
FileType = FILETYPE_COFF;
WordSize = 32;
Executable = (Get<SCOFF_FileHeader>(0).Flags & PE_F_EXEC) != 0;
}
else if (Get<uint16>(0) == PE_MACHINE_X8664) {
// COFF64/PE32+
FileType = FILETYPE_COFF;
WordSize = 64;
Executable = (Get<SCOFF_FileHeader>(0).Flags & PE_F_EXEC) != 0;
}
else if (Get<uint8>(0) == OMF_THEADR) {
// OMF 16 or 32
FileType = FILETYPE_OMF;
// Word size can only be determined by searching through records in file:
GetOMFWordSize(); // Determine word size
}
else if (Get<uint8>(0) == OMF_LIBHEAD) {
// OMF Library 16 or 32
FileType = FILETYPE_OMFLIBRARY;
}
else if ((Get<uint16>(0) & 0xFFF9) == 0x5A49) {
// DOS file or file with DOS stub
FileType = FILETYPE_DOS;
WordSize = 16;
Executable = 1;
uint32 Signature = Get<uint32>(0x3C);
if (Signature + 8 < DataSize) {
if (Get<uint16>(Signature) == 0x454E) {
// Windows 3.x file
FileType = FILETYPE_WIN3X;
}
else if (Get<uint16>(Signature) == 0x4550) {
// COFF file
uint16 MachineType = Get<uint16>(Signature + 4);
if (MachineType == PE_MACHINE_I386) {
FileType = FILETYPE_COFF;
WordSize = 32;
}
else if (MachineType == PE_MACHINE_X8664) {
FileType = FILETYPE_COFF;
WordSize = 64;
}
}
}
}
else if (namelen > 4 && stricmp(FileName + namelen - 4, ".com") == 0) {
// DOS .com file recognized only from its extension
FileType = FILETYPE_DOS;
WordSize = 16; Executable = 1;
}
else if (Get<uint16>(0) == 0 && namelen > 4 && stricmp(FileName + namelen - 4, ".obj") == 0) {
// Possibly alias record in COFF library
FileType = FILETYPE_COFF;
WordSize = 0;
Executable = 0;
}
else {
// Unknown file type
int utype = Get<uint32>(0);
err.submit(2018, utype, FileName);
FileType = 0;
}
return FileType;
}
char const * CFileBuffer::GetFileFormatName(int FileType) {
// Get name of file format type
return Lookup (FileFormatNames, FileType);
}
void CFileBuffer::SetFileType(int type) {
// Set file format type
FileType = type;
}
void CFileBuffer::Reset() {
// Set all members to zero
SetSize(0); // Deallocate memory buffer
memset(this, 0, sizeof(*this));
}
char * CFileBuffer::SetFileNameExtension(const char * f) {
// Set file name extension according to FileType
static char name[MAXFILENAMELENGTH+8];
int i;
if (strlen(f) > MAXFILENAMELENGTH) err.submit(2203, f);
strncpy(name, f, MAXFILENAMELENGTH);
// Search for last '.' in file name
for (i = (int)strlen(name)-1; i > 0; i--) if (name[i] == '.') break;
if (i < 1) {
// '.' not found. Append '.' to name
i = (int)strlen(name); if (i > MAXFILENAMELENGTH-4) i = MAXFILENAMELENGTH-4;
}
// Get default extension
if (cmd.OutputType == FILETYPE_ASM) {
strcpy(name+i, ".asm"); // Assembly file
}
else if (cmd.OutputType == FILETYPE_COFF || cmd.OutputType == FILETYPE_OMF) {
if ((FileType & (FILETYPE_LIBRARY | FILETYPE_OMFLIBRARY)) || (cmd.LibraryOptions & CMDL_LIBRARY_ADDMEMBER)) {
strcpy(name+i, ".lib"); // Windows function library
}
else {
strcpy(name+i, ".obj"); // Windows object file
}
}
else { // output type is ELF or MACHO
if ((FileType & (FILETYPE_LIBRARY | FILETYPE_OMFLIBRARY)) || (cmd.LibraryOptions & CMDL_LIBRARY_ADDMEMBER)) {
strcpy(name+i, ".a"); // Linux/BSD/Mac function library
}
else {
strcpy(name+i, ".o"); // Linux/BSD/Mac object file
}
}
return name;
}
void CFileBuffer::CheckOutputFileName() {
// Make output file name or check that requested name is valid
if (!(cmd.FileOptions & CMDL_FILE_OUTPUT)) return;
OutputFileName = cmd.OutputFile;
if (OutputFileName == 0) {
// Output file name not specified. Make filename
OutputFileName = cmd.OutputFile = SetFileNameExtension(FileName);
}
if (strcmp(FileName,OutputFileName) == 0 && !(cmd.FileOptions & CMDL_FILE_IN_OUT_SAME)) {
// Input and output files have same name
err.submit(2005, FileName);
}
}
void operator >> (CFileBuffer & a, CFileBuffer & b) {
// Transfer ownership of buffer and other properties from a to b
b.SetSize(0); // De-allocate old buffer from target if it has one
b.buffer = a.buffer; // Transfer buffer
a.buffer = 0; // Remove buffer from source, so that buffer has only one owner
// Copy properties
b.DataSize = a.GetDataSize(); // Size of data, offset to vacant space
b.BufferSize = a.GetBufferSize(); // Size of allocated buffer
b.NumEntries = a.GetNumEntries(); // Number of objects pushed
b.Executable = a.Executable; // File is executable
if (a.WordSize) b.WordSize = a.WordSize; // Segment word size (16, 32, 64)
if (a.FileName) b.FileName = a.FileName; // Name of input file
if (a.OutputFileName) b.OutputFileName = a.OutputFileName;// Name of output file
if (a.GetFileType()) b.FileType = a.GetFileType(); // Object file type
a.SetSize(0); // Reset a's properties
}
void CFileBuffer::GetOMFWordSize() {
// Determine word size for OMF file.
// There is no simple way to get the word size. Looking for odd-numbered
// record types is not sufficient. A 32-bit OMF file may use 16-bit SEGDEF
// records. We have to look for segments with the 'P' attribute set. And
// even this is not completely safe, because MASM may generate empty 32-bit
// segments so we have to look only at segments with nonzero size.
// We can still have any mixture of 16- and 32-bit segments, though, so no
// method is absolutely safe.
// We have to parse through all records in file buffer
uint8 RecordType; // Type of current record
uint32 RecordStart; // Index to start of current record
uint32 RecordEnd; // Index to end of current record
uint32 RecordLength; // Length of current record
uint32 Index = 0; // Current offset from buffer while reading
OMF_SAttrib SegAttr; // Segment attributed
uint32 SegLength; // Segment length
WordSize = 16; // WordSize = 16 if no 32 bit records found
while (Index < GetDataSize()) {
RecordStart = Index; // Record starts here
RecordType = Get<uint8>(Index++); // Get first byte of record = type
RecordLength = Get<uint16>(Index); // Next two bytes = length
Index += 2;
RecordEnd = RecordStart + RecordLength + 3;// End of record
if (RecordEnd > GetDataSize()) {
// Record goes beyond end of file
err.submit(2301); break;
}
if ((RecordType & 1) && RecordType < OMF_LIBHEAD) { // Odd-numbered type means 32 bit
WordSize = 32; // ..but this method is not safe
}
if ((RecordType & 0xFE) == OMF_SEGDEF) { // Segment definition record
SegAttr.b = Get<uint8>(Index++); // Get segment attributes
if (SegAttr.u.A == 0) {
// Frame and Offset only included if A = 0
Index += 2+1;
}
SegLength = (RecordType & 1) ? Get<uint32>(Index) : Get<uint16>(Index); // Segment length
if (SegAttr.u.P && SegLength) { // if segment has P attribute and nonzero length
WordSize = 32; // .. then it is a 32-bit segment
}
}
Index = RecordEnd; // Point to next record
}
}
// Class CTextFileBuffer is used for building text files
// Constructor
CTextFileBuffer::CTextFileBuffer() {
column = 0;
// Use UNIX linefeeds only if GASM output
LineType = (cmd.SubType == SUBTYPE_GASM) ? 1 : 0;
}
void CTextFileBuffer::Put(const char * text) {
// Write text string to buffer
uint32 len = (uint32)strlen(text); // Length of text
Push(text, len); // Add to buffer without terminating zero
column += len; // Update column
}
void CTextFileBuffer::Put(const char character) {
// Write single character to buffer
Push(&character, 1); // Add to buffer
column ++; // Update column
}
void CTextFileBuffer::NewLine() {
// Add linefeed
if (LineType == 0) {
Push("\r\n", 2); // DOS/Windows style linefeed
}
else {
Push("\n", 1); // UNIX style linefeed
}
column = 0; // Reset column
}
void CTextFileBuffer::Tabulate(uint32 i) {
// Insert spaces until column i
uint32 j;
if (i > column) { // Only insert spaces if we are not already past i
for (j = column; j < i; j++) Push(" ", 1); // Insert i - column spaces
column = i; // Update column
}
}
void CTextFileBuffer::PutDecimal(int32 x, int IsSigned) {
// Write decimal number to buffer, unsigned or signed
char text[16];
sprintf(text, IsSigned ? "%i" : "%u", x);
Put(text);
}
void CTextFileBuffer::PutHex(uint8 x, int MasmForm) {
// Write hexadecimal 8 bit number to buffer
// If MasmForm >= 1 then the function will write the number in a
// way that can be read by the assembler, e.g. 0FFH or 0xFF
char text[16];
if (MasmForm && cmd.SubType == SUBTYPE_GASM) {
// Needs 0x prefix
sprintf(text, "0x%02X", x);
Put(text);
return;
}
if (MasmForm && x >= 0xA0) {
Put("0"); // Make sure it doesn't begin with a letter
}
sprintf(text, "%02X", x);
Put(text);
if (MasmForm) Put("H");
}
void CTextFileBuffer::PutHex(uint16 x, int MasmForm) {
// Write hexadecimal 16 bit number to buffer
// If MasmForm >= 1 then the function will write the number in a
// way that can be read by the assembler, e.g. 0FFH or 0xFF
// If MasmForm == 2 then leading zeroes are stripped
char text[16];
if (MasmForm && cmd.SubType == SUBTYPE_GASM) {
// Needs 0x prefix
sprintf(text, MasmForm==1 ? "0x%04X" : "0x%X", x);
Put(text);
return;
}
sprintf(text, (MasmForm < 2) ? "%04X" : "%X", x);
// Check if leading zero needed
if (MasmForm && text[0] > '9') {
Put("0"); // Leading zero needed
}
Put(text);
if (MasmForm) Put("H");
}
void CTextFileBuffer::PutHex(uint32 x, int MasmForm) {
// Write hexadecimal 32 bit number to buffer
// If MasmForm >= 1 then the function will write the number in a
// way that can be read by the assembler, e.g. 0FFH or 0xFF
// If MasmForm == 2 then leading zeroes are stripped
char text[16];
if (MasmForm && cmd.SubType == SUBTYPE_GASM) {
// Needs 0x prefix
sprintf(text, MasmForm==1 ? "0x%08X" : "0x%X", x);
Put(text);
return;
}
sprintf(text, (MasmForm < 2) ? "%08X" : "%X", x);
// Check if leading zero needed
if (MasmForm && text[0] > '9') {
Put("0"); // Leading zero needed
}
Put(text);
if (MasmForm) Put("H");
}
void CTextFileBuffer::PutHex(uint64 x, int MasmForm) {
// Write unsigned hexadecimal 64 bit number to buffer
// If MasmForm >= 1 then the function will write the number in a
// way that can be read by the assembler, e.g. 0FFH or 0xFF
// If MasmForm == 2 then leading zeroes are stripped
char text[32];
if (MasmForm < 2) { // Print all digits
sprintf(text, "%08X%08X", HighDWord(x), uint32(x));
}
else { // Skip leading zeroes
if (HighDWord(x)) {
sprintf(text, "%X%08X", HighDWord(x), uint32(x));
}
else {
sprintf(text, "%X", uint32(x));
}
}
if (MasmForm) {
if (cmd.SubType == SUBTYPE_GASM) {
// Needs 0x prefix
Put("0x");
Put(text);
}
else {
// use 0FFH form
if (text[0] > '9') Put("0"); // Leading zero needed
Put(text);
Put("H");
}
}
else {
// write hexadecimal number only
Put(text);
}
}
void CTextFileBuffer::PutFloat(float x) {
// Write floating point number to buffer
char text[64];
sprintf(text, "%.7G", x);
Put(text);
}
void CTextFileBuffer::PutFloat(double x) {
// Write floating point number to buffer
char text[64];
sprintf(text, "%.16G", x);
Put(text);
}

View File

@ -0,0 +1,393 @@
/**************************** containers.h ********************************
* Author: Agner Fog
* Date created: 2006-07-15
* Last modified: 2007-02-01
* Project: objconv
* Module: containers.h
* Description:
* Header file for container classes and dynamic memory allocation
*
* Copyright 2006-2008 GNU General Public License http://www.gnu.org/licenses
*****************************************************************************/
/*****************************************************************************
This header file declares various container classes for dynamic allocation
of memory for files and other types of data with unpredictable sizes.
These classes have private access to the memory buffer in order to prevent
memory leaks. It is important to use these classes for all dynamic memory
allocation.
The class CMemoryBuffer and its descendants are used for many purposes of
storage of data with a size that is not known in advance. CMemoryBuffer
allows the size of its data to grow when new data are appended with the
Push() member function.
The class CFileBuffer, which is derived from CMemoryBuffer, is used for
reading, writing and storing object files and other files.
There are many different classes for different things you can do with
an object file. These classes, declared in converters.h, are all
descendants of CFileBuffer. It is possible to transfer a data buffer
from one object to another by the operator
A >> B
where A and B are both objects of classes that descend from CFileBuffer.
The file buffer that was owned by A is transferred to B and A is left empty
after the A >> B operation. This makes sure that a memory buffer is always
owned by one, and only one, object. The opposite operator B << A does the
same thing.
The >> operator is used whenever we want to do something to a file buffer
that requires a specialized class. The file buffer is transferred from the
object that owns it to an object of the specialized class and transferred
back again to the original owner when the object of the specialized class
has done its job.
You may say that the descendants of CFileBuffer have a chameleonic nature:
You can change the nature of a piece of data owned by an object by
transferring it to an object of a different class. This couldn't be done
by traditional polymorphism because it is not possible to change the class
of an object after it is created, and there are too many different things
you can do with object files for a single class to handle them all.
The container class CMemoryBuffer is useful for storing data of mixed types.
Data of arbitrary type can be accessed by Get<type>(offset) or by
Buf() + offset.
If all items in a dynamic array are of the same type then it is easier to
use one of the template classes CArrayBuf<> or CSList<>. These can be
used in the same way as normal arrays with the operator [].
CArrayBuf<> and CSList<> both have a member function SetNum() to allocate
the size. The size of CArrayBuf<> can be set only once, while the size of
CSList<> can be changed at any time. CSList<> also has a member function
Push() that adds records sequentially. CSList can be sorted if operators
< and == are defined for the record type.
Warning:
It is necessary to use CArrayBuf<> rather than CSList<> if the record type
has a constructor or destructor.
Warning:
It is not safe to make pointers to data inside a dynamic array of type
CMemoryBuffer or CSList<> because the buffer may be re-allocated when the
size grows. Such pointers will only work if we are finished with all push
operations. It is safer to address data inside the buffer by their index
or offset relative to the buffer.
*****************************************************************************/
#ifndef CONTAINERS_H
#define CONTAINERS_H
extern CErrorReporter err; // Defined in error.cpp
class CFileBuffer; // Declared below
void operator >> (CFileBuffer & a, CFileBuffer & b); // Transfer ownership of buffer and other properties
// Class CMemoryBuffer makes a dynamic array which can grow as new data are
// added. Used for storage of files, file sections, tables, etc.
class CMemoryBuffer {
public:
CMemoryBuffer(); // Constructor
~CMemoryBuffer(); // Destructor
void SetSize(uint32 size); // Allocate buffer of specified size
void SetDataSize(uint32 size); // Claim space as a data
uint32 GetDataSize() {return DataSize;}; // File data size
uint32 GetBufferSize(){return BufferSize;}; // Buffer size
uint32 GetNumEntries(){return NumEntries;}; // Get number of entries
uint32 Push(void const * obj, uint32 size); // Add object to buffer, return offset
uint32 PushString(char const * s); // Add ASCIIZ string to buffer, return offset
uint32 GetLastIndex(); // Index of last object pushed (zero-based)
void Align(uint32 a); // Align next entry to address divisible by a
int8 * Buf() {return buffer;}; // Access to buffer
template <class TX> TX & Get(uint32 Offset) { // Get object of arbitrary type from buffer
if (Offset >= DataSize) {err.submit(2016); Offset = 0;} // Offset out of range
return *(TX*)(buffer + Offset);}
private:
CMemoryBuffer(CMemoryBuffer&); // Make private copy constructor to prevent copying
int8 * buffer; // Buffer containing binary data. To be modified only by SetSize and operator >>
uint32 BufferSize; // Size of allocated buffer ( > DataSize)
protected:
uint32 NumEntries; // Number of objects pushed
uint32 DataSize; // Size of data, offset to vacant space
friend void operator >> (CFileBuffer & a, CFileBuffer & b); // Transfer ownership of buffer and other properties
};
static inline void operator << (CFileBuffer & b, CFileBuffer & a) {a >> b;} // Same as operator << above
// Class CFileBuffer is used for storage of input and output files
class CFileBuffer : public CMemoryBuffer {
public:
CFileBuffer(); // Default constructor
CFileBuffer(char const * filename); // Constructor
void Read(int IgnoreError = 0); // Read file into buffer
void Write(); // Write buffer to file
int GetFileType(); // Get file format type
void SetFileType(int type); // Set file format type
void Reset(); // Set all members to zero
static char const * GetFileFormatName(int FileType); // Get name of file format type
char const * FileName; // Name of input file
char const * OutputFileName; // Output file name
int WordSize; // Segment word size (16, 32, 64)
int FileType; // Object file type
int Executable; // File is executable
char * SetFileNameExtension(const char * f); // Set file name extension according to FileType
protected:
void GetOMFWordSize(); // Determine word size for OMF file
void CheckOutputFileName(); // Make output file name or check that requested name is valid
};
// Class CTextFileBuffer is used for building text files
class CTextFileBuffer : public CFileBuffer {
public:
CTextFileBuffer(); // Constructor
void Put(const char * text); // Write text string to buffer
void Put(const char character); // Write single character to buffer
void NewLine(); // Add linefeed
void Tabulate(uint32 i); // Insert spaces until column i
int LineType; // 0 = DOS/Windows linefeeds, 1 = UNIX linefeeds
void PutDecimal(int32 x, int IsSigned = 0); // Write decimal number to buffer
void PutHex(uint8 x, int MasmForm = 0); // Write hexadecimal number to buffer
void PutHex(uint16 x, int MasmForm = 0); // Write hexadecimal number to buffer
void PutHex(uint32 x, int MasmForm = 0); // Write hexadecimal number to buffer
void PutHex(uint64 x, int MasmForm = 0); // Write hexadecimal number to buffer
void PutFloat(float x); // Write floating point number to buffer
void PutFloat(double x); // Write floating point number to buffer
uint32 GetColumn() {return column;} // Get column number
protected:
uint32 column; // Current column
private:
uint32 PushString(char const * s){return 0;}; // Make PushString private to prevent using it
};
// Class CArrayBuf<RecordType> is used for dynamic arrays.
// The size of the array can be set only once.
// Use CArrayBuf rather than one of the other container classes if RecordType
// has a constructor or destructor.
template <class RecordType>
class CArrayBuf {
private:
RecordType * buffer; // Dynamically allocated memory
uint32 num; // Number of entries in array
CArrayBuf (CArrayBuf &); // Make private copy constructor to prevent copying
public:
CArrayBuf() { // Default constructor
num = 0;
}
~CArrayBuf() { // Destructor
if (num) delete[] buffer; // Deallocate memory. Will call RecordType destructor if any
}
void SetNum(uint32 n) { // Set size of array. May be called only once!
if (n <= num) return; // Already allocated
if (num) {
err.submit(9004); // Cannot resize because items may have destructors
}
else {
buffer = new RecordType[n]; // Allocate memory. Will call RecordType constructor if any
if (!buffer) {
err.submit(9006); // Memory allocation failed
}
else {
num = n; // Save size
memset(buffer, 0, n*sizeof(RecordType));// Initialize to zero
}
}
}
uint32 GetNumEntries() {
return num; // Read size
}
RecordType & operator[] (uint32 i) { // Access array element [i]
if (i >= num) {
err.submit(9003); i = 0; // Error: index out of range
}
return buffer[i];
}
void SetZero() { // Set all items in array to 0
memset(buffer, 0, num*sizeof(RecordType)); // Warning: overwrites all members of RecordType with 0
}
};
// Class CSList<RecordType> is used for dynamic arrays where all records
// have the same type RecordType. The list can be sorted if desired.
//
// An array defined as
// CSList<RecordType> list;
// can be used in several ways:
//
// 1. The size can be set with list.SetNum(n) where n is the maximum number of
// entries. New entries can then be added in random order with list[i] = x;
// where i < n. Unused entries will be zero.
// 2. Entries can be added sequentially with
// list.Push(x);
// The first entry will be list[0]
// 3. Entries added with method 1 or 2 can be sorted in ascending order by
// calling list.Sort();
// 4. The list can be kept sorted at all times if records are added with
// list.PushSort(x);
// The list will be kept sorted in ascending order, provided that it
// was sorted before the call to PushSort.
// 5. The list can be kept sorted at all times and without duplicates if
// records are added with list.PushUnique(x);
// The list will be sorted and without duplicates after PushUnique if
// it was so before the call to PushUnique.
// 6. Entries can be read at all times as x = list[i];
// An error will be submitted if i >= list.GetNumEntries()
// 7. A sorted list can be searched for entry x by i = list.FindFirst(x);
// or i = list.Exists(x);
//
// Requirements:
// RecordType can be a simple type, a structure or a class.
// If RecordType has a constructor or destructor then they will not be
// called properly. Use CArrayBuf instead of CSList if RecordType has
// a constructor or destructor.
// The operator < const must be defined for RecordType if any of the sorting
// features are used, i.e. Sort(), PushSort(), FindFirst(), Exists().
//
// Example:
// struct S1 { // Define RecordType
// int Index;
// int operator < (S1 const & x) const { // Define operator <
// return Index < x.Index;}
// };
// CSList<S1> list; // Make list
// S1 a; a.Index = 5; // Make record
// list.PushUnique(a); // Put record into list
template <class RecordType>
class CSList : private CMemoryBuffer {
public:
void Push(RecordType const & x) {
// Add member to list
CMemoryBuffer::Push(&x, sizeof(x));
}
void PushZero() {
// Add blank entry to list
CMemoryBuffer::Push(0, sizeof(RecordType));
}
void SetNum(uint32 n) {
// Reserve space for n entries. Fill with zeroes
SetSize(n * sizeof(RecordType));
NumEntries = n; DataSize = n * sizeof(RecordType);
}
uint32 GetNumEntries() {
// Get number of entries
return NumEntries;
}
RecordType & operator[] (uint32 i) {
// Get entries by operator [] as for an array
if (i >= NumEntries) {
err.submit(9003); i = 0;} // Error: index out of range
return *(RecordType*)(Buf() + i * sizeof(RecordType));
}
void Sort() {
// Sort list by ascending RecordType items
// Operator < must be defined for RecordType
// Simple Bubble sort:
int32 i, j;
RecordType temp, * p1, * p2;
for (i = 0; i < (int32)NumEntries; i++) {
for (j = 0; j < (int32)NumEntries - i - 1; j++) {
p1 = (RecordType*)(Buf() + j * sizeof(RecordType));
p2 = (RecordType*)(Buf() + (j+1) * sizeof(RecordType));
if (*p2 < *p1) {
// Swap records
temp = *p1; *p1 = *p2; *p2 = temp;
}
}
}
}
int32 FindFirst(RecordType const & x) {
// Returns index to first record >= x.
// Returns 0 if x is smaller than all entries.
// Returns NumEntries if x is bigger than all entries. Note that this
// is not a valid index into the list.
// List must be sorted before calling FindFirst
uint32 a = 0; // Start of search interval
uint32 b = NumEntries; // End of search interval + 1
uint32 c = 0; // Middle of search interval
// Binary search loop:
while (a < b) {
c = (a + b) / 2;
if ((*this)[c] < x) {
a = c + 1;}
else {
b = c;}
}
return (int32)a;
}
int32 Exists(RecordType const & x) {
// Returns the record number if a record equal to x exists in the list.
// Returns -1 if not. The list must be sorted before calling Exists.
// Two records a and b are assumed to be equal if !(a < b || b < a)
uint32 i = FindFirst(x);
if (i == NumEntries) return -1;
if (x < (*this)[i]) return -1; else return i;
}
int32 PushSort(RecordType const & x) {
// Add member to list and keep the list sorted.
// If the list is sorted before calling PushSort then it will also be
// sorted after the call. If x is equal to an existing entry then x
// will be inserted before the existing entry.
// Operator < must be defined for RecordType.
int32 i = FindFirst(x); // Find where to insert x
int32 RecordsToMove = (int32)NumEntries-i; // Number of records to move
SetNum(NumEntries + 1); // Make space for one more record
// Move subsequent entries up one place
if (RecordsToMove > 0) {
memmove(Buf() + i * sizeof(RecordType) + sizeof(RecordType),
Buf() + i * sizeof(RecordType),
RecordsToMove * sizeof(RecordType));
}
// Insert x at position i
(*this)[i] = x;
return i;
}
int32 PushUnique(RecordType const & x) {
// Add member to list and keep the list sorted. Avoids duplicate entries.
// PushUnique will insert x in the list and keep the list sorted.
// If an entry equal to x already exists in the list then x is not
// inserted, and the return value will be the index to the existing entry.
// If no entry equal to x existed then x is inserted and the return
// value is the index to the new entry.
// This list must be sorted and without duplicates before calling
// PushUnique.
// Operator < must be defined for RecordType.
int32 i = FindFirst(x); // Find where to insert x
if (i < (int32)NumEntries && !(x < (*this)[i])) {
return i; // Duplicate found. Return index
}
int32 RecordsToMove = (int32)NumEntries-i; // Number of records to move
SetNum(NumEntries + 1); // Make space for one more record
// Move subsequent entries up one place
if (RecordsToMove > 0) {
memmove(Buf() + i * sizeof(RecordType) + sizeof(RecordType),
Buf() + i * sizeof(RecordType),
RecordsToMove * sizeof(RecordType));
}
// Insert x at position i
(*this)[i] = x;
// Return index
return i;
}
void Remove(uint32 index) {
// Remove record with this index
if (index >= NumEntries) return; // Index out of range
uint32 RecordsToMove = NumEntries - index - 1; // Number of records to move
// Move subsequent entries down one place
if (RecordsToMove > 0) {
memmove(Buf() + index * sizeof(RecordType),
Buf() + index * sizeof(RecordType) + sizeof(RecordType),
RecordsToMove * sizeof(RecordType));
}
// Count down number of entries
SetNum(NumEntries - 1);
}
};
#endif // #ifndef CONTAINERS_H

View File

@ -0,0 +1,529 @@
/**************************** converters.h ********************************
* Author: Agner Fog
* Date created: 2006-07-15
* Last modified: 2008-05-25
* Project: objconv
* Module: converters.h
* Description:
* Header file for file conversion classes.
*
* Copyright 2006-2008 GNU General Public License http://www.gnu.org/licenses
*****************************************************************************/
/******************************* Classes ********************************
This header file declares various classes for interpreting and converting
different types of object files. These classes are all derived from the
container class CFileBuffer, declared in containers.h.
See containers.h for an explanation of the container classes and the
operators >> and << which can transfer a data buffer from an object of one
class to an object of another class.
*****************************************************************************/
#ifndef CONVERTERS_H
#define CONVERTERS_H
// Structure for string index entry in library
struct SStringEntry {
uint32 String; // Offset to string
uint32 Member; // Library member
};
// Class CResponseFileBuffer is used for storage of a command line response file
class CResponseFileBuffer : public CFileBuffer {
public:
CResponseFileBuffer(char const * filename); // Constructor
~CResponseFileBuffer(); // Destructor
CResponseFileBuffer * next; // Linked list if more than one buffer
};
// Class for deciding what to do with input file
// Its memory buffer contains the input file and later the output file
class CMain : public CFileBuffer {
public:
CMain(); // Constructor
void Go(); // Do whatever the command line parameters say
};
// Class CConverter is used for converting or dumping a file of any type
class CConverter : public CFileBuffer {
public:
CConverter(); // Constructor
void Go(); // Do whatever the command line parameters say
protected:
void DumpCOF(); // Dump PE/COFF file
void DumpELF(); // Dump ELF file
void DumpMACHO(); // Dump Mach-O file
void DumpOMF(); // Dump OMF file
void ParseMACUnivBin(); // Dump Mac universal binary
void COF2COF(); // Make changes in PE file
void COF2ELF(); // Convert PE/COFF to ELF file
void COF2OMF(); // Convert PE/COFF to OMF file
void ELF2ELF(); // Make changes in ELF file
void ELF2COF(); // Convert ELF to PE file
void ELF2MAC(); // Convert ELF to Mach-O file
void OMF2COF(); // Convert OMF file to PE/COFF
void COF2ASM(); // Disassemble PE/COFF file
void ELF2ASM(); // Disassemble ELF file
void MAC2ELF(); // Convert Mach-O file to ELF file
void MAC2MAC(); // Make changes in Mach-O file
void MAC2ASM(); // Disassemble Mach-O file
void OMF2ASM(); // Disassemble OMF file
};
// Class for interpreting and dumping PE/COFF files
class CCOFF : public CFileBuffer {
public:
CCOFF(); // Default constructor
void ParseFile(); // Parse file buffer
void Dump(int options); // Dump file
void PrintSymbolTable(int symnum); // Dump symbol table entries
void PrintImportExport(); // Print imported and exported symbols
static void PrintSegmentCharacteristics(uint32 flags); // Print segment characteristics
char const * GetSymbolName(int8* Symbol); // Get symbol name from 8 byte entry
char const * GetSectionName(int8* Symbol); // Get section name from 8 byte entry
const char * GetFileName(SCOFF_SymTableEntry *); // Get file name from records in symbol table
const char * GetShortFileName(SCOFF_SymTableEntry*);// Same as above. Strips path before filename
char const * GetStorageClassName(uint8 sc); // Get storage class name
void PublicNames(CMemoryBuffer * Strings, CSList<SStringEntry> * Index, int m); // Make list of public names
int GetImageDir(uint32 n, SCOFF_ImageDirAddress * dir); // Find address of image directory for executable files
protected:
CArrayBuf<SCOFF_SectionHeader> SectionHeaders;// Copy of section headers
int NSections; // Number of sections
SCOFF_FileHeader * FileHeader; // File header
SCOFF_SymTableEntry * SymbolTable; // Pointer to symbol table (for object files)
char * StringTable; // Pointer to string table (for object files)
uint32 StringTableSize; // Size of string table (for object files)
int NumberOfSymbols; // Number of symbol table entries (for object files)
uint64 ImageBase; // Image base (for executable files)
SCOFF_OptionalHeader * OptionalHeader; // Optional header (for executable files)
SCOFF_IMAGE_DATA_DIRECTORY * pImageDirs; // Pointer to image directories (for executable files)
uint32 NumImageDirs; // Number of image directories (for executable files)
uint32 EntryPoint; // Entry point (for executable files)
};
// Class for interpreting and dumping ELF files. Has templates for 32 and 64 bit version
template <class TFileHeader, class TSectionHeader, class TSymbol, class TRelocation>
class CELF : public CFileBuffer {
public:
CELF(); // Default constructor
void ParseFile(); // Parse file buffer
void Dump(int options); // Dump file
void PublicNames(CMemoryBuffer * Strings, CSList<SStringEntry> * Index, int m); // Make list of public names
protected:
const char * SymbolName(uint32 index); // Get name of symbol
TFileHeader FileHeader; // Copy of file header
char * SecStringTable; // Section header string table
uint32 SecStringTableLen; // Length of section header string table
uint32 NSections; // Number of sections
int SectionHeaderSize; // Size of each section header
CArrayBuf<TSectionHeader> SectionHeaders; // Copy of section headers
uint32 SymbolTableOffset; // Offset to symbol table
uint32 SymbolTableEntrySize; // Entry size of symbol table
uint32 SymbolTableEntries; // Number of symbols
uint32 SymbolStringTableOffset; // Offset to symbol string table
uint32 SymbolStringTableSize; // Size of symbol string table
};
// Class for interpreting and dumping Mach-O files
class COMF : public CFileBuffer {
public:
COMF(); // Default constructor
void ParseFile(); // Parse file buffer
void Dump(int options); // Dump file
void PublicNames(CMemoryBuffer * Strings, CSList<SStringEntry> * Index, int m); // Make list of public names
protected:
uint32 NumRecords; // Number of records
CSList<SOMFRecordPointer> Records; // Record pointers (List is 0-based)
CMemoryBuffer NameBuffer; // Store segment names and symbol names
CSList<uint32> LocalNameOffset; // Offset into NameBuffer of segment names by name index
CSList<uint32> SegmentNameOffset; // Offset into NameBuffer of segment names by segment index
CSList<uint32> SymbolNameOffset; // Offset into NameBuffer of external symbol names
CSList<uint32> GroupNameOffset; // Offset into NameBuffer of group names
char * GetLocalName(uint32 i); // Get segment name by name index
uint32 GetLocalNameO(uint32 i); // Get segment name by converting name index offset into NameBuffer
const char * GetSegmentName(uint32 i); // Get segment name by segment index
const char * GetSymbolName(uint32 i); // Get external symbol name
const char * GetGroupName(uint32 i); // Get group name by index
static const char * GetRecordTypeName(uint32 i);// Get OMF record type name
void DumpRecordTypes(); // Dump summary of records
void DumpNames(); // Dump local names records
void DumpSymbols(); // Dump public and external names records
void DumpSegments(); // Dump segment records
void DumpRelocations(); // Dump fixup records
void DumpComments(); // Dump coment records
};
// Class for interpreting and dumping Mach-O files. Has templates for 32 and 64 bit version
template <class TMAC_header, class TMAC_segment_command, class TMAC_section, class TMAC_nlist, class MInt>
class CMACHO : public CFileBuffer {
public:
CMACHO(); // Default constructor
void ParseFile(); // Parse file buffer
void Dump(int options); // Dump file
void PublicNames(CMemoryBuffer * Strings, CSList<SStringEntry> * Index, int m); // Make list of public names
protected:
TMAC_header FileHeader; // Copy of file header
uint64 ImageBase; // Image base for executable file
uint32 SegmentOffset; // File offset of segment
uint32 SegmentSize; // Size of segment
uint32 SectionHeaderOffset; // File offset of section headers
uint32 NumSections; // Number of sections
uint32 SymTabOffset; // File offset of symbol table
uint32 SymTabNumber; // Number of entries in symbol table
uint32 StringTabOffset; // File offset of string table
uint32 StringTabSize; // Size of string table
uint32 ilocalsym; // index to local symbols
uint32 nlocalsym; // number of local symbols
uint32 iextdefsym; // index to public symbols
uint32 nextdefsym; // number of public symbols
uint32 iundefsym; // index to external symbols
uint32 nundefsym; // number of external symbols
uint32 IndirectSymTabOffset; // file offset to the indirect symbol table
uint32 IndirectSymTabNumber; // number of indirect symbol table entries
};
// Class for parsing Macintosh universal binary
class CMACUNIV : public CFileBuffer {
public:
CMACUNIV(); // Default constructor
void Go(int options); // Apply command line options to all components
};
// class CCOF2ELF handles conversion from PE/COFF file to ELF file. Has templates for 32 and 64 bit version
template <class TELF_Header, class TELF_SectionHeader, class TELF_Symbol, class TELF_Relocation>
class CCOF2ELF : public CCOFF {
public:
CCOF2ELF(); // Constructor
void Convert(); // Do the conversion
protected:
void MakeSegments(); // Convert subfunction: Segments
void MakeSymbolTable(); // Convert subfunction: Symbol table and string tables
void MakeRelocationTables(); // Convert subfunction: Relocation tables
void MakeBinaryFile(); // Convert subfunction: Putting sections together
int symtab; // Symbol table section number
int shstrtab; // Section name string table section number
int strtab; // Object name string table section number
int stabstr; // Debug string table section number
int NumSectionsNew; // Number of sections generated for 'to' file
int MaxSectionsNew; // Number of section buffers allocated for 'to' file
CArrayBuf<CMemoryBuffer> NewSections; // Buffers for building each section
CArrayBuf<TELF_SectionHeader> NewSectionHeaders;// Buffer for temporary section headers
CArrayBuf<int> NewSectIndex; // Buffers for array of new section indices
CArrayBuf<int> NewSymbolIndex; // Buffers for array of new symbol indices
CFileBuffer ToFile; // File buffer for ELF file
TELF_Header NewFileHeader; // New file header
};
// class CCOF2OMF handles conversion from PE/COFF file to OMF file
class CCOF2OMF : public CCOFF {
public:
CCOF2OMF(); // Constructor
void Convert(); // Do the conversion
protected:
void MakeSegmentList(); // Make temporary segment conversion list
void MakeSymbolList(); // Make temporary symbol conversion list
void MakeRelocationsList(); // Make temporary list of relocations (fixups) and sort it
void MakeLNAMES(); // Make THEADR and LNAMES records
void MakeSEGDEF(); // Make SEGDEF and GRPDEF records
void MakeEXTDEF(); // Make EXTDEF records
void MakePUBDEF(); // Make PUBDEF records
void MakeLEDATA(); // Make LEDATA, LIDATA and FIXUPP records
void MakeMODEND(); // Make MODEND record and finish file
CArrayBuf<SOMFSegmentList> SectionBuffer; // Summarize old sections. Translate section index to segment index
CArrayBuf<SOMFSymbolList> SymbolBuffer; // Translate old symbol index to new public/external index
CSList<SOMFRelocation> RelocationBuffer; // Summarize and sort relocations
CMemoryBuffer NameBuffer; // Temporary storage of text strings
COMFFileBuilder ToFile; // File buffer for new OMF file
int NumSegments; // Number of segments in new file
int SectionBufferNum; // Number of entries in SectionBuffer
uint32 NumPublicSymbols; // Number of public symbols in new file
uint32 NumExternalSymbols; // Number of external symbols in new file
uint32 NumRelocations; // Number of entries in RelocationBuffer
};
// class COMF2COF handles conversion from OMF file to PE/COFF file
class COMF2COF : public COMF {
public:
COMF2COF(); // Constructor
void Convert(); // Do the conversion
protected:
// Convert subfunctions:
void MakeFileHeader(); // File header
void MakeSymbolTable1(); // Make symbol table and string table entries for file and segments
void MakeSymbolTable2(); // Make symbol table and string table entries for external symbols
void MakeSymbolTable3(); // Make symbol table and string table entries for public symbols
void MakeSymbolTable4(); // Make symbol table and string table entries for communal symbols
void MakeSymbolTable5(); // Make symbol table and string table entries for local symbols
void MakeSections(); // Make sections and relocation tables
void MakeBinaryFile(); // Putting sections together
void CheckUnsupportedRecords(); // Make warnings if file containes unsupported record types
int NumSectionsNew; // Number of sections in new file
CFileBuffer ToFile; // File buffer for PE/COFF file
CSList<SCOFF_SymTableEntry> NewSymbolTable; // New symbol table entries
CSList<SCOFF_SectionHeader> NewSectionHeaders;// New section headers
CMemoryBuffer NewStringTable; // Buffer for building new string table
CMemoryBuffer NewData; // Raw data for each section in new file and its relocation table
CSList<uint32> SegmentTranslation; // Translate old segment number to new symbol table index
CSList<uint32> ExtdefTranslation; // Translate old external symbol number to new symbol table index
CSList<SOMFLocalSymbol> LocalSymbols; // List for assigning names to unnamed local symbols
SCOFF_FileHeader NewFileHeader; // New file header
};
// class CELF2COF handles conversion from ELF file to PE/COFF file. Has templates for 32 and 64 bit version
template <class TELF_Header, class TELF_SectionHeader, class TELF_Symbol, class TELF_Relocation>
class CELF2COF : public CELF<ELFSTRUCTURES> {
public:
CELF2COF(); // Constructor
void Convert(); // Do the conversion
protected:
void MakeFileHeader(); // Convert subfunction: File header
void MakeSectionsIndex(); // Convert subfunction: Make section index translation table
void MakeSections(); // Convert subfunction: Make sections and relocation tables
void MakeSymbolTable(); // Convert subfunction: Symbol table and string tables
void HideUnusedSymbols(); // Convert subfunction: Hide unused symbols
void MakeBinaryFile(); // Convert subfunction: Putting sections together
int NumSectionsNew; // Number of sections in new file
CArrayBuf<int32> NewSectIndex; // Array of new section indices
CArrayBuf<int32> SymbolsUsed; // Array of new symbol indices
CSList<int32> NewSymbolIndex; // Buffer for array of new symbol indices
CMemoryBuffer NewSymbolTable; // Buffer for building new symbol table
CMemoryBuffer NewStringTable; // Buffer for building new string table
CMemoryBuffer NewRawData; // Buffer for building new raw data area
uint32 RawDataOffset; // File offset for raw data
CFileBuffer ToFile; // File buffer for PE/COFF file
SCOFF_FileHeader NewFileHeader; // New file header
};
// class CELF2MAC handles conversion from ELF file to Mach-O file
template <class TELF_Header, class TELF_SectionHeader, class TELF_Symbol, class TELF_Relocation,
class TMAC_header, class TMAC_segment_command, class TMAC_section, class TMAC_nlist, class MInt>
class CELF2MAC : public CELF<ELFSTRUCTURES> {
public:
CELF2MAC(); // Constructor
void Convert(); // Do the conversion
protected:
void MakeFileHeader(); // Convert subfunction: File header
void MakeSectionsIndex(); // Convert subfunction: Make section index translation table
void MakeSections(); // Convert subfunction: Make sections and relocation tables
void MakeSymbolTable(); // Convert subfunction: Symbol table and string tables
void FindUnusedSymbols(); // Convert subfunction: Check if symbols used, remove unused symbols
void MakeBinaryFile(); // Convert subfunction: Putting sections together
// Translate relocations, seperate function for 32 and 64 bits:
void Elf2MacRelocations(Elf32_Shdr &, MAC_section_32 &, uint32 NewRawDataOffset, uint32 oldsec);
void Elf2MacRelocations(Elf64_Shdr &, MAC_section_64 &, uint32 NewRawDataOffset, uint32 oldsec);
int GetImagebaseSymbol(); // Symbol table index of __mh_execute_header
CFileBuffer ToFile; // File buffer for new Mach-O file
CMemoryBuffer NewRawData; // Buffer for building new raw data area
CMemoryBuffer NewRelocationTab; // Buffer for new relocation tables
CMemoryBuffer NewStringTable; // Buffer for building new string table
CMemoryBuffer UnnamedSymbolsTable; // Buffer for assigning names to unnamed symbols
CArrayBuf<int> NewSectIndex; // Array of new section indices
CArrayBuf<MInt> NewSectOffset; // Array of new section offsets
CArrayBuf<int> OldSymbolScope; // Table of symbol bindings: 0 = local, 1 = public, 2 = external
CArrayBuf<int> OldSymbolUsed; // Check if symbol is used
MacSymbolTableBuilder<TMAC_nlist, MInt> NewSymTab[3]; // New symbol tables for local, public, external symbols
uint32 NumSymbols[4]; // Accumulated number of entries in each NewSymTab[]
uint32 NewSectHeadOffset; // File offset to first section header
uint32 NewSymtabOffset; // File offset to symtab command
int NumSectionsNew; // Number of sections in new file
uint32 RawDataOffset; // Offset to raw data in old file
uint32 NumOldSymbols; // Number of symbols in old file
uint32 CommandOffset; // Offset to first load command = segment header
};
// class MAC2ELF handles conversion from Mach-O file to ELF file
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>
class CMAC2ELF : public CMACHO<MACSTRUCTURES> {
public:
CMAC2ELF(); // Constructor
void Convert(); // Do the conversion
protected:
void MakeSegments(); // Convert subfunction: Segments
void MakeSymbolTable(); // Convert subfunction: Symbol table and string tables
void MakeRelocationTables(MAC_header_32&); // Convert subfunction: Relocation tables, 32-bit version
void MakeRelocationTables(MAC_header_64&); // Convert subfunction: Relocation tables, 64-bit version
void MakeImportTables(); // Convert subfunction: Fill import tables
void MakeBinaryFile(); // Convert subfunction: Putting sections together
void TranslateAddress(MInt addr, uint32 & section, uint32 & offset); // Translate address to section + offset
uint32 MakeGOTEntry(int symbol); // Make entry in fake GOT for symbol
void MakeGOT(); // Make fake Global Offset Table
int symtab; // Symbol table section number
int shstrtab; // Section name string table section number
int strtab; // Object name string table section number
int stabstr; // Debug string table section number
uint32 NumSectionsNew; // Number of sections generated for 'to' file
uint32 MaxSectionsNew; // Number of section buffers allocated for 'to' file
uint32 HasGOT; // Contains references to global offset table
int FakeGOTSection; // Fake GOT section number
int FakeGOTSymbol; // Symbol index for fake GOT
TELF_Header NewFileHeader; // New file header
CArrayBuf<CMemoryBuffer> NewSections; // Buffers for building each section
CArrayBuf<TELF_SectionHeader> NewSectionHeaders;// Array of temporary section headers
CArrayBuf<int> NewSectIndex; // Array of new section indices
CArrayBuf<int> NewSymbolIndex; // Array of new symbol indices
CArrayBuf<int> SectionSymbols; // Array of new symbol indices for sections
CFileBuffer ToFile; // File buffer for ELF file
CSList<int> GOTSymbols; // List of symbols needing GOT entry
};
// class CCOF2COF handles symbol changes in a PE/COFF file
class CCOF2COF : public CCOFF {
public:
CCOF2COF(); // Constructor
void Convert(); // Do the conversion
protected:
void MakeSymbolTable(); // Convert subfunction: Symbol table and string tables
void MakeBinaryFile(); // Convert subfunction: Putting sections together
CMemoryBuffer NewSymbolTable; // Buffers for building new symbol table
CMemoryBuffer NewStringTable; // Buffers for building new string table
CFileBuffer ToFile; // File buffer for modified PE file
};
// class CELF2ELF handles symbol changes in ELF file. Has templates for 32 and 64 bit version
template <class TELF_Header, class TELF_SectionHeader, class TELF_Symbol, class TELF_Relocation>
class CELF2ELF : public CELF<ELFSTRUCTURES> {
public:
CELF2ELF(); // Constructor
void Convert(); // Do the conversion
protected:
void MakeSymbolTable(); // Convert subfunction: Symbol table and string tables
void ChangeSections(); // Convert subfunction: Change section names if needed
void MakeBinaryFile(); // Convert subfunction: Putting sections together
uint32 isymtab[2]; // static and dynamic symbol table section number
uint32 istrtab[4]; // string table section number: symbols, dynamic symbols, sections, debug
CMemoryBuffer NewSymbolTable[2]; // Buffers for building new symbol tables: static, dynamic
CMemoryBuffer NewStringTable[4]; // Buffers for building new string tables: symbols, dynamic symbols, sections, debug
CArrayBuf<uint32> NewSymbolIndex; // Array for translating old to new symbol indices
uint32 NumOldSymbols; // Size of NewSymbolIndex table
uint32 FirstGlobalSymbol; // Index to first global symbol in .symtab
CFileBuffer ToFile; // File buffer for modified PE file
};
// class CMAC2MAC handles symbol changes in Mach-O file. Has templates for 32 and 64 bit version
template <class TMAC_header, class TMAC_segment_command, class TMAC_section, class TMAC_nlist, class MInt>
class CMAC2MAC : public CMACHO<MACSTRUCTURES> {
public:
CMAC2MAC(); // Constructor
void Convert(); // Do the conversion
protected:
void MakeSymbolTable(); // Convert subfunction: Symbol table and string tables
void ChangeSegments(); // Convert subfunction: Change segment names if needed
void ChangeSections(uint32 HeaderOffset, uint32 Num);// Convert subfunction: Change section names and relocation records if needed
void ChangeImportTable(uint32 FileOffset, uint32 Num);// Convert subfunction: Change symbol indices in import table if needed
void MakeBinaryFile(); // Convert subfunction: Putting sections together
int NewSymbolIndex(int OldIndex); // Convert subfunction: Translate old to new symbol index
uint32 NewFileOffset(uint32 OldOffset); // Convert subfunction: Translate old to new file offset
MacSymbolTableBuilder<TMAC_nlist, MInt> NewSymbols[3];// Buffers for building new symbol tables: local, public, external
CMemoryBuffer NewSymbolTable; // Buffer for building new symbol table
CMemoryBuffer NewStringTable; // Buffer for building new string table
CFileBuffer ToFile; // File buffer for modified PE file
uint32 NumOldSymbols; // Size of NewSymbolIndex table
uint32 NewIlocalsym; // index to local symbols
uint32 NewNlocalsym; // number of local symbols
uint32 NewIextdefsym; // index to public symbols
uint32 NewNextdefsym; // number of public symbols
uint32 NewIundefsym; // index to external symbols
uint32 NewNundefsym; // number of external symbols
uint32 NewSymtabOffset; // Offset to new symbol table
uint32 NewStringtabOffset; // Offset to new string table
uint32 NewStringtabEnd; // Offset to end of new string table
uint32 OldTablesEnd; // End of old symbol table and string table
int32 SizeDifference; // Size of new file minus size of old file
};
// class CCOF2ASM handles disassembly of PE/COFF file
class CCOF2ASM : public CCOFF {
public:
CCOF2ASM(); // Constructor
void Convert(); // Do the conversion
protected:
CDisassembler Disasm; // Disassembler
void MakeSectionList(); // Make Sections list and Relocations list in Disasm
void MakeSymbolList(); // Make Symbols list in Disasm
void MakeDynamicRelocations(); // Make dynamic base relocations for executable files
void MakeImportList(); // Make imported symbols for executable files
void MakeExportList(); // Make exported symbols for executable files
void MakeListLabels(); // Attach names to all image directories
};
// class CELF2ASM handles disassembly of ELF file
template <class TELF_Header, class TELF_SectionHeader, class TELF_Symbol, class TELF_Relocation>
class CELF2ASM : public CELF<ELFSTRUCTURES> {
public:
CELF2ASM(); // Constructor
void Convert(); // Do the conversion
protected:
CDisassembler Disasm; // Disassembler
CArrayBuf<int32>SectionNumberTranslate; // Translate section numbers in source file to section numbers in asm file
CArrayBuf<uint32>SymbolTableOffset; // Addend to add to symbol number for each symbol table
int64 ImageBase; // Image base if executable file
uint32 ExeType; // File type: 0 = object, 1 = DLL/shared object, 2 = executable
uint32 NumSymbols; // Number of symbols defined
void FindImageBase(); // Find image base
void MakeSectionList(); // Make Sections list in Disasm
void MakeSymbolList(); // Make Symbols list in Disasm
void MakeRelocations(); // Make relocations for object and executable files
void MakeImportList(); // Make imported symbols for executable files
void MakeExportList(); // Make exported symbols for executable files
void MakeListLabels(); // Attach names to all image directories
};
// class CMAC2ASM handles disassembly of Mach-O file
template <class TMAC_header, class TMAC_segment_command, class TMAC_section, class TMAC_nlist, class MInt>
class CMAC2ASM : public CMACHO<MACSTRUCTURES> {
public:
CMAC2ASM(); // Constructor
void Convert(); // Do the conversion
protected:
void MakeSectionList(); // Make Sections list in Disasm
void MakeSymbolList(); // Make Symbols list in Disasm
void MakeRelocations(); // Make relocation list in Disasm
void MakeImports(); // Make symbol entries for imported symbols
CDisassembler Disasm; // Disassembler
CMemoryBuffer StringBuffer; // Buffer for making section names
CSList<MAC_SECT_WITH_RELOC> RelocationQueue; // List of relocation tables
CSList<TMAC_section*> ImportSections; // List of sections needing extra symbols: import tables, literals, etc.
};
// class COMF2ASM handles disassembly of OMF object files
class COMF2ASM : public COMF {
public:
COMF2ASM(); // Constructor
void Convert(); // Do the conversion
protected:
void CountSegments(); // Make temporary Segments table
void MakeExternalSymbolsTable(); // Make external symbols in Disasm
void MakePublicSymbolsTable(); // Make symbol table entries for public symbols
void MakeCommunalSymbolsTable(); // Make symbol table entries for communal symbols
void MakeGroupDefinitions(); // Make segment group definitions
void MakeSegmentList(); // Make Segments list in Disasm
void MakeRelocations(int32 Segment, uint32 RecNum, uint32 SOffset, uint32 RSize, uint8 * SData);// Make relocation list in Disasm
CDisassembler Disasm; // Disassembler
CSList<SOMFSegment> Segments; // Name, size, etc. of all segments
CSList<uint32> ExtdefTranslation; // Translate old external symbol number to disasm symbol table index
CSList<uint32> PubdefTranslation; // Translate old public symbol number to disasm symbol table index
CMemoryBuffer SegmentData; // Binary segment data
int32 NumSegments; // Number of segments
int32 FirstComDatSection; // First COMDAT section. All sections before this are SEGDEF segments
};
#endif // #ifndef CONVERTERS_H

View File

@ -0,0 +1,843 @@
/**************************** disasm.h **********************************
* Author: Agner Fog
* Date created: 2007-02-21
* Last modified: 2014-12-06
* Project: objconv
* Module: disasm.h
* Description:
* Header file for disassembler
*
* Copyright 2007-2014 GNU General Public License http://www.gnu.org/licenses
*****************************************************************************/
#ifndef DISASM_H
#define DISASM_H
// Define tabulator positions for output
#define AsmTab1 8 // Column for opcode
#define AsmTab2 16 // Column for first operand
#define AsmTab3 56 // Column for comment
#define ReplaceIllegalChars 0 // 1 if you want to replace illegal characters in symbol names
// Structure for defining x86 opcode maps
struct SOpcodeDef {
const char * Name; // opcode name
uint32 InstructionSet; // mmx, sse, 3dnow, x64, etc.
uint32 AllowedPrefixes; // prefixes allowed for this opcode
uint16 InstructionFormat; // opcode type, number of operands
uint16 Destination; // type and size of destination operand
uint16 Source1; // type and size of 1. source operand
uint16 Source2; // type and size of 2. source operand
uint16 Source3; // type and size of 3. source operand
uint16 EVEX; // options for interpreting EVEX prefix, may be used for 4. source operand otherwise (unused)
uint16 MVEX; // options for interpreting MVEX prefix: swizzle, convert, mask options
uint16 TableLink; // this entry is a link to another map
uint16 Options; // miscellaneous options
};
/**************** Constants for opcode definition **********************
I have deliberately not assigned names to these constants because this would
make the tables in opcodes.cpp wery broad with many constant names OR'ed together.
It would be almost impossible to align the columns in a readable way.
Sorry that you have to look up the constants here.
The following tables define the possible values for each field in SOpcodeDef:
Name:
-----
Opcode mnemonic
InstructionSet:
(Some values can be OR'ed):
---------------------------
0: 8086
1: 80186
2: 80286
3: 80386
4: 80486, cpuid
5: Pentium
6: Pentium Pro, cmov, fcomi
7: MMX
8: Pentium II
0x11: SSE
0x12: SSE2
0x13: SSE3
0x14: Suppl. SSE3
0x15: SSE4.1
0x16: SSE4.2
0x17: AES
0x18: CLMUL
0x19: AVX
0x1A: FMA3
0x1C: AVX2
0x1D: BMI1, BMI2, ADX, RDRAND, RDSEED, INVPCID, SMAP, PRFCHW, F16C, Transactional Synchronization
0x20: AVX512F,BW,DQ,VL
0x21: AVX512PF,ER,CD
0x22: SHA,TBD
0x23: AVX512IFMA,VBMI
0x24: AVX512_4FMAPS, ..
0x80: MIC Knights Corner
0x100: 8087
0x101: 80387
0x800: Privileged instruction
0x1001: AMD 3DNow
0x1002: AMD 3DNow extension
0x1004: AMD SSE4a or AMD virtualization
0x1005: AMD XOP
0x1006: AMD FMA4
0x1007: AMD TBM
0x2001; VIA
0x4000: Only available in 64 bit mode
0x8000: Not available in 64 bit mode
0x10000: Proposed instruction code, preliminary specification
0x20000: Proposed instruction code never implemented, preliminary specification later changed
AllowedPrefixes:
(Values can be OR'ed):
----------------------
0: No prefix allowed other than possibly segment and address size prefixes if there is a mod/reg/rm byte
1: Address size prefix allowed, even if no mod/reg/rm byte
2: This is a stack operation. Address size prefix will truncate the stack pointer. Make warning if address size prefix or operand size prefix
4: Segment prefix allowed, even if no mod/reg/rm byte
8: Branch prediction hint prefix allowed (on Pentium 4) or BND prefix allowed
0x10: LOCK prefix allowed
0x20: REP prefix allowed
0x40: REPE/REPNE prefix allowed
0x80: This is a jump operation. 66 prefix will truncate EIP. Make warning if 66 prefix in 32 bit mode. 66 prefix not allowed in 64 bit mode.
0x100: 66 prefix determines integer operand size
0x200: 66 prefix allowed for other purpose. Typical meanings are:
* indicates packed integer xmm vs. mmx,
* indicates packed double precision xmm (pd) vs. packed single (ps)
* always required
0x400: F3 prefix allowed for other purpose. Typical = scalar single precision xmm (ss)
0x800: F2 prefix allowed for other purpose. Typical = scalar double precision xmm (sd)
0xC40: F2 and F3 prefix allowed for XACQUIRE and XRELEASE
0xE00: none/66/F2/F3 prefix indicate ps/pd/sd/ss vector
0x1000: REX.W prefix determines integer g.p. operand size or fp precision or swaps operands or other purpose
0x2000: REX.W prefix allowed but unnecessary
0x3000: REX.W prefix determines integer (vector) operand size d/q or ps/pd
0x4000: VEX.W prefix determines integer (vector) operand size b/w
0x5000: VEX.W and 66 prefix determines integer operand size b/w/d/q (mask instructions. B = 66W0, W = _W0, D = 66W1, Q = _W1)
0x7000: REX.W prefix swaps last two operands (AMD)
0x8000: Instruction not allowed without 66/F2/F3 prefix as specified by previous bits
0x10000: VEX or XOP prefix allowed
0x20000: VEX or EVEX or XOP prefix required
0x40000: VEX.L prefix allowed
0x80000: VEX.vvvv prefix allowed
0x100000:VEX.L prefix required
0x200000:VEX.L prefix allowed only if pp bits < 2
0x400000:MVEX prefix allowed
0x800000:EVEX prefix allowed
InstructionFormat:
(Values can be OR'ed):
----------------------
0: Illegal opcode.
1: No mod/reg/rm byte. Operands are implicit
2: No mod/reg/rm byte. No operands (other than possibly immediate operand)
3: No mod/reg/rm byte. Register operand indicated by bits 0-2
4: Has VEX or EVEX prefix and no mod/reg/rm byte, Register operand, if any, indicated by VEX.v
0x10: Has mod/reg/rm byte and possibly a SIB byte
0x11: Has mod/reg/rm byte and one register/memory operand
0x12: Has mod/reg/rm byte, a register destination operand and a register/memory source operand
0x13: Has mod/reg/rm byte, a register/memory destination operand and a register source operand
0x14: Has mod/reg/rm byte and AMD DREX byte. One destination and two source operands and possibly an immediate byte operand (AMD SSE5 instructions never implemened)
0x15: Has mod/reg/rm byte and AMD DREX byte. One destination and three source operands. One of the source operands is equal to the destination operand (AMD SSE5 instructions never implemened)
0x18: Has VEX or EVEX prefix and 2 operands. (NDD) Dest = VEX.v, src = rm, opcode extension in r bits. Src omitted if no VEX prefix.
0x19: Has VEX or EVEX prefix and 3 operands. (NDS) Dest = r, src1 = VEX.v, src2 = rm. Src1 omitted if no VEX prefix. May swap src1 and src2 if VEX.W = 0
0x1A: Has VEX prefix and 3 operands. Dest = rm, src1 = VEX.v, src2 = r
0x1B: Has VEX prefix and 3 operands. Dest = r, src1 = rm, src2 = VEX.v.
0x1C: Has VEX prefix and 4 operands. Dest = r, src1 = VEX.v, src2 = rm, src3 = bits 4-7 of immediate byte. May swap src2 and src3 if VEX.W
0x1D: Has VEX prefix and 4 operands. Dest = r, src1 = bits 4-7 of immediate byte, src2 = rm, src3 = VEX.v. May swap src2 and src3 if VEX.W
0x1E: Has VEX prefix VSIB and 2 or 3 operands. Dest = r or rm, src1 = rm or r, src2 = VEX.v or k register or none. VSIB byte required (rm operand & 0xF00 = index register size, rm operand & 0xFF = operand size)
0x20: Has 2 bytes immediate operand (ret i) or 1 + 1 bytes (insrtq)
0x40: Has 1 byte immediate operand or short jump
0x60: Has 2 + 1 = 3 bytes immediate operand (enter)
0x80: Has 2 or 4 bytes immediate operand or near jump
0x100: Has a 2, 4 or 8 bytes immediate operand
0x200: Has a 2+2 or 4+2 far direct jump operand
0x400: Has a 2, 4 or 8 bytes direct memory operand
0x800: Has a far indirect memory operand, dword, fword or tbyte
0x2000: Opcode reserved for future extensions
0x4000: Undocumented opcode or illegal (undocumented if name specified, otherwise illegal or unknown)
0x8000: This is a prefix, not an opcode
0x8001: This is a segment prefix
Destination and Source operand types,
used by SOpcodeDef::Destination, SOpcodeDef::Source, and CDisassembler::s.Operands[].
Many of the bit values can be OR'ed. If an instruction has two source operands, then
the values for these two operands are OR'ed (e.g. imul eax,ebx,9; shrd eax,ebx,cl).
-------------------------------------------------------------------------------------
0: No explicit operand
1: 8 bit integer
2: 16 bit integer
3: 32 bit integer
4: 64 bit integer
5: 80 bit integer memory
6: integer memory, other size
7: 48 bit memory
8: 16 or 32 bit integer, depending on 66 prefix
9: 16, 32 or 64 bit integer, depending on 66 or REX.W prefix. (8 bit in some cases as indicated by AllowedPrefixes)
0x0A: 16, 32 or 64 bit integer, default size = address size (REX.W not needed)
0x0B: 16, 32 or 64 bit near indirect pointer (jump)
0x0C: 16, 32 or 64 bit near indirect pointer (call)
0x0D: 16+16, 32+16 or 64+16 bits far indirect pointer (jump or call)
0x11: 8 bit constant, unsigned
0x12: 16 bit constant, unsigned
0x13: 32 bit constant, unsigned
0x18: 16 or 32 bit constant, unsigned
0x19: 16, 32 or 64 bit constant, unsigned
0x21: 8 bit constant, signed
0x22: 16 bit constant, signed
0x23: 32 bit constant, signed
0x28: 16 or 32 bit constant, signed
0x29: 16, 32 or 64 bit constant, signed
0x31: 8 bit constant, hexadecimal
0x32: 16 bit constant, hexadecimal
0x33: 32 bit constant, hexadecimal
0x34: 64 bit constant, hexadecimal
0x38: 16 or 32 bit constant, hexadecimal
0x39: 16, 32 or 64 bit constant, hexadecimal
0x40: float x87, unknown size or register only
0x43: 32 bit float x87, single precision
0x44: 64 bit float x87, double precision
0x45: 80 bit float x87, long double precision
0x48: float SSE, unknown size
0x4A: 16 bit float, half precision
0x4B: 32 bit float SSE, single precision (ss) or packed (ps)
0x4C: 64 bit float SSE2, double precision (sd) or packed (pd)
0x4F: XMM float. Size depends on prefix: none = ps, 66 = pd, F2 = sd, F3 = ss; or VEX.W bit = sd/pd
0x50: Full vector, aligned
0x51: Full vector, unaligned
0x81: Short jump destination, 8 bits
0x82: Near jump destination, 16 or 32 bits, depending on operand size
0x83: Near call destination, 16 or 32 bits, depending on operand size
0x84: Far jump destination, 16+16 or 32+16 bits, depending on operand size
0x85: Far call destination, 16+16 or 32+16 bits, depending on operand size
0x91: segment register
0x92: control register
0x93: debug register
0x94: test register (obsolete or undocumented)
0x95: k0 - k7 mask register. 16 bits if memory operand, 32-64 bits if register
0x96: (reserved for future mask register > 16 bits)
0x98: bnd0 - bnd3 bounds register
0xa1: al
0xa2: ax
0xa3: eax
0xa4: rax
0xa8: ax or eax
0xa9: ax, eax or rax
0xae: xmm0
0xaf: st(0)
0xb1: 1
0xb2: dx
0xb3: cl
0xc0: [bx], [ebx] or [rbx]
0xc1: [si], [esi] or [rsi]
0xc2: es:[di], es:[edi] or [rdi]
// The following values can be added to specify vectors
0x100: Vector MMX or XMM or YMM or ZMM, depending on 66 prefix and VEX.L prefix and EVEX.LL prefix
0x200: Vector XMM, YMM or ZMM, depending on VEX.L prefix and EVEX.LL prefix
0x300: Vector MMX (8 bytes)
0x400: Vector XMM (16 bytes)
0x500: Vector YMM (32 bytes)
0x600: Vector ZMM (64 bytes)
0x700: Future ??? (128 bytes)
0xF00: Vector half the size defined by VEX.L prefix and EVEX.LL prefix. Minimum size = 8 bytes for memory, xmm for register
// The following values can be added to specify operand type
0x1000: Must be register, memory operand not allowed
0x2000: Must be memory, register operand not allowed
// The following bit values apply to CDisassembler::s.Operands[] only:
0x10000: Direct memory operand without mod/reg/rm byte
0x20000: Register operand indicated by last bits of opcode and B bit
0x30000: Register or memory operand indicated by mod and rm bits of mod/reg/rm byte and B,X bits
0x40000: Register operand indicated by reg bits of mod/reg/rm byte and R bit
0x50000: Register operand indicated by dest bits of DREX byte
0x60000: Register operand indicated by VEX.vvvv bits
0x70000: Register operand indicated by bits 4-7 of immediate operand
0x80000: (Register operand indicated by bits 0-3 of immediate operand. unused, reserved for future use)
0x100000: Immediate operand using immediate field or first part of it
0x200000: Immediate operand using second part of immediate field
0x1000000: Is code
0x2000000: Is supposed to be code, but dubious
0x4000000: Is data
// The following bit values applies only to symbol types originating from object file
0x40000000: Gnu indirect function (CPU dispatcher)
0x80000000: Symbol is a segment (in COFF file symbol table)
EVEX:
--------
This field indicates the meaning of the z, L'L, b and aaa bits of an EVEX prefix.
(The EVEX field may also be used in the future for indicating an extra operand
if it is not needed for its current purpose).
Bit 0-3 indicate meaning of L'L, b field:
0x01 broadcast allowed for memory operand, LL indicate vector length
0x02 SAE allowed for register operands, no rounding control, LL indicate vector length
0x06 rounding control and SAE allowed for register operands
0x08 Scalar. LL ignored
Bit 4-7 indicate mask use in aaa/kkk field
0x00 no masking. aaa must be zero
0x10 allow masking, not zeroing
0x20 allow masking and zeroing
0x50 allow masking, not zeroing. aaa must be nonzero
0x80 mask is modified by instruction
Bit 12-15 indicate offset multiplier
0x0000 Multiplier corresponds to memory operand size
0x1000 Multiplier corresponds to vector element size
0x2200 Multiplier corresponds to half the size of the largest vector operand
0x2400 Multiplier corresponds to 1/4 of the size of the largest vector operand
0x2600 Multiplier corresponds to 1/8 of the size of the largest vector operand
MVEX:
--------
This field indicates the meaning of the sss, e and kkk bits of an MVEX prefix.
(The MVEX field may also be used in the future for indicating an extra operand
if it is not needed for its current purpose).
Bit 0-4 indicate meaning of sss field:
0. none, sss must be 0
1. sss ignored or used only for sae, offset multiplier defined, vector size defined
2. sss ignored or used only for sae, offset multiplier defined, vector size not defined by sss
3. reserved for future use
4. Sf32. 32-bit float operand. permutation if register, broadcast or conversion if memory operand
5. Sf64. 64-bit float operand. permutation if register, broadcast if memory operand
6. Si32. 32-bit integer operand. permutation if register, broadcast or conversion if memory operand
7. Si64. 64-bit integer operand. permutation if register, broadcast if memory operand
8. Uf32. 32-bit float memory operand. Up conversion from smaller integer or float operand
9. Uf64. 64-bit float memory operand. Currently no conversion supported
0xA. Ui32. 32-bit integer memory operand. Up conversion from smaller integer operand
0xB. Ui64. 64-bit integer memory operand. Currently no conversion supported
0xC. Df32. 32-bit float memory operand. Down conversion to smaller integer or float operand
0xD. Df64. 64-bit float memory operand. Currently no conversion supported
0xE. Di32. 32-bit integer memory operand. Down conversion to smaller integer operand
0xF. Di64. 64-bit integer memory operand. Currently no conversion supported
0x10. Uf32, broadcast * 4, vbroadcastf32x4
0x11. Uf64, broadcast * 4, vbroadcastf64x4
0x12. Ui32, broadcast * 4, vbroadcasti32x4
0x13. Ui64, broadcast * 4, vbroadcasti64x4
0x14. Si32, half size, vcvtdq2pd, vcvtudq2pd
0x15. Sf32, half size, vcvtps2pd
0x16. Sf32, without register swizzle and limited broadcast, vfmadd233ps
Bit 6-7 indicate offset multiplier
0x00 No broadcast. Multiplier corresponds to conversion
0x40 Broadcast, gather and scatter instructions. Multiplier corresponds to element size before conversion
Bit 8-10 indicate alternative meaning of sss field for register operand when E bit is 1:
0x000. E bit not allowed for register operand
0x100. sss specifies rounding mode
0x200. high s bit indicates suppress all exceptions {sae}
0x300. sss specifies rounding mode and sae
0x400. no rounding and no sae. sss bits ignored when E = 1
Bit 11 ignore E bit
0x000. The E bit means cache eviction hint
0x800. The E bit is ignored for memory operands or has a different meaning
Bit 12-13 indicate meaning of kkk field
0x0000. kkk bits unused, must be 0
0x1000. kkk bits specify register used for masked operation
0x2000. kkk bits specify mask register as destination operand
0x3000. kkk bits specify mask register used both for masked operation and as destination operand
The multiplier for single-byte address offsets is derived from the meaning of the sss field.
TableLink:
----------
Used for linking to another opcode table when more than one opcode begins
with the same bytes or when different specifications are needed in different
cases. When TableLink is nonzero then InstructionSet is an index into
OpcodeTables pointing to a subtable. The subtable is indexed according to
the criterion defined by TableLink.
0: No link to other table
1: Use following byte as index into next table (256 entries)
2: Use reg field of mod/reg/rm byte as index into next table (8 entries)
3: Use mod < 3 vs. mod == 3 as index (0: memory operand, 1: register operand)
4: Use mod and reg fields of mod/reg/rm byte as index into next table,
first 8 entries indexed by reg for mod < 3, next 8 entries indexed by reg for mod = 3.
5: Use rm bits of mod/reg/rm byte as index into next table (8 entries)
6: Use immediate byte after any operands as index into next table. Note: Instruction format must be specified
7: Use mode as index into next table (0: 16 bits, 1: 32 bits, 2: 64 bits)
8: Use operand size as index into next table (0: 16 bits, 1: 32 bits, 2: 64 bits)
9: Use prefixes as index into next table (0: none, 1: 66, 2: F2, 3: F3)
0x0A: Use address size as index into next table (0: 16 bits, 1: 32 bits, 2: 64 bits)
0x0B: Use VEX prefix and VEX.L bits as index into next table (0: VEX absent, 1: VEX.L=0, 2: VEX.L=1, 3:MVEX or EVEX.LL=2, 4: EVEX.LL=3)
0x0C: Use VEX.W bit as index into next table (0: VEX.W=0, 1: VEX.W=1)
0x0D: Use vector size by VEX.L bits as index into next table (0: VEX.L=0, 1: VEX.L=1, 2:MVEX or EVEX.LL=2, 3: EVEX.LL=3)
0x0E: Use VEX prefix type as index into next table. (0: 2- or 3-bytes VEX or none, 1: 4-bytes EVEX or MVEX)
0x0F: Use MVEX.E bit as index into next table. (0: MVEX.E = 0 or no MVEX, 1: MVEX.E = 1)
0x10: Use assembly language dialect as index into next table (0: MASM, 1: NASM/YASM, 2: GAS)
0x11: Use VEX prefix type as index into next table. (0: none, 1: VEX prefix, 2: EVEX prefix, 3: MVEX prefix)
Options:
(Values can be OR'ed):
----------------------
1: Append suffix for operand size or type to opcode name (prefix 0x100: b/w/d/q, 0xE00: ps/pd/ss/sd, 0x1000: s/d, 0x3000: d/q, 0x4000: b/w)
2: Prepend 'v' to opcode name if VEX prefix present
4: Does not change destination register
8: Can change registers other than explicit destination register (includes call etc.)
0x10: Unconditional jump. Next instruction will not be executed unless there is a jump to it.
0x20: Code prefixes explicitly. Assembler cannot code prefixes on this instruction
0x40: Instruction may be used as NOP or filler
0x80: Shorter version of instruction exists for certain operand values
0x100: Aligned. Memory operand must be aligned, even if VEX prefixed
0x200: Unaligned. Unaligned memory operand always allowed.
0x400: Opcode name differs if 64 bits
0x800: Do not write size specifier on memory operand
0x1000: Append alternative suffix to opcode name (prefix 0x3000: "32"/"64")
*/
// Structure for opcode swizzle table entries indicating meaning of EVEX.sss bits
struct SwizSpec {
uint32 memop; // memory operand type
uint32 memopsize; // memory operand size = byte offset multiplier = required alignment
uint32 elementsize; // memory operand size for broadcast, gather and scatter instructions
const char * name; // name of permutation, conversion or rounding
};
// Define data structures and classes used by class CDisassembler:
// Structure for properties of a single opcode during disassembly
struct SOpcodeProp {
SOpcodeDef const * OpcodeDef; // Points to entry in opcode map
uint8 Prefixes[8]; // Stores the last prefix encountered in each category
uint8 Conflicts[8]; // Counts prefix conflicts as different prefixes in the same category
uint32 Warnings1; // Warnings about conditions that could be intentional and suboptimal code
uint32 Warnings2; // Warnings about possible misinterpretation
uint32 Errors; // Errors that will prevent execution or are unlikely to be intentional
uint32 AddressSize; // Address size: 16, 32 or 64
uint32 OperandSize; // Operand size: 16, 32 or 64
uint32 MaxNumOperands; // Number of opcode table operands to check
uint32 Mod; // mod bits of mod/reg/rm byte
uint32 Reg; // reg bits of mod/reg/rm byte
uint32 RM; // r/m bits of mod/reg/rm byte
uint32 MFlags; // Memory operand type: 1=has memory operand, 2=has mod/reg/rm byte, 4=has SIB byte, 8=has VEX or DREX byte, 0x100=is rip-relative
uint32 BaseReg; // Base register + 1. (0 if none)
uint32 IndexReg; // Index register + 1. (0 if none)
uint32 Scale; // Scale factor = 2^Scale
uint32 Vreg; // ~VEX.vvvv or AMD DREX byte
uint32 Kreg; // EVEX.aaa = MVEX.kkk mask register
uint32 Esss; // EVEX.zLLb = MVEX.Esss option bits
SwizSpec const * SwizRecord; // Selected entry in MVEX table for MVEX code
uint32 OffsetMultiplier; // Multiplier for 1-byte offset calculated from EVEX or obtained from MVEX.sss and table lookup
uint32 Operands[5]; // Operand types for destination, source, immediate
uint32 OpcodeStart1; // Index to first opcode byte, after prefixes
uint32 OpcodeStart2; // Index to last opcode byte, after 0F, 0F 38, etc., before mod/reg/rm byte and operands
uint32 AddressField; // Beginning of address/displacement field
uint32 AddressFieldSize; // Size of address/displacement field
uint32 AddressRelocation; // Relocation pointing to address field
uint32 ImmediateField; // Beginning of immediate operand or jump address field
uint32 ImmediateFieldSize; // Size of immediate operand or jump address field
uint32 ImmediateRelocation; // Relocation pointing to immediate operand or jump address field
const char * OpComment; // Additional comment for opcode
void Reset() { // Set everything to zero
memset(this, 0, sizeof(*this));}
};
// The meaning of each bit in s.Warnings and s.Errors is given in
// AsmErrorTexts and AsmWarningTexts in the beginning of disasm.cpp
// Prefix categories used by s.Prefixes[category]
// 0: Segment prefix (26, 2E, 36, 3E, 64, 65)
// 1: Address size prefix (67)
// 2: Lock prefix (F0)
// 3: Repeat prefix (F2, F3) or VEX prefix (C4, C5) or EVEX, MVEX (62) or XOP (8F)
// 4: Operand size prefix (66, REX.W)
// 5: Operand type prefix (66, F2, F3)
// 6: VEX prefix: bit 5: VEX.L (vector length), bit 0-4: VEX.mmmmm
// MVEX: bit 5 = 0, bit 6 = 1. EVEX: bit 5 = 1, bit 6 = 1
// 7: Rex prefix (40 - 4F), VEX.W,R,X,B, DREX.W,R,X,B
// bit 0: B = extension of mod/rm or base or opcode
// bit 1: X = extension of index register
// bit 2: R = extension of reg bits
// bit 3: W = 64 bit operand size, or swap operands or other use of VEX.W
// bit 4: 2-bytes VEX prefix
// bit 5: 3 or 4-bytes VEX prefix
// bit 6: REX prefix
// bit 7: XOP prefix or DREX byte (AMD only)
// Note that the 66 and REX.W prefixes belong to two categories. The interpretation
// is determined by AllowedPrefixes in SOpcodeDef
// Structure for tracing register values etc.
// See CDisassembler::UpdateTracer() in disasm.cpp for an explanation
struct SATracer {
uint8 Regist[16]; // Defines the type of information contained in each g.p. register
uint32 Value[16]; // Meaning depends on the value of Regist[i]
void Reset() { // Set to zero
*(uint64*)Regist = 0; *(uint64*)(Regist+8) = 0;
}
};
// Structure for defining section
struct SASection {
uint8 * Start; // Point to start of binary data
uint32 SectionAddress; // Address of section (image relative)
uint32 InitSize; // Size of initialized data in section
uint32 TotalSize; // Size of initialized and uninitialized data in section
uint32 Type; // 0 = unknown, 1 = code,
// 2 = data, 3 = uninitialized data only, 4 = constant data,
// 0x10 = debug info, 0x11 = exception info.
// 0x800 = segment group
// 0x1000 = communal section
uint32 Align; // Alignment = 1 << Align
uint32 WordSize; // Word size, 16, 32, 64
uint32 Name; // Name, as index into CDisassembler::NameBuffer
int32 Group; // Group that the segment is member of. 0 = none, -2 = flat, > 0 = defined group
};
// Structure for defining relocation or cross-reference
struct SARelocation {
int32 Section; // Section of relocation source
uint32 Offset; // Offset of relocation source into section
uint32 Type; // Relocation types:
// 0 = unknown, 1 = direct, 2 = self-relative, 4 = image-relative,
// 8 = segment relative, 0x10 = relative to arbitrary ref. point,
// 0x21 = direct, has already been relocated to image base (executable files only)
// 0x41 = direct, make entry in procedure linkage table. Ignore addend (executable files only)
// 0x81 = direct to Gnu indirect function PLT entry
// 0x100 = segment address/descriptor, 0x200 = segment of symbol,
// 0x400 = segment:offset far
// 0x1001 = reference to GOT entry relative to GOT. 0x1002 = self-relative reference to GOT or GOT-entry
// 0x2002 = self-relative to PLT
uint32 Size; // 1 = byte, 2 = word, 4 = dword, 6 = fword, 8 = qword
int32 Addend; // Addend to add to target address,
// including distance from source to instruction pointer in self-relative addresses,
// not including inline addend.
uint32 TargetOldIndex; // Old symbol table index of target
uint32 RefOldIndex; // Old symbol table index of reference point if Type = 8, 0x10, 0x200
int operator < (const SARelocation & y) const{// Operator for sorting relocation table by source address
return Section < y.Section || (Section == y.Section && Offset < y.Offset);}
};
// Structure for indicating where a function begins and ends
struct SFunctionRecord {
int32 Section; // Section containing function
uint32 Start; // Offset of function start
uint32 End; // Offset of function end
uint32 Scope; // Scope of function. 0 = inaccessible, 1 = function local, 2 = file local, 4 = public, 8 = weak public, 0x10 = communal, 0x20 = external
// 0x10000 means End not known, extend it when you pass End
uint32 OldSymbolIndex; // Old symbol table index
int operator < (const SFunctionRecord & y) const{// Operator for sorting function table by source address
return Section < y.Section || (Section == y.Section && Start < y.Start);}
};
// Structure for defining symbol
struct SASymbol {
int32 Section; // Section number. 0 = external, -1 = absolute symbol, -16 = section to be found from image-relative offset
uint32 Offset; // Offset into section. (Value for absolute symbol)
uint32 Size; // Number of bytes used by symbol or function. 0 = unknown
uint32 Type; // Use values listed above for SOpcodeDef operands. 0 = unknown type
uint32 Name; // Name, as index into CDisassembler::SymbolNameBuffer. 0 = no name yet
uint32 DLLName; // Name of DLL if symbol imported by dynamic linking
uint32 Scope; // 0 = inaccessible, 1 = function local, 2 = file local, 4 = public, 8 = weak public, 0x10 = communal, 0x20 = external, 0x100 = has been written
uint32 OldIndex; // Index in original symbol table. Used for tracking relocation entries
void Reset() { // Set everything to zero
memset(this, 0, sizeof(*this));}
int operator < (const SASymbol & y) const { // Operator for sorting symbol table
return Section < y.Section || (Section == y.Section && Offset < y.Offset);}
};
// Define class CSymbolTable
class CSymbolTable {
public:
CSymbolTable(); // Constructor
uint32 AddSymbol(int32 Section, uint32 Offset,// Add a symbol from original file
uint32 Size, uint32 Type, uint32 Scope,
uint32 OldIndex, const char * Name, const char * DLLName = 0);
uint32 NewSymbol(int32 Section, uint32 Offset, uint32 Scope); // Add symbol to list
uint32 NewSymbol(SASymbol & sym); // Add symbol to list
void AssignNames(); // Assign names to symbols that do not have a name
uint32 FindByAddress(int32 Section, uint32 Offset, uint32 * Last, uint32 * NextAfter = 0); // Find symbols by address
uint32 FindByAddress(int32 Section, uint32 Offset); // Find symbols by address
uint32 Old2NewIndex(uint32 OldIndex); // Translate old symbol index to new index
SASymbol & operator [](uint32 NewIndex) { // Access symbol by new index
return List[NewIndex];}
const char * HasName(uint32 symo); // Ask if symbol has a name, input = old index, output = name or 0
const char * GetName(uint32 symi); // Get symbol name by new index. (Assign a name if none)
const char * GetNameO(uint32 symo); // Get symbol name by old index. (Assign a name if none)
const char * GetDLLName(uint32 symi); // Get import DLL name
void AssignName(uint32 symi, const char *name); // Give symbol a specific name
uint32 GetLimit() {return OldNum;} // Get highest old symbol number + 1
uint32 GetNumEntries() {return List.GetNumEntries();}// Get highest new symbol number + 1
protected:
CSList<SASymbol> List; // List of symbols, sorted by address
CMemoryBuffer SymbolNameBuffer; // String buffer for names of symbols
CSList<uint32> TranslateOldIndex; // Table to translate old symbol index to new symbol index
void UpdateIndex(); // Update TranslateOldIndex
uint32 OldNum; // = 1 + max OldIndex
uint32 NewNum; // Number of entries in List
uint32 UnnamedNum; // Number of unnamed symbols
public:
const char * UnnamedSymbolsPrefix; // Prefix for names of unnamed symbols
const char * UnnamedSymFormat; // Format string for giving names to unnamed symbols
const char * ImportTablePrefix; // Prefix for pointers in import table
};
// Define class CDisassembler
// Instructions for use:
// The calling program must first define the imagebase, if any, by calling
// Init. Define all sections by calls to AddSection.
// Then define all symbols and relocations or cross-references by calls to
// AddSymbol and AddRelocation.
// Then call Go().
// Go() and its subfunctions will sort Symbols and Relocations, add all
// nameless symbols to its symbol table and give them names, assign types
// to all symbols as good as possible from the available information, and
// find where each function begins and ends. Then it will disassemble the
// code and fill OutFile with the disassembly.
class CDisassembler {
public:
CDisassembler(); // Constructor. Initializes tables etc.
void Go(); // Do the disassembly
void Init(uint32 ExeType, int64 ImageBase); // Define file type and imagebase if executable file
// ExeType: 0 = object, 1 = position independent shared object, 2 = executable file
// Set ExeType = 2 if addresses have been relocated to a nonzero image base and there is no base relocation table.
void AddSection( // Define section to be disassembled
uint8 * Buffer, // Buffer containing raw data
uint32 InitSize, // Size of initialized data in section
uint32 TotalSize, // Size of initialized and uninitialized data in section
uint32 SectionAddress, // Start address of section (image relative)
uint32 Type, // 0 = unknown, 1 = code, 2 = data, 3 = uninitialized data, 4 = constant data
uint32 Align, // Alignment = 1 << Align
uint32 WordSize, // Segment word size: 16, 32 or 64
const char * Name, // Name of section
uint32 NameLength = 0); // Length of name if not zero terminated
uint32 AddSymbol( // Define symbol for disassembler
int32 Section, // Section number (1-based). 0 = external, -1 = absolute, -16 = Offset contains image-relative address
uint32 Offset, // Offset into section. (Value for absolute symbol)
uint32 Size, // Number of bytes used by symbol or function. 0 = unknown
uint32 Type, // Symbol type. Use values listed above for SOpcodeDef operands. 0 = unknown type
uint32 Scope, // 1 = function local, 2 = file local, 4 = public, 8 = weak public, 0x10 = communal, 0x20 = external
uint32 OldIndex, // Unique identifier used in relocation entries. Value must be > 0 and limited because an array is created with this as index.
// A value will be assigned and returned if 0.
const char * Name, // Name of symbol. Zero-terminated ASCII string. A name will be assigned if 0.
const char * DLLName = 0); // Name of DLL if imported dynamically
void AddRelocation( // Define relocation or cross-reference for disassembler
int32 Section, // Section of relocation source:
// Sections (and groups) are numbered in the order they are defined, starting at 1
// 0 = none or external, -1 = absolute symbol
// -16 = Offset contains image-relative address
uint32 Offset, // Offset of relocation source into section
int32 Addend, // Addend to add to target address,
// including distance from source to instruction pointer in self-relative addresses,
// not including inline addend.
uint32 Type, // see above at SARelocation for definition of relocation types
uint32 Size, // 1 = byte, 2 = word, 4 = dword, 8 = qword
uint32 TargetIndex, // Symbol index of target
uint32 ReferenceIndex = 0); // Symbol index of reference point if Type 0x10, Segment index if Type = 8 or 0x200
int32 AddSectionGroup( // Define section group (from OMF file)
const char * Name, // Name of group
int32 MemberSegment); // Group member. Repeat for multiple members. 0 if none.
static void CountInstructions(); // Count total number of instructions defined in opcodes.cpp
const char * CommentSeparator; // "; " or "# " Start of comment string
const char * HereOperator; // "$" or "." indicating current position
CTextFileBuffer OutFile; // Output file
protected:
CSymbolTable Symbols; // Table of symbols
CSList<SASection> Sections; // List of sections. First is 0
CSList<SARelocation> Relocations; // List of cross references. First is 0
CMemoryBuffer NameBuffer; // String buffer for names of sections. First is 0.
CSList<SFunctionRecord> FunctionList; // List of functions
int64 ImageBase; // Image base for executable files
uint32 ExeType; // File type: 0 = object, 1 = position independent shared object, 2 = executable
uint32 RelocationsInSource; // Number of relocations in source file
// Code parser: The following members are used for parsing
// an opcode and identifying its components
uint8 * Buffer; // Point to start of binary data
SOpcodeProp s; // Properties of current opcode
SATracer t; // Trace of register contents
uint32 Pass; // 1 = pass 1, 2-3 = pass 1 repeated, 0x10 = pass 2, 0x100 = repetition requested
uint32 SectionEnd; // End of current section
uint32 WordSize; // Segment word size: 16, 32, 64
uint32 Section; // Current section/segment
uint32 SectionAddress; // Address of beginning of this section
uint32 SectionType; // 0 = unknown, 1 = code, 2 = data, 3 = uninitialized data, 4 = constant data
uint32 CodeMode; // 1 if current position contains code, 2 if dubiuos, 4 if data
uint32 IFunction; // Index into FunctionList
uint32 FunctionEnd; // End address of current function (pass 2)
uint32 LabelBegin; // Address of nearest preceding label
uint32 LabelEnd; // Address of next label
uint32 LabelInaccessible; // Address of inaccessible code
uint32 IBegin; // Begin of current instruction
uint32 IEnd; // End of current instruction
uint32 DataType; // Type of current data
uint32 DataSize; // Size of current data
uint32 FlagPrevious; // 1: previous instruction was a NOP.
// 2: previous instruction was unconditional jump. 6: instruction was ud2
// 0x100: previous data aligned by 16
// 0x200: previous data aligned by 32
uint8 InstructionSetMax; // Highest instruction set encountered
uint8 InstructionSetAMDMAX; // Highest AMD-specific instruction set encountered
uint16 InstructionSetOR; // Bitwise OR of all instruction sets encountered
uint16 Opcodei; // Map number and index in opcodes.cpp
uint16 OpcodeOptions; // Option flags for opcode
uint16 PreviousOpcodei; // Opcode for previous instruction
uint16 PreviousOpcodeOptions; // Option flags for previous instruction
uint32 CountErrors; // Number of errors since last label
uint32 Syntax; // Assembly syntax dialect: 1: MASM/TASM, 2: NASM/YASM, 4: GAS
uint32 MasmOptions; // Options needed for MASM: 1: dotname, 2: fs used, 4: gs used
// 0x100: 16 bit segments, 0x200: 32 bit segments, 0x400: 64 bit segments
uint32 NamesChanged; // Symbol names containing invalid characters changed
int32 Assumes[6]; // Assumed value of segment register es, cs, ss, ds, fs, gs. See CDisassembler::WriteSectionName for values
void Pass1(); // Pass 1: Find symbols types and unnamed symbols
void Pass2(); // Pass 2: Write output file
int NextFunction2(); // Loop through function blocks in pass 2. Return 0 if finished
int NextLabel(); // Loop through labels. (Pass 2)
int NextInstruction1(); // Go to next instruction. Return 0 if none. (Pass 1)
int NextInstruction2(); // Go to next instruction. Return 0 if none. (Pass 2)
void ParseInstruction(); // Parse one opcode
void ScanPrefixes(); // Scan prefixes
void StorePrefix(uint32 Category, uint8 Byte);// Store prefix according to category
void FindMapEntry(); // Find entry in opcode maps
void FindOperands(); // Interpret mod/reg/rm and SIB bytes and find operand fields
void FindOperandTypes(); // Determine the types of each operand
void FindBroadcast(); // Find broadcast and offset multiplier for EVEX code
void SwizTableLookup(); // Find swizzle table entry for MVEX code
void FindLabels(); // Find any labels at current position and next
void CheckForMisplacedLabel(); // Remove any label placed inside function
void FindRelocations(); // Find any relocation sources in this instruction
void FindWarnings(); // Find any reasons for warnings in code
void FindErrors(); // Find any errors in code
void FindInstructionSet(); // Update instruction set
void CheckForNops(); // Check if warnings are caused by multi-byte NOP
void UpdateSymbols(); // Find unnamed symbols, determine symbol types, update symbol list, call CheckJumpTarget if jump/call
void UpdateTracer(); // Trace register values
void MarkCodeAsDubious(); // Remember that this may be data in a code segment
void CheckRelocationTarget(uint32 IRel, uint32 TargetType, uint32 TargetSize);// Update relocation record and its target
void CheckJumpTarget(uint32 symi); // Extend range of current function to jump target, if needed
void FollowJumpTable(uint32 symi, uint32 RelType);// Check jump/call table and its targets
uint32 MakeMissingRelocation(int32 Section, uint32 Offset, uint32 RelType, uint32 TargetType, uint32 TargetScope, uint32 SourceSize = 0, uint32 RefPoint = 0); // Make a relocation and its target symbol from inline address
void CheckImportSymbol(uint32 symi); // Check for indirect jump to import table entry
void CheckForFunctionBegin(); // Check if function begins at current position
void CheckForFunctionEnd(); // Check if function ends at current position
void CheckLabel(); // Check if a label is needed before instruction
void InitialErrorCheck(); // Check for illegal relocations table entries
void FinalErrorCheck(); // Check for illegal entries in symbol table and relocations table
void CheckNamesValid(); // Fix invalid characters in symbol and section names
void FixRelocationTargetAddresses(); // Find missing relocation target addresses
int TranslateAbsAddress(int64 Addr, int32 &Sect, uint32 &Offset); // Translate absolute virtual address to section and offset
void WriteFileBegin(); // Write begin of file
void WriteFileBeginMASM(); // Write MASM-specific file init
void WriteFileBeginYASM(); // Write YASM-specific file init
void WriteFileBeginGASM(); // Write GAS-specific file init
void WriteFileEnd(); // Write end of file
void WriteSegmentBegin(); // Write begin of segment
void WriteSegmentBeginMASM(); // Write begin of segment, MASM syntax
void WriteSegmentBeginYASM(); // Write begin of segment, YASM syntax
void WriteSegmentBeginGASM(); // Write begin of segment, GAS syntax
void WriteSegmentEnd(); // Write end of segment
void WritePublicsAndExternalsMASM(); // Write public and external symbol definitions, MASM syntax
void WritePublicsAndExternalsYASMGASM(); // Write public and external symbol definitions, YASM and GAS syntax
void WriteFunctionBegin(); // Write begin of function
void WriteFunctionBeginMASM(uint32 symi, uint32 scope);// Write begin of function, MASM syntax
void WriteFunctionBeginYASM(uint32 symi, uint32 scope);// Write begin of function, YASM syntax
void WriteFunctionBeginGASM(uint32 symi, uint32 scope);// Write begin of function, GAS syntax
void WriteFunctionEnd(); // Write end of function
void WriteFunctionEndMASM(uint32 symi); // Write end of function, MASM syntax
void WriteFunctionEndYASM(uint32 symi); // Write end of function, YASM syntax
void WriteFunctionEndGASM(uint32 symi); // Write end of function, GAS syntax
void WriteCodeLabel(uint32 symi); // Write private or public code label
void WriteCodeLabelMASM(uint32 symi, uint32 scope);// Write private or public code label, MASM syntax
void WriteCodeLabelYASM(uint32 symi, uint32 scope);// Write private or public code label, MASM syntax
void WriteCodeLabelGASM(uint32 symi, uint32 scope);// Write private or public code label, MASM syntax
int WriteFillers(); // Check if code is a series of NOPs or other fillers. If so then write it as such
void WriteAlign(uint32 a); // Write alignment directive
void WriteErrorsAndWarnings(); // Write errors and warnings, if any
void WriteAssume(); // Write assume directive for segment register
void WriteInstruction(); // Write instruction and operands
void WriteCodeComment(); // Write hex listing of instruction as comment after instruction
void WriteStringInstruction(); // Write string instruction or xlat instruction
void WriteShortRegOperand(uint32 Type); // Write register operand from lower 3 bits of opcode byte to OutFile
void WriteRegOperand(uint32 Type); // Write register operand from reg bits to OutFile
void WriteRMOperand(uint32 Type); // Write memory or register operand from mod/rm bits of mod/reg/rm byte and possibly SIB byte to OutFile
void WriteDREXOperand(uint32 Type); // Write register operand from dest bits of DREX byte
void WriteVEXOperand(uint32 Type, int i); // Write register operand from VEX.vvvv bits or immediate bits
void WriteOperandAttributeEVEX(int i, int isMem);// Write operand attributes and instruction attributes from EVEX z, LL, b and aaa bits
void WriteOperandAttributeMVEX(int i, int isMem);// Write operand attributes and instruction attributes from MVEX sss, e and kkk bits
void WriteImmediateOperand(uint32 Type); // Write immediate operand or direct jump/call address
void WriteOtherOperand(uint32 Type); // Write other type of operand
void WriteRegisterName(uint32 Value, uint32 Type); // Write name of register to OutFile
void WriteSectionName(int32 SegIndex); // Write section name from section index
void WriteSymbolName(uint32 symi); // Write symbol name
void WriteRelocationTarget(uint32 irel, uint32 Context, int64 Addend);// Write cross reference
void WriteOperandType(uint32 type); // Write type override before operand, e.g. "dword ptr"
void WriteOperandTypeMASM(uint32 type); // Write type override before operand, e.g. "dword ptr", MASM syntax
void WriteOperandTypeYASM(uint32 type); // Write type override before operand, e.g. "dword", YASM syntax
void WriteOperandTypeGASM(uint32 type); // Write type override before operand, e.g. "dword ptr", GAS syntax
void WriteDataItems(); // Write data items
void WriteDataLabelMASM(const char * name, uint32 sym, int line); // Write label before data item, MASM syntax
void WriteDataLabelYASM(const char * name, uint32 sym, int line); // Write label before data item, YASM syntax
void WriteDataLabelGASM(const char * name, uint32 sym, int line); // Write label before data item, GAS syntax
void WriteUninitDataItemsMASM(uint32 size, uint32 count);// Write uninitialized (BSS) data, MASM syntax
void WriteUninitDataItemsYASM(uint32 size, uint32 count);// Write uninitialized (BSS) data, YASM syntax
void WriteUninitDataItemsGASM(uint32 size, uint32 count);// Write uninitialized (BSS) data, GAS syntax
void WriteDataDirectiveMASM(uint32 size); // Write DB, etc., MASM syntax
void WriteDataDirectiveYASM(uint32 size); // Write DB, etc., MASM syntax
void WriteDataDirectiveGASM(uint32 size); // Write DB, etc., MASM syntax
void WriteDataComment(uint32 ElementSize, uint32 LinePos, uint32 Pos, uint32 irel);// Write comment after data item
uint32 GetDataItemSize(uint32 Type); // Get size of data item with specified type
uint32 GetDataElementSize(uint32 Type); // Get size of vector element in data item with specified type
int32 GetSegmentRegisterFromPrefix(); // Translate segment prefix to segment register
template <class TX> TX & Get(uint32 Offset) { // Get object of arbitrary type from buffer
return *(TX*)(Buffer + Offset);}
};
// Declare tables in opcodes.cpp:
extern SOpcodeDef OpcodeMap0[256]; // First opcode map
extern uint32 OpcodeStartPageVEX[]; // Entries to opcode maps, indexed by VEX.mmmm bits
extern SOpcodeDef const * OpcodeStartPageXOP[]; // Entries to opcode maps, indexed by XOP.mmmm bits
extern const uint32 NumOpcodeStartPageVEX; // Number of entries in OpcodeStartPage
extern const uint32 NumOpcodeStartPageXOP; // Number of entries in OpcodeStartPageXOP
extern const SOpcodeDef * const OpcodeTables[]; // Pointers to all opcode tables
extern const uint32 OpcodeTableLength[]; // Size of each table pointed to by OpcodeTables[]
extern const uint32 NumOpcodeTables1, NumOpcodeTables2;// Number of entries in OpcodeTables[] and OpcodeTableLength[]
extern const char * RegisterNames8[8]; // Names of 8 bit registers
extern const char * RegisterNames8x[16]; // Names of 8 bit registers with REX prefix
extern const char * RegisterNames16[16]; // Names of 16 bit registers
extern const char * RegisterNames32[16]; // Names of 32 bit registers
extern const char * RegisterNames64[16]; // Names of 64 bit registers
extern const char * RegisterNamesSeg[8]; // Names of segment registers
extern const char * RegisterNamesCR[16]; // Names of control registers
extern SwizSpec const * SwizTables[][2]; // Pointers to swizzle tables
extern SwizSpec const * SwizRoundTables[][2]; // Pointers to swizzle round tables
extern const char * EVEXRoundingNames[5]; // Tables of rounding mode names for EVEX
// Define constants for special section/segment/group values
#define ASM_SEGMENT_UNKNOWN 0 // Unknown segment for external symbols
#define ASM_SEGMENT_ABSOLUTE -1 // No segment for absolute public symbols
#define ASM_SEGMENT_FLAT -2 // Flat segment group for non-segmented code
#define ASM_SEGMENT_NOTHING -3 // Segment register assumed to nothing by assume directive
#define ASM_SEGMENT_ERROR -4 // Segment register assumed to error (don't use) by assume directive
#define ASM_SEGMENT_IMGREL -16 // Offset is relative to image base or file base,
// ..leave it to the disassembler to find which section contains this address.
// Values > 0 are indices into the Sections buffer representing a named section, segment or group
#endif // #ifndef DISASM_H

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,574 @@
/**************************** elf.cpp *********************************
* Author: Agner Fog
* Date created: 2006-07-18
* Last modified: 2017-10-18
* Project: objconv
* Module: elf.cpp
* Description:
* Module for reading ELF files
*
* Class CELF is used for reading, interpreting and dumping ELF files.
*
* Copyright 2006-2017 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.
// File class names
SIntTxt ELFFileClassNames[] = {
{ELFCLASSNONE, "None"},
{ELFCLASS32, "32-bit object"},
{ELFCLASS64, "64-bit object"}
};
// Data encoding names
SIntTxt ELFDataEncodeNames[] = {
{ELFDATANONE, "None"},
{ELFDATA2LSB, "Little Endian"},
{ELFDATA2MSB, "Big Endian"}
};
// ABI names
SIntTxt ELFABINames[] = {
{ELFOSABI_SYSV, "System V"},
{ELFOSABI_HPUX, "HP-UX"},
{ELFOSABI_ARM, "ARM"},
{ELFOSABI_STANDALONE,"Embedded"},
};
// File type names
SIntTxt ELFFileTypeNames[] = {
{ET_NONE, "None"},
{ET_REL, "Relocatable"},
{ET_EXEC, "Executable"},
{ET_DYN, "Shared object"},
{ET_CORE, "Core file"}
};
// Section type names
SIntTxt ELFSectionTypeNames[] = {
{SHT_NULL, "None"},
{SHT_PROGBITS, "Program data"},
{SHT_SYMTAB, "Symbol table"},
{SHT_STRTAB, "String table"},
{SHT_RELA, "Relocation w addends"},
{SHT_HASH, "Symbol hash table"},
{SHT_DYNAMIC, "Dynamic linking info"},
{SHT_NOTE, "Notes"},
{SHT_NOBITS, "bss"},
{SHT_REL, "Relocation entries"},
{SHT_SHLIB, "Reserved"},
{SHT_DYNSYM, "Dynamic linker symbol table"},
{SHT_INIT_ARRAY, "Array of constructors"},
{SHT_FINI_ARRAY, "Array of destructors"},
{SHT_PREINIT_ARRAY, "Array of pre-constructors"},
{SHT_GROUP, "Section group"},
{SHT_SYMTAB_SHNDX, "Extended section indices"}
};
// Section flag names
SIntTxt ELFSectionFlagNames[] = {
{SHF_WRITE, "Writeable"},
{SHF_ALLOC, "Allocate"},
{SHF_EXECINSTR, "Executable"},
{SHF_MERGE, "Merge"},
{SHF_STRINGS, "Strings"},
{SHF_INFO_LINK, "sh_info"},
{SHF_LINK_ORDER, "Preserve order"},
{SHF_OS_NONCONFORMING,"OS specific"}
};
// Symbol binding names
SIntTxt ELFSymbolBindingNames[] = {
{STB_LOCAL, "Local"},
{STB_GLOBAL, "Global"},
{STB_WEAK, "Weak"}
};
// Symbol Type names
SIntTxt ELFSymbolTypeNames[] = {
{STT_NOTYPE, "None"},
{STT_OBJECT, "Object"},
{STT_FUNC, "Function"},
{STT_SECTION, "Section"},
{STT_FILE, "File"},
{STT_COMMON, "Common"},
{STT_GNU_IFUNC, "Indirect function/dispatcher"}
};
// Relocation type names x86 32 bit
SIntTxt ELF32RelocationNames[] = {
{R_386_NONE, "None"},
{R_386_32, "Absolute 32 bit"},
{R_386_PC32, "Self-relative 32 bit"},
{R_386_GOT32, "32 bit GOT entry"},
{R_386_PLT32, "32 bit PLT address"},
{R_386_COPY, "Copy symbol at runtime"},
{R_386_GLOB_DAT, "Create GOT entry"},
{R_386_JMP_SLOT, "Create PLT entry"},
{R_386_RELATIVE, "Adjust by image base"},
{R_386_GOTOFF, "32 bit offset to GOT"},
{R_386_GOTPC, "32 bit PC relative offset to GOT"},
{R_386_IRELATIVE, "32 bit ref. to indirect function PLT"}
};
// Relocation type names x86 64 bit
SIntTxt ELF64RelocationNames[] = {
{R_X86_64_NONE, "None"},
{R_X86_64_64, "Direct 64 bit"},
{R_X86_64_PC32, "Self relative 32 bit signed"},
{R_X86_64_GOT32, "32 bit GOT entry"},
{R_X86_64_PLT32, "32 bit PLT address"},
{R_X86_64_COPY, "Copy symbol at runtime"},
{R_X86_64_GLOB_DAT, "Create GOT entry"},
{R_X86_64_JUMP_SLOT, "Create PLT entry"},
{R_X86_64_RELATIVE, "Adjust by program base"},
{R_X86_64_GOTPCREL, "32 bit signed pc relative offset to GOT"},
{R_X86_64_32, "Direct 32 bit zero extended"},
{R_X86_64_32S, "Direct 32 bit sign extended"},
{R_X86_64_16, "Direct 16 bit zero extended"},
{R_X86_64_PC16, "16 bit sign extended pc relative"},
{R_X86_64_8, "Direct 8 bit sign extended"},
{R_X86_64_PC8, "8 bit sign extended pc relative"},
{R_X86_64_IRELATIVE, "32 bit ref. to indirect function PLT"}
};
// Machine names
SIntTxt ELFMachineNames[] = {
{EM_NONE, "None"}, // No machine
{EM_M32, "AT&T WE 32100"},
{EM_SPARC, "SPARC"},
{EM_386, "Intel x86"},
{EM_68K, "Motorola m68k"},
{EM_88K, "Motorola m88k"},
{EM_860, "MIPS R3000 big-endian"},
{EM_MIPS, "MIPS R3000 big-endian"},
{EM_S370, "IBM System/370"},
{EM_MIPS_RS3_LE, "NMIPS R3000 little-endianone"},
{EM_PARISC, "HPPA"},
{EM_VPP500, "Fujitsu VPP500"},
{EM_SPARC32PLUS, "Sun v8plus"},
{EM_960, "Intel 80960"},
{EM_PPC, "PowerPC"},
{EM_PPC64, "PowerPC 64-bit"},
{EM_S390, "IBM S390"},
{EM_V800, "NEC V800"},
{EM_FR20, "Fujitsu FR20"},
{EM_RH32, "TRW RH-32"},
{EM_RCE, "Motorola RCE"},
{EM_ARM, "ARM"},
{EM_FAKE_ALPHA, "Digital Alpha"},
{EM_SH, "Hitachi SH"},
{EM_SPARCV9, "SPARC v9 64-bit"},
{EM_TRICORE, "Siemens Tricore"},
{EM_ARC, "Argonaut RISC"},
{EM_H8_300, "Hitachi H8/300"},
{EM_H8_300H, "Hitachi H8/300H"},
{EM_H8S, "Hitachi H8S"},
{EM_H8_500, "EM_H8_500"},
{EM_IA_64, "Intel IA64"},
{EM_MIPS_X, "Stanford MIPS-X"},
{EM_COLDFIRE, "Motorola Coldfire"},
{EM_68HC12, "Motorola M68HC12"},
{EM_MMA, "Fujitsu MMA"},
{EM_PCP, "Siemens PCP"},
{EM_NCPU, "Sony nCPU"},
{EM_NDR1, "Denso NDR1"},
{EM_STARCORE, "Motorola Start*Core"},
{EM_ME16, "Toyota ME16"},
{EM_ST100, "ST100"},
{EM_TINYJ, "Tinyj"},
{EM_X86_64, "x86-64"},
{EM_PDSP, "Sony DSP"},
{EM_FX66, "Siemens FX66"},
{EM_ST9PLUS, "ST9+ 8/16"},
{EM_ST7, "ST7 8"},
{EM_68HC16, "MC68HC16"},
{EM_68HC11, "MC68HC11"},
{EM_68HC08, "MC68HC08"},
{EM_68HC05, "MC68HC05"},
{EM_SVX, "SVx"},
{EM_AT19, "ST19"},
{EM_VAX, "VAX"},
{EM_CRIS, "Axis"},
{EM_JAVELIN, "Infineon"},
{EM_FIREPATH, "Element 14"},
{EM_ZSP, "LSI Logic"},
{EM_HUANY, "Harvard"},
{EM_PRISM, "SiTera Prism"},
{EM_AVR, "Atmel AVR"},
{EM_FR30, "FR30"},
{EM_D10V, "D10V"},
{EM_D30V, "D30V"},
{EM_V850, "NEC v850"},
{EM_M32R, "M32R"},
{EM_MN10300, "MN10300"},
{EM_MN10200, "MN10200"},
{EM_PJ, "picoJava"},
{EM_ALPHA, "Alpha"}
};
// Program header type names
SIntTxt ELFPTypeNames[] = {
{PT_NULL, "Unused"},
{PT_LOAD, "Loadable program segment"},
{PT_DYNAMIC, "Dynamic linking information"},
{PT_INTERP, "Program interpreter"},
{PT_NOTE, "Auxiliary information"},
{PT_SHLIB, "Reserved"},
{PT_PHDR, "Entry for header table itself"}
};
// Class CELF members:
// Constructor
template <class TELF_Header, class TELF_SectionHeader, class TELF_Symbol, class TELF_Relocation>
CELF<ELFSTRUCTURES>::CELF() {
memset(this, 0, sizeof(*this));
}
// ParseFile
template <class TELF_Header, class TELF_SectionHeader, class TELF_Symbol, class TELF_Relocation>
void CELF<ELFSTRUCTURES>::ParseFile(){
// Load and parse file buffer
uint32 i;
FileHeader = *(TELF_Header*)Buf(); // Copy file header
NSections = FileHeader.e_shnum;
SectionHeaders.SetNum(NSections); // Allocate space for section headers
SectionHeaders.SetZero();
uint32 Symtabi = 0; // Index to symbol table
// check header integrity
if (FileHeader.e_phoff > GetDataSize() || FileHeader.e_phoff + FileHeader.e_phentsize > GetDataSize()) err.submit(2035);
if (FileHeader.e_shoff > GetDataSize() || FileHeader.e_shoff + FileHeader.e_shentsize > GetDataSize()) err.submit(2035);
// Find section headers
SectionHeaderSize = FileHeader.e_shentsize;
if (SectionHeaderSize <= 0) err.submit(2033);
uint32 SectionOffset = uint32(FileHeader.e_shoff);
for (i = 0; i < NSections; i++) {
SectionHeaders[i] = Get<TELF_SectionHeader>(SectionOffset);
// check section header integrity
if (SectionHeaders[i].sh_type != SHT_NOBITS && (SectionHeaders[i].sh_offset > GetDataSize()
|| SectionHeaders[i].sh_offset + SectionHeaders[i].sh_size > GetDataSize()
|| SectionHeaders[i].sh_offset + SectionHeaders[i].sh_entsize > GetDataSize())) {
err.submit(2035);
}
SectionOffset += SectionHeaderSize;
if (SectionHeaders[i].sh_type == SHT_SYMTAB) {
// Symbol table found
Symtabi = i;
}
}
// if (Buf() && GetNumEntries()) {
if (Buf() && GetDataSize()) {
SecStringTable = Buf() + uint32(SectionHeaders[FileHeader.e_shstrndx].sh_offset);
SecStringTableLen = uint32(SectionHeaders[FileHeader.e_shstrndx].sh_size);
}
if (SectionOffset > GetDataSize()) {
err.submit(2110); // Section table points to outside file
}
if (Symtabi) {
// Save offset to symbol table
SymbolTableOffset = (uint32)(SectionHeaders[Symtabi].sh_offset);
SymbolTableEntrySize = (uint32)(SectionHeaders[Symtabi].sh_entsize); // Entry size of symbol table
if (SymbolTableEntrySize == 0) {err.submit(2034); return;} // Avoid division by zero
SymbolTableEntries = uint32(SectionHeaders[Symtabi].sh_size) / SymbolTableEntrySize;
// Find associated string table
uint32 Stringtabi = SectionHeaders[Symtabi].sh_link;
if (Stringtabi < NSections) {
SymbolStringTableOffset = (uint32)(SectionHeaders[Stringtabi].sh_offset);
SymbolStringTableSize = (uint32)(SectionHeaders[Stringtabi].sh_size);
}
else {
Symtabi = 0; // Error
}
}
}
// Dump
template <class TELF_Header, class TELF_SectionHeader, class TELF_Symbol, class TELF_Relocation>
void CELF<ELFSTRUCTURES>::Dump(int options) {
uint32 i;
if (options & DUMP_FILEHDR) {
// File header
printf("\nDump of ELF file %s", FileName);
printf("\n-----------------------------------------------");
printf("\nFile size: %i", GetDataSize());
printf("\nFile header:");
printf("\nFile class: %s, Data encoding: %s, ELF version %i, ABI: %s, ABI version %i",
Lookup(ELFFileClassNames, FileHeader.e_ident[EI_CLASS]),
Lookup(ELFDataEncodeNames, FileHeader.e_ident[EI_DATA]),
FileHeader.e_ident[EI_VERSION],
Lookup(ELFABINames, FileHeader.e_ident[EI_OSABI]),
FileHeader.e_ident[EI_ABIVERSION]);
printf("\nFile type: %s, Machine: %s, version: %i",
Lookup(ELFFileTypeNames, FileHeader.e_type),
Lookup(ELFMachineNames, FileHeader.e_machine),
FileHeader.e_version);
printf("\nNumber of sections: %2i, Processor flags: 0x%X",
NSections, FileHeader.e_flags);
}
if ((options & DUMP_SECTHDR) && FileHeader.e_phnum) {
// Dump program headers
uint32 nProgramHeaders = FileHeader.e_phnum;
uint32 programHeaderSize = FileHeader.e_phentsize;
if (programHeaderSize <= 0) err.submit(2033);
uint32 programHeaderOffset = (uint32)FileHeader.e_phoff;
Elf64_Phdr pHeader;
for (i = 0; i < nProgramHeaders; i++) {
if (WordSize == 32) {
Elf32_Phdr pHeader32 = Get<Elf32_Phdr>(programHeaderOffset);
pHeader.p_type = pHeader32.p_type;
pHeader.p_offset = pHeader32.p_offset;
pHeader.p_vaddr = pHeader32.p_vaddr;
pHeader.p_paddr = pHeader32.p_paddr;
pHeader.p_filesz = pHeader32.p_filesz;
pHeader.p_memsz = pHeader32.p_memsz;
pHeader.p_flags = pHeader32.p_flags;
pHeader.p_align = pHeader32.p_align;
}
else {
pHeader = Get<Elf64_Phdr>(programHeaderOffset);
}
printf("\nProgram header Type: %s, flags 0x%X",
Lookup(ELFPTypeNames, (uint32)pHeader.p_type), (uint32)pHeader.p_flags);
printf("\noffset = 0x%X, vaddr = 0x%X, paddr = 0x%X, filesize = 0x%X, memsize = 0x%X, align = 0x%X",
(uint32)pHeader.p_offset, (uint32)pHeader.p_vaddr, (uint32)pHeader.p_paddr, (uint32)pHeader.p_filesz, (uint32)pHeader.p_memsz, (uint32)pHeader.p_align);
programHeaderOffset += programHeaderSize;
if (pHeader.p_filesz < 0x100 && (int32)pHeader.p_offset < GetDataSize() && memchr(Buf()+pHeader.p_offset, 0, (uint32)pHeader.p_filesz)) {
printf("\nContents: %s", Buf()+(int32)pHeader.p_offset);
}
}
}
if (options & DUMP_SECTHDR) {
// Dump section headers
printf("\n\nSection headers:");
for (uint32 sc = 0; sc < NSections; sc++) {
// Get copy of 32-bit header or converted 64-bit header
TELF_SectionHeader sheader = SectionHeaders[sc];
uint32 entrysize = (uint32)(sheader.sh_entsize);
uint32 namei = sheader.sh_name;
if (namei >= SecStringTableLen) {err.submit(2112); break;}
printf("\n%2i Name: %-18s Type: %s", sc, SecStringTable + namei,
Lookup(ELFSectionTypeNames, sheader.sh_type));
if (sheader.sh_flags) {
printf("\n Flags: 0x%X:", uint32(sheader.sh_flags));
for (int fi = 1; fi < (1 << 30); fi <<= 1) {
if (uint32(sheader.sh_flags) & fi) {
printf(" %s", Lookup(ELFSectionFlagNames,fi));
}
}
}
if (sheader.sh_addr) {
printf("\n Address: 0x%X", uint32(sheader.sh_addr));
}
if (sheader.sh_offset || sheader.sh_size) {
printf("\n FileOffset: 0x%X, Size: 0x%X",
uint32(sheader.sh_offset), uint32(sheader.sh_size));
}
if (sheader.sh_addralign) {
printf("\n Alignment: 0x%X", uint32(sheader.sh_addralign));
}
if (sheader.sh_entsize) {
printf("\n Entry size: 0x%X", uint32(sheader.sh_entsize));
switch (sheader.sh_type) {
case SHT_DYNAMIC:
printf("\n String table: %i", sheader.sh_link);
break;
case SHT_HASH:
printf("\n Symbol table: %i", sheader.sh_link);
break;
case SHT_REL: case SHT_RELA:
printf("\n Symbol table: %i, Reloc. section: %i",
sheader.sh_link, sheader.sh_info);
break;
case SHT_SYMTAB: case SHT_DYNSYM:
printf("\n Symbol string table: %i, First global symbol: %i",
sheader.sh_link, sheader.sh_info);
break;
default:
if (sheader.sh_link) {
printf("\n Link: %i", sheader.sh_link);
}
if (sheader.sh_info) {
printf("\n Info: %i", sheader.sh_info);
}
}
}
if (sheader.sh_type == SHT_STRTAB && (options & DUMP_STRINGTB)) {
// Print string table
printf("\n String table:");
char * p = Buf() + uint32(sheader.sh_offset) + 1;
uint32 nread = 1, len;
while (nread < uint32(sheader.sh_size)) {
len = (uint32)strlen(p);
printf(" >>%s<<", p);
nread += len + 1;
p += len + 1;
}
}
if ((sheader.sh_type==SHT_SYMTAB || sheader.sh_type==SHT_DYNSYM) && (options & DUMP_SYMTAB)) {
// Dump symbol table
// Find associated string table
if (sheader.sh_link >= (uint32)NSections) {err.submit(2035); sheader.sh_link = 0;}
int8 * strtab = Buf() + uint32(SectionHeaders[sheader.sh_link].sh_offset);
// Find symbol table
uint32 symtabsize = (uint32)(sheader.sh_size);
int8 * symtab = Buf() + uint32(sheader.sh_offset);
int8 * symtabend = symtab + symtabsize;
if (entrysize < sizeof(TELF_Symbol)) {err.submit(2033); entrysize = sizeof(TELF_Symbol);}
printf("\n Symbols:");
// Loop through symbol table
int symi; // Symbol number
for (symi = 0; symtab < symtabend; symtab += entrysize, symi++) {
// Copy 32 bit symbol table entry or convert 64 bit entry
TELF_Symbol sym = *(TELF_Symbol*)symtab;
int type = sym.st_type;
int binding = sym.st_bind;
if (*(strtab + sym.st_name)) {
printf("\n %2i Name: %s,", symi, strtab + sym.st_name);}
else {
printf("\n %2i Unnamed,", symi);}
if (sym.st_value || type == STT_OBJECT || type == STT_FUNC || type == STT_GNU_IFUNC || int16(sym.st_shndx) < 0)
printf(" Value: 0x%X", uint32(sym.st_value));
if (sym.st_size) printf(" Size: %i", uint32(sym.st_size));
if (sym.st_other) printf(" Other: 0x%X", sym.st_other);
if (int16(sym.st_shndx) >= 0) printf(" Section: %i", sym.st_shndx);
else { // Special segment values
switch (int16(sym.st_shndx)) {
case SHN_ABS:
printf(" Absolute,"); break;
case SHN_COMMON:
printf(" Common,"); break;
case SHN_XINDEX:
printf(" Index in extra table,"); break;
default:
printf(" Section: 0x%X", sym.st_shndx);
}
}
if (sym.st_type || sym.st_bind) {
printf(" Type: %s, Binding: %s",
Lookup(ELFSymbolTypeNames, type),
Lookup(ELFSymbolBindingNames, binding));
}
}
}
if ((sheader.sh_type==SHT_REL || sheader.sh_type==SHT_RELA ) && (options & DUMP_RELTAB)) {
printf("\n Relocations:");
int8 * reltab = Buf() + uint32(sheader.sh_offset);
int8 * reltabend = reltab + uint32(sheader.sh_size);
uint32 expectedentrysize = sheader.sh_type == SHT_RELA ?
sizeof(TELF_Relocation) : // Elf32_Rela, Elf64_Rela
sizeof(TELF_Relocation) - WordSize/8; // Elf32_Rel, Elf64_Rel
if (entrysize < expectedentrysize) {err.submit(2033); entrysize = expectedentrysize;}
// Loop through entries
for (; reltab < reltabend; reltab += entrysize) {
// Copy relocation table entry with or without addend
TELF_Relocation rel; rel.r_addend = 0;
memcpy(&rel, reltab, entrysize);
printf ("\n Offset: 0x%X, Symbol: %i, Name: %s\n Type: %s",
uint32(rel.r_offset), rel.r_sym, SymbolName(rel.r_sym),
(WordSize == 32) ?
Lookup (ELF32RelocationNames, rel.r_type) :
Lookup (ELF64RelocationNames, rel.r_type));
if (rel.r_addend) printf (", Addend: 0x%X", uint32(rel.r_addend));
// Find inline addend
TELF_SectionHeader relsheader = SectionHeaders[sheader.sh_info];
uint32 relsoffset = uint32(relsheader.sh_offset);
if (relsoffset+rel.r_offset < GetDataSize()) {
int32 * piaddend = (int32*)(Buf()+relsoffset+rel.r_offset);
if (* piaddend) printf (", Inline addend: 0x%X", * piaddend);
}
}
}
}
}
}
// PublicNames
template <class TELF_Header, class TELF_SectionHeader, class TELF_Symbol, class TELF_Relocation>
void CELF<ELFSTRUCTURES>::PublicNames(CMemoryBuffer * Strings, CSList<SStringEntry> * Index, int m) {
// Make list of public names
// Interpret header:
ParseFile();
// Loop through section headers
for (uint32 sc = 0; sc < NSections; sc++) {
// Get copy of 32-bit header or converted 64-bit header
TELF_SectionHeader sheader = SectionHeaders[sc];
uint32 entrysize = uint32(sheader.sh_entsize);
if (sheader.sh_type==SHT_SYMTAB || sheader.sh_type==SHT_DYNSYM) {
// Dump symbol table
// Find associated string table
if (sheader.sh_link >= (uint32)NSections) {err.submit(2035); sheader.sh_link = 0;}
int8 * strtab = Buf() + uint32(SectionHeaders[sheader.sh_link].sh_offset);
// Find symbol table
uint32 symtabsize = uint32(sheader.sh_size);
int8 * symtab = Buf() + uint32(sheader.sh_offset);
int8 * symtabend = symtab + symtabsize;
if (entrysize < sizeof(TELF_Symbol)) {err.submit(2033); entrysize = sizeof(TELF_Symbol);}
// Loop through symbol table
for (int symi = 0; symtab < symtabend; symtab += entrysize, symi++) {
// Copy 32 bit symbol table entry or convert 64 bit entry
TELF_Symbol sym = *(TELF_Symbol*)symtab;
int type = sym.st_type;
int binding = sym.st_bind;
if (int16(sym.st_shndx) > 0
&& type != STT_SECTION && type != STT_FILE
&& (binding == STB_GLOBAL || binding == STB_WEAK)) {
// Public symbol found
SStringEntry se;
se.Member = m;
// Store name
se.String = Strings->PushString(strtab + sym.st_name);
// Store name index
Index->Push(se);
}
}
}
}
}
// SymbolName
template <class TELF_Header, class TELF_SectionHeader, class TELF_Symbol, class TELF_Relocation>
const char * CELF<ELFSTRUCTURES>::SymbolName(uint32 index) {
// Get name of symbol. (ParseFile() must be called first)
const char * symname = "?"; // Symbol name
uint32 symi; // Symbol index
uint32 stri; // String index
if (SymbolTableOffset) {
symi = SymbolTableOffset + index * SymbolTableEntrySize;
if (symi < GetDataSize()) {
stri = Get<TELF_Symbol>(symi).st_name;
if (stri < SymbolStringTableSize) {
symname = Buf() + SymbolStringTableOffset + stri;
}
}
}
return symname;
}
// Make template instances for 32 and 64 bits
template class CELF<ELF32STRUCTURES>;
template class CELF<ELF64STRUCTURES>;

View File

@ -0,0 +1,853 @@
/**************************** elf.h ***********************************
* Author: Agner Fog
* Date created: 2006-07-18
* Last modified: 2009-07-15
* Project: objconv
* Module: elf.h
* Description:
* Header file for definition of structures in 32 and 64 bit ELF object file
* format.
*
* Copyright 2006-2009 GNU General Public License http://www.gnu.org/licenses
*****************************************************************************/
#ifndef ELF_H
#define ELF_H
/********************** FILE HEADER **********************/
struct Elf32_Ehdr {
uint8 e_ident[16]; // Magic number and other info
uint16 e_type; // Object file type
uint16 e_machine; // Architecture
uint32 e_version; // Object file version
uint32 e_entry; // Entry point virtual address
uint32 e_phoff; // Program header table file offset
uint32 e_shoff; // Section header table file offset
uint32 e_flags; // Processor-specific flags
uint16 e_ehsize; // ELF header size in bytes
uint16 e_phentsize; // Program header table entry size
uint16 e_phnum; // Program header table entry count
uint16 e_shentsize; // Section header table entry size
uint16 e_shnum; // Section header table entry count
uint16 e_shstrndx; // Section header string table index
};
struct Elf64_Ehdr {
uint8 e_ident[16]; // Magic number and other info
uint16 e_type; // Object file type
uint16 e_machine; // Architecture
uint32 e_version; // Object file version
uint64 e_entry; // Entry point virtual address
uint64 e_phoff; // Program header table file offset
uint64 e_shoff; // Section header table file offset
uint32 e_flags; // Processor-specific flags
uint16 e_ehsize; // ELF header size in bytes
uint16 e_phentsize; // Program header table entry size
uint16 e_phnum; // Program header table entry count
uint16 e_shentsize; // Section header table entry size
uint16 e_shnum; // Section header table entry count
uint16 e_shstrndx; // Section header string table index
};
/* Fields in the e_ident array. The EI_* macros are indices into the
array. The macros under each EI_* macro are the values the byte
may have. */
/* Conglomeration of the identification bytes, for easy testing as a word. */
#define ELFMAG "\177ELF"
#define EI_CLASS 4 /* File class byte index */
#define ELFCLASSNONE 0 /* Invalid class */
#define ELFCLASS32 1 /* 32-bit objects */
#define ELFCLASS64 2 /* 64-bit objects */
#define ELFCLASSNUM 3
#define EI_DATA 5 /* Data encoding byte index */
#define ELFDATANONE 0 /* Invalid data encoding */
#define ELFDATA2LSB 1 /* 2's complement, little endian */
#define ELFDATA2MSB 2 /* 2's complement, big endian */
#define ELFDATANUM 3
#define EI_VERSION 6 /* File version byte index */
/* Value must be EV_CURRENT */
#define EI_OSABI 7 /* OS ABI identification */
#define ELFOSABI_SYSV 0 /* UNIX System V ABI */
#define ELFOSABI_HPUX 1 /* HP-UX */
#define ELFOSABI_ARM 97 /* ARM */
#define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */
#define EI_ABIVERSION 8 /* ABI version */
#define EI_PAD 9 /* Byte index of padding bytes */
/* Legal values for e_type (object file type). */
#define ET_NONE 0 /* No file type */
#define ET_REL 1 /* Relocatable file */
#define ET_EXEC 2 /* Executable file */
#define ET_DYN 3 /* Shared object file */
#define ET_CORE 4 /* Core file */
#define ET_NUM 5 /* Number of defined types */
#define ET_LOOS 0xfe00 /* OS-specific range start */
#define ET_HIOS 0xfeff /* OS-specific range end */
#define ET_LOPROC 0xff00 /* Processor-specific range start */
#define ET_HIPROC 0xffff /* Processor-specific range end */
/* Legal values for e_machine (architecture). */
#define EM_NONE 0 /* No machine */
#define EM_M32 1 /* AT&T WE 32100 */
#define EM_SPARC 2 /* SUN SPARC */
#define EM_386 3 /* Intel 80386 */
#define EM_68K 4 /* Motorola m68k family */
#define EM_88K 5 /* Motorola m88k family */
#define EM_860 7 /* Intel 80860 */
#define EM_MIPS 8 /* MIPS R3000 big-endian */
#define EM_S370 9 /* IBM System/370 */
#define EM_MIPS_RS3_LE 10 /* MIPS R3000 little-endian */
#define EM_PARISC 15 /* HPPA */
#define EM_VPP500 17 /* Fujitsu VPP500 */
#define EM_SPARC32PLUS 18 /* Sun's "v8plus" */
#define EM_960 19 /* Intel 80960 */
#define EM_PPC 20 /* PowerPC */
#define EM_PPC64 21 /* PowerPC 64-bit */
#define EM_S390 22 /* IBM S390 */
#define EM_V800 36 /* NEC V800 series */
#define EM_FR20 37 /* Fujitsu FR20 */
#define EM_RH32 38 /* TRW RH-32 */
#define EM_RCE 39 /* Motorola RCE */
#define EM_ARM 40 /* ARM */
#define EM_FAKE_ALPHA 41 /* Digital Alpha */
#define EM_SH 42 /* Hitachi SH */
#define EM_SPARCV9 43 /* SPARC v9 64-bit */
#define EM_TRICORE 44 /* Siemens Tricore */
#define EM_ARC 45 /* Argonaut RISC Core */
#define EM_H8_300 46 /* Hitachi H8/300 */
#define EM_H8_300H 47 /* Hitachi H8/300H */
#define EM_H8S 48 /* Hitachi H8S */
#define EM_H8_500 49 /* Hitachi H8/500 */
#define EM_IA_64 50 /* Intel Merced */
#define EM_MIPS_X 51 /* Stanford MIPS-X */
#define EM_COLDFIRE 52 /* Motorola Coldfire */
#define EM_68HC12 53 /* Motorola M68HC12 */
#define EM_MMA 54 /* Fujitsu MMA Multimedia Accelerator*/
#define EM_PCP 55 /* Siemens PCP */
#define EM_NCPU 56 /* Sony nCPU embeeded RISC */
#define EM_NDR1 57 /* Denso NDR1 microprocessor */
#define EM_STARCORE 58 /* Motorola Start*Core processor */
#define EM_ME16 59 /* Toyota ME16 processor */
#define EM_ST100 60 /* STMicroelectronic ST100 processor */
#define EM_TINYJ 61 /* Advanced Logic Corp. Tinyj emb.fam*/
#define EM_X86_64 62 /* AMD x86-64 architecture */
#define EM_PDSP 63 /* Sony DSP Processor */
#define EM_FX66 66 /* Siemens FX66 microcontroller */
#define EM_ST9PLUS 67 /* STMicroelectronics ST9+ 8/16 mc */
#define EM_ST7 68 /* STmicroelectronics ST7 8 bit mc */
#define EM_68HC16 69 /* Motorola MC68HC16 microcontroller */
#define EM_68HC11 70 /* Motorola MC68HC11 microcontroller */
#define EM_68HC08 71 /* Motorola MC68HC08 microcontroller */
#define EM_68HC05 72 /* Motorola MC68HC05 microcontroller */
#define EM_SVX 73 /* Silicon Graphics SVx */
#define EM_AT19 74 /* STMicroelectronics ST19 8 bit mc */
#define EM_VAX 75 /* Digital VAX */
#define EM_CRIS 76 /* Axis Communications 32-bit embedded processor */
#define EM_JAVELIN 77 /* Infineon Technologies 32-bit embedded processor */
#define EM_FIREPATH 78 /* Element 14 64-bit DSP Processor */
#define EM_ZSP 79 /* LSI Logic 16-bit DSP Processor */
#define EM_MMIX 80 /* Donald Knuth's educational 64-bit processor */
#define EM_HUANY 81 /* Harvard University machine-independent object files */
#define EM_PRISM 82 /* SiTera Prism */
#define EM_AVR 83 /* Atmel AVR 8-bit microcontroller */
#define EM_FR30 84 /* Fujitsu FR30 */
#define EM_D10V 85 /* Mitsubishi D10V */
#define EM_D30V 86 /* Mitsubishi D30V */
#define EM_V850 87 /* NEC v850 */
#define EM_M32R 88 /* Mitsubishi M32R */
#define EM_MN10300 89 /* Matsushita MN10300 */
#define EM_MN10200 90 /* Matsushita MN10200 */
#define EM_PJ 91 /* picoJava */
#define EM_NUM 92
#define EM_ALPHA 0x9026
/* Legal values for e_version (version). */
#define EV_NONE 0 /* Invalid ELF version */
#define EV_CURRENT 1 /* Current version */
#define EV_NUM 2
/* Section header. */
struct Elf32_Shdr {
uint32 sh_name; // Section name (string tbl index)
uint32 sh_type; // Section type
uint32 sh_flags; // Section flags
uint32 sh_addr; // Section virtual addr at execution
uint32 sh_offset; // Section file offset
uint32 sh_size; // Section size in bytes
uint32 sh_link; // Link to another section
uint32 sh_info; // Additional section information
uint32 sh_addralign; // Section alignment
uint32 sh_entsize; // Entry size if section holds table
};
struct Elf64_Shdr {
uint32 sh_name; // Section name (string tbl index)
uint32 sh_type; // Section type
uint64 sh_flags; // Section flags
uint64 sh_addr; // Section virtual addr at execution
uint64 sh_offset; // Section file offset
uint64 sh_size; // Section size in bytes
uint32 sh_link; // Link to another section
uint32 sh_info; // Additional section information
uint64 sh_addralign; // Section alignment
uint64 sh_entsize; // Entry size if section holds table
};
/* Special section indices. */
#define SHN_UNDEF 0 // Undefined section
#define SHN_LORESERVE ((int16)0xff00) // Start of reserved indices
#define SHN_LOPROC ((int16)0xff00) // Start of processor-specific
#define SHN_HIPROC ((int16)0xff1f) // End of processor-specific
#define SHN_LOOS ((int16)0xff20) // Start of OS-specific
#define SHN_HIOS ((int16)0xff3f) // End of OS-specific
#define SHN_ABS ((int16)0xfff1) // Associated symbol is absolute
#define SHN_COMMON ((int16)0xfff2) // Associated symbol is common
#define SHN_XINDEX ((int16)0xffff) // Index is in extra table
#define SHN_HIRESERVE ((int16)0xffff) // End of reserved indices
// Legal values for sh_type (section type).
#define SHT_NULL 0 // Section header table entry unused
#define SHT_PROGBITS 1 // Program data
#define SHT_SYMTAB 2 // Symbol table
#define SHT_STRTAB 3 // String table
#define SHT_RELA 4 // Relocation entries with addends. Warning: Works only in 64 bit mode in my tests!
#define SHT_HASH 5 // Symbol hash table
#define SHT_DYNAMIC 6 // Dynamic linking information
#define SHT_NOTE 7 // Notes
#define SHT_NOBITS 8 // Program space with no data (bss)
#define SHT_REL 9 // Relocation entries, no addends
#define SHT_SHLIB 10 // Reserved
#define SHT_DYNSYM 11 // Dynamic linker symbol table
#define SHT_INIT_ARRAY 14 // Array of constructors
#define SHT_FINI_ARRAY 15 // Array of destructors
#define SHT_PREINIT_ARRAY 16 // Array of pre-constructors
#define SHT_GROUP 17 // Section group
#define SHT_SYMTAB_SHNDX 18 // Extended section indeces
#define SHT_NUM 19 // Number of defined types.
#define SHT_LOOS 0x60000000 // Start OS-specific
#define SHT_CHECKSUM 0x6ffffff8 // Checksum for DSO content.
#define SHT_LOSUNW 0x6ffffffa // Sun-specific low bound.
#define SHT_SUNW_move 0x6ffffffa
#define SHT_SUNW_COMDAT 0x6ffffffb
#define SHT_SUNW_syminfo 0x6ffffffc
#define SHT_GNU_verdef 0x6ffffffd // Version definition section.
#define SHT_GNU_verneed 0x6ffffffe // Version needs section.
#define SHT_GNU_versym 0x6fffffff // Version symbol table.
#define SHT_HISUNW 0x6fffffff // Sun-specific high bound.
#define SHT_HIOS 0x6fffffff // End OS-specific type
#define SHT_LOPROC 0x70000000 // Start of processor-specific
#define SHT_HIPROC 0x7fffffff // End of processor-specific
#define SHT_LOUSER 0x80000000 // Start of application-specific
#define SHT_HIUSER 0x8fffffff // End of application-specific
#define SHT_REMOVE_ME 0xffffff99 // Specific to objconv program: Removed debug or exception handler section
// Legal values for sh_flags (section flags).
#define SHF_WRITE (1 << 0) // Writable
#define SHF_ALLOC (1 << 1) // Occupies memory during execution
#define SHF_EXECINSTR (1 << 2) // Executable
#define SHF_MERGE (1 << 4) // Might be merged
#define SHF_STRINGS (1 << 5) // Contains nul-terminated strings
#define SHF_INFO_LINK (1 << 6) // `sh_info' contains SHT index
#define SHF_LINK_ORDER (1 << 7) // Preserve order after combining
#define SHF_OS_NONCONFORMING (1 << 8) // Non-standard OS specific handling required
#define SHF_MASKOS 0x0ff00000 // OS-specific.
#define SHF_MASKPROC 0xf0000000 // Processor-specific
/* Section group handling. */
#define GRP_COMDAT 0x1 /* Mark group as COMDAT. */
/* Symbol table entry. */
struct Elf32_Sym {
uint32 st_name; // Symbol name (string tbl index)
uint32 st_value; // Symbol value
uint32 st_size; // Symbol size
uint8 st_type: 4, // Symbol type
st_bind: 4; // Symbol binding
uint8 st_other; // Symbol visibility
uint16 st_shndx; // Section index
};
struct Elf64_Sym {
uint32 st_name; // Symbol name (string tbl index)
uint8 st_type: 4, // Symbol type
st_bind: 4; // Symbol binding
uint8 st_other; // Symbol visibility
uint16 st_shndx; // Section index
uint64 st_value; // Symbol value
uint64 st_size; // Symbol size
};
/* The syminfo section if available contains additional information about
every dynamic symbol. */
struct Elf32_Syminfo {
uint16 si_boundto; /* Direct bindings, symbol bound to */
uint16 si_flags; /* Per symbol flags */
};
struct Elf64_Syminfo {
uint16 si_boundto; /* Direct bindings, symbol bound to */
uint16 si_flags; /* Per symbol flags */
};
/* Possible values for si_boundto. */
#define SYMINFO_BT_SELF 0xffff /* Symbol bound to self */
#define SYMINFO_BT_PARENT 0xfffe /* Symbol bound to parent */
#define SYMINFO_BT_LOWRESERVE 0xff00 /* Beginning of reserved entries */
/* Possible bitmasks for si_flags. */
#define SYMINFO_FLG_DIRECT 0x0001 /* Direct bound symbol */
#define SYMINFO_FLG_PASSTHRU 0x0002 /* Pass-thru symbol for translator */
#define SYMINFO_FLG_COPY 0x0004 /* Symbol is a copy-reloc */
#define SYMINFO_FLG_LAZYLOAD 0x0008 /* Symbol bound to object to be lazy loaded */
/* Syminfo version values. */
#define SYMINFO_NONE 0
#define SYMINFO_CURRENT 1
#define SYMINFO_NUM 2
/* Special section index. */
#define SHN_UNDEF 0 /* No section, undefined symbol. */
// How to extract and insert information held in the st_info field.
// Both Elf32_Sym and Elf64_Sym use the same one-byte st_info field.
//#define ELF32_ST_BIND(val) (((uint8) (val)) >> 4)
//#define ELF32_ST_TYPE(val) ((val) & 0xf)
//#define ELF32_ST_INFO(bind,type) (((bind) << 4) + ((type) & 0xf))
// Legal values for ST_BIND subfield of st_info (symbol binding).
#define STB_LOCAL 0 // Local symbol
#define STB_GLOBAL 1 // Global symbol
#define STB_WEAK 2 // Weak symbol
#define STB_NUM 3 // Number of defined types.
#define STB_LOOS 10 // Start of OS-specific
#define STB_HIOS 12 // End of OS-specific
#define STB_LOPROC 13 // Start of processor-specific
#define STB_HIPROC 15 // End of processor-specific
// Legal values for ST_TYPE subfield of st_info (symbol type).
#define STT_NOTYPE 0 // Symbol type is unspecified
#define STT_OBJECT 1 // Symbol is a data object
#define STT_FUNC 2 // Symbol is a code object
#define STT_SECTION 3 // Symbol associated with a section
#define STT_FILE 4 // Symbol's name is file name
#define STT_COMMON 5 // Symbol is a common data object
#define STT_NUM 6 // Number of defined types.
#define STT_LOOS 10 // Start of OS-specific
#define STT_GNU_IFUNC 10 // Symbol is an indirect code object (function dispatcher)
#define STT_HIOS 12 // End of OS-specific
#define STT_LOPROC 13 // Start of processor-specific
#define STT_HIPROC 15 // End of processor-specific
/* Symbol table indices are found in the hash buckets and chain table
of a symbol hash table section. This special index value indicates
the end of a chain, meaning no further symbols are found in that bucket. */
#define STN_UNDEF 0 /* End of a chain. */
/* How to extract and insert information held in the st_other field. */
#define ELF32_ST_VISIBILITY(o) ((o) & 0x03)
/* For ELF64 the definitions are the same. */
#define ELF64_ST_VISIBILITY(o) ELF32_ST_VISIBILITY (o)
/* Symbol visibility specification encoded in the st_other field. */
#define STV_DEFAULT 0 /* Default symbol visibility rules */
#define STV_INTERNAL 1 /* Processor specific hidden class */
#define STV_HIDDEN 2 /* Sym unavailable in other modules */
#define STV_PROTECTED 3 /* Not preemptible, not exported */
// Relocation table entry structures
// How to extract and insert information held in the r_info field.
//#define ELF32_R_SYM(val) ((val) >> 8)
//#define ELF32_R_TYPE(val) ((val) & 0xff)
//#define ELF32_R_INFO(sym,type) (((sym) << 8) + ((type) & 0xff))
//#define ELF64_R_SYM(i) ((uint32)((i) >> 32))
//#define ELF64_R_TYPE(i) ((i) & 0xffffffff)
//#define ELF64_R_INFO(sym,type) ((((uint64) (sym)) << 32) + (type))
// Relocation table entry without addend (in section of type SHT_REL)
struct Elf32_Rel {
uint32 r_offset; // Address
uint32 r_type: 8, // Relocation type
r_sym: 24; // Symbol index
};
struct Elf64_Rel {
uint64 r_offset; // Address
uint32 r_type; // Relocation type
uint32 r_sym; // Symbol index
};
// Relocation table entry with addend (in section of type SHT_RELA)
// Warning: Elf32_Rela doesn't work in any of the systems I have tried.
// Use Elf32_Rel instead with addend in relocated field.
// Use Elf64_Rela in 64 bit mode. Elf64_Rel not accepted?
struct Elf32_Rela {
uint32 r_offset; // Address
uint32 r_type: 8, // Relocation type
r_sym: 24; // Symbol index
int32 r_addend; // Addend
};
struct Elf64_Rela {
uint64 r_offset; // Address
uint32 r_type; // Relocation type
uint32 r_sym; // Symbol index
int64 r_addend; // Addend
};
// i386 Relocation types
#define R_386_NONE 0 // No reloc
#define R_386_32 1 // Direct 32 bit
#define R_386_PC32 2 // Self-relative 32 bit (not EIP relative in the sense used in COFF files)
#define R_386_GOT32 3 // 32 bit GOT entry
#define R_386_PLT32 4 // 32 bit PLT address
#define R_386_COPY 5 // Copy symbol at runtime
#define R_386_GLOB_DAT 6 // Create GOT entry
#define R_386_JMP_SLOT 7 // Create PLT entry
#define R_386_RELATIVE 8 // Adjust by program base
#define R_386_GOTOFF 9 // 32 bit offset to GOT
#define R_386_GOTPC 10 // 32 bit self relative offset to GOT
#define R_386_IRELATIVE 42 // Reference to PLT entry of indirect function (STT_GNU_IFUNC)
//#define R_386_NUM 11 // Number of entries
// AMD x86-64 relocation types
#define R_X86_64_NONE 0 // No reloc
#define R_X86_64_64 1 // Direct 64 bit
#define R_X86_64_PC32 2 // Self relative 32 bit signed (not RIP relative in the sense used in COFF files)
#define R_X86_64_GOT32 3 // 32 bit GOT entry
#define R_X86_64_PLT32 4 // 32 bit PLT address
#define R_X86_64_COPY 5 // Copy symbol at runtime
#define R_X86_64_GLOB_DAT 6 // Create GOT entry
#define R_X86_64_JUMP_SLOT 7 // Create PLT entry
#define R_X86_64_RELATIVE 8 // Adjust by program base
#define R_X86_64_GOTPCREL 9 // 32 bit signed self relative offset to GOT
#define R_X86_64_32 10 // Direct 32 bit zero extended
#define R_X86_64_32S 11 // Direct 32 bit sign extended
#define R_X86_64_16 12 // Direct 16 bit zero extended
#define R_X86_64_PC16 13 // 16 bit sign extended self relative
#define R_X86_64_8 14 // Direct 8 bit sign extended
#define R_X86_64_PC8 15 // 8 bit sign extended self relative
#define R_X86_64_IRELATIVE 37 // Reference to PLT entry of indirect function (STT_GNU_IFUNC)
//#define R_X86_64_NUM 16 // Number of entries
// Pseudo-record when ELF is used as intermediary between COFF and MachO:
#define R_UNSUPPORTED_IMAGEREL 21 // Image-relative not supported
// Program segment header.
struct Elf32_Phdr {
uint32 p_type; /* Segment type */
uint32 p_offset; /* Segment file offset */
uint32 p_vaddr; /* Segment virtual address */
uint32 p_paddr; /* Segment physical address */
uint32 p_filesz; /* Segment size in file */
uint32 p_memsz; /* Segment size in memory */
uint32 p_flags; /* Segment flags */
uint32 p_align; /* Segment alignment */
};
struct Elf64_Phdr {
uint32 p_type; /* Segment type */
uint32 p_flags; /* Segment flags */
uint64 p_offset; /* Segment file offset */
uint64 p_vaddr; /* Segment virtual address */
uint64 p_paddr; /* Segment physical address */
uint64 p_filesz; /* Segment size in file */
uint64 p_memsz; /* Segment size in memory */
uint64 p_align; /* Segment alignment */
};
/* Legal values for p_type (segment type). */
#define PT_NULL 0 /* Program header table entry unused */
#define PT_LOAD 1 /* Loadable program segment */
#define PT_DYNAMIC 2 /* Dynamic linking information */
#define PT_INTERP 3 /* Program interpreter */
#define PT_NOTE 4 /* Auxiliary information */
#define PT_SHLIB 5 /* Reserved */
#define PT_PHDR 6 /* Entry for header table itself */
#define PT_NUM 7 /* Number of defined types */
#define PT_LOOS 0x60000000 /* Start of OS-specific */
#define PT_HIOS 0x6fffffff /* End of OS-specific */
#define PT_LOPROC 0x70000000 /* Start of processor-specific */
#define PT_HIPROC 0x7fffffff /* End of processor-specific */
/* Legal values for p_flags (segment flags). */
#define PF_X (1 << 0) /* Segment is executable */
#define PF_W (1 << 1) /* Segment is writable */
#define PF_R (1 << 2) /* Segment is readable */
#define PF_MASKOS 0x0ff00000 /* OS-specific */
#define PF_MASKPROC 0xf0000000 /* Processor-specific */
/* Legal values for note segment descriptor types for core files. */
#define NT_PRSTATUS 1 /* Contains copy of prstatus struct */
#define NT_FPREGSET 2 /* Contains copy of fpregset struct */
#define NT_PRPSINFO 3 /* Contains copy of prpsinfo struct */
#define NT_PRXREG 4 /* Contains copy of prxregset struct */
#define NT_PLATFORM 5 /* String from sysinfo(SI_PLATFORM) */
#define NT_AUXV 6 /* Contains copy of auxv array */
#define NT_GWINDOWS 7 /* Contains copy of gwindows struct */
#define NT_PSTATUS 10 /* Contains copy of pstatus struct */
#define NT_PSINFO 13 /* Contains copy of psinfo struct */
#define NT_PRCRED 14 /* Contains copy of prcred struct */
#define NT_UTSNAME 15 /* Contains copy of utsname struct */
#define NT_LWPSTATUS 16 /* Contains copy of lwpstatus struct */
#define NT_LWPSINFO 17 /* Contains copy of lwpinfo struct */
#define NT_PRFPXREG 20 /* Contains copy of fprxregset struct*/
/* Legal values for the note segment descriptor types for object files. */
#define NT_VERSION 1 /* Contains a version string. */
/* Dynamic section entry. */
struct Elf32_Dyn {
int32 d_tag; /* Dynamic entry type */
union {
uint32 d_val; /* Integer value */
uint32 d_ptr; /* Address value */
} d_un;
};
struct Elf64_Dyn {
int64 d_tag; /* Dynamic entry type */
union {
uint64 d_val; /* Integer value */
uint64 d_ptr; /* Address value */
} d_un;
};
/* Legal values for d_tag (dynamic entry type). */
#define DT_NULL 0 /* Marks end of dynamic section */
#define DT_NEEDED 1 /* Name of needed library */
#define DT_PLTRELSZ 2 /* Size in bytes of PLT relocs */
#define DT_PLTGOT 3 /* Processor defined value */
#define DT_HASH 4 /* Address of symbol hash table */
#define DT_STRTAB 5 /* Address of string table */
#define DT_SYMTAB 6 /* Address of symbol table */
#define DT_RELA 7 /* Address of Rela relocs */
#define DT_RELASZ 8 /* Total size of Rela relocs */
#define DT_RELAENT 9 /* Size of one Rela reloc */
#define DT_STRSZ 10 /* Size of string table */
#define DT_SYMENT 11 /* Size of one symbol table entry */
#define DT_INIT 12 /* Address of init function */
#define DT_FINI 13 /* Address of termination function */
#define DT_SONAME 14 /* Name of shared object */
#define DT_RPATH 15 /* Library search path (deprecated) */
#define DT_SYMBOLIC 16 /* Start symbol search here */
#define DT_REL 17 /* Address of Rel relocs */
#define DT_RELSZ 18 /* Total size of Rel relocs */
#define DT_RELENT 19 /* Size of one Rel reloc */
#define DT_PLTREL 20 /* Type of reloc in PLT */
#define DT_DEBUG 21 /* For debugging; unspecified */
#define DT_TEXTREL 22 /* Reloc might modify .text */
#define DT_JMPREL 23 /* Address of PLT relocs */
#define DT_BIND_NOW 24 /* Process relocations of object */
#define DT_INIT_ARRAY 25 /* Array with addresses of init fct */
#define DT_FINI_ARRAY 26 /* Array with addresses of fini fct */
#define DT_INIT_ARRAYSZ 27 /* Size in bytes of DT_INIT_ARRAY */
#define DT_FINI_ARRAYSZ 28 /* Size in bytes of DT_FINI_ARRAY */
#define DT_RUNPATH 29 /* Library search path */
#define DT_FLAGS 30 /* Flags for the object being loaded */
#define DT_ENCODING 32 /* Start of encoded range */
#define DT_PREINIT_ARRAY 32 /* Array with addresses of preinit fct*/
#define DT_PREINIT_ARRAYSZ 33 /* size in bytes of DT_PREINIT_ARRAY */
#define DT_NUM 34 /* Number used */
#define DT_LOOS 0x60000000 /* Start of OS-specific */
#define DT_HIOS 0x6fffffff /* End of OS-specific */
#define DT_LOPROC 0x70000000 /* Start of processor-specific */
#define DT_HIPROC 0x7fffffff /* End of processor-specific */
#define DT_PROCNUM DT_MIPS_NUM /* Most used by any processor */
/* DT_* entries which fall between DT_VALRNGHI & DT_VALRNGLO use the
Dyn.d_un.d_val field of the Elf*_Dyn structure. This follows Sun's
approach. */
#define DT_VALRNGLO 0x6ffffd00
#define DT_CHECKSUM 0x6ffffdf8
#define DT_PLTPADSZ 0x6ffffdf9
#define DT_MOVEENT 0x6ffffdfa
#define DT_MOVESZ 0x6ffffdfb
#define DT_FEATURE_1 0x6ffffdfc /* Feature selection (DTF_*). */
#define DT_POSFLAG_1 0x6ffffdfd /* Flags for DT_* entries, effecting the following DT_* entry. */
#define DT_SYMINSZ 0x6ffffdfe /* Size of syminfo table (in bytes) */
#define DT_SYMINENT 0x6ffffdff /* Entry size of syminfo */
#define DT_VALRNGHI 0x6ffffdff
/* DT_* entries which fall between DT_ADDRRNGHI & DT_ADDRRNGLO use the
Dyn.d_un.d_ptr field of the Elf*_Dyn structure.
If any adjustment is made to the ELF object after it has been
built these entries will need to be adjusted. */
#define DT_ADDRRNGLO 0x6ffffe00
#define DT_SYMINFO 0x6ffffeff /* syminfo table */
#define DT_ADDRRNGHI 0x6ffffeff
/* The versioning entry types. The next are defined as part of the GNU extension. */
#define DT_VERSYM 0x6ffffff0
#define DT_RELACOUNT 0x6ffffff9
#define DT_RELCOUNT 0x6ffffffa
/* These were chosen by Sun. */
#define DT_FLAGS_1 0x6ffffffb /* State flags, see DF_1_* below. */
#define DT_VERDEF 0x6ffffffc /* Address of version definition table */
#define DT_VERDEFNUM 0x6ffffffd /* Number of version definitions */
#define DT_VERNEED 0x6ffffffe /* Address of table with needed versions */
#define DT_VERNEEDNUM 0x6fffffff /* Number of needed versions */
#define DT_VERSIONTAGIDX(tag) (DT_VERNEEDNUM - (tag)) /* Reverse order! */
#define DT_VERSIONTAGNUM 16
/* Sun added these machine-independent extensions in the "processor-specific"
range. Be compatible. */
#define DT_AUXILIARY 0x7ffffffd /* Shared object to load before self */
#define DT_FILTER 0x7fffffff /* Shared object to get values from */
#define DT_EXTRATAGIDX(tag) ((uint32)-((int32) (tag) <<1>>1)-1)
#define DT_EXTRANUM 3
/* Values of `d_un.d_val' in the DT_FLAGS entry. */
#define DF_ORIGIN 0x00000001 /* Object may use DF_ORIGIN */
#define DF_SYMBOLIC 0x00000002 /* Symbol resolutions starts here */
#define DF_TEXTREL 0x00000004 /* Object contains text relocations */
#define DF_BIND_NOW 0x00000008 /* No lazy binding for this object */
/* State flags selectable in the `d_un.d_val' element of the DT_FLAGS_1
entry in the dynamic section. */
#define DF_1_NOW 0x00000001 /* Set RTLD_NOW for this object. */
#define DF_1_GLOBAL 0x00000002 /* Set RTLD_GLOBAL for this object. */
#define DF_1_GROUP 0x00000004 /* Set RTLD_GROUP for this object. */
#define DF_1_NODELETE 0x00000008 /* Set RTLD_NODELETE for this object.*/
#define DF_1_LOADFLTR 0x00000010 /* Trigger filtee loading at runtime.*/
#define DF_1_INITFIRST 0x00000020 /* Set RTLD_INITFIRST for this object*/
#define DF_1_NOOPEN 0x00000040 /* Set RTLD_NOOPEN for this object. */
#define DF_1_ORIGIN 0x00000080 /* $ORIGIN must be handled. */
#define DF_1_DIRECT 0x00000100 /* Direct binding enabled. */
#define DF_1_TRANS 0x00000200
#define DF_1_INTERPOSE 0x00000400 /* Object is used to interpose. */
#define DF_1_NODEFLIB 0x00000800 /* Ignore default lib search path. */
#define DF_1_NODUMP 0x00001000
#define DF_1_CONFALT 0x00002000
#define DF_1_ENDFILTEE 0x00004000
/* Flags for the feature selection in DT_FEATURE_1. */
#define DTF_1_PARINIT 0x00000001
#define DTF_1_CONFEXP 0x00000002
/* Flags in the DT_POSFLAG_1 entry effecting only the next DT_* entry. */
#define DF_P1_LAZYLOAD 0x00000001 /* Lazyload following object. */
#define DF_P1_GROUPPERM 0x00000002 /* Symbols from next object are not generally available. */
/* Version definition sections. */
struct Elf32_Verdef {
uint16 vd_version; /* Version revision */
uint16 vd_flags; /* Version information */
uint16 vd_ndx; /* Version Index */
uint16 vd_cnt; /* Number of associated aux entries */
uint32 vd_hash; /* Version name hash value */
uint32 vd_aux; /* Offset in bytes to verdaux array */
uint32 vd_next; /* Offset in bytes to next verdef entry */
};
struct Elf64_Verdef {
uint16 vd_version; /* Version revision */
uint16 vd_flags; /* Version information */
uint16 vd_ndx; /* Version Index */
uint16 vd_cnt; /* Number of associated aux entries */
uint32 vd_hash; /* Version name hash value */
uint32 vd_aux; /* Offset in bytes to verdaux array */
uint32 vd_next; /* Offset in bytes to next verdef entry */
};
/* Legal values for vd_version (version revision). */
#define VER_DEF_NONE 0 /* No version */
#define VER_DEF_CURRENT 1 /* Current version */
#define VER_DEF_NUM 2 /* Given version number */
/* Legal values for vd_flags (version information flags). */
#define VER_FLG_BASE 0x1 /* Version definition of file itself */
#define VER_FLG_WEAK 0x2 /* Weak version identifier */
/* Auxialiary version information. */
struct Elf32_Verdaux {
uint32 vda_name; /* Version or dependency names */
uint32 vda_next; /* Offset in bytes to next verdaux entry */
};
struct Elf64_Verdaux {
uint32 vda_name; /* Version or dependency names */
uint32 vda_next; /* Offset in bytes to next verdaux entry */
};
/* Version dependency section. */
struct Elf32_Verneed {
uint16 vn_version; /* Version of structure */
uint16 vn_cnt; /* Number of associated aux entries */
uint32 vn_file; /* Offset of filename for this dependency */
uint32 vn_aux; /* Offset in bytes to vernaux array */
uint32 vn_next; /* Offset in bytes to next verneed entry */
};
struct Elf64_Verneed {
uint16 vn_version; /* Version of structure */
uint16 vn_cnt; /* Number of associated aux entries */
uint32 vn_file; /* Offset of filename for this dependency */
uint32 vn_aux; /* Offset in bytes to vernaux array */
uint32 vn_next; /* Offset in bytes to next verneed entry */
};
/* Legal values for vn_version (version revision). */
#define VER_NEED_NONE 0 /* No version */
#define VER_NEED_CURRENT 1 /* Current version */
#define VER_NEED_NUM 2 /* Given version number */
/* Auxiliary needed version information. */
struct Elf32_Vernaux {
uint32 vna_hash; /* Hash value of dependency name */
uint16 vna_flags; /* Dependency specific information */
uint16 vna_other; /* Unused */
uint32 vna_name; /* Dependency name string offset */
uint32 vna_next; /* Offset in bytes to next vernaux entry */
};
struct Elf64_Vernaux {
uint32 vna_hash; /* Hash value of dependency name */
uint16 vna_flags; /* Dependency specific information */
uint16 vna_other; /* Unused */
uint32 vna_name; /* Dependency name string offset */
uint32 vna_next; /* Offset in bytes to next vernaux entry */
};
/* Legal values for vna_flags. */
#define VER_FLG_WEAK 0x2 /* Weak version identifier */
/* Note section contents. Each entry in the note section begins with
a header of a fixed form. */
struct Elf32_Nhdr {
uint32 n_namesz; /* Length of the note's name. */
uint32 n_descsz; /* Length of the note's descriptor. */
uint32 n_type; /* Type of the note. */
};
struct Elf64_Nhdr {
uint32 n_namesz; /* Length of the note's name. */
uint32 n_descsz; /* Length of the note's descriptor. */
uint32 n_type; /* Type of the note. */
};
/* Known names of notes. */
/* Solaris entries in the note section have this name. */
#define ELF_NOTE_SOLARIS "SUNW Solaris"
/* Note entries for GNU systems have this name. */
#define ELF_NOTE_GNU "GNU"
/* Defined types of notes for Solaris. */
/* Value of descriptor (one word) is desired pagesize for the binary. */
#define ELF_NOTE_PAGESIZE_HINT 1
/* Defined note types for GNU systems. */
/* ABI information. The descriptor consists of words:
word 0: OS descriptor
word 1: major version of the ABI
word 2: minor version of the ABI
word 3: subminor version of the ABI
*/
#define ELF_NOTE_ABI 1
/* Known OSes. These value can appear in word 0 of an ELF_NOTE_ABI
note section entry. */
#define ELF_NOTE_OS_LINUX 0
#define ELF_NOTE_OS_GNU 1
#define ELF_NOTE_OS_SOLARIS2 2
/* Move records. */
struct Elf32_Move {
uint64 m_value; /* Symbol value. */
uint32 m_info; /* Size and index. */
uint32 m_poffset; /* Symbol offset. */
uint16 m_repeat; /* Repeat count. */
uint16 m_stride; /* Stride info. */
};
struct Elf64_Move {
uint64 m_value; /* Symbol value. */
uint64 m_info; /* Size and index. */
uint64 m_poffset; /* Symbol offset. */
uint16 m_repeat; /* Repeat count. */
uint16 m_stride; /* Stride info. */
};
/* Macro to construct move records. */
#define ELF32_M_SYM(info) ((info) >> 8)
#define ELF32_M_SIZE(info) ((uint8) (info))
#define ELF32_M_INFO(sym, size) (((sym) << 8) + (uint8) (size))
#define ELF64_M_SYM(info) ELF32_M_SYM (info)
#define ELF64_M_SIZE(info) ELF32_M_SIZE (info)
#define ELF64_M_INFO(sym, size) ELF32_M_INFO (sym, size)
/********************** Strings **********************/
#define ELF_CONSTRUCTOR_NAME ".ctors" // Name of constructors segment
// Macros listing all word-size dependent structures, used as template parameter list
#define ELFSTRUCTURES TELF_Header, TELF_SectionHeader, TELF_Symbol, TELF_Relocation
#define ELF32STRUCTURES Elf32_Ehdr, Elf32_Shdr, Elf32_Sym, Elf32_Rela
#define ELF64STRUCTURES Elf64_Ehdr, Elf64_Shdr, Elf64_Sym, Elf64_Rela
#endif // #ifndef ELF_H

View File

@ -0,0 +1,526 @@
/**************************** elf2asm.cpp *********************************
* Author: Agner Fog
* Date created: 2007-04-22
* Last modified: 2016-11-06
* Project: objconv
* Module: elf2asm.cpp
* Description:
* Module for disassembling ELF
*
* Copyright 2007-2016 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>
CELF2ASM<ELFSTRUCTURES>::CELF2ASM() {
}
// FindImageBase()
template <class TELF_Header, class TELF_SectionHeader, class TELF_Symbol, class TELF_Relocation>
void CELF2ASM<ELFSTRUCTURES>::FindImageBase() {
// Find image base if executable file
// Check if executable
switch (this->FileHeader.e_type) {
case ET_REL: default:
// Not an executable file
ExeType = 0; ImageBase = 0;
return;
case ET_DYN: // Shared object
ExeType = 1;
break;
case ET_EXEC: // Executable file
ExeType = 2;
break;
}
// Loop through sections to find the first allocated section
for (uint32 sc = 0; sc < this->NSections; sc++) {
if (this->SectionHeaders[sc].sh_type == SHT_PROGBITS // Must be code or data section
&& (this->SectionHeaders[sc].sh_flags & SHF_ALLOC) // Must be allocated
&& this->SectionHeaders[sc].sh_offset <= this->SectionHeaders[sc].sh_addr) { // Avoid negative
// Image base can be calculated from this section
ImageBase = this->SectionHeaders[sc].sh_addr - this->SectionHeaders[sc].sh_offset;
// Make sure ImageBase is divisible by page size
ImageBase = ImageBase & - 0x1000;
// Stop searching
return;
}
}
// Failure. Cannot compute image base from any of the sections
ImageBase = 0;
return;
}
// Convert
template <class TELF_Header, class TELF_SectionHeader, class TELF_Symbol, class TELF_Relocation>
void CELF2ASM<ELFSTRUCTURES>::Convert() {
// Do the conversion
// Find image base and executable type
FindImageBase();
// Tell disassembler
Disasm.Init(ExeType, ImageBase); // Set image base
// Make Sections list in Disasm
MakeSectionList();
// Make Symbols list in Disasm
MakeSymbolList();
// Make relocations for object and executable files
MakeRelocations();
if (ImageBase) {
// Executable file
MakeImportList(); // Make imported symbols for executable files
MakeExportList(); // Make exported symbols for executable files
MakeListLabels(); // Put labels on all image directory tables
}
Disasm.Go(); // Disassemble
*this << Disasm.OutFile; // Take over output file from Disasm
}
// MakeSectionList
template <class TELF_Header, class TELF_SectionHeader, class TELF_Symbol, class TELF_Relocation>
void CELF2ASM<ELFSTRUCTURES>::MakeSectionList() {
// Make Sections list and Relocations list in Disasm
// Allocate array for translating oroginal section numbers to new index
SectionNumberTranslate.SetNum(this->NSections + 1);
uint32 NewSectionIndex = 0;
for (uint32 sc = 0; sc < this->NSections; sc++) {
// Get copy of 32-bit header or converted 64-bit header
TELF_SectionHeader sheader = this->SectionHeaders[sc];
//int entrysize = (uint32)(sheader.sh_entsize);
uint32 namei = sheader.sh_name;
if (namei >= this->SecStringTableLen) {err.submit(2112); break;}
// if (sheader.sh_type == SHT_PROGBITS || sheader.sh_type == SHT_NOBITS) {
// // This is a code, data or bss section
if (sheader.sh_flags & SHF_ALLOC) {
// This is an allocated section
// Give it a new index
SectionNumberTranslate[sc] = ++NewSectionIndex;
// Get section parameters
uint8 * Buffer = (uint8*)(this->Buf()) + (uint32)sheader.sh_offset;
uint32 InitSize = (sheader.sh_type == SHT_NOBITS) ? 0 : (uint32)sheader.sh_size;
uint32 TotalSize = (uint32)sheader.sh_size;
uint32 SectionAddress = (uint32)sheader.sh_addr - (uint32)ImageBase;
uint32 Align = FloorLog2((uint32)sheader.sh_addralign);
const char * Name = this->SecStringTableLen ? this->SecStringTable + namei : "???";
// Detect segment type
uint32 Type = 0;
if (sheader.sh_flags & SHF_ALLOC) {
// Allocate
if (sheader.sh_type == SHT_NOBITS) {
// Uninitialized data
Type = 3;
}
else if (sheader.sh_flags & SHF_EXECINSTR) {
// Executable
Type = 1;
}
else if (!(sheader.sh_flags & SHF_WRITE)) {
// Not writeable
Type = 4;
}
else {
// Initialized writeable data
Type = 2;
}
}
// Save section record
Disasm.AddSection(Buffer, InitSize, TotalSize, SectionAddress, Type, Align, this->WordSize, Name);
}
}
}
// MakeSymbolList
template <class TELF_Header, class TELF_SectionHeader, class TELF_Symbol, class TELF_Relocation>
void CELF2ASM<ELFSTRUCTURES>::MakeSymbolList() {
// Make Symbols list in Disasm
// Allocate array for translate symbol indices for multiple symbol tables in
// source file to a single symbol table in disassembler
SymbolTableOffset.SetNum(this->NSections + 1);
NumSymbols = 0;
for (uint32 sc = 0; sc < this->NSections; sc++) {
// Get copy of 32-bit header or converted 64-bit header
TELF_SectionHeader sheader = this->SectionHeaders[sc];
int entrysize = (uint32)(sheader.sh_entsize);
if (sheader.sh_type==SHT_SYMTAB || sheader.sh_type==SHT_DYNSYM) {
// This is a symbol table
// Offset for symbols in this symbol table = number of preceding symbols from other symbol tables
SymbolTableOffset[sc] = NumSymbols;
// Find associated string table
if (sheader.sh_link >= this->NSections) {err.submit(2035); sheader.sh_link = 0;}
int8 * strtab = this->Buf() + uint32(this->SectionHeaders[sheader.sh_link].sh_offset);
// Find symbol table
uint32 symtabsize = (uint32)(sheader.sh_size);
int8 * symtab = this->Buf() + uint32(sheader.sh_offset);
int8 * symtabend = symtab + symtabsize;
if (entrysize < (int)sizeof(TELF_Symbol)) {err.submit(2033); entrysize = (int)sizeof(TELF_Symbol);}
// Loop through symbol table
uint32 symi1; // Symbol number in this table
uint32 symi2; // Symbol number in joined table
symtab += entrysize; // Skip symbol number 0
for (symi1 = 1; symtab < symtabend; symtab += entrysize, symi1++) {
// Symbol number in joined table = symi1 + number of symbols in preceding tables
symi2 = SymbolTableOffset[sc] + symi1;
// Copy 32 bit symbol table entry or convert 64 bit entry
TELF_Symbol sym = *(TELF_Symbol*)symtab;
// Parameters
uint32 Offset = uint32(sym.st_value);
uint32 Size = (uint32)sym.st_size;
// Get section
int32 Section = int16(sym.st_shndx);
if (Section >= (int32)(this->NSections)) {
// Error. wrong section
Section = 0;
}
if (Section > 0) {
// Translate to new section index
Section = SectionNumberTranslate[Section];
}
else if ((int16)Section < 0) {
// Special section values
if ((int16)Section == SHN_ABS) {
// Absolute symbol
Section = ASM_SEGMENT_ABSOLUTE;
}
else {
// Other special values
Section = ASM_SEGMENT_ERROR;
}
}
// Get name
const char * Name = 0;
if (*(strtab + sym.st_name)) {
Name = strtab + sym.st_name;
}
// Get import .so name
const char * DLLName = 0;
if (sheader.sh_type==SHT_DYNSYM && sym.st_value == 0
&& sym.st_shndx == 0 && sym.st_size > 0) {
// I don't know how to find out which .so the symbol is imported from
// It must be something in the .dynamic section.
DLLName = "?.so";
}
// Get scope
uint32 Scope = 0;
switch (sym.st_bind) {
case STB_LOCAL:
Scope = 2;
break;
case STB_WEAK:
Scope = 8;
if (Section > 0) break;
// Section == 0: continue as global
case STB_GLOBAL:
// Public or external
Scope = (sym.st_shndx > 0) ? 4 : 0x20;
break;
}
// Get type
uint32 Type = 0;
if (sym.st_type == STT_FUNC) {
// Function
Type = 0x83;
}
else if (sym.st_type == STT_GNU_IFUNC) {
// Gnu indirect function
Type = 0x40000083;
}
else if (sym.st_type == STT_OBJECT) {
// Probably a data object
switch (Size) {
case 1:
Type = 1;
break;
case 2:
Type = 2;
break;
case 4:
Type = 3;
break;
case 8:
Type = 4;
break;
default:
Type = 1;
break;
}
}
else if (sym.st_type == STT_COMMON) {
// Communal?
Type = 0;
Scope = 0x10;
}
else if (sym.st_type == STT_SECTION) {
// This is a section
Type = 0x80000082;
Scope = 0;
}
else if (sym.st_type == STT_NOTYPE) {
Type = 0;
}
else if (sym.st_type == STT_FILE) {
// file name. ignore
continue;
}
else {
// unknown type. warning
err.submit(1062, Name);
Type = 0;
//continue;
}
if (Scope != 0x20) {
// Not external
// Check if offset is absolute or section relative
if (ExeType && Offset >= (uint32)ImageBase) {
// Offset is absolute address
if (Section >= 0
&& (uint32)Section < this->NSections
&& Offset >= (uint32)this->SectionHeaders[Section].sh_addr
&& Offset - (uint32)this->SectionHeaders[Section].sh_addr < (uint32)(this->SectionHeaders[Section].sh_size)) {
// Change to section relative offset
Offset -= (uint32)(this->SectionHeaders[Section].sh_addr);
}
else {
// Address is outside specified section or otherwise inconsistent.
// Let Disasm try to find the address
Section = ASM_SEGMENT_IMGREL;
Offset -= (uint32)ImageBase;
}
}
}
// Store new symbol record
Disasm.AddSymbol(Section, Offset, Size, Type, Scope, symi2, Name, DLLName);
// Count symbols
NumSymbols++;
}
}
}
}
// MakeRelocations
template <class TELF_Header, class TELF_SectionHeader, class TELF_Symbol, class TELF_Relocation>
void CELF2ASM<ELFSTRUCTURES>::MakeRelocations() {
// Make relocations for object and executable files
int32 Section; // Source section new index
// Loop through sections
for (uint32 sc = 0; sc < this->NSections; sc++) {
// Get copy of 32-bit header or converted 64-bit header
TELF_SectionHeader sheader = this->SectionHeaders[sc];
int entrysize = (uint32)(sheader.sh_entsize);
if (sheader.sh_type == SHT_REL || sheader.sh_type == SHT_RELA) {
// Relocations section
int8 * reltab = this->Buf() + uint32(sheader.sh_offset);
int8 * reltabend = reltab + uint32(sheader.sh_size);
int expectedentrysize = sheader.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;}
// Loop through entries
for (; reltab < reltabend; reltab += entrysize) {
// Copy relocation table entry with or without addend
TELF_Relocation rel; rel.r_addend = 0;
memcpy(&rel, reltab, entrysize);
// Get section-relative or absolute address
uint32 Offset = (uint32)rel.r_offset;
// Get addend, if any
int32 Addend = (uint32)rel.r_addend;
// Find target symbol
uint32 TargetIndex = rel.r_sym;
if (sheader.sh_link < this->NSections) {
// sh_link indicates which symbol table r_sym refers to
TargetIndex += SymbolTableOffset[sheader.sh_link];
}
// Find section
if (sheader.sh_info < this->NSections) {
Section = SectionNumberTranslate[sheader.sh_info];
}
else {
// Not found. Try to let disasm find by absolute address
Section = ASM_SEGMENT_IMGREL;
if (Offset < (uint32)ImageBase) Offset += (uint32)ImageBase;
}
// Get relocation type and size
uint32 Type = 0;
uint32 Size = 0;
if (this->WordSize == 32) {
switch (rel.r_type) {
case R_386_RELATIVE: // Adjust by program base
Type = 0x21; Size = 4;
break;
case R_386_JMP_SLOT: // Create PLT entry
Type = 0x41; Size = 4;
break;
case R_386_PLT32: // Self-relative to PLT
Type = 0x2002; Size = 4;
break;
case R_386_32:
// Direct 32 bit
Type = 1; Size = 4;
break;
case R_386_PC32:
// Self-relative 32 bit
Type = 2; Size = 4;
break;
case R_386_GOTPC:
// Self-relative offset to GOT
Type = 0x1002; Size = 4;
break;
case R_386_IRELATIVE:
// Reference to Gnu indirect function
Type = 0x81; Size = 4;
break;
case R_386_GLOB_DAT:
case R_386_GOT32:
case R_386_GOTOFF:
// Create GOT entry
Type = 0x1001; Size = 4;
break;
}
}
else {
// 64 bit
switch (rel.r_type) {
case R_X86_64_RELATIVE: // Adjust by program base
Type = 0x21; Size = 8;
break;
case R_X86_64_JUMP_SLOT: // Create PLT entry
Type = 0x41; Size = 8;
break;
case R_X86_64_64:
// Direct 64 bit
Type = 1; Size = 8;
break;
case R_X86_64_PC32:
// Self relative 32 bit signed
Type = 2; Size = 4;
break;
case R_X86_64_32: case R_X86_64_32S:
// Direct 32 bit zero extended or sign extend
Type = 1; Size = 4;
break;
case R_X86_64_16:
// Direct 16 bit zero extended
Type = 1; Size = 2;
break;
case R_X86_64_PC16:
// 16 bit sign extended pc relative
Type = 2; Size = 2;
break;
case R_X86_64_8:
// Direct 8 bit sign extended
Type = 1; Size = 1;
break;
case R_X86_64_PC8:
// 8 bit sign extended pc relative
Type = 2; Size = 1;
break;
case R_X86_64_GOTPCREL:
// Self relative 32 bit signed offset to GOT entry
Type = 0x1002; Size = 4;
break;
case R_X86_64_IRELATIVE:
// Reference to Gnu indirect function
Type = 0x81; Size = 4;
break;
case R_X86_64_PLT32: // Self-relative to PLT
Type = 0x2002; Size = 4;
break;
case R_X86_64_GLOB_DAT: // Create GOT entry
case R_X86_64_GOT32:
Type = 0x1001; Size = 4;
break;
}
}
// Check if offset is absolute or section relative
if (ImageBase && Offset > (uint32)ImageBase) {
// Offset is absolute address
if (Section > 0 && (uint32)Section < this->NSections
&& Offset >= (uint32)(this->SectionHeaders[Section].sh_addr)
&& Offset - (uint32)(this->SectionHeaders[Section].sh_addr) < (uint32)(this->SectionHeaders[Section].sh_size)) {
// Change to section relative offset
Offset -= (uint32)(this->SectionHeaders[Section].sh_addr);
}
else {
// Inconsistent. Let Disasm try to find the address
Section = ASM_SEGMENT_IMGREL;
Offset -= (uint32)ImageBase;
}
}
// Save relocation record
Disasm.AddRelocation(Section, Offset, Addend, Type, Size, TargetIndex);
}
}
}
}
// MakeImportList
template <class TELF_Header, class TELF_SectionHeader, class TELF_Symbol, class TELF_Relocation>
void CELF2ASM<ELFSTRUCTURES>::MakeImportList() {
// Make imported symbols for executable files
}
// MakeExportList
template <class TELF_Header, class TELF_SectionHeader, class TELF_Symbol, class TELF_Relocation>
void CELF2ASM<ELFSTRUCTURES>::MakeExportList() {
// Make exported symbols for executable files
}
// MakeListLabels
template <class TELF_Header, class TELF_SectionHeader, class TELF_Symbol, class TELF_Relocation>
void CELF2ASM<ELFSTRUCTURES>::MakeListLabels() {
// Attach names to all image directories
}
// Make template instances for 32 and 64 bits
template class CELF2ASM<ELF32STRUCTURES>;
template class CELF2ASM<ELF64STRUCTURES>;

View 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>;

View File

@ -0,0 +1,424 @@
/**************************** elf2elf.cpp *****************************
* Author: Agner Fog
* Date created: 2006-01-13
* Last modified: 2013-11-27
* Project: objconv
* Module: elf2elf.cpp
* Description:
* Module for changing symbol names in ELF 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>
CELF2ELF<ELFSTRUCTURES>::CELF2ELF() {
// Initialize everything
memset(this, 0, sizeof(*this));
}
// Convert()
template <class TELF_Header, class TELF_SectionHeader, class TELF_Symbol, class TELF_Relocation>
void CELF2ELF<ELFSTRUCTURES>::Convert() {
// Some compilers require this-> for accessing members of template base class,
// according to the so-called two-phase lookup rule.
MakeSymbolTable(); // Remake symbol tables and string tables
ChangeSections(); // Modify section names and relocation table symbol indices
MakeBinaryFile(); // Put everyting together into ToFile
*this << ToFile; // Take over new file buffer
}
// MakeSymbolTable()
template <class TELF_Header, class TELF_SectionHeader, class TELF_Symbol, class TELF_Relocation>
void CELF2ELF<ELFSTRUCTURES>::MakeSymbolTable() {
uint32 SectionNumber; // Section number
char * SectionName; // Section name
uint32 SecNamei; // Section name index
uint32 OldSymi; // Old symbol index
uint32 NewSymi; // New symbol index
int isymt; // 0 = symtab, 1 = dynsym
const char * name1; // Old name of symbol
const char * name2; // Changed name of symbol
int SymbolType; // Symbol type for cmd.SymbolChange
int action; // Symbol change action
int binding; // Symbol binding
TELF_Symbol sym; // Symbol table entry
TELF_Symbol AliasEntry; // Symbol table alias entry
uint32 symnamei; // New symbol name index
CMemoryBuffer TempGlobalSymbolTable; // Temporary storage of public and external symbols
// Find symbol table and string tables
for (SectionNumber = 0; SectionNumber < this->NSections; SectionNumber++) {
// Get copy of 32-bit header or converted 64-bit header
TELF_SectionHeader sheader = this->SectionHeaders[SectionNumber];
switch (sheader.sh_type) {
case SHT_SYMTAB:
isymtab[0] = SectionNumber; // Symbol table found
istrtab[0] = this->SectionHeaders[SectionNumber].sh_link; // Associated string table
break;
case SHT_DYNSYM:
isymtab[1] = SectionNumber; // Dynamic symbol table found
istrtab[1] = this->SectionHeaders[SectionNumber].sh_link; // Associated string table
break;
case SHT_STRTAB:
SecNamei = sheader.sh_name;
if (SecNamei >= this->SecStringTableLen) {
err.submit(2112); return;}
SectionName = this->SecStringTable + SecNamei;
if (SectionNumber == this->FileHeader.e_shstrndx || !strcmp(SectionName,".shstrtab")) {
istrtab[2] = SectionNumber; // Section header string table found
}
else if (!strcmp(SectionName,".strtab") && !istrtab[0]) {
istrtab[0] = SectionNumber; // Symbol string table found
}
else if (!strcmp(SectionName,".stabstr")) {
istrtab[3] = SectionNumber; // Debug string table found
}
break;
}
}
// Make new symbol tables and string tables
// Loop through possibly two symbol tables
for (isymt = 0; isymt < 2; isymt++) {
if (isymtab[isymt] && isymtab[isymt] < this->NSections
&& istrtab[isymt] && istrtab[isymt] < this->NSections) {
// Symbol table header
uint32 SymTabHeaderOffset = uint32(this->FileHeader.e_shoff + isymtab[isymt] * this->SectionHeaderSize);
//TELF_SectionHeader SymTabHeader = this->Get<TELF_SectionHeader>(SymTabHeaderOffset);
// Some compilers fail with the double template here. Avoid the template:
TELF_SectionHeader SymTabHeader = *(TELF_SectionHeader*)(this->Buf() + SymTabHeaderOffset);
// Find symbol table
uint32 symtabsize = (uint32)(SymTabHeader.sh_size);
int8 * symtab = this->Buf() + SymTabHeader.sh_offset;
int8 * symtabend = symtab + symtabsize;
int entrysize = (int)(SymTabHeader.sh_entsize);
if (entrysize <= 0) entrysize = sizeof(TELF_Symbol);
// Find string table
char * StringTable = this->Buf() + this->SectionHeaders[istrtab[isymt]].sh_offset;
uint32 StringTableLen = uint32(this->SectionHeaders[istrtab[isymt]].sh_size);
NewStringTable[isymt].Push(0, 1); // Initialize new string table, first entry 0
if (isymt == 0) {
// Allocate NewSymbolIndex
NumOldSymbols = (symtabsize + entrysize - 1) / entrysize; // round up to nearest integer to be safe
NewSymbolIndex.SetNum(NumOldSymbols); // Allocate array
NewSymbolIndex.SetZero(); // Initialize
}
// Loop through old symbol table
for (OldSymi = 0; symtab < symtabend; symtab += entrysize, OldSymi++) {
// Symbol table entry
sym = *(TELF_Symbol*)symtab;
// Symbol name
if (sym.st_name < StringTableLen) {
name1 = StringTable + sym.st_name;}
else {
err.submit(2035); name1 = 0;
}
name2 = 0;
// Symbol type
int type = sym.st_type;
binding = sym.st_bind;
if (binding == STB_LOCAL) {
SymbolType = SYMT_LOCAL; // Symbol is local
}
else if (type == STT_OBJECT || type == STT_FUNC || type == STT_NOTYPE) {
if (int16(sym.st_shndx) > 0) { // Check section number
SymbolType = SYMT_PUBLIC; // Symbol is public
}
else {
SymbolType = SYMT_EXTERNAL; // Symbol is external
}
}
else {
SymbolType = SYMT_OTHER; // Symbol is section or filename or debug
}
// Check if any change required for this symbol
action = cmd.SymbolChange(name1, &name2, SymbolType);
switch (action) {
case SYMA_NOCHANGE:
// No change
break;
case SYMA_MAKE_WEAK:
// Make symbol weak
if (cmd.OutputType == FILETYPE_COFF) {
// PE/COFF format does not support weak publics. Use this only when converting to ELF
err.submit(2200);
}
// Make weak
binding = STB_WEAK;
sym.st_bind = binding;
sym.st_type = type ;
break;
case SYMA_MAKE_LOCAL:
// Make public symbol local, make external symbol ignored
binding = STB_LOCAL; SymbolType = SYMT_LOCAL;
sym.st_bind = binding;
sym.st_type = type ;
break;
case SYMA_CHANGE_NAME:
// Change name of symbol
name1 = name2; name2 = 0;
break;
case SYMA_ALIAS:
// Make alias and keep old name
if (isymt != 0) err.submit(1033, name1); // alias in dynsym not supported yet
AliasEntry = sym;
break;
default:
err.submit(9000); // unknown error
}
// Add entry to new string table
if (name1 && *name1) {
symnamei = NewStringTable[isymt].PushString(name1);
}
else {
symnamei = 0;
}
sym.st_name = symnamei;
if (isymt == 0) {
// The symtab symbol table must be ordered with local symbols first.
// Therefore the public and external symbols are temporarily stored
// in TempGlobalSymbolTable and the high bit of NewSymi is set.
// The two tables are joined together when the number of local symbols
// is known and the indexes into TempGlobalSymbolTable are adjusted
// to indexes into the joined table.
if (SymbolType == SYMT_LOCAL) {
NewSymbolTable[isymt].Push(&sym, entrysize);
NewSymi = NewSymbolTable[isymt].GetLastIndex();
}
else {
TempGlobalSymbolTable.Push(&sym, entrysize);
NewSymi = TempGlobalSymbolTable.GetLastIndex() | 0x80000000;
}
// Insert into symbol index translation table
NewSymbolIndex[OldSymi] = NewSymi;
if (action == SYMA_ALIAS && name2 && *name2) {
// Make one more entry for new alias
symnamei = NewStringTable[isymt].PushString(name2);
AliasEntry.st_name = symnamei;
TempGlobalSymbolTable.Push(&AliasEntry, entrysize);
}
}
else {
// dynsym table has no local symbols
// no index translation table is currently needed
NewSymbolTable[isymt].Push(&sym, entrysize);
}
} // End of loop through old symbol table
if (isymt == 0) {
// The symbol table has been temporarily split into local and non-local
// Save index to first nonlocal symbol
FirstGlobalSymbol = NewSymbolTable[isymt].GetNumEntries();
// Adjust symbol index translation table
for (OldSymi = 0; OldSymi < NumOldSymbols; OldSymi++) {
if (NewSymbolIndex[OldSymi] & 0x80000000) {
// Translate index into TempGlobalSymbolTable to index into joined table
NewSymbolIndex[OldSymi] = (NewSymbolIndex[OldSymi] & ~0x80000000) + FirstGlobalSymbol;
}
}
// Join the two tables
NewSymbolTable[isymt].Push(TempGlobalSymbolTable.Buf(), TempGlobalSymbolTable.GetDataSize());
}
}
} // End of isymt loop through possibly two symbol tables
}
// ChangeSections()
template <class TELF_Header, class TELF_SectionHeader, class TELF_Symbol, class TELF_Relocation>
void CELF2ELF<ELFSTRUCTURES>::ChangeSections() {
// Convert subfunction: Change section names if needed and adjust all relocation tables
uint32 SectionNumber; // Section number
const char * name1; // Section name
const char * name2; // Changed section name
int action; // Name change action
TELF_SectionHeader * sheaderp; // Pointer to section header
uint32 SectionHeaderOffset; // File offset to section header
uint32 namei; // Section name index into string table
TELF_Relocation * relocp; // Pointer to relocation entry
uint32 oldsymi, newsymi; // Relocation symbol index
// Initialize section header string table .shstrtab. First entry = 0
NewStringTable[2].Push(0, 1);
// Loop through sections
SectionHeaderOffset = uint32(this->FileHeader.e_shoff);
for (SectionNumber = 0; SectionNumber < this->NSections; SectionNumber++, SectionHeaderOffset += this->FileHeader.e_shentsize) {
// Get section header
sheaderp = (TELF_SectionHeader*)(this->Buf() + SectionHeaderOffset);
// Section name
namei = sheaderp->sh_name;
if (namei >= this->SecStringTableLen) {
err.submit(2112); sheaderp->sh_name = 0; return;}
name1 = this->SecStringTable + namei;
// Check if name change
action = cmd.SymbolChange(name1, &name2, SYMT_SECTION);
if (action == SYMA_CHANGE_NAME) name1 = name2;
// Store name in .shstrtab string table
if (name1 && *name1) {
namei = NewStringTable[2].PushString(name1);
}
else {
namei = 0;
}
sheaderp->sh_name = namei; // Put new string index into section header
if (sheaderp->sh_type == SHT_REL || sheaderp->sh_type == SHT_RELA) {
// This is a relocation section. Update all symbol indices
int8 * reltab = this->Buf() + sheaderp->sh_offset;
int8 * reltabend = reltab + sheaderp->sh_size;
int entrysize = (int)(sheaderp->sh_entsize);
if (entrysize <= 0) entrysize = sizeof(TELF_Relocation);
// Loop through entries
for (; reltab < reltabend; reltab += entrysize) {
relocp = (TELF_Relocation*)reltab;
oldsymi = relocp->r_sym;
if (oldsymi >= NumOldSymbols) {
err.submit(2040); oldsymi = 0;
}
// Translate symbol index
newsymi = NewSymbolIndex[oldsymi];
// Put back into relocation entry
relocp->r_sym = newsymi;
}
}
}
}
// MakeBinaryFile()
template <class TELF_Header, class TELF_SectionHeader, class TELF_Symbol, class TELF_Relocation>
void CELF2ELF<ELFSTRUCTURES>::MakeBinaryFile() {
uint32 SectionNumber; // Section number
CMemoryBuffer NewSectionHeaders; // Temporary storage of section headers
// Copy file header
ToFile.Push(this->Buf(), sizeof(TELF_Header));
// Copy program header if any
if (this->FileHeader.e_phnum) {
ToFile.Push(this->Buf() + this->FileHeader.e_phoff, this->FileHeader.e_phentsize * this->FileHeader.e_phnum);
((TELF_Header*)ToFile.Buf())->e_phoff = sizeof(TELF_Header);
}
// Copy section data
uint32 SectionHeaderOffset = uint32(this->FileHeader.e_shoff);
TELF_SectionHeader sheader; // Section header
// Loop through sections
for (SectionNumber = 0; SectionNumber < this->NSections; SectionNumber++, SectionHeaderOffset += this->FileHeader.e_shentsize) {
// Get section header
//sheader = this->Get<TELF_SectionHeader>(SectionHeaderOffset);
// Some compilers fail with the double template here. Avoid the template:
sheader = *(TELF_SectionHeader*)(this->Buf() + SectionHeaderOffset);
// Check for null section
if (SectionNumber == 0 && sheader.sh_type != 0) {
// First section must be null
err.submit(2036, 0);
}
// Align
ToFile.Align(16);
// Check for sections that have been modified
if (SectionNumber == isymtab[0]) {
// Static symbol table .symtab
sheader.sh_offset = ToFile.Push(NewSymbolTable[0].Buf(), NewSymbolTable[0].GetDataSize());
sheader.sh_size = NewSymbolTable[0].GetDataSize();
sheader.sh_info = FirstGlobalSymbol;
}
else if (SectionNumber == isymtab[1]) {
// Dynamic symbol table .dynsym
sheader.sh_offset = ToFile.Push(NewSymbolTable[1].Buf(), NewSymbolTable[1].GetDataSize());
sheader.sh_size = NewSymbolTable[1].GetDataSize();
}
else if (SectionNumber == istrtab[0]) {
// Symbol string table .strtab
sheader.sh_offset = ToFile.Push(NewStringTable[0].Buf(), NewStringTable[0].GetDataSize());
sheader.sh_size = NewStringTable[0].GetDataSize();
}
else if (SectionNumber == istrtab[1] && SectionNumber != istrtab[0]) {
// Dynamic symbol string table if different from .strtab
sheader.sh_offset = ToFile.Push(NewStringTable[1].Buf(), NewStringTable[1].GetDataSize());
sheader.sh_size = NewStringTable[1].GetDataSize();
}
else if (SectionNumber == istrtab[2]) {
// Section name string table .shstrtab
sheader.sh_offset = ToFile.Push(NewStringTable[2].Buf(), NewStringTable[2].GetDataSize());
sheader.sh_size = NewStringTable[2].GetDataSize();
}
else if (sheader.sh_type == SHT_NOBITS) {
// BSS section. Nothing
;
}
else {
// Any other section (including istrtab[3] = .stabstr)
sheader.sh_offset = ToFile.Push(this->Buf() + (uint32)sheader.sh_offset, (uint32)sheader.sh_size);
}
// Store section header
NewSectionHeaders.Push(&sheader, sizeof(sheader));
} // End of section loop
// Align
ToFile.Align(16);
// Store section headers
uint32 SectionHeadersOffset = ToFile.Push(NewSectionHeaders.Buf(), NewSectionHeaders.GetDataSize());
// Update file header
((TELF_Header*)ToFile.Buf())->e_shoff = SectionHeadersOffset;
((TELF_Header*)ToFile.Buf())->e_shentsize = sizeof(TELF_SectionHeader);
((TELF_Header*)ToFile.Buf())->e_shnum = NewSectionHeaders.GetNumEntries();
((TELF_Header*)ToFile.Buf())->e_shstrndx = istrtab[2];
}
// Make template instances for 32 and 64 bits
template class CELF2ELF<ELF32STRUCTURES>;
template class CELF2ELF<ELF64STRUCTURES>;

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,336 @@
/**************************** error.cpp **********************************
* Author: Agner Fog
* Date created: 2006-07-15
* Last modified: 2017-10-18
* Project: objconv
* Module: error.cpp
* Description:
* Standard procedure for error reporting to stderr
*
* Copyright 2006-2017 GNU General Public License http://www.gnu.org/licenses
*****************************************************************************/
// Define this if you get problems:
// #define OBJCONV_ERROR_CPP 1
#include "stdafx.h"
#define MAX_ERROR_TEXT_LENGTH 1024 // Maximum length of error text including extra info
// Make and initialize error reporter object
CErrorReporter err;
SErrorText ErrorTexts[] = {
// Unknown error
{0, 2, "Unknown error number!"},
// Warning messages
{1001, 1, "Empty command line option"},
{1002, 1, "Unknown command line option: %s"},
{1003, 1, "Unknown warning/error number: %i"},
{1006, 1, "Nothing do do. Copying file unchanged"},
{1008, 1, "Converting COFF file to ELF and back again."},
{1009, 1, "Converting OMF file to COFF and back again."},
{1010, 1, "Section index and section-relative fixup not supported in ELF file. Probably a debug record"},
{1011, 1, "Converting Mach-O file to ELF and back again."},
{1020, 1, "Non-public symbol %s cannot be made weak"},
{1021, 1, "Non-public symbol %s cannot be made local"},
{1022, 1, "Non-public symbol %s cannot get an alias"},
{1023, 1, "External symbol %s made local. Access to this symbol will cause error"},
{1024, 1, "Cannot change prefix on name %s, not a symbol"},
{1029, 1, "Debug information may be incompatible"},
{1030, 1, "Exception information may be incompatible"},
{1031, 1, "Windows resource information not translated"},
{1032, 1, "More than one symbol table found in ELF file"},
{1033, 1, "Sorry, cannot currently make alias in dynamic symbol table. Symbol = %s"},
{1040, 1, "Name of section %s too long. Truncating to 16 characters"},
{1050, 0, "Position dependent references will not work in .so file. (First occurrence is symbol %s. This message can be turned off with -wd1050)"},
{1051, 1, "Weak public not supported in target file type, symbol %s"},
{1052, 1, "Indirect symbol index out of range"},
{1053, 1, "Common constant converted to public: %s"},
{1054, 1, "Cannot find import table"},
{1055, 1, "Communal section currently not supported by objconv. Section dropped"},
{1060, 1, "Different alignments specified for same segment, %s. Using highest alignment"},
{1061, 1, "Symbol %s has lazy binding"},
{1062, 1, "Symbol %s has unknown type"},
{1063, 1, "Gnu indirect function (CPU dispatcher) cannot be converted"},
{1101, 1, "Output file name should have extension .lib or .a"},
{1102, 1, "Library members have different type"},
{1103, 1, "Output file name ignored"},
{1104, 1, "Library member %s not found. Extraction failed"},
{1105, 1, "Library member %s not found. Deletion failed"},
{1106, 1, "Symbol %s not found. Modification of this symbol failed"},
{1107, 1, "Name of library member %s should have extension .o or .obj"},
{1108, 1, "Name of library member %s too long. Truncating to 15 characters"},
{1109, 1, "Library member %s has unknown type. Possibly alias record without code"},
{1150, 1, "Universal binary contains more than one component that can be converted. Specify desired word size or use lipo to extract desired component"},
{1151, 1, "Skipping component with wordsize %i"},
{1202, 1, "OMF Record checksum error"},
{1203, 1, "Unrecognized data in OMF subrecord"},
{1204, 1, "String too long building OMF file. Truncating to 255 characters: %s"},
{1205, 1, "Alignment by %i possibly not supported for OMF file. Using page alignment (256 or 4096 depending on system)"},
{1206, 1, "Stack segment ignored"},
{1207, 1, "Overlapping data"},
{1208, 1, "Back-patched code (possibly OK)"},
{1211, 1, "%i comment records ignored"},
{1212, 1, "Record type (%s) not supported"},
{1213, 1, "Hash table has %i occurrences of name %s"},
{1214, 1, "Symbol %s defined in both modules %s"},
{1215, 1, "More than 251 blocks required in symbol hash table. May fail with some linkers"},
{1300, 1, "File contains 32-bit absolute address. Must link with option -image_base %s -pagezero_size 1000"},
{1301, 1, "Image-relative address converted to absolute. Assumes image base = "},
{1302, 1, "64-bit relocation with arbitrary reference point converted to 32-bit self-relative. Will fail if offset is negative"},
{1303, 1, "Cannot find imported symbol"},
{1304, 1, "Unknown relocation address"},
// Error messages
{2001, 2, "No more than one input file and one output file can be specified"},
{2002, 2, "Word size (%i) not supported for output file"},
{2003, 2, "Only one output format option can be specified. Command line error at %s"},
{2004, 2, "Unknown command line option: %s"},
{2005, 2, "Input file and output file cannot have same name: %s"},
{2006, 2, "Unsupported file type for file %s: %s"},
{2007, 2, "Cannot dump and convert file in the same command"},
{2008, 2, "This option must have two symbol names: %s"},
{2009, 2, "This option must have one symbol name: %s"},
{2010, 2, "Sorry. Dump of file type %s is not supported"},
{2011, 2, "Sorry. Conversion of file type %s is not supported"},
{2012, 2, "Cannot convert from word size %i to word size %i"},
{2013, 2, "Sorry. Conversion of file type %s to %s is not supported"},
{2014, 2, "File contains information for .NET common language runtime. Cannot convert"},
{2015, 2, "More than one option specified for symbol %s"},
{2016, 2, "Index out of range"},
{2017, 2, "File name %s specified more than once"},
{2018, 2, "Unknown type 0x%X for file: %s"},
{2020, 2, "Overflow when converting value of symbol %s to 32 bits"},
{2021, 2, "File contains information for objective-C runtime code. Cannot convert"},
{2022, 2, "Cannot convert executable file"},
{2030, 2, "Unsupported relocation type (%i)"},
{2031, 2, "Relocated symbol not found"},
{2032, 2, "Relocation points outside segment"},
{2033, 2, "Error in ELF file. Record size not specified"},
{2034, 2, "Symbol table not found in ELF file"},
{2035, 2, "Pointer out of range in object file"},
{2036, 2, "Unknown section index in ELF file: %i"},
{2037, 2, "Symbol storage/binding type %i not supported"},
{2038, 2, "Symbol type %i not supported"},
{2040, 2, "Symbol table corrupt in object file"},
{2041, 2, "File has relocation of uninitialized data"},
{2042, 2, "Relocation to global offset table found. Cannot convert position-independent code"},
{2043, 2, "Relocation to procedure linkage table found. Cannot convert"},
{2044, 2, "Relocation relative to arbitrary reference point that cannot be converted"},
{2045, 2, "Unknown import table type"},
{2050, 2, "Inconsistent relocation record pair"},
{2051, 2, "Too many symbols for Mach-O file. Maximum = 16M"},
{2052, 2, "Unexpected data between symbol table and string table"},
{2103, 2, "Cannot read input file %s"},
{2104, 2, "Cannot write output file %s"},
{2105, 2, "Wrong size of file %s"},
{2107, 2, "Too many response files"},
{2110, 2, "COFF file section table corrupt"},
{2112, 2, "String table corrupt"},
{2114, 2, "This is an intermediate file for whole-program-optimization in Intel compiler"},
{2200, 2, "Weak public symbols not supported in this file format"},
{2202, 2, "Symbol name %s too long. Cannot change prefix"},
{2203, 2, "File name %s too long"},
{2210, 2, "File contains overlapping relocation sources"},
{2301, 2, "OMF Record extends beyond end of file"},
{2302, 2, "Fixup source extends beyond end of section"},
{2303, 2, "Too many symbols for OMF file. Index exceeds 32767"},
{2304, 2, "Word-size index exceeds 65535"},
{2305, 2, "%i Communal sections found. Currently not supported by Objconv"},
{2306, 2, "Segment size is 4 Gbytes"},
{2307, 2, "Segment address is absolute"},
{2308, 2, "Unknown alignment %i"},
{2309, 2, "Data outside bounds of segment %s"},
{2310, 2, "Iterated data outside bounds of segment"},
{2311, 2, "Relocation of iterated data not supported by objconv"},
{2312, 2, "FIXUPP record does not refer to data record"},
{2313, 2, "OMF file has compression of repeated relocation target (thread). This is not supported in objconv"},
{2314, 2, "Unknown relocation method T%i"},
{2315, 2, "Group-relative relocation to %s not supported"},
{2316, 2, "Incompatible relocation method: %s"},
{2317, 2, "Incompatible word size: %i"},
{2318, 2, "OMF file has compression of repeated communal data. This is not supported in objconv"},
{2320, 2, "Mixed 32-bit and 64-bit segments"},
{2321, 2, "Wrong record size found"},
{2330, 2, "Imagebase specified more than once"},
{2331, 2, "Imagebase must be divisible by page size 1000 (hexadecimal)"},
{2332, 2, "Imagebase must > 0 and < 80000000 (hexadecimal)"},
{2500, 2, "Library/archive file is corrupt"},
{2501, 2, "Cannot store file of type %s in library"},
{2502, 2, "Too many members in library"},
{2503, 2, "Output file name must be specified"},
{2504, 2, "Object file type (%s) does not match library"},
{2505, 2, "Object file word size (%i) does not match library"},
{2506, 2, "Overflow of buffer for library member names"},
{2507, 2, "%s is an import library. Cannot convert to static library"},
{2600, 2, "Library has more than one header"},
{2601, 2, "Library page size (%i) is not a power of 2"},
{2602, 2, "Library end record does not match dictionary offset in OMF library"},
{2603, 2, "Public name %s not found in hash table"},
{2605, 2, "Symbol hash table too big. Creation of library failed"},
{2606, 2, "Too many library members. Creation of library failed"},
{2610, 2, "Library end record not found"},
{2620, 2, "You need to extract library members before disassembling"},
{2621, 2, "Wrong output file type"},
{2701, 2, "Wrong number of members in universal binary (%i)"},
{3000, 1, "Internal error in opcode table"},
{3001, 1, "Internal error: Unknown register type 0x%X"},
// Fatal errors makes the program stop immediately:
{9000, 9, "Objconv program internal inconsistency"},
{9001, 9, "Objconv program has been compiled with wrong integer sizes"},
{9002, 9, "Objconv cannot run on machine with big-endian memory organization"},
{9003, 9, "Array index out of range"},
{9004, 9, "Cannot resize array of type CArrayBuf"},
{9005, 9, "Exceeding 1kb size limit while building OMF record"},
{9006, 9, "Memory allocation failed"},
{9007, 9, "Objcopy internal error in opcode map 0x%X"},
// Mark end of list
{9999, 9999, "End of error text list"}
};
// Constructor for CErrorReporter
CErrorReporter::CErrorReporter() {
NumErrors = NumWarnings = WorstError = 0;
MaxWarnings = 50; // Max number of warning messages to pring
MaxErrors = 50; // Max number of error messages to print
}
SErrorText * CErrorReporter::FindError(int ErrorNumber) {
// Search for error in ErrorTexts
int e;
const int ErrorTextsLength = sizeof(ErrorTexts) / sizeof(ErrorTexts[0]);
for (e = 0; e < ErrorTextsLength; e++) {
if (ErrorTexts[e].ErrorNumber == ErrorNumber) return ErrorTexts + e;
}
// Error number not found
static SErrorText UnknownErr = ErrorTexts[0];
UnknownErr.ErrorNumber = ErrorNumber;
UnknownErr.Status = 0x102; // Unknown error
return &UnknownErr;
}
void CErrorReporter::submit(int ErrorNumber) {
// Print error message with no extra info
SErrorText * err = FindError(ErrorNumber);
HandleError(err, err->Text);
}
void CErrorReporter::submit(int ErrorNumber, int extra) {
// Print error message with extra numeric info
// ErrorTexts[ErrorNumber] must contain %i where extra is to be inserted
char text[MAX_ERROR_TEXT_LENGTH];
SErrorText * err = FindError(ErrorNumber);
snprintf(text, MAX_ERROR_TEXT_LENGTH, err->Text, extra);
HandleError(err, text);
}
void CErrorReporter::submit(int ErrorNumber, int extra1, int extra2) {
// Print error message with 2 extra numeric values inserted
// ErrorTexts[ErrorNumber] must contain two %i fields where extra numbers are to be inserted
char text[MAX_ERROR_TEXT_LENGTH];
SErrorText * err = FindError(ErrorNumber);
snprintf(text, MAX_ERROR_TEXT_LENGTH, err->Text, extra1, extra2);
HandleError(err, text);
}
void CErrorReporter::submit(int ErrorNumber, char const * extra) {
// Print error message with extra text info
// ErrorTexts[ErrorNumber] must contain %s where extra is to be inserted
char text[MAX_ERROR_TEXT_LENGTH];
SErrorText * err = FindError(ErrorNumber);
snprintf(text, MAX_ERROR_TEXT_LENGTH, err->Text, extra);
HandleError(err, text);
}
void CErrorReporter::submit(int ErrorNumber, char const * extra1, char const * extra2) {
// Print error message with two extra text info fields
// ErrorTexts[ErrorNumber] must contain %s where extra texts are to be inserted
char text[MAX_ERROR_TEXT_LENGTH];
if (extra1 == 0) extra1 = "???"; if (extra2 == 0) extra2 = "???";
SErrorText * err = FindError(ErrorNumber);
snprintf(text, MAX_ERROR_TEXT_LENGTH, err->Text, extra1, extra2);
HandleError(err, text);
}
void CErrorReporter::submit(int ErrorNumber, int extra1, char const * extra2) {
// Print error message with two extra text fields inserted
// ErrorTexts[ErrorNumber] must contain %i and %s where extra texts are to be inserted
char text[MAX_ERROR_TEXT_LENGTH];
if (extra2 == 0) extra2 = "???";
SErrorText * err = FindError(ErrorNumber);
snprintf(text, MAX_ERROR_TEXT_LENGTH, err->Text, extra1, extra2);
HandleError(err, text);
}
void CErrorReporter::HandleError(SErrorText * err, char const * text) {
// HandleError is used by submit functions
// check severity
int severity = err->Status & 0x0F;
if (severity == 0) {
return; // Ignore message
}
if (severity > 1 && err->ErrorNumber > WorstError) {
// Store highest error number
WorstError = err->ErrorNumber;
}
if (severity == 1) {
// Treat message as warning
if (++NumWarnings > MaxWarnings) return; // Maximum number of warnings has been printed
// Treat message as warning
fprintf(stderr, "\nWarning %i: %s", err->ErrorNumber, text);
if (NumWarnings == MaxWarnings) {
// Maximum number reached
fprintf(stderr, "\nSupressing further warning messages");
}
}
else {
// Treat message as error
if (++NumErrors > MaxErrors) return; // Maximum number of warnings has been printed
fprintf(stderr, "\nError %i: %s", err->ErrorNumber, text);
if (NumErrors == MaxErrors) {
// Maximum number reached
fprintf(stderr, "\nSupressing further warning messages");
}
}
if (severity == 9) {
// Abortion required
fprintf(stderr, "\nAborting\n");
exit(err->ErrorNumber);
}
}
int CErrorReporter::Number() {
// Get number of fatal errors
return NumErrors;
}
int CErrorReporter::GetWorstError() {
// Get highest warning or error number encountered
return WorstError;
}
void CErrorReporter::ClearError(int ErrorNumber) {
// Ignore further occurrences of this error
int e;
const int ErrorTextsLength = sizeof(ErrorTexts) / sizeof(ErrorTexts[0]);
for (e = 0; e < ErrorTextsLength; e++) {
if (ErrorTexts[e].ErrorNumber == ErrorNumber) break;
}
if (e < ErrorTextsLength) {
ErrorTexts[e].Status = 0;
}
}

View File

@ -0,0 +1,51 @@
/**************************** error.h ************************************
* Author: Agner Fog
* Date created: 2006-07-15
* Last modified: 2006-07-15
* Project: objconv
* Module: error.h
* Description:
* Header file for error handler error.cpp
*
* Copyright 2006-2008 GNU General Public License http://www.gnu.org/licenses
*****************************************************************************/
#ifndef OBJCONV_ERROR_H
#define OBJCONV_ERROR_H
// Structure for defining error message texts
struct SErrorText {
int ErrorNumber; // Error number
int Status; // bit 0-3 = severity: 0 = ignore, 1 = warning, 2 = error, 9 = abort
// bit 8 = error number not found
char const * Text; // Error text
};
// General error routine for reporting warning and error messages to STDERR output
class CErrorReporter {
public:
CErrorReporter(); // Default constructor
static SErrorText * FindError(int ErrorNumber); // Search for error in ErrorTexts
void submit(int ErrorNumber); // Print error message
void submit(int ErrorNumber, int extra); // Print error message with extra info
void submit(int ErrorNumber, int, int); // Print error message with two extra numbers inserted
void submit(int ErrorNumber, char const * extra); // Print error message with extra info
void submit(int ErrorNumber, char const *, char const *); // Print error message with two extra text fields inserted
void submit(int ErrorNumber, int, char const *); // Print error message with two extra text fields inserted
int Number(); // Get number of errors
int GetWorstError(); // Get highest warning or error number encountered
void ClearError(int ErrorNumber); // Ignore further occurrences of this error
protected:
int NumErrors; // Number of errors detected
int NumWarnings; // Number of warnings detected
int WorstError; // Highest error number encountered
int MaxWarnings; // Max number of warning messages to pring
int MaxErrors; // Max number of error messages to print
void HandleError(SErrorText * err, char const * text); // Used by submit function
};
#ifndef OBJCONV_ERROR_CPP
extern CErrorReporter err; // Error handling object is in error.cpp
extern SErrorText ErrorTexts[]; // List of error texts
#endif
#endif // #ifndef OBJCONV_ERROR_H

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,126 @@
/**************************** library.h ********************************
* Author: Agner Fog
* Date created: 2006-07-15
* Last modified: 2013-08-22
* Project: objconv
* Module: library.h
* Description:
* Header file defining classes for reading and writing UNIX and OMF style
* libraries.
*
* Copyright 2007-2013 GNU General Public License http://www.gnu.org/licenses
*****************************************************************************/
#ifndef LIBRARY_H
#define LIBRARY_H
// Make big-endian numbers for library
uint32 EndianChange(uint32); // Convert little-endian to big-endian number, or vice versa
// Define UNIX library member header
struct SUNIXLibraryHeader {
char Name[16]; // Member name
char Date[12]; // Member date, seconds, decimal ASCII
char UserID[6]; // Member User ID, decimal ASCII
char GroupID[6]; // Member Group ID, decimal ASCII
char FileMode[8]; // Member file mode, octal
char FileSize[10]; // Member file size, decimal ASCII
char HeaderEnd[2]; // "`\n"
};
// Class for extracting members from library or building a library
class CLibrary : public CFileBuffer {
public:
CLibrary(); // Constructor
void Go(); // Do whatever the command line says
void Dump(); // Print contents of library
//static char *TruncateMemberName(char const*);// Remove path and truncate object file name to 15 characters
static char * ShortenMemberName(char const *name); // Truncate library member name to 15 characters and make unique. The original long name is not overwritten
static char * StripMemberName(char *); // Remove path from library member name. Original long name is overwritten
const char * GetModuleName(uint32 Index); // Get name of module from index or page index
protected:
// Properties for UNIX input libraries only
uint32 LongNames; // Offset to long names member
uint32 LongNamesSize; // Size of long names member
uint32 AlignBy; // Member alignment
// Properties for OMF input libraries only
uint32 PageSize; // Alignment of members
uint32 DictionaryOffset; // Offset to hash table
uint32 DictionarySize; // Dictionary size, in 512 bytes blocks
// Methods and properties for reading library:
void DumpUNIX(); // Print contents of UNIX style library
void DumpOMF(); // Print contents of OMF style library
void CheckOMFHash(CMemoryBuffer &stringbuf, CSList<SStringEntry> &index);// Check if OMF library hash table has correct entries for all symbol names
void StartExtracting(); // Initialize before ExtractMember()
char * ExtractMember(CFileBuffer*); // Extract next library member from input library
char * ExtractMemberUNIX(CFileBuffer*); // Extract member of UNIX style library
char * ExtractMemberOMF(CFileBuffer*); // Extract member of OMF style library
uint32 NextHeader(uint32 Offset); // Loop through library headers
CConverter MemberBuffer; // Buffer containing single library member
uint32 CurrentOffset; // Offset to current member
uint32 CurrentNumber; // Number of current member
int MemberFileType; // File type of members
// Methods and properties for modifying or writing library
void FixNames(); // Calls StripMemberNamesUNIX or RebuildOMF
void StripMemberNamesUNIX(); // Remove path from member names
void RebuildOMF(); // Rebuild OMF style library to make member names short
void InsertMember(CFileBuffer*); // Add next library member to output library
void InsertMemberUNIX(CFileBuffer*);// Add member to UNIX library
void InsertMemberOMF(CFileBuffer*); // Add member to OMF library
void MakeBinaryFile(); // Combine string index and members into binary file
void MakeBinaryFileUNIX(); // Make UNIX library
void MakeBinaryFileOMF(); // Make OMF library
void SortStringTable(); // Sort the string table
void MakeSymbolTableUnix(); // Make symbol table for COFF, ELF or MACHO library
CFileBuffer OutFile; // Buffer for building output file
CSList<SStringEntry> StringEntries; // String table using SStringEntry
CMemoryBuffer LongNamesBuffer; // Buffer for building the "//" longnames member
CMemoryBuffer StringBuffer; // Buffer containing strings
CMemoryBuffer DataBuffer; // Buffer containing raw members
CSList<uint32> Indexes; // Buffer containing indexes into DataBuffer
int RepressWarnings; // Repress warnings when rebuilding library
};
// Definitions for OMF library hash table:
#define OMFNumBuckets 37 // Number of buckets per block
#define OMFBlockSize 512 // Size of each block
// Structure of hash table block
union SOMFHashBlock {
struct {
uint8 Buckets[OMFNumBuckets]; // Indicators for each bucket
uint8 FreeSpace; // Pointer to free space
uint8 Data[OMFBlockSize-OMFNumBuckets-1]; // Contains strings and module indices
} b;
uint8 Strings[OMFBlockSize]; // Start of each string = length
};
// Hash table handler
class COMFHashTable {
public:
void Init(SOMFHashBlock * blocks, uint32 NumBlocks); // Initialize
void MakeHash(int8 * name); // Compute hash
int FindString(uint32 & ModulePage, uint32 & Conflicts); // Search for string. Get number of occurrences, module, number of conflicting strings
int InsertString(uint16 & ModulePage); // Insert string in hash table. Return 0 if success
void MakeHashTable(CSList<SStringEntry> & StringEntries, CMemoryBuffer & StringBuffer, CMemoryBuffer & HashTable, CLibrary * Library); // Make hash table
protected:
uint8 * String; // String to search for or insert
uint32 StringLength; // Length of string
SOMFHashBlock * blocks; // Pointer to blocks
uint32 NumBlocks; // Number of blocks
uint16 StartBlock; // Start block for search
uint16 StartBucket; // Start bucket for search
uint16 BlockD; // Block step size in search
uint16 BucketD; // Bucket step size in search
};
#endif // #ifndef LIBRARY_H

View File

@ -0,0 +1,577 @@
/**************************** mac2asm.cpp *********************************
* Author: Agner Fog
* Date created: 2007-05-24
* Last modified: 2008-05-12
* Project: objconv
* Module: mac2asm.cpp
* Description:
* Module for disassembling Mach-O files
*
* Copyright 2007-2008 GNU General Public License http://www.gnu.org/licenses
*****************************************************************************/
#include "stdafx.h"
// Constructor
template <class TMAC_header, class TMAC_segment_command, class TMAC_section, class TMAC_nlist, class MInt>
CMAC2ASM<MACSTRUCTURES>::CMAC2ASM() {
}
// Convert
template <class TMAC_header, class TMAC_segment_command, class TMAC_section, class TMAC_nlist, class MInt>
void CMAC2ASM<MACSTRUCTURES>::Convert() {
// Do the conversion
// Check cpu type
switch (this->FileHeader.cputype) {
case MAC_CPU_TYPE_I386:
this->WordSize = 32; break;
case MAC_CPU_TYPE_X86_64:
this->WordSize = 64; break;
default:
// Wrong type
err.submit(2011, ""); return;
}
// check object/executable file type
uint32 ExeType; // File type: 0 = object, 1 = position independent shared object, 2 = executable
switch (this->FileHeader.filetype) {
case MAC_OBJECT: // Relocatable object file
ExeType = 0; break;
case MAC_FVMLIB: // fixed VM shared library file
case MAC_DYLIB: // dynamicly bound shared library file
case MAC_BUNDLE: // part of universal binary
ExeType = 1; break;
case MAC_EXECUTE: // demand paged executable file
case MAC_CORE: // core file
case MAC_PRELOAD: // preloaded executable file
ExeType = 2; break;
default: // Other types
err.submit(2011, ""); return;
}
// Tell disassembler
// Disasm.Init(ExeType, this->ImageBase);
Disasm.Init(ExeType, 0);
// Make Sections list and relocations list
MakeSectionList();
// Make Symbols list in Disasm
MakeSymbolList();
// Make relocations list in Disasm
MakeRelocations();
// Make symbol entries for imported symbols
MakeImports();
Disasm.Go(); // Disassemble
*this << Disasm.OutFile; // Take over output file from Disasm
}
// MakeSectionList
template <class TMAC_header, class TMAC_segment_command, class TMAC_section, class TMAC_nlist, class MInt>
void CMAC2ASM<MACSTRUCTURES>::MakeSectionList() {
// Make Sections list and Relocations list in Disasm
uint32 icmd; // Command index
int32 isec1; // Section index within segment
int32 isec2 = 0; // Section index global
int32 nsect; // Number of sections in segment
uint32 cmd; // Load command
uint32 cmdsize; // Command size
StringBuffer.Push(0, 1); // Initialize string buffer
// Pointer to current position
uint8 * currentp = (uint8*)(this->Buf() + sizeof(TMAC_header));
// Loop through file commands
for (icmd = 1; icmd <= this->FileHeader.ncmds; icmd++) {
cmd = ((MAC_load_command*)currentp) -> cmd;
cmdsize = ((MAC_load_command*)currentp) -> cmdsize;
if (cmd == MAC_LC_SEGMENT || cmd == MAC_LC_SEGMENT_64) {
// This is a segment command
if ((this->WordSize == 64) ^ (cmd == MAC_LC_SEGMENT_64)) {
// Inconsistent word size
err.submit(2320); break;
}
// Number of sections in segment
nsect = ((TMAC_segment_command*)currentp) -> nsects;
// Find first section header
TMAC_section * sectp = (TMAC_section*)(currentp + sizeof(TMAC_segment_command));
// Loop through section headers
for (isec1 = 1; isec1 <= nsect; isec1++, sectp++) {
if (sectp->offset >= this->GetDataSize()) {
// points outside file
err.submit(2035); break;
}
// Get section properties
isec2++; // Section number
uint32 MacSectionType = sectp->flags & MAC_SECTION_TYPE;
uint8 * Buffer = (uint8*)(this->Buf()) + sectp->offset;
uint32 TotalSize = (uint32)sectp->size;
uint32 InitSize = TotalSize;
if (MacSectionType == MAC_S_ZEROFILL) InitSize = 0;
uint32 SectionAddress = (uint32)sectp->addr;
uint32 Align = sectp->align;
// Get section type
// 0 = unknown, 1 = code, 2 = data, 3 = uninitialized data, 4 = constant data
uint32 Type = 0;
if (sectp->flags & (MAC_S_ATTR_PURE_INSTRUCTIONS | MAC_S_ATTR_SOME_INSTRUCTIONS)) {
Type = 1; // code
}
else if (MacSectionType == MAC_S_ZEROFILL) {
Type = 3; // uninitialized data
}
else {
Type = 2; // data or anything else
}
// Make section name by combining segment name and section name
uint32 NameOffset = StringBuffer.Push(sectp->segname, (uint32)strlen(sectp->segname)); // Segment name
StringBuffer.Push(".", 1); // Separate by dot
StringBuffer.PushString(sectp->sectname); // Section name
char * Name = StringBuffer.Buf() + NameOffset;
// Save section record
Disasm.AddSection(Buffer, InitSize, TotalSize, SectionAddress, Type, Align, this->WordSize, Name);
// Save information about relocation list for this section
if (sectp->nreloc) {
MAC_SECT_WITH_RELOC RelList = {isec2, sectp->offset, sectp->nreloc, sectp->reloff};
RelocationQueue.Push(RelList);
}
// Find import tables
if (MacSectionType >= MAC_S_NON_LAZY_SYMBOL_POINTERS && MacSectionType <= MAC_S_LAZY_SYMBOL_POINTERS /*?*/) {
// This is an import table
ImportSections.Push(sectp);
}
// Find literals sections
if (MacSectionType == MAC_S_4BYTE_LITERALS || MacSectionType == MAC_S_8BYTE_LITERALS) {
// This is a literals section
ImportSections.Push(sectp);
}
}
}
currentp += cmdsize;
}
}
// MakeRelocations
template <class TMAC_header, class TMAC_segment_command, class TMAC_section, class TMAC_nlist, class MInt>
void CMAC2ASM<MACSTRUCTURES>::MakeRelocations() {
// Make relocations for object and executable files
uint32 iqq; // Index into RelocationQueue = table of relocation tables
uint32 irel; // Index into relocation table
int32 Section; // Section index
uint32 SectOffset; // File offset of section binary data
uint32 NumReloc; // Number of relocations records for this section
uint32 ReltabOffset; // File offset of relocation table for this section
uint32 SourceOffset; // Section-relative offset of relocation source
uint32 SourceSize; // Size of relocation source
int32 Inline = 0; // Inline addend at relocation source
uint32 TargetAddress; // Base-relative address of relocation target
uint32 TargetSymbol; // Symbol index of target
//int32 TargetSection; // Target section
int32 Addend; // Offset to add to target
uint32 ReferenceAddress; // Base-relative address of reference point
uint32 ReferenceSymbol; // Symbol index of reference point
uint32 R_Type; // Relocation type in Mach-O record
uint32 R_Type2; // Relocation type of second entry of a pair
uint32 R_PCRel; // Relocation is self-relative
uint32 RelType = 0; // Relocation type translated to disasm record
// Loop through RelocationQueue. There is one entry for each relocation table
for (iqq = 0; iqq < RelocationQueue.GetNumEntries(); iqq++) {
Section = RelocationQueue[iqq].Section; // Section index
SectOffset = RelocationQueue[iqq].SectOffset; // File offset of section binary data
NumReloc = RelocationQueue[iqq].NumReloc; // Number of relocations records for this section
ReltabOffset = RelocationQueue[iqq].ReltabOffset; // File offset of relocation table for this section
if (NumReloc == 0) continue;
if (ReltabOffset == 0 || ReltabOffset >= this->GetDataSize() || ReltabOffset + NumReloc*sizeof(MAC_relocation_info) >= this->GetDataSize()) {
// Pointer out of range
err.submit(2035); return;
}
// pointer to relocation info
union {
MAC_relocation_info * r;
MAC_scattered_relocation_info * s;
int8 * b;
} relp;
// Point to first relocation entry
relp.b = this->Buf() + ReltabOffset;
// Loop through relocation table
for (irel = 0; irel < NumReloc; irel++, relp.r++) {
// Set defaults
ReferenceAddress = ReferenceSymbol = TargetSymbol = Addend = 0;
if (relp.s->r_scattered) {
// scattered relocation entry
SourceOffset = relp.s->r_address;
SourceSize = 1 << relp.s->r_length;
R_PCRel = relp.s->r_pcrel;
R_Type = relp.s->r_type;
TargetAddress = relp.s->r_value;
TargetSymbol = 0;
}
else {
// non-scattered relocation entry
SourceOffset = relp.r->r_address;
SourceSize = 1 << relp.r->r_length;
R_PCRel = relp.r->r_pcrel;
R_Type = relp.r->r_type;
if (relp.r->r_extern) {
TargetSymbol = relp.r->r_symbolnum + 1;
}
else {
//TargetSection = relp.r->r_symbolnum;
}
TargetAddress = 0;
}
if (this->WordSize == 32 && (R_Type == MAC32_RELOC_SECTDIFF || R_Type == MAC32_RELOC_LOCAL_SECTDIFF)) {
// This is the first of a pair of relocation entries.
// Get second entry containing reference point
irel++; relp.r++;
if (irel >= NumReloc) {err.submit(2050); break;}
if (relp.s->r_scattered) {
// scattered relocation entry
R_Type2 = relp.s->r_type;
ReferenceAddress = relp.s->r_value;
ReferenceSymbol = 0;
}
else {
// non-scattered relocation entry
ReferenceSymbol = relp.r->r_symbolnum + 1;
R_Type2 = relp.r->r_type;
ReferenceAddress = 0;
}
if (R_Type2 != MAC32_RELOC_PAIR) {err.submit(2050); break;}
if (ReferenceSymbol == 0) {
// Reference point has no symbol index. Make one
ReferenceSymbol = Disasm.AddSymbol(ASM_SEGMENT_IMGREL, ReferenceAddress, 0, 0, 2, 0, 0);
}
}
if (this->WordSize == 64 && R_Type == MAC64_RELOC_SUBTRACTOR) {
// This is the first of a pair of relocation entries.
// The first entry contains reference point to subtract
irel++; relp.r++;
if (irel >= NumReloc || relp.s->r_scattered || relp.r->r_type != MAC64_RELOC_UNSIGNED) {
err.submit(2050); break;
}
ReferenceSymbol = TargetSymbol;
R_PCRel = relp.r->r_pcrel;
if (relp.r->r_extern) {
TargetSymbol = relp.r->r_symbolnum + 1;
}
else {
//TargetSection = relp.r->r_symbolnum;
}
TargetAddress = 0;
}
// Get inline addend or address
if (SectOffset + SourceOffset < this->GetDataSize()) {
switch (SourceSize) {
case 1:
Inline = CMemoryBuffer::Get<int8>(SectOffset+SourceOffset);
// (this->Get<int8> doesn't work on Gnu compiler 4.0.1)
break;
case 2:
Inline = CMemoryBuffer::Get<int16>(SectOffset+SourceOffset);
break;
case 4: case 8:
Inline = CMemoryBuffer::Get<int32>(SectOffset+SourceOffset);
break;
default:
Inline = 0;
}
}
if (this->WordSize == 32) {
// Calculate target address and addend, 32 bit system
if (R_Type == MAC32_RELOC_SECTDIFF || R_Type == MAC32_RELOC_LOCAL_SECTDIFF) {
// Relative to reference point
// Compensate for inline value = TargetAddress - ReferenceAddress;
Addend = ReferenceAddress - TargetAddress;
}
else if (R_PCRel) {
// Self-relative
TargetAddress += Inline + SourceOffset + SourceSize;
Addend = -4 - Inline;
}
else {
// Direct
TargetAddress += Inline;
Addend = -Inline;
}
}
if (TargetSymbol == 0) {
// Target has no symbol index. Make one
TargetSymbol = Disasm.AddSymbol(ASM_SEGMENT_IMGREL, TargetAddress, 0, 0, 2, 0, 0);
}
// Find type
if (this->WordSize == 32) {
switch (R_Type) {
case MAC32_RELOC_VANILLA:
// Direct or self-relative
RelType = R_PCRel ? 2 : 1;
break;
case MAC32_RELOC_SECTDIFF: case MAC32_RELOC_LOCAL_SECTDIFF:
// Relative to reference point
RelType = 0x10;
break;
case MAC32_RELOC_PB_LA_PTR:
// Lazy pointer
RelType = 0x41; //??
break;
default:
// Unknown type
err.submit(2030, R_Type);
break;
}
}
else { // 64-bit relocation types
switch (R_Type) {
case MAC64_RELOC_UNSIGNED:
// Absolute address
RelType = 1;
break;
case MAC64_RELOC_BRANCH:
// Signed 32-bit displacement with implicit -4 addend
case MAC64_RELOC_SIGNED:
// Signed 32-bit displacement with implicit -4 addend
case MAC64_RELOC_SIGNED_1:
// Signed 32-bit displacement with implicit -4 addend and explicit -1 addend
case MAC64_RELOC_SIGNED_2:
// Signed 32-bit displacement with implicit -4 addend and explicit -2 addend
case MAC64_RELOC_SIGNED_4:
// Signed 32-bit displacement with implicit -4 addend and explicit -4 addend
RelType = 2; Addend -= 4;
break;
case MAC64_RELOC_GOT:
// Absolute or relative reference to GOT?
// RelType = 0x1001; break;
case MAC64_RELOC_GOT_LOAD:
// Signed 32-bit displacement to GOT
RelType = 0x1002; Addend -= 4;
break;
case MAC64_RELOC_SUBTRACTOR:
// 32 or 64 bit relative to arbitrary reference point
RelType = 0x10;
break;
default:
// Unknown type
err.submit(2030, R_Type);
break;
}
}
// Make relocation record
Disasm.AddRelocation(Section, SourceOffset, Addend,
RelType, SourceSize, TargetSymbol, ReferenceSymbol);
}
}
}
// MakeSymbolList
template <class TMAC_header, class TMAC_segment_command, class TMAC_section, class TMAC_nlist, class MInt>
void CMAC2ASM<MACSTRUCTURES>::MakeSymbolList() {
// Make Symbols list in Disasm
uint32 symi; // Symbol index, 0-based
uint32 symn = 0; // Symbol number, 1-based
char * Name; // Symbol name
int32 Section; // Section number (1-based). 0 = external, ASM_SEGMENT_ABSOLUTE = absolute, ASM_SEGMENT_IMGREL = image-relative
uint32 Offset; // Offset into section. (Value for absolute symbol)
uint32 Type; // Symbol type. Use values listed above for SOpcodeDef operands. 0 = unknown type
uint32 Scope; // 1 = function local, 2 = file local, 4 = public, 8 = weak public, 0x10 = communal, 0x20 = external
// pointer to string table
char * strtab = (char*)(this->Buf() + this->StringTabOffset);
// loop through symbol table
TMAC_nlist * symp = (TMAC_nlist*)(this->Buf() + this->SymTabOffset);
for (symi = 0; symi < this->SymTabNumber; symi++, symp++) {
if (symp->n_type & MAC_N_STAB) {
// Debug symbol. Ignore
continue;
}
if (symp->n_strx < this->StringTabSize) {
// Normal symbol
Section = symp->n_sect;
Offset = (uint32)symp->n_value;
Name = strtab + symp->n_strx;
symn = symi + 1; // Convert 0-based to 1-based index
// Get scope
if (symi < this->iextdefsym) {
// Local
Scope = 2;
}
else if (Section && (symp->n_type & MAC_N_TYPE) != MAC_N_UNDF) {
// Public
Scope = 4;
}
else {
// External
Scope = 0x20;
}
// Check if absolute
if ((symp->n_type & MAC_N_TYPE) == MAC_N_ABS) {
// Absolute
Section = ASM_SEGMENT_ABSOLUTE; Scope = 4;
}
// Check if weak/communal
if (symp->n_type & MAC_N_PEXT) {
// Communal?
Scope = 0x10;
}
else if (symp->n_desc & MAC_N_WEAK_DEF) {
// Weak public
Scope = 8;
}
else if (symp->n_desc & MAC_N_WEAK_REF) {
// Weak external (not supported by disassembler)
Scope = 0x20;
}
// Get type
Type = 0;
// Offset is always based, not section-relative
if (Section > 0) Section = ASM_SEGMENT_IMGREL;
// Add symbol to diassembler
Disasm.AddSymbol(Section, Offset, 0, Type, Scope, symn, Name);
}
}
}
template <class TMAC_header, class TMAC_segment_command, class TMAC_section, class TMAC_nlist, class MInt>
void CMAC2ASM<MACSTRUCTURES>::MakeImports() {
// Make symbol entries for all import tables
uint32 isec; // Index into ImportSections list
uint32 SectionType; // Section type
TMAC_section * sectp; // Pointer to section
TMAC_nlist * symp0 = (TMAC_nlist*)(this->Buf() + this->SymTabOffset); // Pointer to symbol table
uint32 * IndSymp = (uint32*)(this->Buf() + this->IndirectSymTabOffset); // Pointer to indirect symbol table
uint32 iimp; // Index into import table
char * strtab = (char*)(this->Buf() + this->StringTabOffset); // pointer to string table
// Loop through import sections
for (isec = 0; isec < ImportSections.GetNumEntries(); isec++) {
// Pointer to section header
sectp = ImportSections[isec];
// Section type
SectionType = sectp->flags & MAC_SECTION_TYPE;
if (SectionType >= MAC_S_NON_LAZY_SYMBOL_POINTERS && SectionType <= MAC_S_MOD_INIT_FUNC_POINTERS) {
// This section contains import tables
// Entry size in import table
uint32 EntrySize = sectp->reserved2;
// Entry size is 4 if not specified
if (EntrySize == 0) EntrySize = 4;
// Number of entries
uint32 NumEntries = (uint32)sectp->size / EntrySize;
// Index into indirect symbol table entry of first entry in import table
uint32 Firsti = sectp->reserved1;
// Check if within range
if (Firsti + NumEntries > this->IndirectSymTabNumber) {
// This occurs when disassembling 64-bit Mach-O executable
// I don't know how to interpret the import table
err.submit(1054); continue;
}
// Loop through import table entries
for (iimp = 0; iimp < NumEntries; iimp++) {
// Address of import table entry
uint32 ImportAddress = (uint32)sectp->addr + iimp * EntrySize;
// Get symbol table index from indirect symbol table
uint32 symi = IndSymp[iimp + Firsti];
// Check index
if (symi == 0x80000000) {
// This value occurs. Maybe it means ignore?
continue;
}
// Check if index within symbol table
if (symi >= this->SymTabNumber) {
err.submit(1052); continue;
}
// Find name
uint32 StringIndex = symp0[symi].n_strx;
if (StringIndex >= this->StringTabSize) {
err.submit(1052); continue;
}
const char * Name = strtab + StringIndex;
// Name of .so to import from
const char * DLLName = "?";
// Symbol type
uint32 Type = 0;
switch (SectionType) {
case MAC_S_NON_LAZY_SYMBOL_POINTERS:
case MAC_S_LAZY_SYMBOL_POINTERS:
// pointer to symbol
Type = 3; break;
case MAC_S_SYMBOL_STUBS:
// jump to function
Type = 0x83;
// Make appear as direct call
DLLName = 0;
break;
case MAC_S_MOD_INIT_FUNC_POINTERS:
// function pointer?
Type = 0x0C; break;
}
// Make symbol record for disassembler
Disasm.AddSymbol(ASM_SEGMENT_IMGREL, ImportAddress, 4, Type, 2, 0, Name, DLLName);
}
}
else if (SectionType == MAC_S_4BYTE_LITERALS) {
// Section contains 4-byte float constants.
// Make symbol
Disasm.AddSymbol(ASM_SEGMENT_IMGREL, (uint32)sectp->addr, 4, 0x43, 2, 0, "Float_constants");
}
else if (SectionType == MAC_S_8BYTE_LITERALS) {
// Section contains 8-byte double constants.
// Make symbol
Disasm.AddSymbol(ASM_SEGMENT_IMGREL, (uint32)sectp->addr, 8, 0x44, 2, 0, "Double_constants");
}
}
}
// Make template instances for 32 and 64 bits
template class CMAC2ASM<MAC32STRUCTURES>;
template class CMAC2ASM<MAC64STRUCTURES>;

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,406 @@
/**************************** mac2mac.cpp *****************************
* Author: Agner Fog
* Date created: 2008-05-25
* Last modified: 2008-05-25
* Project: objconv
* Module: mac2mac.cpp
* Description:
* Module for changing symbol names in Mach-O file
*
* Copyright 2008 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 TMAC_header, class TMAC_segment_command, class TMAC_section, class TMAC_nlist, class MInt>
CMAC2MAC<MACSTRUCTURES>::CMAC2MAC() {
// Initialize everything
memset(this, 0, sizeof(*this));
}
// Convert()
template <class TMAC_header, class TMAC_segment_command, class TMAC_section, class TMAC_nlist, class MInt>
void CMAC2MAC<MACSTRUCTURES>::Convert() {
MakeSymbolTable(); // Remake symbol tables and string tables
MakeBinaryFile(); // Put everyting together into ToFile
ChangeSegments(); // Modify section names and relocation table symbol indices
*this << ToFile; // Take over new file buffer
}
// MakeSymbolTable()
template <class TMAC_header, class TMAC_segment_command, class TMAC_section, class TMAC_nlist, class MInt>
void CMAC2MAC<MACSTRUCTURES>::MakeSymbolTable() {
// Remake symbol tables and string table
int OldScope = 0; // Old scope of symbol. 0=local, 1=public, 2=external
int NewScope; // New scope of symbol. 0=local, 1=public, 2=external
uint32 symi; // Old index of symbol
const char * Name1; // Old symbol name
const char * Name2; // New symbol name
int action; // Action to take on symbol
int SymType; // Symbol type
int SymDesc; // Symbol descriptor
uint8 Section; // Symbol section
// pointer to symbol table
TMAC_nlist * symp = (TMAC_nlist*)(this->Buf() + this->SymTabOffset);
// pointer to string table
char * strtab = (char*)(this->Buf() + this->StringTabOffset);
// loop through symbol table
for (symi = 0; symi < this->SymTabNumber; symi++, symp++) {
// Check indices for first symbol of each scope category
if (symi == this->iextdefsym && this->nextdefsym) OldScope = 1;
if (symi == this->iundefsym && this->nundefsym) OldScope = 2;
NewScope = OldScope;
if (symp->n_strx >= this->StringTabSize) {
// Index out of range
err.submit(2112); continue;
}
// Get symbol name
Name1 = strtab + symp->n_strx;
// Get type, descriptor and section
SymType = symp->n_type; // Symbol type
SymDesc = symp->n_desc; // Symbol descriptor
Section = symp->n_sect; // Symbol section
// Check if any change required for this symbol
action = cmd.SymbolChange(Name1, &Name2, SYMT_LOCAL + OldScope);
switch (action) {
case SYMA_NOCHANGE:
// No change
break;
case SYMA_MAKE_WEAK:
// Make symbol weak
if (cmd.OutputType == FILETYPE_COFF) {
// PE/COFF format does not support weak publics
err.submit(2200);
}
// Make weak
if (OldScope == 1) {
SymDesc |= MAC_N_WEAK_DEF; // Weak public. Allowed only in coalesced (communal) section
}
else if (OldScope == 2) {
SymDesc |= MAC_N_WEAK_REF; // Weak external
}
else {
err.submit(1020, Name1); // Local symbol
}
break;
case SYMA_MAKE_LOCAL:
// Make public symbol local, make external symbol ignored
if (OldScope == 1) {
NewScope = 0; // Public changed to local
SymType &= ~MAC_N_EXT;
}
else if (OldScope == 2) {
Section = MAC_NO_SECT; // External symbol. Set to 0
SymDesc = 0;
SymType = MAC_N_UNDF;
}
else err.submit(1021, Name1);
break;
case SYMA_CHANGE_NAME:
// Change name of symbol
Name1 = Name2; Name2 = 0;
break;
case SYMA_ALIAS:
// Make alias and keep old name
if (OldScope != 1) {
err.submit(1022, Name1); break;
}
// Make alias
NewSymbols[1].AddSymbol(-1, Name2, SymType, SymDesc, Section, symp->n_value);
break;
default:
err.submit(9000); // unknown error
}
// Store symbol, possibly modified
NewSymbols[NewScope].AddSymbol(symi, Name1, SymType, SymDesc, Section, symp->n_value);
}
// Put everything into symbol table and string table
if (this->SymTabNumber) {
NewStringTable.SetDataSize(1); // First record must indicate empty string (see nlist.n_un in Mach-O File Format Reference)
}
for (NewScope = 0; NewScope < 3; NewScope++) {
NewSymbols[NewScope].SortList(); // Sort each list alphabetically
NewSymbols[NewScope].StoreList(&NewSymbolTable, &NewStringTable);
}
// Indices to local, public and external symbols
NewIlocalsym = 0; // index to local symbols
NewNlocalsym = NewSymbols[0].GetNumEntries(); // number of local symbols
NewIextdefsym = NewNlocalsym; // index to public symbols
NewNextdefsym = NewSymbols[1].GetNumEntries();// number of public symbols
NewIundefsym = NewNlocalsym + NewNextdefsym; // index to external symbols
NewNundefsym = NewSymbols[2].GetNumEntries(); // number of external symbols
// Calculate difference in size of new tables versus old tables
// (this calculation is moved to MakeBinaryFile)
// SizeDifference = NewSymbolTable.GetDataSize + NewStringTable.GetDataSize()
// - this->SymTabNumber * sizeof(TMAC_nlist) - this->StringTabSize;
}
template <class TMAC_header, class TMAC_segment_command, class TMAC_section, class TMAC_nlist, class MInt>
int CMAC2MAC<MACSTRUCTURES>::NewSymbolIndex(int32 OldIndex) {
// Convert subfunction: Translate old to new symbol index
int NewIndex;
int Scope;
// Search for symbol in all scopes
for (Scope = 0; Scope < 3; Scope++) {
NewIndex = NewSymbols[Scope].TranslateIndex(OldIndex);
if (NewIndex >= 0) {
// OldIndex found. Add offset into appropriate table
if (Scope == 1) NewIndex += NewIextdefsym;
else if (Scope == 2) NewIndex += NewIundefsym;
return NewIndex;
}
}
//err.submit(2031);
return -1;
}
template <class TMAC_header, class TMAC_segment_command, class TMAC_section, class TMAC_nlist, class MInt>
uint32 CMAC2MAC<MACSTRUCTURES>::NewFileOffset(uint32 OldOffset) {
// Convert subfunction: Translate old to new file offset
if (OldOffset <= NewSymtabOffset) {
// Before symbol table. No change
return OldOffset;
}
if (OldOffset >= OldTablesEnd) {
// After string table. Add size difference
return OldOffset + SizeDifference;
}
// Between symbol table and string table.
// The possibility of something between these two tables has not been accounted for
err.submit(2052);
return 0;
}
// MakeBinaryFile()
template <class TMAC_header, class TMAC_segment_command, class TMAC_section, class TMAC_nlist, class MInt>
void CMAC2MAC<MACSTRUCTURES>::MakeBinaryFile() {
uint32 OldSymtabEnd; // End of old symbol table
uint32 OldStringtabEnd; // End of old string table
const int WordSize = sizeof(MInt) * 8; // Word size, 32 or 64 bits
// Offset to symbol table and string table
NewSymtabOffset = this->SymTabOffset;
if (this->StringTabOffset && this->StringTabOffset < NewSymtabOffset) NewSymtabOffset = this->StringTabOffset;
if (NewSymtabOffset == 0) NewSymtabOffset = this->GetDataSize();
// Copy all headers and all data until TablesOffset
ToFile.Push(this->Buf(), NewSymtabOffset);
ToFile.Align(WordSize/8);
NewSymtabOffset = ToFile.GetDataSize();
// Copy new symbol table
ToFile.Push(NewSymbolTable.Buf(), NewSymbolTable.GetDataSize());
// Copy new string table
NewStringtabOffset = ToFile.GetDataSize();
ToFile.Push(NewStringTable.Buf(), NewStringTable.GetDataSize());
ToFile.Align(2);
NewStringtabEnd = ToFile.GetDataSize();
// Find end of old tables
OldSymtabEnd = this->SymTabOffset + this->SymTabNumber * sizeof(TMAC_nlist);
OldStringtabEnd = this->StringTabOffset + this->StringTabSize;
OldTablesEnd = OldStringtabEnd;
if (OldSymtabEnd > OldTablesEnd) OldTablesEnd = OldSymtabEnd;
if (OldTablesEnd == 0) OldTablesEnd = this->GetDataSize();
// Size difference between new and old tables
SizeDifference = NewStringtabEnd - OldTablesEnd;
// Is there anything in the old file after these tables?
if (OldTablesEnd && this->GetDataSize() > OldTablesEnd) {
// There is something after these tables. Copy it
ToFile.Push(this->Buf() + OldTablesEnd, this->GetDataSize() - OldTablesEnd);
}
}
// ChangeSegments()
template <class TMAC_header, class TMAC_segment_command, class TMAC_section, class TMAC_nlist, class MInt>
void CMAC2MAC<MACSTRUCTURES>::ChangeSegments() {
// Convert subfunction: Change section names if needed and adjust all relocation tables
uint32 FileOffset; // Current offset into file
uint32 lcmd; // Load command
uint32 cmdsize = 0; // Command size
uint32 icmd; // Loop counter
int action; // Name change action
char * Name1; // Old name
const char * Name2; // New name
FileOffset = sizeof(TMAC_header);
// Loop through file commands
for (icmd = 1; icmd <= this->FileHeader.ncmds; icmd++, FileOffset += cmdsize) {
lcmd = ((MAC_load_command*)(ToFile.Buf() + FileOffset)) -> cmd;
cmdsize = ((MAC_load_command*)(ToFile.Buf() + FileOffset)) -> cmdsize;
// Interpret specific command type
switch(lcmd) {
case MAC_LC_SEGMENT: { // 32-bit segment
MAC_segment_command_32 * sh = (MAC_segment_command_32*)(ToFile.Buf() + FileOffset);
Name1 = sh->segname;
// Check if any change required for this symbol
action = cmd.SymbolChange(Name1, &Name2, SYMT_SECTION);
if (action == SYMA_CHANGE_NAME) {
// Change segment name
if (strlen(Name2) > 16) err.submit(1040);
strncpy(Name1, Name2, 16);
}
// Change section names and relocations in all sections under this segment
ChangeSections(FileOffset + sizeof(MAC_segment_command_32), sh->nsects);
break;}
case MAC_LC_SEGMENT_64: { // 64-bit segment
MAC_segment_command_64 * sh = (MAC_segment_command_64*)(ToFile.Buf() + FileOffset);
Name1 = sh->segname;
// Check if any change required for this symbol
action = cmd.SymbolChange(Name1, &Name2, SYMT_SECTION);
if (action == SYMA_CHANGE_NAME) {
// Change segment name
if (strlen(Name2) > 16) err.submit(1040);
strncpy(Name1, Name2, 16);
}
// Change section names and relocations in all sections under this segment
ChangeSections(FileOffset + sizeof(MAC_segment_command_64), sh->nsects);
break;}
case MAC_LC_SYMTAB: { // Symbol table header
MAC_symtab_command * sh = (MAC_symtab_command*)(ToFile.Buf() + FileOffset);
// Change table addresses
sh->symoff = NewSymtabOffset;
sh->nsyms = NewSymbolTable.GetDataSize() / sizeof(TMAC_nlist);
sh->stroff = NewStringtabOffset;
sh->strsize = NewStringtabEnd - NewStringtabOffset;
break;}
case MAC_LC_DYSYMTAB: { // dynamic link-edit symbol table
MAC_dysymtab_command * sh = (MAC_dysymtab_command*)(ToFile.Buf() + FileOffset);
// Change indices to symbol tables
sh->ilocalsym = NewIlocalsym;
sh->nlocalsym = NewNlocalsym;
sh->iextdefsym = NewIextdefsym;
sh->nextdefsym = NewNextdefsym;
sh->iundefsym = NewIundefsym;
sh->nundefsym = NewNundefsym;
// Change table addresses
sh->tocoff = NewFileOffset(sh->tocoff);
sh->modtaboff = NewFileOffset(sh->modtaboff);
sh->extrefsymoff = NewFileOffset(sh->extrefsymoff);
sh->indirectsymoff = NewFileOffset(sh->indirectsymoff);
sh->extreloff = NewFileOffset(sh->extreloff);
sh->locreloff = NewFileOffset(sh->locreloff);
if (sh->nindirectsyms) {
// Change symbol indices in import table
ChangeImportTable(sh->indirectsymoff, sh->nindirectsyms);
}
break;}
}
}
}
template <class TMAC_header, class TMAC_segment_command, class TMAC_section, class TMAC_nlist, class MInt>
void CMAC2MAC<MACSTRUCTURES>::ChangeSections(uint32 HeaderOffset, uint32 Num) {
// Convert subfunction: Change section names and relocation records if needed
int action; // Name change action
char * Name1; // Old name
const char * Name2; // New name
uint32 isec1; // Section index
TMAC_section * secp; // Pointer to section header
uint32 irel; // Relocation index
MAC_relocation_info * relp; // Pointer to relocation record
// Loop through section headers
for (isec1 = 0; isec1 < Num; isec1++) {
// Find section header
secp = (TMAC_section*)(ToFile.Buf() + HeaderOffset + isec1*sizeof(TMAC_section));
// Segment name
Name1 = secp->segname;
action = cmd.SymbolChange(Name1, &Name2, SYMT_SECTION);
if (action == SYMA_CHANGE_NAME) {
// Change segment name
if (strlen(Name2) > 16) err.submit(1040);
strncpy(Name1, Name2, 16);
}
// Section name
Name1 = secp->sectname;
action = cmd.SymbolChange(Name1, &Name2, SYMT_SECTION);
if (action == SYMA_CHANGE_NAME) {
// Change section name
if (strlen(Name2) > 16) err.submit(1040);
strncpy(Name1, Name2, 16);
}
// Update file offset
secp->offset = NewFileOffset(secp->offset);
if (secp->nreloc) {
// This section has relocations
// Update relocations offset
secp->reloff = NewFileOffset(secp->reloff);
// Pointer to relocation records
relp = (MAC_relocation_info*)(ToFile.Buf() + secp->reloff);
// Loop through relocations, if any
for (irel = 0; irel < secp->nreloc; irel++, relp++) {
// Only non-scattered r_extern relocations have symbol index
if (!(relp->r_address & R_SCATTERED) && relp->r_extern) {
// Update symbol index
relp->r_symbolnum = NewSymbolIndex(relp->r_symbolnum);
}
}
}
}
}
template <class TMAC_header, class TMAC_segment_command, class TMAC_section, class TMAC_nlist, class MInt>
void CMAC2MAC<MACSTRUCTURES>::ChangeImportTable(uint32 FileOffset, uint32 Num) {
// Convert subfunction: Change symbol indices in import table if needed
uint32 i; // Index
uint32 * p; // pointer to current entry
// Find first entry
p = (uint32*)(ToFile.Buf() + FileOffset);
// Loop through table
for (i = 0; i < Num; i++, p++) {
// Translate symbol index
*p = NewSymbolIndex(*p);
}
}
// Make template instances for 32 and 64 bits
template class CMAC2MAC<MAC32STRUCTURES>;
template class CMAC2MAC<MAC64STRUCTURES>;

View File

@ -0,0 +1,754 @@
/**************************** macho.cpp *******************************
* Author: Agner Fog
* Date created: 2007-01-06
* Last modified: 2008-06-02
* Project: objconv
* Module: macho.cpp
* Description:
* Module for reading Mach-O files
*
* Class CMACHO is used for reading, interpreting and dumping Mach-O files.
*
* Copyright 2007-2008 GNU General Public License http://www.gnu.org/licenses
*****************************************************************************/
#include "stdafx.h"
// Machine names
SIntTxt MacMachineNames[] = {
{MAC_CPU_TYPE_I386, "Intel 32 bit"},
{MAC_CPU_TYPE_X86_64, "Intel 64 bit"},
{MAC_CPU_TYPE_ARM, "Arm"},
{MAC_CPU_TYPE_SPARC, "Sparc"},
{MAC_CPU_TYPE_POWERPC, "Power PC 32 bit"},
{MAC_CPU_TYPE_POWERPC64, "Power PC 64 bit"}
};
// CPU subtype names
SIntTxt MacCPUSubtypeNames[] = {
{MAC_CPU_SUBTYPE_POWERPC_ALL, "Power PC All"},
{MAC_CPU_SUBTYPE_I386_ALL, "Intel All"}
};
// File type names
SIntTxt MacFileTypeNames[] = {
{MAC_OBJECT, "Relocatable object file"},
{MAC_EXECUTE, "demand paged executable file"},
{MAC_FVMLIB, "fixed VM shared library file"},
{MAC_CORE, "core file"},
{MAC_PRELOAD, "preloaded executable file"},
{MAC_DYLIB, "dynamicly bound shared library file"},
{MAC_DYLINKER, "dynamic link editor"},
{MAC_BUNDLE, "dynamicly bound bundle file"}
};
// Command type names
SIntTxt MacCommandTypeNames[] = {
{MAC_LC_SEGMENT, "Segment"},
{MAC_LC_SYMTAB, "Symbol table"},
{MAC_LC_SYMSEG, "gdb symbol table info (obsolete)"},
{MAC_LC_THREAD, "thread"},
{MAC_LC_UNIXTHREAD, "unix thread"},
{MAC_LC_LOADFVMLIB, "load a specified fixed VM shared library"},
{MAC_LC_IDFVMLIB, "fixed VM shared library identification"},
{MAC_LC_IDENT, "object identification info (obsolete)"},
{MAC_LC_FVMFILE, "fixed VM file inclusion (internal use)"},
{MAC_LC_PREPAGE, "prepage command (internal use)"},
{MAC_LC_DYSYMTAB, "dynamic link-edit symbol table info"},
{MAC_LC_LOAD_DYLIB, "load a dynamicly linked shared library"},
{MAC_LC_ID_DYLIB, "dynamicly linked shared lib identification"},
{MAC_LC_LOAD_DYLINKER, "load a dynamic linker"},
{MAC_LC_ID_DYLINKER, "dynamic linker identification"},
{MAC_LC_PREBOUND_DYLIB, "modules prebound for a dynamicly linked shared library"},
{MAC_LC_ROUTINES, "image routines"},
{MAC_LC_SUB_FRAMEWORK, "sub framework"},
{MAC_LC_SUB_UMBRELLA, "sub umbrella"},
{MAC_LC_SUB_CLIENT, "sub client"},
{MAC_LC_SUB_LIBRARY, "sub library"},
{MAC_LC_TWOLEVEL_HINTS, "two-level namespace lookup hints"},
{MAC_LC_PREBIND_CKSUM, "prebind checksum"},
{MAC_LC_LOAD_WEAK_DYLIB&0xFF, "load a dynamically linked shared library, all symbols weak"},
{MAC_LC_SEGMENT_64, "64-bit segment"},
{MAC_LC_ROUTINES_64, "64-bit image routine"},
{MAC_LC_UUID, "uuid"}
};
// Relocation type names, 32 bit
SIntTxt Mac32RelocationTypeNames[] = {
{MAC32_RELOC_VANILLA, "Generic"},
{MAC32_RELOC_PAIR, "Second entry of a pair"},
{MAC32_RELOC_SECTDIFF, "Section diff"},
{MAC32_RELOC_PB_LA_PTR, "Prebound lazy "},
{MAC32_RELOC_LOCAL_SECTDIFF, "SectDif local"}
};
// Relocation type names, 64 bit
SIntTxt Mac64RelocationTypeNames[] = {
{MAC64_RELOC_UNSIGNED, "absolute address"},
{MAC64_RELOC_SIGNED, "signed 32-bit displ."},
{MAC64_RELOC_BRANCH, "Rel. jump 32-bit displ."},
{MAC64_RELOC_GOT_LOAD, "MOVQ load of a GOT entry"},
{MAC64_RELOC_GOT, "other GOT reference"},
{MAC64_RELOC_SUBTRACTOR, "Subtractor"},
{MAC64_RELOC_SIGNED_1, "signed 32-bit displacement with -1 addend"},
{MAC64_RELOC_SIGNED_2, "signed 32-bit displacement with -2 addend"},
{MAC64_RELOC_SIGNED_4, "signed 32-bit displacement with -4 addend"}
};
// Symbol type names
SIntTxt MacSymbolTypeNames[] = {
{MAC_N_UNDF, "Undefined, no section"},
{MAC_N_ABS, "Absolute, no section"},
{MAC_N_SECT, "Defined"},
{MAC_N_PBUD, "Prebound undefined (defined in a dylib)"},
{MAC_N_INDR, "Indirect"}
};
// Symbol reference type names
SIntTxt MacSymbolReferenceTypeNames[] = {
{MAC_REF_FLAG_UNDEFINED_NON_LAZY, "External non lazy"},
{MAC_REF_FLAG_UNDEFINED_LAZY, "External lazy (function call)"},
{MAC_REF_FLAG_DEFINED, "Defined public"},
{MAC_REF_FLAG_PRIVATE_DEFINED, "Defined private"},
{MAC_REF_FLAG_PRIVATE_UNDEFINED_NON_LAZY, "Private undefined non lazy"},
{MAC_REF_FLAG_PRIVATE_UNDEFINED_LAZY, "Private undefined lazy"}
};
// Symbol descriptor flag names
SIntTxt MacSymbolDescriptorFlagNames[] = {
{MAC_REFERENCED_DYNAMICALLY, "Referenced dynamically"},
// {MAC_N_DESC_DISCARDED, "Discarded"},
{MAC_N_NO_DEAD_STRIP, "Don't dead-strip"},
{MAC_N_WEAK_REF, "Weak external"},
{MAC_N_WEAK_DEF, "Weak public"}
};
// Class CMACHO members:
// Constructor
template <class TMAC_header, class TMAC_segment_command, class TMAC_section, class TMAC_nlist, class MInt>
CMACHO<MACSTRUCTURES>::CMACHO() {
// Set everything to zero
memset(this, 0, sizeof(*this));
}
template <class TMAC_header, class TMAC_segment_command, class TMAC_section, class TMAC_nlist, class MInt>
void CMACHO<MACSTRUCTURES>::ParseFile(){
// Load and parse file buffer
FileHeader = *(TMAC_header*)Buf(); // Copy file header
// Loop through file commands
uint32 cmd, cmdsize;
uint32 currentoffset = sizeof(TMAC_header);
for (uint32 i = 1; i <= FileHeader.ncmds; i++) {
if (currentoffset >= this->GetDataSize()) {
err.submit(2016); return;
}
uint8 * currentp = (uint8*)(Buf() + currentoffset);
cmd = ((MAC_load_command*)currentp) -> cmd;
cmdsize = ((MAC_load_command*)currentp) -> cmdsize;
// Interpret specific command type
switch(cmd) {
case MAC_LC_SEGMENT: {
if (WordSize != 32) err.submit(2320); // mixed segment size
MAC_segment_command_32 * sh = (MAC_segment_command_32*)currentp;
SegmentOffset = sh->fileoff; // File offset of segment
SegmentSize = sh->filesize; // Size of segment
NumSections = sh->nsects; // Number of sections
SectionHeaderOffset = currentoffset + sizeof(TMAC_segment_command); // File offset of section headers
if (!ImageBase && strcmp(sh->segname, "__TEXT")==0) ImageBase = sh->vmaddr; // Find image base
break;}
case MAC_LC_SEGMENT_64: {
if (WordSize != 64) err.submit(2320); // mixed segment size
MAC_segment_command_64 * sh = (MAC_segment_command_64*)currentp;
SegmentOffset = (uint32)sh->fileoff; // File offset of segment
SegmentSize = (uint32)sh->filesize; // Size of segment
NumSections = sh->nsects; // Number of sections
SectionHeaderOffset = currentoffset + sizeof(TMAC_segment_command); // File offset of section headers
if (!ImageBase && strcmp(sh->segname, "__TEXT")==0) ImageBase = sh->vmaddr; // Find image base
break;}
case MAC_LC_SYMTAB: {
MAC_symtab_command * sh = (MAC_symtab_command*)currentp;
SymTabOffset = sh->symoff; // File offset of symbol table
SymTabNumber = sh->nsyms; // Number of entries in symbol table
StringTabOffset = sh->stroff; // File offset of string table
StringTabSize = sh->strsize; // Size of string table
break;}
case MAC_LC_DYSYMTAB: {
MAC_dysymtab_command * sh = (MAC_dysymtab_command*)currentp;
ilocalsym = sh->ilocalsym; // index to local symbols
nlocalsym = sh->nlocalsym; // number of local symbols
iextdefsym = sh->iextdefsym; // index to externally defined symbols
nextdefsym = sh->nextdefsym; // number of externally defined symbols
iundefsym = sh->iundefsym; // index to undefined symbols
nundefsym = sh->nundefsym; // number of undefined symbols
IndirectSymTabOffset = sh->indirectsymoff;// file offset to the indirect symbol table
IndirectSymTabNumber = sh->nindirectsyms; // number of indirect symbol table entries
break;}
}
currentoffset += cmdsize;
}
}
// Debug dump
template <class TMAC_header, class TMAC_segment_command, class TMAC_section, class TMAC_nlist, class MInt>
void CMACHO<MACSTRUCTURES>::Dump(int options) {
uint32 icmd; // Command index
int32 isec1; // Section index within segment
int32 isec2; // Section index global
int32 nsect; // Number of sections in segment
if (options & DUMP_FILEHDR) {
// File header
printf("\nDump of Mach-O file %s", FileName);
printf("\n-----------------------------------------------");
printf("\nFile size: 0x%X", this->GetDataSize());
printf("\nFile header:");
printf("\n CPU type: %s, subtype: %s",
Lookup(MacMachineNames, FileHeader.cputype),
Lookup(MacCPUSubtypeNames, FileHeader.cpusubtype));
printf("\n File type: %s - %s",
GetFileFormatName(FileType), Lookup(MacFileTypeNames, FileHeader.filetype));
printf("\n Number of load commands: %i, Size of commands: 0x%X, Flags: %X",
FileHeader.ncmds, FileHeader.sizeofcmds, FileHeader.flags);
}
uint32 cmd; // Load command
uint32 cmdsize; // Command size
// Pointer to current position
uint8 * currentp = (uint8*)(Buf() + sizeof(TMAC_header));
// Loop through file commands
for (icmd = 1; icmd <= FileHeader.ncmds; icmd++) {
cmd = ((MAC_load_command*)currentp) -> cmd;
cmdsize = ((MAC_load_command*)currentp) -> cmdsize;
if (options & DUMP_SECTHDR) {
// Dump command header
printf("\n\nCommand %i: %s, size: 0x%X", icmd,
Lookup(MacCommandTypeNames, cmd), cmdsize);
// Interpret specific command type
switch(cmd) {
case MAC_LC_SEGMENT: {
MAC_segment_command_32 * sh = (MAC_segment_command_32*)currentp;
printf("\n Name: %s, Memory address 0x%X, Memory size 0x%X"
"\n File offset 0x%X, File size 0x%X, Maxprot 0x%X, Initprot 0x%X"
"\n Number of sections %i, Flags 0x%X",
sh->segname, sh->vmaddr, sh->vmsize,
sh->fileoff, sh->filesize, sh->maxprot, sh->initprot,
sh->nsects, sh->flags);
break;}
case MAC_LC_SEGMENT_64: {
MAC_segment_command_64 * sh = (MAC_segment_command_64*)currentp;
printf("\n Name: %s, \n Memory address 0x%08X%08X, Memory size 0x%08X%08X"
"\n File offset 0x%08X%08X, File size 0x%08X%08X\n Maxprot 0x%X, Initprot 0x%X"
"\n Number of sections %i, Flags 0x%X",
sh->segname, (uint32)(sh->vmaddr>>32), (uint32)sh->vmaddr,
(uint32)(sh->vmsize>>32), (uint32)sh->vmsize,
(uint32)(sh->fileoff>>32), (uint32)sh->fileoff,
(uint32)(sh->filesize>>32), (uint32)sh->filesize,
sh->maxprot, sh->initprot,
sh->nsects, sh->flags);
break;}
case MAC_LC_SYMTAB: {
MAC_symtab_command * sh = (MAC_symtab_command*)currentp;
printf("\n Symbol table offset 0x%X, number of symbols %i,"
"\n String table offset 0x%X, String table size 0x%X",
sh->symoff, sh->nsyms, sh->stroff, sh->strsize);
break;}
case MAC_LC_DYSYMTAB: {
MAC_dysymtab_command * sh = (MAC_dysymtab_command*)currentp;
printf("\n Index to local symbols %i, number of local symbols %i,"
"\n Index to external symbols %i, number of external symbols %i,"
"\n Index to undefined symbols %i, number of undefined symbols %i,"
"\n File offset to TOC 0x%X, number of entries in TOC %i,",
sh->ilocalsym, sh->nlocalsym, sh->iextdefsym, sh->nextdefsym,
sh->iundefsym, sh->nundefsym, sh->tocoff, sh->ntoc);
printf("\n File offset to module table 0x%X, Number of module table entries %i,"
"\n Offset to referenced symbol table 0x%X, Number of referenced symtab entries %i"
"\n Offset to indirect symbol table 0x%X, Number of indirect symtab entries %i"
"\n Offset to external relocation entries 0x%X, Number of external reloc. entries %i"
"\n Offset to local relocation entries 0x%X, Number of local reloc. entries %i",
sh->modtaboff, sh->nmodtab, sh->extrefsymoff, sh->nextrefsyms,
sh->indirectsymoff, sh->nindirectsyms, sh->extreloff, sh->nextrel,
sh->locreloff, sh->nlocrel);
break;}
}
}
currentp += cmdsize;
}
// Dump section headers
if (options & DUMP_SECTHDR) {
printf("\n\nSections:");
// Reset current pointer
currentp = (uint8*)(Buf() + sizeof(TMAC_header));
isec2 = 0;
// Loop through load commands
for (icmd = 1; icmd <= FileHeader.ncmds; icmd++) {
cmd = ((MAC_load_command*)currentp) -> cmd;
cmdsize = ((MAC_load_command*)currentp) -> cmdsize;
if (cmd == MAC_LC_SEGMENT) {
// This is a 32-bit segment command
// Number of sections in segment
nsect = ((MAC_segment_command_32*)currentp) -> nsects;
// Find first section header
MAC_section_32 * sectp = (MAC_section_32*)(currentp + sizeof(MAC_segment_command_32));
// Loop through section headers
for (isec1 = 1; isec1 <= nsect; isec1++, sectp++) {
printf("\n\nSection %i: Name: %s, Segment: %s.",
++isec2, sectp->sectname, sectp->segname);
printf("\n Memory address 0x%X, Size 0x%X, File offset 0x%X"
"\n Alignment %i, Reloc. ent. offset 0x%X, Num reloc. %i"
"\n Flags 0x%X, reserved1 0x%X, reserved2 0x%X",
sectp->addr, sectp->size, sectp->offset, 1 << sectp->align,
sectp->reloff, sectp->nreloc, sectp->flags,
sectp->reserved1, sectp->reserved2);
if (sectp->nreloc && (options & DUMP_RELTAB)) {
// Dump relocations
printf("\n Relocations:");
if (sectp->reloff >= this->GetDataSize()) {err.submit(2035); break;}
MAC_relocation_info * relp = (MAC_relocation_info*)(Buf() + sectp->reloff);
for (uint32 r = 1; r <= sectp->nreloc; r++, relp++) {
if (relp->r_address & R_SCATTERED) {
// scattered relocation into
MAC_scattered_relocation_info * scatp = (MAC_scattered_relocation_info*)relp;
if (!(scatp->r_type & MAC32_RELOC_PAIR)) {
printf ("\n Offset: 0x%X, Value: 0x%X, Length: %i, Scat. Type: %s",
scatp->r_address, scatp->r_value, 1 << scatp->r_length,
Lookup(Mac32RelocationTypeNames, scatp->r_type));
if (scatp->r_address < sectp->size) {
printf(", Inline: 0x%X", *(int32*)(Buf()+sectp->offset+scatp->r_address));
}
}
else {
// Second entry of a pair
printf ("\n Offset2: 0x%X, Value2: 0x%X, Length2: %i",
scatp->r_address, scatp->r_value, 1 << scatp->r_length);
}
if (scatp->r_pcrel) printf(", PC relative");
}
else {
// non-scattered
if (relp->r_extern) printf ("\n Symbol number %i, ", relp->r_symbolnum);
else printf ("\n Section: %i, ", relp->r_symbolnum);
printf ("Offset: 0x%X, ", relp->r_address);
if (relp->r_pcrel) printf ("PC relative, ");
printf ("\n Length: %i, Extern: %i, Type: %s",
1 << relp->r_length, relp->r_extern,
Lookup(Mac32RelocationTypeNames, relp->r_type));
if (relp->r_address < sectp->size) {
printf(", Inline: 0x%X", *(int32*)(Buf()+sectp->offset+relp->r_address));
}
}
}
}
}
}
if (cmd == MAC_LC_SEGMENT_64) {
// This is a 64-bit segment command
// Number of sections in segment
nsect = ((MAC_segment_command_64*)currentp) -> nsects;
// Find first section header
MAC_section_64 * sectp = (MAC_section_64*)(currentp + sizeof(MAC_segment_command_64));
// Loop through section headers
for (isec1 = 1; isec1 <= nsect; isec1++, sectp++) {
printf("\n\nSection %i: Name: %s, Segment: %s.",
++isec2, sectp->sectname, sectp->segname);
printf("\n Memory address 0x%X, Size 0x%X, File offset 0x%X"
"\n Alignment %i, Reloc. ent. offset 0x%X, Num reloc. %i"
"\n Flags 0x%X, reserved1 0x%X, reserved2 0x%X",
(uint32)sectp->addr, (uint32)sectp->size, sectp->offset, 1 << sectp->align,
sectp->reloff, sectp->nreloc, sectp->flags,
sectp->reserved1, sectp->reserved2);
if (sectp->nreloc && (options & DUMP_RELTAB)) {
// Dump relocations
printf("\n Relocations:");
MAC_relocation_info * relp = (MAC_relocation_info*)(Buf() + sectp->reloff);
for (uint32 r = 1; r <= sectp->nreloc; r++, relp++) {
if (relp->r_address & R_SCATTERED) {
// scattered relocation into (not used in 64-bit Mach-O)
MAC_scattered_relocation_info * scatp = (MAC_scattered_relocation_info*)relp;
if (!(scatp->r_type & MAC32_RELOC_PAIR)) {
printf ("\n Unexpected scattered relocation. Offset: 0x%X, Value: 0x%X, Length: %i, Scat. Type: %s",
scatp->r_address, scatp->r_value, 1 << scatp->r_length,
Lookup(Mac64RelocationTypeNames, scatp->r_type));
if (scatp->r_address < sectp->size) {
printf(", Inline: 0x%X", *(int32*)(Buf()+sectp->offset+scatp->r_address));
}
}
else {
// Second entry of a pair
printf ("\n Offset2: 0x%X, Value2: 0x%X, Length2: %i",
scatp->r_address, scatp->r_value, 1 << scatp->r_length);
}
if (scatp->r_pcrel) printf(", PC relative");
}
else {
// non-scattered
if (relp->r_extern) printf ("\n Symbol number %i, ", relp->r_symbolnum);
else printf ("\n Section: %i, ", relp->r_symbolnum);
printf ("Offset: 0x%X, ", relp->r_address);
if (relp->r_pcrel) printf ("PC relative, ");
printf ("\n Length: %i, Extern: %i, Type: %s",
1 << relp->r_length, relp->r_extern,
Lookup(Mac64RelocationTypeNames, relp->r_type));
if (relp->r_type != MAC64_RELOC_SUBTRACTOR && relp->r_address < sectp->size) {
// Print inline addend
if (relp->r_length == 3) {
// 8 bytes inline addend
printf(", Inline: 0x%08X%08X", *(int32*)(Buf()+sectp->offset+relp->r_address+4), *(int32*)(Buf()+sectp->offset+relp->r_address));
}
else {
// 4 bytes inline addend
printf(", Inline: 0x%08X", *(int32*)(Buf()+sectp->offset+relp->r_address));
}
}
}
}
}
}
}
currentp += cmdsize;
}
}
// pointer to string table
char * strtab = (char*)(Buf() + StringTabOffset);
// pointer to symbol table
TMAC_nlist * symp0 = (TMAC_nlist*)(Buf() + SymTabOffset);
// Dump symbol table
if (options & DUMP_SYMTAB) {
printf("\n\nSymbol table:");
uint32 i;
TMAC_nlist * symp;
// loop through symbol table
for (i = 0, symp = symp0; i < SymTabNumber; i++, symp++) {
// Header for first symbol of each category: (alphabetical within each category)
if (i == ilocalsym && nlocalsym) printf("\n\n Local symbols:");
if (i == iextdefsym && nextdefsym) printf("\n\n Public symbols:");
if (i == iundefsym && nundefsym) printf("\n\n External symbols:");
if (symp->n_strx < StringTabSize && !(symp->n_type & MAC_N_STAB)) {
printf("\n %2i %s, Section %i, Value 0x%X\n ",
i, strtab + symp->n_strx, symp->n_sect, uint32(symp->n_value));
}
else {
printf("\n String table offset: 0x%X, Section %i, Value 0x%X\n ",
symp->n_strx, symp->n_sect, uint32(symp->n_value));
}
if (symp->n_type & MAC_N_STAB) {
printf ("Debug symbol, stab = 0x%X, ", symp->n_type);
}
else {
if (symp->n_type & MAC_N_PEXT) printf ("Private external (limited global scope), ");
if (symp->n_type & MAC_N_EXT ) printf ("External, ");
printf("%s", Lookup(MacSymbolTypeNames, symp->n_type & MAC_N_TYPE));
}
printf("\n Reference type: %s, Flags: ",
Lookup(MacSymbolReferenceTypeNames, symp->n_desc & MAC_REF_TYPE));
for (uint32 f = MAC_REFERENCED_DYNAMICALLY; f <= MAC_N_WEAK_DEF; f <<= 1) {
if (symp->n_desc & f) {
printf("%s, ", Lookup(MacSymbolDescriptorFlagNames, f));
}
}
}
// Check if indirect symbol table is valid
if (IndirectSymTabNumber && IndirectSymTabOffset + IndirectSymTabNumber*4 < this->GetDataSize()) {
// Write indirect symbol table
printf("\n\n Indirect symbols:");
// loop through indirect symbol table
uint32 * IndSymip = (uint32*)(Buf() + IndirectSymTabOffset);
for (i = 0; i < IndirectSymTabNumber; i++, IndSymip++) {
// Check if index within symbol table
if (*IndSymip >= SymTabNumber) {
//err.submit(2016);
printf("\n Unknown(0x%X)", *IndSymip);
continue;
}
// Find record
TMAC_nlist * pIndSym = symp0 + *IndSymip;
// Find name
uint32 StringIndex = pIndSym->n_strx;
if (StringIndex >= StringTabSize) {
err.submit(2035); continue;
}
// print name
printf("\n %s", strtab + StringIndex);
// print type, etc.
printf(", type 0x%X, sect %i, desc 0x%X, val 0x%X",
pIndSym->n_type, pIndSym->n_sect, pIndSym->n_desc, uint32(pIndSym->n_value));
}
}
}
// Dump string table
if (options & DUMP_STRINGTB) {
printf("\n\nString table:");
uint32 str = 0, istr = 0;
while (str < StringTabSize) {
char * p = (char*)(Buf() + StringTabOffset + str);
printf("\n %3i: %s", str, p);
istr++; str += (uint32)strlen(p) + 1;
}
}
}
template <class TMAC_header, class TMAC_segment_command, class TMAC_section, class TMAC_nlist, class MInt>
void CMACHO<MACSTRUCTURES>::PublicNames(CMemoryBuffer * Strings, CSList<SStringEntry> * Index, int m) {
// Make list of public names
uint32 i;
SStringEntry se; // Entry in Index
// Interpret header:
ParseFile();
// pointer to string table
char * strtab = (char*)(Buf() + StringTabOffset);
// loop through public symbol table
TMAC_nlist * symp = (TMAC_nlist*)(Buf() + SymTabOffset + iextdefsym * sizeof(TMAC_nlist));
for (i = 0; i < nextdefsym; i++, symp++) {
if (symp->n_strx < StringTabSize && !(symp->n_type & MAC_N_STAB)) {
// Public symbol found
se.Member = m;
// Store name
se.String = Strings->PushString(strtab + symp->n_strx);
// Store name index
Index->Push(se);
}
}
}
// Member functions for class MacSymbolTableBuilder
template <class TMAC_nlist, class MInt>
MacSymbolTableBuilder<TMAC_nlist, MInt>::MacSymbolTableBuilder() { // Constructor
sorted = 0;
}
template <class TMAC_nlist, class MInt>
void MacSymbolTableBuilder<TMAC_nlist, MInt>::AddSymbol(int OldIndex, const char * name, int type, int Desc, int section, MInt value) {
// Add symbol to list
MacSymbolRecord<TMAC_nlist> rec;
memset(&rec, 0, sizeof(rec)); // Set to zero
/* !!
if (GetNumEntries() == 0) {
// First record must indicate empty string
rec.Name = StringBuffer.PushString(""); // Empty string
Push(&rec, sizeof(rec)); // Put empty record in memory buffer
}
*/
rec.n_type = (uint8)type; // Copy values
rec.n_sect = (uint8)section;
rec.n_desc = (int16)Desc;
rec.n_value = value;
rec.Name = StringBuffer.PushString(name); // Copy name and store index
rec.OldIndex = OldIndex; // Remember old index
Push(&rec, sizeof(rec)); // Put in memory buffer
sorted = 0; // Remember not sorted
}
template <class TMAC_nlist, class MInt>
void MacSymbolTableBuilder<TMAC_nlist, MInt>::SortList() {
// Sort the list
if (sorted) return; // allready sorted
MacSymbolRecord<TMAC_nlist> * p = (MacSymbolRecord<TMAC_nlist>*)Buf(); // Point to list
// Simple Shell sort with Sedgewick gaps:
int i, j, k, gap, n = (int)GetNumEntries();
for (k = 15; k >= 0; k--) {
gap = (1 << 2 * k) | (3 << k >> 1) | 1; // Sedgewick gap grants O(N^4/3)
for (i = gap; i < n; i++) {
MacSymbolRecord<TMAC_nlist> key = p[i];
char * strkey = StringBuffer.Buf() + key.Name;
for (j = i - gap; j >= 0 && strcmp(strkey, StringBuffer.Buf() + p[j].Name) < 0; j -= gap) {
p[j + gap] = p[j];
}
p[j + gap] = key;
}
}
sorted = 1;
}
template <class TMAC_nlist, class MInt>
int MacSymbolTableBuilder<TMAC_nlist, MInt>::TranslateIndex(int OldIndex) {
// Translate old index to new index (0-based)
// Returns -1 if not found
// Don't sort list. This would change indices if __mh_executer_header added later
// if (!sorted) SortList();
MacSymbolRecord<TMAC_nlist> * p = (MacSymbolRecord<TMAC_nlist>*)Buf(); // Point to list
// Search through list for OldIndex
for (int i = 0; i < (int)GetNumEntries(); i++) {
if (p[i].OldIndex == OldIndex) {
// Match found
return i;
}
}
// Not found
return -1;
}
template <class TMAC_nlist, class MInt>
void MacSymbolTableBuilder<TMAC_nlist, MInt>::StoreList(CMemoryBuffer * SymbolTable, CMemoryBuffer * StringTable) {
// Store sorted list in buffers
// Don't sort list unless commanded to do so. Will mess up indices
// if (!sorted) SortList(); // Make sure list is sorted
MacSymbolRecord<TMAC_nlist> * p = (MacSymbolRecord<TMAC_nlist>*)Buf(); // Point to list
for (uint32 i = 0; i < GetNumEntries(); i++, p++) {
p->n_strx = StringTable->PushString(StringBuffer.Buf()+p->Name); // Put name in string table
SymbolTable->Push(p, sizeof(TMAC_nlist)); // Store only the TMAC_nlist part of the record in SymbolTable
}
}
template <class TMAC_nlist, class MInt>
int MacSymbolTableBuilder<TMAC_nlist, MInt>::Search(const char * name) {
// Search for name. Return -1 if not found.
MacSymbolRecord<TMAC_nlist> * p = (MacSymbolRecord<TMAC_nlist>*)Buf(); // Point to list
for (int i = 0; i < (int)GetNumEntries(); i++) {
if (strcmp(StringBuffer.Buf()+p[i].Name, name) == 0) {
return i; // Found
}
}
return -1; // Not found
}
template <class TMAC_nlist, class MInt>
MacSymbolRecord<TMAC_nlist> & MacSymbolTableBuilder<TMAC_nlist, MInt>::operator[] (uint32 i) {
// Access member
uint32 Offset = i * sizeof(MacSymbolRecord<TMAC_nlist>);
if (i + sizeof(MacSymbolRecord<TMAC_nlist>) > this->GetDataSize()) {
err.submit(9003); Offset = 0;
}
return Get<MacSymbolRecord<TMAC_nlist> >(Offset);
}
/****** Class CMACUNIV for parsing Macintosh universal binary *************/
CMACUNIV::CMACUNIV() {
// Default constructor
}
void CMACUNIV::Go(int options) {
// Apply command options to all components
// Check file size
if (GetDataSize() < 28) return;
// Read number of components
uint32 NumComponents = EndianChange(Get<MAC_UNIV_FAT_HEADER>(0).num_arch);
if (NumComponents == 0 || NumComponents > 10) {
// Number of components too big or too small
err.submit(2701, NumComponents);
return;
}
uint32 i; // Component number
uint32 fo; // File offset of component pointer
CConverter ComponentBuffer; // Used for converting component
CConverter OutputBuffer; // Temporary storage of output file
int DesiredWordSize = cmd.DesiredWordSize; // Desired word size, if specified on command line
// Loop through components
for (i = 0, fo = sizeof(MAC_UNIV_FAT_HEADER); i < NumComponents; i++, fo += sizeof(MAC_UNIV_FAT_ARCH)) {
// Get component pointer
MAC_UNIV_FAT_ARCH & ComponentPointer = Get<MAC_UNIV_FAT_ARCH>(fo);
// Get offset and size of component
uint32 ComponentOffset = EndianChange(ComponentPointer.offset);
uint32 ComponentSize = EndianChange(ComponentPointer.size);
// Check within range
if (ComponentOffset + ComponentSize > GetDataSize()) {
err.submit(2016);
return;
}
// Put component into buffer
ComponentBuffer.Reset();
ComponentBuffer.Push(Buf() + ComponentOffset, ComponentSize);
// Indicate component
printf("\n\n\nComponent file number %i:\n", i + 1);
// Check type
uint32 ComponentType = ComponentBuffer.GetFileType();
if (DesiredWordSize && DesiredWordSize != ComponentBuffer.WordSize) {
err.submit(1151, ComponentBuffer.WordSize);
}
else if (ComponentType != FILETYPE_MACHO_LE) {
// Format not supported
printf(" Format not supported: %s", GetFileFormatName(ComponentType));
}
else {
// Format OK. Handle component
if (cmd.DumpOptions == 0 && OutputBuffer.GetDataSize()) {
// More than one component that can be converted
err.submit(1150);
}
else {
// Transfer filenames
ComponentBuffer.FileName = FileName;
ComponentBuffer.OutputFileName = OutputFileName;
// Do command
ComponentBuffer.Go();
// Is there an output file?
if (cmd.DumpOptions == 0) {
// Save output file
ComponentBuffer >> OutputBuffer;
}
}
}
}
// Is there an output file?
if (OutputBuffer.GetDataSize()) {
// Take over output file and skip remaining components
*this << OutputBuffer;
}
}
// Make template instances for 32 and 64 bits
template class CMACHO<MAC32STRUCTURES>;
template class CMACHO<MAC64STRUCTURES>;
template class MacSymbolTableBuilder<MAC_nlist_32, int32>;
template class MacSymbolTableBuilder<MAC_nlist_64, int64>;

View File

@ -0,0 +1,791 @@
/**************************** macho.h ****************************************
* Author: Agner Fog
* Date created: 2007-01-06
* Last modified: 2008-05-23
* Project: objconv
* Module: macho.h
* Description:
* Header file for definition of data structures in 32 bit Mach-O object file.
* Also defines class MacSymbolTableBuilder
* Also defines structures for MacIntosh universal binaries
*
* Copyright 2006-2008 GNU General Public License http://www.gnu.org/licenses
* Parts (c) 2003 Apple public source license http://www.opensource.apple.com/apsl/
***********************************************************************************/
#ifndef MACHO_H
#define MACHO_H
/********************** FILE HEADER **********************/
struct MAC_header_32 {
uint32 magic; // mach magic number identifier
uint32 cputype; // cpu specifier
uint32 cpusubtype; // machine specifier
uint32 filetype; // type of file
uint32 ncmds; // number of load commands
uint32 sizeofcmds; // the size of all the load commands
uint32 flags; // flags
};
struct MAC_header_64 {
uint32 magic; // mach magic number identifier
uint32 cputype; // cpu specifier
uint32 cpusubtype; // machine specifier
uint32 filetype; // type of file
uint32 ncmds; // number of load commands
uint32 sizeofcmds; // the size of all the load commands
uint32 flags; // flags
uint32 reserved; // reserved for future use
};
// Constant for the magic field of the MAC_header (32-bit architectures)
#define MAC_MAGIC_32 0xFEEDFACE // 32 bit little endian
#define MAC_MAGIC_64 0xFEEDFACF // 64 bit little endian
#define MAC_CIGAM_32 0xCEFAEDFE // 32 bit big endian
#define MAC_CIGAM_64 0xCFFAEDFE // 64 bit big endian
#define MAC_CIGAM_UNIV 0xBEBAFECA // MacIntosh universal binary
// Constants for cputype
#define MAC_CPU_TYPE_I386 7
#define MAC_CPU_TYPE_X86_64 0x1000007
#define MAC_CPU_TYPE_ARM 12
#define MAC_CPU_TYPE_SPARC 14
#define MAC_CPU_TYPE_POWERPC 18
#define MAC_CPU_TYPE_POWERPC64 0x1000012
// Constants for cpusubtype
#define MAC_CPU_SUBTYPE_I386_ALL 3
#define MAC_CPU_SUBTYPE_X86_64_ALL 3
#define MAC_CPU_SUBTYPE_ARM_ALL 0
#define MAC_CPU_SUBTYPE_SPARC_ALL 0
#define MAC_CPU_SUBTYPE_POWERPC_ALL 0
// Constants for the filetype field of the MAC_header
#define MAC_OBJECT 0x1 /* relocatable object file */
#define MAC_EXECUTE 0x2 /* demand paged executable file */
#define MAC_FVMLIB 0x3 /* fixed VM shared library file */
#define MAC_CORE 0x4 /* core file */
#define MAC_PRELOAD 0x5 /* preloaded executable file */
#define MAC_DYLIB 0x6 /* dynamicly bound shared library file*/
#define MAC_DYLINKER 0x7 /* dynamic link editor */
#define MAC_BUNDLE 0x8 /* dynamicly bound bundle file */
// Constants for the flags field of the MAC_header
#define MAC_NOUNDEFS 0x1 // the object file has no undefined references, can be executed
#define MAC_INCRLINK 0x2 // the object file is the output of an incremental link against a base file and can't be link edited again
#define MAC_DYLDLINK 0x4 // the object file is input for the dynamic linker and can't be staticly link edited again
#define MAC_BINDATLOAD 0x8 // the object file's undefined references are bound by the dynamic linker when loaded.
#define MAC_PREBOUND 0x10 // the file has it's dynamic undefined references prebound.
#define MAC_SPLIT_SEGS 0x20 // the file has its read-only and read-write segments split
#define MAC_LAZY_INIT 0x40 // the shared library init routine is to be run lazily via catching memory faults to its writeable segments (obsolete)
#define MAC_TWOLEVEL 0x80 // the image is using two-level name space bindings
#define MAC_FORCE_FLAT 0x100 // the executable is forcing all images to use flat name space bindings
#define MAC_NOMULTIDEFS 0x200 // this umbrella guarantees no multiple defintions of symbols in its sub-images so the two-level namespace hints can always be used
#define MAC_NOFIXPREBINDING 0x400 // do not have dyld notify the prebinding agent about this executable
#define MAC_PREBINDABLE 0x800 // the binary is not prebound but can have its prebinding redone. only used when MH_PREBOUND is not set
#define MAC_ALLMODSBOUND 0x1000 // indicates that this binary binds to all two-level namespace modules of its dependent libraries. only used when MH_PREBINDABLE and MH_TWOLEVEL are both set
#define MAC_SUBSECTIONS_VIA_SYMBOLS 0x2000 // safe to divide up the sections into sub-sections via symbols for dead code stripping
#define MAC_CANONICAL 0x4000 // the binary has been canonicalized via the unprebind operation
//??
#define MAC_VM_PROT_NONE 0x00
#define MAC_VM_PROT_READ 0x01
#define MAC_VM_PROT_WRITE 0x02
#define MAC_VM_PROT_EXECUTE 0x04
#define MAC_VM_PROT_ALL 0x07
// Load commands
struct MAC_load_command {
uint32 cmd; // type of load command
uint32 cmdsize; // total size of command in bytes
};
// Constants for the cmd field of all load commands, the type
#define MAC_LC_REQ_DYLD 0x80000000 // This bit is added if unknown command cannot be ignored
#define MAC_LC_SEGMENT 0x1 /* segment of this file to be mapped */
#define MAC_LC_SYMTAB 0x2 /* link-edit stab symbol table info */
#define MAC_LC_SYMSEG 0x3 /* link-edit gdb symbol table info (obsolete) */
#define MAC_LC_THREAD 0x4 /* thread */
#define MAC_LC_UNIXTHREAD 0x5 /* unix thread (includes a stack) */
#define MAC_LC_LOADFVMLIB 0x6 /* load a specified fixed VM shared library */
#define MAC_LC_IDFVMLIB 0x7 /* fixed VM shared library identification */
#define MAC_LC_IDENT 0x8 /* object identification info (obsolete) */
#define MAC_LC_FVMFILE 0x9 /* fixed VM file inclusion (internal use) */
#define MAC_LC_PREPAGE 0xa /* prepage command (internal use) */
#define MAC_LC_DYSYMTAB 0xb /* dynamic link-edit symbol table info */
#define MAC_LC_LOAD_DYLIB 0xc /* load a dynamicly linked shared library */
#define MAC_LC_ID_DYLIB 0xd /* dynamicly linked shared lib identification */
#define MAC_LC_LOAD_DYLINKER 0xe /* load a dynamic linker */
#define MAC_LC_ID_DYLINKER 0xf /* dynamic linker identification */
#define MAC_LC_PREBOUND_DYLIB 0x10 /* modules prebound for a dynamicly linked shared library */
#define MAC_LC_ROUTINES 0x11 /* image routines */
#define MAC_LC_SUB_FRAMEWORK 0x12 /* sub framework */
#define MAC_LC_SUB_UMBRELLA 0x13 /* sub umbrella */
#define MAC_LC_SUB_CLIENT 0x14 /* sub client */
#define MAC_LC_SUB_LIBRARY 0x15 /* sub library */
#define MAC_LC_TWOLEVEL_HINTS 0x16 /* two-level namespace lookup hints */
#define MAC_LC_PREBIND_CKSUM 0x17 /* prebind checksum */
#define MAC_LC_LOAD_WEAK_DYLIB (0x18 | MAC_LC_REQ_DYLD)
#define MAC_LC_SEGMENT_64 0x19 /* 64-bit segment of this file to be mapped */
#define MAC_LC_ROUTINES_64 0x1a /* 64-bit image routines */
#define MAC_LC_UUID 0x1b /* the uuid */
/*
* The segment load command indicates that a part of this file is to be
* mapped into the task's address space. The size of this segment in memory,
* vmsize, maybe equal to or larger than the amount to map from this file,
* filesize. The file is mapped starting at fileoff to the beginning of
* the segment in memory, vmaddr. The rest of the memory of the segment,
* if any, is allocated zero fill on demand. The segment's maximum virtual
* memory protection and initial virtual memory protection are specified
* by the maxprot and initprot fields. If the segment has sections then the
* section structures directly follow the segment command and their size is
* reflected in cmdsize.
*/
struct MAC_segment_command_32 { /* for 32-bit architectures */
uint32 cmd; /* LC_SEGMENT */
uint32 cmdsize; /* includes sizeof section structs */
char segname[16]; /* segment name */
uint32 vmaddr; /* memory address of this segment */
uint32 vmsize; /* memory size of this segment */
uint32 fileoff; /* file offset of this segment */
uint32 filesize; /* amount to map from the file */
uint32 maxprot; /* maximum VM protection */
uint32 initprot; /* initial VM protection */
uint32 nsects; /* number of sections in segment */
uint32 flags; /* flags */
};
/*
* The 64-bit segment load command indicates that a part of this file is to be
* mapped into a 64-bit task's address space. If the 64-bit segment has
* sections then section_64 structures directly follow the 64-bit segment
* command and their size is reflected in cmdsize.
*/
struct MAC_segment_command_64 { /* for 64-bit architectures */
uint32 cmd; /* LC_SEGMENT_64 */
uint32 cmdsize; /* includes sizeof section_64 structs */
char segname[16]; /* segment name */
uint64 vmaddr; /* memory address of this segment */
uint64 vmsize; /* memory size of this segment */
uint64 fileoff; /* file offset of this segment */
uint64 filesize; /* amount to map from the file */
uint32 maxprot; /* maximum VM protection */
uint32 initprot; /* initial VM protection */
uint32 nsects; /* number of sections in segment */
uint32 flags; /* flags */
};
/* Constants for the flags field of the segment_command */
#define MAC_SG_HIGHVM 0x1 // the file contents for this segment is for the high part of the
// VM space, the low part is zero filled (for stacks in core files)
#define MAC_SG_FVMLIB 0x2 // this segment is the VM that is allocated by a fixed VM library,
// for overlap checking in the link editor
#define MAC_SG_NORELOC 0x4 // this segment has nothing that was relocated in it and nothing
// relocated to it, that is it maybe safely replaced without relocation
/*
* A segment is made up of zero or more sections. Non-MH_OBJECT files have
* all of their segments with the proper sections in each, and padded to the
* specified segment alignment when produced by the link editor. The first
* segment of a MH_EXECUTE and MH_FVMLIB format file contains the mach_header
* and load commands of the object file before it's first section. The zero
* fill sections are always last in their segment (in all formats). This
* allows the zeroed segment padding to be mapped into memory where zero fill
* sections might be. The gigabyte zero fill sections, those with the section
* type S_GB_ZEROFILL, can only be in a segment with sections of this type.
* These segments are then placed after all other segments.
*
* The MH_OBJECT format has all of it's sections in one segment for
* compactness. There is no padding to a specified segment boundary and the
* mach_header and load commands are not part of the segment.
*
* Sections with the same section name, sectname, going into the same segment,
* segname, are combined by the link editor. The resulting section is aligned
* to the maximum alignment of the combined sections and is the new section's
* alignment. The combined sections are aligned to their original alignment in
* the combined section. Any padded bytes to get the specified alignment are
* zeroed.
*
* The format of the relocation entries referenced by the reloff and nreloc
* fields of the section structure for mach object files is described in the
* header file <reloc.h>.
*/
struct MAC_section_32 { /* for 32-bit architectures */
char sectname[16]; /* name of this section */
char segname[16]; /* segment this section goes in */
uint32 addr; /* memory address of this section */
uint32 size; /* size in bytes of this section */
uint32 offset; /* file offset of this section */
uint32 align; /* section alignment (power of 2) */
uint32 reloff; /* file offset of relocation entries */
uint32 nreloc; /* number of relocation entries */
uint32 flags; /* flags (section type and attributes)*/
uint32 reserved1; /* reserved */
uint32 reserved2; /* reserved */
};
struct MAC_section_64 { /* for 64-bit architectures */
char sectname[16]; /* name of this section */
char segname[16]; /* segment this section goes in */
uint64 addr; /* memory address of this section */
uint64 size; /* size in bytes of this section */
uint32 offset; /* file offset of this section */
uint32 align; /* section alignment (power of 2) */
uint32 reloff; /* file offset of relocation entries */
uint32 nreloc; /* number of relocation entries */
uint32 flags; /* flags (section type and attributes)*/
uint32 reserved1; /* reserved (for offset or index) */
uint32 reserved2; /* reserved (for count or sizeof) */
uint32 reserved3; // reserved (Note: specified in loader.h, but not in MachORuntime.pdf)
};
/* The flags field of a section structure is separated into two parts a section
* type and section attributes. The section types are mutually exclusive (it
* can only have one type) but the section attributes are not (it may have more
* than one attribute). */
#define MAC_SECTION_TYPE 0x000000ff /* 256 section types */
#define MAC_SECTION_ATTRIBUTES 0xffffff00 /* 24 section attributes */
/* Constants for the type of a section */
#define MAC_S_REGULAR 0x0 /* regular section */
#define MAC_S_ZEROFILL 0x1 /* zero fill on demand section */
#define MAC_S_CSTRING_LITERALS 0x2 /* section with only literal C strings*/
#define MAC_S_4BYTE_LITERALS 0x3 /* section with only 4 byte literals */
#define MAC_S_8BYTE_LITERALS 0x4 /* section with only 8 byte literals */
#define MAC_S_LITERAL_POINTERS 0x5 /* section with only pointers to literals */
/* For the two types of symbol pointers sections and the symbol stubs section
* they have indirect symbol table entries. For each of the entries in the
* section the indirect symbol table entries, in corresponding order in the
* indirect symbol table, start at the index stored in the reserved1 field
* of the section structure. Since the indirect symbol table entries
* correspond to the entries in the section the number of indirect symbol table
* entries is inferred from the size of the section divided by the size of the
* entries in the section. For symbol pointers sections the size of the entries
* in the section is 4 bytes and for symbol stubs sections the byte size of the
* stubs is stored in the reserved2 field of the section structure. */
#define MAC_S_NON_LAZY_SYMBOL_POINTERS 0x6 // section with only non-lazy symbol pointers
#define MAC_S_LAZY_SYMBOL_POINTERS 0x7 // section with only lazy symbol pointers
#define MAC_S_SYMBOL_STUBS 0x8 // section with only symbol stubs, byte size of stub in the reserved2 field
#define MAC_S_MOD_INIT_FUNC_POINTERS 0x9 // section with only function pointers for initialization
#define MAC_S_MOD_TERM_FUNC_POINTERS 0xa // section with only function pointers for termination
#define MAC_S_COALESCED 0xb // section contains symbols that are to be coalesced
#define MAC_S_GB_ZEROFILL 0xc // zero fill on demand section that can be larger than 4 gigabytes
#define MAC_S_INTERPOSING 0xd // section with only pairs of function pointers for interposing
#define MAC_S_16BYTE_LITERALS 0xe // section with only 16 byte literals
// Constants for the section attributes part of the flags field of a section structure.
#define MAC_SECTION_ATTRIBUTES_USR 0xff000000 /* User setable attributes */
#define MAC_S_ATTR_PURE_INSTRUCTIONS 0x80000000 /* section contains only true machine instructions */
#define MAC_S_ATTR_NO_TOC 0x40000000 /* section contains coalesced symbols that are not to be in a ranlib table of contents */
#define MAC_S_ATTR_STRIP_STATIC_SYMS 0x20000000 /* ok to strip static symbols in this section in files with the MH_DYLDLINK flag */
#define MAC_S_ATTR_NO_DEAD_STRIP 0x10000000 /* no dead stripping */
#define MAC_S_ATTR_LIVE_SUPPORT 0x08000000 /* blocks are live if they reference live blocks */
#define MAC_S_ATTR_SELF_MODIFYING_CODE 0x04000000 /* Used with i386 code stubs written on by dyld */
#define MAC_S_ATTR_DEBUG 0x02000000 /* a debug section */
#define MAC_SECTION_ATTRIBUTES_SYS 0x00ffff00 /* system setable attributes */
#define MAC_S_ATTR_SOME_INSTRUCTIONS 0x00000400 /* section contains some machine instructions */
#define MAC_S_ATTR_EXT_RELOC 0x00000200 /* section has external relocation entries */
#define MAC_S_ATTR_LOC_RELOC 0x00000100 /* section has local relocation entries */
/* The names of segments and sections in them are mostly meaningless to the
* link-editor. But there are few things to support traditional UNIX
* executables that require the link-editor and assembler to use some names
* agreed upon by convention.
*
* The initial protection of the "__TEXT" segment has write protection turned
* off (not writeable).
*
* The link-editor will allocate common symbols at the end of the "__common"
* section in the "__DATA" segment. It will create the section and segment
* if needed. */
/* The currently known segment names and the section names in those segments */
#define MAC_SEG_PAGEZERO "__PAGEZERO" // the pagezero segment which has no protections and catches NULL references for MH_EXECUTE files
#define MAC_SEG_TEXT "__TEXT" // the tradition UNIX text segment
#define MAC_SECT_TEXT "__text" // the real text part of the text section no headers, and no padding
#define MAC_SECT_FVMLIB_INIT0 "__fvmlib_init0" // the fvmlib initialization section
#define MAC_SECT_FVMLIB_INIT1 "__fvmlib_init1" // the section following the fvmlib initialization section
#define MAC_SEG_DATA "__DATA" // the tradition UNIX data segment
#define MAC_SECT_DATA "__data" // the real initialized data section no padding, no bss overlap
#define MAC_SECT_BSS "__bss" // the real uninitialized data section no padding
#define MAC_SECT_COMMON "__common" // the section common symbols are allocated in by the link editor
#define MAC_SEG_OBJC "__OBJC" // objective-C runtime segment
#define MAC_SECT_OBJC_SYMBOLS "__symbol_table" // symbol table
#define MAC_SECT_OBJC_MODULES "__module_info" // module information
#define MAC_SECT_OBJC_STRINGS "__selector_strs" // string table
#define MAC_SECT_OBJC_REFS "__selector_refs" // string table
#define MAC_SEG_ICON "__ICON" // the NeXT icon segment
#define MAC_SECT_ICON_HEADER "__header" // the icon headers
#define MAC_SECT_ICON_TIFF "__tiff" // the icons in tiff format
#define MAC_SEG_LINKEDIT "__LINKEDIT" // the segment containing all structs created and maintained by the link editor. Created with -seglinkedit option to ld(1) for MH_EXECUTE and FVMLIB file types only
#define MAC_SEG_UNIXSTACK "__UNIXSTACK" // the unix stack segment
#define MAC_SEG_IMPORT "__IMPORT" // the segment for the self (dyld) modifing code stubs that has read, write and execute permissions
/* The symtab_command contains the offsets and sizes of the link-edit 4.3BSD
* "stab" style symbol table information as described in the header files
* <nlist.h> and <stab.h>. */
struct MAC_symtab_command {
uint32 cmd; /* LC_SYMTAB */
uint32 cmdsize; /* sizeof(MAC_symtab_command) */
uint32 symoff; /* symbol table offset */
uint32 nsyms; /* number of symbol table entries */
uint32 stroff; /* string table offset */
uint32 strsize; /* string table size in bytes */
};
/* This is the second set of the symbolic information which is used to support
* the data structures for the dynamicly link editor.
*
* The original set of symbolic information in the symtab_command which contains
* the symbol and string tables must also be present when this load command is
* present. When this load command is present the symbol table is organized
* into three groups of symbols:
* local symbols (static and debugging symbols) - grouped by module
* defined external symbols - grouped by module (sorted by name if not lib)
* undefined external symbols (sorted by name)
* In this load command there are offsets and counts to each of the three groups
* of symbols.
*
* This load command contains a the offsets and sizes of the following new
* symbolic information tables:
* table of contents
* module table
* reference symbol table
* indirect symbol table
* The first three tables above (the table of contents, module table and
* reference symbol table) are only present if the file is a dynamicly linked
* shared library. For executable and object modules, which are files
* containing only one module, the information that would be in these three
* tables is determined as follows:
* table of contents - the defined external symbols are sorted by name
* module table - the file contains only one module so everything in the
* file is part of the module.
* reference symbol table - is the defined and undefined external symbols
*
* For dynamicly linked shared library files this load command also contains
* offsets and sizes to the pool of relocation entries for all sections
* separated into two groups:
* external relocation entries
* local relocation entries
* For executable and object modules the relocation entries continue to hang
* off the section structures. */
struct MAC_dysymtab_command {
uint32 cmd; /* LC_DYSYMTAB */
uint32 cmdsize; /* sizeof(struct dysymtab_command) */
/* The symbols indicated by symoff and nsyms of the LC_SYMTAB load command
* are grouped into the following three groups:
* local symbols (further grouped by the module they are from)
* defined external symbols (further grouped by the module they are from)
* undefined symbols
*
* The local symbols are used only for debugging. The dynamic binding
* process may have to use them to indicate to the debugger the local
* symbols for a module that is being bound.
*
* The last two groups are used by the dynamic binding process to do the
* binding (indirectly through the module table and the reference symbol
* table when this is a dynamicly linked shared library file). */
uint32 ilocalsym; // index to local symbols
uint32 nlocalsym; // number of local symbols
uint32 iextdefsym; // index to externally defined symbols
uint32 nextdefsym; // number of externally defined symbols
uint32 iundefsym; // index to undefined symbols
uint32 nundefsym; // number of undefined symbols
/* For the dynamic binding process to find which module a symbol
* is defined in the table of contents is used (analogous to the ranlib
* structure in an archive) which maps defined external symbols to modules
* they are defined in. This exists only in a dynamicly linked shared
* library file. For executable and object modules the defined external
* symbols are sorted by name and is use as the table of contents. */
uint32 tocoff; /* file offset to table of contents */
uint32 ntoc; /* number of entries in table of contents */
/* To support dynamic binding of "modules" (whole object files) the symbol
* table must reflect the modules that the file was created from. This is
* done by having a module table that has indexes and counts into the merged
* tables for each module. The module structure that these two entries
* refer to is described below. This exists only in a dynamicly linked
* shared library file. For executable and object modules the file only
* contains one module so everything in the file belongs to the module. */
uint32 modtaboff; /* file offset to module table */
uint32 nmodtab; /* number of module table entries */
/* To support dynamic module binding the module structure for each module
* indicates the external references (defined and undefined) each module
* makes. For each module there is an offset and a count into the
* reference symbol table for the symbols that the module references.
* This exists only in a dynamicly linked shared library file. For
* executable and object modules the defined external symbols and the
* undefined external symbols indicates the external references. */
uint32 extrefsymoff; /* offset to referenced symbol table */
uint32 nextrefsyms; /* number of referenced symbol table entries */
/* The sections that contain "symbol pointers" and "routine stubs" have
* indexes and (implied counts based on the size of the section and fixed
* size of the entry) into the "indirect symbol" table for each pointer
* and stub. For every section of these two types the index into the
* indirect symbol table is stored in the section header in the field
* reserved1. An indirect symbol table entry is simply a 32bit index into
* the symbol table to the symbol that the pointer or stub is referring to.
* The indirect symbol table is ordered to match the entries in the section. */
uint32 indirectsymoff; // file offset to the indirect symbol table
uint32 nindirectsyms; // number of indirect symbol table entries
/* To support relocating an individual module in a library file quickly the
* external relocation entries for each module in the library need to be
* accessed efficiently. Since the relocation entries can't be accessed
* through the section headers for a library file they are separated into
* groups of local and external entries further grouped by module. In this
* case the presents of this load command who's extreloff, nextrel,
* locreloff and nlocrel fields are non-zero indicates that the relocation
* entries of non-merged sections are not referenced through the section
* structures (and the reloff and nreloc fields in the section headers are
* set to zero).
*
* Since the relocation entries are not accessed through the section headers
* this requires the r_address field to be something other than a section
* offset to identify the item to be relocated. In this case r_address is
* set to the offset from the vmaddr of the first LC_SEGMENT command.
*
* The relocation entries are grouped by module and the module table
* entries have indexes and counts into them for the group of external
* relocation entries for that the module.
*
* For sections that are merged across modules there must not be any
* remaining external relocation entries for them (for merged sections
* remaining relocation entries must be local). */
uint32 extreloff; /* offset to external relocation entries */
uint32 nextrel; /* number of external relocation entries */
/* All the local relocation entries are grouped together (they are not
* grouped by their module since they are only used if the object is moved
* from it staticly link edited address). */
uint32 locreloff; /* offset to local relocation entries */
uint32 nlocrel; /* number of local relocation entries */
};
/* An indirect symbol table entry is simply a 32bit index into the symbol table
* to the symbol that the pointer or stub is refering to. Unless it is for a
* non-lazy symbol pointer section for a defined symbol which strip(1) as
* removed. In which case it has the value INDIRECT_SYMBOL_LOCAL. If the
* symbol was also absolute INDIRECT_SYMBOL_ABS is or'ed with that. */
#define MAC_INDIRECT_SYMBOL_LOCAL 0x80000000
#define MAC_INDIRECT_SYMBOL_ABS 0x40000000
// Relocation entries
/* Format of a relocation entry of a Mach-O file. Modified from the 4.3BSD
* format. The modifications from the original format were changing the value
* of the r_symbolnum field for "local" (r_extern == 0) relocation entries.
* This modification is required to support symbols in an arbitrary number of
* sections not just the three sections (text, data and bss) in a 4.3BSD file.
* Also the last 4 bits have had the r_type tag added to them. */
#define R_SCATTERED 0x80000000 // mask to be applied to the r_address field of a relocation_info structure to tell that
// is is really a scattered_relocation_info stucture
struct MAC_relocation_info {
uint32 r_address; // offset in the section to what is being relocated (source)
uint32 r_symbolnum:24, // symbol table index (0-based) if r_extern == 1 or section number (1-based) if r_extern == 0
r_pcrel:1, // pc relative. The target address (inline) is already pc relative
r_length:2, // 0=byte, 1=word, 2=dword
r_extern:1, // r_extern = 1 for symbols in symbol table
r_type:4; // if not 0, machine specific relocation type
}; // The inline value of the source is the target address (pc-relative
// or absolute) if r_extern = 0, or an addend if r_extern = 1.
struct MAC_scattered_relocation_info {
uint32 r_address:24, // offset in the section to what is being relocated (source)
r_type:4, // if not 0, machine specific relocation type
r_length:2, // 0=byte, 1=word, 2=dword, 3=qword
r_pcrel:1, // pc relative. The target address is already pc relative
r_scattered:1; // 1=scattered, 0=non-scattered (see above)
int32 r_value; // target address (without any offset added. The offset is stored inline in the source)
};
// 32-bit relocation types:
/* Relocation types used in a generic implementation. Relocation entries for
* normal things use the generic relocation as discribed above and their r_type
* is GENERIC_RELOC_VANILLA (a value of zero).
*
* Another type of generic relocation, GENERIC_RELOC_SECTDIFF, is to support
* the difference of two symbols defined in different sections. That is the
* expression "symbol1 - symbol2 + constant" is a relocatable expression when
* both symbols are defined in some section. For this type of relocation
* both relocations entries are scattered relocation entries. The value of
* symbol1 is stored in the first relocation entry's r_value field and the
* value of symbol2 is stored in the pair's r_value field.
*
* A special case for a prebound lazy pointer is needed to be able to set the
* value of the lazy pointer back to its non-prebound state. This is done
* using the GENERIC_RELOC_PB_LA_PTR r_type. This is a scattered relocation
* entry where the r_value field is the value of the lazy pointer not prebound. */
/* My interpretation (A Fog):
32-bit: Objects are not addressed by their offset into the section but by
their "absolute" address. This "absolute" address has no reality.
It is the address that the object would have if the section was placed
at the address specified in the addr field of the section header.
Scattered:
The first record, of type MAC32_RELOC_SECTDIFF or MAC32_RELOC_LOCAL_SECTDIFF
contains the "absolute" address of a first reference point, let's call it ref1,
in the r_value field. The second record, of type MAC32_RELOC_PAIR contains the
"absolute" address of a second reference point, ref2, in the r_value field.
The inline value is the "absolute" address of the relocation target minus ref2.
ref1 is often = target, but may be any label preceding the target. The linker
has to add (ref1 - ref2) in image minus (ref1 - ref2) in object file to the
inline value. The relocation source (the position of the inline field) is
given in r_address in the first record, relative the the section.
Non-scattered, absolute, r_extern = 1:
r_symbolnum = symbol index (0-based)
Non-scattered, absolute, r_extern = 0:
r_symbolnum = section index, inline = absolute address of target?
Non-scattered, r_pcrel = 1, r_extern = 1:
r_symbolnum = symbol index (0-based)
Inline = source absolute address - 4
Non-scattered, r_pcrel = 1, r_extern = 0:
r_symbolnum = section index,
inline = absolute address of target - absolute address of source - 4
*/
#define MAC32_RELOC_VANILLA 0 // A generic relocation entry for both addresses contained in data
// and addresses contained in CPU instructions.
#define MAC32_RELOC_PAIR 1 // The second relocation entry of a pair. Only follows a GENERIC_RELOC_SECTDIFF
#define MAC32_RELOC_SECTDIFF 2 // A relocation entry for an item that contains the difference of
// two section addresses. This is generally used for position-independent code generation.
#define MAC32_RELOC_PB_LA_PTR 3 // —Arelocation entry for a prebound lazy pointer. This is always
// a scattered relocation entry. The r_value field contains the non-prebound value of the lazy pointer.
#define MAC32_RELOC_LOCAL_SECTDIFF 4 // SECTDIFF—Similar to GENERIC_RELOC_SECTDIFF except that this entry refers specifically to the address in this item.
// If the address is that of a globally visible coalesced symbol, this relocation entry does not change if the symbol is overridden.
// This is used to associate stack unwinding information with the object code this relocation entry describes.
// 64-bit relocation types:
// Scattered relocations are not used in 64-bit Mach-O.
// reloc.h says that references to local symbols are made by the nearest
// preceding public symbol + displacement, but my experiments show that
// local symbol records are used, which of course is easier.
// r_extern = 1 is used even for non-external symbols!
// The target address is not stored inline. The -4 offset for self-relative
// addresses is implicit, unlike in 32-bit Mach-O. If the difference
// between source address and instruction pointer is e.g. -5, then the
// -4 is implicit, and the -1 is explicit!
#define MAC64_RELOC_UNSIGNED 0 // absolute address, 32 or 64 bits
#define MAC64_RELOC_SIGNED 1 // signed 32-bit displacement with implicit -4 addend
#define MAC64_RELOC_BRANCH 2 // same, used for CALL and JMP instructions
#define MAC64_RELOC_GOT_LOAD 3 // self-relative load of a GOT entry
#define MAC64_RELOC_GOT 4 // other GOT references
#define MAC64_RELOC_SUBTRACTOR 5 // must be followed by a X86_64_RELOC_UNSIGNED
#define MAC64_RELOC_SIGNED_1 6 // signed 32-bit displacement with implicit -4 addend and explicit -1 addend
#define MAC64_RELOC_SIGNED_2 7 // signed 32-bit displacement with implicit -4 addend and explicit -2 addend
#define MAC64_RELOC_SIGNED_4 8 // signed 32-bit displacement with implicit -4 addend and explicit -4 addend
// Symbol table entries
/* Format of a symbol table entry of a Mach-O file. Modified from the BSD
* format. The modifications from the original format were changing n_other
* (an unused field) to n_sect and the addition of the N_SECT type. These
* modifications are required to support symbols in an arbitrary number of
* sections not just the three sections (text, data and bss) in a BSD file. */
struct MAC_nlist_32 {
uint32 n_strx; // index into the string table
uint8 n_type; // type flag, see below
uint8 n_sect; // section number or NO_SECT
int16 n_desc; // see <mach-o/stab.h>
uint32 n_value; // value of this symbol (or stab offset)
};
struct MAC_nlist_64 {
uint32 n_strx; // index into the string table
uint8 n_type; // type flag, see below
uint8 n_sect; // section number or NO_SECT
int16 n_desc; // see <mach-o/stab.h>
uint64 n_value; // value of this symbol (or stab offset)
};
/* Symbols with a index into the string table of zero are
* defined to have a null, "", name. */
/* The n_type field really contains three fields:
* unsigned char N_STAB:3,
* N_PEXT:1,
* N_TYPE:3,
* N_EXT:1;
* which are used via the following masks. */
#define MAC_N_STAB 0xe0 /* if any of these bits set, a symbolic debugging entry */
#define MAC_N_PEXT 0x10 /* private external symbol bit */
#define MAC_N_TYPE 0x0e /* mask for the type bits */
#define MAC_N_EXT 0x01 /* external symbol bit, set for external symbols */
/* Only symbolic debugging entries have some of the N_STAB bits set and if any
* of these bits are set then it is a symbolic debugging entry (a stab). In
* which case then the values of the n_type field (the entire field) are given
* in <mach-o/stab.h> */
// Values for N_TYPE bits of the n_type field.
#define MAC_N_UNDF 0x0 // undefined, n_sect == NO_SECT
#define MAC_N_ABS 0x2 // absolute, n_sect == NO_SECT
#define MAC_N_SECT 0xe // defined in section number n_sect
#define MAC_N_PBUD 0xc // prebound undefined (defined in a dylib)
#define MAC_N_INDR 0xa // indirect
/* If the type is MAC_N_INDR then the symbol is defined to be the same as another
* symbol. In this case the n_value field is an index into the string table
* of the other symbol's name. When the other symbol is defined then they both
* take on the defined type and value. */
/* If the type is MAC_N_SECT then the n_sect field contains an ordinal of the
* section the symbol is defined in. The sections are numbered from 1 and
* refer to sections in order they appear in the load commands for the file
* they are in. This means the same ordinal may very well refer to different
* sections in different files.
*
* The n_value field for all symbol table entries (including N_STAB's) gets
* updated by the link editor based on the value of it's n_sect field and where
* the section n_sect references gets relocated. If the value of the n_sect
* field is NO_SECT then it's n_value field is not changed by the link editor. */
#define MAC_NO_SECT 0 // symbol is not in any section
#define MAC_MAX_SECT 255 // 1 thru 255 inclusive
/* Common symbols are represented by undefined (N_UNDF) external (N_EXT) types
* who's values (n_value) are non-zero. In which case the value of the n_value
* field is the size (in bytes) of the common symbol. The n_sect field is set
* to NO_SECT. */
/* To support the lazy binding of undefined symbols in the dynamic link-editor,
* the undefined symbols in the symbol table (the nlist structures) are marked
* with the indication if the undefined reference is a lazy reference or
* non-lazy reference. If both a non-lazy reference and a lazy reference is
* made to the same symbol the non-lazy reference takes precedence. A reference
* is lazy only when all references to that symbol are made through a symbol
* pointer in a lazy symbol pointer section.
*
* The implementation of marking nlist structures in the symbol table for
* undefined symbols will be to use some of the bits of the n_desc field as a
* reference type. The mask REFERENCE_TYPE will be applied to the n_desc field
* of an nlist structure for an undefined symbol to determine the type of
* undefined reference (lazy or non-lazy).
*
* The constants for the REFERENCE FLAGS are propagated to the reference table
* in a shared library file. In that case the constant for a defined symbol,
* REFERENCE_FLAG_DEFINED, is also used. */
/* Reference type bits of the n_desc field of undefined symbols */
#define MAC_REF_TYPE 0xf
/* types of references */
#define MAC_REF_FLAG_UNDEFINED_NON_LAZY 0
#define MAC_REF_FLAG_UNDEFINED_LAZY 1
#define MAC_REF_FLAG_DEFINED 2
#define MAC_REF_FLAG_PRIVATE_DEFINED 3
#define MAC_REF_FLAG_PRIVATE_UNDEFINED_NON_LAZY 4
#define MAC_REF_FLAG_PRIVATE_UNDEFINED_LAZY 5
/* To simplify stripping of objects that use are used with the dynamic link
* editor, the static link editor marks the symbols defined an object that are
* referenced by a dynamicly bound object (dynamic shared libraries, bundles).
* With this marking strip knows not to strip these symbols. */
/* The non-reference type bits of the n_desc field for global symbols are
* reserved for the dynamic link editor. All of these bits must start out
* zero in the object file. */
// Additional n_desc flags
#define MAC_REFERENCED_DYNAMICALLY 0x10 // Must be set for any defined symbol that is referenced by dynamic-loader APIs (such as dlsym and NSLookupSymbolInImage) and not ordinary
// undefined symbol references. The strip tool uses this bit to avoid removing symbols that must exist: If the symbol has this bit set, strip does not strip it.
#define MAC_N_DESC_DISCARDED 0x20 // Sometimes used by the dynamic linker at runtime in a fully linked image. Do not set this bit in a fully linked image.
//#define MAC_N_DESC_DISCARDED 0x8000
#define MAC_N_NO_DEAD_STRIP 0x20 // When set in a relocatable object file (file type MH_OBJECT) on a defined symbol,
// indicates to the static linker to never dead-strip the symbol. (Note that the same bit (0x20) is used for two nonoverlapping purposes.)
#define MAC_N_WEAK_REF 0x40 // Indicates that this undefined symbol is aweak reference. If the dynamic linker cannot find a definition
// for this symbol, it sets the address of this symbol to 0. The static linker sets this symbol given the appropriate weak-linking flags.
#define MAC_N_WEAK_DEF 0x80 // Indicates that this symbol is a weak definition. If the static linker or the dynamic linker finds another
// (non-weak) definition for this symbol, theweak definition is ignored. Only symbols in a coalesced section (page 21) can be marked as a weak definition.
// Data structure used when sorting symbol table for Mach-O file in MacSymbolTableBuilder
template <class TMAC_nlist>
struct MacSymbolRecord : public TMAC_nlist {
uint32 Name; // Index into MacSymbolTableBuilder::StringBuffer
int OldIndex; // Old symbol index
};
// Class for building and storing symbol table, sorted or unsorted
template <class TMAC_nlist, class MInt>
class MacSymbolTableBuilder : public CMemoryBuffer {
int sorted; // Remember if list is sorted
CMemoryBuffer StringBuffer; // Temporary storage of symbol names
public:
MacSymbolTableBuilder(); // Constructor
void AddSymbol(int OldIndex, const char * name, int type, int Desc, int section, MInt value); // Add symbol to list
void SortList(); // Sort the list
int TranslateIndex(int OldIndex); // Translate old index to new index, after sorting
void StoreList(CMemoryBuffer * SymbolTable, CMemoryBuffer * StringTable); // Store sorted list in buffers
int Search(const char * name); // Search for name. -1 if not found
MacSymbolRecord<TMAC_nlist> & operator[] (uint32 i); // Access member
};
// structures for MacIntosh universal binaries
struct MAC_UNIV_FAT_HEADER { // File header for universal binary
uint32 magic; // Magic number 0xCAFEBABE, big endian
uint32 num_arch; // Number of members, big endian
};
struct MAC_UNIV_FAT_ARCH { // Member pointer
uint32 cputype; // cpu type
uint32 cpusubtype; // cpu subtype
uint32 offset; // file offset of member
uint32 size; // size of member
uint32 align; // alignment in file = 2^align
};
// Structure used for list of sections that have relocations during disassembly
struct MAC_SECT_WITH_RELOC {
int32 Section; // Section index
uint32 SectOffset; // File offset of section binary data
uint32 NumReloc; // Number of relocations records for this section
uint32 ReltabOffset; // File offset of relocation table for this section
};
/********************** Strings **********************/
#define MAC_CONSTRUCTOR_NAME "__mod_init_func" // Name of constructors section
// Macros listing all word-size dependent structures, used as template parameter list
#define MACSTRUCTURES TMAC_header, TMAC_segment_command, TMAC_section, TMAC_nlist, MInt
#define MAC32STRUCTURES MAC_header_32, MAC_segment_command_32, MAC_section_32, MAC_nlist_32, int32
#define MAC64STRUCTURES MAC_header_64, MAC_segment_command_64, MAC_section_64, MAC_nlist_64, int64
#endif // #ifndef MACHO_H

View File

@ -0,0 +1,784 @@
/**************************** main.cpp **********************************
* Author: Agner Fog
* Date created: 2006-07-26
* Last modified: 2011-10-28
* Project: objconv
* Module: main.cpp
* Description:
* Objconv is a portable C++ program for converting object file formats.
* Compile for console mode on any platform.
*
* Module main contains the program entry
*
* Copyright 2006-2011 GNU General Public License http://www.gnu.org/licenses
*****************************************************************************/
#include "stdafx.h"
// Texts of option feedback. Adding or removing leading underscores on symbols
SIntTxt UnderscoreOptionNames[] = {
{CMDL_UNDERSCORE_NOCHANGE, "Not adding or removing underscores for this filetype"},
{CMDL_UNDERSCORE_REMOVE, "Removing leading underscores from symbol names"},
{CMDL_UNDERSCORE_ADD, "Adding leading underscores to symbol names"},
{CMDL_UNDERSCORE_REMOVE|CMDL_KEEP_ALIAS, "Removing leading underscores from symbol names. Keeping old name as alias"},
{CMDL_UNDERSCORE_ADD|CMDL_KEEP_ALIAS, "Adding leading underscores to symbol names. Keeping old name as alias"}
};
// Texts of option feedback. Changing leading dot or underscore on section names
SIntTxt SectionDotOptionNames[] = {
{CMDL_SECTIONDOT_NOCHANGE, "Not changing leading character on section names for this filetype"},
{CMDL_SECTIONDOT_U2DOT, "Changing leading underscores on section names to dot"},
{CMDL_SECTIONDOT_DOT2U, "Changing leading dot on nonstandard section names to underscore"}
};
// Check that integer type definitions are correct.
// Will generate an error message if the compiler makes the integer types
// with wrong size.
static void CheckIntegerTypes() {
if (
sizeof(uint8) != 1 ||
sizeof(int16) != 2 ||
sizeof(int32) != 4 ||
sizeof(int64) != 8) {
err.submit(9001); // Make error message if type definitions are wrong
}
}
// Check that we are running on a machine with little-endian memory organization
static void CheckEndianness() {
static uint8 bytes[4] = {1, 2, 3, 4};
if (*(uint32*)bytes != 0x04030201) {
// Big endian
err.submit(9002);
}
}
// Function to convert powers of 2 to index
int FloorLog2(uint32 x) {
int i = -1;
do {
x >>= 1;
i++;
} while (x);
return i;
}
const char * timestring(uint32 t) {
// Convert 32 bit time stamp to string
// Fix the problem that time_t may be 32 bit or 64 bit
union {
time_t t;
uint32 t32;
} utime;
utime.t = 0;
utime.t32 = t;
const char * string = ctime(&utime.t);
if (string == 0) string = "?";
return string;
}
// Main. Program starts here
int main(int argc, char * argv[]) {
CheckIntegerTypes(); // Check that compiler has the right integer sizes
CheckEndianness(); // Check that machine is little-endian
#ifdef _DEBUG
// For debugging only. Remove this
if (argc == 1) {
char * dummyarg[] = {"", "@resp.txt"}; // Read command line from file resp.txt
argc = 2; argv = dummyarg;}
#endif
cmd.ReadCommandLine(argc, argv); // Read command line parameters
if (cmd.ShowHelp) return 0; // Help screen has been printed. Do nothing else
CMain maincvt; // This object takes care of all conversions etc.
maincvt.Go();
// Do everything the command line says
if (cmd.Verbose) printf("\n"); // End with newline
return err.GetWorstError(); // Return with error code
}
// Class CMainConverter is used for control of the conversion process
CMain::CMain() : CFileBuffer() {
}
void CMain::Go() {
// Do whatever the command line parameters say
FileName = cmd.InputFile; // Get input file name from command line
// Ignore nonexisting filename when building library
int IgnoreError = (cmd.FileOptions & CMDL_FILE_IN_IF_EXISTS) && !cmd.OutputFile;
Read(IgnoreError); // Read input file
GetFileType(); // Determine file type
cmd.InputType = FileType; // Save input file type in cmd for access from other modules
if (cmd.OutputType == 0) {
// desired type not specified
cmd.OutputType = FileType;
}
if (err.Number()) return; // Return if error
CheckOutputFileName(); // Construct output file name with default extension
if (err.Number()) return;
if ((FileType & (FILETYPE_LIBRARY | FILETYPE_OMFLIBRARY))
|| (cmd.LibraryOptions & CMDL_LIBRARY_ADDMEMBER)) {
// Input file is a library or we are building a library
CLibrary lib; // Library handler object
*this >> lib; // Transfer my file buffer to lib
lib.Go(); // Do conversion or dump
*this << lib; // Get file buffer back
}
else {
// Input file is an object file
CConverter conv; // Make converter object
*this >> conv; // Transfer my file buffer to conv
conv.Go(); // Do conversion or dump
*this << conv; // Get file buffer back
}
if ((cmd.FileOptions & CMDL_FILE_OUTPUT) && OutputFileName) {
// There is an output file to write
cmd.CheckSymbolModifySuccess(); // Check if symbols to modify were found
if (err.Number()) return; // Return if error
FileName = OutputFileName; // Output file name
Write(); // Write output file
if (cmd.Verbose) cmd.ReportStatistics(); // Report statistics
}
}
CConverter::CConverter() {
// Constructor
}
void CConverter::DumpCOF() {
// Dump COFF file
CCOFF cof; // Make object for interpreting COFF file
*this >> cof; // Give it my buffer
cof.ParseFile(); // Parse file buffer
if (err.Number()) return; // Return if error
cof.Dump(cmd.DumpOptions); // Dump file
*this << cof; // Take back my buffer
}
void CConverter::DumpELF() {
// Dump ELF file
if (WordSize == 32) {
// Make object for interpreting 32 bit ELF file
CELF<ELF32STRUCTURES> elf;
*this >> elf; // Give it my buffer
elf.ParseFile(); // Parse file buffer
if (err.Number()) return; // Return if error
elf.Dump(cmd.DumpOptions); // Dump file
*this << elf; // Take back my buffer
}
else {
// Make object for interpreting 32 bit ELF file
CELF<ELF64STRUCTURES> elf;
*this >> elf; // Give it my buffer
elf.ParseFile(); // Parse file buffer
if (err.Number()) return; // Return if error
elf.Dump(cmd.DumpOptions); // Dump file
*this << elf; // Take back my buffer
}
}
void CConverter::DumpMACHO() {
// Dump Mach-O file
if (WordSize == 32) {
// Make object for interpreting 32 bit Mach-O file
CMACHO<MAC32STRUCTURES> macho;
*this >> macho; // Give it my buffer
macho.ParseFile(); // Parse file buffer
if (err.Number()) return; // Return if error
macho.Dump(cmd.DumpOptions); // Dump file
*this << macho; // Take back my buffer
}
else {
// Make object for interpreting 64 bit Mach-O file
CMACHO<MAC64STRUCTURES> macho;
*this >> macho; // Give it my buffer
macho.ParseFile(); // Parse file buffer
if (err.Number()) return; // Return if error
macho.Dump(cmd.DumpOptions); // Dump file
*this << macho; // Take back my buffer
}
}
void CConverter::ParseMACUnivBin() {
// Dump Mac universal binary
CMACUNIV macuniv; // Make object for interpreting Mac universal binary file
*this >> macuniv; // Give it my buffer
macuniv.Go(cmd.DumpOptions); // Dump file components
*this << macuniv; // Take back my buffer
}
void CConverter::DumpOMF() {
// Dump OMF file
COMF omf; // Make object for interpreting OMF file
*this >> omf; // Give it my buffer
omf.ParseFile(); // Parse file buffer
if (err.Number()) return; // Return if error
omf.Dump(cmd.DumpOptions); // Dump file
*this << omf; // Take back my buffer
}
void CConverter::COF2ELF() {
// Convert COFF to ELF file
if (WordSize == 32) {
// Make instance of converter, 32 bit template
CCOF2ELF<ELF32STRUCTURES> conv; // Make object for conversion
*this >> conv; // Give it my buffer
conv.ParseFile(); // Parse file buffer
if (err.Number()) return; // Return if error
conv.Convert(); // Convert
*this << conv; // Take back converted buffer
}
else {
// Make instance of converter, 64 bit template
CCOF2ELF<ELF64STRUCTURES> conv; // Make object for conversion
*this >> conv; // Give it my buffer
conv.ParseFile(); // Parse file buffer
if (err.Number()) return; // Return if error
conv.Convert(); // Convert
*this << conv; // Take back converted buffer
}
}
void CConverter::COF2OMF() {
// Convert COFF to OMF file
CCOF2OMF conv; // Make object for conversion
*this >> conv; // Give it my buffer
conv.ParseFile(); // Parse file buffer
if (err.Number()) return; // Return if error
conv.Convert(); // Convert
*this << conv; // Take back converted buffer
}
void CConverter::OMF2COF() {
// Convert OMF to COFF file
COMF2COF conv; // Make object for conversion
*this >> conv; // Give it my buffer
conv.ParseFile(); // Parse file buffer
if (err.Number()) return; // Return if error
conv.Convert(); // Convert
*this << conv; // Take back converted buffer
}
void CConverter::ELF2COF() {
// Convert ELF to COFF file
if (WordSize == 32) {
// Make instance of converter, 32 bit template
CELF2COF<ELF32STRUCTURES> conv;
*this >> conv; // Give it my buffer
conv.ParseFile(); // Parse file buffer
if (err.Number()) return; // Return if error
conv.Convert(); // Convert
*this << conv; // Take back converted buffer
}
else {
// Make instance of converter, 64 bit template
CELF2COF<ELF64STRUCTURES> conv;
*this >> conv; // Give it my buffer
conv.ParseFile(); // Parse file buffer
if (err.Number()) return; // Return if error
conv.Convert(); // Convert
*this << conv; // Take back converted buffer
}
}
void CConverter::ELF2MAC() {
// Convert ELF to Mach-O file
if (WordSize == 32) {
// Make instance of converter, 32 bit template
CELF2MAC<ELF32STRUCTURES,MAC32STRUCTURES> conv;
*this >> conv; // Give it my buffer
conv.ParseFile(); // Parse file buffer
if (err.Number()) return; // Return if error
conv.Convert(); // Convert
*this << conv; // Take back converted buffer
}
else {
// Make instance of converter, 64 bit template
CELF2MAC<ELF64STRUCTURES,MAC64STRUCTURES> conv;
*this >> conv; // Give it my buffer
conv.ParseFile(); // Parse file buffer
if (err.Number()) return; // Return if error
conv.Convert(); // Convert
*this << conv; // Take back converted buffer
}
}
void CConverter::MAC2ELF() {
// Convert Mach-O file to ELF file
if (WordSize == 32) {
// Make instance of converter, 32 bit template
CMAC2ELF<MAC32STRUCTURES,ELF32STRUCTURES> conv;
*this >> conv; // Give it my buffer
conv.ParseFile(); // Parse file buffer
if (err.Number()) return; // Return if error
conv.Convert(); // Convert
*this << conv; // Take back converted buffer
}
else {
// Make instance of converter, 64 bit template
CMAC2ELF<MAC64STRUCTURES,ELF64STRUCTURES> conv;
*this >> conv; // Give it my buffer
conv.ParseFile(); // Parse file buffer
if (err.Number()) return; // Return if error
conv.Convert(); // Convert
*this << conv; // Take back converted buffer
}
}
void CConverter::COF2ASM() {
// Disassemble COFF file
CCOF2ASM conv; // Make object for conversion
*this >> conv; // Give it my buffer
conv.ParseFile(); // Parse file buffer
if (err.Number()) return; // Return if error
conv.Convert(); // Convert
*this << conv; // Take back converted buffer
}
void CConverter::ELF2ASM() {
// Disassemble ELF file
if (WordSize == 32) {
// Make instance of converter, 32 bit template
CELF2ASM<ELF32STRUCTURES> conv;
*this >> conv; // Give it my buffer
conv.ParseFile(); // Parse file buffer
if (err.Number()) return; // Return if error
conv.Convert(); // Convert
*this << conv; // Take back converted buffer
}
else {
// Make instance of converter, 64 bit template
CELF2ASM<ELF64STRUCTURES> conv;
*this >> conv; // Give it my buffer
conv.ParseFile(); // Parse file buffer
if (err.Number()) return; // Return if error
conv.Convert(); // Convert
*this << conv; // Take back converted buffer
}
}
void CConverter::MAC2ASM() {
// Disassemble Mach-O file
if (WordSize == 32) {
// Make instance of converter, 32 bit template
CMAC2ASM<MAC32STRUCTURES> conv;
*this >> conv; // Give it my buffer
conv.ParseFile(); // Parse file buffer
if (err.Number()) return; // Return if error
conv.Convert(); // Convert
*this << conv; // Take back converted buffer
}
else {
// Make instance of converter, 64 bit template
CMAC2ASM<MAC64STRUCTURES> conv;
*this >> conv; // Give it my buffer
conv.ParseFile(); // Parse file buffer
if (err.Number()) return; // Return if error
conv.Convert(); // Convert
*this << conv; // Take back converted buffer
}
}
void CConverter::OMF2ASM() {
// Disassemble OMF file
COMF2ASM conv; // Make object for conversion
*this >> conv; // Give it my buffer
conv.ParseFile(); // Parse file buffer
if (err.Number()) return; // Return if error
conv.Convert(); // Convert
*this << conv; // Take back converted buffer
}
void CConverter::COF2COF() {
// Make changes in COFF file
CCOF2COF conv; // Make instance of converter
*this >> conv; // Give it my buffer
conv.ParseFile(); // Parse file buffer
if (err.Number()) return; // Return if error
conv.Convert(); // Convert
*this << conv; // Take back converted buffer
}
void CConverter::ELF2ELF() {
// Make changes in ELF file
if (WordSize == 32) {
// Make instance of converter, 32 bit template
CELF2ELF<ELF32STRUCTURES> conv;
*this >> conv; // Give it my buffer
conv.ParseFile(); // Parse file buffer
if (err.Number()) return; // Return if error
conv.Convert(); // Convert
*this << conv; // Take back converted buffer
}
else {
// Make instance of converter, 64 bit template
CELF2ELF<ELF64STRUCTURES> conv;
*this >> conv; // Give it my buffer
conv.ParseFile(); // Parse file buffer
if (err.Number()) return; // Return if error
conv.Convert(); // Convert
*this << conv; // Take back converted buffer
}
}
void CConverter::MAC2MAC() {
// Make changes in Mach-O file
if (WordSize == 32) {
// Make instance of converter, 32 bit template
CMAC2MAC<MAC32STRUCTURES> conv;
*this >> conv; // Give it my buffer
conv.ParseFile(); // Parse file buffer
if (err.Number()) return; // Return if error
conv.Convert(); // Convert
*this << conv; // Take back converted buffer
}
else {
// Make instance of converter, 64 bit template
CMAC2MAC<MAC64STRUCTURES> conv;
*this >> conv; // Give it my buffer
conv.ParseFile(); // Parse file buffer
if (err.Number()) return; // Return if error
conv.Convert(); // Convert
*this << conv; // Take back converted buffer
}
}
void CConverter::Go() {
// Convert or dump file, depending on command line parameters
GetFileType(); // Determine file type
cmd.InputType = FileType; // Save input file type in cmd for access from other modules
if (err.Number()) return; // Return if error
if (cmd.OutputType == CMDL_OUTPUT_DUMP) {
// File dump requested
if (cmd.Verbose > 0) {
// Tell what we are doing:
printf("\nDump of file: %s, type: %s%i", FileName, GetFileFormatName(FileType), WordSize);
}
switch(FileType) {
case FILETYPE_ELF:
DumpELF(); break;
case FILETYPE_COFF:
DumpCOF(); break;
case FILETYPE_MACHO_LE:
DumpMACHO(); break;
case FILETYPE_OMF:
DumpOMF(); break;
case FILETYPE_MAC_UNIVBIN:
ParseMACUnivBin(); break;
default:
err.submit(2010, GetFileFormatName(FileType)); // Dump of this file type not supported
}
printf("\n"); // New line
}
else {
// File conversion requested
if (cmd.DesiredWordSize == 0) cmd.DesiredWordSize = WordSize;
if (WordSize && WordSize != cmd.DesiredWordSize) {
err.submit(2012, WordSize, cmd.DesiredWordSize); // Cannot convert word size
return;
}
if (Executable && cmd.OutputType != CMDL_OUTPUT_MASM) {
// Attempt to convert executable file
err.submit(2022);
}
if (err.Number()) return; // Return if error
if (cmd.Verbose > (uint32)(cmd.LibraryOptions != 0)) {
// Tell what we are doing:
printf("\nInput file: %s, output file: %s", FileName, OutputFileName);
if (FileType != cmd.OutputType) {
printf("\nConverting from %s%2i to %s%2i",
GetFileFormatName(FileType), WordSize,
GetFileFormatName(cmd.OutputType), WordSize);
}
else {
printf("\nModifying %s%2i file", GetFileFormatName(FileType), WordSize);
}
}
// Check underscore options
if (cmd.Underscore && cmd.OutputType != 0) {
if (cmd.Underscore == CMDL_UNDERSCORE_CHANGE) {
// Find underscore option for desired conversion
if (WordSize == 32) {
// In 32-bit, all formats except ELF have underscores
if (FileType == FILETYPE_ELF && cmd.OutputType != FILETYPE_ELF) {
// Converting from ELF32. Add underscores
cmd.Underscore = CMDL_UNDERSCORE_ADD;
}
else if (FileType != FILETYPE_ELF && cmd.OutputType == FILETYPE_ELF) {
// Converting to ELF32. Remove underscores
cmd.Underscore = CMDL_UNDERSCORE_REMOVE;
}
else {
// Anything else 32-bit. No change
cmd.Underscore = CMDL_UNDERSCORE_NOCHANGE;
}
}
else {
// In 64-bit, only Mach-O has underscores
if (FileType == FILETYPE_MACHO_LE && cmd.OutputType != FILETYPE_MACHO_LE) {
// Converting from MachO-64. Remove underscores
cmd.Underscore = CMDL_UNDERSCORE_REMOVE;
}
else if (FileType != FILETYPE_MACHO_LE && cmd.OutputType == FILETYPE_MACHO_LE) {
// Converting to MachO-64. Add underscores
cmd.Underscore = CMDL_UNDERSCORE_ADD;
}
else {
// Anything else 64-bit. No change
cmd.Underscore = CMDL_UNDERSCORE_NOCHANGE;
}
}
}
if (cmd.Verbose > (uint32)(cmd.LibraryOptions != 0)) { // Tell which option is chosen
printf("\n%s", Lookup(UnderscoreOptionNames, cmd.Underscore));
}
}
// Check sectionname options
if (cmd.SegmentDot && cmd.OutputType != 0) {
if (cmd.SegmentDot == CMDL_SECTIONDOT_CHANGE) {
if (cmd.OutputType == FILETYPE_COFF || cmd.OutputType == FILETYPE_MACHO_LE || cmd.OutputType == FILETYPE_OMF) {
// Change leading '.' to '_' in nonstandard section names
cmd.SegmentDot = CMDL_SECTIONDOT_DOT2U;
}
else if (cmd.OutputType == FILETYPE_ELF) {
// Change leading '_' to '.' in nonstandard section names
cmd.SegmentDot = CMDL_SECTIONDOT_U2DOT;
}
else {
cmd.SegmentDot = CMDL_SECTIONDOT_NOCHANGE;
}
}
if (cmd.Verbose > (uint32)(cmd.LibraryOptions != 0)) { // Tell which option is chosen
printf("\n%s", Lookup(SectionDotOptionNames, cmd.SegmentDot));
}
}
// Check debug info options
if (cmd.DebugInfo == CMDL_DEBUG_DEFAULT) {
cmd.DebugInfo = (FileType != cmd.OutputType) ? CMDL_DEBUG_STRIP : CMDL_DEBUG_PRESERVE;
}
// Check exception handler info options
if (cmd.ExeptionInfo == CMDL_EXCEPTION_DEFAULT) {
cmd.ExeptionInfo = (FileType != cmd.OutputType) ? CMDL_EXCEPTION_STRIP : CMDL_EXCEPTION_PRESERVE;
}
// Choose conversion
switch (FileType) {
// Conversion from ELF
case FILETYPE_ELF:
switch (cmd.OutputType) {
case FILETYPE_COFF:
// Conversion from ELF to COFF
ELF2ELF(); // Make symbol changes in ELF file
if (err.Number()) return; // Return if error
ELF2COF(); // Convert to COFF
break;
case FILETYPE_MACHO_LE:
// Conversion from ELF to Mach-O
ELF2MAC(); // Convert to Mach-O
if (err.Number()) return; // Return if error
MAC2MAC(); // Make symbol changes in Mach-O file, sort symbol tables alphabetically
break;
case FILETYPE_OMF:
// Conversion from ELF to OMF
ELF2ELF(); // Make symbol changes in ELF file
if (err.Number()) return; // Return if error
ELF2COF(); // Convert to COFF first
if (err.Number()) return; // Return if error
COF2OMF(); // Then convert to OMF
break;
case FILETYPE_ELF:
// Make changes in ELF file
if (cmd.SymbolChangesRequested()) {
ELF2ELF(); // Make symbol changes in ELF file
}
else if (!cmd.LibraryOptions) {
err.submit(1006); // Warning: nothing to do
}
break;
case CMDL_OUTPUT_MASM:
// Disassemble ELF file
ELF2ASM(); // Disassemble
break;
default:
// Conversion not supported
err.submit(2013, GetFileFormatName(FileType), GetFileFormatName(cmd.OutputType));
}
break;
// Conversion from COFF
case FILETYPE_COFF:
switch (cmd.OutputType) {
case FILETYPE_COFF:
// No conversion. Modify file
if (cmd.DebugInfo == CMDL_DEBUG_STRIP || cmd.ExeptionInfo == CMDL_EXCEPTION_STRIP) {
COF2ELF(); // Convert to ELF and back again to strip debug and exception info
if (err.Number()) return; // Return if error
ELF2COF();
err.submit(1008); // Warning: Converting to ELF and back again
}
if (cmd.SymbolChangesRequested()) {
COF2COF(); // Make symbol name changes in COFF file
}
else if (cmd.DebugInfo != CMDL_DEBUG_STRIP && cmd.ExeptionInfo != CMDL_EXCEPTION_STRIP && !cmd.LibraryOptions) {
err.submit(1006); // Warning: nothing to do
}
break;
case FILETYPE_ELF:
COF2COF(); // Make symbol changes in COFF file
if (err.Number()) return; // Return if error
COF2ELF(); // Convert to ELF
break;
case FILETYPE_OMF:
COF2COF(); // Make symbol changes in COFF file
if (err.Number()) return; // Return if error
COF2OMF(); // Convert to OMF
break;
case FILETYPE_MACHO_LE:
COF2ELF(); // Convert from COFF to ELF
if (err.Number()) return; // Return if error
ELF2MAC(); // Then convert from ELF to Mach-O
if (err.Number()) return; // Return if error
MAC2MAC(); // Make symbol changes in Mach-O file and sort symbol table
break;
case CMDL_OUTPUT_MASM:
// Disassemble COFF file
COF2ASM(); // Disassemble
break;
default:
// Conversion not supported
err.submit(2013, GetFileFormatName(FileType), GetFileFormatName(cmd.OutputType));
}
break;
// Conversion from OMF
case FILETYPE_OMF:
switch (cmd.OutputType) {
case FILETYPE_OMF:
// No conversion. Modify file
if (cmd.SymbolChangesRequested() || cmd.DebugInfo == CMDL_DEBUG_STRIP || cmd.ExeptionInfo == CMDL_EXCEPTION_STRIP) {
OMF2COF(); // Convert to COFF and back again to do requested changes
if (err.Number()) return; // Return if error
COF2COF(); // Make symbol changes in COFF file
if (err.Number()) return; // Return if error
COF2OMF();
err.submit(1009); // Warning: Converting to COFF and back again
}
break;
case FILETYPE_COFF:
OMF2COF(); // Convert to COFF
if (err.Number()) return; // Return if error
COF2COF(); // Make symbol changes in COFF file
break;
case FILETYPE_ELF:
OMF2COF(); // Convert to COFF
if (err.Number()) return; // Return if error
COF2COF(); // Make symbol changes in COFF file
if (err.Number()) return; // Return if error
COF2ELF(); // Convert to ELF
break;
case FILETYPE_MACHO_LE:
OMF2COF(); // Convert to COFF
if (err.Number()) return; // Return if error
COF2ELF(); // Convert from COFF to ELF
if (err.Number()) return; // Return if error
ELF2MAC(); // Then convert from ELF to Mach-O
if (err.Number()) return; // Return if error
MAC2MAC(); // Make symbol changes in Mach-O file and sort symbol table
break;
case CMDL_OUTPUT_MASM:
// Disassemble OMF file
OMF2ASM(); // Disassemble
break;
default:
// Conversion not supported
err.submit(2013, GetFileFormatName(FileType), GetFileFormatName(cmd.OutputType));
}
break;
// Conversions from Mach-O
case FILETYPE_MACHO_LE:
switch (cmd.OutputType) {
case FILETYPE_ELF:
MAC2ELF(); // Convert to ELF
if (err.Number()) return; // Return if error
ELF2ELF(); // Make symbol changes in ELF file
break;
case FILETYPE_COFF:
MAC2ELF(); // Convert to ELF
if (err.Number()) return; // Return if error
ELF2ELF(); // Make symbol changes in ELF file
if (err.Number()) return; // Return if error
ELF2COF(); // Convert to COFF
break;
case FILETYPE_OMF:
MAC2ELF(); // Convert to ELF
if (err.Number()) return; // Return if error
ELF2ELF(); // Make symbol changes in ELF file
if (err.Number()) return; // Return if error
ELF2COF(); // Convert to COFF
if (err.Number()) return; // Return if error
COF2OMF(); // Convert to OMF
break;
case FILETYPE_MACHO_LE:
MAC2MAC(); // Make symbol changes in mACH-o file
break;
case CMDL_OUTPUT_MASM:
// Disassemble Mach-O file
MAC2ASM(); // Disassemble
break;
default:
// Conversion not supported
err.submit(2013, GetFileFormatName(FileType), GetFileFormatName(cmd.OutputType));
}
break;
case FILETYPE_MAC_UNIVBIN:
ParseMACUnivBin(); break;
// Conversion from other types
default:
err.submit(2006, FileName, GetFileFormatName(FileType)); // Conversion of this file type not supported
}
}
}

View File

@ -0,0 +1,139 @@
/**************************** maindef.h **********************************
* Author: Agner Fog
* Date created: 2006-08-26
* Last modified: 2018-10-08
* Project: objconv
* Module: maindef.h
* Description:
* Header file for type definitions and other main definitions.
*
* Copyright 2006-2018 GNU General Public License http://www.gnu.org/licenses
*****************************************************************************/
#ifndef MAINDEF_H
#define MAINDEF_H
// Program version
#define OBJCONV_VERSION 2.52
// Integer type definitions with platform-independent sizes:
#include <limits.h>
#if defined(_I64_MAX)
// Microsoft compilers use __int64 etc
typedef char int8; // 8 bit signed integer
typedef unsigned char uint8; // 8 bit unsigned integer
typedef short int int16; // 16 bit signed integer
typedef unsigned short int uint16; // 16 bit unsigned integer
typedef int int32; // 32 bit signed integer
typedef unsigned int uint32; // 32 bit unsigned integer
typedef __int64 int64; // 64 bit signed integer
typedef unsigned __int64 uint64; // 64 bit unsigned integer
#elif defined(INT_MAX) && defined(LLONG_MAX) && INT_MAX==2147483647L && LLONG_MAX==9223372036854775807LL
// Compiler has int = 32 bit and long long = 64 bit
typedef char int8; // 8 bit signed integer
typedef unsigned char uint8; // 8 bit unsigned integer
typedef short int int16; // 16 bit signed integer
typedef unsigned short int uint16; // 16 bit unsigned integer
typedef int int32; // 32 bit signed integer
typedef unsigned int uint32; // 32 bit unsigned integer
typedef long long int64; // 64 bit signed integer
typedef unsigned long long uint64; // 64 bit unsigned integer
#else
// Compilers supporting C99 or C++0x or C++1x have inttypes.h defining these integer types
// This is the preferred solution:
#include <inttypes.h>
//typedef int8_t int8; // Gnu compiler can't convert int8_t to char
typedef char int8; // 8 bit signed integer
typedef uint8_t uint8; // 8 bit unsigned integer
typedef int16_t int16; // 16 bit signed integer
typedef uint16_t uint16; // 16 bit unsigned integer
typedef int32_t int32; // 32 bit signed integer
typedef uint32_t uint32; // 32 bit unsigned integer
typedef int64_t int64; // 64 bit signed integer
typedef uint64_t uint64; // 64 bit unsigned integer
#endif
// Get high part of a 64-bit integer
static inline uint32 HighDWord (uint64 x) {
return (uint32)(x >> 32);
}
// Check if compiling for big-endian machine
// (__BIG_ENDIAN__ may not be defined even on big endian systems, so this check is not
// sufficient. A further check is done in CheckEndianness() in main.cpp)
#if defined(__BIG_ENDIAN__) && (__BIG_ENDIAN__ != 4321)
#error This machine has big-endian memory organization. Objconv program will not work
#endif
// Max file name length
#define MAXFILENAMELENGTH 256
// File types
#define FILETYPE_COFF 1 // Windows COFF/PE file
#define FILETYPE_OMF 2 // Windows OMF file
#define FILETYPE_ELF 3 // Linux or BSD ELF file
#define FILETYPE_MACHO_LE 4 // Mach-O file, little endian
#define FILETYPE_MACHO_BE 5 // Mach-O file, big endian
#define FILETYPE_DOS 6 // DOS file
#define FILETYPE_WIN3X 7 // Windows 3.x file
#define IMPORT_LIBRARY_MEMBER 0x10 // Member of import library, Windows
#define FILETYPE_MAC_UNIVBIN 0x11 // Macintosh universal binary
#define FILETYPE_MS_WPO 0x20 // Object file for whole program optimization, MS
#define FILETYPE_INTEL_WPO 0x21 // Object file for whole program optimization, Intel
#define FILETYPE_WIN_UNKNOWN 0x29 // Unknown subtype, Windows
#define FILETYPE_ASM 0x100 // Disassembly output
#define FILETYPE_LIBRARY 0x1000 // UNIX-style library/archive
#define FILETYPE_OMFLIBRARY 0x2000 // OMF-style library
// Library subtypes
#define LIBTYPE_OMF 0x01 // OMF library
#define LIBTYPE_SHORTNAMES 0x10 // Short member names only, compatible with all systems
#define LIBTYPE_WINDOWS 0x11 // Long member names in "//" member, terminated by 0
#define LIBTYPE_LINUX 0x12 // Long member names in "//" member, terminated by '/'+LF
#define LIBTYPE_BSD_MAC 0x13 // Long member name after header. Length indicated by #1/<length>
// Define constants for symbol scope
#define S_LOCAL 0 // Local symbol. Accessed only internally
#define S_PUBLIC 1 // Public symbol. Visible from other modules
#define S_EXTERNAL 2 // External symbol. Defined in another module
// Macro to calculate the size of an array
#define TableSize(x) ((int)(sizeof(x)/sizeof(x[0])))
// Structures and functions used for lookup tables:
// Structure of integers and char *, used for tables of text strings
struct SIntTxt {
uint32 a;
const char * b;
};
// Translate integer value to text string by looking up in table of SIntTxt.
// Parameters: p = table, n = length of table, x = value to find in table
static inline char const * LookupText(SIntTxt const * p, int n, uint32 x) {
for (int i=0; i<n; i++, p++) {
if (p->a == x) return p->b;
}
// Not found
static char utext[32];
sprintf(utext, "unknown(0x%X)", x);
return utext;
}
// Macro to get length of text list and call LookupText
#define Lookup(list,x) LookupText(list, sizeof(list)/sizeof(list[0]), x)
// Function to convert powers of 2 to index
int FloorLog2(uint32 x);
// Convert 32 bit time stamp to string
const char * timestring(uint32 t);
#endif // #ifndef MAINDEF_H

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,269 @@
/***************************** omf.h *************************************
* Author: Agner Fog
* Date created: 2007-01-29
* Last modified: 2007-01-29
* Project: objconv
* Module: omf.h
* Description:
* Header file for definition of data structures and constants in OMF object
* file format. Also defines class COMFFileBuilder.
*
* Copyright 2006-2008 GNU General Public License http://www.gnu.org/licenses
******************************************************************************
*
* An OMF file consists of a chain of records which all have the same basic
* structure:
* 1. One byte describing the type of record
* 2. A 16-bit word indicating the length of the rest of the record
* 3. Data of variable types and sizes (max 1024 bytes)
* 4. One byte for checksum. Some systems just set this byte to 0
*
* The OMF format is designed for compactness. All integers of type "index"
* are represented by one byte if no bigger than 127, or by two bytes if
* 128 or more. The most significant bit of the first byte indicates whether
* there are one or two bytes. Integers indicating a segment offset are 16
* bits if the type byte is even, or 32 bits if the type byte is odd.
* Some fields can be left out if they are zero or repeated. The precense
* or absense of a particular field may depend on certain bits in the preceding
* fields. The records cannot be defined as C++ structures because a field
* with variable size or a field that can be absent makes the position of the
* subsequent fields variable.
*
* For these reasons, you will not find any structures defining OMF records
* in this header file. Only the bitfields that are used are defined here.
* Instead, I have defined the member functions of SOMFRecordPointer for
* reading fields of various types occurring in OMF records, and the member
* functions of COMFFileBuilder for writing these fields. The structure of
* an OMF record is simply defined by calling these functions in the right
* order.
*
* The size of the data field is limited to 1024 bytes because records of type
* FIXUPP have only 10 bits for indexing into the data field of a preceding
* record of type LEDATA or LIDATA. Most tools (but not all!) limit the size
* of all types of records to 1024 bytes of data, although this limitation
* is technically necessary only for LEDATA and LIDATA records. A segment
* bigger than one kilobyte must be split into several LEDATA records. Each
* LEDATA record is followed by a FIXUPP record if it has relocations.
*
* Symbol names and other text strings are stored with one byte indicating the
* length of the string followed by an ASCII string without terminating zero.
* Consequently, the length of all symbol names is limited to 255 characters.
*
*****************************************************************************/
#ifndef OMF_H
#define OMF_H
//********************** Record types **********************
#define OMF_THEADR 0x80 // Translator Header Record
#define OMF_LHEADR 0x82 // Library Module Header Record
#define OMF_COMENT 0x88 // Comment Record (Including all comment class extensions)
#define OMF_MODEND 0x8A // (0x8B) Module End Record
#define OMF_EXTDEF 0x8C // External Names Definition Record
#define OMF_PUBDEF 0x90 // (0x91) Public Names Definition Record
#define OMF_LINNUM 0x94 // (0x95) Line Numbers Record
#define OMF_LNAMES 0x96 // List of Names Record
#define OMF_SEGDEF 0x98 // (0x99) Segment Definition Record
#define OMF_GRPDEF 0x9A // Group Definition Record
#define OMF_FIXUPP 0x9C // (0x9D) Fixup Record
#define OMF_LEDATA 0xA0 // (0xA1) Logical Enumerated Data Record
#define OMF_LIDATA 0xA2 // (0xA3) Logical Iterated Data Record
#define OMF_COMDEF 0xB0 // Communal Names Definition Record
#define OMF_BAKPAT 0xB2 // (0xB3) Backpatch Record
#define OMF_LEXTDEF 0xB4 // Local External Names Definition Record
#define OMF_LPUBDEF 0xB6 // (0xB7) Local Public Names Definition Record
#define OMF_LCOMDEF 0xB8 // Local Communal Names Definition Record
#define OMF_CEXTDEF 0xBC // COMDAT External Names Definition Record
#define OMF_COMDAT 0xC2 // (0xC3) Initialized Communal Data Record
#define OMF_LINSYM 0xC4 // (0xC5) Symbol Line Numbers Record
#define OMF_ALIAS 0xC6 // Alias Definition Record
#define OMF_NBKPAT 0xC8 // (0xC9) Named Backpatch Record
#define OMF_LLNAMES 0xCA // Local Logical Names Definition Record
#define OMF_VERNUM 0xCC // OMF Version Number Record
#define OMF_VENDEXT 0xCE // Vendor-specific OMF Extension Record
#define OMF_LIBHEAD 0xF0 // Library Header Record
#define OMF_LIBEND 0xF1 // Library End Record
#define OMF_LIBEXT 0xF2 // Library extended dictionary
/********************** Relocation types **********************/
#define OMF_Fixup_8bit 0 // 8 bit or low byte of 16 bits
#define OMF_Fixup_16bit 1 // 16 bit offset
#define OMF_Fixup_Segment 2 // 16 bit segment selector
#define OMF_Fixup_Far 3 // 16 bit offset + 16 big segment
#define OMF_Fixup_Hi8bit 4 // High 8 bits of 16 bit offset
#define OMF_Fixup_16bitLoader 5 // 16 bit, loader resolved
#define OMF_Fixup_Pharlab48 6 // 32 bit offset + 16 bit segment, Pharlab only
#define OMF_Fixup_32bit 9 // 32 bit offset
#define OMF_Fixup_Farword 11 // 32 bit offset + 16 bit segment
#define OMF_Fixup_32bitLoader 13 // 32 bit, loader resolved
// Define fixed indexes in LNAMES for default group and class names
#define OMF_LNAME_FLAT 1 // Default group name
#define OMF_LNAME_CODE 2 // Default class for code
#define OMF_LNAME_DATA 3 // Default class for data
#define OMF_LNAME_BSS 4 // Default class for uninitialized data
#define OMF_LNAME_CONST 5 // Default class for constant data
#define OMF_LNAME_LAST 5 // Last default name. Nondefault names start at OMF_LNAME_LAST + 1
// Class name STACK not used
// Define bitfield structures used in OMF records
union OMF_SAttrib { // Structure of attributes in SEGDEF record
uint8 b; // Byte
struct {
uint8 P:1, // 0: 16 bit, 1: 32 bit
B:1, // Big
C:3, // Combination (private, public, stack, common)
A:3; // Alignment
} u;
};
union OMF_SLocat { // Structure of first two bytes of FIXUP subrecord swapped = Locat field
uint8 bytes[2]; // First two bytes swapped
struct {
uint16 Offset:10, // Offset into LEDATA (or LIDATA)
Location:4, // Relocation method
M:1, // 0 = self-relative, 1 = direct
one:1; // 1 = FIXUP subrecord, 0 = THREAD subrecord
} s;
};
union OMF_SFixData { // Structure of FixData field in FIXUP subrecord of FIXUPP record
uint8 b; // Byte
struct {
uint8 Target:2, // Target method (T=0) or target thread number (T=1)
P:1, // 0 = target displacement field present, 1 = displacement is zero
T:1, // 0 = target field present, 1 = target defined by thread
Frame:3, // Frame method (F=0) or frame thread (F=1)
F:1; // 0 = target frame field present, 1 = frame defined by thread
} s;
};
union OMF_STrdDat { // Structure of Thread Data field in THREAD subrecord of FIXUPP record
uint8 b; // Byte
struct {
uint8 Thread:2, // Thread number
Method:3, // Method (T0 - T3, F0 - F6)
Unused:1, // 0
D:1, // 0 = Target thread, 1 = Frame thread
Zero:1; // 1 = FIXUP subrecord, 0 = THREAD subrecord
} s;
};
// Structure of OMF record pointer
struct SOMFRecordPointer {
public:
uint8 Type; // Record type
uint8 Type2; // Record type, made even
uint16 Unused; // Align
uint32 FileOffset; // Position in file
uint32 FileEnd; // End of file = file size
uint32 Index; // Offset to current byte while parsing from start of record
uint32 End; // Offset to checksum byte from start of record
int8 * buffer; // Pointer to file buffer
uint8 GetByte(); // Read next byte from buffer
uint16 GetWord(); // Read next 16 bit word from buffer
uint32 GetDword(); // Read next 32 bit dword from buffer
uint32 GetIndex(); // Read byte or word, depending on sign of first byte
uint32 GetNumeric(); // Read word or dword, depending on record type even or odd
uint32 GetLength(); // Read 1, 2, 3 or 4 bytes, depending on value of first byte
char * GetString(); // Read string and return as ASCIIZ string
void Start(int8 * Buffer, uint32 FileOffset, uint32 FileEnd); // Start scanning through records
uint8 GetNext(uint32 align = 0);// Get next record
uint32 InterpretLIDATABlock(); // Interpret Data block in LIDATA record recursively
uint32 UnpackLIDATABlock(int8 * destination, uint32 MaxSize); // Unpack Data block in LIDATA record recursively and store data at destination
};
// Class for building OMF files
class COMFFileBuilder : public CFileBuffer {
public:
COMFFileBuilder(); // Constructor
void StartRecord(uint8 type); // Start building new record
void EndRecord(); // Finish building current record
void PutByte(uint8); // Put byte into buffer
void PutWord(uint16); // Put 16 bit word into buffer
void PutDword(uint32); // Put 32 bit dword into buffer
void PutIndex(uint32); // Put byte or word into buffer (word if > 127)
void PutNumeric(uint32); // Put word or dword into buffer, depending on type being even or odd
void PutString(const char *); // Put ASCII string into buffer, preceded by size
void PutBinary(void *, uint32); // Put binary data of any length
uint32 GetSize(); // Get size of data added so far to current record
protected:
uint8 Type; // Record type
uint32 Index; // Index to current offset
uint32 RecordStart; // Index to start of current record
};
// Structure for temporary segment list used while building OMF file
struct SOMFSegmentList {
public:
uint32 NewNumber; // Segment index in new file
uint32 OldName; // Segment name in old file as index into NameBuffer
uint32 NewName; // Segment name in new file as index into NameBuffer
uint32 NewNameI; // Segment name in new file as index into LNAMES record. Zero for subsequent entries with same segment name
SCOFF_SectionHeader * psechdr; // Pointer to old section header
uint32 Align; // Alignment = 2^Align
uint32 Class; // Class in new file
uint32 Offset; // Offset of section in old file to first section with same name
uint32 Size; // Size of section. First record has combined size of all sections with same name
uint32 SegmentSize; // Size of segment = combined size of all sections with same name. Stored only in first section of segment
};
// Structure for temporary symbol list used while building OMF file
struct SOMFSymbolList {
public:
uint32 Scope; // 0 = local, 1 = public, 2 = external
uint32 NewIndex; // PUBDEF index if Scope = 1, EXTDEF index if scope = 2
uint32 Segment; // New segment index
uint32 Offset; // Offset relative to segment = first section with same name
uint32 Name; // Symbol name in new file as index into NameBuffer
};
// Structure for temporary relocation (fixup) list used while building OMF file
struct SOMFRelocation {
public:
uint32 Section; // Section number in old file
uint32 SourceOffset; // Offset of source relative to section
int32 Mode; // 0 = EIP-relative, 1 = direct, -1 = unsupported
uint32 Scope; // 0 = local, 2 = external
uint32 TargetSegment; // Segment index or EXTDEF index of target in new file
uint32 TargetOffset; // Offset relative to segment in new file of target
int operator < (SOMFRelocation const & x) const {// operator < for sorting by CSList::Sort()
return Section < x.Section || (Section == x.Section && SourceOffset < x.SourceOffset);
}
};
// Structure for assigning names to unnamed local symbols while converting OMF file
struct SOMFLocalSymbol {
uint32 Offset; // Offset into segment
uint32 Segment; // Segment number in old file
uint32 Name; // Assigned name as index into new string table
uint32 NewSymtabIndex; // Index into new symbol table
// Operator < needed for sorting table of SOMFLocalSymbol:
int operator < (const SOMFLocalSymbol & b) const {
return Segment < b.Segment || (Segment == b.Segment && Offset < b.Offset);
}
};
// Structure for interpreted SEGDEF record used during disassembly
struct SOMFSegment {
uint32 NameO; // Segment name, as offset into NameBuffer
uint32 Offset; // Segment address
uint32 Size; // Segment size
uint32 Align; // Alignment = 1 << Align
uint32 Type; // Segment type (as defined in disasm.h)
uint32 WordSize; // 16 or 32 bits
uint32 BufOffset; // Offset of raw data into SegmentData buffer
uint32 NameIndex; // Name index, used for COMDAT segment only
};
#endif // #ifndef OMF_H

View File

@ -0,0 +1,954 @@
/**************************** omf2asm.cpp *********************************
* Author: Agner Fog, modified by Don Clugston
* Date created: 2007-05-27
* Last modified: 2014-05-32
* Project: objconv
* Module: omf2asm.cpp
* Description:
* Module for disassembling OMF object files
*
* (c) 2007-2014 GNU General Public License www.gnu.org/copyleft/gpl.html
*****************************************************************************/
#include "stdafx.h"
// Constructor
COMF2ASM::COMF2ASM() {
}
// Convert
void COMF2ASM::Convert() {
// Do the conversion
// Tell disassembler
Disasm.Init(0, 0);
// Make temporary Segments table
CountSegments();
// Make external symbols in Disasm
MakeExternalSymbolsTable();
// Make public symbols in Disasm
MakePublicSymbolsTable();
// Make symbol table entries for communal symbols.
MakeCommunalSymbolsTable();
// Make Segment list and relocations list
MakeSegmentList();
// Make group definitions
MakeGroupDefinitions();
// Disassemble
Disasm.Go();
// Take over output file from Disasm
*this << Disasm.OutFile;
}
void COMF2ASM::CountSegments() {
// Make temporary Segments table
uint32 i; // Record number
uint32 NameIndex; // Name index
uint32 ClassIndex; // Class name index
SOMFSegment SegRecord; // Segment record
// Define structure of attributes
OMF_SAttrib Attributes;
// Initialize temporary list of segments. Entry 0 is blank
Segments.PushZero();
// Search for SEGDEF records
for (i = 0; i < NumRecords; i++) {
if (Records[i].Type2 == OMF_SEGDEF) {
// SEGDEF record
Records[i].Index = 3;
// Loop through entries in record. There should be only 1
while (Records[i].Index < Records[i].End) {
// Read segment attributes
Attributes.b = Records[i].GetByte();
if (Attributes.u.A == 0) {
// Frame and Offset only included if A = 0
Records[i].GetWord(); // Frame ignored
SegRecord.Offset = Records[i].GetByte();
}
else SegRecord.Offset = 0;
SegRecord.Size = Records[i].GetNumeric();
NameIndex = Records[i].GetIndex();
ClassIndex = Records[i].GetIndex(); // Class index
Records[i].GetIndex(); // Overlay index ignored
SegRecord.NameO = GetLocalNameO(NameIndex); // Segment name
if (Attributes.u.B) {
// Segment is big
if (Attributes.u.P) {
// 32 bit segment. Big means 2^32 bytes!
err.submit(2306);
}
else {
// 16 bit segment. Big means 2^16 bytes
SegRecord.Size = 0x10000;
}
}
// Get word size
SegRecord.WordSize = Attributes.u.P ? 32 : 16;
// Get alignment
switch (Attributes.u.A) {
case 0: // Absolute segment
case 1: // Byte alignment
SegRecord.Align = 0;
break;
case 2: // Word alignment
SegRecord.Align = 1;
break;
case 3: // Paragraph alignment
SegRecord.Align = 4;
break;
case 4: // Page alignment
SegRecord.Align = 16;
break;
case 5: // DWord alignment
SegRecord.Align = 2;
break;
default: // Unknown
SegRecord.Align = 3; // Arbitrary value
break;
}
// Get further attributes from class name
char * ClassName = GetLocalName(ClassIndex);
// Convert class name to upper case
uint32 n = (uint32)strlen(ClassName);
for (uint32 j = 0; j < n; j++) ClassName[j] &= ~0x20;
// Search for known class names.
// Standard names are CODE, DATA, BSS, CONST, STACK
if (strstr(ClassName, "CODE") || strstr(ClassName, "TEXT")) {
// Code segment
SegRecord.Type = 1;
}
else if (strstr(ClassName, "DATA")) {
// Data segment
SegRecord.Type = 2;
}
else if (strstr(ClassName, "BSS")) {
// Unitialized data segment
SegRecord.Type = 3;
}
else if (strstr(ClassName, "CONST")) {
// Constant data segment
SegRecord.Type = 4;
}
else if (strstr(ClassName, "STACK")) {
// Stack segment.
SegRecord.Type = 0;
}
else {
// Unknown/user defined class. Assume data segment
SegRecord.Type = 2;
}
// Store temporary segment record
Segments.Push(SegRecord);
}
if (Records[i].Index != Records[i].End) err.submit(1203); // Check for consistency
}
}
FirstComDatSection = Segments.GetNumEntries();
// Communal sections (as used by Digital Mars):
// This part by Don Clugston
for (i = 0; i < NumRecords; i++) {
if (Records[i].Type2 == OMF_COMDAT) {
Records[i].Index = 3;
uint8 flags = Records[i].GetByte();
if ((flags & 2) != 0) {
// don't support iterated data yet
err.submit(2318); // Error message: not supported
continue;
}
uint8 attribs = Records[i].GetByte();
uint8 align = Records[i].GetByte();
uint32 ofs = Records[i].GetNumeric();
Records[i].GetIndex(); // type (ignore)
//uint16 publicBase = 0;
uint16 publicSegment = 0;
// From the OMF Spec 1.1: "If alloc type is EXPLICIT, public base is present and is
// identical to public base fields BaseGroup, Base Segment & BaseFrame in the PUBDEF."
// BUT: In the diagram in the spec it is described as 1-2 bytes (ie, an Index field).
// but in PUBDEF, those fields are Index, Index, or Index, zero, Index. (2-5 bytes)
// The diagram appears to be erroneous.
if ((attribs & 0xF) == 0){
//publicBase = Records[i].GetIndex();
publicSegment = Records[i].GetIndex();
if (publicSegment == 0) {
//Records[i].GetIndex(); // skip frame in this case
// I don't have the Digital Mars obj spec, but this seems to help ??
publicSegment = Records[i].GetIndex(); // ??
}
}
uint16 publicName = Records[i].GetIndex();
uint32 RecSize = Records[i].End - Records[i].Index; // Calculate size of data
if (attribs & 0xF) {
SegRecord.Type = 0x1000 | (attribs & 0xFF);
SegRecord.WordSize = (attribs & 0x2) ? 32 : 16;
}
else {
// use value from segdef
SegRecord.Type = 0x1000 | Segments[publicSegment].Type;
SegRecord.WordSize = Segments[publicSegment].WordSize;
}
//SegRecord.Type |= 1;//!!
if (align != 0) {
// alignment: (none), byte, word, paragraph, page, dword, arbitrary, arbitrary.
static const int alignvalues[] = {0, 0, 1, 4, 16, 2, 3, 3};
SegRecord.Align = alignvalues[align & 0x7];
}
else { // use value from segdef
SegRecord.Align = Segments[publicSegment].Align;
}
SegRecord.Size = RecSize;
// Get function name
const char * name = GetLocalName(publicName);
// Make a section name by putting _text$ before function name
uint32 ComdatSectionNameIndex = NameBuffer.Push("_text$", 6);
NameBuffer.PushString(name); // append function name
SegRecord.NameO = ComdatSectionNameIndex;
SegRecord.NameIndex = publicName;
if (flags & 1) {
// continuation.
// Add to the length to the previous entry.
Segments[Segments.GetNumEntries()-1].Size += RecSize;
}
else {
SegRecord.Offset = ofs;
Segments.Push(SegRecord);
}
}
}
// Communal sections (as used by Borland):
for (i = 0; i < NumRecords; i++) {
if (Records[i].Type2 == OMF_COMDEF) {
uint32 DType, DSize = 0, DNum;
uint16 Segment = 0;
const char * FuncName = 0;
// Loop through possibly multiple entries in record
while (Records[i].Index < Records[i].End) {
// Get function name
FuncName = Records[i].GetString();
Records[i].GetByte(); // Type index, should be 0, ignored
DType = Records[i].GetByte(); // Data type
switch (DType) {
case 0x61:
DNum = Records[i].GetLength();
DSize = Records[i].GetLength() * DNum;
break;
case 0x62:
DSize = Records[i].GetLength();
break;
default:
DSize = Records[i].GetLength();
if (DType < 0x60) { // Borland segment index
Segment = DType;
break;
}
err.submit(2016); // unknown type
break;
}
}
if (Segment >= Segments.GetNumEntries()) {err.submit(2016); return;}
// Copy segment record
SegRecord = Segments[Segment];
// Make a section name as SEGMENTNAME$FUNCTIONNAME
const char * SegmentName = NameBuffer.Buf() + SegRecord.NameO;
uint32 ComdatSectionNameIndex = NameBuffer.Push(SegmentName, strlen(SegmentName));
NameBuffer.Push("$", 1);
NameBuffer.PushString(FuncName); // append function name
SegRecord.NameO = ComdatSectionNameIndex;
SegRecord.Size = DSize;
SegRecord.Type |= 0x1000;
//SegRecord.BufOffset = ??
// Store segment
Segments.Push(SegRecord);
if (Records[i].Index != Records[i].End) err.submit(1203); // Check for consistency
}
}
// Number of segments, not including blank zero entry
NumSegments = Segments.GetNumEntries() - 1;
}
void COMF2ASM::MakeExternalSymbolsTable() {
// Make symbol table and string table entries for external symbols
uint32 iextsym; // External symbol index
uint32 isymo; // Symbol index in disassembler
uint32 NumExtSym = SymbolNameOffset.GetNumEntries(); // Number of external symbols
ExtdefTranslation.SetNum(NumExtSym+1); // Allocate space in symbol index translation table
// Loop through external symbol names
for (iextsym = 1; iextsym < NumExtSym; iextsym++) {
// Get name
const char * Name = GetSymbolName(iextsym);
// Define symbol
isymo = Disasm.AddSymbol(0, 0, 0, 0, 0x20, 0, Name);
// Update table for translating old EXTDEF number to disassembler symbol index
ExtdefTranslation[iextsym] = isymo;
}
}
void COMF2ASM::MakePublicSymbolsTable() {
// Make symbol table entries for public symbols
uint32 i; // Record index
char * string; // Symbol name
uint32 Segment; // Segment
uint32 Offset; // Offset
uint32 isymo; // Symbol number in disasm
uint32 CommunalSection = FirstComDatSection; // Index to communal section
PubdefTranslation.Push(0); // Make index 0 = 0
// Search for PUBDEF records
for (i = 0; i < NumRecords; i++) {
if (Records[i].Type2 == OMF_PUBDEF) {
// PUBDEF record
Records[i].Index = 3;
Records[i].GetIndex(); // Group. Ignore
Segment = Records[i].GetIndex(); // Segment
if (Segment == 0) Records[i].GetWord(); // Base frame. Ignore
// Loop through strings in record
while (Records[i].Index < Records[i].End) {
string = Records[i].GetString(); // Symbol name
Offset = Records[i].GetNumeric(); // Offset to segment
Records[i].GetIndex(); // Type index. Ignore
// Define symbol
isymo = Disasm.AddSymbol(Segment, Offset, 0, 0, 4, 0, string);
// Update table for translating old PUBDEF number to disassembler symbol index
PubdefTranslation.Push(isymo);
}
if (Records[i].Index != Records[i].End) err.submit(1203); // Check for consistency
}
}
// Search for OMF_COMDEF records
for (i = 0; i < NumRecords; i++) {
if (Records[i].Type2 == OMF_COMDEF) {
// COMDEF record, Borland communal name
uint32 DType;
//uint32 DSize;
//uint32 DNum;
Records[i].Index = 3;
// Loop through possibly multiple entries in record
while (Records[i].Index < Records[i].End) {
string = Records[i].GetString();
Records[i].GetByte(); // Type index, should be 0, ignore
DType = Records[i].GetByte(); // Data type
switch (DType) {
case 0x61:
//DNum = Records[i].GetLength();
//DSize = Records[i].GetLength();
continue; // Don't know what to do with this type. Ignore
case 0x62:
//DSize = Records[i].GetLength();
continue; // Don't know what to do with this type. Ignore
default:
//DSize = Records[i].GetLength();
if (DType < 0x60) { // Borland segment index
break;
}
continue; // Unknown type. Ignore
}
// Define symbol
Segment = CommunalSection;
isymo = Disasm.AddSymbol(Segment, 0, 0, 0, 0x10, 0, string);
// Update table for translating old PUBDEF number to disassembler symbol index
PubdefTranslation.Push(isymo);
}
CommunalSection++;
if (Records[i].Index != Records[i].End) err.submit(1203); // Check for consistency
}
}
}
void COMF2ASM::MakeCommunalSymbolsTable() {
// Make symbol table entries for communal symbols
char * string; // Symbol name
// Search for communal records
for (uint32 i = 0; i < NumRecords; i++) {
// Count communal records
if (Records[i].Type2 == OMF_CEXTDEF) {
Records[i].Index = 3;
// Loop through strings in record
while (Records[i].Index < Records[i].End) {
uint32 LIndex = Records[i].GetIndex();
Records[i].GetIndex(); // Group. Ignore
string = GetLocalName(LIndex);
// find section with same name
int32 section = 0;
for (uint32 j = 0; j < Segments.GetNumEntries(); j++) {
if (Segments[j].NameIndex == LIndex) {
section = (int32)j; break;
}
}
// Define symbol
Disasm.AddSymbol(section, 0, 0, 0, 0x10, 0, string);
}
}
}
}
void COMF2ASM::MakeGroupDefinitions() {
// Make segment group definitions
uint32 i; // Record index
// Search for group records
for (i = 0; i < NumRecords; i++) {
if (Records[i].Type2 == OMF_GRPDEF) {
// GRPDEF record
Records[i].Index = 3;
// Get group name
uint32 ClassIndex = Records[i].GetIndex();
char * GroupName = GetLocalName(ClassIndex);
// Define group
Disasm.AddSectionGroup(GroupName, 0);
// Loop through remaining entries in record
while (Records[i].Index < Records[i].End) {
// Entry type should be 0xFF
uint8 Type = Records[i].GetByte();
// Get member name
int32 NameIndex = Records[i].GetIndex();
// Check if type valid
if (Type == 0xFF && NameIndex > 0) {
// A group member is found. Add member to group
Disasm.AddSectionGroup(GroupName, NameIndex);
}
}
if (Records[i].Index != Records[i].End) err.submit(1203); // Check for consistency
}
}
}
// MakeSegmentList
void COMF2ASM::MakeSegmentList() {
// Make Sections list in Disasm
int32 SegNum; // Segment number
int32 Segment = 0; // Segment number in OMF record
uint32 RecNum; // OMF record number
uint32 LastDataRecord; // OMF record number of last LEDATA record
uint32 RecOffset; // Segment offset of LEDATA, LIDATA record
uint32 RecSize; // Data size of LEDATA, LIDATA record
uint32 LastDataRecordSize; // Last RecSize
uint32 LastOffset; // Last RecOffset
int8 * LastDataRecordPointer; // Point to last raw data
uint32 BufOffset; // Offset of segment into SegmentData buffer
CMemoryBuffer TempBuf; // Temporary buffer for building raw data
// Loop through segments
for (SegNum = 1; SegNum <= NumSegments; SegNum++) {
// Get size
uint32 SegmentSize = Segments[SegNum].Size;
if (SegmentSize == 0) continue; // Empty segment
// Allocate temporary data buffer and reset it
TempBuf.SetSize(SegmentSize + 16);
int FillByte = 0; // Byte to fill memory with
if (Segments[SegNum].Type == 1) {
// Code segment. Fill any unused bytes with NOP opcode = 0x90
FillByte = 0x90;
}
memset(TempBuf.Buf(), FillByte, SegmentSize + 16);// Reset to all 0 or NOP
LastDataRecord = 0;
LastDataRecordSize = 0;
LastDataRecordPointer = 0;
LastOffset = 0;
int comdatsSoFar = 0;
// Search for LEDATA, LIDATA and FIXUPP records for this segment
for (RecNum = 0; RecNum < NumRecords; RecNum++) {
if (Records[RecNum].Type2 == OMF_LEDATA) {
// LEDATA record
Records[RecNum].Index = 3; // Initialize record reading
Segment = Records[RecNum].GetIndex();// Read segment number
if ((Segment & 0xC000) == 0x4000) {
// Refers to Borland communal section
Segment = (Segment & ~0x4000) + FirstComDatSection - 1;
}
if (Segment != SegNum) continue; // Does not refer to this segment
RecOffset = Records[RecNum].GetNumeric();// Read offset of this record
RecSize = Records[RecNum].End - Records[RecNum].Index; // Calculate size of data
LastDataRecord = RecNum; // Save for later FIXUPP that refers to this record
if (RecOffset < LastOffset + LastDataRecordSize && LastOffset < RecOffset + RecSize) {
// Overlapping data records
if (RecOffset + 8 < LastOffset + LastDataRecordSize || Segments[SegNum].Type != 1) {
// Overlapping data by more than 7 bytes or not executable code
err.submit(1207);
}
else {
// Possibly backpatched code
err.submit(1208); // Warning
err.ClearError(1208); // Report only once
}
}
LastDataRecordSize = RecSize;
LastDataRecordPointer = Records[RecNum].buffer + Records[RecNum].FileOffset + Records[RecNum].Index;
LastOffset = RecOffset; // Save offset for subsequent FIXUPP records
// Check if data within segment
if (RecOffset + RecSize > SegmentSize) {
err.submit(2309, GetSegmentName(Segment));
continue;
}
// Put raw data into temporary buffer
memcpy(TempBuf.Buf() + RecOffset, LastDataRecordPointer, RecSize);
} // Finished with LEDATA record
if (Records[RecNum].Type2 == OMF_LIDATA) {
// LIDATA record
Records[RecNum].Index = 3; // Initialize record reading
Segment = Records[RecNum].GetIndex();
if (Segment != SegNum) continue; // Does not refer to this segment
LastDataRecord = RecNum; // Save for later FIXUPP that refers to this record
RecOffset = Records[RecNum].GetNumeric();// Read offset
if (RecOffset > SegmentSize) {
err.submit(2310); continue; // Error: outside bounds
}
// Unpack LIDATA blocks recursively
RecSize = Records[RecNum].UnpackLIDATABlock(TempBuf.Buf() + RecOffset, SegmentSize - RecOffset);
if (RecOffset < LastOffset + LastDataRecordSize && LastOffset < RecOffset + RecSize) {
// Overlapping data records
err.submit(1207); // Warning
}
LastDataRecordSize = RecSize; // Save data size
LastOffset = RecOffset; // Save offset for subsequent FIXUPP records
} // Finished with LIDATA record
if (Records[RecNum].Type2 == OMF_COMDAT) {
// COMDAT record.
Records[RecNum].Index = 3; // Initialize record reading
uint16 flags = Records[RecNum].GetByte();
if ((flags&1)==0) { // not a continuation
++comdatsSoFar;
LastDataRecord = RecNum; // Save for later FIXUPP that refers to this record
}
Segment = FirstComDatSection + comdatsSoFar-1;
if (SegNum != Segment) continue;
uint16 attribs = Records[RecNum].GetByte();
Records[RecNum].GetByte(); // align (ignore)
RecOffset = Records[RecNum].GetNumeric();
Records[RecNum].GetIndex(); // type (ignore)
if ((attribs&0xF)==0) {
Records[RecNum].GetIndex(); // public base
uint16 publicSegment = Records[RecNum].GetIndex();
if (publicSegment==0) Records[RecNum].GetIndex(); // public frame (ignore)
}
Records[RecNum].GetIndex(); // public name (ignore)
RecSize = Records[RecNum].End - Records[RecNum].Index; // Calculate size of data
LastDataRecord = RecNum; // Save for later FIXUPP that refers to this record
LastDataRecordSize = RecSize;
LastDataRecordPointer = Records[RecNum].buffer + Records[RecNum].Index+Records[RecNum].FileOffset;
LastOffset = RecOffset;
// Put raw data into temporary buffer
memcpy(TempBuf.Buf() + RecOffset, LastDataRecordPointer, RecSize);
} // Finished with COMDAT record
if (Records[RecNum].Type2 == OMF_FIXUPP) {
// FIXUPP record
if (Segment != SegNum) continue; // Does not refer to this segment
Records[RecNum].Index = 3;
if (Records[LastDataRecord].Type2 == OMF_LEDATA) {
// FIXUPP for last LEDATA record
// Make relocation records
MakeRelocations(Segment, RecNum, LastOffset, LastDataRecordSize, (uint8*)TempBuf.Buf());
}
else if (Records[RecNum].Index < Records[RecNum].End) {
// Non-empty FIXUPP record does not refer to LEDATA record
if (Records[LastDataRecord].Type2 == OMF_COMDAT) {
// FIXUPP for last COMDAT record
// Make relocation records
MakeRelocations(Segment, RecNum, LastOffset, LastDataRecordSize, (uint8*)TempBuf.Buf());
}
else if (Records[LastDataRecord].Type2 == OMF_LIDATA) {
err.submit(2311); // Error: Relocation of iterated data not supported
}
else {
err.submit(2312); // Does not refer to data record
}
}
}
} // End of loop to search for LEDATA, LIDATA and FIXUPP records for this segment
// Transfer raw data from TempBuf to SegmentData buffer
BufOffset = SegmentData.Push(TempBuf.Buf(), SegmentSize);
// Remember offset into SegmentData
Segments[SegNum].BufOffset = BufOffset;
} // End of first loop through segments
// We must put all segments into SegmentData buffer before we assign pointers to
// the raw data because otherwise the SegmentData buffer might me reallocated
// when it grows and the pointers become invalid. This is the reasons why we
// have two loops through the segments here.
// Second loop through segments
int totalcodesize=0;
for (SegNum = 1; SegNum <= NumSegments; SegNum++) {
// Pointer to merged raw data
uint8 * RawDatap = (uint8*)SegmentData.Buf() + Segments[SegNum].BufOffset;
// Size of raw data
uint32 InitSize = (Segments[SegNum].Type == 3) ? 0 : Segments[SegNum].Size;
// Define segment
const char * SegmentName = NameBuffer.Buf() + Segments[SegNum].NameO;
Disasm.AddSection(RawDatap, InitSize, Segments[SegNum].Size, Segments[SegNum].Offset,
Segments[SegNum].Type, Segments[SegNum].Align, Segments[SegNum].WordSize, SegmentName);
if (Segments[SegNum].Type == 1 || Segments[SegNum].Type == 0x1001) {
totalcodesize += Segments[SegNum].Size;
}
}
}
// MakeRelocations
void COMF2ASM::MakeRelocations(int32 Segment, uint32 RecNum, uint32 SOffset, uint32 RSize, uint8 * SData) {
// Make relocations for object and executable files
// Parameters:
// Segment = segment index of last LEDATA record
// RecNum = FIXUPP record number
// SOffset = segment relative offset of last LEDATA record
// RSize = Size of last LEDATA record
// SData = pointer to raw segment data
uint32 Frame, Target, TargetDisplacement; // Contents of FIXUPP record
uint8 byte1, byte2; // First two bytes of subrecord
int32 Inline; // Inline address or addend in relocation source
//int16 InlineSeg; // Segment address stored in relocation source
int32 Addend; // Correction to add to target address
int32 SourceSize; // Size of relocation source
uint32 RelType; // Relocation type, as defined in disasm.h
int32 TargetSegment; // Target segment or group
uint32 TargetOffset; // Target offset
uint32 TargetSymbol; // Symbol index of target
uint32 ReferenceIndex; // Segment/group index of reference frame
// Bitfields in subrecords
OMF_SLocat Locat; // Structure of first two bytes of FIXUP subrecord swapped = Locat field
OMF_SFixData FixData; // Structure of FixData field in FIXUP subrecord of FIXUPP record
OMF_STrdDat TrdDat; // Structure of Thread Data field in THREAD subrecord of FIXUPP record
Records[RecNum].Index = 3;
// Loop through entries in record
while (Records[RecNum].Index < Records[RecNum].End) {
// Read first byte
byte1 = Records[RecNum].GetByte();
if (byte1 & 0x80) {
// This is a FIXUP subrecord
Frame = 0; Target = 0; TargetDisplacement = 0; Addend = 0; ReferenceIndex = 0;
// read second byte
byte2 = Records[RecNum].GetByte();
// swap bytes and put into byte12 bitfield
Locat.bytes[1] = byte1;
Locat.bytes[0] = byte2;
// Read FixData
FixData.b = Records[RecNum].GetByte();
// Read conditional fields
if (FixData.s.F) {
// Frame specified by previously define thread
// Does anybody still use compression of repeated fixup targets?
// I don't care to support this if it is never used
err.submit(2313); // Error message: not supported
continue;
}
else {
if (FixData.s.Frame < 4) {
// Frame datum field present
Frame = Records[RecNum].GetIndex();
}
else Frame = 0;
switch (FixData.s.Frame) { // Frame method
case 0: // F0: segment
ReferenceIndex = Frame;
break;
case 1: // F1: group
// Groups defined after segments. Add number of segments to get group index
ReferenceIndex = Frame + NumSegments;
break;
default:
case 2: // F2: external symbol
ReferenceIndex = 0;
break;
case 4: // F4: traget frame = source frame
Frame = Segment;
break;
case 5: // F5: target frame = target segment
Frame = 0;
break;
}
}
if (FixData.s.T == 0) {
// Target specified
Target = Records[RecNum].GetIndex();
if ((Target & 0xC000) == 0x4000) {
// Refers to Borland communal section
Target = (Target & ~0x4000) + FirstComDatSection - 1;
}
//uint32 TargetMethod = FixData.s.Target + FixData.s.P * 4;
}
else {
// Target specified in previous thread
// Does anybody still use compression of repeated fixup targets?
// I don't care to support this if it is never used
err.submit(2313); // Error message: not supported
continue;
}
if (FixData.s.P == 0) {
TargetDisplacement = Records[RecNum].GetNumeric();
}
if (!SData || Locat.s.Offset > RSize) {
err.submit(2032); // Relocation points outside segment
return;
}
// Get inline addend and check relocation method
// Pointer to relocation source inline in raw data:
uint8 * inlinep = SData + SOffset + Locat.s.Offset;
Inline = 0; SourceSize = 0;
//InlineSeg = 0;
TargetSegment = 0; TargetOffset = 0; TargetSymbol = 0;
// Relocation type
if (Locat.s.M) {
// Segment relative
RelType = 8;
}
else {
// (E)IP relative
RelType = 2;
}
switch (Locat.s.Location) {// Relocation method
case OMF_Fixup_8bit: // 8 bit
SourceSize = 1;
Inline = *(int8*)inlinep;
break;
case OMF_Fixup_16bit: // 16 bit
SourceSize = 2;
Inline = *(int16*)inlinep;
break;
case OMF_Fixup_32bit: // 32 bit
SourceSize = 4;
Inline = *(int32*)inlinep;
break;
case OMF_Fixup_Far: // far 16+16 bit
RelType = 0x400;
SourceSize = 4;
Inline = *(int16*)inlinep;
break;
case OMF_Fixup_Farword: // far 32+16 bit
case OMF_Fixup_Pharlab48:
RelType = 0x400;
SourceSize = 6;
Inline = *(int32*)inlinep;
break;
case OMF_Fixup_Segment: // segment selector
if (TargetDisplacement || FixData.s.Target == 2) {
// An offset is specified or an external symbol.
// Segment of symbol is required (seg xxx)
RelType = 0x200;
}
else {
// A segment name or group name is required
RelType = 0x100;
};
SourceSize = 2;
Inline = *(int16*)inlinep;
break;
case OMF_Fixup_16bitLoader: // 16-bit loader resolved
RelType = 0x21;
SourceSize = 2;
Inline = *(int16*)inlinep;
break;
case OMF_Fixup_32bitLoader: // 32-bit loader resolved
RelType = 0x21;
SourceSize = 4;
Inline = *(int32*)inlinep;
break;
default: // unknown or not supported
RelType = 0;
SourceSize = 0;
Inline = 0;
} // end switch
// Offset of relocation source
uint32 SourceOffset = SOffset + Locat.s.Offset;
// Relocation type: direct or (E)IP-relative
if (RelType == 2) {
// (E)IP-relative
// Correct for difference between source address and end of instruction
Addend = -SourceSize;
}
// Check target method
switch (FixData.s.Target) { // = Target method modulo 4
case 0: // T0 and T4: Target = segment
// Local or public symbol
TargetSegment = Target; // Target segment
TargetOffset = TargetDisplacement; // Target offset
if (RelType != 0x100) {
// Add inline to target address, except if target is a segment only
TargetOffset += Inline;
Addend -= Inline; // Avoid adding Inline twice
}
break;
case 1: // T1 and T5: Target = segment group
// Warning: this method has not occurred. Not tested!
// Groups are numbered in sequence after segments in Disasm. Add number of segments to group index
TargetSegment = Target + NumSegments;// Target group
TargetOffset = TargetDisplacement; // Target offset
if (RelType != 0x100) {
// Add inline to target address, except if target is a segment only
TargetOffset += Inline;
Addend -= Inline; // Avoid adding Inline twice
}
break;
case 2: // T2 and T6: Target = external symbol
// Translate old EXTDEF index to new symbol table index
if (Target < ExtdefTranslation.GetNumEntries()) {
TargetSymbol = ExtdefTranslation[Target];
}
break;
default: // Unknown method
err.submit(2314, FixData.s.Target + FixData.s.P * 4);
}
if (TargetSymbol == 0) {
// Make symbol record for target
TargetSymbol = Disasm.AddSymbol(TargetSegment, TargetOffset, 0, 0, 2, 0, 0);
}
if (FixData.s.Frame == 4 && FixData.s.Target + FixData.s.P*4 == 6) {
// Note:
// Frame method F4 is apparently used by 16-bit Borland compiler for
// indicating floating point instructions that can be emulated if no
// 8087 processor is present. I can't find this documented anywhere.
// I don't know what the exact criterion is for indicating that a FIXUP
// subrecord is not a relocation record but a f.p. emulating record.
// I have chosen to consider all subrecords with frame method F4 and
// target method T6 to be ignored.
;
}
else {
// This is a proper relocation subrecord
Disasm.AddRelocation(Segment, SourceOffset, Addend, RelType, SourceSize, TargetSymbol, ReferenceIndex);
}
}
else {
// This is a THREAD subrecord.
// I don't think this feature for compressing fixup data is
// used any more, if it ever was. I am not supporting it here.
// Frame threads can be safely ignored. A target thread cannot
// be ignored if there is any reference to it. The error is
// reported above at the reference to a target thread, not here.
TrdDat.b = byte1; // Put byte into bitfield
if (TrdDat.s.Method < 4) { // Make sure we read this correctly, even if ignored
Records[RecNum].GetIndex(); // has index field if method < 4 ?
}
}
} // Finished loop through subrecords
if (Records[RecNum].Index != Records[RecNum].End) err.submit(1203); // Check for consistency
}

View File

@ -0,0 +1,875 @@
/**************************** omf2cof.cpp *********************************
* Author: Agner Fog
* Date created: 2007-02-08
* Last modified: 2018-08-15
* Project: objconv
* Module: omf2cof.cpp
* Description:
* Module for converting OMF file to PE/COFF file
*
* Copyright 2007-2018 GNU General Public License http://www.gnu.org/licenses
*****************************************************************************/
#include "stdafx.h"
// Alignment value translation table
static const uint32 OMFAlignTranslate[8] = {0,1,2,16,256,4,0,0};
COMF2COF::COMF2COF() {
// Constructor
memset(this, 0, sizeof(*this)); // Reset everything
}
void COMF2COF::Convert() {
// Do the conversion
// 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
MakeSymbolTable1(); // Make symbol table and string table entries for file and segments
MakeSymbolTable2(); // Make symbol table and string table entries for external symbols
MakeSymbolTable3(); // Make symbol table and string table entries for public symbols
MakeSymbolTable4(); // Make symbol table and string table entries for communal symbols
MakeSymbolTable5(); // Make symbol table and string table entries for local symbols
MakeSections(); // Make sections and relocation tables
CheckUnsupportedRecords(); // Make warnings if file containes unsupported record types
MakeBinaryFile(); // Put sections together
*this << ToFile; // Take over new file buffer
}
void COMF2COF::MakeFileHeader() {
// Convert subfunction: File header
// Make PE file header
NewFileHeader.Machine = PE_MACHINE_I386;
NewFileHeader.TimeDateStamp = (uint32)time(0);
NewFileHeader.SizeOfOptionalHeader = 0;
NewFileHeader.Flags = 0;
// Values inserted later:
NewFileHeader.NumberOfSections = 0;
NewFileHeader.PSymbolTable = 0;
NewFileHeader.NumberOfSymbols = 0;
}
void COMF2COF::MakeSymbolTable1() {
// Make symbol table string table and section table entries for file and segments
SCOFF_SymTableEntry sym; // Symbol table entry
SCOFF_SectionHeader sec; // Section header entry
char * ClassName; // Old segment class name
// Initialize new string table. make space for 4-bytes size
NewStringTable.Push(0, 4);
// Allocate SegmentTranslation buffer
SegmentTranslation.SetNum(SegmentNameOffset.GetNumEntries());
// Make symbol table entry for file name
memset(&sym, 0, SIZE_SCOFF_SymTableEntry);
strcpy(sym.s.Name, ".file");
sym.s.SectionNumber = COFF_SECTION_DEBUG;
sym.s.StorageClass = COFF_CLASS_FILE;
char * ShortFileName = CLibrary::ShortenMemberName(OutputFileName);
sym.s.NumAuxSymbols = 1; // File name is truncated so it will fit into the 18 bytes of SIZE_SCOFF_SymTableEntry
NewSymbolTable.Push(sym); // Store symbol table entry
// Needs auxiliary entry:
memset(&sym, 0, SIZE_SCOFF_SymTableEntry);
if (strlen(ShortFileName) < SIZE_SCOFF_SymTableEntry) {
strcpy(sym.s.Name, ShortFileName);
}
NewSymbolTable.Push(sym); // Store auxiliary symbol table entry
// Define structure of attributes
OMF_SAttrib Attributes;
// Other segment properties
uint32 SegLength, NameIndex, ClassIndex;
//uint32 Offset;
const char * sname; // Segment/section name
uint32 SegNum = 0; // Segment/section number
uint32 StringI; // New sting table index
uint32 i; // Record number
int32 j, n; // Temporary
// Loop through segments of old file
for (i = 0; i < NumRecords; i++) {
if (Records[i].Type2 == OMF_SEGDEF) {
// SEGDEF record
Records[i].Index = 3;
// Loop through entries in record. There should be only 1
while (Records[i].Index < Records[i].End) {
Attributes.b = Records[i].GetByte(); // Read attributes
if (Attributes.u.A == 0) {
// Frame and Offset only included if A = 0
Records[i].GetWord(); // Frame ignored
Records[i].GetByte();
}
//else Offset = 0;
SegLength = Records[i].GetNumeric();
NameIndex = Records[i].GetIndex();
ClassIndex = Records[i].GetIndex(); // Class index
Records[i].GetIndex(); // Overlay index ignored
sname = GetLocalName(NameIndex); // Segment name = new section name
if (Attributes.u.B) {
// Segment is big
if (Attributes.u.P) {
// 32 bit segment. Big means 2^32 bytes!
err.submit(2306);
}
else {
// 16 bit segment. Big means 2^16 bytes
SegLength = 0x10000;
}
}
// make symbol table entry
memset(&sym, 0, SIZE_SCOFF_SymTableEntry);
// Put name into string table
StringI = NewStringTable.PushString(sname);
// Put name into symbol table
//COFF_PutNameInSymbolTable(sym, sname, NewStringTable);
((uint32*)(sym.s.Name))[1] = StringI;
sym.s.SectionNumber = ++SegNum; // Count section number
sym.s.StorageClass = COFF_CLASS_STATIC;
sym.s.NumAuxSymbols = 1; // Needs 1 aux record
// Remember NewSymbolTable index
SegmentTranslation[SegNum] = NewSymbolTable.GetNumEntries();
NewSymbolTable.Push(sym); // Store symbol table entry
// Make auxiliary entry
memset(&sym, 0, SIZE_SCOFF_SymTableEntry);
// Insert section size
sym.section.Length = SegLength;
// Remember to insert NumberOfRelocations here later
// Store auxiliary symbol table entry
NewSymbolTable.Push(sym);
// Make section header
memset(&sec, 0, sizeof(sec)); // Reset section header
// Put name into section header
sprintf(sec.Name, "/%i", StringI);
// Put size into section header
sec.SizeOfRawData = SegLength;
// Alignment
switch (Attributes.u.A) {
case 0: // Absolute segment
err.submit(2307); break;
case 1: // Byte
sec.Flags |= PE_SCN_ALIGN_1; break;
case 2: // Word
sec.Flags |= PE_SCN_ALIGN_2; break;
case 3: // Paragraph
sec.Flags |= PE_SCN_ALIGN_16; break;
case 4: // Page. May be 256 or 4096, depending on system
// If we use 4096 where the source intended 256, we may get
// size and symbol offsets wrong!
sec.Flags |= PE_SCN_ALIGN_256; break;
case 5: // Dword
sec.Flags |= PE_SCN_ALIGN_4; break;
default: // Unknown alignment
err.submit(2308, Attributes.u.A);
sec.Flags |= PE_SCN_ALIGN_16; break;
}
// Get further attributes from class name
ClassName = GetLocalName(ClassIndex);
// Convert class name to upper case
n = (int32)strlen(ClassName);
for (j = 0; j < n; j++) ClassName[j] &= ~0x20;
// Search for known class names.
// Standard names are CODE, DATA, BSS, CONST, STACK
if (strstr(ClassName, "CODE") || strstr(ClassName, "TEXT")) {
// Code segment
sec.Flags |= PE_SCN_CNT_CODE | PE_SCN_MEM_EXECUTE | PE_SCN_MEM_READ;
}
else if (strstr(ClassName, "DATA")) {
// Data segment
sec.Flags |= PE_SCN_CNT_INIT_DATA | PE_SCN_MEM_READ | PE_SCN_MEM_WRITE;
}
else if (strstr(ClassName, "BSS")) {
// Unitialized data segment
sec.Flags |= PE_SCN_CNT_UNINIT_DATA | PE_SCN_MEM_READ | PE_SCN_MEM_WRITE;
}
else if (strstr(ClassName, "CONST")) {
// Constant data segment
sec.Flags |= PE_SCN_CNT_INIT_DATA | PE_SCN_MEM_READ;
}
else if (strstr(ClassName, "STACK")) {
// Stack segment. Ignore
sec.Flags |= PE_SCN_LNK_REMOVE;
err.submit(1206); // Warning: ignored
}
else {
// Unknown/user defined class. Assume data segment
sec.Flags |= PE_SCN_CNT_INIT_DATA | PE_SCN_MEM_READ | PE_SCN_MEM_WRITE;
}
// Insert pointers to relocations and raw data later
// Store section header
NewSectionHeaders.Push(sec);
}
if (Records[i].Index != Records[i].End) err.submit(1203); // Check for consistency
}
if (Records[i].Type2 == OMF_COMDAT || Records[i].Type2 == OMF_COMDEF) {
// Communal sections
err.submit(1055);
}
}
}
void COMF2COF::MakeSymbolTable2() {
// Make symbol table and string table entries for external symbols
uint32 i;
SCOFF_SymTableEntry sym; // new symbol table entry
uint32 NumExtSym = SymbolNameOffset.GetNumEntries(); // Number of external symbols
ExtdefTranslation.SetNum(NumExtSym+1); // Allocate space in translation table
// Loop through external symbol names
for (i = 1; i < NumExtSym; i++) {
// Reset symbol table entry
memset(&sym, 0, SIZE_SCOFF_SymTableEntry);
// Insert name
COFF_PutNameInSymbolTable(sym, GetSymbolName(i), NewStringTable);
// Insert storage class
sym.s.StorageClass = COFF_CLASS_EXTERNAL;
// Store symbol table entry
NewSymbolTable.Push(sym);
// Update table for translating old EXTDEF number (1-based) to new symbol table index (0-based)
ExtdefTranslation[i] = NewSymbolTable.GetNumEntries() - 1;
}
}
void COMF2COF::MakeSymbolTable3() {
// Make symbol table and string table entries for public symbols
SCOFF_SymTableEntry sym; // new symbol table entry
uint32 i; // Record index
char * string; // Symbol name
uint32 Segment; // Segment
uint32 Offset; // Offset
uint32 Namei; // Index into symbol table
SOMFLocalSymbol localsym; // Entry into LocalSymbols
// Search for PUBDEF records
for (i = 0; i < NumRecords; i++) {
if (Records[i].Type2 == OMF_PUBDEF) {
// PUBDEF record
Records[i].Index = 3;
Records[i].GetIndex(); // Group. Ignore
Segment = Records[i].GetIndex(); // Segment
if (Segment == 0) Records[i].GetWord(); // Base frame. Ignore
// Loop through strings in record
while (Records[i].Index < Records[i].End) {
string = Records[i].GetString(); // Symbol name
Offset = Records[i].GetNumeric(); // Offset to segment
Records[i].GetIndex(); // Type index. Ignore
// Reset symbol table entry
memset(&sym, 0, SIZE_SCOFF_SymTableEntry);
// Insert name
Namei = COFF_PutNameInSymbolTable(sym, string, NewStringTable);
// Insert storage class
sym.s.StorageClass = COFF_CLASS_EXTERNAL;
// Store offset
sym.s.Value = Offset;
// Section number = segment number
if (Segment == 0) sym.s.SectionNumber = COFF_SECTION_ABSOLUTE;
else sym.s.SectionNumber = (int16)Segment;
// Store symbol table entry
NewSymbolTable.Push(sym);
// Make entry into LocalSymbols to indicate that this symbol has a name
if (Segment > 0) {
// Make index into NewStringTable if we don't allready have one
if (Namei == 0) Namei = NewStringTable.PushString(string);
localsym.Offset = Offset;
localsym.Segment = Segment;
localsym.Name = Namei;
localsym.NewSymtabIndex = NewSymbolTable.GetNumEntries() - 1; // 0-based index into new symbol table
LocalSymbols.PushUnique(localsym);
}
}
if (Records[i].Index != Records[i].End) err.submit(1203); // Check for consistency
}
}
}
void COMF2COF::MakeSymbolTable4() {
// Make symbol table and string table entries for communal symbols
// Warning: Currently not supported!
}
void COMF2COF::MakeSymbolTable5() {
// Make symbol table and string table entries for local symbols.
// There is no table for local symbols in OMF files. We have to search
// through all FIXUPP records for relocation targets and assign arbitrary
// names to them.
uint32 i; // Loop counter
uint32 Target, TargetDisplacement; // Contents of FIXUPP record
uint8 byte1, byte2; // First two bytes of FIXUPP subrecord
// Bitfields in subrecords
OMF_SLocat Locat; // Structure of first two bytes of FIXUP subrecord swapped = Locat field
OMF_SFixData FixData; // Structure of FixData field in FIXUP subrecord of FIXUPP record
OMF_STrdDat TrdDat; // Structure of Thread Data field in THREAD subrecord of FIXUPP record
int8 * LastDataRecordPointer = 0; // Pointer to data in the data record that relocations refer to
uint32 LastDataRecordSize = 0; // Size of the data record that relocations refer to
SOMFLocalSymbol localsym; // Entry into LocalSymbols
uint32 LocalSymNum = 0; // Number of unnamed local symbols
char NewName[32]; // Buffer for making new name
SCOFF_SymTableEntry sym; // New symbol table entry
// Search for FIXUPP records and data records
for (i = 0; i < NumRecords; i++) {
if (Records[i].Type2 == OMF_LEDATA) {
// LEDATA record. Remember pointer to binary data in order to read inline offset
Records[i].Index = 3; // Initialize record reading
Records[i].GetIndex(); // Read segment and offset
Records[i].GetNumeric();
LastDataRecordSize = Records[i].End - Records[i].Index; // Calculate size of data
LastDataRecordPointer = Records[i].buffer + Records[i].FileOffset + Records[i].Index;
}
if (Records[i].Type2 == OMF_FIXUPP) {
// FIXUPP record
Records[i].Index = 3; // Initialize record reading
// Loop through entries in record
while (Records[i].Index < Records[i].End) {
// Read first byte
byte1 = Records[i].GetByte();
if (byte1 & 0x80) {
// This is a FIXUP subrecord
Target = 0; TargetDisplacement = 0;
// read second byte
byte2 = Records[i].GetByte();
// swap bytes and put into byte12 bitfield
Locat.bytes[1] = byte1;
Locat.bytes[0] = byte2;
// Read FixData
FixData.b = Records[i].GetByte();
// Read conditional fields
if (FixData.s.F == 0) {
if (FixData.s.Frame < 4) {
Records[i].GetIndex(); // Frame. Ignore
}
}
if (FixData.s.T == 0) {
// Target specified
Target = Records[i].GetIndex();
//uint32 TargetMethod = FixData.s.Target + FixData.s.P * 4;
}
if (FixData.s.P == 0) {
TargetDisplacement = Records[i].GetNumeric();
}
// Get inline addend
if (LastDataRecordPointer && Locat.s.Offset < LastDataRecordSize) {
int8 * inlinep = LastDataRecordPointer + Locat.s.Offset;
if (Locat.s.Location == 9 || Locat.s.Location == 13) {
TargetDisplacement += *(int32*)inlinep;
}
}
if (FixData.s.T == 0 && (FixData.s.Target == 0 || FixData.s.Target == 1)) {
// Target is local symbol
// Make entry in LocalSymbols
localsym.Offset = TargetDisplacement; // Offset to segment
localsym.Segment = Target; // Target segment
localsym.Name = 0; // Has no name yet
localsym.NewSymtabIndex = 0; // Not in new symbol table yet
// Make entry in LocalSymbols.
// PushUnique will not make an entry if this target address already
// has an entry in LocalSymbols and possibly a public name
LocalSymbols.PushUnique(localsym);
}
}
else {
// This is a THREAD subrecord. Read and ignore
TrdDat.b = byte1; // Put byte into bitfield
if (TrdDat.s.Method < 4) {
Records[i].GetIndex(); // has index field if method < 4 ?
}
}
} // Finished loop through subrecords
if (Records[i].Index != Records[i].End) err.submit(1203); // Check for consistency
}
} // Finished loop through records
// Now check LocalSymbols for unnamed symbols
for (i = 0; i < LocalSymbols.GetNumEntries(); i++) {
if (LocalSymbols[i].Name == 0) {
// Unnamed symbol. Give it a name
sprintf(NewName, "?NoName%02i", ++LocalSymNum);
// Make index in new symbol table
// Reset symbol table entry
memset(&sym, 0, SIZE_SCOFF_SymTableEntry);
// Insert name
LocalSymbols[i].Name = COFF_PutNameInSymbolTable(sym, NewName, NewStringTable);
// if (LocalSymbols[i].Name == 0) LocalSymbols[i].Name = NewStringTable.PushString(NewName);
// Store offset
sym.s.Value = LocalSymbols[i].Offset;
// Section number = segment number
sym.s.SectionNumber = LocalSymbols[i].Segment;
// Storage class
sym.s.StorageClass = COFF_CLASS_STATIC;
// Store symbol table entry
NewSymbolTable.Push(sym);
// Store index into new symbol table (0 - based)
LocalSymbols[i].NewSymtabIndex = NewSymbolTable.GetNumEntries() - 1;
}
}
}
void COMF2COF::MakeSections() {
// Make sections and relocation tables
uint32 SegNum; // Index into NewSectionHeaders = segment - 1
uint32 DesiredSegment; // Old segment number = new section number
uint32 RecNum; // Old record number
CMemoryBuffer TempBuf; // Temporary buffer for building raw data
CMemoryBuffer RelocationTable; // Temporary buffer for building new relocation table
SCOFF_Relocation rel; // New relocation table record
uint32 LastDataRecord = 0; // Index to the data record that relocations refer to
uint32 LastDataRecordSize = 0; // Size of the data record that relocations refer to
int8 * LastDataRecordPointer = 0; // Pointer to data in the data record that relocations refer to
uint32 Segment = 0; // Segment of last LEDATA, LIDATA or COMDEF record
uint32 Offset; // Offset of LEDATA or LIDATA record to segment
uint32 Size; // Size of data in LEDATA or LIDATA record
uint32 SegmentSize; // Total size of segment
uint32 LastOffset; // Offset after last LEDATA into segment
uint32 FileOffsetData; // File offset of first raw data and relocations in new file
uint32 FileOffset; // File offset of current raw data or relocations
// File offset of first data = size of file header and section headers
FileOffsetData = sizeof(SCOFF_FileHeader) + NewSectionHeaders.GetNumEntries() * sizeof(SCOFF_SectionHeader);
// Loop through segments
for (SegNum = 0; SegNum < NewSectionHeaders.GetNumEntries(); SegNum++) {
DesiredSegment = SegNum + 1; // Search for records referring to this segment
SegmentSize = NewSectionHeaders[SegNum].SizeOfRawData;
if (SegmentSize == 0) continue; // Empty segment
// Allocate temporary data buffer and reset it
TempBuf.SetSize(SegmentSize + 16);
int FillByte = 0; // Byte to fill memory with
if (NewSectionHeaders[SegNum].Flags & PE_SCN_CNT_CODE) {
// Code segment. Fill any unused bytes with NOP opcode = 0x90
FillByte = 0x90;
}
memset(TempBuf.Buf(), FillByte, SegmentSize + 16);// Reset to all 0 or NOP
// Reset relocation table buffer
RelocationTable.SetSize(0);
LastOffset = 0; LastDataRecordSize = 0;
// Search for LEDATA, LIDATA and FIXUPP records for this segment
for (RecNum = 0; RecNum < NumRecords; RecNum++) {
if (Records[RecNum].Type2 == OMF_LEDATA) {
// LEDATA record
Records[RecNum].Index = 3; // Initialize record reading
Segment = Records[RecNum].GetIndex();// Read segment number
if (Segment != DesiredSegment) continue; // Does not refer to this segment
Offset = Records[RecNum].GetNumeric();// Read offset
Size = Records[RecNum].End - Records[RecNum].Index; // Calculate size of data
LastDataRecord = RecNum; // Save for later FIXUPP that refers to this record
// Check if data within segment
if (Offset + Size > SegmentSize) {
err.submit(2309, GetSegmentName(Segment));
return;
}
if (Offset < LastOffset + LastDataRecordSize && LastOffset < Offset + Size) {
// Overlapping data records
if (Offset + 8 < LastOffset + LastDataRecordSize || !(NewSectionHeaders[SegNum].Flags & PE_SCN_CNT_CODE)) {
// Overlapping data by more than 7 bytes or not executable code
err.submit(1207);
}
else {
// Possibly backpatched code
err.submit(1208); // Warning
err.ClearError(1208); // Report only once
}
}
LastDataRecordSize = Size;
LastDataRecordPointer = Records[RecNum].buffer + Records[RecNum].FileOffset + Records[RecNum].Index;
LastOffset = Offset; // Save offset for subsequent FIXUPP records
/*// Check if data within segment
if (Offset + Size > SegmentSize) {
err.submit(2309, GetSegmentName(Segment));
continue;
} */
// Put raw data into temporary buffer
memcpy(TempBuf.Buf() + Offset, LastDataRecordPointer, Size);
} // Finished with LEDATA record
if (Records[RecNum].Type2 == OMF_LIDATA) {
// LIDATA record
Records[RecNum].Index = 3; // Initialize record reading
Segment = Records[RecNum].GetIndex();
if (Segment != DesiredSegment) continue; // Does not refer to this segment
LastDataRecord = RecNum; // Save for later FIXUPP that refers to this record
Offset = Records[RecNum].GetNumeric();// Read offset
if (Offset > SegmentSize) {
err.submit(2310); return; // Error: outside bounds
}
// Unpack LIDATA blocks recursively
Size = Records[RecNum].UnpackLIDATABlock(TempBuf.Buf() + Offset, SegmentSize - Offset);
if (Offset < LastOffset + LastDataRecordSize && LastOffset < Offset + Size) {
// Overlapping data records
err.submit(1207); // Warning
}
LastDataRecordSize = Size; // Save data size
LastOffset = Offset; // Save offset for subsequent FIXUPP records
} // Finished with LIDATA record
if (Records[RecNum].Type2 == OMF_COMDAT) {
// COMDAT record. Currently not supported by objconv
LastDataRecord = RecNum; // Save for later FIXUPP that refers to this record
Segment = 0; // Ignore any relocation referring to this
}
if (Records[RecNum].Type2 == OMF_FIXUPP) {
// FIXUPP record
if (Segment != DesiredSegment) continue; // Does not refer to this segment
uint32 Target, TargetDisplacement; // Contents of FIXUPP record
//uint32 Frame; // Contents of FIXUPP record
uint8 byte1, byte2; // First two bytes of subrecord
// Bitfields in subrecords
OMF_SLocat Locat; // Structure of first two bytes of FIXUP subrecord swapped = Locat field
OMF_SFixData FixData; // Structure of FixData field in FIXUP subrecord of FIXUPP record
OMF_STrdDat TrdDat; // Structure of Thread Data field in THREAD subrecord of FIXUPP record
Records[RecNum].Index = 3;
if (Records[LastDataRecord].Type2 != OMF_LEDATA && Records[RecNum].Index < Records[RecNum].End) {
// Non-empty FIXUPP record does not refer to LEDATA record
if (Records[LastDataRecord].Type2 == OMF_COMDAT) {
// COMDAT currently not supported. Ignore!
}
else if (Records[LastDataRecord].Type2 == OMF_LIDATA) {
err.submit(2311); // Error: Relocation of iterated data not supported
}
else {
err.submit(2312); // Does not refer to data record
}
continue; // Ignore this FIXUPP record
}
// Loop through entries in record
while (Records[RecNum].Index < Records[RecNum].End) {
// Read first byte
byte1 = Records[RecNum].GetByte();
if (byte1 & 0x80) {
// This is a FIXUP subrecord
//Frame = 0;
Target = 0; TargetDisplacement = 0;
// read second byte
byte2 = Records[RecNum].GetByte();
// swap bytes and put into byte12 bitfield
Locat.bytes[1] = byte1;
Locat.bytes[0] = byte2;
// Read FixData
FixData.b = Records[RecNum].GetByte();
// Read conditional fields
if (FixData.s.F == 0) {
if (FixData.s.Frame < 4) {
Records[RecNum].GetIndex();
}
}
if (FixData.s.T == 0) {
// Target specified
Target = Records[RecNum].GetIndex();
//uint32 TargetMethod = FixData.s.Target + FixData.s.P * 4;
}
else {
// Target specified in previous thread
// Does anybody still use compression of repeated fixup targets?
// I don't care to support this if it is never used
err.submit(2313); // Error message: not supported
continue;
}
if (FixData.s.P == 0) {
TargetDisplacement = Records[RecNum].GetNumeric();
}
// Get inline addend and check relocation method
if (LastDataRecordPointer && Locat.s.Offset < LastDataRecordSize) {
// Pointer to relocation source inline in raw data:
int8 * inlinep = LastDataRecordPointer + Locat.s.Offset;
switch (Locat.s.Location) { // Relocation method
case 9: case 13: // 32 bit
// The OMF format may indicate a relocation target by an
// offset stored inline in the relocation source.
// We prefer to store the target address explicitly in a
// symbol table entry.
// Add the inline offset to the explicit offset
TargetDisplacement += *(uint32*)inlinep;
// Remove the inline addend to avoid adding it twice:
// We have to do this in the new buffer TempBuf because
// the data have already been copied to TempBuf
if (*(uint32*)(TempBuf.Buf() + LastOffset + Locat.s.Offset) != *(uint32*)inlinep) {
// Check that the data in Buf() and TempBuf.Buf() are the same
err.submit(9000);
}
// Remove the inline addend to avoid adding it twice
*(uint32*)(TempBuf.Buf() + LastOffset + Locat.s.Offset) = 0;
break;
case 0: case 4: // 8 bit. Not supported
err.submit(2316, "8 bit"); break;
case 1: case 2: case 5: // 16 bit. Not supported
err.submit(2316, "16 bit"); break;
case 3: // 16+16 bit. Not supported
err.submit(2316, "16+16 bit far"); break;
case 6: case 11: // 16+32 bit. Not supported
err.submit(2316, "16+32 bit far"); break;
}
}
// Make relocation record
// Offset of relocation source
rel.VirtualAddress = Locat.s.Offset + LastOffset;
SOMFLocalSymbol locsym; // Symbol record for search in LocalSymbols table
int32 LocalSymbolsIndex; // Index into LocalSymbols table
// Relocation type: direct or EIP-relative
// (The displacement between relocation source and EIP for
// self-relative relocations is implicit in both OMF and COFF
// files. No need for correction)
rel.Type = Locat.s.M ? COFF32_RELOC_DIR32 : COFF32_RELOC_REL32;
switch (FixData.s.Target) { // = Target method modulo 4
case 0: // T0 and T4: Target = segment
// Local or public symbol. Search in LocalSymbols table
locsym.Segment = Target; // Target segment
locsym.Offset = TargetDisplacement; // Target offset including inline displacement
// Find in LocalSymbols table
LocalSymbolsIndex = LocalSymbols.Exists(locsym);
if (LocalSymbolsIndex < 0) {err.submit(9000); continue;} // Not found
// Get index into new symbol table
rel.SymbolTableIndex = LocalSymbols[LocalSymbolsIndex].NewSymtabIndex;
break;
case 1: // T1 and T5: Target = segment group
// Don't know how to handle group-relative relocation. Make error message
err.submit(2315, GetLocalName(Target));
continue;
case 2: // T2 and T6: Target = external symbol
// Translate old EXTDEF index to new symbol table index
if (Target >= ExtdefTranslation.GetNumEntries()) {
Target = 0; err.submit(2312);
continue;
}
rel.SymbolTableIndex = ExtdefTranslation[Target];
// Put addend inline in new file
if (LastOffset + Locat.s.Offset < SegmentSize) {
*(uint32*)(TempBuf.Buf() + LastOffset + Locat.s.Offset) = TargetDisplacement;
}
break;
default: // Unknown method
err.submit(2314, FixData.s.Target + FixData.s.P * 4);
}
// Store in temporary relocation table
RelocationTable.Push(&rel, SIZE_SCOFF_Relocation);
}
else {
// This is a THREAD subrecord.
// I don't think this feature for compressing fixup data is
// used any more, if it ever was. I am not supporting it here.
// Frame threads can be safely ignored. A target thread cannot
// be ignored if there is any reference to it. The error is
// reported above at the reference to a target thread, not here.
TrdDat.b = byte1; // Put byte into bitfield
if (TrdDat.s.Method < 4) { // Make sure we read this correctly, even if ignored
Records[RecNum].GetIndex(); // has index field if method < 4 ?
}
}
} // Finished loop through subrecords
if (Records[RecNum].Index != Records[RecNum].End) err.submit(1203); // Check for consistency
}
} // End of loop to search for LEDATA, LIDATA and FIXUPP records for this segment
// Transfer raw data from TempBuf to NewData buffer
FileOffset = NewData.Push(TempBuf.Buf(), SegmentSize);
// Put file offset of raw data into section header
NewSectionHeaders[SegNum].PRawData = FileOffsetData + FileOffset;
// Align relocation table by 4
NewData.Align(4);
// Transfer relocation table from RelocationTable to NewData buffer
FileOffset = NewData.Push(RelocationTable.Buf(), RelocationTable.GetDataSize());
// Put file offset of relocations into section header
NewSectionHeaders[SegNum].PRelocations = FileOffsetData + FileOffset;
// Put number of relocations into section header
NewSectionHeaders[SegNum].NRelocations = (uint16)(RelocationTable.GetNumEntries());
// Put number of relocations into symbol table auxiliary entry.
// Search for the symbol table entry for this section:
for (uint32 sym = 0; sym < NewSymbolTable.GetNumEntries(); sym++) {
if ((uint32)NewSymbolTable[sym].s.SectionNumber == DesiredSegment
&& NewSymbolTable[sym].s.StorageClass == COFF_CLASS_STATIC
&& NewSymbolTable[sym].s.NumAuxSymbols == 1) {
// Found right symbol table entry. Insert NumberOfRelocations
NewSymbolTable[sym+1].section.NumberOfRelocations = NewSectionHeaders[SegNum].NRelocations;
break; // No need to search further
}
}
} // End of loop through segments
}
void COMF2COF::CheckUnsupportedRecords() {
// Make warnings if file containes unsupported record types
uint32 RecNum; // Record number
uint32 NumComdat = 0; // Number of COMDAT records
uint32 NumComent = 0; // Number of COMENT records
// Loop through all records
for (RecNum = 0; RecNum < NumRecords; RecNum++) {
// Check record type
switch (Records[RecNum].Type2) {
case OMF_THEADR: case OMF_MODEND: case OMF_EXTDEF: case OMF_PUBDEF:
case OMF_LNAMES: case OMF_SEGDEF: case OMF_GRPDEF: case OMF_FIXUPP:
case OMF_LEDATA: case OMF_LIDATA: case OMF_COMDEF: case OMF_VERNUM:
// These record types are supported or can safely be ignored
break;
case OMF_LINNUM: case OMF_LINSYM:
// Debug records
cmd.CountDebugRemoved(); break;
case OMF_COMDAT: case OMF_LCOMDEF: case OMF_CEXTDEF:
NumComdat++; break; // Count COMDAT records
case OMF_COMENT:
NumComent++; break; // Count COMENT records
default: // Warning for unknown record type
err.submit(1212, COMF::GetRecordTypeName(Records[RecNum].Type2));
}
}
// Report number of unsupported sections found
if (NumComdat) err.submit(2305, NumComdat);
if (NumComent) err.submit(1211, NumComent);
}
void COMF2COF::MakeBinaryFile() {
// Putting sections together
uint32 i;
// Get number of symbols and sections into file header
NewFileHeader.NumberOfSymbols = NewSymbolTable.GetNumEntries();
NewFileHeader.NumberOfSections = NewSectionHeaders.GetNumEntries();
// Put file header into new file
ToFile.Push(&NewFileHeader, sizeof(NewFileHeader));
// Put section headers into new file
if (NewSectionHeaders.GetNumEntries()) {
ToFile.Push(&NewSectionHeaders[0], NewSectionHeaders.GetNumEntries() * sizeof(SCOFF_SectionHeader));
}
// Put raw data and relocation tables into new file
ToFile.Push(NewData.Buf(), NewData.GetDataSize());
// Get address of symbol table into file header
ToFile.Get<SCOFF_FileHeader>(0).PSymbolTable = ToFile.GetDataSize();
// Put symbol table into new file
for (i = 0; i < NewSymbolTable.GetNumEntries(); i++) {
ToFile.Push(&NewSymbolTable[i], SIZE_SCOFF_SymTableEntry);
}
// Insert string table size
NewStringTable.Get<uint32>(0) = NewStringTable.GetDataSize();
// Put string table into new file
ToFile.Push(NewStringTable.Buf(), NewStringTable.GetDataSize());
}

View File

@ -0,0 +1,382 @@
/**************************** omfhash.cpp **********************************
* Author: Agner Fog
* Date created: 2007-02-14
* Last modified: 2007-02-14
* Project: objconv
* Module: omfhash.cpp
* Description:
* This module contains code for searching and making hash tables for OMF
* libraries.
*
* Copyright 2007-2008 GNU General Public License http://www.gnu.org/licenses
*****************************************************************************/
#include "stdafx.h"
void COMFHashTable::Init(SOMFHashBlock * blocks, uint32 NumBlocks) {
// Initialize
this->blocks = blocks; // Pointer to blocks
this->NumBlocks = NumBlocks; // Number of blocks
String = 0;
StringLength = 0;
}
// Rotate right 16-bit word
uint16 RotR(uint16 x, uint16 bits) {
return (x >> bits) | (x << (16 - bits));
}
// Rotate left 16-bit word
uint16 RotL(uint16 x, uint16 bits) {
return (x << bits) | (x >> (16 - bits));
}
void COMFHashTable::MakeHash(int8 * name) {
// Compute hash according to the official algorithm
uint8 * pb; // Pointer for forward scan through string
uint8 * pe; // Pointer for backwards scan through string
uint16 c; // Current character converted to lower case
uint16 BlockX; // Calculate block hash
uint16 BucketX; // Calculate block hash
String = (uint8*)name; // Type cast string to unsigned char *
StringLength = (uint32)strlen(name);
if (StringLength > 255 || StringLength == 0) {
// String too long
err.submit(1204, name); // Warning: truncating
StringLength = 255;
String[StringLength] = 0; // Truncation modifies string source!
}
String = (uint8*)name; // Type cast to unsigned characters
pb = String; // Initialize pointer for forward scan
pe = String + StringLength; // Initialize pointer for backward scan
BlockX = BucketD = StringLength | 0x20; // Initialize left-to-right scan
BucketX = BlockD = 0; // Initialize right-to-left scan
// Scan loop
while (1) {
c = *(--pe) | 0x20; // Read character for backward scan, make lower case
BucketX = RotR(BucketX, 2) ^ c; // Rotate, XOR
BlockD = RotL(BlockD, 2) ^ c; // Rotate, XOR
if (pe == String) break; // Stop loop when backward scan finished
c = *(pb++) | 0x20; // Read character for forward scan, make lower case
BlockX = RotL(BlockX, 2) ^ c; // Rotate, XOR
BucketD = RotR(BucketD, 2) ^ c; // Rotate, XOR
}
// Make values modulo number of blocks / buckets
BlockX = BlockX % NumBlocks;
BlockD = BlockD % NumBlocks;
if (BlockD == 0) BlockD = 1;
BucketX = BucketX % OMFNumBuckets;
BucketD = BucketD % OMFNumBuckets;
if (BucketD == 0) BucketD = 1;
StartBlock = BlockX;
StartBucket = BucketX;
}
int COMFHashTable::FindString(uint32 & ModulePage, uint32 & Conflicts) {
// Search for String.
// Returns number of occurrences of String
// Module receives the module page for the first occurrence
// Conflicts receives the number of conflicting entries encountered before the match
uint32 Num = 0; // Number of occurrences of string found
uint16 Block; // Block number
uint16 Bucket; // Bucket number
uint32 StringIndex; // Index to string
Conflicts = 0; // Start counting Conflicts
Block = StartBlock;
Bucket = StartBucket;
// Loop through blocks
do {
// Loop through buckets
do {
// String index of current bucket
StringIndex = blocks[Block].b.Buckets[Bucket];
if (StringIndex == 0) {
if (blocks[Block].b.FreeSpace < 0xff) {
// Empty bucket found. End of search
return Num;
}
else {
// Block is full. Search next block
// Note: It would be logical to set StartBucket = Bucket
// here in order to allow all buckets in the next block
// to be tried, but the official algorithm doesn't seem
// to do so!?
// StartBucket = Bucket;
break;
}
}
// Bucket contains a string. Is it the same string?
if (blocks[Block].Strings[StringIndex*2] == StringLength
&& strncmp((int8*)&blocks[Block].Strings[StringIndex*2+1], (int8*)String, StringLength) == 0) {
// Matching string found
Num++;
if (Num == 1) {
// First occurrence. Save module number
ModulePage = *(uint16*)&blocks[Block].Strings[StringIndex*2+1+StringLength];
}
}
else {
// Conflicting string found
Conflicts++;
}
// Next bucket
Bucket = (Bucket + BucketD) % OMFNumBuckets;
} while (Bucket != StartBucket);
// Next block
Block = (Block + BlockD) % NumBlocks;
} while (Block != StartBlock);
// Finished searching all blocks and buckets
return Num;
}
int COMFHashTable::InsertString(uint16 & ModulePage) {
// Insert string in hash table.
// Parameter:
// ModulePage = module address / page size
// Return value:
// 0 if success,
// 1 if identical string allready exists in the table. New string will not be entered.
// ModulePage will receive the module page of the existing string in this case.
// 2 if table is full,
uint16 Block; // Block number
uint16 Bucket; // Bucket number
uint32 StringIndex; // Index to string space
uint32 StringOffset; // Offset to string from begin of block
uint32 SpaceRequired; // Space required to store string
SpaceRequired = StringLength + 3; // Space for string + stringlength + module index
SpaceRequired = (SpaceRequired + 1) & uint32(-2);// Round up to nearest even
Block = StartBlock;
Bucket = StartBucket;
// Loop through blocks
do {
// Loop through buckets
do {
// String index of current bucket
StringIndex = blocks[Block].b.Buckets[Bucket];
if (StringIndex == 0) {
// Found empty bucket. Check if block has enough free space
if (uint32(OMFBlockSize) - blocks[Block].b.FreeSpace * 2 < SpaceRequired) {
// Not enough space in block.
// Continue with same bucket in next block.
// Note: It would be logical to set StartBucket = Bucket
// here in order to allow all buckets in the next block
// to be tried, but the official algorithm doesn't seem
// to do so!?
// StartBucket = Bucket;
break;
}
// Enough space found. Enter string in bucket
StringIndex = blocks[Block].b.FreeSpace;
blocks[Block].b.Buckets[Bucket] = StringIndex;
// Address to store string
StringOffset = StringIndex * 2;
// Store string length
blocks[Block].Strings[StringOffset] = (uint8)StringLength;
// Copy string
memcpy(blocks[Block].Strings + StringOffset + 1, String, StringLength);
// Insert module page number
*(uint16*)(blocks[Block].Strings + StringOffset + 1 + StringLength) = ModulePage;
// Update free space
blocks[Block].b.FreeSpace += (uint8)(SpaceRequired / 2);
// Check if overflow
if (blocks[Block].b.FreeSpace == 0) blocks[Block].b.FreeSpace = 0xFF;
// Indicate success
return 0;
}
else {
// Bucket contains a string. Check if it is the same string
if (blocks[Block].Strings[StringIndex*2] == StringLength
&& strncmp((int8*)(blocks[Block].Strings+StringIndex*2+1), (int8*)String, StringLength) == 0) {
// Identical string found. Return module index for existing string entry
ModulePage = *(uint16*)(blocks[Block].Strings+StringIndex*2+1+StringLength);
// Indicate failure
return 1;
}
}
// Bucket was full. Go to next bucket
Bucket = (Bucket + BucketD) % OMFNumBuckets;
} while (Bucket != StartBucket);
// If we got here, we have found no empty bucket in the block or
// there was not enough string space in the block.
// We need to mark the block as full to tell the linker to
// continue in next block when searching for this string
// Whether the block has any empty buckets or not
blocks[Block].b.FreeSpace = 0xFF;
// Go to next block
Block = (Block + BlockD) % NumBlocks;
} while (Block != StartBlock);
// Finished searching all blocks and buckets
// No empty space found. Indicate failure:
return 2;
}
// Table of prime numbers
// You may add more prime numbers if very big library files are needed
static const uint32 PrimeNumbers[] = {
1, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71,
73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157,
163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241,
251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347,
349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439,
443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547,
557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643,
647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751,
757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859,
863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977,
983, 991, 997, 1009, 1013, 1019, 1021, 1031, 1033, 1039, 1049, 1051, 1061, 1063,
1069, 1087, 1091, 1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151, 1153, 1163,
1171, 1181, 1187, 1193, 1201, 1213, 1217, 1223, 1229, 1231, 1237, 1249, 1259,
1277, 1279, 1283, 1289, 1291, 1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361,
1367, 1373, 1381, 1399, 1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451, 1453,
1459, 1471, 1481, 1483, 1487, 1489, 1493, 1499, 1511, 1523, 1531, 1543, 1549,
1553, 1559, 1567, 1571, 1579, 1583, 1597, 1601, 1607, 1609, 1613, 1619, 1621,
1627, 1637, 1657, 1663, 1667, 1669, 1693, 1697, 1699, 1709, 1721, 1723, 1733,
1741, 1747, 1753, 1759, 1777, 1783, 1787, 1789, 1801, 1811, 1823, 1831, 1847,
1861, 1867, 1871, 1873, 1877, 1879, 1889, 1901, 1907, 1913, 1931, 1933, 1949,
1951, 1973, 1979, 1987, 1993, 1997, 1999, 2003, 2011, 2017, 2027, 2029, 2039,
2053, 2063, 2069, 2081, 2083, 2087, 2089, 2099, 2111, 2113, 2129, 2131, 2137,
2141, 2143, 2153, 2161, 2179, 2203, 2207, 2213, 2221, 2237, 2239, 2243, 2251,
2267, 2269, 2273, 2281, 2287, 2293, 2297, 2309, 2311, 2333, 2339, 2341, 2347,
2351, 2357, 2371, 2377, 2381, 2383, 2389, 2393, 2399, 2411, 2417, 2423, 2437,
2441, 2447, 2459, 2467, 2473, 2477, 2503, 2521, 2531, 2539, 2543, 2549, 2551,
2557, 2579, 2591, 2593, 2609, 2617, 2621, 2633, 2647, 2657, 2659, 2663, 2671,
2677, 2683, 2687, 2689, 2693, 2699, 2707, 2711, 2713, 2719, 2729, 2731, 2741,
2749, 2753, 2767, 2777, 2789, 2791, 2797, 2801, 2803, 2819, 2833, 2837, 2843,
2851, 2857, 2861, 2879, 2887, 2897, 2903, 2909, 2917, 2927, 2939, 2953, 2957,
2963, 2969, 2971, 2999, 3001, 3011, 3019, 3023, 3037, 3041, 3049, 3061, 3067,
3079, 3083, 3089, 3109, 3119, 3121, 3137, 3163, 3167, 3169, 3181, 3187, 3191,
3203, 3209, 3217, 3221, 3229, 3251, 3253, 3257, 3259, 3271, 3299, 3301, 3307,
3313, 3319, 3323, 3329, 3331, 3343, 3347, 3359, 3361, 3371, 3373, 3389, 3391,
3407, 3413, 3433, 3449, 3457, 3461, 3463, 3467, 3469, 3491, 3499, 3511, 3517,
3527, 3529, 3533, 3539, 3541, 3547, 3557, 3559, 3571, 3581, 3583, 3593, 3607,
3613, 3617, 3623, 3631, 3637, 3643, 3659, 3671, 3673, 3677, 3691, 3697, 3701,
3709, 3719, 3727, 3733, 3739, 3761, 3767, 3769, 3779, 3793, 3797, 3803, 3821,
3823, 3833, 3847, 3851, 3853, 3863, 3877, 3881, 3889, 3907, 3911, 3917, 3919,
3923, 3929, 3931, 3943, 3947, 3967, 3989, 4001, 4003, 4007, 4013, 4019, 4021,
4027, 4049, 4051, 4057, 4073, 4079, 4091, 4093, 4099, 4111, 4127, 4129, 4133,
4139, 4153, 4157, 4159, 4177, 4201, 4211, 4217, 4219, 4229, 4231, 4241, 4243,
4253, 4259, 4261, 4271, 4273, 4283, 4289, 4297, 4327, 4337, 4339, 4349, 4357,
4363, 4373, 4391, 4397, 4409, 4421, 4423, 4441, 4447, 4451, 4457, 4463, 4481,
4483, 4493, 4507, 4513, 4517, 4519, 4523, 4547, 4549, 4561, 4567, 4583, 4591,
4597, 4603, 4621, 4637, 4639, 4643, 4649, 4651, 4657, 4663, 4673, 4679, 4691,
4703, 4721, 4723, 4729, 4733, 4751, 4759, 4783, 4787, 4789, 4793, 4799, 4801,
4813, 4817, 4831, 4861, 4871, 4877, 4889, 4903, 4909, 4919, 4931, 4933, 4937,
4943, 4951, 4957, 4967, 4969, 4973, 4987, 4993, 4999, 5003, 5009, 5011, 5021
};
// Length of table
static const uint32 PrimeNumbersLen = sizeof(PrimeNumbers)/sizeof(PrimeNumbers[0]);
void COMFHashTable::MakeHashTable(CSList<SStringEntry> & StringEntries,
CMemoryBuffer & StringBuffer, CMemoryBuffer & OutFile, CLibrary * Library) {
// Make hash table. Parameters:
// StringEntries[].String = name of each public symbol as offset into StringBuffer
// StringEntries[].Member = page address of member = offset / page size
// StringBuffer = contains all strings
// OutFile will receive the output hash table
CSList<SOMFHashBlock> HashTable; // Hash table
COMFHashTable TableHandler; // Hash table handler
uint32 NumBlocksI; // Number of blocks as index into prime number table
uint32 BlockI; // Block index
uint32 SymI; // Symbol index
int8 * String; // Symbol name
uint16 Module1, Module2; // Module page = offset / page size
int Result; // 0 = success
// Estimate required number of blocks
NumBlocks = (StringEntries.GetNumEntries() * 8 + StringBuffer.GetDataSize()) / 256;
// Find nearest prime number >= NumBlocks, but stay within the range from 2 to 251.
// The minimum NumBlocks is 1, but some systems use 2 as the minimum.
// The maximum is 251, but some linkers may allow a higher number
for (NumBlocksI = 1; NumBlocksI < 55; NumBlocksI++) {
if (PrimeNumbers[NumBlocksI] >= NumBlocks) break;
}
// Try if this number of blocks is sufficient
while (NumBlocksI < PrimeNumbersLen) {
// Get number of blocks from prime numbers table
NumBlocks = PrimeNumbers[NumBlocksI];
// Check if <= 251
if (NumBlocks > 255) err.submit(1215); // Number of blocks exceeds official limit. May still work with some linkers
// Allocate space for hash table
HashTable.SetNum(NumBlocks);
memset(&HashTable[0], 0, NumBlocks * OMFBlockSize);
// Initialize hash table handler
TableHandler.Init(&HashTable[0], NumBlocks);
// Set free space pointers
for (BlockI = 0; BlockI < NumBlocks; BlockI++) {
TableHandler.blocks[BlockI].b.FreeSpace = 19;
}
Result = 0;
// Insert symbols
// Loop through symbols
for (SymI = 0; SymI < StringEntries.GetNumEntries(); SymI++) {
// Symbol name
String = StringBuffer.Buf() + StringEntries[SymI].String;
// Module page
Module1 = Module2 = StringEntries[SymI].Member;
// Insert name in table
TableHandler.MakeHash(String);
Result = TableHandler.InsertString(Module2);
if (Result == 1) {
// String already exists
// Compose error string "Modulename1 and Modulename2"
char ErrorModuleNames[64];
strcpy(ErrorModuleNames, Library->GetModuleName(Module1));
strcpy(ErrorModuleNames + strlen(ErrorModuleNames), " and ");
strcpy(ErrorModuleNames + strlen(ErrorModuleNames), Library->GetModuleName(Module2));
// submit error message
err.submit(1214, String, ErrorModuleNames);
}
if (Result == 2) {
// Table is full. Stop and repeat with a higher NumBlocks
break;
}
} // End of loop through symbols
if (Result < 2) {
// Finished with success
// Store hash table
OutFile.Push(&HashTable[0], HashTable.GetNumEntries() * OMFBlockSize);
return;
}
// Table is full. Try again with a higher number of blocks
NumBlocksI++;
}
// End of loop through PrimeNumbers table
err.submit(2605); // Failed to make table
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,5 @@
// stdafx.cpp : source file that includes just the standard includes
// objconv.pch will be the pre-compiled header
// stdafx.obj will contain the pre-compiled type information
#include "stdafx.h"

View File

@ -0,0 +1,46 @@
/**************************** stdafx.h **********************************
* Author: Agner Fog
* Date created: 2006-07-15
* Last modified: 2006-07-15
* Project: objconv
* Module: stdafx.h
* Description:
* Header file including other header files for the project.
*
* Copyright 2006-2008 GNU General Public License http://www.gnu.org/licenses
*****************************************************************************/
#ifndef OBJCONV_STDAFX_H
#define OBJCONV_STDAFX_H
// System header files
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#ifdef _MSC_VER // For Microsoft compiler only:
#include <io.h> // File in/out function headers
#include <fcntl.h>
#include <sys/stat.h>
#define stricmp _stricmp // For later versions of MS compiler
#define strnicmp _strnicmp // For later versions of MS compiler
#define filelength _filelength // For later versions of MS compiler
#else // For Gnu and other compilers:
#define stricmp strcasecmp // Alternative function names
#define strnicmp strncasecmp
#endif
// Project header files. The order of these files is not arbitrary.
#include "maindef.h" // Constants, integer types, etc.
#include "error.h" // Error handler
#include "containers.h" // Classes for data buffers and dynamic memory allocation
#include "coff.h" // COFF files structure
#include "elf.h" // ELF files structure
#include "omf.h" // OMF files structure
#include "macho.h" // Mach-O files structure
#include "disasm.h" // Structures and classes for disassembler
#include "converters.h" // Classes for file converters
#include "library.h" // Classes for reading and writing libraries
#include "cmdline.h" // Command line interpreter class
#endif // defined OBJCONV_STDAFX_H