VirtualBox

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

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

bs3kit: a bit more of the ELF -> OMF converter.

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