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