diff options
Diffstat (limited to 'ecomp-c/asm-i386.c')
-rw-r--r-- | ecomp-c/asm-i386.c | 113 |
1 files changed, 78 insertions, 35 deletions
diff --git a/ecomp-c/asm-i386.c b/ecomp-c/asm-i386.c index c9de15a..584c631 100644 --- a/ecomp-c/asm-i386.c +++ b/ecomp-c/asm-i386.c @@ -32,6 +32,7 @@ * E9 XX XX XX XX jmp rel32 * E8 XX XX XX XX call rel32 * C3 ret + * C2 XX XX ret imm16 * F4 hlt * CD XX int nnn * 90 nop @@ -52,6 +53,9 @@ * rel32 * relative address offset (8/32 bits) * + * imm16 + * little endian 16-bit constant + * * format binary * use32 * org 0x00000000 @@ -68,7 +72,8 @@ enum { MAX_NUMBER_LEN = 10, MAX_HEXNUMBER_LEN = 8, MAX_STRING_LEN = 64, - MAX_PASSES = 10 + MAX_PASSES = 10, + MAX_NOF_OPERANDS = 64 }; static int DEBUG_GETCHAR = 0; @@ -842,7 +847,8 @@ typedef struct OpcodeInfo { Symbol *label; int addr; Opcode opcode; - int nof_operands; + int min_operands; + int max_operands; OperandInfo *operand; struct OpcodeInfo *next; int size; @@ -866,51 +872,60 @@ static OpcodeInfo *parseOpcode( void ) case 'a': if( strcmp( ident, "add" ) == 0 ) { opcode_info->opcode = OPCODE_ADD; - opcode_info->nof_operands = 2; + opcode_info->min_operands = 2; + opcode_info->max_operands = 2; opcode_info->size = 2; } break; case 'c': if( strcmp( ident, "cmp" ) == 0 ) { opcode_info->opcode = OPCODE_CMP; - opcode_info->nof_operands = 2; + opcode_info->min_operands = 2; + opcode_info->max_operands = 2; opcode_info->size = 2; } else if( strcmp( ident, "call" ) == 0 ) { opcode_info->opcode = OPCODE_CALL; - opcode_info->nof_operands = 1; + opcode_info->min_operands = 1; + opcode_info->max_operands = 1; opcode_info->size = 5; } break; case 'd': if( strcmp( ident, "dd" ) == 0 ) { opcode_info->opcode = OPCODE_PSEUDO_DD; - opcode_info->nof_operands = 1; + opcode_info->min_operands = 1; + opcode_info->max_operands = MAX_NOF_OPERANDS; opcode_info->size = 4; } else if( strcmp( ident, "db" ) == 0 ) { opcode_info->opcode = OPCODE_PSEUDO_DB; - opcode_info->nof_operands = 1; + opcode_info->min_operands = 1; + opcode_info->max_operands = MAX_NOF_OPERANDS; opcode_info->size = 1; } else if( strcmp( ident, "dw" ) == 0 ) { opcode_info->opcode = OPCODE_PSEUDO_DW; - opcode_info->nof_operands = 1; + opcode_info->min_operands = 1; + opcode_info->max_operands = MAX_NOF_OPERANDS; opcode_info->size = 2; } else if( strcmp( ident, "div" ) == 0 ) { opcode_info->opcode = OPCODE_DIV; - opcode_info->nof_operands = 1; + opcode_info->min_operands = 1; + opcode_info->max_operands = 1; opcode_info->size = 2; } break; case 'h': if( strcmp( ident, "hlt" ) == 0 ) { opcode_info->opcode = OPCODE_HLT; - opcode_info->nof_operands = 0; + opcode_info->min_operands = 0; + opcode_info->max_operands = 0; opcode_info->size = 1; } break; case 'i': if( strcmp( ident, "int" ) == 0 ) { opcode_info->opcode = OPCODE_INT; - opcode_info->nof_operands = 1; + opcode_info->min_operands = 1; + opcode_info->max_operands = 1; opcode_info->size = 2; } break; @@ -919,43 +934,50 @@ static OpcodeInfo *parseOpcode( void ) case 'm': if( strcmp( ident, "jmp" ) == 0 ) { opcode_info->opcode = OPCODE_JMP; - opcode_info->nof_operands = 1; + opcode_info->min_operands = 1; + opcode_info->max_operands = 1; opcode_info->size = 2; } break; case 'e': if( strcmp( ident, "je" ) == 0 ) { opcode_info->opcode = OPCODE_JE; - opcode_info->nof_operands = 1; + opcode_info->min_operands = 1; + opcode_info->max_operands = 1; opcode_info->size = 2; } break; case 'n': if( strcmp( ident, "jne" ) == 0 ) { opcode_info->opcode = OPCODE_JNE; - opcode_info->nof_operands = 1; + opcode_info->min_operands = 1; + opcode_info->max_operands = 1; opcode_info->size = 2; } break; case 'b': if( strcmp( ident, "jb" ) == 0 ) { opcode_info->opcode = OPCODE_JB; - opcode_info->nof_operands = 1; + opcode_info->min_operands = 1; + opcode_info->max_operands = 1; opcode_info->size = 2; } else if( strcmp( ident, "jbe" ) == 0 ) { opcode_info->opcode = OPCODE_JBE; - opcode_info->nof_operands = 1; + opcode_info->min_operands = 1; + opcode_info->max_operands = 1; opcode_info->size = 2; } break; case 'a': if( strcmp( ident, "ja" ) == 0 ) { opcode_info->opcode = OPCODE_JA; - opcode_info->nof_operands = 1; + opcode_info->min_operands = 1; + opcode_info->max_operands = 1; opcode_info->size = 2; } else if( strcmp( ident, "jae" ) == 0 ) { opcode_info->opcode = OPCODE_JAE; - opcode_info->nof_operands = 1; + opcode_info->min_operands = 1; + opcode_info->max_operands = 1; opcode_info->size = 2; } break; @@ -964,43 +986,50 @@ static OpcodeInfo *parseOpcode( void ) case 'm': if( strcmp( ident, "mov" ) == 0 ) { opcode_info->opcode = OPCODE_MOV; - opcode_info->nof_operands = 2; + opcode_info->min_operands = 2; + opcode_info->max_operands = 2; opcode_info->size = 5; } else if( strcmp( ident, "mul" ) == 0 ) { opcode_info->opcode = OPCODE_MUL; - opcode_info->nof_operands = 1; + opcode_info->min_operands = 1; + opcode_info->max_operands = 1; opcode_info->size = 2; } break; case 'n': if( strcmp( ident, "nop" ) == 0 ) { opcode_info->opcode = OPCODE_NOP; - opcode_info->nof_operands = 0; + opcode_info->min_operands = 0; + opcode_info->max_operands = 0; opcode_info->size = 1; } break; case 'p': if( strcmp( ident, "push" ) == 0 ) { opcode_info->opcode = OPCODE_PUSH; - opcode_info->nof_operands = 1; + opcode_info->min_operands = 1; + opcode_info->max_operands = 1; opcode_info->size = 1; } else if( strcmp( ident, "pop" ) == 0 ) { opcode_info->opcode = OPCODE_POP; - opcode_info->nof_operands = 1; + opcode_info->min_operands = 1; + opcode_info->max_operands = 1; opcode_info->size = 1; } break; case 'r': if( strcmp( ident, "ret" ) == 0 ) { opcode_info->opcode = OPCODE_RET; - opcode_info->nof_operands = 0; + opcode_info->min_operands = 0; + opcode_info->max_operands = 1; opcode_info->size = 1; } break; case 's': if( strcmp( ident, "sub" ) == 0 ) { opcode_info->opcode = OPCODE_SUB; - opcode_info->nof_operands = 2; + opcode_info->min_operands = 2; + opcode_info->max_operands = 2; opcode_info->size = 2; } break; @@ -1317,17 +1346,16 @@ static void parseOperands( OpcodeInfo *opcode_info ) } } - if( opcode_info->opcode != OPCODE_PSEUDO_DB && - opcode_info->opcode != OPCODE_PSEUDO_DW && - opcode_info->opcode != OPCODE_PSEUDO_DD && - nof_operands != opcode_info->nof_operands ) { - Abort( "'%s' expects %d operand(s), %d given", opcodename[opcode_info->opcode], opcode_info->nof_operands, nof_operands ); + if( nof_operands < opcode_info->min_operands ) { + Abort( "'%s' expects at least %d operand(s), only %d given", opcodename[opcode_info->opcode], opcode_info->min_operands, nof_operands ); + } + if( nof_operands > opcode_info->max_operands ) { + Abort( "'%s' expects at most %d operand(s), but %d given", opcodename[opcode_info->opcode], opcode_info->max_operands, nof_operands ); } switch( opcode_info->opcode ) { case OPCODE_HLT: case OPCODE_NOP: - case OPCODE_RET: break; case OPCODE_PSEUDO_DD: case OPCODE_PSEUDO_DW: { @@ -1349,7 +1377,7 @@ static void parseOperands( OpcodeInfo *opcode_info ) i++; operand_info = operand_info->next; } - opcode_info->nof_operands = i; + opcode_info->max_operands = i; opcode_info->size = size; } break; case OPCODE_PSEUDO_DB: { @@ -1367,7 +1395,7 @@ static void parseOperands( OpcodeInfo *opcode_info ) i++; operand_info = operand_info->next; } - opcode_info->nof_operands = i; + opcode_info->max_operands = i; opcode_info->size = size; } break; case OPCODE_MOV: @@ -1434,9 +1462,19 @@ static void parseOperands( OpcodeInfo *opcode_info ) } break; case OPCODE_INT: - if( opcode_info->operand->next->type != OPERAND_ABSOLUTE ) { + if( opcode_info->operand->type == OPERAND_ABSOLUTE ) { /* int $80, jump to interrupt vector number */ } + case OPCODE_RET: + if( opcode_info->operand == NULL ) { + /* ok, no parameter return */ + opcode_info->size = 1; + } else if( opcode_info->operand->type == OPERAND_ABSOLUTE ) { + /* return, pop N bytes from stack */ + opcode_info->size = 3; + } else { + Abort( "'%s' expects either no operand or a number of bytes to remove from the stack", opcodename[opcode_info->opcode] ); + } break; default: Abort( "Unhandled opcode '%s' when checking operand validity", opcodename[opcode_info->opcode] ); @@ -2169,7 +2207,12 @@ static void emit_opcode( OpcodeInfo *opcode_info ) } break; case OPCODE_RET: - Emit( "%c", 0xC3 ); + if( opcode_info->operand == NULL ) { + Emit( "%c", 0xC3 ); + } else if( opcode_info->operand->type == OPERAND_ABSOLUTE ) { + Emit( "%c", 0xC2 ); + Emit_word_little_endian( opcode_info->operand->num ); + } break; case OPCODE_PSEUDO_ASSIGN: break; |