mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-10 23:32:09 +00:00
Finally, some real progress on the linker.
There is still much to be done, but this seems to be a workable approach.
This commit is contained in:
parent
bad7078797
commit
3761cddca6
1 changed files with 460 additions and 110 deletions
|
@ -66,14 +66,19 @@ static __attribute__ ((used)) const char rcsid[] = "$Id$";
|
||||||
#include "immediate.h"
|
#include "immediate.h"
|
||||||
#include "linker.h"
|
#include "linker.h"
|
||||||
#include "obj_file.h"
|
#include "obj_file.h"
|
||||||
|
#include "obj_type.h"
|
||||||
#include "options.h"
|
#include "options.h"
|
||||||
#include "qfcc.h"
|
#include "qfcc.h"
|
||||||
#include "reloc.h"
|
#include "reloc.h"
|
||||||
#include "strpool.h"
|
#include "strpool.h"
|
||||||
#include "type.h"
|
#include "type.h"
|
||||||
|
|
||||||
|
static void linker_error (const char *fmt, ...)
|
||||||
|
__attribute__ ((format (printf, 1, 2)));
|
||||||
|
static void linker_warning (const char *fmt, ...)
|
||||||
|
__attribute__ ((format (printf, 1, 2)));
|
||||||
static void def_error (qfo_def_t *def, const char *fmt, ...)
|
static void def_error (qfo_def_t *def, const char *fmt, ...)
|
||||||
__attribute__ ((used, format (printf, 2, 3)));
|
__attribute__ ((format (printf, 2, 3)));
|
||||||
static void def_warning (qfo_def_t *def, const char *fmt, ...)
|
static void def_warning (qfo_def_t *def, const char *fmt, ...)
|
||||||
__attribute__ ((used, format (printf, 2, 3)));
|
__attribute__ ((used, format (printf, 2, 3)));
|
||||||
|
|
||||||
|
@ -96,7 +101,27 @@ static builtin_sym_t builtin_symbols[] __attribute__ ((used)) = {
|
||||||
{".param_7", &type_param, QFOD_NOSAVE},
|
{".param_7", &type_param, QFOD_NOSAVE},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef struct defref_s {
|
||||||
|
struct defref_s *next;
|
||||||
|
qfo_def_t **def_list;
|
||||||
|
int def;
|
||||||
|
int space;
|
||||||
|
} defref_t;
|
||||||
|
|
||||||
|
#define REF(r) ((*(r)->def_list) + (r)->def)
|
||||||
|
|
||||||
|
static defref_t *free_defrefs;
|
||||||
|
|
||||||
|
static hashtab_t *extern_defs;
|
||||||
|
static hashtab_t *defined_defs;
|
||||||
|
|
||||||
|
static hashtab_t *extern_type_defs;
|
||||||
|
static hashtab_t *defined_type_defs;
|
||||||
|
static qfo_mspace_t *qfo_type_defs;
|
||||||
|
|
||||||
static qfo_t *work;
|
static qfo_t *work;
|
||||||
|
static defref_t **work_defrefs;
|
||||||
|
static int num_work_defrefs;
|
||||||
static strpool_t *work_strings;
|
static strpool_t *work_strings;
|
||||||
static codespace_t *work_code;
|
static codespace_t *work_code;
|
||||||
static defspace_t *work_near_data;
|
static defspace_t *work_near_data;
|
||||||
|
@ -104,6 +129,59 @@ static defspace_t *work_far_data;
|
||||||
static defspace_t *work_entity_data;
|
static defspace_t *work_entity_data;
|
||||||
static defspace_t *work_type_data;
|
static defspace_t *work_type_data;
|
||||||
|
|
||||||
|
static dstring_t *linker_current_file;
|
||||||
|
|
||||||
|
#define QFOSTR(q,s) QFO_GETSTR (q, s)
|
||||||
|
#define WORKSTR(s) QFOSTR (work, s)
|
||||||
|
|
||||||
|
/** Produce an error message for defs with mismatched types.
|
||||||
|
|
||||||
|
\param def The new def.
|
||||||
|
\param prev The previous definition.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
linker_type_mismatch (qfo_def_t *def, qfo_def_t *prev)
|
||||||
|
{
|
||||||
|
def_error (def, "type mismatch for `%s' `%s'",
|
||||||
|
WORKSTR (def->name),
|
||||||
|
QFO_TYPESTR (work, def->type));
|
||||||
|
def_error (prev, "previous definition `%s'",
|
||||||
|
QFO_TYPESTR (work, prev->type));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Create a new def reference.
|
||||||
|
|
||||||
|
References are required to avoid problems with realloc moving things
|
||||||
|
around.
|
||||||
|
|
||||||
|
The \a def must be in the \a space, and the \a space must be in the
|
||||||
|
\c work qfo.
|
||||||
|
|
||||||
|
\param def The def for which the reference will be created.
|
||||||
|
\param space The defspace in \c work which holds \a def.
|
||||||
|
\param def_list The list which currently holds the def.
|
||||||
|
\return The new reference.
|
||||||
|
*/
|
||||||
|
static defref_t *
|
||||||
|
get_defref (qfo_def_t *def, qfo_mspace_t *space, qfo_def_t **def_list)
|
||||||
|
{
|
||||||
|
defref_t *defref;
|
||||||
|
|
||||||
|
ALLOC (16384, defref_t, defrefs, defref);
|
||||||
|
defref->def_list = def_list;
|
||||||
|
defref->def = def - *def_list;
|
||||||
|
defref->space = space - work->spaces;
|
||||||
|
return defref;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *
|
||||||
|
defs_get_key (void *_r, void *unused)
|
||||||
|
{
|
||||||
|
defref_t *r = (defref_t *)_r;
|
||||||
|
qfo_def_t *d = REF (r);
|
||||||
|
return WORKSTR (d->name);
|
||||||
|
}
|
||||||
|
|
||||||
/** Add a string to the working qfo string pool.
|
/** Add a string to the working qfo string pool.
|
||||||
|
|
||||||
If the string is already in the string pool, the already existing string
|
If the string is already in the string pool, the already existing string
|
||||||
|
@ -124,6 +202,108 @@ add_string (const char *str)
|
||||||
return new;
|
return new;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Resolve an external def with its global definition.
|
||||||
|
|
||||||
|
The types of the external def and the global def must match.
|
||||||
|
The offset and flags of the global def are copied to the external def.
|
||||||
|
\fixme handle cross-space resolutions.
|
||||||
|
\fixme copy relocs from \a ext to \a def and "delete" \a ext?
|
||||||
|
|
||||||
|
\param ext The external def.
|
||||||
|
\param def The global definition.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
resolve_external_def (defref_t *ext, defref_t *def)
|
||||||
|
{
|
||||||
|
if (REF (ext)->type != REF (def)->type) {
|
||||||
|
linker_type_mismatch (REF (ext), REF (def));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (def->space != ext->space)
|
||||||
|
internal_error (0, "help, help!");
|
||||||
|
REF (ext)->offset = REF (def)->offset;
|
||||||
|
REF (ext)->flags = REF (def)->flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
process_def (defref_t *ref, qfo_mspace_t *space)
|
||||||
|
{
|
||||||
|
qfo_def_t *def;
|
||||||
|
defref_t *r;
|
||||||
|
const char *name;
|
||||||
|
|
||||||
|
def = REF (ref);
|
||||||
|
name = WORKSTR (def->name);
|
||||||
|
r = Hash_Find (defined_defs, name);
|
||||||
|
if (def->flags & QFOD_EXTERNAL) {
|
||||||
|
if (!def->num_relocs)
|
||||||
|
return;
|
||||||
|
if (r) {
|
||||||
|
resolve_external_def (ref, r);
|
||||||
|
} else {
|
||||||
|
Hash_Add (extern_defs, ref);
|
||||||
|
}
|
||||||
|
} else if (def->flags & QFOD_GLOBAL) {
|
||||||
|
if (r) {
|
||||||
|
if (REF (r)->flags & QFOD_SYSTEM) {
|
||||||
|
if (def->type != REF (r)->type) {
|
||||||
|
linker_type_mismatch (def, REF (r));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/// System defs may be redefined only once.
|
||||||
|
REF (r)->flags &= ~QFOD_SYSTEM;
|
||||||
|
if (ref->space != r->space)
|
||||||
|
internal_error (0, "help, help!");
|
||||||
|
//FIXME copy stuff from new def to existing def???
|
||||||
|
def->offset = REF(r)->offset;
|
||||||
|
def->flags = REF(r)->flags;
|
||||||
|
} else {
|
||||||
|
def_error (def, "%s redefined", WORKSTR (def->name));
|
||||||
|
def_error (REF (r), "previous definition");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Hash_Add (defined_defs, ref);
|
||||||
|
if (!(def->flags & QFOD_LOCAL))
|
||||||
|
def->offset += space->data_size;
|
||||||
|
while ((r = Hash_Del (extern_defs, name)))
|
||||||
|
resolve_external_def (r, ref);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
add_defs (qfo_t *qfo, qfo_mspace_t *space, qfo_mspace_t *dest_space)
|
||||||
|
{
|
||||||
|
int count = space->num_defs;
|
||||||
|
int size;
|
||||||
|
int i;
|
||||||
|
qfo_def_t *idef;
|
||||||
|
qfo_def_t *odef;
|
||||||
|
defref_t *ref;
|
||||||
|
|
||||||
|
size = (num_work_defrefs + count) * sizeof (defref_t *);
|
||||||
|
work_defrefs = realloc (work_defrefs, size);
|
||||||
|
size = (dest_space->num_defs + count) * sizeof (qfo_def_t);
|
||||||
|
dest_space->defs = realloc (dest_space->defs, size);
|
||||||
|
idef = space->defs;
|
||||||
|
odef = dest_space->defs + dest_space->num_defs;
|
||||||
|
for (i = 0; i < count; i++, idef++, odef++) {
|
||||||
|
*odef = *idef;
|
||||||
|
idef->offset = num_work_defrefs; // so def can be found
|
||||||
|
odef->name = add_string (QFOSTR (qfo, idef->name));
|
||||||
|
odef->file = add_string (QFOSTR (qfo, idef->file));
|
||||||
|
ref = get_defref (odef, dest_space, &dest_space->defs);
|
||||||
|
work_defrefs[num_work_defrefs++] = ref;
|
||||||
|
process_def (ref, dest_space);
|
||||||
|
}
|
||||||
|
dest_space->num_defs += count;
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Add all the strings in the strings space to the working qfo.
|
||||||
|
|
||||||
|
\param strings The strings space of the qfo being linked.
|
||||||
|
*/
|
||||||
static void
|
static void
|
||||||
add_qfo_strings (qfo_mspace_t *strings)
|
add_qfo_strings (qfo_mspace_t *strings)
|
||||||
{
|
{
|
||||||
|
@ -137,6 +317,10 @@ add_qfo_strings (qfo_mspace_t *strings)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Add the code in the code space to the working qfo.
|
||||||
|
|
||||||
|
\param code The code space of the qfo being linked.
|
||||||
|
*/
|
||||||
static void
|
static void
|
||||||
add_code (qfo_mspace_t *code)
|
add_code (qfo_mspace_t *code)
|
||||||
{
|
{
|
||||||
|
@ -145,6 +329,10 @@ add_code (qfo_mspace_t *code)
|
||||||
work->spaces[qfo_code_space].data_size = work_code->size;
|
work->spaces[qfo_code_space].data_size = work_code->size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Add the data in a data space to the working qfo.
|
||||||
|
|
||||||
|
\param data A data space of the qfo being linked.
|
||||||
|
*/
|
||||||
static void
|
static void
|
||||||
add_data (int space, qfo_mspace_t *data)
|
add_data (int space, qfo_mspace_t *data)
|
||||||
{
|
{
|
||||||
|
@ -163,93 +351,33 @@ add_data (int space, qfo_mspace_t *data)
|
||||||
work->spaces[space].data_size = work_spaces[space]->size;
|
work->spaces[space].data_size = work_spaces[space]->size;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define QFOSTR(q,s) ((q)->spaces[qfo_strings_space].d.strings + (s))
|
/** Add a defspace to the working qfo.
|
||||||
#define WORKSTR(q,s) QFOSTR (work, s)
|
|
||||||
|
|
||||||
|
\param qfo The qfo being linked.
|
||||||
|
\param space The defspace from \a qfo that will be added to the working
|
||||||
|
qfo.
|
||||||
|
*/
|
||||||
static void
|
static void
|
||||||
update_relocs (qfo_t *qfo)
|
add_space (qfo_t *qfo, qfo_mspace_t *space)
|
||||||
{
|
{
|
||||||
int i;
|
qfo_mspace_t *ws;
|
||||||
qfo_reloc_t *reloc;
|
if (space->type != qfos_data)
|
||||||
|
internal_error (0, "bad space type for add_space (): %d", space->type);
|
||||||
for (reloc = qfo->relocs, i = 0; i < qfo->num_relocs; i++, reloc++) {
|
space->id = work->num_spaces++; // so the space in work can be found
|
||||||
if (!reloc->space) {
|
work->spaces = realloc (work->spaces,
|
||||||
// code space is implied
|
work->num_spaces * sizeof (qfo_mspace_t));
|
||||||
reloc->offset += work->spaces[qfo_code_space].data_size;
|
ws = &work->spaces[space->id];
|
||||||
} else if (reloc->space < 0 || reloc->space >= qfo->num_spaces) {
|
memset (ws, 0, sizeof (qfo_mspace_t));
|
||||||
//FIXME proper diagnostic
|
ws->type = space->type;
|
||||||
fprintf (stderr, "bad reloc space: %d", reloc->space);
|
if (space->num_defs)
|
||||||
reloc->type = rel_none;
|
add_defs (qfo, space, ws);
|
||||||
} else if (reloc->space < qfo_num_spaces) {
|
if (space->d.data) {
|
||||||
reloc->offset += work->spaces[reloc->space].data_size;
|
int size = space->data_size * sizeof (pr_type_t);
|
||||||
} else {
|
ws->d.data = malloc (size);
|
||||||
reloc->space += work->num_spaces;
|
memcpy (ws->d.data, space->d.data, size);
|
||||||
}
|
|
||||||
reloc->target += work->num_defs; //FIXME wrong
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
update_defs (qfo_t *qfo)
|
|
||||||
{
|
|
||||||
int space;
|
|
||||||
int i;
|
|
||||||
qfo_def_t *def;
|
|
||||||
|
|
||||||
for (space = 0; space < qfo->num_spaces; space++) {
|
|
||||||
if (space == qfo_type_space)
|
|
||||||
continue; // complicated. handle separately
|
|
||||||
for (def = qfo->spaces[space].defs, i = 0;
|
|
||||||
i < qfo->spaces[space].num_defs; i++, def++) {
|
|
||||||
//XXX type handled later
|
|
||||||
def->name = add_string (QFOSTR (qfo, def->name));
|
|
||||||
if (space < qfo_num_spaces)
|
|
||||||
def->offset += work->spaces[space].data_size;
|
|
||||||
def->relocs += work->num_relocs;
|
|
||||||
def->file = add_string (QFOSTR (qfo, def->file));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
update_funcs (qfo_t *qfo)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
qfo_func_t *func;
|
|
||||||
|
|
||||||
for (func = qfo->funcs, i = 0; i < qfo->num_funcs; i++, func++) {
|
|
||||||
func->name = add_string (QFOSTR (qfo, func->name));
|
|
||||||
//XXX type handled later
|
|
||||||
func->file = add_string (QFOSTR (qfo, func->file));
|
|
||||||
if (func->code > 0)
|
|
||||||
func->code += work->spaces[qfo_code_space].data_size;
|
|
||||||
func->def += work->num_defs;
|
|
||||||
if (!func->locals_space) {
|
|
||||||
// no locals (builtin function?)
|
|
||||||
} else if (func->locals_space < qfo_num_spaces) {
|
|
||||||
//FIXME proper diagnostic
|
|
||||||
fprintf (stderr, "function with weird locals: setting to none\n");
|
|
||||||
func->locals_space = 0;
|
|
||||||
} else {
|
|
||||||
func->locals_space += work->num_spaces - qfo_num_spaces;
|
|
||||||
}
|
|
||||||
func->line_info += work->num_lines;
|
|
||||||
func->relocs += work->num_relocs;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
update_lines (qfo_t *qfo)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
pr_lineno_t *lineno;
|
|
||||||
|
|
||||||
for (lineno = qfo->lines, i = 0; i < qfo->num_lines; i++, lineno++) {
|
|
||||||
if (lineno->line)
|
|
||||||
lineno->fa.addr += work->spaces[qfo_code_space].data_size;
|
|
||||||
else
|
|
||||||
lineno->fa.func += work->num_funcs;
|
|
||||||
}
|
}
|
||||||
|
ws->data_size = space->data_size;
|
||||||
|
ws->id = space->id;
|
||||||
}
|
}
|
||||||
|
|
||||||
static __attribute__ ((used)) void
|
static __attribute__ ((used)) void
|
||||||
|
@ -258,12 +386,29 @@ define_def (const char *name, etype_t basic_type, const char *full_type,
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Initialize the linker state.
|
||||||
|
*/
|
||||||
void
|
void
|
||||||
linker_begin (void)
|
linker_begin (void)
|
||||||
{
|
{
|
||||||
|
linker_current_file = dstring_newstr ();
|
||||||
|
|
||||||
|
extern_defs = Hash_NewTable (16381, defs_get_key, 0, 0);
|
||||||
|
defined_defs = Hash_NewTable (16381, defs_get_key, 0, 0);
|
||||||
|
|
||||||
|
extern_type_defs = Hash_NewTable (16381, defs_get_key, 0, 0);
|
||||||
|
defined_type_defs = Hash_NewTable (16381, defs_get_key, 0, 0);
|
||||||
|
|
||||||
work = qfo_new ();
|
work = qfo_new ();
|
||||||
work->spaces = calloc (qfo_num_spaces, sizeof (qfo_mspace_t));
|
work->spaces = calloc (qfo_num_spaces, sizeof (qfo_mspace_t));
|
||||||
work->num_spaces = qfo_num_spaces;
|
work->num_spaces = qfo_num_spaces;
|
||||||
|
work->spaces[qfo_null_space].type = qfos_null;
|
||||||
|
work->spaces[qfo_strings_space].type = qfos_string;
|
||||||
|
work->spaces[qfo_code_space].type = qfos_code;
|
||||||
|
work->spaces[qfo_near_data_space].type = qfos_data;
|
||||||
|
work->spaces[qfo_far_data_space].type = qfos_data;
|
||||||
|
work->spaces[qfo_entity_space].type = qfos_entity;
|
||||||
|
work->spaces[qfo_type_space].type = qfos_type;
|
||||||
|
|
||||||
// adding data will take care of connecting the work qfo spaces with
|
// adding data will take care of connecting the work qfo spaces with
|
||||||
// the actual space data
|
// the actual space data
|
||||||
|
@ -275,20 +420,185 @@ linker_begin (void)
|
||||||
work_type_data = defspace_new ();
|
work_type_data = defspace_new ();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
typedef int (*space_func) (qfo_t *qfo, qfo_mspace_t *space);
|
||||||
|
|
||||||
|
static int
|
||||||
|
process_null (qfo_t *qfo, qfo_mspace_t *space)
|
||||||
|
{
|
||||||
|
if (space->defs || space->num_defs || space->d.data || space->data_size
|
||||||
|
|| space->id) {
|
||||||
|
linker_error ("non-null null space");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
process_code (qfo_t *qfo, qfo_mspace_t *space)
|
||||||
|
{
|
||||||
|
if (space->defs || space->num_defs) {
|
||||||
|
linker_error ("defs in code space");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (space->id != qfo_code_space)
|
||||||
|
linker_warning ("hmm, unexpected code space. *shrug*");
|
||||||
|
add_code (space);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
process_data (qfo_t *qfo, qfo_mspace_t *space)
|
||||||
|
{
|
||||||
|
if (space->id == qfo_near_data_space) {
|
||||||
|
add_data (qfo_near_data_space, space);
|
||||||
|
} else if (space->id == qfo_far_data_space) {
|
||||||
|
add_data (qfo_far_data_space, space);
|
||||||
|
} else {
|
||||||
|
add_space (qfo, space);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
process_strings (qfo_t *qfo, qfo_mspace_t *space)
|
||||||
|
{
|
||||||
|
if (space->defs || space->num_defs) {
|
||||||
|
linker_error ("defs in strings space");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
add_qfo_strings (space);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
process_entity (qfo_t *qfo, qfo_mspace_t *space)
|
||||||
|
{
|
||||||
|
add_data (qfo_entity_space, space);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static pointer_t
|
||||||
|
transfer_type (qfo_t *qfo, qfo_mspace_t *space, pointer_t type_offset)
|
||||||
|
{
|
||||||
|
qfot_type_t *type;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
type = (qfot_type_t *) (char *) &space->d.data[type_offset];
|
||||||
|
if (type->ty < 0)
|
||||||
|
return type->t.class;
|
||||||
|
switch ((ty_type_e) type->ty) {
|
||||||
|
case ty_none:
|
||||||
|
if (type->t.type == ev_func) {
|
||||||
|
int count;
|
||||||
|
qfot_func_t *f = &type->t.func;
|
||||||
|
pointer_t *p;
|
||||||
|
count = f->num_params;
|
||||||
|
if (count < 0)
|
||||||
|
count = ~count; //ones complement
|
||||||
|
f->return_type = transfer_type (qfo, space, f->return_type);
|
||||||
|
for (i = 0, p = f->param_types; i < count; i++, p++)
|
||||||
|
*p = transfer_type (qfo, space, *p);
|
||||||
|
} else if (type->t.type == ev_pointer
|
||||||
|
|| type->t.type == ev_field) {
|
||||||
|
qfot_fldptr_t *fp = &type->t.fldptr;
|
||||||
|
fp->aux_type = transfer_type (qfo, space, fp->aux_type);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ty_struct:
|
||||||
|
case ty_union:
|
||||||
|
case ty_enum:
|
||||||
|
type->t.strct.tag = add_string (QFOSTR (qfo, type->t.strct.tag));
|
||||||
|
for (i = 0; i < type->t.strct.num_fields; i++) {
|
||||||
|
qfot_var_t *field = &type->t.strct.fields[i];
|
||||||
|
field->type = transfer_type (qfo, space, field->type);
|
||||||
|
field->name = add_string (QFOSTR (qfo, field->name));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ty_array:
|
||||||
|
type->t.array.type = transfer_type (qfo, space,
|
||||||
|
type->t.array.type);
|
||||||
|
break;
|
||||||
|
case ty_class:
|
||||||
|
//FIXME this is broken
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
type_offset = defspace_alloc_loc (work_type_data, type->size);
|
||||||
|
memcpy (work_type_data->data + type_offset, type,
|
||||||
|
type->size * sizeof (pr_type_t));
|
||||||
|
type->ty = -1;
|
||||||
|
type->t.class = type_offset;
|
||||||
|
return type_offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
process_type (qfo_t *qfo, qfo_mspace_t *space)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int size;
|
||||||
|
qfo_def_t *def;
|
||||||
|
qfo_def_t *type_def;
|
||||||
|
qfo_mspace_t *type_space;
|
||||||
|
qfot_type_t *type;
|
||||||
|
const char *name;
|
||||||
|
defref_t *ref;
|
||||||
|
pointer_t offset;
|
||||||
|
|
||||||
|
if (qfo_type_defs) {
|
||||||
|
linker_error ("type space already defined");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
qfo_type_defs = space;
|
||||||
|
type_space = &work->spaces[qfo_type_space];
|
||||||
|
size = (type_space->num_defs + space->num_defs) * sizeof (qfo_def_t);
|
||||||
|
type_space->defs = realloc (type_space->defs, size);
|
||||||
|
for (i = 0, def = space->defs; i < space->num_defs; i++, def++) {
|
||||||
|
name = QFOSTR (qfo, def->name);
|
||||||
|
type = (qfot_type_t *) (char *) &space->d.data[def->offset];
|
||||||
|
if ((ref = Hash_Find (defined_type_defs, name))) {
|
||||||
|
type->ty = -1;
|
||||||
|
type->t.class = REF (ref)->offset;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
offset = transfer_type (qfo, space, def->offset);
|
||||||
|
type_def = type_space->defs + type_space->num_defs++;
|
||||||
|
ref = get_defref (type_def, type_space, &type_space->defs);
|
||||||
|
Hash_Add (defined_type_defs, ref);
|
||||||
|
while ((ref = Hash_Del (extern_type_defs, name))) {
|
||||||
|
REF (ref)->flags = 0;
|
||||||
|
REF (ref)->offset = type_def->offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
size = type_space->num_defs * sizeof (qfo_def_t);
|
||||||
|
type_space->defs = realloc (type_space->defs, size);
|
||||||
|
|
||||||
|
type_space->d.data = work_type_data->data;
|
||||||
|
type_space->data_size = work_type_data->size;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
linker_add_qfo (qfo_t *qfo)
|
linker_add_qfo (qfo_t *qfo)
|
||||||
{
|
{
|
||||||
update_relocs (qfo);
|
static space_func funcs[] = {
|
||||||
update_defs (qfo);
|
process_null,
|
||||||
update_funcs (qfo);
|
process_code,
|
||||||
update_lines (qfo);
|
process_data,
|
||||||
|
process_strings,
|
||||||
|
process_entity,
|
||||||
|
process_type,
|
||||||
|
};
|
||||||
|
int i;
|
||||||
|
qfo_mspace_t *space;
|
||||||
|
|
||||||
add_qfo_strings (&qfo->spaces[qfo_strings_space]);
|
for (i = 0, space = qfo->spaces; i < qfo->num_spaces; i++, space++) {
|
||||||
add_code (&qfo->spaces[qfo_code_space]);
|
if (space->type < 0 || space->type > qfos_type) {
|
||||||
add_data (qfo_near_data_space, &qfo->spaces[qfo_near_data_space]);
|
linker_error ("bad space type");
|
||||||
add_data (qfo_far_data_space, &qfo->spaces[qfo_far_data_space]);
|
return 1;
|
||||||
add_data (qfo_entity_space, &qfo->spaces[qfo_entity_space]);
|
}
|
||||||
//FIXME handle type data
|
if (funcs[space->type] (qfo, space))
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
@ -296,9 +606,13 @@ linker_add_object_file (const char *filename)
|
||||||
{
|
{
|
||||||
qfo_t *qfo;
|
qfo_t *qfo;
|
||||||
|
|
||||||
|
dsprintf (linker_current_file, "%s", filename);
|
||||||
|
|
||||||
qfo = qfo_open (filename);
|
qfo = qfo_open (filename);
|
||||||
if (!qfo)
|
if (!qfo) {
|
||||||
|
linker_error ("error opening");
|
||||||
return 1;
|
return 1;
|
||||||
|
}
|
||||||
if (qfo->num_spaces < qfo_num_spaces
|
if (qfo->num_spaces < qfo_num_spaces
|
||||||
|| qfo->spaces[qfo_null_space].type != qfos_null
|
|| qfo->spaces[qfo_null_space].type != qfos_null
|
||||||
|| qfo->spaces[qfo_strings_space].type != qfos_string
|
|| qfo->spaces[qfo_strings_space].type != qfos_string
|
||||||
|
@ -307,8 +621,7 @@ linker_add_object_file (const char *filename)
|
||||||
|| qfo->spaces[qfo_far_data_space].type != qfos_data
|
|| qfo->spaces[qfo_far_data_space].type != qfos_data
|
||||||
|| qfo->spaces[qfo_entity_space].type != qfos_entity
|
|| qfo->spaces[qfo_entity_space].type != qfos_entity
|
||||||
|| qfo->spaces[qfo_type_space].type != qfos_type) {
|
|| qfo->spaces[qfo_type_space].type != qfos_type) {
|
||||||
//FIXME proper diagnostic
|
linker_error ("missing or mangled standard spaces");
|
||||||
fprintf (stderr, "%s: missing or mangled standard spaces", filename);
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -372,26 +685,30 @@ linker_add_lib (const char *libname)
|
||||||
QFile *f;
|
QFile *f;
|
||||||
qfo_t *qfo;
|
qfo_t *qfo;
|
||||||
|
|
||||||
|
dsprintf (linker_current_file, "%s(%s)", path_name,
|
||||||
|
pack->files[i].name);
|
||||||
f = Qsubopen (path_name, pack->files[i].filepos,
|
f = Qsubopen (path_name, pack->files[i].filepos,
|
||||||
pack->files[i].filelen, 1);
|
pack->files[i].filelen, 1);
|
||||||
qfo = qfo_read (f);
|
qfo = qfo_read (f);
|
||||||
Qclose (f);
|
Qclose (f);
|
||||||
|
|
||||||
if (!qfo)
|
if (!qfo) {
|
||||||
|
linker_error ("error opening");
|
||||||
return 1;
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
for (j = 0; j < qfo->num_defs; j++) {
|
for (j = 0; j < qfo->num_defs; j++) {
|
||||||
// qfo_def_t *def = qfo->defs + j;
|
qfo_def_t *def = qfo->defs + j;
|
||||||
// if ((def->flags & QFOD_GLOBAL)
|
if ((def->flags & QFOD_GLOBAL)
|
||||||
// && !(def->flags & QFOD_EXTERNAL)
|
&& !(def->flags & QFOD_EXTERNAL)
|
||||||
// && Hash_Find (extern_defs, qfo->strings + def->name)) {
|
&& Hash_Find (extern_defs, QFOSTR (qfo, def->name))) {
|
||||||
// if (options.verbosity >= 2)
|
if (options.verbosity >= 2)
|
||||||
// printf ("adding %s because of %s\n",
|
printf ("adding %s because of %s\n",
|
||||||
// pack->files[i].name, qfo->strings + def->name);
|
pack->files[i].name, QFOSTR (qfo, def->name));
|
||||||
// linker_add_qfo (qfo);
|
linker_add_qfo (qfo);
|
||||||
// did_something = 1;
|
did_something = 1;
|
||||||
// break;
|
break;
|
||||||
// }
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
qfo_delete (qfo);
|
qfo_delete (qfo);
|
||||||
|
@ -559,3 +876,36 @@ def_warning (qfo_def_t *def, const char *fmt, ...)
|
||||||
// pr.strings = strings;
|
// pr.strings = strings;
|
||||||
warning (0, "%s", string->str);
|
warning (0, "%s", string->str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
linker_warning (const char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
|
||||||
|
fprintf (stderr, "%s: warning: ", linker_current_file->str);
|
||||||
|
|
||||||
|
va_start (args, fmt);
|
||||||
|
vfprintf (stderr, fmt, args);
|
||||||
|
va_end (args);
|
||||||
|
|
||||||
|
fputs ("\n", stderr);
|
||||||
|
|
||||||
|
if (options.warnings.promote)
|
||||||
|
pr.error_count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
linker_error (const char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
|
||||||
|
fprintf (stderr, "%s: ", linker_current_file->str);
|
||||||
|
|
||||||
|
va_start (args, fmt);
|
||||||
|
vfprintf (stderr, fmt, args);
|
||||||
|
va_end (args);
|
||||||
|
|
||||||
|
fputs ("\n", stderr);
|
||||||
|
|
||||||
|
pr.error_count++;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue