• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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