📄 x86bc.c
字号:
rel = yasm_intnum_get_int(num); rel -= jmp->shortop.opcode_len+1; yasm_expr_destroy(temp); /* does a short form exist? */ if (jmp->shortop.opcode_len == 0) { yasm__error(bc->line, N_("short jump does not exist")); return YASM_BC_RESOLVE_ERROR | YASM_BC_RESOLVE_UNKNOWN_LEN; } /* short displacement must fit in -128 <= rel <= +127 */ if (rel < -128 || rel > 127) { yasm__error(bc->line, N_("short jump out of range")); return YASM_BC_RESOLVE_ERROR | YASM_BC_RESOLVE_UNKNOWN_LEN; } } } break; case JMP_NEAR_FORCED: /* 2/4 byte relative displacement (depending on operand size) */ jrtype = JMP_NEAR; if (save) { if (jmp->nearop.opcode_len == 0) { yasm__error(bc->line, N_("near jump does not exist")); return YASM_BC_RESOLVE_ERROR | YASM_BC_RESOLVE_UNKNOWN_LEN; } } break; default: temp = yasm_expr_copy(jmp->target); temp = yasm_expr_simplify(temp, NULL); /* Check for far displacement (seg:off). */ if (yasm_expr_is_op(temp, YASM_EXPR_SEGOFF)) { jrtype = JMP_FAR; break; /* length handled below */ } else if (jmp->op_sel == JMP_FAR) { yasm__error(bc->line, N_("far jump does not have a far displacement")); return YASM_BC_RESOLVE_ERROR | YASM_BC_RESOLVE_UNKNOWN_LEN; } /* Try to find shortest displacement based on difference between * target expr value and our (this bytecode's) offset. Note this * requires offset to be set BEFORE calling calc_len in order for * this test to be valid. */ temp = yasm_expr_create(YASM_EXPR_SUB, yasm_expr_expr(temp), yasm_expr_sym(jmp->origin), bc->line); num = yasm_expr_get_intnum(&temp, calc_bc_dist); if (num) { rel = yasm_intnum_get_int(num); rel -= jmp->shortop.opcode_len+1; /* short displacement must fit within -128 <= rel <= +127 */ if (jmp->shortop.opcode_len != 0 && rel >= -128 && rel <= 127) { /* It fits into a short displacement. */ jrtype = JMP_SHORT; } else if (jmp->nearop.opcode_len != 0) { /* Near for now, but could get shorter in the future if * there's a short form available. */ jrtype = JMP_NEAR; if (jmp->shortop.opcode_len != 0) retval = YASM_BC_RESOLVE_NONE; } else { /* Doesn't fit into short, and there's no near opcode. * Error out if saving, otherwise just make it a short * (in the hopes that a short might make it possible for * it to actually be within short range). */ if (save) { yasm__error(bc->line, N_("short jump out of range (near jump does not exist)")); return YASM_BC_RESOLVE_ERROR | YASM_BC_RESOLVE_UNKNOWN_LEN; } jrtype = JMP_SHORT; } } else { /* It's unknown. Thus, assume near displacement. If a near * opcode is not available, use a short opcode instead. * If we're saving, error if a near opcode is not available. */ if (jmp->nearop.opcode_len != 0) { if (jmp->shortop.opcode_len != 0) retval = YASM_BC_RESOLVE_NONE; jrtype = JMP_NEAR; } else { if (save) { yasm__error(bc->line, N_("short jump out of range (near jump does not exist)")); return YASM_BC_RESOLVE_ERROR | YASM_BC_RESOLVE_UNKNOWN_LEN; } jrtype = JMP_SHORT; } } yasm_expr_destroy(temp); break; } switch (jrtype) { case JMP_SHORT: if (save) jmp->op_sel = JMP_SHORT; if (jmp->shortop.opcode_len == 0) return YASM_BC_RESOLVE_UNKNOWN_LEN; /* size not available */ bc->len += jmp->shortop.opcode_len + 1; break; case JMP_NEAR: if (save) jmp->op_sel = JMP_NEAR; if (jmp->nearop.opcode_len == 0) return YASM_BC_RESOLVE_UNKNOWN_LEN; /* size not available */ bc->len += jmp->nearop.opcode_len; bc->len += (opersize == 16) ? 2 : 4; break; case JMP_FAR: if (save) jmp->op_sel = JMP_FAR; if (jmp->farop.opcode_len == 0) return YASM_BC_RESOLVE_UNKNOWN_LEN; /* size not available */ bc->len += jmp->farop.opcode_len; bc->len += 2; /* segment */ bc->len += (opersize == 16) ? 2 : 4; break; default: yasm_internal_error(N_("unknown jump type")); } bc->len += (jmp->addrsize != 0 && jmp->addrsize != jmp->mode_bits) ? 1:0; bc->len += (jmp->opersize != 0 && jmp->opersize != jmp->mode_bits) ? 1:0; bc->len += (jmp->lockrep_pre != 0) ? 1:0; return retval;}static intx86_bc_insn_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d, yasm_output_expr_func output_expr, /*@unused@*/ yasm_output_reloc_func output_reloc){ x86_insn *insn = (x86_insn *)bc; /*@null@*/ x86_effaddr *x86_ea = insn->ea; /*@null@*/ yasm_effaddr *ea = &x86_ea->ea; yasm_immval *imm = insn->imm; unsigned int i; unsigned char *bufp_orig = *bufp; /* Prefixes */ if (insn->special_prefix != 0) YASM_WRITE_8(*bufp, insn->special_prefix); if (insn->lockrep_pre != 0) YASM_WRITE_8(*bufp, insn->lockrep_pre); if (x86_ea && x86_ea->segment != 0) YASM_WRITE_8(*bufp, x86_ea->segment); if (insn->opersize != 0 && ((insn->mode_bits != 64 && insn->opersize != insn->mode_bits) || (insn->mode_bits == 64 && insn->opersize == 16))) YASM_WRITE_8(*bufp, 0x66); if (insn->addrsize != 0 && insn->addrsize != insn->mode_bits) YASM_WRITE_8(*bufp, 0x67); if (insn->rex != 0xff) { if (insn->mode_bits == 64 && insn->opersize == 64 && insn->def_opersize_64 != 64) insn->rex |= 0x48; if (insn->rex != 0) { if (insn->mode_bits != 64) yasm_internal_error( N_("x86: got a REX prefix in non-64-bit mode")); YASM_WRITE_8(*bufp, insn->rex); } } /* Opcode */ for (i=0; i<insn->opcode_len; i++) YASM_WRITE_8(*bufp, insn->opcode[i]); /* Effective address: ModR/M (if required), SIB (if required), and * displacement (if required). */ if (ea) { if (x86_ea->need_modrm) { if (!x86_ea->valid_modrm) yasm_internal_error(N_("invalid Mod/RM in x86 tobytes_insn")); YASM_WRITE_8(*bufp, x86_ea->modrm); } if (x86_ea->need_sib) { if (!x86_ea->valid_sib) yasm_internal_error(N_("invalid SIB in x86 tobytes_insn")); YASM_WRITE_8(*bufp, x86_ea->sib); } if (ea->disp) { x86_effaddr eat = *x86_ea; /* structure copy */ unsigned char displen = ea->len; unsigned char addrsize = insn->addrsize; eat.valid_modrm = 0; /* force checkea to actually run */ /* Call checkea() to simplify the registers out of the * displacement. Throw away all of the return values except for * the modified expr. */ if (yasm_x86__expr_checkea(&ea->disp, &addrsize, insn->mode_bits, ea->nosplit, &displen, &eat.modrm, &eat.valid_modrm, &eat.need_modrm, &eat.sib, &eat.valid_sib, &eat.need_sib, &eat.pcrel, &insn->rex, yasm_common_calc_bc_dist)) yasm_internal_error(N_("checkea failed")); if (ea->disp) { if (eat.pcrel) { /*@null@*/ yasm_expr *wrt = yasm_expr_extract_wrt(&ea->disp); ea->disp = yasm_expr_create(YASM_EXPR_SUB, yasm_expr_expr(ea->disp), yasm_expr_sym(eat.origin), bc->line); if (wrt) { ea->disp = yasm_expr_create(YASM_EXPR_WRT, yasm_expr_expr(ea->disp), yasm_expr_expr(wrt), bc->line); } if (output_expr(&ea->disp, *bufp, ea->len, (size_t)(ea->len*8), 0, (unsigned long)(*bufp-bufp_orig), bc, 1, 1, d)) return 1; } else { if (output_expr(&ea->disp, *bufp, ea->len, (size_t)(ea->len*8), 0, (unsigned long)(*bufp-bufp_orig), bc, 0, 1, d)) return 1; } *bufp += ea->len; } else { /* 0 displacement, but we didn't know it before, so we have to * write out 0 value. */ for (i=0; i<ea->len; i++) YASM_WRITE_8(*bufp, 0); } } } /* Immediate (if required) */ if (imm && imm->val) { if (output_expr(&imm->val, *bufp, imm->len, (size_t)(imm->len*8), 0, (unsigned long)(*bufp-bufp_orig), bc, 0, 1, d)) return 1; *bufp += imm->len; } return 0;}static intx86_bc_jmp_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d, yasm_output_expr_func output_expr, /*@unused@*/ yasm_output_reloc_func output_reloc){ x86_jmp *jmp = (x86_jmp *)bc; unsigned char opersize; unsigned int i; unsigned char *bufp_orig = *bufp; /*@null@*/ yasm_expr *targetseg; /*@null@*/ yasm_expr *wrt; yasm_expr *dup; /* Prefixes */ if (jmp->lockrep_pre != 0) YASM_WRITE_8(*bufp, jmp->lockrep_pre); /* FIXME: branch hints! */ if (jmp->opersize != 0 && jmp->opersize != jmp->mode_bits) YASM_WRITE_8(*bufp, 0x66); if (jmp->addrsize != 0 && jmp->addrsize != jmp->mode_bits) YASM_WRITE_8(*bufp, 0x67); /* As opersize may be 0, figure out its "real" value. */ opersize = (jmp->opersize == 0) ? jmp->mode_bits : jmp->opersize; /* Check here to see if forced forms are actually legal. */ switch (jmp->op_sel) { case JMP_SHORT_FORCED: case JMP_SHORT: /* 1 byte relative displacement */ if (jmp->shortop.opcode_len == 0) yasm_internal_error(N_("short jump does not exist")); /* Opcode */ for (i=0; i<jmp->shortop.opcode_len; i++) YASM_WRITE_8(*bufp, jmp->shortop.opcode[i]); /* Relative displacement */ wrt = yasm_expr_extract_wrt(&jmp->target); jmp->target = yasm_expr_create(YASM_EXPR_SUB, yasm_expr_expr(jmp->target), yasm_expr_sym(jmp->origin), bc->line); if (wrt) jmp->target = yasm_expr_create_tree(jmp->target, YASM_EXPR_WRT, wrt, bc->line); if (output_expr(&jmp->target, *bufp, 1, 8, 0, (unsigned long)(*bufp-bufp_orig), bc, 1, 1, d)) return 1; *bufp += 1; break; case JMP_NEAR_FORCED: case JMP_NEAR: /* 2/4 byte relative displacement (depending on operand size) */ if (jmp->nearop.opcode_len == 0) { yasm__error(bc->line, N_("near jump does not exist")); return 1; } /* Opcode */ for (i=0; i<jmp->nearop.opcode_len; i++) YASM_WRITE_8(*bufp, jmp->nearop.opcode[i]); /* Relative displacement */ wrt = yasm_expr_extract_wrt(&jmp->target); jmp->target = yasm_expr_create(YASM_EXPR_SUB, yasm_expr_expr(jmp->target), yasm_expr_sym(jmp->origin), bc->line); if (wrt) jmp->target = yasm_expr_create_tree(jmp->target, YASM_EXPR_WRT, wrt, bc->line); i = (opersize == 16) ? 2 : 4; if (output_expr(&jmp->target, *bufp, i, i*8, 0, (unsigned long)(*bufp-bufp_orig), bc, 1, 1, d)) return 1; *bufp += i; break; case JMP_FAR: /* far absolute (4/6 byte depending on operand size) */ if (jmp->farop.opcode_len == 0) { yasm__error(bc->line, N_("far jump does not exist")); return 1; } /* Opcode */ for (i=0; i<jmp->farop.opcode_len; i++) YASM_WRITE_8(*bufp, jmp->farop.opcode[i]); /* Absolute displacement: segment and offset */ jmp->target = yasm_expr_simplify(jmp->target, NULL); dup = yasm_expr_copy(jmp->target); targetseg = yasm_expr_extract_segoff(&dup); if (!targetseg) yasm_internal_error(N_("could not extract segment for far jump")); i = (opersize == 16) ? 2 : 4; if (output_expr(&dup, *bufp, i, i*8, 0, (unsigned long)(*bufp-bufp_orig), bc, 0, 1, d)) return 1; *bufp += i; if (output_expr(&targetseg, *bufp, 2, 2*8, 0, (unsigned long)(*bufp-bufp_orig), bc, 0, 1, d)) return 1; *bufp += 2; yasm_expr_destroy(dup); yasm_expr_destroy(targetseg); break; default: yasm_internal_error(N_("unrecognized relative jump op_sel")); } return 0;}intyasm_x86__intnum_fixup_rel(yasm_arch *arch, yasm_intnum *intn, size_t valsize, const yasm_bytecode *bc, unsigned long line){ yasm_intnum *delta; if (valsize != 8 && valsize != 16 && valsize != 32) yasm_internal_error( N_("tried to do PC-relative offset from invalid sized value")); delta = yasm_intnum_create_uint(bc->len); yasm_intnum_calc(intn, YASM_EXPR_SUB, delta, line); yasm_intnum_destroy(delta); return 0;}intyasm_x86__intnum_tobytes(yasm_arch *arch, const yasm_intnum *intn, unsigned char *buf, size_t destsize, size_t valsize, int shift, const yasm_bytecode *bc, int warn, unsigned long line){ /* Write value out. */ yasm_intnum_get_sized(intn, buf, destsize, valsize, shift, 0, warn, line); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -