VirtualBox

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

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

Horseradish. Nasm emitting incorrect addend for wrt RIP stuff. VBoxBs3ObjConverter.cpp

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 179.7 KB
Line 
1/* $Id: VBoxBs3ObjConverter.cpp 60462 2016-04-12 16:17:20Z 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 if (fSelfRel)
1731 *uLoc.pu32 = iAddend + 4;
1732 else
1733 *uLoc.pu32 = iAddend;
1734 break;
1735 }
1736
1737 case R_X86_64_NONE:
1738 continue; /* Ignore this one */
1739
1740 case R_X86_64_GOT32:
1741 case R_X86_64_PLT32:
1742 case R_X86_64_COPY:
1743 case R_X86_64_GLOB_DAT:
1744 case R_X86_64_JMP_SLOT:
1745 case R_X86_64_RELATIVE:
1746 case R_X86_64_GOTPCREL:
1747 case R_X86_64_16:
1748 case R_X86_64_PC16:
1749 case R_X86_64_8:
1750 case R_X86_64_PC8:
1751 case R_X86_64_DTPMOD64:
1752 case R_X86_64_DTPOFF64:
1753 case R_X86_64_TPOFF64:
1754 case R_X86_64_TLSGD:
1755 case R_X86_64_TLSLD:
1756 case R_X86_64_DTPOFF32:
1757 case R_X86_64_GOTTPOFF:
1758 case R_X86_64_TPOFF32:
1759 default:
1760 return error(pThis->pszSrc, "Unsupported fixup type %#x (%s) at rva=%#x in section #%u '%s' against '%s'\n",
1761 uType, g_apszElfAmd64RelTypes[uType], paRelocs[iReloc].r_offset, i, pszSegNm, pszSymName);
1762 }
1763
1764 /* Add the fixup. */
1765 if (idxFrame == UINT16_MAX)
1766 error(pThis->pszSrc, "idxFrame=UINT16_MAX for %s type=%s\n", pszSymName, g_apszElfAmd64RelTypes[uType]);
1767 fRet = omfWriter_LEDataAddFixup(pThis, offDataRec, fSelfRel, bLocation, bFrame, idxFrame,
1768 bTarget, idxTarget, fTargetDisp, offTargetDisp) && fRet;
1769 }
1770
1771 /*
1772 * Write the LEDATA and associated FIXUPPs.
1773 */
1774 if (!omfWriter_LEDataEnd(pThis))
1775 return false;
1776
1777 /*
1778 * Advance.
1779 */
1780 paRelocs += cChunkRelocs;
1781 cRelocs -= cChunkRelocs;
1782 if (cbData > cbChunk)
1783 {
1784 cbData -= cbChunk;
1785 pbData += cbChunk;
1786 }
1787 else
1788 cbData = 0;
1789 off += cbChunk;
1790 cbVirtData -= cbChunk;
1791 }
1792 }
1793
1794 return fRet;
1795}
1796
1797
1798static bool convertElfToOmf(const char *pszFile, uint8_t const *pbFile, size_t cbFile, FILE *pDst)
1799{
1800 /*
1801 * Validate the source file a little.
1802 */
1803 ELFDETAILS ElfStuff;
1804 if (!validateElf(pszFile, pbFile, cbFile, &ElfStuff))
1805 return false;
1806
1807 /*
1808 * Instantiate the OMF writer.
1809 */
1810 POMFWRITER pThis = omfWriter_Create(pszFile, ElfStuff.pEhdr->e_shnum, ElfStuff.cSymbols, pDst);
1811 if (!pThis)
1812 return false;
1813
1814 /*
1815 * Write the OMF object file.
1816 */
1817 if (omfWriter_BeginModule(pThis, pszFile))
1818 {
1819 Elf64_Ehdr const *pEhdr = (Elf64_Ehdr const *)pbFile;
1820 Elf64_Shdr const *paShdrs = (Elf64_Shdr const *)&pbFile[pEhdr->e_shoff];
1821 const char *pszStrTab = (const char *)&pbFile[paShdrs[pEhdr->e_shstrndx].sh_offset];
1822
1823 if ( convertElfSectionsToSegDefsAndGrpDefs(pThis, &ElfStuff)
1824 && convertElfSymbolsToPubDefsAndExtDefs(pThis, &ElfStuff)
1825 && omfWriter_LinkPassSeparator(pThis)
1826 && convertElfSectionsToLeDataAndFixupps(pThis, &ElfStuff, pbFile, cbFile)
1827 && omfWriter_EndModule(pThis) )
1828 {
1829
1830 omfWriter_Destroy(pThis);
1831 return true;
1832 }
1833 }
1834
1835 omfWriter_Destroy(pThis);
1836 return false;
1837}
1838
1839
1840
1841/*********************************************************************************************************************************
1842* COFF -> OMF Converter *
1843*********************************************************************************************************************************/
1844
1845/** AMD64 relocation type names for (Microsoft) COFF. */
1846static const char * const g_apszCoffAmd64RelTypes[] =
1847{
1848 "ABSOLUTE",
1849 "ADDR64",
1850 "ADDR32",
1851 "ADDR32NB",
1852 "REL32",
1853 "REL32_1",
1854 "REL32_2",
1855 "REL32_3",
1856 "REL32_4",
1857 "REL32_5",
1858 "SECTION",
1859 "SECREL",
1860 "SECREL7",
1861 "TOKEN",
1862 "SREL32",
1863 "PAIR",
1864 "SSPAN32"
1865};
1866
1867/** AMD64 relocation type sizes for (Microsoft) COFF. */
1868static uint8_t const g_acbCoffAmd64RelTypes[] =
1869{
1870 8, /* ABSOLUTE */
1871 8, /* ADDR64 */
1872 4, /* ADDR32 */
1873 4, /* ADDR32NB */
1874 4, /* REL32 */
1875 4, /* REL32_1 */
1876 4, /* REL32_2 */
1877 4, /* REL32_3 */
1878 4, /* REL32_4 */
1879 4, /* REL32_5 */
1880 2, /* SECTION */
1881 4, /* SECREL */
1882 1, /* SECREL7 */
1883 0, /* TOKEN */
1884 4, /* SREL32 */
1885 0, /* PAIR */
1886 4, /* SSPAN32 */
1887};
1888
1889/** Macro for getting the size of a AMD64 COFF relocation. */
1890#define COFF_AMD64_RELOC_SIZE(a_Type) ( (a_Type) < RT_ELEMENTS(g_acbCoffAmd64RelTypes) ? g_acbCoffAmd64RelTypes[(a_Type)] : 1)
1891
1892
1893static const char *coffGetSymbolName(PCIMAGE_SYMBOL pSym, const char *pchStrTab, uint32_t cbStrTab, char pszShortName[16])
1894{
1895 if (pSym->N.Name.Short != 0)
1896 {
1897 memcpy(pszShortName, pSym->N.ShortName, 8);
1898 pszShortName[8] = '\0';
1899 return pszShortName;
1900 }
1901 if (pSym->N.Name.Long < cbStrTab)
1902 {
1903 uint32_t const cbLeft = cbStrTab - pSym->N.Name.Long;
1904 const char *pszRet = pchStrTab + pSym->N.Name.Long;
1905 if (memchr(pszRet, '\0', cbLeft) != NULL)
1906 return pszRet;
1907 }
1908 error("<null>", "Invalid string table index %#x!\n", pSym->N.Name.Long);
1909 return "Invalid Symbol Table Entry";
1910}
1911
1912static bool validateCoff(const char *pszFile, uint8_t const *pbFile, size_t cbFile)
1913{
1914 /*
1915 * Validate the header and our other expectations.
1916 */
1917 PIMAGE_FILE_HEADER pHdr = (PIMAGE_FILE_HEADER)pbFile;
1918 if (pHdr->Machine != IMAGE_FILE_MACHINE_AMD64)
1919 return error(pszFile, "Expected IMAGE_FILE_MACHINE_AMD64 not %#x\n", pHdr->Machine);
1920 if (pHdr->SizeOfOptionalHeader != 0)
1921 return error(pszFile, "Expected SizeOfOptionalHeader to be zero, not %#x\n", pHdr->SizeOfOptionalHeader);
1922 if (pHdr->NumberOfSections == 0)
1923 return error(pszFile, "Expected NumberOfSections to be non-zero\n");
1924 uint32_t const cbHeaders = pHdr->NumberOfSections * sizeof(IMAGE_SECTION_HEADER) + sizeof(*pHdr);
1925 if (cbHeaders > cbFile)
1926 return error(pszFile, "Section table goes beyond the end of the of the file (cSections=%#x)\n", pHdr->NumberOfSections);
1927 if (pHdr->NumberOfSymbols)
1928 {
1929 if ( pHdr->PointerToSymbolTable >= cbFile
1930 || pHdr->NumberOfSymbols * (uint64_t)IMAGE_SIZE_OF_SYMBOL > cbFile)
1931 return error(pszFile, "Symbol table goes beyond the end of the of the file (cSyms=%#x, offFile=%#x)\n",
1932 pHdr->NumberOfSymbols, pHdr->PointerToSymbolTable);
1933 }
1934
1935 return true;
1936}
1937
1938
1939static bool convertCoffSectionsToSegDefsAndGrpDefs(POMFWRITER pThis, PCIMAGE_SECTION_HEADER paShdrs, uint16_t cSections)
1940{
1941 /*
1942 * Do the list of names pass.
1943 */
1944 uint16_t idxGrpFlat, idxGrpData;
1945 uint16_t idxClassCode, idxClassData, idxClassDebugSymbols, idxClassDebugTypes;
1946 if ( !omfWriter_LNamesBegin(pThis, true /*fAddZeroEntry*/)
1947 || !omfWriter_LNamesAddN(pThis, RT_STR_TUPLE("FLAT"), &idxGrpFlat)
1948 || !omfWriter_LNamesAddN(pThis, RT_STR_TUPLE("BS3DATA64_GROUP"), &idxGrpData)
1949 || !omfWriter_LNamesAddN(pThis, RT_STR_TUPLE("BS3CLASS64CODE"), &idxClassCode)
1950 || !omfWriter_LNamesAddN(pThis, RT_STR_TUPLE("FAR_DATA"), &idxClassData)
1951 || !omfWriter_LNamesAddN(pThis, RT_STR_TUPLE("DEBSYM"), &idxClassDebugSymbols)
1952 || !omfWriter_LNamesAddN(pThis, RT_STR_TUPLE("DEBTYP"), &idxClassDebugTypes)
1953 )
1954 return false;
1955
1956 bool fHaveData = false;
1957 for (uint16_t i = 0; i < cSections; i++)
1958 {
1959 /* Copy the name and terminate it. */
1960 char szName[32];
1961 memcpy(szName, paShdrs[i].Name, sizeof(paShdrs[i].Name));
1962 unsigned cchName = sizeof(paShdrs[i].Name);
1963 while (cchName > 0 && RT_C_IS_SPACE(szName[cchName - 1]))
1964 cchName--;
1965 if (cchName == 0)
1966 return error(pThis->pszSrc, "Section #%u has an empty name!\n", i);
1967 szName[cchName] = '\0';
1968
1969 if ( (paShdrs[i].Characteristics & (IMAGE_SCN_LNK_REMOVE | IMAGE_SCN_LNK_INFO))
1970 || strcmp(szName, ".pdata") == 0 /* Exception stuff, I think, so discard it. */
1971 || strcmp(szName, ".xdata") == 0 /* Ditto. */ )
1972 {
1973 pThis->paSegments[i].iSegDef = UINT16_MAX;
1974 pThis->paSegments[i].iGrpDef = UINT16_MAX;
1975 pThis->paSegments[i].iSegNm = UINT16_MAX;
1976 pThis->paSegments[i].iGrpNm = UINT16_MAX;
1977 pThis->paSegments[i].iClassNm = UINT16_MAX;
1978 pThis->paSegments[i].pszName = NULL;
1979 }
1980 else
1981 {
1982 /* Translate the name, group and class. */
1983 if (strcmp(szName, ".text") == 0)
1984 {
1985 strcpy(szName, "BS3TEXT64");
1986 pThis->paSegments[i].iGrpNm = idxGrpFlat;
1987 pThis->paSegments[i].iClassNm = idxClassCode;
1988 }
1989 else if (strcmp(szName, ".data") == 0)
1990 {
1991 strcpy(szName, "BS3DATA64");
1992 pThis->paSegments[i].iGrpNm = idxGrpData;
1993 pThis->paSegments[i].iClassNm = idxClassData;
1994 }
1995 else if (strcmp(szName, ".bss") == 0)
1996 {
1997 strcpy(szName, "BS3BSS64");
1998 pThis->paSegments[i].iGrpNm = idxGrpData;
1999 pThis->paSegments[i].iClassNm = idxClassData;
2000 }
2001 else if (strcmp(szName, ".rdata") == 0)
2002 {
2003 strcpy(szName, "BS3DATA64CONST");
2004 pThis->paSegments[i].iGrpNm = idxGrpData;
2005 pThis->paSegments[i].iClassNm = idxClassData;
2006 }
2007 else if (strcmp(szName, ".debug$S") == 0)
2008 {
2009 strcpy(szName, "$$SYMBOLS");
2010 pThis->paSegments[i].iGrpNm = UINT16_MAX;
2011 pThis->paSegments[i].iClassNm = idxClassDebugSymbols;
2012 }
2013 else if (strcmp(szName, ".debug$T") == 0)
2014 {
2015 strcpy(szName, "$$TYPES");
2016 pThis->paSegments[i].iGrpNm = UINT16_MAX;
2017 pThis->paSegments[i].iClassNm = idxClassDebugTypes;
2018 }
2019 else if (paShdrs[i].Characteristics & (IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_CNT_CODE))
2020 {
2021 pThis->paSegments[i].iGrpNm = idxGrpFlat;
2022 pThis->paSegments[i].iClassNm = idxClassCode;
2023 error(pThis->pszSrc, "Unknown code segment: '%s'\n", szName);
2024 }
2025 else
2026 {
2027 pThis->paSegments[i].iGrpNm = idxGrpData;
2028 pThis->paSegments[i].iClassNm = idxClassData;
2029 error(pThis->pszSrc, "Unknown data (?) segment: '%s'\n", szName);
2030 }
2031
2032 /* Save the name. */
2033 pThis->paSegments[i].pszName = strdup(szName);
2034 if (!pThis->paSegments[i].pszName)
2035 return error(pThis->pszSrc, "Out of memory!\n");
2036
2037 /* Add the section name. */
2038 if (!omfWriter_LNamesAdd(pThis, pThis->paSegments[i].pszName, &pThis->paSegments[i].iSegNm))
2039 return false;
2040
2041 fHaveData |= pThis->paSegments[i].iGrpNm == idxGrpData;
2042 }
2043 }
2044
2045 if (!omfWriter_LNamesEnd(pThis))
2046 return false;
2047
2048 /*
2049 * Emit segment definitions.
2050 */
2051 uint16_t iSegDef = 1; /* Start counting at 1. */
2052 for (uint16_t i = 0; i < cSections; i++)
2053 {
2054 if (pThis->paSegments[i].iSegDef == UINT16_MAX)
2055 continue;
2056
2057 uint8_t bSegAttr = 0;
2058
2059 /* The A field. */
2060 switch (paShdrs[i].Characteristics & IMAGE_SCN_ALIGN_MASK)
2061 {
2062 default:
2063 case IMAGE_SCN_ALIGN_1BYTES:
2064 bSegAttr |= 1 << 5;
2065 break;
2066 case IMAGE_SCN_ALIGN_2BYTES:
2067 bSegAttr |= 2 << 5;
2068 break;
2069 case IMAGE_SCN_ALIGN_4BYTES:
2070 bSegAttr |= 5 << 5;
2071 break;
2072 case IMAGE_SCN_ALIGN_8BYTES:
2073 case IMAGE_SCN_ALIGN_16BYTES:
2074 bSegAttr |= 3 << 5;
2075 break;
2076 case IMAGE_SCN_ALIGN_32BYTES:
2077 case IMAGE_SCN_ALIGN_64BYTES:
2078 case IMAGE_SCN_ALIGN_128BYTES:
2079 case IMAGE_SCN_ALIGN_256BYTES:
2080 bSegAttr |= 4 << 5;
2081 break;
2082 case IMAGE_SCN_ALIGN_512BYTES:
2083 case IMAGE_SCN_ALIGN_1024BYTES:
2084 case IMAGE_SCN_ALIGN_2048BYTES:
2085 case IMAGE_SCN_ALIGN_4096BYTES:
2086 case IMAGE_SCN_ALIGN_8192BYTES:
2087 bSegAttr |= 6 << 5; /* page aligned, pharlabs extension. */
2088 break;
2089 }
2090
2091 /* The C field. */
2092 bSegAttr |= 2 << 2; /* public */
2093
2094 /* The B field. We don't have 4GB segments, so leave it as zero. */
2095
2096 /* The D field shall be set as we're doing USE32. */
2097 bSegAttr |= 1;
2098
2099
2100 /* Done. */
2101 if (!omfWriter_SegDef(pThis, bSegAttr, paShdrs[i].SizeOfRawData,
2102 pThis->paSegments[i].iSegNm,
2103 pThis->paSegments[i].iClassNm))
2104 return false;
2105 pThis->paSegments[i].iSegDef = iSegDef++;
2106 }
2107
2108 /*
2109 * Flat group definition (#1) - special, no members.
2110 */
2111 uint16_t iGrpDef = 1;
2112 if ( !omfWriter_GrpDefBegin(pThis, idxGrpFlat)
2113 || !omfWriter_GrpDefEnd(pThis))
2114 return false;
2115 for (uint16_t i = 0; i < cSections; i++)
2116 if (pThis->paSegments[i].iGrpNm == idxGrpFlat)
2117 pThis->paSegments[i].iGrpDef = iGrpDef;
2118 pThis->idxGrpFlat = iGrpDef++;
2119
2120 /*
2121 * Data group definition (#2).
2122 */
2123 /** @todo do we need to consider missing segments and ordering? */
2124 uint16_t cGrpNms = 0;
2125 uint16_t aiGrpNms[2];
2126 if (fHaveData)
2127 aiGrpNms[cGrpNms++] = idxGrpData;
2128 for (uint32_t iGrpNm = 0; iGrpNm < cGrpNms; iGrpNm++)
2129 {
2130 if (!omfWriter_GrpDefBegin(pThis, aiGrpNms[iGrpNm]))
2131 return false;
2132 for (uint16_t i = 0; i < cSections; i++)
2133 if (pThis->paSegments[i].iGrpNm == aiGrpNms[iGrpNm])
2134 {
2135 pThis->paSegments[i].iGrpDef = iGrpDef;
2136 if (!omfWriter_GrpDefAddSegDef(pThis, pThis->paSegments[i].iSegDef))
2137 return false;
2138 }
2139 if (!omfWriter_GrpDefEnd(pThis))
2140 return false;
2141 iGrpDef++;
2142 }
2143
2144 return true;
2145}
2146
2147/**
2148 * This is for matching STATIC symbols with value 0 against the section name,
2149 * to see if it's a section reference or symbol at offset 0 reference.
2150 *
2151 * @returns true / false.
2152 * @param pszSymbol The symbol name.
2153 * @param pachSectName8 The section name (8-bytes).
2154 */
2155static bool isCoffSymbolMatchingSectionName(const char *pszSymbol, uint8_t const pachSectName8[8])
2156{
2157 uint32_t off = 0;
2158 char ch;
2159 while (off < 8 && (ch = pszSymbol[off]) != '\0')
2160 {
2161 if (ch != pachSectName8[off])
2162 return false;
2163 off++;
2164 }
2165 while (off < 8)
2166 {
2167 if (!RT_C_IS_SPACE((ch = pachSectName8[off])))
2168 return ch == '\0';
2169 off++;
2170 }
2171 return true;
2172}
2173
2174static bool convertCoffSymbolsToPubDefsAndExtDefs(POMFWRITER pThis, PCIMAGE_SYMBOL paSymbols, uint16_t cSymbols,
2175 const char *pchStrTab, PCIMAGE_SECTION_HEADER paShdrs)
2176{
2177
2178 if (!cSymbols)
2179 return true;
2180 uint32_t const cbStrTab = *(uint32_t const *)pchStrTab;
2181 char szShort[16];
2182
2183 /*
2184 * Process the symbols the first.
2185 */
2186 uint32_t iSymImageBase = UINT32_MAX;
2187 uint32_t cAbsSyms = 0;
2188 uint32_t cExtSyms = 0;
2189 uint32_t cPubSyms = 0;
2190 for (uint32_t iSeg = 0; iSeg < pThis->cSegments; iSeg++)
2191 pThis->paSegments[iSeg].cPubDefs = 0;
2192
2193 for (uint16_t iSym = 0; iSym < cSymbols; iSym++)
2194 {
2195 const char *pszSymName = coffGetSymbolName(&paSymbols[iSym], pchStrTab, cbStrTab, szShort);
2196
2197 pThis->paSymbols[iSym].enmType = OMFSYMTYPE_IGNORED;
2198 pThis->paSymbols[iSym].idx = UINT16_MAX;
2199 pThis->paSymbols[iSym].idxSegDef = UINT16_MAX;
2200 pThis->paSymbols[iSym].idxGrpDef = UINT16_MAX;
2201
2202 int16_t const idxSection = paSymbols[iSym].SectionNumber;
2203 if ( (idxSection >= 1 && idxSection <= (int32_t)pThis->cSegments)
2204 || idxSection == IMAGE_SYM_ABSOLUTE)
2205 {
2206 switch (paSymbols[iSym].StorageClass)
2207 {
2208 case IMAGE_SYM_CLASS_EXTERNAL:
2209 if (idxSection != IMAGE_SYM_ABSOLUTE)
2210 {
2211 if (pThis->paSegments[idxSection - 1].iSegDef != UINT16_MAX)
2212 {
2213 pThis->paSymbols[iSym].enmType = OMFSYMTYPE_PUBDEF;
2214 pThis->paSymbols[iSym].idxSegDef = pThis->paSegments[idxSection - 1].iSegDef;
2215 pThis->paSymbols[iSym].idxGrpDef = pThis->paSegments[idxSection - 1].iGrpDef;
2216 pThis->paSegments[idxSection - 1].cPubDefs++;
2217 cPubSyms++;
2218 }
2219 }
2220 else
2221 {
2222 pThis->paSymbols[iSym].enmType = OMFSYMTYPE_PUBDEF;
2223 pThis->paSymbols[iSym].idxSegDef = 0;
2224 pThis->paSymbols[iSym].idxGrpDef = 0;
2225 cAbsSyms++;
2226 }
2227 break;
2228
2229 case IMAGE_SYM_CLASS_STATIC:
2230 if ( paSymbols[iSym].Value == 0
2231 && idxSection != IMAGE_SYM_ABSOLUTE
2232 && isCoffSymbolMatchingSectionName(pszSymName, paShdrs[idxSection - 1].Name) )
2233 {
2234 pThis->paSymbols[iSym].enmType = OMFSYMTYPE_SEGDEF;
2235 pThis->paSymbols[iSym].idxSegDef = pThis->paSegments[idxSection - 1].iSegDef;
2236 pThis->paSymbols[iSym].idxGrpDef = pThis->paSegments[idxSection - 1].iGrpDef;
2237 break;
2238 }
2239 /* fall thru */
2240
2241 case IMAGE_SYM_CLASS_END_OF_FUNCTION:
2242 case IMAGE_SYM_CLASS_AUTOMATIC:
2243 case IMAGE_SYM_CLASS_REGISTER:
2244 case IMAGE_SYM_CLASS_LABEL:
2245 case IMAGE_SYM_CLASS_MEMBER_OF_STRUCT:
2246 case IMAGE_SYM_CLASS_ARGUMENT:
2247 case IMAGE_SYM_CLASS_STRUCT_TAG:
2248 case IMAGE_SYM_CLASS_MEMBER_OF_UNION:
2249 case IMAGE_SYM_CLASS_UNION_TAG:
2250 case IMAGE_SYM_CLASS_TYPE_DEFINITION:
2251 case IMAGE_SYM_CLASS_ENUM_TAG:
2252 case IMAGE_SYM_CLASS_MEMBER_OF_ENUM:
2253 case IMAGE_SYM_CLASS_REGISTER_PARAM:
2254 case IMAGE_SYM_CLASS_BIT_FIELD:
2255 case IMAGE_SYM_CLASS_BLOCK:
2256 case IMAGE_SYM_CLASS_FUNCTION:
2257 case IMAGE_SYM_CLASS_END_OF_STRUCT:
2258 case IMAGE_SYM_CLASS_FILE:
2259 pThis->paSymbols[iSym].enmType = OMFSYMTYPE_INTERNAL;
2260 if (idxSection != IMAGE_SYM_ABSOLUTE)
2261 {
2262 pThis->paSymbols[iSym].idxSegDef = pThis->paSegments[idxSection - 1].iSegDef;
2263 pThis->paSymbols[iSym].idxGrpDef = pThis->paSegments[idxSection - 1].iGrpDef;
2264 }
2265 else
2266 {
2267 pThis->paSymbols[iSym].idxSegDef = 0;
2268 pThis->paSymbols[iSym].idxGrpDef = 0;
2269 }
2270 break;
2271
2272 case IMAGE_SYM_CLASS_SECTION:
2273 case IMAGE_SYM_CLASS_EXTERNAL_DEF:
2274 case IMAGE_SYM_CLASS_NULL:
2275 case IMAGE_SYM_CLASS_UNDEFINED_LABEL:
2276 case IMAGE_SYM_CLASS_UNDEFINED_STATIC:
2277 case IMAGE_SYM_CLASS_CLR_TOKEN:
2278 case IMAGE_SYM_CLASS_FAR_EXTERNAL:
2279 case IMAGE_SYM_CLASS_WEAK_EXTERNAL:
2280 return error(pThis->pszSrc, "Unsupported storage class value %#x for symbol #%u (%s)\n",
2281 paSymbols[iSym].StorageClass, iSym, pszSymName);
2282
2283 default:
2284 return error(pThis->pszSrc, "Unknown storage class value %#x for symbol #%u (%s)\n",
2285 paSymbols[iSym].StorageClass, iSym, pszSymName);
2286 }
2287 }
2288 else if (idxSection == IMAGE_SYM_UNDEFINED)
2289 {
2290 if ( paSymbols[iSym].StorageClass == IMAGE_SYM_CLASS_EXTERNAL
2291 || paSymbols[iSym].StorageClass == IMAGE_SYM_CLASS_EXTERNAL_DEF)
2292 {
2293 pThis->paSymbols[iSym].enmType = OMFSYMTYPE_EXTDEF;
2294 cExtSyms++;
2295 if (iSymImageBase == UINT32_MAX && strcmp(pszSymName, "__ImageBase") == 0)
2296 iSymImageBase = iSym;
2297 }
2298 else
2299 return error(pThis->pszSrc, "Unknown/unknown storage class value %#x for undefined symbol #%u (%s)\n",
2300 paSymbols[iSym].StorageClass, iSym, pszSymName);
2301 }
2302 else if (idxSection != IMAGE_SYM_DEBUG)
2303 return error(pThis->pszSrc, "Invalid section number %#x for symbol #%u (%s)\n", idxSection, iSym, pszSymName);
2304
2305 /* Skip AUX symbols. */
2306 uint8_t cAuxSyms = paSymbols[iSym].NumberOfAuxSymbols;
2307 while (cAuxSyms-- > 0)
2308 {
2309 iSym++;
2310 pThis->paSymbols[iSym].enmType = OMFSYMTYPE_INVALID;
2311 pThis->paSymbols[iSym].idx = UINT16_MAX;
2312 }
2313 }
2314
2315 /*
2316 * Emit the PUBDEFs the first time around (see order of records in TIS spec).
2317 */
2318 uint16_t idxPubDef = 1;
2319 if (cPubSyms)
2320 {
2321 for (uint32_t iSeg = 0; iSeg < pThis->cSegments; iSeg++)
2322 if (pThis->paSegments[iSeg].cPubDefs > 0)
2323 {
2324 uint16_t const idxSegDef = pThis->paSegments[iSeg].iSegDef;
2325 if (!omfWriter_PubDefBegin(pThis, pThis->paSegments[iSeg].iGrpDef, idxSegDef))
2326 return false;
2327 for (uint16_t iSym = 0; iSym < cSymbols; iSym++)
2328 if ( pThis->paSymbols[iSym].idxSegDef == idxSegDef
2329 && pThis->paSymbols[iSym].enmType == OMFSYMTYPE_PUBDEF)
2330 {
2331 const char *pszName = coffGetSymbolName(&paSymbols[iSym], pchStrTab, cbStrTab, szShort);
2332 if (!omfWriter_PubDefAdd(pThis, paSymbols[iSym].Value, pszName))
2333 return false;
2334
2335 /* If the symbol doesn't start with an underscore and is a _c64 or _lm64 symbol,
2336 add an underscore prefixed alias to ease access from 16-bit and 32-bit code. */
2337 size_t cchName = strlen(pszName);
2338 if ( *pszName != '_'
2339 && ( (cchName > 4 && strcmp(&pszName[cchName - 4], "_c64") == 0)
2340 || (cchName > 5 && strcmp(&pszName[cchName - 5], "_lm64") == 0) ) )
2341 {
2342 char szCdeclName[512];
2343 if (cchName > sizeof(szCdeclName) - 2)
2344 cchName = sizeof(szCdeclName) - 2;
2345 szCdeclName[0] = '_';
2346 memcpy(&szCdeclName[1], pszName, cchName);
2347 szCdeclName[cchName + 1] = '\0';
2348 if (!omfWriter_PubDefAdd(pThis, paSymbols[iSym].Value, szCdeclName))
2349 return false;
2350 }
2351
2352 pThis->paSymbols[iSym].idx = idxPubDef++;
2353 }
2354 if (!omfWriter_PubDefEnd(pThis))
2355 return false;
2356 }
2357 }
2358
2359 if (cAbsSyms > 0)
2360 {
2361 if (!omfWriter_PubDefBegin(pThis, 0, 0))
2362 return false;
2363 for (uint16_t iSym = 0; iSym < cSymbols; iSym++)
2364 if ( pThis->paSymbols[iSym].idxSegDef == 0
2365 && pThis->paSymbols[iSym].enmType == OMFSYMTYPE_PUBDEF)
2366 {
2367 if (!omfWriter_PubDefAdd(pThis, paSymbols[iSym].Value,
2368 coffGetSymbolName(&paSymbols[iSym], pchStrTab, cbStrTab, szShort)) )
2369 return false;
2370 pThis->paSymbols[iSym].idx = idxPubDef++;
2371 }
2372 if (!omfWriter_PubDefEnd(pThis))
2373 return false;
2374 }
2375
2376 /*
2377 * Go over the symbol table and emit external definition records.
2378 */
2379 if (!omfWriter_ExtDefBegin(pThis))
2380 return false;
2381 uint16_t idxExtDef = 1;
2382 for (uint16_t iSym = 0; iSym < cSymbols; iSym++)
2383 if (pThis->paSymbols[iSym].enmType == OMFSYMTYPE_EXTDEF)
2384 {
2385 if (!omfWriter_ExtDefAdd(pThis, coffGetSymbolName(&paSymbols[iSym], pchStrTab, cbStrTab, szShort)))
2386 return false;
2387 pThis->paSymbols[iSym].idx = idxExtDef++;
2388 }
2389
2390 /* Always add an __ImageBase reference, in case we need it to deal with ADDR32NB fixups. */
2391 /** @todo maybe we don't actually need this and could use FLAT instead? */
2392 if (iSymImageBase != UINT32_MAX)
2393 pThis->idxExtImageBase = pThis->paSymbols[iSymImageBase].idx;
2394 else if (omfWriter_ExtDefAdd(pThis, "__ImageBase"))
2395 pThis->idxExtImageBase = idxExtDef;
2396 else
2397 return false;
2398
2399 if (!omfWriter_ExtDefEnd(pThis))
2400 return false;
2401
2402 return true;
2403}
2404
2405
2406static bool convertCoffSectionsToLeDataAndFixupps(POMFWRITER pThis, uint8_t const *pbFile, size_t cbFile,
2407 PCIMAGE_SECTION_HEADER paShdrs, uint16_t cSections,
2408 PCIMAGE_SYMBOL paSymbols, uint16_t cSymbols, const char *pchStrTab)
2409{
2410 uint32_t const cbStrTab = *(uint32_t const *)pchStrTab;
2411 bool fRet = true;
2412 for (uint32_t i = 0; i < pThis->cSegments; i++)
2413 {
2414 if (pThis->paSegments[i].iSegDef == UINT16_MAX)
2415 continue;
2416
2417 char szShortName[16];
2418 const char *pszSegNm = pThis->paSegments[i].pszName;
2419 uint16_t cRelocs = paShdrs[i].NumberOfRelocations;
2420 PCIMAGE_RELOCATION paRelocs = (PCIMAGE_RELOCATION)&pbFile[paShdrs[i].PointerToRelocations];
2421 uint32_t cbVirtData = paShdrs[i].SizeOfRawData;
2422 uint32_t cbData = paShdrs[i].Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA ? 0 : cbVirtData;
2423 uint8_t const *pbData = &pbFile[paShdrs[i].PointerToRawData];
2424 uint32_t off = 0;
2425
2426 /* Check that the relocations are sorted and within the section. */
2427 for (uint32_t iReloc = 1; iReloc < cRelocs; iReloc++)
2428 if (paRelocs[iReloc - 1].u.VirtualAddress >= paRelocs[iReloc].u.VirtualAddress)
2429 return error(pThis->pszSrc, "Section #%u (%s) relocations aren't sorted\n", i, pszSegNm);
2430 if ( cRelocs > 0
2431 && paRelocs[cRelocs - 1].u.VirtualAddress - paShdrs[i].VirtualAddress
2432 + COFF_AMD64_RELOC_SIZE(paRelocs[cRelocs - 1].Type) > cbVirtData)
2433 return error(pThis->pszSrc,
2434 "Section #%u (%s) relocations beyond section data! cbVirtData=%#x RvaFix=%#x RVASeg=%#x type=%#x\n",
2435 i, pszSegNm, cbVirtData, paRelocs[cRelocs - 1].u.VirtualAddress, paShdrs[i].VirtualAddress,
2436 paRelocs[cRelocs - 1].Type);
2437
2438 /* The OMF record size requires us to split larger sections up. To make
2439 life simple, we fill zeros for unitialized (BSS) stuff. */
2440 const uint32_t cbMaxData = RT_MIN(OMF_MAX_RECORD_PAYLOAD - 1 - (pThis->paSegments[i].iSegDef >= 128) - 4 - 1, _1K);
2441 while (cbVirtData > 0)
2442 {
2443 /* Figure out how many bytes to put out in this chunk. Must make sure
2444 fixups doesn't cross chunk boundraries. ASSUMES sorted relocs. */
2445 uint32_t cChunkRelocs = cRelocs;
2446 uint32_t cbChunk = cbVirtData;
2447 uint32_t uRvaEnd = paShdrs[i].VirtualAddress + off + cbChunk;
2448 if (cbChunk > cbMaxData)
2449 {
2450 cbChunk = cbMaxData;
2451 uRvaEnd = paShdrs[i].VirtualAddress + off + cbChunk;
2452 cChunkRelocs = 0;
2453
2454 /* Quickly determin the reloc range. */
2455 while ( cChunkRelocs < cRelocs
2456 && paRelocs[cChunkRelocs].u.VirtualAddress < uRvaEnd)
2457 cChunkRelocs++;
2458
2459 /* Ensure final reloc doesn't go beyond chunk. */
2460 while ( cChunkRelocs > 0
2461 && paRelocs[cChunkRelocs - 1].u.VirtualAddress + COFF_AMD64_RELOC_SIZE(paRelocs[cChunkRelocs - 1].Type)
2462 > uRvaEnd)
2463 {
2464 uint32_t cbDrop = uRvaEnd - paRelocs[cChunkRelocs - 1].u.VirtualAddress;
2465 cbChunk -= cbDrop;
2466 uRvaEnd -= cbDrop;
2467 cChunkRelocs--;
2468 }
2469
2470 if (!cbVirtData)
2471 return error(pThis->pszSrc, "Wtf? cbVirtData is zero!\n");
2472 }
2473
2474 /*
2475 * We stash the bytes into the OMF writer record buffer, receiving a
2476 * pointer to the start of it so we can make adjustments if necessary.
2477 */
2478 uint8_t *pbCopy;
2479 if (!omfWriter_LEDataBeginEx(pThis, pThis->paSegments[i].iSegDef, off, cbChunk, cbData, pbData, &pbCopy))
2480 return false;
2481
2482 /*
2483 * Convert fiuxps.
2484 */
2485 uint32_t const uRvaChunk = paShdrs[i].VirtualAddress + off;
2486 for (uint32_t iReloc = 0; iReloc < cChunkRelocs; iReloc++)
2487 {
2488 /* Get the OMF and COFF data for the symbol the reloc references. */
2489 if (paRelocs[iReloc].SymbolTableIndex >= pThis->cSymbols)
2490 return error(pThis->pszSrc, "Relocation symtab index (%#x) is out of range in segment #%u '%s'\n",
2491 paRelocs[iReloc].SymbolTableIndex, i, pszSegNm);
2492 PCIMAGE_SYMBOL pCoffSym = &paSymbols[paRelocs[iReloc].SymbolTableIndex];
2493 POMFSYMBOL pOmfSym = &pThis->paSymbols[paRelocs[iReloc].SymbolTableIndex];
2494
2495 /* Calc fixup location in the pending chunk and setup a flexible pointer to it. */
2496 uint16_t offDataRec = (uint16_t)(paRelocs[iReloc].u.VirtualAddress - uRvaChunk);
2497 RTPTRUNION uLoc;
2498 uLoc.pu8 = &pbCopy[offDataRec];
2499
2500 /* OMF fixup data initialized with typical defaults. */
2501 bool fSelfRel = true;
2502 uint8_t bLocation = OMF_FIX_LOC_32BIT_OFFSET;
2503 uint8_t bFrame = OMF_FIX_F_GRPDEF;
2504 uint16_t idxFrame = pThis->idxGrpFlat;
2505 uint8_t bTarget;
2506 uint16_t idxTarget;
2507 bool fTargetDisp;
2508 uint32_t offTargetDisp;
2509 switch (pOmfSym->enmType)
2510 {
2511 case OMFSYMTYPE_INTERNAL:
2512 case OMFSYMTYPE_PUBDEF:
2513 bTarget = OMF_FIX_T_SEGDEF;
2514 idxTarget = pOmfSym->idxSegDef;
2515 fTargetDisp = true;
2516 offTargetDisp = pCoffSym->Value;
2517 break;
2518
2519 case OMFSYMTYPE_SEGDEF:
2520 bTarget = OMF_FIX_T_SEGDEF_NO_DISP;
2521 idxTarget = pOmfSym->idxSegDef;
2522 fTargetDisp = false;
2523 offTargetDisp = 0;
2524 break;
2525
2526 case OMFSYMTYPE_EXTDEF:
2527 bTarget = OMF_FIX_T_EXTDEF_NO_DISP;
2528 idxTarget = pOmfSym->idx;
2529 fTargetDisp = false;
2530 offTargetDisp = 0;
2531 break;
2532
2533 default:
2534 return error(pThis->pszSrc, "Relocation in segment #%u '%s' references ignored or invalid symbol (%s)\n",
2535 i, pszSegNm, coffGetSymbolName(pCoffSym, pchStrTab, cbStrTab, szShortName));
2536 }
2537
2538 /* Do COFF relocation type conversion. */
2539 switch (paRelocs[iReloc].Type)
2540 {
2541 case IMAGE_REL_AMD64_ADDR64:
2542 {
2543 uint64_t uAddend = *uLoc.pu64;
2544 if (uAddend > _1G)
2545 fRet = error(pThis->pszSrc, "ADDR64 with large addend (%#llx) at %#x in segment #%u '%s'\n",
2546 uAddend, paRelocs[iReloc].u.VirtualAddress, i, pszSegNm);
2547 fSelfRel = false;
2548 break;
2549 }
2550
2551 case IMAGE_REL_AMD64_REL32_1:
2552 case IMAGE_REL_AMD64_REL32_2:
2553 case IMAGE_REL_AMD64_REL32_3:
2554 case IMAGE_REL_AMD64_REL32_4:
2555 case IMAGE_REL_AMD64_REL32_5:
2556 /** @todo Check whether OMF read addends from the data or relies on the
2557 * displacement. Also, check what it's relative to. */
2558 *uLoc.pu32 -= paRelocs[iReloc].Type - IMAGE_REL_AMD64_REL32;
2559 break;
2560
2561 case IMAGE_REL_AMD64_ADDR32:
2562 fSelfRel = false;
2563 break;
2564
2565 case IMAGE_REL_AMD64_ADDR32NB:
2566 fSelfRel = false;
2567 bFrame = OMF_FIX_F_EXTDEF;
2568 idxFrame = pThis->idxExtImageBase;
2569 break;
2570
2571 case IMAGE_REL_AMD64_REL32:
2572 /* defaults are ok. */
2573 break;
2574
2575 case IMAGE_REL_AMD64_SECTION:
2576 bLocation = OMF_FIX_LOC_16BIT_SEGMENT;
2577 /* fall thru */
2578
2579 case IMAGE_REL_AMD64_SECREL:
2580 fSelfRel = false;
2581 if (pOmfSym->enmType == OMFSYMTYPE_EXTDEF)
2582 {
2583 bFrame = OMF_FIX_F_EXTDEF;
2584 idxFrame = pOmfSym->idx;
2585 }
2586 else
2587 {
2588 bFrame = OMF_FIX_F_SEGDEF;
2589 idxFrame = pOmfSym->idxSegDef;
2590 }
2591 break;
2592
2593 case IMAGE_REL_AMD64_ABSOLUTE:
2594 continue; /* Ignore it like the PECOFF.DOC says we should. */
2595
2596 case IMAGE_REL_AMD64_SECREL7:
2597 default:
2598 return error(pThis->pszSrc, "Unsupported fixup type %#x (%s) at rva=%#x in section #%u '%-8.8s'\n",
2599 paRelocs[iReloc].Type,
2600 paRelocs[iReloc].Type < RT_ELEMENTS(g_apszCoffAmd64RelTypes)
2601 ? g_apszCoffAmd64RelTypes[paRelocs[iReloc].Type] : "unknown",
2602 paRelocs[iReloc].u.VirtualAddress, i, paShdrs[i].Name);
2603 }
2604
2605 /* Add the fixup. */
2606 if (idxFrame == UINT16_MAX)
2607 error(pThis->pszSrc, "idxFrame=UINT16_MAX for %s type=%s\n",
2608 coffGetSymbolName(pCoffSym, pchStrTab, cbStrTab, szShortName),
2609 g_apszCoffAmd64RelTypes[paRelocs[iReloc].Type]);
2610 fRet = omfWriter_LEDataAddFixup(pThis, offDataRec, fSelfRel, bLocation, bFrame, idxFrame,
2611 bTarget, idxTarget, fTargetDisp, offTargetDisp) && fRet;
2612 }
2613
2614 /*
2615 * Write the LEDATA and associated FIXUPPs.
2616 */
2617 if (!omfWriter_LEDataEnd(pThis))
2618 return false;
2619
2620 /*
2621 * Advance.
2622 */
2623 paRelocs += cChunkRelocs;
2624 cRelocs -= cChunkRelocs;
2625 if (cbData > cbChunk)
2626 {
2627 cbData -= cbChunk;
2628 pbData += cbChunk;
2629 }
2630 else
2631 cbData = 0;
2632 off += cbChunk;
2633 cbVirtData -= cbChunk;
2634 }
2635 }
2636
2637 return fRet;
2638}
2639
2640
2641static bool convertCoffToOmf(const char *pszFile, uint8_t const *pbFile, size_t cbFile, FILE *pDst)
2642{
2643 /*
2644 * Validate the source file a little.
2645 */
2646 if (!validateCoff(pszFile, pbFile, cbFile))
2647 return false;
2648
2649 /*
2650 * Instantiate the OMF writer.
2651 */
2652 PIMAGE_FILE_HEADER pHdr = (PIMAGE_FILE_HEADER)pbFile;
2653 POMFWRITER pThis = omfWriter_Create(pszFile, pHdr->NumberOfSections, pHdr->NumberOfSymbols, pDst);
2654 if (!pThis)
2655 return false;
2656
2657 /*
2658 * Write the OMF object file.
2659 */
2660 if (omfWriter_BeginModule(pThis, pszFile))
2661 {
2662 PCIMAGE_SECTION_HEADER paShdrs = (PCIMAGE_SECTION_HEADER)(pHdr + 1);
2663 PCIMAGE_SYMBOL paSymTab = (PCIMAGE_SYMBOL)&pbFile[pHdr->PointerToSymbolTable];
2664 const char *pchStrTab = (const char *)&paSymTab[pHdr->NumberOfSymbols];
2665 if ( convertCoffSectionsToSegDefsAndGrpDefs(pThis, paShdrs, pHdr->NumberOfSections)
2666 && convertCoffSymbolsToPubDefsAndExtDefs(pThis, paSymTab, pHdr->NumberOfSymbols, pchStrTab, paShdrs)
2667 && omfWriter_LinkPassSeparator(pThis)
2668 && convertCoffSectionsToLeDataAndFixupps(pThis, pbFile, cbFile, paShdrs, pHdr->NumberOfSections,
2669 paSymTab, pHdr->NumberOfSymbols, pchStrTab)
2670 && omfWriter_EndModule(pThis) )
2671 {
2672
2673 omfWriter_Destroy(pThis);
2674 return true;
2675 }
2676 }
2677
2678 omfWriter_Destroy(pThis);
2679 return false;
2680}
2681
2682
2683/*********************************************************************************************************************************
2684* Mach-O/AMD64 -> OMF/i386 Converter *
2685*********************************************************************************************************************************/
2686
2687//#define MACHO_TO_OMF_CONVERSION
2688#ifdef MACHO_TO_OMF_CONVERSION
2689
2690/** AMD64 relocation type names for Mach-O. */
2691static const char * const g_apszMachOAmd64RelTypes[] =
2692{
2693 "X86_64_RELOC_UNSIGNED",
2694 "X86_64_RELOC_SIGNED",
2695 "X86_64_RELOC_BRANCH",
2696 "X86_64_RELOC_GOT_LOAD",
2697 "X86_64_RELOC_GOT",
2698 "X86_64_RELOC_SUBTRACTOR",
2699 "X86_64_RELOC_SIGNED_1",
2700 "X86_64_RELOC_SIGNED_2",
2701 "X86_64_RELOC_SIGNED_4"
2702};
2703
2704/** AMD64 relocation type sizes for Mach-O. */
2705static uint8_t const g_acbMachOAmd64RelTypes[] =
2706{
2707 8, /* X86_64_RELOC_UNSIGNED */
2708 4, /* X86_64_RELOC_SIGNED */
2709 4, /* X86_64_RELOC_BRANCH */
2710 4, /* X86_64_RELOC_GOT_LOAD */
2711 4, /* X86_64_RELOC_GOT */
2712 8, /* X86_64_RELOC_SUBTRACTOR */
2713 4, /* X86_64_RELOC_SIGNED_1 */
2714 4, /* X86_64_RELOC_SIGNED_2 */
2715 4, /* X86_64_RELOC_SIGNED_4 */
2716};
2717
2718/** Macro for getting the size of a AMD64 ELF relocation. */
2719#define ELF_AMD64_RELOC_SIZE(a_Type) ( (a_Type) < RT_ELEMENTS(g_acbElfAmd64RelTypes) ? g_acbElfAmd64RelTypes[(a_Type)] : 1)
2720
2721
2722typedef struct ELFDETAILS
2723{
2724 /** The ELF header. */
2725 Elf64_Ehdr const *pEhdr;
2726 /** The section header table. */
2727 Elf64_Shdr const *paShdrs;
2728 /** The string table for the section names. */
2729 const char *pchShStrTab;
2730
2731 /** The symbol table section number. UINT16_MAX if not found. */
2732 uint16_t iSymSh;
2733 /** The string table section number. UINT16_MAX if not found. */
2734 uint16_t iStrSh;
2735
2736 /** The symbol table. */
2737 Elf64_Sym const *paSymbols;
2738 /** The number of symbols in the symbol table. */
2739 uint32_t cSymbols;
2740
2741 /** Pointer to the (symbol) string table if found. */
2742 const char *pchStrTab;
2743 /** The string table size. */
2744 size_t cbStrTab;
2745
2746} ELFDETAILS;
2747typedef ELFDETAILS *PELFDETAILS;
2748typedef ELFDETAILS const *PCELFDETAILS;
2749
2750
2751static bool validateElf(const char *pszFile, uint8_t const *pbFile, size_t cbFile, PELFDETAILS pElfStuff)
2752{
2753 /*
2754 * Initialize the ELF details structure.
2755 */
2756 memset(pElfStuff, 0, sizeof(*pElfStuff));
2757 pElfStuff->iSymSh = UINT16_MAX;
2758 pElfStuff->iStrSh = UINT16_MAX;
2759
2760 /*
2761 * Validate the header and our other expectations.
2762 */
2763 Elf64_Ehdr const *pEhdr = (Elf64_Ehdr const *)pbFile;
2764 pElfStuff->pEhdr = pEhdr;
2765 if ( pEhdr->e_ident[EI_CLASS] != ELFCLASS64
2766 || pEhdr->e_ident[EI_DATA] != ELFDATA2LSB
2767 || pEhdr->e_ehsize != sizeof(Elf64_Ehdr)
2768 || pEhdr->e_shentsize != sizeof(Elf64_Shdr)
2769 || pEhdr->e_version != EV_CURRENT )
2770 return error(pszFile, "Unsupported ELF config\n");
2771 if (pEhdr->e_type != ET_REL)
2772 return error(pszFile, "Expected relocatable ELF file (e_type=%d)\n", pEhdr->e_type);
2773 if (pEhdr->e_machine != EM_X86_64)
2774 return error(pszFile, "Expected relocatable ELF file (e_type=%d)\n", pEhdr->e_machine);
2775 if (pEhdr->e_phnum != 0)
2776 return error(pszFile, "Expected e_phnum to be zero not %u\n", pEhdr->e_phnum);
2777 if (pEhdr->e_shnum < 2)
2778 return error(pszFile, "Expected e_shnum to be two or higher\n");
2779 if (pEhdr->e_shstrndx >= pEhdr->e_shnum || pEhdr->e_shstrndx == 0)
2780 return error(pszFile, "Bad e_shstrndx=%u (e_shnum=%u)\n", pEhdr->e_shstrndx, pEhdr->e_shnum);
2781 if ( pEhdr->e_shoff >= cbFile
2782 || pEhdr->e_shoff + pEhdr->e_shnum * sizeof(Elf64_Shdr) > cbFile)
2783 return error(pszFile, "Section table is outside the file (e_shoff=%#llx, e_shnum=%u, cbFile=%#llx)\n",
2784 pEhdr->e_shstrndx, pEhdr->e_shnum, (uint64_t)cbFile);
2785
2786 /*
2787 * Locate the section name string table.
2788 * We assume it's okay as we only reference it in verbose mode.
2789 */
2790 Elf64_Shdr const *paShdrs = (Elf64_Shdr const *)&pbFile[pEhdr->e_shoff];
2791 pElfStuff->paShdrs = paShdrs;
2792
2793 Elf64_Xword const cbShStrTab = paShdrs[pEhdr->e_shstrndx].sh_size;
2794 if ( paShdrs[pEhdr->e_shstrndx].sh_offset > cbFile
2795 || cbShStrTab > cbFile
2796 || paShdrs[pEhdr->e_shstrndx].sh_offset + cbShStrTab > cbFile)
2797 return error(pszFile,
2798 "Section string table is outside the file (sh_offset=%#" ELF_FMT_X64 " sh_size=%#" ELF_FMT_X64 " cbFile=%#" ELF_FMT_X64 ")\n",
2799 paShdrs[pEhdr->e_shstrndx].sh_offset, paShdrs[pEhdr->e_shstrndx].sh_size, (Elf64_Xword)cbFile);
2800 const char *pchShStrTab = (const char *)&pbFile[paShdrs[pEhdr->e_shstrndx].sh_offset];
2801 pElfStuff->pchShStrTab = pchShStrTab;
2802
2803 /*
2804 * Work the section table.
2805 */
2806 bool fRet = true;
2807 for (uint32_t i = 1; i < pEhdr->e_shnum; i++)
2808 {
2809 if (paShdrs[i].sh_name >= cbShStrTab)
2810 return error(pszFile, "Invalid sh_name value (%#x) for section #%u\n", paShdrs[i].sh_name, i);
2811 const char *pszShNm = &pchShStrTab[paShdrs[i].sh_name];
2812
2813 if ( paShdrs[i].sh_offset > cbFile
2814 || paShdrs[i].sh_size > cbFile
2815 || paShdrs[i].sh_offset + paShdrs[i].sh_size > cbFile)
2816 return error(pszFile, "Section #%u '%s' has data outside the file: %#" ELF_FMT_X64 " LB %#" ELF_FMT_X64 " (cbFile=%#" ELF_FMT_X64 ")\n",
2817 i, pszShNm, paShdrs[i].sh_offset, paShdrs[i].sh_size, (Elf64_Xword)cbFile);
2818 if (g_cVerbose)
2819 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"
2820 " link=%u info=%#x align=%#" ELF_FMT_X64 " entsize=%#" ELF_FMT_X64 "\n",
2821 i, paShdrs[i].sh_name, pszShNm, paShdrs[i].sh_type, paShdrs[i].sh_flags,
2822 paShdrs[i].sh_addr, paShdrs[i].sh_offset, paShdrs[i].sh_size,
2823 paShdrs[i].sh_link, paShdrs[i].sh_info, paShdrs[i].sh_addralign, paShdrs[i].sh_entsize);
2824
2825 if (paShdrs[i].sh_link >= pEhdr->e_shnum)
2826 return error(pszFile, "Section #%u '%s' links to a section outside the section table: %#x, max %#x\n",
2827 i, pszShNm, paShdrs[i].sh_link, pEhdr->e_shnum);
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 (!RT_IS_POWER_OF_TWO(paShdrs[i].sh_addralign))
2832 return error(pszFile, "Section #%u '%s' alignment value is not a power of two: %#" ELF_FMT_X64 "\n",
2833 i, pszShNm, paShdrs[i].sh_addralign);
2834 if (paShdrs[i].sh_addr != 0)
2835 return error(pszFile, "Section #%u '%s' has non-zero address: %#" ELF_FMT_X64 "\n", i, pszShNm, paShdrs[i].sh_addr);
2836
2837 if (paShdrs[i].sh_type == SHT_RELA)
2838 {
2839 if (paShdrs[i].sh_entsize != sizeof(Elf64_Rela))
2840 return error(pszFile, "Expected sh_entsize to be %u not %u for section #%u (%s)\n", (unsigned)sizeof(Elf64_Rela),
2841 paShdrs[i].sh_entsize, i, pszShNm);
2842 uint32_t const cRelocs = paShdrs[i].sh_size / sizeof(Elf64_Rela);
2843 if (cRelocs * sizeof(Elf64_Rela) != paShdrs[i].sh_size)
2844 return error(pszFile, "Uneven relocation entry count in #%u (%s): sh_size=%#" ELF_FMT_X64 "\n",
2845 i, pszShNm, paShdrs[i].sh_size);
2846 if ( paShdrs[i].sh_offset > cbFile
2847 || paShdrs[i].sh_size >= cbFile
2848 || paShdrs[i].sh_offset + paShdrs[i].sh_size > cbFile)
2849 return error(pszFile, "The content of section #%u '%s' is outside the file (%#" ELF_FMT_X64 " LB %#" ELF_FMT_X64 ", cbFile=%#lx)\n",
2850 i, pszShNm, paShdrs[i].sh_offset, paShdrs[i].sh_size, (unsigned long)cbFile);
2851 if (paShdrs[i].sh_info != i - 1)
2852 return error(pszFile, "Expected relocation section #%u (%s) to link to previous section: sh_info=%#u\n",
2853 i, pszShNm, (unsigned)paShdrs[i].sh_link);
2854 if (paShdrs[paShdrs[i].sh_link].sh_type != SHT_SYMTAB)
2855 return error(pszFile, "Expected relocation section #%u (%s) to link to symbol table: sh_link=%#u -> sh_type=%#x\n",
2856 i, pszShNm, (unsigned)paShdrs[i].sh_link, (unsigned)paShdrs[paShdrs[i].sh_link].sh_type);
2857 uint32_t cSymbols = paShdrs[paShdrs[i].sh_link].sh_size / paShdrs[paShdrs[i].sh_link].sh_entsize;
2858
2859 Elf64_Rela const *paRelocs = (Elf64_Rela *)&pbFile[paShdrs[i].sh_offset];
2860 for (uint32_t j = 0; j < cRelocs; j++)
2861 {
2862 uint8_t const bType = ELF64_R_TYPE(paRelocs[j].r_info);
2863 if (RT_UNLIKELY(bType >= R_X86_64_COUNT))
2864 fRet = error(pszFile,
2865 "%#018" ELF_FMT_X64 " %#018" ELF_FMT_X64 ": unknown fix up %#x (%+" ELF_FMT_D64 ")\n",
2866 paRelocs[j].r_offset, paRelocs[j].r_info, bType, paRelocs[j].r_addend);
2867 if (RT_UNLIKELY( j > 1
2868 && paRelocs[j].r_offset <= paRelocs[j - 1].r_offset
2869 && paRelocs[j].r_offset + ELF_AMD64_RELOC_SIZE(ELF64_R_TYPE(paRelocs[j].r_info))
2870 < paRelocs[j - 1].r_offset ))
2871 fRet = error(pszFile,
2872 "%#018" ELF_FMT_X64 " %#018" ELF_FMT_X64 ": out of offset order (prev %" ELF_FMT_X64 ")\n",
2873 paRelocs[j].r_offset, paRelocs[j].r_info, paRelocs[j - 1].r_offset);
2874 uint32_t const iSymbol = ELF64_R_SYM(paRelocs[j].r_info);
2875 if (RT_UNLIKELY(iSymbol >= cSymbols))
2876 fRet = error(pszFile,
2877 "%#018" ELF_FMT_X64 " %#018" ELF_FMT_X64 ": symbol index (%#x) out of bounds (%#x)\n",
2878 paRelocs[j].r_offset, paRelocs[j].r_info, iSymbol, cSymbols);
2879 }
2880 if (RT_UNLIKELY( cRelocs > 0
2881 && fRet
2882 && ( paRelocs[cRelocs - 1].r_offset > paShdrs[i - 1].sh_size
2883 || paRelocs[cRelocs - 1].r_offset + ELF_AMD64_RELOC_SIZE(ELF64_R_TYPE(paRelocs[cRelocs-1].r_info))
2884 > paShdrs[i - 1].sh_size )))
2885 fRet = error(pszFile,
2886 "%#018" ELF_FMT_X64 " %#018" ELF_FMT_X64 ": out of bounds (sh_size %" ELF_FMT_X64 ")\n",
2887 paRelocs[cRelocs - 1].r_offset, paRelocs[cRelocs - 1].r_info, paShdrs[i - 1].sh_size);
2888
2889 }
2890 else if (paShdrs[i].sh_type == SHT_REL)
2891 fRet = error(pszFile, "Section #%u '%s': Unexpected SHT_REL section\n", i, pszShNm);
2892 else if (paShdrs[i].sh_type == SHT_SYMTAB)
2893 {
2894 if (paShdrs[i].sh_entsize != sizeof(Elf64_Sym))
2895 fRet = error(pszFile, "Section #%u '%s': Unsupported symbol table entry size in : #%u (expected #%u)\n",
2896 i, pszShNm, paShdrs[i].sh_entsize, sizeof(Elf64_Sym));
2897 Elf64_Xword const cSymbols = paShdrs[i].sh_size / paShdrs[i].sh_entsize;
2898 if (cSymbols * paShdrs[i].sh_entsize != paShdrs[i].sh_size)
2899 fRet = error(pszFile, "Section #%u '%s': Size not a multiple of entry size: %#" ELF_FMT_X64 " %% %#" ELF_FMT_X64 " = %#" ELF_FMT_X64 "\n",
2900 i, pszShNm, paShdrs[i].sh_size, paShdrs[i].sh_entsize, paShdrs[i].sh_size % paShdrs[i].sh_entsize);
2901 if (cSymbols > UINT32_MAX)
2902 fRet = error(pszFile, "Section #%u '%s': too many symbols: %" ELF_FMT_X64 "\n",
2903 i, pszShNm, paShdrs[i].sh_size, cSymbols);
2904
2905 if (pElfStuff->iSymSh == UINT16_MAX)
2906 {
2907 pElfStuff->iSymSh = (uint16_t)i;
2908 pElfStuff->paSymbols = (Elf64_Sym const *)&pbFile[paShdrs[i].sh_offset];
2909 pElfStuff->cSymbols = cSymbols;
2910
2911 if (paShdrs[i].sh_link != 0)
2912 {
2913 /* Note! The symbol string table section header may not have been validated yet! */
2914 Elf64_Shdr const *pStrTabShdr = &paShdrs[paShdrs[i].sh_link];
2915 pElfStuff->iStrSh = paShdrs[i].sh_link;
2916 pElfStuff->pchStrTab = (const char *)&pbFile[pStrTabShdr->sh_offset];
2917 pElfStuff->cbStrTab = (size_t)pStrTabShdr->sh_size;
2918 }
2919 else
2920 fRet = error(pszFile, "Section #%u '%s': String table link is out of bounds (%#x)\n",
2921 i, pszShNm, paShdrs[i].sh_link);
2922 }
2923 else
2924 fRet = error(pszFile, "Section #%u '%s': Found additonal symbol table, previous in #%u\n",
2925 i, pszShNm, pElfStuff->iSymSh);
2926 }
2927 }
2928 return fRet;
2929}
2930
2931static bool convertElfSectionsToSegDefsAndGrpDefs(POMFWRITER pThis, PCELFDETAILS pElfStuff)
2932{
2933 /*
2934 * Do the list of names pass.
2935 */
2936 uint16_t idxGrpFlat, idxGrpData;
2937 uint16_t idxClassCode, idxClassData, idxClassDwarf;
2938 if ( !omfWriter_LNamesBegin(pThis, true /*fAddZeroEntry*/)
2939 || !omfWriter_LNamesAddN(pThis, RT_STR_TUPLE("FLAT"), &idxGrpFlat)
2940 || !omfWriter_LNamesAddN(pThis, RT_STR_TUPLE("BS3DATA64_GROUP"), &idxGrpData)
2941 || !omfWriter_LNamesAddN(pThis, RT_STR_TUPLE("BS3CLASS64CODE"), &idxClassCode)
2942 || !omfWriter_LNamesAddN(pThis, RT_STR_TUPLE("FAR_DATA"), &idxClassData)
2943 || !omfWriter_LNamesAddN(pThis, RT_STR_TUPLE("DWARF"), &idxClassDwarf)
2944 )
2945 return false;
2946
2947 bool fHaveData = false;
2948 Elf64_Shdr const *pShdr = &pElfStuff->paShdrs[1];
2949 Elf64_Half const cSections = pElfStuff->pEhdr->e_shnum;
2950 for (Elf64_Half i = 1; i < cSections; i++, pShdr++)
2951 {
2952 const char *pszName = &pElfStuff->pchShStrTab[pShdr->sh_name];
2953 if (*pszName == '\0')
2954 return error(pThis->pszSrc, "Section #%u has an empty name!\n", i);
2955
2956 switch (pShdr->sh_type)
2957 {
2958 case SHT_PROGBITS:
2959 case SHT_NOBITS:
2960 /* We drop a few sections we don't want:. */
2961 if ( strcmp(pszName, ".comment") != 0 /* compiler info */
2962 && strcmp(pszName, ".note.GNU-stack") != 0 /* some empty section for hinting the linker/whatever */
2963 && strcmp(pszName, ".eh_frame") != 0 /* unwind / exception info */
2964 )
2965 {
2966 pThis->paSegments[i].iSegDef = UINT16_MAX;
2967 pThis->paSegments[i].iGrpDef = UINT16_MAX;
2968
2969 /* Translate the name and determine group and class.
2970 Note! We currently strip sub-sections. */
2971 if ( strcmp(pszName, ".text") == 0
2972 || strncmp(pszName, RT_STR_TUPLE(".text.")) == 0)
2973 {
2974 pszName = "BS3TEXT64";
2975 pThis->paSegments[i].iGrpNm = idxGrpFlat;
2976 pThis->paSegments[i].iClassNm = idxClassCode;
2977 }
2978 else if ( strcmp(pszName, ".data") == 0
2979 || strncmp(pszName, RT_STR_TUPLE(".data.")) == 0)
2980 {
2981 pszName = "BS3DATA64";
2982 pThis->paSegments[i].iGrpNm = idxGrpData;
2983 pThis->paSegments[i].iClassNm = idxClassData;
2984 }
2985 else if (strcmp(pszName, ".bss") == 0)
2986 {
2987 pszName = "BS3BSS64";
2988 pThis->paSegments[i].iGrpNm = idxGrpData;
2989 pThis->paSegments[i].iClassNm = idxClassData;
2990 }
2991 else if ( strcmp(pszName, ".rodata") == 0
2992 || strncmp(pszName, RT_STR_TUPLE(".rodata.")) == 0)
2993 {
2994 pszName = "BS3DATA64CONST";
2995 pThis->paSegments[i].iGrpNm = idxGrpData;
2996 pThis->paSegments[i].iClassNm = idxClassData;
2997 }
2998 else if (strncmp(pszName, RT_STR_TUPLE(".debug_")) == 0)
2999 {
3000 pThis->paSegments[i].iGrpNm = UINT16_MAX;
3001 pThis->paSegments[i].iClassNm = idxClassDwarf;
3002 }
3003 else
3004 {
3005 pThis->paSegments[i].iGrpNm = idxGrpData;
3006 pThis->paSegments[i].iClassNm = idxClassData;
3007 error(pThis->pszSrc, "Unknown data (?) segment: '%s'\n", pszName);
3008 }
3009
3010 /* Save the name. */
3011 pThis->paSegments[i].pszName = strdup(pszName);
3012 if (!pThis->paSegments[i].pszName)
3013 return error(pThis->pszSrc, "Out of memory!\n");
3014
3015 /* Add the section name. */
3016 if (!omfWriter_LNamesAdd(pThis, pThis->paSegments[i].pszName, &pThis->paSegments[i].iSegNm))
3017 return false;
3018
3019 fHaveData |= pThis->paSegments[i].iGrpDef == idxGrpData;
3020 break;
3021 }
3022 /* fall thru */
3023
3024 default:
3025 pThis->paSegments[i].iSegDef = UINT16_MAX;
3026 pThis->paSegments[i].iGrpDef = UINT16_MAX;
3027 pThis->paSegments[i].iSegNm = UINT16_MAX;
3028 pThis->paSegments[i].iGrpNm = UINT16_MAX;
3029 pThis->paSegments[i].iClassNm = UINT16_MAX;
3030 pThis->paSegments[i].pszName = NULL;
3031 break;
3032 }
3033 }
3034
3035 if (!omfWriter_LNamesEnd(pThis))
3036 return false;
3037
3038 /*
3039 * Emit segment definitions.
3040 */
3041 uint16_t iSegDef = 1; /* Start counting at 1. */
3042 pShdr = &pElfStuff->paShdrs[1];
3043 for (Elf64_Half i = 1; i < cSections; i++, pShdr++)
3044 {
3045 if (pThis->paSegments[i].iSegNm == UINT16_MAX)
3046 continue;
3047
3048 uint8_t bSegAttr = 0;
3049
3050 /* The A field. */
3051 switch (pShdr->sh_addralign)
3052 {
3053 case 0:
3054 case 1:
3055 bSegAttr |= 1 << 5;
3056 break;
3057 case 2:
3058 bSegAttr |= 2 << 5;
3059 break;
3060 case 4:
3061 bSegAttr |= 5 << 5;
3062 break;
3063 case 8:
3064 case 16:
3065 bSegAttr |= 3 << 5;
3066 break;
3067 case 32:
3068 case 64:
3069 case 128:
3070 case 256:
3071 bSegAttr |= 4 << 5;
3072 break;
3073 default:
3074 bSegAttr |= 6 << 5; /* page aligned, pharlabs extension. */
3075 break;
3076 }
3077
3078 /* The C field. */
3079 bSegAttr |= 2 << 2; /* public */
3080
3081 /* The B field. We don't have 4GB segments, so leave it as zero. */
3082
3083 /* The D field shall be set as we're doing USE32. */
3084 bSegAttr |= 1;
3085
3086
3087 /* Done. */
3088 if (!omfWriter_SegDef(pThis, bSegAttr, (uint32_t)pShdr->sh_size,
3089 pThis->paSegments[i].iSegNm,
3090 pThis->paSegments[i].iClassNm))
3091 return false;
3092 pThis->paSegments[i].iSegDef = iSegDef++;
3093 }
3094
3095 /*
3096 * Flat group definition (#1) - special, no members.
3097 */
3098 uint16_t iGrpDef = 1;
3099 if ( !omfWriter_GrpDefBegin(pThis, idxGrpFlat)
3100 || !omfWriter_GrpDefEnd(pThis))
3101 return false;
3102 for (uint16_t i = 0; i < cSections; i++)
3103 if (pThis->paSegments[i].iGrpNm == idxGrpFlat)
3104 pThis->paSegments[i].iGrpDef = iGrpDef;
3105 pThis->idxGrpFlat = iGrpDef++;
3106
3107 /*
3108 * Data group definition (#2).
3109 */
3110 /** @todo do we need to consider missing segments and ordering? */
3111 uint16_t cGrpNms = 0;
3112 uint16_t aiGrpNms[2];
3113 if (fHaveData)
3114 aiGrpNms[cGrpNms++] = idxGrpData;
3115 for (uint32_t iGrpNm = 0; iGrpNm < cGrpNms; iGrpNm++)
3116 {
3117 if (!omfWriter_GrpDefBegin(pThis, aiGrpNms[iGrpNm]))
3118 return false;
3119 for (uint16_t i = 0; i < cSections; i++)
3120 if (pThis->paSegments[i].iGrpNm == aiGrpNms[iGrpNm])
3121 {
3122 pThis->paSegments[i].iGrpDef = iGrpDef;
3123 if (!omfWriter_GrpDefAddSegDef(pThis, pThis->paSegments[i].iSegDef))
3124 return false;
3125 }
3126 if (!omfWriter_GrpDefEnd(pThis))
3127 return false;
3128 iGrpDef++;
3129 }
3130
3131 return true;
3132}
3133
3134static bool convertElfSymbolsToPubDefsAndExtDefs(POMFWRITER pThis, PCELFDETAILS pElfStuff)
3135{
3136 if (!pElfStuff->cSymbols)
3137 return true;
3138
3139 /*
3140 * Process the symbols the first.
3141 */
3142 uint32_t cAbsSyms = 0;
3143 uint32_t cExtSyms = 0;
3144 uint32_t cPubSyms = 0;
3145 for (uint32_t iSeg = 0; iSeg < pThis->cSegments; iSeg++)
3146 pThis->paSegments[iSeg].cPubDefs = 0;
3147
3148 uint32_t const cSections = pElfStuff->pEhdr->e_shnum;
3149 uint32_t const cSymbols = pElfStuff->cSymbols;
3150 Elf64_Sym const * const paSymbols = pElfStuff->paSymbols;
3151 for (uint32_t iSym = 0; iSym < cSymbols; iSym++)
3152 {
3153 const uint8_t bBind = ELF64_ST_BIND(paSymbols[iSym].st_info);
3154 const uint8_t bType = ELF64_ST_TYPE(paSymbols[iSym].st_info);
3155 const char *pszSymName = &pElfStuff->pchStrTab[paSymbols[iSym].st_name];
3156 if ( *pszSymName == '\0'
3157 && bType == STT_SECTION
3158 && paSymbols[iSym].st_shndx < cSections)
3159 pszSymName = &pElfStuff->pchShStrTab[pElfStuff->paShdrs[paSymbols[iSym].st_shndx].sh_name];
3160
3161 pThis->paSymbols[iSym].enmType = OMFSYMTYPE_IGNORED;
3162 pThis->paSymbols[iSym].idx = UINT16_MAX;
3163 pThis->paSymbols[iSym].idxSegDef = UINT16_MAX;
3164 pThis->paSymbols[iSym].idxGrpDef = UINT16_MAX;
3165
3166 uint32_t const idxSection = paSymbols[iSym].st_shndx;
3167 if (idxSection == SHN_UNDEF)
3168 {
3169 if (bBind == STB_GLOBAL)
3170 {
3171 pThis->paSymbols[iSym].enmType = OMFSYMTYPE_EXTDEF;
3172 cExtSyms++;
3173 if (*pszSymName == '\0')
3174 return error(pThis->pszSrc, "External symbol #%u (%s) has an empty name.\n", iSym, pszSymName);
3175 }
3176 else if (bBind != STB_LOCAL || iSym != 0) /* Entry zero is usually a dummy. */
3177 return error(pThis->pszSrc, "Unsupported or invalid bind type %#x for undefined symbol #%u (%s)\n",
3178 bBind, iSym, pszSymName);
3179 }
3180 else if (idxSection < cSections)
3181 {
3182 pThis->paSymbols[iSym].idxSegDef = pThis->paSegments[idxSection].iSegDef;
3183 pThis->paSymbols[iSym].idxGrpDef = pThis->paSegments[idxSection].iGrpDef;
3184 if (bBind == STB_GLOBAL)
3185 {
3186 pThis->paSymbols[iSym].enmType = OMFSYMTYPE_PUBDEF;
3187 pThis->paSegments[idxSection].cPubDefs++;
3188 cPubSyms++;
3189 if (bType == STT_SECTION)
3190 return error(pThis->pszSrc, "Don't know how to export STT_SECTION symbol #%u (%s)\n", iSym, pszSymName);
3191 if (*pszSymName == '\0')
3192 return error(pThis->pszSrc, "Public symbol #%u (%s) has an empty name.\n", iSym, pszSymName);
3193 }
3194 else if (bType == STT_SECTION)
3195 pThis->paSymbols[iSym].enmType = OMFSYMTYPE_SEGDEF;
3196 else
3197 pThis->paSymbols[iSym].enmType = OMFSYMTYPE_INTERNAL;
3198 }
3199 else if (idxSection == SHN_ABS)
3200 {
3201 if (bType != STT_FILE)
3202 {
3203 if (bBind == STB_GLOBAL)
3204 {
3205 pThis->paSymbols[iSym].enmType = OMFSYMTYPE_PUBDEF;
3206 pThis->paSymbols[iSym].idxSegDef = 0;
3207 pThis->paSymbols[iSym].idxGrpDef = 0;
3208 cAbsSyms++;
3209 if (*pszSymName == '\0')
3210 return error(pThis->pszSrc, "Public absolute symbol #%u (%s) has an empty name.\n", iSym, pszSymName);
3211 }
3212 else
3213 return error(pThis->pszSrc, "Unsupported or invalid bind type %#x for absolute symbol #%u (%s)\n",
3214 bBind, iSym, pszSymName);
3215 }
3216 }
3217 else
3218 return error(pThis->pszSrc, "Unsupported or invalid section number %#x for symbol #%u (%s)\n",
3219 idxSection, iSym, pszSymName);
3220 }
3221
3222 /*
3223 * Emit the PUBDEFs the first time around (see order of records in TIS spec).
3224 */
3225 uint16_t idxPubDef = 1;
3226 if (cPubSyms)
3227 {
3228 for (uint32_t iSeg = 0; iSeg < pThis->cSegments; iSeg++)
3229 if (pThis->paSegments[iSeg].cPubDefs > 0)
3230 {
3231 uint16_t const idxSegDef = pThis->paSegments[iSeg].iSegDef;
3232 if (!omfWriter_PubDefBegin(pThis, pThis->paSegments[iSeg].iGrpDef, idxSegDef))
3233 return false;
3234 for (uint16_t iSym = 0; iSym < cSymbols; iSym++)
3235 if ( pThis->paSymbols[iSym].idxSegDef == idxSegDef
3236 && pThis->paSymbols[iSym].enmType == OMFSYMTYPE_PUBDEF)
3237 {
3238 const char *pszName = &pElfStuff->pchStrTab[paSymbols[iSym].st_name];
3239 if (!omfWriter_PubDefAdd(pThis, paSymbols[iSym].st_value, pszName))
3240 return false;
3241
3242 /* If the symbol doesn't start with an underscore and is a _c64 or _lm64 symbol,
3243 add an underscore prefixed alias to ease access from 16-bit and 32-bit code. */
3244 size_t cchName = strlen(pszName);
3245 if ( *pszName != '_'
3246 && ( (cchName > 4 && strcmp(&pszName[cchName - 4], "_c64") == 0)
3247 || (cchName > 5 && strcmp(&pszName[cchName - 5], "_lm64") == 0) ) )
3248 {
3249 char szCdeclName[512];
3250 if (cchName > sizeof(szCdeclName) - 2)
3251 cchName = sizeof(szCdeclName) - 2;
3252 szCdeclName[0] = '_';
3253 memcpy(&szCdeclName[1], pszName, cchName);
3254 szCdeclName[cchName + 1] = '\0';
3255 if (!omfWriter_PubDefAdd(pThis, paSymbols[iSym].st_value, szCdeclName))
3256 return false;
3257 }
3258
3259 pThis->paSymbols[iSym].idx = idxPubDef++;
3260 }
3261 if (!omfWriter_PubDefEnd(pThis))
3262 return false;
3263 }
3264 }
3265
3266 if (cAbsSyms > 0)
3267 {
3268 if (!omfWriter_PubDefBegin(pThis, 0, 0))
3269 return false;
3270 for (uint16_t iSym = 0; iSym < cSymbols; iSym++)
3271 if ( pThis->paSymbols[iSym].idxSegDef == 0
3272 && pThis->paSymbols[iSym].enmType == OMFSYMTYPE_PUBDEF)
3273 {
3274 const char *pszName = &pElfStuff->pchStrTab[paSymbols[iSym].st_name];
3275 if (!omfWriter_PubDefAdd(pThis, paSymbols[iSym].st_value, pszName))
3276 return false;
3277 pThis->paSymbols[iSym].idx = idxPubDef++;
3278 }
3279 if (!omfWriter_PubDefEnd(pThis))
3280 return false;
3281 }
3282
3283 /*
3284 * Go over the symbol table and emit external definition records.
3285 */
3286 if (!omfWriter_ExtDefBegin(pThis))
3287 return false;
3288 uint16_t idxExtDef = 1;
3289 for (uint16_t iSym = 0; iSym < cSymbols; iSym++)
3290 if (pThis->paSymbols[iSym].enmType == OMFSYMTYPE_EXTDEF)
3291 {
3292 const char *pszName = &pElfStuff->pchStrTab[paSymbols[iSym].st_name];
3293 if (!omfWriter_ExtDefAdd(pThis, pszName))
3294 return false;
3295 pThis->paSymbols[iSym].idx = idxExtDef++;
3296 }
3297
3298 if (!omfWriter_ExtDefEnd(pThis))
3299 return false;
3300
3301 return true;
3302}
3303
3304static bool convertElfSectionsToLeDataAndFixupps(POMFWRITER pThis, PCELFDETAILS pElfStuff, uint8_t const *pbFile, size_t cbFile)
3305{
3306 Elf64_Sym const *paSymbols = pElfStuff->paSymbols;
3307 Elf64_Shdr const *paShdrs = pElfStuff->paShdrs;
3308 bool fRet = true;
3309 for (uint32_t i = 1; i < pThis->cSegments; i++)
3310 {
3311 if (pThis->paSegments[i].iSegDef == UINT16_MAX)
3312 continue;
3313
3314 const char *pszSegNm = &pElfStuff->pchShStrTab[paShdrs[i].sh_name];
3315 bool const fRelocs = i + 1 < pThis->cSegments && paShdrs[i + 1].sh_type == SHT_RELA;
3316 uint32_t cRelocs = fRelocs ? paShdrs[i + 1].sh_size / sizeof(Elf64_Rela) : 0;
3317 Elf64_Rela const *paRelocs = fRelocs ? (Elf64_Rela *)&pbFile[paShdrs[i + 1].sh_offset] : NULL;
3318 Elf64_Xword cbVirtData = paShdrs[i].sh_size;
3319 Elf64_Xword cbData = paShdrs[i].sh_type == SHT_NOBITS ? 0 : cbVirtData;
3320 uint8_t const *pbData = &pbFile[paShdrs[i].sh_offset];
3321 uint32_t off = 0;
3322
3323 /* The OMF record size requires us to split larger sections up. To make
3324 life simple, we fill zeros for unitialized (BSS) stuff. */
3325 const uint32_t cbMaxData = RT_MIN(OMF_MAX_RECORD_PAYLOAD - 1 - (pThis->paSegments[i].iSegDef >= 128) - 4 - 1, _1K);
3326 while (cbVirtData > 0)
3327 {
3328 /* Figure out how many bytes to put out in this chunk. Must make sure
3329 fixups doesn't cross chunk boundraries. ASSUMES sorted relocs. */
3330 uint32_t cChunkRelocs = cRelocs;
3331 uint32_t cbChunk = cbVirtData;
3332 uint32_t offEnd = off + cbChunk;
3333 if (cbChunk > cbMaxData)
3334 {
3335 cbChunk = cbMaxData;
3336 offEnd = off + cbChunk;
3337 cChunkRelocs = 0;
3338
3339 /* Quickly determin the reloc range. */
3340 while ( cChunkRelocs < cRelocs
3341 && paRelocs[cChunkRelocs].r_offset < offEnd)
3342 cChunkRelocs++;
3343
3344 /* Ensure final reloc doesn't go beyond chunk. */
3345 while ( cChunkRelocs > 0
3346 && paRelocs[cChunkRelocs - 1].r_offset
3347 + ELF_AMD64_RELOC_SIZE(ELF64_R_TYPE(paRelocs[cChunkRelocs - 1].r_info))
3348 > offEnd)
3349 {
3350 uint32_t cbDrop = offEnd - paRelocs[cChunkRelocs - 1].r_offset;
3351 cbChunk -= cbDrop;
3352 offEnd -= cbDrop;
3353 cChunkRelocs--;
3354 }
3355
3356 if (!cbVirtData)
3357 return error(pThis->pszSrc, "Wtf? cbVirtData is zero!\n");
3358 }
3359
3360 /*
3361 * We stash the bytes into the OMF writer record buffer, receiving a
3362 * pointer to the start of it so we can make adjustments if necessary.
3363 */
3364 uint8_t *pbCopy;
3365 if (!omfWriter_LEDataBeginEx(pThis, pThis->paSegments[i].iSegDef, off, cbChunk, cbData, pbData, &pbCopy))
3366 return false;
3367
3368 /*
3369 * Convert fiuxps.
3370 */
3371 for (uint32_t iReloc = 0; iReloc < cChunkRelocs; iReloc++)
3372 {
3373 /* Get the OMF and ELF data for the symbol the reloc references. */
3374 uint32_t const uType = ELF64_R_TYPE(paRelocs[iReloc].r_info);
3375 uint32_t const iSymbol = ELF64_R_SYM(paRelocs[iReloc].r_info);
3376 Elf64_Sym const * const pElfSym = &paSymbols[iSymbol];
3377 POMFSYMBOL const pOmfSym = &pThis->paSymbols[iSymbol];
3378 const char * const pszSymName = &pElfStuff->pchStrTab[pElfSym->st_name];
3379
3380 /* Calc fixup location in the pending chunk and setup a flexible pointer to it. */
3381 uint16_t offDataRec = (uint16_t)(paRelocs[iReloc].r_offset - off);
3382 RTPTRUNION uLoc;
3383 uLoc.pu8 = &pbCopy[offDataRec];
3384
3385 /* OMF fixup data initialized with typical defaults. */
3386 bool fSelfRel = true;
3387 uint8_t bLocation = OMF_FIX_LOC_32BIT_OFFSET;
3388 uint8_t bFrame = OMF_FIX_F_GRPDEF;
3389 uint16_t idxFrame = pThis->idxGrpFlat;
3390 uint8_t bTarget;
3391 uint16_t idxTarget;
3392 bool fTargetDisp;
3393 uint32_t offTargetDisp;
3394 switch (pOmfSym->enmType)
3395 {
3396 case OMFSYMTYPE_INTERNAL:
3397 case OMFSYMTYPE_PUBDEF:
3398 bTarget = OMF_FIX_T_SEGDEF;
3399 idxTarget = pOmfSym->idxSegDef;
3400 fTargetDisp = true;
3401 offTargetDisp = pElfSym->st_value;
3402 break;
3403
3404 case OMFSYMTYPE_SEGDEF:
3405 bTarget = OMF_FIX_T_SEGDEF_NO_DISP;
3406 idxTarget = pOmfSym->idxSegDef;
3407 fTargetDisp = false;
3408 offTargetDisp = 0;
3409 break;
3410
3411 case OMFSYMTYPE_EXTDEF:
3412 bTarget = OMF_FIX_T_EXTDEF_NO_DISP;
3413 idxTarget = pOmfSym->idx;
3414 fTargetDisp = false;
3415 offTargetDisp = 0;
3416 break;
3417
3418 default:
3419 return error(pThis->pszSrc, "Relocation in segment #%u '%s' references ignored or invalid symbol (%s)\n",
3420 i, pszSegNm, pszSymName);
3421 }
3422
3423 /* Do COFF relocation type conversion. */
3424 switch (uType)
3425 {
3426 case R_X86_64_64:
3427 {
3428 int64_t iAddend = paRelocs[iReloc].r_addend;
3429 if (iAddend > _1G || iAddend < -_1G)
3430 fRet = error(pThis->pszSrc, "R_X86_64_64 with large addend (%" ELF_FMT_D64 ") at %#x in segment #%u '%s'\n",
3431 iAddend, paRelocs[iReloc].r_offset, i, pszSegNm);
3432 *uLoc.pu64 = iAddend;
3433 fSelfRel = false;
3434 break;
3435 }
3436
3437 case R_X86_64_32:
3438 case R_X86_64_32S: /* signed, unsigned, whatever. */
3439 fSelfRel = false;
3440 /* fall thru */
3441 case R_X86_64_PC32:
3442 {
3443 /* defaults are ok, just handle the addend. */
3444 int32_t iAddend = paRelocs[iReloc].r_addend;
3445 if (iAddend != paRelocs[iReloc].r_addend)
3446 fRet = error(pThis->pszSrc, "R_X86_64_PC32 with large addend (%d) at %#x in segment #%u '%s'\n",
3447 iAddend, paRelocs[iReloc].r_offset, i, pszSegNm);
3448 *uLoc.pu32 = iAddend;
3449 break;
3450 }
3451
3452 case R_X86_64_NONE:
3453 continue; /* Ignore this one */
3454
3455 case R_X86_64_GOT32:
3456 case R_X86_64_PLT32:
3457 case R_X86_64_COPY:
3458 case R_X86_64_GLOB_DAT:
3459 case R_X86_64_JMP_SLOT:
3460 case R_X86_64_RELATIVE:
3461 case R_X86_64_GOTPCREL:
3462 case R_X86_64_16:
3463 case R_X86_64_PC16:
3464 case R_X86_64_8:
3465 case R_X86_64_PC8:
3466 case R_X86_64_DTPMOD64:
3467 case R_X86_64_DTPOFF64:
3468 case R_X86_64_TPOFF64:
3469 case R_X86_64_TLSGD:
3470 case R_X86_64_TLSLD:
3471 case R_X86_64_DTPOFF32:
3472 case R_X86_64_GOTTPOFF:
3473 case R_X86_64_TPOFF32:
3474 default:
3475 return error(pThis->pszSrc, "Unsupported fixup type %#x (%s) at rva=%#x in section #%u '%s' against '%s'\n",
3476 uType, g_apszElfAmd64RelTypes[uType], paRelocs[iReloc].r_offset, i, pszSegNm, pszSymName);
3477 }
3478
3479 /* Add the fixup. */
3480 if (idxFrame == UINT16_MAX)
3481 error(pThis->pszSrc, "idxFrame=UINT16_MAX for %s type=%s\n", pszSymName, g_apszElfAmd64RelTypes[uType]);
3482 fRet = omfWriter_LEDataAddFixup(pThis, offDataRec, fSelfRel, bLocation, bFrame, idxFrame,
3483 bTarget, idxTarget, fTargetDisp, offTargetDisp) && fRet;
3484 }
3485
3486 /*
3487 * Write the LEDATA and associated FIXUPPs.
3488 */
3489 if (!omfWriter_LEDataEnd(pThis))
3490 return false;
3491
3492 /*
3493 * Advance.
3494 */
3495 paRelocs += cChunkRelocs;
3496 cRelocs -= cChunkRelocs;
3497 if (cbData > cbChunk)
3498 {
3499 cbData -= cbChunk;
3500 pbData += cbChunk;
3501 }
3502 else
3503 cbData = 0;
3504 off += cbChunk;
3505 cbVirtData -= cbChunk;
3506 }
3507 }
3508
3509 return fRet;
3510}
3511
3512
3513static bool convertMachoToOmf(const char *pszFile, uint8_t const *pbFile, size_t cbFile, FILE *pDst)
3514{
3515 /*
3516 * Validate the source file a little.
3517 */
3518 ELFDETAILS ElfStuff;
3519 if (!validateElf(pszFile, pbFile, cbFile, &ElfStuff))
3520 return false;
3521
3522 /*
3523 * Instantiate the OMF writer.
3524 */
3525 POMFWRITER pThis = omfWriter_Create(pszFile, ElfStuff.pEhdr->e_shnum, ElfStuff.cSymbols, pDst);
3526 if (!pThis)
3527 return false;
3528
3529 /*
3530 * Write the OMF object file.
3531 */
3532 if (omfWriter_BeginModule(pThis, pszFile))
3533 {
3534 Elf64_Ehdr const *pEhdr = (Elf64_Ehdr const *)pbFile;
3535 Elf64_Shdr const *paShdrs = (Elf64_Shdr const *)&pbFile[pEhdr->e_shoff];
3536 const char *pszStrTab = (const char *)&pbFile[paShdrs[pEhdr->e_shstrndx].sh_offset];
3537
3538 if ( convertElfSectionsToSegDefsAndGrpDefs(pThis, &ElfStuff)
3539 && convertElfSymbolsToPubDefsAndExtDefs(pThis, &ElfStuff)
3540 && omfWriter_LinkPassSeparator(pThis)
3541 && convertElfSectionsToLeDataAndFixupps(pThis, &ElfStuff, pbFile, cbFile)
3542 && omfWriter_EndModule(pThis) )
3543 {
3544
3545 omfWriter_Destroy(pThis);
3546 return true;
3547 }
3548 }
3549
3550 omfWriter_Destroy(pThis);
3551 return false;
3552}
3553
3554#endif /* !MACHO_TO_OMF_CONVERSION */
3555
3556
3557/*********************************************************************************************************************************
3558* OMF Converter/Tweaker *
3559*********************************************************************************************************************************/
3560
3561/** Watcom intrinsics we need to modify so we can mix 32-bit and 16-bit
3562 * code, since the 16 and 32 bit compilers share several names.
3563 * The names are length prefixed.
3564 */
3565static const char * const g_apszExtDefRenames[] =
3566{
3567 "\x05" "__I4D",
3568 "\x05" "__I4M",
3569 "\x05" "__I8D",
3570 "\x06" "__I8DQ",
3571 "\x07" "__I8DQE",
3572 "\x06" "__I8DR",
3573 "\x07" "__I8DRE",
3574 "\x06" "__I8LS",
3575 "\x05" "__I8M",
3576 "\x06" "__I8ME",
3577 "\x06" "__I8RS",
3578 "\x05" "__PIA",
3579 "\x05" "__PIS",
3580 "\x05" "__PTC",
3581 "\x05" "__PTS",
3582 "\x05" "__U4D",
3583 "\x05" "__U4M",
3584 "\x05" "__U8D",
3585 "\x06" "__U8DQ",
3586 "\x07" "__U8DQE",
3587 "\x06" "__U8DR",
3588 "\x07" "__U8DRE",
3589 "\x06" "__U8LS",
3590 "\x05" "__U8M",
3591 "\x06" "__U8ME",
3592 "\x06" "__U8RS",
3593};
3594
3595/**
3596 * Records line number information for a file in a segment (for CV8 debug info).
3597 */
3598typedef struct OMFFILELINES
3599{
3600 /** The source info offset. */
3601 uint32_t offSrcInfo;
3602 /** Number of line/offset pairs. */
3603 uint32_t cPairs;
3604 /** Number of pairs allocated. */
3605 uint32_t cPairsAlloc;
3606 /** Table with line number and offset pairs, ordered by offset. */
3607 PRTCV8LINEPAIR paPairs;
3608} OMFFILEINES;
3609typedef OMFFILEINES *POMFFILEINES;
3610
3611/**
3612 * Records line number information for a segment (for CV8 debug info).
3613 */
3614typedef struct OMFSEGLINES
3615{
3616 /** Number of files. */
3617 uint32_t cFiles;
3618 /** Number of bytes we need. */
3619 uint32_t cb;
3620 /** The segment index. */
3621 uint16_t idxSeg;
3622 /** File table. */
3623 POMFFILEINES paFiles;
3624} OMFSEGLINES;
3625typedef OMFSEGLINES *POMFSEGLINES;
3626
3627/**
3628 * OMF conversion details.
3629 *
3630 * Keeps information relevant to the conversion and CV8 debug info.
3631 */
3632typedef struct OMFDETAILS
3633{
3634 /** Set if it has line numbers. */
3635 bool fLineNumbers;
3636 /** Set if we think this may be a 32-bit OMF file. */
3637 bool fProbably32bit;
3638 /** Set if this module may need mangling. */
3639 bool fMayNeedMangling;
3640 /** Number of SEGDEFs records. */
3641 uint32_t cSegDefs;
3642 /** The LNAME index of '$$SYMBOLS' or UINT16_MAX it not found. */
3643 uint16_t iSymbolsNm;
3644 /** The LNAME index of 'DEBSYM' or UINT16_MAX it not found. */
3645 uint16_t iDebSymNm;
3646 /** The '$$SYMBOLS' segment index. */
3647 uint16_t iSymbolsSeg;
3648
3649 /** CV8: Filename string table size. */
3650 uint32_t cbStrTab;
3651 /** CV8: Filename string table allocation size (always multiple of dword,
3652 * zero initialized). */
3653 uint32_t cbStrTabAlloc;
3654 /** CV8: Filename String table. */
3655 char *pchStrTab;
3656 /** CV8: Elements in the source info table. */
3657 uint16_t cSrcInfo;
3658 /** CV8: Source info table. */
3659 PRTCV8SRCINFO paSrcInfo;
3660
3661 /** Number of entries in the paSegLines table. */
3662 uint32_t cSegLines;
3663 /** Segment line numbers, indexed by segment number. */
3664 POMFSEGLINES paSegLines;
3665} OMFDETAILS;
3666typedef OMFDETAILS *POMFDETAILS;
3667typedef OMFDETAILS const *PCOMFDETAILS;
3668
3669
3670/**
3671 * Adds a line number to the CV8 debug info.
3672 *
3673 * @returns success indicator.
3674 * @param pOmfStuff Where to collect CV8 debug info.
3675 * @param cchSrcFile The length of the source file name.
3676 * @param pchSrcFile The source file name, not terminated.
3677 * @param poffFile Where to return the source file information table
3678 * offset (for use in the line number tables).
3679 */
3680static bool collectOmfAddFile(POMFDETAILS pOmfStuff, uint8_t cchSrcFile, const char *pchSrcFile, uint32_t *poffFile)
3681{
3682 /*
3683 * Do lookup first.
3684 */
3685 uint32_t i = pOmfStuff->cSrcInfo;
3686 while (i-- > 0)
3687 {
3688 const char *pszCur = &pOmfStuff->pchStrTab[pOmfStuff->paSrcInfo[i].offSourceName];
3689 if ( strncmp(pszCur, pchSrcFile, cchSrcFile) == 0
3690 && pszCur[cchSrcFile] == '\0')
3691 {
3692 *poffFile = i * sizeof(pOmfStuff->paSrcInfo[0]);
3693 return true;
3694 }
3695 }
3696
3697 /*
3698 * Add it to the string table (dword aligned and zero padded).
3699 */
3700 uint32_t offSrcTab = pOmfStuff->cbStrTab;
3701 if (offSrcTab + cchSrcFile + 1 > pOmfStuff->cbStrTabAlloc)
3702 {
3703 uint32_t cbNew = (offSrcTab == 0) + offSrcTab + cchSrcFile + 1;
3704 cbNew = RT_ALIGN(cbNew, 256);
3705 void *pvNew = realloc(pOmfStuff->pchStrTab, cbNew);
3706 if (!pvNew)
3707 return error("???", "out of memory");
3708 pOmfStuff->pchStrTab = (char *)pvNew;
3709 pOmfStuff->cbStrTabAlloc = cbNew;
3710 memset(&pOmfStuff->pchStrTab[offSrcTab], 0, cbNew - offSrcTab);
3711
3712 if (!offSrcTab)
3713 offSrcTab++;
3714 }
3715
3716 memcpy(&pOmfStuff->pchStrTab[offSrcTab], pchSrcFile, cchSrcFile);
3717 pOmfStuff->pchStrTab[offSrcTab + cchSrcFile] = '\0';
3718 pOmfStuff->cbStrTab = offSrcTab + cchSrcFile + 1;
3719
3720 /*
3721 * Add it to the filename info table.
3722 */
3723 if ((pOmfStuff->cSrcInfo % 8) == 0)
3724 {
3725 void *pvNew = realloc(pOmfStuff->paSrcInfo, sizeof(pOmfStuff->paSrcInfo[0]) * (pOmfStuff->cSrcInfo + 8));
3726 if (!pvNew)
3727 return error("???", "out of memory");
3728 pOmfStuff->paSrcInfo = (PRTCV8SRCINFO)pvNew;
3729 }
3730
3731 PRTCV8SRCINFO pSrcInfo = &pOmfStuff->paSrcInfo[pOmfStuff->cSrcInfo++];
3732 pSrcInfo->offSourceName = offSrcTab;
3733 pSrcInfo->uDigestType = RTCV8SRCINFO_DIGEST_TYPE_MD5;
3734 memset(&pSrcInfo->Digest, 0, sizeof(pSrcInfo->Digest));
3735
3736 *poffFile = (uint32_t)((uintptr_t)pSrcInfo - (uintptr_t)pOmfStuff->paSrcInfo);
3737 return true;
3738}
3739
3740
3741/**
3742 * Adds a line number to the CV8 debug info.
3743 *
3744 * @returns success indicator.
3745 * @param pOmfStuff Where to collect CV8 debug info.
3746 * @param idxSeg The segment index.
3747 * @param off The segment offset.
3748 * @param uLine The line number.
3749 * @param offSrcInfo The source file info table offset.
3750 */
3751static bool collectOmfAddLine(POMFDETAILS pOmfStuff, uint16_t idxSeg, uint32_t off, uint16_t uLine, uint32_t offSrcInfo)
3752{
3753 /*
3754 * Get/add the segment line structure.
3755 */
3756 if (idxSeg >= pOmfStuff->cSegLines)
3757 {
3758 void *pvNew = realloc(pOmfStuff->paSegLines, (idxSeg + 1) * sizeof(pOmfStuff->paSegLines[0]));
3759 if (!pvNew)
3760 return error("???", "out of memory");
3761 pOmfStuff->paSegLines = (POMFSEGLINES)pvNew;
3762
3763 memset(&pOmfStuff->paSegLines[pOmfStuff->cSegLines], 0,
3764 (idxSeg + 1 - pOmfStuff->cSegLines) * sizeof(pOmfStuff->paSegLines[0]));
3765 for (uint32_t i = pOmfStuff->cSegLines; i <= idxSeg; i++)
3766 {
3767 pOmfStuff->paSegLines[i].idxSeg = i;
3768 pOmfStuff->paSegLines[i].cb = sizeof(RTCV8LINESHDR);
3769 }
3770 pOmfStuff->cSegLines = idxSeg + 1;
3771 }
3772 POMFSEGLINES pSegLines = &pOmfStuff->paSegLines[idxSeg];
3773
3774 /*
3775 * Get/add the file structure with the segment.
3776 */
3777 POMFFILEINES pFileLines = NULL;
3778 uint32_t i = pSegLines->cFiles;
3779 while (i-- > 0)
3780 if (pSegLines->paFiles[i].offSrcInfo == offSrcInfo)
3781 {
3782 pFileLines = &pSegLines->paFiles[i];
3783 break;
3784 }
3785 if (!pFileLines)
3786 {
3787 i = pSegLines->cFiles;
3788 if ((i % 4) == 0)
3789 {
3790 void *pvNew = realloc(pSegLines->paFiles, (i + 4) * sizeof(pSegLines->paFiles[0]));
3791 if (!pvNew)
3792 return error("???", "out of memory");
3793 pSegLines->paFiles = (POMFFILEINES)pvNew;
3794 }
3795
3796 pSegLines->cFiles = i + 1;
3797 pSegLines->cb += sizeof(RTCV8LINESSRCMAP);
3798
3799 pFileLines = &pSegLines->paFiles[i];
3800 pFileLines->offSrcInfo = offSrcInfo;
3801 pFileLines->cPairs = 0;
3802 pFileLines->cPairsAlloc = 0;
3803 pFileLines->paPairs = NULL;
3804 }
3805
3806 /*
3807 * Add the line number (sorted, duplicates removed).
3808 */
3809 if (pFileLines->cPairs + 1 > pFileLines->cPairsAlloc)
3810 {
3811 void *pvNew = realloc(pFileLines->paPairs, (pFileLines->cPairsAlloc + 16) * sizeof(pFileLines->paPairs[0]));
3812 if (!pvNew)
3813 return error("???", "out of memory");
3814 pFileLines->paPairs = (PRTCV8LINEPAIR)pvNew;
3815 pFileLines->cPairsAlloc += 16;
3816 }
3817
3818 i = pFileLines->cPairs;
3819 while (i > 0 && ( off < pFileLines->paPairs[i - 1].offSection
3820 || ( off == pFileLines->paPairs[i - 1].offSection
3821 && uLine < pFileLines->paPairs[i - 1].uLineNumber)) )
3822 i--;
3823 if ( i == pFileLines->cPairs
3824 || off != pFileLines->paPairs[i].offSection
3825 || uLine != pFileLines->paPairs[i].uLineNumber)
3826 {
3827 if (i < pFileLines->cPairs)
3828 memmove(&pFileLines->paPairs[i + 1], &pFileLines->paPairs[i],
3829 (pFileLines->cPairs - i) * sizeof(pFileLines->paPairs));
3830 pFileLines->paPairs[i].offSection = off;
3831 pFileLines->paPairs[i].uLineNumber = uLine;
3832 pFileLines->paPairs[i].fEndOfStatement = true;
3833 pFileLines->cPairs++;
3834 pSegLines->cb += sizeof(pFileLines->paPairs[0]);
3835 }
3836
3837 return true;
3838}
3839
3840
3841/**
3842 * Parses OMF file gathering line numbers (for CV8 debug info) and checking out
3843 * external defintions for mangling work (compiler instrinsics).
3844 *
3845 * @returns success indicator.
3846 * @param pszFile The name of the OMF file.
3847 * @param pbFile The file content.
3848 * @param cbFile The size of the file content.
3849 * @param pOmfStuff Where to collect CV8 debug info and anything else we
3850 * find out about the OMF file.
3851 */
3852static bool collectOmfDetails(const char *pszFile, uint8_t const *pbFile, size_t cbFile, POMFDETAILS pOmfStuff)
3853{
3854 uint32_t cLNames = 0;
3855 uint32_t cExtDefs = 0;
3856 uint32_t cPubDefs = 0;
3857 uint32_t off = 0;
3858 uint8_t cchSrcFile = 0;
3859 const char *pchSrcFile = NULL;
3860 uint32_t offSrcInfo = UINT32_MAX;
3861
3862 memset(pOmfStuff, 0, sizeof(*pOmfStuff));
3863 pOmfStuff->iDebSymNm = UINT16_MAX;
3864 pOmfStuff->iSymbolsNm = UINT16_MAX;
3865 pOmfStuff->iSymbolsSeg = UINT16_MAX;
3866
3867 while (off + 3 < cbFile)
3868 {
3869 uint8_t bRecType = pbFile[off];
3870 uint16_t cbRec = RT_MAKE_U16(pbFile[off + 1], pbFile[off + 2]);
3871 if (g_cVerbose > 2)
3872 printf( "%#07x: type=%#04x len=%#06x\n", off, bRecType, cbRec);
3873 if (off + cbRec > cbFile)
3874 return error(pszFile, "Invalid record length at %#x: %#x (cbFile=%#lx)\n", off, cbRec, (unsigned long)cbFile);
3875
3876 uint32_t offRec = 0;
3877 uint8_t const *pbRec = &pbFile[off + 3];
3878#define OMF_CHECK_RET(a_cbReq, a_Name) /* Not taking the checksum into account, so we're good with 1 or 2 byte fields. */ \
3879 if (offRec + (a_cbReq) <= cbRec) {/*likely*/} \
3880 else return error(pszFile, "Malformed " #a_Name "! off=%#x offRec=%#x cbRec=%#x cbNeeded=%#x line=%d\n", \
3881 off, offRec, cbRec, (a_cbReq), __LINE__)
3882#define OMF_READ_IDX(a_idx, a_Name) \
3883 do { \
3884 OMF_CHECK_RET(2, a_Name); \
3885 a_idx = pbRec[offRec++]; \
3886 if ((a_idx) & 0x80) \
3887 a_idx = (((a_idx) & 0x7f) << 8) | pbRec[offRec++]; \
3888 } while (0)
3889
3890 switch (bRecType)
3891 {
3892 /*
3893 * Record LNAME records, scanning for FLAT.
3894 */
3895 case OMF_LNAMES:
3896 while (offRec + 1 < cbRec)
3897 {
3898 uint8_t cch = pbRec[offRec];
3899 if (offRec + 1 + cch >= cbRec)
3900 return error(pszFile, "Invalid LNAME string length at %#x+3+%#x: %#x (cbFile=%#lx)\n",
3901 off, offRec, cch, (unsigned long)cbFile);
3902
3903 cLNames++;
3904 if (g_cVerbose > 2)
3905 printf(" LNAME[%u]: %-*.*s\n", cLNames, cch, cch, &pbRec[offRec + 1]);
3906
3907 if (cch == 4 && memcmp(&pbRec[offRec + 1], "FLAT", 4) == 0)
3908 pOmfStuff->fProbably32bit = true;
3909
3910 if ( cch == 6
3911 && pOmfStuff->iDebSymNm == UINT16_MAX
3912 && memcmp(&pbRec[offRec + 1], "DEBSYM", 6) == 0)
3913 pOmfStuff->iDebSymNm = cLNames;
3914 if ( cch == 9
3915 && pOmfStuff->iSymbolsNm == UINT16_MAX
3916 && memcmp(&pbRec[offRec + 1], "$$SYMBOLS", 9) == 0)
3917 pOmfStuff->iSymbolsNm = cLNames;
3918
3919 offRec += cch + 1;
3920 }
3921 break;
3922
3923 /*
3924 * Display external defitions if -v is specified, also check if anything needs mangling.
3925 */
3926 case OMF_EXTDEF:
3927 while (offRec + 1 < cbRec)
3928 {
3929 uint8_t cch = pbRec[offRec++];
3930 OMF_CHECK_RET(cch, EXTDEF);
3931 char *pchName = (char *)&pbRec[offRec];
3932 offRec += cch;
3933
3934 uint16_t idxType;
3935 OMF_READ_IDX(idxType, EXTDEF);
3936
3937 if (g_cVerbose > 2)
3938 printf(" EXTDEF [%u]: %-*.*s type=%#x\n", cExtDefs, cch, cch, pchName, idxType);
3939 else if (g_cVerbose > 0)
3940 printf(" U %-*.*s\n", cch, cch, pchName);
3941
3942 /* Look for g_apszExtDefRenames entries that requires changing. */
3943 if ( !pOmfStuff->fMayNeedMangling
3944 && cch >= 5
3945 && cch <= 7
3946 && pchName[0] == '_'
3947 && pchName[1] == '_'
3948 && ( pchName[2] == 'U'
3949 || pchName[2] == 'I'
3950 || pchName[2] == 'P')
3951 && ( pchName[3] == '4'
3952 || pchName[3] == '8'
3953 || pchName[3] == 'I'
3954 || pchName[3] == 'T') )
3955 {
3956 pOmfStuff->fMayNeedMangling = true;
3957 }
3958 }
3959 break;
3960
3961 /*
3962 * Display public names if -v is specified.
3963 */
3964 case OMF_PUBDEF32:
3965 case OMF_LPUBDEF32:
3966 pOmfStuff->fProbably32bit = true;
3967 case OMF_PUBDEF16:
3968 case OMF_LPUBDEF16:
3969 if (g_cVerbose > 0)
3970 {
3971 char const chType = bRecType == OMF_PUBDEF16 || bRecType == OMF_PUBDEF32 ? 'T' : 't';
3972 const char *pszRec = "LPUBDEF";
3973 if (chType == 'T')
3974 pszRec++;
3975
3976 uint16_t idxGrp;
3977 OMF_READ_IDX(idxGrp, [L]PUBDEF);
3978
3979 uint16_t idxSeg;
3980 OMF_READ_IDX(idxSeg, [L]PUBDEF);
3981
3982 uint16_t uFrameBase = 0;
3983 if (idxSeg == 0)
3984 {
3985 OMF_CHECK_RET(2, [L]PUBDEF);
3986 uFrameBase = RT_MAKE_U16(pbRec[offRec], pbRec[offRec + 1]);
3987 offRec += 2;
3988 }
3989 if (g_cVerbose > 2)
3990 printf(" %s: idxGrp=%#x idxSeg=%#x uFrameBase=%#x\n", pszRec, idxGrp, idxSeg, uFrameBase);
3991 uint16_t const uSeg = idxSeg ? idxSeg : uFrameBase;
3992
3993 while (offRec + 1 < cbRec)
3994 {
3995 uint8_t cch = pbRec[offRec++];
3996 OMF_CHECK_RET(cch, [L]PUBDEF);
3997 const char *pchName = (const char *)&pbRec[offRec];
3998 offRec += cch;
3999
4000 uint32_t offSeg;
4001 if (bRecType & OMF_REC32)
4002 {
4003 OMF_CHECK_RET(4, [L]PUBDEF);
4004 offSeg = RT_MAKE_U32_FROM_U8(pbRec[offRec], pbRec[offRec + 1], pbRec[offRec + 2], pbRec[offRec + 3]);
4005 offRec += 4;
4006 }
4007 else
4008 {
4009 OMF_CHECK_RET(2, [L]PUBDEF);
4010 offSeg = RT_MAKE_U16(pbRec[offRec], pbRec[offRec + 1]);
4011 offRec += 2;
4012 }
4013
4014 uint16_t idxType;
4015 OMF_READ_IDX(idxType, [L]PUBDEF);
4016
4017 if (g_cVerbose > 2)
4018 printf(" %s[%u]: off=%#010x type=%#x %-*.*s\n", pszRec, cPubDefs, offSeg, idxType, cch, cch, pchName);
4019 else if (g_cVerbose > 0)
4020 printf("%04x:%08x %c %-*.*s\n", uSeg, offSeg, chType, cch, cch, pchName);
4021 }
4022 }
4023 break;
4024
4025 /*
4026 * Must count segment defitions to figure the index of our segment.
4027 */
4028 case OMF_SEGDEF16:
4029 case OMF_SEGDEF32:
4030 pOmfStuff->cSegDefs++;
4031 break;
4032
4033 /*
4034 * Gather file names.
4035 */
4036 case OMF_THEADR: /* watcom */
4037 cchSrcFile = pbRec[offRec++];
4038 OMF_CHECK_RET(cchSrcFile, OMF_THEADR);
4039 pchSrcFile = (const char *)&pbRec[offRec];
4040 if (!collectOmfAddFile(pOmfStuff, cchSrcFile, pchSrcFile, &offSrcInfo))
4041 return false;
4042 break;
4043
4044 case OMF_COMENT:
4045 {
4046 OMF_CHECK_RET(2, COMENT);
4047 offRec++; /* skip the type (flags) */
4048 uint8_t bClass = pbRec[offRec++];
4049 if (bClass == OMF_CCLS_BORLAND_SRC_FILE) /* nasm */
4050 {
4051 OMF_CHECK_RET(1+1+4, BORLAND_SRC_FILE);
4052 offRec++; /* skip unknown byte */
4053 cchSrcFile = pbRec[offRec++];
4054 OMF_CHECK_RET(cchSrcFile + 4, BORLAND_SRC_FILE);
4055 pchSrcFile = (const char *)&pbRec[offRec];
4056 offRec += cchSrcFile;
4057 if (offRec + 4 + 1 != cbRec)
4058 return error(pszFile, "BAD BORLAND_SRC_FILE record at %#x: %d bytes left\n",
4059 off, cbRec - offRec - 4 - 1);
4060 if (!collectOmfAddFile(pOmfStuff, cchSrcFile, pchSrcFile, &offSrcInfo))
4061 return false;
4062 break;
4063 }
4064 break;
4065 }
4066
4067 /*
4068 * Line number conversion.
4069 */
4070 case OMF_LINNUM16:
4071 case OMF_LINNUM32:
4072 {
4073 uint16_t idxGrp;
4074 OMF_READ_IDX(idxGrp, LINNUM);
4075 uint16_t idxSeg;
4076 OMF_READ_IDX(idxSeg, LINNUM);
4077
4078 uint16_t iLine;
4079 uint32_t offSeg;
4080 if (bRecType == OMF_LINNUM16)
4081 while (offRec + 4 < cbRec)
4082 {
4083 iLine = RT_MAKE_U16(pbRec[offRec + 0], pbRec[offRec + 1]);
4084 offSeg = RT_MAKE_U16(pbRec[offRec + 2], pbRec[offRec + 3]);
4085 if (!collectOmfAddLine(pOmfStuff, idxSeg, offSeg, iLine, offSrcInfo))
4086 return false;
4087 offRec += 4;
4088 }
4089 else
4090 while (offRec + 6 < cbRec)
4091 {
4092 iLine = RT_MAKE_U16(pbRec[offRec + 0], pbRec[offRec + 1]);
4093 offSeg = RT_MAKE_U32_FROM_U8(pbRec[offRec + 2], pbRec[offRec + 3], pbRec[offRec + 4], pbRec[offRec + 5]);
4094 if (!collectOmfAddLine(pOmfStuff, idxSeg, offSeg, iLine, offSrcInfo))
4095 return false;
4096 offRec += 6;
4097 }
4098 if (offRec + 1 != cbRec)
4099 return error(pszFile, "BAD LINNUM record at %#x: %d bytes left\n", off, cbRec - offRec - 1);
4100 break;
4101 }
4102 }
4103
4104 /* advance */
4105 off += cbRec + 3;
4106 }
4107
4108 return true;
4109#undef OMF_READ_IDX
4110#undef OMF_CHECK_RET
4111}
4112
4113
4114/**
4115 * Writes the debug segment definitions (names too).
4116 *
4117 * @returns success indicator.
4118 * @param pThis The OMF writer.
4119 * @param pOmfStuff The OMF stuff with CV8 line number info.
4120 */
4121static bool convertOmfWriteDebugSegDefs(POMFWRITER pThis, POMFDETAILS pOmfStuff)
4122{
4123 if ( pOmfStuff->cSegLines == 0
4124 || pOmfStuff->iSymbolsSeg != UINT16_MAX)
4125 return true;
4126
4127 /*
4128 * Emit the LNAMES we need.
4129 */
4130#if 1
4131 if ( pOmfStuff->iSymbolsNm == UINT16_MAX
4132 || pOmfStuff->iDebSymNm == UINT16_MAX)
4133 {
4134 if ( !omfWriter_LNamesBegin(pThis, true /*fAddZeroEntry*/)
4135 || ( pOmfStuff->iSymbolsNm == UINT16_MAX
4136 && !omfWriter_LNamesAdd(pThis, "$$SYMBOLS", &pOmfStuff->iSymbolsNm))
4137 || ( pOmfStuff->iDebSymNm == UINT16_MAX
4138 && !omfWriter_LNamesAdd(pThis, "DEBSYM", &pOmfStuff->iDebSymNm))
4139 || !omfWriter_LNamesEnd(pThis) )
4140 return false;
4141 }
4142#else
4143 if ( !omfWriter_LNamesBegin(pThis, true /*fAddZeroEntry*/)
4144 || !omfWriter_LNamesAdd(pThis, "$$SYMBOLS2", &pOmfStuff->iSymbolsNm)
4145 || !omfWriter_LNamesAdd(pThis, "DEBSYM2", &pOmfStuff->iDebSymNm)
4146 || !omfWriter_LNamesEnd(pThis) )
4147 return false;
4148#endif
4149
4150 /*
4151 * Emit the segment defitions.
4152 */
4153 pOmfStuff->iSymbolsSeg = ++pOmfStuff->cSegDefs;
4154
4155 uint8_t bSegAttr = 0;
4156 bSegAttr |= 5 << 5; /* A: dword alignment */
4157 bSegAttr |= 0 << 2; /* C: private */
4158 bSegAttr |= 0 << 1; /* B: not big */
4159 bSegAttr |= 1; /* D: use32 */
4160
4161 /* calc the segment size. */
4162 uint32_t cbSeg = 4; /* dword 4 */
4163 cbSeg += 4 + 4 + RT_ALIGN_32(pOmfStuff->cbStrTab, 4);
4164 cbSeg += 4 + 4 + pOmfStuff->cSrcInfo * sizeof(pOmfStuff->paSrcInfo[0]);
4165 uint32_t i = pOmfStuff->cSegLines;
4166 while (i-- > 0)
4167 if (pOmfStuff->paSegLines[i].cFiles > 0)
4168 cbSeg += 4 + 4 + pOmfStuff->paSegLines[i].cb;
4169 return omfWriter_SegDef(pThis, bSegAttr, cbSeg, pOmfStuff->iSymbolsNm, pOmfStuff->iDebSymNm);
4170}
4171
4172
4173/**
4174 * Writes the debug segment data.
4175 *
4176 * @returns success indicator.
4177 * @param pThis The OMF writer.
4178 * @param pOmfStuff The OMF stuff with CV8 line number info.
4179 */
4180static bool convertOmfWriteDebugData(POMFWRITER pThis, POMFDETAILS pOmfStuff)
4181{
4182 if (pOmfStuff->cSegLines == 0)
4183 return true;
4184
4185 /* Begin and write the CV version signature. */
4186 uint32_t const cbMaxChunk = RT_ALIGN(OMF_MAX_RECORD_PAYLOAD - 1 - 16, 4); /* keep the data dword aligned */
4187 if ( !omfWriter_LEDataBegin(pThis, pOmfStuff->iSymbolsSeg, 0)
4188 || !omfWriter_LEDataAddU32(pThis, RTCVSYMBOLS_SIGNATURE_CV8))
4189 return false;
4190
4191 /*
4192 * Emit the string table (no fixups).
4193 */
4194 uint32_t cbLeft = pOmfStuff->cbStrTab;
4195 if ( !omfWriter_LEDataAddU32(pThis, RTCV8SYMBLOCK_TYPE_SRC_STR)
4196 || !omfWriter_LEDataAddU32(pThis, cbLeft)
4197 || !omfWriter_LEDataAddBytes(pThis, pOmfStuff->pchStrTab, RT_ALIGN_32(cbLeft, 4)) ) /* table is zero padded to nearest dword */
4198 return false;
4199
4200 /*
4201 * Emit the source file info table (no fixups).
4202 */
4203 cbLeft = pOmfStuff->cSrcInfo * sizeof(pOmfStuff->paSrcInfo[0]);
4204 if ( !omfWriter_LEDataAddU32(pThis, RTCV8SYMBLOCK_TYPE_SRC_INFO)
4205 || !omfWriter_LEDataAddU32(pThis, cbLeft)
4206 || !omfWriter_LEDataAddBytes(pThis, pOmfStuff->paSrcInfo, cbLeft) )
4207 return false;
4208
4209 /*
4210 * Emit the segment line numbers. There are two fixups here at the start
4211 * of each chunk.
4212 */
4213 POMFSEGLINES pSegLines = pOmfStuff->paSegLines;
4214 uint32_t i = pOmfStuff->cSegLines;
4215 while (i-- > 0)
4216 {
4217 if (pSegLines->cFiles)
4218 {
4219 /* Calc covered area. */
4220 uint32_t cbSectionCovered = 0;
4221 uint32_t j = pSegLines->cFiles;
4222 while (j-- > 0)
4223 {
4224 uint32_t offLast = pSegLines->paFiles[j].paPairs[pSegLines->paFiles[j].cPairs - 1].offSection;
4225 if (offLast > cbSectionCovered)
4226 offLast = cbSectionCovered;
4227 }
4228
4229 /* For simplicity and debuggability, just split the LEDATA here. */
4230 if ( !omfWriter_LEDataSplit(pThis)
4231 || !omfWriter_LEDataAddU32(pThis, RTCV8SYMBLOCK_TYPE_SECT_LINES)
4232 || !omfWriter_LEDataAddU32(pThis, pSegLines->cb)
4233 || !omfWriter_LEDataAddU32(pThis, 0) /*RTCV8LINESHDR::offSection*/
4234 || !omfWriter_LEDataAddU16(pThis, 0) /*RTCV8LINESHDR::iSection*/
4235 || !omfWriter_LEDataAddU16(pThis, 0) /*RTCV8LINESHDR::u16Padding*/
4236 || !omfWriter_LEDataAddU32(pThis, cbSectionCovered) /*RTCV8LINESHDR::cbSectionCovered*/ )
4237 return false;
4238
4239 /* Fixup #1: segment offset - IMAGE_REL_AMD64_SECREL. */
4240 if (!omfWriter_LEDataAddFixupNoDisp(pThis, 4 + 4 + RT_OFFSETOF(RTCV8LINESHDR, offSection), OMF_FIX_LOC_32BIT_OFFSET,
4241 OMF_FIX_F_SEGDEF, pSegLines->idxSeg,
4242 OMF_FIX_T_SEGDEF_NO_DISP, pSegLines->idxSeg))
4243 return false;
4244
4245
4246 /* Fixup #2: segment number - IMAGE_REL_AMD64_SECTION. */
4247 if (!omfWriter_LEDataAddFixupNoDisp(pThis, 4 + 4 + RT_OFFSETOF(RTCV8LINESHDR, iSection), OMF_FIX_LOC_16BIT_SEGMENT,
4248 OMF_FIX_F_SEGDEF, pSegLines->idxSeg,
4249 OMF_FIX_T_SEGDEF_NO_DISP, pSegLines->idxSeg))
4250 return false;
4251
4252 /* Emit data for each source file. */
4253 for (j = 0; j < pSegLines->cFiles; j++)
4254 {
4255 uint32_t const cbPairs = pSegLines->paFiles[j].cPairs * sizeof(RTCV8LINEPAIR);
4256 if ( !omfWriter_LEDataAddU32(pThis, pSegLines->paFiles[j].offSrcInfo) /*RTCV8LINESSRCMAP::offSourceInfo*/
4257 || !omfWriter_LEDataAddU32(pThis, pSegLines->paFiles[j].cPairs) /*RTCV8LINESSRCMAP::cLines*/
4258 || !omfWriter_LEDataAddU32(pThis, cbPairs + sizeof(RTCV8LINESSRCMAP)) /*RTCV8LINESSRCMAP::cb*/
4259 || !omfWriter_LEDataAddBytes(pThis, pSegLines->paFiles[j].paPairs, cbPairs))
4260 return false;
4261 }
4262 }
4263 pSegLines++;
4264 }
4265
4266 return omfWriter_LEDataEnd(pThis);
4267}
4268
4269
4270/**
4271 * This does the actual converting, passthru style.
4272 *
4273 * It only modifies, removes and inserts stuff it care about, the rest is passed
4274 * thru as-is.
4275 *
4276 * @returns success indicator.
4277 * @param pThis The OMF writer.
4278 * @param pbFile The original file content.
4279 * @param cbFile The size of the original file.
4280 * @param pOmfStuff The OMF stuff we've gathered during the first pass,
4281 * contains CV8 line number info if we converted anything.
4282 */
4283static bool convertOmfPassthru(POMFWRITER pThis, uint8_t const *pbFile, size_t cbFile, POMFDETAILS pOmfStuff)
4284{
4285 bool const fConvertLineNumbers = true;
4286 bool fSeenTheAdr = false;
4287 uint32_t off = 0;
4288 while (off + 3 < cbFile)
4289 {
4290 uint8_t bRecType = pbFile[off];
4291 uint16_t cbRec = RT_MAKE_U16(pbFile[off + 1], pbFile[off + 2]);
4292 uint32_t offRec = 0;
4293 uint8_t const *pbRec = &pbFile[off + 3];
4294
4295#define OMF_READ_IDX(a_idx, a_Name) \
4296 do { \
4297 a_idx = pbRec[offRec++]; \
4298 if ((a_idx) & 0x80) \
4299 a_idx = (((a_idx) & 0x7f) << 8) | pbRec[offRec++]; \
4300 } while (0)
4301
4302 /*
4303 * Remove/insert switch. will
4304 */
4305 bool fSkip = false;
4306 switch (bRecType)
4307 {
4308 /*
4309 * Mangle watcom intrinsics if necessary.
4310 */
4311 case OMF_EXTDEF:
4312 if (pOmfStuff->fMayNeedMangling)
4313 {
4314 if (!omfWriter_ExtDefBegin(pThis))
4315 return false;
4316 while (offRec + 1 < cbRec)
4317 {
4318 uint8_t cchName = pbRec[offRec++];
4319 char *pchName = (char *)&pbRec[offRec];
4320 offRec += cchName;
4321
4322 uint16_t idxType;
4323 OMF_READ_IDX(idxType, EXTDEF);
4324
4325 /* Look for g_apszExtDefRenames entries that requires changing. */
4326 if ( cchName >= 5
4327 && cchName <= 7
4328 && pchName[0] == '_'
4329 && pchName[1] == '_'
4330 && ( pchName[2] == 'U'
4331 || pchName[2] == 'I'
4332 || pchName[2] == 'P')
4333 && ( pchName[3] == '4'
4334 || pchName[3] == '8'
4335 || pchName[3] == 'I'
4336 || pchName[3] == 'T') )
4337 {
4338 char szName[12];
4339 memcpy(szName, pchName, cchName);
4340 szName[cchName] = '\0';
4341
4342 uint32_t i = RT_ELEMENTS(g_apszExtDefRenames);
4343 while (i-- > 0)
4344 if ( cchName == (uint8_t)g_apszExtDefRenames[i][0]
4345 && memcmp(&g_apszExtDefRenames[i][1], szName, cchName) == 0)
4346 {
4347 szName[0] = pOmfStuff->fProbably32bit ? '?' : '_';
4348 szName[1] = '?';
4349 break;
4350 }
4351
4352 if (!omfWriter_ExtDefAddN(pThis, szName, cchName, idxType))
4353 return false;
4354 }
4355 else if (!omfWriter_ExtDefAddN(pThis, pchName, cchName, idxType))
4356 return false;
4357 }
4358 if (!omfWriter_ExtDefEnd(pThis))
4359 return false;
4360 fSkip = true;
4361 }
4362 break;
4363
4364 /*
4365 * Remove line number records.
4366 */
4367 case OMF_LINNUM16:
4368 case OMF_LINNUM32:
4369 fSkip = fConvertLineNumbers;
4370 break;
4371
4372 /*
4373 * Remove all but the first OMF_THEADR.
4374 */
4375 case OMF_THEADR:
4376 fSkip = fSeenTheAdr && fConvertLineNumbers;
4377 fSeenTheAdr = true;
4378 break;
4379
4380 /*
4381 * Remove borland source file changes. Also, emit our SEGDEF
4382 * before the pass marker.
4383 */
4384 case OMF_COMENT:
4385 if (fConvertLineNumbers)
4386 {
4387 fSkip = pbRec[1] == OMF_CCLS_BORLAND_SRC_FILE;
4388 if (pbRec[1] == OMF_CCLS_LINK_PASS_SEP)
4389 if (!convertOmfWriteDebugSegDefs(pThis, pOmfStuff))
4390 return false;
4391 }
4392 break;
4393
4394 /*
4395 * Redo these to the OMF writer is on top of the index thing.
4396 */
4397 case OMF_LNAMES:
4398 if (!omfWriter_LNamesBegin(pThis, false /*fAddZeroEntry*/))
4399 return false;
4400 while (offRec + 1 < cbRec)
4401 {
4402 uint8_t cch = pbRec[offRec];
4403 const char *pch = (const char *)&pbRec[offRec + 1];
4404 if (!omfWriter_LNamesAddN(pThis, pch, cch, NULL))
4405 return false;
4406 offRec += cch + 1;
4407 }
4408 if (!omfWriter_LNamesEnd(pThis))
4409 return false;
4410
4411 fSkip = true;
4412 break;
4413
4414 /*
4415 * Upon seeing MODEND we write out the debug info.
4416 */
4417 case OMF_MODEND16:
4418 case OMF_MODEND32:
4419 if (fConvertLineNumbers)
4420 {
4421 if ( convertOmfWriteDebugSegDefs(pThis, pOmfStuff)
4422 && convertOmfWriteDebugData(pThis, pOmfStuff))
4423 { /* likely */ }
4424 else return false;
4425 }
4426 break;
4427 }
4428
4429 /*
4430 * Pass the record thru, if so was decided.
4431 */
4432 if (!fSkip)
4433 {
4434 if ( omfWriter_RecBegin(pThis, bRecType)
4435 && omfWriter_RecAddBytes(pThis, pbRec, cbRec)
4436 && omfWriter_RecEnd(pThis, false))
4437 { /* likely */ }
4438 else return false;
4439 }
4440
4441 /* advance */
4442 off += cbRec + 3;
4443 }
4444
4445 return true;
4446}
4447
4448
4449/**
4450 * Converts LINNUMs and compiler intrinsics in an OMF object file.
4451 *
4452 * Wlink does a cheesy (to use their own term) job of generating the
4453 * sstSrcModule subsection. It is limited to one file and cannot deal with line
4454 * numbers in different segment. The latter is very annoying in assembly files
4455 * that jumps between segments, these a frequent on crash stacks.
4456 *
4457 * The solution is to convert to the same line number tables that cl.exe /Z7
4458 * generates for our 64-bit C code, we named that format codeview v8, or CV8.
4459 * Our code codeview debug info reader can deal with this already because of the
4460 * 64-bit code, so Bob's your uncle.
4461 *
4462 * @returns success indicator.
4463 * @param pszFile The name of the file being converted.
4464 * @param pbFile The file content.
4465 * @param cbFile The size of the file content.
4466 * @param pDst The destiation (output) file.
4467 */
4468static bool convertOmfToOmf(const char *pszFile, uint8_t const *pbFile, size_t cbFile, FILE *pDst)
4469{
4470 /*
4471 * Collect line number information.
4472 */
4473 OMFDETAILS OmfStuff;
4474 if (!collectOmfDetails(pszFile, pbFile, cbFile, &OmfStuff))
4475 return false;
4476
4477 /*
4478 * Instantiate the OMF writer and do pass-thru modifications.
4479 */
4480 bool fRc;
4481 POMFWRITER pThis = omfWriter_Create(pszFile, 0, 0, pDst);
4482 if (pThis)
4483 {
4484 fRc = convertOmfPassthru(pThis, pbFile, cbFile, &OmfStuff);
4485 omfWriter_Destroy(pThis);
4486 }
4487 else
4488 fRc = false;
4489
4490
4491 /*
4492 * Cleanup OmfStuff.
4493 */
4494 uint32_t i = OmfStuff.cSegLines;
4495 while (i-- >0)
4496 {
4497 uint32_t j = OmfStuff.paSegLines[i].cFiles;
4498 while (j-- > 0)
4499 free(OmfStuff.paSegLines[i].paFiles[j].paPairs);
4500 free(OmfStuff.paSegLines[i].paFiles);
4501 }
4502 free(OmfStuff.paSegLines);
4503 free(OmfStuff.paSrcInfo);
4504 free(OmfStuff.pchStrTab);
4505 return fRc;
4506}
4507
4508
4509/**
4510 * Does the convertion using convertelf and convertcoff.
4511 *
4512 * @returns exit code (0 on success, non-zero on failure)
4513 * @param pszFile The file to convert.
4514 */
4515static int convertit(const char *pszFile)
4516{
4517 /* Construct the filename for saving the unmodified file. */
4518 char szOrgFile[_4K];
4519 size_t cchFile = strlen(pszFile);
4520 if (cchFile + sizeof(".original") > sizeof(szOrgFile))
4521 {
4522 error(pszFile, "Filename too long!\n");
4523 return RTEXITCODE_FAILURE;
4524 }
4525 memcpy(szOrgFile, pszFile, cchFile);
4526 memcpy(&szOrgFile[cchFile], ".original", sizeof(".original"));
4527
4528 /* Read the whole file. */
4529 void *pvFile;
4530 size_t cbFile;
4531 if (readfile(pszFile, &pvFile, &cbFile))
4532 {
4533 /*
4534 * Do format conversions / adjustments.
4535 */
4536 bool fRc = false;
4537 uint8_t *pbFile = (uint8_t *)pvFile;
4538 if ( cbFile > sizeof(Elf64_Ehdr)
4539 && pbFile[0] == ELFMAG0
4540 && pbFile[1] == ELFMAG1
4541 && pbFile[2] == ELFMAG2
4542 && pbFile[3] == ELFMAG3)
4543 {
4544 if (writefile(szOrgFile, pvFile, cbFile))
4545 {
4546 FILE *pDst = openfile(pszFile, true /*fWrite*/);
4547 if (pDst)
4548 {
4549 fRc = convertElfToOmf(pszFile, pbFile, cbFile, pDst);
4550 fRc = fclose(pDst) == 0 && fRc;
4551 }
4552 }
4553 }
4554 else if ( cbFile > sizeof(IMAGE_FILE_HEADER)
4555 && RT_MAKE_U16(pbFile[0], pbFile[1]) == IMAGE_FILE_MACHINE_AMD64
4556 && RT_MAKE_U16(pbFile[2], pbFile[3]) * sizeof(IMAGE_SECTION_HEADER) + sizeof(IMAGE_FILE_HEADER)
4557 < cbFile
4558 && RT_MAKE_U16(pbFile[2], pbFile[3]) > 0)
4559 {
4560 if (writefile(szOrgFile, pvFile, cbFile))
4561 {
4562 FILE *pDst = openfile(pszFile, true /*fWrite*/);
4563 if (pDst)
4564 {
4565 fRc = convertCoffToOmf(pszFile, pbFile, cbFile, pDst);
4566 fRc = fclose(pDst) == 0 && fRc;
4567 }
4568 }
4569 }
4570 else if ( cbFile >= 8
4571 && pbFile[0] == OMF_THEADR
4572 && RT_MAKE_U16(pbFile[1], pbFile[2]) < cbFile)
4573 {
4574 if (writefile(szOrgFile, pvFile, cbFile))
4575 {
4576 FILE *pDst = openfile(pszFile, true /*fWrite*/);
4577 if (pDst)
4578 {
4579 fRc = convertOmfToOmf(pszFile, pbFile, cbFile, pDst);
4580 fRc = fclose(pDst) == 0 && fRc;
4581 }
4582 }
4583 }
4584 else
4585 fprintf(stderr, "error: Don't recognize format of '%s' (%#x %#x %#x %#x, cbFile=%lu)\n",
4586 pszFile, pbFile[0], pbFile[1], pbFile[2], pbFile[3], (unsigned long)cbFile);
4587 free(pvFile);
4588 if (fRc)
4589 return 0;
4590 }
4591 return 1;
4592}
4593
4594
4595int main(int argc, char **argv)
4596{
4597 int rcExit = 0;
4598
4599 /*
4600 * Scan the arguments.
4601 */
4602 for (int i = 1; i < argc; i++)
4603 {
4604 if (argv[i][0] == '-')
4605 {
4606 const char *pszOpt = &argv[i][1];
4607 if (*pszOpt == '-')
4608 {
4609 /* Convert long options to short ones. */
4610 pszOpt--;
4611 if (!strcmp(pszOpt, "--verbose"))
4612 pszOpt = "v";
4613 else if (!strcmp(pszOpt, "--version"))
4614 pszOpt = "V";
4615 else if (!strcmp(pszOpt, "--help"))
4616 pszOpt = "h";
4617 else
4618 {
4619 fprintf(stderr, "syntax errro: Unknown options '%s'\n", pszOpt);
4620 return 2;
4621 }
4622 }
4623
4624 /* Process the list of short options. */
4625 while (*pszOpt)
4626 {
4627 switch (*pszOpt++)
4628 {
4629 case 'v':
4630 g_cVerbose++;
4631 break;
4632
4633 case 'V':
4634 printf("%s\n", "$Revision: 60462 $");
4635 return 0;
4636
4637 case '?':
4638 case 'h':
4639 printf("usage: %s [options] -o <output> <input1> [input2 ... [inputN]]\n",
4640 argv[0]);
4641 return 0;
4642 }
4643 }
4644 }
4645 else
4646 {
4647 /*
4648 * File to convert. Do the job right away.
4649 */
4650 rcExit = convertit(argv[i]);
4651 if (rcExit != 0)
4652 break;
4653 }
4654 }
4655
4656 return rcExit;
4657}
4658
4659
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