labels.c
上传用户:yuppie_zhu
上传日期:2007-01-08
资源大小:535k
文件大小:12k
源码类别:

编译器/解释器

开发平台:

C/C++

  1. /* labels.c  label handling for the Netwide Assembler
  2.  *
  3.  * The Netwide Assembler is copyright (C) 1996 Simon Tatham and
  4.  * Julian Hall. All rights reserved. The software is
  5.  * redistributable under the licence given in the file "Licence"
  6.  * distributed in the NASM archive.
  7.  */
  8. #include <stdio.h>
  9. #include <string.h>
  10. #include <stdlib.h>
  11. #include "nasm.h"
  12. #include "nasmlib.h"
  13. /*
  14.  * A local label is one that begins with exactly one period. Things
  15.  * that begin with _two_ periods are NASM-specific things.
  16.  */
  17. #define islocal(l) ((l)[0] == '.' && (l)[1] != '.')
  18. #define LABEL_BLOCK  320        /* no. of labels/block */
  19. #define LBLK_SIZE    (LABEL_BLOCK*sizeof(union label))
  20. #define LABEL_HASHES 32        /* no. of hash table entries */
  21. #define END_LIST -3        /* don't clash with NO_SEG! */
  22. #define END_BLOCK -2
  23. #define BOGUS_VALUE -4
  24. #define PERMTS_SIZE  4096        /* size of text blocks */
  25. /* values for label.defn.is_global */
  26. #define DEFINED_BIT 1
  27. #define GLOBAL_BIT 2
  28. #define EXTERN_BIT 4
  29. #define NOT_DEFINED_YET 0
  30. #define TYPE_MASK 3
  31. #define LOCAL_SYMBOL (DEFINED_BIT)
  32. #define GLOBAL_PLACEHOLDER (GLOBAL_BIT)
  33. #define GLOBAL_SYMBOL (DEFINED_BIT|GLOBAL_BIT)
  34. union label {        /* actual label structures */
  35.     struct {
  36. long segment, offset;
  37.         char *label, *special;
  38. int is_global, is_norm;
  39.     } defn;
  40.     struct {
  41. long movingon, dummy;
  42. union label *next;
  43.     } admin;
  44. };
  45. struct permts {        /* permanent text storage */
  46.     struct permts *next;        /* for the linked list */
  47.     int size, usage;        /* size and used space in ... */
  48.     char data[PERMTS_SIZE];        /* ... the data block itself */
  49. };
  50. static union label *ltab[LABEL_HASHES];/* using a hash table */
  51. static union label *lfree[LABEL_HASHES];/* pointer into the above */
  52. static struct permts *perm_head;      /* start of perm. text storage */
  53. static struct permts *perm_tail;      /* end of perm. text storage */
  54. static void init_block (union label *blk);
  55. static char *perm_copy (char *string1, char *string2);
  56. static char *prevlabel;
  57. static int initialised = FALSE;
  58. /*
  59.  * Internal routine: finds the `union label' corresponding to the
  60.  * given label name. Creates a new one, if it isn't found, and if
  61.  * `create' is TRUE.
  62.  */
  63. static union label *find_label (char *label, int create) 
  64. {
  65.     int hash = 0;
  66.     char *p, *prev;
  67.     int prevlen;
  68.     union label *lptr;
  69.     if (islocal(label))
  70. prev = prevlabel;
  71.     else
  72. prev = "";
  73.     prevlen = strlen(prev);
  74.     p = prev;
  75.     while (*p) hash += *p++;
  76.     p = label;
  77.     while (*p) hash += *p++;
  78.     hash %= LABEL_HASHES;
  79.     lptr = ltab[hash];
  80.     while (lptr->admin.movingon != END_LIST) {
  81. if (lptr->admin.movingon == END_BLOCK) {
  82.     lptr = lptr->admin.next;
  83.     if (!lptr)
  84. break;
  85. }
  86. if (!strncmp(lptr->defn.label, prev, prevlen) &&
  87.     !strcmp(lptr->defn.label+prevlen, label))
  88.     return lptr;
  89. lptr++;
  90.     }
  91.     if (create) {
  92. if (lfree[hash]->admin.movingon == END_BLOCK) {
  93.     /*
  94.      * must allocate a new block
  95.      */
  96.     lfree[hash]->admin.next = (union label *) nasm_malloc (LBLK_SIZE);
  97.     lfree[hash] = lfree[hash]->admin.next;
  98.     init_block(lfree[hash]);
  99. }
  100. lfree[hash]->admin.movingon = BOGUS_VALUE;
  101. lfree[hash]->defn.label = perm_copy (prev, label);
  102. lfree[hash]->defn.special = NULL;
  103. lfree[hash]->defn.is_global = NOT_DEFINED_YET;
  104. return lfree[hash]++;
  105.     } 
  106.     else
  107. return NULL;
  108. }
  109. int lookup_label (char *label, long *segment, long *offset) 
  110. {
  111.     union label *lptr;
  112.     if (!initialised)
  113. return 0;
  114.     lptr = find_label (label, 0);
  115.     if (lptr && (lptr->defn.is_global & DEFINED_BIT)) {
  116. *segment = lptr->defn.segment;
  117. *offset = lptr->defn.offset;
  118. return 1;
  119.     } 
  120.     else
  121. return 0;
  122. }
  123. int is_extern (char *label) 
  124. {
  125.     union label *lptr;
  126.     if (!initialised)
  127. return 0;
  128.     lptr = find_label (label, 0);
  129.     if (lptr && (lptr->defn.is_global & EXTERN_BIT))
  130. return 1;
  131.     else
  132. return 0;
  133. }
  134. void redefine_label (char *label, long segment, long offset, char *special,
  135.    int is_norm, int isextrn, struct ofmt *ofmt, efunc error) 
  136. {
  137.     union label *lptr;
  138.     /* This routine possibly ought to check for phase errors.  Most assemblers
  139.      * check for phase errors at this point.  I don't know whether phase errors
  140.      * are even possible, nor whether they are checked somewhere else
  141.      */
  142.     (void) segment;  /* Don't warn that this parameter is unused */
  143.     (void) offset;   /* Don't warn that this parameter is unused */
  144.     (void) special;  /* Don't warn that this parameter is unused */
  145.     (void) is_norm;  /* Don't warn that this parameter is unused */
  146.     (void) isextrn;  /* Don't warn that this parameter is unused */
  147.     (void) ofmt;     /* Don't warn that this parameter is unused */
  148. #ifdef DEBUG
  149.     if (!strncmp(label, "debugdump", 9))
  150. fprintf(stderr, "debug: redefine_label (%s, %ld, %08lx, %s, %d, %d)n",
  151. label, segment, offset, special, is_norm, isextrn);
  152. #endif
  153.     if (!islocal(label)) {
  154. lptr = find_label (label, 1);
  155. if (!lptr)
  156.     error (ERR_PANIC, "can't find label `%s' on pass two", label);
  157. if (*label != '.' && lptr->defn.is_norm)
  158.     prevlabel = lptr->defn.label;
  159.     }
  160. }
  161. void define_label (char *label, long segment, long offset, char *special,
  162.    int is_norm, int isextrn, struct ofmt *ofmt, efunc error) 
  163. {
  164.     union label *lptr;
  165. #ifdef DEBUG
  166.     if (!strncmp(label, "debugdump", 9))
  167. fprintf(stderr, "debug: define_label (%s, %ld, %08lx, %s, %d, %d)n",
  168. label, segment, offset, special, is_norm, isextrn);
  169. #endif
  170.     lptr = find_label (label, 1);
  171.     if (lptr->defn.is_global & DEFINED_BIT) {
  172. error(ERR_NONFATAL, "symbol `%s' redefined", label);
  173. return;
  174.     }
  175.     lptr->defn.is_global |= DEFINED_BIT;
  176.     if (isextrn)
  177. lptr->defn.is_global |= EXTERN_BIT;
  178.     if (label[0] != '.' && is_norm)    /* not local, but not special either */
  179. prevlabel = lptr->defn.label;
  180.     else if (label[0] == '.' && label[1] != '.' && !*prevlabel)
  181. error(ERR_NONFATAL, "attempt to define a local label before any"
  182.       " non-local labels");
  183.     lptr->defn.segment = segment;
  184.     lptr->defn.offset = offset;
  185.     lptr->defn.is_norm = (label[0] != '.' && is_norm);
  186.     if ( (lptr->defn.is_global & (GLOBAL_BIT|EXTERN_BIT)) != EXTERN_BIT ) {
  187.       ofmt->symdef (lptr->defn.label, segment, offset,
  188.     !!(lptr->defn.is_global & GLOBAL_BIT),
  189.     special ? special : lptr->defn.special);
  190.       ofmt->current_dfmt->debug_deflabel (label, segment, offset,
  191.     !!(lptr->defn.is_global & GLOBAL_BIT),
  192.     special ? special : lptr->defn.special);
  193.     }
  194. }
  195. void define_common (char *label, long segment, long size, char *special,
  196.     struct ofmt *ofmt, efunc error) 
  197. {
  198.     union label *lptr;
  199.     lptr = find_label (label, 1);
  200.     if (lptr->defn.is_global & DEFINED_BIT) {
  201. error(ERR_NONFATAL, "symbol `%s' redefined", label);
  202. return;
  203.     }
  204.     lptr->defn.is_global |= DEFINED_BIT;
  205.     if (label[0] != '.')        /* not local, but not special either */
  206. prevlabel = lptr->defn.label;
  207.     else
  208. error(ERR_NONFATAL, "attempt to define a local label as a "
  209.       "common variable");
  210.     lptr->defn.segment = segment;
  211.     lptr->defn.offset = 0;
  212.     ofmt->symdef (lptr->defn.label, segment, size, 2,
  213.   special ? special : lptr->defn.special);
  214.     ofmt->current_dfmt->debug_deflabel(lptr->defn.label, segment, size, 2,
  215.   special ? special : lptr->defn.special);
  216. }
  217. void declare_as_global (char *label, char *special, efunc error) 
  218. {
  219.     union label *lptr;
  220.     if (islocal(label)) {
  221. error(ERR_NONFATAL, "attempt to declare local symbol `%s' as"
  222.       " global", label);
  223. return;
  224.     }
  225.     lptr = find_label (label, 1);
  226.     switch (lptr->defn.is_global & TYPE_MASK) {
  227.       case NOT_DEFINED_YET:
  228. lptr->defn.is_global = GLOBAL_PLACEHOLDER;
  229. lptr->defn.special = special ? perm_copy(special, "") : NULL;
  230. break;
  231.       case GLOBAL_PLACEHOLDER:        /* already done: silently ignore */
  232.       case GLOBAL_SYMBOL:
  233. break;
  234.       case LOCAL_SYMBOL:
  235. if (!lptr->defn.is_global & EXTERN_BIT)
  236.     error(ERR_NONFATAL, "symbol `%s': GLOBAL directive must"
  237.   " appear before symbol definition", label);
  238. break;
  239.     }
  240. }
  241. int init_labels (void) 
  242. {
  243.     int i;
  244.     for (i=0; i<LABEL_HASHES; i++) {
  245. ltab[i] = (union label *) nasm_malloc (LBLK_SIZE);
  246. if (!ltab[i])
  247.     return -1;        /* can't initialise, panic */
  248. init_block (ltab[i]);
  249. lfree[i] = ltab[i];
  250.     }
  251.     perm_head = 
  252. perm_tail = (struct permts *) nasm_malloc (sizeof(struct permts));
  253.     if (!perm_head)
  254.      return -1;
  255.     perm_head->next = NULL;
  256.     perm_head->size = PERMTS_SIZE;
  257.     perm_head->usage = 0;
  258.     prevlabel = "";
  259.     initialised = TRUE;
  260.     return 0;
  261. }
  262. void cleanup_labels (void) 
  263. {
  264.     int i;
  265.     initialised = FALSE;
  266.     for (i=0; i<LABEL_HASHES; i++) {
  267. union label *lptr, *lhold;
  268. lptr = lhold = ltab[i];
  269. while (lptr) {
  270.     while (lptr->admin.movingon != END_BLOCK) lptr++;
  271.     lptr = lptr->admin.next;
  272.     nasm_free (lhold);
  273.     lhold = lptr;
  274. }
  275.     }
  276.     while (perm_head) {
  277. perm_tail = perm_head;
  278. perm_head = perm_head->next;
  279. nasm_free (perm_tail);
  280.     }
  281. }
  282. static void init_block (union label *blk) 
  283. {
  284.     int j;
  285.     for (j=0; j<LABEL_BLOCK-1; j++)
  286.      blk[j].admin.movingon = END_LIST;
  287.     blk[LABEL_BLOCK-1].admin.movingon = END_BLOCK;
  288.     blk[LABEL_BLOCK-1].admin.next = NULL;
  289. }
  290. static char *perm_copy (char *string1, char *string2) 
  291. {
  292.     char *p, *q;
  293.     int len = strlen(string1)+strlen(string2)+1;
  294.     if (perm_tail->size - perm_tail->usage < len) {
  295. perm_tail->next = (struct permts *)nasm_malloc(sizeof(struct permts));
  296. perm_tail = perm_tail->next;
  297. perm_tail->next = NULL;
  298. perm_tail->size = PERMTS_SIZE;
  299. perm_tail->usage = 0;
  300.     }
  301.     p = q = perm_tail->data + perm_tail->usage;
  302.     while ( (*q = *string1++) ) q++;
  303.     while ( (*q++ = *string2++) ) ;
  304.     perm_tail->usage = q - perm_tail->data;
  305.     return p;
  306. }
  307. /*
  308.  * Notes regarding bug involving redefinition of external segments.
  309.  *
  310.  * Up to and including v0.97, the following code didn't work. From 0.97
  311.  * developers release 2 onwards, it will generate an error.
  312.  *
  313.  * EXTERN extlabel
  314.  * newlabel EQU extlabel + 1
  315.  *
  316.  * The results of allowing this code through are that two import records
  317.  * are generated, one for 'extlabel' and one for 'newlabel'.
  318.  *
  319.  * The reason for this is an inadequacy in the defined interface between
  320.  * the label manager and the output formats. The problem lies in how the
  321.  * output format driver tells that a label is an external label for which
  322.  * a label import record must be produced. Most (all except bin?) produce
  323.  * the record if the segment number of the label is not one of the internal
  324.  * segments that the output driver is producing.
  325.  *
  326.  * A simple fix to this would be to make the output formats keep track of
  327.  * which symbols they've produced import records for, and make them not
  328.  * produce import records for segments that are already defined.
  329.  *
  330.  * The best way, which is slightly harder but reduces duplication of code
  331.  * and should therefore make the entire system smaller and more stable is
  332.  * to change the interface between assembler, define_label(), and
  333.  * the output module. The changes that are needed are:
  334.  *
  335.  * The semantics of the 'isextern' flag passed to define_label() need
  336.  * examining. This information may or may not tell us what we need to
  337.  * know (ie should we be generating an import record at this point for this
  338.  * label). If these aren't the semantics, the semantics should be changed
  339.  * to this.
  340.  *
  341.  * The output module interface needs changing, so that the `isextern' flag
  342.  * is passed to the module, so that it can be easily tested for.
  343.  */