VirtualBox

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

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

VBoxBs3ObjConverter: ELF conversion fixes.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 113.8 KB
Line 
1/* $Id: VBoxBs3ObjConverter.cpp 60136 2016-03-22 13:40:01Z vboxsync $ */
2/** @file
3 * VirtualBox Validation Kit - Boot Sector 3 object file convert.
4 */
5
6/*
7 * Copyright (C) 2006-2016 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 + 2U <= 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 + 4U <= 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 <= OMF_FIX_T_FRAME_NO) )
696 /*return*/ error(pThis->pszSrc,
697 "Internal error: offDataRec=%#x bFrame=%u idxFrame=%#x bTarget=%u idxTarget=%#x fTargetDisp=%d offTargetDisp=%#x\n",
698 offDataRec, bFrame, idxFrame, bTarget, idxTarget, fTargetDisp, offTargetDisp);
699
700
701 /*
702 * Encode the FIXUP subrecord.
703 */
704 uint8_t abFixup[16];
705 uint8_t off = 0;
706 /* Location */
707 abFixup[off++] = (offDataRec >> 8) | (bLocation << 2) | ((uint8_t)!fSelfRel << 6) | 0x80;
708 abFixup[off++] = (uint8_t)offDataRec;
709 /* Fix Data */
710 abFixup[off++] = 0x00 /*F=0*/ | (bFrame << 4) | 0x00 /*T=0*/ | bTarget;
711 /* Frame Datum */
712 if (bFrame <= OMF_FIX_F_FRAME_NO)
713 {
714 if (idxFrame >= 128)
715 abFixup[off++] = (uint8_t)(idxFrame >> 8);
716 abFixup[off++] = (uint8_t)idxFrame;
717 }
718 /* Target Datum */
719 if (idxTarget >= 128)
720 abFixup[off++] = (uint8_t)(idxTarget >> 8);
721 abFixup[off++] = (uint8_t)idxTarget;
722 /* Target Displacement */
723 if (fTargetDisp)
724 {
725 abFixup[off++] = RT_BYTE1(offTargetDisp);
726 abFixup[off++] = RT_BYTE2(offTargetDisp);
727 abFixup[off++] = RT_BYTE3(offTargetDisp);
728 abFixup[off++] = RT_BYTE4(offTargetDisp);
729 }
730
731 return omfWriter_LEDataAddFixuppBytes(pThis, abFixup, off);
732}
733
734/**
735 * LEDATA + FIXUPP - End of records.
736 */
737static bool omfWriter_LEDataEnd(POMFWRITER pThis)
738{
739 if (omfWriter_RecEndWithCrc(pThis))
740 {
741 for (unsigned iFixupp = 0; iFixupp <= pThis->iFixupp; iFixupp++)
742 {
743 uint8_t const cbRec = pThis->aFixupps[iFixupp].cbRec;
744 if (!cbRec)
745 break;
746 if ( !omfWriter_RecBegin(pThis, OMF_FIXUPP32)
747 || !omfWriter_RecAddBytes(pThis, pThis->aFixupps[iFixupp].abData, cbRec)
748 || !omfWriter_RecEndWithCrc(pThis))
749 return false;
750 }
751 pThis->iFixupp = 0;
752 return true;
753 }
754 return false;
755}
756
757/**
758 * MODEND - End of module, simple variant.
759 */
760static bool omfWriter_EndModule(POMFWRITER pThis)
761{
762 return omfWriter_RecBegin(pThis, OMF_MODEND32)
763 && omfWriter_RecAddU8(pThis, 0)
764 && omfWriter_RecEndWithCrc(pThis);
765}
766
767
768
769
770/*********************************************************************************************************************************
771* ELF64/AMD64 -> ELF64/i386 Converter *
772*********************************************************************************************************************************/
773
774/** AMD64 relocation type names for ELF. */
775static const char * const g_apszElfAmd64RelTypes[] =
776{
777 "R_X86_64_NONE",
778 "R_X86_64_64",
779 "R_X86_64_PC32",
780 "R_X86_64_GOT32",
781 "R_X86_64_PLT32",
782 "R_X86_64_COPY",
783 "R_X86_64_GLOB_DAT",
784 "R_X86_64_JMP_SLOT",
785 "R_X86_64_RELATIVE",
786 "R_X86_64_GOTPCREL",
787 "R_X86_64_32",
788 "R_X86_64_32S",
789 "R_X86_64_16",
790 "R_X86_64_PC16",
791 "R_X86_64_8",
792 "R_X86_64_PC8",
793 "R_X86_64_DTPMOD64",
794 "R_X86_64_DTPOFF64",
795 "R_X86_64_TPOFF64",
796 "R_X86_64_TLSGD",
797 "R_X86_64_TLSLD",
798 "R_X86_64_DTPOFF32",
799 "R_X86_64_GOTTPOFF",
800 "R_X86_64_TPOFF32",
801};
802
803/** AMD64 relocation type sizes for ELF. */
804static uint8_t const g_acbElfAmd64RelTypes[] =
805{
806 0, /* R_X86_64_NONE */
807 8, /* R_X86_64_64 */
808 4, /* R_X86_64_PC32 */
809 4, /* R_X86_64_GOT32 */
810 4, /* R_X86_64_PLT32 */
811 0, /* R_X86_64_COPY */
812 0, /* R_X86_64_GLOB_DAT */
813 0, /* R_X86_64_JMP_SLOT */
814 0, /* R_X86_64_RELATIVE */
815 0, /* R_X86_64_GOTPCREL */
816 4, /* R_X86_64_32 */
817 4, /* R_X86_64_32S */
818 2, /* R_X86_64_16 */
819 2, /* R_X86_64_PC16 */
820 1, /* R_X86_64_8 */
821 1, /* R_X86_64_PC8 */
822 0, /* R_X86_64_DTPMOD64 */
823 0, /* R_X86_64_DTPOFF64 */
824 0, /* R_X86_64_TPOFF64 */
825 0, /* R_X86_64_TLSGD */
826 0, /* R_X86_64_TLSLD */
827 0, /* R_X86_64_DTPOFF32 */
828 0, /* R_X86_64_GOTTPOFF */
829 0, /* R_X86_64_TPOFF32 */
830};
831
832/** Macro for getting the size of a AMD64 ELF relocation. */
833#define ELF_AMD64_RELOC_SIZE(a_Type) ( (a_Type) < RT_ELEMENTS(g_acbElfAmd64RelTypes) ? g_acbElfAmd64RelTypes[(a_Type)] : 1)
834
835
836typedef struct ELFDETAILS
837{
838 /** The ELF header. */
839 Elf64_Ehdr const *pEhdr;
840 /** The section header table. */
841 Elf64_Shdr const *paShdrs;
842 /** The string table for the section names. */
843 const char *pchShStrTab;
844
845 /** The symbol table section number. UINT16_MAX if not found. */
846 uint16_t iSymSh;
847 /** The string table section number. UINT16_MAX if not found. */
848 uint16_t iStrSh;
849
850 /** The symbol table. */
851 Elf64_Sym const *paSymbols;
852 /** The number of symbols in the symbol table. */
853 uint32_t cSymbols;
854
855 /** Pointer to the (symbol) string table if found. */
856 const char *pchStrTab;
857 /** The string table size. */
858 size_t cbStrTab;
859
860} ELFDETAILS;
861typedef ELFDETAILS *PELFDETAILS;
862typedef ELFDETAILS const *PCELFDETAILS;
863
864
865static bool validateElf(const char *pszFile, uint8_t const *pbFile, size_t cbFile, PELFDETAILS pElfStuff)
866{
867 /*
868 * Initialize the ELF details structure.
869 */
870 memset(pElfStuff, 0, sizeof(*pElfStuff));
871 pElfStuff->iSymSh = UINT16_MAX;
872 pElfStuff->iStrSh = UINT16_MAX;
873
874 /*
875 * Validate the header and our other expectations.
876 */
877 Elf64_Ehdr const *pEhdr = (Elf64_Ehdr const *)pbFile;
878 pElfStuff->pEhdr = pEhdr;
879 if ( pEhdr->e_ident[EI_CLASS] != ELFCLASS64
880 || pEhdr->e_ident[EI_DATA] != ELFDATA2LSB
881 || pEhdr->e_ehsize != sizeof(Elf64_Ehdr)
882 || pEhdr->e_shentsize != sizeof(Elf64_Shdr)
883 || pEhdr->e_version != EV_CURRENT )
884 return error(pszFile, "Unsupported ELF config\n");
885 if (pEhdr->e_type != ET_REL)
886 return error(pszFile, "Expected relocatable ELF file (e_type=%d)\n", pEhdr->e_type);
887 if (pEhdr->e_machine != EM_X86_64)
888 return error(pszFile, "Expected relocatable ELF file (e_type=%d)\n", pEhdr->e_machine);
889 if (pEhdr->e_phnum != 0)
890 return error(pszFile, "Expected e_phnum to be zero not %u\n", pEhdr->e_phnum);
891 if (pEhdr->e_shnum < 2)
892 return error(pszFile, "Expected e_shnum to be two or higher\n");
893 if (pEhdr->e_shstrndx >= pEhdr->e_shnum || pEhdr->e_shstrndx == 0)
894 return error(pszFile, "Bad e_shstrndx=%u (e_shnum=%u)\n", pEhdr->e_shstrndx, pEhdr->e_shnum);
895 if ( pEhdr->e_shoff >= cbFile
896 || pEhdr->e_shoff + pEhdr->e_shnum * sizeof(Elf64_Shdr) > cbFile)
897 return error(pszFile, "Section table is outside the file (e_shoff=%#llx, e_shnum=%u, cbFile=%#llx)\n",
898 pEhdr->e_shstrndx, pEhdr->e_shnum, (uint64_t)cbFile);
899
900 /*
901 * Locate the section name string table.
902 * We assume it's okay as we only reference it in verbose mode.
903 */
904 Elf64_Shdr const *paShdrs = (Elf64_Shdr const *)&pbFile[pEhdr->e_shoff];
905 pElfStuff->paShdrs = paShdrs;
906
907 Elf64_Xword const cbShStrTab = paShdrs[pEhdr->e_shstrndx].sh_size;
908 if ( paShdrs[pEhdr->e_shstrndx].sh_offset > cbFile
909 || cbShStrTab > cbFile
910 || paShdrs[pEhdr->e_shstrndx].sh_offset + cbShStrTab > cbFile)
911 return error(pszFile,
912 "Section string table is outside the file (sh_offset=%#" ELF_FMT_X64 " sh_size=%#" ELF_FMT_X64 " cbFile=%#" ELF_FMT_X64 ")\n",
913 paShdrs[pEhdr->e_shstrndx].sh_offset, paShdrs[pEhdr->e_shstrndx].sh_size, (Elf64_Xword)cbFile);
914 const char *pchShStrTab = (const char *)&pbFile[paShdrs[pEhdr->e_shstrndx].sh_offset];
915 pElfStuff->pchShStrTab = pchShStrTab;
916
917 /*
918 * Work the section table.
919 */
920 bool fRet = true;
921 for (uint32_t i = 1; i < pEhdr->e_shnum; i++)
922 {
923 if (paShdrs[i].sh_name >= cbShStrTab)
924 return error(pszFile, "Invalid sh_name value (%#x) for section #%u\n", paShdrs[i].sh_name, i);
925 const char *pszShNm = &pchShStrTab[paShdrs[i].sh_name];
926
927 if ( paShdrs[i].sh_offset > cbFile
928 || paShdrs[i].sh_size > cbFile
929 || paShdrs[i].sh_offset + paShdrs[i].sh_size > cbFile)
930 return error(pszFile, "Section #%u '%s' has data outside the file: %#" ELF_FMT_X64 " LB %#" ELF_FMT_X64 " (cbFile=%#" ELF_FMT_X64 ")\n",
931 i, pszShNm, paShdrs[i].sh_offset, paShdrs[i].sh_size, (Elf64_Xword)cbFile);
932 if (g_cVerbose)
933 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"
934 " link=%u info=%#x align=%#" ELF_FMT_X64 " entsize=%#" ELF_FMT_X64 "\n",
935 i, paShdrs[i].sh_name, pszShNm, paShdrs[i].sh_type, paShdrs[i].sh_flags,
936 paShdrs[i].sh_addr, paShdrs[i].sh_offset, paShdrs[i].sh_size,
937 paShdrs[i].sh_link, paShdrs[i].sh_info, paShdrs[i].sh_addralign, paShdrs[i].sh_entsize);
938
939 if (paShdrs[i].sh_link >= pEhdr->e_shnum)
940 return error(pszFile, "Section #%u '%s' links to a section outside the section table: %#x, max %#x\n",
941 i, pszShNm, paShdrs[i].sh_link, pEhdr->e_shnum);
942 if (!RT_IS_POWER_OF_TWO(paShdrs[i].sh_addralign))
943 return error(pszFile, "Section #%u '%s' alignment value is not a power of two: %#" ELF_FMT_X64 "\n",
944 i, pszShNm, paShdrs[i].sh_addralign);
945 if (!RT_IS_POWER_OF_TWO(paShdrs[i].sh_addralign))
946 return error(pszFile, "Section #%u '%s' alignment value is not a power of two: %#" ELF_FMT_X64 "\n",
947 i, pszShNm, paShdrs[i].sh_addralign);
948 if (paShdrs[i].sh_addr != 0)
949 return error(pszFile, "Section #%u '%s' has non-zero address: %#" ELF_FMT_X64 "\n", i, pszShNm, paShdrs[i].sh_addr);
950
951 if (paShdrs[i].sh_type == SHT_RELA)
952 {
953 if (paShdrs[i].sh_entsize != sizeof(Elf64_Rela))
954 return error(pszFile, "Expected sh_entsize to be %u not %u for section #%u (%s)\n", (unsigned)sizeof(Elf64_Rela),
955 paShdrs[i].sh_entsize, i, pszShNm);
956 uint32_t const cRelocs = paShdrs[i].sh_size / sizeof(Elf64_Rela);
957 if (cRelocs * sizeof(Elf64_Rela) != paShdrs[i].sh_size)
958 return error(pszFile, "Uneven relocation entry count in #%u (%s): sh_size=%#" ELF_FMT_X64 "\n",
959 i, pszShNm, paShdrs[i].sh_size);
960 if ( paShdrs[i].sh_offset > cbFile
961 || paShdrs[i].sh_size >= cbFile
962 || paShdrs[i].sh_offset + paShdrs[i].sh_size > cbFile)
963 return error(pszFile, "The content of section #%u '%s' is outside the file (%#" ELF_FMT_X64 " LB %#" ELF_FMT_X64 ", cbFile=%#lx)\n",
964 i, pszShNm, paShdrs[i].sh_offset, paShdrs[i].sh_size, (unsigned long)cbFile);
965 if (paShdrs[i].sh_info != i - 1)
966 return error(pszFile, "Expected relocation section #%u (%s) to link to previous section: sh_info=%#u\n",
967 i, pszShNm, (unsigned)paShdrs[i].sh_link);
968 if (paShdrs[paShdrs[i].sh_link].sh_type != SHT_SYMTAB)
969 return error(pszFile, "Expected relocation section #%u (%s) to link to symbol table: sh_link=%#u -> sh_type=%#x\n",
970 i, pszShNm, (unsigned)paShdrs[i].sh_link, (unsigned)paShdrs[paShdrs[i].sh_link].sh_type);
971 uint32_t cSymbols = paShdrs[paShdrs[i].sh_link].sh_size / paShdrs[paShdrs[i].sh_link].sh_entsize;
972
973 Elf64_Rela const *paRelocs = (Elf64_Rela *)&pbFile[paShdrs[i].sh_offset];
974 for (uint32_t j = 0; j < cRelocs; j++)
975 {
976 uint8_t const bType = ELF64_R_TYPE(paRelocs[j].r_info);
977 if (RT_UNLIKELY(bType >= R_X86_64_COUNT))
978 fRet = error(pszFile,
979 "%#018" ELF_FMT_X64 " %#018" ELF_FMT_X64 ": unknown fix up %#x (%+" ELF_FMT_D64 ")\n",
980 paRelocs[j].r_offset, paRelocs[j].r_info, bType, paRelocs[j].r_addend);
981 if (RT_UNLIKELY( j > 1
982 && paRelocs[j].r_offset <= paRelocs[j - 1].r_offset
983 && paRelocs[j].r_offset + ELF_AMD64_RELOC_SIZE(ELF64_R_TYPE(paRelocs[j].r_info))
984 < paRelocs[j - 1].r_offset ))
985 fRet = error(pszFile,
986 "%#018" ELF_FMT_X64 " %#018" ELF_FMT_X64 ": out of offset order (prev %" ELF_FMT_X64 ")\n",
987 paRelocs[j].r_offset, paRelocs[j].r_info, paRelocs[j - 1].r_offset);
988 uint32_t const iSymbol = ELF64_R_SYM(paRelocs[j].r_info);
989 if (RT_UNLIKELY(iSymbol >= cSymbols))
990 fRet = error(pszFile,
991 "%#018" ELF_FMT_X64 " %#018" ELF_FMT_X64 ": symbol index (%#x) out of bounds (%#x)\n",
992 paRelocs[j].r_offset, paRelocs[j].r_info, iSymbol, cSymbols);
993 }
994 if (RT_UNLIKELY( cRelocs > 0
995 && fRet
996 && ( paRelocs[cRelocs - 1].r_offset > paShdrs[i - 1].sh_size
997 || paRelocs[cRelocs - 1].r_offset + ELF_AMD64_RELOC_SIZE(ELF64_R_TYPE(paRelocs[cRelocs-1].r_info))
998 > paShdrs[i - 1].sh_size )))
999 fRet = error(pszFile,
1000 "%#018" ELF_FMT_X64 " %#018" ELF_FMT_X64 ": out of bounds (sh_size %" ELF_FMT_X64 ")\n",
1001 paRelocs[cRelocs - 1].r_offset, paRelocs[cRelocs - 1].r_info, paShdrs[i - 1].sh_size);
1002
1003 }
1004 else if (paShdrs[i].sh_type == SHT_REL)
1005 fRet = error(pszFile, "Section #%u '%s': Unexpected SHT_REL section\n", i, pszShNm);
1006 else if (paShdrs[i].sh_type == SHT_SYMTAB)
1007 {
1008 if (paShdrs[i].sh_entsize != sizeof(Elf64_Sym))
1009 fRet = error(pszFile, "Section #%u '%s': Unsupported symbol table entry size in : #%u (expected #%u)\n",
1010 i, pszShNm, paShdrs[i].sh_entsize, sizeof(Elf64_Sym));
1011 Elf64_Xword const cSymbols = paShdrs[i].sh_size / paShdrs[i].sh_entsize;
1012 if (cSymbols * paShdrs[i].sh_entsize != paShdrs[i].sh_size)
1013 fRet = error(pszFile, "Section #%u '%s': Size not a multiple of entry size: %#" ELF_FMT_X64 " %% %#" ELF_FMT_X64 " = %#" ELF_FMT_X64 "\n",
1014 i, pszShNm, paShdrs[i].sh_size, paShdrs[i].sh_entsize, paShdrs[i].sh_size % paShdrs[i].sh_entsize);
1015 if (cSymbols > UINT32_MAX)
1016 fRet = error(pszFile, "Section #%u '%s': too many symbols: %" ELF_FMT_X64 "\n",
1017 i, pszShNm, paShdrs[i].sh_size, cSymbols);
1018
1019 if (pElfStuff->iSymSh == UINT16_MAX)
1020 {
1021 pElfStuff->iSymSh = (uint16_t)i;
1022 pElfStuff->paSymbols = (Elf64_Sym const *)&pbFile[paShdrs[i].sh_offset];
1023 pElfStuff->cSymbols = cSymbols;
1024
1025 if (paShdrs[i].sh_link != 0)
1026 {
1027 /* Note! The symbol string table section header may not have been validated yet! */
1028 Elf64_Shdr const *pStrTabShdr = &paShdrs[paShdrs[i].sh_link];
1029 pElfStuff->iStrSh = paShdrs[i].sh_link;
1030 pElfStuff->pchStrTab = (const char *)&pbFile[pStrTabShdr->sh_offset];
1031 pElfStuff->cbStrTab = (size_t)pStrTabShdr->sh_size;
1032 }
1033 else
1034 fRet = error(pszFile, "Section #%u '%s': String table link is out of bounds (%#x)\n",
1035 i, pszShNm, paShdrs[i].sh_link);
1036 }
1037 else
1038 fRet = error(pszFile, "Section #%u '%s': Found additonal symbol table, previous in #%u\n",
1039 i, pszShNm, pElfStuff->iSymSh);
1040 }
1041 }
1042 return fRet;
1043}
1044
1045#define ELF_TO_OMF_CONVERSION
1046
1047#ifdef ELF_TO_OMF_CONVERSION
1048
1049
1050static bool convertElfSectionsToSegDefsAndGrpDefs(POMFWRITER pThis, PCELFDETAILS pElfStuff)
1051{
1052 /*
1053 * Do the list of names pass.
1054 */
1055 uint16_t idxGrpFlat, idxGrpData;
1056 uint16_t idxClassCode, idxClassData, idxClassDwarf;
1057 if ( !omfWriter_LNamesBegin(pThis)
1058 || !omfWriter_LNamesAddN(pThis, RT_STR_TUPLE("FLAT"), &idxGrpFlat)
1059 || !omfWriter_LNamesAddN(pThis, RT_STR_TUPLE("BS3DATA64_GROUP"), &idxGrpData)
1060 || !omfWriter_LNamesAddN(pThis, RT_STR_TUPLE("BS3CLASS64CODE"), &idxClassCode)
1061 || !omfWriter_LNamesAddN(pThis, RT_STR_TUPLE("FAR_DATA"), &idxClassData)
1062 || !omfWriter_LNamesAddN(pThis, RT_STR_TUPLE("DWARF"), &idxClassDwarf)
1063 )
1064 return false;
1065
1066 bool fHaveData = false;
1067 Elf64_Shdr const *pShdr = &pElfStuff->paShdrs[1];
1068 Elf64_Half const cSections = pElfStuff->pEhdr->e_shnum;
1069 for (Elf64_Half i = 1; i < cSections; i++, pShdr++)
1070 {
1071 const char *pszName = &pElfStuff->pchShStrTab[pShdr->sh_name];
1072 if (*pszName == '\0')
1073 return error(pThis->pszSrc, "Section #%u has an empty name!\n", i);
1074
1075 switch (pShdr->sh_type)
1076 {
1077 case SHT_PROGBITS:
1078 case SHT_NOBITS:
1079 /* We drop a few sections we don't want:. */
1080 if ( strcmp(pszName, ".comment") != 0 /* compiler info */
1081 && strcmp(pszName, ".note.GNU-stack") != 0 /* some empty section for hinting the linker/whatever */
1082 && strcmp(pszName, ".eh_frame") != 0 /* unwind / exception info */
1083 )
1084 {
1085 pThis->paSegments[i].iSegDef = UINT16_MAX;
1086 pThis->paSegments[i].iGrpDef = UINT16_MAX;
1087
1088 /* Translate the name and determine group and class.
1089 Note! We currently strip sub-sections. */
1090 if ( strcmp(pszName, ".text") == 0
1091 || strncmp(pszName, RT_STR_TUPLE(".text.")) == 0)
1092 {
1093 pszName = "BS3TEXT64";
1094 pThis->paSegments[i].iGrpNm = idxGrpFlat;
1095 pThis->paSegments[i].iClassNm = idxClassCode;
1096 }
1097 else if ( strcmp(pszName, ".data") == 0
1098 || strncmp(pszName, RT_STR_TUPLE(".data.")) == 0)
1099 {
1100 pszName = "BS3DATA64";
1101 pThis->paSegments[i].iGrpNm = idxGrpData;
1102 pThis->paSegments[i].iClassNm = idxClassData;
1103 }
1104 else if (strcmp(pszName, ".bss") == 0)
1105 {
1106 pszName = "BS3BSS64";
1107 pThis->paSegments[i].iGrpNm = idxGrpData;
1108 pThis->paSegments[i].iClassNm = idxClassData;
1109 }
1110 else if ( strcmp(pszName, ".rodata") == 0
1111 || strncmp(pszName, RT_STR_TUPLE(".rodata.")) == 0)
1112 {
1113 pszName = "BS3DATA64CONST";
1114 pThis->paSegments[i].iGrpNm = idxGrpData;
1115 pThis->paSegments[i].iClassNm = idxClassData;
1116 }
1117 else if (strncmp(pszName, RT_STR_TUPLE(".debug_")) == 0)
1118 {
1119 pThis->paSegments[i].iGrpNm = UINT16_MAX;
1120 pThis->paSegments[i].iClassNm = idxClassDwarf;
1121 }
1122 else
1123 {
1124 pThis->paSegments[i].iGrpNm = idxGrpData;
1125 pThis->paSegments[i].iClassNm = idxClassData;
1126 error(pThis->pszSrc, "Unknown data (?) segment: '%s'\n", pszName);
1127 }
1128
1129 /* Save the name. */
1130 pThis->paSegments[i].pszName = strdup(pszName);
1131 if (!pThis->paSegments[i].pszName)
1132 return error(pThis->pszSrc, "Out of memory!\n");
1133
1134 /* Add the section name. */
1135 if (!omfWriter_LNamesAdd(pThis, pThis->paSegments[i].pszName, &pThis->paSegments[i].iSegNm))
1136 return false;
1137
1138 fHaveData |= pThis->paSegments[i].iGrpDef == idxGrpData;
1139 break;
1140 }
1141 /* fall thru */
1142
1143 default:
1144 pThis->paSegments[i].iSegDef = UINT16_MAX;
1145 pThis->paSegments[i].iGrpDef = UINT16_MAX;
1146 pThis->paSegments[i].iSegNm = UINT16_MAX;
1147 pThis->paSegments[i].iGrpNm = UINT16_MAX;
1148 pThis->paSegments[i].iClassNm = UINT16_MAX;
1149 pThis->paSegments[i].pszName = NULL;
1150 break;
1151 }
1152 }
1153
1154 if (!omfWriter_LNamesEnd(pThis))
1155 return false;
1156
1157 /*
1158 * Emit segment definitions.
1159 */
1160 uint16_t iSegDef = 1; /* Start counting at 1. */
1161 pShdr = &pElfStuff->paShdrs[1];
1162 for (Elf64_Half i = 1; i < cSections; i++, pShdr++)
1163 {
1164 if (pThis->paSegments[i].iSegNm == UINT16_MAX)
1165 continue;
1166
1167 uint8_t bSegAttr = 0;
1168
1169 /* The A field. */
1170 switch (pShdr->sh_addralign)
1171 {
1172 case 0:
1173 case 1:
1174 bSegAttr |= 1 << 5;
1175 break;
1176 case 2:
1177 bSegAttr |= 2 << 5;
1178 break;
1179 case 4:
1180 bSegAttr |= 5 << 5;
1181 break;
1182 case 8:
1183 case 16:
1184 bSegAttr |= 3 << 5;
1185 break;
1186 case 32:
1187 case 64:
1188 case 128:
1189 case 256:
1190 bSegAttr |= 4 << 5;
1191 break;
1192 default:
1193 bSegAttr |= 6 << 5; /* page aligned, pharlabs extension. */
1194 break;
1195 }
1196
1197 /* The C field. */
1198 bSegAttr |= 2 << 2; /* public */
1199
1200 /* The B field. We don't have 4GB segments, so leave it as zero. */
1201
1202 /* The D field shall be set as we're doing USE32. */
1203 bSegAttr |= 1;
1204
1205
1206 /* Done. */
1207 if (!omfWriter_SegDef(pThis, bSegAttr, (uint32_t)pShdr->sh_size,
1208 pThis->paSegments[i].iSegNm,
1209 pThis->paSegments[i].iClassNm))
1210 return false;
1211 pThis->paSegments[i].iSegDef = iSegDef++;
1212 }
1213
1214 /*
1215 * Flat group definition (#1) - special, no members.
1216 */
1217 uint16_t iGrpDef = 1;
1218 if ( !omfWriter_GrpDefBegin(pThis, idxGrpFlat)
1219 || !omfWriter_GrpDefEnd(pThis))
1220 return false;
1221 for (uint16_t i = 0; i < cSections; i++)
1222 if (pThis->paSegments[i].iGrpNm == idxGrpFlat)
1223 pThis->paSegments[i].iGrpDef = iGrpDef;
1224 pThis->idxGrpFlat = iGrpDef++;
1225
1226 /*
1227 * Data group definition (#2).
1228 */
1229 /** @todo do we need to consider missing segments and ordering? */
1230 uint16_t cGrpNms = 0;
1231 uint16_t aiGrpNms[2];
1232 if (fHaveData)
1233 aiGrpNms[cGrpNms++] = idxGrpData;
1234 for (uint32_t iGrpNm = 0; iGrpNm < cGrpNms; iGrpNm++)
1235 {
1236 if (!omfWriter_GrpDefBegin(pThis, aiGrpNms[iGrpNm]))
1237 return false;
1238 for (uint16_t i = 0; i < cSections; i++)
1239 if (pThis->paSegments[i].iGrpNm == aiGrpNms[iGrpNm])
1240 {
1241 pThis->paSegments[i].iGrpDef = iGrpDef;
1242 if (!omfWriter_GrpDefAddSegDef(pThis, pThis->paSegments[i].iSegDef))
1243 return false;
1244 }
1245 if (!omfWriter_GrpDefEnd(pThis))
1246 return false;
1247 iGrpDef++;
1248 }
1249
1250 return true;
1251}
1252
1253static bool convertElfSymbolsToPubDefsAndExtDefs(POMFWRITER pThis, PCELFDETAILS pElfStuff)
1254{
1255 if (!pElfStuff->cSymbols)
1256 return true;
1257
1258 /*
1259 * Process the symbols the first.
1260 */
1261 uint32_t cAbsSyms = 0;
1262 uint32_t cExtSyms = 0;
1263 uint32_t cPubSyms = 0;
1264 for (uint32_t iSeg = 0; iSeg < pThis->cSegments; iSeg++)
1265 pThis->paSegments[iSeg].cPubDefs = 0;
1266
1267 uint32_t const cSections = pElfStuff->pEhdr->e_shnum;
1268 uint32_t const cSymbols = pElfStuff->cSymbols;
1269 Elf64_Sym const * const paSymbols = pElfStuff->paSymbols;
1270 for (uint32_t iSym = 0; iSym < cSymbols; iSym++)
1271 {
1272 const uint8_t bBind = ELF64_ST_BIND(paSymbols[iSym].st_info);
1273 const uint8_t bType = ELF64_ST_TYPE(paSymbols[iSym].st_info);
1274 const char *pszSymName = &pElfStuff->pchStrTab[paSymbols[iSym].st_name];
1275 if ( *pszSymName == '\0'
1276 && bType == STT_SECTION
1277 && paSymbols[iSym].st_shndx < cSections)
1278 pszSymName = &pElfStuff->pchShStrTab[pElfStuff->paShdrs[paSymbols[iSym].st_shndx].sh_name];
1279
1280 pThis->paSymbols[iSym].enmType = OMFSYMTYPE_IGNORED;
1281 pThis->paSymbols[iSym].idx = UINT16_MAX;
1282 pThis->paSymbols[iSym].idxSegDef = UINT16_MAX;
1283 pThis->paSymbols[iSym].idxGrpDef = UINT16_MAX;
1284
1285 uint32_t const idxSection = paSymbols[iSym].st_shndx;
1286 if (idxSection == SHN_UNDEF)
1287 {
1288 if (bBind == STB_GLOBAL)
1289 {
1290 pThis->paSymbols[iSym].enmType = OMFSYMTYPE_EXTDEF;
1291 cExtSyms++;
1292 if (*pszSymName == '\0')
1293 return error(pThis->pszSrc, "External symbol #%u (%s) has an empty name.\n", iSym, pszSymName);
1294 }
1295 else if (bBind != STB_LOCAL || iSym != 0) /* Entry zero is usually a dummy. */
1296 return error(pThis->pszSrc, "Unsupported or invalid bind type %#x for undefined symbol #%u (%s)\n",
1297 bBind, iSym, pszSymName);
1298 }
1299 else if (idxSection < cSections)
1300 {
1301 pThis->paSymbols[iSym].idxSegDef = pThis->paSegments[idxSection].iSegDef;
1302 pThis->paSymbols[iSym].idxGrpDef = pThis->paSegments[idxSection].iGrpDef;
1303 if (bBind == STB_GLOBAL)
1304 {
1305 pThis->paSymbols[iSym].enmType = OMFSYMTYPE_PUBDEF;
1306 pThis->paSegments[idxSection].cPubDefs++;
1307 cPubSyms++;
1308 if (bType == STT_SECTION)
1309 return error(pThis->pszSrc, "Don't know how to export STT_SECTION symbol #%u (%s)\n", iSym, pszSymName);
1310 if (*pszSymName == '\0')
1311 return error(pThis->pszSrc, "Public symbol #%u (%s) has an empty name.\n", iSym, pszSymName);
1312 }
1313 else if (bType == STT_SECTION)
1314 pThis->paSymbols[iSym].enmType = OMFSYMTYPE_SEGDEF;
1315 else
1316 pThis->paSymbols[iSym].enmType = OMFSYMTYPE_INTERNAL;
1317 }
1318 else if (idxSection == SHN_ABS)
1319 {
1320 if (bType != STT_FILE)
1321 {
1322 if (bBind == STB_GLOBAL)
1323 {
1324 pThis->paSymbols[iSym].enmType = OMFSYMTYPE_PUBDEF;
1325 pThis->paSymbols[iSym].idxSegDef = 0;
1326 pThis->paSymbols[iSym].idxGrpDef = 0;
1327 cAbsSyms++;
1328 if (*pszSymName == '\0')
1329 return error(pThis->pszSrc, "Public absolute symbol #%u (%s) has an empty name.\n", iSym, pszSymName);
1330 }
1331 else
1332 return error(pThis->pszSrc, "Unsupported or invalid bind type %#x for absolute symbol #%u (%s)\n",
1333 bBind, iSym, pszSymName);
1334 }
1335 }
1336 else
1337 return error(pThis->pszSrc, "Unsupported or invalid section number %#x for symbol #%u (%s)\n",
1338 idxSection, iSym, pszSymName);
1339 }
1340
1341 /*
1342 * Emit the PUBDEFs the first time around (see order of records in TIS spec).
1343 */
1344 uint16_t idxPubDef = 1;
1345 if (cPubSyms)
1346 {
1347 for (uint32_t iSeg = 0; iSeg < pThis->cSegments; iSeg++)
1348 if (pThis->paSegments[iSeg].cPubDefs > 0)
1349 {
1350 uint16_t const idxSegDef = pThis->paSegments[iSeg].iSegDef;
1351 if (!omfWriter_PubDefBegin(pThis, pThis->paSegments[iSeg].iGrpDef, idxSegDef))
1352 return false;
1353 for (uint16_t iSym = 0; iSym < cSymbols; iSym++)
1354 if ( pThis->paSymbols[iSym].idxSegDef == idxSegDef
1355 && pThis->paSymbols[iSym].enmType == OMFSYMTYPE_PUBDEF)
1356 {
1357 const char *pszName = &pElfStuff->pchStrTab[paSymbols[iSym].st_name];
1358 if (!omfWriter_PubDefAdd(pThis, paSymbols[iSym].st_value, pszName))
1359 return false;
1360
1361 /* If the symbol doesn't start with an underscore and is a _c64 or _lm64 symbol,
1362 add an underscore prefixed alias to ease access from 16-bit and 32-bit code. */
1363 size_t cchName = strlen(pszName);
1364 if ( *pszName != '_'
1365 && ( (cchName > 4 && strcmp(&pszName[cchName - 4], "_c64") == 0)
1366 || (cchName > 5 && strcmp(&pszName[cchName - 5], "_lm64") == 0) ) )
1367 {
1368 char szCdeclName[512];
1369 if (cchName > sizeof(szCdeclName) - 2)
1370 cchName = sizeof(szCdeclName) - 2;
1371 szCdeclName[0] = '_';
1372 memcpy(&szCdeclName[1], pszName, cchName);
1373 szCdeclName[cchName + 1] = '\0';
1374 if (!omfWriter_PubDefAdd(pThis, paSymbols[iSym].st_value, szCdeclName))
1375 return false;
1376 }
1377
1378 pThis->paSymbols[iSym].idx = idxPubDef++;
1379 }
1380 if (!omfWriter_PubDefEnd(pThis))
1381 return false;
1382 }
1383 }
1384
1385 if (cAbsSyms > 0)
1386 {
1387 if (!omfWriter_PubDefBegin(pThis, 0, 0))
1388 return false;
1389 for (uint16_t iSym = 0; iSym < cSymbols; iSym++)
1390 if ( pThis->paSymbols[iSym].idxSegDef == 0
1391 && pThis->paSymbols[iSym].enmType == OMFSYMTYPE_PUBDEF)
1392 {
1393 const char *pszName = &pElfStuff->pchStrTab[paSymbols[iSym].st_name];
1394 if (!omfWriter_PubDefAdd(pThis, paSymbols[iSym].st_value, pszName))
1395 return false;
1396 pThis->paSymbols[iSym].idx = idxPubDef++;
1397 }
1398 if (!omfWriter_PubDefEnd(pThis))
1399 return false;
1400 }
1401
1402 /*
1403 * Go over the symbol table and emit external definition records.
1404 */
1405 if (!omfWriter_ExtDefBegin(pThis))
1406 return false;
1407 uint16_t idxExtDef = 1;
1408 for (uint16_t iSym = 0; iSym < cSymbols; iSym++)
1409 if (pThis->paSymbols[iSym].enmType == OMFSYMTYPE_EXTDEF)
1410 {
1411 const char *pszName = &pElfStuff->pchStrTab[paSymbols[iSym].st_name];
1412 if (!omfWriter_ExtDefAdd(pThis, pszName))
1413 return false;
1414 pThis->paSymbols[iSym].idx = idxExtDef++;
1415 }
1416
1417 if (!omfWriter_ExtDefEnd(pThis))
1418 return false;
1419
1420 return true;
1421}
1422
1423static bool convertElfSectionsToLeDataAndFixupps(POMFWRITER pThis, PCELFDETAILS pElfStuff, uint8_t const *pbFile, size_t cbFile)
1424{
1425 Elf64_Sym const *paSymbols = pElfStuff->paSymbols;
1426 Elf64_Shdr const *paShdrs = pElfStuff->paShdrs;
1427 bool fRet = true;
1428 for (uint32_t i = 1; i < pThis->cSegments; i++)
1429 {
1430 if (pThis->paSegments[i].iSegDef == UINT16_MAX)
1431 continue;
1432
1433 const char *pszSegNm = &pElfStuff->pchShStrTab[paShdrs[i].sh_name];
1434 bool const fRelocs = i + 1 < pThis->cSegments && paShdrs[i + 1].sh_type == SHT_RELA;
1435 uint32_t cRelocs = fRelocs ? paShdrs[i + 1].sh_size / sizeof(Elf64_Rela) : 0;
1436 Elf64_Rela const *paRelocs = fRelocs ? (Elf64_Rela *)&pbFile[paShdrs[i + 1].sh_offset] : NULL;
1437 Elf64_Xword cbVirtData = paShdrs[i].sh_size;
1438 Elf64_Xword cbData = paShdrs[i].sh_type == SHT_NOBITS ? 0 : cbVirtData;
1439 uint8_t const *pbData = &pbFile[paShdrs[i].sh_offset];
1440 uint32_t off = 0;
1441
1442 /* The OMF record size requires us to split larger sections up. To make
1443 life simple, we fill zeros for unitialized (BSS) stuff. */
1444 const uint32_t cbMaxData = RT_MIN(OMF_MAX_RECORD_PAYLOAD - 1 - (pThis->paSegments[i].iSegDef >= 128) - 4 - 1, _1K);
1445 while (cbVirtData > 0)
1446 {
1447 /* Figure out how many bytes to put out in this chunk. Must make sure
1448 fixups doesn't cross chunk boundraries. ASSUMES sorted relocs. */
1449 uint32_t cChunkRelocs = cRelocs;
1450 uint32_t cbChunk = cbVirtData;
1451 uint32_t offEnd = off + cbChunk;
1452 if (cbChunk > cbMaxData)
1453 {
1454 cbChunk = cbMaxData;
1455 offEnd = off + cbChunk;
1456 cChunkRelocs = 0;
1457
1458 /* Quickly determin the reloc range. */
1459 while ( cChunkRelocs < cRelocs
1460 && paRelocs[cChunkRelocs].r_offset < offEnd)
1461 cChunkRelocs++;
1462
1463 /* Ensure final reloc doesn't go beyond chunk. */
1464 while ( cChunkRelocs > 0
1465 && paRelocs[cChunkRelocs - 1].r_offset
1466 + ELF_AMD64_RELOC_SIZE(ELF64_R_TYPE(paRelocs[cChunkRelocs - 1].r_info))
1467 > offEnd)
1468 {
1469 uint32_t cbDrop = offEnd - paRelocs[cChunkRelocs - 1].r_offset;
1470 cbChunk -= cbDrop;
1471 offEnd -= cbDrop;
1472 cChunkRelocs--;
1473 }
1474
1475 if (!cbVirtData)
1476 return error(pThis->pszSrc, "Wtf? cbVirtData is zero!\n");
1477 }
1478
1479 /*
1480 * We stash the bytes into the OMF writer record buffer, receiving a
1481 * pointer to the start of it so we can make adjustments if necessary.
1482 */
1483 uint8_t *pbCopy;
1484 if (!omfWriter_LEDataBegin(pThis, pThis->paSegments[i].iSegDef, off, cbChunk, cbData, pbData, &pbCopy))
1485 return false;
1486
1487 /*
1488 * Convert fiuxps.
1489 */
1490 for (uint32_t iReloc = 0; iReloc < cChunkRelocs; iReloc++)
1491 {
1492 /* Get the OMF and ELF data for the symbol the reloc references. */
1493 uint32_t const uType = ELF64_R_TYPE(paRelocs[iReloc].r_info);
1494 uint32_t const iSymbol = ELF64_R_SYM(paRelocs[iReloc].r_info);
1495 Elf64_Sym const * const pElfSym = &paSymbols[iSymbol];
1496 POMFSYMBOL const pOmfSym = &pThis->paSymbols[iSymbol];
1497 const char * const pszSymName = &pElfStuff->pchStrTab[pElfSym->st_name];
1498
1499 /* Calc fixup location in the pending chunk and setup a flexible pointer to it. */
1500 uint16_t offDataRec = (uint16_t)(paRelocs[iReloc].r_offset - off);
1501 RTPTRUNION uLoc;
1502 uLoc.pu8 = &pbCopy[offDataRec];
1503
1504 /* OMF fixup data initialized with typical defaults. */
1505 bool fSelfRel = true;
1506 uint8_t bLocation = OMF_FIX_LOC_32BIT_OFFSET;
1507 uint8_t bFrame = OMF_FIX_F_GRPDEF;
1508 uint16_t idxFrame = pThis->idxGrpFlat;
1509 uint8_t bTarget;
1510 uint16_t idxTarget;
1511 bool fTargetDisp;
1512 uint32_t offTargetDisp;
1513 switch (pOmfSym->enmType)
1514 {
1515 case OMFSYMTYPE_INTERNAL:
1516 case OMFSYMTYPE_PUBDEF:
1517 bTarget = OMF_FIX_T_SEGDEF;
1518 idxTarget = pOmfSym->idxSegDef;
1519 fTargetDisp = true;
1520 offTargetDisp = pElfSym->st_value;
1521 break;
1522
1523 case OMFSYMTYPE_SEGDEF:
1524 bTarget = OMF_FIX_T_SEGDEF_NO_DISP;
1525 idxTarget = pOmfSym->idxSegDef;
1526 fTargetDisp = false;
1527 offTargetDisp = 0;
1528 break;
1529
1530 case OMFSYMTYPE_EXTDEF:
1531 bTarget = OMF_FIX_T_EXTDEF_NO_DISP;
1532 idxTarget = pOmfSym->idx;
1533 fTargetDisp = false;
1534 offTargetDisp = 0;
1535 break;
1536
1537 default:
1538 return error(pThis->pszSrc, "Relocation in segment #%u '%s' references ignored or invalid symbol (%s)\n",
1539 i, pszSegNm, pszSymName);
1540 }
1541
1542 /* Do COFF relocation type conversion. */
1543 switch (uType)
1544 {
1545 case R_X86_64_64:
1546 {
1547 int64_t iAddend = paRelocs[iReloc].r_addend;
1548 if (iAddend > _1G || iAddend < -_1G)
1549 fRet = error(pThis->pszSrc, "R_X86_64_64 with large addend (%" ELF_FMT_D64 ") at %#x in segment #%u '%s'\n",
1550 iAddend, paRelocs[iReloc].r_offset, i, pszSegNm);
1551 *uLoc.pu64 = iAddend;
1552 fSelfRel = false;
1553 break;
1554 }
1555
1556 case R_X86_64_32:
1557 case R_X86_64_32S: /* signed, unsigned, whatever. */
1558 fSelfRel = false;
1559 /* fall thru */
1560 case R_X86_64_PC32:
1561 {
1562 /* defaults are ok, just handle the addend. */
1563 int32_t iAddend = paRelocs[iReloc].r_addend;
1564 if (iAddend != paRelocs[iReloc].r_addend)
1565 fRet = error(pThis->pszSrc, "R_X86_64_PC32 with large addend (%d) at %#x in segment #%u '%s'\n",
1566 iAddend, paRelocs[iReloc].r_offset, i, pszSegNm);
1567 *uLoc.pu32 = iAddend;
1568 break;
1569 }
1570
1571 case R_X86_64_NONE:
1572 continue; /* Ignore this one */
1573
1574 case R_X86_64_GOT32:
1575 case R_X86_64_PLT32:
1576 case R_X86_64_COPY:
1577 case R_X86_64_GLOB_DAT:
1578 case R_X86_64_JMP_SLOT:
1579 case R_X86_64_RELATIVE:
1580 case R_X86_64_GOTPCREL:
1581 case R_X86_64_16:
1582 case R_X86_64_PC16:
1583 case R_X86_64_8:
1584 case R_X86_64_PC8:
1585 case R_X86_64_DTPMOD64:
1586 case R_X86_64_DTPOFF64:
1587 case R_X86_64_TPOFF64:
1588 case R_X86_64_TLSGD:
1589 case R_X86_64_TLSLD:
1590 case R_X86_64_DTPOFF32:
1591 case R_X86_64_GOTTPOFF:
1592 case R_X86_64_TPOFF32:
1593 default:
1594 return error(pThis->pszSrc, "Unsupported fixup type %#x (%s) at rva=%#x in section #%u '%s' against '%s'\n",
1595 uType, g_apszElfAmd64RelTypes[uType], paRelocs[iReloc].r_offset, i, pszSegNm, pszSymName);
1596 }
1597
1598 /* Add the fixup. */
1599 if (idxFrame == UINT16_MAX)
1600 error(pThis->pszSrc, "idxFrame=UINT16_MAX for %s type=%s\n", pszSymName, g_apszElfAmd64RelTypes[uType]);
1601 fRet = omfWriter_LEDataAddFixup(pThis, offDataRec, fSelfRel, bLocation, bFrame, idxFrame,
1602 bTarget, idxTarget, fTargetDisp, offTargetDisp) && fRet;
1603 }
1604
1605 /*
1606 * Write the LEDATA and associated FIXUPPs.
1607 */
1608 if (!omfWriter_LEDataEnd(pThis))
1609 return false;
1610
1611 /*
1612 * Advance.
1613 */
1614 paRelocs += cChunkRelocs;
1615 cRelocs -= cChunkRelocs;
1616 if (cbData > cbChunk)
1617 {
1618 cbData -= cbChunk;
1619 pbData += cbChunk;
1620 }
1621 else
1622 cbData = 0;
1623 off += cbChunk;
1624 cbVirtData -= cbChunk;
1625 }
1626 }
1627
1628 return fRet;
1629}
1630
1631
1632static bool convertElfToOmf(const char *pszFile, uint8_t const *pbFile, size_t cbFile, FILE *pDst)
1633{
1634 /*
1635 * Validate the source file a little.
1636 */
1637 ELFDETAILS ElfStuff;
1638 if (!validateElf(pszFile, pbFile, cbFile, &ElfStuff))
1639 return false;
1640
1641 /*
1642 * Instantiate the OMF writer.
1643 */
1644 POMFWRITER pThis = omfWriter_Create(pszFile, ElfStuff.pEhdr->e_shnum, ElfStuff.cSymbols, pDst);
1645 if (!pThis)
1646 return false;
1647
1648 /*
1649 * Write the OMF object file.
1650 */
1651 if (omfWriter_BeginModule(pThis, pszFile))
1652 {
1653 Elf64_Ehdr const *pEhdr = (Elf64_Ehdr const *)pbFile;
1654 Elf64_Shdr const *paShdrs = (Elf64_Shdr const *)&pbFile[pEhdr->e_shoff];
1655 const char *pszStrTab = (const char *)&pbFile[paShdrs[pEhdr->e_shstrndx].sh_offset];
1656
1657 if ( convertElfSectionsToSegDefsAndGrpDefs(pThis, &ElfStuff)
1658 && convertElfSymbolsToPubDefsAndExtDefs(pThis, &ElfStuff)
1659 && omfWriter_LinkPassSeparator(pThis)
1660 && convertElfSectionsToLeDataAndFixupps(pThis, &ElfStuff, pbFile, cbFile)
1661 && omfWriter_EndModule(pThis) )
1662 {
1663
1664 omfWriter_Destroy(pThis);
1665 return true;
1666 }
1667 }
1668
1669 omfWriter_Destroy(pThis);
1670 return false;
1671}
1672
1673#else /* !ELF_TO_OMF_CONVERSION */
1674
1675static bool convertelf(const char *pszFile, uint8_t *pbFile, size_t cbFile)
1676{
1677 /*
1678 * Validate the header and our other expectations.
1679 */
1680 ELFDETAILS ElfStuff;
1681 if (!validateElf(pszFile, pbFile, cbFile, &ElfStuff))
1682 return false;
1683
1684 /*
1685 * Locate the section name string table.
1686 * We assume it's okay as we only reference it in verbose mode.
1687 */
1688 Elf64_Ehdr const *pEhdr = (Elf64_Ehdr const *)pbFile;
1689 Elf64_Shdr const *paShdrs = (Elf64_Shdr const *)&pbFile[pEhdr->e_shoff];
1690 const char *pszStrTab = (const char *)&pbFile[paShdrs[pEhdr->e_shstrndx].sh_offset];
1691
1692 /*
1693 * Work the section table.
1694 */
1695 for (uint32_t i = 1; i < pEhdr->e_shnum; i++)
1696 {
1697 if (g_cVerbose)
1698 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"
1699 " link=%u info=%#x align=%#" ELF_FMT_X64 " entsize=%#" ELF_FMT_X64 "\n",
1700 i, paShdrs[i].sh_name, &pszStrTab[paShdrs[i].sh_name], paShdrs[i].sh_type, paShdrs[i].sh_flags,
1701 paShdrs[i].sh_addr, paShdrs[i].sh_offset, paShdrs[i].sh_size,
1702 paShdrs[i].sh_link, paShdrs[i].sh_info, paShdrs[i].sh_addralign, paShdrs[i].sh_entsize);
1703 if (paShdrs[i].sh_type == SHT_RELA)
1704 {
1705 Elf64_Rela *paRelocs = (Elf64_Rela *)&pbFile[paShdrs[i].sh_offset];
1706 uint32_t const cRelocs = paShdrs[i].sh_size / sizeof(Elf64_Rela);
1707 for (uint32_t j = 0; j < cRelocs; j++)
1708 {
1709 uint32_t const uType = ELF64_R_TYPE(paRelocs[j].r_info);
1710 if (g_cVerbose > 1)
1711 printf("%#018" ELF_FMT_X64 " %#018" ELF_FMT_X64 " %s %+" ELF_FMT_D64 "\n", paRelocs[j].r_offset, paRelocs[j].r_info,
1712 uType < RT_ELEMENTS(g_apszElfAmd64RelTypes) ? g_apszElfAmd64RelTypes[uType] : "unknown", paRelocs[j].r_addend);
1713
1714 /* Truncate 64-bit wide absolute relocations, ASSUMING that the high bits
1715 are already zero and won't be non-zero after calculating the fixup value. */
1716 if (uType == R_X86_64_64)
1717 {
1718 paRelocs[j].r_info &= ~(uint64_t)0xff;
1719 paRelocs[j].r_info |= R_X86_64_32;
1720 }
1721 }
1722 }
1723 else if (paShdrs[i].sh_type == SHT_REL)
1724 return error(pszFile, "Did not expect SHT_REL sections (#%u '%s')\n", i, &pszStrTab[paShdrs[i].sh_name]);
1725 }
1726 return true;
1727}
1728
1729#endif /* !ELF_TO_OMF_CONVERSION */
1730
1731
1732
1733
1734/*********************************************************************************************************************************
1735* COFF -> OMF Converter *
1736*********************************************************************************************************************************/
1737
1738/** AMD64 relocation type names for (Microsoft) COFF. */
1739static const char * const g_apszCoffAmd64RelTypes[] =
1740{
1741 "ABSOLUTE",
1742 "ADDR64",
1743 "ADDR32",
1744 "ADDR32NB",
1745 "REL32",
1746 "REL32_1",
1747 "REL32_2",
1748 "REL32_3",
1749 "REL32_4",
1750 "REL32_5",
1751 "SECTION",
1752 "SECREL",
1753 "SECREL7",
1754 "TOKEN",
1755 "SREL32",
1756 "PAIR",
1757 "SSPAN32"
1758};
1759
1760/** AMD64 relocation type sizes for (Microsoft) COFF. */
1761static uint8_t const g_acbCoffAmd64RelTypes[] =
1762{
1763 8, /* ABSOLUTE */
1764 8, /* ADDR64 */
1765 4, /* ADDR32 */
1766 4, /* ADDR32NB */
1767 4, /* REL32 */
1768 4, /* REL32_1 */
1769 4, /* REL32_2 */
1770 4, /* REL32_3 */
1771 4, /* REL32_4 */
1772 4, /* REL32_5 */
1773 2, /* SECTION */
1774 4, /* SECREL */
1775 1, /* SECREL7 */
1776 0, /* TOKEN */
1777 4, /* SREL32 */
1778 0, /* PAIR */
1779 4, /* SSPAN32 */
1780};
1781
1782/** Macro for getting the size of a AMD64 COFF relocation. */
1783#define COFF_AMD64_RELOC_SIZE(a_Type) ( (a_Type) < RT_ELEMENTS(g_acbCoffAmd64RelTypes) ? g_acbCoffAmd64RelTypes[(a_Type)] : 1)
1784
1785
1786static const char *coffGetSymbolName(PCIMAGE_SYMBOL pSym, const char *pchStrTab, uint32_t cbStrTab, char pszShortName[16])
1787{
1788 if (pSym->N.Name.Short != 0)
1789 {
1790 memcpy(pszShortName, pSym->N.ShortName, 8);
1791 pszShortName[8] = '\0';
1792 return pszShortName;
1793 }
1794 if (pSym->N.Name.Long < cbStrTab)
1795 {
1796 uint32_t const cbLeft = cbStrTab - pSym->N.Name.Long;
1797 const char *pszRet = pchStrTab + pSym->N.Name.Long;
1798 if (memchr(pszRet, '\0', cbLeft) != NULL)
1799 return pszRet;
1800 }
1801 error("<null>", "Invalid string table index %#x!\n", pSym->N.Name.Long);
1802 return "Invalid Symbol Table Entry";
1803}
1804
1805static bool validateCoff(const char *pszFile, uint8_t const *pbFile, size_t cbFile)
1806{
1807 /*
1808 * Validate the header and our other expectations.
1809 */
1810 PIMAGE_FILE_HEADER pHdr = (PIMAGE_FILE_HEADER)pbFile;
1811 if (pHdr->Machine != IMAGE_FILE_MACHINE_AMD64)
1812 return error(pszFile, "Expected IMAGE_FILE_MACHINE_AMD64 not %#x\n", pHdr->Machine);
1813 if (pHdr->SizeOfOptionalHeader != 0)
1814 return error(pszFile, "Expected SizeOfOptionalHeader to be zero, not %#x\n", pHdr->SizeOfOptionalHeader);
1815 if (pHdr->NumberOfSections == 0)
1816 return error(pszFile, "Expected NumberOfSections to be non-zero\n");
1817 uint32_t const cbHeaders = pHdr->NumberOfSections * sizeof(IMAGE_SECTION_HEADER) + sizeof(*pHdr);
1818 if (cbHeaders > cbFile)
1819 return error(pszFile, "Section table goes beyond the end of the of the file (cSections=%#x)\n", pHdr->NumberOfSections);
1820 if (pHdr->NumberOfSymbols)
1821 {
1822 if ( pHdr->PointerToSymbolTable >= cbFile
1823 || pHdr->NumberOfSymbols * (uint64_t)IMAGE_SIZE_OF_SYMBOL > cbFile)
1824 return error(pszFile, "Symbol table goes beyond the end of the of the file (cSyms=%#x, offFile=%#x)\n",
1825 pHdr->NumberOfSymbols, pHdr->PointerToSymbolTable);
1826 }
1827
1828 return true;
1829}
1830
1831
1832static bool convertCoffSectionsToSegDefsAndGrpDefs(POMFWRITER pThis, PCIMAGE_SECTION_HEADER paShdrs, uint16_t cSections)
1833{
1834 /*
1835 * Do the list of names pass.
1836 */
1837 uint16_t idxGrpFlat, idxGrpData;
1838 uint16_t idxClassCode, idxClassData, idxClassDebugSymbols, idxClassDebugTypes;
1839 if ( !omfWriter_LNamesBegin(pThis)
1840 || !omfWriter_LNamesAddN(pThis, RT_STR_TUPLE("FLAT"), &idxGrpFlat)
1841 || !omfWriter_LNamesAddN(pThis, RT_STR_TUPLE("BS3DATA64_GROUP"), &idxGrpData)
1842 || !omfWriter_LNamesAddN(pThis, RT_STR_TUPLE("BS3CLASS64CODE"), &idxClassCode)
1843 || !omfWriter_LNamesAddN(pThis, RT_STR_TUPLE("FAR_DATA"), &idxClassData)
1844 || !omfWriter_LNamesAddN(pThis, RT_STR_TUPLE("DEBSYM"), &idxClassDebugSymbols)
1845 || !omfWriter_LNamesAddN(pThis, RT_STR_TUPLE("DEBTYP"), &idxClassDebugTypes)
1846 )
1847 return false;
1848
1849 bool fHaveData = false;
1850 for (uint16_t i = 0; i < cSections; i++)
1851 {
1852 /* Copy the name and terminate it. */
1853 char szName[32];
1854 memcpy(szName, paShdrs[i].Name, sizeof(paShdrs[i].Name));
1855 unsigned cchName = sizeof(paShdrs[i].Name);
1856 while (cchName > 0 && RT_C_IS_SPACE(szName[cchName - 1]))
1857 cchName--;
1858 if (cchName == 0)
1859 return error(pThis->pszSrc, "Section #%u has an empty name!\n", i);
1860 szName[cchName] = '\0';
1861
1862 if ( (paShdrs[i].Characteristics & (IMAGE_SCN_LNK_REMOVE | IMAGE_SCN_LNK_INFO))
1863 || strcmp(szName, ".pdata") == 0 /* Exception stuff, I think, so discard it. */
1864 || strcmp(szName, ".xdata") == 0 /* Ditto. */ )
1865 {
1866 pThis->paSegments[i].iSegDef = UINT16_MAX;
1867 pThis->paSegments[i].iGrpDef = UINT16_MAX;
1868 pThis->paSegments[i].iSegNm = UINT16_MAX;
1869 pThis->paSegments[i].iGrpNm = UINT16_MAX;
1870 pThis->paSegments[i].iClassNm = UINT16_MAX;
1871 pThis->paSegments[i].pszName = NULL;
1872 }
1873 else
1874 {
1875 /* Translate the name, group and class. */
1876 if (strcmp(szName, ".text") == 0)
1877 {
1878 strcpy(szName, "BS3TEXT64");
1879 pThis->paSegments[i].iGrpNm = idxGrpFlat;
1880 pThis->paSegments[i].iClassNm = idxClassCode;
1881 }
1882 else if (strcmp(szName, ".data") == 0)
1883 {
1884 strcpy(szName, "BS3DATA64");
1885 pThis->paSegments[i].iGrpNm = idxGrpData;
1886 pThis->paSegments[i].iClassNm = idxClassData;
1887 }
1888 else if (strcmp(szName, ".bss") == 0)
1889 {
1890 strcpy(szName, "BS3BSS64");
1891 pThis->paSegments[i].iGrpNm = idxGrpData;
1892 pThis->paSegments[i].iClassNm = idxClassData;
1893 }
1894 else if (strcmp(szName, ".rdata") == 0)
1895 {
1896 strcpy(szName, "BS3DATA64CONST");
1897 pThis->paSegments[i].iGrpNm = idxGrpData;
1898 pThis->paSegments[i].iClassNm = idxClassData;
1899 }
1900 else if (strcmp(szName, ".debug$S") == 0)
1901 {
1902 strcpy(szName, "$$SYMBOLS");
1903 pThis->paSegments[i].iGrpNm = UINT16_MAX;
1904 pThis->paSegments[i].iClassNm = idxClassDebugSymbols;
1905 }
1906 else if (strcmp(szName, ".debug$T") == 0)
1907 {
1908 strcpy(szName, "$$TYPES");
1909 pThis->paSegments[i].iGrpNm = UINT16_MAX;
1910 pThis->paSegments[i].iClassNm = idxClassDebugTypes;
1911 }
1912 else if (paShdrs[i].Characteristics & (IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_CNT_CODE))
1913 {
1914 pThis->paSegments[i].iGrpNm = idxGrpFlat;
1915 pThis->paSegments[i].iClassNm = idxClassCode;
1916 error(pThis->pszSrc, "Unknown code segment: '%s'\n", szName);
1917 }
1918 else
1919 {
1920 pThis->paSegments[i].iGrpNm = idxGrpData;
1921 pThis->paSegments[i].iClassNm = idxClassData;
1922 error(pThis->pszSrc, "Unknown data (?) segment: '%s'\n", szName);
1923 }
1924
1925 /* Save the name. */
1926 pThis->paSegments[i].pszName = strdup(szName);
1927 if (!pThis->paSegments[i].pszName)
1928 return error(pThis->pszSrc, "Out of memory!\n");
1929
1930 /* Add the section name. */
1931 if (!omfWriter_LNamesAdd(pThis, pThis->paSegments[i].pszName, &pThis->paSegments[i].iSegNm))
1932 return false;
1933
1934 fHaveData |= pThis->paSegments[i].iGrpDef == idxGrpData;
1935 }
1936 }
1937
1938 if (!omfWriter_LNamesEnd(pThis))
1939 return false;
1940
1941 /*
1942 * Emit segment definitions.
1943 */
1944 uint16_t iSegDef = 1; /* Start counting at 1. */
1945 for (uint16_t i = 0; i < cSections; i++)
1946 {
1947 if (pThis->paSegments[i].iSegDef == UINT16_MAX)
1948 continue;
1949
1950 uint8_t bSegAttr = 0;
1951
1952 /* The A field. */
1953 switch (paShdrs[i].Characteristics & IMAGE_SCN_ALIGN_MASK)
1954 {
1955 default:
1956 case IMAGE_SCN_ALIGN_1BYTES:
1957 bSegAttr |= 1 << 5;
1958 break;
1959 case IMAGE_SCN_ALIGN_2BYTES:
1960 bSegAttr |= 2 << 5;
1961 break;
1962 case IMAGE_SCN_ALIGN_4BYTES:
1963 bSegAttr |= 5 << 5;
1964 break;
1965 case IMAGE_SCN_ALIGN_8BYTES:
1966 case IMAGE_SCN_ALIGN_16BYTES:
1967 bSegAttr |= 3 << 5;
1968 break;
1969 case IMAGE_SCN_ALIGN_32BYTES:
1970 case IMAGE_SCN_ALIGN_64BYTES:
1971 case IMAGE_SCN_ALIGN_128BYTES:
1972 case IMAGE_SCN_ALIGN_256BYTES:
1973 bSegAttr |= 4 << 5;
1974 break;
1975 case IMAGE_SCN_ALIGN_512BYTES:
1976 case IMAGE_SCN_ALIGN_1024BYTES:
1977 case IMAGE_SCN_ALIGN_2048BYTES:
1978 case IMAGE_SCN_ALIGN_4096BYTES:
1979 case IMAGE_SCN_ALIGN_8192BYTES:
1980 bSegAttr |= 6 << 5; /* page aligned, pharlabs extension. */
1981 break;
1982 }
1983
1984 /* The C field. */
1985 bSegAttr |= 2 << 2; /* public */
1986
1987 /* The B field. We don't have 4GB segments, so leave it as zero. */
1988
1989 /* The D field shall be set as we're doing USE32. */
1990 bSegAttr |= 1;
1991
1992
1993 /* Done. */
1994 if (!omfWriter_SegDef(pThis, bSegAttr, paShdrs[i].SizeOfRawData,
1995 pThis->paSegments[i].iSegNm,
1996 pThis->paSegments[i].iClassNm))
1997 return false;
1998 pThis->paSegments[i].iSegDef = iSegDef++;
1999 }
2000
2001 /*
2002 * Flat group definition (#1) - special, no members.
2003 */
2004 uint16_t iGrpDef = 1;
2005 if ( !omfWriter_GrpDefBegin(pThis, idxGrpFlat)
2006 || !omfWriter_GrpDefEnd(pThis))
2007 return false;
2008 for (uint16_t i = 0; i < cSections; i++)
2009 if (pThis->paSegments[i].iGrpNm == idxGrpFlat)
2010 pThis->paSegments[i].iGrpDef = iGrpDef;
2011 pThis->idxGrpFlat = iGrpDef++;
2012
2013 /*
2014 * Data group definition (#2).
2015 */
2016 /** @todo do we need to consider missing segments and ordering? */
2017 uint16_t cGrpNms = 0;
2018 uint16_t aiGrpNms[2];
2019 if (fHaveData)
2020 aiGrpNms[cGrpNms++] = idxGrpData;
2021 for (uint32_t iGrpNm = 0; iGrpNm < cGrpNms; iGrpNm++)
2022 {
2023 if (!omfWriter_GrpDefBegin(pThis, aiGrpNms[iGrpNm]))
2024 return false;
2025 for (uint16_t i = 0; i < cSections; i++)
2026 if (pThis->paSegments[i].iGrpNm == aiGrpNms[iGrpNm])
2027 {
2028 pThis->paSegments[i].iGrpDef = iGrpDef;
2029 if (!omfWriter_GrpDefAddSegDef(pThis, pThis->paSegments[i].iSegDef))
2030 return false;
2031 }
2032 if (!omfWriter_GrpDefEnd(pThis))
2033 return false;
2034 iGrpDef++;
2035 }
2036
2037 return true;
2038}
2039
2040/**
2041 * This is for matching STATIC symbols with value 0 against the section name,
2042 * to see if it's a section reference or symbol at offset 0 reference.
2043 *
2044 * @returns true / false.
2045 * @param pszSymbol The symbol name.
2046 * @param pachSectName8 The section name (8-bytes).
2047 */
2048static bool isCoffSymbolMatchingSectionName(const char *pszSymbol, uint8_t const pachSectName8[8])
2049{
2050 uint32_t off = 0;
2051 char ch;
2052 while (off < 8 && (ch = pszSymbol[off]) != '\0')
2053 {
2054 if (ch != pachSectName8[off])
2055 return false;
2056 off++;
2057 }
2058 while (off < 8)
2059 {
2060 if (!RT_C_IS_SPACE((ch = pachSectName8[off])))
2061 return ch == '\0';
2062 off++;
2063 }
2064 return true;
2065}
2066
2067static bool convertCoffSymbolsToPubDefsAndExtDefs(POMFWRITER pThis, PCIMAGE_SYMBOL paSymbols, uint16_t cSymbols,
2068 const char *pchStrTab, PCIMAGE_SECTION_HEADER paShdrs)
2069{
2070
2071 if (!cSymbols)
2072 return true;
2073 uint32_t const cbStrTab = *(uint32_t const *)pchStrTab;
2074 char szShort[16];
2075
2076 /*
2077 * Process the symbols the first.
2078 */
2079 uint32_t iSymImageBase = UINT32_MAX;
2080 uint32_t cAbsSyms = 0;
2081 uint32_t cExtSyms = 0;
2082 uint32_t cPubSyms = 0;
2083 for (uint32_t iSeg = 0; iSeg < pThis->cSegments; iSeg++)
2084 pThis->paSegments[iSeg].cPubDefs = 0;
2085
2086 for (uint16_t iSym = 0; iSym < cSymbols; iSym++)
2087 {
2088 const char *pszSymName = coffGetSymbolName(&paSymbols[iSym], pchStrTab, cbStrTab, szShort);
2089
2090 pThis->paSymbols[iSym].enmType = OMFSYMTYPE_IGNORED;
2091 pThis->paSymbols[iSym].idx = UINT16_MAX;
2092 pThis->paSymbols[iSym].idxSegDef = UINT16_MAX;
2093 pThis->paSymbols[iSym].idxGrpDef = UINT16_MAX;
2094
2095 int16_t const idxSection = paSymbols[iSym].SectionNumber;
2096 if ( (idxSection >= 1 && idxSection <= (int32_t)pThis->cSegments)
2097 || idxSection == IMAGE_SYM_ABSOLUTE)
2098 {
2099 switch (paSymbols[iSym].StorageClass)
2100 {
2101 case IMAGE_SYM_CLASS_EXTERNAL:
2102 if (idxSection != IMAGE_SYM_ABSOLUTE)
2103 {
2104 if (pThis->paSegments[idxSection - 1].iSegDef != UINT16_MAX)
2105 {
2106 pThis->paSymbols[iSym].enmType = OMFSYMTYPE_PUBDEF;
2107 pThis->paSymbols[iSym].idxSegDef = pThis->paSegments[idxSection - 1].iSegDef;
2108 pThis->paSymbols[iSym].idxGrpDef = pThis->paSegments[idxSection - 1].iGrpDef;
2109 pThis->paSegments[idxSection - 1].cPubDefs++;
2110 cPubSyms++;
2111 }
2112 }
2113 else
2114 {
2115 pThis->paSymbols[iSym].enmType = OMFSYMTYPE_PUBDEF;
2116 pThis->paSymbols[iSym].idxSegDef = 0;
2117 pThis->paSymbols[iSym].idxGrpDef = 0;
2118 cAbsSyms++;
2119 }
2120 break;
2121
2122 case IMAGE_SYM_CLASS_STATIC:
2123 if ( paSymbols[iSym].Value == 0
2124 && idxSection != IMAGE_SYM_ABSOLUTE
2125 && isCoffSymbolMatchingSectionName(pszSymName, paShdrs[idxSection - 1].Name) )
2126 {
2127 pThis->paSymbols[iSym].enmType = OMFSYMTYPE_SEGDEF;
2128 pThis->paSymbols[iSym].idxSegDef = pThis->paSegments[idxSection - 1].iSegDef;
2129 pThis->paSymbols[iSym].idxGrpDef = pThis->paSegments[idxSection - 1].iGrpDef;
2130 break;
2131 }
2132 /* fall thru */
2133
2134 case IMAGE_SYM_CLASS_END_OF_FUNCTION:
2135 case IMAGE_SYM_CLASS_AUTOMATIC:
2136 case IMAGE_SYM_CLASS_REGISTER:
2137 case IMAGE_SYM_CLASS_LABEL:
2138 case IMAGE_SYM_CLASS_MEMBER_OF_STRUCT:
2139 case IMAGE_SYM_CLASS_ARGUMENT:
2140 case IMAGE_SYM_CLASS_STRUCT_TAG:
2141 case IMAGE_SYM_CLASS_MEMBER_OF_UNION:
2142 case IMAGE_SYM_CLASS_UNION_TAG:
2143 case IMAGE_SYM_CLASS_TYPE_DEFINITION:
2144 case IMAGE_SYM_CLASS_ENUM_TAG:
2145 case IMAGE_SYM_CLASS_MEMBER_OF_ENUM:
2146 case IMAGE_SYM_CLASS_REGISTER_PARAM:
2147 case IMAGE_SYM_CLASS_BIT_FIELD:
2148 case IMAGE_SYM_CLASS_BLOCK:
2149 case IMAGE_SYM_CLASS_FUNCTION:
2150 case IMAGE_SYM_CLASS_END_OF_STRUCT:
2151 case IMAGE_SYM_CLASS_FILE:
2152 pThis->paSymbols[iSym].enmType = OMFSYMTYPE_INTERNAL;
2153 if (idxSection != IMAGE_SYM_ABSOLUTE)
2154 {
2155 pThis->paSymbols[iSym].idxSegDef = pThis->paSegments[idxSection - 1].iSegDef;
2156 pThis->paSymbols[iSym].idxGrpDef = pThis->paSegments[idxSection - 1].iGrpDef;
2157 }
2158 else
2159 {
2160 pThis->paSymbols[iSym].idxSegDef = 0;
2161 pThis->paSymbols[iSym].idxGrpDef = 0;
2162 }
2163 break;
2164
2165 case IMAGE_SYM_CLASS_SECTION:
2166 case IMAGE_SYM_CLASS_EXTERNAL_DEF:
2167 case IMAGE_SYM_CLASS_NULL:
2168 case IMAGE_SYM_CLASS_UNDEFINED_LABEL:
2169 case IMAGE_SYM_CLASS_UNDEFINED_STATIC:
2170 case IMAGE_SYM_CLASS_CLR_TOKEN:
2171 case IMAGE_SYM_CLASS_FAR_EXTERNAL:
2172 case IMAGE_SYM_CLASS_WEAK_EXTERNAL:
2173 return error(pThis->pszSrc, "Unsupported storage class value %#x for symbol #%u (%s)\n",
2174 paSymbols[iSym].StorageClass, iSym, pszSymName);
2175
2176 default:
2177 return error(pThis->pszSrc, "Unknown storage class value %#x for symbol #%u (%s)\n",
2178 paSymbols[iSym].StorageClass, iSym, pszSymName);
2179 }
2180 }
2181 else if (idxSection == IMAGE_SYM_UNDEFINED)
2182 {
2183 if ( paSymbols[iSym].StorageClass == IMAGE_SYM_CLASS_EXTERNAL
2184 || paSymbols[iSym].StorageClass == IMAGE_SYM_CLASS_EXTERNAL_DEF)
2185 {
2186 pThis->paSymbols[iSym].enmType = OMFSYMTYPE_EXTDEF;
2187 cExtSyms++;
2188 if (iSymImageBase == UINT32_MAX && strcmp(pszSymName, "__ImageBase") == 0)
2189 iSymImageBase = iSym;
2190 }
2191 else
2192 return error(pThis->pszSrc, "Unknown/unknown storage class value %#x for undefined symbol #%u (%s)\n",
2193 paSymbols[iSym].StorageClass, iSym, pszSymName);
2194 }
2195 else if (idxSection != IMAGE_SYM_DEBUG)
2196 return error(pThis->pszSrc, "Invalid section number %#x for symbol #%u (%s)\n", idxSection, iSym, pszSymName);
2197
2198 /* Skip AUX symbols. */
2199 uint8_t cAuxSyms = paSymbols[iSym].NumberOfAuxSymbols;
2200 while (cAuxSyms-- > 0)
2201 {
2202 iSym++;
2203 pThis->paSymbols[iSym].enmType = OMFSYMTYPE_INVALID;
2204 pThis->paSymbols[iSym].idx = UINT16_MAX;
2205 }
2206 }
2207
2208 /*
2209 * Emit the PUBDEFs the first time around (see order of records in TIS spec).
2210 */
2211 uint16_t idxPubDef = 1;
2212 if (cPubSyms)
2213 {
2214 for (uint32_t iSeg = 0; iSeg < pThis->cSegments; iSeg++)
2215 if (pThis->paSegments[iSeg].cPubDefs > 0)
2216 {
2217 uint16_t const idxSegDef = pThis->paSegments[iSeg].iSegDef;
2218 if (!omfWriter_PubDefBegin(pThis, pThis->paSegments[iSeg].iGrpDef, idxSegDef))
2219 return false;
2220 for (uint16_t iSym = 0; iSym < cSymbols; iSym++)
2221 if ( pThis->paSymbols[iSym].idxSegDef == idxSegDef
2222 && pThis->paSymbols[iSym].enmType == OMFSYMTYPE_PUBDEF)
2223 {
2224 const char *pszName = coffGetSymbolName(&paSymbols[iSym], pchStrTab, cbStrTab, szShort);
2225 if (!omfWriter_PubDefAdd(pThis, paSymbols[iSym].Value, pszName))
2226 return false;
2227
2228 /* If the symbol doesn't start with an underscore and is a _c64 or _lm64 symbol,
2229 add an underscore prefixed alias to ease access from 16-bit and 32-bit code. */
2230 size_t cchName = strlen(pszName);
2231 if ( *pszName != '_'
2232 && ( (cchName > 4 && strcmp(&pszName[cchName - 4], "_c64") == 0)
2233 || (cchName > 5 && strcmp(&pszName[cchName - 5], "_lm64") == 0) ) )
2234 {
2235 char szCdeclName[512];
2236 if (cchName > sizeof(szCdeclName) - 2)
2237 cchName = sizeof(szCdeclName) - 2;
2238 szCdeclName[0] = '_';
2239 memcpy(&szCdeclName[1], pszName, cchName);
2240 szCdeclName[cchName + 1] = '\0';
2241 if (!omfWriter_PubDefAdd(pThis, paSymbols[iSym].Value, szCdeclName))
2242 return false;
2243 }
2244
2245 pThis->paSymbols[iSym].idx = idxPubDef++;
2246 }
2247 if (!omfWriter_PubDefEnd(pThis))
2248 return false;
2249 }
2250 }
2251
2252 if (cAbsSyms > 0)
2253 {
2254 if (!omfWriter_PubDefBegin(pThis, 0, 0))
2255 return false;
2256 for (uint16_t iSym = 0; iSym < cSymbols; iSym++)
2257 if ( pThis->paSymbols[iSym].idxSegDef == 0
2258 && pThis->paSymbols[iSym].enmType == OMFSYMTYPE_PUBDEF)
2259 {
2260 if (!omfWriter_PubDefAdd(pThis, paSymbols[iSym].Value,
2261 coffGetSymbolName(&paSymbols[iSym], pchStrTab, cbStrTab, szShort)) )
2262 return false;
2263 pThis->paSymbols[iSym].idx = idxPubDef++;
2264 }
2265 if (!omfWriter_PubDefEnd(pThis))
2266 return false;
2267 }
2268
2269 /*
2270 * Go over the symbol table and emit external definition records.
2271 */
2272 if (!omfWriter_ExtDefBegin(pThis))
2273 return false;
2274 uint16_t idxExtDef = 1;
2275 for (uint16_t iSym = 0; iSym < cSymbols; iSym++)
2276 if (pThis->paSymbols[iSym].enmType == OMFSYMTYPE_EXTDEF)
2277 {
2278 if (!omfWriter_ExtDefAdd(pThis, coffGetSymbolName(&paSymbols[iSym], pchStrTab, cbStrTab, szShort)))
2279 return false;
2280 pThis->paSymbols[iSym].idx = idxExtDef++;
2281 }
2282
2283 /* Always add an __ImageBase reference, in case we need it to deal with ADDR32NB fixups. */
2284 /** @todo maybe we don't actually need this and could use FLAT instead? */
2285 if (iSymImageBase != UINT32_MAX)
2286 pThis->idxExtImageBase = pThis->paSymbols[iSymImageBase].idx;
2287 else if (omfWriter_ExtDefAdd(pThis, "__ImageBase"))
2288 pThis->idxExtImageBase = idxExtDef;
2289 else
2290 return false;
2291
2292 if (!omfWriter_ExtDefEnd(pThis))
2293 return false;
2294
2295 return true;
2296}
2297
2298
2299static bool convertCoffSectionsToLeDataAndFixupps(POMFWRITER pThis, uint8_t const *pbFile, size_t cbFile,
2300 PCIMAGE_SECTION_HEADER paShdrs, uint16_t cSections,
2301 PCIMAGE_SYMBOL paSymbols, uint16_t cSymbols, const char *pchStrTab)
2302{
2303 uint32_t const cbStrTab = *(uint32_t const *)pchStrTab;
2304 bool fRet = true;
2305 for (uint32_t i = 0; i < pThis->cSegments; i++)
2306 {
2307 if (pThis->paSegments[i].iSegDef == UINT16_MAX)
2308 continue;
2309
2310 char szShortName[16];
2311 const char *pszSegNm = pThis->paSegments[i].pszName;
2312 uint16_t cRelocs = paShdrs[i].NumberOfRelocations;
2313 PCIMAGE_RELOCATION paRelocs = (PCIMAGE_RELOCATION)&pbFile[paShdrs[i].PointerToRelocations];
2314 uint32_t cbVirtData = paShdrs[i].SizeOfRawData;
2315 uint32_t cbData = paShdrs[i].Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA ? 0 : cbVirtData;
2316 uint8_t const *pbData = &pbFile[paShdrs[i].PointerToRawData];
2317 uint32_t off = 0;
2318
2319 /* Check that the relocations are sorted and within the section. */
2320 for (uint32_t iReloc = 1; iReloc < cRelocs; iReloc++)
2321 if (paRelocs[iReloc - 1].u.VirtualAddress >= paRelocs[iReloc].u.VirtualAddress)
2322 return error(pThis->pszSrc, "Section #%u (%s) relocations aren't sorted\n", i, pszSegNm);
2323 if ( cRelocs > 0
2324 && paRelocs[cRelocs - 1].u.VirtualAddress - paShdrs[i].VirtualAddress
2325 + COFF_AMD64_RELOC_SIZE(paRelocs[cRelocs - 1].Type) > cbVirtData)
2326 return error(pThis->pszSrc,
2327 "Section #%u (%s) relocations beyond section data! cbVirtData=%#x RvaFix=%#x RVASeg=%#x type=%#x\n",
2328 i, pszSegNm, cbVirtData, paRelocs[cRelocs - 1].u.VirtualAddress, paShdrs[i].VirtualAddress,
2329 paRelocs[cRelocs - 1].Type);
2330
2331 /* The OMF record size requires us to split larger sections up. To make
2332 life simple, we fill zeros for unitialized (BSS) stuff. */
2333 const uint32_t cbMaxData = RT_MIN(OMF_MAX_RECORD_PAYLOAD - 1 - (pThis->paSegments[i].iSegDef >= 128) - 4 - 1, _1K);
2334 while (cbVirtData > 0)
2335 {
2336 /* Figure out how many bytes to put out in this chunk. Must make sure
2337 fixups doesn't cross chunk boundraries. ASSUMES sorted relocs. */
2338 uint32_t cChunkRelocs = cRelocs;
2339 uint32_t cbChunk = cbVirtData;
2340 uint32_t uRvaEnd = paShdrs[i].VirtualAddress + off + cbChunk;
2341 if (cbChunk > cbMaxData)
2342 {
2343 cbChunk = cbMaxData;
2344 uRvaEnd = paShdrs[i].VirtualAddress + off + cbChunk;
2345 cChunkRelocs = 0;
2346
2347 /* Quickly determin the reloc range. */
2348 while ( cChunkRelocs < cRelocs
2349 && paRelocs[cChunkRelocs].u.VirtualAddress < uRvaEnd)
2350 cChunkRelocs++;
2351
2352 /* Ensure final reloc doesn't go beyond chunk. */
2353 while ( cChunkRelocs > 0
2354 && paRelocs[cChunkRelocs - 1].u.VirtualAddress + COFF_AMD64_RELOC_SIZE(paRelocs[cChunkRelocs - 1].Type)
2355 > uRvaEnd)
2356 {
2357 uint32_t cbDrop = uRvaEnd - paRelocs[cChunkRelocs - 1].u.VirtualAddress;
2358 cbChunk -= cbDrop;
2359 uRvaEnd -= cbDrop;
2360 cChunkRelocs--;
2361 }
2362
2363 if (!cbVirtData)
2364 return error(pThis->pszSrc, "Wtf? cbVirtData is zero!\n");
2365 }
2366
2367 /*
2368 * We stash the bytes into the OMF writer record buffer, receiving a
2369 * pointer to the start of it so we can make adjustments if necessary.
2370 */
2371 uint8_t *pbCopy;
2372 if (!omfWriter_LEDataBegin(pThis, pThis->paSegments[i].iSegDef, off, cbChunk, cbData, pbData, &pbCopy))
2373 return false;
2374
2375 /*
2376 * Convert fiuxps.
2377 */
2378 uint32_t const uRvaChunk = paShdrs[i].VirtualAddress + off;
2379 for (uint32_t iReloc = 0; iReloc < cChunkRelocs; iReloc++)
2380 {
2381 /* Get the OMF and COFF data for the symbol the reloc references. */
2382 if (paRelocs[iReloc].SymbolTableIndex >= pThis->cSymbols)
2383 return error(pThis->pszSrc, "Relocation symtab index (%#x) is out of range in segment #%u '%s'\n",
2384 paRelocs[iReloc].SymbolTableIndex, i, pszSegNm);
2385 PCIMAGE_SYMBOL pCoffSym = &paSymbols[paRelocs[iReloc].SymbolTableIndex];
2386 POMFSYMBOL pOmfSym = &pThis->paSymbols[paRelocs[iReloc].SymbolTableIndex];
2387
2388 /* Calc fixup location in the pending chunk and setup a flexible pointer to it. */
2389 uint16_t offDataRec = (uint16_t)(paRelocs[iReloc].u.VirtualAddress - uRvaChunk);
2390 RTPTRUNION uLoc;
2391 uLoc.pu8 = &pbCopy[offDataRec];
2392
2393 /* OMF fixup data initialized with typical defaults. */
2394 bool fSelfRel = true;
2395 uint8_t bLocation = OMF_FIX_LOC_32BIT_OFFSET;
2396 uint8_t bFrame = OMF_FIX_F_GRPDEF;
2397 uint16_t idxFrame = pThis->idxGrpFlat;
2398 uint8_t bTarget;
2399 uint16_t idxTarget;
2400 bool fTargetDisp;
2401 uint32_t offTargetDisp;
2402 switch (pOmfSym->enmType)
2403 {
2404 case OMFSYMTYPE_INTERNAL:
2405 case OMFSYMTYPE_PUBDEF:
2406 bTarget = OMF_FIX_T_SEGDEF;
2407 idxTarget = pOmfSym->idxSegDef;
2408 fTargetDisp = true;
2409 offTargetDisp = pCoffSym->Value;
2410 break;
2411
2412 case OMFSYMTYPE_SEGDEF:
2413 bTarget = OMF_FIX_T_SEGDEF_NO_DISP;
2414 idxTarget = pOmfSym->idxSegDef;
2415 fTargetDisp = false;
2416 offTargetDisp = 0;
2417 break;
2418
2419 case OMFSYMTYPE_EXTDEF:
2420 bTarget = OMF_FIX_T_EXTDEF_NO_DISP;
2421 idxTarget = pOmfSym->idx;
2422 fTargetDisp = false;
2423 offTargetDisp = 0;
2424 break;
2425
2426 default:
2427 return error(pThis->pszSrc, "Relocation in segment #%u '%s' references ignored or invalid symbol (%s)\n",
2428 i, pszSegNm, coffGetSymbolName(pCoffSym, pchStrTab, cbStrTab, szShortName));
2429 }
2430
2431 /* Do COFF relocation type conversion. */
2432 switch (paRelocs[iReloc].Type)
2433 {
2434 case IMAGE_REL_AMD64_ADDR64:
2435 {
2436 uint64_t uAddend = *uLoc.pu64;
2437 if (uAddend > _1G)
2438 fRet = error(pThis->pszSrc, "ADDR64 with large addend (%#llx) at %#x in segment #%u '%s'\n",
2439 uAddend, paRelocs[iReloc].u.VirtualAddress, i, pszSegNm);
2440 fSelfRel = false;
2441 break;
2442 }
2443
2444 case IMAGE_REL_AMD64_REL32_1:
2445 case IMAGE_REL_AMD64_REL32_2:
2446 case IMAGE_REL_AMD64_REL32_3:
2447 case IMAGE_REL_AMD64_REL32_4:
2448 case IMAGE_REL_AMD64_REL32_5:
2449 /** @todo Check whether OMF read addends from the data or relies on the
2450 * displacement. Also, check what it's relative to. */
2451 *uLoc.pu32 += paRelocs[iReloc].Type - IMAGE_REL_AMD64_REL32;
2452 break;
2453
2454 case IMAGE_REL_AMD64_ADDR32:
2455 fSelfRel = false;
2456 break;
2457
2458 case IMAGE_REL_AMD64_ADDR32NB:
2459 fSelfRel = false;
2460 bFrame = OMF_FIX_F_EXTDEF;
2461 idxFrame = pThis->idxExtImageBase;
2462 break;
2463
2464 case IMAGE_REL_AMD64_REL32:
2465 /* defaults are ok. */
2466 break;
2467
2468 case IMAGE_REL_AMD64_SECTION:
2469 bLocation = OMF_FIX_LOC_16BIT_SEGMENT;
2470 /* fall thru */
2471
2472 case IMAGE_REL_AMD64_SECREL:
2473 fSelfRel = false;
2474 if (pOmfSym->enmType == OMFSYMTYPE_EXTDEF)
2475 {
2476 bFrame = OMF_FIX_F_EXTDEF;
2477 idxFrame = pOmfSym->idx;
2478 }
2479 else
2480 {
2481 bFrame = OMF_FIX_F_SEGDEF;
2482 idxFrame = pOmfSym->idxSegDef;
2483 }
2484 break;
2485
2486 case IMAGE_REL_AMD64_ABSOLUTE:
2487 continue; /* Ignore it like the PECOFF.DOC says we should. */
2488
2489 case IMAGE_REL_AMD64_SECREL7:
2490 default:
2491 return error(pThis->pszSrc, "Unsupported fixup type %#x (%s) at rva=%#x in section #%u '%-8.8s'\n",
2492 paRelocs[iReloc].Type,
2493 paRelocs[iReloc].Type < RT_ELEMENTS(g_apszCoffAmd64RelTypes)
2494 ? g_apszCoffAmd64RelTypes[paRelocs[iReloc].Type] : "unknown",
2495 paRelocs[iReloc].u.VirtualAddress, i, paShdrs[i].Name);
2496 }
2497
2498 /* Add the fixup. */
2499 if (idxFrame == UINT16_MAX)
2500 error(pThis->pszSrc, "idxFrame=UINT16_MAX for %s type=%s\n",
2501 coffGetSymbolName(pCoffSym, pchStrTab, cbStrTab, szShortName),
2502 g_apszCoffAmd64RelTypes[paRelocs[iReloc].Type]);
2503 fRet = omfWriter_LEDataAddFixup(pThis, offDataRec, fSelfRel, bLocation, bFrame, idxFrame,
2504 bTarget, idxTarget, fTargetDisp, offTargetDisp) && fRet;
2505 }
2506
2507 /*
2508 * Write the LEDATA and associated FIXUPPs.
2509 */
2510 if (!omfWriter_LEDataEnd(pThis))
2511 return false;
2512
2513 /*
2514 * Advance.
2515 */
2516 paRelocs += cChunkRelocs;
2517 cRelocs -= cChunkRelocs;
2518 if (cbData > cbChunk)
2519 {
2520 cbData -= cbChunk;
2521 pbData += cbChunk;
2522 }
2523 else
2524 cbData = 0;
2525 off += cbChunk;
2526 cbVirtData -= cbChunk;
2527 }
2528 }
2529
2530 return fRet;
2531}
2532
2533
2534static bool convertCoffToOmf(const char *pszFile, uint8_t const *pbFile, size_t cbFile, FILE *pDst)
2535{
2536 /*
2537 * Validate the source file a little.
2538 */
2539 if (!validateCoff(pszFile, pbFile, cbFile))
2540 return false;
2541
2542 /*
2543 * Instantiate the OMF writer.
2544 */
2545 PIMAGE_FILE_HEADER pHdr = (PIMAGE_FILE_HEADER)pbFile;
2546 POMFWRITER pThis = omfWriter_Create(pszFile, pHdr->NumberOfSections, pHdr->NumberOfSymbols, pDst);
2547 if (!pThis)
2548 return false;
2549
2550 /*
2551 * Write the OMF object file.
2552 */
2553 if (omfWriter_BeginModule(pThis, pszFile))
2554 {
2555 PCIMAGE_SECTION_HEADER paShdrs = (PCIMAGE_SECTION_HEADER)(pHdr + 1);
2556 PCIMAGE_SYMBOL paSymTab = (PCIMAGE_SYMBOL)&pbFile[pHdr->PointerToSymbolTable];
2557 const char *pchStrTab = (const char *)&paSymTab[pHdr->NumberOfSymbols];
2558 if ( convertCoffSectionsToSegDefsAndGrpDefs(pThis, paShdrs, pHdr->NumberOfSections)
2559 && convertCoffSymbolsToPubDefsAndExtDefs(pThis, paSymTab, pHdr->NumberOfSymbols, pchStrTab, paShdrs)
2560 && omfWriter_LinkPassSeparator(pThis)
2561 && convertCoffSectionsToLeDataAndFixupps(pThis, pbFile, cbFile, paShdrs, pHdr->NumberOfSections,
2562 paSymTab, pHdr->NumberOfSymbols, pchStrTab)
2563 && omfWriter_EndModule(pThis) )
2564 {
2565
2566 omfWriter_Destroy(pThis);
2567 return true;
2568 }
2569 }
2570
2571 omfWriter_Destroy(pThis);
2572 return false;
2573}
2574
2575
2576
2577/*********************************************************************************************************************************
2578* OMF Converter/Tweaker *
2579*********************************************************************************************************************************/
2580
2581/** Watcom intrinsics we need to modify so we can mix 32-bit and 16-bit
2582 * code, since the 16 and 32 bit compilers share several names.
2583 * The names are length prefixed.
2584 */
2585static const char * const g_apszExtDefRenames[] =
2586{
2587 "\x05" "__I4D",
2588 "\x05" "__I4M",
2589 "\x05" "__I8D",
2590 "\x06" "__I8DQ",
2591 "\x07" "__I8DQE",
2592 "\x06" "__I8DR",
2593 "\x07" "__I8DRE",
2594 "\x06" "__I8LS",
2595 "\x05" "__I8M",
2596 "\x06" "__I8ME",
2597 "\x06" "__I8RS",
2598 "\x05" "__PIA",
2599 "\x05" "__PIS",
2600 "\x05" "__PTC",
2601 "\x05" "__PTS",
2602 "\x05" "__U4D",
2603 "\x05" "__U4M",
2604 "\x05" "__U8D",
2605 "\x06" "__U8DQ",
2606 "\x07" "__U8DQE",
2607 "\x06" "__U8DR",
2608 "\x07" "__U8DRE",
2609 "\x06" "__U8LS",
2610 "\x05" "__U8M",
2611 "\x06" "__U8ME",
2612 "\x06" "__U8RS",
2613};
2614
2615/**
2616 * Renames references to intrinsic helper functions so they won't clash between
2617 * 32-bit and 16-bit code.
2618 *
2619 * @returns true / false.
2620 * @param pszFile File name for complaining.
2621 * @param pbFile Pointer to the file content.
2622 * @param cbFile Size of the file content.
2623 */
2624static bool convertomf(const char *pszFile, uint8_t *pbFile, size_t cbFile, const char **papchLNames, uint32_t cLNamesMax)
2625{
2626 uint32_t cLNames = 0;
2627 uint32_t cExtDefs = 0;
2628 uint32_t cPubDefs = 0;
2629 bool fProbably32bit = false;
2630 uint32_t off = 0;
2631
2632 while (off + 3 < cbFile)
2633 {
2634 uint8_t bRecType = pbFile[off];
2635 uint16_t cbRec = RT_MAKE_U16(pbFile[off + 1], pbFile[off + 2]);
2636 if (g_cVerbose > 2)
2637 printf( "%#07x: type=%#04x len=%#06x\n", off, bRecType, cbRec);
2638 if (off + cbRec > cbFile)
2639 return error(pszFile, "Invalid record length at %#x: %#x (cbFile=%#lx)\n", off, cbRec, (unsigned long)cbFile);
2640
2641 if (bRecType & OMF_REC32)
2642 fProbably32bit = true;
2643
2644 uint32_t offRec = 0;
2645 uint8_t *pbRec = &pbFile[off + 3];
2646#define OMF_CHECK_RET(a_cbReq, a_Name) /* Not taking the checksum into account, so we're good with 1 or 2 byte fields. */ \
2647 if (offRec + (a_cbReq) <= cbRec) {/*likely*/} \
2648 else return error(pszFile, "Malformed " #a_Name "! off=%#x offRec=%#x cbRec=%#x cbNeeded=%#x line=%d\n", \
2649 off, offRec, cbRec, (a_cbReq), __LINE__)
2650 switch (bRecType)
2651 {
2652 /*
2653 * Scan external definitions for intrinsics needing mangling.
2654 */
2655 case OMF_EXTDEF:
2656 {
2657 while (offRec + 1 < cbRec)
2658 {
2659 uint8_t cch = pbRec[offRec++];
2660 OMF_CHECK_RET(cch, EXTDEF);
2661 char *pchName = (char *)&pbRec[offRec];
2662 offRec += cch;
2663
2664 OMF_CHECK_RET(2, EXTDEF);
2665 uint16_t idxType = pbRec[offRec++];
2666 if (idxType & 0x80)
2667 idxType = ((idxType & 0x7f) << 8) | pbRec[offRec++];
2668
2669 if (g_cVerbose > 2)
2670 printf(" EXTDEF [%u]: %-*.*s type=%#x\n", cExtDefs, cch, cch, pchName, idxType);
2671 else if (g_cVerbose > 0)
2672 printf(" U %-*.*s\n", cch, cch, pchName);
2673
2674 /* Look for g_apszExtDefRenames entries that requires changing. */
2675 if ( cch >= 5
2676 && cch <= 7
2677 && pchName[0] == '_'
2678 && pchName[1] == '_'
2679 && ( pchName[2] == 'U'
2680 || pchName[2] == 'I'
2681 || pchName[2] == 'P')
2682 && ( pchName[3] == '4'
2683 || pchName[3] == '8'
2684 || pchName[3] == 'I'
2685 || pchName[3] == 'T') )
2686 {
2687 uint32_t i = RT_ELEMENTS(g_apszExtDefRenames);
2688 while (i-- > 0)
2689 if ( cch == (uint8_t)g_apszExtDefRenames[i][0]
2690 && memcmp(&g_apszExtDefRenames[i][1], pchName, cch) == 0)
2691 {
2692 pchName[0] = fProbably32bit ? '?' : '_';
2693 pchName[1] = '?';
2694 break;
2695 }
2696 }
2697
2698 cExtDefs++;
2699 }
2700 break;
2701 }
2702
2703 /*
2704 * Record LNAME records, scanning for FLAT.
2705 */
2706 case OMF_LNAMES:
2707 {
2708 while (offRec + 1 < cbRec)
2709 {
2710 uint8_t cch = pbRec[offRec];
2711 if (offRec + 1 + cch >= cbRec)
2712 return error(pszFile, "Invalid LNAME string length at %#x+3+%#x: %#x (cbFile=%#lx)\n",
2713 off, offRec, cch, (unsigned long)cbFile);
2714 if (cLNames + 1 >= cLNamesMax)
2715 return error(pszFile, "Too many LNAME strings\n");
2716
2717 if (g_cVerbose > 2)
2718 printf(" LNAME[%u]: %-*.*s\n", cLNames, cch, cch, &pbRec[offRec + 1]);
2719
2720 papchLNames[cLNames++] = (const char *)&pbRec[offRec];
2721 if (cch == 4 && memcmp(&pbRec[offRec + 1], "FLAT", 4) == 0)
2722 fProbably32bit = true;
2723
2724 offRec += cch + 1;
2725 }
2726 break;
2727 }
2728
2729 /*
2730 * Display public names if -v is specified.
2731 */
2732 case OMF_PUBDEF16:
2733 case OMF_PUBDEF32:
2734 case OMF_LPUBDEF16:
2735 case OMF_LPUBDEF32:
2736 {
2737 if (g_cVerbose > 0)
2738 {
2739 char const chType = bRecType == OMF_PUBDEF16 || bRecType == OMF_PUBDEF32 ? 'T' : 't';
2740 const char *pszRec = "LPUBDEF";
2741 if (chType == 'T')
2742 pszRec++;
2743
2744 OMF_CHECK_RET(2, [L]PUBDEF);
2745 uint16_t idxGrp = pbRec[offRec++];
2746 if (idxGrp & 0x80)
2747 idxGrp = ((idxGrp & 0x7f) << 8) | pbRec[offRec++];
2748
2749 OMF_CHECK_RET(2, [L]PUBDEF);
2750 uint16_t idxSeg = pbRec[offRec++];
2751 if (idxSeg & 0x80)
2752 idxSeg = ((idxSeg & 0x7f) << 8) | pbRec[offRec++];
2753
2754 uint16_t uFrameBase = 0;
2755 if (idxSeg == 0)
2756 {
2757 OMF_CHECK_RET(2, [L]PUBDEF);
2758 uFrameBase = RT_MAKE_U16(pbRec[offRec], pbRec[offRec + 1]);
2759 offRec += 2;
2760 }
2761 if (g_cVerbose > 2)
2762 printf(" %s: idxGrp=%#x idxSeg=%#x uFrameBase=%#x\n", pszRec, idxGrp, idxSeg, uFrameBase);
2763 uint16_t const uSeg = idxSeg ? idxSeg : uFrameBase;
2764
2765 while (offRec + 1 < cbRec)
2766 {
2767 uint8_t cch = pbRec[offRec++];
2768 OMF_CHECK_RET(cch, [L]PUBDEF);
2769 const char *pchName = (const char *)&pbRec[offRec];
2770 offRec += cch;
2771
2772 uint32_t offSeg;
2773 if (bRecType & OMF_REC32)
2774 {
2775 OMF_CHECK_RET(4, [L]PUBDEF);
2776 offSeg = RT_MAKE_U32_FROM_U8(pbRec[offRec], pbRec[offRec + 1], pbRec[offRec + 2], pbRec[offRec + 3]);
2777 offRec += 4;
2778 }
2779 else
2780 {
2781 OMF_CHECK_RET(2, [L]PUBDEF);
2782 offSeg = RT_MAKE_U16(pbRec[offRec], pbRec[offRec + 1]);
2783 offRec += 2;
2784 }
2785
2786 OMF_CHECK_RET(2, [L]PUBDEF);
2787 uint16_t idxType = pbRec[offRec++];
2788 if (idxType & 0x80)
2789 idxType = ((idxType & 0x7f) << 8) | pbRec[offRec++];
2790
2791 if (g_cVerbose > 2)
2792 printf(" %s[%u]: off=%#010x type=%#x %-*.*s\n", pszRec, cPubDefs, offSeg, idxType, cch, cch, pchName);
2793 else if (g_cVerbose > 0)
2794 printf("%04x:%08x %c %-*.*s\n", uSeg, offSeg, chType, cch, cch, pchName);
2795
2796 cPubDefs++;
2797 }
2798 }
2799 break;
2800 }
2801 }
2802
2803 /* advance */
2804 off += cbRec + 3;
2805 }
2806 return true;
2807}
2808
2809
2810/**
2811 * Does the convertion using convertelf and convertcoff.
2812 *
2813 * @returns exit code (0 on success, non-zero on failure)
2814 * @param pszFile The file to convert.
2815 */
2816static int convertit(const char *pszFile)
2817{
2818 /* Construct the filename for saving the unmodified file. */
2819 char szOrgFile[_4K];
2820 size_t cchFile = strlen(pszFile);
2821 if (cchFile + sizeof(".original") > sizeof(szOrgFile))
2822 {
2823 error(pszFile, "Filename too long!\n");
2824 return RTEXITCODE_FAILURE;
2825 }
2826 memcpy(szOrgFile, pszFile, cchFile);
2827 memcpy(&szOrgFile[cchFile], ".original", sizeof(".original"));
2828
2829 /* Read the whole file. */
2830 void *pvFile;
2831 size_t cbFile;
2832 if (readfile(pszFile, &pvFile, &cbFile))
2833 {
2834 /*
2835 * Do format conversions / adjustments.
2836 */
2837 bool fRc = false;
2838 uint8_t *pbFile = (uint8_t *)pvFile;
2839 if ( cbFile > sizeof(Elf64_Ehdr)
2840 && pbFile[0] == ELFMAG0
2841 && pbFile[1] == ELFMAG1
2842 && pbFile[2] == ELFMAG2
2843 && pbFile[3] == ELFMAG3)
2844 {
2845#ifdef ELF_TO_OMF_CONVERSION
2846 if (writefile(szOrgFile, pvFile, cbFile))
2847 {
2848 FILE *pDst = openfile(pszFile, true /*fWrite*/);
2849 if (pDst)
2850 {
2851 fRc = convertElfToOmf(pszFile, pbFile, cbFile, pDst);
2852 fRc = fclose(pDst) == 0 && fRc;
2853 }
2854 }
2855#else
2856 fRc = writefile(szOrgFile, pvFile, cbFile)
2857 && convertelf(pszFile, pbFile, cbFile)
2858 && writefile(pszFile, pvFile, cbFile);
2859#endif
2860 }
2861 else if ( cbFile > sizeof(IMAGE_FILE_HEADER)
2862 && RT_MAKE_U16(pbFile[0], pbFile[1]) == IMAGE_FILE_MACHINE_AMD64
2863 && RT_MAKE_U16(pbFile[2], pbFile[3]) * sizeof(IMAGE_SECTION_HEADER) + sizeof(IMAGE_FILE_HEADER)
2864 < cbFile
2865 && RT_MAKE_U16(pbFile[2], pbFile[3]) > 0)
2866 {
2867 if (writefile(szOrgFile, pvFile, cbFile))
2868 {
2869 FILE *pDst = openfile(pszFile, true /*fWrite*/);
2870 if (pDst)
2871 {
2872 fRc = convertCoffToOmf(pszFile, pbFile, cbFile, pDst);
2873 fRc = fclose(pDst) == 0 && fRc;
2874 }
2875 }
2876 }
2877 else if ( cbFile >= 8
2878 && pbFile[0] == OMF_THEADR
2879 && RT_MAKE_U16(pbFile[1], pbFile[2]) < cbFile)
2880 {
2881 const char **papchLNames = (const char **)calloc(sizeof(*papchLNames), _32K);
2882 fRc = writefile(szOrgFile, pvFile, cbFile)
2883 && convertomf(pszFile, pbFile, cbFile, papchLNames, _32K)
2884 && writefile(pszFile, pvFile, cbFile);
2885 free(papchLNames);
2886 }
2887 else
2888 fprintf(stderr, "error: Don't recognize format of '%s' (%#x %#x %#x %#x, cbFile=%lu)\n",
2889 pszFile, pbFile[0], pbFile[1], pbFile[2], pbFile[3], (unsigned long)cbFile);
2890 free(pvFile);
2891 if (fRc)
2892 return 0;
2893 }
2894 return 1;
2895}
2896
2897
2898int main(int argc, char **argv)
2899{
2900 int rcExit = 0;
2901
2902 /*
2903 * Scan the arguments.
2904 */
2905 for (int i = 1; i < argc; i++)
2906 {
2907 if (argv[i][0] == '-')
2908 {
2909 const char *pszOpt = &argv[i][1];
2910 if (*pszOpt == '-')
2911 {
2912 /* Convert long options to short ones. */
2913 pszOpt--;
2914 if (!strcmp(pszOpt, "--verbose"))
2915 pszOpt = "v";
2916 else if (!strcmp(pszOpt, "--version"))
2917 pszOpt = "V";
2918 else if (!strcmp(pszOpt, "--help"))
2919 pszOpt = "h";
2920 else
2921 {
2922 fprintf(stderr, "syntax errro: Unknown options '%s'\n", pszOpt);
2923 return 2;
2924 }
2925 }
2926
2927 /* Process the list of short options. */
2928 while (*pszOpt)
2929 {
2930 switch (*pszOpt++)
2931 {
2932 case 'v':
2933 g_cVerbose++;
2934 break;
2935
2936 case 'V':
2937 printf("%s\n", "$Revision: 60136 $");
2938 return 0;
2939
2940 case '?':
2941 case 'h':
2942 printf("usage: %s [options] -o <output> <input1> [input2 ... [inputN]]\n",
2943 argv[0]);
2944 return 0;
2945 }
2946 }
2947 }
2948 else
2949 {
2950 /*
2951 * File to convert. Do the job right away.
2952 */
2953 rcExit = convertit(argv[i]);
2954 if (rcExit != 0)
2955 break;
2956 }
2957 }
2958
2959 return rcExit;
2960}
2961
2962
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