/*                                                                          */

/* Copyright (c) 1998, 1999, 2000, 2001, 2002, Intel Corporation            */

/* All rights reserved.                                                     */

/*                                                                          */

/* WARRANTY DISCLAIMER                                                      */

/*                                                                          */

/* THESE MATERIALS ARE PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS   */

/* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT        */

/* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR    */

/* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR ITS      */

/* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,    */

/* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,      */

/* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR       */

/* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY      */

/* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR TORT (INCLUDING   */

/* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THESE      */

/* MATERIALS, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.            */

/*                                                                          */

/* Intel Corporation is the author of the Materials, and requests that all  */

/* problem reports or change requests be submitted to it directly at        */

/* http://developer.intel.com/opensource.                                   */

/*                                                                          */

/*

*******************************************************************************

*******************************************************************************

*/

#include "pe32.h"

#include <sys/types.h>

#include <time.h>

#include "endianess.h"

/* a structure that is used to hold all available sections and sort them */

/* by virtual address                                                    */

struct sec_vlist {

    PE32_section_object *sec;

    PE32_vaddr vaddr;

};

struct sg_vlist {

    PE32_secgrp_object *sg;

    PE32_vaddr vaddr;

};

static FUNC mfl_err PE32_write_pe_file_header (PE32_file_object *fod);

#ifdef PECOFF32_EM

static FUNC mfl_err PE32_64_write_pe_file_header (PE32_file_object *fod);

#endif

static FUNC mfl_err PE32_prepare_PE32_sections_and_write (PE32_file_object *fod);

static FUNC mfl_err PE32_write_one_coff_sec_content (PE32_file_object *pfobj,

                                                PE32_section_object *psecobj);

static FUNC mfl_err PE32_write_pe_sections (PE32_file_object *fod);

static FUNC mfl_err PE32_write_pe_section_header

    (PE32_file_object *fod, struct sg_vlist *secl);

static FUNC mfl_err PE32_write_internal_hdr (PE32_file_object *fod,

                                             int internal, ULONG charac,

                                             PE32_offset *file_ptr);

static FUNC mfl_err PE32_write_pe_section_content

    (PE32_file_object *fod, struct sg_vlist *secl);

static FUNC mfl_err PE32_write_basereloc (PE32_file_object *fod,

                                          struct sg_vlist *secl);

static FUNC mfl_err PE32_write_export_symbols (PE32_file_object *fod);

static FUNC mfl_err PE32_write_import_symbols (PE32_file_object *fod);

static FUNC mfl_err PE32_write_file_pad_align (PE32_file_object *fod,

                                               PE32_offset *file_ptr,

                                               PE32_align align);

static FUNC mfl_err PE32_write_file_pad_offset (PE32_file_object *fod,

                                                PE32_offset file_ptr,

                                                PE32_offset offset);

static FUNC mfl_err PE32_open_for_write (PE32_file_object *fod, mfl_str name);

static FUNC mfl_err PE32_calculate_image_size (PE32_file_object *pfobj);

static FUNC mfl_err PE32_prepare_coff_file_for_write (PE32_file_object *pfobj);

static FUNC mfl_err PE32_write_coff_file_header (PE32_file_object *pfobj);

static FUNC mfl_err PE32_write_coff_sec_header (PE32_file_object *pfobj);

static FUNC mfl_err PE32_write_coff_sec_content (PE32_file_object *pfobj);

static FUNC mfl_err PE32_write_coff_symtab_strtab (PE32_file_object *pfobj);

/****************************************************************************

 *                         PE32_write_file                                  *

 *                                                                          *

 * Write function for pe32 files                                            *

 ****************************************************************************/

FUNC mfl_err PE32_write_file (mfl_str name, mfl_od od)

{

    mfl_err error;

    PE32_file_object *fod;

    mfl_file_type file_type;

    fod = (PE32_file_object *)od;

    if ((error = PE32_open_for_write (fod, name)) != MFL_OK)

      return error;

    if (fod->mflfh.name != NULL)

        mfl_free (fod->mflfh.name);

    if ((fod->mflfh.name = mfl_malloc(strlen(name) +1)) == NULL)

        return MFL_ERR_NOT_ENOUGH_MEMORY;

    strcpy(fod->mflfh.name, name);

    if ((error = PE32_get_file_type(od,MFL_PROP_FILE_TYPE,NULL,&file_type)) != MFL_OK)

        return error;

    if (file_type == MFL_FILE_TYPE_DYN_EXEC || file_type == MFL_FILE_TYPE_SHARED)

    {

        if ((error = PE32_prepare_PE32_sections_and_write(fod)) != MFL_OK)

           return error;

        /*

        if ((error = PE32_write_pe_file_header (fod)) != MFL_OK)

            return error;

        if ((error = PE32_prepare_section_for_write(fod)) != MFL_OK) {

            return error;

        }

        if ((error = PE32_translate_coff_symtabs(pfobj)) != MFL_OK) {

            return error;

        }

        if ((error = PE32_write_pe_sections (fod)) != MFL_OK)

           return error;

        */

        if ((error = PE32_write_coff_symtab_strtab(fod)) != MFL_OK)

           return error;

     }

     else

     {

        /* Write Coff OMF file (relocatble files only ) */

        if (file_type == MFL_FILE_TYPE_RELOC)

        {

            if ((error = PE32_prepare_coff_file_for_write(fod)) != MFL_OK)

               return error;

            if ((error = PE32_write_coff_file_header(fod)) != MFL_OK)

               return error;

            if ((error = PE32_write_coff_sec_header(fod)) != MFL_OK)

               return error;

            if ((error = PE32_write_coff_sec_content(fod)) != MFL_OK)

               return error;

            if ((error = PE32_write_coff_symtab_strtab(fod)) != MFL_OK)

               return error;

        }

        else

          /* In the case of non support write file type */

          return MFL_ERR_INV_FILE_TYPE;

     }

    return MFL_OK;

}

static FUNC int cmpvv (const void *v1, const void *v2)

{

    return ((struct sec_vlist *)v1)->vaddr - ((struct sec_vlist *)v2)->vaddr;

}

/******************************************************************************

 *                      PE32_prepare_PE32_sections_and_write                  *

 * Prepare the PE32 file for writing and calculate the total size of the file

 * and the final place of all the tables (relocation tables symbol table and

 * string table).  Very similar to the PE32_prepare_coff_file_for_write.

 * The only difference is that the sections are sorted by their virtual addr,

 * and the section size is put into Ish->Misc.VirtualSize field of the section.

 ******************************************************************************/

static FUNC mfl_err PE32_prepare_PE32_sections_and_write (PE32_file_object *pfobj)

{

    mfl_err              error;

    mfl_32size           file_size, sec_size, aligned_sec_size;

    PE32_section_object  *psecobj;

    struct sec_vlist *scl;

    unsigned int i, sec_ind, sec_num, total_num_sec;

    /* create new COFF string table */

    if ((error = PE32_strtab_init(pfobj)) != MFL_OK) {

        return error;

    }

    /* Build Coff symbol table and string table */

    if ((error = PE32_translate_coff_symtabs(pfobj)) != MFL_OK) {

        return error;

    }

    /* build the sections list */

    sec_num = 0;

    total_num_sec = 0;

    psecobj = MFL_OD_FIRST;

    while ((psecobj = hash_get_next (pfobj->sec_ht, (mfl_hash_od)psecobj))

           != MFL_OD_END)

     {

        total_num_sec++;

        if (PE32_is_sec_mem_expand(psecobj) == FALSE)

            sec_num++;

        else

            /* In the case of .bss section */

            psecobj->Ish->PointerToRawData = 0;

     }

    sec_size = 0;

    file_size = pfobj->doshdr.e_lfanew +

                sizeof(pfobj->nthdr.Signature) +

                sizeof(IMAGE_FILE_HEADER) +

                pfobj->nthdr.FileHeader.SizeOfOptionalHeader;

    pfobj->nthdr.FileHeader.NumberOfSections = total_num_sec;

    file_size += total_num_sec * IMAGE_SIZEOF_SECTION_HEADER;

  if (sec_num > 0)

   {

    if ((scl = mfl_malloc(sec_num * sizeof(struct sec_vlist))) == NULL) {

        return MFL_ERR_NOT_ENOUGH_MEMORY;

    }

    sec_ind = 0;

    psecobj = MFL_OD_FIRST;

    while ((psecobj = hash_get_next (pfobj->sec_ht, (mfl_hash_od)psecobj))

           != MFL_OD_END)

     {

        if (PE32_is_sec_mem_expand(psecobj) == FALSE) {

            scl[sec_ind].sec = psecobj;

            scl[sec_ind].vaddr = PE32_section_vaddr(psecobj);

            sec_ind++;

        }

     }

    qsort(scl, sec_num, sizeof(struct sec_vlist), cmpvv);

    for (i=0; i< sec_num; i++)

     {

      psecobj = scl[i].sec;

      psecobj->Ish->PointerToRawData = file_size;

      file_size += PE32_section_size(psecobj);

      /* In sco the section get virtualAddress is the place of the section

        in the file. */

      if (pfobj->mflfh.company_style == MFL_COMP_STYLE_MICROFOCUS) {

            psecobj->Ish->VirtualAddress = sec_size;

        }

      aligned_sec_size = (PE32_section_size(psecobj) +

                          PE32_section_alignment(psecobj) - 1) &

                        ~(PE32_section_alignment(psecobj) - 1);

      psecobj->Ish->Misc.VirtualSize = PE32_section_size(psecobj);

      sec_size += PE32_section_size(psecobj);

      /* Transfer MOFL relocation table to COFF table and update the */

      /* relocation addend inside the section raw content.           */

#ifdef PECOFF32_EM

      if (pfobj->nthdr.FileHeader.Machine == IMAGE_FILE_MACHINE_TAHOE ||

          pfobj->nthdr.FileHeader.Machine == IMAGE_FILE_MACHINE_IA6432) {

            if ((error = PE32_trans_mofl_to_tahoe_reloc(psecobj)) != MFL_OK) {

                return error;

            }

        } else

#endif /* PECOFF32_EM */

        if ((error = PE32_trans_mofl_to_reloc(psecobj,

                    pfobj->nthdr.FileHeader.Machine)) != MFL_OK) {

            return error;

        }

      /* Prepare for lineinfo */

      if ((error = PE32_prepare_lineinfo_for_write(psecobj)) != MFL_OK) {

            return error;

      }

      if (psecobj->Ish->NumberOfLinenumbers > 0)

       {

        psecobj->Ish->PointerToLinenumbers = file_size;

        file_size += psecobj->Ish->NumberOfLinenumbers * IMAGE_SIZEOF_LINENUMBER;

       }

      else

       {

        psecobj->Ish->PointerToLinenumbers = 0;

       }

     }

   }

    /* compute data offset for the remaining sections */

    psecobj = MFL_OD_FIRST;

    while ((psecobj = hash_get_next (pfobj->sec_ht, (mfl_hash_od)psecobj))

           != MFL_OD_END)

     {

      if (PE32_is_sec_mem_expand(psecobj) == FALSE)

        continue;

      psecobj->Ish->PointerToRawData = file_size;

      file_size += PE32_section_size(psecobj);

      /* In sco the section get virtualAddress is the place of the section

        in the file. */

      if (pfobj->mflfh.company_style == MFL_COMP_STYLE_MICROFOCUS) {

            psecobj->Ish->VirtualAddress = sec_size;

        }

      aligned_sec_size = (PE32_section_size(psecobj) +

                          PE32_section_alignment(psecobj) - 1) &

                        ~(PE32_section_alignment(psecobj) - 1);

      psecobj->Ish->Misc.VirtualSize = PE32_section_size(psecobj);

      sec_size += PE32_section_size(psecobj);

      /* Transfer MOFL relocation table to COFF table and update the */

      /* relocation addend inside the section raw content.           */

#ifdef PECOFF32_EM

      if (pfobj->nthdr.FileHeader.Machine == IMAGE_FILE_MACHINE_TAHOE ||

          pfobj->nthdr.FileHeader.Machine == IMAGE_FILE_MACHINE_IA6432) {

            if ((error = PE32_trans_mofl_to_tahoe_reloc(psecobj)) != MFL_OK) {

                return error;

            }

        } else

#endif /* PECOFF32_EM */

        if ((error = PE32_trans_mofl_to_reloc(psecobj,

                        pfobj->nthdr.FileHeader.Machine)) != MFL_OK) {

            return error;

        }

      /* Prepare for lineinfo */

      if ((error = PE32_prepare_lineinfo_for_write(psecobj)) != MFL_OK) {

            return error;

      }

      if (psecobj->Ish->NumberOfLinenumbers > 0)

       {

        psecobj->Ish->PointerToLinenumbers = file_size;

        file_size += psecobj->Ish->NumberOfLinenumbers * IMAGE_SIZEOF_LINENUMBER;

       }

      else

       {

        psecobj->Ish->PointerToLinenumbers = 0;

       }

     }

    /* Update the Value field of all the define symbol in any section */

    if ((error = PE32_update_coff_symbol(pfobj)) != MFL_OK) {

        return error;

    }

    pfobj->nthdr.FileHeader.PointerToSymbolTable = file_size;

    file_size += pfobj->nthdr.FileHeader.NumberOfSymbols * IMAGE_SIZEOF_SYMBOL;

    file_size += pfobj->str_size;

    /* write the file */

    /* first, the header */

    if ((error = PE32_write_pe_file_header (pfobj)) != MFL_OK)

        return error;

    /* now, write the section headers */

    if ((error = PE32_write_coff_sec_header(pfobj)) != MFL_OK)

       return error;

    /* write the sections themselves */

    for (i=0; i< sec_num; i++)

     {

      psecobj = scl[i].sec;

      if ((error = PE32_write_one_coff_sec_content(pfobj, psecobj)) != MFL_OK)

        return error;

     }

    /* write the remaining sections */

    psecobj = MFL_OD_FIRST;

    while ((psecobj = hash_get_next (pfobj->sec_ht, (mfl_hash_od)psecobj))

           != MFL_OD_END)

     {

      if (PE32_is_sec_mem_expand(psecobj) == FALSE)

        continue;

      if ((error = PE32_write_one_coff_sec_content(pfobj, psecobj)) != MFL_OK)

        return error;

     }

    if (scl)

     {

        mfl_free(scl);

        scl = 0;

     }

    return MFL_OK;

}

/**************************************************************************************

 *                          PE32_prepare_coff_file_for_write                          *

 * Prepare the Coff file for writing and calculate the total size of the file and the *

 * final place of all the tables (relocation tables symbol table and string table ).  *

 **************************************************************************************/

static FUNC mfl_err PE32_prepare_coff_file_for_write (PE32_file_object *pfobj)

{

    mfl_err              error;

    mfl_32size           file_size, sec_size;

    PE32_section_object  *psecobj;

    /* create new COFF string table */

    if ((error = PE32_strtab_init(pfobj)) != MFL_OK) {

        return error;

    }

    /* Build the Coff section list */

    if ((error = PE32_prepare_section_for_write(pfobj)) != MFL_OK) {

        return error;

    }

    /* Build Coff symbol table and string table */

    if ((error = PE32_translate_coff_symtabs(pfobj)) != MFL_OK) {

        return error;

    }

    /* Find the file size and the symbol table place */

    file_size = IMAGE_SIZEOF_FILE_HEADER;

    file_size += pfobj->nthdr.FileHeader.NumberOfSections * IMAGE_SIZEOF_SECTION_HEADER;

    sec_size = 0;

    psecobj = MFL_OD_FIRST;

    while ((psecobj = hash_get_next (pfobj->sec_ht, (mfl_hash_od)psecobj))

           != MFL_OD_END) {

        if (PE32_is_sec_mem_expand(psecobj) == FALSE) {

            psecobj->Ish->PointerToRawData = file_size;

            file_size += PE32_section_size(psecobj);

        } else {

            /* In the case of .bss section */

            psecobj->Ish->PointerToRawData = 0;

        }

        /* In sco the section get virtualAddress is the place of the section in the file. */

        if (pfobj->mflfh.company_style == MFL_COMP_STYLE_MICROFOCUS) {

            psecobj->Ish->VirtualAddress = sec_size;

        }

        psecobj->Ish->Misc.VirtualSize = 0;

#if 0

        psecobj->Ish->Misc.PhysicalAddress = sec_size;

#endif /* 0 */

        sec_size += PE32_section_size(psecobj);

        /* Transfer MOFL relocation table to COFF table and update the */

        /* relocation addend inside the section raw content.           */

#ifdef PECOFF32_EM

        if (pfobj->nthdr.FileHeader.Machine == IMAGE_FILE_MACHINE_TAHOE ||

            pfobj->nthdr.FileHeader.Machine == IMAGE_FILE_MACHINE_IA6432) {

            if ((error = PE32_trans_mofl_to_tahoe_reloc(psecobj)) != MFL_OK) {

                return error;

            }

        } else

#endif /* PECOFF32_EM */

        if ((error = PE32_trans_mofl_to_reloc(psecobj,

                        pfobj->nthdr.FileHeader.Machine)) != MFL_OK) {

            return error;

        }

    /* In the GNT architecture the section raw content should come in one piece.*/

    /* Set the pointer of the relocation table in the output file. */

    if (mfl_od_omf(pfobj) != MFL_OMF_GNT32)

     {

      mfl_rel_num num_of_relocs = psecobj->relocations_num;

      if (num_of_relocs > 0)

       {

        psecobj->Ish->PointerToRelocations = file_size;

        file_size += num_of_relocs * IMAGE_SIZEOF_RELOCATION;

        if (num_of_relocs > USHRT_MAX)

         {

          /* too much relocations? For Microsoft formats the number of relocs */

          /* is written as the 1st relocation, see winnt.h, line 3931 */

          file_size += IMAGE_SIZEOF_RELOCATION;

         }

       }

      else

       {

        psecobj->Ish->PointerToRelocations = 0;

       }

     }

        /* Prepare for lineinfo */

        if ((error = PE32_prepare_lineinfo_for_write(psecobj)) != MFL_OK) {

            return error;

        }

        if (psecobj->Ish->NumberOfLinenumbers > 0) {

            psecobj->Ish->PointerToLinenumbers = file_size;

            file_size += psecobj->Ish->NumberOfLinenumbers * IMAGE_SIZEOF_LINENUMBER;

        } else {

            psecobj->Ish->PointerToLinenumbers = 0;

        }

    }

    /* In the GNT architecture the section raw content should come in one piece. */

    /* Set the pointer of the relocation table in the output file. */

    if (mfl_od_omf(pfobj) == MFL_OMF_GNT32) {

        psecobj = MFL_OD_FIRST;

        while ((psecobj = hash_get_next (pfobj->sec_ht, (mfl_hash_od)psecobj)) != MFL_OD_END) {

            if (psecobj->Ish->NumberOfRelocations > 0) {

                psecobj->Ish->PointerToRelocations = file_size;

                file_size += psecobj->Ish->NumberOfRelocations * IMAGE_SIZEOF_RELOCATION;

            } else {

                psecobj->Ish->PointerToRelocations = 0;

            }

        }

    }

    /* Update the Value field of all the define symbol in any section */

    if ((error = PE32_update_coff_symbol(pfobj)) != MFL_OK) {

        return error;

    }

    pfobj->nthdr.FileHeader.PointerToSymbolTable = file_size;

    file_size += pfobj->nthdr.FileHeader.NumberOfSymbols * IMAGE_SIZEOF_SYMBOL;

    file_size += pfobj->str_size;

    return MFL_OK;

}

/******************************************************************************

 *                      PE32_write_coff_file_header                           *

 *                                                                            *

 * Write the COFF file header.                                                *

 ******************************************************************************/

static FUNC mfl_err PE32_write_coff_file_header (PE32_file_object *pfobj)

{

    mfl_err error;

#ifdef PECOFF32_EM

    if (mfl_od_omf(pfobj) == MFL_OMF_PE3264 ||

        (mfl_od_omf(pfobj) == MFL_OMF_COFF32 &&

         pfobj->nthdr.FileHeader.Machine == IMAGE_FILE_MACHINE_IA6432 &&

         (pfobj->nthdr.FileHeader.Characteristics & IMAGE_FILE_LARGE_ADDRESS_AWARE)))

     {

      pfobj->nthdr.FileHeader.Characteristics &= ~(WORD)IMAGE_FILE_32BIT_MACHINE;

      pfobj->nthdr.FileHeader.Characteristics |= IMAGE_FILE_LARGE_ADDRESS_AWARE;

      pfobj->nthdr.FileHeader.TimeDateStamp = time (NULL);

     }

    else

     {

      pfobj->nthdr.FileHeader.Characteristics &= ~(WORD)IMAGE_FILE_32BIT_MACHINE;

      pfobj->nthdr.FileHeader.Characteristics &= ~(WORD)IMAGE_FILE_LARGE_ADDRESS_AWARE;

      pfobj->nthdr.FileHeader.TimeDateStamp = time (NULL);

     }

     if (mfl_od_omf(pfobj) == MFL_OMF_COFF32)

     {

        pfobj->nthdr.FileHeader.Characteristics &= ~(WORD)IMAGE_FILE_LARGE_ADDRESS_AWARE;

     }

#endif /* PECOFF32_EM */

    PE32_swap_filehdr(&pfobj->nthdr.FileHeader);

    /* Write the COFF file header */

    if ((error = mfl_write(&pfobj->nthdr.FileHeader, IMAGE_SIZEOF_FILE_HEADER, (mfl_file_obj *)pfobj)) != MFL_OK) {

        return error;

    }

    /* Restore file header */

    PE32_swap_filehdr(&pfobj->nthdr.FileHeader);

    return MFL_OK;

}

/******************************************************************************

 *                      PE32_write_coff_sec_header                            *

 *                                                                            *

 * Write Coff section header table                                            *

 ******************************************************************************/

static FUNC mfl_err PE32_write_coff_sec_header (PE32_file_object *pfobj)

{

    mfl_err             error;

    PE32_section_object *psecobj;

    psecobj = MFL_OD_FIRST;

    while ((psecobj = hash_get_next (pfobj->sec_ht, (mfl_hash_od)psecobj)) != MFL_OD_END) {

        if (IMAGE_SCN_CNT_CODE & psecobj->Ish->Characteristics) {

            psecobj->Ish->Characteristics &=

                ~(IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_CNT_UNINITIALIZED_DATA);

            psecobj->Ish->Characteristics |= (IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ);

        } else if (IMAGE_SCN_CNT_INITIALIZED_DATA & psecobj->Ish->Characteristics) {

            psecobj->Ish->Characteristics &= ~IMAGE_SCN_CNT_UNINITIALIZED_DATA;

        } else if ((IMAGE_SCN_CNT_UNINITIALIZED_DATA & psecobj->Ish->Characteristics) == 0) {

            if (IMAGE_SCN_MEM_EXECUTE & psecobj->Ish->Characteristics) {

                psecobj->Ish->Characteristics |= IMAGE_SCN_CNT_CODE;

            } else if (IMAGE_SCN_MEM_READ & psecobj->Ish->Characteristics) {

                psecobj->Ish->Characteristics |= IMAGE_SCN_CNT_INITIALIZED_DATA;

            }

        }

#ifdef DUMMY_CODE

        /* Copied from PE32_set_sec_rt_attr() */

        if (IMAGE_SCN_MEM_EXECUTE & psecobj->Ish->Characteristics) {

            psecobj->Ish->Characteristics &= ~IMAGE_SCN_CNT_INITIALIZED_DATA;

        } else if (IMAGE_SCN_MEM_READ & psecobj->Ish->Characteristics) {

            psecobj->Ish->Characteristics &= ~IMAGE_SCN_CNT_CODE;

        }

#endif /* DUMMY_CODE */

    if (psecobj->relocations_num > USHRT_MAX)

     {/* too much relocations */

      psecobj->Ish->Characteristics |= IMAGE_SCN_LNK_NRELOC_OVFL;

      psecobj->Ish->NumberOfRelocations = USHRT_MAX;

     }

        PE32_swap_shdr(psecobj->Ish);

        if ((error = mfl_write(psecobj->Ish, IMAGE_SIZEOF_SECTION_HEADER, (mfl_file_obj *)pfobj)) != MFL_OK) {

            return error;

        }

        /* Restore section header */

        PE32_swap_shdr(psecobj->Ish);

    }

    return MFL_OK;

}

/********************************************************************************

 *                     PE32_write_one_sec_content                               *

 *                                                                              *

 * Write Coff section's raw content and the section's relocation table.         *

 * Before the writing check if the calculation process is correct.              *

 *******************************************************************************/

static FUNC mfl_err PE32_write_one_coff_sec_content (PE32_file_object *pfobj,

                                                PE32_section_object *psecobj)

{

 mfl_err            error;

 mfl_file_off       foff;

 mfl_rel_num        num_of_relocs;

 IMAGE_RELOCATION   first_reloc;

  /* Write the section raw content if for non .bss section */

  if (PE32_is_sec_mem_expand(psecobj) == FALSE)

   {

    /* Check that the file calculation is correct */

    if ((error = mfl_tell((mfl_file_obj *)pfobj, &foff)) != MFL_OK)

            return error;

    if (foff != psecobj->Ish->PointerToRawData)

            return MFL_ERR_INTERNAL;

    if ((error = mfl_write(psecobj->content, PE32_section_size(psecobj),

                            (mfl_file_obj *)pfobj)) != MFL_OK)

            return error;

   }

  /* In the GNT architecture the section raw content should come in one piece.*/

  if (mfl_od_omf(pfobj) != MFL_OMF_GNT32)

   {

    /* write the section relocation table if exist */

    num_of_relocs = psecobj->relocations_num;

    if (num_of_relocs > 0)

     {

      /* Check that the file calculation is correct */

      if ((error = mfl_tell((mfl_file_obj *)pfobj, &foff)) != MFL_OK)

                return error;

      if (foff != psecobj->Ish->PointerToRelocations)

                return MFL_ERR_INTERNAL;

      if (num_of_relocs > USHRT_MAX)

       {

        /* too much relocations? For Microsoft formats the number of relocs */

        /* is written as the 1st relocation, see winnt.h, line 3931 */

        first_reloc.VirtualAddress = num_of_relocs;

        first_reloc.SymbolTableIndex = 0;

        first_reloc.Type = 0;

        if ((error = mfl_write(&first_reloc,

                               IMAGE_SIZEOF_RELOCATION,

                               (mfl_file_obj *)pfobj)) != MFL_OK)

                        return error;

       }

      if (IMAGE_SIZEOF_RELOCATION == sizeof(IMAGE_RELOCATION))

       {

        if ((error = mfl_write(psecobj->prblock,

                               (mfl_32size)num_of_relocs *

                                    IMAGE_SIZEOF_RELOCATION,

                               (mfl_file_obj *)pfobj)) != MFL_OK)

                    return error;

       }

      else

       {

        WORD i;

        for (i = 0; i < num_of_relocs; ++i)

         {

          if ((error = mfl_write(psecobj->prblock + i,

                                 IMAGE_SIZEOF_RELOCATION,

                                 (mfl_file_obj *)pfobj)) != MFL_OK)

                        return error;

         }

       }

     }

   }

  /* Write lineinfo if exist */

  if (psecobj->Ish->NumberOfLinenumbers > 0)

   {

    /* Check that the file calculation is correct */

    if ((error = mfl_tell((mfl_file_obj *)pfobj, &foff)) != MFL_OK)

            return error;

    if (foff != psecobj->Ish->PointerToLinenumbers)

            return MFL_ERR_INTERNAL;

    if ((error = mfl_write(psecobj->lineinfo,

                           (mfl_32size)psecobj->Ish->NumberOfLinenumbers *

                                IMAGE_SIZEOF_LINENUMBER,

                           (mfl_file_obj *)pfobj)) != MFL_OK)

            return error;

   }

    /* In the GNT architecture the section raw content should come in one piece.*/

    if (mfl_od_omf(pfobj) == MFL_OMF_GNT32) {

        psecobj = MFL_OD_FIRST;

        while ((psecobj = hash_get_next(pfobj->sec_ht, (mfl_hash_od)psecobj)) != MFL_OD_END) {

            /* write the section relocation table if exist */

            if (psecobj->Ish->NumberOfRelocations > 0) {

                /* Check that the file calculation is correct */

                if ((error = mfl_tell((mfl_file_obj *)pfobj,&foff)) != MFL_OK) {

                    return error;

                }

                if (foff != psecobj->Ish->PointerToRelocations) {

                    return MFL_ERR_INTERNAL;

                }

                if (IMAGE_SIZEOF_RELOCATION == sizeof(IMAGE_RELOCATION)) {

                    if ((error = mfl_write(psecobj->prblock,

                                           (mfl_32size)psecobj->Ish->NumberOfRelocations * IMAGE_SIZEOF_RELOCATION,

                                           (mfl_file_obj *)pfobj)) != MFL_OK) {

                        return error;

                    }

                } else {

                    WORD i;

                    for (i = 0; i < psecobj->Ish->NumberOfRelocations; ++i) {

                        if ((error = mfl_write(psecobj->prblock + i, IMAGE_SIZEOF_RELOCATION, (mfl_file_obj *)pfobj)) != MFL_OK) {

                            return error;

                        }

                    }

                }

            }

        }

    }

    return MFL_OK;

}

/*********************************************************************************

 *                     PE32_write_coff_sec_content                               *

 *                                                                               *

 * Write Coff sections' raw content and the sections' relocation table.          *

 * Before the writing check if the calculation process is correct.               *

 *********************************************************************************/

static FUNC mfl_err PE32_write_coff_sec_content (PE32_file_object *pfobj)

{

    mfl_err             error;

    PE32_section_object *psecobj;

    mfl_file_off        foff;

    mfl_rel_num         num_of_relocs;

    IMAGE_RELOCATION    first_reloc;

    psecobj = MFL_OD_FIRST;

  while ((psecobj = hash_get_next(pfobj->sec_ht, (mfl_hash_od)psecobj)) != MFL_OD_END) {

        /* Write the section raw content if for non .bss section */

        if (PE32_is_sec_mem_expand(psecobj) == FALSE) {

            /* Check that the file calculation is correct */

            if ((error = mfl_tell((mfl_file_obj *)pfobj, &foff)) != MFL_OK) {

                return error;

            }

            if (foff != psecobj->Ish->PointerToRawData) {

                return MFL_ERR_INTERNAL;

            }

            if ((error = mfl_write(psecobj->content, PE32_section_size(psecobj), (mfl_file_obj *)pfobj)) != MFL_OK) {

                return error;

            }

        }

    /* In the GNT architecture the section raw content should come in one piece.*/

    if (mfl_od_omf(pfobj) != MFL_OMF_GNT32)

     {

      /* write the section relocation table if exist */

      num_of_relocs = psecobj->relocations_num;

      if (num_of_relocs > 0)

       {

        /* Check that the file calculation is correct */

        if ((error = mfl_tell((mfl_file_obj *)pfobj, &foff)) != MFL_OK)

                    return error;

        if (foff != psecobj->Ish->PointerToRelocations)

                    return MFL_ERR_INTERNAL;

       if (num_of_relocs > USHRT_MAX)

        {

         /* too much relocations? For Microsoft formats the number of relocs */

         /* is written as the 1st relocation, see winnt.h, line 3931 */

         first_reloc.VirtualAddress = num_of_relocs;

         first_reloc.SymbolTableIndex = 0;

         first_reloc.Type = 0;

         if ((error = mfl_write(&first_reloc,

                                IMAGE_SIZEOF_RELOCATION,

                                (mfl_file_obj *)pfobj)) != MFL_OK)

                        return error;

        }

        if (IMAGE_SIZEOF_RELOCATION == sizeof(IMAGE_RELOCATION))

         {

          if ((error = mfl_write(psecobj->prblock,

                                 (mfl_32size)num_of_relocs *

                                    IMAGE_SIZEOF_RELOCATION,

                                 (mfl_file_obj *)pfobj)) != MFL_OK)

                        return error;

         }

        else

         {

          WORD i;

          for (i = 0; i < num_of_relocs; ++i)

           {

            if ((error = mfl_write(psecobj->prblock + i,

                                   IMAGE_SIZEOF_RELOCATION,

                                   (mfl_file_obj *)pfobj)) != MFL_OK)

                            return error;

           }

         }

       }

     }

        /* Write lineinfo if exist */

        if (psecobj->Ish->NumberOfLinenumbers > 0) {

            /* Check that the file calculation is correct */

            if ((error = mfl_tell((mfl_file_obj *)pfobj, &foff)) != MFL_OK) {

                return error;

            }

            if (foff != psecobj->Ish->PointerToLinenumbers) {

                return MFL_ERR_INTERNAL;

            }

            if ((error = mfl_write(psecobj->lineinfo,

                                   (mfl_32size)psecobj->Ish->NumberOfLinenumbers * IMAGE_SIZEOF_LINENUMBER,

                                   (mfl_file_obj *)pfobj)) != MFL_OK) {

                return error;

            }

        }

    }

    /* In the GNT architectura the section rawconten shuld come in one piece. */

    if (mfl_od_omf(pfobj) == MFL_OMF_GNT32) {

        psecobj = MFL_OD_FIRST;

        while ((psecobj = hash_get_next(pfobj->sec_ht, (mfl_hash_od)psecobj)) != MFL_OD_END) {

            /* write the section relocation table if exist */

            if (psecobj->Ish->NumberOfRelocations > 0) {

                /* Check that the file calculation is correct */

                if ((error = mfl_tell((mfl_file_obj *)pfobj,&foff)) != MFL_OK) {

                    return error;

                }

                if (foff != psecobj->Ish->PointerToRelocations) {

                    return MFL_ERR_INTERNAL;

                }

                if (IMAGE_SIZEOF_RELOCATION == sizeof(IMAGE_RELOCATION)) {

                    if ((error = mfl_write(psecobj->prblock,

                                           (mfl_32size)psecobj->Ish->NumberOfRelocations * IMAGE_SIZEOF_RELOCATION,

                                           (mfl_file_obj *)pfobj)) != MFL_OK) {

                        return error;

                    }

                } else {

                    WORD i;

                    for (i = 0; i < psecobj->Ish->NumberOfRelocations; ++i) {

                        if ((error = mfl_write(psecobj->prblock + i, IMAGE_SIZEOF_RELOCATION, (mfl_file_obj *)pfobj)) != MFL_OK) {

                            return error;

                        }

                    }

                }

            }

        }

    }

    return MFL_OK;

}

/***************************************************************************************

 *                           PE32_write_coff_symtab_strtab                             *

 *                                                                                     *

 * Write the Coff symbol table and the Coff string table after the symbol table.       *

 ***************************************************************************************/

static FUNC mfl_err PE32_write_coff_symtab_strtab (PE32_file_object *pfobj)

{

    mfl_err      error;

    mfl_file_off foff;

    /* Check that the file calculation is correct */

    if ((error = mfl_tell((mfl_file_obj *)pfobj, &foff)) != MFL_OK) {

        return error;

    }

    if ((unsigned)pfobj->nthdr.FileHeader.PointerToSymbolTable != foff) {

        return MFL_ERR_INTERNAL;

    }

    /* Write the Coff symbol table */

    if (IMAGE_SIZEOF_SYMBOL == sizeof(IMAGE_SYMBOL)) {

        if ((error = mfl_write(pfobj->Coffsym,

                               pfobj->nthdr.FileHeader.NumberOfSymbols * IMAGE_SIZEOF_SYMBOL,

                               (mfl_file_obj *)pfobj)) != MFL_OK) {

            return error;

        }

    } else {

        DWORD i;

        for (i = 0; i < pfobj->nthdr.FileHeader.NumberOfSymbols; ++i) {

            if ((error = mfl_write(pfobj->Coffsym + i, IMAGE_SIZEOF_SYMBOL, (mfl_file_obj *)pfobj)) != MFL_OK) {

                return error;

            }

        }

    }

    /* Write the Coff string table */

    *(UINT *)pfobj->strtab = mfl_endian_select_int(*(UINT *)pfobj->strtab, 0);

    if ((error = mfl_write(pfobj->strtab, pfobj->str_size, (mfl_file_obj *)pfobj)) != MFL_OK) {

        return error;

    }

    *(UINT *)pfobj->strtab = mfl_endian_select_int(*(UINT *)pfobj->strtab, 0);

    return MFL_OK;

}

#ifdef PECOFF32_EM

/****************************************************************************

 *                      PE32_64_write_pe_file_header                        *

 *                                                                          *

 * Write file headers                                                       *

 ****************************************************************************/

static FUNC mfl_err PE32_64_write_pe_file_header (PE32_file_object *fod)

{

    mfl_err error;

    if (fod->nthdr.OptionalHeader.pe3264.SectionAlignment < PE32_I386_PAGE_SIZE) {

        fod->nthdr.OptionalHeader.pe3264.SectionAlignment = PE32_I386_PAGE_SIZE;

    }

    if (fod->nthdr.OptionalHeader.pe3264.SectionAlignment >=

        ((fod->nthdr.FileHeader.Machine == IMAGE_FILE_MACHINE_TAHOE) ||

         (fod->nthdr.FileHeader.Machine == IMAGE_FILE_MACHINE_IA64) ?

            PE32_EM_PAGE_SIZE : PE32_I386_PAGE_SIZE)

       ) {

        PE32_file_align(fod) = PE32_SECTOR_SIZE;

    } else {

        PE32_file_align(fod) = fod->nthdr.OptionalHeader.pe3264.SectionAlignment;

    }

    if ((error = mfl_write(&fod->doshdr, sizeof(fod->doshdr), (mfl_file_obj *)fod))

            != MFL_OK) {

        return error;

    }

    if ((error = PE32_write_file_pad_offset(fod, sizeof(fod->doshdr), (ULONG)fod->doshdr.e_lfanew)) != MFL_OK) {

        return error;

    }

    fod->nthdr.Signature = IMAGE_NT_SIGNATURE;

    fod->nthdr.FileHeader.Characteristics |= IMAGE_FILE_LARGE_ADDRESS_AWARE;

    fod->nthdr.FileHeader.Characteristics &= ~IMAGE_FILE_32BIT_MACHINE;

    fod->nthdr.FileHeader.NumberOfSections = (USHORT)PE32_file_get_sec_num(fod);

    fod->nthdr.FileHeader.TimeDateStamp = time (NULL);

    fod->nthdr.FileHeader.SizeOfOptionalHeader = IMAGE_SIZEOF_NT_OPTIONAL_HEADER_PE3264;

    fod->nthdr.FileHeader.Characteristics |= IMAGE_FILE_BYTES_REVERSED_LO |

        IMAGE_FILE_LOCAL_SYMS_STRIPPED | IMAGE_FILE_LINE_NUMS_STRIPPED;

    /* set the pe header virsions */

    fod->nthdr.OptionalHeader.pe3264.Magic = PE3264_NT_HEADER_MAGIC;

    fod->nthdr.OptionalHeader.pe3264.MajorLinkerVersion = VER_MAJOR;

    fod->nthdr.OptionalHeader.pe3264.MinorLinkerVersion = VER_MINOR;

    fod->nthdr.OptionalHeader.pe3264.MajorOperatingSystemVersion = PE32_MAJOR_OS_VERSION;

    fod->nthdr.OptionalHeader.pe3264.MinorOperatingSystemVersion = PE32_MINOR_OS_VERSION;

    fod->nthdr.OptionalHeader.pe3264.MajorImageVersion = PE32_MAJOR_IMAGE_VERSION;

    fod->nthdr.OptionalHeader.pe3264.MinorImageVersion = PE32_MINOR_IMAGE_VERSION;

    fod->nthdr.OptionalHeader.pe3264.MajorSubsystemVersion = PE32_MAJOR_SUBSYS_VERSION;

    fod->nthdr.OptionalHeader.pe3264.MinorSubsystemVersion = PE32_MINOR_SUBSYS_VERSION;

                                        /* calculate file header size */

                                        /* header size + section header table size */

    fod->nthdr.OptionalHeader.pe3264.SizeOfHeaders = (fod->doshdr.e_lfanew + sizeof(fod->nthdr.Signature) +

                sizeof (IMAGE_FILE_HEADER) + IMAGE_SIZEOF_NT_OPTIONAL_HEADER_PE3264 +

                sizeof (IMAGE_SECTION_HEADER) * PE32_file_sec_num (fod)

                /* aligned to file alignment */

                + PE32_file_align (fod) -1) & ~(PE32_file_align (fod) -1);

    PE32_file_get_grouped_size(fod);

    /* calculate the image size */

    if ((error = PE32_calculate_image_size(fod)) != MFL_OK) {

        return error;

    }

    /* set in the file header table the address and the size of the PE spacial */

    /* section like .rsrc , .debug                                             */

    if ((error = PE32_set_ft_spacial_sec(fod)) != MFL_OK) {

        return error;

    }

    fod->nthdr.OptionalHeader.pe3264.NumberOfRvaAndSizes = IMAGE_NUMBEROF_DIRECTORY_ENTRIES;

#ifdef BIG_ENDIAN

    /* patch the fields */

    {IMAGE_NT_HEADERS_PE3264 nt_header;

     nt_header = fod->nthdr;

     mfl_int_swap((int *)&nt_header.Signature);

     PE32_swap_filehdr(&nt_header.FileHeader);

     PE32_swap_pehdr(NULL, &nt_header);

     error = mfl_write(&nt_header, sizeof(nt_header), (mfl_file_obj *)fod);

     /* swap the headers back */

     mfl_int_swap((int *)&nt_header.Signature);

     PE32_swap_filehdr(&nt_header.FileHeader);

     PE32_swap_pehdr(NULL, &nt_header);

    }

#else

    error = mfl_write(&fod->nthdr, sizeof(fod->nthdr), (mfl_file_obj *)fod);

#endif

    if (error == MFL_OK) {

        error = PE32_write_file_pad_offset (fod, fod->doshdr.e_lfanew +

                                            sizeof(fod->nthdr),

                                            fod->doshdr.e_lfanew +

                                            sizeof(fod->nthdr.Signature) +

                                            sizeof(IMAGE_FILE_HEADER) +

                                            IMAGE_SIZEOF_NT_OPTIONAL_HEADER_PE3264);

    }

    return error;

}

#endif /* PECOFF32_EM */

/****************************************************************************

 *                      PE32_write_pe_file_header                           *

 *                                                                          *

 * Write file headers                                                       *

 ****************************************************************************/

static FUNC mfl_err PE32_write_pe_file_header (PE32_file_object *fod)

{

    mfl_err error;

#ifdef PECOFF32_EM

    if (mfl_od_omf(fod) == MFL_OMF_PE3264)

        return PE32_64_write_pe_file_header(fod);

#endif /* PECOFF32_EM */

    if (fod->nthdr.OptionalHeader.pe32.SectionAlignment < PE32_SECTOR_SIZE) {

        fod->nthdr.OptionalHeader.pe32.SectionAlignment = PE32_SECTOR_SIZE;

    }

    if (fod->nthdr.OptionalHeader.pe32.SectionAlignment >=

#ifdef PECOFF32_EM

        ((fod->nthdr.FileHeader.Machine == IMAGE_FILE_MACHINE_TAHOE ||

          fod->nthdr.FileHeader.Machine == IMAGE_FILE_MACHINE_IA6432) ?

        PE32_EM_PAGE_SIZE : PE32_I386_PAGE_SIZE)

#else  /* PECOFF32_EM */

        PE32_I386_PAGE_SIZE

#endif /* PECOFF32_EM */

       ) {

        PE32_file_align(fod) = PE32_SECTOR_SIZE;

    } else {

        PE32_file_align(fod) = fod->nthdr.OptionalHeader.pe32.SectionAlignment;

    }

    if ((error = mfl_write(&fod->doshdr, sizeof(fod->doshdr), (mfl_file_obj *)fod)) != MFL_OK) {

        return error;

    }

    if ((error = PE32_write_file_pad_offset(fod, sizeof(fod->doshdr), (ULONG)fod->doshdr.e_lfanew)) != MFL_OK) {

        return error;

    }

#ifdef PECOFF32_EM

    fod->nthdr.FileHeader.Characteristics |= IMAGE_FILE_32BIT_MACHINE;

    fod->nthdr.FileHeader.Characteristics &= ~(WORD)IMAGE_FILE_LARGE_ADDRESS_AWARE;

#else  /* PECOFF32_EM */

/*  fod->nthdr.FileHeader.Machine = IMAGE_FILE_MACHINE_I386; */

    fod->nthdr.FileHeader.Characteristics |= IMAGE_FILE_32BIT_MACHINE;

#endif /* PECOFF32_EM */

    fod->nthdr.FileHeader.NumberOfSections = (USHORT)PE32_file_get_sec_num(fod);

    fod->nthdr.FileHeader.TimeDateStamp = time (NULL);

    fod->nthdr.FileHeader.SizeOfOptionalHeader = IMAGE_SIZEOF_NT_OPTIONAL_HEADER;

    fod->nthdr.FileHeader.Characteristics |= IMAGE_FILE_BYTES_REVERSED_LO |

        IMAGE_FILE_LOCAL_SYMS_STRIPPED | IMAGE_FILE_LINE_NUMS_STRIPPED;

    /* set the pe header virsions */

    fod->nthdr.OptionalHeader.pe32.Magic = PE32_NT_HEADER_MAGIC;

    fod->nthdr.OptionalHeader.pe32.MajorLinkerVersion = VER_MAJOR;

    fod->nthdr.OptionalHeader.pe32.MinorLinkerVersion = VER_MINOR;

    fod->nthdr.OptionalHeader.pe32.MajorOperatingSystemVersion = PE32_MAJOR_OS_VERSION;

    fod->nthdr.OptionalHeader.pe32.MinorOperatingSystemVersion = PE32_MINOR_OS_VERSION;

    fod->nthdr.OptionalHeader.pe32.MajorImageVersion = PE32_MAJOR_IMAGE_VERSION;

    fod->nthdr.OptionalHeader.pe32.MinorImageVersion = PE32_MINOR_IMAGE_VERSION;

    fod->nthdr.OptionalHeader.pe32.MajorSubsystemVersion = PE32_MAJOR_SUBSYS_VERSION;

    fod->nthdr.OptionalHeader.pe32.MinorSubsystemVersion = PE32_MINOR_SUBSYS_VERSION;

                                        /* calculate file header size */

                                        /* header size + section header table size */

    fod->nthdr.OptionalHeader.pe32.SizeOfHeaders = (fod->doshdr.e_lfanew + sizeof(fod->nthdr.Signature) +

                sizeof (IMAGE_FILE_HEADER) + IMAGE_SIZEOF_NT_OPTIONAL_HEADER +

                sizeof (IMAGE_SECTION_HEADER) * PE32_file_sec_num (fod)

                /* aligned to file alignment */

                + PE32_file_align (fod) -1) & ~(PE32_file_align (fod) -1);

    PE32_file_get_grouped_size(fod);

    /* calculate the image size */

    if ((error = PE32_calculate_image_size(fod)) != MFL_OK) {

        return error;

    }

    /* set in the file header table the address and the size of the PE spacial */

    /* section like .rsrc , .debug                                             */

    if ((error = PE32_set_ft_spacial_sec(fod)) != MFL_OK) {

        return error;

    }

    fod->nthdr.OptionalHeader.pe32.NumberOfRvaAndSizes = IMAGE_NUMBEROF_DIRECTORY_ENTRIES;

    /* write only the PE32 header */

#ifdef BIG_ENDIAN

    /* patch the fields */

    {IMAGE_NT_HEADERS_PE3264 nt_header;

     nt_header = fod->nthdr;

     mfl_int_swap((int *)&nt_header.Signature);

     PE32_swap_filehdr(&nt_header.FileHeader);

     PE32_swap_pehdr(NULL, &nt_header);

     error = mfl_write(&nt_header, sizeof(nt_header.Signature) +

                                    sizeof(IMAGE_FILE_HEADER),

                        (mfl_file_obj *)fod);

     if (error == MFL_OK)

        error = mfl_write(&nt_header.OptionalHeader.pe32,

                            sizeof(nt_header.OptionalHeader.pe32),

                            (mfl_file_obj *)fod);

     /* swap the headers back */

     mfl_int_swap((int *)&nt_header.Signature);

     PE32_swap_filehdr(&nt_header.FileHeader);

     PE32_swap_pehdr(NULL, &nt_header);

    }

#else

    error = mfl_write(&fod->nthdr, sizeof(fod->nthdr.Signature) +

                                    sizeof(IMAGE_FILE_HEADER),

                        (mfl_file_obj *)fod);

    if (error == MFL_OK)

        error = mfl_write(&fod->nthdr.OptionalHeader.pe32,

                            sizeof(fod->nthdr.OptionalHeader.pe32),

                            (mfl_file_obj *)fod);

#endif

    if (error == MFL_OK) {

        error = PE32_write_file_pad_offset (fod, fod->doshdr.e_lfanew +

                                            sizeof(fod->nthdr.Signature) +

                                            sizeof(IMAGE_FILE_HEADER) +

                                            IMAGE_SIZEOF_NT_OPTIONAL_HEADER,

                                            fod->doshdr.e_lfanew +

                                            sizeof(fod->nthdr.Signature) +

                                            sizeof(IMAGE_FILE_HEADER) +

                                            IMAGE_SIZEOF_NT_OPTIONAL_HEADER);

    }

    return error;

}

/***************************************************************************/

/*                       PE32_calculate_image_size                         */

/*                                                                         */

/* Calculate the size of the image file that load to the memory in the run */

/* time                                                                    */

/***************************************************************************/

static FUNC mfl_err PE32_calculate_image_size (PE32_file_object *pfobj)

{

    PE32_secgrp_object *psecgobj;

    PE32_size          image_size = 0;

    PE32_size          sg_image;

    int                idx;

    /* In the meantime we assume the file doesn't have base relocations */

    /* and therefore cannot be relocated at run time */

    pfobj->nthdr.FileHeader.Characteristics |= IMAGE_FILE_RELOCS_STRIPPED;

    for (psecgobj = pfobj->secgrps;

         psecgobj != MFL_OD_NULL && psecgobj != MFL_OD_END;

         psecgobj = (PE32_secgrp_object *)psecgobj->next) {

        /* calculate regular section size */

        if (psecgobj->sec != MFL_OD_NULL) {

            sg_image = (PE32_section_size(psecgobj->sec) + PE32_section_vaddr(psecgobj->sec) +

                PE32_get_object_align(pfobj) - 1) & ~(PE32_get_object_align(pfobj) - 1);

            image_size = MAX(image_size, sg_image);

            continue;

        }

        /* calculate import section size */

        if ((psecgobj->internal & PE32_SECTION_EXPAND) &&

            ((psecgobj->internal & PE32_INTERNAL_OVRHD_MASK) == PE32_INTERNAL_SEC_IMPORT)) {

            idx = image_directory_idx[PE32_INTERNAL_SEC_IMPORT];

            sg_image = (PE32_file_dir_vaddr(pfobj, idx) + PE32_file_dir_size(pfobj, idx) +

                PE32_get_object_align(pfobj) - 1) & ~(PE32_get_object_align(pfobj) - 1);

            image_size = MAX(image_size, sg_image);

            continue;

        }

        /* calculate export section size */

        if ((psecgobj->internal & PE32_SECTION_EXPAND) &&

            ((psecgobj->internal & PE32_INTERNAL_OVRHD_MASK) == PE32_INTERNAL_SEC_EXPORT)) {

            idx = image_directory_idx[PE32_INTERNAL_SEC_EXPORT];

            sg_image = (PE32_file_dir_vaddr(pfobj, idx) + PE32_file_dir_size(pfobj, idx) +

                PE32_get_object_align(pfobj) - 1) & ~(PE32_get_object_align(pfobj) - 1);

            image_size = MAX(image_size, sg_image);

            continue;

        }

        /*calculate relocation size */

        if ((psecgobj->internal & PE32_SECTION_EXPAND) &&

            ((psecgobj->internal & PE32_INTERNAL_OVRHD_MASK) == PE32_INTERNAL_SEC_RELOC)) {

            idx = image_directory_idx[PE32_INTERNAL_SEC_RELOC];

            sg_image = (PE32_file_dir_vaddr(pfobj, idx) + PE32_file_dir_size(pfobj, idx) +

                PE32_get_object_align(pfobj) - 1) & ~(PE32_get_object_align(pfobj) - 1);

            image_size = MAX(image_size, sg_image);

            /* The file does have base relocations */

            pfobj->nthdr.FileHeader.Characteristics &= ~(ULONG)IMAGE_FILE_RELOCS_STRIPPED;

            continue;

        }

    }

    IMAGE_NT_HEADERS_OptionalHeader(pfobj->nthdr, SizeOfImage) = image_size;

    return MFL_OK;

}

static FUNC int cmpv (const void *v1, const void *v2)

{

    return ((struct sg_vlist *)v1)->vaddr - ((struct sg_vlist *)v2)->vaddr;

}

/****************************************************************************

 *                       PE32_write_pe_sections                             *

 *                                                                          *

 * Write section function                                                   *

 ****************************************************************************/

static FUNC mfl_err PE32_write_pe_sections (PE32_file_object *fod)

{

    mfl_err error = MFL_OK;

    struct sg_vlist *sgl;

    PE32_secgrp_object *sg;

    int i;

    if ((sgl = mfl_malloc(fod->secgrp_num * sizeof(struct sg_vlist))) == NULL) {

        return MFL_ERR_NOT_ENOUGH_MEMORY;

    }

    for (i=0, sg=fod->secgrps; sg != NULL; i++, sg = (PE32_secgrp_object *)sg->next) {

        sgl[i].sg = sg;

        if (sg->sec != NULL) {

            sgl[i].vaddr = PE32_section_vaddr(sg->sec);

        } else if (sg->internal & PE32_SECTION_EXPAND) {

            sgl[i].vaddr = PE32_file_dir_vaddr(fod,

                image_directory_idx[sg->internal & PE32_INTERNAL_OVRHD_MASK]);

        } else {

            sgl[i].vaddr = 0;

        }

    }

    qsort(sgl, (unsigned)fod->secgrp_num, sizeof(struct sg_vlist), cmpv);

    error = PE32_write_pe_section_header(fod, sgl);

    if (error == MFL_OK) {

        error = PE32_write_pe_section_content(fod, sgl);

    }

    mfl_free(sgl);

    return error;

}

/****************************************************************************

 *                    PE32_write_pe_section_header                          *

 *                                                                          *

 * Write header for all sections including internal secions.                *

 ****************************************************************************/

static FUNC mfl_err PE32_write_pe_section_header

    (PE32_file_object *fod, struct sg_vlist *sgl)

{

    PE32_size size;

    PE32_offset file_ptr;

    int i, j;

    mfl_err error = MFL_OK;

#if 0

    /* verify that overhead on relocations counted */

    if ((fod->ovrhd & PE32_INTERNAL_OVRHD_MASK) == 0)

        return MFL_ERR_OVERHD_MIS;

#endif

    /* calculate first section file offset */

    /* header size + section header table size */

    file_ptr = (fod->doshdr.e_lfanew + sizeof(fod->nthdr.Signature) +

                sizeof(IMAGE_FILE_HEADER) + IMAGE_SIZEOF_NT_OPTIONAL_HEADER +

                sizeof(IMAGE_SECTION_HEADER) *  PE32_file_sec_num(fod) +

                /* aligned to file alignment */

                + PE32_file_align(fod) - 1) & ~(PE32_file_align(fod) - 1);

    for (i = j = 0; i < fod->secgrp_num; i++) {

        /* write regular section header entry */

        if (sgl[i].sg->sec != MFL_OD_NULL) {

            /* VirtualSize will contain actual section size */

            sgl[i].sg->sec->Ish->Misc.VirtualSize = size = PE32_section_size(sgl[i].sg->sec);

            if (PE32_is_sec_mem_expand(sgl[i].sg->sec) == FALSE) {

                sgl[i].sg->sec->Ish->PointerToRawData = file_ptr;

                PE32_section_size(sgl[i].sg->sec) =

                    (size + PE32_file_align(fod) - 1) & ~(PE32_file_align(fod) - 1);

                file_ptr += PE32_section_size(sgl[i].sg->sec);

            } else {

                /* set zero to the pointer to the raw content*/

                /* if it is bss section                      */

                sgl[i].sg->sec->Ish->PointerToRawData = 0;

                PE32_section_size(sgl[i].sg->sec) = 0;

            }

            if ((error = mfl_write (sgl[i].sg->sec->Ish, sizeof(IMAGE_SECTION_HEADER),

                 (mfl_file_obj *)fod)) != MFL_OK)

            {

                break;

            }

            PE32_section_size(sgl[i].sg->sec) = size;

            continue;

        }

        /* write import section header entry */

        if ((sgl[i].sg->internal & PE32_SECTION_EXPAND) &&

            ((sgl[i].sg->internal & PE32_INTERNAL_OVRHD_MASK) == PE32_INTERNAL_SEC_IMPORT)) {

            if ((error = PE32_write_internal_hdr(fod, PE32_INTERNAL_SEC_IMPORT,

                         IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_MEM_READ,

                         &file_ptr)) != MFL_OK)

            {

                return error;

            }

            continue;

        }

        /* write export section header entry */

        if ((sgl[i].sg->internal & PE32_SECTION_EXPAND) &&

            ((sgl[i].sg->internal & PE32_INTERNAL_OVRHD_MASK) == PE32_INTERNAL_SEC_EXPORT)) {

            if ((error = PE32_write_internal_hdr(fod, PE32_INTERNAL_SEC_EXPORT,

                         IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ,

                         &file_ptr)) != MFL_OK) {

                return error;

            }

            continue;

        }

        /* relocation section header */

        if ((sgl[i].sg->internal & PE32_SECTION_EXPAND) &&

            ((sgl[i].sg->internal & PE32_INTERNAL_OVRHD_MASK) == PE32_INTERNAL_SEC_RELOC)) {

            if ((error = PE32_write_internal_hdr(fod, PE32_INTERNAL_SEC_RELOC,

                         IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_DISCARDABLE | IMAGE_SCN_MEM_READ,

                         &file_ptr)) != MFL_OK) {

                return error;

            }

            continue;

        }

    }

    /* Write gep of zero show the contenue of the file will be align in */

    /* the file alignment                                               */

    /* calculate first section file offset */

    /* header size + section header table size */

    file_ptr = fod->doshdr.e_lfanew + sizeof(fod->nthdr.Signature) +

               sizeof (IMAGE_FILE_HEADER) + IMAGE_SIZEOF_NT_OPTIONAL_HEADER +

               sizeof (IMAGE_SECTION_HEADER) *  PE32_file_sec_num (fod);

    if ((error = PE32_write_file_pad_align(fod, &file_ptr, PE32_file_align(fod))) != MFL_OK) {

        return error;

    }

    return error;

}

/****************************************************************************

 *                     PE32_write_internal_hdr                              *

 *                                                                          *

 * Fill and write internal section header                                   *

 ****************************************************************************/

static FUNC mfl_err PE32_write_internal_hdr (PE32_file_object *fod,

                                             int internal, ULONG charac,

                                             PE32_offset *file_ptr)

{

    IMAGE_SECTION_HEADER sech;

    mfl_err error;

    int idx;

    memset(&sech, 0, sizeof(IMAGE_SECTION_HEADER));

    strcpy((mfl_str)sech.Name, str_internal[internal]);

    idx = image_directory_idx[internal];

    sech.VirtualAddress = PE32_file_dir_vaddr(fod, idx);

    sech.Misc.VirtualSize = PE32_file_dir_size(fod, idx);

    sech.SizeOfRawData = (PE32_file_dir_size(fod, idx) + PE32_file_align(fod) - 1) &

        ~(PE32_file_align(fod) - 1);

    sech.PointerToRawData = *file_ptr;

    sech.Characteristics = charac;

    error = mfl_write(&sech, sizeof(IMAGE_SECTION_HEADER), (mfl_file_obj *)fod);

    *file_ptr += sech.SizeOfRawData;

    return error;

}

/****************************************************************************

 *                    PE32_write_pe_section_content                         *

 *                                                                          *

 * Write in file content of all sections                                    *

 ****************************************************************************/

static FUNC mfl_err PE32_write_pe_section_content

    (PE32_file_object *fod, struct sg_vlist *sgl)

{

    int i;

    PE32_offset file_ptr, Check_off;

    mfl_err error;

    /* calculate file offset */

    file_ptr = IMAGE_NT_HEADERS_OptionalHeader(fod->nthdr, SizeOfHeaders);

    if ((error = PE32_write_file_pad_align(fod, &file_ptr, PE32_file_align(fod))) != MFL_OK) {

        return error;

    }

    for (i = 0; i < fod->secgrp_num; i++) {

        Check_off = ftell(fod->mflfh.fhandle);

        if (sgl[i].sg->sec != NULL && PE32_is_sec_mem_expand(sgl[i].sg->sec) == FALSE) {

            if ((error = mfl_write(sgl[i].sg->sec->content,

                                   sgl[i].sg->sec->Ish->SizeOfRawData,

                                   (mfl_file_obj *)fod)) != MFL_OK) {

                break;

            }

            file_ptr += sgl[i].sg->sec->Ish->SizeOfRawData;

            if ((error = PE32_write_file_pad_align(fod, &file_ptr, PE32_file_align(fod))) != MFL_OK) {

                return error;

            }

            continue;

        }

        if ((sgl[i].sg->internal & PE32_SECTION_EXPAND) &&

            ((sgl[i].sg->internal & PE32_INTERNAL_OVRHD_MASK) == PE32_INTERNAL_SEC_IMPORT)) {

            if ((error = PE32_write_import_symbols(fod)) != MFL_OK) {

                return error;

            }

            file_ptr += PE32_file_dir_size(fod, IMAGE_DIRECTORY_ENTRY_IMPORT);

            if ((error = PE32_write_file_pad_align(fod, &file_ptr, PE32_file_align(fod))) != MFL_OK) {

                return error;

            }

            continue;

        }

        if ((sgl[i].sg->internal & PE32_SECTION_EXPAND) &&

            ((sgl[i].sg->internal & PE32_INTERNAL_OVRHD_MASK) == PE32_INTERNAL_SEC_EXPORT)) {

            if ((error = PE32_write_export_symbols(fod)) != MFL_OK) {

                return error;

            }

            file_ptr += PE32_file_dir_size(fod, IMAGE_DIRECTORY_ENTRY_EXPORT);

            if ((error = PE32_write_file_pad_align(fod, &file_ptr, PE32_file_align(fod))) != MFL_OK) {

                return error;

            }

            continue;

        }

        if ((sgl[i].sg->internal & PE32_SECTION_EXPAND) &&

            ((sgl[i].sg->internal & PE32_INTERNAL_OVRHD_MASK) == PE32_INTERNAL_SEC_RELOC)) {

            if ((error = PE32_write_basereloc(fod, sgl)) != MFL_OK) {

                return error;

            }

            file_ptr += PE32_file_dir_size(fod, IMAGE_DIRECTORY_ENTRY_BASERELOC);

            if ((error = PE32_write_file_pad_align(fod, &file_ptr, PE32_file_align(fod))) != MFL_OK) {

                return error;

            }

            continue;

        }

    }

    return error;

}

/****************************************************************************

 *                       PE32_write_basereloc                               *

 *                                                                          *

 * Write executable relocataions                                            *

 ****************************************************************************/

static FUNC mfl_err PE32_write_basereloc (PE32_file_object *fod,

                                          struct sg_vlist *sgl)

{

    mfl_err error;

    int i, j, nblock;

    void *relbuf;

    IMAGE_BASE_RELOCATION *block_header;

    USHORT *type_offset;

    PE32_vaddr addr;

    PE32_reloc_object *rod;

    PE32_section_object *sec;

    mfl_file_off foff;

    mfl_tell((mfl_file_obj *)fod,&foff);

    if ((relbuf = block_header =

         mfl_malloc (PE32_file_dir_size (fod,IMAGE_DIRECTORY_ENTRY_BASERELOC)+

                     sizeof (USHORT))) == NULL)

        return MFL_ERR_NOT_ENOUGH_MEMORY;

    /* for each section */

    for (i=0; i < fod->secgrp_num; i++)

        if (sgl[i].sg->sec != NULL) {

            sec = sgl[i].sg->sec;

            /* get number of 4K blocks */

            nblock = (PE32_section_size (sec) + 0xfff) >> 12;

            /* for each 4K block */

            for (j=0, addr = PE32_section_vaddr(sec); j < nblock;

                 j++, addr += 0x1000) {

                /* if block has relocations */

                if (sec->pdir[j].rcnt != 0) {

                    /* fill block header */

                    block_header->VirtualAddress = addr;

                    block_header->SizeOfBlock = sizeof (IMAGE_BASE_RELOCATION) +

                        sizeof (USHORT) * sec->pdir[j].rcnt;

                    /* for each relocation in block */

                    type_offset = (USHORT *)(block_header + 1);

                    for (rod=(PE32_reloc_object *)sec->pdir[j].rod;

                         rod != NULL; rod = rod->next, type_offset++)

                        /* fill type-offset value */

                        *type_offset = (rod->offset & 0xfff)| (rod->type << 12);

                    /* pad next entry (maybe last one) */

                    *type_offset = 0;

                    /* advance to next block header */

                    block_header = (IMAGE_BASE_RELOCATION *)((char *)block_header + block_header->SizeOfBlock);

                }

            }

        }

    /* write relocations */

    error = mfl_write (relbuf,

                       PE32_file_dir_size(fod,IMAGE_DIRECTORY_ENTRY_BASERELOC),

                       (mfl_file_obj *)fod);

    mfl_tell((mfl_file_obj *)fod,&foff);

    mfl_free (relbuf);

    return error;

}

/****************************************************************************

 *                    PE32_write_export_symbols                             *

 *                                                                          *

 * Write export symbol table                                                *

 ****************************************************************************/

static FUNC mfl_err PE32_write_export_symbols (PE32_file_object *fod)

{

    mfl_err error;

    int i;

    void *symbuf;

    IMAGE_EXPORT_DIRECTORY *st_header;

    PE32_symtab_object *stod;

    static mfl_sym_grp grp = MFL_SYM_EXPORT;

    static mfl_next next = {MFL_OD_FIRST, MFL_OBJ_SYMTAB, MFL_PROP_SYMTAB_GRP,

                                &grp};

    PE32_symbol_object *sym;

    PE32_size sec_size;

    PE32_vaddr sec_addr;

    PE32_vaddr *func_addr;

    PE32_vaddr *name_addr;

    USHORT *ord;

    char *func_name;

    PE32_vaddr name_ptr;

    int sym_num;

    int len;

    mfl_file_off foff;

    mfl_tell((mfl_file_obj *)fod,&foff);

    sec_size = PE32_file_dir_size (fod,IMAGE_DIRECTORY_ENTRY_EXPORT);

    sec_addr = PE32_file_dir_vaddr (fod,IMAGE_DIRECTORY_ENTRY_EXPORT);

    if ((symbuf = st_header = mfl_malloc (sec_size)) == NULL)

        return MFL_ERR_NOT_ENOUGH_MEMORY;

    /* get numbet of symbols in all export symbol tables */

    next.od = MFL_OD_FIRST;

    sym_num = 0;

    while ((error = PE32_get_next_symtab (fod, &next, &stod)) == MFL_OK) {

        sym_num += stod->syms->item_num;

        next.od = (mfl_od)stod;

    }

    /* fill symbol table header */

    st_header->Characteristics = 0;

    st_header->TimeDateStamp = time(NULL);

    st_header->MajorVersion = 0;

    st_header->MinorVersion = 0;

    st_header->Base = 1;

    st_header->NumberOfFunctions = sym_num;

    st_header->NumberOfNames = sym_num;

    st_header->AddressOfFunctions = sec_addr +  sizeof (IMAGE_EXPORT_DIRECTORY);

    st_header->AddressOfNames = st_header->AddressOfFunctions + sym_num;

    st_header->AddressOfNameOrdinals = st_header->AddressOfNames + sym_num;

    st_header->Name = (ULONG)(st_header->AddressOfNameOrdinals + sym_num);

    /* calculate pointer to smaller tables */

    func_addr = (PE32_vaddr *)(st_header + 1);

    name_addr = func_addr + sym_num;

    ord = (PUSHORT)(name_addr + sym_num);

    func_name = (char *)(ord + sym_num);

    name_ptr = st_header->Name;

    strcpy (func_name, fod->mflfh.name);

    len = strlen (func_name) + 1;

    func_name += len;

    name_ptr += len;

    i = 0;

    /* for all export symbol tables */

    next.od = MFL_OD_FIRST;

    while ((error = PE32_get_next_symtab (fod, &next, &stod)) == MFL_OK) {

        next.od = (mfl_od)stod;

        /* for all symbols in symbol table */

        sym = MFL_OD_FIRST;

        while ((sym = hash_get_next (stod->syms, (mfl_hash_od)sym))

                != MFL_OD_END) {

            func_addr[i] = PE32_symbol_vaddr (sym);

            name_addr[i] = name_ptr;

            ord[i] = i;

            strcpy (func_name, PE32_symbol_name(sym));

            len = strlen (func_name) + 1;

            func_name += len;

            name_ptr += len;

            i++;

        }

    }

    /* reset the rest of the buffer */

    memset (func_name, 0, sec_size - ((ULONG)func_name - (ULONG)st_header));

    /* write symbols */

    error = mfl_write (st_header, sec_size, (mfl_file_obj *)fod);

    mfl_tell((mfl_file_obj *)fod,&foff);

    mfl_free (st_header);

    return error;

}

/****************************************************************************

 *                    PE32_write_import_symbols                             *

 *                                                                          *

 * Write import symbol table                                                *

 ****************************************************************************/

static FUNC mfl_err PE32_write_import_symbols (PE32_file_object *fod)

{

    mfl_err error;

    PE32_size sec_size;

    PE32_vaddr sec_addr;

    unsigned int i;

    int j,len;

    void *symbuf;

    int sym_num;

    int st_num;

    PE32_symtab_object *stod;

    PE32_symbol_object *sym;

    PE32_vaddr *adr_tab_1, *adr_tab_2;

    PE32_vaddr *ptr_tab_1, *ptr_tab_2;

    IMAGE_IMPORT_BY_NAME *adr_hint_tab;

    IMAGE_IMPORT_BY_NAME *ptr_hint_tab;

    IMAGE_IMPORT_DESCRIPTOR *st_header;

    static mfl_sym_grp grp = MFL_SYM_IMPORT;

    static mfl_next next = {MFL_OD_FIRST, MFL_OBJ_SYMTAB, MFL_PROP_SYMTAB_GRP,

                                &grp};

    mfl_file_off foff;

    mfl_tell((mfl_file_obj *)fod,&foff);

    sec_size = PE32_file_dir_size (fod,IMAGE_DIRECTORY_ENTRY_IMPORT);

    sec_addr = PE32_file_dir_vaddr (fod,IMAGE_DIRECTORY_ENTRY_IMPORT);

    if ((symbuf = st_header = mfl_malloc (sec_size)) == NULL)

        return MFL_ERR_NOT_ENOUGH_MEMORY;

    /* for all import symbol tables */

    next.od = MFL_OD_FIRST;

    sym_num = 0;

    st_num = 0;

    while ((error = PE32_get_next_symtab (fod, &next, &stod)) == MFL_OK) {

        sym_num += stod->syms->item_num;

        st_num++;

        next.od = (mfl_od)stod;

    }

    /* image based addresses */

    adr_tab_1 = (PE32_vaddr *)(sec_addr + sizeof(IMAGE_IMPORT_DESCRIPTOR) * (st_num+1));

    adr_tab_2 = adr_tab_1 + sym_num + st_num;

    adr_hint_tab = (IMAGE_IMPORT_BY_NAME *)(adr_tab_2 + sym_num + st_num);

    /* buffer addresses */

    ptr_tab_1 = (PE32_vaddr *)(st_header + st_num + 1);

    ptr_tab_2 = ptr_tab_1 + sym_num + st_num;

    ptr_hint_tab =  (IMAGE_IMPORT_BY_NAME *)(ptr_tab_2 + sym_num + st_num);

    next.od = MFL_OD_FIRST;

    for (j=0; j < st_num; j++) {

        /* get next symbol table */

        if ((error = PE32_get_next_symtab (fod, &next, &stod)) != MFL_OK)

            return error;

        next.od = (mfl_od)stod;

        /* fill symbol table header entry */

        st_header[j].Characteristics = (ULONG)adr_tab_1;

        st_header[j].TimeDateStamp = 0;

        st_header[j].ForwarderChain = 0;

        st_header[j].Name = (ULONG)adr_hint_tab;

        /*st_header[j].FirstThunk = (IMAGE_THUNK_DATA *)adr_tab_2;*/

        st_header[j].FirstThunk = (DWORD)adr_tab_2;

        /* copy shared file name */

        strcpy ((char *)ptr_hint_tab, stod->file);

        ((char *)ptr_hint_tab) [-1] = '\0';

        /* advance pointers */

        ptr_hint_tab =

          (IMAGE_IMPORT_BY_NAME *)(ptr_hint_tab + ((strlen (stod->file) + 2) & (unsigned)~1));

        adr_hint_tab =

          (IMAGE_IMPORT_BY_NAME *)((char *)adr_hint_tab +

                                   ((strlen (stod->file) + 2) & (unsigned)~1));

        sym = MFL_OD_FIRST;

        for (i=0; i < stod->syms->item_num; i++) {

            sym = hash_get_next (stod->syms, (mfl_hash_od)sym);

            /* fill lookup and address table */

            ptr_tab_1[i] = (PE32_vaddr)adr_hint_tab;

            ptr_tab_2[i] = (PE32_vaddr)adr_hint_tab;

            /* fill hint-name table */

            ptr_hint_tab->Hint = (USHORT)sym->ord;

            strcpy ((mfl_str)ptr_hint_tab->Name, sym->name);

            ((char *)ptr_hint_tab) [-1] = '\0';

            /* addvance pointers */

            len =  (sizeof (USHORT) + strlen (sym->name) + 2) & (unsigned)~1;

            adr_hint_tab = (IMAGE_IMPORT_BY_NAME *)((char *)adr_hint_tab + len);

            ptr_hint_tab = (IMAGE_IMPORT_BY_NAME *)((char *)ptr_hint_tab + len);

        }

        /* advance image base addresses */

        adr_tab_1 += stod->syms->item_num + 1;

        adr_tab_2 += stod->syms->item_num + 1;

        /* advance table pointers */

        ptr_tab_1[stod->syms->item_num] = 0;

        ptr_tab_2[stod->syms->item_num] = 0;

        ptr_tab_1 += stod->syms->item_num + 1;

        ptr_tab_2 += stod->syms->item_num + 1;

    }

     if (st_num > 0)

        memset(&st_header[st_num],0,sizeof(IMAGE_IMPORT_DESCRIPTOR));

    /* write import table */

    if ((error = mfl_write (symbuf,sec_size,(mfl_file_obj *)fod)) != MFL_OK)

       return error;

    mfl_tell((mfl_file_obj *)fod,&foff);

    mfl_free (symbuf);

    return MFL_OK;

}

/****************************************************************************

 *                        PE32_write_file_pad_align                         *

 *                                                                          *

 * Pad file to required alignment                                           *

 ****************************************************************************/

static FUNC mfl_err PE32_write_file_pad_align (PE32_file_object *fod,

                                               PE32_offset *file_ptr,

                                               PE32_align align)

{

    PE32_offset end;

    char *buf;

    PE32_size size;

    mfl_err error;

    mfl_file_off foff;

    mfl_tell((mfl_file_obj *)fod,&foff);

    /* calculate next aligned offset */

    end = (*file_ptr + align - 1) & ~(align-1);

    /* return if offset already aligned */

    if (end == *file_ptr)

        return MFL_OK;

    /* calculate fill size */

    size = end - *file_ptr;

    *file_ptr = end;

    /* allocate and reset pad buffer */

    if ((buf = mfl_malloc (size)) == NULL)

        return MFL_ERR_NOT_ENOUGH_MEMORY;

    memset (buf, 0, size);

    /* write the pad buffer */

    error = mfl_write (buf, size, (mfl_file_obj *)fod);

    /* free pad buffer */

    mfl_tell((mfl_file_obj *)fod,&foff);

    mfl_free (buf);

    return error;

}

/****************************************************************************

 *                    PE32_write_file_pad_offset                            *

 *                                                                          *

 * Pad file with zero from a certain offset to another offset               *

 ****************************************************************************/

static FUNC mfl_err PE32_write_file_pad_offset (PE32_file_object *fod,

                                                PE32_offset file_ptr,

                                                PE32_offset offset)

{

    char *buf;

    PE32_size size;

    mfl_err error;

    /* calculate fill size */

    size = offset - file_ptr;

    /* allocate and reset pad buffer */

    if ((buf = mfl_malloc (size)) == NULL)

        return MFL_ERR_NOT_ENOUGH_MEMORY;

    memset (buf, 0, size);

    /* write the pad buffer */

    error = mfl_write (buf, size, (mfl_file_obj *)fod);

    /* free pad buffer */

    mfl_free (buf);

    return error;

}

/****************************************************************************

 *                       PE32_open_for_write                                *

 *                                                                          *

 * Open file for write if needed. Complete reading file content first if    *

 * the file was initialy opened for read.                                   *

 ****************************************************************************/

static FUNC mfl_err PE32_open_for_write (PE32_file_object *fod, mfl_str name)

{

    mfl_err    error;

    mfl_file_p pfout;

    if (fod->mflfh.write_open == TRUE) {

        return MFL_OK;

    }

    /* if file is open for read - read all file content and close it */

    if ((error = PE32_read_all_cfile (fod)) != MFL_OK) {

        return error;

    }

    if ((error = mfl_open_normal_or_fd_file (name, 0, &pfout, MFL_OPEN_WRITE_STD

)) != MFL_OK) {

        return error;

    }

    mfl_file_header(fod)->mflfh.write_open = TRUE;

    mfl_file_header(fod)->mflfh.file_open = TRUE;

    mfl_file_header(fod)->mflfh.open_with_fd = FALSE;

    /* mark that for now this file does not used with mmap */

    mfl_file_header(fod)->mflfh.used_mmap = FALSE;

    mfl_file_header(fod)->mflfh.fhandle = pfout;

    /* insert the file to the open file list */

    if ((error = mfl_insert_new_open_file((mfl_file_obj *)fod)) != MFL_OK) {

        return error;

    }

    return MFL_OK;

}