From 181596f5bfbd9860629c19221413fba71a20e3ca Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 12 Feb 2011 22:34:38 +0900 Subject: [PATCH] Make relocation records store the space of the relocation. The space is meaningless for op_* relocations as they are always in the code space, but def_* relocations need to know which space holds the location to be adjusted. --- tools/qfcc/include/emit.h | 41 ++++++++++------- tools/qfcc/include/reloc.h | 53 +++++++++++++++------- tools/qfcc/source/class.c | 6 +-- tools/qfcc/source/emit.c | 2 +- tools/qfcc/source/function.c | 4 +- tools/qfcc/source/immediate.c | 17 ++++--- tools/qfcc/source/method.c | 8 +++- tools/qfcc/source/reloc.c | 83 +++++++++++++++++++++++++---------- tools/qfcc/source/switch.c | 5 ++- 9 files changed, 146 insertions(+), 73 deletions(-) diff --git a/tools/qfcc/include/emit.h b/tools/qfcc/include/emit.h index d7ae2f841..eebd5c1dc 100644 --- a/tools/qfcc/include/emit.h +++ b/tools/qfcc/include/emit.h @@ -36,26 +36,35 @@ struct sblock_s; void emit_statements (struct sblock_s *first_sblock); -#define EMIT_STRING(s,dest,str) \ - do { \ - (dest) = ReuseString (str); \ - reloc_def_string (POINTER_OFS (s, &(dest)));\ +#define EMIT_STRING(s,dest,str) \ + do { \ + def_t loc; \ + loc.space = s; \ + loc.offset = POINTER_OFS (s, &(dest)); \ + (dest) = ReuseString (str); \ + reloc_def_string (&loc);\ } while (0) -#define EMIT_DEF(s,dest,def) \ - do { \ - def_t *d = (def); \ - (dest) = d ? d->offset : 0; \ - if (d) \ - reloc_def_def (d, POINTER_OFS (s, &(dest)));\ +#define EMIT_DEF(s,dest,def) \ + do { \ + def_t *d = (def); \ + def_t loc; \ + loc.space = s; \ + loc.offset = POINTER_OFS (s, &(dest)); \ + (dest) = d ? d->offset : 0; \ + if (d) \ + reloc_def_def (d, &loc); \ } while (0) -#define EMIT_DEF_OFS(s,dest,def) \ - do { \ - def_t *d = (def); \ - (dest) = d ? d->offset : 0; \ - if (d) \ - reloc_def_def_ofs (d, POINTER_OFS (s, &(dest)));\ +#define EMIT_DEF_OFS(s,dest,def) \ + do { \ + def_t *d = (def); \ + def_t loc; \ + loc.space = s; \ + loc.offset = POINTER_OFS (s, &(dest)); \ + (dest) = d ? d->offset : 0; \ + if (d) \ + reloc_def_def_ofs (d, &loc); \ } while (0) #endif//__emit_h diff --git a/tools/qfcc/include/reloc.h b/tools/qfcc/include/reloc.h index e26aa1855..2d8b59026 100644 --- a/tools/qfcc/include/reloc.h +++ b/tools/qfcc/include/reloc.h @@ -70,7 +70,11 @@ typedef enum { typedef struct reloc_s { struct reloc_s *next; ///< next reloc in reloc chain struct ex_label_s *label; ///< instruction label for *_op relocs - int offset; ///< the addressof the location in need of + struct defspace_s *space; ///< the space containing the location in + ///< need of adjustment for def_* relocations + ///< (op_* relocations always use the code + ///< space) + int offset; ///< the address of the location in need of ///< adjustment reloc_type type; ///< type type of relocation to perform int line; ///< current source line when creating reloc @@ -95,10 +99,11 @@ void relocate_refs (reloc_t *refs, int offset); The current source file and line will be preserved in the relocation record. - \param offset The address of the instruction that will be adjusted. + \param space The defspace containting the location to be adjusted. + \param offset The address of the location to be adjusted. \param type The type of relocation to be performed. */ -reloc_t *new_reloc (int offset, reloc_type type); +reloc_t *new_reloc (struct defspace_s *space, int offset, reloc_type type); /** Create a relocation record for an instruction referencing a def. @@ -139,9 +144,11 @@ void reloc_op_def_ofs (struct def_s *def, int offset, int field); value stored in the data location. \param def The def being referenced. - \param offset The address of the data location that will be adjusted. + \param location Def describing the location of the reference to be + adjusted. As the def's space and offset will be copied + into the relocation record, a dummy def may be used. */ -void reloc_def_def (struct def_s *def, int offset); +void reloc_def_def (struct def_s *def, struct def_s *location); /** Create a relocation record for a data location referencing a def. @@ -152,9 +159,11 @@ void reloc_def_def (struct def_s *def, int offset); the value stored in the data location. \param def The def being referenced. - \param offset The address of the data location that will be adjusted. + \param location Def describing the location of the reference to be + adjusted. As the def's space and offset will be copied + into the relocation record, a dummy def may be used. */ -void reloc_def_def_ofs (struct def_s *def, int offset); +void reloc_def_def_ofs (struct def_s *def, struct def_s *location); /** Create a relocation record for a data location referencing a function. @@ -165,9 +174,11 @@ void reloc_def_def_ofs (struct def_s *def, int offset); value stored in the data location. \param func The function being referenced. - \param offset The address of the data location that will be adjusted. + \param location Def describing the location of the reference to be + adjusted. As the def's space and offset will be copied + into the relocation record, a dummy def may be used. */ -void reloc_def_func (struct function_s *func, int offset); +void reloc_def_func (struct function_s *func, struct def_s *location); /** Create a relocation record for a data location referencing a string. @@ -177,9 +188,11 @@ void reloc_def_func (struct function_s *func, int offset); When the relocation is performed, the string index will replace the value stored in the data location. - \param offset The address of the data location that will be adjusted. + \param location Def describing the location of the reference to be + adjusted. As the def's space and offset will be copied + into the relocation record, a dummy def may be used. */ -void reloc_def_string (int offset); +void reloc_def_string (struct def_s *location); /** Create a relocation record for a data location referencing a field. @@ -190,9 +203,11 @@ void reloc_def_string (int offset); value stored in the data location. \param def The def representing the field being referenced. - \param offset The address of the data location that will be adjusted. + \param location Def describing the location of the reference to be + adjusted. As the def's space and offset will be copied + into the relocation record, a dummy def may be used. */ -void reloc_def_field (struct def_s *def, int offset); +void reloc_def_field (struct def_s *def, struct def_s *location); /** Create a relocation record for a data location referencing a field. @@ -203,9 +218,11 @@ void reloc_def_field (struct def_s *def, int offset); the value stored in the data location. \param def The def representing the field being referenced. - \param offset The address of the data location that will be adjusted. + \param location Def describing the location of the reference to be + adjusted. As the def's space and offset will be copied + into the relocation record, a dummy def may be used. */ -void reloc_def_field_ofs (struct def_s *def, int offset); +void reloc_def_field_ofs (struct def_s *def, struct def_s *location); /** Create a relocation record for a data location referencing an instruction. @@ -217,9 +234,11 @@ void reloc_def_field_ofs (struct def_s *def, int offset); value stored in the data location. \param label The label representing the instruction being referenced. - \param offset The address of the data location that will be adjusted. + \param location Def describing the location of the reference to be + adjusted. As the def's space and offset will be copied + into the relocation record, a dummy def may be used. */ -void reloc_def_op (struct ex_label_s *label, int offset); +void reloc_def_op (struct ex_label_s *label, struct def_s *location); ///@} diff --git a/tools/qfcc/source/class.c b/tools/qfcc/source/class.c index b2152f432..ce1722ddd 100644 --- a/tools/qfcc/source/class.c +++ b/tools/qfcc/source/class.c @@ -589,7 +589,7 @@ emit_class_ref (const char *class_name) name_def = name_sym->s.def; if (!name_def->external) D_INT (ref_def) = name_def->offset; - reloc_def_def (name_def, ref_def->offset); + reloc_def_def (name_def, ref_def); } static void @@ -636,7 +636,7 @@ emit_category_ref (const char *class_name, const char *category_name) name_def = name_sym->s.def; if (!name_def->external) D_INT (ref_def) = name_def->offset; - reloc_def_def (name_def, ref_def->offset); + reloc_def_def (name_def, ref_def); } static void @@ -1030,7 +1030,7 @@ class_pointer_symbol (class_t *class) class->def = class_symbol (&class_type, 1)->s.def; if (!class->def->external) D_INT (def) = class->def->offset; - reloc_def_def (class->def, def->offset); + reloc_def_def (class->def, def); return sym; } diff --git a/tools/qfcc/source/emit.c b/tools/qfcc/source/emit.c index c198ec7d6..43438001a 100644 --- a/tools/qfcc/source/emit.c +++ b/tools/qfcc/source/emit.c @@ -152,7 +152,7 @@ add_statement_op_ref (operand_t *op, dstatement_t *st, int field) { if (op && op->op_type == op_label) { int st_ofs = st - pr.code->code; - reloc_t *reloc = new_reloc (st_ofs, rel_op_a_op + field); + reloc_t *reloc = new_reloc (0, st_ofs, rel_op_a_op + field); reloc->next = op->o.label->dest->relocs; op->o.label->dest->relocs = reloc; diff --git a/tools/qfcc/source/function.c b/tools/qfcc/source/function.c index aa3e2bf62..4f752c501 100644 --- a/tools/qfcc/source/function.c +++ b/tools/qfcc/source/function.c @@ -542,7 +542,7 @@ begin_function (symbol_t *sym, const char *nicename, symtab_t *parent) sym->s.func->def->constant = 1; sym->s.func->def->nosave = 1; add_function (sym->s.func); - reloc_def_func (sym->s.func, sym->s.func->def->offset); + reloc_def_func (sym->s.func, sym->s.func->def); } sym->s.func->code = pr.code->size; @@ -603,7 +603,7 @@ build_builtin_function (symbol_t *sym, expr_t *bi_val) else bi = expr_float (bi_val); sym->s.func->builtin = bi; - reloc_def_func (sym->s.func, sym->s.func->def->offset); + reloc_def_func (sym->s.func, sym->s.func->def); build_function (sym->s.func); finish_function (sym->s.func); diff --git a/tools/qfcc/source/immediate.c b/tools/qfcc/source/immediate.c index dd2f31b88..904699ad8 100644 --- a/tools/qfcc/source/immediate.c +++ b/tools/qfcc/source/immediate.c @@ -162,7 +162,6 @@ ReuseConstant (expr_t *expr, def_t *def) hashtab_t *tab = 0; type_t *type; expr_t e = *expr; - reloc_t *reloc = 0; immediate_t *imm, search; if (!string_imm_defs) { @@ -266,15 +265,19 @@ ReuseConstant (expr_t *expr, def_t *def) // copy the immediate to the global area switch (e.e.value.type) { case ev_string: - reloc = new_reloc (cn->offset, rel_def_string); + reloc_def_string (cn); break; case ev_func: - if (e.e.value.v.func_val) - reloc = new_reloc (cn->offset, rel_def_func); + if (e.e.value.v.func_val) { + reloc_t *reloc; + reloc = new_reloc (cn->space, cn->offset, rel_def_func); + reloc->next = pr.relocs; + pr.relocs = reloc; + } break; case ev_field: if (e.e.value.v.pointer.def) - reloc_def_field_ofs (e.e.value.v.pointer.def, cn->offset); + reloc_def_field_ofs (e.e.value.v.pointer.def, cn); break; case ev_pointer: if (e.e.value.v.pointer.def) { @@ -285,10 +288,6 @@ ReuseConstant (expr_t *expr, def_t *def) default: break; } - if (reloc) { - reloc->next = pr.relocs; - pr.relocs = reloc; - } memcpy (D_POINTER (void, cn), &e.e, 4 * type_size (type)); diff --git a/tools/qfcc/source/method.c b/tools/qfcc/source/method.c index 1f5969798..cfdfff43c 100644 --- a/tools/qfcc/source/method.c +++ b/tools/qfcc/source/method.c @@ -451,8 +451,12 @@ emit_methods_list_item (def_t *def, void *data, int index) EMIT_STRING (def->space, meth->method_name, m->name); EMIT_STRING (def->space, meth->method_types, m->types); meth->method_imp = D_FUNCTION (m->def); - if (m->func) - reloc_def_func (m->func, POINTER_OFS (def->space, &meth->method_imp)); + if (m->func) { + def_t loc; + loc.space = def->space; + loc.offset = POINTER_OFS (def->space, &meth->method_imp); + reloc_def_func (m->func, &loc); + } } def_t * diff --git a/tools/qfcc/source/reloc.c b/tools/qfcc/source/reloc.c index 4967dc40f..19e235ef5 100644 --- a/tools/qfcc/source/reloc.c +++ b/tools/qfcc/source/reloc.c @@ -54,7 +54,27 @@ static __attribute__ ((used)) const char rcsid[] = static reloc_t *free_refs; -#define G_INT(o) pr.near_data->data[o].integer_var +static const char *reloc_name[] = { + "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", + "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", + "rel_def_field_ofs", +}; + +#define RELOC(r) (r)->space->data[(r)->offset].integer_var void relocate_refs (reloc_t *reloc, int offset) @@ -62,6 +82,10 @@ relocate_refs (reloc_t *reloc, int offset) int o; while (reloc) { + debug (0, "reloc %s:%x %s %x", + reloc->space ? (reloc->space == pr.near_data ? "near" : "far") + : "code", + reloc->offset, reloc_name[reloc->type], offset); switch (reloc->type) { case rel_none: break; @@ -109,11 +133,11 @@ relocate_refs (reloc_t *reloc, int offset) error (0, "invalid statement offset: %d >= %d, %d", offset, pr.code->size, reloc->offset); } else - G_INT (reloc->offset) = offset; + RELOC (reloc) = offset; break; case rel_def_def: case rel_def_func: - G_INT (reloc->offset) = offset; + RELOC (reloc) = offset; break; case rel_def_string: break; @@ -141,10 +165,10 @@ relocate_refs (reloc_t *reloc, int offset) pr.code->code[reloc->offset].c = o; break; case rel_def_def_ofs: - G_INT (reloc->offset) += offset; + RELOC (reloc) += offset; break; case rel_def_field_ofs: - G_INT (reloc->offset) += G_INT (offset); + RELOC (reloc) += pr.data->data[offset].integer_var; break; } reloc = reloc->next; @@ -152,11 +176,12 @@ relocate_refs (reloc_t *reloc, int offset) } reloc_t * -new_reloc (int offset, reloc_type type) +new_reloc (defspace_t *space, int offset, reloc_type type) { reloc_t *ref; ALLOC (16384, reloc_t, refs, ref); + ref->space = space; ref->offset = offset; ref->type = type; ref->line = pr.source_line; @@ -168,7 +193,7 @@ new_reloc (int offset, reloc_type type) void reloc_op_def (def_t *def, int offset, int field) { - reloc_t *ref = new_reloc (offset, rel_op_a_def + field); + reloc_t *ref = new_reloc (0, offset, rel_op_a_def + field); ref->return_address = __builtin_return_address (0); ref->next = def->relocs; def->relocs = ref; @@ -177,70 +202,84 @@ reloc_op_def (def_t *def, int offset, int field) void reloc_op_def_ofs (def_t *def, int offset, int field) { - reloc_t *ref = new_reloc (offset, rel_op_a_def_ofs + field); + reloc_t *ref = new_reloc (0, offset, rel_op_a_def_ofs + field); ref->return_address = __builtin_return_address (0); ref->next = def->relocs; def->relocs = ref; } void -reloc_def_def (def_t *def, int offset) +reloc_def_def (def_t *def, def_t *location) { - reloc_t *ref = new_reloc (offset, rel_def_def); + reloc_t *ref; + + ref = new_reloc (location->space, location->offset, rel_def_def); ref->return_address = __builtin_return_address (0); ref->next = def->relocs; def->relocs = ref; } void -reloc_def_def_ofs (def_t *def, int offset) +reloc_def_def_ofs (def_t *def, def_t *location) { - reloc_t *ref = new_reloc (offset, rel_def_def_ofs); + reloc_t *ref; + + ref = new_reloc (location->space, location->offset, rel_def_def_ofs); ref->return_address = __builtin_return_address (0); ref->next = def->relocs; def->relocs = ref; } void -reloc_def_func (function_t *func, int offset) +reloc_def_func (function_t *func, def_t *location) { - reloc_t *ref = new_reloc (offset, rel_def_func); + reloc_t *ref; + + ref = new_reloc (location->space, location->offset, rel_def_func); ref->return_address = __builtin_return_address (0); ref->next = func->refs; func->refs = ref; } void -reloc_def_string (int offset) +reloc_def_string (def_t *location) { - reloc_t *ref = new_reloc (offset, rel_def_string); + reloc_t *ref; + + ref = new_reloc (location->space, location->offset, rel_def_string); ref->return_address = __builtin_return_address (0); ref->next = pr.relocs; pr.relocs = ref; } void -reloc_def_field (def_t *def, int offset) +reloc_def_field (def_t *def, def_t *location) { - reloc_t *ref = new_reloc (offset, rel_def_field); + reloc_t *ref; + + ref = new_reloc (location->space, location->offset, rel_def_field); ref->return_address = __builtin_return_address (0); ref->next = def->relocs; def->relocs = ref; } void -reloc_def_field_ofs (def_t *def, int offset) +reloc_def_field_ofs (def_t *def, def_t *location) { - reloc_t *ref = new_reloc (offset, rel_def_field_ofs); + reloc_t *ref; + + ref = new_reloc (location->space, location->offset, rel_def_field_ofs); ref->return_address = __builtin_return_address (0); ref->next = def->relocs; def->relocs = ref; } void -reloc_def_op (ex_label_t *label, int offset) +reloc_def_op (ex_label_t *label, def_t *location) { - reloc_t *ref = new_reloc (offset, rel_def_op); + reloc_t *ref; + + ref = new_reloc (location->space, location->offset, rel_def_op); ref->return_address = __builtin_return_address (0); ref->next = pr.relocs; ref->label = label; diff --git a/tools/qfcc/source/switch.c b/tools/qfcc/source/switch.c index e75503c95..9137c37c3 100644 --- a/tools/qfcc/source/switch.c +++ b/tools/qfcc/source/switch.c @@ -340,7 +340,10 @@ 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++) { - reloc_def_op (&tree->labels[i]->e.label, sym->s.def->offset + i); + def_t loc; + loc.space = sym->s.def->space; + loc.offset = sym->s.def->offset + i; + reloc_def_op (&tree->labels[i]->e.label, &loc); } } }