VirtualBox

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

Last change on this file since 66182 was 65928, checked in by vboxsync, 8 years ago

Bs3Kit: Better converter error message.

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