mirror of https://github.com/lianthony/NT4.0
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
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);
|
|
}
|