static void assemble_file(char *fname) { char *directive, *value, *p, *q, *special, *line, debugid[80]; insn output_ins; int i, rn_error, validid; long seg, offs; struct tokenval tokval; expr *e; int pass, pass_max; int pass_cnt = 0; /* count actual passes */
if (cmd_sb == 32 && cmd_cpu < IF_386) report_error(ERR_FATAL, "command line: 32-bit segment size requires a higher cpu");
pass_max = (optimizing > 0 ? optimizing : 0) + 2; /* passes 1, optimizing, then 2 */ pass0 = !(optimizing > 0); /* start at 1 if not optimizing */
/* 正式进行指令汇编 */ for (pass = 1; pass <= pass_max && pass0 <= 2; pass++) { /* 没有优化的情况下是循环 2 遍,优化的情况下最多循环 4 遍 */ int pass1, pass2; ldfunc def_label;
pass1 = pass < pass_max ? 1 : 2; /* seq is 1, 1, 1,..., 1, 2 */ pass2 = pass > 1 ? 2 : 1; /* seq is 1, 2, 2,..., 2, 2 */ /* pass0 seq is 0, 0, 0,..., 1, 2 */
def_label = pass > 1 ? redefine_label : define_label;
sb = cmd_sb; /* set 'bits' to command line default */ cpu = cmd_cpu; if (pass0 == 2) { if (*listname) nasmlist.init(listname, report_error); } in_abs_seg = FALSE; global_offset_changed = FALSE; /* set by redefine_label */ location.segment = ofmt->section(NULL, pass2, &sb); /* 获取代码段索引,并且将 sb 设置成 32 ,在这里, pass2 不起作用*/ if (pass > 1) { /* 估计是插入机器码用的 ??? */ saa_rewind(forwrefs); forwref = saa_rstruct(forwrefs); raa_free(offsets); offsets = raa_init(); } preproc->reset(fname, pass1, report_error, evaluate, &nasmlist); globallineno = 0; if (pass == 1) location.known = TRUE; location.offset = offs = GET_CURR_OFFS; /* #define GET_CURR_OFFS (in_abs_seg ? abs_offset : raa_read(offsets, location.segment)) */
while ((line = preproc->getline())) { globallineno++;
/* here we parse our directives; this is not handled by the 'real' * parser. */ directive = line; if ((i = getkw(&directive, &value))) { switch (i) { case 1: /* [SEGMENT n] 例如:[SECTION .text] */ seg = ofmt->section(value, pass2, &sb); /* 建立相应的 section, 并获取其索引 */ if (seg == NO_SEG) { report_error(pass1 == 1 ? ERR_NONFATAL : ERR_PANIC, "segment name `%s' not recognised", value); } else { in_abs_seg = FALSE; location.segment = seg; } break; case 2: /* [EXTERN label(:special) (size 计算式)] */ if (*value == '$') value++; /* skip initial $ if present */ if (pass0 == 2) { q = value; while (*q && *q != ':') q++; if (*q == ':') { *q++ = '\0'; ofmt->symdef(value, 0L, 0L, 3, q); /* * 将变量名与属性取出放入 value 与 q 中,然后进行处理,参数 3 表示已经定义的全局变量 * global, extern 的符号最后插入 */ } } else if (pass == 1) { /* pass == 1 */ q = value; validid = TRUE; if (!isidstart(*q)) validid = FALSE; while (*q && *q != ':') { if (!isidchar(*q)) validid = FALSE; q++; } if (!validid) { /* 判断是否符合变量声明规定 */ report_error(ERR_NONFATAL, "identifier expected after EXTERN"); break; } /* 通过 : 判断,将字符串的名字和属性分别放入 value 和 q 中 */ if (*q == ':') { *q++ = '\0'; special = q; } else special = NULL;
if (!is_extern(value)) { /* allow re-EXTERN to be ignored */ int temp = pass0; pass0 = 1; /* fake pass 1 in labels.c */ declare_as_global(value, special, report_error); /* 在这个函数,pass0 不起作用 */ define_label(value, seg_alloc(), 0L, NULL, FALSE, TRUE, ofmt, report_error); pass0 = temp; } } /* else pass0 == 1 */ break; case 3: /* [BITS bits] */ sb = get_bits(value); break; case 4: /* [GLOBAL symbol(:special) (size 计算式)] */ if (*value == '$') value++; /* skip initial $ if present */ if (pass0 == 2) { /* pass 2 */ q = value; while (*q && *q != ':') q++; if (*q == ':') { *q++ = '\0'; ofmt->symdef(value, 0L, 0L, 3, q); /* * 将变量名与属性取出放入 value 与 q 中,然后进行处理,参数 3 表示已经定义的全局变量 * global, extern 的符号最后插入 */ } } else if (pass2 == 1) { /* pass == 1 */ q = value; validid = TRUE; if (!isidstart(*q)) validid = FALSE; while (*q && *q != ':') { if (!isidchar(*q)) validid = FALSE; q++; } if (!validid) { report_error(ERR_NONFATAL, "identifier expected after GLOBAL"); break; } if (*q == ':') { *q++ = '\0'; special = q; } else special = NULL; declare_as_global(value, special, report_error); } /* pass == 1 */ break; case 5: /* [COMMON symbol size:special] */ if (*value == '$') value++; /* skip initial $ if present */ if (pass0 == 1) { p = value; validid = TRUE; if (!isidstart(*p)) validid = FALSE; /* 获取 symbol */ while (*p && !isspace(*p)) { if (!isidchar(*p)) validid = FALSE; p++; } if (!validid) { report_error(ERR_NONFATAL, "identifier expected after COMMON"); break; } if (*p) { long size;
/* 获取 size */ while (*p && isspace(*p)) *p++ = '\0'; q = p; while (*q && *q != ':') q++;
/* 获取 special */ if (*q == ':') { *q++ = '\0'; special = q; } else special = NULL; size = readnum(p, &rn_error); if (rn_error) report_error(ERR_NONFATAL, "invalid size specified in COMMON declaration"); else define_common(value, seg_alloc(), size, special, ofmt, report_error); } else report_error(ERR_NONFATAL, "no size specified in COMMON declaration"); } else if (pass0 == 2) { /* pass == 2 */ q = value; while (*q && *q != ':') { if (isspace(*q)) *q = '\0'; q++; } if (*q == ':') { *q++ = '\0'; ofmt->symdef(value, 0L, 0L, 3, q); } } break; case 6: /* [ABSOLUTE address] */ stdscan_reset(); stdscan_bufptr = value; tokval.t_type = TOKEN_INVALID; e = evaluate(stdscan, NULL, &tokval, NULL, pass2, report_error, NULL); if (e) { if (!is_reloc(e)) report_error(pass0 == 1 ? ERR_NONFATAL : ERR_PANIC, "cannot use non-relocatable expression as ABSOLUTE address"); else { abs_seg = reloc_seg(e); abs_offset = reloc_value(e); } } else if (pass == 1) abs_offset = 0x100; /* don't go near zero in case of / */ else report_error(ERR_PANIC, "invalid ABSOLUTE address in pass two"); in_abs_seg = TRUE; location.segment = NO_SEG; break; case 7: /* DEBUG */ p = value; q = debugid; validid = TRUE; if (!isidstart(*p)) validid = FALSE; while (*p && !isspace(*p)) { if (!isidchar(*p)) validid = FALSE; *q++ = *p++; } *q++ = 0; if (!validid) { report_error(pass == 1 ? ERR_NONFATAL : ERR_PANIC, "identifier expected after DEBUG"); break; } while (*p && isspace(*p)) p++; if (pass == pass_max) ofmt->current_dfmt->debug_directive(debugid, p); break; case 8: /* [WARNING {+|-}warn-name] */ if (pass1 == 1) { while (*value && isspace(*value)) value++;
if (*value == '+' || *value == '-') { validid = (*value == '-') ? TRUE : FALSE; value++; } else validid = FALSE;
for (i = 1; i <= ERR_WARN_MAX; i++) if (!nasm_stricmp(value, suppressed_names[i])) break; if (i <= ERR_WARN_MAX) suppressed[i] = validid; else report_error(ERR_NONFATAL, "invalid warning id in WARNING directive"); } break; case 9: /* cpu */ cpu = get_cpu(value); break; case 10: /* fbk 9/2/00 *//* [LIST {+|-}] */ /* 在源代码中关闭或者开启 listing file 功能 */ while (*value && isspace(*value)) value++;
if (*value == '+') { user_nolist = 0; } else { if (*value == '-') { user_nolist = 1; } else { report_error(ERR_NONFATAL, "invalid parameter to \"list\" directive"); } } break; default: if (!ofmt->directive(directive, value, pass2)) report_error(pass1 == 1 ? ERR_NONFATAL : ERR_PANIC, "unrecognised directive [%s]", directive); } } else { /* it isn't a directive */ /* 处理非 directive */
parse_line(pass1, line, &output_ins, report_error, evaluate, def_label);
if (!(optimizing > 0) && pass == 2) { if (forwref != NULL && globallineno == forwref->lineno) { /* 在 pass == 2 的时候,设置 label forward 标记 */ output_ins.forw_ref = TRUE; do { output_ins.oprs[forwref->operand].opflags |= OPFLAG_FORWARD; forwref = saa_rstruct(forwrefs); } while (forwref != NULL && forwref->lineno == globallineno); } else output_ins.forw_ref = FALSE; }
if (!(optimizing > 0) && output_ins.forw_ref) { if (pass == 1) { /* 在 pass == 1 的时候,将 Forward Label 放入 forwrefs 中 */ for (i = 0; i < output_ins.operands; i++) { if (output_ins.oprs[i].opflags & OPFLAG_FORWARD) { struct forwrefinfo *fwinf = (struct forwrefinfo *) saa_wstruct(forwrefs); fwinf->lineno = globallineno; fwinf->operand = i; } } } else { /* pass == 2 */ /* * Hack to prevent phase error in the code * rol ax,x * x equ 1 * * If the second operand is a forward reference, * the UNITY property of the number 1 in that * operand is cancelled. Otherwise the above * sequence will cause a phase error. * * This hack means that the above code will * generate 286+ code. * * The forward reference will mean that the * operand will not have the UNITY property on * the first pass, so the pass behaviours will * be consistent. */
if (output_ins.operands >= 2 && (output_ins.oprs[1].opflags & OPFLAG_FORWARD)) { output_ins.oprs[1].type &= ~(ONENESS | BYTENESS); }
} /* pass == 2 */
}
/* forw_ref */ if (output_ins.opcode == I_EQU) { if (pass1 == 1) { /* 处理 equ 指令,当作 label 处理 */ /* * Special `..' EQUs get processed in pass two, * except `..@' macro-processor EQUs which are done * in the normal place. */ if (!output_ins.label) report_error(ERR_NONFATAL, "EQU not preceded by label"); /* equ 0; 显示此出错信息 */
else if (output_ins.label[0] != '.' || output_ins.label[1] != '.' || output_ins.label[2] == '@') { if (output_ins.operands == 1 && (output_ins.oprs[0].type & IMMEDIATE) && output_ins.oprs[0].wrt == NO_SEG) { int isext = output_ins.oprs[0].opflags & OPFLAG_EXTERN; def_label(output_ins.label, output_ins.oprs[0].segment, output_ins.oprs[0].offset, NULL, FALSE, isext, ofmt, report_error); } else if (output_ins.operands == 2 /* Temp: equ 0:3 ;segment:offset */ && (output_ins.oprs[0].type & IMMEDIATE) && (output_ins.oprs[0].type & COLON) && output_ins.oprs[0].segment == NO_SEG && output_ins.oprs[0].wrt == NO_SEG && (output_ins.oprs[1].type & IMMEDIATE) && output_ins.oprs[1].segment == NO_SEG && output_ins.oprs[1].wrt == NO_SEG) { def_label(output_ins.label, output_ins.oprs[0].offset | SEG_ABS, /* 地址固定的参数 */ output_ins.oprs[1].offset, NULL, FALSE, FALSE, ofmt, report_error); } else report_error(ERR_NONFATAL, "bad syntax for EQU"); } } else { /* pass == 2 */ /* * Special `..' EQUs get processed here, except * `..@' macro processor EQUs which are done above. */ if (output_ins.label[0] == '.' && output_ins.label[1] == '.' && output_ins.label[2] != '@') { if (output_ins.operands == 1 && (output_ins.oprs[0].type & IMMEDIATE)) { define_label(output_ins.label, output_ins.oprs[0].segment, output_ins.oprs[0].offset, NULL, FALSE, FALSE, ofmt, report_error); } else if (output_ins.operands == 2 && (output_ins.oprs[0].type & IMMEDIATE) && (output_ins.oprs[0].type & COLON) && output_ins.oprs[0].segment == NO_SEG && (output_ins.oprs[1].type & IMMEDIATE) && output_ins.oprs[1].segment == NO_SEG) { define_label(output_ins.label, output_ins.oprs[0].offset | SEG_ABS, output_ins.oprs[1].offset, NULL, FALSE, FALSE, ofmt, report_error); } else report_error(ERR_NONFATAL, "bad syntax for EQU"); } } /* pass == 2 */ } else { /* instruction isn't an EQU */
if (pass1 == 1) { /* 主要是计算指令长度 */
long l = insn_size(location.segment, offs, sb, cpu, &output_ins, report_error);
/* if (using_debug_info) && output_ins.opcode != -1) */ if (using_debug_info) { /* fbk 03/25/01 */ /* this is done here so we can do debug type info */ long typeinfo = TYS_ELEMENTS(output_ins.operands); switch (output_ins.opcode) { case I_RESB: typeinfo = TYS_ELEMENTS(output_ins.oprs[0].offset) | TY_BYTE; break; case I_RESW: typeinfo = TYS_ELEMENTS(output_ins.oprs[0].offset) | TY_WORD; break; case I_RESD: typeinfo = TYS_ELEMENTS(output_ins.oprs[0].offset) | TY_DWORD; break; case I_RESQ: typeinfo = TYS_ELEMENTS(output_ins.oprs[0].offset) | TY_QWORD; break; case I_REST: typeinfo = TYS_ELEMENTS(output_ins.oprs[0].offset) | TY_TBYTE; break; case I_DB: typeinfo |= TY_BYTE; break; case I_DW: typeinfo |= TY_WORD; break; case I_DD: if (output_ins.eops_float) typeinfo |= TY_FLOAT; else typeinfo |= TY_DWORD; break; case I_DQ: typeinfo |= TY_QWORD; break; case I_DT: typeinfo |= TY_TBYTE; break; default: typeinfo = TY_LABEL;
}
ofmt->current_dfmt->debug_typevalue(typeinfo); /* 在该版本,此函数未实现 */ } if (l != -1) { offs += l; SET_CURR_OFFS(offs); } /* * else l == -1 => invalid instruction, which will be * flagged as an error on pass 2 */
} else { /* pass == 2 */ /* 汇编指令 */ offs += assemble(location.segment, offs, sb, cpu, &output_ins, ofmt, report_error, &nasmlist); SET_CURR_OFFS(offs); } } /* not an EQU */ cleanup_insn(&output_ins); } nasm_free(line); location.offset = offs = GET_CURR_OFFS; } /* end while (line = preproc->getline... */
if (pass1 == 2 && global_offset_changed) report_error(ERR_NONFATAL, "phase error detected at end of assembly.");
if (pass1 == 1) preproc->cleanup(1);
if (pass1 == 1 && terminate_after_phase) { fclose(ofile); remove(outname); if (want_usage) usage(); exit(1); } pass_cnt++; if (pass > 1 && !global_offset_changed) { pass0++; if (pass0 == 2) pass = pass_max - 1; } else if (!(optimizing > 0)) pass0++;
} /* for (pass=1; pass<=2; pass++) */
preproc->cleanup(0); /* pass = 0 */ nasmlist.cleanup(); #if 1 if (optimizing > 0 && opt_verbose_info) /* -On and -Ov switches */ fprintf(stdout, "info:: assembly required 1+%d+1 passes\n", pass_cnt - 2); #endif } /* exit from assemble_file (...) */
|