欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

TCC(TinyC)编译器汉化(中文编译器、汉语编程)之八:汇编处理

程序员文章站 2022-03-30 20:21:59
...

汇编处理源码如下:

/*
 *  GAS之类的ZHI汇编程序
 */

#定义 全局_使用
#导入 "zhi.h"
#如果已定义 配置_ZHI_汇编

静态 段 *最后_代码_段; /* 处理.previous asm指令 */

静态_函数 整数型 汇编_获取_局部_标签_名称(知心状态机 *状态机1, 无符号 整数型 n)
{
    字符型 buf[64];
    单词存储结构 *ts;

    snprintf(buf, 取大小(buf), "L..%u", n);
    ts = 单词表_查找(buf, strlen(buf));
    返回 ts->单词编码;
}

静态 整数型 zhi_汇编_内部(知心状态机 *状态机1, 整数型 do_preprocess, 整数型 global);
静态 符号* 汇编_新_标签(知心状态机 *状态机1, 整数型 label, 整数型 is_local);
静态 符号* 汇编_新_标签1(知心状态机 *状态机1, 整数型 label, 整数型 is_local, 整数型 sh_num, 整数型 value);

/* 如果C名称以_开头,则通过删除第一个_来仅在C中表示以_开头的asm标签。 开头没有_的ASM名称与C名称不对应,但是我们也使用全局C单词表来跟踪ASM名称,因此我们需要将其转换为与C名称不冲突的名称,因此在前面添加 一个 '。' 为他们,但强制设置ELF汇编名称。  */
静态 整数型 汇编2c名称(整数型 v, 整数型 *addeddot)
{
    常量 字符型 *name;
    *addeddot = 0;
    如果 (!zhi_状态->前导_下划线)
      返回 v;
    name = 取_单词字符串(v, NULL);
    如果 (!name)
      返回 v;
    如果 (name[0] == '_') {
        v = 单词表_查找(name + 1, strlen(name) - 1)->单词编码;
    } 否则 如果 (!strchr(name, '.')) {
        整数型 n = strlen(name) + 2;
        字符型 newname[n];
        snprintf(newname, n, ".%s", name);
        v = 单词表_查找(newname, n - 1)->单词编码;
        *addeddot = 1;
    }
    返回 v;
}

静态 符号 *汇编_标签_查找(整数型 v)
{
    符号 *sym;
    整数型 addeddot;
    v = 汇编2c名称(v, &addeddot);
    sym = 符号_查询(v);
    判断 (sym && sym->符号_范围 && !(sym->type.t & VT_静态))
        sym = sym->prev_tok;
    返回 sym;
}

静态 符号 *汇编_标签_推送(整数型 v)
{
    整数型 addeddot, v2 = 汇编2c名称(v, &addeddot);
    /* 我们总是为临时的符号定义(对于.set,对于实际的defs删除)添加VT_EXTERN,对于仅引用而言,它是正确的。  */
    符号 *sym = 推送_一个_全局标识符(v2, VT_汇编 | VT_外部 | VT_静态, 0);
    如果 (addeddot)
        sym->汇编_label = v;
    返回 sym;
}

/* 返回一个可以在汇编器内部使用的符号,名称为NAME。 来自asm和C源代码的符号共享一个名称空间。 如果我们生成一个asm符号,
 * 它也是一个(文件全局)C符号,但是它不能按名称访问(例如“ L.123”),或者其类型信息使得没有适当的C声明就无法使用。
 * 有时我们需要从asm可以通过名称访问的符号,这些符号在C中是匿名的,在这种情况下,可以使用CSYM将所有信息从该符号传输到
 * (可能是新创建的)asm符号。  */
静态_函数 符号* 获取_汇编_符号(整数型 name, 符号 *csym)
{
    符号 *sym = 汇编_标签_查找(name);
    如果 (!sym) {
	sym = 汇编_标签_推送(name);
	如果 (csym)
	  sym->c = csym->c;
    }
    返回 sym;
}

静态 符号* 汇编_段_符号(知心状态机 *状态机1,*sec)
{
    字符型 buf[100];
    整数型 label = 单词表_查找(buf,
        snprintf(buf, 取大小 buf, "L.%s", sec->name)
        )->单词编码;
    符号 *sym = 汇编_标签_查找(label);
    返回 sym ? sym : 汇编_新_标签1(状态机1, label, 1, sec->sh_num, 0);
}

/* 我们不使用C表达式解析器来处理符号。 也许可以对C表达式解析器进行调整。 */

静态 无类型 汇编_表达式_一元(知心状态机 *状态机1, 表达式值 *pe)
{
    符号 *sym;
    整数型 op, label;
    uint64_t n;
    常量 字符型 *p;

    选择(单词编码) {
    分支 常量_预处理编号:
        p = 单词值.str.data;
        n = strtoull(p, (字符型 **)&p, 0);
        如果 (*p == 'b' || *p == 'f') {
            /* 后退或前进标签 */
            label = 汇编_获取_局部_标签_名称(状态机1, n);
            sym = 汇编_标签_查找(label);
            如果 (*p == 'b') {
                /* backward : find the last corresponding 已定义 label */
                如果 (sym && (!sym->c || elf符号(sym)->st_shndx == SHN_UNDEF))
                    sym = sym->prev_tok;
                如果 (!sym)
                    错误_打印("找不到本地标签 '%d' ", (整数型)n);
            } 否则 {
                /* forward */
                如果 (!sym || (sym->c && elf符号(sym)->st_shndx != SHN_UNDEF)) {
                    /* 如果 the last label is 已定义, then 定义 a new one */
		    sym = 汇编_标签_推送(label);
                }
            }
	    pe->v = 0;
	    pe->sym = sym;
	    pe->pcrel = 0;
        } 否则 如果 (*p == '\0') {
            pe->v = n;
            pe->sym = NULL;
	    pe->pcrel = 0;
        } 否则 {
            错误_打印("无效的数字语法");
        }
        带有宏替换的下个标记();
        跳出;
    分支 '+':
        带有宏替换的下个标记();
        汇编_表达式_一元(状态机1, pe);
        跳出;
    分支 '-':
    分支 '~':
        op = 单词编码;
        带有宏替换的下个标记();
        汇编_表达式_一元(状态机1, pe);
        如果 (pe->sym)
            错误_打印("invalid operation with label");
        如果 (op == '-')
            pe->v = -pe->v;
        否则
            pe->v = ~pe->v;
        跳出;
    分支 常量_字符型:
    分支 常量_长字符型:
	pe->v = 单词值.i;
	pe->sym = NULL;
	pe->pcrel = 0;
	带有宏替换的下个标记();
	跳出;
    分支 '(':
        带有宏替换的下个标记();
        汇编_表达式(状态机1, pe);
        跳过(')');
        跳出;
    分支 '.':
        pe->v = 输出代码索引;
        pe->sym = 汇编_段_符号(状态机1, 当前_生成代码_段);
        pe->pcrel = 0;
        带有宏替换的下个标记();
        跳出;
    default:
        如果 (单词编码 >= 符_识别) {
	    ELF符号 *esym;
            /* label 分支 : 如果 the label was not found, add one */
	    sym = 获取_汇编_符号(单词编码, NULL);
	    esym = elf符号(sym);
            如果 (esym && esym->st_shndx == SHN_ABS) {
                /* 如果 absolute symbol, no need to put a symbol value */
                pe->v = esym->st_value;
                pe->sym = NULL;
		pe->pcrel = 0;
            } 否则 {
                pe->v = 0;
                pe->sym = sym;
		pe->pcrel = 0;
            }
            带有宏替换的下个标记();
        } 否则 {
            错误_打印("错误的表达语法 [%s]", 取_单词字符串(单词编码, &单词值));
        }
        跳出;
    }
}
    
静态 无类型 汇编_表达式_乘除余(知心状态机 *状态机1, 表达式值 *pe)
{
    整数型 op;
    表达式值 e2;

    汇编_表达式_一元(状态机1, pe);
    循环(;;) {
        op = 单词编码;
        如果 (op != '*' && op != '/' && op != '%' && 
            op != 双符号_左位移 && op != 双符号_右位移)
            跳出;
        带有宏替换的下个标记();
        汇编_表达式_一元(状态机1, &e2);
        如果 (pe->sym || e2.sym)
            错误_打印("无效的操作标签");
        选择(op) {
        分支 '*':
            pe->v *= e2.v;
            跳出;
        分支 '/':  
            如果 (e2.v == 0) {
            div_error:
                错误_打印("被零除");
            }
            pe->v /= e2.v;
            跳出;
        分支 '%':  
            如果 (e2.v == 0)
                去向 div_error;
            pe->v %= e2.v;
            跳出;
        分支 双符号_左位移:
            pe->v <<= e2.v;
            跳出;
        default:
        分支 双符号_右位移:
            pe->v >>= e2.v;
            跳出;
        }
    }
}

静态 无类型 汇编_表达式_逻辑(知心状态机 *状态机1, 表达式值 *pe)
{
    整数型 op;
    表达式值 e2;

    汇编_表达式_乘除余(状态机1, pe);
    循环(;;) {
        op = 单词编码;
        如果 (op != '&' && op != '|' && op != '^')
            跳出;
        带有宏替换的下个标记();
        汇编_表达式_乘除余(状态机1, &e2);
        如果 (pe->sym || e2.sym)
            错误_打印("invalid operation with label");
        选择(op) {
        分支 '&':
            pe->v &= e2.v;
            跳出;
        分支 '|':  
            pe->v |= e2.v;
            跳出;
        default:
        分支 '^':
            pe->v ^= e2.v;
            跳出;
        }
    }
}

静态 内联 无类型 汇编_表达式_和(知心状态机 *状态机1, 表达式值 *pe)
{
    整数型 op;
    表达式值 e2;

    汇编_表达式_逻辑(状态机1, pe);
    循环(;;) {
        op = 单词编码;
        如果 (op != '+' && op != '-')
            跳出;
        带有宏替换的下个标记();
        汇编_表达式_逻辑(状态机1, &e2);
        如果 (op == '+') {
            如果 (pe->sym != NULL && e2.sym != NULL)
                去向 cannot_relocate;
            pe->v += e2.v;
            如果 (pe->sym == NULL && e2.sym != NULL)
                pe->sym = e2.sym;
        } 否则 {
            pe->v -= e2.v;
            /* 注意:在这种情况下,我们不如气体强大,因为我们在表达式中仅存储一个符号 */
	    如果 (!e2.sym) {
		/* OK */
	    } 否则 如果 (pe->sym == e2.sym) { 
		/* OK */
		pe->sym = NULL; /* 相同的符号可以减为NULL */
	    } 否则 {
		ELF符号 *esym1, *esym2;
		esym1 = elf符号(pe->sym);
		esym2 = elf符号(e2.sym);
		如果 (esym1 && esym1->st_shndx == esym2->st_shndx
		    && esym1->st_shndx != SHN_UNDEF) {
		    /* we also accept 已定义 symbols in the same section */
		    pe->v += esym1->st_value - esym2->st_value;
		    pe->sym = NULL;
		} 否则 如果 (esym2->st_shndx == 当前_生成代码_段->sh_num) {
		    /* When subtracting a 已定义 symbol in current section
		       this actually makes the value PC-relative.  */
		    pe->v -= esym2->st_value - 输出代码索引 - 4;
		    pe->pcrel = 1;
		    e2.sym = NULL;
		} 否则 {
cannot_relocate:
		    错误_打印("无效的操作标签");
		}
	    }
        }
    }
}

静态 内联 无类型 汇编_表达式_比较(知心状态机 *状态机1, 表达式值 *pe)
{
    整数型 op;
    表达式值 e2;

    汇编_表达式_和(状态机1, pe);
    循环(;;) {
        op = 单词编码;
	如果 (op != 双符号_等于 && op != 双符号_不等于
	    && (op > 符_GT || op < 符号_ULE))
            跳出;
        带有宏替换的下个标记();
        汇编_表达式_和(状态机1, &e2);
        如果 (pe->sym || e2.sym)
            错误_打印("无效的操作标签");
        选择(op) {
	分支 双符号_等于:
	    pe->v = pe->v == e2.v;
	    跳出;
	分支 双符号_不等于:
	    pe->v = pe->v != e2.v;
	    跳出;
	分支 符_LT:
	    pe->v = (int64_t)pe->v < (int64_t)e2.v;
	    跳出;
	分支 双符号_大于等于:
	    pe->v = (int64_t)pe->v >= (int64_t)e2.v;
	    跳出;
	分支 双符号_小于等于:
	    pe->v = (int64_t)pe->v <= (int64_t)e2.v;
	    跳出;
	分支 符_GT:
	    pe->v = (int64_t)pe->v > (int64_t)e2.v;
	    跳出;
        default:
            跳出;
        }
	/* GAS compare results are -1/0 not 1/0.  */
	pe->v = -(int64_t)pe->v;
    }
}

静态_函数 无类型 汇编_表达式(知心状态机 *状态机1, 表达式值 *pe)
{
    汇编_表达式_比较(状态机1, pe);
}

静态_函数 整数型 汇编_整数_表达式(知心状态机 *状态机1)
{
    表达式值 e;
    汇编_表达式(状态机1, &e);
    如果 (e.sym)
        应为("constant");
    返回 e.v;
}

静态 符号* 汇编_新_标签1(知心状态机 *状态机1, 整数型 label, 整数型 is_local,
                           整数型 sh_num, 整数型 value)
{
    符号 *sym;
    ELF符号 *esym;

    sym = 汇编_标签_查找(label);
    如果 (sym) {
	esym = elf符号(sym);
	/* A VT_外部 symbol, even 如果 it has a section is considered
	   overridable.  This is how we "定义" .set targets.  Real
	   definitions won't have VT_外部 set.  */
        如果 (esym && esym->st_shndx != SHN_UNDEF) {
            /* the label is already 已定义 */
            如果 (是_汇编_符号(sym)
                && (is_local == 1 || (sym->type.t & VT_外部)))
                去向 new_label;
            如果 (!(sym->type.t & VT_外部))
                错误_打印("assembler label '%s' already 已定义",
                          取_单词字符串(label, NULL));
        }
    } 否则 {
    new_label:
        sym = 汇编_标签_推送(label);
    }
    如果 (!sym->c)
      更新_外部_符号2(sym, SHN_UNDEF, 0, 0, 1);
    esym = elf符号(sym);
    esym->st_shndx = sh_num;
    esym->st_value = value;
    如果 (is_local != 2)
        sym->type.t &= ~VT_外部;
    返回 sym;
}

静态 符号* 汇编_新_标签(知心状态机 *状态机1, 整数型 label, 整数型 is_local)
{
    返回 汇编_新_标签1(状态机1, label, is_local, 当前_生成代码_段->sh_num, 输出代码索引);
}

/* 将LABEL的值设置为某些表达式的值(可能涉及其他符号)。 LABEL以后仍可以覆盖。  */
静态 符号* 设置_符号(知心状态机 *状态机1, 整数型 label)
{
    long n;
    表达式值 e;
    符号 *sym;
    ELF符号 *esym;
    带有宏替换的下个标记();
    汇编_表达式(状态机1, &e);
    n = e.v;
    esym = elf符号(e.sym);
    如果 (esym)
	n += esym->st_value;
    sym = 汇编_新_标签1(状态机1, label, 2, esym ? esym->st_shndx : SHN_ABS, n);
    elf符号(sym)->st_other |= ST_ASM_SET;
    返回 sym;
}

静态 无类型 使用_段1(知心状态机 *状态机1,*sec)
{
    当前_生成代码_段->数据_偏移 = 输出代码索引;
    当前_生成代码_段 = sec;
    输出代码索引 = 当前_生成代码_段->数据_偏移;
}

静态 无类型 使用_段(知心状态机 *状态机1, 常量 字符型 *name)
{*sec;
    sec = 查找_段(状态机1, name);
    使用_段1(状态机1, sec);
}

静态 无类型 推送_段(知心状态机 *状态机1, 常量 字符型 *name)
{*sec = 查找_段(状态机1, name);
    sec->prev = 当前_生成代码_段;
    使用_段1(状态机1, sec);
}

静态 无类型 弹出_段(知心状态机 *状态机1)
{*prev = 当前_生成代码_段->prev;
    如果 (!prev)
        错误_打印(".popsection without .pushsection");
    当前_生成代码_段->prev = NULL;
    使用_段1(状态机1, prev);
}

静态 无类型 汇编_解析_指令(知心状态机 *状态机1, 整数型 global)
{
    整数型 n, offset, v, size, tok1;*sec;
    uint8_t *ptr;

    /* 汇编指令 */
    sec = 当前_生成代码_段;
    选择(单词编码) {
    分支 符_汇编DIR_align:
    分支 符_汇编DIR_balign:
    分支 符_汇编DIR_p2align:
    分支 符_汇编DIR_skip:
    分支 符_汇编DIR_space:
        tok1 = 单词编码;
        带有宏替换的下个标记();
        n = 汇编_整数_表达式(状态机1);
        如果 (tok1 == 符_汇编DIR_p2align)
        {
            如果 (n < 0 || n > 30)
                错误_打印("invalid p2align, must be between 0 and 30");
            n = 1 << n;
            tok1 = 符_汇编DIR_align;
        }
        如果 (tok1 == 符_汇编DIR_align || tok1 == 符_汇编DIR_balign) {
            如果 (n < 0 || (n & (n-1)) != 0)
                错误_打印("alignment must be a positive power of two");
            offset = (输出代码索引 + n - 1) & -n;
            size = offset - 输出代码索引;
            /* 该部分必须具有兼容的对齐方式 */
            如果 (sec->sh_addralign < n)
                sec->sh_addralign = n;
        } 否则 {
	    如果 (n < 0)
	        n = 0;
            size = n;
        }
        v = 0;
        如果 (单词编码 == ',') {
            带有宏替换的下个标记();
            v = 汇编_整数_表达式(状态机1);
        }
    zero_pad:
        如果 (sec->sh_type != SHT_NOBITS) {
            sec->数据_偏移 = 输出代码索引;
            ptr = 段_ptr_添加(sec, size);
            memset(ptr, v, size);
        }
        输出代码索引 += size;
        跳出;
    分支 符_汇编DIR_quad:
#如果已定义 ZHI_TARGET_X86_64
	size = 8;
	去向 汇编_data;
#否则
        带有宏替换的下个标记();
        循环(;;) {
            uint64_t vl;
            常量 字符型 *p;

            p = 单词值.str.data;
            如果 (单词编码 != 常量_预处理编号) {
            error_constant:
                错误_打印("64 bit constant");
            }
            vl = strtoll(p, (字符型 **)&p, 0);
            如果 (*p != '\0')
                去向 error_constant;
            带有宏替换的下个标记();
            如果 (sec->sh_type != SHT_NOBITS) {
                /* XXX: endianness */
                生成_le32(vl);
                生成_le32(vl >> 32);
            } 否则 {
                输出代码索引 += 8;
            }
            如果 (单词编码 != ',')
                跳出;
            带有宏替换的下个标记();
        }
        跳出;
#结束如果
    分支 符_汇编DIR_byte:
        size = 1;
        去向 汇编_data;
    分支 符_汇编DIR_word:
    分支 符_汇编DIR_short:
        size = 2;
        去向 汇编_data;
    分支 符_汇编DIR_long:
    分支 符_汇编DIR_整数型:
        size = 4;
    汇编_data:
        带有宏替换的下个标记();
        循环(;;) {
            表达式值 e;
            汇编_表达式(状态机1, &e);
            如果 (sec->sh_type != SHT_NOBITS) {
                如果 (size == 4) {
                    生成_32位表达式(&e);
#如果已定义 ZHI_TARGET_X86_64
		} 否则 如果 (size == 8) {
		    生成_64位表达式(&e);
#结束如果
                } 否则 {
                    如果 (e.sym)
                        应为("constant");
                    如果 (size == 1)
                        生成(e.v);
                    否则
                        生成_le16(e.v);
                }
            } 否则 {
                输出代码索引 += size;
            }
            如果 (单词编码 != ',')
                跳出;
            带有宏替换的下个标记();
        }
        跳出;
    分支 符_汇编DIR_fill:
        {
            整数型 repeat, size, val, i, j;
            uint8_t repeat_buf[8];
            带有宏替换的下个标记();
            repeat = 汇编_整数_表达式(状态机1);
            如果 (repeat < 0) {
                错误_打印("repeat < 0; .fill ignored");
                跳出;
            }
            size = 1;
            val = 0;
            如果 (单词编码 == ',') {
                带有宏替换的下个标记();
                size = 汇编_整数_表达式(状态机1);
                如果 (size < 0) {
                    错误_打印("size < 0; .fill ignored");
                    跳出;
                }
                如果 (size > 8)
                    size = 8;
                如果 (单词编码 == ',') {
                    带有宏替换的下个标记();
                    val = 汇编_整数_表达式(状态机1);
                }
            }
            /* XXX: endianness */
            repeat_buf[0] = val;
            repeat_buf[1] = val >> 8;
            repeat_buf[2] = val >> 16;
            repeat_buf[3] = val >> 24;
            repeat_buf[4] = 0;
            repeat_buf[5] = 0;
            repeat_buf[6] = 0;
            repeat_buf[7] = 0;
            循环(i = 0; i < repeat; i++) {
                循环(j = 0; j < size; j++) {
                    生成(repeat_buf[j]);
                }
            }
        }
        跳出;
    分支 符_汇编DIR_rept:
        {
            整数型 repeat;
            单词字符串 *init_str;
            带有宏替换的下个标记();
            repeat = 汇编_整数_表达式(状态机1);
            init_str = 单词字符串_分配();
            判断 (带有宏替换的下个标记(), 单词编码 != 符_汇编DIR_endr) {
                如果 (单词编码 == CH_文件结尾)
                    错误_打印("we at end of file, .endr not found");
                单词字符串中添加当前解析的字符(init_str);
            }
            单词字符串_增加大小(init_str, -1);
            单词字符串_增加大小(init_str, 0);
            开始_宏(init_str, 1);
            判断 (repeat-- > 0) {
                zhi_汇编_内部(状态机1, (解析_标记 & 解析_标记_预处理),
				      global);
                宏_ptr = init_str->str;
            }
            结束_宏();
            带有宏替换的下个标记();
            跳出;
        }
    分支 符_汇编DIR_org:
        {
            无符号 long n;
	    表达式值 e;
	    ELF符号 *esym;
            带有宏替换的下个标记();
	    汇编_表达式(状态机1, &e);
	    n = e.v;
	    esym = elf符号(e.sym);
	    如果 (esym) {
		如果 (esym->st_shndx != 当前_生成代码_段->sh_num)
		  应为("constant or same-section symbol");
		n += esym->st_value;
	    }
            如果 (n < 输出代码索引)
                错误_打印("attempt to .org backwards");
            v = 0;
            size = n - 输出代码索引;
            去向 zero_pad;
        }
        跳出;
    分支 符_汇编DIR_set:
	带有宏替换的下个标记();
	tok1 = 单词编码;
	带有宏替换的下个标记();
	/* 也接受“ .set东西”,但是对此不做任何事情。 它在GAS中用于设置各种功能,例如“ .set mips16”。 */
	如果 (单词编码 == ',')
	    设置_符号(状态机1, tok1);
	跳出;
    分支 符_汇编DIR_globl:
    分支 符_汇编DIR_global:
    分支 符_汇编DIR_weak:
    分支 符_汇编DIR_hidden:
	tok1 = 单词编码;
	执行 { 
            符号 *sym;
            带有宏替换的下个标记();
            sym = 获取_汇编_符号(单词编码, NULL);
	    如果 (tok1 != 符_汇编DIR_hidden)
                sym->type.t &= ~VT_静态;
            如果 (tok1 == 符_汇编DIR_weak)
                sym->a.weak = 1;
	    否则 如果 (tok1 == 符_汇编DIR_hidden)
	        sym->a.visibility = STV_HIDDEN;
            更新_存储(sym);
            带有宏替换的下个标记();
	} 判断 (单词编码 == ',');
	跳出;
    分支 符_汇编DIR_string:
    分支 符_汇编DIR_ascii:
    分支 符_汇编DIR_asciz:
        {
            常量 uint8_t *p;
            整数型 i, size, t;

            t = 单词编码;
            带有宏替换的下个标记();
            循环(;;) {
                如果 (单词编码 != 常量_字符串)
                    应为("string constant");
                p = 单词值.str.data;
                size = 单词值.str.size;
                如果 (t == 符_汇编DIR_ascii && size > 0)
                    size--;
                循环(i = 0; i < size; i++)
                    生成(p[i]);
                带有宏替换的下个标记();
                如果 (单词编码 == ',') {
                    带有宏替换的下个标记();
                } 否则 如果 (单词编码 != 常量_字符串) {
                    跳出;
                }
            }
	}
	跳出;
    分支 符_汇编DIR_text:
    分支 符_汇编DIR_data:
    分支 符_汇编DIR_bss:
	{ 
            字符型 sname[64];
            tok1 = 单词编码;
            n = 0;
            带有宏替换的下个标记();
            如果 (单词编码 != ';' && 单词编码 != 符_换行) {
		n = 汇编_整数_表达式(状态机1);
		带有宏替换的下个标记();
            }
            如果 (n)
                sprintf(sname, "%s%d", 取_单词字符串(tok1, NULL), n);
            否则
                sprintf(sname, "%s", 取_单词字符串(tok1, NULL));
            使用_段(状态机1, sname);
	}
	跳出;
    分支 符_汇编DIR_file:
        {
            字符型 文件名[512];

            文件名[0] = '\0';
            带有宏替换的下个标记();

            如果 (单词编码 == 常量_字符串)
                连接_字符串(文件名, 取大小(文件名), 单词值.str.data);
            否则
                连接_字符串(文件名, 取大小(文件名), 取_单词字符串(单词编码, NULL));

            如果 (状态机1->警告_不支持)
                zhi_警告("ignoring .file %s", 文件名);

            带有宏替换的下个标记();
        }
        跳出;
    分支 符_汇编DIR_ident:
        {
            字符型 ident[256];

            ident[0] = '\0';
            带有宏替换的下个标记();

            如果 (单词编码 == 常量_字符串)
                连接_字符串(ident, 取大小(ident), 单词值.str.data);
            否则
                连接_字符串(ident, 取大小(ident), 取_单词字符串(单词编码, NULL));

            如果 (状态机1->警告_不支持)
                zhi_警告("ignoring .ident %s", ident);

            带有宏替换的下个标记();
        }
        跳出;
    分支 符_汇编DIR_size:
        { 
            符号 *sym;

            带有宏替换的下个标记();
            sym = 汇编_标签_查找(单词编码);
            如果 (!sym) {
                错误_打印("label not found: %s", 取_单词字符串(单词编码, NULL));
            }

            /* XXX .size name,label2-label1 */
            如果 (状态机1->警告_不支持)
                zhi_警告("ignoring .size %s,*", 取_单词字符串(单词编码, NULL));

            带有宏替换的下个标记();
            跳过(',');
            判断 (单词编码 != 符_换行 && 单词编码 != ';' && 单词编码 != CH_文件结尾) {
                带有宏替换的下个标记();
            }
        }
        跳出;
    分支 符_汇编DIR_type:
        { 
            符号 *sym;
            常量 字符型 *newtype;

            带有宏替换的下个标记();
            sym = 获取_汇编_符号(单词编码, NULL);
            带有宏替换的下个标记();
            跳过(',');
            如果 (单词编码 == 常量_字符串) {
                newtype = 单词值.str.data;
            } 否则 {
                如果 (单词编码 == '@' || 单词编码 == '%')
                    带有宏替换的下个标记();
                newtype = 取_单词字符串(单词编码, NULL);
            }

            如果 (!strcmp(newtype, "function") || !strcmp(newtype, "STT_FUNC")) {
                sym->type.t = (sym->type.t & ~VT_基本类型) | VT_函数;
            }
            否则 如果 (状态机1->警告_不支持)
                zhi_警告("change type of '%s' from 0x%x to '%s' ignored", 
                    取_单词字符串(sym->v, NULL), sym->type.t, newtype);

            带有宏替换的下个标记();
        }
        跳出;
    分支 符_汇编DIR_pushsection:
    分支 符_汇编DIR_section:
        {
            字符型 sname[256];
	    整数型 old_nb_section = 状态机1->数量_段数;

	    tok1 = 单词编码;
            /* XXX: support more options */
            带有宏替换的下个标记();
            sname[0] = '\0';
            判断 (单词编码 != ';' && 单词编码 != 符_换行 && 单词编码 != ',') {
                如果 (单词编码 == 常量_字符串)
                    连接_字符串(sname, 取大小(sname), 单词值.str.data);
                否则
                    连接_字符串(sname, 取大小(sname), 取_单词字符串(单词编码, NULL));
                带有宏替换的下个标记();
            }
            如果 (单词编码 == ',') {
                /* 跳过 section options */
                带有宏替换的下个标记();
                如果 (单词编码 != 常量_字符串)
                    应为("string constant");
                带有宏替换的下个标记();
                如果 (单词编码 == ',') {
                    带有宏替换的下个标记();
                    如果 (单词编码 == '@' || 单词编码 == '%')
                        带有宏替换的下个标记();
                    带有宏替换的下个标记();
                }
            }
            最后_代码_段 = 当前_生成代码_段;
	    如果 (tok1 == 符_汇编DIR_section)
	        使用_段(状态机1, sname);
	    否则
	        推送_段(状态机1, sname);
	    /* If we just allocated a new section reset its alignment to
	       1.  创建_节 normally acts 循环 GCC compatibility and
	       sets alignment to 指针_大小.  The assembler behaves different. */
	    如果 (old_nb_section != 状态机1->数量_段数)
	        当前_生成代码_段->sh_addralign = 1;
        }
        跳出;
    分支 符_汇编DIR_previous:
        {*sec;
            带有宏替换的下个标记();
            如果 (!最后_代码_段)
                错误_打印("no previous section referenced");
            sec = 当前_生成代码_段;
            使用_段1(状态机1, 最后_代码_段);
            最后_代码_段 = sec;
        }
        跳出;
    分支 符_汇编DIR_popsection:
	带有宏替换的下个标记();
	弹出_段(状态机1);
	跳出;
#如果已定义 ZHI_TARGET_I386
    分支 符_汇编DIR_code16:
        {
            带有宏替换的下个标记();
            状态机1->段_大小 = 16;
        }
        跳出;
    分支 符_汇编DIR_code32:
        {
            带有宏替换的下个标记();
            状态机1->段_大小 = 32;
        }
        跳出;
#结束如果
#如果已定义 ZHI_TARGET_X86_64
    /* added 循环 compatibility with GAS */
    分支 符_汇编DIR_code64:
        带有宏替换的下个标记();
        跳出;
#结束如果
    default:
        错误_打印("未知的汇编指令 '.%s'", 取_单词字符串(单词编码, NULL));
        跳出;
    }
}


/* 解析一个文件 */
静态 整数型 zhi_汇编_内部(知心状态机 *状态机1, 整数型 do_preprocess, 整数型 global)
{
    整数型 opcode;
    整数型 saved_解析_标记 = 解析_标记;

    解析_标记 = 解析_标记_汇编_文件 | 解析_标记_单词字符串;
    如果 (do_preprocess)
        解析_标记 |= 解析_标记_预处理;
    循环(;;) {
        带有宏替换的下个标记();
        如果 (单词编码 == 符_文件结尾)
            跳出;
        解析_标记 |= 解析_标记_换行符; /* XXX: suppress that hack */
    redo:
        如果 (单词编码 == '#') {
            /* horrible gas comment */
            判断 (单词编码 != 符_换行)
                带有宏替换的下个标记();
        } 否则 如果 (单词编码 >= 定义_汇编目录_第一个 && 单词编码 <= 定义_汇编目录_最后一个) {
            汇编_解析_指令(状态机1, global);
        } 否则 如果 (单词编码 == 常量_预处理编号) {
            常量 字符型 *p;
            整数型 n;
            p = 单词值.str.data;
            n = strtoul(p, (字符型 **)&p, 10);
            如果 (*p != '\0')
                应为("':'");
            /* new local label */
            汇编_新_标签(状态机1, 汇编_获取_局部_标签_名称(状态机1, n), 1);
            带有宏替换的下个标记();
            跳过(':');
            去向 redo;
        } 否则 如果 (单词编码 >= 符_识别) {
            /* instruction or label */
            opcode = 单词编码;
            带有宏替换的下个标记();
            如果 (单词编码 == ':') {
                /* new label */
                汇编_新_标签(状态机1, opcode, 0);
                带有宏替换的下个标记();
                去向 redo;
            } 否则 如果 (单词编码 == '=') {
		设置_符号(状态机1, opcode);
                去向 redo;
            } 否则 {
                汇编_指令代码(状态机1, opcode);
            }
        }
        /* end of line */
        如果 (单词编码 != ';' && 单词编码 != 符_换行)
            应为("end of line");
        解析_标记 &= ~解析_标记_换行符; /* XXX: suppress that hack */
    }

    解析_标记 = saved_解析_标记;
    返回 0;
}

/* 汇编当前文件 */
静态_函数 整数型 zhi_汇编(知心状态机 *状态机1, 整数型 do_preprocess)
{
    整数型 ret;
    zhi_调试_开始(状态机1);
    /* default section is text */
    当前_生成代码_段 = 生成代码_段;
    输出代码索引 = 当前_生成代码_段->数据_偏移;
    不需要_代码生成 = 0;
    ret = zhi_汇编_内部(状态机1, do_preprocess, 1);
    当前_生成代码_段->数据_偏移 = 输出代码索引;
    zhi_结束_调试(状态机1);
    返回 ret;
}

/********************************************************************/
/* GCC内联asm支持 */

/* 在不进行C预处理的情况下,在当前C编译单元中组装字符串'str'。 注意:通过在末尾修改'\ 0'来修改str */
静态 无类型 zhi_内联_汇编(知心状态机 *状态机1, 字符型 *str, 整数型 len, 整数型 global)
{
    常量 整数型 *saved_宏_ptr = 宏_ptr;
    整数型 dotid = 设置_等值数('.', IS_ID);
    整数型 dolid = 设置_等值数('$', 0);

    打开缓存文件(状态机1, ":asm:", len);
    memcpy(file->buffer, str, len);
    宏_ptr = NULL;
    zhi_汇编_内部(状态机1, 0, global);
    关闭文件();

    设置_等值数('$', dolid);
    设置_等值数('.', dotid);
    宏_ptr = saved_宏_ptr;
}

/* 通过编号或ID(gcc 3扩展语法)查找约束。 如果找不到,则返回-1。 约束后以char返回* pp */
静态_函数 整数型 查找_约束(汇编操作数 *operands, 整数型 数量_operands,
                           常量 字符型 *name, 常量 字符型 **pp)
{
    整数型 index;
    单词存储结构 *ts;
    常量 字符型 *p;

    如果 (是数字(*name)) {
        index = 0;
        判断 (是数字(*name)) {
            index = (index * 10) + (*name) - '0';
            name++;
        }
        如果 ((无符号)index >= 数量_operands)
            index = -1;
    } 否则 如果 (*name == '[') {
        name++;
        p = strchr(name, ']');
        如果 (p) {
            ts = 单词表_查找(name, p - name);
            循环(index = 0; index < 数量_operands; index++) {
                如果 (operands[index].id == ts->单词编码)
                    去向 found;
            }
            index = -1;
        found:
            name = p + 1;
        } 否则 {
            index = -1;
        }
    } 否则 {
        index = -1;
    }
    如果 (pp)
        *pp = name;
    返回 index;
}

静态 无类型 替代_汇编_操作数(汇编操作数 *operands, 整数型 数量_operands,动态字符串 *out_str, 动态字符串 *in_str)
{
    整数型 c, index, modifier;
    常量 字符型 *str;
    汇编操作数 *op;
    堆栈值 sv;

    动态字符串_初始化(out_str);
    str = in_str->指向字符串的指针;
    循环(;;) {
        c = *str++;
        如果 (c == '%') {
            如果 (*str == '%') {
                str++;
                去向 添加_字符;
            }
            modifier = 0;
            如果 (*str == 'c' || *str == 'n' ||
                *str == 'b' || *str == 'w' || *str == 'h' || *str == 'k' ||
		*str == 'q' ||
		/*在PIC模式下,GCC中的P将在符号引用中添加“ @PLT”,并使文字操作数不使用“ $”修饰。 */
		*str == 'P')
                modifier = *str++;
            index = 查找_约束(operands, 数量_operands, str, &str);
            如果 (index < 0)
                错误_打印("invalid operand reference after %%");
            op = &operands[index];
            sv = *op->vt;
            如果 (op->reg >= 0) {
                sv.r = op->reg;
                如果 ((op->vt->r & VT_值掩码) == VT_LLOCAL && op->is_memory)
                    sv.r |= VT_LVAL;
            }
            替换_汇编_操作数(out_str, &sv, modifier);
        } 否则 {
        添加_字符:
            动态字符串_追加单个字符(out_str, c);
            如果 (c == '\0')
                跳出;
        }
    }
}


静态 无类型 解析_汇编_操作数(汇编操作数 *operands, 整数型 *数量_operands_ptr,
                               整数型 is_output)
{
    汇编操作数 *op;
    整数型 数量_operands;

    如果 (单词编码 != ':') {
        数量_operands = *数量_operands_ptr;
        循环(;;) {
	    动态字符串 astr;
            如果 (数量_operands >= 最大_汇编_操作数)
                错误_打印("太多的汇编操作数");
            op = &operands[数量_operands++];
            op->id = 0;
            如果 (单词编码 == '[') {
                带有宏替换的下个标记();
                如果 (单词编码 < 符_识别)
                    应为("identifier");
                op->id = 单词编码;
                带有宏替换的下个标记();
                跳过(']');
            }
	    解析_多_字符串(&astr, "string constant");
            op->constraint = 内存_申请(astr.字符串长度);
            strcpy(op->constraint, astr.指向字符串的指针);
	    动态字符串_释放(&astr);
            跳过('(');
            通用表达式();
            如果 (is_output) {
                如果 (!(栈顶值->type.t & VT_数组))
                    测试_左值();
            } 否则 {
                /* 我们希望避免使用LLOCAL的情况,除非使用'm'约束。 请注意,它可能来自寄存器存储,因此我们需要转换(reg)大小写 */
                如果 ((栈顶值->r & VT_LVAL) &&
                    ((栈顶值->r & VT_值掩码) == VT_LLOCAL ||
                     (栈顶值->r & VT_值掩码) < VT_VC常量) &&
                    !strchr(op->constraint, 'm')) {
                    将rc寄存器值存储在栈顶值中(寄存器类_整数);
                }
            }
            op->vt = 栈顶值;
            跳过(')');
            如果 (单词编码 == ',') {
                带有宏替换的下个标记();
            } 否则 {
                跳出;
            }
        }
        *数量_operands_ptr = 数量_operands;
    }
}

/* 解析GCC asm()指令 */
静态_函数 无类型 汇编_指令字符串(无类型)
{
    动态字符串 astr, astr1;
    汇编操作数 operands[最大_汇编_操作数];
    整数型 数量_outputs, 数量_operands, i, must_subst, out_reg;
    uint8_t clobber_regs[NB_ASM_REGS];*sec;

    /* 由于我们总是生成asm()指令,因此可以忽略volatile */
    如果 (单词编码 == 关键字_VOLATILE1 || 单词编码 == 关键字_VOLATILE2 || 单词编码 == 关键字_VOLATILE3 || 单词编码 == 关键字_易变) {
        带有宏替换的下个标记();
    }
    解析_汇编_字符串(&astr);
    数量_operands = 0;
    数量_outputs = 0;
    must_subst = 0;
    memset(clobber_regs, 0, 取大小(clobber_regs));
    如果 (单词编码 == ':') {
        带有宏替换的下个标记();
        must_subst = 1;
        /* 输出参数 */
        解析_汇编_操作数(operands, &数量_operands, 1);
        数量_outputs = 数量_operands;
        如果 (单词编码 == ':') {
            带有宏替换的下个标记();
            如果 (单词编码 != ')') {
                /* 输入参数 */
                解析_汇编_操作数(operands, &数量_operands, 0);
                如果 (单词编码 == ':') {
                    /* 垃圾清单 */
                    /* XXX: 处理寄存器 */
                    带有宏替换的下个标记();
                    循环(;;) {
                        如果 (单词编码 != 常量_字符串)
                            应为("string constant");
                        汇编_破坏者(clobber_regs, 单词值.str.data);/**/
                        带有宏替换的下个标记();
                        如果 (单词编码 == ',') {
                            带有宏替换的下个标记();
                        } 否则 {
                            跳出;
                        }
                    }
                }
            }
        }
    }
    跳过(')');
    /* 注意:我们不吃';' 这样我们就可以在汇编程序解析后还原当前令牌 */
    如果 (单词编码 != ';')
        应为("';'");
    
    /* 将所有值保存在内存中 */
    保存_寄存器最多n个堆栈条目(0);

    /* 计算约束 */
    汇编_计算_约束(operands, 数量_operands, 数量_outputs, 
                            clobber_regs, &out_reg);

    /* 替换asm字符串中的操作数。 如果没有操作数(GCC行为),则不会进行替换*/
#如果已定义 ASM_DEBUG
    printf("asm: \"%s\"\n", (字符型 *)astr.指向字符串的指针);
#结束如果
    如果 (must_subst) {
        替代_汇编_操作数(operands, 数量_operands, &astr1, &astr);
        动态字符串_释放(&astr);
    } 否则 {
        astr1 = astr;
    }
#如果已定义 ASM_DEBUG
    printf("subst_asm: \"%s\"\n", (字符型 *)astr1.指向字符串的指针);
#结束如果

    /* 产生负荷 */
    汇编_生成_代码(operands, 数量_operands, 数量_outputs, 0, 
                 clobber_regs, out_reg);    

    /* 用zhi内部汇编器组装轴向  */
    sec = 当前_生成代码_段;
    /* 用zhi内部汇编器组装字符串 */
    zhi_内联_汇编(zhi_状态, astr1.指向字符串的指针, astr1.字符串长度 - 1, 0);
    如果 (sec != 当前_生成代码_段) {
        zhi_警告("内联 asm tries to change current section");
        使用_段1(zhi_状态, sec);
    }

    /* 恢复当前的C标识符 */
    带有宏替换的下个标记();

    /* 如果需要,存储输出值*/
    汇编_生成_代码(operands, 数量_operands, 数量_outputs, 1, 
                 clobber_regs, out_reg);
    
    /* 释放一切 */
    循环(i=0;i<数量_operands;i++) {
        汇编操作数 *op;
        op = &operands[i];
        内存_释放(op->constraint);
        弹出堆栈值();
    }
    动态字符串_释放(&astr1);
}

静态_函数 无类型 汇编_全局_instr(无类型)
{
    动态字符串 astr;
    整数型 saved_nocode_wanted = 不需要_代码生成;

    /* 始终会发出全局asm块。  */
    不需要_代码生成 = 0;
    带有宏替换的下个标记();
    解析_汇编_字符串(&astr);
    跳过(')');
    /* 注意:我们不吃';' 这样我们就可以在汇编程序解析后还原当前标识 */
    如果 (单词编码 != ';')
        应为("';'");
    
#如果已定义 ASM_DEBUG
    printf("汇编_global: \"%s\"\n", (字符型 *)astr.指向字符串的指针);
#结束如果
    当前_生成代码_段 = 生成代码_段;
    输出代码索引 = 当前_生成代码_段->数据_偏移;

    /* 用zhi内部汇编器组装字符串 */
    zhi_内联_汇编(zhi_状态, astr.指向字符串的指针, astr.字符串长度 - 1, 1);
    
    当前_生成代码_段->数据_偏移 = 输出代码索引;

    /* 恢复当前的C标识符 */
    带有宏替换的下个标记();

    动态字符串_释放(&astr);
    不需要_代码生成 = saved_nocode_wanted;
}
#结束如果 /* 配置_ZHI_汇编 */