VirtualBox

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

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

omfWriter_LEDataAddFixup: added missing flag in two byte indexes.

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