\#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>

#include "langext.h"
#include "defines.h"
#include "types.h"
#include "subs.h"
#include "globals.h"

static byte defaultStub[]={
    0x4D,0x5A,0x6C,0x00,0x01,0x00,0x00,0x00,
    0x04,0x00,0x11,0x00,0xFF,0xFF,0x03,0x00,
    0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,
    0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x0E,0x1F,0xBA,0x0E,0x00,0xB4,0x09,0xCD,
    0x21,0xB8,0x00,0x4C,0xCD,0x21,0x54,0x68,
    0x69,0x73,0x20,0x70,0x72,0x6F,0x67,0x72,
    0x61,0x6D,0x20,0x72,0x65,0x71,0x75,0x69,
    0x72,0x65,0x73,0x20,0x57,0x69,0x6E,0x33,
    0x32,0x0D,0x0A,0x24
};

static int_32 defaultStubSize=sizeof(defaultStub);

void GetFixupTarget(PRELOC r,long *bseg,UINT *tofs,int isFlat)
{
    long baseseg;
    long targseg;
    UINT targofs;

    r->outputPos=seglist[r->segnum]->base+r->ofs;
    switch(r->ftype)
    {
    case REL_SEGFRAME:
    case REL_LILEFRAME:
         baseseg=r->frame;
         break;
    case REL_GRPFRAME:
         baseseg=grplist[r->frame]->segnum;
         break;
    case REL_EXTFRAME:
        switch(externs[r->frame].flags)
        {
        case EXT_MATCHEDPUBLIC:
	    if(!externs[r->frame].pubdef) 
	    {
		printf("Reloc:Unmatched extern %s\n",externs[r->frame].name);
		errcount++;
		break;
	    }
	    
            baseseg=externs[r->frame].pubdef->segnum;
            break;
        case EXT_MATCHEDIMPORT:
            baseseg=impdefs[externs[r->frame].impnum].segnum;
            break;
        default:
            printf("Reloc:Unmatched external referenced in frame\n");
            errcount++;
            break;
        }
        break;
    default:
        printf("Reloc:Unsupported FRAME type %i\n",r->ftype);
        errcount++;
    }
    if(baseseg<0)
    {
        printf("Undefined base seg\n");
        exit(1);
    }   /* this is a fix for TASM FLAT model, where FLAT group has no segments */

    switch(r->ttype)
    {
    case REL_EXTDISP:
        switch(externs[r->target].flags)
        {
        case EXT_MATCHEDPUBLIC:
	    if(!externs[r->target].pubdef) 
	    {
		printf("Reloc:Unmatched extern %s\n",externs[r->frame].name);
		errcount++;
		break;
	    }
	    
            targseg=externs[r->target].pubdef->segnum;
            targofs=externs[r->target].pubdef->ofs;
            break;
        case EXT_MATCHEDIMPORT:
            targseg=impdefs[externs[r->target].impnum].segnum;
            targofs=impdefs[externs[r->target].impnum].ofs;
            break;
        default:
            printf("Reloc:Unmatched external referenced in frame\n");
            errcount++;
            break;
        }
         targofs+=r->disp;
         break;
    case REL_EXTONLY:
        switch(externs[r->target].flags)
        {
        case EXT_MATCHEDPUBLIC:
	    if(!externs[r->target].pubdef) 
	    {
		printf("Reloc:Unmatched extern %s\n",externs[r->target].name);
		errcount++;
		break;
	    }
	    
            targseg=externs[r->target].pubdef->segnum;
            targofs=externs[r->target].pubdef->ofs;
            break;
        case EXT_MATCHEDIMPORT:
            targseg=impdefs[externs[r->target].impnum].segnum;
            targofs=impdefs[externs[r->target].impnum].ofs;
            break;
        default:
            printf("Reloc:Unmatched external referenced in frame\n");
            errcount++;
            break;
        }
         break;
    case REL_SEGONLY:
         targseg=r->target;
         targofs=0;
         break;
    case REL_SEGDISP:
         targseg=r->target;
         targofs=r->disp;
         break;
    case REL_GRPONLY:
         targseg=grplist[r->target]->segnum;
         targofs=0;
         break;
    case REL_GRPDISP:
         targseg=grplist[r->target]->segnum;
         targofs=r->disp;
         break;
    default:
            printf("Reloc:Unsupported TARGET type %i\n",r->ttype);
            errcount++;
    }
    if(targseg<0)
    {
        printf("undefined seg\n");
        exit(1);
    }
    if((!errcount) && (!seglist[targseg]))
    {
	printf("Reloc: no target segment\n");
	
        errcount++;
    }
    if((!errcount) && (!seglist[baseseg]))
    {
	printf("reloc: no base segment\n");
	
        errcount++;
    }

    if(!errcount)
    {
/*
        if(((seglist[targseg]->attr&SEG_ALIGN)!=SEG_ABS) &&
           ((seglist[baseseg]->attr&SEG_ALIGN)!=SEG_ABS))
        {
            if(seglist[baseseg]->base>seglist[targseg]->base)
            {
                printf("Reloc:Negative base address\n");
                errcount++;
            }
            targofs+=seglist[targseg]->base-seglist[baseseg]->base;
        }
*/
        if((seglist[baseseg]->attr&SEG_ALIGN)==SEG_ABS)
        {
            printf("Warning: Reloc frame is absolute segment\n");
            targseg=baseseg;
        }
        else if((seglist[targseg]->attr&SEG_ALIGN)==SEG_ABS)
        {
            printf("Warning: Reloc target is in absolute segment\n");
            targseg=baseseg;
        }
        if(!isFlat || ((seglist[baseseg]->attr&SEG_ALIGN)==SEG_ABS))
        {
            if(seglist[baseseg]->base>(seglist[targseg]->base+targofs))
            {
                printf("Error: target address out of frame\n");
                printf("Base=%08X,target=%08X\n",
                    seglist[baseseg]->base,seglist[targseg]->base+targofs);
                errcount++;
            }
            targofs+=seglist[targseg]->base-seglist[baseseg]->base;
            *bseg=baseseg;
            *tofs=targofs;
        }
        else
        {
            *bseg=-1;
            *tofs=targofs+seglist[targseg]->base;
        }
    }
    else
    {
	printf("relocation error occurred\n");
        *bseg=0;
        *tofs=0;
    }
}

void BuildPEImports(long impsectNum,PE_object_ptr objectTable, PE_header_ptr pehead)
BeginDeclarations
    bit_32 i,j,k;
    bit_16 *reqimps=NULL,reqcount=0;
    string_ptr *dllNames=NULL;
    bit_16 *dllNumImps=NULL;
    bit_16 *dllImpsDone=NULL;
    bit_16 *dllImpNameSize=NULL;
    bit_32 dllCount=0,dllNameSize=0,namePos;
    SEG *impsect;
    bit_32 thunkPos,thunk2Pos,impNamePos;
    PE_object_ptr lastobjecttable = objectTable- 1 ;
    PE_import_dir_ptr impdir ;
#define ImpDir (*impdir) 
#define ObjectTable (*objectTable)
#define LastObjectTable(*lastobjecttable)
#define PEHead (*pehead)
EndDeclarations
BeginCode

    ReturnIf (impsectNum LessThan 0) ;

    For i=0;i<n_imports;i++
     BeginFor
			LoopIf(!imports[i].use_count);
			 For j=0;j<reqcount;j++
        BeginFor
          ExitIf(reqimps[j] Equals imports[i].ordinal) ;
        EndFor ;
        LoopIf(j IsNotEqualTo reqcount) ;
          
        reqimps=(bit_16_ptr)reallocate_memory(reqimps,(reqcount+1)*sizeof(bit_16));
        reqimps[reqcount++]= i;
        For j=0;j<dllCount;j++
        BeginFor
          ExitIf(!compare_string(imports[i].module_ident,dllNames[j]))) ;
        }
				If j Equals dllcount
         Then
            dllNames=(string_ptr *)reallocate_memory(dllNames,(dllCount+1)*sizeof(char*));
            dllNumImps=(bit_16_ptr)reallocate_memory(dllNumImps,(dllCount+1)*sizeof(bit_16));
				    dllImpsDone=(bit_16_ptr)reallocate_memory(dllImpsDone,(dllCount+1)*sizeof(bit_16));
            dllImpNameSize=(bit_16_ptr)reallocate_memory(dllImpNameSize,(dllCount+1)*sizeof(bit_16));
            dllNames[dllCount]=[externs[i].impnum].mod_name;
						String(dllNames[dllcount])[Length(dllNames[dllcount])] = 0;
            dllNumImps[dllCount]=0;
            dllImpsDone[dllCount]=0;
            dllImpNameSize[dllCount]=0;
            dllNameSize+=Length(dllNames[dllCount])+1;
            if(dllNameSize&1) dllNameSize++;
            dllCount++;
          Endif ;
        dllNumImps[j]++;
				If imports[i].entry_ident IsNotZero
          Then
            dllImpNameSize[j]+=Length(imports[i],entryident)+3;
            /* the +3 ensure room for 2-byte hint and null terminator */
            If dllImpNameSize[j] And 1
						  Then
                dllImpNameSize[j]++;
              EndIf ;
          EndiF ;
     EndFor ;

    ReturnIf(!reqcount || !dllCount) ;

    LastObjectTable += impsectNum-1 ;
		objectTable+= LastObjectTable + 1 ;
    k = LastObjectTable.raw_ptr + LastObjectTable.raw_size ;
    k+=fileAlign-1;
    k&=(0xffffffff-(fileAlign-1)); /* aligned */

    /* k is now physical location of this object */
    ObjectTable.raw_ptr = k ;

    k = LastObjectTable.virtual_size + LastObjectTable.virtual_start ;
    ObjectTable.virtual_start = k ;

    impsect=outlist[impsectNum];
    impsect->base=k+imageBase; /* get base address of section */

    impsect->length=(dllCount+1)*PE_IMPORTDIRENTRY_SIZE+dllNameSize;
    if(impsect->length&3) impsect->length+=4-(impsect->length&3); /* align to 4-byte boundary */
    thunkPos=impsect->base+impsect->length;
    For j=0,i=0; j<dllCount; j++
      BeginFor
        i+=dllNumImps[j]+1; /* add number of entries in DLL thunk table */
      EndFor ;
    /* now i= number of entries in Thunk tables for all DLLs */
    /* get address of name tables, which follow thunk tables */
    impNamePos=thunkPos+i*2*4; /* 2 thunk tables per DLL, 4 bytes per entry */
    impsect->length+=i*2*4; /* update length of section too. */

    For j=0,i=0 ; j<dllCount; j++
      BeginFor
        i+=dllImpNameSize[j]; /* add size of import names and hints */
      EndFor ;

    impsect->highest_uninitialized_byte = impsect->length+=i;

    impsect->data=(PUCHAR)allocate_memory(impsect->length);
    impsect->datmask=(PUCHAR)allocate_memory((impsect->length+7)/8);

    /* end of directory entries=name table */
    namePos=impsect->base+(dllCount+1)*PE_IMPORTDIRENTRY_SIZE;
		impdir = impsect->data ;
    For i=0; i<dllCount; i++
      BeginFor
        /* add directory entry */
				ImpDir.thunkPos = thunkPos - imageBase ;
				ImpDir.timeStamp = 0;
				ImpDir.version = 0;
				ImpDir.dllName = namePos - imageBase ;
				ImpDir.thunk2Pos = thunk2Pos =  thunkPos+ (dllNumImps[i]+1) * 4 ;
        memcpy(impsect->data+namePos-impsect->base,String(dllNames[i]),j = Length(dllNames[i]));
        namePos+=j+1;
        If namePos And 1
          Then
            impsect->data[namePos++ -impsect->base]=0;
          EndIf ;
        /* add imported names to table */
        For k=0; k<reqcount; k++
          BeginFor
						LoopIf(compare_string(imports[reqimps[k]].moduleident,dllNames[i])) ;
						If imports[reqimps[k]].entryident
							Then
                /* store pointers to name entry in thunk tables */
								*(bit_32 *)(impsect->data + thunkPos - impsect->base) = impNamePos - imageBase ;
								*(bit_32 *)(impsect->data + thunk2Pos - impsect->base) = impNamePos - imageBase ;

                /* no hint */
                impsect->data[impNamePos-impsect->base]=0;
                impsect->data[impNamePos-impsect->base+1]=0;
                impNamePos+=2;
                /* store name */
				        memcpy(impsect->data+impNamePos-impsect->base,String(reqimps[k].entryident),j = Length(reqImps[k].entryident));
        				impNamePos+=j+1;
        				If impNamePos And 1
          				Then
            				impsect->data[impNamePos++ -impsect->base]=0;
          				EndIf ;
              Else
                /* store ordinal number in thunk tables */
                j=imports[reqimps[k]].ordinal+PE_ORDINAL_FLAG;
								*(bit_32 *)(impsect->data + thunkPos - impsect->base) = j ;
								*(bit_32 *)(impsect->data + thunk2Pos - impsect->base) = j;
              EndIf ;
// FIXME
            impdefs[reqimps[k]].segnum=impsect->absofs;
            impdefs[reqimps[k]].ofs=thunk2Pos-impsect->base;
//
            thunkPos+=4;
            thunk2Pos+=4;
        }
        /* zero out end of thunk tables */
				*(bit_32 *)(impsect->data + thunkPos - impsect->base) = 0 ;
				*(bit_32 *)(impsect->data + thunk2Pos - impsect->base) = 0;
        thunkPos=thunk2Pos+4;
				impdir++ ;
    }
    /* zero out the final entry to mark the end of the table */
		memset(impdir,0,PE_IMPORTDIRENTRY_SIZE) '

    k=impsect->length;
    k+=objectAlign-1;
    k&=(0xffffffff-(objectAlign-1));
    impsect->virtualSize=k;

	  ObjectTable.virtual_length ;
    ObjectTable.length = impsect->length ;

    PEHead.import_rva = outlist[impsectnum]->base-imageBase ;
    PEHead.import_rva = outlist[impsectnum]->length ;
}
#undef ImpDir
#undef PEHead
#undef ObjectTable 
#undef LastObjectTable 
void BuildPERelocs(long relocSectNum,PUCHAR objectTable)
{
    int i,j;
    PRELOC r;
    PSEG relocSect;
    UINT curStartPos;
    UINT curBlockPos;
    UINT k;
    long targseg;
    UINT targofs;
    unsigned long templ;
    unsigned short temps;

    /* do fixups */
    for(i=0;i<fixcount;i++)
    {
        GetFixupTarget(relocs[i],&targseg,&targofs,TRUE);
        switch(relocs[i]->rtype)
        {
        case FIX_BASE:
        case FIX_PTR1616:
        case FIX_PTR1632:
             if(targseg<0)
             {
                printf("Reloc %li:Segment selector relocations are not supported in PE files\n",i);
		printf("rtype=%02X, frame=%04X, target=%04X, ftype=%02X, ttype=%02X\n",
		       relocs[i]->rtype,relocs[i]->frame,relocs[i]->target,relocs[i]->ftype,
		       relocs[i]->ttype);
		
                errcount++;
             }
             else
             {
                j=relocs[i]->ofs;
                if(relocs[i]->rtype==FIX_PTR1616)
                {
                    if(targofs>0xffff)
                    {
                        printf("Relocs %li:Warning 32 bit offset in 16 bit field\n",i);
                    }
                    targofs&=0xffff;
                    temps=seglist[relocs[i]->segnum]->data[j];
                    temps+=seglist[relocs[i]->segnum]->data[j+1]<<8;
                    temps+=targofs;
                    seglist[relocs[i]->segnum]->data[j]=temps&0xff;
                    seglist[relocs[i]->segnum]->data[j+1]=(temps>>8)&0xff;
                    j+=2;
                }
                else if(relocs[i]->rtype==FIX_PTR1632)
                {
                    templ=seglist[relocs[i]->segnum]->data[j];
                    templ+=seglist[relocs[i]->segnum]->data[j+1]<<8;
                    templ+=seglist[relocs[i]->segnum]->data[j+2]<<16;
                    templ+=seglist[relocs[i]->segnum]->data[j+3]<<24;
                    templ+=targofs;
                    seglist[relocs[i]->segnum]->data[j]=templ&0xff;
                    seglist[relocs[i]->segnum]->data[j+1]=(templ>>8)&0xff;
                    seglist[relocs[i]->segnum]->data[j+2]=(templ>>16)&0xff;
                    seglist[relocs[i]->segnum]->data[j+3]=(templ>>24)&0xff;
                    j+=4;
                }
                temps=seglist[relocs[i]->segnum]->data[j];
                temps+=seglist[relocs[i]->segnum]->data[j+1]<<8;
                temps+=seglist[targseg]->absframe;
                seglist[relocs[i]->segnum]->data[j]=temps&0xff;
                seglist[relocs[i]->segnum]->data[j+1]=(temps>>8)&0xff;
             }
             break;
        case FIX_OFS32:
        case FIX_OFS32_2:
            templ=seglist[relocs[i]->segnum]->data[relocs[i]->ofs];
            templ+=seglist[relocs[i]->segnum]->data[relocs[i]->ofs+1]<<8;
            templ+=seglist[relocs[i]->segnum]->data[relocs[i]->ofs+2]<<16;
            templ+=seglist[relocs[i]->segnum]->data[relocs[i]->ofs+3]<<24;
            templ+=targofs;
            seglist[relocs[i]->segnum]->data[relocs[i]->ofs]=templ&0xff;
            seglist[relocs[i]->segnum]->data[relocs[i]->ofs+1]=(templ>>8)&0xff;
            seglist[relocs[i]->segnum]->data[relocs[i]->ofs+2]=(templ>>16)&0xff;
            seglist[relocs[i]->segnum]->data[relocs[i]->ofs+3]=(templ>>24)&0xff;
             break;
	case FIX_RVA32:
            templ=seglist[relocs[i]->segnum]->data[relocs[i]->ofs];
            templ+=seglist[relocs[i]->segnum]->data[relocs[i]->ofs+1]<<8;
            templ+=seglist[relocs[i]->segnum]->data[relocs[i]->ofs+2]<<16;
            templ+=seglist[relocs[i]->segnum]->data[relocs[i]->ofs+3]<<24;
            templ+=targofs-imageBase;
            seglist[relocs[i]->segnum]->data[relocs[i]->ofs]=templ&0xff;
            seglist[relocs[i]->segnum]->data[relocs[i]->ofs+1]=(templ>>8)&0xff;
            seglist[relocs[i]->segnum]->data[relocs[i]->ofs+2]=(templ>>16)&0xff;
            seglist[relocs[i]->segnum]->data[relocs[i]->ofs+3]=(templ>>24)&0xff;
             break;
        case FIX_OFS16:
        case FIX_OFS16_2:
            if(targofs>0xffff)
            {
                printf("Relocs %li:Warning 32 bit offset in 16 bit field\n",i);
            }
            targofs&=0xffff;
            temps=seglist[relocs[i]->segnum]->data[relocs[i]->ofs];
            temps+=seglist[relocs[i]->segnum]->data[relocs[i]->ofs+1]<<8;
            temps+=targofs;
            seglist[relocs[i]->segnum]->data[relocs[i]->ofs]=temps&0xff;
            seglist[relocs[i]->segnum]->data[relocs[i]->ofs+1]=(temps>>8)&0xff;
             break;
        case FIX_LBYTE:
        case FIX_HBYTE:
            printf("Error: Byte relocations not supported in PE files\n");
            errcount++;
            break;
        case FIX_SELF_LBYTE:
            if(targseg>=0)
            {
                printf("Error: Absolute Reloc target not supported for self-relative fixups\n");
                errcount++;
            }
            else
            {
                j=targofs;
                j-=(seglist[relocs[i]->segnum]->base+relocs[i]->ofs+1);
                if((j<-128)||(j>127))
                {
                    printf("Error: Reloc %li out of range\n",i);
                }
                else
                {
                    seglist[relocs[i]->segnum]->data[relocs[i]->ofs]+=j;
                }
            }
            break;
        case FIX_SELF_OFS16:
        case FIX_SELF_OFS16_2:
            if(targseg>=0)
            {
                printf("Error: Absolute Reloc target not supported for self-relative fixups\n");
                errcount++;
            }
            else
            {
                j=targofs;
                j-=(seglist[relocs[i]->segnum]->base+relocs[i]->ofs+2);
                if((j<-32768)||(j>32767))
                {
                    printf("Error: Reloc %li out of range\n",i);
                }
                else
                {
                    temps=seglist[relocs[i]->segnum]->data[relocs[i]->ofs];
                    temps+=seglist[relocs[i]->segnum]->data[relocs[i]->ofs+1]<<8;
                    temps+=j;
                    seglist[relocs[i]->segnum]->data[relocs[i]->ofs]=temps&0xff;
                    seglist[relocs[i]->segnum]->data[relocs[i]->ofs+1]=(temps>>8)&0xff;
                }
            }
            break;
        case FIX_SELF_OFS32:
        case FIX_SELF_OFS32_2:
            if(targseg>=0)
            {
                printf("Error: Absolute Reloc target not supported for self-relative fixups\n");
                errcount++;
            }
            else
            {
                j=targofs;
                j-=(seglist[relocs[i]->segnum]->base+relocs[i]->ofs+4);
                templ=seglist[relocs[i]->segnum]->data[relocs[i]->ofs];
                templ+=seglist[relocs[i]->segnum]->data[relocs[i]->ofs+1]<<8;
                templ+=seglist[relocs[i]->segnum]->data[relocs[i]->ofs+2]<<16;
                templ+=seglist[relocs[i]->segnum]->data[relocs[i]->ofs+3]<<24;
                templ+=j;
                seglist[relocs[i]->segnum]->data[relocs[i]->ofs]=templ&0xff;
                seglist[relocs[i]->segnum]->data[relocs[i]->ofs+1]=(templ>>8)&0xff;
                seglist[relocs[i]->segnum]->data[relocs[i]->ofs+2]=(templ>>16)&0xff;
                seglist[relocs[i]->segnum]->data[relocs[i]->ofs+3]=(templ>>24)&0xff;
            }
            break;
        default:
                printf("Reloc %li:Relocation type %i not supported\n",i,relocs[i]->rtype);
                errcount++;
        }
    }

    /* get reloc section */
    relocSect=outlist[relocSectNum]; /* get section structure */

    /* sort relocations into order of increasing address */
    for(i=1;i<fixcount;i++)
    {
    r=relocs[i]; /* save current reloc */
    for(j=i-1;j>=0;j--) /* search backwards through table */
    {
        /* stop once we've found a target before current */
            if(r->outputPos>=relocs[j]->outputPos) break;
            /* otherwise move reloc entry up */
            relocs[j+1]=relocs[j];
        }
        j++; /* point to first entry after non-match */
        relocs[j]=r; /* put current reloc in position */
    }

    for(i=0,curStartPos=0,curBlockPos=0;i<fixcount;i++)
    {
        switch(relocs[i]->rtype)
        {
        case FIX_SELF_OFS32:
        case FIX_SELF_OFS32_2:
        case FIX_SELF_OFS16:
        case FIX_SELF_OFS16_2:
	case FIX_SELF_LBYTE:
	case FIX_RVA32:
                continue; /* self-relative fixups and RVA fixups don't relocate */
        default:
                break;
        }
        if(relocs[i]->outputPos>=(curStartPos+0x1000)) /* more than 4K past block start? */
        {
            j=relocSect->length&3;
            if(j) /* unaligned block position */
            {
                relocSect->length+=4-j; /* update length to align block */
                /* and block memory */
                relocSect->data=(PUCHAR)reallocate_memory(relocSect->data,relocSect->length);
                /* update size of current reloc block */
                k=relocSect->data[curBlockPos+4];
                k+=relocSect->data[curBlockPos+5]<<8;
                k+=relocSect->data[curBlockPos+6]<<16;
                k+=relocSect->data[curBlockPos+7]<<24;
                k+=4-j;
                relocSect->data[curBlockPos+4]=k&0xff;
                relocSect->data[curBlockPos+5]=(k>>8)&0xff;
                relocSect->data[curBlockPos+6]=(k>>16)&0xff;
                relocSect->data[curBlockPos+7]=(k>>24)&0xff;
                for(j=4-j;j>0;j--)
                {
                    relocSect->data[relocSect->length-j]=0;
                }
            }
            curBlockPos=relocSect->length; /* get address in section of current block */
            relocSect->length+=8; /* 8 bytes block header */
            /* increase size of block */
            relocSect->data=(PUCHAR)reallocate_memory(relocSect->data,relocSect->length);
            /* store reloc base address, and block size */
            curStartPos=relocs[i]->outputPos&0xfffff000; /* start of mem page */

            /* start pos is relative to image base */
            relocSect->data[curBlockPos]=(curStartPos-imageBase)&0xff;
            relocSect->data[curBlockPos+1]=((curStartPos-imageBase)>>8)&0xff;
            relocSect->data[curBlockPos+2]=((curStartPos-imageBase)>>16)&0xff;
            relocSect->data[curBlockPos+3]=((curStartPos-imageBase)>>24)&0xff;

            relocSect->data[curBlockPos+4]=8; /* start size is 8 bytes */
            relocSect->data[curBlockPos+5]=0;
            relocSect->data[curBlockPos+6]=0;
            relocSect->data[curBlockPos+7]=0;
        }
        relocSect->data=(PUCHAR)reallocate_memory(relocSect->data,relocSect->length+2);

        j=relocs[i]->outputPos-curStartPos; /* low 12 bits of address */
        switch(relocs[i]->rtype)
        {
        case FIX_PTR1616:
        case FIX_OFS16:
        case FIX_OFS16_2:
            j|= PE_REL_LOW16;
            break;
        case FIX_PTR1632:
        case FIX_OFS32:
    case FIX_OFS32_2:
            j|= PE_REL_OFS32;
        }
        /* store relocation */
        relocSect->data[relocSect->length]=j&0xff;
        relocSect->data[relocSect->length+1]=(j>>8)&0xff;
        /* update block length */
        relocSect->length+=2;
        /* update size of current reloc block */
        k=relocSect->data[curBlockPos+4];
        k+=relocSect->data[curBlockPos+5]<<8;
        k+=relocSect->data[curBlockPos+6]<<16;
        k+=relocSect->data[curBlockPos+7]<<24;
        k+=2;
        relocSect->data[curBlockPos+4]=k&0xff;
        relocSect->data[curBlockPos+5]=(k>>8)&0xff;
        relocSect->data[curBlockPos+6]=(k>>16)&0xff;
        relocSect->data[curBlockPos+7]=(k>>24)&0xff;
    }
    /* if no fixups, then build NOP fixups, to make Windows NT happy */
    /* when it trys to relocate image */
    if(relocSect->length==0)
    {
    /* 12 bytes for dummy section */
        relocSect->length=12;
    relocSect->data=(PUCHAR)allocate_memory(12);
    /* zero it out for now */
        for(i=0;i<12;i++) relocSect->data[i]=0;
    relocSect->data[4]=12; /* size of block */
    }

    relocSect->datmask=(PUCHAR)allocate_memory((relocSect->length+7)/8);
    for(i=0;i<(relocSect->length+7)/8;i++)
    {
        relocSect->datmask[i]=0xff;
    }

    objectTable+=PE_OBJECTENTRY_SIZE*relocSectNum; /* point to reloc object entry */
    k=relocSect->length;
    k+=objectAlign-1;
    k&=(0xffffffff-(objectAlign-1));
    relocSect->virtualSize=k;
    objectTable[8]=k&0xff; /* store virtual size (in memory) of segment */
    objectTable[9]=(k>>8)&0xff;
    objectTable[10]=(k>>16)&0xff;
    objectTable[11]=(k>>24)&0xff;

    k=relocSect->length;
    objectTable[16]=(k)&0xff; /* store initialised data size */
    objectTable[17]=(k>>8)&0xff;
    objectTable[18]=(k>>16)&0xff;
    objectTable[19]=(k>>16)&0xff;

    k=objectTable[-PE_OBJECTENTRY_SIZE+20]; /* get physical start of prev object */
    k+=objectTable[-PE_OBJECTENTRY_SIZE+21]<<8;
    k+=objectTable[-PE_OBJECTENTRY_SIZE+22]<<16;
    k+=objectTable[-PE_OBJECTENTRY_SIZE+23]<<24;

    k+=objectTable[-PE_OBJECTENTRY_SIZE+16]; /* add physical length of prev object */
    k+=objectTable[-PE_OBJECTENTRY_SIZE+17]<<8;
    k+=objectTable[-PE_OBJECTENTRY_SIZE+18]<<16;
    k+=objectTable[-PE_OBJECTENTRY_SIZE+19]<<24;

    k+=fileAlign-1;
    k&=(0xffffffff-(fileAlign-1)); /* aligned */

    /* k is now physical location of this object */

    objectTable[20]=(k)&0xff; /* store physical file offset */
    objectTable[21]=(k>>8)&0xff;
    objectTable[22]=(k>>16)&0xff;
    objectTable[23]=(k>>24)&0xff;

    k=objectTable[-PE_OBJECTENTRY_SIZE+12]; /* get virtual start of prev object */
    k+=objectTable[-PE_OBJECTENTRY_SIZE+13]<<8;
    k+=objectTable[-PE_OBJECTENTRY_SIZE+14]<<16;
    k+=objectTable[-PE_OBJECTENTRY_SIZE+15]<<24;

    k+=objectTable[-PE_OBJECTENTRY_SIZE+8]; /* add virtual length of prev object */
    k+=objectTable[-PE_OBJECTENTRY_SIZE+9]<<8;
    k+=objectTable[-PE_OBJECTENTRY_SIZE+10]<<16;
    k+=objectTable[-PE_OBJECTENTRY_SIZE+11]<<24;

    /* store base address (RVA) of section */
    objectTable[12]=(k)&0xff;
    objectTable[13]=(k>>8)&0xff;
    objectTable[14]=(k>>16)&0xff;
    objectTable[15]=(k>>24)&0xff;

    relocSect->base=k+imageBase; /* relocate section */

    return;
}

void BuildPEExports(long SectNum,PUCHAR objectTable,PUCHAR name)
{
        long i,j;
        UINT k;
    PSEG expSect;
    UINT namelen;
    UINT numNames=0;
    UINT RVAStart;
    UINT nameRVAStart;
    UINT ordinalStart;
    UINT nameSpaceStart;
    UINT minOrd;
    UINT maxOrd;
    UINT numOrds;
    PPEXPREC nameList;
    PEXPREC curName;

    if(!expcount || (SectNum<0)) return; /* return if no exports */
    expSect=outlist[SectNum];

    if(name)
    {
        namelen=strlen(name);
        /* search backwards for path separator */
        for(i=namelen-1;(i>=0) && (name[i]!=PATH_CHAR);i--);
        if(i>=0) /* if found path separator */
        {
            name+=(i+1); /* update name pointer past path */
            namelen -= (i+1); /* and reduce length */
        }
    }
    else namelen=0;

    expSect->length=PE_EXPORTHEADER_SIZE+4*expcount+namelen+1;
    /* min section size= header size + num exports * pointer size */
    /* plus space for null-terminated name */

    minOrd=0xffffffff; /* max ordinal num */
    maxOrd=0;

    for(i=0;i<expcount;i++)
    {
        /* check we've got an exported name */
        if(expdefs[i].exp_name && strlen(expdefs[i].exp_name))
        {
            /* four bytes for name pointer */
            /* two bytes for ordinal, 1 for null terminator */
            expSect->length+=strlen(expdefs[i].exp_name)+7;
            numNames++;
        }

        if(expdefs[i].flags&EXP_ORD) /* ordinal? */
        {
            if(expdefs[i].ordinal<minOrd) minOrd=expdefs[i].ordinal;
            if(expdefs[i].ordinal>maxOrd) maxOrd=expdefs[i].ordinal;
        }
    }

    numOrds=expcount; /* by default, number of RVAs=number of exports */
    if(maxOrd>=minOrd) /* actually got some ordinal references? */
    {
        i=maxOrd-minOrd+1; /* get number of ordinals */
        if(i>expcount) /* if bigger range than number of exports */
        {
            expSect->length+=4*(i-expcount); /* up length */
            numOrds=i; /* get new num RVAs */
        }
    }
    else
    {
        minOrd=1; /* if none defined, min is set to 1 */
    }

    expSect->data=(PUCHAR)allocate_memory(expSect->length);

    objectTable+=PE_OBJECTENTRY_SIZE*SectNum; /* point to reloc object entry */
    k=expSect->length;
    k+=objectAlign-1;
    k&=(0xffffffff-(objectAlign-1));
    expSect->virtualSize=k;
    objectTable[8]=k&0xff; /* store virtual size (in memory) of segment */
    objectTable[9]=(k>>8)&0xff;
    objectTable[10]=(k>>16)&0xff;
    objectTable[11]=(k>>24)&0xff;

    k=expSect->length;
    objectTable[16]=(k)&0xff; /* store initialised data size */
    objectTable[17]=(k>>8)&0xff;
    objectTable[18]=(k>>16)&0xff;
    objectTable[19]=(k>>16)&0xff;

    k=objectTable[-PE_OBJECTENTRY_SIZE+20]; /* get physical start of prev object */
    k+=objectTable[-PE_OBJECTENTRY_SIZE+21]<<8;
    k+=objectTable[-PE_OBJECTENTRY_SIZE+22]<<16;
    k+=objectTable[-PE_OBJECTENTRY_SIZE+23]<<24;

    k+=objectTable[-PE_OBJECTENTRY_SIZE+16]; /* add physical length of prev object */
    k+=objectTable[-PE_OBJECTENTRY_SIZE+17]<<8;
    k+=objectTable[-PE_OBJECTENTRY_SIZE+18]<<16;
    k+=objectTable[-PE_OBJECTENTRY_SIZE+19]<<24;

    k+=fileAlign-1;
    k&=(0xffffffff-(fileAlign-1)); /* aligned */

    /* k is now physical location of this object */

    objectTable[20]=(k)&0xff; /* store physical file offset */
    objectTable[21]=(k>>8)&0xff;
    objectTable[22]=(k>>16)&0xff;
    objectTable[23]=(k>>24)&0xff;

    k=objectTable[-PE_OBJECTENTRY_SIZE+12]; /* get virtual start of prev object */
    k+=objectTable[-PE_OBJECTENTRY_SIZE+13]<<8;
    k+=objectTable[-PE_OBJECTENTRY_SIZE+14]<<16;
    k+=objectTable[-PE_OBJECTENTRY_SIZE+15]<<24;

    k+=objectTable[-PE_OBJECTENTRY_SIZE+8]; /* add virtual length of prev object */
    k+=objectTable[-PE_OBJECTENTRY_SIZE+9]<<8;
    k+=objectTable[-PE_OBJECTENTRY_SIZE+10]<<16;
    k+=objectTable[-PE_OBJECTENTRY_SIZE+11]<<24;

    /* store base address (RVA) of section */
    objectTable[12]=(k)&0xff;
    objectTable[13]=(k>>8)&0xff;
    objectTable[14]=(k>>16)&0xff;
    objectTable[15]=(k>>24)&0xff;

    expSect->base=k+imageBase; /* relocate section */

    /* start with buf=all zero */
    for(i=0;i<expSect->length;i++) expSect->data[i]=0;

    /* store creation time of export data */
    k=(UINT)time(NULL);
    expSect->data[4]=k&0xff;
    expSect->data[5]=(k>>8)&0xff;
    expSect->data[6]=(k>>16)&0xff;
    expSect->data[7]=(k>>24)&0xff;

    expSect->data[16]=(minOrd)&0xff; /* store ordinal base */
    expSect->data[17]=(minOrd>>8)&0xff;
    expSect->data[18]=(minOrd>>16)&0xff;
    expSect->data[19]=(minOrd>>24)&0xff;

    /* store number of RVAs */
    expSect->data[20]=numOrds&0xff;
    expSect->data[21]=(numOrds>>8)&0xff;
    expSect->data[22]=(numOrds>>16)&0xff;
    expSect->data[23]=(numOrds>>24)&0xff;

    RVAStart=PE_EXPORTHEADER_SIZE; /* start address of RVA table */
    nameRVAStart=RVAStart+numOrds*4; /* start of name table entries */
    ordinalStart=nameRVAStart+numNames*4; /* start of associated ordinal entries */
    nameSpaceStart=ordinalStart+numNames*2; /* start of actual names */

    /* store number of named exports */
    expSect->data[24]=numNames&0xff;
    expSect->data[25]=(numNames>>8)&0xff;
    expSect->data[26]=(numNames>>16)&0xff;
    expSect->data[27]=(numNames>>24)&0xff;

    /* store address of address table */
    expSect->data[28]=(RVAStart+expSect->base-imageBase)&0xff;
    expSect->data[29]=((RVAStart+expSect->base-imageBase)>>8)&0xff;
    expSect->data[30]=((RVAStart+expSect->base-imageBase)>>16)&0xff;
    expSect->data[31]=((RVAStart+expSect->base-imageBase)>>24)&0xff;

    /* store address of name table */
    expSect->data[32]=(nameRVAStart+expSect->base-imageBase)&0xff;
    expSect->data[33]=((nameRVAStart+expSect->base-imageBase)>>8)&0xff;
    expSect->data[34]=((nameRVAStart+expSect->base-imageBase)>>16)&0xff;
    expSect->data[35]=((nameRVAStart+expSect->base-imageBase)>>24)&0xff;

    /* store address of ordinal table */
    expSect->data[36]=(ordinalStart+expSect->base-imageBase)&0xff;
    expSect->data[37]=((ordinalStart+expSect->base-imageBase)>>8)&0xff;
    expSect->data[38]=((ordinalStart+expSect->base-imageBase)>>16)&0xff;
    expSect->data[39]=((ordinalStart+expSect->base-imageBase)>>24)&0xff;

    /* process numbered exports */
    for(i=0;i<expcount;i++)
    {
        if(expdefs[i].flags&EXP_ORD)
        {
            /* get current RVA */
            k=expSect->data[RVAStart+4*(expdefs[i].ordinal-minOrd)];
            k+=expSect->data[RVAStart+4*(expdefs[i].ordinal-minOrd)+1]<<8;
            k+=expSect->data[RVAStart+4*(expdefs[i].ordinal-minOrd)+2]<<16;
            k+=expSect->data[RVAStart+4*(expdefs[i].ordinal-minOrd)+3]<<24;
            if(k) /* error if already used */
            {
                printf("Duplicate export ordinal %i\n",expdefs[i].ordinal);
                exit(1);
            }
            /* get RVA of export entry */
            k=expdefs[i].pubdef->ofs+
                seglist[expdefs[i].pubdef->segnum]->base-
                imageBase;
            /* store it */
            expSect->data[RVAStart+4*(expdefs[i].ordinal-minOrd)]=k&0xff;
            expSect->data[RVAStart+4*(expdefs[i].ordinal-minOrd)+1]=(k>>8)&0xff;
            expSect->data[RVAStart+4*(expdefs[i].ordinal-minOrd)+2]=(k>>16)&0xff;
            expSect->data[RVAStart+4*(expdefs[i].ordinal-minOrd)+3]=(k>>24)&0xff;
        }
    }

    /* process non-numbered exports */
    for(i=0,j=RVAStart;i<expcount;i++)
    {
        if(!(expdefs[i].flags&EXP_ORD))
        {
            do
            {
                k=expSect->data[j];
                k+=expSect->data[j+1]<<8;
                k+=expSect->data[j+2]<<16;
                k+=expSect->data[j+3]<<24;
                if(k) j+=4;
            }
            while(k); /* move through table until we find a free spot */
            /* get RVA of export entry */
            k=expdefs[i].pubdef->ofs;
            k+=seglist[expdefs[i].pubdef->segnum]->base;
            k-=imageBase;
            /* store RVA */
            expSect->data[j]=k&0xff;
            expSect->data[j+1]=(k>>8)&0xff;
            expSect->data[j+2]=(k>>16)&0xff;
            expSect->data[j+3]=(k>>24)&0xff;
            expdefs[i].ordinal=(j-RVAStart)/4+minOrd; /* store ordinal */
            j+=4;
        }
    }

    if(numNames) /* sort name table if present */
    {
        nameList=(PPEXPREC)allocate_memory(numNames*sizeof(PEXPREC));
        j=0; /* no entries yet */
        for(i=0;i<expcount;i++)
        {
            if(expdefs[i].exp_name && expdefs[i].exp_name[0])
            {
                /* make entry in name list */
                nameList[j]=&expdefs[i];
                j++;
            }
        }
        /* sort them into order */
        for(i=1;i<numNames;i++)
        {
            curName=nameList[i];
            for(j=i-1;j>=0;j--)
            {
                /* break out if we're above previous entry */
                if(strcmp(curName->exp_name,nameList[j]->exp_name)>=0)
                {
                    break;
                }
                /* else move entry up */
                nameList[j+1]=nameList[j];
            }
            j++; /* move to one after better entry */
            nameList[j]=curName; /* insert current entry into position */
        }
        /* and store */
        for(i=0;i<numNames;i++)
        {
            /* store ordinal */
            expSect->data[ordinalStart]=(nameList[i]->ordinal-minOrd)&0xff;
            expSect->data[ordinalStart+1]=((nameList[i]->ordinal-minOrd)>>8)&0xff;
            ordinalStart+=2;
            /* store name RVA */
            expSect->data[nameRVAStart]=(nameSpaceStart+expSect->base-imageBase)&0xff;
            expSect->data[nameRVAStart+1]=((nameSpaceStart+expSect->base-imageBase)>>8)&0xff;
            expSect->data[nameRVAStart+2]=((nameSpaceStart+expSect->base-imageBase)>>16)&0xff;
            expSect->data[nameRVAStart+3]=((nameSpaceStart+expSect->base-imageBase)>>24)&0xff;
            nameRVAStart+=4;
            /* store name */
            for(j=0;nameList[i]->exp_name[j];j++,nameSpaceStart++)
            {
                expSect->data[nameSpaceStart]=nameList[i]->exp_name[j];
            }
            /* store NULL */
            expSect->data[nameSpaceStart]=0;
            nameSpaceStart++;
        }
    }

    /* store library name */
    for(j=0;j<namelen;j++)
    {
        expSect->data[nameSpaceStart+j]=name[j];
    }
    if(namelen)
    {
        expSect->data[nameSpaceStart+j]=0;
        /* store name RVA */
        expSect->data[12]=(nameSpaceStart+expSect->base-imageBase)&0xff;
        expSect->data[13]=((nameSpaceStart+expSect->base-imageBase)>>8)&0xff;
        expSect->data[14]=((nameSpaceStart+expSect->base-imageBase)>>16)&0xff;
        expSect->data[15]=((nameSpaceStart+expSect->base-imageBase)>>24)&0xff;
    }

    expSect->datmask=(PUCHAR)allocate_memory((expSect->length+7)/8);
    for(i=0;i<(expSect->length+7)/8;i++)
    {
        expSect->datmask[i]=0xff;
    }

    return;
}

void BuildPEResources(long sectNum,PUCHAR objectTable)
{
    long i,j;
    UINT k;
    SEG *ressect;
    RESOURCE curres;
    int numtypes,numnamedtypes;
    int numPairs,numnames,numids;
    UINT nameSize,dataSize;
    UINT tableSize,dataListSize;
    UINT namePos,dataPos,tablePos,dataListPos;
    UINT curTypePos,curNamePos,curLangPos;
    char *curTypeName,*curName;
    int curTypeId,curId;

    if((sectNum<0) || !rescount) return;

    objectTable+=PE_OBJECTENTRY_SIZE*sectNum; /* point to import object entry */
    k=objectTable[-PE_OBJECTENTRY_SIZE+20]; /* get physical start of prev object */
    k+=objectTable[-PE_OBJECTENTRY_SIZE+21]<<8;
    k+=objectTable[-PE_OBJECTENTRY_SIZE+22]<<16;
    k+=objectTable[-PE_OBJECTENTRY_SIZE+23]<<24;

    k+=objectTable[-PE_OBJECTENTRY_SIZE+16]; /* add physical length of prev object */
    k+=objectTable[-PE_OBJECTENTRY_SIZE+17]<<8;
    k+=objectTable[-PE_OBJECTENTRY_SIZE+18]<<16;
    k+=objectTable[-PE_OBJECTENTRY_SIZE+19]<<24;

    k+=fileAlign-1;
    k&=(0xffffffff-(fileAlign-1)); /* aligned */

    /* k is now physical location of this object */

    objectTable[20]=(k)&0xff; /* store physical file offset */
    objectTable[21]=(k>>8)&0xff;
    objectTable[22]=(k>>16)&0xff;
    objectTable[23]=(k>>24)&0xff;

    k=objectTable[-PE_OBJECTENTRY_SIZE+12]; /* get virtual start of prev object */
    k+=objectTable[-PE_OBJECTENTRY_SIZE+13]<<8;
    k+=objectTable[-PE_OBJECTENTRY_SIZE+14]<<16;
    k+=objectTable[-PE_OBJECTENTRY_SIZE+15]<<24;

    k+=objectTable[-PE_OBJECTENTRY_SIZE+8]; /* add virtual length of prev object */
    k+=objectTable[-PE_OBJECTENTRY_SIZE+9]<<8;
    k+=objectTable[-PE_OBJECTENTRY_SIZE+10]<<16;
    k+=objectTable[-PE_OBJECTENTRY_SIZE+11]<<24;

    /* store base address (RVA) of section */
    objectTable[12]=(k)&0xff;
    objectTable[13]=(k>>8)&0xff;
    objectTable[14]=(k>>16)&0xff;
    objectTable[15]=(k>>24)&0xff;

    ressect=outlist[sectNum];
    ressect->base=k; /* get base RVA of section */

    /* sort into type-id order */
    for(i=1;i<rescount;i++)
    {
        curres=resource[i];
        for(j=i-1;j>=0;j--)
        {
            if(resource[j].typename)
            {
                if(!curres.typename) break;
                if(wstricmp(curres.typename,resource[j].typename)>0) break;
                if(wstricmp(curres.typename,resource[j].typename)==0)
                {
                    if(resource[j].name)
                    {
                        if(!curres.name) break;
                        if(wstricmp(curres.name,resource[j].name)>0) break;
                        if(wstricmp(curres.name,resource[j].name)==0)
                        {
                            if(resource[j].languageid>curres.languageid)
                                break;
                            if(resource[j].languageid==curres.languageid)
                            {
                                printf("Error duplicate resource ID\n");
                                exit(1);
                            }
                        }
                    }
                    else
                    {
                        if(!curres.name)
                        {
                            if(curres.id>resource[j].id) break;
                            if(curres.id==resource[j].id)
                            {
                                if(resource[j].languageid>curres.languageid)
                                    break;
                                if(resource[j].languageid==curres.languageid)
                                {
                                    printf("Error duplicate resource ID\n");
                                    exit(1);
                                }
                            }
                        }
                    }
                }
            }
            else
            {
                if(!curres.typename)
                {
                    if(curres.typeid>resource[j].typeid) break;
                    if(curres.typeid==resource[j].typeid)
                    {
                        if(resource[j].name)
                        {
                            if(!curres.name) break;
                            if(wstricmp(curres.name,resource[j].name)>0) break;
                            if(wstricmp(curres.name,resource[j].name)==0)
                            {
                                if(resource[j].languageid>curres.languageid)
                                    break;
                                if(resource[j].languageid==curres.languageid)
                                {
                                    printf("Error duplicate resource ID\n");
                                    exit(1);
                                }
                            }
                        }
                        else
                        {
                            if(!curres.name)
                            {
                                if(curres.id>resource[j].id) break;
                                if(curres.id==resource[j].id)
                                {
                                    if(resource[j].languageid>curres.languageid)
                                        break;
                                    if(resource[j].languageid==curres.languageid)
                                    {
                                        printf("Error duplicate resource ID\n");
                                        exit(1);
                                    }
                                }
                            }
                        }
                    }
                }
            }
            resource[j+1]=resource[j];
        }
        j++;
        resource[j]=curres;
    }

    nameSize=0;
    dataSize=0;
    for(i=0;i<rescount;i++)
    {
        if(resource[i].typename)
        {
            nameSize+=2+2*wstrlen(resource[i].typename);
	}
        if(resource[i].name)
        {
            nameSize+=2+2*wstrlen(resource[i].name);
        }
        dataSize+=resource[i].length+3;
	dataSize&=0xfffffffc;
    }

    /* count named types */
    numnamedtypes=0;
    numPairs=rescount;
    for(i=0;i<rescount;i++)
    {
        if(!resource[i].typename) break;
        if((i>0) && !wstricmp(resource[i].typename,resource[i-1].typename))
        {
            if(resource[i].name)
            {
                if(wstricmp(resource[i].name,resource[i-1].name)==0)
                    numPairs--;
            }
            else
            {
                if(!resource[i-1].name && (resource[i].id ==resource[i-1].id))
                    numPairs--;
            }
            continue;
        }
        numnamedtypes++;
    }
    numtypes=numnamedtypes;
    for(;i<rescount;i++)
    {
        if((i>0) && !resource[i-1].typename && (resource[i].typeid==resource[i-1].typeid))
        {
            if(resource[i].name)
            {
                if(wstricmp(resource[i].name,resource[i-1].name)==0)
                    numPairs--;
            }
            else
            {
                if(!resource[i-1].name && (resource[i].id ==resource[i-1].id))
                    numPairs--;
            }
            continue;
        }
        numtypes++;
    }

    tableSize=(rescount+numtypes+numPairs)*PE_RESENTRY_SIZE+
        (numtypes+numPairs+1)*PE_RESDIR_SIZE;
    dataListSize=rescount*PE_RESDATAENTRY_SIZE;

    tablePos=0;
    dataListPos=tableSize;
    namePos=tableSize+dataListSize;
    dataPos=tableSize+nameSize+dataListSize+3;
    dataPos&=0xfffffffc;

    ressect->length=dataPos+dataSize;

    ressect->data=(PUCHAR)allocate_memory(ressect->length);

    ressect->datmask=(PUCHAR)allocate_memory((ressect->length+7)/8);

    /* empty section to start with */
    for(i=0;i<ressect->length;i++)
        ressect->data[i]=0;

    /* build master directory */
    /* store time/date of creation */
    k=(UINT)time(NULL);
    ressect->data[4]=k&0xff;
    ressect->data[5]=(k>>8)&0xff;
    ressect->data[6]=(k>>16)&0xff;
    ressect->data[7]=(k>>24)&0xff;

    ressect->data[12]=numnamedtypes&0xff;
    ressect->data[13]=(numnamedtypes>>8)&0xff;
    ressect->data[14]=(numtypes-numnamedtypes)&0xff;
    ressect->data[15]=((numtypes-numnamedtypes)>>8)&0xff;

    tablePos=16+numtypes*PE_RESENTRY_SIZE;
    curTypePos=16;
    curTypeName=NULL;
    curTypeId=-1;
    for(i=0;i<rescount;i++)
    {
        if(!(resource[i].typename && curTypeName &&
            !wstricmp(resource[i].typename,curTypeName))
            && !(!resource[i].typename && !curTypeName && curTypeId==resource[i].typeid))
        {
            if(resource[i].typename)
            {
                ressect->data[curTypePos]=(namePos)&0xff;
                ressect->data[curTypePos+1]=((namePos)>>8)&0xff;
                ressect->data[curTypePos+2]=((namePos)>>16)&0xff;
                ressect->data[curTypePos+3]=(((namePos)>>24)&0xff)|0x80;
                curTypeName=resource[i].typename;
                k=wstrlen(curTypeName);
                ressect->data[namePos]=k&0xff;
                ressect->data[namePos+1]=(k>>8)&0xff;
                namePos+=2;
                memcpy(ressect->data+namePos,curTypeName,k*2);
                namePos+=k*2;
                curTypeId=-1;
            }
            else
            {
                curTypeName=NULL;
                curTypeId=resource[i].typeid;
                ressect->data[curTypePos]=curTypeId&0xff;
                ressect->data[curTypePos+1]=(curTypeId>>8)&0xff;
                ressect->data[curTypePos+2]=(curTypeId>>16)&0xff;
                ressect->data[curTypePos+3]=(curTypeId>>24)&0xff;
            }
            ressect->data[curTypePos+4]=(tablePos)&0xff;
            ressect->data[curTypePos+5]=((tablePos)>>8)&0xff;
            ressect->data[curTypePos+6]=((tablePos)>>16)&0xff;
            ressect->data[curTypePos+7]=(((tablePos)>>24)&0x7f) | 0x80;

            numnames=numids=0;
            for(j=i;j<rescount;j++)
            {
                if(resource[i].typename)
                {
                    if(!resource[j].typename) break;
                    if(wstricmp(resource[i].typename,resource[j].typename)!=0) break;
                }
                else
                {
                    if(resource[j].typeid!=resource[i].typeid) break;
                }
                if(resource[j].name)
                {
                    if(((j>i) && (wstricmp(resource[j].name,resource[j-1].name)!=0))
                        || (j==i))
                        numnames++;
                }
                else
                {
                    if(((j>i) && (resource[j-1].name || (resource[j].id!=resource[j-1].id)))
                        || (j==i))
                        numids++;
                }
            }
	    /* store time/date of creation */
	    k=(UINT)time(NULL);
	    ressect->data[tablePos+4]=k&0xff;
	    ressect->data[tablePos+5]=(k>>8)&0xff;
	    ressect->data[tablePos+6]=(k>>16)&0xff;
	    ressect->data[tablePos+7]=(k>>24)&0xff;

            ressect->data[tablePos+12]=numnames&0xff;
            ressect->data[tablePos+13]=(numnames>>8)&0xff;
            ressect->data[tablePos+14]=numids&0xff;
            ressect->data[tablePos+15]=(numids>>8)&0xff;

            curNamePos=tablePos+PE_RESDIR_SIZE;
            curName=NULL;
            curId=-1;
            tablePos+=PE_RESDIR_SIZE+(numids+numnames)*PE_RESENTRY_SIZE;
            curTypePos+=PE_RESENTRY_SIZE;
        }
        if(!(resource[i].name && curName &&
            !wstricmp(resource[i].name,curName))
            && !(!resource[i].name && !curName && curId==resource[i].id))
        {
            if(resource[i].name)
            {
                ressect->data[curNamePos]=(namePos)&0xff;
                ressect->data[curNamePos+1]=((namePos)>>8)&0xff;
                ressect->data[curNamePos+2]=((namePos)>>16)&0xff;
                ressect->data[curNamePos+3]=(((namePos)>>24)&0xff)|0x80;
                curName=resource[i].name;
                k=wstrlen(curName);
                ressect->data[namePos]=k&0xff;
                ressect->data[namePos+1]=(k>>8)&0xff;
                namePos+=2;
                memcpy(ressect->data+namePos,curName,k*2);
                namePos+=k*2;
                curId=-1;
            }
            else
            {
                curName=NULL;
                curId=resource[i].id;
                ressect->data[curNamePos]=curId&0xff;
                ressect->data[curNamePos+1]=(curId>>8)&0xff;
                ressect->data[curNamePos+2]=(curId>>16)&0xff;
                ressect->data[curNamePos+3]=(curId>>24)&0xff;
            }
            ressect->data[curNamePos+4]=(tablePos)&0xff;
            ressect->data[curNamePos+5]=((tablePos)>>8)&0xff;
            ressect->data[curNamePos+6]=((tablePos)>>16)&0xff;
            ressect->data[curNamePos+7]=(((tablePos)>>24)&0x7f) | 0x80;

            numids=0;
            for(j=i;j<rescount;j++)
            {
                if(resource[i].typename)
                {
                    if(!resource[j].typename) break;
                    if(wstricmp(resource[i].typename,resource[j].typename)!=0) break;
                }
                else
                {
                    if(resource[j].typeid!=resource[i].typeid) break;
                }
                if(resource[i].name)
                {
                    if(!resource[j].name) break;
                    if(wstricmp(resource[j].name,resource[i].name)!=0) break;
                }
                else
                {
                    if(resource[j].id!=resource[i].id) break;
                }
                numids++;
            }
            numnames=0; /* no names for languages */
	    /* store time/date of creation */
	    k=(UINT)time(NULL);
	    ressect->data[tablePos+4]=k&0xff;
	    ressect->data[tablePos+5]=(k>>8)&0xff;
	    ressect->data[tablePos+6]=(k>>16)&0xff;
	    ressect->data[tablePos+7]=(k>>24)&0xff;

            ressect->data[tablePos+12]=numnames&0xff;
            ressect->data[tablePos+13]=(numnames>>8)&0xff;
            ressect->data[tablePos+14]=numids&0xff;
            ressect->data[tablePos+15]=(numids>>8)&0xff;

            curLangPos=tablePos+PE_RESDIR_SIZE;
            tablePos+=PE_RESDIR_SIZE+numids*PE_RESENTRY_SIZE;
            curNamePos+=PE_RESENTRY_SIZE;
        }
        ressect->data[curLangPos]=resource[i].languageid&0xff;
        ressect->data[curLangPos+1]=(resource[i].languageid>>8)&0xff;
        ressect->data[curLangPos+2]=(resource[i].languageid>>16)&0xff;
        ressect->data[curLangPos+3]=(resource[i].languageid>>24)&0xff;

        ressect->data[curLangPos+4]=(dataListPos)&0xff;
        ressect->data[curLangPos+5]=((dataListPos)>>8)&0xff;
        ressect->data[curLangPos+6]=((dataListPos)>>16)&0xff;
        ressect->data[curLangPos+7]=(((dataListPos)>>24)&0x7f);
        curLangPos+=PE_RESENTRY_SIZE;


        ressect->data[dataListPos]=(dataPos+ressect->base)&0xff;
        ressect->data[dataListPos+1]=((dataPos+ressect->base)>>8)&0xff;
        ressect->data[dataListPos+2]=((dataPos+ressect->base)>>16)&0xff;
        ressect->data[dataListPos+3]=((dataPos+ressect->base)>>24)&0xff;
        ressect->data[dataListPos+4]=resource[i].length&0xff;
        ressect->data[dataListPos+5]=(resource[i].length>>8)&0xff;
        ressect->data[dataListPos+6]=(resource[i].length>>16)&0xff;
        ressect->data[dataListPos+7]=(resource[i].length>>24)&0xff;
        memcpy(ressect->data+dataPos,resource[i].data,resource[i].length);
        dataPos+=resource[i].length+3;
	dataPos&=0xfffffffc;
        dataListPos+=PE_RESDATAENTRY_SIZE;
    }

    /* mark whole section as required output */
    for(i=0;i<(ressect->length+7)/8;i++)
        ressect->datmask[i]=0xff;

    /* update object table */
    ressect->base+=imageBase;

    k=ressect->length;
    k+=objectAlign-1;
    k&=(0xffffffff-(objectAlign-1));
    ressect->virtualSize=k;
    objectTable[8]=k&0xff; /* store virtual size (in memory) of segment */
    objectTable[9]=(k>>8)&0xff;
    objectTable[10]=(k>>16)&0xff;
    objectTable[11]=(k>>24)&0xff;

    k=ressect->length;
    objectTable[16]=(k)&0xff; /* store initialised data size */
    objectTable[17]=(k>>8)&0xff;
    objectTable[18]=(k>>16)&0xff;
    objectTable[19]=(k>>16)&0xff;

    return;
}

void getStub(PUCHAR *pstubData,UINT *pstubSize)
{
    FILE *f;
    unsigned char headbuf[0x1c];
    PUCHAR buf;
    UINT imageSize;
    UINT headerSize;
    UINT relocSize;
    UINT relocStart;
    int i;

    if(stubName)
    {
        f=fopen(stubName,"rb");
        if(!f)
        {
            printf("Unable to open stub file %s\n",stubName);
            exit(1);
        }
        if(fread(headbuf,1,0x1c,f)!=0x1c) /* try and read 0x1c bytes */
        {
            printf("Error reading from file %s\n",stubName);
            exit(1);
        }
        if((headbuf[0]!=0x4d) || (headbuf[1]!=0x5a))
        {
            printf("Stub not valid EXE file\n");
            exit(1);
        }
        /* get size of image */
        imageSize=headbuf[2]+(headbuf[3]<<8)+((headbuf[4]+(headbuf[5]<<8))<<9);
        if(imageSize%512) imageSize-=512;
        headerSize=(headbuf[8]+(headbuf[9]<<8))<<4;
        relocSize=(headbuf[6]+(headbuf[7]<<8))<<2;
        imageSize-=headerSize;
        printf("imageSize=%i\n",imageSize);
        printf("header=%i\n",headerSize);
        printf("reloc=%i\n",relocSize);

        /* allocate buffer for load image */
        buf=(PUCHAR)allocate_memory(imageSize+0x40+((relocSize+0xf)&0xfffffff0));
        /* copy header */
        for(i=0;i<0x1c;i++) buf[i]=headbuf[i];

        relocStart=headbuf[0x18]+(headbuf[0x19]<<8);
        /* load relocs */
        fseek(f,relocStart,SEEK_SET);
        if(fread(buf+0x40,1,relocSize,f)!=relocSize)
        {
            printf("Error reading from file %s\n",stubName);
            exit(1);
        }

        /* paragraph align reloc size */
        relocSize+=0xf;
        relocSize&=0xfffffff0;

        /* move to start of data */
        fseek(f,headerSize,SEEK_SET);
        /* new header is 4 paragraphs long + relocSize*/
        relocSize>>=4;
        relocSize+=4;
        buf[8]=relocSize&0xff;
        buf[9]=(relocSize>>8)&0xff;
        headerSize=relocSize<<4;
        /* load data into correct position */
        if(fread(buf+headerSize,1,imageSize,f)!=imageSize)
        {
            printf("Error reading from file %s\n",stubName);
            exit(1);
        }
        /* relocations start at 0x40 */
        buf[0x18]=0x40;
        buf[0x19]=0;
        imageSize+=headerSize; /* total file size */
        /* store pointer and size */
        (*pstubData)=buf;
        (*pstubSize)=imageSize;
        i=imageSize%512; /* size mod 512 */
        imageSize=(imageSize+511)>>9; /* number of 512-byte pages */
        buf[2]=i&0xff;
        buf[3]=(i>>8)&0xff;
        buf[4]=imageSize&0xff;
        buf[5]=(imageSize>>8)&0xff;
    }
    else
    {
        (*pstubData)=defaultStub;
        (*pstubSize)=defaultStubSize;
    }
}

void OutputWin32file(byte_ptr outname)
BeginDeclarations
    bit_32 i,j,k;
    bit_32 started;
    bit_32 lastout;
    byte_ptr headbuf;
    PE_header_ptr pehead ;
#define PEHead (*pehead)
    PE_object_ptr peobject ;
#define PEObject (*peobject)
    byte_ptr stubData;
    FILE *outfile;
    bit_32 headerSize;
    bit_32 headerVirtSize;
    bit_32 stubSize;
    bit_32 nameIndex;
    bit_32 sectionStart;
    bit_32 headerStart;
    bit_32 relocSectNum,importSectNum,exportSectNum,resourceSectNum;
    bit_32 codeBase=0;
    bit_32 dataBase=0;
    bit_32 codeSize=0;
    bit_32 dataSize=0;
EndDeclarations
BeginCode
    errcount=0;

    /* allocate section entries for imports, exports and relocs if required */
    If n_imports
      Then
        importSectNum=createOutputSection("imports",
            WINF_INITDATA | WINF_SHARED | WINF_READABLE);
      Else
        importSectNum=-1;
      EndIf ;

    If n_exports
      Then
        exportSectNum=createOutputSection("exports",
            WINF_INITDATA | WINF_SHARED | WINF_READABLE);
      Else
        exportSectNum=-1;
      EndIf ;

    /* Windows NT requires a reloc section to relocate image files, even */
    /* if it contains no actual fixups */
    relocSectNum=createOutputSection("relocs",
        WINF_INITDATA | WINF_SHARED | WINF_DISCARDABLE | WINF_READABLE);

    If n_resources
      Then
        resourceSectNum=createOutputSection("resource",
            WINF_INITDATA | WINF_SHARED | WINF_READABLE);
      Else
        resourceSectNum=-1;
      Endif ;

    /* build header */
    getStub(&stubData,&stubSize);

    headerStart=stubSize; /* get start of PE header */
    headerStart+=7;
    headerStart&=0xfffffff8; /* align PE header to 8 byte boundary */

    headerSize=PE_HEADBUF_SIZE+outcount*PE_OBJECTENTRY_SIZE+stubSize;
    headerVirtSize=headerSize+(objectAlign-1);
    headerVirtSize&=(0xffffffff-(objectAlign-1));
    headerSize+=(fileAlign-1);
    headerSize&=(0xffffffff-(fileAlign-1));


    headbuf=allocate_memory(headerSize);

    memset(headbuf,0,headerSize);

    memcpy(headbuf,stubData,stubSize ) ;

    *(bit_32_ptr)( headbuf + 0x3c) = headerStart ; /* Pointer to PE header */
    pehead = headbuf + headerStart ;

    PEHead.sig = 0x00004550 ; /* PE__ */
    PEhead.cpu_type = PE_INTEL386 ;
    /* store time/date of creation */
    PEHead.time=(bit_32)time(NULL);
    PEHead.nt_hdr_size = PE_OPTIONAL_HEADER_SIZE ;

    i=PE_FILE_EXECUTABLE | PE_FILE_32BIT;                   /* get flags */
    If buildDll
      Then
        i|= PE_FILE_LIBRARY;                /* if DLL, flag it */
      Else ;
    PEHead.flags = i ;

    PEHead.magic = PE_MAGICNUM ;

    PEHead.image_base = imageBase ;

    PEHead.file_align = fileAlign ;
    PEHead.object_align = objectAlign ;

    PEHead.os_major_version = osMajor ;
    PEHead.os_minor_version = osMinor ;
    PEHead.subsys_major_version = subsysMajor ;
    PEHead.subsys_minor_version = subsysMinor ;
    PEHead.subsystem = subSystem ;

    PEHead.num_rvas = PE_NUM_VAS ;
    PEHead.header_size = headerSize ;
    PEHead.heap_size = heapSize ;
    PEHead.heap_commit = heapCommitSize ;
    PEHead.stack_size = stackSize ;
    PEHead.stack_commit = stackCommit ;


    /* shift segment start addresses up into place and build section headers */
    sectionStart=headerSize;
    j=headerStart+PE_HEADBUF_SIZE;
		peobject = headbuf + headerStart + PE_HEADBUF_SIZE ;

    For i=0;i<outcount;i++,peobject++
      BeginFor
        nameIndex=outlist[i]->nameindex;
        If nameIndex GreaterThanOrEqualTo 0
          Then
						j = strlen(namelist[nameIndex]) ;
						j = j < 8 ? j : 8 ;
						memcpy(PEObject.name,namelist[nameIndex],j) ;
          EndIf ;
				PEObject.virtual_size = k = outlist[i]->virtualSize ;

        if Not padsegments /* if not padding segments, reduce space consumption */
          Then 
						PEObject.raw_size = outlist[i].highest_uninitialized_byte ;
				  Else
            PEObject.raw_size = k ;
          EndIf ;

				PEObject.raw_ptr = sectionStart ;


        k+=fileAlign-1;
        k&=(0xffffffff-(fileAlign-1)); /* aligned initialised length */

        sectionStart+=k; /* update section start address for next section */

        outlist[i]->base+=headerVirtSize;
				PEObject.virtual_address = outlist[i]->base ;
				outlist[i]->base += imageBase ;

        PEObject.flags = =(outlist[i]->winFlags ^ WINF_NEG_FLAGS) & WINF_IMAGE_FLAGS; /* get characteristice for section */
			EndFor ;

    PEHead.num_object = outcount ;

    /* build import, export and relocation sections */
		peobject = headbuf + headerStart + PE_HEADBUF_SIZE ;
    BuildPEImports(importSectNum,peObject,peHead);
    BuildPEExports(exportSectNum,peobject,pehead,outname);
    BuildPERelocs(relocSectNum,peobject,pehead);
    BuildPEResources(resourceSectNum,peobject,pehead);

		
    If errcount
      Then
        exit(1);
      Endif ;

    If start_address_found IsTrue
     Then
      fixup                 = start_address;
			PEHead.entry_point    = target() - imageBase ; /* RVA */
      If buildDll  /* if library */
        Then
          /* flag that entry point should always be called */
				  PEHead.dll_flags = 0xf ;
			  EndIf ;
     Else  /* No start address found. */
      linker_error(4,"No start address.\n");
     EndIf;

    if(relocSectNum>=0) /* if relocs, add section entry */
    {
        headbuf[headerStart+PE_FIXUPRVA]=(outlist[relocSectNum]->base-imageBase)&0xff;
        headbuf[headerStart+PE_FIXUPRVA+1]=((outlist[relocSectNum]->base-imageBase)>>8)&0xff;
        headbuf[headerStart+PE_FIXUPRVA+2]=((outlist[relocSectNum]->base-imageBase)>>16)&0xff;
        headbuf[headerStart+PE_FIXUPRVA+3]=((outlist[relocSectNum]->base-imageBase)>>24)&0xff;
        headbuf[headerStart+PE_FIXUPSIZE]=(outlist[relocSectNum]->length)&0xff;
        headbuf[headerStart+PE_FIXUPSIZE+1]=(outlist[relocSectNum]->length>>8)&0xff;
        headbuf[headerStart+PE_FIXUPSIZE+2]=(outlist[relocSectNum]->length>>16)&0xff;
        headbuf[headerStart+PE_FIXUPSIZE+3]=(outlist[relocSectNum]->length>>24)&0xff;
    }

    if(exportSectNum>=0) /* if relocs, add section entry */
    {
        headbuf[headerStart+PE_EXPORTRVA]=(outlist[exportSectNum]->base-imageBase)&0xff;
        headbuf[headerStart+PE_EXPORTRVA+1]=((outlist[exportSectNum]->base-imageBase)>>8)&0xff;
        headbuf[headerStart+PE_EXPORTRVA+2]=((outlist[exportSectNum]->base-imageBase)>>16)&0xff;
        headbuf[headerStart+PE_EXPORTRVA+3]=((outlist[exportSectNum]->base-imageBase)>>24)&0xff;
        headbuf[headerStart+PE_EXPORTSIZE]=(outlist[exportSectNum]->length)&0xff;
        headbuf[headerStart+PE_EXPORTSIZE+1]=(outlist[exportSectNum]->length>>8)&0xff;
        headbuf[headerStart+PE_EXPORTSIZE+2]=(outlist[exportSectNum]->length>>16)&0xff;
        headbuf[headerStart+PE_EXPORTSIZE+3]=(outlist[exportSectNum]->length>>24)&0xff;
    }

    if(resourceSectNum>=0) /* if relocs, add section entry */
    {
        headbuf[headerStart+PE_RESOURCERVA]=(outlist[resourceSectNum]->base-imageBase)&0xff;
        headbuf[headerStart+PE_RESOURCERVA+1]=((outlist[resourceSectNum]->base-imageBase)>>8)&0xff;
        headbuf[headerStart+PE_RESOURCERVA+2]=((outlist[resourceSectNum]->base-imageBase)>>16)&0xff;
        headbuf[headerStart+PE_RESOURCERVA+3]=((outlist[resourceSectNum]->base-imageBase)>>24)&0xff;
        headbuf[headerStart+PE_RESOURCESIZE]=(outlist[resourceSectNum]->length)&0xff;
        headbuf[headerStart+PE_RESOURCESIZE+1]=(outlist[resourceSectNum]->length>>8)&0xff;
        headbuf[headerStart+PE_RESOURCESIZE+2]=(outlist[resourceSectNum]->length>>16)&0xff;
        headbuf[headerStart+PE_RESOURCESIZE+3]=(outlist[resourceSectNum]->length>>24)&0xff;
    }

    j=headerStart+PE_HEADBUF_SIZE+(outcount-1)*PE_OBJECTENTRY_SIZE;

    i=headbuf[j+12];        /* get base of last section - image base */
    i+=headbuf[j+13]<<8;
    i+=headbuf[j+14]<<16;
    i+=headbuf[j+15]<<24;

    i+=headbuf[j+8];        /* add virtual size of section */
    i+=headbuf[j+9]<<8;
    i+=headbuf[j+10]<<16;
    i+=headbuf[j+11]<<24;

    headbuf[headerStart+PE_IMAGESIZE]=i&0xff;
    headbuf[headerStart+PE_IMAGESIZE+1]=(i>>8)&0xff;
    headbuf[headerStart+PE_IMAGESIZE+2]=(i>>16)&0xff;
    headbuf[headerStart+PE_IMAGESIZE+3]=(i>>24)&0xff;

    headbuf[headerStart+PE_CODEBASE]=codeBase&0xff;
    headbuf[headerStart+PE_CODEBASE+1]=(codeBase>>8)&0xff;
    headbuf[headerStart+PE_CODEBASE+2]=(codeBase>>16)&0xff;
    headbuf[headerStart+PE_CODEBASE+3]=(codeBase>>24)&0xff;

    headbuf[headerStart+PE_DATABASE]=dataBase&0xff;
    headbuf[headerStart+PE_DATABASE+1]=(dataBase>>8)&0xff;
    headbuf[headerStart+PE_DATABASE+2]=(dataBase>>16)&0xff;
    headbuf[headerStart+PE_DATABASE+3]=(dataBase>>24)&0xff;

    headbuf[headerStart+PE_CODESIZE]=codeSize&0xff;
    headbuf[headerStart+PE_CODESIZE+1]=(codeSize>>8)&0xff;
    headbuf[headerStart+PE_CODESIZE+2]=(codeSize>>16)&0xff;
    headbuf[headerStart+PE_CODESIZE+3]=(codeSize>>24)&0xff;

    headbuf[headerStart+PE_INITDATASIZE]=dataSize&0xff;
    headbuf[headerStart+PE_INITDATASIZE+1]=(dataSize>>8)&0xff;
    headbuf[headerStart+PE_INITDATASIZE+2]=(dataSize>>16)&0xff;
    headbuf[headerStart+PE_INITDATASIZE+3]=(dataSize>>24)&0xff;

    /* zero out section start for all zero-length segments */
    j=headerStart+PE_HEADBUF_SIZE;
    for(i=0;i<outcount;i++,j+=PE_OBJECTENTRY_SIZE)
    {
        /* check if size in file is zero */
        k=headbuf[j+16]|headbuf[j+17]|headbuf[j+18]|headbuf[j+19];
        if(!k)
        {
            /* if so, zero section start */
            headbuf[j+20]=headbuf[j+21]=headbuf[j+22]=headbuf[j+23]=0;
        }
    }

    if(errcount!=0)
    {
        exit(1);
    }

    outfile=fopen(outname,"wb");
    if(!outfile)
    {
        printf("Error writing to file %s\n",outname);
        exit(1);
    }

    for(i=0;i<headerSize;i++)
    {
        fputc(headbuf[i],outfile);
    }

    started=lastout=imageBase+headerVirtSize;

    for(i=0;i<outcount;i++)
    {
        if(outlist[i] && ((outlist[i]->attr&SEG_ALIGN) !=SEG_ABS))
        {
            /* ensure section is aligned to file-Align */
            while(ftell(outfile)&(fileAlign-1))
            {
                fputc(0,outfile);
            }
            if(started>outlist[i]->base)
            {
                printf("Segment overlap\n");
                printf("Next addr=%08X,base=%08X\n",started,outlist[i]->base);
                fclose(outfile);
                exit(1);
            }
            if(padsegments)
            {
                while(started<outlist[i]->base)
                {
                    fputc(0,outfile);
                    started++;
                }
            }
            else
            {
                started=outlist[i]->base;
            }
            for(j=0;j<outlist[i]->length;j++)
            {
                if(GetNbit(outlist[i]->datmask,j))
                {
                    for(;lastout<started;lastout++)
                    {
                        fputc(0,outfile);
                    }
                    fputc(outlist[i]->data[j],outfile);
                    lastout=started+1;
                }
                else if(padsegments)
                {
                    fputc(0,outfile);
                    lastout=started+1;
                }
                started++;
            }
            started=lastout=outlist[i]->base+outlist[i]->virtualSize;
        }
    }

    fclose(outfile);
EndCode
#undef PEObject
#undef PEHead