VirtualBox

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

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

bs3kit: line number improvments.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 179.6 KB
Line 
1/* $Id: VBoxBs3ObjConverter.cpp 60265 2016-03-31 00:48:14Z 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/sort.h>
39#include <iprt/x86.h>
40
41#include <iprt/formats/elf64.h>
42#include <iprt/formats/elf-amd64.h>
43#include <iprt/formats/pecoff.h>
44#include <iprt/formats/omf.h>
45#include <iprt/formats/codeview.h>
46
47
48/*********************************************************************************************************************************
49* Defined Constants And Macros *
50*********************************************************************************************************************************/
51#if ARCH_BITS == 64 && !defined(RT_OS_WINDOWS) && !defined(RT_OS_DARWIN)
52# define ELF_FMT_X64 "lx"
53# define ELF_FMT_D64 "ld"
54#else
55# define ELF_FMT_X64 "llx"
56# define ELF_FMT_D64 "lld"
57#endif
58
59
60/*********************************************************************************************************************************
61* Global Variables *
62*********************************************************************************************************************************/
63/** Verbosity level. */
64static unsigned g_cVerbose = 0;
65
66
67/**
68 * Opens a file for binary reading or writing.
69 *
70 * @returns File stream handle.
71 * @param pszFile The name of the file.
72 * @param fWrite Whether to open for writing or reading.
73 */
74static FILE *openfile(const char *pszFile, bool fWrite)
75{
76#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
77 FILE *pFile = fopen(pszFile, fWrite ? "wb" : "rb");
78#else
79 FILE *pFile = fopen(pszFile, fWrite ? "w" : "r");
80#endif
81 if (!pFile)
82 fprintf(stderr, "error: Failed to open '%s' for %s: %s (%d)\n",
83 pszFile, fWrite ? "writing" : "reading", strerror(errno), errno);
84 return pFile;
85}
86
87
88/**
89 * Read the given file into memory.
90 *
91 * @returns true on success, false on failure.
92 * @param pszFile The file to read.
93 * @param ppvFile Where to return the memory.
94 * @param pcbFile Where to return the size.
95 */
96static bool readfile(const char *pszFile, void **ppvFile, size_t *pcbFile)
97{
98 FILE *pFile = openfile(pszFile, false);
99 if (pFile)
100 {
101 /*
102 * Figure the size.
103 */
104 if (fseek(pFile, 0, SEEK_END) == 0)
105 {
106 long cbFile = ftell(pFile);
107 if (cbFile > 0)
108 {
109 if (fseek(pFile, SEEK_SET, 0) == 0)
110 {
111 /*
112 * Allocate and read content.
113 */
114 void *pvFile = malloc((size_t)cbFile);
115 if (pvFile)
116 {
117 if (fread(pvFile, cbFile, 1, pFile) == 1)
118 {
119 *ppvFile = pvFile;
120 *pcbFile = (size_t)cbFile;
121 fclose(pFile);
122 return true;
123 }
124 free(pvFile);
125 fprintf(stderr, "error: fread failed in '%s': %s (%d)\n", pszFile, strerror(errno), errno);
126 }
127 else
128 fprintf(stderr, "error: failed to allocate %ld bytes of memory for '%s'\n", cbFile, pszFile);
129 }
130 else
131 fprintf(stderr, "error: fseek #2 failed in '%s': %s (%d)\n", pszFile, strerror(errno), errno);
132 }
133 else
134 fprintf(stderr, "error: ftell failed in '%s': %s (%d)\n", pszFile, strerror(errno), errno);
135 }
136 else
137 fprintf(stderr, "error: fseek #1 failed in '%s': %s (%d)\n", pszFile, strerror(errno), errno);
138 fclose(pFile);
139 }
140 return false;
141}
142
143
144/**
145 * Write the given file into memory.
146 *
147 * @returns true on success, false on failure.
148 * @param pszFile The file to write.
149 * @param pvFile Where to return the memory.
150 * @param cbFile Where to return the size.
151 */
152static bool writefile(const char *pszFile, void const *pvFile, size_t cbFile)
153{
154 remove(pszFile);
155
156 int rc = -1;
157 FILE *pFile = openfile(pszFile, true);
158 if (pFile)
159 {
160 if (fwrite(pvFile, cbFile, 1, pFile) == 1)
161 {
162 fclose(pFile);
163 return true;
164 }
165 fprintf(stderr, "error: fwrite failed in '%s': %s (%d)\n", pszFile, strerror(errno), errno);
166 fclose(pFile);
167 }
168 return false;
169}
170
171
172/**
173 * Reports an error and returns false.
174 *
175 * @returns false
176 * @param pszFile The filename.
177 * @param pszFormat The message format string.
178 * @param ... Format arguments.
179 */
180static bool error(const char *pszFile, const char *pszFormat, ...)
181{
182 fflush(stdout);
183 fprintf(stderr, "error: %s: ", pszFile);
184 va_list va;
185 va_start(va, pszFormat);
186 vfprintf(stderr, pszFormat, va);
187 va_end(va);
188 return false;
189}
190
191
192
193/*********************************************************************************************************************************
194* Common OMF Writer *
195*********************************************************************************************************************************/
196
197/** Entry for each segment/section in the source format for mapping it to a
198 * segment defintion. */
199typedef struct OMFTOSEGDEF
200{
201 /** The segment defintion index of the section, UINT16_MAX if not translated. */
202 uint16_t iSegDef;
203 /** The group index for this segment, UINT16_MAX if not applicable. */
204 uint16_t iGrpDef;
205 /** The class name table entry, UINT16_MAX if not applicable. */
206 uint16_t iClassNm;
207 /** The group name for this segment, UINT16_MAX if not applicable. */
208 uint16_t iGrpNm;
209 /** The group name for this segment, UINT16_MAX if not applicable. */
210 uint16_t iSegNm;
211 /** The number of public definitions for this segment. */
212 uint32_t cPubDefs;
213 /** The segment name (OMF). */
214 char *pszName;
215} OMFTOSEGDEF;
216/** Pointer to a segment/section to segdef mapping. */
217typedef OMFTOSEGDEF *POMFTOSEGDEF;
218
219/** Symbol table translation type. */
220typedef enum OMFSYMTYPE
221{
222 /** Invalid symbol table entry (aux sym). */
223 OMFSYMTYPE_INVALID = 0,
224 /** Ignored. */
225 OMFSYMTYPE_IGNORED,
226 /** A public defintion. */
227 OMFSYMTYPE_PUBDEF,
228 /** An external definition. */
229 OMFSYMTYPE_EXTDEF,
230 /** A segment reference for fixups. */
231 OMFSYMTYPE_SEGDEF,
232 /** Internal symbol that may be used for fixups. */
233 OMFSYMTYPE_INTERNAL
234} OMFSYMTYPE;
235
236/** Symbol table translation. */
237typedef struct OMFSYMBOL
238{
239 /** What this source symbol table entry should be translated into. */
240 OMFSYMTYPE enmType;
241 /** The OMF table index. UINT16_MAX if not applicable. */
242 uint16_t idx;
243 /** The OMF segment definition index. */
244 uint16_t idxSegDef;
245 /** The OMF group definition index. */
246 uint16_t idxGrpDef;
247} OMFSYMBOL;
248/** Pointer to an source symbol table translation entry. */
249typedef OMFSYMBOL *POMFSYMBOL;
250
251/**
252 * OMF converter & writer instance.
253 */
254typedef struct OMFWRITER
255{
256 /** The source file name (for bitching). */
257 const char *pszSrc;
258 /** The destination output file. */
259 FILE *pDst;
260
261 /** Pointer to the table mapping from source segments/section to segdefs. */
262 POMFTOSEGDEF paSegments;
263 /** Number of source segments/sections. */
264 uint32_t cSegments;
265
266 /** Number of entries in the source symbol table. */
267 uint32_t cSymbols;
268 /** Pointer to the table mapping from source symbols to OMF stuff. */
269 POMFSYMBOL paSymbols;
270
271 /** LEDATA segment offset. */
272 uint32_t offSeg;
273 /** Start of the current LEDATA record. */
274 uint32_t offSegRec;
275 /** The LEDATA end segment offset. */
276 uint32_t offSegEnd;
277 /** The current LEDATA segment. */
278 uint16_t idx;
279
280 /** The index of the next list of names entry. */
281 uint16_t idxNextName;
282
283 /** The current record size. */
284 uint16_t cbRec;
285 /** The current record type */
286 uint8_t bType;
287 /** The record data buffer (too large, but whatever). */
288 uint8_t abData[_1K + 64];
289
290 /** Current FIXUPP entry. */
291 uint8_t iFixupp;
292 /** FIXUPP records being prepared for LEDATA currently stashed in abData.
293 * We may have to adjust addend values in the LEDATA when converting to OMF
294 * fixups. */
295 struct
296 {
297 uint16_t cbRec;
298 uint8_t abData[_1K + 64];
299 uint8_t abAlign[2]; /**< Alignment padding. */
300 } aFixupps[3];
301
302 /** The index of the FLAT group. */
303 uint16_t idxGrpFlat;
304 /** The EXTDEF index of the __ImageBase symbol. */
305 uint16_t idxExtImageBase;
306} OMFWRITE;
307/** Pointer to an OMF writer. */
308typedef OMFWRITE *POMFWRITER;
309
310
311/**
312 * Creates an OMF writer instance.
313 */
314static POMFWRITER omfWriter_Create(const char *pszSrc, uint32_t cSegments, uint32_t cSymbols, FILE *pDst)
315{
316 POMFWRITER pThis = (POMFWRITER)calloc(sizeof(OMFWRITER), 1);
317 if (pThis)
318 {
319 pThis->pszSrc = pszSrc;
320 pThis->idxNextName = 1; /* We start counting at 1. */
321 pThis->cSegments = cSegments;
322 pThis->paSegments = (POMFTOSEGDEF)calloc(sizeof(OMFTOSEGDEF), cSegments);
323 if (pThis->paSegments)
324 {
325 pThis->cSymbols = cSymbols;
326 pThis->paSymbols = (POMFSYMBOL)calloc(sizeof(OMFSYMBOL), cSymbols);
327 if (pThis->paSymbols)
328 {
329 pThis->pDst = pDst;
330 return pThis;
331 }
332 free(pThis->paSegments);
333 }
334 free(pThis);
335 }
336 error(pszSrc, "Out of memory!\n");
337 return NULL;
338}
339
340/**
341 * Destroys the given OMF writer instance.
342 * @param pThis OMF writer instance.
343 */
344static void omfWriter_Destroy(POMFWRITER pThis)
345{
346 free(pThis->paSymbols);
347 for (uint32_t i = 0; i < pThis->cSegments; i++)
348 if (pThis->paSegments[i].pszName)
349 free(pThis->paSegments[i].pszName);
350 free(pThis->paSegments);
351 free(pThis);
352}
353
354static bool omfWriter_RecBegin(POMFWRITER pThis, uint8_t bType)
355{
356 pThis->bType = bType;
357 pThis->cbRec = 0;
358 return true;
359}
360
361static bool omfWriter_RecAddU8(POMFWRITER pThis, uint8_t b)
362{
363 if (pThis->cbRec < OMF_MAX_RECORD_PAYLOAD)
364 {
365 pThis->abData[pThis->cbRec++] = b;
366 return true;
367 }
368 return error(pThis->pszSrc, "Exceeded max OMF record length (bType=%#x)!\n", pThis->bType);
369}
370
371static bool omfWriter_RecAddU16(POMFWRITER pThis, uint16_t u16)
372{
373 if (pThis->cbRec + 2U <= OMF_MAX_RECORD_PAYLOAD)
374 {
375 pThis->abData[pThis->cbRec++] = (uint8_t)u16;
376 pThis->abData[pThis->cbRec++] = (uint8_t)(u16 >> 8);
377 return true;
378 }
379 return error(pThis->pszSrc, "Exceeded max OMF record length (bType=%#x)!\n", pThis->bType);
380}
381
382static bool omfWriter_RecAddU32(POMFWRITER pThis, uint32_t u32)
383{
384 if (pThis->cbRec + 4U <= OMF_MAX_RECORD_PAYLOAD)
385 {
386 pThis->abData[pThis->cbRec++] = (uint8_t)u32;
387 pThis->abData[pThis->cbRec++] = (uint8_t)(u32 >> 8);
388 pThis->abData[pThis->cbRec++] = (uint8_t)(u32 >> 16);
389 pThis->abData[pThis->cbRec++] = (uint8_t)(u32 >> 24);
390 return true;
391 }
392 return error(pThis->pszSrc, "Exceeded max OMF record length (bType=%#x)!\n", pThis->bType);
393}
394
395static bool omfWriter_RecAddIdx(POMFWRITER pThis, uint16_t idx)
396{
397 if (idx < 128)
398 return omfWriter_RecAddU8(pThis, (uint8_t)idx);
399 if (idx < _32K)
400 return omfWriter_RecAddU8(pThis, (uint8_t)(idx >> 7) | 0x80)
401 && omfWriter_RecAddU8(pThis, (uint8_t)idx);
402 return error(pThis->pszSrc, "Index out of range %#x\n", idx);
403}
404
405static bool omfWriter_RecAddBytes(POMFWRITER pThis, const void *pvData, size_t cbData)
406{
407 const uint16_t cbNasmHack = OMF_MAX_RECORD_PAYLOAD + 1;
408 if (cbData + pThis->cbRec <= cbNasmHack)
409 {
410 memcpy(&pThis->abData[pThis->cbRec], pvData, cbData);
411 pThis->cbRec += (uint16_t)cbData;
412 return true;
413 }
414 return error(pThis->pszSrc, "Exceeded max OMF record length (bType=%#x, cbData=%#x, cbRec=%#x, max=%#x)!\n",
415 pThis->bType, (unsigned)cbData, pThis->cbRec, OMF_MAX_RECORD_PAYLOAD);
416}
417
418static bool omfWriter_RecAddStringN(POMFWRITER pThis, const char *pchString, size_t cchString)
419{
420 if (cchString < 256)
421 {
422 return omfWriter_RecAddU8(pThis, (uint8_t)cchString)
423 && omfWriter_RecAddBytes(pThis, pchString, cchString);
424 }
425 return error(pThis->pszSrc, "String too long (%u bytes): '%*.*s'\n",
426 (unsigned)cchString, (int)cchString, (int)cchString, pchString);
427}
428
429static bool omfWriter_RecAddString(POMFWRITER pThis, const char *pszString)
430{
431 return omfWriter_RecAddStringN(pThis, pszString, strlen(pszString));
432}
433
434static bool omfWriter_RecEnd(POMFWRITER pThis, bool fAddCrc)
435{
436 if ( !fAddCrc
437 || omfWriter_RecAddU8(pThis, 0))
438 {
439 OMFRECHDR RecHdr = { pThis->bType, RT_H2LE_U16(pThis->cbRec) };
440 if ( fwrite(&RecHdr, sizeof(RecHdr), 1, pThis->pDst) == 1
441 && fwrite(pThis->abData, pThis->cbRec, 1, pThis->pDst) == 1)
442 {
443 pThis->bType = 0;
444 pThis->cbRec = 0;
445 return true;
446 }
447 return error(pThis->pszSrc, "Write error\n");
448 }
449 return false;
450}
451
452static bool omfWriter_RecEndWithCrc(POMFWRITER pThis)
453{
454 return omfWriter_RecEnd(pThis, true /*fAddCrc*/);
455}
456
457
458static bool omfWriter_BeginModule(POMFWRITER pThis, const char *pszFile)
459{
460 return omfWriter_RecBegin(pThis, OMF_THEADR)
461 && omfWriter_RecAddString(pThis, pszFile)
462 && omfWriter_RecEndWithCrc(pThis);
463}
464
465static bool omfWriter_LNamesAddN(POMFWRITER pThis, const char *pchName, size_t cchName, uint16_t *pidxName)
466{
467 /* split? */
468 if (pThis->cbRec + 1 /*len*/ + cchName + 1 /*crc*/ > OMF_MAX_RECORD_PAYLOAD)
469 {
470 if (pThis->cbRec == 0)
471 return error(pThis->pszSrc, "Too long LNAME '%*.*s'\n", (int)cchName, (int)cchName, pchName);
472 if ( !omfWriter_RecEndWithCrc(pThis)
473 || !omfWriter_RecBegin(pThis, OMF_LNAMES))
474 return false;
475 }
476
477 if (pidxName)
478 *pidxName = pThis->idxNextName;
479 pThis->idxNextName++;
480 return omfWriter_RecAddStringN(pThis, pchName, cchName);
481}
482
483static bool omfWriter_LNamesAdd(POMFWRITER pThis, const char *pszName, uint16_t *pidxName)
484{
485 return omfWriter_LNamesAddN(pThis, pszName, strlen(pszName), pidxName);
486}
487
488static bool omfWriter_LNamesBegin(POMFWRITER pThis, bool fAddZeroEntry)
489{
490 /* First entry is an empty string. */
491 return omfWriter_RecBegin(pThis, OMF_LNAMES)
492 && ( pThis->idxNextName > 1
493 || !fAddZeroEntry
494 || omfWriter_LNamesAddN(pThis, "", 0, NULL));
495}
496
497static bool omfWriter_LNamesEnd(POMFWRITER pThis)
498{
499 return omfWriter_RecEndWithCrc(pThis);
500}
501
502
503static bool omfWriter_SegDef(POMFWRITER pThis, uint8_t bSegAttr, uint32_t cbSeg, uint16_t idxSegName, uint16_t idxSegClass)
504{
505 return omfWriter_RecBegin(pThis, OMF_SEGDEF32)
506 && omfWriter_RecAddU8(pThis, bSegAttr)
507 && omfWriter_RecAddU32(pThis, cbSeg)
508 && omfWriter_RecAddIdx(pThis, idxSegName)
509 && omfWriter_RecAddIdx(pThis, idxSegClass)
510 && omfWriter_RecAddIdx(pThis, 1) /* overlay name index = NULL entry */
511 && omfWriter_RecEndWithCrc(pThis);
512}
513
514static bool omfWriter_GrpDefBegin(POMFWRITER pThis, uint16_t idxGrpName)
515{
516 return omfWriter_RecBegin(pThis, OMF_GRPDEF)
517 && omfWriter_RecAddIdx(pThis, idxGrpName);
518}
519
520static bool omfWriter_GrpDefAddSegDef(POMFWRITER pThis, uint16_t idxSegDef)
521{
522 return omfWriter_RecAddU8(pThis, 0xff)
523 && omfWriter_RecAddIdx(pThis, idxSegDef);
524}
525
526static bool omfWriter_GrpDefEnd(POMFWRITER pThis)
527{
528 return omfWriter_RecEndWithCrc(pThis);
529}
530
531
532static bool omfWriter_PubDefBegin(POMFWRITER pThis, uint16_t idxGrpDef, uint16_t idxSegDef)
533{
534 return omfWriter_RecBegin(pThis, OMF_PUBDEF32)
535 && omfWriter_RecAddIdx(pThis, idxGrpDef)
536 && omfWriter_RecAddIdx(pThis, idxSegDef)
537 && ( idxSegDef != 0
538 || omfWriter_RecAddU16(pThis, 0));
539
540}
541
542static bool omfWriter_PubDefAddN(POMFWRITER pThis, uint32_t uValue, const char *pchString, size_t cchString)
543{
544 /* Split? */
545 if (pThis->cbRec + 1 + cchString + 4 + 1 + 1 > OMF_MAX_RECORD_PAYLOAD)
546 {
547 if (cchString >= 256)
548 return error(pThis->pszSrc, "PUBDEF string too long %u ('%s')\n",
549 (unsigned)cchString, (int)cchString, (int)cchString, pchString);
550 if (!omfWriter_RecEndWithCrc(pThis))
551 return false;
552
553 /* Figure out the initial data length. */
554 pThis->cbRec = 1 + ((pThis->abData[0] & 0x80) != 0);
555 if (pThis->abData[pThis->cbRec] != 0)
556 pThis->cbRec += 1 + ((pThis->abData[pThis->cbRec] & 0x80) != 0);
557 else
558 pThis->cbRec += 3;
559 pThis->bType = OMF_PUBDEF32;
560 }
561
562 return omfWriter_RecAddStringN(pThis, pchString, cchString)
563 && omfWriter_RecAddU32(pThis, uValue)
564 && omfWriter_RecAddIdx(pThis, 0); /* type */
565}
566
567static bool omfWriter_PubDefAdd(POMFWRITER pThis, uint32_t uValue, const char *pszString)
568{
569 return omfWriter_PubDefAddN(pThis, uValue, pszString, strlen(pszString));
570}
571
572static bool omfWriter_PubDefEnd(POMFWRITER pThis)
573{
574 return omfWriter_RecEndWithCrc(pThis);
575}
576
577/**
578 * EXTDEF - Begin record.
579 */
580static bool omfWriter_ExtDefBegin(POMFWRITER pThis)
581{
582 return omfWriter_RecBegin(pThis, OMF_EXTDEF);
583
584}
585
586/**
587 * EXTDEF - Add an entry, split record if necessary.
588 */
589static bool omfWriter_ExtDefAddN(POMFWRITER pThis, const char *pchString, size_t cchString, uint16_t idxType)
590{
591 /* Split? */
592 if (pThis->cbRec + 1 + cchString + 1 + 1 > OMF_MAX_RECORD_PAYLOAD)
593 {
594 if (cchString >= 256)
595 return error(pThis->pszSrc, "EXTDEF string too long %u ('%s')\n",
596 (unsigned)cchString, (int)cchString, (int)cchString, pchString);
597 if ( !omfWriter_RecEndWithCrc(pThis)
598 || !omfWriter_RecBegin(pThis, OMF_EXTDEF))
599 return false;
600 }
601
602 return omfWriter_RecAddStringN(pThis, pchString, cchString)
603 && omfWriter_RecAddIdx(pThis, idxType); /* type */
604}
605
606/**
607 * EXTDEF - Add an entry, split record if necessary.
608 */
609static bool omfWriter_ExtDefAdd(POMFWRITER pThis, const char *pszString)
610{
611 return omfWriter_ExtDefAddN(pThis, pszString, strlen(pszString), 0);
612}
613
614/**
615 * EXTDEF - End of record.
616 */
617static bool omfWriter_ExtDefEnd(POMFWRITER pThis)
618{
619 return omfWriter_RecEndWithCrc(pThis);
620}
621
622/**
623 * COMENT/LINK_PASS_SEP - Add a link pass separator comment.
624 */
625static bool omfWriter_LinkPassSeparator(POMFWRITER pThis)
626{
627 return omfWriter_RecBegin(pThis, OMF_COMENT)
628 && omfWriter_RecAddU8(pThis, OMF_CTYP_NO_LIST)
629 && omfWriter_RecAddU8(pThis, OMF_CCLS_LINK_PASS_SEP)
630 && omfWriter_RecAddU8(pThis, 1)
631 && omfWriter_RecEndWithCrc(pThis);
632}
633
634
635/**
636 * LEDATA + FIXUPP - Begin records.
637 */
638static bool omfWriter_LEDataBegin(POMFWRITER pThis, uint16_t idxSeg, uint32_t offSeg)
639{
640 if ( omfWriter_RecBegin(pThis, OMF_LEDATA32)
641 && omfWriter_RecAddIdx(pThis, idxSeg)
642 && omfWriter_RecAddU32(pThis, offSeg))
643 {
644 pThis->idx = idxSeg;
645 pThis->offSeg = offSeg;
646 pThis->offSegRec = offSeg;
647 pThis->offSegEnd = offSeg + OMF_MAX_RECORD_PAYLOAD - 1 /*CRC*/ - pThis->cbRec;
648 pThis->offSegEnd &= ~(uint32_t)7; /* qword align. */
649
650 /* Reset the associated FIXUPP records. */
651 pThis->iFixupp = 0;
652 for (unsigned i = 0; i < RT_ELEMENTS(pThis->aFixupps); i++)
653 pThis->aFixupps[i].cbRec = 0;
654 return true;
655 }
656 return false;
657}
658
659/**
660 * LEDATA + FIXUPP - Begin records.
661 */
662static bool omfWriter_LEDataBeginEx(POMFWRITER pThis, uint16_t idxSeg, uint32_t offSeg,
663 uint32_t cbData, uint32_t cbRawData, void const *pbRawData, uint8_t **ppbData)
664{
665 if ( omfWriter_RecBegin(pThis, OMF_LEDATA32)
666 && omfWriter_RecAddIdx(pThis, idxSeg)
667 && omfWriter_RecAddU32(pThis, offSeg))
668 {
669 if ( cbData <= _1K
670 && pThis->cbRec + cbData + 1 <= OMF_MAX_RECORD_PAYLOAD)
671 {
672 uint8_t *pbDst = &pThis->abData[pThis->cbRec];
673 if (ppbData)
674 *ppbData = pbDst;
675
676 if (cbRawData)
677 memcpy(pbDst, pbRawData, RT_MIN(cbData, cbRawData));
678 if (cbData > cbRawData)
679 memset(&pbDst[cbRawData], 0, cbData - cbRawData);
680
681 pThis->cbRec += cbData;
682 pThis->idx = idxSeg;
683 pThis->offSegRec = offSeg;
684 pThis->offSeg = offSeg + cbData;
685 pThis->offSegEnd = offSeg + cbData;
686
687 /* Reset the associated FIXUPP records. */
688 pThis->iFixupp = 0;
689 for (unsigned i = 0; i < RT_ELEMENTS(pThis->aFixupps); i++)
690 pThis->aFixupps[i].cbRec = 0;
691 return true;
692 }
693 error(pThis->pszSrc, "Too much data for LEDATA record! (%#x)\n", (unsigned)cbData);
694 }
695 return false;
696}
697
698/**
699 * LEDATA + FIXUPP - Add FIXUPP subrecord bytes, split if necessary.
700 */
701static bool omfWriter_LEDataAddFixuppBytes(POMFWRITER pThis, void *pvSubRec, size_t cbSubRec)
702{
703 /* Split? */
704 unsigned iFixupp = pThis->iFixupp;
705 if (pThis->aFixupps[iFixupp].cbRec + cbSubRec >= OMF_MAX_RECORD_PAYLOAD)
706 {
707 if (g_cVerbose >= 2)
708 printf("debug: FIXUPP split\n");
709 iFixupp++;
710 if (iFixupp >= RT_ELEMENTS(pThis->aFixupps))
711 return error(pThis->pszSrc, "Out of FIXUPP records\n");
712 pThis->iFixupp = iFixupp;
713 pThis->aFixupps[iFixupp].cbRec = 0; /* paranoia */
714 }
715
716 /* Append the sub-record data. */
717 memcpy(&pThis->aFixupps[iFixupp].abData[pThis->aFixupps[iFixupp].cbRec], pvSubRec, cbSubRec);
718 pThis->aFixupps[iFixupp].cbRec += (uint16_t)cbSubRec;
719 return true;
720}
721
722/**
723 * LEDATA + FIXUPP - Add fixup, split if necessary.
724 */
725static bool omfWriter_LEDataAddFixup(POMFWRITER pThis, uint16_t offDataRec, bool fSelfRel, uint8_t bLocation,
726 uint8_t bFrame, uint16_t idxFrame,
727 uint8_t bTarget, uint16_t idxTarget, bool fTargetDisp, uint32_t offTargetDisp)
728{
729 if (g_cVerbose >= 2)
730 printf("debug: FIXUP[%#x]: off=%#x frame=%u:%#x target=%u:%#x disp=%d:%#x\n", pThis->aFixupps[pThis->iFixupp].cbRec,
731 offDataRec, bFrame, idxFrame, bTarget, idxTarget, fTargetDisp, offTargetDisp);
732
733 if ( offDataRec >= _1K
734 || bFrame >= 6
735 || bTarget > 6
736 || idxFrame >= _32K
737 || idxTarget >= _32K
738 || fTargetDisp != (bTarget <= OMF_FIX_T_FRAME_NO) )
739 return error(pThis->pszSrc,
740 "Internal error: offDataRec=%#x bFrame=%u idxFrame=%#x bTarget=%u idxTarget=%#x fTargetDisp=%d offTargetDisp=%#x\n",
741 offDataRec, bFrame, idxFrame, bTarget, idxTarget, fTargetDisp, offTargetDisp);
742
743
744 /*
745 * Encode the FIXUP subrecord.
746 */
747 uint8_t abFixup[16];
748 uint8_t off = 0;
749 /* Location */
750 abFixup[off++] = (offDataRec >> 8) | (bLocation << 2) | ((uint8_t)!fSelfRel << 6) | 0x80;
751 abFixup[off++] = (uint8_t)offDataRec;
752 /* Fix Data */
753 abFixup[off++] = 0x00 /*F=0*/ | (bFrame << 4) | 0x00 /*T=0*/ | bTarget;
754 /* Frame Datum */
755 if (bFrame <= OMF_FIX_F_FRAME_NO)
756 {
757 if (idxFrame >= 128)
758 abFixup[off++] = (uint8_t)(idxFrame >> 8);
759 abFixup[off++] = (uint8_t)idxFrame;
760 }
761 /* Target Datum */
762 if (idxTarget >= 128)
763 abFixup[off++] = (uint8_t)(idxTarget >> 8);
764 abFixup[off++] = (uint8_t)idxTarget;
765 /* Target Displacement */
766 if (fTargetDisp)
767 {
768 abFixup[off++] = RT_BYTE1(offTargetDisp);
769 abFixup[off++] = RT_BYTE2(offTargetDisp);
770 abFixup[off++] = RT_BYTE3(offTargetDisp);
771 abFixup[off++] = RT_BYTE4(offTargetDisp);
772 }
773
774 return omfWriter_LEDataAddFixuppBytes(pThis, abFixup, off);
775}
776
777/**
778 * LEDATA + FIXUPP - Add simple fixup, split if necessary.
779 */
780static bool omfWriter_LEDataAddFixupNoDisp(POMFWRITER pThis, uint16_t offDataRec, uint8_t bLocation,
781 uint8_t bFrame, uint16_t idxFrame, uint8_t bTarget, uint16_t idxTarget)
782{
783 return omfWriter_LEDataAddFixup(pThis, offDataRec, false /*fSelfRel*/, bLocation, bFrame, idxFrame, bTarget, idxTarget,
784 false /*fTargetDisp*/, 0 /*offTargetDisp*/);
785}
786
787
788/**
789 * LEDATA + FIXUPP - End of records.
790 */
791static bool omfWriter_LEDataEnd(POMFWRITER pThis)
792{
793 if (omfWriter_RecEndWithCrc(pThis))
794 {
795 for (unsigned iFixupp = 0; iFixupp <= pThis->iFixupp; iFixupp++)
796 {
797 uint16_t const cbRec = pThis->aFixupps[iFixupp].cbRec;
798 if (!cbRec)
799 break;
800 if (g_cVerbose >= 3)
801 printf("debug: FIXUPP32 #%u cbRec=%#x\n", iFixupp, cbRec);
802 if ( !omfWriter_RecBegin(pThis, OMF_FIXUPP32)
803 || !omfWriter_RecAddBytes(pThis, pThis->aFixupps[iFixupp].abData, cbRec)
804 || !omfWriter_RecEndWithCrc(pThis))
805 return false;
806 }
807 pThis->iFixupp = 0;
808 return true;
809 }
810 return false;
811}
812
813/**
814 * LEDATA + FIXUPP - Splits the LEDATA record.
815 */
816static bool omfWriter_LEDataSplit(POMFWRITER pThis)
817{
818 return omfWriter_LEDataEnd(pThis)
819 && omfWriter_LEDataBegin(pThis, pThis->idx, pThis->offSeg);
820}
821
822/**
823 * LEDATA + FIXUPP - Returns available space in current LEDATA record.
824 */
825static uint32_t omfWriter_LEDataAvailable(POMFWRITER pThis)
826{
827 if (pThis->offSeg < pThis->offSegEnd)
828 return pThis->offSegEnd - pThis->offSeg;
829 return 0;
830}
831
832/**
833 * LEDATA + FIXUPP - Splits LEDATA record if less than @a cb bytes available.
834 */
835static bool omfWriter_LEDataEnsureSpace(POMFWRITER pThis, uint32_t cb)
836{
837 if ( omfWriter_LEDataAvailable(pThis) >= cb
838 || omfWriter_LEDataSplit(pThis))
839 return true;
840 return false;
841}
842
843/**
844 * LEDATA + FIXUPP - Adds data to the LEDATA record, splitting it if needed.
845 */
846static bool omfWriter_LEDataAddBytes(POMFWRITER pThis, void const *pvData, size_t cbData)
847{
848 while (cbData > 0)
849 {
850 uint32_t cbAvail = omfWriter_LEDataAvailable(pThis);
851 if (cbAvail >= cbData)
852 {
853 if (omfWriter_RecAddBytes(pThis, pvData, cbData))
854 {
855 pThis->offSeg += (uint32_t)cbData;
856 break;
857 }
858 return false;
859 }
860 if (!omfWriter_RecAddBytes(pThis, pvData, cbAvail))
861 return false;
862 pThis->offSeg += cbAvail;
863 pvData = (uint8_t const *)pvData + cbAvail;
864 cbData -= cbAvail;
865 if (!omfWriter_LEDataSplit(pThis))
866 return false;
867 }
868 return true;
869}
870
871/**
872 * LEDATA + FIXUPP - Adds a U32 to the LEDATA record, splitting if needed.
873 */
874static bool omfWriter_LEDataAddU32(POMFWRITER pThis, uint32_t u32)
875{
876 if ( omfWriter_LEDataEnsureSpace(pThis, 4)
877 && omfWriter_RecAddU32(pThis, u32))
878 {
879 pThis->offSeg += 4;
880 return true;
881 }
882 return false;
883}
884
885/**
886 * LEDATA + FIXUPP - Adds a U16 to the LEDATA record, splitting if needed.
887 */
888static bool omfWriter_LEDataAddU16(POMFWRITER pThis, uint16_t u16)
889{
890 if ( omfWriter_LEDataEnsureSpace(pThis, 2)
891 && omfWriter_RecAddU16(pThis, u16))
892 {
893 pThis->offSeg += 2;
894 return true;
895 }
896 return false;
897}
898
899/**
900 * LEDATA + FIXUPP - Adds a byte to the LEDATA record, splitting if needed.
901 */
902static bool omfWriter_LEDataAddU8(POMFWRITER pThis, uint8_t b)
903{
904 if ( omfWriter_LEDataEnsureSpace(pThis, 1)
905 && omfWriter_RecAddU8(pThis, b))
906 {
907 pThis->offSeg += 1;
908 return true;
909 }
910 return false;
911}
912
913/**
914 * MODEND - End of module, simple variant.
915 */
916static bool omfWriter_EndModule(POMFWRITER pThis)
917{
918 return omfWriter_RecBegin(pThis, OMF_MODEND32)
919 && omfWriter_RecAddU8(pThis, 0)
920 && omfWriter_RecEndWithCrc(pThis);
921}
922
923
924
925
926/*********************************************************************************************************************************
927* ELF64/AMD64 -> ELF64/i386 Converter *
928*********************************************************************************************************************************/
929
930/** AMD64 relocation type names for ELF. */
931static const char * const g_apszElfAmd64RelTypes[] =
932{
933 "R_X86_64_NONE",
934 "R_X86_64_64",
935 "R_X86_64_PC32",
936 "R_X86_64_GOT32",
937 "R_X86_64_PLT32",
938 "R_X86_64_COPY",
939 "R_X86_64_GLOB_DAT",
940 "R_X86_64_JMP_SLOT",
941 "R_X86_64_RELATIVE",
942 "R_X86_64_GOTPCREL",
943 "R_X86_64_32",
944 "R_X86_64_32S",
945 "R_X86_64_16",
946 "R_X86_64_PC16",
947 "R_X86_64_8",
948 "R_X86_64_PC8",
949 "R_X86_64_DTPMOD64",
950 "R_X86_64_DTPOFF64",
951 "R_X86_64_TPOFF64",
952 "R_X86_64_TLSGD",
953 "R_X86_64_TLSLD",
954 "R_X86_64_DTPOFF32",
955 "R_X86_64_GOTTPOFF",
956 "R_X86_64_TPOFF32",
957};
958
959/** AMD64 relocation type sizes for ELF. */
960static uint8_t const g_acbElfAmd64RelTypes[] =
961{
962 0, /* R_X86_64_NONE */
963 8, /* R_X86_64_64 */
964 4, /* R_X86_64_PC32 */
965 4, /* R_X86_64_GOT32 */
966 4, /* R_X86_64_PLT32 */
967 0, /* R_X86_64_COPY */
968 0, /* R_X86_64_GLOB_DAT */
969 0, /* R_X86_64_JMP_SLOT */
970 0, /* R_X86_64_RELATIVE */
971 0, /* R_X86_64_GOTPCREL */
972 4, /* R_X86_64_32 */
973 4, /* R_X86_64_32S */
974 2, /* R_X86_64_16 */
975 2, /* R_X86_64_PC16 */
976 1, /* R_X86_64_8 */
977 1, /* R_X86_64_PC8 */
978 0, /* R_X86_64_DTPMOD64 */
979 0, /* R_X86_64_DTPOFF64 */
980 0, /* R_X86_64_TPOFF64 */
981 0, /* R_X86_64_TLSGD */
982 0, /* R_X86_64_TLSLD */
983 0, /* R_X86_64_DTPOFF32 */
984 0, /* R_X86_64_GOTTPOFF */
985 0, /* R_X86_64_TPOFF32 */
986};
987
988/** Macro for getting the size of a AMD64 ELF relocation. */
989#define ELF_AMD64_RELOC_SIZE(a_Type) ( (a_Type) < RT_ELEMENTS(g_acbElfAmd64RelTypes) ? g_acbElfAmd64RelTypes[(a_Type)] : 1)
990
991
992typedef struct ELFDETAILS
993{
994 /** The ELF header. */
995 Elf64_Ehdr const *pEhdr;
996 /** The section header table. */
997 Elf64_Shdr const *paShdrs;
998 /** The string table for the section names. */
999 const char *pchShStrTab;
1000
1001 /** The symbol table section number. UINT16_MAX if not found. */
1002 uint16_t iSymSh;
1003 /** The string table section number. UINT16_MAX if not found. */
1004 uint16_t iStrSh;
1005
1006 /** The symbol table. */
1007 Elf64_Sym const *paSymbols;
1008 /** The number of symbols in the symbol table. */
1009 uint32_t cSymbols;
1010
1011 /** Pointer to the (symbol) string table if found. */
1012 const char *pchStrTab;
1013 /** The string table size. */
1014 size_t cbStrTab;
1015
1016} ELFDETAILS;
1017typedef ELFDETAILS *PELFDETAILS;
1018typedef ELFDETAILS const *PCELFDETAILS;
1019
1020
1021static bool validateElf(const char *pszFile, uint8_t const *pbFile, size_t cbFile, PELFDETAILS pElfStuff)
1022{
1023 /*
1024 * Initialize the ELF details structure.
1025 */
1026 memset(pElfStuff, 0, sizeof(*pElfStuff));
1027 pElfStuff->iSymSh = UINT16_MAX;
1028 pElfStuff->iStrSh = UINT16_MAX;
1029
1030 /*
1031 * Validate the header and our other expectations.
1032 */
1033 Elf64_Ehdr const *pEhdr = (Elf64_Ehdr const *)pbFile;
1034 pElfStuff->pEhdr = pEhdr;
1035 if ( pEhdr->e_ident[EI_CLASS] != ELFCLASS64
1036 || pEhdr->e_ident[EI_DATA] != ELFDATA2LSB
1037 || pEhdr->e_ehsize != sizeof(Elf64_Ehdr)
1038 || pEhdr->e_shentsize != sizeof(Elf64_Shdr)
1039 || pEhdr->e_version != EV_CURRENT )
1040 return error(pszFile, "Unsupported ELF config\n");
1041 if (pEhdr->e_type != ET_REL)
1042 return error(pszFile, "Expected relocatable ELF file (e_type=%d)\n", pEhdr->e_type);
1043 if (pEhdr->e_machine != EM_X86_64)
1044 return error(pszFile, "Expected relocatable ELF file (e_type=%d)\n", pEhdr->e_machine);
1045 if (pEhdr->e_phnum != 0)
1046 return error(pszFile, "Expected e_phnum to be zero not %u\n", pEhdr->e_phnum);
1047 if (pEhdr->e_shnum < 2)
1048 return error(pszFile, "Expected e_shnum to be two or higher\n");
1049 if (pEhdr->e_shstrndx >= pEhdr->e_shnum || pEhdr->e_shstrndx == 0)
1050 return error(pszFile, "Bad e_shstrndx=%u (e_shnum=%u)\n", pEhdr->e_shstrndx, pEhdr->e_shnum);
1051 if ( pEhdr->e_shoff >= cbFile
1052 || pEhdr->e_shoff + pEhdr->e_shnum * sizeof(Elf64_Shdr) > cbFile)
1053 return error(pszFile, "Section table is outside the file (e_shoff=%#llx, e_shnum=%u, cbFile=%#llx)\n",
1054 pEhdr->e_shstrndx, pEhdr->e_shnum, (uint64_t)cbFile);
1055
1056 /*
1057 * Locate the section name string table.
1058 * We assume it's okay as we only reference it in verbose mode.
1059 */
1060 Elf64_Shdr const *paShdrs = (Elf64_Shdr const *)&pbFile[pEhdr->e_shoff];
1061 pElfStuff->paShdrs = paShdrs;
1062
1063 Elf64_Xword const cbShStrTab = paShdrs[pEhdr->e_shstrndx].sh_size;
1064 if ( paShdrs[pEhdr->e_shstrndx].sh_offset > cbFile
1065 || cbShStrTab > cbFile
1066 || paShdrs[pEhdr->e_shstrndx].sh_offset + cbShStrTab > cbFile)
1067 return error(pszFile,
1068 "Section string table is outside the file (sh_offset=%#" ELF_FMT_X64 " sh_size=%#" ELF_FMT_X64 " cbFile=%#" ELF_FMT_X64 ")\n",
1069 paShdrs[pEhdr->e_shstrndx].sh_offset, paShdrs[pEhdr->e_shstrndx].sh_size, (Elf64_Xword)cbFile);
1070 const char *pchShStrTab = (const char *)&pbFile[paShdrs[pEhdr->e_shstrndx].sh_offset];
1071 pElfStuff->pchShStrTab = pchShStrTab;
1072
1073 /*
1074 * Work the section table.
1075 */
1076 bool fRet = true;
1077 for (uint32_t i = 1; i < pEhdr->e_shnum; i++)
1078 {
1079 if (paShdrs[i].sh_name >= cbShStrTab)
1080 return error(pszFile, "Invalid sh_name value (%#x) for section #%u\n", paShdrs[i].sh_name, i);
1081 const char *pszShNm = &pchShStrTab[paShdrs[i].sh_name];
1082
1083 if ( paShdrs[i].sh_offset > cbFile
1084 || paShdrs[i].sh_size > cbFile
1085 || paShdrs[i].sh_offset + paShdrs[i].sh_size > cbFile)
1086 return error(pszFile, "Section #%u '%s' has data outside the file: %#" ELF_FMT_X64 " LB %#" ELF_FMT_X64 " (cbFile=%#" ELF_FMT_X64 ")\n",
1087 i, pszShNm, paShdrs[i].sh_offset, paShdrs[i].sh_size, (Elf64_Xword)cbFile);
1088 if (g_cVerbose)
1089 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"
1090 " link=%u info=%#x align=%#" ELF_FMT_X64 " entsize=%#" ELF_FMT_X64 "\n",
1091 i, paShdrs[i].sh_name, pszShNm, paShdrs[i].sh_type, paShdrs[i].sh_flags,
1092 paShdrs[i].sh_addr, paShdrs[i].sh_offset, paShdrs[i].sh_size,
1093 paShdrs[i].sh_link, paShdrs[i].sh_info, paShdrs[i].sh_addralign, paShdrs[i].sh_entsize);
1094
1095 if (paShdrs[i].sh_link >= pEhdr->e_shnum)
1096 return error(pszFile, "Section #%u '%s' links to a section outside the section table: %#x, max %#x\n",
1097 i, pszShNm, paShdrs[i].sh_link, pEhdr->e_shnum);
1098 if (!RT_IS_POWER_OF_TWO(paShdrs[i].sh_addralign))
1099 return error(pszFile, "Section #%u '%s' alignment value is not a power of two: %#" ELF_FMT_X64 "\n",
1100 i, pszShNm, paShdrs[i].sh_addralign);
1101 if (!RT_IS_POWER_OF_TWO(paShdrs[i].sh_addralign))
1102 return error(pszFile, "Section #%u '%s' alignment value is not a power of two: %#" ELF_FMT_X64 "\n",
1103 i, pszShNm, paShdrs[i].sh_addralign);
1104 if (paShdrs[i].sh_addr != 0)
1105 return error(pszFile, "Section #%u '%s' has non-zero address: %#" ELF_FMT_X64 "\n", i, pszShNm, paShdrs[i].sh_addr);
1106
1107 if (paShdrs[i].sh_type == SHT_RELA)
1108 {
1109 if (paShdrs[i].sh_entsize != sizeof(Elf64_Rela))
1110 return error(pszFile, "Expected sh_entsize to be %u not %u for section #%u (%s)\n", (unsigned)sizeof(Elf64_Rela),
1111 paShdrs[i].sh_entsize, i, pszShNm);
1112 uint32_t const cRelocs = paShdrs[i].sh_size / sizeof(Elf64_Rela);
1113 if (cRelocs * sizeof(Elf64_Rela) != paShdrs[i].sh_size)
1114 return error(pszFile, "Uneven relocation entry count in #%u (%s): sh_size=%#" ELF_FMT_X64 "\n",
1115 i, pszShNm, paShdrs[i].sh_size);
1116 if ( paShdrs[i].sh_offset > cbFile
1117 || paShdrs[i].sh_size >= cbFile
1118 || paShdrs[i].sh_offset + paShdrs[i].sh_size > cbFile)
1119 return error(pszFile, "The content of section #%u '%s' is outside the file (%#" ELF_FMT_X64 " LB %#" ELF_FMT_X64 ", cbFile=%#lx)\n",
1120 i, pszShNm, paShdrs[i].sh_offset, paShdrs[i].sh_size, (unsigned long)cbFile);
1121 if (paShdrs[i].sh_info != i - 1)
1122 return error(pszFile, "Expected relocation section #%u (%s) to link to previous section: sh_info=%#u\n",
1123 i, pszShNm, (unsigned)paShdrs[i].sh_link);
1124 if (paShdrs[paShdrs[i].sh_link].sh_type != SHT_SYMTAB)
1125 return error(pszFile, "Expected relocation section #%u (%s) to link to symbol table: sh_link=%#u -> sh_type=%#x\n",
1126 i, pszShNm, (unsigned)paShdrs[i].sh_link, (unsigned)paShdrs[paShdrs[i].sh_link].sh_type);
1127 uint32_t cSymbols = paShdrs[paShdrs[i].sh_link].sh_size / paShdrs[paShdrs[i].sh_link].sh_entsize;
1128
1129 Elf64_Rela const *paRelocs = (Elf64_Rela *)&pbFile[paShdrs[i].sh_offset];
1130 for (uint32_t j = 0; j < cRelocs; j++)
1131 {
1132 uint8_t const bType = ELF64_R_TYPE(paRelocs[j].r_info);
1133 if (RT_UNLIKELY(bType >= R_X86_64_COUNT))
1134 fRet = error(pszFile,
1135 "%#018" ELF_FMT_X64 " %#018" ELF_FMT_X64 ": unknown fix up %#x (%+" ELF_FMT_D64 ")\n",
1136 paRelocs[j].r_offset, paRelocs[j].r_info, bType, paRelocs[j].r_addend);
1137 if (RT_UNLIKELY( paRelocs[j].r_offset > paShdrs[i - 1].sh_size
1138 || paRelocs[j].r_offset + ELF_AMD64_RELOC_SIZE(ELF64_R_TYPE(paRelocs[j].r_info))
1139 > paShdrs[i - 1].sh_size))
1140 fRet = error(pszFile,
1141 "%#018" ELF_FMT_X64 " %#018" ELF_FMT_X64 ": out of bounds (sh_size %" ELF_FMT_X64 ")\n",
1142 paRelocs[j].r_offset, paRelocs[j].r_info, paShdrs[i - 1].sh_size);
1143
1144 uint32_t const iSymbol = ELF64_R_SYM(paRelocs[j].r_info);
1145 if (RT_UNLIKELY(iSymbol >= cSymbols))
1146 fRet = error(pszFile,
1147 "%#018" ELF_FMT_X64 " %#018" ELF_FMT_X64 ": symbol index (%#x) out of bounds (%#x)\n",
1148 paRelocs[j].r_offset, paRelocs[j].r_info, iSymbol, cSymbols);
1149 }
1150 }
1151 else if (paShdrs[i].sh_type == SHT_REL)
1152 fRet = error(pszFile, "Section #%u '%s': Unexpected SHT_REL section\n", i, pszShNm);
1153 else if (paShdrs[i].sh_type == SHT_SYMTAB)
1154 {
1155 if (paShdrs[i].sh_entsize != sizeof(Elf64_Sym))
1156 fRet = error(pszFile, "Section #%u '%s': Unsupported symbol table entry size in : #%u (expected #%u)\n",
1157 i, pszShNm, paShdrs[i].sh_entsize, sizeof(Elf64_Sym));
1158 Elf64_Xword const cSymbols = paShdrs[i].sh_size / paShdrs[i].sh_entsize;
1159 if (cSymbols * paShdrs[i].sh_entsize != paShdrs[i].sh_size)
1160 fRet = error(pszFile, "Section #%u '%s': Size not a multiple of entry size: %#" ELF_FMT_X64 " %% %#" ELF_FMT_X64 " = %#" ELF_FMT_X64 "\n",
1161 i, pszShNm, paShdrs[i].sh_size, paShdrs[i].sh_entsize, paShdrs[i].sh_size % paShdrs[i].sh_entsize);
1162 if (cSymbols > UINT32_MAX)
1163 fRet = error(pszFile, "Section #%u '%s': too many symbols: %" ELF_FMT_X64 "\n",
1164 i, pszShNm, paShdrs[i].sh_size, cSymbols);
1165
1166 if (pElfStuff->iSymSh == UINT16_MAX)
1167 {
1168 pElfStuff->iSymSh = (uint16_t)i;
1169 pElfStuff->paSymbols = (Elf64_Sym const *)&pbFile[paShdrs[i].sh_offset];
1170 pElfStuff->cSymbols = cSymbols;
1171
1172 if (paShdrs[i].sh_link != 0)
1173 {
1174 /* Note! The symbol string table section header may not have been validated yet! */
1175 Elf64_Shdr const *pStrTabShdr = &paShdrs[paShdrs[i].sh_link];
1176 pElfStuff->iStrSh = paShdrs[i].sh_link;
1177 pElfStuff->pchStrTab = (const char *)&pbFile[pStrTabShdr->sh_offset];
1178 pElfStuff->cbStrTab = (size_t)pStrTabShdr->sh_size;
1179 }
1180 else
1181 fRet = error(pszFile, "Section #%u '%s': String table link is out of bounds (%#x)\n",
1182 i, pszShNm, paShdrs[i].sh_link);
1183 }
1184 else
1185 fRet = error(pszFile, "Section #%u '%s': Found additonal symbol table, previous in #%u\n",
1186 i, pszShNm, pElfStuff->iSymSh);
1187 }
1188 }
1189 return fRet;
1190}
1191
1192
1193static bool convertElfSectionsToSegDefsAndGrpDefs(POMFWRITER pThis, PCELFDETAILS pElfStuff)
1194{
1195 /*
1196 * Do the list of names pass.
1197 */
1198 uint16_t idxGrpFlat, idxGrpData;
1199 uint16_t idxClassCode, idxClassData, idxClassDwarf;
1200 if ( !omfWriter_LNamesBegin(pThis, true /*fAddZeroEntry*/)
1201 || !omfWriter_LNamesAddN(pThis, RT_STR_TUPLE("FLAT"), &idxGrpFlat)
1202 || !omfWriter_LNamesAddN(pThis, RT_STR_TUPLE("BS3DATA64_GROUP"), &idxGrpData)
1203 || !omfWriter_LNamesAddN(pThis, RT_STR_TUPLE("BS3CLASS64CODE"), &idxClassCode)
1204 || !omfWriter_LNamesAddN(pThis, RT_STR_TUPLE("FAR_DATA"), &idxClassData)
1205 || !omfWriter_LNamesAddN(pThis, RT_STR_TUPLE("DWARF"), &idxClassDwarf)
1206 )
1207 return false;
1208
1209 bool fHaveData = false;
1210 Elf64_Shdr const *pShdr = &pElfStuff->paShdrs[1];
1211 Elf64_Half const cSections = pElfStuff->pEhdr->e_shnum;
1212 for (Elf64_Half i = 1; i < cSections; i++, pShdr++)
1213 {
1214 const char *pszName = &pElfStuff->pchShStrTab[pShdr->sh_name];
1215 if (*pszName == '\0')
1216 return error(pThis->pszSrc, "Section #%u has an empty name!\n", i);
1217
1218 switch (pShdr->sh_type)
1219 {
1220 case SHT_PROGBITS:
1221 case SHT_NOBITS:
1222 /* We drop a few sections we don't want:. */
1223 if ( strcmp(pszName, ".comment") != 0 /* compiler info */
1224 && strcmp(pszName, ".note.GNU-stack") != 0 /* some empty section for hinting the linker/whatever */
1225 && strcmp(pszName, ".eh_frame") != 0 /* unwind / exception info */
1226 )
1227 {
1228 pThis->paSegments[i].iSegDef = UINT16_MAX;
1229 pThis->paSegments[i].iGrpDef = UINT16_MAX;
1230
1231 /* Translate the name and determine group and class.
1232 Note! We currently strip sub-sections. */
1233 if ( strcmp(pszName, ".text") == 0
1234 || strncmp(pszName, RT_STR_TUPLE(".text.")) == 0)
1235 {
1236 pszName = "BS3TEXT64";
1237 pThis->paSegments[i].iGrpNm = idxGrpFlat;
1238 pThis->paSegments[i].iClassNm = idxClassCode;
1239 }
1240 else if ( strcmp(pszName, ".data") == 0
1241 || strncmp(pszName, RT_STR_TUPLE(".data.")) == 0)
1242 {
1243 pszName = "BS3DATA64";
1244 pThis->paSegments[i].iGrpNm = idxGrpData;
1245 pThis->paSegments[i].iClassNm = idxClassData;
1246 }
1247 else if (strcmp(pszName, ".bss") == 0)
1248 {
1249 pszName = "BS3BSS64";
1250 pThis->paSegments[i].iGrpNm = idxGrpData;
1251 pThis->paSegments[i].iClassNm = idxClassData;
1252 }
1253 else if ( strcmp(pszName, ".rodata") == 0
1254 || strncmp(pszName, RT_STR_TUPLE(".rodata.")) == 0)
1255 {
1256 pszName = "BS3DATA64CONST";
1257 pThis->paSegments[i].iGrpNm = idxGrpData;
1258 pThis->paSegments[i].iClassNm = idxClassData;
1259 }
1260 else if (strncmp(pszName, RT_STR_TUPLE(".debug_")) == 0)
1261 {
1262 pThis->paSegments[i].iGrpNm = UINT16_MAX;
1263 pThis->paSegments[i].iClassNm = idxClassDwarf;
1264 }
1265 else
1266 {
1267 pThis->paSegments[i].iGrpNm = idxGrpData;
1268 pThis->paSegments[i].iClassNm = idxClassData;
1269 error(pThis->pszSrc, "Unknown data (?) segment: '%s'\n", pszName);
1270 }
1271
1272 /* Save the name. */
1273 pThis->paSegments[i].pszName = strdup(pszName);
1274 if (!pThis->paSegments[i].pszName)
1275 return error(pThis->pszSrc, "Out of memory!\n");
1276
1277 /* Add the section name. */
1278 if (!omfWriter_LNamesAdd(pThis, pThis->paSegments[i].pszName, &pThis->paSegments[i].iSegNm))
1279 return false;
1280
1281 fHaveData |= pThis->paSegments[i].iGrpNm == idxGrpData;
1282 break;
1283 }
1284 /* fall thru */
1285
1286 default:
1287 pThis->paSegments[i].iSegDef = UINT16_MAX;
1288 pThis->paSegments[i].iGrpDef = UINT16_MAX;
1289 pThis->paSegments[i].iSegNm = UINT16_MAX;
1290 pThis->paSegments[i].iGrpNm = UINT16_MAX;
1291 pThis->paSegments[i].iClassNm = UINT16_MAX;
1292 pThis->paSegments[i].pszName = NULL;
1293 break;
1294 }
1295 }
1296
1297 if (!omfWriter_LNamesEnd(pThis))
1298 return false;
1299
1300 /*
1301 * Emit segment definitions.
1302 */
1303 uint16_t iSegDef = 1; /* Start counting at 1. */
1304 pShdr = &pElfStuff->paShdrs[1];
1305 for (Elf64_Half i = 1; i < cSections; i++, pShdr++)
1306 {
1307 if (pThis->paSegments[i].iSegNm == UINT16_MAX)
1308 continue;
1309
1310 uint8_t bSegAttr = 0;
1311
1312 /* The A field. */
1313 switch (pShdr->sh_addralign)
1314 {
1315 case 0:
1316 case 1:
1317 bSegAttr |= 1 << 5;
1318 break;
1319 case 2:
1320 bSegAttr |= 2 << 5;
1321 break;
1322 case 4:
1323 bSegAttr |= 5 << 5;
1324 break;
1325 case 8:
1326 case 16:
1327 bSegAttr |= 3 << 5;
1328 break;
1329 case 32:
1330 case 64:
1331 case 128:
1332 case 256:
1333 bSegAttr |= 4 << 5;
1334 break;
1335 default:
1336 bSegAttr |= 6 << 5; /* page aligned, pharlabs extension. */
1337 break;
1338 }
1339
1340 /* The C field. */
1341 bSegAttr |= 2 << 2; /* public */
1342
1343 /* The B field. We don't have 4GB segments, so leave it as zero. */
1344
1345 /* The D field shall be set as we're doing USE32. */
1346 bSegAttr |= 1;
1347
1348
1349 /* Done. */
1350 if (!omfWriter_SegDef(pThis, bSegAttr, (uint32_t)pShdr->sh_size,
1351 pThis->paSegments[i].iSegNm,
1352 pThis->paSegments[i].iClassNm))
1353 return false;
1354 pThis->paSegments[i].iSegDef = iSegDef++;
1355 }
1356
1357 /*
1358 * Flat group definition (#1) - special, no members.
1359 */
1360 uint16_t iGrpDef = 1;
1361 if ( !omfWriter_GrpDefBegin(pThis, idxGrpFlat)
1362 || !omfWriter_GrpDefEnd(pThis))
1363 return false;
1364 for (uint16_t i = 0; i < cSections; i++)
1365 if (pThis->paSegments[i].iGrpNm == idxGrpFlat)
1366 pThis->paSegments[i].iGrpDef = iGrpDef;
1367 pThis->idxGrpFlat = iGrpDef++;
1368
1369 /*
1370 * Data group definition (#2).
1371 */
1372 /** @todo do we need to consider missing segments and ordering? */
1373 uint16_t cGrpNms = 0;
1374 uint16_t aiGrpNms[2];
1375 if (fHaveData)
1376 aiGrpNms[cGrpNms++] = idxGrpData;
1377 for (uint32_t iGrpNm = 0; iGrpNm < cGrpNms; iGrpNm++)
1378 {
1379 if (!omfWriter_GrpDefBegin(pThis, aiGrpNms[iGrpNm]))
1380 return false;
1381 for (uint16_t i = 0; i < cSections; i++)
1382 if (pThis->paSegments[i].iGrpNm == aiGrpNms[iGrpNm])
1383 {
1384 pThis->paSegments[i].iGrpDef = iGrpDef;
1385 if (!omfWriter_GrpDefAddSegDef(pThis, pThis->paSegments[i].iSegDef))
1386 return false;
1387 }
1388 if (!omfWriter_GrpDefEnd(pThis))
1389 return false;
1390 iGrpDef++;
1391 }
1392
1393 return true;
1394}
1395
1396static bool convertElfSymbolsToPubDefsAndExtDefs(POMFWRITER pThis, PCELFDETAILS pElfStuff)
1397{
1398 if (!pElfStuff->cSymbols)
1399 return true;
1400
1401 /*
1402 * Process the symbols the first.
1403 */
1404 uint32_t cAbsSyms = 0;
1405 uint32_t cExtSyms = 0;
1406 uint32_t cPubSyms = 0;
1407 for (uint32_t iSeg = 0; iSeg < pThis->cSegments; iSeg++)
1408 pThis->paSegments[iSeg].cPubDefs = 0;
1409
1410 uint32_t const cSections = pElfStuff->pEhdr->e_shnum;
1411 uint32_t const cSymbols = pElfStuff->cSymbols;
1412 Elf64_Sym const * const paSymbols = pElfStuff->paSymbols;
1413 for (uint32_t iSym = 0; iSym < cSymbols; iSym++)
1414 {
1415 const uint8_t bBind = ELF64_ST_BIND(paSymbols[iSym].st_info);
1416 const uint8_t bType = ELF64_ST_TYPE(paSymbols[iSym].st_info);
1417 const char *pszSymName = &pElfStuff->pchStrTab[paSymbols[iSym].st_name];
1418 if ( *pszSymName == '\0'
1419 && bType == STT_SECTION
1420 && paSymbols[iSym].st_shndx < cSections)
1421 pszSymName = &pElfStuff->pchShStrTab[pElfStuff->paShdrs[paSymbols[iSym].st_shndx].sh_name];
1422
1423 pThis->paSymbols[iSym].enmType = OMFSYMTYPE_IGNORED;
1424 pThis->paSymbols[iSym].idx = UINT16_MAX;
1425 pThis->paSymbols[iSym].idxSegDef = UINT16_MAX;
1426 pThis->paSymbols[iSym].idxGrpDef = UINT16_MAX;
1427
1428 uint32_t const idxSection = paSymbols[iSym].st_shndx;
1429 if (idxSection == SHN_UNDEF)
1430 {
1431 if (bBind == STB_GLOBAL)
1432 {
1433 pThis->paSymbols[iSym].enmType = OMFSYMTYPE_EXTDEF;
1434 cExtSyms++;
1435 if (*pszSymName == '\0')
1436 return error(pThis->pszSrc, "External symbol #%u (%s) has an empty name.\n", iSym, pszSymName);
1437 }
1438 else if (bBind != STB_LOCAL || iSym != 0) /* Entry zero is usually a dummy. */
1439 return error(pThis->pszSrc, "Unsupported or invalid bind type %#x for undefined symbol #%u (%s)\n",
1440 bBind, iSym, pszSymName);
1441 }
1442 else if (idxSection < cSections)
1443 {
1444 pThis->paSymbols[iSym].idxSegDef = pThis->paSegments[idxSection].iSegDef;
1445 pThis->paSymbols[iSym].idxGrpDef = pThis->paSegments[idxSection].iGrpDef;
1446 if (bBind == STB_GLOBAL)
1447 {
1448 pThis->paSymbols[iSym].enmType = OMFSYMTYPE_PUBDEF;
1449 pThis->paSegments[idxSection].cPubDefs++;
1450 cPubSyms++;
1451 if (bType == STT_SECTION)
1452 return error(pThis->pszSrc, "Don't know how to export STT_SECTION symbol #%u (%s)\n", iSym, pszSymName);
1453 if (*pszSymName == '\0')
1454 return error(pThis->pszSrc, "Public symbol #%u (%s) has an empty name.\n", iSym, pszSymName);
1455 }
1456 else if (bType == STT_SECTION)
1457 pThis->paSymbols[iSym].enmType = OMFSYMTYPE_SEGDEF;
1458 else
1459 pThis->paSymbols[iSym].enmType = OMFSYMTYPE_INTERNAL;
1460 }
1461 else if (idxSection == SHN_ABS)
1462 {
1463 if (bType != STT_FILE)
1464 {
1465 if (bBind == STB_GLOBAL)
1466 {
1467 pThis->paSymbols[iSym].enmType = OMFSYMTYPE_PUBDEF;
1468 pThis->paSymbols[iSym].idxSegDef = 0;
1469 pThis->paSymbols[iSym].idxGrpDef = 0;
1470 cAbsSyms++;
1471 if (*pszSymName == '\0')
1472 return error(pThis->pszSrc, "Public absolute symbol #%u (%s) has an empty name.\n", iSym, pszSymName);
1473 }
1474 else
1475 return error(pThis->pszSrc, "Unsupported or invalid bind type %#x for absolute symbol #%u (%s)\n",
1476 bBind, iSym, pszSymName);
1477 }
1478 }
1479 else
1480 return error(pThis->pszSrc, "Unsupported or invalid section number %#x for symbol #%u (%s)\n",
1481 idxSection, iSym, pszSymName);
1482 }
1483
1484 /*
1485 * Emit the PUBDEFs the first time around (see order of records in TIS spec).
1486 */
1487 uint16_t idxPubDef = 1;
1488 if (cPubSyms)
1489 {
1490 for (uint32_t iSeg = 0; iSeg < pThis->cSegments; iSeg++)
1491 if (pThis->paSegments[iSeg].cPubDefs > 0)
1492 {
1493 uint16_t const idxSegDef = pThis->paSegments[iSeg].iSegDef;
1494 if (!omfWriter_PubDefBegin(pThis, pThis->paSegments[iSeg].iGrpDef, idxSegDef))
1495 return false;
1496 for (uint16_t iSym = 0; iSym < cSymbols; iSym++)
1497 if ( pThis->paSymbols[iSym].idxSegDef == idxSegDef
1498 && pThis->paSymbols[iSym].enmType == OMFSYMTYPE_PUBDEF)
1499 {
1500 const char *pszName = &pElfStuff->pchStrTab[paSymbols[iSym].st_name];
1501 if (!omfWriter_PubDefAdd(pThis, paSymbols[iSym].st_value, pszName))
1502 return false;
1503
1504 /* If the symbol doesn't start with an underscore and is a _c64 or _lm64 symbol,
1505 add an underscore prefixed alias to ease access from 16-bit and 32-bit code. */
1506 size_t cchName = strlen(pszName);
1507 if ( *pszName != '_'
1508 && ( (cchName > 4 && strcmp(&pszName[cchName - 4], "_c64") == 0)
1509 || (cchName > 5 && strcmp(&pszName[cchName - 5], "_lm64") == 0) ) )
1510 {
1511 char szCdeclName[512];
1512 if (cchName > sizeof(szCdeclName) - 2)
1513 cchName = sizeof(szCdeclName) - 2;
1514 szCdeclName[0] = '_';
1515 memcpy(&szCdeclName[1], pszName, cchName);
1516 szCdeclName[cchName + 1] = '\0';
1517 if (!omfWriter_PubDefAdd(pThis, paSymbols[iSym].st_value, szCdeclName))
1518 return false;
1519 }
1520
1521 pThis->paSymbols[iSym].idx = idxPubDef++;
1522 }
1523 if (!omfWriter_PubDefEnd(pThis))
1524 return false;
1525 }
1526 }
1527
1528 if (cAbsSyms > 0)
1529 {
1530 if (!omfWriter_PubDefBegin(pThis, 0, 0))
1531 return false;
1532 for (uint16_t iSym = 0; iSym < cSymbols; iSym++)
1533 if ( pThis->paSymbols[iSym].idxSegDef == 0
1534 && pThis->paSymbols[iSym].enmType == OMFSYMTYPE_PUBDEF)
1535 {
1536 const char *pszName = &pElfStuff->pchStrTab[paSymbols[iSym].st_name];
1537 if (!omfWriter_PubDefAdd(pThis, paSymbols[iSym].st_value, pszName))
1538 return false;
1539 pThis->paSymbols[iSym].idx = idxPubDef++;
1540 }
1541 if (!omfWriter_PubDefEnd(pThis))
1542 return false;
1543 }
1544
1545 /*
1546 * Go over the symbol table and emit external definition records.
1547 */
1548 if (!omfWriter_ExtDefBegin(pThis))
1549 return false;
1550 uint16_t idxExtDef = 1;
1551 for (uint16_t iSym = 0; iSym < cSymbols; iSym++)
1552 if (pThis->paSymbols[iSym].enmType == OMFSYMTYPE_EXTDEF)
1553 {
1554 const char *pszName = &pElfStuff->pchStrTab[paSymbols[iSym].st_name];
1555 if (!omfWriter_ExtDefAdd(pThis, pszName))
1556 return false;
1557 pThis->paSymbols[iSym].idx = idxExtDef++;
1558 }
1559
1560 if (!omfWriter_ExtDefEnd(pThis))
1561 return false;
1562
1563 return true;
1564}
1565
1566/**
1567 * @callback_method_impl{FNRTSORTCMP, For Elf64_Rela tables.}
1568 */
1569static DECLCALLBACK(int) convertElfCompareRelA(void const *pvElement1, void const *pvElement2, void *pvUser)
1570{
1571 Elf64_Rela const *pReloc1 = (Elf64_Rela const *)pvElement1;
1572 Elf64_Rela const *pReloc2 = (Elf64_Rela const *)pvElement2;
1573 if (pReloc1->r_offset < pReloc2->r_offset)
1574 return -1;
1575 if (pReloc1->r_offset > pReloc2->r_offset)
1576 return 1;
1577 return 0;
1578}
1579
1580static bool convertElfSectionsToLeDataAndFixupps(POMFWRITER pThis, PCELFDETAILS pElfStuff, uint8_t const *pbFile, size_t cbFile)
1581{
1582 Elf64_Sym const *paSymbols = pElfStuff->paSymbols;
1583 Elf64_Shdr const *paShdrs = pElfStuff->paShdrs;
1584 bool fRet = true;
1585 for (uint32_t i = 1; i < pThis->cSegments; i++)
1586 {
1587 if (pThis->paSegments[i].iSegDef == UINT16_MAX)
1588 continue;
1589
1590 const char *pszSegNm = &pElfStuff->pchShStrTab[paShdrs[i].sh_name];
1591 bool const fRelocs = i + 1 < pThis->cSegments && paShdrs[i + 1].sh_type == SHT_RELA;
1592 uint32_t cRelocs = fRelocs ? paShdrs[i + 1].sh_size / sizeof(Elf64_Rela) : 0;
1593 Elf64_Rela const *paRelocs = fRelocs ? (Elf64_Rela *)&pbFile[paShdrs[i + 1].sh_offset] : NULL;
1594 Elf64_Xword cbVirtData = paShdrs[i].sh_size;
1595 Elf64_Xword cbData = paShdrs[i].sh_type == SHT_NOBITS ? 0 : cbVirtData;
1596 uint8_t const *pbData = &pbFile[paShdrs[i].sh_offset];
1597 uint32_t off = 0;
1598
1599 /* We sort fixups by r_offset in order to more easily split them into chunks. */
1600 RTSortShell((void *)paRelocs, cRelocs, sizeof(paRelocs[0]), convertElfCompareRelA, NULL);
1601
1602 /* The OMF record size requires us to split larger sections up. To make
1603 life simple, we fill zeros for unitialized (BSS) stuff. */
1604 const uint32_t cbMaxData = RT_MIN(OMF_MAX_RECORD_PAYLOAD - 1 - (pThis->paSegments[i].iSegDef >= 128) - 4 - 1, _1K);
1605 while (cbVirtData > 0)
1606 {
1607 /* Figure out how many bytes to put out in this chunk. Must make sure
1608 fixups doesn't cross chunk boundraries. ASSUMES sorted relocs. */
1609 uint32_t cChunkRelocs = cRelocs;
1610 uint32_t cbChunk = cbVirtData;
1611 uint32_t offEnd = off + cbChunk;
1612 if (cbChunk > cbMaxData)
1613 {
1614 cbChunk = cbMaxData;
1615 offEnd = off + cbChunk;
1616 cChunkRelocs = 0;
1617
1618 /* Quickly determin the reloc range. */
1619 while ( cChunkRelocs < cRelocs
1620 && paRelocs[cChunkRelocs].r_offset < offEnd)
1621 cChunkRelocs++;
1622
1623 /* Ensure final reloc doesn't go beyond chunk. */
1624 while ( cChunkRelocs > 0
1625 && paRelocs[cChunkRelocs - 1].r_offset
1626 + ELF_AMD64_RELOC_SIZE(ELF64_R_TYPE(paRelocs[cChunkRelocs - 1].r_info))
1627 > offEnd)
1628 {
1629 uint32_t cbDrop = offEnd - paRelocs[cChunkRelocs - 1].r_offset;
1630 cbChunk -= cbDrop;
1631 offEnd -= cbDrop;
1632 cChunkRelocs--;
1633 }
1634
1635 if (!cbVirtData)
1636 return error(pThis->pszSrc, "Wtf? cbVirtData is zero!\n");
1637 }
1638 if (g_cVerbose >= 2)
1639 printf("debug: LEDATA off=%#x cb=%#x cRelocs=%#x sect=#%u segdef=%#x grpdef=%#x '%s'\n",
1640 off, cbChunk, cRelocs, i, pThis->paSegments[i].iSegDef, pThis->paSegments[i].iGrpDef, pszSegNm);
1641
1642 /*
1643 * We stash the bytes into the OMF writer record buffer, receiving a
1644 * pointer to the start of it so we can make adjustments if necessary.
1645 */
1646 uint8_t *pbCopy;
1647 if (!omfWriter_LEDataBeginEx(pThis, pThis->paSegments[i].iSegDef, off, cbChunk, cbData, pbData, &pbCopy))
1648 return false;
1649
1650 /*
1651 * Convert fiuxps.
1652 */
1653 for (uint32_t iReloc = 0; iReloc < cChunkRelocs; iReloc++)
1654 {
1655 /* Get the OMF and ELF data for the symbol the reloc references. */
1656 uint32_t const uType = ELF64_R_TYPE(paRelocs[iReloc].r_info);
1657 uint32_t const iSymbol = ELF64_R_SYM(paRelocs[iReloc].r_info);
1658 Elf64_Sym const * const pElfSym = &paSymbols[iSymbol];
1659 POMFSYMBOL const pOmfSym = &pThis->paSymbols[iSymbol];
1660 const char * const pszSymName = &pElfStuff->pchStrTab[pElfSym->st_name];
1661
1662 /* Calc fixup location in the pending chunk and setup a flexible pointer to it. */
1663 uint16_t offDataRec = (uint16_t)(paRelocs[iReloc].r_offset - off);
1664 RTPTRUNION uLoc;
1665 uLoc.pu8 = &pbCopy[offDataRec];
1666
1667 /* OMF fixup data initialized with typical defaults. */
1668 bool fSelfRel = true;
1669 uint8_t bLocation = OMF_FIX_LOC_32BIT_OFFSET;
1670 uint8_t bFrame = OMF_FIX_F_GRPDEF;
1671 uint16_t idxFrame = pThis->idxGrpFlat;
1672 uint8_t bTarget;
1673 uint16_t idxTarget;
1674 bool fTargetDisp;
1675 uint32_t offTargetDisp;
1676 switch (pOmfSym->enmType)
1677 {
1678 case OMFSYMTYPE_INTERNAL:
1679 case OMFSYMTYPE_PUBDEF:
1680 bTarget = OMF_FIX_T_SEGDEF;
1681 idxTarget = pOmfSym->idxSegDef;
1682 fTargetDisp = true;
1683 offTargetDisp = pElfSym->st_value;
1684 break;
1685
1686 case OMFSYMTYPE_SEGDEF:
1687 bTarget = OMF_FIX_T_SEGDEF_NO_DISP;
1688 idxTarget = pOmfSym->idxSegDef;
1689 fTargetDisp = false;
1690 offTargetDisp = 0;
1691 break;
1692
1693 case OMFSYMTYPE_EXTDEF:
1694 bTarget = OMF_FIX_T_EXTDEF_NO_DISP;
1695 idxTarget = pOmfSym->idx;
1696 fTargetDisp = false;
1697 offTargetDisp = 0;
1698 break;
1699
1700 default:
1701 return error(pThis->pszSrc, "Relocation in segment #%u '%s' references ignored or invalid symbol (%s)\n",
1702 i, pszSegNm, pszSymName);
1703 }
1704
1705 /* Do COFF relocation type conversion. */
1706 switch (uType)
1707 {
1708 case R_X86_64_64:
1709 {
1710 int64_t iAddend = paRelocs[iReloc].r_addend;
1711 if (iAddend > _1G || iAddend < -_1G)
1712 fRet = error(pThis->pszSrc, "R_X86_64_64 with large addend (%" ELF_FMT_D64 ") at %#x in segment #%u '%s'\n",
1713 iAddend, paRelocs[iReloc].r_offset, i, pszSegNm);
1714 *uLoc.pu64 = iAddend;
1715 fSelfRel = false;
1716 break;
1717 }
1718
1719 case R_X86_64_32:
1720 case R_X86_64_32S: /* signed, unsigned, whatever. */
1721 fSelfRel = false;
1722 /* fall thru */
1723 case R_X86_64_PC32:
1724 {
1725 /* defaults are ok, just handle the addend. */
1726 int32_t iAddend = paRelocs[iReloc].r_addend;
1727 if (iAddend != paRelocs[iReloc].r_addend)
1728 fRet = error(pThis->pszSrc, "R_X86_64_PC32 with large addend (%d) at %#x in segment #%u '%s'\n",
1729 iAddend, paRelocs[iReloc].r_offset, i, pszSegNm);
1730 *uLoc.pu32 = iAddend;
1731 break;
1732 }
1733
1734 case R_X86_64_NONE:
1735 continue; /* Ignore this one */
1736
1737 case R_X86_64_GOT32:
1738 case R_X86_64_PLT32:
1739 case R_X86_64_COPY:
1740 case R_X86_64_GLOB_DAT:
1741 case R_X86_64_JMP_SLOT:
1742 case R_X86_64_RELATIVE:
1743 case R_X86_64_GOTPCREL:
1744 case R_X86_64_16:
1745 case R_X86_64_PC16:
1746 case R_X86_64_8:
1747 case R_X86_64_PC8:
1748 case R_X86_64_DTPMOD64:
1749 case R_X86_64_DTPOFF64:
1750 case R_X86_64_TPOFF64:
1751 case R_X86_64_TLSGD:
1752 case R_X86_64_TLSLD:
1753 case R_X86_64_DTPOFF32:
1754 case R_X86_64_GOTTPOFF:
1755 case R_X86_64_TPOFF32:
1756 default:
1757 return error(pThis->pszSrc, "Unsupported fixup type %#x (%s) at rva=%#x in section #%u '%s' against '%s'\n",
1758 uType, g_apszElfAmd64RelTypes[uType], paRelocs[iReloc].r_offset, i, pszSegNm, pszSymName);
1759 }
1760
1761 /* Add the fixup. */
1762 if (idxFrame == UINT16_MAX)
1763 error(pThis->pszSrc, "idxFrame=UINT16_MAX for %s type=%s\n", pszSymName, g_apszElfAmd64RelTypes[uType]);
1764 fRet = omfWriter_LEDataAddFixup(pThis, offDataRec, fSelfRel, bLocation, bFrame, idxFrame,
1765 bTarget, idxTarget, fTargetDisp, offTargetDisp) && fRet;
1766 }
1767
1768 /*
1769 * Write the LEDATA and associated FIXUPPs.
1770 */
1771 if (!omfWriter_LEDataEnd(pThis))
1772 return false;
1773
1774 /*
1775 * Advance.
1776 */
1777 paRelocs += cChunkRelocs;
1778 cRelocs -= cChunkRelocs;
1779 if (cbData > cbChunk)
1780 {
1781 cbData -= cbChunk;
1782 pbData += cbChunk;
1783 }
1784 else
1785 cbData = 0;
1786 off += cbChunk;
1787 cbVirtData -= cbChunk;
1788 }
1789 }
1790
1791 return fRet;
1792}
1793
1794
1795static bool convertElfToOmf(const char *pszFile, uint8_t const *pbFile, size_t cbFile, FILE *pDst)
1796{
1797 /*
1798 * Validate the source file a little.
1799 */
1800 ELFDETAILS ElfStuff;
1801 if (!validateElf(pszFile, pbFile, cbFile, &ElfStuff))
1802 return false;
1803
1804 /*
1805 * Instantiate the OMF writer.
1806 */
1807 POMFWRITER pThis = omfWriter_Create(pszFile, ElfStuff.pEhdr->e_shnum, ElfStuff.cSymbols, pDst);
1808 if (!pThis)
1809 return false;
1810
1811 /*
1812 * Write the OMF object file.
1813 */
1814 if (omfWriter_BeginModule(pThis, pszFile))
1815 {
1816 Elf64_Ehdr const *pEhdr = (Elf64_Ehdr const *)pbFile;
1817 Elf64_Shdr const *paShdrs = (Elf64_Shdr const *)&pbFile[pEhdr->e_shoff];
1818 const char *pszStrTab = (const char *)&pbFile[paShdrs[pEhdr->e_shstrndx].sh_offset];
1819
1820 if ( convertElfSectionsToSegDefsAndGrpDefs(pThis, &ElfStuff)
1821 && convertElfSymbolsToPubDefsAndExtDefs(pThis, &ElfStuff)
1822 && omfWriter_LinkPassSeparator(pThis)
1823 && convertElfSectionsToLeDataAndFixupps(pThis, &ElfStuff, pbFile, cbFile)
1824 && omfWriter_EndModule(pThis) )
1825 {
1826
1827 omfWriter_Destroy(pThis);
1828 return true;
1829 }
1830 }
1831
1832 omfWriter_Destroy(pThis);
1833 return false;
1834}
1835
1836
1837
1838/*********************************************************************************************************************************
1839* COFF -> OMF Converter *
1840*********************************************************************************************************************************/
1841
1842/** AMD64 relocation type names for (Microsoft) COFF. */
1843static const char * const g_apszCoffAmd64RelTypes[] =
1844{
1845 "ABSOLUTE",
1846 "ADDR64",
1847 "ADDR32",
1848 "ADDR32NB",
1849 "REL32",
1850 "REL32_1",
1851 "REL32_2",
1852 "REL32_3",
1853 "REL32_4",
1854 "REL32_5",
1855 "SECTION",
1856 "SECREL",
1857 "SECREL7",
1858 "TOKEN",
1859 "SREL32",
1860 "PAIR",
1861 "SSPAN32"
1862};
1863
1864/** AMD64 relocation type sizes for (Microsoft) COFF. */
1865static uint8_t const g_acbCoffAmd64RelTypes[] =
1866{
1867 8, /* ABSOLUTE */
1868 8, /* ADDR64 */
1869 4, /* ADDR32 */
1870 4, /* ADDR32NB */
1871 4, /* REL32 */
1872 4, /* REL32_1 */
1873 4, /* REL32_2 */
1874 4, /* REL32_3 */
1875 4, /* REL32_4 */
1876 4, /* REL32_5 */
1877 2, /* SECTION */
1878 4, /* SECREL */
1879 1, /* SECREL7 */
1880 0, /* TOKEN */
1881 4, /* SREL32 */
1882 0, /* PAIR */
1883 4, /* SSPAN32 */
1884};
1885
1886/** Macro for getting the size of a AMD64 COFF relocation. */
1887#define COFF_AMD64_RELOC_SIZE(a_Type) ( (a_Type) < RT_ELEMENTS(g_acbCoffAmd64RelTypes) ? g_acbCoffAmd64RelTypes[(a_Type)] : 1)
1888
1889
1890static const char *coffGetSymbolName(PCIMAGE_SYMBOL pSym, const char *pchStrTab, uint32_t cbStrTab, char pszShortName[16])
1891{
1892 if (pSym->N.Name.Short != 0)
1893 {
1894 memcpy(pszShortName, pSym->N.ShortName, 8);
1895 pszShortName[8] = '\0';
1896 return pszShortName;
1897 }
1898 if (pSym->N.Name.Long < cbStrTab)
1899 {
1900 uint32_t const cbLeft = cbStrTab - pSym->N.Name.Long;
1901 const char *pszRet = pchStrTab + pSym->N.Name.Long;
1902 if (memchr(pszRet, '\0', cbLeft) != NULL)
1903 return pszRet;
1904 }
1905 error("<null>", "Invalid string table index %#x!\n", pSym->N.Name.Long);
1906 return "Invalid Symbol Table Entry";
1907}
1908
1909static bool validateCoff(const char *pszFile, uint8_t const *pbFile, size_t cbFile)
1910{
1911 /*
1912 * Validate the header and our other expectations.
1913 */
1914 PIMAGE_FILE_HEADER pHdr = (PIMAGE_FILE_HEADER)pbFile;
1915 if (pHdr->Machine != IMAGE_FILE_MACHINE_AMD64)
1916 return error(pszFile, "Expected IMAGE_FILE_MACHINE_AMD64 not %#x\n", pHdr->Machine);
1917 if (pHdr->SizeOfOptionalHeader != 0)
1918 return error(pszFile, "Expected SizeOfOptionalHeader to be zero, not %#x\n", pHdr->SizeOfOptionalHeader);
1919 if (pHdr->NumberOfSections == 0)
1920 return error(pszFile, "Expected NumberOfSections to be non-zero\n");
1921 uint32_t const cbHeaders = pHdr->NumberOfSections * sizeof(IMAGE_SECTION_HEADER) + sizeof(*pHdr);
1922 if (cbHeaders > cbFile)
1923 return error(pszFile, "Section table goes beyond the end of the of the file (cSections=%#x)\n", pHdr->NumberOfSections);
1924 if (pHdr->NumberOfSymbols)
1925 {
1926 if ( pHdr->PointerToSymbolTable >= cbFile
1927 || pHdr->NumberOfSymbols * (uint64_t)IMAGE_SIZE_OF_SYMBOL > cbFile)
1928 return error(pszFile, "Symbol table goes beyond the end of the of the file (cSyms=%#x, offFile=%#x)\n",
1929 pHdr->NumberOfSymbols, pHdr->PointerToSymbolTable);
1930 }
1931
1932 return true;
1933}
1934
1935
1936static bool convertCoffSectionsToSegDefsAndGrpDefs(POMFWRITER pThis, PCIMAGE_SECTION_HEADER paShdrs, uint16_t cSections)
1937{
1938 /*
1939 * Do the list of names pass.
1940 */
1941 uint16_t idxGrpFlat, idxGrpData;
1942 uint16_t idxClassCode, idxClassData, idxClassDebugSymbols, idxClassDebugTypes;
1943 if ( !omfWriter_LNamesBegin(pThis, true /*fAddZeroEntry*/)
1944 || !omfWriter_LNamesAddN(pThis, RT_STR_TUPLE("FLAT"), &idxGrpFlat)
1945 || !omfWriter_LNamesAddN(pThis, RT_STR_TUPLE("BS3DATA64_GROUP"), &idxGrpData)
1946 || !omfWriter_LNamesAddN(pThis, RT_STR_TUPLE("BS3CLASS64CODE"), &idxClassCode)
1947 || !omfWriter_LNamesAddN(pThis, RT_STR_TUPLE("FAR_DATA"), &idxClassData)
1948 || !omfWriter_LNamesAddN(pThis, RT_STR_TUPLE("DEBSYM"), &idxClassDebugSymbols)
1949 || !omfWriter_LNamesAddN(pThis, RT_STR_TUPLE("DEBTYP"), &idxClassDebugTypes)
1950 )
1951 return false;
1952
1953 bool fHaveData = false;
1954 for (uint16_t i = 0; i < cSections; i++)
1955 {
1956 /* Copy the name and terminate it. */
1957 char szName[32];
1958 memcpy(szName, paShdrs[i].Name, sizeof(paShdrs[i].Name));
1959 unsigned cchName = sizeof(paShdrs[i].Name);
1960 while (cchName > 0 && RT_C_IS_SPACE(szName[cchName - 1]))
1961 cchName--;
1962 if (cchName == 0)
1963 return error(pThis->pszSrc, "Section #%u has an empty name!\n", i);
1964 szName[cchName] = '\0';
1965
1966 if ( (paShdrs[i].Characteristics & (IMAGE_SCN_LNK_REMOVE | IMAGE_SCN_LNK_INFO))
1967 || strcmp(szName, ".pdata") == 0 /* Exception stuff, I think, so discard it. */
1968 || strcmp(szName, ".xdata") == 0 /* Ditto. */ )
1969 {
1970 pThis->paSegments[i].iSegDef = UINT16_MAX;
1971 pThis->paSegments[i].iGrpDef = UINT16_MAX;
1972 pThis->paSegments[i].iSegNm = UINT16_MAX;
1973 pThis->paSegments[i].iGrpNm = UINT16_MAX;
1974 pThis->paSegments[i].iClassNm = UINT16_MAX;
1975 pThis->paSegments[i].pszName = NULL;
1976 }
1977 else
1978 {
1979 /* Translate the name, group and class. */
1980 if (strcmp(szName, ".text") == 0)
1981 {
1982 strcpy(szName, "BS3TEXT64");
1983 pThis->paSegments[i].iGrpNm = idxGrpFlat;
1984 pThis->paSegments[i].iClassNm = idxClassCode;
1985 }
1986 else if (strcmp(szName, ".data") == 0)
1987 {
1988 strcpy(szName, "BS3DATA64");
1989 pThis->paSegments[i].iGrpNm = idxGrpData;
1990 pThis->paSegments[i].iClassNm = idxClassData;
1991 }
1992 else if (strcmp(szName, ".bss") == 0)
1993 {
1994 strcpy(szName, "BS3BSS64");
1995 pThis->paSegments[i].iGrpNm = idxGrpData;
1996 pThis->paSegments[i].iClassNm = idxClassData;
1997 }
1998 else if (strcmp(szName, ".rdata") == 0)
1999 {
2000 strcpy(szName, "BS3DATA64CONST");
2001 pThis->paSegments[i].iGrpNm = idxGrpData;
2002 pThis->paSegments[i].iClassNm = idxClassData;
2003 }
2004 else if (strcmp(szName, ".debug$S") == 0)
2005 {
2006 strcpy(szName, "$$SYMBOLS");
2007 pThis->paSegments[i].iGrpNm = UINT16_MAX;
2008 pThis->paSegments[i].iClassNm = idxClassDebugSymbols;
2009 }
2010 else if (strcmp(szName, ".debug$T") == 0)
2011 {
2012 strcpy(szName, "$$TYPES");
2013 pThis->paSegments[i].iGrpNm = UINT16_MAX;
2014 pThis->paSegments[i].iClassNm = idxClassDebugTypes;
2015 }
2016 else if (paShdrs[i].Characteristics & (IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_CNT_CODE))
2017 {
2018 pThis->paSegments[i].iGrpNm = idxGrpFlat;
2019 pThis->paSegments[i].iClassNm = idxClassCode;
2020 error(pThis->pszSrc, "Unknown code segment: '%s'\n", szName);
2021 }
2022 else
2023 {
2024 pThis->paSegments[i].iGrpNm = idxGrpData;
2025 pThis->paSegments[i].iClassNm = idxClassData;
2026 error(pThis->pszSrc, "Unknown data (?) segment: '%s'\n", szName);
2027 }
2028
2029 /* Save the name. */
2030 pThis->paSegments[i].pszName = strdup(szName);
2031 if (!pThis->paSegments[i].pszName)
2032 return error(pThis->pszSrc, "Out of memory!\n");
2033
2034 /* Add the section name. */
2035 if (!omfWriter_LNamesAdd(pThis, pThis->paSegments[i].pszName, &pThis->paSegments[i].iSegNm))
2036 return false;
2037
2038 fHaveData |= pThis->paSegments[i].iGrpNm == idxGrpData;
2039 }
2040 }
2041
2042 if (!omfWriter_LNamesEnd(pThis))
2043 return false;
2044
2045 /*
2046 * Emit segment definitions.
2047 */
2048 uint16_t iSegDef = 1; /* Start counting at 1. */
2049 for (uint16_t i = 0; i < cSections; i++)
2050 {
2051 if (pThis->paSegments[i].iSegDef == UINT16_MAX)
2052 continue;
2053
2054 uint8_t bSegAttr = 0;
2055
2056 /* The A field. */
2057 switch (paShdrs[i].Characteristics & IMAGE_SCN_ALIGN_MASK)
2058 {
2059 default:
2060 case IMAGE_SCN_ALIGN_1BYTES:
2061 bSegAttr |= 1 << 5;
2062 break;
2063 case IMAGE_SCN_ALIGN_2BYTES:
2064 bSegAttr |= 2 << 5;
2065 break;
2066 case IMAGE_SCN_ALIGN_4BYTES:
2067 bSegAttr |= 5 << 5;
2068 break;
2069 case IMAGE_SCN_ALIGN_8BYTES:
2070 case IMAGE_SCN_ALIGN_16BYTES:
2071 bSegAttr |= 3 << 5;
2072 break;
2073 case IMAGE_SCN_ALIGN_32BYTES:
2074 case IMAGE_SCN_ALIGN_64BYTES:
2075 case IMAGE_SCN_ALIGN_128BYTES:
2076 case IMAGE_SCN_ALIGN_256BYTES:
2077 bSegAttr |= 4 << 5;
2078 break;
2079 case IMAGE_SCN_ALIGN_512BYTES:
2080 case IMAGE_SCN_ALIGN_1024BYTES:
2081 case IMAGE_SCN_ALIGN_2048BYTES:
2082 case IMAGE_SCN_ALIGN_4096BYTES:
2083 case IMAGE_SCN_ALIGN_8192BYTES:
2084 bSegAttr |= 6 << 5; /* page aligned, pharlabs extension. */
2085 break;
2086 }
2087
2088 /* The C field. */
2089 bSegAttr |= 2 << 2; /* public */
2090
2091 /* The B field. We don't have 4GB segments, so leave it as zero. */
2092
2093 /* The D field shall be set as we're doing USE32. */
2094 bSegAttr |= 1;
2095
2096
2097 /* Done. */
2098 if (!omfWriter_SegDef(pThis, bSegAttr, paShdrs[i].SizeOfRawData,
2099 pThis->paSegments[i].iSegNm,
2100 pThis->paSegments[i].iClassNm))
2101 return false;
2102 pThis->paSegments[i].iSegDef = iSegDef++;
2103 }
2104
2105 /*
2106 * Flat group definition (#1) - special, no members.
2107 */
2108 uint16_t iGrpDef = 1;
2109 if ( !omfWriter_GrpDefBegin(pThis, idxGrpFlat)
2110 || !omfWriter_GrpDefEnd(pThis))
2111 return false;
2112 for (uint16_t i = 0; i < cSections; i++)
2113 if (pThis->paSegments[i].iGrpNm == idxGrpFlat)
2114 pThis->paSegments[i].iGrpDef = iGrpDef;
2115 pThis->idxGrpFlat = iGrpDef++;
2116
2117 /*
2118 * Data group definition (#2).
2119 */
2120 /** @todo do we need to consider missing segments and ordering? */
2121 uint16_t cGrpNms = 0;
2122 uint16_t aiGrpNms[2];
2123 if (fHaveData)
2124 aiGrpNms[cGrpNms++] = idxGrpData;
2125 for (uint32_t iGrpNm = 0; iGrpNm < cGrpNms; iGrpNm++)
2126 {
2127 if (!omfWriter_GrpDefBegin(pThis, aiGrpNms[iGrpNm]))
2128 return false;
2129 for (uint16_t i = 0; i < cSections; i++)
2130 if (pThis->paSegments[i].iGrpNm == aiGrpNms[iGrpNm])
2131 {
2132 pThis->paSegments[i].iGrpDef = iGrpDef;
2133 if (!omfWriter_GrpDefAddSegDef(pThis, pThis->paSegments[i].iSegDef))
2134 return false;
2135 }
2136 if (!omfWriter_GrpDefEnd(pThis))
2137 return false;
2138 iGrpDef++;
2139 }
2140
2141 return true;
2142}
2143
2144/**
2145 * This is for matching STATIC symbols with value 0 against the section name,
2146 * to see if it's a section reference or symbol at offset 0 reference.
2147 *
2148 * @returns true / false.
2149 * @param pszSymbol The symbol name.
2150 * @param pachSectName8 The section name (8-bytes).
2151 */
2152static bool isCoffSymbolMatchingSectionName(const char *pszSymbol, uint8_t const pachSectName8[8])
2153{
2154 uint32_t off = 0;
2155 char ch;
2156 while (off < 8 && (ch = pszSymbol[off]) != '\0')
2157 {
2158 if (ch != pachSectName8[off])
2159 return false;
2160 off++;
2161 }
2162 while (off < 8)
2163 {
2164 if (!RT_C_IS_SPACE((ch = pachSectName8[off])))
2165 return ch == '\0';
2166 off++;
2167 }
2168 return true;
2169}
2170
2171static bool convertCoffSymbolsToPubDefsAndExtDefs(POMFWRITER pThis, PCIMAGE_SYMBOL paSymbols, uint16_t cSymbols,
2172 const char *pchStrTab, PCIMAGE_SECTION_HEADER paShdrs)
2173{
2174
2175 if (!cSymbols)
2176 return true;
2177 uint32_t const cbStrTab = *(uint32_t const *)pchStrTab;
2178 char szShort[16];
2179
2180 /*
2181 * Process the symbols the first.
2182 */
2183 uint32_t iSymImageBase = UINT32_MAX;
2184 uint32_t cAbsSyms = 0;
2185 uint32_t cExtSyms = 0;
2186 uint32_t cPubSyms = 0;
2187 for (uint32_t iSeg = 0; iSeg < pThis->cSegments; iSeg++)
2188 pThis->paSegments[iSeg].cPubDefs = 0;
2189
2190 for (uint16_t iSym = 0; iSym < cSymbols; iSym++)
2191 {
2192 const char *pszSymName = coffGetSymbolName(&paSymbols[iSym], pchStrTab, cbStrTab, szShort);
2193
2194 pThis->paSymbols[iSym].enmType = OMFSYMTYPE_IGNORED;
2195 pThis->paSymbols[iSym].idx = UINT16_MAX;
2196 pThis->paSymbols[iSym].idxSegDef = UINT16_MAX;
2197 pThis->paSymbols[iSym].idxGrpDef = UINT16_MAX;
2198
2199 int16_t const idxSection = paSymbols[iSym].SectionNumber;
2200 if ( (idxSection >= 1 && idxSection <= (int32_t)pThis->cSegments)
2201 || idxSection == IMAGE_SYM_ABSOLUTE)
2202 {
2203 switch (paSymbols[iSym].StorageClass)
2204 {
2205 case IMAGE_SYM_CLASS_EXTERNAL:
2206 if (idxSection != IMAGE_SYM_ABSOLUTE)
2207 {
2208 if (pThis->paSegments[idxSection - 1].iSegDef != UINT16_MAX)
2209 {
2210 pThis->paSymbols[iSym].enmType = OMFSYMTYPE_PUBDEF;
2211 pThis->paSymbols[iSym].idxSegDef = pThis->paSegments[idxSection - 1].iSegDef;
2212 pThis->paSymbols[iSym].idxGrpDef = pThis->paSegments[idxSection - 1].iGrpDef;
2213 pThis->paSegments[idxSection - 1].cPubDefs++;
2214 cPubSyms++;
2215 }
2216 }
2217 else
2218 {
2219 pThis->paSymbols[iSym].enmType = OMFSYMTYPE_PUBDEF;
2220 pThis->paSymbols[iSym].idxSegDef = 0;
2221 pThis->paSymbols[iSym].idxGrpDef = 0;
2222 cAbsSyms++;
2223 }
2224 break;
2225
2226 case IMAGE_SYM_CLASS_STATIC:
2227 if ( paSymbols[iSym].Value == 0
2228 && idxSection != IMAGE_SYM_ABSOLUTE
2229 && isCoffSymbolMatchingSectionName(pszSymName, paShdrs[idxSection - 1].Name) )
2230 {
2231 pThis->paSymbols[iSym].enmType = OMFSYMTYPE_SEGDEF;
2232 pThis->paSymbols[iSym].idxSegDef = pThis->paSegments[idxSection - 1].iSegDef;
2233 pThis->paSymbols[iSym].idxGrpDef = pThis->paSegments[idxSection - 1].iGrpDef;
2234 break;
2235 }
2236 /* fall thru */
2237
2238 case IMAGE_SYM_CLASS_END_OF_FUNCTION:
2239 case IMAGE_SYM_CLASS_AUTOMATIC:
2240 case IMAGE_SYM_CLASS_REGISTER:
2241 case IMAGE_SYM_CLASS_LABEL:
2242 case IMAGE_SYM_CLASS_MEMBER_OF_STRUCT:
2243 case IMAGE_SYM_CLASS_ARGUMENT:
2244 case IMAGE_SYM_CLASS_STRUCT_TAG:
2245 case IMAGE_SYM_CLASS_MEMBER_OF_UNION:
2246 case IMAGE_SYM_CLASS_UNION_TAG:
2247 case IMAGE_SYM_CLASS_TYPE_DEFINITION:
2248 case IMAGE_SYM_CLASS_ENUM_TAG:
2249 case IMAGE_SYM_CLASS_MEMBER_OF_ENUM:
2250 case IMAGE_SYM_CLASS_REGISTER_PARAM:
2251 case IMAGE_SYM_CLASS_BIT_FIELD:
2252 case IMAGE_SYM_CLASS_BLOCK:
2253 case IMAGE_SYM_CLASS_FUNCTION:
2254 case IMAGE_SYM_CLASS_END_OF_STRUCT:
2255 case IMAGE_SYM_CLASS_FILE:
2256 pThis->paSymbols[iSym].enmType = OMFSYMTYPE_INTERNAL;
2257 if (idxSection != IMAGE_SYM_ABSOLUTE)
2258 {
2259 pThis->paSymbols[iSym].idxSegDef = pThis->paSegments[idxSection - 1].iSegDef;
2260 pThis->paSymbols[iSym].idxGrpDef = pThis->paSegments[idxSection - 1].iGrpDef;
2261 }
2262 else
2263 {
2264 pThis->paSymbols[iSym].idxSegDef = 0;
2265 pThis->paSymbols[iSym].idxGrpDef = 0;
2266 }
2267 break;
2268
2269 case IMAGE_SYM_CLASS_SECTION:
2270 case IMAGE_SYM_CLASS_EXTERNAL_DEF:
2271 case IMAGE_SYM_CLASS_NULL:
2272 case IMAGE_SYM_CLASS_UNDEFINED_LABEL:
2273 case IMAGE_SYM_CLASS_UNDEFINED_STATIC:
2274 case IMAGE_SYM_CLASS_CLR_TOKEN:
2275 case IMAGE_SYM_CLASS_FAR_EXTERNAL:
2276 case IMAGE_SYM_CLASS_WEAK_EXTERNAL:
2277 return error(pThis->pszSrc, "Unsupported storage class value %#x for symbol #%u (%s)\n",
2278 paSymbols[iSym].StorageClass, iSym, pszSymName);
2279
2280 default:
2281 return error(pThis->pszSrc, "Unknown storage class value %#x for symbol #%u (%s)\n",
2282 paSymbols[iSym].StorageClass, iSym, pszSymName);
2283 }
2284 }
2285 else if (idxSection == IMAGE_SYM_UNDEFINED)
2286 {
2287 if ( paSymbols[iSym].StorageClass == IMAGE_SYM_CLASS_EXTERNAL
2288 || paSymbols[iSym].StorageClass == IMAGE_SYM_CLASS_EXTERNAL_DEF)
2289 {
2290 pThis->paSymbols[iSym].enmType = OMFSYMTYPE_EXTDEF;
2291 cExtSyms++;
2292 if (iSymImageBase == UINT32_MAX && strcmp(pszSymName, "__ImageBase") == 0)
2293 iSymImageBase = iSym;
2294 }
2295 else
2296 return error(pThis->pszSrc, "Unknown/unknown storage class value %#x for undefined symbol #%u (%s)\n",
2297 paSymbols[iSym].StorageClass, iSym, pszSymName);
2298 }
2299 else if (idxSection != IMAGE_SYM_DEBUG)
2300 return error(pThis->pszSrc, "Invalid section number %#x for symbol #%u (%s)\n", idxSection, iSym, pszSymName);
2301
2302 /* Skip AUX symbols. */
2303 uint8_t cAuxSyms = paSymbols[iSym].NumberOfAuxSymbols;
2304 while (cAuxSyms-- > 0)
2305 {
2306 iSym++;
2307 pThis->paSymbols[iSym].enmType = OMFSYMTYPE_INVALID;
2308 pThis->paSymbols[iSym].idx = UINT16_MAX;
2309 }
2310 }
2311
2312 /*
2313 * Emit the PUBDEFs the first time around (see order of records in TIS spec).
2314 */
2315 uint16_t idxPubDef = 1;
2316 if (cPubSyms)
2317 {
2318 for (uint32_t iSeg = 0; iSeg < pThis->cSegments; iSeg++)
2319 if (pThis->paSegments[iSeg].cPubDefs > 0)
2320 {
2321 uint16_t const idxSegDef = pThis->paSegments[iSeg].iSegDef;
2322 if (!omfWriter_PubDefBegin(pThis, pThis->paSegments[iSeg].iGrpDef, idxSegDef))
2323 return false;
2324 for (uint16_t iSym = 0; iSym < cSymbols; iSym++)
2325 if ( pThis->paSymbols[iSym].idxSegDef == idxSegDef
2326 && pThis->paSymbols[iSym].enmType == OMFSYMTYPE_PUBDEF)
2327 {
2328 const char *pszName = coffGetSymbolName(&paSymbols[iSym], pchStrTab, cbStrTab, szShort);
2329 if (!omfWriter_PubDefAdd(pThis, paSymbols[iSym].Value, pszName))
2330 return false;
2331
2332 /* If the symbol doesn't start with an underscore and is a _c64 or _lm64 symbol,
2333 add an underscore prefixed alias to ease access from 16-bit and 32-bit code. */
2334 size_t cchName = strlen(pszName);
2335 if ( *pszName != '_'
2336 && ( (cchName > 4 && strcmp(&pszName[cchName - 4], "_c64") == 0)
2337 || (cchName > 5 && strcmp(&pszName[cchName - 5], "_lm64") == 0) ) )
2338 {
2339 char szCdeclName[512];
2340 if (cchName > sizeof(szCdeclName) - 2)
2341 cchName = sizeof(szCdeclName) - 2;
2342 szCdeclName[0] = '_';
2343 memcpy(&szCdeclName[1], pszName, cchName);
2344 szCdeclName[cchName + 1] = '\0';
2345 if (!omfWriter_PubDefAdd(pThis, paSymbols[iSym].Value, szCdeclName))
2346 return false;
2347 }
2348
2349 pThis->paSymbols[iSym].idx = idxPubDef++;
2350 }
2351 if (!omfWriter_PubDefEnd(pThis))
2352 return false;
2353 }
2354 }
2355
2356 if (cAbsSyms > 0)
2357 {
2358 if (!omfWriter_PubDefBegin(pThis, 0, 0))
2359 return false;
2360 for (uint16_t iSym = 0; iSym < cSymbols; iSym++)
2361 if ( pThis->paSymbols[iSym].idxSegDef == 0
2362 && pThis->paSymbols[iSym].enmType == OMFSYMTYPE_PUBDEF)
2363 {
2364 if (!omfWriter_PubDefAdd(pThis, paSymbols[iSym].Value,
2365 coffGetSymbolName(&paSymbols[iSym], pchStrTab, cbStrTab, szShort)) )
2366 return false;
2367 pThis->paSymbols[iSym].idx = idxPubDef++;
2368 }
2369 if (!omfWriter_PubDefEnd(pThis))
2370 return false;
2371 }
2372
2373 /*
2374 * Go over the symbol table and emit external definition records.
2375 */
2376 if (!omfWriter_ExtDefBegin(pThis))
2377 return false;
2378 uint16_t idxExtDef = 1;
2379 for (uint16_t iSym = 0; iSym < cSymbols; iSym++)
2380 if (pThis->paSymbols[iSym].enmType == OMFSYMTYPE_EXTDEF)
2381 {
2382 if (!omfWriter_ExtDefAdd(pThis, coffGetSymbolName(&paSymbols[iSym], pchStrTab, cbStrTab, szShort)))
2383 return false;
2384 pThis->paSymbols[iSym].idx = idxExtDef++;
2385 }
2386
2387 /* Always add an __ImageBase reference, in case we need it to deal with ADDR32NB fixups. */
2388 /** @todo maybe we don't actually need this and could use FLAT instead? */
2389 if (iSymImageBase != UINT32_MAX)
2390 pThis->idxExtImageBase = pThis->paSymbols[iSymImageBase].idx;
2391 else if (omfWriter_ExtDefAdd(pThis, "__ImageBase"))
2392 pThis->idxExtImageBase = idxExtDef;
2393 else
2394 return false;
2395
2396 if (!omfWriter_ExtDefEnd(pThis))
2397 return false;
2398
2399 return true;
2400}
2401
2402
2403static bool convertCoffSectionsToLeDataAndFixupps(POMFWRITER pThis, uint8_t const *pbFile, size_t cbFile,
2404 PCIMAGE_SECTION_HEADER paShdrs, uint16_t cSections,
2405 PCIMAGE_SYMBOL paSymbols, uint16_t cSymbols, const char *pchStrTab)
2406{
2407 uint32_t const cbStrTab = *(uint32_t const *)pchStrTab;
2408 bool fRet = true;
2409 for (uint32_t i = 0; i < pThis->cSegments; i++)
2410 {
2411 if (pThis->paSegments[i].iSegDef == UINT16_MAX)
2412 continue;
2413
2414 char szShortName[16];
2415 const char *pszSegNm = pThis->paSegments[i].pszName;
2416 uint16_t cRelocs = paShdrs[i].NumberOfRelocations;
2417 PCIMAGE_RELOCATION paRelocs = (PCIMAGE_RELOCATION)&pbFile[paShdrs[i].PointerToRelocations];
2418 uint32_t cbVirtData = paShdrs[i].SizeOfRawData;
2419 uint32_t cbData = paShdrs[i].Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA ? 0 : cbVirtData;
2420 uint8_t const *pbData = &pbFile[paShdrs[i].PointerToRawData];
2421 uint32_t off = 0;
2422
2423 /* Check that the relocations are sorted and within the section. */
2424 for (uint32_t iReloc = 1; iReloc < cRelocs; iReloc++)
2425 if (paRelocs[iReloc - 1].u.VirtualAddress >= paRelocs[iReloc].u.VirtualAddress)
2426 return error(pThis->pszSrc, "Section #%u (%s) relocations aren't sorted\n", i, pszSegNm);
2427 if ( cRelocs > 0
2428 && paRelocs[cRelocs - 1].u.VirtualAddress - paShdrs[i].VirtualAddress
2429 + COFF_AMD64_RELOC_SIZE(paRelocs[cRelocs - 1].Type) > cbVirtData)
2430 return error(pThis->pszSrc,
2431 "Section #%u (%s) relocations beyond section data! cbVirtData=%#x RvaFix=%#x RVASeg=%#x type=%#x\n",
2432 i, pszSegNm, cbVirtData, paRelocs[cRelocs - 1].u.VirtualAddress, paShdrs[i].VirtualAddress,
2433 paRelocs[cRelocs - 1].Type);
2434
2435 /* The OMF record size requires us to split larger sections up. To make
2436 life simple, we fill zeros for unitialized (BSS) stuff. */
2437 const uint32_t cbMaxData = RT_MIN(OMF_MAX_RECORD_PAYLOAD - 1 - (pThis->paSegments[i].iSegDef >= 128) - 4 - 1, _1K);
2438 while (cbVirtData > 0)
2439 {
2440 /* Figure out how many bytes to put out in this chunk. Must make sure
2441 fixups doesn't cross chunk boundraries. ASSUMES sorted relocs. */
2442 uint32_t cChunkRelocs = cRelocs;
2443 uint32_t cbChunk = cbVirtData;
2444 uint32_t uRvaEnd = paShdrs[i].VirtualAddress + off + cbChunk;
2445 if (cbChunk > cbMaxData)
2446 {
2447 cbChunk = cbMaxData;
2448 uRvaEnd = paShdrs[i].VirtualAddress + off + cbChunk;
2449 cChunkRelocs = 0;
2450
2451 /* Quickly determin the reloc range. */
2452 while ( cChunkRelocs < cRelocs
2453 && paRelocs[cChunkRelocs].u.VirtualAddress < uRvaEnd)
2454 cChunkRelocs++;
2455
2456 /* Ensure final reloc doesn't go beyond chunk. */
2457 while ( cChunkRelocs > 0
2458 && paRelocs[cChunkRelocs - 1].u.VirtualAddress + COFF_AMD64_RELOC_SIZE(paRelocs[cChunkRelocs - 1].Type)
2459 > uRvaEnd)
2460 {
2461 uint32_t cbDrop = uRvaEnd - paRelocs[cChunkRelocs - 1].u.VirtualAddress;
2462 cbChunk -= cbDrop;
2463 uRvaEnd -= cbDrop;
2464 cChunkRelocs--;
2465 }
2466
2467 if (!cbVirtData)
2468 return error(pThis->pszSrc, "Wtf? cbVirtData is zero!\n");
2469 }
2470
2471 /*
2472 * We stash the bytes into the OMF writer record buffer, receiving a
2473 * pointer to the start of it so we can make adjustments if necessary.
2474 */
2475 uint8_t *pbCopy;
2476 if (!omfWriter_LEDataBeginEx(pThis, pThis->paSegments[i].iSegDef, off, cbChunk, cbData, pbData, &pbCopy))
2477 return false;
2478
2479 /*
2480 * Convert fiuxps.
2481 */
2482 uint32_t const uRvaChunk = paShdrs[i].VirtualAddress + off;
2483 for (uint32_t iReloc = 0; iReloc < cChunkRelocs; iReloc++)
2484 {
2485 /* Get the OMF and COFF data for the symbol the reloc references. */
2486 if (paRelocs[iReloc].SymbolTableIndex >= pThis->cSymbols)
2487 return error(pThis->pszSrc, "Relocation symtab index (%#x) is out of range in segment #%u '%s'\n",
2488 paRelocs[iReloc].SymbolTableIndex, i, pszSegNm);
2489 PCIMAGE_SYMBOL pCoffSym = &paSymbols[paRelocs[iReloc].SymbolTableIndex];
2490 POMFSYMBOL pOmfSym = &pThis->paSymbols[paRelocs[iReloc].SymbolTableIndex];
2491
2492 /* Calc fixup location in the pending chunk and setup a flexible pointer to it. */
2493 uint16_t offDataRec = (uint16_t)(paRelocs[iReloc].u.VirtualAddress - uRvaChunk);
2494 RTPTRUNION uLoc;
2495 uLoc.pu8 = &pbCopy[offDataRec];
2496
2497 /* OMF fixup data initialized with typical defaults. */
2498 bool fSelfRel = true;
2499 uint8_t bLocation = OMF_FIX_LOC_32BIT_OFFSET;
2500 uint8_t bFrame = OMF_FIX_F_GRPDEF;
2501 uint16_t idxFrame = pThis->idxGrpFlat;
2502 uint8_t bTarget;
2503 uint16_t idxTarget;
2504 bool fTargetDisp;
2505 uint32_t offTargetDisp;
2506 switch (pOmfSym->enmType)
2507 {
2508 case OMFSYMTYPE_INTERNAL:
2509 case OMFSYMTYPE_PUBDEF:
2510 bTarget = OMF_FIX_T_SEGDEF;
2511 idxTarget = pOmfSym->idxSegDef;
2512 fTargetDisp = true;
2513 offTargetDisp = pCoffSym->Value;
2514 break;
2515
2516 case OMFSYMTYPE_SEGDEF:
2517 bTarget = OMF_FIX_T_SEGDEF_NO_DISP;
2518 idxTarget = pOmfSym->idxSegDef;
2519 fTargetDisp = false;
2520 offTargetDisp = 0;
2521 break;
2522
2523 case OMFSYMTYPE_EXTDEF:
2524 bTarget = OMF_FIX_T_EXTDEF_NO_DISP;
2525 idxTarget = pOmfSym->idx;
2526 fTargetDisp = false;
2527 offTargetDisp = 0;
2528 break;
2529
2530 default:
2531 return error(pThis->pszSrc, "Relocation in segment #%u '%s' references ignored or invalid symbol (%s)\n",
2532 i, pszSegNm, coffGetSymbolName(pCoffSym, pchStrTab, cbStrTab, szShortName));
2533 }
2534
2535 /* Do COFF relocation type conversion. */
2536 switch (paRelocs[iReloc].Type)
2537 {
2538 case IMAGE_REL_AMD64_ADDR64:
2539 {
2540 uint64_t uAddend = *uLoc.pu64;
2541 if (uAddend > _1G)
2542 fRet = error(pThis->pszSrc, "ADDR64 with large addend (%#llx) at %#x in segment #%u '%s'\n",
2543 uAddend, paRelocs[iReloc].u.VirtualAddress, i, pszSegNm);
2544 fSelfRel = false;
2545 break;
2546 }
2547
2548 case IMAGE_REL_AMD64_REL32_1:
2549 case IMAGE_REL_AMD64_REL32_2:
2550 case IMAGE_REL_AMD64_REL32_3:
2551 case IMAGE_REL_AMD64_REL32_4:
2552 case IMAGE_REL_AMD64_REL32_5:
2553 /** @todo Check whether OMF read addends from the data or relies on the
2554 * displacement. Also, check what it's relative to. */
2555 *uLoc.pu32 -= paRelocs[iReloc].Type - IMAGE_REL_AMD64_REL32;
2556 break;
2557
2558 case IMAGE_REL_AMD64_ADDR32:
2559 fSelfRel = false;
2560 break;
2561
2562 case IMAGE_REL_AMD64_ADDR32NB:
2563 fSelfRel = false;
2564 bFrame = OMF_FIX_F_EXTDEF;
2565 idxFrame = pThis->idxExtImageBase;
2566 break;
2567
2568 case IMAGE_REL_AMD64_REL32:
2569 /* defaults are ok. */
2570 break;
2571
2572 case IMAGE_REL_AMD64_SECTION:
2573 bLocation = OMF_FIX_LOC_16BIT_SEGMENT;
2574 /* fall thru */
2575
2576 case IMAGE_REL_AMD64_SECREL:
2577 fSelfRel = false;
2578 if (pOmfSym->enmType == OMFSYMTYPE_EXTDEF)
2579 {
2580 bFrame = OMF_FIX_F_EXTDEF;
2581 idxFrame = pOmfSym->idx;
2582 }
2583 else
2584 {
2585 bFrame = OMF_FIX_F_SEGDEF;
2586 idxFrame = pOmfSym->idxSegDef;
2587 }
2588 break;
2589
2590 case IMAGE_REL_AMD64_ABSOLUTE:
2591 continue; /* Ignore it like the PECOFF.DOC says we should. */
2592
2593 case IMAGE_REL_AMD64_SECREL7:
2594 default:
2595 return error(pThis->pszSrc, "Unsupported fixup type %#x (%s) at rva=%#x in section #%u '%-8.8s'\n",
2596 paRelocs[iReloc].Type,
2597 paRelocs[iReloc].Type < RT_ELEMENTS(g_apszCoffAmd64RelTypes)
2598 ? g_apszCoffAmd64RelTypes[paRelocs[iReloc].Type] : "unknown",
2599 paRelocs[iReloc].u.VirtualAddress, i, paShdrs[i].Name);
2600 }
2601
2602 /* Add the fixup. */
2603 if (idxFrame == UINT16_MAX)
2604 error(pThis->pszSrc, "idxFrame=UINT16_MAX for %s type=%s\n",
2605 coffGetSymbolName(pCoffSym, pchStrTab, cbStrTab, szShortName),
2606 g_apszCoffAmd64RelTypes[paRelocs[iReloc].Type]);
2607 fRet = omfWriter_LEDataAddFixup(pThis, offDataRec, fSelfRel, bLocation, bFrame, idxFrame,
2608 bTarget, idxTarget, fTargetDisp, offTargetDisp) && fRet;
2609 }
2610
2611 /*
2612 * Write the LEDATA and associated FIXUPPs.
2613 */
2614 if (!omfWriter_LEDataEnd(pThis))
2615 return false;
2616
2617 /*
2618 * Advance.
2619 */
2620 paRelocs += cChunkRelocs;
2621 cRelocs -= cChunkRelocs;
2622 if (cbData > cbChunk)
2623 {
2624 cbData -= cbChunk;
2625 pbData += cbChunk;
2626 }
2627 else
2628 cbData = 0;
2629 off += cbChunk;
2630 cbVirtData -= cbChunk;
2631 }
2632 }
2633
2634 return fRet;
2635}
2636
2637
2638static bool convertCoffToOmf(const char *pszFile, uint8_t const *pbFile, size_t cbFile, FILE *pDst)
2639{
2640 /*
2641 * Validate the source file a little.
2642 */
2643 if (!validateCoff(pszFile, pbFile, cbFile))
2644 return false;
2645
2646 /*
2647 * Instantiate the OMF writer.
2648 */
2649 PIMAGE_FILE_HEADER pHdr = (PIMAGE_FILE_HEADER)pbFile;
2650 POMFWRITER pThis = omfWriter_Create(pszFile, pHdr->NumberOfSections, pHdr->NumberOfSymbols, pDst);
2651 if (!pThis)
2652 return false;
2653
2654 /*
2655 * Write the OMF object file.
2656 */
2657 if (omfWriter_BeginModule(pThis, pszFile))
2658 {
2659 PCIMAGE_SECTION_HEADER paShdrs = (PCIMAGE_SECTION_HEADER)(pHdr + 1);
2660 PCIMAGE_SYMBOL paSymTab = (PCIMAGE_SYMBOL)&pbFile[pHdr->PointerToSymbolTable];
2661 const char *pchStrTab = (const char *)&paSymTab[pHdr->NumberOfSymbols];
2662 if ( convertCoffSectionsToSegDefsAndGrpDefs(pThis, paShdrs, pHdr->NumberOfSections)
2663 && convertCoffSymbolsToPubDefsAndExtDefs(pThis, paSymTab, pHdr->NumberOfSymbols, pchStrTab, paShdrs)
2664 && omfWriter_LinkPassSeparator(pThis)
2665 && convertCoffSectionsToLeDataAndFixupps(pThis, pbFile, cbFile, paShdrs, pHdr->NumberOfSections,
2666 paSymTab, pHdr->NumberOfSymbols, pchStrTab)
2667 && omfWriter_EndModule(pThis) )
2668 {
2669
2670 omfWriter_Destroy(pThis);
2671 return true;
2672 }
2673 }
2674
2675 omfWriter_Destroy(pThis);
2676 return false;
2677}
2678
2679
2680/*********************************************************************************************************************************
2681* Mach-O/AMD64 -> OMF/i386 Converter *
2682*********************************************************************************************************************************/
2683
2684//#define MACHO_TO_OMF_CONVERSION
2685#ifdef MACHO_TO_OMF_CONVERSION
2686
2687/** AMD64 relocation type names for Mach-O. */
2688static const char * const g_apszMachOAmd64RelTypes[] =
2689{
2690 "X86_64_RELOC_UNSIGNED",
2691 "X86_64_RELOC_SIGNED",
2692 "X86_64_RELOC_BRANCH",
2693 "X86_64_RELOC_GOT_LOAD",
2694 "X86_64_RELOC_GOT",
2695 "X86_64_RELOC_SUBTRACTOR",
2696 "X86_64_RELOC_SIGNED_1",
2697 "X86_64_RELOC_SIGNED_2",
2698 "X86_64_RELOC_SIGNED_4"
2699};
2700
2701/** AMD64 relocation type sizes for Mach-O. */
2702static uint8_t const g_acbMachOAmd64RelTypes[] =
2703{
2704 8, /* X86_64_RELOC_UNSIGNED */
2705 4, /* X86_64_RELOC_SIGNED */
2706 4, /* X86_64_RELOC_BRANCH */
2707 4, /* X86_64_RELOC_GOT_LOAD */
2708 4, /* X86_64_RELOC_GOT */
2709 8, /* X86_64_RELOC_SUBTRACTOR */
2710 4, /* X86_64_RELOC_SIGNED_1 */
2711 4, /* X86_64_RELOC_SIGNED_2 */
2712 4, /* X86_64_RELOC_SIGNED_4 */
2713};
2714
2715/** Macro for getting the size of a AMD64 ELF relocation. */
2716#define ELF_AMD64_RELOC_SIZE(a_Type) ( (a_Type) < RT_ELEMENTS(g_acbElfAmd64RelTypes) ? g_acbElfAmd64RelTypes[(a_Type)] : 1)
2717
2718
2719typedef struct ELFDETAILS
2720{
2721 /** The ELF header. */
2722 Elf64_Ehdr const *pEhdr;
2723 /** The section header table. */
2724 Elf64_Shdr const *paShdrs;
2725 /** The string table for the section names. */
2726 const char *pchShStrTab;
2727
2728 /** The symbol table section number. UINT16_MAX if not found. */
2729 uint16_t iSymSh;
2730 /** The string table section number. UINT16_MAX if not found. */
2731 uint16_t iStrSh;
2732
2733 /** The symbol table. */
2734 Elf64_Sym const *paSymbols;
2735 /** The number of symbols in the symbol table. */
2736 uint32_t cSymbols;
2737
2738 /** Pointer to the (symbol) string table if found. */
2739 const char *pchStrTab;
2740 /** The string table size. */
2741 size_t cbStrTab;
2742
2743} ELFDETAILS;
2744typedef ELFDETAILS *PELFDETAILS;
2745typedef ELFDETAILS const *PCELFDETAILS;
2746
2747
2748static bool validateElf(const char *pszFile, uint8_t const *pbFile, size_t cbFile, PELFDETAILS pElfStuff)
2749{
2750 /*
2751 * Initialize the ELF details structure.
2752 */
2753 memset(pElfStuff, 0, sizeof(*pElfStuff));
2754 pElfStuff->iSymSh = UINT16_MAX;
2755 pElfStuff->iStrSh = UINT16_MAX;
2756
2757 /*
2758 * Validate the header and our other expectations.
2759 */
2760 Elf64_Ehdr const *pEhdr = (Elf64_Ehdr const *)pbFile;
2761 pElfStuff->pEhdr = pEhdr;
2762 if ( pEhdr->e_ident[EI_CLASS] != ELFCLASS64
2763 || pEhdr->e_ident[EI_DATA] != ELFDATA2LSB
2764 || pEhdr->e_ehsize != sizeof(Elf64_Ehdr)
2765 || pEhdr->e_shentsize != sizeof(Elf64_Shdr)
2766 || pEhdr->e_version != EV_CURRENT )
2767 return error(pszFile, "Unsupported ELF config\n");
2768 if (pEhdr->e_type != ET_REL)
2769 return error(pszFile, "Expected relocatable ELF file (e_type=%d)\n", pEhdr->e_type);
2770 if (pEhdr->e_machine != EM_X86_64)
2771 return error(pszFile, "Expected relocatable ELF file (e_type=%d)\n", pEhdr->e_machine);
2772 if (pEhdr->e_phnum != 0)
2773 return error(pszFile, "Expected e_phnum to be zero not %u\n", pEhdr->e_phnum);
2774 if (pEhdr->e_shnum < 2)
2775 return error(pszFile, "Expected e_shnum to be two or higher\n");
2776 if (pEhdr->e_shstrndx >= pEhdr->e_shnum || pEhdr->e_shstrndx == 0)
2777 return error(pszFile, "Bad e_shstrndx=%u (e_shnum=%u)\n", pEhdr->e_shstrndx, pEhdr->e_shnum);
2778 if ( pEhdr->e_shoff >= cbFile
2779 || pEhdr->e_shoff + pEhdr->e_shnum * sizeof(Elf64_Shdr) > cbFile)
2780 return error(pszFile, "Section table is outside the file (e_shoff=%#llx, e_shnum=%u, cbFile=%#llx)\n",
2781 pEhdr->e_shstrndx, pEhdr->e_shnum, (uint64_t)cbFile);
2782
2783 /*
2784 * Locate the section name string table.
2785 * We assume it's okay as we only reference it in verbose mode.
2786 */
2787 Elf64_Shdr const *paShdrs = (Elf64_Shdr const *)&pbFile[pEhdr->e_shoff];
2788 pElfStuff->paShdrs = paShdrs;
2789
2790 Elf64_Xword const cbShStrTab = paShdrs[pEhdr->e_shstrndx].sh_size;
2791 if ( paShdrs[pEhdr->e_shstrndx].sh_offset > cbFile
2792 || cbShStrTab > cbFile
2793 || paShdrs[pEhdr->e_shstrndx].sh_offset + cbShStrTab > cbFile)
2794 return error(pszFile,
2795 "Section string table is outside the file (sh_offset=%#" ELF_FMT_X64 " sh_size=%#" ELF_FMT_X64 " cbFile=%#" ELF_FMT_X64 ")\n",
2796 paShdrs[pEhdr->e_shstrndx].sh_offset, paShdrs[pEhdr->e_shstrndx].sh_size, (Elf64_Xword)cbFile);
2797 const char *pchShStrTab = (const char *)&pbFile[paShdrs[pEhdr->e_shstrndx].sh_offset];
2798 pElfStuff->pchShStrTab = pchShStrTab;
2799
2800 /*
2801 * Work the section table.
2802 */
2803 bool fRet = true;
2804 for (uint32_t i = 1; i < pEhdr->e_shnum; i++)
2805 {
2806 if (paShdrs[i].sh_name >= cbShStrTab)
2807 return error(pszFile, "Invalid sh_name value (%#x) for section #%u\n", paShdrs[i].sh_name, i);
2808 const char *pszShNm = &pchShStrTab[paShdrs[i].sh_name];
2809
2810 if ( paShdrs[i].sh_offset > cbFile
2811 || paShdrs[i].sh_size > cbFile
2812 || paShdrs[i].sh_offset + paShdrs[i].sh_size > cbFile)
2813 return error(pszFile, "Section #%u '%s' has data outside the file: %#" ELF_FMT_X64 " LB %#" ELF_FMT_X64 " (cbFile=%#" ELF_FMT_X64 ")\n",
2814 i, pszShNm, paShdrs[i].sh_offset, paShdrs[i].sh_size, (Elf64_Xword)cbFile);
2815 if (g_cVerbose)
2816 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"
2817 " link=%u info=%#x align=%#" ELF_FMT_X64 " entsize=%#" ELF_FMT_X64 "\n",
2818 i, paShdrs[i].sh_name, pszShNm, paShdrs[i].sh_type, paShdrs[i].sh_flags,
2819 paShdrs[i].sh_addr, paShdrs[i].sh_offset, paShdrs[i].sh_size,
2820 paShdrs[i].sh_link, paShdrs[i].sh_info, paShdrs[i].sh_addralign, paShdrs[i].sh_entsize);
2821
2822 if (paShdrs[i].sh_link >= pEhdr->e_shnum)
2823 return error(pszFile, "Section #%u '%s' links to a section outside the section table: %#x, max %#x\n",
2824 i, pszShNm, paShdrs[i].sh_link, pEhdr->e_shnum);
2825 if (!RT_IS_POWER_OF_TWO(paShdrs[i].sh_addralign))
2826 return error(pszFile, "Section #%u '%s' alignment value is not a power of two: %#" ELF_FMT_X64 "\n",
2827 i, pszShNm, paShdrs[i].sh_addralign);
2828 if (!RT_IS_POWER_OF_TWO(paShdrs[i].sh_addralign))
2829 return error(pszFile, "Section #%u '%s' alignment value is not a power of two: %#" ELF_FMT_X64 "\n",
2830 i, pszShNm, paShdrs[i].sh_addralign);
2831 if (paShdrs[i].sh_addr != 0)
2832 return error(pszFile, "Section #%u '%s' has non-zero address: %#" ELF_FMT_X64 "\n", i, pszShNm, paShdrs[i].sh_addr);
2833
2834 if (paShdrs[i].sh_type == SHT_RELA)
2835 {
2836 if (paShdrs[i].sh_entsize != sizeof(Elf64_Rela))
2837 return error(pszFile, "Expected sh_entsize to be %u not %u for section #%u (%s)\n", (unsigned)sizeof(Elf64_Rela),
2838 paShdrs[i].sh_entsize, i, pszShNm);
2839 uint32_t const cRelocs = paShdrs[i].sh_size / sizeof(Elf64_Rela);
2840 if (cRelocs * sizeof(Elf64_Rela) != paShdrs[i].sh_size)
2841 return error(pszFile, "Uneven relocation entry count in #%u (%s): sh_size=%#" ELF_FMT_X64 "\n",
2842 i, pszShNm, paShdrs[i].sh_size);
2843 if ( paShdrs[i].sh_offset > cbFile
2844 || paShdrs[i].sh_size >= cbFile
2845 || paShdrs[i].sh_offset + paShdrs[i].sh_size > cbFile)
2846 return error(pszFile, "The content of section #%u '%s' is outside the file (%#" ELF_FMT_X64 " LB %#" ELF_FMT_X64 ", cbFile=%#lx)\n",
2847 i, pszShNm, paShdrs[i].sh_offset, paShdrs[i].sh_size, (unsigned long)cbFile);
2848 if (paShdrs[i].sh_info != i - 1)
2849 return error(pszFile, "Expected relocation section #%u (%s) to link to previous section: sh_info=%#u\n",
2850 i, pszShNm, (unsigned)paShdrs[i].sh_link);
2851 if (paShdrs[paShdrs[i].sh_link].sh_type != SHT_SYMTAB)
2852 return error(pszFile, "Expected relocation section #%u (%s) to link to symbol table: sh_link=%#u -> sh_type=%#x\n",
2853 i, pszShNm, (unsigned)paShdrs[i].sh_link, (unsigned)paShdrs[paShdrs[i].sh_link].sh_type);
2854 uint32_t cSymbols = paShdrs[paShdrs[i].sh_link].sh_size / paShdrs[paShdrs[i].sh_link].sh_entsize;
2855
2856 Elf64_Rela const *paRelocs = (Elf64_Rela *)&pbFile[paShdrs[i].sh_offset];
2857 for (uint32_t j = 0; j < cRelocs; j++)
2858 {
2859 uint8_t const bType = ELF64_R_TYPE(paRelocs[j].r_info);
2860 if (RT_UNLIKELY(bType >= R_X86_64_COUNT))
2861 fRet = error(pszFile,
2862 "%#018" ELF_FMT_X64 " %#018" ELF_FMT_X64 ": unknown fix up %#x (%+" ELF_FMT_D64 ")\n",
2863 paRelocs[j].r_offset, paRelocs[j].r_info, bType, paRelocs[j].r_addend);
2864 if (RT_UNLIKELY( j > 1
2865 && paRelocs[j].r_offset <= paRelocs[j - 1].r_offset
2866 && paRelocs[j].r_offset + ELF_AMD64_RELOC_SIZE(ELF64_R_TYPE(paRelocs[j].r_info))
2867 < paRelocs[j - 1].r_offset ))
2868 fRet = error(pszFile,
2869 "%#018" ELF_FMT_X64 " %#018" ELF_FMT_X64 ": out of offset order (prev %" ELF_FMT_X64 ")\n",
2870 paRelocs[j].r_offset, paRelocs[j].r_info, paRelocs[j - 1].r_offset);
2871 uint32_t const iSymbol = ELF64_R_SYM(paRelocs[j].r_info);
2872 if (RT_UNLIKELY(iSymbol >= cSymbols))
2873 fRet = error(pszFile,
2874 "%#018" ELF_FMT_X64 " %#018" ELF_FMT_X64 ": symbol index (%#x) out of bounds (%#x)\n",
2875 paRelocs[j].r_offset, paRelocs[j].r_info, iSymbol, cSymbols);
2876 }
2877 if (RT_UNLIKELY( cRelocs > 0
2878 && fRet
2879 && ( paRelocs[cRelocs - 1].r_offset > paShdrs[i - 1].sh_size
2880 || paRelocs[cRelocs - 1].r_offset + ELF_AMD64_RELOC_SIZE(ELF64_R_TYPE(paRelocs[cRelocs-1].r_info))
2881 > paShdrs[i - 1].sh_size )))
2882 fRet = error(pszFile,
2883 "%#018" ELF_FMT_X64 " %#018" ELF_FMT_X64 ": out of bounds (sh_size %" ELF_FMT_X64 ")\n",
2884 paRelocs[cRelocs - 1].r_offset, paRelocs[cRelocs - 1].r_info, paShdrs[i - 1].sh_size);
2885
2886 }
2887 else if (paShdrs[i].sh_type == SHT_REL)
2888 fRet = error(pszFile, "Section #%u '%s': Unexpected SHT_REL section\n", i, pszShNm);
2889 else if (paShdrs[i].sh_type == SHT_SYMTAB)
2890 {
2891 if (paShdrs[i].sh_entsize != sizeof(Elf64_Sym))
2892 fRet = error(pszFile, "Section #%u '%s': Unsupported symbol table entry size in : #%u (expected #%u)\n",
2893 i, pszShNm, paShdrs[i].sh_entsize, sizeof(Elf64_Sym));
2894 Elf64_Xword const cSymbols = paShdrs[i].sh_size / paShdrs[i].sh_entsize;
2895 if (cSymbols * paShdrs[i].sh_entsize != paShdrs[i].sh_size)
2896 fRet = error(pszFile, "Section #%u '%s': Size not a multiple of entry size: %#" ELF_FMT_X64 " %% %#" ELF_FMT_X64 " = %#" ELF_FMT_X64 "\n",
2897 i, pszShNm, paShdrs[i].sh_size, paShdrs[i].sh_entsize, paShdrs[i].sh_size % paShdrs[i].sh_entsize);
2898 if (cSymbols > UINT32_MAX)
2899 fRet = error(pszFile, "Section #%u '%s': too many symbols: %" ELF_FMT_X64 "\n",
2900 i, pszShNm, paShdrs[i].sh_size, cSymbols);
2901
2902 if (pElfStuff->iSymSh == UINT16_MAX)
2903 {
2904 pElfStuff->iSymSh = (uint16_t)i;
2905 pElfStuff->paSymbols = (Elf64_Sym const *)&pbFile[paShdrs[i].sh_offset];
2906 pElfStuff->cSymbols = cSymbols;
2907
2908 if (paShdrs[i].sh_link != 0)
2909 {
2910 /* Note! The symbol string table section header may not have been validated yet! */
2911 Elf64_Shdr const *pStrTabShdr = &paShdrs[paShdrs[i].sh_link];
2912 pElfStuff->iStrSh = paShdrs[i].sh_link;
2913 pElfStuff->pchStrTab = (const char *)&pbFile[pStrTabShdr->sh_offset];
2914 pElfStuff->cbStrTab = (size_t)pStrTabShdr->sh_size;
2915 }
2916 else
2917 fRet = error(pszFile, "Section #%u '%s': String table link is out of bounds (%#x)\n",
2918 i, pszShNm, paShdrs[i].sh_link);
2919 }
2920 else
2921 fRet = error(pszFile, "Section #%u '%s': Found additonal symbol table, previous in #%u\n",
2922 i, pszShNm, pElfStuff->iSymSh);
2923 }
2924 }
2925 return fRet;
2926}
2927
2928static bool convertElfSectionsToSegDefsAndGrpDefs(POMFWRITER pThis, PCELFDETAILS pElfStuff)
2929{
2930 /*
2931 * Do the list of names pass.
2932 */
2933 uint16_t idxGrpFlat, idxGrpData;
2934 uint16_t idxClassCode, idxClassData, idxClassDwarf;
2935 if ( !omfWriter_LNamesBegin(pThis, true /*fAddZeroEntry*/)
2936 || !omfWriter_LNamesAddN(pThis, RT_STR_TUPLE("FLAT"), &idxGrpFlat)
2937 || !omfWriter_LNamesAddN(pThis, RT_STR_TUPLE("BS3DATA64_GROUP"), &idxGrpData)
2938 || !omfWriter_LNamesAddN(pThis, RT_STR_TUPLE("BS3CLASS64CODE"), &idxClassCode)
2939 || !omfWriter_LNamesAddN(pThis, RT_STR_TUPLE("FAR_DATA"), &idxClassData)
2940 || !omfWriter_LNamesAddN(pThis, RT_STR_TUPLE("DWARF"), &idxClassDwarf)
2941 )
2942 return false;
2943
2944 bool fHaveData = false;
2945 Elf64_Shdr const *pShdr = &pElfStuff->paShdrs[1];
2946 Elf64_Half const cSections = pElfStuff->pEhdr->e_shnum;
2947 for (Elf64_Half i = 1; i < cSections; i++, pShdr++)
2948 {
2949 const char *pszName = &pElfStuff->pchShStrTab[pShdr->sh_name];
2950 if (*pszName == '\0')
2951 return error(pThis->pszSrc, "Section #%u has an empty name!\n", i);
2952
2953 switch (pShdr->sh_type)
2954 {
2955 case SHT_PROGBITS:
2956 case SHT_NOBITS:
2957 /* We drop a few sections we don't want:. */
2958 if ( strcmp(pszName, ".comment") != 0 /* compiler info */
2959 && strcmp(pszName, ".note.GNU-stack") != 0 /* some empty section for hinting the linker/whatever */
2960 && strcmp(pszName, ".eh_frame") != 0 /* unwind / exception info */
2961 )
2962 {
2963 pThis->paSegments[i].iSegDef = UINT16_MAX;
2964 pThis->paSegments[i].iGrpDef = UINT16_MAX;
2965
2966 /* Translate the name and determine group and class.
2967 Note! We currently strip sub-sections. */
2968 if ( strcmp(pszName, ".text") == 0
2969 || strncmp(pszName, RT_STR_TUPLE(".text.")) == 0)
2970 {
2971 pszName = "BS3TEXT64";
2972 pThis->paSegments[i].iGrpNm = idxGrpFlat;
2973 pThis->paSegments[i].iClassNm = idxClassCode;
2974 }
2975 else if ( strcmp(pszName, ".data") == 0
2976 || strncmp(pszName, RT_STR_TUPLE(".data.")) == 0)
2977 {
2978 pszName = "BS3DATA64";
2979 pThis->paSegments[i].iGrpNm = idxGrpData;
2980 pThis->paSegments[i].iClassNm = idxClassData;
2981 }
2982 else if (strcmp(pszName, ".bss") == 0)
2983 {
2984 pszName = "BS3BSS64";
2985 pThis->paSegments[i].iGrpNm = idxGrpData;
2986 pThis->paSegments[i].iClassNm = idxClassData;
2987 }
2988 else if ( strcmp(pszName, ".rodata") == 0
2989 || strncmp(pszName, RT_STR_TUPLE(".rodata.")) == 0)
2990 {
2991 pszName = "BS3DATA64CONST";
2992 pThis->paSegments[i].iGrpNm = idxGrpData;
2993 pThis->paSegments[i].iClassNm = idxClassData;
2994 }
2995 else if (strncmp(pszName, RT_STR_TUPLE(".debug_")) == 0)
2996 {
2997 pThis->paSegments[i].iGrpNm = UINT16_MAX;
2998 pThis->paSegments[i].iClassNm = idxClassDwarf;
2999 }
3000 else
3001 {
3002 pThis->paSegments[i].iGrpNm = idxGrpData;
3003 pThis->paSegments[i].iClassNm = idxClassData;
3004 error(pThis->pszSrc, "Unknown data (?) segment: '%s'\n", pszName);
3005 }
3006
3007 /* Save the name. */
3008 pThis->paSegments[i].pszName = strdup(pszName);
3009 if (!pThis->paSegments[i].pszName)
3010 return error(pThis->pszSrc, "Out of memory!\n");
3011
3012 /* Add the section name. */
3013 if (!omfWriter_LNamesAdd(pThis, pThis->paSegments[i].pszName, &pThis->paSegments[i].iSegNm))
3014 return false;
3015
3016 fHaveData |= pThis->paSegments[i].iGrpDef == idxGrpData;
3017 break;
3018 }
3019 /* fall thru */
3020
3021 default:
3022 pThis->paSegments[i].iSegDef = UINT16_MAX;
3023 pThis->paSegments[i].iGrpDef = UINT16_MAX;
3024 pThis->paSegments[i].iSegNm = UINT16_MAX;
3025 pThis->paSegments[i].iGrpNm = UINT16_MAX;
3026 pThis->paSegments[i].iClassNm = UINT16_MAX;
3027 pThis->paSegments[i].pszName = NULL;
3028 break;
3029 }
3030 }
3031
3032 if (!omfWriter_LNamesEnd(pThis))
3033 return false;
3034
3035 /*
3036 * Emit segment definitions.
3037 */
3038 uint16_t iSegDef = 1; /* Start counting at 1. */
3039 pShdr = &pElfStuff->paShdrs[1];
3040 for (Elf64_Half i = 1; i < cSections; i++, pShdr++)
3041 {
3042 if (pThis->paSegments[i].iSegNm == UINT16_MAX)
3043 continue;
3044
3045 uint8_t bSegAttr = 0;
3046
3047 /* The A field. */
3048 switch (pShdr->sh_addralign)
3049 {
3050 case 0:
3051 case 1:
3052 bSegAttr |= 1 << 5;
3053 break;
3054 case 2:
3055 bSegAttr |= 2 << 5;
3056 break;
3057 case 4:
3058 bSegAttr |= 5 << 5;
3059 break;
3060 case 8:
3061 case 16:
3062 bSegAttr |= 3 << 5;
3063 break;
3064 case 32:
3065 case 64:
3066 case 128:
3067 case 256:
3068 bSegAttr |= 4 << 5;
3069 break;
3070 default:
3071 bSegAttr |= 6 << 5; /* page aligned, pharlabs extension. */
3072 break;
3073 }
3074
3075 /* The C field. */
3076 bSegAttr |= 2 << 2; /* public */
3077
3078 /* The B field. We don't have 4GB segments, so leave it as zero. */
3079
3080 /* The D field shall be set as we're doing USE32. */
3081 bSegAttr |= 1;
3082
3083
3084 /* Done. */
3085 if (!omfWriter_SegDef(pThis, bSegAttr, (uint32_t)pShdr->sh_size,
3086 pThis->paSegments[i].iSegNm,
3087 pThis->paSegments[i].iClassNm))
3088 return false;
3089 pThis->paSegments[i].iSegDef = iSegDef++;
3090 }
3091
3092 /*
3093 * Flat group definition (#1) - special, no members.
3094 */
3095 uint16_t iGrpDef = 1;
3096 if ( !omfWriter_GrpDefBegin(pThis, idxGrpFlat)
3097 || !omfWriter_GrpDefEnd(pThis))
3098 return false;
3099 for (uint16_t i = 0; i < cSections; i++)
3100 if (pThis->paSegments[i].iGrpNm == idxGrpFlat)
3101 pThis->paSegments[i].iGrpDef = iGrpDef;
3102 pThis->idxGrpFlat = iGrpDef++;
3103
3104 /*
3105 * Data group definition (#2).
3106 */
3107 /** @todo do we need to consider missing segments and ordering? */
3108 uint16_t cGrpNms = 0;
3109 uint16_t aiGrpNms[2];
3110 if (fHaveData)
3111 aiGrpNms[cGrpNms++] = idxGrpData;
3112 for (uint32_t iGrpNm = 0; iGrpNm < cGrpNms; iGrpNm++)
3113 {
3114 if (!omfWriter_GrpDefBegin(pThis, aiGrpNms[iGrpNm]))
3115 return false;
3116 for (uint16_t i = 0; i < cSections; i++)
3117 if (pThis->paSegments[i].iGrpNm == aiGrpNms[iGrpNm])
3118 {
3119 pThis->paSegments[i].iGrpDef = iGrpDef;
3120 if (!omfWriter_GrpDefAddSegDef(pThis, pThis->paSegments[i].iSegDef))
3121 return false;
3122 }
3123 if (!omfWriter_GrpDefEnd(pThis))
3124 return false;
3125 iGrpDef++;
3126 }
3127
3128 return true;
3129}
3130
3131static bool convertElfSymbolsToPubDefsAndExtDefs(POMFWRITER pThis, PCELFDETAILS pElfStuff)
3132{
3133 if (!pElfStuff->cSymbols)
3134 return true;
3135
3136 /*
3137 * Process the symbols the first.
3138 */
3139 uint32_t cAbsSyms = 0;
3140 uint32_t cExtSyms = 0;
3141 uint32_t cPubSyms = 0;
3142 for (uint32_t iSeg = 0; iSeg < pThis->cSegments; iSeg++)
3143 pThis->paSegments[iSeg].cPubDefs = 0;
3144
3145 uint32_t const cSections = pElfStuff->pEhdr->e_shnum;
3146 uint32_t const cSymbols = pElfStuff->cSymbols;
3147 Elf64_Sym const * const paSymbols = pElfStuff->paSymbols;
3148 for (uint32_t iSym = 0; iSym < cSymbols; iSym++)
3149 {
3150 const uint8_t bBind = ELF64_ST_BIND(paSymbols[iSym].st_info);
3151 const uint8_t bType = ELF64_ST_TYPE(paSymbols[iSym].st_info);
3152 const char *pszSymName = &pElfStuff->pchStrTab[paSymbols[iSym].st_name];
3153 if ( *pszSymName == '\0'
3154 && bType == STT_SECTION
3155 && paSymbols[iSym].st_shndx < cSections)
3156 pszSymName = &pElfStuff->pchShStrTab[pElfStuff->paShdrs[paSymbols[iSym].st_shndx].sh_name];
3157
3158 pThis->paSymbols[iSym].enmType = OMFSYMTYPE_IGNORED;
3159 pThis->paSymbols[iSym].idx = UINT16_MAX;
3160 pThis->paSymbols[iSym].idxSegDef = UINT16_MAX;
3161 pThis->paSymbols[iSym].idxGrpDef = UINT16_MAX;
3162
3163 uint32_t const idxSection = paSymbols[iSym].st_shndx;
3164 if (idxSection == SHN_UNDEF)
3165 {
3166 if (bBind == STB_GLOBAL)
3167 {
3168 pThis->paSymbols[iSym].enmType = OMFSYMTYPE_EXTDEF;
3169 cExtSyms++;
3170 if (*pszSymName == '\0')
3171 return error(pThis->pszSrc, "External symbol #%u (%s) has an empty name.\n", iSym, pszSymName);
3172 }
3173 else if (bBind != STB_LOCAL || iSym != 0) /* Entry zero is usually a dummy. */
3174 return error(pThis->pszSrc, "Unsupported or invalid bind type %#x for undefined symbol #%u (%s)\n",
3175 bBind, iSym, pszSymName);
3176 }
3177 else if (idxSection < cSections)
3178 {
3179 pThis->paSymbols[iSym].idxSegDef = pThis->paSegments[idxSection].iSegDef;
3180 pThis->paSymbols[iSym].idxGrpDef = pThis->paSegments[idxSection].iGrpDef;
3181 if (bBind == STB_GLOBAL)
3182 {
3183 pThis->paSymbols[iSym].enmType = OMFSYMTYPE_PUBDEF;
3184 pThis->paSegments[idxSection].cPubDefs++;
3185 cPubSyms++;
3186 if (bType == STT_SECTION)
3187 return error(pThis->pszSrc, "Don't know how to export STT_SECTION symbol #%u (%s)\n", iSym, pszSymName);
3188 if (*pszSymName == '\0')
3189 return error(pThis->pszSrc, "Public symbol #%u (%s) has an empty name.\n", iSym, pszSymName);
3190 }
3191 else if (bType == STT_SECTION)
3192 pThis->paSymbols[iSym].enmType = OMFSYMTYPE_SEGDEF;
3193 else
3194 pThis->paSymbols[iSym].enmType = OMFSYMTYPE_INTERNAL;
3195 }
3196 else if (idxSection == SHN_ABS)
3197 {
3198 if (bType != STT_FILE)
3199 {
3200 if (bBind == STB_GLOBAL)
3201 {
3202 pThis->paSymbols[iSym].enmType = OMFSYMTYPE_PUBDEF;
3203 pThis->paSymbols[iSym].idxSegDef = 0;
3204 pThis->paSymbols[iSym].idxGrpDef = 0;
3205 cAbsSyms++;
3206 if (*pszSymName == '\0')
3207 return error(pThis->pszSrc, "Public absolute symbol #%u (%s) has an empty name.\n", iSym, pszSymName);
3208 }
3209 else
3210 return error(pThis->pszSrc, "Unsupported or invalid bind type %#x for absolute symbol #%u (%s)\n",
3211 bBind, iSym, pszSymName);
3212 }
3213 }
3214 else
3215 return error(pThis->pszSrc, "Unsupported or invalid section number %#x for symbol #%u (%s)\n",
3216 idxSection, iSym, pszSymName);
3217 }
3218
3219 /*
3220 * Emit the PUBDEFs the first time around (see order of records in TIS spec).
3221 */
3222 uint16_t idxPubDef = 1;
3223 if (cPubSyms)
3224 {
3225 for (uint32_t iSeg = 0; iSeg < pThis->cSegments; iSeg++)
3226 if (pThis->paSegments[iSeg].cPubDefs > 0)
3227 {
3228 uint16_t const idxSegDef = pThis->paSegments[iSeg].iSegDef;
3229 if (!omfWriter_PubDefBegin(pThis, pThis->paSegments[iSeg].iGrpDef, idxSegDef))
3230 return false;
3231 for (uint16_t iSym = 0; iSym < cSymbols; iSym++)
3232 if ( pThis->paSymbols[iSym].idxSegDef == idxSegDef
3233 && pThis->paSymbols[iSym].enmType == OMFSYMTYPE_PUBDEF)
3234 {
3235 const char *pszName = &pElfStuff->pchStrTab[paSymbols[iSym].st_name];
3236 if (!omfWriter_PubDefAdd(pThis, paSymbols[iSym].st_value, pszName))
3237 return false;
3238
3239 /* If the symbol doesn't start with an underscore and is a _c64 or _lm64 symbol,
3240 add an underscore prefixed alias to ease access from 16-bit and 32-bit code. */
3241 size_t cchName = strlen(pszName);
3242 if ( *pszName != '_'
3243 && ( (cchName > 4 && strcmp(&pszName[cchName - 4], "_c64") == 0)
3244 || (cchName > 5 && strcmp(&pszName[cchName - 5], "_lm64") == 0) ) )
3245 {
3246 char szCdeclName[512];
3247 if (cchName > sizeof(szCdeclName) - 2)
3248 cchName = sizeof(szCdeclName) - 2;
3249 szCdeclName[0] = '_';
3250 memcpy(&szCdeclName[1], pszName, cchName);
3251 szCdeclName[cchName + 1] = '\0';
3252 if (!omfWriter_PubDefAdd(pThis, paSymbols[iSym].st_value, szCdeclName))
3253 return false;
3254 }
3255
3256 pThis->paSymbols[iSym].idx = idxPubDef++;
3257 }
3258 if (!omfWriter_PubDefEnd(pThis))
3259 return false;
3260 }
3261 }
3262
3263 if (cAbsSyms > 0)
3264 {
3265 if (!omfWriter_PubDefBegin(pThis, 0, 0))
3266 return false;
3267 for (uint16_t iSym = 0; iSym < cSymbols; iSym++)
3268 if ( pThis->paSymbols[iSym].idxSegDef == 0
3269 && pThis->paSymbols[iSym].enmType == OMFSYMTYPE_PUBDEF)
3270 {
3271 const char *pszName = &pElfStuff->pchStrTab[paSymbols[iSym].st_name];
3272 if (!omfWriter_PubDefAdd(pThis, paSymbols[iSym].st_value, pszName))
3273 return false;
3274 pThis->paSymbols[iSym].idx = idxPubDef++;
3275 }
3276 if (!omfWriter_PubDefEnd(pThis))
3277 return false;
3278 }
3279
3280 /*
3281 * Go over the symbol table and emit external definition records.
3282 */
3283 if (!omfWriter_ExtDefBegin(pThis))
3284 return false;
3285 uint16_t idxExtDef = 1;
3286 for (uint16_t iSym = 0; iSym < cSymbols; iSym++)
3287 if (pThis->paSymbols[iSym].enmType == OMFSYMTYPE_EXTDEF)
3288 {
3289 const char *pszName = &pElfStuff->pchStrTab[paSymbols[iSym].st_name];
3290 if (!omfWriter_ExtDefAdd(pThis, pszName))
3291 return false;
3292 pThis->paSymbols[iSym].idx = idxExtDef++;
3293 }
3294
3295 if (!omfWriter_ExtDefEnd(pThis))
3296 return false;
3297
3298 return true;
3299}
3300
3301static bool convertElfSectionsToLeDataAndFixupps(POMFWRITER pThis, PCELFDETAILS pElfStuff, uint8_t const *pbFile, size_t cbFile)
3302{
3303 Elf64_Sym const *paSymbols = pElfStuff->paSymbols;
3304 Elf64_Shdr const *paShdrs = pElfStuff->paShdrs;
3305 bool fRet = true;
3306 for (uint32_t i = 1; i < pThis->cSegments; i++)
3307 {
3308 if (pThis->paSegments[i].iSegDef == UINT16_MAX)
3309 continue;
3310
3311 const char *pszSegNm = &pElfStuff->pchShStrTab[paShdrs[i].sh_name];
3312 bool const fRelocs = i + 1 < pThis->cSegments && paShdrs[i + 1].sh_type == SHT_RELA;
3313 uint32_t cRelocs = fRelocs ? paShdrs[i + 1].sh_size / sizeof(Elf64_Rela) : 0;
3314 Elf64_Rela const *paRelocs = fRelocs ? (Elf64_Rela *)&pbFile[paShdrs[i + 1].sh_offset] : NULL;
3315 Elf64_Xword cbVirtData = paShdrs[i].sh_size;
3316 Elf64_Xword cbData = paShdrs[i].sh_type == SHT_NOBITS ? 0 : cbVirtData;
3317 uint8_t const *pbData = &pbFile[paShdrs[i].sh_offset];
3318 uint32_t off = 0;
3319
3320 /* The OMF record size requires us to split larger sections up. To make
3321 life simple, we fill zeros for unitialized (BSS) stuff. */
3322 const uint32_t cbMaxData = RT_MIN(OMF_MAX_RECORD_PAYLOAD - 1 - (pThis->paSegments[i].iSegDef >= 128) - 4 - 1, _1K);
3323 while (cbVirtData > 0)
3324 {
3325 /* Figure out how many bytes to put out in this chunk. Must make sure
3326 fixups doesn't cross chunk boundraries. ASSUMES sorted relocs. */
3327 uint32_t cChunkRelocs = cRelocs;
3328 uint32_t cbChunk = cbVirtData;
3329 uint32_t offEnd = off + cbChunk;
3330 if (cbChunk > cbMaxData)
3331 {
3332 cbChunk = cbMaxData;
3333 offEnd = off + cbChunk;
3334 cChunkRelocs = 0;
3335
3336 /* Quickly determin the reloc range. */
3337 while ( cChunkRelocs < cRelocs
3338 && paRelocs[cChunkRelocs].r_offset < offEnd)
3339 cChunkRelocs++;
3340
3341 /* Ensure final reloc doesn't go beyond chunk. */
3342 while ( cChunkRelocs > 0
3343 && paRelocs[cChunkRelocs - 1].r_offset
3344 + ELF_AMD64_RELOC_SIZE(ELF64_R_TYPE(paRelocs[cChunkRelocs - 1].r_info))
3345 > offEnd)
3346 {
3347 uint32_t cbDrop = offEnd - paRelocs[cChunkRelocs - 1].r_offset;
3348 cbChunk -= cbDrop;
3349 offEnd -= cbDrop;
3350 cChunkRelocs--;
3351 }
3352
3353 if (!cbVirtData)
3354 return error(pThis->pszSrc, "Wtf? cbVirtData is zero!\n");
3355 }
3356
3357 /*
3358 * We stash the bytes into the OMF writer record buffer, receiving a
3359 * pointer to the start of it so we can make adjustments if necessary.
3360 */
3361 uint8_t *pbCopy;
3362 if (!omfWriter_LEDataBeginEx(pThis, pThis->paSegments[i].iSegDef, off, cbChunk, cbData, pbData, &pbCopy))
3363 return false;
3364
3365 /*
3366 * Convert fiuxps.
3367 */
3368 for (uint32_t iReloc = 0; iReloc < cChunkRelocs; iReloc++)
3369 {
3370 /* Get the OMF and ELF data for the symbol the reloc references. */
3371 uint32_t const uType = ELF64_R_TYPE(paRelocs[iReloc].r_info);
3372 uint32_t const iSymbol = ELF64_R_SYM(paRelocs[iReloc].r_info);
3373 Elf64_Sym const * const pElfSym = &paSymbols[iSymbol];
3374 POMFSYMBOL const pOmfSym = &pThis->paSymbols[iSymbol];
3375 const char * const pszSymName = &pElfStuff->pchStrTab[pElfSym->st_name];
3376
3377 /* Calc fixup location in the pending chunk and setup a flexible pointer to it. */
3378 uint16_t offDataRec = (uint16_t)(paRelocs[iReloc].r_offset - off);
3379 RTPTRUNION uLoc;
3380 uLoc.pu8 = &pbCopy[offDataRec];
3381
3382 /* OMF fixup data initialized with typical defaults. */
3383 bool fSelfRel = true;
3384 uint8_t bLocation = OMF_FIX_LOC_32BIT_OFFSET;
3385 uint8_t bFrame = OMF_FIX_F_GRPDEF;
3386 uint16_t idxFrame = pThis->idxGrpFlat;
3387 uint8_t bTarget;
3388 uint16_t idxTarget;
3389 bool fTargetDisp;
3390 uint32_t offTargetDisp;
3391 switch (pOmfSym->enmType)
3392 {
3393 case OMFSYMTYPE_INTERNAL:
3394 case OMFSYMTYPE_PUBDEF:
3395 bTarget = OMF_FIX_T_SEGDEF;
3396 idxTarget = pOmfSym->idxSegDef;
3397 fTargetDisp = true;
3398 offTargetDisp = pElfSym->st_value;
3399 break;
3400
3401 case OMFSYMTYPE_SEGDEF:
3402 bTarget = OMF_FIX_T_SEGDEF_NO_DISP;
3403 idxTarget = pOmfSym->idxSegDef;
3404 fTargetDisp = false;
3405 offTargetDisp = 0;
3406 break;
3407
3408 case OMFSYMTYPE_EXTDEF:
3409 bTarget = OMF_FIX_T_EXTDEF_NO_DISP;
3410 idxTarget = pOmfSym->idx;
3411 fTargetDisp = false;
3412 offTargetDisp = 0;
3413 break;
3414
3415 default:
3416 return error(pThis->pszSrc, "Relocation in segment #%u '%s' references ignored or invalid symbol (%s)\n",
3417 i, pszSegNm, pszSymName);
3418 }
3419
3420 /* Do COFF relocation type conversion. */
3421 switch (uType)
3422 {
3423 case R_X86_64_64:
3424 {
3425 int64_t iAddend = paRelocs[iReloc].r_addend;
3426 if (iAddend > _1G || iAddend < -_1G)
3427 fRet = error(pThis->pszSrc, "R_X86_64_64 with large addend (%" ELF_FMT_D64 ") at %#x in segment #%u '%s'\n",
3428 iAddend, paRelocs[iReloc].r_offset, i, pszSegNm);
3429 *uLoc.pu64 = iAddend;
3430 fSelfRel = false;
3431 break;
3432 }
3433
3434 case R_X86_64_32:
3435 case R_X86_64_32S: /* signed, unsigned, whatever. */
3436 fSelfRel = false;
3437 /* fall thru */
3438 case R_X86_64_PC32:
3439 {
3440 /* defaults are ok, just handle the addend. */
3441 int32_t iAddend = paRelocs[iReloc].r_addend;
3442 if (iAddend != paRelocs[iReloc].r_addend)
3443 fRet = error(pThis->pszSrc, "R_X86_64_PC32 with large addend (%d) at %#x in segment #%u '%s'\n",
3444 iAddend, paRelocs[iReloc].r_offset, i, pszSegNm);
3445 *uLoc.pu32 = iAddend;
3446 break;
3447 }
3448
3449 case R_X86_64_NONE:
3450 continue; /* Ignore this one */
3451
3452 case R_X86_64_GOT32:
3453 case R_X86_64_PLT32:
3454 case R_X86_64_COPY:
3455 case R_X86_64_GLOB_DAT:
3456 case R_X86_64_JMP_SLOT:
3457 case R_X86_64_RELATIVE:
3458 case R_X86_64_GOTPCREL:
3459 case R_X86_64_16:
3460 case R_X86_64_PC16:
3461 case R_X86_64_8:
3462 case R_X86_64_PC8:
3463 case R_X86_64_DTPMOD64:
3464 case R_X86_64_DTPOFF64:
3465 case R_X86_64_TPOFF64:
3466 case R_X86_64_TLSGD:
3467 case R_X86_64_TLSLD:
3468 case R_X86_64_DTPOFF32:
3469 case R_X86_64_GOTTPOFF:
3470 case R_X86_64_TPOFF32:
3471 default:
3472 return error(pThis->pszSrc, "Unsupported fixup type %#x (%s) at rva=%#x in section #%u '%s' against '%s'\n",
3473 uType, g_apszElfAmd64RelTypes[uType], paRelocs[iReloc].r_offset, i, pszSegNm, pszSymName);
3474 }
3475
3476 /* Add the fixup. */
3477 if (idxFrame == UINT16_MAX)
3478 error(pThis->pszSrc, "idxFrame=UINT16_MAX for %s type=%s\n", pszSymName, g_apszElfAmd64RelTypes[uType]);
3479 fRet = omfWriter_LEDataAddFixup(pThis, offDataRec, fSelfRel, bLocation, bFrame, idxFrame,
3480 bTarget, idxTarget, fTargetDisp, offTargetDisp) && fRet;
3481 }
3482
3483 /*
3484 * Write the LEDATA and associated FIXUPPs.
3485 */
3486 if (!omfWriter_LEDataEnd(pThis))
3487 return false;
3488
3489 /*
3490 * Advance.
3491 */
3492 paRelocs += cChunkRelocs;
3493 cRelocs -= cChunkRelocs;
3494 if (cbData > cbChunk)
3495 {
3496 cbData -= cbChunk;
3497 pbData += cbChunk;
3498 }
3499 else
3500 cbData = 0;
3501 off += cbChunk;
3502 cbVirtData -= cbChunk;
3503 }
3504 }
3505
3506 return fRet;
3507}
3508
3509
3510static bool convertMachoToOmf(const char *pszFile, uint8_t const *pbFile, size_t cbFile, FILE *pDst)
3511{
3512 /*
3513 * Validate the source file a little.
3514 */
3515 ELFDETAILS ElfStuff;
3516 if (!validateElf(pszFile, pbFile, cbFile, &ElfStuff))
3517 return false;
3518
3519 /*
3520 * Instantiate the OMF writer.
3521 */
3522 POMFWRITER pThis = omfWriter_Create(pszFile, ElfStuff.pEhdr->e_shnum, ElfStuff.cSymbols, pDst);
3523 if (!pThis)
3524 return false;
3525
3526 /*
3527 * Write the OMF object file.
3528 */
3529 if (omfWriter_BeginModule(pThis, pszFile))
3530 {
3531 Elf64_Ehdr const *pEhdr = (Elf64_Ehdr const *)pbFile;
3532 Elf64_Shdr const *paShdrs = (Elf64_Shdr const *)&pbFile[pEhdr->e_shoff];
3533 const char *pszStrTab = (const char *)&pbFile[paShdrs[pEhdr->e_shstrndx].sh_offset];
3534
3535 if ( convertElfSectionsToSegDefsAndGrpDefs(pThis, &ElfStuff)
3536 && convertElfSymbolsToPubDefsAndExtDefs(pThis, &ElfStuff)
3537 && omfWriter_LinkPassSeparator(pThis)
3538 && convertElfSectionsToLeDataAndFixupps(pThis, &ElfStuff, pbFile, cbFile)
3539 && omfWriter_EndModule(pThis) )
3540 {
3541
3542 omfWriter_Destroy(pThis);
3543 return true;
3544 }
3545 }
3546
3547 omfWriter_Destroy(pThis);
3548 return false;
3549}
3550
3551#endif /* !MACHO_TO_OMF_CONVERSION */
3552
3553
3554/*********************************************************************************************************************************
3555* OMF Converter/Tweaker *
3556*********************************************************************************************************************************/
3557
3558/** Watcom intrinsics we need to modify so we can mix 32-bit and 16-bit
3559 * code, since the 16 and 32 bit compilers share several names.
3560 * The names are length prefixed.
3561 */
3562static const char * const g_apszExtDefRenames[] =
3563{
3564 "\x05" "__I4D",
3565 "\x05" "__I4M",
3566 "\x05" "__I8D",
3567 "\x06" "__I8DQ",
3568 "\x07" "__I8DQE",
3569 "\x06" "__I8DR",
3570 "\x07" "__I8DRE",
3571 "\x06" "__I8LS",
3572 "\x05" "__I8M",
3573 "\x06" "__I8ME",
3574 "\x06" "__I8RS",
3575 "\x05" "__PIA",
3576 "\x05" "__PIS",
3577 "\x05" "__PTC",
3578 "\x05" "__PTS",
3579 "\x05" "__U4D",
3580 "\x05" "__U4M",
3581 "\x05" "__U8D",
3582 "\x06" "__U8DQ",
3583 "\x07" "__U8DQE",
3584 "\x06" "__U8DR",
3585 "\x07" "__U8DRE",
3586 "\x06" "__U8LS",
3587 "\x05" "__U8M",
3588 "\x06" "__U8ME",
3589 "\x06" "__U8RS",
3590};
3591
3592/**
3593 * Records line number information for a file in a segment (for CV8 debug info).
3594 */
3595typedef struct OMFFILELINES
3596{
3597 /** The source info offset. */
3598 uint32_t offSrcInfo;
3599 /** Number of line/offset pairs. */
3600 uint32_t cPairs;
3601 /** Number of pairs allocated. */
3602 uint32_t cPairsAlloc;
3603 /** Table with line number and offset pairs, ordered by offset. */
3604 PRTCV8LINEPAIR paPairs;
3605} OMFFILEINES;
3606typedef OMFFILEINES *POMFFILEINES;
3607
3608/**
3609 * Records line number information for a segment (for CV8 debug info).
3610 */
3611typedef struct OMFSEGLINES
3612{
3613 /** Number of files. */
3614 uint32_t cFiles;
3615 /** Number of bytes we need. */
3616 uint32_t cb;
3617 /** The segment index. */
3618 uint16_t idxSeg;
3619 /** File table. */
3620 POMFFILEINES paFiles;
3621} OMFSEGLINES;
3622typedef OMFSEGLINES *POMFSEGLINES;
3623
3624/**
3625 * OMF conversion details.
3626 *
3627 * Keeps information relevant to the conversion and CV8 debug info.
3628 */
3629typedef struct OMFDETAILS
3630{
3631 /** Set if it has line numbers. */
3632 bool fLineNumbers;
3633 /** Set if we think this may be a 32-bit OMF file. */
3634 bool fProbably32bit;
3635 /** Set if this module may need mangling. */
3636 bool fMayNeedMangling;
3637 /** Number of SEGDEFs records. */
3638 uint32_t cSegDefs;
3639 /** The LNAME index of '$$SYMBOLS' or UINT16_MAX it not found. */
3640 uint16_t iSymbolsNm;
3641 /** The LNAME index of 'DEBSYM' or UINT16_MAX it not found. */
3642 uint16_t iDebSymNm;
3643 /** The '$$SYMBOLS' segment index. */
3644 uint16_t iSymbolsSeg;
3645
3646 /** CV8: Filename string table size. */
3647 uint32_t cbStrTab;
3648 /** CV8: Filename string table allocation size (always multiple of dword,
3649 * zero initialized). */
3650 uint32_t cbStrTabAlloc;
3651 /** CV8: Filename String table. */
3652 char *pchStrTab;
3653 /** CV8: Elements in the source info table. */
3654 uint16_t cSrcInfo;
3655 /** CV8: Source info table. */
3656 PRTCV8SRCINFO paSrcInfo;
3657
3658 /** Number of entries in the paSegLines table. */
3659 uint32_t cSegLines;
3660 /** Segment line numbers, indexed by segment number. */
3661 POMFSEGLINES paSegLines;
3662} OMFDETAILS;
3663typedef OMFDETAILS *POMFDETAILS;
3664typedef OMFDETAILS const *PCOMFDETAILS;
3665
3666
3667/**
3668 * Adds a line number to the CV8 debug info.
3669 *
3670 * @returns success indicator.
3671 * @param pOmfStuff Where to collect CV8 debug info.
3672 * @param cchSrcFile The length of the source file name.
3673 * @param pchSrcFile The source file name, not terminated.
3674 * @param poffFile Where to return the source file information table
3675 * offset (for use in the line number tables).
3676 */
3677static bool collectOmfAddFile(POMFDETAILS pOmfStuff, uint8_t cchSrcFile, const char *pchSrcFile, uint32_t *poffFile)
3678{
3679 /*
3680 * Do lookup first.
3681 */
3682 uint32_t i = pOmfStuff->cSrcInfo;
3683 while (i-- > 0)
3684 {
3685 const char *pszCur = &pOmfStuff->pchStrTab[pOmfStuff->paSrcInfo[i].offSourceName];
3686 if ( strncmp(pszCur, pchSrcFile, cchSrcFile) == 0
3687 && pszCur[cchSrcFile] == '\0')
3688 {
3689 *poffFile = i * sizeof(pOmfStuff->paSrcInfo[0]);
3690 return true;
3691 }
3692 }
3693
3694 /*
3695 * Add it to the string table (dword aligned and zero padded).
3696 */
3697 uint32_t offSrcTab = pOmfStuff->cbStrTab;
3698 if (offSrcTab + cchSrcFile + 1 > pOmfStuff->cbStrTabAlloc)
3699 {
3700 uint32_t cbNew = (offSrcTab == 0) + offSrcTab + cchSrcFile + 1;
3701 cbNew = RT_ALIGN(cbNew, 256);
3702 void *pvNew = realloc(pOmfStuff->pchStrTab, cbNew);
3703 if (!pvNew)
3704 return error("???", "out of memory");
3705 pOmfStuff->pchStrTab = (char *)pvNew;
3706 pOmfStuff->cbStrTabAlloc = cbNew;
3707 memset(&pOmfStuff->pchStrTab[offSrcTab], 0, cbNew - offSrcTab);
3708
3709 if (!offSrcTab)
3710 offSrcTab++;
3711 }
3712
3713 memcpy(&pOmfStuff->pchStrTab[offSrcTab], pchSrcFile, cchSrcFile);
3714 pOmfStuff->pchStrTab[offSrcTab + cchSrcFile] = '\0';
3715 pOmfStuff->cbStrTab = offSrcTab + cchSrcFile + 1;
3716
3717 /*
3718 * Add it to the filename info table.
3719 */
3720 if ((pOmfStuff->cSrcInfo % 8) == 0)
3721 {
3722 void *pvNew = realloc(pOmfStuff->paSrcInfo, sizeof(pOmfStuff->paSrcInfo[0]) * (pOmfStuff->cSrcInfo + 8));
3723 if (!pvNew)
3724 return error("???", "out of memory");
3725 pOmfStuff->paSrcInfo = (PRTCV8SRCINFO)pvNew;
3726 }
3727
3728 PRTCV8SRCINFO pSrcInfo = &pOmfStuff->paSrcInfo[pOmfStuff->cSrcInfo++];
3729 pSrcInfo->offSourceName = offSrcTab;
3730 pSrcInfo->uDigestType = RTCV8SRCINFO_DIGEST_TYPE_MD5;
3731 memset(&pSrcInfo->Digest, 0, sizeof(pSrcInfo->Digest));
3732
3733 *poffFile = (uint32_t)((uintptr_t)pSrcInfo - (uintptr_t)pOmfStuff->paSrcInfo);
3734 return true;
3735}
3736
3737
3738/**
3739 * Adds a line number to the CV8 debug info.
3740 *
3741 * @returns success indicator.
3742 * @param pOmfStuff Where to collect CV8 debug info.
3743 * @param idxSeg The segment index.
3744 * @param off The segment offset.
3745 * @param uLine The line number.
3746 * @param offSrcInfo The source file info table offset.
3747 */
3748static bool collectOmfAddLine(POMFDETAILS pOmfStuff, uint16_t idxSeg, uint32_t off, uint16_t uLine, uint32_t offSrcInfo)
3749{
3750 /*
3751 * Get/add the segment line structure.
3752 */
3753 if (idxSeg >= pOmfStuff->cSegLines)
3754 {
3755 void *pvNew = realloc(pOmfStuff->paSegLines, (idxSeg + 1) * sizeof(pOmfStuff->paSegLines[0]));
3756 if (!pvNew)
3757 return error("???", "out of memory");
3758 pOmfStuff->paSegLines = (POMFSEGLINES)pvNew;
3759
3760 memset(&pOmfStuff->paSegLines[pOmfStuff->cSegLines], 0,
3761 (idxSeg + 1 - pOmfStuff->cSegLines) * sizeof(pOmfStuff->paSegLines[0]));
3762 for (uint32_t i = pOmfStuff->cSegLines; i <= idxSeg; i++)
3763 {
3764 pOmfStuff->paSegLines[i].idxSeg = i;
3765 pOmfStuff->paSegLines[i].cb = sizeof(RTCV8LINESHDR);
3766 }
3767 pOmfStuff->cSegLines = idxSeg + 1;
3768 }
3769 POMFSEGLINES pSegLines = &pOmfStuff->paSegLines[idxSeg];
3770
3771 /*
3772 * Get/add the file structure with the segment.
3773 */
3774 POMFFILEINES pFileLines = NULL;
3775 uint32_t i = pSegLines->cFiles;
3776 while (i-- > 0)
3777 if (pSegLines->paFiles[i].offSrcInfo == offSrcInfo)
3778 {
3779 pFileLines = &pSegLines->paFiles[i];
3780 break;
3781 }
3782 if (!pFileLines)
3783 {
3784 i = pSegLines->cFiles;
3785 if ((i % 4) == 0)
3786 {
3787 void *pvNew = realloc(pSegLines->paFiles, (i + 4) * sizeof(pSegLines->paFiles[0]));
3788 if (!pvNew)
3789 return error("???", "out of memory");
3790 pSegLines->paFiles = (POMFFILEINES)pvNew;
3791 }
3792
3793 pSegLines->cFiles = i + 1;
3794 pSegLines->cb += sizeof(RTCV8LINESSRCMAP);
3795
3796 pFileLines = &pSegLines->paFiles[i];
3797 pFileLines->offSrcInfo = offSrcInfo;
3798 pFileLines->cPairs = 0;
3799 pFileLines->cPairsAlloc = 0;
3800 pFileLines->paPairs = NULL;
3801 }
3802
3803 /*
3804 * Add the line number (sorted, duplicates removed).
3805 */
3806 if (pFileLines->cPairs + 1 > pFileLines->cPairsAlloc)
3807 {
3808 void *pvNew = realloc(pFileLines->paPairs, (pFileLines->cPairsAlloc + 16) * sizeof(pFileLines->paPairs[0]));
3809 if (!pvNew)
3810 return error("???", "out of memory");
3811 pFileLines->paPairs = (PRTCV8LINEPAIR)pvNew;
3812 pFileLines->cPairsAlloc += 16;
3813 }
3814
3815 i = pFileLines->cPairs;
3816 while (i > 0 && ( off < pFileLines->paPairs[i - 1].offSection
3817 || ( off == pFileLines->paPairs[i - 1].offSection
3818 && uLine < pFileLines->paPairs[i - 1].uLineNumber)) )
3819 i--;
3820 if ( i == pFileLines->cPairs
3821 || off != pFileLines->paPairs[i].offSection
3822 || uLine != pFileLines->paPairs[i].uLineNumber)
3823 {
3824 if (i < pFileLines->cPairs)
3825 memmove(&pFileLines->paPairs[i + 1], &pFileLines->paPairs[i],
3826 (pFileLines->cPairs - i) * sizeof(pFileLines->paPairs));
3827 pFileLines->paPairs[i].offSection = off;
3828 pFileLines->paPairs[i].uLineNumber = uLine;
3829 pFileLines->paPairs[i].fEndOfStatement = true;
3830 pFileLines->cPairs++;
3831 pSegLines->cb += sizeof(pFileLines->paPairs[0]);
3832 }
3833
3834 return true;
3835}
3836
3837
3838/**
3839 * Parses OMF file gathering line numbers (for CV8 debug info) and checking out
3840 * external defintions for mangling work (compiler instrinsics).
3841 *
3842 * @returns success indicator.
3843 * @param pszFile The name of the OMF file.
3844 * @param pbFile The file content.
3845 * @param cbFile The size of the file content.
3846 * @param pOmfStuff Where to collect CV8 debug info and anything else we
3847 * find out about the OMF file.
3848 */
3849static bool collectOmfDetails(const char *pszFile, uint8_t const *pbFile, size_t cbFile, POMFDETAILS pOmfStuff)
3850{
3851 uint32_t cLNames = 0;
3852 uint32_t cExtDefs = 0;
3853 uint32_t cPubDefs = 0;
3854 uint32_t off = 0;
3855 uint8_t cchSrcFile = 0;
3856 const char *pchSrcFile = NULL;
3857 uint32_t offSrcInfo = UINT32_MAX;
3858
3859 memset(pOmfStuff, 0, sizeof(*pOmfStuff));
3860 pOmfStuff->iDebSymNm = UINT16_MAX;
3861 pOmfStuff->iSymbolsNm = UINT16_MAX;
3862 pOmfStuff->iSymbolsSeg = UINT16_MAX;
3863
3864 while (off + 3 < cbFile)
3865 {
3866 uint8_t bRecType = pbFile[off];
3867 uint16_t cbRec = RT_MAKE_U16(pbFile[off + 1], pbFile[off + 2]);
3868 if (g_cVerbose > 2)
3869 printf( "%#07x: type=%#04x len=%#06x\n", off, bRecType, cbRec);
3870 if (off + cbRec > cbFile)
3871 return error(pszFile, "Invalid record length at %#x: %#x (cbFile=%#lx)\n", off, cbRec, (unsigned long)cbFile);
3872
3873 uint32_t offRec = 0;
3874 uint8_t const *pbRec = &pbFile[off + 3];
3875#define OMF_CHECK_RET(a_cbReq, a_Name) /* Not taking the checksum into account, so we're good with 1 or 2 byte fields. */ \
3876 if (offRec + (a_cbReq) <= cbRec) {/*likely*/} \
3877 else return error(pszFile, "Malformed " #a_Name "! off=%#x offRec=%#x cbRec=%#x cbNeeded=%#x line=%d\n", \
3878 off, offRec, cbRec, (a_cbReq), __LINE__)
3879#define OMF_READ_IDX(a_idx, a_Name) \
3880 do { \
3881 OMF_CHECK_RET(2, a_Name); \
3882 a_idx = pbRec[offRec++]; \
3883 if ((a_idx) & 0x80) \
3884 a_idx = (((a_idx) & 0x7f) << 8) | pbRec[offRec++]; \
3885 } while (0)
3886
3887 switch (bRecType)
3888 {
3889 /*
3890 * Record LNAME records, scanning for FLAT.
3891 */
3892 case OMF_LNAMES:
3893 while (offRec + 1 < cbRec)
3894 {
3895 uint8_t cch = pbRec[offRec];
3896 if (offRec + 1 + cch >= cbRec)
3897 return error(pszFile, "Invalid LNAME string length at %#x+3+%#x: %#x (cbFile=%#lx)\n",
3898 off, offRec, cch, (unsigned long)cbFile);
3899
3900 cLNames++;
3901 if (g_cVerbose > 2)
3902 printf(" LNAME[%u]: %-*.*s\n", cLNames, cch, cch, &pbRec[offRec + 1]);
3903
3904 if (cch == 4 && memcmp(&pbRec[offRec + 1], "FLAT", 4) == 0)
3905 pOmfStuff->fProbably32bit = true;
3906
3907 if ( cch == 6
3908 && pOmfStuff->iDebSymNm == UINT16_MAX
3909 && memcmp(&pbRec[offRec + 1], "DEBSYM", 6) == 0)
3910 pOmfStuff->iDebSymNm = cLNames;
3911 if ( cch == 9
3912 && pOmfStuff->iSymbolsNm == UINT16_MAX
3913 && memcmp(&pbRec[offRec + 1], "$$SYMBOLS", 9) == 0)
3914 pOmfStuff->iSymbolsNm = cLNames;
3915
3916 offRec += cch + 1;
3917 }
3918 break;
3919
3920 /*
3921 * Display external defitions if -v is specified, also check if anything needs mangling.
3922 */
3923 case OMF_EXTDEF:
3924 while (offRec + 1 < cbRec)
3925 {
3926 uint8_t cch = pbRec[offRec++];
3927 OMF_CHECK_RET(cch, EXTDEF);
3928 char *pchName = (char *)&pbRec[offRec];
3929 offRec += cch;
3930
3931 uint16_t idxType;
3932 OMF_READ_IDX(idxType, EXTDEF);
3933
3934 if (g_cVerbose > 2)
3935 printf(" EXTDEF [%u]: %-*.*s type=%#x\n", cExtDefs, cch, cch, pchName, idxType);
3936 else if (g_cVerbose > 0)
3937 printf(" U %-*.*s\n", cch, cch, pchName);
3938
3939 /* Look for g_apszExtDefRenames entries that requires changing. */
3940 if ( !pOmfStuff->fMayNeedMangling
3941 && cch >= 5
3942 && cch <= 7
3943 && pchName[0] == '_'
3944 && pchName[1] == '_'
3945 && ( pchName[2] == 'U'
3946 || pchName[2] == 'I'
3947 || pchName[2] == 'P')
3948 && ( pchName[3] == '4'
3949 || pchName[3] == '8'
3950 || pchName[3] == 'I'
3951 || pchName[3] == 'T') )
3952 {
3953 pOmfStuff->fMayNeedMangling = true;
3954 }
3955 }
3956 break;
3957
3958 /*
3959 * Display public names if -v is specified.
3960 */
3961 case OMF_PUBDEF32:
3962 case OMF_LPUBDEF32:
3963 pOmfStuff->fProbably32bit = true;
3964 case OMF_PUBDEF16:
3965 case OMF_LPUBDEF16:
3966 if (g_cVerbose > 0)
3967 {
3968 char const chType = bRecType == OMF_PUBDEF16 || bRecType == OMF_PUBDEF32 ? 'T' : 't';
3969 const char *pszRec = "LPUBDEF";
3970 if (chType == 'T')
3971 pszRec++;
3972
3973 uint16_t idxGrp;
3974 OMF_READ_IDX(idxGrp, [L]PUBDEF);
3975
3976 uint16_t idxSeg;
3977 OMF_READ_IDX(idxSeg, [L]PUBDEF);
3978
3979 uint16_t uFrameBase = 0;
3980 if (idxSeg == 0)
3981 {
3982 OMF_CHECK_RET(2, [L]PUBDEF);
3983 uFrameBase = RT_MAKE_U16(pbRec[offRec], pbRec[offRec + 1]);
3984 offRec += 2;
3985 }
3986 if (g_cVerbose > 2)
3987 printf(" %s: idxGrp=%#x idxSeg=%#x uFrameBase=%#x\n", pszRec, idxGrp, idxSeg, uFrameBase);
3988 uint16_t const uSeg = idxSeg ? idxSeg : uFrameBase;
3989
3990 while (offRec + 1 < cbRec)
3991 {
3992 uint8_t cch = pbRec[offRec++];
3993 OMF_CHECK_RET(cch, [L]PUBDEF);
3994 const char *pchName = (const char *)&pbRec[offRec];
3995 offRec += cch;
3996
3997 uint32_t offSeg;
3998 if (bRecType & OMF_REC32)
3999 {
4000 OMF_CHECK_RET(4, [L]PUBDEF);
4001 offSeg = RT_MAKE_U32_FROM_U8(pbRec[offRec], pbRec[offRec + 1], pbRec[offRec + 2], pbRec[offRec + 3]);
4002 offRec += 4;
4003 }
4004 else
4005 {
4006 OMF_CHECK_RET(2, [L]PUBDEF);
4007 offSeg = RT_MAKE_U16(pbRec[offRec], pbRec[offRec + 1]);
4008 offRec += 2;
4009 }
4010
4011 uint16_t idxType;
4012 OMF_READ_IDX(idxType, [L]PUBDEF);
4013
4014 if (g_cVerbose > 2)
4015 printf(" %s[%u]: off=%#010x type=%#x %-*.*s\n", pszRec, cPubDefs, offSeg, idxType, cch, cch, pchName);
4016 else if (g_cVerbose > 0)
4017 printf("%04x:%08x %c %-*.*s\n", uSeg, offSeg, chType, cch, cch, pchName);
4018 }
4019 }
4020 break;
4021
4022 /*
4023 * Must count segment defitions to figure the index of our segment.
4024 */
4025 case OMF_SEGDEF16:
4026 case OMF_SEGDEF32:
4027 pOmfStuff->cSegDefs++;
4028 break;
4029
4030 /*
4031 * Gather file names.
4032 */
4033 case OMF_THEADR: /* watcom */
4034 cchSrcFile = pbRec[offRec++];
4035 OMF_CHECK_RET(cchSrcFile, OMF_THEADR);
4036 pchSrcFile = (const char *)&pbRec[offRec];
4037 if (!collectOmfAddFile(pOmfStuff, cchSrcFile, pchSrcFile, &offSrcInfo))
4038 return false;
4039 break;
4040
4041 case OMF_COMENT:
4042 {
4043 OMF_CHECK_RET(2, COMENT);
4044 offRec++; /* skip the type (flags) */
4045 uint8_t bClass = pbRec[offRec++];
4046 if (bClass == OMF_CCLS_BORLAND_SRC_FILE) /* nasm */
4047 {
4048 OMF_CHECK_RET(1+1+4, BORLAND_SRC_FILE);
4049 offRec++; /* skip unknown byte */
4050 cchSrcFile = pbRec[offRec++];
4051 OMF_CHECK_RET(cchSrcFile + 4, BORLAND_SRC_FILE);
4052 pchSrcFile = (const char *)&pbRec[offRec];
4053 offRec += cchSrcFile;
4054 if (offRec + 4 + 1 != cbRec)
4055 return error(pszFile, "BAD BORLAND_SRC_FILE record at %#x: %d bytes left\n",
4056 off, cbRec - offRec - 4 - 1);
4057 if (!collectOmfAddFile(pOmfStuff, cchSrcFile, pchSrcFile, &offSrcInfo))
4058 return false;
4059 break;
4060 }
4061 break;
4062 }
4063
4064 /*
4065 * Line number conversion.
4066 */
4067 case OMF_LINNUM16:
4068 case OMF_LINNUM32:
4069 {
4070 uint16_t idxGrp;
4071 OMF_READ_IDX(idxGrp, LINNUM);
4072 uint16_t idxSeg;
4073 OMF_READ_IDX(idxSeg, LINNUM);
4074
4075 uint16_t iLine;
4076 uint32_t off;
4077 if (bRecType == OMF_LINNUM16)
4078 while (offRec + 4 < cbRec)
4079 {
4080 iLine = RT_MAKE_U16(pbRec[offRec + 0], pbRec[offRec + 1]);
4081 off = RT_MAKE_U16(pbRec[offRec + 2], pbRec[offRec + 3]);
4082 if (!collectOmfAddLine(pOmfStuff, idxSeg, off, iLine, offSrcInfo))
4083 return false;
4084 offRec += 4;
4085 }
4086 else
4087 while (offRec + 6 < cbRec)
4088 {
4089 iLine = RT_MAKE_U16(pbRec[offRec + 0], pbRec[offRec + 1]);
4090 off = RT_MAKE_U32_FROM_U8(pbRec[offRec + 2], pbRec[offRec + 3], pbRec[offRec + 4], pbRec[offRec + 5]);
4091 if (!collectOmfAddLine(pOmfStuff, idxSeg, off, iLine, offSrcInfo))
4092 return false;
4093 offRec += 6;
4094 }
4095 if (offRec + 1 != cbRec)
4096 return error(pszFile, "BAD LINNUM record at %#x: %d bytes left\n", off, cbRec - offRec - 1);
4097 break;
4098 }
4099 }
4100
4101 /* advance */
4102 off += cbRec + 3;
4103 }
4104
4105 return true;
4106#undef OMF_READ_IDX
4107#undef OMF_CHECK_RET
4108}
4109
4110
4111/**
4112 * Writes the debug segment definitions (names too).
4113 *
4114 * @returns success indicator.
4115 * @param pThis The OMF writer.
4116 * @param pOmfStuff The OMF stuff with CV8 line number info.
4117 */
4118static bool convertOmfWriteDebugSegDefs(POMFWRITER pThis, POMFDETAILS pOmfStuff)
4119{
4120 if ( pOmfStuff->cSegLines == 0
4121 || pOmfStuff->iSymbolsSeg != UINT16_MAX)
4122 return true;
4123
4124 /*
4125 * Emit the LNAMES we need.
4126 */
4127#if 1
4128 if ( pOmfStuff->iSymbolsNm == UINT16_MAX
4129 || pOmfStuff->iDebSymNm == UINT16_MAX)
4130 {
4131 if ( !omfWriter_LNamesBegin(pThis, true /*fAddZeroEntry*/)
4132 || ( pOmfStuff->iSymbolsNm == UINT16_MAX
4133 && !omfWriter_LNamesAdd(pThis, "$$SYMBOLS", &pOmfStuff->iSymbolsNm))
4134 || ( pOmfStuff->iDebSymNm == UINT16_MAX
4135 && !omfWriter_LNamesAdd(pThis, "DEBSYM", &pOmfStuff->iDebSymNm))
4136 || !omfWriter_LNamesEnd(pThis) )
4137 return false;
4138 }
4139#else
4140 if ( !omfWriter_LNamesBegin(pThis, true /*fAddZeroEntry*/)
4141 || !omfWriter_LNamesAdd(pThis, "$$SYMBOLS2", &pOmfStuff->iSymbolsNm)
4142 || !omfWriter_LNamesAdd(pThis, "DEBSYM2", &pOmfStuff->iDebSymNm)
4143 || !omfWriter_LNamesEnd(pThis) )
4144 return false;
4145#endif
4146
4147 /*
4148 * Emit the segment defitions.
4149 */
4150 pOmfStuff->iSymbolsSeg = ++pOmfStuff->cSegDefs;
4151
4152 uint8_t bSegAttr = 0;
4153 bSegAttr |= 5 << 5; /* A: dword alignment */
4154 bSegAttr |= 0 << 2; /* C: private */
4155 bSegAttr |= 0 << 1; /* B: not big */
4156 bSegAttr |= 1; /* D: use32 */
4157
4158 /* calc the segment size. */
4159 uint32_t cbSeg = 4; /* dword 4 */
4160 cbSeg += 4 + 4 + RT_ALIGN_32(pOmfStuff->cbStrTab, 4);
4161 cbSeg += 4 + 4 + pOmfStuff->cSrcInfo * sizeof(pOmfStuff->paSrcInfo[0]);
4162 uint32_t i = pOmfStuff->cSegLines;
4163 while (i-- > 0)
4164 if (pOmfStuff->paSegLines[i].cFiles > 0)
4165 cbSeg += 4 + 4 + pOmfStuff->paSegLines[i].cb;
4166 return omfWriter_SegDef(pThis, bSegAttr, cbSeg, pOmfStuff->iSymbolsNm, pOmfStuff->iDebSymNm);
4167}
4168
4169
4170/**
4171 * Writes the debug segment data.
4172 *
4173 * @returns success indicator.
4174 * @param pThis The OMF writer.
4175 * @param pOmfStuff The OMF stuff with CV8 line number info.
4176 */
4177static bool convertOmfWriteDebugData(POMFWRITER pThis, POMFDETAILS pOmfStuff)
4178{
4179 if (pOmfStuff->cSegLines == 0)
4180 return true;
4181
4182 /* Begin and write the CV version signature. */
4183 uint32_t const cbMaxChunk = RT_ALIGN(OMF_MAX_RECORD_PAYLOAD - 1 - 16, 4); /* keep the data dword aligned */
4184 if ( !omfWriter_LEDataBegin(pThis, pOmfStuff->iSymbolsSeg, 0)
4185 || !omfWriter_LEDataAddU32(pThis, RTCVSYMBOLS_SIGNATURE_CV8))
4186 return false;
4187
4188 /*
4189 * Emit the string table (no fixups).
4190 */
4191 uint32_t cbLeft = pOmfStuff->cbStrTab;
4192 if ( !omfWriter_LEDataAddU32(pThis, RTCV8SYMBLOCK_TYPE_SRC_STR)
4193 || !omfWriter_LEDataAddU32(pThis, cbLeft)
4194 || !omfWriter_LEDataAddBytes(pThis, pOmfStuff->pchStrTab, RT_ALIGN_32(cbLeft, 4)) ) /* table is zero padded to nearest dword */
4195 return false;
4196
4197 /*
4198 * Emit the source file info table (no fixups).
4199 */
4200 cbLeft = pOmfStuff->cSrcInfo * sizeof(pOmfStuff->paSrcInfo[0]);
4201 if ( !omfWriter_LEDataAddU32(pThis, RTCV8SYMBLOCK_TYPE_SRC_INFO)
4202 || !omfWriter_LEDataAddU32(pThis, cbLeft)
4203 || !omfWriter_LEDataAddBytes(pThis, pOmfStuff->paSrcInfo, cbLeft) )
4204 return false;
4205
4206 /*
4207 * Emit the segment line numbers. There are two fixups here at the start
4208 * of each chunk.
4209 */
4210 POMFSEGLINES pSegLines = pOmfStuff->paSegLines;
4211 uint32_t i = pOmfStuff->cSegLines;
4212 while (i-- > 0)
4213 {
4214 if (pSegLines->cFiles)
4215 {
4216 /* Calc covered area. */
4217 uint32_t cbSectionCovered = 0;
4218 uint32_t j = pSegLines->cFiles;
4219 while (j-- > 0)
4220 {
4221 uint32_t offLast = pSegLines->paFiles[j].paPairs[pSegLines->paFiles[j].cPairs - 1].offSection;
4222 if (offLast > cbSectionCovered)
4223 offLast = cbSectionCovered;
4224 }
4225
4226 /* For simplicity and debuggability, just split the LEDATA here. */
4227 if ( !omfWriter_LEDataSplit(pThis)
4228 || !omfWriter_LEDataAddU32(pThis, RTCV8SYMBLOCK_TYPE_SECT_LINES)
4229 || !omfWriter_LEDataAddU32(pThis, pSegLines->cb)
4230 || !omfWriter_LEDataAddU32(pThis, 0) /*RTCV8LINESHDR::offSection*/
4231 || !omfWriter_LEDataAddU16(pThis, 0) /*RTCV8LINESHDR::iSection*/
4232 || !omfWriter_LEDataAddU16(pThis, 0) /*RTCV8LINESHDR::u16Padding*/
4233 || !omfWriter_LEDataAddU32(pThis, cbSectionCovered) /*RTCV8LINESHDR::cbSectionCovered*/ )
4234 return false;
4235
4236 /* Fixup #1: segment offset - IMAGE_REL_AMD64_SECREL. */
4237 if (!omfWriter_LEDataAddFixupNoDisp(pThis, 4 + 4 + RT_OFFSETOF(RTCV8LINESHDR, offSection), OMF_FIX_LOC_32BIT_OFFSET,
4238 OMF_FIX_F_SEGDEF, pSegLines->idxSeg,
4239 OMF_FIX_T_SEGDEF_NO_DISP, pSegLines->idxSeg))
4240 return false;
4241
4242
4243 /* Fixup #2: segment number - IMAGE_REL_AMD64_SECTION. */
4244 if (!omfWriter_LEDataAddFixupNoDisp(pThis, 4 + 4 + RT_OFFSETOF(RTCV8LINESHDR, iSection), OMF_FIX_LOC_16BIT_SEGMENT,
4245 OMF_FIX_F_SEGDEF, pSegLines->idxSeg,
4246 OMF_FIX_T_SEGDEF_NO_DISP, pSegLines->idxSeg))
4247 return false;
4248
4249 /* Emit data for each source file. */
4250 for (uint32_t j = 0; j < pSegLines->cFiles; j++)
4251 {
4252 uint32_t const cbPairs = pSegLines->paFiles[j].cPairs * sizeof(RTCV8LINEPAIR);
4253 if ( !omfWriter_LEDataAddU32(pThis, pSegLines->paFiles[j].offSrcInfo) /*RTCV8LINESSRCMAP::offSourceInfo*/
4254 || !omfWriter_LEDataAddU32(pThis, pSegLines->paFiles[j].cPairs) /*RTCV8LINESSRCMAP::cLines*/
4255 || !omfWriter_LEDataAddU32(pThis, cbPairs + sizeof(RTCV8LINESSRCMAP)) /*RTCV8LINESSRCMAP::cb*/
4256 || !omfWriter_LEDataAddBytes(pThis, pSegLines->paFiles[j].paPairs, cbPairs))
4257 return false;
4258 }
4259 }
4260 pSegLines++;
4261 }
4262
4263 return omfWriter_LEDataEnd(pThis);
4264}
4265
4266
4267/**
4268 * This does the actual converting, passthru style.
4269 *
4270 * It only modifies, removes and inserts stuff it care about, the rest is passed
4271 * thru as-is.
4272 *
4273 * @returns success indicator.
4274 * @param pThis The OMF writer.
4275 * @param pbFile The original file content.
4276 * @param cbFile The size of the original file.
4277 * @param pOmfStuff The OMF stuff we've gathered during the first pass,
4278 * contains CV8 line number info if we converted anything.
4279 */
4280static bool convertOmfPassthru(POMFWRITER pThis, uint8_t const *pbFile, size_t cbFile, POMFDETAILS pOmfStuff)
4281{
4282 bool const fConvertLineNumbers = true;
4283 bool fSeenTheAdr = false;
4284 uint32_t off = 0;
4285 while (off + 3 < cbFile)
4286 {
4287 uint8_t bRecType = pbFile[off];
4288 uint16_t cbRec = RT_MAKE_U16(pbFile[off + 1], pbFile[off + 2]);
4289 uint32_t offRec = 0;
4290 uint8_t const *pbRec = &pbFile[off + 3];
4291
4292#define OMF_READ_IDX(a_idx, a_Name) \
4293 do { \
4294 a_idx = pbRec[offRec++]; \
4295 if ((a_idx) & 0x80) \
4296 a_idx = (((a_idx) & 0x7f) << 8) | pbRec[offRec++]; \
4297 } while (0)
4298
4299 /*
4300 * Remove/insert switch. will
4301 */
4302 bool fSkip = false;
4303 switch (bRecType)
4304 {
4305 /*
4306 * Mangle watcom intrinsics if necessary.
4307 */
4308 case OMF_EXTDEF:
4309 if (pOmfStuff->fMayNeedMangling)
4310 {
4311 if (!omfWriter_ExtDefBegin(pThis))
4312 return false;
4313 while (offRec + 1 < cbRec)
4314 {
4315 uint8_t cchName = pbRec[offRec++];
4316 char *pchName = (char *)&pbRec[offRec];
4317 offRec += cchName;
4318
4319 uint16_t idxType;
4320 OMF_READ_IDX(idxType, EXTDEF);
4321
4322 /* Look for g_apszExtDefRenames entries that requires changing. */
4323 if ( cchName >= 5
4324 && cchName <= 7
4325 && pchName[0] == '_'
4326 && pchName[1] == '_'
4327 && ( pchName[2] == 'U'
4328 || pchName[2] == 'I'
4329 || pchName[2] == 'P')
4330 && ( pchName[3] == '4'
4331 || pchName[3] == '8'
4332 || pchName[3] == 'I'
4333 || pchName[3] == 'T') )
4334 {
4335 char szName[12];
4336 memcpy(szName, pchName, cchName);
4337 szName[cchName] = '\0';
4338
4339 uint32_t i = RT_ELEMENTS(g_apszExtDefRenames);
4340 while (i-- > 0)
4341 if ( cchName == (uint8_t)g_apszExtDefRenames[i][0]
4342 && memcmp(&g_apszExtDefRenames[i][1], szName, cchName) == 0)
4343 {
4344 szName[0] = pOmfStuff->fProbably32bit ? '?' : '_';
4345 szName[1] = '?';
4346 break;
4347 }
4348
4349 if (!omfWriter_ExtDefAddN(pThis, szName, cchName, idxType))
4350 return false;
4351 }
4352 else if (!omfWriter_ExtDefAddN(pThis, pchName, cchName, idxType))
4353 return false;
4354 }
4355 if (!omfWriter_ExtDefEnd(pThis))
4356 return false;
4357 fSkip = true;
4358 }
4359 break;
4360
4361 /*
4362 * Remove line number records.
4363 */
4364 case OMF_LINNUM16:
4365 case OMF_LINNUM32:
4366 fSkip = fConvertLineNumbers;
4367 break;
4368
4369 /*
4370 * Remove all but the first OMF_THEADR.
4371 */
4372 case OMF_THEADR:
4373 fSkip = fSeenTheAdr && fConvertLineNumbers;
4374 fSeenTheAdr = true;
4375 break;
4376
4377 /*
4378 * Remove borland source file changes. Also, emit our SEGDEF
4379 * before the pass marker.
4380 */
4381 case OMF_COMENT:
4382 if (fConvertLineNumbers)
4383 {
4384 fSkip = pbRec[1] == OMF_CCLS_BORLAND_SRC_FILE;
4385 if (pbRec[1] == OMF_CCLS_LINK_PASS_SEP)
4386 if (!convertOmfWriteDebugSegDefs(pThis, pOmfStuff))
4387 return false;
4388 }
4389 break;
4390
4391 /*
4392 * Redo these to the OMF writer is on top of the index thing.
4393 */
4394 case OMF_LNAMES:
4395 if (!omfWriter_LNamesBegin(pThis, false /*fAddZeroEntry*/))
4396 return false;
4397 while (offRec + 1 < cbRec)
4398 {
4399 uint8_t cch = pbRec[offRec];
4400 const char *pch = (const char *)&pbRec[offRec + 1];
4401 if (!omfWriter_LNamesAddN(pThis, pch, cch, NULL))
4402 return false;
4403 offRec += cch + 1;
4404 }
4405 if (!omfWriter_LNamesEnd(pThis))
4406 return false;
4407
4408 fSkip = true;
4409 break;
4410
4411 /*
4412 * Upon seeing MODEND we write out the debug info.
4413 */
4414 case OMF_MODEND16:
4415 case OMF_MODEND32:
4416 if (fConvertLineNumbers)
4417 {
4418 if ( convertOmfWriteDebugSegDefs(pThis, pOmfStuff)
4419 && convertOmfWriteDebugData(pThis, pOmfStuff))
4420 { /* likely */ }
4421 else return false;
4422 }
4423 break;
4424 }
4425
4426 /*
4427 * Pass the record thru, if so was decided.
4428 */
4429 if (!fSkip)
4430 {
4431 if ( omfWriter_RecBegin(pThis, bRecType)
4432 && omfWriter_RecAddBytes(pThis, pbRec, cbRec)
4433 && omfWriter_RecEnd(pThis, false))
4434 { /* likely */ }
4435 else return false;
4436 }
4437
4438 /* advance */
4439 off += cbRec + 3;
4440 }
4441
4442 return true;
4443}
4444
4445
4446/**
4447 * Converts LINNUMs and compiler intrinsics in an OMF object file.
4448 *
4449 * Wlink does a cheesy (to use their own term) job of generating the
4450 * sstSrcModule subsection. It is limited to one file and cannot deal with line
4451 * numbers in different segment. The latter is very annoying in assembly files
4452 * that jumps between segments, these a frequent on crash stacks.
4453 *
4454 * The solution is to convert to the same line number tables that cl.exe /Z7
4455 * generates for our 64-bit C code, we named that format codeview v8, or CV8.
4456 * Our code codeview debug info reader can deal with this already because of the
4457 * 64-bit code, so Bob's your uncle.
4458 *
4459 * @returns success indicator.
4460 * @param pszFile The name of the file being converted.
4461 * @param pbFile The file content.
4462 * @param cbFile The size of the file content.
4463 * @param pDst The destiation (output) file.
4464 */
4465static bool convertOmfToOmf(const char *pszFile, uint8_t const *pbFile, size_t cbFile, FILE *pDst)
4466{
4467 /*
4468 * Collect line number information.
4469 */
4470 OMFDETAILS OmfStuff;
4471 if (!collectOmfDetails(pszFile, pbFile, cbFile, &OmfStuff))
4472 return false;
4473
4474 /*
4475 * Instantiate the OMF writer and do pass-thru modifications.
4476 */
4477 bool fRc;
4478 POMFWRITER pThis = omfWriter_Create(pszFile, 0, 0, pDst);
4479 if (pThis)
4480 {
4481 fRc = convertOmfPassthru(pThis, pbFile, cbFile, &OmfStuff);
4482 omfWriter_Destroy(pThis);
4483 }
4484 else
4485 fRc = false;
4486
4487
4488 /*
4489 * Cleanup OmfStuff.
4490 */
4491 uint32_t i = OmfStuff.cSegLines;
4492 while (i-- >0)
4493 {
4494 uint32_t j = OmfStuff.paSegLines[i].cFiles;
4495 while (j-- > 0)
4496 free(OmfStuff.paSegLines[i].paFiles[j].paPairs);
4497 free(OmfStuff.paSegLines[i].paFiles);
4498 }
4499 free(OmfStuff.paSegLines);
4500 free(OmfStuff.paSrcInfo);
4501 free(OmfStuff.pchStrTab);
4502 return fRc;
4503}
4504
4505
4506/**
4507 * Does the convertion using convertelf and convertcoff.
4508 *
4509 * @returns exit code (0 on success, non-zero on failure)
4510 * @param pszFile The file to convert.
4511 */
4512static int convertit(const char *pszFile)
4513{
4514 /* Construct the filename for saving the unmodified file. */
4515 char szOrgFile[_4K];
4516 size_t cchFile = strlen(pszFile);
4517 if (cchFile + sizeof(".original") > sizeof(szOrgFile))
4518 {
4519 error(pszFile, "Filename too long!\n");
4520 return RTEXITCODE_FAILURE;
4521 }
4522 memcpy(szOrgFile, pszFile, cchFile);
4523 memcpy(&szOrgFile[cchFile], ".original", sizeof(".original"));
4524
4525 /* Read the whole file. */
4526 void *pvFile;
4527 size_t cbFile;
4528 if (readfile(pszFile, &pvFile, &cbFile))
4529 {
4530 /*
4531 * Do format conversions / adjustments.
4532 */
4533 bool fRc = false;
4534 uint8_t *pbFile = (uint8_t *)pvFile;
4535 if ( cbFile > sizeof(Elf64_Ehdr)
4536 && pbFile[0] == ELFMAG0
4537 && pbFile[1] == ELFMAG1
4538 && pbFile[2] == ELFMAG2
4539 && pbFile[3] == ELFMAG3)
4540 {
4541 if (writefile(szOrgFile, pvFile, cbFile))
4542 {
4543 FILE *pDst = openfile(pszFile, true /*fWrite*/);
4544 if (pDst)
4545 {
4546 fRc = convertElfToOmf(pszFile, pbFile, cbFile, pDst);
4547 fRc = fclose(pDst) == 0 && fRc;
4548 }
4549 }
4550 }
4551 else if ( cbFile > sizeof(IMAGE_FILE_HEADER)
4552 && RT_MAKE_U16(pbFile[0], pbFile[1]) == IMAGE_FILE_MACHINE_AMD64
4553 && RT_MAKE_U16(pbFile[2], pbFile[3]) * sizeof(IMAGE_SECTION_HEADER) + sizeof(IMAGE_FILE_HEADER)
4554 < cbFile
4555 && RT_MAKE_U16(pbFile[2], pbFile[3]) > 0)
4556 {
4557 if (writefile(szOrgFile, pvFile, cbFile))
4558 {
4559 FILE *pDst = openfile(pszFile, true /*fWrite*/);
4560 if (pDst)
4561 {
4562 fRc = convertCoffToOmf(pszFile, pbFile, cbFile, pDst);
4563 fRc = fclose(pDst) == 0 && fRc;
4564 }
4565 }
4566 }
4567 else if ( cbFile >= 8
4568 && pbFile[0] == OMF_THEADR
4569 && RT_MAKE_U16(pbFile[1], pbFile[2]) < cbFile)
4570 {
4571 if (writefile(szOrgFile, pvFile, cbFile))
4572 {
4573 FILE *pDst = openfile(pszFile, true /*fWrite*/);
4574 if (pDst)
4575 {
4576 fRc = convertOmfToOmf(pszFile, pbFile, cbFile, pDst);
4577 fRc = fclose(pDst) == 0 && fRc;
4578 }
4579 }
4580 }
4581 else
4582 fprintf(stderr, "error: Don't recognize format of '%s' (%#x %#x %#x %#x, cbFile=%lu)\n",
4583 pszFile, pbFile[0], pbFile[1], pbFile[2], pbFile[3], (unsigned long)cbFile);
4584 free(pvFile);
4585 if (fRc)
4586 return 0;
4587 }
4588 return 1;
4589}
4590
4591
4592int main(int argc, char **argv)
4593{
4594 int rcExit = 0;
4595
4596 /*
4597 * Scan the arguments.
4598 */
4599 for (int i = 1; i < argc; i++)
4600 {
4601 if (argv[i][0] == '-')
4602 {
4603 const char *pszOpt = &argv[i][1];
4604 if (*pszOpt == '-')
4605 {
4606 /* Convert long options to short ones. */
4607 pszOpt--;
4608 if (!strcmp(pszOpt, "--verbose"))
4609 pszOpt = "v";
4610 else if (!strcmp(pszOpt, "--version"))
4611 pszOpt = "V";
4612 else if (!strcmp(pszOpt, "--help"))
4613 pszOpt = "h";
4614 else
4615 {
4616 fprintf(stderr, "syntax errro: Unknown options '%s'\n", pszOpt);
4617 return 2;
4618 }
4619 }
4620
4621 /* Process the list of short options. */
4622 while (*pszOpt)
4623 {
4624 switch (*pszOpt++)
4625 {
4626 case 'v':
4627 g_cVerbose++;
4628 break;
4629
4630 case 'V':
4631 printf("%s\n", "$Revision: 60265 $");
4632 return 0;
4633
4634 case '?':
4635 case 'h':
4636 printf("usage: %s [options] -o <output> <input1> [input2 ... [inputN]]\n",
4637 argv[0]);
4638 return 0;
4639 }
4640 }
4641 }
4642 else
4643 {
4644 /*
4645 * File to convert. Do the job right away.
4646 */
4647 rcExit = convertit(argv[i]);
4648 if (rcExit != 0)
4649 break;
4650 }
4651 }
4652
4653 return rcExit;
4654}
4655
4656
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