diff --git a/tools/qfcc/include/Makefile.am b/tools/qfcc/include/Makefile.am index 59b52d9fd..612e19c7b 100644 --- a/tools/qfcc/include/Makefile.am +++ b/tools/qfcc/include/Makefile.am @@ -1,5 +1,5 @@ AUTOMAKE_OPTIONS= foreign EXTRA_DIST= class.h cmdlib.h cpp.h debug.h def.h expr.h function.h idstuff.h \ - immediate.h method.h obj_file.h opcodes.h options.h qfcc.h \ - reloc.h struct.h switch.h type.h + immediate.h linker.h method.h obj_file.h opcodes.h options.h \ + qfcc.h reloc.h struct.h switch.h type.h diff --git a/tools/qfcc/include/class.h b/tools/qfcc/include/class.h index c1bea2f6d..c40df3e42 100644 --- a/tools/qfcc/include/class.h +++ b/tools/qfcc/include/class.h @@ -55,6 +55,7 @@ struct method_s; struct protocol_s; struct type_s; +struct def_s *class_def (class_t *class, int external); void class_init (void); class_t *get_class (const char *name, int create); void class_add_methods (class_t *class, struct methodlist_s *methods); @@ -69,7 +70,7 @@ struct struct_field_s *class_find_ivar (class_t *class, int protected, struct expr_s *class_ivar_expr (class_t *class, const char *name); struct method_s *class_find_method (class_t *class, struct method_s *method); struct method_s *class_message_response (class_t *class, struct expr_s *sel); -struct def_s *class_def (class_t *class); +struct def_s *class_pointer_def (class_t *class); class_t *get_category (const char *class_name, const char *category_name, int create); void class_finish_module (void); diff --git a/tools/qfcc/include/linker.h b/tools/qfcc/include/linker.h new file mode 100644 index 000000000..197fb2e37 --- /dev/null +++ b/tools/qfcc/include/linker.h @@ -0,0 +1,39 @@ +/* + link.h + + qc object file linking + + Copyright (C) 2001 Bill Currie + + Author: Bill Currie + Date: 2002/7/3 + + 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 __linker_h +#define __linker_h + +void linker_begin (void); +void linker_add_object_file (const char *filename); +void linker_finish (void); + +#endif//__linker_h diff --git a/tools/qfcc/include/obj_file.h b/tools/qfcc/include/obj_file.h index 7d741a47b..9692f5a88 100644 --- a/tools/qfcc/include/obj_file.h +++ b/tools/qfcc/include/obj_file.h @@ -33,6 +33,7 @@ #define __obj_file_h #include "QF/pr_comp.h" +#include "QF/pr_debug.h" #define QFO "QFO" #define QFO_VERSION 0x00001001 // MMmmmRRR 0.001.001 (hex) @@ -118,6 +119,16 @@ typedef struct qfo_s { int num_lines; } qfo_t; +#define QFO_var(q, t, o) ((q)->data[o].t##_var) +#define QFO_FLOAT(q, o) QFO_var (q, float, o) +#define QFO_INT(q, o) QFO_var (q, integer, o) +#define QFO_VECTOR(q, o) QFO_var (q, vector, o) +#define QFO_STRING(q, o) (pr.strings + QFO_var (q, string, o)) +#define QFO_FUNCTION(q, o) QFO_var (q, func, o) +#define QFO_POINTER(q, t,o) ((t *)((q)->data + o)) +#define QFO_STRUCT(q, t,o) (*QFO_POINTER (q, t, o)) + int write_obj_file (const char *filename); +qfo_t *read_obj_file (const char *filename); #endif//__obj_file_h diff --git a/tools/qfcc/include/type.h b/tools/qfcc/include/type.h index 65438683f..dc1b42cdd 100644 --- a/tools/qfcc/include/type.h +++ b/tools/qfcc/include/type.h @@ -88,6 +88,7 @@ int type_assignable (type_t *dst, type_t *src); int type_size (type_t *type); void init_types (void); +void chain_initial_types (void); void clear_typedefs (void); diff --git a/tools/qfcc/source/Makefile.am b/tools/qfcc/source/Makefile.am index 49342afd3..98adb16ed 100644 --- a/tools/qfcc/source/Makefile.am +++ b/tools/qfcc/source/Makefile.am @@ -39,8 +39,8 @@ bin_PROGRAMS= qfcc qfcc_SOURCES= \ class.c cmdlib.c cpp.c debug.c def.c emit.c expr.c function.c idstuff.c \ - immediate.c method.c obj_file.c opcodes.c options.c qc-lex.l qc-parse.y \ - qfcc.c reloc.c struct.c switch.c type.c + immediate.c linker.c method.c obj_file.c opcodes.c options.c qc-lex.l \ + qc-parse.y qfcc.c reloc.c struct.c switch.c type.c qfcc_LDADD= $(QFCC_LIBS) qfcc_DEPENDENCIES= $(QFCC_DEPS) diff --git a/tools/qfcc/source/class.c b/tools/qfcc/source/class.c index 0acfe0968..caad2f0b8 100644 --- a/tools/qfcc/source/class.c +++ b/tools/qfcc/source/class.c @@ -84,6 +84,22 @@ class_init (void) class_Class.super_class = get_class ("Object", 1); } +def_t * +class_def (class_t *class, int external) +{ + const char *name; + storage_class_t storage = external ? st_extern : st_global; + + if (!class->class_name) + return 0; + if (class->category_name) + name = va ("_OBJ_CATEGORY_%s_%s", + class->class_name, class->category_name); + else + name = va ("_OBJ_CLASS_%s", class->class_name); + return get_def (type_category, name, pr.scope, storage); +} + class_t * get_class (const char *name, int create) { @@ -152,16 +168,10 @@ void class_begin (class_t *class) { current_class = class; - if (class->def) - return; + class->def = class_def (class, 0); if (class->class_name && class->category_name) { pr_category_t *category; - class->def = get_def (type_category, - va ("_OBJ_CATEGORY_%s_%s", - class->class_name, - class->category_name), - pr.scope, st_static); class->def->initialized = class->def->constant = 1; category = &G_STRUCT (pr_category_t, class->def->ofs); category->category_name = ReuseString (class->category_name); @@ -190,9 +200,6 @@ class_begin (class_t *class) meta->protocols = emit_protocol_list (class->protocols, class->class_name); - class->def = get_def (type_Class.aux_type, - va ("_OBJ_CLASS_%s", class->class_name), - pr.scope, st_static); class->def->initialized = class->def->constant = 1; cls = &G_STRUCT (pr_class_t, class->def->ofs); cls->class_pointer = meta_def->ofs; @@ -394,7 +401,7 @@ get_category (const char *class_name, const char *category_name, int create) } def_t * -class_def (class_t *class) +class_pointer_def (class_t *class) { def_t *def; @@ -403,12 +410,12 @@ class_def (class_t *class) pr.scope, st_static); if (def->initialized) return def; - if (class->def) { //FIXME need externals? - G_INT (def->ofs) = class->def->ofs; - } else { - warning (0, "%s not implemented", class->class_name); - } def->initialized = def->constant = 1; + if (!class->def) + class->def = class_def (class, 1); + if (!class->def->external) + G_INT (def->ofs) = class->def->ofs; + //FIXME need reloc return def; } diff --git a/tools/qfcc/source/def.c b/tools/qfcc/source/def.c index a280eb689..78f3edf28 100644 --- a/tools/qfcc/source/def.c +++ b/tools/qfcc/source/def.c @@ -247,7 +247,7 @@ get_def (type_t *type, const char *name, scope_t *scope, } } set_storage_bits (def, storage); - if (storage == st_extern || storage == st_static) + if (storage == st_extern) def_initialized (def); return def; diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index ef1a03210..d08ad17aa 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -138,7 +138,7 @@ convert_name (expr_t *e) class = get_class (name, 0); if (class) { e->type = ex_def; - e->e.def = class_def (class); + e->e.def = class_pointer_def (class); return; } d = get_def (NULL, name, current_scope, st_none); @@ -1648,8 +1648,8 @@ function_expr (expr_t *e1, expr_t *e2) e->type = expr_types[t->type]; } if (!type_assignable (ftype->parm_types[i], t)) { - print_type (ftype->parm_types[i]); puts(""); - print_type (t); puts(""); + print_type (ftype->parm_types[i]); puts (""); + print_type (t); puts (""); err = error (e, "type mismatch for parameter %d of %s", i + 1, e1->e.def->name); } diff --git a/tools/qfcc/source/immediate.c b/tools/qfcc/source/immediate.c index 3e1888c56..e466f9214 100644 --- a/tools/qfcc/source/immediate.c +++ b/tools/qfcc/source/immediate.c @@ -63,44 +63,36 @@ static const char * float_imm_get_key (void *_def, void *unused) { def_t *def = (def_t *) _def; - static char rep[20]; return va ("\001float:%08X\001", G_INT (def->ofs)); - return rep; } static const char * vector_imm_get_key (void *_def, void *unused) { def_t *def = (def_t *) _def; - static char rep[60]; return va ("\001vector:%08X\001%08X\001%08X\001", G_INT (def->ofs), G_INT (def->ofs + 1), G_INT (def->ofs + 2)); - return rep; } static const char * quaternion_imm_get_key (void *_def, void *unused) { def_t *def = (def_t *) _def; - static char rep[60]; return va ("\001quaternion:%08X\001%08X\001%08X\001%08X\001", G_INT (def->ofs), G_INT (def->ofs + 1), G_INT (def->ofs + 2), G_INT (def->ofs + 3)); - return rep; } static const char * int_imm_get_key (void *_def, void *_str) { def_t *def = (def_t *) _def; - static char rep[60]; char *str = (char *) _str; return va ("\001%s:%08X\001", str, G_INT (def->ofs)); - return rep; } static const char * diff --git a/tools/qfcc/source/linker.c b/tools/qfcc/source/linker.c new file mode 100644 index 000000000..b5fff788e --- /dev/null +++ b/tools/qfcc/source/linker.c @@ -0,0 +1,165 @@ +/* + link.c + + qc object file linking + + Copyright (C) 2001 Bill Currie + + Author: Bill Currie + Date: 2002/7/3 + + 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 "QF/hash.h" + +#include "def.h" +#include "expr.h" +#include "immediate.h" +#include "obj_file.h" +#include "qfcc.h" + +static hashtab_t *extern_defs; +static hashtab_t *defined_defs; + +static const char * +defs_get_key (void *_def, void *unused) +{ + qfo_def_t *def = (qfo_def_t *) _def; + + return pr.strings + def->name; +} + +void +add_code (qfo_t *qfo) +{ + int num_statements = pr.num_statements; + + pr.num_statements += qfo->code_size; + if (pr.num_statements >= pr.statements_size) { + pr.statements_size = (pr.num_statements + 16383) & ~16384; + pr.statements = realloc (pr.statements, + pr.statements_size * sizeof (dstatement_t)); + } + memcpy (pr.statements + num_statements, qfo->code, + qfo->code_size * sizeof (dstatement_t)); +} + +void +add_defs (qfo_t *qfo) +{ + qfo_def_t *def; + qfo_def_t *d; + + for (def = qfo->defs; def - qfo->defs < qfo->num_defs; def++) { + def->full_type = ReuseString (qfo->strings + def->full_type); + def->name = ReuseString (qfo->strings + def->name); + def->file = ReuseString (qfo->strings + def->file); + if (def->flags & QFOD_EXTERNAL) { + Hash_Add (extern_defs, def); + } else { + if (def->flags & QFOD_GLOBAL) { + if ((d = Hash_Find (defined_defs, pr.strings + def->name))) { + error (0, "%s redefined", pr.strings + def->name); + } + } + if (def->basic_type == ev_string && def->ofs + && QFO_var (qfo, string, def->ofs)) { + string_t s; + s = ReuseString (QFO_STRING (qfo, def->ofs)); + QFO_var (qfo, string, def->ofs) = s; + } + if (def->ofs) + def->ofs += pr.near_data->size; + if (def->flags & QFOD_GLOBAL) { + while ((d = Hash_Find (extern_defs, pr.strings + def->name))) { + Hash_Del (extern_defs, pr.strings + d->name); + if (d->full_type != def->full_type) { + error (0, "type mismatch %s %s", + pr.strings + def->full_type, + pr.strings + d->full_type); + } + } + Hash_Add (defined_defs, def); + } + } + } +} + +void +add_functions (qfo_t *qfo) +{ + qfo_function_t *func; + + for (func = qfo->functions; func - qfo->functions < qfo->num_functions; + func++) { + func->name = ReuseString (qfo->strings + func->name); + func->file = ReuseString (qfo->strings + func->file); + if (func->code) + func->code += pr.num_statements; + } +} + +void +linker_begin (void) +{ + extern_defs = Hash_NewTable (16381, defs_get_key, 0, 0); + defined_defs = Hash_NewTable (16381, defs_get_key, 0, 0); + if (pr.statements) + free (pr.statements); + memset (&pr, 0, sizeof (pr)); + pr.num_statements = 1; + pr.statements_size = 16384; + pr.statements = calloc (pr.statements_size, sizeof (dstatement_t)); + pr.statement_linenums = calloc (pr.statements_size, sizeof (int)); + CopyString (""); + pr.num_functions = 1; + pr.near_data = new_defspace (); + pr.near_data->data = calloc (65536, sizeof (pr_type_t)); +} + +void +linker_add_object_file (const char *filename) +{ + qfo_t *qfo; + + qfo = read_obj_file (filename); + if (!qfo) + return; + puts(filename); + add_defs (qfo); + add_functions (qfo); + add_code (qfo); + //add_data (qfo); + //add_far_data (qfo); + //add_strings (qfo); +} + +void +linker_finish (void) +{ +} diff --git a/tools/qfcc/source/obj_file.c b/tools/qfcc/source/obj_file.c index 94f00a35c..0ea343000 100644 --- a/tools/qfcc/source/obj_file.c +++ b/tools/qfcc/source/obj_file.c @@ -287,6 +287,10 @@ read_obj_file (const char *filename) pr_lineno_t *line; file = Qopen (filename, "rbz"); + if (!file) { + perror (filename); + return 0; + } Qread (file, &hdr, sizeof (hdr)); @@ -325,6 +329,7 @@ read_obj_file (const char *filename) qfo->relocs = malloc (qfo->num_relocs * sizeof (qfo_reloc_t)); qfo->defs = malloc (qfo->num_defs * sizeof (qfo_def_t)); qfo->functions = malloc (qfo->num_functions * sizeof (qfo_function_t)); + qfo->lines = malloc (qfo->num_lines * sizeof (pr_lineno_t)); Qread (file, qfo->code, qfo->code_size * sizeof (dstatement_t)); Qread (file, qfo->data, qfo->data_size * sizeof (pr_type_t)); @@ -388,5 +393,5 @@ read_obj_file (const char *filename) line->line = LittleLong (line->line); } - return 0; + return qfo; } diff --git a/tools/qfcc/source/qfcc.c b/tools/qfcc/source/qfcc.c index 517768557..f06052053 100644 --- a/tools/qfcc/source/qfcc.c +++ b/tools/qfcc/source/qfcc.c @@ -71,6 +71,7 @@ static const char rcsid[] = #include "function.h" #include "idstuff.h" #include "immediate.h" +#include "linker.h" #include "method.h" #include "obj_file.h" #include "opcodes.h" @@ -131,6 +132,7 @@ InitData (void) free (pr.statements); memset (&pr, 0, sizeof (pr)); } + chain_initial_types (); pr_source_line = 1; pr_error_count = 0; pr.num_statements = 1; @@ -538,8 +540,11 @@ separate_compile (void) } } if (!err && !options.compile) { + linker_begin (); for (file = source_files; *file; file++) { + linker_add_object_file (*file); } + linker_finish (); } return err; } diff --git a/tools/qfcc/source/type.c b/tools/qfcc/source/type.c index ef97100ba..e6125de98 100644 --- a/tools/qfcc/source/type.c +++ b/tools/qfcc/source/type.c @@ -276,6 +276,9 @@ print_type (type_t *type) class->category_name ? va (" (%s)", class->category_name) : ""); break; + case ev_struct: + printf (" %s %s", pr_type_name[type->type], type->name); + break; default: printf(" %s", pr_type_name[type->type]); break; @@ -340,7 +343,11 @@ _encode_type (dstring_t *encoding, type_t *type, int level) case ev_object: case ev_class: dstring_appendstr (encoding, "{"); - dstring_appendstr (encoding, type->name); + if (type->name) { + dstring_appendstr (encoding, type->name); + } else if (type->type == ev_object || type->type == ev_class) { + dstring_appendstr (encoding, type->class->class_name); + } if (level < 2) { dstring_appendstr (encoding, "="); for (field = type->struct_head; field; field = field->next) @@ -441,32 +448,14 @@ init_types (void) { type_t *type; - chain_type (&type_void); - chain_type (&type_string); - chain_type (&type_float); - chain_type (&type_vector); - chain_type (&type_entity); - chain_type (&type_field); - chain_type (&type_function); - chain_type (&type_pointer); - chain_type (&type_floatfield); - chain_type (&type_quaternion); - chain_type (&type_integer); - chain_type (&type_uinteger); - chain_type (&type_short); - chain_type (&type_struct); - chain_type (&type_IMP); - type = type_SEL.aux_type = new_struct (0); new_struct_field (type, &type_string, "sel_id", vis_public); new_struct_field (type, &type_string, "sel_types", vis_public); - chain_type (&type_SEL); type = type_Method.aux_type = new_struct (0); new_struct_field (type, type_SEL.aux_type, "method_name", vis_public); new_struct_field (type, &type_string, "method_types", vis_public); new_struct_field (type, &type_IMP, "method_imp", vis_public); - chain_type (&type_Method); type = type_Class.aux_type = new_struct (0); type->type = ev_class; @@ -485,7 +474,6 @@ init_types (void) new_struct_field (type, &type_pointer, "sibling_class", vis_public); new_struct_field (type, &type_pointer, "protocols", vis_public); new_struct_field (type, &type_pointer, "gc_object_type", vis_public); - chain_type (&type_Class); type = type_Protocol.aux_type = new_struct (0); type->type = ev_class; @@ -496,14 +484,12 @@ init_types (void) new_struct_field (type, &type_pointer, "protocol_list", vis_public); new_struct_field (type, &type_pointer, "instance_methods", vis_public); new_struct_field (type, &type_pointer, "class_methods", vis_public); - chain_type (&type_Protocol); type = type_id.aux_type = new_struct ("id"); type->type = ev_object; type->class = &class_id; class_id.ivars = type_id.aux_type; new_struct_field (type, &type_Class, "class_pointer", vis_public); - chain_type (&type_id); type = type_category = new_struct (0); new_struct_field (type, &type_string, "category_name", vis_public); @@ -511,22 +497,48 @@ init_types (void) new_struct_field (type, &type_pointer, "instance_methods", vis_public); new_struct_field (type, &type_pointer, "class_methods", vis_public); new_struct_field (type, &type_pointer, "protocols", vis_public); - chain_type (type_category); type = type_ivar = new_struct (0); new_struct_field (type, &type_string, "ivar_name", vis_public); new_struct_field (type, &type_string, "ivar_type", vis_public); new_struct_field (type, &type_integer, "ivar_offset", vis_public); - chain_type (type_ivar); type = type_module = new_struct (0); new_struct_field (type, &type_integer, "version", vis_public); new_struct_field (type, &type_integer, "size", vis_public); new_struct_field (type, &type_string, "name", vis_public); new_struct_field (type, &type_pointer, "symtab", vis_public); - chain_type (type_module); type_obj_exec_class.parm_types[0] = pointer_type (type_module); +} + +void +chain_initial_types (void) +{ + chain_type (&type_void); + chain_type (&type_string); + chain_type (&type_float); + chain_type (&type_vector); + chain_type (&type_entity); + chain_type (&type_field); + chain_type (&type_function); + chain_type (&type_pointer); + chain_type (&type_floatfield); + chain_type (&type_quaternion); + chain_type (&type_integer); + chain_type (&type_uinteger); + chain_type (&type_short); + chain_type (&type_struct); + chain_type (&type_IMP); + + chain_type (&type_SEL); + chain_type (&type_Method); + chain_type (&type_Class); + chain_type (&type_Protocol); + chain_type (&type_id); + chain_type (type_category); + chain_type (type_ivar); + chain_type (type_module); chain_type (&type_obj_exec_class); }