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 #define islocal(l) ((l)[0] == '.' && (l)[1] != '.')
21 #define LABEL_BLOCK 320 /* no. of labels/block */
22 #define LBLK_SIZE (LABEL_BLOCK*sizeof(union label))
23 #define LABEL_HASHES 32 /* no. of hash table entries */
25 #define END_LIST -3 /* don't clash with NO_SEG! */
27 #define BOGUS_VALUE -4
29 #define PERMTS_SIZE 4096 /* size of text blocks */
31 /* values for label.defn.is_global */
36 #define NOT_DEFINED_YET 0
38 #define LOCAL_SYMBOL (DEFINED_BIT)
39 #define GLOBAL_PLACEHOLDER (GLOBAL_BIT)
40 #define GLOBAL_SYMBOL (DEFINED_BIT|GLOBAL_BIT)
42 union label
{ /* actual label structures */
45 char *label
, *special
;
54 struct permts
{ /* permanent text storage */
55 struct permts
*next
; /* for the linked list */
56 int size
, usage
; /* size and used space in ... */
57 char data
[PERMTS_SIZE
]; /* ... the data block itself */
60 static union label
*ltab
[LABEL_HASHES
];/* using a hash table */
61 static union label
*lfree
[LABEL_HASHES
];/* pointer into the above */
62 static struct permts
*perm_head
; /* start of perm. text storage */
63 static struct permts
*perm_tail
; /* end of perm. text storage */
65 static void init_block (union label
*blk
);
66 static char *perm_copy (char *string1
, char *string2
);
68 static char *prevlabel
;
70 static int initialised
= FALSE
;
73 * Internal routine: finds the `union label' corresponding to the
74 * given label name. Creates a new one, if it isn't found, and if
77 static union label
*find_label (char *label
, int create
) {
87 prevlen
= strlen(prev
);
89 while (*p
) hash
+= *p
++;
91 while (*p
) hash
+= *p
++;
94 while (lptr
->admin
.movingon
!= END_LIST
) {
95 if (lptr
->admin
.movingon
== END_BLOCK
) {
96 lptr
= lptr
->admin
.next
;
100 if (!strncmp(lptr
->defn
.label
, prev
, prevlen
) &&
101 !strcmp(lptr
->defn
.label
+prevlen
, label
))
106 if (lfree
[hash
]->admin
.movingon
== END_BLOCK
) {
108 * must allocate a new block
110 lfree
[hash
]->admin
.next
= (union label
*) nasm_malloc (LBLK_SIZE
);
111 lfree
[hash
] = lfree
[hash
]->admin
.next
;
112 init_block(lfree
[hash
]);
115 lfree
[hash
]->admin
.movingon
= BOGUS_VALUE
;
116 lfree
[hash
]->defn
.label
= perm_copy (prev
, label
);
117 lfree
[hash
]->defn
.special
= NULL
;
118 lfree
[hash
]->defn
.is_global
= NOT_DEFINED_YET
;
119 return lfree
[hash
]++;
124 int lookup_label (char *label
, long *segment
, long *offset
) {
130 lptr
= find_label (label
, 0);
131 if (lptr
&& (lptr
->defn
.is_global
& DEFINED_BIT
)) {
132 *segment
= lptr
->defn
.segment
;
133 *offset
= lptr
->defn
.offset
;
139 int is_extern (char *label
) {
145 lptr
= find_label (label
, 0);
146 if (lptr
&& (lptr
->defn
.is_global
& EXTERN_BIT
))
152 void define_label_stub (char *label
, efunc error
) {
155 if (!islocal(label
)) {
156 lptr
= find_label (label
, 1);
158 error (ERR_PANIC
, "can't find label `%s' on pass two", label
);
160 prevlabel
= lptr
->defn
.label
;
164 void define_label (char *label
, long segment
, long offset
, char *special
,
165 int is_norm
, int isextrn
, struct ofmt
*ofmt
, efunc error
) {
168 lptr
= find_label (label
, 1);
169 if (lptr
->defn
.is_global
& DEFINED_BIT
) {
170 error(ERR_NONFATAL
, "symbol `%s' redefined", label
);
173 lptr
->defn
.is_global
|= DEFINED_BIT
;
175 lptr
->defn
.is_global
|= EXTERN_BIT
;
177 if (label
[0] != '.' && is_norm
) /* not local, but not special either */
178 prevlabel
= lptr
->defn
.label
;
179 else if (label
[0] == '.' && label
[1] != '.' && !*prevlabel
)
180 error(ERR_NONFATAL
, "attempt to define a local label before any"
181 " non-local labels");
183 lptr
->defn
.segment
= segment
;
184 lptr
->defn
.offset
= offset
;
186 ofmt
->symdef (lptr
->defn
.label
, segment
, offset
,
187 !!(lptr
->defn
.is_global
& GLOBAL_BIT
),
188 special
? special
: lptr
->defn
.special
);
191 void define_common (char *label
, long segment
, long size
, char *special
,
192 struct ofmt
*ofmt
, efunc error
) {
195 lptr
= find_label (label
, 1);
196 if (lptr
->defn
.is_global
& DEFINED_BIT
) {
197 error(ERR_NONFATAL
, "symbol `%s' redefined", label
);
200 lptr
->defn
.is_global
|= DEFINED_BIT
;
202 if (label
[0] != '.') /* not local, but not special either */
203 prevlabel
= lptr
->defn
.label
;
205 error(ERR_NONFATAL
, "attempt to define a local label as a "
208 lptr
->defn
.segment
= segment
;
209 lptr
->defn
.offset
= 0;
211 ofmt
->symdef (lptr
->defn
.label
, segment
, size
, 2,
212 special
? special
: lptr
->defn
.special
);
215 void declare_as_global (char *label
, char *special
, efunc error
) {
218 if (islocal(label
)) {
219 error(ERR_NONFATAL
, "attempt to declare local symbol `%s' as"
223 lptr
= find_label (label
, 1);
224 switch (lptr
->defn
.is_global
& TYPE_MASK
) {
225 case NOT_DEFINED_YET
:
226 lptr
->defn
.is_global
= GLOBAL_PLACEHOLDER
;
227 lptr
->defn
.special
= special
? perm_copy(special
, "") : NULL
;
229 case GLOBAL_PLACEHOLDER
: /* already done: silently ignore */
233 if (!lptr
->defn
.is_global
& EXTERN_BIT
)
234 error(ERR_NONFATAL
, "symbol `%s': GLOBAL directive must"
235 " appear before symbol definition", label
);
240 int init_labels (void) {
243 for (i
=0; i
<LABEL_HASHES
; i
++) {
244 ltab
[i
] = (union label
*) nasm_malloc (LBLK_SIZE
);
246 return -1; /* can't initialise, panic */
247 init_block (ltab
[i
]);
251 perm_head
= perm_tail
= (struct permts
*) nasm_malloc (sizeof(struct permts
));
255 perm_head
->next
= NULL
;
256 perm_head
->size
= PERMTS_SIZE
;
257 perm_head
->usage
= 0;
266 void cleanup_labels (void) {
271 for (i
=0; i
<LABEL_HASHES
; i
++) {
272 union label
*lptr
, *lhold
;
274 lptr
= lhold
= ltab
[i
];
277 while (lptr
->admin
.movingon
!= END_BLOCK
) lptr
++;
278 lptr
= lptr
->admin
.next
;
285 perm_tail
= perm_head
;
286 perm_head
= perm_head
->next
;
287 nasm_free (perm_tail
);
291 static void init_block (union label
*blk
) {
294 for (j
=0; j
<LABEL_BLOCK
-1; j
++)
295 blk
[j
].admin
.movingon
= END_LIST
;
296 blk
[LABEL_BLOCK
-1].admin
.movingon
= END_BLOCK
;
297 blk
[LABEL_BLOCK
-1].admin
.next
= NULL
;
300 static char *perm_copy (char *string1
, char *string2
) {
302 int len
= strlen(string1
)+strlen(string2
)+1;
304 if (perm_tail
->size
- perm_tail
->usage
< len
) {
305 perm_tail
->next
= (struct permts
*)nasm_malloc(sizeof(struct permts
));
306 perm_tail
= perm_tail
->next
;
307 perm_tail
->next
= NULL
;
308 perm_tail
->size
= PERMTS_SIZE
;
309 perm_tail
->usage
= 0;
311 p
= q
= perm_tail
->data
+ perm_tail
->usage
;
312 while ( (*q
= *string1
++) ) q
++;
313 while ( (*q
++ = *string2
++) );
314 perm_tail
->usage
= q
- perm_tail
->data
;