quakeforge/tools/qfcc/source/obj_file.c
Bill Currie 7a504f8983 Use float for enum defs in v6 progs.
The values are (or should be!) written as floats, so don't give any
debuggers hernias when displaying enums in v6 progs.
2013-01-17 20:53:22 +09:00

1048 lines
30 KiB
C

/*
obj_file.c
qfcc object file support
Copyright (C) 2002 Bill Currie <bill@taniwha.org>
Author: Bill Currie <bill@taniwha.org>
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
#ifdef HAVE_STRING_H
# include <string.h>
#endif
#ifdef HAVE_STRINGS_H
# include <strings.h>
#endif
#include <stdlib.h>
#include "QF/dstring.h"
#include "QF/qendian.h"
#include "QF/quakeio.h"
#include "QF/va.h"
#include "codespace.h"
#include "debug.h"
#include "def.h"
#include "defspace.h"
#include "emit.h"
#include "expr.h"
#include "function.h"
#include "obj_file.h"
#include "obj_type.h"
#include "options.h"
#include "qfcc.h"
#include "reloc.h"
#include "statements.h"
#include "strpool.h"
#include "symtab.h"
#include "type.h"
#include "value.h"
static int
count_relocs (reloc_t *r)
{
int count;
for (count = 0; r; r = r->next)
count++;
return count;
}
static unsigned
qfo_def_flags (def_t *def)
{
unsigned flags = 0;
if (def->initialized)
flags |= QFOD_INITIALIZED;
if (def->constant)
flags |= QFOD_CONSTANT;
if (def->global)
flags |= QFOD_GLOBAL;
if (def->external)
flags |= QFOD_EXTERNAL;
if (def->local)
flags |= QFOD_LOCAL;
if (def->system)
flags |= QFOD_SYSTEM;
if (def->nosave)
flags |= QFOD_NOSAVE;
if (def->param)
flags |= QFOD_PARAM;
return flags;
}
static void
qfo_encode_one_reloc (reloc_t *reloc, qfo_reloc_t **qfo_reloc, pr_int_t target)
{
qfo_reloc_t *q;
q = (*qfo_reloc)++;
if (reloc->space) // op_* relocs do not have a space (code is implied)
q->space = reloc->space->qfo_space;
q->offset = reloc->offset;
q->type = reloc->type;
q->target = target;
}
static int
qfo_encode_relocs (reloc_t *relocs, qfo_reloc_t **qfo_relocs, pr_int_t target)
{
int count;
reloc_t *r;
for (count = 0, r = relocs; r; r = r->next) {
count++;
qfo_encode_one_reloc (r, qfo_relocs, target);
}
return count;
}
static int
qfo_encode_defs (qfo_t *qfo, def_t *defs, qfo_def_t **qfo_defs,
qfo_reloc_t **qfo_relocs)
{
int count;
def_t *d;
qfo_def_t *q;
for (count = 0, d = defs; d; d = d->next) {
count++;
q = (*qfo_defs)++;
d->qfo_def = q - qfo->defs;
// defs in the type data space do not have types
if (d->type)
q->type = d->type->type_def->offset;
q->name = ReuseString (d->name);
q->offset = d->offset;
q->relocs = *qfo_relocs - qfo->relocs;
q->num_relocs = qfo_encode_relocs (d->relocs, qfo_relocs,
q - qfo->defs);
q->flags = qfo_def_flags (d);
q->file = d->file;
q->line = d->line;
}
return count;
}
static void
qfo_count_space_stuff (qfo_t *qfo, defspace_t *space)
{
def_t *d;
for (d = space->defs; d; d = d->next) {
qfo->num_defs++;
qfo->num_relocs += count_relocs (d->relocs);
}
}
static void
qfo_count_function_stuff (qfo_t *qfo, function_t *functions)
{
function_t *func;
for (func = functions; func; func = func->next) {
qfo->num_funcs++;
qfo->num_relocs += count_relocs (func->refs);
if (func->symtab && func->symtab->space) {
qfo->num_spaces++;
qfo_count_space_stuff (qfo, func->symtab->space);
}
}
}
static void
qfo_count_stuff (qfo_t *qfo, pr_info_t *pr)
{
qfo_count_space_stuff (qfo, pr->near_data);
qfo_count_space_stuff (qfo, pr->far_data);
qfo_count_space_stuff (qfo, pr->entity_data);
qfo_count_space_stuff (qfo, pr->type_data);
qfo_count_function_stuff (qfo, pr->func_head);
qfo->num_relocs += count_relocs (pr->relocs);
}
static void
qfo_init_string_space (qfo_t *qfo, qfo_mspace_t *space, strpool_t *strings)
{
strings->qfo_space = space - qfo->spaces;
space->type = qfos_string;
space->num_defs = 0;
space->defs = 0;
space->d.strings = strings->strings;
space->data_size = strings->size;
space->id = qfo_strings_space;
}
static void
qfo_init_code_space (qfo_t *qfo, qfo_mspace_t *space, codespace_t *code)
{
code->qfo_space = space - qfo->spaces;
space->type = qfos_code;
space->num_defs = 0;
space->defs = 0;
space->d.code = code->code;
space->data_size = code->size;
space->id = qfo_code_space;
}
static void
qfo_init_data_space (qfo_t *qfo, qfo_def_t **defs, qfo_reloc_t **relocs,
qfo_mspace_t *space, defspace_t *data)
{
data->qfo_space = space - qfo->spaces;
space->type = qfos_data;
space->defs = *defs;
space->num_defs = qfo_encode_defs (qfo, data->defs, defs, relocs);
space->d.data = data->data;
space->data_size = data->size;
}
static void
qfo_init_entity_space (qfo_t *qfo, qfo_def_t **defs, qfo_reloc_t **relocs,
qfo_mspace_t *space, defspace_t *data)
{
data->qfo_space = space - qfo->spaces;
space->type = qfos_entity;
space->defs = *defs;
space->num_defs = qfo_encode_defs (qfo, data->defs, defs, relocs);
space->d.data = 0;
space->data_size = data->size;
space->id = qfo_entity_space;
}
static void
qfo_init_type_space (qfo_t *qfo, qfo_def_t **defs, qfo_reloc_t **relocs,
qfo_mspace_t *space, defspace_t *data)
{
data->qfo_space = space - qfo->spaces;
space->type = qfos_type;
space->defs = *defs;
space->num_defs = qfo_encode_defs (qfo, data->defs, defs, relocs);
space->d.data = data->data;
space->data_size = data->size;
space->id = qfo_type_space;
}
static void
qfo_encode_functions (qfo_t *qfo, qfo_def_t **defs, qfo_reloc_t **relocs,
qfo_mspace_t *space, function_t *functions)
{
function_t *f;
qfo_func_t *q;
for (f = functions, q = qfo->funcs; f; f = f->next, q++) {
q->name = f->s_name;
q->type = f->def->type->type_def->offset;
q->file = f->s_file;
q->line = f->def->line;
q->code = f->code;
if (f->builtin) // FIXME redundant
q->code = -f->builtin;
q->def = f->def->qfo_def;
if (f->symtab && f->symtab->space) {
space->id = f->symtab->space->qfo_space;
qfo_init_data_space (qfo, defs, relocs, space++, f->symtab->space);
q->locals_space = f->symtab->space->qfo_space;
}
q->line_info = f->line_info;
q->relocs = *relocs - qfo->relocs;
q->num_relocs = qfo_encode_relocs (f->refs, relocs, q - qfo->funcs);
}
}
qfo_t *
qfo_from_progs (pr_info_t *pr)
{
qfo_t *qfo;
qfo_def_t *def;
qfo_reloc_t *reloc;
reloc_t *r;
qfo = calloc (1, sizeof (qfo_t));
qfo->num_spaces = qfo_num_spaces; // certain spaces are always present
qfo_count_stuff (qfo, pr);
qfo->spaces = calloc (qfo->num_spaces, sizeof (qfo_mspace_t));
qfo->relocs = calloc (qfo->num_relocs, sizeof (qfo_reloc_t));
qfo->defs = calloc (qfo->num_defs, sizeof (qfo_def_t));
qfo->funcs = calloc (qfo->num_funcs, sizeof (qfo_func_t));
def = qfo->defs;
reloc = qfo->relocs;
pr->code->qfo_space = qfo_code_space;
pr->near_data->qfo_space = qfo_near_data_space;
pr->far_data->qfo_space = qfo_far_data_space;
pr->entity_data->qfo_space = qfo_entity_space;
pr->type_data->qfo_space = qfo_type_space;
pr->strings->qfo_space = qfo_strings_space;
qfo_init_code_space (qfo, &qfo->spaces[qfo_code_space], pr->code);
qfo_init_data_space (qfo, &def, &reloc, &qfo->spaces[qfo_near_data_space],
pr->near_data);
qfo->spaces[qfo_near_data_space].id = qfo_near_data_space;
qfo_init_data_space (qfo, &def, &reloc, &qfo->spaces[qfo_far_data_space],
pr->far_data);
qfo->spaces[qfo_far_data_space].id = qfo_far_data_space;
qfo_init_entity_space (qfo, &def, &reloc, &qfo->spaces[qfo_entity_space],
pr->entity_data);
qfo_init_type_space (qfo, &def, &reloc, &qfo->spaces[qfo_type_space],
pr->type_data);
qfo_encode_functions (qfo, &def, &reloc, qfo->spaces + qfo_num_spaces,
pr->func_head);
if (pr->num_linenos) {
qfo->lines = malloc (pr->num_linenos * sizeof (pr_lineno_t));
memcpy (qfo->lines, pr->linenos,
pr->num_linenos * sizeof (pr_lineno_t));
qfo->num_lines = pr->num_linenos;
}
// strings must be done last because encoding defs and functions adds the
// names
qfo_init_string_space (qfo, &qfo->spaces[qfo_strings_space], pr->strings);
qfo->num_loose_relocs = qfo->num_relocs - (reloc - qfo->relocs);
for (r = pr->relocs; r; r = r->next) {
if (r->type == rel_def_op) {
qfo_encode_one_reloc (r, &reloc, r->label->dest->offset);
} else if (r->type == rel_def_string) {
def_t d;
d.space = r->space;
d.offset = r->offset;
qfo_encode_one_reloc (r, &reloc, D_STRING (&d));
} else {
qfo_encode_one_reloc (r, &reloc, 0);
}
}
return qfo;
}
static int
qfo_space_size (qfo_mspace_t *space)
{
switch (space->type) {
case qfos_null:
return 0;
case qfos_code:
return space->data_size * sizeof (*space->d.code);
case qfos_data:
// data size > 0 but d.data == null -> all data is zero
if (!space->d.data)
return 0;
return space->data_size * sizeof (*space->d.data);
case qfos_string:
return space->data_size * sizeof (*space->d.strings);
case qfos_entity:
return 0;
case qfos_type:
return space->data_size * sizeof (*space->d.data);
}
return 0;
}
static void
qfo_byteswap_space (void *space, int size, qfos_type_t type)
{
int c;
pr_type_t *val;
dstatement_t *s;
switch (type) {
case qfos_null:
case qfos_string:
break;
case qfos_code:
for (s = (dstatement_t *) space, c = 0; c < size; c++, s++) {
s->op = LittleShort (s->op);
s->a = LittleShort (s->a);
s->b = LittleShort (s->b);
s->c = LittleShort (s->c);
}
break;
case qfos_data:
case qfos_entity:
case qfos_type:
for (val = (pr_type_t *) space, c = 0; c < size; c++, val++)
val->integer_var = LittleLong (val->integer_var);
break;
}
}
int
qfo_write (qfo_t *qfo, const char *filename)
{
int size;
int space_offset;
int i;
byte *data;
qfo_header_t *header;
qfo_space_t *spaces;
qfo_reloc_t *relocs;
qfo_def_t *defs;
qfo_func_t *funcs;
pr_lineno_t *lines;
byte *space_data;
QFile *file;
file = Qopen (filename, options.gzip ? "wbz9" : "wb");
if (!file)
return -1;
size = sizeof (qfo_header_t);
size += sizeof (qfo_space_t) * qfo->num_spaces;
size += sizeof (qfo_reloc_t) * qfo->num_relocs;
size += sizeof (qfo_def_t) * qfo->num_defs;
size += sizeof (qfo_func_t) * qfo->num_funcs;
size += sizeof (pr_lineno_t) * qfo->num_lines;
space_offset = size;
for (i = 0; i < qfo->num_spaces; i++)
size += RUP (qfo_space_size (qfo->spaces + i), 16);
data = calloc (1, size);
header = (qfo_header_t *) data;
memcpy (header->qfo, QFO, 4);
header->version = LittleLong (QFO_VERSION);
header->num_spaces = LittleLong (qfo->num_spaces);
header->num_relocs = LittleLong (qfo->num_relocs);
header->num_defs = LittleLong (qfo->num_defs);
header->num_funcs = LittleLong (qfo->num_funcs);
header->num_lines = LittleLong (qfo->num_lines);
header->num_loose_relocs = LittleLong (qfo->num_loose_relocs);
spaces = (qfo_space_t *) &header[1];
relocs = (qfo_reloc_t *) &spaces[qfo->num_spaces];
defs = (qfo_def_t *) &relocs[qfo->num_relocs];
funcs = (qfo_func_t *) &defs[qfo->num_defs];
lines = (pr_lineno_t *) &funcs[qfo->num_funcs];
space_data = data + space_offset;
for (i = 0; i < qfo->num_spaces; i++) {
spaces[i].type = LittleLong (qfo->spaces[i].type);
if (qfo->spaces[i].defs)
spaces[i].defs = LittleLong (qfo->spaces[i].defs - qfo->defs);
spaces[i].num_defs = LittleLong (qfo->spaces[i].num_defs);
if (qfo->spaces[i].d.data) {
int space_size = qfo_space_size (qfo->spaces + i);
spaces[i].data = LittleLong (space_data - data);
memcpy (space_data, qfo->spaces[i].d.data, space_size);
qfo_byteswap_space (space_data, qfo->spaces[i].data_size,
qfo->spaces[i].type);
space_data += RUP (space_size, 16);
}
spaces[i].data_size = LittleLong (qfo->spaces[i].data_size);
spaces[i].id = LittleLong (qfo->spaces[i].id);
}
for (i = 0; i < qfo->num_relocs; i++) {
relocs[i].space = LittleLong (qfo->relocs[i].space);
relocs[i].offset = LittleLong (qfo->relocs[i].offset);
relocs[i].type = LittleLong (qfo->relocs[i].type);
relocs[i].target = LittleLong (qfo->relocs[i].target);
}
for (i = 0; i < qfo->num_defs; i++) {
defs[i].type = LittleLong (qfo->defs[i].type);
defs[i].name = LittleLong (qfo->defs[i].name);
defs[i].offset = LittleLong (qfo->defs[i].offset);
defs[i].relocs = LittleLong (qfo->defs[i].relocs);
defs[i].num_relocs = LittleLong (qfo->defs[i].num_relocs);
defs[i].flags = LittleLong (qfo->defs[i].flags);
defs[i].file = LittleLong (qfo->defs[i].file);
defs[i].line = LittleLong (qfo->defs[i].line);
}
for (i = 0; i < qfo->num_funcs; i++) {
funcs[i].name = LittleLong (qfo->funcs[i].name);
funcs[i].type = LittleLong (qfo->funcs[i].type);
funcs[i].file = LittleLong (qfo->funcs[i].file);
funcs[i].line = LittleLong (qfo->funcs[i].line);
funcs[i].code = LittleLong (qfo->funcs[i].code);
funcs[i].def = LittleLong (qfo->funcs[i].def);
funcs[i].locals_space = LittleLong (qfo->funcs[i].locals_space);
funcs[i].line_info = LittleLong (qfo->funcs[i].line_info);
funcs[i].relocs = LittleLong (qfo->funcs[i].relocs);
funcs[i].num_relocs = LittleLong (qfo->funcs[i].num_relocs);
}
for (i = 0; i < qfo->num_lines; i++) {
lines[i].fa.addr = LittleLong (qfo->lines[i].fa.addr);
lines[i].line = LittleLong (qfo->lines[i].line);
}
Qwrite (file, data, size);
free (data);
Qclose (file);
return 0;
}
qfo_t *
qfo_read (QFile *file)
{
char *data;
int size;
qfo_header_t *header;
qfo_space_t *spaces;
qfo_t *qfo;
int i;
size = Qfilesize (file);
data = malloc (size);
Qread (file, data, size);
header = (qfo_header_t *) data;
header->version = LittleLong (header->version);
if (memcmp (header->qfo, QFO, 4) || header->version != QFO_VERSION) {
fprintf (stderr, "not a valid qfo file\n");
free (data);
return 0;
}
qfo = calloc (1, sizeof (qfo_t));
qfo->num_spaces = LittleLong (header->num_spaces);
qfo->num_relocs = LittleLong (header->num_relocs);
qfo->num_defs = LittleLong (header->num_defs);
qfo->num_funcs = LittleLong (header->num_funcs);
qfo->num_lines = LittleLong (header->num_lines);
qfo->num_loose_relocs = LittleLong (header->num_loose_relocs);
spaces = (qfo_space_t *) &header[1];
qfo->data = data;
qfo->spaces = calloc (sizeof (qfo_mspace_t), qfo->num_spaces);
qfo->relocs = (qfo_reloc_t *) &spaces[qfo->num_spaces];
qfo->defs = (qfo_def_t *) &qfo->relocs[qfo->num_relocs];
qfo->funcs = (qfo_func_t *) &qfo->defs[qfo->num_defs];
qfo->lines = (pr_lineno_t *) &qfo->funcs[qfo->num_funcs];
for (i = 0; i < qfo->num_spaces; i++) {
qfo->spaces[i].type = LittleLong (spaces[i].type);
qfo->spaces[i].num_defs = LittleLong (spaces[i].num_defs);
if (qfo->spaces[i].num_defs)
qfo->spaces[i].defs = qfo->defs + LittleLong (spaces[i].defs);
qfo->spaces[i].data_size = LittleLong (spaces[i].data_size);
if (spaces[i].data) {
qfo->spaces[i].d.strings = data + LittleLong (spaces[i].data);
qfo_byteswap_space (qfo->spaces[i].d.data,
qfo->spaces[i].data_size, qfo->spaces[i].type);
}
qfo->spaces[i].id = LittleLong (spaces[i].id);
}
for (i = 0; i < qfo->num_relocs; i++) {
qfo->relocs[i].space = LittleLong (qfo->relocs[i].space);
qfo->relocs[i].offset = LittleLong (qfo->relocs[i].offset);
qfo->relocs[i].type = LittleLong (qfo->relocs[i].type);
qfo->relocs[i].target = LittleLong (qfo->relocs[i].target);
}
for (i = 0; i < qfo->num_defs; i++) {
qfo->defs[i].type = LittleLong (qfo->defs[i].type);
qfo->defs[i].name = LittleLong (qfo->defs[i].name);
qfo->defs[i].offset = LittleLong (qfo->defs[i].offset);
qfo->defs[i].relocs = LittleLong (qfo->defs[i].relocs);
qfo->defs[i].num_relocs = LittleLong (qfo->defs[i].num_relocs);
qfo->defs[i].flags = LittleLong (qfo->defs[i].flags);
qfo->defs[i].file = LittleLong (qfo->defs[i].file);
qfo->defs[i].line = LittleLong (qfo->defs[i].line);
}
for (i = 0; i < qfo->num_funcs; i++) {
qfo->funcs[i].name = LittleLong (qfo->funcs[i].name);
qfo->funcs[i].type = LittleLong (qfo->funcs[i].type);
qfo->funcs[i].file = LittleLong (qfo->funcs[i].file);
qfo->funcs[i].line = LittleLong (qfo->funcs[i].line);
qfo->funcs[i].code = LittleLong (qfo->funcs[i].code);
qfo->funcs[i].def = LittleLong (qfo->funcs[i].def);
qfo->funcs[i].locals_space = LittleLong (qfo->funcs[i].locals_space);
qfo->funcs[i].line_info = LittleLong (qfo->funcs[i].line_info);
qfo->funcs[i].relocs = LittleLong (qfo->funcs[i].relocs);
qfo->funcs[i].num_relocs = LittleLong (qfo->funcs[i].num_relocs);
}
for (i = 0; i < qfo->num_lines; i++) {
qfo->lines[i].fa.addr = LittleLong (qfo->lines[i].fa.addr);
qfo->lines[i].line = LittleLong (qfo->lines[i].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;
}
qfo_t *
qfo_new (void)
{
return calloc (1, sizeof (qfo_t));
}
void
qfo_delete (qfo_t *qfo)
{
if (qfo->data) {
free (qfo->data);
} else {
int i;
for (i = 0; i < qfo->num_spaces; i++)
free (qfo->spaces->d.data);
free (qfo->relocs);
free (qfo->defs);
free (qfo->funcs);
free (qfo->lines);
}
free (qfo->spaces);
free (qfo);
}
static etype_t
get_def_type (qfo_t *qfo, pointer_t type)
{
qfot_type_t *type_def;
if (type >= qfo->spaces[qfo_type_space].data_size)
return ev_void;
type_def = QFO_POINTER (qfo, qfo_type_space, qfot_type_t, type);
switch ((ty_meta_e)type_def->ty) {
case ty_none:
// field, pointer and function types store their basic type in
// the same location.
return type_def->t.type;
case ty_struct:
case ty_union:
return ev_invalid;
case ty_enum:
if (options.code.progsversion == PROG_ID_VERSION)
return ev_float;
return ev_integer;
case ty_array:
case ty_class:
return ev_invalid;
}
return ev_invalid;
}
static etype_t
get_type_size (qfo_t *qfo, pointer_t type)
{
qfot_type_t *type_def;
int i, size;
if (type >= qfo->spaces[qfo_type_space].data_size)
return 1;
type_def = QFO_POINTER (qfo, qfo_type_space, qfot_type_t, type);
switch ((ty_meta_e)type_def->ty) {
case ty_none:
// field, pointer and function types store their basic type in
// the same location.
return pr_type_size[type_def->t.type];
case ty_struct:
for (i = size = 0; i < type_def->t.strct.num_fields; i++)
size += get_type_size (qfo, type_def->t.strct.fields[i].type);
return size;
case ty_union:
for (i = size = 0; i < type_def->t.strct.num_fields; i++) {
int s;
s = get_type_size (qfo, type_def->t.strct.fields[i].type);
if (s > size)
size = s;
}
return size;
case ty_enum:
return pr_type_size[ev_integer];
case ty_array:
return type_def->t.array.size
* get_type_size (qfo, type_def->t.array.type);
case ty_class:
return 0; // FIXME
}
return 0;
}
static void
function_params (qfo_t *qfo, qfo_func_t *func, dfunction_t *df)
{
qfot_type_t *type;
int num_params;
int i;
if (func->type >= qfo->spaces[qfo_type_space].data_size)
return;
type = QFO_POINTER (qfo, qfo_type_space, qfot_type_t, func->type);
if (type->ty != ty_none && type->t.type != ev_func)
return;
df->numparms = num_params = type->t.func.num_params;
if (num_params < 0)
num_params = ~num_params;
for (i = 0; i < num_params; i++)
df->parm_size[i] = get_type_size (qfo, type->t.func.param_types[i]);
}
static void
convert_def (qfo_t *qfo, const qfo_def_t *def, ddef_t *ddef)
{
ddef->type = get_def_type (qfo, def->type);
ddef->ofs = def->offset;
ddef->s_name = def->name;
if (!(def->flags & QFOD_NOSAVE)
&& !(def->flags & QFOD_CONSTANT)
&& (def->flags & QFOD_GLOBAL)
&& ddef->type != ev_func
&& ddef->type != ev_field)
ddef->type |= DEF_SAVEGLOBAL;
}
static void
qfo_relocate_refs (qfo_t *qfo)
{
int i;
qfo_reloc_t *reloc;
for (i = 0, reloc = qfo->relocs; i < qfo->num_relocs; i++, reloc++) {
// this will be valid only for *_def[_ofs] and *_field[_ofs] relocs
qfo_def_t *def = qfo->defs + reloc->target;
switch (reloc->type) {
case rel_none:
break;
case rel_op_a_def:
QFO_STATEMENT (qfo, reloc->offset)->a = def->offset;
break;
case rel_op_b_def:
QFO_STATEMENT (qfo, reloc->offset)->b = def->offset;
break;
case rel_op_c_def:
QFO_STATEMENT (qfo, reloc->offset)->c = def->offset;
break;
case rel_op_a_op:
case rel_op_b_op:
case rel_op_c_op:
// these should never appear in a qfo file
break;
case rel_def_op:
QFO_INT (qfo, reloc->space, reloc->offset) = reloc->target;
break;
case rel_def_def:
QFO_INT (qfo, reloc->space, reloc->offset) = def->offset;
break;
case rel_def_func:
QFO_INT (qfo, reloc->space, reloc->offset) = reloc->target + 1;
break;
case rel_def_string:
QFO_INT (qfo, reloc->space, reloc->offset) = reloc->target;
break;
case rel_def_field:
QFO_INT (qfo, reloc->space, reloc->offset) = def->offset;
break;
case rel_op_a_def_ofs:
QFO_STATEMENT (qfo, reloc->offset)->a += def->offset;
break;
case rel_op_b_def_ofs:
QFO_STATEMENT (qfo, reloc->offset)->b += def->offset;
break;
case rel_op_c_def_ofs:
QFO_STATEMENT (qfo, reloc->offset)->c += def->offset;
break;
case rel_def_def_ofs:
QFO_INT (qfo, reloc->space, reloc->offset) += def->offset;
break;
case rel_def_field_ofs:
QFO_INT (qfo, reloc->space, reloc->offset) += def->offset;
break;
}
}
}
dprograms_t *
qfo_to_progs (qfo_t *qfo, int *size)
{
byte *data;
char *strings;
dstatement_t *statements;
dfunction_t *functions;
ddef_t *globaldefs;
ddef_t *fielddefs;
pr_type_t *globals;
pr_type_t *locals;
pr_type_t *far_data;
pr_type_t *type_data;
dprograms_t *progs;
qfo_def_t *types_def = 0;
int i, j;
unsigned locals_size = 0;
int locals_start;
int big_locals = 0;
int big_func = 0;
*size = RUP (sizeof (dprograms_t), 16);
progs = calloc (1, *size);
progs->version = options.code.progsversion;
progs->numstatements = qfo->spaces[qfo_code_space].data_size;
progs->numglobaldefs = qfo->spaces[qfo_near_data_space].num_defs;
//FIXME ddef offsets are 16 bits
progs->numglobaldefs += qfo->spaces[qfo_far_data_space].num_defs;
progs->numfielddefs = qfo->spaces[qfo_entity_space].num_defs;
progs->numfunctions = qfo->num_funcs + 1;
progs->numstrings = qfo->spaces[qfo_strings_space].data_size;
progs->numglobals = qfo->spaces[qfo_near_data_space].data_size;
progs->numglobals += qfo->spaces[qfo_far_data_space].data_size;
progs->numglobals += qfo->spaces[qfo_type_space].data_size;
locals_start = qfo->spaces[qfo_near_data_space].data_size;
for (i = qfo_num_spaces; i < qfo->num_spaces; i++) {
if (options.code.local_merging) {
if (locals_size < qfo->spaces[i].data_size) {
locals_size = qfo->spaces[i].data_size;
big_locals = i;
}
} else {
locals_size += qfo->spaces[i].data_size;
}
}
progs->numglobals += locals_size;
progs->numglobals = RUP (progs->numglobals, 16 / sizeof (pr_type_t));
progs->entityfields = qfo->spaces[qfo_entity_space].data_size;
*size += progs->numstatements * sizeof (dstatement_t);
*size += progs->numglobaldefs * sizeof (ddef_t);
*size += progs->numfielddefs * sizeof (ddef_t);
*size += progs->numfunctions * sizeof (dfunction_t);
*size += RUP (progs->numstrings * sizeof (char), 16);
*size += progs->numglobals * sizeof (pr_type_t);
progs = realloc (progs, *size);
data = (byte *) progs;
memset (progs + 1, 0, *size - sizeof (dprograms_t));
data += RUP (sizeof (dprograms_t), 16);
progs->ofs_strings = data - (byte *) progs;
strings = (char *) data;
data += RUP (progs->numstrings * sizeof (char), 16);
progs->ofs_statements = data - (byte *) progs;
statements = (dstatement_t *) data;
data += progs->numstatements * sizeof (dstatement_t);
progs->ofs_functions = data - (byte *) progs;
functions = (dfunction_t *) data;
functions++; // skip over null function
data += progs->numfunctions * sizeof (dfunction_t);
progs->ofs_globaldefs = data - (byte *) progs;
globaldefs = (ddef_t *) data;
data += progs->numglobaldefs * sizeof (ddef_t);
progs->ofs_fielddefs = data - (byte *) progs;
fielddefs = (ddef_t *) (globaldefs + progs->numglobaldefs);
data += progs->numfielddefs * sizeof (ddef_t);
progs->ofs_globals = data - (byte *) progs;
globals = (pr_type_t*) data;
locals = globals + qfo->spaces[qfo_near_data_space].data_size;
far_data = locals + locals_size;
type_data = far_data + qfo->spaces[qfo_far_data_space].data_size;
memcpy (strings, qfo->spaces[qfo_strings_space].d.strings,
qfo->spaces[qfo_strings_space].data_size * sizeof (char));
qfo->spaces[qfo_strings_space].d.strings = strings;
memcpy (statements, qfo->spaces[qfo_code_space].d.code,
qfo->spaces[qfo_code_space].data_size * sizeof (dstatement_t));
qfo->spaces[qfo_code_space].d.code = statements;
for (i = 0; i < qfo->num_funcs; i++) {
dfunction_t *df = functions + i;
qfo_func_t *qf = qfo->funcs + i;
qfo_mspace_t *space = qfo->spaces + qf->locals_space;
df->first_statement = qf->code;
df->parm_start = locals_start;
df->locals = space->data_size;
// finalize the offsets of the local defs
for (j = 0; j < space->num_defs; j++)
space->defs[j].offset += locals_start;
if (!options.code.local_merging)
locals_start += df->locals;
df->profile = 0;
df->s_name = qf->name;
df->s_file = qf->file;
function_params (qfo, qf, df);
}
for (i = 0; i < qfo->spaces[qfo_near_data_space].num_defs; i++) {
qfo_def_t *def = qfo->spaces[qfo_near_data_space].defs + i;
if (!strcmp (QFO_GETSTR (qfo, def->name), ".type_encodings"))
types_def = def;
convert_def (qfo, def, globaldefs++);
}
//FIXME ddef offsets are 16 bits
for (i = 0; i < qfo->spaces[qfo_far_data_space].num_defs; i++) {
qfo_def_t *def = qfo->spaces[qfo_far_data_space].defs + i;
def->offset += far_data - globals;
convert_def (qfo, def, globaldefs++);
}
for (i = 0; i < qfo->spaces[qfo_type_space].num_defs; i++) {
qfo->spaces[qfo_type_space].defs[i].offset += type_data - globals;
}
for (i = 0; i < qfo->spaces[qfo_entity_space].num_defs; i++) {
convert_def (qfo, qfo->spaces[qfo_entity_space].defs + i,
fielddefs + i);
}
// copy near data
memcpy (globals, qfo->spaces[qfo_near_data_space].d.data,
qfo->spaces[qfo_near_data_space].data_size * sizeof (pr_type_t));
qfo->spaces[qfo_near_data_space].d.data = globals;
// lcear locals data
memset (locals, 0, locals_size * sizeof (pr_type_t));
// copy far data
memcpy (far_data, qfo->spaces[qfo_far_data_space].d.data,
qfo->spaces[qfo_far_data_space].data_size * sizeof (pr_type_t));
qfo->spaces[qfo_far_data_space].d.data = far_data;
// copy type data
memcpy (type_data, qfo->spaces[qfo_type_space].d.data,
qfo->spaces[qfo_type_space].data_size * sizeof (pr_type_t));
qfo->spaces[qfo_type_space].d.data = type_data;
qfo_relocate_refs (qfo);
if (types_def) {
qfot_type_encodings_t *encodings;
encodings = (qfot_type_encodings_t *) &globals[types_def->offset];
encodings->types = type_data - globals;
encodings->size = qfo->spaces[qfo_type_space].data_size;
}
// undo the relocation of the offsets of local defs so the local defs have
// the correct offset in the debug info
for (i = 0; i < qfo->num_funcs; i++) {
dfunction_t *df = functions + i;
qfo_func_t *qf = qfo->funcs + i;
qfo_mspace_t *space = qfo->spaces + qf->locals_space;
if (qf->locals_space == big_locals)
big_func = i;
for (j = 0; j < space->num_defs; j++)
space->defs[j].offset -= df->parm_start;
}
if (options.verbosity >= 0) {
const char *big_function = "";
if (big_func)
big_function = va (" (%s)", strings + qfo->funcs[big_func].name);
printf ("%6i strofs\n", progs->numstrings);
printf ("%6i statements\n", progs->numstatements);
printf ("%6i functions\n", progs->numfunctions);
printf ("%6i global defs\n", progs->numglobaldefs);
printf ("%6i fielddefs\n", progs->numfielddefs);
printf ("%6i globals\n", progs->numglobals);
printf (" %6i near globals\n",
qfo->spaces[qfo_near_data_space].data_size + locals_size);
printf (" %6i locals size%s\n", locals_size, big_function);
printf (" %6i far globals\n",
qfo->spaces[qfo_far_data_space].data_size);
printf (" %6i type globals\n",
qfo->spaces[qfo_type_space].data_size);
printf ("%6i entity fields\n", progs->entityfields);
}
if (options.verbosity >= -1)
printf ("%6i TOTAL SIZE\n", *size);
return progs;
}
pr_debug_header_t *
qfo_to_sym (qfo_t *qfo, int *size)
{
pr_debug_header_t *sym;
int i, j;
pr_auxfunction_t *auxfuncs;
pr_auxfunction_t *aux;
pr_lineno_t *linenos;
ddef_t *locals, *ld;
*size = sizeof (pr_debug_header_t);
sym = calloc (1, *size);
sym->version = PROG_DEBUG_VERSION;
for (i = 0; i < qfo->num_funcs; i++) {
qfo_func_t *func = qfo->funcs + i;
int num_locals = 0;
if (func->locals_space)
num_locals = qfo->spaces[func->locals_space].num_defs;
if (!func->line_info && !num_locals)
continue;
sym->num_auxfunctions++;
sym->num_locals += num_locals;
}
sym->num_linenos = qfo->num_lines;
*size += sym->num_auxfunctions * sizeof (pr_auxfunction_t);
*size += sym->num_linenos * sizeof (pr_lineno_t);
*size += sym->num_locals * sizeof (ddef_t);
sym = realloc (sym, *size);
auxfuncs = (pr_auxfunction_t *)(sym + 1);
linenos = (pr_lineno_t *)(auxfuncs + sym->num_auxfunctions);
locals = (ddef_t *)(linenos + sym->num_linenos);
sym->auxfunctions = (char *) auxfuncs - (char *) sym;
sym->linenos = (char *) linenos - (char *) sym;
sym->locals = (char *) locals - (char *) sym;
ld = locals;
for (i = 0, aux = auxfuncs; i < qfo->num_funcs; i++) {
qfo_func_t *func = qfo->funcs + i;
qfo_def_t *def = 0;
int num_locals = 0;
qfot_type_t *type;
if (func->locals_space) {
num_locals = qfo->spaces[func->locals_space].num_defs;
def = qfo->spaces[func->locals_space].defs;
}
if (!func->line_info && !num_locals)
continue;
memset (aux, 0, sizeof (*aux));
aux->function = i + 1;
aux->source_line = func->line;
aux->line_info = func->line_info;
if (func->line_info)
qfo->lines[func->line_info].fa.func = aux - auxfuncs;
if (num_locals) {
aux->local_defs = ld - locals;
for (j = 0; j < num_locals; j++)
convert_def (qfo, def++, ld++);
}
aux->num_locals = num_locals;
//FIXME check type
type = QFO_POINTER (qfo, qfo_type_space, qfot_type_t, func->type);
aux->return_type = type->t.func.return_type;
aux++;
}
memcpy (linenos, qfo->lines, qfo->num_lines * sizeof (pr_lineno_t));
return sym;
}