Subversion Repositories Kolibri OS

Rev

Rev 647 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. /*
  2.  *  GAS like assembler for TCC
  3.  *
  4.  *  Copyright (c) 2001-2004 Fabrice Bellard
  5.  *
  6.  * This library is free software; you can redistribute it and/or
  7.  * modify it under the terms of the GNU Lesser General Public
  8.  * License as published by the Free Software Foundation; either
  9.  * version 2 of the License, or (at your option) any later version.
  10.  *
  11.  * This library is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14.  * Lesser General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU Lesser General Public
  17.  * License along with this library; if not, write to the Free Software
  18.  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  19.  */
  20.  
  21. #include "tcc.h"
  22. #ifdef CONFIG_TCC_ASM
  23.  
  24. ST_FUNC int asm_get_local_label_name(TCCState *s1, unsigned int n)
  25. {
  26.     char buf[64];
  27.     TokenSym *ts;
  28.  
  29.     snprintf(buf, sizeof(buf), "L..%u", n);
  30.     ts = tok_alloc(buf, strlen(buf));
  31.     return ts->tok;
  32. }
  33.  
  34. ST_FUNC void asm_expr(TCCState *s1, ExprValue *pe);
  35. static int tcc_assemble_internal(TCCState *s1, int do_preprocess);
  36. static Sym sym_dot;
  37.  
  38. /* We do not use the C expression parser to handle symbols. Maybe the
  39.    C expression parser could be tweaked to do so. */
  40.  
  41. static void asm_expr_unary(TCCState *s1, ExprValue *pe)
  42. {
  43.     Sym *sym;
  44.     int op, n, label;
  45.     const char *p;
  46.  
  47.     switch(tok) {
  48.     case TOK_PPNUM:
  49.         p = tokc.str.data;
  50.         n = strtoul(p, (char **)&p, 0);
  51.         if (*p == 'b' || *p == 'f') {
  52.             /* backward or forward label */
  53.             label = asm_get_local_label_name(s1, n);
  54.             sym = label_find(label);
  55.             if (*p == 'b') {
  56.                 /* backward : find the last corresponding defined label */
  57.                 if (sym && sym->r == 0)
  58.                     sym = sym->prev_tok;
  59.                 if (!sym)
  60.                     tcc_error("local label '%d' not found backward", n);
  61.             } else {
  62.                 /* forward */
  63.                 if (!sym || sym->r) {
  64.                     /* if the last label is defined, then define a new one */
  65.                     sym = label_push(&s1->asm_labels, label, 0);
  66.                     sym->type.t = VT_STATIC | VT_VOID;
  67.                 }
  68.             }
  69.             pe->v = 0;
  70.             pe->sym = sym;
  71.         } else if (*p == '\0') {
  72.             pe->v = n;
  73.             pe->sym = NULL;
  74.         } else {
  75.             tcc_error("invalid number syntax");
  76.         }
  77.         next();
  78.         break;
  79.     case '+':
  80.         next();
  81.         asm_expr_unary(s1, pe);
  82.         break;
  83.     case '-':
  84.     case '~':
  85.         op = tok;
  86.         next();
  87.         asm_expr_unary(s1, pe);
  88.         if (pe->sym)
  89.             tcc_error("invalid operation with label");
  90.         if (op == '-')
  91.             pe->v = -pe->v;
  92.         else
  93.             pe->v = ~pe->v;
  94.         break;
  95.     case TOK_CCHAR:
  96.     case TOK_LCHAR:
  97.         pe->v = tokc.i;
  98.         pe->sym = NULL;
  99.         next();
  100.         break;
  101.     case '(':
  102.         next();
  103.         asm_expr(s1, pe);
  104.         skip(')');
  105.         break;
  106.     case '.':
  107.         pe->v = 0;
  108.         pe->sym = &sym_dot;
  109.         sym_dot.type.t = VT_VOID | VT_STATIC;
  110.         sym_dot.r = cur_text_section->sh_num;
  111.         sym_dot.jnext = ind;
  112.         next();
  113.         break;
  114.     default:
  115.         if (tok >= TOK_IDENT) {
  116.             /* label case : if the label was not found, add one */
  117.             sym = label_find(tok);
  118.             if (!sym) {
  119.                 sym = label_push(&s1->asm_labels, tok, 0);
  120.                 /* NOTE: by default, the symbol is global */
  121.                 sym->type.t = VT_VOID;
  122.             }
  123.             if (sym->r == SHN_ABS) {
  124.                 /* if absolute symbol, no need to put a symbol value */
  125.                 pe->v = sym->jnext;
  126.                 pe->sym = NULL;
  127.             } else {
  128.                 pe->v = 0;
  129.                 pe->sym = sym;
  130.             }
  131.             next();
  132.         } else {
  133.             tcc_error("bad expression syntax [%s]", get_tok_str(tok, &tokc));
  134.         }
  135.         break;
  136.     }
  137. }
  138.    
  139. static void asm_expr_prod(TCCState *s1, ExprValue *pe)
  140. {
  141.     int op;
  142.     ExprValue e2;
  143.  
  144.     asm_expr_unary(s1, pe);
  145.     for(;;) {
  146.         op = tok;
  147.         if (op != '*' && op != '/' && op != '%' &&
  148.             op != TOK_SHL && op != TOK_SAR)
  149.             break;
  150.         next();
  151.         asm_expr_unary(s1, &e2);
  152.         if (pe->sym || e2.sym)
  153.             tcc_error("invalid operation with label");
  154.         switch(op) {
  155.         case '*':
  156.             pe->v *= e2.v;
  157.             break;
  158.         case '/':  
  159.             if (e2.v == 0) {
  160.             div_error:
  161.                 tcc_error("division by zero");
  162.             }
  163.             pe->v /= e2.v;
  164.             break;
  165.         case '%':  
  166.             if (e2.v == 0)
  167.                 goto div_error;
  168.             pe->v %= e2.v;
  169.             break;
  170.         case TOK_SHL:
  171.             pe->v <<= e2.v;
  172.             break;
  173.         default:
  174.         case TOK_SAR:
  175.             pe->v >>= e2.v;
  176.             break;
  177.         }
  178.     }
  179. }
  180.  
  181. static void asm_expr_logic(TCCState *s1, ExprValue *pe)
  182. {
  183.     int op;
  184.     ExprValue e2;
  185.  
  186.     asm_expr_prod(s1, pe);
  187.     for(;;) {
  188.         op = tok;
  189.         if (op != '&' && op != '|' && op != '^')
  190.             break;
  191.         next();
  192.         asm_expr_prod(s1, &e2);
  193.         if (pe->sym || e2.sym)
  194.             tcc_error("invalid operation with label");
  195.         switch(op) {
  196.         case '&':
  197.             pe->v &= e2.v;
  198.             break;
  199.         case '|':  
  200.             pe->v |= e2.v;
  201.             break;
  202.         default:
  203.         case '^':
  204.             pe->v ^= e2.v;
  205.             break;
  206.         }
  207.     }
  208. }
  209.  
  210. static inline void asm_expr_sum(TCCState *s1, ExprValue *pe)
  211. {
  212.     int op;
  213.     ExprValue e2;
  214.  
  215.     asm_expr_logic(s1, pe);
  216.     for(;;) {
  217.         op = tok;
  218.         if (op != '+' && op != '-')
  219.             break;
  220.         next();
  221.         asm_expr_logic(s1, &e2);
  222.         if (op == '+') {
  223.             if (pe->sym != NULL && e2.sym != NULL)
  224.                 goto cannot_relocate;
  225.             pe->v += e2.v;
  226.             if (pe->sym == NULL && e2.sym != NULL)
  227.                 pe->sym = e2.sym;
  228.         } else {
  229.             pe->v -= e2.v;
  230.             /* NOTE: we are less powerful than gas in that case
  231.                because we store only one symbol in the expression */
  232.             if (!pe->sym && !e2.sym) {
  233.                 /* OK */
  234.             } else if (pe->sym && !e2.sym) {
  235.                 /* OK */
  236.             } else if (pe->sym && e2.sym) {
  237.                 if (pe->sym == e2.sym) {
  238.                     /* OK */
  239.                 } else if (pe->sym->r == e2.sym->r && pe->sym->r != 0) {
  240.                     /* we also accept defined symbols in the same section */
  241.                     pe->v += pe->sym->jnext - e2.sym->jnext;
  242.                 } else {
  243.                     goto cannot_relocate;
  244.                 }
  245.                 pe->sym = NULL; /* same symbols can be subtracted to NULL */
  246.             } else {
  247.             cannot_relocate:
  248.                 tcc_error("invalid operation with label");
  249.             }
  250.         }
  251.     }
  252. }
  253.  
  254. ST_FUNC void asm_expr(TCCState *s1, ExprValue *pe)
  255. {
  256.     asm_expr_sum(s1, pe);
  257. }
  258.  
  259. ST_FUNC int asm_int_expr(TCCState *s1)
  260. {
  261.     ExprValue e;
  262.     asm_expr(s1, &e);
  263.     if (e.sym)
  264.         expect("constant");
  265.     return e.v;
  266. }
  267.  
  268. /* NOTE: the same name space as C labels is used to avoid using too
  269.    much memory when storing labels in TokenStrings */
  270. static void asm_new_label1(TCCState *s1, int label, int is_local,
  271.                            int sh_num, int value)
  272. {
  273.     Sym *sym;
  274.  
  275.     sym = label_find(label);
  276.     if (sym) {
  277.         if (sym->r) {
  278.             /* the label is already defined */
  279.             if (!is_local) {
  280.                 tcc_error("assembler label '%s' already defined",
  281.                       get_tok_str(label, NULL));
  282.             } else {
  283.                 /* redefinition of local labels is possible */
  284.                 goto new_label;
  285.             }
  286.         }
  287.     } else {
  288.     new_label:
  289.         sym = label_push(&s1->asm_labels, label, 0);
  290.         sym->type.t = VT_STATIC | VT_VOID;
  291.     }
  292.     sym->r = sh_num;
  293.     sym->jnext = value;
  294. }
  295.  
  296. static void asm_new_label(TCCState *s1, int label, int is_local)
  297. {
  298.     asm_new_label1(s1, label, is_local, cur_text_section->sh_num, ind);
  299. }
  300.  
  301. static void asm_free_labels(TCCState *st)
  302. {
  303.     Sym *s, *s1;
  304.     Section *sec;
  305.  
  306.     for(s = st->asm_labels; s != NULL; s = s1) {
  307.         s1 = s->prev;
  308.         /* define symbol value in object file */
  309.         if (s->r) {
  310.             if (s->r == SHN_ABS)
  311.                 sec = SECTION_ABS;
  312.             else
  313.                 sec = st->sections[s->r];
  314.             put_extern_sym2(s, sec, s->jnext, 0, 0);
  315.         }
  316.         /* remove label */
  317.         table_ident[s->v - TOK_IDENT]->sym_label = NULL;
  318.         sym_free(s);
  319.     }
  320.     st->asm_labels = NULL;
  321. }
  322.  
  323. static void use_section1(TCCState *s1, Section *sec)
  324. {
  325.     cur_text_section->data_offset = ind;
  326.     cur_text_section = sec;
  327.     ind = cur_text_section->data_offset;
  328. }
  329.  
  330. static void use_section(TCCState *s1, const char *name)
  331. {
  332.     Section *sec;
  333.     sec = find_section(s1, name);
  334.     use_section1(s1, sec);
  335. }
  336.  
  337. static void asm_parse_directive(TCCState *s1)
  338. {
  339.     int n, offset, v, size, tok1;
  340.     Section *sec;
  341.     uint8_t *ptr;
  342.  
  343.     /* assembler directive */
  344.     sec = cur_text_section;
  345.     switch(tok) {
  346.     case TOK_ASMDIR_align:
  347.     case TOK_ASMDIR_p2align:
  348.     case TOK_ASMDIR_skip:
  349.     case TOK_ASMDIR_space:
  350.         tok1 = tok;
  351.         next();
  352.         n = asm_int_expr(s1);
  353.         if (tok1 == TOK_ASMDIR_p2align)
  354.         {
  355.             if (n < 0 || n > 30)
  356.                 tcc_error("invalid p2align, must be between 0 and 30");
  357.             n = 1 << n;
  358.             tok1 = TOK_ASMDIR_align;
  359.         }
  360.         if (tok1 == TOK_ASMDIR_align) {
  361.             if (n < 0 || (n & (n-1)) != 0)
  362.                 tcc_error("alignment must be a positive power of two");
  363.             offset = (ind + n - 1) & -n;
  364.             size = offset - ind;
  365.             /* the section must have a compatible alignment */
  366.             if (sec->sh_addralign < n)
  367.                 sec->sh_addralign = n;
  368.         } else {
  369.             size = n;
  370.         }
  371.         v = 0;
  372.         if (tok == ',') {
  373.             next();
  374.             v = asm_int_expr(s1);
  375.         }
  376.     zero_pad:
  377.         if (sec->sh_type != SHT_NOBITS) {
  378.             sec->data_offset = ind;
  379.             ptr = section_ptr_add(sec, size);
  380.             memset(ptr, v, size);
  381.         }
  382.         ind += size;
  383.         break;
  384.     case TOK_ASMDIR_quad:
  385.         next();
  386.         for(;;) {
  387.             uint64_t vl;
  388.             const char *p;
  389.  
  390.             p = tokc.str.data;
  391.             if (tok != TOK_PPNUM) {
  392.             error_constant:
  393.                 tcc_error("64 bit constant");
  394.             }
  395.             vl = strtoll(p, (char **)&p, 0);
  396.             if (*p != '\0')
  397.                 goto error_constant;
  398.             next();
  399.             if (sec->sh_type != SHT_NOBITS) {
  400.                 /* XXX: endianness */
  401.                 gen_le32(vl);
  402.                 gen_le32(vl >> 32);
  403.             } else {
  404.                 ind += 8;
  405.             }
  406.             if (tok != ',')
  407.                 break;
  408.             next();
  409.         }
  410.         break;
  411.     case TOK_ASMDIR_byte:
  412.         size = 1;
  413.         goto asm_data;
  414.     case TOK_ASMDIR_word:
  415.     case TOK_ASMDIR_short:
  416.         size = 2;
  417.         goto asm_data;
  418.     case TOK_ASMDIR_long:
  419.     case TOK_ASMDIR_int:
  420.         size = 4;
  421.     asm_data:
  422.         next();
  423.         for(;;) {
  424.             ExprValue e;
  425.             asm_expr(s1, &e);
  426.             if (sec->sh_type != SHT_NOBITS) {
  427.                 if (size == 4) {
  428.                     gen_expr32(&e);
  429.                 } else {
  430.                     if (e.sym)
  431.                         expect("constant");
  432.                     if (size == 1)
  433.                         g(e.v);
  434.                     else
  435.                         gen_le16(e.v);
  436.                 }
  437.             } else {
  438.                 ind += size;
  439.             }
  440.             if (tok != ',')
  441.                 break;
  442.             next();
  443.         }
  444.         break;
  445.     case TOK_ASMDIR_fill:
  446.         {
  447.             int repeat, size, val, i, j;
  448.             uint8_t repeat_buf[8];
  449.             next();
  450.             repeat = asm_int_expr(s1);
  451.             if (repeat < 0) {
  452.                 tcc_error("repeat < 0; .fill ignored");
  453.                 break;
  454.             }
  455.             size = 1;
  456.             val = 0;
  457.             if (tok == ',') {
  458.                 next();
  459.                 size = asm_int_expr(s1);
  460.                 if (size < 0) {
  461.                     tcc_error("size < 0; .fill ignored");
  462.                     break;
  463.                 }
  464.                 if (size > 8)
  465.                     size = 8;
  466.                 if (tok == ',') {
  467.                     next();
  468.                     val = asm_int_expr(s1);
  469.                 }
  470.             }
  471.             /* XXX: endianness */
  472.             repeat_buf[0] = val;
  473.             repeat_buf[1] = val >> 8;
  474.             repeat_buf[2] = val >> 16;
  475.             repeat_buf[3] = val >> 24;
  476.             repeat_buf[4] = 0;
  477.             repeat_buf[5] = 0;
  478.             repeat_buf[6] = 0;
  479.             repeat_buf[7] = 0;
  480.             for(i = 0; i < repeat; i++) {
  481.                 for(j = 0; j < size; j++) {
  482.                     g(repeat_buf[j]);
  483.                 }
  484.             }
  485.         }
  486.         break;
  487.     case TOK_ASMDIR_rept:
  488.         {
  489.             int repeat;
  490.             TokenString init_str;
  491.             ParseState saved_parse_state = {0};
  492.             next();
  493.             repeat = asm_int_expr(s1);
  494.             tok_str_new(&init_str);
  495.             next();
  496.             while ((tok != TOK_ASMDIR_endr) && (tok != CH_EOF)) {
  497.                 tok_str_add_tok(&init_str);
  498.                 next();
  499.             }
  500.             if (tok == CH_EOF) tcc_error("we at end of file, .endr not found");
  501.             next();
  502.             tok_str_add(&init_str, -1);
  503.             tok_str_add(&init_str, 0);
  504.             save_parse_state(&saved_parse_state);
  505.             begin_macro(&init_str, 0);
  506.             while (repeat-- > 0) {
  507.                 tcc_assemble_internal(s1, (parse_flags & PARSE_FLAG_PREPROCESS));
  508.                 macro_ptr = init_str.str;
  509.             }
  510.             end_macro();
  511.             restore_parse_state(&saved_parse_state);
  512.             break;
  513.         }
  514.     case TOK_ASMDIR_org:
  515.         {
  516.             unsigned long n;
  517.             next();
  518.             /* XXX: handle section symbols too */
  519.             n = asm_int_expr(s1);
  520.             if (n < ind)
  521.                 tcc_error("attempt to .org backwards");
  522.             v = 0;
  523.             size = n - ind;
  524.             goto zero_pad;
  525.         }
  526.         break;
  527.     case TOK_ASMDIR_globl:
  528.     case TOK_ASMDIR_global:
  529.     case TOK_ASMDIR_weak:
  530.     case TOK_ASMDIR_hidden:
  531.     tok1 = tok;
  532.         do {
  533.             Sym *sym;
  534.  
  535.             next();
  536.             sym = label_find(tok);
  537.             if (!sym) {
  538.                 sym = label_push(&s1->asm_labels, tok, 0);
  539.                 sym->type.t = VT_VOID;
  540.             }
  541.             if (tok1 != TOK_ASMDIR_hidden)
  542.                 sym->type.t &= ~VT_STATIC;
  543.             if (tok1 == TOK_ASMDIR_weak)
  544.                 sym->type.t |= VT_WEAK;
  545.             else if (tok1 == TOK_ASMDIR_hidden)
  546.                 sym->type.t |= STV_HIDDEN << VT_VIS_SHIFT;
  547.             next();
  548.         } while (tok == ',');
  549.         break;
  550.     case TOK_ASMDIR_string:
  551.     case TOK_ASMDIR_ascii:
  552.     case TOK_ASMDIR_asciz:
  553.         {
  554.             const uint8_t *p;
  555.             int i, size, t;
  556.  
  557.             t = tok;
  558.             next();
  559.             for(;;) {
  560.                 if (tok != TOK_STR)
  561.                     expect("string constant");
  562.                 p = tokc.str.data;
  563.                 size = tokc.str.size;
  564.                 if (t == TOK_ASMDIR_ascii && size > 0)
  565.                     size--;
  566.                 for(i = 0; i < size; i++)
  567.                     g(p[i]);
  568.                 next();
  569.                 if (tok == ',') {
  570.                     next();
  571.                 } else if (tok != TOK_STR) {
  572.                     break;
  573.                 }
  574.             }
  575.         }
  576.         break;
  577.     case TOK_ASMDIR_text:
  578.     case TOK_ASMDIR_data:
  579.     case TOK_ASMDIR_bss:
  580.         {
  581.             char sname[64];
  582.             tok1 = tok;
  583.             n = 0;
  584.             next();
  585.             if (tok != ';' && tok != TOK_LINEFEED) {
  586.                 n = asm_int_expr(s1);
  587.                 next();
  588.             }
  589.             if (n)
  590.                 sprintf(sname, "%s%d", get_tok_str(tok1, NULL), n);
  591.             else
  592.                 sprintf(sname, "%s", get_tok_str(tok1, NULL));
  593.             use_section(s1, sname);
  594.         }
  595.         break;
  596.     case TOK_ASMDIR_file:
  597.         {
  598.             char filename[512];
  599.  
  600.             filename[0] = '\0';
  601.             next();
  602.  
  603.             if (tok == TOK_STR)
  604.                 pstrcat(filename, sizeof(filename), tokc.str.data);
  605.             else
  606.                 pstrcat(filename, sizeof(filename), get_tok_str(tok, NULL));
  607.  
  608.             if (s1->warn_unsupported)
  609.                 tcc_warning("ignoring .file %s", filename);
  610.  
  611.             next();
  612.         }
  613.         break;
  614.     case TOK_ASMDIR_ident:
  615.         {
  616.             char ident[256];
  617.  
  618.             ident[0] = '\0';
  619.             next();
  620.  
  621.             if (tok == TOK_STR)
  622.                 pstrcat(ident, sizeof(ident), tokc.str.data);
  623.             else
  624.                 pstrcat(ident, sizeof(ident), get_tok_str(tok, NULL));
  625.  
  626.             if (s1->warn_unsupported)
  627.                 tcc_warning("ignoring .ident %s", ident);
  628.  
  629.             next();
  630.         }
  631.         break;
  632.     case TOK_ASMDIR_size:
  633.         {
  634.             Sym *sym;
  635.  
  636.             next();
  637.             sym = label_find(tok);
  638.             if (!sym) {
  639.                 tcc_error("label not found: %s", get_tok_str(tok, NULL));
  640.             }
  641.  
  642.             /* XXX .size name,label2-label1 */
  643.             if (s1->warn_unsupported)
  644.                 tcc_warning("ignoring .size %s,*", get_tok_str(tok, NULL));
  645.  
  646.             next();
  647.             skip(',');
  648.             while (tok != '\n' && tok != CH_EOF) {
  649.                 next();
  650.             }
  651.         }
  652.         break;
  653.     case TOK_ASMDIR_type:
  654.         {
  655.             Sym *sym;
  656.             const char *newtype;
  657.  
  658.             next();
  659.             sym = label_find(tok);
  660.             if (!sym) {
  661.                 sym = label_push(&s1->asm_labels, tok, 0);
  662.                 sym->type.t = VT_VOID;
  663.             }
  664.  
  665.             next();
  666.             skip(',');
  667.             if (tok == TOK_STR) {
  668.                 newtype = tokc.str.data;
  669.             } else {
  670.                 if (tok == '@' || tok == '%')
  671.                     next();
  672.                 newtype = get_tok_str(tok, NULL);
  673.             }
  674.  
  675.             if (!strcmp(newtype, "function") || !strcmp(newtype, "STT_FUNC")) {
  676.                 sym->type.t = (sym->type.t & ~VT_BTYPE) | VT_FUNC;
  677.             }
  678.             else if (s1->warn_unsupported)
  679.                 tcc_warning("change type of '%s' from 0x%x to '%s' ignored",
  680.                     get_tok_str(sym->v, NULL), sym->type.t, newtype);
  681.  
  682.             next();
  683.         }
  684.         break;
  685.     case TOK_ASMDIR_section:
  686.         {
  687.             char sname[256];
  688.  
  689.             /* XXX: support more options */
  690.             next();
  691.             sname[0] = '\0';
  692.             while (tok != ';' && tok != TOK_LINEFEED && tok != ',') {
  693.                 if (tok == TOK_STR)
  694.                     pstrcat(sname, sizeof(sname), tokc.str.data);
  695.                 else
  696.                     pstrcat(sname, sizeof(sname), get_tok_str(tok, NULL));
  697.                 next();
  698.             }
  699.             if (tok == ',') {
  700.                 /* skip section options */
  701.                 next();
  702.                 if (tok != TOK_STR)
  703.                     expect("string constant");
  704.                 next();
  705.                 if (tok == ',') {
  706.                     next();
  707.                     if (tok == '@' || tok == '%')
  708.                         next();
  709.                     next();
  710.                 }
  711.             }
  712.             last_text_section = cur_text_section;
  713.             use_section(s1, sname);
  714.         }
  715.         break;
  716.     case TOK_ASMDIR_previous:
  717.         {
  718.             Section *sec;
  719.             next();
  720.             if (!last_text_section)
  721.                 tcc_error("no previous section referenced");
  722.             sec = cur_text_section;
  723.             use_section1(s1, last_text_section);
  724.             last_text_section = sec;
  725.         }
  726.         break;
  727. #ifdef TCC_TARGET_I386
  728.     case TOK_ASMDIR_code16:
  729.         {
  730.             next();
  731.             s1->seg_size = 16;
  732.         }
  733.         break;
  734.     case TOK_ASMDIR_code32:
  735.         {
  736.             next();
  737.             s1->seg_size = 32;
  738.         }
  739.         break;
  740. #endif
  741. #ifdef TCC_TARGET_X86_64
  742.     /* added for compatibility with GAS */
  743.     case TOK_ASMDIR_code64:
  744.         next();
  745.         break;
  746. #endif
  747.     default:
  748.         tcc_error("unknown assembler directive '.%s'", get_tok_str(tok, NULL));
  749.         break;
  750.     }
  751. }
  752.  
  753.  
  754. /* assemble a file */
  755. static int tcc_assemble_internal(TCCState *s1, int do_preprocess)
  756. {
  757.     int opcode;
  758.  
  759. #if 0
  760.     /* print stats about opcodes */
  761.     {
  762.         const ASMInstr *pa;
  763.         int freq[4];
  764.         int op_vals[500];
  765.         int nb_op_vals, i, j;
  766.  
  767.         nb_op_vals = 0;
  768.         memset(freq, 0, sizeof(freq));
  769.         for(pa = asm_instrs; pa->sym != 0; pa++) {
  770.             freq[pa->nb_ops]++;
  771.             for(i=0;i<pa->nb_ops;i++) {
  772.                 for(j=0;j<nb_op_vals;j++) {
  773.                     if (pa->op_type[i] == op_vals[j])
  774.                         goto found;
  775.                 }
  776.                 op_vals[nb_op_vals++] = pa->op_type[i];
  777.             found: ;
  778.             }
  779.         }
  780.         for(i=0;i<nb_op_vals;i++) {
  781.             int v = op_vals[i];
  782.             if ((v & (v - 1)) != 0)
  783.                 printf("%3d: %08x\n", i, v);
  784.         }
  785.         printf("size=%d nb=%d f0=%d f1=%d f2=%d f3=%d\n",
  786.                sizeof(asm_instrs), sizeof(asm_instrs) / sizeof(ASMInstr),
  787.                freq[0], freq[1], freq[2], freq[3]);
  788.     }
  789. #endif
  790.  
  791.     /* XXX: undefine C labels */
  792.  
  793.     ch = file->buf_ptr[0];
  794.     tok_flags = TOK_FLAG_BOL | TOK_FLAG_BOF;
  795.     parse_flags = PARSE_FLAG_ASM_FILE | PARSE_FLAG_TOK_STR;
  796.     if (do_preprocess)
  797.         parse_flags |= PARSE_FLAG_PREPROCESS;
  798.     next();
  799.     for(;;) {
  800.         if (tok == TOK_EOF)
  801.             break;
  802.         parse_flags |= PARSE_FLAG_LINEFEED; /* XXX: suppress that hack */
  803.     redo:
  804.         if (tok == '#') {
  805.             /* horrible gas comment */
  806.             while (tok != TOK_LINEFEED)
  807.                 next();
  808.         } else if (tok >= TOK_ASMDIR_FIRST && tok <= TOK_ASMDIR_LAST) {
  809.             asm_parse_directive(s1);
  810.         } else if (tok == TOK_PPNUM) {
  811.             const char *p;
  812.             int n;
  813.             p = tokc.str.data;
  814.             n = strtoul(p, (char **)&p, 10);
  815.             if (*p != '\0')
  816.                 expect("':'");
  817.             /* new local label */
  818.             asm_new_label(s1, asm_get_local_label_name(s1, n), 1);
  819.             next();
  820.             skip(':');
  821.             goto redo;
  822.         } else if (tok >= TOK_IDENT) {
  823.             /* instruction or label */
  824.             opcode = tok;
  825.             next();
  826.             if (tok == ':') {
  827.                 /* new label */
  828.                 asm_new_label(s1, opcode, 0);
  829.                 next();
  830.                 goto redo;
  831.             } else if (tok == '=') {
  832.                 int n;
  833.                 next();
  834.                 n = asm_int_expr(s1);
  835.                 asm_new_label1(s1, opcode, 0, SHN_ABS, n);
  836.                 goto redo;
  837.             } else {
  838.                 asm_opcode(s1, opcode);
  839.             }
  840.         }
  841.         /* end of line */
  842.         if (tok != ';' && tok != TOK_LINEFEED){
  843.             expect("end of line");
  844.         }
  845.         parse_flags &= ~PARSE_FLAG_LINEFEED; /* XXX: suppress that hack */
  846.         next();
  847.     }
  848.  
  849.     asm_free_labels(s1);
  850.  
  851.     return 0;
  852. }
  853.  
  854. /* Assemble the current file */
  855. ST_FUNC int tcc_assemble(TCCState *s1, int do_preprocess)
  856. {
  857.     Sym *define_start;
  858.     int ret;
  859.  
  860.     preprocess_init(s1);
  861.  
  862.     /* default section is text */
  863.     cur_text_section = text_section;
  864.     ind = cur_text_section->data_offset;
  865.  
  866.     define_start = define_stack;
  867.  
  868.     /* an elf symbol of type STT_FILE must be put so that STB_LOCAL
  869.        symbols can be safely used */
  870.     put_elf_sym(symtab_section, 0, 0,
  871.                 ELFW(ST_INFO)(STB_LOCAL, STT_FILE), 0,
  872.                 SHN_ABS, file->filename);
  873.  
  874.     ret = tcc_assemble_internal(s1, do_preprocess);
  875.  
  876.     cur_text_section->data_offset = ind;
  877.  
  878.     free_defines(define_start);
  879.  
  880.     return ret;
  881. }
  882.  
  883. /********************************************************************/
  884. /* GCC inline asm support */
  885.  
  886. /* assemble the string 'str' in the current C compilation unit without
  887.    C preprocessing. NOTE: str is modified by modifying the '\0' at the
  888.    end */
  889. static void tcc_assemble_inline(TCCState *s1, char *str, int len)
  890. {
  891.     int saved_parse_flags;
  892.     const int *saved_macro_ptr;
  893.  
  894.     saved_parse_flags = parse_flags;
  895.     saved_macro_ptr = macro_ptr;
  896.  
  897.     tcc_open_bf(s1, ":asm:", len);
  898.     memcpy(file->buffer, str, len);
  899.  
  900.     macro_ptr = NULL;
  901.     tcc_assemble_internal(s1, 0);
  902.     tcc_close();
  903.  
  904.     parse_flags = saved_parse_flags;
  905.     macro_ptr = saved_macro_ptr;
  906. }
  907.  
  908. /* find a constraint by its number or id (gcc 3 extended
  909.    syntax). return -1 if not found. Return in *pp in char after the
  910.    constraint */
  911. ST_FUNC int find_constraint(ASMOperand *operands, int nb_operands,
  912.                            const char *name, const char **pp)
  913. {
  914.     int index;
  915.     TokenSym *ts;
  916.     const char *p;
  917.  
  918.     if (isnum(*name)) {
  919.         index = 0;
  920.         while (isnum(*name)) {
  921.             index = (index * 10) + (*name) - '0';
  922.             name++;
  923.         }
  924.         if ((unsigned)index >= nb_operands)
  925.             index = -1;
  926.     } else if (*name == '[') {
  927.         name++;
  928.         p = strchr(name, ']');
  929.         if (p) {
  930.             ts = tok_alloc(name, p - name);
  931.             for(index = 0; index < nb_operands; index++) {
  932.                 if (operands[index].id == ts->tok)
  933.                     goto found;
  934.             }
  935.             index = -1;
  936.         found:
  937.             name = p + 1;
  938.         } else {
  939.             index = -1;
  940.         }
  941.     } else {
  942.         index = -1;
  943.     }
  944.     if (pp)
  945.         *pp = name;
  946.     return index;
  947. }
  948.  
  949. static void subst_asm_operands(ASMOperand *operands, int nb_operands,
  950.                                int nb_outputs,
  951.                                CString *out_str, CString *in_str)
  952. {
  953.     int c, index, modifier;
  954.     const char *str;
  955.     ASMOperand *op;
  956.     SValue sv;
  957.  
  958.     cstr_new(out_str);
  959.     str = in_str->data;
  960.     for(;;) {
  961.         c = *str++;
  962.         if (c == '%') {
  963.             if (*str == '%') {
  964.                 str++;
  965.                 goto add_char;
  966.             }
  967.             modifier = 0;
  968.             if (*str == 'c' || *str == 'n' ||
  969.                 *str == 'b' || *str == 'w' || *str == 'h')
  970.                 modifier = *str++;
  971.             index = find_constraint(operands, nb_operands, str, &str);
  972.             if (index < 0)
  973.                 tcc_error("invalid operand reference after %%");
  974.             op = &operands[index];
  975.             sv = *op->vt;
  976.             if (op->reg >= 0) {
  977.                 sv.r = op->reg;
  978.                 if ((op->vt->r & VT_VALMASK) == VT_LLOCAL && op->is_memory)
  979.                     sv.r |= VT_LVAL;
  980.             }
  981.             subst_asm_operand(out_str, &sv, modifier);
  982.         } else {
  983.         add_char:
  984.             cstr_ccat(out_str, c);
  985.             if (c == '\0')
  986.                 break;
  987.         }
  988.     }
  989. }
  990.  
  991.  
  992. static void parse_asm_operands(ASMOperand *operands, int *nb_operands_ptr,
  993.                                int is_output)
  994. {
  995.     ASMOperand *op;
  996.     int nb_operands;
  997.  
  998.     if (tok != ':') {
  999.         nb_operands = *nb_operands_ptr;
  1000.         for(;;) {
  1001.             if (nb_operands >= MAX_ASM_OPERANDS)
  1002.                 tcc_error("too many asm operands");
  1003.             op = &operands[nb_operands++];
  1004.             op->id = 0;
  1005.             if (tok == '[') {
  1006.                 next();
  1007.                 if (tok < TOK_IDENT)
  1008.                     expect("identifier");
  1009.                 op->id = tok;
  1010.                 next();
  1011.                 skip(']');
  1012.             }
  1013.             if (tok != TOK_STR)
  1014.                 expect("string constant");
  1015.             op->constraint = tcc_malloc(tokc.str.size);
  1016.             strcpy(op->constraint, tokc.str.data);
  1017.             next();
  1018.             skip('(');
  1019.             gexpr();
  1020.             if (is_output) {
  1021.                 test_lvalue();
  1022.             } else {
  1023.                 /* we want to avoid LLOCAL case, except when the 'm'
  1024.                    constraint is used. Note that it may come from
  1025.                    register storage, so we need to convert (reg)
  1026.                    case */
  1027.                 if ((vtop->r & VT_LVAL) &&
  1028.                     ((vtop->r & VT_VALMASK) == VT_LLOCAL ||
  1029.                      (vtop->r & VT_VALMASK) < VT_CONST) &&
  1030.                     !strchr(op->constraint, 'm')) {
  1031.                     gv(RC_INT);
  1032.                 }
  1033.             }
  1034.             op->vt = vtop;
  1035.             skip(')');
  1036.             if (tok == ',') {
  1037.                 next();
  1038.             } else {
  1039.                 break;
  1040.             }
  1041.         }
  1042.         *nb_operands_ptr = nb_operands;
  1043.     }
  1044. }
  1045.  
  1046. /* parse the GCC asm() instruction */
  1047. ST_FUNC void asm_instr(void)
  1048. {
  1049.     CString astr, astr1;
  1050.     ASMOperand operands[MAX_ASM_OPERANDS];
  1051.     int nb_outputs, nb_operands, i, must_subst, out_reg;
  1052.     uint8_t clobber_regs[NB_ASM_REGS];
  1053.  
  1054.     next();
  1055.     /* since we always generate the asm() instruction, we can ignore
  1056.        volatile */
  1057.     if (tok == TOK_VOLATILE1 || tok == TOK_VOLATILE2 || tok == TOK_VOLATILE3) {
  1058.         next();
  1059.     }
  1060.     parse_asm_str(&astr);
  1061.     nb_operands = 0;
  1062.     nb_outputs = 0;
  1063.     must_subst = 0;
  1064.     memset(clobber_regs, 0, sizeof(clobber_regs));
  1065.     if (tok == ':') {
  1066.         next();
  1067.         must_subst = 1;
  1068.         /* output args */
  1069.         parse_asm_operands(operands, &nb_operands, 1);
  1070.         nb_outputs = nb_operands;
  1071.         if (tok == ':') {
  1072.             next();
  1073.             if (tok != ')') {
  1074.                 /* input args */
  1075.                 parse_asm_operands(operands, &nb_operands, 0);
  1076.                 if (tok == ':') {
  1077.                     /* clobber list */
  1078.                     /* XXX: handle registers */
  1079.                     next();
  1080.                     for(;;) {
  1081.                         if (tok != TOK_STR)
  1082.                             expect("string constant");
  1083.                         asm_clobber(clobber_regs, tokc.str.data);
  1084.                         next();
  1085.                         if (tok == ',') {
  1086.                             next();
  1087.                         } else {
  1088.                             break;
  1089.                         }
  1090.                     }
  1091.                 }
  1092.             }
  1093.         }
  1094.     }
  1095.     skip(')');
  1096.     /* NOTE: we do not eat the ';' so that we can restore the current
  1097.        token after the assembler parsing */
  1098.     if (tok != ';')
  1099.         expect("';'");
  1100.    
  1101.     /* save all values in the memory */
  1102.     save_regs(0);
  1103.  
  1104.     /* compute constraints */
  1105.     asm_compute_constraints(operands, nb_operands, nb_outputs,
  1106.                             clobber_regs, &out_reg);
  1107.  
  1108.     /* substitute the operands in the asm string. No substitution is
  1109.        done if no operands (GCC behaviour) */
  1110. #ifdef ASM_DEBUG
  1111.     printf("asm: \"%s\"\n", (char *)astr.data);
  1112. #endif
  1113.     if (must_subst) {
  1114.         subst_asm_operands(operands, nb_operands, nb_outputs, &astr1, &astr);
  1115.         cstr_free(&astr);
  1116.     } else {
  1117.         astr1 = astr;
  1118.     }
  1119. #ifdef ASM_DEBUG
  1120.     printf("subst_asm: \"%s\"\n", (char *)astr1.data);
  1121. #endif
  1122.  
  1123.     /* generate loads */
  1124.     asm_gen_code(operands, nb_operands, nb_outputs, 0,
  1125.                  clobber_regs, out_reg);    
  1126.  
  1127.     /* assemble the string with tcc internal assembler */
  1128.     tcc_assemble_inline(tcc_state, astr1.data, astr1.size - 1);
  1129.  
  1130.     /* restore the current C token */
  1131.     next();
  1132.  
  1133.     /* store the output values if needed */
  1134.     asm_gen_code(operands, nb_operands, nb_outputs, 1,
  1135.                  clobber_regs, out_reg);
  1136.    
  1137.     /* free everything */
  1138.     for(i=0;i<nb_operands;i++) {
  1139.         ASMOperand *op;
  1140.         op = &operands[i];
  1141.         tcc_free(op->constraint);
  1142.         vpop();
  1143.     }
  1144.     cstr_free(&astr1);
  1145. }
  1146.  
  1147. ST_FUNC void asm_global_instr(void)
  1148. {
  1149.     CString astr;
  1150.  
  1151.     next();
  1152.     parse_asm_str(&astr);
  1153.     skip(')');
  1154.     /* NOTE: we do not eat the ';' so that we can restore the current
  1155.        token after the assembler parsing */
  1156.     if (tok != ';')
  1157.         expect("';'");
  1158.    
  1159. #ifdef ASM_DEBUG
  1160.     printf("asm_global: \"%s\"\n", (char *)astr.data);
  1161. #endif
  1162.     cur_text_section = text_section;
  1163.     ind = cur_text_section->data_offset;
  1164.  
  1165.     /* assemble the string with tcc internal assembler */
  1166.     tcc_assemble_inline(tcc_state, astr.data, astr.size - 1);
  1167.    
  1168.     cur_text_section->data_offset = ind;
  1169.  
  1170.     /* restore the current C token */
  1171.     next();
  1172.  
  1173.     cstr_free(&astr);
  1174. }
  1175. #endif /* CONFIG_TCC_ASM */
  1176.