VirtualBox

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

Last change on this file since 84794 was 84509, checked in by vboxsync, 5 years ago

iprt/cdefs.h,*: Introducing RT_FLEXIBLE_ARRAY_EXTENSION as a g++ hack that allows us to use RT_FLEXIBLE_ARRAY without the compiler going all pendantic on us. Only tested with 10.1.0. bugref:9746

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