diff --git a/tools/qfcc/include/reloc.h b/tools/qfcc/include/reloc.h index 99d4992a1..be6d5e622 100644 --- a/tools/qfcc/include/reloc.h +++ b/tools/qfcc/include/reloc.h @@ -45,6 +45,10 @@ typedef enum { rel_def_func, rel_def_string, rel_def_field, + rel_op_a_def_ofs, + rel_op_b_def_ofs, + rel_op_c_def_ofs, + rel_def_def_ofs, } reloc_type; typedef struct reloc_s { @@ -59,7 +63,10 @@ struct statement_s; reloc_t *new_reloc (int ofs, reloc_type type); void relocate_refs (reloc_t *refs, int ofs); +void reloc_op_def (struct def_s *def, int ofs, int field); +void reloc_op_def_ofs (struct def_s *def, int ofs, int field); void reloc_def_def (struct def_s *def, int ofs); +void reloc_def_def_ofs (struct def_s *def, int ofs); void reloc_def_func (struct function_s *func, int ofs); void reloc_def_string (int ofs); void reloc_def_field (struct def_s *def, int ofs); diff --git a/tools/qfcc/source/emit.c b/tools/qfcc/source/emit.c index fc04b7668..3bfabc7c2 100644 --- a/tools/qfcc/source/emit.c +++ b/tools/qfcc/source/emit.c @@ -97,16 +97,16 @@ codespace_newstatement (codespace_t *codespace) } static void -add_statement_ref (def_t *def, dstatement_t *st, reloc_type type) +add_statement_ref (def_t *def, dstatement_t *st, int field) { if (def) { - reloc_t *ref = new_reloc (st - pr.code->code, type); + int st_ofs = st - pr.code->code; - if (def->alias) + if (def->alias) { def = def->alias; - - ref->next = def->refs; - def->refs = ref; + reloc_op_def_ofs (def, st_ofs, field); + } else + reloc_op_def (def, st_ofs, field); def->users--; def->used = 1; @@ -162,9 +162,9 @@ emit_statement (expr_t *e, opcode_t *op, def_t *var_a, def_t *var_b, var_c ? var_c->name : "", statement->c); #endif - add_statement_ref (var_a, statement, rel_op_a_def); - add_statement_ref (var_b, statement, rel_op_b_def); - add_statement_ref (var_c, statement, rel_op_c_def); + add_statement_ref (var_a, statement, 0); + add_statement_ref (var_b, statement, 1); + add_statement_ref (var_c, statement, 2); if (op->right_associative) return var_a; @@ -384,11 +384,10 @@ emit_deref_expr (expr_t *e, def_t *dest) e = e->e.expr.e1; if (e->type == ex_pointer) { if (e->e.pointer.def) { - d = new_def (e->e.pointer.type, 0, current_scope); + d = new_def (e->e.pointer.type, 0, e->e.pointer.def->scope); d->local = e->e.pointer.def->local; - d->ofs = POINTER_VAL (e->e.pointer); - if (d->ofs == e->e.pointer.def->ofs) - d->alias = e->e.pointer.def; + d->ofs = e->e.pointer.val; + d->alias = e->e.pointer.def; } else if (e->e.pointer.val >= 0 && e->e.pointer.val < 65536) { d = new_def (e->e.pointer.type, 0, current_scope); d->ofs = e->e.pointer.val; diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index ec2ea43a9..d9dcda5ae 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -1249,7 +1249,7 @@ field_expr (expr_t *e1, expr_t *e2) e = new_expr (); e->type = ex_pointer; e1 = e1->e.expr.e1; - i = POINTER_VAL (e1->e.pointer); + i = e1->e.pointer.val; e->e.pointer.val = i + field->offset; e->e.pointer.type = field->type; return unary_expr ('.', e); diff --git a/tools/qfcc/source/linker.c b/tools/qfcc/source/linker.c index 50bf282bd..0ddb945d8 100644 --- a/tools/qfcc/source/linker.c +++ b/tools/qfcc/source/linker.c @@ -215,6 +215,9 @@ add_relocs (qfo_t *qfo) case rel_op_a_def: case rel_op_b_def: case rel_op_c_def: + case rel_op_a_def_ofs: + case rel_op_b_def_ofs: + case rel_op_c_def_ofs: reloc->ofs += code_base; break; case rel_op_a_op: @@ -232,6 +235,7 @@ add_relocs (qfo_t *qfo) DATA (reloc->ofs)->func_var = reloc->def + 1; break; case rel_def_def: + case rel_def_def_ofs: reloc->ofs += data_base; break; case rel_def_string: @@ -470,6 +474,10 @@ fixup_relocs (void) case rel_op_c_def: case rel_def_def: case rel_def_field: + case rel_op_a_def_ofs: + case rel_op_b_def_ofs: + case rel_op_c_def_ofs: + case rel_def_def_ofs: def = defs.defs + reloc->def; if (def->flags & (QFOD_EXTERNAL | QFOD_LOCAL | QFOD_ABSOLUTE)) continue; @@ -498,6 +506,10 @@ fixup_relocs (void) case rel_op_a_op: case rel_op_b_op: case rel_op_c_op: + case rel_op_a_def_ofs: + case rel_op_b_def_ofs: + case rel_op_c_def_ofs: + case rel_def_def_ofs: break; case rel_def_op: DATA (reloc->ofs)->integer_var = reloc->def; @@ -806,8 +818,12 @@ undefined_def (qfo_def_t *def) qfo_reloc_t *reloc = relocs.relocs + def->relocs; for (i = 0; i < def->num_relocs; i++, reloc++) { - if ((reloc->type == rel_op_a_def || reloc->type == rel_op_b_def - || reloc->type == rel_op_c_def) + if ((reloc->type == rel_op_a_def + || reloc->type == rel_op_b_def + || reloc->type == rel_op_c_def + || reloc->type == rel_op_a_def_ofs + || reloc->type == rel_op_b_def_ofs + || reloc->type == rel_op_c_def_ofs) && lines.lines) { qfo_func_t *func = funcs.funcs; qfo_func_t *best = func; diff --git a/tools/qfcc/source/qfcc.c b/tools/qfcc/source/qfcc.c index 1c1ece9f6..2075add76 100644 --- a/tools/qfcc/source/qfcc.c +++ b/tools/qfcc/source/qfcc.c @@ -426,11 +426,8 @@ finish_compilation (void) st_global)); } - for (def = pr.scope->head; def; def = def->def_next) { - if (def->global || def->absolute) - continue; + for (def = pr.scope->head; def; def = def->def_next) relocate_refs (def->refs, def->ofs); - } pr.functions = calloc (pr.num_functions + 1, sizeof (dfunction_t)); for (df = pr.functions + 1, f = pr.func_head; f; df++, f = f->next) { @@ -452,8 +449,6 @@ finish_compilation (void) } df->parm_start = pr.near_data->size; for (def = f->scope->head; def; def = def->def_next) { - if (def->absolute) - continue; def->ofs += pr.near_data->size; relocate_refs (def->refs, def->ofs); } diff --git a/tools/qfcc/source/reloc.c b/tools/qfcc/source/reloc.c index ade3d7da5..10bf78137 100644 --- a/tools/qfcc/source/reloc.c +++ b/tools/qfcc/source/reloc.c @@ -114,6 +114,30 @@ relocate_refs (reloc_t *refs, int ofs) break; case rel_def_field: break; + case rel_op_a_def_ofs: + o = ofs + pr.code->code[refs->ofs].a; + if (o < 0 || o > 65535) + error (0, "def offset out of range"); + else + pr.code->code[refs->ofs].a = o; + break; + case rel_op_b_def_ofs: + o = ofs + pr.code->code[refs->ofs].b; + if (o < 0 || o > 65535) + error (0, "def offset out of range"); + else + pr.code->code[refs->ofs].b = o; + break; + case rel_op_c_def_ofs: + o = ofs + pr.code->code[refs->ofs].c; + if (o < 0 || o > 65535) + error (0, "def offset out of range"); + else + pr.code->code[refs->ofs].c = o; + break; + case rel_def_def_ofs: + G_INT (refs->ofs) += ofs; + break; } refs = refs->next; } @@ -132,6 +156,24 @@ new_reloc (int ofs, reloc_type type) return ref; } +void +reloc_op_def (def_t *def, int ofs, int field) +{ + reloc_t *ref = new_reloc (ofs, rel_op_a_def + field); + ref->next = def->refs; + def->refs = ref; +} + +void +reloc_op_def_ofs (def_t *def, int ofs, int field) +{ + reloc_t *ref = new_reloc (ofs, rel_op_a_def_ofs + field); + unsigned short x = (&pr.code->code[ofs].a)[field]; + printf ("%3d %c %3d %3d %s\n", ofs, 'a' + field, x, def->ofs, def->name); + ref->next = def->refs; + def->refs = ref; +} + void reloc_def_def (def_t *def, int ofs) { @@ -140,6 +182,14 @@ reloc_def_def (def_t *def, int ofs) def->refs = ref; } +void +reloc_def_def_ofs (def_t *def, int ofs) +{ + reloc_t *ref = new_reloc (ofs, rel_def_def_ofs); + ref->next = def->refs; + def->refs = ref; +} + void reloc_def_func (function_t *func, int ofs) {