VirtualBox

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

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

scm --update-copyright-year

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