1 /*
2 * GAS-compatible parser
3 *
4 * Copyright (C) 2005-2007 Peter Johnson
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the author nor the names of other contributors
15 * may be used to endorse or promote products derived from this
16 * software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 */
30 #include <util.h>
31
32 #include <libyasm.h>
33
34 #include <ctype.h>
35 #include <limits.h>
36 #include <math.h>
37
38 #include "modules/parsers/gas/gas-parser.h"
39
40 typedef struct dir_lookup {
41 const char *name;
42 yasm_bytecode * (*handler) (yasm_parser_gas *, unsigned int);
43 unsigned int param;
44 enum gas_parser_state newstate;
45 } dir_lookup;
46
47 static void cpp_line_marker(yasm_parser_gas *parser_gas);
48 static void nasm_line_marker(yasm_parser_gas *parser_gas);
49 static yasm_bytecode *parse_instr(yasm_parser_gas *parser_gas);
50 static int parse_dirvals(yasm_parser_gas *parser_gas, yasm_valparamhead *vps);
51 static int parse_datavals(yasm_parser_gas *parser_gas, yasm_datavalhead *dvs);
52 static int parse_strvals(yasm_parser_gas *parser_gas, yasm_datavalhead *dvs);
53 static yasm_effaddr *parse_memaddr(yasm_parser_gas *parser_gas);
54 static yasm_insn_operand *parse_operand(yasm_parser_gas *parser_gas);
55 static yasm_expr *parse_expr(yasm_parser_gas *parser_gas);
56 static yasm_expr *parse_expr0(yasm_parser_gas *parser_gas);
57 static yasm_expr *parse_expr1(yasm_parser_gas *parser_gas);
58 static yasm_expr *parse_expr2(yasm_parser_gas *parser_gas);
59
60 static void define_label(yasm_parser_gas *parser_gas, char *name, int local);
61 static void define_lcomm(yasm_parser_gas *parser_gas, /*@only@*/ char *name,
62 yasm_expr *size, /*@null@*/ yasm_expr *align);
63 static yasm_section *gas_get_section
64 (yasm_parser_gas *parser_gas, /*@only@*/ char *name, /*@null@*/ char *flags,
65 /*@null@*/ char *type, /*@null@*/ yasm_valparamhead *objext_valparams,
66 int builtin);
67 static void gas_switch_section
68 (yasm_parser_gas *parser_gas, /*@only@*/ const char *name,
69 /*@null@*/ char *flags, /*@null@*/ char *type,
70 /*@null@*/ yasm_valparamhead *objext_valparams, int builtin);
71 static yasm_bytecode *gas_parser_align
72 (yasm_parser_gas *parser_gas, yasm_section *sect, yasm_expr *boundval,
73 /*@null@*/ yasm_expr *fillval, /*@null@*/ yasm_expr *maxskipval,
74 int power2);
75 static yasm_bytecode *gas_parser_dir_fill
76 (yasm_parser_gas *parser_gas, /*@only@*/ yasm_expr *repeat,
77 /*@only@*/ /*@null@*/ yasm_expr *size,
78 /*@only@*/ /*@null@*/ yasm_expr *value);
79
80 #define is_eol_tok(tok) ((tok) == '\n' || (tok) == ';' || (tok) == 0)
81 #define is_eol() is_eol_tok(curtok)
82
83 #define get_next_token() (curtok = gas_parser_lex(&curval, parser_gas))
84
85 static void
get_peek_token(yasm_parser_gas * parser_gas)86 get_peek_token(yasm_parser_gas *parser_gas)
87 {
88 char savech = parser_gas->tokch;
89 if (parser_gas->peek_token != NONE)
90 yasm_internal_error(N_("can only have one token of lookahead"));
91 parser_gas->peek_token =
92 gas_parser_lex(&parser_gas->peek_tokval, parser_gas);
93 parser_gas->peek_tokch = parser_gas->tokch;
94 parser_gas->tokch = savech;
95 }
96
97 static void
destroy_curtok_(yasm_parser_gas * parser_gas)98 destroy_curtok_(yasm_parser_gas *parser_gas)
99 {
100 if (curtok < 256)
101 ;
102 else switch ((enum tokentype)curtok) {
103 case INTNUM:
104 yasm_intnum_destroy(curval.intn);
105 break;
106 case FLTNUM:
107 yasm_floatnum_destroy(curval.flt);
108 break;
109 case ID:
110 case LABEL:
111 case STRING:
112 yasm_xfree(curval.str.contents);
113 break;
114 default:
115 break;
116 }
117 curtok = NONE; /* sanity */
118 }
119 #define destroy_curtok() destroy_curtok_(parser_gas)
120
121 /* Eat all remaining tokens to EOL, discarding all of them. If there's any
122 * intervening tokens, generates an error (junk at end of line).
123 */
124 static void
demand_eol_(yasm_parser_gas * parser_gas)125 demand_eol_(yasm_parser_gas *parser_gas)
126 {
127 if (is_eol())
128 return;
129
130 yasm_error_set(YASM_ERROR_SYNTAX,
131 N_("junk at end of line, first unrecognized character is `%c'"),
132 parser_gas->tokch);
133
134 do {
135 destroy_curtok();
136 get_next_token();
137 } while (!is_eol());
138 }
139 #define demand_eol() demand_eol_(parser_gas)
140
141 static int
expect_(yasm_parser_gas * parser_gas,int token)142 expect_(yasm_parser_gas *parser_gas, int token)
143 {
144 static char strch[] = "` '";
145 const char *str;
146
147 if (curtok == token)
148 return 1;
149
150 switch (token) {
151 case INTNUM: str = "integer"; break;
152 case FLTNUM: str = "floating point value"; break;
153 case STRING: str = "string"; break;
154 case REG: str = "register"; break;
155 case REGGROUP: str = "register group"; break;
156 case SEGREG: str = "segment register"; break;
157 case TARGETMOD: str = "target modifier"; break;
158 case LEFT_OP: str = "<<"; break;
159 case RIGHT_OP: str = ">>"; break;
160 case ID: str = "identifier"; break;
161 case LABEL: str = "label"; break;
162 default:
163 strch[1] = token;
164 str = strch;
165 break;
166 }
167 yasm_error_set(YASM_ERROR_PARSE, "expected %s", str);
168 destroy_curtok();
169 return 0;
170 }
171 #define expect(token) expect_(parser_gas, token)
172
173 static yasm_bytecode *
parse_line(yasm_parser_gas * parser_gas)174 parse_line(yasm_parser_gas *parser_gas)
175 {
176 yasm_bytecode *bc;
177 yasm_expr *e;
178 yasm_valparamhead vps;
179 char *id;
180 const dir_lookup *dir;
181
182 if (is_eol())
183 return NULL;
184
185 bc = parse_instr(parser_gas);
186 if (bc)
187 return bc;
188
189 switch (curtok) {
190 case ID:
191 id = ID_val;
192
193 /* See if it's a gas-specific directive */
194 dir = (const dir_lookup *)HAMT_search(parser_gas->dirs, id);
195 if (dir) {
196 parser_gas->state = dir->newstate;
197 get_next_token(); /* ID */
198 return dir->handler(parser_gas, dir->param);
199 }
200
201 get_next_token(); /* ID */
202 if (curtok == ':') {
203 /* Label */
204 parser_gas->state = INITIAL;
205 get_next_token(); /* : */
206 define_label(parser_gas, id, 0);
207 return parse_line(parser_gas);
208 } else if (curtok == '=') {
209 /* EQU */
210 /* TODO: allow redefinition, assigning to . (same as .org) */
211 parser_gas->state = INITIAL;
212 get_next_token(); /* = */
213 e = parse_expr(parser_gas);
214 if (e)
215 yasm_symtab_define_equ(p_symtab, id, e, cur_line);
216 else
217 yasm_error_set(YASM_ERROR_SYNTAX,
218 N_("expression expected after `%s'"), "=");
219 yasm_xfree(id);
220 return NULL;
221 }
222
223 /* possibly a directive; try to parse it */
224 parse_dirvals(parser_gas, &vps);
225 if (!yasm_object_directive(p_object, id, "gas", &vps, NULL,
226 cur_line)) {
227 yasm_vps_delete(&vps);
228 yasm_xfree(id);
229 return NULL;
230 }
231 yasm_vps_delete(&vps);
232 if (id[0] == '.')
233 yasm_warn_set(YASM_WARN_GENERAL,
234 N_("directive `%s' not recognized"), id);
235 else
236 yasm_error_set(YASM_ERROR_SYNTAX,
237 N_("instruction not recognized: `%s'"), id);
238 yasm_xfree(id);
239 return NULL;
240 case LABEL:
241 define_label(parser_gas, LABEL_val, 0);
242 get_next_token(); /* LABEL */
243 return parse_line(parser_gas);
244 case CPP_LINE_MARKER:
245 get_next_token();
246 cpp_line_marker(parser_gas);
247 return NULL;
248 case NASM_LINE_MARKER:
249 get_next_token();
250 nasm_line_marker(parser_gas);
251 return NULL;
252 default:
253 yasm_error_set(YASM_ERROR_SYNTAX,
254 N_("label or instruction expected at start of line"));
255 return NULL;
256 }
257 }
258
259 /*
260 Handle line markers generated by cpp.
261
262 We expect a positive integer (line) followed by a string (filename). If we
263 fail to find either of these, we treat the line as a comment. There is a
264 possibility of false positives (mistaking a comment for a line marker, when
265 the comment is not intended as a line marker) but this cannot be avoided
266 without adding a filter to the input before passing it to cpp.
267
268 This function is only called if the preprocessor was 'cpp', since the
269 CPP_LINE_MARKER token isn't generated for any other preprocessor. With any
270 other preprocessor, anything after a '#' is always treated as a comment.
271 */
272 static void
cpp_line_marker(yasm_parser_gas * parser_gas)273 cpp_line_marker(yasm_parser_gas *parser_gas)
274 {
275 yasm_valparamhead vps;
276 yasm_valparam *vp;
277 unsigned long line;
278 char *filename;
279
280 /* Line number. */
281 if (curtok != INTNUM) {
282 /* Skip over a comment. */
283 while (curtok != '\n')
284 get_next_token();
285
286 return;
287 }
288
289 if (yasm_intnum_sign(INTNUM_val) < 0) {
290 get_next_token(); /* INTNUM */
291 yasm_error_set(YASM_ERROR_SYNTAX,
292 N_("line number is negative"));
293 return;
294 }
295
296 line = yasm_intnum_get_uint(INTNUM_val);
297
298 /*
299 Set to (line - 1) since the directive indicates that the *next* line
300 will have the number given.
301
302 cpp should never produce line=0, but the if keeps us safe just incase.
303 */
304 if (line != 0)
305 line--;
306
307 yasm_intnum_destroy(INTNUM_val);
308 get_next_token(); /* INTNUM */
309
310 /* File name, in quotes. */
311 if (curtok != STRING) {
312 /* Skip over a comment. */
313 while (curtok != '\n')
314 get_next_token();
315
316 return;
317 }
318
319 filename = STRING_val.contents;
320 get_next_token();
321
322 /* Set linemap. */
323 yasm_linemap_set(parser_gas->linemap, filename, 0, line, 1);
324
325 /*
326 The first line marker in the file (which should be on the first line
327 of the file) will give us the name of the source file. This information
328 needs to be passed on to the debug format module.
329 */
330 if (parser_gas->seen_line_marker == 0) {
331 parser_gas->seen_line_marker = 1;
332
333 yasm_vps_initialize(&vps);
334 vp = yasm_vp_create_string(NULL, filename);
335 yasm_vps_append(&vps, vp);
336
337 yasm_object_directive(p_object, ".file", "gas", &vps, NULL, cur_line);
338
339 yasm_vps_delete(&vps);
340 } else
341 yasm_xfree(filename);
342
343 /* Skip flags. */
344 while (1) {
345 switch (curtok) {
346 case INTNUM:
347 break;
348
349 case '\n':
350 return;
351
352 default:
353 yasm_error_set(YASM_ERROR_SYNTAX,
354 N_("junk at end of cpp line marker"));
355 return;
356 }
357 get_next_token();
358 }
359 }
360
361 /*
362 Handle line markers generated by the nasm preproc.
363
364 We expect a positive integer (line) followed by a plus sign, followed by
365 another positive integer, followed by a string (filename).
366
367 This function is only called if the preprocessor was 'nasm', since the
368 NASM_LINE_MARKER token isn't generated for any other preprocessor.
369 */
370 static void
nasm_line_marker(yasm_parser_gas * parser_gas)371 nasm_line_marker(yasm_parser_gas *parser_gas)
372 {
373 yasm_valparamhead vps;
374 yasm_valparam *vp;
375 unsigned long line, incr;
376 char *filename;
377
378 /* Line number. */
379 if (!expect(INTNUM)) return;
380
381 if (yasm_intnum_sign(INTNUM_val) < 0) {
382 get_next_token(); /* INTNUM */
383 yasm_error_set(YASM_ERROR_SYNTAX,
384 N_("line number is negative"));
385 return;
386 }
387
388 line = yasm_intnum_get_uint(INTNUM_val);
389
390 /*
391 Set to (line - 1) since the directive indicates that the *next* line
392 will have the number given.
393
394 cpp should never produce line=0, but the if keeps us safe just incase.
395 */
396 if (line != 0)
397 line--;
398
399 yasm_intnum_destroy(INTNUM_val);
400 get_next_token(); /* INTNUM */
401
402 if (!expect('+')) return;
403 get_next_token(); /* + */
404
405 /* Line number increment. */
406 if (!expect(INTNUM)) return;
407
408 if (yasm_intnum_sign(INTNUM_val) < 0) {
409 get_next_token(); /* INTNUM */
410 yasm_error_set(YASM_ERROR_SYNTAX,
411 N_("line increment is negative"));
412 return;
413 }
414
415 incr = yasm_intnum_get_uint(INTNUM_val);
416 yasm_intnum_destroy(INTNUM_val);
417
418 /* File name is not in quotes, so need to switch to a different tokenizer
419 * state.
420 */
421 parser_gas->state = NASM_FILENAME;
422 get_next_token(); /* INTNUM */
423 if (!expect(STRING)) {
424 parser_gas->state = INITIAL;
425 return;
426 }
427
428 filename = STRING_val.contents;
429
430 /* Set linemap. */
431 yasm_linemap_set(parser_gas->linemap, filename, 0, line, incr);
432
433 /*
434 The first line marker in the file (which should be on the first line
435 of the file) will give us the name of the source file. This information
436 needs to be passed on to the debug format module.
437 */
438 if (parser_gas->seen_line_marker == 0) {
439 parser_gas->seen_line_marker = 1;
440
441 yasm_vps_initialize(&vps);
442 vp = yasm_vp_create_string(NULL, filename);
443 yasm_vps_append(&vps, vp);
444
445 yasm_object_directive(p_object, ".file", "gas", &vps, NULL, cur_line);
446
447 yasm_vps_delete(&vps);
448 } else
449 yasm_xfree(filename);
450
451 /* We need to poke back on the \n that was consumed by the tokenizer */
452 parser_gas->peek_token = '\n';
453 get_next_token();
454 }
455
456 /* Line directive */
457 static yasm_bytecode *
dir_line(yasm_parser_gas * parser_gas,unsigned int param)458 dir_line(yasm_parser_gas *parser_gas, unsigned int param)
459 {
460 if (!expect(INTNUM)) return NULL;
461 if (yasm_intnum_sign(INTNUM_val) < 0) {
462 get_next_token(); /* INTNUM */
463 yasm_error_set(YASM_ERROR_SYNTAX,
464 N_("line number is negative"));
465 return NULL;
466 }
467
468 parser_gas->dir_line = yasm_intnum_get_uint(INTNUM_val);
469 yasm_intnum_destroy(INTNUM_val);
470 get_next_token(); /* INTNUM */
471
472 if (parser_gas->dir_fileline == 3) {
473 /* Have both file and line */
474 yasm_linemap_set(parser_gas->linemap, NULL, 0,
475 parser_gas->dir_line, 1);
476 } else if (parser_gas->dir_fileline == 1) {
477 /* Had previous file directive only */
478 parser_gas->dir_fileline = 3;
479 yasm_linemap_set(parser_gas->linemap, parser_gas->dir_file, 0,
480 parser_gas->dir_line, 1);
481 } else {
482 /* Didn't see file yet */
483 parser_gas->dir_fileline = 2;
484 }
485 return NULL;
486 }
487
488 /* Alignment directives */
489
490 static yasm_bytecode *
dir_align(yasm_parser_gas * parser_gas,unsigned int param)491 dir_align(yasm_parser_gas *parser_gas, unsigned int param)
492 {
493 yasm_expr *bound, *fill=NULL, *maxskip=NULL;
494
495 bound = parse_expr(parser_gas);
496 if (!bound) {
497 yasm_error_set(YASM_ERROR_SYNTAX,
498 N_(".align directive must specify alignment"));
499 return NULL;
500 }
501
502 if (curtok == ',') {
503 get_next_token(); /* ',' */
504 fill = parse_expr(parser_gas);
505 if (curtok == ',') {
506 get_next_token(); /* ',' */
507 maxskip = parse_expr(parser_gas);
508 }
509 }
510
511 return gas_parser_align(parser_gas, cursect, bound, fill, maxskip,
512 (int)param);
513 }
514
515 static yasm_bytecode *
dir_org(yasm_parser_gas * parser_gas,unsigned int param)516 dir_org(yasm_parser_gas *parser_gas, unsigned int param)
517 {
518 yasm_intnum *start, *value=NULL;
519 yasm_bytecode *bc;
520
521 /* TODO: support expr instead of intnum */
522 if (!expect(INTNUM)) return NULL;
523 start = INTNUM_val;
524 get_next_token(); /* INTNUM */
525
526 if (curtok == ',') {
527 get_next_token(); /* ',' */
528 /* TODO: support expr instead of intnum */
529 if (!expect(INTNUM)) return NULL;
530 value = INTNUM_val;
531 get_next_token(); /* INTNUM */
532 }
533 if (value) {
534 bc = yasm_bc_create_org(yasm_intnum_get_uint(start),
535 yasm_intnum_get_uint(value), cur_line);
536 yasm_intnum_destroy(value);
537 } else
538 bc = yasm_bc_create_org(yasm_intnum_get_uint(start), 0,
539 cur_line);
540 yasm_intnum_destroy(start);
541 return bc;
542 }
543
544 /* Data visibility directives */
545
546 static yasm_bytecode *
dir_local(yasm_parser_gas * parser_gas,unsigned int param)547 dir_local(yasm_parser_gas *parser_gas, unsigned int param)
548 {
549 if (!expect(ID)) return NULL;
550 yasm_symtab_declare(p_symtab, ID_val, YASM_SYM_DLOCAL, cur_line);
551 yasm_xfree(ID_val);
552 get_next_token(); /* ID */
553 return NULL;
554 }
555
556 static yasm_bytecode *
dir_comm(yasm_parser_gas * parser_gas,unsigned int is_lcomm)557 dir_comm(yasm_parser_gas *parser_gas, unsigned int is_lcomm)
558 {
559 yasm_expr *align = NULL;
560 /*@null@*/ /*@dependent@*/ yasm_symrec *sym;
561 char *id;
562 yasm_expr *e;
563
564 if (!expect(ID)) return NULL;
565 id = ID_val;
566 get_next_token(); /* ID */
567 if (!expect(',')) {
568 yasm_xfree(id);
569 return NULL;
570 }
571 get_next_token(); /* , */
572 e = parse_expr(parser_gas);
573 if (!e) {
574 yasm_error_set(YASM_ERROR_SYNTAX, N_("size expected for `%s'"),
575 ".COMM");
576 return NULL;
577 }
578 if (curtok == ',') {
579 /* Optional alignment expression */
580 get_next_token(); /* ',' */
581 align = parse_expr(parser_gas);
582 }
583 /* If already explicitly declared local, treat like LCOMM */
584 if (is_lcomm
585 || ((sym = yasm_symtab_get(p_symtab, id))
586 && yasm_symrec_get_visibility(sym) == YASM_SYM_DLOCAL)) {
587 define_lcomm(parser_gas, id, e, align);
588 } else if (align) {
589 /* Give third parameter as objext valparam */
590 yasm_valparamhead *extvps = yasm_vps_create();
591 yasm_valparam *vp = yasm_vp_create_expr(NULL, align);
592 yasm_vps_append(extvps, vp);
593
594 sym = yasm_symtab_declare(p_symtab, id, YASM_SYM_COMMON,
595 cur_line);
596 yasm_symrec_set_common_size(sym, e);
597 yasm_symrec_set_objext_valparams(sym, extvps);
598
599 yasm_xfree(id);
600 } else {
601 sym = yasm_symtab_declare(p_symtab, id, YASM_SYM_COMMON,
602 cur_line);
603 yasm_symrec_set_common_size(sym, e);
604 yasm_xfree(id);
605 }
606 return NULL;
607 }
608
609 /* Integer data definition directives */
610
611 static yasm_bytecode *
dir_ascii(yasm_parser_gas * parser_gas,unsigned int withzero)612 dir_ascii(yasm_parser_gas *parser_gas, unsigned int withzero)
613 {
614 yasm_datavalhead dvs;
615 if (!parse_strvals(parser_gas, &dvs))
616 return NULL;
617 return yasm_bc_create_data(&dvs, 1, (int)withzero, p_object->arch,
618 cur_line);
619 }
620
621 static yasm_bytecode *
dir_data(yasm_parser_gas * parser_gas,unsigned int size)622 dir_data(yasm_parser_gas *parser_gas, unsigned int size)
623 {
624 yasm_datavalhead dvs;
625 if (!parse_datavals(parser_gas, &dvs))
626 return NULL;
627 return yasm_bc_create_data(&dvs, size, 0, p_object->arch, cur_line);
628 }
629
630 static yasm_bytecode *
dir_leb128(yasm_parser_gas * parser_gas,unsigned int sign)631 dir_leb128(yasm_parser_gas *parser_gas, unsigned int sign)
632 {
633 yasm_datavalhead dvs;
634 if (!parse_datavals(parser_gas, &dvs))
635 return NULL;
636 return yasm_bc_create_leb128(&dvs, (int)sign, cur_line);
637 }
638
639 /* Empty space / fill data definition directives */
640
641 static yasm_bytecode *
dir_zero(yasm_parser_gas * parser_gas,unsigned int param)642 dir_zero(yasm_parser_gas *parser_gas, unsigned int param)
643 {
644 yasm_bytecode *bc;
645 yasm_datavalhead dvs;
646 yasm_expr *e = parse_expr(parser_gas);
647 if (!e) {
648 yasm_error_set(YASM_ERROR_SYNTAX,
649 N_("expression expected after `%s'"), ".ZERO");
650 return NULL;
651 }
652
653 yasm_dvs_initialize(&dvs);
654 yasm_dvs_append(&dvs, yasm_dv_create_expr(
655 p_expr_new_ident(yasm_expr_int(yasm_intnum_create_uint(0)))));
656 bc = yasm_bc_create_data(&dvs, 1, 0, p_object->arch, cur_line);
657 yasm_bc_set_multiple(bc, e);
658 return bc;
659 }
660
661 static yasm_bytecode *
dir_skip(yasm_parser_gas * parser_gas,unsigned int param)662 dir_skip(yasm_parser_gas *parser_gas, unsigned int param)
663 {
664 yasm_expr *e, *e_val;
665 yasm_bytecode *bc;
666 yasm_datavalhead dvs;
667
668 e = parse_expr(parser_gas);
669 if (!e) {
670 yasm_error_set(YASM_ERROR_SYNTAX,
671 N_("expression expected after `%s'"), ".SKIP");
672 return NULL;
673 }
674 if (curtok != ',')
675 return yasm_bc_create_reserve(e, 1, cur_line);
676 get_next_token(); /* ',' */
677 e_val = parse_expr(parser_gas);
678 yasm_dvs_initialize(&dvs);
679 yasm_dvs_append(&dvs, yasm_dv_create_expr(e_val));
680 bc = yasm_bc_create_data(&dvs, 1, 0, p_object->arch, cur_line);
681
682 yasm_bc_set_multiple(bc, e);
683 return bc;
684 }
685
686 /* fill data definition directive */
687 static yasm_bytecode *
dir_fill(yasm_parser_gas * parser_gas,unsigned int param)688 dir_fill(yasm_parser_gas *parser_gas, unsigned int param)
689 {
690 yasm_expr *sz=NULL, *val=NULL;
691 yasm_expr *e = parse_expr(parser_gas);
692 if (!e) {
693 yasm_error_set(YASM_ERROR_SYNTAX,
694 N_("expression expected after `%s'"), ".FILL");
695 return NULL;
696 }
697 if (curtok == ',') {
698 get_next_token(); /* ',' */
699 sz = parse_expr(parser_gas);
700 if (curtok == ',') {
701 get_next_token(); /* ',' */
702 val = parse_expr(parser_gas);
703 }
704 }
705 return gas_parser_dir_fill(parser_gas, e, sz, val);
706 }
707
708 /* Section directives */
709
710 static yasm_bytecode *
dir_bss_section(yasm_parser_gas * parser_gas,unsigned int param)711 dir_bss_section(yasm_parser_gas *parser_gas, unsigned int param)
712 {
713 gas_switch_section(parser_gas, ".bss", NULL, NULL, NULL, 1);
714 return NULL;
715 }
716
717 static yasm_bytecode *
dir_data_section(yasm_parser_gas * parser_gas,unsigned int param)718 dir_data_section(yasm_parser_gas *parser_gas, unsigned int param)
719 {
720 gas_switch_section(parser_gas, ".data", NULL, NULL, NULL, 1);
721 return NULL;
722 }
723
724 static yasm_bytecode *
dir_text_section(yasm_parser_gas * parser_gas,unsigned int param)725 dir_text_section(yasm_parser_gas *parser_gas, unsigned int param)
726 {
727 gas_switch_section(parser_gas, ".text", NULL, NULL, NULL, 1);
728 return NULL;
729 }
730
731 static yasm_bytecode *
dir_section(yasm_parser_gas * parser_gas,unsigned int param)732 dir_section(yasm_parser_gas *parser_gas, unsigned int param)
733 {
734 /* DIR_SECTION ID ',' STRING ',' '@' ID ',' dirvals */
735 char *sectname, *flags = NULL, *type = NULL;
736 yasm_valparamhead vps;
737 int have_vps = 0;
738
739 if (!expect(ID)) return NULL;
740 sectname = ID_val;
741 get_next_token(); /* ID */
742
743 if (curtok == ',') {
744 get_next_token(); /* ',' */
745 if (!expect(STRING)) {
746 yasm_error_set(YASM_ERROR_SYNTAX,
747 N_("flag string expected"));
748 yasm_xfree(sectname);
749 return NULL;
750 }
751 flags = STRING_val.contents;
752 get_next_token(); /* STRING */
753 }
754
755 if (curtok == ',') {
756 get_next_token(); /* ',' */
757 if (!expect('@')) {
758 yasm_xfree(sectname);
759 yasm_xfree(flags);
760 return NULL;
761 }
762 get_next_token(); /* '@' */
763 if (!expect(ID)) {
764 yasm_xfree(sectname);
765 yasm_xfree(flags);
766 return NULL;
767 }
768 type = ID_val;
769 get_next_token(); /* ID */
770 }
771
772 if (curtok == ',') {
773 get_next_token(); /* ',' */
774 if (parse_dirvals(parser_gas, &vps))
775 have_vps = 1;
776 }
777
778 gas_switch_section(parser_gas, sectname, flags, type,
779 have_vps ? &vps : NULL, 0);
780 yasm_xfree(sectname);
781 yasm_xfree(flags);
782 return NULL;
783 }
784
785 /* Other directives */
786
787 static yasm_bytecode *
dir_equ(yasm_parser_gas * parser_gas,unsigned int param)788 dir_equ(yasm_parser_gas *parser_gas, unsigned int param)
789 {
790 yasm_expr *e;
791 char *id;
792
793 /* ID ',' expr */
794 if (!expect(ID)) return NULL;
795 id = ID_val;
796 get_next_token(); /* ID */
797 if (!expect(',')) {
798 yasm_xfree(id);
799 return NULL;
800 }
801 get_next_token(); /* ',' */
802 e = parse_expr(parser_gas);
803 if (e)
804 yasm_symtab_define_equ(p_symtab, id, e, cur_line);
805 else
806 yasm_error_set(YASM_ERROR_SYNTAX,
807 N_("expression expected after `%s'"), ",");
808 yasm_xfree(id);
809 return NULL;
810 }
811
812 static yasm_bytecode *
dir_file(yasm_parser_gas * parser_gas,unsigned int param)813 dir_file(yasm_parser_gas *parser_gas, unsigned int param)
814 {
815 yasm_valparamhead vps;
816 yasm_valparam *vp;
817
818 if (curtok == STRING) {
819 /* No file number; this form also sets the assembler's
820 * internal line number.
821 */
822 char *filename = STRING_val.contents;
823
824 get_next_token(); /* STRING */
825 if (parser_gas->dir_fileline == 3) {
826 /* Have both file and line */
827 const char *old_fn;
828 unsigned long old_line;
829
830 yasm_linemap_lookup(parser_gas->linemap, cur_line, &old_fn,
831 &old_line);
832 yasm_linemap_set(parser_gas->linemap, filename, 0, old_line,
833 1);
834 } else if (parser_gas->dir_fileline == 2) {
835 /* Had previous line directive only */
836 parser_gas->dir_fileline = 3;
837 yasm_linemap_set(parser_gas->linemap, filename, 0,
838 parser_gas->dir_line, 1);
839 } else {
840 /* Didn't see line yet, save file */
841 parser_gas->dir_fileline = 1;
842 if (parser_gas->dir_file)
843 yasm_xfree(parser_gas->dir_file);
844 parser_gas->dir_file = yasm__xstrdup(filename);
845 }
846
847 /* Pass change along to debug format */
848 yasm_vps_initialize(&vps);
849 vp = yasm_vp_create_string(NULL, filename);
850 yasm_vps_append(&vps, vp);
851
852 yasm_object_directive(p_object, ".file", "gas", &vps, NULL,
853 cur_line);
854
855 yasm_vps_delete(&vps);
856 return NULL;
857 }
858
859 /* fileno filename form */
860 yasm_vps_initialize(&vps);
861
862 if (!expect(INTNUM)) return NULL;
863 vp = yasm_vp_create_expr(NULL,
864 p_expr_new_ident(yasm_expr_int(INTNUM_val)));
865 yasm_vps_append(&vps, vp);
866 get_next_token(); /* INTNUM */
867
868 if (!expect(STRING)) {
869 yasm_vps_delete(&vps);
870 return NULL;
871 }
872 vp = yasm_vp_create_string(NULL, STRING_val.contents);
873 yasm_vps_append(&vps, vp);
874 get_next_token(); /* STRING */
875
876 yasm_object_directive(p_object, ".file", "gas", &vps, NULL,
877 cur_line);
878
879 yasm_vps_delete(&vps);
880 return NULL;
881 }
882
883
884 static yasm_bytecode *
dir_intel_syntax(yasm_parser_gas * parser_gas,unsigned int param)885 dir_intel_syntax(yasm_parser_gas *parser_gas, unsigned int param)
886 {
887 parser_gas->intel_syntax = 1;
888
889 do {
890 destroy_curtok();
891 get_next_token();
892 } while (!is_eol());
893 return NULL;
894 }
895
896 static yasm_bytecode *
dir_att_syntax(yasm_parser_gas * parser_gas,unsigned int param)897 dir_att_syntax(yasm_parser_gas *parser_gas, unsigned int param)
898 {
899 parser_gas->intel_syntax = 0;
900 return NULL;
901 }
902
903 static yasm_bytecode *
parse_instr(yasm_parser_gas * parser_gas)904 parse_instr(yasm_parser_gas *parser_gas)
905 {
906 yasm_bytecode *bc;
907 char *id;
908 size_t id_len;
909 uintptr_t prefix;
910
911 if (parser_gas->intel_syntax) {
912 bc = parse_instr_intel(parser_gas);
913 if (bc) {
914 yasm_warn_disable(YASM_WARN_UNREC_CHAR);
915 do {
916 destroy_curtok();
917 get_next_token();
918 } while (!is_eol());
919 yasm_warn_enable(YASM_WARN_UNREC_CHAR);
920 }
921 return bc;
922 }
923
924 if (curtok != ID)
925 return NULL;
926
927 id = ID_val;
928 id_len = ID_len;
929
930 /* instructions/prefixes must start with a letter */
931 if (!isalpha(id[0]))
932 return NULL;
933
934 /* check to be sure it's not a label or equ */
935 get_peek_token(parser_gas);
936 if (parser_gas->peek_token == ':' || parser_gas->peek_token == '=')
937 return NULL;
938
939 switch (yasm_arch_parse_check_insnprefix
940 (p_object->arch, ID_val, ID_len, cur_line, &bc, &prefix)) {
941 case YASM_ARCH_INSN:
942 {
943 yasm_insn *insn;
944
945 /* Propagate errors in case we got a warning from the arch */
946 yasm_errwarn_propagate(parser_gas->errwarns, cur_line);
947
948 insn = yasm_bc_get_insn(bc);
949
950 yasm_xfree(id);
951 get_next_token(); /* ID */
952 if (is_eol())
953 return bc; /* no operands */
954
955 /* parse operands */
956 for (;;) {
957 yasm_insn_operand *op = parse_operand(parser_gas);
958 if (!op) {
959 yasm_error_set(YASM_ERROR_SYNTAX,
960 N_("expression syntax error"));
961 yasm_bc_destroy(bc);
962 return NULL;
963 }
964 yasm_insn_ops_append(insn, op);
965
966 if (is_eol())
967 break;
968 if (!expect(',')) {
969 yasm_bc_destroy(bc);
970 return NULL;
971 }
972 get_next_token();
973 }
974 return bc;
975 }
976 case YASM_ARCH_PREFIX:
977 /* Propagate errors in case we got a warning from the arch */
978 yasm_errwarn_propagate(parser_gas->errwarns, cur_line);
979
980 yasm_xfree(id);
981 get_next_token(); /* ID */
982 bc = parse_instr(parser_gas);
983 if (!bc)
984 bc = yasm_arch_create_empty_insn(p_object->arch, cur_line);
985 yasm_insn_add_prefix(yasm_bc_get_insn(bc), prefix);
986 return bc;
987 default:
988 break;
989 }
990
991 /* Check for segment register used as prefix */
992 switch (yasm_arch_parse_check_regtmod(p_object->arch, ID_val, ID_len,
993 &prefix)) {
994 case YASM_ARCH_SEGREG:
995 yasm_xfree(id);
996 get_next_token(); /* ID */
997 bc = parse_instr(parser_gas);
998 if (!bc)
999 bc = yasm_arch_create_empty_insn(p_object->arch, cur_line);
1000 yasm_insn_add_seg_prefix(yasm_bc_get_insn(bc), prefix);
1001 return bc;
1002 default:
1003 return NULL;
1004 }
1005 }
1006
1007 static int
parse_dirvals(yasm_parser_gas * parser_gas,yasm_valparamhead * vps)1008 parse_dirvals(yasm_parser_gas *parser_gas, yasm_valparamhead *vps)
1009 {
1010 yasm_valparam *vp;
1011 yasm_expr *e;
1012 int num = 0;
1013
1014 yasm_vps_initialize(vps);
1015
1016 for (;;) {
1017 switch (curtok) {
1018 case ID:
1019 get_peek_token(parser_gas);
1020 switch (parser_gas->peek_token) {
1021 case '+': case '-':
1022 case '|': case '^': case '&': case '!':
1023 case '*': case '/': case '%': case LEFT_OP: case RIGHT_OP:
1024 e = parse_expr(parser_gas);
1025 vp = yasm_vp_create_expr(NULL, e);
1026 break;
1027 default:
1028 /* Just an ID */
1029 vp = yasm_vp_create_id(NULL, ID_val, '\0');
1030 get_next_token(); /* ID */
1031 break;
1032 }
1033 break;
1034 case STRING:
1035 vp = yasm_vp_create_string(NULL, STRING_val.contents);
1036 get_next_token(); /* STRING */
1037 break;
1038 case REG:
1039 e = p_expr_new_ident(yasm_expr_reg(REG_val));
1040 vp = yasm_vp_create_expr(NULL, e);
1041 get_next_token(); /* REG */
1042 break;
1043 case '@':
1044 /* XXX: is throwing it away *really* the right thing? */
1045 get_next_token(); /* @ */
1046 continue;
1047 default:
1048 e = parse_expr(parser_gas);
1049 if (!e)
1050 return num;
1051 vp = yasm_vp_create_expr(NULL, e);
1052 break;
1053 }
1054 yasm_vps_append(vps, vp);
1055 num++;
1056 if (curtok == ',')
1057 get_next_token(); /* ',' */
1058 }
1059 return num;
1060 }
1061
1062 static int
parse_datavals(yasm_parser_gas * parser_gas,yasm_datavalhead * dvs)1063 parse_datavals(yasm_parser_gas *parser_gas, yasm_datavalhead *dvs)
1064 {
1065 yasm_expr *e;
1066 yasm_dataval *dv;
1067 int num = 0;
1068
1069 yasm_dvs_initialize(dvs);
1070
1071 for (;;) {
1072 e = parse_expr(parser_gas);
1073 if (!e) {
1074 yasm_dvs_delete(dvs);
1075 yasm_dvs_initialize(dvs);
1076 return 0;
1077 }
1078 dv = yasm_dv_create_expr(e);
1079 yasm_dvs_append(dvs, dv);
1080 num++;
1081 if (curtok != ',')
1082 break;
1083 get_next_token(); /* ',' */
1084 }
1085 return num;
1086 }
1087
1088 static int
parse_strvals(yasm_parser_gas * parser_gas,yasm_datavalhead * dvs)1089 parse_strvals(yasm_parser_gas *parser_gas, yasm_datavalhead *dvs)
1090 {
1091 yasm_dataval *dv;
1092 int num = 0;
1093
1094 yasm_dvs_initialize(dvs);
1095
1096 for (;;) {
1097 if (!expect(STRING)) {
1098 yasm_dvs_delete(dvs);
1099 yasm_dvs_initialize(dvs);
1100 return 0;
1101 }
1102 dv = yasm_dv_create_string(STRING_val.contents, STRING_val.len);
1103 yasm_dvs_append(dvs, dv);
1104 get_next_token(); /* STRING */
1105 num++;
1106 if (curtok != ',')
1107 break;
1108 get_next_token(); /* ',' */
1109 }
1110 return num;
1111 }
1112
1113 /* instruction operands */
1114 /* memory addresses */
1115 static yasm_effaddr *
parse_memaddr(yasm_parser_gas * parser_gas)1116 parse_memaddr(yasm_parser_gas *parser_gas)
1117 {
1118 yasm_effaddr *ea = NULL;
1119 yasm_expr *e1, *e2;
1120 int strong = 0;
1121
1122 if (curtok == SEGREG) {
1123 uintptr_t segreg = SEGREG_val;
1124 get_next_token(); /* SEGREG */
1125 if (!expect(':')) return NULL;
1126 get_next_token(); /* ':' */
1127 ea = parse_memaddr(parser_gas);
1128 if (!ea)
1129 return NULL;
1130 yasm_ea_set_segreg(ea, segreg);
1131 return ea;
1132 }
1133
1134 /* We want to parse a leading expression, except when it's actually
1135 * just a memory address (with no preceding expression) such as
1136 * (REG...) or (,...).
1137 */
1138 get_peek_token(parser_gas);
1139 if (curtok != '(' || (parser_gas->peek_token != REG
1140 && parser_gas->peek_token != ','))
1141 e1 = parse_expr(parser_gas);
1142 else
1143 e1 = NULL;
1144
1145 if (curtok == '(') {
1146 int havereg = 0;
1147 uintptr_t reg = 0;
1148 yasm_intnum *scale = NULL;
1149
1150 get_next_token(); /* '(' */
1151
1152 /* base register */
1153 if (curtok == REG) {
1154 e2 = p_expr_new_ident(yasm_expr_reg(REG_val));
1155 get_next_token(); /* REG */
1156 } else
1157 e2 = p_expr_new_ident(yasm_expr_int(yasm_intnum_create_uint(0)));
1158
1159 if (curtok == ')')
1160 goto done;
1161
1162 if (!expect(',')) {
1163 yasm_error_set(YASM_ERROR_SYNTAX, N_("invalid memory expression"));
1164 if (e1) yasm_expr_destroy(e1);
1165 yasm_expr_destroy(e2);
1166 return NULL;
1167 }
1168 get_next_token(); /* ',' */
1169
1170 if (curtok == ')')
1171 goto done;
1172
1173 /* index register */
1174 if (curtok == REG) {
1175 reg = REG_val;
1176 havereg = 1;
1177 get_next_token(); /* REG */
1178 if (curtok != ',') {
1179 scale = yasm_intnum_create_uint(1);
1180 goto done;
1181 }
1182 get_next_token(); /* ',' */
1183 }
1184
1185 /* scale */
1186 if (!expect(INTNUM)) {
1187 yasm_error_set(YASM_ERROR_SYNTAX, N_("non-integer scale"));
1188 if (e1) yasm_expr_destroy(e1);
1189 yasm_expr_destroy(e2);
1190 return NULL;
1191 }
1192 scale = INTNUM_val;
1193 get_next_token(); /* INTNUM */
1194
1195 done:
1196 if (!expect(')')) {
1197 yasm_error_set(YASM_ERROR_SYNTAX, N_("invalid memory expression"));
1198 if (scale) yasm_intnum_destroy(scale);
1199 if (e1) yasm_expr_destroy(e1);
1200 yasm_expr_destroy(e2);
1201 return NULL;
1202 }
1203 get_next_token(); /* ')' */
1204
1205 if (scale) {
1206 if (!havereg) {
1207 if (yasm_intnum_get_uint(scale) != 1)
1208 yasm_warn_set(YASM_WARN_GENERAL,
1209 N_("scale factor of %u without an index register"),
1210 yasm_intnum_get_uint(scale));
1211 yasm_intnum_destroy(scale);
1212 } else
1213 e2 = p_expr_new(yasm_expr_expr(e2), YASM_EXPR_ADD,
1214 yasm_expr_expr(p_expr_new(yasm_expr_reg(reg), YASM_EXPR_MUL,
1215 yasm_expr_int(scale))));
1216 }
1217
1218 if (e1) {
1219 /* Ordering is critical here to correctly detecting presence of
1220 * RIP in RIP-relative expressions.
1221 */
1222 e1 = p_expr_new_tree(e2, YASM_EXPR_ADD, e1);
1223 } else
1224 e1 = e2;
1225 strong = 1;
1226 }
1227
1228 if (!e1)
1229 return NULL;
1230 ea = yasm_arch_ea_create(p_object->arch, e1);
1231 if (strong)
1232 ea->strong = 1;
1233 return ea;
1234 }
1235
1236 static yasm_insn_operand *
parse_operand(yasm_parser_gas * parser_gas)1237 parse_operand(yasm_parser_gas *parser_gas)
1238 {
1239 yasm_effaddr *ea;
1240 yasm_insn_operand *op;
1241 uintptr_t reg;
1242
1243 switch (curtok) {
1244 case REG:
1245 reg = REG_val;
1246 get_next_token(); /* REG */
1247 return yasm_operand_create_reg(reg);
1248 case SEGREG:
1249 /* need to see if it's really a memory address */
1250 get_peek_token(parser_gas);
1251 if (parser_gas->peek_token == ':') {
1252 ea = parse_memaddr(parser_gas);
1253 if (!ea)
1254 return NULL;
1255 return yasm_operand_create_mem(ea);
1256 }
1257 reg = SEGREG_val;
1258 get_next_token(); /* SEGREG */
1259 return yasm_operand_create_segreg(reg);
1260 case REGGROUP:
1261 {
1262 unsigned long regindex;
1263 reg = REGGROUP_val;
1264 get_next_token(); /* REGGROUP */
1265 if (curtok != '(')
1266 return yasm_operand_create_reg(reg);
1267 get_next_token(); /* '(' */
1268 if (!expect(INTNUM)) {
1269 yasm_error_set(YASM_ERROR_SYNTAX,
1270 N_("integer register index expected"));
1271 return NULL;
1272 }
1273 regindex = yasm_intnum_get_uint(INTNUM_val);
1274 get_next_token(); /* INTNUM */
1275 if (!expect(')')) {
1276 yasm_error_set(YASM_ERROR_SYNTAX,
1277 N_("missing closing parenthesis for register index"));
1278 return NULL;
1279 }
1280 get_next_token(); /* ')' */
1281 reg = yasm_arch_reggroup_get_reg(p_object->arch, reg, regindex);
1282 if (reg == 0) {
1283 yasm_error_set(YASM_ERROR_SYNTAX, N_("bad register index `%u'"),
1284 regindex);
1285 return NULL;
1286 }
1287 return yasm_operand_create_reg(reg);
1288 }
1289 case '$':
1290 {
1291 yasm_expr *e;
1292 get_next_token(); /* '$' */
1293 e = parse_expr(parser_gas);
1294 if (!e) {
1295 yasm_error_set(YASM_ERROR_SYNTAX,
1296 N_("expression missing after `%s'"), "$");
1297 return NULL;
1298 }
1299 return yasm_operand_create_imm(e);
1300 }
1301 case '*':
1302 get_next_token(); /* '*' */
1303 if (curtok == REG) {
1304 op = yasm_operand_create_reg(REG_val);
1305 get_next_token(); /* REG */
1306 } else {
1307 ea = parse_memaddr(parser_gas);
1308 if (!ea) {
1309 yasm_error_set(YASM_ERROR_SYNTAX,
1310 N_("expression missing after `%s'"), "*");
1311 return NULL;
1312 }
1313 op = yasm_operand_create_mem(ea);
1314 }
1315 op->deref = 1;
1316 return op;
1317 default:
1318 ea = parse_memaddr(parser_gas);
1319 if (!ea)
1320 return NULL;
1321 return yasm_operand_create_mem(ea);
1322 }
1323 }
1324
1325 /* Expression grammar parsed is:
1326 *
1327 * expr : expr0 [ {+,-} expr0...]
1328 * expr0 : expr1 [ {|,^,&,!} expr1...]
1329 * expr1 : expr2 [ {*,/,%,<<,>>} expr2...]
1330 * expr2 : { ~,+,- } expr2
1331 * | (expr)
1332 * | symbol
1333 * | number
1334 */
1335
1336 static yasm_expr *
parse_expr(yasm_parser_gas * parser_gas)1337 parse_expr(yasm_parser_gas *parser_gas)
1338 {
1339 yasm_expr *e, *f;
1340 e = parse_expr0(parser_gas);
1341 if (!e)
1342 return NULL;
1343
1344 while (curtok == '+' || curtok == '-') {
1345 int op = curtok;
1346 get_next_token();
1347 f = parse_expr0(parser_gas);
1348 if (!f) {
1349 yasm_expr_destroy(e);
1350 return NULL;
1351 }
1352
1353 switch (op) {
1354 case '+': e = p_expr_new_tree(e, YASM_EXPR_ADD, f); break;
1355 case '-': e = p_expr_new_tree(e, YASM_EXPR_SUB, f); break;
1356 }
1357 }
1358 return e;
1359 }
1360
1361 static yasm_expr *
parse_expr0(yasm_parser_gas * parser_gas)1362 parse_expr0(yasm_parser_gas *parser_gas)
1363 {
1364 yasm_expr *e, *f;
1365 e = parse_expr1(parser_gas);
1366 if (!e)
1367 return NULL;
1368
1369 while (curtok == '|' || curtok == '^' || curtok == '&' || curtok == '!') {
1370 int op = curtok;
1371 get_next_token();
1372 f = parse_expr1(parser_gas);
1373 if (!f) {
1374 yasm_expr_destroy(e);
1375 return NULL;
1376 }
1377
1378 switch (op) {
1379 case '|': e = p_expr_new_tree(e, YASM_EXPR_OR, f); break;
1380 case '^': e = p_expr_new_tree(e, YASM_EXPR_XOR, f); break;
1381 case '&': e = p_expr_new_tree(e, YASM_EXPR_AND, f); break;
1382 case '!': e = p_expr_new_tree(e, YASM_EXPR_NOR, f); break;
1383 }
1384 }
1385 return e;
1386 }
1387
1388 static yasm_expr *
parse_expr1(yasm_parser_gas * parser_gas)1389 parse_expr1(yasm_parser_gas *parser_gas)
1390 {
1391 yasm_expr *e, *f;
1392 e = parse_expr2(parser_gas);
1393 if (!e)
1394 return NULL;
1395
1396 while (curtok == '*' || curtok == '/' || curtok == '%' || curtok == LEFT_OP
1397 || curtok == RIGHT_OP) {
1398 int op = curtok;
1399 get_next_token();
1400 f = parse_expr2(parser_gas);
1401 if (!f) {
1402 yasm_expr_destroy(e);
1403 return NULL;
1404 }
1405
1406 switch (op) {
1407 case '*': e = p_expr_new_tree(e, YASM_EXPR_MUL, f); break;
1408 case '/': e = p_expr_new_tree(e, YASM_EXPR_DIV, f); break;
1409 case '%': e = p_expr_new_tree(e, YASM_EXPR_MOD, f); break;
1410 case LEFT_OP: e = p_expr_new_tree(e, YASM_EXPR_SHL, f); break;
1411 case RIGHT_OP: e = p_expr_new_tree(e, YASM_EXPR_SHR, f); break;
1412 }
1413 }
1414 return e;
1415 }
1416
1417 static yasm_expr *
parse_expr2(yasm_parser_gas * parser_gas)1418 parse_expr2(yasm_parser_gas *parser_gas)
1419 {
1420 yasm_expr *e;
1421 yasm_symrec *sym;
1422
1423 switch (curtok) {
1424 case '+':
1425 get_next_token();
1426 return parse_expr2(parser_gas);
1427 case '-':
1428 get_next_token();
1429 e = parse_expr2(parser_gas);
1430 if (!e)
1431 return NULL;
1432 return p_expr_new_branch(YASM_EXPR_NEG, e);
1433 case '~':
1434 get_next_token();
1435 e = parse_expr2(parser_gas);
1436 if (!e)
1437 return NULL;
1438 return p_expr_new_branch(YASM_EXPR_NOT, e);
1439 case '(':
1440 get_next_token();
1441 e = parse_expr(parser_gas);
1442 if (!e)
1443 return NULL;
1444 if (!expect(')')) {
1445 yasm_error_set(YASM_ERROR_SYNTAX, N_("missing parenthesis"));
1446 return NULL;
1447 }
1448 get_next_token();
1449 return e;
1450 case INTNUM:
1451 e = p_expr_new_ident(yasm_expr_int(INTNUM_val));
1452 get_next_token();
1453 return e;
1454 case FLTNUM:
1455 e = p_expr_new_ident(yasm_expr_float(FLTNUM_val));
1456 get_next_token();
1457 return e;
1458 case ID:
1459 {
1460 char *name = ID_val;
1461 get_next_token(); /* ID */
1462
1463 /* "." references the current assembly position */
1464 if (name[1] == '\0' && name[0] == '.')
1465 sym = yasm_symtab_define_curpos(p_symtab, ".",
1466 parser_gas->prev_bc, cur_line);
1467 else
1468 sym = yasm_symtab_use(p_symtab, name, cur_line);
1469 yasm_xfree(name);
1470
1471 if (curtok == '@') {
1472 yasm_symrec *wrt;
1473 /* TODO: this is needed for shared objects, e.g. sym@PLT */
1474 get_next_token(); /* '@' */
1475 if (!expect(ID)) {
1476 yasm_error_set(YASM_ERROR_SYNTAX,
1477 N_("expected identifier after `@'"));
1478 return NULL;
1479 }
1480 wrt = yasm_objfmt_get_special_sym(p_object, ID_val, "gas");
1481 yasm_xfree(ID_val);
1482 get_next_token(); /* ID */
1483 if (!wrt) {
1484 yasm_warn_set(YASM_WARN_GENERAL,
1485 N_("unrecognized identifier after `@'"));
1486 return p_expr_new_ident(yasm_expr_sym(sym));
1487 }
1488 return p_expr_new(yasm_expr_sym(sym), YASM_EXPR_WRT,
1489 yasm_expr_sym(wrt));
1490 }
1491
1492 return p_expr_new_ident(yasm_expr_sym(sym));
1493 }
1494 default:
1495 return NULL;
1496 }
1497 }
1498
1499 static void
define_label(yasm_parser_gas * parser_gas,char * name,int local)1500 define_label(yasm_parser_gas *parser_gas, char *name, int local)
1501 {
1502 if (!local) {
1503 if (parser_gas->locallabel_base)
1504 yasm_xfree(parser_gas->locallabel_base);
1505 parser_gas->locallabel_base_len = strlen(name);
1506 parser_gas->locallabel_base =
1507 yasm_xmalloc(parser_gas->locallabel_base_len+1);
1508 strcpy(parser_gas->locallabel_base, name);
1509 }
1510
1511 yasm_symtab_define_label(p_symtab, name, parser_gas->prev_bc, 1,
1512 cur_line);
1513 yasm_xfree(name);
1514 }
1515
1516 static void
define_lcomm(yasm_parser_gas * parser_gas,char * name,yasm_expr * size,yasm_expr * align)1517 define_lcomm(yasm_parser_gas *parser_gas, /*@only@*/ char *name,
1518 yasm_expr *size, /*@null@*/ yasm_expr *align)
1519 {
1520 /* Put into .bss section. */
1521 /*@dependent@*/ yasm_section *bss =
1522 gas_get_section(parser_gas, yasm__xstrdup(".bss"), NULL, NULL, NULL, 1);
1523
1524 if (align) {
1525 /* XXX: assume alignment is in bytes, not power-of-two */
1526 yasm_section_bcs_append(bss, gas_parser_align(parser_gas, bss, align,
1527 NULL, NULL, 0));
1528 }
1529
1530 yasm_symtab_define_label(p_symtab, name, yasm_section_bcs_last(bss), 1,
1531 cur_line);
1532 yasm_section_bcs_append(bss, yasm_bc_create_reserve(size, 1, cur_line));
1533 yasm_xfree(name);
1534 }
1535
1536 static yasm_section *
gas_get_section(yasm_parser_gas * parser_gas,char * name,char * flags,char * type,yasm_valparamhead * objext_valparams,int builtin)1537 gas_get_section(yasm_parser_gas *parser_gas, char *name,
1538 /*@null@*/ char *flags, /*@null@*/ char *type,
1539 /*@null@*/ yasm_valparamhead *objext_valparams,
1540 int builtin)
1541 {
1542 yasm_valparamhead vps;
1543 yasm_valparam *vp;
1544 char *gasflags;
1545 yasm_section *new_section;
1546
1547 yasm_vps_initialize(&vps);
1548 vp = yasm_vp_create_id(NULL, name, '\0');
1549 yasm_vps_append(&vps, vp);
1550
1551 if (!builtin) {
1552 if (flags)
1553 gasflags = yasm__xstrdup(flags);
1554 else
1555 gasflags = yasm__xstrdup("");
1556 vp = yasm_vp_create_string(yasm__xstrdup("gasflags"), gasflags);
1557 yasm_vps_append(&vps, vp);
1558 if (type) {
1559 vp = yasm_vp_create_id(NULL, type, '\0');
1560 yasm_vps_append(&vps, vp);
1561 }
1562 }
1563
1564 new_section = yasm_objfmt_section_switch(p_object, &vps, objext_valparams,
1565 cur_line);
1566
1567 yasm_vps_delete(&vps);
1568 return new_section;
1569 }
1570
1571 static void
gas_switch_section(yasm_parser_gas * parser_gas,const char * name,char * flags,char * type,yasm_valparamhead * objext_valparams,int builtin)1572 gas_switch_section(yasm_parser_gas *parser_gas, const char *name,
1573 /*@null@*/ char *flags, /*@null@*/ char *type,
1574 /*@null@*/ yasm_valparamhead *objext_valparams,
1575 int builtin)
1576 {
1577 yasm_section *new_section;
1578
1579 new_section = gas_get_section(parser_gas, yasm__xstrdup(name), flags, type,
1580 objext_valparams, builtin);
1581 if (new_section) {
1582 cursect = new_section;
1583 parser_gas->prev_bc = yasm_section_bcs_last(new_section);
1584 } else
1585 yasm_error_set(YASM_ERROR_GENERAL, N_("invalid section name `%s'"),
1586 name);
1587
1588 if (objext_valparams)
1589 yasm_vps_delete(objext_valparams);
1590 }
1591
1592 static yasm_bytecode *
gas_parser_align(yasm_parser_gas * parser_gas,yasm_section * sect,yasm_expr * boundval,yasm_expr * fillval,yasm_expr * maxskipval,int power2)1593 gas_parser_align(yasm_parser_gas *parser_gas, yasm_section *sect,
1594 yasm_expr *boundval, /*@null@*/ yasm_expr *fillval,
1595 /*@null@*/ yasm_expr *maxskipval, int power2)
1596 {
1597 yasm_intnum *boundintn;
1598
1599 /* Convert power of two to number of bytes if necessary */
1600 if (power2)
1601 boundval = yasm_expr_create(YASM_EXPR_SHL,
1602 yasm_expr_int(yasm_intnum_create_uint(1)),
1603 yasm_expr_expr(boundval), cur_line);
1604
1605 /* Largest .align in the section specifies section alignment. */
1606 boundintn = yasm_expr_get_intnum(&boundval, 0);
1607 if (boundintn) {
1608 unsigned long boundint = yasm_intnum_get_uint(boundintn);
1609
1610 /* Alignments must be a power of two. */
1611 if (is_exp2(boundint)) {
1612 if (boundint > yasm_section_get_align(sect))
1613 yasm_section_set_align(sect, boundint, cur_line);
1614 }
1615 }
1616
1617 return yasm_bc_create_align(boundval, fillval, maxskipval,
1618 yasm_section_is_code(sect) ?
1619 yasm_arch_get_fill(p_object->arch) : NULL,
1620 cur_line);
1621 }
1622
1623 static yasm_bytecode *
gas_parser_dir_fill(yasm_parser_gas * parser_gas,yasm_expr * repeat,yasm_expr * size,yasm_expr * value)1624 gas_parser_dir_fill(yasm_parser_gas *parser_gas, /*@only@*/ yasm_expr *repeat,
1625 /*@only@*/ /*@null@*/ yasm_expr *size,
1626 /*@only@*/ /*@null@*/ yasm_expr *value)
1627 {
1628 yasm_datavalhead dvs;
1629 yasm_bytecode *bc;
1630 unsigned int ssize;
1631
1632 if (size) {
1633 /*@dependent@*/ /*@null@*/ yasm_intnum *intn;
1634 intn = yasm_expr_get_intnum(&size, 0);
1635 if (!intn) {
1636 yasm_error_set(YASM_ERROR_NOT_ABSOLUTE,
1637 N_("size must be an absolute expression"));
1638 yasm_expr_destroy(repeat);
1639 yasm_expr_destroy(size);
1640 if (value)
1641 yasm_expr_destroy(value);
1642 return NULL;
1643 }
1644 ssize = yasm_intnum_get_uint(intn);
1645 } else
1646 ssize = 1;
1647
1648 if (!value)
1649 value = yasm_expr_create_ident(
1650 yasm_expr_int(yasm_intnum_create_uint(0)), cur_line);
1651
1652 yasm_dvs_initialize(&dvs);
1653 yasm_dvs_append(&dvs, yasm_dv_create_expr(value));
1654 bc = yasm_bc_create_data(&dvs, ssize, 0, p_object->arch, cur_line);
1655
1656 yasm_bc_set_multiple(bc, repeat);
1657
1658 return bc;
1659 }
1660
1661 static dir_lookup dirs_static[] = {
1662 /* FIXME: Whether this is power-of-two or not depends on arch and objfmt. */
1663 {".align", dir_align, 0, INITIAL},
1664 {".p2align", dir_align, 1, INITIAL},
1665 {".balign", dir_align, 0, INITIAL},
1666 {".org", dir_org, 0, INITIAL},
1667 /* data visibility directives */
1668 {".local", dir_local, 0, INITIAL},
1669 {".comm", dir_comm, 0, INITIAL},
1670 {".lcomm", dir_comm, 1, INITIAL},
1671 /* integer data declaration directives */
1672 {".byte", dir_data, 1, INITIAL},
1673 {".2byte", dir_data, 2, INITIAL},
1674 {".4byte", dir_data, 4, INITIAL},
1675 {".8byte", dir_data, 8, INITIAL},
1676 {".16byte", dir_data, 16, INITIAL},
1677 /* TODO: These should depend on arch */
1678 {".short", dir_data, 2, INITIAL},
1679 {".int", dir_data, 4, INITIAL},
1680 {".long", dir_data, 4, INITIAL},
1681 {".hword", dir_data, 2, INITIAL},
1682 {".quad", dir_data, 8, INITIAL},
1683 {".octa", dir_data, 16, INITIAL},
1684 /* XXX: At least on x86, this is 2 bytes */
1685 {".value", dir_data, 2, INITIAL},
1686 /* ASCII data declaration directives */
1687 {".ascii", dir_ascii, 0, INITIAL}, /* no terminating zero */
1688 {".asciz", dir_ascii, 1, INITIAL}, /* add terminating zero */
1689 {".string", dir_ascii, 1, INITIAL}, /* add terminating zero */
1690 /* LEB128 integer data declaration directives */
1691 {".sleb128", dir_leb128, 1, INITIAL}, /* signed */
1692 {".uleb128", dir_leb128, 0, INITIAL}, /* unsigned */
1693 /* floating point data declaration directives */
1694 {".float", dir_data, 4, INITIAL},
1695 {".single", dir_data, 4, INITIAL},
1696 {".double", dir_data, 8, INITIAL},
1697 {".tfloat", dir_data, 10, INITIAL},
1698 /* section directives */
1699 {".bss", dir_bss_section, 0, INITIAL},
1700 {".data", dir_data_section, 0, INITIAL},
1701 {".text", dir_text_section, 0, INITIAL},
1702 {".section", dir_section, 0, SECTION_DIRECTIVE},
1703 /* empty space/fill directives */
1704 {".skip", dir_skip, 0, INITIAL},
1705 {".space", dir_skip, 0, INITIAL},
1706 {".fill", dir_fill, 0, INITIAL},
1707 {".zero", dir_zero, 0, INITIAL},
1708 /* syntax directives */
1709 {".intel_syntax", dir_intel_syntax, 0, INITIAL},
1710 {".att_syntax", dir_att_syntax, 0, INITIAL},
1711 /* other directives */
1712 {".equ", dir_equ, 0, INITIAL},
1713 {".file", dir_file, 0, INITIAL},
1714 {".line", dir_line, 0, INITIAL},
1715 {".set", dir_equ, 0, INITIAL}
1716 };
1717
1718 static void
no_delete(void * data)1719 no_delete(void *data)
1720 {
1721 }
1722
1723 void
gas_parser_parse(yasm_parser_gas * parser_gas)1724 gas_parser_parse(yasm_parser_gas *parser_gas)
1725 {
1726 dir_lookup word;
1727 unsigned int i;
1728 int replace = 1;
1729
1730 word.name = ".word";
1731 word.handler = dir_data;
1732 word.param = yasm_arch_wordsize(p_object->arch)/8;
1733 word.newstate = INITIAL;
1734
1735 /* Create directive lookup */
1736 parser_gas->dirs = HAMT_create(1, yasm_internal_error_);
1737 HAMT_insert(parser_gas->dirs, word.name, &word, &replace, no_delete);
1738 for (i=0; i<NELEMS(dirs_static); i++) {
1739 replace = 1;
1740 HAMT_insert(parser_gas->dirs, dirs_static[i].name,
1741 &dirs_static[i], &replace, no_delete);
1742 }
1743
1744 while (get_next_token() != 0) {
1745 yasm_bytecode *bc = NULL, *temp_bc;
1746
1747 if (!is_eol()) {
1748 bc = parse_line(parser_gas);
1749 demand_eol();
1750 }
1751
1752 yasm_errwarn_propagate(parser_gas->errwarns, cur_line);
1753
1754 temp_bc = yasm_section_bcs_append(cursect, bc);
1755 if (temp_bc)
1756 parser_gas->prev_bc = temp_bc;
1757 if (curtok == ';')
1758 continue; /* don't advance line number until \n */
1759 if (parser_gas->save_input)
1760 yasm_linemap_add_source(parser_gas->linemap,
1761 temp_bc,
1762 (char *)parser_gas->save_line[parser_gas->save_last ^ 1]);
1763 yasm_linemap_goto_next(parser_gas->linemap);
1764 parser_gas->dir_line++; /* keep track for .line followed by .file */
1765 }
1766
1767 HAMT_destroy(parser_gas->dirs, no_delete);
1768 }
1769