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
;
91 if (!strncmp(lptr
->defn
.label
, prev
, prevlen
) &&
92 !strcmp(lptr
->defn
.label
+prevlen
, label
))
97 if (lfree
[hash
]->admin
.movingon
== END_BLOCK
) {
99 * must allocate a new block
101 lfree
[hash
]->admin
.next
= (union label
*) nasm_malloc (LBLK_SIZE
);
102 lfree
[hash
] = lfree
[hash
]->admin
.next
;
103 init_block(lfree
[hash
]);
106 lfree
[hash
]->admin
.movingon
= BOGUS_VALUE
;
107 lfree
[hash
]->defn
.label
= perm_copy (prev
, label
);
108 lfree
[hash
]->defn
.is_global
= NOT_DEFINED_YET
;
109 return lfree
[hash
]++;
114 int lookup_label (char *label
, long *segment
, long *offset
) {
117 lptr
= find_label (label
, 0);
118 if (lptr
&& (lptr
->defn
.is_global
== LOCAL_SYMBOL
||
119 lptr
->defn
.is_global
== GLOBAL_SYMBOL
)) {
120 *segment
= lptr
->defn
.segment
;
121 *offset
= lptr
->defn
.offset
;
127 void define_label_stub (char *label
, efunc error
) {
130 if (!islocal(label
)) {
131 lptr
= find_label (label
, 1);
133 error (ERR_PANIC
, "can't find label `%s' on pass two", label
);
134 prevlabel
= lptr
->defn
.label
;
138 void define_label (char *label
, long segment
, long offset
,
139 struct ofmt
*ofmt
, efunc error
) {
142 lptr
= find_label (label
, 1);
143 switch (lptr
->defn
.is_global
) {
144 case NOT_DEFINED_YET
:
145 lptr
->defn
.is_global
= LOCAL_SYMBOL
;
147 case GLOBAL_PLACEHOLDER
:
148 lptr
->defn
.is_global
= GLOBAL_SYMBOL
;
151 error(ERR_NONFATAL
, "symbol `%s' redefined", label
);
155 if (label
[0] != '.') /* not local, but not special either */
156 prevlabel
= lptr
->defn
.label
;
157 else if (!*prevlabel
)
158 error(ERR_NONFATAL
, "attempt to define a local label before any"
159 " non-local labels");
161 lptr
->defn
.segment
= segment
;
162 lptr
->defn
.offset
= offset
;
164 ofmt
->symdef (lptr
->defn
.label
, segment
, offset
,
165 lptr
->defn
.is_global
== GLOBAL_SYMBOL
);
168 void define_common (char *label
, long segment
, long size
,
169 struct ofmt
*ofmt
, efunc error
) {
172 lptr
= find_label (label
, 1);
173 switch (lptr
->defn
.is_global
) {
174 case NOT_DEFINED_YET
:
175 lptr
->defn
.is_global
= LOCAL_SYMBOL
;
177 case GLOBAL_PLACEHOLDER
:
178 lptr
->defn
.is_global
= GLOBAL_SYMBOL
;
181 error(ERR_NONFATAL
, "symbol `%s' redefined", label
);
185 if (label
[0] != '.') /* not local, but not special either */
186 prevlabel
= lptr
->defn
.label
;
188 error(ERR_NONFATAL
, "attempt to define a local label as a "
191 lptr
->defn
.segment
= segment
;
192 lptr
->defn
.offset
= 0;
194 ofmt
->symdef (lptr
->defn
.label
, segment
, size
, 2);
197 void declare_as_global (char *label
, efunc error
) {
200 if (islocal(label
)) {
201 error(ERR_NONFATAL
, "attempt to declare local symbol `%s' as"
205 lptr
= find_label (label
, 1);
206 switch (lptr
->defn
.is_global
) {
207 case NOT_DEFINED_YET
:
208 lptr
->defn
.is_global
= GLOBAL_PLACEHOLDER
;
210 case GLOBAL_PLACEHOLDER
: /* already done: silently ignore */
214 error(ERR_NONFATAL
, "symbol `%s': [GLOBAL] directive must"
215 " appear before symbol definition", label
);
220 int init_labels (void) {
223 for (i
=0; i
<LABEL_HASHES
; i
++) {
224 ltab
[i
] = (union label
*) nasm_malloc (LBLK_SIZE
);
226 return -1; /* can't initialise, panic */
227 init_block (ltab
[i
]);
231 perm_head
= perm_tail
= (struct permts
*) nasm_malloc (sizeof(struct permts
));
235 perm_head
->next
= NULL
;
236 perm_head
->size
= PERMTS_SIZE
;
237 perm_head
->usage
= 0;
244 void cleanup_labels (void) {
247 for (i
=0; i
<LABEL_HASHES
; i
++) {
248 union label
*lptr
, *lhold
;
250 lptr
= lhold
= ltab
[i
];
253 while (lptr
->admin
.movingon
!= END_BLOCK
) lptr
++;
254 lptr
= lptr
->admin
.next
;
261 perm_tail
= perm_head
;
262 perm_head
= perm_head
->next
;
263 nasm_free (perm_tail
);
267 static void init_block (union label
*blk
) {
270 for (j
=0; j
<LABEL_BLOCK
-1; j
++)
271 blk
[j
].admin
.movingon
= END_LIST
;
272 blk
[LABEL_BLOCK
-1].admin
.movingon
= END_BLOCK
;
273 blk
[LABEL_BLOCK
-1].admin
.next
= NULL
;
276 static char *perm_copy (char *string1
, char *string2
) {
278 int len
= strlen(string1
)+strlen(string2
)+1;
280 if (perm_tail
->size
- perm_tail
->usage
< len
) {
281 perm_tail
->next
= (struct permts
*)nasm_malloc(sizeof(struct permts
));
282 perm_tail
= perm_tail
->next
;
283 perm_tail
->size
= PERMTS_SIZE
;
284 perm_tail
->usage
= 0;
286 p
= q
= perm_tail
->data
+ perm_tail
->usage
;
287 while ( (*q
= *string1
++) ) q
++;
288 while ( (*q
++ = *string2
++) );
289 perm_tail
->usage
= q
- perm_tail
->data
;