| 1 | /* $Id: libconv.c,v 1.3 2000-09-02 21:07:53 bird Exp $
 | 
|---|
| 2 |  *
 | 
|---|
| 3 |  * Very simple OMF/LIB dumper.
 | 
|---|
| 4 |  *
 | 
|---|
| 5 |  * Copyright (c) 1999 knut st. osmundsen
 | 
|---|
| 6 |  *
 | 
|---|
| 7 |  * Project Odin Software License can be found in LICENSE.TXT
 | 
|---|
| 8 |  *
 | 
|---|
| 9 |  */
 | 
|---|
| 10 | 
 | 
|---|
| 11 | 
 | 
|---|
| 12 | /*@Header***********************************************************************
 | 
|---|
| 13 | *   Header Files                                                               *
 | 
|---|
| 14 | *******************************************************************************/
 | 
|---|
| 15 | #include <stdio.h>
 | 
|---|
| 16 | #include <string.h>
 | 
|---|
| 17 | #include <malloc.h>
 | 
|---|
| 18 | 
 | 
|---|
| 19 | 
 | 
|---|
| 20 | #include "include/omf.h"
 | 
|---|
| 21 | 
 | 
|---|
| 22 | int fCodeToCode16 = 0;
 | 
|---|
| 23 | int fRemoveExtra = 0;
 | 
|---|
| 24 | 
 | 
|---|
| 25 | /*@IntFunc**********************************************************************
 | 
|---|
| 26 | *   Internal Functions                                                         *
 | 
|---|
| 27 | *******************************************************************************/
 | 
|---|
| 28 | int processFile(const char *pszFilename, const char *pszFilenameOut);
 | 
|---|
| 29 | void *processRecord(void *pvRecord, void *pvBase, FILE *phNew, unsigned short *ausTrans);
 | 
|---|
| 30 | 
 | 
|---|
| 31 | 
 | 
|---|
| 32 | 
 | 
|---|
| 33 | int main(int argc, char **argv)
 | 
|---|
| 34 | {
 | 
|---|
| 35 |     int rc = 0;
 | 
|---|
| 36 |     int argi = 1;
 | 
|---|
| 37 | 
 | 
|---|
| 38 |     if (argc == 4)
 | 
|---|
| 39 |     {
 | 
|---|
| 40 |         argi = 2;
 | 
|---|
| 41 |         fRemoveExtra = 1;
 | 
|---|
| 42 |     }
 | 
|---|
| 43 |     if (argc != 3)
 | 
|---|
| 44 |         printf("syntax error - requires two filename, in.lib and out.lib\n");
 | 
|---|
| 45 | 
 | 
|---|
| 46 |     rc = processFile(argv[argi], argv[argi+1]);
 | 
|---|
| 47 | 
 | 
|---|
| 48 |     return rc;
 | 
|---|
| 49 | }
 | 
|---|
| 50 | 
 | 
|---|
| 51 | 
 | 
|---|
| 52 | 
 | 
|---|
| 53 | 
 | 
|---|
| 54 | int processFile(const char *pszFilename, const char *pszFilenameOut)
 | 
|---|
| 55 | {
 | 
|---|
| 56 |     FILE *phFile;
 | 
|---|
| 57 |     FILE *phNew;
 | 
|---|
| 58 |     char *psz;
 | 
|---|
| 59 |     int rc = 0;
 | 
|---|
| 60 | 
 | 
|---|
| 61 |     psz = strrchr(pszFilename, '\\');
 | 
|---|
| 62 |     if (psz)
 | 
|---|
| 63 |         fCodeToCode16 = stricmp(psz, "\\dhcalls.lib") == 0;
 | 
|---|
| 64 | 
 | 
|---|
| 65 |     phFile = fopen(pszFilename, "rb");
 | 
|---|
| 66 |     phNew = fopen(pszFilenameOut, "wb");
 | 
|---|
| 67 |     if (phFile != NULL && phNew != NULL)
 | 
|---|
| 68 |     {
 | 
|---|
| 69 |         int cbFile;
 | 
|---|
| 70 | 
 | 
|---|
| 71 |         /* get size of file */
 | 
|---|
| 72 |         if (!fseek(phFile, 0, SEEK_END)
 | 
|---|
| 73 |             && (cbFile = ftell(phFile) ) != -1
 | 
|---|
| 74 |             && !fseek(phFile, 0, SEEK_SET)
 | 
|---|
| 75 |             )
 | 
|---|
| 76 |         {
 | 
|---|
| 77 |             void *pvFile;
 | 
|---|
| 78 | 
 | 
|---|
| 79 |             /* allocater memory */
 | 
|---|
| 80 |             pvFile = malloc(cbFile);
 | 
|---|
| 81 |             if (pvFile != NULL)
 | 
|---|
| 82 |             {
 | 
|---|
| 83 |                 /* read the whole file */
 | 
|---|
| 84 |                 if (fread(pvFile, cbFile, 1, phFile) == 1)
 | 
|---|
| 85 |                 {
 | 
|---|
| 86 |                     unsigned short * ausTrans = calloc(sizeof(unsigned short), cbFile / 16 ); /* Assumes page size of 16 FIXME! */
 | 
|---|
| 87 |                     void *pvNew = pvFile;
 | 
|---|
| 88 | 
 | 
|---|
| 89 | 
 | 
|---|
| 90 |                     /*  main loop */
 | 
|---|
| 91 |                     while (pvNew < (void*)(cbFile + (int)pvFile))
 | 
|---|
| 92 |                         pvNew = processRecord(pvNew, pvFile, phNew, ausTrans);
 | 
|---|
| 93 |                 }
 | 
|---|
| 94 |                 else
 | 
|---|
| 95 |                     rc = 4;
 | 
|---|
| 96 |             }
 | 
|---|
| 97 |             else
 | 
|---|
| 98 |                 rc = 3;
 | 
|---|
| 99 |         }
 | 
|---|
| 100 |         else
 | 
|---|
| 101 |             rc = 2;
 | 
|---|
| 102 |         fclose(phFile);
 | 
|---|
| 103 |         fclose(phNew);
 | 
|---|
| 104 |     }
 | 
|---|
| 105 |     else
 | 
|---|
| 106 |         rc = 1;
 | 
|---|
| 107 | 
 | 
|---|
| 108 |     return rc;
 | 
|---|
| 109 | }
 | 
|---|
| 110 | 
 | 
|---|
| 111 | 
 | 
|---|
| 112 | 
 | 
|---|
| 113 | void *processRecord(void *pvRecord, void *pvBase, FILE *phNew, unsigned short *ausTrans)
 | 
|---|
| 114 | {
 | 
|---|
| 115 |     static char *apszLNames[256];
 | 
|---|
| 116 |     static int   cpszLNames = 0;
 | 
|---|
| 117 |     static int   iCode16 = 0;
 | 
|---|
| 118 |     static int   cbPage = 16;       /* fixme todo TODO FIXME ASSUMES: pagesize = 16 */
 | 
|---|
| 119 |     void *pvRet = pvRecord;
 | 
|---|
| 120 |     int  cbRecord;
 | 
|---|
| 121 |     int  i;
 | 
|---|
| 122 |     int  fChanged = 0;
 | 
|---|
| 123 | 
 | 
|---|
| 124 |     switch (*(unsigned char*)pvRecord)
 | 
|---|
| 125 |     {
 | 
|---|
| 126 |        case LIBHDR:
 | 
|---|
| 127 |             if (*(unsigned short*)((int)pvRecord+1) < 6)
 | 
|---|
| 128 |                 fprintf(stderr, "error: not supported LIBHDR\n");
 | 
|---|
| 129 |             cbRecord = *((unsigned short*)((int)pvRecord+1)) + 3;
 | 
|---|
| 130 |             break;
 | 
|---|
| 131 | 
 | 
|---|
| 132 |         case THEADR:
 | 
|---|
| 133 |             /* Add entry to the translation table - used to translate block numbers in the dictionary */
 | 
|---|
| 134 |             ausTrans[((char*)pvRecord - (char*)pvBase) / cbPage] = (unsigned short)(ftell(phNew) / cbPage);
 | 
|---|
| 135 |             cbRecord = *((unsigned short*)((int)pvRecord+1)) + 3;
 | 
|---|
| 136 |             break;
 | 
|---|
| 137 | 
 | 
|---|
| 138 |         case SEGDEF: /* 16-bit segdef */
 | 
|---|
| 139 |             cbRecord = *((unsigned short*)((int)pvRecord+1)) + 3;
 | 
|---|
| 140 |             *((char*)pvRecord + 9) =  0;
 | 
|---|
| 141 |             i = *(char*)((int)pvRecord + 6);
 | 
|---|
| 142 |             if (cbRecord == 10 && i <= cpszLNames && strcmp(apszLNames[i-1], "CODE") == 0)
 | 
|---|
| 143 |             {
 | 
|---|
| 144 |                 *(char*)((int)pvRecord + 6) = iCode16+1;
 | 
|---|
| 145 |             }
 | 
|---|
| 146 |             i = *(char*)((int)pvRecord + 6);
 | 
|---|
| 147 |             if (cbRecord == 10 &&  (*((char *)pvRecord + 3) & 0xE0) == 0x20 && i <= cpszLNames && strcmp(apszLNames[i-1], "CODE16_IOSEG") == 0)
 | 
|---|
| 148 |             {   /* change alignment of this segment... */
 | 
|---|
| 149 |                 /* fprintf(stderr, "debug %s 0x%02x\n", apszLNames[*(char*)((int)pvRecord + 6) - 1], (*((char *)pvRecord + 3) & 0xFF)); */
 | 
|---|
| 150 |                 *((char*)pvRecord + 3) =  0x40 | (*((char*)pvRecord + 3) & 0x1F);
 | 
|---|
| 151 |             }
 | 
|---|
| 152 |             break;
 | 
|---|
| 153 | 
 | 
|---|
| 154 |         case MODEND:
 | 
|---|
| 155 |         case MODEND2:
 | 
|---|
| 156 |         {
 | 
|---|
| 157 |             unsigned long ul = (unsigned long)pvRecord - (unsigned long)pvBase;
 | 
|---|
| 158 | 
 | 
|---|
| 159 |             cbRecord = *((unsigned short*)((int)pvRecord+1)) + 3;
 | 
|---|
| 160 |             /* it seems to be somthing funny here! - lets try aligning it to on a 16 bytes boundrary... */
 | 
|---|
| 161 |             /* PS. I know this I have a wrong approch to the lib files, not using the directory... */
 | 
|---|
| 162 |             /* Aug 13 2000 4:24am: The alignment of modules are found in the library header.
 | 
|---|
| 163 |              *    It's the size of the library header.
 | 
|---|
| 164 |              *    Not implemented yet. TODO FIXME BUGBUG ASSUMES
 | 
|---|
| 165 |              */
 | 
|---|
| 166 |             fChanged = 1;
 | 
|---|
| 167 |             fwrite(pvRecord, 1, cbRecord, phNew);
 | 
|---|
| 168 |             ul += cbRecord;
 | 
|---|
| 169 |             if (*((unsigned char*)((int)pvRecord+cbRecord)) == 0x00)
 | 
|---|
| 170 |             {
 | 
|---|
| 171 |                 if ((ul % cbPage) > 0)
 | 
|---|
| 172 |                     cbRecord += cbPage - (ul % cbPage);
 | 
|---|
| 173 |             }
 | 
|---|
| 174 |             /*if (*((unsigned char*)pvRecord + cbRecord) != LIBEND)*/
 | 
|---|
| 175 |             {
 | 
|---|
| 176 |                 ul = ftell(phNew);
 | 
|---|
| 177 |                 while (ul++ % cbPage != 0)
 | 
|---|
| 178 |                     fputc(0, phNew);
 | 
|---|
| 179 |             }
 | 
|---|
| 180 |             while (cpszLNames-- > 0)
 | 
|---|
| 181 |                 free(apszLNames[cpszLNames]);
 | 
|---|
| 182 |         } break;
 | 
|---|
| 183 | 
 | 
|---|
| 184 |         case PUBDEF:
 | 
|---|
| 185 |         {
 | 
|---|
| 186 |             cbRecord = *((unsigned short*)((int)pvRecord+1)) + 3;
 | 
|---|
| 187 |             *((char*)pvRecord + cbRecord - 1) = 0;
 | 
|---|
| 188 |             break;
 | 
|---|
| 189 |         }
 | 
|---|
| 190 | 
 | 
|---|
| 191 |         case LNAMES:
 | 
|---|
| 192 |         {
 | 
|---|
| 193 |             char *apszConv[] =
 | 
|---|
| 194 |             {
 | 
|---|
| 195 |                 /* classes */
 | 
|---|
| 196 |                 "CODE",         "CODE",
 | 
|---|
| 197 |                 "IOSEG_CODE",   "CODE",
 | 
|---|
| 198 |                 "DATA",         "FAR_DATA",
 | 
|---|
| 199 |                 "BSS",          "DATA16BSS",
 | 
|---|
| 200 |                 "CONST",        "DATA16CONST",
 | 
|---|
| 201 |                 /* segment names */
 | 
|---|
| 202 |                 "_TEXT",        "CODE16",
 | 
|---|
| 203 |                 "_IOSEG",       "CODE16_IOSEG",
 | 
|---|
| 204 |                 "_CODE",        "CODE16",           /* dhcalls */
 | 
|---|
| 205 |                 "_DATA",        "DATA16",
 | 
|---|
| 206 |                 "_BSS",         "DATA16BSS",
 | 
|---|
| 207 |                 "_CONST",       "DATA16CONST",
 | 
|---|
| 208 |                 /* groups */
 | 
|---|
| 209 |                 "DGROUP",       "DATA16_GROUP",
 | 
|---|
| 210 |                 NULL, NULL
 | 
|---|
| 211 |             };
 | 
|---|
| 212 | 
 | 
|---|
| 213 |             int     cb;
 | 
|---|
| 214 |             int     cbNew; /* record size */
 | 
|---|
| 215 |             char   *psz;
 | 
|---|
| 216 |             iCode16 = -1;
 | 
|---|
| 217 | 
 | 
|---|
| 218 |             cpszLNames = 0;
 | 
|---|
| 219 |             cbRecord = *((unsigned short*)((int)pvRecord+1)) + 3;
 | 
|---|
| 220 |             cb = 3;
 | 
|---|
| 221 |             cbNew = 1;
 | 
|---|
| 222 |             psz = (char*)pvRecord + 3;
 | 
|---|
| 223 |             while (cb < cbRecord-1)
 | 
|---|
| 224 |             {
 | 
|---|
| 225 |                 int j = 0;
 | 
|---|
| 226 |                 char szName[256];
 | 
|---|
| 227 | 
 | 
|---|
| 228 |                 strncpy(szName, psz+1, *psz);
 | 
|---|
| 229 |                 szName[*psz] = '\0';
 | 
|---|
| 230 | 
 | 
|---|
| 231 |                 while (apszConv[j] != NULL && stricmp(szName, apszConv[j]) != 0)
 | 
|---|
| 232 |                     j += 2;
 | 
|---|
| 233 | 
 | 
|---|
| 234 |                 if (apszConv[j] == NULL)
 | 
|---|
| 235 |                 {
 | 
|---|
| 236 |                     cbNew += *psz + 1;
 | 
|---|
| 237 |                     if (*psz != 0)
 | 
|---|
| 238 |                         printf("LNAMES: %.*s was not converted\n", *psz, psz+1);
 | 
|---|
| 239 |                     apszLNames[cpszLNames++] = strdup(&szName[0]);
 | 
|---|
| 240 |                 }
 | 
|---|
| 241 |                 else
 | 
|---|
| 242 |                 {
 | 
|---|
| 243 |                     cbNew += strlen(apszConv[j+1]) + 1;
 | 
|---|
| 244 |                     if (strcmp(apszConv[j+1], "CODE16") == 0)
 | 
|---|
| 245 |                         iCode16 = cpszLNames;
 | 
|---|
| 246 |                     apszLNames[cpszLNames++] = strdup(apszConv[j+1]);
 | 
|---|
| 247 |                 }
 | 
|---|
| 248 |                 cb += *psz + 1;
 | 
|---|
| 249 |                 psz += 1 + *psz;
 | 
|---|
| 250 |             }
 | 
|---|
| 251 | 
 | 
|---|
| 252 |             if (iCode16 == -1)
 | 
|---|
| 253 |             {
 | 
|---|
| 254 |                 iCode16 = cpszLNames;
 | 
|---|
| 255 |                 apszLNames[cpszLNames++] = strdup("CODE16");
 | 
|---|
| 256 |                 cbNew += 1 + 6;
 | 
|---|
| 257 |             }
 | 
|---|
| 258 | 
 | 
|---|
| 259 |             fChanged = 1;
 | 
|---|
| 260 |             fputc(LNAMES, phNew);
 | 
|---|
| 261 |             fwrite(&cbNew, 1, 2, phNew);
 | 
|---|
| 262 | 
 | 
|---|
| 263 |             for (i = 0; i < cpszLNames; i++)
 | 
|---|
| 264 |             {
 | 
|---|
| 265 |                 fputc(strlen(apszLNames[i]), phNew);
 | 
|---|
| 266 |                 fwrite(apszLNames[i], 1, strlen(apszLNames[i]), phNew);
 | 
|---|
| 267 |             }
 | 
|---|
| 268 | 
 | 
|---|
| 269 |             fputc(0, phNew);
 | 
|---|
| 270 |             break;
 | 
|---|
| 271 |         }
 | 
|---|
| 272 | 
 | 
|---|
| 273 |         case LIBEND:
 | 
|---|
| 274 |         {
 | 
|---|
| 275 |             /* align dictionary at 512 byte (3 is min size of this record) */
 | 
|---|
| 276 |             int cBlocks;
 | 
|---|
| 277 |             unsigned short int cbSize  = (((ftell(phNew) + 3 + 0x1ff) & ~0x1ff) - ftell(phNew)) - 3;
 | 
|---|
| 278 |             unsigned long int  offDict = ftell(phNew) + cbSize + 3;
 | 
|---|
| 279 |             cbRecord = cbSize + 3;
 | 
|---|
| 280 |             fwrite(pvRecord, 1, 1, phNew);
 | 
|---|
| 281 |             fwrite(&cbSize, 1, sizeof(cbSize), phNew);
 | 
|---|
| 282 |             while (cbSize-- > 0)
 | 
|---|
| 283 |                 fwrite("\0", 1, 1, phNew);
 | 
|---|
| 284 | 
 | 
|---|
| 285 |             /* update header record. */
 | 
|---|
| 286 |             fseek(phNew, 3, SEEK_SET);
 | 
|---|
| 287 |             fwrite(&offDict, 1, sizeof(offDict), phNew);
 | 
|---|
| 288 |             fseek(phNew, offDict, SEEK_SET);
 | 
|---|
| 289 | 
 | 
|---|
| 290 |             /* Translate the dictionary */
 | 
|---|
| 291 |             pvRecord = (void*)((char*)pvRecord + *(unsigned short*)((char*)pvRecord + 1) + 3);
 | 
|---|
| 292 |             cBlocks = *(unsigned short *)((char*)pvBase + 7);
 | 
|---|
| 293 |             for (i = 0; i < cBlocks; i++)
 | 
|---|
| 294 |             {
 | 
|---|
| 295 |                 int j;
 | 
|---|
| 296 |                 char *pchBlock = (char*)pvRecord + i * 512;
 | 
|---|
| 297 |                 for (j = 0; j < 37; j++)
 | 
|---|
| 298 |                 {
 | 
|---|
| 299 |                     if (pchBlock[j] > 19 && pchBlock[j] < 0xff)
 | 
|---|
| 300 |                     {
 | 
|---|
| 301 |                         unsigned short *pusBlock = (unsigned short*)&pchBlock[pchBlock[j] * 2];
 | 
|---|
| 302 |                         pusBlock = (unsigned short *) ((char*)pusBlock + *(char*)pusBlock + 1);
 | 
|---|
| 303 |                         if (ausTrans[*pusBlock] == 0)
 | 
|---|
| 304 |                             fprintf(stderr, "error: dictionary entry don't point to a THEADR page!\n");
 | 
|---|
| 305 |                         else
 | 
|---|
| 306 |                             *pusBlock = ausTrans[*pusBlock];
 | 
|---|
| 307 |                     }
 | 
|---|
| 308 |                 }
 | 
|---|
| 309 | 
 | 
|---|
| 310 |             }
 | 
|---|
| 311 | 
 | 
|---|
| 312 |             /* Write the dictionary */
 | 
|---|
| 313 |             fwrite(pvRecord, 512, cBlocks, phNew);
 | 
|---|
| 314 |             return (void*)0xffffffff; /* FINE */
 | 
|---|
| 315 |         }
 | 
|---|
| 316 | 
 | 
|---|
| 317 |         case COMENT:
 | 
|---|
| 318 |         {
 | 
|---|
| 319 |             cbRecord = *((unsigned short*)((int)pvRecord+1)) + 3;
 | 
|---|
| 320 |             switch (*((unsigned char*)((int)pvRecord+4)))
 | 
|---|
| 321 |             {
 | 
|---|
| 322 |                 /* remove "Link Pass Separator" */
 | 
|---|
| 323 |                 case 0xA2:
 | 
|---|
| 324 |                 /* remove "LIBMOD" - The VAC 3.6.5 Linker don't like these! */
 | 
|---|
| 325 |                 case 0xA3:
 | 
|---|
| 326 |                     fChanged = fRemoveExtra;
 | 
|---|
| 327 |                     break;
 | 
|---|
| 328 |             }
 | 
|---|
| 329 |             break;
 | 
|---|
| 330 |         }
 | 
|---|
| 331 | 
 | 
|---|
| 332 |         /*
 | 
|---|
| 333 |          * Remove checksum
 | 
|---|
| 334 |          */
 | 
|---|
| 335 |         /*
 | 
|---|
| 336 |         case GRPDEF:
 | 
|---|
| 337 |         case FIXUPP:
 | 
|---|
| 338 |         case FIXUPP2:
 | 
|---|
| 339 |         case LEDATA:
 | 
|---|
| 340 |         {
 | 
|---|
| 341 |             cbRecord = *((unsigned short*)((int)pvRecord+1)) + 3;
 | 
|---|
| 342 |             *((char*)pvRecord + cbRecord - 1) = 0;
 | 
|---|
| 343 |             break;
 | 
|---|
| 344 |         }
 | 
|---|
| 345 |         */
 | 
|---|
| 346 | 
 | 
|---|
| 347 |         default:
 | 
|---|
| 348 |             cbRecord = *((unsigned short*)((int)pvRecord+1)) + 3;
 | 
|---|
| 349 |             break;
 | 
|---|
| 350 |     }
 | 
|---|
| 351 | 
 | 
|---|
| 352 |     if (!fChanged)
 | 
|---|
| 353 |         fwrite(pvRet, 1, cbRecord, phNew);
 | 
|---|
| 354 | 
 | 
|---|
| 355 | 
 | 
|---|
| 356 |     return (void*)((int)pvRet + cbRecord);
 | 
|---|
| 357 | }
 | 
|---|
| 358 | 
 | 
|---|
| 359 | 
 | 
|---|