From 60a4b1c9ef95103c440fe11b14bf00e0ea94a9fc Mon Sep 17 00:00:00 2001 From: turbocat Date: Sun, 6 Feb 2022 11:09:00 +0000 Subject: [PATCH] Added objconv port. git-svn-id: svn://kolibrios.org@9683 a494cfbc-eb01-0410-851d-a64ba20cac60 --- programs/develop/objconv/.gitignore | 5 + programs/develop/objconv/.gitmodules | 3 + programs/develop/objconv/Tupfile.lua | 40 + programs/develop/objconv/cmdline.cpp | 1269 +++++ programs/develop/objconv/cmdline.h | 190 + programs/develop/objconv/cof2asm.cpp | 529 ++ programs/develop/objconv/cof2cof.cpp | 306 ++ programs/develop/objconv/cof2elf.cpp | 826 +++ programs/develop/objconv/cof2omf.cpp | 803 +++ programs/develop/objconv/coff.cpp | 914 ++++ programs/develop/objconv/coff.h | 537 ++ programs/develop/objconv/containers.cpp | 718 +++ programs/develop/objconv/containers.h | 393 ++ programs/develop/objconv/converters.h | 529 ++ programs/develop/objconv/disasm.h | 843 +++ programs/develop/objconv/disasm1.cpp | 4697 +++++++++++++++++ programs/develop/objconv/disasm2.cpp | 4335 ++++++++++++++++ programs/develop/objconv/elf.cpp | 574 +++ programs/develop/objconv/elf.h | 853 +++ programs/develop/objconv/elf2asm.cpp | 526 ++ programs/develop/objconv/elf2cof.cpp | 702 +++ programs/develop/objconv/elf2elf.cpp | 424 ++ programs/develop/objconv/elf2mac.cpp | 1098 ++++ programs/develop/objconv/error.cpp | 336 ++ programs/develop/objconv/error.h | 51 + programs/develop/objconv/library.cpp | 2103 ++++++++ programs/develop/objconv/library.h | 126 + programs/develop/objconv/mac2asm.cpp | 577 +++ programs/develop/objconv/mac2elf.cpp | 1267 +++++ programs/develop/objconv/mac2mac.cpp | 406 ++ programs/develop/objconv/macho.cpp | 754 +++ programs/develop/objconv/macho.h | 791 +++ programs/develop/objconv/main.cpp | 784 +++ programs/develop/objconv/maindef.h | 139 + programs/develop/objconv/omf.cpp | 1065 ++++ programs/develop/objconv/omf.h | 269 + programs/develop/objconv/omf2asm.cpp | 954 ++++ programs/develop/objconv/omf2cof.cpp | 875 ++++ programs/develop/objconv/omfhash.cpp | 382 ++ programs/develop/objconv/opcodes.cpp | 6266 +++++++++++++++++++++++ programs/develop/objconv/stdafx.cpp | 5 + programs/develop/objconv/stdafx.h | 46 + 42 files changed, 38310 insertions(+) create mode 100644 programs/develop/objconv/.gitignore create mode 100644 programs/develop/objconv/.gitmodules create mode 100755 programs/develop/objconv/Tupfile.lua create mode 100644 programs/develop/objconv/cmdline.cpp create mode 100644 programs/develop/objconv/cmdline.h create mode 100644 programs/develop/objconv/cof2asm.cpp create mode 100644 programs/develop/objconv/cof2cof.cpp create mode 100644 programs/develop/objconv/cof2elf.cpp create mode 100644 programs/develop/objconv/cof2omf.cpp create mode 100644 programs/develop/objconv/coff.cpp create mode 100644 programs/develop/objconv/coff.h create mode 100644 programs/develop/objconv/containers.cpp create mode 100644 programs/develop/objconv/containers.h create mode 100644 programs/develop/objconv/converters.h create mode 100644 programs/develop/objconv/disasm.h create mode 100644 programs/develop/objconv/disasm1.cpp create mode 100644 programs/develop/objconv/disasm2.cpp create mode 100644 programs/develop/objconv/elf.cpp create mode 100644 programs/develop/objconv/elf.h create mode 100644 programs/develop/objconv/elf2asm.cpp create mode 100644 programs/develop/objconv/elf2cof.cpp create mode 100644 programs/develop/objconv/elf2elf.cpp create mode 100644 programs/develop/objconv/elf2mac.cpp create mode 100644 programs/develop/objconv/error.cpp create mode 100644 programs/develop/objconv/error.h create mode 100644 programs/develop/objconv/library.cpp create mode 100644 programs/develop/objconv/library.h create mode 100644 programs/develop/objconv/mac2asm.cpp create mode 100644 programs/develop/objconv/mac2elf.cpp create mode 100644 programs/develop/objconv/mac2mac.cpp create mode 100644 programs/develop/objconv/macho.cpp create mode 100644 programs/develop/objconv/macho.h create mode 100644 programs/develop/objconv/main.cpp create mode 100644 programs/develop/objconv/maindef.h create mode 100644 programs/develop/objconv/omf.cpp create mode 100644 programs/develop/objconv/omf.h create mode 100644 programs/develop/objconv/omf2asm.cpp create mode 100644 programs/develop/objconv/omf2cof.cpp create mode 100644 programs/develop/objconv/omfhash.cpp create mode 100644 programs/develop/objconv/opcodes.cpp create mode 100644 programs/develop/objconv/stdafx.cpp create mode 100644 programs/develop/objconv/stdafx.h diff --git a/programs/develop/objconv/.gitignore b/programs/develop/objconv/.gitignore new file mode 100644 index 0000000000..296b635b05 --- /dev/null +++ b/programs/develop/objconv/.gitignore @@ -0,0 +1,5 @@ +.vs +src/.vs +src/Release +src/Debug +src/x64 \ No newline at end of file diff --git a/programs/develop/objconv/.gitmodules b/programs/develop/objconv/.gitmodules new file mode 100644 index 0000000000..8859214b0f --- /dev/null +++ b/programs/develop/objconv/.gitmodules @@ -0,0 +1,3 @@ +[submodule "c2nasm/nasm"] + path = c2nasm/nasm + url = https://github.com/gitGNU/nasm diff --git a/programs/develop/objconv/Tupfile.lua b/programs/develop/objconv/Tupfile.lua new file mode 100755 index 0000000000..8f0fcdbcfe --- /dev/null +++ b/programs/develop/objconv/Tupfile.lua @@ -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") + diff --git a/programs/develop/objconv/cmdline.cpp b/programs/develop/objconv/cmdline.cpp new file mode 100644 index 0000000000..dd8604f6f7 --- /dev/null +++ b/programs/develop/objconv/cmdline.cpp @@ -0,0 +1,1269 @@ +/**************************** cmdline.cpp ********************************** +* Author: Agner Fog +* Date created: 2006-07-25 +* Last modified: 2018-01-29 +* Project: objconv +* Module: cmdline.cpp +* Description: +* This module is for interpretation of command line options +* Also contains symbol change function +* +* Copyright 2006-2018 GNU General Public License http://www.gnu.org/licenses +*****************************************************************************/ + +#include "stdafx.h" + +// List of recognized output file type options +static SIntTxt TypeOptionNames[] = { + {CMDL_OUTPUT_ELF, "elf"}, + {CMDL_OUTPUT_PE, "pe"}, + {CMDL_OUTPUT_PE, "coff"}, + {CMDL_OUTPUT_PE, "cof"}, + {CMDL_OUTPUT_PE, "win"}, + {CMDL_OUTPUT_OMF, "omf"}, + {CMDL_OUTPUT_MACHO, "mac"}, + {CMDL_OUTPUT_MACHO, "macho"}, + {CMDL_OUTPUT_MACHO, "mach-o"}, + {CMDL_OUTPUT_MACHO, "mach"}, + {CMDL_OUTPUT_MASM, "asm"}, + {CMDL_OUTPUT_MASM, "masm"}, + {CMDL_OUTPUT_MASM, "tasm"}, + {CMDL_OUTPUT_MASM, "nasm"}, + {CMDL_OUTPUT_MASM, "yasm"}, + {CMDL_OUTPUT_MASM, "gasm"}, + {CMDL_OUTPUT_MASM, "gas"} +}; + +// List of subtype names +static SIntTxt SubtypeNames[] = { + {SUBTYPE_MASM, "asm"}, + {SUBTYPE_MASM, "masm"}, + {SUBTYPE_MASM, "tasm"}, + {SUBTYPE_YASM, "nasm"}, + {SUBTYPE_YASM, "yasm"}, + {SUBTYPE_GASM, "gasm"}, + {SUBTYPE_GASM, "gas"} +}; + +// List of standard names that are always translated +const uint32 MaxType = FILETYPE_MACHO_LE; + +// Standard names in 32-bit mode +const char * StandardNames32[][MaxType+1] = { + // 0, COFF, OMF, ELF, MACHO + {0,"___ImageBase","___ImageBase","__executable_start","__mh_execute_header"} +}; + +// Standard names in 64-bit mode +// COFF removes an underscore in 32-bit. There is no 64-bit OMF +const char * StandardNames64[][MaxType+1] = { + // 0, COFF, OMF, ELF, MACHO + {0,"__ImageBase", "", "__executable_start","__mh_execute_header"} +}; + +const int NumStandardNames = sizeof(StandardNames32) / sizeof(StandardNames32[0]); + + +// Command line interpreter +CCommandLineInterpreter cmd; // Instantiate command line interpreter + +CCommandLineInterpreter::CCommandLineInterpreter() { + // Default constructor + memset(this, 0, sizeof(*this)); // Set all to zero + Verbose = CMDL_VERBOSE_YES; // How much diagnostics to print on screen + DumpOptions = DUMP_NONE; // Dump options + DebugInfo = CMDL_DEBUG_DEFAULT; // Strip or convert debug info + ExeptionInfo = CMDL_EXCEPTION_DEFAULT; // Strip or preserve exception handling info + SegmentDot = CMDL_SECTIONDOT_NOCHANGE; // Change underscore/dot in beginning of segment names + Underscore = CMDL_UNDERSCORE_NOCHANGE; // Add/remove underscores in symbol names + LibraryOptions = CMDL_LIBRARY_DEFAULT; // Library options +} + + +CCommandLineInterpreter::~CCommandLineInterpreter() { // Destructor +} + + +void CCommandLineInterpreter::ReadCommandLine(int argc, char * argv[]) { + + // Read command line + for (int i = 1; i < argc; i++) { + ReadCommandItem(argv[i]); + } + if (ShowHelp || (InputFile == 0 && OutputFile == 0) /* || !OutputType */) { + // No useful command found. Print help + Help(); ShowHelp = 1; + return; + } + // Check file options + FileOptions = CMDL_FILE_INPUT; + if (LibraryOptions == CMDL_LIBRARY_ADDMEMBER) { + // Adding object files to library. Library may not exist + FileOptions = CMDL_FILE_IN_IF_EXISTS; + } + if (DumpOptions || ((LibraryOptions & CMDL_LIBRARY_EXTRACTMEM) && !(LibraryOptions & CMDL_LIBRARY_ADDMEMBER))) { + // Dumping or extracting. Output file not used + if (OutputFile) err.submit(1103); // Output file name ignored + OutputFile = 0; + } + else { + // Output file required + FileOptions |= CMDL_FILE_OUTPUT; + } + if ((LibraryOptions & CMDL_LIBRARY_ADDMEMBER) && !(LibraryOptions & CMDL_LIBRARY_CONVERT)) { + // Adding library members only. Output file may have same name as input file + FileOptions |= CMDL_FILE_IN_OUT_SAME; + } + // Check output type + if (!OutputType) { + // Output type not defined yet + if (LibraryOptions & (CMDL_LIBRARY_CONVERT | CMDL_LIBRARY_ADDMEMBER)) { + OutputType = FILETYPE_LIBRARY; + } + } +} + + +void CCommandLineInterpreter::ReadCommandItem(char * string) { + // Read one option from command line + // Skip leading whitespace + while (*string != 0 && *string <= ' ') string++; + if (*string == 0) return; // Empty string + + // Look for option prefix and response file prefix + const char OptionPrefix1 = '-'; // Option must begin with '-' +#if defined (_WIN32) || defined (__WINDOWS__) + const char OptionPrefix2 = '/'; // '/' allowed instead of '-' in Windows only +#else + const char OptionPrefix2 = '-'; +#endif + const char ResponseFilePrefix = '@'; // Response file name prefixed by '@' + if (*string == OptionPrefix1 || *string == OptionPrefix2) { + // Option prefix found. This is a command line option + InterpretCommandOption(string+1); + } + else if (*string == ResponseFilePrefix) { + // Response file prefix found. Read more options from response file + ReadCommandFile(string+1); + } + else { + // No prefix found. This is an input or output file name + InterpretFileName(string); + } + + int loc, last = SymbolList.GetNumEntries() - 1; + if (last > 0) { + // relocate last entry (binary insertion sort): + SSymbolChange * List = (SSymbolChange *)SymbolList.Buf(); + SSymbolChange key = List[last]; + SymbolBinSearch(key.Name1, last, &loc); + memmove(List + loc + 1, List + loc, (last - loc) * sizeof(SSymbolChange)); + List[loc] = key; + } +} + + +void CCommandLineInterpreter::ReadCommandFile(char * filename) { + // Read commands from file + if (*filename <= ' ') { + err.submit(1001); return; // Warning: empty filename + } + + // Check if too many response file buffers (possibly because file includes itself) + if (++NumBuffers > MAX_COMMAND_FILES) {err.submit(2107); return;} + + // Allocate buffer for response files. + if (ResponseFiles.GetNumEntries() == 0) { + ResponseFiles.SetNum(MAX_COMMAND_FILES); + ResponseFiles.SetZero(); + } + + // Read response file into new buffer + ResponseFiles[NumBuffers-1].FileName = filename; + ResponseFiles[NumBuffers-1].Read(); + + // Get buffer with file contents + char * buffer = ResponseFiles[NumBuffers-1].Buf(); + char * ItemBegin, * ItemEnd; // Mark begin and end of token in buffer + + // Check if buffer is allocated + if (buffer) { + + // Parse contents of response file for tokens + while (*buffer) { + + // Skip whitespace + while (*buffer != 0 && uint8(*buffer) <= uint8(' ')) buffer++; + if (*buffer == 0) break; // End of buffer found + ItemBegin = buffer; + + // Find end of token + ItemEnd = buffer+1; + while (uint8(*ItemEnd) > uint8(' ')) ItemEnd++; + if (*ItemEnd == 0) { + buffer = ItemEnd; + } + else { + buffer = ItemEnd + 1; + *ItemEnd = 0; // Mark end of token + } + // Found token. + // Check if it is a comment beginning with '#' or '//' + if (ItemBegin[0] == '#' || (ItemBegin[0] == '/' && ItemBegin[1] == '/' )) { + // This is a comment. Skip to end of line + ItemEnd = buffer; + while (*ItemEnd != 0 && *ItemEnd != '\n') { + ItemEnd++; + } + if (*ItemEnd == 0) { + buffer = ItemEnd; + } + else { + buffer = ItemEnd + 1; + } + continue; + } + // Not a comment. Interpret token + ReadCommandItem(ItemBegin); + } + } +} + + +void CCommandLineInterpreter::InterpretFileName(char * string) { + // Interpret input or output filename from command line + + switch (libmode) { + case 1: // First filename after -lib = inputfile and outputfile + InputFile = string; + libmode = 2; + return; + + case 2: // Second or later filename after -lib = object file to add to library + AddObjectToLibrary(string, string); + return; + } + // libmode = 0: Ordinary input or output file + + if (!InputFile) { + // Input file not specified yet + InputFile = string; + } + else if (!OutputFile) { + // Output file not specified yet + OutputFile = string; + } + else { + // Both input and output files already specified + err.submit(2001); + } +} + + +void CCommandLineInterpreter::InterpretCommandOption(char * string) { + // Interpret one option from command line + if (*string <= ' ') { + err.submit(1001); return; // Warning: empty option + } + + // Detect option type + switch(string[0]) { + case 'f': case 'F': // output file format + if (string[1] == 'd') { + // -fd == deprecated dump option + InterpretDumpOption(string+2); break; + } + InterpretOutputTypeOption(string+1); break; + + case 'v': case 'V': // verbose/silent + InterpretVerboseOption(string+1); break; + + case 'd': case 'D': // dump option + InterpretDumpOption(string+1); break; + // Debug info option + //InterpretDebugInfoOption(string+1); break; + + case 'x': case 'X': // Exception handler info option + InterpretExceptionInfoOption(string+1); break; + + case 'h': case 'H': case '?': // Help + ShowHelp = 1; break; + + case 'e': case 'E': // Error option + case 'w': case 'W': // Warning option + InterpretErrorOption(string); break; + + case 'n': case 'N': // Symbol name change option + case 'a': case 'A': // Symbol name alias option + InterpretSymbolNameChangeOption(string); break; + + case 'i': case 'I': // Imagebase + if ((string[1] | 0x20) == 'm') { + InterpretImagebaseOption(string); + } + break; + + case 'l': case 'L': // Library option + InterpretLibraryOption(string); break; + + case 'c': // Count instruction codes supported + // This is an easter egg: You can only get it if you know it's there + if (strncmp(string,"countinstructions", 17) == 0) { + CDisassembler::CountInstructions(); + exit(0); + } + + default: // Unknown option + err.submit(1002, string); + } +} + + +void CCommandLineInterpreter::InterpretLibraryOption(char * string) { + // Interpret options for manipulating library/archive files + + // Check for -lib command + if (stricmp(string, "lib") == 0) { // Found -lib command + if (InputFile) { + libmode = 2; // Input file already specified. Remaining file names are object files to add + } + else { + libmode = 1; // The rest of the command line must be interpreted as library name and object file names + } + return; + } + + SSymbolChange sym = {0,0,0,0}; // Symbol change record + int i; // Loop counter + + // Check for member name and optional new name in this command + char * name1 = 0, * name2 = 0, separator; + if ((string[2] == ':' || string[2] == '|') && string[3]) { + // name1 found + separator = string[2]; + name1 = string+3; + // Search for second separator or end + name2 = name1 + 1; + while (name2[0] != 0) { + if (name2[0] == separator) { + *name2 = 0; // Mark end of name1 + if (name2[1]) { + // name2 found + name2++; // Name2 starts here + break; + } + } + name2++; + } + if (name2 == 0 || name2[0] == 0 || name2[0] == separator) { + // name 2 is blank + //name2 = name1; + name2 = 0; + } + else { + // Check if name2 ends with separator + for (i = 0; i < (int)strlen(name2); i++) { + if (name2[i] == separator) name2[i] = 0; + } + } + } + // Check for duplicate name + if (SymbolIsInList(name1)) { + // This symbol is already in list + err.submit(2017, name1); + return; + } + + sym.Name1 = name1; // Store names in symbol change record + sym.Name2 = name2; + + switch (string[1]) { + case 'a': case 'A': // Add input file to library + if (name1) { + AddObjectToLibrary(name1, name2); + } + else err.submit(2004, string); + break; + + case 'x': case 'X': // Extract member(s) from library + if (name1) { + // Extract specified member + cmd.LibraryOptions = CMDL_LIBRARY_EXTRACTMEM; + sym.Action = SYMA_EXTRACT_MEMBER; + SymbolList.Push(&sym, sizeof(sym)); + } + else { + // Extract all members + cmd.LibraryOptions = CMDL_LIBRARY_EXTRACTALL; + } + break; + + case 'd': case 'D': // Delete member from library + if (name1) { + // Delete specified member + cmd.LibraryOptions = CMDL_LIBRARY_CONVERT; + sym.Action = SYMA_DELETE_MEMBER; + SymbolList.Push(&sym, sizeof(sym)); + } + else err.submit(2004, string); + break; + + case 's': case 'S': // Use short member names for compatibility + cmd.LibrarySubtype = LIBTYPE_SHORTNAMES; + break; + + default: + err.submit(2004, string); // Unknown option + } +} + + +void CCommandLineInterpreter::AddObjectToLibrary(char * filename, char * membername) { + // Add object file to library + if (!filename || !*filename) { + err.submit(2004, filename-1); return; // Empty string + } + + if (!membername || !*membername) membername = filename; + + SSymbolChange Sym = {0,0,0,0}; // Symbol change record + + Sym.Name2 = filename; // Object file name + + if (!MemberNamesAllocated) { + // Allocate space for truncated member names + const int SafetySpace = 1024; + + // Get size of response files + if (ResponseFiles.GetNumEntries()) { + MemberNamesAllocated = ResponseFiles[0].GetDataSize() + ResponseFiles[1].GetDataSize(); + } + // Allocate this size + SafetySpace + MemberNames.SetSize(MemberNamesAllocated + SafetySpace); + + // Remember allocated buffer size + MemberNamesAllocated = MemberNames.GetBufferSize(); + } + + // Truncate name and store it in MemberNames + //uint32 Name1Offset = MemberNames.PushString(CLibrary::TruncateMemberName(membername)); + uint32 Name1Offset = MemberNames.PushString(membername); + Sym.Name1 = (char*)(MemberNames.Buf() + Name1Offset); + CLibrary::StripMemberName(Sym.Name1); + + // Note: Sym.Name1 points to allocated memory in violation of good programming practice. + // Check that it is not reallocated: + if (MemberNames.GetBufferSize() != MemberNamesAllocated) { + err.submit(2506); // Cannot reallocate MemberNames because we have pointers to in in SymbolList + return; + } + + // Check for duplicate name + if (SymbolIsInList(Sym.Name1)) { + // This symbol is already in list + err.submit(2017, Sym.Name1); + return; + } + + // Store options + cmd.LibraryOptions |= CMDL_LIBRARY_ADDMEMBER; + Sym.Action = SYMA_ADD_MEMBER; + + // Store SYMA_ADD_MEMBER record in symbol list + SymbolList.Push(&Sym, sizeof(Sym)); +} + + +void CCommandLineInterpreter::InterpretOutputTypeOption(char * string) { + // Interpret output file format option from command line + + int opt; + for (opt = 0; opt < TableSize(TypeOptionNames); opt++) { + int len = (int)strlen(TypeOptionNames[opt].b); + if (strncmp(string, TypeOptionNames[opt].b, len) == 0) { + // Match found + if (OutputType) err.submit(2003, string); // More than one output type specified + if (DumpOptions) err.submit(2007); // Both dump and convert specified + + // Save desired output type + OutputType = TypeOptionNames[opt].a; + + // Check if name is followed by a word size + int wordsize = 0; + if (string[len]) wordsize = atoi(string+len); + switch (wordsize) { + case 0: // No word size specified + break; + + case 32: case 64: // Valid word size + DesiredWordSize = wordsize; + break; + + default: // Illegal word size + err.submit(2002, wordsize); + } + break; // Finished searching + } + } + + // Check if found + if (opt >= TableSize(TypeOptionNames)) err.submit(2004, string-1); + + if (OutputType == CMDL_OUTPUT_MASM) { + // Get subtype + for (opt = 0; opt < TableSize(SubtypeNames); opt++) { + int len = (int)strlen(SubtypeNames[opt].b); + if (strncmp(string, SubtypeNames[opt].b, len) == 0) { + // Match found + SubType = SubtypeNames[opt].a; break; + } + } + } +} + + +void CCommandLineInterpreter::InterpretVerboseOption(char * string) { + // Interpret silent/verbose option from command line + Verbose = atoi(string); +} + + +void CCommandLineInterpreter::InterpretDumpOption(char * string) { + // Interpret dump option from command line + if (OutputType || DumpOptions) err.submit(2007); // Both dump and convert specified + + char * s1 = string; + while (*s1) { + switch (*(s1++)) { + case 'f': case 'F': // dump file header + DumpOptions |= DUMP_FILEHDR; break; + case 'h': case 'H': // dump section headers + DumpOptions |= DUMP_SECTHDR; break; + case 's': case 'S': // dump symbol table + DumpOptions |= DUMP_SYMTAB; break; + case 'r': case 'R': // dump relocations + DumpOptions |= DUMP_RELTAB; break; + case 'n': case 'N': // dump string table + DumpOptions |= DUMP_STRINGTB; break; + case 'c': case 'C': // dump comment records (currently only for OMF) + DumpOptions |= DUMP_COMMENT; break; + default: + err.submit(2004, string-1); // Unknown option + } + } + if (DumpOptions == 0) DumpOptions = DUMP_FILEHDR; + OutputType = CMDL_OUTPUT_DUMP; + if (OutputType && OutputType != CMDL_OUTPUT_DUMP) err.submit(2007); // Both dump and convert specified + OutputType = CMDL_OUTPUT_DUMP; +} + + +void CCommandLineInterpreter::InterpretDebugInfoOption(char * string) { + // Interpret debug info option from command line + if (strlen(string) > 1) err.submit(2004, string-1); // Unknown option + switch (*string) { + case 's': case 'S': case 'r': case 'R': // Strip (remove) + DebugInfo = CMDL_DEBUG_STRIP; break; + case 'p': case 'P': // Preserve + DebugInfo = CMDL_DEBUG_PRESERVE; break; + case 'l': case 'L': // (Not supported) + DebugInfo = CMDL_DEBUG_LINNUM; break; + case 'c': case 'C': // (Not supported) + DebugInfo = CMDL_DEBUG_SYMBOLS; break; + default: + err.submit(2004, string-1); // Unknown option + } +} + + +void CCommandLineInterpreter::InterpretExceptionInfoOption(char * string) { + // Interpret exception handler info option from command line + if (strlen(string) > 1) err.submit(2004, string-1); // Unknown option + switch (*string) { + case 's': case 'S': case 'r': case 'R': // Strip (remove) + ExeptionInfo = CMDL_EXCEPTION_STRIP; break; + case 'p': case 'P': // Preserve + ExeptionInfo = CMDL_EXCEPTION_PRESERVE; break; + default: + err.submit(2004, string-1); // Unknown option + } +} + + +void CCommandLineInterpreter::InterpretErrorOption(char * string) { + // Interpret warning/error option from command line + if (strlen(string) < 3) { + err.submit(2004, string); return; // Unknown option + } + int newstatus; // New status for this error number + + switch (string[1]) { + case 'd': case 'D': // Disable + newstatus = 0; break; + + case 'w': case 'W': // Treat as warning + newstatus = 1; break; + + case 'e': case 'E': // Treat as error + newstatus = 2; break; + + default: + err.submit(2004, string); // Unknown option + return; + } + if (string[2] == 'x' || string[2] == 'X') { + // Apply new status to all non-fatal messages + for (SErrorText * ep = ErrorTexts; ep->Status < 9; ep++) { + ep->Status = newstatus; // Change status of all errors + } + } + else { + int ErrNum = atoi(string+2); + if (ErrNum == 0 && string[2] != '0') { + err.submit(2004, string); return; // Unknown option + } + // Search for this error number + SErrorText * ep = err.FindError(ErrNum); + if (ep->Status & 0x100) { + // Error number not found + err.submit(1003, ErrNum); return; // Unknown error number + } + // Change status of this error + ep->Status = newstatus; + } +} + +void CCommandLineInterpreter::InterpretSymbolNameChangeOption(char * string) { + // Interpret various options for changing symbol names + SSymbolChange sym = {0,0,0,0}; // Symbol change record + string[0] |= 0x20; // change first letter to lower case + + // Check for symbol names in this command + char * name1 = 0, * name2 = 0; + if (string[2] == ':' && string[3]) { + // name1 found + name1 = string+3; + // Search for second ':' or end + name2 = name1 + 1; + while (name2[0] != 0) { + if (name2[0] == ':') { + *name2 = 0; // Mark end of name1 + if (name2[1]) { + // name2 found + name2++; // Name2 starts here + break; + } + } + name2++; + } + if (name2 && name2[0]) { + // name2 found. check if it ends with ':' + for (uint32 i = 0; i < (uint32)strlen(name2); i++) { + if (name2[i] == ':') name2[i] = 0; + } + } + if (name2[0] == 0) name2 = 0; + } + // Check for duplicate name + if (name1 && SymbolIsInList(name1)) { + // This symbol is already in list + err.submit(2015, name1); + return; + } + + switch (string[1]) { + case 'u': case 'U': // underscore option + switch (string[2]) { + case 0: + Underscore = CMDL_UNDERSCORE_CHANGE; + if (string[0] == 'a') Underscore |= CMDL_KEEP_ALIAS; + break; + case '+': case 'a': case 'A': + Underscore = CMDL_UNDERSCORE_ADD; + if (string[0] == 'a') Underscore |= CMDL_KEEP_ALIAS; + break; + case '-': case 'r': case 'R': + Underscore = CMDL_UNDERSCORE_REMOVE; + if (string[0] == 'a') Underscore |= CMDL_KEEP_ALIAS; + break; + default: + err.submit(2004, string); // Unknown option + } + break; + + case 'd': case 'D': // section name dot option + SegmentDot = CMDL_SECTIONDOT_CHANGE; + break; + + case 'r': case 'R': // name replace option + if (name1 == 0 || name2 == 0 || *name1 == 0 || *name2 == 0) { + err.submit(2008, string); return; + } + sym.Name1 = name1; + sym.Name2 = name2; + sym.Action = SYMA_CHANGE_NAME; + if (string[0] == 'a') sym.Action |= SYMA_ALIAS; + SymbolList.Push(&sym, sizeof(sym)); SymbolChangeEntries++; + break; + + case 'p': case 'P': // prefix replace option + if (name1 == 0 || *name1 == 0) { + err.submit(2008, string); return; + } + if (name2 == 0) name2 = (char*)""; + sym.Name1 = name1; + sym.Name2 = name2; + sym.Action = SYMA_CHANGE_PREFIX; + if (string[0] == 'a') sym.Action |= SYMA_ALIAS; + PrefixSuffixList.Push(&sym, sizeof(sym)); SymbolChangeEntries++; + break; + + case 's': case 'S': // suffix replace option + if (name1 == 0 || *name1 == 0) { + err.submit(2008, string); return; + } + if (name2 == 0) name2 = (char*)""; + sym.Name1 = name1; + sym.Name2 = name2; + sym.Action = SYMA_CHANGE_SUFFIX; + if (string[0] == 'a') sym.Action |= SYMA_ALIAS; + PrefixSuffixList.Push(&sym, sizeof(sym)); SymbolChangeEntries++; + break; + + case 'w': case 'W': // Weaken symbol + if (name1 == 0 || *name1 == 0 || name2) { + err.submit(2009, string); return; + } + sym.Name1 = name1; + sym.Action = SYMA_MAKE_WEAK; + SymbolList.Push(&sym, sizeof(sym)); SymbolChangeEntries++; + break; + + case 'l': case 'L': // Make symbol local or hidden + if (name1 == 0 || *name1 == 0 || name2) { + err.submit(2009, string); return; + } + sym.Name1 = name1; + sym.Action = SYMA_MAKE_LOCAL; + SymbolList.Push(&sym, sizeof(sym)); SymbolChangeEntries++; + break; + + default: + err.submit(2004, string); // Unknown option + } +} + +void CCommandLineInterpreter::InterpretImagebaseOption(char * string) { + // Interpret image base option + char * p = strchr(string, '='); + if ((strnicmp(string, "imagebase", 9) && strnicmp(string, "image_base", 10)) || !p) { + // Unknown option + err.submit(1002, string); + return; + } + if (ImageBase) err.submit(2330); // Imagebase specified more than once + + p++; // point to number following '=' + // Loop through string to interpret hexadecimal number + while (*p) { + char letter = *p | 0x20; // lower case letter + if (*p >= '0' && *p <= '9') { + // 0 - 9 hexadecimal digit + ImageBase = (ImageBase << 4) + *p - '0'; + } + else if (letter >= 'a' && letter <= 'f') { + // A - F hexadecimal digit + ImageBase = (ImageBase << 4) + letter - 'a' + 10; + } + else if (letter == 'h') { + // Hexadecimal number may end with 'H' + break; + } + else if (letter == 'x' || letter == ' ') { + // Hexadecimal number may begin with 0x + if (ImageBase) { + // 'x' preceded by number other than 0 + err.submit(1002, string); break; + } + } + else { + // Any other character not allowed + err.submit(1002, string); break; + } + // next character + p++; + } + if (ImageBase & 0xFFF) { + // Must be divisible by page size + err.submit(2331, string); + } + if ((int32)ImageBase <= 0) { + // Cannot be zero or > 2^31 + err.submit(2332, string); + } +} + + +SSymbolChange const * CCommandLineInterpreter::GetMemberToAdd() { + // Get names of object files to add to library + // replaced will be set to 1 if a member with the same name is replaced + + // Search through SymbolList, continuing from last CurrentSymbol + while (CurrentSymbol < SymbolList.GetDataSize()) { + // Get pointer to current symbol record + SSymbolChange * Sym = (SSymbolChange *)(SymbolList.Buf() + CurrentSymbol); + // Increment pointer + CurrentSymbol += sizeof(SSymbolChange); + // Check record type + if (Sym->Action == SYMA_ADD_MEMBER) { + // Name found + return Sym; + } + } + // No more names found + return 0; +} + + +void CCommandLineInterpreter::CheckExtractSuccess() { + // Check if library members to extract were found + + // Search through SymbolList for extract records + for (uint32 i = 0; i < SymbolList.GetDataSize(); i += sizeof(SSymbolChange)) { + SSymbolChange * Sym = (SSymbolChange *)(SymbolList.Buf() + i); + if (Sym->Action == SYMA_EXTRACT_MEMBER && Sym->Done == 0) { + // Member has not been extracted + err.submit(1104, Sym->Name1); + } + } +} + + +void CCommandLineInterpreter::CheckSymbolModifySuccess() { + // Check if symbols to modify were found + + // Search through SymbolList for symbol change records + for (uint32 i = 0; i < SymbolList.GetDataSize(); i += sizeof(SSymbolChange)) { + SSymbolChange * Sym = (SSymbolChange *)(SymbolList.Buf() + i); + if (Sym->Action >= SYMA_MAKE_WEAK && Sym->Action < SYMA_ADD_MEMBER && Sym->Done == 0) { + // Member has not been extracted + err.submit(1106, Sym->Name1); + } + if (Sym->Action == SYMA_DELETE_MEMBER && Sym->Done == 0) { + // Member has not been extracted + err.submit(1105, Sym->Name1); + } + } +} + + +int CCommandLineInterpreter::SymbolIsInList(char const * name) { + // Check if name is already in symbol list + int unused; + return SymbolBinSearch(name, SymbolList.GetNumEntries(), &unused); +} + + +int CCommandLineInterpreter::SymbolBinSearch(char const * name, int nsym, int * location) { + SSymbolChange * List = (SSymbolChange *)SymbolList.Buf(); + int lo = 0, hi = nsym - 1; + while (lo <= hi) { + int mid = (lo + hi) >> 1; + int comp = strcmp(name, List[mid].Name1); + if (!comp) { + *location = mid; + return 1; + } else if (comp < 0) { + hi = mid - 1; + } else { + lo = mid + 1; + } + } + *location = lo; + return 0; +} + + +int CCommandLineInterpreter::SymbolChange(char const * oldname, char const ** newname, int symtype) { + // Check if symbol has to be changed + int action = 0, i, isym; + int nsym = SymbolList.GetNumEntries(); + int n_prefix_suffix = PrefixSuffixList.GetNumEntries(); + if (oldname == 0) return SYMA_NOCHANGE; + if (newname) *newname = 0; + + // Convert standard names if type conversion + if (cmd.InputType != cmd.OutputType + && uint32(cmd.InputType) <= MaxType && uint32(cmd.OutputType) <= MaxType) { + if (DesiredWordSize == 32) { + // Look for standard names to translate, 32-bit + for (i = 0; i < NumStandardNames; i++) { + if (strcmp(oldname, StandardNames32[i][cmd.InputType]) == 0) { + // Match found + *newname = StandardNames32[i][cmd.OutputType]; + CountSymbolNameChanges++; + return SYMA_CHANGE_NAME; // Change name of symbol + } + } + } + else { + // Look for standard names to translate, 64-bit + for (i = 0; i < NumStandardNames; i++) { + if (strcmp(oldname, StandardNames64[i][cmd.InputType]) == 0) { + // Match found + *newname = StandardNames64[i][cmd.OutputType]; + CountSymbolNameChanges++; + return SYMA_CHANGE_NAME; // Change name of symbol + } + } + } + } + + // See if there are other conversions to do + if (Underscore == 0 && SegmentDot == 0 && nsym == 0 && n_prefix_suffix == 0) return SYMA_NOCHANGE; // Nothing to do + if (oldname == 0 || *oldname == 0) return SYMA_NOCHANGE; // No name + + static char NameBuffer[MAXSYMBOLLENGTH]; + + // search for name in list of names specified by user on command line + SSymbolChange * psym; + int found = SymbolBinSearch(oldname, nsym, &isym); + if (found) { + psym = (SSymbolChange *)SymbolList.Buf() + isym; + } else { + // Search prefix/suffix match + psym = (SSymbolChange *)PrefixSuffixList.Buf(); + for (isym = 0; isym < n_prefix_suffix; isym++, psym++) { + int n1len = (int)strlen(psym->Name1); // Length of string to search for + int onlen = (int)strlen(oldname); // Length of string to match + if ((psym->Action&~SYMA_ALIAS) == SYMA_CHANGE_PREFIX && strncmp(oldname, psym->Name1, n1len)==0) break; // matching prefix found + if ((psym->Action&~SYMA_ALIAS) == SYMA_CHANGE_SUFFIX && strcmp(oldname+onlen-n1len, psym->Name1)==0) break; // matching suffix found + } + found = isym < n_prefix_suffix; + } + + if (found) { + // A matching name was found. + action = psym->Action; + // Whatever action is specified here is overriding any general option + // Statistics counting + switch (action & ~SYMA_ALIAS) { + + case SYMA_MAKE_WEAK: // Make public symbol weak + if (symtype == SYMT_PUBLIC) { + CountSymbolsWeakened++; psym->Done++; + } + else { // only public symbols can be weakened + err.submit(1020, oldname); // cannot make weak + action = SYMA_NOCHANGE; + } + break; + + case SYMA_MAKE_LOCAL: // Hide public or external symbol + if (symtype == SYMT_PUBLIC || symtype == SYMT_EXTERNAL) { + CountSymbolsMadeLocal++; psym->Done++; + if (symtype == SYMT_EXTERNAL) err.submit(1023, oldname); + } + else { // only public and external symbols can be made local + err.submit(1021, oldname); // cannot make local + action = SYMA_NOCHANGE; + } + break; + + case SYMA_CHANGE_NAME: // Change name of symbol or segment or library member + CountSymbolNameChanges++; psym->Done++; + *newname = psym->Name2; + break; + + case SYMA_CHANGE_PREFIX: // Change beginning of symbol name + if (symtype == SYMT_PUBLIC || symtype == SYMT_EXTERNAL || symtype == SYMT_LOCAL || symtype == SYMT_SECTION) { + if (strlen(oldname) - strlen(psym->Name1) + strlen(psym->Name2) >= MAXSYMBOLLENGTH) { + err.submit(2202, oldname); // Name too long + action = SYMA_NOCHANGE; break; + } + strcpy(NameBuffer, psym->Name2); + strcpy(NameBuffer + strlen(psym->Name2), oldname + strlen(psym->Name1)); + action = SYMA_CHANGE_NAME; + *newname = NameBuffer; + CountSymbolNameChanges++; psym->Done++; + } + else { // only symbols and segments can change prefix + err.submit(1024, oldname); + action = SYMA_NOCHANGE; + } + break; + + case SYMA_CHANGE_SUFFIX: // Change end of symbol name + if (symtype == SYMT_PUBLIC || symtype == SYMT_EXTERNAL || symtype == SYMT_LOCAL || symtype == SYMT_SECTION) { + if (strlen(oldname) - strlen(psym->Name1) + strlen(psym->Name2) >= MAXSYMBOLLENGTH) { + err.submit(2202, oldname); // Name too long + action = SYMA_NOCHANGE; break; + } + strcpy(NameBuffer, oldname); + strcpy(NameBuffer + strlen(oldname) - strlen(psym->Name1), psym->Name2); + action = SYMA_CHANGE_NAME; + *newname = NameBuffer; + CountSymbolNameChanges++; psym->Done++; + } + else { // only symbols and segments can change prefix + err.submit(1024, oldname); + action = SYMA_NOCHANGE; + } + break; + + case SYMA_EXTRACT_MEMBER: + *newname = psym->Name2; + // continue in next case + case SYMA_DELETE_MEMBER: case SYMA_ADD_MEMBER: + if (symtype == SYMT_LIBRARYMEMBER) { + // Change to library member + psym->Done++; + } + else { + // Ignore action for symbols that have the same name as a library member + action = SYMA_NOCHANGE; + } + } + + if (action && (psym->Action & SYMA_ALIAS)) { + // Keep old name as alias + if (symtype == SYMT_PUBLIC) { + CountSymbolNameAliases++; psym->Done++; + action = SYMA_ALIAS; + } + else { // only public symbols can have aliases + CountSymbolNameChanges--; + err.submit(1022, oldname); // cannot make alias + action = SYMA_NOCHANGE; + } + } + + // Action to take + return action; + } + + // Not found in list. Check for section options + if (symtype == SYMT_SECTION) { + if (!strncmp(oldname, ".rela", 5)) { + // ELF relocation section must have same name change as mother section + const char * name2; + int action2 = SymbolChange(oldname+5, &name2, symtype); + if (action2 == SYMA_CHANGE_NAME && strlen(name2) + 6 < MAXSYMBOLLENGTH) { + sprintf(NameBuffer, ".rela%s", name2); + *newname = NameBuffer; + return action2; + } + } + if (!strncmp(oldname, ".rel", 4)) { + // ELF relocation section must have same name change as mother section + const char * name2; + int action2 = SymbolChange(oldname+4, &name2, symtype); + if (action2 == SYMA_CHANGE_NAME && strlen(name2) + 5 < MAXSYMBOLLENGTH) { + sprintf(NameBuffer, ".rel%s", name2); + *newname = NameBuffer; + return action2; + } + } + if (SegmentDot) { + // Change section name + + if (SegmentDot == CMDL_SECTIONDOT_U2DOT && oldname[0] == '_') { + // replace '_' by '.' + strncpy(NameBuffer, oldname, MAXSYMBOLLENGTH-1); + NameBuffer[MAXSYMBOLLENGTH-1] = 0; // Terminate string + NameBuffer[0] = '.'; + *newname = NameBuffer; + CountSectionDotConversions++; + return SYMA_CHANGE_NAME; + } + if (SegmentDot == CMDL_SECTIONDOT_DOT2U && oldname[0] == '.') { + // replace '.' by '_' + // Note: Microsoft and Intel compilers have . on standard names + // and _ on nonstandard names in COFF files + // Borland requires _ on all segment names in OMF files + /* + // Standard section names that should not be changed + static char const * StandardSectionNames[] = { + ".text", ".data", ".bss", ".comment", ".lib" + }; + for (uint32 i = 0; i < sizeof(StandardSectionNames)/sizeof(StandardSectionNames[0]); i++) { + if (stricmp(oldname,StandardSectionNames[i]) == 0) { + // Standard name. Don't change + return SYMA_NOCHANGE; + } + }*/ + strncpy(NameBuffer, oldname, MAXSYMBOLLENGTH-1); + NameBuffer[MAXSYMBOLLENGTH-1] = 0; // Terminate string + NameBuffer[0] = '_'; + *newname = NameBuffer; + CountSectionDotConversions++; + return SYMA_CHANGE_NAME; + } + } + } + + // Check for underscore options + if ((Underscore & 0x0F) == CMDL_UNDERSCORE_REMOVE && oldname[0] == '_') { + // Remove underscore + if ((Underscore & CMDL_KEEP_ALIAS) && symtype == SYMT_PUBLIC) { + // Alias only applicable to public symbols + // Make alias without underscore + *newname = oldname + 1; + CountUnderscoreConversions++; CountSymbolNameAliases++; + return SYMA_ALIAS; + } + // Change name applicable to public and external symbols + if (symtype == SYMT_PUBLIC || symtype == SYMT_EXTERNAL) { + // Make new name without underscore + *newname = oldname + 1; + CountUnderscoreConversions++; + return SYMA_CHANGE_NAME; + } + } + if ((Underscore & 0x0F) == CMDL_UNDERSCORE_ADD) { + // Add underscore even if it already has one + if ((Underscore & CMDL_KEEP_ALIAS) && symtype == SYMT_PUBLIC) { + // Alias only applicable to public symbols + // Make alias with underscore + strncpy(NameBuffer+1, oldname, MAXSYMBOLLENGTH-2); + NameBuffer[MAXSYMBOLLENGTH-1] = 0; // Terminate string + NameBuffer[0] = '_'; + *newname = NameBuffer; + CountUnderscoreConversions++; CountSymbolNameAliases++; + return SYMA_ALIAS; + } + // Change name applicable to public and external symbols + if (symtype == SYMT_PUBLIC || symtype == SYMT_EXTERNAL) { + // Make new name with underscore + strncpy(NameBuffer+1, oldname, MAXSYMBOLLENGTH-2); + NameBuffer[MAXSYMBOLLENGTH-1] = 0; // Terminate string + NameBuffer[0] = '_'; + *newname = NameBuffer; + CountUnderscoreConversions++; + return SYMA_CHANGE_NAME; + } + } + return SYMA_NOCHANGE; +} + + +int CCommandLineInterpreter::SymbolChangesRequested() { + // Any kind of symbol change requested on command line + return (Underscore != 0) + | (SegmentDot != 0) << 1 + | (SymbolChangeEntries != 0) << 2; +} + + +void CCommandLineInterpreter::CountDebugRemoved() { + // Count debug sections removed + CountDebugSectionsRemoved++; +} + + +void CCommandLineInterpreter::CountExceptionRemoved() { + // Count exception handler sections removed + CountExceptionSectionsRemoved++; +} + + +void CCommandLineInterpreter::CountSymbolsHidden() { + // Count unused external references hidden + CountUnusedSymbolsHidden++; +} + + +void CCommandLineInterpreter::ReportStatistics() { + // Report statistics about name changes etc. + if (DebugInfo == CMDL_DEBUG_STRIP || ExeptionInfo == CMDL_EXCEPTION_STRIP + || Underscore || SegmentDot || SymbolList.GetNumEntries()) { + printf ("\n"); + } + if (DebugInfo == CMDL_DEBUG_STRIP) { + printf ("\n%3i Debug sections removed", CountDebugSectionsRemoved); + } + if (ExeptionInfo == CMDL_EXCEPTION_STRIP) { + printf ("\n%3i Exception sections removed", CountExceptionSectionsRemoved); + } + if ((DebugInfo == CMDL_DEBUG_STRIP || ExeptionInfo == CMDL_EXCEPTION_STRIP) + && CountUnusedSymbolsHidden) { + printf ("\n%3i Unused external symbol references hidden", CountUnusedSymbolsHidden); + } + + if (Underscore || SegmentDot || SymbolList.GetNumEntries()) { + if (CountUnderscoreConversions || Underscore) { + printf ("\n%3i Changes in leading underscores on symbol names", CountUnderscoreConversions); + } + if (CountSectionDotConversions || SegmentDot) { + printf ("\n%3i Changes in leading characters on section names", CountSectionDotConversions); + } + if (CountSymbolNameChanges) { + printf ("\n%3i Symbol names changed", CountSymbolNameChanges); + } + if (CountSymbolNameAliases) { + printf ("\n%3i Public symbol names aliased", CountSymbolNameAliases); + } + if (CountSymbolsWeakened) { + printf ("\n%3i Public symbol names made weak", CountSymbolsWeakened); + } + if (CountSymbolsMadeLocal) { + printf ("\n%3i Public or external symbol names made local", CountSymbolsMadeLocal); + } + if (SymbolChangeEntries && !CountSymbolNameChanges && !CountSymbolNameAliases && !CountSymbolsWeakened && !CountSymbolsMadeLocal) { + printf ("\n No symbols to change were found"); + } + } +} + + +void CCommandLineInterpreter::Help() { + // Print help message + printf("\nObject file converter version %.2f for x86 and x86-64 platforms.", OBJCONV_VERSION); + printf("\nCopyright (c) 2018 by Agner Fog. Gnu General Public License."); + printf("\n\nUsage: objconv options inputfile [outputfile]"); + printf("\n\nOptions:"); + printf("\n-fXXX[SS] Output file format XXX, word size SS. Supported formats:"); + printf("\n PE, COFF, ELF, OMF, MACHO\n"); + printf("\n-fasm Disassemble file (-fmasm, -fnasm, -fyasm, -fgasm)\n"); + printf("\n-dXXX Dump file contents to console."); + printf("\n Values of XXX (can be combined):"); + printf("\n f: File header, h: section Headers, s: Symbol table,"); + printf("\n r: Relocation table, n: string table.\n"); + + printf("\n-nu change symbol Name Underscores to the default for the target format."); + printf("\n-nu- remove Underscores from symbol Names."); + printf("\n-nu+ add Underscores to symbol Names."); + printf("\n-nd replace Dot/underscore in section names."); + printf("\n-nr:N1:N2 Replace symbol Name N1 with N2."); + printf("\n-np:N1:N2 Replace symbol Prefix N1 with N2."); + printf("\n-ns:N1:N2 Replace symbol Suffix N1 with N2."); + printf("\n-ar:N1:N2 make Alias N2 for existing public name N1."); + printf("\n-ap:N1:N2 Replace symbol Prefix and keep old name as alias."); + printf("\n-as:N1:N2 Replace symbol Suffix and keep old name as alias."); + printf("\n-nw:N1 make public symbol Name N1 Weak (ELF and MAC64 only)."); + printf("\n-nl:N1 make public symbol Name N1 Local (invisible).\n"); + //printf("\n-ds Strip Debug info."); // default if input and output are different formats + //printf("\n-dp Preserve Debug info, even if it is incompatible."); + printf("\n-xs Strip exception handling info and other incompatible info."); // default if input and output are different formats. Hides unused symbols + printf("\n-xp Preserve exception handling info and other incompatible info.\n"); + + printf("\n-lx eXtract all members from Library."); + printf("\n-lx:N1:N2 eXtract member N1 from Library to file N2."); + printf("\n-ld:N1 Delete member N1 from Library."); + printf("\n-la:N1:N2 Add object file N1 to Library as member N2."); + printf("\n Alternative: -lib LIBRARYNAME OBJECTFILENAMES.\n"); + + printf("\n-vN Verbose options. Values of N:"); + printf("\n 0: Silent, 1: Print file names and types, 2: Tell about conversions."); + + printf("\n-wdNNN Disable Warning NNN."); + printf("\n-weNNN treat Warning NNN as Error. -wex: treat all warnings as errors."); + printf("\n-edNNN Disable Error number NNN."); + printf("\n-ewNNN treat Error number NNN as Warning.\n"); + + printf("\n-h Print this help screen.\n"); + + printf("\n@RFILE Read additional options from response file RFILE.\n"); + printf("\n\nExample:"); + printf("\nobjconv -felf32 -nu filename.obj filename.o\n\n"); +} diff --git a/programs/develop/objconv/cmdline.h b/programs/develop/objconv/cmdline.h new file mode 100644 index 0000000000..8296664765 --- /dev/null +++ b/programs/develop/objconv/cmdline.h @@ -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 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 diff --git a/programs/develop/objconv/cof2asm.cpp b/programs/develop/objconv/cof2asm.cpp new file mode 100644 index 0000000000..4a025e620d --- /dev/null +++ b/programs/develop/objconv/cof2asm.cpp @@ -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(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(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(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(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(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(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(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(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(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(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); + } + } +} diff --git a/programs/develop/objconv/cof2cof.cpp b/programs/develop/objconv/cof2cof.cpp new file mode 100644 index 0000000000..765740d0b4 --- /dev/null +++ b/programs/develop/objconv/cof2cof.cpp @@ -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(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(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. +} diff --git a/programs/develop/objconv/cof2elf.cpp b/programs/develop/objconv/cof2elf.cpp new file mode 100644 index 0000000000..4511281726 --- /dev/null +++ b/programs/develop/objconv/cof2elf.cpp @@ -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 +CCOF2ELF::CCOF2ELF () { + // Constructor + memset(this, 0, sizeof(*this)); +} + + +template +void CCOF2ELF::Convert() { + // Do the conversion + NumSectionsNew = 5; // Number of sections generated so far + + // Allocate variable size buffers + MaxSectionsNew = NumSectionsNew + 2 * NSections; // Max number of sections needed + NewSections.SetNum(MaxSectionsNew); // Allocate buffers for each section + NewSections.SetZero(); // Initialize + NewSectionHeaders.SetNum(MaxSectionsNew); // Allocate array for temporary section headers + NewSectionHeaders.SetZero(); // Initialize + NewSectIndex.SetNum(NSections); // Array for translating old section index (0-based) to new section index + NewSectIndex.SetZero(); // Initialize + NewSymbolIndex.SetNum(NumberOfSymbols); // Array of new symbol indices + NewSymbolIndex.SetZero(); // Initialize + + // Call the subfunctions + ToFile.SetFileType(FILETYPE_ELF); // Set type of to file + MakeSegments(); // Make segment headers and code/data segments + MakeSymbolTable(); // Symbol table and string tables + MakeRelocationTables(); // Relocation tables + MakeBinaryFile(); // Putting sections together + *this << ToFile; // Take over new file buffer +} + + +template +void CCOF2ELF::MakeSegments() { + // Convert subfunction: Make segment headers and code/data segments + TELF_SectionHeader NewSecHeader; // New section header + int oldsec; // Section index in old file + int newsec; // Section index in new file + uint32 SecNameIndex; // Section name index into shstrtab + char const * SecName; // Name of new section + const int WordSize = sizeof(NewFileHeader.e_entry) * 8; // word size 32 or 64 bits + + // Special segment names + static const char * SpecialSegmentNames[] = { + "Null", ".symtab", ".shstrtab", ".strtab", ".stabstr" + }; + // Indexes to these are: + symtab = 1; // Symbol table section number + shstrtab = 2; // Section name string table section number + strtab = 3; // Object name string table section number + stabstr = 4; // Debug string table section number + + // Number of special segments = number of names in SpecialSegmentNames: + const int NumSpecialSegments = sizeof(SpecialSegmentNames)/sizeof(SpecialSegmentNames[0]); + + // Make first section header string table entry empty + NewSections[shstrtab].PushString(""); + + // Loop through special sections, except the first Null section: + for (newsec = 0; newsec < NumSpecialSegments; newsec++) { + // Put data into new section header: + // Initialize to zero + memset(&NewSecHeader, 0, sizeof(NewSecHeader)); + + if (newsec > 0) { + // Put name into section header string table + SecName = SpecialSegmentNames[newsec]; + SecNameIndex = NewSections[shstrtab].PushString(SecName); + + // Put name into new section header + NewSecHeader.sh_name = SecNameIndex; + } + + // Put section header into temporary buffer + NewSectionHeaders[newsec] = NewSecHeader; + } + + // Put type, flags, etc. into special segments: + NewSectionHeaders[symtab] .sh_type = SHT_SYMTAB; + NewSectionHeaders[symtab] .sh_entsize = sizeof(TELF_Symbol); + NewSectionHeaders[symtab] .sh_link = strtab; + NewSectionHeaders[shstrtab].sh_type = SHT_STRTAB; + NewSectionHeaders[shstrtab].sh_flags = SHF_STRINGS; + NewSectionHeaders[shstrtab].sh_addralign = 1; + NewSectionHeaders[strtab] .sh_type = SHT_STRTAB; + NewSectionHeaders[strtab] .sh_flags = SHF_STRINGS; + NewSectionHeaders[strtab] .sh_addralign = 1; + NewSectionHeaders[stabstr] .sh_type = SHT_STRTAB; + NewSectionHeaders[stabstr] .sh_flags = SHF_STRINGS; + NewSectionHeaders[stabstr] .sh_addralign = 1; + + if (newsec != NumSectionsNew) { + // Check my program for internal consistency + // If you get this error then change the value of NumSectionsNew in + // the constructor CCOF2ELF::CCOF2ELF to equal the number of entries in + // SpecialSegmentNames, including the Null segment + err.submit(9000); + } + + // Loop through source file sections + for (oldsec = 0; oldsec < this->NSections; oldsec++) { + + // Pointer to old section header + SCOFF_SectionHeader * SectionHeader = &this->SectionHeaders[oldsec]; + + // Get section name + SecName = this->GetSectionName(SectionHeader->Name); + if (strnicmp(SecName,"debug",5) == 0 || strnicmp(SecName+1,"debug",5) == 0) { + // This is a debug section + if (cmd.DebugInfo == CMDL_DEBUG_STRIP) { + // Remove debug info + NewSectIndex[oldsec] = COFF_SECTION_REMOVE_ME; // Remember that this section is removed + cmd.CountDebugRemoved(); + continue; + } + else if (cmd.InputType != cmd.OutputType) { + err.submit(1029); // Warn that debug information is incompatible + } + } + if (strnicmp(SecName,".drectve",8) == 0 || (SectionHeader->Flags & (PE_SCN_LNK_INFO | PE_SCN_LNK_REMOVE))) { + // This is a directive section + if (cmd.ExeptionInfo) { + // Remove directive section + NewSectIndex[oldsec] = COFF_SECTION_REMOVE_ME; // Remember that this section is removed + cmd.CountExceptionRemoved(); + continue; + } + } + if (strnicmp(SecName,".pdata", 6) == 0) { + // This section has exception information + if (cmd.ExeptionInfo == CMDL_EXCEPTION_STRIP) { + // Remove exception info + NewSectIndex[oldsec] = COFF_SECTION_REMOVE_ME; // Remember that this section is removed + cmd.CountExceptionRemoved(); + continue; + } + else if (cmd.InputType != cmd.OutputType) { + err.submit(1030); // Warn that exception information is incompatible + } + } + + if (strnicmp(SecName,".cormeta", 8) == 0) { + // This is a .NET Common Language Runtime section + err.submit(2014); + } + if (strnicmp(SecName,".rsrc", 5) == 0) { + // This section has Windows resource information + err.submit(1031); + } + + // Store section index in index translation table (zero-based index) + NewSectIndex[oldsec] = newsec; + + // Store section data + if (SectionHeader->SizeOfRawData > 0) { + NewSections[newsec].Push(Buf()+SectionHeader->PRawData, SectionHeader->SizeOfRawData); + } + + // Put data into new section header: + // Initialize to zero + memset(&NewSecHeader, 0, sizeof(NewSecHeader)); + + // Section type + if (!(SectionHeader->Flags & PE_SCN_LNK_REMOVE)) { + NewSecHeader.sh_type = SHT_PROGBITS; // Program code or data + NewSecHeader.sh_flags |= SHF_ALLOC; // Occupies memory during execution + } + if (SectionHeader->Flags & PE_SCN_CNT_UNINIT_DATA) { + NewSecHeader.sh_type = SHT_NOBITS; // BSS + } + + // Section flags + if (SectionHeader->Flags & PE_SCN_MEM_WRITE) { + NewSecHeader.sh_flags |= SHF_WRITE; + } + if (SectionHeader->Flags & PE_SCN_MEM_EXECUTE) { + NewSecHeader.sh_flags |= SHF_EXECINSTR; + } + + // Check for special sections + if (strcmp(SecName, COFF_CONSTRUCTOR_NAME)==0) { + // Constructors segment + SecName = ELF_CONSTRUCTOR_NAME; + NewSecHeader.sh_flags = SHF_WRITE | SHF_ALLOC; + } + + // Put name into section header string table + SecNameIndex = NewSections[shstrtab].PushString(SecName); + + // Put name into new section header + NewSecHeader.sh_name = SecNameIndex; + + // Section virtual memory address + NewSecHeader.sh_addr = SectionHeader->VirtualAddress; + + // Section size in memory + NewSecHeader.sh_size = SectionHeader->VirtualSize; + + // Section alignment + if (SectionHeader->Flags & PE_SCN_ALIGN_MASK) { + NewSecHeader.sh_addralign = uint32(1 << (((SectionHeader->Flags & PE_SCN_ALIGN_MASK) / PE_SCN_ALIGN_1) - 1)); + } + + // Put section header into temporary buffer + NewSectionHeaders[newsec] = NewSecHeader; + + // Increment section number + newsec++; + + if (SectionHeader->NRelocations > 0) { + // Source section has relocations. + // Make a relocation section in destination file + + // Put data into relocation section header: + // Initialize to zero + memset(&NewSecHeader, 0, sizeof(NewSecHeader)); + + // Name for relocation section = ".rel" or ".rela" + name of section + const int MAXSECTIONNAMELENGTH = 256; + char RelocationSectionName[MAXSECTIONNAMELENGTH] = ".rel"; + if (WordSize == 64) strcat(RelocationSectionName, "a"); // 32-bit: .rel, 64-bit: .rela + + strncat(RelocationSectionName, SecName, MAXSECTIONNAMELENGTH-5); + RelocationSectionName[MAXSECTIONNAMELENGTH-1] = 0; + + // Put name into section header string table + uint32 SecNameIndex = NewSections[shstrtab].PushString(RelocationSectionName); + + // Put name into new section header + NewSecHeader.sh_name = SecNameIndex; + + // Section type + NewSecHeader.sh_type = (WordSize == 32) ? SHT_REL : SHT_RELA; // Relocation section + + // Put section header into temporary buffer + NewSectionHeaders[newsec] = NewSecHeader; + + // Increment section number + newsec++; + } + } + // Number of sections generated + NumSectionsNew = newsec; +} + + +template +void CCOF2ELF::MakeSymbolTable() { + // Convert subfunction: Make symbol table and string tables + int isym; // current symbol table entry + int numaux; // Number of auxiliary entries in source record + int OldSectionIndex; // Index into old section table. 1-based + int NewSectionIndex; // Index into new section table. 0-based + //const int WordSize = sizeof(NewFileHeader.e_entry) * 8; // word size 32 or 64 bits + + TELF_Symbol sym; // Temporary symbol table record + const char * name1; // Name of section or main record + + // Pointer to old symbol table + union { + SCOFF_SymTableEntry * p; // Symtab entry pointer + int8 * b; // Used for increment + } OldSymtab; + + // Make the first record empty + NewSections[symtab].Push(0, sizeof(TELF_Symbol)); + + // Make first string table entries empty + NewSections[strtab] .PushString(""); + NewSections[stabstr].PushString(""); + + // Loop twice through source symbol table to get local symbols first, global symbols last + // Loop 1: Look for local symbols only + OldSymtab.p = SymbolTable; // Pointer to source symbol table + for (isym = 0; isym < this->NumberOfSymbols; isym += numaux+1, OldSymtab.b += SIZE_SCOFF_SymTableEntry*(numaux+1)) { + + if (OldSymtab.b >= Buf() + DataSize) { + err.submit(2040); + break; + } + + // Number of auxiliary records belonging to same symbol + numaux = OldSymtab.p->s.NumAuxSymbols; if (numaux < 0) numaux = 0; + + if (OldSymtab.p->s.StorageClass != COFF_CLASS_EXTERNAL && OldSymtab.p->s.StorageClass != COFF_CLASS_WEAK_EXTERNAL) { + // Symbol is local + + // Reset destination entry + memset(&sym, 0, sizeof(sym)); + + // Binding + sym.st_bind = STB_LOCAL; + + // Get first aux record if numaux > 0 + //SCOFF_SymTableEntryAux * sa = (SCOFF_SymTableEntryAux *)(OldSymtab.b + SIZE_SCOFF_SymTableEntry); + + // Symbol name + name1 = this->GetSymbolName(OldSymtab.p->s.Name); + + // Symbol value + sym.st_value = OldSymtab.p->s.Value; + + // Get section + OldSectionIndex = OldSymtab.p->s.SectionNumber; // 1-based index into old section table + NewSectionIndex = 0; // 0-based index into old section table + if (OldSectionIndex > 0 && OldSectionIndex <= this->NSections) { + // Subtract 1 from OldSectionIndex because NewSectIndex[] is zero-based while OldSectionIndex is 1-based + // Get new section index from translation table + NewSectionIndex = NewSectIndex[OldSectionIndex-1]; + } + if (NewSectionIndex == COFF_SECTION_REMOVE_ME) { + continue; // Section has been removed. Remove symbol too + } + + sym.st_shndx = (uint16)NewSectionIndex; + + // Check symbol type + if (OldSymtab.p->s.StorageClass == COFF_CLASS_FILE) { + // This is a filename record + if (numaux > 0 && numaux < 20) { + // Get filename from subsequent Aux records. + // Remove path from filename because the path makes no sense on a different platform. + const char * filename = GetShortFileName(OldSymtab.p); + // Put file name into string table and debug string table + sym.st_name = NewSections[strtab].PushString(filename); + NewSections[stabstr].PushString(filename); + } + // Attributes for filename record + sym.st_shndx = (uint16)SHN_ABS; + sym.st_type = STT_FILE; + sym.st_bind = STB_LOCAL; + sym.st_value = 0; + } + else if (numaux && OldSymtab.p->s.StorageClass == COFF_CLASS_STATIC + && OldSymtab.p->s.Value == 0 && OldSymtab.p->s.Type != 0x20) { + // This is a section definition record + sym.st_name = 0; name1 = 0; + sym.st_type = STT_SECTION; + sym.st_bind = STB_LOCAL; + sym.st_value = 0; + // aux record contains length and number of relocations. Ignore aux record + } + else if (OldSymtab.p->s.SectionNumber < 0) { + // This is an absolute or debug symbol + sym.st_type = STT_NOTYPE; + sym.st_shndx = (uint16)SHN_ABS; + } + else if (OldSymtab.p->s.Type == 0 && OldSymtab.p->s.StorageClass == COFF_CLASS_FUNCTION) { + // This is a .bf, .lf, or .ef record following a function record + // Contains line number information etc. Ignore this record + continue; + } + else if (OldSymtab.p->s.SectionNumber <= 0) { + // Unknown + sym.st_type = STT_NOTYPE; + } + else { + // This is a local data definition record + sym.st_type = STT_OBJECT; + // The size is not specified in COFF record, + // so we may give it an arbitrary size: + // sym.size = 4; + } + + // Put symbol name into string table if we have not already done so + if (sym.st_name == 0 && name1) { + sym.st_name = NewSections[strtab].PushString(name1); + } + + // Put record into new symbol table + NewSections[symtab].Push(&sym, sizeof(sym)); + + // Insert into symbol translation table + NewSymbolIndex[isym] = NewSections[symtab].GetLastIndex(); + + } // End if not external + } // End loop 1 + + // Finished with local symbols + // Make index to first global symbol + NewSectionHeaders[symtab].sh_info = NewSections[symtab].GetLastIndex() + 1; + + // Loop 2: Look for global symbols only + OldSymtab.p = SymbolTable; // Pointer to source symbol table + for (isym = 0; isym < NumberOfSymbols; isym += numaux+1, OldSymtab.b += SIZE_SCOFF_SymTableEntry*(numaux+1)) { + + // Number of auxiliary records belonging to same symbol + numaux = OldSymtab.p->s.NumAuxSymbols; if (numaux < 0) numaux = 0; + + if (OldSymtab.p->s.StorageClass == COFF_CLASS_EXTERNAL || OldSymtab.p->s.StorageClass == COFF_CLASS_WEAK_EXTERNAL) { + // Symbol is global (public or external) + + // Reset destination entry + memset(&sym, 0, sizeof(sym)); + + // Binding + sym.st_bind = STB_GLOBAL; + if (OldSymtab.p->s.StorageClass == COFF_CLASS_WEAK_EXTERNAL) sym.st_bind = STB_WEAK; + + // Get first aux record if numaux > 0 + SCOFF_SymTableEntry * sa = (SCOFF_SymTableEntry*)(OldSymtab.b + SIZE_SCOFF_SymTableEntry); + + // Symbol name + name1 = GetSymbolName(OldSymtab.p->s.Name); + + // Symbol value + sym.st_value = OldSymtab.p->s.Value; + + // Get section + OldSectionIndex = OldSymtab.p->s.SectionNumber; // 1-based index into old section table + NewSectionIndex = 0; // 0-based index into old section table + if (OldSectionIndex > 0 && OldSectionIndex <= NSections) { + // Subtract 1 from OldSectionIndex because NewSectIndex[] is zero-based while OldSectionIndex is 1-based + // Get new section index from translation table + NewSectionIndex = NewSectIndex[OldSectionIndex-1]; + } + if (NewSectionIndex == COFF_SECTION_REMOVE_ME) { + continue; // Section has been removed. Remove symbol too + } + if ((int16)OldSectionIndex == COFF_SECTION_ABSOLUTE) { + NewSectionIndex = SHN_ABS; + } + + sym.st_shndx = (uint16)NewSectionIndex; + + // Check symbol type + if (OldSymtab.p->s.SectionNumber < 0) { + // This is an absolute or debug symbol + sym.st_type = STT_NOTYPE; + } + else if (OldSymtab.p->s.Type == COFF_TYPE_FUNCTION && OldSymtab.p->s.SectionNumber > 0) { + // This is a function definition record + sym.st_type = STT_FUNC; + if (numaux) { + // Get size from aux record + sym.st_size = sa->func.TotalSize; + } + if (sym.st_size == 0) { + // The size is not specified in the COFF file. + // We may give it an arbitrary size: + // sym.size = 1; + } + } + else if (OldSymtab.p->s.SectionNumber <= 0) { + // This is an external symbol + sym.st_type = STT_NOTYPE; + } + else { + // This is a data definition record + sym.st_type = STT_OBJECT; + // Symbol must have a size. The size is not specified in COFF record, + // so we just give it an arbitrary size + sym.st_size = 4; + } + + // Put symbol name into string table if we have not already done so + if (sym.st_name == 0 && name1) { + sym.st_name = NewSections[strtab].PushString(name1); + } + + // Put record into new symbol table + NewSections[symtab].Push(&sym, sizeof(sym)); + + // Insert into symbol translation table + NewSymbolIndex[isym] = NewSections[symtab].GetLastIndex(); + + } // End if external + } // End loop 2 +} + + +template +void CCOF2ELF::MakeRelocationTables() { + // Convert subfunction: Relocation tables + int32 oldsec; // Relocated section number in source file + int32 newsec; // Relocated section number in destination file + int32 newsecr; // Relocation table section number in destination file + TELF_SectionHeader * NewRelTableSecHeader; // Section header for new relocation table + char TempText[32]; // Temporary text buffer + const int WordSize = sizeof(NewFileHeader.e_entry) * 8; // word size 32 or 64 bits + + // Loop through source file sections + for (oldsec = 0; oldsec < NSections; oldsec++) { + + // New section index + newsec = NewSectIndex[oldsec]; + if (newsec == COFF_SECTION_REMOVE_ME) { + continue; // This is a debug or exception handler section which has been removed + } + + // Pointer to old section header + SCOFF_SectionHeader * SectionHeader = &this->SectionHeaders[oldsec]; + + if (SectionHeader->NRelocations > 0) { + // This section has relocations + + // Finc new relocation table section + newsecr = newsec + 1; + + // Check that we have allocated a relocation section + if (oldsec+1 < this->NSections && NewSectIndex[oldsec+1] == newsecr) err.submit(9000); + if (newsecr >= NumSectionsNew) err.submit(9000); + + // New relocation table section header + NewRelTableSecHeader = &NewSectionHeaders[newsecr]; + + // Insert header info + NewRelTableSecHeader->sh_type = (WordSize == 32) ? SHT_REL : SHT_RELA; + NewRelTableSecHeader->sh_flags = 0; + NewRelTableSecHeader->sh_addralign = WordSize / 8; // Alignment + NewRelTableSecHeader->sh_link = symtab; // Point to symbol table + NewRelTableSecHeader->sh_info = newsec; // Point to relocated section + // Entry size: + NewRelTableSecHeader->sh_entsize = (WordSize == 32) ? sizeof(Elf32_Rel) : sizeof(Elf64_Rela); + + // Pointer to old relocation entry + union { + SCOFF_Relocation * p; // pointer to record + int8 * b; // used for address calculation and incrementing + } OldReloc; + + // Loop through relocations + + OldReloc.b = Buf() + SectionHeader->PRelocations; + for (int i = 0; i < SectionHeader->NRelocations; i++, OldReloc.b += SIZE_SCOFF_Relocation) { + + // Make new relocation entry and set to zero + TELF_Relocation NewRelocEntry; + memset(&NewRelocEntry, 0, sizeof(NewRelocEntry)); + + // Section offset of relocated address + NewRelocEntry.r_offset = OldReloc.p->VirtualAddress; + + // Target symbol + uint32 TargetSymbol = OldReloc.p->SymbolTableIndex; + if (TargetSymbol >= (uint32)NumberOfSymbols) { + err.submit(2031); // Symbol not in table + } + else { // Translate symbol number + NewRelocEntry.r_sym = NewSymbolIndex[TargetSymbol]; + } + + if (WordSize == 32) { + // Interpret 32-bit COFF relocation types + switch (OldReloc.p->Type) { + case COFF32_RELOC_ABS: // Ignored + NewRelocEntry.r_type = R_386_NONE; break; + + case COFF32_RELOC_TOKEN: // .NET common language runtime token + err.submit(2014); // Error message + // Continue in next case and insert absolute address as token: + case COFF32_RELOC_DIR32: // 32-bit absolute virtual address + NewRelocEntry.r_type = R_386_32; break; + + case COFF32_RELOC_IMGREL: // 32-bit image relative address + // Image-relative relocation not supported in ELF + if (cmd.OutputType == FILETYPE_MACHO_LE) { + // Intermediate during conversion to MachO + NewRelocEntry.r_type = R_UNSUPPORTED_IMAGEREL; + break; + } + // Work-around unsupported image-relative relocation + // Convert to absolute + NewRelocEntry.r_type = R_386_32; // Absolute relocation + if (cmd.ImageBase == 0) { + // Default image base for 32-bit Linux + cmd.ImageBase = 0x8048000; // 0x400000 ? + } + NewRelocEntry.r_addend -= cmd.ImageBase; + // Warn that image base must be set to the specified value + sprintf(TempText, "%X", cmd.ImageBase); // write value as hexadecimal + err.submit(1301, TempText); err.ClearError(1301); + break; + + case COFF32_RELOC_REL32: // 32-bit self-relative + NewRelocEntry.r_type = R_386_PC32; + // Difference between EIP-relative and self-relative relocation = size of address field + NewRelocEntry.r_addend = -4; break; + /* !! error if self-relative relocation with offset + !! test data that fails = testpic32.obj */ + + case COFF32_RELOC_SECTION: // 16-bit section index in file + case COFF32_RELOC_SECREL: // 32-bit section-relative + case COFF32_RELOC_SECREL7: // 8-bit section-relative + // These fixup types are not supported in ELF files + if (cmd.DebugInfo != CMDL_DEBUG_STRIP) { + // Issue warning. Ignore if stripping debug info + err.submit(1010); + } + break; + + default: + err.submit(2030, OldReloc.p->Type); break; // Error: Unknown relocation type (%i) ignored + } + } + else { + // Interpret 64-bit COFF relocation types + switch (OldReloc.p->Type) { + case COFF64_RELOC_ABS: // Ignored + NewRelocEntry.r_type = R_X86_64_NONE; break; + + case COFF64_RELOC_TOKEN: // .NET common language runtime token + err.submit(2014); // Error message + // Continue in next case and insert absolute address as token: + + case COFF64_RELOC_ABS64: // 64 bit absolute virtual address + NewRelocEntry.r_type = R_X86_64_64; break; + + case COFF64_RELOC_PPC_TOKEN: + err.submit(2014); // Error message + // Continue in next case and insert absolute address as token: + + case COFF64_RELOC_ABS32: // 32 bit absolute address + NewRelocEntry.r_type = R_X86_64_32S; break; + + case COFF64_RELOC_IMGREL: // 32 bit image-relative + // Image-relative relocation not supported in ELF + if (cmd.OutputType == FILETYPE_MACHO_LE) { + // Intermediate during conversion to MachO + NewRelocEntry.r_type = R_UNSUPPORTED_IMAGEREL; + break; + } + // Work-around unsupported image-relative relocation + // Convert to absolute + NewRelocEntry.r_type = R_X86_64_32S; // Absolute 32-bit relocation + if (cmd.ImageBase == 0) { + // Default image base for 64-bit Linux + cmd.ImageBase = 0x400000; + } + NewRelocEntry.r_addend -= cmd.ImageBase; + // Warn that image base must be set to the specified value + sprintf(TempText, "%X", cmd.ImageBase); // write value as hexadecimal + err.submit(1301, TempText); err.ClearError(1301); + break; + + case COFF64_RELOC_REL32: // 32 bit, RIP-relative + case COFF64_RELOC_REL32_1: // 32 bit, relative to RIP - 1. For instruction with immediate byte operand + case COFF64_RELOC_REL32_2: // 32 bit, relative to RIP - 2. For instruction with immediate word operand + case COFF64_RELOC_REL32_3: // 32 bit, relative to RIP - 3. (useless) + case COFF64_RELOC_REL32_4: // 32 bit, relative to RIP - 4. For instruction with immediate dword operand + case COFF64_RELOC_REL32_5: // 32 bit, relative to RIP - 5. (useless) + NewRelocEntry.r_type = R_X86_64_PC32; + // Note: + // The microprocessor calculates RIP-relative addresses + // relative to the value of the instruction pointer AFTER + // the instruction. This is equal to the address of the + // relocated field plus the size of the relocated field + // itself plus the size of any immediate operand coming + // after the relocated field. + // The COFF format makes the correction for this offset in + // the linker by using a differet relocation type for + // immediate operand size = 0, 1, 2 or 4. + // The ELF format makes the same correction by an explicit + // addend, which is -4, -5, -6 or -8, respectively. + // The difference between RIP-relative and self-relative + // relocation is equal to the size of the address field plus + // the size of any immediate operand: + NewRelocEntry.r_addend = -(4 + OldReloc.p->Type - COFF64_RELOC_REL32); + break; + + case COFF64_RELOC_SECTION: // 16-bit section index in file + case COFF64_RELOC_SECREL: // 32-bit section-relative + case COFF64_RELOC_SECREL7: // 8-bit section-relative + + // These fixup types are not supported in ELF files + if (cmd.DebugInfo != CMDL_DEBUG_STRIP) { + // Issue warning. Ignore if stripping debug info + err.submit(1010); + } + break; + + default: + err.submit(2030, OldReloc.p->Type); break; // Error: Unknown relocation type (%i) ignored + } + } + + // Find inline addend + int32 * paddend = 0; + if (OldReloc.p->VirtualAddress + 4 > NewSections[newsec].GetDataSize() + || NewSectionHeaders[newsec].sh_type == SHT_NOBITS) { + // Address of relocation is invalid + err.submit(2032); + } + else { + // Make pointer to inline addend + paddend = (int32*)(NewSections[newsec].Buf() + + NewSectionHeaders[newsec].sh_offset + OldReloc.p->VirtualAddress); + } + + // Put relocation record into table + if (WordSize == 32) { + if (NewRelocEntry.r_addend != 0) { + // Use inline addends in 32 bit ELF (SHT_REL) + // Put addend inline + * paddend += uint32(NewRelocEntry.r_addend); + NewRelocEntry.r_addend = 0; + } + + // Save 32-bit relocation record Elf32_Rel, not Elf32_Rela + if (NewRelocEntry.r_addend) err.submit(9000); + NewSections[newsecr].Push(&NewRelocEntry, sizeof(Elf32_Rel)); + } + else { + // 64 bit + /* + if (*paddend != 0) { + // Use explicit addend in 64 bit ELF (SHT_RELA) + // Explicit addend may cause link error if it appears to point outside section + NewRelocEntry.r_addend += *paddend; + *paddend = 0; + }*/ + + // Save 64-bit relocation record. Must be Elf64_Rela + NewSections[newsecr].Push(&NewRelocEntry, sizeof(Elf64_Rela)); + } + } + } + } +} + + +template +void CCOF2ELF::MakeBinaryFile() { + // Convert subfunction: Make section headers and file header, + // and combine everything into a single memory buffer. + int32 newsec; // Section index + uint32 SecOffset; // Section offset in file + uint32 SecSize; // Section size in file + uint32 SectionHeaderOffset; // File offset to section headers + + // Set file type in ToFile + ToFile.SetFileType(FILETYPE_ELF); + + // Make space for file header in ToFile, but don't fill data into it yet + ToFile.Push(0, sizeof(TELF_Header)); + + // Loop through new section buffers + for (newsec = 0; newsec < NumSectionsNew; newsec++) { + + // Size of section + SecSize = NewSections[newsec].GetDataSize(); + + // Put section into ToFile + SecOffset = ToFile.Push(NewSections[newsec].Buf(), SecSize); + + // Put size and offset into section header + NewSectionHeaders[newsec].sh_offset = SecOffset; + NewSectionHeaders[newsec].sh_size = SecSize; + + // Align before next entry + ToFile.Align(16); + } + + // Start offset of section headers + SectionHeaderOffset = ToFile.GetDataSize(); + + // Loop through new section headers + for (newsec = 0; newsec < NumSectionsNew; newsec++) { + + // Put section header into ToFile + ToFile.Push(&NewSectionHeaders[newsec], sizeof(TELF_SectionHeader)); + } + + // Make file header + TELF_Header FileHeader; + memset(&FileHeader, 0, sizeof(FileHeader)); // Initialize to 0 + + // Put file type magic number in + strcpy((char*)(FileHeader.e_ident), ELFMAG); + // File class + FileHeader.e_ident[EI_CLASS] = (WordSize == 32) ? ELFCLASS32 : ELFCLASS64; + // Data Endian-ness + FileHeader.e_ident[EI_DATA] = ELFDATA2LSB; + // ELF version + FileHeader.e_ident[EI_VERSION] = EV_CURRENT; + // ABI + FileHeader.e_ident[EI_OSABI] = ELFOSABI_SYSV; + // ABI version + FileHeader.e_ident[EI_ABIVERSION] = 0; + // File type + FileHeader.e_type = ET_REL; + // Machine architecture + FileHeader.e_machine = (WordSize == 32) ? EM_386 : EM_X86_64; + // Version + FileHeader.e_version = EV_CURRENT; + // Flags + FileHeader.e_flags = 0; + + // Section header table offset + FileHeader.e_shoff = SectionHeaderOffset; + + // File header size + FileHeader.e_ehsize = sizeof(TELF_Header); + + // Section header size + FileHeader.e_shentsize = sizeof(TELF_SectionHeader); + + // Number of section headers + FileHeader.e_shnum = (uint16)NumSectionsNew; + + // Section header string table index + FileHeader.e_shstrndx = (uint16)shstrtab; + + // Put file header into beginning of ToFile where we made space for it + memcpy(ToFile.Buf(), &FileHeader, sizeof(FileHeader)); +} + + +// Make template instances for 32 and 64 bits +template class CCOF2ELF; +template class CCOF2ELF; diff --git a/programs/develop/objconv/cof2omf.cpp b/programs/develop/objconv/cof2omf.cpp new file mode 100644 index 0000000000..2e49e0a896 --- /dev/null +++ b/programs/develop/objconv/cof2omf.cpp @@ -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 +} diff --git a/programs/develop/objconv/coff.cpp b/programs/develop/objconv/coff.cpp new file mode 100644 index 0000000000..adb3b1f5fd --- /dev/null +++ b/programs/develop/objconv/coff.cpp @@ -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(0) & 0xFFF9) == 0x5A49) { + // File has DOS stub + uint32 Signature = Get(0x3C); + if (Signature + 8 < DataSize && Get(Signature) == 0x4550) { + // Executable PE file + FileHeaderOffset = Signature + 4; + } + else { + err.submit(9000); + return; + } + } + // Find file header + FileHeader = &Get(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(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(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(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 * 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(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(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(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(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(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(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(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(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(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)); + } +} diff --git a/programs/develop/objconv/coff.h b/programs/develop/objconv/coff.h new file mode 100644 index 0000000000..8b6c635aa7 --- /dev/null +++ b/programs/develop/objconv/coff.h @@ -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 diff --git a/programs/develop/objconv/containers.cpp b/programs/develop/objconv/containers.cpp new file mode 100644 index 0000000000..1ef0ada669 --- /dev/null +++ b/programs/develop/objconv/containers.cpp @@ -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(),"!",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(0).e_type != ET_REL; + switch (Buf()[EI_CLASS]) { + case ELFCLASS32: + WordSize = 32; break; + case ELFCLASS64: + WordSize = 64; break; + } + } + else if (Get(0) == MAC_MAGIC_32) { + // Mach-O 32 little endian + FileType = FILETYPE_MACHO_LE; + WordSize = 32; + Executable = Get(0).filetype != MAC_OBJECT; + } + else if (Get(0) == MAC_MAGIC_64) { + // Mach-O 64 little endian + FileType = FILETYPE_MACHO_LE; + WordSize = 64; + Executable = Get(0).filetype != MAC_OBJECT; + } + else if (Get(0) == MAC_CIGAM_32) { + // Mach-O 32 big endian + FileType = FILETYPE_MACHO_BE; + WordSize = 32; + } + else if (Get(0) == MAC_CIGAM_64) { + // Mach-O 64 big endian + FileType = FILETYPE_MACHO_BE; + WordSize = 64; + } + else if (Get(0) == MAC_CIGAM_UNIV) { + // MacIntosh universal binary + FileType = FILETYPE_MAC_UNIVBIN; + WordSize = 0; + } + else if (Get(0) == 0xFFFF0000 || Get(0) == 0x10000) { + // Windows subtypes: + if (Get(4) == 0) { + // This type only occurs when attempting to extract a member from an import library + FileType = IMPORT_LIBRARY_MEMBER; + } + else if (Get(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(6) == PE_MACHINE_I386) { + WordSize = 32; + } + else if (Get(6) == PE_MACHINE_X8664) { + WordSize = 64; + } + else { + WordSize = 0; + } + } + else if (Get(0) == PE_MACHINE_I386) { + // COFF/PE 32 + FileType = FILETYPE_COFF; + WordSize = 32; + Executable = (Get(0).Flags & PE_F_EXEC) != 0; + } + else if (Get(0) == PE_MACHINE_X8664) { + // COFF64/PE32+ + FileType = FILETYPE_COFF; + WordSize = 64; + Executable = (Get(0).Flags & PE_F_EXEC) != 0; + } + else if (Get(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(0) == OMF_LIBHEAD) { + // OMF Library 16 or 32 + FileType = FILETYPE_OMFLIBRARY; + } + else if ((Get(0) & 0xFFF9) == 0x5A49) { + // DOS file or file with DOS stub + FileType = FILETYPE_DOS; + WordSize = 16; + Executable = 1; + uint32 Signature = Get(0x3C); + if (Signature + 8 < DataSize) { + if (Get(Signature) == 0x454E) { + // Windows 3.x file + FileType = FILETYPE_WIN3X; + } + else if (Get(Signature) == 0x4550) { + // COFF file + uint16 MachineType = Get(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(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(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(Index++); // Get first byte of record = type + RecordLength = Get(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(Index++); // Get segment attributes + if (SegAttr.u.A == 0) { + // Frame and Offset only included if A = 0 + Index += 2+1; + } + SegLength = (RecordType & 1) ? Get(Index) : Get(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); +} diff --git a/programs/develop/objconv/containers.h b/programs/develop/objconv/containers.h new file mode 100644 index 0000000000..afcbdd22ff --- /dev/null +++ b/programs/develop/objconv/containers.h @@ -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(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 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 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 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 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 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 list; // Make list +// S1 a; a.Index = 5; // Make record +// list.PushUnique(a); // Put record into list + +template +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 diff --git a/programs/develop/objconv/converters.h b/programs/develop/objconv/converters.h new file mode 100644 index 0000000000..e200180294 --- /dev/null +++ b/programs/develop/objconv/converters.h @@ -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 * 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 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 CELF : public CFileBuffer { +public: + CELF(); // Default constructor + void ParseFile(); // Parse file buffer + void Dump(int options); // Dump file + void PublicNames(CMemoryBuffer * Strings, CSList * 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 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 * Index, int m); // Make list of public names +protected: + uint32 NumRecords; // Number of records + CSList Records; // Record pointers (List is 0-based) + CMemoryBuffer NameBuffer; // Store segment names and symbol names + CSList LocalNameOffset; // Offset into NameBuffer of segment names by name index + CSList SegmentNameOffset; // Offset into NameBuffer of segment names by segment index + CSList SymbolNameOffset; // Offset into NameBuffer of external symbol names + CSList 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 CMACHO : public CFileBuffer { +public: + CMACHO(); // Default constructor + void ParseFile(); // Parse file buffer + void Dump(int options); // Dump file + void PublicNames(CMemoryBuffer * Strings, CSList * 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 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 NewSections; // Buffers for building each section + CArrayBuf NewSectionHeaders;// Buffer for temporary section headers + CArrayBuf NewSectIndex; // Buffers for array of new section indices + CArrayBuf 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 SectionBuffer; // Summarize old sections. Translate section index to segment index + CArrayBuf SymbolBuffer; // Translate old symbol index to new public/external index + CSList 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 NewSymbolTable; // New symbol table entries + CSList 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 SegmentTranslation; // Translate old segment number to new symbol table index + CSList ExtdefTranslation; // Translate old external symbol number to new symbol table index + CSList 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 CELF2COF : public CELF { +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 NewSectIndex; // Array of new section indices + CArrayBuf SymbolsUsed; // Array of new symbol indices + CSList 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 CELF2MAC : public CELF { +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 NewSectIndex; // Array of new section indices + CArrayBuf NewSectOffset; // Array of new section offsets + CArrayBuf OldSymbolScope; // Table of symbol bindings: 0 = local, 1 = public, 2 = external + CArrayBuf OldSymbolUsed; // Check if symbol is used + MacSymbolTableBuilder 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 CMAC2ELF : public CMACHO { +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 NewSections; // Buffers for building each section + CArrayBuf NewSectionHeaders;// Array of temporary section headers + CArrayBuf NewSectIndex; // Array of new section indices + CArrayBuf NewSymbolIndex; // Array of new symbol indices + CArrayBuf SectionSymbols; // Array of new symbol indices for sections + CFileBuffer ToFile; // File buffer for ELF file + CSList 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 CELF2ELF : public CELF { +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 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 CMAC2MAC : public CMACHO { +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 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 CELF2ASM : public CELF { +public: + CELF2ASM(); // Constructor + void Convert(); // Do the conversion +protected: + CDisassembler Disasm; // Disassembler + CArrayBufSectionNumberTranslate; // Translate section numbers in source file to section numbers in asm file + CArrayBufSymbolTableOffset; // 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 CMAC2ASM : public CMACHO { +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 RelocationQueue; // List of relocation tables + CSList 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 Segments; // Name, size, etc. of all segments + CSList ExtdefTranslation; // Translate old external symbol number to disasm symbol table index + CSList 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 diff --git a/programs/develop/objconv/disasm.h b/programs/develop/objconv/disasm.h new file mode 100644 index 0000000000..ce274f0dcb --- /dev/null +++ b/programs/develop/objconv/disasm.h @@ -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 List; // List of symbols, sorted by address + CMemoryBuffer SymbolNameBuffer; // String buffer for names of symbols + CSList 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 Sections; // List of sections. First is 0 + CSList Relocations; // List of cross references. First is 0 + CMemoryBuffer NameBuffer; // String buffer for names of sections. First is 0. + CSList 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 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 diff --git a/programs/develop/objconv/disasm1.cpp b/programs/develop/objconv/disasm1.cpp new file mode 100644 index 0000000000..05b1ae62f5 --- /dev/null +++ b/programs/develop/objconv/disasm1.cpp @@ -0,0 +1,4697 @@ +/**************************** disasm1.cpp ******************************** +* Author: Agner Fog +* Date created: 2007-02-25 +* Last modified: 2016-11-09 +* Project: objconv +* Module: disasm1.cpp +* Description: +* Module for disassembler. +* +* Most of the disassembler code is in this file. +* Instruction tables are in opcodes.cpp. +* All functions relating to file output are in disasm2.cpp +* +* Copyright 2007-2016 GNU General Public License http://www.gnu.org/licenses +*****************************************************************************/ +#include "stdafx.h" + + +/************************** class CSymbolTable ***************************** + +class CSymbolTable is a container class for a sorted list of symbols. The list +of symbols is kept sorted by address at all times. Named symbols from the +original file are added to the list with AddSymbol(). New symbols for jump +targets and code blocks that do not have a name are added during pass 1 by +NewSymbol(). AssignNames() assigns names to these unnamed symbols. + +A symbol in the list can be found in three different ways: By its address, +by its old index, and by its new index. The new index is monotonous, so that +consecutive new indices correspond to consecutive addresses. Unfortunately, +the new index of a symbol will change whenever another symbol with a lower +address is added to the list. Therefore, we need to use the old index rather +than the new index for identifying a symbol, e.g. in the relocation table. +The old index is a permanent, unique identifier, but in random order. +The old index of a symbol is usually the same as the index used in the +original file and in the relocation table. New symbols added during pass 1 +will get assigned an old index which is higher than the highest value that +occurred in the original file. Do not make a pointer or reference to a symbol. +It may become invalid when new symbols are added. + +To access a symbol by its old index, you have to translate it with Old2NewIndex +To access a symbol by its new index, use operator []. +To find a symbol by its address, use FindByAddress(). + +******************************************************************************/ + +CSymbolTable::CSymbolTable() { + // Constructor + OldNum = 1; + NewNum = 0; // Initialize + UnnamedNum = 0; // Number of unnamed symbols + UnnamedSymFormat = 0; // Format string for giving names to unnamed symbols + UnnamedSymbolsPrefix = cmd.SubType == SUBTYPE_GASM ? "$_" : "?_";// Prefix to add to unnamed symbols + ImportTablePrefix = "imp_"; // Prefix for pointers in import table + + // Make dummy symbol number 0 + SASymbol sym0; + sym0.Reset(); + sym0.Section = 0x80000000; // Lowest possible address + List.PushSort(sym0); // Put into Symbols list + + SymbolNameBuffer.Push(0, 1); // Make string 0 empty +} + +uint32 CSymbolTable::AddSymbol(int32 Section, uint32 Offset, uint32 Size, +uint32 Type, uint32 Scope, uint32 OldIndex, const char * Name, const char * DLLName) { + // Add symbol from original file to symbol table. + // If name is not known then set Name = 0. A name will then be assigned + // OldIndex is the identifier used in relocation records. If the symbol is known + // by address rather than by index, then set OldIndex = 0. The return value will + // be the assigned value of OldIndex to use in relocation records. The returned value + // of OldIndex will be equal to the OldIndex of any previous symbols with same address. + + // Symbol record + SASymbol NewSym; // New symbol table entry + + NewSym.Section = Section; + NewSym.Offset = Offset; + NewSym.Size = Size; + NewSym.Type = Type; + NewSym.Scope = Scope; + NewSym.OldIndex = OldIndex; + + // Store symbol name in NameBuffer + if (Name && *Name) { + NewSym.Name = SymbolNameBuffer.GetDataSize(); + if (DLLName) { + // Imported from DLL. Prefix name with "imp_" + SymbolNameBuffer.Push(ImportTablePrefix, (uint32)strlen(ImportTablePrefix)); + } + // Store name + SymbolNameBuffer.PushString(Name); + } + else { + NewSym.Name = 0; // Will get a name later + } + // Store DLL name in NameBuffer + if (DLLName && *DLLName) { + NewSym.DLLName = SymbolNameBuffer.PushString(DLLName); + } + else { + NewSym.DLLName = 0; + } + + if (OldIndex == 0) { + // Make non-unique entry + uint32 NewIndex = NewSymbol(NewSym); + // Get old index + OldIndex = List[NewIndex].OldIndex; + } + else { + // Make unique entry + List.PushSort(NewSym); + } + + // Set OldNum to 1 + maximum OldIndex + if (OldIndex >= OldNum) OldNum = OldIndex + 1; + + return OldIndex; +} + +uint32 CSymbolTable::NewSymbol(SASymbol & sym) { + // Add symbol to symbol table. + // Will not add a new symbol if one already exists at this address and + // either the new symbol or the existing symbol has no name. + // The return value is the new index to a new or existing symbol. + // The type or scope of any existing symbol will be modified if + // the type or scope of the new symbol is higher. + // The name will be applied to the existing symbol if the existing symbol + // has no name. + + // Find new index of any existing symbol with same address + int32 SIndex = FindByAddress(sym.Section, sym.Offset); + + if (SIndex > 0 && !(List[SIndex].Type & 0x80000000) + && !(sym.Name && List[SIndex].Name)) { + // Existing symbol found. Update it with type and scope + + // Choose between Type of existing symbol and new Type information. + // The highest Type value takes precedence, except near indirect jump/call, + // which has highest precedence + if (((sym.Type & 0xFF) > (List[SIndex].Type & 0xFF) + && ((List[SIndex].Type+1) & 0xFE) != 0x0C) || ((sym.Type+1) & 0xFE) == 0x0C) { + // New symbol has higher type + List[SIndex].Type = sym.Type; + } + if ((sym.Scope & 0xFF) > (List[SIndex].Scope & 0xFF)) { + // New symbol has higher Scope + List[SIndex].Scope = sym.Scope; + } + if (sym.Name && !List[SIndex].Name) { + // New symbol has name, old symbol has no name + List[SIndex].Name = sym.Name; + } + } + else { + // No existing symbol. Make new one + // Give it an old index + if (sym.OldIndex == 0) sym.OldIndex = OldNum++; + + SIndex = List.PushSort(sym); + } + + // Return new index + return SIndex; +} + + +uint32 CSymbolTable::NewSymbol(int32 Section, uint32 Offset, uint32 Scope) { + // Add symbol to jump target or code block that doesn't have a name. + // Will not add a new symbol if one already exists at this address. + // The return value is the new index to a new or existing symbol. + // The symbol will get a name later. + + // Symbol record + SASymbol NewSym; // New symbol table entry + NewSym.Reset(); + + NewSym.Section = Section; + NewSym.Offset = Offset; + NewSym.Scope = Scope; + + // Store new symbol record if no symbol with this address already exists + return NewSymbol(NewSym); +} + +void CSymbolTable::AssignNames() { + // Assign names to symbols that do not have a name + + uint32 i; // New symbol index + uint32 NumDigits; // Number of digits in new symbol names + char name[64]; // Buffer for making symbol name + static char Format[64]; + + // Find necessary number of digits + NumDigits = 3; i = NewNum; + while (i >= 1000) { + i /= 10; + NumDigits++; + } + + // Format string for symbol names + sprintf(Format, "%s%c0%i%c", UnnamedSymbolsPrefix, '%', NumDigits, 'i'); + UnnamedSymFormat = Format; + + // Update TranslateOldIndex + UpdateIndex(); + + // Loop through symbols + for (i = 1; i < List.GetNumEntries(); i++) { + if (List[i].Name == 0 && List[i].Scope != 0) { + // Symbol has no name. Make one + sprintf(name, UnnamedSymFormat, ++UnnamedNum); + // Store new name + List[i].Name = SymbolNameBuffer.PushString(name); + } + } + // Round up the value of UnnamedNum in case more names are assigned later + if (NewNum < 1000) { + UnnamedNum = (UnnamedNum + 199) / 100 * 100; + } + else { + UnnamedNum = (UnnamedNum + 1999) / 1000 * 1000; + } + +#if 0 // + // For debugging: list all symbols + printf("\n\nSymbols:"); + for (i = 0; i < List.GetNumEntries(); i++) { + + // if (List[i].Offset > 0x0 && List[i].Offset < 0x8) + + printf("\n%3X %3X %s Sect %i Offset %X Type %X Size %i Scope %i", + i, List[i].OldIndex, GetName(i), + List[i].Section, List[i].Offset, List[i].Type, List[i].Size, List[i].Scope); + } +#endif +} + +uint32 CSymbolTable::FindByAddress(int32 Section, uint32 Offset, uint32 * Last, uint32 * NextAfter) { + // Find symbols by address + // The return value will be the new index to the first symbol at the + // specified address. The return value will be zero if no symbol found. + // If more than one symbol is found with the same address then Last + // will receive the new index of the last symbol with this address. + // NextAfter will receive the new index of the first symbol with an + // address higher than the specified address in the same section, or + // zero if none. + + uint32 i1; // New index of first symbol + uint32 i2; // New index of last symbol + uint32 i3; // New index of first symbol after address + + // Make dummy symbol record for searching + SASymbol sym; + sym.Section = Section; + sym.Offset = Offset; + + // Search List by address + i1 = List.FindFirst(sym); + + if (i1 == 0 || i1 >= List.GetNumEntries()) { + // No symbol found at this address or later. Return 0 + if (NextAfter) *NextAfter = 0; + return 0; + } + if (sym < List[i1]) { + // No symbol found at this address, but one found at higher address + // Check if same section + if (List[i1].Section != Section) i1 = 0; + // Return symbol at later address + if (NextAfter) *NextAfter = i1; + return 0; + } + + // A symbol was found at this address. + // Search for more symbols at same address + i2 = i1; + while (i2+1 < List.GetNumEntries() && !(sym < List[i2+1])) i2++; + + // Search for first symbol after this address in same section + if (i2+1 < List.GetNumEntries() && List[i2+1].Section == Section) { + i3 = i2 + 1; // Found + } + else { + i3 = 0; // Not found + } + + // Return last symbol at same address + if (Last) *Last = i2; + + // Return first symbol at higher address + if (NextAfter) *NextAfter = i3; + + // Return first symbol at address + return i1; +} + +uint32 CSymbolTable::FindByAddress(int32 Section, uint32 Offset) { + // Find symbols by address + // The return value will be the new index to a first symbol at the + // specified address. If more than one symbol is found at the same + // address then the one with the highest scope (and which is not + // a section record) is returned; + uint32 s0, s1, s2 = 0; + uint32 MaxScope = 0; + // Find all symbols at this address + s0 = s1 = FindByAddress(Section, Offset, &s2); + // Check if any symbols found + if (s0 == 0) return 0; + + // Loop through symbols at this address + for (; s1 <= s2; s1++) { + // Look for highest scope (and not section) + if ((*this)[s1].Scope >= MaxScope && !((*this)[s1].Type & 0x80000000)) { + s0 = s1; MaxScope = (*this)[s1].Scope; + } + } + // Return index to symbol with highest scope + return s0; +} + +uint32 CSymbolTable::Old2NewIndex(uint32 OldIndex) { + // Translate old symbol index to new symbol index + + // Check if TranslateOldIndex is up to date + if (NewNum != List.GetNumEntries()) { + // New entries have been added since last update. Update TranslateOldIndex + UpdateIndex(); + } + // Check if valid + if (OldIndex >= OldNum) OldIndex = 0; + + // Translate old index to new index + uint32 NewIndex = TranslateOldIndex[OldIndex]; + + // Check limit + if (NewIndex >= NewNum) NewIndex = 0; + + // Return new index + return NewIndex; +} + +const char * CSymbolTable::HasName(uint32 symo) { + // Ask if symbol has a name, input = old index, output = name or 0 + // Returns 0 if symbol has no name yet. + // Use HasName rather than GetName or GetNameO during pass 1 to avoid + // naming symbols in random order. + + // Get new index + uint32 symi = Old2NewIndex(symo); + // Check if valid + if (symi == 0 || symi >= NewNum) return 0; + // Check if symbol has a name + if ((*this)[symi].Name == 0) return 0; + // Symbol has a name + return GetName(symi); +} + +const char * CSymbolTable::GetName(uint32 symi) { + // Get symbol name from new index. + // A name will be assigned to the symbol if it doesn't have one + + // Get name index from symbol record + uint32 NameIndex = (*this)[symi].Name; + if (NameIndex == 0) { + // Symbol has no name + // Search for other symbol with same address + uint32 Alias = FindByAddress((*this)[symi].Section,(*this)[symi].Offset); + if ((*this)[Alias].Name) { + // A named symbol with same address found + NameIndex = (*this)[Alias].Name; + } + else { + // Give symbol a name + // This should occur only if new symbols are made during pass 2 + char name[64]; // Buffer for making symbol name + sprintf(name, "Unnamed_%X_%X", (*this)[symi].Section, (*this)[symi].Offset); + // sprintf(name, UnnamedSymFormat, ++UnnamedNum); + // Store new name + NameIndex = (*this)[symi].Name = SymbolNameBuffer.PushString(name); + } + } + // Check if valid + if (NameIndex == 0 || NameIndex >= SymbolNameBuffer.GetDataSize()) { + // NameIndex is invalid + return "ErrorNoName"; + } + // Return name + return SymbolNameBuffer.Buf() + NameIndex; +} + +const char * CSymbolTable::GetNameO(uint32 symo) { + // Get symbol name by old index. + // A name will be assigned to the symbol if it doesn't have one + return GetName(Old2NewIndex(symo)); +} + +const char * CSymbolTable::GetDLLName(uint32 symi) { + // Get import DLL name from old index + if ((*this)[symi].DLLName == 0) { + // No name + return "ErrorNoName"; + } + // Get name DLL index from symbol record + uint32 NameIndex = (*this)[symi].DLLName; + // Check if valid + if (NameIndex == 0 || NameIndex >= SymbolNameBuffer.GetDataSize()) { + // NameIndex is invalid + return "ErrorNoName"; + } + // Return name + return SymbolNameBuffer.Buf() + NameIndex; +} + +void CSymbolTable::AssignName(uint32 symi, const char *name) { + // Give symbol a specific name + (*this)[symi].Name = SymbolNameBuffer.PushString(name); +} + +void CSymbolTable::UpdateIndex() { + // Update TranslateOldIndex + uint32 i; // New index + + // Allocate array with sufficient size + TranslateOldIndex.SetNum(OldNum); + + // Initialize to zeroes + memset(&TranslateOldIndex[0], 0, TranslateOldIndex.GetNumEntries() * sizeof(uint32)); + + for (i = 0; i < List.GetNumEntries(); i++) { + if (List[i].OldIndex < OldNum) { + TranslateOldIndex[List[i].OldIndex] = i; + } + else { + // symbol index out of range + err.submit(2031); // Report error + List[i].OldIndex = 0; // Reset index that was out of range + } + } + NewNum = List.GetNumEntries(); +} + + +/************************** class CDisassembler ***************************** +Members of class CDisassembler +Members that relate to file output are in disasm2.cpp +******************************************************************************/ + +CDisassembler::CDisassembler() { + // Constructor + Sections.PushZero(); // Make first section entry zero + Relocations.PushZero(); // Make first relocation entry zero + NameBuffer.Push(0, 1); // Make first string entry zero + FunctionList.PushZero(); // Make first function entry zero + // Initialize variables + Buffer = 0; + InstructionSetMax = InstructionSetAMDMAX = 0; + InstructionSetOR = FlagPrevious = NamesChanged = 0; + WordSize = MasmOptions = RelocationsInSource = ExeType = 0; + ImageBase = 0; + Syntax = cmd.SubType; // Assembly syntax dialect + if (Syntax == SUBTYPE_GASM) { + CommentSeparator = "# "; // Symbol for indicating comment + HereOperator = "."; // Symbol for current address + } + else { + CommentSeparator = "; "; // Symbol for indicating comment + HereOperator = "$"; // Symbol for current address + } +}; + +void CDisassembler::Init(uint32 ExeType, int64 ImageBase) { + // Define file type and imagebase if executable file + this->ExeType = ExeType; + this->ImageBase = ImageBase; +} + +void CDisassembler::AddSection( +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 to be added to offset in listing +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) { // Length of name if not zero terminated + + // Check values + if (Buffer == 0) Type = 3; + if (Name == 0) Name = "?"; + if (NameLength == 0) NameLength = (uint32)strlen(Name); + if (TotalSize < InitSize) TotalSize = InitSize; + + // Define section to be disassembled + SASection SecRec; // New section record + + SecRec.Start = Buffer; + SecRec.SectionAddress = SectionAddress; + SecRec.InitSize = InitSize; + SecRec.TotalSize = TotalSize; + SecRec.Type = Type; + SecRec.Align = Align; + SecRec.WordSize = WordSize; + // Save name in NameBuffer + SecRec.Name = NameBuffer.Push(Name, NameLength); + // Terminate with zero + NameBuffer.Push(0, 1); + // Default group is 'flat' except in 16 bit mode + if (WordSize == 16 || (MasmOptions & 0x100)) { + // 16-bit or mixed segment size. Group is unknown + SecRec.Group = 0; + } + else { + // Pure 32 or 64 bit mode. Group = flat + SecRec.Group = ASM_SEGMENT_FLAT; + } + + // Save section record + Sections.Push(SecRec); + + // Remember WordSize + switch (WordSize) { + case 16: + MasmOptions |= 0x100; break; + case 32: + MasmOptions |= 0x200; break; + case 64: + MasmOptions |= 0x400; break; + } +} + +int32 CDisassembler::AddSectionGroup(const char * Name, int32 MemberSegment) { + // Define section group (from OMF file). + // Must be called after all segments have been defined. + // To define a group with multiple members, you must call AddSectionGroup + // multiple times. You must finish adding members to one group before + // starting the definition of another group. + // You can define a group without defining its members by calling + // AddSectionGroup with MemberSegment = 0. + + // Check values + if (Name == 0) Name = "?"; + + // Find preceding segment or group definition + int32 LastIndex = Sections.GetNumEntries() - 1; + // Index of group record + int32 GroupIndex = LastIndex; + + const char * LastName = "?"; + if (Sections[LastIndex].Name < NameBuffer.GetDataSize()) { + // Last name valid + LastName = NameBuffer.Buf() + Sections[LastIndex].Name; + } + // Check if group name already defined + if (strcmp(Name, LastName) != 0) { + // Not define. Make group record in Sections list + SASection SecRec; // New section record + memset(&SecRec, 0, sizeof(SecRec)); // Initialize + + // Set type = group + SecRec.Type = 0x800; + + // Save name in NameBuffer + SecRec.Name = NameBuffer.PushString(Name); + + // Save group index = my own index + SecRec.Group = ++GroupIndex; + + // Save section record + Sections.Push(SecRec); + } + // Find MemberSegment record + if (MemberSegment && MemberSegment < GroupIndex) { + // Register group index in segment record + Sections[MemberSegment].Group = GroupIndex; + } + // Return value is group index + return GroupIndex; +} + +uint32 CDisassembler::AddSymbol( +int32 Section, // Section number (1-based). ASM_SEGMENT_UNKNOWN = external, ASM_SEGMENT_ABSOLUTE = absolute, ASM_SEGMENT_IMGREL = image-relative +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. +const char * Name, // Name of symbol. Zero-terminated +const char * DLLName) { // Name of DLL if imported dynamically + + // Add symbol form original file. + // Multiple symbols at same address are allowed. + // If section is not known then set Section = ASM_SEGMENT_IMGREL and Offset = image-relative address + // If name is not known then set Name = 0. A name will then be assigned + // OldIndex is the identifier used in relocation records. It must be nonzero. + // If the original file uses 0-based symbol indices then add 1 to OldIndex + // and remember to also add 1 when referring to the symbol in a relocation record. + // If the symbol is known by address rather than by index, then set OldIndex = 0. + // The return value will be the assigned value of OldIndex to use in relocation records. + // The returned value of OldIndex will be equal to the OldIndex of any previous symbols + // with same address. All symbols that have an identifier (OldIndex) must be defined + // before any symbol identified by address only in order to avoid using the same OldIndex. + + // Check if image-relative + if (Section == ASM_SEGMENT_IMGREL) { + // Translate absolute virtual address to section and offset + TranslateAbsAddress(ImageBase + (int32)Offset, Section, Offset); + } + + // Define symbol for disassembler + return Symbols.AddSymbol(Section, Offset, Size, Type, Scope, OldIndex, Name, DLLName); +} + +void CDisassembler::AddRelocation( +int32 Section, // Section of relocation source +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, // Relocation type. See SARelocation in disasm.h for definition of values +uint32 Size, // 1 = byte, 2 = word, 4 = dword, 8 = qword +uint32 TargetIndex, // Symbol index of target +uint32 ReferenceIndex) { // Symbol index of reference point if Type = 8 or 0x10 + + // Check if image-relative + if (Section == ASM_SEGMENT_IMGREL) { + // Translate absolute virtual address to section and offset + if (!TranslateAbsAddress(ImageBase + (int32)Offset, Section, Offset)) { + err.submit(1304); + } + } + + if (Type != 0x41) { + // Define relocation or cross-reference for disassembler + SARelocation RelRec; // New relocation record + + RelRec.Section = Section; + RelRec.Offset = Offset; + RelRec.Type = Type; + RelRec.Size = Size; + RelRec.Addend = Addend; + RelRec.TargetOldIndex = TargetIndex; + RelRec.RefOldIndex = ReferenceIndex; + + // Save relocation record + Relocations.PushSort(RelRec); + } + else { + // Make entry in procedure linkage table + uint32 targetsym = Symbols.Old2NewIndex(TargetIndex); + if (targetsym && Symbols[targetsym].DLLName) { + // Put label on entry in procedure linkage table (import table) + // Copy Name and DLLName from target symbol + SASymbol ImportSym = Symbols[targetsym]; + ImportSym.Section = Section; + ImportSym.Offset = Offset; + ImportSym.Type = 0x0C; + ImportSym.OldIndex = 0; + ImportSym.Scope = 2; + Symbols.NewSymbol(ImportSym); + } + } +} + +void CDisassembler::Go() { + // Do the disassembly + + // Check for illegal entries in relocations table + InitialErrorCheck(); + + // Find missing relocation target addresses + FixRelocationTargetAddresses(); + + // Pass 1: Find symbols types and unnamed symbols + Pass = 1; + Pass1(); + Pass = 2; + Pass1(); + + if (Pass & 0x100) { + // Repetition of pass 1 requested + Pass = 3; + Pass1(); + Pass = 4; + Pass1(); + } + + // Put names on unnamed symbols + Symbols.AssignNames(); + + // Fix invalid characters in symbol and section names + CheckNamesValid(); + +#if 0 // + // Show function list. For debugging only + printf("\n\nFunctionList:"); + for (uint32 i = 0; i < FunctionList.GetNumEntries(); i++) { + printf("\nsect %i, start %X, end %X, scope %i, name %s", + FunctionList[i].Section, FunctionList[i].Start, FunctionList[i].End, + FunctionList[i].Scope, Symbols.GetNameO(FunctionList[i].OldSymbolIndex)); + } +#endif +#if 0 + // For debugging: list all relocations + printf("\n\nRelocations:"); + for (uint32 i = 0; i < Relocations.GetNumEntries(); i++) { + printf("\nsect %i, os %X, type %X, size %i, add %X, target %X", + Relocations[i].Section, Relocations[i].Offset, Relocations[i].Type, + Relocations[i].Size, Relocations[i].Addend, Relocations[i].TargetOldIndex); + } +#endif +#if 0 + // For debugging: list all sections + printf("\n\nSections:"); + for (uint32 s = 1; s < Sections.GetNumEntries(); s++) { + printf("\n%2i, %s", s, NameBuffer.Buf() + Sections[s].Name); + } +#endif + + // Begin writing output file + WriteFileBegin(); + + // Pass 2: Write all sections to output file + Pass = 0x10; + Pass2(); + + // Check for illegal entries in symbol table and relocations table + FinalErrorCheck(); + + // Finish writing output file + WriteFileEnd(); +}; + +void CDisassembler::Pass1() { + + /* Pass 1: does the following jobs: + -------------------------------- + + * Scans all code sections, instruction by instruction. Checks code syntax. + + * Tries to identify where each function begins and ends. + + * Follows all references to data in order to determine data type for + each data symbol. + + * Assigns symbol table entries for all jump and call targets that do not + allready have a name. + + * Follows all jump instructions to identify code blocks that are connected. + Code blocks in same section that are connected through jumps (not calls) + are joined together into the same function. + + * Identifies and analyzes tables of jump addresses and call addresses, + e.g. switch/case tables and virtual function tables. + + * Tries to identify any data in the code section. If erroneous code or + sequences of zeroes are found then the nearest preceding label is marked + as dubious and the analysis of code is skipped until the next code label. + Pass 1 will be repeated in this case in order to follow backwards jumps + from subsequent code. Dubious code will be shown as both code and data + in the output of pass 2. + */ + + // Loop through sections, pass 1 + for (Section = 1; Section < Sections.GetNumEntries(); Section++) { + + // Get section type + SectionType = Sections[Section].Type; + if (SectionType & 0x800) continue; // This is a group + + // Code or data + CodeMode = (SectionType & 1) ? 1 : 4; + LabelBegin = FlagPrevious = CountErrors = 0; + + if ((Sections[Section].Type & 0xFF) == 1) { + // This is a code section + + // Initialize code parser + Buffer = Sections[Section].Start; + SectionEnd = FunctionEnd = LabelInaccessible = Sections[Section].TotalSize; + WordSize = Sections[Section].WordSize; + SectionAddress = Sections[Section].SectionAddress; + if (Buffer == 0) continue; + + IBegin = IEnd = LabelEnd = 0; + IFunction = 0; + + // Loop through instructions + while (NextInstruction1()) { + + // check if function beings here + CheckForFunctionBegin(); + + // Find any label here + FindLabels(); + + // Check if code + if (CodeMode < 4) { + // This is code + + // Parse instruction + ParseInstruction(); + } + else { + // This is data. Skip to next label + IEnd = LabelEnd; + } + // check if function ends here + CheckForFunctionEnd(); + } + } + else { + // This is a data section + // Make a single entry in FunctionList covering the whole section + SFunctionRecord fun = {(int)Section, 0, Sections[Section].TotalSize, 0, 0}; + FunctionList.PushUnique(fun); + } + } +} + +void CDisassembler::FindLabels() { + // Find any labels at current position and next during pass 1 + uint32 sym1, sym2 = 0, sym3 = 0; // Symbol indices + + // Search for labels from IBegin + sym1 = Symbols.FindByAddress(Section, IBegin, &sym2, &sym3); + + if (sym1 && sym2) { + // Set LabelBegin to address of last label at current address + LabelBegin = Symbols[sym2].Offset; + CountErrors = 0; + + // Get code mode from label + if ((Symbols[sym2].Type & 0xF0) == 0x80) { + // This is known to be code + CodeMode = 1; + } + else if ((Symbols[sym2].Type & 0xFF) == 0) { + // Type is unknown + if ((Symbols[sym2].Scope & 4) && SectionType == 1) { + // Public label in code segment. Consider this code + CodeMode = 1; + } + // Otherwise: Assume same type as previous + } + else { + // This is known to be data + CodeMode = 4; + } + // Reset tracer + t.Reset(); + } + if (sym3) { + // Set LabelEnd to address of next symbol + LabelEnd = Symbols[sym3].Offset; + if (LabelEnd > SectionEnd) LabelEnd = SectionEnd; + } + else { + // No next label + LabelEnd = SectionEnd; + } +} + +void CDisassembler::CheckForMisplacedLabel() { + // Remove any label placed inside function + // This is called if there appears to be a function end inside an instruction + if (FunctionEnd && FunctionEnd < SectionEnd) { + FunctionEnd = IEnd; + FunctionList[IFunction].Scope |= 0x10000; + } + else { + s.Errors |= 0x10; + } +} + +int CDisassembler::NextLabel() { + // Loop through labels from IEnd. Pass 2 + uint32 sym, sym1, sym2 = 0, sym3 = 0; // Symbol indices + + // Make ready for next instruction + IBegin = IEnd; + + // Reset tracer + t.Reset(); + + // Check if end of function/section + if (IEnd >= FunctionEnd || IEnd >= SectionEnd) { + // No more labels in this function or section + return 0; + } + + // Search for labels from IEnd + sym1 = Symbols.FindByAddress(Section, IEnd, &sym2, &sym3); + + if (sym1) { + // Symbol found + for (sym = sym1; sym <= sym2; sym++) { + // Remember symbol address + LabelBegin = Symbols[sym].Offset; + CountErrors = 0; + + if ((SectionType & 0xFF) == 1) { + // Code section. Get CodeMode + if ((Symbols[sym].Type >> 24) & 0xF) { + // Get CodeMode from last label. 1 = code, 2 = dubiuos, 4 = data + CodeMode = (Symbols[sym].Type >> 24) & 0xF; + } + else if (Symbols[sym].Type & 0x80) { + // Type defined as jump/call. This is known to be code + CodeMode = 1; + } + else if (Symbols[sym].Type == 0) { + // Type is unknown. (Assume same type as previous) changed to: + // Type is unknown. Assume code + CodeMode = 1; + } + else { + // This has been accessed as data + CodeMode = 4; + } + } + else { + // This is a data segment + CodeMode = 4; + } + // Get symbol type and size, except for section type + if (!(Symbols[sym].Type & 0x80000000)) { + DataType = Symbols[sym].Type; + DataSize = GetDataItemSize(DataType); + if (((DataType+1) & 0xFE) == 0x0C && Symbols[sym].Size) { + // Jump table can have different sizes for direct or image relative + DataSize = Symbols[sym].Size; + } + } + } + } + if (sym3) { + // Next label found + LabelEnd = Symbols[sym3].Offset; + return 1; + } + // No new label found. Continue to FunctionEnd + LabelEnd = FunctionEnd; + return 1; +} + +int CDisassembler::NextFunction2() { + // Loop through function blocks in pass 2. Return 0 if finished + + SFunctionRecord Fun; // Dummy function record for search and compare + + if (IFunction == 0) { + // Begin of section. Find first function block + Fun.Section = Section; + Fun.Start = IBegin; + IFunction = FunctionList.FindFirst(Fun); + } + else { + // Try next function block + IFunction++; + } + // Check if IFunction is valid + if (IFunction == 0 || IFunction >= FunctionList.GetNumEntries()) { + // Not valid + IFunction = 0; + return 0; + } + // Check if IFunction is within current section + Fun.Section = Section; + Fun.Start = SectionEnd; + if (Fun < FunctionList[IFunction]) { + // Past end of current section + IFunction = 0; + return 0; + } + // IFunction is within current section + // End of function + FunctionEnd = FunctionList[IFunction].End; + + // Check if function has a defined size + if (FunctionEnd <= FunctionList[IFunction].Start) { + // Size unknown. Continue until begin of next function + if (IFunction+1 < FunctionList.GetNumEntries() + && FunctionList[IFunction+1] < Fun + && FunctionList[IFunction] < FunctionList[IFunction+1]) { + FunctionEnd = FunctionList[IFunction+1].Start; + } + else { + // No next function. Continue until end of section + FunctionEnd = SectionEnd; + } + } + + // return IFunction for success + return 1; +} + +void CDisassembler::CheckForFunctionBegin() { + // Check if function begins at current position + uint32 sym1, sym2 = 0, sym3 = 0; // Symbol indices + SFunctionRecord fun; // New function record + IBegin = IEnd; + + if (IFunction == 0) { + // No function defined. Begin new function here + + // Search for nearest labels + sym1 = Symbols.FindByAddress(Section, IEnd, &sym2, &sym3); + + if (sym1 == 0) { + // There is no label here. Make one with Scope = 0 + sym1 = Symbols.NewSymbol(Section, IEnd, 0); + // Update labels + LabelBegin = LabelEnd = CountErrors = 0; + FindLabels(); + } + // Check that sym1 is valid + if (sym1 == 0 || sym1 >= Symbols.GetNumEntries()) { + err.submit(9000); return; + } + + // Make function record for FunctionList + fun.Section = Section; + fun.Start = IBegin; + fun.End = IBegin; + fun.Scope = Symbols[sym1].Scope; + fun.OldSymbolIndex = Symbols[sym1].OldIndex; + + // Add to function list + IFunction = FunctionList.PushUnique(fun); + + // End of function not known yet + FunctionEnd = SectionEnd; LabelEnd = 0; + } +} + +void CDisassembler::CheckForFunctionEnd() { + // Check if function ends at current position + if (IFunction >= FunctionList.GetNumEntries()) { + // Should not occur + err.submit(9000); IFunction = 0; return; + } + + // Function ends if section ends here + if (IEnd >= SectionEnd) { + // Current function must end because section ends here + FunctionList[IFunction].End = SectionEnd; + FunctionList[IFunction].Scope &= ~0x10000; + IFunction = 0; + + // Check if return instruction + if (s.OpcodeDef && !(s.OpcodeDef->Options & 0x10) && (Pass & 0x10)) { + // No return or unconditional jump. Write error message + s.Errors |= 0x10000; + WriteErrorsAndWarnings(); + } + return; + } + + // Function ends after ret or unconditional jump and preceding code had no + // jumps beyond this position: + if (s.OpcodeDef && s.OpcodeDef->Options & 0x10) { + // A return or unconditional jump instruction was found. + FlagPrevious |= 2; + + // Mark this position as inaccessible if there is no reference to this place + Symbols.NewSymbol(Section, IEnd, 0); + // Update labels + LabelBegin = LabelEnd = CountErrors = 0; + FindLabels(); + + if (IEnd >= FunctionList[IFunction].End) { + // Indicate current function ends here + FunctionList[IFunction].End = IEnd; + FunctionList[IFunction].Scope &= ~0x10000; + IFunction = 0; + return; + } + } + + // Function ends at next label if preceding label is inaccessible and later end not known + if (IFunction && FunctionList[IFunction].Scope == 0 && IEnd >= FunctionList[IFunction].End) { + if (Symbols.FindByAddress(Section, IEnd)) { + // Previous label was inaccessible. There is a new label here. Begin new function here + IFunction = 0; + return; + } + } + + // Function does not end here + return; +} + + +void CDisassembler::CheckRelocationTarget(uint32 IRel, uint32 TargetType, uint32 TargetSize) { + // Update relocation record and its target. + // This function updates the symbol type and size of a relocation target. + // If the relocation target is a section:offset address then a new + // symbol record is made + uint32 SymOldI; // Old index of target symbol + uint32 SymNewI; // New index of target symbol + int32 TargetSection; // Section of target symbol + uint32 TargetOffset; // Offset of target symbol + + // Check if relocation valid + if (!IRel || IRel >= Relocations.GetNumEntries() || !Relocations[IRel].TargetOldIndex + || Relocations[IRel].Section <= 0 || uint32(Relocations[IRel].Section) >= Sections.GetNumEntries()) { + return; + } + + // Find target symbol + SymOldI = Relocations[IRel].TargetOldIndex; + + // Look up in symbol table + SymNewI = Symbols.Old2NewIndex(SymOldI); + + // Check if valid + if (!Symbols[SymNewI].OldIndex) return; + + if (Symbols[SymNewI].Type & 0x80000000) { + // Symbol is a section record. Relocation refers to a section-relative address + // Make a new symbol for this data item. The symbol will get a name later + + // Get address of new symbol + TargetSection = Symbols[SymNewI].Section; + TargetOffset = Symbols[SymNewI].Offset + Relocations[IRel].Addend; + + // Pointer to relocation source address + uint8 * RelSource = Sections[Relocations[IRel].Section].Start + Relocations[IRel].Offset; + + // Inline Addend; + int32 InlineA = 0; + switch (Relocations[IRel].Size) { + case 1: + InlineA = *(int8*)RelSource; break; + case 2: + InlineA = *(int16*)RelSource; break; + case 4: case 8: + InlineA = *(int32*)RelSource; break; + } + // Add inline addend to target address + TargetOffset += InlineA; + + if (Relocations[IRel].Type & 2) { + // Address is self-relative + if ((s.AddressFieldSize && (s.MFlags & 0x100)) || s.ImmediateFieldSize) { + // Relative jump or rip-relative address + TargetOffset += IEnd - s.AddressField; + InlineA += IEnd - s.AddressField; + } + else { + // Self-relative address in data segment or unknown + // This may occur in position-independent code + // We can't calculate the intended target + // Make sure there is a symbol, but don't change existing symbol if there is one + SymNewI = Symbols.NewSymbol(TargetSection, 0, 2); + return; + } + } + // Make new symbol in symbol table if none exists + SymNewI = Symbols.NewSymbol(TargetSection, TargetOffset, 2); + + if (SymNewI) { + // Get old index + SymOldI = Symbols[SymNewI].OldIndex; + + // Change relocation record to point to new symbol + Relocations[IRel].TargetOldIndex = SymOldI; + + // Compensate for inline addend and rip-relative address + Relocations[IRel].Addend = -InlineA; + } + } + + // Check if symbol has a scope assigned + if (Symbols[SymNewI].Scope == 0) Symbols[SymNewI].Scope = 2; + + // Choose between Symbols[SymNewI].Type and TargetType the one that has the highest priority + if ((TargetType & 0xFF) > (Symbols[SymNewI].Type & 0xFF) + || (((TargetType+1) & 0xFE) == 0x0C && (Symbols[SymNewI].Type & 0xFF) > 0x0C)) { + + // No type assigned yet, or new type overrides old type + Symbols[SymNewI].Type = TargetType; + + // Choose biggest size. Size for code pointer takes precedence + if (TargetSize > Symbols[SymNewI].Size || ((TargetType+1) & 0xFE) == 0x0C) { + Symbols[SymNewI].Size = TargetSize; + } + } +} + + +void CDisassembler::CheckJumpTarget(uint32 symi) { + // Extend range of current function to jump target, if needed + + // Check if current section is valid + if (Section == 0 || Section >= Sections.GetNumEntries()) return; + + // Check if current function is valid + if (IFunction == 0 || IFunction >= FunctionList.GetNumEntries()) return; + + // Check if target is in same section + if (Symbols[symi].Section != (int32)Section) return; + + // Check if target extends current function + if (Symbols[symi].Offset > FunctionList[IFunction].End && Symbols[symi].Offset <= Sections[Section].InitSize) { + // Target is after tentative end of current function but within section + + // Check if it is a known function + if ((Symbols[symi].Type & 0xFF) == 0x83 || (Symbols[symi].Type & 0xFF) == 0x85 + || (Symbols[symi].Scope & 0x1C)) { + // Target is known as public or a function. No need to extend current function + return; + } + // Extend current function forward to include target offset + FunctionList[IFunction].End = Symbols[symi].Offset; + FunctionList[IFunction].Scope |= 0x10000; + } + else if (Symbols[symi].Offset < FunctionList[IFunction].Start) { + // Target is before tentative begin of current function but within section + + // Check if target is already in function table + SFunctionRecord fun; + fun.Section = Symbols[symi].Section; + fun.Start = Symbols[symi].Offset; + uint32 IFun = FunctionList.Exists(fun); + if (IFun > 0 && IFun < FunctionList.GetNumEntries()) { + // Target is the beginning of a known function. No need to extend current function + return; + } + + /* Removed: This is a mess. Looks better when functions are separate + // Target points inside a previously defined function. Join the two functions into one + IFun = FunctionList.FindFirst(fun) - 1; + if (IFun > 0 && IFun < FunctionList.GetNumEntries() && FunctionList[IFun].Section == Section) { + + // Get maximum scope of the two functions + if (FunctionList[IFun].Scope < FunctionList[IFunction].Scope) { + FunctionList[IFun].Scope = FunctionList[IFunction].Scope; + } + + // Get maximum end of the two functions + if (FunctionList[IFun].End < FunctionList[IFunction].End) { + FunctionList[IFun].End = FunctionList[IFunction].End; + } + + // Remove entry IFunction from FunctionList + FunctionList.Remove(IFunction); + + // Set current function to IFun + IFunction = IFun; + } + */ + } +} + + +void CDisassembler::Pass2() { + + /* Pass 2: does the following jobs: + -------------------------------- + + * Scans through all sections, code and data. + + * Code is analyzed, instruction by instruction. Checks code syntax. + + * Outputs warnings for suboptimal instruction codes and error messages + for erroneous code and erroneous relocations. + + * Outputs disassembly of all instructions, operands and relocations, + followed by the binary code listing as comment. + + * Outputs disassembly of all data, followed by alternative representations + as comment. + + * Outputs dubious code as both code and data in order to allow a re-assembly + to produce identical code. + */ + + // Loop through sections, pass 2 + for (Section = 1; Section < Sections.GetNumEntries(); Section++) { + + // Get section type + SectionType = Sections[Section].Type; + if (SectionType & 0x800) continue; // This is a group + + if (((SectionType & 0xFF) == 0x10) && cmd.DebugInfo == CMDL_DEBUG_STRIP) { + // Skip debug section + cmd.CountDebugRemoved(); + continue; + } + if (((SectionType & 0xFF) == 0x11) && cmd.ExeptionInfo == CMDL_EXCEPTION_STRIP) { + // Skip exception section + cmd.CountExceptionRemoved(); + continue; + } + // Is this code or data? + CodeMode = ((SectionType & 0xFF) == 1) ? 1 : 4; + + // Initialize + LabelBegin = FlagPrevious = CountErrors = 0; + Buffer = Sections[Section].Start; + SectionEnd = Sections[Section].TotalSize; + LabelInaccessible = Sections[Section].InitSize; + WordSize = Sections[Section].WordSize; + SectionAddress = Sections[Section].SectionAddress; + + // Write segment directive + WriteSegmentBegin(); + + IBegin = IEnd = LabelEnd = IFunction = DataType = DataSize = 0; + + // Loop through function blocks in this section + while (NextFunction2()) { + + // Check CodeMode from label + NextLabel(); + + // Write begin function + if (CodeMode & 3) WriteFunctionBegin(); + + // Loop through labels + while (NextLabel()) { + + // Loop through code + while (NextInstruction2()) { + + if (CodeMode & 3) { + // Interpret this as code + + // Write label if any + CheckLabel(); + + // Parse instruction + ParseInstruction(); + + // Check for filling space + if (((s.Warnings1 & 0x10000000) || s.Warnings1 == 0x1000000) && WriteFillers()) { + // Code is inaccessible fillers. Has been written by CheckForFillers() + continue; + } + + // Write any error and warning messages to OutFile + WriteErrorsAndWarnings(); + + // Write instruction to OutFile + WriteInstruction(); + + // Write hex code as comment after instruction + WriteCodeComment(); + } + if (CodeMode & 6) { + + // Interpret this as data + WriteDataItems(); + } + if (IEnd <= IBegin) { + + // Prevent infinite loop + IEnd++; + break; + } + } + } + // Write end of function, if any + if (CodeMode & 3) WriteFunctionEnd(); // End function + } + // Write end of segment + WriteSegmentEnd(); + } +} + +/******************** Explanation of tracer: *************************** + +This is a machine which can trace the contents of each register in certain +situations. It is currently used for recognizing certain instruction patterns +that are used by various 64 bit compilers for accessing jump tables and +virtual function tables. The trace machine can be extended for other purposes. + +A switch/case statement is typically implemented as follows by the 64 bit MS +C++ compiler: + +.code +lea rbx, [__ImageBase] +mov eax, [SwitchIndex] +add eax, - LowerLimit +cmp eax, Range +ja LabelDefault +cdqe +mov ecx, [imagerel(SwitchTable) + rbx + rax*4] +add rcx, rbx +jmp rcx + +.data +SwitchTable label dword +dd imagerel(Label1) +dd imagerel(Label2) +dd imagerel(Label3) + +Some other compilers use the beginning of the switch table or the beginning of +the code section as reference point for 32-bit jump addresses. Other +compilers use 64-bit addresses in the switch table. We want to recognize +all these patterns in order to disassemble a switch table in a comprehensible +way and find the case label targets. + +In order to recognize a switch table in the above example, the tracer must +do the following tasks: + +1. Calculate the rip-relative address in the lea instruction and detect +that it is equal to the image base. + +2. Remember that rbx contains the image base. + +3. When interpreting the mov ecx instruction it recognizes that the base +pointer contains the image base, therefore the displacement must be +interpreted as an image-relative address. Calculate this address and +give it a name. + +4. Remember that ecx contains an an element from the array SwitchTable. +It is not yet known that SwitchTable is a switch table. + +5. After add rcx,rbx remember that rcx contains an element from the array +SwitchTable plus the image base. + +6. When interpreting the jmp rcx instruction, the information about the +contents of rcx is used for concluding that SwitchTable contains jump +addresses, and that these addresses are image-relative. If there had +been no add rcx,rbx, we would conclude that SwitchTable contains +absolute virtual addresses. + +7. Go through all elements of SwitchTable. Calculate the address that each +element points to, give it a name, and extend the scope of the current +function to include this target. + +8. It would be possible to determine the length of the switch table from +the cmp instruction, but the tracer does not currently use this +information. Instead, it stops parsing the switch table at the first +known label or the first invalid address. + +This is quite a long way to go for acquiring this information, but it is +necessary in order to tell what is code and what is data and to find out +where the function ends. Unfortunately, the MS compiler puts switch tables +in the code segment rather than in the data segment which would give better +caching and code prefetching. If the switch table was not identified as such, +it would be impossible to tell what is code and what is data. + +The tracer is also used for identifying virtual function tables. + +Values of SATracer::Regist[i] tells what kind of information register i contains: +0 Unknown contents +1 Contains image base +4 Contains a constant = Value[i] +8 Contains a value < Value[i]. (Not implemented yet) +0x10 Contains the value of a symbol. Value[i] contains the old index of the symbol +0x11 Contains the value of an array element. Value[i] contains the symbol old index of the array +0x12 Contains the value of an array element + image base. Value[i] contains the symbol old index of the array. (array may contain image-relative jump addresses) +0x13 Contains the value of an array element + array base. Value[i] contains the symbol old index of the array. (array may contain jump addresses relative to array base) +0x18 Contains the address of a symbol. Value[i] contains the symbol old index +0x19 Contains the address of an array element. Value[i] contains the symbol old index of the array +*/ + +void CDisassembler::UpdateTracer() { + // Trace register values. See explanation above + uint32 reg; // Destination register number + uint32 srcreg; // Source register number + + if (s.Operands[0] & 0xFF) { + // There is a destination operand + if ((s.Operands[0] & 0xFF) < 5 && (s.Operands[0] & 0x1000)) { + // Destination operand is a general purpose register + switch (s.Operands[0] & 0xF0000) { + case 0x20000: + // Register indicated by last bits of opcode byte + reg = Get(s.OpcodeStart2) & 7; + // Check REX.B prefix + if (s.Prefixes[7] & 1) reg |= 8; // Add 8 if REX.B prefix + break; + case 0x30000: + // Register indicated by rm bits of mod/reg/rm byte + reg = s.RM; + break; + case 0x40000: + // Register indicated by reg bits of mod/reg/rm byte + reg = s.Reg; + break; + default: + // Error. Don't know where to find destination register + t.Reset(); return; + } + } + else if ((s.Operands[0] & 0xFF) >= 0xA0 && (s.Operands[0] & 0xFF) <= 0xA9) { + // Destination is al, ax, eax, or rax + reg = 0; + } + else { + // Destination is not a general purpose register + return; + } + } + else { + // There is no destination operand + return; + } + + // Destination operand is a general purpose register + if (OpcodeOptions & 4) { + // Destination register is not changed + return; + } + + // Check the opcode to find out what has happened to this register + switch (Opcodei) { + case 0xB0: case 0xB1: case 0xB2: case 0xB3: + case 0xB4: case 0xB5: case 0xB6: case 0xB7: + case 0xB8: case 0xB9: case 0xBA: case 0xBB: + case 0xBC: case 0xBD: case 0xBE: case 0xBF: + // MOV register, constant + t.Regist[reg] = 0; + if (s.OperandSize < 32) { + // Only part of register is changed + return; + } + if (s.ImmediateRelocation) { + if (s.OperandSize < WordSize || !(Relocations[s.ImmediateRelocation].Type & 0x21)) { + // Wrong size or type of relocation + return; + } + // Register contains the address of a symbol + t.Regist[reg] = 0x18; + t.Value [reg] = Relocations[s.ImmediateRelocation].TargetOldIndex; + return; + } + + // Register value is a known constant + t.Regist[reg] = 4; + // Save value + switch (s.ImmediateFieldSize) { + case 1: + t.Value[reg] = Get(s.ImmediateField); + break; + case 2: + t.Value[reg] = Get(s.ImmediateField); + break; + case 4: + case 8: // 64-bit value truncated to 32 bits + t.Value[reg] = Get(s.ImmediateField); + break; + default: + // Error. Should not occur + t.Regist[reg] = 0; + } + return; + /* This part is currently unused: + case 0x31: case 0x33: case 0x29: case 0x2B: + // XOR or SUB. Check if source and destination is same register + if ((s.Operands[0] & 0xFFFF) == (s.Operands[1] & 0xFFFF) && s.Reg == s.RM && s.OperandSize >= 32) { + // XOR OR SUB with same source and destination produces zero + t.Regist[reg] = 4; + t.Value [reg] = 0; + return; + } + break; + */ + + case 0x8D: + // LEA + if (s.AddressFieldSize == 4 && s.AddressRelocation && s.OperandSize >= 32) { + // Register contains the address of a symbol + if (!(Relocations[s.AddressRelocation].Type & 1) && WordSize < 64) { + // Cannot follow position-independent code in 32 bit mode + t.Regist[reg] = 0; return; + } + t.Regist[reg] = 0x18; + t.Value [reg] = Relocations[s.AddressRelocation].TargetOldIndex; + // Check if symbol has name + const char * SymName = Symbols.HasName(t.Value[reg]); + if (SymName && strcmp(SymName, "__ImageBase") == 0) { + // Symbol is imagebase + t.Regist[reg] = 1; + } + // Check if base or index register + if (s.BaseReg || s.IndexReg) t.Regist[reg]++; + return; + } + if (!s.AddressRelocation && s.BaseReg && s.IndexReg && s.Scale == 0) { + // LEA used as ADD + + if (t.Regist[s.BaseReg-1] == 1 && (t.Regist[s.IndexReg-1] & 0xFE) == 0x10) { + // Adding imagebase to the value of a symbol or array element + t.Regist[reg] = 0x12; + t.Value [reg] = t.Value[s.IndexReg-1]; + return; + } + if (t.Regist[s.IndexReg-1] == 1 && (t.Regist[s.BaseReg-1] & 0xFE) == 0x10) { + // Adding the value of a symbol or array element to the imagebase + t.Regist[reg] = 0x12; + t.Value [reg] = t.Value[s.BaseReg-1]; + return; + } + if ((((t.Regist[s.IndexReg-1] & 0xFE) == 0x18 && (t.Regist[s.BaseReg-1] & 0xFE) == 0x10) + || ((t.Regist[s.IndexReg-1] & 0xFE) == 0x10 && (t.Regist[s.BaseReg-1] & 0xFE) == 0x18)) + && t.Value [s.IndexReg-1] == t.Value[s.BaseReg-1]) { + // Adding the value of an array element to the base address of same array. + // This is a computed jump address if array contains self-relative addresses + t.Regist[reg] = 0x13; + t.Value [reg] = t.Value[s.BaseReg-1]; + return; + } + } + break; + + case 0x89: case 0x8B: case 0x3B02: + // MOV and MOVSXD instruction + if (s.OperandSize < 32) break; // Only part of register is changed + if (!(s.MFlags & 1)) { + // MOV reg,reg. Copy register contents + if (Opcodei == 0x8B || Opcodei == 0x3B02) { + // Source register indicated by rm bits + srcreg = s.RM; + } + else { + // Source register indicated by reg bits + srcreg = s.Reg; + } + t.Regist[reg] = t.Regist[srcreg]; + t.Value [reg] = t.Value [srcreg]; + return; + } + // MOV reg,mem + if (s.AddressFieldSize == 4 && s.AddressRelocation) { + // Register contains the value of a symbol + if (!(Relocations[s.AddressRelocation].Type & 1) && WordSize < 64) { + // Cannot follow position-independent code in 32 bit mode + t.Regist[reg] = 0; return; + } + t.Regist[reg] = 0x10; + t.Value [reg] = Relocations[s.AddressRelocation].TargetOldIndex; + + // Check if base or index register + if (s.BaseReg || s.IndexReg) t.Regist[reg]++; + return; + } + if (s.BaseReg && (t.Regist[s.BaseReg-1] & 0xFE) == 0x18) { + // Memory operand has a base register which contains the address of a symbol + // Destination register will contain value of same symbol + t.Regist[reg] = 0x10; + t.Value [reg] = t.Value[s.BaseReg-1]; + if (s.IndexReg || s.AddressFieldSize || (t.Regist[s.BaseReg-1] & 1)) { + // There is an offset + t.Regist[reg] |= 1; + } + return; + } + if (s.IndexReg && (t.Regist[s.IndexReg-1] & 0xFE) == 0x18 && s.BaseReg && s.Scale == 0) { + // Same as above, base and index registers swapped, scale factor = 1 + t.Regist[reg] = 0x10; + t.Value [reg] = t.Value[s.IndexReg-1]; + if (s.AddressFieldSize || (t.Regist[s.IndexReg-1] & 1)) { + // There is an offset + t.Regist[reg] |= 1; + } + return; + } + break; + + case 0x01: case 0x03: + // ADD instruction + if (s.OperandSize < 32) break; // Only part of register is changed + if (Opcodei == 0x03) { + // Source register indicated by rm bits + srcreg = s.RM; + } + else { + // Source register indicated by reg bits + srcreg = s.Reg; + } + if (t.Regist[srcreg] == 1 && (t.Regist[reg] & 0xFE) == 0x10) { + // Adding imagebase to the value of a symbol or array element + t.Regist[reg] = 0x12; + return; + } + if (t.Regist[reg] == 1 && (t.Regist[srcreg] & 0xFE) == 0x10) { + // Adding the value of a symbol or array element to the imagebase + t.Regist[reg] = 0x12; + t.Value [reg] = t.Value[srcreg]; + return; + } + if ((((t.Regist[srcreg] & 0xFE) == 0x18 && (t.Regist[reg] & 0xFE) == 0x10) + || ((t.Regist[srcreg] & 0xFE) == 0x10 && (t.Regist[reg] & 0xFE) == 0x18)) + && t.Value [reg] == t.Value[srcreg]) { + // Adding the value of an array element to the base address of same array. + // This is a computed jump address if array contains self-relative addresses + t.Regist[reg] = 0x13; + return; + } + break; + + case 0x3902: + // CDQE. eax sign extended to rax. Ignore + return; + case 0x3900: case 0x3901: + // CBW, CWDE. rax changed + t.Regist[0] = 0; + return; + case 0x3A00: case 0x3A01: case 0x3A02: + // CWD, CDQ, CQO. rdx changed + t.Regist[2] = 0; + return; + } + // Anything else: Remember that this register is changed + t.Regist[reg] = 0; + + if (OpcodeOptions & 8) { + // Registers other than destination register may be changed + t.Reset(); + } +} + + +void CDisassembler::UpdateSymbols() { + // Find unnamed symbols, determine symbol types, + // update symbol list, call CheckJumpTarget if jump/call. + // This function is called during pass 1 for every instruction + + uint32 OpI; // Operand index + uint32 OperandType; // Type of operand + uint32 SymOldI; // Symbol table old index + uint32 SymNewI; // Symbol table new index + + // Loop through all operands for one instruction + for (OpI = 0; OpI < 4; OpI++) { + if (s.Operands[OpI]) { + SymNewI = 0; // Reset symbol index + OperandType = s.Operands[OpI]; // Operand type + + // Check if indirect jump/call + if (OpI == 0 && ((s.OpcodeDef->Destination + 1) & 0xFE) == 0x0C) { + OperandType = s.OpcodeDef->Destination; + } + + // Check operand type + if ((OperandType & 0xF0) == 0x80) { + // This is a jump/call destination + + if (!s.ImmediateRelocation) { + // Has no reference to other symbol. Make one + + // Relocation type + uint32 RelocationType = 2; // Self relative + if ((OperandType & 0xFE) == 0x84) RelocationType = 8; // Far + + // Scope + uint32 TargetScope = 1; // Function local + if ((OperandType & 0xFF) >= 0x83) TargetScope = 2; // Call or far. File scope + + // Make relocation and target symbol + SymNewI = MakeMissingRelocation(Section, s.ImmediateField, RelocationType, OperandType, TargetScope); + + // Update labels + LabelBegin = 0; + FindLabels(); + + if (TargetScope == 1 && SymNewI) { + // Short or near jump (not call). Update range of current function + CheckJumpTarget(SymNewI); + } + } + else { + // Jump or call to relocated symbol + // Look up in Relocations table + SymOldI = Relocations[s.ImmediateRelocation].TargetOldIndex; + + // Look up in symbol table + SymNewI = Symbols.Old2NewIndex(SymOldI); + if (Symbols[SymNewI].OldIndex) { + // Found + // Check if symbol already has a scope assigned + if (Symbols[SymNewI].Scope == 0) Symbols[SymNewI].Scope = 2; + + // Check if symbol already has a type assigned + if ((OperandType & 0xFF) > (Symbols[SymNewI].Type & 0xFF)) { + + // No type assigned yet, or new type overrides old type + Symbols[SymNewI].Type = (Symbols[SymNewI].Type & ~0xFF) | OperandType; + } + // Check if jump target is in data segment + if (Symbols[SymNewI].Section > 0 && (uint16)(Symbols[SymNewI].Section) < Sections.GetNumEntries() + && (Sections[Symbols[SymNewI].Section].Type & 0xFF) > 1) { + s.Warnings1 |= 0x80000; + } + } + } + } + else { + // Check if reference to data symbol + if ((s.Operands[OpI] & 0x2000) && (s.Operands[OpI] & 0xD0000) == 0x10000) { + // Memory operand + + if (s.AddressRelocation) { + // There is a reference to a data symbol + + // Make exception for LEA: Target type is unknown + if (Opcodei == 0x8D) OperandType = 0; + + // Check and update relocation target + CheckRelocationTarget(s.AddressRelocation, OperandType, GetDataItemSize(OperandType)); + } + else if (s.AddressFieldSize >= 4) { + // Relocation missing. Make one if possible + uint32 TargetType = OperandType; + if (Opcodei == 0x8D) { + // Source of LEA instruction has no type + TargetType = 0; + } + // Check addressing mode + if (s.MFlags & 0x100) { + // There is a rip-relative reference + // Make relocation record and target record + MakeMissingRelocation(Section, s.AddressField, 2, TargetType, 2); + FindRelocations(); + } + else if (s.BaseReg && t.Regist[s.BaseReg-1] == 1 && s.AddressFieldSize == 4) { + // Memory operand has a base register which has been traced + // to contain the image base. Make image-relative relocation + MakeMissingRelocation(Section, s.AddressField, 4, TargetType, 2); + FindRelocations(); + } + else if (ImageBase && !(RelocationsInSource & 0x20) && s.AddressFieldSize >= 4) { + // No base relocations in source. Make direct relocation + MakeMissingRelocation(Section, s.AddressField, 1, TargetType, 2, s.AddressFieldSize); + FindRelocations(); + } + } + } + if ((s.Operands[OpI] & 0xF0) >= 0x10 && (s.Operands[OpI] & 0xF0) < 0x40) { + // Immediate operand + + if (!s.ImmediateRelocation && s.ImmediateFieldSize >= 4 + && ImageBase && !(RelocationsInSource & 0x20) + && (Opcodei == 0x3000 || Opcodei == 0x68 || (Opcodei & 0xFFF8) == 0xB8)) { + // instruction = MOV or PUSH, immediate operand may be an address + // Make a relocation if immediate value is valid address + MakeMissingRelocation(Section, s.ImmediateField, 1, 0, 2, s.ImmediateFieldSize); + FindRelocations(); + } + if (s.ImmediateRelocation) { + // There is a reference to the offset of a data symbol + // Check and update relocation target + CheckRelocationTarget(s.ImmediateRelocation, 0, 0); + } + } + } + if (((OperandType + 1) & 0xFE) == 0x0C) { + // Indirect jump or call. Find jump table or virtual table + + // Default relocation type for jump table is direct + uint32 RelocationType = 1; + + // Find symbol table entry for jump pointer or call pointer + if (s.AddressRelocation && Relocations[s.AddressRelocation].TargetOldIndex) { + // Look up in symbol table + SymNewI = Symbols.Old2NewIndex(Relocations[s.AddressRelocation].TargetOldIndex); + } + else SymNewI = 0; + + if (SymNewI == 0 || Symbols[SymNewI].OldIndex == 0) { + // Symbol for jump table not found yet + if (s.Operands[OpI] & 0x2000) { + // There is a memory operand + if (s.BaseReg && (t.Regist[s.BaseReg-1] & 0xFE) == 0x18) { + // Memory operand has a base register which has been traced to + // point to a known symbol + SymNewI = Symbols.Old2NewIndex(t.Value[s.BaseReg-1]); + } + else if (((s.BaseReg != 0) ^ (s.IndexReg != 0)) && s.AddressFieldSize == 4 && ExeType) { + // Here is a jump table with an absolute address + SymNewI = MakeMissingRelocation(Section, s.AddressField, 1, 0x0B, 2, s.AddressFieldSize); + } + } + else { + // Jump or call to a register operand + // Check if the register value has been traced + if ((t.Regist[s.RM] & 0x1C) == 0x10) { + // Register contains an array element. Get symbol for this array + SymNewI = Symbols.Old2NewIndex(t.Value[s.RM]); + // Check relocation type + if (t.Regist[s.RM] == 0x12) { + // Register contains array element plus imagebase. + RelocationType = 4; // Array elements must have image-relative relocations + } + if (t.Regist[s.RM] == 0x13) { + // Register contains array element plus base address of same array + RelocationType = 0x10; // Array elements must have self-relative relocations + } + } + } + } + // Check if valid symbol for jump/call table + if (SymNewI && Symbols[SymNewI].OldIndex) { + // Jump/call table found + + if ((s.Operands[OpI] & 0x2000) && !s.BaseReg && !s.IndexReg && Opcodei == 0x2704) { + // Simple memory operand + // Assign name if symbol is import table entry + CheckImportSymbol(SymNewI); + } + + // Check relocation type if memory operand + if ((s.Operands[OpI] & 0x2000) && s.BaseReg && t.Regist[s.BaseReg-1] == 1) { + // Memory operand has a base register which has been traced to contain the imagebase + RelocationType = 4; // Array elements must have image-relative relocations + } + + // Check symbol type + if ((Symbols[SymNewI].Type & 0xFF) < (OperandType & 0xFF) /*|| (Symbols[SymNewI].Type & 0xF0)*/) { + // No type assigned yet, or new type overrides old type + Symbols[SymNewI].Type = OperandType; + } + + // Check symbol size + if (RelocationType == 4 && WordSize > 16) { + Symbols[SymNewI].Size = 4; // Image relative + } + if (RelocationType == 0x10 && WordSize > 16) { + Symbols[SymNewI].Size = 4; // Relative to table base + } + else { + Symbols[SymNewI].Size = WordSize / 8; // Direct + } + + // Follow what the jump/call table points to + FollowJumpTable(SymNewI, RelocationType); + } + } + } + } +} + + +void CDisassembler::FollowJumpTable(uint32 symi, uint32 RelType) { + // Check jump/call table and its targets + uint32 sym1, sym2, sym3 = 0; // Symbol indices + uint32 NextLabel; // Offset of next label + uint32 Pos; // Current position + SARelocation rel; // Relocation record for searching + int32 Reli; // Index to relocation + uint32 NewType = 0; // Type to assign to symbol + int32 SourceSection; // Section of relocation source + uint32 SourceOffset; // Offset of relocation source + uint32 SourceSize; // Size of relocation source + uint32 TargetType; // Type for relocation target + uint32 RefPoint = 0; // Reference point if relocationtype = 0x10 + int32 Addend = 0; // Inline addend + + // Check if sym is valid + if (Symbols[symi].OldIndex == 0) return; + + // Get type of target + switch (s.OpcodeDef->Destination & 0xFF) { + case 0x0B: // Near indirect jump. Target type = jump destination + NewType = 0x82; break; + case 0x0C: // Near indirect call. Target type = call destination + NewType = 0x83; break; + default: // Should not occur + return; + } + + // Check symbol size + if ((RelType & 4) && WordSize >= 32) { + // Image relative relocation + Symbols[symi].Size = 4; + } + else if ((RelType & 0x10) && WordSize >= 32) { + // Relative to table base + Symbols[symi].Size = 4; + RefPoint = Symbols[symi].OldIndex; // Reference point = table base + } + else if ((RelType & 0x21) || Symbols[symi].Size == 0) { + // Direct near relocation + Symbols[symi].Size = WordSize / 8; + } + + // Check symbol type + if (uint32(s.OpcodeDef->Destination & 0xFF) > (Symbols[symi].Type & 0xFF)) { + // No type assigned yet, or new type overrides old type + Symbols[symi].Type = s.OpcodeDef->Destination | 0x4000000; + } + // Make sure symbol is marked as data + Symbols[symi].Type |= 0x4000000; + + // Check if symbol has a scope assigned + if (Symbols[symi].Scope == 0) Symbols[symi].Scope = 2; + + // Save symbol properties + // (The reference to sym will become invalid when new symbols are created) + SourceSection = Symbols[symi].Section; + SourceOffset = Symbols[symi].Offset; + SourceSize = Symbols[symi].Size; + TargetType = 0x82; + + // Target type = jump label + if ((Symbols[symi].Type & 0xFF) == 0x0C) TargetType++; // Target type = call label + + // Find next label + sym1 = Symbols.FindByAddress(SourceSection, SourceOffset, &sym2, &sym3); + if (sym1 && sym3) { + // Assume that table ends at next label + NextLabel = Symbols[sym3].Offset; + } + else { + // No next label. End at source section end + NextLabel = Sections[SourceSection].InitSize; + } + + // Loop through table of jump/call addresses + for (Pos = SourceOffset; Pos < NextLabel; Pos += SourceSize) { + + // Search for relocation source at table entry + rel.Section = SourceSection; + rel.Offset = Pos; + Reli = Relocations.Exists(rel); + + if (Reli > 0) { + // Relocation found. Check target + CheckRelocationTarget(Reli, TargetType, 0); + } + else { + // No relocation here. Make one if possible + + uint32 symi = MakeMissingRelocation(rel.Section, rel.Offset, RelType, TargetType, 2, 0, RefPoint); + if (!symi) { + // Failed to make a meaningful relocation. End jump table + break; + } + int32 TargetSection = Symbols[symi].Section; + if (!TargetSection || (Sections[TargetSection].Type & 0xFF) != 1) { + // Target is not in code section. End jump table + break; + } + // Find the newly made relocation + Reli = Relocations.Exists(rel); + if (Reli <= 0) break; + } + // Relocation found. Check if valid + if (!(Relocations[Reli].Type & 0x37) || !Relocations[Reli].TargetOldIndex) { + // Wrong relocation type or invalid. Stop searching + break; + } + // Find relocation target + uint32 TargetSymI = Symbols.Old2NewIndex(Relocations[Reli].TargetOldIndex); + if (!TargetSymI) { + // Target invalid + break; + } + + // Calculate target address + Addend = Relocations[Reli].Addend; + // Check inline addend if target is section-relative and this is an object file + if (!ExeType && Symbols[TargetSymI].Offset == 0) { + + switch (SourceSize) { + case 2: + Addend += *(int16*)(Sections[SourceSection].Start + Pos); + break; + case 4: case 8: + Addend += *(int32*)(Sections[SourceSection].Start + Pos); + break; + default: + Addend += 0; + } + if (Addend) { + // Make new symbol at target address + uint32 NewSymOffset = Addend; + if (Relocations[Reli].Type & 2) { // relative + if (RelType == 0x10) { // arbitrary reference point + NewSymOffset -= (Relocations[Reli].Offset - SourceOffset); + } + } + uint32 NewSym = Symbols.NewSymbol(Symbols[TargetSymI].Section, NewSymOffset, 2); + if (NewSym) TargetSymI = NewSym; + } + } + + // Update target symbol type + if ((Symbols[TargetSymI].Type & 0xFF) < NewType) { + Symbols[TargetSymI].Type = (Symbols[TargetSymI].Type & ~0xFF) | NewType; + } + // Extend current function to include target + CheckJumpTarget(TargetSymI); + + // Update NextLabel in case new target is between Pos and NextLabel + if (Symbols[TargetSymI].Section == SourceSection && Symbols[TargetSymI].Offset > Pos && Symbols[TargetSymI].Offset < NextLabel) { + NextLabel = Symbols[TargetSymI].Offset; + } + } + + if (Pos < NextLabel) { + // There is no label after jump table. Make one with zero scope + SASymbol SymAfter; + SymAfter.Reset(); + SymAfter.Section = SourceSection; + SymAfter.Offset = Pos; + SymAfter.Type = (Sections[SourceSection].Type & 0xFF) == 1 ? 0x82 : 0; + Symbols.NewSymbol(SymAfter); + } +} + + +uint32 CDisassembler::MakeMissingRelocation(int32 Section, uint32 Offset, uint32 RelType, uint32 TargetType, uint32 TargetScope, uint32 SourceSize, uint32 RefPoint) { + // Make a relocation and its target symbol from inline address + /* This function is used for executable files that have already been + relocated for making the relocation information that has been + lost as well as the symbol record that the relocation should + point to. + Parameters: + Section Section of relocation source + Offset Offset of relocation source + RelType Relocation type: 1 = direct, 2 = self relative, 4 = image relative, 0x10 = relative to reference point + TargetType Symbol type for target + TargetScope Scope for target symbol + SourceSize Size of source field (0 = default for relocation type and WordSize) + RefPoint Reference point if RelType = 0x10 (symbol old index) + + The return value is a symbol new index for the target, or zero if failure + + The size of the relocation source is implied from RelType + A symbol record for the target will be made if none exists. + The scope of the target symbol will be file local (2) + */ + + SARelocation Rel; // Temporary relocation record + SASymbol Sym; // Temporary symbol record for target + Sym.Reset(); + int32 irel; // Relocation index + uint32 isym = 0; // Symbol new index + int64 InlineA; // Inline address or displacement + int64 TargetAbsAddr; // Absolute address of target + + // Check if Section valid + if (Section <= 0 || (uint32)Section >= Sections.GetNumEntries() || Offset >= Sections[Section].InitSize || !Sections[Section].Start) { + return 0; + } + + // Check if a relocation would be missing + if (RelType & 1) { + // Direct relocation + if (RelocationsInSource & 0x20) return 0; // Source file has base relocations. There would be a relocation here if needed + } + else if (RelType & 4) { + // Image relative + if (!ExeType) return 0; // Object file. There would be a relocation here if needed + } + + // Check if a relocation already exists + Rel.Section = Section; + Rel.Offset = Offset; + irel = Relocations.Exists(Rel); + if (irel > 0) return 0; // Relocation exists. Don't do anything + + if (SourceSize == 0) { + // Source size not specified. Get default source size + if ((TargetType & 0xFF) == 0x81) { + // Short jump + SourceSize = 1; + } + else if (RelType & 1) { + // Direct relocation. Size depends on word size + SourceSize = WordSize / 8; + } + else if (RelType & 0x12) { + // Self relative or relative to table base + SourceSize = (WordSize == 16) ? 2 : 4; + } + else if (RelType & 4 && WordSize > 16) { + // Image relative + SourceSize = 4; + } + else { + // Other value. Ignore + return 0; + } + } + + // Get inline address or displacement from source address + if (SourceSize == 8) { + InlineA = *(int64*)(Sections[Section].Start + Offset); + } + else if (SourceSize == 4) { + InlineA = *(int32*)(Sections[Section].Start + Offset); + } + else if (SourceSize == 2) { + InlineA = *(int16*)(Sections[Section].Start + Offset); + } + else { // 1 + InlineA = *(int8*)(Sections[Section].Start + Offset); + } + + // Get absolute virtual address of target + if (RelType & 1) { + // Direct address + TargetAbsAddr = InlineA; + } + else if (RelType & 2) { + // Self relative. Translate self-relative to absolute address + TargetAbsAddr = InlineA + ImageBase + SectionAddress + IEnd; + } + else if (RelType & 0x10) { + // Relative to reference point. Translate relative to absolute address + uint32 RefSym = Symbols.Old2NewIndex(RefPoint); + TargetAbsAddr = InlineA + Symbols[RefSym].Offset + Sections[Symbols[RefSym].Section].SectionAddress; + } + else { + // Image relative + TargetAbsAddr = InlineA + ImageBase; + } + + if (ExeType) { + // Executable file + // Translate to section:offset address + if (TranslateAbsAddress(TargetAbsAddr, Sym.Section, Sym.Offset)) { + + // Make a symbol for this address if none exists + Sym.Scope = TargetScope; + Sym.Type = TargetType; + isym = Symbols.NewSymbol(Sym); + } + else if (TargetAbsAddr == ImageBase && TargetAbsAddr) { + // Reference to image base (nonzero) + // Make a symbol for image base if none exists + Sym.Scope = 0x20; + Sym.Type = 0; + isym = Symbols.NewSymbol(Sym); + if (isym && Symbols[isym].Name == 0) { + Symbols.AssignName(isym, "__ImageBase"); + } + } + } + else { + // Object file + Sym.Section = Section; + Sym.Offset = (uint32)TargetAbsAddr - SectionAddress; + + // Make a symbol for this address if none exists + Sym.Scope = TargetScope; + Sym.Type = TargetType; + isym = Symbols.NewSymbol(Sym); + } + + if ((RelType & 2) && (TargetType & 0xF0) == 0x80 && Sym.Section == Section && CodeMode == 1) { + // Relocation not needed for relative jump/call within same section + return isym; + } + + if (isym) { + // Relocation addend + int32 Addend = -(int32)InlineA; + if (RelType & 2) { + // Correct self-relative record for bias + if (s.MFlags & 0x100) { + // rip-relative address + Addend -= IEnd - s.AddressField; + } + else { + // self-relative jump etc. + Addend -= SourceSize; + } + } + + // Make a relocation record + AddRelocation (Section, Offset, Addend, RelType, SourceSize, Symbols[isym].OldIndex, RefPoint); + + // Update s.AddressRelocation and s.ImmediateRelocation + if (CodeMode & 3) { + FindRelocations(); + + // Remove warning for absolute address + s.Warnings1 &= ~0x8000; + } + } + return isym; +} + + +void CDisassembler::CheckImportSymbol(uint32 symi) { + // Check for indirect jump to import table entry + + if (Symbols[symi].DLLName) { + // Instruction is an indirect jump to symbol table entry + // Find label at current instruction + uint32 sym2 = Symbols.FindByAddress(Section, IBegin); + if (sym2 && Symbols[sym2].Name == 0) { + // Label at current instruction has no name + // Give current instruction the import name without "_imp" prefix + const char * ImpName = Symbols.GetName(symi); + if (strncmp(ImpName, Symbols.ImportTablePrefix, (uint32)strlen(Symbols.ImportTablePrefix)) == 0) { + Symbols.AssignName(sym2, ImpName + (uint32)strlen(Symbols.ImportTablePrefix)); + } + } + } +} + +void CDisassembler::MarkCodeAsDubious() { + // Remember that this may be data in a code segment + uint32 sym1, sym2 = 0, sym3 = 0; // Preceding and succeding symbols + + // Check likelihood that this is data rather than code + if (((s.Errors & 0x4000) && ((s.Warnings1 & 0x10000000) || CountErrors > 1)) + || CountErrors > 5) { + // There are more than 5 errors, or consecutive zeroes and at + // least one more error or inaccessible code. + // Consider this sufficient evidence that this is very unlikely + // to be code. Show it as data only + CodeMode = 4; + } + if (CodeMode < 4) { + // This may be code containing errors or interpreted out of phase. + // Set CodeMode to dubious so that it will be shown as both code and data + CodeMode = 2; + } + + if (Pass & 0x0F) { + // Pass 1. Mark preceding label as dubious + + // Check nearest preceding label + if (LabelBegin == 0) { + // There is no preceding label. Make one + Symbols.NewSymbol(Section, IBegin, 1); + LabelBegin = 0; + FindLabels(); + } + + // Find symbol index for nearest preceding label + sym1 = Symbols.FindByAddress(Section, LabelBegin, &sym2, &sym3); + + if (sym1 && sym2) { + // Mark symbol as dubious or data + Symbols[sym2].Type = (Symbols[sym2].Type & ~0xF000000) | (CodeMode << 24); + } + + // Request repetition of pass 1 + Pass |= 0x100; + + /* Skip to next label. + This is removed because we want to accumulate errors as evidence for + determined whether this is code or data + // Is there a label after this? + if (sym3) { + // Skip to next label + if (Symbols[sym3].Offset > IEnd) { + IBegin = IEnd = Symbols[sym3].Offset; + } + } + else { + // No next label. Skip to section end + IBegin = IEnd = SectionEnd; + } + */ + } +} + + +int CDisassembler::NextInstruction1() { + // Go to next instruction or data item. Return 0 if none. Pass 1 + IBegin = IEnd; + + // Reset everything in s field + s.Reset(); + + // Return if there are more instructions + return (IBegin < SectionEnd); +} + +int CDisassembler::NextInstruction2() { + // Go to next instruction or data item. Return 0 if none. Pass 2 + IBegin = IEnd; + + // Reset everything in s field + s.Reset(); + + // Return if there are more instructions + return (IBegin < FunctionEnd && IBegin < LabelEnd && IBegin < SectionEnd); +} + +void CDisassembler::ParseInstruction() { + // Parse one opcode + FlagPrevious = 0; // Reset flag from previous instruction + + s.OpcodeStart1 = IBegin; // Index to start of instruction + + // Scan prefixes first + ScanPrefixes(); + + // Find opcode map entry + FindMapEntry(); // Find entry in opcode maps + + // Find operands + FindOperands(); // Interpret mod/reg/rm and SIB bytes and find operands + + // Determine the types of each operand + FindOperandTypes(); + + if (s.Prefixes[3] == 0x62) { + if (s.Prefixes[6] & 0x20) { // EVEX + FindBroadcast(); // Find broadcast and offet multiplier for EVEX code + } + else { // MVEX + SwizTableLookup(); // Find swizzle table record if MVEX prefix + } + } + + // Find any relocation sources in this instruction + FindRelocations(); + + // Find any reasons for warnings + FindWarnings(); + + // Find any errors + FindErrors(); + + if (!s.Errors && CodeMode == 1) { + // Find instruction set + FindInstructionSet(); + + // Update symbol types for operands of this instruction + UpdateSymbols(); + + // Trace register values + UpdateTracer(); + } +} + + +void CDisassembler::ScanPrefixes() { + // Scan prefixes + uint32 i; // Index to current byte + uint8 Byte; // Current byte of code + for (i = IBegin; i < SectionEnd; i++) { + + // Read code byte + Byte = Buffer[i]; + + // Check if Byte is a prefix + if (WordSize == 64 && (Byte & 0xF0) == 0x40) { + + // This is a REX prefix + if (Byte & 0x08) { + // REX.W prefix + StorePrefix(4, 0x48); // REX.W also in category operand size + } + StorePrefix(7, Byte); // Store in category REX + } + else if (i+1 < SectionEnd && + ((((Byte & 0xFE) == 0xC4 || Byte == 0x62) && (WordSize == 64 || (Buffer[i+1] >= 0xC0))) + || (Byte == 0x8F && (Buffer[i+1] & 0x38)))) { + // This is a VEX, EVEX, MVEX or XOP prefix + + // Check for invalid prefixes before this + if (s.Prefixes[5] | s.Prefixes[7]) s.Warnings1 |= 0x800; + + // Get equivalent prefixes + uint8 prefix3 = Byte; // Repeat prefix (F2, F3) or VEX prefix (C4, C5, 62) + uint8 prefix4; // 66, 48 Operand size prefix + uint8 prefix5; // 66, F2, F3 operand type prefixes + uint8 prefix6; // VEX.mmmmm and VEX.L + uint8 prefix7; // equivalent to REX prefix + uint8 vvvv; // vvvv register operand + if (Byte == 0xC5) { + // 2-bytes VEX prefix + if (i+2 >= SectionEnd) { + IEnd = i+2; + s.Errors |= 0x10; return; // End of buffer reached + } + Byte = Buffer[++i]; // Second byte + prefix5 = Byte & 3; // pp bits + prefix6 = (Byte << 3) & 0x20; // L bit + prefix6 |= 1; // mmmmm bits = 1 for 0F map + vvvv = (~Byte >> 3) & 0x0F; // vvvv operand + prefix7 = 0x10; // Indicate 2-bytes VEX prefix + prefix7 |= (~Byte >> 5) & 4; // R bit + } + else { + // 3 or 4-bytes VEX/EVEX/MVEX prefix or XOP prefix + if (i+3+(Byte==0x62) >= SectionEnd) { + IEnd = i+3+(Byte==0x62); + s.Errors |= 0x10; return; // End of buffer reached + } + prefix7 = (Byte == 0x8F) ? 0x80 : 0x20;// Indicate 3/4-bytes VEX prefix or XOP prefix + Byte = Buffer[++i]; // Second byte + prefix6 = Byte & 0x1F; // mmmmm bits + prefix7 |= (~Byte >> 5) & 7; // R,X,B bits + Byte = Buffer[++i]; // Third byte + prefix5 = Byte & 3; // pp bits + prefix6 |= (Byte << 3) & 0x20; // VEX: L bit, MVEX: 0, EVEX: 1 + vvvv = (~Byte >> 3) & 0x0F; // vvvv operand + prefix7 |= (Byte >> 4) & 8; // W bit + if (prefix3 == 0x62) { + // 4-bytes EVEX or MVEX prefix + prefix6 |= 0x40; // Indicates EVEX or MVEX prefix, bit 5 is 0 for MVEX, 1 for EVEX + Byte = Buffer[++i]; // Fourth byte + s.Kreg = Byte & 0x07; // kkk mask register + vvvv |= (~Byte & 8) << 1; // extra v bit + s.Esss = Byte >> 4; // EVEX: zLLb, MVEX: Esss bits + } + } + StorePrefix(3, prefix3); // VEX prefix + // Get operand size prefix + prefix4 = (prefix5 == 1) ? 0x66 : 0; + if (prefix7 & 8) prefix4 = 0x48; + StorePrefix(4, prefix4); // Operand size prefix + // Translate operand type prefix values + static const uint8 PrefixValues[4] = {0, 0x66, 0xF3, 0xF2}; + prefix5 = PrefixValues[prefix5]; + StorePrefix(5, prefix5); // Operand type prefix + StorePrefix(6, prefix6); // VEX mmmmm,L + StorePrefix(7, prefix7); // REX prefix equivalent + s.Vreg = vvvv; // Store vvvv operand + // Next byte cannot be a prefix. Stop searching for prefixes + s.OpcodeStart1 = i + 1; + return; + } + else if (OpcodeMap0[Byte].InstructionFormat & 0x8000) { + + // This is a prefix (other than REX/VEX) + switch (Byte) { + case 0x26: case 0x2E: case 0x36: case 0x3E: case 0x64: case 0x65: + // Segment prefix + StorePrefix(0, Byte); // Store prefix + if (Byte == 0x64) MasmOptions |= 2; // Remember FS used + if (Byte == 0x65) MasmOptions |= 4; // Remember GS used + break; + + case 0x67: + // Address size prefix + StorePrefix(1, Byte); break; + + case 0xF0: + // Lock prefix + StorePrefix(2, Byte); break; + + case 0xF2: case 0xF3: + // Repeat prefix + StorePrefix(3, Byte); // Both in category repeat and operand type + StorePrefix(5, Byte); break; + + case 0x66: + // Operand size + StorePrefix(4, Byte); // Both in category operand size and operand type + StorePrefix(5, Byte); break; + + default: + err.submit(9000); + } + } + else { + // This is not a prefix + s.OpcodeStart1 = i; + return; + } + } + // Error: end of block reached before end of prefixes + IEnd = i; + s.Errors |= 0x10; +} + + +void CDisassembler::StorePrefix(uint32 Category, uint8 Byte) { + // Store prefix according to category + if (Category > 7) {err.submit(9000); return;} // Out of range + + // Check if we already have a prefix in this category + if (s.Prefixes[Category]) { + // We already have a prefix in this category + if (s.Prefixes[Category] != Byte || Category == 7) { + // Conflicting prefixes in this category + s.Conflicts[Category]++; + } + else { + // Same prefix occurs more than once + s.Warnings1 |= 0x100; + } + } + // Check if REX prefix before this + if (s.Prefixes[7]) s.Errors |= 0x20; + + // Save prefix in category + s.Prefixes[Category] = Byte; +} + + +void CDisassembler::FindMapEntry() { + // Find entry in opcode maps + uint32 i = s.OpcodeStart1; // Index to current byte + uint16 Link; // Link to another map + uint8 Byte = Buffer[i]; // Current byte of code or index into map + uint32 MapNumber = 0; // Map number in opcodes.cpp + uint32 StartPage; // Index to start page in opcode map + uint32 MapNumber0 = 0; // Fallback start page if no map entry found in StartPage + SOpcodeDef const * MapEntry; // Point to current opcode map entry + + // Get start page from VEX.mmmm or XOP.mmmm bits if any + switch (s.Prefixes[3]) { + default: // no multibyte prefix + StartPage = 0; + MapEntry = OpcodeTables[StartPage] + Byte; + break; + case 0xC4: case 0xC5: case 0x62: // 2-, 3-, or 4-bytes VEX prefix + StartPage = s.Prefixes[6] & 0x0F; // 4 mmmm bits or 0 if no VEX or XOP prefix + if (StartPage >= NumOpcodeStartPageVEX) { + s.Errors |= 0x10000; StartPage = 0; // mmmm bits out of range + } + MapNumber = OpcodeStartPageVEX[StartPage]; + if (StartPage == 1) MapNumber0 = 1; + if (StartPage == 2 && s.Prefixes[3] == 0x62) { + if ((s.Prefixes[5] & 0xFE) == 0xF2) { // shortcut for EVEX F2 0F 38 and EVEX F3 0F 38 + StartPage = 8 + (s.Prefixes[5] & 1); + MapNumber0 = MapNumber; + MapNumber = OpcodeStartPageVEX[StartPage]; + } + } + + // Get entry [Byte] in map + MapEntry = OpcodeTables[MapNumber] + Byte; + + // There are two entries for mm = 1: OpcodeMap1 for legacy code and OpcodeMapB1 for VEX-only code. + // There are two entries for mm = 2: OpcodeMap2 for legacy code and OpcodeMapB2 for EVEX-only code with F3 prefix. + // We don't want to have the same code in two different maps because this may cause errors if a code + // is updated only in one of the maps. + // Search the shortcut map first, then the default map + if ((MapEntry->Name == 0 && MapEntry->TableLink == 0) || Byte >= OpcodeTableLength[MapNumber]) { + // not found here, try in default map + MapNumber = MapNumber0; + MapEntry = OpcodeTables[MapNumber] + Byte; + } + if (MapNumber == 0) s.Errors |= 0x10000; // no map found + break; + case 0x8F: // XOP prefix + StartPage = (s.Prefixes[6] & 0x1F) - 8; // 4 mmmm bits or 0 if no VEX or XOP prefix + if (StartPage >= NumOpcodeStartPageXOP) { + s.Errors |= 0x10000; StartPage = 0; // mmmm bits out of range + } + MapEntry = OpcodeStartPageXOP[StartPage] + Byte;// Get entry [Byte] in map + } + + // Save previous opcode and options + *(uint32*)&PreviousOpcodei = *(uint32*)&Opcodei; + *(uint32*)&Opcodei = 0; + + // Loop through map tree (exit loop when Link == 0) + while (1) { + + // Check if MapEntry has a link to another map + Link = MapEntry->TableLink; + + switch (Link) { + case 0: // No link + // Final map entry found + s.OpcodeStart2 = i; + s.OpcodeDef = MapEntry; + + // Save opcode and options + Opcodei = (MapNumber << 8) | Byte; + OpcodeOptions = MapEntry->Options; + + // Return success + return; + + case 1: // Use following byte as index into next table + if (i >= SectionEnd) { + // Instruction extends beyond end of block + IEnd = i; s.Errors |= 0x10; + s.OpcodeStart2 = i; + return; + } + Byte = Buffer[++i]; // Get next byte of code as index + break; + + case 2: // Use reg field of mod/reg/rm byte as index into next table + Byte = (Buffer[i+1] >> 3) & 7; // Read reg bits + break; + + case 3: // Use mod < 3 vs. mod == 3 as index into next table + Byte = (Buffer[i+1] & 0xC0) == 0xC0; // 1 if mod == 3 + break; + + case 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. + Byte = (Buffer[i+1] >> 3) & 7; // Read reg bits + if ((Buffer[i+1] & 0xC0) == 0xC0) Byte += 8; // Add 8 if mod == 3 + break; + + case 5: // Use rm bits of mod/reg/rm byte as index into next table + Byte = Buffer[i+1] & 7; // Read r/m bits + break; + + case 6: // Use immediate byte after any other operands as index into next table + s.OpcodeStart2 = i; + s.OpcodeDef = MapEntry; + FindOperands(); // Find size of all operand fields and end of instruction + Byte = Buffer[IEnd - 1]; // Last byte of instruction + break; + + case 7: // Use mode as index into next table (16, 32, 64 bits) + switch (WordSize) { + case 16: + Byte = 0; break; + case 32: default: + Byte = 1; break; + case 64: + Byte = 2; + } + break; + + case 8: // Use operand size as index into next table (16, 32, 64 bits) + switch (WordSize) { + case 64: + if (s.Prefixes[4] == 0x48) { // REX.W prefix = 64 bit + Byte = 2; break; + } + // Else continue in case 32: + case 32: default: + Byte = (s.Prefixes[4] == 0x66) ? 0 : 1; break; + case 16: + Byte = (s.Prefixes[4] == 0x66) ? 1 : 0; break; + } + break; + + case 9: // Use operand type prefixes as index into next table (none, 66, F2, F3) + switch (s.Prefixes[5]) { + case 0: default: + Byte = 0; break; + case 0x66: + Byte = 1; + if (s.Prefixes[3] == 0xF2) Byte = 2; // F2/F3 take precedence over 66 in (tzcnt instruction) + else if (s.Prefixes[3] == 0xF3) Byte = 3; + break; + case 0xF2: + Byte = 2; break; + case 0xF3: + Byte = 3; break; + } + break; + + case 0xA: // Use address size as index into next table (16, 32, 64 bits) + switch (WordSize) { + case 64: + Byte = (s.Prefixes[1] == 0x67) ? 1 : 2; break; + case 32: default: + Byte = (s.Prefixes[1] == 0x67) ? 0 : 1; break; + case 16: + Byte = (s.Prefixes[1] == 0x67) ? 1 : 0; break; + } + break; + + case 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 + // (VEX absent, VEX.L=0, VEX.L=1) + if ((s.Prefixes[7] & 0xB0) == 0) { + Byte = 0; // VEX absent + } + else if ((s.Prefixes[6] & 0x60) == 0x60) { // EVEX + Byte = ((s.Esss >> 1) & 3) + 1; // EVEX.LL bits + } + else if ((s.Prefixes[6] & 0x60) == 0x40) { // MVEX + Byte = 3; + } + else { // VEX + Byte = 1 + (s.Prefixes[6] >> 5 & 1); // 1 + VEX.L + } + break; + + case 0x0C: // Use VEX.W bit as index into next table + Byte = (s.Prefixes[7] & 0x08) >> 3; + break; + + case 0x0D: // Use vector size by VEX.L bit and EVEX/MVEX as index into next table + // 0: VEX.L=0, 1: VEX.L=1, 2:MVEX or EVEX.LL=2, 3: EVEX.LL=3 + Byte = (s.Prefixes[6] >> 5) & 1; // VEX.L indicates xmm or ymm + if (s.Prefixes[3] == 0x62) { + if (s.Prefixes[6] & 0x20) { + // EVEX. Use LL bits + Byte = (s.Esss >> 1) & 3; + } + else { + // MVEX. Always 512 bits + Byte = 2; + } + } + break; + + case 0x0E: // Use VEX type as index into next table: 0 = 2 or 3 bytes VEX, 1 = 4 bytes EVEX + Byte = (s.Prefixes[3] == 0x62); // EVEX + break; + + case 0x0F: // Use MVEX.E bit as index into next table + Byte = (s.Prefixes[3] == 0x62 && (s.Esss & 8)); // MVEX.E bit + break; + + case 0x10: // Use assembly language dialect as index into next table + Byte = Syntax; + break; + + case 0x11: // Use VEX prefix type as index into next table. (0: none, 1: VEX prefix, 2: EVEX prefix, 3: MVEX prefix) + if ((s.Prefixes[3] & ~1) == 0xC4) Byte = 1; // 2 or 3-bytes VEX prefix + else if (s.Prefixes[3] == 0x62) { // EVEX or MVEX + if (s.Prefixes[6] & 0x20) Byte = 2; // EVEX + else Byte = 3; // MVEX + } + else Byte = 0; // no VEX + break; + + default: // Internal error in map tree + err.submit(9007, MapNumber); + s.OpcodeStart2 = i; + return; + } + + // Get next map from branched tree of maps + MapNumber = MapEntry->InstructionSet; + if (MapNumber >= NumOpcodeTables1 || OpcodeTableLength[MapNumber] == 0) { + err.submit(9007, MapNumber); return; // Map number out of range + } + + // Use Byte as index into new map. Check if within range + if (Byte >= OpcodeTableLength[MapNumber]) { + // Points outside map. Get last entry in map containing default + Byte = OpcodeTableLength[MapNumber] - 1; + } + // Point to entry [Byte] in new map + MapEntry = OpcodeTables[MapNumber] + Byte; + if (MapEntry == 0) { + err.submit(9007, MapNumber); return; // Map missing + } + + } // Loop end. Go to next +} + + +void CDisassembler::FindOperands() { + // Interpret mod/reg/rm and SIB bytes and find operands + s.MFlags = 0; // Memory operand flags: + // 1 = has memory operand, + // 2 = has mod/reg/rm byte, + // 4 = has SIB byte, + // 8 = has DREX byte (AMD SSE5 instructions never implemented), + // 0x10 = is rip-relative + uint8 ModRegRM; // mod/reg/rm byte + uint8 SIB; // SIB byte + + // Get address size + if (WordSize == 64) s.AddressSize = (s.Prefixes[1] == 0x67) ? 32 : 64; + else s.AddressSize = (WordSize == 16) ^ (s.Prefixes[1] == 0x67) ? 16 : 32; + + s.AddressFieldSize = s.ImmediateFieldSize = 0;// Initialize + + // Position of next element in opcode + s.AddressField = s.OpcodeStart2 + 1; + + // Check if there is a mod/reg/rm byte + if (s.OpcodeDef->InstructionFormat & 0x10) { + + // There is a mod/reg/rm byte + s.MFlags |= 2; + + if (s.OpcodeStart2 + 1 >= FunctionEnd) { + CheckForMisplacedLabel(); + } + + // Read mod/reg/rm byte + ModRegRM = Buffer[s.AddressField++]; + s.Mod = ModRegRM >> 6; // mod = bit 6-7 + s.Reg = (ModRegRM >> 3) & 7; // reg = bit 3-5 + s.RM = ModRegRM & 7; // RM = bit 0-2 + + // Check if there is a SIB byte + if (s.AddressSize > 16 && s.Mod != 3 && s.RM == 4) { + // There is a SIB byte + s.MFlags |= 4; // Remember we have a SIB byte + SIB = Buffer[s.AddressField++]; // Read SIB byte + // Get scale, index, base + s.Scale = SIB >> 6; // Scale = bit 6-7 + s.IndexReg = (SIB >> 3) & 7; // Index = bit 3-5 + s.BaseReg = SIB & 7; // Base = bit 0-2 + } + + // Check if there is a DREX byte (AMD SSE5 instructions never implemented): + if ((s.OpcodeDef->InstructionFormat & 0x1E) == 0x14) { + s.MFlags |= 8; // Remember we have a DREX byte + s.Vreg = Buffer[s.AddressField++]; // Read DREX byte + // The R,X,B bits of Vreg are equivalent to the corresponding bits of a REX prefix: + s.Prefixes[7] |= (s.Vreg & 7) | 0x80; + } + + if (s.AddressField > FunctionEnd) { + CheckForMisplacedLabel(); + } + + // Check REX prefix + if (s.Prefixes[7] & 4) s.Reg |= 8; // Add REX.R to reg field + if (s.Prefixes[7] & 1) s.RM |= 8; // Add REX.B to RM field + + // Interpretation of mod/reg/rm byte is different for 16 bit address size + if (s.AddressSize == 16) { + + if (s.Mod != 3) { + // There is a memory operand + s.MFlags |= 1; + + // Get size of address/displacement operand from mod bits + // (Will be overwritten later if none) + if (s.Mod == 1) { + s.AddressFieldSize = 1; // Size of displacement field + } + else if (s.Mod == 2) { + s.AddressFieldSize = 2; // Size of displacement field + } + + // Check if direct memory operand + if (s.Mod == 0 && s.RM == 6) { + // Direct memory operand and nothing else + s.AddressFieldSize = 2; // Size of address field + } + else { + // Indirect memory operand + // Get base and index registers + // [bx+si], [bx+di], [bp+si], [bp+di], [si], [di], [bp], [bx] + static const uint8 BaseRegister [8] = {3+1, 3+1, 5+1, 5+1, 0, 0, 5+1, 3+1}; + static const uint8 IndexRegister[8] = {6+1, 7+1, 6+1, 7+1, 6+1, 7+1, 0, 0}; + // Save register number + 1, because 0 means none. + s.BaseReg = BaseRegister [s.RM]; // Base register = BX or BP or none + s.IndexReg = IndexRegister[s.RM]; // Index register = SI or DI or none + s.Scale = 0; // No scale factor in 16 bit mode + } + } + } + else { + // Address size is 32 or 64 bits + + if (s.Mod != 3) { + // There is a memory operand + s.MFlags |= 1; + + // Get size of address/displacement operand from mod bits + // (Will be overwritten later if none) + if (s.Mod == 1) { + s.AddressFieldSize = 1; // Size of displacement field + } + else if (s.Mod == 2) { + s.AddressFieldSize = 4; // Size of displacement field + } + + // Check if direct memory operand + if (s.Mod == 0 && (s.RM & 7) == 5) { + // Direct memory operand and nothing else + s.AddressFieldSize = 4; // Size of address field + } + else if ((s.RM & 7) == 4) { + // There is a SIB byte + + // Check REX prefix + if (s.Prefixes[7] & 2) s.IndexReg |= 8; // Add REX.X to index + if (s.Prefixes[7] & 1) s.BaseReg |= 8; // Add REX.B to base + s.RM &= 7; // Remove REX.B from RM + + s.BaseReg++; // Add 1 so that 0 means none + if (s.IndexReg == 4 && (s.OpcodeDef->InstructionFormat & 0x1F) != 0x1E) { + // No index register + s.IndexReg = 0; + } + else { + s.IndexReg++; // Add 1 so that 0 means none + } + + if (s.Mod == 0 && s.BaseReg == 5+1) { + // No base register, 32 bit address + s.AddressFieldSize = 4; + s.BaseReg = 0; + } + } + else { + // Indirect memory operand and no SIB byte + s.BaseReg = s.RM; // Get base register from RM bits + s.BaseReg++; // Add 1 because 0 means none + } + } + else { + // No memory operand. Address size is 32 or 64 bits + } + // Check if rip-relative + if (WordSize == 64 && (s.MFlags & 7) == 3 && !s.BaseReg && s.AddressFieldSize == 4) { + // Memory operand is rip-relative + s.MFlags |= 0x100; + } + } + if (s.Prefixes[3] == 0x62) { + // EVEX prefix gives another extra register bit + s.Reg += ~(s.Prefixes[6]) & 0x10; // extra r bit = highest m bit + if (s.Mod == 3) { + // Register operands only. B bit extended by X bit + s.RM += (s.Prefixes[7] & 2) << 3; + } + else if (s.IndexReg && s.OpcodeDef->InstructionFormat == 0x1E) { + // VSIB byte. Index register extended by one of the v bits, base register < 16 + s.IndexReg += s.Vreg & 0x10; + } + } + } + + // Get operand size + uint32 OpSizePrefix = 0; + if (s.Prefixes[4] == 0x66 && (s.OpcodeDef->AllowedPrefixes & 0x100)) OpSizePrefix = 1; // Operand size prefix + if (s.Prefixes[4] == 0x48 && (s.OpcodeDef->AllowedPrefixes & 0x1000)) OpSizePrefix = 2; // Rex.W prefix + s.OperandSize = (WordSize == 16) ^ (OpSizePrefix & 1) ? 16 : 32; + if (OpSizePrefix == 2) s.OperandSize = 64; + if ((s.OpcodeDef->AllowedPrefixes & 0x3000) == 0x3000 && WordSize == 64 && (OpSizePrefix & 2)) s.OperandSize = 64; + + // Get any immediate operand + // Offset to immediate operand field, if any + s.ImmediateField = s.AddressField + s.AddressFieldSize; + + // Check InstructionFormat for immediate and direct operands + switch (s.OpcodeDef->InstructionFormat & 0x0FE0) { + case 0x20: // Has 2 bytes immediate operand + s.ImmediateFieldSize = 2; break; + + case 0x40: // Has 1 byte immediate operand or short jump + s.ImmediateFieldSize = 1; break; + + case 0x60: // Has 3 bytes immediate operand (enter) + s.ImmediateFieldSize = 3; break; + + case 0x80: // Has 2 or 4 bytes immediate operand or near jump/call + if ((s.OpcodeDef->Destination & 0xFE) == 0x82) { + // Near jump/call address size depends on WordSize and operand size prefix, + // but not on address size prefix + s.ImmediateFieldSize = (WordSize == 16) ^ (s.Prefixes[4] == 0x66) ? 2 : 4; + if (WordSize == 64) s.ImmediateFieldSize = 4; // 66 prefix ignored in 64 bit mode + } + else { + // Size of other immediate data depend on operand size + s.ImmediateFieldSize = (s.OperandSize == 16) ? 2 : 4; + } + break; + + case 0x100: // Has 2, 4 or 8 bytes immediate operand + s.ImmediateFieldSize = s.OperandSize / 8; + break; + + case 0x200: // Has 2+2 or 4+2 bytes far direct jump/call operand + s.ImmediateFieldSize = (WordSize == 16) ^ (s.Prefixes[4] == 0x66) ? 4 : 6; + break; + + case 0x400: // Has 2, 4 or 8 bytes direct memory operand + s.AddressFieldSize = s.AddressSize / 8; + s.AddressField = s.ImmediateField; + s.ImmediateField = s.AddressField + s.AddressFieldSize; + s.ImmediateFieldSize = 0; + break; + + default: // No immediate operand + s.ImmediateFieldSize = 0; + } + + // Find instruction end + IEnd = s.ImmediateField + s.ImmediateFieldSize; + if (IEnd > FunctionEnd) { + CheckForMisplacedLabel(); + if (IEnd > SectionEnd) { + // instruction extends outside code block + s.Errors |= 0x10; + IEnd = SectionEnd; + } + } +} + +void CDisassembler::FindBroadcast() { + // Find broadcast and offset multiplier for EVEX code + if (s.Mod != 3) { + // has memory operand + uint32 m; // find memory operand + for (m = 0; m < s.MaxNumOperands; m++) { + if (s.Operands[m] & 0x2000) break; + } + if (m == s.MaxNumOperands) return; // no memory operand found. should not occur + uint32 r; // find largest vector operand + uint32 vectortype = 0; + for (r = 0; r < s.MaxNumOperands; r++) { + if ((s.Operands[r] & 0xF00) > vectortype) vectortype = s.Operands[r] & 0xF00; + } + uint32 vectorsize = GetDataItemSize(vectortype); + if (m < s.MaxNumOperands) { + if ((s.OpcodeDef->EVEX & 1) && (s.Esss & 1)) { + // broadcasting. multiplier = element size + s.OffsetMultiplier = GetDataElementSize(s.Operands[m]); + // operand size = element size + s.Operands[m] &= ~0xF00; + if (s.OffsetMultiplier >= vectorsize) { + s.Warnings2 |= 0x200; // broadcasting to scalar + } + } + else if (s.OpcodeDef->EVEX & 0x1000) { + // multiplier = element size, not broadcasting + s.OffsetMultiplier = GetDataElementSize(s.Operands[m]); + } + else if (s.OpcodeDef->EVEX & 0x2000) { + // multiplier = fraction of largest vector size + s.OffsetMultiplier = vectorsize >> ((s.OpcodeDef->EVEX & 0x600) >> 9); + } + else { + // not broadcasting. multiplier = vector size + s.OffsetMultiplier = GetDataItemSize(s.Operands[m]); + } + } + } +} + + +void CDisassembler::SwizTableLookup() { + // Find the swizzle table record that correspond to the instruction and the sss bits for MVEX instructions + int sw = (s.OpcodeDef->MVEX & 0x1F); // swizzle metatable index + int opsize = 0; // operand size override + if (s.OpcodeDef->Options & 1) { + // operand size depends on prefix bits + if (s.OpcodeDef->AllowedPrefixes & 0x1000) { + // operand size depends on W bit + if (s.Prefixes[7] & 8) opsize = 1; + } + else if (s.OpcodeDef->AllowedPrefixes & 0x300) { + // operand size depends on 66 implied prefix + if (s.Prefixes[5] == 0x66) opsize = 1; + } + } + int IsMem = s.Mod != 3; // has memory operand + // find record in swizzle tables + s.SwizRecord = &(SwizTables[sw | opsize][IsMem][s.Esss & 7]); + // find offset multiplier + if (s.OpcodeDef->MVEX & 0x40) { + // address single element + s.OffsetMultiplier = s.SwizRecord->elementsize; + } + else { + // address vector or subvector + s.OffsetMultiplier = s.SwizRecord->memopsize; + if (s.OffsetMultiplier == 0) { + // no swizzle, use vector size + uint16 source = s.OpcodeDef->Source2; // last source operand + if (!(source & 0xF00)) source = s.OpcodeDef->Source1; // if source2 is not a vector, use source1 + switch ((source >> 8) & 0xF) { + case 2: + // vector size depends on prefixes, currently only zmm supported when EVEX prefix is present + s.OffsetMultiplier = 0x40; break; + case 4: + s.OffsetMultiplier = 0x10; break; + case 5: + s.OffsetMultiplier = 0x20; break; + case 6: + s.OffsetMultiplier = 0x40; break; + } + } + } +} + +void CDisassembler::FindOperandTypes() { + // Determine the type of each operand + uint32 i, j, k; // Operands index + int nimm = 0; // Number of immediate operands + uint32 AllowedPref = s.OpcodeDef->AllowedPrefixes; + uint32 oper; // current operand definition + + s.MaxNumOperands = 4; // may be 5 in the future in cases where EVEX field is used as an extra operand + + // Copy all operands from opcode map and zero-extend + for (i = 0; i < s.MaxNumOperands; i++) { + s.Operands[i] = (&s.OpcodeDef->Destination)[i]; + } + + // Check instruction format + switch (s.OpcodeDef->InstructionFormat & 0x1F) { + + case 2: // No operands or only immediate operand + break; + + case 3: // Register operand indicated by bits 0-2 of opcode + // Find which of the operands it applies to + if ((s.Operands[0] & 0xFF) > 0 && (s.Operands[0] & 0xFF) < 0xB) i = 0; else i = 1; + // Indicate this operand uses opcode bits + s.Operands[i] |= 0x20000; + break; + + case 4: // Register operand indicated by VEX.vvvv bits + // Find which of the operands it applies to + if ((s.Operands[0] & 0xFF) < 0xB || (s.Operands[0] & 0xFF) == 0x95) i = 0; else i = 1; + // Indicate this operand uses VEX.vvvv bits + s.Operands[i] |= 0x60000; + break; + + case 0x11: // There is a mod/reg/rm byte and one operand + // Find which of the operands it applies to + for (j = k = 0; j < 2; j++) { + if (s.Operands[j]) { + switch (s.Operands[j] & 0xF0) { + case 0: case 0x40: case 0x50: + // This operand can have use rm bits + k |= j+1; + } + } + } + if (k < 1 || k > 2) { + // There must be one, and only one, operand that can use rm bits + s.Errors |= 0x80000; // Error in opcode table + } + else { + // Indicate this operand uses mod and rm bits + s.Operands[k-1] |= 0x30000; + } + break; + + case 0x12: // There is a mod/reg/rm byte and two operands. Destination is reg + // Destination operand uses s.Reg bits + s.Operands[0] |= 0x40000; + // Source operand uses mod and rm bits + s.Operands[1] |= 0x30000; + break; + + case 0x13: // There is a mod/reg/rm byte and two operands. Source is reg + // Destination operand uses mod and rm bits + s.Operands[0] |= 0x30000; + // Source operand uses s.Reg bits + s.Operands[1] |= 0x40000; + break; + + case 0x14: case 0x15: { // There is a DREX byte and three or four operands + // Combine OC0 from DREX byte and OC1 from opcode byte into Operand configuration + int OperandConfiguration = ((s.Vreg >> 3) & 1) | ((Get(s.OpcodeStart2) >> 1) & 2); + // Determine operands + s.Operands[0] |= 0x50000; // Destination determined by dest field of DREX byte + if (s.OpcodeDef->InstructionFormat & 1) { + // Four XMM or register operands + switch (OperandConfiguration) { + case 0: + s.Operands[1] = s.Operands[0]; // 1. source = same as destination + s.Operands[2] |= 0x40000; // 2. source = reg + s.Operands[3] |= 0x30000; // 3. source = rm + break; + case 1: + s.Operands[1] = s.Operands[0]; // 1. source = same as destination + s.Operands[2] |= 0x30000; // 2. source = rm + s.Operands[3] |= 0x40000; // 3. source = reg + break; + case 2: + s.Operands[1] |= 0x40000; // 1. source = reg + s.Operands[2] |= 0x30000; // 2. source = rm + s.Operands[3] = s.Operands[0]; // 3. source = same as destination + break; + case 3: + s.Operands[1] |= 0x30000; // 1. source = rm + s.Operands[2] |= 0x40000; // 2. source = reg + s.Operands[3] = s.Operands[0]; // 3. source = same as destination + break; + } + } + else { + // Three XMM or register operands + if ((OperandConfiguration & 1) == 0) { + // OC0 = 0 + s.Operands[1] |= 0x40000; // 1. source = reg + s.Operands[2] |= 0x30000; // 2. source = rm + } + else { + // OC0 = 1 + s.Operands[1] |= 0x30000; // 1. source = rm + s.Operands[2] |= 0x40000; // 2. source = reg + } + } + break;} + + case 0x18: // Has VEX prefix and 2 operands + // Dest = VEX.vvvv, src = rm, opcode extension in r bits. + // Destination operand uses VEX.vvvv bits + s.Operands[0] |= 0x60000; + // Source1 operand uses mod and rm bits + s.Operands[1] |= 0x30000; + if (!(s.Prefixes[7] & 0xB0)) { + // One operand omitted if no VEX prefix + s.Operands[0] = s.Operands[1]; s.Operands[1] = 0; + } + break; + + case 0x19: // Has VEX prefix and 3 operands + // Dest = r, src1 = VEX.vvvv, src2 = rm. + s.Operands[0] |= 0x40000; + s.Operands[1] |= 0x60000; + s.Operands[2] |= 0x30000; + if (!(s.Prefixes[7] & 0xB0)) { + // One source operand omitted if no VEX prefix + s.Operands[1] = s.Operands[2]; s.Operands[2] = 0; + } + // Preliminary AMD specification + if ((AllowedPref & 0x7000) == 0x7000 && !(s.Prefixes[7] & 8)) { + // Swap src1 and src2 if XOP prefix and XOP.W = 0 + k = s.Operands[1]; s.Operands[1] = s.Operands[2]; s.Operands[2] = k; + } + break; + + case 0x1A: // Has VEX prefix and 3 operands. + // Dest = rm, src1 = VEX.v, src2 = r + s.Operands[0] |= 0x30000; + s.Operands[1] |= 0x60000; + s.Operands[2] |= 0x40000; + if (!(s.Prefixes[7] & 0xB0)) { + // One source operand omitted if no VEX prefix + s.Operands[1] = s.Operands[2]; s.Operands[2] = 0; + } + break; + + case 0x1B: // Has VEX prefix and 3 operands + // Dest = r, src1 = rm, src2 = VEX.vvvv + s.Operands[0] |= 0x40000; + s.Operands[1] |= 0x30000; + s.Operands[2] |= 0x60000; + if (!(s.Prefixes[7] & 0xB0)) { + // Last source operand omitted if no VEX prefix + s.Operands[2] = 0; + } + break; + + case 0x1C: // Has VEX prefix and 4 operands + // Dest = r, src1 = VEX.v, src2 = rm, src3 = bits 4-7 of immediate byte + s.Operands[0] |= 0x40000; + s.Operands[1] |= 0x60000; + s.Operands[2] |= 0x30000; + s.Operands[3] |= 0x70000; + if ((s.Prefixes[7] & 8) && (AllowedPref & 0x7000) == 0x7000) { + // Swap src2 and src3 if VEX.W + k = s.Operands[2]; s.Operands[2] = s.Operands[3]; s.Operands[3] = k; + } + nimm++; // part of immediate byte used + break; + + case 0x1D: // Has VEX prefix and 4 operands + // Dest = r, src1 = bits 4-7 of immediate byte, src2 = rm, src3 = VEX.vvvv + s.Operands[0] |= 0x40000; + s.Operands[1] |= 0x70000; + s.Operands[2] |= 0x30000; + s.Operands[3] |= 0x60000; + if ((s.Prefixes[7] & 8) && (AllowedPref & 0x7000) == 0x7000) { + // Swap src2 and src3 if VEX.W + k = s.Operands[2]; s.Operands[2] = s.Operands[3]; s.Operands[3] = k; + } + nimm++; // part of immediate byte used + break; + + case 0x1E: // Has VEX prefix, VSIB and 1, 2 or 3 operands. + if (s.Operands[0] & 0x2000) { + // destination is memory + // Dest = rm, src1 = r + s.Operands[0] |= 0x30000; + s.Operands[1] |= 0x40000; + //if (s.Operands[2]) s.Operands[2] |= 0x60000; + } + else { + // Dest = r, src1 = rm, src2 = VEX.v + if (s.Operands[0]) s.Operands[0] |= 0x40000; + s.Operands[1] |= 0x30000; + if (s.Operands[2]) s.Operands[2] |= 0x60000; + } + break; + + default: // No explicit operands. + // Check for implicit memory operands + for (i = 0; i < 2; i++) { + if (s.Operands[i] & 0x2000) { + // Direct memory operand + s.Operands[i] |= 0x10000; + if (s.OpcodeDef->InstructionFormat > 1) { + // There is an address field + s.AddressFieldSize = s.AddressSize / 8; + s.AddressField = s.OpcodeStart2 + 1; + s.MFlags |= 1; // Remember we have a memory operand + } + } + } + break; + } + + // Loop for destination and source operands + for (i = 0; i < s.MaxNumOperands; i++) { + // Ignore empty operands + if (s.Operands[i] == 0) continue; + + // Immediate operands + if ((s.Operands[i] & 0xFF) >= 0x10 && (s.Operands[i] & 0xFF) < 0x40) { + if (nimm++) { + s.Operands[i] |= 0x200000; // second immediate operand + } + else { + s.Operands[i] |= 0x100000; // first immediate operand + } + } + + // Check if register or memory + switch (s.Operands[i] & 0x3000) { + case 0x1000: // Must be register + if ((s.Operands[i] & 0xF0000) == 0x30000 && s.Mod != 3 && (s.OpcodeDef->InstructionFormat & 0x10)) { + s.Errors |= 8; // Is memory. Indicate wrong operand type + s.Operands[i] = (s.Operands[i] & ~0x1000) | 0x2000;// Indicate it is memory + } + break; + + case 0x2000: // Must be memory operand + if ((s.Operands[i] & 0xD0000) != 0x10000 || s.Mod == 3) { + s.Errors |= 8; // Is register. Indicate wrong operand type + s.Operands[i] = (s.Operands[i] & ~0x2000) | 0x1000; // Indicate it is register + } + break; + + case 0x0000: // Can be register or memory + if ((s.Operands[i] & 0xF0000) == 0x10000) { + // Direct memory operand + s.Operands[i] |= 0x2000; break; + } + if ((s.Operands[i] & 0xF0000) == 0x30000) { + // Indicated by mod/rm bits + if (s.Mod == 3) { + s.Operands[i] |= 0x1000; // Is register + } + else { + s.Operands[i] |= 0x2000; // Is memory + } + break; + } + if ((s.Operands[i] & 0xF0) != 0x10) { // Not a constant + s.Operands[i] |= 0x1000; // Anything else is register + } + break; + } + + // Resolve types that depend on prefixes or WordSize + switch (s.Operands[i] & 0xFF) { + case 8: case 0x18: case 0x28: case 0x38: case 0xA8: + // 16 or 32 bits + s.Operands[i] &= ~0x0F; + s.Operands[i] |= (s.OperandSize == 16) ? 2 : 3; + break; + + case 9: case 0x19: case 0x29: case 0x39: case 0xA9: + // 8, 16, 32 or 64 bits, depending on operand size prefixes + s.Operands[i] &= ~0x0F; + switch (AllowedPref & 0x7000) { + case 0x3000: default: // 32 or 64 depending on mode and 66 or REX.W prefix + s.Operands[i] |= (s.OperandSize == 16) ? 2 : ((s.OperandSize == 64) ? 4 : 3); + break; + case 0x4000: // VEX.W prefix determines integer (vector) operand size b/w + if ((s.Prefixes[7] & 8) == 0) { // W bit + s.OperandSize = 8; + s.Operands[i] |= 1; + } + else { + s.OperandSize = 16; + s.Operands[i] |= 2; + } + break; + case 0x5000: // VEX.W and 66 prefix determines integer operand size b/w/d/q (mask instructions. B = 66W0, W = _W0, D = 66W1, Q = _W1) + s.Operands[i] |= (s.Prefixes[5] != 0x66) + ((s.Prefixes[7] & 8) >> 2) + 1; + break; + } + break; + + case 0xB: case 0xC: // 16, 32 or 64 bits. Fixed size = 64 in 64 bit mode + s.Operands[i] &= ~0x0F; + if (WordSize == 64) { + s.Operands[i] |= 4; + } + else { + s.Operands[i] |= (s.OperandSize == 16) ? 2 : 3; + } + break; + + case 0xA: // 16, 32 or 64 bits. Default size = 64 in 64 bit mode + s.Operands[i] &= ~0x0F; + if (WordSize == 64) { + s.Operands[i] |= (s.OperandSize == 16) ? 2 : 4; + } + else { + s.Operands[i] |= (s.OperandSize == 16) ? 2 : 3; + } + break; + + case 0xD: // 16+16, 32+16 or 64+16 bits far indirect pointer (jump or call) + s.Operands[i] &= ~0x0F; + s.Operands[i] |= (s.OperandSize == 16) ? 3 : ((s.OperandSize == 64) ? 5 : 7); + break; + + case 0x4F: // XMM float. Size and precision depend on prefix bits + s.Operands[i] &= ~0x7F; // remove type + if ((AllowedPref & 0x1000) && !((AllowedPref & 0xF00) == 0xE00)) { + // precision depends on VEX.W bit + if (s.Prefixes[7] & 8) { + s.Operands[i] |= 0x4C; + } + else { + s.Operands[i] |= 0x4B; + } + } + else { + // Size and precision depend on prefix: none = ps, 66 = pd, F2 = sd, F3 = ss + switch (s.Prefixes[5]) { + case 0: // No prefix = ps + s.Operands[i] |= 0x4B; break; + case 0x66: // 66 prefix = pd + s.Operands[i] |= 0x4C; break; + case 0xF3: // F3 prefix = ss + s.Operands[i] |= 0x4B; + s.Operands[i] &= ~0xF00; // make scalar + break; + case 0xF2: // F2 prefix = sd + s.Operands[i] |= 0x4C; + s.Operands[i] &= ~0xF00; // make scalar + break; + }; + break; + } + } + + // Resolve vector size + switch (s.Operands[i] & 0xF00) { + case 0x100: // MMX or XMM or YMM or ZMM depending on 66 prefix and VEX.L prefix and EVEX prefix + case 0x200: // XMM or YMM or ZMM depending on prefixes + case 0xF00: // Half the size defined by VEX.L prefix and EVEX.LL prefix. Minimum size = 8 bytes for memory, xmm for register + + oper = s.Operands[i] & ~0xF00; // element type + if (s.Prefixes[3] == 0x62) { // EVEX or MVEX prefix + if (s.Prefixes[6] & 0x20) { + // EVEX prefix + // Do LL bits specify vector size when b = 1 for instructions that allow + // sae but not rounding? Perhaps not, because sae is only allowed for + // 512 bit vectors, but manual says otherwise. + // NASM version 2.11.06 sets LL = 0 when b = 1 for vrangeps instruction + //??if ((s.OpcodeDef->EVEX & 4) && (s.Mod == 3) && (s.Esss & 1)) { + if ((s.OpcodeDef->EVEX & 6) && (s.Mod == 3) && (s.Esss & 1)) { + // rounding control, register operand. L'L do not indicate vector size + oper |= 0x600; // zmm + } + else if (s.OpcodeDef->EVEX & 8) { + // scalar + oper |= 0x400; // xmm + } + else { + // L'L indicates vector size + oper |= 0x400 + ((s.Esss & 6) << 7); // xmm, ymm, zmm, + } + } + else { + // MVEX prefix + oper |= 0x600; // zmm + } + } + else if (s.Prefixes[6] & 0x20) { + oper |= 0x500; // VEX.L: ymm + } + else if (s.Prefixes[5] == 0x66 || (s.Operands[i] & 0x200)) { + oper |= 0x400; // 66 prefix or mm not allowed: xmm + } + else { + oper |= 0x300; // no prefix: mm + } + if ((s.Operands[i] & 0xF00) == 0xF00) { + // half size vector + oper -= 0x100; + if ((oper & 0x1000) || (s.OpcodeDef->InstructionFormat == 0x1E)) { + // is register or vsib index. minimum size is xmm + if ((oper & 0xF00) < 0x400) { + oper = (oper & ~0x300) | 0x400; + } + } + } + s.Operands[i] = oper; // save corrected vector size + + break; + } + + // resolve types that depend on MVEX swizzle + if ((s.Prefixes[6] & 0x60) == 0x40 && (s.Operands[i] & 0xF0000) == 0x30000) { + int sw = (s.OpcodeDef->MVEX & 0x1F); + if (sw) { + int optype = s.SwizRecord ? s.SwizRecord->memop : 0; //? + if (s.OpcodeDef->InstructionFormat == 0x1E) { + // vsib addressing: s.Operands[i] & 0xF00 indicates index register size, s.Operands[i] & 0xFF indicates operand size + s.Operands[i] = (s.Operands[i] & ~0xFF) | (optype & 0xFF); + } + else if (s.OpcodeDef->MVEX & 0x40) { + // operand is not a full vector + s.Operands[i] = (s.Operands[i] & ~0xFFF) | (optype & 0xFF); + } + else { + // get operand type from swizzle table only + if (optype) s.Operands[i] = optype | 0x30000; + } + } + } + } +} + + +void CDisassembler::FindWarnings() { + // Find any reasons for warnings in code + uint32 i; // Operand index + uint32 OperandSize; // Operand size + uint8 RexBits = 0; // Bits in REX prefix + + if ((s.OpcodeDef->Options & 0x80) && s.ImmediateFieldSize > 1 && s.ImmediateRelocation == 0) { + // Check if sign-extended operand can be used + if ((s.ImmediateFieldSize == 2 && Get(s.ImmediateField) == Get(s.ImmediateField)) + || (s.ImmediateFieldSize == 4 && Get(s.ImmediateField) == Get(s.ImmediateField))) { + s.Warnings1 |= 1; // Sign-extended operand could be used + } + } + if (WordSize == 64 && s.ImmediateFieldSize == 8 && s.ImmediateRelocation == 0) { + // We have a 64 bit immediate operand. Could it be made shorter? + if (Get(s.ImmediateField+4) == 0) { + s.Warnings1 |= 2; // Upper half is zero. Could use zero-extension + } + else if (Get(s.ImmediateField) == Get(s.ImmediateField)) { + s.Warnings1 |= 1; // Could use sign-extension + } + } + // Check if displacement could be made smaller + if (s.AddressFieldSize > 0 && s.AddressRelocation == 0 + && (s.BaseReg || (s.IndexReg && !s.BaseReg && s.Scale < 2)) + && s.OffsetMultiplier <= 1) { + // There is a displacement which might be unnecessary + switch (s.AddressFieldSize) { + case 1: // 1 byte displacement + if (Get(s.AddressField) == 0 + && (((s.BaseReg-1) & 7) != 5 || (s.AddressSize == 16 && s.IndexReg))) + s.Warnings1 |= 4; // Displacement is 0 and an addressing mode without displacement exists + break; + case 2: // 2 bytes displacement + if (Get(s.AddressField) == 0) s.Warnings1 |= 4; // Displacement is 0 + else if (Get(s.AddressField) == Get(s.AddressField)) s.Warnings1 |= 8; // Could use sign extension + break; + case 4: // 4 bytes displacement + if (s.OpcodeDef->InstructionFormat != 0x1E) { + if (Get(s.AddressField) == 0) s.Warnings1 |= 4; // Displacement is 0 + else if (Get(s.AddressField) == Get(s.AddressField)) s.Warnings1 |= 8; // Could use sign extension + } + break; + case 8: // 8 bytes displacement + if (Get(s.AddressField) == Get(s.AddressField)) + // Has 8 bytes displacement. Could use sign-extended or rip-relative + s.Warnings1 |= 8; + break; + } + } + // Check for unnecessary SIB byte + if ((s.MFlags&4) && (s.BaseReg&7)!=4+1 && (s.IndexReg==0 || (s.BaseReg==0 && s.Scale==0))) { + if (WordSize == 64 && s.BaseReg==0 && s.IndexReg==0) s.Warnings1 |= 0x4000; // 64-bit address not rip-relative + else if ((s.Operands[0] & 0xFF) != 0x98 && (s.Operands[1] & 0xFF) != 0x98 && s.OpcodeDef->InstructionFormat != 0x1E) { // ignore if bounds register used or vsib + s.Warnings1 |= 0x10; // Unnecessary SIB byte + } + } + // Check if shorter instruction exists for register operands + if ((s.OpcodeDef->Options & 0x80) && !(s.OpcodeDef->InstructionFormat & 0xFE0) && s.Mod == 3 + && !(WordSize == 64 && Get(s.OpcodeStart1) == 0xFF)) { + s.Warnings1 |= 0x20; // No memory operand. A shorter version exists for register operand + } + // Check for length-changing prefix + if (s.ImmediateFieldSize > 1 && s.Prefixes[4] == 0x66 + && (s.OpcodeDef->AllowedPrefixes & 0x100) && !(s.OpcodeDef->InstructionFormat & 0x20)) { + // 66 prefix changes length of immediate field + s.Warnings1 |= 0x40; + } + // Check for bogus length-changing prefix causing stall on Intel Core2. + // Will occur if 66 prefix and first opcode byte is F7 and there is a 16 bytes boundary between opcode byte and mod/reg/rm byte + if (Get(s.OpcodeStart1) == 0xF7 && s.Prefixes[4] == 0x66 && ((s.OpcodeStart1+1) & 0xF) == 0 && !s.ImmediateFieldSize) { + s.Warnings1 |= 0x2000000; + } + // Warn for address size prefix if mod/reg/rm byte + // (This does not cause a stall in 64 bit mode, but I am issueing a + // warning anyway because the changed address size is probably unintended) + if (s.Prefixes[1] == 0x67 && (s.MFlags & 2)) { + s.Warnings1 |= 0x80; + } + // Check for unnecessary REX.W prefix + if ((s.OpcodeDef->AllowedPrefixes & 0x7000) == 0x2000 && s.Prefixes[7] == 0x48) { + s.Warnings1 |= 0x200; // REX.W prefix valid but unnecessary + } + // Check for meaningless prefixes + if (!(s.OpcodeDef->InstructionFormat & 0x10) || s.Mod == 3) { + // No mod/reg/rm byte or only register operand. Check for address size and segment prefixes + if ((s.Prefixes[0] && !(s.OpcodeDef->AllowedPrefixes & 0xC)) + || (s.Prefixes[1] && !(s.OpcodeDef->AllowedPrefixes & 3))) { + s.Warnings1 |= 0x400; // Unnecessary segment or address size prefix + } + } + + // Check for meaningless segment prefixes + if (s.Prefixes[0] && !(s.OpcodeDef->AllowedPrefixes & 0x0C)) { + // Segment prefix is not branch hint + if (WordSize == 64 && (s.Prefixes[0] & 0x02)) + s.Warnings1 |= 0x400; // CS, DS, ES or SS prefix in 64 bit mode has no effect + if (s.Prefixes[0] == 0x3E && s.BaseReg != 4+1 && s.BaseReg != 5+1) + s.Warnings1 |= 0x400; // Unnecessary DS: segment prefix + if (s.Prefixes[0] == 0x36 && (s.BaseReg == 4+1 || s.BaseReg == 5+1) ) + s.Warnings1 |= 0x400; // Unnecessary SS: segment prefix + if (Opcodei == 0x8D) + s.Warnings1 |= 0x400; // Segment prefix on LEA instruction + if (s.Mod == 3) + s.Warnings1 |= 0x400; // mod/reg/rm byte indicates no memory operand + } + + // Check for meaningless 66 prefix + if (s.Prefixes[4] == 0x66 && !(s.OpcodeDef->AllowedPrefixes & 0x380)) + s.Warnings1 |= 0x400; // 66 prefix not allowed here + + // Check for meaningless F2 prefix + if (s.Prefixes[3] == 0xF2 && !(s.OpcodeDef->AllowedPrefixes & 0x868)) + s.Warnings1 |= 0x400; // F2 prefix not allowed here + + // Check for meaningless F3 prefix + if (s.Prefixes[3] == 0xF3 && !(s.OpcodeDef->AllowedPrefixes & 0x460)) + s.Warnings1 |= 0x400; // F3 prefix not allowed here + + // Check for meaningless REX prefix bits + if (s.Prefixes[7]) { + // REX, VEX, XOP or DREX present + // Get significant bits + RexBits = s.Prefixes[7] & 0x0F; + // Check if empty REX prefix + if (RexBits == 0 && (s.Prefixes[7] & 0x40) && (s.Operands[0] & 0xFF) != 1 && (s.Operands[1] & 0xFF) != 1) { + // Empty REX prefix needed only if 8 bit register register + s.Warnings1 |= 0x400; + } + // Clear bits that are used: + // Check if REX.W bit used + if (s.OpcodeDef->AllowedPrefixes & 0x3000) RexBits &= ~8; + // Check if REX.R and REX.B bit used for source or destination operands + for (i = 0; i < 4; i++) { + switch (s.Operands[i] & 0xF0000) { + case 0x40000: // uses reg bits, check if REX.R allowed + if ((s.Operands[i] & 0xF00) != 0x300 && (s.Operands[i] & 0x58) != 0x40 && (s.Operands[i] & 0xFF) != 0x91) + // REX.R used for operand and register type allows value > 7 + RexBits &= ~4; + break; + case 0x30000: // Uses rm bits. check if REX.B allowed + if ((s.Operands[i] & 0xF00) != 0x300 && (s.Operands[i] & 0x58) != 0x40 && (s.Operands[i] & 0xFF) != 0x91) + // REX.B used for operand and register type allows value > 7 + RexBits &= ~1; + break; + case 0x20000: // Register operand indicated by opcode bits and REX:B + RexBits &= ~1; + break; + } + } + // Check if REX.X bit used for index register + if (s.IndexReg) RexBits &= ~2; + // Check if REX.B bit used for base register + if (s.BaseReg) RexBits &= ~1; + // Check if REX.X bit used for base register with EVEX prefix + if (s.Prefixes[3] == 0x62 && s.Mod == 3) RexBits &= ~2; + + // Check if VEX.W bit used for some purpose + if ((s.OpcodeDef->AllowedPrefixes & 0x7000) != 0 && (s.Prefixes[7] & 0xB0)) RexBits &= ~8; + + // Any unused bits left? + if (RexBits) { + s.Warnings1 |= 0x400; // At least one REX bit makes no sense here + } + } + // Check for registers not allowed in 32-bit mode + if (this->WordSize < 64) { + if (s.Prefixes[7] & 7 & ~RexBits) { + s.Errors |= 0x200; // Register 8-15 not allowed in this mode + } + if (s.Prefixes[7] & 0xB0) { + // VEX present, check vvvv register operand + if (s.Vreg & 8) s.Errors |= 0x200; // Register 8-15 not allowed in this mode + // Check imm[7:4] register operand + if ((s.OpcodeDef->InstructionFormat & 0x1E) == 0x1C && (Get(s.ImmediateField) & 8)) { + s.Errors |= 0x200; // Register 8-15 not allowed in this mode + } + } + } + + // Check for meaningless VEX prefix bits + if (s.Prefixes[7] & 0xB0) { + // VEX present + if ((s.Prefixes[6] & 0x60) == 0x20) { // VEX.L bit set and not EVEX + if (!(s.OpcodeDef->AllowedPrefixes & 0x240000)) s.Warnings1 |= 0x40000000; // L bit not allowed + if ((s.OpcodeDef->AllowedPrefixes & 0x200000) && s.Prefixes[5] > 0x66) s.Warnings1 |= 0x40000000; // L bit not allowed with F2 and F3 prefix + } + else { + if ((s.OpcodeDef->AllowedPrefixes & 0x100000) && !(s.Prefixes[6] & 0x20)) s.Warnings1 |= 0x1000; // L bit missing + } + if ((s.Prefixes[6] & 0x10) && s.Prefixes[3] != 0x62) { + s.Warnings1 |= 0x40000000; // Uppermost m bit only allowed if EVEX prefix + } + // check VEX.v bits + if (s.Prefixes[3] == 0x62 && s.OpcodeDef->InstructionFormat == 0x1E) { + // has EVEX VSIB address + if (s.Vreg & 0xF) { + s.Warnings1 |= 0x40000000; // vvvv bits not allowed, v' bit allowed + } + } + else { // not EVEX VSIB + if ((s.Vreg & 0x1F) && !(s.OpcodeDef->AllowedPrefixes & 0x80000)) { + s.Warnings1 |= 0x40000000; // vvvvv bits not allowed + } + } + } + // Check for meaningless EVEX and MVEX prefix bits + if (s.Prefixes[3] == 0x62) { + if (s.Prefixes[6] & 0x20) { + // EVEX prefix + if (s.Mod == 3) { + // register operands + if (!(s.OpcodeDef->EVEX & 6) && (s.Esss & 1)) { + s.Warnings2 |= 0x40; // rounding and sae not allowed + } + } + else { + // memory operand + if (!(s.OpcodeDef->EVEX & 1) && (s.Esss & 1)) { + s.Warnings2 |= 0x40; // broadcast not allowed + } + } + if (!(s.OpcodeDef->EVEX & 0x30) && s.Kreg) { + s.Warnings2 |= 0x40; // masking not allowed + } + else if (!(s.OpcodeDef->EVEX & 0x20) && (s.Esss & 8)) { + s.Warnings2 |= 0x40; // zeroing not allowed + } + else if ((s.OpcodeDef->EVEX & 0x40) && s.Kreg == 0) { + s.Warnings2 |= 0x100; // mask register must be nonzero + } + } + else { + // MVEX prefix. + if (s.Mod == 3) { + // register operands only + if ((s.Esss & 8) && (s.OpcodeDef->MVEX & 0x600) == 0) { + s.Warnings2 |= 0x80; // E bit not allowed for register operand here + } + } + if (((s.OpcodeDef->MVEX & 0x1F) == 0) && (s.Esss & 7) != 0) { + s.Warnings2 |= 0x80; // sss bits not allowed here + } + if (s.Kreg && (s.OpcodeDef->MVEX & 0x3000) == 0) { + s.Warnings2 |= 0x80; // kkk bits not allowed here + } + } + } + + // Check for conflicting prefixes + if (s.OpcodeDef->AllowedPrefixes & 0x140) s.Conflicts[5] = 0; // 66 + F2/F3 allowed for string instructions + if ((s.OpcodeDef->AllowedPrefixes & 0x1200) == 0x1200) s.Conflicts[4] = 0; // 66 + REX.W allowed for e.g. movd/movq instruction + if (*(int64*)&s.Conflicts) s.Warnings1 |= 0x800; // Conflicting prefixes. Check all categories at once + + // Check for missing prefixes + if ((s.OpcodeDef->AllowedPrefixes & 0x8000) && s.Prefixes[5] == 0) + s.Warnings1 |= 0x1000; // Required 66/F2/F3 prefix missing + if ((s.OpcodeDef->AllowedPrefixes & 0x20000) && (s.Prefixes[7] & 0xB0) == 0) + s.Warnings1 |= 0x1000; // Required VEX prefix missing + + // Check for VEX prefix not allowed + if (!(s.OpcodeDef->AllowedPrefixes & 0xC30000) && (s.Prefixes[7] & 0xB0)) + s.Warnings1 |= 0x40000000; // VEX prefix not allowed + + // Check for EVEX and MVEX prefix allowed + if (s.Prefixes[3] == 0x62) { + + if (s.Prefixes[6] & 0x20) { + if (!(s.OpcodeDef->AllowedPrefixes & 0x800000)) s.Warnings2 |= 0x10; + } + else { + if (!(s.OpcodeDef->AllowedPrefixes & 0x400000)) s.Warnings2 |= 0x20; + } + } + + // Check for unused SIB scale factor + if (s.Scale && s.IndexReg == 0) s.Warnings1 |= 0x2000; // SIB has scale factor but no index register + + // Check if address in 64 bit mode is rip-relative + if (WordSize == 64 && s.AddressFieldSize >= 4 && s.AddressRelocation && !(s.MFlags & 0x100)) { + // 32-bit address in 64 bit mode is not rip-relative. Check if image-relative + if (s.AddressRelocation >= Relocations.GetNumEntries() || !(Relocations[s.AddressRelocation].Type & 0x14)) { + // Not image-relative or relative to reference point + if (s.AddressFieldSize == 8) { + s.Warnings1 |= 0x20000000; // Full 64-bit address + } + else { + s.Warnings1 |= 0x4000; // 32-bit absolute address + } + } + } + // Check if direct address is relocated + if (s.AddressFieldSize > 1 && !s.AddressRelocation && !s.BaseReg && !s.IndexReg && (WordSize != 16 || !(s.Prefixes[0] & 0x40))) + s.Warnings1 |= 0x8000; // Direct address has no relocation, except FS: and GS: + + // Check if address relocation type is correct + if (s.AddressFieldSize > 1 && s.AddressRelocation && (s.MFlags & 1)) { + // Memory operand found. Should it be direct or self-relative + if (s.MFlags & 0x100) { + // Memory address should be self-relative (rip-relative) + if (!(Relocations[s.AddressRelocation].Type & 2)) { + s.Warnings1 |= 0x10000; // rip-relative relocation expected but not found + } + } + else { + // Memory address should be direct + if (Relocations[s.AddressRelocation].Type & 0x302) { + s.Warnings1 |= 0x10000; // direct address expected, other type found + } + } + + // Check if memory address has correct alignment + // Loop through destination and source operands + for (i = 0; i < s.MaxNumOperands; i++) { + // Operand type + uint32 OperandType = s.Operands[i]; + if ((OperandType & 0x2000) && Opcodei != 0x8D) { + // This is a memory operand (except LEA). Get target offset + int64 TargetOffset = 0; + switch (s.AddressFieldSize) { + case 1: + TargetOffset = Get(s.AddressField); break; + case 2: + TargetOffset = Get(s.AddressField); break; + case 4: + TargetOffset = Get(s.AddressField); + if (s.MFlags & 0x100) { + // Compute rip-relative address + TargetOffset += IEnd - s.AddressField; + } + break; + case 8: + TargetOffset = Get(s.AddressField); break; + } + // Add relocation offset + TargetOffset += Relocations[s.AddressRelocation].Addend; + + // Find relocation target + uint32 SymbolOldIndex = Relocations[s.AddressRelocation].TargetOldIndex; + uint32 SymbolNewIndex = Symbols.Old2NewIndex(SymbolOldIndex); + if (SymbolNewIndex) { + // Add relocation target offset + TargetOffset += Symbols[SymbolNewIndex].Offset; + // Target section + int32 TargetSection = Symbols[SymbolNewIndex].Section; + if (TargetSection && (uint32)TargetSection < Sections.GetNumEntries()) { + // Add relocation section address + TargetOffset += Sections[TargetSection].SectionAddress; + } + if ((Relocations[s.AddressRelocation].Type & 0x10) && Relocations[s.AddressRelocation].RefOldIndex) { + // Add offset of reference point + uint32 RefIndex = Symbols.Old2NewIndex(Relocations[s.AddressRelocation].RefOldIndex); + TargetOffset += Symbols[RefIndex].Offset; + } + if (Relocations[s.AddressRelocation].Type & 0x3000) { + // GOT entry etc. Can't check alignment + continue; + } + } + + // Get operand size + OperandSize = GetDataItemSize(OperandType); + if (s.OffsetMultiplier) OperandSize = s.OffsetMultiplier; + while (OperandSize & (OperandSize-1)) { + // Not a power of 2. Get nearest lower power of 2 + OperandSize = OperandSize & (OperandSize-1); + } + + // Check if aligned + if ((TargetOffset & (OperandSize-1)) && !(s.Warnings1 & 0x10000)) { + // Memory operand is misaligned + if (s.OffsetMultiplier) { + // EVEX code with required alignment + s.Warnings1 |= 0x800000; // Serious. Generates fault + } + else if (OperandSize < 16) { + // Performance penalty but no fault + s.Warnings1 |= 0x400000; // Warn not aligned + } + else { + // XMM or larger. May generate fault + // with VEX: only explicitly aligned instructions generate fault + // without VEX: all require alignment except explicitly unaligned + if (s.OpcodeDef->Options & 0x100 || (!(s.Prefixes[7] & 0xB0) && !(s.OpcodeDef->Options & 0x200))) { + s.Warnings1 |= 0x800000; // Serious. Generates fault + } + else { + s.Warnings1 |= 0x400000; // Not serious. Performance penalty only + } + } + } + } + } + } + + // Check if jump relocation type is correct + if (s.ImmediateFieldSize > 1 && s.ImmediateRelocation && (s.OpcodeDef->Destination & 0xFE) == 0x82) { + // Near jump or call. Relocation must be self-relative + if (!(Relocations[s.ImmediateRelocation].Type & 2)) { + s.Warnings1 |= 0x10000; // Self-relative relocation expected but not found + } + } + // Check operand size for jumps + if ((s.OpcodeDef->AllowedPrefixes & 0x80) && s.Prefixes[4]) { + // Jump instruction sensitive to operand size prefix + if (WordSize == 32) s.Warnings1 |= 0x20000; // Instruction pointer truncated + if (WordSize == 64) s.Warnings1 |= 0x400; // Prefix has no effect + } + + // Check address size for stack operations + if ((s.OpcodeDef->AllowedPrefixes & 2) && s.Prefixes[1]) + s.Warnings1 |= 0x40000; // Stack operation has address size prefix + + // Check for undocumented opcode + if ((s.OpcodeDef->InstructionFormat & 0x4000) && s.OpcodeDef->Name) + s.Warnings1 |= 0x100000; // Undocumented opcode + + // Check for future opcode + if (s.OpcodeDef->InstructionFormat & 0x2000) + s.Warnings1 |= 0x200000; // Opcode reserved for future extensions + + // Check instruction set + if (s.OpcodeDef->InstructionSet & 0x10000) + s.Warnings2 |= 0x2; // Planned future instruction + + if (s.OpcodeDef->InstructionSet & 0x20000) + s.Warnings2 |= 0x4; // Proposed instruction code never implemented, preliminary specification later changed + + // Check operand size for stack operations + if ((s.OpcodeDef->AllowedPrefixes & 0x102) == 0x102) { + if (s.Prefixes[4] == 0x66 || (Get(s.OpcodeStart1) == 0xCF && s.OperandSize != WordSize)) { + s.Warnings1 |= 0x4000000; // Non-default size for stack operation + } + } + + // Check if function ends with ret or unconditional jump (or nop) + if (IEnd == FunctionEnd && !(s.OpcodeDef->Options & 0x50)) { + s.Warnings1 |= 0x8000000; // Function does not end with return or jump + } + + // Check for multi-byte NOP and UD2 + if (s.OpcodeDef->Options & 0x50) CheckForNops(); + + // Check for inaccessible code + if (IBegin == LabelInaccessible) { + s.Warnings1 |= 0x10000000; // Inaccessible code other than NOP or UD2 + } +} + + +void CDisassembler::FindErrors() { + // Find any errors in code + if (IEnd - IBegin > 15) { + // Instruction longer than 15 bytes + s.Errors |= 1; + } + if (s.Prefixes[2] && (!(s.OpcodeDef->AllowedPrefixes & 0x10) || !(s.MFlags & 1))) { + // Lock prefix not allowed for this instruction + s.Errors |= 2; + } + if ( s.OpcodeDef->InstructionFormat == 0 + || ((s.OpcodeDef->InstructionFormat & 0x4000) && s.OpcodeDef->Name == 0)) { + // Illegal instruction + s.Errors |= 4; + } + if ((s.OpcodeDef->InstructionSet & 0x8000) && WordSize == 64) { + // Instruction not allowed in 64 bit mode + s.Errors |= 0x40; + } + if (IEnd > LabelEnd && IBegin < LabelEnd) { + // Instruction crosses a label + // Check if label is public + uint32 sym1 = Symbols.FindByAddress(Section, LabelEnd, 0, 0); + if (sym1 && (Symbols[sym1].Scope & 0x1C)) { + // Label is public. Code interpretation may be out of phase + s.Errors |= 0x80; + // Put interpretation in phase with label + IEnd = LabelEnd; + } + else { + // Symbol is local. + // This may be a spurious label produced by misinterpretation elsewhere + if (sym1) Symbols[sym1].Type = 0; // Remove symbol type + s.Warnings2 |= 1; + } + } + if ((s.MFlags & 3) == 3 && (s.Prefixes[7] & 1) && s.BaseReg == 0 && s.AddressFieldSize == 4) { + // Attempt to use R13 as base register without displacement + s.Errors |= 0x100; + } + if ((s.OpcodeDef->InstructionFormat & 0x1E) == 0x14) { + // Check validity of DREX byte + if ((s.Vreg & 0x87) && WordSize < 64) { + s.Errors |= 0x200; // Attempt to use XMM8-15 in 16 or 32 bit mode (ignored, may be changed to warning) + } + if (s.Prefixes[7] & 0x40) { + s.Errors |= 0x400; // Both REX and DREX byte + } + if ((s.Vreg & 2) && !(s.MFlags & 4)) { + s.Errors |= 0x800; // DREX.X bit but no SIB byte (probably ignored, may be changed to warning) + } + } + if ((s.OpcodeDef->InstructionFormat & 0x1F) == 0x1E) { + // Instruction needs VSIB byte + if (s.IndexReg == 0) s.Errors |= 8; // Illegal operand: no index register + } + if (LabelEnd >= s.OpcodeStart2+2 && ( + Get(s.OpcodeStart2) == 0 + || Get(s.OpcodeStart2) == 0xFFFF + // || Get(s.OpcodeStart2) == 0xCCCC + )) { + // Two consecutive bytes of zero gives the instruction: add byte ptr [eax],al + // This instruction is very unlikely to occur in normal code but occurs + // frequently in data. Mark to code as probably data. + // Two bytes of 0xFF makes no legal instruction but occurs frequently in data. + // Two bytes of 0xCC is debug breaks used by debuggers for marking illegal addresses or unitialized data + s.Errors = 0x4000; + } + if (s.Errors) { + // Errors found. May be data in code segment + CountErrors++; + MarkCodeAsDubious(); + } +} + + +void CDisassembler::FindRelocations() { + // Find any relocation sources in this instruction + SARelocation rel1, rel2; // Make relocation records for searching + rel1.Section = Section; + rel1.Offset = IBegin; // rel1 marks begin of this instruction + rel2.Section = Section; + rel2.Offset = IEnd; // rel2 marks end of this instruction + + // Search for relocations in this instruction + uint32 irel = Relocations.FindFirst(rel1); // Finds first relocation source >= IBegin + + if (irel == 0 || irel >= Relocations.GetNumEntries()) { + // No relocations found + return; + } + if (Relocations[irel] < rel2) { + // Found relocation points between IBegin and IEnd + if (Relocations[irel].Offset == s.AddressField && s.AddressFieldSize) { + // Relocation points to address field + s.AddressRelocation = irel; + if (Relocations[irel].Size > s.AddressFieldSize) { + // Right place but wrong size + s.Errors |= 0x1000; + } + } + else if (Relocations[irel].Offset == s.ImmediateField && s.ImmediateFieldSize) { + // Relocation points to immediate operand/jump address field + s.ImmediateRelocation = irel; + if (Relocations[irel].Size > s.ImmediateFieldSize) { + // Right place but wrong size + s.Errors |= 0x1000; + } + } + else { + // Relocation source points to a wrong address + s.Errors |= 0x1000; + } + if (s.AddressRelocation) { + // Found relocation for address field, there may be + // a second relocation for the immediate field + if (irel + 1 < Relocations.GetNumEntries() && Relocations[irel+1] < rel2) { + // Second relocation found + if (Relocations[irel+1].Offset == s.ImmediateField && s.ImmediateFieldSize) { + // Relocation points to immediate operand/jump address field + s.ImmediateRelocation = irel + 1; + if (Relocations[irel+1].Size > s.ImmediateFieldSize) { + // Right place but wrong size + s.Errors |= 0x1000; + } + else { + // Second relocation accepted + irel++; + } + } + } + } + // Check if there are more relocations + if (irel + 1 < Relocations.GetNumEntries() && Relocations[irel+1] < rel2) { + // This relocation points before IEnd but doesn't fit any operand or overlaps previous relocation + if ((s.Operands[0] & 0xFE) == 0x84 && Relocations[irel+1].Offset == s.ImmediateField + s.ImmediateFieldSize - 2) { + // Fits segment field of far jump/call + ; + } + else { + // Relocation doesn't fit anywhere + s.Errors |= 0x1000; + } + } + } +} + + +void CDisassembler::FindInstructionSet() { + // Update instruction set + uint16 InstSet = s.OpcodeDef->InstructionSet; + if (InstSet == 7 && s.Prefixes[5] == 0x66) { + // Change MMX to SSE2 if 66 prefix + InstSet = 0x12; + } + if ((s.Prefixes[7] & 0x30) && InstSet < 0x19) { + // VEX instruction set if VEX prefix + InstSet = 0x19; + } + if (s.Prefixes[6] & 0x40) { + // EVEX or MVEX prefix + if (s.Prefixes[6] & 0x20) { + // EVEX prefix + if (InstSet < 0x20) InstSet = 0x20; + } + else { + // MVEX prefix + if (InstSet < 0x80) InstSet = 0x80; + } + } + if ((InstSet & 0xFF00) == 0x1000) { + // AMD-specific instruction set + // Set AMD-specific instruction set to max + if ((InstSet & 0xFF) > InstructionSetAMDMAX) { + InstructionSetAMDMAX = InstSet & 0xFF; + } + } + else { + // Set Intel or generic instruction set to maximum + if ((InstSet & 0xFF) > InstructionSetMax) { + InstructionSetMax = InstSet & 0xFF; + } + } + + // Set InstructionSetOR to a bitwise OR of all instruction sets encountered + InstructionSetOR |= InstSet; + + if (s.OpcodeDef->Options & 0x10) { + FlagPrevious |= 2; + } +} + + +void CDisassembler::CheckLabel() { + // Check if there is a label at instruction, and write it + // Write begin and end of function + + // Search in symbol table + uint32 Sym1, Sym2; // First and last symbol + + // Find all symbol table entries at this address + Sym1 = Symbols.FindByAddress(Section, IBegin, &Sym2); + + if (Sym1) { + // Found at least one symbol + // Loop for all symbols with same address + for (uint32 s = Sym1; s <= Sym2; s++) { + + // Check if label has already been written as a function label + if (!(Symbols[s].Scope & 0x100) && !(Symbols[s].Type & 0x80000000)) { + + // Write label as a private or public code label + WriteCodeLabel(s); + } + } + // Get symbol type and size + DataType = Symbols[Sym2].Type; + DataSize = GetDataItemSize(DataType); + } +} + + +void CDisassembler::CheckForNops() { + // Check for multi-byte NOP and UD2 instructions + + switch (Opcodei) { + case 0x3C00: case 0x3C01: case 0x3C02: case 0x11F: // NOP + // These opcodes are intended for NOPs. Indicate if longer than one byte + if (IEnd - IBegin > 1) s.Warnings1 |= 0x1000000; + // Remember NOP + FlagPrevious |= 1; + break; + + case 0x8D: // LEA + // LEA is often used as NOP with destination = base register + if (s.Mod < 3 && s.Reg+1 == s.BaseReg && s.IndexReg == 0 && + s.AddressSize == s.OperandSize && s.OperandSize >= WordSize) { + // Destination is same as base register. + // Check if displacement is 0 + switch (s.AddressFieldSize) { + case 0: + break; + case 1: + if (Get(s.AddressField) != 0) return; + break; + case 2: + if (Get(s.AddressField) != 0) return; + break; + case 4: + if (Get(s.AddressField) != 0) return; + break; + default: + return; + } + // Displacement is zero. This is a multi-byte NOP + s.Warnings1 |= 0x1000000; + break; + } + + case 0x86: case 0x87: // XCHG + case 0x88: case 0x89: case 0x8A: case 0x8B: // MOV + // Check if source and destination are the same register + if (s.Mod == 3 && s.Reg == s.RM && s.OperandSize >= WordSize) { + // Moving a register to itself. This is a NOP + s.Warnings1 |= 0x1000000; + } + break; + case 0x10B: // UD2 + FlagPrevious |= 6; + break; + } + + if (s.Warnings1 & 0x1000000) { + // A multi-byte NOP is detected. + // Remove warnings for longer-than-necessary instruction + s.Warnings1 &= ~ 0x873D; + // Remember NOP + FlagPrevious |= 1; + } +} + + +void CDisassembler::InitialErrorCheck() { + // Check for illegal relocations table entries + uint32 i; // Loop counter + + // Loop through relocations table + for (i = 1; i < Relocations.GetNumEntries(); i++) { + if (Relocations[i].TargetOldIndex >= Symbols.GetLimit()) { + // Nonexisting relocation target + Relocations[i].TargetOldIndex = 0; + } + if (Relocations[i].RefOldIndex >= Symbols.GetLimit()) { + // Nonexisting reference index + Relocations[i].RefOldIndex = 0; + } + // Remember types of relocations in source + RelocationsInSource |= Relocations[i].Type; + } + + // Check opcode tables + if (NumOpcodeTables1 != NumOpcodeTables2) { + err.submit(9007, 0xFFFF); + } +} + + +void CDisassembler::FinalErrorCheck() { + // Check for illegal entries in symbol table and relocations table + uint32 i; // Loop counter + int SpaceWritten = 0; // Blank line written + + // Loop through symbol table + for (i = 1; i < Symbols.GetNumEntries(); i++) { + if (Symbols[i].Section <= 0 || (Symbols[i].Type & 0x80000000)) { + // Constant or external symbol or section + continue; + } + if ((uint32)Symbols[i].Section >= Sections.GetNumEntries() + || Symbols[i].Offset > Sections[Symbols[i].Section].TotalSize) { + // Symbol has illegal address + // Blank line + if (!SpaceWritten++) OutFile.NewLine(); + // Write comment + OutFile.Put(CommentSeparator); + OutFile.Put("Error: Symbol "); + // Write symbol name + OutFile.Put(Symbols.GetName(i)); + // Write the illegal address + OutFile.Put(" has a non-existing address. Section: "); + if (Symbols[i].Section != ASM_SEGMENT_IMGREL) { + OutFile.PutDecimal(Symbols[i].Section, 1); + } + else { + OutFile.Put("Unknown"); + } + OutFile.Put(" Offset: "); + OutFile.PutHex(Symbols[i].Offset, 1); + OutFile.NewLine(); + } + } + // Loop through relocations table + for (i = 1; i < Relocations.GetNumEntries(); i++) { + // Check source address + if (Relocations[i].Section == 0 + || (uint32)Relocations[i].Section >= Sections.GetNumEntries() + || (Sections[Relocations[i].Section].Type & 0xFF) == 3 + || Relocations[i].Offset >= Sections[Relocations[i].Section].InitSize) { + // Relocation has illegal source address + // Blank line + if (!SpaceWritten++) OutFile.NewLine(); + // Write comment + OutFile.Put(CommentSeparator); + OutFile.Put("Error: Relocation number "); + OutFile.PutDecimal(i); + OutFile.Put(" has a non-existing source address. Section: "); + if (Relocations[i].Section != ASM_SEGMENT_IMGREL) { + OutFile.PutDecimal(Relocations[i].Section, 1); + } + else { + OutFile.Put("Unknown"); + } + OutFile.Put(" Offset: "); + OutFile.PutHex(Relocations[i].Offset, 1); + OutFile.NewLine(); + } + // Check target + if (Relocations[i].TargetOldIndex == 0 + || Relocations[i].TargetOldIndex >= Symbols.GetLimit() + || Relocations[i].RefOldIndex >= Symbols.GetLimit()) { + // Relocation has illegal target + // Blank line + if (!SpaceWritten++) OutFile.NewLine(); + // Write comment + OutFile.Put(CommentSeparator); + OutFile.Put("Error: Relocation number "); + OutFile.PutDecimal(i); + OutFile.Put(" at section "); + OutFile.PutDecimal(Relocations[i].Section); + OutFile.Put(" offset "); + OutFile.PutHex(Relocations[i].Offset); + OutFile.Put(" has a non-existing target index. Target: "); + OutFile.PutDecimal(Relocations[i].TargetOldIndex, 1); + if (Relocations[i].RefOldIndex) { + OutFile.Put(", Reference point index: "); + OutFile.PutDecimal(Relocations[i].RefOldIndex, 1); + } + OutFile.NewLine(); + } + } +} + + +void CDisassembler::CheckNamesValid() { + // Fix invalid symbol and section names + uint32 i, j; // Loop counter + uint32 Len; // Length of name + uint32 Changed; // Symbol is changed + char c; // Character in symbol + const char * ValidCharacters; // List of valid characters in symbol names + // Make list of characters valid in symbol names other than alphanumeric characters + switch (Syntax) { + case SUBTYPE_MASM: + ValidCharacters = "_$@?"; break; + case SUBTYPE_YASM: + ValidCharacters = "_$@?.~#"; break; + case SUBTYPE_GASM: + ValidCharacters = "_$."; break; + default: + err.submit(9000); + } + + // Loop through sections + for (i = 1; i < Sections.GetNumEntries(); i++) { + char * SecName = NameBuffer.Buf() + Sections[i].Name; + if (Syntax == SUBTYPE_MASM && SecName[0] == '.') { + // Name begins with dot + // Check for reserved names + if (stricmp(SecName, ".text") == 0 + || stricmp(SecName, ".data") == 0 + || stricmp(SecName, ".code") == 0 + || stricmp(SecName, ".const") == 0) { + // Change . to _ in beginning of name to avoid reserved directive name + SecName[0] = '_'; + } + else { + // Other name beginning with . + // Set option dotname + MasmOptions |= 1; + } + } + } + // Loop through symbols + for (i = 1; i < Symbols.GetNumEntries(); i++) { + if (Symbols[i].Name) { + // Warning: violating const specifier in GetName(): + char * SymName = (char *)Symbols.GetName(i); + Len = strlen(SymName); Changed = 0; + // Loop through characters in symbol + for (j = 0; j < Len; j++) { + c = SymName[j]; + if (!(((c | 0x20) >= 'a' && (c | 0x20) <= 'z') + || (c >= '0' && c <= '9' && j != 0) + || strchr(ValidCharacters, c))) { + // Illegal character found + if (Syntax == SUBTYPE_MASM) { + if (j == 0 && c == '.') { + // Symbol beginning with dot in MASM + if (Symbols[i].Type & 0x80000000) { + // This is a segment. Check for reserved names + if (stricmp(SymName, ".text") == 0 + || stricmp(SymName, ".data") == 0 + || stricmp(SymName, ".code") == 0 + || stricmp(SymName, ".const") == 0) { + // Change . to _ in beginning of name to avoid reserved directive name + SymName[0] = '_'; // Warning: violating const specifier in GetName() + break; // break out of j loop + } + } + // Set option dotname + MasmOptions |= 1; + } + else { + // Other illegal character in MASM +#if ReplaceIllegalChars + SymName[j] = '?'; +#endif + Changed++; + } + } + else { + // Illegal character in GAS or YASM syntax +#if ReplaceIllegalChars + SymName[j] = (Syntax == SUBTYPE_YASM) ? '?' : '$'; +#endif + Changed++; + } + } + } + // Count names changed + if (Changed) NamesChanged++; + } + } +} + + +void CDisassembler::FixRelocationTargetAddresses() { + // Fix missing relocation target addresses + // to section:offset addresses + uint32 r; // Relocation index + uint32 s; // Symbol index + int32 sect; + + // Loop through relocations + for (r = 1; r < Relocations.GetNumEntries(); r++) { + + if (Relocations[r].TargetOldIndex == 0 && (Relocations[r].Type & 0x60)) { + // Target symbol not defined. Make new symbol + SASymbol sym; + sym.Reset(); + + // Find target address from relocation source + sect = Relocations[r].Section; + if ((uint32)sect >= Sections.GetNumEntries()) continue; + uint8 * pSectionData = Sections[sect].Start; + if (!pSectionData) continue; + int64 TargetOffset = 0; + if (Relocations[r].Size == 4) { + TargetOffset = *(int32*)(pSectionData + Relocations[r].Offset); + } + else if (Relocations[r].Size == 8) { + TargetOffset = *(int64*)(pSectionData + Relocations[r].Offset); + } + else { + // Error: wrong size + continue; + } + if (HighDWord(TargetOffset)) { + // Error: out of range + continue; + } + // Translate to section:offset address + if (!(TranslateAbsAddress(TargetOffset, sym.Section, sym.Offset))) { + // Translation failed + continue; + } + // Default scope is file local + sym.Scope = 2; + + // Add symbol if it doesn't exist or get index of existing symbol + s = Symbols.NewSymbol(sym); + + // Make reference to symbol from relocation record + if (s) { + Relocations[r].TargetOldIndex = Symbols[s].OldIndex; + } + } + } +} + + +int CDisassembler::TranslateAbsAddress(int64 Addr, int32 &Sect, uint32 &Offset) { + // Translate absolute virtual address to section and offset + // Returns 1 if valid address found. + int32 Section; + + // Get image-relative address + Addr -= ImageBase; + // Fail if too big + if (HighDWord(Addr)) return 0; + + // Search through sections + for (Section = 1; (uint32)Section < Sections.GetNumEntries(); Section++) { + uint32 SectionAddress = Sections[Section].SectionAddress; + if ((uint32)Addr >= SectionAddress && (uint32)Addr < SectionAddress + Sections[Section].TotalSize) { + // Address is within this section + // Return section and offset + Sect = Section; + Offset = (uint32)Addr - SectionAddress; + // Return 1 to indicate success + return 1; + } + } + // Not found. Return 0 + return 0; +} + + +uint32 CDisassembler::GetDataItemSize(uint32 Type) { + // Get size in bytes of data item with specified type + uint32 Size = 1; + + switch (Type & 0xFF) { + // Scalar types + case 1: + Size = 1; break; + case 2: case 0x4A: case 0x95: + Size = 2; break; + case 3: case 0x43: case 0x4B: + Size = 4; break; + case 4: case 0x44: case 0x4C: + Size = 8; break; + case 5: case 0x45: + Size = 10; break; + case 7: + Size = 6; break; + case 0x50: case 51: + Size = 16; break; + case 0x0B: case 0x0C: + // Function pointer + Size = WordSize / 8; break; + case 0x0D: + // Far function pointer + Size = WordSize / 8 + 2; break; + } + switch (Type & 0xF00) { + // Override above size if vector of known size + case 0x300: + Size = 8; break; + case 0x400: + Size = 16; break; + case 0x500: + Size = 32; break; + case 0x600: + Size = 64; break; + case 0x700: + Size = 128; break; + } + return Size; +} + + +uint32 CDisassembler::GetDataElementSize(uint32 Type) { + // Get size of vector element in data item with specified type + if ((Type & 0xF0) == 0x50) { + // Vector of unknown elements + return GetDataItemSize(Type); + } + else { + // Vector of known elements. Return element type + return GetDataItemSize(Type & 7); + } +} + + +int32 CDisassembler::GetSegmentRegisterFromPrefix() { + // Translate segment prefix to segment register + switch (s.Prefixes[0]) { + case 0x26: // ES: + return 0; + case 0x2E: // CS: + return 1; + case 0x36: // SS: + return 2; + case 0x3E: // DS: + return 3; + case 0x64: // FS: + return 4; + case 0x65: // GS: + return 5; + } + return -1; // Error: none +} diff --git a/programs/develop/objconv/disasm2.cpp b/programs/develop/objconv/disasm2.cpp new file mode 100644 index 0000000000..ba06a0d85d --- /dev/null +++ b/programs/develop/objconv/disasm2.cpp @@ -0,0 +1,4335 @@ +/**************************** disasm2.cpp ******************************** +* Author: Agner Fog +* Date created: 2007-02-25 +* Last modified: 2016-11-27 +* Project: objconv +* Module: disasm2.cpp +* Description: +* Module for disassembler containing file output functions +* +* Changes that relate to assembly language syntax should be done in this file only. +* +* Copyright 2007-2016 GNU General Public License http://www.gnu.org/licenses +*****************************************************************************/ +#include "stdafx.h" + +/********************** Warning and error texts *************************** +These texts are inserted in disassembled code in case of warnings or errors. + +The occurrence of an error makes the disassembler mark the code block between +the nearest known code labels as dubious. This means that the byte sequence +might be data in the code segment or the disassembler might be out of phase +with instruction boundaries. Dubious code will be shown both as code and as +data. + +A warning will be shown as 'Note:' before the instruction it applies to. +This might indicate suboptimal coding or a possible cause for concern. + +The criteria for distinguishing between warnings and errors is not the +severity of consequences, but whether the condition is likely to be caused +by common programming errors or by data in the code segment. + +Some of the warning messages are quite benign, e.g. an unnecessary prefix. +Other warning messages can have severe consequences, e.g. a function missing +a return statement. + +Still other warnings are no case for concern, but a condition requiring +attention. For example the message: "Multi-byte NOP. Replace with ALIGN", +might actually indicate a well optimized code. But it requires attention +because the assembler cannot re-create the multi-byte NOP if the code +is assembled again. The programmer needs to decide what level of alignment +is optimal and replace the NOP with an align statement. + +*****************************************************************************/ + +// Define error texts. +SIntTxt AsmErrorTexts[] = { + {1, "Instruction longer than 15 bytes"}, + {2, "Lock prefix not allowed for this opcode"}, + {4, "Illegal opcode"}, + {8, "Illegal operands for this opcode"}, + {0x10, "Instruction extends beyond end of code block"}, + {0x20, "Prefix after REX prefix not allowed"}, + {0x40, "This instruction is not allowed in 64 bit mode"}, + {0x80, "Instruction out of phase with next label"}, + {0x100, "Attempt to use R13 as base register without displacement"}, + {0x200, "Register 8 - 15 only allowed in 64 bit mode (Ignored)."}, + {0x400, "REX prefix not allowed on instruction with DREX byte"}, + {0x800, "VEX has X bit but no SIB byte (Probably ignored)"}, + {0x1000, "Relocation source does not match address or operand field"}, + {0x2000, "Overlapping relocations"}, + {0x4000, "This is unlikely to be code"}, // Consecutive bytes of 0 found + {0x8000, "VEX.L bit not allowed here"}, + {0x10000, "VEX.mmmm bits out of range"}, + {0x80000, "Internal error in opcode table in opcodes.cpp"} +}; + +// Warning texts 1: Warnings about conditions that could be intentional and suboptimal code +SIntTxt AsmWarningTexts1[] = { + {1, "Immediate operand could be made smaller by sign extension"}, + {2, "Immediate operand could be made smaller by zero extension"}, + {4, "Zero displacement could be omitted"}, + {8, "Displacement could be made smaller by sign extension"}, + {0x10, "SIB byte unnecessary here"}, + {0x20, "A shorter instruction exists for register operand"}, + {0x40, "Length-changing prefix causes delay on Intel processors"}, + {0x80, "Address size prefix should be avoided"}, + {0x100, "Same prefix occurs more than once"}, + {0x200, "Prefix valid but unnecessary"}, + {0x400, "Prefix bit or byte has no meaning in this context"}, + {0x800, "Contradicting prefixes"}, + {0x1000, "Required prefix missing"}, + {0x2000, "Address has scale factor but no index register"}, + {0x4000, "Address is not rip-relative"}, + {0x8000, "Absolute memory address without relocation"}, + {0x10000, "Unusual relocation type for this operand"}, + {0x20000, "Instruction pointer truncated by operand size prefix"}, + {0x40000, "Stack pointer truncated by address size prefix"}, + {0x80000, "Jump or call to data segment not allowed"}, + {0x100000, "Undocumented opcode"}, + {0x200000, "Unknown opcode reserved for future extensions"}, + {0x400000, "Memory operand is misaligned. Performance penalty"}, + {0x800000, "Alignment fault. Memory operand must be aligned"}, + {0x1000000, "Multi-byte NOP. Replace with ALIGN"}, + {0x2000000, "Bogus length-changing prefix causes delay on Intel processors here"}, + {0x4000000, "Non-default size for stack operation"}, + {0x8000000, "Function does not end with ret or jmp"}, + {0x10000000, "No jump seems to point here"}, + {0x20000000, "Full 64-bit address"}, + {0x40000000, "VEX prefix bits not allowed here"} +}; + +// Warning texts 2: Warnings about possible misinterpretation; serious warnings +SIntTxt AsmWarningTexts2[] = { + {1, "Label out of phase with instruction. Possibly spurious"}, + {2, "Planned future instruction, according to preliminary specification"}, + {4, "This instruction has been planned but never implemented because plans were changed. Will not work"}, + {0x10, "EVEX prefix not allowed for this instruction"}, + {0x20, "MVEX prefix not allowed for this instruction"}, + {0x40, "EVEX prefix option bits not allowed here"}, + {0x80, "MVEX prefix option bits not allowed here"}, + {0x100, "Mask register must be nonzero"}, + {0x200, "Broadcasting to scalar not allowd"}, +}; + + +// Indication of relocation types in comments: +SIntTxt RelocationTypeNames[] = { + {0x001, "(d)" }, // Direct address in flat address space + {0x002, "(rel)" }, // Self-relative + {0x004, "(imgrel)" }, // Image-relative + {0x008, "(segrel)" }, // Segment-relative + {0x010, "(refpoint)" }, // Relative to arbitrary point (position-independent code in Mach-O) + {0x021, "(d)" }, // Direct (adjust by image base) + {0x041, "(d)" }, // Direct (make procecure linkage table entry) + {0x081, "(indirect)" }, // Gnu indirect function dispatcher (make procecure linkage table entry?) + {0x100, "(seg)" }, // Segment address or descriptor + {0x200, "(sseg)" }, // Segment of symbol + {0x400, "(far)" }, // Far segment:offset address + {0x1001, "(GOT)" }, // GOT entry + {0x1002, "(GOT r)" }, // self-relative to GOT entry + {0x2002, "(PLT r)" } // self-relative to PLT entry +}; + +// Instruction set names +const char * InstructionSetNames[] = { + "8086", "80186", "80286", "80386", // 0 - 3 + "80486", "Pentium", "Pentium Pro", "MMX", // 4 - 7 + "Pentium II", "", "", "", // 8 - B + "", "", "", "", // C - F + "", "SSE", "SSE2", "SSE3", // 10 - 13 + "Supplementary SSE3", "SSE4.1", "SSE4.2", "AES", // 14 - 17 + "CLMUL", "AVX", "FMA3", "?", // 18 - 1B + "AVX2", "BMI etc.", "?", "?", // 1C - 1F + "AVX-512", "AVX512PF/ER/CD", "MPX,SHA,TBD", "AVX512IFMA/VBMI", // 20 - 23 + "AVX512_4FMAPS", "?", "?", "?", // 24 - 27 + "?", "?", "?", "?", // 28 - 2B + "?", "?", "?", "?", // 2C - 2F + "?", "?", "?", "?", // 30 - 33 + "?", "?", "?", "?", // 34 - 37 + "?", "?", "?", "?", // 38 - 3B + "?", "?", "?", "?", // 3C - 3F + "?", "?", "?", "?", // 40 - 43 + "?", "?", "?", "?", // 44 - 47 + "?", "?", "?", "?", // 48 - 4B + "?", "?", "?", "?", // 4C - 4F + "?", "?", "?", "?", // 50 - 53 + "?", "?", "?", "?", // 54 - 57 + "?", "?", "?", "?", // 58 - 5B + "?", "?", "?", "?", // 5C - 5F + "?", "?", "?", "?", // 60 - 63 + "?", "?", "?", "?", // 64 - 67 + "?", "?", "?", "?", // 68 - 6B + "?", "?", "?", "?", // 6C - 6F + "?", "?", "?", "?", // 70 - 73 + "?", "?", "?", "?", // 74 - 77 + "?", "?", "?", "?", // 78 - 7B + "?", "?", "?", "?", // 7C - 7F + "Knights Corner", "?", "?", "?", // 80 - 83 + "?", "?", "?", "?" // 84 - 87 +}; + +const int InstructionSetNamesLen = TableSize(InstructionSetNames); + + +/************************** class CDisassembler ***************************** +Most member functions of CDisassembler are defined in disasm1.cpp + +Only the functions that produce output are defined here: +******************************************************************************/ + +void CDisassembler::WriteShortRegOperand(uint32 Type) { + // Write register operand from lower 3 bits of opcode byte to OutFile + uint32 rnum = Get(s.OpcodeStart2) & 7; + // Check REX.B prefix + if (s.Prefixes[7] & 1) rnum |= 8; // Add 8 if REX.B prefix + // Write register name + WriteRegisterName(rnum, Type); +} + +void CDisassembler::WriteRegOperand(uint32 Type) { + // Write register operand from reg bits + uint32 Num = s.Reg; // Register number + + // Write register name + WriteRegisterName(Num, Type); +} + +void CDisassembler::WriteRMOperand(uint32 Type) { + // Write memory or register operand from mod/rm bits of mod/reg/rm byte + // and possibly SIB byte or direct memory operand to OutFile. + // Also used for writing direct memory operand + + if ((Type & 0xFF) == 0) { + // No explicit operand + return; + } + + uint32 Components = 0; // Count number of addends inside [] + int64 Addend = 0; // Inline displacement or addend + int AddressingMode = 0; // 0: 16- or 32 bit addressing mode + // 1: 64-bit pointer + // 2: 32-bit absolute in 64-bit mode + // 4: 64-bit rip-relative + // 8: 64-bit absolute + // Check if register or memory + if (s.Mod == 3) { + // Register operand + WriteRegisterName(s.RM, Type); + return; + } + + // Find addend, if any + switch (s.AddressFieldSize) { + case 1: // 1 byte displacement + Addend = Get(s.AddressField); + break; + case 2: // 2 bytes displacement + Addend = Get(s.AddressField); + break; + case 4: // 4 bytes displacement + Addend = Get(s.AddressField); + if ((s.MFlags & 0x100) && !s.AddressRelocation) { + // rip-relative + Addend += ImageBase + uint64(SectionAddress + IEnd); + } + break; + case 8: // 8 bytes address + Addend = Get(s.AddressField); + break; + } + // Get AddressingMode + if (s.AddressSize > 32) { + if (s.MFlags & 0x100) { + AddressingMode = 4; // 64-bit rip-relative + } + else if (s.AddressFieldSize == 8) { + AddressingMode = 8; // 64-bit absolute + } + else if (s.AddressRelocation || (s.BaseReg==0 && s.IndexReg==0)) { + AddressingMode = 2; // 32-bit absolute in 64-bit mode + } + else { + AddressingMode = 1; // 64-bit pointer + } + } + + // Make exception for LEA with no type + if (Opcodei == 0x8D) { + Type = 0; + } + // Write type override + if ((s.OpcodeDef->InstructionFormat & 0x1F) == 0x1E) { + WriteOperandType(Type & 0xFF); // has vsib address: write element type rather than vector type + } + else if (!(s.OpcodeDef->Options & 0x800)) { + WriteOperandType(Type); // write operand type + } + + if (Syntax != SUBTYPE_MASM) { + // Write "[" around memory operands, before segment + OutFile.Put("["); + } + + // Write segment prefix, if any + if (s.Prefixes[0]) { + OutFile.Put(RegisterNamesSeg[GetSegmentRegisterFromPrefix()]); + OutFile.Put(":"); + } + else if (!s.BaseReg && !s.IndexReg && (!s.AddressRelocation || (s.Warnings1 & 0x10000)) && Syntax != SUBTYPE_YASM) { + // No pointer register and no memory reference or wrong type of memory reference. + // Write segment register to indicate that we have a memory operand + OutFile.Put("DS:"); + } + + if (Syntax == SUBTYPE_MASM) { + // Write "[" around memory operands, after segment + OutFile.Put("["); + } + + if (Syntax == SUBTYPE_YASM && (AddressingMode & 0x0E)) { + // Specify absolute or relative addressing mode + switch (AddressingMode) { + case 2: OutFile.Put("abs "); break; + case 4: OutFile.Put("rel "); break; + case 8: OutFile.Put("abs qword "); break; + } + } + + // Write relocation target, if any + if (s.AddressRelocation) { + // Write cross reference + WriteRelocationTarget(s.AddressRelocation, 4 | (s.MFlags & 0x100), Addend); + // Addend has been written, don't write it again + Addend = 0; + // Remember that something has been written + Components++; + } + + // Check address size for pointer registers + //const char * * PointerRegisterNames; + uint32 RegisterType = 0; + switch (s.AddressSize) { + case 16: + RegisterType = 2; break; + case 32: + RegisterType = 3; break; + case 64: + RegisterType = 4; break; + } + + // Write base register, if any + if (s.BaseReg) { + if (Components++) OutFile.Put("+"); // Put "+" if anything before + WriteRegisterName(s.BaseReg - 1, RegisterType); + } + + // Write index register, if any + if (s.IndexReg) { + if (Components++) OutFile.Put("+"); // Put "+" if anything before + if ((s.OpcodeDef->InstructionFormat & 0x1F) != 0x1E) { + // normal index register + WriteRegisterName(s.IndexReg - 1, RegisterType); + } + else { + // VSIB byte specifies vector index register + WriteRegisterName(s.IndexReg - 1, Type & 0xF00); + } + // Write scale factor, if any + if (s.Scale) { + OutFile.Put("*"); + OutFile.PutDecimal(1 << s.Scale); + } + } + + // Write +/- before addend + if (Components && Addend) { + // Displacement comes after base/index registers + if (Addend >= 0 || s.AddressFieldSize == 8) { + // Positive. Write + + OutFile.Put("+"); + } + else { + // Negative. Write - + OutFile.Put("-"); + Addend = -Addend; + } + } + + if (Addend || Components == 0) { + // Find minimum number of digits needed + uint32 AddendSize = s.AddressFieldSize; + if ((uint64)Addend < 0x100 && AddendSize > 1) AddendSize = 1; + else if ((uint64)Addend < 0x10000 && AddendSize > 2) AddendSize = 2; + + // Write address or addend as hexadecimal + OutFile.PutHex((uint64)Addend, 2); + + // Check if offset multiplier needed + if (s.OffsetMultiplier && s.AddressFieldSize == 1 && Addend) { + OutFile.Put("*"); + OutFile.PutHex(s.OffsetMultiplier, 2); + } + } + + if (Syntax == SUBTYPE_GASM && (AddressingMode == 4)) { + // Need to specify rip-relative address + OutFile.Put("+rip"); + } + + // End with "]" + OutFile.Put("]"); +} + + +void CDisassembler::WriteOperandType(uint32 type) { + switch (Syntax) { + case SUBTYPE_MASM: + WriteOperandTypeMASM(type); break; + case SUBTYPE_YASM: + WriteOperandTypeYASM(type); break; + case SUBTYPE_GASM: + WriteOperandTypeGASM(type); break; + } +} + +void CDisassembler::WriteOperandTypeMASM(uint32 type) { + // Write type override before operand, e.g. "dword ", MASM syntax + if (type & 0xF00) { + type &= 0xF00; // Ignore element type for vectors + } + else { + type &= 0xFF; // Use operand type only + } + + switch (type) { + case 1: // 8 bits + OutFile.Put("byte "); break; + case 2: // 16 bits + OutFile.Put("word "); break; + case 3: // 32 bits + OutFile.Put("dword "); break; + case 4: // 64 bits + OutFile.Put("qword "); break; + case 5: // 80 bits + if ((s.OpcodeDef->Destination & 0xFF) == 0xD) { + // 64+16 bit far pointer. Not supported by MASM + OutFile.Put("fword "); + s.OpComment = "64+16 bit. Need REX.W prefix"; + } + else { + OutFile.Put("tbyte ");} + break; + case 6: case 0x40: case 0x48: case 0: + // Other size. Write nothing + break; + case 7: case 0x0D: // 48 bits or far + OutFile.Put("fword "); + if ((s.OpcodeDef->Destination & 0xFF) == 0xD && WordSize == 64) { + // All assemblers I have tried forget the REX.W prefix here. Make a notice + s.OpComment = "32+16 bit. Possibly forgot REX.W prefix"; + } + break; + case 0x4A: // 16 bits float + OutFile.Put("word "); break; + case 0x43: // 32 bits float (x87) + case 0x4B: // 32 bits float (SSE2) + OutFile.Put("dword "); break; + case 0x44: // 64 bits float + case 0x4C: // 64 bits float (SSE2) + OutFile.Put("qword "); break; + case 0x45: // 80 bits float + OutFile.Put("tbyte "); break; + case 0x84: case 0x85: // far call + OutFile.Put("far "); break; + case 0x95: // 16 bits mask register + OutFile.Put("word "); break; + case 0x300: // MMX + OutFile.Put("qword "); break; + case 0x400: // XMM + OutFile.Put("xmmword "); break; + case 0x500: // YMM + OutFile.Put("ymmword "); break; + case 0x600: // ZMM + OutFile.Put("zmmword "); break; + case 0x700: // future 1024 bit + OutFile.Put("?mmword "); break; + } + OutFile.Put("ptr "); +} + +void CDisassembler::WriteOperandTypeYASM(uint32 type) { + // Write type override before operand, e.g. "dword", NASM/YASM syntax + if (type & 0xF00) { + type &= 0xF00; // Ignore element type for vectors + } + else { + type &= 0xFF; // Use operand type only + } + uint32 Dest = s.OpcodeDef->Destination & 0xFF;// Destination operand + if (Dest >= 0xB && Dest < 0x10) { + // This is a pointer + if (Dest < 0x0D) { + OutFile.Put("near "); // Near indirect jump/call + } + else { + // Far pointer + if ((WordSize == 16 && type == 3) || (WordSize == 32 && type == 7)) { + OutFile.Put("far "); + } + else { + // Size currently not supported by YASM + switch (type) { + case 3: OutFile.Put("far "); + s.OpComment = "16+16 bit. Needs 66H prefix"; + break; + case 7: OutFile.Put("far "); + s.OpComment = "32+16 bit. Possibly forgot REX.W prefix"; + break; + case 5: OutFile.Put("far "); + s.OpComment = "64+16 bit. Needs REX.W prefix"; + break; + } + } + } + return; + } + switch (type) { + case 1: // 8 bits + OutFile.Put("byte "); break; + case 2: // 16 bits + OutFile.Put("word "); break; + case 3: // 32 bits + OutFile.Put("dword "); break; + case 4: // 64 bits + OutFile.Put("qword "); break; + case 5: // 80 bits + OutFile.Put("tbyte "); break; + case 7: // 48 bits + OutFile.Put("fword "); break; + case 0x4A: // 16 bits float + OutFile.Put("word "); break; + case 0x43: // 32 bits float (x87) + case 0x4B: // 32 bits float (SSE2) + OutFile.Put("dword "); break; + case 0x44: // 64 bits float + case 0x4C: // 64 bits float (SSE2) + OutFile.Put("qword "); break; + case 0x45: // 80 bits float + OutFile.Put("tbyte "); break; + case 0x84: case 0x85: // far call + OutFile.Put("far "); break; + case 0x95: // 16 bits mask register + OutFile.Put("word "); break; + case 0x300: // MMX + OutFile.Put("qword "); break; + case 0x400: // XMM + OutFile.Put("oword "); break; + case 0x500: // YMM + OutFile.Put("yword "); break; + case 0x600: // ZMM + OutFile.Put("zword "); break; + case 0x700: // Future 128 bytes + OutFile.Put("?word "); break; + default:; // Anything else: write nothing + } +} + +void CDisassembler::WriteOperandTypeGASM(uint32 type) { + // Write type override before operand, e.g. "dword ", GAS syntax + if (type & 0xF00) { + type &= 0xF00; // Ignore element type for vectors + } + else { + type &= 0xFF; // Use operand type only + } + + switch (type) { + case 1: // 8 bits + OutFile.Put("byte "); break; + case 2: // 16 bits + OutFile.Put("word "); break; + case 3: // 32 bits + OutFile.Put("dword "); break; + case 4: // 64 bits + OutFile.Put("qword "); break; + case 5: // 80 bits + if ((s.OpcodeDef->Destination & 0xFF) == 0xD) { + // 64+16 bit far pointer. Not supported by Gas + OutFile.Put("fword "); + s.OpComment = "64+16 bit. Needs REX.W prefix"; + } + else { + OutFile.Put("tbyte ");} + break; + case 6: case 0x40: case 0x48: case 0: + // Other size. Write nothing + break; + case 7: // 48 bits + OutFile.Put("fword "); + if ((s.OpcodeDef->Destination & 0xFF) == 0xD && WordSize == 64) { + // All assemblers I have tried forget the REX.W prefix here. Make a notice + s.OpComment = "32+16 bit. Possibly forgot REX.W prefix"; + } + break; + case 0x4A: // 16 bits float + OutFile.Put("word "); break; + case 0x43: // 32 bits float (x87) + case 0x4B: // 32 bits float (SSE2) + OutFile.Put("dword "); break; + case 0x44: // 64 bits float + case 0x4C: // 64 bits float (SSE2) + OutFile.Put("qword "); break; + case 0x45: // 80 bits float + OutFile.Put("tbyte "); break; + case 0x84: case 0x85: // far call + OutFile.Put("far "); break; + case 0x95: // 16 bits mask register + OutFile.Put("word "); break; + case 0x300: // MMX + OutFile.Put("qword "); break; + case 0x400: // XMM + OutFile.Put("xmmword "); break; + case 0x500: // YMM + OutFile.Put("ymmword "); break; + case 0x600: // ZMM + OutFile.Put("zmmword "); break; + case 0x700: // future 1024 bit + OutFile.Put("?mmword "); break; + } +} + + +void CDisassembler::WriteDREXOperand(uint32 Type) { + // Write register operand from dest bits of DREX byte (AMD only) + uint32 Num = s.Vreg >> 4; // Register number + // Write register name + WriteRegisterName(Num, Type); +} + +void CDisassembler::WriteVEXOperand(uint32 Type, int i) { + // Write register operand from VEX.vvvv bits or immediate bits + uint32 Num; // Register number + switch (i) { + case 0: // Use VEX.vvvv bits + Num = s.Vreg & 0x1F; break; + case 1: // Use immediate bits 4-7 + Num = Get(s.ImmediateField) >> 4; break; + case 2: // Use immediate bits 0-3 (Unused. For possible future use) + Num = Get(s.ImmediateField) & 0x0F; break; + default: + Num = 0; + } + // Write register name + WriteRegisterName(Num, Type); +} + + +void CDisassembler::WriteOperandAttributeEVEX(int i, int isMem) { + // Write operand attributes and instruction attributes from EVEX z, LL, b and aaa bits + // i = operand number (0 = destination, 1 = first source, 2 = second source, + // 98 = after last SIMD operand, 99 = after last operand) + // isMem: true if memory operand, false if register operand + uint32 swiz = s.OpcodeDef->EVEX; // indicates meaning of EVEX attribute bits + + if ((swiz & 0x30) && (i == 0 || (s.OpcodeDef->Destination == 0 && i == 1))) { // first operand + // write mask + if (s.Kreg || (swiz & 0xC0)) { + OutFile.Put(" {k"); + OutFile.PutDecimal(s.Kreg); + OutFile.Put("}"); + if ((swiz & 0x20) && (s.Esss & 8)) { + // zeroing + OutFile.Put("{z}"); + } + } + } + if (swiz & 0x07) { + // broadcast, rounding or sae allowed + if (isMem && i < 8) { + // memory operand + if ((swiz & 0x01) && (s.Esss & 1)) { + // write memory broadcast + // calculate broadcast factor + uint32 op = s.Operands[i]; // operand + uint32 elementsize = GetDataElementSize(op); // element size + uint32 opv = s.Operands[0]; // any vector operand + if (!(opv & 0xF00)) opv = s.Operands[1]; // first operand is not a vector, use next + uint32 vectorsize = GetDataItemSize(opv); // vector size + if (vectorsize > elementsize) { // avoid broadcasting to scalar + if (elementsize) { // avoid division by zero + OutFile.Put(" {1to"); + OutFile.PutDecimal(vectorsize/elementsize); + OutFile.Put("}"); + } + else { + OutFile.Put("{unknown broadcast}"); + } + } + } + } + if (i == 98 && s.Mod == 3) { // after last SIMD operand. no memory operand + // NASM has rounding mode and sae decoration after last SIMD operand with a comma. + // No spec. for other assemblers available yet (2014). + // use i == 99 if it should be placed after last operand. + // Perhaps the comma should be removed for other assemblers? + if ((swiz & 0x4) && (s.Esss & 1)) { + // write rounding mode + uint32 rounding = (s.Esss >> 1) & 3; + OutFile.Put(", {"); + OutFile.Put(EVEXRoundingNames[rounding]); + OutFile.Put("}"); + } + else if ((swiz & 0x2) && (s.Esss & 1)) { + // no rounding mode. write sae + OutFile.Put(", {"); + OutFile.Put(EVEXRoundingNames[4]); + OutFile.Put("}"); + } + } + } +} + + +void CDisassembler::WriteOperandAttributeMVEX(int i, int isMem) { + // Write operand attributes and instruction attributes from MVEX sss, e and kkk bits. + // i = operand number (0 = destination, 1 = first source, 2 = second source, 99 = after last operand) + // isMem: true if memory operand, false if register operand + uint32 swiz = s.OpcodeDef->MVEX; // indicates meaning of MVEX attribute bits + const int R_sae_syntax = 0; // syntax alternatives for rounding mode + sae + // 0: {rn-sae}, 1: {rn}{sae} + const char * text = 0; // temporary text pointer + + if ((swiz & 0x1000) && (i == 0 || (s.OpcodeDef->Destination == 0 && i == 1))) { // first operand + // write mask + if (s.Kreg || (swiz & 0x2000)) { + OutFile.Put(" {k"); + OutFile.PutDecimal(s.Kreg); + OutFile.Put("}"); + } + } + if (swiz & 0x1F) { + // swizzle allowed + if (isMem && i < 90) { + // write memory broadcast/up/down conversion + text = s.SwizRecord->name; + if (text && *text) { + OutFile.Put(" {"); OutFile.Put(text); OutFile.Put("}"); + } + } + //if (i == 2 || ((s.OpcodeDef->Source2 & 0xF0F00) == 0 && i == 1)) { + if (i == 98) { // after last SIMD operand + // last register or memory operand + if (s.Mod == 3 && !((swiz & 0x700) && (s.Esss & 8))) { // skip alternative meaning of sss field for register operand when E=1 + // write register swizzle + text = s.SwizRecord->name; + if (text && *text) { + OutFile.Put(" {"); OutFile.Put(text); OutFile.Put("}"); + } + } + } + if (i == 99) { // after last operand + if (s.Mod == 3 && (swiz & 0x300) && (s.Esss & 8)) { + // alternative meaning of sss field for register operand when E=1 + switch (swiz & 0x300) { + case 0x100: // rounding mode and not sae + text = SwizRoundTables[0][0][s.Esss & 3].name; + break; + case 0x200: // suppress all exceptions + if ((s.Esss & 4) && !(swiz & 0x800)) text = "sae"; + break; + case 0x300: // rounding mode and sae + text = SwizRoundTables[0][R_sae_syntax][s.Esss & 7].name; + break; + } + } + if (text && *text) { + OutFile.Put(", {"); OutFile.Put(text); OutFile.Put("}"); + } + } + } + if (isMem && (s.Esss & 8) && !(swiz & 0x800)) { + // cache eviction hint after memory operand + OutFile.Put(" {eh}"); + } +} + +void CDisassembler::WriteRegisterName(uint32 Value, uint32 Type) { + // Write name of register to OutFile + if (Type & 0xF00) { + // vector register + Type &= 0xF00; + } + else { + // Other register + Type &= 0xFF; // Remove irrelevant bits + } + + // Check fixed registers (do not depend on Value) + switch (Type) { + case 0xA1: // al + Type = 1; Value = 0; + break; + + case 0xA2: // ax + Type = 2; Value = 0; + break; + + case 0xA3: // eax + Type = 3; Value = 0; + break; + + case 0xA4: // rax + Type = 4; Value = 0; + break; + + case 0xAE: // xmm0 + Type = 0x400; Value = 0; + break; + + case 0xAF: // st(0) + Type = 0x40; Value = 0; + break; + + case 0xB2: // dx + Type = 2; Value = 2; + break; + + case 0xB3: // cl + Type = 1; Value = 1; + break; + } + + // Get register number limit + uint32 RegNumLimit = 7; // largest register number + if (WordSize >= 64) { + RegNumLimit = 15; + if ((s.Prefixes[6] & 0x40) && (Type & 0xF40)) { + // EVEX or MVEX prefix and vector + RegNumLimit = 31; + } + } + + switch (Type) { + case 0x91: // segment register + RegNumLimit = 5; + break; + case 0x300: // mmx + case 0x40: // st register + case 0x95: // k mask register + RegNumLimit = 7; + break; + case 0x98: // bounds register + RegNumLimit = 3; + break; + } + if (Value > RegNumLimit) { + // register number out of range + OutFile.Put("unknown register "); + switch (Type) { + case 1: + OutFile.Put("(8 bit) "); break; + case 2: + OutFile.Put("(16 bit) "); break; + case 3: + OutFile.Put("(32 bit) "); break; + case 4: + OutFile.Put("(64 bit) "); break; + case 0x40: // st register + OutFile.Put("st"); break; + case 0x91: // Segment register + OutFile.Put("seg"); break; + case 0x92: // Control register + OutFile.Put("cr"); break; + case 0x95: // k mask register + OutFile.Put("k"); break; + case 0x300: // mmx register + OutFile.Put("mm"); break; + case 0x400: // xmm register + OutFile.Put("xmm"); break; + case 0x500: // ymm register + OutFile.Put("ymm"); break; + case 0x600: // zmm register + OutFile.Put("zmm"); break; + case 0x700: // future 1024 bit register + OutFile.Put("?mm"); break; + } + OutFile.PutDecimal(Value); + } + else { + // Write register name depending on type + switch (Type) { + case 1: // 8 bit register. Depends on any REX prefix + OutFile.Put(s.Prefixes[7] ? RegisterNames8x[Value] : RegisterNames8[Value & 7]); + break; + + case 2: // 16 bit register + OutFile.Put(RegisterNames16[Value]); + break; + + case 3: // 32 bit register + OutFile.Put(RegisterNames32[Value]); + break; + + case 4: // 64 bit register + OutFile.Put(RegisterNames64[Value]); + break; + + case 0x300: // mmx register + OutFile.Put("mm"); + OutFile.PutDecimal(Value); + break; + + case 0x400: // xmm register (packed integer or float) + case 0x48: case 0x4B: case 0x4C: // xmm register (scalar float) + OutFile.Put("xmm"); + OutFile.PutDecimal(Value); + break; + + case 0x500: // ymm register (packed) + OutFile.Put("ymm"); + OutFile.PutDecimal(Value); + break; + + case 0x600: // zmm register (packed) + OutFile.Put("zmm"); + OutFile.PutDecimal(Value); + break; + + case 0x700: // future 1024 bit register + OutFile.Put("?mm"); + OutFile.PutDecimal(Value); + break; + + case 0x40: // st register + if (Syntax == SUBTYPE_YASM) { + // NASM, YASM and GAS-AT&T use st0 + OutFile.Put("st"); + OutFile.PutDecimal(Value); + } + else { + // MASM and GAS-Intel use st(0), + OutFile.Put("st("); + OutFile.PutDecimal(Value); + OutFile.Put(")"); + } + break; + + case 0x91: // Segment register + OutFile.Put(RegisterNamesSeg[Value & 7]); + break; + + case 0x92: // Control register + OutFile.Put(RegisterNamesCR[Value]); + break; + + case 0x93: // Debug register + OutFile.Put("dr"); + OutFile.PutDecimal(Value); + break; + + case 0x94: // Test register (obsolete) + OutFile.Put("tr"); + OutFile.PutDecimal(Value); + break; + + case 0x95: // k mask register + OutFile.Put("k"); + OutFile.PutDecimal(Value); + break; + + case 0x98: // bounds register + OutFile.Put("bnd"); + OutFile.PutDecimal(Value); + break; + + case 0xB1: // 1 + OutFile.Put("1"); + break; + + default: // Unexpected + OutFile.Put("UNKNOWN REGISTER TYPE "); + OutFile.PutDecimal(Value); + break; + } + } +} + + +void CDisassembler::WriteImmediateOperand(uint32 Type) { + // Write immediate operand or direct jump/call address + int WriteFormat; // 0: unsigned, 1: signed, 2: hexadecimal + int Components = 0; // Number of components in immediate operand + uint32 OSize; // Operand size + uint32 FieldPointer; // Pointer to field containing value + uint32 FieldSize; // Size of field containing value + int64 Value = 0; // Value of immediate operand + + // Check if far + if ((Type & 0xFE) == 0x84) { + // Write far + WriteOperandType(Type); + } + + // Check if type override needed + if ((s.OpcodeDef->AllowedPrefixes & 2) && s.Prefixes[4] == 0x66 + && (Opcodei == 0x68 || Opcodei == 0x6A)) { + // Push immediate with non-default operand size needs type override + WriteOperandType(s.OperandSize == 16 ? 2 : 3); + } + + FieldPointer = s.ImmediateField; + FieldSize = s.ImmediateFieldSize; + + if (Syntax == SUBTYPE_YASM && (Type & 0x0F) == 4 && FieldSize == 8) { + // Write type override to make sure we get 8 bytes address in case there is a relocation here + WriteOperandType(4); + } + + if (Type & 0x200000) { + if (FieldSize > 1) { + // Uses second part of field. Single byte only + FieldPointer += FieldSize-1; + FieldSize = 1; + } + else { + // Uses half a byte + FieldSize = 0; + } + } + + // Get inline value + switch (FieldSize) { + case 0: // 4 bits + Value = Get(FieldPointer) & 0x0F; + break; + + case 1: // 8 bits + Value = Get(FieldPointer); + break; + + case 2: // 16 bits + Value = Get(FieldPointer); break; + + case 6: // 48 bits + Value = Get(FieldPointer); + Value += (uint64)Get(FieldPointer + 4) << 32; + break; + + case 4: // 32 bits + Value = Get(FieldPointer); break; + + case 8: // 64 bits + Value = Get(FieldPointer); break; + + case 3: // 16+8 bits ("Enter" instruction) + if ((Type & 0xFF) == 0x12) { + // First 16 bits + FieldSize = 2; Value = Get(FieldPointer); break; + } + // else continue in default case to get error message + + default: // Other sizes should not occur + err.submit(3000); Value = -1; + } + + // Check if relocation + if (s.ImmediateRelocation) { + // Write relocation target name + uint32 Context = 2; + if ((Type & 0xFC) == 0x80) Context = 8; // Near jump/call destination + if ((Type & 0xFC) == 0x84) Context = 0x10; // Far jump/call destination + + // Write cross reference + WriteRelocationTarget(s.ImmediateRelocation, Context, Value); + + // Remember that Value has been written + Value = 0; + Components++; + } + // Check if AAM or AAD + if (Value == 10 && (Opcodei & 0xFE) == 0xD4) { + // Don't write operand for AAM or AAD if = 10 + return; + } + + // Write as unsigned, signed or hexadecimal: + if ((Type & 0xF0) == 0x30 || (Type & 0xF0) == 0x80) { + // Hexadecimal + WriteFormat = 2; + } + else if (s.ImmediateFieldSize == 8) { + // 64 bit constant + if (Value == (int32)Value) { + // Signed + WriteFormat = 1; + } + else { + // Hexadecimal + WriteFormat = 2; + } + } + else if ((Type & 0xF0) == 0x20) { + // Signed + WriteFormat = 1; + } + else { + // Unsigned + WriteFormat = 0; + } + + if ((Type & 0xFC) == 0x80 && !s.ImmediateRelocation) { + // Self-relative jump or call without relocation. Adjust immediate value + Value += IEnd; // Get absolute address of target + + // Look for symbol at target address + uint32 ISymbol = Symbols.FindByAddress(Section, (uint32)Value); + if (ISymbol && (Symbols[ISymbol].Name || CodeMode == 1)) { + // Symbol found. Write its name + OutFile.Put(Symbols.GetName(ISymbol)); + // No offset to write + return; + } + // Target address has no name + Type |= 0x4000; // Write target as hexadecimal + } + + // Operand size + if ((s.Operands[0] & 0xFFF) <= 0xA || (s.Operands[0] & 0xF0) == 0xA0) { + // Destination is general purpose register + OSize = s.OperandSize; + } + else { + // Constant probably unrelated to destination size + OSize = 8; + } + // Check if destination is 8 bit operand + //if ((s.Operands[0] & 0xFF) == 1 || (s.Operands[0] & 0xFF) == 0xA1) OSize = 8; + + // Check if sign extended + if (OSize > s.ImmediateFieldSize * 8) { + if (WriteFormat == 2 && Value >= 0) { + // Hexadecimal sign extended, not negative: + // Does not need full length + OSize = s.ImmediateFieldSize * 8; + } + else if (WriteFormat == 0) { + // Unsigned and sign extended, change to signed + WriteFormat = 1; + } + } + + if (Components) { + // There was a relocated name + if (Value) { + // Addend to relocation is not zero + if (Value > 0 || WriteFormat != 1) { + OutFile.Put("+"); // Put "+" between name and addend + } + else { + OutFile.Put("-"); // Put "-" between name and addend + Value = - Value; // Change sign to avoid another "-" + } + } + else { + // No addend to relocated name + return; + } + } + // Write value + if (WriteFormat == 2) { + // Write with hexadecimal number appropriate size + switch (OSize) { + case 8: // 8 bits + OutFile.PutHex((uint8)Value, 1); break; + case 16: // 16 bits + if ((Type & 0xFC) == 0x84) { + // Segment of far call + OutFile.PutHex((uint16)(Value >> 16), 1); + OutFile.Put(':'); + } + OutFile.PutHex((uint16)Value, 2); break; + case 32: // 32 bits + default: // Should not occur + if ((Type & 0xFC) == 0x84) { + // Segment of far call + OutFile.PutHex((uint16)(Value >> 32), 1); + OutFile.Put(':'); + } + OutFile.PutHex((uint32)Value, 2); break; + case 64: // 64 bits + OutFile.PutHex((uint64)Value, 2); break; + } + } + else { + // Write as signed or unsigned decimal + if (WriteFormat == 0) { // unsigned + switch (OSize) { + case 8: // 8 bits + Value &= 0x00FF; break; + case 16: // 16 bits + Value &= 0xFFFF; break; + } + } + OutFile.PutDecimal((int32)Value, WriteFormat); // Write value. Signed or usigned decimal + } +} + + +void CDisassembler::WriteOtherOperand(uint32 Type) { + // Write other type of operand + const char * * OpRegisterNames; // Pointer to list of register names + uint32 RegI = 0; // Index into list of register names + + switch (Type & 0x8FF) { + case 0xA1: // AL + OpRegisterNames = RegisterNames8; + break; + case 0xA2: // AX + OpRegisterNames = RegisterNames16; + break; + case 0xA3: // EAX + OpRegisterNames = RegisterNames32; + break; + case 0xA4: // RAX + OpRegisterNames = RegisterNames64; + break; + case 0xAE: // xmm0 + OutFile.Put("xmm0"); + return; + case 0xAF: // ST(0) + OutFile.Put("st(0)"); + return; + case 0xB1: // 1 + OutFile.Put("1"); + return; + case 0xB2: // DX + OpRegisterNames = RegisterNames16; + RegI = 2; + break; + case 0xB3: // CL + OpRegisterNames = RegisterNames8; + RegI = 1; + break; + default: + OutFile.Put("unknown operand"); + err.submit(3000); + return; + } + // Write register name + OutFile.Put(OpRegisterNames[RegI]); +} + + +void CDisassembler::WriteErrorsAndWarnings() { + // Write errors, warnings and comments, if any + uint32 n; // Error bit + if (s.Errors) { + // There are errors + // Loop through all bits in s.Errors + for (n = 1; n; n <<= 1) { + if (s.Errors & n) { + if (OutFile.GetColumn()) OutFile.NewLine(); + OutFile.Put(CommentSeparator); // Write "\n; " + OutFile.Put("Error: "); // Write "Error: " + OutFile.Put(Lookup(AsmErrorTexts,n));// Write error text + OutFile.NewLine(); + } + } + } + + if (s.Warnings1) { + // There are warnings 1 + // Loop through all bits in s.Warnings1 + for (n = 1; n; n <<= 1) { + if (s.Warnings1 & n) { + if (OutFile.GetColumn()) OutFile.NewLine(); + OutFile.Put(CommentSeparator); // Write "; " + OutFile.Put("Note: "); // Write "Note: " + OutFile.Put(Lookup(AsmWarningTexts1, n));// Write warning text + OutFile.NewLine(); + } + } + } + if (s.Warnings2) { + // There are warnings 2 + // Loop through all bits in s.Warnings2 + for (n = 1; n; n <<= 1) { + if (s.Warnings2 & n) { + if (OutFile.GetColumn()) OutFile.NewLine(); + OutFile.Put(CommentSeparator); // Write "; " + OutFile.Put("Warning: "); // Write "Warning: " + OutFile.Put(Lookup(AsmWarningTexts2, n)); // Write warning text + OutFile.NewLine(); + } + } + if (s.Warnings2 & 1) { + // Write spurious label + uint32 sym1 = Symbols.FindByAddress(Section, LabelEnd); + if (sym1) { + const char * name = Symbols.GetName(sym1); + OutFile.Put(CommentSeparator); + OutFile.Put(name); + OutFile.Put("; Misplaced symbol at address "); + OutFile.PutHex(Symbols[sym1].Offset); + OutFile.NewLine(); + } + } + } + + if (s.OpcodeDef && (s.OpcodeDef->AllowedPrefixes & 8) && !s.Warnings1) { + if (s.Prefixes[0]) { + // Branch hint prefix. Write comment + OutFile.Put(CommentSeparator); // Write "; " + switch (s.Prefixes[0]) { + case 0x2E: + OutFile.Put("Branch hint prefix for Pentium 4: Predict no jump"); + break; + case 0x3E: + OutFile.Put("Branch hint prefix for Pentium 4: Predict jump"); + break; + case 0x64: + OutFile.Put("Branch hint prefix for Pentium 4: Predict alternate"); + break; + default: + OutFile.Put("Note: Unrecognized branch hint prefix"); + } + OutFile.NewLine(); + } + } +} + +void CDisassembler::WriteSymbolName(uint32 symi) { + // Write symbol name. symi = new symbol index + OutFile.Put(Symbols.GetName(symi)); +} + +void CDisassembler::WriteSectionName(int32 SegIndex) { + // Write name of section, segment or group from section index + const char * Name = 0; + // Check for special index values + switch (SegIndex) { + case ASM_SEGMENT_UNKNOWN: // Unknown segment. Typical for external symbols + Name = "Unknown"; break; + case ASM_SEGMENT_ABSOLUTE: // No segment. Used for absolute symbols + Name = "Absolute"; break; + case ASM_SEGMENT_FLAT: // Flat segment group + Name = "flat"; break; + case ASM_SEGMENT_NOTHING: // No segment + Name = "Nothing"; break; + case ASM_SEGMENT_ERROR: // Segment register assumed to error + Name = "Error"; break; + case ASM_SEGMENT_IMGREL: // Segment unknown. Offset relative to image base or file base + Name = "ImageBased"; break; + default: // > 0 means normal segment index + if ((uint32)SegIndex >= Sections.GetNumEntries()) { + // Out of range + Name = "IndexOutOfRange"; + } + else { + // Get index into NameBuffer + uint32 NameIndex = Sections[SegIndex].Name; + // Check if valid + if (NameIndex == 0 || NameIndex >= NameBuffer.GetDataSize()) { + Name = "ErrorNameMissing"; + } + else { + // Normal valid name of segment, section or group + Name = NameBuffer.Buf() + NameIndex; + } + } + break; + } + if (Syntax == SUBTYPE_YASM && Name[0] == '_') { + // Change leading underscore to dot + OutFile.Put('.'); + OutFile.Put(Name+1); // Write rest of name + } + else { + // Write name + OutFile.Put(Name); + } +} + +void CDisassembler::WriteDataItems() { + // Write data items to output file + + int LineState; // 0: Start of new line, write label + // 1: Label written if any, write data directive + // 2: Data directive written, write data + // 3: First data item written, write comma and more data + // 4: Last data item written, write comment + // 5: Comment written if any, start new line + uint32 Pos = IBegin; // Current position + uint32 LinePos = IBegin; // Position for beginning of output line + uint32 BytesPerLine; // Number of bytes to write per line + uint32 LineEnd; // Data position for end of line + uint32 DataEnd; // End of data + uint32 ElementSize, OldElementSize; // Size of each data element + uint32 RelOffset; // Offset of relocation + uint32 irel, Oldirel; // Relocation index + int64 Value; // Inline value or addend + const char * Symname; // Symbol name + int SeparateLine; // Label is on separate line + + SARelocation Rel; // Dummy relocation record + + // Check if size is valid + if (DataSize == 0) DataSize = 1; + if (DataSize > 32) DataSize = 32; + + // Expected end position + if (CodeMode & 3) { + // Writing data for dubious code. Make same length as code instruction + DataEnd = IEnd; + } + else { + // Regular data. End at next label + DataEnd = LabelEnd; + if (DataEnd > FunctionEnd) DataEnd = FunctionEnd; + if (DataEnd <= Pos) DataEnd = Pos + DataSize; + if (DataEnd > Sections[Section].InitSize && Pos < Sections[Section].InitSize) { + DataEnd = Sections[Section].InitSize; + } + } + + // Size of each data element + ElementSize = DataSize; + + // Check if packed type + if (DataType & 0xF00) { + // This is a packed vector type. Get element size + ElementSize = GetDataElementSize(DataType); + } + + // Avoid sizes that are not powers of 2 + if (ElementSize == 6 || ElementSize == 10) ElementSize = 2; + + // Set maximum element size to 8 + if (ElementSize > 8) ElementSize = 8; + + // Set minimum element size to 1 + if (ElementSize < 1) ElementSize = 1; + + if (Pos + ElementSize > DataEnd) { + // Make sure we end at DataEnd + ElementSize = 1; BytesPerLine = 8; + LineEnd = DataEnd; + } + + // Set number of bytes per line + BytesPerLine = (DataSize == 10) ? 10 : 8; + + if (!(CodeMode & 3)) { + // Begin new line for each data item (except in code segment) + OutFile.NewLine(); + } + LineState = 0; irel = 0; + + // Check if alignment required + if (DataSize >= 16 && (DataType & 0xC00) && (DataType & 0xFF) != 0x51 + && (FlagPrevious & 0x100) < (DataSize << 4) && !(IBegin & (DataSize-1))) { + // Write align directive + WriteAlign(DataSize); + // Remember that data is aligned + FlagPrevious |= (DataSize << 4); + } + + // Get symbol name for label + uint32 sym; // Current symbol index + uint32 sym1, sym2 = 0; // First and last symbol at current address + + sym1 = Symbols.FindByAddress(Section, Pos, &sym2); + + // Loop for one or more symbols at this address + for (sym = sym1; sym <= sym2; sym++) { + + if (sym && Symbols[sym].Scope && !(Symbols[sym].Scope & 0x100) && !(Symbols[sym].Type & 0x80000000)) { + + // Prepare for writing symbol label + Symname = Symbols.GetName(sym); // Symbol name + // Check if label needs a separate line + SeparateLine = (ElementSize != DataSize + || Symbols[sym].Size != DataSize + || strlen(Symname) > AsmTab1 + || sym < sym2 + // || (Sections[Section].Type & 0xFF) == 3 + || ((Symbols[sym].Type+1) & 0xFE) == 0x0C); + + // Write symbol label + switch (Syntax) { + case SUBTYPE_MASM: + WriteDataLabelMASM(Symname, sym, SeparateLine); break; + case SUBTYPE_YASM: + WriteDataLabelYASM(Symname, sym, SeparateLine); break; + case SUBTYPE_GASM: + WriteDataLabelGASM(Symname, sym, SeparateLine); break; + } + LineState = 1; // Label written + if (SeparateLine) { + LineState = 0; + } + } + } + + if ((Sections[Section].Type & 0xFF) == 3 || Pos >= Sections[Section].InitSize) { + // This is an unitialized data (BSS) section + // Data repeat count + uint32 DataCount = (DataEnd - Pos) / ElementSize; + if (DataCount) { + OutFile.Tabulate(AsmTab1); + // Write data directives + switch (Syntax) { + case SUBTYPE_MASM: + WriteUninitDataItemsMASM(ElementSize, DataCount); break; + case SUBTYPE_YASM: + WriteUninitDataItemsYASM(ElementSize, DataCount); break; + case SUBTYPE_GASM: + WriteUninitDataItemsGASM(ElementSize, DataCount); break; + } + // Write comment + WriteDataComment(ElementSize, Pos, Pos, 0); + OutFile.NewLine(); + LineState = 0; + } + // Update data position + Pos += DataCount * ElementSize; + + if (Pos < DataEnd) { + // Some odd data remain. Write as bytes + DataCount = DataEnd - Pos; + ElementSize = 1; + OutFile.Tabulate(AsmTab1); + switch (Syntax) { + case SUBTYPE_MASM: + WriteUninitDataItemsMASM(ElementSize, DataCount); break; + case SUBTYPE_YASM: + WriteUninitDataItemsYASM(ElementSize, DataCount); break; + case SUBTYPE_GASM: + WriteUninitDataItemsGASM(ElementSize, DataCount); break; + } + // Write comment + WriteDataComment(ElementSize, Pos, Pos, 0); + OutFile.NewLine(); + Pos = DataEnd; + LineState = 0; + } + } + else { + // Not a BSS section + // Label has been written, write data + + // Loop for one or more elements + LinePos = Pos; + while (Pos < DataEnd) { + + // Find end of line position + LineEnd = LinePos + BytesPerLine; + + // Remember element size and relocation + OldElementSize = ElementSize; + Oldirel = irel; + + // Check if relocation + Rel.Section = Section; + Rel.Offset = Pos; + uint32 irel = Relocations.FindFirst(Rel); + if (irel >= Relocations.GetNumEntries() || Relocations[irel].Section != (int32)Section) { + // No relevant relocation + irel = 0; + } + if (irel) { + // A relocation is found + // Check relocation source + RelOffset = Relocations[irel].Offset; + if (RelOffset == Pos) { + // Relocation source is here + // Make sure the size fits and begin new line + ElementSize = Relocations[irel].Size; BytesPerLine = 8; + if (ElementSize < 1) ElementSize = WordSize / 8; + if (ElementSize < 1) ElementSize = 4; + LineEnd = Pos + ElementSize; + if (LineState > 2) LineState = 4; // Make sure we begin at new line + } + else if (RelOffset < Pos + ElementSize) { + // Relocation source begins before end of element with current ElementSize + // Change ElementSize to make sure a new element begins at relocation source + ElementSize = 1; BytesPerLine = 8; + LineEnd = RelOffset; + if (LineState > 2) LineState = 4; // Make sure we begin at new line + irel = 0; + } + else { + // Relocation is after this element + irel = 0; + } + // Check for overlapping relocations + if (irel && irel+1 < Relocations.GetNumEntries() + && Relocations[irel+1].Section == (int32)Section + && Relocations[irel+1].Offset < RelOffset + ElementSize) { + // Overlapping relocations + s.Errors |= 0x2000; + WriteErrorsAndWarnings(); + LineEnd = Relocations[irel+1].Offset; + if (LineState > 2) LineState = 4; // Make sure we begin at new line + } + // Drop alignment + FlagPrevious &= ~0xF00; + } + if (irel == 0) { + // No relocation here + // Check if DataEnd would be exceeded + if (Pos + ElementSize > DataEnd) { + // Make sure we end at DataEnd unless there is a relocation source here + ElementSize = 1; BytesPerLine = 8; + LineEnd = DataEnd; + if (LineState > 2) LineState = 4; // Make sure we begin at new line + FlagPrevious &= ~0xF00; // Drop alignment + } + } + // Check if new line needed + if (LineState == 4) { + // Finish this line + if (!(CodeMode & 3)) { + WriteDataComment(OldElementSize, LinePos, Pos, Oldirel); + } + // Start new line + OutFile.NewLine(); + LineState = 0; + LinePos = Pos; + continue; + } + + // Tabulate + OutFile.Tabulate(AsmTab1); + + if (LineState < 2) { + // Write data definition directive for appropriate size + switch (Syntax) { + case SUBTYPE_MASM: + WriteDataDirectiveMASM(ElementSize); break; + case SUBTYPE_YASM: + WriteDataDirectiveYASM(ElementSize); break; + case SUBTYPE_GASM: + WriteDataDirectiveGASM(ElementSize); break; + } + LineState = 2; + } + else if (LineState == 3) { + // Not the first element, write comma + OutFile.Put(", "); + } + // Get inline value + switch (ElementSize) { + case 1: Value = Get(Pos); break; + case 2: Value = Get(Pos); break; + case 4: Value = Get(Pos); break; + case 6: Value = Get(Pos) + ((uint64)Get(Pos+4) << 32); break; + case 8: Value = Get(Pos); break; + case 10: Value = Get(Pos); break; + default: Value = 0; // should not occur + } + if (irel) { + // There is a relocation here. Write the name etc. + WriteRelocationTarget(irel, 1, Value); + } + else { + // Write value + switch (ElementSize) { + case 1: + OutFile.PutHex((uint8)Value, 1); + break; + case 2: + OutFile.PutHex((uint16)Value, 1); + break; + case 4: + OutFile.PutHex((uint32)Value, 1); + break; + case 6: + OutFile.PutHex((uint16)(Value >> 32), 1); + OutFile.Put(":"); + OutFile.PutHex((uint32)Value, 1); + break; + case 8: + OutFile.PutHex((uint64)Value, 1); + break; + case 10: + OutFile.Put("??"); + break; + } + } + LineState = 3; + // Increment position + Pos += ElementSize; + + // Check if end of line + if (Pos >= LineEnd || Pos >= DataEnd) LineState = 4; + + if (LineState == 4) { + // End of line + if (!(CodeMode & 3)) { + // Write comment + WriteDataComment(ElementSize, LinePos, Pos, irel); + } + OutFile.NewLine(); + LinePos = Pos; + LineState = 0; + } + } + } + + // Indicate end + if (IEnd < Pos) IEnd = Pos; + if (IEnd > LabelEnd) IEnd = LabelEnd; + if (IEnd > FunctionEnd && FunctionEnd) IEnd = FunctionEnd; + + // Reset FlagPrevious if not aligned + if (DataSize < 16 || (DataType & 0xFF) == 0x28) FlagPrevious = 0; +} + + +void CDisassembler::WriteDataLabelMASM(const char * name, uint32 sym, int line) { + // Write label before data item, MASM syntax + // name = name of data item(s) + // sym = symbol index + // line = 1 if label is on separate line, 0 if data follows on same line + // Write name + OutFile.Put(name); + // At least one space + OutFile.Put(" "); + // Tabulate + OutFile.Tabulate(AsmTab1); + + if (line) { + // Write label and type on seperate line + // Get size + uint32 Symsize = Symbols[sym].Size; + if (Symsize == 0) Symsize = DataSize; + OutFile.Put("label "); + // Write type + switch(Symsize) { + case 1: default: + OutFile.Put("byte"); break; + case 2: + OutFile.Put("word"); break; + case 4: + OutFile.Put("dword"); break; + case 6: + OutFile.Put("fword"); break; + case 8: + OutFile.Put("qword"); break; + case 10: + OutFile.Put("tbyte"); break; + case 16: + OutFile.Put("xmmword"); break; + case 32: + OutFile.Put("ymmword"); break; + } + // Check if jump table or call table + if (((Symbols[sym].Type+1) & 0xFE) == 0x0C) { + OutFile.Tabulate(AsmTab3); + OutFile.Put(CommentSeparator); + if (Symbols[sym].DLLName) { + // DLL import + OutFile.Put("import from "); + OutFile.Put(Symbols.GetDLLName(sym)); + } + else if (Symbols[sym].Type & 1) { + OutFile.Put("switch/case jump table"); + } + else { + OutFile.Put("virtual table or function pointer"); + } + } + // New line + OutFile.NewLine(); + } +} + +void CDisassembler::WriteDataLabelYASM(const char * name, uint32 sym, int line) { + // Write label before data item, YASM syntax + // name = name of data item(s) + // sym = symbol index + // line = 1 if label is on separate line, 0 if data follows on same line + // Write name and colon + OutFile.Put(name); + OutFile.Put(": "); + // Tabulate + OutFile.Tabulate(AsmTab1); + + if (line) { + // Write label on seperate line + // Write comment + OutFile.Tabulate(AsmTab3); + OutFile.Put(CommentSeparator); + // Check if jump table or call table + if (((Symbols[sym].Type+1) & 0xFE) == 0x0C) { + if (Symbols[sym].DLLName) { + // DLL import + OutFile.Put("import from "); + OutFile.Put(Symbols.GetDLLName(sym)); + } + else if (Symbols[sym].Type & 1) { + OutFile.Put("switch/case jump table"); + } + else { + OutFile.Put("virtual table or function pointer"); + } + } + else { + // Write size + uint32 Symsize = Symbols[sym].Size; + if (Symsize == 0) Symsize = DataSize; + switch(Symsize) { + case 1: default: + OutFile.Put("byte"); break; + case 2: + OutFile.Put("word"); break; + case 4: + OutFile.Put("dword"); break; + case 6: + OutFile.Put("fword"); break; + case 8: + OutFile.Put("qword"); break; + case 10: + OutFile.Put("tbyte"); break; + case 16: + OutFile.Put("oword"); break; + case 32: + OutFile.Put("yword"); break; + case 64: + OutFile.Put("zword"); break; + } + } + // New line + OutFile.NewLine(); + } +} + +void CDisassembler::WriteDataLabelGASM(const char * name, uint32 sym, int line) { + // Write label before data item, GAS syntax + // name = name of data item(s) + // sym = symbol index + // line = 1 if label is on separate line, 0 if data follows on same line + // Write name and colon + OutFile.Put(name); + OutFile.Put(": "); + // Tabulate + OutFile.Tabulate(AsmTab1); + + if (line) { + // Write label on seperate line + // Write comment + OutFile.Tabulate(AsmTab3); + OutFile.Put(CommentSeparator); + // Check if jump table or call table + if (((Symbols[sym].Type+1) & 0xFE) == 0x0C) { + if (Symbols[sym].DLLName) { + // DLL import + OutFile.Put("import from "); + OutFile.Put(Symbols.GetDLLName(sym)); + } + else if (Symbols[sym].Type & 1) { + OutFile.Put("switch/case jump table"); + } + else { + OutFile.Put("virtual table or function pointer"); + } + } + else { + // Write size + uint32 Symsize = Symbols[sym].Size; + if (Symsize == 0) Symsize = DataSize; + switch(Symsize) { + case 1: default: + OutFile.Put("byte"); break; + case 2: + OutFile.Put("word"); break; + case 4: + OutFile.Put("int"); break; + case 6: + OutFile.Put("farword"); break; + case 8: + OutFile.Put("qword"); break; + case 10: + OutFile.Put("tfloat"); break; + case 16: + OutFile.Put("xmmword"); break; + case 32: + OutFile.Put("ymmword"); break; + } + } + // New line + OutFile.NewLine(); + } +} + +void CDisassembler::WriteUninitDataItemsMASM(uint32 size, uint32 count) { + // Write uninitialized (BSS) data, MASM syntax + // size = size of each data element + // count = number of data elements on each line + + // Write data definition directive for appropriate size + switch (size) { + case 1: + OutFile.Put("db "); break; + case 2: + OutFile.Put("dw "); break; + case 4: + OutFile.Put("dd "); break; + case 6: + OutFile.Put("df "); break; + case 8: + OutFile.Put("dq "); break; + case 10: + OutFile.Put("dt "); break; + } + OutFile.Tabulate(AsmTab2); + if (count > 1) { + // Write duplication operator + OutFile.PutDecimal(count); + OutFile.Put(" dup (?)"); + } + else { + // DataCount == 1 + OutFile.Put("?"); + } +} + +void CDisassembler::WriteUninitDataItemsYASM(uint32 size, uint32 count) { + // Write uninitialized (BSS) data, YASM syntax + // Write data definition directive for appropriate size + switch (size) { + case 1: + OutFile.Put("resb "); break; + case 2: + OutFile.Put("resw "); break; + case 4: + OutFile.Put("resd "); break; + case 6: + OutFile.Put("resw "); count *= 3; break; + case 8: + OutFile.Put("resq "); break; + case 10: + OutFile.Put("rest "); break; + } + OutFile.Tabulate(AsmTab2); + OutFile.PutDecimal(count); +} + +void CDisassembler::WriteUninitDataItemsGASM(uint32 size, uint32 count) { + // Write uninitialized (BSS) data, GAS syntax + OutFile.Put(".zero"); + OutFile.Tabulate(AsmTab2); + if (count != 1) { + OutFile.PutDecimal(count); OutFile.Put(" * "); + } + OutFile.PutDecimal(size); +} + +void CDisassembler::WriteDataDirectiveMASM(uint32 size) { + // Write DB, etc., MASM syntax + // Write data definition directive for appropriate size + switch (size) { + case 1: OutFile.Put("db "); break; + case 2: OutFile.Put("dw "); break; + case 4: OutFile.Put("dd "); break; + case 6: OutFile.Put("df "); break; + case 8: OutFile.Put("dq "); break; + case 10: OutFile.Put("dt "); break; + case 16: OutFile.Put("xmmword "); break; + case 32: OutFile.Put("ymmword "); break; + default: OutFile.Put("Error "); break; + } +} + +void CDisassembler::WriteDataDirectiveYASM(uint32 size) { + // Write DB, etc., YASM syntax + // Write data definition directive for appropriate size + switch (size) { + case 1: OutFile.Put("db "); break; + case 2: OutFile.Put("dw "); break; + case 4: OutFile.Put("dd "); break; + case 6: OutFile.Put("df "); break; + case 8: OutFile.Put("dq "); break; + case 10: OutFile.Put("dt "); break; + case 16: OutFile.Put("ddq "); break; + default: OutFile.Put("Error "); break; + } +} + +void CDisassembler::WriteDataDirectiveGASM(uint32 size) { + // Write DB, etc., GAS syntax + // Write data definition directive for appropriate size + switch (size) { + case 1: OutFile.Put(".byte "); break; + case 2: OutFile.Put(".short "); break; + case 4: OutFile.Put(".int "); break; + case 8: OutFile.Put(".quad "); break; + case 10: OutFile.Put(".tfloat "); break; + default: OutFile.Put("Error "); break; + } +} + + +void CDisassembler::WriteDataComment(uint32 ElementSize, uint32 LinePos, uint32 Pos, uint32 irel) { + // Write comment after data item + uint32 pos1; // Position of data for comment + uint32 RelType = 0; // Relocation type + char TextBuffer[64]; // Buffer for writing floating point number + + OutFile.Tabulate(AsmTab3); // Tabulate to comment field + OutFile.Put(CommentSeparator); // Start comment + + // Write address + if (SectionEnd + SectionAddress + (uint32)ImageBase > 0xFFFF) { + // Write 32 bit address + OutFile.PutHex(LinePos + SectionAddress + (uint32)ImageBase); + } + else { + // Write 16 bit address + OutFile.PutHex((uint16)(LinePos + SectionAddress)); + } + + if ((Sections[Section].Type & 0xFF) == 3 || Pos > Sections[Section].InitSize) { + // Unitialized data. Write no data + return; + } + + if (irel && irel < Relocations.GetNumEntries() && Relocations[irel].Offset == LinePos) { + // Value is relocated, get relocation type + RelType = Relocations[irel].Type; + } + + // Space after address + OutFile.Put(" _ "); + + // Comment type depends on ElementSize and DataType + switch (ElementSize) { + case 1: + // Bytes. Write ASCII characters + for (pos1 = LinePos; pos1 < Pos; pos1++) { + // Get character + int8 c = Get(pos1); + // Avoid non-printable characters + if (c < ' ' || c == 0x7F) c = '.'; + // Print ASCII character + OutFile.Put(c); + } + break; + case 2: + // Words. Write as decimal + for (pos1 = LinePos; pos1 < Pos; pos1 += 2) { + if (RelType) { + OutFile.PutHex(Get(pos1), 1); // Write as hexadecimal + } + else { + OutFile.PutDecimal(Get(pos1), 1);// Write as signed decimal + } + OutFile.Put(' '); + } + break; + case 4: + // Dwords + for (pos1 = LinePos; pos1 < Pos; pos1 += 4) { + if ((DataType & 0x47) == 0x43) { + // Write as float + sprintf(TextBuffer, "%.8G", Get(pos1)); + OutFile.Put(TextBuffer); + // Make sure the number has a . or E to indicate a floating point number + if (!strchr(TextBuffer,'.') && !strchr(TextBuffer,'E')) OutFile.Put(".0"); + } + else if (((DataType + 1) & 0xFF) == 0x0C || RelType) { + // jump/call address or offset. Write as hexadecimal + OutFile.PutHex(Get(pos1)); + } + else { + // Other. Write as decimal + OutFile.PutDecimal(Get(pos1), 1); + } + OutFile.Put(' '); + } + break; + case 8: + // Qwords + for (pos1 = LinePos; pos1 < Pos; pos1 += 8) { + if ((DataType & 0x47) == 0x44) { + // Write as double + sprintf(TextBuffer, "%.16G", Get(pos1)); + OutFile.Put(TextBuffer); + // Make sure the number has a . or E to indicate a floating point number + if (!strchr(TextBuffer,'.') && !strchr(TextBuffer,'E')) OutFile.Put(".0"); + } + else { + // Write as hexadecimal + OutFile.PutHex(Get(pos1)); + } + OutFile.Put(' '); + } + break; + case 10: + // tbyte. Many compilers do not support long doubles in sprintf. Write as bytes + for (pos1 = LinePos; pos1 < Pos; pos1++) { + OutFile.PutHex(Get(pos1), 1); + } + break; + } + if (RelType) { + // Indicate relocation type + OutFile.Put(Lookup(RelocationTypeNames, RelType)); + } +} + + +void CDisassembler::WriteRelocationTarget(uint32 irel, uint32 Context, int64 Addend) { + // Write cross reference, including addend, but not including segment override and [] + // irel = index into Relocations + // Context: + // 1 = Data definition + // 2 = Immediate data field in instruction + // 4 = Data address in instruction + // 8 = Near jump/call destination + // 0x10 = Far jump/call destination + // 0x100 = Self-relative address expected + // Addend: inline addend + // Implicit parameters: + // IBegin: value of '$' operator + // IEnd: reference point for self-relative addressing + // BaseReg, IndexReg + + uint32 RefFrame; // Target segment + int32 Addend2 = 0; // Difference between '$' and reference point + + // Get relocation type + uint32 RelType = Relocations[irel].Type; + + if (RelType & 0x60) { + // Inline addend is already relocated. + // Ignore addend and treat as direct relocation + RelType = 1; + Addend = 0; + } + + // Get relocation size + uint32 RelSize = Relocations[irel].Size; + + // Get relocation addend + Addend += Relocations[irel].Addend; + + // Get relocation target + uint32 Target = Relocations[irel].TargetOldIndex; + + // Is offset operand needed? + if (Syntax != SUBTYPE_YASM && ( + ((RelType & 0xB) && (Context & 2)) + || ((RelType & 8) && (Context & 0x108)))) { + // offset operator needed to convert memory operand to immediate address + OutFile.Put("offset "); + } + + // Is seg operand needed? + if (RelType & 0x200) { + // seg operator needed to convert memory operand to its segment + OutFile.Put("seg "); + } + + // Is explicit segment or frame needed? + if ((RelType & 0x408) && (Context & 0x11B)) { + // Write name of segment/group frame + RefFrame = Relocations[irel].RefOldIndex; + if (!RefFrame) { + // No frame. Use segment of symbol + RefFrame = Symbols[Symbols.Old2NewIndex(Target)].Section; + } + if (RefFrame && RefFrame < Sections.GetNumEntries()) { + // Write segment or group name + const char * SecName = NameBuffer.Buf()+Sections[RefFrame].Name; + OutFile.Put(SecName); + OutFile.Put(":"); + } + } + + // Is imagerel operator needed? + if (RelType & 4) { + // imagerel operator needed to get image-relative address + OutFile.Put("imagerel("); + } + + // Adjust addend + // Adjust offset if self-relative relocation expected and found + if ((RelType & 2) && (Context & 0x108)) { + // Self-relative relocation expected and found + // Adjust by size of address field and immediate field + Addend += IEnd - Relocations[irel].Offset; + } + // Subtract self-reference if unexpected self-relative relocation + if ((RelType & 2) && !(Context & 0x108)) { + // Self-relative relocation found but not expected + // Fix difference between '$' and reference point + Addend2 = Relocations[irel].Offset - IBegin; + Addend -= Addend2; + } + // Add self-reference if self-relative relocation expected but not found + if (!(RelType & 2) && (Context & 0x108)) { + // Self-relative relocation expected but not found + // Fix difference between '$' and reference point + Addend += IEnd - IBegin; + } + + if (RelType & 0x100) { + // Target is a segment + RefFrame = Symbols[Symbols.Old2NewIndex(Target)].Section; + if (RefFrame && RefFrame < Sections.GetNumEntries()) { + const char * SecName = NameBuffer.Buf()+Sections[RefFrame].Name; + OutFile.Put(SecName); + } + else { + OutFile.Put("undefined segment"); + } + } + else { + // Target is a symbol + + // Find target symbol + uint32 TargetSym = Symbols.Old2NewIndex(Target); + + // Check if Target is appropriate + if (((Symbols[TargetSym].Type & 0x80000000) || (int32)Addend) + && !(CodeMode == 1 && s.BaseReg)) { + // Symbol is a start-of-section entry in symbol table, or has an addend + // Look for a more appropriate symbol, except if code with base register + uint32 sym, sym1, sym2 = 0; + sym1 = Symbols.FindByAddress(Symbols[TargetSym].Section, Symbols[TargetSym].Offset + (int32)Addend, &sym2); + for (sym = sym1; sym && sym <= sym2; sym++) { + if (Symbols[sym].Scope && !(Symbols[sym].Type & 0x80000000)) { + // Found a better symbol name for target address + TargetSym = sym; + Addend = Addend2; + } + } + } + // Write name of target symbol + OutFile.Put(Symbols.GetName(TargetSym)); + + if (Syntax == SUBTYPE_GASM && ( + RelType == 0x41 || RelType == 0x81 || RelType == 0x2002)) { + // make PLT entry + OutFile.Put("@PLT"); + } + } + + // End parenthesis if we started one + if (RelType & 4) { + OutFile.Put(")"); + } + + // Subtract reference point, if any + if (RelType & 0x10) { + OutFile.Put("-"); + // Write name of segment/group frame + uint32 RefPoint = Relocations[irel].RefOldIndex; + if (RefPoint) { + // Reference point name valid + OutFile.Put(Symbols.GetNameO(RefPoint)); + } + else { + OutFile.Put("Reference_Point_Missing"); + } + } + + // Subtract self-reference if unexpected self-relative relocation + if ((RelType & 2) && !(Context & 0x108)) { + // Self-relative relocation found but not expected + OutFile.Put("-"); OutFile.Put(HereOperator); + } + + // Add self-reference if self-relative relocation expected but not found + if (!(RelType & 2) && (Context & 0x108)) { + // Self-relative relocation expected but not found + OutFile.Put("+"); OutFile.Put(HereOperator); + } + + // Write addend, if not zero + if (Addend) { + if (Addend < 0) { + // Negative, write "-" + OutFile.Put("-"); + Addend = -Addend; + } + else { + // Positive, write "+" + OutFile.Put("+"); + } + + // Write value as hexadecimal + switch (RelSize) { + case 1: + OutFile.PutHex((uint8)Addend, 1); + break; + case 2: + OutFile.PutHex((uint16)Addend, 2); + break; + case 4: + OutFile.PutHex((uint32)Addend, 2); + break; + case 6: + OutFile.PutHex((uint16)(Addend >> 32), 1); + OutFile.Put(":"); + OutFile.PutHex((uint32)Addend, 1); + break; + case 8: + OutFile.PutHex((uint64)Addend, 2); + break; + default: + OutFile.Put("??"); // Should not occur + break; + } + } +} + + +int CDisassembler::WriteFillers() { + // Check if code is a series of NOPs or other fillers. + // If so then write it as filler and return 1. + // If not, then return 0. + + // Check if code is filler + if (!(OpcodeOptions & 0x40)) { + // This instruction can not be used as filler + return 0; + } + uint32 FillerType; // Type of filler + const char * FillerName = s.OpcodeDef->Name; // Name of filler + uint32 IFillerBegin = IBegin; // Start of filling space + uint32 IFillerEnd; // End of filling space + + // check for CC = int 3 breakpoint, 3C00 = 90 NOP, 11F = multibyte NOP + if (Opcodei == 0xCC || (Opcodei & 0xFFFE) == 0x3C00 || Opcodei == 0x11F) { + // Instruction is a NOP or int 3 breakpoint + FillerType = Opcodei; + } + else if (s.Warnings1 & 0x1000000) { + // Instruction is a LEA, MOV, etc. with same source and destination + // used as a multi-byte NOP + FillerType = 0xFFFFFFFF; + } + else { + // This instruction does something. Not a filler + return 0; + } + // Save beginning position + IFillerEnd = IEnd = IBegin; + + // Loop through instructions to find all consecutive fillers + while (NextInstruction2()) { + + // Parse instruction + ParseInstruction(); + + // Check if code is filler + if (!(OpcodeOptions & 0x40)) { + // This instruction can not be a filler + // Save position of this instruction + IFillerEnd = IBegin; + break; + } + if (Opcodei != 0xCC && (Opcodei & 0xFFFE) != 0x3C00 && Opcodei != 0x11F + && !(s.Warnings1 & 0x1000000)) { + // Not a filler + // Save position of this instruction + IFillerEnd = IBegin; + break; + } + // If loop exits here then fillers end at end of this instruction + IFillerEnd = IEnd; + } + // Safety check + if (IFillerEnd <= IFillerBegin) return 0; + + // Size of fillers + uint32 FillerSize = IFillerEnd - IFillerBegin; + + // Write size of filling space + OutFile.Put(CommentSeparator); + OutFile.Put("Filling space: "); + OutFile.PutHex(FillerSize, 2); + OutFile.NewLine(); + // Write filler type + OutFile.Put(CommentSeparator); + OutFile.Put("Filler type: "); + switch (FillerType) { + case 0xCC: + FillerName = "INT 3 Debug breakpoint"; break; + case 0x3C00: + FillerName = "NOP"; break; + case 0x3C01: + FillerName = "NOP with prefixes"; break; + case 0x011F: + FillerName = "Multi-byte NOP";break; + } + OutFile.Put(FillerName); + if (FillerType == 0xFFFFFFFF) { + OutFile.Put(" with same source and destination"); + } + + // Write as bytes + uint32 Pos; + for (Pos = IFillerBegin; Pos < IFillerEnd; Pos++) { + if (((Pos - IFillerBegin) & 7) == 0) { + // Start new line + OutFile.NewLine(); + OutFile.Put(CommentSeparator); + OutFile.Tabulate(AsmTab1); + OutFile.Put(Syntax == SUBTYPE_GASM ? ".byte " : "db "); + } + else { + // Continue on same line + OutFile.Put(", "); + } + // Write byte value + OutFile.PutHex(Get(Pos), 1); + } + // Blank line + OutFile.NewLine(); OutFile.NewLine(); + + // Find alignment + uint32 Alignment = 4; // Limit to 2^4 = 16 + + // Check if first non-filler is aligned by this value + while (Alignment && (IFillerEnd & ((1 << Alignment) - 1))) { + // Not aligned by 2^Alignment + Alignment--; + } + if (Alignment) { + + // Check if smaller alignment would do + if (Alignment > 3 && FillerSize < 1u << (Alignment-1)) { + // End is aligned by 16, but there are less than 8 filler bytes. + // Change to align 8 + Alignment--; + } + // Write align directive + WriteAlign(1 << Alignment); + // Prevent writing ALIGN again + FlagPrevious &= ~1; + } + + // Restore IBegin and IEnd to beginning of first non-filler instruction + IBegin = IEnd = IFillerEnd; + + if (LabelInaccessible == IFillerBegin && IFillerEnd < LabelEnd) { + // Mark first instruction after filler as inaccessible + LabelInaccessible = IFillerEnd; + } + + // Return success. Fillers have been written. Don't write as normal instructions + return 1; +} + +void CDisassembler::WriteAlign(uint32 a) { + // Write alignment directive + OutFile.Put(Syntax == SUBTYPE_GASM ? ".ALIGN" : "ALIGN"); + OutFile.Tabulate(AsmTab1); + OutFile.PutDecimal(a); + OutFile.NewLine(); +} + +void CDisassembler::WriteFileBegin() { + // Write begin of file + + OutFile.SetFileType(FILETYPE_ASM); + + // Initial comment + OutFile.Put(CommentSeparator); + OutFile.Put("Disassembly of file: "); + OutFile.Put(cmd.InputFile); + OutFile.NewLine(); + // Date and time. + // Note: will fail after year 2038 on computers that use 32-bit time_t + time_t time1 = time(0); + char * timestring = ctime(&time1); + if (timestring) { + // Remove terminating '\n' in timestring + for (char *c = timestring; *c; c++) { + if (*c < ' ') *c = 0; + } + // Write date and time as comment + OutFile.Put(CommentSeparator); + OutFile.Put(timestring); + OutFile.NewLine(); + } + + // Write mode + OutFile.Put(CommentSeparator); + OutFile.Put("Mode: "); + OutFile.PutDecimal(WordSize); + OutFile.Put(" bits"); + OutFile.NewLine(); + + // Write syntax dialect + OutFile.Put(CommentSeparator); + OutFile.Put("Syntax: "); + switch (Syntax) { + case SUBTYPE_MASM: + OutFile.Put(WordSize < 64 ? "MASM/ML" : "MASM/ML64"); break; + case SUBTYPE_YASM: + OutFile.Put("YASM/NASM"); break; + case SUBTYPE_GASM: + OutFile.Put("GAS(Intel)"); break; + } + OutFile.NewLine(); + + // Write instruction set as comment + // Instruction set is at least .386 if 32 bit mode + if (InstructionSetMax < 3 && (MasmOptions & 0x200)) InstructionSetMax = 3; + + // Get name of basic instruction set + const char * set0 = ""; + if (InstructionSetMax < InstructionSetNamesLen) { + set0 = InstructionSetNames[InstructionSetMax]; + } + + // Write as comment + OutFile.Put(CommentSeparator); + OutFile.Put("Instruction set: "); + OutFile.Put(set0); + + if (InstructionSetAMDMAX) { + // Get name of any AMD-specific instruction set + const char * setA = ""; + switch (InstructionSetAMDMAX) { + case 1: setA = "AMD 3DNow"; break; + case 2: setA = "AMD 3DNowE"; break; + case 4: setA = "AMD SSE4a"; break; + case 5: setA = "AMD XOP"; break; + case 6: setA = "AMD FMA4"; break; + case 7: setA = "AMD TBM"; break; + } + if (*setA) { + OutFile.Put(", "); + OutFile.Put(setA); + } + } + // VIA instruction set: + if (InstructionSetOR & 0x2000) OutFile.Put(", VIA"); + + // Additional instruction sets: + if (WordSize > 32) OutFile.Put(", x64"); + if (InstructionSetOR & 0x100) OutFile.Put(", 80x87"); + if (InstructionSetOR & 0x800) OutFile.Put(", privileged instructions"); + OutFile.NewLine(); + + if (NamesChanged) { + // Tell that symbol names have been changed + OutFile.NewLine(); + OutFile.Put(CommentSeparator); + OutFile.Put("Error: symbol names contain illegal characters,"); + OutFile.NewLine(); OutFile.Put(CommentSeparator); + OutFile.PutDecimal(NamesChanged); +#if ReplaceIllegalChars + OutFile.Put(" Symbol names changed"); +#else + OutFile.Put(" Symbol names not changed"); +#endif + OutFile.NewLine(); + } + + // Write syntax-specific initializations + switch (Syntax) { + case SUBTYPE_MASM: + WriteFileBeginMASM(); + WritePublicsAndExternalsMASM(); + break; + case SUBTYPE_YASM: + WriteFileBeginYASM(); + WritePublicsAndExternalsYASMGASM(); + break; + case SUBTYPE_GASM: + WriteFileBeginGASM(); + WritePublicsAndExternalsYASMGASM(); + break; + } +} + + +void CDisassembler::WriteFileBeginMASM() { + // Write MASM-specific file init + if (WordSize < 64) { + // Write instruction set directive, except for 64 bit assembler + const char * set1 = ""; + switch (InstructionSetMax) { + case 0: set1 = ".8086"; break; + case 1: set1 = ".186"; break; + case 2: set1 = ".286"; break; + case 3: set1 = ".386"; break; + case 4: set1 = ".486"; break; + case 5: set1 = ".586"; break; + case 6: default: + set1 = ".686"; break; + } + // Write basic instruction set + OutFile.NewLine(); + OutFile.Put(set1); + if (InstructionSetOR & 0x800) { + // Privileged. Add "p" + OutFile.Put("p"); + } + OutFile.NewLine(); + // Write extended instruction set + if (InstructionSetOR & 0x100) { + // Floating point + if (InstructionSetMax < 3) { + OutFile.Put(".8087"); OutFile.NewLine(); + } + else if (InstructionSetMax < 5) { + OutFile.Put(".387"); OutFile.NewLine(); + } + } + if (InstructionSetMax >= 0x11) { + // .xmm directive. Not differentiated between SSE, SSE2, etc. + OutFile.Put(".xmm"); OutFile.NewLine(); + } + else if (InstructionSetMax >= 7) { + // .mmx directive + OutFile.Put(".mmx"); OutFile.NewLine(); + } + } + if (MasmOptions & 1) { + // Need dotname option + OutFile.Put("option dotname"); OutFile.NewLine(); + } + if (WordSize == 32) { + // Write .model flat if 32 bit mode + OutFile.Put(".model flat"); OutFile.NewLine(); + } + // Initialize Assumes for segment registers + if (!(MasmOptions & 0x100)) { + // No 16-bit segments. Assume CS=DS=ES=SS=flat + Assumes[0]=Assumes[1]=Assumes[2]=Assumes[3] = ASM_SEGMENT_FLAT; + } + else { + // 16-bit segmented model. Segment register values unknown + Assumes[0]=Assumes[1]=Assumes[2]=Assumes[3] = ASM_SEGMENT_UNKNOWN; + } + // FS and GS assumed to ERROR + Assumes[4] = Assumes[5] = ASM_SEGMENT_ERROR; + + // Write assume if FS or GS used + // This is superfluous because an assume directive will be written at first use of FS/GS + if (MasmOptions & 2) { + OutFile.Put("assume fs:nothing"); OutFile.NewLine(); + } + if (MasmOptions & 4) { + OutFile.Put("assume gs:nothing"); OutFile.NewLine(); + } + OutFile.NewLine(); // Blank line +} + +void CDisassembler::WriteFileBeginYASM() { + // Write YASM-specific file init + OutFile.NewLine(); + if (WordSize == 64) { + OutFile.Put("default rel"); OutFile.NewLine(); + } + //if (InstructionSetMax >= 0x11) {OutFile.Put("%define xmmword oword"); OutFile.NewLine();} + //if (InstructionSetMax >= 0x19) {OutFile.Put("%define ymmword"); OutFile.NewLine();} + OutFile.NewLine(); +} + +void CDisassembler::WriteFileBeginGASM() { + // Write GAS-specific file init + OutFile.NewLine(); + OutFile.Put(CommentSeparator); + OutFile.Put("Note: Uses Intel syntax with destination operand first. Remember to"); + OutFile.NewLine(); + OutFile.Put(CommentSeparator); + OutFile.Put("put syntax directives in the beginning and end of inline assembly:"); + OutFile.NewLine(); + OutFile.Put(".intel_syntax noprefix "); + OutFile.NewLine(); OutFile.NewLine(); +} + +void CDisassembler::WritePublicsAndExternalsMASM() { + // Write public and external symbol definitions + uint32 i; // Loop counter + uint32 LinesWritten = 0; // Count lines written + const char * XName; // Name of external symbols + + // Loop through public symbols + for (i = 0; i < Symbols.GetNumEntries(); i++) { + if (Symbols[i].Scope & 0x1C) { + // Symbol is public + OutFile.Put("public "); + // Write name + OutFile.Put(Symbols.GetName(i)); + // Check if weak or communal + if (Symbols[i].Scope & 0x18) { + // Scope is weak or communal + OutFile.Tabulate(AsmTab3); + OutFile.Put(CommentSeparator); + if (Symbols[i].Scope & 8) OutFile.Put("Note: Weak. Not supported by MASM "); + if (Symbols[i].Scope & 0x10) OutFile.Put("Note: Communal. Not supported by MASM"); + } + OutFile.NewLine(); LinesWritten++; + } + } + // Blank line if anything written + if (LinesWritten) { + OutFile.NewLine(); + LinesWritten = 0; + } + // Loop through external symbols + for (i = 0; i < Symbols.GetNumEntries(); i++) { + + if (Symbols[i].Scope & 0x20) { + // Symbol is external + OutFile.Put("extern "); + // Get name + XName = Symbols.GetName(i); + // Check for dynamic import + if (Symbols[i].DLLName && strncmp(XName, Symbols.ImportTablePrefix, (uint32)strlen(Symbols.ImportTablePrefix)) == 0) { + // Remove "_imp" prefix from name + XName += (uint32)strlen(Symbols.ImportTablePrefix); + } + + // Write name + OutFile.Put(XName); + OutFile.Put(": "); + + // Write type + if ((Symbols[i].Type & 0xFE) == 0x84) { + // Far + OutFile.Put("far"); + } + else if ((Symbols[i].Type & 0xF0) == 0x80 || Symbols[i].DLLName) { + // Near + OutFile.Put("near"); + } + else { + // Data. Write size + switch (GetDataItemSize(Symbols[i].Type)) { + case 1: default: OutFile.Put("byte"); break; + case 2: OutFile.Put("word"); break; + case 4: OutFile.Put("dword"); break; + case 6: OutFile.Put("fword"); break; + case 8: OutFile.Put("qword"); break; + case 10: OutFile.Put("tbyte"); break; + case 16: OutFile.Put("xmmword"); break; + case 32: OutFile.Put("ymmword"); break; + } + } + // Add comment if DLL import + if (Symbols[i].DLLName) { + OutFile.Tabulate(AsmTab3); + OutFile.Put(CommentSeparator); + OutFile.Put(Symbols.GetDLLName(i)); + } + // Finished line + OutFile.NewLine(); LinesWritten++; + } + } + // Blank line if anything written + if (LinesWritten) { + OutFile.NewLine(); + LinesWritten = 0; + } + // Write the value of any constants + // Loop through symbols + for (i = 0; i < Symbols.GetNumEntries(); i++) { + // Local symbols included because there might be a rip-relative address to a named constant = 0 + if (Symbols[i].Section == ASM_SEGMENT_ABSOLUTE /*&& (Symbols[i].Scope & 0x1C)*/) { + // Symbol is constant + // Write name + OutFile.Put(Symbols.GetName(i)); + OutFile.Put(" equ "); + // Write value as hexadecimal + OutFile.PutHex(Symbols[i].Offset, 1); + // Write decimal value as comment + OutFile.Tabulate(AsmTab3); + OutFile.Put(CommentSeparator); + OutFile.PutDecimal(Symbols[i].Offset, 1); + OutFile.NewLine(); LinesWritten++; + } + } + // Blank line if anything written + if (LinesWritten) { + OutFile.NewLine(); + LinesWritten = 0; + } + // Write any group definitions + int32 GroupId, SegmentId; + // Loop through sections to search for group definitions + for (GroupId = 1; GroupId < (int32)Sections.GetNumEntries(); GroupId++) { + + // Get section type + uint32 SectionType = Sections[GroupId].Type; + if (SectionType & 0x800) { + // This is a segment group definition + // Count number of members + uint32 NumMembers = 0; + // Write group name + WriteSectionName(GroupId); + // Write "group" + OutFile.Put(" "); OutFile.Tabulate(AsmTab1); OutFile.Put("GROUP "); + // Search for group members + for (SegmentId = 1; SegmentId < (int32)Sections.GetNumEntries(); SegmentId++) { + if (Sections[SegmentId].Group == GroupId && !(Sections[SegmentId].Type & 0x800)) { + // is this first member? + if (NumMembers++) { + // Not first member. Write comma + OutFile.Put(", "); + } + // Write group member + WriteSectionName(SegmentId); + } + } + // End line + OutFile.NewLine(); LinesWritten++; + } + } + // Blank line if anything written + if (LinesWritten) { + OutFile.NewLine(); + LinesWritten = 0; + } +} + + +void CDisassembler::WritePublicsAndExternalsYASMGASM() { + // Write public and external symbol definitions, YASM and GAS syntax + uint32 i; // Loop counter + uint32 LinesWritten = 0; // Count lines written + const char * XName; // Name of external symbols + + // Loop through public symbols + for (i = 0; i < Symbols.GetNumEntries(); i++) { + if (Symbols[i].Scope & 0x1C) { + // Symbol is public + if (Syntax == SUBTYPE_GASM) OutFile.Put("."); + OutFile.Put("global "); + // Write name + OutFile.Put(Symbols.GetName(i)); + + // Write type + if ((Symbols[i].Type & 0xF0) == 0x80) { + // Symbol is a function + if (Syntax == SUBTYPE_YASM) { + OutFile.Put(": function"); + } + else if (Syntax == SUBTYPE_GASM) { + OutFile.NewLine(); + OutFile.Put(".type "); + OutFile.Put(Symbols.GetName(i)); + OutFile.Put(", @function"); + } + } + + // Check if weak or communal + if (Symbols[i].Scope & 0x18) { + // Scope is weak or communal + OutFile.Tabulate(AsmTab3); + OutFile.Put(CommentSeparator); + if (Symbols[i].Scope & 8) OutFile.Put("Note: Weak."); + if (Symbols[i].Scope & 0x10) OutFile.Put("Note: Communal."); + } + OutFile.NewLine(); LinesWritten++; + } + } + // Blank line if anything written + if (LinesWritten) { + OutFile.NewLine(); + LinesWritten = 0; + } + // Loop through external symbols + for (i = 0; i < Symbols.GetNumEntries(); i++) { + + if (Symbols[i].Scope & 0x20) { + // Symbol is external + if (Syntax == SUBTYPE_GASM) OutFile.Put("."); + OutFile.Put("extern "); + // Get name + XName = Symbols.GetName(i); + // Check for dynamic import + if (Symbols[i].DLLName && strncmp(XName, Symbols.ImportTablePrefix, (uint32)strlen(Symbols.ImportTablePrefix)) == 0) { + // Remove "_imp" prefix from name + XName += (uint32)strlen(Symbols.ImportTablePrefix); + } + // Write name + OutFile.Put(XName); + OutFile.Put(" "); + OutFile.Tabulate(AsmTab3); + OutFile.Put(CommentSeparator); + + // Write type + if ((Symbols[i].Type & 0xFE) == 0x84) { + // Far + OutFile.Put("far"); + } + else if ((Symbols[i].Type & 0xF0) == 0x80 || Symbols[i].DLLName) { + // Near + OutFile.Put("near"); + } + else { + // Data. Write size + switch (GetDataItemSize(Symbols[i].Type)) { + case 1: default: OutFile.Put("byte"); break; + case 2: OutFile.Put("word"); break; + case 4: OutFile.Put("dword"); break; + case 6: OutFile.Put("fword"); break; + case 8: OutFile.Put("qword"); break; + case 10: OutFile.Put("tbyte"); break; + case 16: OutFile.Put("xmmword"); break; + case 32: OutFile.Put("ymmword"); break; + } + } + // Add comment if DLL import + if (Symbols[i].DLLName) { + OutFile.Tabulate(AsmTab3); + OutFile.Put(CommentSeparator); + OutFile.Put(Symbols.GetDLLName(i)); + } + // Finished line + OutFile.NewLine(); LinesWritten++; + } + } + // Blank line if anything written + if (LinesWritten) { + OutFile.NewLine(); LinesWritten = 0; + } + // Write the value of any constants + // Loop through symbols + for (i = 0; i < Symbols.GetNumEntries(); i++) { + if (Symbols[i].Section == ASM_SEGMENT_ABSOLUTE /*&& (Symbols[i].Scope & 0x1C)*/) { + // Symbol is constant + if (Syntax == SUBTYPE_YASM) { + // Write name equ value + OutFile.Put(Symbols.GetName(i)); + OutFile.Put(" equ "); + } + else { + // Gas: write .equ name, value + OutFile.Put(".equ "); + OutFile.Tabulate(AsmTab1); + OutFile.Put(Symbols.GetName(i)); + OutFile.Put(", "); + } + // Write value as hexadecimal + OutFile.PutHex(Symbols[i].Offset, 1); + // Write decimal value as comment + OutFile.Tabulate(AsmTab3); + OutFile.Put(CommentSeparator); + OutFile.PutDecimal(Symbols[i].Offset, 1); + OutFile.NewLine(); LinesWritten++; + } + } + // Blank line if anything written + if (LinesWritten) { + OutFile.NewLine(); + LinesWritten = 0; + } + // Write any group definitions + int32 GroupId, SegmentId; + // Loop through sections to search for group definitions + for (GroupId = 1; GroupId < (int32)Sections.GetNumEntries(); GroupId++) { + // Get section type + uint32 SectionType = Sections[GroupId].Type; + if (SectionType & 0x800) { + // This is a segment group definition + // Count number of members + uint32 NumMembers = 0; + // Write group name + WriteSectionName(GroupId); + // Write "group" + OutFile.Put(" "); OutFile.Tabulate(AsmTab1); OutFile.Put("GROUP "); + // Search for group members + for (SegmentId = 1; SegmentId < (int32)Sections.GetNumEntries(); SegmentId++) { + if (Sections[SegmentId].Group == GroupId && !(Sections[SegmentId].Type & 0x800)) { + // is this first member? + if (NumMembers++) { + // Not first member. Write comma + OutFile.Put(", "); + } + // Write group member + WriteSectionName(SegmentId); + } + } + // End line + OutFile.NewLine(); LinesWritten++; + } + } + // Blank line if anything written + if (LinesWritten) { + OutFile.NewLine(); + LinesWritten = 0; + } +} + + +void CDisassembler::WriteFileEnd() { + // Write end of file + OutFile.NewLine(); + switch(Syntax) { + case SUBTYPE_MASM: + OutFile.Put("END"); break; + case SUBTYPE_GASM: + OutFile.Put(CommentSeparator); + OutFile.Put("Return to AT&T syntax with destination operand last:"); + OutFile.NewLine(); + OutFile.Put(".att_syntax prefix "); + OutFile.NewLine(); + break; + case SUBTYPE_YASM: + break; + } +} + + +void CDisassembler::WriteSegmentBegin() { + // Write begin of segment + // Choose dialect + switch (Syntax) { + case SUBTYPE_MASM: + WriteSegmentBeginMASM(); break; + case SUBTYPE_YASM: + WriteSegmentBeginYASM(); break; + case SUBTYPE_GASM: + WriteSegmentBeginGASM(); break; + } +} + + +void CDisassembler::WriteSegmentBeginMASM() { + // Write begin of segment + OutFile.NewLine(); // Blank line + + // Check if Section is valid + if (Section == 0 || Section >= Sections.GetNumEntries()) { + // Illegal segment entry + OutFile.Put("UNKNOWN SEGMENT"); OutFile.NewLine(); + return; + } + + // Write segment name + WriteSectionName(Section); + // Tabulate + OutFile.Put(" "); OutFile.Tabulate(AsmTab1); + // Write "segment" + OutFile.Put("SEGMENT "); + + // Write alignment + switch (Sections[Section].Align) { + case 0: // 1 + OutFile.Put("BYTE "); break; + case 1: // 2 + OutFile.Put("WORD "); break; + case 2: // 4 + OutFile.Put("DWORD "); break; + case 4: // 16 + OutFile.Put("PARA "); break; + //case 8: // 256 or 4096. Definition is ambiguous! + // OutFile.Put("PAGE "); break; + default: + // Non-standard alignment + OutFile.Put("ALIGN("); + OutFile.PutDecimal(1 << Sections[Section].Align); + OutFile.Put(") "); + break; + } + if (WordSize != 64) { + // "PUBLIC" not supported by ml64 assembler + OutFile.Put("PUBLIC "); + // Write segment word size if necessary + if (MasmOptions & 0x100) { + // There is at least one 16-bit segment. Write segment word size + OutFile.Put("USE"); + OutFile.PutDecimal(Sections[Section].WordSize); + OutFile.Put(" "); + } + } + // Write segment class + switch (Sections[Section].Type & 0xFF) { + case 1: + OutFile.Put("'CODE'"); break; + case 2: + OutFile.Put("'DATA'"); break; + case 3: + OutFile.Put("'BSS'"); break; + case 4: + OutFile.Put("'CONST'"); break; + default:; + // Unknown class. Write nothing + } + + // Tabulate to comment + OutFile.Put(" "); OutFile.Tabulate(AsmTab3); + OutFile.Put(CommentSeparator); + // Write section number + OutFile.Put("section number "); + OutFile.PutDecimal(Section); + + // New line + OutFile.NewLine(); + + if (Sections[Section].Type & 0x1000) { + // Communal + OutFile.Put(CommentSeparator); + OutFile.Put(" Communal section not supported by MASM"); + OutFile.NewLine(); + } + + if (WordSize == 16 && Sections[Section].Type == 1) { + // 16 bit code segment. Write ASSUME CS: SEGMENTNAME + OutFile.Put("ASSUME "); + OutFile.Tabulate(AsmTab1); + OutFile.Put("CS:"); + if (Sections[Section].Group) { + // Group name takes precedence over segment name + WriteSectionName(Sections[Section].Group); + } + else { + WriteSectionName(Section); + } + OutFile.NewLine(); + Assumes[1] = Section; + } +} + +void CDisassembler::WriteSegmentBeginYASM() { + // Write begin of segment + OutFile.NewLine(); // Blank line + + // Check if Section is valid + if (Section == 0 || Section >= Sections.GetNumEntries()) { + // Illegal segment entry + OutFile.Put("UNKNOWN SEGMENT"); OutFile.NewLine(); + return; + } + + // Write SECTION directive + OutFile.Put("SECTION "); + // Write segment name + WriteSectionName(Section); + // Tabulate + OutFile.Put(" "); OutFile.Tabulate(AsmTab2); + OutFile.Put("align="); + OutFile.PutDecimal(1 << Sections[Section].Align); + if (Sections[Section].WordSize != WordSize) { + OutFile.Put(" use"); + OutFile.PutDecimal(Sections[Section].WordSize); + } + if ((Sections[Section].Type & 0xFF) == 1) { + OutFile.Put(" execute"); + } + else { + OutFile.Put(" noexecute"); + } + + // Tabulate to comment + OutFile.Put(" "); OutFile.Tabulate(AsmTab3); + OutFile.Put(CommentSeparator); + // Write section number + OutFile.Put("section number "); + OutFile.PutDecimal(Section); + // Write type + OutFile.Put(", "); + switch (Sections[Section].Type & 0xFF) { + case 1: OutFile.Put("code"); break; + case 2: OutFile.Put("data"); break; + case 3: OutFile.Put("bss"); break; + case 4: OutFile.Put("const"); break; + default: OutFile.Put("unknown type: "); + OutFile.PutHex(Sections[Section].Type & 0xFF); + break; + } + + // New line + OutFile.NewLine(); + + if (Sections[Section].Type & 0x1000) { + // Communal + OutFile.Put(CommentSeparator); + OutFile.Put(" Communal section not supported by YASM"); + OutFile.NewLine(); + } +} + +void CDisassembler::WriteSegmentBeginGASM() { + // Write begin of segment + uint32 Type; // Section type + + OutFile.NewLine(); // Blank line + + // Check if Section is valid + if (Section == 0 || Section >= Sections.GetNumEntries()) { + // Illegal segment entry + OutFile.Put("UNKNOWN SEGMENT"); OutFile.NewLine(); + return; + } + + // Write SECTION directive + OutFile.Put(".SECTION "); + OutFile.Tabulate(AsmTab1); + // Write segment name + WriteSectionName(Section); + // Tabulate + OutFile.Put(" "); OutFile.Tabulate(AsmTab2); + // Flags not supported by all versions of Gas. Put as comment: + OutFile.Put(CommentSeparator); + // Write flags + OutFile.Put('"'); + Type = Sections[Section].Type & 0xFF; + if (Type) OutFile.Put('a'); // Allocatable + if (Type != 1 && Type != 4) OutFile.Put('w'); // Writeable + if (Type == 1) OutFile.Put('x'); // Executable + OutFile.Put('"'); + if (Type) OutFile.Put(", @progbits"); // Allocatable + + // Tabulate to comment + OutFile.Put(" "); OutFile.Tabulate(AsmTab3); + OutFile.Put(CommentSeparator); + // Write section number + OutFile.Put("section number "); + OutFile.PutDecimal(Section); + // Write type + OutFile.Put(", "); + switch (Sections[Section].Type & 0xFF) { + case 1: OutFile.Put("code"); break; + case 2: OutFile.Put("data"); break; + case 3: OutFile.Put("bss"); break; + case 4: OutFile.Put("const"); break; + default: OutFile.Put("unknown"); break; + } + OutFile.NewLine(); // Blank line + if (Sections[Section].Type & 0x1000) { + // Communal + OutFile.Put(CommentSeparator); + OutFile.Put(" Communal section "); + OutFile.NewLine(); + } + + // Write alignment + OutFile.Tabulate(AsmTab1); + OutFile.Put(".ALIGN"); + OutFile.Tabulate(AsmTab2); + OutFile.PutDecimal(1 << Sections[Section].Align); + + // New line + OutFile.NewLine(); +} + + +void CDisassembler::WriteSegmentEnd() { + // Write end of segment + OutFile.NewLine(); + + if (Syntax != SUBTYPE_MASM) { + // Not MASM syntax, write only blank line + return; + } + + // Check if Section is valid + if (Section == 0 || Section >= Sections.GetNumEntries()) { + // Illegal segment entry + OutFile.Put("UNKNOWN ENDS"); OutFile.NewLine(); + return; + } + + // Write segment name + const char * segname = NameBuffer.Buf() + Sections[Section].Name; + OutFile.Put(segname); + + // Tabulate + OutFile.Put(" "); OutFile.Tabulate(AsmTab1); + // Write "segment" + OutFile.Put("ENDS"); + // New line + OutFile.NewLine(); +} + + + +void CDisassembler::WriteFunctionBegin() { + // Write begin of function IFunction + + // Check if IFunction is valid + if (IFunction == 0 || IFunction >= FunctionList.GetNumEntries()) { + // Should not occur + OutFile.Put(CommentSeparator); + OutFile.Put("Internal error: undefined function begin"); + return; + } + + // Get symbol old index + uint32 symi = FunctionList[IFunction].OldSymbolIndex; + + // Get symbol record + uint32 SymI = Symbols.Old2NewIndex(symi); + + OutFile.NewLine(); // Blank line + + // Remember that symbol has been written + Symbols[SymI].Scope |= 0x100; + + // Check alignment if preceded by NOP + if ((FlagPrevious & 1) && (IBegin & 0x0F) == 0 && Sections[Section].Align >= 4) { + WriteAlign(16); + } + + if (Symbols[SymI].Name == 0) { + // Has no name. Probably only NOP fillers + return; + } + + // Write function name etc. + switch (Syntax) { + case SUBTYPE_MASM: + WriteFunctionBeginMASM(SymI, Symbols[SymI].Scope); break; + case SUBTYPE_YASM: + WriteFunctionBeginYASM(SymI, Symbols[SymI].Scope); break; + case SUBTYPE_GASM: + WriteFunctionBeginGASM(SymI, Symbols[SymI].Scope); break; + } +} + +void CDisassembler::WriteFunctionBeginMASM(uint32 symi, uint32 scope) { + // Write begin of function, MASM syntax + // Write name + WriteSymbolName(symi); + // Space + OutFile.Put(" "); OutFile.Tabulate(AsmTab1); + + if (scope & 0x1C) { + // Scope is public + // Write "PROC" + OutFile.Put("PROC"); + // Write "NEAR" unless 64 bit mode + if (WordSize < 64) OutFile.Put(" NEAR"); + // Check if weak + if (scope & 8) { + OutFile.NewLine(); + OutFile.Put(CommentSeparator); + OutFile.Put(" WEAK "); + WriteSymbolName(symi); + } + // Check if communal + if (scope & 0x10) { + OutFile.NewLine(); + OutFile.Put(CommentSeparator); + OutFile.Put(" COMDEF "); + WriteSymbolName(symi); + } + } + else { + // Scope is local + OutFile.Put("LABEL NEAR"); + } + // Check if Gnu indirect + if (Symbols[symi].Type & 0x40000000) { + OutFile.Put(CommentSeparator); + OutFile.Put("Gnu indirect function"); // Cannot be represented in Masm syntax + } + // End line + OutFile.NewLine(); +} + +void CDisassembler::WriteFunctionBeginYASM(uint32 symi, uint32 scope) { + // Write begin of function, YASM syntax + // Write name + WriteSymbolName(symi); + // Colon + OutFile.Put(":"); OutFile.Tabulate(AsmTab1); + + if (scope & 0x1C) { + // Scope is public + // Write comment + OutFile.Put(CommentSeparator); + OutFile.Put("Function begin"); + // Check if weak + if (scope & 8) { + OutFile.Put(", weak"); + } + // Check if communal + if (scope & 0x10) { + OutFile.Put(", communal"); + } + } + else { + // Scope is local. Write comment + OutFile.Put(CommentSeparator); + OutFile.Put("Local function"); + } + // Check if Gnu indirect + if (Symbols[symi].Type & 0x40000000) { + OutFile.Put(CommentSeparator); + OutFile.Put("Gnu indirect function"); // Cannot be represented in NASM/YASM syntax + } + // End line + OutFile.NewLine(); +} + +void CDisassembler::WriteFunctionBeginGASM(uint32 symi, uint32 scope) { + // Write begin of function, GAS syntax + WriteSymbolName(symi); // Write name + OutFile.Put(":"); + OutFile.Tabulate(AsmTab3); OutFile.Put(CommentSeparator); + if (scope & 3) OutFile.Put("Local "); + if (scope & 8) OutFile.Put("weak "); + if (scope & 0x10) OutFile.Put("communal "); + OutFile.Put("Function"); + OutFile.NewLine(); + OutFile.Tabulate(AsmTab1); + OutFile.Put(".type "); + OutFile.Tabulate(AsmTab2); + WriteSymbolName(symi); // Write name + if (Symbols[symi].Type & 0x40000000) { + OutFile.Put(", @gnu_indirect_function"); + } + else { + OutFile.Put(", @function"); + } + OutFile.NewLine(); +} + + +void CDisassembler::WriteFunctionEnd() { + // Write end of function + + // Check if IFunction is valid + if (IFunction == 0 || IFunction >= FunctionList.GetNumEntries()) { + // Should not occur + OutFile.Put(CommentSeparator); + OutFile.Put("Internal error: undefined function end"); + return; + } + + // Get symbol index + uint32 SymOldI = FunctionList[IFunction].OldSymbolIndex; + uint32 SymNewI = Symbols.Old2NewIndex(SymOldI); + + // check scope + if (Symbols[SymNewI].Scope & 0x1C) { + // Has public scope. Write end of function + switch (Syntax) { + case SUBTYPE_MASM: + WriteFunctionEndMASM(SymNewI); break; + case SUBTYPE_YASM: + WriteFunctionEndYASM(SymNewI); break; + case SUBTYPE_GASM: + WriteFunctionEndGASM(SymNewI); break; + } + } +} + +void CDisassembler::WriteFunctionEndMASM(uint32 symi) { + // Write end of function, MASM syntax + // Write name + WriteSymbolName(symi); + + // Space + OutFile.Put(" "); OutFile.Tabulate(AsmTab1); + // Write "ENDP" + OutFile.Put("ENDP"); + OutFile.NewLine(); +} + +void CDisassembler::WriteFunctionEndYASM(uint32 symi) { + // Write end of function, YASM syntax + // Write comment + OutFile.Put(CommentSeparator); + // Write name + WriteSymbolName(symi); + OutFile.Put(" End of function"); + OutFile.NewLine(); +} + +void CDisassembler::WriteFunctionEndGASM(uint32 symi){ + // Write end of function, GAS syntax + // Write .size directive + OutFile.Tabulate(AsmTab1); + OutFile.Put(".size "); + OutFile.Tabulate(AsmTab2); + WriteSymbolName(symi); // Name of function + OutFile.Put(", . - "); + WriteSymbolName(symi); // Name of function + OutFile.Tabulate(AsmTab3); + OutFile.Put(CommentSeparator); + OutFile.Put("End of function is probably here"); + OutFile.NewLine(); +} + + +void CDisassembler::WriteCodeLabel(uint32 symi) { + // Write private or public code label. symi is new symbol index + + // Get scope + uint32 Scope = Symbols[symi].Scope; + + // Check scope + if (Scope & 0x100) return; // Has been written as function begin + + if (Scope == 0) { + // Inaccessible. No name. Make blank line + OutFile.NewLine(); + // Remember position for warning check + LabelInaccessible = IBegin; + return; + } + + // Begin on new line if preceded by another symbol + if (OutFile.GetColumn()) OutFile.NewLine(); + + // Check alignment if preceded by NOP + if ((Scope & 0xFF) > 1 && (FlagPrevious & 1) && (IBegin & 0x0F) == 0 && Sections[Section].Align >= 4) { + WriteAlign(16); + } + + switch (Syntax) { + case SUBTYPE_MASM: + WriteCodeLabelMASM(symi, Symbols[symi].Scope); break; + case SUBTYPE_YASM: + WriteCodeLabelYASM(symi, Symbols[symi].Scope); break; + case SUBTYPE_GASM: + WriteCodeLabelGASM(symi, Symbols[symi].Scope); break; + } + + // Remember this has been written + Symbols[symi].Scope |= 0x100; +} + + +void CDisassembler::WriteCodeLabelMASM(uint32 symi, uint32 scope) { + // Write private or public code label, MASM syntax + if ((scope & 0xFF) > 1) { + // Scope > function local. Write as label near + // Check if extra linefeed needed + // if (!(IFunction && FunctionList[IFunction].Start == IBegin)) + // New line + OutFile.NewLine(); + + // Write name + WriteSymbolName(symi); + // Space + OutFile.Put(" "); OutFile.Tabulate(AsmTab1); + // Write "LABEL" + OutFile.Put("LABEL"); + // Write "NEAR" even 64 bit mode + OutFile.Put(" NEAR"); + // New line + OutFile.NewLine(); + + // Check if weak + if (scope & 8) { + OutFile.Put(CommentSeparator); + OutFile.Put(" WEAK "); + WriteSymbolName(symi); + OutFile.NewLine(); + } + // Check if communal + if (scope & 0x10) { + OutFile.Put(CommentSeparator); + OutFile.Put(" COMDEF "); + WriteSymbolName(symi); + OutFile.NewLine(); + } + } + else { + // Symbol is local to current function. Write name with colon + if (FlagPrevious & 2) { + // Insert blank line if previous instruction was unconditional jump or return + OutFile.NewLine(); + } + // Write name + WriteSymbolName(symi); + // Write ":" + OutFile.Put(":"); + if (OutFile.GetColumn() > AsmTab1) { + // Past tabstop. Go to next line + OutFile.NewLine(); // New line + } + } +} + +void CDisassembler::WriteCodeLabelYASM(uint32 symi, uint32 scope) { + // Write private or public code label, YASM syntax + if ((scope & 0xFF) > 2) { + // Scope is public + OutFile.NewLine(); + // Write name + WriteSymbolName(symi); + OutFile.Put(":"); + + // Check if weak + if (scope & 8) { + OutFile.Put(CommentSeparator); + OutFile.Put(" weak "); + WriteSymbolName(symi); + } + // Check if communal + if (scope & 0x10) { + OutFile.Put(CommentSeparator); + OutFile.Put(" communal "); + WriteSymbolName(symi); + } + OutFile.NewLine(); + } + else { + // Symbol is local to current function. Write name with colon + if (FlagPrevious & 2) { + // Insert blank line if previous instruction was unconditional jump or return + OutFile.NewLine(); + } + // Write name + WriteSymbolName(symi); + // Write ":" + OutFile.Put(":"); + if (OutFile.GetColumn() > AsmTab1) { + // Past tabstop. Go to next line + OutFile.NewLine(); // New line + } + } +} + +void CDisassembler::WriteCodeLabelGASM(uint32 symi, uint32 scope) { + // Write private or public code label, GAS syntax same as YASM syntax + WriteCodeLabelYASM(symi, scope); +} + +void CDisassembler::WriteAssume() { + // Write assume directive for segment register if MASM syntax + if (Syntax != SUBTYPE_MASM) return; + if (!s.AddressField) return; + + int32 SegReg, PrefixSeg; // Segment register used + uint32 symo; // Target symbol old index + uint32 symi; // Target symbol new index + int32 TargetSegment; // Target segment/section + int32 TargetGroup; // Group containing target segment + + // Find which segment register is used for addressing memory operand + SegReg = 3; // DS is default + if (s.BaseReg == 4+1 || s.BaseReg == 5+1) { + // Base register is (E)BP or ESP + SegReg = 2; // SS register used unless there is a prefix + } + if (s.Prefixes[0]) { + // There is a segment prefix + PrefixSeg = GetSegmentRegisterFromPrefix(); + if (PrefixSeg >= 0 && PrefixSeg <= 5) { + // Segment prefix is valid. Segment determined by segment prefix + SegReg = PrefixSeg; + } + } + // Default target segment is none + TargetSegment = TargetGroup = 0; + + // Find symbol referenced by next instruction + if (s.AddressRelocation && s.AddressRelocation < Relocations.GetNumEntries()) { + symo = Relocations[s.AddressRelocation].TargetOldIndex; // Target symbol old index + if (symo) { + symi = Symbols.Old2NewIndex(symo); // Target symbol new index + if (symi) { + TargetSegment = Symbols[symi].Section; // Target segment + if (TargetSegment < 0 || TargetSegment >= (int32)Sections.GetNumEntries()) { + TargetSegment = 0; + } + else { + TargetGroup = Sections[TargetSegment].Group; // Group containing target segment + if (TargetGroup <= ASM_SEGMENT_ERROR || TargetGroup >= (int32)Sections.GetNumEntries()) { + TargetGroup = 0; + } + } + } + } + } + if (TargetSegment) { + // Target has a segment. Check if it is different from currently assumed segment + if (TargetSegment != Assumes[SegReg] && TargetGroup != Assumes[SegReg]) { + // Assume directive needed + // If segment belongs to a group then the group takes precedence + if (TargetGroup) TargetSegment = TargetGroup; + // Write assume directive + OutFile.Put("ASSUME "); + OutFile.Tabulate(AsmTab1); + OutFile.Put(RegisterNamesSeg[SegReg]); // Name of segment register used + OutFile.Put(":"); + WriteSectionName(TargetSegment); // Name of segment or group referenced + OutFile.NewLine(); + Assumes[SegReg] = TargetSegment; + } + } + else { + // Target segment not specified. Assumed value may be anyting but 'error' + if (Assumes[SegReg] <= ASM_SEGMENT_ERROR) { + // Segment register is assumed to 'error'. Change assume to 'nothing' + OutFile.Put("ASSUME "); + OutFile.Tabulate(AsmTab1); + OutFile.Put(RegisterNamesSeg[SegReg]); // Name of segment register used + OutFile.Put(":NOTHING"); + OutFile.NewLine(); + Assumes[SegReg] = ASM_SEGMENT_NOTHING; + } + } +} + + +void CDisassembler::WriteInstruction() { + // Write instruction and operands + uint32 NumOperands = 0; // Number of operands written + uint32 i; // Loop index + const char * OpName; // Opcode name + + if (s.AddressFieldSize && Syntax == SUBTYPE_MASM) { + // There is a memory operand. Check if ASSUME directive needed + WriteAssume(); + } + + if (CodeMode & 6) { + // Code is dubious. Show as comment only + OutFile.Put(CommentSeparator); // Start comment + } + else if ((s.OpcodeDef->Options & 0x20) && s.OpcodeStart1 > IBegin) { + // Write prefixes explicitly. + // This is used for rare cases where the assembler cannot generate the prefix + OutFile.Tabulate(AsmTab1); // Tabulate + OutFile.Put(Syntax == SUBTYPE_GASM ? ".byte " : "DB "); + OutFile.Tabulate(AsmTab2); // Tabulate + for (i = IBegin; i < s.OpcodeStart1; i++) { + if (i > IBegin) OutFile.Put(", "); + OutFile.PutHex(Get(i), 1); + } + OutFile.Tabulate(AsmTab3); // Tabulate + OutFile.Put(CommentSeparator); + if ((s.OpcodeDef->AllowedPrefixes & 8) && Get(IBegin) == 0xF2) { + OutFile.Put("BND prefix coded explicitly"); // Comment + } + else { + OutFile.Put("Prefix coded explicitly"); // Comment + } + OutFile.NewLine(); + } + + if ((s.Operands[0] & 0xF0) == 0xC0 || (s.Operands[1] & 0xF0) == 0xC0) { + // String instruction or xlat instruction + WriteStringInstruction(); + return; + } + + OutFile.Tabulate(AsmTab1); // Tabulate + + if ((s.OpcodeDef->AllowedPrefixes & 0xC40) == 0xC40) { + switch (s.Prefixes[5]) { + case 0xF2: + OutFile.Put("xacquire "); break; // xacquire prefix + case 0xF3: + OutFile.Put("xrelease "); break; // xrelease prefix + } + } + if (s.Prefixes[2]) { + OutFile.Put("lock "); // Lock prefix + } + + // Get opcode name + if (s.OpcodeDef->Name) { + // Opcode name + OpName = s.OpcodeDef->Name; + // Search for opcode comment + s.OpComment = strchr(OpName, ';'); + if (s.OpComment) s.OpComment++; // Point to after ';' + } + else { + OpName = "UNDEFINED"; // Undefined code with no name + s.OpComment = 0; + } + + // Check prefix option + if ((s.OpcodeDef->Options & 2) && (s.Prefixes[7] & 0x30)) { + // Put prefix 'v' for VEX-prefixed instruction + OutFile.Put('v'); + } + + // Write opcode name + if (s.OpComment) { + // OpName string contains opcode name and comment, separated by ';' + while (*OpName != ';' && *OpName != 0) { // Write opcode name until comment + OutFile.Put(*(OpName++)); + } + } + else { + OutFile.Put(OpName); // Write normal opcode name + } + + // Check suffix option + if (s.OpcodeDef->Options & 1) { + // Append suffix for operand size or type to name + if ((s.OpcodeDef->AllowedPrefixes & 0x7000) == 0x1000) { + // F.P. operand size defined by W prefix bit + i = s.Prefixes[7] & 8; // W prefix bit + OutFile.Put(i ? 'd' : 's'); + } + else if ((s.OpcodeDef->AllowedPrefixes & 0x7000) == 0x3000) { + // Integer or f.p. operand size defined by W prefix bit + bool f = false; + // Find out if operands are integer or f.p. + for (i = 0; i < s.MaxNumOperands; i++) { + if ((s.Operands[i] & 0xF0) == 0x40) { + f = true; break; + } + } + i = s.Prefixes[7] & 8; // W prefix bit + if (f) { + OutFile.Put(i ? 'd' : 's'); // float precision suffix + } + else { + OutFile.Put(i ? 'q' : 'd'); // integer size suffix + } + } + else if ((s.OpcodeDef->AllowedPrefixes & 0x7000) == 0x4000) { + // Integer operand size defined by W prefix bit + i = s.Prefixes[7] & 8; // W prefix bit + OutFile.Put(i ? 'w' : 'b'); + } + else if ((s.OpcodeDef->AllowedPrefixes & 0x7000) == 0x5000) { + // mask register operand size defined by W prefix bit and 66 prefix + i = (s.Prefixes[7] & 8) >> 2; // W prefix bit + i |= s.Prefixes[5] != 0x66; // 66 prefix bit + OutFile.Put("bwdq"[i]); + } + else if (s.OpcodeDef->AllowedPrefixes & 0xE00) { + // F.P. operand type and size defined by prefixes + switch (s.Prefixes[5]) { + case 0: // No prefix = ps + OutFile.Put("ps"); break; + case 0x66: // 66 prefix = pd + OutFile.Put("pd"); break; + case 0xF3: // F3 prefix = ss + OutFile.Put("ss"); break; + case 0xF2: // F2 prefix = sd + OutFile.Put("sd"); break; + default: + err.submit(9000); // Should not occur + } + } + else if (s.OpcodeDef->AllowedPrefixes & 0x100){ + // Integer operand size defined by prefixes + // Suffix for operand size + i = s.OperandSize / 8; + if (i <= 8) { + static const char SizeSuffixes[] = " bw d f q"; // Table of suffixes + OutFile.Put(SizeSuffixes[i]); + } + } + } + // Alternative suffix option + if (s.OpcodeDef->Options & 0x1000) { + // Append alternative suffix for vector element size to name + if ((s.OpcodeDef->AllowedPrefixes & 0x7000) == 0x3000) { + // Integer operand size defined by W prefix bit + i = ((s.Prefixes[7] & 8) + 8) * 4; // W prefix bit -> 8 / 16 + OutFile.PutDecimal(i); + } + if ((s.OpcodeDef->AllowedPrefixes & 0x7000) == 0x4000) { // 32 / 64 + i = (s.Prefixes[7] & 8) + 8; // W prefix bit -> 8 / 16 + OutFile.PutDecimal(i); + } + } + // More suffix option + if ((s.OpcodeDef->Options & 0x400) && s.ImmediateFieldSize == 8) { + // 64 bit immediate mov + if (Syntax == SUBTYPE_GASM) OutFile.Put("abs"); + } + + // Space between opcode name and operands + OutFile.Put(" "); OutFile.Tabulate(AsmTab2); // Tabulate. At least one space + + // Loop for all operands to write + for (i = 0; i < s.MaxNumOperands; i++) { + if (s.Operands[i] & 0xFFFF) { + + // Write operand i + if (NumOperands++) { + // At least one operand before this one. Separate by ", " + OutFile.Put(", "); + } + + // Write constant and jump operands + switch (s.Operands[i] & 0xF0) { + case 0x10: case 0x20: case 0x30: case 0x80: + WriteImmediateOperand(s.Operands[i]); + continue; + } + + // Write register and memory operands + uint32 optype = (s.Operands[i] >> 16) & 0x0F; + switch (optype) { + case 0: // Other type of operand + WriteOtherOperand(s.Operands[i]); break; + + case 0x1: // Direct memory operand + WriteRMOperand(s.Operands[i]); break; + + case 0x2: // Register operand indicated by last bits of opcode + WriteShortRegOperand(s.Operands[i]); break; + + case 0x3: // Register or memory operand indicated by mod/rm bits + WriteRMOperand(s.Operands[i]); break; + + case 0x4: // Register operand indicated by reg bits + WriteRegOperand(s.Operands[i]); break; + + case 0x5: // Register operand indicated by dest bits of DREX byte + WriteDREXOperand(s.Operands[i]); break; + + case 0x6: // Register operand indicated by VEX.vvvv bits + WriteVEXOperand(s.Operands[i], 0); break; + + case 0x7: // Register operand indicated by bits 4-7 of immediate operand + WriteVEXOperand(s.Operands[i], 1); break; + + case 0x8: // Register operand indicated by bits 0-3 of immediate operand + WriteVEXOperand(s.Operands[i], 2); break; // Unused. For future use + } + int isMem = optype == 3 && s.Mod != 3; + if (s.Prefixes[3] == 0x62) { // EVEX and MVEX prefix can have extra operand attributes + if (s.Prefixes[6] & 0x20) { + WriteOperandAttributeEVEX(i, isMem); + } + else { + WriteOperandAttributeMVEX(i, isMem); + } + } + if (s.Prefixes[3] == 0x62 && (i == s.MaxNumOperands - 1 || (s.Operands[i+1] & 0xFFF) < 0x40)) { + // This is the last SIMD operand + if (!(s.Operands[4] & 0x80000000)) { + s.Operands[4] |= 0x80000000; // Make sure we don't write this twice + if (s.Prefixes[6] & 0x20) { + WriteOperandAttributeEVEX(98, isMem); + } + else { + WriteOperandAttributeMVEX(98, isMem); + } + } + } + } + } + if (s.Prefixes[3] == 0x62) { // EVEX and MVEX prefix can have extra attributes after operands + if (s.Prefixes[6] & 0x20) { + WriteOperandAttributeEVEX(99, 0); + } + else { + WriteOperandAttributeMVEX(99, 0); + } + } + if (s.OpComment) { + // Write opcode comment + OutFile.Put(' '); + OutFile.Put(CommentSeparator); + OutFile.Put(s.OpComment); + } +} + + +void CDisassembler::WriteStringInstruction() { + // Write string instruction or xlat instruction + uint32 NumOperands = 0; // Number of operands written + uint32 i; // Loop index + uint32 Segment; // Possible segment prefix + + if (!(s.OpcodeDef->AllowedPrefixes & 0x1100)) { + // Operand size is 8 if operand size prefixes not allowed + s.OperandSize = 8; + } + + OutFile.Tabulate(AsmTab1); // Tabulate + + if (Syntax != SUBTYPE_MASM && s.Prefixes[0] && (s.OpcodeDef->AllowedPrefixes & 4)) { + // Get segment prefix + Segment = GetSegmentRegisterFromPrefix(); // Interpret segment prefix + // Write segment override + OutFile.Put(RegisterNamesSeg[Segment]); + OutFile.Put(" "); + } + + // Check repeat prefix + if (s.OpcodeDef->AllowedPrefixes & 0x20) { + if (s.Prefixes[3]) { + // Repeat prefix + OutFile.Put("rep "); + } + } + else if (s.OpcodeDef->AllowedPrefixes & 0x40) { + if (s.Prefixes[3] == 0xF2) { + // repne prefix + OutFile.Put("repne "); + } + else if (s.Prefixes[3] == 0xF3) { + // repe prefix + OutFile.Put("repe "); + } + } + + // Write opcode name + OutFile.Put(s.OpcodeDef->Name); // Opcode name + + if (Syntax == SUBTYPE_MASM + && (((s.OpcodeDef->AllowedPrefixes & 4) && s.Prefixes[0]) + || ((s.OpcodeDef->AllowedPrefixes & 1) && s.Prefixes[1]))) { + // Has segment or address size prefix. Must write operands explicitly + OutFile.Put(" "); // Space before operands + + // Check address size for pointer registers + const char * * PointerRegisterNames; + switch (s.AddressSize) { + case 16: + PointerRegisterNames = RegisterNames16; break; + case 32: + PointerRegisterNames = RegisterNames32; break; + case 64: + PointerRegisterNames = RegisterNames64; break; + default: + PointerRegisterNames = 0; // should not occur + } + + // Loop for possibly two operands + for (i = 0; i < 2; i++) { + if (s.Operands[i]) { + // Operand i defined + if (NumOperands++) { + // An operand before this one. Separate by ", " + OutFile.Put(", "); + } + if (NumOperands == 1) { + // Write operand size for first operand + switch (s.OperandSize) { + case 8: + OutFile.Put("byte "); break; + case 16: + OutFile.Put("word "); break; + case 32: + OutFile.Put("dword "); break; + case 64: + OutFile.Put("qword "); break; + } + } + // Get segment + Segment = 1; // Default segment is DS + if (s.Prefixes[0]) { + Segment = GetSegmentRegisterFromPrefix(); // Interpret segment prefix + } + if ((s.Operands[i] & 0xCF) == 0xC2) { + Segment = 0; // Segment is ES regardless of prefix for [edi] operand + } + // Write segment override + OutFile.Put(RegisterNamesSeg[Segment]); + OutFile.Put(":"); + // Opening "[" + OutFile.Put("["); + + // Write pointer register + switch (s.Operands[i] & 0xCF) { + case 0xC0: // [bx], [ebx] or [rbx] + OutFile.Put(PointerRegisterNames[3]); + break; + case 0xC1: // [si], [esi] or [rsi] + OutFile.Put(PointerRegisterNames[6]); + break; + case 0xC2: // [di], [edi] or [rdi] + OutFile.Put(PointerRegisterNames[7]); + break; + } + // Closing "]" + OutFile.Put("]"); + } + } + } + else { + // We don't have to write the operands + // Append suffix for operand size, except for xlat + if ((s.Operands[1] & 0xCF) != 0xC0) { + + // Suffix for operand size + uint32 i = s.OperandSize / 8; + if (i <= 8) { + static const char SizeSuffixes[] = " bw d q"; // Table of suffixes + OutFile.Put(SizeSuffixes[i]); + } + } + } +} + + +void CDisassembler::WriteCodeComment() { + // Write hex listing of instruction as comment after instruction + uint32 i; // Index to current byte + uint32 FieldSize; // Number of bytes in field + const char * Spacer; // Space between fields + + OutFile.Tabulate(AsmTab3); // Tabulate to comment field + OutFile.Put(CommentSeparator); // Start comment + + // Write address + if (SectionEnd + SectionAddress + (uint32)ImageBase > 0xFFFF) { + // Write 32 bit address + OutFile.PutHex(IBegin + SectionAddress + (uint32)ImageBase); + } + else { + // Write 16 bit address + OutFile.PutHex((uint16)(IBegin + SectionAddress)); + } + + // Space after address + OutFile.Put(" _"); + + // Start of instruction + i = IBegin; + + // Write bytes + while (i < IEnd) { + FieldSize = 1; // Size of field to write + Spacer = " "; // Space between fields + + // Spacer and FieldSize depends on fields + if (i == s.OpcodeStart1 && i > IBegin) { + Spacer = ": "; // Space between prefixes and opcode + } + if (i == s.OpcodeStart2 + 1) { + Spacer = ". "; // Space between opcode and mod/reg/rm bytes + } + if (i == s.AddressField && s.AddressFieldSize) { + Spacer = ", "; // Space before address field + FieldSize = s.AddressFieldSize; + } + if (i == s.ImmediateField && s.ImmediateFieldSize) { + Spacer = ", "; // Space before immediate operand field + FieldSize = s.ImmediateFieldSize; + } + // Write space + OutFile.Put(Spacer); + + // Write byte or bytes + switch (FieldSize) { + case 1: // Write single byte + OutFile.PutHex(Get(i)); + break; + case 2: // Write two bytes + OutFile.PutHex(Get(i)); + break; + case 3: // Write three bytes (operands for "enter" instruction) + OutFile.PutHex(Get(i)); + OutFile.Put(", "); + OutFile.PutHex(Get(i+2)); + break; + case 4: // Write four bytes + if ((s.Operands[0] & 0xFE) == 0x84) { + // Far jump/call address + OutFile.PutHex(Get(i)); + OutFile.Put(" "); + OutFile.PutHex(Get(i+2)); + } + else { + // Any other 32 bit operand + OutFile.PutHex(Get(i)); + } + break; + case 6: // Write six bytes (far jump address) + OutFile.PutHex(Get(i)); + OutFile.Put(" "); + OutFile.PutHex(Get(i+4)); + break; + case 8: // Write eight bytes + OutFile.PutHex(Get(i)); + break; + } + // Search for relocation + SARelocation rel1; // Make relocation records for searching + rel1.Section = Section; + rel1.Offset = i; // rel1 marks current field in instruction + + // Is there a relocation source exactly here? + int32 irel = Relocations.Exists(rel1); // Finds relocation with source = i + + if (irel > 0) { + // This field has a relocation. Indicate relocation type + // 0 = unknown, 1 = direct, 2 = self-relative, 3 = image-relative, + // 4 = segment relative, 5 = relative to arbitrary ref. point, 8 = segment address/descriptor + uint32 RelType = Relocations[irel].Type; + if (RelType) { + OutFile.Put(Lookup(RelocationTypeNames, RelType)); + } + if (Relocations[irel].Size > FieldSize) { + // Relocation has wrong size + OutFile.Put(" Misplaced relocation."); + } + } + + // Point to next byte + i += FieldSize; + } + // New line + OutFile.NewLine(); +} + + +void CDisassembler::CountInstructions() { + // Count total number of instructions defined in opcodes.cpp + // Two instructions are regarded as the same and counted as one if they + // have the same name and differ only in the bits that define register + // name, operand size, etc. + + uint32 map; // Map number + uint32 index; // Index into map + uint32 n; // Number of instructions with same code + uint32 iset; // Instruction set + uint32 instructions = 0; // Total number of instructions + uint32 mmxinstr = 0; // Number of MMX instructions + uint32 sseinstr = 0; // Number of SSE instructions + uint32 sse2instr = 0; // Number of SSE2 instructions + uint32 sse3instr = 0; // Number of SSE3 instructions + uint32 ssse3instr = 0; // Number of SSSE3 instructions + uint32 sse41instr = 0; // Number of SSE4.1 instructions + uint32 sse42instr = 0; // Number of SSE4.2 instructions + uint32 AVXinstr = 0; // Number of AVX instructions + uint32 FMAinstr = 0; // Number of FMA3 and later instructions + uint32 AVX2instr = 0; // Number of AVX2 instructions + uint32 BMIinstr = 0; // Number of BMI instructions and other small instruction sets + uint32 AVX512instr = 0; // Number of AVX-512 instructions + uint32 MICinstr = 0; // Number of MIC instructions + uint32 AMDinstr = 0; // Number of AMD instructions + uint32 VIAinstr = 0; // Number of AMD instructions + uint32 privilinstr = 0; // Number of privileged instructions + uint32 undocinstr = 0; // Number of undocumented instructions + uint32 droppedinstr = 0; // Number of opcodes planned but never implemented + uint32 VEXdouble = 0; // Number of instructions that have both VEX and non-VEX version + SOpcodeDef const * opcode; // Pointer to map entry + + // Loop through all maps + for (map = 0; map < NumOpcodeTables1; map++) { + // Loop through each map + for (index = 0; index < OpcodeTableLength[map]; index++) { + opcode = OpcodeTables[map] + index; + if (opcode->InstructionFormat && opcode->Name + && !opcode->TableLink && !(opcode->InstructionFormat & 0x8000)) { + // instruction is defined + if ((opcode->InstructionFormat & 0xFFF) == 3 + && index > 0 && (opcode-1)->Name + && strcmp(opcode->Name, (opcode-1)->Name) == 0) { + // Same as previous instruction, just with another register + continue; // Don't count this + } + n = 1; // Default = one instruction per map entry + // Check if we have multiple instructions with different prefixes + if (opcode->Options & 1) { + if (opcode->AllowedPrefixes & 0x3000) { + n++; // Extra instruction with W prefix bit + } + else if (opcode->AllowedPrefixes & 0xE00) { + if (opcode->AllowedPrefixes & 0x200) n++; // Extra instruction with 66 prefix + if (opcode->AllowedPrefixes & 0x400) n++; // Extra instruction with F3 prefix + if (opcode->AllowedPrefixes & 0x800) n++; // Extra instruction with F2 prefix + } + else if (opcode->AllowedPrefixes & 0x100) { + n++; // Extra instruction with 66 prefix + if (opcode->AllowedPrefixes & 0x1000) n++;// Extra instruction with L prefix bit + } + } + if (opcode->Options & 2) VEXdouble += n; // Instructions that have both VEX and non-VEX version + instructions += n; // Count total instructions + + iset = opcode->InstructionSet; // Instruction set + if (iset & 0x20000) { + droppedinstr += n; iset = 0; // Opcodes planned but never implemented + } + if (iset & 0x800) privilinstr += n; // Privileged instruction + if (opcode->InstructionFormat & 0x4000) undocinstr += n; // Undocumented instruction + + switch (iset & 0x37FF) { + case 7: // MMX + mmxinstr += n; break; + case 0x11: // SSE + sseinstr += n; break; + case 0x12: // SSE2 + sse2instr += n; break; + case 0x13: // SSE3 + sse3instr += n; break; + case 0x14: // SSSE3 + ssse3instr += n; break; + case 0x15: // SSE4.1 + sse41instr += n; break; + case 0x16: // SSE4.2 + sse42instr += n; break; + case 0x17: case 0x18: case 0x19: // VEX etc. + AVXinstr += n; break; + case 0x1A: case 0x1B: // FMA and later instructions + FMAinstr += n; break; + case 0x1C: // AVX2 instructions + AVX2instr += n; break; + case 0x1D: case 0x1E: // BMI and other small instruction sets + BMIinstr += n; break; + case 0x20: // AVX-512 instructions + AVX512instr += n; break; + case 0x80: // MIC instructions + MICinstr += n; break; + case 0x1001: case 0x1002: case 0x1004: case 0x1005: case 0x1006: // AMD + AMDinstr += n; break; + case 0x2001: // VIA + VIAinstr += n; break; + } + } + } + } + + // output result + printf("\n\nNumber of instruction opcodes supported by disassembler:\n%5i Total, including:", + instructions); + printf("\n%5i Privileged instructions", privilinstr); + printf("\n%5i MMX instructions", mmxinstr); + printf("\n%5i SSE instructions", sseinstr); + printf("\n%5i SSE2 instructions", sse2instr); + printf("\n%5i SSE3 instructions", sse3instr); + printf("\n%5i SSSE3 instructions", ssse3instr); + printf("\n%5i SSE4.1 instructions", sse41instr); + printf("\n%5i SSE4.2 instructions", sse42instr); + printf("\n%5i AVX instructions etc.", AVXinstr); + printf("\n%5i AVX2 instructions", AVX2instr); + printf("\n%5i FMA3 instructions", FMAinstr); + printf("\n%5i BMI/micsellaneous instr.", BMIinstr); + printf("\n%5i AVX-512 instructions", AVX512instr); + printf("\n%5i MIC/Xeon Phi instructions", MICinstr); + printf("\n%5i AMD instructions", AMDinstr); + printf("\n%5i VIA instructions", VIAinstr); + printf("\n%5i instructions planned but never implemented in any CPU", droppedinstr); + printf("\n%5i undocumented or illegal instructions", undocinstr); + printf("\n%5i instructions have both VEX and non-VEX versions", VEXdouble); + printf("\n"); + +#if 0 // temporary test code + + // find entries with 0x2000 prefix code + printf("\n\nInstructions with operand swap flag:\n"); + // Loop through all maps + for (map = 0; map < NumOpcodeTables1; map++) { + // Loop through each map + for (index = 0; index < OpcodeTableLength[map]; index++) { + opcode = OpcodeTables[map] + index; + if ((opcode->AllowedPrefixes & 0x2000) == 0x2000) { + printf("\n%04X %02X %s", map, index, opcode->Name); + } + } + } + + /* + printf("\n\nTables linked by type 0x0E:\n"); + // Loop through all maps + for (map = 0; map < NumOpcodeTables1; map++) { + // Loop through each map + for (index = 0; index < OpcodeTableLength[map]; index++) { + opcode = OpcodeTables[map] + index; + if (opcode->TableLink == 0x0E) { + printf(" 0x%02X", opcode->InstructionSet); + } + } + }*/ + + printf("\n"); + +#endif +} diff --git a/programs/develop/objconv/elf.cpp b/programs/develop/objconv/elf.cpp new file mode 100644 index 0000000000..d32cfccf98 --- /dev/null +++ b/programs/develop/objconv/elf.cpp @@ -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 +CELF::CELF() { + memset(this, 0, sizeof(*this)); +} + +// ParseFile +template +void CELF::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(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 +void CELF::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(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(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 +void CELF::PublicNames(CMemoryBuffer * Strings, CSList * 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 +const char * CELF::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(symi).st_name; + if (stri < SymbolStringTableSize) { + symname = Buf() + SymbolStringTableOffset + stri; + } + } + } + return symname; +} + + +// Make template instances for 32 and 64 bits +template class CELF; +template class CELF; diff --git a/programs/develop/objconv/elf.h b/programs/develop/objconv/elf.h new file mode 100644 index 0000000000..220a9cd1ad --- /dev/null +++ b/programs/develop/objconv/elf.h @@ -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 diff --git a/programs/develop/objconv/elf2asm.cpp b/programs/develop/objconv/elf2asm.cpp new file mode 100644 index 0000000000..eb76179f59 --- /dev/null +++ b/programs/develop/objconv/elf2asm.cpp @@ -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 +CELF2ASM::CELF2ASM() { +} + + +// FindImageBase() +template +void CELF2ASM::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 +void CELF2ASM::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 +void CELF2ASM::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 +void CELF2ASM::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 +void CELF2ASM::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 +void CELF2ASM::MakeImportList() { + // Make imported symbols for executable files +} + +// MakeExportList +template +void CELF2ASM::MakeExportList() { + // Make exported symbols for executable files +} + +// MakeListLabels +template +void CELF2ASM::MakeListLabels() { + // Attach names to all image directories +} + + +// Make template instances for 32 and 64 bits +template class CELF2ASM; +template class CELF2ASM; diff --git a/programs/develop/objconv/elf2cof.cpp b/programs/develop/objconv/elf2cof.cpp new file mode 100644 index 0000000000..4f961ae93f --- /dev/null +++ b/programs/develop/objconv/elf2cof.cpp @@ -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 +CELF2COF::CELF2COF() { + // Reset all + memset(this, 0, sizeof(*this)); +} + + +// Convert(): Do the conversion +template +void CELF2COF::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 +void CELF2COF::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 +void CELF2COF::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 +void CELF2COF::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 +void CELF2COF::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 +void CELF2COF::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 +void CELF2COF::MakeBinaryFile() { + + // Insert string table size + //NewStringTable.Get(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; +template class CELF2COF; diff --git a/programs/develop/objconv/elf2elf.cpp b/programs/develop/objconv/elf2elf.cpp new file mode 100644 index 0000000000..55c6f2a0f7 --- /dev/null +++ b/programs/develop/objconv/elf2elf.cpp @@ -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 +CELF2ELF::CELF2ELF() { + // Initialize everything + memset(this, 0, sizeof(*this)); +} + + +// Convert() +template +void CELF2ELF::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 +void CELF2ELF::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(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 +void CELF2ELF::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 +void CELF2ELF::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(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; +template class CELF2ELF; diff --git a/programs/develop/objconv/elf2mac.cpp b/programs/develop/objconv/elf2mac.cpp new file mode 100644 index 0000000000..e089c13d63 --- /dev/null +++ b/programs/develop/objconv/elf2mac.cpp @@ -0,0 +1,1098 @@ +/**************************** elf2mac.cpp ********************************* +* Author: Agner Fog +* Date created: 2007-01-10 +* Last modified: 2012-05-05 +* Project: objconv +* Module: elf2mac.cpp +* Description: +* Module for converting ELF file to Mach-O file +* +* Copyright 2007-2012 GNU General Public License http://www.gnu.org/licenses +*****************************************************************************/ + +#include "stdafx.h" + +template + CELF2MAC::CELF2MAC() { + // Constructor + memset(this, 0, sizeof(*this)); // Reset everything +} + +template + void CELF2MAC::Convert() { + // Do the conversion + // Some compilers require this-> for accessing members of template base class, + // according to the so-called two-phase lookup rule. + + // Call the subfunctions + ToFile.SetFileType(FILETYPE_MACHO_LE); // Set type of new file + MakeFileHeader(); // Make file header + MakeSectionsIndex(); // Make sections index translation table + FindUnusedSymbols(); // Check if symbols used, remove unused symbols + MakeSymbolTable(); // Make symbol table and string tables + MakeSections(); // Make sections and relocation tables + MakeBinaryFile(); // Put sections together + *this << ToFile; // Take over new file buffer +} + + +template +void CELF2MAC::MakeFileHeader() { + // Convert subfunction: Make file header and load segment command + TMAC_header NewHeader; // new file header + NewHeader.magic = (this->WordSize == 32) ? MAC_MAGIC_32 : MAC_MAGIC_64; // Mach magic number identifier + NewHeader.cputype = (this->WordSize == 32) ? MAC_CPU_TYPE_I386 : MAC_CPU_TYPE_X86_64; + NewHeader.cpusubtype = MAC_CPU_SUBTYPE_I386_ALL; + NewHeader.filetype = MAC_OBJECT; + NewHeader.ncmds = 3; // Three commands = segment, symbol table, dynsymtab + NewHeader.sizeofcmds = 0; // Set this later + NewHeader.flags = 0; // No flags needed + + // put file header in OutFile + ToFile.Push(&NewHeader, sizeof(NewHeader)); +} + + +template +void CELF2MAC::MakeSectionsIndex() { + // Make sections index translation table and section offset table. + + // We must make these tables before the sections, because they are needed for the + // symbol tables and relocation tables, and we must make the symbol tables before + // the relocation tables, and we must make the relocation tables together with the + // sections. + uint32 oldsec; // Section number in old file + uint32 newsec = 0; // Section number in new file + NewSectIndex. SetNum(this->NSections); // Allocate size for section index table + NewSectIndex. SetZero(); // Initialize + NewSectOffset.SetNum(this->NSections); // Allocate buffer for section offset table + NewSectOffset.SetZero(); // Initialize + + MInt NewVirtualAddress = 0; // Virtual address of new section as specified in Mach-O file + + // First loop through old sections + for (oldsec = 0; oldsec < this->NSections; oldsec++) { + NewSectIndex[oldsec] = 0; + NewSectOffset[oldsec] = 0; + + // 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(); + continue; + } + } + + 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(); + continue; + } + } + + // Search for program data sections only + if (this->SectionHeaders[oldsec].sh_type != SHT_PROGBITS + && this->SectionHeaders[oldsec].sh_type != SHT_NOBITS) { + // Has no data. Ignore + continue; + } + + if (this->SectionHeaders[oldsec].sh_size == 0) { + // Remove empty section + // The linker has a bug with empty sections + continue; + } + + // Section index translation table + NewSectIndex[oldsec] = newsec++; + + // Calculate virtual memory address of section. This address does not have + // much to do with the final address, but it is needed in relocation entries. + + // Alignment + int NewAlign = FloorLog2((uint32)this->SectionHeaders[oldsec].sh_addralign); + if (NewAlign > 12) NewAlign = 12; // What is the limit for highest alignment? + int AlignBy = 1 << NewAlign; + + // Align memory address + NewVirtualAddress = (NewVirtualAddress + AlignBy - 1) & -(MInt)AlignBy; + + // Virtual memory address of new section + NewSectOffset[oldsec] = NewVirtualAddress; + + // Increment memory address + NewVirtualAddress += this->SectionHeaders[oldsec].sh_size; + + // Fix v. 2.14: Align end of memory address by 4 + NewVirtualAddress = (NewVirtualAddress + 3) & MInt(-4); + } + + // Store number of sections in new file + NumSectionsNew = newsec; + + // Calculate file offset of first raw data + RawDataOffset = sizeof(TMAC_header) + + sizeof(TMAC_segment_command) + + NumSectionsNew * sizeof(TMAC_section) + + sizeof(MAC_symtab_command) + + sizeof(MAC_dysymtab_command); + + // Align end of memory address by 4 + NewVirtualAddress = (NewVirtualAddress + 3) & MInt(-4); + + // Make segment command + TMAC_segment_command NewSegment; + memset(&NewSegment, 0, sizeof(NewSegment)); + NewSegment.cmd = (this->WordSize == 32) ? MAC_LC_SEGMENT : MAC_LC_SEGMENT_64; + NewSegment.cmdsize = sizeof(TMAC_segment_command) + NumSectionsNew * sizeof(TMAC_section); + NewSegment.fileoff = RawDataOffset; + NewSegment.nsects = NumSectionsNew; + NewSegment.maxprot = NewSegment.initprot = 7; // 1=read, 2=write, 4=execute + NewSegment.vmsize = NewVirtualAddress; + NewSegment.filesize = 0; // Changed later + + // put segment command in OutFile + CommandOffset = ToFile.Push(&NewSegment, sizeof(NewSegment)); +} + + +template +void CELF2MAC::MakeSymbolTable() { + // Convert subfunction: Symbol table and string tables + 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 + int8 * symtabend; // End of old symbol table + uint32 entrysize; // Size of each entry in old symbol table + TELF_Symbol OldSym; // Old symbol table record + uint32 OldSymI; // Symbol index in old symbol table + const char * symname; // Symbol name + int NewSection = 0; // New section index + int NewType; // New symbol type + int NewDesc; // New symbol reference type + MInt Value; // Symbol value + uint32 Scope; // 0: Local, 1: Public, 2: External + + // 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++; + + // Copy symbol table header for convenience + OldHeader = this->SectionHeaders[oldsec]; + + // Find associated string table + if (OldHeader.sh_link >= (uint32)(this->NSections)) { + err.submit(2035); OldHeader.sh_link = 0; + } + strtab = this->Buf() + (uint32)this->SectionHeaders[OldHeader.sh_link].sh_offset; + + // 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; + + if (NewSymTab[0].GetNumEntries() == 0) { + // make empty symbol record for index 0 + NewSymTab[0].AddSymbol(0, "", 0, 0, 0, 0); + } + + // Loop through old symbol table + for (OldSymI = 0; symtab < symtabend; symtab += entrysize, OldSymI++) { + + if (OldSymI == 0) continue; // First symbol entry in ELF file is unused + + // Copy 32 bit symbol table entry or convert 64 bit entry + OldSym = *(TELF_Symbol*)symtab; + + // Old symbol type + int type = OldSym.st_type; + + // Old symbol storage class = binding + int binding = OldSym.st_bind; + + // Get symbol name + if (OldSym.st_name < this->SymbolStringTableSize) { + symname = strtab + OldSym.st_name; + } + else { + err.submit(2112); // String table corrupt + continue; // Ignore + } + if (symname == 0 || *symname == 0) { + // Symbol has no name. Give it a name + // Mac linker messes this up if the symbol doesn't have a unique name. + char tempbuf[80]; + sprintf(tempbuf, "?unnamed%i", OldSymI); + int os = UnnamedSymbolsTable.PushString(tempbuf); + symname = UnnamedSymbolsTable.Buf() + os; + } + + NewType = NewDesc = 0; // New symbol type + + // Value = address + Value = OldSym.st_value; + + // Section + if (OldSym.st_shndx == SHN_UNDEF) { + NewSection = 0; // External + } + else if ((int16)(OldSym.st_shndx) == SHN_ABS) { + NewType |= MAC_N_ABS; // Absolute symbol + NewDesc |= MAC_N_NO_DEAD_STRIP; + NewSection = 0; + } + else if ((int16)(OldSym.st_shndx) == SHN_COMMON) { + NewType |= MAC_N_ABS; // Common symbol. Translate to abs and make warning + NewDesc |= MAC_N_NO_DEAD_STRIP; + NewSection = 0; + err.submit(1053, symname); // Warning. Common 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 + NewSection = NewSectIndex[OldSym.st_shndx] + 1; + // Value must be absolute address. Add section address + Value += NewSectOffset[OldSym.st_shndx]; + } + + // Convert binding/storage class + switch (binding) { + case STB_LOCAL: // Local + Scope = S_LOCAL; + if (!(NewType & MAC_N_ABS)) NewType |= MAC_N_SECT; + break; + + case STB_GLOBAL: + if (NewSection || (NewType & MAC_N_ABS)) { + // Public + Scope = S_PUBLIC; + NewType |= MAC_N_EXT; + if (!(NewType & MAC_N_ABS)) NewType |= MAC_N_SECT; + } + else { + // External + Scope = S_EXTERNAL; + NewType |= MAC_N_EXT; + } + NewDesc |= MAC_REF_FLAG_UNDEFINED_NON_LAZY; + break; + + case STB_WEAK: + if (NewSection) { + // Weak public + Scope = S_PUBLIC; + NewType |= MAC_N_EXT | MAC_N_SECT; + NewDesc |= MAC_N_WEAK_DEF; + if (this->WordSize == 32) { + err.submit(1051, symname); // Weak public only allowed in coalesced section of MachO-32 + } + } + else { + // Weak external + Scope = S_EXTERNAL; + NewType |= MAC_N_EXT; + NewDesc |= MAC_N_WEAK_REF; + } + break; + + default: + Scope = S_LOCAL; + err.submit(2037, binding); // Other. Not supported + } + + // Make record depending on type + switch (type) { + case STT_OBJECT: case STT_NOTYPE: + // Data object + break; + + case STT_GNU_IFUNC: + err.submit(1063); // Warning: Gnu indirect function cannot be converted + // continue in next case: + + case STT_FUNC: + // Function + break; + + case STT_FILE: + // File name record. Ignore + continue; + + case STT_SECTION: + // Section name record. (Has no name) + break; + + case STT_COMMON: + default: + err.submit(2038, type); // Symbol type not supported + continue; + } + + // Discard unused symbols + if (Scope != S_PUBLIC && !OldSymbolUsed[OldSymI]) continue; + + // Store new symbol record in the appropriate table + if (Scope > 2) err.submit(9000); + + NewSymTab[Scope].AddSymbol(OldSymI, symname, NewType, NewDesc, NewSection, Value); + + // Store scope in OldSymbolScope + if (OldSymI < NumOldSymbols) { + OldSymbolScope[OldSymI] = Scope; + } + } // 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 +} + + +template +void CELF2MAC::Elf2MacRelocations(Elf32_Shdr & OldRelHeader, MAC_section_32 & NewHeader, uint32 NewRawDataOffset, uint32 oldsec) { + // Convert 32-bit relocations from ELF to MAC + // (This function has two template instances, only the 32-bit instance is used) + + Elf32_Rela OldRelocation; // Old relocation table entry + MAC_scattered_relocation_info scat; // Scattered relocation entry + memset(&scat, 0, sizeof(scat)); + + // Get pointer to old relocation table + int8 * reltab = this->Buf() + OldRelHeader.sh_offset; + int8 * reltabend = reltab + OldRelHeader.sh_size; + + // Get entry size + uint32 entrysize = (uint32)OldRelHeader.sh_entsize; + uint32 expectedentrysize = (OldRelHeader.sh_type == SHT_REL) ? sizeof(Elf32_Rel) : sizeof(Elf32_Rela); + if (entrysize < expectedentrysize) {err.submit(2033); entrysize = expectedentrysize;} + + // File pointer to relocations + NewHeader.reloff = NewRelocationTab.GetNumEntries()*sizeof(MAC_relocation_info); // Offset to first relocation table added later + + // Loop through relocation table entries + for (; reltab < reltabend; reltab += entrysize) { + + // Copy relocation entry with or without addend + OldRelocation.r_addend = 0; + memcpy(&OldRelocation, reltab, entrysize); + + // Find inline addend + uint32 InlinePosition = (uint32)(NewRawDataOffset + 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); + + // Add old addend if any + *piaddend += (int32)OldRelocation.r_addend; + + // Define relocation parameters + uint32 r_address = 0; // section-relative offset to relocation source + uint32 r_symbolnum = 0; // symbol index if r_extern == 1 or section ordinal if r_extern == 0 + // uint32 r_value = 0; // value of relocation target + // int r_scattered = 0; // use scattered relocation + int r_pcrel = 0; // self relative + int r_length = 2; // size of source: 0=byte, 1=2 bytes, 2=4 bytes, 3=8 bytes + int r_extern = 0; // public or external + int r_type = 0; // if not 0, machine specific relocation type + int Scope = 0; // Symbol scope: 0 = local, 1 = public, 2 = external + + // source offset + r_address = (uint32)OldRelocation.r_offset; + + // target scope + if (OldRelocation.r_sym < NumOldSymbols) { + Scope = OldSymbolScope[OldRelocation.r_sym]; + } + + // Get r_extern: 0 = local target referenced by address, + // 1 = external symbol referenced by symbol table index + switch (Scope) { + case S_LOCAL: // Local target must be referenced by address + r_extern = 0; break; + + case S_PUBLIC: // Public target is optionally referenced by index or by address + r_extern = 0; + // r_extern = 1; is not allowed! + break; + + case S_EXTERNAL: // External target is always referenced by index + r_extern = 1; break; + } + + // Get zero-based index into NewSymTab[Scope] + int newindex = NewSymTab[Scope].TranslateIndex(OldRelocation.r_sym); + if (newindex < 0) { + // Symbol not found or wrong type + err.submit(2031); + break; + } + if (r_extern) { + // r_symbolnum is zero based index into combined symbol tables. + // Add number of entries in preceding NewSymTab tables to index + // into NewSymTab[Scope] + r_symbolnum = newindex + NumSymbols[Scope]; + } + else { + // r_extern = 0. r_symbolnum = target section + r_symbolnum = NewSymTab[Scope][newindex].n_sect; + + // Absolute address of target stored inline in source + *piaddend += (uint32)NewSymTab[Scope][newindex].n_value; + } + + // Get relocation type and fix addend + switch(OldRelocation.r_type) { + case R_386_NONE: // Ignored + continue; + + 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 + r_type = MAC32_RELOC_VANILLA; + break; + + case R_386_PC32: // 32-bit self-relative + r_type = MAC32_RELOC_VANILLA; + r_pcrel = 1; + // Mach-O 32 bit format requires that self-relative addresses must have + // self-relative values already before relocation. Therefore + // the source address is subtracted. + // (The PC reference point is the end of the source = start + // of source + 4, but ELF files have the same offset so no further + // correction is needed when converting from ELF file). + + // !! ToDo: Self-relative relocations plus offset to local symbol in a different section + // sometimes causes problems in Mac linker, perhaps because it fails to determine + // correctly which section the target is in. Use a relocation with a reference point + // instead. This probably occurs only in assembler-coded self-relative 32-bit code. + // (Use asmlib A_strtoupper and A_strcspn as test cases - they fail if dummy data + // at the end of .data section is removed) + *piaddend -= r_address + (uint32)NewHeader.addr; + break; + + case R_UNSUPPORTED_IMAGEREL: // 32-bit image-relative + // This occurs only when converting from COFF (via ELF) + // Needs scattered relocation entry + scat.r_address = r_address; + scat.r_length = 2; + scat.r_pcrel = 0; + scat.r_scattered = 1; + scat.r_type = MAC32_RELOC_SECTDIFF; + scat.r_value = r_symbolnum; + // Store first entry of scattered pair + NewRelocationTab.Push(&scat, sizeof(scat)); + NewHeader.nreloc++; + // Make subtractor record for image base + scat.r_type = MAC32_RELOC_PAIR; + scat.r_value = GetImagebaseSymbol(); + // Store second entry of scattered pair + NewRelocationTab.Push(&scat, sizeof(scat)); + NewHeader.nreloc++; + continue; + + 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 + r_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 + r_type = 0; + break; + + default: // Unknown or unsupported relocation method + err.submit(2030, OldRelocation.r_type); + r_type = 0; break; + } + + if (!r_pcrel) { + // Warn for position dependent code. + // This warning is currently turned off in error.cpp. + err.submit(1050, this->SymbolName(OldRelocation.r_sym)); + // Write this error only once + err.ClearError(1050); + } + + // Make relocation entry + MAC_relocation_info rel; + memset(&rel, 0, sizeof(rel)); + + // Make non-scattered relocation entry + rel.r_address = r_address; + rel.r_symbolnum = r_symbolnum; + rel.r_pcrel = r_pcrel; + rel.r_length = r_length; + rel.r_extern = r_extern; + rel.r_type = r_type; + + // Store relocation entry + NewRelocationTab.Push(&rel, sizeof(rel)); + NewHeader.nreloc++; + + // Remember that symbol is used + // if (SymbolsUsed && OldRelocation.r_type && NewRelocation.r_symbolnum < ?) { + // SymbolsUsed[NewRelocation.r_symbolnum]++;} + + } // End of relocations loop +} + +template +void CELF2MAC::Elf2MacRelocations(Elf64_Shdr & OldRelHeader, MAC_section_64 & NewHeader, uint32 NewRawDataOffset, uint32 oldsec) { + // Convert 64-bit relocations from ELF to MAC + // (This function has two template instances, only the 64-bit instance is used) + + // Make relocation entry for dummy subtractor + MAC_relocation_info relsub; + memset(&relsub, 0, sizeof(relsub)); + + Elf64_Rela OldRelocation; // Old relocation table entry + + // Get pointer to old relocation table + int8 * reltab = this->Buf() + OldRelHeader.sh_offset; + int8 * reltabend = reltab + OldRelHeader.sh_size; + + // Get entry size + uint32 entrysize = (uint32)OldRelHeader.sh_entsize; + uint32 expectedentrysize = (OldRelHeader.sh_type == SHT_REL) ? sizeof(Elf64_Rel) : sizeof(Elf64_Rela); + if (entrysize < expectedentrysize) {err.submit(2033); entrysize = expectedentrysize;} + + // File pointer to relocations + NewHeader.reloff = NewRelocationTab.GetNumEntries()*sizeof(MAC_relocation_info); // Offset to first relocation table added later + + // Loop through relocation table entries + for (; reltab < reltabend; reltab += entrysize) { + + // Copy relocation entry with or without addend + OldRelocation.r_addend = 0; + memcpy(&OldRelocation, reltab, entrysize); + + // Find inline addend + uint32 InlinePosition = (uint32)(NewRawDataOffset + 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); + + // Add old addend if any + *piaddend += (uint32)OldRelocation.r_addend; + + // Define relocation parameters + uint32 r_address = 0; // section-relative offset to relocation source + uint32 r_symbolnum = 0; // symbol index if r_extern == 1 or section ordinal if r_extern == 0 + // uint32 r_value = 0; // value of relocation target + // int r_scattered = 0; // scattered relocations not used in 64 bit + int r_pcrel = 0; // self relative + int r_length = 2; // size of source: 0=byte, 1=2 bytes, 2=4 bytes, 3=8 bytes + int r_extern = 0; // public or external + int r_type = 0; // if not 0, machine specific relocation type + int Scope = 0; // Symbol scope: 0 = local, 1 = public, 2 = external + + // source offset + r_address = (uint32)OldRelocation.r_offset; + + // target scope + if (OldRelocation.r_sym < NumOldSymbols) { + Scope = OldSymbolScope[OldRelocation.r_sym]; + } + + // Get r_extern: 0 = local target referenced by address, + // 1 = public or external symbol referenced by symbol table index + switch (Scope) { + case S_LOCAL: // Local target + // r_extern = 0; // Local target must be referenced by address + // Note: the description in reloc.h says that local targets are addressed + // relative to any preceding public target. If there is no preceding label + // then referenced by address in the segment. However, the Gnu compiler + // uses reference to a local symbol and sets r_extern = 1 to indicate that + // it refers to a symbol record, not to an address. I have chosen to use the + // latter method because it is simpler, though undocumented. + r_extern = 1; + break; + + case S_PUBLIC: // Public target is optionally referenced by index or by address + r_extern = 1; + break; + + case S_EXTERNAL: // External target is always referenced by index + r_extern = 1; + break; + } + + // Get zero-based index into NewSymTab[Scope] + int newindex = NewSymTab[Scope].TranslateIndex(OldRelocation.r_sym); + if (newindex < 0) { + // Symbol not found or wrong type + err.submit(2031); + break; + } + + // r_symbolnum is zero based index into combined symbol tables. + // Add number of entries in preceding NewSymTab tables to index + // into NewSymTab[Scope] + r_symbolnum = newindex + NumSymbols[Scope]; + + // Get relocation type and fix addend, 64 bit + switch(OldRelocation.r_type) { + case R_X86_64_NONE: // Ignored + continue; + + case R_X86_64_64: + // 64-bit absolute virtual address + r_type = MAC64_RELOC_UNSIGNED; r_length = 3; + break; + + case R_X86_64_IRELATIVE: + err.submit(1063); // Warning: Gnu indirect function cannot be converted + // continue in next case?: + case R_X86_64_32: case R_X86_64_32S: { + // 32-bit absolute virtual address + // Note: The linker doesn't accept a 32-bit absolute address + // Make address relative to the image base, and add the value of the image base to compensate + if (cmd.ImageBase == 0) { + // Default image base if not specified + cmd.ImageBase = 0x400000; + } + + // Make subtractor relocation entry for image base + relsub.r_address = r_address; + relsub.r_symbolnum = GetImagebaseSymbol(); + relsub.r_length = 2; + relsub.r_extern = 1; + relsub.r_type = MAC64_RELOC_SUBTRACTOR; + + NewRelocationTab.Push(&relsub, sizeof(relsub)); + NewHeader.nreloc++; + // Add image base to compensate for subtracted image base + *piaddend += cmd.ImageBase; + + // Now we can add the address we really want: + r_type = MAC64_RELOC_UNSIGNED; + r_length = 2; + + // Warn that image base must be set to the specified value + char ImageBaseHex[32]; + sprintf(ImageBaseHex, "%X", cmd.ImageBase); // write value as hexadecimal + err.submit(1300, ImageBaseHex); err.ClearError(1300); + break;} + + case R_X86_64_PC32: // 32-bit self-relative + r_type = MAC64_RELOC_BRANCH; + // MAC64_RELOC_SIGNED does the same, but the linker complains if external symbol + r_length = 2; + r_pcrel = 1; + // Difference between EIP-relative and self-relative relocation = size of address field + // Adjust inline addend for different relocation method: + *piaddend += 4; + break; + + case R_UNSUPPORTED_IMAGEREL: // 32-bit image-relative + // This occurs only when converting from COFF (via ELF) + // Make subtractor relocation entry for image base + relsub.r_address = r_address; + relsub.r_symbolnum = GetImagebaseSymbol(); + relsub.r_length = 2; + relsub.r_extern = 1; + relsub.r_type = MAC64_RELOC_SUBTRACTOR; + + NewRelocationTab.Push(&relsub, sizeof(relsub)); + NewHeader.nreloc++; + + // Second record adds the target address + r_type = MAC64_RELOC_UNSIGNED; + r_length = 2; + break; + + case R_X86_64_GLOB_DAT: case R_X86_64_GOTPCREL: + // Create 64-bit GOT entry?? + r_type = MAC64_RELOC_GOT; r_length = 2; + break; + + case R_X86_64_GOT32: + // 32-bit GOT entry + err.submit(2042); // cannot convert 32-bit GOT + err.ClearError(2042); // report this error only once + r_type = 0; + break; + + case R_X86_64_PLT32: case R_X86_64_JUMP_SLOT: + // procedure linkage table + err.submit(2043); // cannot convert import table + err.ClearError(2043); // report this error only once + r_type = 0; + break; + + case R_X86_64_COPY: case R_X86_64_RELATIVE: + default: // Unknown or unsupported relocation method + err.submit(2030, OldRelocation.r_type); + r_type = 0; break; + } + + // Make relocation entry + MAC_relocation_info rel; + memset(&rel, 0, sizeof(rel)); + + // Make non-scattered relocation entry + rel.r_address = r_address; + rel.r_symbolnum = r_symbolnum; + rel.r_pcrel = r_pcrel; + rel.r_length = r_length; + rel.r_extern = r_extern; + rel.r_type = r_type; + + // Store relocation entry + NewRelocationTab.Push(&rel, sizeof(rel)); + NewHeader.nreloc++; + + // Remember that symbol is used + // if (SymbolsUsed && OldRelocation.r_type && NewRelocation.r_symbolnum < ?) { + // SymbolsUsed[NewRelocation.r_symbolnum]++;} + + } // End of relocations loop +} + +template +void CELF2MAC::MakeSections() { + // Convert subfunction: Make sections and relocation tables + uint32 oldsec; // Section number in old file + uint32 relsec; // Relocation section in old file + TMAC_section NewHeader; // New section header + TELF_SectionHeader OldHeader; // Old section header + TELF_SectionHeader OldRelHeader;// Old relocation section header + uint32 NewVirtualAddress = 0; // Virtual address of new section + uint32 NewRawDataOffset = 0; // Offset into NewRawData of section. + // NewRawDataOffset is different from NewVirtualAddress if alignment of sections in + // the object file is different from alignment of sections in memory + + // Count cumulative number of symbols in each scope + NumSymbols[0] = 0; + NumSymbols[1] = NumSymbols[0] + NewSymTab[0].GetNumEntries(); + NumSymbols[2] = NumSymbols[1] + NewSymTab[1].GetNumEntries(); + NumSymbols[3] = NumSymbols[2] + NewSymTab[2].GetNumEntries(); + if (NumSymbols[3] >= 0x1000000) err.submit(2051); // Too many symbols, max = 2^24 + + NewSectHeadOffset = ToFile.GetDataSize(); + + // Second loop through old sections + for (oldsec = 0; oldsec < this->NSections; oldsec++) { + + // Copy old header for convenience + OldHeader = this->SectionHeaders[oldsec]; + + if (OldHeader.sh_size == 0) { + // Remove empty section + // The linker has a bug with empty sections + continue; + } + + // 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; + + // Translate section name and truncate to 16 characters + if (!stricmp(sname,".text") || !stricmp(sname,"_text")) { + strcpy(NewHeader.sectname, "__text"); + strcpy(NewHeader.segname, "__TEXT"); + } + else if (!stricmp(sname,".data") || !stricmp(sname,"_data")) { + strcpy(NewHeader.sectname, "__data"); + strcpy(NewHeader.segname, "__DATA"); + } + else if (!strnicmp(sname+1,"bss", 3)) { + strcpy(NewHeader.sectname, "__bss"); + strcpy(NewHeader.segname, "__DATA"); + } + else if (!strnicmp(sname+1,"const", 5) || !strnicmp(sname+1,"rodata", 6)) { + strcpy(NewHeader.sectname, "__const"); + strcpy(NewHeader.segname, "__DATA"); + } + else if (!strnicmp(sname, ELF_CONSTRUCTOR_NAME, 5)) { + // Constructors + strcpy(NewHeader.sectname, MAC_CONSTRUCTOR_NAME); + strcpy(NewHeader.segname, "__DATA"); + NewHeader.flags = MAC_S_MOD_INIT_FUNC_POINTERS; + } + else if (OldHeader.sh_flags & SHF_EXECINSTR) { + // Other code section + if (strlen(NewHeader.sectname) > 16) err.submit(1040, NewHeader.sectname); // Warning: name truncated + strncpy(NewHeader.sectname, sname, 16); + strcpy(NewHeader.segname, "__TEXT"); + } + else { + // Other data section. Truncate name to 16 characters + if (strlen(NewHeader.sectname) > 16) err.submit(1040, NewHeader.sectname); // Warning: name truncated + strncpy(NewHeader.sectname, sname, 16); + strcpy(NewHeader.segname, "__DATA"); + } + if (NewHeader.sectname[0] == '.') { + // Make sure name begins with '_' + NewHeader.sectname[0] = '_'; + } + + // Raw data + NewHeader.size = OldHeader.sh_size; // section size in file + + // File to raw data for section + NewHeader.offset = NewRawData.GetDataSize() + RawDataOffset; + + if (OldHeader.sh_size && OldHeader.sh_type != SHT_NOBITS) { // Not for .bss segment + // Copy raw data + NewRawDataOffset = NewRawData.Push(this->Buf()+(uint32)OldHeader.sh_offset, (uint32)OldHeader.sh_size); + NewRawData.Align(4); + } + + // Section flags + if (OldHeader.sh_flags & SHF_EXECINSTR) { + NewHeader.flags |= MAC_S_ATTR_PURE_INSTRUCTIONS | MAC_S_ATTR_SOME_INSTRUCTIONS; + } + else if (OldHeader.sh_type == SHT_NOBITS) { + NewHeader.flags |= MAC_S_ZEROFILL; // .bss segment + } + + // Alignment + NewHeader.align = FloorLog2((uint32)OldHeader.sh_addralign); + if (NewHeader.align > 12) NewHeader.align = 12; // What is the limit for highest alignment? + int AlignBy = 1 << NewHeader.align; + + // Align memory address + NewVirtualAddress = (NewVirtualAddress + AlignBy - 1) & -AlignBy; + + // Virtual memory address of new section + NewHeader.addr = NewVirtualAddress; + NewVirtualAddress += (uint32)OldHeader.sh_size; + + // 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 + Elf2MacRelocations(OldRelHeader, NewHeader, NewRawDataOffset, oldsec); + } + } // End of search for relocation table + + // Align raw data for next section + NewRawData.Align(4); + + // Fix v. 2.14: adjust NewVirtualAddress to match above alignment + NewVirtualAddress = (NewVirtualAddress + 3) & MInt(-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 + + +template +void CELF2MAC::FindUnusedSymbols() { + // Check if symbols used, remove unused symbols + + // Allocate table OldSymbolScope and OldSymbolUsed + NumOldSymbols = this->SymbolTableEntries; + if (NumOldSymbols > 0 && NumOldSymbols < 0x1000000) { + OldSymbolScope.SetNum(NumOldSymbols); + OldSymbolScope.SetZero(); + OldSymbolUsed.SetNum(NumOldSymbols); + OldSymbolUsed.SetZero(); + } + + // Loop through section headers + for (uint32 sc = 0; sc < this->NSections; sc++) { + uint32 entrysize = uint32(this->SectionHeaders[sc].sh_entsize); + // printf("\n%2i Name: %-18s ", sc, SecStringTable + sheader.sh_name); + + if ((this->SectionHeaders[sc].sh_type==SHT_REL || this->SectionHeaders[sc].sh_type==SHT_RELA)) { + // Relocation list + int8 * reltab = this->Buf() + uint32(this->SectionHeaders[sc].sh_offset); + int8 * reltabend = reltab + uint32(this->SectionHeaders[sc].sh_size); + uint32 expectedentrysize = this->SectionHeaders[sc].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) { + int isymbol = ((TELF_Relocation*)reltab)->r_sym; + // printf("\n>SymbolUsed: %i, Name: %s",isymbol,SymbolName(isymbol)); + // Remember symbol used + OldSymbolUsed[isymbol]++; + } + } + } +} + +template +void CELF2MAC::MakeBinaryFile() { + // Convert subfunction: Putting sections together + // File header, segment command and section headers have been inserted. + int i; + + // Update segment header for segment size in file + ((TMAC_segment_command*)(ToFile.Buf()+CommandOffset))->filesize = NewRawData.GetDataSize(); + + // Make symbol table command + MAC_symtab_command symtab; + memset(&symtab, 0, sizeof(symtab)); + symtab.cmd = MAC_LC_SYMTAB; + symtab.cmdsize = sizeof(symtab); + // symoff, nsyms, stroff, strsize inserted later + // Store symtab command + NewSymtabOffset = ToFile.Push(&symtab, sizeof(symtab)); + + // Make MAC_dysymtab_command command + MAC_dysymtab_command dysymtab; + memset(&dysymtab, 0, sizeof(dysymtab)); + dysymtab.cmd = MAC_LC_DYSYMTAB; + dysymtab.cmdsize = sizeof(dysymtab); + dysymtab.ilocalsym = 0; // index to local symbols + dysymtab.nlocalsym = NewSymTab[0].GetNumEntries(); // number of local symbols + dysymtab.iextdefsym = dysymtab.nlocalsym; // index to externally defined symbols + dysymtab.nextdefsym = NewSymTab[1].GetNumEntries(); // number of externally defined symbols + dysymtab.iundefsym = dysymtab.iextdefsym + dysymtab.nextdefsym; // index to public symbols + dysymtab.nundefsym = NewSymTab[2].GetNumEntries(); // number of public symbols + // Store MAC_dysymtab_command command + ToFile.Push(&dysymtab, sizeof(dysymtab)); + + // Store section data + uint32 Current = ToFile.Push(NewRawData.Buf(), NewRawData.GetDataSize()); + if (Current != RawDataOffset) err.submit(9000); + + ToFile.Align(4); + + // Store relocation tables + uint32 Reltabs = ToFile.Push(NewRelocationTab.Buf(), NewRelocationTab.GetDataSize()); + + // Initialize new string table. First string is empty + NewStringTable.Push(0, 1); + + // Store symbol tables and make string table + // Tables are not sorted alphabetically yet. This will be done subsequently + // by CMAC2MAC + uint32 Symtabs = ToFile.GetDataSize(); + uint32 NumSyms = 0; + for (i = 0; i < 3; i++) { + NumSyms += NewSymTab[i].GetNumEntries(); + NewSymTab[i].StoreList(&ToFile, &NewStringTable); + } + + // Store string table + uint32 StringTab = ToFile.Push(NewStringTable.Buf(), NewStringTable.GetDataSize()); + + // Set missing values in file header + ((TMAC_header*)ToFile.Buf())->sizeofcmds = RawDataOffset - sizeof(TMAC_header); + + // Adjust relocation offsets in section headers + TMAC_section* sectp = (TMAC_section*)(ToFile.Buf() + NewSectHeadOffset); + for (i = 0; i < NumSectionsNew; i++, sectp++) { + sectp->reloff += Reltabs; + } + + // Set missing symoff, nsyms, stroff, strsize in symtab command + MAC_symtab_command * symtabp = (MAC_symtab_command*)(ToFile.Buf() + NewSymtabOffset); + symtabp->symoff = Symtabs; + symtabp->nsyms = NumSyms; + symtabp->stroff = StringTab; + symtabp->strsize = NewStringTable.GetDataSize(); +} + +template +int CELF2MAC::GetImagebaseSymbol() { + // Get symbol table index of __mh_execute_header = image base + // Create this symbol table entry if it doesn't exist + + const char * ImageBaseName = "__mh_execute_header"; + static int ImagebaseSymbol = -1; + + if (ImagebaseSymbol >= 0) { + // Found previously + return ImagebaseSymbol; + } + // Search for name among external symbols + int index2 = NewSymTab[2].Search(ImageBaseName); + if (index2 >= 0) { + // found + ImagebaseSymbol = index2 + NumSymbols[2]; + return ImagebaseSymbol; + } + // Not found. Create symbol + NewSymTab[2].AddSymbol(NumOldSymbols, ImageBaseName, MAC_N_EXT, 0, 0, 0); + ImagebaseSymbol = NewSymTab[2].TranslateIndex(NumOldSymbols) + NumSymbols[2]; + NumSymbols[3]++; + return ImagebaseSymbol; +} + + +// Make template instances for 32 and 64 bits +template class CELF2MAC; +template class CELF2MAC; diff --git a/programs/develop/objconv/error.cpp b/programs/develop/objconv/error.cpp new file mode 100644 index 0000000000..494c5d9b3a --- /dev/null +++ b/programs/develop/objconv/error.cpp @@ -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; + } +} diff --git a/programs/develop/objconv/error.h b/programs/develop/objconv/error.h new file mode 100644 index 0000000000..e7efa56e42 --- /dev/null +++ b/programs/develop/objconv/error.h @@ -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 diff --git a/programs/develop/objconv/library.cpp b/programs/develop/objconv/library.cpp new file mode 100644 index 0000000000..55a1b494f9 --- /dev/null +++ b/programs/develop/objconv/library.cpp @@ -0,0 +1,2103 @@ +/**************************** library.cpp ********************************** +* Author: Agner Fog +* Date created: 2006-08-27 +* Last modified: 2017-07-27 +* Project: objconv +* Module: library.cpp +* Description: +* This module contains code for reading, writing and manipulating function +* libraries (archives) of the UNIX type and OMF type. +* +* Copyright 2006-2017 GNU General Public License http://www.gnu.org/licenses +*****************************************************************************/ + +#include "stdafx.h" + +// OMF Library flag names +SIntTxt OMFLibraryFlags[] = { + {0, "Flag = 0"}, + {1, "Case sensitive"} +}; + + +CLibrary::CLibrary() { + // Constructor + CurrentOffset = 0; + CurrentNumber = 0; + LongNames = 0; + LongNamesSize = 0; + AlignBy = 0; + MemberFileType = 0; + RepressWarnings = 0; + PageSize = 16; +} + + +void CLibrary::Go() { + // Do to library whatever the command line says + char const * MemberName1 = 0; // Name of library member + char const * MemberName2 = 0; // Modified name of library member + int action = 0; // Action to take on member + int FileType1 = 0; // File type of current member + int WordSize1 = 0; // Word size of current member + + if (cmd.DumpOptions && !(cmd.LibraryOptions & CMDL_LIBRARY_EXTRACTMEM)) { + // Dump library, but not its members + Dump(); + return; + } + + // Remove path form member names and check member type before extracting or adding members + AlignBy = 2; + if (GetDataSize()) FixNames(); + + if (err.Number()) return; // Stop if error + + // check LibraryOptions and whether an output file is specified + if (cmd.FileOptions & CMDL_FILE_OUTPUT) { + // Output is a library file + if ((cmd.OutputFile == 0 || cmd.OutputFile[0] == 0) && !(cmd.LibraryOptions & CMDL_LIBRARY_ADDMEMBER)) { + err.submit(2503); // Output file name missing + return; + } + // Check extension + if (strstr(cmd.OutputFile, ".lib") && strstr(cmd.OutputFile, ".LIB") && strstr(cmd.OutputFile, ".a")) { + err.submit(1101); // Warning wrong extension + } + if (cmd.OutputType >= IMPORT_LIBRARY_MEMBER) { + // Wrong output type + if (cmd.OutputType == FILETYPE_ASM) { + // Attempt to disassemble whole library + err.submit(2620); + } + else { + err.submit(2621); + } + return; + } + } + + // Desired alignment = 2 for COFF and ELF, 8 for Mach-O + AlignBy = 2; + if (cmd.OutputType == FILETYPE_MACHO_LE) AlignBy = 8; + + // Determine library type and subtype + if (cmd.LibrarySubtype == 0) { + switch (cmd.OutputType) { + case FILETYPE_OMF: case FILETYPE_OMFLIBRARY: + cmd.LibrarySubtype = LIBTYPE_OMF; break; + case FILETYPE_COFF: case FILETYPE_DOS: + cmd.LibrarySubtype = LIBTYPE_WINDOWS; break; + case FILETYPE_ELF: + cmd.LibrarySubtype = LIBTYPE_LINUX; break; + case FILETYPE_MACHO_LE: case FILETYPE_MACHO_BE: + cmd.LibrarySubtype = LIBTYPE_BSD_MAC; break; + case FILETYPE_LIBRARY: + switch (cmd.InputType) { + case FILETYPE_COFF: case FILETYPE_DOS: + cmd.LibrarySubtype = LIBTYPE_WINDOWS; break; + case FILETYPE_ELF: + cmd.LibrarySubtype = LIBTYPE_LINUX; break; + case FILETYPE_MACHO_LE: case FILETYPE_MACHO_BE: + cmd.LibrarySubtype = LIBTYPE_BSD_MAC; break; + } + break; + default: + cmd.LibrarySubtype = LIBTYPE_SHORTNAMES; + } + } + + // Reserve space for data buffer + DataBuffer.SetSize(GetBufferSize()); + + // Check options + if (!cmd.LibraryOptions) cmd.LibraryOptions = CMDL_LIBRARY_CONVERT; + + if (cmd.Verbose) { + // Tell what we are doing + if ((cmd.LibraryOptions & CMDL_LIBRARY_ADDMEMBER) && GetDataSize() == 0) { + // Creating library + printf("\nCreating library %s (%s)", FileName, GetFileFormatName(cmd.OutputType)); + } + else if (OutputFileName) { + // Print input file name + printf("\nInput library: %s", FileName); + if (cmd.InputType != cmd.OutputType) { + // Converting library type. Print input file type + int InType = cmd.InputType; + if (InType == FILETYPE_LIBRARY || InType == FILETYPE_OMFLIBRARY) InType = cmd.MemberType; + printf(", Format: %s", GetFileFormatName(InType)); + if (cmd.DesiredWordSize) printf("%i", cmd.DesiredWordSize); + } + // Print output file name and type + printf(", Output: %s, Format: %s", OutputFileName, GetFileFormatName(cmd.OutputType)); + if (cmd.DesiredWordSize) printf("%i", cmd.DesiredWordSize); + } + else { + printf("\nExtracting from library file: %s", FileName); + } + } + + // Convert library or extract or add or dump all members + StartExtracting(); // Initialize before ExtractMember() + + // Loop through input library + while ((MemberName1 = ExtractMember(&MemberBuffer)) != 0) { + + // Check if any specific action required for this member + action = cmd.SymbolChange(MemberName1, &MemberName2, SYMT_LIBRARYMEMBER); + /* + if ((action != SYMA_CHANGE_NAME && action != SYMA_EXTRACT_MEMBER) || MemberName2 == 0) { + MemberName2 = MemberName1; // No name change + } */ + MemberBuffer.FileName = MemberName1; + MemberBuffer.OutputFileName = MemberName2 ? MemberName2 : MemberName1; + + if (action == SYMA_DELETE_MEMBER) { + // Remove this member from library + if (cmd.Verbose) { + printf("\nRemoving member %s from library", MemberName1); + } + continue; + } + if (action == SYMA_ADD_MEMBER) { + // Replace this member with new file + // (Message comes later when adding new member) + continue; + } + + // Check type of this member + FileType1 = MemberBuffer.GetFileType(); + if (FileType1 == 0) continue; + WordSize1 = MemberBuffer.WordSize; + + if (!(cmd.LibraryOptions & (CMDL_LIBRARY_EXTRACTMEM | CMDL_LIBRARY_ADDMEMBER))) { + // Not adding or extracting members. Apply conversion options to all members + if (cmd.SymbolChangesRequested() || FileType1 != cmd.OutputType) { + + // Check file type before conversion + int FileType0 = MemberBuffer.GetFileType(); + // Conversion or name change requested + MemberBuffer.Go(); // Do required conversion + if (err.Number()) break; // Stop if error + // Check type again after conversion + FileType1 = MemberBuffer.GetFileType(); + if (MemberBuffer.OutputFileName == 0 || FileType1 != FileType0) { + MemberBuffer.OutputFileName = MemberBuffer.SetFileNameExtension(MemberBuffer.FileName); + } + MemberBuffer.FileName = MemberBuffer.OutputFileName; + } + } + if (MemberFileType == 0) MemberFileType = FileType1; + if (WordSize == 0) WordSize = WordSize1; + if (FileType1 != MemberFileType || WordSize1 != WordSize) { + if (WordSize1 == 0) { + // Library member has no wordsize + err.submit(1109, MemberBuffer.FileName); + } + else { + // Library members have different type or word size + err.submit(1102); + } + } + + if (cmd.LibraryOptions & CMDL_LIBRARY_EXTRACTMEM) { + // Extract member(s) + if (action == SYMA_EXTRACT_MEMBER || cmd.LibraryOptions == CMDL_LIBRARY_EXTRACTALL) { + // Extract this member + if (cmd.DumpOptions == 0 && cmd.OutputType != CMDL_OUTPUT_DUMP) { + // Write this member to file + if (err.Number()) return; // Check first if error + + if (cmd.SymbolChangesRequested() || FileType1 != cmd.OutputType) { + // Conversion or name change requested + + // Check type before conversion + int FileType0 = MemberBuffer.GetFileType(); + MemberBuffer.Go(); + if (err.Number()) return; // Stop if error + // Check type after conversion + FileType1 = MemberBuffer.GetFileType(); + if (MemberBuffer.OutputFileName == 0 /*|| FileType1 != FileType0*/) { + MemberBuffer.OutputFileName = MemberBuffer.SetFileNameExtension(MemberBuffer.FileName); + } + } + if (MemberBuffer.OutputFileName == 0) { + MemberBuffer.OutputFileName = MemberBuffer.FileName; + } + if (cmd.Verbose) { + // Tell what we are doing + if (MemberName1 == MemberName2) { + printf("\nExtracting file %s from library", MemberName1); + } + else { + printf("\nExtracting library member %s to file %s", MemberName1, MemberBuffer.OutputFileName); + } + } + if (WordSize1 == 0) { + err.submit(1109, MemberName1); + } + // Write this member to file + MemberBuffer.Write(); + } + else { + // Dump this member + MemberBuffer.Go(); + } + } + } + else if (cmd.DumpOptions == 0) { + // Add member to new library + if (MemberName2 == 0) MemberName2 = MemberName1; + if (cmd.Verbose) { + // Tell what we are doing + if (strcmp(MemberName1, MemberName2) != 0) { + printf("\nRenaming member %s to %s", MemberName1, MemberName2); + } + } + // Put into new library + InsertMember(&MemberBuffer); + } + } // End of loop through library + // Stop if error + if (err.Number()) return; + + if (cmd.LibraryOptions & CMDL_LIBRARY_ADDMEMBER) { + // Add object files to library + SSymbolChange const * sym; + // Loop through file names to add + while ((sym = cmd.GetMemberToAdd()) != 0) { + MemberBuffer.Reset(); // Reset MemberBuffer + // Name of object file + MemberBuffer.FileName = sym->Name2; // Name of object file + MemberBuffer.OutputFileName = sym->Name1; // Name of new member + // Read object file + MemberBuffer.Read(); + // Stop if read failed + if (err.Number()) continue; + // Detect file type + int NewMemberType = MemberBuffer.GetFileType(); + if (cmd.Verbose) { + // Tell what we are doing + if (sym->Done) { + printf("\nReplacing member %s with file %s", sym->Name1, sym->Name2); + } + else { + printf("\nAdding member %s from file %s", sym->Name1, sym->Name2); + } + if (NewMemberType != cmd.OutputType) { + // Converting type + printf(". Converting from %s.", GetFileFormatName(NewMemberType)); + } + } + // Do any conversion required + MemberBuffer.Go(); + + // Stop if error + if (err.Number()) continue; + + // Check if file type is right after conversion + MemberFileType = MemberBuffer.FileType; + if (WordSize == 0) WordSize = MemberBuffer.WordSize; + if (MemberFileType != cmd.OutputType) { + // Library members have different type + err.submit(2504, GetFileFormatName(MemberBuffer.FileType)); continue; + } + if (MemberBuffer.WordSize != WordSize) { + // Library members have different word size + err.submit(2505, MemberBuffer.WordSize); continue; + } + // Put into library + MemberBuffer.FileName = MemberBuffer.OutputFileName; + InsertMember(&MemberBuffer); + } // End of loop through object file names + } + // Stop if error + if (err.Number()) return; + + if (cmd.LibraryOptions & CMDL_LIBRARY_EXTRACTMEM) { + cmd.CheckExtractSuccess(); // Check if members to extract were found + } + + if (cmd.FileOptions & CMDL_FILE_OUTPUT) { + // Make output library + MakeBinaryFile(); + // Take over OutFile buffer + *this << OutFile; + } + else { + // No output library + OutputFileName = 0; + } +} + +void CLibrary::FixNames() { + // Rebuild library or fix member names + // Dispatch according to library type + switch (cmd.InputType) { + case FILETYPE_OMF: case FILETYPE_OMFLIBRARY: + // Rebuild OMF style library and fix long member names + RebuildOMF(); break; + + case FILETYPE_LIBRARY: + default: + // Fix names in UNIX style library + StripMemberNamesUNIX(); break; + } +} + +/* Unused: +void CLibrary::Rebuild() { + // Rebuild library: fix member names + // Dispatch according to library type + switch (cmd.InputType) { + case FILETYPE_OMF: case FILETYPE_OMFLIBRARY: + // Rebuild OMF style library + RebuildOMF(); break; + + case FILETYPE_LIBRARY: + default: + // Rebuild UNIX style library + RebuildUNIX(); break; + } +} + +void CLibrary::RebuildUNIX() { + // Rebuild UNIX style library + // Make member names unique and without path. Rebuild symbol table + char const * MemberName1 = 0; // Name of library member + uint32 OutputFileType; + + // Save OutputType before changing it + OutputFileType = cmd.OutputType; + + // Loop through input library + CurrentOffset = 8; CurrentNumber = 0; + while ((MemberName1 = ExtractMember(&MemberBuffer)) != 0) { + // Properties of member + MemberBuffer.FileName = MemberBuffer.OutputFileName = MemberName1; + // Check if import library + if (MemberBuffer.Get(0) == 0xFFFF0000) { + // Import library. Cannot do anything sensible + err.submit(2507, cmd.InputFile); return; + } + // Remember member type + cmd.MemberType = MemberBuffer.GetFileType(); + // Temporarily set OutputType to MemberType + cmd.OutputType = cmd.MemberType; + // Put into new library + InsertMember(&MemberBuffer); + } + // Avoid getting warnings twice for duplicate symbols + RepressWarnings = 1; + // Make library header etc. and add all members to OutFile + MakeBinaryFile(); + RepressWarnings = 0; + + // Restore OutputType + cmd.OutputType = OutputFileType; + + // Replace file buffer by OutFile + *this << OutFile; + + // Clear buffers used for building OutFile + StringBuffer.SetSize(0); + StringEntries.SetNum(0); + Indexes.SetNum(0); + DataBuffer.SetSize(0); +} +*/ + +void CLibrary::RebuildOMF() { + // Rebuild OMF style library. + // Removes paths from member names, truncates to 16 characters, and makes unique. + // Symbol table is removed, not remade + + SOMFRecordPointer rec; // Current OMF record + char * ModuleName; // Module name + SStringEntry se; // String entry record to save + COMFFileBuilder NewBuffer; // Buffer for rebuilt library + uint32 Align; // Alignment + + // Remember member file type + cmd.MemberType = FILETYPE_OMF; + + // Initialize record pointer + rec.Start(Buf(), 0, GetDataSize()); + + // Read header + if (rec.Type2 != OMF_LIBHEAD) {err.submit(2500); return;} // Does not start with library header + + // Read library header + DictionaryOffset = rec.GetDword(); + DictionarySize = rec.GetWord(); + if ((uint64)DictionaryOffset + DictionarySize >= GetDataSize()) {err.submit(2035); return;} + + rec.GetByte(); // Ignore flag + // Page size / alignment for members + PageSize = rec.End + 1; + Align = 1 << FloorLog2(PageSize); // Make power of 2 + if (PageSize != Align) { + err.submit(2601, PageSize); // Error: not a power of 2 + } + + // Copy library header to new buffer + NewBuffer.Push(Buf(), PageSize); + + // Reset record loop end when DictionaryOffset is known + rec.FileEnd = DictionaryOffset; + + // Next record is start of first module + rec.GetNext(); + if (rec.Type2 != OMF_THEADR) err.submit(2500); // Member does not start with THEADR + + // Loop through the records of all OMF modules + do { + // Check record type + switch (rec.Type2) { + + case OMF_THEADR: // Start of module + + // Get name + ModuleName = rec.GetString(); + + // Remove path, truncate name and make unique + ModuleName = ShortenMemberName(ModuleName); + + // Remember name to check for duplicates + // Not needed any more: + se.String = StringBuffer.PushString(ModuleName); + se.Member = NewBuffer.GetDataSize(); + StringEntries.Push(se); + + // Make new THEADR record + NewBuffer.StartRecord(OMF_THEADR); + NewBuffer.PutString(ModuleName); + NewBuffer.EndRecord(); + break; + + case OMF_MODEND: case OMF_LIBEND: // End of module or library + // Copy MODEND record + NewBuffer.Push(Buf() + rec.FileOffset, rec.End + 1); + + // Align output file by PageSize + NewBuffer.Align(PageSize); + break; + + default: // Any other record in module + // Copy record unchanged + NewBuffer.Push(Buf() + rec.FileOffset, rec.End + 1); + break; + } + } // Point to next record + while (rec.GetNext(PageSize)); // End of loop through records + + // Put dictionary offset in LIBHEAD record + DictionaryOffset = NewBuffer.GetDataSize(); + NewBuffer.Get(3) = DictionaryOffset; + + // Take over modified library file + *this << NewBuffer; + + // Empty used buffers + StringEntries.SetNum(0); + StringBuffer.SetSize(0); +} + + +void CLibrary::StripMemberNamesUNIX() { + // Remove path from member names, set extension to default + char * MemberName1 = 0; // Name of library member + + // Loop through input library + CurrentOffset = 8; CurrentNumber = 0; + while ((MemberName1 = ExtractMember(&MemberBuffer)) != 0) { + // Properties of member + // Check if import library + if (MemberBuffer.Get(0) == 0xFFFF0000) { + // Import library. Cannot do anything sensible + err.submit(2507, cmd.InputFile); return; + } + if (MemberName1[0] == '/') continue; // names record + // remember member type + if (cmd.MemberType == 0) { + cmd.MemberType = MemberBuffer.GetFileType(); + } + // Fix name + StripMemberName(MemberName1); + // Check word size + if (cmd.DesiredWordSize == 0) { + cmd.DesiredWordSize = MemberBuffer.WordSize; + } + else if (cmd.DesiredWordSize != MemberBuffer.WordSize && MemberBuffer.WordSize != 0) { + err.submit(2012, MemberBuffer.WordSize, cmd.DesiredWordSize); // wrong word size + return; + } + if (cmd.OutputType == FILETYPE_LIBRARY || cmd.OutputType == FILETYPE_OMFLIBRARY) { + cmd.OutputType = cmd.MemberType; + } + } +} + + +void CLibrary::Dump() { + // Print contents of library + + // Dispatch according to library type + switch (cmd.InputType) { + case FILETYPE_LIBRARY: + DumpUNIX(); break; // Print contents of UNIX style library + + case FILETYPE_OMFLIBRARY: + DumpOMF(); break; // Print contents of OMF style library + + default: + err.submit(9000); // Should not occur + } +} + +void CLibrary::DumpOMF() { + // Print contents of OMF style library + uint8 Flags; // Dictionary flags + uint32 i; // Loop counter + uint32 Align; // Member alignment + uint32 RecordEnd; // End of OMF record + SOMFRecordPointer rec; // Current OMF record + char * MemberName; // Name of library member + char * SymbolName; // Name of public symbol in member + uint32 MemberStart = 0; // Start of member + uint32 MemberEnd; // End of member + uint32 MemberNum = 0; // Member number + uint32 FirstPublic; // Index to first public name of current member + CMemoryBuffer Strings; // Local string buffer + CSList MemberIndex; // Local member index buffer + COMF Member; // Local buffer for member + + DictionaryOffset = GetDataSize(); // Loop end. This value is changed when library header is read + rec.Start(Buf(), 0, DictionaryOffset); // Initialize record pointer + + PageSize = 0; + + printf("\nDump of library %s\nExported symbols by member:\n", cmd.InputFile); + + // Loop through the records of all OMF modules + do { + // Check record type + switch (rec.Type2) { + + case OMF_LIBHEAD: // Library header. This should be the first record + if (PageSize || rec.FileOffset > 0) { + err.submit(2600); break; // More than one header + } + // Read library header + DictionaryOffset = rec.GetDword(); + DictionarySize = rec.GetWord(); + if ((uint64)DictionaryOffset + DictionarySize >= GetDataSize()) {err.submit(2035); return;} + Flags = rec.GetByte(); + // Page size / alignment for members + PageSize = rec.End + 1; + Align = 1 << FloorLog2(PageSize); // Make power of 2 + if (PageSize != Align) { + err.submit(2601, PageSize); // Error: not a power of 2 + } + // Reset record loop end when DictionaryOffset is known + rec.FileEnd = DictionaryOffset; + + // Print values from LIBHEAD + printf("\nOMF Library. Page size %i. %s.", + PageSize, Lookup(OMFLibraryFlags, Flags)); + break; + + case OMF_THEADR: // Module header. Member starts here + MemberName = rec.GetString(); // Get name + MemberStart = rec.FileOffset; // Get start address + printf("\nMember %s Offset 0x%X", MemberName, MemberStart);// Print member name + break; + + case OMF_MODEND: // Member ends here. + RecordEnd = rec.FileOffset + rec.End + 1;// End of record + MemberEnd = RecordEnd; // = member end address + + // Store member in temporary buffer + Member.SetSize(0); + Member.Push(Buf() + MemberStart, MemberEnd - MemberStart); + + // Get public names from member + FirstPublic = MemberIndex.GetNumEntries(); + Member.PublicNames(&Strings, &MemberIndex, ++MemberNum); + + // Print public names + for (i = FirstPublic; i < MemberIndex.GetNumEntries(); i++) { + SymbolName = Strings.Buf() + MemberIndex[i].String; + printf("\n %s", SymbolName); + } + // Align next member by PageSize; + MemberEnd = (MemberEnd + PageSize - 1) & - (int32)PageSize; + rec.End = MemberEnd - rec.FileOffset - 1; + break; + + case OMF_LIBEND: // Last member should end here + RecordEnd = rec.FileOffset + rec.End + 1;// End of record + if (RecordEnd != DictionaryOffset) err.submit(2602); + break; + } + } // Go to next record + while (rec.GetNext()); // End of loop through records + + // Check hash table integrity + CheckOMFHash(Strings, MemberIndex); + + // Check if there is an extended library dictionary + uint32 ExtendedDictionaryOffset = DictionaryOffset + DictionarySize * 512; + + if (ExtendedDictionaryOffset > GetDataSize()) { + err.submit(2500); // File is truncated + } + if (ExtendedDictionaryOffset < GetDataSize()) { + // Library contains extended dictionary + uint32 ExtendedDictionarySize = GetDataSize() - ExtendedDictionaryOffset; + uint8 DictionaryType = Get(ExtendedDictionaryOffset); // Read first byte of extended dictionary + if (DictionaryType == OMF_LIBEXT) { + // Extended dictionary in the official format + printf("\nExtended dictionary IBM/MS format. size %i", ExtendedDictionarySize); + } + else if (ExtendedDictionarySize >= 10 && (DictionaryType == 0xAD || Get(ExtendedDictionaryOffset + 2) == MemberNum)) { + // Extended dictionary in the proprietary Borland format, documented only in US Patent 5408665, 1995 + printf("\nExtended dictionary Borland format. size %i", ExtendedDictionarySize); + } + else { + // Unknown format + printf("\nExtended dictionary size %i, unknown type 0x%02X", + ExtendedDictionarySize, DictionaryType); + } + } +} + +void CLibrary::DumpUNIX() { + // Print contents of UNIX style library + + const char * MemberName = 0; + CurrentOffset = 8; CurrentNumber = 0; + + printf("\nDump of library %s", cmd.InputFile); + + if (cmd.DumpOptions & DUMP_SECTHDR) { + // dump headers + SUNIXLibraryHeader * Header = 0; // Member header + uint32 MemberSize = 0; // Size of member + //uint32 HeaderExtra = 0; // Extra added to size of header + //uint32 NameIndex; // Index into long names member + char * Name = 0; // Name of member + int symindex = 0; // count symbol index records + int i; // loop counter + + // Search for member + while (CurrentOffset) { + //HeaderExtra = 0; + // Extract next library member from input library + Header = &Get(CurrentOffset); + // Size of member + MemberSize = (uint32)atoi(Header->FileSize); + // Member name + Name = Header->Name; + // Terminate name + for (i = 0; i < 15; i++) { + if (Name[i] == ' ') { + Name[i+1] = 0; break; + } + } + if (i == 16) Name[i] = 0; + + if (strncmp(Name, "//", 2) == 0) { + // This is the long names member. + printf("\nLongnames header \"%s\". Offset 0x%X, size 0x%X", Name, + CurrentOffset + (uint32)sizeof(SUNIXLibraryHeader), MemberSize); + } + else if (Name[0] == '/' && Name[1] <= ' ') { + // Symbol index + printf("\nSymbol index %i, \"%s\"", ++symindex, Name); + } + else if (strncmp(Name, "__.SYMDEF", 9) == 0) { + // Mac/BSD Symbol index + printf("\nSymbol index %i, \"%s\"", ++symindex, Name); + } + else if (strncmp(Name, "#1/", 3) == 0) { + // Name refers to long name after the header + // This variant is used by Mac and some versions of BSD + //HeaderExtra = atoi(Name+3); + Name += sizeof(SUNIXLibraryHeader); + if (strncmp(Name, "__.SYMDEF", 9) == 0) { + // Symbol table "__.SYMDEF SORTED" as long name + printf("\nSymbol index %i, \"%s\"", ++symindex, Name); + } + } + else break; + // Point to next member + CurrentOffset = NextHeader(CurrentOffset); + } + CurrentOffset = 8; CurrentNumber = 0; + } + + printf("\n\nExported symbols by member:\n"); + + // Loop through library + while (CurrentOffset + sizeof(SUNIXLibraryHeader) < DataSize) { + + // Reset buffers + StringBuffer.SetSize(0); + MemberBuffer.Reset(); + StringEntries.SetNum(0); + + // Get member name + MemberName = ExtractMember(&MemberBuffer); + if (MemberName == 0) break; + printf("\nMember %s", MemberName); + MemberBuffer.FileName = MemberName; + + // Detect file type of member + MemberFileType = MemberBuffer.GetFileType(); + + WordSize = MemberBuffer.WordSize; + printf (" - %s", GetFileFormatName(MemberFileType)); + if (WordSize) { + printf("-%i", MemberBuffer.WordSize); + } + else { + printf(". Type not specified. Possibly alias record"); + } + + // Get symbol table for specific file type + switch (MemberFileType) { + case FILETYPE_ELF: + if (WordSize == 32) { + // Make instance of file parser, 32 bit template + CELF elf; + MemberBuffer >> elf; // Transfer MemberBuffer to elf object + elf.PublicNames(&StringBuffer, &StringEntries, 0); + break; + } + else { + // Make instance of file parser, 64 bit template + CELF elf; + MemberBuffer >> elf; // Transfer MemberBuffer to elf object + elf.PublicNames(&StringBuffer, &StringEntries, 0); + break; + } + + case FILETYPE_COFF: { + CCOFF coff; + MemberBuffer >> coff; // Transfer MemberBuffer to coff object + coff.PublicNames(&StringBuffer, &StringEntries, 0); + break;} + + case FILETYPE_MACHO_LE: + if (WordSize == 32) { + // Make instance of file parser, 32 bit template + CMACHO mac; + MemberBuffer >> mac; // Transfer MemberBuffer to coff object + mac.PublicNames(&StringBuffer, &StringEntries, 0); + break; + } + else { + // Make instance of file parser, 64 bit template + CMACHO mac; + MemberBuffer >> mac; // Transfer MemberBuffer to coff object + mac.PublicNames(&StringBuffer, &StringEntries, 0); + break; + } + + case IMPORT_LIBRARY_MEMBER: { + // This is an import library + char * name1 = MemberBuffer.Buf() + 20; + printf("\n Import %s from %s", name1, name1 + strlen(name1) + 1); + break;} + + default: + printf("\n Cannot extract symbol names from this file type"); + break; + } + + // Loop through table of public names + for (uint32 i = 0; i < StringEntries.GetNumEntries(); i++) { + uint32 j = StringEntries[i].String; + printf("\n %s", StringBuffer.Buf() + j); + } + } +} + + +uint32 CLibrary::NextHeader(uint32 Offset) { + + // Loop through library headers. + // Input = current offset. Output = next offset + SUNIXLibraryHeader * Header; // Member header + int32 MemberSize; // Size of member + //uint32 HeaderExtra = 0; // Extra added to size of header + uint32 NextOffset; // Offset of next header + + if (Offset + sizeof(SUNIXLibraryHeader) >= DataSize) { + // No more members + return 0; + } + // Find header + Header = &Get(Offset); + + // Size of member + MemberSize = atoi(Header->FileSize); + if (MemberSize < 0 || MemberSize + Offset + sizeof(SUNIXLibraryHeader) > DataSize) { + err.submit(2500); // Points outside file + return 0; + } + if (strncmp(Header->Name, "#1/", 3) == 0) { + // Name refers to long name after the header + // This variant is used by Mac and some versions of BSD. + // HeaderExtra is included in MemberSize: + // HeaderExtra = atoi(Header->Name+3); + } + + // Get next offset + NextOffset = Offset + sizeof(SUNIXLibraryHeader) + MemberSize; + // Round up to align by 2 + NextOffset = (NextOffset + 1) & ~ 1; + // Check if last + if (NextOffset >= DataSize) NextOffset = 0; + return NextOffset; +} + + +void CLibrary::StartExtracting() { + // Initialize before ExtractMember() + if (cmd.InputType == FILETYPE_OMFLIBRARY) { + SOMFRecordPointer rec; // OMF records + rec.Start(Buf(), 0, GetDataSize()); // Initialize record pointer + if (rec.Type2 != OMF_LIBHEAD) { + err.submit(2500); return; // This should not happen + } + // Read library header + DictionaryOffset = rec.GetDword(); // Read dictionary offset + DictionarySize = rec.GetWord(); // Read dictionary size + rec.GetByte(); // Read flag + // Page size / alignment for members + PageSize = rec.End + 1; + uint32 align = 1 << FloorLog2(PageSize); // Make power of 2 + if (PageSize != align) { + err.submit(2601, PageSize); // Error: not a power of 2 + } + CurrentOffset = PageSize; // Offset to first library member + } + else { + // Unix style library. First header at offset 8 + CurrentOffset = 8; + } + // Current member number + CurrentNumber = 0; +} + + +char * CLibrary::ExtractMember(CFileBuffer * Destination) { + // Extract library member + // Dispatch according to library type + if (cmd.InputType == FILETYPE_OMFLIBRARY || cmd.InputType == FILETYPE_OMF) { + return ExtractMemberOMF(Destination); + } + else { + return ExtractMemberUNIX(Destination); + } +} + + +char * CLibrary::ExtractMemberOMF(CFileBuffer * Destination) { + // Extract member of OMF style library + + uint32 RecordEnd; // End of OMF record + SOMFRecordPointer rec; // Current OMF record + char * MemberName = 0; // Name of library member + uint32 MemberStart = 0; // Start of member + uint32 MemberEnd = 0; // End of member + + if (CurrentOffset >= DictionaryOffset) return 0;// No more members + + rec.Start(Buf(), CurrentOffset, DictionaryOffset);// Initialize record pointer + + // Loop through the records of all OMF modules + do { + // Check record type + switch (rec.Type2) { + + case OMF_THEADR: // Module header. Member starts here + MemberName = rec.GetString(); // Get name + MemberStart = rec.FileOffset; // Get start address + break; + + case OMF_MODEND: // Member ends here. + RecordEnd = rec.FileOffset + rec.End +1;// End of record + MemberEnd = RecordEnd; // = member end address + + // Save member as raw data + if (Destination) { + Destination->SetSize(0); // Make sure destination buffer is empty + Destination->FileType = Destination->WordSize = 0; + Destination->Push(Buf() + MemberStart, MemberEnd - MemberStart); + } + + // Align next member by PageSize; + rec.GetNext(PageSize); + CurrentOffset = rec.FileOffset; + + // Check name + //!!if (MemberName[0] == 0) MemberName = (char*)"NoName!"; + + // Return member name + return MemberName; + + case OMF_LIBEND: // Last member should end here + RecordEnd = rec.FileOffset + rec.End + 1;// End of record + if (RecordEnd != DictionaryOffset) err.submit(2602); + + // No more members: + return 0; + } + } // Go to next record + while (rec.GetNext()); // End of loop through records + + err.submit(2610); // Library end record not found + return 0; +} + + +char * CLibrary::ExtractMemberUNIX(CFileBuffer * Destination) { + // Extract member of UNIX style library + // This function is called repeatedly to get each member of library/archive + SUNIXLibraryHeader * Header = 0; // Member header + uint32 MemberSize = 0; // Size of member + uint32 HeaderExtra = 0; // Extra added to size of header + uint32 NameIndex; // Index into long names member + char * Name = 0; // Name of member + int Skip = 1; // Skip record and search for next + int i; // Loop counter + char * p; // Used for loop through string + + if (CurrentOffset == 0 || CurrentOffset + sizeof(SUNIXLibraryHeader) >= DataSize) { + // No more members + return 0; + } + + // Search for member + while (Skip && CurrentOffset) { + HeaderExtra = 0; + // Extract next library member from input library + Header = &Get(CurrentOffset); + // Size of member + MemberSize = (uint32)atoi(Header->FileSize); + if (MemberSize + CurrentOffset + sizeof(SUNIXLibraryHeader) > DataSize) { + err.submit(2500); // Points outside file + return 0; + } + // Member name + Name = Header->Name; + if (strncmp(Name, "// ", 3) == 0) { + // This is the long names member. Remember its position + LongNames = CurrentOffset + sizeof(SUNIXLibraryHeader); + LongNamesSize = MemberSize; + // The long names are terminated by '/' or 0, depending on system, + // but may contain non-terminating '/'. Find out which type we have: + // Pointer to LongNames record + p = Buf() + LongNames; + // Find out whether we have terminating zeroes: + if ((LongNamesSize > 1 && p[LongNamesSize-1] == '/') || (p[LongNamesSize-1] <= ' ' && p[LongNamesSize-2] == '/')) { + // Names are terminated by '/'. Replace all '/' by 0 in the longnames record + for (uint32 j = 0; j < LongNamesSize; j++, p++) { + if (*p == '/') *p = 0; + } + } + } + else if (strncmp(Name, "/ ", 2) == 0 + || strncmp(Name, "__.SYMDEF", 9) == 0) { + // This is a symbol index member. + // The symbol index is not used because we are always building a new symbol index. + } + else if (Name[0] == '/' && Name[1] >= '0' && Name[1] <= '9' && LongNames) { + // Name contains index into LongNames record + NameIndex = atoi(Name+1); + if (NameIndex < LongNamesSize) { + Name = Buf() + LongNames + NameIndex; + } + else { + Name = (char*)"NoName!"; + } + Skip = 0; + } + else if (strncmp(Name, "#1/", 3) == 0) { + // Name refers to long name after the header + // This variant is used by Mac and some versions of BSD + HeaderExtra = atoi(Name+3); + Name += sizeof(SUNIXLibraryHeader); + if (MemberSize > HeaderExtra) { + // The length of the name, HeaderExtra, is included in the + // Header->FileSize field. Subtract to get the real file size + MemberSize -= HeaderExtra; + } + if (strncmp(Name, "__.SYMDEF", 9) == 0) { + // Symbol table "__.SYMDEF SORTED" as long name + Skip = 1; + } + else { + Skip = 0; + } + } + else { + // Ordinary short name + // Name may be terminated by '/' or space. Replace termination char by 0 + for (i = 15; i >= 0; i--) { + if (Name[i] == ' ' || Name[i] == '/') Name[i] = 0; + else break; + } + // Terminate name with max length by overwriting Date field, which we are not using + Name[16] = 0; + Skip = 0; + } + // Point to next member + CurrentOffset = NextHeader(CurrentOffset); + // Increment number + CurrentNumber += !Skip; + } // End of while loop + + // Save member as raw data + if (Destination) { + Destination->SetSize(0); // Make sure destination buffer is empty + Destination->FileType = Destination->WordSize = 0; + Destination->Push((int8*)Header + sizeof(SUNIXLibraryHeader) + HeaderExtra, MemberSize); + } + + // Check name + if (Name[0] == 0) Name = (char*)"NoName!"; + + // Return member name + return Name; +} + +void CLibrary::InsertMember(CFileBuffer * member) { + // Add member to output library + if (cmd.OutputType == FILETYPE_OMF) { + InsertMemberOMF(member); // OMF style output library + } + else { + InsertMemberUNIX(member); // UNIX style output library + } +} + + +void CLibrary::InsertMemberOMF(CFileBuffer * member) { + // Add member to OMF library + + // Check file type + if (member->GetFileType() != FILETYPE_OMF) err.submit(9000); + + // Get word size + WordSize = member->WordSize; + + // Store offset + uint32 offset = DataBuffer.GetDataSize(); + Indexes.Push(offset); + + // Store member + DataBuffer.Push(member->Buf(), member->GetDataSize()); + DataBuffer.Align(PageSize); + + // Member index + uint32 mindex = Indexes.GetNumEntries() - 1; + + // Get public string table + COMF omf; + *member >> omf; // Translate member to class OMF + omf.PublicNames(&StringBuffer, &StringEntries, mindex); // Make list of public names + *member << omf; // Return buffer to member +} + + +void CLibrary::InsertMemberUNIX(CFileBuffer * member) { + // Add next library member to output library + uint32 RawSize = 0; // Size of binary file + uint32 AlignmentPadding = 0; // Padding after file + char * name = 0; // Name of member + int NameLength = 0; // length of name + int NameAfter = 0; // length of name after MachO header + int i; // loop counter, index + + // Get word size + WordSize = member->WordSize; + + // Make member header + SUNIXLibraryHeader header; + memset(&header, ' ', sizeof(SUNIXLibraryHeader)); // Fill with spaces + + // Name of member + if (member->OutputFileName == 0 || *member->OutputFileName == 0) member->OutputFileName = member->FileName; + + if (cmd.LibrarySubtype == LIBTYPE_SHORTNAMES) { + // Make short name + name = ShortenMemberName(member->OutputFileName); + } + else { + // Remove path from library member name. Original long name is overwritten + name = StripMemberName((char*)(member->OutputFileName)); + } + NameLength = strlen(name); + + if (cmd.OutputType == FILETYPE_MACHO_LE && cmd.LibrarySubtype != LIBTYPE_SHORTNAMES) { + // Mach-O library stores name after header record. + // Name is zero padded to length 4 modulo 8 to align by 8 + int pad = 8 - ((NameLength + 4) & 7); + NameAfter = NameLength + pad; + sprintf(header.Name, "#1/%i ", NameAfter); + } + else { + // ELF and COFF library store names < 16 characters in the name field + if (NameLength < 16) { + // (Don't use sprintf to write header.Name here: It seems that Gnu sprintf checks the size of the + // buffer it is writing to. Gives buffer overrun error when termniating zero goes beyond the name field) + memset(header.Name, ' ', 16); + memcpy(header.Name, name, NameLength); + header.Name[NameLength] = '/'; + } + else { + // store in LongNamesBuffer + if (cmd.OutputType == FILETYPE_COFF) { + // COFF: Name is zero-terminated + i = LongNamesBuffer.PushString(name); + } + else { + // ELF: Name terminated by "/\n" + i = LongNamesBuffer.Push(name, NameLength); + LongNamesBuffer.Push("/\n", 2); + } + // store index into long names member + sprintf(header.Name, "/%i ", i); + } + } + + // Date + sprintf(header.Date, "%u ", (uint32)time(0)); + + // User and group id + header.UserID[0] = '0'; + header.GroupID[0] = '0'; + // File mode + strcpy(header.FileMode, "100666"); + // Size of binary file + RawSize = member->GetDataSize(); + // Calculate alignment padding + if (AlignBy) { + AlignmentPadding = uint32(-int32(RawSize)) & (AlignBy-1); + } + + // File size including name string + sprintf(header.FileSize, "%u ", NameAfter + RawSize + AlignmentPadding); + + // Header end + header.HeaderEnd[0] = '`'; + header.HeaderEnd[1] = '\n'; + + // Remove terminating zeroes + for (uint32 i = 0; i < sizeof(SUNIXLibraryHeader); i++) { + if (((char*)&header)[i] == 0) ((char*)&header)[i] = ' '; + } + + // Store offset + uint32 offset = DataBuffer.GetDataSize(); + Indexes.Push(offset); + + // Store member header + DataBuffer.Push(&header, sizeof(header)); + + if (cmd.OutputType == FILETYPE_MACHO_LE) { + // Store member name after header if Mach-O + if (NameAfter) { + // Mach-O library stores name after header record. + DataBuffer.PushString(name); + } + DataBuffer.Align(AlignBy); + } + + // Store member + DataBuffer.Push(member->Buf(), RawSize); + + // Align by padding with '\n' + for (uint32 i = 0; i < AlignmentPadding; i++) { + DataBuffer.Push("\n", 1); + } + + // Member index + uint32 mindex = Indexes.GetNumEntries() - 1; + + // Get public string table + switch(member->GetFileType()) { + case FILETYPE_COFF: { + CCOFF coff; + *member >> coff; // Translate member to type COFF + coff.PublicNames(&StringBuffer, &StringEntries, mindex); // Make list of public names + *member << coff; // Return buffer to member + break;} + + case FILETYPE_OMF: { + COMF omf; + *member >> omf; // Translate member to type COFF + omf.PublicNames(&StringBuffer, &StringEntries, mindex); // Make list of public names + *member << omf; // Return buffer to member + break;} + + case FILETYPE_ELF: + if (WordSize == 32) { + // Make instance of file parser, 32 bit template + CELF elf; + *member >> elf; // Translate member to type ELF + elf.PublicNames(&StringBuffer, &StringEntries, mindex); // Make list of public names + *member << elf; // Return buffer to member + break; + } + else { + // Make instance of file parser, 64 bit template + CELF elf; + *member >> elf; // Translate member to type ELF + elf.PublicNames(&StringBuffer, &StringEntries, mindex); // Make list of public names + *member << elf; // Return buffer to member + break; + } + + case FILETYPE_MACHO_LE: + if (WordSize == 32) { + // Make instance of file parser, 32 bit template + CMACHO mac; + *member >> mac; // Translate member to type ELF + mac.PublicNames(&StringBuffer, &StringEntries, mindex); // Make list of public names + *member << mac; // Return buffer to member + break; + } + else { + // Make instance of file parser, 64 bit template + CMACHO mac; + *member >> mac; // Translate member to type ELF + mac.PublicNames(&StringBuffer, &StringEntries, mindex); // Make list of public names + *member << mac; // Return buffer to member + break; + } + + default: // Type not supported + err.submit(2501, GetFileFormatName(member->GetFileType())); + break; + } +} + +/* unused: +char * CLibrary::TruncateMemberName(char const * name) { + // Remove path and truncate object file name to 15 characters + // This function removes any path from the member name, + // changes the extension to the default for the the output file type, + // changes any spaces to underscores, and + // truncates the member name to 15 characters for the sake of compatibility. + // The return value is an ASCII string in a static buffer + static char TruncName[32]; // Truncated name + int maxlen; // Max length, not including extension + char const * p1; // Point to start of name without path + char const * extension; // Default extension for file type + int i; // Loop counter + int len; // String length + static int DummyNumber = 0; // Count invalid/null names + int FileType; // File type + + // Remove path + len = (int)strlen(name); p1 = name; + for (i = len-1; i >= 0; i--) { + if (name[i] == '/' || name[i] == '\\' || name[i] == ':') { + p1 = name + i + 1; break; + } + } + // Remove extension + len = (int)strlen(p1); + for (i = len-1; i >= 0; i--) { + if (p1[i] == '.') { + len = i; break; + } + } + + // Check if any name remains + if (len == 0) { // No name. Make one + sprintf(TruncName, "NoName%i", ++DummyNumber); + p1 = TruncName; len = (int)strlen(p1); + } + + // Get file type + FileType = cmd.OutputType; + if (FileType == CMDL_OUTPUT_DUMP || FileType == 0) FileType = cmd.InputType; + if (FileType >= FILETYPE_LIBRARY) FileType = cmd.MemberType; + + // Get default extension and max length of name without extension + if (FileType == FILETYPE_COFF || FileType == FILETYPE_OMF) { + maxlen = 11; extension = ".obj"; + } + else { + maxlen = 13; extension = ".o"; + } + if (len > maxlen) len = maxlen; + + // Truncate name + strncpy(TruncName, p1, len); + TruncName[len] = 0; + + // Remove any spaces or other illegal characters + len = (int)strlen(TruncName); + for (i = 0; i < len; i++) { + if ((uint8)TruncName[i] <= 0x20) TruncName[i] = '_'; + } + + // Add default extension + strcpy(TruncName+strlen(TruncName), extension); + + // Terminate + TruncName[15] = 0; + return TruncName; +} +*/ + +char * CLibrary::StripMemberName(char * name) { + // Remove path from zero-terminated library member name and set extension to default. + // Note: Original long name is overwritten + char * p1; // Point to start of name without path + const char * extension = 0; // Default extension for file type + int i; // Loop counter + int len0; // Original string length + int len; // String length + int nlen; // length of name without extension + int elen = 0; // length of extension + static int DummyNumber = 0; // Count invalid/null names + int FileType; // File type + + // Length + len0 = len = (int)strlen(name); + + // Remove path + p1 = name; + for (i = len-1; i >= 0; i--) { + if (name[i] == '/' || name[i] == '\\' || name[i] == ':') { + p1 = name + i + 1; break; + } + } + len -= i + 1; + + // move to begin of buffer + if (p1 > name) { + memmove(name, p1, len + 1); + } + + // Get file type + if (cmd.MemberType) { + FileType = cmd.MemberType; + } + else if (cmd.LibraryOptions & CMDL_LIBRARY_EXTRACTMEM) { + FileType = cmd.InputType; + } + else { + FileType = cmd.OutputType; + } + if (FileType == CMDL_OUTPUT_DUMP || FileType == 0) FileType = cmd.InputType; + if (FileType >= FILETYPE_LIBRARY) FileType = cmd.MemberType; + + // Get default extension and max length of name without extension + if (FileType == FILETYPE_COFF || FileType == FILETYPE_OMF) { + extension = ".obj"; elen = 4; + } + else if (FileType == FILETYPE_ELF || FileType == FILETYPE_MACHO_LE || FileType == FILETYPE_MACHO_BE) { + extension = ".o"; elen = 2; + } + + // find extension + for (nlen = len-1; nlen >= 0; nlen--) { + if (name[nlen] == '.') { + break; + } + } + + // Remove any spaces or other illegal characters + for (i = 0; i < nlen; i++) { + if ((uint8)name[i] <= 0x20 || name[i] == '.') name[i] = '_'; + } + + // Check if any name remains + if ((len == 0 && len0 > 12) || nlen == 0) { // No name. Make one + sprintf(name, "NoName%i", ++DummyNumber); + len = (int)strlen(name); + } + + // Replace extension + if (len + elen <= len0 && extension != 0) { + strcpy(name + nlen, extension); + } + // Terminate + return name; +} + + +char * CLibrary::ShortenMemberName(char const *name) { + // Truncate library member name to 15 characters and make unique + // The path is removed and the extension set to default. + // The original long name is not overwritten + static char fixedName[32]; // Modified name + char const * p1; // Point to start of name without path + char const * extension; // Default extension for file type + int i; // Loop counter + int len; // Filename length + int len0; // Filename length without extension + int elen; // length of extension + static int RunningNumber = 0; // Enumerate truncated names + int FileType; // File type + + // Length + len = (int)strlen(name); + + // Skip path + p1 = name; + for (i = len-1; i >= 0; i--) { + if (name[i] == '/' || name[i] == '\\' || name[i] == ':') { + p1 = name + i + 1; break; + } + } + len = (int)strlen(name); + + // move to static buffer + if (len > 15) len = 15; + memcpy(fixedName, p1, len); + fixedName[len] = 0; + + // find extension + for (i = len-1; i >= 0; i--) { + if (fixedName[i] == '.') { + fixedName[i] = 0; break; + } + } + // length without extension + len0 = (int)strlen(fixedName); + + // Remove any spaces or other illegal characters + for (i = 0; i < len0; i++) { + if ((uint8)fixedName[i] <= 0x20 || fixedName[i] == '.') fixedName[i] = '_'; + } + + // Check if any name remains + if (len0 == 0) { // No name. Make one + sprintf(fixedName, "NoName_%X", RunningNumber++); + len0 = (int)strlen(fixedName); + } + + // Get file type + FileType = cmd.OutputType; + if (FileType == CMDL_OUTPUT_DUMP || FileType == 0) FileType = cmd.InputType; + if (FileType >= FILETYPE_LIBRARY) FileType = cmd.MemberType; + + // Get default extension and max length of name without extension + if (FileType == FILETYPE_COFF || FileType == FILETYPE_OMF) { + extension = ".obj"; elen = 4; + } + else { + extension = ".o"; elen = 2; + } + + // Make unique and add extension + if (len0 + elen >= 15) { + // Name is truncated or possibly identical to some other truncated name. + // Insert 2-, 3- or 4-digit running hexadecimal number. + if (RunningNumber < 0x100) { + sprintf(fixedName + 12 - elen, "_%02X%s", RunningNumber++, extension); + } + else if (RunningNumber < 0x1000) { + sprintf(fixedName + 12 - elen, "%03X%s", RunningNumber++, extension); + } + else { + sprintf(fixedName + 11 - elen, "%04X%s", (RunningNumber++ & 0xFFFF), extension); + } + } + else { + // Short name. Just add extension + strcpy(fixedName + len0, extension); + } + + // Return static name buffer + return fixedName; +} + +/* Unused: +int CLibrary::MemberNameExistsUNIX(char * name) { + // Check if DataBuffer contains a member with this name + char Name1[20], Name2[20]; + uint32 i, j; + + // Terminate name without extension + memcpy(Name1, name, 16); + for (j = 0; j < 16; j++) { + if (Name1[j] == '.' || Name1[j] == '/') Name1[j] = 0; + } + + // Loop through previous members in DataBuffer + for (i = 0; i < Indexes.GetNumEntries(); i++) { + uint32 offset = Indexes[i]; + // Copy name of member i + memcpy(Name2, DataBuffer.Buf() + offset, 16); + // Terminate name2 + for (j = 0; j < 16; j++) { + if (Name2[j] == '.' || Name2[j] == '/') Name2[j] = 0; + } + // Case-insensitive compare of names + if (stricmp(Name1, Name2) == 0) { + // Identical name found + return i + 1; + } + } + // No identical name found + return 0; +}*/ + + +void CLibrary::SortStringTable() { + // Sort the string table in ASCII order + + // Length of table + int32 n = StringEntries.GetNumEntries(); + if (n <= 0) return; + + // Point to table of SStringEntry records + SStringEntry * Table = &StringEntries[0]; + // String pointers + char * s1, * s2; + + // Simple Shell sort with Sedgewick gaps: + int32 i, j, k, gap; + 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++) { + SStringEntry key = Table[i]; + char * strkey = StringBuffer.Buf() + key.String; + for (j = i - gap; j >= 0 && strcmp(strkey, StringBuffer.Buf() + Table[j].String) < 0; j -= gap) { + Table[j + gap] = Table[j]; + } + Table[j + gap] = key; + } + } + + // Now StringEntries has been sorted. Reorder StringBuffer to the sort order. + CMemoryBuffer SortedStringBuffer; // Temporary buffer for strings in sort order + for (i = 0; i < n; i++) { + // Pointer to old string + s1 = StringBuffer.Buf() + Table[i].String; + // Update table to point to new string + Table[i].String = SortedStringBuffer.GetDataSize(); + // Put string into SortedStringBuffer + SortedStringBuffer.PushString(s1); + } + if (SortedStringBuffer.GetDataSize() != StringBuffer.GetDataSize()) { + // The two string buffers should be same size + err.submit(9000); return; + } + // Copy SortedStringBuffer into StringBuffer + memcpy(StringBuffer.Buf(), SortedStringBuffer.Buf(), StringBuffer.GetDataSize()); + + // Check for duplicate symbols + for (i = 0; i < n-1; i++) { + s1 = StringBuffer.Buf() + Table[i].String; + for (j = i + 1; j < n; j++) { + s2 = StringBuffer.Buf() + Table[j].String; + if (strcmp(s1,s2) == 0) { + // Duplicate found + // Compose error string "Modulename1 and Modulename2" + uint32 errstring = LongNamesBuffer.GetDataSize(); + LongNamesBuffer.PushString(GetModuleName(Table[i].Member)); + LongNamesBuffer.SetSize(LongNamesBuffer.GetDataSize()-1); // remove terminating zero + LongNamesBuffer.Push(" and ", 5); + LongNamesBuffer.PushString(GetModuleName(Table[j].Member)); + err.submit(1214, s1, (char*)LongNamesBuffer.Buf() + errstring); + LongNamesBuffer.SetSize(errstring); // remove string again + i++; // Prevent excessive messages + } + else { + break; + } + } + } +} + + +uint32 EndianChange(uint32 n) { + // Convert little-endian to big-endian number, or vice versa + return (n << 24) | ((n & 0x0000FF00) << 8) | ((n & 0x00FF0000) >> 8) | (n >> 24); +} + + +uint32 RoundEven(uint32 n) { + // Round up number to nearest even + return (n + 1) & uint32(-2); +} + + +uint32 Round4(uint32 n) { + // Round up number to nearest multiple of 4 + return (n + 3) & uint32(-4); +} + + +void CLibrary::MakeSymbolTableUnix() { + // Make symbol table for COFF, ELF or MACHO library + // Uses UNIX archive format for COFF, BSD and Mac + uint32 i; // Loop counter + uint32 MemberOffset; // Offset to member + uint32 LongNameSize = 0; // Length of symbol table name if stored after record + + int SymbolTableType = cmd.OutputType; // FILETYPE_COFF = 1: COFF + // FILETYPE_ELF = 3: ELF + // FILETYPE_MACHO_LE = 4: Mac, unsorted + // 0x10000004: Mac, sorted + // Newer Mac tools require the sorted type, unless there are multiple publics with same name + if (SymbolTableType == FILETYPE_MACHO_LE) SymbolTableType |= 0x10000000; + + // Make symbol table header + SUNIXLibraryHeader SymTab; // Symbol table header + memset(&SymTab, ' ', sizeof(SymTab)); // Fill with spaces + SymTab.Name[0] = '/'; // Name = '/' + // The silly Mac linker requires that the symbol table has a date stamp not + // older than the .a file. Fix this by post-dating the symbol table: + uint32 PostDate = 0; + if (SymbolTableType & 0x10000000) PostDate = 100; // Post-date if mac sorted symbol table + sprintf(SymTab.Date, "%u ", (uint32)time(0) + PostDate); // Date stamp for symbol table + + SymTab.UserID[0] = '0'; // UserID = 0 (may be omitted in COFF) + SymTab.GroupID[0] = '0'; // GroupID = 0 (may be omitted in COFF) + strcpy(SymTab.FileMode, "100666"); // FileMode = 0100666 (may be 0 in COFF) + + SymTab.HeaderEnd[0] = '`'; // End with "`\n" + SymTab.HeaderEnd[1] = '\n'; + + // File header + OutFile.Push("!\n", 8); + + uint32 NumMembers = Indexes.GetNumEntries(); // Number of members + uint32 NumStrings = StringEntries.GetNumEntries(); // Number of symbol names + uint32 StringsLen = StringBuffer.GetDataSize(); // Size of string table + + // Calculate sizes of string index records, not including header + // Unsorted index, used in ELF and COFF libraries + uint32 Index1Size = (NumStrings+1)*4 + StringsLen; + // Sorted index, used in COFF libraries as second member + uint32 Index2Size = (NumMembers+2)*4 + NumStrings*2 + StringsLen; + // Sorted index, used in Mach-O libraries + uint32 Index3Size = Round4(NumStrings*8 + 8 + StringsLen); + // Longnames member + uint32 LongnamesMemberSize = 0; + // Official MS COFF reference says that the "//" longnames member must be present, + // even if it is unused, but MS LIB does not make it unless it is needed. + // Here, we will include the longnames member only if it is needed + if ((SymbolTableType == FILETYPE_COFF || SymbolTableType == FILETYPE_ELF) && LongNamesBuffer.GetDataSize()) { + LongnamesMemberSize = sizeof(SUNIXLibraryHeader) + LongNamesBuffer.GetDataSize(); + } + + // Offset to first member + uint32 FirstMemberOffset = 0; + switch (SymbolTableType) { + case FILETYPE_COFF: + FirstMemberOffset = 8 + 2*sizeof(SUNIXLibraryHeader) + RoundEven(Index1Size) + + RoundEven(Index2Size) + RoundEven(LongnamesMemberSize); + break; + case FILETYPE_ELF: + FirstMemberOffset = 8 + sizeof(SUNIXLibraryHeader) + RoundEven(Index1Size) + + RoundEven(LongnamesMemberSize); + break; + case FILETYPE_MACHO_LE: + FirstMemberOffset = 8 + sizeof(SUNIXLibraryHeader) + Index3Size; + break; + case FILETYPE_MACHO_LE | 0x10000000: // Mac, sorted + LongNameSize = 20; + FirstMemberOffset = 8 + sizeof(SUNIXLibraryHeader) + Index3Size + LongNameSize; + break; + default: + err.submit(2501, GetFileFormatName(cmd.OutputType)); + } + + // Make unsorted symbol table for COFF or ELF output + if (SymbolTableType == FILETYPE_COFF || SymbolTableType == FILETYPE_ELF) { + + // Put file size into symbol table header + sprintf(SymTab.FileSize, "%u ", Index1Size); + // Remove terminating zeroes + for (i = 0; i < sizeof(SymTab); i++) { + if (((char*)&SymTab)[i] == 0) ((char*)&SymTab)[i] = ' '; + } + + // Store header + OutFile.Push(&SymTab, sizeof(SymTab)); + + // Store table of offsets + uint32 BigEndian; // Number converted to big-endian + BigEndian = EndianChange(NumStrings); + OutFile.Push(&BigEndian, sizeof(BigEndian)); // Number of symbols + + // Loop through strings + for (i = 0; i < NumStrings; i++) { + // Get record in temporary symbol table + SStringEntry * psym = &StringEntries[i]; + // Get offset of member in DataBuffer + MemberOffset = Indexes[psym->Member]; + // Add size of headers to compute member offset in final file + BigEndian = EndianChange(MemberOffset + FirstMemberOffset); + // Store offset as big endian number + OutFile.Push(&BigEndian, sizeof(BigEndian)); + } + + // Store strings + OutFile.Push(StringBuffer.Buf(), StringBuffer.GetDataSize()); + // Align by 2 + if (OutFile.GetDataSize() & 1) { + OutFile.Push("\n", 1); + } + } + + // Sort string table + if (!RepressWarnings && SymbolTableType != FILETYPE_MACHO_LE) SortStringTable(); + + // Make sorted symbol table, COFF style + if (SymbolTableType == FILETYPE_COFF) { + if (NumMembers > 0xFFFF) err.submit(2502); // Too many members + + // Reuse symbol table header, change size entry + sprintf(SymTab.FileSize, "%u ", Index2Size); + + // Remove terminating zeroes + for (i = 0; i < sizeof(SymTab); i++) { + if (((char*)&SymTab)[i] == 0) ((char*)&SymTab)[i] = ' '; + } + // Store header + OutFile.Push(&SymTab, sizeof(SymTab)); + + // Store number of members + OutFile.Push(&NumMembers, sizeof(NumMembers)); + + // Store member offsets + for (i = 0; i < NumMembers; i++) { + MemberOffset = Indexes[i] + FirstMemberOffset; + OutFile.Push(&MemberOffset, sizeof(MemberOffset)); + } + + // Store number of symbols + OutFile.Push(&NumStrings, sizeof(NumStrings)); + + // Store member index for each string + // Loop through strings + for (i = 0; i < NumStrings; i++) { + // Get record in temporary symbol table + SStringEntry * psym = &StringEntries[i]; + // Get member index, 16 bits + uint16 MemberI = (uint16)(psym->Member + 1); + OutFile.Push(&MemberI, sizeof(MemberI)); + } + + // Store strings + OutFile.Push(StringBuffer.Buf(), StringBuffer.GetDataSize()); + // Align by 2 + if (OutFile.GetDataSize() & 1) { + OutFile.Push("\n", 1); + } + } + + // Make longnames table member for COFF or ELF output + // (The decision whether to include a "//" longnames member is taken above) + if (LongnamesMemberSize) { + // reuse SymTab + strcpy(SymTab.Name, "// "); // Name = "//" + memset(SymTab.FileSize, ' ', 10); + sprintf(SymTab.FileSize, "%u", LongNamesBuffer.GetDataSize()); + + // Remove terminating zeroes + for (i = 0; i < sizeof(SymTab); i++) { + if (((char*)&SymTab)[i] == 0) ((char*)&SymTab)[i] = ' '; + } + // Store header + OutFile.Push(&SymTab, sizeof(SymTab)); + // Store data + OutFile.Push(LongNamesBuffer.Buf(), LongNamesBuffer.GetDataSize()); + // Align by 2 + if (OutFile.GetDataSize() & 1) { + OutFile.Push("\n", 1); + } + } + + // Make sorted or unsorted symbol table, Mach-O style + if ((SymbolTableType & 0xFFFF) == FILETYPE_MACHO_LE) { + + if (SymbolTableType & 0x10000000) { + // Sorted table. "__.SYMDEF SORTED" stored as long name + memcpy(SymTab.Name, "#1/20 ", 16); + // Put file size into symbol table header, including long name length + sprintf(SymTab.FileSize, "%u ", Index3Size + LongNameSize); + } + else { + // Unsorted table. "__.SYMDEF" stored as short name + memcpy(SymTab.Name, "__.SYMDEF ", 16); + // Put file size into symbol table header + sprintf(SymTab.FileSize, "%u ", Index3Size); + } + + // Remove terminating zeroes + for (i = 0; i < sizeof(SymTab); i++) { + if (((char*)&SymTab)[i] == 0) ((char*)&SymTab)[i] = ' '; + } + + // Store header + OutFile.Push(&SymTab, sizeof(SymTab)); + + if (SymbolTableType & 0x10000000) { + // Store long name "__.SYMDEF SORTED" + OutFile.Push("__.SYMDEF SORTED\0\0\0\0", LongNameSize); + } + + // Store an array of records of string index and member offsets + // Store length first + uint32 ArrayLength = NumStrings * sizeof(SStringEntry); + OutFile.Push(&ArrayLength, sizeof(ArrayLength)); + + // Loop through strings + for (i = 0; i < NumStrings; i++) { + // Get record in temporary symbol table + SStringEntry * psym = &StringEntries[i]; + SStringEntry Record; + Record.String = psym->String; + Record.Member = Indexes[psym->Member] + FirstMemberOffset; + // Store symbol record + OutFile.Push(&Record, sizeof(Record)); + } + + // Store length of string table + StringsLen = Round4(StringsLen); // Round up to align by 4 + OutFile.Push(&StringsLen, sizeof(StringsLen)); + // Store strings + OutFile.Push(StringBuffer.Buf(), StringBuffer.GetDataSize()); + // Align by 4 + OutFile.Align(4); + // Cross check precalculated size (8 is the size of "!\n" file identifier) + if (OutFile.GetDataSize() != Index3Size + sizeof(SymTab) + 8 + LongNameSize) err.submit(9000); + } +} + + +void CLibrary::MakeBinaryFile() { + if (cmd.OutputType == FILETYPE_OMF) { + MakeBinaryFileOMF(); // OMF style output library + } + else { + MakeBinaryFileUNIX(); // UNIX style output library + } +} + + +void CLibrary::MakeBinaryFileOMF() { + // Make OMF library + uint32 PageSize; // Page size / alignment for output library + uint32 temp; // Temporary + uint16 temp16; // Temporary + uint8 temp8; // Temporary + uint32 MemberI; // Member number + uint32 MemberOffset; // File offset of member in output file + uint32 MemberStart; // Start of member in DataBuffer + uint32 MemberEnd; // End of member in DataBuffer + uint32 SymbolI; // Public symbol number + uint32 DictionaryOffset2; // Offset to hash table + CSList MemberPageIndex; // Remember page index of each member + + // Check number of entries + if (DataBuffer.GetNumEntries() >= 0x8000) { + err.submit(2606); return; // Error: too big + } + + // Find optimal page size + PageSize = DataBuffer.GetDataSize() / (0x8000 - DataBuffer.GetNumEntries()); + // Make power of 2, minimum 16 + temp = FloorLog2(PageSize) + 1; + if (temp < 4) temp = 4; + PageSize = 1 << temp; + + // Make library header + temp8 = OMF_LIBHEAD; + OutFile.Push(&temp8, 1); // Library header type byte + temp16 = PageSize - 3; + OutFile.Push(&temp16, 2); // Record length + OutFile.Push(0, 6); // Dictionary offset and size: insert later + temp8 = 1; + OutFile.Push(&temp8, 1); // Flag: case sensitive + OutFile.Align(PageSize); // Align for first member + + // Allocate MemberPageIndex + MemberPageIndex.SetNum(Indexes.GetNumEntries()); + + // Insert members + for (MemberI = 0; MemberI < Indexes.GetNumEntries(); MemberI++) { + + // Find member in DataBuffer + MemberStart = Indexes[MemberI]; // Start of member in DataBuffer + if (MemberI+1 < Indexes.GetNumEntries()) { + // Not last member + MemberEnd = Indexes[MemberI+1]; // End of member in DataBuffer = start of next member + } + else { + // Last member + MemberEnd = DataBuffer.GetDataSize(); // End of member in DataBuffer = end of DataBuffer + } + + // Put member into output file + MemberOffset = OutFile.Push(DataBuffer.Buf() + MemberStart, MemberEnd - MemberStart); + + // Align next member + OutFile.Align(PageSize); + + // Member page index + MemberPageIndex[MemberI] = MemberOffset / PageSize; + } + + // Change member index to member page index in StringEntries + // Loop through StringEntries + for (SymbolI = 0; SymbolI < StringEntries.GetNumEntries(); SymbolI++) { + // Member index + MemberI = StringEntries[SymbolI].Member; + if (MemberI < MemberPageIndex.GetNumEntries()) { + // Change to member page + StringEntries[SymbolI].Member = MemberPageIndex[MemberI]; + } + } + + // Make OMF_LIBEND record + temp8 = OMF_LIBEND; + OutFile.Push(&temp8, 1); // Library header type byte + temp16 = PageSize - 3; // Length of rest of record + OutFile.Push(&temp16, 2); // Record length + OutFile.Align(PageSize); // Align + + // Offset to hash table + DictionaryOffset2 = OutFile.GetDataSize(); + + // Make hash table for public symbols + COMFHashTable HashTable; + HashTable.MakeHashTable(StringEntries, StringBuffer, OutFile, this); // Make hash table + + // Insert missing values in library header + // Hash table offset + OutFile.Get(3) = DictionaryOffset2; + + // Hash table size + OutFile.Get(7) = (OutFile.GetDataSize() - DictionaryOffset2) / OMFBlockSize; +} + + +void CLibrary::MakeBinaryFileUNIX() { + // Make UNIX library + // Combine string index and members into binary file + + // Reserve file buffer for output file + OutFile.SetSize(GetBufferSize()); + + if (cmd.OutputType == FILETYPE_COFF || cmd.OutputType == FILETYPE_ELF || cmd.OutputType == FILETYPE_MACHO_LE) { + // COFF, ELF and MAach-O libraries all use Unix-style archive with + // differences in symbol table format + + // Make symbol table + MakeSymbolTableUnix(); + + // Store all members + OutFile.Push(DataBuffer.Buf(), DataBuffer.GetDataSize()); + } + else { + err.submit(2501, GetFileFormatName(cmd.OutputType)); + } +} + + +void CLibrary::CheckOMFHash(CMemoryBuffer &stringbuf, CSList &index) { + // Check if OMF library hash table has correct entries for all symbol names + uint32 i; // Loop counter + int8 * Name; // Public symbol name + COMFHashTable HashTab; // OMF hash table interpreter + uint32 NString; // Number of occurrences of Name in hash table + uint32 Module; // Module with first occurrence of Name + uint32 Conf, ConfSum = 0; // Count number of conflicting entries in hash table + + // Initialize hash table interpreter + HashTab.Init(&Get(DictionaryOffset), DictionarySize); + + // Loop through public symbol names + for (i = 0; i < index.GetNumEntries(); i++) { + // Get public name + Name = stringbuf.Buf() + index[i].String; + // Make hash + HashTab.MakeHash(Name); + // Search for string + NString = HashTab.FindString(Module, Conf); + // Count conflicting strings + ConfSum += Conf; + + // Make error message if not 1 occurrence of Name + if (NString == 0) err.submit(2603, Name); // Error if not found + if (NString > 1) err.submit(1213, NString, Name); // Warning more than one occurrence + + //printf("\n%i occurence of %s, module offset %i", NString, Name, Module); + } + printf("\n\nHash table %i blocks x 37 buckets at offet 0x%X.\n Efficiency: %i conflicts for %i entries", + DictionarySize, DictionaryOffset, ConfSum, index.GetNumEntries()); +} + + +const char * CLibrary::GetModuleName(uint32 Index) { + // Get name of module from index (UNIX) or page index (OMF) + static char name[32]; + if (cmd.OutputType == FILETYPE_OMF || cmd.OutputType == FILETYPE_OMFLIBRARY) { + // Get name of module in OMF library + if (Index * PageSize < OutFile.GetDataSize() && OutFile.Get(Index * PageSize) == OMF_THEADR) { + SOMFRecordPointer rec; // Record pointer + rec.Start(OutFile.Buf(), Index * PageSize, OutFile.GetDataSize()); + if (rec.Type2 == OMF_THEADR) { + // Get module name from THEADR record + strncpy(name, rec.GetString(), 16); + // Make sure name is not too long + name[16] = 0; + // Return name + return name; + } + } + // No module starts here + return "?"; + } + // UNIX style library. + if (Index < Indexes.GetNumEntries()) { + // Get offset from Index + uint32 Offset = Indexes[Index]; + if (Offset < DataBuffer.GetDataSize()) { + // Copy name from header + memcpy(name, DataBuffer.Buf() + Offset, 16); + // Check for long name + if (strncmp(name, "#1/", 3) == 0) { + // Long name after record + memcpy(name, DataBuffer.Buf()+Offset+sizeof(SUNIXLibraryHeader), 16); + } + else if (name[0] == '/') { + // Long name in longnames record + uint32 NameIndex = atoi(name+1); + if (NameIndex < LongNamesSize) { + return LongNamesBuffer.Buf() + NameIndex; + } + else { + return "?"; + } + } + + // Find terminating '/' + for (int i = 0; i < 16; i++) if (name[i] == '/') name[i] = 0; + // Make sure name is not too long + name[16] = 0; + // return name + return name; + } + } + // Error + return "?"; +} diff --git a/programs/develop/objconv/library.h b/programs/develop/objconv/library.h new file mode 100644 index 0000000000..4a55c1a58e --- /dev/null +++ b/programs/develop/objconv/library.h @@ -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 &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 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 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 & 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 diff --git a/programs/develop/objconv/mac2asm.cpp b/programs/develop/objconv/mac2asm.cpp new file mode 100644 index 0000000000..eb3c9662ef --- /dev/null +++ b/programs/develop/objconv/mac2asm.cpp @@ -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 +CMAC2ASM::CMAC2ASM() { +} + +// Convert +template +void CMAC2ASM::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 +void CMAC2ASM::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 +void CMAC2ASM::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(SectOffset+SourceOffset); + // (this->Get doesn't work on Gnu compiler 4.0.1) + break; + case 2: + Inline = CMemoryBuffer::Get(SectOffset+SourceOffset); + break; + case 4: case 8: + Inline = CMemoryBuffer::Get(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 +void CMAC2ASM::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 +void CMAC2ASM::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; +template class CMAC2ASM; diff --git a/programs/develop/objconv/mac2elf.cpp b/programs/develop/objconv/mac2elf.cpp new file mode 100644 index 0000000000..ebd9f951d6 --- /dev/null +++ b/programs/develop/objconv/mac2elf.cpp @@ -0,0 +1,1267 @@ +/**************************** mac2elf.cpp ********************************* +* Author: Agner Fog +* Date created: 2008-05-15 +* Last modified: 2009-05-19 +* Project: objconv +* Module: mac2elf.cpp +* Description: +* Module for converting Mach-O file to ELF file +* +* Copyright 2008 GNU General Public License http://www.gnu.org/licenses +*****************************************************************************/ + +#include "stdafx.h" + + +template +CMAC2ELF::CMAC2ELF () { + // Constructor + memset(this, 0, sizeof(*this)); // Reset everything +} + + +template +void CMAC2ELF::Convert() { + // Do the conversion + // Some compilers require this-> for accessing members of template base class, + // according to the so-called two-phase lookup rule. + + NumSectionsNew = 5; // Number of sections generated so far + + // Allocate variable size buffers + MaxSectionsNew = NumSectionsNew + 2 * this->NumSections + 2;// Max number of sections needed + NewSections.SetNum(MaxSectionsNew+1); // Allocate buffers for each section + NewSections.SetZero(); // Initialize + NewSectionHeaders.SetNum(MaxSectionsNew+1); // Allocate array for temporary section headers + NewSectionHeaders.SetZero(); // Initialize + NewSectIndex.SetNum(this->NumSections+1); // Array for translating old section index to new section index + NewSectIndex.SetZero(); // Initialize + SectionSymbols.SetNum(this->MaxSectionsNew+1); // Array of new symbol indices for sections + SectionSymbols.SetZero(); // Initialize + NewSymbolIndex.SetNum(this->SymTabNumber); // Array of new symbol indices + NewSymbolIndex.SetZero(); // Initialize + + // Call the subfunctions + ToFile.SetFileType(FILETYPE_ELF); // Set type of to file + MakeSegments(); // Make segment headers and code/data segments + MakeSymbolTable(); // Symbol table and string tables + MakeRelocationTables(this->FileHeader); // Make relocation tables + MakeImportTables(); // Fill import tables + MakeGOT(); // Make fake Global Offset Table + MakeBinaryFile(); // Putting sections together + *this << ToFile; // Take over new file buffer +} + + +template +void CMAC2ELF::MakeSegments() { + // Convert subfunction: Make segment headers and code/data segments + TELF_SectionHeader NewSecHeader; // New section header + uint32 oldsec; // Section index in old file + uint32 newsec; // Section index in new file + uint32 SecNameIndex; // Section name index into shstrtab + char const * SecName; // Name of new section + const int MAXSECTIONNAMELENGTH = 256; + char RelocationSectionName[MAXSECTIONNAMELENGTH]; + const int WordSize = sizeof(MInt) * 8; + + // Special segment names + static const char * SpecialSegmentNames[] = { + "Null", ".symtab", ".shstrtab", ".strtab", ".stabstr" + }; + // Indexes to these are: + symtab = 1; // Symbol table section number + shstrtab = 2; // Section name string table section number + strtab = 3; // Object name string table section number + stabstr = 4; // Debug string table section number + + // Number of special segments = number of names in SpecialSegmentNames: + const uint32 NumSpecialSegments = sizeof(SpecialSegmentNames)/sizeof(SpecialSegmentNames[0]); + + // Make first section header string table entry empty + NewSections[shstrtab].PushString(""); + + // Loop through special sections, except the first Null section: + for (newsec = 0; newsec < NumSpecialSegments; newsec++) { + // Put data into new section header: + // Initialize to zero + memset(&NewSecHeader, 0, sizeof(NewSecHeader)); + + if (newsec > 0) { + // Put name into section header string table + SecName = SpecialSegmentNames[newsec]; + SecNameIndex = NewSections[shstrtab].PushString(SecName); + + // Put name into new section header + NewSecHeader.sh_name = SecNameIndex; + } + + // Put section header into temporary buffer + NewSectionHeaders[newsec] = NewSecHeader; + } + + // Put type, flags, etc. into special segments: + NewSectionHeaders[symtab] .sh_type = SHT_SYMTAB; + NewSectionHeaders[symtab] .sh_entsize = sizeof(TELF_Symbol); + NewSectionHeaders[symtab] .sh_link = strtab; + NewSectionHeaders[shstrtab].sh_type = SHT_STRTAB; + NewSectionHeaders[shstrtab].sh_flags = SHF_STRINGS; + NewSectionHeaders[shstrtab].sh_addralign = 1; + NewSectionHeaders[strtab] .sh_type = SHT_STRTAB; + NewSectionHeaders[strtab] .sh_flags = SHF_STRINGS; + NewSectionHeaders[strtab] .sh_addralign = 1; + NewSectionHeaders[stabstr] .sh_type = SHT_STRTAB; + NewSectionHeaders[stabstr] .sh_flags = SHF_STRINGS; + NewSectionHeaders[stabstr] .sh_addralign = 1; + + if (newsec != NumSectionsNew) { + // Check my program for internal consistency + // If you get this error then change the value of NumSectionsNew in + // the constructor to equal the number of entries in + // SpecialSegmentNames, including the Null segment + err.submit(9000); + } + + // Find sections in old file + uint32 icmd; // Current load command + uint32 command; // Load command + uint32 cmdsize = 0; // Command size + + // Pointer to current position in old file + uint8 * currentp = (uint8*)(this->Buf() + sizeof(TMAC_header)); + + // Loop through file commands + for (icmd = 1; icmd <= this->FileHeader.ncmds; icmd++, currentp += cmdsize) { + command = ((MAC_load_command*)currentp) -> cmd; + cmdsize = ((MAC_load_command*)currentp) -> cmdsize; + + if (command == MAC_LC_SEGMENT || command == MAC_LC_SEGMENT_64) { + // This is the segment command (there should be only one) + if ((command == MAC_LC_SEGMENT) ^ (WordSize == 32)) { + // 32-bit segment in 64-bit file or vice versa + err.submit(2320); return; + } + if (cmdsize < sizeof(TMAC_segment_command)) { + // Zero cmdsize or too small + err.submit(2321); return; + } + // Point to segment command + TMAC_segment_command * sh = (TMAC_segment_command*)currentp; + + if (stricmp(sh->segname, MAC_SEG_OBJC) == 0) { + // objective-C runtime segment + err.submit(2021); continue; + } + + // Find first section header + TMAC_section * sectp = (TMAC_section*)(currentp + sizeof(TMAC_segment_command)); + + // Loop through section headers + for (oldsec = 1; oldsec <= this->NumSections; oldsec++, sectp++) { + + // Get section name + SecName = sectp->sectname; + + // Check for special section names + if (stricmp(SecName,"__eh_frame") == 0) { + // This is an exception handler section + if (cmd.ExeptionInfo == CMDL_EXCEPTION_STRIP) { + // Remove exception handler section + cmd.CountExceptionRemoved(); + continue; + } + else if (cmd.InputType != cmd.OutputType) { + err.submit(1030); // Warn that exception information is incompatible + } + } + if (sectp->flags & MAC_S_ATTR_DEBUG) { + // This section has debug information + if (cmd.DebugInfo == CMDL_DEBUG_STRIP) { + // Remove debug info + cmd.CountDebugRemoved(); + continue; + } + else if (cmd.InputType != cmd.OutputType) { + err.submit(1029); // Warn that debug information is incompatible + } + } + + // Store section index in index translation table + NewSectIndex[oldsec] = newsec; + + // Store section data + if (sectp->size > 0 && !((sectp->flags & MAC_SECTION_TYPE) == MAC_S_ZEROFILL || (sectp->flags & MAC_SECTION_TYPE)==MAC_S_GB_ZEROFILL)) { + NewSections[newsec].Push(this->Buf()+sectp->offset, uint32(sectp->size)); + } + + // Put data into new section header: + // Initialize to zero + memset(&NewSecHeader, 0, sizeof(NewSecHeader)); + + uint32 type = sectp->flags & MAC_SECTION_TYPE; + uint32 attributes = sectp->flags & MAC_SECTION_ATTRIBUTES; + + // Section type + if (type == MAC_S_ZEROFILL || type == MAC_S_GB_ZEROFILL) { + // BSS section + NewSecHeader.sh_type = SHT_NOBITS; // BSS + } + else { + // Normal code or data section + NewSecHeader.sh_type = SHT_PROGBITS; // Program code or data + } + + // Section flags + NewSecHeader.sh_flags |= SHF_ALLOC; // Occupies memory during execution + if (attributes & (MAC_S_ATTR_SOME_INSTRUCTIONS | MAC_S_ATTR_PURE_INSTRUCTIONS)) { + // Executable + NewSecHeader.sh_flags |= SHF_EXECINSTR; + } + else { + switch (type) { + case MAC_S_CSTRING_LITERALS: + case MAC_S_4BYTE_LITERALS: + case MAC_S_8BYTE_LITERALS: + case MAC_S_16BYTE_LITERALS: + case MAC_S_LITERAL_POINTERS: + // not writeable + break; + default: + // writeable + NewSecHeader.sh_flags |= SHF_WRITE; + break; + } + } + + // Check for special sections + if (strcmp(SecName, MAC_CONSTRUCTOR_NAME) == 0) { + // Constructors segment + SecName = ELF_CONSTRUCTOR_NAME; + NewSecHeader.sh_flags = SHF_WRITE | SHF_ALLOC; + } + + // Put name into section header string table + SecNameIndex = NewSections[shstrtab].PushString(SecName); + + // Put name into new section header + NewSecHeader.sh_name = SecNameIndex; + + // Section virtual memory address + NewSecHeader.sh_addr = sectp->addr; + + // Section size in memory + NewSecHeader.sh_size = sectp->size; + + // Section alignment + NewSecHeader.sh_addralign = uint32(1 << sectp->align); + + // Put section header into temporary buffer + NewSectionHeaders[newsec] = NewSecHeader; + + // Increment section number + newsec++; + + // Check if section is import table + int SectionType = sectp->flags & MAC_SECTION_TYPE; + int IsImportTable = SectionType >= MAC_S_NON_LAZY_SYMBOL_POINTERS && SectionType <= MAC_S_SYMBOL_STUBS; + + if (sectp->nreloc > 0 || IsImportTable) { + // Source section has relocations. + // Make a relocation section in destination file + + // Put data into relocation section header: + // Initialize to zero + memset(&NewSecHeader, 0, sizeof(NewSecHeader)); + + // Name for relocation section = ".rel" or ".rela" + name of section + if (WordSize == 32) { + strcpy(RelocationSectionName, ".rel"); + } + else { + strcpy(RelocationSectionName, ".rela"); + } + strncat(RelocationSectionName, SecName, MAXSECTIONNAMELENGTH-5); + RelocationSectionName[MAXSECTIONNAMELENGTH-1] = 0; + + // Put name into section header string table + uint32 SecNameIndex = NewSections[shstrtab].PushString(RelocationSectionName); + + // Put name into new section header + NewSecHeader.sh_name = SecNameIndex; + + // Section type + NewSecHeader.sh_type = (WordSize == 32) ? SHT_REL : SHT_RELA; // Relocation section + + // Entry size + NewSecHeader.sh_entsize = (WordSize == 32) ? sizeof(Elf32_Rel) : sizeof(Elf64_Rela); // Relocation section + + // Section alignment + NewSecHeader.sh_addralign = WordSize / 8; + + // Link to the section it relocates for + NewSecHeader.sh_info = newsec - 1; + + // Put section header into temporary buffer + NewSectionHeaders[newsec] = NewSecHeader; + + // Increment section number + newsec++; + + // Check if there are any GOT relocations + // Pointer to old relocation entry + if (sectp->reloff >= this->GetDataSize()) {err.submit(2035); break;} + MAC_relocation_info * relp = (MAC_relocation_info*)(this->Buf() + sectp->reloff); + // Loop through old relocations + for (uint32 oldr = 1; oldr <= sectp->nreloc; oldr++, relp++) { + uint32 RType = relp->r_type; // relocation type + // No scattered relocation in 64-bit mode. GOT only in 64-bit mode + if (WordSize == 64 && (RType == MAC64_RELOC_GOT_LOAD || RType == MAC64_RELOC_GOT)) { + HasGOT++; + } + } + } + } + + // Check if GOT needed + if (HasGOT && WordSize == 64) { + // Make a fake Global Offset Table + FakeGOTSection = newsec; + + // Put name and data into section header + memset(&NewSecHeader, 0, sizeof(NewSecHeader)); + SecNameIndex = NewSections[shstrtab].PushString("_fakeGOT"); + NewSecHeader.sh_name = SecNameIndex; + NewSecHeader.sh_type = SHT_PROGBITS; // Type + NewSecHeader.sh_flags = SHF_ALLOC; // Flags + NewSecHeader.sh_addralign = 8; // Alignment + + // Put section header into temporary buffer + NewSectionHeaders[newsec++] = NewSecHeader; + + // Make relocation section for fake GOT + memset(&NewSecHeader, 0, sizeof(NewSecHeader)); + // Put name and data into section header + SecNameIndex = NewSections[shstrtab].PushString("_rela.fakeGOT"); + NewSecHeader.sh_name = SecNameIndex; + NewSecHeader.sh_type = SHT_RELA; // Type + NewSecHeader.sh_flags = 0; // Flags + NewSecHeader.sh_addralign = 8; // Alignment + NewSecHeader.sh_entsize = sizeof(Elf64_Rela); // Entry size + NewSecHeader.sh_info = newsec - 1; // Link to the section it relocates for + NewSecHeader.sh_link = symtab; // Link to symbol table + // Put section header into temporary buffer + NewSectionHeaders[newsec++] = NewSecHeader; + } + // Number of sections generated + NumSectionsNew = newsec; + } + } +} + + +template +void CMAC2ELF::MakeSymbolTable() { + // Convert subfunction: Make symbol table and string tables + uint32 isym; // current old symbol table entry + uint32 OldSectionIndex; // Index into old section table. 1-based + uint32 NewSectionIndex; // Index into new section table. 0-based + const char * name1; // Name of symbol + TELF_Symbol sym; // Temporary symbol table record + uint32 DebugRemoved = 0;// Debug symbols removed + + // pointer to old string table + char * oldstringtab = (char*)(this->Buf() + this->StringTabOffset); + + // pointer to old symbol table + TMAC_nlist * symp0, *symp; + symp0 = (TMAC_nlist*)(this->Buf() + this->SymTabOffset); + + // Check within range + if (this->SymTabOffset + this->SymTabNumber * sizeof(TMAC_nlist) > this->DataSize) { + err.submit(2040); return; + } + + // Make the first symbol record empty + NewSections[symtab].Push(0, sizeof(TELF_Symbol)); + + // Make first string table entries empty + NewSections[strtab] .PushString(""); + NewSections[stabstr].PushString(""); + + // Make symbol records for the start of each section in case they are needed + // by section-relative relocations (r_extern = 0 in MAC_relocation_info) + for (uint32 sec = 1; sec < NumSectionsNew; sec++) { + uint32 type = NewSectionHeaders[sec].sh_type; + if (type == SHT_PROGBITS || type == SHT_NOBITS) { + // Make unnamed symbol table entry for this section + memset(&sym, 0, sizeof(sym)); + sym.st_shndx = sec; + sym.st_type = STT_SECTION; + // Put record into new symbol table + NewSections[symtab].Push(&sym, sizeof(sym)); + // Insert into section symbol translation table + SectionSymbols[sec] = NewSections[symtab].GetLastIndex(); + } + } + + // Loop through old symbol table. Local symbols first, global symbols last + for (isym = 0, symp = symp0; isym < this->SymTabNumber; isym++, symp++) { + + if ((symp->n_type & MAC_N_STAB) && (cmd.DebugInfo & CMDL_DEBUG_STRIP)) { + // Debug symbol should be removed + DebugRemoved++; continue; + } + + // Reset destination entry + memset(&sym, 0, sizeof(sym)); + + // Get binding + if (isym < this->iextdefsym) { + // Local + sym.st_bind = STB_LOCAL; + } + else if (symp->n_desc & (MAC_N_WEAK_REF | MAC_N_WEAK_DEF)) { + // Weak public or weak external + sym.st_bind = STB_WEAK; + } + else { + // Global (public or external) + sym.st_bind = STB_GLOBAL; + } + + // Symbol name + if (symp->n_strx < this->StringTabSize) { + name1 = oldstringtab + symp->n_strx; + } + else { + err.submit(2112); break; + } + + // Symbol value + sym.st_value = symp->n_value; + + // Get section + OldSectionIndex = symp->n_sect; + if (OldSectionIndex > this->NumSections) { + err.submit(2016); break; + } + // Get new section index + NewSectionIndex = 0; + if (OldSectionIndex > 0) { + // Get new section index from translation table + NewSectionIndex = NewSectIndex[OldSectionIndex]; + // Change symbol address to section-relative + // (Also in 64-bit mode) + sym.st_value -= NewSectionHeaders[NewSectionIndex].sh_addr; + } + sym.st_shndx = (uint16)NewSectionIndex; + + if (OldSectionIndex && !NewSectionIndex) { + // Section has been removed. Remove symbol also + continue; + } + + // Check symbol type + int32 RefType = symp->n_desc & MAC_REF_TYPE; + if (RefType == MAC_REF_FLAG_UNDEFINED_LAZY || RefType == MAC_REF_FLAG_PRIVATE_UNDEFINED_LAZY) { + // Lazy binding + err.submit(1061, name1); + } + else if ((symp->n_type & MAC_N_TYPE) == MAC_N_ABS) { + // Absolute symbol + sym.st_type = STT_NOTYPE; + sym.st_shndx = (uint16)SHN_ABS; + if (sym.st_bind == STB_LOCAL) { + continue; // Remove absolute local symbol (not allowed in COFF) + } + } + else if (sym.st_shndx == 0) { // added by Vladimir 'phcoder' Serbinenko: + // This is an external + sym.st_type = STT_NOTYPE; + } + else { + // This is a data definition record + if (NewSectionHeaders[NewSectionIndex].sh_flags & SHF_EXECINSTR) { + // Code section, assume this is a function + sym.st_type = STT_FUNC; + } + else { + // This is a data object + sym.st_type = STT_OBJECT; + } + if (sym.st_bind == STB_GLOBAL && NewSectionIndex) { + // Symbol is public + // The size is not specified in Mac record, + // so we may give it an arbitrary size: + sym.st_size = 4; + } + } + + // Put symbol name into string table + if (name1 && *name1) { + sym.st_name = NewSections[strtab].PushString(name1); + } + + // Put record into new symbol table + NewSections[symtab].Push(&sym, sizeof(sym)); + + // Insert into symbol translation table + NewSymbolIndex[isym] = NewSections[symtab].GetLastIndex(); + + // Make index to first global symbol + if (isym >= this->iextdefsym && !NewSectionHeaders[symtab].sh_info) { + // This is the first global symbol + NewSectionHeaders[symtab].sh_info = NewSymbolIndex[isym]; + } + } +} + + +template +void CMAC2ELF::MakeRelocationTables(MAC_header_32&) { + // Convert subfunction: Relocation tables, 32-bit version + + uint32 oldsec; // Relocated section number in source file + uint32 newsec; // Relocated section number in destination file + uint32 newsecr; // Relocation table section number in destination file + MInt SectAddr; // Section address of relocation source + MInt SourceAddress; // Address of relocation source including section address + MInt TargetAddress; // Target address including section address + uint32 TargetSection; // New section index of relocation target + uint32 TargetOffset; // Section-relative offset of relocation target + uint32 RefAddress; // Reference point address including section address + uint32 RefSection; // New section index of reference point + uint32 RefOffset; // Section-relative offset of reference point + int32 * inlinep = 0; // Pointer to inline addend + //const int WordSize = sizeof(MInt) * 8; + + TELF_SectionHeader * NewRelTableSecHeader; // Section header for new relocation table + + // Number of symbols + uint32 NumSymbols = NewSections[symtab].GetNumEntries(); + + // New symbol table + //Elf32_Sym * NewSymbolTable = (Elf32_Sym *)(NewSections[symtab].Buf()); + + // Find first section header + MAC_section_32 * sectp = (MAC_section_32*)(this->Buf() + this->SectionHeaderOffset); + + // Loop through section headers + for (oldsec = 1; oldsec <= this->NumSections; oldsec++, sectp++) { + + if (sectp->nreloc > 0) { + // Source section has relocations + + // New section index + newsec = NewSectIndex[oldsec]; + + // Check that section has not been deleted + if (newsec > 0) { + + // Section address + SectAddr = NewSectionHeaders[newsec].sh_addr; + + // Finc new relocation table section + newsecr = newsec + 1; + if (newsecr >= NewSectionHeaders.GetNumEntries()) { + err.submit(9000); return;} + + // New relocation table section header + NewRelTableSecHeader = &NewSectionHeaders[newsecr]; + + // Check that we have allocated this as a relocation section + if (NewRelTableSecHeader->sh_info != newsec) { + err.submit(9000); return; + } + + // Insert header info + NewRelTableSecHeader->sh_type = SHT_REL; + NewRelTableSecHeader->sh_flags = 0; + NewRelTableSecHeader->sh_addralign = 4; + NewRelTableSecHeader->sh_link = symtab; // Point to symbol table + NewRelTableSecHeader->sh_info = newsec; // Point to relocated section + NewRelTableSecHeader->sh_entsize = sizeof(Elf32_Rel); // Entry size: + + // Pointer to old relocation entry + if (sectp->reloff >= this->GetDataSize()) {err.submit(2035); break;} + MAC_relocation_info * relp = (MAC_relocation_info*)(this->Buf() + sectp->reloff); + + // Loop through old relocations + for (uint32 oldr = 1; oldr <= sectp->nreloc; oldr++, relp++) { + + // Make new relocation entry and set to zero + Elf32_Rel NewRelocEntry; + + memset(&NewRelocEntry, 0, sizeof(NewRelocEntry)); + + if (relp->r_address & R_SCATTERED) { + // scattered relocation into + MAC_scattered_relocation_info * scatp = (MAC_scattered_relocation_info*)relp; + + // Address of source + NewRelocEntry.r_offset = scatp->r_address; + if (NewRelocEntry.r_offset >= NewSections[newsec].GetDataSize()) { + err.submit(2035); continue; // Out of range + } + // Pointer to inline addend + inlinep = (int32*)(NewSections[newsec].Buf() + NewRelocEntry.r_offset); + if (scatp->r_pcrel) { + // Self-relative scattered + if (scatp->r_type != MAC32_RELOC_VANILLA) { + err.submit(2030, scatp->r_type); continue; // Unexpected type + } + // Scattered, self-relative, vanilla + // Note: I have never seen this relocation method, so I have not + // been able to test it. I don't know for sure how it works and + // the documentation is poor. + SourceAddress = SectAddr + scatp->r_address; + + // Target address + TargetAddress = SourceAddress + *inlinep; + TranslateAddress(TargetAddress, TargetSection, TargetOffset); + if (TargetSection == 0) {err.submit(2031); continue;} // not found + NewRelocEntry.r_sym = SectionSymbols[TargetSection]; + if (NewRelocEntry.r_sym == 0) { + err.submit(2031); continue; // refers to non-program section + } + + // inline contains full relative address + // compensate by subtracting relative address to target section + *inlinep -= int32(NewSectionHeaders[TargetSection].sh_addr - SourceAddress); + // Relocation type + NewRelocEntry.r_type = R_386_PC32; + } + else if (scatp->r_type == MAC32_RELOC_VANILLA) { + // Scattered, absolute + TargetAddress = *inlinep; + TranslateAddress(TargetAddress, TargetSection, TargetOffset); + if (TargetSection == 0) { + err.submit(2031); continue;} // Target not found + NewRelocEntry.r_sym = SectionSymbols[TargetSection]; + *inlinep = TargetOffset; + NewRelocEntry.r_type = R_386_32; + if (scatp->r_length != 2) { + err.submit(2030, scatp->r_type); continue; // Only 32-bit supported + } + } + else if (scatp->r_type == MAC32_RELOC_SECTDIFF || scatp->r_type == MAC32_RELOC_LOCAL_SECTDIFF) { + // relative to arbitrary reference point + // check that next record is MAC32_RELOC_PAIR + if (oldr == sectp->nreloc || (scatp+1)->r_type != MAC32_RELOC_PAIR || scatp->r_length != 2) { + err.submit(2050); continue; + } + // Find target address and reference point + RefAddress = (scatp+1)->r_value; + TranslateAddress(RefAddress, RefSection, RefOffset); + TargetAddress = RefAddress + *inlinep; + TranslateAddress(TargetAddress, TargetSection, TargetOffset); + // Check that both points are found + if (RefSection == 0 || TargetSection == 0) { + err.submit(2031); oldr++; relp++; continue; + } + // Address relative to arbitrary reference point can be translated + // to self-relative address if reference point is in same section as source + if (RefSection != newsec) { + err.submit(2044); oldr++; relp++; continue; + } + // Translation is possible + // Get symbol for target section + NewRelocEntry.r_sym = SectionSymbols[TargetSection]; + // Make self-relative relocation + NewRelocEntry.r_type = R_386_PC32; + // Calculate compensating addend + *inlinep = TargetOffset + scatp->r_address - RefOffset; + // Linker will add (target section) - (source full address) to *inlinep, which gives + // (target full address) - (reference point full address) + // Advance pointers because we have used two records + oldr++; relp++; + } + else if (scatp->r_type == MAC32_RELOC_PB_LA_PTR) { + // procedure linkage table. Not supported + NewRelocEntry.r_type = R_386_PLT32; + err.submit(2043); + } + else { + // unknown scattered relocation type + err.submit(2030, scatp->r_type); continue; + } + } + else { + // Non scattered relocation info + // Section offset of relocated address + NewRelocEntry.r_offset = relp->r_address; + if (NewRelocEntry.r_offset >= NewSections[newsec].GetDataSize()) { + err.submit(2035); continue; // Out of range + } + // Pointer to inline addend + inlinep = (int32*)(NewSections[newsec].Buf() + NewRelocEntry.r_offset); + + if (relp->r_extern) { + // r_extern = 1: target indicated by symbol index + uint32 symold = relp->r_symbolnum; + if (symold >= this->SymTabNumber) { + err.submit(2031); continue; // index out of range + } + NewRelocEntry.r_sym = NewSymbolIndex[symold]; + if (relp->r_pcrel) { + // Self-relative. + // Inline contains -(source address) + // Add (source address) to compensate + *inlinep += int32(SectAddr + relp->r_address); + } + } + else { + // r_extern = 0. Target indicated by section + offset + // Old section number + uint32 secold = relp->r_symbolnum; + if (secold > this->NumSections) { + err.submit(2031); continue; // index out of range + } + TargetSection = NewSectIndex[secold]; + NewRelocEntry.r_sym = SectionSymbols[TargetSection]; + if (NewRelocEntry.r_sym == 0 || NewRelocEntry.r_sym > NumSymbols) { + err.submit(2031); continue; // refers to non-program section + } + if (relp->r_pcrel) { + // Self-relative. + // Inline contains (target address)-(source address) + // Subtract this to compensate + + // Target section address + TargetOffset = uint32(NewSectionHeaders[TargetSection].sh_addr); + SourceAddress = SectAddr + relp->r_address; + *inlinep -= int32(TargetOffset - SourceAddress); + } + else { + // Absolute reference + // Inline contains target address, convert to section:offset address + TranslateAddress(*inlinep, TargetSection, TargetOffset); + if (TargetSection == 0) { // Target not found + err.submit(2035); continue; + } + // Translate to section-relative address by subtracting target section address + *inlinep -= int32(NewSectionHeaders[TargetSection].sh_addr); + } + } + // relocation type (32-bit non-scattered) + switch (relp->r_type) { + case MAC32_RELOC_VANILLA: + // Normal relocation + if (relp->r_pcrel) { // self relative + NewRelocEntry.r_type = R_386_PC32; + } + else { // direct + NewRelocEntry.r_type = R_386_32; + } + break; + default: + err.submit(2030, relp->r_type); // unknown type + continue; + } + // size + if (relp->r_length != 2) { // wrong size + err.submit(2030,relp->r_type); + } + } + // Put relocation record into table + NewSections[newsecr].Push(&NewRelocEntry, sizeof(NewRelocEntry)); + } + } + } + } +} + + +template +void CMAC2ELF::MakeRelocationTables(MAC_header_64&) { + // Convert subfunction: Relocation tables, 64-bit version + + uint32 oldsec; // Relocated section number in source file + uint32 newsec; // Relocated section number in destination file + uint32 newsecr; // Relocation table section number in destination file + uint32 symold; // Old index of symbol + uint32 TargetSym; // Target symbol + uint32 TargetSection; // New section index of relocation target + uint32 RefSym; // Reference symbol + uint32 RefSection; // New section index of reference point + int64 RefOffset; // Section-relative offset of reference point + int64 SectAddr; // Address of current section + //const int WordSize = sizeof(MInt) * 8; // Word size, 32 or 64 bits + + TELF_SectionHeader * NewRelTableSecHeader; // Section header for new relocation table + + // Number of symbols + //uint32 NumSymbols = NewSections[symtab].GetNumEntries(); + + // New symbol table + Elf64_Sym * NewSymbolTable = (Elf64_Sym *)(NewSections[symtab].Buf()); + + // Find first section header + MAC_section_64 * sectp = (MAC_section_64*)(this->Buf() + this->SectionHeaderOffset); + + // Loop through section headers + for (oldsec = 1; oldsec <= this->NumSections; oldsec++, sectp++) { + + if (sectp->nreloc > 0) { + // Source section has relocations + + // New section index + newsec = NewSectIndex[oldsec]; + + // Check that section has not been deleted + if (newsec > 0) { + + // Section address + SectAddr = NewSectionHeaders[newsec].sh_addr; + + // Finc new relocation table section + newsecr = newsec + 1; + if (newsecr > NewSectionHeaders.GetNumEntries()) { + err.submit(9000); return; + } + + // New relocation table section header + NewRelTableSecHeader = &NewSectionHeaders[newsecr]; + + // Check that we have allocated this as a relocation section + if (NewRelTableSecHeader->sh_info != newsec) { + err.submit(9000); return; + } + + // Insert header info + NewRelTableSecHeader->sh_type = SHT_RELA; + NewRelTableSecHeader->sh_flags = 0; + NewRelTableSecHeader->sh_addralign = 8; + NewRelTableSecHeader->sh_link = symtab; // Point to symbol table + NewRelTableSecHeader->sh_info = newsec; // Point to relocated section + // Entry size: + NewRelTableSecHeader->sh_entsize = sizeof(Elf64_Rela); + + // Pointer to old relocation entry + if (sectp->reloff >= this->GetDataSize()) {err.submit(2035); break;} + MAC_relocation_info * relp = (MAC_relocation_info*)(this->Buf() + sectp->reloff); + + // Loop through old relocations + for (uint32 oldr = 1; oldr <= sectp->nreloc; oldr++, relp++) { + + // Make new relocation entry and set to zero + Elf64_Rela NewRelocEntry; + memset(&NewRelocEntry, 0, sizeof(NewRelocEntry)); + + // Pointer to inline addend + int32 * inlinep = 0; + + if (relp->r_address & R_SCATTERED) { + // scattered not allowed in 64-bit + err.submit(2030, ((MAC_scattered_relocation_info*)relp)->r_type); continue; + } + else { + // Non scattered relocation info + // Section offset of relocated address + NewRelocEntry.r_offset = relp->r_address; + if (NewRelocEntry.r_offset >= NewSections[newsec].GetDataSize()) { + err.submit(2035); continue; // Out of range + } + // Pointer to inline addend + inlinep = (int32*)(NewSections[newsec].Buf() + NewRelocEntry.r_offset); + + // Symbol index of target + symold = relp->r_symbolnum; + if (relp->r_extern) { + if (symold >= this->SymTabNumber) { + err.submit(2031); continue; // index out of range + } + NewRelocEntry.r_sym = NewSymbolIndex[symold]; + } + else { + // r_extern = 0, r_symbolnum = section + if (symold > NumSectionsNew) {err.submit(2031); continue;} + TargetSection = NewSectIndex[symold]; + NewRelocEntry.r_sym = SectionSymbols[TargetSection]; + if (relp->r_pcrel) { + // Self-relative. + // Inline contains (target address)-(source address) + // Subtract this to compensate + // Target section address + uint64 TargetSectAddr = NewSectionHeaders[TargetSection].sh_addr; + uint64 SourceAddress = SectAddr + relp->r_address; + *inlinep -= int32(TargetSectAddr - SourceAddress); + *inlinep += 4; // Compensate for subtracting 4 below + } + } + + // Find relocation type + switch (relp->r_type) { + case MAC64_RELOC_UNSIGNED: // absolute address, 32 or 64 bits + if (relp->r_length == 2) { + NewRelocEntry.r_type = R_X86_64_32S; // 32 bit signed + } + else if (relp->r_length == 3) { + NewRelocEntry.r_type = R_X86_64_64; // 64 bit + } + else { + err.submit(2030,relp->r_type); continue; + } + break; + case MAC64_RELOC_SIGNED: // rip-relative, implicit addend = -4 + case MAC64_RELOC_BRANCH: // rip-relative, implicit addend = -4 + case MAC64_RELOC_SIGNED_1: // implicit addend = -4, not -5 + case MAC64_RELOC_SIGNED_2: // implicit addend = -4, not -6 + case MAC64_RELOC_SIGNED_4: // implicit addend = -4, not -8 + // These are all the same: + // signed 32-bit rip-relative with implicit -4 addend + if (relp->r_length != 2) { // wrong size + err.submit(2030,relp->r_type); continue; + } + NewRelocEntry.r_type = R_X86_64_PC32; + // ELF = self-relative, Mac64 = rip-relative. Compensate for difference + *inlinep -= 4; + break; + case MAC64_RELOC_SUBTRACTOR: + // relative to arbitrary reference point + // must be followed by a X86_64_RELOC_UNSIGNED + // check that next record is MAC64_RELOC_UNSIGNED + if (oldr == sectp->nreloc || (relp+1)->r_type != MAC64_RELOC_UNSIGNED) { + err.submit(2050); continue; + } + // Reference symbol + RefSym = NewRelocEntry.r_sym; + RefSection = NewSymbolTable[RefSym].st_shndx; + RefOffset = NewSymbolTable[RefSym].st_value; + + // Target symbol + symold = (relp+1)->r_symbolnum; + if (symold >= this->SymTabNumber) { + err.submit(2031); continue; // index out of range + } + TargetSym = NewSymbolIndex[symold]; + NewRelocEntry.r_sym = TargetSym; + + // Address relative to arbitrary reference point can be translated + // to self-relative address if reference point is in same section as source + if (RefSection != newsec) { + err.submit(2044); oldr++; relp++; continue; + } + if (relp->r_length == 2) { + *inlinep += int32(NewRelocEntry.r_offset) - int32(RefOffset); + } + else if (relp->r_length == 3) { + *(int64*)inlinep += NewRelocEntry.r_offset - RefOffset; + // there is no 64-bit self-relative relocation in ELF, + // use 32-bit self-relative and hope there is no carry + err.submit(1302); // Warn. This will fail if inline value changes sign + } + else { + err.submit(2044); // wrong size + } + // self-relative type + NewRelocEntry.r_type = R_X86_64_PC32; + + // increment counters because we used two records + relp++; oldr++; + break; + + case MAC64_RELOC_GOT_LOAD: // a rip-relative load of a GOT entry + *inlinep = -4; + // Continue into next case + case MAC64_RELOC_GOT: // other GOT references + // Make fake GOT entry + //NewRelocEntry.r_addend = MakeGOTEntry(NewRelocEntry.r_sym) - 4; + *inlinep += MakeGOTEntry(NewRelocEntry.r_sym); + NewRelocEntry.r_sym = FakeGOTSymbol; + NewRelocEntry.r_type = R_X86_64_PC32; + break; + } + } + + // Put relocation record into table + NewSections[newsecr].Push(&NewRelocEntry, sizeof(NewRelocEntry)); + } + } + } + } +} + + +template +void CMAC2ELF::MakeBinaryFile() { + // Convert subfunction: Make section headers and file header, + // and combine everything into a single memory buffer. + uint32 newsec; // Section index + uint32 SecOffset; // Section offset in file + uint32 SecSize; // Section size in file + uint32 SectionHeaderOffset; // File offset to section headers + const int WordSize = sizeof(MInt) * 8; + + // Set file type in ToFile + ToFile.SetFileType(FILETYPE_ELF); + + // Make space for file header in ToFile, but don't fill data into it yet + ToFile.Push(0, sizeof(TELF_Header)); + + // Loop through new section buffers + for (newsec = 0; newsec < NumSectionsNew; newsec++) { + + // Size of section + SecSize = NewSections[newsec].GetDataSize(); + + // Put section into ToFile + SecOffset = ToFile.Push(NewSections[newsec].Buf(), SecSize); + + // Put size and offset into section header + NewSectionHeaders[newsec].sh_offset = SecOffset; + if (SecSize) { // Don't set size of BSS sections to zero + NewSectionHeaders[newsec].sh_size = SecSize; + } + + // Align before next entry + ToFile.Align(16); + } + + // Start offset of section headers + SectionHeaderOffset = ToFile.GetDataSize(); + + // Loop through new section headers + for (newsec = 0; newsec < NumSectionsNew; newsec++) { + + // Put section header into ToFile + ToFile.Push(&NewSectionHeaders[newsec], sizeof(TELF_SectionHeader)); + } + + // Make file header + TELF_Header FileHeader; + memset(&FileHeader, 0, sizeof(FileHeader)); // Initialize to 0 + + // Put file type magic number in + strcpy((char*)(FileHeader.e_ident), ELFMAG); + // File class + FileHeader.e_ident[EI_CLASS] = (WordSize == 32) ? ELFCLASS32 : ELFCLASS64; + // Data Endian-ness + FileHeader.e_ident[EI_DATA] = ELFDATA2LSB; + // ELF version + FileHeader.e_ident[EI_VERSION] = EV_CURRENT; + // ABI + FileHeader.e_ident[EI_OSABI] = ELFOSABI_SYSV; + // ABI version + FileHeader.e_ident[EI_ABIVERSION] = 0; + // File type + FileHeader.e_type = ET_REL; + // Machine architecture + FileHeader.e_machine = (WordSize == 32) ? EM_386 : EM_X86_64; + // Version + FileHeader.e_version = EV_CURRENT; + // Flags + FileHeader.e_flags = 0; + + // Section header table offset + FileHeader.e_shoff = SectionHeaderOffset; + + // File header size + FileHeader.e_ehsize = sizeof(TELF_Header); + + // Section header size + FileHeader.e_shentsize = sizeof(TELF_SectionHeader); + + // Number of section headers + FileHeader.e_shnum = (uint16)NumSectionsNew; + + // Section header string table index + FileHeader.e_shstrndx = (uint16)shstrtab; + + // Put file header into beginning of ToFile where we made space for it + memcpy(ToFile.Buf(), &FileHeader, sizeof(FileHeader)); +} + +template +void CMAC2ELF::MakeImportTables() { + // Convert subfunction: Fill import tables + uint32 oldsec; // Old section number + uint32 Type; // Old section type + uint32 NumEntries; // Number of entries in import table + uint32 EntrySize; // Entry size of import table + uint32 NewSec1; // New section number of import table + uint32 NewSec2; // New section number of relocation for import table + uint32 Offset; // Offset of relocation source + uint32 OldSymbol; // Old symbol number of import + uint32 i; // Loop counter + uint32 * IndSymTab; // Pointer to indirect symbol table + uint32 IndSymi; // Index into indirect symbol table + uint32 IndSymNum; // Number of entries in indirect symbol table + TELF_Relocation NewRelocEntry; // New relocation entry + const int WordSize = sizeof(MInt) * 8; + + // Machine code of jmp instruction + static const int8 JmpInstruction[5] = {int8(0xE9), int8(0xFC), int8(0xFF), int8(0xFF), int8(0xFF)}; + + // Number of indirect symbols + IndSymNum = this->IndirectSymTabNumber; + if (IndSymNum == 0) { + return; // No indirect symbols + } + // Find indirect symbol table + IndSymTab = (uint32*)(this->Buf() + this->IndirectSymTabOffset); + + // Find first section header + TMAC_section * sectp = (TMAC_section*)(this->Buf() + this->SectionHeaderOffset); + + // Loop through section headers + for (oldsec = 1; oldsec <= this->NumSections; oldsec++, sectp++) { + // Search for import tables + Type = sectp->flags & MAC_SECTION_TYPE; + if (Type >= MAC_S_NON_LAZY_SYMBOL_POINTERS && Type <= MAC_S_SYMBOL_STUBS) { + // This is an import table + + // Indirect symbol table first entry + IndSymi = sectp->reserved1; + + // Entry size: + EntrySize = sectp->reserved2; + if (EntrySize == 0) EntrySize = WordSize / 8; + + // Find new section + NewSec1 = NewSectIndex[oldsec]; + NumEntries = uint32(NewSectionHeaders[NewSec1].sh_size) / EntrySize; + + // Find new relocation section + NewSec2 = NewSec1 + 1; + if (NewSectionHeaders[NewSec2].sh_type != SHT_REL && NewSectionHeaders[NewSec2].sh_type != SHT_RELA) { + err.submit(9000); // This should be a relocation section + } + NewSectionHeaders[NewSec2].sh_link = symtab; // Point to symbol table + + // Offset of first relocation + Offset = EntrySize & 1; // 1 if EntrySize = 5, otherwise 0 + + // Loop through entries + for (i = 0; i < NumEntries; i++, Offset += EntrySize) { + // Find symbol + if (IndSymi >= IndSymNum) { + err.submit(1303); break; // Import symbol table exhausted + } + OldSymbol = IndSymTab[IndSymi]; + if (OldSymbol >= this->SymTabNumber) { + err.submit(1052); break; + } + // Increment pointer to import symbol table + IndSymi++; + + // Make relocation record + memset(&NewRelocEntry, 0, sizeof(NewRelocEntry)); + NewRelocEntry.r_offset = Offset; + if (WordSize == 32) { + if (EntrySize == 4) { + NewRelocEntry.r_type = R_386_32; + } + else if (EntrySize == 5) { + NewRelocEntry.r_type = R_386_PC32; + } + else { + err.submit(2045); + } + } + else { // 64 bit + if (EntrySize == 8) { + NewRelocEntry.r_type = R_X86_64_64; + } + else if (EntrySize == 5) { + NewRelocEntry.r_type = R_X86_64_PC32; + } + else { + err.submit(2045); + } + } + NewRelocEntry.r_sym = NewSymbolIndex[OldSymbol]; + + // Store relocation record + NewSections[NewSec2].Push(&NewRelocEntry, (WordSize==32) ? sizeof(Elf32_Rel) : sizeof(Elf64_Rela)); + + // Insert jmp instruction if EntrySize = 5 + if (EntrySize == 5) { + if (Offset -1 + EntrySize > NewSections[NewSec1].GetDataSize()) { + err.submit(9000); // Outside section + } + memcpy(NewSections[NewSec1].Buf()+Offset-1, JmpInstruction, 5); + } + } + } + } +} + + +template +void CMAC2ELF::TranslateAddress(MInt addr, uint32 & section, uint32 & offset) { + // Translate 32-bit address to section + offset + // (Sections are not necessarily ordered by address) + uint32 sec; + MInt secstart; + for (sec = 1; sec < NumSectionsNew; sec++) { + secstart = NewSectionHeaders[sec].sh_addr; + if (addr >= secstart && addr < secstart + MInt(NewSectionHeaders[sec].sh_size)) { + // Section found + section = sec; + offset = uint32(addr - secstart); + return; + } + } + // Not found + section = offset = 0; +} + +template +uint32 CMAC2ELF::MakeGOTEntry(int symbol) { + // Make entry in fake GOT for symbol + uint32 NumGOTEntries = GOTSymbols.GetNumEntries(); + uint32 symi; // Symbol index + const int WordSize = sizeof(MInt) * 8; + + // Get symbol for start of GOT + FakeGOTSymbol = SectionSymbols[FakeGOTSection]; + + // Search for symbol in previous entries + for (symi = 0; symi < NumGOTEntries; symi++) { + if (GOTSymbols[symi] == symbol) break; + } + if (symi == NumGOTEntries) { + // Not found. Make new entry + GOTSymbols.Push(symbol); + } + return symi * (WordSize / 8); +} + + +template +void CMAC2ELF::MakeGOT() { + // Make fake Global Offset Table + const int WordSize = sizeof(MInt) * 8; + if (!HasGOT) return; + + uint32 NumEntries = GOTSymbols.GetNumEntries(); + NewSections[FakeGOTSection].Push(0, NumEntries*(WordSize/8)); + + // Make relocations for GOT + Elf64_Rela NewRelocEntry; + memset(&NewRelocEntry, 0, sizeof(NewRelocEntry)); + + for (uint32 i = 0; i < NumEntries; i++) { + NewRelocEntry.r_offset = i * (WordSize/8); + NewRelocEntry.r_sym = GOTSymbols[i]; + NewRelocEntry.r_type = R_X86_64_64; + NewSections[FakeGOTSection+1].Push(&NewRelocEntry, sizeof(NewRelocEntry)); + } +} + + +// Make template instances for 32 and 64 bits +template class CMAC2ELF; +template class CMAC2ELF; diff --git a/programs/develop/objconv/mac2mac.cpp b/programs/develop/objconv/mac2mac.cpp new file mode 100644 index 0000000000..5494a46082 --- /dev/null +++ b/programs/develop/objconv/mac2mac.cpp @@ -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 +CMAC2MAC::CMAC2MAC() { + // Initialize everything + memset(this, 0, sizeof(*this)); +} + + +// Convert() +template +void CMAC2MAC::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 +void CMAC2MAC::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 +int CMAC2MAC::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 +uint32 CMAC2MAC::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 +void CMAC2MAC::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 +void CMAC2MAC::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 +void CMAC2MAC::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 +void CMAC2MAC::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; +template class CMAC2MAC; diff --git a/programs/develop/objconv/macho.cpp b/programs/develop/objconv/macho.cpp new file mode 100644 index 0000000000..5dbf272e6a --- /dev/null +++ b/programs/develop/objconv/macho.cpp @@ -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 +CMACHO::CMACHO() { + // Set everything to zero + memset(this, 0, sizeof(*this)); +} + +template +void CMACHO::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 +void CMACHO::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 +void CMACHO::PublicNames(CMemoryBuffer * Strings, CSList * 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 +MacSymbolTableBuilder::MacSymbolTableBuilder() { // Constructor + sorted = 0; +} + +template +void MacSymbolTableBuilder::AddSymbol(int OldIndex, const char * name, int type, int Desc, int section, MInt value) { + // Add symbol to list + MacSymbolRecord 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 +void MacSymbolTableBuilder::SortList() { + // Sort the list + if (sorted) return; // allready sorted + + MacSymbolRecord * p = (MacSymbolRecord*)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 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 +int MacSymbolTableBuilder::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 * p = (MacSymbolRecord*)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 +void MacSymbolTableBuilder::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 * p = (MacSymbolRecord*)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 +int MacSymbolTableBuilder::Search(const char * name) { + // Search for name. Return -1 if not found. + MacSymbolRecord * p = (MacSymbolRecord*)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 +MacSymbolRecord & MacSymbolTableBuilder::operator[] (uint32 i) { + // Access member + uint32 Offset = i * sizeof(MacSymbolRecord); + if (i + sizeof(MacSymbolRecord) > this->GetDataSize()) { + err.submit(9003); Offset = 0; + } + return Get >(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(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(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; +template class CMACHO; +template class MacSymbolTableBuilder; +template class MacSymbolTableBuilder; diff --git a/programs/develop/objconv/macho.h b/programs/develop/objconv/macho.h new file mode 100644 index 0000000000..73e5da5173 --- /dev/null +++ b/programs/develop/objconv/macho.h @@ -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 . + */ +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 + * and . */ + +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 + 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 + 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 */ + +// 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 +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 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 & 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 diff --git a/programs/develop/objconv/main.cpp b/programs/develop/objconv/main.cpp new file mode 100644 index 0000000000..11a0cf514f --- /dev/null +++ b/programs/develop/objconv/main.cpp @@ -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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 + } + } +} diff --git a/programs/develop/objconv/maindef.h b/programs/develop/objconv/maindef.h new file mode 100644 index 0000000000..cdb70d2ecf --- /dev/null +++ b/programs/develop/objconv/maindef.h @@ -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 +#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 + //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/ + +// 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; ia == 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 diff --git a/programs/develop/objconv/omf.cpp b/programs/develop/objconv/omf.cpp new file mode 100644 index 0000000000..eb309d642e --- /dev/null +++ b/programs/develop/objconv/omf.cpp @@ -0,0 +1,1065 @@ +/**************************** omf.cpp ********************************* +* Author: Agner Fog +* Date created: 2007-01-29 +* Last modified: 2018-05-26 +* Project: objconv +* Module: omf.cpp +* Description: +* Module for reading OMF files +* +* Class COMF is used for reading, interpreting and dumping OMF files. +* +* Copyright 2007-2018 GNU General Public License http://www.gnu.org/licenses +*****************************************************************************/ +#include "stdafx.h" + +// OMF Record type names +SIntTxt OMFRecordTypeNames[] = { + {OMF_THEADR, "Translator Header"}, + {OMF_LHEADR, "Library Module Header"}, + {OMF_COMENT, "Comment"}, + {OMF_MODEND, "Module End"}, + {OMF_EXTDEF, "External Names Definition"}, + {OMF_PUBDEF, "Public Names Definition"}, + {OMF_LINNUM, "Line Numbers"}, + {OMF_LNAMES, "List of Names"}, + {OMF_SEGDEF, "Segment Definition"}, + {OMF_GRPDEF, "Group Definition"}, + {OMF_FIXUPP, "Fixup"}, + {OMF_LEDATA, "Enumerated Data"}, + {OMF_LIDATA, "Iterated Data"}, + {OMF_COMDEF, "Communal Names Definition"}, + {OMF_BAKPAT, "Backpatch"}, + {OMF_LEXTDEF, "Local External Names"}, + {OMF_LPUBDEF, "Local Public Names"}, + {OMF_LCOMDEF, "Local Communal Names"}, + {OMF_CEXTDEF, "COMDAT External Names"}, + {OMF_COMDAT, "Initialized Communal Data"}, + {OMF_LINSYM, "Symbol Line Numbers"}, + {OMF_ALIAS, "Alias Definition"}, + {OMF_NBKPAT, "Named Backpatch"}, + {OMF_LLNAMES, "Local Logical Names"}, + {OMF_VERNUM, "OMF Version Number"}, + {OMF_VENDEXT, "Vendor-specific OMF Extension"}, + {OMF_LIBHEAD, "Library Header"}, + {OMF_LIBEND, "Library End"} +}; + +// Segment combination names +SIntTxt OMFSegmentCombinationNames[] = { + {0, "Private"}, + {1, "Invalid"}, + {2, "Public"}, + {3, "Invalid"}, + {4, "Public 4"}, + {5, "Stack"}, + {6, "Common"}, + {7, "Public 7"} +}; + +// Relocation mode names +static SIntTxt OMFRelocationModeNames[] = { + {0, "Relatv"}, + {1, "Direct"} +}; + + +// Fixup location names +static SIntTxt OMFFixupLocationNames[] = { + {OMF_Fixup_8bit, "8 bit"}, // 0 + {OMF_Fixup_16bit, "16 bit"}, // 1 + {OMF_Fixup_Segment, "segment selector, 16 bit"}, // 2 + {OMF_Fixup_Far, "far pointer 16+16 bit"}, // 3 + {OMF_Fixup_Hi8bit, "high 8 bit of 16 bits"}, // 4 + {OMF_Fixup_16bitLoader, "16 bit loader resolved"}, // 5 + {OMF_Fixup_Pharlab48, "farword 48 bit, Pharlab only"},// 6 + {OMF_Fixup_32bit, "32 bit"}, // 9 + {OMF_Fixup_Farword, "farword 32+16 bit"}, // 11 + {OMF_Fixup_32bitLoader, "32 bit loader resolved"} // 13 +}; + +// Alignment value translation table +static const uint32 OMFAlignTranslate[8] = {0,1,2,16,256,4,0,0}; + + +// Class COMF members: +// Constructor + +COMF::COMF() { + // Default constructor + memset(this, 0, sizeof(*this)); // reset everything +} + + +void COMF::ParseFile() { + // Parse file buffer + //uint8 RecordType; // Type of current record + uint32 Checksum; // Record checksum + uint32 ChecksumZero = 0; // Count number of records with zero checksum + SOMFRecordPointer rec; // Current record pointer + + // Make first entry zero in name lists + LocalNameOffset.PushZero(); + SegmentNameOffset.PushZero(); + GroupNameOffset.PushZero(); + SymbolNameOffset.PushZero(); + + // Initialize record pointer + rec.Start(Buf(), 0, GetDataSize()); + + // Loop through records to set record pointers and store names + do { + // Read record + //RecordType = rec.Type2; // First byte of record = type + + // Compute checksum + Checksum = 0; rec.Index = 0; + while (rec.Index < rec.End) Checksum += rec.GetByte(); + uint32 CheckByte = rec.GetByte(); + if ((Checksum + CheckByte) & 0xFF) { + // Checksum failed + if (CheckByte == 0) { + ChecksumZero++; + } + else err.submit(1202); // Checksum error + } + + // Store record pointer + rec.Index = 3; // Offset to current byte while parsing + Records.Push(rec); // Store record pointer in list + + if (rec.Type2 == OMF_LNAMES) { + // LNAMES record. Store local names by name index + // Loop through strings in record + while (rec.Index < rec.End) { + char * LocalName = rec.GetString(); + uint32 LocalNameIndex = NameBuffer.PushString(LocalName); // Store local name + LocalNameOffset.Push(LocalNameIndex);// Store local name index + } + if (rec.Index != rec.End) err.submit(1203); // Check for consistency + } + + if (rec.Type2 == OMF_SEGDEF) { + // SEGDEF record. Store segment names by segment index + OMF_SAttrib Attributes; + if (rec.Type2 == OMF_SEGDEF) { + Attributes.b = rec.GetByte(); // Read attributes + if (Attributes.u.A == 0) { + // Frame and Offset only included if A = 0 + rec.GetWord(); rec.GetByte(); + } + rec.GetNumeric(); // Length + } + uint32 NameIndex = rec.GetIndex(); + if (NameIndex < LocalNameOffset.GetNumEntries()) { + SegmentNameOffset.Push(LocalNameOffset[NameIndex]); // List by segment index + } + } + + if (rec.Type2 == OMF_GRPDEF) { + // GRPDEF record. Store group name + uint32 NameIndex = rec.GetIndex(); + if (NameIndex < LocalNameOffset.GetNumEntries()) { + GroupNameOffset.Push(LocalNameOffset[NameIndex]); // List by group index + } + } + + if (rec.Type2 == OMF_EXTDEF) { + // EXTDEF record. Store external symbol names + // Loop through strings in record + while (rec.Index < rec.End) { + char * symbolname = rec.GetString(); + rec.GetIndex(); + uint32 SymbolNameIndex = NameBuffer.PushString(symbolname); // Store external name + SymbolNameOffset.Push(SymbolNameIndex); // Save in name index table + } + if (rec.Index != rec.End) err.submit(1203); // Check for consistency + } + + if (rec.Type2 == OMF_CEXTDEF) { + // CEXTDEF record. Store communal symbol names + // Loop through entries in record + uint32 SymbolNameIndex; // Index into NameBuffer + while (rec.Index < rec.End) { + uint32 LIndex = rec.GetIndex(); // Index into preceding LNAMES + rec.GetIndex(); // Type index. Ignore + // Get name from LocalNameOffset and put into SymbolNameOffset. + if (LIndex < LocalNameOffset.GetNumEntries()) { + SymbolNameIndex = LocalNameOffset[LIndex]; + } + else SymbolNameIndex = 0; + SymbolNameOffset.Push(SymbolNameIndex); // Save in name index table + } + if (rec.Index != rec.End) err.submit(1203); // Check for consistency + } + } // Point to next record + while (rec.GetNext()); // End of loop through records + + NumRecords = Records.GetNumEntries(); // Number of records + + if (ChecksumZero) printf("\nChecksums are zero"); // This is taken out of the loop to report it only once +} + + +void COMF::Dump(int options) { + // Dump file + if (options & DUMP_FILEHDR) DumpRecordTypes(); // Dump summary of record types + + if (options & DUMP_STRINGTB) DumpNames(); // Dump names records + + if (options & DUMP_SYMTAB) DumpSymbols(); // Dump public/external name records + + if (options & DUMP_SECTHDR) DumpSegments(); // Dump segment records + + if (options & DUMP_RELTAB) DumpRelocations(); // Dump fixup records + + if (options & DUMP_COMMENT) DumpComments(); // Dump coment records +} + +void COMF::DumpRecordTypes() { + // Dump summary of records + printf("\nSummary of records:"); + for (uint32 i = 0; i < NumRecords; i++) { + // Print record type + printf("\n Record %02X, %s%s, total length %i", Records[i].Type, + Lookup(OMFRecordTypeNames, Records[i].Type2), + (Records[i].Type & 1) ? ".32" : "", + Records[i].End+1); + } +} + + +void COMF::DumpNames() { + // Dump local names records + uint32 i; // Record index + uint32 ln = 0; // Local name index + printf("\n\nLocal names:"); + for (i = 0; i < NumRecords; i++) { + if (Records[i].Type2 == OMF_LNAMES) { + // LNAMES record. There should be only one + // Loop through strings in record + while (Records[i].Index < Records[i].End) { + printf("\n %2i %s", ++ln, Records[i].GetString()); + } + if (Records[i].Index != Records[i].End) err.submit(1203); // Check for consistency + } + + if (Records[i].Type2 == OMF_THEADR || Records[i].Type2 == OMF_LHEADR) { + // Module header record + // Loop through strings in record + while (Records[i].Index < Records[i].End) { + printf("\n Module: %s\n", Records[i].GetString()); + } + if (Records[i].Index != Records[i].End) err.submit(1203); // Check for consistency + } + if (Records[i].Type2 == OMF_COMDEF) { + // COMDEF record. Communal names + uint32 DType, DSize, DNum; + printf("\n\n Communal names:"); + + // Loop through strings in record + while (Records[i].Index < Records[i].End) { + printf("\n \"%s\":", Records[i].GetString()); + printf(" %i", Records[i].GetByte()); // Type index, should be 0 + DType = Records[i].GetByte(); // Data type + switch (DType) { + case 0x61: + DNum = Records[i].GetLength(); + DSize = Records[i].GetLength(); + printf(" FAR: %i*%i bytes", DNum, DSize); + break; + case 0x62: + DSize = Records[i].GetLength(); + printf(" NEAR: 0x%X bytes", DSize); + break; + default: + DSize = Records[i].GetLength(); + if (DType < 0x60) { // Borland segment index + printf(" segment %i, size 0x%X", DType, DSize); + break; + } + printf(" unknown type %i, size 0x%X", DType, DSize); + break; + } + } + if (Records[i].Index != Records[i].End) err.submit(1203); // Check for consistency + } + } +} + +void COMF::DumpSymbols() { + // Dump public, external and communal names records + uint32 i; // Record index + uint32 xn = 0; // External name index + char * string; + uint32 TypeIndex; + uint32 Group; + uint32 Segment; + uint32 BaseFrame; + uint32 Offset; + + for (i = 0; i < NumRecords; i++) { + if (Records[i].Type2 == OMF_EXTDEF) { + // EXTDEF record. + Records[i].Index = 3; + printf("\n\nExternal names:"); + + // Loop through strings in record + while (Records[i].Index < Records[i].End) { + string = Records[i].GetString(); + TypeIndex = Records[i].GetIndex(); + printf("\n %2i %s, Type %i", ++xn, string, TypeIndex); + } + if (Records[i].Index != Records[i].End) err.submit(1203); // Check for consistency + } + + if (Records[i].Type2 == OMF_PUBDEF) { + // PUBDEF record. + printf("\n\nPublic names:"); + Records[i].Index = 3; + Group = Records[i].GetIndex(); + Segment = Records[i].GetIndex(); + BaseFrame = 0; + if (Segment == 0) BaseFrame = Records[i].GetWord(); + // Loop through strings in record + while (Records[i].Index < Records[i].End) { + string = Records[i].GetString(); + Offset = Records[i].GetNumeric(); + TypeIndex = Records[i].GetIndex(); + printf("\n %s, Segment %s, Group %s, Offset 0x%X, Type %i", + string, GetSegmentName(Segment), GetGroupName(Group), Offset, TypeIndex); + if (BaseFrame) printf(", Frame %i", BaseFrame); + } + if (Records[i].Index != Records[i].End) err.submit(1203); // Check for consistency + } + + if (Records[i].Type2 == OMF_CEXTDEF) { + // CEXTDEF record. + printf("\n\nCommunal names:"); + Records[i].Index = 3; + while (Records[i].Index < Records[i].End) { + uint32 LIndex = Records[i].GetIndex(); // Index into preceding LNAMES + uint32 Type = Records[i].GetIndex(); // Type index. Ignored + printf("\n %2i %s, Type %i", ++xn, GetLocalName(LIndex), Type); + } + if (Records[i].Index != Records[i].End) err.submit(1203); // Check for consistency + } + } +} + + +void COMF::DumpSegments() { + // Dump all segment records + + // Define structure of attributes + OMF_SAttrib Attributes; + + // Record values + uint32 Frame, Offset, SegLength, NameIndex, ClassIndex, OverlayIndex; + + uint32 i; // Record number + uint32 SegNum = 0; // Segment number + + printf("\n\nSegment 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) { + Attributes.b = Records[i].GetByte(); // Read attributes + if (Attributes.u.A == 0) { + // Frame and Offset only included if A = 0 + Frame = Records[i].GetWord(); Offset = Records[i].GetByte(); + } + else Frame = Offset = 0; + SegLength = Records[i].GetNumeric(); + NameIndex = Records[i].GetIndex(); + ClassIndex = Records[i].GetIndex(); + OverlayIndex = Records[i].GetIndex(); + + printf("\n Segment %2i, Name %s, Class %s, Align %i, %s, %i bit", + ++SegNum, GetLocalName(NameIndex), GetLocalName(ClassIndex), + OMFAlignTranslate[Attributes.u.A], + Lookup(OMFSegmentCombinationNames, Attributes.u.C), + Attributes.u.P ? 32 : 16); + if (Attributes.u.B) printf(", big"); + if (Attributes.u.A == 0) printf(", Frame %i, Offset 0x%X", Frame, Offset); + printf(", Length %i", SegLength); + if (OverlayIndex) printf("\n Overlay %i", OverlayIndex); + } + if (Records[i].Index != Records[i].End) err.submit(1203); // Check for consistency + } + } + printf("\n\nGroup records:"); + for (i = 0; i < NumRecords; i++) { + if (Records[i].Type2 == OMF_GRPDEF) { + // GRPDEF record + Records[i].Index = 3; + ClassIndex = Records[i].GetIndex(); + printf("\n Group: %s\n Segments:", GetLocalName(ClassIndex)); + + // Loop through remaining entries in record + while (Records[i].Index < Records[i].End) { + uint8 Type = Records[i].GetByte(); + if (Type != 0xFF) printf(" Type=%X:", Type); + NameIndex = Records[i].GetIndex(); + printf(" %s", GetSegmentName(NameIndex)); + } + if (Records[i].Index != Records[i].End) err.submit(1203); // Check for consistency + } + } +} + + +void COMF::DumpRelocations() { + // Dump all LEDATA, LIDATA, COMDAT and FIXUPP records + //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 i; // Loop counter + uint32 Segment, Offset, Size; // Contents of LEDATA or LIDATA record + uint32 LastOffset = 0; // Offset of last LEDATA or LIDATA record + uint32 Frame, Target, TargetDisplacement; // 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 + + printf("\n\nLEDATA, LIDATA, COMDAT and FIXUPP records:"); + for (i = 0; i < NumRecords; i++) { + if (Records[i].Type2 == OMF_LEDATA) { + // LEDATA record + Segment = Records[i].GetIndex(); // Read segment and offset + Offset = Records[i].GetNumeric(); + Size = Records[i].End - Records[i].Index; // Calculate size of data + //LastDataRecord = i; // Save for later FIXUPP that refers to this record + LastDataRecordSize = Size; + LastDataRecordPointer = Records[i].buffer + Records[i].FileOffset + Records[i].Index; + if (Segment < 0x4000) { + printf("\n LEDATA: segment %s, Offset 0x%X, Size 0x%X", // Dump segment, offset, size + GetSegmentName(Segment), Offset, Size); + LastOffset = Offset; + } + else { // Undocumented Borland communal section + printf("\n LEDATA communal section %i, Offset 0x%X, Size 0x%X", // Dump segment, offset, size + (Segment & ~0x4000), Offset, Size); + LastOffset = Offset; + } + } + + if (Records[i].Type2 == OMF_LIDATA) { + // LIDATA record + Segment = Records[i].GetIndex(); + Offset = Records[i].GetNumeric(); + //LastDataRecord = i; + LastDataRecordSize = Records[i].End - Records[i].Index; // Size before expansion of repeat blocks + LastDataRecordPointer = Records[i].buffer + Records[i].FileOffset + Records[i].Index; + printf("\n LIDATA: segment %s, Offset 0x%X, Size ", + GetSegmentName(Segment), Offset); + // Call recursive function to interpret repeat data block + Size = Records[i].InterpretLIDATABlock(); + printf(" = 0x%X", Size); + LastOffset = Offset; + } + + if (Records[i].Type2 == OMF_COMDAT) { + // COMDAT record + //uint32 Flags = Records[i].GetByte(); // 1 = continuation, 2 = iterated, 4 = local, 8 = data in code segment + uint32 Attributes = Records[i].GetByte(); + uint32 Base = 0; + // 0 = explicit, 1 = far code, 2 = far data, 3 = code32, 4 = data32 + // 0x00 = no match, 0x10 = pick any, 0x20 = same size, 0x30 = exact match + uint32 Align = Records[i].GetByte(); // Alignment + Offset = Records[i].GetNumeric(); // Offset + uint32 TypeIndex = Records[i].GetIndex(); // Type index + if ((Attributes & 0x0F) == 0) { + Base = Records[i].GetIndex(); // Public base + } + uint32 NameIndex = Records[i].GetIndex(); // LNAMES index + Size = Records[i].End - Records[i].Index; // Calculate size of data + + printf("\n COMDAT: name %s, Offset 0x%X, Size 0x%X, Attrib 0x%02X, Align %i, Type %i, Base %i", + GetLocalName(NameIndex), Offset, Size, Attributes, Align, TypeIndex, Base); + LastOffset = Offset; + } + + if (Records[i].Type2 == OMF_FIXUPP) { + // FIXUPP record + printf("\n FIXUPP:"); + Records[i].Index = 3; + + // 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 + Frame = 0; 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(); + + // print mode and location + printf("\n %s %s, Offset 0x%X", + Lookup(OMFRelocationModeNames, Locat.s.M), + Lookup(OMFFixupLocationNames, Locat.s.Location), + Locat.s.Offset + LastOffset); + + // Read conditional fields + if (FixData.s.F == 0) { + if (FixData.s.Frame < 4) { + Frame = Records[i].GetIndex(); + } + else Frame = 0; + + switch (FixData.s.Frame) { // Frame method + case 0: // F0: segment + printf(", segment %s", GetSegmentName(Frame)); break; + + case 1: // F1: group + printf(", group %s", GetGroupName(Frame)); break; + + case 2: // F2: external symbol + printf(", external frame %s", GetSymbolName(Frame)); break; + + case 4: // F4: frame = source, + // or Borland floating point emulation record (undocumented?) + printf(", frame = source; or Borland f.p. emulation record"); + break; + + case 5: // F5: frame = target + printf(", frame = target"); break; + + default: + printf(", target frame %i method F%i", Frame, FixData.s.Frame); + } + } + else { + printf(", frame uses thread %i", FixData.s.Frame); + } + + if (FixData.s.T == 0) { + // Target specified + Target = Records[i].GetIndex(); + uint32 TargetMethod = FixData.s.Target + FixData.s.P * 4; + + switch (FixData.s.Target) { // = Target method modulo 4 + case 0: // T0 and T4: Target = segment + case 1: // T1 and T5: Target = segment group + printf(". Segment %s (T%i)", + GetSegmentName(Target), TargetMethod); + break; + case 2: // T2 and T6: Target = external symbol + printf(". Symbol %s (T%i)", + GetSymbolName(Target), TargetMethod); + break; + default: // Unknown method + printf(", target %i unknown method T%i", Target, TargetMethod); + } + } + else { + // Target specified in previous thread + printf(", target uses thread %i", FixData.s.Target); + } + + if (FixData.s.P == 0) { + TargetDisplacement = Records[i].GetNumeric(); + printf("\n target displacement %i", TargetDisplacement); + } + // Get inline addend + if (LastDataRecordPointer && Locat.s.Offset < LastDataRecordSize) { + int8 * inlinep = LastDataRecordPointer + Locat.s.Offset; + switch (Locat.s.Location) { + case 0: case 4: // 8 bit + printf(", inline 0x%X", *inlinep); break; + + case 1: case 2: case 5: // 16 bit + printf(", inline 0x%X", *(int16*)inlinep); break; + + case 3: // 16+16 bit + printf(", inline 0x%X:0x%X", *(int16*)(inlinep+2), *(int16*)inlinep); break; + + case 9: case 13: // 32 bit + printf(", inline 0x%X", *(int32*)inlinep); break; + + case 6: case 11: // 16+32 bit + printf(", inline 0x%X:0x%X", *(int16*)(inlinep+4), *(int32*)inlinep); break; + } + } + } + else { + // This is a THREAD subrecord + TrdDat.b = byte1; // Put byte into bitfield + + uint32 Index = 0; + if (TrdDat.s.Method < 4) { + Index = Records[i].GetIndex(); // has index field if method < 4 ? + } + printf("\n %s Thread %i. Method %s%i, index %i", + (TrdDat.s.D ? "Frame" : "Target"), TrdDat.s.Thread, + (TrdDat.s.D ? "F" : "T"), TrdDat.s.Method, Index); + } + } // Finished loop through subrecords + if (Records[i].Index != Records[i].End) err.submit(1203); // Check for consistency + } + } // Finished loop through records +} + + +void COMF::DumpComments() { + // Dump COMENT records + uint32 i; // Record index + int startindex; + printf("\n"); + for (i = 0; i < NumRecords; i++) { + if (Records[i].Type2 == OMF_COMENT) { + // COMENT record + printf("\nCOMENT record:\n"); + startindex = Records[i].Index; + // Print as hex + while (Records[i].Index < Records[i].End) { + printf("%02X ", Records[i].GetByte()); + } + // Print again as string + Records[i].Index = startindex; + printf("\n"); + while (Records[i].Index < Records[i].End) { + printf("%c ", Records[i].GetByte()); + } + printf("\n"); + if (Records[i].Index != Records[i].End) err.submit(1203); // Check for consistency + } + } +} + + +void COMF::PublicNames(CMemoryBuffer * Strings, CSList * Index, int m) { + // Make list of public names + // Strings will receive ASCIIZ strings + // Index will receive records of type SStringEntry with Member = m + SOMFRecordPointer rec; // Current OMF record + char * string; // Symbol name + SStringEntry se; // String entry record to save + + // Initialize record pointer + rec.Start(Buf(), 0, GetDataSize()); + + // Loop through records and search for PUBDEF records + do { + // Read record + if (rec.Type2 == OMF_PUBDEF) { + + // Public symbols definition found + rec.GetIndex(); // Read group + uint32 Segment = rec.GetIndex(); // Read segment + if (Segment == 0) rec.GetWord(); // Read base frame + // Loop through strings in record + while (rec.Index < rec.End) { + string = rec.GetString(); // Read name + rec.GetNumeric(); // Read offset + rec.GetIndex(); // Read type + // Make SStringEntry record + se.Member = m; + // Store name + se.String = Strings->PushString(string); + // Store name index + Index->Push(se); + } + if (rec.Index != rec.End) err.submit(1203); // Check for consistency + } + if (rec.Type2 == OMF_CEXTDEF) { + // CEXTDEF record. Store communal symbol names + // Loop through entries in record + while (rec.Index < rec.End) { + uint32 LIndex = rec.GetIndex() - 1; // Index into preceding LNAMES + rec.GetIndex(); // Type index. Ignore + // Check if index valid + if (LIndex < LocalNameOffset.GetNumEntries()) { + // Make SStringEntry record + se.Member = m; + // Get name + char * name = GetLocalName(LIndex); + if (strlen(name) > 0) { + // Store name + se.String = Strings->PushString(name); + // Store name index + Index->Push(se); + } + } + } + if (rec.Index != rec.End) err.submit(1203); // Check for consistency + } + if (rec.Type2 == OMF_LNAMES) { + // LNAMES record. Check if file has been parsed + if (Records.GetNumEntries() == 0) { + // ParseFile has not been called. We need to store LNAMES table because + // these names may be needed by subsequent EXTDEF records. + // Loop through strings in record + while (rec.Index < rec.End) { + char * LocalName = rec.GetString(); + uint32 LocalNameIndex = NameBuffer.PushString(LocalName); // Store local name + LocalNameOffset.Push(LocalNameIndex);// Store local name index + } + if (rec.Index != rec.End) err.submit(1203); // Check for consistency + } + } + } // Get next record + while (rec.GetNext()); // End of loop through records +} + +char * COMF::GetLocalName(uint32 i) { + // Get section name or class name by name index + if (i == 0 || i >= LocalNameOffset.GetNumEntries()) { + i = NameBuffer.PushString("null"); + return NameBuffer.Buf() + i; + } + return NameBuffer.Buf() + LocalNameOffset[i]; +} + +uint32 COMF::GetLocalNameO(uint32 i) { + // Get section name or class by converting name index offset into NameBuffer + if (i > 0 && i < LocalNameOffset.GetNumEntries()) { + return LocalNameOffset[i]; + } + return 0; +} + +const char * COMF::GetSegmentName(uint32 i) { + // Get section name by segment index + if (i == 0) return "none"; + if ((i & 0xC000) == 0x4000) { + // Borland communal section + static char text[32]; + sprintf(text, "communal section %i", i - 0x4000); + return text; + } + if (i <= NumRecords) { + return NameBuffer.Buf() + SegmentNameOffset[i]; + } + return "?"; +} + + +const char * COMF::GetSymbolName(uint32 i) { + // Get external symbol name by index + if (i == 0) return "null"; + if (i < SymbolNameOffset.GetNumEntries()) { + return NameBuffer.Buf() + SymbolNameOffset[i]; + } + // return "?"; + // index out of range + static char temp[100]; + sprintf(temp, "Unknown index %i", i); + return temp; +} + +const char * COMF::GetGroupName(uint32 i) { + // Get group name by index + if (i == 0) return "none"; + if (i <= NumRecords) { + return NameBuffer.Buf() + GroupNameOffset[i]; + } + return "?"; +} + +const char * COMF::GetRecordTypeName(uint32 i) { + // Get record type name + return Lookup(OMFRecordTypeNames, i); +} + +// Member functions for parsing SOMFRecordPointer +uint8 SOMFRecordPointer::GetByte() { + // Read next byte from buffer + return *(buffer + FileOffset + Index++); +} + +uint16 SOMFRecordPointer::GetWord() { + // Read next 16 bit word from buffer + uint16 x = *(uint16*)(buffer + FileOffset + Index); + Index += 2; + return x; +} + +uint32 SOMFRecordPointer::GetDword() { + // Read next 32 bit dword from buffer + uint32 x = *(uint32*)(buffer + FileOffset + Index); + Index += 4; + return x; +} + +uint32 SOMFRecordPointer::GetIndex() { + // Read byte or word, depending on sign of first byte + uint32 byte1, byte2; + byte1 = GetByte(); + if (byte1 & 0x80) { + // Two byte index + byte2 = GetByte(); + return ((byte1 & 0x7F) << 8) | byte2; + } + else { + // One byte index + return byte1; + } +} + +uint32 SOMFRecordPointer::GetNumeric(){ + // Read word or dword, depending on record type even or odd + if (Type & 1) { + // Odd record type. Number is 32 bits + return GetDword(); + } + else { + // Even record type. Number is 16 bit s + return GetWord(); + } +} + +uint32 SOMFRecordPointer::GetLength() { + // Read 1, 2, 3 or 4 bytes, depending on value of first byte + uint32 x = GetByte(); + switch (x) { + case 0x81: // 16-bit value + return GetWord(); + case 0x82: // 24-bit value + x = GetWord(); + return (GetByte() << 16) + x; + case 0x84: // 32-bit value + return GetDword(); + default: // 8-bit value + if (x > 0x80) err.submit(1203); + return x; + } +} + +char * SOMFRecordPointer::GetString() { + // Read string and return as ASCIIZ string in static buffer + static char String[256]; + uint8 Length = GetByte(); + if (Length == 0 /*|| Length >= sizeof(String)*/) { + String[0] = 0; + } + else { + // Copy string + memcpy(String, buffer + FileOffset + Index, Length); + // Terminate by 0 + String[Length] = 0; + } + // Point to next + Index += Length; + + return String; +} + +void SOMFRecordPointer::Start(int8 * Buffer, uint32 FileOffset, uint32 FileEnd) { + // Start scanning through records + this->buffer = Buffer; + this->FileOffset = FileOffset; + this->FileEnd = FileEnd; + Index = 0; + Type = GetByte(); + Type2 = Type; if (Type2 < OMF_LIBHEAD) Type2 &= ~1; // Make even + uint16 RecordSize = GetWord(); + End = Index + RecordSize - 1; + if (FileOffset + RecordSize + 3 > FileEnd) err.submit(2301); // Extends beyond end of file +} + +uint8 SOMFRecordPointer::GetNext(uint32 align) { + // Get next record. Returns record type, made even. Returns 0 if finished + // align = alignment after MODEND records = page size. Applies to lib files only + FileOffset += End + 1; + + // Check if alignment needed + if (align > 1 && Type2 == OMF_MODEND) { + // Align after MODEND record in library + FileOffset = (FileOffset + align - 1) & - (int32)align; + } + if (FileOffset >= FileEnd) return 0; // End of file + Index = 0; // Start reading record + Type = GetByte(); // Get record type + Type2 = Type; if (Type2 < OMF_LIBHEAD) Type2 &= ~1; // Make even + uint16 RecordSize = GetWord(); // Get record size + End = Index + RecordSize - 1; // Point to checksum byte + if ((uint64)FileOffset + RecordSize + 3 > FileEnd) err.submit(2301); // Extends beyond end of file + return Type2; +} + +uint32 SOMFRecordPointer::InterpretLIDATABlock() { + // Interpret Data block in LIDATA record recursively + // Prints repeat count and returns total size + uint32 RepeatCount = GetNumeric(); + uint32 BlockCount = GetWord(); + uint32 Size = 0; + printf("%i * ", RepeatCount); + if (BlockCount == 0) { + Size = GetByte(); + Index += Size; + printf("%i", Size); + return RepeatCount * Size; + } + // Nested repeat blocks + printf("("); + for (uint32 i = 0; i < BlockCount; i++) { + // Recursion + Size += InterpretLIDATABlock(); + if (i+1 < BlockCount) printf(" + "); + } + printf(")"); + return RepeatCount * Size; +} + + +uint32 SOMFRecordPointer::UnpackLIDATABlock(int8 * destination, uint32 MaxSize) { + // Unpack Data block in LIDATA record recursively and store data at destination + uint32 RepeatCount = GetNumeric(); // Outer repeat count + uint32 BlockCount = GetWord(); // Inner repeat count + uint32 Size = 0; // Size of data expanded so far + uint32 RSize; // Size of recursively expanded data + uint32 SaveIndex; // Save Index for repetition + uint32 i, j; // Loop counters + if (BlockCount == 0) { + // Contains one repeated block + Size = GetByte(); // Size of repeated block + if (RepeatCount * Size > MaxSize) { + // Data outside allowed area + err.submit(2310); // Error message + Index += Size; // Point to after block + return 0; // No data stored + } + + // Loop RepeatCount times + for (i = 0; i < RepeatCount; i++) { + // copy data block into destination + memcpy(destination, buffer + FileOffset + Index, Size); + destination += Size; + } + Index += Size; // Point to after block + return RepeatCount * Size; // Size of expanded data + } + // Nested repeat blocks + SaveIndex = Index; + // Loop RepeatCount times + for (i = 0; i < RepeatCount; i++) { + // Go back and repeat unpacking + Index = SaveIndex; + // Loop BlockCount times + for (j = 0; j < BlockCount; j++) { + // Recursion + RSize = UnpackLIDATABlock(destination, MaxSize); + destination += RSize; + MaxSize -= RSize; + Size += RSize; + } + } + return Size; +} + + +// Members of COMFFileBuilder, class for building OMF files +COMFFileBuilder::COMFFileBuilder() { + // Constructor + Index = 0; +} + +void COMFFileBuilder::StartRecord(uint8 type) { + // Start building new record + this->Type = type; // Save type + RecordStart = Index = GetDataSize(); // Remember start position + PutByte(Type); // Put type into record + PutWord(0); // Reserve space for size, put in later +} + +void COMFFileBuilder::EndRecord() { + // Finish building current record + // Update length + Get(RecordStart + 1) = GetSize() + 1; + + // Make checksum + int8 checksum = 0; + for (uint32 i = RecordStart; i < Index; i++) checksum += Buf()[i]; + PutByte(-checksum); + + // Check size limit + if (GetSize() > 0x407) { + err.submit(9005); + } +} + +void COMFFileBuilder::PutByte(uint8 x) { + // Put byte into buffer + Push(&x, 1); + Index++; +} + +void COMFFileBuilder::PutWord(uint16 x) { + // Put 16 bit word into buffer + Push(&x, 2); + Index += 2; +} + +void COMFFileBuilder::PutDword(uint32 x) { + // Put 32 bit dword into buffer + Push(&x, 4); + Index += 4; +} + +void COMFFileBuilder::PutIndex(uint32 x) { + // Put byte or word into buffer (word if > 0x7F) + if (x < 0x80) { + // One byte + PutByte(x); + } + else { + // Two bytes + if (x > 0x7fff) { + err.submit(2303); // Index out of range + } + PutByte((uint8)(x >> 8) | 0x80); // First byte = high byte | 0x80 + PutByte(uint8(x)); // Second byte = low byte + } +} + +void COMFFileBuilder::PutNumeric(uint32 x) { + // Put word or dword into buffer, depending on type being even or odd + if (Type & 1) { + PutDword(x); // Type is odd, put 32 bits + } + else { + if (x > 0xffff) err.submit(2304);// Index out of range + PutWord(uint16(x)); // Type is even, put 16 bits + } +} + +void COMFFileBuilder::PutString(const char * s) { + // Put ASCII string into buffer, preceded by size + uint32 len = (uint32)strlen(s); // Check length + if (len > 255) { + // String too long + err.submit(1204, s); // Issue warning + len = 255; // Truncate string to 255 characters + } + PutByte(uint8(len)); // Store length + Push(s, len); // Store len bytes + Index += len; // Update index +} + +void COMFFileBuilder::PutBinary(void * p, uint32 Size) { + // Put binary data of any length + if (Size > 1024) {err.submit(9000); Size = 1024;} // 1024 bytes size limit + Push(p, Size); + Index += Size; +} + +uint32 COMFFileBuilder::GetSize() { + // Get size of data added so far + if (Index <= RecordStart + 3) return 0; + return Index - RecordStart - 3; // Type and size fields not included in size +} diff --git a/programs/develop/objconv/omf.h b/programs/develop/objconv/omf.h new file mode 100644 index 0000000000..43a163a82a --- /dev/null +++ b/programs/develop/objconv/omf.h @@ -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 diff --git a/programs/develop/objconv/omf2asm.cpp b/programs/develop/objconv/omf2asm.cpp new file mode 100644 index 0000000000..93ac72ff3d --- /dev/null +++ b/programs/develop/objconv/omf2asm.cpp @@ -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 +} diff --git a/programs/develop/objconv/omf2cof.cpp b/programs/develop/objconv/omf2cof.cpp new file mode 100644 index 0000000000..f429faac1e --- /dev/null +++ b/programs/develop/objconv/omf2cof.cpp @@ -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(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(0) = NewStringTable.GetDataSize(); + + // Put string table into new file + ToFile.Push(NewStringTable.Buf(), NewStringTable.GetDataSize()); +} diff --git a/programs/develop/objconv/omfhash.cpp b/programs/develop/objconv/omfhash.cpp new file mode 100644 index 0000000000..1185164d9b --- /dev/null +++ b/programs/develop/objconv/omfhash.cpp @@ -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 & 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 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 +} diff --git a/programs/develop/objconv/opcodes.cpp b/programs/develop/objconv/opcodes.cpp new file mode 100644 index 0000000000..70a4f10538 --- /dev/null +++ b/programs/develop/objconv/opcodes.cpp @@ -0,0 +1,6266 @@ +/**************************** opcodes.cpp ******************************* +* Author: Agner Fog +* Date created: 2007-02-21 +* Last modified: 2018-10-08 +* Project: objconv +* Module: opcodes.cpp +* Description: +* Definition of opcode maps used by disassembler +* +* Copyright 2007-2018 GNU General Public License http://www.gnu.org/licenses +*****************************************************************************/ + + +/*************************** Define opcode maps ****************************** + +Each line in the tables defines an instruction. +Name is the name of the instruction, possibly without suffix for operand size etc. +Instset defines which instruction set is required. +Prefix defines which prefixes are allowed or required and what they do. +Format defines which scheme the instruction code is modeled after. +Dest is the type of the destination operand. +Source1-3 defines the types of up to 3 source operands. +Link indicates branching into a subpage. +Options is used for various types of additional information. + +These code tables are organized as a big branching tree. +A line can branch into a subpage if more than one instruction or variant +begins with the same code bytes. Each subpage can branch further to form +a tree structure many levels deep. The first page, OpcodeMap0, is indexed +by the first code byte after any prefixes. The subpages can be indexed by +several different criteria, such as subsequent bytes, various bit-fields, +or by the values of any prefixes that come before the code byte. The +branching criteria are indicated in the 'link' column, while the submap +number is indicated in the 'instset' field. + +The interpretation of an instruction may start at the root, OpcodeMap0, +and follow any branches until the final leaf is found. +Instructions with VEX, EVEX or MVEX prefix use the VEX.mm bits as +shortcuts to the subpages OpcodeMap1, OpcodeMap2 and OpcodeMap4. + +The values in the tables do not use names for the constants because each +value would need the combination of several names so that the lines would +be extremely long and very difficult to align in a readable way. The meaning +of the values in each field in the map entries is defined in disasm.h. + +OpcodeTables[] is an array of pointers to all the maps. + +OpcodeTableLength[] indicates the size of each map. + +If a map is incomplete, then the last entry should indicate a default for +the missing entries, i.e. how to display the illegal or unknown instruction +codes. + +New entries can be added whenever a new extension to the instruction set is +introduced. + +*****************************************************************************/ + +#include "stdafx.h" + +// Primary opcode map. This is the root of the opcode lookup tree +SOpcodeDef OpcodeMap0[256] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"add", 0 , 0xC50 , 0x13 , 0x1 , 0x1001, 0 , 0 , 0 , 0 , 0 , 0 }, // 00 + {"add", 0 , 0x1D50 , 0x13 , 0x9 , 0x1009, 0 , 0 , 0 , 0 , 0 , 0 }, // 01 + {"add", 0 , 0 , 0x12 , 0x1001, 0x1 , 0 , 0 , 0 , 0 , 0 , 0 }, // 02 + {"add", 0 , 0x1100 , 0x12 , 0x1009, 0x9 , 0 , 0 , 0 , 0 , 0 , 0 }, // 03 + {"add", 0 , 0 , 0x41 , 0xA1 , 0x21 , 0 , 0 , 0 , 0 , 0 , 0 }, // 04 + {"add", 0 , 0x1100 , 0x81 , 0xA9 , 0x28 , 0 , 0 , 0 , 0 , 0 , 0x80 }, // 05 + {"push es", 0x8000, 0x2 , 0x1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 06 + {"pop es", 0x8000, 0x2 , 0x1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 07 + {"or", 0 , 0xC50 , 0x13 , 0x1 , 0x1001, 0 , 0 , 0 , 0 , 0 , 0 }, // 08 + {"or", 0 , 0x1D50 , 0x13 , 0x9 , 0x1009, 0 , 0 , 0 , 0 , 0 , 0 }, // 09 + {"or", 0 , 0 , 0x12 , 0x1001, 0x1 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0A + {"or", 0 , 0x1100 , 0x12 , 0x1009, 0x9 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0B + {"or", 0 , 0 , 0x41 , 0xA1 , 0x31 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0C + {"or", 0 , 0x1100 , 0x81 , 0xA9 , 0x39 , 0 , 0 , 0 , 0 , 0 , 0x80 }, // 0D + {"push cs", 0x8000, 0x2 , 0x1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0E + {0, 0x1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x1 , 0 }, // 0F link to OpcodeMap1 +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"adc", 0 , 0xC50 , 0x13 , 0x1 , 0x1001, 0 , 0 , 0 , 0 , 0 , 0 }, // 10 + {"adc", 0 , 0x1D50 , 0x13 , 0x9 , 0x1009, 0 , 0 , 0 , 0 , 0 , 0 }, // 11 + {"adc", 0 , 0 , 0x12 , 0x1001, 0x1 , 0 , 0 , 0 , 0 , 0 , 0 }, // 12 + {"adc", 0 , 0x1100 , 0x12 , 0x1009, 0x9 , 0 , 0 , 0 , 0 , 0 , 0 }, // 13 + {"adc", 0 , 0 , 0x41 , 0xA1 , 0x21 , 0 , 0 , 0 , 0 , 0 , 0 }, // 14 + {"adc", 0 , 0x1100 , 0x81 , 0xA9 , 0x29 , 0 , 0 , 0 , 0 , 0 , 0x80 }, // 15 + {"push ss", 0x8000, 0x2 , 0x1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 16 + {"pop ss", 0x8000, 0x2 , 0x1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 17 + {"sbb", 0 , 0xC50 , 0x13 , 0x1 , 0x1001, 0 , 0 , 0 , 0 , 0 , 0 }, // 18 + {"sbb", 0 , 0x1D50 , 0x13 , 0x9 , 0x1009, 0 , 0 , 0 , 0 , 0 , 0 }, // 19 + {"sbb", 0 , 0 , 0x12 , 0x1001, 0x1 , 0 , 0 , 0 , 0 , 0 , 0 }, // 1A + {"sbb", 0 , 0x1100 , 0x12 , 0x1009, 0x9 , 0 , 0 , 0 , 0 , 0 , 0 }, // 1B + {"sbb", 0 , 0 , 0x41 , 0xA1 , 0x21 , 0 , 0 , 0 , 0 , 0 , 0 }, // 1C + {"sbb", 0 , 0x1100 , 0x81 , 0xA9 , 0x29 , 0 , 0 , 0 , 0 , 0 , 0x80 }, // 1D + {"push ds", 0x8000, 0x2 , 0x1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 1E + {"pop ds", 0x8000, 0x2 , 0x1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 1F +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"and", 0 , 0xC50 , 0x13 , 0x1 , 0x1001, 0 , 0 , 0 , 0 , 0 , 0 }, // 20 + {"and", 0 , 0x1D50 , 0x13 , 0x9 , 0x1009, 0 , 0 , 0 , 0 , 0 , 0 }, // 21 + {"and", 0 , 0 , 0x12 , 0x1001, 0x1 , 0 , 0 , 0 , 0 , 0 , 0 }, // 22 + {"and", 0 , 0x1100 , 0x12 , 0x1009, 0x9 , 0 , 0 , 0 , 0 , 0 , 0 }, // 23 + {"and", 0 , 0 , 0x41 , 0xA1 , 0x31 , 0 , 0 , 0 , 0 , 0 , 0 }, // 24 + {"and", 0 , 0x1100 , 0x81 , 0xA9 , 0x39 , 0 , 0 , 0 , 0 , 0 , 0x80 }, // 25 + {"es:", 0 , 0 , 0x8001, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 26 + {"daa", 0x8000, 0 , 0x2 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x8 }, // 27 + {"sub", 0 , 0xC50 , 0x13 , 0x1 , 0x1001, 0 , 0 , 0 , 0 , 0 , 0 }, // 28 + {"sub", 0 , 0x1D50 , 0x13 , 0x9 , 0x1009, 0 , 0 , 0 , 0 , 0 , 0 }, // 29 + {"sub", 0 , 0 , 0x12 , 0x1001, 0x1 , 0 , 0 , 0 , 0 , 0 , 0 }, // 2A + {"sub", 0 , 0x1100 , 0x12 , 0x1009, 0x9 , 0 , 0 , 0 , 0 , 0 , 0 }, // 2B + {"sub", 0 , 0 , 0x41 , 0xA1 , 0x21 , 0 , 0 , 0 , 0 , 0 , 0 }, // 2C + {"sub", 0 , 0x1100 , 0x81 , 0xA9 , 0x29 , 0 , 0 , 0 , 0 , 0 , 0x80 }, // 2D + {"cs:", 0 , 0 , 0x8001, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 2E + {"das", 0x8000, 0 , 0x2 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x8 }, // 2F +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"xor", 0 , 0xC50 , 0x13 , 0x1 , 0x1001, 0 , 0 , 0 , 0 , 0 , 0 }, // 30 + {"xor", 0 , 0x1D50 , 0x13 , 0x9 , 0x1009, 0 , 0 , 0 , 0 , 0 , 0 }, // 31 + {"xor", 0 , 0 , 0x12 , 0x1001, 0x1 , 0 , 0 , 0 , 0 , 0 , 0 }, // 32 + {"xor", 0 , 0x1100 , 0x12 , 0x1009, 0x9 , 0 , 0 , 0 , 0 , 0 , 0 }, // 33 + {"xor", 0 , 0 , 0x41 , 0xA1 , 0x31 , 0 , 0 , 0 , 0 , 0 , 0 }, // 34 + {"xor", 0 , 0x1100 , 0x81 , 0xA9 , 0x39 , 0 , 0 , 0 , 0 , 0 , 0x80 }, // 35 + {"ss:", 0 , 0 , 0x8001, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 36 + {"aaa", 0x8000, 0 , 0x2 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x8 }, // 37 + {"cmp", 0 , 0 , 0x13 , 0x1 , 0x1001, 0 , 0 , 0 , 0 , 0 , 0x4 }, // 38 + {"cmp", 0 , 0x1100 , 0x13 , 0x9 , 0x1009, 0 , 0 , 0 , 0 , 0 , 0x4 }, // 39 + {"cmp", 0 , 0 , 0x12 , 0x1001, 0x1 , 0 , 0 , 0 , 0 , 0 , 0x4 }, // 3A + {"cmp", 0 , 0x1100 , 0x12 , 0x1009, 0x9 , 0 , 0 , 0 , 0 , 0 , 0x4 }, // 3B + {"cmp", 0 , 0 , 0x41 , 0xA1 , 0x11 , 0 , 0 , 0 , 0 , 0 , 0x4 }, // 3C + {"cmp", 0 , 0x1100 , 0x81 , 0xA9 , 0x19 , 0 , 0 , 0 , 0 , 0 , 0x84 }, // 3D + {"ds:", 0 , 0 , 0x8001, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 3E + {"aas", 0x8000, 0 , 0x2 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x8 }, // 3F +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"inc", 0x8000, 0x100 , 0x3 , 0x1008, 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 40 + {"inc", 0x8000, 0x100 , 0x3 , 0x1008, 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 41 + {"inc", 0x8000, 0x100 , 0x3 , 0x1008, 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 42 + {"inc", 0x8000, 0x100 , 0x3 , 0x1008, 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 43 + {"inc", 0x8000, 0x100 , 0x3 , 0x1008, 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 44 + {"inc", 0x8000, 0x100 , 0x3 , 0x1008, 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 45 + {"inc", 0x8000, 0x100 , 0x3 , 0x1008, 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 46 + {"inc", 0x8000, 0x100 , 0x3 , 0x1008, 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 47 + {"dec", 0x8000, 0x100 , 0x3 , 0x1008, 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 48 + {"dec", 0x8000, 0x100 , 0x3 , 0x1008, 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 49 + {"dec", 0x8000, 0x100 , 0x3 , 0x1008, 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 4A + {"dec", 0x8000, 0x100 , 0x3 , 0x1008, 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 4B + {"dec", 0x8000, 0x100 , 0x3 , 0x1008, 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 4C + {"dec", 0x8000, 0x100 , 0x3 , 0x1008, 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 4D + {"dec", 0x8000, 0x100 , 0x3 , 0x1008, 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 4E + {"dec", 0x8000, 0x100 , 0x3 , 0x1008, 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 4F +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"push", 0 , 0x2102 , 0x3 , 0x100A, 0 , 0 , 0 , 0 , 0 , 0 , 0x4 }, // 50 + {"push", 0 , 0x2102 , 0x3 , 0x100A, 0 , 0 , 0 , 0 , 0 , 0 , 0x4 }, // 51 + {"push", 0 , 0x2102 , 0x3 , 0x100A, 0 , 0 , 0 , 0 , 0 , 0 , 0x4 }, // 52 + {"push", 0 , 0x2102 , 0x3 , 0x100A, 0 , 0 , 0 , 0 , 0 , 0 , 0x4 }, // 53 + {"push", 0 , 0x2102 , 0x3 , 0x100A, 0 , 0 , 0 , 0 , 0 , 0 , 0x4 }, // 54 + {"push", 0 , 0x2102 , 0x3 , 0x100A, 0 , 0 , 0 , 0 , 0 , 0 , 0x4 }, // 55 + {"push", 0 , 0x2102 , 0x3 , 0x100A, 0 , 0 , 0 , 0 , 0 , 0 , 0x4 }, // 56 + {"push", 0 , 0x2102 , 0x3 , 0x100A, 0 , 0 , 0 , 0 , 0 , 0 , 0x4 }, // 57 + {"pop", 0 , 0x2102 , 0x3 , 0x100A, 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 58 + {"pop", 0 , 0x2102 , 0x3 , 0x100A, 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 59 + {"pop", 0 , 0x2102 , 0x3 , 0x100A, 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 5A + {"pop", 0 , 0x2102 , 0x3 , 0x100A, 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 5B + {"pop", 0 , 0x2102 , 0x3 , 0x100A, 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 5C + {"pop", 0 , 0x2102 , 0x3 , 0x100A, 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 5D + {"pop", 0 , 0x2102 , 0x3 , 0x100A, 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 5E + {"pop", 0 , 0x2102 , 0x3 , 0x100A, 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 5F +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"pusha", 0x8001, 0x102 , 0x2 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x5 }, // 60 + {"popa", 0x8001, 0x102 , 0x2 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x9 }, // 61 + {"bound", 0x8001, 0x106 , 0x12 , 0x1008, 0x2009, 0 , 0 , 0 , 0 , 0 , 0 }, // 62 + {0, 0x3B , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x7 , 0 }, // 63 Link to arpl/movsxd + {"fs:", 0 , 0 , 0x8001, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 64 + {"gs:", 0 , 0 , 0x8001, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 65 + {"operand size:",0x0, 0 , 0x8000, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 66 + {"address size:",0x0, 0 , 0x8000, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 67 + {"push", 0 , 0x2102 , 0x82 , 0 , 0x29 , 0 , 0 , 0 , 0 , 0 , 0x80 }, // 68 push imm word + {"imul", 0x1 , 0x1100 , 0x92 , 0x1009, 0x9 , 0x29 , 0 , 0 , 0 , 0 , 0x80 }, // 69 imul r,m,iv + {"push", 0 , 0x2102 , 0x42 , 0 , 0x21 , 0 , 0 , 0 , 0 , 0 , 0 }, // 6A push imm byte + {"imul", 0x1 , 0x1100 , 0x52 , 0x1009, 0x9 , 0x21 , 0 , 0 , 0 , 0 , 0 }, // 6B imul r,m,ib + {"insb", 0 , 0x21 , 0x1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x8 }, // 6C insb + {"ins", 0 , 0x121 , 0x1 , 0x20C2, 0xB2 , 0 , 0 , 0 , 0 , 0 , 0x8 }, // 6D insw + {"outsb", 0 , 0x21 , 0x1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x8 }, // 6E outsb + {"outs", 0 , 0x121 , 0x1 , 0xB2 , 0x20C2, 0 , 0 , 0 , 0 , 0 , 0x8 }, // 6F outs +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"jo", 0 , 0x88 , 0x42 , 0x81 , 0 , 0 , 0 , 0 , 0 , 0 , 0xA0 }, // 70 conditional short jumps + {"jno", 0 , 0x88 , 0x42 , 0x81 , 0 , 0 , 0 , 0 , 0 , 0 , 0xA0 }, // 71 + {"jc", 0 , 0x88 , 0x42 , 0x81 , 0 , 0 , 0 , 0 , 0 , 0 , 0xA0 }, // 72 + {"jnc", 0 , 0x88 , 0x42 , 0x81 , 0 , 0 , 0 , 0 , 0 , 0 , 0xA0 }, // 73 + {"jz", 0 , 0x88 , 0x42 , 0x81 , 0 , 0 , 0 , 0 , 0 , 0 , 0xA0 }, // 74 + {"jnz", 0 , 0x88 , 0x42 , 0x81 , 0 , 0 , 0 , 0 , 0 , 0 , 0xA0 }, // 75 + {"jbe", 0 , 0x88 , 0x42 , 0x81 , 0 , 0 , 0 , 0 , 0 , 0 , 0xA0 }, // 76 + {"ja", 0 , 0x88 , 0x42 , 0x81 , 0 , 0 , 0 , 0 , 0 , 0 , 0xA0 }, // 77 + {"js", 0 , 0x88 , 0x42 , 0x81 , 0 , 0 , 0 , 0 , 0 , 0 , 0xA0 }, // 78 + {"jns", 0 , 0x88 , 0x42 , 0x81 , 0 , 0 , 0 , 0 , 0 , 0 , 0xA0 }, // 79 + {"jpe", 0 , 0x88 , 0x42 , 0x81 , 0 , 0 , 0 , 0 , 0 , 0 , 0xA0 }, // 7A + {"jpo", 0 , 0x88 , 0x42 , 0x81 , 0 , 0 , 0 , 0 , 0 , 0 , 0xA0 }, // 7B + {"jl", 0 , 0x88 , 0x42 , 0x81 , 0 , 0 , 0 , 0 , 0 , 0 , 0xA0 }, // 7C + {"jge", 0 , 0x88 , 0x42 , 0x81 , 0 , 0 , 0 , 0 , 0 , 0 , 0xA0 }, // 7D + {"jle", 0 , 0x88 , 0x42 , 0x81 , 0 , 0 , 0 , 0 , 0 , 0 , 0xA0 }, // 7E + {"jg", 0 , 0x88 , 0x42 , 0x81 , 0 , 0 , 0 , 0 , 0 , 0 , 0xA0 }, // 7F +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"grp1", 0x1A , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x2 , 0 }, // 80 link to immediate grp 1 + {"grp1", 0x1B , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x2 , 0 }, // 81 link to immediate grp 1 + {"grp1", 0x1C , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x2 , 0 }, // 82 link to immediate grp 1 + {"grp1", 0x1D , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x2 , 0 }, // 83 link to immediate grp 1 + {"test", 0 , 0 , 0x13 , 0x1 , 0x1001, 0 , 0 , 0 , 0 , 0 , 0x4 }, // 84 + {"test", 0 , 0x1100 , 0x13 , 0x9 , 0x1009, 0 , 0 , 0 , 0 , 0 , 0x4 }, // 85 + {"xchg", 0 , 0xC50 , 0x13 , 0x1 , 0x1001, 0 , 0 , 0 , 0 , 0 , 0x48 }, // 86 + {"xchg", 0 , 0x1D50 , 0x13 , 0x9 , 0x1009, 0 , 0 , 0 , 0 , 0 , 0x48 }, // 87 + {"mov", 0 , 0xC40 , 0x13 , 0x1 , 0x1001, 0 , 0 , 0 , 0 , 0 , 0x40 }, // 88 + {"mov", 0 , 0x1D40 , 0x13 , 0x9 , 0x1009, 0 , 0 , 0 , 0 , 0 , 0x40 }, // 89 + {"mov", 0 , 0 , 0x12 , 0x1001, 0x1 , 0 , 0 , 0 , 0 , 0 , 0x40 }, // 8A + {"mov", 0 , 0x1100 , 0x12 , 0x1009, 0x9 , 0 , 0 , 0 , 0 , 0 , 0x40 }, // 8B + {"mov", 0 , 0x1100 , 0x13 , 0x9 , 0x91 , 0 , 0 , 0 , 0 , 0 , 0 }, // 8C mov r16,segreg + {"lea", 0 , 0x1101 , 0x12 , 0x1009, 0x2009, 0 , 0 , 0 , 0 , 0 , 0xC0 }, // 8D + {"mov", 0 , 0x1100 , 0x12 , 0x91 , 0x9 , 0 , 0 , 0 , 0 , 0 , 0 }, // 8E mov segreg,r16 + {"pop", 0x28 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x2 , 0 }, // 8F Link to group 1A +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"nop", 0x3C , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x9 , 0 }, // 90 NOP/Pause. Link to map + {"xchg", 0 , 0x1100 , 0x3 , 0x1009, 0xA9 , 0 , 0 , 0 , 0 , 0 , 0x8 }, // 91 xchg cx,ax + {"xchg", 0 , 0x1100 , 0x3 , 0x1009, 0xA9 , 0 , 0 , 0 , 0 , 0 , 0x8 }, // 92 xchg dx,ax + {"xchg", 0 , 0x1100 , 0x3 , 0x1009, 0xA9 , 0 , 0 , 0 , 0 , 0 , 0x8 }, // 93 xchg bx,ax + {"xchg", 0 , 0x1100 , 0x3 , 0x1009, 0xA9 , 0 , 0 , 0 , 0 , 0 , 0x8 }, // 94 xchg sp,ax + {"xchg", 0 , 0x1100 , 0x3 , 0x1009, 0xA9 , 0 , 0 , 0 , 0 , 0 , 0x8 }, // 95 xchg bp,ax + {"xchg", 0 , 0x1100 , 0x3 , 0x1009, 0xA9 , 0 , 0 , 0 , 0 , 0 , 0x8 }, // 96 xchg si,ax + {"xchg", 0 , 0x1100 , 0x3 , 0x1009, 0xA9 , 0 , 0 , 0 , 0 , 0 , 0x8 }, // 97 xchg di,ax + {"cbw", 0x39 , 0x1100 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x8 , 0 }, // 98 Link to map + {"cwd", 0x3A , 0x1100 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x8 , 0 }, // 99 Link to map + {"call", 0x8000, 0x182 , 0x200 , 0x85 , 0 , 0 , 0 , 0 , 0 , 0 , 0x28 }, // 9A call far + {"fwait", 0x100 , 0 , 0x2 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 9B + {"pushf", 0x3E , 0x2100 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x8 , 0 }, // 9C Link to map: pushf/d/q + {"popf", 0x3F , 0x2100 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x8 , 0 }, // 9D Link to map: popf/d/q + {"sahf", 0 , 0 , 0x2 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 9E + {"lahf", 0 , 0 , 0x2 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x8 }, // 9F +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"mov", 0 , 0x5 , 0x401 , 0x10A1, 0x2001, 0 , 0 , 0 , 0 , 0 , 0 }, // A0 mov al,mem + {"mov", 0 , 0x1105 , 0x401 , 0x10A9, 0x2009, 0 , 0 , 0 , 0 , 0 , 0 }, // A1 mov ax,mem + {"mov", 0 , 0x5 , 0x401 , 0x2001, 0x10A1, 0 , 0 , 0 , 0 , 0 , 0 }, // A2 mov mem,al + {"mov", 0 , 0x1105 , 0x401 , 0x2009, 0x10A9, 0 , 0 , 0 , 0 , 0 , 0 }, // A3 mov mem,ax + {"movs", 0 , 0x25 , 0x1 , 0x20C2, 0x20C1, 0 , 0 , 0 , 0 , 0 , 0x8 }, // A4 movsb + {"movs", 0 , 0x1125 , 0x1 , 0x20C2, 0x20C1, 0 , 0 , 0 , 0 , 0 , 0x8 }, // A5 movsw + {"cmps", 0 , 0x45 , 0x1 , 0x20C2, 0x20C1, 0 , 0 , 0 , 0 , 0 , 0x8 }, // A6 cmpsb + {"cmps", 0 , 0x1145 , 0x1 , 0x20C2, 0x20C1, 0 , 0 , 0 , 0 , 0 , 0x8 }, // A7 cmpsw + {"test", 0 , 0 , 0x41 , 0x10A1, 0x31 , 0 , 0 , 0 , 0 , 0 , 0x4 }, // A8 test al,ib + {"test", 0 , 0x1100 , 0x81 , 0x10A9, 0x39 , 0 , 0 , 0 , 0 , 0 , 0x4 }, // A9 test ax,iw + {"stos", 0 , 0x21 , 0x1 , 0x20C2, 0 , 0 , 0 , 0 , 0 , 0 , 0x8 }, // AA stosb + {"stos", 0 , 0x1121 , 0x1 , 0x20C2, 0 , 0 , 0 , 0 , 0 , 0 , 0x8 }, // AB stosw + {"lods", 0 , 0x25 , 0x1 , 0 , 0x20C1, 0 , 0 , 0 , 0 , 0 , 0x8 }, // AC lodsb + {"lods", 0 , 0x1125 , 0x1 , 0 , 0x20C1, 0 , 0 , 0 , 0 , 0 , 0x8 }, // AD lodsw + {"scas", 0 , 0x41 , 0x1 , 0x20C2, 0 , 0 , 0 , 0 , 0 , 0 , 0x8 }, // AE scasb + {"scas", 0 , 0x1141 , 0x1 , 0x20C2, 0 , 0 , 0 , 0 , 0 , 0 , 0x8 }, // AF scasw +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"mov", 0 , 0 , 0x43 , 0x1001, 0x11 , 0 , 0 , 0 , 0 , 0 , 0 }, // B0 mov al,ib + {"mov", 0 , 0 , 0x43 , 0x1001, 0x11 , 0 , 0 , 0 , 0 , 0 , 0 }, // B1 mov cl,ib + {"mov", 0 , 0 , 0x43 , 0x1001, 0x11 , 0 , 0 , 0 , 0 , 0 , 0 }, // B2 mov dl,ib + {"mov", 0 , 0 , 0x43 , 0x1001, 0x11 , 0 , 0 , 0 , 0 , 0 , 0 }, // B3 mov bl,ib + {"mov", 0 , 0 , 0x43 , 0x1001, 0x11 , 0 , 0 , 0 , 0 , 0 , 0 }, // B4 mov ah,ib + {"mov", 0 , 0 , 0x43 , 0x1001, 0x11 , 0 , 0 , 0 , 0 , 0 , 0 }, // B5 mov ch,ib + {"mov", 0 , 0 , 0x43 , 0x1001, 0x11 , 0 , 0 , 0 , 0 , 0 , 0 }, // B6 mov dh,ib + {"mov", 0 , 0 , 0x43 , 0x1001, 0x11 , 0 , 0 , 0 , 0 , 0 , 0 }, // B7 mov bh,ib + {"mov", 0 , 0x1100 , 0x103 , 0x1009, 0x19 , 0 , 0 , 0 , 0 , 0 , 0x400 }, // B8 mov ax,iw + {"mov", 0 , 0x1100 , 0x103 , 0x1009, 0x19 , 0 , 0 , 0 , 0 , 0 , 0x400 }, // B9 mov cx,iw + {"mov", 0 , 0x1100 , 0x103 , 0x1009, 0x19 , 0 , 0 , 0 , 0 , 0 , 0x400 }, // BA mov dx,iw + {"mov", 0 , 0x1100 , 0x103 , 0x1009, 0x19 , 0 , 0 , 0 , 0 , 0 , 0x400 }, // BB mov bx,iw + {"mov", 0 , 0x1100 , 0x103 , 0x1009, 0x19 , 0 , 0 , 0 , 0 , 0 , 0x400 }, // BC mov sp,iw + {"mov", 0 , 0x1100 , 0x103 , 0x1009, 0x19 , 0 , 0 , 0 , 0 , 0 , 0x400 }, // BD mov bp,iw + {"mov", 0 , 0x1100 , 0x103 , 0x1009, 0x19 , 0 , 0 , 0 , 0 , 0 , 0x400 }, // BE mov si,iw + {"mov", 0 , 0x1100 , 0x103 , 0x1009, 0x19 , 0 , 0 , 0 , 0 , 0 , 0x400 }, // BF mov di,iw +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"grp2", 0x1E , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x2 , 0 }, // C0 link to grp 2 + {"grp2", 0x1F , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x2 , 0 }, // C1 link to grp 2 + {"ret", 0 , 0x21AA , 0x22 , 0 , 0x12 , 0 , 0 , 0 , 0 , 0 , 0x30 }, // C2 retn iw + {"ret", 0 , 0x21AA , 0x2 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x30 }, // C3 retn + {"les", 0x8000, 0x100 , 0x812 , 0x1009, 0x200C, 0 , 0 , 0 , 0 , 0 , 0 }, // C4 les + {"lds", 0x8000, 0x100 , 0x812 , 0x1009, 0x200C, 0 , 0 , 0 , 0 , 0 , 0 }, // C5 lds + {"mov", 0x2F , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x4 , 0 }, // C6 link to grp 11 + {"mov", 0x30 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x4 , 0 }, // C7 link to grp 11 + {"enter", 0 , 0 , 0x62 , 0 , 0x12 , 0x11 , 0 , 0 , 0 , 0 , 0x8 }, // C8 + {"leave", 0 , 0 , 0x2 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x8 }, // C9 + {"retf", 0 , 0x2182 , 0x22 , 0 , 0x12 , 0 , 0 , 0 , 0 , 0 , 0x10 }, // CA retf iw + {"retf", 0 , 0x2182 , 0x2 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x10 }, // CB retf + {"int 3;breakpoint or filler",0,0,2 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x48 }, // CC + {"int", 0 , 0 , 0x42 , 0 , 0x11 , 0 , 0 , 0 , 0 , 0 , 0x8 }, // CD + {"into", 0x8000, 0 , 0x2 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // CE + {0, 0x19 , 0x1100 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x8 , 0 }, // CF link to IRET +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"grp2", 0x20 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x2 , 0 }, // D0 link to grp 2 + {"grp2", 0x21 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x2 , 0 }, // D1 link to grp 2 + {"grp2", 0x22 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x2 , 0 }, // D2 link to grp 2 + {"grp2", 0x23 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x2 , 0 }, // D3 link to grp 2 + {"aam", 0x8000, 0 , 0x42 , 0 , 0x11 , 0 , 0 , 0 , 0 , 0 , 0x8 }, // D4. Don't show immediate operand if = 10 ! + {"aad", 0x8000, 0 , 0x42 , 0 , 0x11 , 0 , 0 , 0 , 0 , 0 , 0x8 }, // D5. Don't show immediate operand if = 10 ! + {"salc", 0x8000, 0 , 0x4002, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // D6 salc (undocumented opcode) + {"xlat", 0x92 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x10 , 0 }, // D7. Link to xlat + {"x87 instr", 0x8 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x4 , 0 }, // D8 link to FP grp + {"x87 instr", 0x9 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x4 , 0 }, // D9 link to FP grp + {"x87 instr", 0xA , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x4 , 0 }, // DA link to FP grp + {"x87 instr", 0xB , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x4 , 0 }, // DB link to FP grp + {"x87 instr", 0xC , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x4 , 0 }, // DC link to FP grp + {"x87 instr", 0xD , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x4 , 0 }, // DD link to FP grp + {"x87 instr", 0xE , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x4 , 0 }, // DE link to FP grp + {"x87 instr", 0xF , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x4 , 0 }, // DF link to FP grp +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"loopne", 0 , 0x80 , 0x42 , 0x81 , 0 , 0 , 0 , 0 , 0 , 0 , 0x8 }, // E0 + {"loope", 0 , 0x80 , 0x42 , 0x81 , 0 , 0 , 0 , 0 , 0 , 0 , 0x8 }, // E1 + {"loop", 0 , 0x80 , 0x42 , 0x81 , 0 , 0 , 0 , 0 , 0 , 0 , 0x8 }, // E2 + {"j(e/r)cxz", 0x3D , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0xA , 0 }, // E3 link to map + {"in", 0x800 , 0 , 0x41 , 0xA1 , 0x11 , 0 , 0 , 0 , 0 , 0 , 0 }, // E4 in al,ib + {"in", 0x800 , 0x100 , 0x41 , 0xA8 , 0x11 , 0 , 0 , 0 , 0 , 0 , 0 }, // E5 in ax,ib + {"out", 0x800 , 0 , 0x41 , 0x32 , 0xA1 , 0 , 0 , 0 , 0 , 0 , 0 }, // E6 out ib,al + {"out", 0x800 , 0x100 , 0x41 , 0x32 , 0xA8 , 0 , 0 , 0 , 0 , 0 , 0 }, // E7 out ib,ax + {"call", 0 , 0xAA , 0x82 , 0x83 , 0 , 0 , 0 , 0 , 0 , 0 , 0x28 }, // E8 call near + {"jmp", 0 , 0xA8 , 0x82 , 0x82 , 0 , 0 , 0 , 0 , 0 , 0 , 0xB0 }, // E9 jmp near + {"jmp", 0x8000, 0x80 , 0x202 , 0x84 , 0 , 0 , 0 , 0 , 0 , 0 , 0x30 }, // EA jmp far + {"jmp", 0 , 0xA8 , 0x42 , 0x81 , 0 , 0 , 0 , 0 , 0 , 0 , 0x30 }, // EB jmp short + {"in", 0x800 , 0 , 0x1 , 0xA1 , 0xB2 , 0 , 0 , 0 , 0 , 0 , 0 }, // EC in al,dx + {"in", 0x800 , 0x100 , 0x1 , 0xA8 , 0xB2 , 0 , 0 , 0 , 0 , 0 , 0 }, // ED in ax,dx + {"out", 0x800 , 0 , 0x1 , 0xB2 , 0xA1 , 0 , 0 , 0 , 0 , 0 , 0 }, // EE out dx,al + {"out", 0x800 , 0x100 , 0x1 , 0xB2 , 0xA8 , 0 , 0 , 0 , 0 , 0 , 0 }, // EF out dx,ax +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"lock:", 0 , 0 , 0x8000, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // F0 lock prefix + {"icebp", 0x8000, 0 , 0x4002, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // F1 ICE breakpoint, undocumented opcode + {"repne:", 0 , 0 , 0x8000, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // F2 repne prefix + {"repe:", 0 , 0 , 0x8000, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // F3 repe prefix + {"hlt", 0 , 0 , 0x2 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x48 }, // F4 + {"cmc", 0 , 0 , 0x2 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // F5 + {"grp3", 0x24 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x2 , 0 }, // F6 link to grp 3 + {"grp3", 0x25 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x2 , 0 }, // F7 link to grp 3 + {"clc", 0 , 0 , 0x2 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // F8 + {"stc", 0 , 0 , 0x2 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // F9 + {"cli", 0x800 , 0 , 0x2 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // FA + {"sti", 0x800 , 0 , 0x2 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // FB + {"cld", 0 , 0 , 0x2 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // FC + {"std", 0 , 0 , 0x2 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // FD + {"grp4", 0x26 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x2 , 0 }, // FE link to grp 4 + {"grp5", 0x27 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x2 , 0 } // FF link to grp 5 +}; + +// Secondary opcode map for 2-byte opcode. First byte = 0F +// Indexed by second opcode byte +SOpcodeDef OpcodeMap1[256] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"grp6", 0x2A , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x2 , 0 }, // 0F 00 link to grp 6; sldt etc. + {"grp7", 0x2B , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x4 , 0 }, // 0F 01 link to grp 7; sgdt etc. + {0, 0x5E , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x3 , 0 }, // 0F 02 link to lar + {0, 0x5F , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x3 , 0 }, // 0F 03 link to lsl + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 04 Illegal + {"syscall", 0x5 , 0 , 0x1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x8 }, // 0F 05 + {"clts", 0x805 , 0 , 0x1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 06 + {"sysret", 0x805 , 0 , 0x1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x10 }, // 0F 07 + {"invd", 0x804 , 0 , 0x1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 08 + {"wbinvd", 0x804 , 0 , 0x1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 09 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0A Illegal + {"ud2", 0x3 , 0 , 0x1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x10 }, // 0F 0B + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0C Illegal + {0, 0xD1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x2 , 0 }, // 0F 0D Link to prefetch + {"FEMS", 0x1001, 0 , 0x2 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F OE. AMD only + {0, 0x6 , 0 , 0x52 , 0 , 0 , 0 , 0 , 0 , 0 , 0x6 , 0 }, // 0F 0F. Link to tertiary map for AMD 3DNow instructions +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {0, 0x40 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x9 , 0 }, // 0F 10 Link to tertiary map: movups, etc. + {0, 0x41 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x9 , 0 }, // 0F 11 Link to tertiary map: movups, etc. + {0, 0x42 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x9 , 0 }, // 0F 12 Link to tertiary map: movlps, etc. + {"movl", 0x11 ,0x812200, 0x13 , 0x234F, 0x144F, 0 , 0 , 0x1000, 0 , 0 , 0x3 }, // 0F 13 movlps/pd + {"unpckl", 0x11 ,0x8D2200, 0x19 , 0x124F, 0x124F, 0x24F , 0 , 0x31 , 0 , 0 , 0x3 }, // 0F 14 unpcklps/pd + {"unpckh", 0x11 ,0x8D2200, 0x19 , 0x124F, 0x124F, 0x24F , 0 , 0x31 , 0 , 0 , 0x3 }, // 0F 15 unpckhps/pd + {0, 0x44 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x9 , 0 }, // 0F 16 Link to tertiary map: movhps, etc. + {"movh", 0x11 ,0x812200, 0x13 , 0x234F, 0x144F, 0 , 0 , 0x1000, 0 , 0 , 0x3 }, // 0F 17 movhps/pd + {0, 0x35 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x2 , 0 }, // 0F 18 Link to tertiary map: group 16 + {"hint", 0x6 , 0 , 0x2012, 0 , 0x6 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 19. Hint instructions reserved for future use + {0, 0x110 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x9 , 0 }, // 0F 1A. Link to BNDMK etc + {0, 0x111 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x9 , 0 }, // 0F 1B. Link to BNDCL etc + {"hint", 0x6 , 0 , 0x2012, 0 , 0x6 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 1C. Hint instructions reserved for future use + {"hint", 0x6 , 0 , 0x2012, 0 , 0x6 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 1D. Hint instructions reserved for future use + {"hint", 0x135 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 9 , 0 }, // 0F 1E. link to endbr64 etc. + {"nop", 0x6 , 0 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x40 }, // 0F 1F. Multi-byte nop +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"mov", 0x803 , 0 , 0x13 , 0x100A, 0x92 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 20. mov r32/64,cr + {"mov", 0x803 , 0x1000 , 0x13 , 0x1009, 0x93 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 21. mov r32,dr + {"mov", 0x803 , 0 , 0x12 , 0x92 , 0x100A, 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 22. mov cr,r32/64 + {"mov", 0x803 , 0x1000 , 0x12 , 0x93 , 0x1009, 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 23. mov dr,r32 +#if 0 // Opcode 0F 24 has two meanings: + // 1: mov r32,tr (obsolete, 80386 only) + {"mov;80386 only",0x803,0x0 , 0x4013, 0x1003, 0x94 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 24. mov r32,tr (80386 only) +#else + // 2: start of 3-byte opcode for AMD SSE5 instructions with DREX byte + {0, 0x68 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x1 , 0 }, // 0F 24. Link to tertiary map for 3-byte opcodes AMD SSE5 with four operands +#endif + {0, 0x69 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x1 , 0 }, // 0F 25. Link to tertiary map for 3-byte opcodes AMD SSE5 with three operands + immediate byte + {"mov;80386 only",0x803,0 , 0x4012, 0x94 , 0x1003, 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 26. mov tr,r32 (80386 only) + {0, 0x803 , 0 , 0x4012, 0x1003, 0x1003, 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 27. illegal + {"mova", 0x11 ,0xC52200, 0x12 , 0x124F, 0x24F, 0 , 0 , 0x30 , 0x1204, 0 , 0x103 }, // 0F 28. movaps/pd + {"mova", 0xBC , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x9 , 0 }, // 0F 29. Link to movaps/pd + {0, 0x46 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x9 , 0 }, // 0F 2A. Link to tertiary map: cvtpi2ps, etc. + {0, 0xD2 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x9 , 0 }, // 0F 2B. Link to tertiary map: movntps/pd,AMD: also ss/sd + {0, 0x47 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x9 , 0 }, // 0F 2C. Link to tertiary map: cvttps2pi, etc. + {0, 0x48 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x9 , 0 }, // 0F 2D. Link to tertiary map: cvtps2pi, etc. + {0, 0x4B , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x9 , 0 }, // 0F 2E. Link to tertiary map: ucomiss/sd + {0, 0x4C , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x9 , 0 }, // 0F 2F. Link to tertiary map: comiss/sd +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"wrmsr", 0x805 , 0x1000 , 0x1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 30 + {"rdtsc", 0x5 , 0 , 0x1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x8 }, // 0F 31 + {"rdmsr", 0x805 , 0x1000 , 0x1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x8 }, // 0F 32 + {"rdpmc", 0x5 , 0 , 0x1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x8 }, // 0F 33 + {"sysenter", 0x8 , 0 , 0x1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x8 }, // 0F 34 + {"sysexit;Same name with or without 48h prefix",0x808,0x1000,1,0,0,0,0, 0 ,0x0 , 0 , 0 }, // 0F 35 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 36 Illegal + {"getsec", 0x14 , 0 , 0x1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x8 }, // 0F 37 + {0, 0x2 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x1 , 0 }, // 0F 38. Link to tertiary map for 3-byte opcodes + {0, 0x3 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x1 , 0 }, // 0F 39. Link to tertiary map for 3-byte opcodes + {0, 0x4 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x1 , 0 }, // 0F 3A. Link to tertiary map for 3-byte opcodes + {0, 0x5 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x1 , 0 }, // 0F 3B. Link to tertiary map for 3-byte opcodes + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3C Illegal + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3D Illegal + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3E Illegal + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3F (VIA/Centaur ALTINST ?) +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"cmovo", 0x6 , 0x1100 , 0x12 , 0x1009, 0x9 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 40. cmov + {"cmovno", 0x6 , 0x1100 , 0x12 , 0x1009, 0x9 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 41. cmov + {"cmovc", 0x6 , 0x1100 , 0x12 , 0x1009, 0x9 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 42. cmov + {"cmovnc", 0x6 , 0x1100 , 0x12 , 0x1009, 0x9 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 43. cmov + {"cmove", 0x6 , 0x1100 , 0x12 , 0x1009, 0x9 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 44. cmov + {"cmovne", 0x6 , 0x1100 , 0x12 , 0x1009, 0x9 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 45. cmov + {"cmovbe", 0x6 , 0x1100 , 0x12 , 0x1009, 0x9 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 46. cmov + {"cmova", 0x6 , 0x1100 , 0x12 , 0x1009, 0x9 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 47. cmov + {"cmovs", 0x6 , 0x1100 , 0x12 , 0x1009, 0x9 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 48. cmov + {"cmovns", 0x6 , 0x1100 , 0x12 , 0x1009, 0x9 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 49. cmov + {"cmovpe", 0x6 , 0x1100 , 0x12 , 0x1009, 0x9 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 4A. cmov + {"cmovpo", 0x6 , 0x1100 , 0x12 , 0x1009, 0x9 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 4B. cmov + {"cmovl", 0x6 , 0x1100 , 0x12 , 0x1009, 0x9 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 4C. cmov + {"cmovge", 0x6 , 0x1100 , 0x12 , 0x1009, 0x9 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 4D. cmov + {"cmovle", 0x6 , 0x1100 , 0x12 , 0x1009, 0x9 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 4E cmov + {"cmovg", 0x6 , 0x1100 , 0x12 , 0x1009, 0x9 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 4F. cmov +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"movmskp", 0xCA , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x9 , 0 }, // 0F 50. Link to movmskps/pd + {"sqrt", 0x76 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x9 , 0 }, // 0F 51. Link to sqrtps/pd/ss/sd + {"rsqrt", 0x77 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x9 , 0 }, // 0F 52. Link to rsqrtps/ss + {"rcp", 0x78 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x9 , 0 }, // 0F 53. Link to rcpps/ss + {"and", 0x11 ,0x8D2200, 0x19 , 0x124F, 0x124F, 0x24F , 0 , 0x21 , 0 , 0 , 0x3 }, // 0F 54. andps/pd + {"andn", 0x11 ,0x8D2200, 0x19 , 0x124F, 0x124F, 0x24F , 0 , 0x21 , 0 , 0 , 0x3 }, // 0F 55. andnps/pd + {"or", 0x11 ,0x8D2200, 0x19 , 0x124F, 0x124F, 0x24F , 0 , 0x21 , 0 , 0 , 0x3 }, // 0F 56. orps/pd + {"xor", 0x11 ,0x8D2200, 0x19 , 0x124F, 0x124F, 0x24F , 0 , 0x21 , 0 , 0 , 0x3 }, // 0F 57. xorps/pd + {"add", 0x11 ,0xE92E00, 0x19 , 0x124F, 0x124F, 0x24F , 0 , 0x37 , 0x1304, 0 , 0x3 }, // 0F 58. addps/pd/ss/sd + {"mul", 0x11 ,0xE92E00, 0x19 , 0x124F, 0x124F, 0x24F , 0 , 0x37 , 0x1304, 0 , 0x3 }, // 0F 59. mulps/pd/ss/sd + {0, 0x49 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x9 , 0 }, // 0F 5A. Link to cvtps2pd, etc. + {0, 0x4A , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x9 , 0 }, // 0F 5B. Link to cvtdq2ps, etc. + {"sub", 0x11 ,0xE92E00, 0x19 , 0x124F, 0x124F, 0x24F , 0 , 0x37 , 0x1304, 0 , 0x3 }, // 0F 5C. subps/pd/ss/sd + {"min", 0x11 ,0xA92E00, 0x19 , 0x124F, 0x124F, 0x24F , 0 , 0x33 , 0 , 0 , 0x3 }, // 0F 5D. minps/pd/ss/sd + {"div", 0x11 ,0xA92E00, 0x19 , 0x124F, 0x124F, 0x24F , 0 , 0x37 , 0 , 0 , 0x3 }, // 0F 5E. divps/pd/ss/sd + {"max", 0x11 ,0xA92E00, 0x19 , 0x124F, 0x124F, 0x24F , 0 , 0x33 , 0 , 0 , 0x3 }, // 0F 5F. maxps/pd/ss/sd +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"punpcklbw", 0x7 ,0x8D0200, 0x19 , 0x1101, 0x1101, 0x101 , 0 , 0 , 0 , 0 , 0x2 }, // 0F 60 + {"punpcklwd", 0x7 ,0x8D2200, 0x19 , 0x1102, 0x1102, 0x102 , 0 , 0 , 0 , 0 , 0x2 }, // 0F 61 + {"punpckldq", 0x7 ,0x8D0200, 0x19 , 0x1103, 0x1103, 0x103 , 0 , 0x21 , 0 , 0 , 0x2 }, // 0F 62 + {"packsswb", 0x7 ,0x8D2200, 0x19 , 0x1201, 0x1202, 0x202 , 0 , 0x20 , 0 , 0 , 0x2 }, // 0F 63 + {"pcmpgtb", 0x118 , 0 , 0x19 , 0 , 0 , 0 , 0 , 0 , 0 , 0xE , 0 }, // 0F 64 + {"pcmpgtw", 0x119 , 0 , 0x19 , 0 , 0 , 0 , 0 , 0 , 0 , 0xE , 0 }, // 0F 65 + {"pcmpgtd", 0xC8 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0xE , 0 }, // 0F 66. link to pcmpgtd + {"packuswb", 0x7 ,0x8D0200, 0x19 , 0x1201, 0x1202, 0x202 , 0 , 0x20 , 0 , 0 , 0x2 }, // 0F 67 + {"punpckhbw", 0x7 ,0x8D2200, 0x19 , 0x1101, 0x1101, 0x101 , 0 , 0x20 , 0 , 0 , 0x2 }, // 0F 68 + {"punpckhwd", 0x7 ,0x8D2200, 0x19 , 0x1102, 0x1102, 0x102 , 0 , 0x20 , 0 , 0 , 0x2 }, // 0F 69 + {"punpckhdq", 0x7 ,0x8D0200, 0x19 , 0x1103, 0x1103, 0x103 , 0 , 0x31 , 0 , 0 , 0x2 }, // 0F 6A + {"packssdw", 0x7 ,0x8D0200, 0x19 , 0x1202, 0x1203, 0x203 , 0 , 0x21 , 0 , 0 , 0x2 }, // 0F 6B + {"punpcklqdq",0x12 ,0x8DB200, 0x19 , 0x1204, 0x1204, 0x204 , 0 , 0x21 , 0 , 0 , 0x2 }, // 0F 6C + {"punpckhqdq",0x12 ,0x8DB200, 0x19 , 0x1204, 0x1204, 0x204 , 0 , 0x21 , 0 , 0 , 0x2 }, // 0F 6D + {0, 0x58 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x8 , 0 }, // 0F 6E. Link to tertiary map: movd/movq + {0, 0x4D , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x9 , 0 }, // 0F 6F. Link to tertiary map: movq/movdqa/movdqu +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {0, 0x4F , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x9 , 0 }, // 0F 70. Link to tertiary map: pshufw, etc. + {0, 0x31 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x2 , 0 }, // 0F 71. Link to tertiary map for group 12 + {0, 0x32 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x2 , 0 }, // 0F 72. Link to tertiary map for group 13 + {0, 0x33 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x2 , 0 }, // 0F 73. Link to tertiary map for group 14 + {"pcmpeqb", 0x116 , 0 , 0x19 , 0 , 0 , 0 , 0 , 0 , 0 , 0xE , 0 }, // 0F 74 + {"pcmpeqw", 0x117 , 0 , 0x19 , 0 , 0 , 0 , 0 , 0 , 0 , 0xE , 0 }, // 0F 75 + {"pcmpeqd", 0xC7 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0xE , 0 }, // 0F 76. link to pcmpeqd + {"emms", 0x79 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0xB , 0 }, // 0F 77. Link to emms, vzeroupper, vzeroall + {0, 0x6C , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x9 , 0 }, // 0F 78. Link to map for wmread, insrtq, extrq + {0, 0x6D , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x9 , 0 }, // 0F 79 without EVEX. Link to map for wmread, insrtq, extrq + {0, 0x6A , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x1 , 0 }, // 0F 7A. Link to map for obsolete 3-byte opcodes AMD SSE5. Note: VEX 0F 7A is in map B1 + {0, 0x6B , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x1 , 0 }, // 0F 7B. Link to map for obsolete 3-byte opcodes AMD SSE5. Note: VEX 0F 7B is in map B1 + {0, 0x5C , 0xA00 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x9 , 0 }, // 0F 7C. Link to map: hadd + {0, 0x5D , 0xA00 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x9 , 0 }, // 0F 7D. Link to map: hsub + {0, 0x59 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x9 , 0 }, // 0F 7E. Link to map: movd/movq + {0, 0x4E , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x9 , 0 }, // 0F 7F. Link to map: movq/movdqa/movdqu +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"jo", 0x3 , 0x8 , 0x80 , 0x82 , 0 , 0 , 0 , 0 , 0 , 0 , 0xA0 }, // 0F 80 + {"jno", 0x3 , 0x8 , 0x80 , 0x82 , 0 , 0 , 0 , 0 , 0 , 0 , 0xA0 }, // 0F 81 + {"jc", 0x3 , 0x8 , 0x80 , 0x82 , 0 , 0 , 0 , 0 , 0 , 0 , 0xA0 }, // 0F 82 + {"jnc", 0x3 , 0x8 , 0x80 , 0x82 , 0 , 0 , 0 , 0 , 0 , 0 , 0xA0 }, // 0F 83 + {"je", 0x3 , 0x8 , 0x80 , 0x82 , 0 , 0 , 0 , 0 , 0 , 0 , 0xA0 }, // 0F 84 + {"jne", 0x3 , 0x8 , 0x80 , 0x82 , 0 , 0 , 0 , 0 , 0 , 0 , 0xA0 }, // 0F 85 + {"jbe", 0x3 , 0x8 , 0x80 , 0x82 , 0 , 0 , 0 , 0 , 0 , 0 , 0xA0 }, // 0F 86 + {"ja", 0x3 , 0x8 , 0x80 , 0x82 , 0 , 0 , 0 , 0 , 0 , 0 , 0xA0 }, // 0F 87 + {"js", 0x3 , 0x8 , 0x80 , 0x82 , 0 , 0 , 0 , 0 , 0 , 0 , 0xA0 }, // 0F 88 + {"jns", 0x3 , 0x8 , 0x80 , 0x82 , 0 , 0 , 0 , 0 , 0 , 0 , 0xA0 }, // 0F 89 + {"jpe", 0x3 , 0x8 , 0x80 , 0x82 , 0 , 0 , 0 , 0 , 0 , 0 , 0xA0 }, // 0F 8A + {"jpo", 0x3 , 0x8 , 0x80 , 0x82 , 0 , 0 , 0 , 0 , 0 , 0 , 0xA0 }, // 0F 8B + {"jl", 0x3 , 0x8 , 0x80 , 0x82 , 0 , 0 , 0 , 0 , 0 , 0 , 0xA0 }, // 0F 8C + {"jge", 0x3 , 0x8 , 0x80 , 0x82 , 0 , 0 , 0 , 0 , 0 , 0 , 0xA0 }, // 0F 8D + {"jle", 0x3 , 0x8 , 0x80 , 0x82 , 0 , 0 , 0 , 0 , 0 , 0 , 0xA0 }, // 0F 8E + {"jg", 0x3 , 0x8 , 0x80 , 0x82 , 0 , 0 , 0 , 0 , 0 , 0 , 0xA0 }, // 0F 8F +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"seto", 0x3 , 0 , 0x11 , 0x1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 90 + {"setno", 0x3 , 0 , 0x11 , 0x1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 91 + {"setb", 0x3 , 0 , 0x11 , 0x1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 92 + {"setae", 0x3 , 0 , 0x11 , 0x1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 93 + {"sete", 0x3 , 0 , 0x11 , 0x1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 94 + {"setne", 0x3 , 0 , 0x11 , 0x1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 95 + {"setbe", 0x3 , 0 , 0x11 , 0x1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 96 + {"seta", 0x3 , 0 , 0x11 , 0x1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 97 + {"sets", 0x3 , 0 , 0x11 , 0x1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 98 + {"setns", 0x3 , 0 , 0x11 , 0x1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 99 + {"setpe", 0x3 , 0 , 0x11 , 0x1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 9A + {"setpo", 0x3 , 0 , 0x11 , 0x1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 9B + {"setl", 0x3 , 0 , 0x11 , 0x1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 9C + {"setge", 0x3 , 0 , 0x11 , 0x1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 9D + {"setle", 0x3 , 0 , 0x11 , 0x1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 9E + {"setg", 0x3 , 0 , 0x11 , 0x1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 9F +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"push fs", 0x3 , 0x2 , 0x1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F A0 + {"pop fs", 0x3 , 0x2 , 0x1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F A1 + {"cpuid", 0x4 , 0 , 0x1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x8 }, // 0F A2 + {"bt", 0x3 , 0x1100 , 0x13 , 0x9 , 0x1009, 0 , 0 , 0 , 0 , 0 , 0 }, // 0F A3 + {"shld", 0x3 , 0x1100 , 0x53 , 0x9 , 0x1009, 0x11 , 0 , 0 , 0 , 0 , 0 }, // 0F A4 + {"shld", 0x3 , 0x1100 , 0x13 , 0x9 , 0x9 , 0xB3 , 0 , 0 , 0 , 0 , 0 }, // 0F A5 + {0, 0xA6 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x4 , 0 }, // 0F A6. Link to VIA instructions + {0, 0xA7 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x4 , 0 }, // 0F A7. Link to VIA instructions + {"push gs", 0x3 , 0x2 , 0x1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F A8 + {"pop gs", 0x3 , 0x2 , 0x1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F A9 + {"rsm", 0x803 , 0 , 0x1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F AA + {"bts", 0x3 , 0x1D50 , 0x13 , 0x9 , 0x1009, 0 , 0 , 0 , 0 , 0 , 0 }, // 0F AB + {"shrd", 0x3 , 0x1100 , 0x53 , 0x9 , 0x1009, 0x11 , 0 , 0 , 0 , 0 , 0 }, // 0F AC + {"shrd", 0x3 , 0x1100 , 0x13 , 0x9 , 0x9 , 0xB3 , 0 , 0 , 0 , 0 , 0 }, // 0F AD + {0, 0x34 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x4 , 0 }, // 0F AE. Link to tertiary map for group 15 + {"imul", 0x1 , 0x1100 , 0x12 , 0x1009, 0x9 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F AF +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"cmpxchg", 0x3 , 0xC50 , 0x13 , 0x2001, 0x1001, 0 , 0 , 0 , 0 , 0 , 0 }, // 0F B0 + {"cmpxchg", 0x3 , 0x1D50 , 0x13 , 0x2009, 0x1009, 0 , 0 , 0 , 0 , 0 , 0 }, // 0F B1 + {"lss", 0 , 0x1100 , 0x812 , 0x1009, 0x200D, 0 , 0 , 0 , 0 , 0 , 0 }, // 0F B2 (valid in 64-bit mode) + {"btr", 0x3 , 0x1D50 , 0x13 , 0x9 , 0x1009, 0 , 0 , 0 , 0 , 0 , 0 }, // 0F B3 + {"lfs", 0 , 0x1100 , 0x812 , 0x1009, 0x200D, 0 , 0 , 0 , 0 , 0 , 0 }, // 0F B4 + {"lgs", 0 , 0x1100 , 0x812 , 0x1009, 0x200D, 0 , 0 , 0 , 0 , 0 , 0 }, // 0F B5 + {"movzx", 0x3 , 0x1100 , 0x12 , 0x1009, 0x1 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F B6 + {"movzx", 0x3 , 0x1100 , 0x12 , 0x1009, 0x2 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F B7 + {0, 0x60 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x9 , 0 }, // 0F B8. Link to tertiary map for popcnt, jmpe + {0, 0x2E , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x2 , 0 }, // 0F B9. Link to tertiary map for group 10: ud1 + {0, 0x2C , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x2 , 0 }, // 0F BA. Link to tertiary map for group 8: bt + {"btc", 0x3 , 0x1D50 , 0x13 , 0x9 , 0x1009, 0 , 0 , 0 , 0 , 0 , 0 }, // 0F BB + {"bsf", 0xAE , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x9 , 0 }, // 0F BC. Link to bsf etc. + {0, 0xD3 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x9 , 0 }, // 0F BD. Link to tertiary map for BSR and LZCNT + {"movsx", 0x3 , 0x1100 , 0x12 , 0x1009, 0x1 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F BE + {"movsx", 0x3 , 0x1100 , 0x12 , 0x1009, 0x2 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F BF +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"xadd", 0x4 , 0x0C50 , 0x13 , 0x1 , 0x1001, 0 , 0 , 0 , 0 , 0 , 0 }, // 0F C0 + {"xadd", 0x4 , 0x1D50 , 0x13 , 0x9 , 0x1009, 0 , 0 , 0 , 0 , 0 , 0 }, // 0F C1 + {0, 0xF5 , 0 , 0x52 , 0 , 0 , 0 , 0 , 0 , 0 , 0x11 , 0 }, // 0F C2. Link to cmpps etc. + {"movnti", 0x11 , 0x1000 , 0x13 , 0x2009, 0x1009, 0 , 0 , 0 , 0 , 0 , 0 }, // 0F C3 + {0, 0x29 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x3 , 0 }, // 0F C4. Link to pinsrw + {"pextrw", 0x7 ,0x812200, 0x52 , 0x1002, 0x1102, 0x11 , 0 , 0x1000, 0 , 0 , 0x2 }, // 0F C5 + {"shuf", 0x11 ,0x8D2200, 0x59 , 0x124F, 0x124F, 0x24F , 0x11 , 0x31 , 0 , 0 , 0x3 }, // 0F C6 + {0, 0x50 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x2 , 0 }, // 0F C7. Link to tertiary map for group 9 + {"bswap", 0x3 , 0x1000 , 0x3 , 0x1009, 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F C8. bswap eax + {"bswap", 0x3 , 0x1000 , 0x3 , 0x1009, 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F C9. bswap ecx + {"bswap", 0x3 , 0x1000 , 0x3 , 0x1009, 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F CA. bswap edx + {"bswap", 0x3 , 0x1000 , 0x3 , 0x1009, 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F CB. bswap ebx + {"bswap", 0x3 , 0x1000 , 0x3 , 0x1009, 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F CC. bswap esp + {"bswap", 0x3 , 0x1000 , 0x3 , 0x1009, 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F CD. bswap ebp + {"bswap", 0x3 , 0x1000 , 0x3 , 0x1009, 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F CE. bswap esi + {"bswap", 0x3 , 0x1000 , 0x3 , 0x1009, 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F CF. bswap edi +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {0, 0x2D , 0xA00 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x9 , 0 }, // 0F D0. Link to addsubps/pd + {"psrlw", 0x99 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x0D , 0 }, // 0F D1. Link to map for psrlw + {"psrld", 0x9A , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x0D , 0 }, // 0F D2. Link to map for psrld + {"psrlq", 0x9B , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x0D , 0 }, // 0F D3. Link to map for psrlq + {"paddq", 0x12 ,0x8D3200, 0x19 , 0x1204, 0x1204, 0x204 , 0 , 0x21 , 0 , 0 , 0x2 }, // 0F D4 + {"pmullw", 0x7 ,0x8DA200, 0x19 , 0x1102, 0x1102, 0x102 , 0 , 0x20 , 0 , 0 , 0x2 }, // 0F D5 + {0, 0x53 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x9 , 0 }, // 0F D6. Link to tertiary map for movq2dq etc. + {"pmovmskb", 0x93 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x0B , 0 }, // 0F D7. Link pmovmskb + {"psubusb", 0x7 ,0x8D2200, 0x19 , 0x1101, 0x1101, 0x101 , 0 , 0x20 , 0 , 0 , 0x2 }, // 0F D8 + {"psubusw", 0x7 ,0x8D2200, 0x19 , 0x1102, 0x1102, 0x102 , 0 , 0x20 , 0 , 0 , 0x2 }, // 0F D9 + {"pminub", 0x7 ,0x8D0200, 0x19 , 0x1101, 0x1101, 0x101 , 0 , 0x20 , 0 , 0 , 0x2 }, // 0F DA + {"pand", 0xC2 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0xE , 0 }, // 0F DB. link to pand + {"paddusb", 0x7 ,0x8D2200, 0x19 , 0x1201, 0x1201, 0x201 , 0 , 0x20 , 0 , 0 , 0x2 }, // 0F DC + {"paddusw", 0x7 ,0x8D2200, 0x19 , 0x1202, 0x1202, 0x202 , 0 , 0x20 , 0 , 0 , 0x2 }, // 0F DD + {"pmaxub", 0x7 ,0x8D2200, 0x19 , 0x1101, 0x1101, 0x101 , 0 , 0x20 , 0 , 0 , 0x2 }, // 0F DE + {"pandn", 0xC3 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0xE , 0 }, // 0F DF. link to pandn +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"pavgb", 0x7 ,0x8D2200, 0x19 , 0x1201, 0x1201, 0x201 , 0 , 0x20 , 0 , 0 , 0x2 }, // 0F E0 + {"psraw", 0x9C , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x0D , 0 }, // 0F E1. Link to map for psraw + {"psrad", 0x9D , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x0D , 0 }, // 0F E2. Link to map for psrad + {"pavgw", 0x7 ,0x8D2200, 0x19 , 0x1202, 0x1202, 0x202 , 0 , 0x20 , 0 , 0 , 0x2 }, // 0F E3 + {"pmulhuw", 0x7 ,0x8DA200, 0x19 , 0x1102, 0x1102, 0x102 , 0 , 0x20 , 0 , 0 , 0x2 }, // 0F E4 + {"pmulhw", 0x7 ,0x8DA200, 0x19 , 0x1102, 0x1102, 0x102 , 0 , 0x20 , 0 , 0 , 0x2 }, // 0F E5 + {0, 0x54 , 0xE00 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x9 , 0 }, // 0F E6. Link to tertiary map for cvtpd2dq etc. + {0, 0x55 , 0x200 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x9 , 0 }, // 0F E7. Link to tertiary map for movntq + {"psubsb", 0x7 ,0x8D2200, 0x19 , 0x1101, 0x1101, 0x101 , 0 , 0x20 , 0 , 0 , 0x2 }, // 0F E8 + {"psubsw", 0x7 ,0x8D2200, 0x19 , 0x1102, 0x1102, 0x102 , 0 , 0x20 , 0 , 0 , 0x2 }, // 0F E9 + {"pminsw", 0x7 ,0x8D2200, 0x19 , 0x1102, 0x1102, 0x102 , 0 , 0x20 , 0 , 0 , 0x2 }, // 0F EA + {"por", 0xC4 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0xE , 0 }, // 0F EB. link to por + {"paddsb", 0x7 ,0x8D2200, 0x19 , 0x1201, 0x1201, 0x201 , 0 , 0x20 , 0 , 0 , 0x2 }, // 0F EC + {"paddsw", 0x7 ,0x8D2200, 0x19 , 0x1202, 0x1202, 0x202 , 0 , 0x20 , 0 , 0 , 0x2 }, // 0F ED + {"pmaxsw", 0x7 ,0x8D2200, 0x19 , 0x1102, 0x1102, 0x102 , 0 , 0x20 , 0 , 0 , 0x2 }, // 0F EE + {"pxor", 0xC5 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0xE , 0 }, // 0F EF. link to pxor +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {0, 0x56 , 0x800 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x9 , 0 }, // 0F F0. Link to tertiary map for lddqu + {"psllw", 0x96 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x0D , 0 }, // 0F F1. Link to map for psllw + {"pslld", 0x97 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x0D , 0 }, // 0F F2. Link to map for pslld + {"psllq", 0x98 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x0D , 0 }, // 0F F3. Link to map for psllq + {"pmuludq", 0x7 ,0x8D2200, 0x19 , 0x1104, 0x1104, 0x104 , 0 , 0x31 , 0 , 0 , 0x2 }, // 0F F4 (32 bit memory operand is broadcast as 64 bit into every second dword) + {"pmaddwd", 0x7 ,0x8D2200, 0x19 , 0x1103, 0x1102, 0x102 , 0 , 0x20 , 0 , 0 , 0x2 }, // 0F F5 + {"psadbw", 0x7 ,0x8D2200, 0x19 , 0x1102, 0x1101, 0x101 , 0 , 0 , 0 , 0 , 0x2 }, // 0F F6 + {0, 0x57 , 0x200 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x9 , 0 }, // 0F F7. Link to tertiary map for maskmovq + {"psubb", 0x7 ,0x8D2200, 0x19 , 0x1101, 0x1101, 0x101 , 0 , 0x20 , 0 , 0 , 0x2 }, // 0F F8 + {"psubw", 0x7 ,0x8D2200, 0x19 , 0x1102, 0x1102, 0x102 , 0 , 0x20 , 0 , 0 , 0x2 }, // 0F F9 + {"psubd", 0x7 ,0xCD0200, 0x19 , 0x1103, 0x1103, 0x103 , 0 , 0x21 , 0x1406, 0 , 0x2 }, // 0F FA + {"psubq", 0x7 ,0x8D2200, 0x19 , 0x1104, 0x1104, 0x104 , 0 , 0x21 , 0 , 0 , 0x2 }, // 0F FB + {"paddb", 0x7 ,0x8D2200, 0x19 , 0x1201, 0x1201, 0x201 , 0 , 0x20 , 0 , 0 , 0x2 }, // 0F FC + {"paddw", 0x7 ,0x8D2200, 0x19 , 0x1202, 0x1202, 0x202 , 0 , 0x20 , 0 , 0 , 0x2 }, // 0F FD + {"paddd", 0x7 ,0xCD0200, 0x19 , 0x1103, 0x1103, 0x103 , 0 , 0x31 , 0x1406, 0 , 0x2 }, // 0F FE + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }}; // 0F FF + + +// Tertiary opcode map for 3-byte opcode. First two bytes = 0F 38 +// or VEX encoded with mmmm = 2 +// Indexed by third opcode byte +SOpcodeDef OpcodeMap2[] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"pshufb", 0x14 ,0x8D2200, 0x19 , 0x1101, 0x1101, 0x101 , 0 , 0x20 , 0 , 0 , 0x2 }, // 0F 38 00 + {"phaddw", 0x14 , 0xD0200, 0x19 , 0x1102, 0x1102, 0x102 , 0 , 0 , 0 , 0 , 0x2 }, // 0F 38 01 + {"phaddd", 0x14 , 0xD0200, 0x19 , 0x1103, 0x1103, 0x103 , 0 , 0 , 0 , 0 , 0x2 }, // 0F 38 02 + {"phaddsw", 0x14 , 0xD0200, 0x19 , 0x1102, 0x1102, 0x102 , 0 , 0 , 0 , 0 , 0x2 }, // 0F 38 03 + {"pmaddubsw", 0x14 ,0x8D2200, 0x19 , 0x1102, 0x1101, 0x101 , 0 , 0x20 , 0 , 0 , 0x2 }, // 0F 38 04 + {"phsubw", 0x14 , 0xD0200, 0x19 , 0x1102, 0x1102, 0x102 , 0 , 0 , 0 , 0 , 0x2 }, // 0F 38 05 + {"phsubd", 0x14 , 0xD0200, 0x19 , 0x1103, 0x1103, 0x103 , 0 , 0 , 0 , 0 , 0x2 }, // 0F 38 06 + {"phsubsw", 0x14 , 0xD0200, 0x19 , 0x1102, 0x1102, 0x102 , 0 , 0 , 0 , 0 , 0x2 }, // 0F 38 07 + {"psignb", 0x14 , 0xD0200, 0x19 , 0x1101, 0x1101, 0x101 , 0 , 0 , 0 , 0 , 0x2 }, // 0F 38 08 + {"psignw", 0x14 , 0xD0200, 0x19 , 0x1102, 0x1102, 0x102 , 0 , 0 , 0 , 0 , 0x2 }, // 0F 38 09 + {"psignd", 0x14 , 0xD0200, 0x19 , 0x1103, 0x1103, 0x103 , 0 , 0 , 0 , 0 , 0x2 }, // 0F 38 0A + + {"pmulhrsw", 0x14 ,0x8DA200, 0x19 , 0x1102, 0x1102, 0x102 , 0 , 0x20 , 0 , 0 , 0x2 }, // 0F 38 0B + {"vpermilps", 0x19 ,0x8FA200, 0x19 , 0x124B, 0x124B, 0x24B , 0 , 0x31 , 0 , 0 , 0 }, // 0F 38 0C + {"vpermilpd", 0x19 ,0x8FA200, 0x19 , 0x124C, 0x124C, 0x24C , 0 , 0x31 , 0 , 0 , 0 }, // 0F 38 0D + {"vtestps", 0x19 , 0x78200, 0x12 , 0x124B, 0x24B , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 0E + {"vtestpd", 0x19 , 0x78200, 0x12 , 0x124B, 0x24B , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 0F + +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {0, 0xEA , 0 , 0x12 , 0 , 0 , 0 , 0 , 0 , 0 , 0x11 , 0 }, // 0F 38 10. Link pblendvb and vpsrlvw + {"vpsravw", 0x1C ,0x8FC200, 0x19 , 0x1209, 0x1209, 0x209 , 0 , 0x20 , 0 , 0 , 0 }, // 0F 38 11 + {"vpsllvw", 0x20 ,0x8FC200, 0x19 , 0x1209, 0x1209, 0x209 , 0 , 0x20 , 0 , 0 , 0 }, // 0F 38 12 + {"vcvtph2ps", 0x19 ,0x878200, 0x12 , 0x250 , 0xF4A , 0 , 0 , 0x2232, 0 , 0 , 0 }, // 0F 38 13 + {0, 0x8D , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0xB , 0 }, // 0F 38 14. Link to vprorvd blendvps and vpmovqw + {0, 0x8E , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0xB , 0 }, // 0F 38 15. Link to vprolvd blendvpd and vpmovqd + {"vpermp", 0x1C ,0x9F9200 ,0x19 , 0x124F, 0x1203, 0x24F , 0 , 0x31 , 0 , 0 , 0x1 }, // 0F 38 16 + {"ptest", 0x15 , 0x58200, 0x12 , 0x1250, 0x250 , 0 , 0 , 0 , 0 , 0 , 0x2 }, // 0F 38 17. Also in AMD SSE5 instruction set + {"vbroadcastss",0x19,0xC78200, 0x12 , 0x124B, 0x04B , 0 , 0 , 0x20 , 0x1048, 0 , 0 }, // 0F 38 18 + {0, 0x12A , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x0E , 0 }, // 0F 38 19. Link to vbroadcastsd + {0, 0xE5 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x0C , 0 }, // 0F 38 1A. Link to broadcast instructions + {0, 0x38 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x0C , 0 }, // 0F 38 1B. Link to vbroadcastf64x4 + {"pabsb", 0x14 ,0x85A200, 0x12 , 0x1201, 0x201 , 0 , 0 , 0x20 , 0 , 0 , 0x2 }, // 0F 38 1C + {"pabsw", 0x14 ,0x85A200, 0x12 , 0x1202, 0x202 , 0 , 0 , 0x20 , 0 , 0 , 0x2 }, // 0F 38 1D + {"pabsd", 0x14 ,0x85B200, 0x12 , 0x1203, 0x203 , 0 , 0 , 0x31 , 0 , 0 , 0x2 }, // 0F 38 1E + {"vpabsq", 0x20 ,0x85B200, 0x12 , 0x1203, 0x203 , 0 , 0 , 0x31 , 0 , 0 , 0x0 }, // 0F 38 1F +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {0, 0x7A , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x3 , 0 }, // 0F 38 20. Link pmovsxbw + {0, 0x7B , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x3 , 0 }, // 0F 38 21. Link pmovsxbd and vpmovdb + {0, 0x7D , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x3 , 0 }, // 0F 38 22. Link pmovsxbq and vpmovqb + {0, 0x7F , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x3 , 0 }, // 0F 38 23. Link pmovsxwd and vpmovdw + {0, 0x80 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x3 , 0 }, // 0F 38 24. Link pmovsxwq and vpmovqw + {0, 0x82 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x3 , 0 }, // 0F 38 25. Link pmovsxdq and vpmovqd + {"vptestm", 0x20 ,0x8BC200, 0x19 , 0x95 , 0x1209, 0x209 , 0 , 0x10 , 0 , 0 , 1 }, // 0F 38 27 + {"vptestm", 0x20 ,0xCBB200, 0x19 , 0x95 , 0x1209, 0x209 , 0 , 0x11 , 0x1406, 0 , 1 }, // 0F 38 27 + {"pmuldq", 0x15 ,0x8DA200, 0x19 , 0x1204, 0x1204, 0x204 , 0 , 0x31 , 0 , 0 , 0x2 }, // 0F 38 28 (32 bit memory operand is broadcast as 64 bit into every second dword) + {0, 0xE3 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0xE , 0 }, // 0F 38 29. Link to pcmpeqq + {0, 0x91 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x9 , 0 }, // 0F 38 2A. Link to movntdqa and vpbroadcastmb2q + {"packusdw", 0x15 ,0x8D8200, 0x19 , 0x1202, 0x1203, 0x203 , 0 , 0x21 , 0 , 0 , 0x2 }, // 0F 38 2B + {0, 0xFD , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0xE , 0 }, // 0F 38 2C. Link to vmaskmovps and vscalefps + {0, 0xFE , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0xE , 0 }, // 0F 38 2D. Link to vmaskmovss and vscalefss + {"vmaskmovps",0x19 , 0xF8200, 0x1A, 0x224B, 0x124B, 0x124B, 0 , 0 , 0 , 0 , 0 }, // 0F 38 2E + {"vmaskmovpd",0x19 , 0xF8200, 0x1A, 0x224C, 0x124C, 0x124C, 0 , 0 , 0 , 0 , 0 }, // 0F 38 2F +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {0, 0x83 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x3 , 0 }, // 0F 38 30. Link pmovzxbv + {0, 0x85 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x3 , 0 }, // 0F 38 31. Link pmovzxbd and vpmovdb + {0, 0x87 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x3 , 0 }, // 0F 38 32. Link pmovzxbq and vpmovqb + {0, 0x89 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x3 , 0 }, // 0F 38 33. Link pmovzxwd and vpmovdw + {0, 0x8A , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x3 , 0 }, // 0F 38 34. Link pmovzxwq and vpmovqw + {0, 0x8C , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x3 , 0 }, // 0F 38 35. Link pmovzxdq and vpmovqd + {"vperm", 0x1C , 0xCFB200,0x19 , 0x1209, 0x1209, 0x209 , 0 , 0x31 , 0x1000, 0 , 0x1 }, // 0F 38 36 + {0, 0xE4 , 0 , 0x19 , 0 , 0 , 0 , 0 , 0 , 0 , 0xE , 0 }, // 0F 38 37 + {0, 0x12C , 0 , 0x19 , 0 , 0 , 0 , 0 , 0 , 0 , 0x9 , 0 }, // 0F 38 38. Link to pminsb etc. + {0, 0xE6 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0xE , 0 }, // 0F 38 39. Link pminsd + {0, 0xFF , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x9 , 0 }, // 0F 38 3A + {0 , 0xE7 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0xE , 0x2 }, // 0F 38 3B. Link pminud + {"pmaxsb", 0x15 ,0x8DA200, 0x19 , 0x1201, 0x1201, 0x201 , 0 , 0x20 , 0 , 0 , 0x2 }, // 0F 38 3C + {0, 0xE8 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0xE , 0 }, // 0F 38 3D. Link pmaxsd + {"pmaxuw", 0x15 ,0x8DA200, 0x19 , 0x1202, 0x1202, 0x202 , 0 , 0x20 , 0 , 0 , 0x2 }, // 0F 38 3E + {0, 0xE9 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0xE , 0 }, // 0F 38 3F. Link pmaxud +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"pmull", 0x15 ,0xCDB200, 0x19 , 0x1203, 0x1203, 0x203 , 0 , 0x31 , 0x1406, 0 , 0x3 }, // 0F 38 40 + {"phminposuw",0x15 ,0x18200, 0x12 , 0x1402, 0x402 , 0 , 0 , 0 , 0 , 0 , 0x2 }, // 0F 38 41 + {"vgetexpp", 0x20 ,0xC29200, 0x12 , 0x124F, 0x24F , 0 , 0 , 0x33 , 0x1204, 0 , 0x101 }, // 0F 38 42 + {"vgetexps", 0x20 ,0xCA9200, 0x19 , 0x144F, 0x24F , 0x04F , 0 , 0x32 , 0x1204, 0 , 0x101 }, // 0F 38 43 + {"vplzcnt", 0x21 ,0x80B200, 0x12 , 0x1209, 0x0209, 0 , 0 , 0x31 , 0 , 0 , 0x1 }, // 0F 38 44 + {"vpsrlv", 0x1C ,0xCFB200, 0x19 , 0x1209, 0x1209, 0x209 , 0 , 0x31 , 0x1406, 0 , 0x1 }, // 0F 38 45 + {"vpsrav", 0x1C ,0xCFB200, 0x19 , 0x1209, 0x1209, 0x209 , 0 , 0x31 , 0x1406, 0 , 0x1 }, // 0F 38 46 + {"vpsllv", 0x1C ,0xCFB200, 0x19 , 0x1209, 0x1209, 0x209 , 0 , 0x31 , 0x1406, 0 , 0x1 }, // 0F 38 47 + {"(reserved)",0x0 ,0x4D2E00, 0x4012, 0x609 , 0x609 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 48 + {"(reserved)",0x0 ,0x4D2E00, 0x4012, 0x609 , 0x609 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 49 + {"(reserved)",0x0 ,0x4D2E00, 0x4012, 0x609 , 0x609 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 4A + {"(reserved)",0x0 ,0x4D2E00, 0x4012, 0x609 , 0x609 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 4B + {"vrcp14p" ,0x20 ,0x8D9200, 0x12 , 0x124F, 0x024F, 0 , 0 , 0x31 , 0 , 0 , 0x1 }, // 0F 38 4C + {"vrcp14s" ,0x20 ,0x8D9200, 0x19 , 0x144F, 0x144F, 0x004F, 0 , 0x30 , 0 , 0 , 0x1 }, // 0F 38 4D + {"vrsqrt14p", 0x20 ,0x8D9200, 0x12 , 0x124F, 0x024F, 0 , 0 , 0x31 , 0 , 0 , 0x1 }, // 0F 38 4E + {"vrsqrt14s", 0x20 ,0x8D9200, 0x19 , 0x144F, 0x144F, 0x004F, 0 , 0x30 , 0 , 0 , 0x1 }, // 0F 38 4F +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"vaddnp", 0x80 ,0x4A9200, 0x19, 0x164F, 0x164F, 0x64F , 0 , 0 , 0x1304, 0 , 0x101 }, // 0F 38 50 + {"vgmaxabsps",0x80 ,0x428200, 0x12 , 0x164F, 0x64F , 0 , 0 , 0 , 0x1204, 0 , 0x100 }, // 0F 38 51 + {"vgminp", 0x80 ,0x429200, 0x12 , 0x164F, 0x64F , 0 , 0 , 0 , 0x1204, 0 , 0x101 }, // 0F 38 52 + {"vgmaxp", 0x80 ,0x429200, 0x12 , 0x164F, 0x64F , 0 , 0 , 0 , 0x1204, 0 , 0x101 }, // 0F 38 53 + {"(reserved)",0x00 ,0x4D2E00, 0x4012, 0x609 , 0x609 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 54 + {"vfixupnanp",0x80 ,0x4A9200, 0x19, 0x164F, 0x164F, 0x603 , 0 , 0 , 0x1206, 0 , 0x101 }, // 0F 38 55 + {"(reserved)",0x00 ,0x4D2E00, 0x4012, 0x609 , 0x609 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 56 + {"(reserved)",0x00 ,0x4D2E00, 0x4012, 0x609 , 0x609 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 57 + {"vpbroadcastd",0xA0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x3 , 0 }, // 0F 38 58. Link to vpbroadcastd + {"vpbroadcastq",0xA1, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x3 , 0 }, // 0F 38 59. Link to vpbroadcastq + {0, 0x84 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x0D , 0 }, // 0F 38 5A. Link to broadcast instructions + {"vbroadcasti64x4",0x80,0xC29200,0x12, 0x1604, 0x2504, 0 , 0 , 0x20 , 0x1013, 0 , 0x100 }, // 0F 38 5B + {"vpadcd", 0x80 , 0x4A8200,0x19 , 0x1603, 0x95 , 0x603 , 0 , 0 , 0x1406, 0 , 0x100 }, // 0F 38 5C + {"vpaddsetcd",0x80 , 0x4A8200,0x19 , 0x1603, 0x95 , 0x603 , 0 , 0 , 0x1406, 0 , 0x100 }, // 0F 38 5D + {"vpsbbd", 0x80 , 0x4A8200,0x19 , 0x1603, 0x95 , 0x603 , 0 , 0 , 0x1406, 0 , 0x100 }, // 0F 38 5E + {"vpsubsetbd",0x80 , 0x4A8200,0x19 , 0x1603, 0x95 , 0x603 , 0 , 0 , 0x1406, 0 , 0x100 }, // 0F 38 5F +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {0, 0 , 0 , 0x2012, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 60 + {0, 0 , 0 , 0x2012, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 61 + {0, 0 , 0 , 0x2012, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 62 + {0, 0 , 0 , 0x2012, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 63 + {"vpblendm", 0x20 ,0xCAB200, 0x19, 0x1209, 0x1209, 0x209 , 0 , 0x21 , 0x1406, 0 , 0x001 }, // 0F 38 64 (alignment required only in Knights Corner) + {"vblendmp", 0x80 ,0xCA9200, 0x19, 0x124F, 0x124F, 0x24F , 0 , 0x21 , 0x1404, 0 , 0x101 }, // 0F 38 65 + {"vpblendm", 0x20 ,0x8AC200, 0x19, 0x1209, 0x1209, 0x209 , 0 , 0x21 , 0x1406, 0 , 0x001 }, // 0F 38 66 + {"(reserved)",0x00 ,0x4D2E00, 0x4012, 0x609 , 0x609 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 67 + {"(reserved)",0x00 ,0x4D2E00, 0x4012, 0x609 , 0x609 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 68 + {"(reserved)",0x00 ,0x4D2E00, 0x4012, 0x609 , 0x609 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 69 + {"(reserved)",0x00 ,0x4D2E00, 0x4012, 0x609 , 0x609 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 6A + {"(reserved)",0x00 ,0x4D2E00, 0x4012, 0x609 , 0x609 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 6B + {"vpsubrd", 0x80 , 0x4A8200,0x19 , 0x1603, 0x95 , 0x603 , 0 , 0 , 0x1406, 0 , 0x100 }, // 0F 38 6C + {"vsubrp", 0x80 ,0x4A9200, 0x19, 0x164F, 0x164F, 0x64F , 0 , 0 , 0x1304, 0 , 0x101 }, // 0F 38 6D + {"vpsbbrd", 0x80 , 0x4A8200,0x19 , 0x1603, 0x95 , 0x603 , 0 , 0 , 0x1406, 0 , 0x100 }, // 0F 38 6E + {"vpsubrsetbd",0x80 , 0x4A8200,0x19 , 0x1603, 0x95 , 0x603 , 0 , 0 , 0x1406, 0 , 0x100 }, // 0F 38 6F +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"(reserved)",0x00 ,0x4D2E00, 0x4012, 0x609 , 0x609 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 70 + {"(reserved)",0x00 ,0x4D2E00, 0x4012, 0x609 , 0x609 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 71 + {"(reserved)",0x00 ,0x4D2E00, 0x4012, 0x609 , 0x609 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 72 + {"(reserved)",0x00 ,0x4D2E00, 0x4012, 0x609 , 0x609 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 73 + {"vpcmpltd", 0x80 ,0x4B8200, 0x19 , 0x95 , 0x1603, 0x603 , 0 , 0 , 0x1406, 0 , 0x100 }, // 0F 38 74 + {"vpermi2" , 0x23 ,0x8EC200, 0x19, 0x1209, 0x1209, 0x209 , 0 , 0x20 , 0 , 0 , 1 }, // 0F 38 75 (instruction set avx512vbmi for byte version) + {"vpermi2", 0x20 ,0x8AB200, 0x19, 0x1609, 0x1609, 0x0609, 0 , 0x31 , 0 , 0 , 0x1 }, // 0F 38 76 + {"vpermi2p", 0x20 ,0x8A9200, 0x19, 0x164F, 0x164F, 0x064F, 0 , 0x31 , 0 , 0 , 0x1 }, // 0F 38 77 + {"vpbroadcastb",0x9E, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x3 , 0 }, // 0F 38 78. Link to vpbroadcastb + {"vpbroadcastw",0x9F, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x3 , 0 }, // 0F 38 79. Link to vpbroadcastw + {"vpbroadcastb",0x20,0x828200, 0x12, 0x1201, 0x1001, 0 , 0 , 0x20 , 0 , 0 , 0 }, // 0F 38 7A + {"vpbroadcastw",0x20,0x828200, 0x12, 0x1202, 0x1002, 0 , 0 , 0x20 , 0 , 0 , 0 }, // 0F 38 7B + {"vpbroadcast",0x20 ,0x82B200, 0x12, 0x1209, 0x1009, 0 , 0 , 0x20 , 0 , 0 , 0x1 }, // 0F 38 7C + {"vpermt2" , 0x20 ,0x8EC200, 0x19, 0x1209, 0x1209, 0x209 , 0 , 0x20 , 0 , 0 , 1 }, // 0F 38 7D (instruction set avx512vbmi for byte version) + {"vpermt2", 0x20 ,0x8AB200, 0x19, 0x1209, 0x1209, 0x209 , 0 , 0x21 , 0 , 0 , 0x1 }, // 0F 38 7E + {"vpermt2p", 0x20 ,0x8A9200, 0x19, 0x164F, 0x164F, 0x064F, 0 , 0x21 , 0 , 0 , 0x1 }, // 0F 38 7F +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {0, 0 , 0 , 0x2012, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 80 + {0, 0 , 0 , 0x2012, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 81 + {"invpcid", 0x81D , 0x9200 , 0x12 , 0x1009, 0x2406, 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 82 + {"vpmultishiftqb",0x23,0x8E9200,0x19 , 0x1204, 0x1204, 0x204 , 0 , 0x21 , 0 , 0 , 0 }, // 0F 38 83 + {"vscaleps", 0x80 ,0x4B8200, 0x19 , 0x164B, 0x164B, 0x603 , 0 , 0 , 0x1306, 0 , 0x100 }, // 0F 38 84 + {0, 0 , 0 , 0x2012, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 85 + {"vpmulhud", 0x80 ,0x4A8200, 0x19 , 0x1603, 0x1603, 0x603 , 0 , 0 , 0x1406, 0 , 0x100 }, // 0F 38 86 + {"vpmulhd", 0x80 ,0x4A8200, 0x19 , 0x1603, 0x1603, 0x603 , 0 , 0 , 0x1406, 0 , 0x100 }, // 0F 38 87 + {"vexpandp", 0x20 ,0x801200, 0x12 , 0x164F, 0x064F, 0 , 0 , 0x1030, 0 , 0 , 1 }, // 0F 38 88 + {"vpexpand", 0x20 ,0x83B200, 0x12 , 0x1209, 0x0209, 0 , 0 , 0x30 , 0 , 0 , 1 }, // 0F 38 89 + {"vcompressp",0x20 ,0x809200, 0x13, 0x024F, 0x124F, 0 , 0 , 0x1030, 0 , 0 , 1 }, // 0F 38 8A + {"vpcompress",0x20 ,0x80B200, 0x13, 0x0209, 0x1209, 0 , 0 , 0x1030, 0 , 0 , 1 }, // 0F 38 8B + {"vpmaskmov", 0x1C , 0xFB200, 0x19, 0x1209, 0x1209, 0x2209, 0 , 0 , 0 , 0 , 1 }, // 0F 38 8C + {"vperm" , 0x23 ,0x8EC200, 0x19, 0x1209, 0x1209, 0x209 , 0 , 0x20 , 0 , 0 , 1 }, // 0F 38 8D + {"vpmaskmov", 0x1C , 0xFB200, 0x1A, 0x2209, 0x1209, 0x1209, 0 , 0 , 0 , 0 , 1 }, // 0F 38 8E + {0, 0 , 0 , 0x2012, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 8F +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {0, 0x102 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0xE , 0 }, // 0F 38 90. link to vpgatherd/q + {0, 0x94 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0xE , 0 }, // 0F 38 91. Link to vpgatherqd/q + {0, 0xB6 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0xE , 0 }, // 0F 38 92. Link to vpgatherdps/pd + {0, 0xE0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0xE , 0 }, // 0F 38 93. Link to vpgatherqps/pd + {"(reserved)",0x00 ,0x4D2E00, 0x4012, 0x609 , 0x609 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 94 + {0, 0 , 0 , 0x2012, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 95 + {"vfmaddsub132p",0x1A,0x8F9200,0x19 , 0x124F, 0x124F, 0x24F , 0 , 0x37 , 0 , 0 , 0x1 }, // 0F 38 96 + {"vfmsubadd132p",0x1A,0x8F9200,0x19 , 0x124F, 0x124F, 0x24F , 0 , 0x37 , 0 , 0 , 0x1 }, // 0F 38 97 + {"vfmadd132p",0x1A ,0xCF9200, 0x19 , 0x124F, 0x124F, 0x24F , 0 , 0x37 , 0x1304, 0 , 0x1 }, // 0F 38 98 + {"vfmadd132s",0x1A ,0x8B9200, 0x19 , 0x144F, 0x144F, 0x04F , 0 , 0x36 , 0 , 0 , 0x1 }, // 0F 38 99 + {"vfmsub132p",0x1A ,0xCF9200, 0x19 , 0x124F, 0x124F, 0x24F , 0 , 0x37 , 0x1304, 0 , 0x1 }, // 0F 38 9A + {"vfmsub132s",0x1A ,0x8B9200, 0x19 , 0x144F, 0x144F, 0x04F , 0 , 0x36 , 0 , 0 , 0x1 }, // 0F 38 9B + {"vfnmadd132p",0x1A ,0xCF9200, 0x19 , 0x124F, 0x124F, 0x24F , 0 , 0x37 , 0x1304, 0 , 0x1 }, // 0F 38 9C + {"vfnmadd132s",0x1A ,0x8B9200, 0x19 , 0x144F, 0x144F, 0x04F , 0 , 0x36 , 0 , 0 , 0x1 }, // 0F 38 9D + {"vfnmsub132p",0x1A ,0xCF9200, 0x19 , 0x124F, 0x124F, 0x24F , 0 , 0x37 , 0x1304, 0 , 0x1 }, // 0F 38 9E + {"vfnmsub132s",0x1A ,0x8B9200, 0x19 , 0x144F, 0x144F, 0x04F , 0 , 0x36 , 0 , 0 , 0x1 }, // 0F 38 9F +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {0, 0xD7 , 0 ,0 , 0 , 0 , 0 , 0 , 0 , 0 , 0xC , 0 }, // 0F 38 A0. Link to vpscatterdd + {0, 0xD8 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0xC , 0 }, // 0F 38 A1. Link to vpscatterqd + {0, 0x100 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0xC , 0 }, // 0F 38 A2. Link to vpscatterdps + {0, 0x101 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0xC , 0 }, // 0F 38 A3. Link to vpscatterqps + {"vfmadd233ps",0x80 ,0x4F8200, 0x19 , 0x124B, 0x124B, 0x24B , 0 , 0 , 0x1316, 0 , 0x100 }, // 0F 38 A4 + {0, 0 , 0 , 0x2012, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 A5 + {"vfmaddsub213p",0x1A,0x8F9200,0x19 , 0x124F, 0x124F, 0x24F , 0 , 0x37 , 0 , 0 , 0x1 }, // 0F 38 A6 + {"vfmsubadd213p",0x1A,0x8F9200,0x19 , 0x124F, 0x124F, 0x24F , 0 , 0x37 , 0 , 0 , 0x1 }, // 0F 38 A7 + {"vfmadd213p",0x1A ,0xCF9200, 0x19 , 0x124F, 0x124F, 0x24F , 0 , 0x37 , 0x1304, 0 , 0x1 }, // 0F 38 A8 + {"vfmadd213s",0x1A ,0x8B9200, 0x19 , 0x144F, 0x144F, 0x04F , 0 , 0x36 , 0 , 0 , 0x1 }, // 0F 38 A9 + {"vfmsub213p",0x1A ,0xCF9200, 0x19 , 0x124F, 0x124F, 0x24F , 0 , 0x37 , 0x1304, 0 , 0x1 }, // 0F 38 AA + {"vfmsub213s",0x1A ,0x8B9200, 0x19 , 0x144F, 0x144F, 0x04F , 0 , 0x36 , 0 , 0 , 0x1 }, // 0F 38 AB + {"vfnmadd213p",0x1A ,0xCF9200, 0x19 , 0x124F, 0x124F, 0x24F , 0 , 0x37 , 0x1304, 0 , 0x1 }, // 0F 38 AC + {"vfnmadd213s",0x1A ,0x8B9200, 0x19 , 0x144F, 0x144F, 0x04F , 0 , 0x36 , 0 , 0 , 0x1 }, // 0F 38 AD + {"vfnmsub213p",0x1A ,0xCF9200, 0x19 , 0x124F, 0x124F, 0x24F , 0 , 0x37 , 0x1304, 0 , 0x1 }, // 0F 38 AE + {"vfnmsub213s",0x1A ,0x8B9200, 0x19 , 0x144F, 0x144F, 0x04F , 0 , 0x36 , 0 , 0 , 0x1 }, // 0F 38 AF + +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"(reserved)",0x00 ,0x4D2E00, 0x401E, 0x609 , 0x609 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 B0 + {0, 0 , 0 , 0x2012, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 B1 + {"(reserved)",0x00 ,0x4D2E00, 0x401E, 0x609 , 0x609 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 B2 + {0, 0 , 0 , 0x2012, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 B3 + {0, 0x128 , 0 , 0x19 , 0 , 0 , 0 , 0 , 0 , 0 , 0x11 , 0 }, // 0F 38 B4. Link to vpmadd52luq + {0, 0x129 , 0 , 0x19 , 0 , 0 , 0 , 0 , 0 , 0 , 0x11 , 0 }, // 0F 38 B5. Link to vpmadd52huq + {"vfmaddsub231p",0x1A,0x8F9200,0x19 , 0x124F, 0x124F, 0x24F , 0 , 0x37 , 0 , 0 , 0x1 }, // 0F 38 B6 + {"vfmsubadd231p",0x1A,0x8F9200,0x19 , 0x124F, 0x124F, 0x24F , 0 , 0x37 , 0 , 0 , 0x1 }, // 0F 38 B7 + {"vfmadd231p", 0x1A,0xCF9200,0x19 , 0x124F, 0x124F, 0x24F , 0 , 0x37 , 0x1304, 0 , 0x1 }, // 0F 38 B8 + {"vfmadd231s", 0x1A,0x8B9200,0x19 , 0x144F, 0x144F, 0x04F , 0 , 0x36 , 0 , 0 , 0x1 }, // 0F 38 B9 + {"vfmsub231p", 0x1A,0xCF9200,0x19 , 0x124F, 0x124F, 0x24F , 0 , 0x37 , 0x1304, 0 , 0x1 }, // 0F 38 BA + {"vfmsub231s", 0x1A,0x8B9200,0x19 , 0x144F, 0x144F, 0x04F , 0 , 0x36 , 0 , 0 , 0x1 }, // 0F 38 BB + {"vfnmadd231p", 0x1A,0xCF9200,0x19 , 0x124F, 0x124F, 0x24F , 0 , 0x37 , 0x1304, 0 , 0x1 }, // 0F 38 BC + {"vfnmadd231s", 0x1A,0x8B9200,0x19 , 0x144F, 0x144F, 0x04F , 0 , 0x36 , 0 , 0 , 0x1 }, // 0F 38 BD + {"vfnmsub231p", 0x1A,0xCF9200,0x19 , 0x124F, 0x124F, 0x24F , 0 , 0x37 , 0x1304, 0 , 0x1 }, // 0F 38 BE + {"vfnmsub231s", 0x1A,0x8B9200,0x19 , 0x144F, 0x144F, 0x04F , 0 , 0x36 , 0 , 0 , 0x1 }, // 0F 38 BF +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"(reserved)",0x0 ,0x4D2E00 , 0x401E, 0x609 , 0x609 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 C0 + {0, 0 , 0 , 0x2012, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 C1 + {0, 0 , 0 , 0x2012, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 C2 + {0, 0 , 0 , 0x2012, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 C3 + {"vpconflict",0x21 ,0x80B200, 0x12 , 0x1209, 0x0209, 0 , 0 , 0x31 , 0 , 0 , 0x1 }, // 0F 38 C4 + {0, 0 , 0 , 0x2012, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 C5 + {0, 0xB7 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0xC , 0 }, // 0F 38 C6. Link to vgatherpf0dps + {0, 0x10F , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x2 , 0 }, // 0F 38 C7. Link to vgatherpf0qps + {0, 0x107 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x11 , 0 }, // 0F 38 C8 + {0, 0x108 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x11 , 0 }, // 0F 38 C9 + {0, 0x109 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x11 , 0 }, // 0F 38 CA + {0, 0x10A , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x11 , 0 }, // 0F 38 CB + {0, 0x10B , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x11 , 0 }, // 0F 38 CC + {0, 0x10C , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x11 , 0 }, // 0F 38 CD + {"(reserved)",0x00 ,0x4D2E00, 0x4012, 0x609 , 0x609 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 CE + {"(reserved)",0x00 ,0x4D2E00, 0x4012, 0x609 , 0x609 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 CF +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {0, 0xBE , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x9 , 0 }, // 0F 38 D0. Link to vloadunpackld + {0, 0xBF , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x9 , 0 }, // 0F 38 D1. Link to vloadunpacklps + {"(reserved)",0x00 ,0x4D2E00, 0x4012, 0x609 , 0x609 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 D2 + {"(reserved)",0x00 ,0x4D2E00, 0x4012, 0x609 , 0x609 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 D3 + {0, 0xC0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x9 , 0 }, // 0F 38 D4. Link to vloadunpackhd + {0, 0xC1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x9 , 0 }, // 0F 38 D5. Link to vloadunpackhps + {"(reserved)",0x00 ,0x4D2E00, 0x4012, 0x609 , 0x609 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 D6 + {"(reserved)",0x00 ,0x4D2E00, 0x4012, 0x609 , 0x609 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 D7 + {0, 0 , 0 , 0x2012, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 D8 + {0, 0 , 0 , 0x2012, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 D9 + {0, 0 , 0 , 0x2012, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 DA + {"aesimc", 0x17 ,0x98200 , 0x19, 0x1101, 0x1101, 0x101 , 0 , 0 , 0 , 0 , 0x2 }, // 0F 38 DB + {"aesenc", 0x17 ,0x98200 , 0x19, 0x1101, 0x1101, 0x101 , 0 , 0 , 0 , 0 , 0x2 }, // 0F 38 DC + {"aesenclast",0x17 ,0x98200 , 0x19, 0x1101, 0x1101, 0x101 , 0 , 0 , 0 , 0 , 0x2 }, // 0F 38 DD + {"aesdec", 0x17 ,0x98200 , 0x19, 0x1101, 0x1101, 0x101 , 0 , 0 , 0 , 0 , 0x2 }, // 0F 38 DE + {"aesdeclast",0x17 ,0x98200 , 0x19, 0x1101, 0x1101, 0x101 , 0 , 0 , 0 , 0 , 0x2 }, // 0F 38 DF +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {0, 0 , 0 , 0x2012, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 E0 + {0, 0 , 0 , 0x2012, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 E1 + {0, 0 , 0 , 0x2012, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 E2 + {0, 0 , 0 , 0x2012, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 E3 + {0, 0 , 0 , 0x2012, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 E4 + {0, 0 , 0 , 0x2012, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 E5 + {0, 0 , 0 , 0x2012, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 E6 + {0, 0 , 0 , 0x2012, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 E7 + {0, 0 , 0 , 0x2012, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 E8 + {0, 0 , 0 , 0x2012, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 E9 + {0, 0 , 0 , 0x2012, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 EA + {0, 0 , 0 , 0x2012, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 EB + {0, 0 , 0 , 0x2012, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 EC + {0, 0 , 0 , 0x2012, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 ED + {0, 0 , 0 , 0x2012, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 EE + {0, 0 , 0 , 0x2012, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 EF +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"crc32", 0x16 ,0x19900 , 0x12 , 0x1009, 0x1 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 F0 + {"crc32", 0x07 ,0x19900 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x8 , 0 }, // 0F 38 F1. Link to crc32 16/32/64 bit + {"andn", 0x1D ,0xB1000 , 0x19 , 0x1009, 0x1009, 0x9 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 F2 + {"blsi", 0xA2 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x2 , 0 }, // 0F 38 F3. Link to blsi etc. by reg bit + {0, 0 , 0 , 0x2012, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 F4 + {"bzhi", 0xA3 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x9 , 0 }, // 0F 38 F5. Link to bzhi, pdep, pext + {"mulx", 0xD0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x9 , 0 }, // 0F 38 F6. Link to mulx, adcx, adox + {"bextr", 0xAD , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x9 , 0 }, // 0F 38 F7. Link to bextr etc. + {0, 0 , 0 , 0x2012, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 F8 + {0, 0 , 0 , 0x2012, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 F9 + {0, 0 , 0 , 0x2012, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 FA + {0, 0 , 0 , 0x2012, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 FB + {0, 0 , 0 , 0x2012, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 FC + {0, 0 , 0 , 0x2012, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 FD + {0, 0 , 0 , 0x2012, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 FE + {0, 0 , 0 , 0x2012, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }}; // 0F 38 FF + +// Tertiary opcode map for 3-byte opcode. First two bytes = 0F 39 +// Reserved by Intel for future extensions, but never used +SOpcodeDef OpcodeMap3[] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {0, 0 , 0 , 0x2012, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }}; // 0F 39 00 + +// Tertiary opcode map for 3-byte opcode. First two bytes = 0F 3A +// or VEX encoded with mmmm = 3 +// Indexed by third opcode byte +SOpcodeDef OpcodeMap4[] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"vpermq", 0x1C ,0x97B200, 0x52 , 0x1204, 0x204 , 0x31 , 0 , 0x31 , 0 , 0 , 0 }, // 0F 3A 00 + {"vpermpd", 0x1C ,0x97B200, 0x52 , 0x124C, 0x24C , 0x31 , 0 , 0x31 , 0 , 0 , 0 }, // 0F 3A 01 + {"vpblendd", 0x1C , 0xF8200, 0x59, 0x1203, 0x1203, 0x203 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 3A 02 + {"valign", 0x20 ,0xCAB200, 0x59, 0x1209, 0x1209, 0x209 , 0x31 , 0x21 , 0x1000, 0 , 0x101 }, // 0F 3A 03 + {"vpermilps", 0x19 ,0x8F8200, 0x52, 0x124B, 0x24B , 0x31 , 0 , 0x31 , 0 , 0 , 0 }, // 0F 3A 04 + {"vpermilpd", 0x19 ,0x8FA200, 0x52, 0x124C, 0x24C , 0x31 , 0 , 0x31 , 0 , 0 , 0 }, // 0F 3A 05 + {"vperm2f128",0x19 ,0x1F8200, 0x59, 0x1550, 0x1550, 0x550 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 3A 06 + {"vpermf32x4",0x80 ,0x438200, 0x52, 0x124B, 0x24B , 0x31 , 0 , 0 , 0x1000, 0 , 0x100 }, // 0F 3A 07 + {0, 0xF9 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0xE , 0 }, // 0F 3A 08. Also in AMD instruction set + {0, 0xFA , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0xE , 0 }, // 0F 3A 09. Also in AMD instruction set + {0, 0xFB , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0xE , 0 }, // 0F 3A 0A. Also in AMD instruction set + {0, 0xFC , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0xE , 0 }, // 0F 3A 0B. Also in AMD instruction set + {"blendps", 0x15 , 0xD8200, 0x59 , 0x124B, 0x124B, 0x24B , 0x31 , 0 , 0 , 0 , 0x2 }, // 0F 3A 0C + {"blendpd", 0x15 , 0xD8200, 0x59 , 0x124C, 0x124C, 0x24C , 0x31 , 0 , 0 , 0 , 0x2 }, // 0F 3A 0D + {"pblendw", 0x15 , 0xD8200, 0x59 , 0x1202, 0x1202, 0x202 , 0x31 , 0 , 0 , 0 , 0x2 }, // 0F 3A 0E + {"palignr", 0x14 ,0x8D2200, 0x59 , 0x1201, 0x1201, 0x201 , 0x31 , 0x20 , 0 , 0 , 0x2 }, // 0F 3A 0F +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A 10 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A 11 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A 12 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A 13 + {0, 0x61 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x3 , 0 }, // 0F 3A 14. Link to pextrb + {0, 0x62 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x3 , 0 }, // 0F 3A 15. Link to pextrw + {0, 0x63 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x8 , 0 }, // 0F 3A 16. Link to pextrd, pextrq + {"extractps" ,0x15 ,0x819200, 0x53 , 0x3 , 0x144B, 0x31 , 0 , 0 , 0 , 0 , 0x2 }, // 0F 3A 17 + {0 ,0x122 , 0 , 0x59 , 0 , 0 , 0 , 0 , 0 , 0 , 0xE , 0 }, // 0F 3A 18 + {0 ,0x11E , 0 , 0x59 , 0 , 0 , 0 , 0 , 0 , 0 , 0xE , 0 }, // 0F 3A 19. Link to vextractf128 + {0 ,0x124 , 0 , 0x59 , 0 , 0 , 0 , 0 , 0 , 0 , 0xC , 0 }, // 0F 3A 1A. Link to vinsertf64x4 + {0, 0xDE , 0 , 0x59 , 0 , 0 , 0 , 0 , 0 , 0 , 0xC , 0 }, // 0F 3A 1B. Link to vextractf64x4 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A 1C +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"vcvtps2ph", 0x1D ,0x878200, 0x53, 0xF4A , 0x250 , 0x31 , 0 , 0x22 , 0 , 0 , 0 }, // 0F 3A 1D + {0, 0x114 , 0 , 0x59 , 0 , 0 , 0 , 0 , 0 , 0 , 0x6 , 0 }, // 0F 3A 1E. link to vpcmpud + {0, 0x115 , 0 , 0x59 , 0 , 0 , 0 , 0 , 0 , 0 , 0x6 , 0 }, // 0F 3A 1F. link to vpcmpd +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {0, 0xA5 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x3 , 0 }, // 0F 3A 20. Link to pinsrb + {"insertps", 0x15 ,0x898200, 0x59 , 0x144B, 0x144B, 0x4B , 0x31 , 0 , 0 , 0 , 0x2 }, // 0F 3A 21 + {"pinsrd/q", 0x75 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x8 , 0 }, // 0F 3A 22. Link to pinsrd/q + {0, 0x8F , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0xC , 0 }, // 0F 3A 23. Link to vshuff32x4 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A 24 + {"vpternlog", 0x20 ,0x88B200, 0x59 , 0x1209, 0x1209, 0x0209, 0x31 , 0x31 , 0 , 0 , 0x1 }, // 0F 3A 25 + {"vgetmantp", 0x20 , 0xC29200,0x52 , 0x124F, 0x24F , 0x31 , 0 , 0x33 , 0x1204, 0 , 0x001 }, // 0F 3A 26 + {"vgetmants", 0x20 , 0xCA9200,0x59 , 0x144F, 0x24F , 0x04F , 0x31 , 0x32 , 0x1204, 0 , 0x001 }, // 0F 3A 27 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A 28 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A 29 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A 2A + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A 2B + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A 2C + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A 2D + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A 2E + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A 2F +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"kshiftr", 0x20 , 0x3C200, 0x52 , 0x1095, 0x1095, 0x11 , 0 , 0 , 0 , 0 , 1 }, // 0F 3A 30 + {"kshiftr", 0x20 , 0x3B200, 0x52 , 0x1095, 0x1095, 0x11 , 0 , 0 , 0 , 0 , 1 }, // 0F 3A 30 + {"kshiftl", 0x20 , 0x3C200, 0x52 , 0x1095, 0x1095, 0x11 , 0 , 0 , 0 , 0 , 1 }, // 0F 3A 32 + {"kshiftl", 0x20 , 0x3B200, 0x52 , 0x1095, 0x1095, 0x11 , 0 , 0 , 0 , 0 , 1 }, // 0F 3A 33 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A 34 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A 35 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A 36 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A 37 + {0, 0x125 , 0 , 0x59 , 0 , 0 , 0 , 0 , 0 , 0 , 0xE , 0 }, // 0F 3A 38. Link to vinserti128 + {0, 0x120 , 0 , 0x59 , 0 , 0 , 0 , 0 , 0 , 0 , 0xE , 0 }, // 0F 3A 39. Link to vextracti128 + {0, 0x127 , 0 , 0x59 , 0 , 0 , 0 , 0 , 0 , 0 , 0xC , 0 }, // 0F 3A 3A. Link to vinserti64x4 + {0, 0xDF , 0 , 0x53 , 0 , 0 , 0 , 0 , 0 , 0 , 0xC , 0 }, // 0F 3A 3B. Link to vextracti64x4 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A 3C + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A 3D + {0, 0xC6 , 0 , 0x59 , 0 , 0 , 0 , 0 , 0 , 0 , 0xE , 0 }, // 0F 3A 3E. Link to kextract and vpcmp + {0, 0x113 , 0 , 0x59 , 0 , 0 , 0 , 0 , 0 , 0 , 0x6 , 0 }, // 0F 3A 3F. Link to vpcmp + // name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"dpps", 0x15 , 0xD8200, 0x59 , 0x124B, 0x124B, 0x24B , 0x31 , 0 , 0 , 0 , 0x2 }, // 0F 3A 40 + {"dppd", 0x15 , 0x98200, 0x59 , 0x144C, 0x144C, 0x44C , 0x31 , 0 , 0 , 0 , 0x2 }, // 0F 3A 41 (No ymm version) + {0, 0x11D , 0 , 0x59 , 0 , 0 , 0 , 0 , 0 , 0 , 0xE , 0x2 }, // 0F 3A 42. Link to mpsadbw + {0, 0x90 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0xC , 0 }, // 0F 3A 43. Link to vshufi32x4 + {"pclmulqdq", 0x18 , 0x98200, 0x59, 0x1404, 0x1404, 0x404 , 0x31 , 0 , 0 , 0 , 0x2 }, // 0F 3A 44 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A 45 + {"vperm2i128",0x1C , 0x1FB200,0x59 , 0x1506, 0x1506, 0x506 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 3A 46 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A 47 + {"vpermil2ps",0x1005, 0xFF200, 0x5C, 0x124B, 0x124B, 0x24B , 0x24B , 0 , 0x31 , 0 , 0 }, // 0F 3A 48 AMD XOP + {"vpermil2pd",0x1005, 0xFF200, 0x5C, 0x124C, 0x124C, 0x24C , 0x24C , 0 , 0x31 , 0 , 0 }, // 0F 3A 49 AMD XOP + {"vblendvps", 0x19 , 0xF8200, 0x5C , 0x124B, 0x24B , 0x24B , 0x24B , 0 , 0 , 0 , 0 }, // 0F 3A 4A + {"vblendvpd", 0x19 , 0xF8200, 0x5C , 0x124C, 0x24C , 0x24C , 0x24C , 0 , 0 , 0 , 0 }, // 0F 3A 4B + {"vpblendvb", 0x19 , 0xF8200, 0x5C , 0x1201, 0x1201, 0x201 , 0x201 , 0 , 0 , 0 , 0 }, // 0F 3A 4C + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A 4D + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A 4E + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A 4F +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"vrangep", 0x20 ,0x8EB200, 0x59, 0x124F, 0x124F, 0x24F , 0x31 , 0x23 , 0 , 0 , 1 }, // 0F 3A 50 + {"vranges", 0x20 ,0x8EB200, 0x59, 0x144F, 0x144F, 0x44F , 0x31 , 0x33 , 0 , 0 , 1 }, // 0F 3A 50 + {"vrndfxpntp",0x80 , 0x4B9200,0x52 , 0x124F, 0x24F , 0x11 , 0 , 0 , 0x1204, 0 , 0x101 }, // 0F 3A 52 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A 53 + {"vfixupimmp",0x20 ,0x881200, 0x59 , 0x124F, 0x124F, 0x024F, 0x31 , 0x33 , 0 , 0 , 1 }, // 0F 3A 54 + {"vfixupimms",0x20 ,0x8C1200, 0x59 , 0x104F, 0x104F, 0x004F, 0x31 , 0x32 , 0 , 0 , 1 }, // 0F 3A 55 + {"vreducep", 0x20 ,0x86B200, 0x52 , 0x124F, 0x24f , 0 , 0x31 , 0x23 , 0 , 0 , 1 }, // 0F 3A 56 + {"vreduces", 0x20 ,0x8EB200, 0x52 , 0x144F, 0x44f , 0 , 0x31 , 0x22 , 0 , 0 , 1 }, // 0F 3A 57 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A 58 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A 59 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A 5A + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A 5B + {"vfmaddsubps",0x1006,0xFF200,0x5C , 0x24B , 0x24B , 0x24B , 0x24B , 0 , 0 , 0 , 0 }, // 0F 3A 5C + {"vfmaddsubpd",0x1006,0xFF200,0x5C , 0x24C , 0x24C , 0x24C , 0x24C , 0 , 0 , 0 , 0 }, // 0F 3A 5D + {"vfmsubaddps",0x1006,0xFF200,0x5C , 0x24B , 0x24B , 0x24B , 0x24B , 0 , 0 , 0 , 0 }, // 0F 3A 5E + {"vfmsubaddpd",0x1006,0xFF200,0x5C , 0x24C , 0x24C , 0x24C , 0x24C , 0 , 0 , 0 , 0 }, // 0F 3A 5F +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"pcmpestrm", 0x16 , 0x18200, 0x52 , 0x1401, 0x451 , 0x31 , 0 , 0 , 0 , 0 , 0x202 }, // 0F 3A 60 + {"pcmpestri", 0x16 , 0x18200, 0x52 , 0x1401, 0x451 , 0x31 , 0 , 0 , 0 , 0 , 0x202 }, // 0F 3A 61 + {"pcmpistrm", 0x16 , 0x18200, 0x52 , 0x1401, 0x451 , 0x31 , 0 , 0 , 0 , 0 , 0x202 }, // 0F 3A 62 + {"pcmpistri", 0x16 , 0x18200, 0x52 , 0x1401, 0x451 , 0x31 , 0 , 0 , 0 , 0 , 0x202 }, // 0F 3A 63 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A 64 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A 65 + {"vfpclassp", 0x20 ,0x82B200, 0x52 , 0x95 , 0x24F , 0x31 , 0 , 0x10 , 0 , 0 , 1 }, // 0F 3A 66 + {"vfpclasss", 0x20 ,0x82B200, 0x52 , 0x95 , 0x44F , 0x31 , 0 , 0x10 , 0 , 0 , 1 }, // 0F 3A 67 +// 4-operand FMA instructions. First specified by Intel, then Intel changed their plans, now supported by AMD + {"vfmaddps", 0x1006,0xFF200 , 0x5C , 0x24B , 0x24B , 0x24B , 0x24B , 0 , 0 , 0 , 0 }, // 0F 3A 68 + {"vfmaddpd", 0x1006,0xFF200 , 0x5C , 0x24C , 0x24C , 0x24C , 0x24C , 0 , 0 , 0 , 0 }, // 0F 3A 69 + {"vfmaddss", 0x1006,0xBF200 , 0x5C , 0x44B , 0x44B , 0x44B , 0x44B , 0 , 0 , 0 , 0 }, // 0F 3A 6A + {"vfmaddsd", 0x1006,0xBF200 , 0x5C , 0x44C , 0x44C , 0x44C , 0x44C , 0 , 0 , 0 , 0 }, // 0F 3A 6B + {"vfmsubps", 0x1006,0xFF200 , 0x5C , 0x24B , 0x24B , 0x24B , 0x24B , 0 , 0 , 0 , 0 }, // 0F 3A 6C + {"vfmsubpd", 0x1006,0xFF200 , 0x5C , 0x24C , 0x24C , 0x24C , 0x24C , 0 , 0 , 0 , 0 }, // 0F 3A 6D + {"vfmsubss", 0x1006,0xBF200 , 0x5C , 0x44B , 0x44B , 0x44B , 0x44B , 0 , 0 , 0 , 0 }, // 0F 3A 6E + {"vfmsubsd", 0x1006,0xBF200 , 0x5C , 0x44C , 0x44C , 0x44C , 0x44C , 0 , 0 , 0 , 0 }, // 0F 3A 6F +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A 70 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A 71 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A 72 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A 73 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A 74 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A 75 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A 76 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A 77 + {"vfnmaddps", 0x1006,0xFF200 , 0x5C , 0x24B , 0x24B , 0x24B , 0x24B , 0 , 0 , 0 , 0 }, // 0F 3A 78 + {"vfnmaddpd", 0x1006,0xFF200 , 0x5C , 0x24C , 0x24C , 0x24C , 0x24C , 0 , 0 , 0 , 0 }, // 0F 3A 79 + {"vfnmaddss", 0x1006,0xBF200 , 0x5C , 0x44B , 0x44B , 0x44B , 0x44B , 0 , 0 , 0 , 0 }, // 0F 3A 7A + {"vfnmaddsd", 0x1006,0xBF200 , 0x5C , 0x44C , 0x44C , 0x44C , 0x44C , 0 , 0 , 0 , 0 }, // 0F 3A 7B + {"vfnmsubps", 0x1006,0xFF200 , 0x5C , 0x24B , 0x24B , 0x24B , 0x24B , 0 , 0 , 0 , 0 }, // 0F 3A 7C + {"vfnmsubpd", 0x1006,0xFF200 , 0x5C , 0x24C , 0x24C , 0x24C , 0x24C , 0 , 0 , 0 , 0 }, // 0F 3A 7D + {"vfnmsubss", 0x1006,0xBF200 , 0x5C , 0x44B , 0x44B , 0x44B , 0x44B , 0 , 0 , 0 , 0 }, // 0F 3A 7E + {"vfnmsubsd", 0x1006,0xBF200 , 0x5C , 0x44C , 0x44C , 0x44C , 0x44C , 0 , 0 , 0 , 0 }, // 0F 3A 7F +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A 80 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A 81 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A 82 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A 83 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A 84 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A 85 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A 86 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A 87 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A 88 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A 89 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A 8A + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A 8B + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A 8C + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A 8D + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A 8E + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A 8F +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A 90 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A 91 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A 92 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A 93 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A 94 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A 95 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A 96 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A 97 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A 98 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A 99 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A 9A + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A 9B + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A 9C + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A 9D + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A 9E + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A 9F +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A A0 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A A1 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A A2 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A A3 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A A4 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A A5 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A A6 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A A7 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A A8 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A A9 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A AA + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A AB + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A AC + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A AD + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A AE + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A AF +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A B0 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A B1 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A B2 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A B3 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A B4 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A B5 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A B6 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A B7 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A B8 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A B9 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A BA + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A BB + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A BC + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A BD + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A BE + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A BF +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A C0 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A C1 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A C2 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A C3 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A C4 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A C5 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A C6 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A C7 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A C8 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A C9 + {0, 0xB4 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0x9 , 0 }, // 0F 3A CA. Link to vcvtfxpntpd2udq etc + {0, 0xB5 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0x9 , 0 }, // 0F 3A CB. Link to vcvtfxpntdq2ps etc + {"sha1rnds4", 0x22 , 0 , 0x52 , 0x1403, 0x0403, 0x31 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A CC + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A CD + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A CE + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A CF +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"(reserved)",0x00 ,0x4D2E00, 0x4052, 0x609 , 0x609 , 0x31 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 D0 + {"(reserved)",0x00 ,0x4D2E00, 0x4052, 0x609 , 0x609 , 0x31 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 D1 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A D2 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A D3 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A D4 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A D5 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A D6 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A D7 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A D8 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A D9 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A DA + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A DB + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A DC + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A DD + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A DE +{"aeskeygenassist",0x17,0x18200 , 0x52, 0x1101, 0x101 , 0x31 , 0 , 0 , 0 , 0 , 0x2 }, // 0F 3A DF +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A E0 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A E1 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A E2 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A E3 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A E4 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A E5 +{"vcvtfxpntpd2dq",0x80 ,0x42B800, 0x52, 0x1603, 0x64C , 0x31 , 0 , 0 , 0x1205, 0 , 0x100 }, // 0F 3A E6 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A E7 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A E8 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A E9 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A EA + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A EB + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A EC + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A ED + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A EE + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A EF +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {0, 0xA4 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0x9 , 0 }, // 0F 3A F0. Link to rorx + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A F1 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A F2 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A F3 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A F4 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A F5 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A F6 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A F7 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A F8 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A F9 + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A FA + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A FB + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A FC + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A FD + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A FE + {0, 0 , 0 , 0x2052, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }}; // 0F 3A FF + + +// Tertiary opcode map for 3-byte opcode. First two bytes = 0F 3B +// Reserved by Intel for future extensions, but never used +SOpcodeDef OpcodeMap5[1] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {0, 0 , 0 , 0x2000, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }}; // 0F 3B 00 + + +// Tertiary opcode map for AMD 3DNow instructions (obsolete). First two bytes = 0F 0F +// Indexed by immediate byte following operands +SOpcodeDef OpcodeMap6[] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 00 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 01 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 02 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 03 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 04 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 05 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 06 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 07 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 08 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 09 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 0A + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 0B + {"PFI2FW", 0x1001, 0 , 0x52 , 0x134B, 0x302 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 0C + {"PI2FD", 0x1001, 0 , 0x52 , 0x134B, 0x303 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 0D + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 0E + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 0F +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 10 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 11 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 12 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 13 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 14 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 15 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 16 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 17 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 18 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 19 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 1A + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 1B + {"PF2IW", 0x1002, 0 , 0x52 , 0x1302, 0x34B , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 1C + {"PF2ID", 0x1001, 0 , 0x52 , 0x1303, 0x34B , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 1D + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 1E + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 1F +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 20 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 21 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 22 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 23 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 24 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 25 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 26 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 27 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 28 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 29 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 2A + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 2B + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 2C + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 2D + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 2E + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 2F +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 30 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 31 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 32 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 33 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 34 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 35 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 36 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 37 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 38 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 39 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 3A + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 3B + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 3C + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 3D + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 3E + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 3F +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 40 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 41 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 42 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 43 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 44 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 45 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 46 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 47 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 48 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 49 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 4A + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 4B + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 4C + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 4D + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 4E + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 4F +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 50 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 51 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 52 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 53 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 54 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 55 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 56 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 57 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 58 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 59 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 5A + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 5B + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 5C + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 5D + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 5E + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 5F +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 60 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 61 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 62 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 63 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 64 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 65 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 66 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 67 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 68 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 69 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 6A + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 6B + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 6C + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 6D + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 6E + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 6F +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 70 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 71 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 72 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 73 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 74 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 75 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 76 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 77 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 78 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 79 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 7A + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 7B + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 7C + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 7D + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 7E + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 7F +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 80 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 81 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 82 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 83 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 84 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 85 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 86 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 87 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 88 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 89 + {"PFNACC", 0x1002, 0 , 0x52 , 0x134B, 0x34B , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 8A + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 8B + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 8C + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 8D + {"PFPNACC", 0x1002, 0 , 0x52 , 0x134B, 0x34B , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 8E + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 8F +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"PFCMPGE", 0x1001, 0 , 0x52 , 0x134B, 0x34B , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 90 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 91 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 92 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 93 + {"PFMIN", 0x1001, 0 , 0x52 , 0x134B, 0x34B , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 94 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 95 + {"PFRCP", 0x1001, 0 , 0x52 , 0x134B, 0x34B , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 96 + {"PFRSQRT", 0x1001, 0 , 0x52 , 0x134B, 0x34B , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 97 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 98 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 99 + {"PFSUB", 0x1001, 0 , 0x52 , 0x134B, 0x34B , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 9A + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 9B + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 9C + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 9D + {"PFADD", 0x1001, 0 , 0x52 , 0x134B, 0x34B , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 9E + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op 9F +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"PFCMPGT", 0x1001, 0 , 0x52 , 0x134B, 0x34B , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op A0 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op A1 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op A2 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op A3 + {"PFMAX", 0x1001, 0 , 0x52 , 0x134B, 0x34B , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op A4 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op A5 + {"PFRCPIT1", 0x1001, 0 , 0x52 , 0x134B, 0x34B , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op A6 + {"PFRSQIT1", 0x1001, 0 , 0x52 , 0x134B, 0x34B , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op A7 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op A8 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op A9 + {"PFSUBR", 0x1001, 0 , 0x52 , 0x134B, 0x34B , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op AA + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op AB + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op AC + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op AD + {"PFACC", 0x1001, 0 , 0x52 , 0x134B, 0x34B , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op AE + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op AF +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"PFCMPEQ", 0x1001, 0 , 0x52 , 0x134B, 0x34B , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op B0 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op B1 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op B2 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op B3 + {"PFMUL", 0x1001, 0 , 0x52 , 0x134B, 0x34B , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op B4 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op B5 + {"PFRCPIT2", 0x1001, 0 , 0x52 , 0x134B, 0x34B , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op B6 + {"PMULHRW", 0x1001, 0 , 0x52 , 0x1302, 0x302 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op B7 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op B8 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op B9 + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op BA + {"PSWAPD", 0x1002, 0 , 0x52 , 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op BB + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op BC + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op BD + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op BE + {"PAVGUSB", 0x1001, 0 , 0x52 , 0x1301, 0x301 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0F op BF +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {0, 0x1001, 0 , 0x2052, 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }}; // 0F 0F op C0 + +// Opcode map for crc32. Opcode byte = 0F 38 F1 +// Indexed by operand size (16, 32, 64) +SOpcodeDef OpcodeMap7[3] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"crc32", 0x16 ,0x19900 , 0x12 , 0x1003, 0x2 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 F1 + {"crc32", 0x16 ,0x19900 , 0x12 , 0x1003, 0x3 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 F1 + {"crc32", 0x16 ,0x19900 , 0x12 , 0x1004, 0x4 , 0 , 0 , 0 , 0 , 0 , 0 }}; // 0F 38 F1 + +// Secondary opcode map for x87 f.p. instructions. Opcode D8 +// Indexed by reg bits and mod == 3 +SOpcodeDef OpcodeMap8[16] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"fadd", 0x100 , 0 , 0x11 , 0 , 0x2043, 0 , 0 , 0 , 0 , 0 , 0 }, // fadd m32 + {"fmul", 0x100 , 0 , 0x11 , 0 , 0x2043, 0 , 0 , 0 , 0 , 0 , 0 }, // fmul m32 + {"fcom", 0x100 , 0 , 0x11 , 0 , 0x2043, 0 , 0 , 0 , 0 , 0 , 0x4 }, // fcom m32 + {"fcomp", 0x100 , 0 , 0x11 , 0 , 0x2043, 0 , 0 , 0 , 0 , 0 , 0x4 }, // fcomp m32 + {"fsub", 0x100 , 0 , 0x11 , 0 , 0x2043, 0 , 0 , 0 , 0 , 0 , 0 }, // fsub m32 + {"fsubr", 0x100 , 0 , 0x11 , 0 , 0x2043, 0 , 0 , 0 , 0 , 0 , 0 }, // fsubr m32 + {"fdiv", 0x100 , 0 , 0x11 , 0 , 0x2043, 0 , 0 , 0 , 0 , 0 , 0 }, // fdiv m32 + {"fdivr", 0x100 , 0 , 0x11 , 0 , 0x2043, 0 , 0 , 0 , 0 , 0 , 0 }, // fdivr m32 + {"fadd", 0x100 , 0 , 0x11 , 0xAF , 0x1040, 0 , 0 , 0 , 0 , 0 , 0 }, // fadd st,st(i) + {"fmul", 0x100 , 0 , 0x11 , 0xAF , 0x1040, 0 , 0 , 0 , 0 , 0 , 0 }, // fmul st,st(i) + {"fcom", 0x100 , 0 , 0x11 , 0 , 0x1040, 0 , 0 , 0 , 0 , 0 , 0x4 }, // fcom st,st(i) + {"fcomp", 0x100 , 0 , 0x11 , 0 , 0x1040, 0 , 0 , 0 , 0 , 0 , 0x4 }, // fcomp st,st(i) + {"fsub", 0x100 , 0 , 0x11 , 0xAF , 0x1040, 0 , 0 , 0 , 0 , 0 , 0 }, // fsub st,st(i) + {"fsubr", 0x100 , 0 , 0x11 , 0xAF , 0x1040, 0 , 0 , 0 , 0 , 0 , 0 }, // fsubr st,st(i) + {"fdiv", 0x100 , 0 , 0x11 , 0xAF , 0x1040, 0 , 0 , 0 , 0 , 0 , 0 }, // fdiv st,st(i) + {"fdivr", 0x100 , 0 , 0x11 , 0xAF , 0x1040, 0 , 0 , 0 , 0 , 0 , 0 }}; // fdivr st,st(i) + +// Secondary opcode map for x87 f.p. instructions. Opcode D9 +// Indexed by reg bits and mod == 3 +SOpcodeDef OpcodeMap9[16] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"fld", 0x100 , 0 , 0x11 , 0 , 0x2043, 0 , 0 , 0 , 0 , 0 , 0 }, // fld m32 + {0, 0 , 0 , 0x4011, 0 , 0x2043, 0 , 0 , 0 , 0 , 0 , 0 }, // illegal + {"fst", 0x100 , 0 , 0x11 , 0x2043, 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // fst m32 + {"fstp", 0x100 , 0 , 0x11 , 0x2043, 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // fstp m32 + {"fldenv", 0x100 , 0 , 0x11 , 0 , 0x2006, 0 , 0 , 0 , 0 , 0 , 0 }, // fldenv m + {"fldcw", 0x100 , 0 , 0x11 , 0 , 0x2002, 0 , 0 , 0 , 0 , 0 , 0 }, // fldcw m16 + {"fnstenv", 0x100 , 0 , 0x11 , 0x2006, 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // fnstenv m + {"fnstcw", 0x100 , 0 , 0x11 , 0x2002, 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // fnstcw m16 + {"fld", 0x100 , 0 , 0x11 , 0 , 0x1040, 0 , 0 , 0 , 0 , 0 , 0 }, // fld st(i) + {"fxch", 0x100 , 0 , 0x11 , 0 , 0x1040, 0 , 0 , 0 , 0 , 0 , 0 }, // fxch st(i) + {"fnop", 0x10 , 0 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0x5 , 0 }, // Link to tertiary map 0x10 fnop + {0, 0 , 0 , 0x4011, 0 , 0x1040, 0 , 0 , 0 , 0 , 0 , 0 }, // Illegal + {0, 0x11 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x5 , 0 }, // Link to tertiary map 0x11 fchs etc. + {0, 0x12 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x5 , 0 }, // Link to tertiary map 0x12 fld1 etc. + {0, 0x13 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x5 , 0 }, // Link to tertiary map 0x13 f2xm1 etc. + {0, 0x14 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x5 , 0 }}; // Link to tertiary map 0x14 fprem etc. + +// Secondary opcode map for x87 f.p. instructions. Opcode DA +// Indexed by reg bits and mod == 3 +SOpcodeDef OpcodeMapA[16] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"fiadd", 0x100 , 0 , 0x11 , 0 , 0x2003, 0 , 0 , 0 , 0 , 0 , 0 }, // fiadd m32 + {"fimul", 0x100 , 0 , 0x11 , 0 , 0x2003, 0 , 0 , 0 , 0 , 0 , 0 }, // fimul m32 + {"ficom", 0x100 , 0 , 0x11 , 0 , 0x2003, 0 , 0 , 0 , 0 , 0 , 0x4 }, // ficom m32 + {"ficomp", 0x100 , 0 , 0x11 , 0 , 0x2003, 0 , 0 , 0 , 0 , 0 , 0x4 }, // ficomp m32 + {"fisub", 0x100 , 0 , 0x11 , 0 , 0x2003, 0 , 0 , 0 , 0 , 0 , 0 }, // fisub m32 + {"fisubr", 0x100 , 0 , 0x11 , 0 , 0x2003, 0 , 0 , 0 , 0 , 0 , 0 }, // fisubr m32 + {"fidiv", 0x100 , 0 , 0x11 , 0 , 0x2003, 0 , 0 , 0 , 0 , 0 , 0 }, // fidiv m32 + {"fidivr", 0x100 , 0 , 0x11 , 0 , 0x2003, 0 , 0 , 0 , 0 , 0 , 0 }, // fidivr m32 + {"fcmovb", 0x6 , 0 , 0x11 , 0xAF , 0x1040, 0 , 0 , 0 , 0 , 0 , 0 }, // fcmovb st,st(i) + {"fcmove", 0x6 , 0 , 0x11 , 0xAF , 0x1040, 0 , 0 , 0 , 0 , 0 , 0 }, // fcmovb st,st(i) + {"fcmovbe", 0x6 , 0 , 0x11 , 0xAF , 0x1040, 0 , 0 , 0 , 0 , 0 , 0 }, // fcmovbe st,st(i) + {"fcmovu", 0x6 , 0 , 0x11 , 0xAF , 0x1040, 0 , 0 , 0 , 0 , 0 , 0 }, // fcmovbe st,st(i) + {0, 0 , 0 , 0x4011, 0 , 0x1040, 0 , 0 , 0 , 0 , 0 , 0 }, // Illegal + {0, 0x15 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x5 , 0 }, // Link to tertiary map 0x15 fucompp + {0, 0 , 0 , 0x4011, 0 , 0x1040, 0 , 0 , 0 , 0 , 0 , 0 }, // Illegal + {0, 0 , 0 , 0x4011, 0 , 0x1040, 0 , 0 , 0 , 0 , 0 , 0 }}; // Illegal + +// Secondary opcode map for x87 f.p. instructions. Opcode DB +// Indexed by reg bits and mod == 3 +SOpcodeDef OpcodeMapB[16] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"fild", 0x100 , 0 , 0x11 , 0 , 0x2003, 0 , 0 , 0 , 0 , 0 , 0 }, // fild m32 + {"fisttp", 0x13 , 0 , 0x11 , 0 , 0x2003, 0 , 0 , 0 , 0 , 0 , 0 }, // fisttp m32 + {"fist", 0x100 , 0 , 0x11 , 0x2003, 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // fist m32 + {"fistp", 0x100 , 0 , 0x11 , 0x2003, 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // fistp m32 + {0, 0 , 0 , 0x4011, 0 , 0x2003, 0 , 0 , 0 , 0 , 0 , 0 }, // illegal + {"fld", 0x100 , 0 , 0x11 , 0 , 0x2045, 0 , 0 , 0 , 0 , 0 , 0 }, // fld m80 + {0, 0 , 0 , 0x4011, 0 , 0x2003, 0 , 0 , 0 , 0 , 0 , 0 }, // illegal + {"fstp", 0x100 , 0 , 0x11 , 0x2045, 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // fst m80 + {"fcmovnb", 0x6 , 0 , 0x11 , 0xAF , 0x1040, 0 , 0 , 0 , 0 , 0 , 0 }, // fcmovnb st,st(i) + {"fcmovne", 0x6 , 0 , 0x11 , 0xAF , 0x1040, 0 , 0 , 0 , 0 , 0 , 0 }, // fcmovne st,st(i) + {"fcmovnbe", 0x6 , 0 , 0x11 , 0xAF , 0x1040, 0 , 0 , 0 , 0 , 0 , 0 }, // fcmovnbe st,st(i) + {"fcmovnu", 0x6 , 0 , 0x11 , 0xAF , 0x1040, 0 , 0 , 0 , 0 , 0 , 0 }, // fcmovnu st,st(i) + {0, 0x16 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x5 , 0 }, // Link to tertiary map 0x16 fclex etc. + {"fucomi", 0x6 , 0 , 0x11 , 0xAF , 0x1040, 0 , 0 , 0 , 0 , 0 , 0x4 }, // fucomi st,st(i) + {"fcomi", 0x6 , 0 , 0x11 , 0xAF , 0x1040, 0 , 0 , 0 , 0 , 0 , 0x4 }, // fcomi st,st(i) + {0, 0 , 0 , 0x4011, 0 , 0x1040, 0 , 0 , 0 , 0 , 0 , 0 }}; // illegal + +// Secondary opcode map for x87 f.p. instructions. Opcode DC +// Indexed by reg bits and mod == 3 +SOpcodeDef OpcodeMapC[16] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"fadd", 0x100 , 0 , 0x11 , 0 , 0x2044, 0 , 0 , 0 , 0 , 0 , 0 }, // fadd m64 + {"fmul", 0x100 , 0 , 0x11 , 0 , 0x2044, 0 , 0 , 0 , 0 , 0 , 0 }, // fmul m64 + {"fcom", 0x100 , 0 , 0x11 , 0 , 0x2044, 0 , 0 , 0 , 0 , 0 , 0x4 }, // fcom m64 + {"fcomp", 0x100 , 0 , 0x11 , 0 , 0x2044, 0 , 0 , 0 , 0 , 0 , 0x4 }, // fcomp m64 + {"fsub", 0x100 , 0 , 0x11 , 0 , 0x2044, 0 , 0 , 0 , 0 , 0 , 0 }, // fsub m64 + {"fsubr", 0x100 , 0 , 0x11 , 0 , 0x2044, 0 , 0 , 0 , 0 , 0 , 0 }, // fsubr m64 + {"fdiv", 0x100 , 0 , 0x11 , 0 , 0x2044, 0 , 0 , 0 , 0 , 0 , 0 }, // fdiv m64 + {"fdivr", 0x100 , 0 , 0x11 , 0 , 0x2044, 0 , 0 , 0 , 0 , 0 , 0 }, // fdivr m64 + {"fadd", 0x100 , 0 , 0x11 , 0x1040, 0xAF , 0 , 0 , 0 , 0 , 0 , 0 }, // fadd st(i),st + {"fmul", 0x100 , 0 , 0x11 , 0x1040, 0xAF , 0 , 0 , 0 , 0 , 0 , 0 }, // fmul st(i),st + {0, 0 , 0 , 0x4011, 0x1040, 0xAF , 0 , 0 , 0 , 0 , 0 , 0 }, // illegal + {0, 0 , 0 , 0x4011, 0x1040, 0xAF , 0 , 0 , 0 , 0 , 0 , 0 }, // illegal + {"fsubr", 0x100 , 0 , 0x11 , 0x1040, 0xAF , 0 , 0 , 0 , 0 , 0 , 0 }, // fsubr st(i),st + {"fsub", 0x100 , 0 , 0x11 , 0x1040, 0xAF , 0 , 0 , 0 , 0 , 0 , 0 }, // fsub st(i),st + {"fdivr", 0x100 , 0 , 0x11 , 0x1040, 0xAF , 0 , 0 , 0 , 0 , 0 , 0 }, // fdivr st(i),st + {"fdiv", 0x100 , 0 , 0x11 , 0x1040, 0xAF , 0 , 0 , 0 , 0 , 0 , 0 }}; // fdiv st(i),st + +// Secondary opcode map for x87 f.p. instructions. Opcode DD +// Indexed by reg bits and mod == 3 +SOpcodeDef OpcodeMapD[16] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"fld", 0x100 , 0 , 0x11 , 0 , 0x2044, 0 , 0 , 0 , 0 , 0 , 0 }, // fld m64 + {"fisttp", 0x13 , 0 , 0x11 , 0x2004, 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // fisttp m64 + {"fst", 0x100 , 0 , 0x11 , 0x2044, 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // fst m64 + {"fstp", 0x100 , 0 , 0x11 , 0x2044, 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // fstp m64 + {"frstor", 0x100 , 0 , 0x11 , 0x2006, 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // frstor 108 bytes + {0, 0 , 0 , 0x4011, 0 , 0x2006, 0 , 0 , 0 , 0 , 0 , 0 }, // illegal + {"fnsave", 0x100 , 0 , 0x11 , 0 , 0x2006, 0 , 0 , 0 , 0 , 0 , 0 }, // fnsave 108 bytes + {"fnstsw", 0x100 , 0 , 0x11 , 0x2002, 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // fstsw m16 + {"ffree", 0x100 , 0 , 0x11 , 0x1040, 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // ffree st(i) + {0, 0 , 0 , 0x4011, 0 , 0x2006, 0 , 0 , 0 , 0 , 0 , 0 }, // illegal + {"fst", 0x100 , 0 , 0x11 , 0x1040, 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // fst st(i) + {"fstp", 0x100 , 0 , 0x11 , 0x1040, 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // fstp st(i) + {"fucom", 0x101 , 0 , 0x11 , 0 , 0x1040, 0 , 0 , 0 , 0 , 0 , 0 }, // fucom st(i) + {"fucomp", 0x101 , 0 , 0x11 , 0 , 0x1040, 0 , 0 , 0 , 0 , 0 , 0 }, // fucomp st(i) + {0, 0 , 0 , 0x4011, 0 , 0x2006, 0 , 0 , 0 , 0 , 0 , 0 }, // illegal + {0, 0 , 0 , 0x4011, 0 , 0x2006, 0 , 0 , 0 , 0 , 0 , 0 }}; // illegal + +// Secondary opcode map for x87 f.p. instructions. Opcode DE +// Indexed by reg bits and mod == 3 +SOpcodeDef OpcodeMapE[16] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"fiadd", 0x100 , 0 , 0x11 , 0 , 0x2002, 0 , 0 , 0 , 0 , 0 , 0 }, // fiadd m16 + {"fimul", 0x100 , 0 , 0x11 , 0 , 0x2002, 0 , 0 , 0 , 0 , 0 , 0 }, // fimul m16 + {"ficom", 0x100 , 0 , 0x11 , 0 , 0x2002, 0 , 0 , 0 , 0 , 0 , 0x4 }, // ficom m16 + {"ficomp", 0x100 , 0 , 0x11 , 0 , 0x2002, 0 , 0 , 0 , 0 , 0 , 0x4 }, // ficomp m16 + {"fisub", 0x100 , 0 , 0x11 , 0 , 0x2002, 0 , 0 , 0 , 0 , 0 , 0 }, // fisub m16 + {"fisubr", 0x100 , 0 , 0x11 , 0 , 0x2002, 0 , 0 , 0 , 0 , 0 , 0 }, // fisubr m16 + {"fidiv", 0x100 , 0 , 0x11 , 0 , 0x2002, 0 , 0 , 0 , 0 , 0 , 0 }, // fidiv m16 + {"fidivr", 0x100 , 0 , 0x11 , 0 , 0x2002, 0 , 0 , 0 , 0 , 0 , 0 }, // fidivr m16 + {"faddp", 0x100 , 0 , 0x11 , 0x1040, 0xAF , 0 , 0 , 0 , 0 , 0 , 0 }, // faddp st(i),st + {"fmulp", 0x100 , 0 , 0x11 , 0x1040, 0xAF , 0 , 0 , 0 , 0 , 0 , 0 }, // fmulp st(i),st + {0, 0 , 0 , 0x4011, 0x1040, 0xAF , 0 , 0 , 0 , 0 , 0 , 0 }, // illegal + {0, 0x17 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x5 , 0 }, // Link to tertiary map 0x17 fcompp + {"fsubrp", 0x100 , 0 , 0x11 , 0x1040, 0xAF , 0 , 0 , 0 , 0 , 0 , 0 }, // fsubrp st(i),st (Yes, the order is illogical here) + {"fsubp", 0x100 , 0 , 0x11 , 0x1040, 0xAF , 0 , 0 , 0 , 0 , 0 , 0 }, // fsubp st(i),st + {"fdivrp", 0x100 , 0 , 0x11 , 0x1040, 0xAF , 0 , 0 , 0 , 0 , 0 , 0 }, // fdivrp st(i),st + {"fdivp", 0x100 , 0 , 0x11 , 0x1040, 0xAF , 0 , 0 , 0 , 0 , 0 , 0 }}; // fdivp st(i),st + +// Secondary opcode map for x87 f.p. instructions. Opcode DF +// Indexed by reg bits and mod == 3 +SOpcodeDef OpcodeMapF[16] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"fild", 0x100 , 0 , 0x11 , 0 , 0x2002, 0 , 0 , 0 , 0 , 0 , 0 }, // fild m16 + {"fisttp", 0x13 , 0 , 0x11 , 0 , 0x2002, 0 , 0 , 0 , 0 , 0 , 0 }, // fisttp m16 + {"fist", 0x100 , 0 , 0x11 , 0x2002, 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // fist m16 + {"fistp", 0x100 , 0 , 0x11 , 0x2002, 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // fistp m16 + {"fbld", 0x100 , 0 , 0x11 , 0 , 0x2005, 0 , 0 , 0 , 0 , 0 , 0 }, // fbld m80 + {"fild", 0x100 , 0 , 0x11 , 0 , 0x2004, 0 , 0 , 0 , 0 , 0 , 0 }, // fild m64 + {"fbstp", 0x100 , 0 , 0x11 , 0x2005, 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // fbstp m80 + {"fistp", 0x100 , 0 , 0x11 , 0x2004, 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // fistp m64 + {0, 0 , 0 , 0x4011, 0 , 0x1040, 0 , 0 , 0 , 0 , 0 , 0 }, // illegal + {0, 0 , 0 , 0x4011, 0 , 0x1040, 0 , 0 , 0 , 0 , 0 , 0 }, // illegal + {0, 0 , 0 , 0x4011, 0 , 0x1040, 0 , 0 , 0 , 0 , 0 , 0 }, // illegal + {0, 0 , 0 , 0x4011, 0 , 0x1040, 0 , 0 , 0 , 0 , 0 , 0 }, // illegal + {0, 0x18 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x5 , 0 }, // Link to tertiary map 0x18 fnstsw ax + {"fucomip", 0x6 , 0 , 0x11 , 0xAF , 0x1040, 0 , 0 , 0 , 0 , 0 , 0x4 }, // fucomp st,st(i) + {"fcomip", 0x6 , 0 , 0x11 , 0xAF , 0x1040, 0 , 0 , 0 , 0 , 0 , 0x4 }, // fcomp st,st(i) + {0, 0 , 0 , 0x4011, 0 , 0x1040, 0 , 0 , 0 , 0 , 0 , 0 }}; // illegal + +// Tertiary opcode map for f.p. D9 / reg = 010 +// Indexed by rm bits of mod/reg/rm byte +SOpcodeDef OpcodeMap10[2] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"fnop", 0x100 , 0 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x40 }, // fnop + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }}; // the rest is illegal + +// Tertiary opcode map for f.p. D9 / reg = 100 +// Indexed by rm bits of mod/reg/rm byte +SOpcodeDef OpcodeMap11[8] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"fchs", 0x100 , 0 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // fchs + {"fabs", 0x100 , 0 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // fabs + {0, 0 , 0 , 0x4010, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // illegal + {0, 0 , 0 , 0x4010, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // illegal + {"ftst", 0x100 , 0 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // ftst + {"fxam", 0x100 , 0 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // fxam + {0, 0 , 0 , 0x4010, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // illegal + {0, 0 , 0 , 0x4010, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }}; // illegal + +// Tertiary opcode map for f.p. D9 / reg = 101 +// Indexed by rm bits of mod/reg/rm byte +SOpcodeDef OpcodeMap12[8] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"fld1", 0x100 , 0 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // fld1 + {"fldl2t", 0x100 , 0 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // + {"fldl2e", 0x100 , 0 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // + {"fldpi", 0x100 , 0 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // + {"fldlg2", 0x100 , 0 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // + {"fldln2", 0x100 , 0 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // + {"fldz", 0x100 , 0 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // + {0, 0 , 0 , 0x4010, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }}; // illegal + +// Tertiary opcode map for f.p. D9 / reg = 110 +// Indexed by rm bits of mod/reg/rm byte +SOpcodeDef OpcodeMap13[8] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"f2xm1", 0x100 , 0 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // f2xm1 + {"fyl2x", 0x100 , 0 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // + {"fptan", 0x100 , 0 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // + {"fpatan", 0x100 , 0 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // + {"fxtract", 0x100 , 0 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // + {"fprem1", 0x100 , 0 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // + {"fdecstp", 0x100 , 0 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // + {"fincstp", 0x100 , 0 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }}; // + +// Tertiary opcode map for f.p. D9 / reg = 111 +// Indexed by rm bits of mod/reg/rm byte +SOpcodeDef OpcodeMap14[8] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"fprem", 0x100 , 0 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // + {"fyl2xp1", 0x100 , 0 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // + {"fsqrt", 0x100 , 0 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // + {"fsincos", 0x101 , 0 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // + {"frndint", 0x100 , 0 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // + {"fscale", 0x100 , 0 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // + {"fsin", 0x101 , 0 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // + {"fcos", 0x101 , 0 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }}; // + +// Tertiary opcode map for f.p. DA / reg = 101 +// Indexed by rm bits of mod/reg/rm byte +SOpcodeDef OpcodeMap15[3] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {0, 0 , 0 , 0x4010, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // illegal + {"fucompp", 0x101 , 0 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // + {0, 0 , 0 , 0x4010, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }}; // illegal + +// Tertiary opcode map for f.p. DB / reg = 100 +// Indexed by rm bits of mod/reg/rm byte +SOpcodeDef OpcodeMap16[5] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {0, 0 , 0 , 0x4010, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // illegal + {0, 0 , 0 , 0x4010, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // illegal + {"fnclex", 0x100 , 0 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // + {"fninit", 0x100 , 0 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x8 }, // + {0, 0 , 0 , 0x4010, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }}; // illegal + +// Tertiary opcode map for f.p. DE / reg = 011 +// Indexed by rm bits of mod/reg/rm byte +SOpcodeDef OpcodeMap17[3] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {0, 0 , 0 , 0x4010, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // illegal + {"fcompp", 0x100 , 0 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x4 }, // + {0, 0 , 0 , 0x4010, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }}; // illegal + +// Tertiary opcode map for f.p. DF / reg = 100 +// Indexed by rm bits of mod/reg/rm byte +SOpcodeDef OpcodeMap18[2] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"fnstsw", 0x100 , 0 , 0x10 , 0xA2 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // + {0, 0 , 0 , 0x4010, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }}; // illegal + +// Secondary opcode map for IRET. Opcode byte = 0xCF +// Indexed by operand size +SOpcodeDef OpcodeMap19[3] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"iret", 0 , 0x102 , 0x2 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x10 }, // CF + {"iretd", 0 , 0x102 , 0x2 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x10 }, // CF + {"iretq", 0 , 0x1102 , 0x2 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x10 }}; // CF + +// Secondary opcode map for immediate group 1. Opcode byte = 0x80 +// Indexed by reg bits = 0 - 7 +SOpcodeDef OpcodeMap1A[8] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"add", 0 , 0x10 , 0x51 , 0x1 , 0x21 , 0 , 0 , 0 , 0 , 0 , 0 }, // 80 /0 + {"or", 0 , 0x10 , 0x51 , 0x1 , 0x31 , 0 , 0 , 0 , 0 , 0 , 0 }, // 80 /1 + {"adc", 0 , 0x10 , 0x51 , 0x1 , 0x21 , 0 , 0 , 0 , 0 , 0 , 0 }, // 80 /2 + {"sbb", 0 , 0x10 , 0x51 , 0x1 , 0x21 , 0 , 0 , 0 , 0 , 0 , 0 }, // 80 /3 + {"and", 0 , 0x10 , 0x51 , 0x1 , 0x31 , 0 , 0 , 0 , 0 , 0 , 0 }, // 80 /4 + {"sub", 0 , 0x10 , 0x51 , 0x1 , 0x21 , 0 , 0 , 0 , 0 , 0 , 0 }, // 80 /5 + {"xor", 0 , 0x10 , 0x51 , 0x1 , 0x31 , 0 , 0 , 0 , 0 , 0 , 0 }, // 80 /6 + {"cmp", 0 , 0 , 0x51 , 0x1 , 0x11 , 0 , 0 , 0 , 0 , 0 , 0x4 }}; // 80 /7 + +// Secondary opcode map for immediate group 1. Opcode byte = 0x81 +// Indexed by reg bits = 0 - 7 +SOpcodeDef OpcodeMap1B[8] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"add", 0 , 0x1110 , 0x91 , 0x9 , 0x28 , 0 , 0 , 0 , 0 , 0 , 0x80 }, // 81 /0 + {"or", 0 , 0x1110 , 0x91 , 0x9 , 0x39 , 0 , 0 , 0 , 0 , 0 , 0x80 }, // 81 /1 + {"adc", 0 , 0x1110 , 0x91 , 0x9 , 0x28 , 0 , 0 , 0 , 0 , 0 , 0x80 }, // 81 /2 + {"sbb", 0 , 0x1110 , 0x91 , 0x9 , 0x28 , 0 , 0 , 0 , 0 , 0 , 0x80 }, // 81 /3 + {"and", 0 , 0x1110 , 0x91 , 0x9 , 0x39 , 0 , 0 , 0 , 0 , 0 , 0x80 }, // 81 /4 + {"sub", 0 , 0x1110 , 0x91 , 0x9 , 0x28 , 0 , 0 , 0 , 0 , 0 , 0x80 }, // 81 /5 + {"xor", 0 , 0x1110 , 0x91 , 0x9 , 0x39 , 0 , 0 , 0 , 0 , 0 , 0x80 }, // 81 /6 + {"cmp", 0 , 0x1100 , 0x91 , 0x9 , 0x28 , 0 , 0 , 0 , 0 , 0 , 0x84 }}; // 81 /7 + +// Secondary opcode map for immediate group 1. Opcode byte = 0x82. +// Undocumented opcode. Signed byte instructions do the same as unsigned byte instructions at 0x80 +SOpcodeDef OpcodeMap1C[8] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"add", 0x8000, 0x10 , 0x4051, 0x1 , 0x21 , 0 , 0 , 0 , 0 , 0 , 0 }, // 82 /0 + {"or", 0x8000, 0x10 , 0x4051, 0x1 , 0x31 , 0 , 0 , 0 , 0 , 0 , 0 }, // 82 /1 + {"adc", 0x8000, 0x10 , 0x4051, 0x1 , 0x21 , 0 , 0 , 0 , 0 , 0 , 0 }, // 82 /2 + {"sbb", 0x8000, 0x10 , 0x4051, 0x1 , 0x21 , 0 , 0 , 0 , 0 , 0 , 0 }, // 82 /3 + {"and", 0x8000, 0x10 , 0x4051, 0x1 , 0x31 , 0 , 0 , 0 , 0 , 0 , 0 }, // 82 /4 + {"sub", 0x8000, 0x10 , 0x4051, 0x1 , 0x21 , 0 , 0 , 0 , 0 , 0 , 0 }, // 82 /5 + {"xor", 0x8000, 0x10 , 0x4051, 0x1 , 0x31 , 0 , 0 , 0 , 0 , 0 , 0 }, // 82 /6 + {"cmp", 0x8000, 0 , 0x4051, 0x1 , 0x11 , 0 , 0 , 0 , 0 , 0 , 0x4 }}; // 82 /7 + +// Secondary opcode map for immediate group 1. Opcode byte = 0x83 +// Indexed by reg bits = 0 - 7 +SOpcodeDef OpcodeMap1D[8] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"add", 0 , 0x1110 , 0x51 , 0x9 , 0x21 , 0 , 0 , 0 , 0 , 0 , 0 }, // 83 /0 + {"or", 0 , 0x1110 , 0x51 , 0x9 , 0x31 , 0 , 0 , 0 , 0 , 0 , 0 }, // 83 /1 + {"adc", 0 , 0x1110 , 0x51 , 0x9 , 0x21 , 0 , 0 , 0 , 0 , 0 , 0 }, // 83 /2 + {"sbb", 0 , 0x1110 , 0x51 , 0x9 , 0x21 , 0 , 0 , 0 , 0 , 0 , 0 }, // 83 /3 + {"and", 0 , 0x1110 , 0x51 , 0x9 , 0x31 , 0 , 0 , 0 , 0 , 0 , 0 }, // 83 /4 + {"sub", 0 , 0x1110 , 0x51 , 0x9 , 0x21 , 0 , 0 , 0 , 0 , 0 , 0 }, // 83 /5 + {"xor", 0 , 0x1110 , 0x51 , 0x9 , 0x31 , 0 , 0 , 0 , 0 , 0 , 0 }, // 83 /6 + {"cmp", 0 , 0x1100 , 0x51 , 0x9 , 0x11 , 0 , 0 , 0 , 0 , 0 , 0x4 }}; // 83 /7 + +// Secondary opcode map for shift group 2. Opcode byte = 0xC0 +// Indexed by reg bits = 0 - 7. +SOpcodeDef OpcodeMap1E[8] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"rol", 0 , 0 , 0x51 , 0x1 , 0x11 , 0 , 0 , 0 , 0 , 0 , 0 }, // C0 /0 rol byte ptr r/m,ib + {"ror", 0 , 0 , 0x51 , 0x1 , 0x11 , 0 , 0 , 0 , 0 , 0 , 0 }, // C0 /1 + {"rcl", 0 , 0 , 0x51 , 0x1 , 0x11 , 0 , 0 , 0 , 0 , 0 , 0 }, // C0 /2 + {"rcr", 0 , 0 , 0x51 , 0x1 , 0x11 , 0 , 0 , 0 , 0 , 0 , 0 }, // C0 /3 + {"shl", 0 , 0 , 0x51 , 0x1 , 0x11 , 0 , 0 , 0 , 0 , 0 , 0 }, // C0 /4 + {"shr", 0 , 0 , 0x51 , 0x1 , 0x11 , 0 , 0 , 0 , 0 , 0 , 0 }, // C0 /5 + {"sal", 0 , 0 , 0x51 , 0x1 , 0x11 , 0 , 0 , 0 , 0 , 0 , 0 }, // C0 /6 + {"sar", 0 , 0 , 0x51 , 0x1 , 0x11 , 0 , 0 , 0 , 0 , 0 , 0 }}; // C0 /7 + +// Secondary opcode map for shift group 2. Opcode byte = 0xC1 +// Indexed by reg bits = 0 - 7. +SOpcodeDef OpcodeMap1F[8] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"rol", 0 , 0x1100 , 0x51 , 0x9 , 0x11 , 0 , 0 , 0 , 0 , 0 , 0 }, // C1 /0 rol word ptr r/m,ib + {"ror", 0 , 0x1100 , 0x51 , 0x9 , 0x11 , 0 , 0 , 0 , 0 , 0 , 0 }, // C1 /1 + {"rcl", 0 , 0x1100 , 0x51 , 0x9 , 0x11 , 0 , 0 , 0 , 0 , 0 , 0 }, // C1 /2 + {"rcr", 0 , 0x1100 , 0x51 , 0x9 , 0x11 , 0 , 0 , 0 , 0 , 0 , 0 }, // C1 /3 + {"shl", 0 , 0x1100 , 0x51 , 0x9 , 0x11 , 0 , 0 , 0 , 0 , 0 , 0 }, // C1 /4 + {"shr", 0 , 0x1100 , 0x51 , 0x9 , 0x11 , 0 , 0 , 0 , 0 , 0 , 0 }, // C1 /5 + {"sal", 0 , 0x1100 , 0x51 , 0x9 , 0x11 , 0 , 0 , 0 , 0 , 0 , 0 }, // C1 /6 + {"sar", 0 , 0x1100 , 0x51 , 0x9 , 0x11 , 0 , 0 , 0 , 0 , 0 , 0 }}; // C1 /7 + +// Secondary opcode map for shift group 2. Opcode byte = 0xD0 +// Indexed by reg bits = 0 - 7. +SOpcodeDef OpcodeMap20[8] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"rol", 0 , 0 , 0x11 , 0x1 , 0xB1 , 0 , 0 , 0 , 0 , 0 , 0 }, // C2 /0 rol byte ptr r/m,1 + {"ror", 0 , 0 , 0x11 , 0x1 , 0xB1 , 0 , 0 , 0 , 0 , 0 , 0 }, // C2 /1 + {"rcl", 0 , 0 , 0x11 , 0x1 , 0xB1 , 0 , 0 , 0 , 0 , 0 , 0 }, // C2 /2 + {"rcr", 0 , 0 , 0x11 , 0x1 , 0xB1 , 0 , 0 , 0 , 0 , 0 , 0 }, // C2 /3 + {"shl", 0 , 0 , 0x11 , 0x1 , 0xB1 , 0 , 0 , 0 , 0 , 0 , 0 }, // C2 /4 + {"shr", 0 , 0 , 0x11 , 0x1 , 0xB1 , 0 , 0 , 0 , 0 , 0 , 0 }, // C2 /5 + {"sal", 0 , 0 , 0x11 , 0x1 , 0xB1 , 0 , 0 , 0 , 0 , 0 , 0 }, // C2 /6 + {"sar", 0 , 0 , 0x11 , 0x1 , 0xB1 , 0 , 0 , 0 , 0 , 0 , 0 }}; // C2 /7 + +// Secondary opcode map for shift group 2. Opcode byte = 0xD1 +// Indexed by reg bits = 0 - 7. +SOpcodeDef OpcodeMap21[8] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"rol", 0 , 0x1100 , 0x11 , 0x9 , 0xB1 , 0 , 0 , 0 , 0 , 0 , 0 }, // C3 /0 rol word ptr r/m,1 + {"ror", 0 , 0x1100 , 0x11 , 0x9 , 0xB1 , 0 , 0 , 0 , 0 , 0 , 0 }, // C3 /1 + {"rcl", 0 , 0x1100 , 0x11 , 0x9 , 0xB1 , 0 , 0 , 0 , 0 , 0 , 0 }, // C3 /2 + {"rcr", 0 , 0x1100 , 0x11 , 0x9 , 0xB1 , 0 , 0 , 0 , 0 , 0 , 0 }, // C3 /3 + {"shl", 0 , 0x1100 , 0x11 , 0x9 , 0xB1 , 0 , 0 , 0 , 0 , 0 , 0 }, // C3 /4 + {"shr", 0 , 0x1100 , 0x11 , 0x9 , 0xB1 , 0 , 0 , 0 , 0 , 0 , 0 }, // C3 /5 + {"sal", 0 , 0x1100 , 0x11 , 0x9 , 0xB1 , 0 , 0 , 0 , 0 , 0 , 0 }, // C3 /6 + {"sar", 0 , 0x1100 , 0x11 , 0x9 , 0xB1 , 0 , 0 , 0 , 0 , 0 , 0 }}; // C3 /7 + +// Secondary opcode map for shift group 2. Opcode byte = 0xD2 +// Indexed by reg bits = 0 - 7. +SOpcodeDef OpcodeMap22[8] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"rol", 0 , 0 , 0x11 , 0x1 , 0xB3 , 0 , 0 , 0 , 0 , 0 , 0 }, // C2 /0 rol byte ptr r/m,cl + {"ror", 0 , 0 , 0x11 , 0x1 , 0xB3 , 0 , 0 , 0 , 0 , 0 , 0 }, // C2 /1 + {"rcl", 0 , 0 , 0x11 , 0x1 , 0xB3 , 0 , 0 , 0 , 0 , 0 , 0 }, // C2 /2 + {"rcr", 0 , 0 , 0x11 , 0x1 , 0xB3 , 0 , 0 , 0 , 0 , 0 , 0 }, // C2 /3 + {"shl", 0 , 0 , 0x11 , 0x1 , 0xB3 , 0 , 0 , 0 , 0 , 0 , 0 }, // C2 /4 + {"shr", 0 , 0 , 0x11 , 0x1 , 0xB3 , 0 , 0 , 0 , 0 , 0 , 0 }, // C2 /5 + {"sal", 0 , 0 , 0x11 , 0x1 , 0xB3 , 0 , 0 , 0 , 0 , 0 , 0 }, // C2 /6 + {"sar", 0 , 0 , 0x11 , 0x1 , 0xB3 , 0 , 0 , 0 , 0 , 0 , 0 }}; // C2 /7 + +// Secondary opcode map for shift group 2. Opcode byte = 0xD3 +// Indexed by reg bits = 0 - 7. +SOpcodeDef OpcodeMap23[8] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"rol", 0 , 0x1100 , 0x11 , 0x9 , 0xB3 , 0 , 0 , 0 , 0 , 0 , 0 }, // C3 /0 rol word ptr r/m,cl + {"ror", 0 , 0x1100 , 0x11 , 0x9 , 0xB3 , 0 , 0 , 0 , 0 , 0 , 0 }, // C3 /1 + {"rcl", 0 , 0x1100 , 0x11 , 0x9 , 0xB3 , 0 , 0 , 0 , 0 , 0 , 0 }, // C3 /2 + {"rcr", 0 , 0x1100 , 0x11 , 0x9 , 0xB3 , 0 , 0 , 0 , 0 , 0 , 0 }, // C3 /3 + {"shl", 0 , 0x1100 , 0x11 , 0x9 , 0xB3 , 0 , 0 , 0 , 0 , 0 , 0 }, // C3 /4 + {"shr", 0 , 0x1100 , 0x11 , 0x9 , 0xB3 , 0 , 0 , 0 , 0 , 0 , 0 }, // C3 /5 + {"sal", 0 , 0x1100 , 0x11 , 0x9 , 0xB3 , 0 , 0 , 0 , 0 , 0 , 0 }, // C3 /6 + {"sar", 0 , 0x1100 , 0x11 , 0x9 , 0xB3 , 0 , 0 , 0 , 0 , 0 , 0 }}; // C3 /7 + +// Secondary opcode map for group 3. Opcode byte = 0xF6 +// Indexed by reg bits = 0 - 7. +SOpcodeDef OpcodeMap24[8] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"test", 0 , 0 , 0x51 , 0x1 , 0x31 , 0 , 0 , 0 , 0 , 0 , 0x4 }, // test rm8,ib + {"test", 0 , 0 , 0x4051, 0x1 , 0x31 , 0 , 0 , 0 , 0 , 0 , 0x4 }, // test rm8,ib. undocumented + {"not", 0 , 0x1C50 , 0x11 , 0x1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // not rm8 + {"neg", 0 , 0x1C50 , 0x11 , 0x1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // neg rm8 + {"mul", 0 , 0 , 0x11 , 0x1 , 0 , 0 , 0 , 0 , 0 , 0 , 0x8 }, // mul rm8 + {"imul", 0 , 0 , 0x11 , 0x1 , 0 , 0 , 0 , 0 , 0 , 0 , 0x8 }, // imul rm8 + {"div", 0 , 0 , 0x11 , 0x1 , 0 , 0 , 0 , 0 , 0 , 0 , 0x8 }, // div rm8 + {"idiv", 0 , 0 , 0x11 , 0x1 , 0 , 0 , 0 , 0 , 0 , 0 , 0x8 }}; // idiv rm8 + +// Secondary opcode map for group 3. Opcode byte = 0xF7 +// Indexed by reg bits = 0 - 7. +SOpcodeDef OpcodeMap25[8] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"test", 0 , 0x1100 , 0x91 , 0x9 , 0x39 , 0 , 0 , 0 , 0 , 0 , 0x4 }, // test rm,i + {"test", 0 , 0x1100 , 0x4091, 0x9 , 0x39 , 0 , 0 , 0 , 0 , 0 , 0x4 }, // test rm,i. undocumented + {"not", 0 , 0x1D50 , 0x11 , 0x9 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // not rm + {"neg", 0 , 0x1D50 , 0x11 , 0x9 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // neg rm + {"mul", 0 , 0x1100 , 0x11 , 0x9 , 0 , 0 , 0 , 0 , 0 , 0 , 0x8 }, // mul rm + {"imul", 0 , 0x1100 , 0x11 , 0x9 , 0 , 0 , 0 , 0 , 0 , 0 , 0x8 }, // imul rm + {"div", 0 , 0x1100 , 0x11 , 0x9 , 0 , 0 , 0 , 0 , 0 , 0 , 0x8 }, // div rm + {"idiv", 0 , 0x1100 , 0x11 , 0x9 , 0 , 0 , 0 , 0 , 0 , 0 , 0x8 }}; // idiv rm + +// Secondary opcode map for group 4. Opcode byte = 0xFE +// Indexed by reg bits = 0 - 7. +SOpcodeDef OpcodeMap26[8] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"inc", 0 , 0xC50 , 0x11 , 0x1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // inc rm8 + {"dec", 0 , 0xC50 , 0x11 , 0x1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // dec rm8 + {0, 0 , 0 , 0x4011, 0x1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }}; // illegal opcode + +// Secondary opcode map for group 5. Opcode byte = 0xFF +// Indexed by reg bits = 0 - 7. +SOpcodeDef OpcodeMap27[8] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"inc", 0 , 0x1D50 , 0x11 , 0x9 , 0 , 0 , 0 , 0 , 0 , 0 , 0x80 }, // inc rm + {"dec", 0 , 0x1D50 , 0x11 , 0x9 , 0 , 0 , 0 , 0 , 0 , 0 , 0x80 }, // dec rm + {"call", 0 , 0x2182 , 0x11 , 0xC , 0 , 0 , 0 , 0 , 0 , 0 , 0x8 }, // call indirect rm + {"call", 0 , 0x1102 , 0x811 , 0x200D, 0 , 0 , 0 , 0 , 0 , 0 , 0x28 }, // call indirect far + {"jmp", 0 , 0x2180 , 0x11 , 0xB , 0 , 0 , 0 , 0 , 0 , 0 , 0x14 }, // jmp indirect rm + {"jmp", 0 , 0x1100 , 0x811 , 0x200D, 0 , 0 , 0 , 0 , 0 , 0 , 0x30 }, // jmp indirect far + {"push", 0 , 0x2102 , 0x11 , 0xA , 0 , 0 , 0 , 0 , 0 , 0 , 0x4 }, // push rm + {0, 0 , 0 , 0x4011, 0x9 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }}; // illegal opcode + +// Secondary opcode map for immediate group 1A. Opcode byte = 0x8F +// Indexed by reg bits = 0 - 7. Values != 0 are discouraged +SOpcodeDef OpcodeMap28[2] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"pop", 0 , 0x2102 , 0x11 , 0x9 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 8F + {"pop", 0 , 0x2102 , 0x4011, 0x9 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }}; // 8F + +// Tertiary opcode map for pinsrw. Opcode byte = 0F C4 +// Indexed by mod bits 0 register vs. memory operand +SOpcodeDef OpcodeMap29[2] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"pinsrw", 0x7 ,0x892200, 0x59 , 0x1102, 0x1102, 0x2002, 0x11 , 0x1000, 0 , 0 , 0x2 }, // 0F C4 mem16 + {"pinsrw", 0x7 ,0x892200, 0x59 , 0x1102, 0x1102, 0x1009, 0x11 , 0 , 0 , 0 , 0x2 }}; // 0F C4 register + +// Tertiary opcode map for group 6. Opcode byte = 0F 00 +// Indexed by reg bits = 0 - 7. +SOpcodeDef OpcodeMap2A[8] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"sldt", 0x2 , 0x1100 , 0x11 , 0x2 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // + {"str", 0x802 , 0x100 , 0x11 , 0x2 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // + {"lldt", 0x802 , 0x2000 , 0x11 , 0 , 0x2002, 0 , 0 , 0 , 0 , 0 , 0 }, // + {"ltr", 0x802 , 0 , 0x11 , 0 , 0x2 , 0 , 0 , 0 , 0 , 0 , 0 }, // + {"verr", 0x802 , 0 , 0x11 , 0 , 0x2 , 0 , 0 , 0 , 0 , 0 , 0 }, // + {"verw", 0x802 , 0 , 0x11 , 0 , 0x2 , 0 , 0 , 0 , 0 , 0 , 0 }, // + {0, 0 , 0 , 0x4011, 0 , 0x2 , 0 , 0 , 0 , 0 , 0 , 0 }, // illegal + {0, 0 , 0 , 0x4011, 0 , 0x2 , 0 , 0 , 0 , 0 , 0 , 0 }}; // illegal + +// Tertiary opcode map for group 7. Opcode byte = 0F 01 +// Indexed by reg bits = 0 - 7 and mod = 11b. +SOpcodeDef OpcodeMap2B[16] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"sgdt", 0x802 , 0x1100 , 0x11 , 0x200D, 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // mod<3, reg=0 + {"sidt", 0x802 , 0x1100 , 0x11 , 0x200D, 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // + {"lgdt", 0x802 , 0x1100 , 0x11 , 0 , 0x200D, 0 , 0 , 0 , 0 , 0 , 0 }, // + {"lidt", 0x802 , 0x1100 , 0x11 , 0 , 0x200D, 0 , 0 , 0 , 0 , 0 , 0 }, // + {"smsw", 0x2 , 0 , 0x11 , 0x2 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // + {0, 0x133 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 9 , 0 }, // link to rstorssp + {"lmsw", 0x802 , 0 , 0x11 , 0 , 0x2 , 0 , 0 , 0 , 0 , 0 , 0 }, // + {"invlpg", 0x4 , 0 , 0x11 , 0 , 0x2006, 0 , 0 , 0 , 0 , 0 , 0 }, // mod<3, reg=7 + + {0, 0x36 , 0 , 0x4011, 0 , 0 , 0 , 0 , 0 , 0 , 5 , 0 }, // link to quarternary map, vmcall etc. + {0, 0x37 , 0 , 0x4011, 0 , 0 , 0 , 0 , 0 , 0 , 5 , 0 }, // link to quarternary map, monitor, mwait + {0, 0xA9 , 0 , 0x4011, 0 , 0 , 0 , 0 , 0 , 0 , 5 , 0 }, // link to quarternary map, xgetbv, xsetbv + {0, 0xAA , 0 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 5 , 0 }, // link AMD virtualization + {"smsw", 0x2 , 0x1100 , 0x11 , 0x9 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // + {0, 0x130 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 5 , 0 }, // link to incssp etc. + {"lmsw", 0x802 , 0 , 0x11 , 0 , 0x2 , 0 , 0 , 0 , 0 , 0 , 0 }, // + {0, 0xAB , 0 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 5 , 0 }}; // link SWAPGS and RDTSCP + +// Secondary opcode map for group 8. Opcode byte = 0F BA: bt +// Indexed by reg bits = 0 - 7. +SOpcodeDef OpcodeMap2C[8] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {0, 0 , 0 , 0x51 , 0x9 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // Illegal + {0, 0 , 0 , 0x51 , 0x9 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // Illegal + {0, 0 , 0 , 0x51 , 0x9 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // Illegal + {0, 0 , 0 , 0x51 , 0x9 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // Illegal + {"bt", 0x3 , 0x1100 , 0x51 , 0x9 , 0x11 , 0 , 0 , 0 , 0 , 0 , 0 }, // + {"bts", 0x3 , 0x1100 , 0x51 , 0x9 , 0x11 , 0 , 0 , 0 , 0 , 0 , 0 }, // + {"btr", 0x3 , 0x1100 , 0x51 , 0x9 , 0x11 , 0 , 0 , 0 , 0 , 0 , 0 }, // + {"btc", 0x3 , 0x1100 , 0x51 , 0x9 , 0x11 , 0 , 0 , 0 , 0 , 0 , 0 }}; // + +// Secondary opcode map for addsub. Opcode byte = 0F D0 +// Indexed by prefix = none, 66, F2, F3 +SOpcodeDef OpcodeMap2D[4] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"addsub", 0x13 , 0xD0000, 0x4019, 0x124F, 0x124F, 0x24F , 0 , 0 , 0 , 0 , 0x2 }, // 0F D0. undefined + {"addsubpd", 0x13 , 0xD0200, 0x19 , 0x124C, 0x124C, 0x24C , 0 , 0 , 0 , 0 , 0x2 }, // 66 0F D0. addsubpd + {"addsubps", 0x13 , 0xD0800, 0x19 , 0x124B, 0x124B, 0x24B , 0 , 0 , 0 , 0 , 0x2 }, // F2 0F D0. addsubps + {"addsub", 0x13 , 0xD0400, 0x4019, 0x124F, 0x124F, 0x24F , 0 , 0 , 0 , 0 , 0x2 }}; // F3 0F D0. undefined + +// Secondary opcode map for group 10. Opcode byte = 0F B9 +// Indexed by reg bits = 0 - 7. +SOpcodeDef OpcodeMap2E[1] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"ud1", 0 , 0 , 0x4012, 0x1009, 0x6 , 0 , 0 , 0 , 0 , 0 , 0 }}; // Invalid opcode, possibly used for emulation + +// Secondary opcode map for mov group 11. Opcode byte = 0xC6 +// Indexed by reg bits and mod. +SOpcodeDef OpcodeMap2F[16] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"mov", 0 , 0xC45 , 0x51 , 0x1 , 0x11 , 0 , 0 , 0 , 0 , 0 , 0 }, // C6 m /0 mov m,ib + {"mov", 0 , 0x5 , 0x4051, 0x1 , 0x11 , 0 , 0 , 0 , 0 , 0 , 0 }, // C6 m /1 + {"mov", 0 , 0x5 , 0x4051, 0x1 , 0x11 , 0 , 0 , 0 , 0 , 0 , 0 }, // C6 m /2 + {"mov", 0 , 0x5 , 0x4051, 0x1 , 0x11 , 0 , 0 , 0 , 0 , 0 , 0 }, // C6 m /3 + {"mov", 0 , 0x5 , 0x4051, 0x1 , 0x11 , 0 , 0 , 0 , 0 , 0 , 0 }, // C6 m /4 + {"mov", 0 , 0x5 , 0x4051, 0x1 , 0x11 , 0 , 0 , 0 , 0 , 0 , 0 }, // C6 m /5 + {"mov", 0 , 0x5 , 0x4051, 0x1 , 0x11 , 0 , 0 , 0 , 0 , 0 , 0 }, // C6 m /6 + {"mov", 0 , 0x5 , 0x4051, 0x1 , 0x11 , 0 , 0 , 0 , 0 , 0 , 0 }, // C6 m /7 + {"", 0 , 0x5 , 0x4051, 0x1 , 0x11 , 0 , 0 , 0 , 0 , 0 , 0 }, // C6 r /0 + {"", 0 , 0x5 , 0x4051, 0x1 , 0x11 , 0 , 0 , 0 , 0 , 0 , 0 }, // C6 r /1 + {"", 0 , 0x5 , 0x4051, 0x1 , 0x11 , 0 , 0 , 0 , 0 , 0 , 0 }, // C6 r /2 + {"", 0 , 0x5 , 0x4051, 0x1 , 0x11 , 0 , 0 , 0 , 0 , 0 , 0 }, // C6 r /3 + {"", 0 , 0x5 , 0x4051, 0x1 , 0x11 , 0 , 0 , 0 , 0 , 0 , 0 }, // C6 r /4 + {"", 0 , 0x5 , 0x4051, 0x1 , 0x11 , 0 , 0 , 0 , 0 , 0 , 0 }, // C6 r /5 + {"", 0 , 0x5 , 0x4051, 0x1 , 0x11 , 0 , 0 , 0 , 0 , 0 , 0 }, // C6 r /6 + {"xabort", 0x1D , 0 , 0x50 , 0 , 0x31 , 0 , 0 , 0 , 0 , 0 , 0 }}; // C6 r /7 + +// Secondary opcode map for mov group 11. Opcode byte = 0xC7 +// Indexed by reg bits and mod. +SOpcodeDef OpcodeMap30[16] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"mov", 0 , 0x1D45 , 0x91 , 0x9 , 0x29 , 0 , 0 , 0 , 0 , 0 , 0 }, // C7 m /0 mov m,iw + {"mov", 0 , 0x5 , 0x4091, 0x9 , 0x29 , 0 , 0 , 0 , 0 , 0 , 0 }, // C7 m /1 + {"mov", 0 , 0x5 , 0x4091, 0x9 , 0x29 , 0 , 0 , 0 , 0 , 0 , 0 }, // C7 m /2 + {"mov", 0 , 0x5 , 0x4091, 0x9 , 0x29 , 0 , 0 , 0 , 0 , 0 , 0 }, // C7 m /3 + {"mov", 0 , 0x5 , 0x4091, 0x9 , 0x29 , 0 , 0 , 0 , 0 , 0 , 0 }, // C7 m /4 + {"mov", 0 , 0x5 , 0x4091, 0x9 , 0x29 , 0 , 0 , 0 , 0 , 0 , 0 }, // C7 m /5 + {"mov", 0 , 0x5 , 0x4091, 0x9 , 0x29 , 0 , 0 , 0 , 0 , 0 , 0 }, // C7 m /6 + {"mov", 0 , 0x5 , 0x4091, 0x9 , 0x29 , 0 , 0 , 0 , 0 , 0 , 0 }, // C7 m /7 + {"mov", 0 , 0x1105 , 0x91 , 0x9 , 0x29 , 0 , 0 , 0 , 0 , 0 , 0 }, // C7 r /0 mov r,iw + {"", 0 , 0 , 0x91 , 0 , 0x29 , 0 , 0 , 0 , 0 , 0 , 0 }, // C7 r /1 + {"", 0 , 0 , 0x91 , 0 , 0x29 , 0 , 0 , 0 , 0 , 0 , 0 }, // C7 r /2 + {"", 0 , 0 , 0x91 , 0 , 0x29 , 0 , 0 , 0 , 0 , 0 , 0 }, // C7 r /3 + {"", 0 , 0 , 0x91 , 0 , 0x29 , 0 , 0 , 0 , 0 , 0 , 0 }, // C7 r /4 + {"", 0 , 0 , 0x91 , 0 , 0x29 , 0 , 0 , 0 , 0 , 0 , 0 }, // C7 r /5 + {"", 0 , 0 , 0x91 , 0 , 0x29 , 0 , 0 , 0 , 0 , 0 , 0 }, // C7 r /6 + {"xbegin", 0x1D , 0x100 , 0x90 , 0 , 0x29 , 0 , 0 , 0 , 0 , 0 , 0 }}; // C7 r /7 + +// Secondary opcode map for group 12. Opcode byte = 0F 71 +// Indexed by reg bits = 0 - 7. +SOpcodeDef OpcodeMap31[8] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {0, 0x7 , 0x90200, 0x58 , 0x1102, 0x1102, 0x11 , 0 , 0 , 0 , 0 , 0x2 }, // Illegal + {0, 0x7 , 0x90200, 0x58 , 0x1102, 0x1102, 0x11 , 0 , 0 , 0 , 0 , 0x2 }, // Illegal + {"psrlw", 0x7 ,0x8D2200, 0x58 , 0x1102, 0x1102, 0x11 , 0 , 0x20 , 0 , 0 , 0x2 }, // 2 + {0, 0x7 , 0x90200, 0x58 , 0x1102, 0x1102, 0x11 , 0 , 0 , 0 , 0 , 0x2 }, // Illegal + {"psraw", 0x7 ,0x8D2200, 0x58 , 0x1102, 0x1102, 0x11 , 0 , 0x20 , 0 , 0 , 0x2 }, // 4 + {0, 0x7 , 0x90200, 0x58 , 0x1102, 0x1102, 0x11 , 0 , 0 , 0 , 0 , 0x2 }, // Illegal + {"psllw", 0x7 ,0x8D2200, 0x58 , 0x1102, 0x1102, 0x11 , 0 , 0x20 , 0 , 0 , 0x2 }, // 6 + {0, 0x7 , 0x90200, 0x58 , 0x1102, 0x1102, 0x11 , 0 , 0 , 0 , 0 , 0x2 }}; // Illegal + +// Secondary opcode map for group 13. Opcode byte = 0F 72 +// Indexed by reg bits = 0 - 7. +SOpcodeDef OpcodeMap32[8] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"vpror", 0x20 ,0x893200, 0x58 , 0x1209, 0x209 , 0x11 , 0 , 0x21 , 0 , 0 , 0x1 }, // /0 + {"vprol", 0x20 ,0x893200, 0x58 , 0x1209, 0x209 , 0x11 , 0 , 0x21 , 0 , 0 , 0x1 }, // /1 + {"psrld", 0x12 ,0xCD3200, 0x58 , 0x1103, 0x103 , 0x11 , 0 , 0x21 , 0x1406, 0 , 0x2 }, // /2 + {0, 0x12 , 0x90200, 0x58 , 0x1103, 0x103 , 0x11 , 0 , 0 , 0 , 0 , 0x2 }, // Illegal + {"psra", 0x12 ,0xCD3200, 0x58 , 0x1109, 0x109 , 0x11 , 0 , 0x31 , 0x1406, 0 , 0x3 }, // /4. W bit controls operand size only if EVEX + {0, 0x12 , 0x90200, 0x58 , 0x1103, 0x103 , 0x11 , 0 , 0 , 0 , 0 , 0x2 }, // Illegal + {"pslld", 0x12 ,0xCD3200, 0x58 , 0x1103, 0x103 , 0x11 , 0 , 0x21 , 0x1406, 0 , 0x2 }, // /6 + {0, 0x12 , 0x90200, 0x58 , 0x1103, 0x103 , 0x11 , 0 , 0 , 0 , 0 , 0x2 }}; // Illegal + +// Secondary opcode map for group 14. Opcode byte = 0F 73 +// Indexed by reg bits = 0 - 7. +SOpcodeDef OpcodeMap33[8] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {0, 0x12 , 0 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // /0 Illegal + {0, 0x12 , 0 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // /1 Illegal + {"psrlq", 0x12 ,0x8D3200, 0x58 , 0x1104, 0x104 , 0x11 , 0 , 0x21 , 0 , 0 , 0x2 }, // /2 + {"psrldq", 0x12 , 0xDA200, 0x58 , 0x1204, 0x204 , 0x11 , 0 , 0 , 0 , 0 , 0x2 }, // /3 Not valid without 66 prefix + {0, 0x12 , 0 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // /4 Illegal + {0, 0x12 , 0 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // /5 Illegal + {"psllq", 0x12 ,0x8D3200, 0x58 , 0x1104, 0x104 , 0x11 , 0 , 0x21 , 0 , 0 , 0x2 }, // /6 + {"pslldq", 0x12 ,0x8DA200, 0x58 , 0x1204, 0x204 , 0x11 , 0 , 0 , 0 , 0 , 0x2 }}; // /7 Not valid without 66 prefix + +// Secondary opcode map for group 15. Opcode byte = 0F AE +// Indexed by reg bits = 0 - 7 and mod = 3 +// These codes are without VEX prefix. Same codes with VEX or MVEX prefix are in OpcodeMapCD +SOpcodeDef OpcodeMap34[16] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"fxsave", 0x11 , 0 , 0x11 , 0x2006, 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F AE /0 + {"fxrstor", 0x11 , 0 , 0x11 , 0 , 0x2006, 0 , 0 , 0 , 0 , 0 , 0x8 }, // 0F AE /1 + {"ldmxcsr", 0x11 , 0x10000, 0x11 , 0 , 0x2003, 0 , 0 , 0 , 0 , 0 , 0x2 }, // 0F AE /2 + {"stmxcsr", 0x11 , 0x10000, 0x11 , 0x2003, 0 , 0 , 0 , 0 , 0 , 0 , 0x2 }, // 0F AE /3 + {0, 0 , 0 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // Illegal + {0, 0x134 , 0 , 0x11 , 0 , 0 , 0 , 0 , 0 , 0 , 9 , 0 }, // 0F AE /5. Link setssbsy + {0, 0xF3 , 0 , 0x11 , 0 , 0 , 0 , 0 , 0 , 0 , 9 , 0 }, // 0F AE /6. Link xsaveopt + {0, 0xF2 , 0 , 0x11 , 0 , 0 , 0 , 0 , 0 , 0 , 9 , 0 }, // 0F AE /7. Link clflush + {"rdfsbase", 0x10000,0x1400 , 0x11 , 0x1009, 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // F3 0F AE m-0 + {"rdgsbase", 0x10000,0x1400 , 0x11 , 0x1009, 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // F3 0F AE m-1 + {"wrfsbase", 0x10000,0x1400 , 0x11 , 0 , 0x1009, 0 , 0 , 0 , 0 , 0 , 0 }, // F3 0F AE m-2 + {"wrgsbase", 0x10000,0x1400 , 0x11 , 0 , 0x1009, 0 , 0 , 0 , 0 , 0 , 0 }, // F3 0F AE m-3 + {0, 0 , 0 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // Illegal + {"lfence", 0x12 , 0 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // m-5 + {"mfence", 0x12 , 0 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // m-6 + {0, 0xF4 , 0 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 9 , 0 }}; // m-7. Link sfence, pcommit + +// Secondary opcode map for group 16. Opcode byte = 0F 18 +// Indexed by reg bits = 0 - 7. +SOpcodeDef OpcodeMap35[8] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"prefetchnta",0x13 ,0x410000, 0x11 , 0 , 0x2006, 0 , 0 , 0 , 0x2 , 0 , 0x2 }, // 0F 18 /0 + {"prefetcht0",0x13 ,0x410000, 0x11 , 0 , 0x2006, 0 , 0 , 0 , 0x2 , 0 , 0x2 }, // 0F 18 /1 + {"prefetcht1",0x13 ,0x410000, 0x11 , 0 , 0x2006, 0 , 0 , 0 , 0x2 , 0 , 0x2 }, // 0F 18 /2 + {"prefetcht2",0x13 ,0x410000, 0x11 , 0 , 0x2006, 0 , 0 , 0 , 0x2 , 0 , 0x2 }, // 0F 18 /3 + {"vprefetchenta",0x13,0x430000,0x11 , 0 , 0x2006, 0 , 0 , 0 , 0x2 , 0 , 0 }, // 0F 18 /4 + {"vprefetche0",0x13 ,0x430000,0x11 , 0 , 0x2006, 0 , 0 , 0 , 0x2 , 0 , 0 }, // 0F 18 /5 + {"vprefetche1",0x13 ,0x430000,0x11 , 0 , 0x2006, 0 , 0 , 0 , 0x2 , 0 , 0 }, // 0F 18 /6 + {"vprefetche2",0x13 ,0x430000,0x11 , 0 , 0x2006, 0 , 0 , 0 , 0x2 , 0 , 0 }}; // 0F 18 /7 + +// Quarternary opcode map for group 7. 0F 01 reg = 0 +// Indexed by rm bits of mod/reg/rm byte +SOpcodeDef OpcodeMap36[6] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {0, 0 , 0 , 0x4010, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // illegal + {"vmcall", 0x813 , 0 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x8 }, // Intel processor only? + {"vmlaunch", 0x813 , 0 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x8 }, // Intel processor only? + {"vmresume", 0x813 , 0 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // Intel processor only? + {"vmxoff", 0x813 , 0 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // Intel processor only? + {0, 0 , 0 , 0x4010, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }}; // illegal + +// Quarternary opcode map for group 7. 0F 01 reg = 1 +// Indexed by rm bits of mod/reg/rm byte +SOpcodeDef OpcodeMap37[5] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"monitor", 0x813 , 0x4 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 1 - 0 + {"mwait", 0x813 , 0 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 1 - 1 + {"clac", 0x81D , 0 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 1 - 2 + {"stac", 0x81D , 0 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 1 - 3 + {0, 0 , 0 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }}; // illegal + +// EVEX 0F 38 1B, indexed by W bit +SOpcodeDef OpcodeMap38[] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"vbroadcastf32x8",0x20,0xC69200,0x12, 0x164B, 0x254B, 0 , 0 , 0x20 , 0x1011, 0 , 0x100 }, // EVEX W0 0F 38 1B + {"vbroadcastf64x4",0x20,0xC69200,0x12, 0x164C, 0x254C, 0 , 0 , 0x20 , 0x1011, 0 , 0x100 }}; // EVEX W1 0F 38 1B + +// Secondary opcode map for cbw/cwde/cdqe. Opcode byte = 0x98 +// Indexed by operand size = 16, 32, 64 +SOpcodeDef OpcodeMap39[3] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"cbw", 0 , 0x100 , 0x1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x8 }, // 98 + {"cwde", 0 , 0x100 , 0x1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x8 }, // 98 + {"cdqe", 0x4000, 0x1000 , 0x1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x8 }}; // 98 + +// Secondary opcode map for cwd/cdq/cqo. Opcode byte = 0x99 +// Indexed by operand size = 16, 32, 64 +SOpcodeDef OpcodeMap3A[3] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"cwd", 0 , 0x100 , 0x1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x8 }, // 99 + {"cdq", 0 , 0x100 , 0x1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x8 }, // 99 + {"cqo", 0x4000, 0x1000 , 0x1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x8 }}; // 99 + + +// Secondary opcode map for arpl/movsxd. Opcode byte = 0x63 +// Indexed by mode = 16, 32, 64 +SOpcodeDef OpcodeMap3B[3] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"arpl", 0x8802, 0 , 0x13 , 0x2 , 0x1002, 0 , 0 , 0 , 0 , 0 , 0 }, // 63 + {"arpl", 0x8802, 0 , 0x13 , 0x2 , 0x1002, 0 , 0 , 0 , 0 , 0 , 0 }, // 63 + {"movsxd", 0x4000, 0x1000 , 0x12 , 0x1009, 0x3 , 0 , 0 , 0 , 0 , 0 , 0 }}; // 63 + +// Secondary opcode map for nop/pause. Opcode byte = 0x90 +// Indexed by prefix = none, 66, F2, F3 +SOpcodeDef OpcodeMap3C[4] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"nop", 0 , 0 , 0x2 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x40 }, // 90 + {"nop", 0 , 0 , 0x2 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x40 }, // 66 90 + {"nop", 0 , 0 , 0x2 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x40 }, // F2 90 + {"pause", 0 , 0x400 , 0x2 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }}; // F3 90. (No instset indicated because backwards compatible) + +// Secondary opcode map for jcxz. Opcode byte = 0xE3 +// Indexed by address size +SOpcodeDef OpcodeMap3D[4] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"jcxz", 0 , 0x81 , 0x42 , 0x81 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // E3 + {"jecxz", 0 , 0x81 , 0x42 , 0x81 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, + {"jrcxz", 0x4000, 0x81 , 0x42 , 0x81 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }}; + +// Secondary opcode map for pushf/d/q. Opcode byte = 0x9C +// Indexed by operand size +SOpcodeDef OpcodeMap3E[3] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"pushf", 0 , 0x102 , 0x2 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 9C pushf + {"pushf", 0 , 0x2102 , 0x2 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x1 }, // 9C pushf/d/q + {"pushf", 0 , 0x2102 , 0x2 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x1 }}; // 9C pushf/d/q + +// Secondary opcode map for poof/d/q. Opcode byte = 0x9D +// Indexed by operand size +SOpcodeDef OpcodeMap3F[3] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"popf", 0 , 0x102 , 0x2 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 9D popf + {"popf", 0 , 0x2102 , 0x2 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x1 }, // 9D popf/d/q + {"popf", 0 , 0x2102 , 0x2 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x1 }}; // 9D popf/d/q + +// Tertiary opcode map for movups etc. Opcode byte = 0F 10 +// Indexed by prefixes (none, 66, F2, F3) +SOpcodeDef OpcodeMap40[4] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"movups", 0x11 ,0x850000, 0x12 , 0x124B, 0x251 , 0 , 0 , 0x30 , 0 , 0 , 0x202 }, // 0F 10 + {"movupd", 0x12 ,0x852200, 0x12 , 0x124C, 0x251 , 0 , 0 , 0x30 , 0 , 0 , 0x202 }, // 66 0F 10 + {"movsd", 0x71 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 3 , 0 }, // F2 0F 10 Link for memory/register + {"movss", 0x72 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 3 , 0 }}; // F3 0F 10 Link for memory/register + +// Tertiary opcode map for movups etc. Opcode byte = 0F 11 +// Indexed by prefixes (none, 66, F2, F3) +SOpcodeDef OpcodeMap41[4] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"movups", 0x11 ,0x850000, 0x13 , 0x251 , 0x124B, 0 , 0 , 0x30 , 0 , 0 , 0x202 }, // 0F 11 + {"movupd", 0x12 ,0x852200, 0x13 , 0x251 , 0x124C, 0 , 0 , 0x30 , 0 , 0 , 0x202 }, // 66 0F 11 + {"movsd", 0x73 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 3 , 0 }, // F2 0F 11 Link for memory/register + {"movss", 0x74 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 3 , 0 }}; // F3 0F 11 Link for memory/register + +// Tertiary opcode map for movlps etc. Opcode byte = 0F 12 +// Indexed by prefixes (none, 66, F2, F3) +SOpcodeDef OpcodeMap42[4] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {0, 0x43 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x3 , 0 }, // Link to quarternary map + {"movlpd", 0x12 ,0x892200, 0x19 , 0x144C, 0x144C, 0x204C, 0 , 0 , 0 , 0 , 0x2 }, // 66 0F 12 + {"movddup", 0x70 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0xB , 0 }, // F2 0F 12 + {"movsldup", 0x13 ,0x852400, 0x12 , 0x124B, 0x24B , 0 , 0 , 0x30 , 0 , 0 , 0x2 }}; // F3 0F 12 + +// Quarternary opcode map for movlps and movhlps. Opcode byte = 0F 12 +// Indexed by mod bits +SOpcodeDef OpcodeMap43[2] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"movlps", 0x11 ,0x892000, 0x19 , 0x144B, 0x144B, 0x234B, 0 , 0x1000, 0 , 0 , 0x2 }, // 0F 12 (mem) + {"movhlps", 0x11 ,0x892000, 0x19 , 0x144B, 0x144B, 0x144B, 0 , 0x00 , 0 , 0 , 0x2 }}; // 0F 12 (reg) + +// Tertiary opcode map for movlps etc. Opcode byte = 0F 16 +// Indexed by prefixes (none, 66, F2, F3) +SOpcodeDef OpcodeMap44[4] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {0, 0x45 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x3 , 0 }, // Link to quarternary map + {"movhpd", 0x12 ,0x892200, 0x19 , 0x144C, 0x144C, 0x204C, 0 , 0x00 , 0 , 0 , 0x2 }, // 66 0F 16 + {0, 0x13 , 0x800 , 0x4012, 0x124C, 0x4C , 0 , 0 , 0 , 0 , 0 , 0 }, // F2 0F 16 + {"movshdup", 0x13 ,0x852400, 0x12 , 0x124B, 0x24B , 0 , 0 , 0x30 , 0 , 0 , 0x2 }}; // F3 0F 16 + +// Quarternary opcode map for movhps and movlhps. Opcode byte = 0F 16 +// Indexed by mod bits +SOpcodeDef OpcodeMap45[2] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"movhps", 0x11 ,0x890000, 0x19 , 0x144B, 0x144B, 0x234B, 0 , 0x1000, 0 , 0 , 0x2 }, // 0F 12 (mem) + {"movlhps", 0x11 ,0x890000, 0x19 , 0x144B, 0x144B, 0x144B, 0 , 0x0 , 0 , 0 , 0x2 }}; // 0F 12 (reg) + +// Tertiary opcode map for cvtpi2ps etc. Opcode byte = 0F 2A +// Indexed by prefixes (none, 66, F2, F3) +SOpcodeDef OpcodeMap46[4] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"cvtpi2ps", 0x11 , 0 , 0x12 , 0x124B, 0x303 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 2A + {"cvtpi2pd", 0x12 , 0x200 , 0x12 , 0x124C, 0x303 , 0 , 0 , 0 , 0 , 0 , 0 }, // 66 0F 2A + {"cvtsi2sd", 0x12 ,0x891800, 0x19 , 0x104C, 0x104C, 0x9 , 0 , 0x6 , 0 , 0 , 0x2 }, // F2 0F 2A + {"cvtsi2ss", 0x12 ,0x891400, 0x19 , 0x104B, 0x104B, 0x9 , 0 , 0x6 , 0 , 0 , 0x2 }}; // F3 0F 2A + +// Tertiary opcode map for cvttps2pi etc. Opcode byte = 0F 2C +// Indexed by prefixes (none, 66, F2, F3) +SOpcodeDef OpcodeMap47[4] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"cvttps2pi", 0x11 , 0 , 0x12 , 0x1303, 0x24B , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 2C + {"cvttpd2pi", 0x12 , 0x200 , 0x12 , 0x1303, 0x24C , 0 , 0 , 0 , 0 , 0 , 0 }, // 66 0F 2C + {"cvttsd2si", 0x12 ,0x811800, 0x12 , 0x1009, 0x4C , 0 , 0 , 0x2 , 0 , 0 , 0x2 }, // F2 0F 2C + {"cvttss2si", 0x12 ,0x811400, 0x12 , 0x1009, 0x4B , 0 , 0 , 0x2 , 0 , 0 , 0x2 }}; // F3 0F 2C + +// Tertiary opcode map for cvtps2pi etc. Opcode byte = 0F 2D +// Indexed by prefixes (none, 66, F2, F3) +SOpcodeDef OpcodeMap48[4] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"cvtps2pi", 0x11 ,0x000000, 0x12 , 0x1303, 0x24B , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 2D + {"cvtpd2pi", 0x12 ,0x000200, 0x12 , 0x1303, 0x24C , 0 , 0 , 0 , 0 , 0 , 0 }, // 66 0F 2D + {"cvtsd2si", 0x12 ,0x811800, 0x12 , 0x1009, 0x4C , 0 , 0 , 0x6 , 0 , 0 , 0x2 }, // F2 0F 2D + {"cvtss2si", 0x12 ,0x811400, 0x12 , 0x1009, 0x4B , 0 , 0 , 0x6 , 0 , 0 , 0x2 }}; // F3 0F 2D + +// Tertiary opcode map for cvtps2pd etc. Opcode byte = 0F 5A +// Indexed by prefixes (none, 66, F2, F3) +SOpcodeDef OpcodeMap49[4] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"cvtps2pd", 0x12 ,0xC50000, 0x12 , 0x124C, 0xF4B , 0 , 0 , 0x33 , 0x1215, 0 , 0x2 }, // 0F 5A + {"cvtpd2ps", 0x12 ,0xC52200, 0x12 , 0x1F4B, 0x24C , 0 , 0 , 0x37, 0x1305, 0 , 0x2 }, // 66 0F 5A + {"cvtsd2ss", 0x12 ,0x892800, 0x19 , 0x104B, 0x4C , 0x4C , 0 , 0x36 , 0 , 0 , 0x2 }, // F2 0F 5A + {"cvtss2sd", 0x12 ,0x892400, 0x19 , 0x104C, 0x104C, 0x4B , 0 , 0x32 , 0 , 0 , 0x2 }}; // F3 0F 5A + +// Tertiary opcode map for cvtdq2ps etc. Opcode byte = 0F 5B +// Indexed by prefixes (none, 66, F2, F3) +SOpcodeDef OpcodeMap4A[4] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"cvtdq2ps", 0x12 ,0x850000, 0x12 , 0x124B, 0x203 , 0 , 0 , 0x37 , 0 , 0 , 0x2 }, // 0F 5B + {"cvtps2dq", 0x12 ,0x850200, 0x12 , 0x1203, 0x24B , 0 , 0 , 0x37 , 0 , 0 , 0x2 }, // 66 0F 5B + {0, 0x12 ,0x800 , 0x4012, 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // F2 0F 5B. Illegal + {"cvttps2dq", 0x12 ,0x852400, 0x12 , 0x1203, 0x24B , 0 , 0 , 0x37 , 0 , 0 , 0x2 }}; // F3 0F 5B + +// Tertiary opcode map for ucomiss/sd etc. Opcode byte = 0F 2E +// Indexed by prefixes (none, 66, F2, F3) +SOpcodeDef OpcodeMap4B[3] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"ucomiss", 0x11 ,0x810200, 0x12 , 0x124B, 0x4B , 0 , 0 , 0x2 , 0 , 0 , 0x6 }, // 0F 2E. ucomiss + {"ucomisd", 0x11 ,0x812200, 0x12 , 0x124C, 0x4C , 0 , 0 , 0x2 , 0 , 0 , 0x6 }, // 66 0F 2E. ucomisd + {0, 0 , 0 , 0x12 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }}; // Illegal + +// Tertiary opcode map for comiss/sd etc. Opcode byte = 0F 2F +// Indexed by prefixes (none, 66, F2, F3) +SOpcodeDef OpcodeMap4C[3] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"comiss", 0x11 ,0x812200, 0x12 , 0x124B, 0x4B , 0 , 0 , 0x2 , 0 , 0 , 0x6 }, // 0F 2F. comiss + {"comisd", 0x11 ,0x812200, 0x12 , 0x124C, 0x4C , 0 , 0 , 0x2 , 0 , 0 , 0x6 }, // 66 0F 2F. comisd + {0, 0 , 0 , 0x12 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }}; // Illegal + +// Tertiary opcode map for movq/movdqa/movdqu. Opcode byte = 0F 6F +// Indexed by prefixes (none, 66, F2, F3) +SOpcodeDef OpcodeMap4D[4] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"movq", 0x7 , 0 , 0x12 , 0x1351, 0x351 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 6F + {"movdqa", 0xB8 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0xE , 0 }, // 66 0F 6F. Link to movdqa and vmovdqa32 + {"vmovdqu", 0x19 ,0x864800, 0x12 , 0x1209, 0x209 , 0 , 0 , 0x20 , 0 , 0 , 0x1200}, // F2 0F 6F + {"movdqu", 0xB9 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0xE , 0 }}; // F3 0F 6F. Link to movdqu and vmovdqu32 + +// Tertiary opcode map for movq/movdqa/movdqu. Opcode byte = 0F 7F +// Indexed by prefixes (none, 66, F2, F3) +SOpcodeDef OpcodeMap4E[4] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"movq", 0x7 , 0 , 0x13 , 0x351 , 0x1351, 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7F + {"movdqa", 0xBA , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0xE , 0 }, // 66 0F 7F. Link to movdqa and vmovdqa32 + {"vmovdqu", 0x19 ,0x864800, 0x13 , 0x209 , 0x1209, 0 , 0 , 0x20 , 0 , 0 ,0x1200 }, // E/MVEX F3 0F 7F + {"movdqu", 0xBB , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0xE , 0 }}; // F3 0F 7F. Link to movdqu and vmovdqu32 + +// Tertiary opcode map for pshufw etc. Opcode byte = 0F 70 +// Indexed by prefixes (none, 66, F2, F3) +SOpcodeDef OpcodeMap4F[4] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"pshufw", 0x7 , 0 , 0x52 , 0x1302, 0x302 , 0x31 , 0 , 0 , 0 , 0 , 0 }, // 0F 70 + {"pshufd", 0x12 ,0xC52100, 0x52 , 0x1203, 0x203 , 0x31 , 0 , 0x21 , 0x1000, 0 , 0x2 }, // 66 0F 70 + {"pshuflw", 0x12 ,0x852800, 0x52 , 0x1202, 0x202 , 0x31 , 0 , 0x20 , 0 , 0 , 0x2 }, // F2 0F 70 + {"pshufhw", 0x12 ,0x852400, 0x52 , 0x1202, 0x202 , 0x31 , 0 , 0x20 , 0 , 0 , 0x2 }}; // F3 0F 70 + +// Tertiary opcode map for group 9. Opcode byte = 0F C7 +// Indexed by reg bits = 0 - 7. +SOpcodeDef OpcodeMap50[8] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0. Illegal + {0, 0x51 , 0x1010 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x8 , 0 }, // 1. Link to map: cmpxchg8b + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // Illegal + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // Illegal + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // Illegal + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // Illegal + {0, 0xAC , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x3 , 0 }, // 6. Link to map: vmptrld etc + {0, 0xAF , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x3 , 0 }}; // 7. Link to map: vmptrst, rdseed + +// Quarternary opcode map for cmpxchg8b. Opcode byte = 0F C7 /1 +// Indexed by operand size: 16, 32, 64 +SOpcodeDef OpcodeMap51[3] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"cmpxchg8b", 0x5 , 0x1C50 , 0x11 , 0x2351, 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // + {"cmpxchg8b", 0x5 , 0x1C50 , 0x11 , 0x2351, 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // + {"cmpxchg16b",0x5 , 0x1C50 , 0x11 , 0x2450, 0 , 0 , 0 , 0 , 0 , 0 , 0 }}; + +// Quarternary opcode map for vmptrld etc. Opcode byte = 0F C7 /6 mem +// Indexed by prefix: none/66/F2/F3 +SOpcodeDef OpcodeMap52[4] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"vmptrld", 0x813 , 0 , 0x11 , 0x2351, 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F C7 /6 mem + {"vmclear", 0x813 , 0x200 , 0x11 , 0x2351, 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // + {0, 0x813 , 0x800 , 0x11 , 0x2351, 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // Illegal + {"vmxon", 0x813 , 0x400 , 0x11 , 0x2351, 0 , 0 , 0 , 0 , 0 , 0 , 0 }}; + +// Quarternary opcode map for movdq2q etc. Opcode byte = 0F D6 +// Indexed by prefix: none/66/F2/F3 +SOpcodeDef OpcodeMap53[4] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // Illegal + {"movq", 0x6F , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x3 , 0 }, // 66: Link to movq m64,xmm / movq xmm,xmm + {"movdq2q", 0x12 , 0x800 , 0x12 , 0x1351, 0x1450, 0 , 0 , 0 , 0 , 0 , 0 }, // F2 + {"movq2dq", 0x12 , 0x400 , 0x12 , 0x1450, 0x1351, 0 , 0 , 0 , 0 , 0 , 0 }}; // F3 + +// Quarternary opcode map for cvtpd2dq etc. Opcode byte = 0F E6 +// Indexed by prefix: none/66/F2/F3 +SOpcodeDef OpcodeMap54[4] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // Illegal + {"cvttpd2dq", 0x12 ,0x852200, 0x12 , 0x1F03, 0x24C , 0 , 0 , 0x33 , 0 , 0 , 0x2 }, // 66 + {"cvtpd2dq", 0x12 ,0x852800, 0x12 , 0x1F03, 0x24C , 0 , 0 , 0x37 , 0 , 0 , 0x2 }, // F2 + {"cvtdq2pd", 0x12 ,0xC50400, 0x12 , 0x124C, 0xF03 , 0 , 0 , 0x31 , 0x1214, 0 , 0x2 }}; // F3 + +// Quarternary opcode map for movntq etc. Opcode byte = 0F E7 +// Indexed by prefix: none/66/F2/F3 +SOpcodeDef OpcodeMap55[3] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"movntq", 0x11 , 0 , 0x13 , 0x2351, 0x1351, 0 , 0 , 0 , 0 , 0 , 0 }, // + {"movntdq", 0x12 ,0x850200, 0x13 , 0x2250, 0x1250, 0 , 0 , 0x00 , 0 , 0 , 0x102 }, // + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }}; // Illegal + +// Quarternary opcode map for lddqu. Opcode byte = 0F F0 +// Indexed by prefix: none/66/F2/F3 +SOpcodeDef OpcodeMap56[4] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {0, 0 , 0 , 0x12 , 0x1450, 0x1450, 0 , 0 , 0 , 0 , 0 , 0 }, // Illegal + {0, 0 , 0x200 , 0x12 , 0x1450, 0x1450, 0 , 0 , 0 , 0 , 0 , 0 }, // + {"lddqu", 0x13 , 0x58800, 0x12 , 0x1250, 0x251, 0 , 0 , 0 , 0 , 0 , 0x202 }, // + {0, 0 , 0x400 , 0x12 , 0x1450, 0x1450, 0 , 0 , 0 , 0 , 0 , 0 }}; // Illegal + +// Quarternary opcode map for maskmovq. Opcode byte = 0F F7 +// Indexed by prefix: none/66/F2/F3 +SOpcodeDef OpcodeMap57[3] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"maskmovq", 0x7 , 0x5 , 0x12 , 0x1351, 0x1351, 0 , 0 , 0 , 0 , 0 , 0x20 }, // + {"maskmovdqu",0x12 , 0x18205, 0x12 , 0x1450, 0x1450, 0 , 0 , 0 , 0 , 0 , 0x22 }, // + {0, 0 , 0 , 0x12 , 0x1450, 0x2450, 0 , 0 , 0 , 0 , 0 , 0 }}; // Illegal + +// Tertiary opcode map for movd/movq. Opcode byte = 0F 6E +// Indexed by operand size 16/32/64 +// First two lines are identical because operand size is determined only by REX.W prefix, +// while 66 prefix determines mmx or xmm register +// Note: VEX/EVEX version is in map B1 +SOpcodeDef OpcodeMap58[3] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"movd", 0x7 , 0x11200, 0x12 , 0x1103, 0x3 , 0 , 0 , 0x00 , 0 , 0 , 0x2 }, // 0F 6E + {"movd", 0x7 , 0x11200, 0x12 , 0x1103, 0x3 , 0 , 0 , 0x00 , 0 , 0 , 0x2 }, // 0F 6E + {"movq", 0x4000, 0x11200, 0x12 , 0x1104, 0x4 , 0 , 0 , 0x00 , 0 , 0 , 0x2 }}; // 0F 6E. Name varies: movd or movq, though the operand is 64 bits + +// Tertiary opcode map for movd/movq. Opcode byte = 0F 7E +// Indexed by prefix: none/66/F2/F3 +SOpcodeDef OpcodeMap59[4] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {0, 0x5A , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x8 , 0 }, // 0F 7E. Link to map 5A. Name depends on REX.W prefix + {0, 0x5A , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x8 , 0 }, // 66 0F 7E. Link to map 5A. Name depends on REX.W prefix + {0, 0x7 , 0 , 0x4013, 0x3 , 0x1103, 0 , 0 , 0 , 0 , 0 , 0 }, // F2 0F 7E. Doesn't exist + {0, 0x5B , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x3 , 0 }}; // F3 0F 7E. Link to map 5B. movq xmm,xmm/m64 + +// Quarternary opcode map for movd/movq. Opcode byte = 66 0F 7E +// Indexed by operand size 16/32/64 +// First two lines are identical because operand size is determined only by REX.W prefix, +// while 66 prefix determines mmx or xmm register +SOpcodeDef OpcodeMap5A[3] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"movd", 0x7 , 0x11200, 0x13 , 0x3 , 0x1103, 0 , 0 , 0 , 0 , 0 , 0x2 }, // 0F 7E + {"movd", 0x7 , 0x11200, 0x13 , 0x3 , 0x1103, 0 , 0 , 0 , 0 , 0 , 0x2 }, // 0F 7E + {"movq", 0x4000, 0x11200, 0x13 , 0x4 , 0x1104, 0x0 , 0 , 0 , 0 , 0 , 0x2 }}; // 0F 7E. Name varies: movd or movq, though the operand is 64 bits + +// Quarternary opcode map for movq xmm,xmm/m64. Opcode byte = F3 0F 7E +// Indexed by memory vs. register operand +// Link to here from both map 59 (without VEX) and map E2 (with VEX) +SOpcodeDef OpcodeMap5B[2] = { + {"movq", 0x12 ,0x812400, 0x12 , 0x1404, 0x4 , 0 , 0 , 0 , 0 , 0 , 0x2 }, // F3 0F 7E. movq xmm,m64 + {"movq", 0x12 ,0x812400, 0x12 , 0x1404, 0x404 , 0 , 0 , 0 , 0 , 0 , 0x2 }}; // F3 0F 7E. movq xmm,xmm + +// Tertiary opcode map for haddps/pd etc. Opcode byte = 0F 7C +// Indexed by prefixes (none, 66, F2, F3) +SOpcodeDef OpcodeMap5C[4] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {0, 0 , 0 , 0x4012, 0x124F, 0x24F , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7C + {"haddpd", 0x13 , 0xD0A00, 0x19 , 0x124C, 0x124C, 0x24C , 0 , 0 , 0 , 0 , 0x2 }, // 66 0F 7C + {"haddps", 0x13 , 0xD0A00, 0x19 , 0x124B, 0x124B, 0x24B , 0 , 0 , 0 , 0 , 0x2 }, // F2 0F 7C + {0, 0 , 0 , 0x4012, 0x124F, 0x24F , 0 , 0 , 0 , 0 , 0 , 0 }}; // F3 0F 7C + +// Tertiary opcode map for hsubps/pd etc. Opcode byte = 0F 7D +// Indexed by prefixes (none, 66, F2, F3) +SOpcodeDef OpcodeMap5D[4] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {0, 0 , 0 , 0x4012, 0x124F, 0x24F , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7D + {"hsubpd", 0x13 , 0xD0A00, 0x19 , 0x124C, 0x124C, 0x24C , 0 , 0 , 0 , 0 , 0x2 }, // 66 0F 7D + {"hsubps", 0x13 , 0xD0A00, 0x19 , 0x124B, 0x124B, 0x24B , 0 , 0 , 0 , 0 , 0x2 }, // F2 0F 7D + {0, 0 , 0 , 0x4012, 0x124F, 0x24F , 0 , 0 , 0 , 0 , 0 , 0 }}; // F3 0F 7D + +// Tertiary opcode map for lar. Opcode byte = 0F 02 +// Indexed by memory vs. register operand +SOpcodeDef OpcodeMap5E[2] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"lar", 0x802 , 0x1100 , 0x12 , 0x1009, 0x2002, 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 02 memory + {"lar", 0x802 , 0x1100 , 0x12 , 0x1009, 0x1009, 0 , 0 , 0 , 0 , 0 , 0 }}; // 0F 02 register + +// Tertiary opcode map for lsl. Opcode byte = 0F 03 +// Indexed by memory vs. register operand +SOpcodeDef OpcodeMap5F[2] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"lsl", 0x802 , 0x1100 , 0x12 , 0x1009, 0x2002, 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 03 memory + {"lsl", 0x802 , 0x1100 , 0x12 , 0x1009, 0x1009, 0 , 0 , 0 , 0 , 0 , 0 }}; // 0F 03 register + +// Tertiary opcode map for popcnt. Opcode byte = 0F B8 +// Indexed by prefixes (none, 66, F2, F3) +SOpcodeDef OpcodeMap60[4] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"jmpe;Itanium only",0,0 , 0x11 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x8 }, // 0F B8 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 66 0F B8 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // F2 0F B8 + {"popcnt", 0x16 ,0x11500 , 0x12 , 0x1009, 0x9 , 0 , 0 , 0 , 0 , 0 , 0 }}; // F3 0F B8 + +// Quarternary opcode map for pextrb. Opcode byte = 0F 3A 14 +// Indexed by memory vs. register operand +SOpcodeDef OpcodeMap61[2] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"pextrb", 0x15 ,0x81A200, 0x53 , 0x2001, 0x1401, 0x31 , 0 , 0x1000, 0 , 0 , 0x2 }, // 0F 3A 14 memory + {"pextrb", 0x15 ,0x81A200, 0x53 , 0x1009, 0x1401, 0x31 , 0 , 0 , 0 , 0 , 0x2 }}; // 0F 3A 14 register + +// Quarternary opcode map for pextrw. Opcode byte = 0F 3A 15 +// Indexed by memory vs. register operand +SOpcodeDef OpcodeMap62[2] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"pextrw", 0x15 ,0x81A200, 0x53 , 0x2002, 0x1402, 0x31 , 0 , 0x1000, 0 , 0 , 0x2 }, // 0F 3A 15 memory + {"pextrw", 0x15 ,0x81A200, 0x53 , 0x1002, 0x1402, 0x31 , 0 , 0 , 0 , 0 , 0x2 }}; // 0F 3A 15 register + +// Quarternary opcode map for pextrd/q. Opcode byte = 0F 3A 16 +// Indexed by operand size (16, 32, 64) +SOpcodeDef OpcodeMap63[3] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"pextr", 0x15 ,0x81B200, 0x53 , 0x3 , 0x1403, 0x31 , 0 , 0x1000, 0 , 0 , 3 }, // 0F 3A 16 pextrd + {"pextr", 0x15 ,0x81B200, 0x53 , 0x3 , 0x1403, 0x31 , 0 , 0x1000, 0 , 0 , 3 }, // 0F 3A 16 pextrd + {"pextr", 0x15 ,0x81B200, 0x53 , 0x4 , 0x1404, 0x31 , 0 , 0x1000, 0 , 0 , 3 }}; // 0F 3A 16 pextrq + +// Opcode map for AMD instructions with XOP prefix and mmmmm = 01000 +// Indexed by first opcode byte after XOP prefix. Has one byte immediate data +SOpcodeDef OpcodeMap64[] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 00 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 01 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 02 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 03 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 04 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 05 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 06 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 07 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 08 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 09 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 0A + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 0B + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 0C + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 0D + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 0E + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 0F + + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 10 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 11 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 12 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 13 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 14 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 15 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 16 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 17 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 18 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 19 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 1A + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 1B + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 1C + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 1D + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 1E + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 1F + + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 20 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 21 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 22 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 23 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 24 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 25 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 26 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 27 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 28 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 29 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 2A + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 2B + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 2C + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 2D + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 2E + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 2F + + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 30 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 31 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 32 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 33 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 34 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 35 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 36 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 37 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 38 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 39 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 3A + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 3B + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 3C + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 3D + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 3E + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 3F + + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 40 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 41 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 42 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 43 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 44 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 45 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 46 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 47 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 48 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 49 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 4A + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 4B + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 4C + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 4D + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 4E + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 4F + + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 50 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 51 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 52 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 53 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 54 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 55 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 56 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 57 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 58 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 59 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 5A + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 5B + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 5C + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 5D + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 5E + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 5F + + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 60 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 61 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 62 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 63 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 64 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 65 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 66 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 67 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 68 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 69 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 6A + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 6B + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 6C + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 6D + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 6E + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 6F + + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 70 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 71 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 72 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 73 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 74 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 75 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 76 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 77 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 78 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 79 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 7A + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 7B + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 7C + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 7D + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 7E + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 7F + + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 80 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 81 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 82 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 83 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 84 + {"vpmacssww", 0x1005, 0xB0000, 0x5C, 0x1202, 0x1202, 0x202 , 0x1202, 0 , 0 , 0 , 0 }, // XOP(8) 85 + {"vpmacsswd", 0x1005, 0xB0000, 0x5C, 0x1203, 0x1202, 0x202 , 0x1203, 0 , 0 , 0 , 0 }, // XOP(8) 86 + {"vpmacssdql",0x1005, 0xB0000, 0x5C, 0x1204, 0x1203, 0x203 , 0x1204, 0 , 0 , 0 , 0 }, // XOP(8) 87 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 88 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 89 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 8A + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 8B + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 8C + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 8D + {"vpmacssdd", 0x1005, 0xB0000, 0x5C, 0x1203, 0x1203, 0x203 , 0x1203, 0 , 0 , 0 , 0 }, // XOP(8) 8E + {"vpmacssdqh",0x1005, 0xB0000, 0x5C, 0x1204, 0x1203, 0x203 , 0x1204, 0 , 0 , 0 , 0 }, // XOP(8) 8F + + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 90 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 91 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 92 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 93 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 94 + {"vpmacsww", 0x1005, 0xB0000, 0x5C, 0x1202, 0x1202, 0x202 , 0x1202, 0 , 0 , 0 , 0 }, // XOP(8) 95 + {"vpmacswd", 0x1005, 0xB0000, 0x5C, 0x1203, 0x1202, 0x202 , 0x1203, 0 , 0 , 0 , 0 }, // XOP(8) 96 + {"vpmacsdql", 0x1005, 0xB0000, 0x5C, 0x1204, 0x1203, 0x203 , 0x1204, 0 , 0 , 0 , 0 }, // XOP(8) 97 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 98 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 99 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 9A + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 9B + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 9C + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) 9D + {"vpmacsdd", 0x1005, 0xB0000, 0x5C, 0x1203, 0x1203, 0x203 , 0x1203, 0 , 0 , 0 , 0 }, // XOP(8) 9E + {"vpmacsdqh", 0x1005, 0xB0000, 0x5C, 0x1204, 0x1203, 0x203 , 0x1204, 0 , 0 , 0 , 0 }, // XOP(8) 9F + +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"cvtph2ps", 0x1D , 0x70000, 0x52 , 0x124B, 0x402 , 0x31 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) A0 + {"cvtps2ph", 0x1D , 0x70000, 0x53 , 0x402, 0x124B, 0x31 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) A1 + {"vpcmov", 0x1005, 0xF7000, 0x5C, 0x1201, 0x1201, 0x201 , 0x201 , 0 , 0 , 0 , 0 }, // XOP(8) A2 + {"vpperm", 0x1005, 0xB7000, 0x5C, 0x1201, 0x1201, 0x201 , 0x201 , 0 , 0 , 0 , 0 }, // XOP(8) A3 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) A4 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) A5 + {"vpmadcsswd",0x1005, 0xB0000, 0x5C, 0x1203, 0x1202, 0x202 , 0x1203, 0 , 0 , 0 , 0 }, // XOP(8) A6 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) A7 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) A8 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) A9 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) AA + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) AB + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) AC + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) AD + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) AE + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) AF + + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) B0 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) B1 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) B2 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) B3 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) B4 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) B5 + {"vpmadcswd", 0x1005, 0xB0000, 0x5C, 0x1203, 0x1202, 0x202 , 0x1203, 0 , 0 , 0 , 0 }, // XOP(8) B6 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) B7 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) B8 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) B9 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) BA + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) BB + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) BC + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) BD + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) BE + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) BF + + {"vprotb", 0x1005, 0x30000, 0x52 , 0x1401, 0x401 , 0x21 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) C0 + {"vprotw", 0x1005, 0x30000, 0x52 , 0x1402, 0x402 , 0x21 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) C1 + {"vprotd", 0x1005, 0x30000, 0x52 , 0x1403, 0x403 , 0x21 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) C2 + {"vprotq", 0x1005, 0x30000, 0x52 , 0x1404, 0x404 , 0x21 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) C3 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) C4 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) C5 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) C6 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) C7 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) C8 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) C9 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) CA + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) CB + {"vpcomb", 0x1005, 0xB0000, 0x59 , 0x1401, 0x1401, 0x401 , 0x31 , 0 , 0 , 0 , 0 }, // XOP(8) CC + {"vpcomw", 0x1005, 0xB0000, 0x59 , 0x1402, 0x1402, 0x402 , 0x31 , 0 , 0 , 0 , 0 }, // XOP(8) CD + {"vpcomd", 0x1005, 0xB0000, 0x59 , 0x1403, 0x1403, 0x403 , 0x31 , 0 , 0 , 0 , 0 }, // XOP(8) CE + {"vpcomq", 0x1005, 0xB0000, 0x59 , 0x1404, 0x1404, 0x404 , 0x31 , 0 , 0 , 0 , 0 }, // XOP(8) CF + + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) D0 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) D1 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) D2 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) D3 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) D4 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) D5 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) D6 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) D7 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) D8 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) D9 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) DA + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) DB + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) DC + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) DD + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) DE + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) DF + + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) E0 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) E1 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) E2 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) E3 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) E4 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) E5 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) E6 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) E7 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) E8 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) E9 + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) EA + {0, 0 , 0 , 0x2059, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(8) EB + {"vpcomub", 0x1005, 0xB0000, 0x59 , 0x1401, 0x1401, 0x401 , 0x31 , 0 , 0 , 0 , 0 }, // XOP(8) EC + {"vpcomuw", 0x1005, 0xB0000, 0x59 , 0x1402, 0x1402, 0x402 , 0x31 , 0 , 0 , 0 , 0 }, // XOP(8) ED + {"vpcomud", 0x1005, 0xB0000, 0x59 , 0x1403, 0x1403, 0x403 , 0x31 , 0 , 0 , 0 , 0 }, // XOP(8) EE + {"vpcomuq", 0x1005, 0xB0000, 0x59 , 0x1404, 0x1404, 0x404 , 0x31 , 0 , 0 , 0 , 0 }}; // XOP(8) EF + + +// Opcode map for AMD instructions with XOP prefix and mmmmm = 01001 +// Indexed by first opcode byte after XOP prefix. Has no immediate data +SOpcodeDef OpcodeMap65[] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 00 + {0, 0xD4 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x2 , 0 }, // XOP(9) 01. Link blcfill etc. + {0, 0xD5 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x2 , 0 }, // XOP(9) 02. Link blcmsk etc. + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 03 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 04 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 05 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 06 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 07 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 08 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 09 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 0A + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 0B + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 0C + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 0D + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 0E + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 0F + + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 10 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 11 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 12 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 13 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 14 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 15 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 16 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 17 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 18 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 19 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 1A + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 1B + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 1C + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 1D + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 1E + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 1F + + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 20 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 21 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 22 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 23 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 24 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 25 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 26 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 27 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 28 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 29 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 2A + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 2B + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 2C + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 2D + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 2E + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 2F + + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 30 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 31 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 32 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 33 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 34 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 35 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 36 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 37 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 38 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 39 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 3A + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 3B + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 3C + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 3D + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 3E + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 3F + + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 40 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 41 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 42 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 43 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 44 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 45 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 46 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 47 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 48 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 49 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 4A + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 4B + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 4C + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 4D + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 4E + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 4F + + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 50 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 51 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 52 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 53 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 54 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 55 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 56 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 57 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 58 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 59 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 5A + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 5B + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 5C + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 5D + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 5E + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 5F + + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 60 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 61 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 62 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 63 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 64 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 65 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 66 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 67 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 68 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 69 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 6A + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 6B + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 6C + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 6D + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 6E + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 6F + + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 70 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 71 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 72 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 73 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 74 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 75 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 76 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 77 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 78 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 79 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 7A + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 7B + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 7C + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 7D + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 7E + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 7F + +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"frczps", 0x11005,0x70000, 0x12 , 0x124B, 0x24B , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 80 + {"frczpd", 0x11005,0x70000, 0x12 , 0x124C, 0x24C , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 81 + {"frczss", 0x11005,0x70000, 0x12 , 0x124B, 0x4B , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 82 + {"frczsd", 0x11005,0x70000, 0x12 , 0x124C, 0x4C , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 83 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 84 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 85 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 86 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 87 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 88 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 89 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 8A + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 8B + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 8C + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 8D + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 8E + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 8F + +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"vprotb", 0x1005, 0xB7000, 0x19 , 0x1401, 0x401 , 0x401 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 90 + {"vprotw", 0x1005, 0xB7000, 0x19 , 0x1402, 0x402 , 0x402 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 91 + {"vprotd", 0x1005, 0xB7000, 0x19 , 0x1403, 0x403 , 0x403 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 92 + {"vprotq", 0x1005, 0xB7000, 0x19 , 0x1404, 0x404 , 0x404 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 93 + {"vpshlb", 0x1005, 0xB7000, 0x19 , 0x1401, 0x401 , 0x401 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 94 + {"vpshlw", 0x1005, 0xB7000, 0x19 , 0x1402, 0x402 , 0x402 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 95 + {"vpshld", 0x1005, 0xB7000, 0x19 , 0x1403, 0x403 , 0x403 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 96 + {"vpshlq", 0x1005, 0xB7000, 0x19 , 0x1404, 0x404 , 0x404 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 97 + {"vpshab", 0x1005, 0xB7000, 0x19 , 0x1401, 0x401 , 0x401 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 98 + {"vpshaw", 0x1005, 0xB7000, 0x19 , 0x1402, 0x402 , 0x402 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 99 + {"vpshad", 0x1005, 0xB7000, 0x19 , 0x1403, 0x403 , 0x403 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 9A + {"vpshaq", 0x1005, 0xB7000, 0x19 , 0x1404, 0x404 , 0x404 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 9B + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 9C + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 9D + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 9E + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 9F + + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) A0 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) A1 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) A2 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) A3 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) A4 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) A5 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) A6 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) A7 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) A8 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) A9 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) AA + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) AB + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) AC + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) AD + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) AE + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) AF + + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) B0 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) B1 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) B2 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) B3 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) B4 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) B5 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) B6 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) B7 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) B8 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) B9 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) BA + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) BB + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) BC + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) BD + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) BE + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) BF + +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) C0 + {"vphaddbw", 0x1005, 0x30000, 0x12 , 0x1402, 0x401 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) C1 + {"vphaddbd", 0x1005, 0x30000, 0x12 , 0x1403, 0x401 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) C2 + {"vphaddbq", 0x1005, 0x30000, 0x12 , 0x1404, 0x401 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) C3 + {0, 0 , 0 , 0x2019, 0x0, 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) C4 + {0, 0 , 0 , 0x2019, 0x0, 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) C5 + {"vphaddwd", 0x1005, 0x30000, 0x12 , 0x1403, 0x402 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) C6 + {"vphaddwq", 0x1005, 0x30000, 0x12 , 0x1404, 0x402 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) C7 + {0, 0 , 0 , 0x2019, 0x0, 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) C8 + {0, 0 , 0 , 0x2019, 0x0, 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) C9 + {0, 0 , 0 , 0x2019, 0x0, 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) CA + {"vphadddq", 0x1005, 0x30000, 0x12 , 0x1404, 0x403 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) CB + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) CC + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) CD + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) CE + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) CF + + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) D0 + {"vphaddubw", 0x1005, 0x30000, 0x12 , 0x1402, 0x401 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) D1 + {"vphaddubd", 0x1005, 0x30000, 0x12 , 0x1403, 0x401 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) D2 + {"vphaddubq", 0x1005, 0x30000, 0x12 , 0x1404, 0x401 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) D3 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) D3 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) D4 + {"vphadduwd", 0x1005, 0x30000, 0x12 , 0x1403, 0x402 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) D6 + {"vphadduwq", 0x1005, 0x30000, 0x12 , 0x1404, 0x402 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) D7 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) D7 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) D8 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) D9 + {"vphaddudq", 0x1005, 0x30000, 0x12 , 0x1404, 0x403 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) DB + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) DC + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) DD + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) DE + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) DF + + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) E0 + {"vphsubbw", 0x1005, 0x30000, 0x12 , 0x1402, 0x401 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) E1 + {"vphsubwd", 0x1005, 0x30000, 0x12 , 0x1403, 0x401 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) E2 + {"vphsubdq", 0x1005, 0x30000, 0x12 , 0x1404, 0x401 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) E3 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) E4 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) E5 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) E6 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) E7 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) E8 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) E9 + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) EA + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) EB + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) EC + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) ED + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) EE + {0, 0 , 0 , 0x2019, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }}; // XOP(9) EF + +// Opcode map for AMD instructions with XOP prefix and mmmmm = 01010 +// Indexed by first opcode byte after XOP prefix. Has 4 bytes immediate data +SOpcodeDef OpcodeMap66[] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(0xA) 00 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(0xA) 01 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(0xA) 02 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(0xA) 03 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(0xA) 04 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(0xA) 05 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(0xA) 06 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(0xA) 07 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(0xA) 08 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(0xA) 09 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(0xA) 0A + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(0xA) 0B + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(0xA) 0C + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(0xA) 0D + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(0xA) 0E + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(0xA) 0F + + {"bextr", 0x1007, 0x11000, 0x92 , 0x1009, 0x9 , 0x33 , 0 , 0 , 0 , 0 , 0 }, // XOP(0xA) 10 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }}; // XOP(0xA) 11 + + +// Opcode map for AMD instructions with XOP prefix and mmmmm = 01011 or whatever (vacant) +// Indexed by first opcode byte after XOP prefix. +SOpcodeDef OpcodeMap67[] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }}; // XOP(0xB) 00 + + +// Tertiary opcode map for 3-byte opcode. First two bytes = 0F 24 +// Indexed by third opcode byte +// AMD SSE5 instructions with three or four operands + +//************************* NOTE *********************** +// These proposed codes have never been implemented. +// Specifications have been changed for the sake of compatibility with Intel AVX coding scheme +// ***************************************************** +SOpcodeDef OpcodeMap68[] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"fmaddps", 0x21006,0x0 , 0x15 , 0x124B, 0x24B , 0x24B , 0x24B , 0 , 0 , 0 , 0 }, // 0F 24 00 + {"fmaddpd", 0x21006,0x0 , 0x15 , 0x124C, 0x24C , 0x24C , 0x24C , 0 , 0 , 0 , 0 }, // 0F 24 01 + {"fmaddss", 0x21006,0x0 , 0x15 , 0x104B, 0x4B , 0x4B , 0x4B , 0 , 0 , 0 , 0 }, // 0F 24 02 + {"fmaddsd", 0x21006,0x0 , 0x15 , 0x104C, 0x4C , 0x4C , 0x4C , 0 , 0 , 0 , 0 }, // 0F 24 03 + {"fmaddps", 0x21006,0x0 , 0x15 , 0x124B, 0x24B , 0x24B , 0x24B , 0 , 0 , 0 , 0 }, // 0F 24 04 + {"fmaddpd", 0x21006,0x0 , 0x15 , 0x124C, 0x24C , 0x24C , 0x24C , 0 , 0 , 0 , 0 }, // 0F 24 05 + {"fmaddss", 0x21006,0x0 , 0x15 , 0x104B, 0x4B , 0x4B , 0x4B , 0 , 0 , 0 , 0 }, // 0F 24 06 + {"fmaddsd", 0x21006,0x0 , 0x15 , 0x104C, 0x4C , 0x4C , 0x4C , 0 , 0 , 0 , 0 }, // 0F 24 07 + {"fmsubps", 0x21006,0x0 , 0x15 , 0x124B, 0x24B , 0x24B , 0x24B , 0 , 0 , 0 , 0 }, // 0F 24 08 + {"fmsubpd", 0x21006,0x0 , 0x15 , 0x124C, 0x24C , 0x24C , 0x24C , 0 , 0 , 0 , 0 }, // 0F 24 09 + {"fmsubss", 0x21006,0x0 , 0x15 , 0x104B, 0x4B , 0x4B , 0x4B , 0 , 0 , 0 , 0 }, // 0F 24 0A + {"fmsubsd", 0x21006,0x0 , 0x15 , 0x104C, 0x4C , 0x4C , 0x4C , 0 , 0 , 0 , 0 }, // 0F 24 0B + {"fmsubps", 0x21006,0x0 , 0x15 , 0x124B, 0x24B , 0x24B , 0x24B , 0 , 0 , 0 , 0 }, // 0F 24 0C + {"fmsubpd", 0x21006,0x0 , 0x15 , 0x124C, 0x24C , 0x24C , 0x24C , 0 , 0 , 0 , 0 }, // 0F 24 0D + {"fmsubss", 0x21006,0x0 , 0x15 , 0x104B, 0x4B , 0x4B , 0x4B , 0 , 0 , 0 , 0 }, // 0F 24 0E + {"fmsubsd", 0x21006,0x0 , 0x15 , 0x104C, 0x4C , 0x4C , 0x4C , 0 , 0 , 0 , 0 }, // 0F 24 0F + + {"fnmaddps", 0x21006,0x0 , 0x15 , 0x124B, 0x24B , 0x24B , 0x24B , 0 , 0 , 0 , 0 }, // 0F 24 10 + {"fnmaddpd", 0x21006,0x0 , 0x15 , 0x124C, 0x24C , 0x24C , 0x24C , 0 , 0 , 0 , 0 }, // 0F 24 11 + {"fnmaddss", 0x21006,0x0 , 0x15 , 0x104B, 0x4B , 0x4B , 0x4B , 0 , 0 , 0 , 0 }, // 0F 24 12 + {"fnmaddsd", 0x21006,0x0 , 0x15 , 0x104C, 0x4C , 0x4C , 0x4C , 0 , 0 , 0 , 0 }, // 0F 24 13 + {"fnmaddps", 0x21006,0x0 , 0x15 , 0x124B, 0x24B , 0x24B , 0x24B , 0 , 0 , 0 , 0 }, // 0F 24 14 + {"fnmaddpd", 0x21006,0x0 , 0x15 , 0x124C, 0x24C , 0x24C , 0x24C , 0 , 0 , 0 , 0 }, // 0F 24 15 + {"fnmaddss", 0x21006,0x0 , 0x15 , 0x104B, 0x4B , 0x4B , 0x4B , 0 , 0 , 0 , 0 }, // 0F 24 16 + {"fnmaddsd", 0x21006,0x0 , 0x15 , 0x104C, 0x4C , 0x4C , 0x4C , 0 , 0 , 0 , 0 }, // 0F 24 17 + {"fnmsubps", 0x21006,0x0 , 0x15 , 0x124B, 0x24B , 0x24B , 0x24B , 0 , 0 , 0 , 0 }, // 0F 24 18 + {"fnmsubpd", 0x21006,0x0 , 0x15 , 0x124C, 0x24C , 0x24C , 0x24C , 0 , 0 , 0 , 0 }, // 0F 24 19 + {"fnmsubss", 0x21006,0x0 , 0x15 , 0x104B, 0x4B , 0x4B , 0x4B , 0 , 0 , 0 , 0 }, // 0F 24 1A + {"fnmsubsd", 0x21006,0x0 , 0x15 , 0x104C, 0x4C , 0x4C , 0x4C , 0 , 0 , 0 , 0 }, // 0F 24 1B + {"fnmsubps", 0x21006,0x0 , 0x15 , 0x124B, 0x24B , 0x24B , 0x24B , 0 , 0 , 0 , 0 }, // 0F 24 1C + {"fnmsubpd", 0x21006,0x0 , 0x15 , 0x124C, 0x24C , 0x24C , 0x24C , 0 , 0 , 0 , 0 }, // 0F 24 1D + {"fnmsubss", 0x21006,0x0 , 0x15 , 0x104B, 0x4B , 0x4B , 0x4B , 0 , 0 , 0 , 0 }, // 0F 24 1E + {"fnmsubsd", 0x21006,0x0 , 0x15 , 0x104C, 0x4C , 0x4C , 0x4C , 0 , 0 , 0 , 0 }, // 0F 24 1F + + {"permps", 0x21005,0x0 , 0x15 , 0x124B, 0x24B , 0x24B , 0x24B , 0 , 0 , 0 , 0 }, // 0F 24 20 + {"permpd", 0x21005,0x0 , 0x15 , 0x124C, 0x24C , 0x24C , 0x24C , 0 , 0 , 0 , 0 }, // 0F 24 21 + {"pcmov", 0x21005,0x0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 22 + {"pperm", 0x21005,0x0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 23 + {"permps", 0x21005,0x0 , 0x15 , 0x124B, 0x24B , 0x24B , 0x24B , 0 , 0 , 0 , 0 }, // 0F 24 24 + {"permpd", 0x21005,0x0 , 0x15 , 0x124C, 0x24C , 0x24C , 0x24C , 0 , 0 , 0 , 0 }, // 0F 24 25 + {"pcmov", 0x21005,0x0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 26 + {"pperm", 0x21005,0x0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 27 + + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 28 + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 29 + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 2A + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 2B + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 2C + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 2D + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 2E + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 2F + + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 30 + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 31 + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 32 + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 33 + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 34 + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 35 + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 36 + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 37 + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 38 + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 39 + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 3A + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 3B + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 3C + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 3D + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 3E + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 3F + + {"protb", 0x21005,0x0 , 0x14 , 0x1401, 0x401 , 0x401 , 0 , 0 , 0 , 0 , 0 }, // 0F 24 40 + {"protw", 0x21005,0x0 , 0x14 , 0x1402, 0x402 , 0x402 , 0 , 0 , 0 , 0 , 0 }, // 0F 24 41 + {"protd", 0x21005,0x0 , 0x14 , 0x1403, 0x403 , 0x403 , 0 , 0 , 0 , 0 , 0 }, // 0F 24 42 + {"protq", 0x21005,0x0 , 0x14 , 0x1404, 0x404 , 0x404 , 0 , 0 , 0 , 0 , 0 }, // 0F 24 43 + {"pshlb", 0x21005,0x0 , 0x14 , 0x1401, 0x401 , 0x401 , 0 , 0 , 0 , 0 , 0 }, // 0F 24 44 + {"pshlw", 0x21005,0x0 , 0x14 , 0x1402, 0x402 , 0x402 , 0 , 0 , 0 , 0 , 0 }, // 0F 24 45 + {"pshld", 0x21005,0x0 , 0x14 , 0x1403, 0x403 , 0x403 , 0 , 0 , 0 , 0 , 0 }, // 0F 24 46 + {"pshlq", 0x21005,0x0 , 0x14 , 0x1404, 0x404 , 0x404 , 0 , 0 , 0 , 0 , 0 }, // 0F 24 47 + {"pshab", 0x21005,0x0 , 0x14 , 0x1401, 0x401 , 0x401 , 0 , 0 , 0 , 0 , 0 }, // 0F 24 48 + {"pshaw", 0x21005,0x0 , 0x14 , 0x1402, 0x402 , 0x402 , 0 , 0 , 0 , 0 , 0 }, // 0F 24 49 + {"pshad", 0x21005,0x0 , 0x14 , 0x1403, 0x403 , 0x403 , 0 , 0 , 0 , 0 , 0 }, // 0F 24 4A + {"pshaq", 0x21005,0x0 , 0x14 , 0x1404, 0x404 , 0x404 , 0 , 0 , 0 , 0 , 0 }, // 0F 24 4B + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 4C + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 4D + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 4E + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 4F + + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 50 + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 51 + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 52 + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 53 + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 54 + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 55 + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 56 + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 57 + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 58 + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 59 + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 5A + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 5B + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 5C + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 5D + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 5E + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 5F + + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 60 + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 61 + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 62 + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 63 + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 64 + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 65 + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 66 + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 67 + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 68 + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 69 + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 6A + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 6B + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 6C + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 6D + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 6E + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 6F + + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 70 + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 71 + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 72 + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 73 + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 74 + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 75 + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 76 + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 77 + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 78 + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 79 + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 7A + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 7B + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 7C + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 7D + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 7E + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 7F + + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 80 + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 81 + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 82 + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 83 + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 84 + {"pmacssww", 0x21005,0x0 , 0x15 , 0x1402, 0x402 , 0x402 , 0x402 , 0 , 0 , 0 , 0 }, // 0F 24 85 + {"pmacsswd", 0x21005,0x0 , 0x15 , 0x1403, 0x402 , 0x402 , 0x402 , 0 , 0 , 0 , 0 }, // 0F 24 86 + {"pmacssdql", 0x21005,0x0 , 0x15 , 0x1404, 0x403 , 0x403 , 0x403 , 0 , 0 , 0 , 0 }, // 0F 24 87 + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 88 + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 89 + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 8A + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 8B + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 8C + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 8D + {"pmacssdd", 0x21005,0x0 , 0x15 , 0x1403, 0x403 , 0x403 , 0x403 , 0 , 0 , 0 , 0 }, // 0F 24 8E + {"pmacssdqh", 0x21005,0x0 , 0x15 , 0x1404, 0x403 , 0x403 , 0x403 , 0 , 0 , 0 , 0 }, // 0F 24 8F + + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 90 + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 91 + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 92 + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 93 + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 94 + {"pmacsww", 0x21005,0x0 , 0x15 , 0x1402, 0x402 , 0x402 , 0x402 , 0 , 0 , 0 , 0 }, // 0F 24 95 + {"pmacswd", 0x21005,0x0 , 0x15 , 0x1403, 0x402 , 0x402 , 0x402 , 0 , 0 , 0 , 0 }, // 0F 24 96 + {"pmacsdql", 0x21005,0x0 , 0x15 , 0x1404, 0x403 , 0x403 , 0x403 , 0 , 0 , 0 , 0 }, // 0F 24 97 + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 98 + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 99 + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 9A + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 9B + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 9C + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 9D + {"pmacsdd", 0x21005,0x0 , 0x15 , 0x1403, 0x403 , 0x403 , 0x403 , 0 , 0 , 0 , 0 }, // 0F 24 9E + {"pmacsdqh", 0x21005,0x0 , 0x15 , 0x1404, 0x403 , 0x403 , 0x403 , 0 , 0 , 0 , 0 }, // 0F 24 9F + + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 A0 + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 A1 + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 A2 + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 A3 + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 A4 + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 A5 + {"pmadcsswd", 0x21005,0x0 , 0x15 , 0x1403, 0x402 , 0x402 , 0x402 , 0 , 0 , 0 , 0 }, // 0F 24 A6 + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 A7 + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 A8 + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 A9 + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 AA + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 AB + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 AC + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 AD + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 AE + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 AF + + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 B0 + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 B1 + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 B2 + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 B3 + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 B4 + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 B5 + {"pmadcswd", 0x21005,0x0 , 0x15 , 0x1403, 0x402 , 0x402 , 0x402 , 0 , 0 , 0 , 0 }, // 0F 24 B6 + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 B7 + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 B8 + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 B9 + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 BA + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 BB + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 BC + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 BD + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 BE + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }, // 0F 24 BF + + {0, 0 , 0 , 0x15 , 0x1450, 0x450 , 0x450 , 0x450 , 0 , 0 , 0 , 0 }}; // 0F 24 C0+. Reserved for future opcodes + +// Tertiary opcode map for 3-byte opcode. First two bytes = 0F 25 +// Indexed by third opcode byte +// AMD SSE5 instructions with three operands + immediate byte +// Note: These proposed codes have never been implemented. +SOpcodeDef OpcodeMap69[] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 00 + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 01 + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 02 + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 03 + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 04 + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 05 + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 06 + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 07 + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 08 + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 09 + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 0A + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 0B + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 0C + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 0D + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 0E + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 0F + + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 10 + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 11 + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 12 + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 13 + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 14 + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 15 + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 16 + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 17 + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 18 + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 19 + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 1A + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 1B + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 1C + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 1D + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 1E + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 1F + + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 20 + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 21 + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 22 + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 23 + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 24 + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 25 + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 26 + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 27 + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 28 + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 29 + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 2A + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 2B + {"comps", 0x21005,0x0 , 0x54 , 0x124B, 0x24B , 0x24B , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 2C + {"compd", 0x21005,0x0 , 0x54 , 0x124C, 0x24C , 0x24C , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 2D + {"comss", 0x21005,0x0 , 0x54 , 0x104B, 0x4B , 0x4B , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 2E + {"comsd", 0x21005,0x0 , 0x54 , 0x104C, 0x4C , 0x4C , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 2F + + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 30 + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 31 + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 32 + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 33 + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 34 + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 35 + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 36 + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 37 + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 38 + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 39 + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 3A + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 3B + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 3C + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 3D + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 3E + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 3F + + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 40 + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 41 + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 42 + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 43 + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 44 + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 45 + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 46 + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 47 + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 48 + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 49 + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 4A + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 4B + {"pcomb", 0x21005,0x0 , 0x54 , 0x1401, 0x401 , 0x401 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 4C + {"pcomw", 0x21005,0x0 , 0x54 , 0x1402, 0x402 , 0x402 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 4D + {"pcomd", 0x21005,0x0 , 0x54 , 0x1403, 0x403 , 0x403 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 4E + {"pcomq", 0x21005,0x0 , 0x54 , 0x1404, 0x404 , 0x404 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 4F + + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 50 + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 51 + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 52 + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 53 + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 54 + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 55 + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 56 + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 57 + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 58 + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 59 + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 5A + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 5B + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 5C + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 5D + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 5E + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 5F + + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 60 + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 61 + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 62 + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 63 + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 64 + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 65 + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 66 + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 67 + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 68 + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 69 + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 6A + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 6B + {"pcomub", 0x21005,0x0 , 0x54 , 0x1401, 0x401 , 0x401 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 6C + {"pcomuw", 0x21005,0x0 , 0x54 , 0x1402, 0x402 , 0x402 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 6D + {"pcomud", 0x21005,0x0 , 0x54 , 0x1403, 0x403 , 0x403 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 6E + {"pcomuq", 0x21005,0x0 , 0x54 , 0x1404, 0x404 , 0x404 , 0x31 , 0 , 0 , 0 , 0 }, // 0F 25 6F + + {0, 0 , 0 , 0x54 , 0x1450, 0x450 , 0x450 , 0x31 , 0 , 0 , 0 , 0 }}; // 0F 25 70+. Reserved for future opcodes + +// Tertiary opcode map for 3-byte opcode. First two bytes = 0F 7A +// Indexed by third opcode byte +// AMD SSE5 instructions with two operands +// Note: These proposed codes have never been implemented. +SOpcodeDef OpcodeMap6A[] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 00 + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 01 + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 02 + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 03 + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 04 + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 05 + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 06 + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 07 + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 08 + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 09 + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 0A + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 0B + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 0C + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 0D + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 0E + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 0F + + {"frczps", 0x21005,0x0 , 0x12 , 0x124B, 0x24B , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 10 + {"frczpd", 0x21005,0x0 , 0x12 , 0x124C, 0x24C , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 11 + {"frczss", 0x21005,0x0 , 0x12 , 0x104B, 0x4B , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 12 + {"frczsd", 0x21005,0x0 , 0x12 , 0x104C, 0x4C , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 13 + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 14 + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 15 + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 16 + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 17 + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 18 + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 19 + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 1A + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 1B + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 1C + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 1D + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 1E + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 1F + + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 20 + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 21 + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 22 + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 23 + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 24 + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 25 + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 26 + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 27 + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 28 + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 29 + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 2A + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 2B + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 2C + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 2D + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 2E + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 2F + + {"cvtph2ps", 0x21007,0x0 , 0x12 , 0x124B, 0x402 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 30 + {"cvtps2ph", 0x21007,0x0 , 0x13 , 0x402, 0x124B, 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 31 + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 32 + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 33 + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 34 + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 35 + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 36 + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 37 + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 38 + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 39 + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 3A + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 3B + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 3C + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 3D + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 3E + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 3F + + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 40 + {"phaddbw", 0x21005,0x0 , 0x12 , 0x1402, 0x401 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 41 + {"phaddbd", 0x21005,0x0 , 0x12 , 0x1403, 0x401 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 42 + {"phaddbq", 0x21005,0x0 , 0x12 , 0x1404, 0x401 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 43 + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 44 + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 45 + {"phaddwd", 0x21005,0x0 , 0x12 , 0x1403, 0x402 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 46 + {"phaddwq", 0x21005,0x0 , 0x12 , 0x1404, 0x402 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 47 + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 48 + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 49 + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 4A + {"phadddq", 0x21005,0x0 , 0x12 , 0x1404, 0x403 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 4B + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 4C + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 4D + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 4E + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 4F + + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 50 + {"phaddubw", 0x21005,0x0 , 0x12 , 0x1402, 0x401 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 51 + {"phaddubd", 0x21005,0x0 , 0x12 , 0x1403, 0x401 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 52 + {"phaddubq", 0x21005,0x0 , 0x12 , 0x1404, 0x401 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 53 + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 54 + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 55 + {"phadduwd", 0x21005,0x0 , 0x12 , 0x1403, 0x402 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 56 + {"phadduwq", 0x21005,0x0 , 0x12 , 0x1404, 0x402 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 57 + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 58 + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 59 + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 5A + {"phaddudq", 0x21005,0x0 , 0x12 , 0x1404, 0x403 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 5B + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 5C + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 5D + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 5E + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 5F + + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 60 + {"phsubbw", 0x21005,0x0 , 0x12 , 0x1402, 0x401 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 61 + {"phsubwd", 0x21005,0x0 , 0x12 , 0x1403, 0x401 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 62 + {"phsubdq", 0x21005,0x0 , 0x12 , 0x1404, 0x401 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 63 + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 64 + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 65 + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 66 + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 67 + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 68 + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 69 + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 6A + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 6B + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 6C + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 6D + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7A 6E + {0, 0 , 0 , 0x12 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }}; // 0F 7A 6F + +// Tertiary opcode map for 3-byte opcode. First two bytes = 0F 7B +// Indexed by third opcode byte +// AMD SSE5 instructions with two operands and an immediate byte operand +// Note: These proposed codes have never been implemented. +SOpcodeDef OpcodeMap6B[] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {0, 0 , 0 , 0x52 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7B 00 + {0, 0 , 0 , 0x52 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7B 01 + {0, 0 , 0 , 0x52 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7B 02 + {0, 0 , 0 , 0x52 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7B 03 + {0, 0 , 0 , 0x52 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7B 04 + {0, 0 , 0 , 0x52 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7B 05 + {0, 0 , 0 , 0x52 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7B 06 + {0, 0 , 0 , 0x52 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7B 07 + {0, 0 , 0 , 0x52 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7B 08 + {0, 0 , 0 , 0x52 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7B 09 + {0, 0 , 0 , 0x52 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7B 0A + {0, 0 , 0 , 0x52 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7B 0B + {0, 0 , 0 , 0x52 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7B 0C + {0, 0 , 0 , 0x52 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7B 0D + {0, 0 , 0 , 0x52 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7B 0E + {0, 0 , 0 , 0x52 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7B 0F + + {0, 0 , 0 , 0x52 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7B 10 + {0, 0 , 0 , 0x52 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7B 11 + {0, 0 , 0 , 0x52 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7B 12 + {0, 0 , 0 , 0x52 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7B 13 + {0, 0 , 0 , 0x52 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7B 14 + {0, 0 , 0 , 0x52 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7B 15 + {0, 0 , 0 , 0x52 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7B 16 + {0, 0 , 0 , 0x52 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7B 17 + {0, 0 , 0 , 0x52 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7B 18 + {0, 0 , 0 , 0x52 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7B 19 + {0, 0 , 0 , 0x52 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7B 1A + {0, 0 , 0 , 0x52 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7B 1B + {0, 0 , 0 , 0x52 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7B 1C + {0, 0 , 0 , 0x52 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7B 1D + {0, 0 , 0 , 0x52 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7B 1E + {0, 0 , 0 , 0x52 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7B 1F + + {0, 0 , 0 , 0x52 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7B 20 + {0, 0 , 0 , 0x52 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7B 21 + {0, 0 , 0 , 0x52 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7B 22 + {0, 0 , 0 , 0x52 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7B 23 + {0, 0 , 0 , 0x52 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7B 24 + {0, 0 , 0 , 0x52 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7B 25 + {0, 0 , 0 , 0x52 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7B 26 + {0, 0 , 0 , 0x52 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7B 27 + {0, 0 , 0 , 0x52 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7B 28 + {0, 0 , 0 , 0x52 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7B 29 + {0, 0 , 0 , 0x52 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7B 2A + {0, 0 , 0 , 0x52 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7B 2B + {0, 0 , 0 , 0x52 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7B 2C + {0, 0 , 0 , 0x52 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7B 2D + {0, 0 , 0 , 0x52 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7B 2E + {0, 0 , 0 , 0x52 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7B 2F + + {0, 0 , 0 , 0x52 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7B 30 + {0, 0 , 0 , 0x52 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7B 31 + {0, 0 , 0 , 0x52 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7B 32 + {0, 0 , 0 , 0x52 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7B 33 + {0, 0 , 0 , 0x52 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7B 34 + {0, 0 , 0 , 0x52 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7B 35 + {0, 0 , 0 , 0x52 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7B 36 + {0, 0 , 0 , 0x52 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7B 37 + {0, 0 , 0 , 0x52 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7B 38 + {0, 0 , 0 , 0x52 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7B 39 + {0, 0 , 0 , 0x52 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7B 3A + {0, 0 , 0 , 0x52 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7B 3B + {0, 0 , 0 , 0x52 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7B 3C + {0, 0 , 0 , 0x52 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7B 3D + {0, 0 , 0 , 0x52 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7B 3E + {0, 0 , 0 , 0x52 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7B 3F + + {"protb" , 0x21005,0x0 , 0x52 , 0x1401, 0x401 , 0x21 , 0 , 0 , 0 , 0 , 0 }, // 0F 7B 40 + {"protw" , 0x21005,0x0 , 0x52 , 0x1402, 0x402 , 0x21 , 0 , 0 , 0 , 0 , 0 }, // 0F 7B 41 + {"protd" , 0x21005,0x0 , 0x52 , 0x1403, 0x403 , 0x21 , 0 , 0 , 0 , 0 , 0 }, // 0F 7B 42 + {"protq" , 0x21005,0x0 , 0x52 , 0x1404, 0x404 , 0x21 , 0 , 0 , 0 , 0 , 0 }, // 0F 7B 43 + {0, 0 , 0 , 0x52 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7B 44 + {0, 0 , 0 , 0x52 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7B 45 + {0, 0 , 0 , 0x52 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7B 46 + {0, 0 , 0 , 0x52 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7B 47 + {0, 0 , 0 , 0x52 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7B 48 + {0, 0 , 0 , 0x52 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7B 49 + {0, 0 , 0 , 0x52 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7B 4A + {0, 0 , 0 , 0x52 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7B 4B + {0, 0 , 0 , 0x52 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7B 4C + {0, 0 , 0 , 0x52 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7B 4D + {0, 0 , 0 , 0x52 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7B 4E + {0, 0 , 0 , 0x52 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 7B 4F + + {0, 0 , 0 , 0x52 , 0x1450, 0x450 , 0 , 0 , 0 , 0 , 0 , 0 }}; // 0F 7B 50+ + + +// Tertiary opcode map for vmread, insrtw, extrq. Opcode byte = 0F 78 +// Indexed by prefix = none, 66, F2, F3 +SOpcodeDef OpcodeMap6C[4] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"vmread", 0x813 , 0x1000 , 0x13 , 0x4 , 0x1004, 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 78. vmread + {0, 0x6E , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x2 , 0 }, // 66 0F 78. link to map 6E: extrq xmm,xmm (AMD SSE4a) + {"insrtq", 0x1004, 0x800 , 0x32 , 0x1450, 0x1450, 0x11 , 0x11 , 0 , 0 , 0 , 0 }, // F2 0F 78. insrtq xmm,xmm,i,i (AMD SSE4a) + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }}; // F3 0F 78. + +// Tertiary opcode map for vmwrite, insrtw, extrq. Opcode byte = 0F 79 without VEX prefix +// Indexed by prefix = none, 66, F2, F3 +SOpcodeDef OpcodeMap6D[4] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"vmwrite", 0x813 , 0x1000 , 0x12 , 0x1004, 0x4 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 79. vmwrite + {"extrq", 0x1004, 0x200 , 0x12 , 0x1450, 0x1450, 0 , 0 , 0 , 0 , 0 , 0 }, // 66 0F 79. link to map 6E: extrq xmm,xmm (AMD SSE4a) + {"insrtq", 0x1004, 0x800 , 0x12 , 0x1450, 0x1450, 0 , 0 , 0 , 0 , 0 , 0 }, // F2 0F 79. insrtq xmm,xmm (AMD SSE4a) + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }}; // F3 0F 79. + +// Quarternary opcode map for extrq. Opcode byte = 66 0F 78 +// Indexed by reg bits = 0 - 7 +SOpcodeDef OpcodeMap6E[] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"extrq", 0x1004, 0x200 , 0x31 , 0x1450, 0x11 , 0x11 , 0 , 0 , 0 , 0 , 0 }, // 66 0F 78. extrq xmm,i,i (AMD SSE4a) + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }}; // reg bits must be 0 + +// Submap for movq xmm/m64,xmm. Opcode byte = 66 0F D6 +// Indexed by memory vs. register operand + SOpcodeDef OpcodeMap6F[2] = { + {"movq", 0x12 ,0x812200, 0x13 , 0x4 , 0x1450, 0 , 0 , 0 , 0 , 0 , 0x2 }, // movq m64,xmm + {"movq", 0x12 ,0x812200, 0x13 , 0x450 , 0x1450, 0 , 0 , 0 , 0 , 0 , 0x2 }}; // movq xmm,xmm + +// Submap for movddup. Opcode byte = F2 0F 12 +// Indexed by VEX.L +SOpcodeDef OpcodeMap70[4] = { + {"movddup", 0x13 , 0x00800, 0x12 , 0x124C, 0x4C , 0 , 0 , 0 , 0 , 0 , 0 }, // no VEX prefix + {"vmovddup", 0x19 ,0x852800, 0x12 , 0x124C, 0x4C , 0 , 0 , 0x20 , 0 , 0 , 0 }, // VEX.L = 0 + {"vmovddup", 0x19 ,0x852800, 0x12 , 0x124C, 0x24C , 0 , 0 , 0x20 , 0 , 0 , 0 }, // VEX.L = 1 + {"vmovddup", 0x19 ,0x852800, 0x12 , 0x124C, 0x24C , 0 , 0 , 0x20 , 0 , 0 , 0 }}; // EVEX.LL = 2 + +// Submap for movsd. Opcode byte = F2 0F 10 +// Indexed by memory/register operand +SOpcodeDef OpcodeMap71[2] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"movsd", 0x12 ,0x812800, 0x12 , 0x104C, 0x4C , 0 , 0 , 0x30 , 0 , 0 , 0x2 }, // F2 0F 10 mem + {"movsd", 0x12 ,0x892800, 0x19 , 0x104C, 0x104C, 0x104C, 0 , 0x30 , 0 , 0 , 0x2 }}; // F2 0F 10 reg + +// Submap for movss. Opcode byte = F3 0F 10 +// Indexed by memory/register operand +SOpcodeDef OpcodeMap72[2] = { + {"movss", 0x12 ,0x812400, 0x12 , 0x104B, 0x4B , 0 , 0 , 0x30 , 0 , 0 , 0x2 }, // F3 0F 10 mem + {"movss", 0x12 ,0x892400, 0x19 , 0x104B, 0x104B, 0x104B, 0 , 0x30 , 0 , 0 , 0x2 }}; // F3 0F 10 reg + +// Submap for movsd. Opcode byte = F2 0F 11 +// Indexed by memory/register operand +SOpcodeDef OpcodeMap73[2] = { + {"movsd", 0x12 ,0x812800, 0x13 , 0x4C , 0x104C, 0 , 0 , 0x30 , 0 , 0 , 0x2 }, // F2 0F 11 mem + {"movsd", 0x12 ,0x892800, 0x19 , 0x104C, 0x104C, 0x104C, 0 , 0x10 , 0 , 0 , 0x2 }}; // F2 0F 11 reg + +// Submap for movss. Opcode byte = F3 0F 11 +// Indexed by memory/register operand +SOpcodeDef OpcodeMap74[2] = { + {"movss", 0x12 ,0x812400, 0x13 , 0x4B , 0x104B, 0 , 0 , 0x10 , 0 , 0 , 0x2 }, // F3 0F 11 mem + {"movss", 0x12 ,0x892400, 0x19 , 0x104B, 0x104B, 0x104B, 0 , 0x30 , 0 , 0 , 0x2 }}; // F3 0F 11 reg + +// Submap for pinsrd/pinsrq. Opcode byte = 0F 3A 22 +// Indexed by operand size +SOpcodeDef OpcodeMap75[3] = { + {"pinsrd", 0x15 ,0x89B200, 0x59 , 0x1403, 0x1403, 0x3 , 0x11 , 0x1000, 0 , 0 , 0x2 }, // (16 bit). 66 prefix actually is 32 bits + {"pinsrd", 0x15 ,0x89B200, 0x59 , 0x1403, 0x1403, 0x3 , 0x11 , 0x1000, 0 , 0 , 0x2 }, // 32 bit + {"pinsrq", 0x15 ,0x89B200, 0x59 , 0x1404, 0x1404, 0x4 , 0x11 , 0x1000, 0 , 0 , 0x2 }}; // 64 bit. REX.W prefix + +// Submap for sqrtps/pd/sd/ss. Opcode byte = 0F 51 +// Indexed by prefix = none, 66, F2, F3 +SOpcodeDef OpcodeMap76[4] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"sqrtps", 0x11 ,0x852E00, 0x12 , 0x124F, 0x24F , 0 , 0 , 0x37 , 0 , 0 , 0x2 }, // 0F 51. sqrtps + {"sqrtpd", 0x11 ,0x852E00, 0x12 , 0x124F, 0x24F , 0 , 0 , 0x37 , 0 , 0 , 0x2 }, // 66 0F 51. sqrtpd + {"sqrtsd", 0x11 ,0x892E00, 0x19 , 0x124F, 0x124F, 0x24F , 0 , 0x36 , 0 , 0 , 0x2 }, // F2 0F 51. sqrtsd + {"sqrtss", 0x11 ,0x892E00, 0x19 , 0x124F, 0x124F, 0x24F , 0 , 0x36 , 0 , 0 , 0x2 }}; // F3 0F 51. sqrtss + +// Submap for rsqrtps/ss. Opcode byte = 0F 52 +// Indexed by prefix = none, 66, F2, F3 +SOpcodeDef OpcodeMap77[4] = { + {"rsqrtps", 0x11 , 0x50E00, 0x12 , 0x124F, 0x24F , 0 , 0 , 0 , 0 , 0 , 0x2 }, // 0F 52. rsqrtps + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x2 , 0 }, // illegal + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x2 , 0 }, // illegal + {"rsqrtss", 0x11 , 0x90E00, 0x19 , 0x124F, 0x124F, 0x24F , 0 , 0 , 0 , 0 , 0x2 }}; // F3 0F 52. rsqrtss + +// Submap for rcpps/ss. Opcode byte = 0F 53 +// Indexed by prefix = none, 66, F2, F3 +SOpcodeDef OpcodeMap78[4] = { + {"rcpps", 0x11 , 0x50E00, 0x12 , 0x124F, 0x24F , 0 , 0 , 0 , 0 , 0 , 0x2 }, // 0F 53. rcpps + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x2 , 0 }, // illegal + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x2 , 0 }, // illegal + {"rcpss", 0x11 , 0x90E00, 0x19 , 0x124F, 0x124F, 0x24F , 0 , 0 , 0 , 0 , 0x2 }}; // F3 0F 53. rcpss + +// Submap for emms/vzeroupper/vzeroall. Opcode byte = 0F 77 +// Indexed by VEX prefix and VEX.L +SOpcodeDef OpcodeMap79[3] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"emms", 0x7 , 0 , 0x2 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 77 + {"vzeroupper",0x19 , 0x10000, 0x2 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 77, L=0 + {"vzeroall", 0x19 , 0x50000, 0x2 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }}; // VEX 0F 77, L=1 + +// Submap for pmovsxbw. Opcode byte = 0F 38 20. Indexed by memory/register operand +SOpcodeDef OpcodeMap7A[2] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"pmovsxbw", 0x15 ,0x85A200, 0x12 , 0x1202, 0xF01 , 0 , 0 , 0x2220, 0 , 0 , 0x2 }, // 0F 38 20 mem, link by VEX.L + {"pmovsxbw", 0x15 ,0x85A200, 0x12 , 0x1202, 0xF01 , 0 , 0 , 0x2220, 0 , 0 , 0x2 }}; // 0F 38 20 reg + +// Submap for pmovsxbd. Opcode byte = 0F 38 21. Indexed by memory/register operand +SOpcodeDef OpcodeMap7B[2] = { + {0, 0x7C , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x0D , 0 }, // 0F 38 21 mem, link by VEX.L + {"pmovsxbd", 0x15 ,0x85A200, 0x12 , 0x1203, 0x401 , 0 , 0 , 0x20 , 0 , 0 , 0x2 }}; // 0F 38 21 reg + +// Submap for pmovsxbd. Opcode byte = 0F 38 21 mem. Indexed by VEX.L +SOpcodeDef OpcodeMap7C[] = { + {"pmovsxbd", 0x15 ,0x85A200, 0x12 , 0x1203, 0x3 , 0 , 0 , 0x2420 , 0 , 0 , 0x2 }, // 0F 38 21 L0 + {"pmovsxbd", 0x15 ,0x85A200, 0x12 , 0x1203, 0x301 , 0 , 0 , 0x2420 , 0 , 0 , 0x2 }, // 0F 38 21 L1 + {"pmovsxbd", 0x15 ,0x85A200, 0x12 , 0x1203, 0x401 , 0 , 0 , 0x2420 , 0 , 0 , 0x2 }}; // 0F 38 21 L2 + +// Submap for pmovsxbq. Opcode byte = 0F 38 22. Indexed by memory/register operand +SOpcodeDef OpcodeMap7D[2] = { + {"pmovsxbq", 0x7E , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x0D , 0 }, // 0F 38 22 mem, link by VEX.L + {"pmovsxbq", 0x15 ,0x858200, 0x12 , 0x1204, 0x401 , 0 , 0 , 0x20 , 0 , 0 , 0x2 }}; // 0F 38 22 reg + +// Submap for pmovsxbq. Opcode byte = 0F 38 22 mem. Indexed by VEX.L +SOpcodeDef OpcodeMap7E[] = { + {"pmovsxbq", 0x15 ,0x85A200, 0x12 , 0x1204, 0x2 , 0 , 0 , 0x2620, 0 , 0 , 0x2 }, // 0F 38 22 L0 + {"pmovsxbq", 0x15 ,0x85A200, 0x12 , 0x1204, 0x3 , 0 , 0 , 0x2620, 0 , 0 , 0x2 }, // 0F 38 22 L1 + {"pmovsxbq", 0x15 ,0x85A200, 0x12 , 0x1204, 0x4 , 0 , 0 , 0x2620, 0 , 0 , 0x2 }}; // 0F 38 22 L2 + +// Submap for pmovsxwd. Opcode byte = 0F 38 23. Indexed by memory/register operand +SOpcodeDef OpcodeMap7F[2] = { + {"pmovsxwd", 0x15 ,0x85A200, 0x12 , 0x1203, 0xF02 , 0 , 0 , 0x2220, 0 , 0 , 0x2 }, // 0F 38 23 mem, link by VEX.L + {"pmovsxwd", 0x15 ,0x85A200, 0x12 , 0x1203, 0xF02 , 0 , 0 , 0x20 , 0 , 0 , 0x2 }}; // 0F 38 23 reg + +// Submap for pmovsxwq. Opcode byte = 0F 38 24. Indexed by memory/register operand +SOpcodeDef OpcodeMap80[2] = { + {"pmovsxwq", 0x81 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x0D , 0 }, // 0F 38 24 mem, link by VEX.L + {"pmovsxwq", 0x15 ,0x85A200, 0x12 , 0x1204, 0x402 , 0 , 0 , 0x30 , 0 , 0 , 0x2 }}; // 0F 38 24 reg + +// Submap for pmovsxwq. Opcode byte = 0F 38 24 mem. Indexed by VEX.L +SOpcodeDef OpcodeMap81[] = { + {"pmovsxwq", 0x15 ,0x85A200, 0x12 , 0x1204, 0x3 , 0 , 0 , 0x2420, 0 , 0 , 0x2 }, // 0F 38 24 L0 + {"pmovsxwq", 0x15 ,0x85A200, 0x12 , 0x1204, 0x302 , 0 , 0 , 0x2420, 0 , 0 , 0x2 }, // 0F 38 24 L1 + {"pmovsxwq", 0x15 ,0x85A200, 0x12 , 0x1204, 0x402 , 0 , 0 , 0x2420, 0 , 0 , 0x2 }}; // 0F 38 24 L1 + +// Submap for pmovsxdq. Opcode byte = 0F 38 25. Indexed by memory/register operand +SOpcodeDef OpcodeMap82[2] = { + {"pmovsxdq", 0x15 ,0x85A200, 0x12 , 0x1204, 0xF03 , 0 , 0 , 0x2220, 0 , 0 , 0x2 }, // 0F 38 25 mem, link by VEX.L + {"pmovsxdq", 0x15 ,0x85A200, 0x12 , 0x1204, 0xF03 , 0 , 0 , 0x2220, 0 , 0 , 0x2 }}; // 0F 38 25 reg + +// Submap for pmovzxbw. Opcode byte = 0F 38 30. Indexed by memory/register operand +SOpcodeDef OpcodeMap83[2] = { + {"pmovzxbw", 0x15 ,0x85A200, 0x12 , 0x1202, 0xF01 , 0 , 0 , 0x2220, 0 , 0 , 0x2 }, // 0F 38 30 L0 + {"pmovzxbw", 0x15 ,0x85A200, 0x12 , 0x1202, 0xF01 , 0 , 0 , 0x2220, 0 , 0 , 0x2 }}; // 0F 38 30 reg + +// Submap for 0F 38 5A, indexed by L bit and MVEX for vector size +SOpcodeDef OpcodeMap84[] = { + {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 5A, 128 bits + {"vbroadcasti128",0x1C,0x978200,0x12 , 0x1550, 0x2451, 0 , 0 , 0x20 , 0 , 0 , 0 }, // 0F 38 5A, 256 bits + {"vbroadcasti32x4",0x80,0xC28200,0x12, 0x1603, 0x2403, 0 , 0 , 0x20 , 0x1012, 0 , 0x100 }, // 0F 38 5A, 512 bits + {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }}; + +// Submap for pmovzxbd. Opcode byte = 0F 38 31. Indexed by memory/register operand +SOpcodeDef OpcodeMap85[2] = { + {"pmovzxbd", 0x86 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x0D , 0 }, // 0F 38 31 mem, link by VEX.L + {"pmovzxbd", 0x15 ,0x85A200, 0x12 , 0x1203, 0x401 , 0 , 0 , 0x20 , 0 , 0 , 0x2 }}; // 0F 38 31 reg + +// Submap for pmovzxbd. Opcode byte = 0F 38 31 mem. Indexed by VEX.L +SOpcodeDef OpcodeMap86[] = { + {"pmovzxbd", 0x15 ,0x85A200, 0x12 , 0x1403, 0x3 , 0 , 0 , 0x2420 , 0 , 0 , 0x2 }, // 0F 38 31 L0 + {"pmovzxbd", 0x15 ,0x85A200, 0x12 , 0x1503, 0x301 , 0 , 0 , 0x2420 , 0 , 0 , 0x2 }, // 0F 38 31 L1 + {"pmovzxbd", 0x15 ,0x85A200, 0x12 , 0x1603, 0x401 , 0 , 0 , 0x2420 , 0 , 0 , 0x2 }}; // 0F 38 31 L2 + +// Submap for pmovzxbq. Opcode byte = 0F 38 32. Indexed by memory/register operand +SOpcodeDef OpcodeMap87[2] = { + {"pmovzxbq", 0x88 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x0D , 0 }, // 0F 38 32 mem, link by VEX.L + {"pmovzxbq", 0x15 ,0x858200, 0x12 , 0x1204, 0x401 , 0 , 0 , 0x20 , 0 , 0 , 0x2 }}; // 0F 38 32 reg + +// Submap for pmovzxbq. Opcode byte = 0F 38 32 mem. Indexed by VEX.L +SOpcodeDef OpcodeMap88[] = { + {"pmovzxbq", 0x15 ,0x85A200, 0x12 , 0x1204, 0x2 , 0 , 0 , 0x2620, 0 , 0 , 0x2 }, // 0F 38 32 L0 + {"pmovzxbq", 0x15 ,0x85A200, 0x12 , 0x1204, 0x3 , 0 , 0 , 0x2620, 0 , 0 , 0x2 }, // 0F 38 32 L1 + {"pmovzxbq", 0x15 ,0x85A200, 0x12 , 0x1204, 0x4 , 0 , 0 , 0x2620, 0 , 0 , 0x2 }}; // 0F 38 32 L2 + +// Submap for pmovzxwd. Opcode byte = 0F 38 33. Indexed by memory/register operand +SOpcodeDef OpcodeMap89[2] = { + {"pmovzxwd", 0x15 ,0x85A200, 0x12 , 0x1203, 0xF02 , 0 , 0 , 0x2220, 0 , 0 , 0x2 }, // 0F 38 33 mem, link by VEX.L + {"pmovzxwd", 0x15 ,0x85A200, 0x12 , 0x1203, 0xF02 , 0 , 0 , 0x2220, 0 , 0 , 0x2 }}; // 0F 38 33 reg + +// Submap for pmovzxwq. Opcode byte = 0F 38 34. Indexed by memory/register operand +SOpcodeDef OpcodeMap8A[2] = { + {"pmovzxwq", 0x8B , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x0D , 0 }, // 0F 38 34 mem, link by VEX.L + {"pmovzxwq", 0x15 ,0x85A200, 0x12 , 0x1204, 0x402 , 0 , 0 , 0x20 , 0 , 0 , 0x2 }}; // 0F 38 34 reg + +// Submap for pmovzxwq. Opcode byte = 0F 38 34 mem. Indexed by VEX.L +SOpcodeDef OpcodeMap8B[] = { + {"pmovzxwq", 0x15 ,0x85A200, 0x12 , 0x1204, 0x3 , 0 , 0 , 0x2420, 0 , 0 , 0x2 }, // 0F 38 34 L0 + {"pmovzxwq", 0x15 ,0x85A200, 0x12 , 0x1204, 0x302 , 0 , 0 , 0x2420, 0 , 0 , 0x2 }, // 0F 38 34 L1 + {"pmovzxwq", 0x15 ,0x85A200, 0x12 , 0x1204, 0x402 , 0 , 0 , 0x2420, 0 , 0 , 0x2 }}; // 0F 38 34 L1 + +// Submap for pmovzxwq. Opcode byte = 0F 38 35. Indexed by memory/register operand +SOpcodeDef OpcodeMap8C[2] = { + {"pmovzxdq", 0x15 ,0x85A200, 0x12 , 0x1204, 0xF03 , 0 , 0 , 0x2220, 0 , 0 , 0x2 }, // 0F 38 35 mem + {"pmovzxdq", 0x15 ,0x85A200, 0x12 , 0x1204, 0xF03 , 0 , 0 , 0x2220, 0 , 0 , 0x2 }}; // 0F 38 35 reg + +// submap for 0F 38 14. Indexed by VEX prefix +SOpcodeDef OpcodeMap8D[] = { + {"blendvps", 0x15 , 0x8200 , 0x12 , 0x124B, 0x24B , 0xAE , 0 , 0 , 0 , 0 , 0 }, // 0F 38 14 + {"vprorv", 0x20 ,0x883200, 0x19 , 0x1209, 0x1209, 0x0209, 0 , 0x31 , 0 , 0 , 0x1 }}; // VEX 0F 38 14 + +// submap for 0F 38 15. Indexed by VEX prefix +SOpcodeDef OpcodeMap8E[] = { + {"blendvpd", 0x15 , 0x8200 , 0x12 , 0x124C, 0x24C , 0xAE , 0 , 0 , 0 , 0 , 0 }, // 0F 38 15 + {"vprolv", 0x20 ,0x883200, 0x19 , 0x1209, 0x1209, 0x0209, 0 , 0x31 , 0 , 0 , 0x1 }}; // VEX 0F 38 15 + +// submap for 0F 3A 23. Index by W bit +SOpcodeDef OpcodeMap8F[] = { + {"vshuff32x4",0x20 ,0x88B200, 0x59 , 0x124F, 0x124F, 0x024F, 0x31 , 0x31 , 0 , 0 , 0 }, // 0F 3A 23. W0 + {"vshuff64x2",0x20 ,0x88B200, 0x59 , 0x124F, 0x124F, 0x024F, 0x31 , 0x31 , 0 , 0 , 0 }}; // 0F 3A 23. W1 + +// submap for 0F 3A 43. Index by W bit +SOpcodeDef OpcodeMap90[] = { + {"vshufi32x4",0x20 ,0x88B200, 0x59 , 0x1209, 0x1209, 0x0209, 0x31 , 0x31 , 0 , 0 , 0 }, // 0F 3A 43. W0 + {"vshufi64x2",0x20 ,0x88B200, 0x59 , 0x1209, 0x1209, 0x0209, 0x31 , 0x31 , 0 , 0 , 0 }}; // 0F 3A 43. W1 + +// submap for 0F 38 2A. Index by 66 F2 F3 prefix +SOpcodeDef OpcodeMap91[] = { + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 2A + {"movntdqa", 0x15 ,0x85A200, 0x12 , 0x1250, 0x2250, 0 , 0 , 0x00 , 0 , 0 , 0x102 }, // 66 0F 38 2A + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // F2 0F 38 2A + {"vpbroadcastmb2q",0x20,0x823400,0x12, 0x1204, 0x1095, 0 , 0 , 0 , 0 , 0 , 0 }}; // F3 0F 38 2A. W1 + +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options +// Submap for xlat. Opcode byte = D7. Indexed by assembly syntax: 0=MASM, 1=NASM/YASM, 2=GAS +SOpcodeDef OpcodeMap92[3] = { + {"xlat", 0 , 0x5 , 0x1 , 0 , 0x20C0, 0 , 0 , 0 , 0 , 0 , 0x8 }, // D7 + {"xlatb", 0 , 0x5 , 0x1 , 0 , 0x20C0, 0 , 0 , 0 , 0 , 0 , 0x8 }, // D7 + {"xlat", 0 , 0x5 , 0x1 , 0 , 0x20C0, 0 , 0 , 0 , 0 , 0 , 0x8 }}; // D7 + +// Submap for pmovmskb, Opcode 0F D7, Indexed by VEX prefix and VEX.L bit +SOpcodeDef OpcodeMap93[3] = { + {"pmovmskb", 0x7 , 0x51200, 0x12 , 0x1009, 0x1150, 0 , 0 , 0 , 0 , 0 , 0x2 }, // 0F D7 + {"pmovmskb", 0x7 , 0x51200, 0x12 , 0x100A, 0x1150, 0 , 0 , 0 , 0 , 0 , 0x2 }, // 0F D7, VEX (32/64 bit dest. depending on mode) + {"pmovmskb", 0x7 , 0x51200, 0x12 , 0x100A, 0x1150, 0 , 0 , 0 , 0 , 0 , 0x2 }}; // 0F D7, VEX.L (32/64 bit dest. depending on mode) + +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options +// Submap for vpgatherq, Opcode 0F 38 91, Indexed by VEX/EVEX +SOpcodeDef OpcodeMap94[2] = { + {0, 0x105 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0xC , 0 }, // + {0, 0x106 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0xC , 0 }}; // + +// Submap for vgatherqps/pd, Opcode 0F 38 93, Indexed by VEX.W bit +SOpcodeDef OpcodeMap95[2] = { + {"vgatherqps",0x1C , 0xE9200, 0x1E, 0xF4B , 0x224B, 0xF4B , 0 , 0 , 0 , 0 , 0 }, // 0F 38 93, W0 + {"vgatherqpd",0x1C , 0xE9200, 0x1E, 0x24C , 0x224C, 0x24C , 0 , 0 , 0 , 0 , 0 }}; // 0F 38 93, W1 + +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options +// Submap for psllw, Opcode 0F F1, Indexed by VEX.L bit +SOpcodeDef OpcodeMap96[] = { + {"psllw", 0x7 ,0x8D2200, 0x19 , 0x1102, 0x1102, 0x102 , 0 , 0x20 , 0 , 0 , 0x2 }, // 0F F1 + {"psllw", 0x7 ,0x8D2200, 0x19 , 0x1202, 0x1202, 0x402 , 0 , 0x20 , 0 , 0 , 0x2 }, // 0F F1, L1 + {"psllw", 0x20 ,0x8D2200, 0x19 , 0x1202, 0x1202, 0x402 , 0 , 0x20 , 0 , 0 , 0x2 }}; // 0F F1, L2 + +// Submap for pslld, Opcode 0F F2, Indexed by VEX.L bit +SOpcodeDef OpcodeMap97[] = { + {"pslld", 0x7 ,0x8D2200, 0x19 , 0x1103, 0x1103, 0x103 , 0 , 0x20 , 0 , 0 , 0x2 }, // 0F F2 + {"pslld", 0x7 ,0x8D2200, 0x19 , 0x1203, 0x1203, 0x403 , 0 , 0x20 , 0 , 0 , 0x2 }, // 0F F2, L1 + {"pslld", 0x20 ,0x8D2200, 0x19 , 0x1203, 0x1203, 0x403 , 0 , 0x20 , 0 , 0 , 0x2 }}; // 0F F2, L1 + +// Submap for psllq, Opcode 0F F3, Indexed by VEX.L bit +SOpcodeDef OpcodeMap98[] = { + {"psllq", 0x7 ,0x8D2200, 0x19 , 0x1104, 0x1104, 0x104 , 0 , 0x30 , 0 , 0 , 0x2 }, // 0F F3 + {"psllq", 0x7 ,0x8D2200, 0x19 , 0x1204, 0x1204, 0x404 , 0 , 0x30 , 0 , 0 , 0x2 }, // 0F F3, L1 + {"psllq", 0x20 ,0x8D2200, 0x19 , 0x1204, 0x1204, 0x404 , 0 , 0x30 , 0 , 0 , 0x2 }}; // 0F F3, L1 + +// Submap for psrlw, Opcode 0F D1, Indexed by VEX.L bit +SOpcodeDef OpcodeMap99[] = { + {"psrlw", 0x7 ,0x8D2200, 0x19 , 0x1102, 0x1102, 0x102 , 0 , 0x20 , 0 , 0 , 0x2 }, // 0F D1 + {"psrlw", 0x7 ,0x8D2200, 0x19 , 0x1202, 0x1202, 0x402 , 0 , 0x20 , 0 , 0 , 0x2 }, // 0F D1 + {"psrlw", 0x7 ,0x8D2200, 0x19 , 0x1202, 0x1202, 0x402 , 0 , 0x20 , 0 , 0 , 0x2 }}; // 0F D1 + +// Submap for psrld, Opcode 0F D2, Indexed by VEX.L bit +SOpcodeDef OpcodeMap9A[] = { + {"psrld", 0x7 ,0x8D2200, 0x19 , 0x1103, 0x1103, 0x103 , 0 , 0x20 , 0 , 0 , 0x2 }, // 0F D2 + {"psrld", 0x7 ,0x8D2200, 0x19 , 0x1203, 0x1203, 0x403 , 0 , 0x20 , 0 , 0 , 0x2 }, // 0F D2 + {"psrld", 0x7 ,0x8D2200, 0x19 , 0x1203, 0x1203, 0x403 , 0 , 0x20 , 0 , 0 , 0x2 }}; // 0F D2 + +// Submap for psrlq, Opcode 0F D3, Indexed by VEX.L bit +SOpcodeDef OpcodeMap9B[] = { + {"psrlq", 0x7 ,0x8D2200, 0x19 , 0x1104, 0x1104, 0x104 , 0 , 0x20 , 0 , 0 , 0x2 }, // 0F D3 + {"psrlq", 0x7 ,0x8D2200, 0x19 , 0x1204, 0x1204, 0x404 , 0 , 0x20 , 0 , 0 , 0x2 }, // 0F D3 + {"psrlq", 0x7 ,0x8D2200, 0x19 , 0x1204, 0x1204, 0x404 , 0 , 0x20 , 0 , 0 , 0x2 }}; // 0F D3 + +// Submap for psraw, Opcode 0F E1, Indexed by VEX.L bit +SOpcodeDef OpcodeMap9C[] = { + {"psraw", 0x7 ,0x8D2200, 0x19 , 0x1102, 0x1102, 0x102 , 0 , 0x20 , 0 , 0 , 0x2 }, // 0F E1 + {"psraw", 0x7 ,0x8D2200, 0x19 , 0x1202, 0x1202, 0x402 , 0 , 0x20 , 0 , 0 , 0x2 }, // 0F E1 + {"psraw", 0x7 ,0x8D2200, 0x19 , 0x1202, 0x1202, 0x402 , 0 , 0x20 , 0 , 0 , 0x2 }}; // 0F E1 + +// Submap for psrad, Opcode 0F E2, Indexed by VEX.L bit +SOpcodeDef OpcodeMap9D[] = { + {"psra", 0x7 ,0x8D3200, 0x19 , 0x1109, 0x1109, 0x109 , 0 , 0x21 , 0 , 0 , 0x3 }, // 0F E2 + {"psra", 0x7 ,0x8D3200, 0x19 , 0x1109, 0x1109, 0x409 , 0 , 0x21 , 0 , 0 , 0x3 }, // 0F E2. w bit specifies operand size only if EVEX + {"psra", 0x7 ,0x8D3200, 0x19 , 0x1109, 0x1109, 0x409 , 0 , 0x21 , 0 , 0 , 0x3 }}; // 0F E2. w bit specifies operand size only if EVEX + +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options +// Submap for vpbroadcastb, Opcode 0F 38 78, Indexed by memory/register +SOpcodeDef OpcodeMap9E[2] = { + {"vpbroadcastb",0x1C,0x878200, 0x12, 0x1201, 0x1 , 0 , 0 , 0x20 , 0 , 0 , 0 }, // 0F 38 78 mem + {"vpbroadcastb",0x1C,0x878200, 0x12, 0x1201, 0x401 , 0 , 0 , 0x20 , 0 , 0 , 0 }}; // 0F 38 78 reg + +// Submap for vpbroadcastw, Opcode 0F 38 79, Indexed by memory/register +SOpcodeDef OpcodeMap9F[2] = { + {"vpbroadcastw",0x1C,0x878200, 0x12, 0x1201, 0x2 , 0 , 0 , 0x20 , 0 , 0 , 0 }, // 0F 38 79 mem + {"vpbroadcastw",0x1C,0x878200, 0x12, 0x1201, 0x402 , 0 , 0 , 0x20 , 0 , 0 , 0 }}; // 0F 38 79 reg + +// Submap for vpbroadcastd, Opcode 0F 38 58, Indexed by memory/register +SOpcodeDef OpcodeMapA0[2] = { + {"vpbroadcastd",0x1C,0xC78200, 0x12, 0x1201, 0x3 , 0 , 0 , 0x20 , 0x100A, 0 , 0 }, // 0F 38 58 mem + {"vpbroadcastd",0x1C,0x878200, 0x12, 0x1201, 0x403 , 0 , 0 , 0x20 , 0 , 0 , 0 }}; // 0F 38 58 reg + +// Submap for vpbroadcastq, Opcode 0F 38 59, Indexed by memory/register +SOpcodeDef OpcodeMapA1[2] = { + {"vpbroadcastq",0x1C,0xC7B200, 0x12, 0x1201, 0x4 , 0 , 0 , 0x20 , 0x100B, 0 , 0 }, // 0F 38 59 mem. (manuals disagree on W bit?) + {"vpbroadcastq",0x1C,0x879200, 0x12, 0x1201, 0x404 , 0 , 0 , 0x20 , 0 , 0 , 0 }}; // 0F 38 59 reg + +// Submap for 0F 38 F3. Indexed by reg bit +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options +SOpcodeDef OpcodeMapA2[8] = { + {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 F3 /0 + {"blsr" , 0x1D , 0xB1000, 0x18 , 0x1009, 0x9 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 F3 /3 + {"blsmsk", 0x1D , 0xB1000, 0x18 , 0x1009, 0x9 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 F3 /3 + {"blsi" , 0x1D , 0xB1000, 0x18 , 0x1009, 0x9 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 F3 /3 + {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 F3 /4 + {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 F3 /5 + {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 F3 /6 + {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }}; // 0F 38 F3 /7 + +// Submap for 0F 38 F5. Indexed by prefixes +SOpcodeDef OpcodeMapA3[4] = { + {"bzhi" , 0x1D , 0xB1000, 0x1B , 0x1009, 0x9 , 0x1009, 0 , 0 , 0 , 0 , 0 }, // 0F 38 F5 + {"wruss" , 0 , 0x1200 , 0x13 , 0x2009, 0x1009, 0 , 0 , 0 , 0 , 0 , 0 }, // 66 0F 38 F5 + {"pdep" , 0x1D , 0xB1000, 0x19 , 0x1009, 0x1009, 0x9 , 0 , 0 , 0 , 0 , 0 }, // F2 0F 38 F5 + {"pext" , 0x1D , 0xB1000, 0x19 , 0x1009, 0x1009, 0x9 , 0 , 0 , 0 , 0 , 0 }}; // F3 0F 38 F5 + +// Submap for 0F 3A F0. Indexed by prefixes +SOpcodeDef OpcodeMapA4[4] = { + {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A F0 + {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 66 0F 3A F0 + {"rorx" , 0x1D , 0x31000, 0x52 , 0x1009, 0x9 , 0x31 , 0 , 0 , 0 , 0 , 0 }, // F2 0F 3A F0 + {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }}; // F3 0F 3A F0 + +// Quarternary opcode map for pinsrb. Opcode byte = 0F 3A 20 +// Indexed by memory vs. register operand +SOpcodeDef OpcodeMapA5[2] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"pinsrb", 0x15 ,0x89A200, 0x59 , 0x1401, 0x1401, 0x2001, 0x31 , 0x1000, 0 , 0 , 0x2 }, // 0F 3A 20 memory 8 + {"pinsrb", 0x15 ,0x89A200, 0x59 , 0x1401, 0x1401, 0x1003, 0x31 , 0 , 0 , 0 , 0x2 }}; // 0F 3A 20 register 32 + +// Opcode map for VIA instructions. Opcode byte = 0F A6 .. +// Indexed by mod and reg fields of mod/reg/rm byte +SOpcodeDef OpcodeMapA6[] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {0, 0 , 0 , 0x12 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F A6, mod<3, reg=0 + {0, 0 , 0 , 0x12 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F A6, mod<3, reg=1 + {0, 0 , 0 , 0x12 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F A6, mod<3, reg=2 + {0, 0 , 0 , 0x12 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F A6, mod<3, reg=3 + {0, 0 , 0 , 0x12 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F A6, mod<3, reg=4 + {0, 0 , 0 , 0x12 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F A6, mod<3, reg=5 + {0, 0 , 0 , 0x12 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F A6, mod<3, reg=6 + {0, 0 , 0 , 0x12 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F A6, mod<3, reg=7 + {"rep montmul;VIA",0x2001,0x8021,0x10, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x8 }, // F3 0F A6 /0 + {"rep xsha1;VIA",0x2001,0x8021,0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x8 }, // F3 0F A6 /1 + {"rep xsha256;VIA",0x2001,0x8021,0x10, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x8 }, // F3 0F A6 /2 + {0, 0 , 0 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }}; // 0F A6, mod=3, reg=3 + +// Opcode map for VIA instructions. Opcode byte = 0F A7 .. +// Indexed by mod and reg fields of mod/reg/rm byte +SOpcodeDef OpcodeMapA7[] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {0, 0 , 0 , 0x12 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F A7, mod<3, reg=0 + {0, 0 , 0 , 0x12 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F A7, mod<3, reg=1 + {0, 0 , 0 , 0x12 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F A7, mod<3, reg=2 + {0, 0 , 0 , 0x12 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F A7, mod<3, reg=3 + {0, 0 , 0 , 0x12 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F A7, mod<3, reg=4 + {0, 0 , 0 , 0x12 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F A7, mod<3, reg=5 + {0, 0 , 0 , 0x12 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F A7, mod<3, reg=6 + {0, 0 , 0 , 0x12 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F A7, mod<3, reg=7 + {0, 0xA8 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x9 , 0 }, // 0F A7, mod=3, reg=0. Link to XSTORE + {"rep xcryptecb;VIA",0x2001,0x8021,0x10,0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x8 }, // F3 0F A7 /1 + {"rep xcryptcbc;VIA",0x2001,0x8021,0x10,0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x8 }, // F3 0F A7 /2 + {"rep xcryptctr;VIA",0x2001,0x8021,0x10,0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x8 }, // F3 0F A7 /3 + {"rep xcryptcfb;VIA",0x2001,0x8021,0x10,0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x8 }, // F3 0F A7 /4 + {"rep xcryptofb;VIA",0x2001,0x8021,0x10,0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x8 }, // F3 0F A7 /5 + {0, 0 , 0 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }}; // 0F A7, mod=3, reg=6 + +// Opcode map for VIA XSTORE instruction. Opcode byte = 0F A7 /0 +// Indexed by prefixes +SOpcodeDef OpcodeMapA8[] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"xstore;VIA",0x2001, 1 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F A7 /0 + {0, 0 , 0 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 66 0F A7 /0 + {0, 0 , 0 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // F2 0F A7 /0 + {"rep xstore;VIA",0x2001,0x21, 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x8 }}; // F3 0F A7 /0 + +// Opcode map for XGETBV, XSETBV instruction. Opcode byte = 0F 01 /2 +// Indexed by rm bits +SOpcodeDef OpcodeMapA9[] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"xgetbv", 0x16 , 0 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x8 }, // 0F 01 D0 + {"xsetbv", 0x16 , 0 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 01 D1 + {0 , 0 , 0 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 01 D2 + {0 , 0 , 0 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 01 D3 + {0 , 0 , 0 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 01 D4 + {"xend" , 0x1D , 0 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 01 D5 + {"xtest" , 0x1D , 0 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 01 D6 + {0 , 0 , 0 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }}; // 0F 01 D7 + +// Opcode map for AMD virtualization instructions 0F 1F 11/011/xxx +// Indexed by rm bits +SOpcodeDef OpcodeMapAA[] = { + {"vmrun" , 0x1804 , 0 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x8 }, // 0F 01 D8 + {"vmmcall", 0x1804 , 0 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x8 }, // 0F 01 D9 + {"vmload", 0x1804 , 0 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x8 }, // 0F 01 DA + {"vmsave", 0x1804 , 0 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x8 }, // 0F 01 DB + {"stgi" , 0x1804 , 0 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x8 }, // 0F 01 DC + {"clgi" , 0x1804 , 0 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x8 }, // 0F 01 DD + {"skinit", 0x1804 , 0 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x8 }, // 0F 01 DE + {0 , 0x1804 , 0 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x8 }}; // 0F 01 DF + +// Opcode map for swapgs and RDTSCP instructions 0F 1F 11/111/xxx +// Indexed by rm bits +SOpcodeDef OpcodeMapAB[] = { + {"swapgs", 0x800 , 0 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x8 }, // 0F 01 F8. instruction set unknown + {"rdtscp", 0x19 , 0 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x8 }, // 0F 01 F9. AMD SSE4.A and Intel AVX? + {0 , 0 , 0 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 01 FA + {0 , 0 , 0 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 01 FB + {"clzero", 0 , 0 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 01 FC. AMD + {0 , 0 , 0 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 01 FD + {0 , 0 , 0 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 01 FE + {0 , 0 , 0 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }}; // 0F 01 FF + +// Opcode map for 0F C7 /6 +// Indexed by mem/reg +SOpcodeDef OpcodeMapAC[] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {0, 0x52 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x9 , 0 }, // 0F C7 /6 mem link to vmptrld etc + {"rdrand", 0x1D , 0x1100 , 0x11 , 0x1009, 0 , 0 , 0 , 0 , 0 , 0 , 0 }}; // 0F C7 /6 reg + +// Submap for 0F 38 F7, indexed by prefixes +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options +SOpcodeDef OpcodeMapAD[] = { + {"bextr", 0x1D , 0xB3000, 0x1B , 0x1009, 0x9 , 0x1009, 0 , 0 , 0 , 0 , 0 }, // 0F 38 F7 + {"shlx", 0x1D , 0xB3200, 0x1B , 0x1009, 0x9 , 0x1009, 0 , 0 , 0 , 0 , 0 }, // 66 0F 38 F7 + {"shrx", 0x1D , 0xB3800, 0x1B , 0x1009, 0x9 , 0x1009, 0 , 0 , 0 , 0 , 0 }, // F2 0F 38 F7 + {"sarx", 0x1D , 0xB3400, 0x1B , 0x1009, 0x9 , 0x1009, 0 , 0 , 0 , 0 , 0 }}; // F3 0F 38 F7 + +// Submap for 0F BC, indexed by prefixes +SOpcodeDef OpcodeMapAE[4] = { + {"bsf" , 0x3 , 0x1100 , 0x12 , 0x1009, 0x9 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F BC + {"bsf" , 0x3 , 0x1100 , 0x12 , 0x1009, 0x9 , 0 , 0 , 0 , 0 , 0 , 0 }, // 66 0F BC + {"tzcnti", 0x20 ,0x31800 , 0x12 , 0x1009, 0x9 , 0 , 0 , 0 , 0 , 0 , 0 }, // F2 0F BC + {"tzcnt" , 0x1D ,0x11500 , 0x12 , 0x1009, 0x9 , 0 , 0 , 0 , 0 , 0 , 0 }}; // F3 0F BC, or 66 F3 0F BC. Does not work for F3 66 0F BC! + +// Submap for 0F C7 /7, Indexed by mem/reg +SOpcodeDef OpcodeMapAF[] = { + {"vmptrst", 0x813 , 0 , 0x11 , 0x2351, 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F C7 /7 mem + {0 , 0x138 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 9 , 0 }}; // 0F C7 /7 reg. link to rdseed, rdpid + + +// Shortcut opcode map for VEX prefix and mmmm = 0000 +// Indexed by first opcode byte after VEX prefix. With or without mod/reg/rm byte, and any number of immediate bytes +SOpcodeDef OpcodeMapB0[] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 00 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 01 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 02 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 03 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 04 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 05 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 06 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 07 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 08 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 09 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0A + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0B + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0C + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0D + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0E + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F + + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 10 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 11 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 12 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 13 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 14 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 15 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 16 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 17 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 18 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 19 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 1A + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 1B + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 1C + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 1D + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 1E + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 1F + + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 20 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 21 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 22 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 23 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 24 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 25 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 26 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 27 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 28 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 29 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 2A + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 2B + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 2C + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 2D + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 2E + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 2F + + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 30 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 31 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 32 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 33 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 34 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 35 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 36 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 37 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 38 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 39 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 3A + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 3B + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 3C + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 3D + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 3E + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 3F + + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 40 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 41 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 42 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 43 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 44 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 45 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 46 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 47 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 48 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 49 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 4A + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 4B + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 4C + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 4D + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 4E + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 4F + + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 50 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 51 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 52 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 53 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 54 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 55 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 56 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 57 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 58 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 59 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 5A + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 5B + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 5C + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 5D + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 5E + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 5F + + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 60 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 61 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 62 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 63 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 64 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 65 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 66 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 67 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 68 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 69 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 6A + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 6B + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 6C + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 6D + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 6E + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 6F + + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 70 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 71 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 72 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 73 + {"jkzd", 0x20 , 0xB0080, 0x44 , 0x95 , 0x81 , 0 , 0 , 0 , 0 , 0 , 0x80 }, // VEX 74 + {"jknzd", 0x20 , 0xB0080, 0x44 , 0x95 , 0x81 , 0 , 0 , 0 , 0 , 0 , 0x80 }, // VEX 75 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 76 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 77 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 78 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 79 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 7A + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 7B + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 7C + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 7D + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 7E + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }}; // VEX 7F + +// Shortcut opcode map for VEX or EVEX prefix and mmmm = 0001 +// Important: if VEX prefix is optional then use OpcodeMap1 instead. Don't put the same code in both maps! +// Indexed by first opcode byte after VEX prefix. With or without mod/reg/rm byte, and any number of immediate bytes +SOpcodeDef OpcodeMapB1[] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 00 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 01 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 02 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 03 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 04 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 05 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 06 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 07 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 08 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 09 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 0A + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 0B + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 0C + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 0D + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 0E + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 0F + + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 10 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 11 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 12 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 13 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 14 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 15 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 16 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 17 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 18 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 19 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 1A + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 1B + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 1C + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 1D + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 1E + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 1F + + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 20 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 21 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 22 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 23 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 24 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 25 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 26 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 27 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 28 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 29 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 2A + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 2B + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 2C + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 2D + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 2E + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 2F + + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 30 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 31 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 32 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 33 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 34 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 35 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 36 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 37 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 38 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 39 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 3A + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 3B + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 3C + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 3D + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 3E + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 3F + +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 40 + {"kand", 0x20 , 0xE5200, 0x19 , 0x1095, 0x1095, 0x1095, 0 , 0 , 0 , 0 , 1 }, // VEX 0F 41 + {"kandn", 0x20 , 0xE5200, 0x19 , 0x1095, 0x1095, 0x1095, 0 , 0 , 0 , 0 , 1 }, // VEX 0F 42 + {"kandnr", 0x80 , 0x30000, 0x12 , 0x95 , 0x1095, 0 , 0 , 0 , 0 , 0 , 1 }, // VEX 0F 43 + {"knot", 0x20 , 0xE5200, 0x12 , 0x1095, 0x1095, 0 , 0 , 0 , 0 , 0 , 1 }, // VEX 0F 44 + {"kor", 0x20 , 0xE5200, 0x19 , 0x1095, 0x1095, 0x1095, 0 , 0 , 0 , 0 , 1 }, // VEX 0F 45 + {"kxnor", 0x20 , 0xE5200, 0x19 , 0x1095, 0x1095, 0x1095, 0 , 0 , 0 , 0 , 1 }, // VEX 0F 46 + {"kxor", 0x20 , 0xE5200, 0x19 , 0x1095, 0x1095, 0x1095, 0 , 0 , 0 , 0 , 1 }, // VEX 0F 47 + {"kmerge2l1h",0x80 , 0x30000, 0x12 , 0x95 , 0x1095, 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 48 + {"kmerge2l1l",0x80 , 0x30000, 0x12 , 0x95 , 0x1095, 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 49 + {"kadd", 0x20 , 0xE5200, 0x19 , 0x1095, 0x1095, 0x1095, 0 , 0 , 0 , 0 , 1 }, // VEX 0F 41 + {0, 0xF0 , 0 , 0x19 , 0 , 0 , 0 , 0 , 0 , 0 , 0x9 , 0 }, // VEX 0F 4B. Link to kunpckbw + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 4C + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 4D + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 4E + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 4F + + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 50 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 51 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 52 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 53 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 54 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 55 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 56 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 57 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 58 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 59 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 5A + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 5B + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 5C + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 5D + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 5E + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 5F + + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 60 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 61 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 62 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 63 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 64 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 65 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 66 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 67 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 68 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 69 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 6A + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 6B + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 6C + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 6D + {"vmov", 0x7 ,0x813200, 0x12 , 0x1409, 0x9 , 0 , 0 , 0x00 , 0 , 0 , 0x1 }, // VEX 0F 6E + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 6F + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 70 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 71 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 72 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 73 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 74 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 75 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 76 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 77 + {0, 0xDA , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x9 , 0 }, // EVEX 0F 78. Link to vcvttpd2udq + {0, 0xD6 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x9 , 0 }, // EVEX 0F 79. Link to vcvtps etc + {0, 0xDC , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x9 , 0 }, // E/MVEX 0F 7A. Link to vcvtudq2pd + {0, 0xDD , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x9 , 0 }, // EVEX 0F 7B. Link to vcvtusi2sd etc + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 7C + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 7D + {0, 0xE2 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x9 , 0 }, // VEX 0F 7E. Link to movq + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 7F + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 80 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 81 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 82 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 83 + {"jkzd", 0x20 , 0xB0080, 0x84 , 0x95 , 0x82 , 0 , 0 , 0 , 0 , 0 , 0x80 }, // VEX 0F 84 + {"jknzd", 0x20 , 0xB0080, 0x84 , 0x95 , 0x82 , 0 , 0 , 0 , 0 , 0 , 0x80 }, // VEX 0F 85 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 86 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 87 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 88 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 89 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 8A + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 8B + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 8C + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 8D + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 8E + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 8F +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {0, 0xEB , 0 , 0x12 , 0 , 0 , 0 , 0 , 0 , 0 , 3 , }, // VEX 0F 90. Link to kmov + {"kmov", 0x20 , 0x35200, 0x13 , 0x2009, 0x1095, 0 , 0 , 0 , 0 , 0 , 1 }, // VEX 0F 91. Name without w in KNC syntax, but code identical + {0, 0xEC , 0 , 0x12 , 0 , 0 , 0 , 0 , 0 , 0 , 0x9 , 0 }, // VEX 0F 92. Link to kmov r, k + {0, 0xEE , 0 , 0x12 , 0 , 0 , 0 , 0 , 0 , 0 , 0x9 , 0 }, // VEX 0F 93. Link to kmov k, r + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 94 + {"kconcath", 0x80 , 0xB0000, 0x19 , 0x1004, 0x1095, 0x1095, 0 , 0 , 0 , 0 , 0 }, // VEX 0F 95 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 96 + {"kconcatl", 0x80 , 0xB0000, 0x19 , 0x1004, 0x1095, 0x1095, 0 , 0 , 0 , 0 , 0 }, // VEX 0F 97 + {"kortest", 0x20 , 0x25200, 0x12 , 0x95 , 0x1095, 0 , 0 , 0 , 0 , 0 , 1 }, // VEX 0F 98 + {"ktest", 0x20 , 0x25200, 0x12 , 0x1095, 0x1095, 0 , 0 , 0 , 0 , 0 , 1 }, // VEX 0F 99 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 9A + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 9B + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 9C + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 9D + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 9E + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 9F + + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F A0 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F A1 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F A2 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F A3 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F A4 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F A5 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F A6 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F A7 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F A8 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F A9 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F AA + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F AB + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F AC + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F AD + {0, 0xCD , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x4 , 0 }, // VEX 0F AE. Link + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }}; // VEX 0F AF + + +// Shortcut opcode map for EVEX F2 0F 38 +// Indexed by first opcode byte after EVEX prefix +SOpcodeDef OpcodeMapB2[] = { + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 00 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 01 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 02 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 03 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 04 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 05 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 06 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 07 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 08 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 09 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 0A + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 0B + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 0C + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 0D + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 0E + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 0F + + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 10 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 11 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 12 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 13 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 14 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 15 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 16 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 17 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 18 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 19 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 1A + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 1B + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 1C + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 1D + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 1E + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 1F + +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 20 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 21 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 22 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 23 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 24 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 25 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 26 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 27 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 28 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 29 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 2A + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 2B + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 2C + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 2D + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 2E + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 2F + + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 30 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 31 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 32 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 33 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 34 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 35 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 36 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 37 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 38 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 39 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 3A + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 3B + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 3C + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 3D + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 3E + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 3F + +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 40 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 41 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 42 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 43 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 44 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 45 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 46 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 47 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 48 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 49 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 4A + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 4B + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 4C + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 4D + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 4E + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 4F + + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 50 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 51 + {"vp4dpwssd" ,0x24 ,0x8F9800, 0x19 , 0x164B, 0x164B, 0x244B, 0 , 0x20 , 0 , 0 , 0 }, // EVEX F2 0F 38 52 + {"vp4dpwssds",0x24 ,0x8F9800, 0x19 , 0x164B, 0x164B, 0x244B, 0 , 0x20 , 0 , 0 , 0 }, // EVEX F2 0F 38 53 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 54 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 55 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 56 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 57 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 58 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 59 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 5A + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 5B + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 5C + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 5D + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 5E + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 5F + +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 60 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 61 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 62 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 63 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 64 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 65 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 66 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 67 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 68 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 69 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 6A + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 6B + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 6C + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 6D + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 6E + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 6F + + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 70 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 71 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 72 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 73 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 74 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 75 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 76 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 77 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 78 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 79 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 7A + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 7B + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 7C + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 7D + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 7E + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 7F + +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 80 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 81 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 82 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 83 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 84 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 85 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 86 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 87 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 88 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 89 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 8A + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 8B + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 8C + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 8D + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 8E + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 8F + + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 90 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 91 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 92 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 93 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 94 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 95 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 96 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 97 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 98 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 99 + {"v4fmaddps", 0x24 ,0x8F9800, 0x19 , 0x164B, 0x164B, 0x264B, 0 , 0x20 , 0 , 0 , 0 }, // EVEX F2 0F 38 9A + {"v4fmaddss", 0x24 ,0x8F9800, 0x19 , 0x144B, 0x144B, 0x244B, 0 , 0x20 , 0 , 0 , 0 }, // EVEX F2 0F 38 9B + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 9C + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 9D + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 9E + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 9F + +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 A0 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 A1 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 A2 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 A3 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 A4 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 A5 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 A6 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 A7 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 A8 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 A9 + {"v4fnmaddps",0x24 ,0x8F9800, 0x19 , 0x164B, 0x164B, 0x264B, 0 , 0x20 , 0 , 0 , 0 }, // EVEX F2 0F 38 AA + {"v4fnmaddss",0x24 ,0x8F9800, 0x19 , 0x144B, 0x144B, 0x244B, 0 , 0x20 , 0 , 0 , 0 }, // EVEX F2 0F 38 AB + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 AC + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 AD + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F2 0F 38 AE + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }}; // EVEX F2 0F 38 AF + + +// Shortcut opcode map for EVEX F3 0F 38 +// Indexed by first opcode byte after EVEX prefix +SOpcodeDef OpcodeMapB3[] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 00 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 01 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 02 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 03 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 04 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 05 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 06 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 07 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 08 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 09 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 0A + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 0B + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 0C + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 0D + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 0E + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 0F + + {"vpmovuswb", 0x20 ,0x820400, 0x13 , 0x0F01, 0x1202, 0 , 0 , 0x2220, 0 , 0 , 0x800 }, // EVEX F3 0F 38 10 + {"vpmovusdb", 0x20 ,0x820400, 0x13 , 0x0401, 0x1203, 0 , 0 , 0x2430, 0 , 0 , 0x800 }, // EVEX F3 0F 38 11 + {"vpmovusqb", 0x20 ,0x820400, 0x13 , 0x0401, 0x1204, 0 , 0 , 0x2630, 0 , 0 , 0x800 }, // EVEX F3 0F 38 12 + {"vpmovusdw", 0x20 ,0x820400, 0x13 , 0x0F02, 0x1203, 0 , 0 , 0x2220, 0 , 0 , 0x800 }, // EVEX F3 0F 38 13 + {"vpmovusqw", 0x20 ,0x820400, 0x13 , 0x0402, 0x1204, 0 , 0 , 0x2430, 0 , 0 , 0x800 }, // EVEX F3 0F 38 14 + {"vpmovusqd", 0x20 ,0x820400, 0x13 , 0x0F03, 0x1204, 0 , 0 , 0x2220, 0 , 0 , 0x800 }, // EVEX F3 0F 38 15 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 16 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 17 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 18 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 19 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 1A + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 1B + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 1C + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 1D + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 1E + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 1F + +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"vpmovswb", 0x20 ,0x820400, 0x13 , 0x0F01, 0x1202, 0 , 0 , 0x2220, 0 , 0 , 0x800 }, // EVEX F3 0F 38 20 + {"vpmovsdb", 0x20 ,0x820400, 0x13 , 0x0401, 0x1203, 0 , 0 , 0x2430, 0 , 0 , 0x800 }, // EVEX F3 0F 38 21 + {"vpmovsqb", 0x20 ,0x820400, 0x13 , 0x0401, 0x1204, 0 , 0 , 0x2630, 0 , 0 , 0x800 }, // EVEX F3 0F 38 22 + {"vpmovsdw", 0x20 ,0x820400, 0x13 , 0x0F02, 0x1203, 0 , 0 , 0x2220, 0 , 0 , 0x800 }, // EVEX F3 0F 38 23 + {"vpmovsqw", 0x20 ,0x820400, 0x13 , 0x0402, 0x1204, 0 , 0 , 0x2430, 0 , 0 , 0x800 }, // EVEX F3 0F 38 24 + {"vpmovsqd", 0x20 ,0x820400, 0x13 , 0x0F03, 0x1204, 0 , 0 , 0x2220, 0 , 0 , 0 }, // EVEX F3 0F 38 25 + {"vptestnm", 0x20 ,0x8EC200, 0x19 , 0x95 , 0x1209, 0x209 , 0 , 0x11 , 0 , 0 , 1 }, // EVEX F3 0F 38 26 + {"vptestnm", 0x20 ,0x8EB200, 0x19 , 0x95 , 0x1209, 0x209 , 0 , 0x11 , 0 , 0 , 1 }, // EVEX F3 0F 38 27 + {"vpmovm2", 0x20 ,0x86C400, 0x12 , 0x1201, 0x95 , 0 , 0 , 0 , 0 , 0 , 1 }, // EVEX F3 0F 38 28 + {0, 0x12E , 0 , 0x12 , 0 , 0 , 0 , 0 , 0 , 0 , 0xC , 0 }, // EVEX F3 0F 38 29 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 2A + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 2B + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 2C + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 2D + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 2E + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 2F + + {"vpmovwb", 0x20 ,0x820400, 0x13 , 0x0F01, 0x1202, 0 , 0 , 0x2220, 0 , 0 , 0x800 }, // EVEX F3 0F 38 30 + {"vpmovdb", 0x20 ,0x820400, 0x13 , 0x0401, 0x1203, 0 , 0 , 0x2420, 0 , 0 , 0x800 }, // EVEX F3 0F 38 31 + {"vpmovqb", 0x20 ,0x820400, 0x13 , 0x0401, 0x1204, 0 , 0 , 0x2620, 0 , 0 , 0x800 }, // EVEX F3 0F 38 32 + {"vpmovdw", 0x20 ,0x820400, 0x13 , 0x0F02, 0x1203, 0 , 0 , 0x2220, 0 , 0 , 0x800 }, // EVEX F3 0F 38 33 + {"vpmovqw", 0x20 ,0x820400, 0x13 , 0x0402, 0x1204, 0 , 0 , 0x2420, 0 , 0 , 0x800 }, // EVEX F3 0F 38 34 + {"vpmovqd", 0x20 ,0x820400, 0x13 , 0x0F03, 0x1204, 0 , 0 , 0x2220, 0 , 0 , 0x800 }, // EVEX F3 0F 38 35 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 36 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 37 + {"vpmovm2", 0x20 ,0x86B400, 0x12 , 0x1201, 0x95 , 0 , 0 , 0 , 0 , 0 , 1 }, // EVEX F3 0F 38 38 + {0, 0x12F , 0 , 0x12 , 0 , 0 , 0 , 0 , 0 , 0 , 0xC , 0 }, // EVEX F3 0F 38 39 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 3A + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 3B + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 3C + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 3D + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 3E + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 3F + +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 40 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 41 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 42 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 43 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 44 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 45 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 46 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 47 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 48 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 49 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 4A + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 4B + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 4C + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 4D + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 4E + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 4F + + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 50 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 51 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 52 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 53 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 54 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 55 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 56 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 57 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 58 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 59 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 5A + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 5B + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 5C + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 5D + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 5E + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 5F + +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 60 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 61 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 62 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 63 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 64 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 65 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 66 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 67 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 68 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 69 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 6A + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 6B + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 6C + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 6D + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 6E + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 6F + + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 70 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 71 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 72 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 73 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 74 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 75 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 76 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 77 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 78 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 79 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 7A + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 7B + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 7C + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 7D + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 7E + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 7F + +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 80 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 81 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 82 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 83 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 84 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 85 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 86 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 87 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 88 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 89 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 8A + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 8B + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 8C + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 8D + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 8E + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 8F + + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 90 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 91 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 92 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 93 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 94 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 95 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 96 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 97 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 98 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 99 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 9A + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 9B + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 9C + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 9D + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 9E + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 9F + +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 A0 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 A1 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 A2 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 A3 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 A4 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 A5 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 A6 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 A7 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 A8 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 A9 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 AA + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 AB + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 AC + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 AD + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 AE + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }}; // EVEX F3 0F 38 AF + + + +// Submap for vcvtfxpntpd2udq etc. Opcode byte = 0F 3A CA +// Indexed by prefix: none/66/F2/F3 +SOpcodeDef OpcodeMapB4[] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options +{"vcvtfxpntudq2ps",0x80 ,0x420000, 0x52 , 0x164B, 0x603 , 0x31 , 0 , 0 , 0x1206, 0 , 0x100 }, // 0F 3A CA +{"vcvtfxpntps2udq",0x80 ,0x420200, 0x52 , 0x1603, 0x64B , 0x31 , 0 , 0 , 0x1204, 0 , 0x100 }, // 66 0F 3A CA +{"vcvtfxpntpd2udq",0x80 ,0x423800, 0x52 , 0x1603, 0x64C , 0x31 , 0 , 0 , 0x1205, 0 , 0x100 }, // F2 0F 3A CA + {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }}; // F3 0F 3A CA + +// Submap for vcvtfxpntdq2ps etc. Opcode byte = 0F 3A CB +// Indexed by prefix: none/66/F2/F3 +SOpcodeDef OpcodeMapB5[] = { +{"vcvtfxpntdq2ps",0x80 ,0x420000, 0x52 , 0x164B, 0x603 , 0x31 , 0 , 0 , 0x1206, 0 , 0x100 }, // 0F 3B CB +{"vcvtfxpntps2dq",0x80 ,0x420200, 0x52 , 0x1603, 0x64B , 0x31 , 0 , 0 , 0x1204, 0 , 0x100 }, // 66 0F 3B CB + {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // F2 0F 3B CB + {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }}; // F3 0F 3B CB + +// Submap for vgatherdps. Opcode byte = 0F 38 92 +// Indexed by MVEX prefix +SOpcodeDef OpcodeMapB6[] = { + {"vgatherdp", 0xCC ,0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0xC , 0 }, // VEX 0F 38 92. link vgatherdps + {"vgatherdp", 0xCB ,0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0xC , 0 }}; // EVEX/MVEX 0F 38 92. link vgatherdps, has k register as mask + +// Submap for E/MVEX 0F 38 C6 vgatherpf.. Indexed by W bit +SOpcodeDef OpcodeMapB7[] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {0 , 0x10D , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x2 , 0 }, // E/MVEX 0F 38 C6. W0 + {0 , 0x10E , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x2 , 0 }}; // E/MVEX 0F 38 C6. W1 + +// Submap for movdqa. Opcode byte = 66 0F 6F +// Indexed by E/MVEX prefix +SOpcodeDef OpcodeMapB8[] = { + {"movdqa", 0x12 , 0x52100, 0x12 , 0x1250, 0x250 , 0 , 0 , 0 , 0 , 0 , 0x102 }, // 66 0F 6F + {"vmovdqa", 0x19 ,0xC53100, 0x12 , 0x1209, 0x209 , 0 , 0 , 0x30 , 0x140A, 0 , 0x1100}}; // E/MVEX.66 0F 6F + +// Submap for movdqu. Opcode byte = F3 0F 6F +// Indexed by E/MVEX prefix +SOpcodeDef OpcodeMapB9[] = { + {"movdqu", 0x12 , 0x50400, 0x12 , 0x1250, 0x251 , 0 , 0 , 0 , 0 , 0 , 0x202 }, // F3 0F 6F + {"vmovdqu", 0x20 ,0x853400, 0x12 , 0x1209, 0x209 , 0 , 0 , 0x30 , 0 , 0 , 0x1200}}; // F3 0F 6F + +// Submap for movdqa. Opcode byte = 66 0F 7F +// Indexed by E/MVEX prefix +SOpcodeDef OpcodeMapBA[] = { + {"movdqa", 0x12 , 0x52100, 0x13 , 0x250 , 0x1250, 0 , 0 , 0 , 0 , 0 , 0x102 }, // 66 0F 7F + {"vmovdqa", 0x19 ,0xC53100, 0x13 , 0x203 , 0x1203, 0 , 0 , 0x30 , 0x140E, 0 , 0x1100}}; // E/MVEX.66.W0 0F 7F + +// Submap for movdqu. Opcode byte = F3 0F 7F +// Indexed by MVEX.W prefix +SOpcodeDef OpcodeMapBB[] = { + {"movdqu", 0x12 , 0x50400, 0x13 , 0x251 , 0x1250, 0 , 0 , 0 , 0 , 0 , 0x202 }, // F3 0F 7F + {"vmovdqu", 0x20 ,0x853400, 0x13 , 0x209 , 0x1209, 0 , 0 , 0x30 , 0 , 0 ,0x1200 }}; // E/MVEX F3 0F 7F + +// Submap for vmovaps. Opcode byte = 0F 29 +// Indexed by prefix: none/66/F2/F3 +SOpcodeDef OpcodeMapBC[] = { + {"mova", 0x11 ,0xC52200, 0x13 , 0x24F , 0x124F, 0 , 0 , 0x30 , 0x140C, 0 , 0x103 }, // 0F 29. movaps + {"mova", 0x11 ,0xC52200, 0x13 , 0x24F , 0x124F, 0 , 0 , 0x30 , 0x140C, 0 , 0x103 }, // 66 0F 29. movapd + {0 , 0xBD , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0xF , 0 }, // F2 0F 29. link to vmovnraps + {0 , 0xBD , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0xF , 0 }}; // F3 0F 29. link to vmovnraps + +// Submap for vmovnraps. Opcode byte = F2/F3 0F 29 +// Indexed by MVEX.E bit +SOpcodeDef OpcodeMapBD[] = { + {"vmovnrap", 0x80 ,0x411C00, 0x13 ,0x224F , 0x124F, 0 , 0 , 0 , 0x180C, 0 , 0x101 }, // F2/F3 0F 29 + {"vmovnrngoap",0x80 ,0x411C00, 0x13 ,0x224F , 0x124F, 0 , 0 , 0 , 0x180C, 0 , 0x101 }}; // F2/F3 0F 29, MVEX.E + +// Submap for vloadunpackld. Opcode byte = 0F 38 D0 +// Indexed by prefix: none/66 +SOpcodeDef OpcodeMapBE[] = { + {"vloadunpackl",0x80, 0x423200,0x12 , 0x1609, 0x2609, 0 , 0 , 0 , 0x100A, 0 , 0x101 }, // 0F 38 D0 + {"vpackstorel" ,0x80, 0x423200,0x13 , 0x2609, 0x1609, 0 , 0 , 0 , 0x100E, 0 , 0x101 }}; // 66 0F 38 D0 + +// Submap for vloadunpacklps. Opcode byte = 0F 38 D1 +// Indexed by prefix: none/66 +SOpcodeDef OpcodeMapBF[] = { + {"vloadunpacklp",0x80,0x421200,0x12 , 0x164F, 0x264F, 0 , 0 , 0 , 0x1008, 0 , 0x101 }, // 0F 38 D1 + {"vpackstorelp" ,0x80,0x421200,0x13 , 0x264F, 0x164F, 0 , 0 , 0 , 0x100C, 0 , 0x101 }}; // 66 0F 38 D1 + +// Submap for vloadunpackhd. Opcode byte = 0F 38 D4 +// Indexed by prefix: none/66 +SOpcodeDef OpcodeMapC0[] = { + {"vloadunpackh",0x80, 0x423200,0x12 , 0x1609, 0x2609, 0 , 0 , 0 , 0x100A, 0 , 0x101 }, // 0F 38 D4 + {"vpackstoreh" ,0x80, 0x423200,0x13 , 0x2609, 0x1609, 0 , 0 , 0 , 0x100E, 0 , 0x101 }}; // 66 0F 38 D4 + +// Submap for vloadunpackhps. Opcode byte = 0F 38 D5 +// Indexed by prefix: none/66 +SOpcodeDef OpcodeMapC1[] = { + {"vloadunpackhp",0x80,0x421200,0x12 , 0x164F, 0x264F, 0 , 0 , 0 , 0x1008, 0 , 0x101 }, // 0F 38 D5 + {"vpackstorehp" ,0x80,0x421200,0x13 , 0x264F, 0x164F, 0 , 0 , 0 , 0x100C, 0 , 0x101 }}; // 66 0F 38 D5 + +// Submap for pand. Opcode byte = 0F DB +// Indexed by E/MVEX prefix +SOpcodeDef OpcodeMapC2[] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"pand", 0x7 , 0xD0200, 0x19 , 0x1150, 0x1150, 0x150 , 0 , 0 , 0 , 0 , 0x2 }, // 0F DB + {"vpand", 0x20 ,0xC93200, 0x19 , 0x1209, 0x1209, 0x209 , 0 , 0x31 , 0x1406, 0 , 0x1 }}; // MVEX 0F DB + +// Submap for pandn. Opcode byte = 0F DF +// Indexed by MVEX prefix +SOpcodeDef OpcodeMapC3[] = { + {"pandn", 0x7 , 0xD0200, 0x19 , 0x1150, 0x1150, 0x150 , 0 , 0 , 0 , 0 , 0x2 }, // 0F DF + {"vpandn", 0x20 ,0xC93200, 0x19 , 0x1209, 0x1209, 0x209 , 0 , 0x31 , 0x1406, 0 , 0x1 }}; // MVEX 0F DF + +// Submap for por. Opcode byte = 0F EB +// Indexed by E/MVEX prefix +SOpcodeDef OpcodeMapC4[] = { + {"por", 0x7 , 0xD0200, 0x19 , 0x1150, 0x1150, 0x150 , 0 , 0 , 0 , 0 , 0x2 }, // 0F EB + {"vpor", 0x20 ,0xC93200, 0x19 , 0x1209, 0x1209, 0x209 , 0 , 0x31 , 0x1406, 0 , 0x1 }}; // MVEX 0F EB + +// Submap for pxor. Opcode byte = 0F EF +// Indexed by MVEX prefix +SOpcodeDef OpcodeMapC5[] = { + {"pxor", 0x7 , 0xD0200, 0x19 , 0x1150, 0x1150, 0x150 , 0 , 0 , 0 , 0 , 0x2 }, // 0F EF + {"vpxor", 0x20 ,0xC93200, 0x19 , 0x1209, 0x1209, 0x209 , 0 , 0x31 , 0x1406, 0 , 0x1 }}; // MVEX 0F EF + +// Submap for vpcmpd. Opcode byte = 0F 3A 3E +// Indexed by VEX / EVEX +SOpcodeDef OpcodeMapC6[] = { + {"kextract", 0x80 , 0x38200, 0x52 , 0x1095, 0x1004, 0x11 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 3A 3E + {0, 0x112 , 0 , 0x59 , 0 , 0 , 0 , 0 , 0 , 0 , 0x6 , 0 }}; // EVEX 0F 3A 3F. Link to vpcmp + +// Submap for pcmpeqd. Opcode byte = 0F 76 +// Indexed by E/MVEX prefix +SOpcodeDef OpcodeMapC7[] = { + {"pcmpeqd", 0x7 , 0xD0200, 0x19 , 0x1103, 0x1103, 0x103 , 0 , 0 , 0 , 0 , 0x2 }, // 0F 76 + {"vpcmpeqd", 0x20 ,0xCBA200, 0x19 , 0x95 , 0x1203, 0x203 , 0 , 0x11 , 0x1406, 0 , 0x000 }}; // E/MVEX 0F 76 + +// Submap for pcmpgtd. Opcode byte = 0F 66 +// Indexed by E/MVEX prefix +SOpcodeDef OpcodeMapC8[] = { + {"pcmpgtd", 0x7 , 0xD0200, 0x19 , 0x1103, 0x1103, 0x103 , 0 , 0 , 0 , 0 , 0x2 }, // 0F 66 + {"vpcmpgtd", 0x20 ,0xCBA200, 0x19 , 0x95 , 0x1203, 0x203 , 0 , 0x11 , 0x1406, 0 , 0x000 }}; // E/MVEX 0F 66 + +// Opcode map for EVEX 66 0F 79. Indexed by W bit +SOpcodeDef OpcodeMapC9[] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options +{"vcvtps2uqq", 0x20 ,0x840200, 0x12 , 0x204 , 0xF4B , 0 , 0 , 0x27 , 0 , 0 , 0 }, // EVEX 66 0F 79. W = 0 +{"vcvtpd2uqq", 0x20 ,0x841200, 0x12 , 0x204 , 0x24C , 0 , 0 , 0x27 , 0 , 0 , 0 }}; // EVEX 66 0F 79. W = 1 + +// Opcode map for 0F 50. Indexed by prefix +SOpcodeDef OpcodeMapCA[] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"movmskps", 0x11 , 0x52000, 0x12 , 0x100A, 0x124B, 0 , 0 , 0 , 0 , 0 , 2 }, // 0F 50. movmskps + {"movmskpd", 0x11 , 0x52200, 0x12 , 0x100A, 0x124C, 0 , 0 , 0 , 0 , 0 , 2 }, // 66 0F 50. movmskpd + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }}; + +// Submap for EVEX vgatherdps. Opcode byte = 0F 38 92 +// Indexed by VEX.W bit +SOpcodeDef OpcodeMapCB[] = { + {"vgatherdps",0x20 ,0xC39200, 0x1E, 0x24F , 0x224F, 0 , 0 , 0x1090, 0x3048, 0 , 0 }, // EVEX/MVEX 0F 38 92 has k register as mask + {"vgatherdpd",0x20 ,0xC39200, 0x1E, 0x24F , 0x2F4F, 0 , 0 , 0x1090, 0x3048, 0 , 0 }}; // EVEX/MVEX 0F 38 92 has k register as mask + +// Submap for vgatherdps. Opcode byte = 0F 38 92 +// Indexed by VEX.W bit +SOpcodeDef OpcodeMapCC[] = { + {"vgatherdps",0x1C ,0x0E9200, 0x1E, 0x24B , 0x224B, 0x24B , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 38 92 + {"vgatherdpd",0x1C ,0x0E9200, 0x1E, 0x24C , 0x2F4C, 0x24C , 0 , 0 , 0 , 0 , 0 }}; // VEX 0F 38 92 + +// Submap for opcodes VEX/MVEX 0F AE +// Indexed by reg bits = 0 - 7 and mod < 3 to mod = 3 +// These codes are with VEX or MVEX prefix. Same codes without prefix are in OpcodeMap34 +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options +SOpcodeDef OpcodeMapCD[] = { + {"fxsave", 0x11 , 0 , 0x11 , 0x2006, 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F AE /0 + {"fxrstor", 0x11 , 0 , 0x11 , 0 , 0x2006, 0 , 0 , 0 , 0 , 0 , 0x8 }, // VEX 0F AE /1 + {"vldmxcsr", 0x11 , 0x10000, 0x11 , 0 , 0x2003, 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F AE /2 + {"vstmxcsr", 0x11 , 0x10000, 0x11 , 0x2003, 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F AE /3 + {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F AE /4 + {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F AE /5 + {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F AE /6 + {0 , 0xCF , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 9 , 0 }, // VEX 0F AE /7. Link + {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F AE reg /0 + {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F AE reg /1 + {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F AE reg /2 + {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F AE reg /3 + {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F AE reg /4 + {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F AE reg /5 + {0 , 0xCE , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 9 , 0 }, // VEX 0F AE reg /6. Link + {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }}; // VEX 0F AE reg /7 + +// Submap for opcodes VEX/MVEX 0F AE /6 +// Indexed by prefixes 66 F2 F3 +SOpcodeDef OpcodeMapCE[] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F AE /6 + {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 66 0F AE /6 + {"spflt" , 0x80 , 0x33400, 0x11 , 0x1009, 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX F2 0F AE /6 + {"delay" , 0x80 , 0x33400, 0x11 , 0x1009, 0 , 0 , 0 , 0 , 0 , 0 , 0 }}; // VEX F3 0F AE /6 + +// Submap for opcodes VEX/MVEX 0F AE /7 +// Indexed by prefixes 66 F2 F3 +SOpcodeDef OpcodeMapCF[] = { + {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F AE /7 + {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 66 0F AE /7 + {"clevict0", 0x80 ,0x430800, 0x11 , 0x2006, 0 , 0 , 0 , 0 , 2 , 0 , 0 }, // VEX F2 0F AE /7 + {"clevict1", 0x80 ,0x430400, 0x11 , 0x2006, 0 , 0 , 0 , 0 , 2 , 0 , 0 }}; // VEX F3 0F AE /7 + +// Submap for opcodes 0F 38 F6 +// Indexed by prefixes 66 F2 F3 +SOpcodeDef OpcodeMapD0[] = { + {"wrss" , 0 , 0x1000 , 0x13 , 0x2009, 0x1009, 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 F6 + {"adcx" , 0x1D , 0x1200 , 0x12 , 0x1009, 0x9 , 0 , 0 , 0 , 0 , 0 , 0 }, // 66 0F 38 F6 + {"mulx" , 0x1D , 0xB1000, 0x19 , 0x1009, 0x1009, 0x9 , 0 , 0 , 0 , 0 , 0 }, // F2 0F 38 F6 + {"adox" , 0x1D , 0x1400 , 0x12 , 0x1009, 0x9 , 0 , 0 , 0 , 0 , 0 , 0 }}; // F3 0F 38 F6 + +SOpcodeDef OpcodeMapD1[] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"prefetch", 0x1001 , 0 , 0x11 , 0 , 0x2006, 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0D /0 AMD only. Works as NOP on Intel + {"prefetchw", 0x1D , 0 , 0x11 , 0 , 0x2006, 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0D /1 + {"prefetchwt1",0x22 , 0 , 0x11 , 0 , 0x2006, 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 0D /2 + {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }}; // + +// Tertiary opcode map for movnt. Opcode byte = 0F 2B +// Indexed by prefix = none, 66, F2, F3 +SOpcodeDef OpcodeMapD2[4] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"movntps", 0x11 ,0x852000, 0x13 , 0x224B, 0x124B, 0 , 0 , 0x00 , 0 , 0 , 0x102 }, // 0F 2B. movntps + {"movntpd", 0x12 ,0x852200, 0x13 , 0x224C, 0x124C, 0 , 0 , 0x00 , 0 , 0 , 0x102 }, // 66 0F 2B. movntpd + {"movntsd", 0x1004, 0x800 , 0x13 , 0x204C, 0x104C, 0 , 0 , 0 , 0 , 0 , 0 }, // F2 0F 2B. movntsd (AMD only) + {"movntss", 0x1004, 0x400 , 0x13 , 0x204B, 0x104B, 0 , 0 , 0 , 0 , 0 , 0 }}; // F3 0F 2B. movntss (AMD only) + +// opcode map for bsr and lzcnt. Opcode byte = 0F BD +// Indexed by prefix = none, 66, F2, F3 +SOpcodeDef OpcodeMapD3[4] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"bsr", 0x3 , 0x1100 , 0x12 , 0x1009, 0x9 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F BD. bsr + {"bsr", 0x3 , 0x1100 , 0x12 , 0x1009, 0x9 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F BD. not allowed + {"bsr", 0x3 , 0x1100 , 0x12 , 0x1009, 0x9 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F BD. not allowed + {"lzcnt", 0x1D ,0x11500 , 0x12 , 0x1009, 0x9 , 0 , 0 , 0 , 0 , 0 , 0 }}; // F3 0F BD. AMD SSE4a, Intel LZCNT + +// Opcode map for blcfill etc. Opcode byte = XOP(9) 01, indexed by reg bits +SOpcodeDef OpcodeMapD4[] = { + {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 01 /0 + {"blcfill", 0x1007, 0x11000, 0x18 , 0x1009, 0x9 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 01 /1 + {"blsfill", 0x1007 , 0x11000, 0x18 , 0x1009, 0x9 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 01 /2 + {"blcs" , 0x1007 , 0x11000, 0x18 , 0x1009, 0x9 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 01 /3 + {"tzmsk" , 0x1007 , 0x11000, 0x18 , 0x1009, 0x9 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 01 /4 + {"blcic" , 0x1007 , 0x11000, 0x18 , 0x1009, 0x9 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 01 /5 + {"blsic" , 0x1007 , 0x11000, 0x18 , 0x1009, 0x9 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 01 /6 + {"t1mskc", 0x1007 , 0x11000, 0x18 , 0x1009, 0x9 , 0 , 0 , 0 , 0 , 0 , 0 }}; // XOP(9) 01 /7 + +// Opcode map for blcmsk etc. Opcode byte = XOP(9) 02, indexed by reg bits +SOpcodeDef OpcodeMapD5[] = { + {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 02 /0 + {"blcmsk", 0x1007 , 0x11000, 0x18 , 0x1009, 0x9 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 02 /1 + {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 02 /2 + {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 02 /3 + {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 02 /4 + {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 02 /5 + {"blci" , 0x1007 , 0x11000, 0x18 , 0x1009, 0x9 , 0 , 0 , 0 , 0 , 0 , 0 }, // XOP(9) 02 /6 + {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }}; // XOP(9) 02 /7 + +// Opcode map for EVEX 0F 79. Indexed by 66,F2,F3 prefix +SOpcodeDef OpcodeMapD6[] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {0, 0xD9 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0xC , 0 }, // EVEX 0F 79. Link to vcvtps/pd2udq + {0, 0xC9 , 0 , 0x12 , 0 , 0 , 0 , 0 , 0 , 0 , 0xC , 0 }, // EVEX 66 0F 79. Link to + {"vcvtsd2usi",0x20 ,0x803800, 0x12 , 0x1009, 0x4C , 0 , 0 , 0x6 , 0 , 0 , 0 }, // EVEX F2 0F 79 + {"vcvtss2usi",0x20 ,0x803800, 0x12 , 0x1009, 0x4B , 0 , 0 , 0x6 , 0 , 0 , 0 }}; // EVEX F3 0F 79 + +// Opcode map for 0F 38 A0. Indexed by VEX.W bit +SOpcodeDef OpcodeMapD7[] = { + {"vpscatterdd",0x20 , 0xC3B200,0x1E , 0x2209, 0x1209, 0 , 0 , 0x1090, 0x304E, 0 , 0x000 }, // W0 0F 38 A0 + {"vpscatterdq",0x20 , 0xC3B200,0x1E , 0x2F09, 0x1209, 0 , 0 , 0x1090, 0x304E, 0 , 0x000 }}; // W1 0F 38 A0 + +// Opcode map for 0F 38 A1. Indexed by VEX.W bit +SOpcodeDef OpcodeMapD8[] = { + {"vpscatterqd",0x20 , 0xC3B200,0x1E , 0x2209, 0x1F09, 0 , 0 , 0x1090, 0x304E, 0 , 0x000 }, // W0 0F 38 A0 + {"vpscatterqq",0x20 , 0xC3B200,0x1E , 0x2209, 0x1209, 0 , 0 , 0x1090, 0x304E, 0 , 0x000 }}; // W1 0F 38 A0 + +// Opcode map for EVEX 0F 79, pp0. Indexed by W bit +SOpcodeDef OpcodeMapD9[] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options +{"vcvtps2udq", 0x20 ,0x840000, 0x12 , 0x203 , 0x24B , 0 , 0 , 0x37 , 0 , 0 , 0 }, // EVEX 0F 79. W = 0 +{"vcvtpd2udq", 0x20 ,0x841000, 0x12 , 0xF03 , 0x24C , 0 , 0 , 0x37 , 0 , 0 , 0 }}; // EVEX 0F 79. W = 1 + +// Opcode map for EVEX 0F 78. Indexed by 66,F2,F3 prefix +SOpcodeDef OpcodeMapDA[] = { + {0, 0xDB , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0xC , 0 }, // EVEX 0F 78. Link to vcvttpd2udq + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 66 EVEX 0F 78 + {"vcvttsd2usi",0x20 ,0x803800, 0x12 , 0x1009, 0x4C , 0 , 0 , 0x2 , 0 , 0 , 0 }, // F2 EVEX 0F 78 + {"vcvttss2usi",0x20 ,0x803400, 0x12 , 0x1009, 0x4B , 0 , 0 , 0x2 , 0 , 0 , 0 }}; // F3 EVEX 0F 78 + +// Opcode map for EVEX 0F 78. Indexed by W bit +SOpcodeDef OpcodeMapDB[] = { + {"vcvttps2udq",0x20 ,0x841000, 0x12 , 0x1203, 0x24B , 0 , 0 , 0x37 , 0 , 0 , 0 }, // VEX 0F 78 + {"vcvttpd2udq",0x20 ,0x841000, 0x12 , 0x1F03, 0x24C , 0 , 0 , 0x37 , 0 , 0 , 0 }}; // VEX 0F 78 + +// Opcode map for EVEX 0F 7A. Indexed by 66,F2,F3 prefix +SOpcodeDef OpcodeMapDC[] = { + {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX 0F 7A + {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 66 EVEX 0F 7A + {0 ,0x11B , 0 , 0x12 , 0 , 0 , 0 , 0 , 0 , 0 , 0xC , 0 }, // F2 EVEX 0F 7A. Link to vcvtudq2ps + {0 ,0x11C , 0 , 0x12 , 0 , 0 , 0 , 0 , 0 , 0 , 0xC , 0 }}; // F3 E/MVEX 0F 7A. Link to vcvtudq2pd + +// Opcode map for EVEX 0F 7B. Indexed by 66,F2,F3 prefix +SOpcodeDef OpcodeMapDD[] = { + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX 0F 7B + {0, 0x11A , 0 , 0x12 , 0 , 0 , 0 , 0 , 0 , 0 , 0xC , 0 }, // 66 EVEX 0F 7B. Link to vcvtps/pd2qq + {"vcvtusi2sd",0x20 ,0x8C3800, 0x19 , 0x104C, 0x104C, 9 , 0 , 0x06 , 0 , 0 , 0 }, // F2 EVEX 0F 7B + {"vcvtusi2ss",0x20 ,0x8C3400, 0x19 , 0x104B, 0x104B, 9 , 0 , 0x06 , 0 , 0 , 0 }}; // F3 EVEX 0F 7B + +// Opcode map for 0F 3A 1B. Indexed by W bit +SOpcodeDef OpcodeMapDE[] = { + {"vextractf32x8",0x20,0x801200,0x53 , 0x54B , 0x124B, 0x31 , 0 , 0x30 , 0 , 0 , 0 }, // 0F 3A 1B. W0 + {"vextractf64x4",0x20,0x801200,0x53 , 0x54B , 0x124B, 0x31 , 0 , 0x30 , 0 , 0 , 0 }}; // 0F 3A 1B. W1 + +// Opcode map for 0F 3A 3B. Indexed by W bit +SOpcodeDef OpcodeMapDF[] = { + {"vextracti32x8",0x20,0x800200, 0x53 , 0x504 , 0x1204, 0x31 , 0 , 0x20 , 0 , 0 , 0 }, // 0F 3A 3B + {"vextracti64x4",0x20,0x801200, 0x53 , 0x504 , 0x1204, 0x31 , 0 , 0x20 , 0 , 0 , 0 }}; // 0F 3A 3B + +// Opcode map for 0F 38 93. Indexed by EVEX present +SOpcodeDef OpcodeMapE0[] = { + {"vgatherqp", 0x95 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0xC , 0 }, // 0F 38 93. Link to vpgatherqps/pd + {"vgatherqp", 0xE1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0xC , 0 }}; // EVEX/MVEX 0F 38 92 has k register as mask. Link by vector size + +// Opcode map for 0F 38 93. Indexed by W bit +SOpcodeDef OpcodeMapE1[] = { + {"vgatherqps",0x20 ,0xC39200, 0x1E , 0xF4F , 0x224F, 0 , 0 , 0x1090, 0x3048, 0 , 0 }, // EVEX/MVEX 0F 38 92. W0 + {"vgatherqpd",0x20 ,0xC39200, 0x1E , 0x24F , 0x224F, 0 , 0 , 0x1090, 0x3048, 0 , 0 }}; // EVEX/MVEX 0F 38 92. W1 + +// map for movd/movq. Opcode byte = 0F 7E +// Indexed by prefix: none/66/F2/F3 +SOpcodeDef OpcodeMapE2[] = { + {"vmov", 0x7 ,0x813200, 0x13 , 0x9 , 0x1409, 0 , 0 , 0x00 , 0 , 0 , 0x1 }, // VEX 0F 7E + {"vmov", 0x7 ,0x813200, 0x13 , 0x9 , 0x1409, 0 , 0 , 0x00 , 0 , 0 , 0x1 }, // 66 VEX 0F 7E + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // F2 VEX 0F 7E + {0, 0x5B , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0x3 , 0 }}; // F3 0F 7E. Link to map 5B. movq xmm,xmm/m64 + +// map for 0F 38 29 +// Indexed by EVEX +SOpcodeDef OpcodeMapE3[] = { + {"pcmpeqq", 0x16 , 0xD8200, 0x19 , 0x1204, 0x1204, 0x204 , 0 , 0 , 0 , 0 , 0x2 }, // 0F 38 29 + {"vpcmpeqq", 0x20 ,0x8FB200, 0x19 , 0x95 , 0x1204, 0x204 , 0 , 0x11 , 0 , 0 , 0 }}; // EVEX 0F 38 29 + +// map for 0F 38 37 +// Indexed by EVEX +SOpcodeDef OpcodeMapE4[] = { + {"pcmpgtq", 0x16 , 0xD8200, 0x19 , 0x1204, 0x1204, 0x204 , 0 , 0 , 0 , 0 , 0x2 }, // 0F 38 37 + {"vpcmpgtq", 0x20 ,0x8FB200, 0x19 , 0x95 , 0x1204, 0x204 , 0 , 0x11 , 0 , 0 , 0 }}; // EVEX 0F 38 37 + +// Submap for 0F 38 1A, indexed by VEX.W bit +SOpcodeDef OpcodeMapE5[] = { + {0 , 0xF8 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0xE , 0 }, // VEX 0F 38 1A /W0, link to vbroadcastf128 vbroadcastf32x4 + {"vbroadcastf64x2",0x20,0xC6B200,0x12, 0x124C, 0x244C, 0 , 0 , 0x20 , 0x1010, 0 , 0x100 }}; // 0F 38 1A, 512 bits + +// Map for 0F 38 39. Indexed by EVEX present +SOpcodeDef OpcodeMapE6[] = { + {"pminsd", 0x15 ,0x4D8200, 0x19 , 0x1203, 0x1203, 0x203 , 0 , 0 , 0x1406, 0 , 0x2 }, // 0F 38 39 + {0, 0x12D , 0 , 0x19 , 0 , 0 , 0 , 0 , 0 , 0 , 0x9 , 0 }}; // EVEX 0F 38 39 + +// Map for 0F 38 3B. Indexed by EVEX present +SOpcodeDef OpcodeMapE7[] = { + {"pminud", 0x15 ,0x4D8200, 0x19 , 0x1203, 0x1203, 0x203 , 0 , 0 , 0x1406, 0 , 0x2 }, // 0F 38 3B + {"vpminu", 0x15 ,0xCDB200, 0x19 , 0x1209, 0x1209, 0x209 , 0 , 0x31 , 0x1406, 0 , 0x1 }}; // 0F 38 3B + +// Map for 0F 38 3D. Indexed by EVEX present +SOpcodeDef OpcodeMapE8[] = { + {"pmaxsd", 0x15 ,0x4D8200, 0x19 , 0x1203, 0x1203, 0x203 , 0 , 0 , 0x1406, 0 , 0x2 }, // 0F 38 3D + {"vpmaxs", 0x15 ,0xCDB200, 0x19 , 0x1209, 0x1209, 0x209 , 0 , 0x31 , 0x1406, 0 , 0x1 }}; // 0F 38 3D + +// Map for 0F 38 3F. Indexed by EVEX present +SOpcodeDef OpcodeMapE9[] = { + {"pmaxud", 0x15 ,0x4D8200, 0x19 , 0x1203, 0x1203, 0x203 , 0 , 0 , 0x1406, 0 , 0x2 }, // 0F 38 3F + {"vpmaxu", 0x15 ,0xCDB200, 0x19 , 0x1209, 0x1209, 0x209 , 0 , 0x31 , 0x1406, 0 , 0x1 }}; // 0F 38 3F + +// Map for 0F 38 10. Indexed by VEX prefix type +SOpcodeDef OpcodeMapEA[] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"pblendvb", 0x15 , 0x8200 , 0x12 , 0x1401, 0x401 , 0xAE , 0 , 0 , 0 , 0 , 0 }, // 0F 38 10 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 38 10 + {"vpsrlvw", 0x20 ,0x8FC200, 0x19 , 0x1209, 0x1209, 0x209 , 0 , 0x20 , 0 , 0 , 0 }, // EVEX 0F 38 10 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }}; // MVEX 0F 38 10 + +// Map for VEX 0F 90. Indexed by memory/register +SOpcodeDef OpcodeMapEB[] = { + {"kmov", 0x20 , 0x35200, 0x12 , 0x1095, 0x2009, 0 , 0 , 0 , 0 , 0 , 1 }, // VEX 0F 90. Name without w in KNC syntax, but code identical + {"kmov", 0x20 , 0x35200, 0x12 , 0x1095, 0x95 , 0 , 0 , 0 , 0 , 0 , 1 }}; // VEX 0F 90. Name without w in KNC syntax, but code identical + +// Map for VEX 0F 92. indexed by prefix 0 66 F2 F3 +// The coding with F2 is different from other k instructions. Allow coding with 66 instead in case this is an error in the manual +SOpcodeDef OpcodeMapEC[] = { + {"kmov", 0x20 , 0x35200, 0x12 , 0x95 , 0x1003, 0 , 0 , 0 , 0 , 0 , 1 }, // VEX 0F 92. Name without w in KNC syntax, but code identical + {"kmov", 0x20 , 0x35200, 0x12 , 0x95 , 0x1003, 0 , 0 , 0 , 0 , 0 , 1 }, // 66 VEX 0F 92 + {0, 0xED , 0 , 0x12 , 0 , 0 , 0 , 0 , 0 , 0 , 0xC , 0 }}; // F2 VEX 0F 92 + +// Map for VEX 0F 92. indexed by VEX.W bit +SOpcodeDef OpcodeMapED[] = { + {"kmovd", 0x20 , 0x35200, 0x12 , 0x95 , 0x1003, 0 , 0 , 0 , 0 , 0 , 0 }, // F2 VEX 0F 92. W0 + {"kmovq", 0x20 , 0x35200, 0x12 , 0x95 , 0x1004, 0 , 0 , 0 , 0 , 0 , 0 }}; // F2 VEX 0F 92. W1 + +// Map for VEX 0F 93. indexed by prefix 0 66 F2 F3 +// The coding with F2 is different from other k instructions. Allow coding with 66 instead in case this is an error in the manual +SOpcodeDef OpcodeMapEE[] = { + {"kmov", 0x20 , 0x35200, 0x12 , 0x1003, 0x1095, 0 , 0 , 0 , 0 , 0 , 1 }, // VEX 0F 93. Name without w in KNC syntax, but code identical + {"kmov", 0x20 , 0x35200, 0x12 , 0x1003, 0x1095, 0 , 0 , 0 , 0 , 0 , 1 }, // 66 VEX 0F 93 + {0, 0xEF , 0 , 0x12 , 0 , 0 , 0 , 0 , 0 , 0 , 0xC , 0 }}; // F2 VEX 0F 93 + +// Map for VEX 0F 93. indexed by VEX.W bit +SOpcodeDef OpcodeMapEF[] = { + {"kmovd", 0x20 , 0x35200, 0x12 , 0x1003, 0x1095, 0 , 0 , 0 , 0 , 0 , 0 }, // F2 VEX 0F 93 W0 + {"kmovq", 0x20 , 0x35200, 0x12 , 0x1004, 0x1095, 0 , 0 , 0 , 0 , 0 , 0 }}; // F2 VEX 0F 93 W1 + +// Map for VEX 0F 4B. indexed by prefix 0 66 F2 F3 +SOpcodeDef OpcodeMapF0[] = { + {0, 0xF1 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0xC , 0 }, + {"kunpckbw", 0x20 ,0x1E3200, 0x19 , 0x1095, 0x1095, 0x1095, 0 , 0 , 0 , 0 , 0 }, // 66 VEX 0F 4B + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }}; + +// Map for VEX 0F 4B. indexed by VEX.W bit +SOpcodeDef OpcodeMapF1[] = { + {"kunpckwd", 0x20 ,0x1E3200, 0x19 , 0x1095, 0x1095, 0x1095, 0 , 0 , 0 , 0 , 0 }, // VEX 0F 4B + {"kunpckdq", 0x20 ,0x1E3200, 0x19 , 0x1095, 0x1095, 0x1095, 0 , 0 , 0 , 0 , 0 }}; + +// Map for 0F AE /7. Indexed by 66 prefix +SOpcodeDef OpcodeMapF2[] = { + {"clflush", 0x12 , 0 , 0x11 , 0x2006, 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F AE /7 + {"clflushopt",0x22 , 0x200 , 0x11 , 0x2006, 0 , 0 , 0 , 0 , 0 , 0 , 0 }}; // 66 0F AE /7 + +// Map for 0F AE /6. Indexed by 66 prefix +SOpcodeDef OpcodeMapF3[] = { + {"xsaveopt", 0x19 , 0x2000 , 0x11 , 0x2006, 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F AE /6 + {"clwb ", 0x22 , 0x200 , 0x11 , 0x2006, 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 66 0F AE /6 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // F2 0F AE /6 + {"clrssbsy", 0 , 0x400 , 0x11 , 0 , 0x2004, 0 , 0 , 0 , 0 , 0 , 0 }}; // F3 0F AE /6 + +// Map for 0F AE reg /7. Indexed by 66 prefix +SOpcodeDef OpcodeMapF4[] = { + {"sfence", 0x12 , 0 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // m-7 + {"pcommit", 0x22 , 0x200 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }}; + +// Opcode map for floating point cmpps/pd instructions. First two bytes = 0F C2 +// Indexed by VEX prefix type +SOpcodeDef OpcodeMapF5[] = { + {0, 0xF6 , 0 , 0x52 , 0 , 0 , 0 , 0 , 0 , 0 , 0x6 , 0 }, // 0F C2. Link to cmpps etc. + {0, 0xF6 , 0 , 0x52 , 0 , 0 , 0 , 0 , 0 , 0 , 0x6 , 0 }, // VEX 0F C2. Link to cmpps etc. + {0, 0xF7 , 0 , 0x52 , 0 , 0 , 0 , 0 , 0 , 0 , 0x6 , 0 }, // EVEX 0F C2. Link to cmpps etc. + {0, 0xF7 , 0 , 0x52 , 0 , 0 , 0 , 0 , 0 , 0 , 0x6 , 0 }}; // MVEX 0F C2. Link to cmpps etc. + +SOpcodeDef OpcodeMapF6[] = { +// Opcode map for floating point cmpps/pd instructions. First two bytes = 0F C2 +// Indexed by immediate byte following operands = 0 - 7 +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"cmpeq", 0x12 ,0xCD2E00, 0x59 , 0x124F, 0x24F , 0x24F , 0 , 0x13 , 0x1204, 0 , 0x3 }, // 0F C2 op 00: cmpeqps/pd + {"cmplt", 0x12 ,0xCD2E00, 0x59 , 0x124F, 0x24F , 0x24F , 0 , 0x13 , 0x1204, 0 , 0x3 }, // 0F C2 op 01: + {"cmple", 0x12 ,0xCD2E00, 0x59 , 0x124F, 0x24F , 0x24F , 0 , 0x13 , 0x1204, 0 , 0x3 }, // 0F C2 op 02: + {"cmpunord", 0x12 ,0xCD2E00, 0x59 , 0x124F, 0x24F , 0x24F , 0 , 0x13 , 0x1204, 0 , 0x3 }, // 0F C2 op 03: + {"cmpneq", 0x12 ,0xCD2E00, 0x59 , 0x124F, 0x24F , 0x24F , 0 , 0x13 , 0x1204, 0 , 0x3 }, // 0F C2 op 04: + {"cmpnlt", 0x12 ,0xCD2E00, 0x59 , 0x124F, 0x24F , 0x24F , 0 , 0x13 , 0x1204, 0 , 0x3 }, // 0F C2 op 05: + {"cmpnle", 0x12 ,0xCD2E00, 0x59 , 0x124F, 0x24F , 0x24F , 0 , 0x13 , 0x1204, 0 , 0x3 }, // 0F C2 op 06: + {"cmpord", 0x12 ,0xCD2E00, 0x59 , 0x124F, 0x24F , 0x24F , 0 , 0x13 , 0x1204, 0 , 0x3 }, // 0F C2 op 07: +// imm > 7 only with VEX + {"vcmpeq_uq", 0x19 ,0x8E2E00, 0x59 , 0x124F, 0x24F , 0x24F , 0 , 0x13 , 0 , 0 , 0x1 }, // 0F C2 op 08: + {"vcmpnge_us",0x19 ,0x8E2E00, 0x59 , 0x124F, 0x24F , 0x24F , 0 , 0x13 , 0 , 0 , 0x1 }, // 0F C2 op 09: + {"vcmpngt_us",0x19 ,0x8E2E00, 0x59 , 0x124F, 0x24F , 0x24F , 0 , 0x13 , 0 , 0 , 0x1 }, // 0F C2 op 0A: + {"vcmpfalse_oq",0x19,0x8E2E00, 0x59 , 0x124F, 0x24F , 0x24F , 0 , 0x13 , 0 , 0 , 0x1 }, // 0F C2 op 0B: + {"vcmpneq_oq",0x19 ,0x8E2E00, 0x59 , 0x124F, 0x24F , 0x24F , 0 , 0x13 , 0 , 0 , 0x1 }, // 0F C2 op 0C: + {"vcmpge_os", 0x19 ,0x8E2E00, 0x59 , 0x124F, 0x24F , 0x24F , 0 , 0x13 , 0 , 0 , 0x1 }, // 0F C2 op 0D: + {"vcmpgt_os", 0x19 ,0x8E2E00, 0x59 , 0x124F, 0x24F , 0x24F , 0 , 0x13 , 0 , 0 , 0x1 }, // 0F C2 op 0E: + {"vcmptrue_uq",0x19 ,0x8E2E00, 0x59 , 0x124F, 0x24F , 0x24F , 0 , 0x13 , 0 , 0 , 0x1 }, // 0F C2 op 0F: + {"vcmpeq_os", 0x19 ,0x8E2E00, 0x59 , 0x124F, 0x24F , 0x24F , 0 , 0x13 , 0 , 0 , 0x1 }, // 0F C2 op 10: + {"vcmplt_oq", 0x19 ,0x8E2E00, 0x59 , 0x124F, 0x24F , 0x24F , 0 , 0x13 , 0 , 0 , 0x1 }, // 0F C2 op 11: + {"vcmple_oq", 0x19 ,0x8E2E00, 0x59 , 0x124F, 0x24F , 0x24F , 0 , 0x13 , 0 , 0 , 0x1 }, // 0F C2 op 12: + {"vcmpunord_s",0x19 ,0x8E2E00, 0x59 , 0x124F, 0x24F , 0x24F , 0 , 0x13 , 0 , 0 , 0x1 }, // 0F C2 op 13: + {"vcmpneq_us",0x19 ,0x8E2E00, 0x59 , 0x124F, 0x24F , 0x24F , 0 , 0x13 , 0 , 0 , 0x1 }, // 0F C2 op 14: + {"vcmpnlt_uq",0x19 ,0x8E2E00, 0x59 , 0x124F, 0x24F , 0x24F , 0 , 0x13 , 0 , 0 , 0x1 }, // 0F C2 op 15: + {"vcmpnle_uq",0x19 ,0x8E2E00, 0x59 , 0x124F, 0x24F , 0x24F , 0 , 0x13 , 0 , 0 , 0x1 }, // 0F C2 op 16: + {"vcmpord_s", 0x19 ,0x8E2E00, 0x59 , 0x124F, 0x24F , 0x24F , 0 , 0x13 , 0 , 0 , 0x1 }, // 0F C2 op 17: + {"vcmpeq_us", 0x19 ,0x8E2E00, 0x59 , 0x124F, 0x24F , 0x24F , 0 , 0x13 , 0 , 0 , 0x1 }, // 0F C2 op 18: + {"vcmpnge_uq",0x19 ,0x8E2E00, 0x59 , 0x124F, 0x24F , 0x24F , 0 , 0x13 , 0 , 0 , 0x1 }, // 0F C2 op 19: + {"vcmpngt_uq",0x19 ,0x8E2E00, 0x59 , 0x124F, 0x24F , 0x24F , 0 , 0x13 , 0 , 0 , 0x1 }, // 0F C2 op 1A: + {"vcmpfalse_os",0x19,0x8E2E00, 0x59 , 0x124F, 0x24F , 0x24F , 0 , 0x13 , 0 , 0 , 0x1 }, // 0F C2 op 1B: + {"vcmpneq_os",0x19 ,0x8E2E00, 0x59 , 0x124F, 0x24F , 0x24F , 0 , 0x13 , 0 , 0 , 0x1 }, // 0F C2 op 1C: + {"vcmpge_oq", 0x19 ,0x8E2E00, 0x59 , 0x124F, 0x24F , 0x24F , 0 , 0x13 , 0 , 0 , 0x1 }, // 0F C2 op 1D: + {"vcmpgt_oq", 0x19 ,0x8E2E00, 0x59 , 0x124F, 0x24F , 0x24F , 0 , 0x13 , 0 , 0 , 0x1 }, // 0F C2 op 1E: + {"vcmptrue_us",0x19 ,0x8E2E00, 0x59 , 0x124F, 0x24F , 0x24F , 0 , 0x13 , 0 , 0 , 0x1 }, // 0F C2 op 1F: + {"vcmp", 0x19 ,0x8E2200, 0x4059, 0x124F, 0x24F , 0x24F , 0x31 , 0x13 , 0 , 0 , 0x3 }}; // 0F C2 op > 1F: cmpps/pd, imm + + +SOpcodeDef OpcodeMapF7[] = { +// Opcode map for floating point cmpps/pd instructions. EVEX 0F C2 +// Indexed by immediate byte following operands = 0 - 7 +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"cmpeq", 0x12 ,0xCD2E00, 0x59 , 0x95, 0x24F , 0x24F , 0 , 0x13 , 0x1204, 0 , 0x3 }, // 0F C2 op 00: cmpeqps/pd + {"cmplt", 0x12 ,0xCD2E00, 0x59 , 0x95, 0x24F , 0x24F , 0 , 0x13 , 0x1204, 0 , 0x3 }, // 0F C2 op 01: + {"cmple", 0x12 ,0xCD2E00, 0x59 , 0x95, 0x24F , 0x24F , 0 , 0x13 , 0x1204, 0 , 0x3 }, // 0F C2 op 02: + {"cmpunord", 0x12 ,0xCD2E00, 0x59 , 0x95, 0x24F , 0x24F , 0 , 0x13 , 0x1204, 0 , 0x3 }, // 0F C2 op 03: + {"cmpneq", 0x12 ,0xCD2E00, 0x59 , 0x95, 0x24F , 0x24F , 0 , 0x13 , 0x1204, 0 , 0x3 }, // 0F C2 op 04: + {"cmpnlt", 0x12 ,0xCD2E00, 0x59 , 0x95, 0x24F , 0x24F , 0 , 0x13 , 0x1204, 0 , 0x3 }, // 0F C2 op 05: + {"cmpnle", 0x12 ,0xCD2E00, 0x59 , 0x95, 0x24F , 0x24F , 0 , 0x13 , 0x1204, 0 , 0x3 }, // 0F C2 op 06: + {"cmpord", 0x12 ,0xCD2E00, 0x59 , 0x95, 0x24F , 0x24F , 0 , 0x13 , 0x1204, 0 , 0x3 }, // 0F C2 op 07: +// imm > 7 only with EVEX prefix, not with MVEX + {"vcmpeq_uq", 0x19 ,0x8E2E00, 0x59 , 0x95, 0x24F , 0x24F , 0 , 0x13 , 0 , 0 , 0x1 }, // 0F C2 op 08: + {"vcmpnge_us",0x19 ,0x8E2E00, 0x59 , 0x95, 0x24F , 0x24F , 0 , 0x13 , 0 , 0 , 0x1 }, // 0F C2 op 09: + {"vcmpngt_us",0x19 ,0x8E2E00, 0x59 , 0x95, 0x24F , 0x24F , 0 , 0x13 , 0 , 0 , 0x1 }, // 0F C2 op 0A: + {"vcmpfalse_oq",0x19,0x8E2E00, 0x59 , 0x95, 0x24F , 0x24F , 0 , 0x13 , 0 , 0 , 0x1 }, // 0F C2 op 0B: + {"vcmpneq_oq",0x19 ,0x8E2E00, 0x59 , 0x95, 0x24F , 0x24F , 0 , 0x13 , 0 , 0 , 0x1 }, // 0F C2 op 0C: + {"vcmpge_os", 0x19 ,0x8E2E00, 0x59 , 0x95, 0x24F , 0x24F , 0 , 0x13 , 0 , 0 , 0x1 }, // 0F C2 op 0D: + {"vcmpgt_os", 0x19 ,0x8E2E00, 0x59 , 0x95, 0x24F , 0x24F , 0 , 0x13 , 0 , 0 , 0x1 }, // 0F C2 op 0E: + {"vcmptrue_uq",0x19 ,0x8E2E00, 0x59 , 0x95, 0x24F , 0x24F , 0 , 0x13 , 0 , 0 , 0x1 }, // 0F C2 op 0F: + {"vcmpeq_os", 0x19 ,0x8E2E00, 0x59 , 0x95, 0x24F , 0x24F , 0 , 0x13 , 0 , 0 , 0x1 }, // 0F C2 op 10: + {"vcmplt_oq", 0x19 ,0x8E2E00, 0x59 , 0x95, 0x24F , 0x24F , 0 , 0x13 , 0 , 0 , 0x1 }, // 0F C2 op 11: + {"vcmple_oq", 0x19 ,0x8E2E00, 0x59 , 0x95, 0x24F , 0x24F , 0 , 0x13 , 0 , 0 , 0x1 }, // 0F C2 op 12: + {"vcmpunord_s",0x19 ,0x8E2E00, 0x59 , 0x95, 0x24F , 0x24F , 0 , 0x13 , 0 , 0 , 0x1 }, // 0F C2 op 13: + {"vcmpneq_us",0x19 ,0x8E2E00, 0x59 , 0x95, 0x24F , 0x24F , 0 , 0x13 , 0 , 0 , 0x1 }, // 0F C2 op 14: + {"vcmpnlt_uq",0x19 ,0x8E2E00, 0x59 , 0x95, 0x24F , 0x24F , 0 , 0x13 , 0 , 0 , 0x1 }, // 0F C2 op 15: + {"vcmpnle_uq",0x19 ,0x8E2E00, 0x59 , 0x95, 0x24F , 0x24F , 0 , 0x13 , 0 , 0 , 0x1 }, // 0F C2 op 16: + {"vcmpord_s", 0x19 ,0x8E2E00, 0x59 , 0x95, 0x24F , 0x24F , 0 , 0x13 , 0 , 0 , 0x1 }, // 0F C2 op 17: + {"vcmpeq_us", 0x19 ,0x8E2E00, 0x59 , 0x95, 0x24F , 0x24F , 0 , 0x13 , 0 , 0 , 0x1 }, // 0F C2 op 18: + {"vcmpnge_uq",0x19 ,0x8E2E00, 0x59 , 0x95, 0x24F , 0x24F , 0 , 0x13 , 0 , 0 , 0x1 }, // 0F C2 op 19: + {"vcmpngt_uq",0x19 ,0x8E2E00, 0x59 , 0x95, 0x24F , 0x24F , 0 , 0x13 , 0 , 0 , 0x1 }, // 0F C2 op 1A: + {"vcmpfalse_os",0x19,0x8E2E00, 0x59 , 0x95, 0x24F , 0x24F , 0 , 0x13 , 0 , 0 , 0x1 }, // 0F C2 op 1B: + {"vcmpneq_os",0x19 ,0x8E2E00, 0x59 , 0x95, 0x24F , 0x24F , 0 , 0x13 , 0 , 0 , 0x1 }, // 0F C2 op 1C: + {"vcmpge_oq", 0x19 ,0x8E2E00, 0x59 , 0x95, 0x24F , 0x24F , 0 , 0x13 , 0 , 0 , 0x1 }, // 0F C2 op 1D: + {"vcmpgt_oq", 0x19 ,0x8E2E00, 0x59 , 0x95, 0x24F , 0x24F , 0 , 0x13 , 0 , 0 , 0x1 }, // 0F C2 op 1E: + {"vcmptrue_us",0x19 ,0x8E2E00, 0x59 , 0x95, 0x24F , 0x24F , 0 , 0x13 , 0 , 0 , 0x1 }, // 0F C2 op 1F: + {"vcmp", 0x19 ,0x8E2200, 0x4059, 0x95, 0x24F , 0x24F , 0x31 , 0x13 , 0 , 0 , 0x3 }}; // 0F C2 op > 1F: cmpps/pd, imm + +// Submap for 0F 38 1A / W0, indexed by EVEX +SOpcodeDef OpcodeMapF8[] = { + {"vbroadcastf128" ,0x19,0x878200,0x12, 0x154B, 0x244B, 0 , 0 , 0x20 , 0 , 0 , 0 }, // VEX 0F 38 1A + {"vbroadcastf32x4",0x10,0xC6B200,0x12, 0x124B, 0x244B, 0 , 0 , 0x20 , 0x1010, 0 , 0x100 }}; // EVEX 0F 38 1A + +// Map for 0F 3A 08. Indexed by EVEX present +SOpcodeDef OpcodeMapF9[] = { + {"roundps", 0x15 , 0x58200, 0x52 , 0x124B, 0x24B , 0x31 , 0 , 0 , 0 , 0 , 0x2 }, // 0F 3A 08. Also in AMD instruction set + {"vrndscaleps",0x20 ,0x858200, 0x52 , 0x124B, 0x24B , 0x31 , 0 , 0x33 , 0 , 0 , 0 }}; // EVEX 0F 3A 08 + +// Map for 0F 3A 09. Indexed by EVEX present +SOpcodeDef OpcodeMapFA[] = { + {"roundpd", 0x15 ,0x858200, 0x52 , 0x124C, 0x24C , 0x31 , 0 , 0 , 0 , 0 , 0x2 }, // 0F 3A 09. Also in AMD instruction set + {"vrndscalepd",0x20 ,0x85A200, 0x52 , 0x124C, 0x24C , 0x31 , 0 , 0x33 , 0 , 0 , 0 }}; // EVEX 0F 3A 09 + +// Map for 0F 3A 0A. Indexed by EVEX present +SOpcodeDef OpcodeMapFB[] = { + {"roundss", 0x15 , 0x98200, 0x59 , 0x104B, 0x104B, 0x4B , 0x31 , 0 , 0 , 0 , 0x2 }, // 0F 3A 0A. Also in AMD instruction set + {"vrndscaless",0x20 ,0x8DB200, 0x59 , 0x104B, 0x004B, 0x4B , 0x31 , 0x32 , 0 , 0 , 0 }}; // EVEX 0F 3A 08 + +// Map for 0F 3A 0B. Indexed by EVEX present +SOpcodeDef OpcodeMapFC[] = { + {"roundsd", 0x15 , 0x98200, 0x59 , 0x104C, 0x104C, 0x4C , 0x31 , 0 , 0 , 0 , 0x2 }, // 0F 3A 0B. Also in AMD instruction set + {"vrndscalesd",0x20 ,0x8DB200, 0x59 , 0x104C, 0x004C, 0x4C , 0x31 , 0x32 , 0 , 0 , 0 }}; // EVEX 0F 3A 08 + +// Map for 0F 38 2C. Indexed by EVEX present +SOpcodeDef OpcodeMapFD[] = { + {"vmaskmovps",0x19 , 0xF8200, 0x19, 0x124B, 0x124B, 0x224B, 0 , 0 , 0 , 0 , 0 }, // 0F 38 2C + {"vscalefp" ,0x20 ,0x899200, 0x19, 0x124F, 0x124F, 0x024F, 0 , 0x37 , 0 , 0 , 0x1 }}; // EVEX 0F 38 2C + +// Map for 0F 38 2D. Indexed by EVEX present +SOpcodeDef OpcodeMapFE[] = { + {"vmaskmovpd",0x19 , 0xF8200, 0x19, 0x124C, 0x124C, 0x224C, 0 , 0 , 0 , 0 , 0 }, // 0F 38 2D + {"vscalefs" ,0x20 ,0x899200, 0x19, 0x144F, 0x144F, 0x044F, 0 , 0x36 , 0 , 0 , 0x1 }}; // EVEX 0F 38 2D + +// Map for 0F 38 3A. Indexed by 66 F2 F3 prefixes +SOpcodeDef OpcodeMapFF[] = { + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 3A + {"pminuw", 0x15 ,0x8D8200, 0x19 , 0x1202, 0x1202, 0x202 , 0 , 0x20 , 0 , 0 , 0x2 }, // 66 0F 38 3A + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // F2 0F 38 3A + {"vpbroadcastmw2d",0x20,0x860400,0x12, 0x1203, 0x1095, 0 , 0 , 0 , 0 , 0 , 0 }}; // F3 0F 38 2A + +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options +// Map for 0F 38 A". Indexed by W bit +SOpcodeDef OpcodeMap100[] = { + {"vscatterdps",0x20 ,0xC39200, 0x1E , 0x224B, 0x1209, 0 , 0 , 0x1090, 0x304C, 0 , 0x000 }, // 0F 38 A2. W0 + {"vscatterdpd",0x20 ,0xC39200, 0x1E , 0x2F4C, 0x1209, 0 , 0 , 0x1090, 0x304C, 0 , 0x000 }}; // 0F 38 A2. W1 + +// Map for 0F 38 A3. Indexed by W bit +SOpcodeDef OpcodeMap101[] = { + {"vscatterqps",0x20 ,0xC39200, 0x1E , 0x224B, 0x1F09, 0 , 0 , 0x1090, 0x304C, 0 , 0x000 }, // 0F 38 A3. W0 + {"vscatterqpd",0x20 ,0xC39200, 0x1E , 0x224C, 0x1209, 0 , 0 , 0x1090, 0x304C, 0 , 0x000 }}; // 0F 38 A3. W1 + + +// Submap for vpgatherd. Opcode byte = 0F 38 90 +// Indexed by VEX/EVEX prefix +SOpcodeDef OpcodeMap102[] = { + {0, 0x103 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0xC , 0 }, // + {0, 0x104 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0xC , 0 }}; // + +// Submap for vpgatherd. Opcode byte = 0F 38 90 +// Indexed by VEX.W bit +SOpcodeDef OpcodeMap103[] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"vpgatherdd",0x1C ,0xCEB200, 0x1E, 0x203 , 0x2203, 0x203 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 90 + {"vpgatherdq",0x1C ,0xCEB200, 0x1E, 0x204 , 0x2F04, 0x204 , 0 , 0 , 0x100A, 0 , 0 }}; // 0F 38 90 + +// Submap for vpgatherd. Opcode byte = 0F 38 90 +// Indexed by EVEX.W bit +SOpcodeDef OpcodeMap104[] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"vpgatherdd",0x1C ,0xCEB200, 0x1E, 0x203 , 0x2203, 0 , 0 , 0x1090, 0x100A, 0 , 0 }, // EVEX 0F 38 90 + {"vpgatherdq",0x1C ,0xCEB200, 0x1E, 0x204 , 0x2F04, 0 , 0 , 0x1090, 0x100A, 0 , 0 }}; // EVEX 0F 38 90 + +// Submap for vpgatherq, Opcode 0F 38 91, Indexed by VEX.W bit +SOpcodeDef OpcodeMap105[] = { + {"vpgatherqd",0x1C ,0x8EB200, 0x1E, 0xF03 , 0x2203, 0xF03 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 91, W0 + {"vpgatherqq",0x1C ,0x8EB200, 0x1E, 0x204 , 0x2204, 0x204 , 0 , 0 , 0 , 0 , 0 }}; // 0F 38 91, W1 + +// Submap for vpgatherq, Opcode 0F 38 91, Indexed by EVEX.W bit +SOpcodeDef OpcodeMap106[] = { + {"vpgatherqd",0x1C ,0x8EB200, 0x1E, 0xF03 , 0x2203, 0 , 0 , 0x1090, 0 , 0 , 0 }, // EVEX 0F 38 91, W0 + {"vpgatherqq",0x1C ,0x8EB200, 0x1E, 0x204 , 0x2204, 0 , 0 , 0x1090, 0 , 0 , 0 }}; // EVEX 0F 38 91, W1 + +// Map for 0F 38 C8. Indexed by VEX prefix type +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options +SOpcodeDef OpcodeMap107[] = { + {"sha1nexte", 0x22 , 0 , 0x12 , 0x1203, 0x0203, 0 , 0 , 0 , 0 , 0 , 0 }, // no VEX + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX + {"vexp2p", 0x21 ,0x809200, 0x12 , 0x124F, 0x024F, 0 , 0 , 0x33 , 0 , 0 , 0x1 }, // EVEX 0F 38 C8 + {"vexp223ps", 0x80 ,0x428200, 0x12 , 0x164B, 0x603 , 0 , 0 , 0 , 0x1201, 0 , 0x100 }}; // MVEX 0F 38 C8 + +// Map for 0F 38 C9. Indexed by VEX prefix type +SOpcodeDef OpcodeMap108[] = { + {"sha1msg1", 0x22 , 0 , 0x12 , 0x1203, 0x0203, 0 , 0 , 0 , 0 , 0 , 0 }, // no VEX + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX 0F 38 C9 + {"vlog2ps", 0x80 ,0x428200, 0x12 , 0x164B, 0x603 , 0 , 0 , 0 , 0x1201, 0 , 0x100 }}; // MVEX 0F 38 C9 + +// Map for 0F 38 CA. Indexed by VEX prefix type +SOpcodeDef OpcodeMap109[] = { + {"sha1msg2", 0x22 , 0 , 0x12 , 0x1203, 0x0203, 0 , 0 , 0 , 0 , 0 , 0 }, // no VEX + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX + {"vrcp28p", 0x21 ,0x809200, 0x12 , 0x124F, 0x024F, 0 , 0 , 0x33 , 0 , 0 , 0x1 }, // EVEX 0F 38 CA + {"vrcp23ps", 0x80 ,0x428200, 0x12 , 0x164B, 0x603 , 0 , 0 , 0 , 0x1201, 0 , 0x100 }}; // MVEX 0F 38 CA + +// Map for 0F 38 CB. Indexed by VEX prefix type +SOpcodeDef OpcodeMap10A[] = { + {"sha256rnds2",0x22 , 0 , 0x12 , 0x1203, 0x0203, 0xAE , 0 , 0 , 0 , 0 , 0 }, // no VEX + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX + {"vrcp28s", 0x21 ,0x809200, 0x12 , 0x104F, 0x004F, 0 , 0 , 0x32 , 0 , 0 , 0x1 }, // EVEX 0F 38 CB + {"vrsqrt23ps",0x80 ,0x428200, 0x12 , 0x164B, 0x603 , 0 , 0 , 0 , 0x1201, 0 , 0x100 }}; // MVEX 0F 38 CB + +// Map for 0F 38 CC. Indexed by VEX prefix type +SOpcodeDef OpcodeMap10B[] = { + {"sha256msg1",0x22 , 0 , 0x12 , 0x1203, 0x0203, 0 , 0 , 0 , 0 , 0 , 0 }, // no VEX + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX + {"vrsqrt28p", 0x21 ,0x809200, 0x12 , 0x124F, 0x024F, 0 , 0 , 0x33 , 0 , 0 , 0x1 }, // EVEX 0F 38 CC + {"vaddsetsps",0x80 ,0x4A8200, 0x19, 0x164B, 0x164B, 0x64B , 0 , 0 , 0x3304, 0 , 0x100 }}; // MVEX 0F 38 CC + +// Map for 0F 38 CD. Indexed by VEX prefix type +SOpcodeDef OpcodeMap10C[] = { + {"sha256msg2",0x22 , 0 , 0x12 , 0x1203, 0x0203, 0 , 0 , 0 , 0 , 0 , 0 }, // no VEX + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX + {"vrsqrt28s", 0x21 ,0x809200, 0x12 , 0x104F, 0x004F, 0 , 0 , 0x32 , 0 , 0 , 0x1 }, // EVEX 0F 38 CD + {"vpaddsetsd",0x80 ,0x4A8200, 0x19 , 0x1603, 0x1603, 0x603 , 0 , 0 , 0x3406, 0 , 0x100 }}; // MVEX 0F 38 CD + +// Submap for MVEX 0F 38 C6. W0 +// Indexed by reg bits +SOpcodeDef OpcodeMap10D[] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options +{"vgatherpf0hintdp",0x80,0x439200, 0x1E, 0 , 0x264B, 0 , 0 , 0 , 0x1048, 0 , 0x101 }, // MVEX 0F 38 C6 /0 +{"vgatherpf0dps",0x21,0xC38200, 0x1E, 0 , 0x224B, 0 , 0 , 0x1010, 0x1048, 0 , 0x000 }, // MVEX 0F 38 C6 /1 +{"vgatherpf1dps",0x21,0xC38200, 0x1E, 0 , 0x224B, 0 , 0 , 0x1010, 0x1048, 0 , 0x000 }, // MVEX 0F 38 C6 /2 + {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // +{"vscatterpf0hintdp",0x80,0x43B200,0x1E, 0 , 0x264B, 0 , 0 , 0 , 0x1048, 0 , 0x101 }, // MVEX 0F 38 C6 /4 +{"vscatterpf0dps",0x21,0xC38200, 0x1E, 0 , 0x224B, 0 , 0 , 0x1010, 0x1048, 0 , 0x000 }, // MVEX 0F 38 C6 /5 +{"vscatterpf1dps",0x21,0xC38200, 0x1E, 0 , 0x224B, 0 , 0 , 0x1010, 0x1048, 0 , 0x000 }, // MVEX 0F 38 C6 /6 + {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }}; // + +// Submap for MVEX 0F 38 C6. W1 +// Indexed by reg bits +SOpcodeDef OpcodeMap10E[] = { +{"vgatherpf0hintdpd",0x80,0x439200,0x1E, 0 , 0x264C, 0 , 0 , 0 , 0x1048, 0 , 0x100 }, // MVEX 0F 38 C6 /0 +{"vgatherpf0dpd",0x21,0xC3A200, 0x1E, 0 , 0x2F4C, 0 , 0 , 0x1010, 0x1048, 0 , 0x000 }, // MVEX 0F 38 C6 /1 +{"vgatherpf1dpd",0x21,0xC3A200, 0x1E, 0 , 0x2F4C, 0 , 0 , 0x1010, 0x1048, 0 , 0x000 }, // MVEX 0F 38 C6 /2 + {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // +{"vscatterpf0hintdp",0x80,0x43B200,0x1E, 0 , 0x264c, 0 , 0 , 0 , 0x1048, 0 , 0x101 }, // MVEX 0F 38 C6 /4 +{"vscatterpf0dpd",0x21,0xC3A200, 0x1E, 0 , 0x2F4C, 0 , 0 , 0x1010, 0x1048, 0 , 0x000 }, // MVEX 0F 38 C6 /5 +{"vscatterpf1dpd",0x21,0xC3A200, 0x1E, 0 , 0x2F4C, 0 , 0 , 0x1010, 0x1048, 0 , 0x100 }, // MVEX 0F 38 C6 /6 + {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }}; // + +// Submap for 0F 38 C7 vgatherpf.. Indexed by reg bits +SOpcodeDef OpcodeMap10F[] = { + {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // +{"vgatherpf0qp", 0x21 ,0xC39200, 0x1E, 0 , 0x224F, 0 , 0 , 0x1010, 0 , 0 , 0x1 }, // 0F 38 C7 /1 +{"vgatherpf1qp", 0x21 ,0xC39200, 0x1E, 0 , 0x224F, 0 , 0 , 0x1010, 0 , 0 , 0x1 }, // 0F 38 C7 /2 + {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // + {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // +{"vscatterpf0qp",0x21 ,0xC39200, 0x1E, 0 , 0x224F, 0 , 0 , 0x1010, 0 , 0 , 0x1 }, // 0F 38 C7 /5 +{"vscatterpf1qp",0x21 ,0xC39200, 0x1E, 0 , 0x224F, 0 , 0 , 0x1010, 0 , 0 , 0x1 }, // 0F 38 C7 /6 + {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }}; // + +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options +// Submap for 0F 1A. Indexed by 66 F2 F3 prefix +SOpcodeDef OpcodeMap110[] = { + {"bndldx", 0x22 , 0 , 0x12, 0x98 , 0x2006, 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 1A + {"bndmov", 0x22 , 0x200 , 0x12, 0x1098, 0x98 , 0 , 0 , 0 , 0 , 0 , 0 }, // 66 0F 1A + {"bndcu" , 0x22 , 0x800 , 0x12, 0x98 , 0x2006, 0 , 0 , 0 , 0 , 0 , 0 }, // F2 0F 1A + {"bndcl" , 0x22 , 0x400 , 0x12, 0x98 , 0x2006, 0 , 0 , 0 , 0 , 0 , 0 }}; // F3 0F 1A + +// Submap for 0F 1B. Indexed by 66 F2 F3 prefix +SOpcodeDef OpcodeMap111[] = { + {"bndstx", 0x22 , 0 , 0x13, 0x2006, 0x98 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 1B + {"bndmov", 0x22 , 0x200 , 0x13, 0x98 , 0x1098, 0 , 0 , 0 , 0 , 0 , 0 }, // 66 0F 1B + {"bndcn" , 0x22 , 0x800 , 0x12, 0x98 , 0x2006, 0 , 0 , 0 , 0 , 0 , 0 }, // F2 0F 1B + {"bndmk" , 0x22 , 0x400 , 0x12, 0x98 , 0x2006, 0 , 0 , 0 , 0 , 0 , 0 }}; // F3 0F 1B + +// Submap for 0F 3A 3E. Indexed by immediate byte. VCMPUB/W +SOpcodeDef OpcodeMap112[] = { + {"vpcmpequ", 0x20 , 0x8FC200,0x59 , 0x95 , 0x1209, 0x209 , 0 , 0x10 , 0 , 0 , 0x01 }, // 0F 3A 3E / 0 + {"vpcmpltu", 0x20 , 0x8FC200,0x59 , 0x95 , 0x1209, 0x209 , 0 , 0x10 , 0 , 0 , 0x01 }, // 0F 3A 3E / 1 + {"vpcmpleu", 0x20 , 0x8FC200,0x59 , 0x95 , 0x1209, 0x209 , 0 , 0x10 , 0 , 0 , 0x01 }, // 0F 3A 3E / 2 + {"vpcmpu", 0x20 , 0x8FC200,0x59 , 0x95 , 0x1209, 0x209 , 0x31 , 0x10 , 0 , 0 , 0x01 }, // 0F 3A 3E / 3 = true + {"vpcmpnequ", 0x20 , 0x8FC200,0x59 , 0x95 , 0x1209, 0x209 , 0 , 0x10 , 0 , 0 , 0x01 }, // 0F 3A 3E / 4 + {"vpcmpnltu", 0x20 , 0x8FC200,0x59 , 0x95 , 0x1209, 0x209 , 0 , 0x10 , 0 , 0 , 0x01 }, // 0F 3A 3E / 5 + {"vpcmpnleu", 0x20 , 0x8FC200,0x59 , 0x95 , 0x1209, 0x209 , 0 , 0x10 , 0 , 0 , 0x01 }, // 0F 3A 3E / 6 + {"vpcmpu", 0x20 , 0x8FC200,0x59 , 0x95 , 0x1209, 0x209 , 0x31 , 0x10 , 0 , 0 , 0x01 }}; // 0F 3A 3E / >= 7 = false + +// Submap for 0F 3A 3F. Indexed by immediate byte. VCMPB/W +SOpcodeDef OpcodeMap113[] = { + {"vpcmpeq", 0x20 , 0x8FC200,0x59 , 0x95 , 0x1209, 0x209 , 0 , 0x10 , 0 , 0 , 0x01 }, // 0F 3A 3F / 0 + {"vpcmplt", 0x20 , 0x8FC200,0x59 , 0x95 , 0x1209, 0x209 , 0 , 0x10 , 0 , 0 , 0x01 }, // 0F 3A 3F / 1 + {"vpcmple", 0x20 , 0x8FC200,0x59 , 0x95 , 0x1209, 0x209 , 0 , 0x10 , 0 , 0 , 0x01 }, // 0F 3A 3F / 2 + {"vpcmp", 0x20 , 0x8FC200,0x59 , 0x95 , 0x1209, 0x209 , 0x31 , 0x10 , 0 , 0 , 0x01 }, // 0F 3A 3F / 3 = true + {"vpcmpneq", 0x20 , 0x8FC200,0x59 , 0x95 , 0x1209, 0x209 , 0 , 0x10 , 0 , 0 , 0x01 }, // 0F 3A 3F / 4 + {"vpcmpnlt", 0x20 , 0x8FC200,0x59 , 0x95 , 0x1209, 0x209 , 0 , 0x10 , 0 , 0 , 0x01 }, // 0F 3A 3F / 5 + {"vpcmpnle", 0x20 , 0x8FC200,0x59 , 0x95 , 0x1209, 0x209 , 0 , 0x10 , 0 , 0 , 0x01 }, // 0F 3A 3F / 6 + {"vpcmp", 0x20 , 0x8FC200,0x59 , 0x95 , 0x1209, 0x209 , 0x31 , 0x10 , 0 , 0 , 0x01 }}; // 0F 3A 3F / >= 7 = false + +// Submap for 0F 3A 1E. Indexed by immediate byte. VCMPUD/Q +SOpcodeDef OpcodeMap114[] = { + {"vpcmpequ", 0x20 , 0xCBB200,0x59 , 0x95 , 0x1209, 0x209 , 0 , 0x11 , 0x1406, 0 , 0x01 }, // 0F 3A 1E / 0 + {"vpcmpltu", 0x20 , 0xCBB200,0x59 , 0x95 , 0x1209, 0x209 , 0 , 0x11 , 0x1406, 0 , 0x01 }, // 0F 3A 1E / 1 + {"vpcmpleu", 0x20 , 0xCBB200,0x59 , 0x95 , 0x1209, 0x209 , 0 , 0x11 , 0x1406, 0 , 0x01 }, // 0F 3A 1E / 2 + {"vpcmpu", 0x20 , 0xCBB200,0x59 , 0x95 , 0x1209, 0x209 , 0x31 , 0x11 , 0x1406, 0 , 0x01 }, // 0F 3A 1E / 3 = true + {"vpcmpnequ", 0x20 , 0xCBB200,0x59 , 0x95 , 0x1209, 0x209 , 0 , 0x11 , 0x1406, 0 , 0x01 }, // 0F 3A 1E / 4 + {"vpcmpnltu", 0x20 , 0xCBB200,0x59 , 0x95 , 0x1209, 0x209 , 0 , 0x11 , 0x1406, 0 , 0x01 }, // 0F 3A 1E / 5 + {"vpcmpnleu", 0x20 , 0xCBB200,0x59 , 0x95 , 0x1209, 0x209 , 0 , 0x11 , 0x1406, 0 , 0x01 }, // 0F 3A 1E / 6 + {"vpcmpu", 0x20 , 0xCBB200,0x59 , 0x95 , 0x1209, 0x209 , 0x31 , 0x11 , 0x1406, 0 , 0x01 }}; // 0F 3A 1E / >= 7 = false + +// Submap for 0F 3A 1F. Indexed by immediate byte. VCMPD/Q +SOpcodeDef OpcodeMap115[] = { + {"vpcmpeq", 0x20 , 0xCBB200,0x59 , 0x95 , 0x1209, 0x209 , 0 , 0x11 , 0x1406, 0 , 0x01 }, // 0F 3A 1F / 0 + {"vpcmplt", 0x20 , 0xCBB200,0x59 , 0x95 , 0x1209, 0x209 , 0 , 0x11 , 0x1406, 0 , 0x01 }, // 0F 3A 1F / 1 + {"vpcmple", 0x20 , 0xCBB200,0x59 , 0x95 , 0x1209, 0x209 , 0 , 0x11 , 0x1406, 0 , 0x01 }, // 0F 3A 1F / 2 + {"vpcmp", 0x20 , 0xCBB200,0x59 , 0x95 , 0x1209, 0x209 , 0x31 , 0x11 , 0x1406, 0 , 0x01 }, // 0F 3A 1F / 3 = true + {"vpcmpneq", 0x20 , 0xCBB200,0x59 , 0x95 , 0x1209, 0x209 , 0 , 0x11 , 0x1406, 0 , 0x01 }, // 0F 3A 1F / 4 + {"vpcmpnlt", 0x20 , 0xCBB200,0x59 , 0x95 , 0x1209, 0x209 , 0 , 0x11 , 0x1406, 0 , 0x01 }, // 0F 3A 1F / 5 + {"vpcmpnle", 0x20 , 0xCBB200,0x59 , 0x95 , 0x1209, 0x209 , 0 , 0x11 , 0x1406, 0 , 0x01 }, // 0F 3A 1F / 6 + {"vpcmp", 0x20 , 0xCBB200,0x59 , 0x95 , 0x1209, 0x209 , 0x31 , 0x11 , 0x1406, 0 , 0x01 }}; // 0F 3A 1F / >= 7 = false + +// Submap for pcmpeqb. Opcode byte = 0F 74 +// Indexed by E/MVEX prefix +SOpcodeDef OpcodeMap116[] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"pcmpeqb", 0x7 , 0xD0200, 0x19 , 0x1101, 0x1101, 0x101 , 0 , 0 , 0 , 0 , 0x2 }, // 0F 74 + {"vpcmpeqb", 0x20 ,0x8FA200, 0x19 , 0x95 , 0x1201, 0x201 , 0 , 0x10 , 0 , 0 , 0 }}; // E/MVEX 0F 76 + +// Submap for pcmpeqw. Opcode byte = 0F 75 +// Indexed by E/MVEX prefix +SOpcodeDef OpcodeMap117[] = { + {"pcmpeqw", 0x7 , 0xD0200, 0x19 , 0x1102, 0x1102, 0x102 , 0 , 0 , 0 , 0 , 0x2 }, // 0F 75 + {"vpcmpeqw", 0x20 ,0x8FA200, 0x19 , 0x95 , 0x1202, 0x202 , 0 , 0x10 , 0 , 0 , 0 }}; // E/MVEX 0F 76 + +// Submap for pcmpgtb. Opcode byte = 0F 64 +// Indexed by EVEX prefix +SOpcodeDef OpcodeMap118[] = { + {"pcmpgtb", 0x7 , 0xD0200, 0x19 , 0x1101, 0x1101, 0x101 , 0 , 0 , 0 , 0 , 0x2 }, // 0F 64 + {"vpcmpgtb", 0x20 ,0x8BA200, 0x19 , 0x95 , 0x1203, 0x203 , 0 , 0x10 , 0x1406, 0 , 0x000 }}; // E/MVEX 0F 64 + + +// Submap for pcmpgtw. Opcode byte = 0F 65 +// Indexed by EVEX prefix +SOpcodeDef OpcodeMap119[] = { + {"pcmpgtw", 0x7 , 0xD0200, 0x19 , 0x1102, 0x1102, 0x102 , 0 , 0 , 0 , 0 , 0x2 }, // 0F 65 + {"vpcmpgtw", 0x20 ,0x8BA200, 0x19 , 0x95 , 0x1203, 0x203 , 0 , 0x10 , 0x1406, 0 , 0x000 }}; // E/MVEX 0F 65 + + +// Opcode map for EVEX 66 0F 7B. Indexed by W bit +SOpcodeDef OpcodeMap11A[] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {"vcvtps2qq", 0x20 ,0x840200, 0x12 , 0x204 , 0xF4B , 0 , 0 , 0x27 , 0 , 0 , 0 }, // EVEX 66 0F 7B. W = 0 + {"vcvtpd2qq", 0x20 ,0x841200, 0x12 , 0x204 , 0x24C , 0 , 0 , 0x27 , 0 , 0 , 0 }}; // EVEX 66 0F 7B. W = 1 + +// Opcode map for EVEX F2 0F 7A. Indexed by W bit +SOpcodeDef OpcodeMap11B[] = { + {"vcvtudq2ps",0x20 ,0xC28800, 0x12 , 0x124B, 0x203 , 0 , 0 , 0x37 , 0x1214, 0 , 0 }, // F2 EVEX 0F 7A W0 + {"vcvtuqq2ps",0x20 ,0x869800, 0x12 , 0x1F4B, 0x204 , 0 , 0 , 0x27 , 0 , 0 , 0 }}; // F2 EVEX 0F 7A W0 + +// Opcode map for EVEX F3 0F 7A. Indexed by W bit +SOpcodeDef OpcodeMap11C[] = { + {"vcvtudq2pd",0x20 ,0xC28400, 0x12 , 0x124C, 0xF03 , 0 , 0 , 0x31 , 0x1214, 0 , 0 }, // F3 E/MVEX 0F 7A W0 + {"vcvtuqq2pd",0x20 ,0x869800, 0x12 , 0x124C, 0x204 , 0 , 0 , 0x27 , 0 , 0 , 0 }}; // F2 EVEX 0F 7A W0 + +// Opcode map for 0F 3A 42. Indexed by EVEX +SOpcodeDef OpcodeMap11D[] = { + {"mpsadbw", 0x15 , 0xD8200, 0x59 , 0x1202, 0x1202, 0x201 , 0x31 , 0 , 0 , 0 , 0x2 }, // 0F 3A 42 + {"vdbpsadbw", 0x20 ,0x8E8200, 0x59 , 0x1202, 0x1202, 0x201 , 0x31 , 0x20 , 0 , 0 , 0 }}; // EVEX 0F 3A 42 + +// Opcode map for 0F 3A 19. Indexed by EVEX +SOpcodeDef OpcodeMap11E[] = { + {"vextractf128" ,0x19,0x978200,0x53, 0x450 , 0x1550, 0x31 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A 19 + {0 ,0x11F,0 ,0x53, 0 , 0 , 0 , 0 , 0 , 0 , 0xC , 0 }}; // EVEX 0F 3A 19 + +// Opcode map for EVEX 0F 3A 19. Indexed by W bit +SOpcodeDef OpcodeMap11F[] = { + {"vextractf32x4",0x20,0x868200,0x53, 0x44B , 0x124B, 0x31 , 0 , 0x20 , 0 , 0 , 0 }, // EVEX W0 0F 3A 19 + {"vextractf64x2",0x20,0x869200,0x53, 0x44C , 0x124C, 0x31 , 0 , 0x20 , 0 , 0 , 0 }}; // EVEX W1 0F 3A 19 + +// Opcode map for EVEX 0F 3A 39. Indexed by EVEX +SOpcodeDef OpcodeMap120[] = { + {"vextracti128",0x1C, 0x978200,0x53 , 0x406 , 0x1506, 0x31 , 0 , 0 , 0 , 0 , 0 }, // 0F 3A 39 + {0 ,0x121, 0 ,0x53 , 0 , 0 , 0 , 0 , 0 , 0 , 0xC , 0 }}; // EVEX 0F 3A 39 + +// Opcode map for EVEX 0F 3A 39. Indexed by W bit +SOpcodeDef OpcodeMap121[] = { + {"vextracti32x4",0x20,0x868200,0x53 , 0x406 , 0x1203, 0x31 , 0 , 0x20 , 0 , 0 , 0 }, // 0F 3A 39 + {"vextracti64x2",0x20,0x869200,0x53 , 0x406 , 0x1203, 0x31 , 0 , 0x20 , 0 , 0 , 0 }}; // 0F 3A 39 + +// Opcode map for 0F 3A 18. Indexed by EVEX +SOpcodeDef OpcodeMap122[] = { + {"vinsertf128",0x19 ,0x9F8200, 0x59 , 0x1250, 0x1250, 0x450 , 0x31 , 0x30 , 0 , 0 , 0 }, // 0F 3A 18 + {0, 0x123 , 0 , 0x59 , 0 , 0 , 0 , 0 , 0 , 0 , 0xC , 0 }}; + +// Opcode map for EVEX 0F 3A 18. Indexed by W bit +SOpcodeDef OpcodeMap123[] = { + {"vinsertf32x4",0x20,0x8AB200, 0x59 , 0x1250, 0x1250, 0x44B , 0x31 , 0x20 , 0 , 0 , 0 }, // EVEX 0F 3A 18. W0 + {"vinsertf64x2",0x20,0x8AB200, 0x59 , 0x1250, 0x1250, 0x44C , 0x31 , 0x20 , 0 , 0 , 0 }}; // EVEX 0F 3A 18. W0 + +// Opcode map for EVEX 0F 3A 1A. Indexed by W bit +SOpcodeDef OpcodeMap124[] = { + {"vinsertf32x8",0x20,0x8AB200, 0x59 , 0x1250, 0x1250, 0x54B , 0x31 , 0x30 , 0 , 0 , 0 }, // 0F 3A 1A + {"vinsertf64x4",0x20,0x8AB200, 0x59 , 0x1250, 0x1250, 0x54C , 0x31 , 0x30 , 0 , 0 , 0 }}; // 0F 3A 1A + +// Opcode map for 0F 3A 38. Indexed by EVEX +SOpcodeDef OpcodeMap125[] = { + {"vinserti128",0x1C ,0x9F8200, 0x59 , 0x1206, 0x1206, 0x406 , 0x31 , 0x30 , 0 , 0 , 0 }, // 0F 3A 38 + {0, 0x126 , 0 , 0x59 , 0 , 0 , 0 , 0 , 0 , 0 , 0xC , 0 }}; + +// Opcode map for EVEX 0F 3A 38. Indexed by W bit +SOpcodeDef OpcodeMap126[] = { + {"vinserti32x4",0x1C ,0x8AB200, 0x59 , 0x1203, 0x1203, 0x403 , 0x31 , 0x20 , 0 , 0 , 0 }, // EVEX 0F 3A 38. W0 + {"vinserti64x2",0x20 ,0x8AB200, 0x59 , 0x1204, 0x1204, 0x404 , 0x31 , 0x20 , 0 , 0 , 0 }}; // EVEX 0F 3A 38. W1 + +// Opcode map for EVEX 0F 3A 3A. Indexed by W bit +SOpcodeDef OpcodeMap127[] = { + {"vinserti32x8",0x20,0x8AB200, 0x59 , 0x1203, 0x1203, 0x503 , 0x31 , 0x20 , 0 , 0 , 0 }, // EVEX 0F 3A 3A. W0 + {"vinserti64x4",0x20,0x8AB200, 0x59 , 0x1204, 0x1204, 0x504 , 0x31 , 0x20 , 0 , 0 , 0 }}; // EVEX 0F 3A 3A. W1 + +// Opcode map for 0F 38 B4. Indexed by VEX prefix type +SOpcodeDef OpcodeMap128[] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 38 B4 + {"vpmadd52luq",0x23 ,0x8EB200, 0x19 , 0x1204, 0x1204, 0x204 , 0 , 0x21 , 0 , 0 , 0 }, // EVEX 0F 38 B4 + {"vpmadd233d",0x80 ,0x4A8200, 0x19 , 0x1603, 0x1603, 0x603 , 0 , 0 , 0x1406, 0 , 0x100 }}; // MVEX 0F 38 B4 + +// Opcode map for 0F 38 B5. Indexed by VEX prefix type +SOpcodeDef OpcodeMap129[] = { + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // VEX 0F 38 B5 + {"vpmadd52huq",0x23 ,0x8EB200, 0x19 , 0x1204, 0x1204, 0x204 , 0 , 0x21 , 0 , 0 , 0 }, // EVEX 0F 38 B5 + {"vpmadd231d",0x80 ,0x4A8200, 0x19 , 0x1603, 0x1603, 0x603 , 0 , 0 , 0x1406, 0 , 0x100 }}; // MVEX 0F 38 B5 + +// 0F 38 19 indexed by VEX / EVEX +SOpcodeDef OpcodeMap12A[] = { + {"vbroadcastsd",0x19,0xC7A200, 0x12 , 0x124C, 0x04C , 0 , 0 , 0x20 , 0x1049, 0 , 0 }, // VEX 0F 38 19 + {0, 0x12B , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0xC , 0 }}; // EVEX 0F 38 19 + +// EVEX 0F 38 19 indexed by W bit +SOpcodeDef OpcodeMap12B[] = { + {"vbroadcastf32x2",0x20,0xC6B200, 0x12,0x124C, 0x04B , 0 , 0 , 0x20 , 0x1049, 0 , 0 }, // EVEX W0 0F 38 19 + {"vbroadcastsd",0x20,0xC6B200, 0x12 , 0x124C, 0x04C , 0 , 0 , 0x20 , 0x1049, 0 , 0 }}; // EVEX W1 0F 38 19 + +// Opcode map for 0F 38 38. Indexed by prefix +SOpcodeDef OpcodeMap12C[] = { + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 38 + {"pminsb", 0x15 ,0x8DA200, 0x19 , 0x1201, 0x1201, 0x201 , 0 , 0x20 , 0 , 0 , 0x2 }, // 66 0F 38 38 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // F2 0F 38 38 + // moved to map B2. this map can be removed +// {"vpmovm2", 0x20 ,0x86B400, 0x12 , 0x1209, 0x95 , 0 , 0 , 0 , 0 , 0 , 1 }}; // F3 0F 38 38 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }}; + +// Opcode map for EVEX 0F 38 39. Indexed by prefix +SOpcodeDef OpcodeMap12D[] = { + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F 38 39 + {"vpmins", 0x15 ,0xCDB200, 0x19 , 0x1209, 0x1209, 0x209 , 0 , 0x31 , 0x1406, 0 , 0x1 }, // 66 0F 38 39 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // F2 0F 38 39 + // this entry has been replaced by a link from map B2. this may be removed + // {0, 0x12F , 0 , 0x12 , 0 , 0 , 0 , 0 , 0 , 0 , 0xC , 0 }}; // F3 0F 38 39 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }}; + +// Opcode map for EVEX 0F 38 29. Indexed by W bit +SOpcodeDef OpcodeMap12E[] = { + {"vpmovb2m", 0x20 ,0x86C400, 0x12 , 0x95 , 0x1209, 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 29 W0 + {"vpmovw2m", 0x20 ,0x86C400, 0x12 , 0x95 , 0x1209, 0 , 0 , 0 , 0 , 0 , 0 }}; // EVEX F3 0F 38 29 W1 + +// Opcode map for EVEX 0F 38 39. Indexed by W bit +SOpcodeDef OpcodeMap12F[] = { + {"vpmovd2m", 0x20 ,0x86B400, 0x12 , 0x95 , 0x1209, 0 , 0 , 0 , 0 , 0 , 0 }, // EVEX F3 0F 38 39 W0 + {"vpmovq2m", 0x20 ,0x86B400, 0x12 , 0x95 , 0x1209, 0 , 0 , 0 , 0 , 0 , 0 }}; // EVEX F3 0F 38 39 W1 + +// Opcode map for 0F 01, mod = 11b, reg = 5 +// Indexed by rm bits +SOpcodeDef OpcodeMap130[] = { + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // rm = 0 + {0, 0x131 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 9 , 0 }, // rm = 1. link to incssp + {0, 0x132 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 9 , 0 }, // rm = 2. link to savessp + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // rm = 3 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // rm = 4 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // rm = 5 + {"rdpkru", 0 , 0x000 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // rm = 6 + {"wrpkru", 0 , 0x000 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }}; // rm = 7 + +// Opcode map for 0F 01, mod = 11b, reg = 5, rm = 1. Indexed by prefix +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options +SOpcodeDef OpcodeMap131[] = { + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 66 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // F2 + {"incssp", 0 , 0x400 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }}; // F3 + +// Opcode map for 0F 01, mod = 11b, reg = 5, rm = 2. Indexed by prefix +SOpcodeDef OpcodeMap132[] = { + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 66 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // F2 + {"savessp", 0 , 0x400 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }}; // F3 + +// Opcode map for 0F 01, mod != 11b, reg = 5. Indexed by prefix +SOpcodeDef OpcodeMap133[] = { + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 66 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // F2 + {"rstorssp", 0 , 0x400 , 0x11 , 0 , 0x2004, 0 , 0 , 0 , 0 , 0 , 0 }}; // F3 + +// Opcode map for 0F AE /5. Link by prefix +SOpcodeDef OpcodeMap134[] = { + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 66 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // F2 + {"setssbsy", 0 , 0x400 , 0x11 , 0 , 0x2004, 0 , 0 , 0 , 0 , 0 , 0 }}; // F3 + +// Opcode map for 0F 1E. Hint instructions. Link by prefix +SOpcodeDef OpcodeMap135[] = { + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 66 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // F2 + {0, 0x136 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 4 , 0 }}; // F3 + +// Opcode map for F3 0F 1E. Hint instructions. Link by mod / reg +SOpcodeDef OpcodeMap136[] = { + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // mod < 3 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // mod = 3, reg = 0 + {"rdssp", 0 , 0x1400 , 0x11 , 0 , 0x1009, 0 , 0 , 0 , 0 , 0 , 0 }, // mod = 3, reg = 1 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // mod = 3, reg = 2 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // mod = 3, reg = 3 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // mod = 3, reg = 4 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // mod = 3, reg = 5 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // mod = 3, reg = 6 + {0, 0x137 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 5 , 0 }}; // mod = 3, reg = 7 + +// Opcode map for F3 0F 1E. mod = 3, reg = 7. Link by rm +SOpcodeDef OpcodeMap137[] = { +// name instset prefix format dest. source1 source2 source3 EVEX MVEX link options + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // rm = 0 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // rm = 1 + {"endbr64", 0 , 0x400 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // rm = 2 + {"endbr32", 0 , 0x400 , 0x10 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // rm = 3 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // rm = 4 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // rm = 5 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // rm = 6 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }}; // rm = 7 + +// Submap for 0F C7 reg /7, Indexed by prefixes +SOpcodeDef OpcodeMap138[] = { + {"rdseed", 0x1D , 0x1100 , 0x11 , 0x1009, 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 0F C7 reg /7 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // 66 0F C7 reg /7 + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }, // F2 0F C7 reg /7 + {"rdpid", 0x1D , 0x1500 , 0x11 , 0x1009, 0 , 0 , 0 , 0 , 0 , 0 , 0 }}; // F3 0F C7 reg /7 + + +SOpcodeDef OpcodeMap139[] = { + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }}; + +SOpcodeDef OpcodeMap13A[] = { + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }}; + +SOpcodeDef OpcodeMap13B[] = { + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }}; + +SOpcodeDef OpcodeMap13C[] = { + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }}; + +SOpcodeDef OpcodeMap13D[] = { + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }}; + +SOpcodeDef OpcodeMap13E[] = { + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }}; + +SOpcodeDef OpcodeMap13F[] = { + {0, 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 }}; + + +/************** Make pointers to all opcode maps ***************************/ +const SOpcodeDef * const OpcodeTables[] = { + OpcodeMap0, OpcodeMap1, OpcodeMap2, OpcodeMap3, + OpcodeMap4, OpcodeMap5, OpcodeMap6, OpcodeMap7, + OpcodeMap8, OpcodeMap9, OpcodeMapA, OpcodeMapB, + OpcodeMapC, OpcodeMapD, OpcodeMapE, OpcodeMapF, + OpcodeMap10, OpcodeMap11, OpcodeMap12, OpcodeMap13, + OpcodeMap14, OpcodeMap15, OpcodeMap16, OpcodeMap17, + OpcodeMap18, OpcodeMap19, OpcodeMap1A, OpcodeMap1B, + OpcodeMap1C, OpcodeMap1D, OpcodeMap1E, OpcodeMap1F, + OpcodeMap20, OpcodeMap21, OpcodeMap22, OpcodeMap23, + OpcodeMap24, OpcodeMap25, OpcodeMap26, OpcodeMap27, + OpcodeMap28, OpcodeMap29, OpcodeMap2A, OpcodeMap2B, + OpcodeMap2C, OpcodeMap2D, OpcodeMap2E, OpcodeMap2F, + OpcodeMap30, OpcodeMap31, OpcodeMap32, OpcodeMap33, + OpcodeMap34, OpcodeMap35, OpcodeMap36, OpcodeMap37, + OpcodeMap38, OpcodeMap39, OpcodeMap3A, OpcodeMap3B, + OpcodeMap3C, OpcodeMap3D, OpcodeMap3E, OpcodeMap3F, + OpcodeMap40, OpcodeMap41, OpcodeMap42, OpcodeMap43, + OpcodeMap44, OpcodeMap45, OpcodeMap46, OpcodeMap47, + OpcodeMap48, OpcodeMap49, OpcodeMap4A, OpcodeMap4B, + OpcodeMap4C, OpcodeMap4D, OpcodeMap4E, OpcodeMap4F, + OpcodeMap50, OpcodeMap51, OpcodeMap52, OpcodeMap53, + OpcodeMap54, OpcodeMap55, OpcodeMap56, OpcodeMap57, + OpcodeMap58, OpcodeMap59, OpcodeMap5A, OpcodeMap5B, + OpcodeMap5C, OpcodeMap5D, OpcodeMap5E, OpcodeMap5F, + OpcodeMap60, OpcodeMap61, OpcodeMap62, OpcodeMap63, + OpcodeMap64, OpcodeMap65, OpcodeMap66, OpcodeMap67, + OpcodeMap68, OpcodeMap69, OpcodeMap6A, OpcodeMap6B, + OpcodeMap6C, OpcodeMap6D, OpcodeMap6E, OpcodeMap6F, + OpcodeMap70, OpcodeMap71, OpcodeMap72, OpcodeMap73, + OpcodeMap74, OpcodeMap75, OpcodeMap76, OpcodeMap77, + OpcodeMap78, OpcodeMap79, OpcodeMap7A, OpcodeMap7B, + OpcodeMap7C, OpcodeMap7D, OpcodeMap7E, OpcodeMap7F, + OpcodeMap80, OpcodeMap81, OpcodeMap82, OpcodeMap83, + OpcodeMap84, OpcodeMap85, OpcodeMap86, OpcodeMap87, + OpcodeMap88, OpcodeMap89, OpcodeMap8A, OpcodeMap8B, + OpcodeMap8C, OpcodeMap8D, OpcodeMap8E, OpcodeMap8F, + OpcodeMap90, OpcodeMap91, OpcodeMap92, OpcodeMap93, + OpcodeMap94, OpcodeMap95, OpcodeMap96, OpcodeMap97, + OpcodeMap98, OpcodeMap99, OpcodeMap9A, OpcodeMap9B, + OpcodeMap9C, OpcodeMap9D, OpcodeMap9E, OpcodeMap9F, + OpcodeMapA0, OpcodeMapA1, OpcodeMapA2, OpcodeMapA3, + OpcodeMapA4, OpcodeMapA5, OpcodeMapA6, OpcodeMapA7, + OpcodeMapA8, OpcodeMapA9, OpcodeMapAA, OpcodeMapAB, + OpcodeMapAC, OpcodeMapAD, OpcodeMapAE, OpcodeMapAF, + OpcodeMapB0, OpcodeMapB1, OpcodeMapB2, OpcodeMapB3, + OpcodeMapB4, OpcodeMapB5, OpcodeMapB6, OpcodeMapB7, + OpcodeMapB8, OpcodeMapB9, OpcodeMapBA, OpcodeMapBB, + OpcodeMapBC, OpcodeMapBD, OpcodeMapBE, OpcodeMapBF, + OpcodeMapC0, OpcodeMapC1, OpcodeMapC2, OpcodeMapC3, + OpcodeMapC4, OpcodeMapC5, OpcodeMapC6, OpcodeMapC7, + OpcodeMapC8, OpcodeMapC9, OpcodeMapCA, OpcodeMapCB, + OpcodeMapCC, OpcodeMapCD, OpcodeMapCE, OpcodeMapCF, + OpcodeMapD0, OpcodeMapD1, OpcodeMapD2, OpcodeMapD3, + OpcodeMapD4, OpcodeMapD5, OpcodeMapD6, OpcodeMapD7, + OpcodeMapD8, OpcodeMapD9, OpcodeMapDA, OpcodeMapDB, + OpcodeMapDC, OpcodeMapDD, OpcodeMapDE, OpcodeMapDF, + OpcodeMapE0, OpcodeMapE1, OpcodeMapE2, OpcodeMapE3, + OpcodeMapE4, OpcodeMapE5, OpcodeMapE6, OpcodeMapE7, + OpcodeMapE8, OpcodeMapE9, OpcodeMapEA, OpcodeMapEB, + OpcodeMapEC, OpcodeMapED, OpcodeMapEE, OpcodeMapEF, + OpcodeMapF0, OpcodeMapF1, OpcodeMapF2, OpcodeMapF3, + OpcodeMapF4, OpcodeMapF5, OpcodeMapF6, OpcodeMapF7, + OpcodeMapF8, OpcodeMapF9, OpcodeMapFA, OpcodeMapFB, + OpcodeMapFC, OpcodeMapFD, OpcodeMapFE, OpcodeMapFF, + OpcodeMap100, OpcodeMap101, OpcodeMap102, OpcodeMap103, + OpcodeMap104, OpcodeMap105, OpcodeMap106, OpcodeMap107, + OpcodeMap108, OpcodeMap109, OpcodeMap10A, OpcodeMap10B, + OpcodeMap10C, OpcodeMap10D, OpcodeMap10E, OpcodeMap10F, + OpcodeMap110, OpcodeMap111, OpcodeMap112, OpcodeMap113, + OpcodeMap114, OpcodeMap115, OpcodeMap116, OpcodeMap117, + OpcodeMap118, OpcodeMap119, OpcodeMap11A, OpcodeMap11B, + OpcodeMap11C, OpcodeMap11D, OpcodeMap11E, OpcodeMap11F, + OpcodeMap120, OpcodeMap121, OpcodeMap122, OpcodeMap123, + OpcodeMap124, OpcodeMap125, OpcodeMap126, OpcodeMap127, + OpcodeMap128, OpcodeMap129, OpcodeMap12A, OpcodeMap12B, + OpcodeMap12C, OpcodeMap12D, OpcodeMap12E, OpcodeMap12F, + OpcodeMap130, OpcodeMap131, OpcodeMap132, OpcodeMap133, + OpcodeMap134, OpcodeMap135, OpcodeMap136, OpcodeMap137, + OpcodeMap138, OpcodeMap139, OpcodeMap13A, OpcodeMap13B, + OpcodeMap13C, OpcodeMap13D, OpcodeMap13E, OpcodeMap13F, +}; + +// size of each table pointed to by OpcodeTables[] +const uint32 OpcodeTableLength[] = { + TableSize(OpcodeMap0), TableSize(OpcodeMap1), TableSize(OpcodeMap2), TableSize(OpcodeMap3), + TableSize(OpcodeMap4), TableSize(OpcodeMap5), TableSize(OpcodeMap6), TableSize(OpcodeMap7), + TableSize(OpcodeMap8), TableSize(OpcodeMap9), TableSize(OpcodeMapA), TableSize(OpcodeMapB), + TableSize(OpcodeMapC), TableSize(OpcodeMapD), TableSize(OpcodeMapE), TableSize(OpcodeMapF), + TableSize(OpcodeMap10), TableSize(OpcodeMap11), TableSize(OpcodeMap12), TableSize(OpcodeMap13), + TableSize(OpcodeMap14), TableSize(OpcodeMap15), TableSize(OpcodeMap16), TableSize(OpcodeMap17), + TableSize(OpcodeMap18), TableSize(OpcodeMap19), TableSize(OpcodeMap1A), TableSize(OpcodeMap1B), + TableSize(OpcodeMap1C), TableSize(OpcodeMap1D), TableSize(OpcodeMap1E), TableSize(OpcodeMap1F), + TableSize(OpcodeMap20), TableSize(OpcodeMap21), TableSize(OpcodeMap22), TableSize(OpcodeMap23), + TableSize(OpcodeMap24), TableSize(OpcodeMap25), TableSize(OpcodeMap26), TableSize(OpcodeMap27), + TableSize(OpcodeMap28), TableSize(OpcodeMap29), TableSize(OpcodeMap2A), TableSize(OpcodeMap2B), + TableSize(OpcodeMap2C), TableSize(OpcodeMap2D), TableSize(OpcodeMap2E), TableSize(OpcodeMap2F), + TableSize(OpcodeMap30), TableSize(OpcodeMap31), TableSize(OpcodeMap32), TableSize(OpcodeMap33), + TableSize(OpcodeMap34), TableSize(OpcodeMap35), TableSize(OpcodeMap36), TableSize(OpcodeMap37), + TableSize(OpcodeMap38), TableSize(OpcodeMap39), TableSize(OpcodeMap3A), TableSize(OpcodeMap3B), + TableSize(OpcodeMap3C), TableSize(OpcodeMap3D), TableSize(OpcodeMap3E), TableSize(OpcodeMap3F), + TableSize(OpcodeMap40), TableSize(OpcodeMap41), TableSize(OpcodeMap42), TableSize(OpcodeMap43), + TableSize(OpcodeMap44), TableSize(OpcodeMap45), TableSize(OpcodeMap46), TableSize(OpcodeMap47), + TableSize(OpcodeMap48), TableSize(OpcodeMap49), TableSize(OpcodeMap4A), TableSize(OpcodeMap4B), + TableSize(OpcodeMap4C), TableSize(OpcodeMap4D), TableSize(OpcodeMap4E), TableSize(OpcodeMap4F), + TableSize(OpcodeMap50), TableSize(OpcodeMap51), TableSize(OpcodeMap52), TableSize(OpcodeMap53), + TableSize(OpcodeMap54), TableSize(OpcodeMap55), TableSize(OpcodeMap56), TableSize(OpcodeMap57), + TableSize(OpcodeMap58), TableSize(OpcodeMap59), TableSize(OpcodeMap5A), TableSize(OpcodeMap5B), + TableSize(OpcodeMap5C), TableSize(OpcodeMap5D), TableSize(OpcodeMap5E), TableSize(OpcodeMap5F), + TableSize(OpcodeMap60), TableSize(OpcodeMap61), TableSize(OpcodeMap62), TableSize(OpcodeMap63), + TableSize(OpcodeMap64), TableSize(OpcodeMap65), TableSize(OpcodeMap66), TableSize(OpcodeMap67), + TableSize(OpcodeMap68), TableSize(OpcodeMap69), TableSize(OpcodeMap6A), TableSize(OpcodeMap6B), + TableSize(OpcodeMap6C), TableSize(OpcodeMap6D), TableSize(OpcodeMap6E), TableSize(OpcodeMap6F), + TableSize(OpcodeMap70), TableSize(OpcodeMap71), TableSize(OpcodeMap72), TableSize(OpcodeMap73), + TableSize(OpcodeMap74), TableSize(OpcodeMap75), TableSize(OpcodeMap76), TableSize(OpcodeMap77), + TableSize(OpcodeMap78), TableSize(OpcodeMap79), TableSize(OpcodeMap7A), TableSize(OpcodeMap7B), + TableSize(OpcodeMap7C), TableSize(OpcodeMap7D), TableSize(OpcodeMap7E), TableSize(OpcodeMap7F), + TableSize(OpcodeMap80), TableSize(OpcodeMap81), TableSize(OpcodeMap82), TableSize(OpcodeMap83), + TableSize(OpcodeMap84), TableSize(OpcodeMap85), TableSize(OpcodeMap86), TableSize(OpcodeMap87), + TableSize(OpcodeMap88), TableSize(OpcodeMap89), TableSize(OpcodeMap8A), TableSize(OpcodeMap8B), + TableSize(OpcodeMap8C), TableSize(OpcodeMap8D), TableSize(OpcodeMap8E), TableSize(OpcodeMap8F), + TableSize(OpcodeMap90), TableSize(OpcodeMap91), TableSize(OpcodeMap92), TableSize(OpcodeMap93), + TableSize(OpcodeMap94), TableSize(OpcodeMap95), TableSize(OpcodeMap96), TableSize(OpcodeMap97), + TableSize(OpcodeMap98), TableSize(OpcodeMap99), TableSize(OpcodeMap9A), TableSize(OpcodeMap9B), + TableSize(OpcodeMap9C), TableSize(OpcodeMap9D), TableSize(OpcodeMap9E), TableSize(OpcodeMap9F), + TableSize(OpcodeMapA0), TableSize(OpcodeMapA1), TableSize(OpcodeMapA2), TableSize(OpcodeMapA3), + TableSize(OpcodeMapA4), TableSize(OpcodeMapA5), TableSize(OpcodeMapA6), TableSize(OpcodeMapA7), + TableSize(OpcodeMapA8), TableSize(OpcodeMapA9), TableSize(OpcodeMapAA), TableSize(OpcodeMapAB), + TableSize(OpcodeMapAC), TableSize(OpcodeMapAD), TableSize(OpcodeMapAE), TableSize(OpcodeMapAF), + TableSize(OpcodeMapB0), TableSize(OpcodeMapB1), TableSize(OpcodeMapB2), TableSize(OpcodeMapB3), + TableSize(OpcodeMapB4), TableSize(OpcodeMapB5), TableSize(OpcodeMapB6), TableSize(OpcodeMapB7), + TableSize(OpcodeMapB8), TableSize(OpcodeMapB9), TableSize(OpcodeMapBA), TableSize(OpcodeMapBB), + TableSize(OpcodeMapBC), TableSize(OpcodeMapBD), TableSize(OpcodeMapBE), TableSize(OpcodeMapBF), + TableSize(OpcodeMapC0), TableSize(OpcodeMapC1), TableSize(OpcodeMapC2), TableSize(OpcodeMapC3), + TableSize(OpcodeMapC4), TableSize(OpcodeMapC5), TableSize(OpcodeMapC6), TableSize(OpcodeMapC7), + TableSize(OpcodeMapC8), TableSize(OpcodeMapC9), TableSize(OpcodeMapCA), TableSize(OpcodeMapCB), + TableSize(OpcodeMapCC), TableSize(OpcodeMapCD), TableSize(OpcodeMapCE), TableSize(OpcodeMapCF), + TableSize(OpcodeMapD0), TableSize(OpcodeMapD1), TableSize(OpcodeMapD2), TableSize(OpcodeMapD3), + TableSize(OpcodeMapD4), TableSize(OpcodeMapD5), TableSize(OpcodeMapD6), TableSize(OpcodeMapD7), + TableSize(OpcodeMapD8), TableSize(OpcodeMapD9), TableSize(OpcodeMapDA), TableSize(OpcodeMapDB), + TableSize(OpcodeMapDC), TableSize(OpcodeMapDD), TableSize(OpcodeMapDE), TableSize(OpcodeMapDF), + TableSize(OpcodeMapE0), TableSize(OpcodeMapE1), TableSize(OpcodeMapE2), TableSize(OpcodeMapE3), + TableSize(OpcodeMapE4), TableSize(OpcodeMapE5), TableSize(OpcodeMapE6), TableSize(OpcodeMapE7), + TableSize(OpcodeMapE8), TableSize(OpcodeMapE9), TableSize(OpcodeMapEA), TableSize(OpcodeMapEB), + TableSize(OpcodeMapEC), TableSize(OpcodeMapED), TableSize(OpcodeMapEE), TableSize(OpcodeMapEF), + TableSize(OpcodeMapF0), TableSize(OpcodeMapF1), TableSize(OpcodeMapF2), TableSize(OpcodeMapF3), + TableSize(OpcodeMapF4), TableSize(OpcodeMapF5), TableSize(OpcodeMapF6), TableSize(OpcodeMapF7), + TableSize(OpcodeMapF8), TableSize(OpcodeMapF9), TableSize(OpcodeMapFA), TableSize(OpcodeMapFB), + TableSize(OpcodeMapFC), TableSize(OpcodeMapFD), TableSize(OpcodeMapFE), TableSize(OpcodeMapFF), + TableSize(OpcodeMap100), TableSize(OpcodeMap101), TableSize(OpcodeMap102), TableSize(OpcodeMap103), + TableSize(OpcodeMap104), TableSize(OpcodeMap105), TableSize(OpcodeMap106), TableSize(OpcodeMap107), + TableSize(OpcodeMap108), TableSize(OpcodeMap109), TableSize(OpcodeMap10A), TableSize(OpcodeMap10B), + TableSize(OpcodeMap10C), TableSize(OpcodeMap10D), TableSize(OpcodeMap10E), TableSize(OpcodeMap10F), + TableSize(OpcodeMap110), TableSize(OpcodeMap111), TableSize(OpcodeMap112), TableSize(OpcodeMap113), + TableSize(OpcodeMap114), TableSize(OpcodeMap115), TableSize(OpcodeMap116), TableSize(OpcodeMap117), + TableSize(OpcodeMap118), TableSize(OpcodeMap119), TableSize(OpcodeMap11A), TableSize(OpcodeMap11B), + TableSize(OpcodeMap11C), TableSize(OpcodeMap11D), TableSize(OpcodeMap11E), TableSize(OpcodeMap11F), + TableSize(OpcodeMap120), TableSize(OpcodeMap121), TableSize(OpcodeMap122), TableSize(OpcodeMap123), + TableSize(OpcodeMap124), TableSize(OpcodeMap125), TableSize(OpcodeMap126), TableSize(OpcodeMap127), + TableSize(OpcodeMap128), TableSize(OpcodeMap129), TableSize(OpcodeMap12A), TableSize(OpcodeMap12B), + TableSize(OpcodeMap12C), TableSize(OpcodeMap12D), TableSize(OpcodeMap12E), TableSize(OpcodeMap12F), + TableSize(OpcodeMap130), TableSize(OpcodeMap131), TableSize(OpcodeMap132), TableSize(OpcodeMap133), + TableSize(OpcodeMap134), TableSize(OpcodeMap135), TableSize(OpcodeMap136), TableSize(OpcodeMap137), + TableSize(OpcodeMap138), TableSize(OpcodeMap139), TableSize(OpcodeMap13A), TableSize(OpcodeMap13B), + TableSize(OpcodeMap13C), TableSize(OpcodeMap13D), TableSize(OpcodeMap13E), TableSize(OpcodeMap13F), +}; + +// number of entries in OpcodeTables +const uint32 NumOpcodeTables1 = TableSize(OpcodeTables); +const uint32 NumOpcodeTables2 = TableSize(OpcodeTableLength); + +// Index to start pages, depending on VEX.mmmm bits +uint32 OpcodeStartPageVEX[] = { + 0xB0, // no escape, VEX.mmmm = 0 + 0xB1, // 0F escape or VEX.mmmm = 1 + 0x2, // 0F 38 escape or VEX.mmmm = 2 + 0x4, // 0f 3A escape or VEX.mmmm = 3 + 0, 0, 0, 0, // reserved for higher mmmm + 0xB2, // 0F 38 escape or EVEX.mmmm = 2 with F2 prefix (pp = 11) + 0xB3 // 0F 38 escape or EVEX.mmmm = 2 with F3 prefix (pp = 10) +}; + +// Index to start pages, depending on XOP.mmmm bits +SOpcodeDef const * OpcodeStartPageXOP[] = { + OpcodeMap64, // XOP.mmmm = 8 + OpcodeMap65, // XOP.mmmm = 9 + OpcodeMap66 // XOP.mmmm = 0xA +}; + +// Number of entries in OpcodeStartPages +const uint32 NumOpcodeStartPageVEX = TableSize(OpcodeStartPageVEX); +const uint32 NumOpcodeStartPageXOP = TableSize(OpcodeStartPageXOP); + + +// Define register names + +// Names of 8 bit registers +const char * RegisterNames8[8] = { + "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh" }; + +// Names of 8 bit registers with REX prefix +const char * RegisterNames8x[16] = { + "al", "cl", "dl", "bl", "spl", "bpl", "sil", "dil", + "r8b", "r9b", "r10b", "r11b", "r12b", "r13b", "r14b", "r15b" }; + +// Names of 16 bit registers +const char * RegisterNames16[16] = { + "ax", "cx", "dx", "bx", "sp", "bp", "si", "di", + "r8w", "r9w", "r10w", "r11w", "r12w", "r13w", "r14w", "r15w" }; + +// Names of 32 bit registers +const char * RegisterNames32[16] = { + "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi", + "r8d", "r9d", "r10d", "r11d", "r12d", "r13d", "r14d", "r15d" }; + +// Names of 64 bit registers +const char * RegisterNames64[16] = { + "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15" }; + +// Names of segment registers +const char * RegisterNamesSeg[8] = { + "es", "cs", "ss", "ds", "fs", "gs", "hs?", "is?" }; // Last two are illegal or undocumented + +// Names of control registers +const char * RegisterNamesCR[16] = { + "cr0", "cr1 ?", "cr2", "cr3", "cr4", "cr5 ?", "cr6 ?", "cr7 ?", + "cr8", "cr9 ?", "cr10 ?", "cr11 ?", "cr12 ?", "cr13 ?", "cr14 ?", "cr15 ?" }; // Those with ? are illegal + + +// MVEX tables: Tables of the meaning of the sss bits in a MVEX prefix + +SwizSpec Sf32r[8] = { // 32-bit float or integer register permutation + {0x64B,64,4,""}, + {0x64B,64,4,"cdab"}, + {0x64B,64,4,"badc"}, + {0x64B,64,4,"dacb"}, + {0x64B,64,4,"aaaa"}, + {0x64B,64,4,"bbbb"}, + {0x64B,64,4,"cccc"}, + {0x64B,64,4,"dddd"}}; + +SwizSpec Sf64r[8] = { // 64-bit float or integer register permutation + {0x64C,64,8,""}, + {0x64C,64,8,"cdab"}, + {0x64C,64,8,"badc"}, + {0x64C,64,8,"dacb"}, + {0x64C,64,8,"aaaa"}, + {0x64C,64,8,"bbbb"}, + {0x64C,64,8,"cccc"}, + {0x64C,64,8,"dddd"}}; + +SwizSpec Sf32m[8] = { // 32-bit float memory broadcast or conversion + {0x64B,64,4,""}, + {0x04B, 4,4,"1to16"}, + {0x44B,16,4,"4to16"}, + {0x54A,32,2,"float16"}, + {0x401,16,1,"uint8"}, + {0x401,16,1,"sint8 N/A!"}, + {0x502,32,2,"uint16"}, + {0x502,32,2,"sint16"}}; + +SwizSpec Sf64m[8] = { // 64-bit float memory broadcast (no conversion) + {0x64C,64,8,""}, + {0x04C, 8,8,"1to8"}, + {0x54C,32,8,"4to8"}, + {0x64C,64,8,"N/A!"}, + {0x64C,64,8,"N/A!"}, + {0x64C,64,8,"N/A!"}, + {0x64C,64,8,"N/A!"}, + {0x64C,64,8,"N/A!"}}; + +SwizSpec Si32m[8] = { // 32-bit integer memory broadcast or conversion + {0x603,64,4,""}, + {0x003, 4,4,"1to16"}, + {0x403,16,4,"4to16"}, + {0x54A,32,2,"N/A!"}, + {0x401,16,1,"uint8"}, + {0x401,16,1,"sint8"}, + {0x502,32,2,"uint16"}, + {0x502,32,2,"sint16"}}; + +SwizSpec Si64m[8] = { // 64-bit integer memory broadcast (no conversion) + {0x604,64,8,""}, + {0x004, 8,8,"1to8"}, + {0x504,32,8,"4to8"}, + {0x604,64,8,"N/A!"}, + {0x604,64,8,"N/A!"}, + {0x604,64,8,"N/A!"}, + {0x604,64,8,"N/A!"}, + {0x604,64,8,"N/A!"}}; + +SwizSpec Uf32m[8] = { // 32-bit float memory up- or down-conversion + {0x64B,64,4,""}, + {0x04B, 4,4,"N/A!"}, + {0x54B,16,4,"N/A!"}, + {0x54A,32,2,"float16"}, + {0x401,16,1,"uint8"}, + {0x401,16,1,"sint8"}, + {0x502,32,2,"uint16"}, + {0x502,32,2,"sint16"}}; + +SwizSpec Uf64m[8] = { // 64-bit float memory, no up- or down-conversion + {0x64C,64,8,""}, + {0x64C,64,8,"N/A!"}, + {0x64C,64,8,"N/A!"}, + {0x64C,64,8,"N/A!"}, + {0x64C,64,8,"N/A!"}, + {0x64C,64,8,"N/A!"}, + {0x64C,64,8,"N/A!"}, + {0x64C,64,8,"N/A!"}}; + +SwizSpec Ui32m[8] = { // 32-bit integer memory up- or down-conversion + {0x603,64,4,""}, + {0x003, 4,4,"N/A!"}, + {0x503,16,4,"N/A!"}, + {0x54A,32,2,"N/A!"}, + {0x401,16,1,"uint8"}, + {0x401,16,1,"sint8"}, + {0x502,32,2,"uint16"}, + {0x502,32,2,"sint16"}}; + +SwizSpec Ui64m[8] = { // 64-bit integer memory, no up- or down-conversion + {0x604,64,8,""}, + {0x604,64,8,"N/A!"}, + {0x604,64,8,"N/A!"}, + {0x604,64,8,"N/A!"}, + {0x604,64,8,"N/A!"}, + {0x604,64,8,"N/A!"}, + {0x604,64,8,"N/A!"}, + {0x604,64,8,"N/A!"}}; + +// special cases: + +SwizSpec Uf32mx4[8] = { // 32-bit float memory up-conversion, broadcast * 4, vbroadcastf32x4 + {0x44B,16,4*4,""}, + {0x04B,16,4*4,"N/A!"}, + {0x54B,16,4*4,"N/A!"}, + {0x004, 8,2*4,"float16"}, + {0x003, 4,1*4,"uint8"}, + {0x003, 4,1*4,"sint8"}, + {0x004, 8,2*4,"uint16"}, + {0x004, 8,2*4,"sint16"}}; + +SwizSpec Uf64mx4[8] = { // 64-bit float memory, no up-conversion, broadcast * 4, vbroadcastf64x4 + {0x54C,32,8*4,""}, + {0x54C,32,8*4,"N/A!"}, + {0x54C,32,8*4,"N/A!"}, + {0x54C,32,8*4,"N/A!"}, + {0x54C,32,8*4,"N/A!"}, + {0x54C,32,8*4,"N/A!"}, + {0x54C,32,8*4,"N/A!"}, + {0x54C,32,8*4,"N/A!"}}; + +SwizSpec Ui32mx4[8] = { // 32-bit integer memory up-conversion, broadcast * 4, vbroadcasti32x4 + {0x403,16,4*4,""}, + {0x003,16,4*4,"N/A!"}, + {0x503,16,4*4,"N/A!"}, + {0x54A, 8,2*4,"N/A!"}, + {0x003, 4,1*4,"uint8"}, + {0x003, 4,1*4,"sint8"}, + {0x004, 8,2*4,"uint16"}, + {0x004, 8,2*4,"sint16"}}; + +SwizSpec Ui64mx4[8] = { // 64-bit integer memory, no up-conversion, broadcast * 4, vbroadcasti64x4 + {0x504,32,8*4,""}, + {0x504,32,8*4,"N/A!"}, + {0x504,32,8*4,"N/A!"}, + {0x504,32,8*4,"N/A!"}, + {0x504,32,8*4,"N/A!"}, + {0x504,32,8*4,"N/A!"}, + {0x504,32,8*4,"N/A!"}, + {0x504,32,8*4,"N/A!"}}; + +SwizSpec Si32mHalf[8] = { // 32-bit integer memory broadcast with conversion to double (VCVTDQ2PD) + {0x503,32,4,""}, + {0x003, 4,4,"1to8"}, + {0x403,16,4,"4to8"}, + {0x503,32,4,"N/A!"}, + {0x503,32,4,"N/A!"}, + {0x503,32,4,"N/A!"}, + {0x503,32,4,"N/A!"}, + {0x503,32,4,"N/A!"}}; + +SwizSpec Sf32mHalf[8] = { // 32-bit float memory broadcast or conversion (vcvtps2pd) + {0x54B,32,4,""}, + {0x04B, 4,4,"1to8"}, + {0x44B,16,4,"4to8"}, + {0x54A,32,2,"N/A!"}, + {0x401,16,1,"N/A!"}, + {0x401,16,1,"N/A!"}, + {0x502,32,2,"N/A!"}, + {0x502,32,2,"N/A!"}}; + +SwizSpec Snone[8] = { // No swizzle + {0x600,64,8*4,""}, + {0x600,64,8*4,"N/A!"}, + {0x600,64,8*4,"N/A!"}, + {0x600,64,8*4,"N/A!"}, + {0x600,64,8*4,"N/A!"}, + {0x600,64,8*4,"N/A!"}, + {0x600,64,8*4,"N/A!"}, + {0x600,64,8*4,"N/A!"}}; + +SwizSpec Sf32mfmadd233[8] = { // 32-bit float memory, without register swizzle and limited broadcast, vfmadd233ps + {0x64B,64,4,""}, + {0x04B, 4,4,"N/A!"}, + {0x44B,16,4,"4to16"}, + {0x54A,32,2,"N/A!"}, + {0x401,16,1,"N/A!"}, + {0x401,16,1,"N/A!"}, + {0x502,32,2,"N/A!"}, + {0x502,32,2,"N/A!"}}; + +SwizSpec Sdummy[8] = { // For unused entries + {0,0,0,""}, + {0,0,0,"??"}, + {0,0,0,"??"}, + {0,0,0,"??"}, + {0,0,0,"??"}, + {0,0,0,"??"}, + {0,0,0,"??"}, + {0,0,0,"??"}}; + +SwizSpec Signore[8] = { // sss bits ignored or used only for sae. Offset multiplier defined + {0x603,64,4,""}, + {0x603,64,4,""}, + {0x603,64,4,""}, + {0x603,64,4,""}, + {0x603,64,4,""}, + {0x603,64,4,""}, + {0x603,64,4,""}, + {0x603,64,4,""}}; + +SwizSpec Signore1[8] = { // sss bits ignored or used only for sae. Offset multiplier defined, vector size not defined + {0x000,64,4,""}, + {0x000,64,4,""}, + {0x000,64,4,""}, + {0x000,64,4,""}, + {0x000,64,4,""}, + {0x000,64,4,""}, + {0x000,64,4,""}, + {0x000,64,4,""}}; + +// Table of swizzle tables +SwizSpec const * SwizTables[][2] = { + {Sdummy,Sdummy}, // 0 no swizzle, sss must be zero + {Signore,Signore}, // 1 sss ignored or used only for sae, offset multiplier defined + {Signore1,Signore1}, // 2 sss ignored or used only for sae, offset multiplier defined, no vector size + {Sdummy,Sdummy}, // 3 unused + {Sf32r,Sf32m}, // 4 Sf32 + {Sf64r,Sf64m}, // 5 Sf64 + {Sf32r,Si32m}, // 6 Si32 + {Sf64r,Si64m}, // 7 Si64 + {Sdummy,Uf32m}, // 8 Uf32 + {Sdummy,Uf64m}, // 9 Uf64 + {Sf32r,Ui32m}, // A Ui32 + {Sf64r,Ui64m}, // B Ui64 + {Sdummy,Uf32m}, // C Df32 + {Sdummy,Uf64m}, // D Df64 + {Sf32r,Ui32m}, // E Di32 + {Sf64r,Ui64m}, // F Di64 + // special cases + {Sdummy,Uf32mx4}, // 10 Uf32 vbroadcastf32x4 + {Sdummy,Uf64mx4}, // 11 Uf64 vbroadcastf64x4 + {Sdummy,Ui32mx4}, // 12 Ui32 vbroadcasti32x4 + {Sdummy,Ui64mx4}, // 13 Ui64 vbroadcasti64x4 + {Sf32r,Si32mHalf}, // 14 Si32 vcvtdq2pd, vcvtudq2pd + {Sf32r,Sf32mHalf}, // 15 Sf32 vcvtps2pd + {Snone,Sf32mfmadd233}// 16 Sf32 without register swizzle and limited broadcast, vfmadd233ps +}; + +SwizSpec Sround_1[8] = { // Register operand rounding mode and suppress all exceptions + {0x64B,32,4,"rn"}, // syntax 1 + {0x64B,32,4,"rd"}, + {0x64B,32,4,"ru"}, + {0x64B,32,4,"rz"}, + {0x64B,32,4,"rn-sae"}, + {0x64B,32,4,"rd-sae"}, + {0x64B,32,4,"ru-sae"}, + {0x64B,32,4,"rz-sae"}}; + +SwizSpec Sround_2[8] = { // Register operand rounding mode and suppress all exceptions + {0x64B,32,4,"rn"}, // alternative syntax + {0x64B,32,4,"rd"}, + {0x64B,32,4,"ru"}, + {0x64B,32,4,"rz"}, + {0x64B,32,4,"rn} {sae"}, + {0x64B,32,4,"rd} {sae"}, + {0x64B,32,4,"ru} {sae"}, + {0x64B,32,4,"rz} {sae"}}; + +// Table of swizzle tables for rounding mode +SwizSpec const * SwizRoundTables[1][2] = { + {Sround_1,Sround_2} +}; + +// EVEX tables: Tables of rounding mode names for EVEX +const char * EVEXRoundingNames[5] = { + "rn-sae", "rd-sae", "ru-sae", "rz-sae", "sae" +}; + diff --git a/programs/develop/objconv/stdafx.cpp b/programs/develop/objconv/stdafx.cpp new file mode 100644 index 0000000000..2bafc024fd --- /dev/null +++ b/programs/develop/objconv/stdafx.cpp @@ -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" diff --git a/programs/develop/objconv/stdafx.h b/programs/develop/objconv/stdafx.h new file mode 100644 index 0000000000..6f950e5079 --- /dev/null +++ b/programs/develop/objconv/stdafx.h @@ -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 +#include +#include +#include +#ifdef _MSC_VER // For Microsoft compiler only: + #include // File in/out function headers + #include + #include + #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