1 /****************************************************************************
2  * Copyright (C) 2008 by Matteo Franchin                                    *
3  *                                                                          *
4  * This file is part of Box.                                                *
5  *                                                                          *
6  *   Box is free software: you can redistribute it and/or modify it         *
7  *   under the terms of the GNU Lesser General Public License as published  *
8  *   by the Free Software Foundation, either version 3 of the License, or   *
9  *   (at your option) any later version.                                    *
10  *                                                                          *
11  *   Box is distributed in the hope that it will be useful,                 *
12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of         *
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          *
14  *   GNU Lesser General Public License for more details.                    *
15  *                                                                          *
16  *   You should have received a copy of the GNU Lesser General Public       *
17  *   License along with Box.  If not, see <http://www.gnu.org/licenses/>.   *
18  ****************************************************************************/
19 
20 #include <assert.h>
21 #include <string.h>
22 #include <stdlib.h>
23 
24 #include "config.h"
25 
26 #include <ltdl.h>
27 #define DYLIB
28 
29 #include "defaults.h"
30 #include "types.h"
31 #include "strutils.h"
32 #include "messages.h"
33 #include "mem.h"
34 #include "vm_priv.h"
35 #include "vmsym.h"
36 #include "vmsymstuff.h"
37 #include "vmproc.h"
38 #include "list.h"
39 
40 #ifdef DYLIB
My_Close_DyLib(void * item)41 static void My_Close_DyLib(void *item) {
42   void *dylib = *((void **) item);
43   if (lt_dlclose(dylib)) {
44     MSG_WARNING("BoxVMSym_Destroy: My_Close_DyLib: lt_dlclose failure");
45   }
46 }
47 #endif
48 
BoxVMSymTable_Init(BoxVMSymTable * st)49 void BoxVMSymTable_Init(BoxVMSymTable *st) {
50   BoxHT_Init_Default(& st->syms, VMSYM_SYM_HT_SIZE);
51   BoxArr_Init(& st->data, sizeof(BoxChar), VMSYM_DATA_ARR_SIZE);
52   BoxArr_Init(& st->defs, sizeof(BoxVMSym), VMSYM_DEF_ARR_SIZE);
53   BoxArr_Init(& st->refs, sizeof(BoxVMSymRef), VMSYM_REF_ARR_SIZE);
54 #ifdef DYLIB
55   BoxArr_Init(& st->dylibs, sizeof(void *), VMSYM_DYLIB_ARR_SIZE);
56   BoxArr_Set_Finalizer(& st->dylibs, My_Close_DyLib);
57 #endif
58 
59   if (lt_dlinit() != 0) {
60     MSG_WARNING("BoxVMSym_Init: lt_dlinit failed!");
61   }
62 }
63 
BoxVMSymTable_Finish(BoxVMSymTable * st)64 void BoxVMSymTable_Finish(BoxVMSymTable *st) {
65   BoxHT_Finish(& st->syms);
66   BoxArr_Finish(& st->data);
67   BoxArr_Finish(& st->defs);
68   BoxArr_Finish(& st->refs);
69 #ifdef DYLIB
70   BoxArr_Finish(& st->dylibs);
71 #endif
72   if (lt_dlexit() != 0) {
73     MSG_WARNING("BoxVMSym_Destroy: lt_dlexit failed!");
74   }
75 }
76 
BoxVMSym_New(BoxVM * vm,BoxUInt sym_type,BoxUInt def_size)77 BoxVMSymID BoxVMSym_New(BoxVM *vm, BoxUInt sym_type, BoxUInt def_size) {
78   return BoxVMSym_Create(vm, sym_type, NULL, def_size);
79 }
80 
81 /* Create a new symbol. */
82 BoxVMSymID
BoxVMSym_Create(BoxVM * vm,BoxUInt sym_type,const void * def,size_t def_size)83 BoxVMSym_Create(BoxVM *vm, BoxUInt sym_type,
84                 const void *def, size_t def_size) {
85   BoxVMSymTable *st = & vm->sym_table;
86   BoxVMSymID sym_id;
87   BoxVMSym *ss = BoxArr_Push(& st->defs, & ss);
88 
89   assert(ss);
90   ss->name.length = 0;
91   ss->name.text = NULL;
92   ss->sym_type = sym_type;
93   ss->defined = 0;
94   ss->def_size = def_size;
95   ss->def_addr = 1 + BoxArr_Num_Items(& st->data);
96   ss->first_ref = 0;
97 
98   sym_id = BoxArr_Num_Items(& st->defs);
99   BoxArr_MPush(& st->data, def, def_size);
100   return sym_id;
101 }
102 
103 /** Associate a name to the symbol sym_id. */
BoxVMSym_Set_Name(BoxVM * vm,BoxVMSymID sym_id,const char * name)104 void BoxVMSym_Set_Name(BoxVM *vm, BoxVMSymID sym_id, const char *name) {
105   BoxVMSymTable *st = & vm->sym_table;
106   BoxHTItem *hi;
107   BoxVMSym *s;
108   /*char *n_str;*/
109   size_t name_len;
110 
111   s = (BoxVMSym *) BoxArr_Item_Ptr(& st->defs, sym_id);
112   if (s->name.length != 0) {
113     MSG_FATAL("This symbol has already been given a name!");
114     assert(0);
115   }
116 
117   name_len = strlen(name) + 1; /* include also the terminating '\0' char */
118   if (BoxHT_Find(& st->syms, name, name_len, & hi)) {
119     MSG_FATAL("Another symbol exists having the name '%s'!", name);
120     assert(0);
121   }
122 
123   (void) BoxHT_Insert_Obj(& st->syms, name, name_len,
124                           & sym_id, sizeof(BoxUInt));
125   if (!BoxHT_Find(& st->syms, name, name_len, & hi) ) {
126     MSG_FATAL("Hashtable seems not to work (from BoxVMSym_Add)");
127     assert(0);
128   }
129 
130   s->name.text = (char *) hi->key;
131   s->name.length = hi->key_size - 1; /* Without the final '\0' */
132 }
133 
BoxVMSym_Get_Name(BoxVM * vm,BoxVMSymID sym_id)134 const char *BoxVMSym_Get_Name(BoxVM *vm, BoxVMSymID sym_id) {
135   BoxVMSymTable *st = & vm->sym_table;
136   BoxVMSym *s = (BoxVMSym *) BoxArr_Item_Ptr(& st->defs, sym_id);
137   return s->name.text;
138 }
139 
140 /* Get the definition data for a symbol. */
BoxVMSym_Get_Definition(BoxVM * vm,BoxVMSymID sym_id)141 void *BoxVMSym_Get_Definition(BoxVM *vm, BoxVMSymID sym_id) {
142   BoxVMSymTable *st = & vm->sym_table;
143   BoxVMSym *s = (BoxVMSym *) BoxArr_Item_Ptr(& st->defs, sym_id);
144   void *def_data_ptr = BoxArr_Item_Ptr(& st->data, s->def_addr);
145   return def_data_ptr;
146 }
147 
148 /* Define a symbol which was previously created with BoxVMSym_Create(). */
149 BoxTask
BoxVMSym_Define(BoxVM * vm,BoxVMSymID sym_id,void * def)150 BoxVMSym_Define(BoxVM *vm, BoxVMSymID sym_id, void *def) {
151   BoxVMSymTable *st = & vm->sym_table;
152   BoxVMSym *s = BoxArr_Get_Item_Ptr(& st->defs, sym_id);
153 
154   if (s->defined) {
155     const char *sym_name = BoxVMSym_Get_Name(vm, sym_id);
156     MSG_ERROR("Double definition of the symbol '%s'.", sym_name);
157     return BOXTASK_FAILURE;
158   }
159 
160   if (def) {
161     void *def_data_ptr = BoxArr_Item_Ptr(& st->data, s->def_addr);
162     (void) memcpy(def_data_ptr, def, s->def_size);
163   }
164 
165   s->defined = 1;
166   return BOXTASK_OK;
167 }
168 
BoxVMSym_Is_Defined(BoxVM * vm,BoxVMSymID sym_id)169 int BoxVMSym_Is_Defined(BoxVM *vm, BoxVMSymID sym_id) {
170   BoxVMSymTable *st = & vm->sym_table;
171   BoxVMSym *s = (BoxVMSym *) BoxArr_Item_Ptr(& st->defs, sym_id);
172   return s->defined;
173 }
174 
BoxVMSym_Ref(BoxVM * vm,BoxVMSymID sym_id,BoxVMSymResolver r,void * ref,size_t ref_size,BoxVMSymStatus resolved)175 void BoxVMSym_Ref(BoxVM *vm, BoxVMSymID sym_id, BoxVMSymResolver r,
176                   void *ref, size_t ref_size, BoxVMSymStatus resolved) {
177   BoxVMSymTable *st = & vm->sym_table;
178   BoxVMSym *s;
179   BoxVMSymRef sr;
180   void *ref_data_ptr;
181 
182   assert(ref_size > 0 || ref == NULL);
183   s = (BoxVMSym *) BoxArr_Item_Ptr(& st->defs, sym_id);
184   sr.sym_id = sym_id;
185   sr.next = s->first_ref;
186   sr.ref_size = ref_size;
187   sr.ref_addr = 1 + BoxArr_Num_Items(& st->data);
188   switch(resolved) {
189   case BOXVMSYM_RESOLVED: sr.resolved = 1; break;
190   case BOXVMSYM_UNRESOLVED: sr.resolved = 0; break;
191   default: sr.resolved = s->defined; break;
192   }
193   sr.resolver = r;
194 
195   /* Copy the data for the reference */
196   if (ref_size > 0) {
197     BoxArr_MPush(& st->data, NULL, ref_size);
198     ref_data_ptr = BoxArr_Item_Ptr(& st->data, sr.ref_addr);
199     (void) memcpy(ref_data_ptr, ref, ref_size);
200   }
201 
202   /* Add the reference */
203   BoxArr_Push(& st->refs, & sr);
204   /* Link the reference to the list of references for the symbol */
205   s->first_ref = BoxArr_Num_Items(& st->refs);
206 }
207 
208 static int
My_Check_Ref(BoxUInt item_num,void * item,void * all_resolved)209 My_Check_Ref(BoxUInt item_num, void *item, void *all_resolved) {
210   BoxVMSymRef *sr = (BoxVMSymRef *) item;
211   *((int *) all_resolved) &= sr->resolved;
212   return 1;
213 }
214 
BoxVMSym_Ref_Check(BoxVM * vm,int * all_resolved)215 void BoxVMSym_Ref_Check(BoxVM *vm, int *all_resolved) {
216   BoxVMSymTable *st = & vm->sym_table;
217   *all_resolved = 1;
218   (void) BoxArr_Iter(& st->refs, My_Check_Ref, all_resolved);
219 }
220 
221 static int
My_Report_Ref(BoxUInt item_num,void * item,void * pass_data)222 My_Report_Ref(BoxUInt item_num, void *item, void *pass_data) {
223   BoxVM *vm = (BoxVM *) pass_data;
224   BoxVMSymRef *sr = (BoxVMSymRef *) item;
225   if (!sr->resolved) {
226     MSG_ERROR("Unresolved reference to the symbol (ID=%d, name='%s')",
227               sr->sym_id, BoxVMSym_Get_Name(vm, sr->sym_id));
228   }
229   return 1;
230 }
231 
BoxVMSym_Ref_Report(BoxVM * vm)232 void BoxVMSym_Ref_Report(BoxVM *vm) {
233   BoxVMSymTable *st = & vm->sym_table;
234   (void) BoxArr_Iter(& st->refs, My_Report_Ref, vm);
235 }
236 
237 #if 0
238 BoxTask BoxVMSym_Resolver_Set(BoxVM *vm, BoxVMSymID sym_id, BoxVMSymResolver r) {
239   BoxVMSymTable *st = & vm->sym_table;
240   BoxVMSym *s;
241 
242   s = (BoxVMSym *) BoxArr_ItemPtr(& st->defs, sym_id);
243   s->resolver = r;
244   return BOXTASK_OK;
245 }
246 #endif
247 
BoxVMSym_Resolve(BoxVM * vm,BoxVMSymID sym_id)248 BoxTask BoxVMSym_Resolve(BoxVM *vm, BoxVMSymID sym_id) {
249   BoxVMSymTable *st = & vm->sym_table;
250   BoxVMSym *s;
251   BoxUInt next;
252   BoxUInt sym_type, def_size, ref_size;
253   void *def, *ref;
254 
255   if (sym_id < 1) {
256     BoxUInt i, num_defs = BoxArr_Num_Items(& st->defs);
257     for(i=1; i<=num_defs; i++) {
258       BOXTASK( BoxVMSym_Resolve(vm, i) );
259     }
260     return BOXTASK_OK;
261   }
262 
263   s = (BoxVMSym *) BoxArr_Item_Ptr(& st->defs, sym_id);
264   if (! s->defined) return BOXTASK_OK;
265   next = s->first_ref;
266   def = BoxArr_Item_Ptr(& st->data, s->def_addr);
267   def_size = s->def_size;
268   sym_type = s->sym_type;
269   while (next > 0) {
270     BoxVMSymRef *sr = (BoxVMSymRef *) BoxArr_Item_Ptr(& st->refs, next);
271     if (sr->sym_id != sym_id) {
272       MSG_FATAL("BoxVMSym_Resolve: bad reference in the chain!");
273       return BOXTASK_FAILURE;
274     }
275 
276     if (!sr->resolved) {
277       if (sr->resolver == NULL) {
278         MSG_ERROR("BoxVMSym_Resolve: cannot resolve the symbol: "
279                   "the resolver is not present!");
280         return BOXTASK_FAILURE;
281       }
282 
283       ref_size = sr->ref_size;
284       ref = (ref_size > 0) ? BoxArr_Item_Ptr(& st->data, sr->ref_addr) : 0;
285 
286       BOXTASK( sr->resolver(vm, sym_id, sym_type, 1, def, def_size,
287                             ref, ref_size) );
288       sr->resolved = 1;
289     }
290 
291     next = sr->next;
292   }
293   return BOXTASK_OK;
294 }
295 
BoxVMSym_Table_Print(BoxVM * vm,FILE * out,BoxVMSymID sym_id)296 void BoxVMSym_Table_Print(BoxVM *vm, FILE *out, BoxVMSymID sym_id) {
297   BoxVMSymTable *st = & vm->sym_table;
298   BoxVMSym *s;
299   BoxUInt next, ref_num;
300   char *sym_name;
301 
302   if (sym_id < 1) {
303     BoxUInt i, num_defs = BoxArr_Num_Items(& st->defs);
304     fprintf(out, "The table contains "SUInt" symbols\n", num_defs);
305     for(i=1; i<=num_defs; i++) {
306       BoxVMSym_Table_Print(vm, out, i);
307     }
308     return;
309   }
310 
311   s = (BoxVMSym  *) BoxArr_Item_Ptr(& st->defs, sym_id);
312   next = s->first_ref;
313   sym_name = (s->name.length > 0) ? s->name.text : "";
314   ref_num = 1;
315 
316   fprintf(out,
317    "Symbol ID = "SUInt"; name = '%s'; type = "SUInt"; "
318    "defined = %d, def_addr = "SUInt", def_size = "SUInt"\n",
319    sym_id, sym_name, s->sym_type,
320    s->defined, s->def_addr, s->def_size);
321 
322   while(next > 0) {
323     BoxVMSymRef *sr = (BoxVMSymRef *) BoxArr_Item_Ptr(& st->refs, next);
324     if (sr->sym_id != sym_id) {
325       fprintf(out, "Bad reference in the chain!");
326       return;
327     }
328 
329     fprintf(out,
330             "  Reference number = "SUInt"; ref_addr = "SUInt"; "
331             "ref_size = "SUInt"; resolved = %d, resolver = %p\n",
332             ref_num, sr->ref_addr,
333             sr->ref_size, sr->resolved, sr->resolver);
334 
335     next = sr->next;
336     ++ref_num;
337   }
338 }
339 
BoxVMSym_Check_Type(BoxVM * vm,BoxVMSymID sym_id,BoxUInt sym_type)340 BoxTask BoxVMSym_Check_Type(BoxVM *vm, BoxVMSymID sym_id, BoxUInt sym_type) {
341   BoxVMSymTable *st = & vm->sym_table;
342   BoxVMSym *s;
343   s = (BoxVMSym *) BoxArr_Item_Ptr(& st->defs, sym_id);
344   return (s->sym_type == sym_type) ? BOXTASK_OK : BOXTASK_FAILURE;
345 }
346 
347 typedef struct {
348   BoxVM      *vm;
349   void       *dylib;
350   const char *lib_file;
351 } MyCLibRefData;
352 
353 #ifdef DYLIB
354 static int
My_Resolve_Ref_With_CLib(BoxVMSymID sym_id,void * item,void * pass_data)355 My_Resolve_Ref_With_CLib(BoxVMSymID sym_id, void *item, void *pass_data) {
356   BoxVMSym *s = (BoxVMSym *) item;
357   if (!s->defined) {
358     MyCLibRefData *clrd = pass_data;
359     BoxVM *vm = clrd->vm;
360     if (s->sym_type == BOXVMSYMTYPE_PROC) {
361       const char *proc_name;
362       if (BoxVMSym_Proc_Is_Implemented(vm, sym_id, & proc_name)) {
363         (void) BoxVMSym_Define_Proc(vm, sym_id, NULL);
364 
365       } else {
366         const char *err_msg;
367         void *sym;
368 
369         err_msg = lt_dlerror();
370         sym = lt_dlsym(clrd->dylib, proc_name);
371         err_msg = lt_dlerror();
372 
373         if (err_msg)
374           return 1;
375 
376         if (!sym) {
377           MSG_ERROR("Symbol '%s' from library '%s' is NULL",
378                     proc_name, clrd->lib_file);
379           return 1;
380         }
381 
382         (void) BoxVMSym_Define_Proc(vm, sym_id, (BoxCCallOld) sym);
383       }
384     }
385   }
386   return 1;
387 }
388 #endif
389 
BoxVMSym_Resolve_CLib(BoxVM * vm,const char * lib_file)390 BoxTask BoxVMSym_Resolve_CLib(BoxVM *vm, const char *lib_file) {
391 #ifdef DYLIB
392   BoxVMSymTable *st = & vm->sym_table;
393   MyCLibRefData clrd;
394   clrd.vm = vm;
395   clrd.lib_file = lib_file;
396   clrd.dylib = lt_dlopenext(lib_file);
397   if (clrd.dylib == NULL)
398     return BOXTASK_FAILURE;
399   BoxArr_Push(& st->dylibs, & clrd.dylib);
400   (void) BoxArr_Iter(& st->defs, My_Resolve_Ref_With_CLib, & clrd);
401   return BOXTASK_OK;
402 #else
403   MSG_WARNING("Cannot load '%s': the virtual machine was compiled "
404               "without support for dynamic loading of libraries.", lib_file);
405   return BOXTASK_FAILURE;
406 #endif
407 }
408 
409 struct clibs_data {
410   BoxVM *vm;
411   BoxList *lib_paths;
412   char *path;
413   char *lib;
414 };
415 
416 static BoxTask
My_Iter_Over_Paths(void * string,void * pass_data)417 My_Iter_Over_Paths(void *string, void *pass_data) {
418   struct clibs_data *cld = (struct clibs_data *) pass_data;
419   char *lib_file;
420   BoxTask status;
421   cld->path = (char *) string;
422   lib_file = Box_Mem_Strdup(Box_Print("%s/lib%s", cld->path, cld->lib));
423   status = BoxVMSym_Resolve_CLib(cld->vm, lib_file);
424   Box_Mem_Free(lib_file);
425   if (status == BOXTASK_OK) return BOXTASK_FAILURE; /* Stop here, if we have found it! */
426   return BOXTASK_OK;
427 }
428 
429 static BoxTask
My_Iter_Over_Libs(void * string,void * pass_data)430 My_Iter_Over_Libs(void *string, void *pass_data) {
431   struct clibs_data *cld = (struct clibs_data *) pass_data;
432   cld->lib = (char *) string;
433   /* IS_SUCCESS is misleading: here we use BOXTASK_OK, just to continue
434    * the iteration. Therefore if we get BOXTASK_OK, it means that the library
435    * has not been found
436    */
437   if (BoxList_Iter(cld->lib_paths, My_Iter_Over_Paths, cld) == BOXTASK_OK) {
438     MSG_WARNING("'%s' <-- library has not been found or cannot be loaded!",
439                 cld->lib);
440   }
441   return BOXTASK_OK;
442 }
443 
444 
445 
446 
447 
448 
449 
450 
451 
452 
453 
454 
455 static int
My_Resolve_Own_Symbol(BoxVMSymID sym_id,void * item,void * pass)456 My_Resolve_Own_Symbol(BoxVMSymID sym_id, void *item, void *pass) {
457   BoxVM *vm = pass;
458   BoxVMSym *s = (BoxVMSym *) item;
459   if (!s->defined) {
460     if (s->sym_type == BOXVMSYMTYPE_PROC) {
461       const char *proc_name;
462       if (BoxVMSym_Proc_Is_Implemented(vm, sym_id, & proc_name))
463         (void) BoxVMSym_Define_Proc(vm, sym_id, NULL);
464 
465       else {
466       }
467     }
468   }
469   return 1;
470 }
471 
My_Resolve_Own_Symbols(BoxVM * vm)472 BoxTask My_Resolve_Own_Symbols(BoxVM *vm) {
473   BoxVMSymTable *st = & vm->sym_table;
474   (void) BoxArr_Iter(& st->defs, My_Resolve_Own_Symbol, vm);
475   return BOXTASK_OK;
476 }
477 
478 
479 
480 
481 
482 
483 
484 
BoxVMSym_Resolve_CLibs(BoxVM * vm,BoxList * lib_paths,BoxList * libs)485 BoxTask BoxVMSym_Resolve_CLibs(BoxVM *vm, BoxList *lib_paths, BoxList *libs) {
486   struct clibs_data cld;
487   (void) My_Resolve_Own_Symbols(vm);
488   cld.vm = vm;
489   cld.lib_paths = lib_paths;
490   return BoxList_Iter(libs, My_Iter_Over_Libs, & cld);
491 }
492 
493 /****************************************************************************/
494 
495 static BoxTask
My_Code_Generator(BoxVM * vm,BoxVMSymID sym_id,BoxUInt sym_type,int defined,void * def,BoxUInt def_size,void * ref,BoxUInt ref_size)496 My_Code_Generator(BoxVM *vm, BoxVMSymID sym_id, BoxUInt sym_type,
497                   int defined, void *def, BoxUInt def_size,
498                   void *ref, BoxUInt ref_size) {
499   BoxVMSymCodeRef *ref_head = (BoxVMSymCodeRef *) ref;
500   void *ref_tail = ref + sizeof(BoxVMSymCodeRef);
501   BoxUInt ref_tail_size = ref_size - sizeof(BoxVMSymCodeRef);
502   BoxVMProcTable *pt = & vm->proc_table;
503   BoxVMProc *tmp_proc;
504   BoxUInt saved_proc_num;
505 
506   saved_proc_num = BoxVM_Proc_Target_Get(vm);
507   BoxVM_Proc_Empty(vm, pt->tmp_proc);
508   BoxVM_Proc_Target_Set(vm, pt->tmp_proc);
509   tmp_proc = pt->target_proc;
510   /* Call the procedure here! */
511   BOXTASK( ref_head->code_gen(vm, sym_id, sym_type, defined,
512                            def, def_size, ref_tail, ref_tail_size) );
513   BoxVM_Proc_Target_Set(vm, ref_head->proc_num);
514   /* Replace the referencing code with the generated code */
515   {
516     void *src = BoxArr_First_Item_Ptr(& tmp_proc->code);
517     int src_size = BoxArr_Num_Items(& tmp_proc->code);
518     BoxArr *dest =  & pt->target_proc->code; /* Destination sheet */
519     int dest_pos = ref_head->pos + 1; /* NEED TO ADD 1 */
520     if (src_size != ref_head->size) {
521       MSG_ERROR("My_Code_Generator: The code for the resolved reference does "
522                 "not match the space which was reserved for it!");
523       return BOXTASK_FAILURE;
524     }
525     BoxArr_Overwrite(dest, dest_pos, src, src_size);
526   }
527   BoxVM_Proc_Target_Set(vm, saved_proc_num);
528   return BOXTASK_OK;
529 }
530 
531 BoxTask
BoxVMSym_Code_Ref(BoxVM * vm,BoxVMSymID sym_id,BoxVMSymCodeGen code_gen,void * ref,size_t ref_size)532 BoxVMSym_Code_Ref(BoxVM *vm, BoxVMSymID sym_id, BoxVMSymCodeGen code_gen,
533                   void *ref, size_t ref_size) {
534   BoxVMSymTable *st = & vm->sym_table;
535   BoxVMSym *s;
536   void *def;
537   BoxVMProcTable *pt = & vm->proc_table;
538 
539   BoxUInt ref_all_size;
540   BoxVMSymCodeRef *ref_head;
541   void *ref_all, *ref_tail;
542 
543   s = (BoxVMSym *) BoxArr_Item_Ptr(& st->defs, sym_id);
544   def = BoxArr_Item_Ptr(& st->data, s->def_addr);
545 
546   ref_all_size = sizeof(BoxVMSymCodeRef) + ref_size;
547   ref_all = Box_Mem_Safe_Alloc(ref_all_size);
548   ref_head = (BoxVMSymCodeRef *) ref_all;
549   ref_tail = ref_all + sizeof(BoxVMSymCodeRef);
550 
551   /* fill the section describing the code */
552   ref_head->code_gen = code_gen;
553   ref_head->proc_num = pt->target_proc_num;
554   ref_head->pos = BoxArr_Num_Items(& pt->target_proc->code);
555 
556   /* Copy the user provided reference data */
557   if (ref != NULL && ref_size > 0)
558     (void) memcpy(ref_tail, ref, ref_size);
559 
560   BOXTASK( code_gen(vm, sym_id, s->sym_type, s->defined, def, s->def_size,
561                  ref, ref_size) );
562   if (pt->target_proc_num != ref_head->proc_num) {
563     MSG_ERROR("BoxVMSym_Code_Ref: the function 'code_gen' must not change "
564               "the current target for compilation!");
565   }
566   ref_head->size = BoxArr_Num_Items(& pt->target_proc->code) - ref_head->pos;
567   BoxVMSym_Ref(vm, sym_id, My_Code_Generator, ref_all, ref_all_size, -1);
568   Box_Mem_Free(ref_all);
569   return BOXTASK_OK;
570 }
571 
572 #if 0
573 /* Usage for the function 'BoxVMSym_Code_Ref' */
574 
575 #  define CALL_TYPE 1
576 
577 /* This is the function which assembles the code for the function call */
578 BoxTask Assemble_Call(BoxVM *vm, BoxVMSymID sym_id, BoxUInt sym_type,
579                       int defined, void *def, BoxUInt def_size,
580                       void *ref, BoxUInt ref_size) {
581   BoxUInt call_num = 0;
582   assert(sym_type == CALL_TYPE);
583   if (defined && def != NULL) {
584     assert(def_size=sizeof(BoxUInt));
585     call_num = *((BoxUInt *) def);
586   }
587   BoxVM_Assemble(vm, ASM_CALL_I, CAT_IMM, call_num);
588   return BOXTASK_OK;
589 }
590 
591 int main(void) {
592   BoxVMSymID sym_id;
593   BoxVM *vm;
594   /* Initialization of the VM goes here
595    ...
596    ...
597    */
598 
599   /* Here we define that a new symbol with type CALL_TYPE=1 exists */
600   (void) BoxVMSym_New(vm, & sym_id, CALL_TYPE, sizeof(BoxUInt));
601   /* Here we make a reference to it: at this point the assembled code for
602    * "call 0" will be added to the current target procedure.
603    * 0 is wrong, but we don't know what is the right number, because
604    * the symbol is still not defined.
605    */
606   (void) BoxVMSym_Code_Ref(vm, sym_id, Assemble_Call);
607   /* Here we define the symbol "my_proc" to be (BoxUInt) 123.
608    * Now we know that all the "call" instructions referencing
609    * the symbol "my_proc" should be assembled with "call 123"
610    */
611   (void) BoxVMSym_Def(vm, sym_id, & ((BoxUInt) 123));
612   /* We can now resolve all the past references which were made when
613    * we were not aware of the real value of "my_proc".
614    * The code "call 0" will be replaced with "call 123"
615    */
616   (void) BoxVMSym_Resolve_All(vm);
617   return 0;
618 }
619 #endif
620