VirtualBox

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

Last change on this file since 84271 was 83773, checked in by vboxsync, 5 years ago

bs3kit: VC++ 14.1 adjustment. bugref:8489

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