home *** CD-ROM | disk | FTP | other *** search
/ io Programmo 40 / IOPROG_40.ISO / SOFT / NETFrameworkSDK.exe / comsdk.cab / samples1.exe / smc / PEwrite.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2000-06-23  |  64.5 KB  |  2,249 lines

  1. /*****************************************************************************/
  2.  
  3. #include "smcPCH.h"
  4. #pragma hdrstop
  5.  
  6. #include <time.h>
  7. #include <sys/types.h>
  8. #include <sys/stat.h>
  9.  
  10. /*****************************************************************************
  11.  *
  12.  *  Return the size of the hint/name table entry for the given name.
  13.  */
  14.  
  15. inline
  16. size_t              hintNameSize(WPEname name)
  17. {
  18.     /* Is this a "real" name or is it an import by ordinal? */
  19.  
  20.     if  (*name->PEnmSpelling() == '#')
  21.     {
  22.         return 0;
  23.     }
  24.     else
  25.     {
  26.         return  2 + (name->PEnmNlen + 2) & ~1;
  27.     }
  28. }
  29.  
  30. /*****************************************************************************
  31.  *
  32.  *  Initialize the name hash table.
  33.  */
  34.  
  35. void                WPEhashTab::WPEhashInit(Compiler         comp,
  36.                                             norls_allocator *alloc,
  37.                                             unsigned         count)
  38. {
  39.     WPEname *       buck;
  40.     size_t          size;
  41.  
  42.     /* Figure out the size of the bucket table and allocate/clear it */
  43.  
  44.     size = count * sizeof(*buck);
  45.     buck = (WPEname*)alloc->nraAlloc(size);
  46.     memset(buck, 0, size);
  47.  
  48.     /* Initialize all the other fields */
  49.  
  50.     WPEhashSize   = count;
  51.     WPEhashMask   = count - 1;
  52.     WPEhashComp   = comp;
  53.     WPEhashAlloc  = alloc;
  54.     WPEhashTable  = buck;
  55.     WPEhashStrLen = 0;
  56. }
  57.  
  58. /*****************************************************************************
  59.  *
  60.  *  Find/add the given name to the import name table ('owner' specifies the
  61.  *  DLL that the import belongs to). The value at '*isNewPtr' will be set to
  62.  *  true if the name was not in the table and has been added.
  63.  */
  64.  
  65. WPEndef             WPEhashTab::WPEhashName(const char *name,
  66.                                             WPEimpDLL   owner, bool *isNewPtr)
  67. {
  68.     bool            isNew;
  69.  
  70.     WPEname         nameEnt;
  71.     WPEndef         nameDsc;
  72.  
  73.     assert(owner);
  74.  
  75.     /* Look for an existing entry that matches the name */
  76.  
  77.     nameEnt = WPEhashName(name, &isNew);
  78.  
  79.     if  (!isNew && (nameEnt->PEnmFlags & PENMF_IMP_NAME))
  80.     {
  81.         /* Existing import - look for a matching entry on the owning DLL */
  82.  
  83.         for (nameDsc = nameEnt->PEnmDefs;
  84.              nameDsc;
  85.              nameDsc = nameDsc->PEndNext)
  86.         {
  87.             assert(nameDsc->PEndName == nameEnt);
  88.  
  89.             if  (nameDsc->PEndDLL == owner)
  90.             {
  91.                 *isNewPtr = false;
  92.  
  93.                 return  nameDsc;
  94.             }
  95.         }
  96.     }
  97.     else
  98.     {
  99.         /* New import - record the name's offset within the name/hint table */
  100.  
  101.         nameEnt->PEnmOffs   = WPEhashStrLen;
  102.  
  103.         /* Remember that this entry is an import */
  104.  
  105.         nameEnt->PEnmFlags |= PENMF_IMP_NAME;
  106.  
  107.         /* Update the total name table size */
  108.  
  109.         WPEhashStrLen += hintNameSize(nameEnt);
  110.     }
  111.  
  112.     /* Add a new DLL to the list of import definitions */
  113.  
  114.     nameDsc = (WPEndef)WPEhashAlloc->nraAlloc(sizeof(*nameDsc));
  115.  
  116.     nameDsc->PEndName      = nameEnt;
  117.  
  118.     nameDsc->PEndNext      = nameEnt->PEnmDefs;
  119.                              nameEnt->PEnmDefs = nameDsc;
  120.  
  121.     nameDsc->PEndDLL       = owner;
  122.  
  123.     /* Append to the DLL's linked list of imports */
  124.  
  125.     nameDsc->PEndNextInDLL = NULL;
  126.  
  127.     if  (owner->PEidImpList)
  128.         owner->PEidImpLast->PEndNextInDLL = nameDsc;
  129.     else
  130.         owner->PEidImpList                = nameDsc;
  131.  
  132.     owner->PEidImpLast = nameDsc;
  133.  
  134.     /* Tell the caller that we've create a new import entry */
  135.  
  136.     *isNewPtr = true;
  137.  
  138.     return  nameDsc;
  139. }
  140.  
  141. /*****************************************************************************
  142.  *
  143.  *  Find/add the given name to the import name table. The value at '*isNewPtr'
  144.  *  will be set to true if the name was not in the table and has been added.
  145.  */
  146.  
  147. WPEname             WPEhashTab::WPEhashName(const char *name, bool *isNewPtr)
  148. {
  149.     WPEname    *    lastPtr;
  150.     unsigned        hash;
  151.     WPEname         nm;
  152.     size_t          sz;
  153.  
  154.     size_t          nlen = strlen(name);
  155.     unsigned        hval = hashTab::hashComputeHashVal(name);
  156.  
  157.     /* Mask the appropriate bits from the hash value */
  158.  
  159.     hash = hval & WPEhashMask;
  160.  
  161.     /* Search the hash table for an existing match */
  162.  
  163.     lastPtr = &WPEhashTable[hash];
  164.  
  165.     for (;;)
  166.     {
  167.         nm = *lastPtr;
  168.         if  (!nm)
  169.             break;
  170.  
  171.         /* Check whether the hash value and identifier lengths match */
  172.  
  173.         if  (nm->PEnmHash == hval && nm->PEnmNlen == nlen)
  174.         {
  175.             if  (!memcmp(nm->PEnmName, name, nlen+1))
  176.             {
  177.                 *isNewPtr = false;
  178.                 return  nm;
  179.             }
  180.         }
  181.  
  182.         lastPtr = &nm->PEnmNext;
  183.     }
  184.  
  185.     /* Figure out the size to allocate */
  186.  
  187.     sz  = sizeof(*nm);
  188.  
  189.     /* Include space for name string + terminating null and round the size */
  190.  
  191.     sz +=   sizeof(int) + nlen;
  192.     sz &= ~(sizeof(int) - 1);
  193.  
  194.     /* Allocate space for the identifier */
  195.  
  196.     nm = (WPEname)WPEhashAlloc->nraAlloc(sz);
  197.  
  198.     /* Insert the identifier into the hash list */
  199.  
  200.     *lastPtr = nm;
  201.  
  202.     /* Fill in the identifier record */
  203.  
  204.     nm->PEnmNext   = NULL;
  205.     nm->PEnmFlags  = 0;
  206.     nm->PEnmHash   = hval;
  207.     nm->PEnmNlen   = nlen;
  208.     nm->PEnmDefs   = NULL;
  209.  
  210.     /* Copy the name string */
  211.  
  212.     memcpy(nm->PEnmName, name, nlen+1);
  213.  
  214.     *isNewPtr = true;
  215.  
  216.     return  nm;
  217. }
  218.  
  219. /*****************************************************************************
  220.  *
  221.  *  Add an import to the import tables. Returns a cookie for the import that
  222.  *  can later be used to obtain the actual address of the corresponding IAT
  223.  *  entry.
  224.  */
  225.  
  226. void    *           writePE::WPEimportAdd(const char *DLLname,
  227.                                           const char *impName)
  228. {
  229.     WPEname         nameDLL;
  230.     WPEndef         nameImp;
  231.     WPEimpDLL       DLLdesc;
  232.     bool            newName;
  233.  
  234.     /* Hash the DLL name first */
  235.  
  236.     nameDLL = WPEimpHash->WPEhashName(DLLname, &newName);
  237.  
  238.     /* Look for an existing DLL entry with a matching name */
  239.  
  240.     if  (newName)
  241.     {
  242.         /* New DLL name - make sure we update the total string length */
  243.  
  244.         WPEimpDLLstrLen += (nameDLL->PEnmNlen + 1) & ~1;
  245.     }
  246.     else
  247.     {
  248.         for (DLLdesc = WPEimpDLLlist; DLLdesc; DLLdesc = DLLdesc->PEidNext)
  249.         {
  250.             if  (DLLdesc->PEidName == nameDLL)
  251.                 goto GOT_DSC;
  252.         }
  253.     }
  254.  
  255.     /* The DLL is not known, add a new entry for it */
  256.  
  257.     DLLdesc = (WPEimpDLL)WPEalloc->nraAlloc(sizeof(*DLLdesc));
  258.  
  259.     DLLdesc->PEidName    = nameDLL;
  260.     DLLdesc->PEidIndex   = WPEimpDLLcnt++;
  261.     DLLdesc->PEidImpCnt  = 0;
  262.     DLLdesc->PEidImpList =
  263.     DLLdesc->PEidImpLast = NULL;
  264.     DLLdesc->PEidNext    = NULL;
  265.  
  266.     /* Append the DLL entry to the end of the DLL list */
  267.  
  268.     if  (WPEimpDLLlast)
  269.         WPEimpDLLlast->PEidNext = DLLdesc;
  270.     else
  271.         WPEimpDLLlist           = DLLdesc;
  272.  
  273.     WPEimpDLLlast = DLLdesc;
  274.  
  275. GOT_DSC:
  276.  
  277.     /* We've got the DLL entry, now look for an existing import from it */
  278.  
  279.     nameImp = WPEimpHash->WPEhashName(impName, DLLdesc, &newName);
  280.  
  281.     if  (newName)
  282.     {
  283.         /* This is a new import, make a note of it */
  284.  
  285.         nameImp->PEndIndex = DLLdesc->PEidImpCnt++;
  286.     }
  287.  
  288.     return  nameImp;
  289. }
  290.  
  291. /*****************************************************************************
  292.  *
  293.  *  The following maps a section id to its name string.
  294.  */
  295.  
  296. const   char        writePE::WPEsecNames[PE_SECT_count][IMAGE_SIZEOF_SHORT_NAME] =
  297. {
  298.     ".text",
  299.     ".data",
  300.     ".rdata",
  301.     ".rsrc",
  302.     ".reloc",
  303. };
  304.  
  305. const   char    *   writePE::WPEsecName(WPEstdSects sect)
  306. {
  307.     assert(sect < PE_SECT_count);
  308.  
  309.     assert(strcmp(WPEsecNames[PE_SECT_text ], ".text" ) == 0);
  310.     assert(strcmp(WPEsecNames[PE_SECT_data ], ".data" ) == 0);
  311.     assert(strcmp(WPEsecNames[PE_SECT_rdata], ".rdata") == 0);
  312.     assert(strcmp(WPEsecNames[PE_SECT_rsrc ], ".rsrc" ) == 0);
  313.     assert(strcmp(WPEsecNames[PE_SECT_reloc], ".reloc") == 0);
  314.  
  315.     return  WPEsecNames[sect];
  316. }
  317.  
  318. /*****************************************************************************
  319.  *
  320.  *  Initialize an instance of the PE writer for the specified output file,
  321.  *  using the given memory allocator. Returns false on success.
  322.  */
  323.  
  324. bool                writePE::WPEinit(Compiler comp, norls_allocator*alloc)
  325. {
  326.     unsigned        offs;
  327.  
  328.     static
  329.     BYTE            entryCode[16] =
  330.     {
  331.         0xFF, 0x25
  332.     };
  333.  
  334.     /* We don't know the name of the output file yet */
  335.  
  336. #ifndef NDEBUG
  337.     WPEoutFnam  = NULL;
  338. #endif
  339.  
  340.     /* Initialize/clear/record various things */
  341.  
  342.     WPEcomp     = comp;
  343.     WPEalloc    = alloc;
  344.  
  345.     WPEsectCnt  = 0;
  346.  
  347.     memset(&WPEsections, 0, sizeof(WPEsections));
  348.     memset(&WPEsecTable, 0, sizeof(WPEsecTable));
  349.  
  350. #ifdef  DEBUG
  351.     WPEstrPoolBase = 0xBEEFCAFE;
  352. #endif
  353.  
  354.     /* Create the standard sections */
  355.  
  356.     WPEaddSection(PE_SECT_text , 0, MAX_PE_TEXT_SIZE);
  357.     WPEaddSection(PE_SECT_rdata, 0, MAX_PE_RDTA_SIZE);
  358.     WPEaddSection(PE_SECT_data , 0, MAX_PE_DATA_SIZE);
  359.  
  360.     /* If we're creating a DLL, we'll need to output relocations */
  361.  
  362.     if  (comp->cmpConfig.ccOutDLL)
  363.         WPEaddSection(PE_SECT_reloc, 0, 0);
  364.  
  365.     /* Initialize the import table logic */
  366.  
  367.     WPEimportInit();
  368.  
  369.     /* Initialize the RC file import logic */
  370.  
  371.     WPEinitRCimp();
  372.  
  373.     /* Add the appropriate import for the entry point */
  374.  
  375.     WPEcorMain = WPEimportAdd("MSCOREE.DLL", comp->cmpConfig.ccOutDLL ? "_CorDllMain"
  376.                                                                       : "_CorExeMain");
  377.  
  378.     /* Reserve space for the entry point code */
  379.  
  380.     offs = WPEsecAddData(PE_SECT_text, entryCode, sizeof(entryCode)); assert(offs == 0);
  381.  
  382.     WPEdebugDirDataSize = 0;
  383.     WPEdebugDirSize     = 0;
  384.     WPEdebugDirData     = NULL;
  385.  
  386.     return  false;
  387. }
  388.  
  389. /*****************************************************************************
  390.  *
  391.  *  Set the name of the output file, this function has to be called (and at the
  392.  *  right time) if an output file is to be generated!
  393.  */
  394.  
  395. void                writePE::WPEsetOutputFileName(const char *outfile)
  396. {
  397.     char    *       buff;
  398.  
  399.     assert(WPEoutFnam == NULL);
  400.  
  401.     /* Make a durable copy of the file name, can't trust those callers */
  402.  
  403.     WPEoutFnam = buff = (char *)WPEalloc->nraAlloc(roundUp(strlen(outfile) + 1));
  404.  
  405.     strcpy(buff, outfile);
  406. }
  407.  
  408. /*****************************************************************************
  409.  *
  410.  *  Add a new section with the given name to the PE file.
  411.  */
  412.  
  413. void                writePE::WPEaddSection(WPEstdSects sect, unsigned attrs,
  414.                                                              size_t   maxSz)
  415. {
  416.     BYTE          * buff;
  417.     PEsection       sec;
  418.  
  419.     assert(WPEsectCnt < PEmaxSections);
  420.     sec = WPEsections + WPEsectCnt++;
  421.  
  422.     /* Make sure the max. size is rounded */
  423.  
  424.     assert((maxSz % OS_page_size) == 0);
  425.  
  426.     /* Allocate the uncommitted buffer */
  427.  
  428.     buff = maxSz ? (BYTE *)VirtualAlloc(NULL, maxSz, MEM_RESERVE, PAGE_READWRITE)
  429.                  : NULL;
  430.  
  431.     /* Initialize the section state */
  432.  
  433.     sec->PEsdBase     =
  434.     sec->PEsdNext     = buff;
  435.     sec->PEsdLast     = buff;
  436.     sec->PEsdEndp     = buff + maxSz;
  437.  
  438.     sec->PEsdRelocs   = NULL;
  439.  
  440. #ifdef  DEBUG
  441.     sec->PEsdIndex    = sect;
  442.     sec->PEsdFinished = false;
  443. #endif
  444.  
  445.     /* Record the entry in the table */
  446.  
  447.     WPEsecTable[sect] = sec;
  448. }
  449.  
  450. /*****************************************************************************
  451.  *
  452.  *  Reserve a given amount of space in the specified section.
  453.  */
  454.  
  455. unsigned            writePE::WPEsecRsvData(WPEstdSects sect, size_t         size,
  456.                                                              size_t         align,
  457.                                                          OUT memBuffPtr REF outRef)
  458. {
  459.     PEsection       sec = WPEgetSection(sect);
  460.  
  461.     unsigned        ofs;
  462.     BYTE        *   nxt;
  463.  
  464.     assert(align ==  1 ||
  465.            align ==  2 ||
  466.            align ==  4 ||
  467.            align ==  8 ||
  468.            align == 16);
  469.  
  470.     /* Compute the offset of the new data */
  471.  
  472.     ofs = sec->PEsdNext - sec->PEsdBase;
  473.  
  474.     /* Do we need to align the allocation? */
  475.  
  476.     if  (align > 1)
  477.     {
  478.         /* Pad if necessary */
  479.  
  480.         if  (ofs & (align - 1))
  481.         {
  482.             WPEsecRsvData(sect, align - (ofs & (align - 1)), 1, outRef);
  483.  
  484.             ofs = sec->PEsdNext - sec->PEsdBase;
  485.  
  486.             assert((ofs & (align - 1)) == 0);
  487.         }
  488.     }
  489.  
  490.     /* See if we have enough committed space in the buffer */
  491.  
  492.     nxt = sec->PEsdNext + size;
  493.  
  494.     if  (nxt > sec->PEsdLast)
  495.     {
  496.         size_t          tmp;
  497.         BYTE    *       end;
  498.  
  499.         /* Round up the desired end-point */
  500.  
  501.         tmp  = ofs + size;
  502.         tmp +=  (OS_page_size - 1);
  503.         tmp &= ~(OS_page_size - 1);
  504.  
  505.         end  = sec->PEsdBase + tmp;
  506.  
  507.         /* Make sure we're not at the end of the buffer */
  508.  
  509.         if  (end > sec->PEsdEndp)
  510.             WPEcomp->cmpFatal(ERRnoMemory);
  511.  
  512.         /* Commit some more memory */
  513.  
  514.         if  (!VirtualAlloc(sec->PEsdLast, end - sec->PEsdLast, MEM_COMMIT, PAGE_READWRITE))
  515.             WPEcomp->cmpFatal(ERRnoMemory);
  516.  
  517.         /* Update the 'last' pointer */
  518.  
  519.         sec->PEsdLast = end;
  520.     }
  521.  
  522.     /* Return the address of the first byte to the caller and update it */
  523.  
  524.     outRef = sec->PEsdNext;
  525.              sec->PEsdNext = nxt;
  526.  
  527.     return  ofs;
  528. }
  529.  
  530. /*****************************************************************************
  531.  *
  532.  *  Append the given blob of data to the specified section.
  533.  */
  534.  
  535. unsigned            writePE::WPEsecAddData(WPEstdSects sect, genericBuff data,
  536.                                                              size_t      size)
  537. {
  538.     memBuffPtr      dest;
  539.     unsigned        offs;
  540.  
  541.     offs = WPEsecRsvData(sect, size, 1, dest);
  542.  
  543.     memcpy(dest, data, size);
  544.  
  545.     return  offs;
  546. }
  547.  
  548. /*****************************************************************************
  549.  *
  550.  *  Returns the address of the data of a section at the given offset.
  551.  */
  552.  
  553. memBuffPtr          writePE::WPEsecAdrData(WPEstdSects sect, unsigned    offs)
  554. {
  555.     PEsection       sec = WPEgetSection(sect);
  556.  
  557.     assert(offs <= (unsigned)(sec->PEsdNext - sec->PEsdBase));
  558.  
  559.     return  sec->PEsdBase + offs;
  560. }
  561.  
  562. /*****************************************************************************
  563.  *
  564.  *  Returns the relative offset of the data area within the section.
  565.  */
  566.  
  567. unsigned            writePE::WPEsecAddrOffs(WPEstdSects sect, memBuffPtr addr)
  568. {
  569.     PEsection       sec = WPEgetSection(sect);
  570.  
  571.     assert(addr >= sec->PEsdBase);
  572.     assert(addr <= sec->PEsdNext);
  573.  
  574.     return addr -  sec->PEsdBase;
  575. }
  576.  
  577. /*****************************************************************************
  578.  *
  579.  *  Reserve space in the code section of the given size and return the address
  580.  *  of where the code bytes are to be copied and the corresponding RVA.
  581.  */
  582.  
  583. unsigned            writePE::WPEallocCode(size_t size,
  584.                                           size_t align, OUT memBuffPtr REF dataRef)
  585. {
  586.     return  CODE_BASE_RVA + WPEsecRsvData(PE_SECT_text, size, align, dataRef);
  587. }
  588.  
  589. /*****************************************************************************
  590.  *
  591.  *  Reserve space for the given amount of string data and return the address
  592.  *  of where the string pool contents are to be copied. This routine must be
  593.  *  called exactly once (just before the PE file is closed), and the base of
  594.  *  the space reserved here will be used to process all string data fixups.
  595.  */
  596.  
  597. void                writePE::WPEallocString(size_t size,
  598.                                             size_t align, OUT memBuffPtr REF dataRef)
  599. {
  600.     /* Allocate the space and remember the relative offset */
  601.  
  602.     WPEstrPoolBase = WPEsecRsvData(PE_SECT_data, size, align, dataRef);
  603. }
  604.  
  605. /*****************************************************************************
  606.  *
  607.  *  Record a fixup: the datum being fixed up is within section 'ssrc' at
  608.  *  offset 'offs', and the value there is to be updated by the base RVA
  609.  *  of section 'sdst'.
  610.  */
  611.  
  612. void                writePE::WPEsecAddFixup(WPEstdSects ssrc,
  613.                                             WPEstdSects sdst, unsigned offs)
  614. {
  615.     PEsection       sec = WPEgetSection(ssrc);
  616.     PEreloc         rel = (PEreloc)WPEalloc->nraAlloc(sizeof(*rel));
  617.  
  618.     /* Make sure the offset is within range */
  619.  
  620.     assert(offs <= WPEsecNextOffs(ssrc));
  621.  
  622.     /* Add the relocation to the section's list */
  623.  
  624.     rel->perSect = sdst; assert(rel->perSect == (unsigned)sdst);
  625.     rel->perOffs = offs; assert(rel->perOffs == (unsigned)offs);
  626.  
  627.     rel->perNext = sec->PEsdRelocs;
  628.                    sec->PEsdRelocs = rel;
  629. }
  630.  
  631. /*****************************************************************************
  632.  *
  633.  *  Initialize the import tracking logic.
  634.  */
  635.  
  636. void                writePE::WPEimportInit()
  637. {
  638.     WPEhash         hash;
  639.  
  640.     /* Create and initialize the name hash table */
  641.  
  642.     hash = WPEimpHash = (WPEhash)WPEalloc->nraAlloc(sizeof(*hash));
  643.     hash->WPEhashInit(WPEcomp, WPEalloc);
  644.  
  645.     /* Initialize all the other import table-related values */
  646.  
  647.     WPEimpDLLcnt    = 0;
  648.     WPEimpDLLlist   =
  649.     WPEimpDLLlast   = NULL;
  650.  
  651.     WPEimpDLLstrLen = 0;
  652. }
  653.  
  654. /*****************************************************************************
  655.  *
  656.  *  Finalize the import table logic and return the total size of the import
  657.  *  tables.
  658.  */
  659.  
  660. size_t              writePE::WPEimportDone(unsigned offs)
  661. {
  662.     WPEimpDLL       DLLdesc;
  663.  
  664.     size_t          temp;
  665.     size_t          tsiz;
  666.  
  667.     size_t          size = 0;
  668.  
  669.     /* Reserve space for the IAT's */
  670.  
  671.     WPEimpOffsIAT  = offs;
  672.  
  673.     for (DLLdesc = WPEimpDLLlist, tsiz = 0;
  674.          DLLdesc;
  675.          DLLdesc = DLLdesc->PEidNext)
  676.     {
  677.         /* Record the base offset of this IAT */
  678.  
  679.         DLLdesc->PEidIATbase = offs;
  680.  
  681.         /* Compute the size of the IAT (it's null-terminated) */
  682.  
  683.         temp  = sizeof(void *) * (DLLdesc->PEidImpCnt + 1);
  684.  
  685.         /* Reserve space for the IAT */
  686.  
  687.         size += temp;
  688.         offs += temp;
  689.         tsiz += temp;
  690.     }
  691.  
  692.     WPEimpSizeIAT  = tsiz;
  693.  
  694.     /* Next comes the import directory table */
  695.  
  696.     WPEimpOffsIDT  = offs;
  697.  
  698.     /* The import directory is NULL-terminated */
  699.  
  700.     temp  = (WPEimpDLLcnt + 1) * sizeof(IMAGE_IMPORT_DESCRIPTOR);
  701.     size += temp;
  702.     offs += temp;
  703.  
  704.     WPEimpSizeIDT  = temp;
  705.  
  706.     /* Next comes the import lookup table */
  707.  
  708.     WPEimpOffsLook = offs;
  709.  
  710.     for (DLLdesc = WPEimpDLLlist;
  711.          DLLdesc;
  712.          DLLdesc = DLLdesc->PEidNext)
  713.     {
  714.         /* Record the base offset of this lookup table */
  715.  
  716.         DLLdesc->PEidILTbase = offs;
  717.  
  718.         /* Compute the size of the ILT (it's null-terminated) */
  719.  
  720.         temp  = sizeof(void *) * (DLLdesc->PEidImpCnt + 1);
  721.  
  722.         /* Reserve space for the ILT */
  723.  
  724.         size += temp;
  725.         offs += temp;
  726.     }
  727.  
  728.     /* Next comes the hint/name table */
  729.  
  730.     WPEimpOffsName = offs;
  731.  
  732.     size += WPEimpHash->WPEhashStrLen;
  733.     offs += WPEimpHash->WPEhashStrLen;
  734.  
  735.     /* The last thing is the DLL name table */
  736.  
  737.     WPEimpOffsDLLn = offs;
  738.  
  739.     size += WPEimpDLLstrLen;
  740.     offs += WPEimpDLLstrLen;
  741.  
  742.     /* Record the total size of all the tables */
  743.  
  744.     WPEimpSizeAll  = size;
  745.  
  746.     return  size;
  747. }
  748.  
  749. /*****************************************************************************
  750.  *
  751.  *  Write the import table to the output file.
  752.  */
  753.  
  754. void                writePE::WPEimportGen(OutFile outf, PEsection sect)
  755. {
  756.     unsigned        baseFile = sect->PEsdAddrFile;
  757.     unsigned        baseRVA  = sect->PEsdAddrRVA;
  758.  
  759.     unsigned        nextIAT;
  760.     unsigned        nextName;
  761.     unsigned        nextLook;
  762.     unsigned        nextDLLn;
  763.  
  764.     WPEimpDLL       DLLdesc;
  765.  
  766.     assert(outf->outFileOffset() == baseFile);
  767.  
  768. #ifdef  DEBUG
  769.     if  (WPEcomp->cmpConfig.ccVerbose >= 2) printf("\n");
  770. #endif
  771.  
  772.     /* Output the IAT entries s for all import of all DLL's */
  773.  
  774.     assert(outf->outFileOffset() == baseFile + WPEimpOffsIAT);
  775.  
  776.     nextName = baseRVA + WPEimpOffsName;
  777.  
  778.     for (DLLdesc = WPEimpDLLlist;
  779.          DLLdesc;
  780.          DLLdesc = DLLdesc->PEidNext)
  781.     {
  782.         WPEndef         imp;
  783.  
  784.         assert(DLLdesc->PEidIATbase == outf->outFileOffset() - baseFile);
  785.  
  786. #ifdef  DEBUG
  787.         if  (WPEcomp->cmpConfig.ccVerbose >= 2) printf("IAT starts at %04X           for '%s'\n", outf->outFileOffset(), DLLdesc->PEidName->PEnmSpelling());
  788. #endif
  789.  
  790.         /* For each import, output the RVA of its hint/name table entry */
  791.  
  792.         for (imp = DLLdesc->PEidImpList; imp; imp = imp->PEndNextInDLL)
  793.         {
  794.             WPEname         name = imp->PEndName;
  795.  
  796.             assert(name->PEnmFlags & PENMF_IMP_NAME);
  797.  
  798. #ifdef  DEBUG
  799.             if  (WPEcomp->cmpConfig.ccVerbose >= 2) printf("    entry --> %04X           for '%s.%s'\n", nextName, DLLdesc->PEidName->PEnmSpelling(), name->PEnmSpelling());
  800. #endif
  801.  
  802.             outf->outFileWriteData(&nextName, sizeof(nextName));
  803.  
  804.             nextName += hintNameSize(name);
  805.         }
  806.  
  807.         /* Output a null entry to terminate the table */
  808.  
  809.         outf->outFileWritePad(sizeof(nextName));
  810.     }
  811.  
  812. #ifdef  DEBUG
  813.     if  (WPEcomp->cmpConfig.ccVerbose >= 2) printf("\n");
  814. #endif
  815.  
  816.     /* Output the import directory */
  817.  
  818.     assert(outf->outFileOffset() == baseFile + WPEimpOffsIDT);
  819.  
  820.     nextIAT  = baseRVA + WPEimpOffsIAT;
  821.     nextLook = baseRVA + WPEimpOffsLook;
  822.     nextDLLn = baseRVA + WPEimpOffsDLLn;
  823.  
  824.     for (DLLdesc = WPEimpDLLlist;
  825.          DLLdesc;
  826.          DLLdesc = DLLdesc->PEidNext)
  827.     {
  828.         IMAGE_IMPORT_DESCRIPTOR impDsc;
  829.  
  830. #ifdef  DEBUG
  831.         if  (WPEcomp->cmpConfig.ccVerbose >= 2) printf("IDT entry --> %04X/%04X/%04X for '%s'\n", nextIAT, nextLook, nextDLLn, DLLdesc->PEidName->PEnmSpelling());
  832. #endif
  833.  
  834.         /* Fill in the entry and append it to the file */
  835.  
  836.         impDsc.Characteristics = nextLook;
  837.         impDsc.TimeDateStamp   = 0;
  838.         impDsc.ForwarderChain  = 0;
  839.         impDsc.Name            = nextDLLn;
  840.         impDsc.FirstThunk      = nextIAT;
  841.  
  842.         outf->outFileWriteData(&impDsc, sizeof(impDsc));
  843.  
  844.         /* Update the offsets for the next entry */
  845.  
  846.         nextIAT  += sizeof(void *) * (DLLdesc->PEidImpCnt + 1);
  847.         nextLook += sizeof(void *) * (DLLdesc->PEidImpCnt + 1);;
  848.         nextDLLn += (DLLdesc->PEidName->PEnmNlen + 1) & ~1;
  849.     }
  850.  
  851.     /* Output a null entry to terminate the table */
  852.  
  853.     outf->outFileWritePad(sizeof(IMAGE_IMPORT_DESCRIPTOR));
  854.  
  855. #ifdef  DEBUG
  856.     if  (WPEcomp->cmpConfig.ccVerbose >= 2) printf("\n");
  857. #endif
  858.  
  859.     /* Output the lookup table */
  860.  
  861.     assert(outf->outFileOffset() == baseFile + WPEimpOffsLook);
  862.  
  863.     nextName = baseRVA + WPEimpOffsName;
  864.     nextDLLn = baseRVA + WPEimpOffsDLLn;
  865.  
  866.     for (DLLdesc = WPEimpDLLlist;
  867.          DLLdesc;
  868.          DLLdesc = DLLdesc->PEidNext)
  869.     {
  870.         WPEndef         imp;
  871.  
  872.         assert(DLLdesc->PEidILTbase == outf->outFileOffset() - baseFile);
  873.  
  874. #ifdef  DEBUG
  875.         if  (WPEcomp->cmpConfig.ccVerbose >= 2) printf("ILT starts at %04X           for '%s'\n", outf->outFileOffset(), DLLdesc->PEidName->PEnmSpelling());
  876. #endif
  877.  
  878.         /* For each import, output the RVA of its hint/name table entry */
  879.  
  880.         for (imp = DLLdesc->PEidImpList; imp; imp = imp->PEndNextInDLL)
  881.         {
  882.             WPEname         name = imp->PEndName;
  883.  
  884.             assert(name->PEnmFlags & PENMF_IMP_NAME);
  885.  
  886. #ifdef  DEBUG
  887.         if  (WPEcomp->cmpConfig.ccVerbose >= 2) printf("    entry --> %04X           for '%s.%s'\n", nextName, DLLdesc->PEidName->PEnmSpelling(), name->PEnmSpelling());
  888. #endif
  889.  
  890.             outf->outFileWriteData(&nextName, sizeof(nextName));
  891.  
  892.             nextName += hintNameSize(name);
  893.         }
  894.  
  895.         /* Output a null entry to terminate the table */
  896.  
  897.         outf->outFileWritePad(sizeof(nextName));
  898.     }
  899.  
  900. #ifdef  DEBUG
  901.     if  (WPEcomp->cmpConfig.ccVerbose >= 2) printf("\n");
  902. #endif
  903.  
  904.     /* Output the hint/name table */
  905.  
  906.     assert(outf->outFileOffset() == baseFile + WPEimpOffsName);
  907.  
  908.     for (DLLdesc = WPEimpDLLlist;
  909.          DLLdesc;
  910.          DLLdesc = DLLdesc->PEidNext)
  911.     {
  912.         WPEndef         imp;
  913.         unsigned        one = 1;
  914.  
  915. #ifdef  DEBUG
  916.         if  (WPEcomp->cmpConfig.ccVerbose >= 2) printf("HNT starts at %04X           for '%s'\n", outf->outFileOffset(), DLLdesc->PEidName->PEnmSpelling());
  917. #endif
  918.  
  919.         /* For each import, output the RVA of its hint/name table entry */
  920.  
  921.         for (imp = DLLdesc->PEidImpList; imp; imp = imp->PEndNextInDLL)
  922.         {
  923.             WPEname         name = imp->PEndName;
  924.  
  925.             assert(name->PEnmFlags & PENMF_IMP_NAME);
  926.  
  927. #ifdef  DEBUG
  928.             if  (WPEcomp->cmpConfig.ccVerbose >= 2)  printf("    entry  at %04X               '%s.%s'\n", outf->outFileOffset(), DLLdesc->PEidName->PEnmSpelling(), name->PEnmSpelling());
  929. #endif
  930.  
  931.             outf->outFileWriteData(&one, 2);
  932.             outf->outFileWriteData(name->PEnmName, name->PEnmNlen+1);
  933.  
  934.             /* Padd if the name has an even size (odd with null terminator) */
  935.  
  936.             if  (!(name->PEnmNlen & 1))
  937.                 outf->outFileWriteByte(0);
  938.         }
  939.     }
  940.  
  941. #ifdef  DEBUG
  942.     if  (WPEcomp->cmpConfig.ccVerbose >= 2) printf("\n");
  943. #endif
  944.  
  945.     /* Finally, output the DLL name table */
  946.  
  947.     assert(outf->outFileOffset() == baseFile + WPEimpOffsDLLn);
  948.  
  949.     for (DLLdesc = WPEimpDLLlist;
  950.          DLLdesc;
  951.          DLLdesc = DLLdesc->PEidNext)
  952.     {
  953.         WPEname         name = DLLdesc->PEidName;
  954.  
  955. #ifdef  DEBUG
  956.         if  (WPEcomp->cmpConfig.ccVerbose >= 2) printf("DLL entry  at %04X               '%s'\n", outf->outFileOffset(), name->PEnmSpelling());
  957. #endif
  958.  
  959.         outf->outFileWriteData(name->PEnmName, name->PEnmNlen+1);
  960.  
  961.         /* Padd if the name has an even size (odd with null terminator) */
  962.  
  963.         if  (!(name->PEnmNlen & 1))
  964.             outf->outFileWriteByte(0);
  965.     }
  966. }
  967.  
  968. /*****************************************************************************
  969.  *
  970.  *  Token remapping logic.
  971.  */
  972.  
  973. #if     MD_TOKEN_REMAP
  974.  
  975. struct  tokenMap;
  976. typedef tokenMap  * TokenMapper;
  977.  
  978. struct  tokenMap : IMapToken
  979. {
  980.     unsigned        refCount;
  981.  
  982.     virtual HRESULT _stdcall QueryInterface(REFIID iid, void **ppv);
  983.     virtual ULONG   _stdcall AddRef();
  984.     virtual ULONG   _stdcall Release();
  985.     virtual HRESULT _stdcall Map(unsigned __int32 oldToken, unsigned __int32 newToken);
  986. };
  987.  
  988. HRESULT
  989. _stdcall            tokenMap::QueryInterface(REFIID iid, void **ppv)
  990. {
  991.     if      (iid == IID_IUnknown)
  992.     {
  993.         *ppv = (void *)this;
  994.         return S_OK;
  995.     }
  996.     else if (iid == IID_IMapToken)
  997.     {
  998.         *ppv = (void *)this;
  999.         return S_OK;
  1000.     }
  1001.     else
  1002.         return E_NOINTERFACE;
  1003. }
  1004.  
  1005. ULONG
  1006. _stdcall            tokenMap::AddRef()
  1007. {
  1008.     return ++refCount;
  1009. }
  1010.  
  1011. ULONG
  1012. _stdcall            tokenMap::Release()
  1013. {
  1014.     unsigned i = --refCount;
  1015.  
  1016. #ifndef __SMC__
  1017.  
  1018.     if (i == 0)
  1019.         delete this;
  1020.  
  1021. #endif
  1022.  
  1023.     return i;
  1024. }
  1025.  
  1026. HRESULT
  1027. _stdcall            tokenMap::Map(unsigned __int32 oldToken, unsigned __int32 newToken)
  1028. {
  1029.     UNIMPL(!"token remapper called, this is NYI");
  1030.  
  1031.     return E_NOTIMPL;
  1032. }
  1033.  
  1034. #endif
  1035.  
  1036. /*****************************************************************************/
  1037.  
  1038. static
  1039. char                COFFmagic[4] = { 'P', 'E', 0, 0 };
  1040.  
  1041. /*****************************************************************************
  1042.  *
  1043.  *  Finish writing the output file, flush it and close it. Returns false if
  1044.  *  successful.
  1045.  */
  1046.  
  1047. bool                writePE::WPEdone(mdToken entryTok, bool errors)
  1048. {
  1049.     unsigned        fileOffs;
  1050.     unsigned        fImgSize;
  1051.     unsigned        filePad;
  1052.  
  1053.     unsigned        DOS_hdrOffs, DOS_hdrSize;
  1054.     unsigned        COFFhdrOffs, COFFhdrSize;
  1055.     unsigned        OPTLhdrOffs, OPTLhdrSize;
  1056.     unsigned        sectTabOffs, sectTabSize;
  1057.  
  1058.     unsigned        virtBase;
  1059.     unsigned        virtOffs;
  1060.  
  1061.     unsigned        sectNum;
  1062.     PEsection       sectPtr;
  1063.  
  1064.     unsigned        entryOfs;
  1065.     unsigned        entryAdr;
  1066.     unsigned    *   ecodePtr;
  1067.  
  1068.     unsigned        codeOffs, codeVirt, codeSize;
  1069.     unsigned        rdatOffs, rdatVirt, rdatSize;
  1070.     unsigned        dataOffs, dataVirt, dataSize;
  1071.     unsigned        rsrcOffs, rsrcVirt, rsrcSize;
  1072.     unsigned        rlocOffs, rlocVirt, rlocSize;
  1073.     unsigned       /*bssOffs,*/          bssSize;
  1074.  
  1075.     unsigned        strPoolRVA;
  1076.     unsigned        strPoolAdr;
  1077.  
  1078.     OutFile         outf;
  1079.  
  1080. #ifdef  DLL
  1081.     void    *       fileBuff;
  1082. #endif
  1083.  
  1084.     static
  1085.     BYTE            DOSstub[] =
  1086.     {
  1087.         /*0040*/ 0x0E,              //  PUSH    CS
  1088.         /*0041*/ 0x1F,              //  POP     DS
  1089.         /*0042*/ 0xE8, 0x00, 0x00,  //  CALL    $+3
  1090.         /*0045*/ 0x5A,              //  POP     DX
  1091.         /*0046*/ 0x83, 0xC2, 0x0D,  //  ADD     DX,+0D
  1092.         /*0049*/ 0xB4, 0x09,        //  MOV     AH,09
  1093.         /*004B*/ 0xCD, 0x21,        //  INT     21
  1094.         /*004D*/ 0xB8, 0x01, 0x4C,  //  MOV     AX,4C01
  1095.         /*0050*/ 0xCD, 0x21,        //  INT     21
  1096.         /*0052*/ "This program cannot be run in DOS mode\r\n$\0\0\0\0"
  1097.     };
  1098.  
  1099.     static
  1100.     IMAGE_DOS_HEADER fileHdrTemplate =
  1101.     {
  1102.         0x5A4D,                     // magic
  1103.         0x0090,                     // bytes in last page
  1104.         0x0003,                     // number of pages
  1105.              0,                     // relocations
  1106.         0x0004,                     // header size
  1107.              0,                     // min extra
  1108.         0xFFFF,                     // max extra
  1109.              0,                     // initial SS
  1110.         0x0080,                     // initial SP
  1111.              0,                     // checksum
  1112.              0,                     // initial IP
  1113.              0,                     // initial CS
  1114.         0x0040,                     // reloc table
  1115.              0,                     // overlay num
  1116.             {0},                    // reserved
  1117.              0,                     // OEM id
  1118.              0,                     // OEM info
  1119.             {0},                    // reserved
  1120.         0x0080,                     // addr of new header
  1121.     };
  1122.  
  1123.     IMAGE_DOS_HEADER        fileHdr;
  1124.  
  1125.     IMAGE_FILE_HEADER       COFFhdr;
  1126.     time_t                  COFFstamp;
  1127.  
  1128.     IMAGE_OPTIONAL_HEADER   OPTLhdr;
  1129.  
  1130.     /* Bail if there were any compilation errors */
  1131.  
  1132.     if  (errors)
  1133.     {
  1134.         // UNDONE: Free up all resources, etc.
  1135.  
  1136.         return true;
  1137.     }
  1138.  
  1139.     /* Drop any image sections that are empty */
  1140.  
  1141.     for (sectNum = 0; sectNum < PE_SECT_count; sectNum++)
  1142.     {
  1143.         /* Get hold of the section entry */
  1144.  
  1145.         sectPtr = WPEsecTable[sectNum];
  1146.         if  (!sectPtr)
  1147.             continue;
  1148.  
  1149.         assert(sectPtr->PEsdIndex == (int)sectNum);
  1150.  
  1151.         /* Is this section empty? */
  1152.  
  1153.         if  (sectPtr->PEsdNext == sectPtr->PEsdBase)
  1154.         {
  1155.             /* The ".rdata" section is never empty */
  1156.  
  1157.             if  (sectNum == PE_SECT_rdata)
  1158.                 continue;
  1159.  
  1160.             /* Don't drop non-empty ".rsrc"/".reloc" sections */
  1161.  
  1162.             if  (sectNum == PE_SECT_rsrc  && WPErsrcSize)
  1163.                 continue;
  1164.             if  (sectNum == PE_SECT_reloc && WPEcomp->cmpConfig.ccOutDLL)
  1165.                 continue;
  1166.  
  1167.             /* Drop this section from the table */
  1168.  
  1169.             WPEsecTable[sectNum] = NULL; WPEsectCnt--;
  1170.         }
  1171.     }
  1172.  
  1173.     /* Figure out the virtual base address of the image */
  1174.  
  1175.     if  (WPEcomp->cmpConfig.ccOutBase)
  1176.     {
  1177.         size_t          align;
  1178.  
  1179.         /* The base must be a multiple of 64K, at least */
  1180.  
  1181.         align = (PEvirtAlignment >= 64*1024) ? PEvirtAlignment
  1182.                                              : 64*1024;
  1183.  
  1184.         /* The base address was specified, make sure it's aligned */
  1185.  
  1186.         virtBase  = WPEcomp->cmpConfig.ccOutBase;
  1187.  
  1188.         virtBase +=  (align - 1);
  1189.         virtBase &= ~(align - 1);
  1190.  
  1191.         /* The base must be at least 0x400000 */
  1192.  
  1193.         if  (virtBase < 0x400000)
  1194.              virtBase = 0x400000;
  1195.     }
  1196.     else
  1197.     {
  1198.         /* Use the default base address */
  1199.  
  1200.         virtBase  = WPEcomp->cmpConfig.ccOutDLL ? 0x10000000
  1201.                                                 : 0x00400000;
  1202.     }
  1203.  
  1204.     WPEvirtBase = virtBase;
  1205.  
  1206.     /* Count/reserve space for the file headers */
  1207.  
  1208.     fileOffs    = 0;
  1209.  
  1210.     /* The first thing is the DOS hader */
  1211.  
  1212.     DOS_hdrSize = sizeof(IMAGE_DOS_HEADER);
  1213.     DOS_hdrOffs = fileOffs;
  1214.                   fileOffs += 0xB8; // DOS_hdrSize;
  1215.  
  1216.     /* The PE/COFF headers are next */
  1217.  
  1218.     COFFhdrSize = sizeof(IMAGE_FILE_HEADER) + 4;    // 4 bytes = "magic" signature
  1219.     COFFhdrOffs = fileOffs;
  1220.                   fileOffs += COFFhdrSize;
  1221.  
  1222.     OPTLhdrSize = sizeof(IMAGE_OPTIONAL_HEADER);
  1223.     OPTLhdrOffs = fileOffs;
  1224.                   fileOffs += OPTLhdrSize;
  1225.  
  1226.     /* Next comes the section table */
  1227.  
  1228.     sectTabSize = sizeof(IMAGE_SECTION_HEADER) * WPEsectCnt;
  1229.     sectTabOffs = fileOffs;
  1230.                   fileOffs += sectTabSize;
  1231.  
  1232.     /* Allocate space for the various sections (properly aligning them) */
  1233.  
  1234.     virtOffs = PEvirtAlignment;
  1235.  
  1236.     /* Figure out the RVA of the main entry point */
  1237.  
  1238.     entryOfs = virtOffs;        // UNDONE: Compute RVA of entry point
  1239.     entryAdr = entryOfs + 2;
  1240.  
  1241. #ifdef  DEBUG
  1242.  
  1243.     if  (WPEcomp->cmpConfig.ccVerbose >= 2)
  1244.     {
  1245.         printf("DOS  header is at 0x%04X (size=0x%02X)\n", DOS_hdrOffs, DOS_hdrSize);
  1246.         printf("COFF header is at 0x%04X (size=0x%02X)\n", COFFhdrOffs, COFFhdrSize);
  1247.         printf("Opt. header is at 0x%04X (size=0x%02X)\n", OPTLhdrOffs, OPTLhdrSize);
  1248.         printf("Section tab is at 0x%04X (size=0x%02X)\n", sectTabOffs, sectTabSize);
  1249.         printf("Section[0]  is at 0x%04X\n"              , fileOffs);
  1250.     }
  1251.  
  1252. #endif
  1253.  
  1254.     dataVirt = dataSize =
  1255.     rlocVirt = rlocSize =
  1256.     rsrcVirt = rsrcSize = bssSize = fImgSize = 0;
  1257.  
  1258.     for (sectNum = 0; sectNum < PE_SECT_count; sectNum++)
  1259.     {
  1260.         size_t          size;
  1261.         unsigned        attr;
  1262.  
  1263.         /* Get hold of the section entry */
  1264.  
  1265.         sectPtr = WPEsecTable[sectNum];
  1266.         if  (!sectPtr)
  1267.             continue;
  1268.  
  1269.         assert(sectPtr->PEsdIndex == (int)sectNum);
  1270.  
  1271.         /* Each section must be properly aligned */
  1272.  
  1273.         fileOffs = (fileOffs + (PEfileAlignment-1)) & ~(PEfileAlignment-1);
  1274.         virtOffs = (virtOffs + (PEvirtAlignment-1)) & ~(PEvirtAlignment-1);
  1275.  
  1276.         /* Figure out how much data we've stored in the section */
  1277.  
  1278.         size = sectPtr->PEsdSizeData = sectPtr->PEsdNext - sectPtr->PEsdBase;
  1279.  
  1280.         /* What kind of a section is this? */
  1281.  
  1282.         switch (sectNum)
  1283.         {
  1284.         case PE_SECT_text:
  1285.  
  1286.             /* Check the RVA of the section */
  1287.  
  1288.             assert(virtOffs == CODE_BASE_RVA);
  1289.  
  1290.             /* Below we'll patch the entry point code sequence */
  1291.  
  1292.             ecodePtr = (unsigned *)(sectPtr->PEsdBase + 2);
  1293.  
  1294.             /* Remember the code size and base offset */
  1295.  
  1296.             codeSize = size;
  1297.             codeOffs = fileOffs;
  1298.             codeVirt = virtOffs;
  1299.  
  1300.             assert(codeVirt == CODE_BASE_RVA);
  1301.  
  1302.             attr     = IMAGE_SCN_CNT_CODE  |
  1303.                        IMAGE_SCN_MEM_READ  |
  1304.                        IMAGE_SCN_MEM_EXECUTE;
  1305.             break;
  1306.  
  1307.         case PE_SECT_data:
  1308.  
  1309.             /* Record the RVA of the .rdata section */
  1310.  
  1311.             WPEdataRVA = virtOffs;
  1312.  
  1313.             /* Now we can set the RVA's of all global variables */
  1314.  
  1315.             WPEcomp->cmpSetGlobMDoffs(virtOffs);
  1316.  
  1317.             /* Figure out the size and flags for the section */
  1318.  
  1319.             dataSize = size;
  1320.             dataOffs = fileOffs;
  1321.             dataVirt = virtOffs;
  1322.  
  1323.             attr     = IMAGE_SCN_MEM_READ  |
  1324.                        IMAGE_SCN_MEM_WRITE |
  1325.                        IMAGE_SCN_CNT_INITIALIZED_DATA;
  1326.             break;
  1327.  
  1328.         case PE_SECT_rdata:
  1329.  
  1330.             /* Record the RVA of the .rdata section */
  1331.  
  1332.             WPErdatRVA = virtOffs;
  1333.  
  1334.             /* Patch the entry code sequence */
  1335.  
  1336.             *ecodePtr   = virtOffs + virtBase;
  1337.  
  1338.             /* Finish up the import directory */
  1339.  
  1340.             size       += WPEimportDone(size);
  1341.  
  1342.             /* Reserve space for the COM+ header and metadata */
  1343.  
  1344.             size       += WPEgetCOMplusSize(size);
  1345.  
  1346.             /* Reserve space for the Debug Directory and our one entry */
  1347.  
  1348.             size       += WPEgetDebugDirSize(size);
  1349.  
  1350.             /* Remember the offset and size of the section */
  1351.  
  1352.             rdatSize    = size;
  1353.             rdatOffs    = fileOffs;
  1354.             rdatVirt    = virtOffs;
  1355.  
  1356.             attr        = IMAGE_SCN_MEM_READ  |
  1357.                           IMAGE_SCN_CNT_INITIALIZED_DATA;
  1358.             break;
  1359.  
  1360.         case PE_SECT_rsrc:
  1361.  
  1362.             /* Record the RVA and size of the .rdata section */
  1363.  
  1364.             WPErsrcRVA  = virtOffs;
  1365.             size        = sectPtr->PEsdSizeData = WPErsrcSize;
  1366.  
  1367.             /* Remember the offset and size of the section */
  1368.  
  1369.             rsrcSize    = size;
  1370.             rsrcOffs    = fileOffs;
  1371.             rsrcVirt    = virtOffs;
  1372.  
  1373.             attr        = IMAGE_SCN_MEM_READ  |
  1374.                           IMAGE_SCN_CNT_INITIALIZED_DATA;
  1375.             break;
  1376.  
  1377.         case PE_SECT_reloc:
  1378.  
  1379.             assert(WPEcomp->cmpConfig.ccOutDLL);
  1380.  
  1381.             /* The following is kind of lame, but it's good enough for now */
  1382.  
  1383.             sectPtr->PEsdSizeData = size = 4 + 4 + 2 * 2;    // space for 2 fixups
  1384.  
  1385.             /* Remember the offset and size of the section */
  1386.  
  1387.             rlocSize    = size;
  1388.             rlocOffs    = fileOffs;
  1389.             rlocVirt    = virtOffs;
  1390.  
  1391.             attr        = IMAGE_SCN_MEM_READ        |
  1392.                           IMAGE_SCN_MEM_DISCARDABLE |
  1393.                           IMAGE_SCN_CNT_INITIALIZED_DATA;
  1394.  
  1395.             break;
  1396.  
  1397.         default:
  1398.             UNIMPL(!"check for unusual section type");
  1399.         }
  1400.  
  1401. #ifdef  DEBUG
  1402.         if  (WPEcomp->cmpConfig.ccVerbose >= 2) printf("  Section hdr #%u at 0x%04X = %08X (size=0x%04X)\n", sectNum, fileOffs, virtOffs, size);
  1403. #endif
  1404.  
  1405.         /* Update the rounded-up file image size */
  1406.  
  1407.         fImgSize += roundUp(size, PEvirtAlignment);
  1408.  
  1409.         /* Record the flags (read/write, execute, and so on */
  1410.  
  1411.         sectPtr->PEsdFlags    = attr;
  1412.  
  1413.         /* Assign a file and virtual base offset to the section */
  1414.  
  1415.         sectPtr->PEsdAddrFile = fileOffs;
  1416.                                 fileOffs += size;
  1417.  
  1418.         sectPtr->PEsdAddrRVA  = virtOffs;
  1419.                                 virtOffs += size;
  1420.     }
  1421.  
  1422.     /* Make sure the size isn't too big */
  1423.  
  1424.     if  (virtOffs > WPEcomp->cmpConfig.ccOutSize && WPEcomp->cmpConfig.ccOutSize)
  1425.         WPEcomp->cmpGenWarn(WRNpgm2big, virtOffs, WPEcomp->cmpConfig.ccOutSize);
  1426.  
  1427.     /* The file size has to be a page multiple [ISSUE: why?] */
  1428.  
  1429.     fileOffs = roundUp(fileOffs, PEfileAlignment);
  1430.  
  1431.     /* Figure out the RVA of the string pool */
  1432.  
  1433.     strPoolRVA = WPEstrPoolBase + dataVirt;
  1434.     strPoolAdr = strPoolRVA + virtBase;
  1435.  
  1436.     /* Start writing to the output file */
  1437.  
  1438.     outf = WPEoutFile = (OutFile)WPEalloc->nraAlloc(sizeof(*outf));
  1439.  
  1440. #ifdef  DLL
  1441.     if  (*WPEoutFnam == ':' && !stricmp(WPEoutFnam, ":memory:"))
  1442.     {
  1443.         fileBuff = VirtualAlloc(NULL, fileOffs, MEM_COMMIT, PAGE_READWRITE);
  1444.         if  (!fileBuff)
  1445.             WPEcomp->cmpFatal(ERRnoMemory);
  1446.  
  1447.         outf->outFileOpen(WPEcomp, fileBuff);
  1448.  
  1449.         WPEcomp->cmpOutputFile = fileBuff;
  1450.     }
  1451.     else
  1452. #endif
  1453.         outf->outFileOpen(WPEcomp, WPEoutFnam);
  1454.  
  1455.     /* Fill in the DOS file header */
  1456.  
  1457.     fileHdr        = fileHdrTemplate;
  1458.  
  1459.     fileHdr.e_cblp = (fileOffs        & 511);
  1460.     fileHdr.e_cp   = (fileOffs + 511) / 512;
  1461.  
  1462.     /* Write out the DOS header */
  1463.  
  1464.     outf->outFileWriteData(&fileHdr, sizeof(fileHdr));
  1465.  
  1466.     /* Write out the DOS stub */
  1467.  
  1468.     assert(outf->outFileOffset() == 16U*fileHdr.e_cparhdr);
  1469.     outf->outFileWriteData(DOSstub, sizeof(DOSstub));
  1470.  
  1471.     /* Next comes the COFF header */
  1472.  
  1473.     assert(outf->outFileOffset() == (unsigned)fileHdr.e_lfanew);
  1474.     outf->outFileWriteData(COFFmagic, sizeof(COFFmagic));
  1475.  
  1476.     /* Compute the timedate stamp */
  1477.  
  1478.     time(&COFFstamp);
  1479.  
  1480.     /* Fill in and write out the COFF header */
  1481.  
  1482.     COFFhdr.Machine                     = IMAGE_FILE_MACHINE_I386;
  1483.     COFFhdr.NumberOfSections            = WPEsectCnt;
  1484.     COFFhdr.TimeDateStamp               = COFFstamp;
  1485.     COFFhdr.PointerToSymbolTable        = 0;
  1486.     COFFhdr.NumberOfSymbols             = 0;
  1487.     COFFhdr.SizeOfOptionalHeader        = sizeof(OPTLhdr);
  1488.     COFFhdr.Characteristics             = IMAGE_FILE_EXECUTABLE_IMAGE    |
  1489.                                           IMAGE_FILE_32BIT_MACHINE       |
  1490.                                           IMAGE_FILE_LINE_NUMS_STRIPPED  |
  1491.                                           IMAGE_FILE_LOCAL_SYMS_STRIPPED;
  1492.  
  1493.     if  (WPEcomp->cmpConfig.ccOutDLL)
  1494.         COFFhdr.Characteristics |= IMAGE_FILE_DLL;
  1495.     else
  1496.         COFFhdr.Characteristics |= IMAGE_FILE_RELOCS_STRIPPED;
  1497.  
  1498.     outf->outFileWriteData(&COFFhdr, sizeof(COFFhdr));
  1499.  
  1500.     /* Next comes the optional COFF header */
  1501.  
  1502.     memset(&OPTLhdr, 0, sizeof(OPTLhdr));
  1503.  
  1504.     OPTLhdr.Magic                       = IMAGE_NT_OPTIONAL_HDR_MAGIC;
  1505.     OPTLhdr.MajorLinkerVersion          = 7;
  1506. //  OPTLhdr.MinorLinkerVersion          = 0;
  1507.     OPTLhdr.SizeOfCode                  = roundUp(codeSize, PEfileAlignment);
  1508.     OPTLhdr.SizeOfInitializedData       = roundUp(dataSize, PEfileAlignment) + 0x400;
  1509.     OPTLhdr.SizeOfUninitializedData     = roundUp( bssSize, PEfileAlignment);
  1510.     OPTLhdr.AddressOfEntryPoint         = entryOfs;
  1511.     OPTLhdr.BaseOfCode                  = codeVirt;
  1512. #ifndef HOST_IA64
  1513.     OPTLhdr.BaseOfData                  = dataVirt;
  1514. #endif
  1515.     OPTLhdr.ImageBase                   = virtBase;
  1516.     OPTLhdr.SectionAlignment            = PEvirtAlignment;
  1517.     OPTLhdr.FileAlignment               = PEfileAlignment;
  1518.     OPTLhdr.MajorOperatingSystemVersion = 4;
  1519.     OPTLhdr.MinorOperatingSystemVersion = 0;
  1520. //  OPTLhdr.Win32VersionValue           = 0;
  1521.     OPTLhdr.SizeOfImage                 = fImgSize + 0x1000;
  1522.     OPTLhdr.SizeOfHeaders               = roundUp(sizeof(fileHdr  ) +
  1523.                                                   sizeof(DOSstub  ) +
  1524.                                                   sizeof(COFFmagic) +
  1525.                                                   sizeof(OPTLhdr  ), PEfileAlignment);
  1526. //  OPTLhdr.MajorImageVersion           = 0;
  1527. //  OPTLhdr.MinorImageVersion           = 0;
  1528.     OPTLhdr.MajorSubsystemVersion       = 4;
  1529. //  OPTLhdr.MinorSubsystemVersion       = 0;
  1530. //  OPTLhdr.Win32VersionValue           = 0;
  1531.     OPTLhdr.Subsystem                   = WPEcomp->cmpConfig.ccSubsystem;
  1532. //  OPTLhdr.DllCharacteristics          = 0;
  1533.     OPTLhdr.SizeOfStackReserve          = 0x100000;
  1534.     OPTLhdr.SizeOfStackCommit           = 0x1000;
  1535.     OPTLhdr.SizeOfHeapReserve           = 0x100000;
  1536.     OPTLhdr.SizeOfHeapCommit            = 0x1000;
  1537. //  OPTLhdr.LoaderFlags                 = 0;
  1538.     OPTLhdr.NumberOfRvaAndSizes         = IMAGE_NUMBEROF_DIRECTORY_ENTRIES;
  1539.  
  1540.     /* Fill in the dictionary */
  1541.  
  1542.     OPTLhdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT        ].VirtualAddress = WPEimpOffsIDT+rdatVirt;
  1543.     OPTLhdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT        ].Size           = WPEimpSizeIDT;
  1544.  
  1545.     OPTLhdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT           ].VirtualAddress = WPEimpOffsIAT+rdatVirt;
  1546.     OPTLhdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT           ].Size           = WPEimpSizeIAT;
  1547.  
  1548.     OPTLhdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE      ].VirtualAddress = rsrcVirt;
  1549.     OPTLhdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE      ].Size           = rsrcSize;
  1550.  
  1551.     OPTLhdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC     ].VirtualAddress = rlocVirt;
  1552.     OPTLhdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC     ].Size           = rlocSize;
  1553.  
  1554.     OPTLhdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress = WPEcomPlusOffs+rdatVirt;
  1555.     OPTLhdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size           = sizeof(IMAGE_COR20_HEADER);
  1556.  
  1557.     if (WPEdebugDirDataSize != 0)
  1558.     {
  1559.         OPTLhdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG         ].VirtualAddress = WPEdebugDirOffs+rdatVirt;
  1560.         OPTLhdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG         ].Size           = WPEdebugDirSize;
  1561.     }
  1562.  
  1563.     /* Write out the optional header */
  1564.  
  1565.     outf->outFileWriteData(&OPTLhdr, sizeof(OPTLhdr));
  1566.  
  1567.     /* Write out the section table */
  1568.  
  1569.     for (sectNum = 0; sectNum < PE_SECT_count; sectNum++)
  1570.     {
  1571.         size_t                  dataSize;
  1572.         IMAGE_SECTION_HEADER    sectHdr;
  1573.  
  1574.         /* Get hold of the section entry */
  1575.  
  1576.         sectPtr = WPEsecTable[sectNum];
  1577.         if  (!sectPtr)
  1578.             continue;
  1579.  
  1580.         assert(sectPtr->PEsdIndex == (int)sectNum);
  1581.  
  1582.         dataSize = sectPtr->PEsdSizeData;
  1583.  
  1584.         /* The import table (and COM+/debugger goo) size is added to .rdata */
  1585.  
  1586.         if  (sectNum == PE_SECT_rdata)
  1587.         {
  1588.             dataSize += WPEimpSizeAll   +
  1589.                         WPEcomPlusSize  +
  1590.                         WPEdebugDirSize +
  1591.                         WPEdebugDirDataSize;
  1592.         }
  1593.  
  1594.         memcpy(§Hdr.Name, WPEsecName((WPEstdSects)sectNum), sizeof(sectHdr.Name));
  1595.  
  1596.         sectHdr.Misc.VirtualSize     = dataSize;
  1597.         sectHdr.VirtualAddress       = sectPtr->PEsdAddrRVA;
  1598.         sectHdr.SizeOfRawData        = roundUp(dataSize, PEfileAlignment);
  1599.         sectHdr.PointerToRawData     = sectPtr->PEsdAddrFile;
  1600.         sectHdr.PointerToRelocations = 0;
  1601.         sectHdr.PointerToLinenumbers = 0;
  1602.         sectHdr.NumberOfRelocations  = 0;
  1603.         sectHdr.NumberOfLinenumbers  = 0;
  1604.         sectHdr.Characteristics      = sectPtr->PEsdFlags;
  1605.  
  1606.         /* Write out the section table entry */
  1607.  
  1608.         outf->outFileWriteData(§Hdr, sizeof(sectHdr));
  1609.     }
  1610.  
  1611.     /* Output the contents of all the sections */
  1612.  
  1613.     for (sectNum = 0; sectNum < PE_SECT_count; sectNum++)
  1614.     {
  1615.         size_t          padSize;
  1616.  
  1617.         /* Get hold of the section entry */
  1618.  
  1619.         sectPtr = WPEsecTable[sectNum];
  1620.         if  (!sectPtr)
  1621.             continue;
  1622.  
  1623.         assert(sectPtr->PEsdIndex == (int)sectNum);
  1624.  
  1625.         /* Pad to get to the next file alignment boundary */
  1626.  
  1627.         padSize = sectPtr->PEsdAddrFile - outf->outFileOffset(); assert((int)padSize >= 0);
  1628.  
  1629.         if  (padSize)
  1630.             outf->outFileWritePad(padSize);
  1631.  
  1632.         /* Output the contents of the section */
  1633.  
  1634.         switch (sectNum)
  1635.         {
  1636.         case PE_SECT_rdata:
  1637.  
  1638.             /* First we output the import table */
  1639.  
  1640.             WPEimportGen     (outf, sectPtr);
  1641.  
  1642.             /* Output the COM+ data */
  1643.  
  1644.             WPEgenCOMplusData(outf, sectPtr, entryTok);
  1645.  
  1646.             /* Output the COM+ data */
  1647.  
  1648.             WPEgenDebugDirData(outf, sectPtr, COFFstamp);
  1649.  
  1650.             /* Are there any relocs in this section? */
  1651.  
  1652.             if  (sectPtr->PEsdRelocs)
  1653.             {
  1654.                 UNIMPL(!"relocs in .rdata - can this happen?");
  1655.             }
  1656.  
  1657.             break;
  1658.  
  1659.         case PE_SECT_rsrc:
  1660.  
  1661.             WPEgenRCcont(outf, sectPtr);
  1662.             break;
  1663.  
  1664.         case PE_SECT_reloc:
  1665.             {
  1666.                 unsigned    temp;
  1667.  
  1668.                 /* Output the page RVA and total fixup block size */
  1669.  
  1670.                 temp = CODE_BASE_RVA; outf->outFileWriteData(&temp, 4);
  1671.                 temp = 4 + 4 + 2 * 2; outf->outFileWriteData(&temp, 4);
  1672.  
  1673.                 /* Output the first  offset + type pair */
  1674.  
  1675.                 assert(entryAdr - CODE_BASE_RVA < 0x1000);
  1676.  
  1677.                 temp = (IMAGE_REL_BASED_HIGHLOW << 12) + (entryAdr - CODE_BASE_RVA);
  1678.                 outf->outFileWriteData(&temp, 2);
  1679.  
  1680.                 /* Output the second offset + type pair */
  1681.  
  1682.                 temp = 0;
  1683.                 outf->outFileWriteData(&temp, 2);
  1684.             }
  1685.             break;
  1686.  
  1687.         default:
  1688.  
  1689.             /* Are there any relocs in this section? */
  1690.  
  1691.             if  (sectPtr->PEsdRelocs)
  1692.             {
  1693.                 PEreloc         rel;
  1694.  
  1695.                 for (rel = sectPtr->PEsdRelocs; rel; rel = rel->perNext)
  1696.                 {
  1697.                     unsigned        adjustv;
  1698.                     PEsection       sectDst;
  1699.                     BYTE        *   patch;
  1700.  
  1701.                     /* Is this a string pool fixup? */
  1702.  
  1703.                     if  (rel->perSect == PE_SECT_string)
  1704.                     {
  1705.                         /* Adjust by the RVA of the string pool */
  1706.  
  1707.                         adjustv = (sectNum == PE_SECT_text) ? strPoolRVA
  1708.                                                             : strPoolAdr;
  1709.  
  1710.                         /* Make sure the string pool has been allocated */
  1711.  
  1712.                         assert(WPEstrPoolBase != 0xBEEFCAFE);
  1713.                     }
  1714.                     else
  1715.                     {
  1716.                         /* Get hold of the target section */
  1717.  
  1718.                         sectDst = WPEgetSection((WPEstdSects)rel->perSect);
  1719.  
  1720.                         /* The value needs to be adjusted by the section's RVA */
  1721.  
  1722.                         adjustv = sectDst->PEsdAddrRVA;
  1723.                     }
  1724.  
  1725.                     /* Compute the address to be patched */
  1726.  
  1727.                     patch = sectPtr->PEsdBase + rel->perOffs;
  1728.  
  1729.                     /* Make sure the patched value is within the section */
  1730.  
  1731.                     assert(patch + sizeof(int) <= sectPtr->PEsdNext);
  1732.  
  1733.                     /* Update the value with the section's RVA */
  1734.  
  1735. #ifdef  DEBUG
  1736. //                  printf("Reloc patch: %04X -> %04X\n", *(unsigned *)patch, *(unsigned *)patch + adjustv);
  1737. #endif
  1738.  
  1739.                     *(unsigned *)patch += adjustv;
  1740.                 }
  1741.             }
  1742.  
  1743.             /* Output the contents of the section */
  1744.  
  1745.             outf->outFileWriteData(sectPtr->PEsdBase, sectPtr->PEsdSizeData);
  1746.             break;
  1747.         }
  1748.     }
  1749.  
  1750.     /* Pad the file to a multiple of page size */
  1751.  
  1752.     filePad = fileOffs - outf->outFileOffset();
  1753.  
  1754.     if  (filePad)
  1755.     {
  1756.         assert((int)filePad > 0);
  1757.         assert((int)filePad < PEfileAlignment);
  1758.  
  1759.         outf->outFileWritePad(filePad);
  1760.     }
  1761.  
  1762.     /* Tell the compiler that we're just about done */
  1763.  
  1764.     WPEcomp->cmpOutputFileDone(outf);
  1765.  
  1766.     /* Close the output file and we're done */
  1767.  
  1768.     outf->outFileDone();
  1769.  
  1770.     if  (!WPEcomp->cmpConfig.ccQuiet)
  1771.         printf("%u bytes written to '%s'\n", fileOffs, WPEoutFnam);
  1772.  
  1773.     return  false;
  1774. }
  1775.  
  1776. /*****************************************************************************
  1777.  *
  1778.  *  Finalize COM+ / metadata output and return the total size of the COM+
  1779.  *  tables.
  1780.  */
  1781.  
  1782. size_t              writePE::WPEgetCOMplusSize(unsigned offs)
  1783. {
  1784.     DWORD           temp;
  1785.     size_t          size = 0;
  1786.  
  1787.     /* Remember the base offset of the COM+ section */
  1788.  
  1789.     WPEcomPlusOffs  = offs;
  1790.  
  1791.     temp  = sizeof(IMAGE_COR20_HEADER);
  1792.     offs += temp;
  1793.     size += temp;
  1794.  
  1795.     /* Get the final size of the metadata */
  1796.  
  1797.     if  (WPEwmde->GetSaveSize(cssAccurate, &temp))
  1798.         WPEcomp->cmpFatal(ERRopenCOR);  // UNDONE: issue a more meaningful error
  1799.  
  1800.     WPEmetaDataSize = temp;
  1801.     WPEmetaDataOffs = offs;
  1802.  
  1803.     offs += temp;
  1804.     size += temp;
  1805.  
  1806.     /* Add the size of the vtable section, if any */
  1807.  
  1808.     size += WPEcomp->cmpVtableCount * sizeof(IMAGE_COR_VTABLEFIXUP);
  1809.  
  1810.     /* Remember the size of all of the COM+ tables */
  1811.  
  1812.     WPEcomPlusSize  = size;
  1813.  
  1814.     return  size;
  1815. }
  1816.  
  1817. /*****************************************************************************
  1818.  *
  1819.  *  Write the COM+ table (and metadata) to the output file.
  1820.  */
  1821.  
  1822. void                writePE::WPEgenCOMplusData(OutFile outf, PEsection sect,
  1823.                                                              mdToken   entryTok)
  1824. {
  1825.     unsigned        baseFile = WPEmetaDataOffs + sect->PEsdAddrFile;
  1826.     unsigned        baseRVA  = WPEmetaDataOffs + sect->PEsdAddrRVA;
  1827.  
  1828.     unsigned        vtabSize = WPEcomp->cmpVtableCount * sizeof(IMAGE_COR_VTABLEFIXUP);
  1829.  
  1830.     IMAGE_COR20_HEADER  COMhdr;
  1831.  
  1832.     /* Fill in the COM+ header */
  1833.  
  1834.     memset(&COMhdr, 0, sizeof(COMhdr));
  1835.  
  1836.     COMhdr.cb                          = sizeof(COMhdr);
  1837.     COMhdr.MajorRuntimeVersion         = 2;
  1838.     COMhdr.MinorRuntimeVersion         = 0;
  1839.     COMhdr.Flags                       = COMIMAGE_FLAGS_ILONLY;
  1840.     COMhdr.EntryPointToken             = entryTok;
  1841.  
  1842.     COMhdr.MetaData    .VirtualAddress = baseRVA;
  1843.     COMhdr.MetaData    .Size           = WPEmetaDataSize;
  1844.  
  1845.     COMhdr.VTableFixups.VirtualAddress = vtabSize ? baseRVA + WPEmetaDataSize : 0;
  1846.     COMhdr.VTableFixups.Size           = vtabSize;
  1847.  
  1848.     /* Write the COM+ header to the file */
  1849.  
  1850.     outf->outFileWriteData(&COMhdr, sizeof(COMhdr));
  1851.  
  1852.     /* Output the metadata */
  1853.  
  1854. //  printf("Writing %u bytes of MD\n", WPEmetaDataSize);
  1855.  
  1856.     void    *       MDbuff = LowLevelAlloc(WPEmetaDataSize);
  1857.     if  (!MDbuff)
  1858.         WPEcomp->cmpFatal(ERRnoMemory);
  1859.  
  1860.     if  (WPEwmde->SaveToMemory(MDbuff, WPEmetaDataSize))
  1861.         WPEcomp->cmpFatal(ERRmetadata);
  1862.  
  1863.     outf->outFileWriteData(MDbuff, WPEmetaDataSize);
  1864.  
  1865.     LowLevelFree(MDbuff);
  1866.  
  1867.     /* Shut down the RC file import logic */
  1868.  
  1869.     WPEdoneRCimp();
  1870.  
  1871.     /* Append any unmanaged vtable entries to the end */
  1872.  
  1873.     if  (vtabSize)
  1874.     {
  1875.         SymList                 vtbls;
  1876.         IMAGE_COR_VTABLEFIXUP   fixup;
  1877. #ifndef NDEBUG
  1878.         unsigned                count = 0;
  1879. #endif
  1880.  
  1881.         for (vtbls = WPEcomp->cmpVtableList; vtbls; vtbls = vtbls->slNext)
  1882.         {
  1883.             SymDef                  vtabSym = vtbls->slSym;
  1884.  
  1885.             assert(vtabSym->sdSymKind == SYM_VAR);
  1886.             assert(vtabSym->sdVar.sdvIsVtable);
  1887.  
  1888.             fixup.RVA   = vtabSym->sdVar.sdvOffset + WPEdataRVA;
  1889.             fixup.Count = vtabSym->sdParent->sdClass.sdcVirtCnt;
  1890.             fixup.Type  = COR_VTABLE_32BIT;
  1891.  
  1892. #ifndef NDEBUG
  1893.             count++;
  1894. #endif
  1895.  
  1896.             outf->outFileWriteData(&fixup, sizeof(fixup));
  1897.         }
  1898.  
  1899.         assert(count == WPEcomp->cmpVtableCount);
  1900.     }
  1901. }
  1902.  
  1903. /*****************************************************************************
  1904.  *
  1905.  *  Finalize Debug Directory output and return the total size of the data
  1906.  *  tables.
  1907.  */
  1908.  
  1909. size_t              writePE::WPEgetDebugDirSize(unsigned offs)
  1910. {
  1911.     DWORD           temp;
  1912.     size_t          size = 0;
  1913.  
  1914.     /* Only emit the directory if there is data to be emitted */
  1915.  
  1916.     if (WPEdebugDirDataSize == 0)
  1917.         return 0;
  1918.  
  1919.     /* Remember the base offset of the COM+ section */
  1920.  
  1921.     WPEdebugDirOffs  = offs;
  1922.  
  1923.     temp  = sizeof(WPEdebugDirIDD) + WPEdebugDirDataSize;
  1924.     offs += temp;
  1925.     size += temp;
  1926.  
  1927.     /* Remember the size of just the debug directory */
  1928.  
  1929.     WPEdebugDirSize  = sizeof(WPEdebugDirIDD);
  1930.  
  1931.     /*
  1932.      * Return the size of both the directory and the data the
  1933.      * directory will point to. This is so that we reserve enough
  1934.      * space in the section for everything.
  1935.      */
  1936.  
  1937.     return  size;
  1938. }
  1939.  
  1940. /*****************************************************************************
  1941.  *
  1942.  *  Write the Debug Directory (and data) to the output file.
  1943.  */
  1944.  
  1945. void                writePE::WPEgenDebugDirData(OutFile outf,
  1946.                                                 PEsection sect,
  1947.                                                 DWORD timestamp)
  1948. {
  1949.     /* Only emit the directory if there is data to be emitted */
  1950.  
  1951.     if (WPEdebugDirDataSize == 0)
  1952.         return;
  1953.  
  1954.     /* We have to set the timestamp and the addresses */
  1955.  
  1956.     WPEdebugDirIDD.TimeDateStamp    = timestamp;
  1957.     WPEdebugDirIDD.AddressOfRawData = 0;
  1958.  
  1959.     /* The data for this entry goes right after it */
  1960.  
  1961.     WPEdebugDirIDD.PointerToRawData = WPEdebugDirOffs + sizeof(WPEdebugDirIDD)
  1962.                                                       + sect->PEsdAddrFile;
  1963.  
  1964.     /* Emit the directory entry */
  1965.  
  1966.     outf->outFileWriteData(&WPEdebugDirIDD, sizeof(WPEdebugDirIDD));
  1967.  
  1968.     /* Emit the data */
  1969.  
  1970.     outf->outFileWriteData(WPEdebugDirData, WPEdebugDirDataSize);
  1971. }
  1972.  
  1973. /*****************************************************************************
  1974.  *
  1975.  *  Initialize and shut down the RC file import logic.
  1976.  */
  1977.  
  1978. void                writePE::WPEinitRCimp()
  1979. {
  1980.     WPErsrcFile =
  1981.     WPErsrcFmap = 0;
  1982.     WPErsrcSize = 0;
  1983. }
  1984.  
  1985. void                writePE::WPEdoneRCimp()
  1986. {
  1987.     if  (WPErsrcFmap) { CloseHandle(WPErsrcFmap);WPErsrcFmap = 0; }
  1988.     if  (WPErsrcFile) { CloseHandle(WPErsrcFile);WPErsrcFile = 0; }
  1989. }
  1990.  
  1991. /*****************************************************************************
  1992.  *
  1993.  *  Add a resource file to the output.
  1994.  */
  1995.  
  1996. bool                writePE::WPEaddRCfile(const char *filename)
  1997. {
  1998.     _Fstat          fileInfo;
  1999.  
  2000.     HANDLE          fileFile = 0;
  2001.     HANDLE          fileFMap = 0;
  2002.  
  2003.     size_t          fileSize;
  2004.     const   BYTE  * fileBase;
  2005.  
  2006.     cycleCounterPause();
  2007.  
  2008.     /* See if the source file exists */
  2009.  
  2010.     if  (_stat(filename, &fileInfo))
  2011.         WPEcomp->cmpGenFatal(ERRopenRdErr, filename);
  2012.  
  2013.     /* Open the file (we know it exists, but we check for errors anyway) */
  2014.  
  2015.     fileFile = CreateFileA(filename, GENERIC_READ,
  2016.                                      FILE_SHARE_READ,
  2017.                                      NULL,
  2018.                                      OPEN_EXISTING,
  2019.                                      FILE_ATTRIBUTE_NORMAL,
  2020.                                      0);
  2021.     if  (!fileFile)
  2022.         WPEcomp->cmpGenFatal(ERRopenRdErr, filename);
  2023.  
  2024.     /* Create a mapping on the input file */
  2025.  
  2026.     fileFMap = CreateFileMappingA(fileFile, NULL, PAGE_READONLY, 0, 0, NULL);
  2027.     if  (!fileFMap)
  2028.     {
  2029.     ERR:
  2030.         if  (fileFMap) CloseHandle(fileFMap);
  2031.         if  (fileFile) CloseHandle(fileFile);
  2032.  
  2033.         return  true;
  2034.     }
  2035.  
  2036.     /* Map the whole file into memory for easy access */
  2037.  
  2038.     fileSize = fileInfo.st_size;
  2039.     fileBase = (const BYTE*)MapViewOfFileEx(fileFMap, FILE_MAP_READ, 0, 0, 0, NULL);
  2040.     if  (!fileBase)
  2041.         goto ERR;
  2042.  
  2043.     cycleCounterResume();
  2044.  
  2045.     /* We've got the file in memory, make sure the header looks OK */
  2046.  
  2047.     IMAGE_FILE_HEADER * hdrPtr = (IMAGE_FILE_HEADER *)fileBase;
  2048.  
  2049.     if  (hdrPtr->Machine              != IMAGE_FILE_MACHINE_I386  ||
  2050. //       hdrPtr->Characteristics      != IMAGE_FILE_32BIT_MACHINE ||
  2051.          hdrPtr->NumberOfSections     == 0                        ||
  2052.          hdrPtr->SizeOfOptionalHeader != 0)
  2053.     {
  2054.         WPEcomp->cmpGenFatal(ERRbadInputFF, filename, "resource");
  2055.     }
  2056.  
  2057.     /* Add up the size of all the interesting sections */
  2058.  
  2059.     IMAGE_SECTION_HEADER *  sectTab = (IMAGE_SECTION_HEADER*)(hdrPtr+1);
  2060.     unsigned                sectCnt = hdrPtr->NumberOfSections;
  2061.  
  2062.     do
  2063.     {
  2064.         if  (sectTab->Characteristics & IMAGE_SCN_MEM_DISCARDABLE)
  2065.             continue;
  2066.  
  2067. //      printf("Section %8s: size = %04X, char = %04X\n", sectTab->Name, sectTab->SizeOfRawData);
  2068.  
  2069.         WPErsrcSize += sectTab->SizeOfRawData;
  2070.     }
  2071.     while (++sectTab, --sectCnt);
  2072.  
  2073.     WPErsrcFmap = fileFMap;
  2074.     WPErsrcFile = fileFile;
  2075.     WPErsrcBase = fileBase;
  2076.  
  2077.     WPEaddSection(PE_SECT_rsrc, 0, roundUp(WPErsrcSize, OS_page_size));
  2078.  
  2079.     /* Indicate success to the caller */
  2080.  
  2081.     return  false;
  2082. }
  2083.  
  2084. /*****************************************************************************
  2085.  *
  2086.  *  Output the contents of the resource file to the output image.
  2087.  */
  2088.  
  2089. void                writePE::WPEgenRCcont(OutFile  outf, PEsection sect)
  2090. {
  2091.     unsigned                baseRVA  = sect->PEsdAddrRVA;
  2092.  
  2093.     const   BYTE *          fileBase = WPErsrcBase;
  2094.  
  2095.     IMAGE_FILE_HEADER     * hdrPtr   = (IMAGE_FILE_HEADER   *)fileBase;
  2096.  
  2097.     IMAGE_SECTION_HEADER  * sectTab  = (IMAGE_SECTION_HEADER*)(hdrPtr+1);
  2098.     unsigned                sectCnt  = hdrPtr->NumberOfSections;
  2099.     unsigned                sectRVA;
  2100.  
  2101.     IMAGE_SYMBOL  *         symTab   = NULL;
  2102.     unsigned                symCnt   = 0;
  2103.  
  2104.     if  (hdrPtr->PointerToSymbolTable)
  2105.     {
  2106.         IMAGE_SYMBOL  *         symPtr;
  2107.         unsigned                symNum;
  2108.         size_t                  symSiz;
  2109.  
  2110.         IMAGE_SECTION_HEADER  * sectPtr = sectTab;
  2111.         int                     sectNum = 1;
  2112.  
  2113.         /* Make a copy of the symbol table */
  2114.  
  2115.         symCnt = symNum = hdrPtr->NumberOfSymbols;
  2116.         symSiz = symCnt * sizeof(*symTab);
  2117.         symTab = symPtr = (IMAGE_SYMBOL*)WPEalloc->nraAlloc(symSiz);
  2118.  
  2119.         memcpy(symTab, fileBase + hdrPtr->PointerToSymbolTable, symSiz);
  2120.  
  2121.         /* Fill in the address of the symbols that refer to sections */
  2122.  
  2123.         sectRVA = baseRVA;
  2124.  
  2125.         do
  2126.         {
  2127.             if  (symPtr->StorageClass  == IMAGE_SYM_CLASS_STATIC &&
  2128.                  symPtr->SectionNumber > 0)
  2129.             {
  2130.                 if  (symPtr->SectionNumber != sectNum)
  2131.                 {
  2132.                     for (sectNum = 1, sectRVA  = baseRVA, sectPtr = sectTab;
  2133.                          sectNum < symPtr->SectionNumber;
  2134.                          sectNum++)
  2135.                     {
  2136.                         if  (!(sectPtr->Characteristics & IMAGE_SCN_MEM_DISCARDABLE))
  2137.                             sectRVA += sectPtr->SizeOfRawData;
  2138.  
  2139.                         sectPtr += 1;
  2140.                     }
  2141.                 }
  2142.  
  2143.                 if  (!(sectPtr->Characteristics & IMAGE_SCN_MEM_DISCARDABLE))
  2144.                 {
  2145.                     if  (symPtr->Value != 0)
  2146.                     {
  2147.                         UNIMPL("hang on - a COFF symbol with a value, what now?");
  2148.                     }
  2149.  
  2150.                     symPtr->Value = sectRVA;
  2151.  
  2152. //                  char temp[9]; memcpy(temp, symPtr->N.ShortName, sizeof(symPtr->N.ShortName)); temp[8] = 0;
  2153. //                  printf("Symbol  %8s: sect=%u RVA=%08X\n", temp, sectNum, sectRVA);
  2154.  
  2155.                     sectRVA += sectPtr->SizeOfRawData;
  2156.                 }
  2157.  
  2158.                 sectPtr += 1;
  2159.                 sectNum += 1;
  2160.             }
  2161.         }
  2162.         while (++symPtr, --symNum);
  2163.     }
  2164.  
  2165.     /* Output the sections to the output file */
  2166.  
  2167.     sectRVA = baseRVA;
  2168.  
  2169.     do
  2170.     {
  2171.         unsigned        relCnt;
  2172.  
  2173.         const   BYTE  * sectAdr;
  2174.         size_t          sectSiz;
  2175.  
  2176.         if  (sectTab->Characteristics & IMAGE_SCN_MEM_DISCARDABLE)
  2177.             continue;
  2178.  
  2179.         /* Figure out the address/size of the section contents in memory */
  2180.  
  2181.         sectAdr = sectTab->PointerToRawData + fileBase;
  2182.         sectSiz = sectTab->   SizeOfRawData;
  2183.  
  2184.         /* Are there any relocs in this section? */
  2185.  
  2186.         relCnt  = sectTab->NumberOfRelocations;
  2187.         if  (relCnt)
  2188.         {
  2189.             BYTE              * buffAdr;
  2190.             IMAGE_RELOCATION  * relTab = (IMAGE_RELOCATION*)(fileBase + sectTab->PointerToRelocations);
  2191.  
  2192.             /* Make a copy of the section so we can scribble on it */
  2193.  
  2194.             buffAdr = (BYTE*)WPEalloc->nraAlloc(roundUp(sectSiz));
  2195.             memcpy(buffAdr, sectAdr, sectSiz); sectAdr = buffAdr;
  2196.  
  2197.             do
  2198.             {
  2199.                 unsigned                symNum = relTab->SymbolTableIndex;
  2200.                 IMAGE_SYMBOL          * symPtr = symTab + symNum;
  2201.                 IMAGE_SECTION_HEADER  * sectTmp;
  2202.  
  2203. //              printf("Reloc at offs %04X: symbol = %u, type = %u\n", relTab->VirtualAddress,
  2204. //                                                                     relTab->SymbolTableIndex,
  2205. //                                                                     relTab->Type);
  2206.  
  2207.                 if  (relTab->Type != IMAGE_REL_I386_DIR32NB)
  2208.                 {
  2209.                     UNIMPL("unrecognized fixup type found in .res file");
  2210.                 }
  2211.  
  2212.                 assert(symNum < symCnt);
  2213.  
  2214.                 if  (symPtr->StorageClass != IMAGE_SYM_CLASS_STATIC)
  2215.                 {
  2216.                     UNIMPL("unrecognized fixup target symbol found in .res file");
  2217.                 }
  2218.  
  2219.                 assert(symPtr->SectionNumber  >  0);
  2220.                 assert(symPtr->SectionNumber  <= (int)hdrPtr->NumberOfSections);
  2221.  
  2222. //              printf("Fixup location @ %04X\n", relTab->VirtualAddress);
  2223. //              printf("Fixup   symbol @ %08X\n", symPtr->Value);
  2224. //              printf("Fixup section  #  u  \n", symPtr->SectionNumber);
  2225.  
  2226.                 sectTmp = sectTab + symPtr->SectionNumber;
  2227.  
  2228. //              printf("Section offset = %08X\n", sectTab->VirtualAddress);
  2229. //              printf("Section size   = %04X\n", sectTab->SizeOfRawData);
  2230.  
  2231.                 assert(relTab->VirtualAddress >= 0);
  2232.                 assert(relTab->VirtualAddress <  sectTmp->SizeOfRawData);
  2233.  
  2234.                 *(int*)(sectAdr + relTab->VirtualAddress) += symPtr->Value;
  2235.             }
  2236.             while (++relTab, --relCnt);
  2237.         }
  2238.  
  2239.         /* Append the section to the output file */
  2240.  
  2241.         outf->outFileWriteData(sectAdr, sectSiz);
  2242.  
  2243.         sectRVA += sectTab->SizeOfRawData;
  2244.     }
  2245.     while (++sectTab, --sectCnt);
  2246. }
  2247.  
  2248. /*****************************************************************************/
  2249.