blob: aad473ec166e069c354c61d6f0bf20f4a315540b [file] [log] [blame]
H. Peter Anvin9e6747c2009-06-28 17:13:04 -07001/* ----------------------------------------------------------------------- *
Cyrill Gorcunovd143f4f2010-07-28 10:18:48 +04002 *
H. Peter Anvin892c4812018-05-30 14:43:46 -07003 * Copyright 1996-2018 The NASM Authors - All Rights Reserved
H. Peter Anvin9e6747c2009-06-28 17:13:04 -07004 * See the file AUTHORS included with the NASM distribution for
5 * the specific copyright holders.
H. Peter Anvinea6e34d2002-04-30 20:51:32 +00006 *
H. Peter Anvin9e6747c2009-06-28 17:13:04 -07007 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following
9 * conditions are met:
10 *
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
Cyrill Gorcunovd143f4f2010-07-28 10:18:48 +040017 *
H. Peter Anvin9e6747c2009-06-28 17:13:04 -070018 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
19 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
20 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 * ----------------------------------------------------------------------- */
33
34/*
35 * labels.c label handling for the Netwide Assembler
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000036 */
37
H. Peter Anvinfe501952007-10-02 21:53:51 -070038#include "compiler.h"
39
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000040#include <stdio.h>
41#include <string.h>
42#include <stdlib.h>
Keith Kaniosb7a89542007-04-12 02:40:54 +000043
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000044#include "nasm.h"
45#include "nasmlib.h"
H. Peter Anvinb20bc732017-03-07 19:23:03 -080046#include "error.h"
H. Peter Anvin6244f4b2007-09-14 18:03:29 -070047#include "hashtbl.h"
H. Peter Anvinc6645832014-11-25 12:07:10 -080048#include "labels.h"
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000049
50/*
H. Peter Anvin98578072018-06-01 18:02:54 -070051 * A dot-local label is one that begins with exactly one period. Things
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000052 * that begin with _two_ periods are NASM-specific things.
H. Peter Anvin1cd0e2d2002-04-30 21:00:33 +000053 *
54 * If TASM compatibility is enabled, a local label can also begin with
H. Peter Anvin98578072018-06-01 18:02:54 -070055 * @@.
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000056 */
H. Peter Anvin98578072018-06-01 18:02:54 -070057static bool islocal(const char *l)
58{
59 if (tasm_compatible_mode) {
60 if (l[0] == '@' && l[1] == '@')
61 return true;
62 }
63
64 return (l[0] == '.' && l[1] != '.');
65}
66
67/*
68 * Return true if this falls into NASM's '..' namespace
69 */
70static bool ismagic(const char *l)
71{
72 return l[0] == '.' && l[1] == '.' && l[2] != '@';
73}
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000074
H. Peter Anvin, Intelbc77f9c2018-06-25 12:39:42 -070075/*
76 * Return true if we should update the local label base
77 * as a result of this symbol. We must exclude local labels
78 * as well as any kind of special labels, including ..@ ones.
79 */
80static bool set_prevlabel(const char *l)
81{
82 if (tasm_compatible_mode) {
83 if (l[0] == '@' && l[1] == '@')
84 return false;
85 }
86
87 return l[0] != '.';
88}
89
Cyrill Gorcunovd143f4f2010-07-28 10:18:48 +040090#define LABEL_BLOCK 128 /* no. of labels/block */
91#define LBLK_SIZE (LABEL_BLOCK * sizeof(union label))
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000092
Cyrill Gorcunovd143f4f2010-07-28 10:18:48 +040093#define END_LIST -3 /* don't clash with NO_SEG! */
94#define END_BLOCK -2
H. Peter Anvinea6e34d2002-04-30 20:51:32 +000095
Cyrill Gorcunovd143f4f2010-07-28 10:18:48 +040096#define PERMTS_SIZE 16384 /* size of text blocks */
H. Peter Anvin565be912009-07-05 22:15:57 -070097#if (PERMTS_SIZE < IDLEN_MAX)
Cyrill Gorcunovd143f4f2010-07-28 10:18:48 +040098 #error "IPERMTS_SIZE must be greater than or equal to IDLEN_MAX"
Ed Berosetc06f6df2003-09-08 00:30:40 +000099#endif
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000100
H. Peter Anvin98578072018-06-01 18:02:54 -0700101/* string values for enum label_type */
102static const char * const types[] =
103{"local", "global", "static", "extern", "common", "special",
104 "output format special"};
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000105
H. Peter Anvine2c80182005-01-15 22:15:51 +0000106union label { /* actual label structures */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000107 struct {
Charles Crayne4e8563d2007-11-05 17:19:32 -0800108 int32_t segment;
H. Peter Anvin29695c82018-06-14 17:04:32 -0700109 int32_t subsection; /* Available for ofmt->herelabel() */
Cyrill Gorcunovd143f4f2010-07-28 10:18:48 +0400110 int64_t offset;
H. Peter Anvin73482482018-06-11 14:54:14 -0700111 int64_t size;
H. Peter Anvin98578072018-06-01 18:02:54 -0700112 char *label, *mangled, *special;
113 enum label_type type, mangled_type;
114 bool defined;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000115 } defn;
116 struct {
Charles Crayne4e8563d2007-11-05 17:19:32 -0800117 int32_t movingon;
118 int64_t dummy;
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000119 union label *next;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000120 } admin;
121};
122
H. Peter Anvine2c80182005-01-15 22:15:51 +0000123struct permts { /* permanent text storage */
124 struct permts *next; /* for the linked list */
H. Peter Anvin98578072018-06-01 18:02:54 -0700125 unsigned int size, usage; /* size and used space in ... */
Keith Kaniosa6dfa782007-04-13 16:47:53 +0000126 char data[PERMTS_SIZE]; /* ... the data block itself */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000127};
H. Peter Anvin98578072018-06-01 18:02:54 -0700128#define PERMTS_HEADER offsetof(struct permts, data)
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000129
H. Peter Anvin9c595b62017-03-07 19:44:21 -0800130uint64_t global_offset_changed; /* counter for global offset changes */
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000131
Cyrill Gorcunovd143f4f2010-07-28 10:18:48 +0400132static struct hash_table ltab; /* labels hash table */
133static union label *ldata; /* all label data blocks */
134static union label *lfree; /* labels free block */
H. Peter Anvine2c80182005-01-15 22:15:51 +0000135static struct permts *perm_head; /* start of perm. text storage */
136static struct permts *perm_tail; /* end of perm. text storage */
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000137
H. Peter Anvine2c80182005-01-15 22:15:51 +0000138static void init_block(union label *blk);
H. Peter Anvin98578072018-06-01 18:02:54 -0700139static char *perm_alloc(size_t len);
H. Peter Anvind2fb7a62007-09-16 17:53:17 -0700140static char *perm_copy(const char *string);
H. Peter Anvin98578072018-06-01 18:02:54 -0700141static char *perm_copy3(const char *s1, const char *s2, const char *s3);
142static const char *mangle_label_name(union label *lptr);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000143
H. Peter Anvin98578072018-06-01 18:02:54 -0700144static const char *prevlabel;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000145
H. Peter Anvin70055962007-10-11 00:05:31 -0700146static bool initialized = false;
H. Peter Anvin76690a12002-04-30 20:52:49 +0000147
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000148/*
H. Peter Anvinfc0ff222016-03-07 21:46:04 -0800149 * Emit a symdef to the output and the debug format backends.
150 */
H. Peter Anvin98578072018-06-01 18:02:54 -0700151static void out_symdef(union label *lptr)
H. Peter Anvinfc0ff222016-03-07 21:46:04 -0800152{
H. Peter Anvin98578072018-06-01 18:02:54 -0700153 int backend_type;
H. Peter Anvin73482482018-06-11 14:54:14 -0700154 int64_t backend_offset;
H. Peter Anvin98578072018-06-01 18:02:54 -0700155
156 /* Backend-defined special segments are passed to symdef immediately */
157 if (pass0 == 2) {
158 /* Emit special fixups for globals and commons */
159 switch (lptr->defn.type) {
160 case LBL_GLOBAL:
H. Peter Anvin98578072018-06-01 18:02:54 -0700161 case LBL_EXTERN:
H. Peter Anvin73482482018-06-11 14:54:14 -0700162 case LBL_COMMON:
H. Peter Anvin98578072018-06-01 18:02:54 -0700163 if (lptr->defn.special)
H. Peter Anvina7c8e392018-06-18 14:17:26 -0700164 ofmt->symdef(lptr->defn.mangled, 0, 0, 3, lptr->defn.special);
H. Peter Anvin98578072018-06-01 18:02:54 -0700165 break;
166 default:
167 break;
168 }
169 return;
170 }
171
172 if (pass0 != 1 && lptr->defn.type != LBL_BACKEND)
173 return;
174
175 /* Clean up this hack... */
176 switch(lptr->defn.type) {
177 case LBL_GLOBAL:
Cyrill Gorcunov70d42962018-07-01 01:59:07 +0300178 case LBL_EXTERN:
H. Peter Anvin98578072018-06-01 18:02:54 -0700179 backend_type = 1;
H. Peter Anvin73482482018-06-11 14:54:14 -0700180 backend_offset = lptr->defn.offset;
H. Peter Anvin98578072018-06-01 18:02:54 -0700181 break;
182 case LBL_COMMON:
183 backend_type = 2;
H. Peter Anvin73482482018-06-11 14:54:14 -0700184 backend_offset = lptr->defn.size;
H. Peter Anvin98578072018-06-01 18:02:54 -0700185 break;
186 default:
187 backend_type = 0;
H. Peter Anvin73482482018-06-11 14:54:14 -0700188 backend_offset = lptr->defn.offset;
H. Peter Anvin98578072018-06-01 18:02:54 -0700189 break;
190 }
191
192 /* Might be necessary for a backend symbol */
193 mangle_label_name(lptr);
194
195 ofmt->symdef(lptr->defn.mangled, lptr->defn.segment,
H. Peter Anvin73482482018-06-11 14:54:14 -0700196 backend_offset, backend_type,
H. Peter Anvin98578072018-06-01 18:02:54 -0700197 lptr->defn.special);
H. Peter Anvinfc0ff222016-03-07 21:46:04 -0800198
199 /*
200 * NASM special symbols are not passed to the debug format; none
201 * of the current backends want to see them.
202 */
H. Peter Anvin98578072018-06-01 18:02:54 -0700203 if (lptr->defn.type == LBL_SPECIAL || lptr->defn.type == LBL_BACKEND)
204 return;
205
206 dfmt->debug_deflabel(lptr->defn.mangled, lptr->defn.segment,
207 lptr->defn.offset, backend_type,
208 lptr->defn.special);
H. Peter Anvinfc0ff222016-03-07 21:46:04 -0800209}
210
211/*
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000212 * Internal routine: finds the `union label' corresponding to the
213 * given label name. Creates a new one, if it isn't found, and if
H. Peter Anvin6867acc2007-10-10 14:58:45 -0700214 * `create' is true.
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000215 */
H. Peter Anvin98578072018-06-01 18:02:54 -0700216static union label *find_label(const char *label, bool create, bool *created)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000217{
H. Peter Anvin97a23472007-09-16 17:57:25 -0700218 union label *lptr, **lpp;
H. Peter Anvin98578072018-06-01 18:02:54 -0700219 char *label_str = NULL;
H. Peter Anvin6244f4b2007-09-14 18:03:29 -0700220 struct hash_insert ip;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000221
H. Peter Anvin98578072018-06-01 18:02:54 -0700222 if (islocal(label))
223 label = label_str = nasm_strcat(prevlabel, label);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000224
H. Peter Anvin166c2472008-05-28 12:28:58 -0700225 lpp = (union label **) hash_find(&ltab, label, &ip);
H. Peter Anvin97a23472007-09-16 17:57:25 -0700226 lptr = lpp ? *lpp : NULL;
H. Peter Anvin6244f4b2007-09-14 18:03:29 -0700227
Cyrill Gorcunov5dfcab62016-07-18 11:49:47 +0300228 if (lptr || !create) {
229 if (created)
H. Peter Anvin98578072018-06-01 18:02:54 -0700230 *created = false;
Cyrill Gorcunovd143f4f2010-07-28 10:18:48 +0400231 return lptr;
Cyrill Gorcunov5dfcab62016-07-18 11:49:47 +0300232 }
H. Peter Anvin6244f4b2007-09-14 18:03:29 -0700233
234 /* Create a new label... */
235 if (lfree->admin.movingon == END_BLOCK) {
Cyrill Gorcunovd143f4f2010-07-28 10:18:48 +0400236 /*
237 * must allocate a new block
238 */
H. Peter Anvin3e555482017-04-23 17:02:46 -0700239 lfree->admin.next = nasm_malloc(LBLK_SIZE);
Cyrill Gorcunovd143f4f2010-07-28 10:18:48 +0400240 lfree = lfree->admin.next;
241 init_block(lfree);
H. Peter Anvin6244f4b2007-09-14 18:03:29 -0700242 }
H. Peter Anvin70653092007-10-19 14:42:29 -0700243
Cyrill Gorcunov5dfcab62016-07-18 11:49:47 +0300244 if (created)
H. Peter Anvin98578072018-06-01 18:02:54 -0700245 *created = true;
Cyrill Gorcunov5dfcab62016-07-18 11:49:47 +0300246
H. Peter Anvin98578072018-06-01 18:02:54 -0700247 nasm_zero(*lfree);
H. Peter Anvin98578072018-06-01 18:02:54 -0700248 lfree->defn.label = perm_copy(label);
H. Peter Anvin29695c82018-06-14 17:04:32 -0700249 lfree->defn.subsection = NO_SEG;
H. Peter Anvin98578072018-06-01 18:02:54 -0700250 if (label_str)
251 nasm_free(label_str);
H. Peter Anvin70653092007-10-19 14:42:29 -0700252
H. Peter Anvin6244f4b2007-09-14 18:03:29 -0700253 hash_add(&ip, lfree->defn.label, lfree);
254 return lfree++;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000255}
256
H. Peter Anvin785ffb92017-03-14 18:41:25 -0700257bool lookup_label(const char *label, int32_t *segment, int64_t *offset)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000258{
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000259 union label *lptr;
260
Keith Kaniosb7a89542007-04-12 02:40:54 +0000261 if (!initialized)
H. Peter Anvin70055962007-10-11 00:05:31 -0700262 return false;
H. Peter Anvin76690a12002-04-30 20:52:49 +0000263
H. Peter Anvin98578072018-06-01 18:02:54 -0700264 lptr = find_label(label, false, NULL);
265 if (lptr && lptr->defn.defined) {
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000266 *segment = lptr->defn.segment;
267 *offset = lptr->defn.offset;
H. Peter Anvin70055962007-10-11 00:05:31 -0700268 return true;
Cyrill Gorcunovd7a64b72010-04-20 15:26:08 +0400269 }
270
271 return false;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000272}
273
H. Peter Anvin785ffb92017-03-14 18:41:25 -0700274bool is_extern(const char *label)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000275{
H. Peter Anvin76690a12002-04-30 20:52:49 +0000276 union label *lptr;
277
Keith Kaniosb7a89542007-04-12 02:40:54 +0000278 if (!initialized)
H. Peter Anvin70055962007-10-11 00:05:31 -0700279 return false;
H. Peter Anvin76690a12002-04-30 20:52:49 +0000280
H. Peter Anvin98578072018-06-01 18:02:54 -0700281 lptr = find_label(label, false, NULL);
282 return lptr && lptr->defn.type == LBL_EXTERN;
H. Peter Anvin76690a12002-04-30 20:52:49 +0000283}
284
H. Peter Anvin98578072018-06-01 18:02:54 -0700285static const char *mangle_strings[] = {"", "", "", ""};
286static bool mangle_string_set[ARRAY_SIZE(mangle_strings)];
287
288/*
289 * Set a prefix or suffix
290 */
291void set_label_mangle(enum mangle_index which, const char *what)
292{
293 if (mangle_string_set[which])
294 return; /* Once set, do not change */
295
296 mangle_strings[which] = perm_copy(what);
297 mangle_string_set[which] = true;
298}
299
300/*
301 * Format a label name with appropriate prefixes and suffixes
302 */
303static const char *mangle_label_name(union label *lptr)
304{
305 const char *prefix;
306 const char *suffix;
307
308 if (likely(lptr->defn.mangled &&
309 lptr->defn.mangled_type == lptr->defn.type))
310 return lptr->defn.mangled; /* Already mangled */
311
312 switch (lptr->defn.type) {
313 case LBL_GLOBAL:
314 case LBL_STATIC:
315 case LBL_EXTERN:
316 prefix = mangle_strings[LM_GPREFIX];
317 suffix = mangle_strings[LM_GSUFFIX];
318 break;
319 case LBL_BACKEND:
320 case LBL_SPECIAL:
321 prefix = suffix = "";
322 break;
323 default:
324 prefix = mangle_strings[LM_LPREFIX];
325 suffix = mangle_strings[LM_LSUFFIX];
326 break;
327 }
328
329 lptr->defn.mangled_type = lptr->defn.type;
330
331 if (!(*prefix) && !(*suffix))
332 lptr->defn.mangled = lptr->defn.label;
333 else
334 lptr->defn.mangled = perm_copy3(prefix, lptr->defn.label, suffix);
335
336 return lptr->defn.mangled;
337}
338
339static void
H. Peter Anvin29695c82018-06-14 17:04:32 -0700340handle_herelabel(union label *lptr, int32_t *segment, int64_t *offset)
H. Peter Anvin892c4812018-05-30 14:43:46 -0700341{
342 int32_t oldseg;
343
344 if (likely(!ofmt->herelabel))
345 return;
346
347 if (unlikely(location.segment == NO_SEG))
348 return;
349
350 oldseg = *segment;
351
352 if (oldseg == location.segment && *offset == location.offset) {
353 /* This label is defined at this location */
354 int32_t newseg;
H. Peter Anvin (Intel)d6441192018-06-27 20:20:21 -0700355 bool copyoffset = false;
H. Peter Anvin892c4812018-05-30 14:43:46 -0700356
H. Peter Anvin98578072018-06-01 18:02:54 -0700357 nasm_assert(lptr->defn.mangled);
H. Peter Anvin29695c82018-06-14 17:04:32 -0700358 newseg = ofmt->herelabel(lptr->defn.mangled, lptr->defn.type,
H. Peter Anvin (Intel)d6441192018-06-27 20:20:21 -0700359 oldseg, &lptr->defn.subsection, &copyoffset);
H. Peter Anvin892c4812018-05-30 14:43:46 -0700360 if (likely(newseg == oldseg))
361 return;
362
363 *segment = newseg;
H. Peter Anvin (Intel)d6441192018-06-27 20:20:21 -0700364 if (copyoffset) {
365 /* Maintain the offset from the old to the new segment */
366 switch_segment(newseg);
367 location.offset = *offset;
368 } else {
369 /* Keep a separate offset for the new segment */
370 *offset = switch_segment(newseg);
371 }
H. Peter Anvin892c4812018-05-30 14:43:46 -0700372 }
373}
374
H. Peter Anvin98578072018-06-01 18:02:54 -0700375static bool declare_label_lptr(union label *lptr,
376 enum label_type type, const char *special)
377{
H. Peter Anvin3cb90682018-06-01 21:05:45 -0700378 if (special && !special[0])
379 special = NULL;
380
H. Peter Anvin98578072018-06-01 18:02:54 -0700381 if (lptr->defn.type == type ||
382 (pass0 == 0 && lptr->defn.type == LBL_LOCAL)) {
383 lptr->defn.type = type;
384 if (special) {
385 if (!lptr->defn.special)
386 lptr->defn.special = perm_copy(special);
387 else if (nasm_stricmp(lptr->defn.special, special))
388 nasm_error(ERR_NONFATAL,
389 "symbol `%s' has inconsistent attributes `%s' and `%s'",
390 lptr->defn.label, lptr->defn.special, special);
391 }
392 return true;
393 }
394
395 /* EXTERN can be replaced with GLOBAL or COMMON */
396 if (lptr->defn.type == LBL_EXTERN &&
397 (type == LBL_GLOBAL || type == LBL_COMMON)) {
398 lptr->defn.type = type;
399 /* Override special unconditionally */
400 if (special)
401 lptr->defn.special = perm_copy(special);
402 return true;
403 }
404
405 /* GLOBAL or COMMON ignore subsequent EXTERN */
406 if ((lptr->defn.type == LBL_GLOBAL || lptr->defn.type == LBL_COMMON) &&
407 type == LBL_EXTERN) {
408 if (!lptr->defn.special)
409 lptr->defn.special = perm_copy(special);
H. Peter Anvin, Intel4fb2acc2018-06-25 13:11:01 -0700410 return false; /* Don't call define_label() after this! */
H. Peter Anvin98578072018-06-01 18:02:54 -0700411 }
412
413 nasm_error(ERR_NONFATAL, "symbol `%s' declared both as %s and %s",
414 lptr->defn.label, types[lptr->defn.type], types[type]);
415
416 return false;
417}
418
419bool declare_label(const char *label, enum label_type type, const char *special)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000420{
Cyrill Gorcunova8e3d6a2018-06-30 20:02:24 +0300421 union label *lptr = find_label(label, true, NULL);
H. Peter Anvin98578072018-06-01 18:02:54 -0700422 return declare_label_lptr(lptr, type, special);
423}
424
425/*
426 * The "normal" argument decides if we should update the local segment
427 * base name or not.
428 */
429void define_label(const char *label, int32_t segment,
430 int64_t offset, bool normal)
431{
432 union label *lptr;
433 bool created, changed;
H. Peter Anvin73482482018-06-11 14:54:14 -0700434 int64_t size;
H. Peter Anvin98578072018-06-01 18:02:54 -0700435
436 /*
437 * Phase errors here can be one of two types: a new label appears,
438 * or the offset changes. Increment global_offset_changed when that
439 * happens, to tell the assembler core to make another pass.
H. Peter Anvineba20a72002-04-30 20:53:55 +0000440 */
H. Peter Anvin98578072018-06-01 18:02:54 -0700441 lptr = find_label(label, true, &created);
H. Peter Anvineba20a72002-04-30 20:53:55 +0000442
H. Peter Anvin, Intelc5e45f62018-06-25 13:16:53 -0700443 if (segment) {
444 /* We are actually defining this label */
445 if (lptr->defn.type == LBL_EXTERN) /* auto-promote EXTERN to GLOBAL */
446 lptr->defn.type = LBL_GLOBAL;
447 } else {
448 /* It's a pseudo-segment (extern, common) */
H. Peter Anvin46c839a2018-06-14 20:00:07 -0700449 segment = lptr->defn.segment ? lptr->defn.segment : seg_alloc();
H. Peter Anvin, Intelc5e45f62018-06-25 13:16:53 -0700450 }
H. Peter Anvinaf5f9182018-06-14 19:53:45 -0700451
H. Peter Anvin98578072018-06-01 18:02:54 -0700452 if (lptr->defn.defined || lptr->defn.type == LBL_BACKEND) {
453 /* We have seen this on at least one previous pass */
454 mangle_label_name(lptr);
455 handle_herelabel(lptr, &segment, &offset);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000456 }
457
H. Peter Anvin98578072018-06-01 18:02:54 -0700458 if (ismagic(label) && lptr->defn.type == LBL_LOCAL)
459 lptr->defn.type = LBL_SPECIAL;
H. Peter Anvin73482482018-06-11 14:54:14 -0700460
H. Peter Anvin, Intelbc77f9c2018-06-25 12:39:42 -0700461 if (set_prevlabel(label) && normal)
H. Peter Anvine2c80182005-01-15 22:15:51 +0000462 prevlabel = lptr->defn.label;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000463
H. Peter Anvin73482482018-06-11 14:54:14 -0700464 if (lptr->defn.type == LBL_COMMON) {
465 size = offset;
466 offset = 0;
467 } else {
468 size = 0; /* This is a hack... */
469 }
470
H. Peter Anvin, Intelbc77f9c2018-06-25 12:39:42 -0700471 changed = created || !lptr->defn.defined ||
472 lptr->defn.segment != segment ||
H. Peter Anvin73482482018-06-11 14:54:14 -0700473 lptr->defn.offset != offset || lptr->defn.size != size;
H. Peter Anvin98578072018-06-01 18:02:54 -0700474 global_offset_changed += changed;
475
476 /*
477 * This probably should be ERR_NONFATAL, but not quite yet. As a
478 * special case, LBL_SPECIAL symbols are allowed to be changed
479 * even during the last pass.
480 */
H. Peter Anvin, Intelbc77f9c2018-06-25 12:39:42 -0700481 if (changed && pass0 > 1 && lptr->defn.type != LBL_SPECIAL) {
482 nasm_error(ERR_WARNING, "label `%s' %s during code generation",
H. Peter Anvin, Intel21398742018-06-25 13:03:39 -0700483 lptr->defn.label,
484 created ? "defined" : "changed");
H. Peter Anvin, Intelbc77f9c2018-06-25 12:39:42 -0700485 }
H. Peter Anvin98578072018-06-01 18:02:54 -0700486
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000487 lptr->defn.segment = segment;
H. Peter Anvin98578072018-06-01 18:02:54 -0700488 lptr->defn.offset = offset;
H. Peter Anvin73482482018-06-11 14:54:14 -0700489 lptr->defn.size = size;
H. Peter Anvin98578072018-06-01 18:02:54 -0700490 lptr->defn.defined = true;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000491
H. Peter Anvin98578072018-06-01 18:02:54 -0700492 out_symdef(lptr);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000493}
494
H. Peter Anvin98578072018-06-01 18:02:54 -0700495/*
496 * Define a special backend label
497 */
498void backend_label(const char *label, int32_t segment, int64_t offset)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000499{
H. Peter Anvin98578072018-06-01 18:02:54 -0700500 if (!declare_label(label, LBL_BACKEND, NULL))
Cyrill Gorcunovd143f4f2010-07-28 10:18:48 +0400501 return;
H. Peter Anvinaeb0e0e2009-06-27 16:30:00 -0700502
H. Peter Anvin98578072018-06-01 18:02:54 -0700503 define_label(label, segment, offset, false);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000504}
505
H. Peter Anvine2c80182005-01-15 22:15:51 +0000506int init_labels(void)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000507{
H. Peter Anvin166c2472008-05-28 12:28:58 -0700508 hash_init(&ltab, HASH_LARGE);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000509
H. Peter Anvin3e555482017-04-23 17:02:46 -0700510 ldata = lfree = nasm_malloc(LBLK_SIZE);
H. Peter Anvin6244f4b2007-09-14 18:03:29 -0700511 init_block(lfree);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000512
Cyrill Gorcunovd143f4f2010-07-28 10:18:48 +0400513 perm_head = perm_tail =
H. Peter Anvin3e555482017-04-23 17:02:46 -0700514 nasm_malloc(sizeof(struct permts));
H. Peter Anvineba20a72002-04-30 20:53:55 +0000515
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000516 perm_head->next = NULL;
517 perm_head->size = PERMTS_SIZE;
518 perm_head->usage = 0;
519
520 prevlabel = "";
521
H. Peter Anvin6867acc2007-10-10 14:58:45 -0700522 initialized = true;
H. Peter Anvin76690a12002-04-30 20:52:49 +0000523
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000524 return 0;
525}
526
H. Peter Anvine2c80182005-01-15 22:15:51 +0000527void cleanup_labels(void)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000528{
H. Peter Anvin6244f4b2007-09-14 18:03:29 -0700529 union label *lptr, *lhold;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000530
H. Peter Anvin6867acc2007-10-10 14:58:45 -0700531 initialized = false;
H. Peter Anvin76690a12002-04-30 20:52:49 +0000532
H. Peter Anvin166c2472008-05-28 12:28:58 -0700533 hash_free(&ltab);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000534
H. Peter Anvin6244f4b2007-09-14 18:03:29 -0700535 lptr = lhold = ldata;
536 while (lptr) {
Cyrill Gorcunovd143f4f2010-07-28 10:18:48 +0400537 lptr = &lptr[LABEL_BLOCK-1];
538 lptr = lptr->admin.next;
539 nasm_free(lhold);
540 lhold = lptr;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000541 }
542
543 while (perm_head) {
H. Peter Anvinaf535c12002-04-30 20:59:21 +0000544 perm_tail = perm_head;
545 perm_head = perm_head->next;
H. Peter Anvine2c80182005-01-15 22:15:51 +0000546 nasm_free(perm_tail);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000547 }
548}
549
H. Peter Anvine2c80182005-01-15 22:15:51 +0000550static void init_block(union label *blk)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000551{
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000552 int j;
553
H. Peter Anvine2c80182005-01-15 22:15:51 +0000554 for (j = 0; j < LABEL_BLOCK - 1; j++)
555 blk[j].admin.movingon = END_LIST;
556 blk[LABEL_BLOCK - 1].admin.movingon = END_BLOCK;
557 blk[LABEL_BLOCK - 1].admin.next = NULL;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000558}
559
H. Peter Anvin98578072018-06-01 18:02:54 -0700560static char * safe_alloc perm_alloc(size_t len)
561{
H. Peter Anvin3cb90682018-06-01 21:05:45 -0700562 char *p;
H. Peter Anvin73482482018-06-11 14:54:14 -0700563
H. Peter Anvin98578072018-06-01 18:02:54 -0700564 if (perm_tail->size - perm_tail->usage < len) {
565 size_t alloc_len = (len > PERMTS_SIZE) ? len : PERMTS_SIZE;
566 perm_tail->next = nasm_malloc(PERMTS_HEADER + alloc_len);
567 perm_tail = perm_tail->next;
568 perm_tail->next = NULL;
569 perm_tail->size = alloc_len;
570 perm_tail->usage = 0;
571 }
H. Peter Anvin3cb90682018-06-01 21:05:45 -0700572 p = perm_tail->data + perm_tail->usage;
H. Peter Anvin98578072018-06-01 18:02:54 -0700573 perm_tail->usage += len;
H. Peter Anvin3cb90682018-06-01 21:05:45 -0700574 return p;
H. Peter Anvin98578072018-06-01 18:02:54 -0700575}
576
H. Peter Anvind2fb7a62007-09-16 17:53:17 -0700577static char *perm_copy(const char *string)
H. Peter Anvineba20a72002-04-30 20:53:55 +0000578{
H. Peter Anvind2fb7a62007-09-16 17:53:17 -0700579 char *p;
H. Peter Anvin98578072018-06-01 18:02:54 -0700580 size_t len;
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000581
H. Peter Anvin98578072018-06-01 18:02:54 -0700582 if (!string)
583 return NULL;
H. Peter Anvin565be912009-07-05 22:15:57 -0700584
H. Peter Anvin98578072018-06-01 18:02:54 -0700585 len = strlen(string)+1; /* Include final NUL */
586
587 p = perm_alloc(len);
H. Peter Anvind2fb7a62007-09-16 17:53:17 -0700588 memcpy(p, string, len);
H. Peter Anvinea6e34d2002-04-30 20:51:32 +0000589
590 return p;
591}
H. Peter Anvineba20a72002-04-30 20:53:55 +0000592
H. Peter Anvin3cb90682018-06-01 21:05:45 -0700593static char *
H. Peter Anvin98578072018-06-01 18:02:54 -0700594perm_copy3(const char *s1, const char *s2, const char *s3)
595{
596 char *p;
597 size_t l1 = strlen(s1);
598 size_t l2 = strlen(s2);
599 size_t l3 = strlen(s3)+1; /* Include final NUL */
H. Peter Anvin73482482018-06-11 14:54:14 -0700600
H. Peter Anvin98578072018-06-01 18:02:54 -0700601 p = perm_alloc(l1+l2+l3);
602 memcpy(p, s1, l1);
603 memcpy(p+l1, s2, l2);
604 memcpy(p+l1+l2, s3, l3);
605
606 return p;
607}
608
609const char *local_scope(const char *label)
Charles Crayned60059e2008-03-12 22:39:03 -0700610{
611 return islocal(label) ? prevlabel : "";
612}
613
H. Peter Anvineba20a72002-04-30 20:53:55 +0000614/*
615 * Notes regarding bug involving redefinition of external segments.
616 *
617 * Up to and including v0.97, the following code didn't work. From 0.97
618 * developers release 2 onwards, it will generate an error.
619 *
620 * EXTERN extlabel
621 * newlabel EQU extlabel + 1
622 *
623 * The results of allowing this code through are that two import records
624 * are generated, one for 'extlabel' and one for 'newlabel'.
625 *
626 * The reason for this is an inadequacy in the defined interface between
627 * the label manager and the output formats. The problem lies in how the
628 * output format driver tells that a label is an external label for which
629 * a label import record must be produced. Most (all except bin?) produce
630 * the record if the segment number of the label is not one of the internal
631 * segments that the output driver is producing.
632 *
633 * A simple fix to this would be to make the output formats keep track of
634 * which symbols they've produced import records for, and make them not
635 * produce import records for segments that are already defined.
636 *
637 * The best way, which is slightly harder but reduces duplication of code
638 * and should therefore make the entire system smaller and more stable is
639 * to change the interface between assembler, define_label(), and
640 * the output module. The changes that are needed are:
641 *
642 * The semantics of the 'isextern' flag passed to define_label() need
643 * examining. This information may or may not tell us what we need to
644 * know (ie should we be generating an import record at this point for this
645 * label). If these aren't the semantics, the semantics should be changed
646 * to this.
647 *
648 * The output module interface needs changing, so that the `isextern' flag
649 * is passed to the module, so that it can be easily tested for.
650 */