From c096d1707246c8631219365034e11b28652c98f4 Mon Sep 17 00:00:00 2001 From: Andreas Baumann Date: Sat, 15 Aug 2020 19:51:05 +0200 Subject: correct returning from procedure with arguments - ec: first working return from a procedure with parameters - asm-i386: needed a ret imm16 to clean up stack when returning from call with parameters - asm-i386: introduced min and max operands constraints (better than arbitrary expections by opcode, for instance dd) --- ecomp-c/asm-i386.c | 113 ++++++++++++++++------- ecomp-c/ec.c | 46 ++++++--- ecomp-c/test.sh | 1 + ecomp-c/tests/procedure_call.easm | 1 + ecomp-c/tests/procedure_call_value_parameters.e | 6 +- ecomp-c/tests/procedure_forward_declaration.easm | 2 + ecomp-c/tests/procedure_local_variables.easm | 1 + ecomp-c/tests/procedure_scoping.easm | 2 + 8 files changed, 120 insertions(+), 52 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; diff --git a/ecomp-c/ec.c b/ecomp-c/ec.c index 5d42355..f6e1926 100644 --- a/ecomp-c/ec.c +++ b/ecomp-c/ec.c @@ -1548,15 +1548,34 @@ static void parseParameterList( Scope *scope ) ExpressionNode *node; Expect( S_lparen ); + Emit( "( " ); do { node = parseExpression( scope ); + generate_expression_comment( node ); if( sym == S_comma ) { sym = getSym( ); } } while( sym != S_rparen ); Expect( S_rparen ); - - (void)node; + + Emit( ")\n" ); + + emit_expression_code( node, scope ); +} + +static void parseProcedureCall( Scope *scope ) +{ + Symbol *symbol; + + symbol = get_symbol( scope, ident ); + + Emit( "; CALL %s", symbol->label ); + if( sym == S_lparen ) { + parseParameterList( scope ); + } else { + Emit( "\n" ); + } + Emit( "call %s\n", symbol->label ); } static void parseStatement( Scope *scope ) @@ -1576,10 +1595,7 @@ static void parseStatement( Scope *scope ) Abort( "Unknown indentifier '%s'", ident ); } if( symbol->class == SYMBOL_CLASS_PROCEDURE_TYPE ) { - if( sym == S_lparen ) { - parseParameterList( scope ); - } - Emit( "call %s\n", symbol->label ); + parseProcedureCall( scope ); } else { parseAssignment( scope ); } @@ -2082,7 +2098,7 @@ static void parseProcedureDeclaration( Scope *scope ) param = symbol->scope->symbol; size_params = 0; - offset = 0; + offset = -4; while( param != NULL ) { if( param->class == SYMBOL_CLASS_VARIABLE ) { int size = get_size( param ); @@ -2143,7 +2159,7 @@ static void parseProcedureDeclaration( Scope *scope ) * at runtime (every time the stack is created for that procedure) */ param_or_local = symbol->scope->symbol; while( param_or_local != NULL ) { - if( param_or_local->class == SYMBOL_CLASS_VARIABLE ) { + if( param_or_local->class == SYMBOL_CLASS_VARIABLE && param_or_local->offset >= 0 ) { /* TODO: use type here! */ int size = get_size( param_or_local ); if( param_or_local->type == integer_type || param_or_local->type == boolean_type ) { @@ -2187,15 +2203,17 @@ static void parseProcedureDeclaration( Scope *scope ) parseStatementBlock( symbol->scope ); - /* discard locals, discard params, reset base pointer */ - if( size_locals + size_params > 0 ) { - Emit( "mov eax, %d\n", size_locals + size_params ); + /* discard locals, restore base pointer, discard params */ + if( size_locals > 0 ) { + Emit( "mov eax, %d\n", size_locals ); Emit( "add esp, eax\n" ); } - Emit( "pop ebp\n" ); - - Emit( "ret\n" ); + if( size_params > 0 ) { + Emit( "ret %d\n", size_params ); + } else { + Emit( "ret\n" ); + } } free_scope( symbol->scope ); diff --git a/ecomp-c/test.sh b/ecomp-c/test.sh index 014eb98..6030462 100755 --- a/ecomp-c/test.sh +++ b/ecomp-c/test.sh @@ -26,6 +26,7 @@ procedure_call procedure_forward_declaration procedure_local_variables procedure_scoping +procedure_call_value_parameters example_divisors example_divisors_array_result example_reverse_array diff --git a/ecomp-c/tests/procedure_call.easm b/ecomp-c/tests/procedure_call.easm index 09daf38..013f8b2 100644 --- a/ecomp-c/tests/procedure_call.easm +++ b/ecomp-c/tests/procedure_call.easm @@ -16,6 +16,7 @@ mov [i], eax pop ebp ret __global_0: +; CALL __global_proc call __global_proc hlt i: dd $00000000 diff --git a/ecomp-c/tests/procedure_call_value_parameters.e b/ecomp-c/tests/procedure_call_value_parameters.e index 3b100ed..f0d6372 100644 --- a/ecomp-c/tests/procedure_call_value_parameters.e +++ b/ecomp-c/tests/procedure_call_value_parameters.e @@ -5,14 +5,14 @@ module procedure_call_value_parameters; var - i : integer := 0; - + i : integer := 1; + procedure proc( x : integer ); var l : integer; begin l := x; - i := x; + i := l; end begin diff --git a/ecomp-c/tests/procedure_forward_declaration.easm b/ecomp-c/tests/procedure_forward_declaration.easm index 79ad4a4..23440e3 100644 --- a/ecomp-c/tests/procedure_forward_declaration.easm +++ b/ecomp-c/tests/procedure_forward_declaration.easm @@ -8,6 +8,7 @@ __global_proc1: push ebp push esp pop ebp +; CALL __global_proc2 call __global_proc2 pop ebp ret @@ -24,6 +25,7 @@ mov [i], eax pop ebp ret __global_0: +; CALL __global_proc1 call __global_proc1 hlt i: dd $00000000 diff --git a/ecomp-c/tests/procedure_local_variables.easm b/ecomp-c/tests/procedure_local_variables.easm index 88312af..1979c0c 100644 --- a/ecomp-c/tests/procedure_local_variables.easm +++ b/ecomp-c/tests/procedure_local_variables.easm @@ -50,6 +50,7 @@ add esp, eax pop ebp ret __global_0: +; CALL __global_proc call __global_proc hlt i: dd $00000001 diff --git a/ecomp-c/tests/procedure_scoping.easm b/ecomp-c/tests/procedure_scoping.easm index 07106a7..64a9d31 100644 --- a/ecomp-c/tests/procedure_scoping.easm +++ b/ecomp-c/tests/procedure_scoping.easm @@ -93,7 +93,9 @@ push eax pop eax pop ebx mov [ebx], eax +; CALL __global_A call __global_A +; CALL __global_B call __global_B hlt y: dd $00000000 -- cgit v1.2.3-54-g00ecf