VirtualBox

source: vbox/trunk/src/VBox/ValidationKit/bootsectors/bs3kit/VBoxBs3ObjConverter.cpp@ 60009

Last change on this file since 60009 was 60009, checked in by vboxsync, 9 years ago

bs3kit: Updates

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 86.1 KB
Line 
1/* $Id: VBoxBs3ObjConverter.cpp 60009 2016-03-13 16:34:32Z vboxsync $ */
2/** @file
3 * VirtualBox Validation Kit - Boot Sector 3 object file convert.
4 */
5
6/*
7 * Copyright (C) 2006-2015 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#include <stdio.h>
32#include <string.h>
33#include <stdlib.h>
34#include <errno.h>
35#include <iprt/types.h>
36#include <iprt/ctype.h>
37#include <iprt/assert.h>
38#include <iprt/x86.h>
39
40#include <iprt/formats/elf64.h>
41#include <iprt/formats/elf-amd64.h>
42#include <iprt/formats/pecoff.h>
43#include <iprt/formats/omf.h>
44
45
46/*********************************************************************************************************************************
47* Defined Constants And Macros *
48*********************************************************************************************************************************/
49#if ARCH_BITS == 64 && !defined(RT_OS_WINDOWS) && !defined(RT_OS_DARWIN)
50# define ELF_FMT_X64 "lx"
51# define ELF_FMT_D64 "ld"
52#else
53# define ELF_FMT_X64 "llx"
54# define ELF_FMT_D64 "lld"
55#endif
56
57
58/*********************************************************************************************************************************
59* Global Variables *
60*********************************************************************************************************************************/
61/** Verbosity level. */
62static unsigned g_cVerbose = 0;
63
64
65/**
66 * Opens a file for binary reading or writing.
67 *
68 * @returns File stream handle.
69 * @param pszFile The name of the file.
70 * @param fWrite Whether to open for writing or reading.
71 */
72static FILE *openfile(const char *pszFile, bool fWrite)
73{
74#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
75 FILE *pFile = fopen(pszFile, fWrite ? "wb" : "rb");
76#else
77 FILE *pFile = fopen(pszFile, fWrite ? "w" : "r");
78#endif
79 if (!pFile)
80 fprintf(stderr, "error: Failed to open '%s' for %s: %s (%d)\n",
81 pszFile, fWrite ? "writing" : "reading", strerror(errno), errno);
82 return pFile;
83}
84
85
86/**
87 * Read the given file into memory.
88 *
89 * @returns true on success, false on failure.
90 * @param pszFile The file to read.
91 * @param ppvFile Where to return the memory.
92 * @param pcbFile Where to return the size.
93 */
94static bool readfile(const char *pszFile, void **ppvFile, size_t *pcbFile)
95{
96 FILE *pFile = openfile(pszFile, false);
97 if (pFile)
98 {
99 /*
100 * Figure the size.
101 */
102 if (fseek(pFile, 0, SEEK_END) == 0)
103 {
104 long cbFile = ftell(pFile);
105 if (cbFile > 0)
106 {
107 if (fseek(pFile, SEEK_SET, 0) == 0)
108 {
109 /*
110 * Allocate and read content.
111 */
112 void *pvFile = malloc((size_t)cbFile);
113 if (pvFile)
114 {
115 if (fread(pvFile, cbFile, 1, pFile) == 1)
116 {
117 *ppvFile = pvFile;
118 *pcbFile = (size_t)cbFile;
119 fclose(pFile);
120 return true;
121 }
122 free(pvFile);
123 fprintf(stderr, "error: fread failed in '%s': %s (%d)\n", pszFile, strerror(errno), errno);
124 }
125 else
126 fprintf(stderr, "error: failed to allocate %ld bytes of memory for '%s'\n", cbFile, pszFile);
127 }
128 else
129 fprintf(stderr, "error: fseek #2 failed in '%s': %s (%d)\n", pszFile, strerror(errno), errno);
130 }
131 else
132 fprintf(stderr, "error: ftell failed in '%s': %s (%d)\n", pszFile, strerror(errno), errno);
133 }
134 else
135 fprintf(stderr, "error: fseek #1 failed in '%s': %s (%d)\n", pszFile, strerror(errno), errno);
136 fclose(pFile);
137 }
138 return false;
139}
140
141
142/**
143 * Write the given file into memory.
144 *
145 * @returns true on success, false on failure.
146 * @param pszFile The file to write.
147 * @param pvFile Where to return the memory.
148 * @param cbFile Where to return the size.
149 */
150static bool writefile(const char *pszFile, void const *pvFile, size_t cbFile)
151{
152 remove(pszFile);
153
154 int rc = -1;
155 FILE *pFile = openfile(pszFile, true);
156 if (pFile)
157 {
158 if (fwrite(pvFile, cbFile, 1, pFile) == 1)
159 {
160 fclose(pFile);
161 return true;
162 }
163 fprintf(stderr, "error: fwrite failed in '%s': %s (%d)\n", pszFile, strerror(errno), errno);
164 fclose(pFile);
165 }
166 return false;
167}
168
169
170/**
171 * Reports an error and returns false.
172 *
173 * @returns false
174 * @param pszFile The filename.
175 * @param pszFormat The message format string.
176 * @param ... Format arguments.
177 */
178static bool error(const char *pszFile, const char *pszFormat, ...)
179{
180 fflush(stdout);
181 fprintf(stderr, "error: %s: ", pszFile);
182 va_list va;
183 va_start(va, pszFormat);
184 vfprintf(stderr, pszFormat, va);
185 va_end(va);
186 return false;
187}
188
189
190
191/*********************************************************************************************************************************
192* Common OMF Writer *
193*********************************************************************************************************************************/
194
195/** Entry for each segment/section in the source format for mapping it to a
196 * segment defintion. */
197typedef struct OMFTOSEGDEF
198{
199 /** The segment defintion index of the section, UINT16_MAX if not translated. */
200 uint16_t iSegDef;
201 /** The group index for this segment, UINT16_MAX if not applicable. */
202 uint16_t iGrpDef;
203 /** The class name table entry, UINT16_MAX if not applicable. */
204 uint16_t iClassNm;
205 /** The group name for this segment, UINT16_MAX if not applicable. */
206 uint16_t iGrpNm;
207 /** The group name for this segment, UINT16_MAX if not applicable. */
208 uint16_t iSegNm;
209 /** The number of public definitions for this segment. */
210 uint32_t cPubDefs;
211 /** The segment name (OMF). */
212 char *pszName;
213} OMFTOSEGDEF;
214/** Pointer to a segment/section to segdef mapping. */
215typedef OMFTOSEGDEF *POMFTOSEGDEF;
216
217/** Symbol table translation type. */
218typedef enum OMFSYMTYPE
219{
220 /** Invalid symbol table entry (aux sym). */
221 OMFSYMTYPE_INVALID = 0,
222 /** Ignored. */
223 OMFSYMTYPE_IGNORED,
224 /** A public defintion. */
225 OMFSYMTYPE_PUBDEF,
226 /** An external definition. */
227 OMFSYMTYPE_EXTDEF,
228 /** A segment reference for fixups. */
229 OMFSYMTYPE_SEGDEF,
230 /** Internal symbol that may be used for fixups. */
231 OMFSYMTYPE_INTERNAL
232} OMFSYMTYPE;
233
234/** Symbol table translation. */
235typedef struct OMFSYMBOL
236{
237 /** What this source symbol table entry should be translated into. */
238 OMFSYMTYPE enmType;
239 /** The OMF table index. UINT16_MAX if not applicable. */
240 uint16_t idx;
241 /** The OMF segment definition index. */
242 uint16_t idxSegDef;
243 /** The OMF group definition index. */
244 uint16_t idxGrpDef;
245} OMFSYMBOL;
246/** Pointer to an source symbol table translation entry. */
247typedef OMFSYMBOL *POMFSYMBOL;
248
249/**
250 * OMF converter & writer instance.
251 */
252typedef struct OMFWRITER
253{
254 /** The source file name (for bitching). */
255 const char *pszSrc;
256 /** The destination output file. */
257 FILE *pDst;
258
259 /** Number of source segments/sections. */
260 uint32_t cSegments;
261 /** Pointer to the table mapping from source segments/section to segdefs. */
262 POMFTOSEGDEF paSegments;
263
264 /** Number of entries in the source symbol table. */
265 uint32_t cSymbols;
266 /** Pointer to the table mapping from source symbols to OMF stuff. */
267 POMFSYMBOL paSymbols;
268
269 /** The index of the next list of names entry. */
270 uint16_t idxNextName;
271
272 /** The current record size. */
273 uint16_t cbRec;
274 /** The current record type */
275 uint8_t bType;
276 /** The record data buffer (too large, but whatever). */
277 uint8_t abData[_1K + 64];
278 /** Alignment padding. */
279 uint8_t abAlign[2];
280
281 /** Current FIXUPP entry. */
282 uint8_t iFixupp;
283 /** FIXUPP records being prepared for LEDATA currently stashed in abData.
284 * We may have to adjust addend values in the LEDATA when converting to OMF
285 * fixups. */
286 struct
287 {
288 uint16_t cbRec;
289 uint8_t abData[_1K + 64];
290 uint8_t abAlign[2]; /**< Alignment padding. */
291 } aFixupps[3];
292
293 /** The index of the FLAT group. */
294 uint16_t idxGrpFlat;
295 /** The EXTDEF index of the __ImageBase symbol. */
296 uint16_t idxExtImageBase;
297} OMFWRITE;
298/** Pointer to an OMF writer. */
299typedef OMFWRITE *POMFWRITER;
300
301
302/**
303 * Creates an OMF writer instance.
304 */
305static POMFWRITER omfWriter_Create(const char *pszSrc, uint32_t cSegments, uint32_t cSymbols, FILE *pDst)
306{
307 POMFWRITER pThis = (POMFWRITER)calloc(sizeof(OMFWRITER), 1);
308 if (pThis)
309 {
310 pThis->pszSrc = pszSrc;
311 pThis->idxNextName = 1; /* We start counting at 1. */
312 pThis->cSegments = cSegments;
313 pThis->paSegments = (POMFTOSEGDEF)calloc(sizeof(OMFTOSEGDEF), cSegments);
314 if (pThis->paSegments)
315 {
316 pThis->cSymbols = cSymbols;
317 pThis->paSymbols = (POMFSYMBOL)calloc(sizeof(OMFSYMBOL), cSymbols);
318 if (pThis->paSymbols)
319 {
320 pThis->pDst = pDst;
321 return pThis;
322 }
323 free(pThis->paSegments);
324 }
325 free(pThis);
326 }
327 error(pszSrc, "Out of memory!\n");
328 return NULL;
329}
330
331/**
332 * Destroys the given OMF writer instance.
333 * @param pThis OMF writer instance.
334 */
335static void omfWriter_Destroy(POMFWRITER pThis)
336{
337 free(pThis->paSymbols);
338 for (uint32_t i = 0; i < pThis->cSegments; i++)
339 if (pThis->paSegments[i].pszName)
340 free(pThis->paSegments[i].pszName);
341 free(pThis->paSegments);
342 free(pThis);
343}
344
345static bool omfWriter_RecBegin(POMFWRITER pThis, uint8_t bType)
346{
347 pThis->bType = bType;
348 pThis->cbRec = 0;
349 return true;
350}
351
352static bool omfWriter_RecAddU8(POMFWRITER pThis, uint8_t b)
353{
354 if (pThis->cbRec < OMF_MAX_RECORD_PAYLOAD)
355 {
356 pThis->abData[pThis->cbRec++] = b;
357 return true;
358 }
359 return error(pThis->pszSrc, "Exceeded max OMF record length (bType=%#x)!\n", pThis->bType);
360}
361
362static bool omfWriter_RecAddU16(POMFWRITER pThis, uint16_t u16)
363{
364 if (pThis->cbRec + 2 <= OMF_MAX_RECORD_PAYLOAD)
365 {
366 pThis->abData[pThis->cbRec++] = (uint8_t)u16;
367 pThis->abData[pThis->cbRec++] = (uint8_t)(u16 >> 8);
368 return true;
369 }
370 return error(pThis->pszSrc, "Exceeded max OMF record length (bType=%#x)!\n", pThis->bType);
371}
372
373static bool omfWriter_RecAddU32(POMFWRITER pThis, uint32_t u32)
374{
375 if (pThis->cbRec + 4 <= OMF_MAX_RECORD_PAYLOAD)
376 {
377 pThis->abData[pThis->cbRec++] = (uint8_t)u32;
378 pThis->abData[pThis->cbRec++] = (uint8_t)(u32 >> 8);
379 pThis->abData[pThis->cbRec++] = (uint8_t)(u32 >> 16);
380 pThis->abData[pThis->cbRec++] = (uint8_t)(u32 >> 24);
381 return true;
382 }
383 return error(pThis->pszSrc, "Exceeded max OMF record length (bType=%#x)!\n", pThis->bType);
384}
385
386static bool omfWriter_RecAddIdx(POMFWRITER pThis, uint16_t idx)
387{
388 if (idx < 128)
389 return omfWriter_RecAddU8(pThis, (uint8_t)idx);
390 if (idx < _32K)
391 return omfWriter_RecAddU8(pThis, (uint8_t)(idx >> 7) | 0x80)
392 && omfWriter_RecAddU8(pThis, (uint8_t)idx);
393 return error(pThis->pszSrc, "Index out of range %#x\n", idx);
394}
395
396static bool omfWriter_RecAddBytes(POMFWRITER pThis, const void *pvData, size_t cbData)
397{
398 if (cbData + pThis->cbRec <= OMF_MAX_RECORD_PAYLOAD)
399 {
400 memcpy(&pThis->abData[pThis->cbRec], pvData, cbData);
401 pThis->cbRec += (uint16_t)cbData;
402 return true;
403 }
404 return error(pThis->pszSrc, "Exceeded max OMF record length (bType=%#x, cbData=%#x)!\n", pThis->bType, (unsigned)cbData);
405}
406
407static bool omfWriter_RecAddStringN(POMFWRITER pThis, const char *pchString, size_t cchString)
408{
409 if (cchString < 256)
410 {
411 return omfWriter_RecAddU8(pThis, (uint8_t)cchString)
412 && omfWriter_RecAddBytes(pThis, pchString, cchString);
413 }
414 return error(pThis->pszSrc, "String too long (%u bytes): '%*.*s'\n",
415 (unsigned)cchString, (int)cchString, (int)cchString, pchString);
416}
417
418static bool omfWriter_RecAddString(POMFWRITER pThis, const char *pszString)
419{
420 return omfWriter_RecAddStringN(pThis, pszString, strlen(pszString));
421}
422
423static bool omfWriter_RecEnd(POMFWRITER pThis, bool fAddCrc)
424{
425 if ( !fAddCrc
426 || omfWriter_RecAddU8(pThis, 0))
427 {
428 OMFRECHDR RecHdr = { pThis->bType, RT_H2LE_U16(pThis->cbRec) };
429 if ( fwrite(&RecHdr, sizeof(RecHdr), 1, pThis->pDst) == 1
430 && fwrite(pThis->abData, pThis->cbRec, 1, pThis->pDst) == 1)
431 {
432 pThis->bType = 0;
433 pThis->cbRec = 0;
434 return true;
435 }
436 return error(pThis->pszSrc, "Write error\n");
437 }
438 return false;
439}
440
441static bool omfWriter_RecEndWithCrc(POMFWRITER pThis)
442{
443 return omfWriter_RecEnd(pThis, true /*fAddCrc*/);
444}
445
446
447static bool omfWriter_BeginModule(POMFWRITER pThis, const char *pszFile)
448{
449 return omfWriter_RecBegin(pThis, OMF_THEADR)
450 && omfWriter_RecAddString(pThis, pszFile)
451 && omfWriter_RecEndWithCrc(pThis);
452}
453
454static bool omfWriter_LNamesAddN(POMFWRITER pThis, const char *pchName, size_t cchName, uint16_t *pidxName)
455{
456 /* split? */
457 if (pThis->cbRec + 1 /*len*/ + cchName + 1 /*crc*/ > OMF_MAX_RECORD_PAYLOAD)
458 {
459 if (pThis->cbRec == 0)
460 return error(pThis->pszSrc, "Too long LNAME '%*.*s'\n", (int)cchName, (int)cchName, pchName);
461 if ( !omfWriter_RecEndWithCrc(pThis)
462 || !omfWriter_RecBegin(pThis, OMF_LNAMES))
463 return false;
464 }
465
466 if (pidxName)
467 *pidxName = pThis->idxNextName;
468 pThis->idxNextName++;
469 return omfWriter_RecAddStringN(pThis, pchName, cchName);
470}
471
472static bool omfWriter_LNamesAdd(POMFWRITER pThis, const char *pszName, uint16_t *pidxName)
473{
474 return omfWriter_LNamesAddN(pThis, pszName, strlen(pszName), pidxName);
475}
476
477static bool omfWriter_LNamesBegin(POMFWRITER pThis)
478{
479 /* First entry is an empty string. */
480 return omfWriter_RecBegin(pThis, OMF_LNAMES)
481 && ( pThis->idxNextName > 1
482 || omfWriter_LNamesAddN(pThis, "", 0, NULL));
483}
484
485static bool omfWriter_LNamesEnd(POMFWRITER pThis)
486{
487 return omfWriter_RecEndWithCrc(pThis);
488}
489
490
491static bool omfWriter_SegDef(POMFWRITER pThis, uint8_t bSegAttr, uint32_t cbSeg, uint16_t idxSegName, uint16_t idxSegClass)
492{
493 return omfWriter_RecBegin(pThis, OMF_SEGDEF32)
494 && omfWriter_RecAddU8(pThis, bSegAttr)
495 && omfWriter_RecAddU32(pThis, cbSeg)
496 && omfWriter_RecAddIdx(pThis, idxSegName)
497 && omfWriter_RecAddIdx(pThis, idxSegClass)
498 && omfWriter_RecAddIdx(pThis, 1) /* overlay name index = NULL entry */
499 && omfWriter_RecEndWithCrc(pThis);
500}
501
502static bool omfWriter_GrpDefBegin(POMFWRITER pThis, uint16_t idxGrpName)
503{
504 return omfWriter_RecBegin(pThis, OMF_GRPDEF)
505 && omfWriter_RecAddIdx(pThis, idxGrpName);
506}
507
508static bool omfWriter_GrpDefAddSegDef(POMFWRITER pThis, uint16_t idxSegDef)
509{
510 return omfWriter_RecAddU8(pThis, 0xff)
511 && omfWriter_RecAddIdx(pThis, idxSegDef);
512}
513
514static bool omfWriter_GrpDefEnd(POMFWRITER pThis)
515{
516 return omfWriter_RecEndWithCrc(pThis);
517}
518
519
520static bool omfWriter_PubDefBegin(POMFWRITER pThis, uint16_t idxGrpDef, uint16_t idxSegDef)
521{
522 return omfWriter_RecBegin(pThis, OMF_PUBDEF32)
523 && omfWriter_RecAddIdx(pThis, idxGrpDef)
524 && omfWriter_RecAddIdx(pThis, idxSegDef)
525 && ( idxSegDef != 0
526 || omfWriter_RecAddU16(pThis, 0));
527
528}
529
530static bool omfWriter_PubDefAddN(POMFWRITER pThis, uint32_t uValue, const char *pchString, size_t cchString)
531{
532 /* Split? */
533 if (pThis->cbRec + 1 + cchString + 4 + 1 + 1 > OMF_MAX_RECORD_PAYLOAD)
534 {
535 if (cchString >= 256)
536 return error(pThis->pszSrc, "PUBDEF string too long %u ('%s')\n",
537 (unsigned)cchString, (int)cchString, (int)cchString, pchString);
538 if (!omfWriter_RecEndWithCrc(pThis))
539 return false;
540
541 /* Figure out the initial data length. */
542 pThis->cbRec = 1 + ((pThis->abData[0] & 0x80) != 0);
543 if (pThis->abData[pThis->cbRec] != 0)
544 pThis->cbRec += 1 + ((pThis->abData[pThis->cbRec] & 0x80) != 0);
545 else
546 pThis->cbRec += 3;
547 pThis->bType = OMF_PUBDEF32;
548 }
549
550 return omfWriter_RecAddStringN(pThis, pchString, cchString)
551 && omfWriter_RecAddU32(pThis, uValue)
552 && omfWriter_RecAddIdx(pThis, 0); /* type */
553}
554
555static bool omfWriter_PubDefAdd(POMFWRITER pThis, uint32_t uValue, const char *pszString)
556{
557 return omfWriter_PubDefAddN(pThis, uValue, pszString, strlen(pszString));
558}
559
560static bool omfWriter_PubDefEnd(POMFWRITER pThis)
561{
562 return omfWriter_RecEndWithCrc(pThis);
563}
564
565/**
566 * EXTDEF - Begin record.
567 */
568static bool omfWriter_ExtDefBegin(POMFWRITER pThis)
569{
570 return omfWriter_RecBegin(pThis, OMF_EXTDEF);
571
572}
573
574/**
575 * EXTDEF - Add an entry, split record if necessary.
576 */
577static bool omfWriter_ExtDefAddN(POMFWRITER pThis, const char *pchString, size_t cchString)
578{
579 /* Split? */
580 if (pThis->cbRec + 1 + cchString + 1 + 1 > OMF_MAX_RECORD_PAYLOAD)
581 {
582 if (cchString >= 256)
583 return error(pThis->pszSrc, "EXTDEF string too long %u ('%s')\n",
584 (unsigned)cchString, (int)cchString, (int)cchString, pchString);
585 if ( !omfWriter_RecEndWithCrc(pThis)
586 || !omfWriter_RecBegin(pThis, OMF_EXTDEF))
587 return false;
588 }
589
590 return omfWriter_RecAddStringN(pThis, pchString, cchString)
591 && omfWriter_RecAddIdx(pThis, 0); /* type */
592}
593
594/**
595 * EXTDEF - Add an entry, split record if necessary.
596 */
597static bool omfWriter_ExtDefAdd(POMFWRITER pThis, const char *pszString)
598{
599 return omfWriter_ExtDefAddN(pThis, pszString, strlen(pszString));
600}
601
602/**
603 * EXTDEF - End of record.
604 */
605static bool omfWriter_ExtDefEnd(POMFWRITER pThis)
606{
607 return omfWriter_RecEndWithCrc(pThis);
608}
609
610/**
611 * COMENT/LINK_PASS_SEP - Add a link pass separator comment.
612 */
613static bool omfWriter_LinkPassSeparator(POMFWRITER pThis)
614{
615 return omfWriter_RecBegin(pThis, OMF_COMENT)
616 && omfWriter_RecAddU8(pThis, OMF_CTYP_NO_LIST)
617 && omfWriter_RecAddU8(pThis, OMF_CCLS_LINK_PASS_SEP)
618 && omfWriter_RecAddU8(pThis, 1)
619 && omfWriter_RecEndWithCrc(pThis);
620}
621
622/**
623 * LEDATA + FIXUPP - Begin records.
624 */
625static bool omfWriter_LEDataBegin(POMFWRITER pThis, uint16_t idxSeg, uint32_t offSeg,
626 uint32_t cbData, uint32_t cbRawData, void const *pbRawData, uint8_t **ppbData)
627{
628 if ( omfWriter_RecBegin(pThis, OMF_LEDATA32)
629 && omfWriter_RecAddIdx(pThis, idxSeg)
630 && omfWriter_RecAddU32(pThis, offSeg))
631 {
632 if ( cbData <= _1K
633 && pThis->cbRec + cbData + 1 <= OMF_MAX_RECORD_PAYLOAD)
634 {
635 uint8_t *pbDst = &pThis->abData[pThis->cbRec];
636 if (ppbData)
637 *ppbData = pbDst;
638
639 if (cbRawData)
640 memcpy(pbDst, pbRawData, RT_MIN(cbData, cbRawData));
641 if (cbData > cbRawData)
642 memset(&pbDst[cbRawData], 0, cbData - cbRawData);
643
644 pThis->cbRec += cbData;
645
646 /* Reset the associated FIXUPP records. */
647 pThis->iFixupp = 0;
648 for (unsigned i = 0; i < RT_ELEMENTS(pThis->aFixupps); i++)
649 pThis->aFixupps[i].cbRec = 0;
650 return true;
651 }
652 error(pThis->pszSrc, "Too much data for LEDATA record! (%#x)\n", (unsigned)cbData);
653 }
654 return false;
655}
656
657/**
658 * LEDATA + FIXUPP - Add FIXUPP subrecord bytes, split if necessary.
659 */
660static bool omfWriter_LEDataAddFixuppBytes(POMFWRITER pThis, void *pvSubRec, size_t cbSubRec)
661{
662 /* Split? */
663 unsigned iFixupp = pThis->iFixupp;
664 if (pThis->aFixupps[iFixupp].cbRec + cbSubRec >= OMF_MAX_RECORD_PAYLOAD)
665 {
666 iFixupp++;
667 if (iFixupp >= RT_ELEMENTS(pThis->aFixupps))
668 return error(pThis->pszSrc, "Out of FIXUPP records\n");
669 pThis->iFixupp = iFixupp;
670 pThis->aFixupps[iFixupp].cbRec = 0; /* paranoia */
671 }
672
673 /* Append the sub-record data. */
674 memcpy(&pThis->aFixupps[iFixupp].abData[pThis->aFixupps[iFixupp].cbRec], pvSubRec, cbSubRec);
675 pThis->aFixupps[iFixupp].cbRec += (uint16_t)cbSubRec;
676 return true;
677}
678
679/**
680 * LEDATA + FIXUPP - Add fixup, split if necessary.
681 */
682static bool omfWriter_LEDataAddFixup(POMFWRITER pThis, uint16_t offDataRec, bool fSelfRel, uint8_t bLocation,
683 uint8_t bFrame, uint16_t idxFrame,
684 uint8_t bTarget, uint16_t idxTarget, bool fTargetDisp, uint32_t offTargetDisp)
685{
686 if (g_cVerbose >= 2)
687 printf("debug: FIXUP[%#x]: off=%#x frame=%u:%#x target=%u:%#x disp=%d:%#x\n", pThis->aFixupps[pThis->iFixupp].cbRec,
688 offDataRec, bFrame, idxFrame, bTarget, idxTarget, fTargetDisp, offTargetDisp);
689
690 if ( offDataRec >= _1K
691 || bFrame >= 6
692 || bTarget > 6
693 || idxFrame >= _32K
694 || idxTarget >= _32K
695 || fTargetDisp != (bTarget <= 4) )
696 /*return*/ error(pThis->pszSrc, "Internal error: off=%#x frame=%u:%#x target=%u:%#x disp=%d:%#x\n",
697 offDataRec, bFrame, idxFrame, bTarget, idxTarget, fTargetDisp, offTargetDisp);
698
699 /*
700 * Encode the FIXUP subrecord.
701 */
702 uint8_t abFixup[16];
703 uint8_t off = 0;
704 /* Location */
705 abFixup[off++] = (offDataRec >> 8) | (bLocation << 2) | ((uint8_t)!fSelfRel << 6) | 0x80;
706 abFixup[off++] = (uint8_t)offDataRec;
707 /* Fix Data */
708 abFixup[off++] = 0x00 /*F=0*/ | (bFrame << 4) | 0x00 /*T=0*/ | bTarget;
709 /* Frame Datum */
710 if (bFrame <= OMF_FIX_F_FRAME_NO)
711 {
712 if (idxFrame >= 128)
713 abFixup[off++] = (uint8_t)(idxFrame >> 8);
714 abFixup[off++] = (uint8_t)idxFrame;
715 }
716 /* Target Datum */
717 if (idxTarget >= 128)
718 abFixup[off++] = (uint8_t)(idxTarget >> 8);
719 abFixup[off++] = (uint8_t)idxTarget;
720 /* Target Displacement */
721 if (fTargetDisp)
722 {
723 abFixup[off++] = RT_BYTE1(offTargetDisp);
724 abFixup[off++] = RT_BYTE2(offTargetDisp);
725 abFixup[off++] = RT_BYTE3(offTargetDisp);
726 abFixup[off++] = RT_BYTE4(offTargetDisp);
727 }
728
729 return omfWriter_LEDataAddFixuppBytes(pThis, abFixup, off);
730}
731
732/**
733 * LEDATA + FIXUPP - End of records.
734 */
735static bool omfWriter_LEDataEnd(POMFWRITER pThis)
736{
737 if (omfWriter_RecEndWithCrc(pThis))
738 {
739 for (unsigned iFixupp = 0; iFixupp <= pThis->iFixupp; iFixupp++)
740 {
741 uint8_t const cbRec = pThis->aFixupps[iFixupp].cbRec;
742 if (!cbRec)
743 break;
744 if ( !omfWriter_RecBegin(pThis, OMF_FIXUPP32)
745 || !omfWriter_RecAddBytes(pThis, pThis->aFixupps[iFixupp].abData, cbRec)
746 || !omfWriter_RecEndWithCrc(pThis))
747 return false;
748 }
749 pThis->iFixupp = 0;
750 return true;
751 }
752 return false;
753}
754
755/**
756 * MODEND - End of module, simple variant.
757 */
758static bool omfWriter_EndModule(POMFWRITER pThis)
759{
760 return omfWriter_RecBegin(pThis, OMF_MODEND32)
761 && omfWriter_RecAddU8(pThis, 0)
762 && omfWriter_RecEndWithCrc(pThis);
763}
764
765
766
767
768/*********************************************************************************************************************************
769* ELF64/AMD64 -> ELF64/i386 Converter *
770*********************************************************************************************************************************/
771
772/** AMD64 relocation type names for ELF. */
773static const char * const g_apszElfAmd64RelTypes[] =
774{
775 "R_X86_64_NONE",
776 "R_X86_64_64",
777 "R_X86_64_PC32",
778 "R_X86_64_GOT32",
779 "R_X86_64_PLT32",
780 "R_X86_64_COPY",
781 "R_X86_64_GLOB_DAT",
782 "R_X86_64_JMP_SLOT",
783 "R_X86_64_RELATIVE",
784 "R_X86_64_GOTPCREL",
785 "R_X86_64_32",
786 "R_X86_64_32S",
787 "R_X86_64_16",
788 "R_X86_64_PC16",
789 "R_X86_64_8",
790 "R_X86_64_PC8",
791 "R_X86_64_DTPMOD64",
792 "R_X86_64_DTPOFF64",
793 "R_X86_64_TPOFF64",
794 "R_X86_64_TLSGD",
795 "R_X86_64_TLSLD",
796 "R_X86_64_DTPOFF32",
797 "R_X86_64_GOTTPOFF",
798 "R_X86_64_TPOFF32",
799};
800
801
802typedef struct ELFDETAILS
803{
804 /** The ELF header. */
805 Elf64_Ehdr const *pEhdr;
806 /** The section header table. */
807 Elf64_Shdr const *paShdrs;
808 /** The string table for the section names. */
809 const char *pchShStrTab;
810
811 /** The symbol table section number. UINT16_MAX if not found. */
812 uint16_t iSymSh;
813 /** The string table section number. UINT16_MAX if not found. */
814 uint16_t iStrSh;
815
816 /** The symbol table. */
817 Elf64_Sym const *paSymbols;
818 /** The number of symbols in the symbol table. */
819 uint32_t cSymbols;
820
821 /** Pointer to the (symbol) string table if found. */
822 const char *pchStrTab;
823 /** The string table size. */
824 size_t cbStrTab;
825
826} ELFDETAILS;
827typedef ELFDETAILS *PELFDETAILS;
828
829
830static bool validateElf(const char *pszFile, uint8_t const *pbFile, size_t cbFile, PELFDETAILS pElfStuff)
831{
832 /*
833 * Initialize the ELF details structure.
834 */
835 memset(pElfStuff, 0, sizeof(*pElfStuff));
836 pElfStuff->iSymSh = UINT16_MAX;
837 pElfStuff->iStrSh = UINT16_MAX;
838
839 /*
840 * Validate the header and our other expectations.
841 */
842 Elf64_Ehdr const *pEhdr = (Elf64_Ehdr const *)pbFile;
843 pElfStuff->pEhdr = pEhdr;
844 if ( pEhdr->e_ident[EI_CLASS] != ELFCLASS64
845 || pEhdr->e_ident[EI_DATA] != ELFDATA2LSB
846 || pEhdr->e_ehsize != sizeof(Elf64_Ehdr)
847 || pEhdr->e_shentsize != sizeof(Elf64_Shdr)
848 || pEhdr->e_version != EV_CURRENT )
849 return error(pszFile, "Unsupported ELF config\n");
850 if (pEhdr->e_type != ET_REL)
851 return error(pszFile, "Expected relocatable ELF file (e_type=%d)\n", pEhdr->e_type);
852 if (pEhdr->e_machine != EM_X86_64)
853 return error(pszFile, "Expected relocatable ELF file (e_type=%d)\n", pEhdr->e_machine);
854 if (pEhdr->e_phnum != 0)
855 return error(pszFile, "Expected e_phnum to be zero not %u\n", pEhdr->e_phnum);
856 if (pEhdr->e_shnum < 2)
857 return error(pszFile, "Expected e_shnum to be two or higher\n");
858 if (pEhdr->e_shstrndx >= pEhdr->e_shnum || pEhdr->e_shstrndx == 0)
859 return error(pszFile, "Bad e_shstrndx=%u (e_shnum=%u)\n", pEhdr->e_shstrndx, pEhdr->e_shnum);
860 if ( pEhdr->e_shoff >= cbFile
861 || pEhdr->e_shoff + pEhdr->e_shnum * sizeof(Elf64_Shdr) > cbFile)
862 return error(pszFile, "Section table is outside the file (e_shoff=%#llx, e_shnum=%u, cbFile=%#llx)\n",
863 pEhdr->e_shstrndx, pEhdr->e_shnum, (uint64_t)cbFile);
864
865 /*
866 * Locate the section name string table.
867 * We assume it's okay as we only reference it in verbose mode.
868 */
869 Elf64_Shdr const *paShdrs = (Elf64_Shdr const *)&pbFile[pEhdr->e_shoff];
870 pElfStuff->paShdrs = paShdrs;
871
872 Elf64_Xword const cbShStrTab = paShdrs[pEhdr->e_shstrndx].sh_size;
873 if ( paShdrs[pEhdr->e_shstrndx].sh_offset > cbFile
874 || cbShStrTab > cbFile
875 || paShdrs[pEhdr->e_shstrndx].sh_offset + cbShStrTab > cbFile)
876 return error(pszFile,
877 "Section string table is outside the file (sh_offset=%#" ELF_FMT_X64 " sh_size=%#" ELF_FMT_X64 " cbFile=%#" ELF_FMT_X64 ")\n",
878 paShdrs[pEhdr->e_shstrndx].sh_offset, paShdrs[pEhdr->e_shstrndx].sh_size, (Elf64_Xword)cbFile);
879 const char *pchShStrTab = (const char *)&pbFile[paShdrs[pEhdr->e_shstrndx].sh_offset];
880 pElfStuff->pchShStrTab = pchShStrTab;
881
882 /*
883 * Work the section table.
884 */
885 bool fRet = true;
886 for (uint32_t i = 1; i < pEhdr->e_shnum; i++)
887 {
888 if (paShdrs[i].sh_name >= cbShStrTab)
889 return error(pszFile, "Invalid sh_name value (%#x) for section #%u\n", paShdrs[i].sh_name, i);
890 const char *pszShNm = &pchShStrTab[paShdrs[i].sh_name];
891
892 if ( paShdrs[i].sh_offset > cbFile
893 || paShdrs[i].sh_size > cbFile
894 || paShdrs[i].sh_offset + paShdrs[i].sh_size > cbFile)
895 return error(pszFile, "Section #%u '%s' has data outside the file: %#" ELF_FMT_X64 " LB %#" ELF_FMT_X64 " (cbFile=%#" ELF_FMT_X64 ")\n",
896 i, pszShNm, paShdrs[i].sh_offset, paShdrs[i].sh_size, (Elf64_Xword)cbFile);
897 if (g_cVerbose)
898 printf("shdr[%u]: name=%#x '%s' type=%#x flags=%#" ELF_FMT_X64 " addr=%#" ELF_FMT_X64 " off=%#" ELF_FMT_X64 " size=%#" ELF_FMT_X64 "\n"
899 " link=%u info=%#x align=%#" ELF_FMT_X64 " entsize=%#" ELF_FMT_X64 "\n",
900 i, paShdrs[i].sh_name, pszShNm, paShdrs[i].sh_type, paShdrs[i].sh_flags,
901 paShdrs[i].sh_addr, paShdrs[i].sh_offset, paShdrs[i].sh_size,
902 paShdrs[i].sh_link, paShdrs[i].sh_info, paShdrs[i].sh_addralign, paShdrs[i].sh_entsize);
903
904 if (paShdrs[i].sh_link >= pEhdr->e_shnum)
905 return error(pszFile, "Section #%u '%s' links to a section outside the section table: %#x, max %#x\n",
906 i, pszShNm, paShdrs[i].sh_link, pEhdr->e_shnum);
907 if (!RT_IS_POWER_OF_TWO(paShdrs[i].sh_addralign))
908 return error(pszFile, "Section #%u '%s' alignment value is not a power of two: %#" ELF_FMT_X64 "\n",
909 i, pszShNm, paShdrs[i].sh_addralign);
910 if (!RT_IS_POWER_OF_TWO(paShdrs[i].sh_addralign))
911 return error(pszFile, "Section #%u '%s' alignment value is not a power of two: %#" ELF_FMT_X64 "\n",
912 i, pszShNm, paShdrs[i].sh_addralign);
913
914 if (paShdrs[i].sh_type == SHT_RELA)
915 {
916 if (paShdrs[i].sh_entsize != sizeof(Elf64_Rela))
917 return error(pszFile, "Expected sh_entsize to be %u not %u for section #%u (%s)\n", (unsigned)sizeof(Elf64_Rela),
918 paShdrs[i].sh_entsize, i, pszShNm);
919 uint32_t const cRelocs = paShdrs[i].sh_size / sizeof(Elf64_Rela);
920 if (cRelocs * sizeof(Elf64_Rela) != paShdrs[i].sh_size)
921 return error(pszFile, "Uneven relocation entry count in #%u (%s): sh_size=%#" ELF_FMT_X64 "\n", (unsigned)sizeof(Elf64_Rela),
922 paShdrs[i].sh_entsize, i, pszShNm, paShdrs[i].sh_size);
923 if ( paShdrs[i].sh_offset > cbFile
924 || paShdrs[i].sh_size >= cbFile
925 || paShdrs[i].sh_offset + paShdrs[i].sh_size > cbFile)
926 return error(pszFile, "The content of section #%u '%s' is outside the file (%#" ELF_FMT_X64 " LB %#" ELF_FMT_X64 ", cbFile=%#lx)\n",
927 i, pszShNm, paShdrs[i].sh_offset, paShdrs[i].sh_size, (unsigned long)cbFile);
928
929 Elf64_Rela const *paRelocs = (Elf64_Rela *)&pbFile[paShdrs[i].sh_offset];
930 for (uint32_t j = 0; j < cRelocs; j++)
931 {
932 uint8_t const bType = ELF64_R_TYPE(paRelocs[j].r_info);
933 if (RT_UNLIKELY(bType >= R_X86_64_COUNT))
934 fRet = error(pszFile,
935 "%#018" ELF_FMT_X64 " %#018" ELF_FMT_X64 " unknown fix up %#x (%+" ELF_FMT_D64 ")\n",
936 paRelocs[j].r_offset, paRelocs[j].r_info, bType, paRelocs[j].r_addend);
937 }
938 }
939 else if (paShdrs[i].sh_type == SHT_REL)
940 fRet = error(pszFile, "Section #%u '%s': Unexpected SHT_REL section\n", i, pszShNm);
941 else if (paShdrs[i].sh_type == SHT_SYMTAB)
942 {
943 if (paShdrs[i].sh_entsize != sizeof(Elf64_Sym))
944 fRet = error(pszFile, "Section #%u '%s': Unsupported symbol table entry size in : #%u (expected #%u)\n",
945 i, pszShNm, paShdrs[i].sh_entsize, sizeof(Elf64_Sym));
946 uint32_t cSymbols = paShdrs[i].sh_size / paShdrs[i].sh_entsize;
947 if ((Elf64_Xword)cSymbols * paShdrs[i].sh_entsize != paShdrs[i].sh_size)
948 fRet = error(pszFile, "Section #%u '%s': Size not a multiple of entry size: %#" ELF_FMT_X64 " %% %#" ELF_FMT_X64 " = %#" ELF_FMT_X64 "\n",
949 i, pszShNm, paShdrs[i].sh_size, paShdrs[i].sh_entsize, paShdrs[i].sh_size % paShdrs[i].sh_entsize);
950 if (pElfStuff->iSymSh == UINT16_MAX)
951 {
952 pElfStuff->iSymSh = (uint16_t)i;
953 pElfStuff->paSymbols = (Elf64_Sym const *)&pbFile[paShdrs[i].sh_offset];
954 pElfStuff->cSymbols = cSymbols;
955
956 if (paShdrs[i].sh_link != 0)
957 {
958 /* Note! The symbol string table section header may not have been validated yet! */
959 Elf64_Shdr const *pStrTabShdr = &paShdrs[paShdrs[i].sh_link];
960 pElfStuff->iStrSh = paShdrs[i].sh_link;
961 pElfStuff->pchStrTab = (const char *)&pbFile[pStrTabShdr->sh_offset];
962 pElfStuff->cbStrTab = (size_t)pStrTabShdr->sh_size;
963 }
964 else
965 fRet = error(pszFile, "Section #%u '%s': String table link is out of bounds (%#x)\n",
966 i, pszShNm, paShdrs[i].sh_link);
967 }
968 else
969 fRet = error(pszFile, "Section #%u '%s': Found additonal symbol table, previous in #%u\n",
970 i, pszShNm, pElfStuff->iSymSh);
971 }
972 }
973 return fRet;
974}
975
976
977#ifdef ELF_TO_OMF_CONVERSION
978
979static bool convertElfToOmf(const char *pszFile, uint8_t const *pbFile, size_t cbFile, FILE *pDst)
980{
981 /*
982 * Validate the source file a little.
983 */
984 ELFDETAILS ElfStuff;
985 if (!validateElf(pszFile, pbFile, cbFile, &ElfStuff))
986 return false;
987
988 /*
989 * Instantiate the OMF writer.
990 */
991 PIMAGE_FILE_HEADER pHdr = (PIMAGE_FILE_HEADER)pbFile;
992 POMFWRITER pThis = omfWriter_Create(pszFile, pHdr->NumberOfSections, pHdr->NumberOfSymbols, pDst);
993 if (!pThis)
994 return false;
995
996 /*
997 * Write the OMF object file.
998 */
999 if (omfWriter_BeginModule(pThis, pszFile))
1000 {
1001 Elf64_Ehdr const *pEhdr = (Elf64_Ehdr const *)pbFile;
1002 Elf64_Shdr const *paShdrs = (Elf64_Shdr const *)&pbFile[pEhdr->e_shoff];
1003 const char *pszStrTab = (const char *)&pbFile[paShdrs[pEhdr->e_shstrndx].sh_offset];
1004
1005 if ( convertElfSectionsToSegDefsAndGrpDefs(pThis, paShdrs, pHdr->NumberOfSections)
1006 //&& convertElfSymbolsToPubDefsAndExtDefs(pThis, paSymTab, pHdr->NumberOfSymbols, pchStrTab, paShdrs)
1007 && omfWriter_LinkPassSeparator(pThis)
1008 //&& convertElfSectionsToLeDataAndFixupps(pThis, pbFile, cbFile, paShdrs, pHdr->NumberOfSections,
1009 // paSymTab, pHdr->NumberOfSymbols, pchStrTab)
1010 && omfWriter_EndModule(pThis) )
1011 {
1012
1013 omfWriter_Destroy(pThis);
1014 return true;
1015 }
1016 }
1017
1018 omfWriter_Destroy(pThis);
1019 return false;
1020}
1021
1022#else /* !ELF_TO_OMF_CONVERSION */
1023
1024static bool convertelf(const char *pszFile, uint8_t *pbFile, size_t cbFile)
1025{
1026 /*
1027 * Validate the header and our other expectations.
1028 */
1029 ELFDETAILS ElfStuff;
1030 if (!validateElf(pszFile, pbFile, cbFile, &ElfStuff))
1031 return false;
1032
1033 /*
1034 * Locate the section name string table.
1035 * We assume it's okay as we only reference it in verbose mode.
1036 */
1037 Elf64_Ehdr const *pEhdr = (Elf64_Ehdr const *)pbFile;
1038 Elf64_Shdr const *paShdrs = (Elf64_Shdr const *)&pbFile[pEhdr->e_shoff];
1039 const char *pszStrTab = (const char *)&pbFile[paShdrs[pEhdr->e_shstrndx].sh_offset];
1040
1041 /*
1042 * Work the section table.
1043 */
1044 for (uint32_t i = 1; i < pEhdr->e_shnum; i++)
1045 {
1046 if (g_cVerbose)
1047 printf("shdr[%u]: name=%#x '%s' type=%#x flags=%#" ELF_FMT_X64 " addr=%#" ELF_FMT_X64 " off=%#" ELF_FMT_X64 " size=%#" ELF_FMT_X64 "\n"
1048 " link=%u info=%#x align=%#" ELF_FMT_X64 " entsize=%#" ELF_FMT_X64 "\n",
1049 i, paShdrs[i].sh_name, &pszStrTab[paShdrs[i].sh_name], paShdrs[i].sh_type, paShdrs[i].sh_flags,
1050 paShdrs[i].sh_addr, paShdrs[i].sh_offset, paShdrs[i].sh_size,
1051 paShdrs[i].sh_link, paShdrs[i].sh_info, paShdrs[i].sh_addralign, paShdrs[i].sh_entsize);
1052 if (paShdrs[i].sh_type == SHT_RELA)
1053 {
1054 Elf64_Rela *paRelocs = (Elf64_Rela *)&pbFile[paShdrs[i].sh_offset];
1055 uint32_t const cRelocs = paShdrs[i].sh_size / sizeof(Elf64_Rela);
1056 for (uint32_t j = 0; j < cRelocs; j++)
1057 {
1058 uint8_t const bType = ELF64_R_TYPE(paRelocs[j].r_info);
1059 if (g_cVerbose > 1)
1060 printf("%#018" ELF_FMT_X64 " %#018" ELF_FMT_X64 " %s %+" ELF_FMT_D64 "\n", paRelocs[j].r_offset, paRelocs[j].r_info,
1061 bType < RT_ELEMENTS(g_apszElfAmd64RelTypes) ? g_apszElfAmd64RelTypes[bType] : "unknown", paRelocs[j].r_addend);
1062
1063 /* Truncate 64-bit wide absolute relocations, ASSUMING that the high bits
1064 are already zero and won't be non-zero after calculating the fixup value. */
1065 if (bType == R_X86_64_64)
1066 {
1067 paRelocs[j].r_info &= ~(uint64_t)0xff;
1068 paRelocs[j].r_info |= R_X86_64_32;
1069 }
1070 }
1071 }
1072 else if (paShdrs[i].sh_type == SHT_REL)
1073 return error(pszFile, "Did not expect SHT_REL sections (#%u '%s')\n", i, &pszStrTab[paShdrs[i].sh_name]);
1074 }
1075 return true;
1076}
1077
1078#endif /* !ELF_TO_OMF_CONVERSION */
1079
1080
1081
1082
1083/*********************************************************************************************************************************
1084* COFF -> OMF Converter *
1085*********************************************************************************************************************************/
1086
1087/** AMD64 relocation type names for (Microsoft) COFF. */
1088static const char * const g_apszCoffAmd64RelTypes[] =
1089{
1090 "ABSOLUTE",
1091 "ADDR64",
1092 "ADDR32",
1093 "ADDR32NB",
1094 "REL32",
1095 "REL32_1",
1096 "REL32_2",
1097 "REL32_3",
1098 "REL32_4",
1099 "REL32_5",
1100 "SECTION",
1101 "SECREL",
1102 "SECREL7",
1103 "TOKEN",
1104 "SREL32",
1105 "PAIR",
1106 "SSPAN32"
1107};
1108
1109/** AMD64 relocation type sizes for (Microsoft) COFF. */
1110static uint8_t const g_acbCoffAmd64RelTypes[] =
1111{
1112 8, /* ABSOLUTE */
1113 8, /* ADDR64 */
1114 4, /* ADDR32 */
1115 4, /* ADDR32NB */
1116 4, /* REL32 */
1117 4, /* REL32_1 */
1118 4, /* REL32_2 */
1119 4, /* REL32_3 */
1120 4, /* REL32_4 */
1121 4, /* REL32_5 */
1122 2, /* SECTION */
1123 4, /* SECREL */
1124 1, /* SECREL7 */
1125 0, /* TOKEN */
1126 4, /* SREL32 */
1127 0, /* PAIR */
1128 4, /* SSPAN32 */
1129};
1130
1131/** Macro for getting the size of a AMD64 COFF relocation. */
1132#define COFF_AMD64_RELOC_SIZE(a_Type) ( (a_Type) < RT_ELEMENTS(g_acbCoffAmd64RelTypes) ? g_acbCoffAmd64RelTypes[(a_Type)] : 1)
1133
1134
1135static const char *coffGetSymbolName(PCIMAGE_SYMBOL pSym, const char *pchStrTab, uint32_t cbStrTab, char pszShortName[16])
1136{
1137 if (pSym->N.Name.Short != 0)
1138 {
1139 memcpy(pszShortName, pSym->N.ShortName, 8);
1140 pszShortName[8] = '\0';
1141 return pszShortName;
1142 }
1143 if (pSym->N.Name.Long < cbStrTab)
1144 {
1145 uint32_t const cbLeft = cbStrTab - pSym->N.Name.Long;
1146 const char *pszRet = pchStrTab + pSym->N.Name.Long;
1147 if (memchr(pszRet, '\0', cbLeft) != NULL)
1148 return pszRet;
1149 }
1150 error("<null>", "Invalid string table index %#x!\n", pSym->N.Name.Long);
1151 return "Invalid Symbol Table Entry";
1152}
1153
1154static bool validateCoff(const char *pszFile, uint8_t const *pbFile, size_t cbFile)
1155{
1156 /*
1157 * Validate the header and our other expectations.
1158 */
1159 PIMAGE_FILE_HEADER pHdr = (PIMAGE_FILE_HEADER)pbFile;
1160 if (pHdr->Machine != IMAGE_FILE_MACHINE_AMD64)
1161 return error(pszFile, "Expected IMAGE_FILE_MACHINE_AMD64 not %#x\n", pHdr->Machine);
1162 if (pHdr->SizeOfOptionalHeader != 0)
1163 return error(pszFile, "Expected SizeOfOptionalHeader to be zero, not %#x\n", pHdr->SizeOfOptionalHeader);
1164 if (pHdr->NumberOfSections == 0)
1165 return error(pszFile, "Expected NumberOfSections to be non-zero\n");
1166 uint32_t const cbHeaders = pHdr->NumberOfSections * sizeof(IMAGE_SECTION_HEADER) + sizeof(*pHdr);
1167 if (cbHeaders > cbFile)
1168 return error(pszFile, "Section table goes beyond the end of the of the file (cSections=%#x)\n", pHdr->NumberOfSections);
1169 if (pHdr->NumberOfSymbols)
1170 {
1171 if ( pHdr->PointerToSymbolTable >= cbFile
1172 || pHdr->NumberOfSymbols * (uint64_t)IMAGE_SIZE_OF_SYMBOL > cbFile)
1173 return error(pszFile, "Symbol table goes beyond the end of the of the file (cSyms=%#x, offFile=%#x)\n",
1174 pHdr->NumberOfSymbols, pHdr->PointerToSymbolTable);
1175 }
1176
1177 return true;
1178}
1179
1180
1181static bool convertCoffSectionsToSegDefsAndGrpDefs(POMFWRITER pThis, PCIMAGE_SECTION_HEADER paShdrs, uint16_t cSections)
1182{
1183 /*
1184 * Do the list of names pass.
1185 */
1186 uint16_t idxGrpFlat, idxGrpData;
1187 uint16_t idxClassCode, idxClassData, idxClassDebugSymbols, idxClassDebugTypes;
1188 if ( !omfWriter_LNamesBegin(pThis)
1189 || !omfWriter_LNamesAddN(pThis, RT_STR_TUPLE("FLAT"), &idxGrpFlat)
1190 || !omfWriter_LNamesAddN(pThis, RT_STR_TUPLE("BS3DATA64_GROUP"), &idxGrpData)
1191 || !omfWriter_LNamesAddN(pThis, RT_STR_TUPLE("BS3CODE64"), &idxClassCode)
1192 || !omfWriter_LNamesAddN(pThis, RT_STR_TUPLE("FAR_DATA"), &idxClassData)
1193 || !omfWriter_LNamesAddN(pThis, RT_STR_TUPLE("DEBSYM"), &idxClassDebugSymbols)
1194 || !omfWriter_LNamesAddN(pThis, RT_STR_TUPLE("DEBTYP"), &idxClassDebugTypes)
1195 )
1196 return false;
1197
1198 bool fHaveData = false;
1199 for (uint16_t i = 0; i < cSections; i++)
1200 {
1201 /* Copy the name and terminate it. */
1202 char szName[32];
1203 memcpy(szName, paShdrs[i].Name, sizeof(paShdrs[i].Name));
1204 unsigned cchName = sizeof(paShdrs[i].Name);
1205 while (cchName > 0 && RT_C_IS_SPACE(szName[cchName - 1]))
1206 cchName--;
1207 if (cchName == 0)
1208 return error(pThis->pszSrc, "Section #%u has an empty name!\n", i);
1209 szName[cchName] = '\0';
1210
1211 if ( (paShdrs[i].Characteristics & (IMAGE_SCN_LNK_REMOVE | IMAGE_SCN_LNK_INFO))
1212 || strcmp(szName, ".pdata") == 0 /* Exception stuff, I think, so discard it. */
1213 || strcmp(szName, ".xdata") == 0 /* Ditto. */ )
1214 {
1215 pThis->paSegments[i].iSegDef = UINT16_MAX;
1216 pThis->paSegments[i].iGrpDef = UINT16_MAX;
1217 pThis->paSegments[i].iSegNm = UINT16_MAX;
1218 pThis->paSegments[i].iGrpNm = UINT16_MAX;
1219 pThis->paSegments[i].iClassNm = UINT16_MAX;
1220 pThis->paSegments[i].pszName = NULL;
1221 }
1222 else
1223 {
1224 /* Translate the name, group and class. */
1225 if (strcmp(szName, ".text") == 0)
1226 {
1227 strcpy(szName, "BS3TEXT64");
1228 pThis->paSegments[i].iGrpNm = idxGrpFlat;
1229 pThis->paSegments[i].iClassNm = idxClassCode;
1230 }
1231 else if (strcmp(szName, ".data") == 0)
1232 {
1233 strcpy(szName, "BS3DATA64");
1234 pThis->paSegments[i].iGrpNm = idxGrpData;
1235 pThis->paSegments[i].iClassNm = idxClassData;
1236 }
1237 else if (strcmp(szName, ".bss") == 0)
1238 {
1239 strcpy(szName, "BS3BSS64");
1240 pThis->paSegments[i].iGrpNm = idxGrpData;
1241 pThis->paSegments[i].iClassNm = idxClassData;
1242 }
1243 else if (strcmp(szName, ".rdata") == 0)
1244 {
1245 strcpy(szName, "BS3DATA64CONST");
1246 pThis->paSegments[i].iGrpNm = idxGrpData;
1247 pThis->paSegments[i].iClassNm = idxClassData;
1248 }
1249 else if (strcmp(szName, ".debug$S") == 0)
1250 {
1251 strcpy(szName, "$$SYMBOLS");
1252 pThis->paSegments[i].iGrpNm = UINT16_MAX;
1253 pThis->paSegments[i].iClassNm = idxClassDebugSymbols;
1254 }
1255 else if (strcmp(szName, ".debug$T") == 0)
1256 {
1257 strcpy(szName, "$$TYPES");
1258 pThis->paSegments[i].iGrpNm = UINT16_MAX;
1259 pThis->paSegments[i].iClassNm = idxClassDebugTypes;
1260 }
1261 else if (paShdrs[i].Characteristics & (IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_CNT_CODE))
1262 {
1263 pThis->paSegments[i].iGrpNm = idxGrpFlat;
1264 pThis->paSegments[i].iClassNm = idxClassCode;
1265 error(pThis->pszSrc, "Unknown code segment: '%s'\n", szName);
1266 }
1267 else
1268 {
1269 pThis->paSegments[i].iGrpNm = idxGrpData;
1270 pThis->paSegments[i].iClassNm = idxClassData;
1271 error(pThis->pszSrc, "Unknown data (?) segment: '%s'\n", szName);
1272 }
1273
1274 /* Save the name. */
1275 pThis->paSegments[i].pszName = strdup(szName);
1276 if (!pThis->paSegments[i].pszName)
1277 return error(pThis->pszSrc, "Out of memory!\n");
1278
1279 /* Add the section name. */
1280 if (!omfWriter_LNamesAdd(pThis, pThis->paSegments[i].pszName, &pThis->paSegments[i].iSegNm))
1281 return false;
1282
1283 fHaveData |= pThis->paSegments[i].iGrpDef == idxGrpData;
1284 }
1285 }
1286
1287 if (!omfWriter_LNamesEnd(pThis))
1288 return false;
1289
1290 /*
1291 * Emit segment definitions.
1292 */
1293 uint16_t iSegDef = 1; /* Start counting at 1. */
1294 for (uint16_t i = 0; i < cSections; i++)
1295 {
1296 if (pThis->paSegments[i].iSegDef == UINT16_MAX)
1297 continue;
1298
1299 uint8_t bSegAttr = 0;
1300
1301 /* The A field. */
1302 switch (paShdrs[i].Characteristics & IMAGE_SCN_ALIGN_MASK)
1303 {
1304 default:
1305 case IMAGE_SCN_ALIGN_1BYTES:
1306 bSegAttr |= 1 << 5;
1307 break;
1308 case IMAGE_SCN_ALIGN_2BYTES:
1309 bSegAttr |= 2 << 5;
1310 break;
1311 case IMAGE_SCN_ALIGN_4BYTES:
1312 bSegAttr |= 5 << 5;
1313 break;
1314 case IMAGE_SCN_ALIGN_8BYTES:
1315 case IMAGE_SCN_ALIGN_16BYTES:
1316 bSegAttr |= 3 << 5;
1317 break;
1318 case IMAGE_SCN_ALIGN_32BYTES:
1319 case IMAGE_SCN_ALIGN_64BYTES:
1320 case IMAGE_SCN_ALIGN_128BYTES:
1321 case IMAGE_SCN_ALIGN_256BYTES:
1322 bSegAttr |= 4 << 5;
1323 break;
1324 case IMAGE_SCN_ALIGN_512BYTES:
1325 case IMAGE_SCN_ALIGN_1024BYTES:
1326 case IMAGE_SCN_ALIGN_2048BYTES:
1327 case IMAGE_SCN_ALIGN_4096BYTES:
1328 case IMAGE_SCN_ALIGN_8192BYTES:
1329 bSegAttr |= 6 << 5; /* page aligned, pharlabs extension. */
1330 break;
1331 }
1332
1333 /* The C field. */
1334 bSegAttr |= 2 << 2; /* public */
1335
1336 /* The B field. We don't have 4GB segments, so leave it as zero. */
1337
1338 /* The D field shall be set as we're doing USE32. */
1339 bSegAttr |= 1;
1340
1341
1342 /* Done. */
1343 if (!omfWriter_SegDef(pThis, bSegAttr, paShdrs[i].SizeOfRawData,
1344 pThis->paSegments[i].iSegNm,
1345 pThis->paSegments[i].iClassNm))
1346 return false;
1347 pThis->paSegments[i].iSegDef = iSegDef++;
1348 }
1349
1350 /*
1351 * Flat group definition (#1) - special, no members.
1352 */
1353 uint16_t iGrpDef = 1;
1354 if ( !omfWriter_GrpDefBegin(pThis, idxGrpFlat)
1355 || !omfWriter_GrpDefEnd(pThis))
1356 return false;
1357 for (uint16_t i = 0; i < cSections; i++)
1358 if (pThis->paSegments[i].iGrpNm == idxGrpFlat)
1359 pThis->paSegments[i].iGrpDef = iGrpDef;
1360 pThis->idxGrpFlat = iGrpDef++;
1361
1362 /*
1363 * Data group definition (#2).
1364 */
1365 /** @todo do we need to consider missing segments and ordering? */
1366 uint16_t cGrpNms = 0;
1367 uint16_t aiGrpNms[2];
1368 if (fHaveData)
1369 aiGrpNms[cGrpNms++] = idxGrpData;
1370 for (uint32_t iGrpNm = 0; iGrpNm < cGrpNms; iGrpNm++)
1371 {
1372 if (!omfWriter_GrpDefBegin(pThis, aiGrpNms[iGrpNm]))
1373 return false;
1374 for (uint16_t i = 0; i < cSections; i++)
1375 if (pThis->paSegments[i].iGrpNm == aiGrpNms[iGrpNm])
1376 {
1377 pThis->paSegments[i].iGrpDef = iGrpDef;
1378 if (!omfWriter_GrpDefAddSegDef(pThis, pThis->paSegments[i].iSegDef))
1379 return false;
1380 }
1381 if (!omfWriter_GrpDefEnd(pThis))
1382 return false;
1383 iGrpDef++;
1384 }
1385
1386 return true;
1387}
1388
1389/**
1390 * This is for matching STATIC symbols with value 0 against the section name,
1391 * to see if it's a section reference or symbol at offset 0 reference.
1392 *
1393 * @returns true / false.
1394 * @param pszSymbol The symbol name.
1395 * @param pachSectName8 The section name (8-bytes).
1396 */
1397static bool isCoffSymbolMatchingSectionName(const char *pszSymbol, uint8_t const pachSectName8[8])
1398{
1399 uint32_t off = 0;
1400 char ch;
1401 while (off < 8 && (ch = pszSymbol[off]) != '\0')
1402 {
1403 if (ch != pachSectName8[off])
1404 return false;
1405 off++;
1406 }
1407 while (off < 8)
1408 {
1409 if (!RT_C_IS_SPACE((ch = pachSectName8[off])))
1410 return ch == '\0';
1411 off++;
1412 }
1413 return true;
1414}
1415
1416static bool convertCoffSymbolsToPubDefsAndExtDefs(POMFWRITER pThis, PCIMAGE_SYMBOL paSymbols, uint16_t cSymbols,
1417 const char *pchStrTab, PCIMAGE_SECTION_HEADER paShdrs)
1418{
1419
1420 if (!cSymbols)
1421 return true;
1422 uint32_t const cbStrTab = *(uint32_t const *)pchStrTab;
1423 char szShort[16];
1424
1425 /*
1426 * Process the symbols the first.
1427 */
1428 uint32_t iSymImageBase = UINT32_MAX;
1429 uint32_t cAbsSyms = 0;
1430 uint32_t cExtSyms = 0;
1431 uint32_t cPubSyms = 0;
1432 for (uint32_t iSeg = 0; iSeg < pThis->cSegments; iSeg++)
1433 pThis->paSegments[iSeg].cPubDefs = 0;
1434
1435 for (uint16_t iSym = 0; iSym < cSymbols; iSym++)
1436 {
1437 const char *pszSymName = coffGetSymbolName(&paSymbols[iSym], pchStrTab, cbStrTab, szShort);
1438
1439 pThis->paSymbols[iSym].enmType = OMFSYMTYPE_IGNORED;
1440 pThis->paSymbols[iSym].idx = UINT16_MAX;
1441 pThis->paSymbols[iSym].idxSegDef = UINT16_MAX;
1442 pThis->paSymbols[iSym].idxGrpDef = UINT16_MAX;
1443
1444 int16_t const idxSection = paSymbols[iSym].SectionNumber;
1445 if ( (idxSection >= 1 && idxSection <= (int32_t)pThis->cSegments)
1446 || idxSection == IMAGE_SYM_ABSOLUTE)
1447 {
1448 switch (paSymbols[iSym].StorageClass)
1449 {
1450 case IMAGE_SYM_CLASS_EXTERNAL:
1451 if (idxSection != IMAGE_SYM_ABSOLUTE)
1452 {
1453 if (pThis->paSegments[idxSection - 1].iSegDef != UINT16_MAX)
1454 {
1455 pThis->paSymbols[iSym].enmType = OMFSYMTYPE_PUBDEF;
1456 pThis->paSymbols[iSym].idxSegDef = pThis->paSegments[idxSection - 1].iSegDef;
1457 pThis->paSymbols[iSym].idxGrpDef = pThis->paSegments[idxSection - 1].iGrpDef;
1458 pThis->paSegments[idxSection - 1].cPubDefs++;
1459 cPubSyms++;
1460 }
1461 }
1462 else
1463 {
1464 pThis->paSymbols[iSym].enmType = OMFSYMTYPE_PUBDEF;
1465 pThis->paSymbols[iSym].idxSegDef = 0;
1466 pThis->paSymbols[iSym].idxGrpDef = 0;
1467 cAbsSyms++;
1468 }
1469 break;
1470
1471 case IMAGE_SYM_CLASS_STATIC:
1472 if ( paSymbols[iSym].Value == 0
1473 && idxSection != IMAGE_SYM_ABSOLUTE
1474 && isCoffSymbolMatchingSectionName(pszSymName, paShdrs[idxSection - 1].Name) )
1475 {
1476 pThis->paSymbols[iSym].enmType = OMFSYMTYPE_SEGDEF;
1477 pThis->paSymbols[iSym].idxSegDef = pThis->paSegments[idxSection - 1].iSegDef;
1478 pThis->paSymbols[iSym].idxGrpDef = pThis->paSegments[idxSection - 1].iGrpDef;
1479 break;
1480 }
1481 /* fall thru */
1482
1483 case IMAGE_SYM_CLASS_END_OF_FUNCTION:
1484 case IMAGE_SYM_CLASS_AUTOMATIC:
1485 case IMAGE_SYM_CLASS_REGISTER:
1486 case IMAGE_SYM_CLASS_LABEL:
1487 case IMAGE_SYM_CLASS_MEMBER_OF_STRUCT:
1488 case IMAGE_SYM_CLASS_ARGUMENT:
1489 case IMAGE_SYM_CLASS_STRUCT_TAG:
1490 case IMAGE_SYM_CLASS_MEMBER_OF_UNION:
1491 case IMAGE_SYM_CLASS_UNION_TAG:
1492 case IMAGE_SYM_CLASS_TYPE_DEFINITION:
1493 case IMAGE_SYM_CLASS_ENUM_TAG:
1494 case IMAGE_SYM_CLASS_MEMBER_OF_ENUM:
1495 case IMAGE_SYM_CLASS_REGISTER_PARAM:
1496 case IMAGE_SYM_CLASS_BIT_FIELD:
1497 case IMAGE_SYM_CLASS_BLOCK:
1498 case IMAGE_SYM_CLASS_FUNCTION:
1499 case IMAGE_SYM_CLASS_END_OF_STRUCT:
1500 case IMAGE_SYM_CLASS_FILE:
1501 pThis->paSymbols[iSym].enmType = OMFSYMTYPE_INTERNAL;
1502 if (idxSection != IMAGE_SYM_ABSOLUTE)
1503 {
1504 pThis->paSymbols[iSym].idxSegDef = pThis->paSegments[idxSection - 1].iSegDef;
1505 pThis->paSymbols[iSym].idxGrpDef = pThis->paSegments[idxSection - 1].iGrpDef;
1506 }
1507 else
1508 {
1509 pThis->paSymbols[iSym].idxSegDef = 0;
1510 pThis->paSymbols[iSym].idxGrpDef = 0;
1511 }
1512 break;
1513
1514 case IMAGE_SYM_CLASS_SECTION:
1515 case IMAGE_SYM_CLASS_EXTERNAL_DEF:
1516 case IMAGE_SYM_CLASS_NULL:
1517 case IMAGE_SYM_CLASS_UNDEFINED_LABEL:
1518 case IMAGE_SYM_CLASS_UNDEFINED_STATIC:
1519 case IMAGE_SYM_CLASS_CLR_TOKEN:
1520 case IMAGE_SYM_CLASS_FAR_EXTERNAL:
1521 case IMAGE_SYM_CLASS_WEAK_EXTERNAL:
1522 return error(pThis->pszSrc, "Unsupported storage class value %#x for symbol #%u (%s)\n",
1523 paSymbols[iSym].StorageClass, iSym, pszSymName);
1524
1525 default:
1526 return error(pThis->pszSrc, "Unknown storage class value %#x for symbol #%u (%s)\n",
1527 paSymbols[iSym].StorageClass, iSym, pszSymName);
1528 }
1529 }
1530 else if (idxSection == IMAGE_SYM_UNDEFINED)
1531 {
1532 if ( paSymbols[iSym].StorageClass == IMAGE_SYM_CLASS_EXTERNAL
1533 || paSymbols[iSym].StorageClass == IMAGE_SYM_CLASS_EXTERNAL_DEF)
1534 {
1535 pThis->paSymbols[iSym].enmType = OMFSYMTYPE_EXTDEF;
1536 cExtSyms++;
1537 if (iSymImageBase == UINT32_MAX && strcmp(pszSymName, "__ImageBase") == 0)
1538 iSymImageBase = iSym;
1539 }
1540 else
1541 return error(pThis->pszSrc, "Unknown/unknown storage class value %#x for undefined symbol #%u (%s)\n",
1542 paSymbols[iSym].StorageClass, iSym, pszSymName);
1543 }
1544 else if (idxSection != IMAGE_SYM_DEBUG)
1545 return error(pThis->pszSrc, "Invalid section number %#x for symbol #%u (%s)\n", idxSection, iSym, pszSymName);
1546
1547 /* Skip AUX symbols. */
1548 uint8_t cAuxSyms = paSymbols[iSym].NumberOfAuxSymbols;
1549 while (cAuxSyms-- > 0)
1550 {
1551 iSym++;
1552 pThis->paSymbols[iSym].enmType = OMFSYMTYPE_INVALID;
1553 pThis->paSymbols[iSym].idx = UINT16_MAX;
1554 }
1555 }
1556
1557 /*
1558 * Emit the PUBDEFs the first time around (see order of records in TIS spec).
1559 */
1560 uint16_t idxPubDef = 1;
1561 if (cPubSyms)
1562 {
1563 for (uint32_t iSeg = 0; iSeg < pThis->cSegments; iSeg++)
1564 if (pThis->paSegments[iSeg].cPubDefs > 0)
1565 {
1566 uint16_t const idxSegDef = pThis->paSegments[iSeg].iSegDef;
1567 if (!omfWriter_PubDefBegin(pThis, pThis->paSegments[iSeg].iGrpDef, idxSegDef))
1568 return false;
1569 for (uint16_t iSym = 0; iSym < cSymbols; iSym++)
1570 if ( pThis->paSymbols[iSym].idxSegDef == idxSegDef
1571 && pThis->paSymbols[iSym].enmType == OMFSYMTYPE_PUBDEF)
1572 {
1573 const char *pszName = coffGetSymbolName(&paSymbols[iSym], pchStrTab, cbStrTab, szShort);
1574 if (!omfWriter_PubDefAdd(pThis, paSymbols[iSym].Value, pszName))
1575 return false;
1576
1577 /* If the symbol doesn't start with an underscore, add an underscore
1578 prefixed alias to ease access from 16-bit and 32-bit code. */
1579 if (*pszName != '_')
1580 {
1581 char szCdeclName[512];
1582 size_t cchName = strlen(pszName);
1583 if (cchName > sizeof(szCdeclName) - 2)
1584 cchName = sizeof(szCdeclName) - 2;
1585 szCdeclName[0] = '_';
1586 memcpy(&szCdeclName[1], pszName, cchName);
1587 szCdeclName[cchName + 1] = '\0';
1588 if (!omfWriter_PubDefAdd(pThis, paSymbols[iSym].Value, szCdeclName))
1589 return false;
1590 }
1591
1592 pThis->paSymbols[iSym].idx = idxPubDef++;
1593 }
1594 if (!omfWriter_PubDefEnd(pThis))
1595 return false;
1596 }
1597 }
1598
1599 if (cAbsSyms > 0)
1600 {
1601 if (!omfWriter_PubDefBegin(pThis, 0, 0))
1602 return false;
1603 for (uint16_t iSym = 0; iSym < cSymbols; iSym++)
1604 if ( pThis->paSymbols[iSym].idxSegDef == 0
1605 && pThis->paSymbols[iSym].enmType == OMFSYMTYPE_PUBDEF)
1606 {
1607 if (!omfWriter_PubDefAdd(pThis, paSymbols[iSym].Value,
1608 coffGetSymbolName(&paSymbols[iSym], pchStrTab, cbStrTab, szShort)) )
1609 return false;
1610 pThis->paSymbols[iSym].idx = idxPubDef++;
1611 }
1612 if (!omfWriter_PubDefEnd(pThis))
1613 return false;
1614 }
1615
1616 /*
1617 * Go over the symbol table and emit external definition records.
1618 */
1619 if (!omfWriter_ExtDefBegin(pThis))
1620 return false;
1621 uint16_t idxExtDef = 1;
1622 for (uint16_t iSym = 0; iSym < cSymbols; iSym++)
1623 if (pThis->paSymbols[iSym].enmType == OMFSYMTYPE_EXTDEF)
1624 {
1625 if (!omfWriter_ExtDefAdd(pThis, coffGetSymbolName(&paSymbols[iSym], pchStrTab, cbStrTab, szShort)))
1626 return false;
1627 pThis->paSymbols[iSym].idx = idxExtDef++;
1628 }
1629
1630 /* Always add an __ImageBase reference, in case we need it to deal with ADDR32NB fixups. */
1631 /** @todo maybe we don't actually need this and could use FLAT instead? */
1632 if (iSymImageBase != UINT32_MAX)
1633 pThis->idxExtImageBase = pThis->paSymbols[iSymImageBase].idx;
1634 else if (omfWriter_ExtDefAdd(pThis, "__ImageBase"))
1635 pThis->idxExtImageBase = idxExtDef;
1636 else
1637 return false;
1638
1639 if (!omfWriter_ExtDefEnd(pThis))
1640 return false;
1641
1642 return true;
1643}
1644
1645
1646static bool convertCoffSectionsToLeDataAndFixupps(POMFWRITER pThis, uint8_t const *pbFile, size_t cbFile,
1647 PCIMAGE_SECTION_HEADER paShdrs, uint16_t cSections,
1648 PCIMAGE_SYMBOL paSymbols, uint16_t cSymbols, const char *pchStrTab)
1649{
1650 uint32_t const cbStrTab = *(uint32_t const *)pchStrTab;
1651 bool fRet = true;
1652 for (uint32_t i = 0; i < pThis->cSegments; i++)
1653 {
1654 if (pThis->paSegments[i].iSegDef == UINT16_MAX)
1655 continue;
1656
1657 char szShortName[16];
1658 const char *pszSegNm = pThis->paSegments[i].pszName;
1659 uint16_t cRelocs = paShdrs[i].NumberOfRelocations;
1660 PCIMAGE_RELOCATION paRelocs = (PCIMAGE_RELOCATION)&pbFile[paShdrs[i].PointerToRelocations];
1661 uint32_t cbVirtData = paShdrs[i].SizeOfRawData;
1662 uint32_t cbData = paShdrs[i].Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA ? 0 : cbVirtData;
1663 uint8_t const *pbData = &pbFile[paShdrs[i].PointerToRawData];
1664 uint32_t off = 0;
1665
1666 /* Check that the relocations are sorted and within the section. */
1667 for (uint32_t iReloc = 1; iReloc < cRelocs; iReloc++)
1668 if (paRelocs[iReloc - 1].u.VirtualAddress >= paRelocs[iReloc].u.VirtualAddress)
1669 return error(pThis->pszSrc, "Section #%u (%s) relocations aren't sorted\n", i, pszSegNm);
1670 if ( cRelocs > 0
1671 && paRelocs[cRelocs - 1].u.VirtualAddress - paShdrs[i].VirtualAddress
1672 + COFF_AMD64_RELOC_SIZE(paRelocs[cRelocs - 1].Type) > cbVirtData)
1673 return error(pThis->pszSrc,
1674 "Section #%u (%s) relocations beyond section data! cbVirtData=%#x RvaFix=%#x RVASeg=%#x type=%#x\n",
1675 i, pszSegNm, cbVirtData, paRelocs[cRelocs - 1].u.VirtualAddress, paShdrs[i].VirtualAddress,
1676 paRelocs[cRelocs - 1].Type);
1677
1678 /* The OMF record size requires us to split larger sections up. To make
1679 life simple, we fill zeros for unitialized (BSS) stuff. */
1680 const uint32_t cbMaxData = RT_MIN(OMF_MAX_RECORD_PAYLOAD - 1 - (pThis->paSegments[i].iSegDef >= 128) - 4 - 1, _1K);
1681 while (cbVirtData > 0)
1682 {
1683 /* Figure out how many bytes to put out in this chunk. Must make sure
1684 fixups doesn't cross chunk boundraries. ASSUMES sorted relocs. */
1685 uint32_t cChunkRelocs = cRelocs;
1686 uint32_t cbChunk = cbVirtData;
1687 uint32_t uRvaEnd = paShdrs[i].VirtualAddress + off + cbChunk;
1688 if (cbChunk > cbMaxData)
1689 {
1690 cbChunk = cbMaxData;
1691 uRvaEnd = paShdrs[i].VirtualAddress + off + cbChunk;
1692 cChunkRelocs = 0;
1693
1694 /* Quickly determin the reloc range. */
1695 while ( cChunkRelocs < cRelocs
1696 && paRelocs[cChunkRelocs].u.VirtualAddress < uRvaEnd)
1697 cChunkRelocs++;
1698
1699 /* Ensure final reloc doesn't go beyond chunk. */
1700 while ( cChunkRelocs > 0
1701 && paRelocs[cChunkRelocs - 1].u.VirtualAddress + COFF_AMD64_RELOC_SIZE(paRelocs[cChunkRelocs - 1].Type)
1702 > uRvaEnd)
1703 {
1704 uint32_t cbDrop = uRvaEnd - paRelocs[cChunkRelocs - 1].u.VirtualAddress;
1705 cbChunk -= cbDrop;
1706 uRvaEnd -= cbDrop;
1707 cChunkRelocs--;
1708 }
1709
1710 if (!cbVirtData)
1711 return error(pThis->pszSrc, "Wtf? cbVirtData is zero!\n");
1712 }
1713
1714 /*
1715 * We stash the bytes into the OMF writer record buffer, receiving a
1716 * pointer to the start of it so we can make adjustments if necessary.
1717 */
1718 uint8_t *pbCopy;
1719 if (!omfWriter_LEDataBegin(pThis, pThis->paSegments[i].iSegDef, off, cbChunk, cbData, pbData, &pbCopy))
1720 return false;
1721
1722 /*
1723 * Convert fiuxps.
1724 */
1725 uint32_t const uRvaChunk = paShdrs[i].VirtualAddress + off;
1726 for (uint32_t iReloc = 0; iReloc < cChunkRelocs; iReloc++)
1727 {
1728 /* Get the OMF and COFF data for the symbol the reloc references. */
1729 if (paRelocs[iReloc].SymbolTableIndex >= pThis->cSymbols)
1730 return error(pThis->pszSrc, "Relocation symtab index (%#x) is out of range in segment #%u '%s'\n",
1731 paRelocs[iReloc].SymbolTableIndex, i, pszSegNm);
1732 PCIMAGE_SYMBOL pCoffSym = &paSymbols[paRelocs[iReloc].SymbolTableIndex];
1733 POMFSYMBOL pOmfSym = &pThis->paSymbols[paRelocs[iReloc].SymbolTableIndex];
1734
1735 /* Calc fixup location in the pending chunk and setup a flexible pointer to it. */
1736 uint16_t offDataRec = (uint16_t)paRelocs[iReloc].u.VirtualAddress - uRvaChunk;
1737 RTPTRUNION uLoc;
1738 uLoc.pu8 = &pbCopy[offDataRec];
1739
1740 /* OMF fixup data initialized with typical defaults. */
1741 bool fSelfRel = true;
1742 uint8_t bLocation = OMF_FIX_LOC_32BIT_OFFSET;
1743 uint8_t bFrame = OMF_FIX_F_GRPDEF;
1744 uint16_t idxFrame = pThis->idxGrpFlat;
1745 uint8_t bTarget;
1746 uint16_t idxTarget;
1747 bool fTargetDisp;
1748 uint32_t offTargetDisp;
1749 switch (pOmfSym->enmType)
1750 {
1751 case OMFSYMTYPE_INTERNAL:
1752 case OMFSYMTYPE_PUBDEF:
1753 bTarget = OMF_FIX_T_SEGDEF;
1754 idxTarget = pOmfSym->idxSegDef;
1755 fTargetDisp = true;
1756 offTargetDisp = pCoffSym->Value;
1757 break;
1758
1759 case OMFSYMTYPE_SEGDEF:
1760 bTarget = OMF_FIX_T_SEGDEF_NO_DISP;
1761 idxTarget = pOmfSym->idxSegDef;
1762 fTargetDisp = false;
1763 offTargetDisp = 0;
1764 break;
1765
1766 case OMFSYMTYPE_EXTDEF:
1767 bTarget = OMF_FIX_T_EXTDEF_NO_DISP;
1768 idxTarget = pOmfSym->idx;
1769 fTargetDisp = false;
1770 offTargetDisp = 0;
1771 break;
1772
1773 default:
1774 return error(pThis->pszSrc, "Relocation in segment #%u '%s' references ignored or invalid symbol (%s)\n",
1775 i, pszSegNm, coffGetSymbolName(pCoffSym, pchStrTab, cbStrTab, szShortName));
1776 }
1777
1778 /* Do COFF relocation type conversion. */
1779 switch (paRelocs[iReloc].Type)
1780 {
1781 case IMAGE_REL_AMD64_ADDR64:
1782 {
1783 uint64_t uAddend = *uLoc.pu64;
1784 if (uAddend > _1G)
1785 fRet = error(pThis->pszSrc, "ADDR64 with large addend (%#llx) at %#x in segment #%u '%s'\n",
1786 uAddend, paRelocs[iReloc].u.VirtualAddress, i, pszSegNm);
1787 fSelfRel = false;
1788 break;
1789 }
1790
1791 case IMAGE_REL_AMD64_REL32_1:
1792 case IMAGE_REL_AMD64_REL32_2:
1793 case IMAGE_REL_AMD64_REL32_3:
1794 case IMAGE_REL_AMD64_REL32_4:
1795 case IMAGE_REL_AMD64_REL32_5:
1796 /** @todo Check whether OMF read addends from the data or relies on the
1797 * displacement. Also, check what it's relative to. */
1798 *uLoc.pu32 += paRelocs[iReloc].Type - IMAGE_REL_AMD64_REL32;
1799 break;
1800
1801 case IMAGE_REL_AMD64_ADDR32:
1802 fSelfRel = false;
1803 break;
1804
1805 case IMAGE_REL_AMD64_ADDR32NB:
1806 fSelfRel = false;
1807 bFrame = OMF_FIX_F_EXTDEF;
1808 idxFrame = pThis->idxExtImageBase;
1809 break;
1810
1811 case IMAGE_REL_AMD64_REL32:
1812 /* defaults are ok. */
1813 break;
1814
1815 case IMAGE_REL_AMD64_SECTION:
1816 bLocation = OMF_FIX_LOC_16BIT_SEGMENT;
1817 /* fall thru */
1818
1819 case IMAGE_REL_AMD64_SECREL:
1820 fSelfRel = false;
1821 if (pOmfSym->enmType == OMFSYMTYPE_EXTDEF)
1822 {
1823 bFrame = OMF_FIX_F_EXTDEF;
1824 idxFrame = pOmfSym->idx;
1825 }
1826 else
1827 {
1828 bFrame = OMF_FIX_F_SEGDEF;
1829 idxFrame = pOmfSym->idxSegDef;
1830 }
1831 break;
1832
1833 case IMAGE_REL_AMD64_ABSOLUTE:
1834 continue; /* Ignore it like the PECOFF.DOC says we should. */
1835
1836 case IMAGE_REL_AMD64_SECREL7:
1837 default:
1838 return error(pThis->pszSrc, "Unsupported fixup type %#x (%s) at rva=%#x in section #%u '%-8.8s'\n",
1839 paRelocs[iReloc].Type,
1840 paRelocs[iReloc].Type < RT_ELEMENTS(g_apszCoffAmd64RelTypes)
1841 ? g_apszCoffAmd64RelTypes[paRelocs[iReloc].Type] : "unknown",
1842 paRelocs[iReloc].u.VirtualAddress, i, paShdrs[i].Name);
1843 }
1844
1845 /* Add the fixup. */
1846 if (idxFrame == UINT16_MAX)
1847 error(pThis->pszSrc, "idxFrame=UINT16_MAX for %s type=%s\n",
1848 coffGetSymbolName(pCoffSym, pchStrTab, cbStrTab, szShortName),
1849 g_apszCoffAmd64RelTypes[paRelocs[iReloc].Type]);
1850 fRet = omfWriter_LEDataAddFixup(pThis, offDataRec, fSelfRel, bLocation, bFrame, idxFrame,
1851 bTarget, idxTarget, fTargetDisp, offTargetDisp) && fRet;
1852 }
1853
1854 /*
1855 * Write the LEDATA and associated FIXUPPs.
1856 */
1857 if (!omfWriter_LEDataEnd(pThis))
1858 return false;
1859
1860 /*
1861 * Advance.
1862 */
1863 paRelocs += cChunkRelocs;
1864 cRelocs -= cChunkRelocs;
1865 if (cbData > cbChunk)
1866 {
1867 cbData -= cbChunk;
1868 pbData += cbChunk;
1869 }
1870 else
1871 cbData = 0;
1872 off += cbChunk;
1873 cbVirtData -= cbChunk;
1874 }
1875 }
1876
1877 return fRet;
1878}
1879
1880
1881static bool convertCoffToOmf(const char *pszFile, uint8_t const *pbFile, size_t cbFile, FILE *pDst)
1882{
1883 /*
1884 * Validate the source file a little.
1885 */
1886 if (!validateCoff(pszFile, pbFile, cbFile))
1887 return false;
1888
1889 /*
1890 * Instantiate the OMF writer.
1891 */
1892 PIMAGE_FILE_HEADER pHdr = (PIMAGE_FILE_HEADER)pbFile;
1893 POMFWRITER pThis = omfWriter_Create(pszFile, pHdr->NumberOfSections, pHdr->NumberOfSymbols, pDst);
1894 if (!pThis)
1895 return false;
1896
1897 /*
1898 * Write the OMF object file.
1899 */
1900 if (omfWriter_BeginModule(pThis, pszFile))
1901 {
1902 PCIMAGE_SECTION_HEADER paShdrs = (PCIMAGE_SECTION_HEADER)(pHdr + 1);
1903 PCIMAGE_SYMBOL paSymTab = (PCIMAGE_SYMBOL)&pbFile[pHdr->PointerToSymbolTable];
1904 const char *pchStrTab = (const char *)&paSymTab[pHdr->NumberOfSymbols];
1905 if ( convertCoffSectionsToSegDefsAndGrpDefs(pThis, paShdrs, pHdr->NumberOfSections)
1906 && convertCoffSymbolsToPubDefsAndExtDefs(pThis, paSymTab, pHdr->NumberOfSymbols, pchStrTab, paShdrs)
1907 && omfWriter_LinkPassSeparator(pThis)
1908 && convertCoffSectionsToLeDataAndFixupps(pThis, pbFile, cbFile, paShdrs, pHdr->NumberOfSections,
1909 paSymTab, pHdr->NumberOfSymbols, pchStrTab)
1910 && omfWriter_EndModule(pThis) )
1911 {
1912
1913 omfWriter_Destroy(pThis);
1914 return true;
1915 }
1916 }
1917
1918 omfWriter_Destroy(pThis);
1919 return false;
1920}
1921
1922
1923
1924/*********************************************************************************************************************************
1925* OMF Converter/Tweaker *
1926*********************************************************************************************************************************/
1927
1928/** Watcom intrinsics we need to modify so we can mix 32-bit and 16-bit
1929 * code, since the 16 and 32 bit compilers share several names.
1930 * The names are length prefixed.
1931 */
1932static const char * const g_apszExtDefRenames[] =
1933{
1934 "\x05" "__I4D",
1935 "\x05" "__I4M",
1936 "\x05" "__I8D",
1937 "\x06" "__I8DQ",
1938 "\x07" "__I8DQE",
1939 "\x06" "__I8DR",
1940 "\x07" "__I8DRE",
1941 "\x06" "__I8LS",
1942 "\x05" "__I8M",
1943 "\x06" "__I8ME",
1944 "\x06" "__I8RS",
1945 "\x05" "__PIA",
1946 "\x05" "__PIS",
1947 "\x05" "__PTC",
1948 "\x05" "__PTS",
1949 "\x05" "__U4D",
1950 "\x05" "__U4M",
1951 "\x05" "__U8D",
1952 "\x06" "__U8DQ",
1953 "\x07" "__U8DQE",
1954 "\x06" "__U8DR",
1955 "\x07" "__U8DRE",
1956 "\x06" "__U8LS",
1957 "\x05" "__U8M",
1958 "\x06" "__U8ME",
1959 "\x06" "__U8RS",
1960};
1961
1962/**
1963 * Renames references to intrinsic helper functions so they won't clash between
1964 * 32-bit and 16-bit code.
1965 *
1966 * @returns true / false.
1967 * @param pszFile File name for complaining.
1968 * @param pbFile Pointer to the file content.
1969 * @param cbFile Size of the file content.
1970 */
1971static bool convertomf(const char *pszFile, uint8_t *pbFile, size_t cbFile, const char **papchLNames, uint32_t cLNamesMax)
1972{
1973 uint32_t cLNames = 0;
1974 uint32_t cExtDefs = 0;
1975 uint32_t cPubDefs = 0;
1976 bool fProbably32bit = false;
1977 uint32_t off = 0;
1978
1979 while (off + 3 < cbFile)
1980 {
1981 uint8_t bRecType = pbFile[off];
1982 uint16_t cbRec = RT_MAKE_U16(pbFile[off + 1], pbFile[off + 2]);
1983 if (g_cVerbose > 2)
1984 printf( "%#07x: type=%#04x len=%#06x\n", off, bRecType, cbRec);
1985 if (off + cbRec > cbFile)
1986 return error(pszFile, "Invalid record length at %#x: %#x (cbFile=%#lx)\n", off, cbRec, (unsigned long)cbFile);
1987
1988 if (bRecType & OMF_REC32)
1989 fProbably32bit = true;
1990
1991 uint32_t offRec = 0;
1992 uint8_t *pbRec = &pbFile[off + 3];
1993#define OMF_CHECK_RET(a_cbReq, a_Name) /* Not taking the checksum into account, so we're good with 1 or 2 byte fields. */ \
1994 if (offRec + (a_cbReq) <= cbRec) {/*likely*/} \
1995 else return error(pszFile, "Malformed " #a_Name "! off=%#x offRec=%#x cbRec=%#x cbNeeded=%#x line=%d\n", \
1996 off, offRec, cbRec, (a_cbReq), __LINE__)
1997 switch (bRecType)
1998 {
1999 /*
2000 * Scan external definitions for intrinsics needing mangling.
2001 */
2002 case OMF_EXTDEF:
2003 {
2004 while (offRec + 1 < cbRec)
2005 {
2006 uint8_t cch = pbRec[offRec++];
2007 OMF_CHECK_RET(cch, EXTDEF);
2008 char *pchName = (char *)&pbRec[offRec];
2009 offRec += cch;
2010
2011 OMF_CHECK_RET(2, EXTDEF);
2012 uint16_t idxType = pbRec[offRec++];
2013 if (idxType & 0x80)
2014 idxType = ((idxType & 0x7f) << 8) | pbRec[offRec++];
2015
2016 if (g_cVerbose > 2)
2017 printf(" EXTDEF [%u]: %-*.*s type=%#x\n", cExtDefs, cch, cch, pchName, idxType);
2018 else if (g_cVerbose > 0)
2019 printf(" U %-*.*s\n", cch, cch, pchName);
2020
2021 /* Look for g_apszExtDefRenames entries that requires changing. */
2022 if ( cch >= 5
2023 && cch <= 7
2024 && pchName[0] == '_'
2025 && pchName[1] == '_'
2026 && ( pchName[2] == 'U'
2027 || pchName[2] == 'I'
2028 || pchName[2] == 'P')
2029 && ( pchName[3] == '4'
2030 || pchName[3] == '8'
2031 || pchName[3] == 'I'
2032 || pchName[3] == 'T') )
2033 {
2034 uint32_t i = RT_ELEMENTS(g_apszExtDefRenames);
2035 while (i-- > 0)
2036 if ( cch == (uint8_t)g_apszExtDefRenames[i][0]
2037 && memcmp(&g_apszExtDefRenames[i][1], pchName, cch) == 0)
2038 {
2039 pchName[0] = fProbably32bit ? '?' : '_';
2040 pchName[1] = '?';
2041 break;
2042 }
2043 }
2044
2045 cExtDefs++;
2046 }
2047 break;
2048 }
2049
2050 /*
2051 * Record LNAME records, scanning for FLAT.
2052 */
2053 case OMF_LNAMES:
2054 {
2055 while (offRec + 1 < cbRec)
2056 {
2057 uint8_t cch = pbRec[offRec];
2058 if (offRec + 1 + cch >= cbRec)
2059 return error(pszFile, "Invalid LNAME string length at %#x+3+%#x: %#x (cbFile=%#lx)\n",
2060 off, offRec, cch, (unsigned long)cbFile);
2061 if (cLNames + 1 >= cLNamesMax)
2062 return error(pszFile, "Too many LNAME strings\n");
2063
2064 if (g_cVerbose > 2)
2065 printf(" LNAME[%u]: %-*.*s\n", cLNames, cch, cch, &pbRec[offRec + 1]);
2066
2067 papchLNames[cLNames++] = (const char *)&pbRec[offRec];
2068 if (cch == 4 && memcmp(&pbRec[offRec + 1], "FLAT", 4) == 0)
2069 fProbably32bit = true;
2070
2071 offRec += cch + 1;
2072 }
2073 break;
2074 }
2075
2076 /*
2077 * Display public names if -v is specified.
2078 */
2079 case OMF_PUBDEF16:
2080 case OMF_PUBDEF32:
2081 case OMF_LPUBDEF16:
2082 case OMF_LPUBDEF32:
2083 {
2084 if (g_cVerbose > 0)
2085 {
2086 char const chType = bRecType == OMF_PUBDEF16 || bRecType == OMF_PUBDEF32 ? 'T' : 't';
2087 const char *pszRec = "LPUBDEF";
2088 if (chType == 'T')
2089 pszRec++;
2090
2091 OMF_CHECK_RET(2, [L]PUBDEF);
2092 uint16_t idxGrp = pbRec[offRec++];
2093 if (idxGrp & 0x80)
2094 idxGrp = ((idxGrp & 0x7f) << 8) | pbRec[offRec++];
2095
2096 OMF_CHECK_RET(2, [L]PUBDEF);
2097 uint16_t idxSeg = pbRec[offRec++];
2098 if (idxSeg & 0x80)
2099 idxSeg = ((idxSeg & 0x7f) << 8) | pbRec[offRec++];
2100
2101 uint16_t uFrameBase = 0;
2102 if (idxSeg == 0)
2103 {
2104 OMF_CHECK_RET(2, [L]PUBDEF);
2105 uFrameBase = RT_MAKE_U16(pbRec[offRec], pbRec[offRec + 1]);
2106 offRec += 2;
2107 }
2108 if (g_cVerbose > 2)
2109 printf(" %s: idxGrp=%#x idxSeg=%#x uFrameBase=%#x\n", pszRec, idxGrp, idxSeg, uFrameBase);
2110 uint16_t const uSeg = idxSeg ? idxSeg : uFrameBase;
2111
2112 while (offRec + 1 < cbRec)
2113 {
2114 uint8_t cch = pbRec[offRec++];
2115 OMF_CHECK_RET(cch, [L]PUBDEF);
2116 const char *pchName = (const char *)&pbRec[offRec];
2117 offRec += cch;
2118
2119 uint32_t offSeg;
2120 if (bRecType & OMF_REC32)
2121 {
2122 OMF_CHECK_RET(4, [L]PUBDEF);
2123 offSeg = RT_MAKE_U32_FROM_U8(pbRec[offRec], pbRec[offRec + 1], pbRec[offRec + 2], pbRec[offRec + 3]);
2124 offRec += 4;
2125 }
2126 else
2127 {
2128 OMF_CHECK_RET(2, [L]PUBDEF);
2129 offSeg = RT_MAKE_U16(pbRec[offRec], pbRec[offRec + 1]);
2130 offRec += 2;
2131 }
2132
2133 OMF_CHECK_RET(2, [L]PUBDEF);
2134 uint16_t idxType = pbRec[offRec++];
2135 if (idxType & 0x80)
2136 idxType = ((idxType & 0x7f) << 8) | pbRec[offRec++];
2137
2138 if (g_cVerbose > 2)
2139 printf(" %s[%u]: off=%#010x type=%#x %-*.*s\n", pszRec, cPubDefs, offSeg, idxType, cch, cch, pchName);
2140 else if (g_cVerbose > 0)
2141 printf("%04x:%08x %c %-*.*s\n", uSeg, offSeg, chType, cch, cch, pchName);
2142
2143 cPubDefs++;
2144 }
2145 }
2146 break;
2147 }
2148 }
2149
2150 /* advance */
2151 off += cbRec + 3;
2152 }
2153 return true;
2154}
2155
2156
2157/**
2158 * Does the convertion using convertelf and convertcoff.
2159 *
2160 * @returns exit code (0 on success, non-zero on failure)
2161 * @param pszFile The file to convert.
2162 */
2163static int convertit(const char *pszFile)
2164{
2165 /* Construct the filename for saving the unmodified file. */
2166 char szOrgFile[_4K];
2167 size_t cchFile = strlen(pszFile);
2168 if (cchFile + sizeof(".original") > sizeof(szOrgFile))
2169 {
2170 error(pszFile, "Filename too long!\n");
2171 return RTEXITCODE_FAILURE;
2172 }
2173 memcpy(szOrgFile, pszFile, cchFile);
2174 memcpy(&szOrgFile[cchFile], ".original", sizeof(".original"));
2175
2176 /* Read the whole file. */
2177 void *pvFile;
2178 size_t cbFile;
2179 if (readfile(pszFile, &pvFile, &cbFile))
2180 {
2181 /*
2182 * Do format conversions / adjustments.
2183 */
2184 bool fRc = false;
2185 uint8_t *pbFile = (uint8_t *)pvFile;
2186 if ( cbFile > sizeof(Elf64_Ehdr)
2187 && pbFile[0] == ELFMAG0
2188 && pbFile[1] == ELFMAG1
2189 && pbFile[2] == ELFMAG2
2190 && pbFile[3] == ELFMAG3)
2191 {
2192#ifdef ELF_TO_OMF_CONVERSION
2193 if (writefile(szOrgFile, pvFile, cbFile))
2194 {
2195 FILE *pDst = openfile(pszFile, true /*fWrite*/);
2196 if (pDst)
2197 {
2198 fRc = convertElfToOmf(pszFile, pbFile, cbFile, pDst);
2199 fRc = fclose(pDst) == 0 && fRc;
2200 }
2201 }
2202#else
2203 fRc = writefile(szOrgFile, pvFile, cbFile)
2204 && convertelf(pszFile, pbFile, cbFile)
2205 && writefile(pszFile, pvFile, cbFile);
2206#endif
2207 }
2208 else if ( cbFile > sizeof(IMAGE_FILE_HEADER)
2209 && RT_MAKE_U16(pbFile[0], pbFile[1]) == IMAGE_FILE_MACHINE_AMD64
2210 && RT_MAKE_U16(pbFile[2], pbFile[3]) * sizeof(IMAGE_SECTION_HEADER) + sizeof(IMAGE_FILE_HEADER)
2211 < cbFile
2212 && RT_MAKE_U16(pbFile[2], pbFile[3]) > 0)
2213 {
2214 if (writefile(szOrgFile, pvFile, cbFile))
2215 {
2216 FILE *pDst = openfile(pszFile, true /*fWrite*/);
2217 if (pDst)
2218 {
2219 fRc = convertCoffToOmf(pszFile, pbFile, cbFile, pDst);
2220 fRc = fclose(pDst) == 0 && fRc;
2221 }
2222 }
2223 }
2224 else if ( cbFile >= 8
2225 && pbFile[0] == OMF_THEADR
2226 && RT_MAKE_U16(pbFile[1], pbFile[2]) < cbFile)
2227 {
2228 const char **papchLNames = (const char **)calloc(sizeof(*papchLNames), _32K);
2229 fRc = writefile(szOrgFile, pvFile, cbFile)
2230 && convertomf(pszFile, pbFile, cbFile, papchLNames, _32K)
2231 && writefile(pszFile, pvFile, cbFile);
2232 free(papchLNames);
2233 }
2234 else
2235 fprintf(stderr, "error: Don't recognize format of '%s' (%#x %#x %#x %#x, cbFile=%lu)\n",
2236 pszFile, pbFile[0], pbFile[1], pbFile[2], pbFile[3], (unsigned long)cbFile);
2237 free(pvFile);
2238 if (fRc)
2239 return 0;
2240 }
2241 return 1;
2242}
2243
2244
2245int main(int argc, char **argv)
2246{
2247 int rcExit = 0;
2248
2249 /*
2250 * Scan the arguments.
2251 */
2252 for (int i = 1; i < argc; i++)
2253 {
2254 if (argv[i][0] == '-')
2255 {
2256 const char *pszOpt = &argv[i][1];
2257 if (*pszOpt == '-')
2258 {
2259 /* Convert long options to short ones. */
2260 pszOpt--;
2261 if (!strcmp(pszOpt, "--verbose"))
2262 pszOpt = "v";
2263 else if (!strcmp(pszOpt, "--version"))
2264 pszOpt = "V";
2265 else if (!strcmp(pszOpt, "--help"))
2266 pszOpt = "h";
2267 else
2268 {
2269 fprintf(stderr, "syntax errro: Unknown options '%s'\n", pszOpt);
2270 return 2;
2271 }
2272 }
2273
2274 /* Process the list of short options. */
2275 while (*pszOpt)
2276 {
2277 switch (*pszOpt++)
2278 {
2279 case 'v':
2280 g_cVerbose++;
2281 break;
2282
2283 case 'V':
2284 printf("%s\n", "$Revision: 60009 $");
2285 return 0;
2286
2287 case '?':
2288 case 'h':
2289 printf("usage: %s [options] -o <output> <input1> [input2 ... [inputN]]\n",
2290 argv[0]);
2291 return 0;
2292 }
2293 }
2294 }
2295 else
2296 {
2297 /*
2298 * File to convert. Do the job right away.
2299 */
2300 rcExit = convertit(argv[i]);
2301 if (rcExit != 0)
2302 break;
2303 }
2304 }
2305
2306 return rcExit;
2307}
2308
2309
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette