📄 assembl.cpp
字号:
else if (match & MA_RNG)
strcpy(errtext,"Constant out of expected range");
else
strcpy(errtext,"Erroneous command");
goto error;
};
// Exact match found. Now construct the code.
hasrm=0; // Whether command has ModR/M byte
hassib=0; // Whether command has SIB byte
dispsize=0; // Size of displacement (if any)
immsize=0; // Size of immediate data (if any)
segment=SEG_UNDEF; // Necessary segment prefix
jmpsize=0; // No relative jumps
memset(tcode,0,sizeof(tcode));
*(ulong *)tcode=pd->code & pd->mask;
memset(tmask,0,sizeof(tmask));
*(ulong *)tmask=pd->mask;
i=pd->len-1; // Last byte of command itself
if (rep) i++; // REPxx prefixes count as extra byte
// In some cases at least one operand must have explicit size declaration (as
// in MOV [EAX],1). This preliminary check does not include all cases.
if (pd->bits==WW || pd->bits==WS || pd->bits==WP)
{
if (datasize==0)
{
strcpy(errtext,"Please specify operand size");
goto error;
}
else if (datasize>1)
tcode[i]|=0x01; // WORD or DWORD size of operands
tmask[i]|=0x01;
}
else if (pd->bits==W3)
{
if (datasize==0)
{
strcpy(errtext,"Please specify operand size");
goto error;
}
else if (datasize>1)
tcode[i]|=0x08; // WORD or DWORD size of operands
tmask[i]|=0x08;
};
// Present suffix of 3DNow! command as immediate byte operand.
if ((pd->type & C_TYPEMASK)==C_NOW)
{
immsize=1;
immediate=(pd->code>>16) & 0xFF;
};
// Process operands again, this time constructing the code.
anydisp=anyimm=anyjmp=0;
for (j=0; j<3; j++)
{ // Up to 3 operands
op=aop+j;
if (j==0)
arg=pd->arg1;
else if
(j==1) arg=pd->arg2;
else
arg=pd->arg3;
if (arg==NNN)
break; // All operands processed
switch (arg)
{
case REG: // Integer register in Reg field
case RG4: // Integer 4-byte register in Reg field
case RMX: // MMX register MMx
case R3D: // 3DNow! register MMx
case CRX: // Control register CRx
case DRX: // Debug register DRx
hasrm=1;
if (op->index<8)
{
tcode[i+1]|=(char)(op->index<<3);
tmask[i+1]|=0x38;
};
break;
case RCM: // Integer register in command byte
case RST: // FPU register (ST(i)) in command byte
if (op->index<8)
{
tcode[i]|=(char)op->index;
tmask[i]|=0x07;
};
break;
case RAC: // Accumulator (AL/AX/EAX, implicit)
case RAX: // AX (2-byte, implicit)
case RDX: // DX (16-bit implicit port address)
case RCL: // Implicit CL register (for shifts)
case RS0: // Top of FPU stack (ST(0))
case MDE: // Destination in string op's ([EDI])
case C01: // Implicit constant 1 (for shifts)
break; // Simply skip implicit operands
case MSO: // Source in string op's ([ESI])
case MXL: // XLAT operand ([EBX+AL])
if (op->segment!=SEG_UNDEF && op->segment!=SEG_DS)
segment=op->segment;
break;
case MRG: // Memory/register in ModRM byte
case MRJ: // Memory/reg in ModRM as JUMP target
case MR1: // 1-byte memory/register in ModRM byte
case MR2: // 2-byte memory/register in ModRM byte
case MR4: // 4-byte memory/register in ModRM byte
case RR4: // 4-byte memory/register (register only)
case MR8: // 8-byte memory/MMX register in ModRM
case RR8: // 8-byte MMX register only in ModRM
case MRD: // 8-byte memory/3DNow! register in ModRM
case RRD: // 8-byte memory/3DNow! (register only)
hasrm=1;
if (op->type!=MRG)
{ // Register in ModRM byte
tcode[i+1]|=0xC0;
tmask[i+1]|=0xC0;
if (op->index<8)
{
tcode[i+1]|=(char)op->index;
tmask[i+1]|=0x07;
};
break;
}; // Note: NO BREAK, continue with address
case MMA: // Memory address in ModRM byte for LEA
case MML: // Memory in ModRM byte (for LES)
case MMS: // Memory in ModRM byte (as SEG:OFFS)
case MM6: // Memory in ModRm (6-byte descriptor)
case MMB: // Two adjacent memory locations (BOUND)
case MD2: // Memory in ModRM byte (16-bit integer)
case MB2: // Memory in ModRM byte (16-bit binary)
case MD4: // Memory in ModRM byte (32-bit integer)
case MD8: // Memory in ModRM byte (64-bit integer)
case MDA: // Memory in ModRM byte (80-bit BCD)
case MF4: // Memory in ModRM byte (32-bit float)
case MF8: // Memory in ModRM byte (64-bit float)
case MFA: // Memory in ModRM byte (80-bit float)
case MFE: // Memory in ModRM byte (FPU environment)
case MFS: // Memory in ModRM byte (FPU state)
case MFX: // Memory in ModRM byte (ext. FPU state)
hasrm=1; displacement=op->offset; anydisp=op->anyoffset;
if (op->base<0 && op->index<0)
{
dispsize=4; // Special case of immediate address
if (op->segment!=SEG_UNDEF && op->segment!=SEG_DS)
segment=op->segment;
tcode[i+1]|=0x05;
tmask[i+1]|=0xC7; }
else if (op->index<0 && op->base!=REG_ESP)
{
tmask[i+1]|=0xC0; // SIB byte unnecessary
if (op->offset==0 && op->anyoffset==0 && op->base!=REG_EBP)
; // [EBP] always requires offset
else if ((constsize & 1)!=0 && ((op->offset>=-128 && op->offset<128) || op->anyoffset!=0) )
{
tcode[i+1]|=0x40; // Disp8
dispsize=1;
}
else
{
tcode[i+1]|=0x80; // Disp32
dispsize=4;
};
if (op->base<8)
{
if (op->segment!=SEG_UNDEF && op->segment!=addr32[op->base].defseg)
segment=op->segment;
tcode[i+1]|= (char)op->base; // Note that case [ESP] has base<0.
tmask[i+1]|=0x07;
}
else
segment=op->segment;
}
else
{ // SIB byte necessary
hassib=1;
if (op->base==REG_EBP && // EBP as base requires offset, optimize
op->index>=0 && op->scale==1 && op->offset==0 && op->anyoffset==0)
{
op->base=op->index; op->index=REG_EBP;
};
if (op->index==REG_ESP && // ESP cannot be an index, reorder
op->scale<=1)
{
op->index=op->base; op->base=REG_ESP; op->scale=1;
};
if (op->base<0 && // No base means 4-byte offset, optimize
op->index>=0 && op->scale==2 &&
op->offset>=-128 && op->offset<128 && op->anyoffset==0)
{
op->base=op->index; op->scale=1;
};
if (op->index==REG_ESP)
{ // Reordering was unsuccessfull
strcpy(errtext,"Invalid indexing mode");
goto error;
};
if (op->base<0)
{
tcode[i+1]|=0x04;
dispsize=4;
}
else if (op->offset==0 && op->anyoffset==0 && op->base!=REG_EBP)
tcode[i+1]|=0x04; // No displacement
else if ((constsize & 1)!=0 && ((op->offset>=-128 && op->offset<128) || op->anyoffset!=0) )
{
tcode[i+1]|=0x44; // Disp8
dispsize=1;
}
else
{
tcode[i+1]|=0x84; // Disp32
dispsize=4; };
tmask[i+1]|=0xC7; // ModRM completed, proceed with SIB
if (op->scale==2)
tcode[i+2]|=0x40;
else if (op->scale==4)
tcode[i+2]|=0x80;
else if (op->scale==8)
tcode[i+2]|=0xC0;
tmask[i+2]|=0xC0;
if (op->index<8)
{
if (op->index<0)
op->index=0x04;
tcode[i+2]|=(char)(op->index<<3);
tmask[i+2]|=0x38;
};
if (op->base<8)
{
if (op->base<0)
op->base=0x05;
if (op->segment!=SEG_UNDEF && op->segment!=addr32[op->base].defseg)
segment=op->segment;
tcode[i+2]|=(char)op->base;
tmask[i+2]|=0x07;
}
else
segment=op->segment;
};
break;
case IMM: // Immediate data (8 or 16/32)
case IMU: // Immediate unsigned data (8 or 16/32)
case VXD: // VxD service (32-bit only)
if (datasize==0 && pd->arg2==NNN && (pd->bits==SS || pd->bits==WS))
datasize=4;
if (datasize==0)
{
strcpy(errtext,"Please specify operand size");
goto error;
};
immediate=op->offset; anyimm=op->anyoffset;
if (pd->bits==SS || pd->bits==WS)
{
if (datasize>1 && (constsize & 2)!=0 && ((immediate>=-128 && immediate<128) || op->anyoffset!=0))
{
immsize=1; tcode[i]|=0x02;
}
else
immsize=datasize;
tmask[i]|=0x02;
}
else
immsize=datasize;
break;
case IMX: // Immediate sign-extendable byte
case IMS: // Immediate byte (for shifts)
case IM1: // Immediate byte
if (immsize==2) // To accomodate ENTER instruction
immediate=(immediate & 0xFFFF) | (op->offset<<16);
else
immediate=op->offset;
anyimm|=op->anyoffset;
immsize++;
break;
case IM2: // Immediate word (ENTER/RET)
immediate=op->offset; anyimm=op->anyoffset;
immsize=2;
break;
case IMA: // Immediate absolute near data address
if (op->segment!=SEG_UNDEF && op->segment!=SEG_DS)
segment=op->segment;
displacement=op->offset;
anydisp=op->anyoffset;
dispsize=4;
break;
case JOB: // Immediate byte offset (for jumps)
jmpoffset=op->offset;
anyjmp=op->anyoffset;
jmpsize=1;
break;
case JOW: // Immediate full offset (for jumps)
jmpoffset=op->offset;
anyjmp=op->anyoffset;
jmpsize=4;
break;
case JMF: // Immediate absolute far jump/call addr
displacement=op->offset;
anydisp=op->anyoffset;
dispsize=4;
immediate=op->segment;
anyimm=op->anyoffset;
immsize=2;
break;
case SGM: // Segment register in ModRM byte
hasrm=1;
if (op->index<6)
{
tcode[i+1]|=(char)(op->index<<3);
tmask[i+1]|=0x38;
};
break;
case SCM: // Segment register in command byte
if (op->index==SEG_FS || op->index==SEG_GS)
{
tcode[0]=0x0F; tmask[0]=0xFF;
i=1;
if (strcmp(name,"PUSH")==0)
tcode[i]=(char)((op->index<<3) | 0x80);
else
tcode[i]=(char)((op->index<<3) | 0x81);
tmask[i]=0xFF;
}
else if (op->index<6)
{
if (op->index==SEG_CS && strcmp(name,"POP")==0)
{
strcpy(errtext,"Unable to POP CS");
goto error;
};
tcode[i]=(char)((tcode[i] & 0xC7) | (op->index<<3)); }
else
{
tcode[i]&=0xC7;
tmask[i]&=0xC7;
};
break;
case PRN: // Near return address (pseudooperand)
case PRF: // Far return address (pseudooperand)
case PAC: // Accumulator (AL/AX/EAX, pseudooperand)
case PAH: // AH (in LAHF/SAHF, pseudooperand)
case PFL: // Lower byte of flags (pseudooperand)
case PS0: // Top of FPU stack (pseudooperand)
case PS1: // ST(1) (pseudooperand)
case PCX: // CX/ECX (pseudooperand)
case PDI: // EDI (pseudooperand in MMX extentions)
break; // Simply skip preudooperands
default: // Undefined type of operand
strcpy(errtext,"Internal Assembler error");
goto error;
};
};
// Gather parts of command together in the complete command.
j=0;
if (lock!=0)
{ // Lock prefix specified
model->code[j]=0xF0;
model->mask[j]=0xFF;
j++;
};
if (datasize==2 && pd->bits!=FF)
{ // Data size prefix necessary
model->code[j]=0x66;
model->mask[j]=0xFF;
j++;
};
if (addrsize==2)
{ // Address size prefix necessary
model->code[j]=0x67;
model->mask[j]=0xFF;
j++;
};
if (segment!=SEG_UNDEF)
{ // Segment prefix necessary
if (segment==SEG_ES)
model->code[j]=0x26;
else if (segment==SEG_CS)
model->code[j]=0x2E;
else if (segment==SEG_SS)
model->code[j]=0x36;
else if (segment==SEG_DS)
model->code[j]=0x3E;
else if (segment==SEG_FS)
model->code[j]=0x64;
else if (segment==SEG_GS)
model->code[j]=0x65;
else
{
strcpy(errtext,"Internal Assembler error");
goto error;
};
model->mask[j]=0xFF;
j++;
};
if (dispsize>0)
{
memcpy(tcode+i+1+hasrm+hassib,&displacement,dispsize);
if (anydisp==0)
memset(tmask+i+1+hasrm+hassib,0xFF,dispsize);
};
if (immsize>0)
{
if (immsize==1)
l=0xFFFFFF00L;
else if (immsize==2)
l=0xFFFF0000L;
else
l=0L;
if ((immediate & l)!=0 && (immediate & l)!=l)
{
strcpy(errtext,"Constant does not fit into operand");
goto error;
};
memcpy(tcode+i+1+hasrm+hassib+dispsize,&immediate,immsize);
if (anyimm==0)
memset(tmask+i+1+hasrm+hassib+dispsize,0xFF,immsize);
};
i=i+1+hasrm+hassib+dispsize+immsize;
jmpoffset=jmpoffset-(i+j+jmpsize);
model->jmpsize=jmpsize;
model->jmpoffset=jmpoffset;
model->jmppos=i+j;
if (jmpsize!=0)
{
if (ip!=0)
{
jmpoffset=jmpoffset-ip;
if (jmpsize==1 && anyjmp==0 && (jmpoffset<-128 || jmpoffset>=128))
{
if (longjump==0 && (jmpmode & 0x03)==0)
{
longjump=1;
goto retrylongjump;
};
sprintf(errtext,"Relative jump out of range, use %s LONG form",name);
goto error;
};
memcpy(tcode+i,&jmpoffset,jmpsize);
};
if
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -