home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
World of Shareware - Software Farm 2
/
wosw_2.zip
/
wosw_2
/
CPROG
/
CGAZV5N3.ZIP
/
OX.C
< prev
next >
Wrap
C/C++ Source or Header
|
1991-02-25
|
57KB
|
1,525 lines
/******** Listing 3 ************************* OX.C ********
* ox.c -- Object Explorer,
* Author: Thomas E. Siering, 1991. See Lisitng 1 for
* copyright notice.
* Compiler: Microsoft C 6.0, Turbo C++ 1.0
*
* Compile time switches: none
*
* Links with: svc.c and apps.c
**************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <io.h>
#include "ox.h"
#define NEAR 0x62
#define FAR 0x61
#define THREADMAX 4
#define MAXLINELENGTH 16
extern FILE *AnalysisFH;
PRIVATE char *ObjBase;
PRIVATE FILE *ObjFH;
PRIVATE FIXUPTHREAD ThreadTable[THREADMAX * 2]; /* for Target AND Frame */
PRIVATE LNODE ListLNAMES;
PRIVATE LNODE ListSEGDEF;
PRIVATE LNODE ListGRPDEF;
PRIVATE LNODE ListEXTDEF;
PRIVATE int GetExplicitFixupp(unsigned char *RecordP);
PRIVATE int GetFixupThread(unsigned char *RecordP);
PRIVATE LNODE *GetThreadFixupMethod(unsigned int method, unsigned int d,
char *RecordP);
PRIVATE void GetFixupLocation(unsigned int loc, char *RecordP);
PRIVATE int IteratedDataBlock(unsigned char *RecordP);
PRIVATE void InstThreadTable(void);
PRIVATE void PutThread(FIXUPTHREAD NewThread);
PRIVATE FIXUPTHREAD *GetThread(unsigned char ThreadID, char ThreadType,
char *RecordP);
PRIVATE int GetFixDatField(unsigned char *RecordP);
PRIVATE char GetVarLengthIdx(char *RecordP, int *Index);
/*------------------------------------------------------------
* InstObjExp -- Instantiate the Object Explorer
*-----------------------------------------------------------*/
PUBLIC void InstObjExp(char ObjFN[], char **ws, long *ObjSize)
{
if ((ObjFH = fopen(ObjFN, "rb")) == NULL) {
fprintf(stderr, "Could Not Open File %s\n", ObjFN);
exit(-1);
}
if ((*ObjSize = filelength(fileno(ObjFH))) == -1) {
fprintf(stderr, "Error in File Size Determination\n");
exit(-1);
}
if ((ObjBase = *ws = malloc((int) *ObjSize)) == NULL) {
fprintf(stderr, "Work Space Allocation Failed. Aborting\n");
exit(-1);
}
if (fread(*ws, sizeof(char), (int) *ObjSize, ObjFH) !=
(unsigned int) *ObjSize) {
fprintf(stderr, "Read of OBJ Failed. Aborting\n");
exit(-1);
}
fclose(ObjFH);
if ((char) **ws != (char) THEADR && (char) **ws != (char) LHEADR) {
fprintf(stderr, "Invalid OBJ file. Aborting\n");
exit(-1);
}
InstList(&ListLNAMES); /* initialize symbol lists */
InstList(&ListSEGDEF);
InstList(&ListGRPDEF);
InstList(&ListEXTDEF);
InstThreadTable();
}
/*===============================================
* 1. OMF comment records:
* THEADR 0x80
* COMENT 0x88
* MODEND 0x8A
*===============================================*/
/*--------------------------------------------------------
* DoTHEADR -- Translator Header record (T-module)
* NOTE: MUST always appear as the first record in OBJ module
*--------------------------------------------------------*/
PUBLIC void DoTHEADR(unsigned char *RecordP)
{
char *ModuleName;
ModuleName = MakeASCIIZ(RecordP);
Output(Message, AnalysisFH, "Module Name:\n %s\n", ModuleName);
free(ModuleName);
}
/*--------------------------------------------------------
* DoCOMENT -- Comment record
* Within the given Comment Classes anything can be put here.
* As a result, COMENT records are popular for OMF extensions.
*-------------------------------------------------------*/
PUBLIC void DoCOMENT(unsigned char *RecordP, int RecordLength)
{
bool NoPurge, NoList;
unsigned char CommentClass;
char *Comment;
char Processor[6];
int PrintLength;
int Offset;
NoPurge = *RecordP & (char) 0x80;
NoList = *RecordP++ & (char) 0x40;
Output(Message, AnalysisFH, " No Purge : %s\n",
NoPurge ? "ON" : "OFF");
Output(Message, AnalysisFH, " No List : %s\n",
NoList ? "ON" : "OFF");
CommentClass = *RecordP++;
RecordLength -= 2; /* past NoPurge/NoList and CommentClass */
/* Note: This string is NOT preceded by "length" byte */
Comment = malloc(RecordLength + 1);
Comment[RecordLength] = '\0';
strncpy(Comment, RecordP, RecordLength);
/* Comment Class */
Output(Message, AnalysisFH, " Comment Class : %02X\n",
CommentClass & 0x00FF);
switch(CommentClass) {
case 0x00 :
Output(Message, AnalysisFH,
" Language Translator: %s\n", Comment);
break;
case 0x01 :
Output(Message, AnalysisFH,
" Copyright : %s\n", Comment);
break;
case 0x81 : /* obsolete: 9F comment class should be used */
Output(Message, AnalysisFH,
" Library Specifier : %s\n", Comment);
break;
case 0x9C :
Output(Message, AnalysisFH,
" DOS Version : %d\n", *(int *) RecordP);
break;
case 0x9D :
if (Comment[0] == '0')
strcpy(Processor, "8086");
else {
strcpy(Processor, "80086");
Processor[2] = Comment[0];
}
Output(Message, AnalysisFH, " Target Processor : %s\n",
Processor);
Output(Message, AnalysisFH, " Memory Model : %c\n",
Comment[1]);
break;
case 0x9E : /* Sets LINK's DOSSEG */
Output(Message, AnalysisFH, " Force Segment Order: %s\n",
Comment);
break;
case 0x9F :
Output(Message, AnalysisFH, " Library Specifier : %s\n",
Comment);
break;
case 0xA0 : /* used for IMPDEF with Windows, OS/2 */
Output(Message, AnalysisFH, " MS-Reserved Field : ");
switch (*RecordP) {
case 1 :
Output(Message, AnalysisFH, "IMPDEF\n");
break;
case 2:
Output(Message, AnalysisFH, "EXPDEF\n");
break;
case 3:
Output(Message, AnalysisFH, "INCDEF\n");
break;
case 4:
Output(Message, AnalysisFH,
"Protected Memory Lib. (386)\n");
break;
default:
Output(Warning, AnalysisFH, "Unknown Comment Record\n");
break;
}
break;
case 0xA1 : /* meaning that obsolete TYPDEF/EXTDEF pairs */
/* not used but COMDEF instead */
Output(Message, AnalysisFH, " Microsoft Extension: %s\n",
Comment);
break;
case 0xA2 :
Output(Message, AnalysisFH, " Start of Link Pass 2\n");
break;
case 0xA3 :
Output(Message, AnalysisFH, " LIBMOD record\n");
break;
case 0xA4 :
Output(Message, AnalysisFH, " EXESTR record\n");
break;
case 0xA5 :
Output(Message, AnalysisFH, " QC # 1 record\n");
break;
case 0xA6 :
Output(Message, AnalysisFH, " INCERR record\n");
break;
case 0xA7 :
Output(Message, AnalysisFH, " NOPAD record\n");
break;
case 0xA8 :
Output(Message, AnalysisFH, " WKEXT record\n");
break;
default:
if (CommentClass >= 0xC0)
Output(Message, AnalysisFH, " User-Defined Comm. :\n");
else
/* This is foul play, or some future non-compliant extension */
Output(Message, AnalysisFH, " Proprietary Comm. :\n");
/* Hex dump the comment (string printing it isn't safe!) */
Offset = GetRecordRelPos(RecordP);
while (RecordLength > 0) {
PrintLength = (RecordLength > MAXLINELENGTH) ?
MAXLINELENGTH : RecordLength;
PrintObjDumpLine(RecordP, AnalysisFH, Offset, PrintLength);
RecordLength -= PrintLength;
Offset += PrintLength;
RecordP += PrintLength;
}
break;
}
free(Comment);
}
/*--------------------------------------------------------------
* DoMODEND -- Module End record
* Indicates end of module, whether it's the main routine in a
* program, and, optionally, program entry point.
* NOTE: MUST always appear as the last record in OBJ module
*-------------------------------------------------------------*/
PUBLIC void DoMODEND(unsigned char *RecordP)
{
bool IsMain;
bool HasEntryPoint;
bool IsRelocatableEP;
/* The top two bytes are relevant: byte 7 - is it main module, */
/* byte 6 - is starting address supplied */
/* The following check will fail on Quick C generated OBJ modules.
This non-standard behavior is undocumented (but harmless). */
#ifdef QUICKC_MYSTERY
if ((*RecordP & (char) 0x3E) != 0)
Output(Warning, AnalysisFH,
"Unrecognizable Module End Attribute Record\n");
#endif
IsMain = *RecordP & (char) 0x80;
HasEntryPoint = *RecordP & (char) 0x40;
IsRelocatableEP = *RecordP++ & (char) 0x01;
Output(Message, AnalysisFH, " %s / %s\n",
(IsMain) ? "Main module" : "Non-Main Module",
(HasEntryPoint) ? "Entry Point" : "No Entry Point");
if (HasEntryPoint)
Output(Message, AnalysisFH, " %s\n",
(IsRelocatableEP) ?
"Relocatable Entry Point" : "Absolute Entry Point");
if (HasEntryPoint) /* Specified starting address */
GetFixDatField(RecordP);
}
/*===============================================
* 2. Symbol lists:
* LNAMES 0x96
* EXTDEF 0x8C
* PUBDEF 0x90
*===============================================*/
/*-------------------------------------------------------------
* DoLNAMES -- Names List record
* List of names which will be referenced by subsequent SEGDEF
* and GRPDEF records in this module, using 1-based index.
* MS LINK limit is 255 logical names/module.
*-------------------------------------------------------------*/
PUBLIC void DoLNAMES(unsigned char *RecordP, int RecordLength)
{
char *LName;
while (RecordLength > 0) {
LName = MakeASCIIZ(RecordP);
Output(Message, AnalysisFH, " %s\n",
*RecordP != '\0' ? LName : "(NULLNAME)");
ListLNAMES = AddListNode(ListLNAMES, LName);
RecordLength -= ((int) *RecordP + 1);
RecordP += ((int) *RecordP + 1);
}
if (RecordLength)
Output(Error, AnalysisFH,
"LNAMES record not recognized. Terminating\n");
}
/*---------------------------------------------------------------
* DoEXTDEF -- External Name Definitions record
* List of symbolic external references (symbols defined in other
* OBJ modules). MS LINK limit is 1023 external names.
*---------------------------------------------------------------*/
PUBLIC void DoEXTDEF(unsigned char *RecordP, int RecordLength)
{
char *ExtName;
int TypeIndex;
char IndexSize;
while (RecordLength > 0) {
ExtName = MakeASCIIZ(RecordP);
ListEXTDEF = AddListNode(ListEXTDEF, ExtName); /*EXTDEF name list*/
Output(Message, AnalysisFH, "\n External Symbol : %s \n",
ExtName);
RecordLength -= ((int) *RecordP + 1);
RecordP += ((int) *RecordP + 1);
/* Type index is reference to a TYPDEF record (if > 0)
EXTDEF/TYPDEF method is mostly obsolete, except for
communal variables. It is replaced by COMDEF records. */
IndexSize = GetVarLengthIdx(RecordP, &TypeIndex);
Output(Message, AnalysisFH, " Type Index : %u\n",
TypeIndex);
RecordLength -= IndexSize;
RecordP += IndexSize;
}
if (RecordLength)
Output(Error, AnalysisFH,
"EXTDEF record not recognized. Terminating\n");
}
/*------------------------------------------------------------
* DoPUBDEF -- Public Name Definitions record
* This record contains the public names used to resolve the
* externals at link time.
*-------------------------------------------------------------*/
PUBLIC void DoPUBDEF(unsigned char *RecordP, int RecordLength)
{
char *PubName;
int GroupIndex;
int SegmentIndex;
LNODE *ListNodeP = NULL;
int TypeIndex;
char IndexSize;
/* If a group is associated with this PUBDEF record, Group Index
indexes to the appropriate GRPDEF, otherwise it's 0 */
IndexSize = GetVarLengthIdx(RecordP, &GroupIndex);
RecordP += IndexSize;
RecordLength -= IndexSize;
if (GroupIndex != 0)
ListNodeP = GetListNode(ListLNAMES, GroupIndex);
Output(Message, AnalysisFH, " Group Name Index : %u -- %s\n",
GroupIndex, ListNodeP != NULL ? ListNodeP->InfoP : "NO GROUP");
/* The Segment Index indexes to previous SEGDEF records to associate a
segment with this PUBDEF. If Segment Index = 0, Group Index = 0. */
ListNodeP = NULL;
IndexSize = GetVarLengthIdx(RecordP, &SegmentIndex);
RecordP += IndexSize;
RecordLength -= IndexSize;
if (SegmentIndex != 0)
ListNodeP = GetListNode(ListSEGDEF, SegmentIndex);
Output(Message, AnalysisFH, " Segment Name Index : %u -- %s\n",
SegmentIndex, ListNodeP != NULL ? ListNodeP->InfoP : "NO SEGMENT");
/* If both Group and Segment Index are 0, a Frame Number follows
which indexes the frame containing the Public symbols */
if (GroupIndex == 0 && SegmentIndex == 0) {
Output(Message, AnalysisFH, " Frame Number = %Xx\n",
*(int *) RecordP);
RecordP += 2;
RecordLength -= 2;
}
while (RecordLength > 0) {
/* PUBLIC's name */
PubName = MakeASCIIZ(RecordP);
Output(Message, AnalysisFH, "\n Public Name : %s \n",
PubName);
free(PubName);
RecordLength -= ((int) *RecordP + 1);
RecordP += ((int) *RecordP + 1);
/* PUBLIC's offset relative to segment, group, or frame (supra) */
Output(Message, AnalysisFH,
" Public Offset : %Xx\n", *(int *) RecordP);
RecordP += 2;
RecordLength -= 2;
/* Type Index refers to preceding TYPDEF record. 0 = no data type */
IndexSize = GetVarLengthIdx(RecordP, &TypeIndex);
RecordP += IndexSize;
RecordLength -= IndexSize;
Output(Message, AnalysisFH, " Type Index : %u\n",
TypeIndex);
}
if (RecordLength)
Output(Error, AnalysisFH,
"PUBDEF record not recognized. Terminating\n");
}
/*====================================
* 3. Memory layout info:
* SEGDEF 0x98
* GRPDEF 0x9A
* COMDEF 0xB0
* TYPDEF 0x8E
*====================================*/
/*---------------------------------------------------------
* DoSEGDEF -- Segment Definition record
* Describes a logical segment: name, length, alignment,
* combination with other logical segments.
* MS LINK limit: 255 SEGDEF records per OBJ modules
*---------------------------------------------------------*/
PUBLIC void DoSEGDEF(unsigned char *RecordP)
{
char *SegmentName;
long SegmentLength;
int SegmentIndex;
int ClassIndex;
int OverlayIndex;
char IndexSize;
struct ACBP {
unsigned Page : 1;
unsigned Big : 1;
unsigned Combine : 3;
unsigned Align : 3;
} ACBP;
ACBP = *(struct ACBP *) RecordP++;
/* Segment Alignment at runtime */
switch(ACBP.Align) {
case 0 :
Output(Message, AnalysisFH, " ABSOLUTE Segment\n");
break;
case 1 :
Output(Message, AnalysisFH, " Relocatable/Align : BYTE\n");
break;
case 2 :
Output(Message, AnalysisFH, " Relocatable/Align : WORD\n");
break;
case 3 :
Output(Message, AnalysisFH, " Relocatable/Align : PARA\n");
break;
case 4 :
Output(Message, AnalysisFH, " Relocatable/Align : PAGE\n");
break;
default:
Output(Warning, AnalysisFH,
"Unrecognizable Segment Alignment Record\n");
break;
}
/* Segment Combination that linker may perform to segments of same name.
Can either concatenate segments, or overlap them. Note: Absolute
segments (Align = 0) canNOT be combined (Combine = 0). */
switch(ACBP.Combine) {
case 0 :
Output(Message, AnalysisFH, " PRIVATE Segment\n");
break;
case 2 :
case 4 :
case 7:
Output(Message, AnalysisFH,
" Combine Type : PUBLIC/Concatenate\n");
break;
case 5 :
Output(Message, AnalysisFH,
" Combine Type : STACK/Concatenate\n");
break;
case 6 :
Output(Message, AnalysisFH,
" Combine Type : COMMON/Overlap\n");
break;
default:
Output(Warning, AnalysisFH,
"Unrecognizable Segment Combination Record\n");
break;
}
/* Big Field determines if segment size is EXACTLY 64k */
if (ACBP.Big == 1)
Output(Message, AnalysisFH, " Segment Size = 64Kb\n");
else
Output(Message, AnalysisFH, " Segment Size < 64Kb\n");
/* Page field is unused in DOS and should be 0. */
if (ACBP.Page != 0)
Output(Message, AnalysisFH,
"Unrecognized Page value in SEGDEF record\n");
/* Frame Number and Offset fields are present only for absolute segments.
Taken together, they provide the segment's starting address: */
if (ACBP.Align == 0) { /* absolute segment specific fields */
Output(Message, AnalysisFH,
" Absolute Segment : Frame Number = %Xx\n",
*(int *) RecordP);
RecordP += 2;
Output(Message, AnalysisFH,
" Absolute Segment : Segment Offset = %Xx\n",
*(unsigned char *) RecordP++);
}
/* Segment Length in bytes */
SegmentLength = (long) *(unsigned int *) RecordP;
/* if Big field was 1 (i.e., 64K segment),
Segment Length field is set to 0 */
if (ACBP.Big == 1 && SegmentLength == 0)
SegmentLength = 65536; /* 64k */
Output(Message, AnalysisFH, " Segment Length : %ld\n",
SegmentLength);
RecordP += 2;
/* The Segment Name Index, Class Name Index, and Overlay Name Index
provide the names from previous LNAMES records. */
IndexSize = GetVarLengthIdx(RecordP, &SegmentIndex);
SegmentName = GetListNode(ListLNAMES, SegmentIndex)->InfoP;
Output(Message, AnalysisFH, " Segment Name Index : %d -- %s\n",
SegmentIndex, SegmentName);
ListSEGDEF = AddListNode(ListSEGDEF, SegmentName);
RecordP += IndexSize;
/* The Class Name Index gives the segment's class(e.g. CODE, or STACK),
so that linker can combine segments of equal class name. */
IndexSize = GetVarLengthIdx(RecordP, &ClassIndex);
Output(Message, AnalysisFH, " Class Name Index : %d -- %s\n",
ClassIndex, GetListNode(ListLNAMES, ClassIndex)->InfoP);
RecordP += IndexSize;
/* The Overlay Name Index identifies a segment with a runtime overlay.
MS LINK ignores it, using command-line parameters to LINK instead. */
IndexSize = GetVarLengthIdx(RecordP, &OverlayIndex);
Output(Message, AnalysisFH, " Overlay Name Index : %d -- %s\n",
OverlayIndex, GetListNode(ListLNAMES, OverlayIndex)->InfoP);
}
/*---------------------------------------------------------
* DoGRPDEF -- Group Definition record
* Defines a group of segments to reside together within
* 64K frame at runtime.
* MS LINK limit: 21 GRPDEF records per OBJ module.
*--------------------------------------------------------*/
PUBLIC void DoGRPDEF(unsigned char *RecordP, int RecordLength)
{
char *GroupName;
int GroupIndex;
int SegmentIndex;
char IndexSize;
/* Get the Group Name via Group Name Index */
IndexSize = GetVarLengthIdx(RecordP, &GroupIndex);
GroupName = GetListNode(ListLNAMES, GroupIndex)->InfoP;
Output(Message, AnalysisFH, " Group Name Index : %d -- %s\n",
GroupIndex, GroupName);
/* Group Name may be later referenced in FIXUPP */
ListGRPDEF = AddListNode(ListGRPDEF, GroupName);
RecordLength -= IndexSize;
RecordP += IndexSize;
/* Remainder of record is made up of Group Component Descriptors: */
while (RecordLength > 0) {
/* First byte is always FF, indicating following
of Segment Name Index */
++RecordP;
RecordLength--;
/* Segment Name Index relative to previous SEGDEF record */
IndexSize = GetVarLengthIdx(RecordP, &SegmentIndex);
Output(Message, AnalysisFH,
" Segment Name Index : %d -- %s\n",
SegmentIndex, GetListNode(ListSEGDEF,
SegmentIndex)->InfoP);
RecordP += IndexSize;
RecordLength -= IndexSize;
}
if (RecordLength)
Output(Error, AnalysisFH,
"GRPDEF record not recognized. Terminating\n");
}
/*-------------------------------------------------------------------
* DoCOMDEF -- Common Name Definitions record
* MS extension declaring a (list of) communal variable(s).
* Being an extension COMDEF records must be indicated by COMENT
* record of Comment Class A1.
*------------------------------------------------------------------*/
PUBLIC void DoCOMDEF(unsigned char *RecordP, int RecordLength)
{
char *ComName;
long CommunalSize;
int TypeIndex;
unsigned char DataSegmentType;
unsigned int NameLength;
char IndexSize;
int i;
while (RecordLength > 0) {
/* Communal Name */
ComName = MakeASCIIZ(RecordP);
ListEXTDEF = AddListNode(ListEXTDEF, ComName); /*EXTDEF name list*/
Output(Message, AnalysisFH,
"\n Communal Symbol : %s \n", ComName);
NameLength = *RecordP + 1; /* name + length byte */
RecordLength -= NameLength;
RecordP += NameLength;
/* Type Index indexes to TYPDEF, or is 0 if no associated type */
IndexSize = GetVarLengthIdx(RecordP, &TypeIndex);
Output(Message, AnalysisFH,
" Type Index : %X\n", (int) TypeIndex);
RecordLength -= IndexSize;
RecordP += IndexSize;
/* Data Segment Type: is Communal Variable NEAR or FAR ? */
DataSegmentType = *RecordP++;
--RecordLength;
if (DataSegmentType == FAR)
Output(Message, AnalysisFH,
" Default Data Segm. : NO/FAR\n");
else if (DataSegmentType == NEAR)
Output(Message, AnalysisFH,
" Default Data Segm. : YES/NEAR\n");
else
Output(Error, AnalysisFH,
"COMDEF record not recognized. Terminating\n");
/* Communal Length field: amount of memory to allocate for communal.
Depending on Data Segment Type, the following bytes are
interpreted: NEAR: variable size in bytes, FAR: number
of elements, element size.
NEAR: Variable Size field ,
FAR: Number of Elements/Element Size */
for (i = 0; i < (DataSegmentType == NEAR ? 1 : 2); i++) {
/* The size field(s) is/are determined from first byte: */
switch (*RecordP) {
/* 2 byte unsigned length field follows, i.e. < 64k */
case 0x81 :
++RecordP;
CommunalSize = (long) *(unsigned int *) RecordP;
RecordLength -= 3;
RecordP += 2;
break;
/* 3 byte unsigned length field: < 16M */
case 0x84 :
++RecordP;
CommunalSize = *(long *) RecordP & 0x00FFFFFF;
RecordLength -= 4;
RecordP += 3;
break;
/* 4 byte signed length field: < 2G */
case 0x88 :
++RecordP;
CommunalSize = *(long *) RecordP;
RecordLength -= 5;
RecordP += 4;
break;
/* char field of value < 80h is actual communal length:
< 128b */
default : /* 1 byte signed length field: < 128b */
CommunalSize = (long) *RecordP++;
--RecordLength;
break;
}
if (DataSegmentType == NEAR)
Output(Message, AnalysisFH,
" Communal Length : %ld bytes\n",
CommunalSize);
else if (i == 0)
Output(Message, AnalysisFH,
" Communal Elements : %ld bytes\n",
CommunalSize);
else
Output(Message, AnalysisFH,
" Element Size : %ld bytes\n",
CommunalSize);
}
}
if (RecordLength)
Output(Error, AnalysisFH,
"COMDEF record not recognized. Terminating\n");
}
/*------------------------------------------------------------
* DoTYPDEF -- Type Definition record
* Type information about PUBDEF or EXTDEF name
*------------------------------------------------------------*/
PUBLIC void DoTYPDEF()
{
Output(Warning, AnalysisFH, "TYPDEF not implemented\n");
}
/*===============================================
* 4. Code and data
* LEDATA 0xA0
* LIDATA 0xA2
*==============================================*/
/*-------------------------------------------------------------
* DoLEDATA -- Logical Enumerated Data record
* Contiguous binary data, executable code or program data.
* Typically, preceded by SEGDEF and followed by FIXUPP record.
* Max. length for data field is 1024 bytes.
*-------------------------------------------------------------*/
PUBLIC void DoLEDATA(unsigned char *RecordP, int RecordLength)
{
int Offset;
int PrintLength;
int SegmentIndex;
char IndexSize;
/* Segment Index field refers to SEGDEF record, indicating
segment into which to place this binary code/data. */
IndexSize = GetVarLengthIdx(RecordP, &SegmentIndex);
Output(Message, AnalysisFH, " Segment Name Index : %d -- %s\n",
SegmentIndex, GetListNode(ListSEGDEF, SegmentIndex)->InfoP);
RecordP += IndexSize;
RecordLength -= IndexSize;
/* Enumerated Data Offset: relative to Segment Index's segment base */
Output(Message, AnalysisFH, " Enum. Data Offset : %Xx\n",
*(int *) RecordP);
RecordP += 2;
RecordLength -= 2;
Output(Message, AnalysisFH, "\nEnumerated Data:\n\n");
Offset = 0; /* offset of data relative to its record */
while (RecordLength > 0) {
PrintLength = (RecordLength > MAXLINELENGTH) ?
MAXLINELENGTH : RecordLength;
PrintObjDumpLine(RecordP, AnalysisFH, Offset, PrintLength);
RecordLength -= PrintLength;
Offset += PrintLength;
RecordP += PrintLength;
}
if (RecordLength)
Output(Error, AnalysisFH,
"LEDATA record not recognized. Terminating\n");
}
/*--------------------------------------------------------------
* DoLIDATA -- Logical Iterated Data record
* Binary code/data represented in repeating patterns (iterations).
* Typically, preceded by SEGDEF and followed by FIXUPP record.
* Max. size of iterated data block field is 512 bytes.
*--------------------------------------------------------------*/
PUBLIC void DoLIDATA(unsigned char *RecordP, int RecordLength)
{
int BytesDone;
int SegmentIndex;
char IndexSize;
/* Segment Index field refers to SEGDEF record, indicating segment
** into which to place this binary code/data. */
IndexSize = GetVarLengthIdx(RecordP, &SegmentIndex);
Output(Message, AnalysisFH, " Segment Name Index : %d -- %s\n",
SegmentIndex, GetListNode(ListSEGDEF, SegmentIndex)->InfoP);
RecordP += IndexSize;
RecordLength -= IndexSize;
/* Iterated Data Offset: relative to Segment Index's segment base */
Output(Message, AnalysisFH, " Iter. Data Offset : %Xx\n",
*(int *) RecordP);
RecordP += 2;
RecordLength -= 2;
while (RecordLength > 0) {
/* Iterated Data Blocks are defined recursively */
BytesDone = IteratedDataBlock(RecordP);
RecordLength -= BytesDone;
RecordP += BytesDone;
}
if (RecordLength)
Output(Error, AnalysisFH,
"LIDATA record not recognized. Terminating\n");
}
/*-----------------------------------------------------------------
* IteratedDataBlock -- Analyzes one Logical Iterated Data record
* This is separated out because of its recursive nature.
*----------------------------------------------------------------*/
PRIVATE int IteratedDataBlock(unsigned char *RecordP)
{
int RepeatCount;
int BlockCount;
int BytesDone;
int Offset;
int DataBlockLength;
int PrintLength;
int RecordLength;
/* Repeat Count is number of times to repeat Content field */
RepeatCount = *(int *) RecordP;
Output(Message, AnalysisFH, "\n Repeat Count : %d\n",
RepeatCount);
RecordP += 2;
/* Block Count is number of iterated data blocks in Content field.
** If 0, Content field contains data only. */
BlockCount = *(int *) RecordP;
Output(Message, AnalysisFH, " Block Count : %d\n", BlockCount);
RecordP += 2;
/* So far: Block Count and Repeat Count words */
BytesDone = 4;
/* Content field: if Block Count != 0, nested iterated Data Blocks */
if (BlockCount > 0) {
FOREVER {
RecordLength = IteratedDataBlock(RecordP);
RecordP += RecordLength;
BytesDone += RecordLength;
if (--BlockCount == 0)
return (BytesDone);
}
}
/* With zero Block Count, this is data: length byte, then data bytes */
DataBlockLength = *(char *) RecordP++;
Output(Message, AnalysisFH, " Data Block Length : %d\n",
DataBlockLength);
/* We've traversed: Data and its Length byte */
BytesDone += DataBlockLength + 1;
/* Print the raw data */
Offset = 0;
while (DataBlockLength > 0) {
PrintLength = (DataBlockLength > MAXLINELENGTH) ?
MAXLINELENGTH : DataBlockLength;
PrintObjDumpLine(RecordP, AnalysisFH, Offset, PrintLength);
DataBlockLength -= PrintLength;
Offset += PrintLength;
RecordP += PrintLength;
}
return (BytesDone);
}
/*===============================================
* 5. Address binding/relocation:
* FIXUPP 0x9C
*==============================================*/
/*----------------------------------------------------------------
* DoFIXUPP -- Relocation Fixup records: Used to resolve addresses
* whose values cannot be determined prior to link time.
* LOCATION: address in OBJ module to be fixed up
* TARGET: address to which fixup refers (to be computed)
* FRAME: relative to which the address is computed
*----------------------------------------------------------------*/
PUBLIC void DoFIXUPP(unsigned char *RecordP, int RecordLength)
{
bool IsFixup;
int FixupLength;
while (RecordLength > 0) {
/* High bit determines difference between Thread field
and Fixup field */
IsFixup = (bool) (*(char *) RecordP & 0x80);
if (IsFixup)
FixupLength = GetExplicitFixupp(RecordP);
else
FixupLength = GetFixupThread(RecordP);
RecordP += FixupLength;
RecordLength -= FixupLength;
}
if (RecordLength)
Output(Error, AnalysisFH,
"FIXUPP record not recognized. Terminating\n");
}
/*-----------------------------------------------------------
* GetFixupThread -- Thread FIXUPP records
* Provides common info for reference by succeeding
* explicit fixup or thread fields in same or subsequent
* FIXUPP records.
*-----------------------------------------------------------*/
PRIVATE int GetFixupThread(unsigned char *RecordP)
{
struct ThrData {
unsigned ThreadNumber : 2;
unsigned Method : 3;
unsigned NotUsed : 1;
unsigned D : 1;
unsigned FixupType : 1; /* 0 = Thread, 1 = Explicit FIXUPP */
} ThreadData;
FIXUPTHREAD Thread;
LNODE *ThreadName;
int RecLength = 1; /* min. record length in bytes */
int IndexSize;
Output(Message, AnalysisFH, "\n%04X -- FIXUPP Thread:\n",
GetRecordRelPos(RecordP));
/* Interpret the thread record */
ThreadData = *(struct ThrData *) RecordP++;
/* Thread will be known by an index 0-3 (for each, Frame and Target) */
Thread.ID = (char) ThreadData.ThreadNumber;
/* D = 0 : Target Thread, identifies the fixup target */
/* D = 1 : Frame Thread, provides info about 64k frame */
Thread.Type = (char) (ThreadData.D == 0 ? 'T' : 'F');
/* Methods: T0 - T7 (for D = 0), and F0 - F5 (for D = 1) */
Thread.Method = (char) ThreadData.Method;
/* Index Field appears always, except for frame threads
using methods F3/4/5 */
if (!(Thread.Type == 'F' && Thread.Method > 2))
IndexSize = GetVarLengthIdx(RecordP, &Thread.ListIndex);
else
Thread.ListIndex = -1; /* none */
Output(Message, AnalysisFH, "\n %s Thread # : %d\n",
Thread.Type == 'F' ? "Frame" : "Target",
(int) Thread.ID);
/* The Method field (combined with D) gives linker method
to identify T/F. DefList is applicable xxxDEF list to r
efer to via Index */
Thread.DefList = GetThreadFixupMethod((int) ThreadData.Method,
(int) ThreadData.D, RecordP - 1);
if (Thread.ListIndex > 0) {
ThreadName = GetListNode(*(Thread.DefList),
Thread.ListIndex)->InfoP;
Output(Message, AnalysisFH, " %s Thread Index: %u -- %s\n",
Thread.Type == 'F' ? "Frame" : "Target",
Thread.ListIndex, ThreadName);
RecLength += IndexSize; /* Record Length in bytes */
}
PutThread(Thread);
return (RecLength); /* Record Length in bytes */
}
/*------------------------------------------------------------------
* GetThreadFixupMethod -- Interpret Method / D fields of Thread FIXUPP rec
*------------------------------------------------------------------*/
PRIVATE LNODE *GetThreadFixupMethod(unsigned int Method, unsigned int D,
char *RecordP)
{
if (D) { /* Frame Thread */
Output(Message, AnalysisFH, " Frame ID Method : F%u -- ",
Method);
switch(Method) {
case 0 :
Output(Message, AnalysisFH,
"SEGDEF index: Highest #ered Frame cont. segm\n");
return (&ListSEGDEF);
case 1 :
Output(Message, AnalysisFH, "GRPDEF index\n");
return (&ListGRPDEF);
case 2 :
Output(Message, AnalysisFH, "EXTDEF index\n");
return (&ListEXTDEF);
case 3 :
Output(Message, AnalysisFH, "Frame Number\n");
return (NULL);
case 4 :
Output(Message, AnalysisFH,
"Highest #ered Frame cont. segm of fixup loc\n");
return (NULL);
case 5 :
Output(Message, AnalysisFH, "Same as target frame\n");
return (NULL);
default:
Output(Warning, AnalysisFH,
"\n%04X -- FIXUPP: Bad Frame Thread Method Value\n",
GetRecordRelPos(RecordP));
return (NULL);
}
}
else { /* Target Thread */
Output(Message, AnalysisFH, " Target ID Method : T%u -- ",
Method);
switch (Method) {
case 0 :
Output(Message, AnalysisFH, "SEGDEF index and offset\n");
return (&ListSEGDEF);
case 1 :
Output(Message, AnalysisFH, "GRPDEF index and offset\n");
return (&ListGRPDEF);
case 2 :
Output(Message, AnalysisFH, "EXTDEF index and offset\n");
return (&ListEXTDEF);
case 3 :
Output(Message, AnalysisFH, "Frame Number and offset\n");
return (NULL);
case 4 :
Output(Message, AnalysisFH, "SEGDEF index only.");
Output(Message, AnalysisFH, "Target at Segment beginning\n");
return (&ListSEGDEF);
case 5 :
Output(Message, AnalysisFH, "GRPDEF index only\n");
return (&ListGRPDEF);
case 6 :
Output(Message, AnalysisFH, "EXTDEF index only\n");
return (&ListEXTDEF);
case 7 :
Output(Message, AnalysisFH, "Frame Number only\n");
return (NULL);
default:
Output(Warning, AnalysisFH,
"\n%04X -- FIXUPP: Bad Target Thread Method Value\n",
GetRecordRelPos(RecordP));
return (NULL);
}
}
}
/*---------------------------------------------------------------
* GetThread -- Retrieve a thread from the thread data table
* If no valid thread, return NULL.
*--------------------------------------------------------------*/
PRIVATE FIXUPTHREAD *GetThread(unsigned char ThreadID, char ThreadType,
char *RecordP)
{
int Idx;
if (ThreadID <= 3) {
/* In table, we store Frame threads first then Target threads */
Idx = (int) (ThreadType == 'F' ? ThreadID :
ThreadID + (char) THREADMAX);
if (ThreadTable[Idx].ListIndex != -1)
return (&ThreadTable[Idx]);
}
/* If we get here, we're in trouble! */
Output(Warning, AnalysisFH,
"\n%04X -- FIXUPP: Bad Thread Reference\n",
GetRecordRelPos(RecordP));
return (NULL);
}
/*--------------------------------------------------------
* PutThread -- Save a thread in the thread data table
*-------------------------------------------------------*/
PRIVATE void PutThread(FIXUPTHREAD NewThread)
{
int Idx;
/* In table, we store Frame threads first then Target threads */
Idx = (int) (NewThread.Type == 'F' ? NewThread.ID :
NewThread.ID + (char) THREADMAX);
ThreadTable[Idx] = NewThread;
}
/*-------------------------------------------------------
* InstThreadTable -- Instantiate the Thread Table
*------------------------------------------------------*/
PRIVATE void InstThreadTable()
{
int i;
for (i = 0; i < THREADMAX * 2; i++)
ThreadTable[i].ID = -1;
}
/*-------------------------------------------------------
* GetExplicitFixupp -- Explicit FIXUPP records
*-------------------------------------------------------*/
PRIVATE int GetExplicitFixupp(unsigned char *RecordP)
{
int RecordLength;
union {
struct {
unsigned DataRecOffset : 10; /* LOCATION position in LxDATA rec */
unsigned Loc : 3; /* location type to be fixed up */
unsigned S : 1; /* unused, should be 0 */
unsigned Mode : 1; /* segment-relative vs self-relative */
unsigned FixupType : 1; /* explicit or thread */
} Word;
char Byte[2];
} Locat;
Output(Message, AnalysisFH, "\n%04X -- Explicit FIXUPP :\n",
GetRecordRelPos(RecordP));
Locat.Byte[1] = *RecordP++; /* read bit fields */
Locat.Byte[0] = *RecordP++; /* in reverse order */
/* Mode bit */
Output(Message, AnalysisFH, "\n Fixup Relativity : %s \n",
Locat.Word.Mode ? "SEGMENT" : "SELF");
GetFixupLocation((int) Locat.Word.Loc, RecordP - 2); /* Loc field */
/* Data Rec Offset in previous LxDATA */
Output(Message, AnalysisFH, " Location Offset : %Xx\n",
(int) Locat.Word.DataRecOffset);
RecordLength = GetFixDatField(RecordP);
return (RecordLength);
}
/*----------------------------------------------------------
* GetFixupLocation -- Determine location to be fixed up.
* (Explicit FIXUPP record)
*----------------------------------------------------------*/
PRIVATE void GetFixupLocation(unsigned int Loc, char *RecordP)
{
Output(Message, AnalysisFH, " Fixup Location : ");
switch (Loc) {
case 0 :
Output(Message, AnalysisFH, "Low-Order Byte\n");
break;
case 5 : /* Loc = 5 is treated as Loc - 1 by linker */
Output(Message, AnalysisFH, "Loader-resolved Offset/");
case 1 :
Output(Message, AnalysisFH, "Ptr-Offset (16-bit)\n");
break;
case 2 :
Output(Message, AnalysisFH, "Ptr-Segment (16-bit)\n");
break;
case 3 :
Output(Message, AnalysisFH, "FAR Pointer (32-bit)\n");
break;
case 4 :
Output(Message, AnalysisFH, "High-Order Byte\n");
break;
default:
Output(Warning, AnalysisFH,
"\n%04X -- FIXUPP: Bad Loc field %04X\n",
GetRecordRelPos(RecordP), Loc);
break;
}
}
/*-----------------------------------------------------------------
* GetFixDatField -- Interpret the FixDat field in explicit FIXUPP
* record and its equivalent, the EndDat in MODEND.
*----------------------------------------------------------------*/
PRIVATE int GetFixDatField(unsigned char *RecordP)
{
struct fd {
unsigned Targt : 2; /* data record offset */
unsigned P : 1;
unsigned T : 1;
unsigned Frame : 3;
unsigned F : 1;
} FixDat;
LNODE *FrameList;
LNODE *TargetList;
FIXUPTHREAD *ThreadP;
int FrameMethod;
int TargetMethod;
int FrameDatum;
int TargetDatum;
int DatumSize;
int RecordLength;
/* F/Frame fields */
FixDat = *(struct fd *) RecordP++;
if (FixDat.F) { /* F = 1 => frame in previous thread */
Output(Message, AnalysisFH, " Frame Reference : THREAD\n");
ThreadP = GetThread((char) FixDat.Frame, 'F', RecordP - 1);
Output(Message, AnalysisFH,
" Frame ID Method : Thread # %u -- %s\n",
(int) FixDat.Frame,
GetListNode(*ThreadP->DefList, ThreadP->ListIndex)->InfoP);
}
else { /* F = 0 => explicit frame */
Output(Message, AnalysisFH, " Frame Reference : EXPLICIT\n");
FrameMethod = (int) FixDat.Frame;
FrameList = GetThreadFixupMethod(FrameMethod, 1, RecordP - 1);
}
/* T field */
if (FixDat.T) /* T = 1 => target in prev. thread */
Output(Message, AnalysisFH, " Target Reference : THREAD\n");
else /* T = 0 => target explicit in FUP */
Output(Message, AnalysisFH, " Target Reference : EXPLICIT\n");
/* P field */
if (FixDat.P) /* P = 1 => target spec 2ndary way */
Output(Message, AnalysisFH,
" Target Specific. : SECONDARY -- IDX / NO OFFSET\n");
else
Output(Message, AnalysisFH,
" Target Specific. : PRIMARY -- IDX / OFFSET\n");
/* Target field */
if (FixDat.T) { /* T = 1 => thread target spec */
ThreadP = GetThread((char) FixDat.Targt, 'T', RecordP - 1);
Output(Message, AnalysisFH,
" Target ID Method : Thread # %u -- %s\n",
(int) FixDat.Targt,
GetListNode(*ThreadP->DefList, ThreadP->ListIndex)->InfoP);
}
else { /* T = 0 => explicit target spec */
/* Target = method of identifying target */
TargetMethod = (int) ((FixDat.P) ? (FixDat.Targt + 4) : FixDat.Targt);
TargetList = GetThreadFixupMethod(TargetMethod, 0, RecordP - 1);
}
RecordLength = 3;
/* Frame Datum */
if (FixDat.F == 0 && FrameMethod < 4) {
DatumSize = GetVarLengthIdx(RecordP, &FrameDatum);
Output(Message, AnalysisFH,
" Frame Datum : %d -- %s\n",
FrameDatum, (FrameList != NULL) ?
GetListNode(*FrameList, FrameDatum)->InfoP : " ");
RecordP += DatumSize;
RecordLength += DatumSize;
}
/* Target Datum */
if (FixDat.T == 0) {
DatumSize = GetVarLengthIdx(RecordP, &TargetDatum);
Output(Message, AnalysisFH,
" Target Datum : %d -- %s\n",
TargetDatum, (TargetList != NULL) ?
GetListNode(*TargetList, TargetDatum)->InfoP : " ");
RecordP += DatumSize;
RecordLength += DatumSize;
}
/* Target Displacement */
if (FixDat.P == 0) {
Output(Message, AnalysisFH, " Target Displacement: %Xx\n",
*(int *) RecordP);
RecordP += 2;
RecordLength += 2;
}
return (RecordLength);
}
/*===========================
* 6. Debugging info:
* LINNUM 0x94
*==========================*/
/*----------------------------------------------------
* DoLINNUM -- Line Numbers record: relates source code line
* numbers to OBJ code addresses.
*---------------------------------------------------*/
PUBLIC void DoLINNUM(unsigned char *RecordP, int RecordLength)
{
int GroupIndex;
int SegmentIndex;
char IndexSize;
LNODE *ListNodeP;
int LineNumber;
unsigned int LineNumberOffset;
/* The Line Number Base (Group Index/Segment Index) describes the
segment to which the line number refers.
Group containing this code (always 0 for MS translators) */
if ((GroupIndex = (int) *RecordP++) != 0) {
ListNodeP = GetListNode(ListLNAMES, GroupIndex);
Output(Message, AnalysisFH, " Group Name Index : %u -- %s\n",
GroupIndex, (ListNodeP != NULL) ? ListNodeP->InfoP : " ");
}
else
Output(Message, AnalysisFH,
" Group Name Index : %u -- NO GROUP\n", GroupIndex);
RecordLength--;
/* Segment Index refers to a previous SEGDEF record. */
IndexSize = GetVarLengthIdx(RecordP, &SegmentIndex);
RecordP += IndexSize;
RecordLength -= IndexSize;
if (SegmentIndex != 0) {
ListNodeP = GetListNode(ListSEGDEF, SegmentIndex);
Output(Message, AnalysisFH, " Segment Name Index : %u -- %s\n",
SegmentIndex, (ListNodeP != NULL) ? ListNodeP->InfoP : " ");
}
else
Output(Message, AnalysisFH,
" Segment Name Index : %u -- NO SEGMENT\n",
SegmentIndex);
while (RecordLength > 0) {
/* Line Number: source code line number (0 <= n <= 32,767) */
LineNumber = *(int *) RecordP;
Output(Message, AnalysisFH, " Line Number : %d\n",
LineNumber);
RecordP += 2;
/* Line Number Offset: offset into code (in segment specified
by Line Number Base) to which line number refers */
LineNumberOffset = *(unsigned int *) RecordP;
Output(Message, AnalysisFH, " Line # Offset : %Xx\n\n",
LineNumberOffset);
RecordP += 2;
RecordLength -= 4;
}
if (RecordLength)
Output(Error, AnalysisFH,
"LINNUM record not recognized. Terminating\n");
}
/*================================
* 7. Obsolete record types
* BLKDEF 0x7A
* BLKEND 0x7C
* LHEADR 0x82
*===============================*/
/*----------------------------------------
* DoBLKDEF -- Block Definition record
*----------------------------------------*/
PUBLIC void DoBLKDEF()
{
Output(Warning, AnalysisFH, "BLKDEF not implemented\n");
}
/*----------------------------------------
* DoBLKEND -- Block End Record
*----------------------------------------*/
PUBLIC void DoBLKEND()
{
Output(Message, AnalysisFH, "\nBLOCK END\n");
}
/*----------------------------------------
* DoLHEADR -- Translator Header Record (L-module)
* NOTE: MUST always appear as the first record in OBJ module
*---------------------------------------*/
PUBLIC void DoLHEADR(unsigned char *RecordP)
{
char *ModuleName;
ModuleName = MakeASCIIZ(RecordP);
Output(Message, AnalysisFH, "Module Name:\n %s\n", ModuleName);
free(ModuleName);
}
/*===============================================
* 8. Microsoft extensions
* BAKPAT 0xB2 (0xB3, for 32-bit offsets)
* LEXTDEF 0xB4
* LPUBDEF 0xB6 (0xB7, for 32-bit offsets)
* LCOMDEF 0xB8
*===============================================*/
/*-------------------------------------------------------
** DoBAKPAT -- Back Patch record: Supplementary to FIXUPP records,
* BAKPAT handles back patches to locations that a regular fix-up
* record cannot easily deal with, e.g. forward references in
* one-pass compilers. This record is specific to Quick C.
*-------------------------------------------------------*/
PUBLIC void DoBAKPAT(unsigned char *RecordP, int RecordLength)
{
int SegmentIndex;
int IndexSize;
LNODE *ListNodeP;
char LocTyp;
unsigned int Offset;
int PatchValue;
/* Segment Index refers to a previous SEGDEF record. */
IndexSize = GetVarLengthIdx(RecordP, &SegmentIndex);
RecordP += IndexSize;
RecordLength -= IndexSize;
ListNodeP = GetListNode(ListSEGDEF, SegmentIndex);
Output(Message, AnalysisFH, " Segment Name Index : %u -- %s\n",
SegmentIndex, (ListNodeP != NULL) ? ListNodeP->InfoP : " ");
/* LocTyp indicates type of location to patch: 0 -> low-byte,
** 1 -> word offset, 32 -> double-word offset */
LocTyp = *RecordP++;
RecordLength--;
Output(Message, AnalysisFH, " Location Type : %d\n",
LocTyp);
/* The remainder of the record is a repeatable pair of Offset into
segment to patch, and value to add to patched Location */
while (RecordLength > 0) {
Offset = *(unsigned int *) RecordP;
Output(Message, AnalysisFH, " Offset : %04Xx\n",
Offset);
RecordP += 2;
PatchValue = *(int *) RecordP;
Output(Message, AnalysisFH, " Patch Value : %04Xx\n\n",
PatchValue);
RecordP += 2;
RecordLength -= 4;
}
if (RecordLength)
Output(Error, AnalysisFH,
"BAKPAT record not recognized. Terminating\n");
}
#define OTRANGE 32
#define LOREC 0x7A
#define HIREC 0xB8
PRIVATE char ObjTypes[OTRANGE][OMFNAMELENGTH] = {
{ "BLKDEF" }, /* 0x7A */
{ "BLKEND" }, /* 0x7C */
{ "" }, /* 0x7E */
{ "THEADR" }, /* 0x80 */
{ "" }, /* 0x82 */
{ "" }, /* 0x84 */
{ "" }, /* 0x86 */
{ "COMENT" }, /* 0x88 */
{ "MODEND" }, /* 0x8A */
{ "EXTDEF" }, /* 0x8C */
{ "TYPDEF" }, /* 0x8E */
{ "PUBDEF" }, /* 0x90 */
{ "" }, /* 0x92 */
{ "LINNUM" }, /* 0x94 */
{ "LNAMES" }, /* 0x96 */
{ "SEGDEF" }, /* 0x98 */
{ "GRPDEF" }, /* 0x9A */
{ "FIXUPP" }, /* 0x9C */
{ "" }, /* 0x9E */
{ "LEDATA" }, /* 0xA0 */
{ "LIDATA" }, /* 0xA2 */
{ "" }, /* 0xA4 */
{ "" }, /* 0xA6 */
{ "" }, /* 0xA8 */
{ "" }, /* 0xAA */
{ "" }, /* 0xAC */
{ "" }, /* 0xAE */
{ "COMDEF" }, /* 0xB0 */
{ "BAKPAT" }, /* 0xB2 */
{ "LEXTDEF" }, /* 0xB4 */
{ "LPUBDEF" }, /* 0xB6 */
{ "LCOMDEF" } /* 0xB8 */
};
/*---------------------------------------------------------------------
* GetObjRecordName -- Supply an OBJ record type number, receive the
* record-type name. NOTE: this table has been tailored to a subset
* of Intel records plus extensions as used by Microsoft.
*--------------------------------------------------------------------*/
PUBLIC RC GetObjRecordName(unsigned char ObjRecType, char ObjRecName[])
{
if (ObjRecType < LOREC || ObjRecType > HIREC) {
ObjRecName[0] = '\0';
return (!OK);
}
strcpy(ObjRecName, ObjTypes[(ObjRecType - LOREC) / 2]);
if (ObjRecName[0] == '\0')
return (!OK);
return (OK);
}
/*-------------------------------------------------------------------
* GetRecordRelPos -- Get an OBJ record's relative position in the
* OBJ module. Note : The return type is unsigned int, assuming a
* a maximum OBJ module size of 64K.
*------------------------------------------------------------------*/
PUBLIC unsigned int GetRecordRelPos(char *CurrentPosition)
{
return (CurrentPosition - ObjBase);
}
/*-------------------------------------------------------------------
* GetVarLengthIdx -- Indexes are variable length: 0-7Fh is fit into
* one byte; 80-7FFF (the max index), is fit into two bytes.
* A two byte field is indicated by the high bit being set,
* and is non-INTEL byte order.
* Example: 8283 equals 283h.
* Returns: Length of index in bytes
*-------------------------------------------------------------------*/
PRIVATE char GetVarLengthIdx(char *RecordP, int *Index)
{
#define BYTE 1
#define WORD 2
union {
char Byte[2];
int Word;
} Int;
if (*RecordP & 0x80) { /* we're dealing with TWO bytes */
/* Clear high bit, and make this index's high byte */
Int.Byte[1] = *RecordP++ & (char) 0x7F;
Int.Byte[0] = *RecordP;
*Index = Int.Word;
return (WORD);
}
else { /* simple byte 0 - 7Fh */
*Index = (int) *RecordP;
return (BYTE);
}
}