|
|
/***********************************************************************
* Microsoft (R) 32-Bit Incremental Linker * * Copyright (C) Microsoft Corp 1992-95. All rights reserved. * * File: cvtomf.cpp * * File Comments: * * Conversion from OMF to COFF * ***********************************************************************/
#include "link.h"
#include "cvtomf.h"
// Type definitions
typedef struct RELOCS { IMAGE_RELOCATION Reloc; struct RELOCS *Next; } RELOCS, *PRELOCS;
typedef struct RELOC_LIST { PRELOCS First; PRELOCS Last; WORD Count; } RELOC_LIST, *PRELOC_LIST;
typedef struct LINENUMS { IMAGE_LINENUMBER Linenum; struct LINENUMS *Next; } LINENUMS, *PLINENUMS;
typedef struct LINENUM_LIST { PLINENUMS First; PLINENUMS Last; WORD Count; } LINENUM_LIST, *PLINENUM_LIST;
// Data definitions
static FILE *objfile;
static jmp_buf mark;
char szCvtomfSourceName[_MAX_PATH];
static SHORT mods; // module count
static DWORD isymDefAux;
// rectyp, use32, reclen, chksum: fields common to all OMF records
static SHORT rectyp; static SHORT use32; static SHORT reclen; static BYTE chksum;
// lnms, lname: name list counter/array
static SHORT lnms; static char *lname[MAXNAM]; static DWORD llname[MAXNAM]; static char *comments[MAXCOM]; static SHORT ncomments; static LONG cmntsize; static fPrecomp; // Regular types or precompiled types?
// segs, grps, exts: segment/group/external counters
static SHORT segs; static SHORT grps; static SHORT defs; static WORD exts;
// segment, group, external: arrays of symbol table indices
static DWORD segment[MAXSCN]; static DWORD group[MAXGRP]; static DWORD extdefs[MAXEXT]; static DWORD external[MAXEXT];
struct segdefn { SHORT namindx; SHORT scn; DWORD align; DWORD flags; } segindx[MAXNAM];
static DWORD SEG_ALIGN[] = { 0L, 1L, 2L, 16L, 1024L*4L, 4L, 0L, 0L };
static SHORT cursegindx;
// dattype, datscn, datoffset: type/section/offset of last data record
static WORD dattype; static SHORT datscn; static DWORD datoffset;
// text_scn: text section #, comes from segdef(), used in handling LEXTDEF
// records
static SHORT text_scn; static SHORT data_scn; static SHORT bss_scn;
// Hash queue for global symbols
static struct sym **hashhead; static struct rlct **rlcthash;
static int omfpass;
// OMF cannot have more than 32k line entries per module
static struct lines *lines; static int line_indx;
#define ALLOCSZ (64) // must be power of 2
#define ALLOCMSK (ALLOCSZ - 1)
static DWORD target[4]; // threads
static BOOL fTargetThreadSeg[4];
struct sfix { DWORD offset; DWORD datoffset; SHORT datscn; WORD dattype; struct sfix *next; };
struct sfix *fixlist, *fixlast;
static WORD flag; static DWORD scnsize; // total size of all sections
static DWORD strsize; // total size of the string table
static DWORD nreloc; // relocation counter
static DWORD nlnno; // linenumber counter
static WORD nscns; // section counter
static DWORD nsyms; // symbol counter
static IMAGE_SECTION_HEADER scnhdr[MAXSCN]; // section headers
static DWORD scnauxidx[MAXSCN]; // special aux symbol entries for each section
static BYTE *RawData[MAXSCN]; static DWORD RawDataMaxSize[MAXSCN]; static PIMAGE_SYMBOL SymTable; static DWORD SymTableMaxSize; static char *CvtomfStringTable; static DWORD StringTableMaxSize;
static RELOC_LIST Relocations[MAXSCN]; static LINENUM_LIST Linenumbers[MAXSCN];
// fatal: print an error message and exit
void fatal(char *format, ...) { va_list args;
va_start(args, format);
printf("LINK : error : "); vprintf(format, args);
putc('\n', stdout);
va_end(args);
_fcloseall();
longjmp(mark, -1); }
VOID syminit(void) { if (!hashhead) { hashhead = (struct sym **) PvAlloc(NBUCKETS * sizeof(struct sym *)); } memset(hashhead, 0, NBUCKETS * sizeof(struct sym *));
if (rlcthash == NULL) { rlcthash = (struct rlct **) PvAlloc(NBUCKETS * sizeof(struct rlct *)); } memset(rlcthash, 0, NBUCKETS * sizeof(struct rlct *)); }
// block: read a block
// ** side-effect ** : update reclen
VOID block(unsigned char *buffer, long size) { if (fread(buffer, 1, (size_t)size, objfile) != (unsigned int)size) { fatal("Bad read of object file"); }
reclen -= (SHORT) size; }
// byte, word, dword: read a fixed-length field
BYTE byte(void) { BYTE c;
block(&c, 1L); return c; }
WORD word(void) { BYTE c[2];
block(c, 2L); return((WORD) c[0] | ((WORD) c[1] << 8)); }
DWORD dword(void) { BYTE c[4];
block(c, 4L); return((DWORD) c[0] | ((DWORD) c[1] << 8) | ((DWORD) c[2] << 16) | ((DWORD) c[3] << 24)); }
// index, length, string: read a variable-length field
SHORT index(void) { BYTE c[2]; SHORT i;
block(c, 1L); i = INDEX_BYTE(c);
if (i == (SHORT) -1) { block(c + 1, 1L); i = (SHORT) INDEX_WORD(c); } return i; }
DWORD length(void) { BYTE c[4];
block(c, 1L);
switch (c[0]) { case LENGTH2: block(c, 2L); return (DWORD)c[0] | ((DWORD)c[1] << 8);
case LENGTH3: block(c, 3L); return (DWORD)c[0] | ((DWORD)c[1] << 8) | ((DWORD)c[2] << 16);
case LENGTH4: block(c, 4L); return (DWORD)c[0] | ((DWORD)c[1] << 8) | ((DWORD)c[2] << 16) | ((DWORD)c[3] << 24);
default: return (DWORD)c[0]; } }
char *string(BOOL strip) { BYTE c; BYTE *s;
block(&c, 1L); s = (BYTE *) PvAlloc(c + 1);
block(s, (long) c); s[c] = '\0';
strip = strip; return (char *)s; }
// hash function for global symbols hash queue
int symhash(const char *key) { unsigned int index = 0;
while (*key) { index += (index << 1) + *key++; }
return(index % NBUCKETS); }
struct sym *findsym(const char *name) { struct sym *ptr;
ptr = hashhead[symhash(name)]; while (ptr) { if (!strcmp(ptr->name, name)) { break; } ptr = ptr->next; } return(ptr); }
VOID addsym(char *name, DWORD offset, WORD type, SHORT scn, WORD ext, WORD typ) { struct sym **list; struct sym *ptr;
ptr = (struct sym *) PvAllocZ(sizeof(struct sym));
ptr->name = name; ptr->offset = offset; ptr->type = type; ptr->scn = scn; ptr->typ = typ; ptr->ext = ext; list = &hashhead[symhash(name)]; if (!*list) { *list = ptr; } else { ptr->next = *list; *list = ptr; } }
VOID updatesym(char *name, DWORD offset, WORD type, SHORT scn, WORD typ) { struct sym *ptr;
ptr = findsym(name); if (ptr) { ptr->offset = offset; ptr->type = type; ptr->scn = scn; ptr->typ = typ; } else { addsym(name, offset, type, scn, exts, typ); } }
DWORD AddLongName(const char *szName) { size_t cbName; DWORD ibName;
if (!strsize) { CvtomfStringTable = (char *) PvAllocZ(BUFFERSIZE);
strsize = sizeof(DWORD); StringTableMaxSize = BUFFERSIZE; }
cbName = strlen(szName) + 1;
ibName = strsize;
if (strsize + cbName > StringTableMaxSize) { void *pv;
// String table grew larger than BUFFERSIZE.
pv = PvAllocZ(StringTableMaxSize + BUFFERSIZE + cbName); memcpy(pv, CvtomfStringTable, StringTableMaxSize); FreePv(CvtomfStringTable);
CvtomfStringTable = (char *) pv; StringTableMaxSize += BUFFERSIZE + cbName; }
memcpy(CvtomfStringTable+ibName, szName, cbName);
strsize += cbName;
return(ibName); }
DWORD symbol(const char *name, DWORD value, SHORT scnum, WORD sclass, WORD csymAux) { int len; IMAGE_SYMBOL syment;
len = strlen(name);
if (len <= IMAGE_SIZEOF_SHORT_NAME) { strncpy((char *)syment.N.ShortName, name, IMAGE_SIZEOF_SHORT_NAME); } else { syment.N.Name.Short = 0; syment.N.Name.Long = AddLongName(name); }
syment.Value = value; syment.SectionNumber = scnum; syment.Type = IMAGE_SYM_TYPE_NULL; syment.StorageClass = (BYTE) sclass; syment.NumberOfAuxSymbols = (BYTE) csymAux;
if (!nsyms) { SymTable = (PIMAGE_SYMBOL) PvAllocZ(BUFFERSIZE);
SymTableMaxSize = BUFFERSIZE; }
if ((nsyms+1)*sizeof(IMAGE_SYMBOL) > SymTableMaxSize) { void *pv;
// Symbol table grew larger than BUFFERSIZE.
pv = PvAllocZ(SymTableMaxSize+BUFFERSIZE); memcpy(pv, (void *) SymTable, SymTableMaxSize); FreePv((void *) SymTable);
SymTable = (PIMAGE_SYMBOL) pv; SymTableMaxSize += BUFFERSIZE; }
SymTable[nsyms] = syment;
return(nsyms++); }
DWORD aux(PIMAGE_AUX_SYMBOL AuxSym) { if ((nsyms+1)*sizeof(IMAGE_SYMBOL) > SymTableMaxSize) { void *pv;
// Symbol table grew larger than BUFFERSIZE.
pv = PvAllocZ(SymTableMaxSize+BUFFERSIZE); memcpy(pv, (void *) SymTable, SymTableMaxSize); FreePv((void *) SymTable);
SymTable = (PIMAGE_SYMBOL) pv; SymTableMaxSize += BUFFERSIZE; }
SymTable[nsyms] = *(PIMAGE_SYMBOL) AuxSym;
return(nsyms++); }
VOID extdef(BOOL cextdef, WORD sclass) { char *name; WORD type; WORD typ; WORD scn; SHORT nam; struct sym *ptr;
while (reclen > 1) { if (cextdef) { nam = index(); name = lname[nam]; } else { name = (sclass == IMAGE_SYM_CLASS_STATIC) ? string(FALSE) : string (TRUE); } typ = (WORD)index();
if (cextdef && llname[nam]) { continue; }
if (++exts >= MAXEXT) { fatal("Too many externals"); } extdefs[++defs] = exts; if (!strcmp(name, _ACRTUSED) || !strcmp(name, __ACRTUSED)) { continue; /* do nothing */ }
type = (sclass == IMAGE_SYM_CLASS_STATIC) ? (WORD)S_LEXT : (WORD)S_EXT;
// Static text. Pass along text section number, or
// AT&T linker will barf (it doesn't like getting
// relocation info for something of class static...).
// Skip the matching LPUBDEF rec that goes along with
// this LEXTDEF -- we already have the section #.
//
// N.B. Assumes LEXTDEF/LPUBDEF recs only emitted for
// static text (not data). Cmerge group PROMISES this
// will be true forever and ever. Note that these
// recs are only emitted for forward references; the
// compiler does self-relative relocation for
// backward references...
ptr = findsym(name); scn = ptr ? ptr->scn : IMAGE_SYM_UNDEFINED; addsym(name, 0, type, scn, exts, typ); } }
VOID save_fixupp(DWORD offset) { struct sfix *newfix;
newfix = (struct sfix *) PvAlloc(sizeof(struct sfix));
newfix->offset = offset; newfix->datoffset = datoffset; newfix->datscn = datscn; newfix->dattype = dattype; newfix->next = NULL; if (!fixlast) { fixlist = fixlast = newfix; } else { fixlast->next = newfix; fixlast = newfix; } }
// method: read a segment, group or external index, if necessary, and return
// a symbol table index
DWORD method(int x) { DWORD idx; SHORT temp;
switch (x) { case SEGMENT: idx = segment[index()]; break;
case GROUP: idx = group[index()]; break;
case EXTERNAL: temp = index(); if (llname[temp]) { idx = llname[temp]; break; } idx = external[extdefs[temp]]; break;
case LOCATION: case TARGET: idx = (DWORD)-1; break;
default: fatal("Bad method in FIXUP record"); }
return(idx); }
// saverlct: remember that there is a fixup to the specified offset
// from the specified symbol.
VOID saverlct(DWORD TargetSymbolIndex, DWORD offset) { unsigned bucket; struct rlct *ptr;
bucket = (TargetSymbolIndex + offset) % NBUCKETS;
ptr = rlcthash[bucket]; while (ptr) { if ((ptr->TargetSymbolIndex == TargetSymbolIndex) && (ptr->offset == offset)) { return; }
ptr = ptr->next; }
ptr = (struct rlct *) PvAlloc(sizeof(struct rlct));
ptr->TargetSymbolIndex = TargetSymbolIndex; ptr->offset = offset; ptr->next = rlcthash[bucket];
rlcthash[bucket] = ptr; }
// rlctlookup: locates the synthetic symbol (created by
// createrlctsyms) representing the specified symbol and offset (which
// was used as a fixup target).
DWORD rlctlookup(DWORD TargetSymbolIndex, DWORD offset) { unsigned bucket; struct rlct *ptr;
bucket = (TargetSymbolIndex + offset) % NBUCKETS;
ptr = rlcthash[bucket]; for (;;) { if ((ptr->TargetSymbolIndex == TargetSymbolIndex) && (ptr->offset == offset)) { return(ptr->SymbolTableIndex); }
ptr = ptr->next; }
#if 0
// We didn't find it. This should never happen ... if we put an assert
// here, will it prevent building standalone cvtomf.exe?
return((DWORD)-1); #endif
}
// createrlctsyms: creates synthetic symbols for non-zero offsets
// from normal symbols.
VOID createrlctsyms(void) { unsigned bucket; struct rlct *ptr; SHORT scn; DWORD value; char name[8]; unsigned i = 0;
for (bucket = 0; bucket < NBUCKETS; bucket++) { for (ptr = rlcthash[bucket]; ptr != NULL; ptr = ptr->next) { scn = SymTable[ptr->TargetSymbolIndex].SectionNumber;
if (scn > 0) { sprintf(name, "$$R%04X", ++i); value = SymTable[ptr->TargetSymbolIndex].Value + ptr->offset; ptr->SymbolTableIndex = symbol(name, value, scn, IMAGE_SYM_CLASS_STATIC, 0); } else { ptr->SymbolTableIndex = ptr->TargetSymbolIndex; } } } }
VOID AddReloc ( IN PRELOC_LIST PtrList, IN DWORD VirtualAddress, IN DWORD SymbolTableIndex, IN WORD Type )
/*++
Routine Description:
Adds to the relocation list.
Arguments:
Return Value:
--*/
{ PRELOCS ptrReloc;
// Allocate next member.
ptrReloc = (PRELOCS) PvAlloc(sizeof(RELOCS));
// Set the fields of the new member.
ptrReloc->Reloc.VirtualAddress = VirtualAddress; ptrReloc->Reloc.SymbolTableIndex = SymbolTableIndex; ptrReloc->Reloc.Type = Type; ptrReloc->Next = NULL;
// If first member in list, remember first member.
if (!PtrList->First) { PtrList->First = ptrReloc; } else { // Not first member, so append to end of list.
PtrList->Last->Next = ptrReloc; }
// Increment number of members in list.
PtrList->Count++;
// Remember last member in list.
PtrList->Last = ptrReloc; }
VOID relocation(SHORT scn, DWORD vaddr, DWORD symndx, WORD type, DWORD offset) { BYTE *pb; SHORT i; PIMAGE_SYMBOL sym;
i = scn - 1;
sym = SymTable + symndx;
if (!strcmp((const char *)sym->N.ShortName, ".file")) { flag = 1; return; }
nreloc++; scnhdr[i].NumberOfRelocations++;
AddReloc(&Relocations[i], vaddr, symndx, type);
pb = RawData[i]+vaddr;
switch (type) { case R_OFF8: case R_OFF16: case R_PCRBYTE: *pb += (BYTE) offset; break;
case IMAGE_REL_I386_DIR16: case IMAGE_REL_I386_REL16: *(WORD UNALIGNED *) pb += (WORD) offset; break;
case IMAGE_REL_I386_DIR32: case IMAGE_REL_I386_REL32: *(DWORD UNALIGNED *) pb += offset; break;
case IMAGE_REL_I386_DIR32NB: break;
default: fatal("Bad COFF relocation type"); } }
VOID fixupp(void) { int i; BYTE c[3]; IMAGE_RELOCATION reloc[MAXREL]; DWORD offset[MAXREL]; BOOL fTargetSeg;
i = 0;
while (reclen > 1) { block(c, 1L);
if (TRD_THRED(c) == (WORD)-1) { block(c + 1, 2L);
if (i >= MAXREL) { fatal("Too many relocation entries"); } if (dattype != LEDATA && dattype != LIDATA) { fatal("Bad relocatable reference"); } reloc[i].VirtualAddress = datoffset + LCT_OFFSET(c);
if (!FIX_F(c)) { method(FIX_FRAME(c)); } if (!FIX_T(c)) { reloc[i].SymbolTableIndex = method(FIX_TARGT(c)); fTargetSeg = (FIX_TARGT(c) == SEGMENT); } else { reloc[i].SymbolTableIndex = target[FIX_TARGT(c)]; fTargetSeg = fTargetThreadSeg[FIX_TARGT(c)]; }
switch (LCT_LOC(c)) { case LOBYTE: if (LCT_M(c)) { reloc[i].Type = R_OFF8; } else { reloc[i].Type = R_PCRBYTE; } break;
case HIBYTE: if (!LCT_M(c)) { fatal("Bad relocation type"); } reloc[i].Type = R_OFF16; break;
case OFFSET16: case OFFSET16LD: if (LCT_M(c)) { reloc[i].Type = IMAGE_REL_I386_DIR16; } else { reloc[i].Type = IMAGE_REL_I386_REL16; } break;
case OFFSET32: case OFFSET32LD: if (LCT_M(c)) { reloc[i].Type = IMAGE_REL_I386_DIR32; } else { reloc[i].Type = IMAGE_REL_I386_REL32; } break;
case OFFSET32NB: reloc[i].Type = IMAGE_REL_I386_DIR32NB; break;
case POINTER48: // UNDONE: Only allow if $$SYMBOLS, $$TYPES, etc
reloc[i].Type = IMAGE_REL_I386_DIR32; break;
case BASE: case POINTER32: fatal("Segment reference in fixup record");
default: fatal("Bad relocation type"); }
if (!FIX_P(c)) { offset[i] = use32 ? dword() : (long)word();
if (fTargetSeg && (offset[i] != 0)) { // In Pass1, remember the targets of fixups to an offset
// from some symbol. In Pass2, make a fixup with offset 0
// from a synthetic symbol (instead of a non-zero offset
// from the original target symbol).
if (omfpass == PASS1) { saverlct(reloc[i].SymbolTableIndex, offset[i]); } else { DWORD SymbolTableIndex;
SymbolTableIndex = rlctlookup(reloc[i].SymbolTableIndex, offset[i]);
if (SymbolTableIndex != reloc[i].SymbolTableIndex) { reloc[i].SymbolTableIndex = SymbolTableIndex; offset[i] = 0; } } } } else { offset[i] = 0; }
i++;
} else if (!TRD_D(c)) { target[TRD_THRED(c)] = method(TRD_METHOD(c)); fTargetThreadSeg[TRD_THRED(c)] = (TRD_METHOD(c) == SEGMENT);
} else { method(TRD_METHOD(c)); } }
if (omfpass == PASS1) { return; }
while (i-- > 0) { relocation(segindx[datscn].scn, reloc[i].VirtualAddress, reloc[i].SymbolTableIndex, reloc[i].Type, offset[i]); } }
VOID pubdef(WORD sclass) { WORD grp; WORD type; SHORT scn; WORD frame; char *name; DWORD value;
grp = (WORD) index(); scn = index();
if (!scn) { scn = IMAGE_SYM_ABSOLUTE; frame = word(); } else { scn = segindx[scn].scn; }
while (reclen > 1) { name = string(TRUE); value = use32 ? dword() : (long)word(); type = (WORD) index();
if (++exts >= MAXEXT) { fatal("Too many externals"); }
addsym(name, value, S_PUB, scn, exts, type); }
sclass = sclass; }
VOID scndata(SHORT scn, DWORD offset, BYTE *buffer, DWORD size) { SHORT i;
i = scn - 1;
if (offset+size > RawDataMaxSize[i]) { void *pv;
// Section grew larger than BUFFERSIZE.
pv = PvAllocZ(RawDataMaxSize[i] + BUFFERSIZE + size); memcpy(pv, RawData[i], RawDataMaxSize[i]); FreePv(RawData[i]);
RawData[i] = (BYTE *) pv; RawDataMaxSize[i] += BUFFERSIZE + size; }
memcpy(RawData[i]+offset, buffer, (size_t)size); }
VOID ledata(void) { long size; BYTE buffer[MAXDAT];
dattype = LEDATA; datscn = index(); datoffset = use32 ? dword() : (DWORD)word();
size = reclen - 1; if (size > MAXDAT) { fatal("Bad data record; too large"); } memset(buffer, 0, (size_t)size); block(buffer, size);
scndata(segindx[datscn].scn, datoffset, buffer, size); }
// expand: expand an iterated data block
long expand(long offset) { long repcnt; long blkcnt; long filptr; long i; SHORT sav_reclen; unsigned char size; BYTE buffer[MAXDAT / 2];
repcnt = use32 ? dword() : (long)word(); blkcnt = (long)word();
if (blkcnt) { filptr = ftell(objfile); sav_reclen = reclen;
while (repcnt-- > 0) { reclen = sav_reclen; for (i = 0; i < blkcnt; i++) { offset = expand(offset); }
if (repcnt && fseek(objfile, filptr, 0)) { fatal("Cannot expand iterated data"); } } } else { size = byte();
// if (size > MAXDAT / 2) {
// fatal("Bad iterated data record; too large");
// }
block(buffer, (long)size);
while (repcnt-- > 0) { scndata(segindx[datscn].scn, offset, buffer, (long)size); offset += (long)size; } }
return offset; }
VOID lidata(void) { dattype = LIDATA; datscn = index(); datoffset = use32 ? dword() : (DWORD)word(); while (reclen > 1) { datoffset = expand(datoffset); } }
VOID comdef(WORD sclass) { char *name; DWORD value; WORD type; BYTE segtype;
while (reclen > 1) { name = string(TRUE); type = (WORD)index(); segtype = byte(); value = length();
if (segtype == COMM_FAR) { value *= length(); }
if (++exts >= MAXEXT) { fatal("Too many externals"); }
extdefs[++defs] = exts; external[exts] = symbol(name, value, IMAGE_SYM_UNDEFINED, sclass, 0); } }
VOID lpubdef (WORD sclass) { WORD grp, type; SHORT scn; WORD frame; char *name; DWORD value;
grp = (WORD)index(); scn = index();
if (!scn) { scn = IMAGE_SYM_ABSOLUTE; frame = word(); } else { scn = segindx[scn].scn; }
while (reclen > 1) { name = string(FALSE); value = use32 ? dword() : (long)word(); type = (WORD)index();
// Update corresponding LEXTDEF symbol table entry's value
// field with the offset field from this LPUBDEF. FIXUPP
// will then cause relocation() to do self-relative fixups
// for static functions.
updatesym(name, value, S_LPUB, scn, type); } sclass = sclass; }
VOID coment(const char *szOmf) { BYTE flags; BYTE SymbolClass; WORD weakExt, defaultExt; struct sym *sptr; WORD count; BYTE *commp;
flags = byte(); SymbolClass = byte(); switch (SymbolClass) { case COM_PRECOMP: fPrecomp = TRUE; break;
case COM_EXESTR: if (ncomments >= MAXCOM) { Warning(szOmf, TOOMANYEXESTR, MAXCOM); } else { long tmp_reclen;
/* reclen includes chksum, which is used as NULL */
commp = (BYTE *)PvAlloc(reclen);
tmp_reclen = (long)reclen; block(commp, tmp_reclen - 1); // side effects on reclen
commp[tmp_reclen - 1] = '\0'; comments[ncomments++] = (char *)commp; cmntsize += tmp_reclen; // want to include null in size
} break;
case COM_WKEXT: case COM_LZEXT: while (reclen > 1) { weakExt = (WORD)extdefs[index()]; defaultExt = (WORD)extdefs[index()]; for (count = 0; count < NBUCKETS; count++) { sptr = hashhead[count]; while (sptr) { if (sptr->ext == weakExt) { if (!sptr->scn) { sptr->type = (SymbolClass == COM_WKEXT ? (WORD)S_WKEXT : (WORD)S_LZEXT); sptr->weakDefaultExt = defaultExt; } break; } sptr = sptr->next; } } } break; } }
WORD section(const char *name, DWORD paddr, DWORD vaddr, DWORD size, DWORD flags) { WORD i; size_t len; DWORD align;
i = nscns++;
if (nscns > MAXSCN) { fatal("Too many COFF sections"); }
RawData[i] = (BYTE *) PvAllocZ(BUFFERSIZE); RawDataMaxSize[i] = BUFFERSIZE;
len = strlen(name);
if (len <= IMAGE_SIZEOF_SHORT_NAME) { strncpy((char *)scnhdr[i].Name, name, IMAGE_SIZEOF_SHORT_NAME); } else { sprintf((char *)scnhdr[i].Name, "/%lu", AddLongName(name)); }
scnhdr[i].Misc.PhysicalAddress = 0; scnhdr[i].VirtualAddress = vaddr; scnhdr[i].SizeOfRawData = size; scnhdr[i].NumberOfRelocations = 0; scnhdr[i].NumberOfLinenumbers = 0;
switch (paddr) { case 1: align = IMAGE_SCN_ALIGN_1BYTES; break; case 2: align = IMAGE_SCN_ALIGN_2BYTES; break; case 4: align = IMAGE_SCN_ALIGN_4BYTES; break; case 8: align = IMAGE_SCN_ALIGN_8BYTES; break; case 16: align = IMAGE_SCN_ALIGN_16BYTES; break; default: align = IMAGE_SCN_ALIGN_16BYTES; }
scnhdr[i].Characteristics = flags | align;
if ((scnhdr[i].Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA) == 0) { scnsize += size; }
return(nscns); }
VOID segdef(void) { unsigned char acbp; unsigned short frame; unsigned short offset; SHORT scn; long size, flags = 0; char *szName; char *szClass; SHORT nam, cls; IMAGE_AUX_SYMBOL auxent; int code_seg = 0; int data_seg = 0; int bss_seg = 0;
if (++segs >= MAXSCN) { fatal("Too many SEGDEF/COMDAT records"); } acbp = byte();
if (!ACBP_A(acbp)) { // UNDONE: Absolute segments should either be fatal or ignored
frame = word(); offset = byte(); } size = use32 ? dword() : (long)word();
nam = index(); szName = lname[nam]; segindx[++cursegindx].namindx = nam;
cls = index(); szClass = lname[cls];
index(); // Skip overlay LNAME index
if (ACBP_B(acbp)) { fatal("Bad segment definition"); }
// Handle $$SYMBOLS and $$TYPES segments
if (!strcmp(szName, SYMBOLS_SEGNAME) && !strcmp(szClass, SYMBOLS_CLASS)) { szName = ".debug$S"; flags = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE | IMAGE_SCN_ALIGN_1BYTES; } else if (!strcmp(szName, TYPES_SEGNAME) && !strcmp(szClass, TYPES_CLASS)) { if (fPrecomp) { szName = ".debug$P"; } else { szName = ".debug$T"; }
flags = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE | IMAGE_SCN_ALIGN_1BYTES; } else if (strcmp(szName, ".debug$F") == 0) { flags = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_DISCARDABLE | IMAGE_SCN_ALIGN_1BYTES; } else { size_t cchClass; char *szClassEnd; char *szOmfName; size_t cchOmfName; char *szCoffName; size_t cchCoffName;
cchClass = strlen(szClass); szClassEnd = szClass + cchClass;
if ((cchClass >= 4) && (strcmp(szClassEnd - 4, "CODE") == 0)) { szOmfName = "_TEXT"; cchOmfName = 5; szCoffName = ".text"; cchCoffName = 5;
flags = IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE; code_seg = cursegindx; } else if ((cchClass >= 4) && (strcmp(szClassEnd - 4, "DATA") == 0)) { szOmfName = "_DATA"; cchOmfName = 5; szCoffName = ".data"; cchCoffName = 5;
flags = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE; data_seg = cursegindx; } else if ((cchClass >= 5) && (strcmp(szClassEnd - 5, "CONST") == 0)) { szOmfName = "CONST"; cchOmfName = 5; szCoffName = ".rdata"; cchCoffName = 6;
flags = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ; data_seg = cursegindx; } else if ((cchClass >= 3) && (strcmp(szClassEnd - 3, "BSS") == 0)) { szOmfName = "_BSS"; cchOmfName = 4; szCoffName = ".bss"; cchCoffName = 4;
flags = IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE; bss_seg = cursegindx; } else { szOmfName = NULL;
flags = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE; }
if (szOmfName != NULL) { // Check for mapping from well known OMF name to COFF name
if (memcmp(szName, szOmfName, cchOmfName) == 0) { if (szName[cchOmfName] == '\0') { szName = szCoffName; } else if (szName[cchOmfName] == '$') { char *szNameT;
szNameT = (char *)PvAlloc(cchCoffName + strlen(szName+cchOmfName) + 1);
strcpy(szNameT, szCoffName); strcat(szNameT, szName+cchOmfName);
// UNDONE: This is a memory leak (albeit a small one)
szName = szNameT; } } }
if (!ACBP_P(acbp)) { // This is a 16 bit segment
flags |= 0x00020000; // REVIEW -- need place for symbolic def
} }
segindx[cursegindx].flags = flags; segindx[cursegindx].align = SEG_ALIGN[ACBP_A(acbp)]; segindx[cursegindx].scn = scn = section(szName, segindx[cursegindx].align, 0, size, flags);
if (code_seg) { text_scn = scn; // hold text section # for L*DEF recs
} if (data_seg) { data_scn = scn; } if (bss_seg) { bss_scn = scn; }
segment[segs] = symbol(szName, 0, scn, IMAGE_SYM_CLASS_STATIC, 1);
// Create aux entry
memset(&auxent, 0, sizeof(IMAGE_AUX_SYMBOL)); auxent.Section.Length = size; scnauxidx[scn - 1] = aux(&auxent); }
VOID linnum(void) { WORD grpindex; SHORT segindex;
grpindex = (WORD) index(); segindex = index();
// store lineno data in core until we process entire set
while (reclen > 1) { WORD lineno; DWORD offset;
lineno = word(); offset = use32 ? dword() : (long) word(); lines[line_indx].offset = offset; lines[line_indx].number = lineno; line_indx++; if ((line_indx & ALLOCMSK) == 0) { lines = (struct lines *) PvRealloc(lines, sizeof(*lines)*(line_indx+ALLOCSZ)); } } }
VOID grpdef(void) { char *name; SHORT scn; BYTE x;
name = lname[index()]; scn = IMAGE_SYM_ABSOLUTE;
while (reclen > 1) { x = byte(); scn = index(); scn = segindx[scn].scn; }
if (++grps >= MAXGRP) { fatal("Too many groups"); }
group[grps] = symbol(name, 0, scn, IMAGE_SYM_CLASS_STATIC, 0); }
VOID theadr(void) { static char *first_name = NULL; char *f_name, *name; int len; WORD csymAux; IMAGE_AUX_SYMBOL auxent;
mods++; f_name = string(FALSE); if (!first_name) { first_name = f_name; strcpy(szCvtomfSourceName, first_name); }
// .h files that define variables will cause THEADR records with
// "-g" and MSC. A subsequent THEADR re-defines the original .c file.
// This is a problem: currently pcc/sdb and MSC/codeview or x.out sdb
// are unable to deal with code or variables in a header file. We will
// print a warning and aVOID spitting out extra .file symbols.
//
// a second case of multiple THEADRs comes from /lib/ldr and multiple
// .o files. In this case, the symbolic debug data is currently
// not coalesed properly so without some trickery we can't translated
// it properly. If we may concessions for an incorrect ldr then when
// it is fixed, we will be broken. Leave undone for now . . .
//
// multiple THEADRs will also be generated by #line directives that
// supply filenames. Good case of this is yacc output. Note: this
// also screws up line number entires!
if (mods > 1) { return; }
csymAux = (WORD) strlen(f_name); if (csymAux % sizeof(IMAGE_AUX_SYMBOL)) { csymAux = (WORD) ((csymAux / sizeof(IMAGE_AUX_SYMBOL)) + 1); } else { csymAux /= sizeof(IMAGE_AUX_SYMBOL); }
symbol(".file", 0, IMAGE_SYM_DEBUG, IMAGE_SYM_CLASS_FILE, csymAux);
// .file aux entry
//
// filenames are not like symbol names: up to 18 chars right in the
// aux record. filenames are never placed in the strings table
name = f_name; while (*name) { memset(&auxent, 0, sizeof(IMAGE_AUX_SYMBOL));
len = 0; while (*name && len < sizeof(IMAGE_AUX_SYMBOL)) { auxent.File.Name[len++] = *name++; }
aux(&auxent); } }
VOID cmntdata(SHORT scn, DWORD offset, char **strings, SHORT nstrings) { SHORT i;
i = scn - 1;
if (offset+nstrings > RawDataMaxSize[i]) { BYTE *pv;
// Section grew larger than BUFFERSIZE.
pv = (BYTE *)PvAllocZ(RawDataMaxSize[i] + BUFFERSIZE + nstrings); memcpy(pv, RawData[i], RawDataMaxSize[i]); FreePv(RawData[i]);
RawData[i] = (BYTE *) pv; RawDataMaxSize[i] += BUFFERSIZE + nstrings; }
memcpy(RawData[i]+offset, *strings, (size_t)nstrings); }
VOID modend(void) { if (ncomments) { SHORT scn;
scn = section(".comment", 1L, 0, cmntsize, (long)(IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_LNK_REMOVE)); cmntdata(scn, 0, comments, ncomments); for (scn = 0; scn < ncomments; scn++) { FreePv(comments[scn]); comments[scn] = NULL; } } }
VOID lnames(DWORD flag) {
while (reclen > 1) { if (++lnms >= MAXNAM) { fatal("Too many names in LNAMES record"); }
lname[lnms] = string(FALSE); llname[lnms] = flag; } }
VOID lheadr(void) { mods++; }
VOID comdatscndata(SHORT scn, DWORD offset, BYTE *buffer, DWORD size) { scnhdr[scn-1].SizeOfRawData += size; scnsize += size; scndata(scn, offset, buffer, size); }
VOID comdat(void) { WORD grp, type, SymbolClass; SHORT scn, nam; long size; DWORD align, symIdx; char *name; BYTE flags; BYTE attr; BYTE algn; BYTE checksum; IMAGE_AUX_SYMBOL auxent; BYTE buffer[MAXDAT]; static SHORT LastComdatScn;
flags = byte(); attr = byte(); algn = byte();
dattype = LEDATA; datoffset = use32 ? dword() : (DWORD)word(); type = (WORD)index();
grp = (WORD)index(); scn = index();
if (!scn) { fatal("Section not defined in COMDAT"); }
nam = index(); name = lname[nam];
size = reclen - 1; if (size > MAXDAT) { fatal("Bad data record; too large"); } memset(buffer, 0, (size_t)size); block(buffer, size);
// Check if continuation of last COMDAT.
if (!(flags & 1)) { if (++segs >= MAXSCN) { fatal("Too many SEGDEF/COMDAT records"); } } else { // continuation of COMDAT.
datscn = LastComdatScn; comdatscndata(segindx[LastComdatScn].scn, datoffset, buffer, size); return; }
datscn = ++cursegindx; segindx[datscn] = segindx[scn]; align = algn ? SEG_ALIGN[algn] : segindx[cursegindx].align; segindx[datscn].scn = section(lname[segindx[scn].namindx], align, 0, size, segindx[scn].flags | IMAGE_SCN_LNK_COMDAT); LastComdatScn = datscn; scndata(segindx[datscn].scn, datoffset, buffer, size);
// Check for iterated data (not supported yet).
if (flags & 2) { fatal("COMDAT uses iterated data"); }
SymbolClass = (flags & 4) ? (WORD)IMAGE_SYM_CLASS_STATIC : (WORD)IMAGE_SYM_CLASS_EXTERNAL;
// Create section symbol.
segment[segs] = symbol(lname[segindx[scn].namindx], 0, segindx[datscn].scn, IMAGE_SYM_CLASS_STATIC, 1);
// Create section aux entry
memset(&auxent, 0, sizeof(IMAGE_AUX_SYMBOL)); auxent.Section.Length = size; if (fread(&checksum, 1, sizeof(BYTE), objfile) != sizeof(BYTE)) { fatal("Bad read of object file"); } if (fseek(objfile, -(long)sizeof(BYTE), SEEK_CUR)) { fatal("Bad seek on object file"); } auxent.Section.CheckSum = (DWORD)checksum; switch (attr) { case 0 : attr = IMAGE_COMDAT_SELECT_NODUPLICATES; break; case 0x10 : attr = IMAGE_COMDAT_SELECT_ANY; break; case 0x20 : attr = IMAGE_COMDAT_SELECT_SAME_SIZE; break; case 0x30 : attr = IMAGE_COMDAT_SELECT_EXACT_MATCH; break; default : attr = 0; } auxent.Section.Selection = attr; scnauxidx[segindx[datscn].scn - 1] = aux(&auxent);
// Create communal name symbol
symIdx = symbol(name, 0, segindx[datscn].scn, SymbolClass, 0);
if (llname[nam] == -1) { llname[nam] = symIdx; } }
VOID nbkpat(void) { char *name; BYTE loctyp;
loctyp = byte(); name = lname[index()]; while (reclen > 1) { DWORD offset; DWORD value; BYTE *pb;
offset = use32 ? dword() : (DWORD) word(); value = use32 ? dword() : (DWORD) word();
pb = RawData[segindx[datscn].scn-1] + offset;
switch (loctyp) { case 0: *pb += (BYTE) value; break;
case 1: *(WORD UNALIGNED *) pb += (WORD) value; break;
case 2: *(DWORD UNALIGNED *) pb += value; break;
default: fatal("Ilegal LocTyp in NBKPAT record"); } } }
VOID bakpat(void) { SHORT scn; BYTE loctyp;
scn = index(); loctyp = byte(); while (reclen > 1) { DWORD offset; DWORD value; BYTE *pb;
offset = use32 ? dword() : (DWORD) word(); value = use32 ? dword() : (DWORD) word();
pb = RawData[segindx[scn].scn-1] + offset;
switch (loctyp) { case 0: *pb += (BYTE) value; break;
case 1: *(WORD UNALIGNED *) pb += (WORD) value; break;
case 2: *(DWORD UNALIGNED *) pb += value; break;
default: fatal("Ilegal LocTyp in BAKPAT record"); } } }
VOID linsym(void) { BYTE flag; DWORD offset; WORD nameindex, lineno;
flag = byte(); nameindex = index();
// store lineno data in core until we process entire set
while (reclen > 1) { lineno = word(); offset = use32 ? dword() : (long)word(); } return; }
// recskip: skip an OMF record leave checksum byte in stream
VOID recskip(void) { if (reclen > 1) { if (fseek(objfile, (long)(reclen - 1), SEEK_CUR)) { fatal("Bad seek on object file"); } reclen = 1; } }
// Define the extra symbol table records needed for a function with line
// numbers. (Assume the initial symbol has already been emitted, with an
// aux count of 1.)
VOID DefineLineNumSymbols(DWORD cline, WORD isec, DWORD /* offsetLine0 */, WORD numberLine0, DWORD cbFunc, WORD numberLineLast) { IMAGE_AUX_SYMBOL auxsym; IMAGE_SYMBOL sym;
SymTable[nsyms - 1].Type = IMAGE_SYM_TYPE_NULL | (IMAGE_SYM_DTYPE_FUNCTION << N_BTSHFT);
memset(&auxsym, 0, sizeof(IMAGE_AUX_SYMBOL)); auxsym.Sym.TagIndex = nsyms + 1; auxsym.Sym.Misc.LnSz.Linenumber = numberLine0; auxsym.Sym.Misc.TotalSize = cbFunc + 1; auxsym.Sym.FcnAry.Function.PointerToLinenumber = 0; auxsym.Sym.FcnAry.Function.PointerToNextFunction = 0; aux(&auxsym);
memset(&sym, 0, sizeof(sym)); memcpy(&sym.N.ShortName[0], ".bf\0\0\0\0\0", IMAGE_SIZEOF_SHORT_NAME); sym.SectionNumber = isec; sym.Type = IMAGE_SYM_TYPE_NULL; sym.StorageClass = IMAGE_SYM_CLASS_FUNCTION; sym.NumberOfAuxSymbols = 1; aux((PIMAGE_AUX_SYMBOL)&sym);
memset(&auxsym, 0, sizeof(auxsym)); auxsym.Sym.Misc.LnSz.Linenumber = numberLine0; aux(&auxsym);
memset(&sym, 0, sizeof(sym)); memcpy(&sym.N.ShortName[0], ".lf\0\0\0\0\0", IMAGE_SIZEOF_SHORT_NAME); sym.Value = cline; sym.SectionNumber = isec; sym.Type = IMAGE_SYM_TYPE_NULL; sym.StorageClass = IMAGE_SYM_CLASS_FUNCTION; aux((PIMAGE_AUX_SYMBOL)&sym);
memset(&sym, 0, sizeof(sym)); memcpy(&sym.N.ShortName[0], ".ef\0\0\0\0\0", IMAGE_SIZEOF_SHORT_NAME); sym.SectionNumber = isec; sym.Type = IMAGE_SYM_TYPE_NULL; sym.StorageClass = IMAGE_SYM_CLASS_FUNCTION; sym.NumberOfAuxSymbols = 1; aux((PIMAGE_AUX_SYMBOL)&sym);
memset(&auxsym, 0, sizeof(auxsym)); auxsym.Sym.Misc.LnSz.Linenumber = numberLineLast; aux(&auxsym); }
// process all remaining EXTDEF, PUBDEF, and COMDEFS not in $$SYMBOLS
// output all remaining symbols in hash list
// note: type should be IMAGE_SYM_TYPE_NULL for any EXTDEF or LEXTDEF only symbols
// free dynamic storage
VOID flush_syms(void) { WORD csymAux; WORD SymbolClass; WORD count; struct sym *psym; IMAGE_AUX_SYMBOL auxent;
csymAux = 0; isymDefAux = 0;
// Flush all but weak externs.
for (count = 0; count < NBUCKETS; count++) { for (psym = hashhead[count]; psym != NULL; psym = psym->next) { if ((external[psym->ext] == NULL) && (psym->type != S_WKEXT) && (psym->type != S_LZEXT)) { // Don't output type data if EXTDEF only
switch(psym->type) { case S_LEXT: case S_LPUB: SymbolClass = IMAGE_SYM_CLASS_STATIC; break;
case S_EXT: csymAux = 0; SymbolClass = IMAGE_SYM_CLASS_EXTERNAL; break;
default: SymbolClass = IMAGE_SYM_CLASS_EXTERNAL; break; }
if ((line_indx != 0) && (isymDefAux == 0) && (psym->scn == text_scn)) { csymAux = 1; }
external[psym->ext] = symbol(psym->name, psym->offset, psym->scn, SymbolClass, csymAux);
if (csymAux) { WORD iline;
isymDefAux = nsyms;
DefineLineNumSymbols(line_indx, text_scn, lines[0].offset, lines[0].number, lines[line_indx - 1].offset - lines[0].offset, lines[line_indx - 1].number);
for (iline = 1; iline < line_indx; iline++) { lines[iline].number -= lines[0].number; }
lines[0].number = 0; lines[0].offset = isymDefAux - 1;
csymAux = 0; // Reset
} } } }
// Flush weak externs.
memset(&auxent, 0, sizeof(IMAGE_AUX_SYMBOL));
for (count = 0; count < NBUCKETS; count++) { struct sym *psymNext;
for (psym = hashhead[count]; psym != NULL; psym = psymNext) { if (external[psym->ext] == NULL) { external[psym->ext] = symbol(psym->name, psym->offset, psym->scn, IMAGE_SYM_CLASS_WEAK_EXTERNAL, 1);
auxent.Sym.TagIndex = external[psym->weakDefaultExt]; auxent.Sym.Misc.TotalSize = (psym->type == S_WKEXT) ? IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY : IMAGE_WEAK_EXTERN_SEARCH_LIBRARY; aux(&auxent); }
psymNext = psym->next;
FreePv(psym); } } }
VOID AddLinenum ( IN PLINENUM_LIST PtrList, IN DWORD VirtualAddress, IN WORD Linenumber )
/*++
Routine Description:
Adds to the linenumber list.
Arguments:
Return Value:
--*/
{ PLINENUMS ptrLinenum;
// Allocate next member.
ptrLinenum = (LINENUMS *) PvAlloc(sizeof(LINENUMS));
// Set the fields of the new member.
ptrLinenum->Linenum.Type.VirtualAddress = VirtualAddress; ptrLinenum->Linenum.Linenumber = Linenumber; ptrLinenum->Next = NULL;
// If first member in list, remember first member.
if (PtrList->First == NULL) { PtrList->First = ptrLinenum; } else { // Not first member, so append to end of list.
PtrList->Last->Next = ptrLinenum; }
// Increment number of members in list.
PtrList->Count++;
// Remember last member in list.
PtrList->Last = ptrLinenum; }
VOID line(SHORT scn, DWORD paddr, WORD lnno) { SHORT i;
i = scn - 1; nlnno++; scnhdr[i].NumberOfLinenumbers++; AddLinenum(&Linenumbers[i], paddr, lnno); }
void process_linenums(void) { const struct lines *lptr = lines; const struct lines *elptr = &lines[line_indx];
while (lptr < elptr) { line(text_scn, lptr->offset, lptr->number); lptr++; } }
VOID proc_fixups(void) { struct sfix *f = fixlist; struct sfix *p = fixlist;
while (f) { // prepare the environment for fixupp()
fseek(objfile, f->offset, 0); rectyp = (SHORT)getc(objfile); if (RECTYP(rectyp) != FIXUPP && RECTYP(rectyp) != FIXUP2) { fatal("proc_fixups: not a fixup record"); } use32 = (SHORT) USE32(rectyp); reclen = (SHORT) word(); datscn = f->datscn; dattype = f->dattype; datoffset = f->datoffset; fixupp(); p = f; f = f->next; FreePv(p); }
fixlist = fixlast = NULL; }
// omf: scan through omf file, processing each record as appropriate
//
// most symbols are loaded into a hash table and not output into COFF
// symbols until the entire file has been scanned. fixup record processing
// is deferred until after all symbols have been output. Note that some
// fixup processing must happen when DebugType==Coff in order to support
// $$SYMBOLS fixup processing for process_sym needs.
VOID omf(const char *szOmf, int pass) { BOOL fReadModend;
mods = lnms = segs = grps = exts = defs = 0; rectyp = 0; use32 = 0; reclen = 0; fPrecomp = 0; dattype = 0; datscn = 0; datoffset = 0;
szCvtomfSourceName[0] = '\0'; // default to blank
omfpass = pass; fReadModend = FALSE;
// initialze core storage for external/public symbols
syminit();
// init core storage for line number entires and $$SYMBOLS fixups
lines = (struct lines *) PvAlloc(sizeof(struct lines) * ALLOCSZ);
line_indx = 0;
// zero out exts[] table for multiple object files
memset(external, 0, MAXEXT * sizeof(DWORD)); memset(extdefs, 0, MAXEXT * sizeof(DWORD)); text_scn = data_scn = bss_scn = 0; cursegindx = ncomments = 0; cmntsize = 0;
// process OMF records
rewind(objfile); while ((rectyp = (SHORT) getc(objfile)) != EOF) { use32 = (SHORT) USE32(rectyp); reclen = word();
switch (RECTYP(rectyp)) { case EXTDEF: extdef(FALSE, IMAGE_SYM_CLASS_EXTERNAL); break;
case CEXTDEF: extdef(TRUE, IMAGE_SYM_CLASS_EXTERNAL); break;
case FIXUPP: case FIXUP2: // deferr until all symbols are read
save_fixupp(ftell(objfile) - 3); fixupp(); break;
case PUBDEF: pubdef(IMAGE_SYM_CLASS_EXTERNAL); break;
case LEDATA: ledata(); break;
case LIDATA: lidata(); break;
case COMDEF: comdef(IMAGE_SYM_CLASS_EXTERNAL); break;
case LEXTDEF: extdef(FALSE, IMAGE_SYM_CLASS_STATIC); break;
case LPUBDEF: lpubdef(IMAGE_SYM_CLASS_STATIC); break;
case COMENT: coment(szOmf); break;
case SEGDEF: segdef(); break;
case LINNUM: linnum(); break;
case GRPDEF: grpdef(); break;
case THEADR: theadr(); break;
case MODEND: fReadModend = TRUE; modend(); break;
case LNAMES: lnames(0); break;
case LLNAMES: lnames((DWORD)-1); break;
case LCOMDEF: comdef(IMAGE_SYM_CLASS_STATIC); break;
case LHEADR: lheadr(); break;
case COMDAT: comdat(); break;
case NBKPAT: nbkpat(); break;
case BAKPAT: bakpat(); break;
case LINSYM: linsym(); break;
default: fatal("Unknown or bad record type %x", RECTYP(rectyp)); break; }
// skip over remaining portion of record
recskip(); chksum = byte();
if (fReadModend) { // Stop after MODEND record
break; } }
if (!fReadModend) { Fatal(szOmf, NOMODEND); }
createrlctsyms();
flush_syms();
process_linenums();
omfpass = PASS2;
proc_fixups(); }
VOID coff(void) { IMAGE_FILE_HEADER filehdr; DWORD scnptr, relptr, lnnoptr, li; WORD i, j;
flag = 0;
// file header
filehdr.Machine = IMAGE_FILE_MACHINE_I386; filehdr.NumberOfSections = nscns; filehdr.TimeDateStamp = time(NULL); filehdr.PointerToSymbolTable = sizeof(IMAGE_FILE_HEADER) + (sizeof(IMAGE_SECTION_HEADER) * nscns) + scnsize + (sizeof(IMAGE_RELOCATION) * nreloc) + (sizeof(IMAGE_LINENUMBER) * nlnno); filehdr.NumberOfSymbols = nsyms; filehdr.SizeOfOptionalHeader = 0; filehdr.Characteristics = IMAGE_FILE_32BIT_MACHINE;
fwrite(&filehdr, sizeof(IMAGE_FILE_HEADER), 1, objfile);
// section headers
scnptr = sizeof(IMAGE_FILE_HEADER) + (sizeof(IMAGE_SECTION_HEADER) * nscns); relptr = sizeof(IMAGE_FILE_HEADER) + (sizeof(IMAGE_SECTION_HEADER) * nscns) + scnsize; lnnoptr = sizeof(IMAGE_FILE_HEADER) + (sizeof(IMAGE_SECTION_HEADER) * nscns) + scnsize + (sizeof(IMAGE_RELOCATION) * nreloc);
for (i = 0; i < nscns; i++) { if ((scnhdr[i].Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA) != IMAGE_SCN_CNT_UNINITIALIZED_DATA) { scnhdr[i].PointerToRawData = scnhdr[i].SizeOfRawData ? scnptr : 0; } else { scnhdr[i].PointerToRawData = 0; } scnhdr[i].PointerToRelocations = scnhdr[i].NumberOfRelocations ? relptr : 0; scnhdr[i].PointerToLinenumbers = scnhdr[i].NumberOfLinenumbers ? lnnoptr : 0; if (isymDefAux != 0) { // Point the first function to all the linenumbers.
((PIMAGE_AUX_SYMBOL)&SymTable[isymDefAux]) ->Sym.FcnAry.Function.PointerToLinenumber = lnnoptr; isymDefAux = 0; }
fwrite(&scnhdr[i], sizeof(IMAGE_SECTION_HEADER), 1, objfile);
if ((scnhdr[i].Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA) != IMAGE_SCN_CNT_UNINITIALIZED_DATA) { scnptr += scnhdr[i].SizeOfRawData; } relptr += sizeof(IMAGE_RELOCATION) * scnhdr[i].NumberOfRelocations; lnnoptr += sizeof(IMAGE_LINENUMBER) * scnhdr[i].NumberOfLinenumbers; }
// section data
for (i = 0; i < nscns; i++) { if (scnhdr[i].SizeOfRawData && scnhdr[i].PointerToRawData) { fwrite(RawData[i], 1, (size_t)scnhdr[i].SizeOfRawData, objfile); } FreePv(RawData[i]); RawData[i] = 0; }
// relocation entries
for (i = 0; i < nscns; i++) { if (scnhdr[i].Characteristics != IMAGE_SCN_LNK_INFO) { if (scnhdr[i].NumberOfRelocations) { PRELOCS ptrReloc; PRELOCS next;
ptrReloc = Relocations[i].First; for (j = 0; j < scnhdr[i].NumberOfRelocations; j++) { fwrite(&ptrReloc->Reloc, sizeof(IMAGE_RELOCATION), 1, objfile); next = ptrReloc->Next; FreePv(ptrReloc); ptrReloc = next; }
Relocations[i].First = NULL; } } }
// line numbers
for (i = 0; i < nscns; i++) { if (scnhdr[i].Characteristics & IMAGE_SCN_CNT_CODE) { WORD temp = scnhdr[i].NumberOfLinenumbers; WORD x = 0;
if (temp) { PLINENUMS ptrLinenum; PLINENUMS next;
ptrLinenum = Linenumbers[i].First; for (j = 0; j < temp; j++) { fwrite(&ptrLinenum->Linenum, sizeof(IMAGE_LINENUMBER), 1, objfile); x++; next = ptrLinenum->Next; FreePv(ptrLinenum); ptrLinenum = next; }
Linenumbers[i].First = NULL; }
scnhdr[i].NumberOfLinenumbers = x; } }
// patch section symbol aux records with #line and #reloc entries
for (i = 0; i < nscns; i++) { if (scnauxidx[i] && SymTable) { PIMAGE_AUX_SYMBOL auxSym;
auxSym = (PIMAGE_AUX_SYMBOL)(SymTable + scnauxidx[i]); auxSym->Section.NumberOfRelocations = scnhdr[i].NumberOfRelocations; auxSym->Section.NumberOfLinenumbers = scnhdr[i].NumberOfLinenumbers; } scnauxidx[i] = 0; }
// symbol table
fseek(objfile, filehdr.PointerToSymbolTable, 0);
if (nsyms) { for (li = 0; li < nsyms; li++) { fwrite((PVOID) (SymTable+li), sizeof(IMAGE_SYMBOL), 1, objfile); }
// always write the count, even if 0
fwrite(&strsize, sizeof(DWORD), 1, objfile);
if (strsize) { strsize -= sizeof(DWORD); fwrite(CvtomfStringTable+sizeof(DWORD), 1, (size_t)strsize, objfile); FreePv(CvtomfStringTable); } }
// clean up
FreePv((void *) SymTable); SymTable = 0;
scnsize = strsize = nreloc = nlnno = nsyms = 0; nscns = 0; }
BOOL FConvertOmfToCoff(const char *szOmf, const char *szCoff) { __try { if (setjmp(mark) != 0) { return(FALSE); }
objfile = fopen(szOmf, "rb");
if (objfile == NULL) { Fatal(NULL, CANTOPENFILE, szOmf); }
omf(szOmf, PASS1);
fclose(objfile);
// Generate COFF file
objfile = fopen(szCoff, "wb");
if (objfile == 0) { Fatal(NULL, CANTOPENFILE, szCoff); }
coff();
fclose(objfile); } __except (fExceptionsOff ? EXCEPTION_CONTINUE_SEARCH : EXCEPTION_EXECUTE_HANDLER) { return(FALSE); }
return(TRUE); }
|