Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1286231
  • 博文数量: 196
  • 博客积分: 4141
  • 博客等级: 中将
  • 技术积分: 2253
  • 用 户 组: 普通用户
  • 注册时间: 2009-03-21 20:04
文章存档

2019年(31)

2016年(1)

2014年(16)

2011年(8)

2010年(25)

2009年(115)

分类:

2009-03-22 12:26:40

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 (...) */

阅读(2916) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~