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_汇编 */
推荐阅读
-
TCC(TinyC)编译器汉化(中文编译器、汉语编程)之四:语法分析上
-
TCC(TinyC)编译器汉化(中文编译器、汉语编程)之三:词法分析
-
TCC(TinyC)编译器汉化(中文编译器、汉语编程)之二:字符(token)汉化
-
TCC(TinyC)编译器汉化(中文编译器、汉语编程)之九:核心库源码
-
TCC(TinyC)编译器汉化(中文编译器、汉语编程)之七:中间语言生成器
-
TCC(TinyC)编译器汉化(中文编译器、汉语编程)之六:中间操作码
-
TCC(TinyC)编译器汉化(中文编译器、汉语编程)之八:汇编处理
-
TCC(TinyC)编译器汉化(中文编译器、汉语编程)之一:主文件汉化
-
TCC(TinyC)编译器汉化(中文编译器、汉语编程)之五:语法分析下