339
|
1 /*
|
|
2 lwasm.c
|
|
3 Copyright © 2009 William Astle
|
|
4
|
|
5 This file is part of LWASM.
|
|
6
|
|
7 LWASM is free software: you can redistribute it and/or modify it under the
|
|
8 terms of the GNU General Public License as published by the Free Software
|
|
9 Foundation, either version 3 of the License, or (at your option) any later
|
|
10 version.
|
|
11
|
|
12 This program is distributed in the hope that it will be useful, but WITHOUT
|
|
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
15 more details.
|
|
16
|
|
17 You should have received a copy of the GNU General Public License along with
|
|
18 this program. If not, see <http://www.gnu.org/licenses/>.
|
|
19
|
|
20
|
|
21 Contains random functions used by the assembler
|
|
22 */
|
|
23
|
|
24 #define __lwasm_c_seen__
|
|
25 #include <config.h>
|
|
26
|
|
27 #include <stdarg.h>
|
|
28 #include <stdlib.h>
|
|
29 #include <stdio.h>
|
|
30
|
|
31 #include "lwasm.h"
|
|
32 #include "util.h"
|
|
33 #include "expr.h"
|
|
34
|
|
35 int debug_level = 0;
|
|
36
|
|
37 int register_error(asmstate_t *as, lwasm_line_t *l, int pass, const char *fmt, ...)
|
|
38 {
|
|
39 lwasm_error_t *e;
|
|
40 va_list args;
|
|
41 char errbuff[1024];
|
|
42 int r;
|
|
43
|
|
44 if (!l)
|
|
45 return;
|
|
46
|
|
47 if (as -> passnum != pass)
|
|
48 return;
|
|
49
|
|
50 va_start(args, fmt);
|
|
51
|
|
52 e = lwasm_alloc(sizeof(lwasm_error_t));
|
|
53
|
|
54 e -> next = l -> err;
|
|
55 l -> err = e;
|
|
56
|
|
57 as -> errorcount++;
|
|
58
|
|
59 r = vsnprintf(errbuff, 1024, fmt, args);
|
|
60 e -> mess = lwasm_strdup(errbuff);
|
|
61
|
|
62 va_end(args);
|
|
63
|
|
64 return r;
|
|
65 }
|
|
66
|
|
67 void lwasm_emit(asmstate_t *as, lwasm_line_t *l, int b)
|
|
68 {
|
|
69 as -> addr += 1;
|
|
70 as -> addr &= 0xffff;
|
|
71
|
|
72 if (as -> outformat == OUTPUT_OBJ && !(as -> csect))
|
|
73 {
|
|
74 register_error(as, l, 1, "Output not allowed outside sections with obj target");
|
|
75 return;
|
|
76 }
|
|
77 if (as -> outformat == OUTPUT_OBJ && as -> csect -> flags & SECTION_BSS)
|
|
78 {
|
|
79 register_error(as, l, 1, "Output not allowed inside BSS sections");
|
|
80 return;
|
|
81 }
|
|
82
|
|
83 if (as -> outformat == OUTPUT_OS9 && as -> inmod == 0)
|
|
84 {
|
|
85 register_error(as, l, 1, "Output not allowed outside of module in OS9 mode");
|
|
86 return;
|
|
87 }
|
|
88
|
|
89 if (as -> passnum == 1)
|
|
90 return;
|
|
91
|
|
92
|
|
93 if (l -> codelen >= l -> codesize)
|
|
94 {
|
|
95 l -> bytes = realloc(l -> bytes, l -> codesize + 16);
|
|
96 l -> codesize += 16;
|
|
97 }
|
|
98 l -> bytes[l -> codelen] = b & 0xff;
|
|
99 l -> codelen += 1;
|
|
100
|
|
101 if (as -> outformat == OUTPUT_OS9 && as -> inmod)
|
|
102 {
|
|
103 // calc the CRC
|
|
104 // this is a direct transliteration from the nitros9 asm source
|
|
105 // to C; it can, no doubt, be optimized for 32 bit processing
|
|
106 b &= 0xff;
|
|
107
|
|
108 b ^= (as -> crc)[0];
|
|
109 (as -> crc)[0] = (as -> crc)[1];
|
|
110 (as -> crc)[1] = (as -> crc)[2];
|
|
111 (as -> crc)[1] ^= (b >> 7);
|
|
112 (as -> crc)[2] = (b << 1);
|
|
113 (as -> crc)[1] ^= (b >> 2);
|
|
114 (as -> crc)[2] ^= (b << 6);
|
|
115 b ^= (b << 1);
|
|
116 b ^= (b << 2);
|
|
117 b ^= (b << 4);
|
|
118 if (b & 0x80)
|
|
119 {
|
|
120 (as -> crc)[0] ^= 0x80;
|
|
121 (as -> crc)[2] ^= 0x21;
|
|
122 }
|
|
123 }
|
|
124 }
|
|
125
|
|
126 void lwasm_emitop(asmstate_t *as, lwasm_line_t *l, int o)
|
|
127 {
|
|
128 if (o >= 0x100)
|
|
129 lwasm_emit(as, l, o >> 8);
|
|
130 lwasm_emit(as, l, o & 0xff);
|
|
131 }
|
|
132
|
|
133 int lwasm_lookupreg2(const char *reglist, char **str)
|
|
134 {
|
|
135 int rval = 0;
|
|
136
|
|
137 while (*reglist)
|
|
138 {
|
|
139 if (toupper(**str) == *reglist)
|
|
140 {
|
|
141 // first char matches
|
|
142 if (reglist[1] == ' ' && !isalpha(*(*str + 1)))
|
|
143 break;
|
|
144 if (toupper(*(*str + 1)) == reglist[1])
|
|
145 break;
|
|
146 }
|
|
147 reglist += 2;
|
|
148 rval++;
|
|
149 }
|
|
150 if (!*reglist)
|
|
151 return -1;
|
|
152 if (reglist[1] == ' ')
|
|
153 (*str)++;
|
|
154 else
|
|
155 (*str) += 2;
|
|
156 return rval;
|
|
157 }
|
|
158
|
|
159 int lwasm_lookupreg3(const char *rlist, const char **str)
|
|
160 {
|
|
161 int rval = 0;
|
|
162 int f = 0;
|
|
163 const char *reglist = rlist;
|
|
164
|
|
165 while (*reglist)
|
|
166 {
|
|
167 if (toupper(**str) == *reglist)
|
|
168 {
|
|
169 // first char matches
|
|
170 if (reglist[1] == ' ')
|
|
171 {
|
|
172 f = 1;
|
|
173 break;
|
|
174 }
|
|
175 if (toupper(*(*str + 1)) == reglist[1])
|
|
176 {
|
|
177 // second char matches
|
|
178 if (reglist[2] == ' ')
|
|
179 {
|
|
180 f = 1;
|
|
181 break;
|
|
182 }
|
|
183 if (toupper(*(*str + 2)) == reglist[2])
|
|
184 {
|
|
185 f = 1;
|
|
186 break;
|
|
187 }
|
|
188 }
|
|
189 }
|
|
190 reglist += 3;
|
|
191 rval++;
|
|
192 }
|
|
193 if (f == 0)
|
|
194 return -1;
|
|
195
|
|
196
|
|
197 reglist = rval * 3 + rlist;
|
|
198 if (reglist[1] == ' ')
|
|
199 (*str) += 1;
|
|
200 else if (reglist[2] == ' ')
|
|
201 (*str) += 2;
|
|
202 else
|
|
203 (*str)+=3;
|
|
204 return rval;
|
|
205 }
|
|
206
|
|
207 struct symstateinfo
|
|
208 {
|
|
209 asmstate_t *as;
|
|
210 lwasm_line_t *l;
|
|
211 int flags;
|
|
212 };
|
|
213
|
|
214 lwasm_expr_stack_t *lwasm_expr_lookup_symbol(char *sym, void *state)
|
|
215 {
|
|
216 lwasm_symbol_ent_t *se;
|
|
217 struct symstateinfo *st;
|
|
218 lwasm_expr_stack_t *rs;
|
|
219 lwasm_expr_term_t *t;
|
|
220 lwasm_expr_stack_node_t *n;
|
|
221
|
|
222 int val;
|
|
223
|
|
224 st = state;
|
|
225 debug_message(3, "lwasm_expr_lookup_symbol(): find '%s' (context=%d)", sym, st -> as -> context);
|
|
226
|
|
227 // check for special symbols first...
|
|
228 if (sym[1] == '\0')
|
|
229 {
|
|
230 switch (sym[0])
|
|
231 {
|
|
232 // current line address
|
|
233 case '*':
|
|
234 case '.':
|
|
235 val = st -> l -> codeaddr;
|
|
236 goto retconst;
|
|
237
|
|
238 case '<':
|
|
239 // previous branch point
|
|
240 // not implemented
|
|
241 break;
|
|
242 case '>':
|
|
243 // next branch point
|
|
244 // not implemented
|
|
245 break;
|
|
246 }
|
|
247 }
|
|
248
|
|
249 // look for local symbol first then global symbol
|
|
250 se = lwasm_find_symbol(st -> as, sym, st -> as -> context);
|
|
251 if (!se)
|
|
252 se = lwasm_find_symbol(st -> as, sym, -1);
|
|
253 debug_message(3, "lwasm_expr_lookup_symbol(): got '%p'", se);
|
|
254 if (!se)
|
|
255 {
|
|
256 register_error(st -> as, st -> l, 2, "Undefined symbol '%s'", sym);
|
|
257 return NULL;
|
|
258 }
|
|
259 // external reference - can not resolve it
|
|
260 if (se -> flags & SYMBOL_EXTERN)
|
|
261 {
|
|
262 return NULL;
|
|
263 }
|
|
264 if (st -> flags & EXPR_SECTCONST)
|
|
265 {
|
|
266 if (se -> sect == st -> l -> sect)
|
|
267 {
|
|
268 if (se -> expr)
|
|
269 goto retsym;
|
|
270 val = se -> value;
|
|
271 goto retconst;
|
|
272 }
|
|
273 }
|
|
274 if (st -> as -> outformat == OUTPUT_OBJ && se -> sect != NULL)
|
|
275 {
|
|
276 return NULL;
|
|
277 }
|
|
278 if (st -> as -> outformat != OUTPUT_OBJ || se -> sect == NULL)
|
|
279 {
|
|
280 // global symbol, intrasegment reference, or not an object target
|
|
281 val = se -> value;
|
|
282 goto retconst;
|
|
283 }
|
|
284
|
|
285 // an intersegment reference will return as NULL (to be resolved at output/link time)
|
|
286 // if se -> expr is NULL, it has to be an intersegment reference here
|
|
287 if (se -> expr == NULL)
|
|
288 {
|
|
289 return NULL;
|
|
290 }
|
|
291
|
|
292 retsym:
|
|
293 // duplicate the expression for return
|
|
294 rs = lwasm_expr_stack_create();
|
|
295 for (n = se -> expr -> head; n; n = n -> next)
|
|
296 {
|
|
297 lwasm_expr_stack_push(rs, n -> term);
|
|
298 }
|
|
299 return rs;
|
|
300
|
|
301 retconst:
|
|
302 rs = lwasm_expr_stack_create();
|
|
303 t = lwasm_expr_term_create_int(val);
|
|
304 lwasm_expr_stack_push(rs, t);
|
|
305 lwasm_expr_term_free(t);
|
|
306 return rs;
|
|
307 }
|
|
308
|
|
309 lwasm_expr_stack_t *lwasm_evaluate_expr(asmstate_t *as, lwasm_line_t *l, const char *inp, const char **outp, int flags)
|
|
310 {
|
|
311 struct symstateinfo st;
|
|
312
|
|
313 st.as = as;
|
|
314 st.l = l;
|
|
315 st.flags = flags;
|
|
316
|
|
317 debug_message(2, "Evaluate expression: %s", inp);
|
|
318
|
|
319 return(lwasm_expr_eval(inp, outp, lwasm_expr_lookup_symbol, &st));
|
|
320 }
|
|
321
|
|
322
|
|
323 int lwasm_reevaluate_expr(asmstate_t *as, lwasm_line_t *l, lwasm_expr_stack_t *s, int flags)
|
|
324 {
|
|
325 struct symstateinfo st;
|
|
326
|
|
327 st.as = as;
|
|
328 st.l = l;
|
|
329 st.flags = flags;
|
|
330 return(lwasm_expr_reval(s, lwasm_expr_lookup_symbol, &st));
|
|
331 }
|
|
332
|
|
333 // return 1 if no undefined symbols (externals and incompletes are okay)
|
|
334 // return 0 if there are undefined symbols
|
|
335 int lwasm_expr_result_ckconst(asmstate_t *as, lwasm_expr_stack_t *s)
|
|
336 {
|
|
337 lwasm_expr_stack_node_t *n;
|
|
338 lwasm_symbol_ent_t *se;
|
|
339
|
|
340 if (as -> outformat != OUTPUT_OBJ)
|
|
341 {
|
|
342 if (lwasm_expr_is_constant(s))
|
|
343 return 1;
|
|
344 else
|
|
345 return 0;
|
|
346 }
|
|
347
|
|
348 for (n = s -> head; n; n = n -> next)
|
|
349 {
|
|
350 if (n -> term -> term_type == LWASM_TERM_SYM)
|
|
351 {
|
|
352 se = lwasm_find_symbol(as, n -> term -> symbol, as -> context);
|
|
353 if (!se)
|
|
354 se = lwasm_find_symbol(as, n -> term -> symbol, -1);
|
|
355 if (!se)
|
|
356 return 0;
|
|
357 }
|
|
358 }
|
|
359 return 1;
|
|
360 }
|
|
361
|
|
362 /*
|
|
363 Evaluate an expression according to the flag value. Return 0 if a constant result was
|
|
364 obtained, 1 if an incomplete result was obtained, and -1 if an error was flagged.
|
|
365
|
|
366 */
|
|
367 int lwasm_expr_result2(asmstate_t *as, lwasm_line_t *l, char **inp, int flag, int *val, int slot)
|
|
368 {
|
|
369 lwasm_expr_stack_t *s = NULL;
|
|
370 const char *ep;
|
|
371 int rval;
|
|
372
|
|
373 if ((as -> passnum == 1 && !(flag & EXPR_REEVAL)) || slot < 0)
|
|
374 {
|
|
375 s = lwasm_evaluate_expr(as, l, *inp, &ep, flag);
|
|
376 if (slot >= 0)
|
|
377 {
|
|
378 l -> exprs[slot] = s;
|
|
379 l -> exprends[slot] = ep;
|
|
380 }
|
|
381 if (!s)
|
|
382 {
|
|
383 register_error(as, l, 1, "Bad expression");
|
|
384 *val = 0;
|
|
385 return -1;
|
|
386 }
|
|
387 *inp = (char *)ep;
|
|
388 if (slot >= 0)
|
|
389 {
|
|
390 // l -> exprends[slot] = (char *)ep;
|
|
391 l -> exprvals[slot] = lwasm_expr_get_value(s);
|
|
392 }
|
|
393 }
|
|
394 else if (l -> exprs[slot])
|
|
395 {
|
|
396 s = l -> exprs[slot];
|
|
397 lwasm_reevaluate_expr(as, l, s, flag);
|
|
398 l -> exprvals[slot] = lwasm_expr_get_value(s);
|
|
399 }
|
|
400 if (as -> passnum == 2 && slot >= 0)
|
|
401 *inp = l -> exprends[slot];
|
|
402
|
|
403 if (s && lwasm_expr_is_constant(s))
|
|
404 {
|
|
405 *val = lwasm_expr_get_value(s);
|
|
406 lwasm_expr_stack_free(s);
|
|
407 l -> exprs[slot] = NULL;
|
|
408 s = NULL;
|
|
409 return 0;
|
|
410 }
|
|
411
|
|
412 if (!s && slot >= 0)
|
|
413 {
|
|
414 *val = l -> exprvals[slot];
|
|
415 return 0;
|
|
416 }
|
|
417 else if (!s)
|
|
418 {
|
|
419 *val = 0;
|
|
420 return 0;
|
|
421 }
|
|
422
|
|
423 // was a constant result on pass 1 requested?
|
|
424 // that means we must have a constant on either pass
|
|
425 if (flag & EXPR_PASS1CONST)
|
|
426 {
|
|
427 *val = 0;
|
|
428 if (slot >= 0)
|
|
429 l -> exprvals[slot] = 0;
|
|
430 register_error(as, l, 1, "Illegal forward, external, or inter-section reference");
|
|
431 lwasm_expr_stack_free(s);
|
|
432 if (slot >= 0)
|
|
433 l -> exprs[slot] = NULL;
|
|
434 return -1;
|
|
435 }
|
|
436
|
|
437 return 1;
|
|
438 }
|
|
439
|
|
440 void debug_message(int level, const char *fmt, ...)
|
|
441 {
|
|
442 va_list args;
|
|
443
|
|
444 va_start(args, fmt);
|
|
445 if (debug_level >= level)
|
|
446 {
|
|
447 if (level > 0)
|
|
448 fprintf(stderr, "DEBUG %d: ", level);
|
|
449 vfprintf(stderr, fmt, args);
|
|
450 fputc('\n', stderr);
|
|
451 }
|
|
452 va_end(args);
|
|
453 }
|
|
454
|
|
455 int lwasm_next_context(asmstate_t *as)
|
|
456 {
|
|
457 int r;
|
|
458 r = as -> nextcontext;
|
|
459 as -> nextcontext += 1;
|
|
460 debug_message(3, "lwasm_next_context(): %d (%d) pass %d", r, as -> nextcontext, as -> passnum);
|
|
461 return r;
|
|
462 }
|
|
463
|