/* obj_file.c qfcc object file support Copyright (C) 2002 Bill Currie Author: Bill Currie Date: 2002/6/21 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 */ #ifdef HAVE_CONFIG_H # include "config.h" #endif static __attribute__ ((used)) const char rcsid[] = "$Id$"; #ifdef HAVE_STRING_H # include #endif #ifdef HAVE_STRINGS_H # include #endif #include #include "QF/dstring.h" #include "QF/qendian.h" #include "QF/quakeio.h" #include "debug.h" #include "def.h" #include "emit.h" #include "expr.h" #include "function.h" #include "immediate.h" #include "obj_file.h" #include "options.h" #include "qfcc.h" #include "reloc.h" #include "strpool.h" #include "type.h" static qfo_def_t *defs; static int num_defs; static qfo_func_t *funcs; static int num_funcs; static qfo_reloc_t *relocs; static int num_relocs; static strpool_t *types; static int count_relocs (reloc_t *reloc) { int num = 0; while (reloc) { num++; reloc = reloc->next; } return num; } static void allocate_stuff (void) { def_t *def; function_t *func; num_defs = pr.scope->num_defs; num_funcs = pr.num_functions - 1; num_relocs = 0; for (def = pr.scope->head; def; def = def->def_next) { num_relocs += count_relocs (def->refs); } for (func = pr.func_head; func; func = func->next) { num_relocs += count_relocs (func->refs); if (func->scope) { num_defs += func->scope->num_defs; for (def = func->scope->head; def; def = def->def_next) { num_relocs += count_relocs (def->refs); } } } num_relocs += count_relocs (pr.relocs); if (num_defs) defs = calloc (num_defs, sizeof (qfo_def_t)); if (num_funcs) funcs = calloc (num_funcs, sizeof (qfo_func_t)); if (num_relocs) relocs = calloc (num_relocs, sizeof (qfo_reloc_t)); } static string_t type_encoding (type_t *type) { static dstring_t *encoding; if (!encoding) encoding = dstring_newstr (); else dstring_clearstr (encoding); encode_type (encoding, type); return strpool_addstr (types, encoding->str); } static int flags (def_t *d) { int flags = 0; if (d->initialized) flags |= QFOD_INITIALIZED; if (d->constant) flags |= QFOD_CONSTANT; if (d->absolute) flags |= QFOD_ABSOLUTE; if (d->global) flags |= QFOD_GLOBAL; if (d->external) flags |= QFOD_EXTERNAL; if (d->local) flags |= QFOD_LOCAL; if (d->system) flags |= QFOD_SYSTEM; if (d->nosave) flags |= QFOD_NOSAVE; return flags; } static void write_one_reloc (reloc_t *r, qfo_reloc_t **reloc, int def) { (*reloc)->ofs = LittleLong (r->ofs); (*reloc)->type = LittleLong (r->type); (*reloc)->def = LittleLong (def); (*reloc)++; } static void write_relocs (reloc_t *r, qfo_reloc_t **reloc, int def) { while (r) { write_one_reloc (r, reloc, def); r = r->next; } } static void write_def (def_t *d, qfo_def_t *def, qfo_reloc_t **reloc) { d->obj_def = def - defs; def->basic_type = LittleLong (d->type->type); def->full_type = LittleLong (type_encoding (d->type)); def->name = LittleLong (ReuseString (d->name)); def->ofs = LittleLong (d->ofs); def->relocs = LittleLong (*reloc - relocs); def->num_relocs = LittleLong (count_relocs (d->refs)); def->flags = LittleLong (flags (d)); def->file = LittleLong (d->file); def->line = LittleLong (d->line); write_relocs (d->refs, reloc, d->obj_def); } static void setup_data (void) { qfo_def_t *def = defs; def_t *d; qfo_func_t *func = funcs; function_t *f; qfo_reloc_t *reloc = relocs; reloc_t *r; dstatement_t *st; pr_type_t *var; pr_lineno_t *line; for (d = pr.scope->head; d; d = d->def_next, def++) write_def (d, def, &reloc); for (f = pr.func_head; f; f = f->next, func++) { func->name = LittleLong (f->s_name); func->file = LittleLong (f->s_file); func->line = LittleLong (f->def->line); func->builtin = LittleLong (f->builtin); func->code = LittleLong (f->code); if (f->def->obj_def) func->def = LittleLong (f->def->obj_def); else { func->def = LittleLong (def - defs); write_def (f->def, def++, &reloc); } if (f->scope) { func->locals_size = LittleLong (f->scope->space->size); func->local_defs = LittleLong (def - defs); func->num_local_defs = LittleLong (f->scope->num_defs); } if (f->aux) func->line_info = LittleLong (f->aux->line_info); func->num_parms = LittleLong (function_parms (f, func->parm_size)); func->relocs = LittleLong (reloc - relocs); func->num_relocs = LittleLong (count_relocs (f->refs)); write_relocs (f->refs, &reloc, func - funcs); if (f->scope) for (d = f->scope->head; d; d = d->def_next) write_def (d, def++, &reloc); } for (r = pr.relocs; r; r = r->next) if (r->type == rel_def_op) write_one_reloc (r, &reloc, r->label->ofs); else write_one_reloc (r, &reloc, 0); for (st = pr.code->code; st - pr.code->code < pr.code->size; st++) { st->op = LittleLong (st->op); st->a = LittleLong (st->a); st->b = LittleLong (st->b); st->c = LittleLong (st->c); } for (var = pr.near_data->data; var - pr.near_data->data < pr.near_data->size; var++) var->integer_var = LittleLong (var->integer_var); if (pr.far_data) for (var = pr.far_data->data; var - pr.far_data->data < pr.far_data->size; var++) var->integer_var = LittleLong (var->integer_var); for (line = pr.linenos; line - pr.linenos < pr.num_linenos; line++) { line->fa.addr = LittleLong (line->fa.addr); line->line = LittleLong (line->line); } } static void round_strings (strpool_t *strings) { memset (strings->strings + strings->size, 0, strings->max_size - strings->size); strings->size = RUP (strings->size, 4); } qfo_t * qfo_from_progs (pr_info_t *pr) { qfo_t *qfo; types = strpool_new (); allocate_stuff (); setup_data (); round_strings (pr->strings); round_strings (types); qfo = qfo_new (); qfo_add_code (qfo, pr->code->code, pr->code->size); qfo_add_data (qfo, pr->near_data->data, pr->near_data->size); if (pr->far_data) qfo_add_far_data (qfo, pr->far_data->data, pr->far_data->size); qfo_add_strings (qfo, pr->strings->strings, pr->strings->size); qfo_add_relocs (qfo, relocs, num_relocs); qfo_add_defs (qfo, defs, num_defs); qfo_add_funcs (qfo, funcs, num_funcs); qfo_add_lines (qfo, pr->linenos, pr->num_linenos); qfo_add_types (qfo, types->strings, types->size); qfo->entity_fields = pr->entity_data->size; free (defs); free (relocs); free (funcs); strpool_delete (types); return qfo; } int qfo_write (qfo_t *qfo, const char *filename) { qfo_header_t hdr; QFile *file; file = Qopen (filename, options.gzip ? "wbz9" : "wb"); if (!file) return -1; memset (&hdr, 0, sizeof (hdr)); memcpy (hdr.qfo, QFO, sizeof (hdr.qfo)); hdr.version = LittleLong (QFO_VERSION); hdr.code_size = LittleLong (qfo->code_size); hdr.data_size = LittleLong (qfo->data_size); hdr.far_data_size = LittleLong (qfo->far_data_size); hdr.strings_size = LittleLong (qfo->strings_size); hdr.num_relocs = LittleLong (qfo->num_relocs); hdr.num_defs = LittleLong (qfo->num_defs); hdr.num_funcs = LittleLong (qfo->num_funcs); hdr.num_lines = LittleLong (qfo->num_lines); hdr.types_size = LittleLong (qfo->types_size); hdr.entity_fields = LittleLong (qfo->entity_fields); Qwrite (file, &hdr, sizeof (hdr)); if (qfo->code_size) Qwrite (file, qfo->code, qfo->code_size * sizeof (dstatement_t)); if (qfo->data_size) Qwrite (file, qfo->data, qfo->data_size * sizeof (pr_type_t)); if (qfo->far_data_size) Qwrite (file, qfo->far_data, qfo->far_data_size * sizeof (pr_type_t)); if (qfo->strings_size) Qwrite (file, qfo->strings, qfo->strings_size); if (qfo->num_relocs) Qwrite (file, qfo->relocs, qfo->num_relocs * sizeof (qfo_reloc_t)); if (qfo->num_defs) Qwrite (file, qfo->defs, qfo->num_defs * sizeof (qfo_def_t)); if (qfo->num_funcs) Qwrite (file, qfo->funcs, qfo->num_funcs * sizeof (qfo_func_t)); if (qfo->num_lines) Qwrite (file, qfo->lines, qfo->num_lines * sizeof (pr_lineno_t)); if (qfo->types_size) Qwrite (file, qfo->types, qfo->types_size); Qclose (file); return 0; } qfo_t * qfo_read (QFile *file) { qfo_header_t hdr; qfo_t *qfo; qfo_def_t *def; qfo_func_t *func; qfo_reloc_t *reloc; dstatement_t *st; pr_type_t *var; pr_lineno_t *line; Qread (file, &hdr, sizeof (hdr)); if (strcmp (hdr.qfo, QFO)) { fprintf (stderr, "not a qfo file\n"); return 0; } qfo = calloc (1, sizeof (qfo_t)); hdr.version = LittleLong (hdr.version); qfo->code_size = LittleLong (hdr.code_size); qfo->data_size = LittleLong (hdr.data_size); qfo->far_data_size = LittleLong (hdr.far_data_size); qfo->strings_size = LittleLong (hdr.strings_size); qfo->num_relocs = LittleLong (hdr.num_relocs); qfo->num_defs = LittleLong (hdr.num_defs); qfo->num_funcs = LittleLong (hdr.num_funcs); qfo->num_lines = LittleLong (hdr.num_lines); qfo->types_size = LittleLong (hdr.types_size); qfo->entity_fields = LittleLong (hdr.entity_fields); if (hdr.version != QFO_VERSION) { fprintf (stderr, "can't read version %x.%03x.%03x\n", (hdr.version >> 24) & 0xff, (hdr.version >> 12) & 0xfff, hdr.version & 0xfff); free (qfo); return 0; } if (qfo->code_size) qfo->code = malloc (qfo->code_size * sizeof (dstatement_t)); if (qfo->data_size) qfo->data = malloc (qfo->data_size * sizeof (pr_type_t)); if (qfo->far_data_size) qfo->far_data = malloc (qfo->far_data_size * sizeof (pr_type_t)); if (qfo->strings_size) qfo->strings = malloc (qfo->strings_size); if (qfo->num_relocs) qfo->relocs = malloc (qfo->num_relocs * sizeof (qfo_reloc_t)); if (qfo->num_defs) qfo->defs = malloc (qfo->num_defs * sizeof (qfo_def_t)); if (qfo->num_funcs) qfo->funcs = malloc (qfo->num_funcs * sizeof (qfo_func_t)); if (qfo->num_lines) qfo->lines = malloc (qfo->num_lines * sizeof (pr_lineno_t)); if (qfo->types_size) qfo->types = malloc (qfo->types_size); if (qfo->code_size) Qread (file, qfo->code, qfo->code_size * sizeof (dstatement_t)); if (qfo->data_size) Qread (file, qfo->data, qfo->data_size * sizeof (pr_type_t)); if (qfo->far_data_size) Qread (file, qfo->far_data, qfo->far_data_size * sizeof (pr_type_t)); if (qfo->strings_size) Qread (file, qfo->strings, qfo->strings_size); if (qfo->num_relocs) Qread (file, qfo->relocs, qfo->num_relocs * sizeof (qfo_reloc_t)); if (qfo->num_defs) Qread (file, qfo->defs, qfo->num_defs * sizeof (qfo_def_t)); if (qfo->num_funcs) Qread (file, qfo->funcs, qfo->num_funcs * sizeof (qfo_func_t)); if (qfo->num_lines) Qread (file, qfo->lines, qfo->num_lines * sizeof (pr_lineno_t)); if (qfo->types_size) Qread (file, qfo->types, qfo->types_size); for (st = qfo->code; st - qfo->code < qfo->code_size; st++) { st->op = LittleLong (st->op); st->a = LittleLong (st->a); st->b = LittleLong (st->b); st->c = LittleLong (st->c); } for (var = qfo->data; var - qfo->data < qfo->data_size; var++) var->integer_var = LittleLong (var->integer_var); if (qfo->far_data) for (var = qfo->far_data; var - qfo->far_data < qfo->far_data_size; var++) var->integer_var = LittleLong (var->integer_var); for (reloc = qfo->relocs; reloc - qfo->relocs < qfo->num_relocs; reloc++) { reloc->ofs = LittleLong (reloc->ofs); reloc->type = LittleLong (reloc->type); reloc->def = LittleLong (reloc->def); } for (def = qfo->defs; def - qfo->defs < qfo->num_defs; def++) { def->basic_type = LittleLong (def->basic_type); def->full_type = LittleLong (def->full_type); def->name = LittleLong (def->name); def->ofs = LittleLong (def->ofs); def->relocs = LittleLong (def->relocs); def->num_relocs = LittleLong (def->num_relocs); def->flags = LittleLong (def->flags); def->file = LittleLong (def->file); def->line = LittleLong (def->line); } for (func = qfo->funcs; func - qfo->funcs < qfo->num_funcs; func++) { func->name = LittleLong (func->name); func->file = LittleLong (func->file); func->line = LittleLong (func->line); func->builtin = LittleLong (func->builtin); func->code = LittleLong (func->code); func->def = LittleLong (func->def); func->locals_size = LittleLong (func->locals_size); func->local_defs = LittleLong (func->local_defs); func->num_local_defs = LittleLong (func->num_local_defs); func->line_info = LittleLong (func->line_info); func->num_parms = LittleLong (func->num_parms); func->relocs = LittleLong (func->relocs); func->num_relocs = LittleLong (func->num_relocs); } for (line = qfo->lines; line - qfo->lines < qfo->num_lines; line++) { line->fa.addr = LittleLong (line->fa.addr); line->line = LittleLong (line->line); } return qfo; } qfo_t * qfo_open (const char *filename) { qfo_t *qfo; QFile *file; file = Qopen (filename, "rbz"); if (!file) { perror (filename); return 0; } qfo = qfo_read (file); Qclose (file); return qfo; } static defspace_t * init_space (int size, pr_type_t *data) { defspace_t *space = new_defspace (); space->size = size; space->max_size = RUP (space->size, 65536); if (!space->max_size) space->max_size=65536; space->data = malloc (space->max_size * sizeof (pr_type_t)); if (size && data) { memcpy (space->data, data, size * sizeof (pr_type_t)); } return space; } int qfo_to_progs (qfo_t *qfo, pr_info_t *pr) { int i; function_t *pf; qfo_func_t *qf; def_t *pd; qfo_def_t *qd; reloc_t *relocs = 0; int first_local; if (qfo->num_relocs) relocs = calloc (qfo->num_relocs, sizeof (reloc_t)); for (i = 0; i < qfo->num_relocs; i++) { if (i + 1 < qfo->num_relocs) relocs[i].next = &relocs[i + 1]; relocs[i].ofs = qfo->relocs[i].ofs; relocs[i].type = qfo->relocs[i].type; } pr->strings = strpool_build (qfo->strings, qfo->strings_size); pr->code = codespace_new (); codespace_addcode (pr->code, qfo->code, qfo->code_size); pr->near_data = init_space (qfo->data_size, qfo->data); pr->far_data = init_space (qfo->far_data_size, qfo->far_data); pr->entity_data = new_defspace (); pr->scope = new_scope (sc_global, pr->near_data, 0); pr->scope->num_defs = qfo->num_defs; if (qfo->num_defs) pr->scope->head = calloc (pr->scope->num_defs, sizeof (def_t)); for (i = 0, pd = pr->scope->head, qd = qfo->defs; i < pr->scope->num_defs; i++, pd++, qd++) { *pr->scope->tail = pd; pr->scope->tail = &pd->def_next; pd->type = parse_type (qfo->types + qd->full_type); pd->name = qd->name ? qfo->strings + qd->name : 0; pd->ofs = qd->ofs; if (qd->num_relocs) { pd->refs = relocs + qd->relocs; pd->refs[qd->num_relocs - 1].next = 0; } pd->initialized = (qd->flags & QFOD_INITIALIZED) != 0; pd->constant = (qd->flags & QFOD_CONSTANT) != 0; pd->absolute = (qd->flags & QFOD_ABSOLUTE) != 0; pd->global = (qd->flags & QFOD_GLOBAL) != 0; pd->external = (qd->flags & QFOD_EXTERNAL) != 0; pd->local = (qd->flags & QFOD_LOCAL) != 0; pd->system = (qd->flags & QFOD_SYSTEM) != 0; pd->nosave = (qd->flags & QFOD_NOSAVE) != 0; pd->file = qd->file; pd->line = qd->line; } pr->num_functions = qfo->num_funcs + 1; if (qfo->num_funcs) pr->func_head = calloc (qfo->num_funcs, sizeof (function_t)); pr->func_tail = &pr->func_head; first_local = qfo->num_defs; for (i = 0, pf = pr->func_head, qf = qfo->funcs; i < qfo->num_funcs; i++, pf++, qf++) { *pr->func_tail = pf; pr->func_tail = &pf->next; pf->aux = new_auxfunction (); pf->aux->function = i + 1; pf->aux->source_line = qf->line; pf->aux->line_info = qf->line_info; pf->aux->local_defs = 0; pf->aux->num_locals = 0; pf->builtin = qf->builtin; pf->code = qf->code; pf->function_num = i + 1; pf->s_file = qf->file; pf->s_name = qf->name; pf->def = pr->scope->head + qf->def; pf->scope = new_scope (sc_params, init_space (qf->locals_size, 0), pr->scope); if (qf->num_local_defs) { if (first_local > qf->local_defs) first_local = qf->local_defs; pf->scope->head = pr->scope->head + qf->local_defs; pf->scope->tail = &pf->scope->head[qf->num_local_defs - 1].def_next; *pf->scope->tail = 0; pf->aux->local_defs = pr->num_locals; for (pd = pf->scope->head; pd; pd = pd->def_next) { if (pd->name) { def_to_ddef (pd, new_local (), 0); pf->aux->num_locals++; } } } if (qf->num_relocs) { pf->refs = relocs + qf->relocs; pf->refs[qf->num_relocs - 1].next = 0; } } if (first_local > 0) { pd = pr->scope->head + first_local - 1; pr->scope->tail = &pd->def_next; pd->def_next = 0; } pr->num_linenos = pr->linenos_size = qfo->num_lines; if (pr->num_linenos) { pr->linenos = malloc (pr->num_linenos * sizeof (pr_lineno_t)); memcpy (pr->linenos, qfo->lines, pr->num_linenos * sizeof (pr_lineno_t)); } pr->entity_data = init_space (qfo->entity_fields, 0); return 0; } qfo_t * qfo_new (void) { return calloc (1, sizeof (qfo_t)); } void qfo_add_code (qfo_t *qfo, dstatement_t *code, int code_size) { if (!code_size) return; qfo->code = malloc (code_size * sizeof (dstatement_t)); qfo->code_size = code_size; memcpy (qfo->code, code, code_size * sizeof (dstatement_t)); } void qfo_add_data (qfo_t *qfo, pr_type_t *data, int data_size) { if (!data_size) return; qfo->data = malloc (data_size * sizeof (pr_type_t)); qfo->data_size = data_size; memcpy (qfo->data, data, data_size * sizeof (pr_type_t)); } void qfo_add_far_data (qfo_t *qfo, pr_type_t *far_data, int far_data_size) { if (!far_data_size) return; qfo->far_data = malloc (far_data_size * sizeof (pr_type_t)); qfo->far_data_size = far_data_size; memcpy (qfo->far_data, far_data, far_data_size * sizeof (pr_type_t)); } void qfo_add_strings (qfo_t *qfo, const char *strings, int strings_size) { if (!strings_size) return; qfo->strings = malloc (strings_size); qfo->strings_size = strings_size; memcpy (qfo->strings, strings, strings_size); } void qfo_add_relocs (qfo_t *qfo, qfo_reloc_t *relocs, int num_relocs) { if (!num_relocs) return; qfo->relocs = malloc (num_relocs * sizeof (qfo_reloc_t)); qfo->num_relocs = num_relocs; memcpy (qfo->relocs, relocs, num_relocs * sizeof (qfo_reloc_t)); } void qfo_add_defs (qfo_t *qfo, qfo_def_t *defs, int num_defs) { if (!num_defs) return; qfo->defs = malloc (num_defs * sizeof (qfo_def_t)); qfo->num_defs = num_defs; memcpy (qfo->defs, defs, num_defs * sizeof (qfo_def_t)); } void qfo_add_funcs (qfo_t *qfo, qfo_func_t *funcs, int num_funcs) { if (!num_funcs) return; qfo->funcs = malloc (num_funcs * sizeof (qfo_func_t)); qfo->num_funcs = num_funcs; memcpy (qfo->funcs, funcs, num_funcs * sizeof (qfo_func_t)); } void qfo_add_lines (qfo_t *qfo, pr_lineno_t *lines, int num_lines) { if (!num_lines) return; qfo->lines = malloc (num_lines * sizeof (pr_lineno_t)); qfo->num_lines = num_lines; memcpy (qfo->lines, lines, num_lines * sizeof (pr_lineno_t)); } void qfo_add_types (qfo_t *qfo, const char *types, int types_size) { if (!types_size) return; qfo->types = malloc (types_size); qfo->types_size = types_size; memcpy (qfo->types, types, types_size); } void qfo_delete (qfo_t *qfo) { if (!qfo) return; if (qfo->code) free (qfo->code); if (qfo->data) free (qfo->data); if (qfo->far_data) free (qfo->far_data); if (qfo->strings) free (qfo->strings); if (qfo->relocs) free (qfo->relocs); if (qfo->defs) free (qfo->defs); if (qfo->funcs) free (qfo->funcs); if (qfo->lines) free (qfo->lines); if (qfo->types) free (qfo->types); free (qfo); }