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 */
32 #define NOT_DEFINED_YET 0
33 #define LOCAL_SYMBOL 1
34 #define GLOBAL_SYMBOL 2
35 #define GLOBAL_PLACEHOLDER 3
37 union label
{ /* actual label structures */
49 struct permts
{ /* permanent text storage */
50 struct permts
*next
; /* for the linked list */
51 int size
, usage
; /* size and used space in ... */
52 char data
[PERMTS_SIZE
]; /* ... the data block itself */
55 static union label
*ltab
[LABEL_HASHES
];/* using a hash table */
56 static union label
*lfree
[LABEL_HASHES
];/* pointer into the above */
57 static struct permts
*perm_head
; /* start of perm. text storage */
58 static struct permts
*perm_tail
; /* end of perm. text storage */
60 static void init_block (union label
*blk
);
61 static char *perm_copy (char *string1
, char *string2
);
63 static char *prevlabel
;
66 * Internal routine: finds the `union label' corresponding to the
67 * given label name. Creates a new one, if it isn't found, and if
70 static union label
*find_label (char *label
, int create
) {
80 prevlen
= strlen(prev
);
82 while (*p
) hash
+= *p
++;
84 while (*p
) hash
+= *p
++;
87 while (lptr
->admin
.movingon
!= END_LIST
) {
88 if (lptr
->admin
.movingon
== END_BLOCK
) {
89 lptr
= lptr
->admin
.next
;
93 if (!strncmp(lptr
->defn
.label
, prev
, prevlen
) &&
94 !strcmp(lptr
->defn
.label
+prevlen
, label
))
99 if (lfree
[hash
]->admin
.movingon
== END_BLOCK
) {
101 * must allocate a new block
103 lfree
[hash
]->admin
.next
= (union label
*) nasm_malloc (LBLK_SIZE
);
104 lfree
[hash
] = lfree
[hash
]->admin
.next
;
105 init_block(lfree
[hash
]);
108 lfree
[hash
]->admin
.movingon
= BOGUS_VALUE
;
109 lfree
[hash
]->defn
.label
= perm_copy (prev
, label
);
110 lfree
[hash
]->defn
.is_global
= NOT_DEFINED_YET
;
111 return lfree
[hash
]++;
116 int lookup_label (char *label
, long *segment
, long *offset
) {
119 lptr
= find_label (label
, 0);
120 if (lptr
&& (lptr
->defn
.is_global
== LOCAL_SYMBOL
||
121 lptr
->defn
.is_global
== GLOBAL_SYMBOL
)) {
122 *segment
= lptr
->defn
.segment
;
123 *offset
= lptr
->defn
.offset
;
129 void define_label_stub (char *label
, efunc error
) {
132 if (!islocal(label
)) {
133 lptr
= find_label (label
, 1);
135 error (ERR_PANIC
, "can't find label `%s' on pass two", label
);
137 prevlabel
= lptr
->defn
.label
;
141 void define_label (char *label
, long segment
, long offset
,
142 struct ofmt
*ofmt
, efunc error
) {
145 lptr
= find_label (label
, 1);
146 switch (lptr
->defn
.is_global
) {
147 case NOT_DEFINED_YET
:
148 lptr
->defn
.is_global
= LOCAL_SYMBOL
;
150 case GLOBAL_PLACEHOLDER
:
151 lptr
->defn
.is_global
= GLOBAL_SYMBOL
;
154 error(ERR_NONFATAL
, "symbol `%s' redefined", label
);
158 if (label
[0] != '.') /* not local, but not special either */
159 prevlabel
= lptr
->defn
.label
;
160 else if (label
[1] != '.' && !*prevlabel
)
161 error(ERR_NONFATAL
, "attempt to define a local label before any"
162 " non-local labels");
164 lptr
->defn
.segment
= segment
;
165 lptr
->defn
.offset
= offset
;
167 ofmt
->symdef (lptr
->defn
.label
, segment
, offset
,
168 lptr
->defn
.is_global
== GLOBAL_SYMBOL
);
171 void define_common (char *label
, long segment
, long size
,
172 struct ofmt
*ofmt
, efunc error
) {
175 lptr
= find_label (label
, 1);
176 switch (lptr
->defn
.is_global
) {
177 case NOT_DEFINED_YET
:
178 lptr
->defn
.is_global
= LOCAL_SYMBOL
;
180 case GLOBAL_PLACEHOLDER
:
181 lptr
->defn
.is_global
= GLOBAL_SYMBOL
;
184 error(ERR_NONFATAL
, "symbol `%s' redefined", label
);
188 if (label
[0] != '.') /* not local, but not special either */
189 prevlabel
= lptr
->defn
.label
;
191 error(ERR_NONFATAL
, "attempt to define a local label as a "
194 lptr
->defn
.segment
= segment
;
195 lptr
->defn
.offset
= 0;
197 ofmt
->symdef (lptr
->defn
.label
, segment
, size
, 2);
200 void declare_as_global (char *label
, efunc error
) {
203 if (islocal(label
)) {
204 error(ERR_NONFATAL
, "attempt to declare local symbol `%s' as"
208 lptr
= find_label (label
, 1);
209 switch (lptr
->defn
.is_global
) {
210 case NOT_DEFINED_YET
:
211 lptr
->defn
.is_global
= GLOBAL_PLACEHOLDER
;
213 case GLOBAL_PLACEHOLDER
: /* already done: silently ignore */
217 error(ERR_NONFATAL
, "symbol `%s': [GLOBAL] directive must"
218 " appear before symbol definition", label
);
223 int init_labels (void) {
226 for (i
=0; i
<LABEL_HASHES
; i
++) {
227 ltab
[i
] = (union label
*) nasm_malloc (LBLK_SIZE
);
229 return -1; /* can't initialise, panic */
230 init_block (ltab
[i
]);
234 perm_head
= perm_tail
= (struct permts
*) nasm_malloc (sizeof(struct permts
));
238 perm_head
->next
= NULL
;
239 perm_head
->size
= PERMTS_SIZE
;
240 perm_head
->usage
= 0;
247 void cleanup_labels (void) {
250 for (i
=0; i
<LABEL_HASHES
; i
++) {
251 union label
*lptr
, *lhold
;
253 lptr
= lhold
= ltab
[i
];
256 while (lptr
->admin
.movingon
!= END_BLOCK
) lptr
++;
257 lptr
= lptr
->admin
.next
;
264 perm_tail
= perm_head
;
265 perm_head
= perm_head
->next
;
266 nasm_free (perm_tail
);
270 static void init_block (union label
*blk
) {
273 for (j
=0; j
<LABEL_BLOCK
-1; j
++)
274 blk
[j
].admin
.movingon
= END_LIST
;
275 blk
[LABEL_BLOCK
-1].admin
.movingon
= END_BLOCK
;
276 blk
[LABEL_BLOCK
-1].admin
.next
= NULL
;
279 static char *perm_copy (char *string1
, char *string2
) {
281 int len
= strlen(string1
)+strlen(string2
)+1;
283 if (perm_tail
->size
- perm_tail
->usage
< len
) {
284 perm_tail
->next
= (struct permts
*)nasm_malloc(sizeof(struct permts
));
285 perm_tail
= perm_tail
->next
;
286 perm_tail
->next
= NULL
;
287 perm_tail
->size
= PERMTS_SIZE
;
288 perm_tail
->usage
= 0;
290 p
= q
= perm_tail
->data
+ perm_tail
->usage
;
291 while ( (*q
= *string1
++) ) q
++;
292 while ( (*q
++ = *string2
++) );
293 perm_tail
->usage
= q
- perm_tail
->data
;