/*                                                                          */

/* 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 <