From 11c7c27f7099597e252019a531d3bae71b51f585 Mon Sep 17 00:00:00 2001
From: Bill Currie <bill@taniwha.org>
Date: Thu, 21 Aug 2003 02:21:30 +0000
Subject: [PATCH] better relocations: pointers to structure members now work

---
 tools/qfcc/include/reloc.h |  7 ++++++
 tools/qfcc/source/emit.c   | 25 +++++++++----------
 tools/qfcc/source/expr.c   |  2 +-
 tools/qfcc/source/linker.c | 20 +++++++++++++--
 tools/qfcc/source/qfcc.c   |  7 +-----
 tools/qfcc/source/reloc.c  | 50 ++++++++++++++++++++++++++++++++++++++
 6 files changed, 89 insertions(+), 22 deletions(-)

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)
 {