vm: new image relocation that doesn't use literal table

db4
Slava Pestov 2009-11-27 17:05:08 -06:00
parent bd02eef38e
commit 58c21a1a11
7 changed files with 287 additions and 234 deletions

View File

@ -54,6 +54,8 @@ void code_block_visitor<Visitor>::visit_object_code_block(object *obj)
quotation *q = (quotation *)obj; quotation *q = (quotation *)obj;
if(q->code) if(q->code)
parent->set_quot_xt(q,visitor(q->code)); parent->set_quot_xt(q,visitor(q->code));
else
q->xt = (void *)lazy_jit_compile;
break; break;
} }
case CALLSTACK_TYPE: case CALLSTACK_TYPE:

View File

@ -3,42 +3,119 @@
namespace factor namespace factor
{ {
void *factor_vm::object_xt(cell obj) cell factor_vm::compute_primitive_relocation(cell arg)
{
return (cell)primitives[untag_fixnum(arg)];
}
/* References to undefined symbols are patched up to call this function on
image load */
void factor_vm::undefined_symbol()
{
general_error(ERROR_UNDEFINED_SYMBOL,false_object,false_object,NULL);
}
void undefined_symbol()
{
return tls_vm()->undefined_symbol();
}
/* Look up an external library symbol referenced by a compiled code block */
cell factor_vm::compute_dlsym_relocation(array *literals, cell index)
{
cell symbol = array_nth(literals,index);
cell library = array_nth(literals,index + 1);
dll *d = (to_boolean(library) ? untag<dll>(library) : NULL);
if(d != NULL && !d->dll)
return (cell)factor::undefined_symbol;
switch(tagged<object>(symbol).type())
{
case BYTE_ARRAY_TYPE:
{
symbol_char *name = alien_offset(symbol);
void *sym = ffi_dlsym(d,name);
if(sym)
return (cell)sym;
else
return (cell)factor::undefined_symbol;
}
case ARRAY_TYPE:
{
array *names = untag<array>(symbol);
for(cell i = 0; i < array_capacity(names); i++)
{
symbol_char *name = alien_offset(array_nth(names,i));
void *sym = ffi_dlsym(d,name);
if(sym)
return (cell)sym;
}
return (cell)factor::undefined_symbol;
}
default:
critical_error("Bad symbol specifier",symbol);
return (cell)factor::undefined_symbol;
}
}
cell factor_vm::compute_xt_relocation(cell obj)
{ {
switch(tagged<object>(obj).type()) switch(tagged<object>(obj).type())
{ {
case WORD_TYPE: case WORD_TYPE:
return untag<word>(obj)->xt; return (cell)untag<word>(obj)->xt;
case QUOTATION_TYPE: case QUOTATION_TYPE:
return untag<quotation>(obj)->xt; return (cell)untag<quotation>(obj)->xt;
default: default:
critical_error("Expected word or quotation",obj); critical_error("Expected word or quotation",obj);
return NULL; return 0;
} }
} }
void *factor_vm::xt_pic(word *w, cell tagged_quot) cell factor_vm::compute_xt_pic_relocation(word *w, cell tagged_quot)
{ {
if(!to_boolean(tagged_quot) || max_pic_size == 0) if(!to_boolean(tagged_quot) || max_pic_size == 0)
return w->xt; return (cell)w->xt;
else else
{ {
quotation *quot = untag<quotation>(tagged_quot); quotation *quot = untag<quotation>(tagged_quot);
if(quot->code) if(quot->code)
return quot->xt; return (cell)quot->xt;
else else
return w->xt; return (cell)w->xt;
} }
} }
void *factor_vm::word_xt_pic(word *w) cell factor_vm::compute_xt_pic_relocation(cell w_)
{ {
return xt_pic(w,w->pic_def); tagged<word> w(w_);
return compute_xt_pic_relocation(w.untagged(),w->pic_def);
} }
void *factor_vm::word_xt_pic_tail(word *w) cell factor_vm::compute_xt_pic_tail_relocation(cell w_)
{ {
return xt_pic(w,w->pic_tail_def); tagged<word> w(w_);
return compute_xt_pic_relocation(w.untagged(),w->pic_tail_def);
}
cell factor_vm::compute_here_relocation(cell arg, cell offset, code_block *compiled)
{
fixnum n = untag_fixnum(arg);
return n >= 0 ? ((cell)compiled->xt() + offset + n) : ((cell)compiled->xt() - n);
}
cell factor_vm::compute_context_relocation()
{
return (cell)&ctx;
}
cell factor_vm::compute_vm_relocation(cell arg)
{
return (cell)this + untag_fixnum(arg);
} }
cell factor_vm::code_block_owner(code_block *compiled) cell factor_vm::code_block_owner(code_block *compiled)
@ -83,19 +160,19 @@ struct word_references_updater {
case RT_XT: case RT_XT:
{ {
code_block *compiled = op.load_code_block(); code_block *compiled = op.load_code_block();
op.store_value((cell)parent->object_xt(compiled->owner)); op.store_value(parent->compute_xt_relocation(compiled->owner));
break; break;
} }
case RT_XT_PIC: case RT_XT_PIC:
{ {
code_block *compiled = op.load_code_block(); code_block *compiled = op.load_code_block();
op.store_value((cell)parent->word_xt_pic(untag<word>(parent->code_block_owner(compiled)))); op.store_value(parent->compute_xt_pic_relocation(parent->code_block_owner(compiled)));
break; break;
} }
case RT_XT_PIC_TAIL: case RT_XT_PIC_TAIL:
{ {
code_block *compiled = op.load_code_block(); code_block *compiled = op.load_code_block();
op.store_value((cell)parent->word_xt_pic_tail(untag<word>(parent->code_block_owner(compiled)))); op.store_value(parent->compute_xt_pic_tail_relocation(parent->code_block_owner(compiled)));
break; break;
} }
default: default:
@ -129,97 +206,39 @@ void factor_vm::update_word_references(code_block *compiled)
} }
} }
/* References to undefined symbols are patched up to call this function on
image load */
void factor_vm::undefined_symbol()
{
general_error(ERROR_UNDEFINED_SYMBOL,false_object,false_object,NULL);
}
void undefined_symbol()
{
return tls_vm()->undefined_symbol();
}
/* Look up an external library symbol referenced by a compiled code block */
void *factor_vm::get_rel_symbol(array *literals, cell index)
{
cell symbol = array_nth(literals,index);
cell library = array_nth(literals,index + 1);
dll *d = (to_boolean(library) ? untag<dll>(library) : NULL);
if(d != NULL && !d->dll)
return (void *)factor::undefined_symbol;
switch(tagged<object>(symbol).type())
{
case BYTE_ARRAY_TYPE:
{
symbol_char *name = alien_offset(symbol);
void *sym = ffi_dlsym(d,name);
if(sym)
return sym;
else
return (void *)factor::undefined_symbol;
}
case ARRAY_TYPE:
{
array *names = untag<array>(symbol);
for(cell i = 0; i < array_capacity(names); i++)
{
symbol_char *name = alien_offset(array_nth(names,i));
void *sym = ffi_dlsym(d,name);
if(sym)
return sym;
}
return (void *)factor::undefined_symbol;
}
default:
critical_error("Bad symbol specifier",symbol);
return (void *)factor::undefined_symbol;
}
}
cell factor_vm::compute_relocation(relocation_entry rel, cell index, code_block *compiled) cell factor_vm::compute_relocation(relocation_entry rel, cell index, code_block *compiled)
{ {
array *literals = (to_boolean(compiled->literals) array *literals = (to_boolean(compiled->literals)
? untag<array>(compiled->literals) : NULL); ? untag<array>(compiled->literals) : NULL);
cell offset = rel.rel_offset() + (cell)compiled->xt();
#define ARG array_nth(literals,index) #define ARG array_nth(literals,index)
switch(rel.rel_type()) switch(rel.rel_type())
{ {
case RT_PRIMITIVE: case RT_PRIMITIVE:
return (cell)primitives[untag_fixnum(ARG)]; return compute_primitive_relocation(ARG);
case RT_DLSYM: case RT_DLSYM:
return (cell)get_rel_symbol(literals,index); return compute_dlsym_relocation(literals,index);
case RT_IMMEDIATE: case RT_IMMEDIATE:
return ARG; return ARG;
case RT_XT: case RT_XT:
return (cell)object_xt(ARG); return compute_xt_relocation(ARG);
case RT_XT_PIC: case RT_XT_PIC:
return (cell)word_xt_pic(untag<word>(ARG)); return compute_xt_pic_relocation(ARG);
case RT_XT_PIC_TAIL: case RT_XT_PIC_TAIL:
return (cell)word_xt_pic_tail(untag<word>(ARG)); return compute_xt_pic_tail_relocation(ARG);
case RT_HERE: case RT_HERE:
{ return compute_here_relocation(ARG,rel.rel_offset(),compiled);
fixnum arg = untag_fixnum(ARG);
return (arg >= 0 ? offset + arg : (cell)compiled->xt() - arg);
}
case RT_THIS: case RT_THIS:
return (cell)compiled->xt(); return (cell)compiled->xt();
case RT_CONTEXT: case RT_CONTEXT:
return (cell)&ctx; return compute_context_relocation();
case RT_UNTAGGED: case RT_UNTAGGED:
return untag_fixnum(ARG); return untag_fixnum(ARG);
case RT_MEGAMORPHIC_CACHE_HITS: case RT_MEGAMORPHIC_CACHE_HITS:
return (cell)&dispatch_stats.megamorphic_cache_hits; return (cell)&dispatch_stats.megamorphic_cache_hits;
case RT_VM: case RT_VM:
return (cell)this + untag_fixnum(ARG); return compute_vm_relocation(ARG);
case RT_CARDS_OFFSET: case RT_CARDS_OFFSET:
return cards_offset; return cards_offset;
case RT_DECKS_OFFSET: case RT_DECKS_OFFSET:

View File

@ -55,177 +55,206 @@ void factor_vm::load_code_heap(FILE *file, image_header *h, vm_parameters *p)
code->allocator->initial_free_list(h->code_size); code->allocator->initial_free_list(h->code_size);
} }
void factor_vm::data_fixup(cell *handle, cell data_relocation_base) struct data_fixupper {
{ cell offset;
if(immediate_p(*handle))
return;
*handle += (data->tenured->start - data_relocation_base); explicit data_fixupper(cell offset_) : offset(offset_) {}
}
template<typename Type> void factor_vm::code_fixup(Type **handle, cell code_relocation_base) object *operator()(object *obj)
{
Type *ptr = *handle;
Type *new_ptr = (Type *)(((cell)ptr) + (code->seg->start - code_relocation_base));
*handle = new_ptr;
}
void factor_vm::fixup_word(word *word, cell code_relocation_base)
{
if(word->code)
code_fixup(&word->code,code_relocation_base);
if(word->profiling)
code_fixup(&word->profiling,code_relocation_base);
code_fixup(&word->xt,code_relocation_base);
}
void factor_vm::fixup_quotation(quotation *quot, cell code_relocation_base)
{
if(quot->code)
{ {
code_fixup(&quot->xt,code_relocation_base); return (object *)((char *)obj + offset);
code_fixup(&quot->code,code_relocation_base);
}
else
quot->xt = (void *)lazy_jit_compile;
}
void factor_vm::fixup_alien(alien *ptr)
{
if(!to_boolean(ptr->base))
ptr->expired = true_object;
else
ptr->update_address();
}
struct stack_frame_fixupper {
factor_vm *parent;
cell code_relocation_base;
explicit stack_frame_fixupper(factor_vm *parent_, cell code_relocation_base_) :
parent(parent_), code_relocation_base(code_relocation_base_) {}
void operator()(stack_frame *frame)
{
parent->code_fixup(&frame->xt,code_relocation_base);
parent->code_fixup(&FRAME_RETURN_ADDRESS(frame,parent),code_relocation_base);
} }
}; };
void factor_vm::fixup_callstack_object(callstack *stack, cell code_relocation_base) struct code_fixupper {
cell offset;
explicit code_fixupper(cell offset_) : offset(offset_) {}
code_block *operator()(code_block *compiled)
{
return (code_block *)((char *)compiled + offset);
}
};
static inline cell tuple_size_with_fixup(cell offset, object *obj)
{ {
stack_frame_fixupper fixupper(this,code_relocation_base); tuple_layout *layout = (tuple_layout *)((char *)UNTAG(((tuple *)obj)->layout) + offset);
iterate_callstack_object(stack,fixupper); return tuple_size(layout);
} }
struct fixup_sizer {
cell offset;
explicit fixup_sizer(cell offset_) : offset(offset_) {}
cell operator()(object *obj)
{
if(obj->type() == TUPLE_TYPE)
return align(tuple_size_with_fixup(offset,obj),data_alignment);
else
return obj->size();
}
};
struct object_fixupper { struct object_fixupper {
factor_vm *parent; factor_vm *parent;
cell data_relocation_base; cell data_offset;
slot_visitor<data_fixupper> data_visitor;
code_block_visitor<code_fixupper> code_visitor;
explicit object_fixupper(factor_vm *parent_, cell data_relocation_base_) : object_fixupper(factor_vm *parent_, cell data_offset_, cell code_offset_) :
parent(parent_), data_relocation_base(data_relocation_base_) { } parent(parent_),
data_offset(data_offset_),
data_visitor(slot_visitor<data_fixupper>(parent_,data_fixupper(data_offset_))),
code_visitor(code_block_visitor<code_fixupper>(parent_,code_fixupper(code_offset_))) {}
void operator()(cell *scan) void operator()(object *obj, cell size)
{ {
parent->data_fixup(scan,data_relocation_base); parent->data->tenured->starts.record_object_start_offset(obj);
switch(obj->type())
{
case ALIEN_TYPE:
{
cell payload_start = obj->binary_payload_start();
data_visitor.visit_slots(obj,payload_start);
alien *ptr = (alien *)obj;
if(!parent->to_boolean(ptr->base))
ptr->expired = parent->true_object;
else
ptr->update_address();
break;
}
case DLL_TYPE:
{
cell payload_start = obj->binary_payload_start();
data_visitor.visit_slots(obj,payload_start);
parent->ffi_dlopen((dll *)obj);
break;
}
case TUPLE_TYPE:
{
cell payload_start = tuple_size_with_fixup(data_offset,obj);
data_visitor.visit_slots(obj,payload_start);
break;
}
default:
{
cell payload_start = obj->binary_payload_start();
data_visitor.visit_slots(obj,payload_start);
code_visitor.visit_object_code_block(obj);
break;
}
}
} }
}; };
/* Initialize an object in a newly-loaded image */ void factor_vm::fixup_data(cell data_offset, cell code_offset)
void factor_vm::relocate_object(object *object,
cell data_relocation_base,
cell code_relocation_base)
{ {
cell type = object->type(); slot_visitor<data_fixupper> data_workhorse(this,data_fixupper(data_offset));
data_workhorse.visit_roots();
object_fixupper fixupper(this,data_offset,code_offset);
fixup_sizer sizer(data_offset);
data->tenured->iterate(fixupper,sizer);
}
struct code_block_updater {
factor_vm *parent;
cell code_offset;
slot_visitor<data_fixupper> data_visitor;
code_fixupper code_visitor;
code_block_updater(factor_vm *parent_, cell data_offset_, cell code_offset_) :
parent(parent_),
code_offset(code_offset_),
data_visitor(slot_visitor<data_fixupper>(parent_,data_fixupper(data_offset_))),
code_visitor(code_fixupper(code_offset_)) {}
void operator()(relocation_entry rel, cell index, code_block *compiled)
{
relocation_type type = rel.rel_type();
instruction_operand op(rel.rel_class(),rel.rel_offset() + (cell)compiled->xt());
/* Tuple relocation is a bit trickier; we have to fix up the array *literals = (parent->to_boolean(compiled->literals)
layout object before we can get the tuple size, so each_slot is ? untag<array>(compiled->literals) : NULL);
out of the question */
if(type == TUPLE_TYPE)
{
tuple *t = (tuple *)object;
data_fixup(&t->layout,data_relocation_base);
cell *scan = t->data(); cell old_offset = (cell)compiled - code_offset;
cell *end = (cell *)((cell)object + object->size());
for(; scan < end; scan++)
data_fixup(scan,data_relocation_base);
}
else
{
object_fixupper fixupper(this,data_relocation_base);
object->each_slot(fixupper);
switch(type) switch(type)
{ {
case WORD_TYPE: case RT_IMMEDIATE:
fixup_word((word *)object,code_relocation_base); op.store_value(data_visitor.visit_pointer(op.load_value(old_offset)));
break; break;
case QUOTATION_TYPE: case RT_XT:
fixup_quotation((quotation *)object,code_relocation_base); case RT_XT_PIC:
case RT_XT_PIC_TAIL:
op.store_code_block(code_visitor(op.load_code_block(old_offset)));
break; break;
case DLL_TYPE: case RT_PRIMITIVE:
ffi_dlopen((dll *)object); op.store_value(parent->compute_primitive_relocation(array_nth(literals,index)));
break; break;
case ALIEN_TYPE: case RT_DLSYM:
fixup_alien((alien *)object); op.store_value(parent->compute_dlsym_relocation(literals,index));
break; break;
case CALLSTACK_TYPE: case RT_HERE:
fixup_callstack_object((callstack *)object,code_relocation_base); op.store_value(parent->compute_here_relocation(array_nth(literals,index),rel.rel_offset(),compiled));
break;
case RT_THIS:
op.store_value((cell)compiled->xt());
break;
case RT_CONTEXT:
op.store_value(parent->compute_context_relocation());
break;
case RT_UNTAGGED:
op.store_value(untag_fixnum(array_nth(literals,index)));
case RT_MEGAMORPHIC_CACHE_HITS:
op.store_value((cell)&parent->dispatch_stats.megamorphic_cache_hits);
break;
case RT_VM:
op.store_value(parent->compute_vm_relocation(array_nth(literals,index)));
break;
case RT_CARDS_OFFSET:
op.store_value(parent->cards_offset);
break;
case RT_DECKS_OFFSET:
op.store_value(parent->decks_offset);
break;
default:
critical_error("Bad rel type",rel.rel_type());
break; break;
} }
} }
} };
/* Since the image might have been saved with a different base address than
where it is loaded, we need to fix up pointers in the image. */
void factor_vm::relocate_data(cell data_relocation_base, cell code_relocation_base)
{
for(cell i = 0; i < special_object_count; i++)
data_fixup(&special_objects[i],data_relocation_base);
data_fixup(&true_object,data_relocation_base);
data_fixup(&bignum_zero,data_relocation_base);
data_fixup(&bignum_pos_one,data_relocation_base);
data_fixup(&bignum_neg_one,data_relocation_base);
cell obj = data->tenured->start;
while(obj)
{
relocate_object((object *)obj,data_relocation_base,code_relocation_base);
data->tenured->starts.record_object_start_offset((object *)obj);
obj = data->tenured->next_object_after(obj);
}
}
void factor_vm::fixup_code_block(code_block *compiled, cell data_relocation_base)
{
/* relocate literal table data */
data_fixup(&compiled->owner,data_relocation_base);
data_fixup(&compiled->literals,data_relocation_base);
data_fixup(&compiled->relocation,data_relocation_base);
relocate_code_block(compiled);
}
struct code_block_fixupper { struct code_block_fixupper {
factor_vm *parent; factor_vm *parent;
cell data_relocation_base; cell data_offset;
cell code_offset;
explicit code_block_fixupper(factor_vm *parent_, cell data_relocation_base_) : code_block_fixupper(factor_vm *parent_, cell data_offset_, cell code_offset_) :
parent(parent_), data_relocation_base(data_relocation_base_) { } parent(parent_),
data_offset(data_offset_),
code_offset(code_offset_) {}
void operator()(code_block *compiled, cell size) void operator()(code_block *compiled, cell size)
{ {
parent->fixup_code_block(compiled,data_relocation_base); slot_visitor<data_fixupper> data_visitor(parent,data_fixupper(data_offset));
data_visitor.visit_code_block_objects(compiled);
code_block_updater updater(parent,data_offset,code_offset);
parent->iterate_relocations(compiled,updater);
} }
}; };
void factor_vm::relocate_code(cell data_relocation_base) void factor_vm::fixup_code(cell data_offset, cell code_offset)
{ {
code_block_fixupper fixupper(this,data_relocation_base); code_block_fixupper fixupper(this,data_offset,code_offset);
iterate_code_heap(fixupper); code->allocator->iterate(fixupper);
} }
/* Read an image file from disk, only done once during startup */ /* Read an image file from disk, only done once during startup */
@ -257,8 +286,11 @@ void factor_vm::load_image(vm_parameters *p)
init_objects(&h); init_objects(&h);
relocate_data(h.data_relocation_base,h.code_relocation_base); cell data_offset = data->tenured->start - h.data_relocation_base;
relocate_code(h.data_relocation_base); cell code_offset = code->seg->start - h.code_relocation_base;
fixup_data(data_offset,code_offset);
fixup_code(data_offset,code_offset);
/* Store image path name */ /* Store image path name */
special_objects[OBJ_IMAGE] = allot_alien(false_object,(cell)p->image_path); special_objects[OBJ_IMAGE] = allot_alien(false_object,(cell)p->image_path);

View File

@ -55,9 +55,14 @@ fixnum instruction_operand::load_value()
return load_value(pointer); return load_value(pointer);
} }
code_block *instruction_operand::load_code_block(cell relative_to)
{
return ((code_block *)load_value(relative_to) - 1);
}
code_block *instruction_operand::load_code_block() code_block *instruction_operand::load_code_block()
{ {
return ((code_block *)load_value() - 1); return load_code_block(pointer);
} }
/* Store a 32-bit value into a PowerPC LIS/ORI sequence */ /* Store a 32-bit value into a PowerPC LIS/ORI sequence */

View File

@ -130,6 +130,7 @@ struct instruction_operand {
fixnum load_value_masked(cell mask, fixnum shift); fixnum load_value_masked(cell mask, fixnum shift);
fixnum load_value(cell relative_to); fixnum load_value(cell relative_to);
fixnum load_value(); fixnum load_value();
code_block *load_code_block(cell relative_to);
code_block *load_code_block(); code_block *load_code_block();
void store_value_2_2(fixnum value); void store_value_2_2(fixnum value);

View File

@ -135,9 +135,7 @@ struct literal_references_visitor {
if(rel.rel_type() == RT_IMMEDIATE) if(rel.rel_type() == RT_IMMEDIATE)
{ {
instruction_operand op(rel.rel_class(),rel.rel_offset() + (cell)compiled->xt()); instruction_operand op(rel.rel_class(),rel.rel_offset() + (cell)compiled->xt());
cell literal = op.load_value(); op.store_value(visitor->visit_pointer(op.load_value()));
literal = visitor->visit_pointer(literal);
op.store_value(literal);
} }
} }
}; };

View File

@ -500,14 +500,17 @@ struct factor_vm
void primitive_fclose(); void primitive_fclose();
//code_block //code_block
void *object_xt(cell obj); cell compute_primitive_relocation(cell arg);
void *xt_pic(word *w, cell tagged_quot);
void *word_xt_pic(word *w);
void *word_xt_pic_tail(word *w);
cell code_block_owner(code_block *compiled);
void undefined_symbol(); void undefined_symbol();
void *get_rel_symbol(array *literals, cell index); cell compute_dlsym_relocation(array *literals, cell index);
cell compute_relocation(relocation_entry rel, cell index, code_block *compiled); cell compute_xt_relocation(cell obj);
cell compute_xt_pic_relocation(word *w, cell tagged_quot);
cell compute_xt_pic_relocation(cell w_);
cell compute_xt_pic_tail_relocation(cell w_);
cell compute_here_relocation(cell arg, cell offset, code_block *compiled);
cell compute_context_relocation();
cell compute_vm_relocation(cell arg);
cell code_block_owner(code_block *compiled);
template<typename Iterator> void iterate_relocations(code_block *compiled, Iterator &iter) template<typename Iterator> void iterate_relocations(code_block *compiled, Iterator &iter)
{ {
@ -528,6 +531,7 @@ struct factor_vm
} }
void update_word_references(code_block *compiled); void update_word_references(code_block *compiled);
cell compute_relocation(relocation_entry rel, cell index, code_block *compiled);
void check_code_address(cell address); void check_code_address(cell address);
void relocate_code_block(code_block *compiled); void relocate_code_block(code_block *compiled);
void fixup_labels(array *labels, code_block *compiled); void fixup_labels(array *labels, code_block *compiled);
@ -567,16 +571,8 @@ struct factor_vm
bool save_image(const vm_char *filename); bool save_image(const vm_char *filename);
void primitive_save_image(); void primitive_save_image();
void primitive_save_image_and_exit(); void primitive_save_image_and_exit();
void data_fixup(cell *handle, cell data_relocation_base); void fixup_data(cell data_offset, cell code_offset);
template<typename Type> void code_fixup(Type **handle, cell code_relocation_base); void fixup_code(cell data_offset, cell code_offset);
void fixup_word(word *word, cell code_relocation_base);
void fixup_quotation(quotation *quot, cell code_relocation_base);
void fixup_alien(alien *d);
void fixup_callstack_object(callstack *stack, cell code_relocation_base);
void relocate_object(object *object, cell data_relocation_base, cell code_relocation_base);
void relocate_data(cell data_relocation_base, cell code_relocation_base);
void fixup_code_block(code_block *compiled, cell data_relocation_base);
void relocate_code(cell data_relocation_base);
void load_image(vm_parameters *p); void load_image(vm_parameters *p);
//callstack //callstack