CVCOMMON.C
上传用户:bangxh
上传日期:2007-01-31
资源大小:42235k
文件大小:19k
源码类别:

Windows编程

开发平台:

Visual C++

  1. /*++
  2. Copyright 1996 - 1997 Microsoft Corporation
  3. Module Name:
  4.     cvcommon.c
  5. Abstract:
  6.     This file contians a set of common routines which are used in
  7.     doing symbol conversions from one type of symbols to CodeView
  8.     symbols.
  9. Author:
  10.     Wesley A. Witt (wesw) 19-April-1993
  11.     Jim Schaad (jimsch) 22 May 1993
  12. --*/
  13. #include        <windows.h>
  14. #include        <stdlib.h>
  15. #include        "cv.h"
  16. #include        "symcvt.h"
  17. #include        "cvcommon.h"
  18. typedef struct tagSYMHASH {
  19.     DWORD       dwHashVal;         // hash value for the symbol
  20.     DWORD       dwHashBucket;      // hash bucket number
  21.     DATASYM16 * dataSym;           // pointer to the symbol info
  22. } SYMHASH;
  23. typedef struct tagOFFSETSORT {
  24.     DWORD       dwOffset;          // offset for the symbol
  25.     DWORD       dwSection;         // section number of the symbol
  26.     DATASYM16 * dataSym;           // pointer to the symbol info
  27. } OFFSETSORT;
  28. int _CRTAPI1 SymHashCompare( const void *arg1, const void *arg2 );
  29. int _CRTAPI1 OffsetSortCompare( const void *arg1, const void *arg2 );
  30. DWORD
  31. CreateSignature( PPOINTERS p )
  32. /*++
  33. Routine Description:
  34.     Creates the CODEVIEW signature record.  Currently this converter only
  35.     generates NB09 data (MS C/C++ 8.0).
  36. Arguments:
  37.     p        - pointer to a POINTERS structure (see symcvt.h)
  38. Return Value:
  39.     number of records generates, this is always 1.
  40. --*/
  41. {
  42.     OMFSignature        *omfSig;
  43.     omfSig = (OMFSignature *) p->pCvCurr;
  44.     strcpy( omfSig->Signature, "NB09" );
  45.     omfSig->filepos = 0;
  46.     p->pCvStart.size += sizeof(OMFSignature);
  47.     p->pCvCurr = (PUCHAR) p->pCvCurr + sizeof(OMFSignature);
  48.     return 1;
  49. }                               /* CreateSignature() */
  50. DWORD
  51. CreateDirectories( PPOINTERS p )
  52. /*++
  53. Routine Description:
  54.     This is the control function for the generation of the CV directories.
  55.     It calls individual functions for the generation of specific types of
  56.     debug directories.
  57. Arguments:
  58.     p        - pointer to a POINTERS structure (see symcvt.h)
  59. Return Value:
  60.     the number of directories created.
  61. --*/
  62. {
  63.     OMFDirHeader        *omfDir = (OMFDirHeader *)p->pCvCurr;
  64.     OMFSignature        *omfSig = (OMFSignature *)p->pCvStart.ptr;
  65.     OMFDirEntry         *omfDirEntry = NULL;
  66.     omfSig->filepos = (DWORD)p->pCvCurr - (DWORD)p->pCvStart.ptr;
  67.     omfDir->cbDirHeader = sizeof(OMFDirHeader);
  68.     omfDir->cbDirEntry  = sizeof(OMFDirEntry);
  69.     omfDir->cDir        = 0;
  70.     omfDir->lfoNextDir  = 0;
  71.     omfDir->flags       = 0;
  72.     p->pCvStart.size += sizeof(OMFDirHeader);
  73.     p->pCvCurr = (PUCHAR) p->pCvCurr + sizeof(OMFDirHeader);
  74.     omfDir->cDir += CreateModuleDirectoryEntries( p );
  75.     omfDir->cDir += CreatePublicDirectoryEntries( p );
  76.     omfDir->cDir += CreateSegMapDirectoryEntries( p );
  77.     omfDir->cDir += CreateSrcModulesDirectoryEntries( p );
  78.     strcpy(p->pCvCurr, "NB090000");
  79.     p->pCvStart.size += 8;
  80.     p->pCvCurr += 8;
  81.     *((DWORD *) (p->pCvCurr-4)) = p->pCvStart.size;
  82.     return omfDir->cDir;
  83. }                               /* CreateDirectories() */
  84. DWORD
  85. CreateModuleDirectoryEntries( PPOINTERS p )
  86. /*++
  87. Routine Description:
  88.     Creates directory entries for each module in the image.
  89. Arguments:
  90.     p        - pointer to a POINTERS structure (see symcvt.h)
  91. Return Value:
  92.     the number of directory entries created.
  93. --*/
  94. {
  95.     OMFDirEntry   *omfDirEntry = NULL;
  96.     OMFModule     *m = NULL;
  97.     OMFModule     *mNext = NULL;
  98.     DWORD         i = 0;
  99.     DWORD         mSize = 0;
  100.     DWORD         lfo = (DWORD)p->pCvModules.ptr - (DWORD)p->pCvStart.ptr;
  101.     m = (OMFModule *) p->pCvModules.ptr;
  102.     for (i=0; i<p->pCvModules.count; i++) {
  103.         mNext = NextMod(m);
  104.         omfDirEntry = (OMFDirEntry *) p->pCvCurr;
  105.         mSize = (DWORD)mNext - (DWORD)m;
  106.         omfDirEntry->SubSection = sstModule;
  107.         omfDirEntry->iMod       = (USHORT) i + 1;
  108.         omfDirEntry->lfo        = lfo;
  109.         omfDirEntry->cb         = mSize;
  110.         lfo += mSize;
  111.         p->pCvStart.size += sizeof(OMFDirEntry);
  112.         p->pCvCurr = (PUCHAR) p->pCvCurr + sizeof(OMFDirEntry);
  113.         m = mNext;
  114.     }
  115.     return p->pCvModules.count;
  116. }                               /* CreateModuleDirectoryEntries() */
  117. DWORD
  118. CreatePublicDirectoryEntries( PPOINTERS p )
  119. /*++
  120. Routine Description:
  121.     Creates the directory entry for the global publics.
  122. Arguments:
  123.     p        - pointer to a POINTERS structure (see symcvt.h)
  124. Return Value:
  125.     the number of directory entries created, always 1.
  126. --*/
  127. {
  128.     OMFDirEntry   *omfDirEntry = (OMFDirEntry *) p->pCvCurr;
  129.     omfDirEntry->SubSection = sstGlobalPub;
  130.     omfDirEntry->iMod       = 0xffff;
  131.     omfDirEntry->lfo        = (DWORD)p->pCvPublics.ptr - (DWORD)p->pCvStart.ptr;
  132.     omfDirEntry->cb         = p->pCvPublics.size;
  133.     p->pCvStart.size += sizeof(OMFDirEntry);
  134.     p->pCvCurr = (PUCHAR) p->pCvCurr + sizeof(OMFDirEntry);
  135.     return 1;
  136. }                               /* CreatePublicDirectoryEntries() */
  137. DWORD
  138. CreateSegMapDirectoryEntries( PPOINTERS p )
  139. /*++
  140. Routine Description:
  141.     Creates the directory entry for the segment map.
  142. Arguments:
  143.     p        - pointer to a POINTERS structure (see symcvt.h)
  144. Return Value:
  145.     the number of directory entries created, always 1.
  146. --*/
  147. {
  148.     OMFDirEntry   *omfDirEntry = (OMFDirEntry *) p->pCvCurr;
  149.     omfDirEntry->SubSection = sstSegMap;
  150.     omfDirEntry->iMod       = 0xffff;
  151.     omfDirEntry->lfo        = (DWORD)p->pCvSegMap.ptr - (DWORD)p->pCvStart.ptr;
  152.     omfDirEntry->cb         = p->pCvSegMap.size;
  153.     p->pCvStart.size += sizeof(OMFDirEntry);
  154.     p->pCvCurr = (PUCHAR) p->pCvCurr + sizeof(OMFDirEntry);
  155.     return 1;
  156. }                               /* CreateSegMapDirectoryEntries() */
  157. DWORD
  158. CreateSrcModulesDirectoryEntries( PPOINTERS p )
  159. /*++
  160. Routine Description:
  161.     Creates directory entries for each source module in the image.
  162. Arguments:
  163.     p        - pointer to a POINTERS structure (see symcvt.h)
  164. Return Value:
  165.     the number of directory entries created.
  166. --*/
  167. {
  168.     OMFDirEntry         *omfDirEntry = NULL;
  169.     DWORD               i;
  170.     DWORD               lfo = (DWORD)p->pCvSrcModules.ptr - (DWORD)p->pCvStart.ptr;
  171.     DWORD               j = lfo;
  172.     OMFSourceModule     *m;
  173.     //
  174.     // if there were no linenumber conversions then bail out
  175.     //
  176.     if (!p->pCvSrcModules.count) {
  177.         return 0;
  178.     }
  179.     for (i=0; i<p->pCvSrcModules.count; i++) {
  180.         if (!p->pMi[i].SrcModule) {
  181.             continue;
  182.         }
  183.         omfDirEntry = (OMFDirEntry *) p->pCvCurr;
  184.         omfDirEntry->SubSection = sstSrcModule;
  185.         omfDirEntry->iMod = (USHORT) p->pMi[i].iMod;
  186.         omfDirEntry->lfo = lfo;
  187.         omfDirEntry->cb = p->pMi[i].cb;
  188.         m = (OMFSourceModule*) p->pMi[i].SrcModule;
  189.         lfo += omfDirEntry->cb;
  190.         p->pCvStart.size += sizeof(OMFDirEntry);
  191.         p->pCvCurr = (PUCHAR) p->pCvCurr + sizeof(OMFDirEntry);
  192.     }
  193.     free( p->pMi );
  194.     return p->pCvSrcModules.count;
  195. }                               /* CreateSrcModulesDirectoryEntries() */
  196. #define byt_toupper(b)      (b & 0xDF)
  197. #define dwrd_toupper(dw)    (dw & 0xDFDFDFDF)
  198. DWORD
  199. DWordXorLrl( char *szSym )
  200. /*++
  201. Routine Description:
  202.     This function will take an ascii character string and generate
  203.     a hash for that string.  The hash algorithm is the CV NB09 hash
  204.     algorithm.
  205. Arguments:
  206.     szSym    - a character pointer, the first char is the string length
  207. Return Value:
  208.     The generated hash value.
  209. --*/
  210. {
  211.     char                *pName = szSym+1;
  212.     int                 cb =  *szSym;
  213.     char                *pch;
  214.     char                c;
  215.     DWORD               hash = 0, ulEnd = 0;
  216.     DWORD UNALIGNED     *pul;
  217.     // Replace all "::" with "__" for hashing purposes
  218.     c = *(pName+cb);
  219.     *(pName+cb) = '';
  220.     pch = strstr( pName, "::" );
  221.     if ( pch ) {
  222.         *pch++ = '_';
  223.         *pch   = '_';
  224.     }
  225.     *(pName+cb) = c;
  226.     // If we're standard call, skip the trailing @999
  227.     pch = pName + cb - 1;
  228.     while (isdigit(*pch)) {
  229.         pch--;
  230.     }
  231.     if (*pch == '@') {
  232.         cb = pch - pName;
  233.     }
  234.     // If we're fastcall, skip the leading '@'
  235.     if (*pName == '@') {
  236.         pName++;
  237.         cb--;
  238.     }
  239.     // Calculate the odd byte hash.
  240.     while (cb & 3) {
  241.         ulEnd |= byt_toupper (pName[cb-1]);
  242.         ulEnd <<=8;
  243.         cb--;
  244.     }
  245.     pul = (DWORD UNALIGNED *)pName;
  246.     // calculate the dword hash for the remaining
  247.     while (cb) {
  248.         hash ^= dwrd_toupper(*pul);
  249.         hash = _lrotl (hash, 4);
  250.         pul++;
  251.         cb -=4;
  252.     }
  253.     // or in the remainder
  254.     hash ^= ulEnd;
  255.     return hash;
  256. }                               /* DWordXorLrl() */
  257. OMFModule *
  258. NextMod(
  259.         OMFModule *             pMod
  260.         )
  261. /*++
  262. Routine Description:
  263.     description-of-function.
  264. Arguments:
  265.     argument-name - Supplies | Returns description of argument.
  266.     .
  267.     .
  268. Return Value:
  269.     return-value - Description of conditions needed to return value. - or -
  270.     None.
  271. --*/
  272. {
  273.     char *      pb;
  274.     pb = (char *) &(pMod->SegInfo[pMod->cSeg]);
  275.     pb += *pb + 1;
  276.     pb = (char *) (((unsigned long) pb + 3) & ~3);
  277.     return (OMFModule *) pb;
  278. }                               /* NextMod() */
  279. int
  280. _CRTAPI1
  281. SymHashCompare(
  282.                const void *     arg1,
  283.                const void *     arg2
  284.                )
  285. /*++
  286. Routine Description:
  287.     Sort compare function for sorting SYMHASH records by hashed
  288.     bucket number.
  289. Arguments:
  290.     arg1     - record #1
  291.     arg2     - record #2
  292. Return Value:
  293.    -1        - record #1 is < record #2
  294.     0        - records are equal
  295.     1        - record #1 is > record #2
  296. --*/
  297. {
  298.     if (((SYMHASH*)arg1)->dwHashBucket < ((SYMHASH*)arg2)->dwHashBucket) {
  299.         return -1;
  300.     }
  301.     if (((SYMHASH*)arg1)->dwHashBucket > ((SYMHASH*)arg2)->dwHashBucket) {
  302.         return 1;
  303.     }
  304.     // BUGBUG: Should we second sort on the hash value?
  305.     return 0;
  306. }                               /* SymHashCompare() */
  307. // Symbol Offset/Hash structure
  308. typedef struct _SOH {
  309.     DWORD uoff;
  310.     DWORD ulHash;
  311. } SOH;
  312. #define MINHASH     6           // Don't create a hash with fewer than 6 slots
  313. DWORD
  314. CreateSymbolHashTable(
  315.     PPOINTERS p
  316.     )
  317. /*++
  318. Routine Description:
  319.     Creates the CV symbol hash table.  This hash table is used
  320.     primarily by debuggers to access symbols in a quick manner.
  321. Arguments:
  322.     p        - pointer to a POINTERS structure (see symcvt.h)
  323. Return Value:
  324.     The number of buckets is the hash table.
  325. --*/
  326. {
  327.     DWORD           i;
  328.     DWORD           j;
  329.     int             k;
  330.     DWORD           numsyms;
  331.     DWORD           numbuckets;
  332.     OMFSymHash      *omfSymHash;
  333.     DATASYM16       *dataSymStart;
  334.     DATASYM16       *dataSym;
  335.     LPVOID          pHashData;
  336.     USHORT          *pCHash;
  337.     DWORD           *pHashTable;
  338.     DWORD           *pBucketCounts;
  339.     DWORD           *pChainTable;
  340.     SYMHASH         *symHashStart;
  341.     SYMHASH         *symHash;
  342. //    DWORD           dwHashVal;
  343.     char *          sz;
  344.     numsyms = p->pCvPublics.count;
  345.     numbuckets = (numsyms+9) / 10;
  346.     numbuckets = (1 + numbuckets) & ~1;
  347.     numbuckets = __max(numbuckets, MINHASH);
  348.     symHashStart =
  349.     symHash = (SYMHASH *) malloc( numsyms * sizeof(SYMHASH) );
  350.     if (symHashStart == NULL) {
  351.         return 0;
  352.     }
  353.     memset( symHashStart, 0, numsyms * sizeof(SYMHASH) );
  354.     pHashData = (LPVOID) p->pCvCurr;
  355.     pCHash = (USHORT *) pHashData;
  356.     pHashTable = (DWORD *) ((DWORD)pHashData + sizeof(DWORD));
  357.     pBucketCounts = (DWORD *) ((DWORD)pHashTable +
  358.                                   (sizeof(DWORD) * numbuckets));
  359.     memset(pBucketCounts, 0, sizeof(DWORD) * numbuckets);
  360.     pChainTable = (DWORD *) ((DWORD)pBucketCounts +
  361.                                  ((sizeof(ULONG) * numbuckets)));
  362.     omfSymHash = (OMFSymHash *) p->pCvPublics.ptr;
  363.     dataSymStart =
  364.     dataSym = (DATASYM16 *) ((DWORD)omfSymHash + sizeof(OMFSymHash));
  365.     *pCHash = (USHORT)numbuckets;
  366.     /*
  367.      *  cruise thru the symbols and calculate the hash values
  368.      *  and the hash bucket numbers; save the info away for later use
  369.      */
  370.     for (i=0; i<numsyms; i++, symHash++) {
  371.         switch( dataSym->rectyp ) {
  372.         case S_PUB16:
  373.             sz = dataSym->name;
  374.             break;
  375.         case S_PUB32:
  376.             sz = ((DATASYM32 *) dataSym)->name;
  377.             break;
  378.         default:
  379.             continue;
  380.         }
  381.         symHash->dwHashVal = DWordXorLrl( sz );
  382.         symHash->dwHashBucket = symHash->dwHashVal % numbuckets;
  383.         pBucketCounts[symHash->dwHashBucket] += 1;
  384.         symHash->dataSym = dataSym;
  385.         dataSym = ((DATASYM16 *) ((char *) dataSym + dataSym->reclen + 2));
  386.     }
  387.     qsort( (void*)symHashStart, numsyms, sizeof(SYMHASH), SymHashCompare );
  388.     j = (char *)pChainTable - (char *)pHashData;
  389.     for (i=0, k = 0;
  390.          i < numbuckets;
  391.          k += pBucketCounts[i], i += 1, pHashTable++ )
  392.     {
  393.         *pHashTable = (DWORD) j + (k * sizeof(DWORD) * 2);
  394.     }
  395.     dataSymStart = (DATASYM16 *) (PUCHAR)((DWORD)omfSymHash);
  396.     for (i=0,symHash=symHashStart; i<numsyms; i++,symHash++,pChainTable++) {
  397.         *pChainTable = (DWORD) (DWORD)symHash->dataSym - (DWORD)dataSymStart;
  398.         ++pChainTable;
  399.         *pChainTable = symHash->dwHashVal;
  400.     }
  401.     UpdatePtrs( p, &p->pCvSymHash, (LPVOID)pChainTable, numsyms );
  402.     omfSymHash->symhash = 10;
  403.     omfSymHash->cbHSym = p->pCvSymHash.size;
  404.     free( symHashStart );
  405.     return numbuckets;
  406. }                               /* CreateSymbolHashTable() */
  407. VOID
  408. UpdatePtrs( PPOINTERS p, PPTRINFO pi, LPVOID lpv, DWORD count )
  409. /*++
  410. Routine Description:
  411.     This function is called by ALL functions that put data into the
  412.     CV data area.  After putting the data into the CV memory this function
  413.     must be called.  It will adjust all of the necessary pointers so the
  414.     the next guy doesn't get hosed.
  415. Arguments:
  416.     p        - pointer to a POINTERS structure (see symcvt.h)
  417.     pi       - the CV pointer that is to be updated
  418.     lpv      - current pointer into the CV data
  419.     count    - the number of items that were placed into the CV data
  420. Return Value:
  421.     void
  422. --*/
  423. {
  424.     if (!count) {
  425.         return;
  426.     }
  427.     pi->ptr = p->pCvCurr;
  428.     pi->size = (DWORD) ((DWORD)lpv - (DWORD)p->pCvCurr);
  429.     pi->count = count;
  430.     p->pCvStart.size += pi->size;
  431.     p->pCvCurr = (PUCHAR) lpv;
  432.     return;
  433. }                               /* UpdatePtrs() */
  434. int
  435. _CRTAPI1
  436. OffsetSortCompare( const void *arg1, const void *arg2 )
  437. /*++
  438. Routine Description:
  439.     Sort compare function for sorting OFFETSORT records by section number.
  440. Arguments:
  441.     arg1     - record #1
  442.     arg2     - record #2
  443. Return Value:
  444.    -1        - record #1 is < record #2
  445.     0        - records are equal
  446.     1        - record #1 is > record #2
  447. --*/
  448. {
  449.     if (((OFFSETSORT*)arg1)->dwSection < ((OFFSETSORT*)arg2)->dwSection) {
  450.         return -1;
  451.     }
  452.     if (((OFFSETSORT*)arg1)->dwSection > ((OFFSETSORT*)arg2)->dwSection) {
  453.         return 1;
  454.     }
  455.     if (((OFFSETSORT*)arg1)->dwOffset < ((OFFSETSORT*)arg2)->dwOffset) {
  456.         return -1;
  457.     }
  458.     if (((OFFSETSORT*)arg1)->dwOffset > ((OFFSETSORT*)arg2)->dwOffset) {
  459.         return 1;
  460.     }
  461.     return 0;
  462. }                               /* OffsetSortCompare() */
  463. DWORD
  464. CreateAddressSortTable( PPOINTERS p )
  465. /*++
  466. Routine Description:
  467.     Creates the CV address sort table. This hash table is used
  468.     primarily by debuggers to access symbols in a quick manner when
  469.     all you have is an address.
  470. Arguments:
  471.     p        - pointer to a POINTERS structure (see symcvt.h)
  472. Return Value:
  473.     The number of sections in the table.
  474. --*/
  475. {
  476.     DWORD               i;
  477.     DWORD               j;
  478.     int                 k;
  479.     DWORD               numsyms = p->pCvPublics.count;
  480.     DWORD               numsections;
  481.     OMFSymHash          *omfSymHash;
  482.     DATASYM16           *dataSymStart;
  483.     DATASYM16           *dataSym;
  484.     LPVOID              pAddressData;
  485.     USHORT              *pCSeg;
  486.     DWORD               *pSegTable;
  487.     DWORD               *pOffsetCounts;
  488.     DWORD               *pOffsetTable;
  489.     OFFSETSORT          *pOffsetSortStart;
  490.     OFFSETSORT          *pOffsetSort;
  491.     extern int          CSymSegs;
  492.     if (p->iptrs.fileHdr) {
  493.         numsections = p->iptrs.fileHdr->NumberOfSections;
  494.     } else if (p->iptrs.sepHdr) {
  495.         numsections = p->iptrs.sepHdr->NumberOfSections;
  496.     } else {
  497.         numsections = CSymSegs;
  498.     }
  499.     pOffsetSortStart =
  500.       pOffsetSort = (OFFSETSORT *) malloc( numsyms * sizeof(OFFSETSORT) );
  501.     if (pOffsetSort == NULL) {
  502.         return 0;
  503.     }
  504.     memset( pOffsetSortStart, 0, numsyms * sizeof(OFFSETSORT) );
  505.     pAddressData = (LPVOID) p->pCvCurr;
  506.     pCSeg = (USHORT *) pAddressData;
  507.     pSegTable = (DWORD *) ((DWORD)pAddressData + sizeof(DWORD));
  508.     pOffsetCounts = (DWORD *) ((DWORD)pSegTable +
  509.                                 (sizeof(DWORD) * numsections));
  510.     pOffsetTable = (DWORD *) ((DWORD)pOffsetCounts +
  511.                               ((sizeof(DWORD) * numsections)));
  512. //    if (numsections & 1) {
  513. //        pOffsetTable = (DWORD *) ((DWORD)pOffsetTable + 2);
  514. //    }
  515.     omfSymHash = (OMFSymHash *) p->pCvPublics.ptr;
  516.     dataSymStart =
  517.       dataSym = (DATASYM16 *) ((DWORD)omfSymHash + sizeof(OMFSymHash));
  518.     *pCSeg = (USHORT)numsections;
  519.     for (i=0;
  520.          i<numsyms;
  521.          i++, pOffsetSort++)
  522.     {
  523.         switch(dataSym->rectyp) {
  524.         case S_PUB16:
  525.             pOffsetSort->dwOffset = dataSym->off;
  526.             pOffsetSort->dwSection = dataSym->seg;
  527.             break;
  528.         case S_PUB32:
  529.             pOffsetSort->dwOffset = ((DATASYM32 *) dataSym)->off;
  530.             pOffsetSort->dwSection = ((DATASYM32 *) dataSym)->seg;
  531.         }
  532.         pOffsetSort->dataSym = dataSym;
  533.         pOffsetCounts[pOffsetSort->dwSection - 1] += 1;
  534.         dataSym = ((DATASYM16 *) ((char *) dataSym + dataSym->reclen + 2));    }
  535. //#if 0
  536.     qsort((void*)pOffsetSortStart, numsyms, sizeof(OFFSETSORT),
  537.           OffsetSortCompare );
  538. //#endif
  539.     j = (DWORD) (DWORD)pOffsetTable - (DWORD)pAddressData;
  540.     for (i=0, k=0;
  541.          i < numsections;
  542.          k += pOffsetCounts[i], i += 1, pSegTable++)
  543.     {
  544.         *pSegTable = (DWORD) j + (k * sizeof(DWORD) * 2);
  545.     }
  546.     dataSymStart = (DATASYM16 *) (PUCHAR)((DWORD)omfSymHash);
  547.     for (i=0, pOffsetSort=pOffsetSortStart;
  548.          i < numsyms;
  549.          i++, pOffsetSort++, pOffsetTable++)
  550.     {
  551.         *pOffsetTable = (DWORD)pOffsetSort->dataSym - (DWORD)dataSymStart;
  552.         pOffsetTable++;
  553.         *pOffsetTable = pOffsetSort->dwOffset;
  554.     }
  555.     UpdatePtrs( p, &p->pCvAddrSort, (LPVOID)pOffsetTable, numsyms );
  556.     omfSymHash->addrhash = 12;
  557.     omfSymHash->cbHAddr = p->pCvAddrSort.size;
  558.     free( pOffsetSortStart );
  559.     return numsections;
  560. }                               /* CreateAddressSort() */