1 /* labels.c label handling for the Netwide Assembler
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.
16 * A local label is one that begins with exactly one period. Things
17 * that begin with _two_ periods are NASM-specific things.
19 * If TASM compatibility is enabled, a local label can also begin with
20 * @@, so @@local is a TASM compatible local label. Note that we only
21 * check for the first @ symbol, although TASM requires both.
25 (tasm_compatible_mode ? \
26 (((l)[0] == '.' || (l)[0] == '@') && (l)[1] != '.') : \
27 ((l)[0] == '.' && (l)[1] != '.'))
28 #define islocalchar(c) \
29 (tasm_compatible_mode ? \
30 ((c) == '.' || (c) == '@') : \
33 #define islocal(l) ((l)[0] == '.' && (l)[1] != '.')
34 #define islocalchar(c) ((c) == '.')
37 #define LABEL_BLOCK 32 /* no. of labels/block */
38 #define LBLK_SIZE (LABEL_BLOCK*sizeof(union label))
39 #define LABEL_HASHES 37 /* no. of hash table entries */
41 #define END_LIST -3 /* don't clash with NO_SEG! */
43 #define BOGUS_VALUE -4
45 #define PERMTS_SIZE 4096 /* size of text blocks */
47 /* values for label.defn.is_global */
52 #define NOT_DEFINED_YET 0
54 #define LOCAL_SYMBOL (DEFINED_BIT)
55 #define GLOBAL_PLACEHOLDER (GLOBAL_BIT)
56 #define GLOBAL_SYMBOL (DEFINED_BIT|GLOBAL_BIT)
58 union label
{ /* actual label structures */
61 char *label
, *special
;
62 int is_global
, is_norm
;
70 struct permts
{ /* permanent text storage */
71 struct permts
*next
; /* for the linked list */
72 int size
, usage
; /* size and used space in ... */
73 char data
[PERMTS_SIZE
]; /* ... the data block itself */
76 extern int global_offset_changed
; /* defined in nasm.c */
78 static union label
*ltab
[LABEL_HASHES
];/* using a hash table */
79 static union label
*lfree
[LABEL_HASHES
];/* pointer into the above */
80 static struct permts
*perm_head
; /* start of perm. text storage */
81 static struct permts
*perm_tail
; /* end of perm. text storage */
83 static void init_block (union label
*blk
);
84 static char *perm_copy (char *string1
, char *string2
);
86 static char *prevlabel
;
88 static int initialised
= FALSE
;
90 char lprefix
[PREFIX_MAX
] = {0};
91 char lpostfix
[PREFIX_MAX
] = {0};
94 * Internal routine: finds the `union label' corresponding to the
95 * given label name. Creates a new one, if it isn't found, and if
98 static union label
*find_label (char *label
, int create
)
109 prevlen
= strlen(prev
);
111 while (*p
) hash
+= *p
++;
113 while (*p
) hash
+= *p
++;
114 hash
%= LABEL_HASHES
;
116 while (lptr
->admin
.movingon
!= END_LIST
) {
117 if (lptr
->admin
.movingon
== END_BLOCK
) {
118 lptr
= lptr
->admin
.next
;
122 if (!strncmp(lptr
->defn
.label
, prev
, prevlen
) &&
123 !strcmp(lptr
->defn
.label
+prevlen
, label
))
128 if (lfree
[hash
]->admin
.movingon
== END_BLOCK
) {
130 * must allocate a new block
132 lfree
[hash
]->admin
.next
= (union label
*) nasm_malloc (LBLK_SIZE
);
133 lfree
[hash
] = lfree
[hash
]->admin
.next
;
134 init_block(lfree
[hash
]);
137 lfree
[hash
]->admin
.movingon
= BOGUS_VALUE
;
138 lfree
[hash
]->defn
.label
= perm_copy (prev
, label
);
139 lfree
[hash
]->defn
.special
= NULL
;
140 lfree
[hash
]->defn
.is_global
= NOT_DEFINED_YET
;
141 return lfree
[hash
]++;
147 int lookup_label (char *label
, long *segment
, long *offset
)
154 lptr
= find_label (label
, 0);
155 if (lptr
&& (lptr
->defn
.is_global
& DEFINED_BIT
)) {
156 *segment
= lptr
->defn
.segment
;
157 *offset
= lptr
->defn
.offset
;
164 int is_extern (char *label
)
171 lptr
= find_label (label
, 0);
172 if (lptr
&& (lptr
->defn
.is_global
& EXTERN_BIT
))
178 void redefine_label (char *label
, long segment
, long offset
, char *special
,
179 int is_norm
, int isextrn
, struct ofmt
*ofmt
, efunc error
)
184 /* This routine possibly ought to check for phase errors. Most assemblers
185 * check for phase errors at this point. I don't know whether phase errors
186 * are even possible, nor whether they are checked somewhere else
189 (void) segment
; /* Don't warn that this parameter is unused */
190 (void) special
; /* Don't warn that this parameter is unused */
191 (void) is_norm
; /* Don't warn that this parameter is unused */
192 (void) isextrn
; /* Don't warn that this parameter is unused */
193 (void) ofmt
; /* Don't warn that this parameter is unused */
197 if (!strncmp(label
, "debugdump", 9))
199 error(ERR_DEBUG
, "redefine_label (%s, %ld, %08lx, %s, %d, %d)",
200 label
, segment
, offset
, special
, is_norm
, isextrn
);
203 lptr
= find_label (label
, 1);
205 error (ERR_PANIC
, "can't find label `%s' on pass two", label
);
207 if (!islocal(label
)) {
208 if (!islocalchar(*label
) && lptr
->defn
.is_norm
)
209 prevlabel
= lptr
->defn
.label
;
212 global_offset_changed
|= (lptr
->defn
.offset
!= offset
);
213 lptr
->defn
.offset
= offset
;
216 exi
= !!(lptr
->defn
.is_global
& GLOBAL_BIT
);
221 slen
= strlen(lprefix
);
222 slen
+= strlen(lptr
->defn
.label
);
223 slen
+= strlen(lpostfix
);
224 slen
++; /* room for that null char */
225 xsymbol
= nasm_malloc(slen
);
226 sprintf(xsymbol
,"%s%s%s",lprefix
,lptr
->defn
.label
,lpostfix
);
228 ofmt
->symdef (xsymbol
, segment
, offset
, exi
,
229 special
? special
: lptr
->defn
.special
);
230 ofmt
->current_dfmt
->debug_deflabel (xsymbol
, segment
, offset
, exi
,
231 special
? special
: lptr
->defn
.special
);
232 /** nasm_free(xsymbol); ! outobj.c stores the pointer; ouch!!! **/
236 if ( (lptr
->defn
.is_global
& (GLOBAL_BIT
|EXTERN_BIT
)) != EXTERN_BIT
) {
237 ofmt
->symdef (lptr
->defn
.label
, segment
, offset
, exi
,
238 special
? special
: lptr
->defn
.special
);
239 ofmt
->current_dfmt
->debug_deflabel (label
, segment
, offset
, exi
,
240 special
? special
: lptr
->defn
.special
);
243 } /* if (pass0 == 1) */
247 void define_label (char *label
, long segment
, long offset
, char *special
,
248 int is_norm
, int isextrn
, struct ofmt
*ofmt
, efunc error
)
255 if (!strncmp(label
, "debugdump", 9))
257 error(ERR_DEBUG
, "define_label (%s, %ld, %08lx, %s, %d, %d)",
258 label
, segment
, offset
, special
, is_norm
, isextrn
);
260 lptr
= find_label (label
, 1);
261 if (lptr
->defn
.is_global
& DEFINED_BIT
) {
262 error(ERR_NONFATAL
, "symbol `%s' redefined", label
);
265 lptr
->defn
.is_global
|= DEFINED_BIT
;
267 lptr
->defn
.is_global
|= EXTERN_BIT
;
269 if (!islocalchar(label
[0]) && is_norm
) /* not local, but not special either */
270 prevlabel
= lptr
->defn
.label
;
271 else if (islocal(label
) && !*prevlabel
) {
272 error(ERR_NONFATAL
, "attempt to define a local label before any"
273 " non-local labels");
276 lptr
->defn
.segment
= segment
;
277 lptr
->defn
.offset
= offset
;
278 lptr
->defn
.is_norm
= (!islocalchar(label
[0]) && is_norm
);
280 if (pass0
== 1 || (!is_norm
&& !isextrn
&& (segment
&1))) {
281 exi
= !!(lptr
->defn
.is_global
& GLOBAL_BIT
);
286 slen
= strlen(lprefix
);
287 slen
+= strlen(lptr
->defn
.label
);
288 slen
+= strlen(lpostfix
);
289 slen
++; /* room for that null char */
290 xsymbol
= nasm_malloc(slen
);
291 sprintf(xsymbol
,"%s%s%s",lprefix
,lptr
->defn
.label
,lpostfix
);
293 ofmt
->symdef (xsymbol
, segment
, offset
, exi
,
294 special
? special
: lptr
->defn
.special
);
295 ofmt
->current_dfmt
->debug_deflabel (xsymbol
, segment
, offset
, exi
,
296 special
? special
: lptr
->defn
.special
);
297 /** nasm_free(xsymbol); ! outobj.c stores the pointer; ouch!!! **/
301 if ( (lptr
->defn
.is_global
& (GLOBAL_BIT
|EXTERN_BIT
)) != EXTERN_BIT
) {
302 ofmt
->symdef (lptr
->defn
.label
, segment
, offset
, exi
,
303 special
? special
: lptr
->defn
.special
);
304 ofmt
->current_dfmt
->debug_deflabel (label
, segment
, offset
, exi
,
305 special
? special
: lptr
->defn
.special
);
308 } /* if (pass0 == 1) */
311 void define_common (char *label
, long segment
, long size
, char *special
,
312 struct ofmt
*ofmt
, efunc error
)
316 lptr
= find_label (label
, 1);
317 if (lptr
->defn
.is_global
& DEFINED_BIT
) {
318 error(ERR_NONFATAL
, "symbol `%s' redefined", label
);
321 lptr
->defn
.is_global
|= DEFINED_BIT
;
323 if (!islocalchar(label
[0])) /* not local, but not special either */
324 prevlabel
= lptr
->defn
.label
;
326 error(ERR_NONFATAL
, "attempt to define a local label as a "
329 lptr
->defn
.segment
= segment
;
330 lptr
->defn
.offset
= 0;
332 ofmt
->symdef (lptr
->defn
.label
, segment
, size
, 2,
333 special
? special
: lptr
->defn
.special
);
334 ofmt
->current_dfmt
->debug_deflabel(lptr
->defn
.label
, segment
, size
, 2,
335 special
? special
: lptr
->defn
.special
);
338 void declare_as_global (char *label
, char *special
, efunc error
)
342 if (islocal(label
)) {
343 error(ERR_NONFATAL
, "attempt to declare local symbol `%s' as"
347 lptr
= find_label (label
, 1);
348 switch (lptr
->defn
.is_global
& TYPE_MASK
) {
349 case NOT_DEFINED_YET
:
350 lptr
->defn
.is_global
= GLOBAL_PLACEHOLDER
;
351 lptr
->defn
.special
= special
? perm_copy(special
, "") : NULL
;
353 case GLOBAL_PLACEHOLDER
: /* already done: silently ignore */
357 if (!lptr
->defn
.is_global
& EXTERN_BIT
)
358 error(ERR_NONFATAL
, "symbol `%s': GLOBAL directive must"
359 " appear before symbol definition", label
);
364 int init_labels (void)
368 for (i
=0; i
<LABEL_HASHES
; i
++) {
369 ltab
[i
] = (union label
*) nasm_malloc (LBLK_SIZE
);
371 return -1; /* can't initialise, panic */
372 init_block (ltab
[i
]);
377 perm_tail
= (struct permts
*) nasm_malloc (sizeof(struct permts
));
382 perm_head
->next
= NULL
;
383 perm_head
->size
= PERMTS_SIZE
;
384 perm_head
->usage
= 0;
393 void cleanup_labels (void)
399 for (i
=0; i
<LABEL_HASHES
; i
++) {
400 union label
*lptr
, *lhold
;
402 lptr
= lhold
= ltab
[i
];
405 while (lptr
->admin
.movingon
!= END_BLOCK
) lptr
++;
406 lptr
= lptr
->admin
.next
;
413 perm_tail
= perm_head
;
414 perm_head
= perm_head
->next
;
415 nasm_free (perm_tail
);
419 static void init_block (union label
*blk
)
423 for (j
=0; j
<LABEL_BLOCK
-1; j
++)
424 blk
[j
].admin
.movingon
= END_LIST
;
425 blk
[LABEL_BLOCK
-1].admin
.movingon
= END_BLOCK
;
426 blk
[LABEL_BLOCK
-1].admin
.next
= NULL
;
429 static char *perm_copy (char *string1
, char *string2
)
432 int len
= strlen(string1
)+strlen(string2
)+1;
434 if (perm_tail
->size
- perm_tail
->usage
< len
) {
435 perm_tail
->next
= (struct permts
*)nasm_malloc(sizeof(struct permts
));
436 perm_tail
= perm_tail
->next
;
437 perm_tail
->next
= NULL
;
438 perm_tail
->size
= PERMTS_SIZE
;
439 perm_tail
->usage
= 0;
441 p
= q
= perm_tail
->data
+ perm_tail
->usage
;
442 while ( (*q
= *string1
++) ) q
++;
443 while ( (*q
++ = *string2
++) ) ;
444 perm_tail
->usage
= q
- perm_tail
->data
;
450 * Notes regarding bug involving redefinition of external segments.
452 * Up to and including v0.97, the following code didn't work. From 0.97
453 * developers release 2 onwards, it will generate an error.
456 * newlabel EQU extlabel + 1
458 * The results of allowing this code through are that two import records
459 * are generated, one for 'extlabel' and one for 'newlabel'.
461 * The reason for this is an inadequacy in the defined interface between
462 * the label manager and the output formats. The problem lies in how the
463 * output format driver tells that a label is an external label for which
464 * a label import record must be produced. Most (all except bin?) produce
465 * the record if the segment number of the label is not one of the internal
466 * segments that the output driver is producing.
468 * A simple fix to this would be to make the output formats keep track of
469 * which symbols they've produced import records for, and make them not
470 * produce import records for segments that are already defined.
472 * The best way, which is slightly harder but reduces duplication of code
473 * and should therefore make the entire system smaller and more stable is
474 * to change the interface between assembler, define_label(), and
475 * the output module. The changes that are needed are:
477 * The semantics of the 'isextern' flag passed to define_label() need
478 * examining. This information may or may not tell us what we need to
479 * know (ie should we be generating an import record at this point for this
480 * label). If these aren't the semantics, the semantics should be changed
483 * The output module interface needs changing, so that the `isextern' flag
484 * is passed to the module, so that it can be easily tested for.