Example #1
0
int findsegment(int16 type,int16 reserved)
{
    int i;

    for (i = 0; i < nsegs; i++)
	if (outputseg[i].type == type) return i;

    return allocnewseg(type,reserved);
}
Example #2
0
File: ldrdf.c Project: aosm/nasm
/*
 * processmodule()
 *
 * step through each segment, determine what exactly we're doing with
 * it, and if we intend to keep it, determine (a) which segment to
 * put it in and (b) whereabouts in that segment it will end up.
 * (b) is fairly easy, because we're now keeping track of how big each
 * segment in our output file is...
 */
void processmodule(const char *filename, struct modulenode *mod)
{
    struct segconfig sconf;
    int seg, outseg;
    void *header;
    rdfheaderrec *hr;
    long bssamount = 0;
    int bss_was_referenced = 0;

    for (seg = 0; seg < mod->f.nsegs; seg++) {
        /*
         * get the segment configuration for this type from the segment
         * table. getsegconfig() is a macro, defined in ldsegs.h.
         */
        getsegconfig(sconf, mod->f.seg[seg].type);

        if (options.verbose > 1) {
            printf("%s %04x [%04x:%10s] ", filename,
                   mod->f.seg[seg].number, mod->f.seg[seg].type,
                   sconf.typedesc);
        }
        /*
         * sconf->dowhat tells us what to do with a segment of this type.
         */
        switch (sconf.dowhat) {
        case SEG_IGNORE:
            /*
             * Set destination segment to -1, to indicate that this segment
             * should be ignored for the purpose of output, ie it is left
             * out of the linked executable.
             */
            mod->seginfo[seg].dest_seg = -1;
            if (options.verbose > 1)
                printf("IGNORED\n");
            break;

        case SEG_NEWSEG:
            /*
             * The configuration tells us to create a new segment for
             * each occurrence of this segment type.
             */
            outseg = allocnewseg(sconf.mergetype,
                                 mod->f.seg[seg].reserved);
            mod->seginfo[seg].dest_seg = outseg;
            mod->seginfo[seg].reloc = 0;
            outputseg[outseg].length = mod->f.seg[seg].length;
            if (options.verbose > 1)
                printf("=> %04x:%08lx (+%04lx)\n", outseg,
                       mod->seginfo[seg].reloc, mod->f.seg[seg].length);
            break;

        case SEG_MERGE:
            /*
             * The configuration tells us to merge the segment with
             * a previously existing segment of type 'sconf.mergetype',
             * if one exists. Otherwise a new segment is created.
             * This is handled transparently by 'findsegment()'.
             */
            outseg = findsegment(sconf.mergetype,
                                 mod->f.seg[seg].reserved);
            mod->seginfo[seg].dest_seg = outseg;

            /*
             * We need to add alignment to these segments.
             */
            if (outputseg[outseg].length % options.align != 0)
                outputseg[outseg].length +=
                    options.align -
                    (outputseg[outseg].length % options.align);

            mod->seginfo[seg].reloc = outputseg[outseg].length;
            outputseg[outseg].length += mod->f.seg[seg].length;

            if (options.verbose > 1)
                printf("=> %04x:%08lx (+%04lx)\n", outseg,
                       mod->seginfo[seg].reloc, mod->f.seg[seg].length);
        }

    }

    /*
     * extract symbols from the header, and dump them into the
     * symbol table
     */
    header = malloc(mod->f.header_len);
    if (!header) {
        fprintf(stderr, "ldrdf: not enough memory\n");
        exit(1);
    }
    if (rdfloadseg(&mod->f, RDOFF_HEADER, header)) {
        rdfperror("ldrdf", filename);
        exit(1);
    }

    while ((hr = rdfgetheaderrec(&mod->f))) {
        switch (hr->type) {
        case RDFREC_IMPORT:    /* imported symbol */
        case RDFREC_FARIMPORT:
            /* Define with seg = -1 */
            symtab_add(hr->i.label, -1, 0);
            break;

        case RDFREC_GLOBAL:{   /* exported symbol */
                int destseg;
                long destreloc;

                if (hr->e.segment == 2) {
                    bss_was_referenced = 1;
                    destreloc = bss_length;
                    if (destreloc % options.align != 0)
                        destreloc +=
                            options.align - (destreloc % options.align);
                    destseg = 2;
                } else {
                    if ((destseg =
                         mod->seginfo[(int)hr->e.segment].dest_seg) == -1)
                        continue;
                    destreloc = mod->seginfo[(int)hr->e.segment].reloc;
                }
                symtab_add(hr->e.label, destseg, destreloc + hr->e.offset);
                break;
            }

        case RDFREC_BSS:       /* BSS reservation */
            /*
             * first, amalgamate all BSS reservations in this module
             * into one, because we allow this in the output format.
             */
            bssamount += hr->b.amount;
            break;

        case RDFREC_COMMON:{   /* Common variable */
                symtabEnt *ste = symtabFind(symtab, hr->c.label);

                /* Is the symbol already in the table? */
                if (ste)
                    break;

                /* Align the variable */
                if (bss_length % hr->c.align != 0)
                    bss_length += hr->c.align - (bss_length % hr->c.align);
                if (options.verbose > 1) {
                    printf("%s %04x common '%s' => 0002:%08lx (+%04lx)\n",
                           filename, hr->c.segment, hr->c.label,
                           bss_length, hr->c.size);
                }

                symtab_add(hr->c.label, 2, bss_length);
                mod->bss_reloc = bss_length;
                bss_length += hr->c.size;
                break;
            }
        }
    }

    if (bssamount != 0 || bss_was_referenced) {
        /*
         * handle the BSS segment - first pad the existing bss length
         * to the correct alignment, then store the length in bss_reloc
         * for this module. Then add this module's BSS length onto
         * bss_length.
         */
        if (bss_length % options.align != 0)
            bss_length += options.align - (bss_length % options.align);

        mod->bss_reloc = bss_length;
        if (options.verbose > 1) {
            printf("%s 0002 [            BSS] => 0002:%08lx (+%04lx)\n",
                   filename, bss_length, bssamount);
        }
        bss_length += bssamount;
    }
#ifdef STINGY_MEMORY
    /*
     * we free the header buffer here, to save memory later.
     * this isn't efficient, but probably halves the memory usage
     * of this program...
     */
    mod->f.header_loc = NULL;
    free(header);

#endif

}