diff --git a/.build.yml b/.build.yml index 1bd8d46..d6b0439 100644 --- a/.build.yml +++ b/.build.yml @@ -2,8 +2,14 @@ image: archlinux packages: - make - cmake + - mkrom + - patchrom + - genkfs + - mktiupgrade + - valgrind sources: - https://github.com/knightos/scas + - https://github.com/knightos/kernel environment: project: scas tasks: @@ -13,3 +19,8 @@ tasks: cd build cmake -DCMAKE_BUILD_TYPE=Release .. make + cd ../../kernel + # Temporary: use scas PR + git checkout scas + mkdir bin/TI84pSE -p + make AS="valgrind --track-origins=yes --leak-check=full --error-exitcode=1 ../scas/build/scas" diff --git a/.gitignore b/.gitignore index f023399..8d1fb99 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,5 @@ test/ build/ .lvimrc tables/z80.c +.ccls +.ccls-cache diff --git a/CMakeLists.txt b/CMakeLists.txt index 692aee5..d1d57b3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,6 @@ cmake_minimum_required(VERSION 2.8.5) project(scas C) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -pedantic -std=c99 -D_XOPEN_SOURCE=700") -set(CMAKE_C_FLAGS_DEVEL "-Werror -g -Og") if(WIN32) set(CMAKE_C_FLAGS "-Wl,--allow-multiple-definition") diff --git a/assembler/assembler.c b/assembler/assembler.c index 1502dbd..1f1ff39 100644 --- a/assembler/assembler.c +++ b/assembler/assembler.c @@ -172,9 +172,18 @@ int try_expand_macro(struct assembler_state *state, char **line) { if (strstr(*line, "macro") == *line + 1) { // Cannot expand macros while defining them return 0; } + if (strstr(*line, "undefine") == *line + 1) { // Should not expand while removing + return 0; + } if (strstr(*line, "ifdef") == *line + 1) { // Should not expand when testing for existence return 0; } + // Shouldn't expand macros in equates + if ((**line == '.' || **line == '#')) { + if (code_strstr(*line, ".equ") || code_strchr(*line, '=')) { + return 0; + } + } int i; for (i = 0; i < state->macros->length; i++) { macro_t *macro = state->macros->items[i]; @@ -326,7 +335,7 @@ int try_add_label(struct assembler_state *state, char **line) { /* Add label */ symbol_t *sym = malloc(sizeof(symbol_t)); - sym->exported = 1; /* TODO: Support explicit export */ + sym->exported = !scas_runtime.options.explicit_export; sym->type = SYMBOL_LABEL; sym->value = state->PC + scas_runtime.options.origin; sym->defined_address = state->current_area->data_length; @@ -433,7 +442,14 @@ int try_match_instruction(struct assembler_state *state, char **_line) { transform_local_labels(expression, state->last_global_label); const char *file_name = stack_peek(state->file_name_stack); transform_relative_labels(expression, state->last_relative_label, file_name); + symbol_t sym_pc = { + .type = SYMBOL_LABEL, + .value = state->PC, + .name = "$" + }; + list_add(state->equates, &sym_pc); result = evaluate_expression(expression, state->equates, &error, &symbol); + state->equates->length -= 1; if (error == EXPRESSION_BAD_SYMBOL) { if (scas_runtime.options.explicit_import && strcmp(symbol, "$") != 0) { unresolved_symbol_t *unresolved_sym = malloc(sizeof(unresolved_symbol_t)); @@ -605,8 +621,8 @@ object_t *assemble(FILE *file, const char *file_name, assembler_settings_t *sett try_empty_line, try_parse_inside_macro, try_split_line, - try_expand_macro, try_add_label, + try_expand_macro, try_handle_directive, try_match_instruction, }; @@ -707,11 +723,7 @@ object_t *assemble(FILE *file, const char *file_name, assembler_settings_t *sett macro_free(macro); } list_free(state.macros); - for (int i = 0; i < state.equates->length; i += 1) { - symbol_t *sym = (symbol_t*)state.equates->items[i]; - free(sym->name); - free(sym); - } + // Equates are also added to an area's symbols list, so they're cleaned up there list_free(state.equates); stack_free(state.source_map_stack); free(state.instruction_buffer); diff --git a/assembler/directives.c b/assembler/directives.c index 3eb3303..61aedfd 100644 --- a/assembler/directives.c +++ b/assembler/directives.c @@ -152,6 +152,7 @@ int handle_block(struct assembler_state *state, char **argv, int argc) { if (error == EXPRESSION_BAD_SYMBOL) { ERROR(ERROR_UNKNOWN_SYMBOL, state->column, symbol); + free_expression(expression); return 1; } @@ -167,6 +168,8 @@ int handle_block(struct assembler_state *state, char **argv, int argc) { result = 0; } } + free(buffer); + free_expression(expression); return 1; } @@ -433,6 +436,8 @@ int handle_undef(struct assembler_state *state, char **argv, int argc) { return 1; } + scas_log(L_DEBUG, "Looking for %s", argv[0]); + int i; for (i = 0; i < state->macros->length; i++) { macro_t *m = state->macros->items[i]; @@ -610,11 +615,20 @@ static void printf_putc(char c) { putchar(c); } -int handle_printf(struct assembler_state *state, char **argv, int argc) { +int handle_echo(struct assembler_state *state, char **argv, int argc) { if (argc == 0) { ERROR(ERROR_INVALID_DIRECTIVE, state->column, "echo expects 1+ arguments"); return 1; } + (void)argv; + return 1; +} + +int handle_printf(struct assembler_state *state, char **argv, int argc) { + if (argc == 0) { + ERROR(ERROR_INVALID_DIRECTIVE, state->column, "printf expects 1+ arguments"); + return 1; + } int len = strlen(argv[0]); if (argv[0][0] != '"' || argv[0][len - 1] != '"') { ERROR(ERROR_INVALID_DIRECTIVE, state->column, "unterminated string"); @@ -737,8 +751,19 @@ int handle_equ(struct assembler_state *state, char **argv, int argc) { ERROR_NO_ARG(ERROR_INVALID_SYNTAX, state->column); return 1; } else { + transform_local_labels(expression, state->last_global_label); + int len = state->equates->length; + for (int i = 0; i < state->current_area->symbols->length; i += 1) { + list_add(state->equates, state->current_area->symbols->items[i]); + } + symbol_t sym_pc = { + .type = SYMBOL_LABEL, + .value = state->PC, + .name = "$" + }; + list_add(state->equates, &sym_pc); result = evaluate_expression(expression, state->equates, &error, &symbol); - free_expression(expression); + state->equates->length = len; } if (error == EXPRESSION_BAD_SYMBOL) { ERROR(ERROR_UNKNOWN_SYMBOL, state->column, symbol); @@ -752,8 +777,10 @@ int handle_equ(struct assembler_state *state, char **argv, int argc) { sym->value = result; sym->exported = 0; list_add(state->equates, sym); + list_add(state->current_area->symbols, sym); scas_log(L_DEBUG, "Added equate '%s' with value 0x%08X", sym->name, sym->value); } + free_expression(expression); return 1; } @@ -1277,7 +1304,7 @@ struct directive directives[] = { { "dl", handle_dl, DELIM_COMMAS }, { "ds", handle_block, DELIM_COMMAS }, { "dw", handle_dw, DELIM_COMMAS }, - //{ "echo", handle_echo, DELIM_COMMAS | DELIM_WHITESPACE }, + { "echo", handle_echo, DELIM_COMMAS | DELIM_WHITESPACE }, { "elif", handle_elseif, 0 }, { "else", handle_else, 0 }, { "elseif", handle_elseif, 0 }, diff --git a/common/errors.c b/common/errors.c index 42d388b..3d1900f 100644 --- a/common/errors.c +++ b/common/errors.c @@ -2,6 +2,7 @@ #include "list.h" #include "log.h" #include "objects.h" +#include #include #include #include @@ -101,15 +102,14 @@ void add_warning(list_t *warnings, int code, size_t line_number, void add_error_from_map(list_t *errors, int code, list_t *maps, uint64_t address, ...) { source_map_t *map; source_map_entry_t *entry; - int found = 0; - int i; - for (i = 0; i < maps->length; ++i) { + bool found = false; + for (int i = 0; i < maps->length; ++i) { map = maps->items[i]; int j; for (j = 0; j < map->entries->length; ++j) { entry = map->entries->items[j]; if (address >= entry->address && address < entry->address + entry->length) { - found = 1; + found = true; break; } } @@ -135,16 +135,25 @@ void add_error_from_map(list_t *errors, int code, list_t *maps, uint64_t address va_end(args); error->message = buf; + scas_log(L_ERROR, "Added error '%s' at:", buf); if (found) { error->line_number = entry->line_number; error->file_name = strdup(map->file_name); error->line = strdup(entry->source_code); + for (int i = 0; i < maps->length; ++i) { + map = maps->items[i]; + for (int j = 0; j < map->entries->length; ++j) { + entry = map->entries->items[j]; + if (address >= entry->address && address < entry->address + entry->length) { + scas_log(L_ERROR, "\t%s:%d:%d", map->file_name, + entry->line_number, error->column); + } + } + } } else { error->line_number = 0; error->file_name = NULL; error->line = NULL; } list_add(errors, error); - scas_log(L_ERROR, "Added error '%s' at %s:%d:%d", buf, error->file_name, - error->line_number, error->column); } diff --git a/common/list.c b/common/list.c index a7585a3..4ddc02f 100644 --- a/common/list.c +++ b/common/list.c @@ -49,12 +49,13 @@ void list_insert(list_t *list, int index, void *item) { void list_del(list_t *list, int index) { list->length--; - memmove(&list->items[index], &list->items[index + 1], sizeof(void*) * (list->length - index)); + if (index != list->length) { + memmove(&list->items[index], &list->items[index + 1], sizeof(void*) * (list->length - index)); + } } void list_cat(list_t *list, list_t *source) { - int i; - for (i = 0; i < source->length; ++i) { + for (int i = 0; i < source->length; ++i) { list_add(list, source->items[i]); } } diff --git a/include/assembler.h b/include/assembler.h index ef761b0..046c2a1 100644 --- a/include/assembler.h +++ b/include/assembler.h @@ -50,6 +50,7 @@ struct assembler_state { object_t *assemble(FILE *file, const char *file_name, assembler_settings_t *settings); void transform_local_labels(tokenized_expression_t *expression, const char *last_global_label); +void transform_relative_labels(tokenized_expression_t *expression, int last_relative_label, const char *const file_name); void macro_free(macro_t *macro); #endif diff --git a/linker/linker.c b/linker/linker.c index acc0c77..b260b97 100644 --- a/linker/linker.c +++ b/linker/linker.c @@ -191,9 +191,8 @@ void link_objects(FILE *output, list_t *objects, linker_settings_t *settings) { if (scas_runtime.options.remove_unused_functions) { remove_unused_functions(merged); } - int i; uint64_t address = 0; - for (i = 0; i < merged->areas->length; ++i) { + for (int i = 0; i < merged->areas->length; ++i) { area_t *area = merged->areas->items[i]; relocate_area(area, address, false); if (settings->automatic_relocation) { @@ -206,11 +205,11 @@ void link_objects(FILE *output, list_t *objects, linker_settings_t *settings) { } address += area->data_length; } - for (i = 0; i < merged->areas->length; ++i) { + for (int i = 0; i < merged->areas->length; ++i) { area_t *area = merged->areas->items[i]; gather_symbols(symbols, area, settings); } - for (i = 0; i < merged->areas->length; ++i) { + for (int i = 0; i < merged->areas->length; ++i) { area_t *area = merged->areas->items[i]; scas_log(L_INFO, "Linking area %s", area->name); if (scas_runtime.options.origin) { @@ -222,6 +221,20 @@ void link_objects(FILE *output, list_t *objects, linker_settings_t *settings) { } settings->write_output(output, final->data, (int)final->data_length); scas_log(L_DEBUG, "Final binary written: %d bytes", ftell(output)); + + if (scas_runtime.symbol_file) { + scas_log(L_DEBUG, "Generating symbol file '%s'", scas_runtime.symbol_file); + FILE *symfile = fopen(scas_runtime.symbol_file, "w"); + for (int i = 0; i < symbols->length; i++) { + symbol_t *symbol = symbols->items[i]; + if (symbol->type == SYMBOL_LABEL && symbol->exported && !strchr(symbol->name, '@')) { + fprintf(symfile, ".equ %s 0x%lX\n", symbol->name, symbol->value); + } + } + fflush(symfile); + fclose(symfile); + } + object_free(merged); area_free(final); list_free(symbols); diff --git a/scas/main.c b/scas/main.c index c0dab1f..1aa3570 100644 --- a/scas/main.c +++ b/scas/main.c @@ -324,6 +324,7 @@ int main(int argc, char **argv) { } fclose(out); } + if (errors->length != 0) { int i; for (i = 0; i < errors->length; ++i) {