VirtualBox

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

Last change on this file since 60218 was 60197, checked in by vboxsync, 9 years ago

VBoxBs3ObjConverter: Got the IMAGE_REL_AMD64_REL32_* the wrong way around.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 149.6 KB
Line 
1/* $Id: VBoxBs3ObjConverter.cpp 60197 2016-03-26 14:13:41Z vboxsync $ */
2/** @file
3 * VirtualBox Validation Kit - Boot Sector 3 object file convert.
4 */
5
6/*
7 * Copyright (C) 2006-2016 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#include <stdio.h>
32#include <string.h>
33#include <stdlib.h>
34#include <errno.h>
35#include <iprt/types.h>
36#include <iprt/ctype.h>
37#include <iprt/assert.h>
38#include <iprt/sort.h>
39#include <iprt/x86.h>
40
41#include <iprt/formats/elf64.h>
42#include <iprt/formats/elf-amd64.h>
43#include <iprt/formats/pecoff.h>
44#include <iprt/formats/omf.h>
45
46
47/*********************************************************************************************************************************
48* Defined Constants And Macros *
49*********************************************************************************************************************************/
50#if ARCH_BITS == 64 && !defined(RT_OS_WINDOWS) && !defined(RT_OS_DARWIN)
51# define ELF_FMT_X64 "lx"
52# define ELF_FMT_D64 "ld"
53#else
54# define ELF_FMT_X64 "llx"
55# define ELF_FMT_D64 "lld"
56#endif
57
58
59/*********************************************************************************************************************************
60* Global Variables *
61*********************************************************************************************************************************/
62/** Verbosity level. */
63static unsigned g_cVerbose = 0;
64
65
66/**
67 * Opens a file for binary reading or writing.
68 *
69 * @returns File stream handle.
70 * @param pszFile The name of the file.
71 * @param fWrite Whether to open for writing or reading.
72 */
73static FILE *openfile(const char *pszFile, bool fWrite)
74{
75#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
76 FILE *pFile = fopen(pszFile, fWrite ? "wb" : "rb");
77#else
78 FILE *pFile = fopen(pszFile, fWrite ? "w" : "r");
79#endif
80 if (!pFile)
81 fprintf(stderr, "error: Failed to open '%s' for %s: %s (%d)\n",
82 pszFile, fWrite ? "writing" : "reading", strerror(errno), errno);
83 return pFile;
84}
85
86
87/**
88 * Read the given file into memory.
89 *
90 * @returns true on success, false on failure.
91 * @param pszFile The file to read.
92 * @param ppvFile Where to return the memory.
93 * @param pcbFile Where to return the size.
94 */
95static bool readfile(const char *pszFile, void **ppvFile, size_t *pcbFile)
96{
97 FILE *pFile = openfile(pszFile, false);
98 if (pFile)
99 {
100 /*
101 * Figure the size.
102 */
103 if (fseek(pFile, 0, SEEK_END) == 0)
104 {
105 long cbFile = ftell(pFile);
106 if (cbFile > 0)
107 {
108 if (fseek(pFile, SEEK_SET, 0) == 0)
109 {
110 /*
111 * Allocate and read content.
112 */
113 void *pvFile = malloc((size_t)cbFile);
114 if (pvFile)
115 {
116 if (fread(pvFile, cbFile, 1, pFile) == 1)
117 {
118 *ppvFile = pvFile;
119 *pcbFile = (size_t)cbFile;
120 fclose(pFile);
121 return true;
122 }
123 free(pvFile);
124 fprintf(stderr, "error: fread failed in '%s': %s (%d)\n", pszFile, strerror(errno), errno);
125 }
126 else
127 fprintf(stderr, "error: failed to allocate %ld bytes of memory for '%s'\n", cbFile, pszFile);
128 }
129 else
130 fprintf(stderr, "error: fseek #2 failed in '%s': %s (%d)\n", pszFile, strerror(errno), errno);
131 }
132 else
133 fprintf(stderr, "error: ftell failed in '%s': %s (%d)\n", pszFile, strerror(errno), errno);
134 }
135 else
136 fprintf(stderr, "error: fseek #1 failed in '%s': %s (%d)\n", pszFile, strerror(errno), errno);
137 fclose(pFile);
138 }
139 return false;
140}
141
142
143/**
144 * Write the given file into memory.
145 *
146 * @returns true on success, false on failure.
147 * @param pszFile The file to write.
148 * @param pvFile Where to return the memory.
149 * @param cbFile Where to return the size.
150 */
151static bool writefile(const char *pszFile, void const *pvFile, size_t cbFile)
152{
153 remove(pszFile);
154
155 int rc = -1;
156 FILE *pFile = openfile(pszFile, true);
157 if (pFile)
158 {
159 if (fwrite(pvFile, cbFile, 1, pFile) == 1)
160 {
161 fclose(pFile);
162 return true;
163 }
164 fprintf(stderr, "error: fwrite failed in '%s': %s (%d)\n", pszFile, strerror(errno), errno);
165 fclose(pFile);
166 }
167 return false;
168}
169
170
171/**
172 * Reports an error and returns false.
173 *
174 * @returns false
175 * @param pszFile The filename.
176 * @param pszFormat The message format string.
177 * @param ... Format arguments.
178 */
179static bool error(const char *pszFile, const char *pszFormat, ...)
180{
181 fflush(stdout);
182 fprintf(stderr, "error: %s: ", pszFile);
183 va_list va;
184 va_start(va, pszFormat);
185 vfprintf(stderr, pszFormat, va);
186 va_end(va);
187 return false;
188}
189
190
191
192/*********************************************************************************************************************************
193* Common OMF Writer *
194*********************************************************************************************************************************/
195
196/** Entry for each segment/section in the source format for mapping it to a
197 * segment defintion. */
198typedef struct OMFTOSEGDEF
199{
200 /** The segment defintion index of the section, UINT16_MAX if not translated. */
201 uint16_t iSegDef;
202 /** The group index for this segment, UINT16_MAX if not applicable. */
203 uint16_t iGrpDef;
204 /** The class name table entry, UINT16_MAX if not applicable. */
205 uint16_t iClassNm;
206 /** The group name for this segment, UINT16_MAX if not applicable. */
207 uint16_t iGrpNm;
208 /** The group name for this segment, UINT16_MAX if not applicable. */
209 uint16_t iSegNm;
210 /** The number of public definitions for this segment. */
211 uint32_t cPubDefs;
212 /** The segment name (OMF). */
213 char *pszName;
214} OMFTOSEGDEF;
215/** Pointer to a segment/section to segdef mapping. */
216typedef OMFTOSEGDEF *POMFTOSEGDEF;
217
218/** Symbol table translation type. */
219typedef enum OMFSYMTYPE
220{
221 /** Invalid symbol table entry (aux sym). */
222 OMFSYMTYPE_INVALID = 0,
223 /** Ignored. */
224 OMFSYMTYPE_IGNORED,
225 /** A public defintion. */
226 OMFSYMTYPE_PUBDEF,
227 /** An external definition. */
228 OMFSYMTYPE_EXTDEF,
229 /** A segment reference for fixups. */
230 OMFSYMTYPE_SEGDEF,
231 /** Internal symbol that may be used for fixups. */
232 OMFSYMTYPE_INTERNAL
233} OMFSYMTYPE;
234
235/** Symbol table translation. */
236typedef struct OMFSYMBOL
237{
238 /** What this source symbol table entry should be translated into. */
239 OMFSYMTYPE enmType;
240 /** The OMF table index. UINT16_MAX if not applicable. */
241 uint16_t idx;
242 /** The OMF segment definition index. */
243 uint16_t idxSegDef;
244 /** The OMF group definition index. */
245 uint16_t idxGrpDef;
246} OMFSYMBOL;
247/** Pointer to an source symbol table translation entry. */
248typedef OMFSYMBOL *POMFSYMBOL;
249
250/**
251 * OMF converter & writer instance.
252 */
253typedef struct OMFWRITER
254{
255 /** The source file name (for bitching). */
256 const char *pszSrc;
257 /** The destination output file. */
258 FILE *pDst;
259
260 /** Number of source segments/sections. */
261 uint32_t cSegments;
262 /** Pointer to the table mapping from source segments/section to segdefs. */
263 POMFTOSEGDEF paSegments;
264
265 /** Number of entries in the source symbol table. */
266 uint32_t cSymbols;
267 /** Pointer to the table mapping from source symbols to OMF stuff. */
268 POMFSYMBOL paSymbols;
269
270 /** The index of the next list of names entry. */
271 uint16_t idxNextName;
272
273 /** The current record size. */
274 uint16_t cbRec;
275 /** The current record type */
276 uint8_t bType;
277 /** The record data buffer (too large, but whatever). */
278 uint8_t abData[_1K + 64];
279 /** Alignment padding. */
280 uint8_t abAlign[2];
281
282 /** Current FIXUPP entry. */
283 uint8_t iFixupp;
284 /** FIXUPP records being prepared for LEDATA currently stashed in abData.
285 * We may have to adjust addend values in the LEDATA when converting to OMF
286 * fixups. */
287 struct
288 {
289 uint16_t cbRec;
290 uint8_t abData[_1K + 64];
291 uint8_t abAlign[2]; /**< Alignment padding. */
292 } aFixupps[3];
293
294 /** The index of the FLAT group. */
295 uint16_t idxGrpFlat;
296 /** The EXTDEF index of the __ImageBase symbol. */
297 uint16_t idxExtImageBase;
298} OMFWRITE;
299/** Pointer to an OMF writer. */
300typedef OMFWRITE *POMFWRITER;
301
302
303/**
304 * Creates an OMF writer instance.
305 */
306static POMFWRITER omfWriter_Create(const char *pszSrc, uint32_t cSegments, uint32_t cSymbols, FILE *pDst)
307{
308 POMFWRITER pThis = (POMFWRITER)calloc(sizeof(OMFWRITER), 1);
309 if (pThis)
310 {
311 pThis->pszSrc = pszSrc;
312 pThis->idxNextName = 1; /* We start counting at 1. */
313 pThis->cSegments = cSegments;
314 pThis->paSegments = (POMFTOSEGDEF)calloc(sizeof(OMFTOSEGDEF), cSegments);
315 if (pThis->paSegments)
316 {
317 pThis->cSymbols = cSymbols;
318 pThis->paSymbols = (POMFSYMBOL)calloc(sizeof(OMFSYMBOL), cSymbols);
319 if (pThis->paSymbols)
320 {
321 pThis->pDst = pDst;
322 return pThis;
323 }
324 free(pThis->paSegments);
325 }
326 free(pThis);
327 }
328 error(pszSrc, "Out of memory!\n");
329 return NULL;
330}
331
332/**
333 * Destroys the given OMF writer instance.
334 * @param pThis OMF writer instance.
335 */
336static void omfWriter_Destroy(POMFWRITER pThis)
337{
338 free(pThis->paSymbols);
339 for (uint32_t i = 0; i < pThis->cSegments; i++)
340 if (pThis->paSegments[i].pszName)
341 free(pThis->paSegments[i].pszName);
342 free(pThis->paSegments);
343 free(pThis);
344}
345
346static bool omfWriter_RecBegin(POMFWRITER pThis, uint8_t bType)
347{
348 pThis->bType = bType;
349 pThis->cbRec = 0;
350 return true;
351}
352
353static bool omfWriter_RecAddU8(POMFWRITER pThis, uint8_t b)
354{
355 if (pThis->cbRec < OMF_MAX_RECORD_PAYLOAD)
356 {
357 pThis->abData[pThis->cbRec++] = b;
358 return true;
359 }
360 return error(pThis->pszSrc, "Exceeded max OMF record length (bType=%#x)!\n", pThis->bType);
361}
362
363static bool omfWriter_RecAddU16(POMFWRITER pThis, uint16_t u16)
364{
365 if (pThis->cbRec + 2U <= OMF_MAX_RECORD_PAYLOAD)
366 {
367 pThis->abData[pThis->cbRec++] = (uint8_t)u16;
368 pThis->abData[pThis->cbRec++] = (uint8_t)(u16 >> 8);
369 return true;
370 }
371 return error(pThis->pszSrc, "Exceeded max OMF record length (bType=%#x)!\n", pThis->bType);
372}
373
374static bool omfWriter_RecAddU32(POMFWRITER pThis, uint32_t u32)
375{
376 if (pThis->cbRec + 4U <= OMF_MAX_RECORD_PAYLOAD)
377 {
378 pThis->abData[pThis->cbRec++] = (uint8_t)u32;
379 pThis->abData[pThis->cbRec++] = (uint8_t)(u32 >> 8);
380 pThis->abData[pThis->cbRec++] = (uint8_t)(u32 >> 16);
381 pThis->abData[pThis->cbRec++] = (uint8_t)(u32 >> 24);
382 return true;
383 }
384 return error(pThis->pszSrc, "Exceeded max OMF record length (bType=%#x)!\n", pThis->bType);
385}
386
387static bool omfWriter_RecAddIdx(POMFWRITER pThis, uint16_t idx)
388{
389 if (idx < 128)
390 return omfWriter_RecAddU8(pThis, (uint8_t)idx);
391 if (idx < _32K)
392 return omfWriter_RecAddU8(pThis, (uint8_t)(idx >> 7) | 0x80)
393 && omfWriter_RecAddU8(pThis, (uint8_t)idx);
394 return error(pThis->pszSrc, "Index out of range %#x\n", idx);
395}
396
397static bool omfWriter_RecAddBytes(POMFWRITER pThis, const void *pvData, size_t cbData)
398{
399 if (cbData + pThis->cbRec <= OMF_MAX_RECORD_PAYLOAD)
400 {
401 memcpy(&pThis->abData[pThis->cbRec], pvData, cbData);
402 pThis->cbRec += (uint16_t)cbData;
403 return true;
404 }
405 return error(pThis->pszSrc, "Exceeded max OMF record length (bType=%#x, cbData=%#x)!\n", pThis->bType, (unsigned)cbData);
406}
407
408static bool omfWriter_RecAddStringN(POMFWRITER pThis, const char *pchString, size_t cchString)
409{
410 if (cchString < 256)
411 {
412 return omfWriter_RecAddU8(pThis, (uint8_t)cchString)
413 && omfWriter_RecAddBytes(pThis, pchString, cchString);
414 }
415 return error(pThis->pszSrc, "String too long (%u bytes): '%*.*s'\n",
416 (unsigned)cchString, (int)cchString, (int)cchString, pchString);
417}
418
419static bool omfWriter_RecAddString(POMFWRITER pThis, const char *pszString)
420{
421 return omfWriter_RecAddStringN(pThis, pszString, strlen(pszString));
422}
423
424static bool omfWriter_RecEnd(POMFWRITER pThis, bool fAddCrc)
425{
426 if ( !fAddCrc
427 || omfWriter_RecAddU8(pThis, 0))
428 {
429 OMFRECHDR RecHdr = { pThis->bType, RT_H2LE_U16(pThis->cbRec) };
430 if ( fwrite(&RecHdr, sizeof(RecHdr), 1, pThis->pDst) == 1
431 && fwrite(pThis->abData, pThis->cbRec, 1, pThis->pDst) == 1)
432 {
433 pThis->bType = 0;
434 pThis->cbRec = 0;
435 return true;
436 }
437 return error(pThis->pszSrc, "Write error\n");
438 }
439 return false;
440}
441
442static bool omfWriter_RecEndWithCrc(POMFWRITER pThis)
443{
444 return omfWriter_RecEnd(pThis, true /*fAddCrc*/);
445}
446
447
448static bool omfWriter_BeginModule(POMFWRITER pThis, const char *pszFile)
449{
450 return omfWriter_RecBegin(pThis, OMF_THEADR)
451 && omfWriter_RecAddString(pThis, pszFile)
452 && omfWriter_RecEndWithCrc(pThis);
453}
454
455static bool omfWriter_LNamesAddN(POMFWRITER pThis, const char *pchName, size_t cchName, uint16_t *pidxName)
456{
457 /* split? */
458 if (pThis->cbRec + 1 /*len*/ + cchName + 1 /*crc*/ > OMF_MAX_RECORD_PAYLOAD)
459 {
460 if (pThis->cbRec == 0)
461 return error(pThis->pszSrc, "Too long LNAME '%*.*s'\n", (int)cchName, (int)cchName, pchName);
462 if ( !omfWriter_RecEndWithCrc(pThis)
463 || !omfWriter_RecBegin(pThis, OMF_LNAMES))
464 return false;
465 }
466
467 if (pidxName)
468 *pidxName = pThis->idxNextName;
469 pThis->idxNextName++;
470 return omfWriter_RecAddStringN(pThis, pchName, cchName);
471}
472
473static bool omfWriter_LNamesAdd(POMFWRITER pThis, const char *pszName, uint16_t *pidxName)
474{
475 return omfWriter_LNamesAddN(pThis, pszName, strlen(pszName), pidxName);
476}
477
478static bool omfWriter_LNamesBegin(POMFWRITER pThis)
479{
480 /* First entry is an empty string. */
481 return omfWriter_RecBegin(pThis, OMF_LNAMES)
482 && ( pThis->idxNextName > 1
483 || omfWriter_LNamesAddN(pThis, "", 0, NULL));
484}
485
486static bool omfWriter_LNamesEnd(POMFWRITER pThis)
487{
488 return omfWriter_RecEndWithCrc(pThis);
489}
490
491
492static bool omfWriter_SegDef(POMFWRITER pThis, uint8_t bSegAttr, uint32_t cbSeg, uint16_t idxSegName, uint16_t idxSegClass)
493{
494 return omfWriter_RecBegin(pThis, OMF_SEGDEF32)
495 && omfWriter_RecAddU8(pThis, bSegAttr)
496 && omfWriter_RecAddU32(pThis, cbSeg)
497 && omfWriter_RecAddIdx(pThis, idxSegName)
498 && omfWriter_RecAddIdx(pThis, idxSegClass)
499 && omfWriter_RecAddIdx(pThis, 1) /* overlay name index = NULL entry */
500 && omfWriter_RecEndWithCrc(pThis);
501}
502
503static bool omfWriter_GrpDefBegin(POMFWRITER pThis, uint16_t idxGrpName)
504{
505 return omfWriter_RecBegin(pThis, OMF_GRPDEF)
506 && omfWriter_RecAddIdx(pThis, idxGrpName);
507}
508
509static bool omfWriter_GrpDefAddSegDef(POMFWRITER pThis, uint16_t idxSegDef)
510{
511 return omfWriter_RecAddU8(pThis, 0xff)
512 && omfWriter_RecAddIdx(pThis, idxSegDef);
513}
514
515static bool omfWriter_GrpDefEnd(POMFWRITER pThis)
516{
517 return omfWriter_RecEndWithCrc(pThis);
518}
519
520
521static bool omfWriter_PubDefBegin(POMFWRITER pThis, uint16_t idxGrpDef, uint16_t idxSegDef)
522{
523 return omfWriter_RecBegin(pThis, OMF_PUBDEF32)
524 && omfWriter_RecAddIdx(pThis, idxGrpDef)
525 && omfWriter_RecAddIdx(pThis, idxSegDef)
526 && ( idxSegDef != 0
527 || omfWriter_RecAddU16(pThis, 0));
528
529}
530
531static bool omfWriter_PubDefAddN(POMFWRITER pThis, uint32_t uValue, const char *pchString, size_t cchString)
532{
533 /* Split? */
534 if (pThis->cbRec + 1 + cchString + 4 + 1 + 1 > OMF_MAX_RECORD_PAYLOAD)
535 {
536 if (cchString >= 256)
537 return error(pThis->pszSrc, "PUBDEF string too long %u ('%s')\n",
538 (unsigned)cchString, (int)cchString, (int)cchString, pchString);
539 if (!omfWriter_RecEndWithCrc(pThis))
540 return false;
541
542 /* Figure out the initial data length. */
543 pThis->cbRec = 1 + ((pThis->abData[0] & 0x80) != 0);
544 if (pThis->abData[pThis->cbRec] != 0)
545 pThis->cbRec += 1 + ((pThis->abData[pThis->cbRec] & 0x80) != 0);
546 else
547 pThis->cbRec += 3;
548 pThis->bType = OMF_PUBDEF32;
549 }
550
551 return omfWriter_RecAddStringN(pThis, pchString, cchString)
552 && omfWriter_RecAddU32(pThis, uValue)
553 && omfWriter_RecAddIdx(pThis, 0); /* type */
554}
555
556static bool omfWriter_PubDefAdd(POMFWRITER pThis, uint32_t uValue, const char *pszString)
557{
558 return omfWriter_PubDefAddN(pThis, uValue, pszString, strlen(pszString));
559}
560
561static bool omfWriter_PubDefEnd(POMFWRITER pThis)
562{
563 return omfWriter_RecEndWithCrc(pThis);
564}
565
566/**
567 * EXTDEF - Begin record.
568 */
569static bool omfWriter_ExtDefBegin(POMFWRITER pThis)
570{
571 return omfWriter_RecBegin(pThis, OMF_EXTDEF);
572
573}
574
575/**
576 * EXTDEF - Add an entry, split record if necessary.
577 */
578static bool omfWriter_ExtDefAddN(POMFWRITER pThis, const char *pchString, size_t cchString)
579{
580 /* Split? */
581 if (pThis->cbRec + 1 + cchString + 1 + 1 > OMF_MAX_RECORD_PAYLOAD)
582 {
583 if (cchString >= 256)
584 return error(pThis->pszSrc, "EXTDEF string too long %u ('%s')\n",
585 (unsigned)cchString, (int)cchString, (int)cchString, pchString);
586 if ( !omfWriter_RecEndWithCrc(pThis)
587 || !omfWriter_RecBegin(pThis, OMF_EXTDEF))
588 return false;
589 }
590
591 return omfWriter_RecAddStringN(pThis, pchString, cchString)
592 && omfWriter_RecAddIdx(pThis, 0); /* type */
593}
594
595/**
596 * EXTDEF - Add an entry, split record if necessary.
597 */
598static bool omfWriter_ExtDefAdd(POMFWRITER pThis, const char *pszString)
599{
600 return omfWriter_ExtDefAddN(pThis, pszString, strlen(pszString));
601}
602
603/**
604 * EXTDEF - End of record.
605 */
606static bool omfWriter_ExtDefEnd(POMFWRITER pThis)
607{
608 return omfWriter_RecEndWithCrc(pThis);
609}
610
611/**
612 * COMENT/LINK_PASS_SEP - Add a link pass separator comment.
613 */
614static bool omfWriter_LinkPassSeparator(POMFWRITER pThis)
615{
616 return omfWriter_RecBegin(pThis, OMF_COMENT)
617 && omfWriter_RecAddU8(pThis, OMF_CTYP_NO_LIST)
618 && omfWriter_RecAddU8(pThis, OMF_CCLS_LINK_PASS_SEP)
619 && omfWriter_RecAddU8(pThis, 1)
620 && omfWriter_RecEndWithCrc(pThis);
621}
622
623/**
624 * LEDATA + FIXUPP - Begin records.
625 */
626static bool omfWriter_LEDataBegin(POMFWRITER pThis, uint16_t idxSeg, uint32_t offSeg,
627 uint32_t cbData, uint32_t cbRawData, void const *pbRawData, uint8_t **ppbData)
628{
629 if ( omfWriter_RecBegin(pThis, OMF_LEDATA32)
630 && omfWriter_RecAddIdx(pThis, idxSeg)
631 && omfWriter_RecAddU32(pThis, offSeg))
632 {
633 if ( cbData <= _1K
634 && pThis->cbRec + cbData + 1 <= OMF_MAX_RECORD_PAYLOAD)
635 {
636 uint8_t *pbDst = &pThis->abData[pThis->cbRec];
637 if (ppbData)
638 *ppbData = pbDst;
639
640 if (cbRawData)
641 memcpy(pbDst, pbRawData, RT_MIN(cbData, cbRawData));
642 if (cbData > cbRawData)
643 memset(&pbDst[cbRawData], 0, cbData - cbRawData);
644
645 pThis->cbRec += cbData;
646
647 /* Reset the associated FIXUPP records. */
648 pThis->iFixupp = 0;
649 for (unsigned i = 0; i < RT_ELEMENTS(pThis->aFixupps); i++)
650 pThis->aFixupps[i].cbRec = 0;
651 return true;
652 }
653 error(pThis->pszSrc, "Too much data for LEDATA record! (%#x)\n", (unsigned)cbData);
654 }
655 return false;
656}
657
658/**
659 * LEDATA + FIXUPP - Add FIXUPP subrecord bytes, split if necessary.
660 */
661static bool omfWriter_LEDataAddFixuppBytes(POMFWRITER pThis, void *pvSubRec, size_t cbSubRec)
662{
663 /* Split? */
664 unsigned iFixupp = pThis->iFixupp;
665 if (pThis->aFixupps[iFixupp].cbRec + cbSubRec >= OMF_MAX_RECORD_PAYLOAD)
666 {
667 if (g_cVerbose >= 2)
668 printf("debug: FIXUPP split\n");
669 iFixupp++;
670 if (iFixupp >= RT_ELEMENTS(pThis->aFixupps))
671 return error(pThis->pszSrc, "Out of FIXUPP records\n");
672 pThis->iFixupp = iFixupp;
673 pThis->aFixupps[iFixupp].cbRec = 0; /* paranoia */
674 }
675
676 /* Append the sub-record data. */
677 memcpy(&pThis->aFixupps[iFixupp].abData[pThis->aFixupps[iFixupp].cbRec], pvSubRec, cbSubRec);
678 pThis->aFixupps[iFixupp].cbRec += (uint16_t)cbSubRec;
679 return true;
680}
681
682/**
683 * LEDATA + FIXUPP - Add fixup, split if necessary.
684 */
685static bool omfWriter_LEDataAddFixup(POMFWRITER pThis, uint16_t offDataRec, bool fSelfRel, uint8_t bLocation,
686 uint8_t bFrame, uint16_t idxFrame,
687 uint8_t bTarget, uint16_t idxTarget, bool fTargetDisp, uint32_t offTargetDisp)
688{
689 if (g_cVerbose >= 2)
690 printf("debug: FIXUP[%#x]: off=%#x frame=%u:%#x target=%u:%#x disp=%d:%#x\n", pThis->aFixupps[pThis->iFixupp].cbRec,
691 offDataRec, bFrame, idxFrame, bTarget, idxTarget, fTargetDisp, offTargetDisp);
692
693 if ( offDataRec >= _1K
694 || bFrame >= 6
695 || bTarget > 6
696 || idxFrame >= _32K
697 || idxTarget >= _32K
698 || fTargetDisp != (bTarget <= OMF_FIX_T_FRAME_NO) )
699 return error(pThis->pszSrc,
700 "Internal error: offDataRec=%#x bFrame=%u idxFrame=%#x bTarget=%u idxTarget=%#x fTargetDisp=%d offTargetDisp=%#x\n",
701 offDataRec, bFrame, idxFrame, bTarget, idxTarget, fTargetDisp, offTargetDisp);
702
703
704 /*
705 * Encode the FIXUP subrecord.
706 */
707 uint8_t abFixup[16];
708 uint8_t off = 0;
709 /* Location */
710 abFixup[off++] = (offDataRec >> 8) | (bLocation << 2) | ((uint8_t)!fSelfRel << 6) | 0x80;
711 abFixup[off++] = (uint8_t)offDataRec;
712 /* Fix Data */
713 abFixup[off++] = 0x00 /*F=0*/ | (bFrame << 4) | 0x00 /*T=0*/ | bTarget;
714 /* Frame Datum */
715 if (bFrame <= OMF_FIX_F_FRAME_NO)
716 {
717 if (idxFrame >= 128)
718 abFixup[off++] = (uint8_t)(idxFrame >> 8);
719 abFixup[off++] = (uint8_t)idxFrame;
720 }
721 /* Target Datum */
722 if (idxTarget >= 128)
723 abFixup[off++] = (uint8_t)(idxTarget >> 8);
724 abFixup[off++] = (uint8_t)idxTarget;
725 /* Target Displacement */
726 if (fTargetDisp)
727 {
728 abFixup[off++] = RT_BYTE1(offTargetDisp);
729 abFixup[off++] = RT_BYTE2(offTargetDisp);
730 abFixup[off++] = RT_BYTE3(offTargetDisp);
731 abFixup[off++] = RT_BYTE4(offTargetDisp);
732 }
733
734 return omfWriter_LEDataAddFixuppBytes(pThis, abFixup, off);
735}
736
737/**
738 * LEDATA + FIXUPP - End of records.
739 */
740static bool omfWriter_LEDataEnd(POMFWRITER pThis)
741{
742 if (omfWriter_RecEndWithCrc(pThis))
743 {
744 for (unsigned iFixupp = 0; iFixupp <= pThis->iFixupp; iFixupp++)
745 {
746 uint16_t const cbRec = pThis->aFixupps[iFixupp].cbRec;
747 if (!cbRec)
748 break;
749 if (g_cVerbose >= 3)
750 printf("debug: FIXUPP32 #%u cbRec=%#x\n", iFixupp, cbRec);
751 if ( !omfWriter_RecBegin(pThis, OMF_FIXUPP32)
752 || !omfWriter_RecAddBytes(pThis, pThis->aFixupps[iFixupp].abData, cbRec)
753 || !omfWriter_RecEndWithCrc(pThis))
754 return false;
755 }
756 pThis->iFixupp = 0;
757 return true;
758 }
759 return false;
760}
761
762/**
763 * MODEND - End of module, simple variant.
764 */
765static bool omfWriter_EndModule(POMFWRITER pThis)
766{
767 return omfWriter_RecBegin(pThis, OMF_MODEND32)
768 && omfWriter_RecAddU8(pThis, 0)
769 && omfWriter_RecEndWithCrc(pThis);
770}
771
772
773
774
775/*********************************************************************************************************************************
776* ELF64/AMD64 -> ELF64/i386 Converter *
777*********************************************************************************************************************************/
778
779/** AMD64 relocation type names for ELF. */
780static const char * const g_apszElfAmd64RelTypes[] =
781{
782 "R_X86_64_NONE",
783 "R_X86_64_64",
784 "R_X86_64_PC32",
785 "R_X86_64_GOT32",
786 "R_X86_64_PLT32",
787 "R_X86_64_COPY",
788 "R_X86_64_GLOB_DAT",
789 "R_X86_64_JMP_SLOT",
790 "R_X86_64_RELATIVE",
791 "R_X86_64_GOTPCREL",
792 "R_X86_64_32",
793 "R_X86_64_32S",
794 "R_X86_64_16",
795 "R_X86_64_PC16",
796 "R_X86_64_8",
797 "R_X86_64_PC8",
798 "R_X86_64_DTPMOD64",
799 "R_X86_64_DTPOFF64",
800 "R_X86_64_TPOFF64",
801 "R_X86_64_TLSGD",
802 "R_X86_64_TLSLD",
803 "R_X86_64_DTPOFF32",
804 "R_X86_64_GOTTPOFF",
805 "R_X86_64_TPOFF32",
806};
807
808/** AMD64 relocation type sizes for ELF. */
809static uint8_t const g_acbElfAmd64RelTypes[] =
810{
811 0, /* R_X86_64_NONE */
812 8, /* R_X86_64_64 */
813 4, /* R_X86_64_PC32 */
814 4, /* R_X86_64_GOT32 */
815 4, /* R_X86_64_PLT32 */
816 0, /* R_X86_64_COPY */
817 0, /* R_X86_64_GLOB_DAT */
818 0, /* R_X86_64_JMP_SLOT */
819 0, /* R_X86_64_RELATIVE */
820 0, /* R_X86_64_GOTPCREL */
821 4, /* R_X86_64_32 */
822 4, /* R_X86_64_32S */
823 2, /* R_X86_64_16 */
824 2, /* R_X86_64_PC16 */
825 1, /* R_X86_64_8 */
826 1, /* R_X86_64_PC8 */
827 0, /* R_X86_64_DTPMOD64 */
828 0, /* R_X86_64_DTPOFF64 */
829 0, /* R_X86_64_TPOFF64 */
830 0, /* R_X86_64_TLSGD */
831 0, /* R_X86_64_TLSLD */
832 0, /* R_X86_64_DTPOFF32 */
833 0, /* R_X86_64_GOTTPOFF */
834 0, /* R_X86_64_TPOFF32 */
835};
836
837/** Macro for getting the size of a AMD64 ELF relocation. */
838#define ELF_AMD64_RELOC_SIZE(a_Type) ( (a_Type) < RT_ELEMENTS(g_acbElfAmd64RelTypes) ? g_acbElfAmd64RelTypes[(a_Type)] : 1)
839
840
841typedef struct ELFDETAILS
842{
843 /** The ELF header. */
844 Elf64_Ehdr const *pEhdr;
845 /** The section header table. */
846 Elf64_Shdr const *paShdrs;
847 /** The string table for the section names. */
848 const char *pchShStrTab;
849
850 /** The symbol table section number. UINT16_MAX if not found. */
851 uint16_t iSymSh;
852 /** The string table section number. UINT16_MAX if not found. */
853 uint16_t iStrSh;
854
855 /** The symbol table. */
856 Elf64_Sym const *paSymbols;
857 /** The number of symbols in the symbol table. */
858 uint32_t cSymbols;
859
860 /** Pointer to the (symbol) string table if found. */
861 const char *pchStrTab;
862 /** The string table size. */
863 size_t cbStrTab;
864
865} ELFDETAILS;
866typedef ELFDETAILS *PELFDETAILS;
867typedef ELFDETAILS const *PCELFDETAILS;
868
869
870static bool validateElf(const char *pszFile, uint8_t const *pbFile, size_t cbFile, PELFDETAILS pElfStuff)
871{
872 /*
873 * Initialize the ELF details structure.
874 */
875 memset(pElfStuff, 0, sizeof(*pElfStuff));
876 pElfStuff->iSymSh = UINT16_MAX;
877 pElfStuff->iStrSh = UINT16_MAX;
878
879 /*
880 * Validate the header and our other expectations.
881 */
882 Elf64_Ehdr const *pEhdr = (Elf64_Ehdr const *)pbFile;
883 pElfStuff->pEhdr = pEhdr;
884 if ( pEhdr->e_ident[EI_CLASS] != ELFCLASS64
885 || pEhdr->e_ident[EI_DATA] != ELFDATA2LSB
886 || pEhdr->e_ehsize != sizeof(Elf64_Ehdr)
887 || pEhdr->e_shentsize != sizeof(Elf64_Shdr)
888 || pEhdr->e_version != EV_CURRENT )
889 return error(pszFile, "Unsupported ELF config\n");
890 if (pEhdr->e_type != ET_REL)
891 return error(pszFile, "Expected relocatable ELF file (e_type=%d)\n", pEhdr->e_type);
892 if (pEhdr->e_machine != EM_X86_64)
893 return error(pszFile, "Expected relocatable ELF file (e_type=%d)\n", pEhdr->e_machine);
894 if (pEhdr->e_phnum != 0)
895 return error(pszFile, "Expected e_phnum to be zero not %u\n", pEhdr->e_phnum);
896 if (pEhdr->e_shnum < 2)
897 return error(pszFile, "Expected e_shnum to be two or higher\n");
898 if (pEhdr->e_shstrndx >= pEhdr->e_shnum || pEhdr->e_shstrndx == 0)
899 return error(pszFile, "Bad e_shstrndx=%u (e_shnum=%u)\n", pEhdr->e_shstrndx, pEhdr->e_shnum);
900 if ( pEhdr->e_shoff >= cbFile
901 || pEhdr->e_shoff + pEhdr->e_shnum * sizeof(Elf64_Shdr) > cbFile)
902 return error(pszFile, "Section table is outside the file (e_shoff=%#llx, e_shnum=%u, cbFile=%#llx)\n",
903 pEhdr->e_shstrndx, pEhdr->e_shnum, (uint64_t)cbFile);
904
905 /*
906 * Locate the section name string table.
907 * We assume it's okay as we only reference it in verbose mode.
908 */
909 Elf64_Shdr const *paShdrs = (Elf64_Shdr const *)&pbFile[pEhdr->e_shoff];
910 pElfStuff->paShdrs = paShdrs;
911
912 Elf64_Xword const cbShStrTab = paShdrs[pEhdr->e_shstrndx].sh_size;
913 if ( paShdrs[pEhdr->e_shstrndx].sh_offset > cbFile
914 || cbShStrTab > cbFile
915 || paShdrs[pEhdr->e_shstrndx].sh_offset + cbShStrTab > cbFile)
916 return error(pszFile,
917 "Section string table is outside the file (sh_offset=%#" ELF_FMT_X64 " sh_size=%#" ELF_FMT_X64 " cbFile=%#" ELF_FMT_X64 ")\n",
918 paShdrs[pEhdr->e_shstrndx].sh_offset, paShdrs[pEhdr->e_shstrndx].sh_size, (Elf64_Xword)cbFile);
919 const char *pchShStrTab = (const char *)&pbFile[paShdrs[pEhdr->e_shstrndx].sh_offset];
920 pElfStuff->pchShStrTab = pchShStrTab;
921
922 /*
923 * Work the section table.
924 */
925 bool fRet = true;
926 for (uint32_t i = 1; i < pEhdr->e_shnum; i++)
927 {
928 if (paShdrs[i].sh_name >= cbShStrTab)
929 return error(pszFile, "Invalid sh_name value (%#x) for section #%u\n", paShdrs[i].sh_name, i);
930 const char *pszShNm = &pchShStrTab[paShdrs[i].sh_name];
931
932 if ( paShdrs[i].sh_offset > cbFile
933 || paShdrs[i].sh_size > cbFile
934 || paShdrs[i].sh_offset + paShdrs[i].sh_size > cbFile)
935 return error(pszFile, "Section #%u '%s' has data outside the file: %#" ELF_FMT_X64 " LB %#" ELF_FMT_X64 " (cbFile=%#" ELF_FMT_X64 ")\n",
936 i, pszShNm, paShdrs[i].sh_offset, paShdrs[i].sh_size, (Elf64_Xword)cbFile);
937 if (g_cVerbose)
938 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"
939 " link=%u info=%#x align=%#" ELF_FMT_X64 " entsize=%#" ELF_FMT_X64 "\n",
940 i, paShdrs[i].sh_name, pszShNm, paShdrs[i].sh_type, paShdrs[i].sh_flags,
941 paShdrs[i].sh_addr, paShdrs[i].sh_offset, paShdrs[i].sh_size,
942 paShdrs[i].sh_link, paShdrs[i].sh_info, paShdrs[i].sh_addralign, paShdrs[i].sh_entsize);
943
944 if (paShdrs[i].sh_link >= pEhdr->e_shnum)
945 return error(pszFile, "Section #%u '%s' links to a section outside the section table: %#x, max %#x\n",
946 i, pszShNm, paShdrs[i].sh_link, pEhdr->e_shnum);
947 if (!RT_IS_POWER_OF_TWO(paShdrs[i].sh_addralign))
948 return error(pszFile, "Section #%u '%s' alignment value is not a power of two: %#" ELF_FMT_X64 "\n",
949 i, pszShNm, paShdrs[i].sh_addralign);
950 if (!RT_IS_POWER_OF_TWO(paShdrs[i].sh_addralign))
951 return error(pszFile, "Section #%u '%s' alignment value is not a power of two: %#" ELF_FMT_X64 "\n",
952 i, pszShNm, paShdrs[i].sh_addralign);
953 if (paShdrs[i].sh_addr != 0)
954 return error(pszFile, "Section #%u '%s' has non-zero address: %#" ELF_FMT_X64 "\n", i, pszShNm, paShdrs[i].sh_addr);
955
956 if (paShdrs[i].sh_type == SHT_RELA)
957 {
958 if (paShdrs[i].sh_entsize != sizeof(Elf64_Rela))
959 return error(pszFile, "Expected sh_entsize to be %u not %u for section #%u (%s)\n", (unsigned)sizeof(Elf64_Rela),
960 paShdrs[i].sh_entsize, i, pszShNm);
961 uint32_t const cRelocs = paShdrs[i].sh_size / sizeof(Elf64_Rela);
962 if (cRelocs * sizeof(Elf64_Rela) != paShdrs[i].sh_size)
963 return error(pszFile, "Uneven relocation entry count in #%u (%s): sh_size=%#" ELF_FMT_X64 "\n",
964 i, pszShNm, paShdrs[i].sh_size);
965 if ( paShdrs[i].sh_offset > cbFile
966 || paShdrs[i].sh_size >= cbFile
967 || paShdrs[i].sh_offset + paShdrs[i].sh_size > cbFile)
968 return error(pszFile, "The content of section #%u '%s' is outside the file (%#" ELF_FMT_X64 " LB %#" ELF_FMT_X64 ", cbFile=%#lx)\n",
969 i, pszShNm, paShdrs[i].sh_offset, paShdrs[i].sh_size, (unsigned long)cbFile);
970 if (paShdrs[i].sh_info != i - 1)
971 return error(pszFile, "Expected relocation section #%u (%s) to link to previous section: sh_info=%#u\n",
972 i, pszShNm, (unsigned)paShdrs[i].sh_link);
973 if (paShdrs[paShdrs[i].sh_link].sh_type != SHT_SYMTAB)
974 return error(pszFile, "Expected relocation section #%u (%s) to link to symbol table: sh_link=%#u -> sh_type=%#x\n",
975 i, pszShNm, (unsigned)paShdrs[i].sh_link, (unsigned)paShdrs[paShdrs[i].sh_link].sh_type);
976 uint32_t cSymbols = paShdrs[paShdrs[i].sh_link].sh_size / paShdrs[paShdrs[i].sh_link].sh_entsize;
977
978 Elf64_Rela const *paRelocs = (Elf64_Rela *)&pbFile[paShdrs[i].sh_offset];
979 for (uint32_t j = 0; j < cRelocs; j++)
980 {
981 uint8_t const bType = ELF64_R_TYPE(paRelocs[j].r_info);
982 if (RT_UNLIKELY(bType >= R_X86_64_COUNT))
983 fRet = error(pszFile,
984 "%#018" ELF_FMT_X64 " %#018" ELF_FMT_X64 ": unknown fix up %#x (%+" ELF_FMT_D64 ")\n",
985 paRelocs[j].r_offset, paRelocs[j].r_info, bType, paRelocs[j].r_addend);
986 if (RT_UNLIKELY( paRelocs[j].r_offset > paShdrs[i - 1].sh_size
987 || paRelocs[j].r_offset + ELF_AMD64_RELOC_SIZE(ELF64_R_TYPE(paRelocs[j].r_info))
988 > paShdrs[i - 1].sh_size))
989 fRet = error(pszFile,
990 "%#018" ELF_FMT_X64 " %#018" ELF_FMT_X64 ": out of bounds (sh_size %" ELF_FMT_X64 ")\n",
991 paRelocs[j].r_offset, paRelocs[j].r_info, paShdrs[i - 1].sh_size);
992
993 uint32_t const iSymbol = ELF64_R_SYM(paRelocs[j].r_info);
994 if (RT_UNLIKELY(iSymbol >= cSymbols))
995 fRet = error(pszFile,
996 "%#018" ELF_FMT_X64 " %#018" ELF_FMT_X64 ": symbol index (%#x) out of bounds (%#x)\n",
997 paRelocs[j].r_offset, paRelocs[j].r_info, iSymbol, cSymbols);
998 }
999 }
1000 else if (paShdrs[i].sh_type == SHT_REL)
1001 fRet = error(pszFile, "Section #%u '%s': Unexpected SHT_REL section\n", i, pszShNm);
1002 else if (paShdrs[i].sh_type == SHT_SYMTAB)
1003 {
1004 if (paShdrs[i].sh_entsize != sizeof(Elf64_Sym))
1005 fRet = error(pszFile, "Section #%u '%s': Unsupported symbol table entry size in : #%u (expected #%u)\n",
1006 i, pszShNm, paShdrs[i].sh_entsize, sizeof(Elf64_Sym));
1007 Elf64_Xword const cSymbols = paShdrs[i].sh_size / paShdrs[i].sh_entsize;
1008 if (cSymbols * paShdrs[i].sh_entsize != paShdrs[i].sh_size)
1009 fRet = error(pszFile, "Section #%u '%s': Size not a multiple of entry size: %#" ELF_FMT_X64 " %% %#" ELF_FMT_X64 " = %#" ELF_FMT_X64 "\n",
1010 i, pszShNm, paShdrs[i].sh_size, paShdrs[i].sh_entsize, paShdrs[i].sh_size % paShdrs[i].sh_entsize);
1011 if (cSymbols > UINT32_MAX)
1012 fRet = error(pszFile, "Section #%u '%s': too many symbols: %" ELF_FMT_X64 "\n",
1013 i, pszShNm, paShdrs[i].sh_size, cSymbols);
1014
1015 if (pElfStuff->iSymSh == UINT16_MAX)
1016 {
1017 pElfStuff->iSymSh = (uint16_t)i;
1018 pElfStuff->paSymbols = (Elf64_Sym const *)&pbFile[paShdrs[i].sh_offset];
1019 pElfStuff->cSymbols = cSymbols;
1020
1021 if (paShdrs[i].sh_link != 0)
1022 {
1023 /* Note! The symbol string table section header may not have been validated yet! */
1024 Elf64_Shdr const *pStrTabShdr = &paShdrs[paShdrs[i].sh_link];
1025 pElfStuff->iStrSh = paShdrs[i].sh_link;
1026 pElfStuff->pchStrTab = (const char *)&pbFile[pStrTabShdr->sh_offset];
1027 pElfStuff->cbStrTab = (size_t)pStrTabShdr->sh_size;
1028 }
1029 else
1030 fRet = error(pszFile, "Section #%u '%s': String table link is out of bounds (%#x)\n",
1031 i, pszShNm, paShdrs[i].sh_link);
1032 }
1033 else
1034 fRet = error(pszFile, "Section #%u '%s': Found additonal symbol table, previous in #%u\n",
1035 i, pszShNm, pElfStuff->iSymSh);
1036 }
1037 }
1038 return fRet;
1039}
1040
1041
1042static bool convertElfSectionsToSegDefsAndGrpDefs(POMFWRITER pThis, PCELFDETAILS pElfStuff)
1043{
1044 /*
1045 * Do the list of names pass.
1046 */
1047 uint16_t idxGrpFlat, idxGrpData;
1048 uint16_t idxClassCode, idxClassData, idxClassDwarf;
1049 if ( !omfWriter_LNamesBegin(pThis)
1050 || !omfWriter_LNamesAddN(pThis, RT_STR_TUPLE("FLAT"), &idxGrpFlat)
1051 || !omfWriter_LNamesAddN(pThis, RT_STR_TUPLE("BS3DATA64_GROUP"), &idxGrpData)
1052 || !omfWriter_LNamesAddN(pThis, RT_STR_TUPLE("BS3CLASS64CODE"), &idxClassCode)
1053 || !omfWriter_LNamesAddN(pThis, RT_STR_TUPLE("FAR_DATA"), &idxClassData)
1054 || !omfWriter_LNamesAddN(pThis, RT_STR_TUPLE("DWARF"), &idxClassDwarf)
1055 )
1056 return false;
1057
1058 bool fHaveData = false;
1059 Elf64_Shdr const *pShdr = &pElfStuff->paShdrs[1];
1060 Elf64_Half const cSections = pElfStuff->pEhdr->e_shnum;
1061 for (Elf64_Half i = 1; i < cSections; i++, pShdr++)
1062 {
1063 const char *pszName = &pElfStuff->pchShStrTab[pShdr->sh_name];
1064 if (*pszName == '\0')
1065 return error(pThis->pszSrc, "Section #%u has an empty name!\n", i);
1066
1067 switch (pShdr->sh_type)
1068 {
1069 case SHT_PROGBITS:
1070 case SHT_NOBITS:
1071 /* We drop a few sections we don't want:. */
1072 if ( strcmp(pszName, ".comment") != 0 /* compiler info */
1073 && strcmp(pszName, ".note.GNU-stack") != 0 /* some empty section for hinting the linker/whatever */
1074 && strcmp(pszName, ".eh_frame") != 0 /* unwind / exception info */
1075 )
1076 {
1077 pThis->paSegments[i].iSegDef = UINT16_MAX;
1078 pThis->paSegments[i].iGrpDef = UINT16_MAX;
1079
1080 /* Translate the name and determine group and class.
1081 Note! We currently strip sub-sections. */
1082 if ( strcmp(pszName, ".text") == 0
1083 || strncmp(pszName, RT_STR_TUPLE(".text.")) == 0)
1084 {
1085 pszName = "BS3TEXT64";
1086 pThis->paSegments[i].iGrpNm = idxGrpFlat;
1087 pThis->paSegments[i].iClassNm = idxClassCode;
1088 }
1089 else if ( strcmp(pszName, ".data") == 0
1090 || strncmp(pszName, RT_STR_TUPLE(".data.")) == 0)
1091 {
1092 pszName = "BS3DATA64";
1093 pThis->paSegments[i].iGrpNm = idxGrpData;
1094 pThis->paSegments[i].iClassNm = idxClassData;
1095 }
1096 else if (strcmp(pszName, ".bss") == 0)
1097 {
1098 pszName = "BS3BSS64";
1099 pThis->paSegments[i].iGrpNm = idxGrpData;
1100 pThis->paSegments[i].iClassNm = idxClassData;
1101 }
1102 else if ( strcmp(pszName, ".rodata") == 0
1103 || strncmp(pszName, RT_STR_TUPLE(".rodata.")) == 0)
1104 {
1105 pszName = "BS3DATA64CONST";
1106 pThis->paSegments[i].iGrpNm = idxGrpData;
1107 pThis->paSegments[i].iClassNm = idxClassData;
1108 }
1109 else if (strncmp(pszName, RT_STR_TUPLE(".debug_")) == 0)
1110 {
1111 pThis->paSegments[i].iGrpNm = UINT16_MAX;
1112 pThis->paSegments[i].iClassNm = idxClassDwarf;
1113 }
1114 else
1115 {
1116 pThis->paSegments[i].iGrpNm = idxGrpData;
1117 pThis->paSegments[i].iClassNm = idxClassData;
1118 error(pThis->pszSrc, "Unknown data (?) segment: '%s'\n", pszName);
1119 }
1120
1121 /* Save the name. */
1122 pThis->paSegments[i].pszName = strdup(pszName);
1123 if (!pThis->paSegments[i].pszName)
1124 return error(pThis->pszSrc, "Out of memory!\n");
1125
1126 /* Add the section name. */
1127 if (!omfWriter_LNamesAdd(pThis, pThis->paSegments[i].pszName, &pThis->paSegments[i].iSegNm))
1128 return false;
1129
1130 fHaveData |= pThis->paSegments[i].iGrpNm == idxGrpData;
1131 break;
1132 }
1133 /* fall thru */
1134
1135 default:
1136 pThis->paSegments[i].iSegDef = UINT16_MAX;
1137 pThis->paSegments[i].iGrpDef = UINT16_MAX;
1138 pThis->paSegments[i].iSegNm = UINT16_MAX;
1139 pThis->paSegments[i].iGrpNm = UINT16_MAX;
1140 pThis->paSegments[i].iClassNm = UINT16_MAX;
1141 pThis->paSegments[i].pszName = NULL;
1142 break;
1143 }
1144 }
1145
1146 if (!omfWriter_LNamesEnd(pThis))
1147 return false;
1148
1149 /*
1150 * Emit segment definitions.
1151 */
1152 uint16_t iSegDef = 1; /* Start counting at 1. */
1153 pShdr = &pElfStuff->paShdrs[1];
1154 for (Elf64_Half i = 1; i < cSections; i++, pShdr++)
1155 {
1156 if (pThis->paSegments[i].iSegNm == UINT16_MAX)
1157 continue;
1158
1159 uint8_t bSegAttr = 0;
1160
1161 /* The A field. */
1162 switch (pShdr->sh_addralign)
1163 {
1164 case 0:
1165 case 1:
1166 bSegAttr |= 1 << 5;
1167 break;
1168 case 2:
1169 bSegAttr |= 2 << 5;
1170 break;
1171 case 4:
1172 bSegAttr |= 5 << 5;
1173 break;
1174 case 8:
1175 case 16:
1176 bSegAttr |= 3 << 5;
1177 break;
1178 case 32:
1179 case 64:
1180 case 128:
1181 case 256:
1182 bSegAttr |= 4 << 5;
1183 break;
1184 default:
1185 bSegAttr |= 6 << 5; /* page aligned, pharlabs extension. */
1186 break;
1187 }
1188
1189 /* The C field. */
1190 bSegAttr |= 2 << 2; /* public */
1191
1192 /* The B field. We don't have 4GB segments, so leave it as zero. */
1193
1194 /* The D field shall be set as we're doing USE32. */
1195 bSegAttr |= 1;
1196
1197
1198 /* Done. */
1199 if (!omfWriter_SegDef(pThis, bSegAttr, (uint32_t)pShdr->sh_size,
1200 pThis->paSegments[i].iSegNm,
1201 pThis->paSegments[i].iClassNm))
1202 return false;
1203 pThis->paSegments[i].iSegDef = iSegDef++;
1204 }
1205
1206 /*
1207 * Flat group definition (#1) - special, no members.
1208 */
1209 uint16_t iGrpDef = 1;
1210 if ( !omfWriter_GrpDefBegin(pThis, idxGrpFlat)
1211 || !omfWriter_GrpDefEnd(pThis))
1212 return false;
1213 for (uint16_t i = 0; i < cSections; i++)
1214 if (pThis->paSegments[i].iGrpNm == idxGrpFlat)
1215 pThis->paSegments[i].iGrpDef = iGrpDef;
1216 pThis->idxGrpFlat = iGrpDef++;
1217
1218 /*
1219 * Data group definition (#2).
1220 */
1221 /** @todo do we need to consider missing segments and ordering? */
1222 uint16_t cGrpNms = 0;
1223 uint16_t aiGrpNms[2];
1224 if (fHaveData)
1225 aiGrpNms[cGrpNms++] = idxGrpData;
1226 for (uint32_t iGrpNm = 0; iGrpNm < cGrpNms; iGrpNm++)
1227 {
1228 if (!omfWriter_GrpDefBegin(pThis, aiGrpNms[iGrpNm]))
1229 return false;
1230 for (uint16_t i = 0; i < cSections; i++)
1231 if (pThis->paSegments[i].iGrpNm == aiGrpNms[iGrpNm])
1232 {
1233 pThis->paSegments[i].iGrpDef = iGrpDef;
1234 if (!omfWriter_GrpDefAddSegDef(pThis, pThis->paSegments[i].iSegDef))
1235 return false;
1236 }
1237 if (!omfWriter_GrpDefEnd(pThis))
1238 return false;
1239 iGrpDef++;
1240 }
1241
1242 return true;
1243}
1244
1245static bool convertElfSymbolsToPubDefsAndExtDefs(POMFWRITER pThis, PCELFDETAILS pElfStuff)
1246{
1247 if (!pElfStuff->cSymbols)
1248 return true;
1249
1250 /*
1251 * Process the symbols the first.
1252 */
1253 uint32_t cAbsSyms = 0;
1254 uint32_t cExtSyms = 0;
1255 uint32_t cPubSyms = 0;
1256 for (uint32_t iSeg = 0; iSeg < pThis->cSegments; iSeg++)
1257 pThis->paSegments[iSeg].cPubDefs = 0;
1258
1259 uint32_t const cSections = pElfStuff->pEhdr->e_shnum;
1260 uint32_t const cSymbols = pElfStuff->cSymbols;
1261 Elf64_Sym const * const paSymbols = pElfStuff->paSymbols;
1262 for (uint32_t iSym = 0; iSym < cSymbols; iSym++)
1263 {
1264 const uint8_t bBind = ELF64_ST_BIND(paSymbols[iSym].st_info);
1265 const uint8_t bType = ELF64_ST_TYPE(paSymbols[iSym].st_info);
1266 const char *pszSymName = &pElfStuff->pchStrTab[paSymbols[iSym].st_name];
1267 if ( *pszSymName == '\0'
1268 && bType == STT_SECTION
1269 && paSymbols[iSym].st_shndx < cSections)
1270 pszSymName = &pElfStuff->pchShStrTab[pElfStuff->paShdrs[paSymbols[iSym].st_shndx].sh_name];
1271
1272 pThis->paSymbols[iSym].enmType = OMFSYMTYPE_IGNORED;
1273 pThis->paSymbols[iSym].idx = UINT16_MAX;
1274 pThis->paSymbols[iSym].idxSegDef = UINT16_MAX;
1275 pThis->paSymbols[iSym].idxGrpDef = UINT16_MAX;
1276
1277 uint32_t const idxSection = paSymbols[iSym].st_shndx;
1278 if (idxSection == SHN_UNDEF)
1279 {
1280 if (bBind == STB_GLOBAL)
1281 {
1282 pThis->paSymbols[iSym].enmType = OMFSYMTYPE_EXTDEF;
1283 cExtSyms++;
1284 if (*pszSymName == '\0')
1285 return error(pThis->pszSrc, "External symbol #%u (%s) has an empty name.\n", iSym, pszSymName);
1286 }
1287 else if (bBind != STB_LOCAL || iSym != 0) /* Entry zero is usually a dummy. */
1288 return error(pThis->pszSrc, "Unsupported or invalid bind type %#x for undefined symbol #%u (%s)\n",
1289 bBind, iSym, pszSymName);
1290 }
1291 else if (idxSection < cSections)
1292 {
1293 pThis->paSymbols[iSym].idxSegDef = pThis->paSegments[idxSection].iSegDef;
1294 pThis->paSymbols[iSym].idxGrpDef = pThis->paSegments[idxSection].iGrpDef;
1295 if (bBind == STB_GLOBAL)
1296 {
1297 pThis->paSymbols[iSym].enmType = OMFSYMTYPE_PUBDEF;
1298 pThis->paSegments[idxSection].cPubDefs++;
1299 cPubSyms++;
1300 if (bType == STT_SECTION)
1301 return error(pThis->pszSrc, "Don't know how to export STT_SECTION symbol #%u (%s)\n", iSym, pszSymName);
1302 if (*pszSymName == '\0')
1303 return error(pThis->pszSrc, "Public symbol #%u (%s) has an empty name.\n", iSym, pszSymName);
1304 }
1305 else if (bType == STT_SECTION)
1306 pThis->paSymbols[iSym].enmType = OMFSYMTYPE_SEGDEF;
1307 else
1308 pThis->paSymbols[iSym].enmType = OMFSYMTYPE_INTERNAL;
1309 }
1310 else if (idxSection == SHN_ABS)
1311 {
1312 if (bType != STT_FILE)
1313 {
1314 if (bBind == STB_GLOBAL)
1315 {
1316 pThis->paSymbols[iSym].enmType = OMFSYMTYPE_PUBDEF;
1317 pThis->paSymbols[iSym].idxSegDef = 0;
1318 pThis->paSymbols[iSym].idxGrpDef = 0;
1319 cAbsSyms++;
1320 if (*pszSymName == '\0')
1321 return error(pThis->pszSrc, "Public absolute symbol #%u (%s) has an empty name.\n", iSym, pszSymName);
1322 }
1323 else
1324 return error(pThis->pszSrc, "Unsupported or invalid bind type %#x for absolute symbol #%u (%s)\n",
1325 bBind, iSym, pszSymName);
1326 }
1327 }
1328 else
1329 return error(pThis->pszSrc, "Unsupported or invalid section number %#x for symbol #%u (%s)\n",
1330 idxSection, iSym, pszSymName);
1331 }
1332
1333 /*
1334 * Emit the PUBDEFs the first time around (see order of records in TIS spec).
1335 */
1336 uint16_t idxPubDef = 1;
1337 if (cPubSyms)
1338 {
1339 for (uint32_t iSeg = 0; iSeg < pThis->cSegments; iSeg++)
1340 if (pThis->paSegments[iSeg].cPubDefs > 0)
1341 {
1342 uint16_t const idxSegDef = pThis->paSegments[iSeg].iSegDef;
1343 if (!omfWriter_PubDefBegin(pThis, pThis->paSegments[iSeg].iGrpDef, idxSegDef))
1344 return false;
1345 for (uint16_t iSym = 0; iSym < cSymbols; iSym++)
1346 if ( pThis->paSymbols[iSym].idxSegDef == idxSegDef
1347 && pThis->paSymbols[iSym].enmType == OMFSYMTYPE_PUBDEF)
1348 {
1349 const char *pszName = &pElfStuff->pchStrTab[paSymbols[iSym].st_name];
1350 if (!omfWriter_PubDefAdd(pThis, paSymbols[iSym].st_value, pszName))
1351 return false;
1352
1353 /* If the symbol doesn't start with an underscore and is a _c64 or _lm64 symbol,
1354 add an underscore prefixed alias to ease access from 16-bit and 32-bit code. */
1355 size_t cchName = strlen(pszName);
1356 if ( *pszName != '_'
1357 && ( (cchName > 4 && strcmp(&pszName[cchName - 4], "_c64") == 0)
1358 || (cchName > 5 && strcmp(&pszName[cchName - 5], "_lm64") == 0) ) )
1359 {
1360 char szCdeclName[512];
1361 if (cchName > sizeof(szCdeclName) - 2)
1362 cchName = sizeof(szCdeclName) - 2;
1363 szCdeclName[0] = '_';
1364 memcpy(&szCdeclName[1], pszName, cchName);
1365 szCdeclName[cchName + 1] = '\0';
1366 if (!omfWriter_PubDefAdd(pThis, paSymbols[iSym].st_value, szCdeclName))
1367 return false;
1368 }
1369
1370 pThis->paSymbols[iSym].idx = idxPubDef++;
1371 }
1372 if (!omfWriter_PubDefEnd(pThis))
1373 return false;
1374 }
1375 }
1376
1377 if (cAbsSyms > 0)
1378 {
1379 if (!omfWriter_PubDefBegin(pThis, 0, 0))
1380 return false;
1381 for (uint16_t iSym = 0; iSym < cSymbols; iSym++)
1382 if ( pThis->paSymbols[iSym].idxSegDef == 0
1383 && pThis->paSymbols[iSym].enmType == OMFSYMTYPE_PUBDEF)
1384 {
1385 const char *pszName = &pElfStuff->pchStrTab[paSymbols[iSym].st_name];
1386 if (!omfWriter_PubDefAdd(pThis, paSymbols[iSym].st_value, pszName))
1387 return false;
1388 pThis->paSymbols[iSym].idx = idxPubDef++;
1389 }
1390 if (!omfWriter_PubDefEnd(pThis))
1391 return false;
1392 }
1393
1394 /*
1395 * Go over the symbol table and emit external definition records.
1396 */
1397 if (!omfWriter_ExtDefBegin(pThis))
1398 return false;
1399 uint16_t idxExtDef = 1;
1400 for (uint16_t iSym = 0; iSym < cSymbols; iSym++)
1401 if (pThis->paSymbols[iSym].enmType == OMFSYMTYPE_EXTDEF)
1402 {
1403 const char *pszName = &pElfStuff->pchStrTab[paSymbols[iSym].st_name];
1404 if (!omfWriter_ExtDefAdd(pThis, pszName))
1405 return false;
1406 pThis->paSymbols[iSym].idx = idxExtDef++;
1407 }
1408
1409 if (!omfWriter_ExtDefEnd(pThis))
1410 return false;
1411
1412 return true;
1413}
1414
1415/**
1416 * @callback_method_impl{FNRTSORTCMP, For Elf64_Rela tables.}
1417 */
1418static DECLCALLBACK(int) convertElfCompareRelA(void const *pvElement1, void const *pvElement2, void *pvUser)
1419{
1420 Elf64_Rela const *pReloc1 = (Elf64_Rela const *)pvElement1;
1421 Elf64_Rela const *pReloc2 = (Elf64_Rela const *)pvElement2;
1422 if (pReloc1->r_offset < pReloc2->r_offset)
1423 return -1;
1424 if (pReloc1->r_offset > pReloc2->r_offset)
1425 return 1;
1426 return 0;
1427}
1428
1429static bool convertElfSectionsToLeDataAndFixupps(POMFWRITER pThis, PCELFDETAILS pElfStuff, uint8_t const *pbFile, size_t cbFile)
1430{
1431 Elf64_Sym const *paSymbols = pElfStuff->paSymbols;
1432 Elf64_Shdr const *paShdrs = pElfStuff->paShdrs;
1433 bool fRet = true;
1434 for (uint32_t i = 1; i < pThis->cSegments; i++)
1435 {
1436 if (pThis->paSegments[i].iSegDef == UINT16_MAX)
1437 continue;
1438
1439 const char *pszSegNm = &pElfStuff->pchShStrTab[paShdrs[i].sh_name];
1440 bool const fRelocs = i + 1 < pThis->cSegments && paShdrs[i + 1].sh_type == SHT_RELA;
1441 uint32_t cRelocs = fRelocs ? paShdrs[i + 1].sh_size / sizeof(Elf64_Rela) : 0;
1442 Elf64_Rela const *paRelocs = fRelocs ? (Elf64_Rela *)&pbFile[paShdrs[i + 1].sh_offset] : NULL;
1443 Elf64_Xword cbVirtData = paShdrs[i].sh_size;
1444 Elf64_Xword cbData = paShdrs[i].sh_type == SHT_NOBITS ? 0 : cbVirtData;
1445 uint8_t const *pbData = &pbFile[paShdrs[i].sh_offset];
1446 uint32_t off = 0;
1447
1448 /* We sort fixups by r_offset in order to more easily split them into chunks. */
1449 RTSortShell((void *)paRelocs, cRelocs, sizeof(paRelocs[0]), convertElfCompareRelA, NULL);
1450
1451 /* The OMF record size requires us to split larger sections up. To make
1452 life simple, we fill zeros for unitialized (BSS) stuff. */
1453 const uint32_t cbMaxData = RT_MIN(OMF_MAX_RECORD_PAYLOAD - 1 - (pThis->paSegments[i].iSegDef >= 128) - 4 - 1, _1K);
1454 while (cbVirtData > 0)
1455 {
1456 /* Figure out how many bytes to put out in this chunk. Must make sure
1457 fixups doesn't cross chunk boundraries. ASSUMES sorted relocs. */
1458 uint32_t cChunkRelocs = cRelocs;
1459 uint32_t cbChunk = cbVirtData;
1460 uint32_t offEnd = off + cbChunk;
1461 if (cbChunk > cbMaxData)
1462 {
1463 cbChunk = cbMaxData;
1464 offEnd = off + cbChunk;
1465 cChunkRelocs = 0;
1466
1467 /* Quickly determin the reloc range. */
1468 while ( cChunkRelocs < cRelocs
1469 && paRelocs[cChunkRelocs].r_offset < offEnd)
1470 cChunkRelocs++;
1471
1472 /* Ensure final reloc doesn't go beyond chunk. */
1473 while ( cChunkRelocs > 0
1474 && paRelocs[cChunkRelocs - 1].r_offset
1475 + ELF_AMD64_RELOC_SIZE(ELF64_R_TYPE(paRelocs[cChunkRelocs - 1].r_info))
1476 > offEnd)
1477 {
1478 uint32_t cbDrop = offEnd - paRelocs[cChunkRelocs - 1].r_offset;
1479 cbChunk -= cbDrop;
1480 offEnd -= cbDrop;
1481 cChunkRelocs--;
1482 }
1483
1484 if (!cbVirtData)
1485 return error(pThis->pszSrc, "Wtf? cbVirtData is zero!\n");
1486 }
1487 if (g_cVerbose >= 2)
1488 printf("debug: LEDATA off=%#x cb=%#x cRelocs=%#x sect=#%u segdef=%#x grpdef=%#x '%s'\n",
1489 off, cbChunk, cRelocs, i, pThis->paSegments[i].iSegDef, pThis->paSegments[i].iGrpDef, pszSegNm);
1490
1491 /*
1492 * We stash the bytes into the OMF writer record buffer, receiving a
1493 * pointer to the start of it so we can make adjustments if necessary.
1494 */
1495 uint8_t *pbCopy;
1496 if (!omfWriter_LEDataBegin(pThis, pThis->paSegments[i].iSegDef, off, cbChunk, cbData, pbData, &pbCopy))
1497 return false;
1498
1499 /*
1500 * Convert fiuxps.
1501 */
1502 for (uint32_t iReloc = 0; iReloc < cChunkRelocs; iReloc++)
1503 {
1504 /* Get the OMF and ELF data for the symbol the reloc references. */
1505 uint32_t const uType = ELF64_R_TYPE(paRelocs[iReloc].r_info);
1506 uint32_t const iSymbol = ELF64_R_SYM(paRelocs[iReloc].r_info);
1507 Elf64_Sym const * const pElfSym = &paSymbols[iSymbol];
1508 POMFSYMBOL const pOmfSym = &pThis->paSymbols[iSymbol];
1509 const char * const pszSymName = &pElfStuff->pchStrTab[pElfSym->st_name];
1510
1511 /* Calc fixup location in the pending chunk and setup a flexible pointer to it. */
1512 uint16_t offDataRec = (uint16_t)(paRelocs[iReloc].r_offset - off);
1513 RTPTRUNION uLoc;
1514 uLoc.pu8 = &pbCopy[offDataRec];
1515
1516 /* OMF fixup data initialized with typical defaults. */
1517 bool fSelfRel = true;
1518 uint8_t bLocation = OMF_FIX_LOC_32BIT_OFFSET;
1519 uint8_t bFrame = OMF_FIX_F_GRPDEF;
1520 uint16_t idxFrame = pThis->idxGrpFlat;
1521 uint8_t bTarget;
1522 uint16_t idxTarget;
1523 bool fTargetDisp;
1524 uint32_t offTargetDisp;
1525 switch (pOmfSym->enmType)
1526 {
1527 case OMFSYMTYPE_INTERNAL:
1528 case OMFSYMTYPE_PUBDEF:
1529 bTarget = OMF_FIX_T_SEGDEF;
1530 idxTarget = pOmfSym->idxSegDef;
1531 fTargetDisp = true;
1532 offTargetDisp = pElfSym->st_value;
1533 break;
1534
1535 case OMFSYMTYPE_SEGDEF:
1536 bTarget = OMF_FIX_T_SEGDEF_NO_DISP;
1537 idxTarget = pOmfSym->idxSegDef;
1538 fTargetDisp = false;
1539 offTargetDisp = 0;
1540 break;
1541
1542 case OMFSYMTYPE_EXTDEF:
1543 bTarget = OMF_FIX_T_EXTDEF_NO_DISP;
1544 idxTarget = pOmfSym->idx;
1545 fTargetDisp = false;
1546 offTargetDisp = 0;
1547 break;
1548
1549 default:
1550 return error(pThis->pszSrc, "Relocation in segment #%u '%s' references ignored or invalid symbol (%s)\n",
1551 i, pszSegNm, pszSymName);
1552 }
1553
1554 /* Do COFF relocation type conversion. */
1555 switch (uType)
1556 {
1557 case R_X86_64_64:
1558 {
1559 int64_t iAddend = paRelocs[iReloc].r_addend;
1560 if (iAddend > _1G || iAddend < -_1G)
1561 fRet = error(pThis->pszSrc, "R_X86_64_64 with large addend (%" ELF_FMT_D64 ") at %#x in segment #%u '%s'\n",
1562 iAddend, paRelocs[iReloc].r_offset, i, pszSegNm);
1563 *uLoc.pu64 = iAddend;
1564 fSelfRel = false;
1565 break;
1566 }
1567
1568 case R_X86_64_32:
1569 case R_X86_64_32S: /* signed, unsigned, whatever. */
1570 fSelfRel = false;
1571 /* fall thru */
1572 case R_X86_64_PC32:
1573 {
1574 /* defaults are ok, just handle the addend. */
1575 int32_t iAddend = paRelocs[iReloc].r_addend;
1576 if (iAddend != paRelocs[iReloc].r_addend)
1577 fRet = error(pThis->pszSrc, "R_X86_64_PC32 with large addend (%d) at %#x in segment #%u '%s'\n",
1578 iAddend, paRelocs[iReloc].r_offset, i, pszSegNm);
1579 *uLoc.pu32 = iAddend;
1580 break;
1581 }
1582
1583 case R_X86_64_NONE:
1584 continue; /* Ignore this one */
1585
1586 case R_X86_64_GOT32:
1587 case R_X86_64_PLT32:
1588 case R_X86_64_COPY:
1589 case R_X86_64_GLOB_DAT:
1590 case R_X86_64_JMP_SLOT:
1591 case R_X86_64_RELATIVE:
1592 case R_X86_64_GOTPCREL:
1593 case R_X86_64_16:
1594 case R_X86_64_PC16:
1595 case R_X86_64_8:
1596 case R_X86_64_PC8:
1597 case R_X86_64_DTPMOD64:
1598 case R_X86_64_DTPOFF64:
1599 case R_X86_64_TPOFF64:
1600 case R_X86_64_TLSGD:
1601 case R_X86_64_TLSLD:
1602 case R_X86_64_DTPOFF32:
1603 case R_X86_64_GOTTPOFF:
1604 case R_X86_64_TPOFF32:
1605 default:
1606 return error(pThis->pszSrc, "Unsupported fixup type %#x (%s) at rva=%#x in section #%u '%s' against '%s'\n",
1607 uType, g_apszElfAmd64RelTypes[uType], paRelocs[iReloc].r_offset, i, pszSegNm, pszSymName);
1608 }
1609
1610 /* Add the fixup. */
1611 if (idxFrame == UINT16_MAX)
1612 error(pThis->pszSrc, "idxFrame=UINT16_MAX for %s type=%s\n", pszSymName, g_apszElfAmd64RelTypes[uType]);
1613 fRet = omfWriter_LEDataAddFixup(pThis, offDataRec, fSelfRel, bLocation, bFrame, idxFrame,
1614 bTarget, idxTarget, fTargetDisp, offTargetDisp) && fRet;
1615 }
1616
1617 /*
1618 * Write the LEDATA and associated FIXUPPs.
1619 */
1620 if (!omfWriter_LEDataEnd(pThis))
1621 return false;
1622
1623 /*
1624 * Advance.
1625 */
1626 paRelocs += cChunkRelocs;
1627 cRelocs -= cChunkRelocs;
1628 if (cbData > cbChunk)
1629 {
1630 cbData -= cbChunk;
1631 pbData += cbChunk;
1632 }
1633 else
1634 cbData = 0;
1635 off += cbChunk;
1636 cbVirtData -= cbChunk;
1637 }
1638 }
1639
1640 return fRet;
1641}
1642
1643
1644static bool convertElfToOmf(const char *pszFile, uint8_t const *pbFile, size_t cbFile, FILE *pDst)
1645{
1646 /*
1647 * Validate the source file a little.
1648 */
1649 ELFDETAILS ElfStuff;
1650 if (!validateElf(pszFile, pbFile, cbFile, &ElfStuff))
1651 return false;
1652
1653 /*
1654 * Instantiate the OMF writer.
1655 */
1656 POMFWRITER pThis = omfWriter_Create(pszFile, ElfStuff.pEhdr->e_shnum, ElfStuff.cSymbols, pDst);
1657 if (!pThis)
1658 return false;
1659
1660 /*
1661 * Write the OMF object file.
1662 */
1663 if (omfWriter_BeginModule(pThis, pszFile))
1664 {
1665 Elf64_Ehdr const *pEhdr = (Elf64_Ehdr const *)pbFile;
1666 Elf64_Shdr const *paShdrs = (Elf64_Shdr const *)&pbFile[pEhdr->e_shoff];
1667 const char *pszStrTab = (const char *)&pbFile[paShdrs[pEhdr->e_shstrndx].sh_offset];
1668
1669 if ( convertElfSectionsToSegDefsAndGrpDefs(pThis, &ElfStuff)
1670 && convertElfSymbolsToPubDefsAndExtDefs(pThis, &ElfStuff)
1671 && omfWriter_LinkPassSeparator(pThis)
1672 && convertElfSectionsToLeDataAndFixupps(pThis, &ElfStuff, pbFile, cbFile)
1673 && omfWriter_EndModule(pThis) )
1674 {
1675
1676 omfWriter_Destroy(pThis);
1677 return true;
1678 }
1679 }
1680
1681 omfWriter_Destroy(pThis);
1682 return false;
1683}
1684
1685
1686
1687/*********************************************************************************************************************************
1688* COFF -> OMF Converter *
1689*********************************************************************************************************************************/
1690
1691/** AMD64 relocation type names for (Microsoft) COFF. */
1692static const char * const g_apszCoffAmd64RelTypes[] =
1693{
1694 "ABSOLUTE",
1695 "ADDR64",
1696 "ADDR32",
1697 "ADDR32NB",
1698 "REL32",
1699 "REL32_1",
1700 "REL32_2",
1701 "REL32_3",
1702 "REL32_4",
1703 "REL32_5",
1704 "SECTION",
1705 "SECREL",
1706 "SECREL7",
1707 "TOKEN",
1708 "SREL32",
1709 "PAIR",
1710 "SSPAN32"
1711};
1712
1713/** AMD64 relocation type sizes for (Microsoft) COFF. */
1714static uint8_t const g_acbCoffAmd64RelTypes[] =
1715{
1716 8, /* ABSOLUTE */
1717 8, /* ADDR64 */
1718 4, /* ADDR32 */
1719 4, /* ADDR32NB */
1720 4, /* REL32 */
1721 4, /* REL32_1 */
1722 4, /* REL32_2 */
1723 4, /* REL32_3 */
1724 4, /* REL32_4 */
1725 4, /* REL32_5 */
1726 2, /* SECTION */
1727 4, /* SECREL */
1728 1, /* SECREL7 */
1729 0, /* TOKEN */
1730 4, /* SREL32 */
1731 0, /* PAIR */
1732 4, /* SSPAN32 */
1733};
1734
1735/** Macro for getting the size of a AMD64 COFF relocation. */
1736#define COFF_AMD64_RELOC_SIZE(a_Type) ( (a_Type) < RT_ELEMENTS(g_acbCoffAmd64RelTypes) ? g_acbCoffAmd64RelTypes[(a_Type)] : 1)
1737
1738
1739static const char *coffGetSymbolName(PCIMAGE_SYMBOL pSym, const char *pchStrTab, uint32_t cbStrTab, char pszShortName[16])
1740{
1741 if (pSym->N.Name.Short != 0)
1742 {
1743 memcpy(pszShortName, pSym->N.ShortName, 8);
1744 pszShortName[8] = '\0';
1745 return pszShortName;
1746 }
1747 if (pSym->N.Name.Long < cbStrTab)
1748 {
1749 uint32_t const cbLeft = cbStrTab - pSym->N.Name.Long;
1750 const char *pszRet = pchStrTab + pSym->N.Name.Long;
1751 if (memchr(pszRet, '\0', cbLeft) != NULL)
1752 return pszRet;
1753 }
1754 error("<null>", "Invalid string table index %#x!\n", pSym->N.Name.Long);
1755 return "Invalid Symbol Table Entry";
1756}
1757
1758static bool validateCoff(const char *pszFile, uint8_t const *pbFile, size_t cbFile)
1759{
1760 /*
1761 * Validate the header and our other expectations.
1762 */
1763 PIMAGE_FILE_HEADER pHdr = (PIMAGE_FILE_HEADER)pbFile;
1764 if (pHdr->Machine != IMAGE_FILE_MACHINE_AMD64)
1765 return error(pszFile, "Expected IMAGE_FILE_MACHINE_AMD64 not %#x\n", pHdr->Machine);
1766 if (pHdr->SizeOfOptionalHeader != 0)
1767 return error(pszFile, "Expected SizeOfOptionalHeader to be zero, not %#x\n", pHdr->SizeOfOptionalHeader);
1768 if (pHdr->NumberOfSections == 0)
1769 return error(pszFile, "Expected NumberOfSections to be non-zero\n");
1770 uint32_t const cbHeaders = pHdr->NumberOfSections * sizeof(IMAGE_SECTION_HEADER) + sizeof(*pHdr);
1771 if (cbHeaders > cbFile)
1772 return error(pszFile, "Section table goes beyond the end of the of the file (cSections=%#x)\n", pHdr->NumberOfSections);
1773 if (pHdr->NumberOfSymbols)
1774 {
1775 if ( pHdr->PointerToSymbolTable >= cbFile
1776 || pHdr->NumberOfSymbols * (uint64_t)IMAGE_SIZE_OF_SYMBOL > cbFile)
1777 return error(pszFile, "Symbol table goes beyond the end of the of the file (cSyms=%#x, offFile=%#x)\n",
1778 pHdr->NumberOfSymbols, pHdr->PointerToSymbolTable);
1779 }
1780
1781 return true;
1782}
1783
1784
1785static bool convertCoffSectionsToSegDefsAndGrpDefs(POMFWRITER pThis, PCIMAGE_SECTION_HEADER paShdrs, uint16_t cSections)
1786{
1787 /*
1788 * Do the list of names pass.
1789 */
1790 uint16_t idxGrpFlat, idxGrpData;
1791 uint16_t idxClassCode, idxClassData, idxClassDebugSymbols, idxClassDebugTypes;
1792 if ( !omfWriter_LNamesBegin(pThis)
1793 || !omfWriter_LNamesAddN(pThis, RT_STR_TUPLE("FLAT"), &idxGrpFlat)
1794 || !omfWriter_LNamesAddN(pThis, RT_STR_TUPLE("BS3DATA64_GROUP"), &idxGrpData)
1795 || !omfWriter_LNamesAddN(pThis, RT_STR_TUPLE("BS3CLASS64CODE"), &idxClassCode)
1796 || !omfWriter_LNamesAddN(pThis, RT_STR_TUPLE("FAR_DATA"), &idxClassData)
1797 || !omfWriter_LNamesAddN(pThis, RT_STR_TUPLE("DEBSYM"), &idxClassDebugSymbols)
1798 || !omfWriter_LNamesAddN(pThis, RT_STR_TUPLE("DEBTYP"), &idxClassDebugTypes)
1799 )
1800 return false;
1801
1802 bool fHaveData = false;
1803 for (uint16_t i = 0; i < cSections; i++)
1804 {
1805 /* Copy the name and terminate it. */
1806 char szName[32];
1807 memcpy(szName, paShdrs[i].Name, sizeof(paShdrs[i].Name));
1808 unsigned cchName = sizeof(paShdrs[i].Name);
1809 while (cchName > 0 && RT_C_IS_SPACE(szName[cchName - 1]))
1810 cchName--;
1811 if (cchName == 0)
1812 return error(pThis->pszSrc, "Section #%u has an empty name!\n", i);
1813 szName[cchName] = '\0';
1814
1815 if ( (paShdrs[i].Characteristics & (IMAGE_SCN_LNK_REMOVE | IMAGE_SCN_LNK_INFO))
1816 || strcmp(szName, ".pdata") == 0 /* Exception stuff, I think, so discard it. */
1817 || strcmp(szName, ".xdata") == 0 /* Ditto. */ )
1818 {
1819 pThis->paSegments[i].iSegDef = UINT16_MAX;
1820 pThis->paSegments[i].iGrpDef = UINT16_MAX;
1821 pThis->paSegments[i].iSegNm = UINT16_MAX;
1822 pThis->paSegments[i].iGrpNm = UINT16_MAX;
1823 pThis->paSegments[i].iClassNm = UINT16_MAX;
1824 pThis->paSegments[i].pszName = NULL;
1825 }
1826 else
1827 {
1828 /* Translate the name, group and class. */
1829 if (strcmp(szName, ".text") == 0)
1830 {
1831 strcpy(szName, "BS3TEXT64");
1832 pThis->paSegments[i].iGrpNm = idxGrpFlat;
1833 pThis->paSegments[i].iClassNm = idxClassCode;
1834 }
1835 else if (strcmp(szName, ".data") == 0)
1836 {
1837 strcpy(szName, "BS3DATA64");
1838 pThis->paSegments[i].iGrpNm = idxGrpData;
1839 pThis->paSegments[i].iClassNm = idxClassData;
1840 }
1841 else if (strcmp(szName, ".bss") == 0)
1842 {
1843 strcpy(szName, "BS3BSS64");
1844 pThis->paSegments[i].iGrpNm = idxGrpData;
1845 pThis->paSegments[i].iClassNm = idxClassData;
1846 }
1847 else if (strcmp(szName, ".rdata") == 0)
1848 {
1849 strcpy(szName, "BS3DATA64CONST");
1850 pThis->paSegments[i].iGrpNm = idxGrpData;
1851 pThis->paSegments[i].iClassNm = idxClassData;
1852 }
1853 else if (strcmp(szName, ".debug$S") == 0)
1854 {
1855 strcpy(szName, "$$SYMBOLS");
1856 pThis->paSegments[i].iGrpNm = UINT16_MAX;
1857 pThis->paSegments[i].iClassNm = idxClassDebugSymbols;
1858 }
1859 else if (strcmp(szName, ".debug$T") == 0)
1860 {
1861 strcpy(szName, "$$TYPES");
1862 pThis->paSegments[i].iGrpNm = UINT16_MAX;
1863 pThis->paSegments[i].iClassNm = idxClassDebugTypes;
1864 }
1865 else if (paShdrs[i].Characteristics & (IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_CNT_CODE))
1866 {
1867 pThis->paSegments[i].iGrpNm = idxGrpFlat;
1868 pThis->paSegments[i].iClassNm = idxClassCode;
1869 error(pThis->pszSrc, "Unknown code segment: '%s'\n", szName);
1870 }
1871 else
1872 {
1873 pThis->paSegments[i].iGrpNm = idxGrpData;
1874 pThis->paSegments[i].iClassNm = idxClassData;
1875 error(pThis->pszSrc, "Unknown data (?) segment: '%s'\n", szName);
1876 }
1877
1878 /* Save the name. */
1879 pThis->paSegments[i].pszName = strdup(szName);
1880 if (!pThis->paSegments[i].pszName)
1881 return error(pThis->pszSrc, "Out of memory!\n");
1882
1883 /* Add the section name. */
1884 if (!omfWriter_LNamesAdd(pThis, pThis->paSegments[i].pszName, &pThis->paSegments[i].iSegNm))
1885 return false;
1886
1887 fHaveData |= pThis->paSegments[i].iGrpNm == idxGrpData;
1888 }
1889 }
1890
1891 if (!omfWriter_LNamesEnd(pThis))
1892 return false;
1893
1894 /*
1895 * Emit segment definitions.
1896 */
1897 uint16_t iSegDef = 1; /* Start counting at 1. */
1898 for (uint16_t i = 0; i < cSections; i++)
1899 {
1900 if (pThis->paSegments[i].iSegDef == UINT16_MAX)
1901 continue;
1902
1903 uint8_t bSegAttr = 0;
1904
1905 /* The A field. */
1906 switch (paShdrs[i].Characteristics & IMAGE_SCN_ALIGN_MASK)
1907 {
1908 default:
1909 case IMAGE_SCN_ALIGN_1BYTES:
1910 bSegAttr |= 1 << 5;
1911 break;
1912 case IMAGE_SCN_ALIGN_2BYTES:
1913 bSegAttr |= 2 << 5;
1914 break;
1915 case IMAGE_SCN_ALIGN_4BYTES:
1916 bSegAttr |= 5 << 5;
1917 break;
1918 case IMAGE_SCN_ALIGN_8BYTES:
1919 case IMAGE_SCN_ALIGN_16BYTES:
1920 bSegAttr |= 3 << 5;
1921 break;
1922 case IMAGE_SCN_ALIGN_32BYTES:
1923 case IMAGE_SCN_ALIGN_64BYTES:
1924 case IMAGE_SCN_ALIGN_128BYTES:
1925 case IMAGE_SCN_ALIGN_256BYTES:
1926 bSegAttr |= 4 << 5;
1927 break;
1928 case IMAGE_SCN_ALIGN_512BYTES:
1929 case IMAGE_SCN_ALIGN_1024BYTES:
1930 case IMAGE_SCN_ALIGN_2048BYTES:
1931 case IMAGE_SCN_ALIGN_4096BYTES:
1932 case IMAGE_SCN_ALIGN_8192BYTES:
1933 bSegAttr |= 6 << 5; /* page aligned, pharlabs extension. */
1934 break;
1935 }
1936
1937 /* The C field. */
1938 bSegAttr |= 2 << 2; /* public */
1939
1940 /* The B field. We don't have 4GB segments, so leave it as zero. */
1941
1942 /* The D field shall be set as we're doing USE32. */
1943 bSegAttr |= 1;
1944
1945
1946 /* Done. */
1947 if (!omfWriter_SegDef(pThis, bSegAttr, paShdrs[i].SizeOfRawData,
1948 pThis->paSegments[i].iSegNm,
1949 pThis->paSegments[i].iClassNm))
1950 return false;
1951 pThis->paSegments[i].iSegDef = iSegDef++;
1952 }
1953
1954 /*
1955 * Flat group definition (#1) - special, no members.
1956 */
1957 uint16_t iGrpDef = 1;
1958 if ( !omfWriter_GrpDefBegin(pThis, idxGrpFlat)
1959 || !omfWriter_GrpDefEnd(pThis))
1960 return false;
1961 for (uint16_t i = 0; i < cSections; i++)
1962 if (pThis->paSegments[i].iGrpNm == idxGrpFlat)
1963 pThis->paSegments[i].iGrpDef = iGrpDef;
1964 pThis->idxGrpFlat = iGrpDef++;
1965
1966 /*
1967 * Data group definition (#2).
1968 */
1969 /** @todo do we need to consider missing segments and ordering? */
1970 uint16_t cGrpNms = 0;
1971 uint16_t aiGrpNms[2];
1972 if (fHaveData)
1973 aiGrpNms[cGrpNms++] = idxGrpData;
1974 for (uint32_t iGrpNm = 0; iGrpNm < cGrpNms; iGrpNm++)
1975 {
1976 if (!omfWriter_GrpDefBegin(pThis, aiGrpNms[iGrpNm]))
1977 return false;
1978 for (uint16_t i = 0; i < cSections; i++)
1979 if (pThis->paSegments[i].iGrpNm == aiGrpNms[iGrpNm])
1980 {
1981 pThis->paSegments[i].iGrpDef = iGrpDef;
1982 if (!omfWriter_GrpDefAddSegDef(pThis, pThis->paSegments[i].iSegDef))
1983 return false;
1984 }
1985 if (!omfWriter_GrpDefEnd(pThis))
1986 return false;
1987 iGrpDef++;
1988 }
1989
1990 return true;
1991}
1992
1993/**
1994 * This is for matching STATIC symbols with value 0 against the section name,
1995 * to see if it's a section reference or symbol at offset 0 reference.
1996 *
1997 * @returns true / false.
1998 * @param pszSymbol The symbol name.
1999 * @param pachSectName8 The section name (8-bytes).
2000 */
2001static bool isCoffSymbolMatchingSectionName(const char *pszSymbol, uint8_t const pachSectName8[8])
2002{
2003 uint32_t off = 0;
2004 char ch;
2005 while (off < 8 && (ch = pszSymbol[off]) != '\0')
2006 {
2007 if (ch != pachSectName8[off])
2008 return false;
2009 off++;
2010 }
2011 while (off < 8)
2012 {
2013 if (!RT_C_IS_SPACE((ch = pachSectName8[off])))
2014 return ch == '\0';
2015 off++;
2016 }
2017 return true;
2018}
2019
2020static bool convertCoffSymbolsToPubDefsAndExtDefs(POMFWRITER pThis, PCIMAGE_SYMBOL paSymbols, uint16_t cSymbols,
2021 const char *pchStrTab, PCIMAGE_SECTION_HEADER paShdrs)
2022{
2023
2024 if (!cSymbols)
2025 return true;
2026 uint32_t const cbStrTab = *(uint32_t const *)pchStrTab;
2027 char szShort[16];
2028
2029 /*
2030 * Process the symbols the first.
2031 */
2032 uint32_t iSymImageBase = UINT32_MAX;
2033 uint32_t cAbsSyms = 0;
2034 uint32_t cExtSyms = 0;
2035 uint32_t cPubSyms = 0;
2036 for (uint32_t iSeg = 0; iSeg < pThis->cSegments; iSeg++)
2037 pThis->paSegments[iSeg].cPubDefs = 0;
2038
2039 for (uint16_t iSym = 0; iSym < cSymbols; iSym++)
2040 {
2041 const char *pszSymName = coffGetSymbolName(&paSymbols[iSym], pchStrTab, cbStrTab, szShort);
2042
2043 pThis->paSymbols[iSym].enmType = OMFSYMTYPE_IGNORED;
2044 pThis->paSymbols[iSym].idx = UINT16_MAX;
2045 pThis->paSymbols[iSym].idxSegDef = UINT16_MAX;
2046 pThis->paSymbols[iSym].idxGrpDef = UINT16_MAX;
2047
2048 int16_t const idxSection = paSymbols[iSym].SectionNumber;
2049 if ( (idxSection >= 1 && idxSection <= (int32_t)pThis->cSegments)
2050 || idxSection == IMAGE_SYM_ABSOLUTE)
2051 {
2052 switch (paSymbols[iSym].StorageClass)
2053 {
2054 case IMAGE_SYM_CLASS_EXTERNAL:
2055 if (idxSection != IMAGE_SYM_ABSOLUTE)
2056 {
2057 if (pThis->paSegments[idxSection - 1].iSegDef != UINT16_MAX)
2058 {
2059 pThis->paSymbols[iSym].enmType = OMFSYMTYPE_PUBDEF;
2060 pThis->paSymbols[iSym].idxSegDef = pThis->paSegments[idxSection - 1].iSegDef;
2061 pThis->paSymbols[iSym].idxGrpDef = pThis->paSegments[idxSection - 1].iGrpDef;
2062 pThis->paSegments[idxSection - 1].cPubDefs++;
2063 cPubSyms++;
2064 }
2065 }
2066 else
2067 {
2068 pThis->paSymbols[iSym].enmType = OMFSYMTYPE_PUBDEF;
2069 pThis->paSymbols[iSym].idxSegDef = 0;
2070 pThis->paSymbols[iSym].idxGrpDef = 0;
2071 cAbsSyms++;
2072 }
2073 break;
2074
2075 case IMAGE_SYM_CLASS_STATIC:
2076 if ( paSymbols[iSym].Value == 0
2077 && idxSection != IMAGE_SYM_ABSOLUTE
2078 && isCoffSymbolMatchingSectionName(pszSymName, paShdrs[idxSection - 1].Name) )
2079 {
2080 pThis->paSymbols[iSym].enmType = OMFSYMTYPE_SEGDEF;
2081 pThis->paSymbols[iSym].idxSegDef = pThis->paSegments[idxSection - 1].iSegDef;
2082 pThis->paSymbols[iSym].idxGrpDef = pThis->paSegments[idxSection - 1].iGrpDef;
2083 break;
2084 }
2085 /* fall thru */
2086
2087 case IMAGE_SYM_CLASS_END_OF_FUNCTION:
2088 case IMAGE_SYM_CLASS_AUTOMATIC:
2089 case IMAGE_SYM_CLASS_REGISTER:
2090 case IMAGE_SYM_CLASS_LABEL:
2091 case IMAGE_SYM_CLASS_MEMBER_OF_STRUCT:
2092 case IMAGE_SYM_CLASS_ARGUMENT:
2093 case IMAGE_SYM_CLASS_STRUCT_TAG:
2094 case IMAGE_SYM_CLASS_MEMBER_OF_UNION:
2095 case IMAGE_SYM_CLASS_UNION_TAG:
2096 case IMAGE_SYM_CLASS_TYPE_DEFINITION:
2097 case IMAGE_SYM_CLASS_ENUM_TAG:
2098 case IMAGE_SYM_CLASS_MEMBER_OF_ENUM:
2099 case IMAGE_SYM_CLASS_REGISTER_PARAM:
2100 case IMAGE_SYM_CLASS_BIT_FIELD:
2101 case IMAGE_SYM_CLASS_BLOCK:
2102 case IMAGE_SYM_CLASS_FUNCTION:
2103 case IMAGE_SYM_CLASS_END_OF_STRUCT:
2104 case IMAGE_SYM_CLASS_FILE:
2105 pThis->paSymbols[iSym].enmType = OMFSYMTYPE_INTERNAL;
2106 if (idxSection != IMAGE_SYM_ABSOLUTE)
2107 {
2108 pThis->paSymbols[iSym].idxSegDef = pThis->paSegments[idxSection - 1].iSegDef;
2109 pThis->paSymbols[iSym].idxGrpDef = pThis->paSegments[idxSection - 1].iGrpDef;
2110 }
2111 else
2112 {
2113 pThis->paSymbols[iSym].idxSegDef = 0;
2114 pThis->paSymbols[iSym].idxGrpDef = 0;
2115 }
2116 break;
2117
2118 case IMAGE_SYM_CLASS_SECTION:
2119 case IMAGE_SYM_CLASS_EXTERNAL_DEF:
2120 case IMAGE_SYM_CLASS_NULL:
2121 case IMAGE_SYM_CLASS_UNDEFINED_LABEL:
2122 case IMAGE_SYM_CLASS_UNDEFINED_STATIC:
2123 case IMAGE_SYM_CLASS_CLR_TOKEN:
2124 case IMAGE_SYM_CLASS_FAR_EXTERNAL:
2125 case IMAGE_SYM_CLASS_WEAK_EXTERNAL:
2126 return error(pThis->pszSrc, "Unsupported storage class value %#x for symbol #%u (%s)\n",
2127 paSymbols[iSym].StorageClass, iSym, pszSymName);
2128
2129 default:
2130 return error(pThis->pszSrc, "Unknown storage class value %#x for symbol #%u (%s)\n",
2131 paSymbols[iSym].StorageClass, iSym, pszSymName);
2132 }
2133 }
2134 else if (idxSection == IMAGE_SYM_UNDEFINED)
2135 {
2136 if ( paSymbols[iSym].StorageClass == IMAGE_SYM_CLASS_EXTERNAL
2137 || paSymbols[iSym].StorageClass == IMAGE_SYM_CLASS_EXTERNAL_DEF)
2138 {
2139 pThis->paSymbols[iSym].enmType = OMFSYMTYPE_EXTDEF;
2140 cExtSyms++;
2141 if (iSymImageBase == UINT32_MAX && strcmp(pszSymName, "__ImageBase") == 0)
2142 iSymImageBase = iSym;
2143 }
2144 else
2145 return error(pThis->pszSrc, "Unknown/unknown storage class value %#x for undefined symbol #%u (%s)\n",
2146 paSymbols[iSym].StorageClass, iSym, pszSymName);
2147 }
2148 else if (idxSection != IMAGE_SYM_DEBUG)
2149 return error(pThis->pszSrc, "Invalid section number %#x for symbol #%u (%s)\n", idxSection, iSym, pszSymName);
2150
2151 /* Skip AUX symbols. */
2152 uint8_t cAuxSyms = paSymbols[iSym].NumberOfAuxSymbols;
2153 while (cAuxSyms-- > 0)
2154 {
2155 iSym++;
2156 pThis->paSymbols[iSym].enmType = OMFSYMTYPE_INVALID;
2157 pThis->paSymbols[iSym].idx = UINT16_MAX;
2158 }
2159 }
2160
2161 /*
2162 * Emit the PUBDEFs the first time around (see order of records in TIS spec).
2163 */
2164 uint16_t idxPubDef = 1;
2165 if (cPubSyms)
2166 {
2167 for (uint32_t iSeg = 0; iSeg < pThis->cSegments; iSeg++)
2168 if (pThis->paSegments[iSeg].cPubDefs > 0)
2169 {
2170 uint16_t const idxSegDef = pThis->paSegments[iSeg].iSegDef;
2171 if (!omfWriter_PubDefBegin(pThis, pThis->paSegments[iSeg].iGrpDef, idxSegDef))
2172 return false;
2173 for (uint16_t iSym = 0; iSym < cSymbols; iSym++)
2174 if ( pThis->paSymbols[iSym].idxSegDef == idxSegDef
2175 && pThis->paSymbols[iSym].enmType == OMFSYMTYPE_PUBDEF)
2176 {
2177 const char *pszName = coffGetSymbolName(&paSymbols[iSym], pchStrTab, cbStrTab, szShort);
2178 if (!omfWriter_PubDefAdd(pThis, paSymbols[iSym].Value, pszName))
2179 return false;
2180
2181 /* If the symbol doesn't start with an underscore and is a _c64 or _lm64 symbol,
2182 add an underscore prefixed alias to ease access from 16-bit and 32-bit code. */
2183 size_t cchName = strlen(pszName);
2184 if ( *pszName != '_'
2185 && ( (cchName > 4 && strcmp(&pszName[cchName - 4], "_c64") == 0)
2186 || (cchName > 5 && strcmp(&pszName[cchName - 5], "_lm64") == 0) ) )
2187 {
2188 char szCdeclName[512];
2189 if (cchName > sizeof(szCdeclName) - 2)
2190 cchName = sizeof(szCdeclName) - 2;
2191 szCdeclName[0] = '_';
2192 memcpy(&szCdeclName[1], pszName, cchName);
2193 szCdeclName[cchName + 1] = '\0';
2194 if (!omfWriter_PubDefAdd(pThis, paSymbols[iSym].Value, szCdeclName))
2195 return false;
2196 }
2197
2198 pThis->paSymbols[iSym].idx = idxPubDef++;
2199 }
2200 if (!omfWriter_PubDefEnd(pThis))
2201 return false;
2202 }
2203 }
2204
2205 if (cAbsSyms > 0)
2206 {
2207 if (!omfWriter_PubDefBegin(pThis, 0, 0))
2208 return false;
2209 for (uint16_t iSym = 0; iSym < cSymbols; iSym++)
2210 if ( pThis->paSymbols[iSym].idxSegDef == 0
2211 && pThis->paSymbols[iSym].enmType == OMFSYMTYPE_PUBDEF)
2212 {
2213 if (!omfWriter_PubDefAdd(pThis, paSymbols[iSym].Value,
2214 coffGetSymbolName(&paSymbols[iSym], pchStrTab, cbStrTab, szShort)) )
2215 return false;
2216 pThis->paSymbols[iSym].idx = idxPubDef++;
2217 }
2218 if (!omfWriter_PubDefEnd(pThis))
2219 return false;
2220 }
2221
2222 /*
2223 * Go over the symbol table and emit external definition records.
2224 */
2225 if (!omfWriter_ExtDefBegin(pThis))
2226 return false;
2227 uint16_t idxExtDef = 1;
2228 for (uint16_t iSym = 0; iSym < cSymbols; iSym++)
2229 if (pThis->paSymbols[iSym].enmType == OMFSYMTYPE_EXTDEF)
2230 {
2231 if (!omfWriter_ExtDefAdd(pThis, coffGetSymbolName(&paSymbols[iSym], pchStrTab, cbStrTab, szShort)))
2232 return false;
2233 pThis->paSymbols[iSym].idx = idxExtDef++;
2234 }
2235
2236 /* Always add an __ImageBase reference, in case we need it to deal with ADDR32NB fixups. */
2237 /** @todo maybe we don't actually need this and could use FLAT instead? */
2238 if (iSymImageBase != UINT32_MAX)
2239 pThis->idxExtImageBase = pThis->paSymbols[iSymImageBase].idx;
2240 else if (omfWriter_ExtDefAdd(pThis, "__ImageBase"))
2241 pThis->idxExtImageBase = idxExtDef;
2242 else
2243 return false;
2244
2245 if (!omfWriter_ExtDefEnd(pThis))
2246 return false;
2247
2248 return true;
2249}
2250
2251
2252static bool convertCoffSectionsToLeDataAndFixupps(POMFWRITER pThis, uint8_t const *pbFile, size_t cbFile,
2253 PCIMAGE_SECTION_HEADER paShdrs, uint16_t cSections,
2254 PCIMAGE_SYMBOL paSymbols, uint16_t cSymbols, const char *pchStrTab)
2255{
2256 uint32_t const cbStrTab = *(uint32_t const *)pchStrTab;
2257 bool fRet = true;
2258 for (uint32_t i = 0; i < pThis->cSegments; i++)
2259 {
2260 if (pThis->paSegments[i].iSegDef == UINT16_MAX)
2261 continue;
2262
2263 char szShortName[16];
2264 const char *pszSegNm = pThis->paSegments[i].pszName;
2265 uint16_t cRelocs = paShdrs[i].NumberOfRelocations;
2266 PCIMAGE_RELOCATION paRelocs = (PCIMAGE_RELOCATION)&pbFile[paShdrs[i].PointerToRelocations];
2267 uint32_t cbVirtData = paShdrs[i].SizeOfRawData;
2268 uint32_t cbData = paShdrs[i].Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA ? 0 : cbVirtData;
2269 uint8_t const *pbData = &pbFile[paShdrs[i].PointerToRawData];
2270 uint32_t off = 0;
2271
2272 /* Check that the relocations are sorted and within the section. */
2273 for (uint32_t iReloc = 1; iReloc < cRelocs; iReloc++)
2274 if (paRelocs[iReloc - 1].u.VirtualAddress >= paRelocs[iReloc].u.VirtualAddress)
2275 return error(pThis->pszSrc, "Section #%u (%s) relocations aren't sorted\n", i, pszSegNm);
2276 if ( cRelocs > 0
2277 && paRelocs[cRelocs - 1].u.VirtualAddress - paShdrs[i].VirtualAddress
2278 + COFF_AMD64_RELOC_SIZE(paRelocs[cRelocs - 1].Type) > cbVirtData)
2279 return error(pThis->pszSrc,
2280 "Section #%u (%s) relocations beyond section data! cbVirtData=%#x RvaFix=%#x RVASeg=%#x type=%#x\n",
2281 i, pszSegNm, cbVirtData, paRelocs[cRelocs - 1].u.VirtualAddress, paShdrs[i].VirtualAddress,
2282 paRelocs[cRelocs - 1].Type);
2283
2284 /* The OMF record size requires us to split larger sections up. To make
2285 life simple, we fill zeros for unitialized (BSS) stuff. */
2286 const uint32_t cbMaxData = RT_MIN(OMF_MAX_RECORD_PAYLOAD - 1 - (pThis->paSegments[i].iSegDef >= 128) - 4 - 1, _1K);
2287 while (cbVirtData > 0)
2288 {
2289 /* Figure out how many bytes to put out in this chunk. Must make sure
2290 fixups doesn't cross chunk boundraries. ASSUMES sorted relocs. */
2291 uint32_t cChunkRelocs = cRelocs;
2292 uint32_t cbChunk = cbVirtData;
2293 uint32_t uRvaEnd = paShdrs[i].VirtualAddress + off + cbChunk;
2294 if (cbChunk > cbMaxData)
2295 {
2296 cbChunk = cbMaxData;
2297 uRvaEnd = paShdrs[i].VirtualAddress + off + cbChunk;
2298 cChunkRelocs = 0;
2299
2300 /* Quickly determin the reloc range. */
2301 while ( cChunkRelocs < cRelocs
2302 && paRelocs[cChunkRelocs].u.VirtualAddress < uRvaEnd)
2303 cChunkRelocs++;
2304
2305 /* Ensure final reloc doesn't go beyond chunk. */
2306 while ( cChunkRelocs > 0
2307 && paRelocs[cChunkRelocs - 1].u.VirtualAddress + COFF_AMD64_RELOC_SIZE(paRelocs[cChunkRelocs - 1].Type)
2308 > uRvaEnd)
2309 {
2310 uint32_t cbDrop = uRvaEnd - paRelocs[cChunkRelocs - 1].u.VirtualAddress;
2311 cbChunk -= cbDrop;
2312 uRvaEnd -= cbDrop;
2313 cChunkRelocs--;
2314 }
2315
2316 if (!cbVirtData)
2317 return error(pThis->pszSrc, "Wtf? cbVirtData is zero!\n");
2318 }
2319
2320 /*
2321 * We stash the bytes into the OMF writer record buffer, receiving a
2322 * pointer to the start of it so we can make adjustments if necessary.
2323 */
2324 uint8_t *pbCopy;
2325 if (!omfWriter_LEDataBegin(pThis, pThis->paSegments[i].iSegDef, off, cbChunk, cbData, pbData, &pbCopy))
2326 return false;
2327
2328 /*
2329 * Convert fiuxps.
2330 */
2331 uint32_t const uRvaChunk = paShdrs[i].VirtualAddress + off;
2332 for (uint32_t iReloc = 0; iReloc < cChunkRelocs; iReloc++)
2333 {
2334 /* Get the OMF and COFF data for the symbol the reloc references. */
2335 if (paRelocs[iReloc].SymbolTableIndex >= pThis->cSymbols)
2336 return error(pThis->pszSrc, "Relocation symtab index (%#x) is out of range in segment #%u '%s'\n",
2337 paRelocs[iReloc].SymbolTableIndex, i, pszSegNm);
2338 PCIMAGE_SYMBOL pCoffSym = &paSymbols[paRelocs[iReloc].SymbolTableIndex];
2339 POMFSYMBOL pOmfSym = &pThis->paSymbols[paRelocs[iReloc].SymbolTableIndex];
2340
2341 /* Calc fixup location in the pending chunk and setup a flexible pointer to it. */
2342 uint16_t offDataRec = (uint16_t)(paRelocs[iReloc].u.VirtualAddress - uRvaChunk);
2343 RTPTRUNION uLoc;
2344 uLoc.pu8 = &pbCopy[offDataRec];
2345
2346 /* OMF fixup data initialized with typical defaults. */
2347 bool fSelfRel = true;
2348 uint8_t bLocation = OMF_FIX_LOC_32BIT_OFFSET;
2349 uint8_t bFrame = OMF_FIX_F_GRPDEF;
2350 uint16_t idxFrame = pThis->idxGrpFlat;
2351 uint8_t bTarget;
2352 uint16_t idxTarget;
2353 bool fTargetDisp;
2354 uint32_t offTargetDisp;
2355 switch (pOmfSym->enmType)
2356 {
2357 case OMFSYMTYPE_INTERNAL:
2358 case OMFSYMTYPE_PUBDEF:
2359 bTarget = OMF_FIX_T_SEGDEF;
2360 idxTarget = pOmfSym->idxSegDef;
2361 fTargetDisp = true;
2362 offTargetDisp = pCoffSym->Value;
2363 break;
2364
2365 case OMFSYMTYPE_SEGDEF:
2366 bTarget = OMF_FIX_T_SEGDEF_NO_DISP;
2367 idxTarget = pOmfSym->idxSegDef;
2368 fTargetDisp = false;
2369 offTargetDisp = 0;
2370 break;
2371
2372 case OMFSYMTYPE_EXTDEF:
2373 bTarget = OMF_FIX_T_EXTDEF_NO_DISP;
2374 idxTarget = pOmfSym->idx;
2375 fTargetDisp = false;
2376 offTargetDisp = 0;
2377 break;
2378
2379 default:
2380 return error(pThis->pszSrc, "Relocation in segment #%u '%s' references ignored or invalid symbol (%s)\n",
2381 i, pszSegNm, coffGetSymbolName(pCoffSym, pchStrTab, cbStrTab, szShortName));
2382 }
2383
2384 /* Do COFF relocation type conversion. */
2385 switch (paRelocs[iReloc].Type)
2386 {
2387 case IMAGE_REL_AMD64_ADDR64:
2388 {
2389 uint64_t uAddend = *uLoc.pu64;
2390 if (uAddend > _1G)
2391 fRet = error(pThis->pszSrc, "ADDR64 with large addend (%#llx) at %#x in segment #%u '%s'\n",
2392 uAddend, paRelocs[iReloc].u.VirtualAddress, i, pszSegNm);
2393 fSelfRel = false;
2394 break;
2395 }
2396
2397 case IMAGE_REL_AMD64_REL32_1:
2398 case IMAGE_REL_AMD64_REL32_2:
2399 case IMAGE_REL_AMD64_REL32_3:
2400 case IMAGE_REL_AMD64_REL32_4:
2401 case IMAGE_REL_AMD64_REL32_5:
2402 /** @todo Check whether OMF read addends from the data or relies on the
2403 * displacement. Also, check what it's relative to. */
2404 *uLoc.pu32 -= paRelocs[iReloc].Type - IMAGE_REL_AMD64_REL32;
2405 break;
2406
2407 case IMAGE_REL_AMD64_ADDR32:
2408 fSelfRel = false;
2409 break;
2410
2411 case IMAGE_REL_AMD64_ADDR32NB:
2412 fSelfRel = false;
2413 bFrame = OMF_FIX_F_EXTDEF;
2414 idxFrame = pThis->idxExtImageBase;
2415 break;
2416
2417 case IMAGE_REL_AMD64_REL32:
2418 /* defaults are ok. */
2419 break;
2420
2421 case IMAGE_REL_AMD64_SECTION:
2422 bLocation = OMF_FIX_LOC_16BIT_SEGMENT;
2423 /* fall thru */
2424
2425 case IMAGE_REL_AMD64_SECREL:
2426 fSelfRel = false;
2427 if (pOmfSym->enmType == OMFSYMTYPE_EXTDEF)
2428 {
2429 bFrame = OMF_FIX_F_EXTDEF;
2430 idxFrame = pOmfSym->idx;
2431 }
2432 else
2433 {
2434 bFrame = OMF_FIX_F_SEGDEF;
2435 idxFrame = pOmfSym->idxSegDef;
2436 }
2437 break;
2438
2439 case IMAGE_REL_AMD64_ABSOLUTE:
2440 continue; /* Ignore it like the PECOFF.DOC says we should. */
2441
2442 case IMAGE_REL_AMD64_SECREL7:
2443 default:
2444 return error(pThis->pszSrc, "Unsupported fixup type %#x (%s) at rva=%#x in section #%u '%-8.8s'\n",
2445 paRelocs[iReloc].Type,
2446 paRelocs[iReloc].Type < RT_ELEMENTS(g_apszCoffAmd64RelTypes)
2447 ? g_apszCoffAmd64RelTypes[paRelocs[iReloc].Type] : "unknown",
2448 paRelocs[iReloc].u.VirtualAddress, i, paShdrs[i].Name);
2449 }
2450
2451 /* Add the fixup. */
2452 if (idxFrame == UINT16_MAX)
2453 error(pThis->pszSrc, "idxFrame=UINT16_MAX for %s type=%s\n",
2454 coffGetSymbolName(pCoffSym, pchStrTab, cbStrTab, szShortName),
2455 g_apszCoffAmd64RelTypes[paRelocs[iReloc].Type]);
2456 fRet = omfWriter_LEDataAddFixup(pThis, offDataRec, fSelfRel, bLocation, bFrame, idxFrame,
2457 bTarget, idxTarget, fTargetDisp, offTargetDisp) && fRet;
2458 }
2459
2460 /*
2461 * Write the LEDATA and associated FIXUPPs.
2462 */
2463 if (!omfWriter_LEDataEnd(pThis))
2464 return false;
2465
2466 /*
2467 * Advance.
2468 */
2469 paRelocs += cChunkRelocs;
2470 cRelocs -= cChunkRelocs;
2471 if (cbData > cbChunk)
2472 {
2473 cbData -= cbChunk;
2474 pbData += cbChunk;
2475 }
2476 else
2477 cbData = 0;
2478 off += cbChunk;
2479 cbVirtData -= cbChunk;
2480 }
2481 }
2482
2483 return fRet;
2484}
2485
2486
2487static bool convertCoffToOmf(const char *pszFile, uint8_t const *pbFile, size_t cbFile, FILE *pDst)
2488{
2489 /*
2490 * Validate the source file a little.
2491 */
2492 if (!validateCoff(pszFile, pbFile, cbFile))
2493 return false;
2494
2495 /*
2496 * Instantiate the OMF writer.
2497 */
2498 PIMAGE_FILE_HEADER pHdr = (PIMAGE_FILE_HEADER)pbFile;
2499 POMFWRITER pThis = omfWriter_Create(pszFile, pHdr->NumberOfSections, pHdr->NumberOfSymbols, pDst);
2500 if (!pThis)
2501 return false;
2502
2503 /*
2504 * Write the OMF object file.
2505 */
2506 if (omfWriter_BeginModule(pThis, pszFile))
2507 {
2508 PCIMAGE_SECTION_HEADER paShdrs = (PCIMAGE_SECTION_HEADER)(pHdr + 1);
2509 PCIMAGE_SYMBOL paSymTab = (PCIMAGE_SYMBOL)&pbFile[pHdr->PointerToSymbolTable];
2510 const char *pchStrTab = (const char *)&paSymTab[pHdr->NumberOfSymbols];
2511 if ( convertCoffSectionsToSegDefsAndGrpDefs(pThis, paShdrs, pHdr->NumberOfSections)
2512 && convertCoffSymbolsToPubDefsAndExtDefs(pThis, paSymTab, pHdr->NumberOfSymbols, pchStrTab, paShdrs)
2513 && omfWriter_LinkPassSeparator(pThis)
2514 && convertCoffSectionsToLeDataAndFixupps(pThis, pbFile, cbFile, paShdrs, pHdr->NumberOfSections,
2515 paSymTab, pHdr->NumberOfSymbols, pchStrTab)
2516 && omfWriter_EndModule(pThis) )
2517 {
2518
2519 omfWriter_Destroy(pThis);
2520 return true;
2521 }
2522 }
2523
2524 omfWriter_Destroy(pThis);
2525 return false;
2526}
2527
2528
2529/*********************************************************************************************************************************
2530* Mach-O/AMD64 -> OMF/i386 Converter *
2531*********************************************************************************************************************************/
2532
2533//#define MACHO_TO_OMF_CONVERSION
2534#ifdef MACHO_TO_OMF_CONVERSION
2535
2536/** AMD64 relocation type names for Mach-O. */
2537static const char * const g_apszMachOAmd64RelTypes[] =
2538{
2539 "X86_64_RELOC_UNSIGNED",
2540 "X86_64_RELOC_SIGNED",
2541 "X86_64_RELOC_BRANCH",
2542 "X86_64_RELOC_GOT_LOAD",
2543 "X86_64_RELOC_GOT",
2544 "X86_64_RELOC_SUBTRACTOR",
2545 "X86_64_RELOC_SIGNED_1",
2546 "X86_64_RELOC_SIGNED_2",
2547 "X86_64_RELOC_SIGNED_4"
2548};
2549
2550/** AMD64 relocation type sizes for Mach-O. */
2551static uint8_t const g_acbMachOAmd64RelTypes[] =
2552{
2553 8, /* X86_64_RELOC_UNSIGNED */
2554 4, /* X86_64_RELOC_SIGNED */
2555 4, /* X86_64_RELOC_BRANCH */
2556 4, /* X86_64_RELOC_GOT_LOAD */
2557 4, /* X86_64_RELOC_GOT */
2558 8, /* X86_64_RELOC_SUBTRACTOR */
2559 4, /* X86_64_RELOC_SIGNED_1 */
2560 4, /* X86_64_RELOC_SIGNED_2 */
2561 4, /* X86_64_RELOC_SIGNED_4 */
2562};
2563
2564/** Macro for getting the size of a AMD64 ELF relocation. */
2565#define ELF_AMD64_RELOC_SIZE(a_Type) ( (a_Type) < RT_ELEMENTS(g_acbElfAmd64RelTypes) ? g_acbElfAmd64RelTypes[(a_Type)] : 1)
2566
2567
2568typedef struct ELFDETAILS
2569{
2570 /** The ELF header. */
2571 Elf64_Ehdr const *pEhdr;
2572 /** The section header table. */
2573 Elf64_Shdr const *paShdrs;
2574 /** The string table for the section names. */
2575 const char *pchShStrTab;
2576
2577 /** The symbol table section number. UINT16_MAX if not found. */
2578 uint16_t iSymSh;
2579 /** The string table section number. UINT16_MAX if not found. */
2580 uint16_t iStrSh;
2581
2582 /** The symbol table. */
2583 Elf64_Sym const *paSymbols;
2584 /** The number of symbols in the symbol table. */
2585 uint32_t cSymbols;
2586
2587 /** Pointer to the (symbol) string table if found. */
2588 const char *pchStrTab;
2589 /** The string table size. */
2590 size_t cbStrTab;
2591
2592} ELFDETAILS;
2593typedef ELFDETAILS *PELFDETAILS;
2594typedef ELFDETAILS const *PCELFDETAILS;
2595
2596
2597static bool validateElf(const char *pszFile, uint8_t const *pbFile, size_t cbFile, PELFDETAILS pElfStuff)
2598{
2599 /*
2600 * Initialize the ELF details structure.
2601 */
2602 memset(pElfStuff, 0, sizeof(*pElfStuff));
2603 pElfStuff->iSymSh = UINT16_MAX;
2604 pElfStuff->iStrSh = UINT16_MAX;
2605
2606 /*
2607 * Validate the header and our other expectations.
2608 */
2609 Elf64_Ehdr const *pEhdr = (Elf64_Ehdr const *)pbFile;
2610 pElfStuff->pEhdr = pEhdr;
2611 if ( pEhdr->e_ident[EI_CLASS] != ELFCLASS64
2612 || pEhdr->e_ident[EI_DATA] != ELFDATA2LSB
2613 || pEhdr->e_ehsize != sizeof(Elf64_Ehdr)
2614 || pEhdr->e_shentsize != sizeof(Elf64_Shdr)
2615 || pEhdr->e_version != EV_CURRENT )
2616 return error(pszFile, "Unsupported ELF config\n");
2617 if (pEhdr->e_type != ET_REL)
2618 return error(pszFile, "Expected relocatable ELF file (e_type=%d)\n", pEhdr->e_type);
2619 if (pEhdr->e_machine != EM_X86_64)
2620 return error(pszFile, "Expected relocatable ELF file (e_type=%d)\n", pEhdr->e_machine);
2621 if (pEhdr->e_phnum != 0)
2622 return error(pszFile, "Expected e_phnum to be zero not %u\n", pEhdr->e_phnum);
2623 if (pEhdr->e_shnum < 2)
2624 return error(pszFile, "Expected e_shnum to be two or higher\n");
2625 if (pEhdr->e_shstrndx >= pEhdr->e_shnum || pEhdr->e_shstrndx == 0)
2626 return error(pszFile, "Bad e_shstrndx=%u (e_shnum=%u)\n", pEhdr->e_shstrndx, pEhdr->e_shnum);
2627 if ( pEhdr->e_shoff >= cbFile
2628 || pEhdr->e_shoff + pEhdr->e_shnum * sizeof(Elf64_Shdr) > cbFile)
2629 return error(pszFile, "Section table is outside the file (e_shoff=%#llx, e_shnum=%u, cbFile=%#llx)\n",
2630 pEhdr->e_shstrndx, pEhdr->e_shnum, (uint64_t)cbFile);
2631
2632 /*
2633 * Locate the section name string table.
2634 * We assume it's okay as we only reference it in verbose mode.
2635 */
2636 Elf64_Shdr const *paShdrs = (Elf64_Shdr const *)&pbFile[pEhdr->e_shoff];
2637 pElfStuff->paShdrs = paShdrs;
2638
2639 Elf64_Xword const cbShStrTab = paShdrs[pEhdr->e_shstrndx].sh_size;
2640 if ( paShdrs[pEhdr->e_shstrndx].sh_offset > cbFile
2641 || cbShStrTab > cbFile
2642 || paShdrs[pEhdr->e_shstrndx].sh_offset + cbShStrTab > cbFile)
2643 return error(pszFile,
2644 "Section string table is outside the file (sh_offset=%#" ELF_FMT_X64 " sh_size=%#" ELF_FMT_X64 " cbFile=%#" ELF_FMT_X64 ")\n",
2645 paShdrs[pEhdr->e_shstrndx].sh_offset, paShdrs[pEhdr->e_shstrndx].sh_size, (Elf64_Xword)cbFile);
2646 const char *pchShStrTab = (const char *)&pbFile[paShdrs[pEhdr->e_shstrndx].sh_offset];
2647 pElfStuff->pchShStrTab = pchShStrTab;
2648
2649 /*
2650 * Work the section table.
2651 */
2652 bool fRet = true;
2653 for (uint32_t i = 1; i < pEhdr->e_shnum; i++)
2654 {
2655 if (paShdrs[i].sh_name >= cbShStrTab)
2656 return error(pszFile, "Invalid sh_name value (%#x) for section #%u\n", paShdrs[i].sh_name, i);
2657 const char *pszShNm = &pchShStrTab[paShdrs[i].sh_name];
2658
2659 if ( paShdrs[i].sh_offset > cbFile
2660 || paShdrs[i].sh_size > cbFile
2661 || paShdrs[i].sh_offset + paShdrs[i].sh_size > cbFile)
2662 return error(pszFile, "Section #%u '%s' has data outside the file: %#" ELF_FMT_X64 " LB %#" ELF_FMT_X64 " (cbFile=%#" ELF_FMT_X64 ")\n",
2663 i, pszShNm, paShdrs[i].sh_offset, paShdrs[i].sh_size, (Elf64_Xword)cbFile);
2664 if (g_cVerbose)
2665 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"
2666 " link=%u info=%#x align=%#" ELF_FMT_X64 " entsize=%#" ELF_FMT_X64 "\n",
2667 i, paShdrs[i].sh_name, pszShNm, paShdrs[i].sh_type, paShdrs[i].sh_flags,
2668 paShdrs[i].sh_addr, paShdrs[i].sh_offset, paShdrs[i].sh_size,
2669 paShdrs[i].sh_link, paShdrs[i].sh_info, paShdrs[i].sh_addralign, paShdrs[i].sh_entsize);
2670
2671 if (paShdrs[i].sh_link >= pEhdr->e_shnum)
2672 return error(pszFile, "Section #%u '%s' links to a section outside the section table: %#x, max %#x\n",
2673 i, pszShNm, paShdrs[i].sh_link, pEhdr->e_shnum);
2674 if (!RT_IS_POWER_OF_TWO(paShdrs[i].sh_addralign))
2675 return error(pszFile, "Section #%u '%s' alignment value is not a power of two: %#" ELF_FMT_X64 "\n",
2676 i, pszShNm, paShdrs[i].sh_addralign);
2677 if (!RT_IS_POWER_OF_TWO(paShdrs[i].sh_addralign))
2678 return error(pszFile, "Section #%u '%s' alignment value is not a power of two: %#" ELF_FMT_X64 "\n",
2679 i, pszShNm, paShdrs[i].sh_addralign);
2680 if (paShdrs[i].sh_addr != 0)
2681 return error(pszFile, "Section #%u '%s' has non-zero address: %#" ELF_FMT_X64 "\n", i, pszShNm, paShdrs[i].sh_addr);
2682
2683 if (paShdrs[i].sh_type == SHT_RELA)
2684 {
2685 if (paShdrs[i].sh_entsize != sizeof(Elf64_Rela))
2686 return error(pszFile, "Expected sh_entsize to be %u not %u for section #%u (%s)\n", (unsigned)sizeof(Elf64_Rela),
2687 paShdrs[i].sh_entsize, i, pszShNm);
2688 uint32_t const cRelocs = paShdrs[i].sh_size / sizeof(Elf64_Rela);
2689 if (cRelocs * sizeof(Elf64_Rela) != paShdrs[i].sh_size)
2690 return error(pszFile, "Uneven relocation entry count in #%u (%s): sh_size=%#" ELF_FMT_X64 "\n",
2691 i, pszShNm, paShdrs[i].sh_size);
2692 if ( paShdrs[i].sh_offset > cbFile
2693 || paShdrs[i].sh_size >= cbFile
2694 || paShdrs[i].sh_offset + paShdrs[i].sh_size > cbFile)
2695 return error(pszFile, "The content of section #%u '%s' is outside the file (%#" ELF_FMT_X64 " LB %#" ELF_FMT_X64 ", cbFile=%#lx)\n",
2696 i, pszShNm, paShdrs[i].sh_offset, paShdrs[i].sh_size, (unsigned long)cbFile);
2697 if (paShdrs[i].sh_info != i - 1)
2698 return error(pszFile, "Expected relocation section #%u (%s) to link to previous section: sh_info=%#u\n",
2699 i, pszShNm, (unsigned)paShdrs[i].sh_link);
2700 if (paShdrs[paShdrs[i].sh_link].sh_type != SHT_SYMTAB)
2701 return error(pszFile, "Expected relocation section #%u (%s) to link to symbol table: sh_link=%#u -> sh_type=%#x\n",
2702 i, pszShNm, (unsigned)paShdrs[i].sh_link, (unsigned)paShdrs[paShdrs[i].sh_link].sh_type);
2703 uint32_t cSymbols = paShdrs[paShdrs[i].sh_link].sh_size / paShdrs[paShdrs[i].sh_link].sh_entsize;
2704
2705 Elf64_Rela const *paRelocs = (Elf64_Rela *)&pbFile[paShdrs[i].sh_offset];
2706 for (uint32_t j = 0; j < cRelocs; j++)
2707 {
2708 uint8_t const bType = ELF64_R_TYPE(paRelocs[j].r_info);
2709 if (RT_UNLIKELY(bType >= R_X86_64_COUNT))
2710 fRet = error(pszFile,
2711 "%#018" ELF_FMT_X64 " %#018" ELF_FMT_X64 ": unknown fix up %#x (%+" ELF_FMT_D64 ")\n",
2712 paRelocs[j].r_offset, paRelocs[j].r_info, bType, paRelocs[j].r_addend);
2713 if (RT_UNLIKELY( j > 1
2714 && paRelocs[j].r_offset <= paRelocs[j - 1].r_offset
2715 && paRelocs[j].r_offset + ELF_AMD64_RELOC_SIZE(ELF64_R_TYPE(paRelocs[j].r_info))
2716 < paRelocs[j - 1].r_offset ))
2717 fRet = error(pszFile,
2718 "%#018" ELF_FMT_X64 " %#018" ELF_FMT_X64 ": out of offset order (prev %" ELF_FMT_X64 ")\n",
2719 paRelocs[j].r_offset, paRelocs[j].r_info, paRelocs[j - 1].r_offset);
2720 uint32_t const iSymbol = ELF64_R_SYM(paRelocs[j].r_info);
2721 if (RT_UNLIKELY(iSymbol >= cSymbols))
2722 fRet = error(pszFile,
2723 "%#018" ELF_FMT_X64 " %#018" ELF_FMT_X64 ": symbol index (%#x) out of bounds (%#x)\n",
2724 paRelocs[j].r_offset, paRelocs[j].r_info, iSymbol, cSymbols);
2725 }
2726 if (RT_UNLIKELY( cRelocs > 0
2727 && fRet
2728 && ( paRelocs[cRelocs - 1].r_offset > paShdrs[i - 1].sh_size
2729 || paRelocs[cRelocs - 1].r_offset + ELF_AMD64_RELOC_SIZE(ELF64_R_TYPE(paRelocs[cRelocs-1].r_info))
2730 > paShdrs[i - 1].sh_size )))
2731 fRet = error(pszFile,
2732 "%#018" ELF_FMT_X64 " %#018" ELF_FMT_X64 ": out of bounds (sh_size %" ELF_FMT_X64 ")\n",
2733 paRelocs[cRelocs - 1].r_offset, paRelocs[cRelocs - 1].r_info, paShdrs[i - 1].sh_size);
2734
2735 }
2736 else if (paShdrs[i].sh_type == SHT_REL)
2737 fRet = error(pszFile, "Section #%u '%s': Unexpected SHT_REL section\n", i, pszShNm);
2738 else if (paShdrs[i].sh_type == SHT_SYMTAB)
2739 {
2740 if (paShdrs[i].sh_entsize != sizeof(Elf64_Sym))
2741 fRet = error(pszFile, "Section #%u '%s': Unsupported symbol table entry size in : #%u (expected #%u)\n",
2742 i, pszShNm, paShdrs[i].sh_entsize, sizeof(Elf64_Sym));
2743 Elf64_Xword const cSymbols = paShdrs[i].sh_size / paShdrs[i].sh_entsize;
2744 if (cSymbols * paShdrs[i].sh_entsize != paShdrs[i].sh_size)
2745 fRet = error(pszFile, "Section #%u '%s': Size not a multiple of entry size: %#" ELF_FMT_X64 " %% %#" ELF_FMT_X64 " = %#" ELF_FMT_X64 "\n",
2746 i, pszShNm, paShdrs[i].sh_size, paShdrs[i].sh_entsize, paShdrs[i].sh_size % paShdrs[i].sh_entsize);
2747 if (cSymbols > UINT32_MAX)
2748 fRet = error(pszFile, "Section #%u '%s': too many symbols: %" ELF_FMT_X64 "\n",
2749 i, pszShNm, paShdrs[i].sh_size, cSymbols);
2750
2751 if (pElfStuff->iSymSh == UINT16_MAX)
2752 {
2753 pElfStuff->iSymSh = (uint16_t)i;
2754 pElfStuff->paSymbols = (Elf64_Sym const *)&pbFile[paShdrs[i].sh_offset];
2755 pElfStuff->cSymbols = cSymbols;
2756
2757 if (paShdrs[i].sh_link != 0)
2758 {
2759 /* Note! The symbol string table section header may not have been validated yet! */
2760 Elf64_Shdr const *pStrTabShdr = &paShdrs[paShdrs[i].sh_link];
2761 pElfStuff->iStrSh = paShdrs[i].sh_link;
2762 pElfStuff->pchStrTab = (const char *)&pbFile[pStrTabShdr->sh_offset];
2763 pElfStuff->cbStrTab = (size_t)pStrTabShdr->sh_size;
2764 }
2765 else
2766 fRet = error(pszFile, "Section #%u '%s': String table link is out of bounds (%#x)\n",
2767 i, pszShNm, paShdrs[i].sh_link);
2768 }
2769 else
2770 fRet = error(pszFile, "Section #%u '%s': Found additonal symbol table, previous in #%u\n",
2771 i, pszShNm, pElfStuff->iSymSh);
2772 }
2773 }
2774 return fRet;
2775}
2776
2777static bool convertElfSectionsToSegDefsAndGrpDefs(POMFWRITER pThis, PCELFDETAILS pElfStuff)
2778{
2779 /*
2780 * Do the list of names pass.
2781 */
2782 uint16_t idxGrpFlat, idxGrpData;
2783 uint16_t idxClassCode, idxClassData, idxClassDwarf;
2784 if ( !omfWriter_LNamesBegin(pThis)
2785 || !omfWriter_LNamesAddN(pThis, RT_STR_TUPLE("FLAT"), &idxGrpFlat)
2786 || !omfWriter_LNamesAddN(pThis, RT_STR_TUPLE("BS3DATA64_GROUP"), &idxGrpData)
2787 || !omfWriter_LNamesAddN(pThis, RT_STR_TUPLE("BS3CLASS64CODE"), &idxClassCode)
2788 || !omfWriter_LNamesAddN(pThis, RT_STR_TUPLE("FAR_DATA"), &idxClassData)
2789 || !omfWriter_LNamesAddN(pThis, RT_STR_TUPLE("DWARF"), &idxClassDwarf)
2790 )
2791 return false;
2792
2793 bool fHaveData = false;
2794 Elf64_Shdr const *pShdr = &pElfStuff->paShdrs[1];
2795 Elf64_Half const cSections = pElfStuff->pEhdr->e_shnum;
2796 for (Elf64_Half i = 1; i < cSections; i++, pShdr++)
2797 {
2798 const char *pszName = &pElfStuff->pchShStrTab[pShdr->sh_name];
2799 if (*pszName == '\0')
2800 return error(pThis->pszSrc, "Section #%u has an empty name!\n", i);
2801
2802 switch (pShdr->sh_type)
2803 {
2804 case SHT_PROGBITS:
2805 case SHT_NOBITS:
2806 /* We drop a few sections we don't want:. */
2807 if ( strcmp(pszName, ".comment") != 0 /* compiler info */
2808 && strcmp(pszName, ".note.GNU-stack") != 0 /* some empty section for hinting the linker/whatever */
2809 && strcmp(pszName, ".eh_frame") != 0 /* unwind / exception info */
2810 )
2811 {
2812 pThis->paSegments[i].iSegDef = UINT16_MAX;
2813 pThis->paSegments[i].iGrpDef = UINT16_MAX;
2814
2815 /* Translate the name and determine group and class.
2816 Note! We currently strip sub-sections. */
2817 if ( strcmp(pszName, ".text") == 0
2818 || strncmp(pszName, RT_STR_TUPLE(".text.")) == 0)
2819 {
2820 pszName = "BS3TEXT64";
2821 pThis->paSegments[i].iGrpNm = idxGrpFlat;
2822 pThis->paSegments[i].iClassNm = idxClassCode;
2823 }
2824 else if ( strcmp(pszName, ".data") == 0
2825 || strncmp(pszName, RT_STR_TUPLE(".data.")) == 0)
2826 {
2827 pszName = "BS3DATA64";
2828 pThis->paSegments[i].iGrpNm = idxGrpData;
2829 pThis->paSegments[i].iClassNm = idxClassData;
2830 }
2831 else if (strcmp(pszName, ".bss") == 0)
2832 {
2833 pszName = "BS3BSS64";
2834 pThis->paSegments[i].iGrpNm = idxGrpData;
2835 pThis->paSegments[i].iClassNm = idxClassData;
2836 }
2837 else if ( strcmp(pszName, ".rodata") == 0
2838 || strncmp(pszName, RT_STR_TUPLE(".rodata.")) == 0)
2839 {
2840 pszName = "BS3DATA64CONST";
2841 pThis->paSegments[i].iGrpNm = idxGrpData;
2842 pThis->paSegments[i].iClassNm = idxClassData;
2843 }
2844 else if (strncmp(pszName, RT_STR_TUPLE(".debug_")) == 0)
2845 {
2846 pThis->paSegments[i].iGrpNm = UINT16_MAX;
2847 pThis->paSegments[i].iClassNm = idxClassDwarf;
2848 }
2849 else
2850 {
2851 pThis->paSegments[i].iGrpNm = idxGrpData;
2852 pThis->paSegments[i].iClassNm = idxClassData;
2853 error(pThis->pszSrc, "Unknown data (?) segment: '%s'\n", pszName);
2854 }
2855
2856 /* Save the name. */
2857 pThis->paSegments[i].pszName = strdup(pszName);
2858 if (!pThis->paSegments[i].pszName)
2859 return error(pThis->pszSrc, "Out of memory!\n");
2860
2861 /* Add the section name. */
2862 if (!omfWriter_LNamesAdd(pThis, pThis->paSegments[i].pszName, &pThis->paSegments[i].iSegNm))
2863 return false;
2864
2865 fHaveData |= pThis->paSegments[i].iGrpDef == idxGrpData;
2866 break;
2867 }
2868 /* fall thru */
2869
2870 default:
2871 pThis->paSegments[i].iSegDef = UINT16_MAX;
2872 pThis->paSegments[i].iGrpDef = UINT16_MAX;
2873 pThis->paSegments[i].iSegNm = UINT16_MAX;
2874 pThis->paSegments[i].iGrpNm = UINT16_MAX;
2875 pThis->paSegments[i].iClassNm = UINT16_MAX;
2876 pThis->paSegments[i].pszName = NULL;
2877 break;
2878 }
2879 }
2880
2881 if (!omfWriter_LNamesEnd(pThis))
2882 return false;
2883
2884 /*
2885 * Emit segment definitions.
2886 */
2887 uint16_t iSegDef = 1; /* Start counting at 1. */
2888 pShdr = &pElfStuff->paShdrs[1];
2889 for (Elf64_Half i = 1; i < cSections; i++, pShdr++)
2890 {
2891 if (pThis->paSegments[i].iSegNm == UINT16_MAX)
2892 continue;
2893
2894 uint8_t bSegAttr = 0;
2895
2896 /* The A field. */
2897 switch (pShdr->sh_addralign)
2898 {
2899 case 0:
2900 case 1:
2901 bSegAttr |= 1 << 5;
2902 break;
2903 case 2:
2904 bSegAttr |= 2 << 5;
2905 break;
2906 case 4:
2907 bSegAttr |= 5 << 5;
2908 break;
2909 case 8:
2910 case 16:
2911 bSegAttr |= 3 << 5;
2912 break;
2913 case 32:
2914 case 64:
2915 case 128:
2916 case 256:
2917 bSegAttr |= 4 << 5;
2918 break;
2919 default:
2920 bSegAttr |= 6 << 5; /* page aligned, pharlabs extension. */
2921 break;
2922 }
2923
2924 /* The C field. */
2925 bSegAttr |= 2 << 2; /* public */
2926
2927 /* The B field. We don't have 4GB segments, so leave it as zero. */
2928
2929 /* The D field shall be set as we're doing USE32. */
2930 bSegAttr |= 1;
2931
2932
2933 /* Done. */
2934 if (!omfWriter_SegDef(pThis, bSegAttr, (uint32_t)pShdr->sh_size,
2935 pThis->paSegments[i].iSegNm,
2936 pThis->paSegments[i].iClassNm))
2937 return false;
2938 pThis->paSegments[i].iSegDef = iSegDef++;
2939 }
2940
2941 /*
2942 * Flat group definition (#1) - special, no members.
2943 */
2944 uint16_t iGrpDef = 1;
2945 if ( !omfWriter_GrpDefBegin(pThis, idxGrpFlat)
2946 || !omfWriter_GrpDefEnd(pThis))
2947 return false;
2948 for (uint16_t i = 0; i < cSections; i++)
2949 if (pThis->paSegments[i].iGrpNm == idxGrpFlat)
2950 pThis->paSegments[i].iGrpDef = iGrpDef;
2951 pThis->idxGrpFlat = iGrpDef++;
2952
2953 /*
2954 * Data group definition (#2).
2955 */
2956 /** @todo do we need to consider missing segments and ordering? */
2957 uint16_t cGrpNms = 0;
2958 uint16_t aiGrpNms[2];
2959 if (fHaveData)
2960 aiGrpNms[cGrpNms++] = idxGrpData;
2961 for (uint32_t iGrpNm = 0; iGrpNm < cGrpNms; iGrpNm++)
2962 {
2963 if (!omfWriter_GrpDefBegin(pThis, aiGrpNms[iGrpNm]))
2964 return false;
2965 for (uint16_t i = 0; i < cSections; i++)
2966 if (pThis->paSegments[i].iGrpNm == aiGrpNms[iGrpNm])
2967 {
2968 pThis->paSegments[i].iGrpDef = iGrpDef;
2969 if (!omfWriter_GrpDefAddSegDef(pThis, pThis->paSegments[i].iSegDef))
2970 return false;
2971 }
2972 if (!omfWriter_GrpDefEnd(pThis))
2973 return false;
2974 iGrpDef++;
2975 }
2976
2977 return true;
2978}
2979
2980static bool convertElfSymbolsToPubDefsAndExtDefs(POMFWRITER pThis, PCELFDETAILS pElfStuff)
2981{
2982 if (!pElfStuff->cSymbols)
2983 return true;
2984
2985 /*
2986 * Process the symbols the first.
2987 */
2988 uint32_t cAbsSyms = 0;
2989 uint32_t cExtSyms = 0;
2990 uint32_t cPubSyms = 0;
2991 for (uint32_t iSeg = 0; iSeg < pThis->cSegments; iSeg++)
2992 pThis->paSegments[iSeg].cPubDefs = 0;
2993
2994 uint32_t const cSections = pElfStuff->pEhdr->e_shnum;
2995 uint32_t const cSymbols = pElfStuff->cSymbols;
2996 Elf64_Sym const * const paSymbols = pElfStuff->paSymbols;
2997 for (uint32_t iSym = 0; iSym < cSymbols; iSym++)
2998 {
2999 const uint8_t bBind = ELF64_ST_BIND(paSymbols[iSym].st_info);
3000 const uint8_t bType = ELF64_ST_TYPE(paSymbols[iSym].st_info);
3001 const char *pszSymName = &pElfStuff->pchStrTab[paSymbols[iSym].st_name];
3002 if ( *pszSymName == '\0'
3003 && bType == STT_SECTION
3004 && paSymbols[iSym].st_shndx < cSections)
3005 pszSymName = &pElfStuff->pchShStrTab[pElfStuff->paShdrs[paSymbols[iSym].st_shndx].sh_name];
3006
3007 pThis->paSymbols[iSym].enmType = OMFSYMTYPE_IGNORED;
3008 pThis->paSymbols[iSym].idx = UINT16_MAX;
3009 pThis->paSymbols[iSym].idxSegDef = UINT16_MAX;
3010 pThis->paSymbols[iSym].idxGrpDef = UINT16_MAX;
3011
3012 uint32_t const idxSection = paSymbols[iSym].st_shndx;
3013 if (idxSection == SHN_UNDEF)
3014 {
3015 if (bBind == STB_GLOBAL)
3016 {
3017 pThis->paSymbols[iSym].enmType = OMFSYMTYPE_EXTDEF;
3018 cExtSyms++;
3019 if (*pszSymName == '\0')
3020 return error(pThis->pszSrc, "External symbol #%u (%s) has an empty name.\n", iSym, pszSymName);
3021 }
3022 else if (bBind != STB_LOCAL || iSym != 0) /* Entry zero is usually a dummy. */
3023 return error(pThis->pszSrc, "Unsupported or invalid bind type %#x for undefined symbol #%u (%s)\n",
3024 bBind, iSym, pszSymName);
3025 }
3026 else if (idxSection < cSections)
3027 {
3028 pThis->paSymbols[iSym].idxSegDef = pThis->paSegments[idxSection].iSegDef;
3029 pThis->paSymbols[iSym].idxGrpDef = pThis->paSegments[idxSection].iGrpDef;
3030 if (bBind == STB_GLOBAL)
3031 {
3032 pThis->paSymbols[iSym].enmType = OMFSYMTYPE_PUBDEF;
3033 pThis->paSegments[idxSection].cPubDefs++;
3034 cPubSyms++;
3035 if (bType == STT_SECTION)
3036 return error(pThis->pszSrc, "Don't know how to export STT_SECTION symbol #%u (%s)\n", iSym, pszSymName);
3037 if (*pszSymName == '\0')
3038 return error(pThis->pszSrc, "Public symbol #%u (%s) has an empty name.\n", iSym, pszSymName);
3039 }
3040 else if (bType == STT_SECTION)
3041 pThis->paSymbols[iSym].enmType = OMFSYMTYPE_SEGDEF;
3042 else
3043 pThis->paSymbols[iSym].enmType = OMFSYMTYPE_INTERNAL;
3044 }
3045 else if (idxSection == SHN_ABS)
3046 {
3047 if (bType != STT_FILE)
3048 {
3049 if (bBind == STB_GLOBAL)
3050 {
3051 pThis->paSymbols[iSym].enmType = OMFSYMTYPE_PUBDEF;
3052 pThis->paSymbols[iSym].idxSegDef = 0;
3053 pThis->paSymbols[iSym].idxGrpDef = 0;
3054 cAbsSyms++;
3055 if (*pszSymName == '\0')
3056 return error(pThis->pszSrc, "Public absolute symbol #%u (%s) has an empty name.\n", iSym, pszSymName);
3057 }
3058 else
3059 return error(pThis->pszSrc, "Unsupported or invalid bind type %#x for absolute symbol #%u (%s)\n",
3060 bBind, iSym, pszSymName);
3061 }
3062 }
3063 else
3064 return error(pThis->pszSrc, "Unsupported or invalid section number %#x for symbol #%u (%s)\n",
3065 idxSection, iSym, pszSymName);
3066 }
3067
3068 /*
3069 * Emit the PUBDEFs the first time around (see order of records in TIS spec).
3070 */
3071 uint16_t idxPubDef = 1;
3072 if (cPubSyms)
3073 {
3074 for (uint32_t iSeg = 0; iSeg < pThis->cSegments; iSeg++)
3075 if (pThis->paSegments[iSeg].cPubDefs > 0)
3076 {
3077 uint16_t const idxSegDef = pThis->paSegments[iSeg].iSegDef;
3078 if (!omfWriter_PubDefBegin(pThis, pThis->paSegments[iSeg].iGrpDef, idxSegDef))
3079 return false;
3080 for (uint16_t iSym = 0; iSym < cSymbols; iSym++)
3081 if ( pThis->paSymbols[iSym].idxSegDef == idxSegDef
3082 && pThis->paSymbols[iSym].enmType == OMFSYMTYPE_PUBDEF)
3083 {
3084 const char *pszName = &pElfStuff->pchStrTab[paSymbols[iSym].st_name];
3085 if (!omfWriter_PubDefAdd(pThis, paSymbols[iSym].st_value, pszName))
3086 return false;
3087
3088 /* If the symbol doesn't start with an underscore and is a _c64 or _lm64 symbol,
3089 add an underscore prefixed alias to ease access from 16-bit and 32-bit code. */
3090 size_t cchName = strlen(pszName);
3091 if ( *pszName != '_'
3092 && ( (cchName > 4 && strcmp(&pszName[cchName - 4], "_c64") == 0)
3093 || (cchName > 5 && strcmp(&pszName[cchName - 5], "_lm64") == 0) ) )
3094 {
3095 char szCdeclName[512];
3096 if (cchName > sizeof(szCdeclName) - 2)
3097 cchName = sizeof(szCdeclName) - 2;
3098 szCdeclName[0] = '_';
3099 memcpy(&szCdeclName[1], pszName, cchName);
3100 szCdeclName[cchName + 1] = '\0';
3101 if (!omfWriter_PubDefAdd(pThis, paSymbols[iSym].st_value, szCdeclName))
3102 return false;
3103 }
3104
3105 pThis->paSymbols[iSym].idx = idxPubDef++;
3106 }
3107 if (!omfWriter_PubDefEnd(pThis))
3108 return false;
3109 }
3110 }
3111
3112 if (cAbsSyms > 0)
3113 {
3114 if (!omfWriter_PubDefBegin(pThis, 0, 0))
3115 return false;
3116 for (uint16_t iSym = 0; iSym < cSymbols; iSym++)
3117 if ( pThis->paSymbols[iSym].idxSegDef == 0
3118 && pThis->paSymbols[iSym].enmType == OMFSYMTYPE_PUBDEF)
3119 {
3120 const char *pszName = &pElfStuff->pchStrTab[paSymbols[iSym].st_name];
3121 if (!omfWriter_PubDefAdd(pThis, paSymbols[iSym].st_value, pszName))
3122 return false;
3123 pThis->paSymbols[iSym].idx = idxPubDef++;
3124 }
3125 if (!omfWriter_PubDefEnd(pThis))
3126 return false;
3127 }
3128
3129 /*
3130 * Go over the symbol table and emit external definition records.
3131 */
3132 if (!omfWriter_ExtDefBegin(pThis))
3133 return false;
3134 uint16_t idxExtDef = 1;
3135 for (uint16_t iSym = 0; iSym < cSymbols; iSym++)
3136 if (pThis->paSymbols[iSym].enmType == OMFSYMTYPE_EXTDEF)
3137 {
3138 const char *pszName = &pElfStuff->pchStrTab[paSymbols[iSym].st_name];
3139 if (!omfWriter_ExtDefAdd(pThis, pszName))
3140 return false;
3141 pThis->paSymbols[iSym].idx = idxExtDef++;
3142 }
3143
3144 if (!omfWriter_ExtDefEnd(pThis))
3145 return false;
3146
3147 return true;
3148}
3149
3150static bool convertElfSectionsToLeDataAndFixupps(POMFWRITER pThis, PCELFDETAILS pElfStuff, uint8_t const *pbFile, size_t cbFile)
3151{
3152 Elf64_Sym const *paSymbols = pElfStuff->paSymbols;
3153 Elf64_Shdr const *paShdrs = pElfStuff->paShdrs;
3154 bool fRet = true;
3155 for (uint32_t i = 1; i < pThis->cSegments; i++)
3156 {
3157 if (pThis->paSegments[i].iSegDef == UINT16_MAX)
3158 continue;
3159
3160 const char *pszSegNm = &pElfStuff->pchShStrTab[paShdrs[i].sh_name];
3161 bool const fRelocs = i + 1 < pThis->cSegments && paShdrs[i + 1].sh_type == SHT_RELA;
3162 uint32_t cRelocs = fRelocs ? paShdrs[i + 1].sh_size / sizeof(Elf64_Rela) : 0;
3163 Elf64_Rela const *paRelocs = fRelocs ? (Elf64_Rela *)&pbFile[paShdrs[i + 1].sh_offset] : NULL;
3164 Elf64_Xword cbVirtData = paShdrs[i].sh_size;
3165 Elf64_Xword cbData = paShdrs[i].sh_type == SHT_NOBITS ? 0 : cbVirtData;
3166 uint8_t const *pbData = &pbFile[paShdrs[i].sh_offset];
3167 uint32_t off = 0;
3168
3169 /* The OMF record size requires us to split larger sections up. To make
3170 life simple, we fill zeros for unitialized (BSS) stuff. */
3171 const uint32_t cbMaxData = RT_MIN(OMF_MAX_RECORD_PAYLOAD - 1 - (pThis->paSegments[i].iSegDef >= 128) - 4 - 1, _1K);
3172 while (cbVirtData > 0)
3173 {
3174 /* Figure out how many bytes to put out in this chunk. Must make sure
3175 fixups doesn't cross chunk boundraries. ASSUMES sorted relocs. */
3176 uint32_t cChunkRelocs = cRelocs;
3177 uint32_t cbChunk = cbVirtData;
3178 uint32_t offEnd = off + cbChunk;
3179 if (cbChunk > cbMaxData)
3180 {
3181 cbChunk = cbMaxData;
3182 offEnd = off + cbChunk;
3183 cChunkRelocs = 0;
3184
3185 /* Quickly determin the reloc range. */
3186 while ( cChunkRelocs < cRelocs
3187 && paRelocs[cChunkRelocs].r_offset < offEnd)
3188 cChunkRelocs++;
3189
3190 /* Ensure final reloc doesn't go beyond chunk. */
3191 while ( cChunkRelocs > 0
3192 && paRelocs[cChunkRelocs - 1].r_offset
3193 + ELF_AMD64_RELOC_SIZE(ELF64_R_TYPE(paRelocs[cChunkRelocs - 1].r_info))
3194 > offEnd)
3195 {
3196 uint32_t cbDrop = offEnd - paRelocs[cChunkRelocs - 1].r_offset;
3197 cbChunk -= cbDrop;
3198 offEnd -= cbDrop;
3199 cChunkRelocs--;
3200 }
3201
3202 if (!cbVirtData)
3203 return error(pThis->pszSrc, "Wtf? cbVirtData is zero!\n");
3204 }
3205
3206 /*
3207 * We stash the bytes into the OMF writer record buffer, receiving a
3208 * pointer to the start of it so we can make adjustments if necessary.
3209 */
3210 uint8_t *pbCopy;
3211 if (!omfWriter_LEDataBegin(pThis, pThis->paSegments[i].iSegDef, off, cbChunk, cbData, pbData, &pbCopy))
3212 return false;
3213
3214 /*
3215 * Convert fiuxps.
3216 */
3217 for (uint32_t iReloc = 0; iReloc < cChunkRelocs; iReloc++)
3218 {
3219 /* Get the OMF and ELF data for the symbol the reloc references. */
3220 uint32_t const uType = ELF64_R_TYPE(paRelocs[iReloc].r_info);
3221 uint32_t const iSymbol = ELF64_R_SYM(paRelocs[iReloc].r_info);
3222 Elf64_Sym const * const pElfSym = &paSymbols[iSymbol];
3223 POMFSYMBOL const pOmfSym = &pThis->paSymbols[iSymbol];
3224 const char * const pszSymName = &pElfStuff->pchStrTab[pElfSym->st_name];
3225
3226 /* Calc fixup location in the pending chunk and setup a flexible pointer to it. */
3227 uint16_t offDataRec = (uint16_t)(paRelocs[iReloc].r_offset - off);
3228 RTPTRUNION uLoc;
3229 uLoc.pu8 = &pbCopy[offDataRec];
3230
3231 /* OMF fixup data initialized with typical defaults. */
3232 bool fSelfRel = true;
3233 uint8_t bLocation = OMF_FIX_LOC_32BIT_OFFSET;
3234 uint8_t bFrame = OMF_FIX_F_GRPDEF;
3235 uint16_t idxFrame = pThis->idxGrpFlat;
3236 uint8_t bTarget;
3237 uint16_t idxTarget;
3238 bool fTargetDisp;
3239 uint32_t offTargetDisp;
3240 switch (pOmfSym->enmType)
3241 {
3242 case OMFSYMTYPE_INTERNAL:
3243 case OMFSYMTYPE_PUBDEF:
3244 bTarget = OMF_FIX_T_SEGDEF;
3245 idxTarget = pOmfSym->idxSegDef;
3246 fTargetDisp = true;
3247 offTargetDisp = pElfSym->st_value;
3248 break;
3249
3250 case OMFSYMTYPE_SEGDEF:
3251 bTarget = OMF_FIX_T_SEGDEF_NO_DISP;
3252 idxTarget = pOmfSym->idxSegDef;
3253 fTargetDisp = false;
3254 offTargetDisp = 0;
3255 break;
3256
3257 case OMFSYMTYPE_EXTDEF:
3258 bTarget = OMF_FIX_T_EXTDEF_NO_DISP;
3259 idxTarget = pOmfSym->idx;
3260 fTargetDisp = false;
3261 offTargetDisp = 0;
3262 break;
3263
3264 default:
3265 return error(pThis->pszSrc, "Relocation in segment #%u '%s' references ignored or invalid symbol (%s)\n",
3266 i, pszSegNm, pszSymName);
3267 }
3268
3269 /* Do COFF relocation type conversion. */
3270 switch (uType)
3271 {
3272 case R_X86_64_64:
3273 {
3274 int64_t iAddend = paRelocs[iReloc].r_addend;
3275 if (iAddend > _1G || iAddend < -_1G)
3276 fRet = error(pThis->pszSrc, "R_X86_64_64 with large addend (%" ELF_FMT_D64 ") at %#x in segment #%u '%s'\n",
3277 iAddend, paRelocs[iReloc].r_offset, i, pszSegNm);
3278 *uLoc.pu64 = iAddend;
3279 fSelfRel = false;
3280 break;
3281 }
3282
3283 case R_X86_64_32:
3284 case R_X86_64_32S: /* signed, unsigned, whatever. */
3285 fSelfRel = false;
3286 /* fall thru */
3287 case R_X86_64_PC32:
3288 {
3289 /* defaults are ok, just handle the addend. */
3290 int32_t iAddend = paRelocs[iReloc].r_addend;
3291 if (iAddend != paRelocs[iReloc].r_addend)
3292 fRet = error(pThis->pszSrc, "R_X86_64_PC32 with large addend (%d) at %#x in segment #%u '%s'\n",
3293 iAddend, paRelocs[iReloc].r_offset, i, pszSegNm);
3294 *uLoc.pu32 = iAddend;
3295 break;
3296 }
3297
3298 case R_X86_64_NONE:
3299 continue; /* Ignore this one */
3300
3301 case R_X86_64_GOT32:
3302 case R_X86_64_PLT32:
3303 case R_X86_64_COPY:
3304 case R_X86_64_GLOB_DAT:
3305 case R_X86_64_JMP_SLOT:
3306 case R_X86_64_RELATIVE:
3307 case R_X86_64_GOTPCREL:
3308 case R_X86_64_16:
3309 case R_X86_64_PC16:
3310 case R_X86_64_8:
3311 case R_X86_64_PC8:
3312 case R_X86_64_DTPMOD64:
3313 case R_X86_64_DTPOFF64:
3314 case R_X86_64_TPOFF64:
3315 case R_X86_64_TLSGD:
3316 case R_X86_64_TLSLD:
3317 case R_X86_64_DTPOFF32:
3318 case R_X86_64_GOTTPOFF:
3319 case R_X86_64_TPOFF32:
3320 default:
3321 return error(pThis->pszSrc, "Unsupported fixup type %#x (%s) at rva=%#x in section #%u '%s' against '%s'\n",
3322 uType, g_apszElfAmd64RelTypes[uType], paRelocs[iReloc].r_offset, i, pszSegNm, pszSymName);
3323 }
3324
3325 /* Add the fixup. */
3326 if (idxFrame == UINT16_MAX)
3327 error(pThis->pszSrc, "idxFrame=UINT16_MAX for %s type=%s\n", pszSymName, g_apszElfAmd64RelTypes[uType]);
3328 fRet = omfWriter_LEDataAddFixup(pThis, offDataRec, fSelfRel, bLocation, bFrame, idxFrame,
3329 bTarget, idxTarget, fTargetDisp, offTargetDisp) && fRet;
3330 }
3331
3332 /*
3333 * Write the LEDATA and associated FIXUPPs.
3334 */
3335 if (!omfWriter_LEDataEnd(pThis))
3336 return false;
3337
3338 /*
3339 * Advance.
3340 */
3341 paRelocs += cChunkRelocs;
3342 cRelocs -= cChunkRelocs;
3343 if (cbData > cbChunk)
3344 {
3345 cbData -= cbChunk;
3346 pbData += cbChunk;
3347 }
3348 else
3349 cbData = 0;
3350 off += cbChunk;
3351 cbVirtData -= cbChunk;
3352 }
3353 }
3354
3355 return fRet;
3356}
3357
3358
3359static bool convertMachoToOmf(const char *pszFile, uint8_t const *pbFile, size_t cbFile, FILE *pDst)
3360{
3361 /*
3362 * Validate the source file a little.
3363 */
3364 ELFDETAILS ElfStuff;
3365 if (!validateElf(pszFile, pbFile, cbFile, &ElfStuff))
3366 return false;
3367
3368 /*
3369 * Instantiate the OMF writer.
3370 */
3371 POMFWRITER pThis = omfWriter_Create(pszFile, ElfStuff.pEhdr->e_shnum, ElfStuff.cSymbols, pDst);
3372 if (!pThis)
3373 return false;
3374
3375 /*
3376 * Write the OMF object file.
3377 */
3378 if (omfWriter_BeginModule(pThis, pszFile))
3379 {
3380 Elf64_Ehdr const *pEhdr = (Elf64_Ehdr const *)pbFile;
3381 Elf64_Shdr const *paShdrs = (Elf64_Shdr const *)&pbFile[pEhdr->e_shoff];
3382 const char *pszStrTab = (const char *)&pbFile[paShdrs[pEhdr->e_shstrndx].sh_offset];
3383
3384 if ( convertElfSectionsToSegDefsAndGrpDefs(pThis, &ElfStuff)
3385 && convertElfSymbolsToPubDefsAndExtDefs(pThis, &ElfStuff)
3386 && omfWriter_LinkPassSeparator(pThis)
3387 && convertElfSectionsToLeDataAndFixupps(pThis, &ElfStuff, pbFile, cbFile)
3388 && omfWriter_EndModule(pThis) )
3389 {
3390
3391 omfWriter_Destroy(pThis);
3392 return true;
3393 }
3394 }
3395
3396 omfWriter_Destroy(pThis);
3397 return false;
3398}
3399
3400#endif /* !MACHO_TO_OMF_CONVERSION */
3401
3402
3403/*********************************************************************************************************************************
3404* OMF Converter/Tweaker *
3405*********************************************************************************************************************************/
3406
3407/** Watcom intrinsics we need to modify so we can mix 32-bit and 16-bit
3408 * code, since the 16 and 32 bit compilers share several names.
3409 * The names are length prefixed.
3410 */
3411static const char * const g_apszExtDefRenames[] =
3412{
3413 "\x05" "__I4D",
3414 "\x05" "__I4M",
3415 "\x05" "__I8D",
3416 "\x06" "__I8DQ",
3417 "\x07" "__I8DQE",
3418 "\x06" "__I8DR",
3419 "\x07" "__I8DRE",
3420 "\x06" "__I8LS",
3421 "\x05" "__I8M",
3422 "\x06" "__I8ME",
3423 "\x06" "__I8RS",
3424 "\x05" "__PIA",
3425 "\x05" "__PIS",
3426 "\x05" "__PTC",
3427 "\x05" "__PTS",
3428 "\x05" "__U4D",
3429 "\x05" "__U4M",
3430 "\x05" "__U8D",
3431 "\x06" "__U8DQ",
3432 "\x07" "__U8DQE",
3433 "\x06" "__U8DR",
3434 "\x07" "__U8DRE",
3435 "\x06" "__U8LS",
3436 "\x05" "__U8M",
3437 "\x06" "__U8ME",
3438 "\x06" "__U8RS",
3439};
3440
3441/**
3442 * Renames references to intrinsic helper functions so they won't clash between
3443 * 32-bit and 16-bit code.
3444 *
3445 * @returns true / false.
3446 * @param pszFile File name for complaining.
3447 * @param pbFile Pointer to the file content.
3448 * @param cbFile Size of the file content.
3449 */
3450static bool convertomf(const char *pszFile, uint8_t *pbFile, size_t cbFile, const char **papchLNames, uint32_t cLNamesMax)
3451{
3452 uint32_t cLNames = 0;
3453 uint32_t cExtDefs = 0;
3454 uint32_t cPubDefs = 0;
3455 bool fProbably32bit = false;
3456 uint32_t off = 0;
3457
3458 while (off + 3 < cbFile)
3459 {
3460 uint8_t bRecType = pbFile[off];
3461 uint16_t cbRec = RT_MAKE_U16(pbFile[off + 1], pbFile[off + 2]);
3462 if (g_cVerbose > 2)
3463 printf( "%#07x: type=%#04x len=%#06x\n", off, bRecType, cbRec);
3464 if (off + cbRec > cbFile)
3465 return error(pszFile, "Invalid record length at %#x: %#x (cbFile=%#lx)\n", off, cbRec, (unsigned long)cbFile);
3466
3467 if (bRecType & OMF_REC32)
3468 fProbably32bit = true;
3469
3470 uint32_t offRec = 0;
3471 uint8_t *pbRec = &pbFile[off + 3];
3472#define OMF_CHECK_RET(a_cbReq, a_Name) /* Not taking the checksum into account, so we're good with 1 or 2 byte fields. */ \
3473 if (offRec + (a_cbReq) <= cbRec) {/*likely*/} \
3474 else return error(pszFile, "Malformed " #a_Name "! off=%#x offRec=%#x cbRec=%#x cbNeeded=%#x line=%d\n", \
3475 off, offRec, cbRec, (a_cbReq), __LINE__)
3476 switch (bRecType)
3477 {
3478 /*
3479 * Scan external definitions for intrinsics needing mangling.
3480 */
3481 case OMF_EXTDEF:
3482 {
3483 while (offRec + 1 < cbRec)
3484 {
3485 uint8_t cch = pbRec[offRec++];
3486 OMF_CHECK_RET(cch, EXTDEF);
3487 char *pchName = (char *)&pbRec[offRec];
3488 offRec += cch;
3489
3490 OMF_CHECK_RET(2, EXTDEF);
3491 uint16_t idxType = pbRec[offRec++];
3492 if (idxType & 0x80)
3493 idxType = ((idxType & 0x7f) << 8) | pbRec[offRec++];
3494
3495 if (g_cVerbose > 2)
3496 printf(" EXTDEF [%u]: %-*.*s type=%#x\n", cExtDefs, cch, cch, pchName, idxType);
3497 else if (g_cVerbose > 0)
3498 printf(" U %-*.*s\n", cch, cch, pchName);
3499
3500 /* Look for g_apszExtDefRenames entries that requires changing. */
3501 if ( cch >= 5
3502 && cch <= 7
3503 && pchName[0] == '_'
3504 && pchName[1] == '_'
3505 && ( pchName[2] == 'U'
3506 || pchName[2] == 'I'
3507 || pchName[2] == 'P')
3508 && ( pchName[3] == '4'
3509 || pchName[3] == '8'
3510 || pchName[3] == 'I'
3511 || pchName[3] == 'T') )
3512 {
3513 uint32_t i = RT_ELEMENTS(g_apszExtDefRenames);
3514 while (i-- > 0)
3515 if ( cch == (uint8_t)g_apszExtDefRenames[i][0]
3516 && memcmp(&g_apszExtDefRenames[i][1], pchName, cch) == 0)
3517 {
3518 pchName[0] = fProbably32bit ? '?' : '_';
3519 pchName[1] = '?';
3520 break;
3521 }
3522 }
3523
3524 cExtDefs++;
3525 }
3526 break;
3527 }
3528
3529 /*
3530 * Record LNAME records, scanning for FLAT.
3531 */
3532 case OMF_LNAMES:
3533 {
3534 while (offRec + 1 < cbRec)
3535 {
3536 uint8_t cch = pbRec[offRec];
3537 if (offRec + 1 + cch >= cbRec)
3538 return error(pszFile, "Invalid LNAME string length at %#x+3+%#x: %#x (cbFile=%#lx)\n",
3539 off, offRec, cch, (unsigned long)cbFile);
3540 if (cLNames + 1 >= cLNamesMax)
3541 return error(pszFile, "Too many LNAME strings\n");
3542
3543 if (g_cVerbose > 2)
3544 printf(" LNAME[%u]: %-*.*s\n", cLNames, cch, cch, &pbRec[offRec + 1]);
3545
3546 papchLNames[cLNames++] = (const char *)&pbRec[offRec];
3547 if (cch == 4 && memcmp(&pbRec[offRec + 1], "FLAT", 4) == 0)
3548 fProbably32bit = true;
3549
3550 offRec += cch + 1;
3551 }
3552 break;
3553 }
3554
3555 /*
3556 * Display public names if -v is specified.
3557 */
3558 case OMF_PUBDEF16:
3559 case OMF_PUBDEF32:
3560 case OMF_LPUBDEF16:
3561 case OMF_LPUBDEF32:
3562 {
3563 if (g_cVerbose > 0)
3564 {
3565 char const chType = bRecType == OMF_PUBDEF16 || bRecType == OMF_PUBDEF32 ? 'T' : 't';
3566 const char *pszRec = "LPUBDEF";
3567 if (chType == 'T')
3568 pszRec++;
3569
3570 OMF_CHECK_RET(2, [L]PUBDEF);
3571 uint16_t idxGrp = pbRec[offRec++];
3572 if (idxGrp & 0x80)
3573 idxGrp = ((idxGrp & 0x7f) << 8) | pbRec[offRec++];
3574
3575 OMF_CHECK_RET(2, [L]PUBDEF);
3576 uint16_t idxSeg = pbRec[offRec++];
3577 if (idxSeg & 0x80)
3578 idxSeg = ((idxSeg & 0x7f) << 8) | pbRec[offRec++];
3579
3580 uint16_t uFrameBase = 0;
3581 if (idxSeg == 0)
3582 {
3583 OMF_CHECK_RET(2, [L]PUBDEF);
3584 uFrameBase = RT_MAKE_U16(pbRec[offRec], pbRec[offRec + 1]);
3585 offRec += 2;
3586 }
3587 if (g_cVerbose > 2)
3588 printf(" %s: idxGrp=%#x idxSeg=%#x uFrameBase=%#x\n", pszRec, idxGrp, idxSeg, uFrameBase);
3589 uint16_t const uSeg = idxSeg ? idxSeg : uFrameBase;
3590
3591 while (offRec + 1 < cbRec)
3592 {
3593 uint8_t cch = pbRec[offRec++];
3594 OMF_CHECK_RET(cch, [L]PUBDEF);
3595 const char *pchName = (const char *)&pbRec[offRec];
3596 offRec += cch;
3597
3598 uint32_t offSeg;
3599 if (bRecType & OMF_REC32)
3600 {
3601 OMF_CHECK_RET(4, [L]PUBDEF);
3602 offSeg = RT_MAKE_U32_FROM_U8(pbRec[offRec], pbRec[offRec + 1], pbRec[offRec + 2], pbRec[offRec + 3]);
3603 offRec += 4;
3604 }
3605 else
3606 {
3607 OMF_CHECK_RET(2, [L]PUBDEF);
3608 offSeg = RT_MAKE_U16(pbRec[offRec], pbRec[offRec + 1]);
3609 offRec += 2;
3610 }
3611
3612 OMF_CHECK_RET(2, [L]PUBDEF);
3613 uint16_t idxType = pbRec[offRec++];
3614 if (idxType & 0x80)
3615 idxType = ((idxType & 0x7f) << 8) | pbRec[offRec++];
3616
3617 if (g_cVerbose > 2)
3618 printf(" %s[%u]: off=%#010x type=%#x %-*.*s\n", pszRec, cPubDefs, offSeg, idxType, cch, cch, pchName);
3619 else if (g_cVerbose > 0)
3620 printf("%04x:%08x %c %-*.*s\n", uSeg, offSeg, chType, cch, cch, pchName);
3621
3622 cPubDefs++;
3623 }
3624 }
3625 break;
3626 }
3627 }
3628
3629 /* advance */
3630 off += cbRec + 3;
3631 }
3632 return true;
3633}
3634
3635
3636/**
3637 * Does the convertion using convertelf and convertcoff.
3638 *
3639 * @returns exit code (0 on success, non-zero on failure)
3640 * @param pszFile The file to convert.
3641 */
3642static int convertit(const char *pszFile)
3643{
3644 /* Construct the filename for saving the unmodified file. */
3645 char szOrgFile[_4K];
3646 size_t cchFile = strlen(pszFile);
3647 if (cchFile + sizeof(".original") > sizeof(szOrgFile))
3648 {
3649 error(pszFile, "Filename too long!\n");
3650 return RTEXITCODE_FAILURE;
3651 }
3652 memcpy(szOrgFile, pszFile, cchFile);
3653 memcpy(&szOrgFile[cchFile], ".original", sizeof(".original"));
3654
3655 /* Read the whole file. */
3656 void *pvFile;
3657 size_t cbFile;
3658 if (readfile(pszFile, &pvFile, &cbFile))
3659 {
3660 /*
3661 * Do format conversions / adjustments.
3662 */
3663 bool fRc = false;
3664 uint8_t *pbFile = (uint8_t *)pvFile;
3665 if ( cbFile > sizeof(Elf64_Ehdr)
3666 && pbFile[0] == ELFMAG0
3667 && pbFile[1] == ELFMAG1
3668 && pbFile[2] == ELFMAG2
3669 && pbFile[3] == ELFMAG3)
3670 {
3671 if (writefile(szOrgFile, pvFile, cbFile))
3672 {
3673 FILE *pDst = openfile(pszFile, true /*fWrite*/);
3674 if (pDst)
3675 {
3676 fRc = convertElfToOmf(pszFile, pbFile, cbFile, pDst);
3677 fRc = fclose(pDst) == 0 && fRc;
3678 }
3679 }
3680 }
3681 else if ( cbFile > sizeof(IMAGE_FILE_HEADER)
3682 && RT_MAKE_U16(pbFile[0], pbFile[1]) == IMAGE_FILE_MACHINE_AMD64
3683 && RT_MAKE_U16(pbFile[2], pbFile[3]) * sizeof(IMAGE_SECTION_HEADER) + sizeof(IMAGE_FILE_HEADER)
3684 < cbFile
3685 && RT_MAKE_U16(pbFile[2], pbFile[3]) > 0)
3686 {
3687 if (writefile(szOrgFile, pvFile, cbFile))
3688 {
3689 FILE *pDst = openfile(pszFile, true /*fWrite*/);
3690 if (pDst)
3691 {
3692 fRc = convertCoffToOmf(pszFile, pbFile, cbFile, pDst);
3693 fRc = fclose(pDst) == 0 && fRc;
3694 }
3695 }
3696 }
3697 else if ( cbFile >= 8
3698 && pbFile[0] == OMF_THEADR
3699 && RT_MAKE_U16(pbFile[1], pbFile[2]) < cbFile)
3700 {
3701 const char **papchLNames = (const char **)calloc(sizeof(*papchLNames), _32K);
3702 fRc = writefile(szOrgFile, pvFile, cbFile)
3703 && convertomf(pszFile, pbFile, cbFile, papchLNames, _32K)
3704 && writefile(pszFile, pvFile, cbFile);
3705 free(papchLNames);
3706 }
3707 else
3708 fprintf(stderr, "error: Don't recognize format of '%s' (%#x %#x %#x %#x, cbFile=%lu)\n",
3709 pszFile, pbFile[0], pbFile[1], pbFile[2], pbFile[3], (unsigned long)cbFile);
3710 free(pvFile);
3711 if (fRc)
3712 return 0;
3713 }
3714 return 1;
3715}
3716
3717
3718int main(int argc, char **argv)
3719{
3720 int rcExit = 0;
3721
3722 /*
3723 * Scan the arguments.
3724 */
3725 for (int i = 1; i < argc; i++)
3726 {
3727 if (argv[i][0] == '-')
3728 {
3729 const char *pszOpt = &argv[i][1];
3730 if (*pszOpt == '-')
3731 {
3732 /* Convert long options to short ones. */
3733 pszOpt--;
3734 if (!strcmp(pszOpt, "--verbose"))
3735 pszOpt = "v";
3736 else if (!strcmp(pszOpt, "--version"))
3737 pszOpt = "V";
3738 else if (!strcmp(pszOpt, "--help"))
3739 pszOpt = "h";
3740 else
3741 {
3742 fprintf(stderr, "syntax errro: Unknown options '%s'\n", pszOpt);
3743 return 2;
3744 }
3745 }
3746
3747 /* Process the list of short options. */
3748 while (*pszOpt)
3749 {
3750 switch (*pszOpt++)
3751 {
3752 case 'v':
3753 g_cVerbose++;
3754 break;
3755
3756 case 'V':
3757 printf("%s\n", "$Revision: 60197 $");
3758 return 0;
3759
3760 case '?':
3761 case 'h':
3762 printf("usage: %s [options] -o <output> <input1> [input2 ... [inputN]]\n",
3763 argv[0]);
3764 return 0;
3765 }
3766 }
3767 }
3768 else
3769 {
3770 /*
3771 * File to convert. Do the job right away.
3772 */
3773 rcExit = convertit(argv[i]);
3774 if (rcExit != 0)
3775 break;
3776 }
3777 }
3778
3779 return rcExit;
3780}
3781
3782
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette