diff options
author | H. Peter Anvin <hpa@zytor.com> | 2009-07-25 17:44:25 -0700 |
---|---|---|
committer | H. Peter Anvin <hpa@zytor.com> | 2009-07-25 17:44:25 -0700 |
commit | 23595f5946bc816185204302a78d8413ed59cc4b (patch) | |
tree | a3353e67afbcccdf5c180708e77339f0fdd910cf /assemble.c | |
parent | 65289e84ed2b9e7abff7e38164fe1ee133c7ff32 (diff) | |
download | nasm-23595f5946bc816185204302a78d8413ed59cc4b.tar.gz nasm-23595f5946bc816185204302a78d8413ed59cc4b.tar.bz2 nasm-23595f5946bc816185204302a78d8413ed59cc4b.zip |
assemble: move the instruction-matching loop into a common function
Move the instruction-matching loop into a common function. This gives
us a single point to adjust the instruction-selection algorithm.
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
Diffstat (limited to 'assemble.c')
-rw-r--r-- | assemble.c | 387 |
1 files changed, 203 insertions, 184 deletions
@@ -195,6 +195,9 @@ static int64_t calcsize(int32_t, int64_t, int, insn *, const uint8_t *); static void gencode(int32_t segment, int64_t offset, int bits, insn * ins, const struct itemplate *temp, int64_t insn_end); +static enum match_result find_match(const struct itemplate **tempp, + insn *instruction, + int32_t segment, int64_t offset, int bits); static enum match_result matches(const struct itemplate *, insn *, int bits); static int32_t regflag(const operand *); static int32_t regval(const operand *); @@ -328,7 +331,7 @@ int64_t assemble(int32_t segment, int64_t offset, int bits, uint32_t cp, { const struct itemplate *temp; int j; - enum match_result size_prob; + enum match_result m; int64_t insn_end; int32_t itimes; int64_t start = offset; @@ -499,149 +502,140 @@ int64_t assemble(int32_t segment, int64_t offset, int bits, uint32_t cp, /* Check to see if we need an address-size prefix */ add_asp(instruction, bits); - size_prob = MERR_INVALOP; + m = find_match(&temp, instruction, segment, offset, bits); - for (temp = nasm_instructions[instruction->opcode]; - temp->opcode != -1; temp++){ - enum match_result m = matches(temp, instruction, bits); - if (m == MOK_GOOD || - (m == MOK_JUMP && jmp_match(segment, offset, bits, - instruction, temp->code))) { - /* Matches! */ - int64_t insn_size = calcsize(segment, offset, bits, - instruction, temp->code); - itimes = instruction->times; - if (insn_size < 0) /* shouldn't be, on pass two */ - error(ERR_PANIC, "errors made it through from pass one"); - else - while (itimes--) { - for (j = 0; j < MAXPREFIX; j++) { - uint8_t c = 0; - switch (instruction->prefixes[j]) { - case P_WAIT: - c = 0x9B; - break; - case P_LOCK: - c = 0xF0; - break; - case P_REPNE: - case P_REPNZ: - c = 0xF2; - break; - case P_REPE: - case P_REPZ: - case P_REP: - c = 0xF3; - break; - case R_CS: - if (bits == 64) { - error(ERR_WARNING | ERR_PASS2, - "cs segment base generated, but will be ignored in 64-bit mode"); - } - c = 0x2E; - break; - case R_DS: - if (bits == 64) { - error(ERR_WARNING | ERR_PASS2, - "ds segment base generated, but will be ignored in 64-bit mode"); - } - c = 0x3E; - break; - case R_ES: - if (bits == 64) { - error(ERR_WARNING | ERR_PASS2, - "es segment base generated, but will be ignored in 64-bit mode"); - } - c = 0x26; - break; - case R_FS: - c = 0x64; - break; - case R_GS: - c = 0x65; - break; - case R_SS: - if (bits == 64) { - error(ERR_WARNING | ERR_PASS2, - "ss segment base generated, but will be ignored in 64-bit mode"); - } - c = 0x36; - break; - case R_SEGR6: - case R_SEGR7: - error(ERR_NONFATAL, - "segr6 and segr7 cannot be used as prefixes"); - break; - case P_A16: - if (bits == 64) { - error(ERR_NONFATAL, - "16-bit addressing is not supported " - "in 64-bit mode"); - } else if (bits != 16) - c = 0x67; - break; - case P_A32: - if (bits != 32) - c = 0x67; - break; - case P_A64: - if (bits != 64) { - error(ERR_NONFATAL, - "64-bit addressing is only supported " - "in 64-bit mode"); - } - break; - case P_ASP: + if (m == MOK_GOOD) { + /* Matches! */ + int64_t insn_size = calcsize(segment, offset, bits, + instruction, temp->code); + itimes = instruction->times; + if (insn_size < 0) /* shouldn't be, on pass two */ + error(ERR_PANIC, "errors made it through from pass one"); + else + while (itimes--) { + for (j = 0; j < MAXPREFIX; j++) { + uint8_t c = 0; + switch (instruction->prefixes[j]) { + case P_WAIT: + c = 0x9B; + break; + case P_LOCK: + c = 0xF0; + break; + case P_REPNE: + case P_REPNZ: + c = 0xF2; + break; + case P_REPE: + case P_REPZ: + case P_REP: + c = 0xF3; + break; + case R_CS: + if (bits == 64) { + error(ERR_WARNING | ERR_PASS2, + "cs segment base generated, but will be ignored in 64-bit mode"); + } + c = 0x2E; + break; + case R_DS: + if (bits == 64) { + error(ERR_WARNING | ERR_PASS2, + "ds segment base generated, but will be ignored in 64-bit mode"); + } + c = 0x3E; + break; + case R_ES: + if (bits == 64) { + error(ERR_WARNING | ERR_PASS2, + "es segment base generated, but will be ignored in 64-bit mode"); + } + c = 0x26; + break; + case R_FS: + c = 0x64; + break; + case R_GS: + c = 0x65; + break; + case R_SS: + if (bits == 64) { + error(ERR_WARNING | ERR_PASS2, + "ss segment base generated, but will be ignored in 64-bit mode"); + } + c = 0x36; + break; + case R_SEGR6: + case R_SEGR7: + error(ERR_NONFATAL, + "segr6 and segr7 cannot be used as prefixes"); + break; + case P_A16: + if (bits == 64) { + error(ERR_NONFATAL, + "16-bit addressing is not supported " + "in 64-bit mode"); + } else if (bits != 16) c = 0x67; - break; - case P_O16: - if (bits != 16) - c = 0x66; - break; - case P_O32: - if (bits == 16) - c = 0x66; - break; - case P_O64: - /* REX.W */ - break; - case P_OSP: + break; + case P_A32: + if (bits != 32) + c = 0x67; + break; + case P_A64: + if (bits != 64) { + error(ERR_NONFATAL, + "64-bit addressing is only supported " + "in 64-bit mode"); + } + break; + case P_ASP: + c = 0x67; + break; + case P_O16: + if (bits != 16) c = 0x66; - break; - case P_none: - break; - default: - error(ERR_PANIC, "invalid instruction prefix"); - } - if (c != 0) { - out(offset, segment, &c, OUT_RAWDATA, 1, - NO_SEG, NO_SEG); - offset++; - } - } - insn_end = offset + insn_size; - gencode(segment, offset, bits, instruction, - temp, insn_end); - offset += insn_size; - if (itimes > 0 && itimes == instruction->times - 1) { - /* - * Dummy call to list->output to give the offset to the - * listing module. - */ - list->output(offset, NULL, OUT_RAWDATA, 0); - list->uplevel(LIST_TIMES); - } - } - if (instruction->times > 1) - list->downlevel(LIST_TIMES); - return offset - start; - } else if (m > 0 && m > size_prob) { - size_prob = m; - } - } - - if (temp->opcode == -1) { /* didn't match any instruction */ - switch (size_prob) { + break; + case P_O32: + if (bits == 16) + c = 0x66; + break; + case P_O64: + /* REX.W */ + break; + case P_OSP: + c = 0x66; + break; + case P_none: + break; + default: + error(ERR_PANIC, "invalid instruction prefix"); + } + if (c != 0) { + out(offset, segment, &c, OUT_RAWDATA, 1, + NO_SEG, NO_SEG); + offset++; + } + } + insn_end = offset + insn_size; + gencode(segment, offset, bits, instruction, + temp, insn_end); + offset += insn_size; + if (itimes > 0 && itimes == instruction->times - 1) { + /* + * Dummy call to list->output to give the offset to the + * listing module. + */ + list->output(offset, NULL, OUT_RAWDATA, 0); + list->uplevel(LIST_TIMES); + } + } + if (instruction->times > 1) + list->downlevel(LIST_TIMES); + return offset - start; + } else { + /* No match */ + switch (m) { case MERR_OPSIZEMISSING: error(ERR_NONFATAL, "operation size not specified"); break; @@ -668,6 +662,7 @@ int64_t insn_size(int32_t segment, int64_t offset, int bits, uint32_t cp, insn * instruction, efunc error) { const struct itemplate *temp; + enum match_result m; errfunc = error; /* to pass to other functions */ cpu = cp; @@ -757,51 +752,47 @@ int64_t insn_size(int32_t segment, int64_t offset, int bits, uint32_t cp, /* Check to see if we need an address-size prefix */ add_asp(instruction, bits); - for (temp = nasm_instructions[instruction->opcode]; - temp->opcode != -1; temp++) { - enum match_result m = matches(temp, instruction, bits); - if (m == MOK_GOOD || - (m == MOK_JUMP && jmp_match(segment, offset, bits, - instruction, temp->code))) { - /* we've matched an instruction. */ - int64_t isize; - const uint8_t *codes = temp->code; - int j; - - isize = calcsize(segment, offset, bits, instruction, codes); - if (isize < 0) - return -1; - for (j = 0; j < MAXPREFIX; j++) { - switch (instruction->prefixes[j]) { - case P_A16: - if (bits != 16) - isize++; - break; - case P_A32: - if (bits != 32) - isize++; - break; - case P_O16: - if (bits != 16) - isize++; - break; - case P_O32: - if (bits == 16) - isize++; - break; - case P_A64: - case P_O64: - case P_none: - break; - default: + m = find_match(&temp, instruction, segment, offset, bits); + if (m == MOK_GOOD) { + /* we've matched an instruction. */ + int64_t isize; + const uint8_t *codes = temp->code; + int j; + + isize = calcsize(segment, offset, bits, instruction, codes); + if (isize < 0) + return -1; + for (j = 0; j < MAXPREFIX; j++) { + switch (instruction->prefixes[j]) { + case P_A16: + if (bits != 16) isize++; - break; - } - } - return isize * instruction->times; - } + break; + case P_A32: + if (bits != 32) + isize++; + break; + case P_O16: + if (bits != 16) + isize++; + break; + case P_O32: + if (bits == 16) + isize++; + break; + case P_A64: + case P_O64: + case P_none: + break; + default: + isize++; + break; + } + } + return isize * instruction->times; + } else { + return -1; /* didn't match any instruction */ } - return -1; /* didn't match any instruction */ } static bool possible_sbyte(operand *o) @@ -1986,6 +1977,34 @@ static int rexflags(int val, int32_t flags, int mask) return rex & mask; } +static enum match_result find_match(const struct itemplate **tempp, + insn *instruction, + int32_t segment, int64_t offset, int bits) +{ + const struct itemplate *temp; + enum match_result m, merr; + + merr = MERR_INVALOP; + + for (temp = nasm_instructions[instruction->opcode]; + temp->opcode != I_none; temp++) { + m = matches(temp, instruction, bits); + if (m == MOK_JUMP) { + if (jmp_match(segment, offset, bits, instruction, temp->code)) + m = MOK_GOOD; + else + m = MERR_INVALOP; + } + if (m > merr) + merr = m; + if (merr == MOK_GOOD) + break; + } + + *tempp = temp; + return merr; +} + static enum match_result matches(const struct itemplate *itemp, insn *instruction, int bits) { |