?? args-x86.c
字號:
/* * libDASM * * Copyright (C) 2000-2003 Patrick Alken * This library comes with absolutely NO WARRANTY * * Should you choose to use and/or modify this source code, please * do so under the terms of the GNU General Public License under which * this library is distributed. * * $Id: args-x86.c,v 1.3 2004/09/02 00:11:59 pa33 Exp $ * * This module is used by the disassembler to construct the argument * string for a particular opcode. */#include <stdio.h>#include <string.h>#include <assert.h>#include "args-x86.h"#include "common-x86.h"#include "inames-x86.h"#include "operands-x86.h"#include "prefix-x86.h"#include "regs-x86.h"/* * Top-level includes */#include "libDASM.h"static char *x86operandRegister(struct x86matchInfo *ptr, int opnum, char *errstr);static int x86operandEffectiveAddress(struct disasmWorkspace *ws, struct x86matchInfo *ptr, unsigned int operand, char *str);static int x86operandSegOff(unsigned char **data, unsigned int operand, char *str);static int x86operandMemoryOffset(struct disasmWorkspace *ws, unsigned char **data, char *str);static unsigned long x86getImmediate(unsigned char **data, unsigned int flags, int *err);/* * The following x86RegisterCodesXX[] tables correspond to table 3.1 * in the Intel Architecture Software Developer's Manual, Vol 2. They * are used to determine the register specified by a +rb/+rw/+rd * code added to the last byte of an opcode. The value added * to the last opcode byte is between 0 and 7, and indexes these * tables to get the correct register. *//* +rb - 8 bit register operand */static int x86RegisterCodes8[] = { R_AL, R_CL, R_DL, R_BL, R_AH, R_CH, R_DH, R_BH};/* +rw - 16 bit register operand */static int x86RegisterCodes16[] = { R_AX, R_CX, R_DX, R_BX, R_SP, R_BP, R_SI, R_DI};/* +rd - 32 bit register operand */static int x86RegisterCodes32[] = { R_EAX, R_ECX, R_EDX, R_EBX, R_ESP, R_EBP, R_ESI, R_EDI};static char *x86SegmentRegisters[] = { "es", "cs", "ss", "ds", "fs", "gs", "?s", "?s"};/*x86constructArguments() Construct the correct arguments for the instruction 'ptr'.Inputs: ws - disasm workspace data - data buffer containing instruction we are disassembling ptr - instruction matching 'data' outbuf - where to store arguments address - address of this instruction in the file or memory we are currently disassembling; when given, relative addresses (such as in a CALL or JMP) will be added to this address to calculate an exact target address.Return: 1 upon success 0 upon failure (error message goes in outbuf)Side effects: On success, outbuf will contain instruction name and arguments On failure, outbuf will contain error message 'data' variable may be advanced due to reading of immediate bytes, modrm bytes, etc*/intx86constructArguments(struct disasmWorkspace *ws, unsigned char **data, struct x86matchInfo *ptr, char *outbuf, unsigned int address){ int ii; /* looping */ struct x86OpCode *opPtr; /* opcode pointer */ char tmpbuf[MAXLINE]; /* temporary buffer */ char *origout; /* original outbuf */ long bias; /* eip relative address bias */ assert(data && *data && ptr && outbuf); /* * bias is initialized to the 2's compliment of the instruction's * actual address in the buffer. We do this to compute the * size of the instruction by adding the new value of *data. * The resulting equation is this: * * bias = NEW_data_addr - OLD_data_addr * * which is precisely what we want. * * Note the [-1] subscript of the character array reference is * to compensate for the fact that the instruction's opcode has * already been "fetched" by the disassembly engine. * * --2004aug30 saf2 * * The purpose of this is for relative operands which are * defined relative to the instruction after the current * instruction. In order to compute an exact address, we * need to know the size of the current opcode. This bias * variable is set to that size in the section below on * relative operands. * * -- Patrick Alken */ bias = -((unsigned long)(&((*data)[-1]))); opPtr = ptr->opPtr; origout = outbuf; if (ws->prefixFlags & PX_LOCK) outbuf += sprintf(outbuf, "%s", "lock "); else if (ws->prefixFlags & PX_REP) outbuf += sprintf(outbuf, "%s", "rep "); else if (ws->prefixFlags & PX_REPE) outbuf += sprintf(outbuf, "%s", "repe "); else if (ws->prefixFlags & PX_REPNE) outbuf += sprintf(outbuf, "%s", "repne "); /* * Write instruction name to outbuf */ outbuf += sprintf(outbuf, "%s", x86InstructionNames[opPtr->name]); /* * Loop through operands and add them to outbuf */ for (ii = 0; ii < opPtr->OperandCount; ++ii) { if (ii == 0) *outbuf++ = ' '; else { *outbuf++ = ','; *outbuf++ = ' '; } if (opPtr->operands[ii] & NEAR) outbuf += sprintf(outbuf, "near "); else if (opPtr->operands[ii] & FAR) outbuf += sprintf(outbuf, "far "); else if (opPtr->operands[ii] & SHORT) outbuf += sprintf(outbuf, "short "); if (opPtr->operands[ii] & (REGISTER | REG_MMX | REG_XMM)) { char *regstr; /* * We have a register operand - determine which register * and print it to outbuf */ regstr = x86operandRegister(ptr, ii, tmpbuf); if (regstr) outbuf += sprintf(outbuf, "%s", regstr); else { strcpy(origout, tmpbuf); return (0); /* error */ } } /* if (opPtr->operands[ii] & (REGISTER | REG_MMX | REG_XMM)) */ else if (opPtr->operands[ii] & IMMEDIATE) { unsigned long value; int err; err = 0; value = x86getImmediate(data, opPtr->operands[ii], &err); if (err) { sprintf(origout, "x86constructArguments: x86getImmediate failed for instruction: %s", x86InstructionNames[opPtr->name]); return (0); } outbuf += sprintf(outbuf, "0x%lx", value); } /* if (opPtr->operands[ii] & IMMEDIATE) */ else if (opPtr->operands[ii] & (REGMEM | MEMORY)) { int ret; /* * We have an rm8/rm16/rm32 operand */ ret = x86operandEffectiveAddress(ws, ptr, opPtr->operands[ii], tmpbuf); if (ret >= 0) outbuf += sprintf(outbuf, "%s", tmpbuf); else { strcpy(origout, tmpbuf); return (0); /* error */ } } /* if (opPtr->operands[ii] & (REGMEM | MEMORY)) */ else if (opPtr->operands[ii] & RELATIVE) { unsigned long value; int err; /* * Relative operands (rel8/16/32) are bytes following * the opcode specifying a relative address */ err = 0; value = x86getImmediate(data, opPtr->operands[ii], &err); if (err) { sprintf(origout, "x86constructArguments: x86getImmediate failed for instruction: %s", x86InstructionNames[opPtr->name]); return (0); } /* * Note: this code was contributed by Samuel Falvo II * <kc5tja =at= arrl net> */ bias += (unsigned long) (*data); if ((unsigned char) *(opPtr->mcode) == 0x0F) { /* two-byte branch */ bias++; } outbuf += sprintf(outbuf, "+0x%lx", value); /* * Store the exact target address in ws->effectiveAddress * so that the calling program can use it to look up * symbols/functions corresponding to this relative * address. */ ws->effectiveAddress = address + value + bias; } /* if (opPtr->operands[ii] & RELATIVE) */ else if (opPtr->operands[ii] & SEG16) { int ret; /* * This operand is ptr16:16 or ptr16:32. * This means we need an expression of the form * segment:offset, where segment is the number of bits on * the left of the colon, and offset is the number of bits * on the right. */ ret = x86operandSegOff(data, opPtr->operands[ii], tmpbuf); if (ret >= 0) outbuf += sprintf(outbuf, "%s", tmpbuf); else { strcpy(origout, tmpbuf); return (0); /* error */ } } /* if (opPtr->operands[ii] & SEG16) */ else if (opPtr->operands[ii] & REG_FPU) { /* * Floating point stack register */ assert(ptr->fpucode >= 0); assert(ptr->fpucode <= 7); outbuf += sprintf(outbuf, "%s", x86RegistersDASM[R_ST0 + ptr->fpucode].name); } /* if (opPtr->operands[ii] & REG_FPU) */ else if (opPtr->operands[ii] & REG_SR) { /* * We have an Sreg operand (segment register). The REG * field of the ModR/M byte specifies which register to use. * According to IAS, Vol 2, the values of the segment registers * are as follows: * * ES = 0 * CS = 1 * SS = 2 * DS = 3 * FS = 4 * GS = 5 */ outbuf += sprintf(outbuf, "%s", x86SegmentRegisters[ptr->msinfo.reg]); } /* if (opPtr->operands[ii] & REG_SR) */ else if (opPtr->operands[ii] & REG_CONTROL) { /* * According to IAS, Vol 2. the REG field of the ModR/M * byte specifies the control register */ outbuf += sprintf(outbuf, "%s", x86RegistersDASM[R_CR0 + ptr->msinfo.reg].name); } /* if (opPtr->operands[ii] & REG_CONTROL) */ else if (opPtr->operands[ii] & REG_DEBUG) { /* * According to IAS, Vol 2. the REG field of the ModR/M * byte specifies the debug register */ outbuf += sprintf(outbuf, "%s", x86RegistersDASM[R_DR0 + ptr->msinfo.reg].name); } /* if (opPtr->operands[ii] & REG_DEBUG) */ else if (opPtr->operands[ii] & MEMOFFS) { int ret; /* * We have a moffs8/16/32 operand. This is a 16 or 32 bit * offset (depending on the size attributes of the instruction) * which comes after the opcode. The 8/16/32 following the moffs * specify the size of the data at the offset location. */ ret = x86operandMemoryOffset(ws, data, tmpbuf); if (ret >= 0) outbuf += sprintf(outbuf, "%s", tmpbuf); else { strcpy(origout, tmpbuf); return (0); /* error */ } } /* if (opPtr->operands[ii] & MEMOFFS) */ else if (opPtr->operands[ii] & CONSTANT) { /* * The operand is a numerical constant whose value * is stored in opinfo[ii] */ assert(opPtr->opinfo[ii] != NOOPARG); outbuf += sprintf(outbuf, "%d", opPtr->opinfo[ii]); } /* if (opPtr->operands[ii] & CONSTANT) */ } /* for (ii = 0; ii < opPtr->OperandCount; ++ii) */ *outbuf = '\0';
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -