📄 assemble.c
字号:
if (c <= 0177) {
/* pick rfield from operand b */
rflags = regflag(&ins->oprs[c & 7]);
rfield = nasm_regvals[ins->oprs[c & 7].basereg];
} else {
/* rfield is constant */
rflags = 0;
rfield = c & 7;
}
if (!process_ea
(&ins->oprs[(c >> 3) & 7], &ea_data, bits,
ins->addr_size, rfield, rflags)) {
errfunc(ERR_NONFATAL, "invalid effective address");
}
p = bytes;
*p++ = ea_data.modrm;
if (ea_data.sib_present)
*p++ = ea_data.sib;
/* DREX suffixes come between the SIB and the displacement */
if (ins->rex & REX_D) {
*p++ =
(ins->drexdst << 4) |
(ins->rex & REX_OC ? 0x08 : 0) |
(ins->rex & (REX_R|REX_X|REX_B));
ins->rex = 0;
}
s = p - bytes;
out(offset, segment, bytes, OUT_RAWDATA, s, NO_SEG, NO_SEG);
/*
* Make sure the address gets the right offset in case
* the line breaks in the .lst file (BR 1197827)
*/
offset += s;
s = 0;
switch (ea_data.bytes) {
case 0:
break;
case 1:
if (ins->oprs[(c >> 3) & 7].segment != NO_SEG) {
data = ins->oprs[(c >> 3) & 7].offset;
out(offset, segment, &data, OUT_ADDRESS, 1,
ins->oprs[(c >> 3) & 7].segment,
ins->oprs[(c >> 3) & 7].wrt);
} else {
*bytes = ins->oprs[(c >> 3) & 7].offset;
out(offset, segment, bytes, OUT_RAWDATA, 1,
NO_SEG, NO_SEG);
}
s++;
break;
case 8:
case 2:
case 4:
data = ins->oprs[(c >> 3) & 7].offset;
warn_overflow(ea_data.bytes, opx);
s += ea_data.bytes;
if (ea_data.rip) {
out(offset, segment, &data,
OUT_REL4ADR, insn_end - offset,
ins->oprs[(c >> 3) & 7].segment,
ins->oprs[(c >> 3) & 7].wrt);
} else {
type = OUT_ADDRESS;
out(offset, segment, &data,
OUT_ADDRESS, ea_data.bytes,
ins->oprs[(c >> 3) & 7].segment,
ins->oprs[(c >> 3) & 7].wrt);
}
break;
}
offset += s;
}
break;
default:
errfunc(ERR_PANIC, "internal instruction table corrupt"
": instruction code 0x%02X given", c);
break;
}
}
}
static int32_t regflag(const operand * o)
{
if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
errfunc(ERR_PANIC, "invalid operand passed to regflag()");
}
return nasm_reg_flags[o->basereg];
}
static int32_t regval(const operand * o)
{
if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
errfunc(ERR_PANIC, "invalid operand passed to regval()");
}
return nasm_regvals[o->basereg];
}
static int op_rexflags(const operand * o, int mask)
{
int32_t flags;
int val;
if (o->basereg < EXPR_REG_START || o->basereg >= REG_ENUM_LIMIT) {
errfunc(ERR_PANIC, "invalid operand passed to op_rexflags()");
}
flags = nasm_reg_flags[o->basereg];
val = nasm_regvals[o->basereg];
return rexflags(val, flags, mask);
}
static int rexflags(int val, int32_t flags, int mask)
{
int rex = 0;
if (val >= 8)
rex |= REX_B|REX_X|REX_R;
if (flags & BITS64)
rex |= REX_W;
if (!(REG_HIGH & ~flags)) /* AH, CH, DH, BH */
rex |= REX_H;
else if (!(REG8 & ~flags) && val >= 4) /* SPL, BPL, SIL, DIL */
rex |= REX_P;
return rex & mask;
}
static int matches(const struct itemplate *itemp, insn * instruction, int bits)
{
int i, size[MAX_OPERANDS], asize, oprs, ret;
ret = 100;
/*
* Check the opcode
*/
if (itemp->opcode != instruction->opcode)
return 0;
/*
* Count the operands
*/
if (itemp->operands != instruction->operands)
return 0;
/*
* Check that no spurious colons or TOs are present
*/
for (i = 0; i < itemp->operands; i++)
if (instruction->oprs[i].type & ~itemp->opd[i] & (COLON | TO))
return 0;
/*
* Process size flags
*/
if (itemp->flags & IF_ARMASK) {
memset(size, 0, sizeof size);
i = ((itemp->flags & IF_ARMASK) >> IF_ARSHFT) - 1;
switch (itemp->flags & IF_SMASK) {
case IF_SB:
size[i] = BITS8;
break;
case IF_SW:
size[i] = BITS16;
break;
case IF_SD:
size[i] = BITS32;
break;
case IF_SQ:
size[i] = BITS64;
break;
case IF_SO:
size[i] = BITS128;
break;
case IF_SY:
size[i] = BITS256;
break;
case IF_SZ:
switch (bits) {
case 16:
size[i] = BITS16;
break;
case 32:
size[i] = BITS32;
break;
case 64:
size[i] = BITS64;
break;
}
break;
default:
break;
}
} else {
asize = 0;
switch (itemp->flags & IF_SMASK) {
case IF_SB:
asize = BITS8;
break;
case IF_SW:
asize = BITS16;
break;
case IF_SD:
asize = BITS32;
break;
case IF_SQ:
asize = BITS64;
break;
case IF_SO:
asize = BITS128;
break;
case IF_SY:
asize = BITS256;
break;
case IF_SZ:
switch (bits) {
case 16:
asize = BITS16;
break;
case 32:
asize = BITS32;
break;
case 64:
asize = BITS64;
break;
}
break;
default:
break;
}
for (i = 0; i < MAX_OPERANDS; i++)
size[i] = asize;
}
/*
* Check that the operand flags all match up
*/
for (i = 0; i < itemp->operands; i++) {
int32_t type = instruction->oprs[i].type;
if (!(type & SIZE_MASK))
type |= size[i];
if (itemp->opd[i] & SAME_AS) {
int j = itemp->opd[i] & ~SAME_AS;
if (type != instruction->oprs[j].type ||
instruction->oprs[i].basereg != instruction->oprs[j].basereg)
return 0;
} else if (itemp->opd[i] & ~type ||
((itemp->opd[i] & SIZE_MASK) &&
((itemp->opd[i] ^ type) & SIZE_MASK))) {
if ((itemp->opd[i] & ~type & ~SIZE_MASK) ||
(type & SIZE_MASK))
return 0;
else
return 1;
}
}
/*
* Check operand sizes
*/
if (itemp->flags & (IF_SM | IF_SM2)) {
oprs = (itemp->flags & IF_SM2 ? 2 : itemp->operands);
asize = 0;
for (i = 0; i < oprs; i++) {
if ((asize = itemp->opd[i] & SIZE_MASK) != 0) {
int j;
for (j = 0; j < oprs; j++)
size[j] = asize;
break;
}
}
} else {
oprs = itemp->operands;
}
for (i = 0; i < itemp->operands; i++) {
if (!(itemp->opd[i] & SIZE_MASK) &&
(instruction->oprs[i].type & SIZE_MASK & ~size[i]))
return 2;
}
/*
* Check template is okay at the set cpu level
*/
if (((itemp->flags & IF_PLEVEL) > cpu))
return 3;
/*
* Check if instruction is available in long mode
*/
if ((itemp->flags & IF_NOLONG) && (bits == 64))
return 4;
/*
* Check if special handling needed for Jumps
*/
if ((uint8_t)(itemp->code[0]) >= 0370)
return 99;
return ret;
}
static ea *process_ea(operand * input, ea * output, int bits,
int addrbits, int rfield, int32_t rflags)
{
bool forw_ref = !!(input->opflags & OPFLAG_FORWARD);
output->rip = false;
/* REX flags for the rfield operand */
output->rex |= rexflags(rfield, rflags, REX_R|REX_P|REX_W|REX_H);
if (!(REGISTER & ~input->type)) { /* register direct */
int i;
int32_t f;
if (input->basereg < EXPR_REG_START /* Verify as Register */
|| input->basereg >= REG_ENUM_LIMIT)
return NULL;
f = regflag(input);
i = nasm_regvals[input->basereg];
if (REG_EA & ~f)
return NULL; /* Invalid EA register */
output->rex |= op_rexflags(input, REX_B|REX_P|REX_W|REX_H);
output->sib_present = false; /* no SIB necessary */
output->bytes = 0; /* no offset necessary either */
output->modrm = 0xC0 | ((rfield & 7) << 3) | (i & 7);
} else { /* it's a memory reference */
if (input->basereg == -1
&& (input->indexreg == -1 || input->scale == 0)) {
/* it's a pure offset */
if (bits == 64 && (~input->type & IP_REL)) {
int scale, index, base;
output->sib_present = true;
scale = 0;
index = 4;
base = 5;
output->sib = (scale << 6) | (index << 3) | base;
output->bytes = 4;
output->modrm = 4 | ((rfield & 7) << 3);
output->rip = false;
} else {
output->sib_present = false;
output->bytes = (addrbits != 16 ? 4 : 2);
output->modrm = (addrbits != 16 ? 5 : 6) | ((rfield & 7) << 3);
output->rip = bits == 64;
}
} else { /* it's an indirection */
int i = input->indexreg, b = input->basereg, s = input->scale;
int32_t o = input->offset, seg = input->segment;
int hb = input->hintbase, ht = input->hinttype;
int t;
int it, bt;
int32_t ix, bx; /* register flags */
if (s == 0)
i = -1; /* make this easy, at least */
if (i >= EXPR_REG_START && i < REG_ENUM_LIMIT) {
it = nasm_regvals[i];
ix = nasm_reg_flags[i];
} else {
it = -1;
ix = 0;
}
if (b >= EXPR_REG_START && b < REG_ENUM_LIMIT) {
bt = nasm_regvals[b];
bx = nasm_reg_flags[b];
} else {
bt = -1;
bx = 0;
}
/* check for a 32/64-bit memory reference... */
if ((ix|bx) & (BITS32|BITS64)) {
/* it must be a 32/64-bit memory reference. Firstly we have
* to check that all registers involved are type E/Rxx. */
int32_t sok = BITS32|BITS64;
if (it != -1) {
if (!(REG64 & ~ix) || !(REG32 & ~ix))
sok &= ix;
else
return NULL;
}
if (bt != -1) {
if (REG_GPR & ~bx)
return NULL; /* Invalid register */
if (~sok & bx & SIZE_MASK)
return NULL; /* Invalid size */
sok &= bx;
}
/* While we're here, ensure the user didn't specify
WORD or QWORD. */
if (input->disp_size == 16 || input->disp_size == 64)
return NULL;
if (addrbits == 16 ||
(addrbits == 32 && !(sok & BITS32)) ||
(addrbits == 64 && !(sok & BITS64)))
return NULL;
/* now reorganize base/index */
if (s == 1 && bt != it && bt != -1 && it != -1 &&
((hb == b && ht == EAH_NOTBASE)
|| (hb == i && ht == EAH_MAKEBASE))) {
/* swap if hints say so */
t = bt, bt = it, it = t;
t = bx, bx = ix, ix = t;
}
if (bt == it) /* convert EAX+2*EAX to 3*EAX */
bt = -1, bx = 0, s++;
if (bt == -1 && s == 1 && !(hb == it && ht == EAH_NOTBASE)) {
/* make single reg ba
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -