Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2397 lines
57 KiB

/***********************************************************************
* 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);
}