summaryrefslogtreecommitdiff
path: root/assemble.c
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2009-07-25 17:44:25 -0700
committerH. Peter Anvin <hpa@zytor.com>2009-07-25 17:44:25 -0700
commit23595f5946bc816185204302a78d8413ed59cc4b (patch)
treea3353e67afbcccdf5c180708e77339f0fdd910cf /assemble.c
parent65289e84ed2b9e7abff7e38164fe1ee133c7ff32 (diff)
downloadnasm-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.c387
1 files changed, 203 insertions, 184 deletions
diff --git a/assemble.c b/assemble.c
index aafbee8..e5df728 100644
--- a/assemble.c
+++ b/assemble.c
@@ -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)
{