⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ldrdf.c

📁 nasm的全套源代码,有些我做了些修改,以方便您更方便更容易调试成功,方便学习做编译器
💻 C
📖 第 1 页 / 共 3 页
字号:
 * symtab_add()
 *
 * inserts a symbol into the global symbol table, which associates symbol
 * names either with addresses, or a marker that the symbol hasn't been
 * resolved yet, or possibly that the symbol has been defined as
 * contained in a dynamic [load time/run time] linked library.
 *
 * segment = -1 => not yet defined
 * segment = -2 => defined as dll symbol
 *
 * If the symbol is already defined, and the new segment >= 0, then
 * if the original segment was < 0 the symbol is redefined, otherwise
 * a duplicate symbol warning is issued. If new segment == -1, this
 * routine won't change a previously existing symbol. It will change
 * to segment = -2 only if the segment was previously < 0.
 */
void symtab_add(const char *symbol, int segment, long offset)
{
    symtabEnt *ste;

    ste = symtabFind(symtab, symbol);
    if (ste) {
        if (ste->segment >= 0) {
            /*
             * symbol previously defined
             */
            if (segment < 0)
                return;
            fprintf(error_file, "warning: `%s' redefined\n", symbol);
            return;
        }

        /*
         * somebody wanted the symbol, and put an undefined symbol
         * marker into the table
         */
        if (segment == -1)
            return;
        /*
         * we have more information now - update the symbol's entry
         */
        ste->segment = segment;
        ste->offset = offset;
        ste->flags = 0;
        return;
    }
    /*
     * this is the first declaration of this symbol
     */
    ste = malloc(sizeof(symtabEnt));
    if (!ste) {
        fprintf(stderr, "ldrdf: out of memory\n");
        exit(1);
    }
    ste->name = strdup(symbol);
    ste->segment = segment;
    ste->offset = offset;
    ste->flags = 0;
    symtabInsert(symtab, ste);
}

/*
 * symtab_get()
 *
 * Retrieves the values associated with a symbol. Undefined symbols
 * are assumed to have -1:0 associated. Returns 1 if the symbol was
 * successfully located.
 */
int symtab_get(const char *symbol, int *segment, long *offset)
{
    symtabEnt *ste = symtabFind(symtab, symbol);
    if (!ste) {
        *segment = -1;
        *offset = 0;
        return 0;
    } else {
        *segment = ste->segment;
        *offset = ste->offset;
        return 1;
    }
}

/*
 * add_library()
 *
 * checks that a library can be opened and is in the correct format,
 * then adds it to the linked list of libraries.
 */
void add_library(const char *name)
{
    if (rdl_verify(name)) {
        rdl_perror("ldrdf", name);
        errorcount++;
        return;
    }
    if (!libraries) {
        lastlib = libraries = malloc(sizeof(*libraries));
        if (!libraries) {
            fprintf(stderr, "ldrdf: out of memory\n");
            exit(1);
        }
    } else {
        lastlib->next = malloc(sizeof(*libraries));
        if (!lastlib->next) {
            fprintf(stderr, "ldrdf: out of memory\n");
            exit(1);
        }
        lastlib = lastlib->next;
    }
    lastlib->next = NULL;
    if (rdl_open(lastlib, name)) {
        rdl_perror("ldrdf", name);
        errorcount++;
        return;
    }
}

/*
 * search_libraries()
 *
 * scans through the list of libraries, attempting to match symbols
 * defined in library modules against symbols that are referenced but
 * not defined (segment = -1 in the symbol table)
 *
 * returns 1 if any extra library modules are included, indicating that
 * another pass through the library list should be made (possibly).
 */
int search_libraries()
{
    struct librarynode *cur;
    rdffile f;
    int i;
    void *header;
    int segment;
    long offset;
    int doneanything = 0, pass = 1, keepfile;
    rdfheaderrec *hr;

    cur = libraries;

    while (cur) {
        if (options.verbose > 2)
            printf("scanning library `%s', pass %d...\n", cur->name, pass);

        for (i = 0; rdl_openmodule(cur, i, &f) == 0; i++) {
            if (pass == 2 && lookformodule(f.name))
                continue;

            if (options.verbose > 3)
                printf("  looking in module `%s'\n", f.name);

            header = malloc(f.header_len);
            if (!header) {
                fprintf(stderr, "ldrdf: not enough memory\n");
                exit(1);
            }
            if (rdfloadseg(&f, RDOFF_HEADER, header)) {
                rdfperror("ldrdf", f.name);
                errorcount++;
                return 0;
            }

            keepfile = 0;

            while ((hr = rdfgetheaderrec(&f))) {
                /* We're only interested in exports, so skip others */
                if (hr->type != RDFREC_GLOBAL)
                    continue;

                /*
                 * If the symbol is marked as SYM_GLOBAL, somebody will be
                 * definitely interested in it..
                 */
                if ((hr->e.flags & SYM_GLOBAL) == 0) {
                    /*
                     * otherwise the symbol is just public. Find it in
                     * the symbol table. If the symbol isn't defined, we
                     * aren't interested, so go on to the next.
                     * If it is defined as anything but -1, we're also not
                     * interested. But if it is defined as -1, insert this
                     * module into the list of modules to use, and go
                     * immediately on to the next module...
                     */
                    if (!symtab_get(hr->e.label, &segment, &offset)
                        || segment != -1)
                        continue;
                }

                doneanything = 1;
                keepfile = 1;

                /*
                 * as there are undefined symbols, we can assume that
                 * there are modules on the module list by the time
                 * we get here.
                 */
                lastmodule->next = malloc(sizeof(*lastmodule->next));
                if (!lastmodule->next) {
                    fprintf(stderr, "ldrdf: not enough memory\n");
                    exit(1);
                }
                lastmodule = lastmodule->next;
                memcpy(&lastmodule->f, &f, sizeof(f));
                lastmodule->name = strdup(f.name);
                lastmodule->next = NULL;
                processmodule(f.name, lastmodule);
                break;
            }
            if (!keepfile) {
                free(f.name);
                f.name = NULL;
                f.fp = NULL;
            }
        }
        if (rdl_error != 0 && rdl_error != RDL_ENOTFOUND)
            rdl_perror("ldrdf", cur->name);

        cur = cur->next;
        if (cur == NULL && pass == 1) {
            cur = libraries;
            pass++;
        }
    }

    return doneanything;
}

/*
 * write_output()
 *
 * this takes the linked list of modules, and walks through it, merging
 * all the modules into a single output module, and then writes this to a
 * file.
 */
void write_output(const char *filename)
{
    FILE *f;
    rdf_headerbuf *rdfheader;
    struct modulenode *cur;
    int i, availableseg, seg, localseg, isrelative;
    void *header;
    rdfheaderrec *hr, newrec;
    symtabEnt *se;
    segtab segs;
    long offset;
    byte *data;

    if ((f = fopen(filename, "wb")) == NULL) {
        fprintf(stderr, "ldrdf: couldn't open %s for output\n", filename);
        exit(1);
    }
    if ((rdfheader = rdfnewheader()) == NULL) {
        fprintf(stderr, "ldrdf: out of memory\n");
        exit(1);
    }

    /*
     * If '-g' option was given, first record in output file will be a
     * `generic' record, filled with a given file content.
     * This can be useful, for example, when constructing multiboot
     * compliant kernels.
     */
    if (generic_rec_file) {
        FILE *ff;

        if (options.verbose)
            printf("\nadding generic record from binary file %s\n",
                   generic_rec_file);

        hr = (rdfheaderrec *) malloc(sizeof(struct GenericRec));
        if ((ff = fopen(generic_rec_file, "r")) == NULL) {
            fprintf(stderr, "ldrdf: couldn't open %s for input\n",
                    generic_rec_file);
            exit(1);
        }
        i = fread(hr->g.data, 1, sizeof(hr->g.data), ff);
        fseek(ff, 0, SEEK_END);
        if (ftell(ff) > sizeof(hr->g.data)) {
            fprintf(error_file,
                    "warning: maximum generic record size is %d, rest of file ignored\n",
                    sizeof(hr->g.data));
        }
        fclose(ff);

        hr->g.type = 0;
        hr->g.reclen = i;
        rdfaddheader(rdfheader, hr);
        free(hr);
    }

    if (options.verbose)
        printf("\nbuilding output module (%d segments)\n", nsegs);

    /*
     * Allocate the memory for the segments. We may be better off
     * building the output module one segment at a time when running
     * under 16 bit DOS, but that would be a slower way of doing this.
     * And you could always use DJGPP...
     */
    for (i = 0; i < nsegs; i++) {
        outputseg[i].data = NULL;
        if (!outputseg[i].length)
            continue;
        outputseg[i].data = malloc(outputseg[i].length);
        if (!outputseg[i].data) {
            fprintf(stderr, "ldrdf: out of memory\n");
            exit(1);
        }
    }

    /*
     * initialise availableseg, used to allocate segment numbers for
     * imported and exported labels...
     */
    availableseg = nsegs;

    /*
     * Step through the modules, performing required actions on each one
     */
    for (cur = modules; cur; cur = cur->next) {
        /*
         * Read the actual segment contents into the correct places in
         * the newly allocated segments
         */

        for (i = 0; i < cur->f.nsegs; i++) {
            int dest = cur->seginfo[i].dest_seg;

            if (dest == -1)
                continue;
            if (rdfloadseg(&cur->f, i,
                           outputseg[dest].data + cur->seginfo[i].reloc)) {
                rdfperror("ldrdf", cur->name);
                exit(1);
            }
        }

        /*
         * Perform fixups, and add new header records where required
         */

        header = malloc(cur->f.header_len);
        if (!header) {
            fprintf(stderr, "ldrdf: out of memory\n");
            exit(1);
        }

        if (cur->f.header_loc)
            rdfheaderrewind(&cur->f);
        else if (rdfloadseg(&cur->f, RDOFF_HEADER, header)) {
            rdfperror("ldrdf", cur->name);
            exit(1);
        }

        /*
         * we need to create a local segment number -> location
         * table for the segments in this module.
         */
        init_seglocations(&segs);
        for (i = 0; i < cur->f.nsegs; i++) {
            add_seglocation(&segs, cur->f.seg[i].number,
                            cur->seginfo[i].dest_seg,
                            cur->seginfo[i].reloc);
        }
        /*
         * and the BSS segment (doh!)
         */
        add_seglocation(&segs, 2, 2, cur->bss_reloc);

        while ((hr = rdfgetheaderrec(&cur->f))) {
            switch (hr->type) {
            case RDFREC_RELOC: /* relocation record - need to do a fixup */
                /*
                 * First correct the offset stored in the segment from
                 * the start of the segment (which may well have changed).
                 *
                 * To do this we add to the number stored the relocation
                 * factor associated with the segment that contains the
                 * target segment.
                 *
                 * The relocation could be a relative relocation, in which
                 * case we have to first subtract the amount we've relocated
                 * the containing segment by.
                 */
                if (!get_seglocation(&segs, hr->r.refseg, &seg, &offset)) {
                    fprintf(stderr,
                            "%s: reloc to undefined segment %04x\n",
                            cur->name, (int)hr->r.refseg);
                    errorcount++;
                    break;
                }

                isrelative =
                    (hr->r.segment & RDOFF_RELATIVEMASK) ==
                    RDOFF_RELATIVEMASK;
                hr->r.segment &= (RDOFF_RELATIVEMASK - 1);

                if (hr->r.segment == 2 ||
                    (localseg =
                     rdffindsegment(&cur->f, hr->r.segment)) == -1) {
                    fprintf(stderr, "%s: reloc from %s segment (%d)\n",
                            cur->name,
                            hr->r.segment == 2 ? "BSS" : "unknown",
                            hr->r.segment);
                    errorcount++;
                    break;
                }

                if (hr->r.length != 1 && hr->r.length != 2 &&
                    hr->r.length != 4) {
                    fprintf(stderr, "%s: nonstandard length reloc "
                            "(%d bytes)\n", cur->name, hr->r.length);
                    errorcount++;
                    break;
                }

                /* 
                 * okay, now the relocation is in the segment pointed to by
                 * cur->seginfo[localseg], and we know everything else is
                 * okay to go ahead and do the relocation
                 */
                data = outputseg[cur->seginfo[localseg].dest_seg].data;
                data += cur->seginfo[localseg].reloc + hr->r.offset;

                /*
                 * data now points to the reference that needs
                 * relocation. Calculate the relocation factor.
                 * Factor is:
                 *      offset of referred object in segment [in offset]
                 *      (- relocation of localseg, if ref is relative)
                 * For simplicity, the result is stored in 'offset'.
                 * Then add 'offset' onto the value at data.
                 */

                if (isrelative)
                    offset -= cur->seginfo[localseg].reloc;
                switch (hr->r.length) {
                case 1:
                    offset += *data;
                    if (offset < -127 || offset > 128)
                        fprintf(error_file,
                                "warning: relocation out of range "
                                "at %s(%02x:%08lx)\n", cur->name,

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -