⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rar3vm.cpp

📁 7-Zip 是一款号称有着现今最高压缩比的压缩软件
💻 CPP
📖 第 1 页 / 共 3 页
字号:
// Rar3Vm.cpp
// According to unRAR license, this code may not be used to develop
// a program that creates RAR archives

/*
Note:
  Due to performance considerations Rar VM may set Flags C incorrectly
  for some operands (SHL x, 0, ... ).
  Check implementation of concrete VM command
  to see if it sets flags right.
*/

#include "StdAfx.h"

#include "Rar3Vm.h"

extern "C"
{
#include "../../../../C/Alloc.h"
#include "../../../../C/7zCrc.h"
}

namespace NCompress {
namespace NRar3 {

UInt32 CMemBitDecoder::ReadBits(int numBits)
{
  UInt32 res = 0;
  for (;;)
  {
    Byte b = _bitPos < _bitSize ? _data[_bitPos >> 3] : 0;
    int avail = (int)(8 - (_bitPos & 7));
    if (numBits <= avail)
    {
      _bitPos += numBits;
      return res | (b >> (avail - numBits)) & ((1 << numBits) - 1);
    }
    numBits -= avail;
    res |= (UInt32)(b & ((1 << avail) - 1)) << numBits;
    _bitPos += avail;
  }
}

UInt32 CMemBitDecoder::ReadBit() { return ReadBits(1); }

namespace NVm {

static const UInt32 kStackRegIndex = kNumRegs - 1;

static const UInt32 FLAG_C = 1;
static const UInt32 FLAG_Z = 2;
static const UInt32 FLAG_S = 0x80000000;

static const Byte CF_OP0 = 0;
static const Byte CF_OP1 = 1;
static const Byte CF_OP2 = 2;
static const Byte CF_OPMASK = 3;
static const Byte CF_BYTEMODE = 4;
static const Byte CF_JUMP = 8;
static const Byte CF_PROC = 16;
static const Byte CF_USEFLAGS = 32;
static const Byte CF_CHFLAGS = 64;

static Byte kCmdFlags[]=
{
  /* CMD_MOV   */ CF_OP2 | CF_BYTEMODE,
  /* CMD_CMP   */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS,
  /* CMD_ADD   */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS,
  /* CMD_SUB   */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS,
  /* CMD_JZ    */ CF_OP1 | CF_JUMP | CF_USEFLAGS,
  /* CMD_JNZ   */ CF_OP1 | CF_JUMP | CF_USEFLAGS,
  /* CMD_INC   */ CF_OP1 | CF_BYTEMODE | CF_CHFLAGS,
  /* CMD_DEC   */ CF_OP1 | CF_BYTEMODE | CF_CHFLAGS,
  /* CMD_JMP   */ CF_OP1 | CF_JUMP,
  /* CMD_XOR   */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS,
  /* CMD_AND   */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS,
  /* CMD_OR    */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS,
  /* CMD_TEST  */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS,
  /* CMD_JS    */ CF_OP1 | CF_JUMP | CF_USEFLAGS,
  /* CMD_JNS   */ CF_OP1 | CF_JUMP | CF_USEFLAGS,
  /* CMD_JB    */ CF_OP1 | CF_JUMP | CF_USEFLAGS,
  /* CMD_JBE   */ CF_OP1 | CF_JUMP | CF_USEFLAGS,
  /* CMD_JA    */ CF_OP1 | CF_JUMP | CF_USEFLAGS,
  /* CMD_JAE   */ CF_OP1 | CF_JUMP | CF_USEFLAGS,
  /* CMD_PUSH  */ CF_OP1,
  /* CMD_POP   */ CF_OP1,
  /* CMD_CALL  */ CF_OP1 | CF_PROC,
  /* CMD_RET   */ CF_OP0 | CF_PROC,
  /* CMD_NOT   */ CF_OP1 | CF_BYTEMODE,
  /* CMD_SHL   */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS,
  /* CMD_SHR   */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS,
  /* CMD_SAR   */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS,
  /* CMD_NEG   */ CF_OP1 | CF_BYTEMODE | CF_CHFLAGS,
  /* CMD_PUSHA */ CF_OP0,
  /* CMD_POPA  */ CF_OP0,
  /* CMD_PUSHF */ CF_OP0 | CF_USEFLAGS,
  /* CMD_POPF  */ CF_OP0 | CF_CHFLAGS,
  /* CMD_MOVZX */ CF_OP2,
  /* CMD_MOVSX */ CF_OP2,
  /* CMD_XCHG  */ CF_OP2 | CF_BYTEMODE,
  /* CMD_MUL   */ CF_OP2 | CF_BYTEMODE,
  /* CMD_DIV   */ CF_OP2 | CF_BYTEMODE,
  /* CMD_ADC   */ CF_OP2 | CF_BYTEMODE | CF_USEFLAGS | CF_CHFLAGS ,
  /* CMD_SBB   */ CF_OP2 | CF_BYTEMODE | CF_USEFLAGS | CF_CHFLAGS ,
  /* CMD_PRINT */ CF_OP0
};

CVm::CVm(): Mem(NULL) {}

bool CVm::Create()
{
  if (Mem == NULL)
    Mem = (Byte *)::MyAlloc(kSpaceSize + 4);
  return (Mem != NULL);
}

CVm::~CVm()
{
  ::MyFree(Mem);
}

// CVm::Execute can change CProgram object: it clears progarm if VM returns error.

bool CVm::Execute(CProgram *prg, const CProgramInitState *initState,
    CBlockRef &outBlockRef, CRecordVector<Byte> &outGlobalData)
{
  memcpy(R, initState->InitR, sizeof(initState->InitR));
  R[kStackRegIndex] = kSpaceSize;
  R[kNumRegs] = 0;
  Flags = 0;

  UInt32 globalSize = MyMin((UInt32)initState->GlobalData.Size(), kGlobalSize);
  if (globalSize != 0)
    memcpy(Mem + kGlobalOffset, &initState->GlobalData[0], globalSize);
  UInt32 staticSize = MyMin((UInt32)prg->StaticData.Size(), kGlobalSize - globalSize);
  if (staticSize != 0)
    memcpy(Mem + kGlobalOffset + globalSize, &prg->StaticData[0], staticSize);

  bool res = true;
  #ifdef RARVM_STANDARD_FILTERS
  if (prg->StandardFilterIndex >= 0)
    ExecuteStandardFilter(prg->StandardFilterIndex);
  else
  #endif
  {
    res = ExecuteCode(prg);
    if (!res)
      prg->Commands[0].OpCode = CMD_RET;
  }
  UInt32 newBlockPos = GetFixedGlobalValue32(NGlobalOffset::kBlockPos) & kSpaceMask;
  UInt32 newBlockSize = GetFixedGlobalValue32(NGlobalOffset::kBlockSize) & kSpaceMask;
  if (newBlockPos + newBlockSize >= kSpaceSize)
    newBlockPos = newBlockSize = 0;
  outBlockRef.Offset = newBlockPos;
  outBlockRef.Size = newBlockSize;

  outGlobalData.Clear();
  UInt32 dataSize = GetFixedGlobalValue32(NGlobalOffset::kGlobalMemOutSize);
  dataSize = MyMin(dataSize, kGlobalSize - kFixedGlobalSize);
  if (dataSize != 0)
  {
    dataSize += kFixedGlobalSize;
    outGlobalData.Reserve(dataSize);
    for (UInt32 i = 0; i < dataSize; i++)
      outGlobalData.Add(Mem[kGlobalOffset + i]);
  }
  return res;
}


#define SET_IP(IP) \
  if ((IP) >= numCommands) return true; \
  if (--maxOpCount <= 0) return false; \
  cmd = commands + (IP);

#define GET_FLAG_S_B(res) (((res) & 0x80) ? FLAG_S : 0)
#define SET_IP_OP1 { UInt32 val = GetOperand32(&cmd->Op1); SET_IP(val); }
#define FLAGS_UPDATE_SZ Flags = res == 0 ? FLAG_Z : res & FLAG_S
#define FLAGS_UPDATE_SZ_B Flags = (res & 0xFF) == 0 ? FLAG_Z : GET_FLAG_S_B(res)

UInt32 CVm::GetOperand32(const COperand *op) const
{
  switch(op->Type)
  {
    case OP_TYPE_REG: return R[op->Data];
    case OP_TYPE_REGMEM: return GetValue32(&Mem[(op->Base + R[op->Data]) & kSpaceMask]);
    default: return op->Data;
  }
}

void CVm::SetOperand32(const COperand *op, UInt32 val)
{
  switch(op->Type)
  {
    case OP_TYPE_REG: R[op->Data] = val; return;
    case OP_TYPE_REGMEM: SetValue32(&Mem[(op->Base + R[op->Data]) & kSpaceMask], val); return;
  }
}

Byte CVm::GetOperand8(const COperand *op) const
{
  switch(op->Type)
  {
    case OP_TYPE_REG: return (Byte)R[op->Data];
    case OP_TYPE_REGMEM: return Mem[(op->Base + R[op->Data]) & kSpaceMask];;
    default: return (Byte)op->Data;
  }
}

void CVm::SetOperand8(const COperand *op, Byte val)
{
  switch(op->Type)
  {
    case OP_TYPE_REG: R[op->Data] = (R[op->Data] & 0xFFFFFF00) | val; return;
    case OP_TYPE_REGMEM: Mem[(op->Base + R[op->Data]) & kSpaceMask] = val; return;
  }
}

UInt32 CVm::GetOperand(bool byteMode, const COperand *op) const
{
  if (byteMode)
    return GetOperand8(op);
  return GetOperand32(op);
}

void CVm::SetOperand(bool byteMode, const COperand *op, UInt32 val)
{
  if (byteMode)
    SetOperand8(op, (Byte)(val & 0xFF));
  else
    SetOperand32(op, val);
}

bool CVm::ExecuteCode(const CProgram *prg)
{
  Int32 maxOpCount = 25000000;
  const CCommand *commands = &prg->Commands[0];
  const CCommand *cmd = commands;
  UInt32 numCommands = prg->Commands.Size();
  for (;;)
  {
    switch(cmd->OpCode)
    {
      #ifndef RARVM_NO_VM
      
      case CMD_MOV:
        SetOperand32(&cmd->Op1, GetOperand32(&cmd->Op2));
        break;
      case CMD_MOVB:
        SetOperand8(&cmd->Op1, GetOperand8(&cmd->Op2));
        break;
      case CMD_CMP:
        {
          UInt32 v1 = GetOperand32(&cmd->Op1);
          UInt32 res = v1 - GetOperand32(&cmd->Op2);
          Flags = res == 0 ? FLAG_Z : (res > v1) | (res & FLAG_S);
        }
        break;
      case CMD_CMPB:
        {
          Byte v1 = GetOperand8(&cmd->Op1);
          Byte res = v1 - GetOperand8(&cmd->Op2);
          res &= 0xFF;
          Flags = res == 0 ? FLAG_Z : (res > v1) | GET_FLAG_S_B(res);
        }
        break;
      case CMD_ADD:
        {
          UInt32 v1 = GetOperand32(&cmd->Op1);
          UInt32 res = v1 + GetOperand32(&cmd->Op2);
          SetOperand32(&cmd->Op1, res);
          Flags = (res < v1) | (res == 0 ? FLAG_Z : (res & FLAG_S));
        }
        break;
      case CMD_ADDB:
        {
          Byte v1 = GetOperand8(&cmd->Op1);
          Byte res = v1 + GetOperand8(&cmd->Op2);
          res &= 0xFF;
          SetOperand8(&cmd->Op1, (Byte)res);
          Flags = (res < v1) | (res == 0 ? FLAG_Z : GET_FLAG_S_B(res));
        }
        break;
      case CMD_ADC:
        {
          UInt32 v1 = GetOperand(cmd->ByteMode, &cmd->Op1);
          UInt32 FC = (Flags & FLAG_C);
          UInt32 res = v1 + GetOperand(cmd->ByteMode, &cmd->Op2) + FC;
          if (cmd->ByteMode)
            res &= 0xFF;
          SetOperand(cmd->ByteMode, &cmd->Op1, res);
          Flags = (res < v1 || res == v1 && FC) | (res == 0 ? FLAG_Z : (res & FLAG_S));
        }
        break;
      case CMD_SUB:
        {
          UInt32 v1 = GetOperand32(&cmd->Op1);
          UInt32 res = v1 - GetOperand32(&cmd->Op2);
          SetOperand32(&cmd->Op1, res);
          Flags = res == 0 ? FLAG_Z : (res > v1) | (res & FLAG_S);
        }
        break;
      case CMD_SUBB:
        {
          UInt32 v1 = GetOperand8(&cmd->Op1);
          UInt32 res = v1 - GetOperand8(&cmd->Op2);
          SetOperand8(&cmd->Op1, (Byte)res);
          Flags = res == 0 ? FLAG_Z : (res > v1) | (res & FLAG_S);
        }
        break;
      case CMD_SBB:
        {
          UInt32 v1 = GetOperand(cmd->ByteMode, &cmd->Op1);
          UInt32 FC = (Flags & FLAG_C);
          UInt32 res = v1 - GetOperand(cmd->ByteMode, &cmd->Op2) - FC;
          // Flags = res == 0 ? FLAG_Z : (res > v1 || res == v1 && FC) | (res & FLAG_S);
          if (cmd->ByteMode)
            res &= 0xFF;
          SetOperand(cmd->ByteMode, &cmd->Op1, res);
          Flags = (res > v1 || res == v1 && FC) | (res == 0 ? FLAG_Z : (res & FLAG_S));
        }
        break;
      case CMD_INC:
        {
          UInt32 res = GetOperand32(&cmd->Op1) + 1;
          SetOperand32(&cmd->Op1, res);
          FLAGS_UPDATE_SZ;
        }
        break;
      case CMD_INCB:
        {
          Byte res = GetOperand8(&cmd->Op1) + 1;
          SetOperand8(&cmd->Op1, res);;
          FLAGS_UPDATE_SZ_B;
        }
        break;
      case CMD_DEC:
        {
          UInt32 res = GetOperand32(&cmd->Op1) - 1;
          SetOperand32(&cmd->Op1, res);
          FLAGS_UPDATE_SZ;
        }
        break;
      case CMD_DECB:
        {
          Byte res = GetOperand8(&cmd->Op1) - 1;
          SetOperand8(&cmd->Op1, res);;
          FLAGS_UPDATE_SZ_B;
        }
        break;
      case CMD_XOR:
        {
          UInt32 res = GetOperand32(&cmd->Op1) ^ GetOperand32(&cmd->Op2);
          SetOperand32(&cmd->Op1, res);
          FLAGS_UPDATE_SZ;
        }
        break;
      case CMD_XORB:
        {
          Byte res = GetOperand8(&cmd->Op1) ^ GetOperand8(&cmd->Op2);
          SetOperand8(&cmd->Op1, res);
          FLAGS_UPDATE_SZ_B;
        }
        break;
      case CMD_AND:

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -