Пример #1
0
static void BinWriteMem (BinDesc* D, MemoryArea* M)
/* Write the segments of one memory area to a file */
{
    unsigned I;

    /* Get the start address of this memory area */
    unsigned long Addr = M->Start;

    /* Debugging: Check that the file offset is correct */
    if (ftell (D->F) != (long)M->FileOffs) {
        Internal ("Invalid file offset for memory area %s: %ld/%lu",
                  GetString (M->Name), ftell (D->F), M->FileOffs);
    }

    /* Walk over all segments in this memory area */
    for (I = 0; I < CollCount (&M->SegList); ++I) {

        int DoWrite;

        /* Get the segment */
        SegDesc* S = CollAtUnchecked (&M->SegList, I);

        /* Keep the user happy */
        Print (stdout, 1, "    Writing `%s'\n", GetString (S->Name));

        /* Writes do only occur in the load area and not for BSS segments */
        DoWrite = (S->Flags & SF_BSS) == 0      &&      /* No BSS segment */
                   S->Load == M                 &&      /* LOAD segment */
                   S->Seg->Dumped == 0;                 /* Not already written */

        /* Output debugging stuff */
        PrintBoolVal ("bss", S->Flags & SF_BSS);
        PrintBoolVal ("LoadArea", S->Load == M);
        PrintBoolVal ("Dumped", S->Seg->Dumped);
        PrintBoolVal ("DoWrite", DoWrite);
        PrintNumVal  ("Address", Addr);
        PrintNumVal  ("FileOffs", (unsigned long) ftell (D->F));

        /* Check if the alignment for the segment from the linker config is
         * a multiple for that of the segment.
         */
        if ((S->RunAlignment % S->Seg->Alignment) != 0) {
            /* Segment requires another alignment than configured
             * in the linker.
             */
            Warning ("Segment `%s' is not aligned properly. Resulting "
                     "executable may not be functional.",
                     GetString (S->Name));
        }

        /* If this is the run memory area, we must apply run alignment. If
         * this is not the run memory area but the load memory area (which
         * means that both are different), we must apply load alignment.
         * Beware: DoWrite may be true even if this is the run memory area,
         * because it may be also the load memory area.
         */
        if (S->Run == M) {

            /* Handle ALIGN and OFFSET/START */
            if (S->Flags & SF_ALIGN) {
                /* Align the address */
                unsigned long NewAddr = AlignAddr (Addr, S->RunAlignment);
                if (DoWrite || (M->Flags & MF_FILL) != 0) {
                    WriteMult (D->F, M->FillVal, NewAddr - Addr);
                    PrintNumVal ("SF_ALIGN", NewAddr - Addr);
                }
                Addr = NewAddr;
            } else if (S->Flags & (SF_OFFSET | SF_START)) {
                unsigned long NewAddr = S->Addr;
                if (S->Flags & SF_OFFSET) {
                    /* It's an offset, not a fixed address, make an address */
                    NewAddr += M->Start;
                }
                if (DoWrite || (M->Flags & MF_FILL) != 0) {
                    WriteMult (D->F, M->FillVal, NewAddr-Addr);
                    PrintNumVal ("SF_OFFSET", NewAddr - Addr);
                }
                Addr = NewAddr;
            }

        } else if (S->Load == M) {

            /* Handle ALIGN_LOAD */
            if (S->Flags & SF_ALIGN_LOAD) {
                /* Align the address */
                unsigned long NewAddr = AlignAddr (Addr, S->LoadAlignment);
                if (DoWrite || (M->Flags & MF_FILL) != 0) {
                    WriteMult (D->F, M->FillVal, NewAddr - Addr);
                    PrintNumVal ("SF_ALIGN_LOAD", NewAddr - Addr);
                }
                Addr = NewAddr;
            }

        }

        /* Now write the segment to disk if it is not a BSS type segment and
         * if the memory area is the load area.
         */
        if (DoWrite) {
            unsigned long P = ftell (D->F);
            SegWrite (D->Filename, D->F, S->Seg, BinWriteExpr, D);
            PrintNumVal ("Wrote", (unsigned long) (ftell (D->F) - P));
        } else if (M->Flags & MF_FILL) {
            WriteMult (D->F, S->Seg->FillVal, S->Seg->Size);
            PrintNumVal ("Filled", (unsigned long) S->Seg->Size);
        }

        /* If this was the load memory area, mark the segment as dumped */
        if (S->Load == M) {
            S->Seg->Dumped = 1;
        }

        /* Calculate the new address */
        Addr += S->Seg->Size;
    }

    /* If a fill was requested, fill the remaining space */
    if ((M->Flags & MF_FILL) != 0 && M->FillLevel < M->Size) {
        unsigned long ToFill = M->Size - M->FillLevel;
        Print (stdout, 2, "    Filling 0x%lx bytes with 0x%02x\n",
               ToFill, M->FillVal);
        WriteMult (D->F, M->FillVal, ToFill);
        M->FillLevel = M->Size;
    }
}
Пример #2
0
void SegWrite (const char* TgtName, FILE* Tgt, Segment* S, SegWriteFunc F, void* Data)
/* Write the data from the given segment to a file. For expressions, F is
** called (see description of SegWriteFunc above).
*/
{
    unsigned      I;
    int           Sign;
    unsigned long Offs = 0;


    /* Remember the output file and offset for the segment */
    S->OutputName = TgtName;
    S->OutputOffs = (unsigned long) ftell (Tgt);

    /* Loop over all sections in this segment */
    for (I = 0; I < CollCount (&S->Sections); ++I) {

        Section*        Sec = CollAtUnchecked (&S->Sections, I);
        Fragment*       Frag;
        unsigned char   FillVal;

        /* Output were this section is from */
        Print (stdout, 2, "      Section from \"%s\"\n", GetObjFileName (Sec->Obj));

        /* If we have fill bytes, write them now. Beware: If this is the
        ** first section, the fill value is not considered part of the segment
        ** and therefore taken from the memory area.
        */
        FillVal = (I == 0)? S->MemArea->FillVal : S->FillVal;
        Print (stdout, 2, "        Filling 0x%lx bytes with 0x%02x\n",
               Sec->Fill, FillVal);
        WriteMult (Tgt, FillVal, Sec->Fill);
        Offs += Sec->Fill;

        /* Loop over all fragments in this section */
        Frag = Sec->FragRoot;
        while (Frag) {

            /* Output fragment data */
            switch (Frag->Type) {

                case FRAG_LITERAL:
                    WriteData (Tgt, Frag->LitBuf, Frag->Size);
                    break;

                case FRAG_EXPR:
                case FRAG_SEXPR:
                    Sign = (Frag->Type == FRAG_SEXPR);
                    /* Call the users function and evaluate the result */
                    switch (F (Frag->Expr, Sign, Frag->Size, Offs, Data)) {

                        case SEG_EXPR_OK:
                            break;

                        case SEG_EXPR_RANGE_ERROR:
                            Error ("Range error in module '%s', line %u",
                                   GetFragmentSourceName (Frag),
                                   GetFragmentSourceLine (Frag));
                            break;

                        case SEG_EXPR_TOO_COMPLEX:
                            Error ("Expression too complex in module '%s', line %u",
                                   GetFragmentSourceName (Frag),
                                   GetFragmentSourceLine (Frag));
                            break;

                        case SEG_EXPR_INVALID:
                            Error ("Invalid expression in module '%s', line %u",
                                   GetFragmentSourceName (Frag),
                                   GetFragmentSourceLine (Frag));
                            break;

                        default:
                            Internal ("Invalid return code from SegWriteFunc");
                    }
                    break;

                case FRAG_FILL:
                    WriteMult (Tgt, S->FillVal, Frag->Size);
                    break;

                default:
                    Internal ("Invalid fragment type: %02X", Frag->Type);
            }

            /* Update the offset */
            Print (stdout, 2, "        Fragment with 0x%x bytes\n",
                   Frag->Size);
            Offs += Frag->Size;

            /* Next fragment */
            Frag = Frag->Next;
        }
    }
}