diff --git a/tools/qfcc/include/def.h b/tools/qfcc/include/def.h index e3bb823df..10af435c1 100644 --- a/tools/qfcc/include/def.h +++ b/tools/qfcc/include/def.h @@ -43,7 +43,7 @@ typedef struct def_s { int ofs; int initialized; // for uninit var detection int constant; // 1 when a declaration included "= immediate" - struct statref_s *refs; // for relocations + struct reloc_s *refs; // for relocations unsigned freed:1; // already freed from the scope unsigned removed:1; // already removed from the symbol table diff --git a/tools/qfcc/include/expr.h b/tools/qfcc/include/expr.h index 3384f0273..f195c8a6f 100644 --- a/tools/qfcc/include/expr.h +++ b/tools/qfcc/include/expr.h @@ -56,8 +56,9 @@ typedef enum { ex_short, } expr_type; -typedef struct { - struct statref_s *refs; +typedef struct ex_label_s { + struct ex_label_s *next; + struct reloc_s *refs; int ofs; const char *name; } ex_label_t; diff --git a/tools/qfcc/include/opcodes.h b/tools/qfcc/include/opcodes.h index 25c7c8da3..b2c2df654 100644 --- a/tools/qfcc/include/opcodes.h +++ b/tools/qfcc/include/opcodes.h @@ -32,31 +32,23 @@ #ifndef __opcodes_h #define __opcodes_h -#include "QF/pr_comp.h" +extern struct opcode_s *op_done; +extern struct opcode_s *op_return; +extern struct opcode_s *op_if; +extern struct opcode_s *op_ifnot; +extern struct opcode_s *op_ifbe; +extern struct opcode_s *op_ifb; +extern struct opcode_s *op_ifae; +extern struct opcode_s *op_ifa; +extern struct opcode_s *op_state; +extern struct opcode_s *op_goto; +extern struct opcode_s *op_jump; +extern struct opcode_s *op_jumpb; -typedef struct statref_s { - struct statref_s *next; - int ofs; - int field; // a, b, c (0, 1, 2) -} statref_t; +struct def_s; -extern opcode_t *op_done; -extern opcode_t *op_return; -extern opcode_t *op_if; -extern opcode_t *op_ifnot; -extern opcode_t *op_ifbe; -extern opcode_t *op_ifb; -extern opcode_t *op_ifae; -extern opcode_t *op_ifa; -extern opcode_t *op_state; -extern opcode_t *op_goto; -extern opcode_t *op_jump; -extern opcode_t *op_jumpb; - -statref_t *PR_NewStatref (int ofs, int field); -void PR_AddStatementRef (struct def_s *def, dstatement_t *st, int field); -opcode_t *PR_Opcode_Find (const char *name, struct def_s *var_a, - struct def_s *var_b, struct def_s *var_c); -void PR_Opcode_Init_Tables (void); +struct opcode_s *opcode_find (const char *name, struct def_s *var_a, + struct def_s *var_b, struct def_s *var_c); +void opcode_init (void); #endif//__opcodes_h diff --git a/tools/qfcc/include/qfcc.h b/tools/qfcc/include/qfcc.h index 57ad3d816..5117412e8 100644 --- a/tools/qfcc/include/qfcc.h +++ b/tools/qfcc/include/qfcc.h @@ -45,6 +45,7 @@ // typedef struct { struct type_s *types; + struct ex_label_s *labels; struct def_s *def_head; // unused head of linked list struct def_s **def_tail; // add new defs after this and move it diff --git a/tools/qfcc/include/reloc.h b/tools/qfcc/include/reloc.h new file mode 100644 index 000000000..a090fd69a --- /dev/null +++ b/tools/qfcc/include/reloc.h @@ -0,0 +1,58 @@ +/* + reloc.h + + #DESCRIPTION# + + Copyright (C) 2001 #AUTHOR# + + Author: #AUTHOR# + Date: #DATE# + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + + $Id$ +*/ + +#ifndef __reloc_h +#define __reloc_h + +typedef enum { + rel_none, + rel_op_a_def, + rel_op_b_def, + rel_op_c_def, + rel_op_a_op, + rel_op_b_op, + rel_op_c_op, + rel_def_op, + rel_def_def, +} reloc_type; + +typedef struct reloc_s { + struct reloc_s *next; + int ofs; + reloc_type type; +} reloc_t; + +struct statement_s; + +reloc_t *new_reloc (int ofs, reloc_type type); +void relocate_refs (reloc_t *refs, int ofs); + +#endif//__reloc_h diff --git a/tools/qfcc/source/Makefile.am b/tools/qfcc/source/Makefile.am index c1bd2ae0e..0c64b6708 100644 --- a/tools/qfcc/source/Makefile.am +++ b/tools/qfcc/source/Makefile.am @@ -40,7 +40,7 @@ bin_PROGRAMS= qfcc qfcc_SOURCES= \ class.c cmdlib.c cpp.c debug.c emit.c expr.c function.c idstuff.c \ immediate.c method.c opcodes.c options.c pr_def.c qc-lex.l qc-parse.y \ - qfcc.c struct.c switch.c type.c + qfcc.c reloc.c struct.c switch.c type.c qfcc_LDADD= $(QFCC_LIBS) qfcc_DEPENDENCIES= $(QFCC_DEPS) diff --git a/tools/qfcc/source/emit.c b/tools/qfcc/source/emit.c index c0c5cb854..0bded415f 100644 --- a/tools/qfcc/source/emit.c +++ b/tools/qfcc/source/emit.c @@ -51,11 +51,26 @@ static const char rcsid[] = #include "opcodes.h" #include "options.h" #include "qfcc.h" +#include "reloc.h" #include "type.h" #include "qc-parse.h" def_t *emit_sub_expr (expr_t *e, def_t *dest); +void +add_statement_ref (def_t *def, dstatement_t *st, int field) +{ + if (def) { + reloc_t *ref = new_reloc (st - pr.statements, field); + + ref->next = def->refs; + def->refs = ref; + + def->users--; + def->used = 1; + } +} + def_t * emit_statement (int sline, opcode_t *op, def_t *var_a, def_t *var_b, def_t *var_c) @@ -118,9 +133,9 @@ emit_statement (int sline, opcode_t *op, def_t *var_a, def_t *var_b, var_c ? var_c->name : "", statement->c); #endif - PR_AddStatementRef (var_a, statement, 0); - PR_AddStatementRef (var_b, statement, 1); - PR_AddStatementRef (var_c, statement, 2); + 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; @@ -131,7 +146,7 @@ void emit_branch (int line, opcode_t *op, expr_t *e, expr_t *l) { dstatement_t *st; - statref_t *ref; + reloc_t *ref; def_t *def = 0; int ofs; @@ -145,7 +160,7 @@ emit_branch (int line, opcode_t *op, expr_t *e, expr_t *l) else st->b = l->e.label.ofs - ofs; } else { - ref = PR_NewStatref (ofs, op != op_goto); + ref = new_reloc (ofs, op == op_goto ? rel_op_a_op : rel_op_b_op); ref->next = l->e.label.refs; l->e.label.refs = ref; } @@ -170,17 +185,17 @@ emit_function_call (expr_t *e, def_t *dest) parm.type = types[extract_type (earg)]; arg = emit_sub_expr (earg, &parm); if (earg->type != ex_expr && earg->type != ex_uexpr) { - op = PR_Opcode_Find ("=", arg, &parm, &def_void); + op = opcode_find ("=", arg, &parm, &def_void); emit_statement (e->line, op, arg, &parm, 0); } } - op = PR_Opcode_Find (va ("", count), &def_function, &def_void, + op = opcode_find (va ("", count), &def_function, &def_void, &def_void); emit_statement (e->line, op, func, 0, 0); def_ret.type = func->type->aux_type; if (dest) { - op = PR_Opcode_Find ("=", dest, &def_ret, &def_void); + op = opcode_find ("=", dest, &def_ret, &def_void); emit_statement (e->line, op, &def_ret, dest, 0); return dest; } else { @@ -223,7 +238,7 @@ emit_assign_expr (int oper, expr_t *e) } def_b = emit_sub_expr (e2, def_a); if (def_b != def_a) { - op = PR_Opcode_Find (operator, def_b, def_a, &def_void); + op = opcode_find (operator, def_b, def_a, &def_void); emit_statement (e->line, op, def_b, def_a, 0); } return def_a; @@ -234,11 +249,11 @@ emit_assign_expr (int oper, expr_t *e) if (e1->type == ex_expr && extract_type (e1->e.expr.e1) == ev_pointer) { def_a = emit_sub_expr (e1->e.expr.e1, 0); def_c = emit_sub_expr (e1->e.expr.e2, 0); - op = PR_Opcode_Find (operator, def_b, def_a, def_c); + op = opcode_find (operator, def_b, def_a, def_c); } else { def_a = emit_sub_expr (e1, 0); def_c = 0; - op = PR_Opcode_Find (operator, def_b, def_a, &def_void); + op = opcode_find (operator, def_b, def_a, &def_void); } emit_statement (e->line, op, def_b, def_a, def_c); return def_b; @@ -316,7 +331,7 @@ emit_sub_expr (expr_t *e, def_t *dest) dest = PR_GetTempDef (e->e.expr.type, pr_scope); dest->users += 2; } - op = PR_Opcode_Find (operator, def_a, def_b, dest); + op = opcode_find (operator, def_a, def_b, dest); d = emit_statement (e->line, op, def_a, def_b, dest); break; case ex_uexpr: @@ -391,7 +406,7 @@ emit_sub_expr (expr_t *e, def_t *dest) default: abort (); } - op = PR_Opcode_Find (operator, def_a, def_b, dest); + op = opcode_find (operator, def_a, def_b, dest); d = emit_statement (e->line, op, def_a, def_b, dest); break; case ex_def: @@ -447,7 +462,6 @@ emit_expr (expr_t *e) def_t *def; def_t *def_a; def_t *def_b; - statref_t *ref; ex_label_t *label; //printf ("%d ", e->line); @@ -459,24 +473,6 @@ emit_expr (expr_t *e) case ex_label: label = &e->e.label; label->ofs = pr.num_statements; - for (ref = label->refs; ref; ref = ref->next) { - switch (ref->field) { - case 0: - pr.statements[ref->ofs].a = label->ofs - ref->ofs; - break; - case 1: - pr.statements[ref->ofs].b = label->ofs - ref->ofs; - break; - case 2: - pr.statements[ref->ofs].c = label->ofs - ref->ofs; - break; - case 3: - G_INT (ref->ofs) = label->ofs; - break; - default: - abort (); - } - } break; case ex_block: for (e = e->e.block.head; e; e = e->next) diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index e9165a2a5..744a8f5e2 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -384,6 +384,8 @@ new_label_expr (void) l->type = ex_label; l->e.label.name = new_label_name (); + l->e.label.next = pr.labels; + pr.labels = &l->e.label; return l; } diff --git a/tools/qfcc/source/opcodes.c b/tools/qfcc/source/opcodes.c index 60d68d1f8..0f4a3dcaa 100644 --- a/tools/qfcc/source/opcodes.c +++ b/tools/qfcc/source/opcodes.c @@ -32,10 +32,10 @@ static const char rcsid[] = #include -#include "qfcc.h" #include "def.h" #include "opcodes.h" #include "options.h" +#include "qfcc.h" #include "type.h" hashtab_t *opcode_type_table_ab; @@ -54,30 +54,6 @@ opcode_t *op_goto; opcode_t *op_jump; opcode_t *op_jumpb; -statref_t * -PR_NewStatref (int ofs, int field) -{ - statref_t *ref = calloc (1, sizeof (statref_t)); - - ref->ofs = ofs; - ref->field = field; - return ref; -} - -void -PR_AddStatementRef (def_t *def, dstatement_t *st, int field) -{ - if (def) { - statref_t *ref = PR_NewStatref (st - pr.statements, field); - - ref->next = def->refs; - def->refs = ref; - - def->users--; - def->used = 1; - } -} - #define ROTL(x,n) (((x)<<(n))|(x)>>(32-n)) static unsigned long @@ -120,7 +96,7 @@ compare (void *_opa, void *_opb, void *_tab) } opcode_t * -PR_Opcode_Find (const char *name, def_t *var_a, def_t *var_b, def_t *var_c) +opcode_find (const char *name, def_t *var_a, def_t *var_b, def_t *var_c) { opcode_t op; hashtab_t **tab; @@ -142,7 +118,7 @@ PR_Opcode_Find (const char *name, def_t *var_a, def_t *var_b, def_t *var_c) } void -PR_Opcode_Init_Tables (void) +opcode_init (void) { opcode_t *op; diff --git a/tools/qfcc/source/qfcc.c b/tools/qfcc/source/qfcc.c index 4906a809e..aa021a6e3 100644 --- a/tools/qfcc/source/qfcc.c +++ b/tools/qfcc/source/qfcc.c @@ -73,6 +73,7 @@ static const char rcsid[] = #include "immediate.h" #include "opcodes.h" #include "options.h" +#include "reloc.h" #include "type.h" options_t options; @@ -311,28 +312,6 @@ PR_BeginCompilation (void) pr_error_count = 0; } -void -PR_RelocateRefs (def_t *def) -{ - statref_t *ref; - - for (ref = def->refs; ref; ref = ref->next) { - switch (ref->field) { - case 0: - pr.statements[ref->ofs].a = def->ofs; - break; - case 1: - pr.statements[ref->ofs].b = def->ofs; - break; - case 2: - pr.statements[ref->ofs].c = def->ofs; - break; - default: - abort (); - } - } -} - /* PR_FinishCompilation @@ -346,6 +325,7 @@ qboolean PR_FinishCompilation (void) function_t *f; def_t *def; expr_t e; + ex_label_t *l; class_finish_module (); // check to make sure all functions prototyped have code @@ -374,7 +354,7 @@ qboolean PR_FinishCompilation (void) for (def = pr.def_head; def; def = def->def_next) { if (def->scope || def->absolute) continue; - PR_RelocateRefs (def); + relocate_refs (def->refs, def->ofs); } for (f = pr.func_head; f; f = f->next) { @@ -389,11 +369,14 @@ qboolean PR_FinishCompilation (void) if (def->absolute) continue; def->ofs += pr.num_globals; - PR_RelocateRefs (def); + relocate_refs (def->refs, def->ofs); } } pr.num_globals += num_localdefs; + for (l = pr.labels; l; l = l->next) + relocate_refs (l->refs, l->ofs); + return !errors; } @@ -443,7 +426,7 @@ main (int argc, char **argv) printf ("progs.src: %s\n", progs_src); } - PR_Opcode_Init_Tables (); + opcode_init (); InitData (); init_types (); diff --git a/tools/qfcc/source/reloc.c b/tools/qfcc/source/reloc.c new file mode 100644 index 000000000..110c8a3dd --- /dev/null +++ b/tools/qfcc/source/reloc.c @@ -0,0 +1,113 @@ +/* + #FILENAME# + + #DESCRIPTION# + + Copyright (C) 2001 #AUTHOR# + + Author: #AUTHOR# + Date: #DATE# + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +static const char rcsid[] = + "$Id$"; + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif +#include + +#include "def.h" +#include "expr.h" +#include "qfcc.h" +#include "reloc.h" + +void +relocate_refs (reloc_t *refs, int ofs) +{ + int o; + + while (refs) { + switch (refs->type) { + case rel_none: + break; + case rel_op_a_def: + if (ofs > 65535) + error (0, "def offset too large"); + else + pr.statements[refs->ofs].a = ofs; + break; + case rel_op_b_def: + if (ofs > 65535) + error (0, "def offset too large"); + else + pr.statements[refs->ofs].b = ofs; + break; + case rel_op_c_def: + if (ofs > 65535) + error (0, "def offset too large"); + else + pr.statements[refs->ofs].c = ofs; + break; + case rel_op_a_op: + o = ofs - refs->ofs; + if (o < -32768 || o > 32767) + error (0, "relative offset too large"); + else + pr.statements[refs->ofs].a = o; + break; + case rel_op_b_op: + o = ofs - refs->ofs; + if (o < -32768 || o > 32767) + error (0, "relative offset too large"); + else + pr.statements[refs->ofs].b = o; + break; + case rel_op_c_op: + o = ofs - refs->ofs; + if (o < -32768 || o > 32767) + error (0, "relative offset too large"); + else + pr.statements[refs->ofs].c = o; + break; + case rel_def_op: + if (ofs >= pr.num_statements) + error (0, "invalid statement offset"); + else + G_INT (refs->ofs) = ofs; + break; + case rel_def_def: + G_INT (refs->ofs) = ofs; + break; + } + refs = refs->next; + } +} + +reloc_t * +new_reloc (int ofs, reloc_type type) +{ + reloc_t *ref = calloc (1, sizeof (reloc_t)); + + ref->ofs = ofs; + ref->type = type; + return ref; +} diff --git a/tools/qfcc/source/switch.c b/tools/qfcc/source/switch.c index 378a13907..04bf26347 100644 --- a/tools/qfcc/source/switch.c +++ b/tools/qfcc/source/switch.c @@ -44,13 +44,15 @@ static const char rcsid[] = #include #include -#include "qfcc.h" #include "def.h" #include "expr.h" #include "opcodes.h" #include "options.h" -#include "type.h" +#include "qfcc.h" +#include "reloc.h" #include "switch.h" +#include "type.h" + #include "qc-parse.h" typedef struct case_node_s { @@ -320,9 +322,9 @@ build_switch (expr_t *sw, case_node_t *tree, int op, expr_t *sw_val, build_switch (sw, tree->right, op, sw_val, temp, default_label); } for (i = 0; i <= high - low; i++) { - statref_t *ref; + reloc_t *ref; - ref = PR_NewStatref (G_INT (def->ofs) + i, 3); + ref = new_reloc (G_INT (def->ofs) + i, rel_def_op); ref->next = tree->labels[i]->e.label.refs; tree->labels[i]->e.label.refs = ref; }