diff --git a/chibicc.h b/chibicc.h index c01e339..0f133b7 100644 --- a/chibicc.h +++ b/chibicc.h @@ -140,6 +140,7 @@ struct Obj { bool is_static; // Global variable + bool is_tentative; char *init_data; Relocation *rel; diff --git a/codegen.c b/codegen.c index 0612118..2066802 100644 --- a/codegen.c +++ b/codegen.c @@ -1136,6 +1136,11 @@ static void emit_data(Obj *prog) { ? MAX(16, var->align) : var->align; println(" .align %d", align); + if (var->is_tentative) { + println(" .comm %s, %d, %d", var->name, var->ty->size, align); + continue; + } + if (var->init_data) { println(" .data"); println("%s:", var->name); diff --git a/parse.c b/parse.c index a03e8c1..96286e1 100644 --- a/parse.c +++ b/parse.c @@ -2947,6 +2947,8 @@ static Token *global_variable(Token *tok, Type *basety, VarAttr *attr) { if (equal(tok, "=")) gvar_initializer(&tok, tok->next, var); + else if (!attr->is_extern) + var->is_tentative = true; } return tok; } @@ -2962,6 +2964,33 @@ static bool is_function(Token *tok) { return ty->kind == TY_FUNC; } +// Remove redundant tentative definitions. +static void scan_globals(void) { + Obj head; + Obj *cur = &head; + + for (Obj *var = globals; var; var = var->next) { + if (!var->is_tentative) { + cur = cur->next = var; + continue; + } + + // Find another definition of the same identifier. + Obj *var2 = globals; + for (; var2; var2 = var2->next) + if (var != var2 && var2->is_definition && !strcmp(var->name, var2->name)) + break; + + // If there's another definition, the tentative definition + // is redundant + if (!var2) + cur = cur->next = var; + } + + cur->next = NULL; + globals = head.next; +} + // program = (typedef | function-definition | global-variable)* Obj *parse(Token *tok) { globals = NULL; @@ -2990,5 +3019,7 @@ Obj *parse(Token *tok) { if (var->is_root) mark_live(var); + // Remove redundant tentative definitions. + scan_globals(); return globals; } diff --git a/test/common b/test/common index c60a42a..9676755 100644 --- a/test/common +++ b/test/common @@ -17,6 +17,8 @@ int *ext2 = &ext1; int ext3 = 7; int ext_fn1(int x) { return x; } int ext_fn2(int x) { return x; } +int common_ext2 = 3; +static int common_local; int false_fn() { return 512; } int true_fn() { return 513; } diff --git a/test/commonsym.c b/test/commonsym.c new file mode 100644 index 0000000..7599527 --- /dev/null +++ b/test/commonsym.c @@ -0,0 +1,19 @@ +#include "test.h" + +int x; +int x = 5; +int y = 7; +int y; +int common_ext1; +int common_ext2; +static int common_local; + +int main() { + ASSERT(5, x); + ASSERT(7, y); + ASSERT(0, common_ext1); + ASSERT(3, common_ext2); + + printf("OK\n"); + return 0; +}