[qfcc] Adjust ivar offsets to preserve alignment

As a class's ivars are built up by inheritance, but with only that
class's ivars in the symbol table, is is necessary to include an offset
based on the super class's ivars in order to ensure alignments are
respected. This is achieved via the new `base` parameter to
build_struct(), which is used to offset the current size while
calculating the aligned offset of the symbols. The parameter is ignored
for unions, as they always start at 0. The ivars for the current class
still have a base offset of 0 until they are actually added to the
class.

Fixes #29
This commit is contained in:
Bill Currie 2022-07-31 16:56:18 +09:00
parent f4ae24e0e0
commit 6253d775e6
3 changed files with 11 additions and 6 deletions

View file

@ -46,7 +46,8 @@ typedef struct {
struct symbol_s *find_struct (int su, struct symbol_s *tag,
struct type_s *type);
struct symbol_s *build_struct (int su, struct symbol_s *tag,
struct symtab_s *symtab, struct type_s *type);
struct symtab_s *symtab, struct type_s *type,
int base);
struct symbol_s *find_enum (struct symbol_s *tag);
struct symtab_s *start_enum (struct symbol_s *enm);
struct symbol_s *finish_enum (struct symbol_s *sym);

View file

@ -846,7 +846,7 @@ struct_specifier
current_symtab = symtab->parent;
if ($1) {
sym = build_struct ($1, $2, symtab, 0);
sym = build_struct ($1, $2, symtab, 0, 0);
$$ = make_spec (sym->type, 0, 0, 0);
if (!sym->table)
symtab_addsymbol (current_symtab, sym);
@ -2051,7 +2051,11 @@ ivar_decl_list
tab->parent = 0;
tab = $$->parent; // preserve the ivars inheritance chain
build_struct ('s', 0, $$, 0);
int base = 0;
if ($<class>0->super_class) {
base = type_size ($<class>0->super_class->type);
}
build_struct ('s', 0, $$, 0, base);
$$->parent = tab;
current_visibility = vis_public;
}

View file

@ -110,7 +110,7 @@ find_struct (int su, symbol_t *tag, type_t *type)
}
symbol_t *
build_struct (int su, symbol_t *tag, symtab_t *symtab, type_t *type)
build_struct (int su, symbol_t *tag, symtab_t *symtab, type_t *type, int base)
{
symbol_t *sym = find_struct (su, tag, type);
symbol_t *s;
@ -131,7 +131,7 @@ build_struct (int su, symbol_t *tag, symtab_t *symtab, type_t *type)
s->type->t.class->name);
}
if (su == 's') {
symtab->size = RUP (symtab->size, s->type->alignment);
symtab->size = RUP (symtab->size + base, s->type->alignment) - base;
s->s.offset = symtab->size;
symtab->size += type_size (s->type);
} else {
@ -304,7 +304,7 @@ make_structure (const char *name, int su, struct_def_t *defs, type_t *type)
internal_error (0, "duplicate symbol: %s", defs->name);
defs++;
}
sym = build_struct (su, sym, strct, type);
sym = build_struct (su, sym, strct, type, 0);
return sym;
}