mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-23 04:42:32 +00:00
First stage of the linker rewrite.
Strings, code and data spaces are "merged". Various offsets are updated. Still to do: o Merge reloc, def, function and line data. o Merge type data. o Update def and function type pointers. o Resolve external defs and check for duplicate defs. o Perform relocations. o anything else I've forgotten :)
This commit is contained in:
parent
74497f00e1
commit
66b255afbf
2 changed files with 199 additions and 622 deletions
|
@ -70,26 +70,10 @@ static __attribute__ ((used)) const char rcsid[] = "$Id$";
|
|||
#include "strpool.h"
|
||||
#include "type.h"
|
||||
|
||||
#define Xgroup(X)\
|
||||
typedef struct {\
|
||||
qfo_##X##_t *X##s;\
|
||||
int num_##X##s;\
|
||||
int max_##X##s;\
|
||||
} X##group_t;
|
||||
|
||||
Xgroup(def) // defgroup_t
|
||||
Xgroup(reloc) // relocgroup_t
|
||||
Xgroup(func) // funcgroup_t
|
||||
|
||||
typedef struct path_s {
|
||||
struct path_s *next;
|
||||
const char *path;
|
||||
} path_t;
|
||||
|
||||
typedef union defref_s {
|
||||
int def;
|
||||
union defref_s *next;
|
||||
} defref_t;
|
||||
static void def_error (qfo_def_t *def, const char *fmt, ...)
|
||||
__attribute__ ((used, format (printf, 2, 3)));
|
||||
static void def_warning (qfo_def_t *def, const char *fmt, ...)
|
||||
__attribute__ ((used, format (printf, 2, 3)));
|
||||
|
||||
typedef struct builtin_sym_s {
|
||||
const char *name;
|
||||
|
@ -97,7 +81,7 @@ typedef struct builtin_sym_s {
|
|||
unsigned flags;
|
||||
} builtin_sym_t;
|
||||
|
||||
static builtin_sym_t builtin_symbols[] = {
|
||||
static builtin_sym_t builtin_symbols[] __attribute__ ((used)) = {
|
||||
{".zero", &type_zero, QFOD_NOSAVE},
|
||||
{".return", &type_param, QFOD_NOSAVE},
|
||||
{".param_0", &type_param, QFOD_NOSAVE},
|
||||
|
@ -110,631 +94,199 @@ static builtin_sym_t builtin_symbols[] = {
|
|||
{".param_7", &type_param, QFOD_NOSAVE},
|
||||
};
|
||||
|
||||
static defref_t *free_defrefs;
|
||||
static qfo_t *work;
|
||||
static strpool_t *work_strings;
|
||||
static codespace_t *work_code;
|
||||
static defspace_t *work_near_data;
|
||||
static defspace_t *work_far_data;
|
||||
static defspace_t *work_entity_data;
|
||||
static defspace_t *work_type_data;
|
||||
|
||||
static hashtab_t *extern_defs;
|
||||
static hashtab_t *defined_defs;
|
||||
static hashtab_t *field_defs;
|
||||
/** Add a string to the working qfo string pool.
|
||||
|
||||
static codespace_t *code;
|
||||
static defspace_t *data;
|
||||
static defspace_t *far_data;
|
||||
static defspace_t *entity;
|
||||
static strpool_t *strings;
|
||||
static strpool_t *type_strings;
|
||||
static relocgroup_t relocs, final_relocs;
|
||||
static defgroup_t global_defs, local_defs, fields, defs;
|
||||
static funcgroup_t funcs;
|
||||
static struct {
|
||||
pr_lineno_t *lines;
|
||||
int num_lines;
|
||||
int max_lines;
|
||||
} lines;
|
||||
static int code_base;
|
||||
static int data_base;
|
||||
static int far_data_base;
|
||||
static int entity_base;
|
||||
static int reloc_base;
|
||||
static int func_base;
|
||||
static int line_base;
|
||||
If the string is already in the string pool, the already existing string
|
||||
index will be returned instead of adding a second copy of the string.
|
||||
|
||||
static path_t *path_head;
|
||||
static path_t **path_tail = &path_head;
|
||||
The strings space in the working qfo is kept up to date.
|
||||
|
||||
#define DATA(x) (data->data + (x))
|
||||
#define STRING(x) (strings->strings + (x))
|
||||
#define TYPE_STRING(x) (type_strings->strings + (x))
|
||||
|
||||
#define Xgroup_add(X)\
|
||||
static void \
|
||||
X##group_add_##X##s (X##group_t *X##group, qfo_##X##_t *X##s, int num_##X##s)\
|
||||
{\
|
||||
if (X##group->num_##X##s + num_##X##s > X##group->max_##X##s) {\
|
||||
X##group->max_##X##s = RUP (X##group->num_##X##s + num_##X##s, 16384);\
|
||||
X##group->X##s = realloc (X##group->X##s,\
|
||||
X##group->max_##X##s * sizeof (qfo_##X##_t));\
|
||||
}\
|
||||
memcpy (X##group->X##s + X##group->num_##X##s, X##s,\
|
||||
num_##X##s * sizeof (qfo_##X##_t));\
|
||||
X##group->num_##X##s += num_##X##s;\
|
||||
}
|
||||
|
||||
Xgroup_add(def); // defgroup_add_defs
|
||||
Xgroup_add(reloc); // relocgroup_add_relocs
|
||||
Xgroup_add(func); // funcgroup_add_funcs
|
||||
|
||||
static void def_error (qfo_def_t *def, const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
|
||||
//static void def_warning (qfo_def_t *def, const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
|
||||
|
||||
static defref_t *
|
||||
get_defref (qfo_def_t *def, defgroup_t *defgroup)
|
||||
{
|
||||
defref_t *defref;
|
||||
|
||||
ALLOC (16384, defref_t, defrefs, defref);
|
||||
defref->def = def - defgroup->defs;
|
||||
return defref;
|
||||
}
|
||||
|
||||
static qfo_def_t *
|
||||
deref_def (defref_t *defref, defgroup_t *defgroup)
|
||||
{
|
||||
return defgroup->defs + defref->def;
|
||||
}
|
||||
|
||||
static const char *
|
||||
defs_get_key (void *_defref, void *_defgroup)
|
||||
{
|
||||
defref_t *defref = (defref_t *) _defref;
|
||||
defgroup_t *defgroup = (defgroup_t *) _defgroup;
|
||||
qfo_def_t *def = deref_def (defref, defgroup);
|
||||
|
||||
return STRING (def->name);
|
||||
}
|
||||
|
||||
static void
|
||||
add_strings (qfo_t *qfo)
|
||||
{
|
||||
// int i;
|
||||
|
||||
// for (i = 0; i < qfo->strings_size; i += strlen (qfo->strings + i) + 1)
|
||||
// strpool_addstr (strings, qfo->strings + i);
|
||||
}
|
||||
|
||||
static void
|
||||
add_relocs (qfo_t *qfo)
|
||||
{
|
||||
int i;
|
||||
|
||||
relocgroup_add_relocs (&relocs, qfo->relocs, qfo->num_relocs);
|
||||
for (i = reloc_base; i < relocs.num_relocs; i++) {
|
||||
qfo_reloc_t *reloc = relocs.relocs + i;
|
||||
switch ((reloc_type)reloc->type) {
|
||||
case rel_none:
|
||||
break;
|
||||
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->offset += code_base;
|
||||
break;
|
||||
case rel_op_a_op:
|
||||
case rel_op_b_op:
|
||||
case rel_op_c_op:
|
||||
// these are relative and fixed up before the .qfo is written
|
||||
break;
|
||||
case rel_def_op:
|
||||
reloc->offset += data_base;
|
||||
reloc->def += code_base;
|
||||
break;
|
||||
case rel_def_func:
|
||||
reloc->offset += data_base;
|
||||
reloc->def += func_base;
|
||||
break;
|
||||
case rel_def_def:
|
||||
case rel_def_def_ofs:
|
||||
reloc->offset += data_base;
|
||||
break;
|
||||
case rel_def_string:
|
||||
reloc->offset += data_base;
|
||||
// DATA (reloc->offset)->string_var =
|
||||
// strpool_addstr (strings,
|
||||
// qfo->strings + DATA (reloc->offset)->string_var);
|
||||
break;
|
||||
case rel_def_field:
|
||||
case rel_def_field_ofs:
|
||||
//FIXME more?
|
||||
reloc->offset += data_base;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//static void
|
||||
//linker_type_mismatch (qfo_def_t *def, qfo_def_t *d)
|
||||
//{
|
||||
// def_error (def, "type mismatch for `%s' `%s'",
|
||||
// STRING (def->name),
|
||||
// TYPE_STRING (def->full_type));
|
||||
// def_error (d, "previous definition `%s'", TYPE_STRING (d->full_type));
|
||||
//}
|
||||
|
||||
static void
|
||||
process_def (qfo_def_t *def)
|
||||
{
|
||||
defref_t *_d;
|
||||
qfo_def_t *d;
|
||||
|
||||
if (def->flags & QFOD_EXTERNAL) {
|
||||
if (!def->num_relocs)
|
||||
return;
|
||||
if ((_d = Hash_Find (defined_defs, STRING (def->name)))) {
|
||||
d = deref_def (_d, &global_defs);
|
||||
// if (d->full_type != def->full_type) {
|
||||
// linker_type_mismatch (def, d);
|
||||
// return;
|
||||
// }
|
||||
def->offset = d->offset;
|
||||
def->flags = d->flags;
|
||||
Hash_Add (defined_defs, get_defref (def, &global_defs));
|
||||
} else {
|
||||
Hash_Add (extern_defs, get_defref (def, &global_defs));
|
||||
}
|
||||
} else if (def->flags & QFOD_GLOBAL) {
|
||||
if ((_d = Hash_Find (defined_defs, STRING (def->name)))) {
|
||||
d = deref_def (_d, &global_defs);
|
||||
if (d->flags & QFOD_SYSTEM) {
|
||||
// int i, size;
|
||||
|
||||
// if (d->full_type != def->full_type) {
|
||||
// linker_type_mismatch (def, d);
|
||||
// return;
|
||||
// }
|
||||
d->flags &= ~QFOD_SYSTEM;
|
||||
d->flags |= def->flags & (QFOD_INITIALIZED | QFOD_CONSTANT);
|
||||
// size = type_size (parse_type (TYPE_STRING (d->full_type)));
|
||||
// memcpy (DATA (d->offset), DATA (def->offset),
|
||||
// size * sizeof (pr_type_t));
|
||||
// for (i = 0; i < relocs.num_relocs; i++) {
|
||||
// qfo_reloc_t *reloc = relocs.relocs + i;
|
||||
// if (reloc->type >= rel_def_def
|
||||
// && reloc->type <= rel_def_field)
|
||||
// if (reloc->offset == def->offset)
|
||||
// reloc->offset = d->offset;
|
||||
// }
|
||||
def->offset = d->offset;
|
||||
def->flags = d->flags;
|
||||
} else {
|
||||
def_error (def, "%s redefined", STRING (def->name));
|
||||
def_error (d, "previous definition");
|
||||
}
|
||||
}
|
||||
while ((_d = Hash_Del (extern_defs, STRING (def->name)))) {
|
||||
Hash_Add (defined_defs, _d);
|
||||
d = deref_def (_d, &global_defs);
|
||||
// if (d->full_type != def->full_type) {
|
||||
// linker_type_mismatch (def, d);
|
||||
// continue;
|
||||
// }
|
||||
d->offset = def->offset;
|
||||
d->flags = def->flags;
|
||||
}
|
||||
Hash_Add (defined_defs, get_defref (def, &global_defs));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
process_field (qfo_def_t *def)
|
||||
{
|
||||
defref_t *_d;
|
||||
qfo_def_t *field_def;
|
||||
pr_type_t *var = DATA (def->offset);
|
||||
|
||||
if (strcmp (STRING (def->name), ".imm")) { //FIXME better test
|
||||
if ((_d = Hash_Find (field_defs, STRING (def->name)))) {
|
||||
field_def = deref_def (_d, &fields);
|
||||
def_error (def, "%s redefined", STRING (def->name));
|
||||
def_error (field_def, "previous definition");
|
||||
}
|
||||
}
|
||||
defgroup_add_defs (&fields, def, 1);
|
||||
field_def = fields.defs + fields.num_defs - 1;
|
||||
field_def->offset = var->integer_var + entity_base;
|
||||
Hash_Add (field_defs, get_defref (field_def, &fields));
|
||||
}
|
||||
|
||||
static void
|
||||
fixup_def (qfo_t *qfo, qfo_def_t *def, int def_num)
|
||||
{
|
||||
pr_int_t i;
|
||||
qfo_reloc_t *reloc;
|
||||
// qfo_func_t *func;
|
||||
// const char *full_type = QFO_TYPESTR (qfo, def->full_type);
|
||||
// const char *name = QFO_GETSTR (qfo, def->name);
|
||||
|
||||
// def->full_type = strpool_addstr (type_strings, full_type);
|
||||
// def->name = strpool_addstr (strings, name);
|
||||
|
||||
def->relocs += reloc_base;
|
||||
for (i = 0, reloc = relocs.relocs + def->relocs;
|
||||
i < def->num_relocs;
|
||||
i++, reloc++)
|
||||
reloc->def = def_num;
|
||||
|
||||
// def->file = strpool_addstr (strings, qfo->strings + def->file);
|
||||
|
||||
if ((def->flags & (QFOD_LOCAL | QFOD_ABSOLUTE)))
|
||||
return;
|
||||
if (!(def->flags & QFOD_EXTERNAL)) {
|
||||
def->offset += data_base;
|
||||
// if (def->flags & QFOD_INITIALIZED) {
|
||||
// pr_type_t *var = DATA (def->offset);
|
||||
// switch (def->basic_type) {
|
||||
// case ev_func:
|
||||
// if (var->func_var) {
|
||||
// func = funcs.funcs + var->func_var - 1;
|
||||
// func->def = def_num;
|
||||
// }
|
||||
// break;
|
||||
// case ev_field:
|
||||
// process_field (def);
|
||||
// break;
|
||||
// default:
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
process_def (def);
|
||||
}
|
||||
|
||||
/* Transfer global defs from the object file. Local defs are skipped because
|
||||
they will be handled by add_funcs.
|
||||
\param str The string to add.
|
||||
\return The string offset in the working qfo string pool.
|
||||
*/
|
||||
static void
|
||||
add_defs (qfo_t *qfo)
|
||||
static string_t
|
||||
add_string (const char *str)
|
||||
{
|
||||
qfo_def_t *s, *e;
|
||||
string_t new;
|
||||
new = strpool_addstr (work_strings, str);
|
||||
work->spaces[qfo_strings_space].d.strings = work_strings->strings;
|
||||
work->spaces[qfo_strings_space].data_size = work_strings->size;
|
||||
return new;
|
||||
}
|
||||
|
||||
for (s = e = qfo->defs; s - qfo->defs < qfo->num_defs; s = e) {
|
||||
int def_num = global_defs.num_defs;
|
||||
qfo_def_t *d;
|
||||
// find the end of the current chunk of global defs
|
||||
while (e - qfo->defs < qfo->num_defs && !(e->flags & QFOD_LOCAL))
|
||||
e++;
|
||||
defgroup_add_defs (&global_defs, s, e - s);
|
||||
for (d = global_defs.defs + def_num; def_num < global_defs.num_defs;
|
||||
d++, def_num++)
|
||||
fixup_def (qfo, d, def_num);
|
||||
// find the beginning of the next chunk of global defs
|
||||
while (e - qfo->defs < qfo->num_defs && (e->flags & QFOD_LOCAL))
|
||||
e++;
|
||||
static void
|
||||
add_qfo_strings (qfo_mspace_t *strings)
|
||||
{
|
||||
const char *str = strings->d.strings;
|
||||
|
||||
while (str - strings->d.strings < strings->data_size) {
|
||||
add_string (str);
|
||||
while (str - strings->d.strings < strings->data_size && *str)
|
||||
str++;
|
||||
str++; // advance past the terminating nul
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
add_funcs (qfo_t *qfo)
|
||||
add_code (qfo_mspace_t *code)
|
||||
{
|
||||
codespace_addcode (work_code, code->d.code, code->data_size);
|
||||
work->spaces[qfo_code_space].d.code = work_code->code;
|
||||
work->spaces[qfo_code_space].data_size = work_code->size;
|
||||
}
|
||||
|
||||
static void
|
||||
add_data (int space, qfo_mspace_t *data)
|
||||
{
|
||||
defspace_t *work_spaces[qfo_num_spaces] = {
|
||||
0, 0, 0,
|
||||
work_near_data,
|
||||
work_far_data,
|
||||
work_entity_data,
|
||||
0,
|
||||
};
|
||||
|
||||
if (space < 0 || space >= qfo_num_spaces || !work_spaces[space])
|
||||
internal_error (0, "bad space for add_data (): %d", space);
|
||||
defspace_add_data (work_spaces[space], data->d.data, data->data_size);
|
||||
work->spaces[space].d.data = work_spaces[space]->data;
|
||||
work->spaces[space].data_size = work_spaces[space]->size;
|
||||
}
|
||||
|
||||
#define QFOSTR(q,s) ((q)->spaces[qfo_strings_space].d.strings + (s))
|
||||
#define WORKSTR(q,s) QFOSTR (work, s)
|
||||
|
||||
static void
|
||||
update_relocs (qfo_t *qfo)
|
||||
{
|
||||
int i;
|
||||
|
||||
funcgroup_add_funcs (&funcs, qfo->funcs, qfo->num_funcs);
|
||||
for (i = func_base; i < funcs.num_funcs; i++) {
|
||||
qfo_func_t *func = funcs.funcs + i;
|
||||
// func->name = strpool_addstr (strings, qfo->strings + func->name);
|
||||
// func->file = strpool_addstr (strings, qfo->strings + func->file);
|
||||
if (func->code)
|
||||
func->code += code_base;
|
||||
// if (func->num_local_defs) {
|
||||
// int def_num = local_defs.num_defs;
|
||||
// qfo_def_t *d;
|
||||
// defgroup_add_defs (&local_defs, qfo->defs + func->local_defs,
|
||||
// func->num_local_defs);
|
||||
// func->local_defs = def_num;
|
||||
// for (d = local_defs.defs + def_num; def_num < local_defs.num_defs;
|
||||
// d++, def_num++)
|
||||
// fixup_def (qfo, d, def_num);
|
||||
// }
|
||||
if (func->line_info)
|
||||
func->line_info += line_base;
|
||||
func->relocs += reloc_base;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
add_lines (qfo_t *qfo)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (lines.num_lines + qfo->num_lines > lines.max_lines) {
|
||||
lines.max_lines = RUP (lines.num_lines + qfo->num_lines, 16384);
|
||||
lines.lines = realloc (lines.lines,
|
||||
lines.max_lines * sizeof (pr_lineno_t));
|
||||
}
|
||||
lines.num_lines += qfo->num_lines;
|
||||
memcpy (lines.lines + line_base, qfo->lines,
|
||||
qfo->num_lines * sizeof (pr_lineno_t));
|
||||
for (i = line_base; i < lines.num_lines; i++) {
|
||||
pr_lineno_t *line = lines.lines + i;
|
||||
if (line->line)
|
||||
line->fa.addr += code_base;
|
||||
else
|
||||
line->fa.func += func_base;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
fixup_relocs (void)
|
||||
{
|
||||
defref_t *_d;
|
||||
qfo_reloc_t *reloc;
|
||||
qfo_def_t *def, *field_def;
|
||||
// qfo_func_t *func;
|
||||
|
||||
for (reloc = qfo->relocs, i = 0; i < qfo->num_relocs; i++, reloc++) {
|
||||
if (!reloc->space) {
|
||||
// code space is implied
|
||||
reloc->offset += work->spaces[qfo_code_space].data_size;
|
||||
} else if (reloc->space < 0 || reloc->space >= qfo->num_spaces) {
|
||||
//FIXME proper diagnostic
|
||||
fprintf (stderr, "bad reloc space: %d", reloc->space);
|
||||
reloc->type = rel_none;
|
||||
} else if (reloc->space < qfo_num_spaces) {
|
||||
reloc->offset += work->spaces[reloc->space].data_size;
|
||||
} else {
|
||||
reloc->space += work->num_spaces;
|
||||
}
|
||||
reloc->def += work->num_defs;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
update_defs (qfo_t *qfo)
|
||||
{
|
||||
int space;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < final_relocs.num_relocs; i++) {
|
||||
reloc = final_relocs.relocs + i;
|
||||
def = 0;
|
||||
switch ((reloc_type)reloc->type) {
|
||||
case rel_none:
|
||||
break;
|
||||
|
||||
case rel_op_a_def:
|
||||
case rel_op_b_def:
|
||||
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:
|
||||
case rel_def_field_ofs:
|
||||
def = defs.defs + reloc->def;
|
||||
if (def->flags & (QFOD_EXTERNAL | QFOD_LOCAL | QFOD_ABSOLUTE))
|
||||
continue;
|
||||
break;
|
||||
|
||||
case rel_def_op:
|
||||
case rel_op_a_op:
|
||||
case rel_op_b_op:
|
||||
case rel_op_c_op:
|
||||
case rel_def_func:
|
||||
case rel_def_string:
|
||||
break;
|
||||
}
|
||||
switch ((reloc_type)reloc->type) {
|
||||
case rel_none:
|
||||
break;
|
||||
case rel_op_a_def:
|
||||
code->code[reloc->offset].a = def->offset;
|
||||
break;
|
||||
case rel_op_b_def:
|
||||
code->code[reloc->offset].b = def->offset;
|
||||
break;
|
||||
case rel_op_c_def:
|
||||
code->code[reloc->offset].c = def->offset;
|
||||
break;
|
||||
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:
|
||||
case rel_def_field_ofs:
|
||||
break;
|
||||
case rel_def_op:
|
||||
DATA (reloc->offset)->integer_var = reloc->def;
|
||||
break;
|
||||
case rel_def_def:
|
||||
DATA (reloc->offset)->integer_var = def->offset;
|
||||
break;
|
||||
case rel_def_func:
|
||||
DATA (reloc->offset)->func_var = reloc->def + 1;
|
||||
break;
|
||||
case rel_def_string:
|
||||
break;
|
||||
case rel_def_field:
|
||||
_d = Hash_Find (field_defs, STRING (def->name));
|
||||
if (_d) { // null if not initialized
|
||||
field_def = deref_def (_d, &fields);
|
||||
DATA (reloc->offset)->integer_var = field_def->offset;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < defs.num_defs; i++) {
|
||||
def = defs.defs + i;
|
||||
// if (def->basic_type == ev_func
|
||||
// && (def->flags & QFOD_INITIALIZED)
|
||||
// && !(def->flags & (QFOD_LOCAL | QFOD_EXTERNAL | QFOD_ABSOLUTE))) {
|
||||
// pr_type_t *var = DATA (def->offset);
|
||||
// if (var->func_var) {
|
||||
// func = funcs.funcs + var->func_var - 1;
|
||||
// func->def = i;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
move_def (hashtab_t *deftab, qfo_def_t *d)
|
||||
{
|
||||
defref_t *_d;
|
||||
qfo_def_t *def;
|
||||
int def_num = defs.num_defs;
|
||||
pr_int_t j;
|
||||
|
||||
defgroup_add_defs (&defs, d, 1);
|
||||
def = defs.defs + def_num;
|
||||
def->relocs = final_relocs.num_relocs;
|
||||
relocgroup_add_relocs (&final_relocs, relocs.relocs + d->relocs,
|
||||
d->num_relocs);
|
||||
for (j = 0; j < d->num_relocs; j++) {
|
||||
relocs.relocs[d->relocs + j].type = rel_none;
|
||||
final_relocs.relocs[def->relocs + j].def = def_num;
|
||||
}
|
||||
// if ((d->flags & QFOD_CONSTANT) && d->basic_type == ev_func) {
|
||||
// qfo_func_t *func;
|
||||
// pr_type_t *var = DATA (d->offset);
|
||||
|
||||
// if (var->func_var) {
|
||||
// func = funcs.funcs + var->func_var - 1;
|
||||
// func->def = def_num;
|
||||
// }
|
||||
// }
|
||||
if (deftab) {
|
||||
while ((_d = Hash_Del (deftab, STRING (def->name)))) {
|
||||
int def_relocs;
|
||||
d = deref_def (_d, &global_defs);
|
||||
relocgroup_add_relocs (&final_relocs, relocs.relocs + d->relocs,
|
||||
d->num_relocs);
|
||||
def_relocs = def->relocs + def->num_relocs;
|
||||
def->num_relocs += d->num_relocs;
|
||||
for (j = 0; j < d->num_relocs; j++) {
|
||||
relocs.relocs[d->relocs + j].type = rel_none;
|
||||
final_relocs.relocs[def_relocs + j].def = def_num;
|
||||
}
|
||||
memset (d, 0, sizeof (*d));
|
||||
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
|
||||
merge_defgroups (void)
|
||||
update_funcs (qfo_t *qfo)
|
||||
{
|
||||
int local_base, i;
|
||||
pr_int_t j;
|
||||
qfo_def_t *def;
|
||||
defref_t *d;
|
||||
int i;
|
||||
qfo_func_t *func;
|
||||
static qfo_def_t null_def;
|
||||
|
||||
for (i = 0; i < global_defs.num_defs; i++) {
|
||||
const char *name;
|
||||
def = global_defs.defs + i;
|
||||
if (memcmp (def, &null_def, sizeof (*def)) == 0)
|
||||
continue;
|
||||
name = STRING (def->name);
|
||||
if ((d = Hash_Del (defined_defs, name)))
|
||||
move_def (defined_defs, deref_def (d, &global_defs));
|
||||
else if ((d = Hash_Del (extern_defs, name)))
|
||||
move_def (extern_defs, deref_def (d, &global_defs));
|
||||
else if (!(def->flags & (QFOD_GLOBAL | QFOD_EXTERNAL)))
|
||||
move_def (0, def);
|
||||
}
|
||||
local_base = defs.num_defs;
|
||||
for (i = 0; i < local_defs.num_defs; i++) {
|
||||
move_def (0, local_defs.defs + i);
|
||||
}
|
||||
for (i = 0; i < funcs.num_funcs; i++) {
|
||||
int r = final_relocs.num_relocs;
|
||||
func = funcs.funcs + i;
|
||||
// func->local_defs += local_base;
|
||||
relocgroup_add_relocs (&final_relocs, relocs.relocs + func->relocs,
|
||||
func->num_relocs);
|
||||
for (j = 0; j < func->num_relocs; j++)
|
||||
relocs.relocs[func->relocs + j].type = rel_none;
|
||||
func->relocs = r;
|
||||
}
|
||||
for (i = 0; i < relocs.num_relocs; i = j) {
|
||||
j = i;
|
||||
while (j < relocs.num_relocs && relocs.relocs[j].type != rel_none)
|
||||
j++;
|
||||
relocgroup_add_relocs (&final_relocs, relocs.relocs + i, j - i);
|
||||
while (j < relocs.num_relocs && relocs.relocs[j].type == rel_none)
|
||||
j++;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
static __attribute__ ((used)) void
|
||||
define_def (const char *name, etype_t basic_type, const char *full_type,
|
||||
unsigned flags, int size, int v)
|
||||
{
|
||||
qfo_def_t d;
|
||||
pr_type_t *val = calloc (size, sizeof (pr_type_t));
|
||||
|
||||
val->integer_var = v;
|
||||
|
||||
memset (&d, 0, sizeof (d));
|
||||
|
||||
// d.basic_type = basic_type;
|
||||
// d.full_type = strpool_addstr (type_strings, full_type);
|
||||
d.name = strpool_addstr (strings, name);
|
||||
d.offset = data->size;
|
||||
if (basic_type == ev_field) {
|
||||
d.relocs = relocs.num_relocs;
|
||||
d.num_relocs = 1;
|
||||
}
|
||||
d.flags = QFOD_GLOBAL | flags;
|
||||
|
||||
defspace_add_data (data, val, size);
|
||||
defgroup_add_defs (&global_defs, &d, 1);
|
||||
process_def (global_defs.defs + global_defs.num_defs - 1);
|
||||
|
||||
if (basic_type == ev_field) {
|
||||
int def_num = global_defs.num_defs - 1;
|
||||
qfo_def_t *def = global_defs.defs + def_num;
|
||||
qfo_reloc_t rel = {def->offset, rel_def_field, def_num};
|
||||
relocgroup_add_relocs (&relocs, &rel, 1);
|
||||
process_field (def);
|
||||
}
|
||||
free (val);
|
||||
}
|
||||
|
||||
void
|
||||
linker_begin (void)
|
||||
{
|
||||
size_t i;
|
||||
work = qfo_new ();
|
||||
work->spaces = calloc (qfo_num_spaces, sizeof (qfo_mspace_t));
|
||||
work->num_spaces = qfo_num_spaces;
|
||||
|
||||
extern_defs = Hash_NewTable (16381, defs_get_key, 0, &global_defs);
|
||||
defined_defs = Hash_NewTable (16381, defs_get_key, 0, &global_defs);
|
||||
field_defs = Hash_NewTable (16381, defs_get_key, 0, &fields);
|
||||
code = codespace_new ();
|
||||
data = new_defspace ();
|
||||
far_data = new_defspace ();
|
||||
entity = new_defspace ();
|
||||
strings = strpool_new ();
|
||||
type_strings = strpool_new ();
|
||||
|
||||
pr.strings = strings;
|
||||
if (!options.partial_link) {
|
||||
dstring_t *encoding = dstring_new ();
|
||||
|
||||
for (i = 0;
|
||||
i < sizeof (builtin_symbols) / sizeof (builtin_symbols[0]);
|
||||
i++) {
|
||||
etype_t basic_type = builtin_symbols[i].type->type;
|
||||
int size = type_size (builtin_symbols[i].type);
|
||||
|
||||
dstring_clearstr (encoding);
|
||||
encode_type (encoding, builtin_symbols[i].type);
|
||||
define_def (builtin_symbols[i].name, basic_type, encoding->str,
|
||||
builtin_symbols[i].flags, size, 0);
|
||||
}
|
||||
}
|
||||
// adding data will take care of connecting the work qfo spaces with
|
||||
// the actual space data
|
||||
work_strings = strpool_new ();
|
||||
work_code = codespace_new ();
|
||||
work_near_data = new_defspace();
|
||||
work_far_data = new_defspace();
|
||||
work_entity_data = new_defspace();
|
||||
work_type_data = new_defspace();
|
||||
}
|
||||
|
||||
static void
|
||||
linker_add_qfo (qfo_t *qfo)
|
||||
{
|
||||
code_base = code->size;
|
||||
data_base = data->size;
|
||||
far_data_base = far_data->size;
|
||||
reloc_base = relocs.num_relocs;
|
||||
func_base = funcs.num_funcs;
|
||||
line_base = lines.num_lines;
|
||||
entity_base = entity->size;
|
||||
update_relocs (qfo);
|
||||
update_defs (qfo);
|
||||
update_funcs (qfo);
|
||||
update_lines (qfo);
|
||||
|
||||
// codespace_addcode (code, qfo->code, qfo->code_size);
|
||||
// defspace_add_data (data, qfo->data, qfo->data_size);
|
||||
// defspace_add_data (far_data, qfo->far_data, qfo->far_data_size);
|
||||
// defspace_add_data (entity, 0, qfo->entity_fields);
|
||||
add_strings (qfo);
|
||||
add_relocs (qfo);
|
||||
add_funcs (qfo);
|
||||
add_defs (qfo);
|
||||
add_lines (qfo);
|
||||
add_qfo_strings (&qfo->spaces[qfo_strings_space]);
|
||||
add_code (&qfo->spaces[qfo_code_space]);
|
||||
add_data (qfo_near_data_space, &qfo->spaces[qfo_near_data_space]);
|
||||
add_data (qfo_far_data_space, &qfo->spaces[qfo_far_data_space]);
|
||||
add_data (qfo_entity_space, &qfo->spaces[qfo_entity_space]);
|
||||
//FIXME handle type data
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -745,6 +297,18 @@ linker_add_object_file (const char *filename)
|
|||
qfo = qfo_open (filename);
|
||||
if (!qfo)
|
||||
return 1;
|
||||
if (qfo->num_spaces < qfo_num_spaces
|
||||
|| qfo->spaces[qfo_null_space].type != qfos_null
|
||||
|| qfo->spaces[qfo_strings_space].type != qfos_string
|
||||
|| qfo->spaces[qfo_code_space].type != qfos_code
|
||||
|| qfo->spaces[qfo_near_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_type_space].type != qfos_type) {
|
||||
//FIXME proper diagnostic
|
||||
fprintf (stderr, "%s: missing or mangled standard spaces", filename);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (options.verbosity >= 2)
|
||||
puts (filename);
|
||||
|
@ -755,6 +319,14 @@ linker_add_object_file (const char *filename)
|
|||
return 0;
|
||||
}
|
||||
|
||||
typedef struct path_s {
|
||||
struct path_s *next;
|
||||
const char *path;
|
||||
} path_t;
|
||||
|
||||
static path_t *path_head;
|
||||
static path_t **path_tail = &path_head;
|
||||
|
||||
int
|
||||
linker_add_lib (const char *libname)
|
||||
{
|
||||
|
@ -827,9 +399,10 @@ linker_add_lib (const char *libname)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
static __attribute__ ((used)) void
|
||||
undefined_def (qfo_def_t *def)
|
||||
{
|
||||
#if 0
|
||||
qfo_def_t line_def;
|
||||
pr_int_t i;
|
||||
qfo_reloc_t *reloc = relocs.relocs + def->relocs;
|
||||
|
@ -871,11 +444,13 @@ undefined_def (qfo_def_t *def)
|
|||
def_error (def, "undefined symbol %s", STRING (def->name));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
qfo_t *
|
||||
linker_finish (void)
|
||||
{
|
||||
#if 0
|
||||
defref_t **undef_defs, **defref;
|
||||
qfo_t *qfo;
|
||||
|
||||
|
@ -931,6 +506,8 @@ linker_finish (void)
|
|||
qfo_add_types (qfo, type_strings->strings, type_strings->size);
|
||||
// qfo->entity_fields = entity->size;
|
||||
return qfo;
|
||||
#endif
|
||||
return work;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -958,25 +535,25 @@ def_error (qfo_def_t *def, const char *fmt, ...)
|
|||
|
||||
pr.source_file = def->file;
|
||||
pr.source_line = def->line;
|
||||
pr.strings = strings;
|
||||
// pr.strings = strings;
|
||||
error (0, "%s", string->str);
|
||||
}
|
||||
|
||||
//static void
|
||||
//def_warning (qfo_def_t *def, const char *fmt, ...)
|
||||
//{
|
||||
// va_list args;
|
||||
// static dstring_t *string;
|
||||
//
|
||||
// if (!string)
|
||||
// string = dstring_new ();
|
||||
//
|
||||
// va_start (args, fmt);
|
||||
// dvsprintf (string, fmt, args);
|
||||
// va_end (args);
|
||||
//
|
||||
// pr.source_file = def->file;
|
||||
// pr.source_line = def->line;
|
||||
static void
|
||||
def_warning (qfo_def_t *def, const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
static dstring_t *string;
|
||||
|
||||
if (!string)
|
||||
string = dstring_new ();
|
||||
|
||||
va_start (args, fmt);
|
||||
dvsprintf (string, fmt, args);
|
||||
va_end (args);
|
||||
|
||||
pr.source_file = def->file;
|
||||
pr.source_line = def->line;
|
||||
// pr.strings = strings;
|
||||
// warning (0, "%s", string->str);
|
||||
//}
|
||||
warning (0, "%s", string->str);
|
||||
}
|
||||
|
|
|
@ -556,7 +556,7 @@ qfo_to_progs (qfo_t *qfo, pr_info_t *pr)
|
|||
qfo_t *
|
||||
qfo_new (void)
|
||||
{
|
||||
return 0;
|
||||
return calloc (1, sizeof (qfo_t));
|
||||
}
|
||||
|
||||
void
|
||||
|
|
Loading…
Reference in a new issue