VirtualBox

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

Last change on this file since 79611 was 77823, checked in by vboxsync, 6 years ago

bs3kit/VBoxBs3ObjConverter: Drop IPRT dependency to reduce rebuild effort. The code only needed Assert() and RTSortShell, so local hacks for the former and include the source file for the latter. bugref:9344

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 211.1 KB
Line 
1/* $Id: VBoxBs3ObjConverter.cpp 77823 2019-03-21 12:20:13Z vboxsync $ */
2/** @file
3 * VirtualBox Validation Kit - Boot Sector 3 object file convert.
4 */
5
6/*
7 * Copyright (C) 2006-2019 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 {
2139 strcpy(szName, "BS3TEXT64");
2140 pThis->paSegments[i].iGrpNm = idxGrpFlat;
2141 pThis->paSegments[i].iClassNm = idxClassCode;
2142 }
2143 else if (strcmp(szName, ".data") == 0)
2144 {
2145 strcpy(szName, "BS3DATA64");
2146 pThis->paSegments[i].iGrpNm = idxGrpData;
2147 pThis->paSegments[i].iClassNm = idxClassData;
2148 }
2149 else if (strcmp(szName, ".bss") == 0)
2150 {
2151 strcpy(szName, "BS3BSS64");
2152 pThis->paSegments[i].iGrpNm = idxGrpData;
2153 pThis->paSegments[i].iClassNm = idxClassData;
2154 }
2155 else if (strcmp(szName, ".rdata") == 0)
2156 {
2157 strcpy(szName, "BS3DATA64CONST");
2158 pThis->paSegments[i].iGrpNm = idxGrpData;
2159 pThis->paSegments[i].iClassNm = idxClassData;
2160 }
2161 else if (strcmp(szName, ".debug$S") == 0)
2162 {
2163 strcpy(szName, "$$SYMBOLS");
2164 pThis->paSegments[i].iGrpNm = UINT16_MAX;
2165 pThis->paSegments[i].iClassNm = idxClassDebugSymbols;
2166 }
2167 else if (strcmp(szName, ".debug$T") == 0)
2168 {
2169 strcpy(szName, "$$TYPES");
2170 pThis->paSegments[i].iGrpNm = UINT16_MAX;
2171 pThis->paSegments[i].iClassNm = idxClassDebugTypes;
2172 }
2173 else if (paShdrs[i].Characteristics & (IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_CNT_CODE))
2174 {
2175 pThis->paSegments[i].iGrpNm = idxGrpFlat;
2176 pThis->paSegments[i].iClassNm = idxClassCode;
2177 error(pThis->pszSrc, "Unknown code segment: '%s'\n", szName);
2178 }
2179 else
2180 {
2181 pThis->paSegments[i].iGrpNm = idxGrpData;
2182 pThis->paSegments[i].iClassNm = idxClassData;
2183 error(pThis->pszSrc, "Unknown data (?) segment: '%s'\n", szName);
2184 }
2185
2186 /* Save the name. */
2187 pThis->paSegments[i].pszName = strdup(szName);
2188 if (!pThis->paSegments[i].pszName)
2189 return error(pThis->pszSrc, "Out of memory!\n");
2190
2191 /* Add the section name. */
2192 if (!omfWriter_LNamesAdd(pThis, pThis->paSegments[i].pszName, &pThis->paSegments[i].iSegNm))
2193 return false;
2194
2195 fHaveData |= pThis->paSegments[i].iGrpNm == idxGrpData;
2196 }
2197 }
2198
2199 if (!omfWriter_LNamesEnd(pThis))
2200 return false;
2201
2202 /*
2203 * Emit segment definitions.
2204 */
2205 uint16_t iSegDef = 1; /* Start counting at 1. */
2206 for (uint16_t i = 0; i < cSections; i++)
2207 {
2208 if (pThis->paSegments[i].iSegDef == UINT16_MAX)
2209 continue;
2210
2211 uint8_t bSegAttr = 0;
2212
2213 /* The A field. */
2214 switch (paShdrs[i].Characteristics & IMAGE_SCN_ALIGN_MASK)
2215 {
2216 default:
2217 case IMAGE_SCN_ALIGN_1BYTES:
2218 bSegAttr |= 1 << 5;
2219 break;
2220 case IMAGE_SCN_ALIGN_2BYTES:
2221 bSegAttr |= 2 << 5;
2222 break;
2223 case IMAGE_SCN_ALIGN_4BYTES:
2224 bSegAttr |= 5 << 5;
2225 break;
2226 case IMAGE_SCN_ALIGN_8BYTES:
2227 case IMAGE_SCN_ALIGN_16BYTES:
2228 bSegAttr |= 3 << 5;
2229 break;
2230 case IMAGE_SCN_ALIGN_32BYTES:
2231 case IMAGE_SCN_ALIGN_64BYTES:
2232 case IMAGE_SCN_ALIGN_128BYTES:
2233 case IMAGE_SCN_ALIGN_256BYTES:
2234 bSegAttr |= 4 << 5;
2235 break;
2236 case IMAGE_SCN_ALIGN_512BYTES:
2237 case IMAGE_SCN_ALIGN_1024BYTES:
2238 case IMAGE_SCN_ALIGN_2048BYTES:
2239 case IMAGE_SCN_ALIGN_4096BYTES:
2240 case IMAGE_SCN_ALIGN_8192BYTES:
2241 bSegAttr |= 6 << 5; /* page aligned, pharlabs extension. */
2242 break;
2243 }
2244
2245 /* The C field. */
2246 bSegAttr |= 2 << 2; /* public */
2247
2248 /* The B field. We don't have 4GB segments, so leave it as zero. */
2249
2250 /* The D field shall be set as we're doing USE32. */
2251 bSegAttr |= 1;
2252
2253
2254 /* Done. */
2255 if (!omfWriter_SegDef(pThis, bSegAttr, paShdrs[i].SizeOfRawData,
2256 pThis->paSegments[i].iSegNm,
2257 pThis->paSegments[i].iClassNm))
2258 return false;
2259 pThis->paSegments[i].iSegDef = iSegDef++;
2260 }
2261
2262 /*
2263 * Flat group definition (#1) - special, no members.
2264 */
2265 uint16_t iGrpDef = 1;
2266 if ( !omfWriter_GrpDefBegin(pThis, idxGrpFlat)
2267 || !omfWriter_GrpDefEnd(pThis))
2268 return false;
2269 for (uint16_t i = 0; i < cSections; i++)
2270 if (pThis->paSegments[i].iGrpNm == idxGrpFlat)
2271 pThis->paSegments[i].iGrpDef = iGrpDef;
2272 pThis->idxGrpFlat = iGrpDef++;
2273
2274 /*
2275 * Data group definition (#2).
2276 */
2277 /** @todo do we need to consider missing segments and ordering? */
2278 uint16_t cGrpNms = 0;
2279 uint16_t aiGrpNms[2] = { 0, 0 }; /* Shut up, GCC. */
2280 if (fHaveData)
2281 aiGrpNms[cGrpNms++] = idxGrpData;
2282 for (uint32_t iGrpNm = 0; iGrpNm < cGrpNms; iGrpNm++)
2283 {
2284 if (!omfWriter_GrpDefBegin(pThis, aiGrpNms[iGrpNm]))
2285 return false;
2286 for (uint16_t i = 0; i < cSections; i++)
2287 if (pThis->paSegments[i].iGrpNm == aiGrpNms[iGrpNm])
2288 {
2289 pThis->paSegments[i].iGrpDef = iGrpDef;
2290 if (!omfWriter_GrpDefAddSegDef(pThis, pThis->paSegments[i].iSegDef))
2291 return false;
2292 }
2293 if (!omfWriter_GrpDefEnd(pThis))
2294 return false;
2295 iGrpDef++;
2296 }
2297
2298 return true;
2299}
2300
2301/**
2302 * This is for matching STATIC symbols with value 0 against the section name,
2303 * to see if it's a section reference or symbol at offset 0 reference.
2304 *
2305 * @returns true / false.
2306 * @param pszSymbol The symbol name.
2307 * @param pachSectName8 The section name (8-bytes).
2308 */
2309static bool isCoffSymbolMatchingSectionName(const char *pszSymbol, uint8_t const pachSectName8[8])
2310{
2311 uint32_t off = 0;
2312 char ch;
2313 while (off < 8 && (ch = pszSymbol[off]) != '\0')
2314 {
2315 if (ch != pachSectName8[off])
2316 return false;
2317 off++;
2318 }
2319 while (off < 8)
2320 {
2321 if (!RT_C_IS_SPACE((ch = pachSectName8[off])))
2322 return ch == '\0';
2323 off++;
2324 }
2325 return true;
2326}
2327
2328static bool convertCoffSymbolsToPubDefsAndExtDefs(POMFWRITER pThis, PCIMAGE_SYMBOL paSymbols, uint16_t cSymbols,
2329 const char *pchStrTab, PCIMAGE_SECTION_HEADER paShdrs)
2330{
2331
2332 if (!cSymbols)
2333 return true;
2334 uint32_t const cbStrTab = *(uint32_t const *)pchStrTab;
2335 char szShort[16];
2336
2337 /*
2338 * Process the symbols the first.
2339 */
2340 uint32_t iSymImageBase = UINT32_MAX;
2341 uint32_t cAbsSyms = 0;
2342 uint32_t cExtSyms = 0;
2343 uint32_t cPubSyms = 0;
2344 for (uint32_t iSeg = 0; iSeg < pThis->cSegments; iSeg++)
2345 pThis->paSegments[iSeg].cPubDefs = 0;
2346
2347 for (uint16_t iSym = 0; iSym < cSymbols; iSym++)
2348 {
2349 const char *pszSymName = coffGetSymbolName(&paSymbols[iSym], pchStrTab, cbStrTab, szShort);
2350
2351 pThis->paSymbols[iSym].enmType = OMFSYMTYPE_IGNORED;
2352 pThis->paSymbols[iSym].idx = UINT16_MAX;
2353 pThis->paSymbols[iSym].idxSegDef = UINT16_MAX;
2354 pThis->paSymbols[iSym].idxGrpDef = UINT16_MAX;
2355
2356 int16_t const idxSection = paSymbols[iSym].SectionNumber;
2357 if ( (idxSection >= 1 && idxSection <= (int32_t)pThis->cSegments)
2358 || idxSection == IMAGE_SYM_ABSOLUTE)
2359 {
2360 switch (paSymbols[iSym].StorageClass)
2361 {
2362 case IMAGE_SYM_CLASS_EXTERNAL:
2363 if (idxSection != IMAGE_SYM_ABSOLUTE)
2364 {
2365 if (pThis->paSegments[idxSection - 1].iSegDef != UINT16_MAX)
2366 {
2367 pThis->paSymbols[iSym].enmType = OMFSYMTYPE_PUBDEF;
2368 pThis->paSymbols[iSym].idxSegDef = pThis->paSegments[idxSection - 1].iSegDef;
2369 pThis->paSymbols[iSym].idxGrpDef = pThis->paSegments[idxSection - 1].iGrpDef;
2370 pThis->paSegments[idxSection - 1].cPubDefs++;
2371 cPubSyms++;
2372 }
2373 }
2374 else
2375 {
2376 pThis->paSymbols[iSym].enmType = OMFSYMTYPE_PUBDEF;
2377 pThis->paSymbols[iSym].idxSegDef = 0;
2378 pThis->paSymbols[iSym].idxGrpDef = 0;
2379 cAbsSyms++;
2380 }
2381 break;
2382
2383 case IMAGE_SYM_CLASS_STATIC:
2384 if ( paSymbols[iSym].Value == 0
2385 && idxSection != IMAGE_SYM_ABSOLUTE
2386 && isCoffSymbolMatchingSectionName(pszSymName, paShdrs[idxSection - 1].Name) )
2387 {
2388 pThis->paSymbols[iSym].enmType = OMFSYMTYPE_SEGDEF;
2389 pThis->paSymbols[iSym].idxSegDef = pThis->paSegments[idxSection - 1].iSegDef;
2390 pThis->paSymbols[iSym].idxGrpDef = pThis->paSegments[idxSection - 1].iGrpDef;
2391 break;
2392 }
2393 RT_FALL_THRU();
2394
2395 case IMAGE_SYM_CLASS_END_OF_FUNCTION:
2396 case IMAGE_SYM_CLASS_AUTOMATIC:
2397 case IMAGE_SYM_CLASS_REGISTER:
2398 case IMAGE_SYM_CLASS_LABEL:
2399 case IMAGE_SYM_CLASS_MEMBER_OF_STRUCT:
2400 case IMAGE_SYM_CLASS_ARGUMENT:
2401 case IMAGE_SYM_CLASS_STRUCT_TAG:
2402 case IMAGE_SYM_CLASS_MEMBER_OF_UNION:
2403 case IMAGE_SYM_CLASS_UNION_TAG:
2404 case IMAGE_SYM_CLASS_TYPE_DEFINITION:
2405 case IMAGE_SYM_CLASS_ENUM_TAG:
2406 case IMAGE_SYM_CLASS_MEMBER_OF_ENUM:
2407 case IMAGE_SYM_CLASS_REGISTER_PARAM:
2408 case IMAGE_SYM_CLASS_BIT_FIELD:
2409 case IMAGE_SYM_CLASS_BLOCK:
2410 case IMAGE_SYM_CLASS_FUNCTION:
2411 case IMAGE_SYM_CLASS_END_OF_STRUCT:
2412 case IMAGE_SYM_CLASS_FILE:
2413 pThis->paSymbols[iSym].enmType = OMFSYMTYPE_INTERNAL;
2414 if (idxSection != IMAGE_SYM_ABSOLUTE)
2415 {
2416 pThis->paSymbols[iSym].idxSegDef = pThis->paSegments[idxSection - 1].iSegDef;
2417 pThis->paSymbols[iSym].idxGrpDef = pThis->paSegments[idxSection - 1].iGrpDef;
2418 }
2419 else
2420 {
2421 pThis->paSymbols[iSym].idxSegDef = 0;
2422 pThis->paSymbols[iSym].idxGrpDef = 0;
2423 }
2424 break;
2425
2426 case IMAGE_SYM_CLASS_SECTION:
2427 case IMAGE_SYM_CLASS_EXTERNAL_DEF:
2428 case IMAGE_SYM_CLASS_NULL:
2429 case IMAGE_SYM_CLASS_UNDEFINED_LABEL:
2430 case IMAGE_SYM_CLASS_UNDEFINED_STATIC:
2431 case IMAGE_SYM_CLASS_CLR_TOKEN:
2432 case IMAGE_SYM_CLASS_FAR_EXTERNAL:
2433 case IMAGE_SYM_CLASS_WEAK_EXTERNAL:
2434 return error(pThis->pszSrc, "Unsupported storage class value %#x for symbol #%u (%s)\n",
2435 paSymbols[iSym].StorageClass, iSym, pszSymName);
2436
2437 default:
2438 return error(pThis->pszSrc, "Unknown storage class value %#x for symbol #%u (%s)\n",
2439 paSymbols[iSym].StorageClass, iSym, pszSymName);
2440 }
2441 }
2442 else if (idxSection == IMAGE_SYM_UNDEFINED)
2443 {
2444 if ( paSymbols[iSym].StorageClass == IMAGE_SYM_CLASS_EXTERNAL
2445 || paSymbols[iSym].StorageClass == IMAGE_SYM_CLASS_EXTERNAL_DEF)
2446 {
2447 pThis->paSymbols[iSym].enmType = OMFSYMTYPE_EXTDEF;
2448 cExtSyms++;
2449 if (iSymImageBase == UINT32_MAX && strcmp(pszSymName, "__ImageBase") == 0)
2450 iSymImageBase = iSym;
2451 }
2452 else
2453 return error(pThis->pszSrc, "Unknown/unknown storage class value %#x for undefined symbol #%u (%s)\n",
2454 paSymbols[iSym].StorageClass, iSym, pszSymName);
2455 }
2456 else if (idxSection != IMAGE_SYM_DEBUG)
2457 return error(pThis->pszSrc, "Invalid section number %#x for symbol #%u (%s)\n", idxSection, iSym, pszSymName);
2458
2459 /* Skip AUX symbols. */
2460 uint8_t cAuxSyms = paSymbols[iSym].NumberOfAuxSymbols;
2461 while (cAuxSyms-- > 0)
2462 {
2463 iSym++;
2464 pThis->paSymbols[iSym].enmType = OMFSYMTYPE_INVALID;
2465 pThis->paSymbols[iSym].idx = UINT16_MAX;
2466 }
2467 }
2468
2469 /*
2470 * Emit the PUBDEFs the first time around (see order of records in TIS spec).
2471 */
2472 uint16_t idxPubDef = 1;
2473 if (cPubSyms)
2474 {
2475 for (uint32_t iSeg = 0; iSeg < pThis->cSegments; iSeg++)
2476 if (pThis->paSegments[iSeg].cPubDefs > 0)
2477 {
2478 uint16_t const idxSegDef = pThis->paSegments[iSeg].iSegDef;
2479 if (!omfWriter_PubDefBegin(pThis, pThis->paSegments[iSeg].iGrpDef, idxSegDef))
2480 return false;
2481 for (uint16_t iSym = 0; iSym < cSymbols; iSym++)
2482 if ( pThis->paSymbols[iSym].idxSegDef == idxSegDef
2483 && pThis->paSymbols[iSym].enmType == OMFSYMTYPE_PUBDEF)
2484 {
2485 /* Underscore prefix all symbols not already underscored or mangled. */
2486 const char *pszName = coffGetSymbolName(&paSymbols[iSym], pchStrTab, cbStrTab, szShort);
2487 if (!omfWriter_PubDefAdd(pThis, paSymbols[iSym].Value, pszName, pszName[0] != '_' && pszName[0] != '?'))
2488 return false;
2489 pThis->paSymbols[iSym].idx = idxPubDef++;
2490 }
2491 if (!omfWriter_PubDefEnd(pThis))
2492 return false;
2493 }
2494 }
2495
2496 if (cAbsSyms > 0)
2497 {
2498 if (!omfWriter_PubDefBegin(pThis, 0, 0))
2499 return false;
2500 for (uint16_t iSym = 0; iSym < cSymbols; iSym++)
2501 if ( pThis->paSymbols[iSym].idxSegDef == 0
2502 && pThis->paSymbols[iSym].enmType == OMFSYMTYPE_PUBDEF)
2503 {
2504 /* Underscore prefix all symbols not already underscored or mangled. */
2505 const char *pszName = coffGetSymbolName(&paSymbols[iSym], pchStrTab, cbStrTab, szShort);
2506 if (!omfWriter_PubDefAdd(pThis, paSymbols[iSym].Value, pszName, pszName[0] != '_' && pszName[0] != '?') )
2507 return false;
2508 pThis->paSymbols[iSym].idx = idxPubDef++;
2509 }
2510 if (!omfWriter_PubDefEnd(pThis))
2511 return false;
2512 }
2513
2514 /*
2515 * Go over the symbol table and emit external definition records.
2516 */
2517 if (!omfWriter_ExtDefBegin(pThis))
2518 return false;
2519 uint16_t idxExtDef = 1;
2520 for (uint16_t iSym = 0; iSym < cSymbols; iSym++)
2521 if (pThis->paSymbols[iSym].enmType == OMFSYMTYPE_EXTDEF)
2522 {
2523 /* Underscore prefix all symbols not already underscored or mangled. */
2524 const char *pszName = coffGetSymbolName(&paSymbols[iSym], pchStrTab, cbStrTab, szShort);
2525 if (!omfWriter_ExtDefAdd(pThis, pszName, pszName[0] != '_' && pszName[0] != '?'))
2526 return false;
2527 pThis->paSymbols[iSym].idx = idxExtDef++;
2528 }
2529
2530 /* Always add an __ImageBase reference, in case we need it to deal with ADDR32NB fixups. */
2531 /** @todo maybe we don't actually need this and could use FLAT instead? */
2532 if (iSymImageBase != UINT32_MAX)
2533 pThis->idxExtImageBase = pThis->paSymbols[iSymImageBase].idx;
2534 else if (omfWriter_ExtDefAdd(pThis, "__ImageBase", false /*fPrependUnderscore*/))
2535 pThis->idxExtImageBase = idxExtDef;
2536 else
2537 return false;
2538
2539 if (!omfWriter_ExtDefEnd(pThis))
2540 return false;
2541
2542 return true;
2543}
2544
2545
2546static bool convertCoffSectionsToLeDataAndFixupps(POMFWRITER pThis, uint8_t const *pbFile, size_t cbFile,
2547 PCIMAGE_SECTION_HEADER paShdrs, uint16_t cSections,
2548 PCIMAGE_SYMBOL paSymbols, uint16_t cSymbols, const char *pchStrTab)
2549{
2550 RT_NOREF_PV(cbFile);
2551 RT_NOREF_PV(cSections);
2552 RT_NOREF_PV(cSymbols);
2553
2554 uint32_t const cbStrTab = *(uint32_t const *)pchStrTab;
2555 bool fRet = true;
2556 for (uint32_t i = 0; i < pThis->cSegments; i++)
2557 {
2558 if (pThis->paSegments[i].iSegDef == UINT16_MAX)
2559 continue;
2560
2561 char szShortName[16];
2562 const char *pszSegNm = pThis->paSegments[i].pszName;
2563 uint16_t cRelocs = paShdrs[i].NumberOfRelocations;
2564 PCIMAGE_RELOCATION paRelocs = (PCIMAGE_RELOCATION)&pbFile[paShdrs[i].PointerToRelocations];
2565 uint32_t cbVirtData = paShdrs[i].SizeOfRawData;
2566 uint32_t cbData = paShdrs[i].Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA ? 0 : cbVirtData;
2567 uint8_t const *pbData = &pbFile[paShdrs[i].PointerToRawData];
2568 uint32_t off = 0;
2569
2570 /* Check that the relocations are sorted and within the section. */
2571 for (uint32_t iReloc = 1; iReloc < cRelocs; iReloc++)
2572 if (paRelocs[iReloc - 1].u.VirtualAddress >= paRelocs[iReloc].u.VirtualAddress)
2573 return error(pThis->pszSrc, "Section #%u (%s) relocations aren't sorted\n", i, pszSegNm);
2574 if ( cRelocs > 0
2575 && paRelocs[cRelocs - 1].u.VirtualAddress - paShdrs[i].VirtualAddress
2576 + COFF_AMD64_RELOC_SIZE(paRelocs[cRelocs - 1].Type) > cbVirtData)
2577 return error(pThis->pszSrc,
2578 "Section #%u (%s) relocations beyond section data! cbVirtData=%#x RvaFix=%#x RVASeg=%#x type=%#x\n",
2579 i, pszSegNm, cbVirtData, paRelocs[cRelocs - 1].u.VirtualAddress, paShdrs[i].VirtualAddress,
2580 paRelocs[cRelocs - 1].Type);
2581
2582 /* The OMF record size requires us to split larger sections up. To make
2583 life simple, we fill zeros for unitialized (BSS) stuff. */
2584 const uint32_t cbMaxData = RT_MIN(OMF_MAX_RECORD_PAYLOAD - 1 - (pThis->paSegments[i].iSegDef >= 128) - 4 - 1, _1K);
2585 while (cbVirtData > 0)
2586 {
2587 /* Figure out how many bytes to put out in this chunk. Must make sure
2588 fixups doesn't cross chunk boundraries. ASSUMES sorted relocs. */
2589 uint32_t cChunkRelocs = cRelocs;
2590 uint32_t cbChunk = cbVirtData;
2591 uint32_t uRvaEnd = paShdrs[i].VirtualAddress + off + cbChunk;
2592 if (cbChunk > cbMaxData)
2593 {
2594 cbChunk = cbMaxData;
2595 uRvaEnd = paShdrs[i].VirtualAddress + off + cbChunk;
2596 cChunkRelocs = 0;
2597
2598 /* Quickly determin the reloc range. */
2599 while ( cChunkRelocs < cRelocs
2600 && paRelocs[cChunkRelocs].u.VirtualAddress < uRvaEnd)
2601 cChunkRelocs++;
2602
2603 /* Ensure final reloc doesn't go beyond chunk. */
2604 while ( cChunkRelocs > 0
2605 && paRelocs[cChunkRelocs - 1].u.VirtualAddress + COFF_AMD64_RELOC_SIZE(paRelocs[cChunkRelocs - 1].Type)
2606 > uRvaEnd)
2607 {
2608 uint32_t cbDrop = uRvaEnd - paRelocs[cChunkRelocs - 1].u.VirtualAddress;
2609 cbChunk -= cbDrop;
2610 uRvaEnd -= cbDrop;
2611 cChunkRelocs--;
2612 }
2613
2614 if (!cbVirtData)
2615 return error(pThis->pszSrc, "Wtf? cbVirtData is zero!\n");
2616 }
2617
2618 /*
2619 * We stash the bytes into the OMF writer record buffer, receiving a
2620 * pointer to the start of it so we can make adjustments if necessary.
2621 */
2622 uint8_t *pbCopy;
2623 if (!omfWriter_LEDataBeginEx(pThis, pThis->paSegments[i].iSegDef, off, cbChunk, cbData, pbData, &pbCopy))
2624 return false;
2625
2626 /*
2627 * Convert fiuxps.
2628 */
2629 uint32_t const uRvaChunk = paShdrs[i].VirtualAddress + off;
2630 for (uint32_t iReloc = 0; iReloc < cChunkRelocs; iReloc++)
2631 {
2632 /* Get the OMF and COFF data for the symbol the reloc references. */
2633 if (paRelocs[iReloc].SymbolTableIndex >= pThis->cSymbols)
2634 return error(pThis->pszSrc, "Relocation symtab index (%#x) is out of range in segment #%u '%s'\n",
2635 paRelocs[iReloc].SymbolTableIndex, i, pszSegNm);
2636 PCIMAGE_SYMBOL pCoffSym = &paSymbols[paRelocs[iReloc].SymbolTableIndex];
2637 POMFSYMBOL pOmfSym = &pThis->paSymbols[paRelocs[iReloc].SymbolTableIndex];
2638
2639 /* Calc fixup location in the pending chunk and setup a flexible pointer to it. */
2640 uint16_t offDataRec = (uint16_t)(paRelocs[iReloc].u.VirtualAddress - uRvaChunk);
2641 RTPTRUNION uLoc;
2642 uLoc.pu8 = &pbCopy[offDataRec];
2643
2644 /* OMF fixup data initialized with typical defaults. */
2645 bool fSelfRel = true;
2646 uint8_t bLocation = OMF_FIX_LOC_32BIT_OFFSET;
2647 uint8_t bFrame = OMF_FIX_F_GRPDEF;
2648 uint16_t idxFrame = pThis->idxGrpFlat;
2649 uint8_t bTarget;
2650 uint16_t idxTarget;
2651 bool fTargetDisp;
2652 uint32_t offTargetDisp;
2653 switch (pOmfSym->enmType)
2654 {
2655 case OMFSYMTYPE_INTERNAL:
2656 case OMFSYMTYPE_PUBDEF:
2657 bTarget = OMF_FIX_T_SEGDEF;
2658 idxTarget = pOmfSym->idxSegDef;
2659 fTargetDisp = true;
2660 offTargetDisp = pCoffSym->Value;
2661 break;
2662
2663 case OMFSYMTYPE_SEGDEF:
2664 bTarget = OMF_FIX_T_SEGDEF_NO_DISP;
2665 idxTarget = pOmfSym->idxSegDef;
2666 fTargetDisp = false;
2667 offTargetDisp = 0;
2668 break;
2669
2670 case OMFSYMTYPE_EXTDEF:
2671 bTarget = OMF_FIX_T_EXTDEF_NO_DISP;
2672 idxTarget = pOmfSym->idx;
2673 fTargetDisp = false;
2674 offTargetDisp = 0;
2675 break;
2676
2677 default:
2678 return error(pThis->pszSrc, "Relocation in segment #%u '%s' references ignored or invalid symbol (%s)\n",
2679 i, pszSegNm, coffGetSymbolName(pCoffSym, pchStrTab, cbStrTab, szShortName));
2680 }
2681
2682 /* Do COFF relocation type conversion. */
2683 switch (paRelocs[iReloc].Type)
2684 {
2685 case IMAGE_REL_AMD64_ADDR64:
2686 {
2687 uint64_t uAddend = *uLoc.pu64;
2688 if (uAddend > _1G)
2689 fRet = error(pThis->pszSrc, "ADDR64 with large addend (%#llx) at %#x in segment #%u '%s'\n",
2690 uAddend, paRelocs[iReloc].u.VirtualAddress, i, pszSegNm);
2691 fSelfRel = false;
2692 break;
2693 }
2694
2695 case IMAGE_REL_AMD64_REL32_1:
2696 case IMAGE_REL_AMD64_REL32_2:
2697 case IMAGE_REL_AMD64_REL32_3:
2698 case IMAGE_REL_AMD64_REL32_4:
2699 case IMAGE_REL_AMD64_REL32_5:
2700 /** @todo Check whether OMF read addends from the data or relies on the
2701 * displacement. Also, check what it's relative to. */
2702 *uLoc.pu32 -= paRelocs[iReloc].Type - IMAGE_REL_AMD64_REL32;
2703 break;
2704
2705 case IMAGE_REL_AMD64_ADDR32:
2706 fSelfRel = false;
2707 break;
2708
2709 case IMAGE_REL_AMD64_ADDR32NB:
2710 fSelfRel = false;
2711 bFrame = OMF_FIX_F_EXTDEF;
2712 idxFrame = pThis->idxExtImageBase;
2713 break;
2714
2715 case IMAGE_REL_AMD64_REL32:
2716 /* defaults are ok. */
2717 break;
2718
2719 case IMAGE_REL_AMD64_SECTION:
2720 bLocation = OMF_FIX_LOC_16BIT_SEGMENT;
2721 RT_FALL_THRU();
2722
2723 case IMAGE_REL_AMD64_SECREL:
2724 fSelfRel = false;
2725 if (pOmfSym->enmType == OMFSYMTYPE_EXTDEF)
2726 {
2727 bFrame = OMF_FIX_F_EXTDEF;
2728 idxFrame = pOmfSym->idx;
2729 }
2730 else
2731 {
2732 bFrame = OMF_FIX_F_SEGDEF;
2733 idxFrame = pOmfSym->idxSegDef;
2734 }
2735 break;
2736
2737 case IMAGE_REL_AMD64_ABSOLUTE:
2738 continue; /* Ignore it like the PECOFF.DOC says we should. */
2739
2740 case IMAGE_REL_AMD64_SECREL7:
2741 default:
2742 return error(pThis->pszSrc, "Unsupported fixup type %#x (%s) at rva=%#x in section #%u '%-8.8s'\n",
2743 paRelocs[iReloc].Type,
2744 paRelocs[iReloc].Type < RT_ELEMENTS(g_apszCoffAmd64RelTypes)
2745 ? g_apszCoffAmd64RelTypes[paRelocs[iReloc].Type] : "unknown",
2746 paRelocs[iReloc].u.VirtualAddress, i, paShdrs[i].Name);
2747 }
2748
2749 /* Add the fixup. */
2750 if (idxFrame == UINT16_MAX)
2751 error(pThis->pszSrc, "idxFrame=UINT16_MAX for %s type=%s\n",
2752 coffGetSymbolName(pCoffSym, pchStrTab, cbStrTab, szShortName),
2753 g_apszCoffAmd64RelTypes[paRelocs[iReloc].Type]);
2754 fRet = omfWriter_LEDataAddFixup(pThis, offDataRec, fSelfRel, bLocation, bFrame, idxFrame,
2755 bTarget, idxTarget, fTargetDisp, offTargetDisp) && fRet;
2756 }
2757
2758 /*
2759 * Write the LEDATA and associated FIXUPPs.
2760 */
2761 if (!omfWriter_LEDataEnd(pThis))
2762 return false;
2763
2764 /*
2765 * Advance.
2766 */
2767 paRelocs += cChunkRelocs;
2768 cRelocs -= cChunkRelocs;
2769 if (cbData > cbChunk)
2770 {
2771 cbData -= cbChunk;
2772 pbData += cbChunk;
2773 }
2774 else
2775 cbData = 0;
2776 off += cbChunk;
2777 cbVirtData -= cbChunk;
2778 }
2779 }
2780
2781 return fRet;
2782}
2783
2784
2785static bool convertCoffToOmf(const char *pszFile, uint8_t const *pbFile, size_t cbFile, FILE *pDst)
2786{
2787 /*
2788 * Validate the source file a little.
2789 */
2790 if (!validateCoff(pszFile, pbFile, cbFile))
2791 return false;
2792
2793 /*
2794 * Instantiate the OMF writer.
2795 */
2796 PIMAGE_FILE_HEADER pHdr = (PIMAGE_FILE_HEADER)pbFile;
2797 POMFWRITER pThis = omfWriter_Create(pszFile, pHdr->NumberOfSections, pHdr->NumberOfSymbols, pDst);
2798 if (!pThis)
2799 return false;
2800
2801 /*
2802 * Write the OMF object file.
2803 */
2804 if (omfWriter_BeginModule(pThis, pszFile))
2805 {
2806 PCIMAGE_SECTION_HEADER paShdrs = (PCIMAGE_SECTION_HEADER)(pHdr + 1);
2807 PCIMAGE_SYMBOL paSymTab = (PCIMAGE_SYMBOL)&pbFile[pHdr->PointerToSymbolTable];
2808 const char *pchStrTab = (const char *)&paSymTab[pHdr->NumberOfSymbols];
2809 if ( convertCoffSectionsToSegDefsAndGrpDefs(pThis, paShdrs, pHdr->NumberOfSections)
2810 && convertCoffSymbolsToPubDefsAndExtDefs(pThis, paSymTab, pHdr->NumberOfSymbols, pchStrTab, paShdrs)
2811 && omfWriter_LinkPassSeparator(pThis)
2812 && convertCoffSectionsToLeDataAndFixupps(pThis, pbFile, cbFile, paShdrs, pHdr->NumberOfSections,
2813 paSymTab, pHdr->NumberOfSymbols, pchStrTab)
2814 && omfWriter_EndModule(pThis) )
2815 {
2816
2817 omfWriter_Destroy(pThis);
2818 return true;
2819 }
2820 }
2821
2822 omfWriter_Destroy(pThis);
2823 return false;
2824}
2825
2826
2827/*********************************************************************************************************************************
2828* Mach-O/AMD64 -> OMF/i386 Converter *
2829*********************************************************************************************************************************/
2830
2831//#define MACHO_TO_OMF_CONVERSION
2832#ifdef MACHO_TO_OMF_CONVERSION
2833
2834/** AMD64 relocation type names for Mach-O. */
2835static const char * const g_apszMachOAmd64RelTypes[] =
2836{
2837 "X86_64_RELOC_UNSIGNED",
2838 "X86_64_RELOC_SIGNED",
2839 "X86_64_RELOC_BRANCH",
2840 "X86_64_RELOC_GOT_LOAD",
2841 "X86_64_RELOC_GOT",
2842 "X86_64_RELOC_SUBTRACTOR",
2843 "X86_64_RELOC_SIGNED_1",
2844 "X86_64_RELOC_SIGNED_2",
2845 "X86_64_RELOC_SIGNED_4"
2846};
2847
2848/** AMD64 relocation type sizes for Mach-O. */
2849static uint8_t const g_acbMachOAmd64RelTypes[] =
2850{
2851 8, /* X86_64_RELOC_UNSIGNED */
2852 4, /* X86_64_RELOC_SIGNED */
2853 4, /* X86_64_RELOC_BRANCH */
2854 4, /* X86_64_RELOC_GOT_LOAD */
2855 4, /* X86_64_RELOC_GOT */
2856 8, /* X86_64_RELOC_SUBTRACTOR */
2857 4, /* X86_64_RELOC_SIGNED_1 */
2858 4, /* X86_64_RELOC_SIGNED_2 */
2859 4, /* X86_64_RELOC_SIGNED_4 */
2860};
2861
2862/** Macro for getting the size of a AMD64 Mach-O relocation. */
2863#define MACHO_AMD64_RELOC_SIZE(a_Type) ( (a_Type) < RT_ELEMENTS(g_acbMachOAmd64RelTypes) ? g_acbMachOAmd64RelTypes[(a_Type)] : 1)
2864
2865
2866typedef struct MACHODETAILS
2867{
2868 /** The ELF header. */
2869 Elf64_Ehdr const *pEhdr;
2870 /** The section header table. */
2871 Elf64_Shdr const *paShdrs;
2872 /** The string table for the section names. */
2873 const char *pchShStrTab;
2874
2875 /** The symbol table section number. UINT16_MAX if not found. */
2876 uint16_t iSymSh;
2877 /** The string table section number. UINT16_MAX if not found. */
2878 uint16_t iStrSh;
2879
2880 /** The symbol table. */
2881 Elf64_Sym const *paSymbols;
2882 /** The number of symbols in the symbol table. */
2883 uint32_t cSymbols;
2884
2885 /** Pointer to the (symbol) string table if found. */
2886 const char *pchStrTab;
2887 /** The string table size. */
2888 size_t cbStrTab;
2889
2890} MACHODETAILS;
2891typedef MACHODETAILS *PMACHODETAILS;
2892typedef MACHODETAILS const *PCMACHODETAILS;
2893
2894
2895static bool validateMacho(const char *pszFile, uint8_t const *pbFile, size_t cbFile, PMACHODETAILS pMachOStuff)
2896{
2897 /*
2898 * Initialize the Mach-O details structure.
2899 */
2900 memset(pMachOStuff, 0, sizeof(*pMachOStuff));
2901 pMachOStuff->iSymSh = UINT16_MAX;
2902 pMachOStuff->iStrSh = UINT16_MAX;
2903
2904 /*
2905 * Validate the header and our other expectations.
2906 */
2907 Elf64_Ehdr const *pEhdr = (Elf64_Ehdr const *)pbFile;
2908 pMachOStuff->pEhdr = pEhdr;
2909 if ( pEhdr->e_ident[EI_CLASS] != ELFCLASS64
2910 || pEhdr->e_ident[EI_DATA] != ELFDATA2LSB
2911 || pEhdr->e_ehsize != sizeof(Elf64_Ehdr)
2912 || pEhdr->e_shentsize != sizeof(Elf64_Shdr)
2913 || pEhdr->e_version != EV_CURRENT )
2914 return error(pszFile, "Unsupported ELF config\n");
2915 if (pEhdr->e_type != ET_REL)
2916 return error(pszFile, "Expected relocatable ELF file (e_type=%d)\n", pEhdr->e_type);
2917 if (pEhdr->e_machine != EM_X86_64)
2918 return error(pszFile, "Expected relocatable ELF file (e_type=%d)\n", pEhdr->e_machine);
2919 if (pEhdr->e_phnum != 0)
2920 return error(pszFile, "Expected e_phnum to be zero not %u\n", pEhdr->e_phnum);
2921 if (pEhdr->e_shnum < 2)
2922 return error(pszFile, "Expected e_shnum to be two or higher\n");
2923 if (pEhdr->e_shstrndx >= pEhdr->e_shnum || pEhdr->e_shstrndx == 0)
2924 return error(pszFile, "Bad e_shstrndx=%u (e_shnum=%u)\n", pEhdr->e_shstrndx, pEhdr->e_shnum);
2925 if ( pEhdr->e_shoff >= cbFile
2926 || pEhdr->e_shoff + pEhdr->e_shnum * sizeof(Elf64_Shdr) > cbFile)
2927 return error(pszFile, "Section table is outside the file (e_shoff=%#llx, e_shnum=%u, cbFile=%#llx)\n",
2928 pEhdr->e_shstrndx, pEhdr->e_shnum, (uint64_t)cbFile);
2929
2930 /*
2931 * Locate the section name string table.
2932 * We assume it's okay as we only reference it in verbose mode.
2933 */
2934 Elf64_Shdr const *paShdrs = (Elf64_Shdr const *)&pbFile[pEhdr->e_shoff];
2935 pMachOStuff->paShdrs = paShdrs;
2936
2937 Elf64_Xword const cbShStrTab = paShdrs[pEhdr->e_shstrndx].sh_size;
2938 if ( paShdrs[pEhdr->e_shstrndx].sh_offset > cbFile
2939 || cbShStrTab > cbFile
2940 || paShdrs[pEhdr->e_shstrndx].sh_offset + cbShStrTab > cbFile)
2941 return error(pszFile,
2942 "Section string table is outside the file (sh_offset=%#" ELF_FMT_X64 " sh_size=%#" ELF_FMT_X64 " cbFile=%#" ELF_FMT_X64 ")\n",
2943 paShdrs[pEhdr->e_shstrndx].sh_offset, paShdrs[pEhdr->e_shstrndx].sh_size, (Elf64_Xword)cbFile);
2944 const char *pchShStrTab = (const char *)&pbFile[paShdrs[pEhdr->e_shstrndx].sh_offset];
2945 pMachOStuff->pchShStrTab = pchShStrTab;
2946
2947 /*
2948 * Work the section table.
2949 */
2950 bool fRet = true;
2951 for (uint32_t i = 1; i < pEhdr->e_shnum; i++)
2952 {
2953 if (paShdrs[i].sh_name >= cbShStrTab)
2954 return error(pszFile, "Invalid sh_name value (%#x) for section #%u\n", paShdrs[i].sh_name, i);
2955 const char *pszShNm = &pchShStrTab[paShdrs[i].sh_name];
2956
2957 if ( paShdrs[i].sh_offset > cbFile
2958 || paShdrs[i].sh_size > cbFile
2959 || paShdrs[i].sh_offset + paShdrs[i].sh_size > cbFile)
2960 return error(pszFile, "Section #%u '%s' has data outside the file: %#" ELF_FMT_X64 " LB %#" ELF_FMT_X64 " (cbFile=%#" ELF_FMT_X64 ")\n",
2961 i, pszShNm, paShdrs[i].sh_offset, paShdrs[i].sh_size, (Elf64_Xword)cbFile);
2962 if (g_cVerbose)
2963 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"
2964 " link=%u info=%#x align=%#" ELF_FMT_X64 " entsize=%#" ELF_FMT_X64 "\n",
2965 i, paShdrs[i].sh_name, pszShNm, paShdrs[i].sh_type, paShdrs[i].sh_flags,
2966 paShdrs[i].sh_addr, paShdrs[i].sh_offset, paShdrs[i].sh_size,
2967 paShdrs[i].sh_link, paShdrs[i].sh_info, paShdrs[i].sh_addralign, paShdrs[i].sh_entsize);
2968
2969 if (paShdrs[i].sh_link >= pEhdr->e_shnum)
2970 return error(pszFile, "Section #%u '%s' links to a section outside the section table: %#x, max %#x\n",
2971 i, pszShNm, paShdrs[i].sh_link, pEhdr->e_shnum);
2972 if (!RT_IS_POWER_OF_TWO(paShdrs[i].sh_addralign))
2973 return error(pszFile, "Section #%u '%s' alignment value is not a power of two: %#" ELF_FMT_X64 "\n",
2974 i, pszShNm, paShdrs[i].sh_addralign);
2975 if (!RT_IS_POWER_OF_TWO(paShdrs[i].sh_addralign))
2976 return error(pszFile, "Section #%u '%s' alignment value is not a power of two: %#" ELF_FMT_X64 "\n",
2977 i, pszShNm, paShdrs[i].sh_addralign);
2978 if (paShdrs[i].sh_addr != 0)
2979 return error(pszFile, "Section #%u '%s' has non-zero address: %#" ELF_FMT_X64 "\n", i, pszShNm, paShdrs[i].sh_addr);
2980
2981 if (paShdrs[i].sh_type == SHT_RELA)
2982 {
2983 if (paShdrs[i].sh_entsize != sizeof(Elf64_Rela))
2984 return error(pszFile, "Expected sh_entsize to be %u not %u for section #%u (%s)\n", (unsigned)sizeof(Elf64_Rela),
2985 paShdrs[i].sh_entsize, i, pszShNm);
2986 uint32_t const cRelocs = paShdrs[i].sh_size / sizeof(Elf64_Rela);
2987 if (cRelocs * sizeof(Elf64_Rela) != paShdrs[i].sh_size)
2988 return error(pszFile, "Uneven relocation entry count in #%u (%s): sh_size=%#" ELF_FMT_X64 "\n",
2989 i, pszShNm, paShdrs[i].sh_size);
2990 if ( paShdrs[i].sh_offset > cbFile
2991 || paShdrs[i].sh_size >= cbFile
2992 || paShdrs[i].sh_offset + paShdrs[i].sh_size > cbFile)
2993 return error(pszFile, "The content of section #%u '%s' is outside the file (%#" ELF_FMT_X64 " LB %#" ELF_FMT_X64 ", cbFile=%#lx)\n",
2994 i, pszShNm, paShdrs[i].sh_offset, paShdrs[i].sh_size, (unsigned long)cbFile);
2995 if (paShdrs[i].sh_info != i - 1)
2996 return error(pszFile, "Expected relocation section #%u (%s) to link to previous section: sh_info=%#u\n",
2997 i, pszShNm, (unsigned)paShdrs[i].sh_link);
2998 if (paShdrs[paShdrs[i].sh_link].sh_type != SHT_SYMTAB)
2999 return error(pszFile, "Expected relocation section #%u (%s) to link to symbol table: sh_link=%#u -> sh_type=%#x\n",
3000 i, pszShNm, (unsigned)paShdrs[i].sh_link, (unsigned)paShdrs[paShdrs[i].sh_link].sh_type);
3001 uint32_t cSymbols = paShdrs[paShdrs[i].sh_link].sh_size / paShdrs[paShdrs[i].sh_link].sh_entsize;
3002
3003 Elf64_Rela const *paRelocs = (Elf64_Rela *)&pbFile[paShdrs[i].sh_offset];
3004 for (uint32_t j = 0; j < cRelocs; j++)
3005 {
3006 uint8_t const bType = ELF64_R_TYPE(paRelocs[j].r_info);
3007 if (RT_UNLIKELY(bType >= R_X86_64_COUNT))
3008 fRet = error(pszFile,
3009 "%#018" ELF_FMT_X64 " %#018" ELF_FMT_X64 ": unknown fix up %#x (%+" ELF_FMT_D64 ")\n",
3010 paRelocs[j].r_offset, paRelocs[j].r_info, bType, paRelocs[j].r_addend);
3011 if (RT_UNLIKELY( j > 1
3012 && paRelocs[j].r_offset <= paRelocs[j - 1].r_offset
3013 && paRelocs[j].r_offset + ELF_AMD64_RELOC_SIZE(ELF64_R_TYPE(paRelocs[j].r_info))
3014 < paRelocs[j - 1].r_offset ))
3015 fRet = error(pszFile,
3016 "%#018" ELF_FMT_X64 " %#018" ELF_FMT_X64 ": out of offset order (prev %" ELF_FMT_X64 ")\n",
3017 paRelocs[j].r_offset, paRelocs[j].r_info, paRelocs[j - 1].r_offset);
3018 uint32_t const iSymbol = ELF64_R_SYM(paRelocs[j].r_info);
3019 if (RT_UNLIKELY(iSymbol >= cSymbols))
3020 fRet = error(pszFile,
3021 "%#018" ELF_FMT_X64 " %#018" ELF_FMT_X64 ": symbol index (%#x) out of bounds (%#x)\n",
3022 paRelocs[j].r_offset, paRelocs[j].r_info, iSymbol, cSymbols);
3023 }
3024 if (RT_UNLIKELY( cRelocs > 0
3025 && fRet
3026 && ( paRelocs[cRelocs - 1].r_offset > paShdrs[i - 1].sh_size
3027 || paRelocs[cRelocs - 1].r_offset + ELF_AMD64_RELOC_SIZE(ELF64_R_TYPE(paRelocs[cRelocs-1].r_info))
3028 > paShdrs[i - 1].sh_size )))
3029 fRet = error(pszFile,
3030 "%#018" ELF_FMT_X64 " %#018" ELF_FMT_X64 ": out of bounds (sh_size %" ELF_FMT_X64 ")\n",
3031 paRelocs[cRelocs - 1].r_offset, paRelocs[cRelocs - 1].r_info, paShdrs[i - 1].sh_size);
3032
3033 }
3034 else if (paShdrs[i].sh_type == SHT_REL)
3035 fRet = error(pszFile, "Section #%u '%s': Unexpected SHT_REL section\n", i, pszShNm);
3036 else if (paShdrs[i].sh_type == SHT_SYMTAB)
3037 {
3038 if (paShdrs[i].sh_entsize != sizeof(Elf64_Sym))
3039 fRet = error(pszFile, "Section #%u '%s': Unsupported symbol table entry size in : #%u (expected #%u)\n",
3040 i, pszShNm, paShdrs[i].sh_entsize, sizeof(Elf64_Sym));
3041 Elf64_Xword const cSymbols = paShdrs[i].sh_size / paShdrs[i].sh_entsize;
3042 if (cSymbols * paShdrs[i].sh_entsize != paShdrs[i].sh_size)
3043 fRet = error(pszFile, "Section #%u '%s': Size not a multiple of entry size: %#" ELF_FMT_X64 " %% %#" ELF_FMT_X64 " = %#" ELF_FMT_X64 "\n",
3044 i, pszShNm, paShdrs[i].sh_size, paShdrs[i].sh_entsize, paShdrs[i].sh_size % paShdrs[i].sh_entsize);
3045 if (cSymbols > UINT32_MAX)
3046 fRet = error(pszFile, "Section #%u '%s': too many symbols: %" ELF_FMT_X64 "\n",
3047 i, pszShNm, paShdrs[i].sh_size, cSymbols);
3048
3049 if (pMachOStuff->iSymSh == UINT16_MAX)
3050 {
3051 pMachOStuff->iSymSh = (uint16_t)i;
3052 pMachOStuff->paSymbols = (Elf64_Sym const *)&pbFile[paShdrs[i].sh_offset];
3053 pMachOStuff->cSymbols = cSymbols;
3054
3055 if (paShdrs[i].sh_link != 0)
3056 {
3057 /* Note! The symbol string table section header may not have been validated yet! */
3058 Elf64_Shdr const *pStrTabShdr = &paShdrs[paShdrs[i].sh_link];
3059 pMachOStuff->iStrSh = paShdrs[i].sh_link;
3060 pMachOStuff->pchStrTab = (const char *)&pbFile[pStrTabShdr->sh_offset];
3061 pMachOStuff->cbStrTab = (size_t)pStrTabShdr->sh_size;
3062 }
3063 else
3064 fRet = error(pszFile, "Section #%u '%s': String table link is out of bounds (%#x)\n",
3065 i, pszShNm, paShdrs[i].sh_link);
3066 }
3067 else
3068 fRet = error(pszFile, "Section #%u '%s': Found additonal symbol table, previous in #%u\n",
3069 i, pszShNm, pMachOStuff->iSymSh);
3070 }
3071 }
3072 return fRet;
3073}
3074
3075static bool convertMachoSectionsToSegDefsAndGrpDefs(POMFWRITER pThis, PCMACHODETAILS pMachOStuff)
3076{
3077 /*
3078 * Do the list of names pass.
3079 */
3080 uint16_t idxGrpFlat, idxGrpData;
3081 uint16_t idxClassCode, idxClassData, idxClassDwarf;
3082 if ( !omfWriter_LNamesBegin(pThis, true /*fAddZeroEntry*/)
3083 || !omfWriter_LNamesAddN(pThis, RT_STR_TUPLE("FLAT"), &idxGrpFlat)
3084 || !omfWriter_LNamesAddN(pThis, RT_STR_TUPLE("BS3DATA64_GROUP"), &idxGrpData)
3085 || !omfWriter_LNamesAddN(pThis, RT_STR_TUPLE("BS3CLASS64CODE"), &idxClassCode)
3086 || !omfWriter_LNamesAddN(pThis, RT_STR_TUPLE("FAR_DATA"), &idxClassData)
3087 || !omfWriter_LNamesAddN(pThis, RT_STR_TUPLE("DWARF"), &idxClassDwarf)
3088 )
3089 return false;
3090
3091 bool fHaveData = false;
3092 Elf64_Shdr const *pShdr = &pMachOStuff->paShdrs[1];
3093 Elf64_Half const cSections = pMachOStuff->pEhdr->e_shnum;
3094 for (Elf64_Half i = 1; i < cSections; i++, pShdr++)
3095 {
3096 const char *pszName = &pMachOStuff->pchShStrTab[pShdr->sh_name];
3097 if (*pszName == '\0')
3098 return error(pThis->pszSrc, "Section #%u has an empty name!\n", i);
3099
3100 switch (pShdr->sh_type)
3101 {
3102 case SHT_PROGBITS:
3103 case SHT_NOBITS:
3104 /* We drop a few sections we don't want:. */
3105 if ( strcmp(pszName, ".comment") != 0 /* compiler info */
3106 && strcmp(pszName, ".note.GNU-stack") != 0 /* some empty section for hinting the linker/whatever */
3107 && strcmp(pszName, ".eh_frame") != 0 /* unwind / exception info */
3108 )
3109 {
3110 pThis->paSegments[i].iSegDef = UINT16_MAX;
3111 pThis->paSegments[i].iGrpDef = UINT16_MAX;
3112
3113 /* Translate the name and determine group and class.
3114 Note! We currently strip sub-sections. */
3115 if ( strcmp(pszName, ".text") == 0
3116 || strncmp(pszName, RT_STR_TUPLE(".text.")) == 0)
3117 {
3118 pszName = "BS3TEXT64";
3119 pThis->paSegments[i].iGrpNm = idxGrpFlat;
3120 pThis->paSegments[i].iClassNm = idxClassCode;
3121 }
3122 else if ( strcmp(pszName, ".data") == 0
3123 || strncmp(pszName, RT_STR_TUPLE(".data.")) == 0)
3124 {
3125 pszName = "BS3DATA64";
3126 pThis->paSegments[i].iGrpNm = idxGrpData;
3127 pThis->paSegments[i].iClassNm = idxClassData;
3128 }
3129 else if (strcmp(pszName, ".bss") == 0)
3130 {
3131 pszName = "BS3BSS64";
3132 pThis->paSegments[i].iGrpNm = idxGrpData;
3133 pThis->paSegments[i].iClassNm = idxClassData;
3134 }
3135 else if ( strcmp(pszName, ".rodata") == 0
3136 || strncmp(pszName, RT_STR_TUPLE(".rodata.")) == 0)
3137 {
3138 pszName = "BS3DATA64CONST";
3139 pThis->paSegments[i].iGrpNm = idxGrpData;
3140 pThis->paSegments[i].iClassNm = idxClassData;
3141 }
3142 else if (strncmp(pszName, RT_STR_TUPLE(".debug_")) == 0)
3143 {
3144 pThis->paSegments[i].iGrpNm = UINT16_MAX;
3145 pThis->paSegments[i].iClassNm = idxClassDwarf;
3146 }
3147 else
3148 {
3149 pThis->paSegments[i].iGrpNm = idxGrpData;
3150 pThis->paSegments[i].iClassNm = idxClassData;
3151 error(pThis->pszSrc, "Unknown data (?) segment: '%s'\n", pszName);
3152 }
3153
3154 /* Save the name. */
3155 pThis->paSegments[i].pszName = strdup(pszName);
3156 if (!pThis->paSegments[i].pszName)
3157 return error(pThis->pszSrc, "Out of memory!\n");
3158
3159 /* Add the section name. */
3160 if (!omfWriter_LNamesAdd(pThis, pThis->paSegments[i].pszName, &pThis->paSegments[i].iSegNm))
3161 return false;
3162
3163 fHaveData |= pThis->paSegments[i].iGrpDef == idxGrpData;
3164 break;
3165 }
3166 RT_FALL_THRU();
3167
3168 default:
3169 pThis->paSegments[i].iSegDef = UINT16_MAX;
3170 pThis->paSegments[i].iGrpDef = UINT16_MAX;
3171 pThis->paSegments[i].iSegNm = UINT16_MAX;
3172 pThis->paSegments[i].iGrpNm = UINT16_MAX;
3173 pThis->paSegments[i].iClassNm = UINT16_MAX;
3174 pThis->paSegments[i].pszName = NULL;
3175 break;
3176 }
3177 }
3178
3179 if (!omfWriter_LNamesEnd(pThis))
3180 return false;
3181
3182 /*
3183 * Emit segment definitions.
3184 */
3185 uint16_t iSegDef = 1; /* Start counting at 1. */
3186 pShdr = &pMachOStuff->paShdrs[1];
3187 for (Elf64_Half i = 1; i < cSections; i++, pShdr++)
3188 {
3189 if (pThis->paSegments[i].iSegNm == UINT16_MAX)
3190 continue;
3191
3192 uint8_t bSegAttr = 0;
3193
3194 /* The A field. */
3195 switch (pShdr->sh_addralign)
3196 {
3197 case 0:
3198 case 1:
3199 bSegAttr |= 1 << 5;
3200 break;
3201 case 2:
3202 bSegAttr |= 2 << 5;
3203 break;
3204 case 4:
3205 bSegAttr |= 5 << 5;
3206 break;
3207 case 8:
3208 case 16:
3209 bSegAttr |= 3 << 5;
3210 break;
3211 case 32:
3212 case 64:
3213 case 128:
3214 case 256:
3215 bSegAttr |= 4 << 5;
3216 break;
3217 default:
3218 bSegAttr |= 6 << 5; /* page aligned, pharlabs extension. */
3219 break;
3220 }
3221
3222 /* The C field. */
3223 bSegAttr |= 2 << 2; /* public */
3224
3225 /* The B field. We don't have 4GB segments, so leave it as zero. */
3226
3227 /* The D field shall be set as we're doing USE32. */
3228 bSegAttr |= 1;
3229
3230
3231 /* Done. */
3232 if (!omfWriter_SegDef(pThis, bSegAttr, (uint32_t)pShdr->sh_size,
3233 pThis->paSegments[i].iSegNm,
3234 pThis->paSegments[i].iClassNm))
3235 return false;
3236 pThis->paSegments[i].iSegDef = iSegDef++;
3237 }
3238
3239 /*
3240 * Flat group definition (#1) - special, no members.
3241 */
3242 uint16_t iGrpDef = 1;
3243 if ( !omfWriter_GrpDefBegin(pThis, idxGrpFlat)
3244 || !omfWriter_GrpDefEnd(pThis))
3245 return false;
3246 for (uint16_t i = 0; i < cSections; i++)
3247 if (pThis->paSegments[i].iGrpNm == idxGrpFlat)
3248 pThis->paSegments[i].iGrpDef = iGrpDef;
3249 pThis->idxGrpFlat = iGrpDef++;
3250
3251 /*
3252 * Data group definition (#2).
3253 */
3254 /** @todo do we need to consider missing segments and ordering? */
3255 uint16_t cGrpNms = 0;
3256 uint16_t aiGrpNms[2] = { 0, 0 }; /* Shut up, GCC. */
3257 if (fHaveData)
3258 aiGrpNms[cGrpNms++] = idxGrpData;
3259 for (uint32_t iGrpNm = 0; iGrpNm < cGrpNms; iGrpNm++)
3260 {
3261 if (!omfWriter_GrpDefBegin(pThis, aiGrpNms[iGrpNm]))
3262 return false;
3263 for (uint16_t i = 0; i < cSections; i++)
3264 if (pThis->paSegments[i].iGrpNm == aiGrpNms[iGrpNm])
3265 {
3266 pThis->paSegments[i].iGrpDef = iGrpDef;
3267 if (!omfWriter_GrpDefAddSegDef(pThis, pThis->paSegments[i].iSegDef))
3268 return false;
3269 }
3270 if (!omfWriter_GrpDefEnd(pThis))
3271 return false;
3272 iGrpDef++;
3273 }
3274
3275 return true;
3276}
3277
3278static bool convertMachOSymbolsToPubDefsAndExtDefs(POMFWRITER pThis, PCMACHODETAILS pMachOStuff)
3279{
3280 if (!pMachOStuff->cSymbols)
3281 return true;
3282
3283 /*
3284 * Process the symbols the first.
3285 */
3286 uint32_t cAbsSyms = 0;
3287 uint32_t cExtSyms = 0;
3288 uint32_t cPubSyms = 0;
3289 for (uint32_t iSeg = 0; iSeg < pThis->cSegments; iSeg++)
3290 pThis->paSegments[iSeg].cPubDefs = 0;
3291
3292 uint32_t const cSections = pMachOStuff->pEhdr->e_shnum;
3293 uint32_t const cSymbols = pMachOStuff->cSymbols;
3294 Elf64_Sym const * const paSymbols = pMachOStuff->paSymbols;
3295 for (uint32_t iSym = 0; iSym < cSymbols; iSym++)
3296 {
3297 const uint8_t bBind = ELF64_ST_BIND(paSymbols[iSym].st_info);
3298 const uint8_t bType = ELF64_ST_TYPE(paSymbols[iSym].st_info);
3299 const char *pszSymName = &pMachOStuff->pchStrTab[paSymbols[iSym].st_name];
3300 if ( *pszSymName == '\0'
3301 && bType == STT_SECTION
3302 && paSymbols[iSym].st_shndx < cSections)
3303 pszSymName = &pMachOStuff->pchShStrTab[pMachOStuff->paShdrs[paSymbols[iSym].st_shndx].sh_name];
3304
3305 pThis->paSymbols[iSym].enmType = OMFSYMTYPE_IGNORED;
3306 pThis->paSymbols[iSym].idx = UINT16_MAX;
3307 pThis->paSymbols[iSym].idxSegDef = UINT16_MAX;
3308 pThis->paSymbols[iSym].idxGrpDef = UINT16_MAX;
3309
3310 uint32_t const idxSection = paSymbols[iSym].st_shndx;
3311 if (idxSection == SHN_UNDEF)
3312 {
3313 if (bBind == STB_GLOBAL)
3314 {
3315 pThis->paSymbols[iSym].enmType = OMFSYMTYPE_EXTDEF;
3316 cExtSyms++;
3317 if (*pszSymName == '\0')
3318 return error(pThis->pszSrc, "External symbol #%u (%s) has an empty name.\n", iSym, pszSymName);
3319 }
3320 else if (bBind != STB_LOCAL || iSym != 0) /* Entry zero is usually a dummy. */
3321 return error(pThis->pszSrc, "Unsupported or invalid bind type %#x for undefined symbol #%u (%s)\n",
3322 bBind, iSym, pszSymName);
3323 }
3324 else if (idxSection < cSections)
3325 {
3326 pThis->paSymbols[iSym].idxSegDef = pThis->paSegments[idxSection].iSegDef;
3327 pThis->paSymbols[iSym].idxGrpDef = pThis->paSegments[idxSection].iGrpDef;
3328 if (bBind == STB_GLOBAL)
3329 {
3330 pThis->paSymbols[iSym].enmType = OMFSYMTYPE_PUBDEF;
3331 pThis->paSegments[idxSection].cPubDefs++;
3332 cPubSyms++;
3333 if (bType == STT_SECTION)
3334 return error(pThis->pszSrc, "Don't know how to export STT_SECTION symbol #%u (%s)\n", iSym, pszSymName);
3335 if (*pszSymName == '\0')
3336 return error(pThis->pszSrc, "Public symbol #%u (%s) has an empty name.\n", iSym, pszSymName);
3337 }
3338 else if (bType == STT_SECTION)
3339 pThis->paSymbols[iSym].enmType = OMFSYMTYPE_SEGDEF;
3340 else
3341 pThis->paSymbols[iSym].enmType = OMFSYMTYPE_INTERNAL;
3342 }
3343 else if (idxSection == SHN_ABS)
3344 {
3345 if (bType != STT_FILE)
3346 {
3347 if (bBind == STB_GLOBAL)
3348 {
3349 pThis->paSymbols[iSym].enmType = OMFSYMTYPE_PUBDEF;
3350 pThis->paSymbols[iSym].idxSegDef = 0;
3351 pThis->paSymbols[iSym].idxGrpDef = 0;
3352 cAbsSyms++;
3353 if (*pszSymName == '\0')
3354 return error(pThis->pszSrc, "Public absolute symbol #%u (%s) has an empty name.\n", iSym, pszSymName);
3355 }
3356 else
3357 return error(pThis->pszSrc, "Unsupported or invalid bind type %#x for absolute symbol #%u (%s)\n",
3358 bBind, iSym, pszSymName);
3359 }
3360 }
3361 else
3362 return error(pThis->pszSrc, "Unsupported or invalid section number %#x for symbol #%u (%s)\n",
3363 idxSection, iSym, pszSymName);
3364 }
3365
3366 /*
3367 * Emit the PUBDEFs the first time around (see order of records in TIS spec).
3368 * Note! We expect the os x compiler to always underscore symbols, so unlike the
3369 * other 64-bit converters we don't need to check for underscores and add them.
3370 */
3371 uint16_t idxPubDef = 1;
3372 if (cPubSyms)
3373 {
3374 for (uint32_t iSeg = 0; iSeg < pThis->cSegments; iSeg++)
3375 if (pThis->paSegments[iSeg].cPubDefs > 0)
3376 {
3377 uint16_t const idxSegDef = pThis->paSegments[iSeg].iSegDef;
3378 if (!omfWriter_PubDefBegin(pThis, pThis->paSegments[iSeg].iGrpDef, idxSegDef))
3379 return false;
3380 for (uint16_t iSym = 0; iSym < cSymbols; iSym++)
3381 if ( pThis->paSymbols[iSym].idxSegDef == idxSegDef
3382 && pThis->paSymbols[iSym].enmType == OMFSYMTYPE_PUBDEF)
3383 {
3384 const char *pszName = &pMachOStuff->pchStrTab[paSymbols[iSym].st_name];
3385 if (!omfWriter_PubDefAdd(pThis, paSymbols[iSym].st_value, pszName, false /*fPrependUnderscore*/))
3386 return false;
3387 pThis->paSymbols[iSym].idx = idxPubDef++;
3388 }
3389 if (!omfWriter_PubDefEnd(pThis))
3390 return false;
3391 }
3392 }
3393
3394 if (cAbsSyms > 0)
3395 {
3396 if (!omfWriter_PubDefBegin(pThis, 0, 0))
3397 return false;
3398 for (uint16_t iSym = 0; iSym < cSymbols; iSym++)
3399 if ( pThis->paSymbols[iSym].idxSegDef == 0
3400 && pThis->paSymbols[iSym].enmType == OMFSYMTYPE_PUBDEF)
3401 {
3402 const char *pszName = &pMachOStuff->pchStrTab[paSymbols[iSym].st_name];
3403 if (!omfWriter_PubDefAdd(pThis, paSymbols[iSym].st_value, pszName, false /*fPrependUnderscore*/))
3404 return false;
3405 pThis->paSymbols[iSym].idx = idxPubDef++;
3406 }
3407 if (!omfWriter_PubDefEnd(pThis))
3408 return false;
3409 }
3410
3411 /*
3412 * Go over the symbol table and emit external definition records.
3413 */
3414 if (!omfWriter_ExtDefBegin(pThis))
3415 return false;
3416 uint16_t idxExtDef = 1;
3417 for (uint16_t iSym = 0; iSym < cSymbols; iSym++)
3418 if (pThis->paSymbols[iSym].enmType == OMFSYMTYPE_EXTDEF)
3419 {
3420 const char *pszName = &pMachOStuff->pchStrTab[paSymbols[iSym].st_name];
3421 if (!omfWriter_ExtDefAdd(pThis, pszName, false /*fPrependUnderscore*/))
3422 return false;
3423 pThis->paSymbols[iSym].idx = idxExtDef++;
3424 }
3425
3426 if (!omfWriter_ExtDefEnd(pThis))
3427 return false;
3428
3429 return true;
3430}
3431
3432static bool convertMachOSectionsToLeDataAndFixupps(POMFWRITER pThis, PCMACHODETAILS pMachOStuff,
3433 uint8_t const *pbFile, size_t cbFile)
3434{
3435 Elf64_Sym const *paSymbols = pMachOStuff->paSymbols;
3436 Elf64_Shdr const *paShdrs = pMachOStuff->paShdrs;
3437 bool fRet = true;
3438 for (uint32_t i = 1; i < pThis->cSegments; i++)
3439 {
3440 if (pThis->paSegments[i].iSegDef == UINT16_MAX)
3441 continue;
3442
3443 const char *pszSegNm = &pMachOStuff->pchShStrTab[paShdrs[i].sh_name];
3444 bool const fRelocs = i + 1 < pThis->cSegments && paShdrs[i + 1].sh_type == SHT_RELA;
3445 uint32_t cRelocs = fRelocs ? paShdrs[i + 1].sh_size / sizeof(Elf64_Rela) : 0;
3446 Elf64_Rela const *paRelocs = fRelocs ? (Elf64_Rela *)&pbFile[paShdrs[i + 1].sh_offset] : NULL;
3447 Elf64_Xword cbVirtData = paShdrs[i].sh_size;
3448 Elf64_Xword cbData = paShdrs[i].sh_type == SHT_NOBITS ? 0 : cbVirtData;
3449 uint8_t const *pbData = &pbFile[paShdrs[i].sh_offset];
3450 uint32_t off = 0;
3451
3452 /* The OMF record size requires us to split larger sections up. To make
3453 life simple, we fill zeros for unitialized (BSS) stuff. */
3454 const uint32_t cbMaxData = RT_MIN(OMF_MAX_RECORD_PAYLOAD - 1 - (pThis->paSegments[i].iSegDef >= 128) - 4 - 1, _1K);
3455 while (cbVirtData > 0)
3456 {
3457 /* Figure out how many bytes to put out in this chunk. Must make sure
3458 fixups doesn't cross chunk boundraries. ASSUMES sorted relocs. */
3459 uint32_t cChunkRelocs = cRelocs;
3460 uint32_t cbChunk = cbVirtData;
3461 uint32_t offEnd = off + cbChunk;
3462 if (cbChunk > cbMaxData)
3463 {
3464 cbChunk = cbMaxData;
3465 offEnd = off + cbChunk;
3466 cChunkRelocs = 0;
3467
3468 /* Quickly determin the reloc range. */
3469 while ( cChunkRelocs < cRelocs
3470 && paRelocs[cChunkRelocs].r_offset < offEnd)
3471 cChunkRelocs++;
3472
3473 /* Ensure final reloc doesn't go beyond chunk. */
3474 while ( cChunkRelocs > 0
3475 && paRelocs[cChunkRelocs - 1].r_offset
3476 + ELF_AMD64_RELOC_SIZE(ELF64_R_TYPE(paRelocs[cChunkRelocs - 1].r_info))
3477 > offEnd)
3478 {
3479 uint32_t cbDrop = offEnd - paRelocs[cChunkRelocs - 1].r_offset;
3480 cbChunk -= cbDrop;
3481 offEnd -= cbDrop;
3482 cChunkRelocs--;
3483 }
3484
3485 if (!cbVirtData)
3486 return error(pThis->pszSrc, "Wtf? cbVirtData is zero!\n");
3487 }
3488
3489 /*
3490 * We stash the bytes into the OMF writer record buffer, receiving a
3491 * pointer to the start of it so we can make adjustments if necessary.
3492 */
3493 uint8_t *pbCopy;
3494 if (!omfWriter_LEDataBeginEx(pThis, pThis->paSegments[i].iSegDef, off, cbChunk, cbData, pbData, &pbCopy))
3495 return false;
3496
3497 /*
3498 * Convert fiuxps.
3499 */
3500 for (uint32_t iReloc = 0; iReloc < cChunkRelocs; iReloc++)
3501 {
3502 /* Get the OMF and ELF data for the symbol the reloc references. */
3503 uint32_t const uType = ELF64_R_TYPE(paRelocs[iReloc].r_info);
3504 uint32_t const iSymbol = ELF64_R_SYM(paRelocs[iReloc].r_info);
3505 Elf64_Sym const * const pElfSym = &paSymbols[iSymbol];
3506 POMFSYMBOL const pOmfSym = &pThis->paSymbols[iSymbol];
3507 const char * const pszSymName = &pMachOStuff->pchStrTab[pElfSym->st_name];
3508
3509 /* Calc fixup location in the pending chunk and setup a flexible pointer to it. */
3510 uint16_t offDataRec = (uint16_t)(paRelocs[iReloc].r_offset - off);
3511 RTPTRUNION uLoc;
3512 uLoc.pu8 = &pbCopy[offDataRec];
3513
3514 /* OMF fixup data initialized with typical defaults. */
3515 bool fSelfRel = true;
3516 uint8_t bLocation = OMF_FIX_LOC_32BIT_OFFSET;
3517 uint8_t bFrame = OMF_FIX_F_GRPDEF;
3518 uint16_t idxFrame = pThis->idxGrpFlat;
3519 uint8_t bTarget;
3520 uint16_t idxTarget;
3521 bool fTargetDisp;
3522 uint32_t offTargetDisp;
3523 switch (pOmfSym->enmType)
3524 {
3525 case OMFSYMTYPE_INTERNAL:
3526 case OMFSYMTYPE_PUBDEF:
3527 bTarget = OMF_FIX_T_SEGDEF;
3528 idxTarget = pOmfSym->idxSegDef;
3529 fTargetDisp = true;
3530 offTargetDisp = pElfSym->st_value;
3531 break;
3532
3533 case OMFSYMTYPE_SEGDEF:
3534 bTarget = OMF_FIX_T_SEGDEF_NO_DISP;
3535 idxTarget = pOmfSym->idxSegDef;
3536 fTargetDisp = false;
3537 offTargetDisp = 0;
3538 break;
3539
3540 case OMFSYMTYPE_EXTDEF:
3541 bTarget = OMF_FIX_T_EXTDEF_NO_DISP;
3542 idxTarget = pOmfSym->idx;
3543 fTargetDisp = false;
3544 offTargetDisp = 0;
3545 break;
3546
3547 default:
3548 return error(pThis->pszSrc, "Relocation in segment #%u '%s' references ignored or invalid symbol (%s)\n",
3549 i, pszSegNm, pszSymName);
3550 }
3551
3552 /* Do COFF relocation type conversion. */
3553 switch (uType)
3554 {
3555 case R_X86_64_64:
3556 {
3557 int64_t iAddend = paRelocs[iReloc].r_addend;
3558 if (iAddend > _1G || iAddend < -_1G)
3559 fRet = error(pThis->pszSrc, "R_X86_64_64 with large addend (%" ELF_FMT_D64 ") at %#x in segment #%u '%s'\n",
3560 iAddend, paRelocs[iReloc].r_offset, i, pszSegNm);
3561 *uLoc.pu64 = iAddend;
3562 fSelfRel = false;
3563 break;
3564 }
3565
3566 case R_X86_64_32:
3567 case R_X86_64_32S: /* signed, unsigned, whatever. */
3568 fSelfRel = false;
3569 RT_FALL_THRU();
3570 case R_X86_64_PC32:
3571 {
3572 /* defaults are ok, just handle the addend. */
3573 int32_t iAddend = paRelocs[iReloc].r_addend;
3574 if (iAddend != paRelocs[iReloc].r_addend)
3575 fRet = error(pThis->pszSrc, "R_X86_64_PC32 with large addend (%d) at %#x in segment #%u '%s'\n",
3576 iAddend, paRelocs[iReloc].r_offset, i, pszSegNm);
3577 *uLoc.pu32 = iAddend;
3578 break;
3579 }
3580
3581 case R_X86_64_NONE:
3582 continue; /* Ignore this one */
3583
3584 case R_X86_64_GOT32:
3585 case R_X86_64_PLT32:
3586 case R_X86_64_COPY:
3587 case R_X86_64_GLOB_DAT:
3588 case R_X86_64_JMP_SLOT:
3589 case R_X86_64_RELATIVE:
3590 case R_X86_64_GOTPCREL:
3591 case R_X86_64_16:
3592 case R_X86_64_PC16:
3593 case R_X86_64_8:
3594 case R_X86_64_PC8:
3595 case R_X86_64_DTPMOD64:
3596 case R_X86_64_DTPOFF64:
3597 case R_X86_64_TPOFF64:
3598 case R_X86_64_TLSGD:
3599 case R_X86_64_TLSLD:
3600 case R_X86_64_DTPOFF32:
3601 case R_X86_64_GOTTPOFF:
3602 case R_X86_64_TPOFF32:
3603 default:
3604 return error(pThis->pszSrc, "Unsupported fixup type %#x (%s) at rva=%#x in section #%u '%s' against '%s'\n",
3605 uType, g_apszElfAmd64RelTypes[uType], paRelocs[iReloc].r_offset, i, pszSegNm, pszSymName);
3606 }
3607
3608 /* Add the fixup. */
3609 if (idxFrame == UINT16_MAX)
3610 error(pThis->pszSrc, "idxFrame=UINT16_MAX for %s type=%s\n", pszSymName, g_apszElfAmd64RelTypes[uType]);
3611 fRet = omfWriter_LEDataAddFixup(pThis, offDataRec, fSelfRel, bLocation, bFrame, idxFrame,
3612 bTarget, idxTarget, fTargetDisp, offTargetDisp) && fRet;
3613 }
3614
3615 /*
3616 * Write the LEDATA and associated FIXUPPs.
3617 */
3618 if (!omfWriter_LEDataEnd(pThis))
3619 return false;
3620
3621 /*
3622 * Advance.
3623 */
3624 paRelocs += cChunkRelocs;
3625 cRelocs -= cChunkRelocs;
3626 if (cbData > cbChunk)
3627 {
3628 cbData -= cbChunk;
3629 pbData += cbChunk;
3630 }
3631 else
3632 cbData = 0;
3633 off += cbChunk;
3634 cbVirtData -= cbChunk;
3635 }
3636 }
3637
3638 return fRet;
3639}
3640
3641
3642static bool convertMachoToOmf(const char *pszFile, uint8_t const *pbFile, size_t cbFile, FILE *pDst)
3643{
3644 /*
3645 * Validate the source file a little.
3646 */
3647 MACHODETAILS MachOStuff;
3648 if (!validateMachO(pszFile, pbFile, cbFile, &MachOStuff))
3649 return false;
3650
3651 /*
3652 * Instantiate the OMF writer.
3653 */
3654 POMFWRITER pThis = omfWriter_Create(pszFile, MachOStuff.pEhdr->e_shnum, MachOStuff.cSymbols, pDst);
3655 if (!pThis)
3656 return false;
3657
3658 /*
3659 * Write the OMF object file.
3660 */
3661 if (omfWriter_BeginModule(pThis, pszFile))
3662 {
3663 Elf64_Ehdr const *pEhdr = (Elf64_Ehdr const *)pbFile;
3664
3665 if ( convertMachOSectionsToSegDefsAndGrpDefs(pThis, &MachOStuff)
3666 && convertMachOSymbolsToPubDefsAndExtDefs(pThis, &MachOStuff)
3667 && omfWriter_LinkPassSeparator(pThis)
3668 && convertMachOSectionsToLeDataAndFixupps(pThis, &MachOStuff, pbFile, cbFile)
3669 && omfWriter_EndModule(pThis) )
3670 {
3671
3672 omfWriter_Destroy(pThis);
3673 return true;
3674 }
3675 }
3676
3677 omfWriter_Destroy(pThis);
3678 return false;
3679}
3680
3681#endif /* !MACHO_TO_OMF_CONVERSION */
3682
3683
3684/*********************************************************************************************************************************
3685* OMF Converter/Tweaker *
3686*********************************************************************************************************************************/
3687
3688/** Watcom intrinsics we need to modify so we can mix 32-bit and 16-bit
3689 * code, since the 16 and 32 bit compilers share several names.
3690 * The names are length prefixed.
3691 */
3692static const char * const g_apszExtDefRenames[] =
3693{
3694 "\x05" "__I4D",
3695 "\x05" "__I4M",
3696 "\x05" "__I8D",
3697 "\x06" "__I8DQ",
3698 "\x07" "__I8DQE",
3699 "\x06" "__I8DR",
3700 "\x07" "__I8DRE",
3701 "\x06" "__I8LS",
3702 "\x05" "__I8M",
3703 "\x06" "__I8ME",
3704 "\x06" "__I8RS",
3705 "\x05" "__PIA",
3706 "\x05" "__PIS",
3707 "\x05" "__PTC",
3708 "\x05" "__PTS",
3709 "\x05" "__U4D",
3710 "\x05" "__U4M",
3711 "\x05" "__U8D",
3712 "\x06" "__U8DQ",
3713 "\x07" "__U8DQE",
3714 "\x06" "__U8DR",
3715 "\x07" "__U8DRE",
3716 "\x06" "__U8LS",
3717 "\x05" "__U8M",
3718 "\x06" "__U8ME",
3719 "\x06" "__U8RS",
3720};
3721
3722/**
3723 * Segment definition.
3724 */
3725typedef struct OMFSEGDEF
3726{
3727 uint32_t cbSeg;
3728 uint8_t bSegAttr;
3729 uint16_t idxName;
3730 uint16_t idxClass;
3731 uint16_t idxOverlay;
3732 uint8_t cchName;
3733 uint8_t cchClass;
3734 uint8_t cchOverlay;
3735 const char *pchName;
3736 const char *pchClass;
3737 const char *pchOverlay;
3738 bool fUse32;
3739 bool f32bitRec;
3740} OMFSEGDEF;
3741typedef OMFSEGDEF *POMFSEGDEF;
3742
3743/**
3744 * Group definition.
3745 */
3746typedef struct OMFGRPDEF
3747{
3748 const char *pchName;
3749 uint16_t idxName;
3750 uint8_t cchName;
3751 uint16_t cSegDefs;
3752 uint16_t *paidxSegDefs;
3753} OMFGRPDEF;
3754typedef OMFGRPDEF *POMFGRPDEF;
3755
3756/**
3757 * Records line number information for a file in a segment (for CV8 debug info).
3758 */
3759typedef struct OMFFILELINES
3760{
3761 /** The source info offset. */
3762 uint32_t offSrcInfo;
3763 /** Number of line/offset pairs. */
3764 uint32_t cPairs;
3765 /** Number of pairs allocated. */
3766 uint32_t cPairsAlloc;
3767 /** Table with line number and offset pairs, ordered by offset. */
3768 PRTCV8LINEPAIR paPairs;
3769} OMFFILEINES;
3770typedef OMFFILEINES *POMFFILEINES;
3771
3772/**
3773 * Records line number information for a segment (for CV8 debug info).
3774 */
3775typedef struct OMFSEGLINES
3776{
3777 /** Number of files. */
3778 uint32_t cFiles;
3779 /** Number of bytes we need. */
3780 uint32_t cb;
3781 /** The segment index. */
3782 uint16_t idxSeg;
3783 /** The group index for this segment. Initially OMF_REPLACE_GRP_XXX values,
3784 * later convertOmfWriteDebugGrpDefs replaces them with actual values. */
3785 uint16_t idxGrp;
3786 /** File table. */
3787 POMFFILEINES paFiles;
3788} OMFSEGLINES;
3789typedef OMFSEGLINES *POMFSEGLINES;
3790
3791/** @name OMF_REPLACE_GRP_XXX - Special OMFSEGLINES::idxGrp values.
3792 * @{ */
3793#define OMF_REPLACE_GRP_CGROUP16 UINT16_C(0xffe0)
3794#define OMF_REPLACE_GRP_RMCODE UINT16_C(0xffe1)
3795#define OMF_REPLACE_GRP_X0CODE UINT16_C(0xffe2)
3796#define OMF_REPLACE_GRP_X1CODE UINT16_C(0xffe3)
3797/** @} */
3798
3799
3800/**
3801 * OMF details allocation that needs to be freed when done.
3802 */
3803typedef struct OMFDETAILSALLOC
3804{
3805 /** Pointer to the next allocation. */
3806 struct OMFDETAILSALLOC *pNext;
3807 /** The allocated bytes. */
3808 uint8_t abData[RT_FLEXIBLE_ARRAY];
3809} OMFDETAILSALLOC;
3810typedef OMFDETAILSALLOC *POMFDETAILSALLOC;
3811
3812/**
3813 * OMF conversion details.
3814 *
3815 * Keeps information relevant to the conversion and CV8 debug info.
3816 */
3817typedef struct OMFDETAILS
3818{
3819 /** The input file name. */
3820 const char *pszFile;
3821
3822 /** Set if it has line numbers. */
3823 bool fLineNumbers;
3824 /** Set if we think this may be a 32-bit OMF file. */
3825 bool fProbably32bit;
3826 /** Set if this module may need mangling. */
3827 bool fMayNeedMangling;
3828 /** The LNAME index of '$$SYMBOLS' or UINT16_MAX it not found. */
3829 uint16_t iSymbolsNm;
3830 /** The LNAME index of 'DEBSYM' or UINT16_MAX it not found. */
3831 uint16_t iDebSymNm;
3832 /** The '$$SYMBOLS' segment index. */
3833 uint16_t iSymbolsSeg;
3834
3835 /** Number of SEGDEFs records. */
3836 uint16_t cSegDefs;
3837 /** Number of GRPDEFs records. */
3838 uint16_t cGrpDefs;
3839 /** Number of listed names. */
3840 uint16_t cLNames;
3841
3842 /** Segment defintions. */
3843 POMFSEGDEF paSegDefs;
3844 /** Group defintions. */
3845 POMFGRPDEF paGrpDefs;
3846 /** Name list. Points to the size repfix. */
3847 char **papchLNames;
3848
3849 /** Code groups we need to keep an eye on for line number fixup purposes. */
3850 struct OMFLINEGROUPS
3851 {
3852 /** The name. */
3853 const char *pszName;
3854 /** The primary class name. */
3855 const char *pszClass1;
3856 /** The secondary class name. */
3857 const char *pszClass2;
3858 /** The main segment name, NULL if not applicable (CGROUP16). */
3859 const char *pszSeg;
3860 /** The name length. */
3861 uint8_t cchName;
3862 /** The primary class name length. */
3863 uint8_t cchClass1;
3864 /** The secondary class name length. */
3865 uint8_t cchClass2;
3866 /** Whether this group is needed. */
3867 bool fNeeded;
3868 /** The group index (UINT16_MAX if not found). */
3869 uint16_t idxGroup;
3870 /** The group name. */
3871 uint16_t idxName;
3872 /** The OMF_REPLACE_GRP_XXX value. */
3873 uint16_t idxReplaceGrp;
3874 } aGroups[4];
3875
3876 /** CV8: Filename string table size. */
3877 uint32_t cbStrTab;
3878 /** CV8: Filename string table allocation size (always multiple of dword,
3879 * zero initialized). */
3880 uint32_t cbStrTabAlloc;
3881 /** CV8: Filename String table. */
3882 char *pchStrTab;
3883 /** CV8: Elements in the source info table. */
3884 uint16_t cSrcInfo;
3885 /** CV8: Source info table. */
3886 PRTCV8SRCINFO paSrcInfo;
3887
3888 /** Number of entries in the paSegLines table. */
3889 uint32_t cSegLines;
3890 /** Segment line numbers, indexed by segment number. */
3891 POMFSEGLINES paSegLines;
3892
3893 /** List of allocations that needs freeing. */
3894 POMFDETAILSALLOC pAllocHead;
3895} OMFDETAILS;
3896typedef OMFDETAILS *POMFDETAILS;
3897typedef OMFDETAILS const *PCOMFDETAILS;
3898
3899
3900/** Grows a table to a given size (a_cNewEntries). */
3901#define OMF_GROW_TABLE_EX_RET_ERR(a_EntryType, a_paTable, a_cEntries, a_cNewEntries) \
3902 do\
3903 { \
3904 size_t cbOld = (a_cEntries) * sizeof(a_EntryType); \
3905 size_t cbNew = (a_cNewEntries) * sizeof(a_EntryType); \
3906 void *pvNew = realloc(a_paTable, cbNew); \
3907 if (pvNew) \
3908 { \
3909 memset((uint8_t *)pvNew + cbOld, 0, cbNew - cbOld); \
3910 (a_paTable) = (a_EntryType *)pvNew; \
3911 } \
3912 else return error("???", "Out of memory!\n"); \
3913 } while (0)
3914
3915/** Grows a table. */
3916#define OMF_GROW_TABLE_RET_ERR(a_EntryType, a_paTable, a_cEntries, a_cEvery) \
3917 if ((a_cEntries) % (a_cEvery) != 0) { /* likely */ } \
3918 else do\
3919 { \
3920 size_t cbOld = (a_cEntries) * sizeof(a_EntryType); \
3921 size_t cbNew = cbOld + (a_cEvery) * sizeof(a_EntryType); \
3922 void *pvNew = realloc(a_paTable, cbNew); \
3923 if (pvNew) \
3924 { \
3925 memset((uint8_t *)pvNew + cbOld, 0, (a_cEvery) * sizeof(a_EntryType)); \
3926 (a_paTable) = (a_EntryType *)pvNew; \
3927 } \
3928 else return error("???", "Out of memory!\n"); \
3929 } while (0)
3930
3931#define OMF_EXPLODE_LNAME(a_pOmfStuff, a_idxName, a_pchName, a_cchName, a_Name) \
3932 do { \
3933 if ((a_idxName) < (a_pOmfStuff)->cLNames) \
3934 { \
3935 a_cchName = (uint8_t)*(a_pOmfStuff)->papchLNames[(a_idxName)]; \
3936 a_pchName = (a_pOmfStuff)->papchLNames[(a_idxName)] + 1; \
3937 } \
3938 else return error((a_pOmfStuff)->pszFile, "Invalid LNAME reference %#x in " #a_Name "!\n", a_idxName); \
3939 } while (0)
3940
3941
3942/**
3943 * Allocates memory that will be freed when we're done converting.
3944 *
3945 * @returns Pointer tot he memory.
3946 * @param pOmfStuff The OMF details data.
3947 * @param cbNeeded The amount of memory required.
3948 */
3949static void *omfDetails_Alloc(POMFDETAILS pOmfStuff, size_t cbNeeded)
3950{
3951 POMFDETAILSALLOC pAlloc = (POMFDETAILSALLOC)malloc(RT_UOFFSETOF_DYN(OMFDETAILSALLOC, abData[cbNeeded]));
3952 if (pAlloc)
3953 {
3954 pAlloc->pNext = pOmfStuff->pAllocHead;
3955 pOmfStuff->pAllocHead = pAlloc;
3956 return &pAlloc->abData[0];
3957 }
3958 return NULL;
3959}
3960
3961/**
3962 * Adds a line number to the CV8 debug info.
3963 *
3964 * @returns success indicator.
3965 * @param pOmfStuff Where to collect CV8 debug info.
3966 * @param cchSrcFile The length of the source file name.
3967 * @param pchSrcFile The source file name, not terminated.
3968 * @param poffFile Where to return the source file information table
3969 * offset (for use in the line number tables).
3970 */
3971static bool collectOmfAddFile(POMFDETAILS pOmfStuff, uint8_t cchSrcFile, const char *pchSrcFile, uint32_t *poffFile)
3972{
3973 /*
3974 * Do lookup first.
3975 */
3976 uint32_t i = pOmfStuff->cSrcInfo;
3977 while (i-- > 0)
3978 {
3979 const char *pszCur = &pOmfStuff->pchStrTab[pOmfStuff->paSrcInfo[i].offSourceName];
3980 if ( strncmp(pszCur, pchSrcFile, cchSrcFile) == 0
3981 && pszCur[cchSrcFile] == '\0')
3982 {
3983 *poffFile = i * sizeof(pOmfStuff->paSrcInfo[0]);
3984 return true;
3985 }
3986 }
3987
3988 /*
3989 * Add it to the string table (dword aligned and zero padded).
3990 */
3991 uint32_t offSrcTab = pOmfStuff->cbStrTab;
3992 if (offSrcTab + cchSrcFile + 1 > pOmfStuff->cbStrTabAlloc)
3993 {
3994 uint32_t cbNew = (offSrcTab == 0) + offSrcTab + cchSrcFile + 1;
3995 cbNew = RT_ALIGN(cbNew, 256);
3996 void *pvNew = realloc(pOmfStuff->pchStrTab, cbNew);
3997 if (!pvNew)
3998 return error("???", "out of memory");
3999 pOmfStuff->pchStrTab = (char *)pvNew;
4000 pOmfStuff->cbStrTabAlloc = cbNew;
4001 memset(&pOmfStuff->pchStrTab[offSrcTab], 0, cbNew - offSrcTab);
4002
4003 if (!offSrcTab)
4004 offSrcTab++;
4005 }
4006
4007 memcpy(&pOmfStuff->pchStrTab[offSrcTab], pchSrcFile, cchSrcFile);
4008 pOmfStuff->pchStrTab[offSrcTab + cchSrcFile] = '\0';
4009 pOmfStuff->cbStrTab = offSrcTab + cchSrcFile + 1;
4010
4011 /*
4012 * Add it to the filename info table.
4013 */
4014 if ((pOmfStuff->cSrcInfo % 8) == 0)
4015 {
4016 void *pvNew = realloc(pOmfStuff->paSrcInfo, sizeof(pOmfStuff->paSrcInfo[0]) * (pOmfStuff->cSrcInfo + 8));
4017 if (!pvNew)
4018 return error("???", "out of memory");
4019 pOmfStuff->paSrcInfo = (PRTCV8SRCINFO)pvNew;
4020 }
4021
4022 PRTCV8SRCINFO pSrcInfo = &pOmfStuff->paSrcInfo[pOmfStuff->cSrcInfo++];
4023 pSrcInfo->offSourceName = offSrcTab;
4024 pSrcInfo->uDigestType = RTCV8SRCINFO_DIGEST_TYPE_MD5;
4025 memset(&pSrcInfo->Digest, 0, sizeof(pSrcInfo->Digest));
4026
4027 *poffFile = (uint32_t)((uintptr_t)pSrcInfo - (uintptr_t)pOmfStuff->paSrcInfo);
4028 return true;
4029}
4030
4031
4032/**
4033 * Adds a line number to the CV8 debug info.
4034 *
4035 * @returns success indicator.
4036 * @param pOmfStuff Where to collect CV8 debug info.
4037 * @param idxSeg The segment index.
4038 * @param off The segment offset.
4039 * @param uLine The line number.
4040 * @param offSrcInfo The source file info table offset.
4041 */
4042static bool collectOmfAddLine(POMFDETAILS pOmfStuff, uint16_t idxSeg, uint32_t off, uint16_t uLine, uint32_t offSrcInfo)
4043{
4044 /*
4045 * Get/add the segment line structure.
4046 */
4047 if (idxSeg >= pOmfStuff->cSegLines)
4048 {
4049 OMF_GROW_TABLE_EX_RET_ERR(OMFSEGLINES, pOmfStuff->paSegLines, pOmfStuff->cSegLines, idxSeg + 1);
4050 for (uint32_t i = pOmfStuff->cSegLines; i <= idxSeg; i++)
4051 {
4052 pOmfStuff->paSegLines[i].idxSeg = i;
4053 pOmfStuff->paSegLines[i].idxGrp = UINT16_MAX;
4054 pOmfStuff->paSegLines[i].cb = sizeof(RTCV8LINESHDR);
4055 }
4056 pOmfStuff->cSegLines = idxSeg + 1;
4057 }
4058 POMFSEGLINES pSegLines = &pOmfStuff->paSegLines[idxSeg];
4059
4060 /*
4061 * Get/add the file structure with the segment.
4062 */
4063 POMFFILEINES pFileLines = NULL;
4064 uint32_t i = pSegLines->cFiles;
4065 while (i-- > 0)
4066 if (pSegLines->paFiles[i].offSrcInfo == offSrcInfo)
4067 {
4068 pFileLines = &pSegLines->paFiles[i];
4069 break;
4070 }
4071 if (!pFileLines)
4072 {
4073 i = pSegLines->cFiles;
4074 OMF_GROW_TABLE_RET_ERR(OMFFILEINES, pSegLines->paFiles, pSegLines->cFiles, 4);
4075 pSegLines->cFiles = i + 1;
4076 pSegLines->cb += sizeof(RTCV8LINESSRCMAP);
4077
4078 pFileLines = &pSegLines->paFiles[i];
4079 pFileLines->offSrcInfo = offSrcInfo;
4080 pFileLines->cPairs = 0;
4081 pFileLines->cPairsAlloc = 0;
4082 pFileLines->paPairs = NULL;
4083
4084 /*
4085 * Check for segment group requirements the first time a segment is used.
4086 */
4087 if (i == 0)
4088 {
4089 if (idxSeg >= pOmfStuff->cSegDefs)
4090 return error("???", "collectOmfAddLine: idxSeg=%#x is out of bounds (%#x)!\n", idxSeg, pOmfStuff->cSegDefs);
4091 POMFSEGDEF pSegDef = &pOmfStuff->paSegDefs[idxSeg];
4092 unsigned j = RT_ELEMENTS(pOmfStuff->aGroups);
4093 while (j-- > 0)
4094 if ( ( pSegDef->cchClass == pOmfStuff->aGroups[j].cchClass1
4095 && memcmp(pSegDef->pchClass, pOmfStuff->aGroups[j].pszClass1, pSegDef->cchClass) == 0)
4096 || ( pSegDef->cchClass == pOmfStuff->aGroups[j].cchClass2
4097 && memcmp(pSegDef->pchClass, pOmfStuff->aGroups[j].pszClass2, pSegDef->cchClass) == 0))
4098 {
4099 pOmfStuff->aGroups[j].fNeeded = true;
4100 pSegLines->idxGrp = pOmfStuff->aGroups[j].idxReplaceGrp;
4101 break;
4102 }
4103 }
4104 }
4105
4106 /*
4107 * Add the line number (sorted, duplicates removed).
4108 */
4109 if (pFileLines->cPairs + 1 > pFileLines->cPairsAlloc)
4110 {
4111 void *pvNew = realloc(pFileLines->paPairs, (pFileLines->cPairsAlloc + 16) * sizeof(pFileLines->paPairs[0]));
4112 if (!pvNew)
4113 return error("???", "out of memory");
4114 pFileLines->paPairs = (PRTCV8LINEPAIR)pvNew;
4115 pFileLines->cPairsAlloc += 16;
4116 }
4117
4118 i = pFileLines->cPairs;
4119 while (i > 0 && ( off < pFileLines->paPairs[i - 1].offSection
4120 || ( off == pFileLines->paPairs[i - 1].offSection
4121 && uLine < pFileLines->paPairs[i - 1].uLineNumber)) )
4122 i--;
4123 if ( i == pFileLines->cPairs
4124 || off != pFileLines->paPairs[i].offSection
4125 || uLine != pFileLines->paPairs[i].uLineNumber)
4126 {
4127 if (i < pFileLines->cPairs)
4128 memmove(&pFileLines->paPairs[i + 1], &pFileLines->paPairs[i],
4129 (pFileLines->cPairs - i) * sizeof(pFileLines->paPairs));
4130 pFileLines->paPairs[i].offSection = off;
4131 pFileLines->paPairs[i].uLineNumber = uLine;
4132 pFileLines->paPairs[i].fEndOfStatement = true;
4133 pFileLines->cPairs++;
4134 pSegLines->cb += sizeof(pFileLines->paPairs[0]);
4135 }
4136
4137 return true;
4138}
4139
4140
4141/**
4142 * Parses OMF file gathering line numbers (for CV8 debug info) and checking out
4143 * external defintions for mangling work (compiler instrinsics).
4144 *
4145 * @returns success indicator.
4146 * @param pszFile The name of the OMF file.
4147 * @param pbFile The file content.
4148 * @param cbFile The size of the file content.
4149 * @param pOmfStuff Where to collect CV8 debug info and anything else we
4150 * find out about the OMF file.
4151 */
4152static bool collectOmfDetails(const char *pszFile, uint8_t const *pbFile, size_t cbFile, POMFDETAILS pOmfStuff)
4153{
4154 uint32_t cExtDefs = 0;
4155 uint32_t cPubDefs = 0;
4156 uint32_t off = 0;
4157 uint8_t cchSrcFile = 0;
4158 const char *pchSrcFile = NULL;
4159 uint32_t offSrcInfo = UINT32_MAX;
4160
4161 memset(pOmfStuff, 0, sizeof(*pOmfStuff));
4162 pOmfStuff->pszFile = pszFile;
4163 pOmfStuff->iDebSymNm = UINT16_MAX;
4164 pOmfStuff->iSymbolsNm = UINT16_MAX;
4165 pOmfStuff->iSymbolsSeg = UINT16_MAX;
4166
4167 /* Dummy entries. */
4168 OMF_GROW_TABLE_RET_ERR(char *, pOmfStuff->papchLNames, pOmfStuff->cLNames, 16);
4169 pOmfStuff->papchLNames[0] = (char *)"";
4170 pOmfStuff->cLNames = 1;
4171
4172 OMF_GROW_TABLE_RET_ERR(OMFSEGDEF, pOmfStuff->paSegDefs, pOmfStuff->cSegDefs, 16);
4173 pOmfStuff->cSegDefs = 1;
4174
4175 OMF_GROW_TABLE_RET_ERR(OMFGRPDEF, pOmfStuff->paGrpDefs, pOmfStuff->cGrpDefs, 16);
4176 pOmfStuff->cGrpDefs = 1;
4177
4178 /* Groups we seek. */
4179#define OMF_INIT_WANTED_GROUP(a_idx, a_szName, a_szClass1, a_szClass2, a_pszSeg, a_idxReplace) \
4180 pOmfStuff->aGroups[a_idx].pszName = a_szName; \
4181 pOmfStuff->aGroups[a_idx].cchName = sizeof(a_szName) - 1; \
4182 pOmfStuff->aGroups[a_idx].pszClass1 = a_szClass1; \
4183 pOmfStuff->aGroups[a_idx].cchClass1 = sizeof(a_szClass1) - 1; \
4184 pOmfStuff->aGroups[a_idx].pszClass2 = a_szClass2; \
4185 pOmfStuff->aGroups[a_idx].cchClass2 = sizeof(a_szClass2) - 1; \
4186 pOmfStuff->aGroups[a_idx].pszSeg = a_pszSeg; \
4187 pOmfStuff->aGroups[a_idx].fNeeded = false; \
4188 pOmfStuff->aGroups[a_idx].idxGroup = UINT16_MAX; \
4189 pOmfStuff->aGroups[a_idx].idxName = UINT16_MAX; \
4190 pOmfStuff->aGroups[a_idx].idxReplaceGrp = a_idxReplace
4191 OMF_INIT_WANTED_GROUP(0, "CGROUP16", "BS3CLASS16CODE", "CODE", NULL, OMF_REPLACE_GRP_CGROUP16);
4192 OMF_INIT_WANTED_GROUP(1, "BS3GROUPRMTEXT16", "BS3CLASS16RMCODE", "", "BS3RMTEXT16", OMF_REPLACE_GRP_RMCODE);
4193 OMF_INIT_WANTED_GROUP(2, "BS3GROUPX0TEXT16", "BS3CLASS16X0CODE", "", "BS3X0TEXT16", OMF_REPLACE_GRP_X0CODE);
4194 OMF_INIT_WANTED_GROUP(3, "BS3GROUPX1TEXT16", "BS3CLASS16X1CODE", "", "BS3X1TEXT16", OMF_REPLACE_GRP_X1CODE);
4195
4196 /*
4197 * Process the OMF records.
4198 */
4199 while (off + 3 < cbFile)
4200 {
4201 uint8_t bRecType = pbFile[off];
4202 uint16_t cbRec = RT_MAKE_U16(pbFile[off + 1], pbFile[off + 2]);
4203 if (g_cVerbose > 2)
4204 printf( "%#07x: type=%#04x len=%#06x\n", off, bRecType, cbRec);
4205 if (off + cbRec > cbFile)
4206 return error(pszFile, "Invalid record length at %#x: %#x (cbFile=%#lx)\n", off, cbRec, (unsigned long)cbFile);
4207
4208 uint32_t offRec = 0;
4209 uint8_t const *pbRec = &pbFile[off + 3];
4210#define OMF_CHECK_RET(a_cbReq, a_Name) /* Not taking the checksum into account, so we're good with 1 or 2 byte fields. */ \
4211 if (offRec + (a_cbReq) <= cbRec) {/*likely*/} \
4212 else return error(pszFile, "Malformed " #a_Name "! off=%#x offRec=%#x cbRec=%#x cbNeeded=%#x line=%d\n", \
4213 off, offRec, cbRec, (a_cbReq), __LINE__)
4214#define OMF_READ_IDX(a_idx, a_Name) \
4215 do { \
4216 OMF_CHECK_RET(2, a_Name); \
4217 a_idx = pbRec[offRec++]; \
4218 if ((a_idx) & 0x80) \
4219 a_idx = (((a_idx) & 0x7f) << 8) | pbRec[offRec++]; \
4220 } while (0)
4221
4222#define OMF_READ_U16(a_u16, a_Name) \
4223 do { \
4224 OMF_CHECK_RET(4, a_Name); \
4225 a_u16 = RT_MAKE_U16(pbRec[offRec], pbRec[offRec + 1]); \
4226 offRec += 2; \
4227 } while (0)
4228#define OMF_READ_U32(a_u32, a_Name) \
4229 do { \
4230 OMF_CHECK_RET(4, a_Name); \
4231 a_u32 = RT_MAKE_U32_FROM_U8(pbRec[offRec], pbRec[offRec + 1], pbRec[offRec + 2], pbRec[offRec + 3]); \
4232 offRec += 4; \
4233 } while (0)
4234
4235 switch (bRecType)
4236 {
4237 /*
4238 * Record LNAME records, scanning for FLAT.
4239 */
4240 case OMF_LNAMES:
4241 while (offRec + 1 < cbRec)
4242 {
4243 uint8_t cch = pbRec[offRec];
4244 if (offRec + 1 + cch >= cbRec)
4245 return error(pszFile, "Invalid LNAME string length at %#x+3+%#x: %#x (cbFile=%#lx)\n",
4246 off, offRec, cch, (unsigned long)cbFile);
4247
4248 if (g_cVerbose > 2)
4249 printf(" LNAME[%u]: %-*.*s\n", pOmfStuff->cLNames, cch, cch, &pbRec[offRec + 1]);
4250
4251 OMF_GROW_TABLE_RET_ERR(char *, pOmfStuff->papchLNames, pOmfStuff->cLNames, 16);
4252 pOmfStuff->papchLNames[pOmfStuff->cLNames] = (char *)&pbRec[offRec];
4253
4254 if (IS_OMF_STR_EQUAL_EX(cch, &pbRec[offRec + 1], "FLAT"))
4255 pOmfStuff->fProbably32bit = true;
4256
4257 if (IS_OMF_STR_EQUAL_EX(cch, &pbRec[offRec + 1], "DEBSYM"))
4258 pOmfStuff->iDebSymNm = pOmfStuff->cLNames;
4259 if (IS_OMF_STR_EQUAL_EX(cch, &pbRec[offRec + 1], "$$SYMBOLS"))
4260 pOmfStuff->iSymbolsNm = pOmfStuff->cLNames;
4261
4262 unsigned j = RT_ELEMENTS(pOmfStuff->aGroups);
4263 while (j-- > 0)
4264 if ( cch == pOmfStuff->aGroups[j].cchName
4265 && memcmp(&pbRec[offRec + 1], pOmfStuff->aGroups[j].pszName, pOmfStuff->aGroups[j].cchName) == 0)
4266 {
4267 pOmfStuff->aGroups[j].idxName = pOmfStuff->cLNames;
4268 break;
4269 }
4270
4271 pOmfStuff->cLNames++;
4272 offRec += cch + 1;
4273 }
4274 break;
4275
4276 /*
4277 * Display external definitions if -v is specified, also check if anything needs mangling.
4278 */
4279 case OMF_EXTDEF:
4280 while (offRec + 1 < cbRec)
4281 {
4282 uint8_t cch = pbRec[offRec++];
4283 OMF_CHECK_RET(cch, EXTDEF);
4284 char *pchName = (char *)&pbRec[offRec];
4285 offRec += cch;
4286
4287 uint16_t idxType;
4288 OMF_READ_IDX(idxType, EXTDEF);
4289
4290 if (g_cVerbose > 2)
4291 printf(" EXTDEF [%u]: %-*.*s type=%#x\n", cExtDefs, cch, cch, pchName, idxType);
4292 else if (g_cVerbose > 0)
4293 printf(" U %-*.*s\n", cch, cch, pchName);
4294
4295 /* Look for g_apszExtDefRenames entries that requires changing. */
4296 if ( !pOmfStuff->fMayNeedMangling
4297 && cch >= 5
4298 && cch <= 7
4299 && pchName[0] == '_'
4300 && pchName[1] == '_'
4301 && ( pchName[2] == 'U'
4302 || pchName[2] == 'I'
4303 || pchName[2] == 'P')
4304 && ( pchName[3] == '4'
4305 || pchName[3] == '8'
4306 || pchName[3] == 'I'
4307 || pchName[3] == 'T') )
4308 {
4309 pOmfStuff->fMayNeedMangling = true;
4310 }
4311 }
4312 break;
4313
4314 /*
4315 * Display public names if -v is specified.
4316 */
4317 case OMF_PUBDEF32:
4318 case OMF_LPUBDEF32:
4319 pOmfStuff->fProbably32bit = true;
4320 RT_FALL_THRU();
4321 case OMF_PUBDEF16:
4322 case OMF_LPUBDEF16:
4323 if (g_cVerbose > 0)
4324 {
4325 char const chType = bRecType == OMF_PUBDEF16 || bRecType == OMF_PUBDEF32 ? 'T' : 't';
4326 const char *pszRec = "LPUBDEF";
4327 if (chType == 'T')
4328 pszRec++;
4329
4330 uint16_t idxGrp;
4331 OMF_READ_IDX(idxGrp, [L]PUBDEF);
4332
4333 uint16_t idxSeg;
4334 OMF_READ_IDX(idxSeg, [L]PUBDEF);
4335
4336 uint16_t uFrameBase = 0;
4337 if (idxSeg == 0)
4338 {
4339 OMF_CHECK_RET(2, [L]PUBDEF);
4340 uFrameBase = RT_MAKE_U16(pbRec[offRec], pbRec[offRec + 1]);
4341 offRec += 2;
4342 }
4343 if (g_cVerbose > 2)
4344 printf(" %s: idxGrp=%#x idxSeg=%#x uFrameBase=%#x\n", pszRec, idxGrp, idxSeg, uFrameBase);
4345 uint16_t const uSeg = idxSeg ? idxSeg : uFrameBase;
4346
4347 while (offRec + 1 < cbRec)
4348 {
4349 uint8_t cch = pbRec[offRec++];
4350 OMF_CHECK_RET(cch, [L]PUBDEF);
4351 const char *pchName = (const char *)&pbRec[offRec];
4352 offRec += cch;
4353
4354 uint32_t offSeg;
4355 if (bRecType & OMF_REC32)
4356 {
4357 OMF_CHECK_RET(4, [L]PUBDEF);
4358 offSeg = RT_MAKE_U32_FROM_U8(pbRec[offRec], pbRec[offRec + 1], pbRec[offRec + 2], pbRec[offRec + 3]);
4359 offRec += 4;
4360 }
4361 else
4362 {
4363 OMF_CHECK_RET(2, [L]PUBDEF);
4364 offSeg = RT_MAKE_U16(pbRec[offRec], pbRec[offRec + 1]);
4365 offRec += 2;
4366 }
4367
4368 uint16_t idxType;
4369 OMF_READ_IDX(idxType, [L]PUBDEF);
4370
4371 if (g_cVerbose > 2)
4372 printf(" %s[%u]: off=%#010x type=%#x %-*.*s\n", pszRec, cPubDefs, offSeg, idxType, cch, cch, pchName);
4373 else if (g_cVerbose > 0)
4374 printf("%04x:%08x %c %-*.*s\n", uSeg, offSeg, chType, cch, cch, pchName);
4375 }
4376 }
4377 break;
4378
4379 /*
4380 * Must count segment definitions to figure the index of our segment.
4381 */
4382 case OMF_SEGDEF16:
4383 case OMF_SEGDEF32:
4384 {
4385 OMF_GROW_TABLE_RET_ERR(OMFSEGDEF, pOmfStuff->paSegDefs, pOmfStuff->cSegDefs, 16);
4386 POMFSEGDEF pSegDef = &pOmfStuff->paSegDefs[pOmfStuff->cSegDefs++];
4387
4388 OMF_CHECK_RET(1 + (bRecType == OMF_SEGDEF16 ? 2 : 4) + 1 + 1 + 1, SEGDEF);
4389 pSegDef->f32bitRec = bRecType == OMF_SEGDEF32;
4390 pSegDef->bSegAttr = pbRec[offRec++];
4391 pSegDef->fUse32 = pSegDef->bSegAttr & 1;
4392 if ((pSegDef->bSegAttr >> 5) == 0)
4393 {
4394 /* A=0: skip frame number of offset. */
4395 OMF_CHECK_RET(3, SEGDEF);
4396 offRec += 3;
4397 }
4398 if (bRecType == OMF_SEGDEF16)
4399 OMF_READ_U16(pSegDef->cbSeg, SEGDEF16);
4400 else
4401 OMF_READ_U32(pSegDef->cbSeg, SEGDEF32);
4402 OMF_READ_IDX(pSegDef->idxName, SEGDEF);
4403 OMF_READ_IDX(pSegDef->idxClass, SEGDEF);
4404 OMF_READ_IDX(pSegDef->idxOverlay, SEGDEF);
4405 OMF_EXPLODE_LNAME(pOmfStuff, pSegDef->idxName, pSegDef->pchName, pSegDef->cchName, SEGDEF);
4406 OMF_EXPLODE_LNAME(pOmfStuff, pSegDef->idxClass, pSegDef->pchClass, pSegDef->cchClass, SEGDEF);
4407 OMF_EXPLODE_LNAME(pOmfStuff, pSegDef->idxOverlay, pSegDef->pchOverlay, pSegDef->cchOverlay, SEGDEF);
4408 break;
4409 }
4410
4411 /*
4412 * Must count segment definitions to figure the index of our group.
4413 */
4414 case OMF_GRPDEF:
4415 {
4416 OMF_GROW_TABLE_RET_ERR(OMFGRPDEF, pOmfStuff->paGrpDefs, pOmfStuff->cGrpDefs, 8);
4417 POMFGRPDEF pGrpDef = &pOmfStuff->paGrpDefs[pOmfStuff->cGrpDefs];
4418
4419 OMF_READ_IDX(pGrpDef->idxName, GRPDEF);
4420 OMF_EXPLODE_LNAME(pOmfStuff, pGrpDef->idxName, pGrpDef->pchName, pGrpDef->cchName, GRPDEF);
4421
4422 unsigned j = RT_ELEMENTS(pOmfStuff->aGroups);
4423 while (j-- > 0)
4424 if (pGrpDef->idxName == pOmfStuff->aGroups[j].idxName)
4425 {
4426 pOmfStuff->aGroups[j].idxGroup = pOmfStuff->cGrpDefs;
4427 break;
4428 }
4429
4430 pGrpDef->cSegDefs = 0;
4431 pGrpDef->paidxSegDefs = NULL;
4432 while (offRec + 2 + 1 <= cbRec)
4433 {
4434 if (pbRec[offRec] != 0xff)
4435 return error(pszFile, "Unsupported GRPDEF member type: %#x\n", pbRec[offRec]);
4436 offRec++;
4437 OMF_GROW_TABLE_RET_ERR(uint16_t, pGrpDef->paidxSegDefs, pGrpDef->cSegDefs, 16);
4438 OMF_READ_IDX(pGrpDef->paidxSegDefs[pGrpDef->cSegDefs], GRPDEF);
4439 pGrpDef->cSegDefs++;
4440 }
4441 pOmfStuff->cGrpDefs++;
4442 break;
4443 }
4444
4445 /*
4446 * Gather file names.
4447 */
4448 case OMF_THEADR: /* watcom */
4449 cchSrcFile = pbRec[offRec++];
4450 OMF_CHECK_RET(cchSrcFile, OMF_THEADR);
4451 pchSrcFile = (const char *)&pbRec[offRec];
4452 if (!collectOmfAddFile(pOmfStuff, cchSrcFile, pchSrcFile, &offSrcInfo))
4453 return false;
4454 break;
4455
4456 case OMF_COMENT:
4457 {
4458 OMF_CHECK_RET(2, COMENT);
4459 offRec++; /* skip the type (flags) */
4460 uint8_t bClass = pbRec[offRec++];
4461 if (bClass == OMF_CCLS_BORLAND_SRC_FILE) /* nasm */
4462 {
4463 OMF_CHECK_RET(1+1+4, BORLAND_SRC_FILE);
4464 offRec++; /* skip unknown byte */
4465 cchSrcFile = pbRec[offRec++];
4466 OMF_CHECK_RET(cchSrcFile + 4, BORLAND_SRC_FILE);
4467 pchSrcFile = (const char *)&pbRec[offRec];
4468 offRec += cchSrcFile;
4469 if (offRec + 4 + 1 != cbRec)
4470 return error(pszFile, "BAD BORLAND_SRC_FILE record at %#x: %d bytes left\n",
4471 off, cbRec - offRec - 4 - 1);
4472 if (!collectOmfAddFile(pOmfStuff, cchSrcFile, pchSrcFile, &offSrcInfo))
4473 return false;
4474 break;
4475 }
4476 break;
4477 }
4478
4479 /*
4480 * Line number conversion.
4481 */
4482 case OMF_LINNUM16:
4483 case OMF_LINNUM32:
4484 {
4485 uint16_t idxGrp;
4486 OMF_READ_IDX(idxGrp, LINNUM);
4487 uint16_t idxSeg;
4488 OMF_READ_IDX(idxSeg, LINNUM);
4489
4490 uint16_t iLine;
4491 uint32_t offSeg;
4492 if (bRecType == OMF_LINNUM16)
4493 while (offRec + 4 < cbRec)
4494 {
4495 iLine = RT_MAKE_U16(pbRec[offRec + 0], pbRec[offRec + 1]);
4496 offSeg = RT_MAKE_U16(pbRec[offRec + 2], pbRec[offRec + 3]);
4497 if (!collectOmfAddLine(pOmfStuff, idxSeg, offSeg, iLine, offSrcInfo))
4498 return false;
4499 offRec += 4;
4500 }
4501 else
4502 while (offRec + 6 < cbRec)
4503 {
4504 iLine = RT_MAKE_U16(pbRec[offRec + 0], pbRec[offRec + 1]);
4505 offSeg = RT_MAKE_U32_FROM_U8(pbRec[offRec + 2], pbRec[offRec + 3], pbRec[offRec + 4], pbRec[offRec + 5]);
4506 if (!collectOmfAddLine(pOmfStuff, idxSeg, offSeg, iLine, offSrcInfo))
4507 return false;
4508 offRec += 6;
4509 }
4510 if (offRec + 1 != cbRec)
4511 return error(pszFile, "BAD LINNUM record at %#x: %d bytes left\n", off, cbRec - offRec - 1);
4512 break;
4513 }
4514 }
4515
4516 /* advance */
4517 off += cbRec + 3;
4518 }
4519
4520 return true;
4521#undef OMF_READ_IDX
4522#undef OMF_CHECK_RET
4523}
4524
4525
4526/**
4527 * Adds a LNAMES entry (returns existing).
4528 *
4529 * @returns success indicator.
4530 * @param pOmfStuff The OMF stuff.
4531 * @param pszName The name to add.
4532 * @param pidxName Where to return the name index.
4533 */
4534static bool omfDetails_AddLName(POMFDETAILS pOmfStuff, const char *pszName, uint16_t *pidxName)
4535{
4536 size_t const cchName = strlen(pszName);
4537
4538 /*
4539 * Check if we've already got the name.
4540 */
4541 for (unsigned iName = 1; iName < pOmfStuff->cLNames; iName++)
4542 if ( (unsigned char)pOmfStuff->papchLNames[iName][0] == cchName
4543 && memcmp(pOmfStuff->papchLNames[iName] + 1, pszName, cchName) == 0)
4544 {
4545 *pidxName = iName;
4546 return true;
4547 }
4548
4549 /*
4550 * Not found, append it.
4551 */
4552 char *pszCopy = (char *)omfDetails_Alloc(pOmfStuff, cchName + 2);
4553 if (!pszCopy)
4554 return false;
4555 *(unsigned char *)&pszCopy[0] = (unsigned char)cchName;
4556 memcpy(pszCopy + 1, pszName, cchName + 1);
4557
4558 OMF_GROW_TABLE_RET_ERR(char *, pOmfStuff->papchLNames, pOmfStuff->cLNames, 16);
4559 pOmfStuff->papchLNames[pOmfStuff->cLNames] = (char *)pszCopy;
4560 *pidxName = pOmfStuff->cLNames;
4561 pOmfStuff->cLNames++;
4562 return true;
4563}
4564
4565
4566/**
4567 * Adds a SEGDEF (always adds a new one).
4568 *
4569 * @returns success indicator.
4570 * @param pOmfStuff The OMF stuff.
4571 * @param bSegAttr The OMF segment attributes.
4572 * @param cbSeg The segment size.
4573 * @param idxSegName The LNAMES index of the segment name.
4574 * @param idxSegClas The LNAMES index of the segment class.
4575 * @param idxOverlay The LNAMES index of the overlay name; pass 1.
4576 * @param fRec32 Set if SEGDEF32 should be emitted, clear for SEGDEF16.
4577 * @param pidxSeg Where to return the segment index.
4578 */
4579static bool omfDetails_AddSegDef(POMFDETAILS pOmfStuff, uint8_t bSegAttr, uint32_t cbSeg, uint16_t idxSegName,
4580 uint16_t idxSegClass, uint16_t idxOverlay, bool fRec32, uint16_t *pidxSeg)
4581{
4582 Assert(cbSeg <= UINT16_MAX || fRec32);
4583 Assert(idxSegName < pOmfStuff->cLNames);
4584 Assert(idxSegClass < pOmfStuff->cLNames);
4585
4586 OMF_GROW_TABLE_RET_ERR(OMFSEGDEF, pOmfStuff->paSegDefs, pOmfStuff->cSegDefs, 16);
4587 POMFSEGDEF pSegDef = &pOmfStuff->paSegDefs[pOmfStuff->cSegDefs];
4588
4589 pSegDef->bSegAttr = bSegAttr;
4590 pSegDef->fUse32 = bSegAttr & 1;
4591 pSegDef->f32bitRec = fRec32;
4592 pSegDef->cbSeg = cbSeg;
4593 pSegDef->idxName = idxSegName;
4594 pSegDef->idxClass = idxSegClass;
4595 pSegDef->idxOverlay = idxOverlay;
4596
4597 OMF_EXPLODE_LNAME(pOmfStuff, pSegDef->idxName, pSegDef->pchName, pSegDef->cchName, SEGDEF);
4598 OMF_EXPLODE_LNAME(pOmfStuff, pSegDef->idxClass, pSegDef->pchClass, pSegDef->cchClass, SEGDEF);
4599 OMF_EXPLODE_LNAME(pOmfStuff, pSegDef->idxOverlay, pSegDef->pchOverlay, pSegDef->cchOverlay, SEGDEF);
4600
4601 *pidxSeg = pOmfStuff->cSegDefs;
4602 pOmfStuff->cSegDefs++;
4603 return true;
4604}
4605
4606
4607/**
4608 * Adds a SEGDEF if not found.
4609 *
4610 * @returns success indicator.
4611 * @param pOmfStuff The OMF stuff.
4612 * @param bSegAttr The OMF segment attributes.
4613 * @param cbSeg The segment size.
4614 * @param idxSegName The LNAMES index of the segment name.
4615 * @param idxSegClas The LNAMES index of the segment class.
4616 * @param idxOverlay The LNAMES index of the overlay name; pass 1.
4617 * @param fRec32 Set if SEGDEF32 should be emitted, clear for SEGDEF16.
4618 * @param pidxSeg Where to return the segment index.
4619 */
4620static bool omfDetails_AddSegDefIfNeeded(POMFDETAILS pOmfStuff, uint8_t bSegAttr, uint32_t cbSeg, uint16_t idxSegName,
4621 uint16_t idxSegClass, uint16_t idxOverlay, bool fRec32, uint16_t *pidxSeg)
4622{
4623 /* Search for name */
4624 for (unsigned iSegDef = 1; iSegDef < pOmfStuff->cSegDefs; iSegDef++)
4625 {
4626 POMFSEGDEF pSegDef = &pOmfStuff->paSegDefs[iSegDef];
4627 if (pSegDef->idxName == idxSegName)
4628 {
4629 if ( pSegDef->bSegAttr != bSegAttr
4630 || pSegDef->f32bitRec != fRec32
4631 || pSegDef->idxName != idxSegName
4632 || pSegDef->idxClass != idxSegClass
4633 || pSegDef->idxOverlay != idxOverlay)
4634 return error(pOmfStuff->pszFile,
4635 "Existing SEGDEF differs: bSegAttr=%#x vs %#x, f32bitRec=%d vs %d, idxName=%#x vs %#x, idxClass=%#x vs %#x, idxOverlay=%#x vs %#x\n",
4636 pSegDef->bSegAttr, bSegAttr,
4637 pSegDef->f32bitRec, fRec32,
4638 pSegDef->idxName, idxSegName,
4639 pSegDef->idxClass, idxSegClass,
4640 pSegDef->idxOverlay, idxOverlay);
4641 *pidxSeg = iSegDef;
4642 return true;
4643 }
4644 }
4645 return omfDetails_AddSegDef(pOmfStuff, bSegAttr, cbSeg, idxSegName, idxSegClass, idxOverlay, fRec32, pidxSeg);
4646}
4647
4648
4649#if 0 /* unused */
4650/**
4651 * Looks up a GRPDEF in the .
4652 *
4653 * @returns Index (0..32K) if found, UINT16_MAX if not found.
4654 * @param pOmfStuff The OMF stuff.
4655 * @param pchName The name to look up.
4656 * @param cchName The length of the name.
4657 */
4658static uint16_t omfDetails_GrpDefLookupN(POMFDETAILS pOmfStuff, const char *pchName, size_t cchName)
4659{
4660 unsigned iGrpDef = pOmfStuff->cGrpDefs;
4661 while (iGrpDef-- > 0)
4662 {
4663 if ( pOmfStuff->paGrpDefs[iGrpDef].cchName == cchName
4664 && memcmp(pOmfStuff->paGrpDefs[iGrpDef].pchName, pchName, cchName) == 0)
4665 return iGrpDef;
4666 }
4667 return UINT16_MAX;
4668}
4669#endif
4670
4671
4672/**
4673 * Adds an empty GRPDEF (always adds a new one).
4674 *
4675 * @returns success indicator.
4676 * @param pOmfStuff The OMF stuff.
4677 * @param idxGrpName The LNAMES index of the group name.
4678 * @param pidxGrp Where to return the group index.
4679 */
4680static bool omfDetails_AddGrpDef(POMFDETAILS pOmfStuff, uint16_t idxGrpName, uint16_t *pidxGrp)
4681{
4682 Assert(idxGrpName < pOmfStuff->cLNames);
4683
4684 OMF_GROW_TABLE_RET_ERR(OMFGRPDEF, pOmfStuff->paGrpDefs, pOmfStuff->cGrpDefs, 8);
4685 POMFGRPDEF pGrpDef = &pOmfStuff->paGrpDefs[pOmfStuff->cGrpDefs];
4686
4687 pGrpDef->idxName = idxGrpName;
4688 pGrpDef->cSegDefs = 0;
4689 pGrpDef->paidxSegDefs = NULL;
4690
4691 *pidxGrp = pOmfStuff->cGrpDefs;
4692 pOmfStuff->cGrpDefs++;
4693 return true;
4694}
4695
4696
4697/**
4698 * Adds a segment to an existing GRPDEF.
4699 *
4700 * @returns success indicator.
4701 * @param pOmfStuff The OMF stuff.
4702 * @param idxGrp The GRPDEF index of the group to append a member to.
4703 * @param idxSeg The SEGDEF index of the segment name.
4704 */
4705static bool omfDetails_AddSegToGrpDef(POMFDETAILS pOmfStuff, uint16_t idxGrp, uint16_t idxSeg)
4706{
4707 Assert(idxGrp < pOmfStuff->cGrpDefs && idxGrp > 0);
4708 Assert(idxSeg < pOmfStuff->cSegDefs && idxSeg > 0);
4709
4710 POMFGRPDEF pGrpDef = &pOmfStuff->paGrpDefs[idxGrp];
4711 OMF_GROW_TABLE_RET_ERR(uint16_t, pGrpDef->paidxSegDefs, pGrpDef->cSegDefs, 16);
4712 pGrpDef->paidxSegDefs[pGrpDef->cSegDefs] = idxSeg;
4713 pGrpDef->cSegDefs++;
4714
4715 return true;
4716}
4717
4718
4719/**
4720 * Marks 16-bit code segment groups that is used in the object file as needed.
4721 *
4722 * @param pOmfStuff The OMF stuff.
4723 */
4724static void convertOmfLookForNeededGroups(POMFDETAILS pOmfStuff)
4725{
4726 /*
4727 * Consult the groups in question. We mark the groups which segments are
4728 * included in the segment definitions as needed.
4729 */
4730 unsigned i = RT_ELEMENTS(pOmfStuff->aGroups);
4731 while (i-- > 0)
4732 if (pOmfStuff->aGroups[i].pszSeg)
4733 {
4734 const char * const pszSegNm = pOmfStuff->aGroups[i].pszSeg;
4735 size_t const cchSegNm = strlen(pszSegNm);
4736 for (unsigned iSegDef = 0; iSegDef < pOmfStuff->cSegDefs; iSegDef++)
4737 if ( pOmfStuff->paSegDefs[iSegDef].cchName == cchSegNm
4738 && memcmp(pOmfStuff->paSegDefs[iSegDef].pchName, pszSegNm, cchSegNm) == 0)
4739 {
4740 pOmfStuff->aGroups[i].fNeeded = true;
4741 break;
4742 }
4743 }
4744}
4745
4746
4747/**
4748 * Adds necessary group and segment definitions.
4749 *
4750 * @returns success indicator.
4751 * @param pOmfStuff The OMF stuff.
4752 */
4753static bool convertOmfAddNeededGrpDefs(POMFDETAILS pOmfStuff)
4754{
4755 /*
4756 * Process the groups.
4757 */
4758 unsigned j = RT_ELEMENTS(pOmfStuff->aGroups);
4759 while (j-- > 0)
4760 if (pOmfStuff->aGroups[j].fNeeded)
4761 {
4762 if (pOmfStuff->aGroups[j].idxName == UINT16_MAX)
4763 {
4764 Assert(pOmfStuff->aGroups[j].idxGroup == UINT16_MAX);
4765 if (!omfDetails_AddLName(pOmfStuff, pOmfStuff->aGroups[j].pszName, &pOmfStuff->aGroups[j].idxName))
4766 return false;
4767 }
4768 if (pOmfStuff->aGroups[j].idxGroup == UINT16_MAX)
4769 {
4770 if (!omfDetails_AddGrpDef(pOmfStuff, pOmfStuff->aGroups[j].idxName, &pOmfStuff->aGroups[j].idxGroup))
4771 return false;
4772
4773 if (pOmfStuff->aGroups[j].pszSeg)
4774 {
4775 /* We need the segment class name. */
4776 uint16_t idxSegClass;
4777 if (!omfDetails_AddLName(pOmfStuff, pOmfStuff->aGroups[j].pszClass1, &idxSegClass))
4778 return false;
4779
4780 /* Prep segment name buffer. */
4781 size_t cchSegNm = strlen(pOmfStuff->aGroups[j].pszSeg);
4782 char szSegNm[256+16];
4783 Assert(cchSegNm < 256);
4784 memcpy(szSegNm, pOmfStuff->aGroups[j].pszSeg, cchSegNm);
4785
4786 /* Add the three segments. */
4787 static RTSTRTUPLE const s_aSuffixes[3] = { {RT_STR_TUPLE("_START")}, {RT_STR_TUPLE("")}, {RT_STR_TUPLE("_END")}, };
4788 for (unsigned iSuffix = 0; iSuffix < RT_ELEMENTS(s_aSuffixes); iSuffix++)
4789 {
4790 uint16_t idxSegNm;
4791 memcpy(&szSegNm[cchSegNm], s_aSuffixes[iSuffix].psz, s_aSuffixes[iSuffix].cch + 1);
4792 if (!omfDetails_AddLName(pOmfStuff, szSegNm, &idxSegNm))
4793 return false;
4794 uint8_t const fAlign = iSuffix == 1 ? OMF_SEG_ATTR_ALIGN_BYTE : OMF_SEG_ATTR_ALIGN_PARA;
4795 uint16_t idxSeg;
4796 if (!omfDetails_AddSegDefIfNeeded(pOmfStuff, fAlign | OMF_SEG_ATTR_COMB_PUBLIC | OMF_SEG_ATTR_USE16,
4797 0, idxSegNm, idxSegClass, 1, false /*fRec*/, &idxSeg))
4798 return false;
4799 if (!omfDetails_AddSegToGrpDef(pOmfStuff, pOmfStuff->aGroups[j].idxGroup, idxSeg))
4800 return false;
4801 }
4802 }
4803 }
4804 }
4805
4806 /*
4807 * Replace group references in the segment lines table.
4808 */
4809 j = RT_ELEMENTS(pOmfStuff->aGroups);
4810 while (j-- > 0)
4811 if (pOmfStuff->aGroups[j].fNeeded)
4812 for (unsigned i = 0; i < pOmfStuff->cSegLines; i++)
4813 if (pOmfStuff->paSegLines[i].idxGrp == pOmfStuff->aGroups[j].idxReplaceGrp)
4814 pOmfStuff->paSegLines[i].idxGrp = pOmfStuff->aGroups[j].idxGroup;
4815 return true;
4816}
4817
4818
4819/**
4820 * Adds the debug segment definitions (names too) to the OMF state.
4821 *
4822 * @returns success indicator.
4823 * @param pOmfStuff The OMF stuff with CV8 line number info.
4824 */
4825static bool convertOmfAddDebugSegDefs(POMFDETAILS pOmfStuff)
4826{
4827 if ( pOmfStuff->cSegLines == 0
4828 || pOmfStuff->iSymbolsSeg != UINT16_MAX)
4829 return true;
4830
4831 /*
4832 * Add the names we need.
4833 */
4834 if ( pOmfStuff->iSymbolsNm == UINT16_MAX
4835 && !omfDetails_AddLName(pOmfStuff, "$$SYMBOLS", &pOmfStuff->iSymbolsNm))
4836 return false;
4837 if ( pOmfStuff->iDebSymNm == UINT16_MAX
4838 && !omfDetails_AddLName(pOmfStuff, "DEBSYM", &pOmfStuff->iDebSymNm))
4839 return false;
4840
4841 /*
4842 * Add the segment definition.
4843 */
4844 uint8_t bSegAttr = 0;
4845 bSegAttr |= 5 << 5; /* A: dword alignment */
4846 bSegAttr |= 0 << 2; /* C: private */
4847 bSegAttr |= 0 << 1; /* B: not big */
4848 bSegAttr |= 1; /* D: use32 */
4849
4850 /* calc the segment size. */
4851 uint32_t cbSeg = 4; /* dword 4 */
4852 cbSeg += 4 + 4 + RT_ALIGN_32(pOmfStuff->cbStrTab, 4);
4853 cbSeg += 4 + 4 + pOmfStuff->cSrcInfo * sizeof(pOmfStuff->paSrcInfo[0]);
4854 uint32_t i = pOmfStuff->cSegLines;
4855 while (i-- > 0)
4856 if (pOmfStuff->paSegLines[i].cFiles > 0)
4857 cbSeg += 4 + 4 + pOmfStuff->paSegLines[i].cb;
4858 return omfDetails_AddSegDef(pOmfStuff, bSegAttr, cbSeg, pOmfStuff->iSymbolsNm, pOmfStuff->iDebSymNm, 1 /*idxOverlay*/,
4859 true /*fRec32*/, &pOmfStuff->iSymbolsSeg);
4860}
4861
4862
4863/**
4864 * Writes the debug segment data.
4865 *
4866 * @returns success indicator.
4867 * @param pThis The OMF writer.
4868 * @param pOmfStuff The OMF stuff with CV8 line number info.
4869 */
4870static bool convertOmfWriteDebugData(POMFWRITER pThis, POMFDETAILS pOmfStuff)
4871{
4872 if (pOmfStuff->cSegLines == 0)
4873 return true;
4874 Assert(pOmfStuff->iSymbolsSeg != UINT16_MAX);
4875
4876 /* Begin and write the CV version signature. */
4877 if ( !omfWriter_LEDataBegin(pThis, pOmfStuff->iSymbolsSeg, 0)
4878 || !omfWriter_LEDataAddU32(pThis, RTCVSYMBOLS_SIGNATURE_CV8))
4879 return false;
4880
4881 /*
4882 * Emit the string table (no fixups).
4883 */
4884 uint32_t cbLeft = pOmfStuff->cbStrTab;
4885 if ( !omfWriter_LEDataAddU32(pThis, RTCV8SYMBLOCK_TYPE_SRC_STR)
4886 || !omfWriter_LEDataAddU32(pThis, cbLeft)
4887 || !omfWriter_LEDataAddBytes(pThis, pOmfStuff->pchStrTab, RT_ALIGN_32(cbLeft, 4)) ) /* table is zero padded to nearest dword */
4888 return false;
4889
4890 /*
4891 * Emit the source file info table (no fixups).
4892 */
4893 cbLeft = pOmfStuff->cSrcInfo * sizeof(pOmfStuff->paSrcInfo[0]);
4894 if ( !omfWriter_LEDataAddU32(pThis, RTCV8SYMBLOCK_TYPE_SRC_INFO)
4895 || !omfWriter_LEDataAddU32(pThis, cbLeft)
4896 || !omfWriter_LEDataAddBytes(pThis, pOmfStuff->paSrcInfo, cbLeft) )
4897 return false;
4898
4899 /*
4900 * Emit the segment line numbers. There are two fixups here at the start
4901 * of each chunk.
4902 */
4903 POMFSEGLINES pSegLines = pOmfStuff->paSegLines;
4904 uint32_t i = pOmfStuff->cSegLines;
4905 while (i-- > 0)
4906 {
4907 if (pSegLines->cFiles)
4908 {
4909 /* Calc covered area. */
4910 uint32_t cbSectionCovered = 0;
4911 uint32_t j = pSegLines->cFiles;
4912 while (j-- > 0)
4913 {
4914 uint32_t offLast = pSegLines->paFiles[j].paPairs[pSegLines->paFiles[j].cPairs - 1].offSection;
4915 if (offLast > cbSectionCovered)
4916 offLast = cbSectionCovered;
4917 }
4918
4919 /* For simplicity and debuggability, just split the LEDATA here. */
4920 if ( !omfWriter_LEDataSplit(pThis)
4921 || !omfWriter_LEDataAddU32(pThis, RTCV8SYMBLOCK_TYPE_SECT_LINES)
4922 || !omfWriter_LEDataAddU32(pThis, pSegLines->cb)
4923 || !omfWriter_LEDataAddU32(pThis, 0) /*RTCV8LINESHDR::offSection*/
4924 || !omfWriter_LEDataAddU16(pThis, 0) /*RTCV8LINESHDR::iSection*/
4925 || !omfWriter_LEDataAddU16(pThis, 0) /*RTCV8LINESHDR::u16Padding*/
4926 || !omfWriter_LEDataAddU32(pThis, cbSectionCovered) /*RTCV8LINESHDR::cbSectionCovered*/ )
4927 return false;
4928
4929 /* Default to the segment (BS3TEXT32, BS3TEXT64) or the group (CGROUP16,
4930 RMGROUP16, etc). The important thing is that we're framing the fixups
4931 using a segment or group which ends up in the codeview segment map. */
4932 uint16_t idxFrame = pSegLines->idxSeg;
4933 uint8_t bFrame = OMF_FIX_F_SEGDEF;
4934 if (pSegLines->idxGrp != UINT16_MAX)
4935 {
4936 idxFrame = pSegLines->idxGrp;
4937 bFrame = OMF_FIX_F_GRPDEF;
4938 }
4939
4940 /* Fixup #1: segment offset - IMAGE_REL_AMD64_SECREL. */
4941 if (!omfWriter_LEDataAddFixupNoDisp(pThis, 4 + 4 + RT_UOFFSETOF(RTCV8LINESHDR, offSection), OMF_FIX_LOC_32BIT_OFFSET,
4942 bFrame, idxFrame, OMF_FIX_T_SEGDEF_NO_DISP, pSegLines->idxSeg))
4943 return false;
4944
4945
4946 /* Fixup #2: segment number - IMAGE_REL_AMD64_SECTION. */
4947 if (!omfWriter_LEDataAddFixupNoDisp(pThis, 4 + 4 + RT_UOFFSETOF(RTCV8LINESHDR, iSection), OMF_FIX_LOC_16BIT_SEGMENT,
4948 bFrame, idxFrame, OMF_FIX_T_SEGDEF_NO_DISP, pSegLines->idxSeg))
4949 return false;
4950
4951 /* Emit data for each source file. */
4952 for (j = 0; j < pSegLines->cFiles; j++)
4953 {
4954 uint32_t const cbPairs = pSegLines->paFiles[j].cPairs * sizeof(RTCV8LINEPAIR);
4955 if ( !omfWriter_LEDataAddU32(pThis, pSegLines->paFiles[j].offSrcInfo) /*RTCV8LINESSRCMAP::offSourceInfo*/
4956 || !omfWriter_LEDataAddU32(pThis, pSegLines->paFiles[j].cPairs) /*RTCV8LINESSRCMAP::cLines*/
4957 || !omfWriter_LEDataAddU32(pThis, cbPairs + sizeof(RTCV8LINESSRCMAP)) /*RTCV8LINESSRCMAP::cb*/
4958 || !omfWriter_LEDataAddBytes(pThis, pSegLines->paFiles[j].paPairs, cbPairs))
4959 return false;
4960 }
4961 }
4962 pSegLines++;
4963 }
4964
4965 return omfWriter_LEDataEnd(pThis);
4966}
4967
4968
4969/**
4970 * Writes out all the segment group definitions.
4971 *
4972 * @returns success indicator.
4973 * @param pThis The OMF writer.
4974 * @param pOmfStuff The OMF stuff containing the segment defs.
4975 * @param pfFlushState Pointer to the flush state variable.
4976 */
4977static bool convertOmfWriteAllSegDefs(POMFWRITER pThis, POMFDETAILS pOmfStuff, int *pfFlushState)
4978{
4979 if (*pfFlushState > 0)
4980 {
4981 for (unsigned iSegDef = 1; iSegDef < pOmfStuff->cSegDefs; iSegDef++)
4982 {
4983 if (!(pOmfStuff->paSegDefs[iSegDef].f32bitRec
4984 ? omfWriter_SegDef : omfWriter_SegDef16)(pThis, pOmfStuff->paSegDefs[iSegDef].bSegAttr,
4985 pOmfStuff->paSegDefs[iSegDef].cbSeg,
4986 pOmfStuff->paSegDefs[iSegDef].idxName,
4987 pOmfStuff->paSegDefs[iSegDef].idxClass,
4988 pOmfStuff->paSegDefs[iSegDef].idxOverlay))
4989 return false;
4990 }
4991 *pfFlushState = -1;
4992 }
4993 return true;
4994}
4995
4996
4997/**
4998 * Writes out all the segment group definitions.
4999 *
5000 * @returns success indicator.
5001 * @param pThis The OMF writer.
5002 * @param pOmfStuff The OMF stuff containing the group defs.
5003 * @param pfFlushState Pointer to the flush state variable.
5004 */
5005static bool convertOmfWriteAllGrpDefs(POMFWRITER pThis, POMFDETAILS pOmfStuff, int *pfFlushState)
5006{
5007 if (*pfFlushState > 0)
5008 {
5009 for (unsigned iGrpDef = 1; iGrpDef < pOmfStuff->cGrpDefs; iGrpDef++)
5010 {
5011 if (!omfWriter_GrpDefBegin(pThis, pOmfStuff->paGrpDefs[iGrpDef].idxName))
5012 return false;
5013 for (unsigned iSegDef = 0; iSegDef < pOmfStuff->paGrpDefs[iGrpDef].cSegDefs; iSegDef++)
5014 if (!omfWriter_GrpDefAddSegDef(pThis, pOmfStuff->paGrpDefs[iGrpDef].paidxSegDefs[iSegDef]))
5015 return false;
5016 if (!omfWriter_GrpDefEnd(pThis))
5017 return false;
5018 }
5019 *pfFlushState = -1;
5020 }
5021 return true;
5022}
5023
5024
5025/**
5026 * This does the actual converting, passthru style.
5027 *
5028 * It only modifies, removes and inserts stuff it care about, the rest is passed
5029 * thru as-is.
5030 *
5031 * @returns success indicator.
5032 * @param pThis The OMF writer.
5033 * @param pbFile The original file content.
5034 * @param cbFile The size of the original file.
5035 * @param pOmfStuff The OMF stuff we've gathered during the first pass,
5036 * contains CV8 line number info if we converted anything.
5037 * @param fConvertLineNumbers Whether we're converting line numbers and stuff.
5038 */
5039static bool convertOmfPassthru(POMFWRITER pThis, uint8_t const *pbFile, size_t cbFile, POMFDETAILS pOmfStuff,
5040 bool fConvertLineNumbers)
5041{
5042 int fFlushLNames = 1;
5043 int fFlushSegDefs = 1;
5044 int fFlushGrpDefs = 1;
5045 bool fSeenTheAdr = false;
5046 bool fConvertFixupp = false;
5047
5048 uint32_t off = 0;
5049 while (off + 3 < cbFile)
5050 {
5051 uint8_t bRecType = pbFile[off];
5052 uint16_t cbRec = RT_MAKE_U16(pbFile[off + 1], pbFile[off + 2]);
5053 uint32_t offRec = 0;
5054 uint8_t const *pbRec = &pbFile[off + 3];
5055
5056#define OMF_READ_IDX(a_idx, a_Name) \
5057 do { \
5058 a_idx = pbRec[offRec++]; \
5059 if ((a_idx) & 0x80) \
5060 a_idx = (((a_idx) & 0x7f) << 8) | pbRec[offRec++]; \
5061 } while (0)
5062
5063#define OMF_PEEK_IDX(a_idx, a_offRec) \
5064 do { \
5065 a_idx = pbRec[a_offRec]; \
5066 if ((a_idx) & 0x80) \
5067 a_idx = (((a_idx) & 0x7f) << 8) | pbRec[(a_offRec) + 1]; \
5068 } while (0)
5069
5070 /*
5071 * Remove/insert switch. will
5072 */
5073 bool fSkip = false;
5074 switch (bRecType)
5075 {
5076 /*
5077 * Mangle watcom intrinsics if necessary.
5078 */
5079 case OMF_EXTDEF:
5080 if (pOmfStuff->fMayNeedMangling)
5081 {
5082 if (!omfWriter_ExtDefBegin(pThis))
5083 return false;
5084 while (offRec + 1 < cbRec)
5085 {
5086 uint8_t cchName = pbRec[offRec++];
5087 char *pchName = (char *)&pbRec[offRec];
5088 offRec += cchName;
5089
5090 uint16_t idxType;
5091 OMF_READ_IDX(idxType, EXTDEF);
5092
5093 /* Look for g_apszExtDefRenames entries that requires changing. */
5094 if ( cchName >= 5
5095 && cchName <= 7
5096 && pchName[0] == '_'
5097 && pchName[1] == '_'
5098 && ( pchName[2] == 'U'
5099 || pchName[2] == 'I'
5100 || pchName[2] == 'P')
5101 && ( pchName[3] == '4'
5102 || pchName[3] == '8'
5103 || pchName[3] == 'I'
5104 || pchName[3] == 'T') )
5105 {
5106 char szName[12];
5107 memcpy(szName, pchName, cchName);
5108 szName[cchName] = '\0';
5109
5110 uint32_t i = RT_ELEMENTS(g_apszExtDefRenames);
5111 while (i-- > 0)
5112 if ( cchName == (uint8_t)g_apszExtDefRenames[i][0]
5113 && memcmp(&g_apszExtDefRenames[i][1], szName, cchName) == 0)
5114 {
5115 szName[0] = pOmfStuff->fProbably32bit ? '?' : '_';
5116 szName[1] = '?';
5117 break;
5118 }
5119
5120 if (!omfWriter_ExtDefAddN(pThis, szName, cchName, idxType, false /*fPrependUnderscore*/))
5121 return false;
5122 }
5123 else if (!omfWriter_ExtDefAddN(pThis, pchName, cchName, idxType, false /*fPrependUnderscore*/))
5124 return false;
5125 }
5126 if (!omfWriter_ExtDefEnd(pThis))
5127 return false;
5128 fSkip = true;
5129 }
5130 break;
5131
5132 /*
5133 * Remove line number records.
5134 */
5135 case OMF_LINNUM16:
5136 case OMF_LINNUM32:
5137 fSkip = fConvertLineNumbers;
5138 break;
5139
5140 /*
5141 * Remove all but the first OMF_THEADR.
5142 */
5143 case OMF_THEADR:
5144 fSkip = fSeenTheAdr && fConvertLineNumbers;
5145 fSeenTheAdr = true;
5146 break;
5147
5148 /*
5149 * Remove borland source file changes. Also, make sure the group
5150 * definitions are written out.
5151 */
5152 case OMF_COMENT:
5153 if (pbRec[1] == OMF_CCLS_LINK_PASS_SEP)
5154 {
5155 Assert(fFlushSegDefs <= 0);
5156 if ( fFlushGrpDefs > 0
5157 && !convertOmfWriteAllGrpDefs(pThis, pOmfStuff, &fFlushGrpDefs))
5158 return false;
5159 }
5160 if (fConvertLineNumbers)
5161 fSkip = pbRec[1] == OMF_CCLS_BORLAND_SRC_FILE;
5162 break;
5163
5164 /*
5165 * Redo these so the OMF writer is on top of the index thing.
5166 */
5167 case OMF_LNAMES:
5168 if (fFlushLNames >= 0)
5169 {
5170 if (!omfWriter_LNamesBegin(pThis, false /*fAddZeroEntry*/))
5171 return false;
5172 if (!fFlushLNames)
5173 {
5174 while (offRec + 1 < cbRec)
5175 {
5176 uint8_t cch = pbRec[offRec];
5177 const char *pch = (const char *)&pbRec[offRec + 1];
5178 if (!omfWriter_LNamesAddN(pThis, pch, cch, NULL))
5179 return false;
5180 offRec += cch + 1;
5181 }
5182 }
5183 else
5184 {
5185 /* Flush all LNAMES in one go. */
5186 for (unsigned i = 1; i < pOmfStuff->cLNames; i++)
5187 if (!omfWriter_LNamesAddN(pThis, pOmfStuff->papchLNames[i] + 1, *pOmfStuff->papchLNames[i], NULL))
5188 return false;
5189 fFlushLNames = -1;
5190 }
5191 if (!omfWriter_LNamesEnd(pThis))
5192 return false;
5193 }
5194 fSkip = true;
5195 break;
5196
5197 /*
5198 * We may want to flush all the segments when we see the first one.
5199 */
5200 case OMF_SEGDEF16:
5201 case OMF_SEGDEF32:
5202 fSkip = fFlushSegDefs != 0;
5203 if (!convertOmfWriteAllSegDefs(pThis, pOmfStuff, &fFlushSegDefs))
5204 return false;
5205 break;
5206
5207 /*
5208 * We may want to flush all the groups when we see the first one.
5209 */
5210 case OMF_GRPDEF:
5211 fSkip = fFlushGrpDefs != 0;
5212 if (!convertOmfWriteAllGrpDefs(pThis, pOmfStuff, &fFlushGrpDefs))
5213 return false;
5214 break;
5215
5216 /*
5217 * Hook LEDATA to flush groups and figure out when to convert FIXUPP records.
5218 */
5219 case OMF_LEDATA16:
5220 case OMF_LEDATA32:
5221 if ( fFlushGrpDefs > 0
5222 && !convertOmfWriteAllGrpDefs(pThis, pOmfStuff, &fFlushGrpDefs))
5223 return false;
5224 fConvertFixupp = false;
5225#if 0
5226 if ( g_f16BitWatcomC
5227 && bRecType == OMF_LEDATA16)
5228 {
5229 /* Check if this is a code segment. */
5230 uint16_t idxSeg;
5231 OMF_PEEK_IDX(idxSeg, offRec);
5232
5233 }
5234#endif
5235 break;
5236
5237
5238 /*
5239 * Convert fixups for 16-bit code segments to groups.
5240 * Deals with switch table trouble.
5241 */
5242 case OMF_FIXUPP16:
5243 if (fConvertFixupp)
5244 {
5245 /* Gave up on this for now, easier to drop the eyecatcher in the _START segments. */
5246 }
5247 break;
5248
5249 /*
5250 * Upon seeing MODEND we write out the debug info.
5251 */
5252 case OMF_MODEND16:
5253 case OMF_MODEND32:
5254 if (fConvertLineNumbers)
5255 if (!convertOmfWriteDebugData(pThis, pOmfStuff))
5256 return false;
5257 break;
5258 }
5259
5260 /*
5261 * Pass the record thru, if so was decided.
5262 */
5263 if (!fSkip)
5264 {
5265 if ( omfWriter_RecBegin(pThis, bRecType)
5266 && omfWriter_RecAddBytes(pThis, pbRec, cbRec)
5267 && omfWriter_RecEnd(pThis, false))
5268 { /* likely */ }
5269 else return false;
5270 }
5271
5272 /* advance */
5273 off += cbRec + 3;
5274 }
5275
5276 return true;
5277}
5278
5279
5280/**
5281 * Converts LINNUMs and compiler intrinsics in an OMF object file.
5282 *
5283 * Wlink does a cheesy (to use their own term) job of generating the
5284 * sstSrcModule subsection. It is limited to one file and cannot deal with line
5285 * numbers in different segment. The latter is very annoying in assembly files
5286 * that jumps between segments, these a frequent on crash stacks.
5287 *
5288 * The solution is to convert to the same line number tables that cl.exe /Z7
5289 * generates for our 64-bit C code, we named that format codeview v8, or CV8.
5290 * Our code codeview debug info reader can deal with this already because of the
5291 * 64-bit code, so Bob's your uncle.
5292 *
5293 * @returns success indicator.
5294 * @param pszFile The name of the file being converted.
5295 * @param pbFile The file content.
5296 * @param cbFile The size of the file content.
5297 * @param pDst The destiation (output) file.
5298 */
5299static bool convertOmfToOmf(const char *pszFile, uint8_t const *pbFile, size_t cbFile, FILE *pDst)
5300{
5301 bool const fConvertLineNumbers = true;
5302
5303 /*
5304 * Collect line number information, names, segment defintions, groups definitions and such.
5305 */
5306 OMFDETAILS OmfStuff;
5307 if (!collectOmfDetails(pszFile, pbFile, cbFile, &OmfStuff))
5308 return false;
5309
5310 /* Mark groups for 16-bit code segments used by this object file as needed
5311 so we can reframe fixups to these segments correctly. */
5312 convertOmfLookForNeededGroups(&OmfStuff);
5313
5314 /* Add debug segments definitions. */
5315 bool fRc = true;
5316 if (fConvertLineNumbers)
5317 fRc = convertOmfAddDebugSegDefs(&OmfStuff);
5318
5319 /* Add any additional group defintions we may need (for 16-bit code segs). */
5320 if (fRc)
5321 fRc = convertOmfAddNeededGrpDefs(&OmfStuff);
5322 if (fRc)
5323 {
5324 /*
5325 * Instantiate the OMF writer and do pass-thru modifications.
5326 */
5327 POMFWRITER pThis = omfWriter_Create(pszFile, 0, 0, pDst);
5328 if (pThis)
5329 {
5330 fRc = convertOmfPassthru(pThis, pbFile, cbFile, &OmfStuff, fConvertLineNumbers);
5331 omfWriter_Destroy(pThis);
5332 }
5333 else
5334 fRc = false;
5335 }
5336
5337 /*
5338 * Cleanup OmfStuff.
5339 */
5340 uint32_t i = OmfStuff.cSegLines;
5341 while (i-- >0)
5342 {
5343 uint32_t j = OmfStuff.paSegLines[i].cFiles;
5344 while (j-- > 0)
5345 free(OmfStuff.paSegLines[i].paFiles[j].paPairs);
5346 free(OmfStuff.paSegLines[i].paFiles);
5347 }
5348 free(OmfStuff.paSegLines);
5349 free(OmfStuff.paSrcInfo);
5350 free(OmfStuff.pchStrTab);
5351
5352 while (OmfStuff.pAllocHead)
5353 {
5354 POMFDETAILSALLOC pFreeMe = OmfStuff.pAllocHead;
5355 OmfStuff.pAllocHead = OmfStuff.pAllocHead->pNext;
5356 free(pFreeMe);
5357 }
5358
5359 return fRc;
5360}
5361
5362
5363/**
5364 * Does the convertion using convertelf and convertcoff.
5365 *
5366 * @returns exit code (0 on success, non-zero on failure)
5367 * @param pszFile The file to convert.
5368 */
5369static int convertit(const char *pszFile)
5370{
5371 /* Construct the filename for saving the unmodified file. */
5372 char szOrgFile[_4K];
5373 size_t cchFile = strlen(pszFile);
5374 if (cchFile + sizeof(".original") > sizeof(szOrgFile))
5375 {
5376 error(pszFile, "Filename too long!\n");
5377 return RTEXITCODE_FAILURE;
5378 }
5379 memcpy(szOrgFile, pszFile, cchFile);
5380 memcpy(&szOrgFile[cchFile], ".original", sizeof(".original"));
5381
5382 /* Read the whole file. */
5383 void *pvFile;
5384 size_t cbFile;
5385 if (readfile(pszFile, &pvFile, &cbFile))
5386 {
5387 /*
5388 * Do format conversions / adjustments.
5389 */
5390 bool fRc = false;
5391 uint8_t *pbFile = (uint8_t *)pvFile;
5392 if ( cbFile > sizeof(Elf64_Ehdr)
5393 && pbFile[0] == ELFMAG0
5394 && pbFile[1] == ELFMAG1
5395 && pbFile[2] == ELFMAG2
5396 && pbFile[3] == ELFMAG3)
5397 {
5398 if (writefile(szOrgFile, pvFile, cbFile))
5399 {
5400 FILE *pDst = openfile(pszFile, true /*fWrite*/);
5401 if (pDst)
5402 {
5403 fRc = convertElfToOmf(pszFile, pbFile, cbFile, pDst);
5404 fRc = fclose(pDst) == 0 && fRc;
5405 }
5406 }
5407 }
5408 else if ( cbFile > sizeof(IMAGE_FILE_HEADER)
5409 && RT_MAKE_U16(pbFile[0], pbFile[1]) == IMAGE_FILE_MACHINE_AMD64
5410 && RT_MAKE_U16(pbFile[2], pbFile[3]) * sizeof(IMAGE_SECTION_HEADER) + sizeof(IMAGE_FILE_HEADER)
5411 < cbFile
5412 && RT_MAKE_U16(pbFile[2], pbFile[3]) > 0)
5413 {
5414 if (writefile(szOrgFile, pvFile, cbFile))
5415 {
5416 FILE *pDst = openfile(pszFile, true /*fWrite*/);
5417 if (pDst)
5418 {
5419 fRc = convertCoffToOmf(pszFile, pbFile, cbFile, pDst);
5420 fRc = fclose(pDst) == 0 && fRc;
5421 }
5422 }
5423 }
5424 else if ( cbFile >= 8
5425 && pbFile[0] == OMF_THEADR
5426 && RT_MAKE_U16(pbFile[1], pbFile[2]) < cbFile)
5427 {
5428 if (writefile(szOrgFile, pvFile, cbFile))
5429 {
5430 FILE *pDst = openfile(pszFile, true /*fWrite*/);
5431 if (pDst)
5432 {
5433 fRc = convertOmfToOmf(pszFile, pbFile, cbFile, pDst);
5434 fRc = fclose(pDst) == 0 && fRc;
5435 }
5436 }
5437 }
5438 else
5439 fprintf(stderr, "error: Don't recognize format of '%s' (%#x %#x %#x %#x, cbFile=%lu)\n",
5440 pszFile, pbFile[0], pbFile[1], pbFile[2], pbFile[3], (unsigned long)cbFile);
5441 free(pvFile);
5442 if (fRc)
5443 return 0;
5444 }
5445 return 1;
5446}
5447
5448
5449int main(int argc, char **argv)
5450{
5451 int rcExit = 0;
5452
5453 /*
5454 * Scan the arguments.
5455 */
5456 for (int i = 1; i < argc; i++)
5457 {
5458 if (argv[i][0] == '-')
5459 {
5460 const char *pszOpt = &argv[i][1];
5461 if (*pszOpt == '-')
5462 {
5463 /* Convert long options to short ones. */
5464 pszOpt--;
5465 if (!strcmp(pszOpt, "--wcc"))
5466 pszOpt = "w";
5467 else if (!strcmp(pszOpt, "--verbose"))
5468 pszOpt = "v";
5469 else if (!strcmp(pszOpt, "--version"))
5470 pszOpt = "V";
5471 else if (!strcmp(pszOpt, "--help"))
5472 pszOpt = "h";
5473 else
5474 {
5475 fprintf(stderr, "syntax errro: Unknown options '%s'\n", pszOpt);
5476 return 2;
5477 }
5478 }
5479
5480 /* Process the list of short options. */
5481 while (*pszOpt)
5482 {
5483 switch (*pszOpt++)
5484 {
5485 case 'w':
5486 g_f16BitWatcomC = true;
5487 break;
5488
5489 case 'v':
5490 g_cVerbose++;
5491 break;
5492
5493 case 'V':
5494 printf("%s\n", "$Revision: 77823 $");
5495 return 0;
5496
5497 case '?':
5498 case 'h':
5499 printf("usage: %s [options] -o <output> <input1> [input2 ... [inputN]]\n",
5500 argv[0]);
5501 return 0;
5502 }
5503 }
5504 }
5505 else
5506 {
5507 /*
5508 * File to convert. Do the job right away.
5509 */
5510 rcExit = convertit(argv[i]);
5511 if (rcExit != 0)
5512 break;
5513 }
5514 }
5515
5516 return rcExit;
5517}
5518
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