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.
5553 lines
154 KiB
5553 lines
154 KiB
/***********************************************************************
|
|
* Microsoft (R) 32-Bit Incremental Linker
|
|
*
|
|
* Copyright (C) Microsoft Corp 1992-1996. All rights reserved.
|
|
*
|
|
* File: deflib.cpp
|
|
*
|
|
* File Comments:
|
|
*
|
|
* Converts definition files into lib files.
|
|
*
|
|
***********************************************************************/
|
|
|
|
#include "link.h"
|
|
|
|
#define END_DEF_FILE 0177
|
|
|
|
#define OrdinalNumber Value
|
|
|
|
static const char szDescriptorPrefix[] = "__IMPORT_DESCRIPTOR_";
|
|
static const char szNullDescriptor[] = "__NULL_IMPORT_DESCRIPTOR";
|
|
static const char szIATPrefix[] = "__imp_";
|
|
static const char szNullThunkSuffix[] = "_NULL_THUNK_DATA";
|
|
static const char NullDescriptorSectionName[] = ".idata$3";
|
|
static const char INT_SectionName[] = ".idata$4";
|
|
static const char IAT_SectionName[] = ".idata$5";
|
|
static const char CodeSectionName[] = ".text";
|
|
static const char DataSectionName[] = ".idata$6";
|
|
static const char PpcNamePrefix[] = "..";
|
|
static const char TocName[] = ".toc";
|
|
|
|
|
|
typedef enum THKSEC
|
|
{
|
|
thksecCv, // .debug$S
|
|
thksecText, // .text
|
|
thksecCvThunk, // .debug$S
|
|
thksecPdata, // .pdata
|
|
thksecRdata, // .rdata
|
|
thksecIAT, // .idata$5
|
|
thksecINT, // .idata$4
|
|
thksecName, // .idata$6
|
|
thksecMax,
|
|
} THKSEC;
|
|
|
|
|
|
#define NAME 0 // Documented for MSVCNT 1.0
|
|
#define LIBRARY 1 // Documented for MSVCNT 1.0
|
|
#define DESCRIPTION 2 // Documented for MSVCNT 1.0
|
|
#define HEAPSIZE 3
|
|
#define STACKSIZE 4 // Documented for MSVCNT 1.0
|
|
#define PROTMODE 5
|
|
#define CODE 6 // Documented for MSVCNT 1.0
|
|
#define DATA 7 // Documented for MSVCNT 1.0
|
|
#define SEGMENTS 8 // Documented for MSVCNT 1.0
|
|
#define EXPORTS 9 // Documented for MSVCNT 1.0
|
|
#define IMPORTS 10
|
|
#define STUB 11
|
|
#define OLD 12
|
|
#define APPLOADER 13
|
|
#define EXETYPE 14
|
|
#define REALMODE 15
|
|
#define FUNCTIONS 16
|
|
#define INCLUDE 17
|
|
#define SECTIONS 18 // Documented for MSVCNT 1.0
|
|
#define OBJECTS 19 // VXD keyword
|
|
#define VERSION 20 // Documented for MSVCNT 1.0
|
|
#define FLAGS 21 // MAC keyword
|
|
#define LOADHEAP 22 // MAC keyword
|
|
#define CLIENTDATA 23 // MAC keyword
|
|
#define VXD 24 // VXD keyword
|
|
#define BADKEYWORD (WORD) -2 // keyword special value
|
|
|
|
static const char * const DefinitionKeywords[] = {
|
|
"NAME",
|
|
"LIBRARY",
|
|
"DESCRIPTION",
|
|
"HEAPSIZE",
|
|
"STACKSIZE",
|
|
"PROTMODE",
|
|
"CODE",
|
|
"DATA",
|
|
"SEGMENTS",
|
|
"EXPORTS",
|
|
"IMPORTS",
|
|
"STUB",
|
|
"OLD",
|
|
"APPLOADER",
|
|
"EXETYPE",
|
|
"REALMODE",
|
|
"FUNCTIONS",
|
|
"INCLUDE",
|
|
"SECTIONS",
|
|
"OBJECTS",
|
|
"VERSION",
|
|
"FLAGS",
|
|
"LOADHEAP",
|
|
"CLIENTDATA",
|
|
"VXD",
|
|
NULL
|
|
};
|
|
|
|
#define EXECUTEONLY 0
|
|
#define EXECUTEREAD 1
|
|
#define READONLY 2
|
|
#define READWRITE 3
|
|
#define SHARED 4 // Documented for MSVCNT 1.0
|
|
#define NONSHARED 5
|
|
#define CONFORMING 6
|
|
#define NONCONFORMING 7
|
|
#define DISCARDABLE 8
|
|
#define NONDISCARDABLE 9
|
|
#define NONE 10
|
|
#define SINGLE 11
|
|
#define MULTIPLE 12
|
|
#define IOPL 13
|
|
#define NOIOPL 14
|
|
#define PRELOAD 15
|
|
#define LOADONCALL 16
|
|
#define MOVEABLE 17
|
|
#define MOVABLE 18
|
|
#define FIXED 19
|
|
#define EXECUTE 20 // Documented for MSVCNT 1.0
|
|
#define READ 21 // Documented for MSVCNT 1.0
|
|
#define WRITE 22 // Documented for MSVCNT 1.0
|
|
#define PURE 23
|
|
#define IMPURE 24
|
|
#define RESIDENT 25 // VXD keyword
|
|
|
|
static const char * const SectionKeywords[] = {
|
|
"EXECUTEONLY",
|
|
"EXECUTEREAD",
|
|
"READONLY",
|
|
"READWRITE",
|
|
"SHARED",
|
|
"NONSHARED",
|
|
"CONFORMING",
|
|
"NONCONFORMING",
|
|
"DISCARDABLE",
|
|
"NONDISCARDABLE",
|
|
"NONE",
|
|
"SINGLE",
|
|
"MULTIPLE",
|
|
"IOPL",
|
|
"NOIOPL",
|
|
"PRELOAD",
|
|
"LOADONCALL",
|
|
"MOVEABLE",
|
|
"MOVABLE",
|
|
"FIXED",
|
|
"EXECUTE",
|
|
"READ",
|
|
"WRITE",
|
|
"PURE",
|
|
"IMPURE",
|
|
"RESIDENT",
|
|
NULL
|
|
};
|
|
|
|
#define NAMEORLIBRARY_BASE 0
|
|
#define NAMEORLIBRARY_WINDOWAPI 1
|
|
#define NAMEORLIBRARY_WINDOWCOMPAT 2
|
|
#define NAMEORLIBRARY_NOTWINDOWCOMPAT 3
|
|
#define NAMEORLIBRARY_NEWFILES 4
|
|
#define NAMEORLIBRARY_LONGNAMES 5
|
|
#define NAMEORLIBRARY_INITINSTANCE 6
|
|
#define NAMEORLIBRARY_DYNAMIC 7
|
|
|
|
static const char * const NameOrLibraryKeywords[] = {
|
|
"BASE",
|
|
"WINDOWAPI",
|
|
"WINDOWCOMPAT",
|
|
"NOTWINDOWCOMPAT",
|
|
"NEWFILES",
|
|
"LONGNAMES",
|
|
"INITINSTANCE",
|
|
"DYNAMIC",
|
|
NULL
|
|
};
|
|
|
|
|
|
static const BYTE i386EntryCode[] = {
|
|
0xFF, 0x25, // jmp dword ptr [IAT] (requires fixup)
|
|
0x00, 0x00, 0x00, 0x00
|
|
};
|
|
|
|
static const THUNK_RELOC i386EntryCodeRelocs[] = {
|
|
{ 0x02, thksymIAT, IMAGE_REL_I386_DIR32 },
|
|
};
|
|
|
|
|
|
static const BYTE R4000EntryCode[] = {
|
|
0x00, 0x00, 0x08, 0x3C, // lui $8,IAT
|
|
0x00, 0x00, 0x08, 0x8D, // lw $8,IAT($8)
|
|
0x08, 0x00, 0x00, 0x01, // jr $8
|
|
0x00, 0x00, 0x00, 0x00, // nop (delay slot)
|
|
};
|
|
|
|
static const BYTE R3000EntryCode[] = {
|
|
0x00, 0x00, 0x08, 0x3C, // lui $8,IAT
|
|
0x00, 0x00, 0x08, 0x8D, // lw $8,IAT($8)
|
|
0x00, 0x00, 0x00, 0x00, // nop (Required for R3000)
|
|
0x08, 0x00, 0x00, 0x01, // jr $8
|
|
0x00, 0x00, 0x00, 0x00, // nop (delay slot)
|
|
};
|
|
|
|
static const THUNK_RELOC MipsEntryCodeRelocs[] = {
|
|
{ 0x00, thksymIAT, IMAGE_REL_MIPS_REFHI },
|
|
{ 0x00, 0x00, IMAGE_REL_MIPS_PAIR },
|
|
{ 0x04, thksymIAT, IMAGE_REL_MIPS_REFLO },
|
|
};
|
|
|
|
|
|
static const BYTE AlphaEntryCode[] = {
|
|
0x00, 0x00, 0x7f, 0x27, // ldah t12, IAT(zero) // t12=r27
|
|
0x00, 0x00, 0x7b, 0xa3, // ldl t12, IAT(pv)
|
|
0x00, 0x00, 0xfb, 0x6b, // jmp $31, (t12)
|
|
};
|
|
|
|
static const THUNK_RELOC AlphaEntryCodeRelocs[] = {
|
|
{ 0x00, thksymIAT, IMAGE_REL_ALPHA_REFHI },
|
|
{ 0x00, 0x00, IMAGE_REL_ALPHA_PAIR },
|
|
{ 0x04, thksymIAT, IMAGE_REL_ALPHA_REFLO },
|
|
};
|
|
|
|
|
|
// UNDONE: Consider using REFHI, PAIR, REFLO fixups for PowerPC to save IAT reference
|
|
|
|
static const BYTE PpcEntryCode[] = {
|
|
0x00, 0x00, 0x62, 0x81, // lwz r.11,[toc]IAT(r.2) (requires fixup)
|
|
0x00, 0x00, 0x8b, 0x81, // lwz r.0,0(r.11)
|
|
0x04, 0x00, 0x41, 0x90, // stw r.2,glsave1(r.1)
|
|
// thunk.body:
|
|
0xa6, 0x03, 0x89, 0x7d, // mtctr r.0
|
|
0x04, 0x00, 0x4b, 0x80, // lwz r.2,4(r.11)
|
|
0x20, 0x04, 0x80, 0x4e, // bctr
|
|
};
|
|
|
|
static const THUNK_RELOC PpcEntryCodeRelocs[] = {
|
|
{ 0x00, thksymIAT, IMAGE_REL_PPC_TOCREL16 | IMAGE_REL_PPC_TOCDEFN },
|
|
};
|
|
|
|
static const DWORD PpcTocRestoreCode = 0x80410004;
|
|
// lwz r.2,glsave1(r.1)
|
|
|
|
static const BYTE PpcEntryCodeFte[] = {
|
|
0x00, 0x00, 0x00, 0x00, // BeginAddress
|
|
0x18, 0x00, 0x00, 0x00, // EndAddress
|
|
0x00, 0x00, 0x00, 0x00, // ExceptionHandler
|
|
0x03, 0x00, 0x00, 0x00, // HandlerData
|
|
0x0d, 0x00, 0x00, 0x00 // PrologEndAddress
|
|
};
|
|
|
|
static const THUNK_RELOC PpcEntryCodeFteRelocs[] = {
|
|
{ 0x00, thksymExport, IMAGE_REL_PPC_IMGLUE },
|
|
{ 0x00, thksymExport, IMAGE_REL_PPC_ADDR32 },
|
|
{ 0x04, thksymExport, IMAGE_REL_PPC_ADDR32 },
|
|
{ 0x10, thksymExport, IMAGE_REL_PPC_ADDR32 },
|
|
};
|
|
|
|
static const BYTE PpcEntryCodeDesc[] = {
|
|
0x00, 0x00, 0x00, 0x00, // Entry code address
|
|
0x00, 0x00, 0x00, 0x00, // Toc value
|
|
};
|
|
|
|
static const THUNK_RELOC PpcEntryCodeDescRelocs[] = {
|
|
{ 0x00, thksymExport, IMAGE_REL_PPC_ADDR32 },
|
|
{ 0x04, thksymToc, IMAGE_REL_PPC_ADDR32 },
|
|
};
|
|
|
|
|
|
static const BYTE m68kLargeEntryCode[] = {// Instructions (word-sized)
|
|
0x41, 0xf9, 0x00, 0x00, 0x00, 0x00, // lea __stb{FunctionName>,a0
|
|
0x20, 0x10, // move.l (a0),d0
|
|
0x67, 0x04, // beq.s *+6
|
|
0x20, 0x40, // movea.l d0,a0
|
|
0x4e, 0xd0, // jmp (a0)
|
|
0x4e, 0xf9, 0x00, 0x00, 0x00, 0x00 // jmp __SLMFuncDispatch
|
|
};
|
|
|
|
static const THUNK_RELOC m68kLargeEntryCodeRelocs[] = {
|
|
{ 0x02, 0x00, IMAGE_REL_M68K_CTOABSD32 }, // sym=data section
|
|
{ 0x10, 0x01, IMAGE_REL_M68K_CTOABSC32 }, // sym=__SLMFuncDispatch
|
|
};
|
|
|
|
|
|
static const THUNK_INFO i386ThunkInfo = {
|
|
i386EntryCode,
|
|
i386EntryCodeRelocs,
|
|
sizeof(i386EntryCode),
|
|
sizeof(i386EntryCodeRelocs) / sizeof(THUNK_RELOC),
|
|
|
|
IMAGE_REL_I386_DIR32NB,
|
|
IMAGE_REL_I386_DIR32NB,
|
|
IMAGE_REL_I386_DIR32NB,
|
|
IMAGE_REL_I386_SECREL,
|
|
IMAGE_REL_I386_SECTION
|
|
};
|
|
|
|
|
|
static const THUNK_INFO R3000ThunkInfo = {
|
|
R3000EntryCode,
|
|
MipsEntryCodeRelocs,
|
|
sizeof(R3000EntryCode),
|
|
sizeof(MipsEntryCodeRelocs) / sizeof(THUNK_RELOC),
|
|
|
|
IMAGE_REL_MIPS_REFWORDNB,
|
|
IMAGE_REL_MIPS_REFWORDNB,
|
|
IMAGE_REL_MIPS_REFWORDNB,
|
|
IMAGE_REL_MIPS_SECREL,
|
|
IMAGE_REL_MIPS_SECTION
|
|
};
|
|
|
|
|
|
static const THUNK_INFO R4000ThunkInfo = {
|
|
R4000EntryCode,
|
|
MipsEntryCodeRelocs,
|
|
sizeof(R4000EntryCode),
|
|
sizeof(MipsEntryCodeRelocs) / sizeof(THUNK_RELOC),
|
|
|
|
IMAGE_REL_MIPS_REFWORDNB,
|
|
IMAGE_REL_MIPS_REFWORDNB,
|
|
IMAGE_REL_MIPS_REFWORDNB,
|
|
IMAGE_REL_MIPS_SECREL,
|
|
IMAGE_REL_MIPS_SECTION
|
|
};
|
|
|
|
|
|
static const THUNK_INFO AlphaThunkInfo = {
|
|
AlphaEntryCode,
|
|
AlphaEntryCodeRelocs,
|
|
sizeof(AlphaEntryCode),
|
|
sizeof(AlphaEntryCodeRelocs) / sizeof(THUNK_RELOC),
|
|
|
|
IMAGE_REL_ALPHA_REFLONGNB,
|
|
IMAGE_REL_ALPHA_REFLONGNB,
|
|
IMAGE_REL_ALPHA_REFLONGNB,
|
|
IMAGE_REL_ALPHA_SECREL,
|
|
IMAGE_REL_ALPHA_SECTION
|
|
};
|
|
|
|
|
|
static const THUNK_INFO PpcThunkInfo = {
|
|
PpcEntryCode,
|
|
PpcEntryCodeRelocs,
|
|
sizeof(PpcEntryCode),
|
|
sizeof(PpcEntryCodeRelocs) / sizeof(THUNK_RELOC),
|
|
|
|
IMAGE_REL_PPC_ADDR32NB,
|
|
IMAGE_REL_PPC_ADDR32NB,
|
|
IMAGE_REL_PPC_ADDR32NB,
|
|
IMAGE_REL_PPC_SECREL,
|
|
IMAGE_REL_PPC_SECTION,
|
|
};
|
|
|
|
|
|
static const THUNK_INFO m68kLargeThunkInfo = {
|
|
m68kLargeEntryCode,
|
|
m68kLargeEntryCodeRelocs,
|
|
sizeof(m68kLargeEntryCode),
|
|
sizeof(m68kLargeEntryCodeRelocs) / sizeof(THUNK_RELOC),
|
|
|
|
IMAGE_REL_M68K_DTOABSD32,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
};
|
|
|
|
|
|
typedef struct IMPLIB_FUNCTION {
|
|
char *Name;
|
|
char *InternalName;
|
|
DWORD Ordinal;
|
|
DWORD Offset;
|
|
DWORD Flags;
|
|
struct IMPLIB_FUNCTION *Next;
|
|
} IMPLIB_FUNCTION, *PIMPLIB_FUNCTION;
|
|
|
|
typedef struct IMPLIB_LIST {
|
|
char *DllName;
|
|
DWORD Offset;
|
|
DWORD FirstIAT;
|
|
PIMPLIB_FUNCTION Function;
|
|
struct IMPLIB_LIST *Next;
|
|
} IMPLIB_LIST, *PIMPLIB_LIST;
|
|
|
|
|
|
typedef struct CVSIG
|
|
{
|
|
DWORD dwSignature;
|
|
} CVSIG;
|
|
|
|
static const CVSIG CvSig =
|
|
{
|
|
1
|
|
};
|
|
|
|
typedef struct CVOBJNAME
|
|
{
|
|
WORD wLen;
|
|
WORD wRecType;
|
|
DWORD dwPchSignature;
|
|
|
|
// Length prefixed object filename is here
|
|
} CVOBJNAME;
|
|
|
|
static CVOBJNAME CvObjName =
|
|
{
|
|
0, // Filled in at run time
|
|
0x0009, // S_OBJNAME
|
|
0
|
|
};
|
|
|
|
static const char szLinkVer[] = "Microsoft LINK " VERSION_STR;
|
|
static BYTE cchLinkVer;
|
|
|
|
typedef struct CVCOMPILE
|
|
{
|
|
WORD wLen;
|
|
WORD wRecType;
|
|
BYTE bMachine;
|
|
BYTE bLanguage;
|
|
BYTE bFlags1;
|
|
BYTE bFlags2;
|
|
|
|
// Length prefixed linker version is here
|
|
} CVCOMPILE;
|
|
|
|
static CVCOMPILE CvCompile =
|
|
{
|
|
0, // Filled in at run time
|
|
0x0001, // S_COMPILE
|
|
0, // Filled in at run time
|
|
7, // UNDONE: CV_CFL_LINK
|
|
0x00,
|
|
0x08
|
|
};
|
|
|
|
#pragma pack(push, 1) // Byte alignment is necessary for CVTHUNK
|
|
|
|
typedef struct CVTHUNK
|
|
{
|
|
WORD wLen;
|
|
WORD wRecType;
|
|
DWORD Parent;
|
|
DWORD End;
|
|
DWORD Next;
|
|
DWORD ib;
|
|
WORD sn;
|
|
WORD cb;
|
|
BYTE Ordinal;
|
|
|
|
// Length prefixed thunk name is here
|
|
} CVTHUNK;
|
|
|
|
#pragma pack(pop)
|
|
|
|
static CVTHUNK CvThunk =
|
|
{
|
|
0, // Filled in at run time
|
|
0x0206, // S_THUNK32
|
|
0,
|
|
0,
|
|
0,
|
|
0, // SECREL relocation applied
|
|
0, // SECTION relocation applied
|
|
0, // Filled in at run time
|
|
0 // THUNK_ORDINAL_NOTYPE
|
|
};
|
|
|
|
typedef struct CVEND
|
|
{
|
|
WORD wLen;
|
|
WORD wRecType;
|
|
} CVEND;
|
|
|
|
static const CVEND CvEnd =
|
|
{
|
|
sizeof(CVEND) - sizeof(WORD),
|
|
0x0006 // S_END
|
|
};
|
|
|
|
#define MAXDIRECTIVESIZE 128
|
|
|
|
static FILE *DefStream;
|
|
static char *szNullThunkName;
|
|
static char *Argument;
|
|
static size_t cchDllName;
|
|
static LONG NewLinkerMember;
|
|
static char *MemberName;
|
|
static char *szCvMemberName;
|
|
static BYTE cchCvMemberName;
|
|
static char *DescriptionString;
|
|
static BYTE *rgfOrdinalAssigned;
|
|
static WORD *rgwHint;
|
|
static BLK blkDirectives = {0};
|
|
static DWORD UserVersionNumber;
|
|
static IMAGE_IMPORT_DESCRIPTOR NullImportDescriptor;
|
|
static BOOL IsMemberNameLongName;
|
|
static char *szLibraryID;
|
|
static char szExportFilename[_MAX_PATH];
|
|
static time_t timeCur;
|
|
extern PIMAGE pimageDeflib;
|
|
|
|
const char VxDDelimiters[] = "' \t";
|
|
|
|
// 2048 max symbol len when templates are used, plus room for an
|
|
// alias/forwarder/ordinal
|
|
|
|
#define MAX_LINE_LEN _4K
|
|
|
|
static char DefLine[MAX_LINE_LEN];
|
|
|
|
char *
|
|
ReadDefinitionFile (
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Read the next line from the definition file, stripping any comments.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
The stripped line or END_DEF_FILE.
|
|
|
|
--*/
|
|
|
|
{
|
|
size_t i;
|
|
char *pch;
|
|
|
|
if (fgets(DefLine, MAX_LINE_LEN, DefStream) == NULL) {
|
|
return("\177");
|
|
}
|
|
|
|
i = strlen(DefLine) - 1;
|
|
|
|
if (DefLine[i] == '\n') {
|
|
DefLine[i] = '\0'; // Replace \n with \0.
|
|
}
|
|
|
|
if (DefLine[i-1] == '\r') {
|
|
DefLine[i-1] = '\0'; // Replace \r with \0.
|
|
}
|
|
|
|
if ((pch = _tcschr(DefLine, ';')) != NULL) {
|
|
*pch = '\0';
|
|
}
|
|
|
|
// Skip leading white space.
|
|
|
|
pch = DefLine;
|
|
while (_istspace(*pch)) {
|
|
pch++; // MBCS: we know that space is 1-byte char,
|
|
// therefore we don't need to use _tcsinc()
|
|
}
|
|
|
|
return(pch);
|
|
}
|
|
|
|
|
|
WORD
|
|
IsDefinitionKeyword (
|
|
const char *szKeyword
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Determines if szName is a definition keyword.
|
|
|
|
Arguments:
|
|
|
|
szName - Name to compare.
|
|
|
|
Return Value:
|
|
|
|
Index of definition keyword, -1 otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
WORD i;
|
|
|
|
for (i = 0; DefinitionKeywords[i] != NULL; i++) {
|
|
if (!strcmp(szKeyword, DefinitionKeywords[i])) {
|
|
return(i);
|
|
}
|
|
}
|
|
|
|
return((WORD) -1);
|
|
}
|
|
|
|
|
|
WORD
|
|
SkipToNextKeyword (
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Ignore all statements between keywords.
|
|
|
|
Arguments:
|
|
|
|
Keyword - Name of keyword being ignored.
|
|
|
|
Return Value:
|
|
|
|
Index of next definition keyword, -1 otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
while ((Argument = ReadDefinitionFile()) != NULL) {
|
|
char c;
|
|
|
|
if ((c = *Argument) != '\0') {
|
|
const char *token;
|
|
|
|
if (c == END_DEF_FILE) {
|
|
return((WORD) -1);
|
|
}
|
|
|
|
if ((token = _tcstok(Argument, " \t")) != NULL) {
|
|
WORD i;
|
|
|
|
if ((i = IsDefinitionKeyword(token)) != (WORD) -1) {
|
|
return(i);
|
|
}
|
|
|
|
// Ignore invalid keyword; let user know about it
|
|
|
|
Warning(DefFilename, IGNOREKEYWORD, token);
|
|
}
|
|
}
|
|
}
|
|
|
|
return((WORD) -1);
|
|
}
|
|
|
|
|
|
void
|
|
CreateDirective (
|
|
const char *Switch
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
IbAppendBlk(&blkDirectives, " ", strlen(" "));
|
|
IbAppendBlk(&blkDirectives, Switch, strlen(Switch));
|
|
}
|
|
|
|
|
|
WORD
|
|
ParseDefNameOrLibrary (
|
|
PIMAGE pimage,
|
|
BOOL IsLibrary
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Assign the program name.
|
|
|
|
Arguments:
|
|
|
|
IsLibrary - TRUE if parsing library name.
|
|
|
|
Return Value:
|
|
|
|
Index of definition keyword, -1 otherwise.
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
static BOOL Parsed;
|
|
BOOL fLFN = FALSE; // for Long FileName
|
|
const char *szToken;
|
|
|
|
InternalError.Phase = "ParseDefNameOrLibrary";
|
|
|
|
if (Parsed) {
|
|
// UNDONE: What about VXD?
|
|
|
|
Warning(DefFilename, IGNOREKEYWORD, (IsLibrary ? "LIBRARY" : "NAME"));
|
|
|
|
return(SkipToNextKeyword());
|
|
}
|
|
|
|
Parsed = TRUE;
|
|
|
|
szToken = SzGetArgument(Argument, &fLFN);
|
|
|
|
if (szToken) {
|
|
char szDirective[MAXDIRECTIVESIZE];
|
|
char szFname[_MAX_FNAME];
|
|
char szExt[_MAX_EXT];
|
|
char szDrive[_MAX_DRIVE] = "";
|
|
char szDir[_MAX_DIR] = "";
|
|
|
|
if (IsLibrary) {
|
|
CreateDirective("/DLL");
|
|
}
|
|
|
|
if (pimageDeflib->ImgFileHdr.Machine == IMAGE_FILE_MACHINE_M68K) {
|
|
szLibraryID = SzDup(szToken);
|
|
}
|
|
|
|
// UNDONE: Error if szToken contains drive or directory components?
|
|
|
|
_splitpath(szToken, szDrive, szDir, szFname, szExt);
|
|
|
|
if (*szDrive != '\0' || *szDir != '\0') {
|
|
Warning (DefFilename, DRIVEDIRIGNORED, (IsLibrary ? "LIBRARY" : "NAME"));
|
|
}
|
|
|
|
pimageDeflib->Switch.Lib.DllName = SzDup(szFname);
|
|
if (szExt[0] != '\0') {
|
|
pimageDeflib->Switch.Lib.DllExtension = SzDup(szExt);
|
|
} else if (pimageDeflib->imaget == imagetVXD) {
|
|
pimageDeflib->Switch.Lib.DllExtension = ".VXD";
|
|
} else if (!IsLibrary) {
|
|
pimageDeflib->Switch.Lib.DllExtension = ".EXE";
|
|
}
|
|
|
|
strcpy(szDirective, "/OUT:");
|
|
if (fLFN) {
|
|
strcat(szDirective, "\"");
|
|
}
|
|
strcat(szDirective, pimageDeflib->Switch.Lib.DllName);
|
|
strcat(szDirective, pimageDeflib->Switch.Lib.DllExtension);
|
|
if (fLFN) {
|
|
strcat(szDirective, "\"");
|
|
}
|
|
CreateDirective(szDirective);
|
|
|
|
// create a NAME directive for VxDs
|
|
if (pimage->imaget == imagetVXD && !IsLibrary) {
|
|
|
|
szDirective[0] = '\0';
|
|
strcpy(szDirective, "/NAME:");
|
|
strcat(szDirective, pimageDeflib->Switch.Lib.DllName);
|
|
|
|
CreateDirective(szDirective);
|
|
}
|
|
|
|
// Certain PowerMac system DLLs don't have the .DLL extension
|
|
// Hence the .ppcshl and .drectve sections should not have the
|
|
// .DLL extension. However, the /OUT should still produce the file
|
|
// with the DLL extension. So after the /OUT directive is generated,
|
|
// the extension is removed if the container name specified with
|
|
// LIBRARY statement in the .DEF file does not have one - ShankarV
|
|
|
|
if ((pimageDeflib->ImgFileHdr.Machine == IMAGE_FILE_MACHINE_MPPC_601) &&
|
|
(szExt[0] == '\0')) {
|
|
pimageDeflib->Switch.Lib.DllExtension = "";
|
|
}
|
|
|
|
for (;;) {
|
|
WORD i;
|
|
|
|
szToken = SzGetArgument(NULL, &fLFN);
|
|
|
|
if (szToken == NULL) {
|
|
break;
|
|
}
|
|
|
|
if (!_strnicmp(szToken, "BASE=", 5)) {
|
|
i = NAMEORLIBRARY_BASE;
|
|
} else {
|
|
for (i = 0; NameOrLibraryKeywords[i] != NULL; i++) {
|
|
if (!_stricmp(szToken, NameOrLibraryKeywords[i])) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
switch (i) {
|
|
char sizeBuf[35];
|
|
DWORD base;
|
|
|
|
case NAMEORLIBRARY_BASE:
|
|
if (pimage->imaget == imagetVXD) {
|
|
goto DoFatal;
|
|
}
|
|
|
|
if (sscanf(szToken+5, "%li", &base) != 1) {
|
|
Fatal(DefFilename, DEFSYNTAX, "NAME");
|
|
}
|
|
strcpy(szDirective, "/BASE:0x");
|
|
_ultoa(base, sizeBuf, 16);
|
|
strcat(szDirective, sizeBuf);
|
|
CreateDirective(szDirective);
|
|
break;
|
|
|
|
case NAMEORLIBRARY_WINDOWAPI:
|
|
if (pimage->imaget == imagetVXD) {
|
|
goto DoFatal;
|
|
}
|
|
|
|
CreateDirective("/SUBSYSTEM:WINDOWS");
|
|
break;
|
|
|
|
case NAMEORLIBRARY_WINDOWCOMPAT:
|
|
if (pimage->imaget == imagetVXD) {
|
|
goto DoFatal;
|
|
}
|
|
|
|
CreateDirective("/SUBSYSTEM:CONSOLE");
|
|
break;
|
|
|
|
case NAMEORLIBRARY_NOTWINDOWCOMPAT:
|
|
if (pimage->imaget == imagetVXD) {
|
|
goto DoFatal;
|
|
}
|
|
|
|
// Ignore, but give a warning
|
|
|
|
Warning(DefFilename, IGNOREKEYWORD, szToken);
|
|
break;
|
|
|
|
case NAMEORLIBRARY_DYNAMIC:
|
|
if (pimage->imaget != imagetVXD) {
|
|
goto DoFatal;
|
|
}
|
|
|
|
CreateDirective("/EXETYPE:DYNAMIC");
|
|
break;
|
|
|
|
case NAMEORLIBRARY_NEWFILES:
|
|
case NAMEORLIBRARY_LONGNAMES:
|
|
case NAMEORLIBRARY_INITINSTANCE:
|
|
if (pimage->imaget == imagetVXD) {
|
|
goto DoFatal;
|
|
}
|
|
|
|
// Ignore
|
|
break;
|
|
|
|
default:
|
|
DoFatal:
|
|
// UNDONE: What about VXD?
|
|
|
|
Fatal(DefFilename, DEFSYNTAX, (IsLibrary ? "LIBRARY" : "NAME"));
|
|
}
|
|
}
|
|
}
|
|
|
|
return(SkipToNextKeyword());
|
|
}
|
|
|
|
|
|
WORD
|
|
ParseDefDescription (
|
|
char *Text
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Assign the description statement.
|
|
|
|
Arguments:
|
|
|
|
Text - The description text.
|
|
|
|
Return Value:
|
|
|
|
Index of definition keyword, -1 otherwise.
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
char *p;
|
|
char *pp;
|
|
|
|
InternalError.Phase = "ParseDefDescription";
|
|
|
|
if (Text && *Text) {
|
|
p = Text;
|
|
while (*p == ' ' || *p == '\t') {
|
|
++p;
|
|
}
|
|
|
|
if (*p == '\'') {
|
|
++p;
|
|
if (*p && ((pp = _tcsrchr(Text, '\'')) != NULL)) {
|
|
*pp = '\0';
|
|
}
|
|
}
|
|
|
|
DescriptionString = SzDup(p);
|
|
}
|
|
|
|
return(SkipToNextKeyword());
|
|
}
|
|
|
|
|
|
WORD
|
|
ParseSizes (
|
|
char *Type,
|
|
DWORD *Size,
|
|
DWORD *CommitSize
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Assigns the stack/heap size and/or commit size.
|
|
|
|
Arguments:
|
|
|
|
Type - Either "STACK" or "HEAP".
|
|
|
|
Text - The text containing the size(s).
|
|
|
|
Size - A pointer to store either the stack or heap size.
|
|
|
|
CommitSize - A pointer to store either the stack or heap commit size.
|
|
|
|
Return Value:
|
|
|
|
Index of definition keyword, -1 otherwise.
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
INT goodScan, amountScan;
|
|
|
|
InternalError.Phase = "ParseSizes";
|
|
|
|
if (Argument && *Argument) {
|
|
goodScan = 0;
|
|
if (strchr(Argument, ',')) {
|
|
if (Argument[0] == ',') {
|
|
Argument++;
|
|
amountScan = 1;
|
|
goodScan = sscanf(Argument, "%li", CommitSize);
|
|
} else {
|
|
amountScan = 2;
|
|
goodScan = sscanf(Argument, "%li,%li", Size, CommitSize);
|
|
}
|
|
} else {
|
|
amountScan = 1;
|
|
goodScan = sscanf(Argument, "%li", Size);
|
|
}
|
|
|
|
if (goodScan != amountScan) {
|
|
Fatal(DefFilename, DEFSYNTAX, Type);
|
|
}
|
|
|
|
if (*CommitSize > *Size) {
|
|
Warning(DefFilename, BADCOMMITSIZE, Type, *Size);
|
|
*CommitSize = *Size;
|
|
}
|
|
}
|
|
|
|
return(SkipToNextKeyword());
|
|
}
|
|
|
|
|
|
WORD
|
|
ParseDefCode (
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Assign the code attributes.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
Index of definition keyword, -1 otherwise.
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
const char *Attributes;
|
|
|
|
InternalError.Phase = "ParseDefCode";
|
|
|
|
while ((Attributes = _tcstok(NULL, Delimiters)) != NULL) {
|
|
DebugVerbose({printf("%s\n", Attributes);});
|
|
}
|
|
|
|
return(SkipToNextKeyword());
|
|
}
|
|
|
|
|
|
WORD
|
|
ParseDefData (
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Assign the data attributes.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
Index of definition keyword, -1 otherwise.
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
const char *Attributes;
|
|
|
|
InternalError.Phase = "ParseDefData";
|
|
|
|
while ((Attributes = _tcstok(NULL, Delimiters)) != NULL) {
|
|
DebugVerbose({printf("%s\n", Attributes);});
|
|
}
|
|
|
|
return(SkipToNextKeyword());
|
|
}
|
|
|
|
|
|
WORD
|
|
IsSectionKeyword (
|
|
char *szKeyword
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Determines if Name is a section keyword.
|
|
|
|
Arguments:
|
|
|
|
Name - Name to compare.
|
|
|
|
Return Value:
|
|
|
|
Index of definition keyword, -1 otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
WORD i;
|
|
|
|
for (i = 0; SectionKeywords[i] != NULL; i++) {
|
|
if (!_stricmp(szKeyword, SectionKeywords[i])) {
|
|
return(i);
|
|
}
|
|
}
|
|
|
|
return((WORD)-1);
|
|
}
|
|
|
|
|
|
WORD
|
|
ParseDefSections (
|
|
const char *Type,
|
|
char *FirstSection
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Assign the section attributes.
|
|
|
|
Arguments:
|
|
|
|
Type - Either "SECTIONS", "SEGMENTS", or "OBJECTS".
|
|
|
|
FirstSection - The name of the first section if specified on same
|
|
line as SECTION keyword.
|
|
|
|
Return Value:
|
|
|
|
Index of definition keyword, -1 otherwise.
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
InternalError.Phase = "ParseDefSections";
|
|
|
|
if (FirstSection) {
|
|
while (*FirstSection == ' ' || *FirstSection == '\t') {
|
|
++FirstSection;
|
|
}
|
|
|
|
Argument = FirstSection;
|
|
} else {
|
|
|
|
Argument = ReadDefinitionFile();
|
|
}
|
|
|
|
do {
|
|
char c;
|
|
const char *szSection;
|
|
WORD i;
|
|
DWORD characteristics;
|
|
BOOL fHasClass;
|
|
BOOL fNonDiscardable;
|
|
char *szAttribute;
|
|
const char *szClass;
|
|
BOOL fIopl;
|
|
BOOL fConforming;
|
|
|
|
c = Argument[0];
|
|
|
|
if (c == '\0') {
|
|
continue;
|
|
}
|
|
|
|
if (c == END_DEF_FILE) {
|
|
return((WORD)-1);
|
|
}
|
|
|
|
szSection = _tcstok(Argument, Delimiters);
|
|
|
|
if ((i = IsDefinitionKeyword(szSection)) != (WORD)-1) {
|
|
return(i);
|
|
}
|
|
|
|
c = szSection[0];
|
|
if ((c == '\'') || (c == '"')) {
|
|
char *p;
|
|
|
|
szSection++;
|
|
|
|
p = strchr(szSection, c);
|
|
|
|
if (p) {
|
|
*p = '\0';
|
|
}
|
|
}
|
|
|
|
if (!FValidSecName(szSection)) {
|
|
Fatal(DefFilename, INVALIDSECNAMEINDEF, szSection);
|
|
}
|
|
|
|
characteristics = 0;
|
|
fHasClass = FALSE;
|
|
fNonDiscardable = FALSE;
|
|
fIopl = FALSE;
|
|
fConforming = FALSE;
|
|
|
|
if ((szAttribute = _tcstok(NULL, Delimiters)) != NULL) {
|
|
if (!_stricmp(szAttribute, "CLASS")) {
|
|
if (pimageDeflib->imaget == imagetVXD) {
|
|
szClass = _tcstok(NULL, VxDDelimiters);
|
|
fHasClass = TRUE;
|
|
} else {
|
|
// Ignore class name
|
|
|
|
_tcstok(NULL, Delimiters);
|
|
}
|
|
|
|
szAttribute = _tcstok(NULL, Delimiters);
|
|
}
|
|
}
|
|
|
|
while (szAttribute != NULL) {
|
|
switch (IsSectionKeyword(szAttribute)) {
|
|
case DISCARDABLE :
|
|
characteristics |= IMAGE_SCN_MEM_DISCARDABLE;
|
|
break;
|
|
|
|
case EXECUTE :
|
|
characteristics |= IMAGE_SCN_MEM_EXECUTE;
|
|
break;
|
|
|
|
case READ :
|
|
characteristics |= IMAGE_SCN_MEM_READ;
|
|
break;
|
|
|
|
case SHARED :
|
|
characteristics |= IMAGE_SCN_MEM_SHARED;
|
|
break;
|
|
|
|
case WRITE :
|
|
characteristics |= IMAGE_SCN_MEM_WRITE;
|
|
break;
|
|
|
|
// VXD specific keywords
|
|
|
|
case NONDISCARDABLE :
|
|
if (pimageDeflib->imaget == imagetVXD) {
|
|
fNonDiscardable = TRUE;
|
|
} else {
|
|
// UNDONE: Should print a warning
|
|
}
|
|
break;
|
|
|
|
case RESIDENT :
|
|
if (pimageDeflib->imaget == imagetVXD) {
|
|
characteristics |= IMAGE_SCN_MEM_RESIDENT;
|
|
} else {
|
|
// UNDONE: Should print a warning
|
|
}
|
|
break;
|
|
|
|
case PRELOAD :
|
|
if (pimageDeflib->imaget == imagetVXD) {
|
|
characteristics |= IMAGE_SCN_MEM_PRELOAD;
|
|
} else {
|
|
// UNDONE: Should print a warning
|
|
}
|
|
break;
|
|
|
|
// Old names.
|
|
|
|
case EXECUTEONLY :
|
|
characteristics |= IMAGE_SCN_MEM_EXECUTE;
|
|
break;
|
|
|
|
case EXECUTEREAD :
|
|
characteristics |= IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ;
|
|
break;
|
|
|
|
case NONSHARED :
|
|
// Default is nonshared, so ignore it.
|
|
|
|
break;
|
|
|
|
case READONLY :
|
|
characteristics |= IMAGE_SCN_MEM_READ;
|
|
break;
|
|
|
|
case READWRITE :
|
|
characteristics |= IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE;
|
|
break;
|
|
|
|
case NONE :
|
|
case SINGLE :
|
|
case MULTIPLE :
|
|
// UNDONE
|
|
break;
|
|
|
|
case CONFORMING :
|
|
if (pimageDeflib->imaget == imagetVXD) {
|
|
fConforming = TRUE;
|
|
break;
|
|
}
|
|
case IOPL :
|
|
if (pimageDeflib->imaget == imagetVXD) {
|
|
fIopl = TRUE;
|
|
break;
|
|
}
|
|
case FIXED :
|
|
case IMPURE :
|
|
case LOADONCALL :
|
|
case MOVABLE :
|
|
case MOVEABLE :
|
|
case NOIOPL :
|
|
case NONCONFORMING :
|
|
case PURE :
|
|
Warning(DefFilename, IGNOREKEYWORD, szAttribute);
|
|
break;
|
|
|
|
default :
|
|
Fatal(DefFilename, DEFSYNTAX, Type);
|
|
}
|
|
|
|
szAttribute = _tcstok(NULL, Delimiters);
|
|
}
|
|
|
|
if ((characteristics != 0) || fHasClass || fNonDiscardable) {
|
|
char szDirective[128];
|
|
char szSectionVxd[128];
|
|
|
|
strcpy(szDirective, "/SECTION:");
|
|
if (pimageDeflib->imaget == imagetVXD) {
|
|
if (fHasClass) {
|
|
strcpy(szSectionVxd, szClass);
|
|
strcat(szSectionVxd, "_vxd");
|
|
}
|
|
else {
|
|
strcpy(szSectionVxd, "vxd");
|
|
}
|
|
if (characteristics & IMAGE_SCN_MEM_PRELOAD) {
|
|
strcat(szSectionVxd, "p");
|
|
}
|
|
if (characteristics & IMAGE_SCN_MEM_EXECUTE) {
|
|
strcat(szSectionVxd, "e");
|
|
}
|
|
if (characteristics & IMAGE_SCN_MEM_READ) {
|
|
strcat(szSectionVxd, "r");
|
|
}
|
|
if (characteristics & IMAGE_SCN_MEM_WRITE) {
|
|
strcat(szSectionVxd, "w");
|
|
}
|
|
if (characteristics & IMAGE_SCN_MEM_SHARED) {
|
|
strcat(szSectionVxd, "s");
|
|
}
|
|
if (characteristics & IMAGE_SCN_MEM_DISCARDABLE) {
|
|
strcat(szSectionVxd, "d");
|
|
}
|
|
if (fNonDiscardable) {
|
|
strcat(szSectionVxd, "n");
|
|
}
|
|
if (fIopl) {
|
|
strcat(szSectionVxd, "i");
|
|
}
|
|
if (fConforming) {
|
|
strcat(szSectionVxd, "c");
|
|
}
|
|
if (characteristics & IMAGE_SCN_MEM_RESIDENT) {
|
|
strcat(szSectionVxd, "x");
|
|
}
|
|
strcat(szDirective, szSectionVxd);
|
|
} else {
|
|
strcat(szDirective, szSection);
|
|
}
|
|
|
|
strcat(szDirective, ",");
|
|
|
|
if (characteristics & IMAGE_SCN_MEM_DISCARDABLE) {
|
|
strcat(szDirective, "D");
|
|
}
|
|
if (characteristics & IMAGE_SCN_MEM_EXECUTE) {
|
|
strcat(szDirective, "E");
|
|
}
|
|
if (characteristics & IMAGE_SCN_MEM_READ) {
|
|
strcat(szDirective, "R");
|
|
}
|
|
if (characteristics & IMAGE_SCN_MEM_SHARED) {
|
|
strcat(szDirective, "S");
|
|
}
|
|
if (characteristics & IMAGE_SCN_MEM_WRITE) {
|
|
strcat(szDirective, "W");
|
|
}
|
|
|
|
if (pimageDeflib->imaget == imagetVXD) {
|
|
if (characteristics & IMAGE_SCN_MEM_PRELOAD) {
|
|
strcat(szDirective, "L");
|
|
}
|
|
if (characteristics & IMAGE_SCN_MEM_RESIDENT) {
|
|
strcat(szDirective, "X");
|
|
}
|
|
if (fIopl) {
|
|
strcat(szDirective, "I");
|
|
}
|
|
if (fConforming) {
|
|
strcat(szDirective, "C");
|
|
}
|
|
|
|
// Negatives must be last as they negate everything afterward.
|
|
|
|
if (fNonDiscardable) {
|
|
strcat(szDirective, "!D");
|
|
}
|
|
}
|
|
|
|
CreateDirective(szDirective);
|
|
|
|
if (pimageDeflib->imaget == imagetVXD) {
|
|
const char *szCoffSection;
|
|
|
|
strcpy(szDirective,"/MERGE:");
|
|
strcat(szDirective, szSection);
|
|
strcat(szDirective, "=");
|
|
strcat(szDirective, szSectionVxd);
|
|
CreateDirective(szDirective);
|
|
|
|
szCoffSection = NULL;
|
|
|
|
if (strcmp(szSection, "_TEXT") == 0) {
|
|
szCoffSection = ".text";
|
|
} else if (strcmp(szSection, "_DATA") == 0) {
|
|
szCoffSection = ".data";
|
|
} else if (strcmp(szSection, "_BSS") == 0) {
|
|
szCoffSection = ".bss";
|
|
} else if (strcmp(szSection, "CONST") == 0) {
|
|
szCoffSection = ".rdata";
|
|
}
|
|
|
|
if (szCoffSection != NULL) {
|
|
// If we merge _TEXT into another section, merge .text
|
|
// into the same section. Do something similar for
|
|
// _DATA and CONST. This allows using COFF objects
|
|
// with a .DEF file that uses OMF segment names.
|
|
|
|
strcpy(szDirective, "/MERGE:");
|
|
strcat(szDirective, szCoffSection);
|
|
strcat(szDirective, "=");
|
|
strcat(szDirective, szSectionVxd);
|
|
CreateDirective(szDirective);
|
|
}
|
|
}
|
|
}
|
|
} while (Argument = ReadDefinitionFile());
|
|
|
|
return((WORD)-1);
|
|
}
|
|
|
|
|
|
WORD
|
|
ParseVxDDefExport (
|
|
char *Argument
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Parse a single export specification and add EXPORT directive to lib.
|
|
|
|
Arguments:
|
|
|
|
pst - external symbol table
|
|
|
|
Argument - Export entry
|
|
|
|
szFilename - name of def file or obj containing the directive.
|
|
|
|
Return Value:
|
|
|
|
Index of definition keyword, 0 otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
char c;
|
|
|
|
InternalError.Phase = "ParseVxdDefExport";
|
|
|
|
if ((c = *Argument) != '\0') {
|
|
char *p;
|
|
char *szExport;
|
|
WORD i;
|
|
char szDirective[MAXDIRECTIVESIZE];
|
|
|
|
szExport = p = Argument;
|
|
|
|
while (*p) {
|
|
switch (*p) {
|
|
case ' ' :
|
|
case '\t':
|
|
case '=' :
|
|
c = *p;
|
|
*p = '\0';
|
|
break;
|
|
|
|
default :
|
|
++p;
|
|
}
|
|
}
|
|
|
|
++p;
|
|
|
|
// Skip trailing spaces.
|
|
|
|
if (*p) {
|
|
while (*p == ' ' || *p == '\t') {
|
|
++p;
|
|
}
|
|
if (c == ' ' || c == '\t') {
|
|
c = *p;
|
|
if (c == '=' || c == '@') {
|
|
++p;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (c && (i = IsDefinitionKeyword(szExport)) != (WORD)-1) {
|
|
return(i);
|
|
}
|
|
|
|
strcpy(szDirective, "/EXPORT:");
|
|
strcat(szDirective, szExport);
|
|
|
|
if (c == '@') {
|
|
size_t ich;
|
|
|
|
strcat(szDirective, ",@");
|
|
|
|
ich = strlen(szDirective);
|
|
|
|
while (isdigit(*p)) {
|
|
szDirective[ich++] = *p++;
|
|
}
|
|
|
|
szDirective[ich] = '\0';
|
|
}
|
|
|
|
CreateDirective(szDirective);
|
|
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
|
|
void
|
|
AddOrdinal(DWORD dwOrdinal)
|
|
// Just keeps track of the range of ordinal values.
|
|
{
|
|
if (!SmallestOrdinal) {
|
|
SmallestOrdinal = LargestOrdinal = dwOrdinal;
|
|
} else if (dwOrdinal < SmallestOrdinal) {
|
|
SmallestOrdinal = dwOrdinal;
|
|
} else if (dwOrdinal > LargestOrdinal) {
|
|
LargestOrdinal = dwOrdinal;
|
|
}
|
|
}
|
|
|
|
|
|
WORD
|
|
ParseAnExport (
|
|
PIMAGE pimage,
|
|
char *szExport,
|
|
const char *szFilename
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Parse a single export specification and add export name to external table.
|
|
|
|
Arguments:
|
|
|
|
pst - external symbol table
|
|
|
|
szExport - Export entry
|
|
|
|
szFilename - name of def file or obj containing the directive.
|
|
|
|
Return Value:
|
|
|
|
Index of definition keyword, -1 otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
char ch;
|
|
char *szToken;
|
|
char *szName;
|
|
char *szOtherName;
|
|
WORD i;
|
|
DWORD dwOrdinal;
|
|
EMODE emode;
|
|
BOOL fNoName;
|
|
BOOL fMacPascal;
|
|
BOOL fPrivate;
|
|
|
|
InternalError.Phase = "ParseAnExport";
|
|
|
|
if (szExport[0] == '\0') {
|
|
return(0);
|
|
}
|
|
|
|
szName = szExport;
|
|
|
|
// Skip to end of name or '='
|
|
|
|
while (((ch = *szExport) != '\0') && (ch != ' ') && (ch != '\t') && (ch != '=')) {
|
|
szExport++;
|
|
}
|
|
|
|
if (ch != '\0') {
|
|
// Null terminate export name and skip over terminator
|
|
|
|
*szExport++ = '\0';
|
|
}
|
|
|
|
// If name is a keyword than we aren't processing an export
|
|
|
|
if ((i = IsDefinitionKeyword(szName)) != (WORD) -1) {
|
|
return(i);
|
|
}
|
|
|
|
szOtherName = NULL;
|
|
fNoName = FALSE;
|
|
fMacPascal = FALSE;
|
|
fPrivate = FALSE;
|
|
emode = emodeProcedure;
|
|
dwOrdinal = 0;
|
|
|
|
// Find the token following the export name.
|
|
// If (ch == '=') then this is really the second token.
|
|
|
|
szToken = _tcstok(szExport, Delimiters);
|
|
|
|
// If the export name wasn't terminated by an '=',
|
|
// check if the next token begins with an '='.
|
|
|
|
if ((ch != '=') && (szToken != NULL) && (szToken[0] == '=')) {
|
|
// Skip the '='. If this is the whole token, get the next token.
|
|
|
|
if (*++szToken == '\0') {
|
|
szToken = _tcstok(NULL, Delimiters);
|
|
}
|
|
|
|
ch = '=';
|
|
}
|
|
|
|
if (ch == '=') {
|
|
if (szToken == NULL) {
|
|
// UNDONE: Syntax error. No identifier following '='.
|
|
}
|
|
|
|
szOtherName = szToken;
|
|
|
|
// Skip the other name
|
|
|
|
szToken = _tcstok(NULL, Delimiters);
|
|
}
|
|
|
|
if ((szToken != NULL) && (szToken[0] == '@')) {
|
|
// Skip the '@'. If this is the whole token, get the next token.
|
|
|
|
if (*++szToken == '\0') {
|
|
szToken = _tcstok(NULL, Delimiters);
|
|
|
|
if (szToken == NULL) {
|
|
// UNDONE: Syntax error. No identifier following '@'.
|
|
|
|
Fatal(szFilename, BADORDINAL, "");
|
|
}
|
|
}
|
|
|
|
if ((sscanf(szToken, "%lu", &dwOrdinal) != 1) ||
|
|
(dwOrdinal == 0) ||
|
|
(dwOrdinal > 0xFFFF)) {
|
|
Fatal(szFilename, BADORDINAL, szToken);
|
|
}
|
|
|
|
AddOrdinal(dwOrdinal);
|
|
|
|
// Skip ordinal number
|
|
|
|
szToken = _tcstok(NULL, Delimiters);
|
|
|
|
if (szToken != NULL) {
|
|
if (pimage->ImgFileHdr.Machine != IMAGE_FILE_MACHINE_M68K) {
|
|
if (_stricmp(szToken, "NONAME") == 0) {
|
|
fNoName = TRUE;
|
|
|
|
szToken = _tcstok(NULL, Delimiters);
|
|
} else if (_stricmp(szToken, "RESIDENTNAME") == 0) {
|
|
Warning(DefFilename, IGNOREKEYWORD, szToken);
|
|
|
|
szToken = _tcstok(NULL, Delimiters);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// UNDONE: Clean up the following code so as to not be so
|
|
// UNDONE: dependent on the order of attributes.
|
|
|
|
if ((szToken != NULL) && (_stricmp(szToken, "PRIVATE") == 0)) {
|
|
fPrivate = TRUE;
|
|
|
|
szToken = _tcstok(NULL, Delimiters);
|
|
}
|
|
|
|
if (pimage->ImgFileHdr.Machine == IMAGE_FILE_MACHINE_M68K) {
|
|
fNoName = TRUE;
|
|
|
|
if ((szToken != NULL) && (_stricmp(szToken, "BYNAME") == 0)) {
|
|
fNoName = FALSE;
|
|
|
|
szToken = _tcstok(NULL, Delimiters);
|
|
}
|
|
|
|
if ((szToken != NULL) && (_stricmp(szToken, "PASCAL") == 0)) {
|
|
char *pch;
|
|
|
|
fMacPascal = TRUE;
|
|
|
|
for (pch = szName; *pch != '\0'; pch++) {
|
|
*pch = (char) toupper(*pch);
|
|
}
|
|
|
|
if (szOtherName != NULL) {
|
|
for (pch = szOtherName; *pch != '\0'; pch++) {
|
|
*pch = (char) toupper(*pch);
|
|
}
|
|
}
|
|
|
|
szToken = _tcstok(NULL, Delimiters);
|
|
}
|
|
} else {
|
|
if (szToken != NULL) {
|
|
if (_stricmp(szToken, "CONSTANT") == 0) {
|
|
// Exporting Data
|
|
|
|
Warning(DefFilename, CONSTANTOLD);
|
|
|
|
emode = emodeConstant;
|
|
|
|
szToken = _tcstok(NULL, Delimiters);
|
|
} else if (_stricmp(szToken, "DATA") == 0) {
|
|
// Really Exporting Data
|
|
|
|
if (fPowerMac) {
|
|
// For PowerMac the data items are
|
|
// exported the same way as functions
|
|
emode = emodeProcedure;
|
|
} else {
|
|
// non-PowerMac cases
|
|
emode = emodeData;
|
|
}
|
|
|
|
szToken = _tcstok(NULL, Delimiters);
|
|
}
|
|
|
|
if ((szToken != NULL) && (_stricmp(szToken, "NODATA") == 0)) {
|
|
// Eat keyword (not used)
|
|
|
|
Warning(DefFilename, IGNOREKEYWORD, szToken);
|
|
|
|
szToken = _tcstok(NULL, Delimiters);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (szToken != NULL) {
|
|
Warning(szFilename, IGNOREKEYWORD, szToken);
|
|
}
|
|
|
|
// Add to external table as defined.
|
|
|
|
AddExportToSymbolTable(szName,
|
|
szOtherName,
|
|
fNoName,
|
|
emode,
|
|
dwOrdinal,
|
|
szFilename,
|
|
FALSE,
|
|
pimage,
|
|
(!fMacPascal && PrependUnderscore),
|
|
fPrivate);
|
|
|
|
if (pimage->ImgFileHdr.Machine == IMAGE_FILE_MACHINE_M68K) {
|
|
NoteMacExport(szName, pimage->pst, fMacPascal, !fNoName);
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
|
|
WORD
|
|
ParseDefExports (
|
|
PIMAGE pimage,
|
|
char *szFirst
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Scan the definiton file and add export names to external table.
|
|
|
|
Arguments:
|
|
|
|
szFirst - The name of the first export if specified on same
|
|
line as EXPORT keyword.
|
|
|
|
Return Value:
|
|
|
|
Index of definition keyword, -1 otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
WORD i;
|
|
|
|
InternalError.Phase = "ParseDefExports";
|
|
|
|
if (szFirst != NULL) {
|
|
// Skip leading white space
|
|
|
|
while (_istspace(*szFirst)) {
|
|
szFirst++; // MBCS: we know that space is 1-byte char,
|
|
// therefore we don't need to use _tcsinc()
|
|
}
|
|
}
|
|
|
|
if (pimage->ImgFileHdr.Machine == IMAGE_FILE_MACHINE_M68K) {
|
|
if ((szFirst == NULL) || (szFirst[0] == '\0')) {
|
|
Fatal(DefFilename, MACNOFUNCTIONSET);
|
|
}
|
|
|
|
CreateCVRSymbol(Argument, pimage->pst, UserVersionNumber);
|
|
szFirst = NULL;
|
|
}
|
|
|
|
if (szFirst != NULL) {
|
|
Argument = szFirst;
|
|
} else {
|
|
Argument = ReadDefinitionFile();
|
|
}
|
|
|
|
do {
|
|
if (Argument[0] == END_DEF_FILE) {
|
|
return((WORD) -1);
|
|
}
|
|
|
|
if (pimage->imaget == imagetVXD) {
|
|
i = ParseVxDDefExport(Argument);
|
|
} else {
|
|
i = ParseAnExport(pimage, Argument, DefFilename);
|
|
}
|
|
|
|
if (i) {
|
|
if (i != VERSION) {
|
|
return(i);
|
|
}
|
|
while (Argument && *Argument++);
|
|
ParseFunctionSetVersion(Argument);
|
|
}
|
|
} while (Argument = ReadDefinitionFile());
|
|
|
|
return((WORD) -1);
|
|
}
|
|
|
|
|
|
WORD
|
|
ParseDefImports (
|
|
char *FirstImport
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Scan the definiton file and add import thunks.
|
|
|
|
Arguments:
|
|
|
|
FirstImport - The name of the first import if specified on same
|
|
line as IMPORT keyword.
|
|
|
|
Return Value:
|
|
|
|
Index of definition keyword, -1 otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
InternalError.Phase = "ParseDefImports";
|
|
|
|
if (FirstImport) {
|
|
while (*FirstImport == ' ' || *FirstImport == '\t') {
|
|
FirstImport++;
|
|
}
|
|
Argument = FirstImport;
|
|
} else {
|
|
Argument = ReadDefinitionFile();
|
|
}
|
|
|
|
do {
|
|
char c;
|
|
|
|
if ((c = *Argument) != '\0') {
|
|
char *p;
|
|
char *dllName;
|
|
WORD i;
|
|
|
|
if (c == END_DEF_FILE) {
|
|
return((WORD)-1);
|
|
}
|
|
|
|
dllName = p = Argument;
|
|
|
|
while (*p) {
|
|
switch (*p) {
|
|
case ' ' :
|
|
case '\t':
|
|
case '.' :
|
|
case '=' :
|
|
c = *p;
|
|
*p = '\0';
|
|
break;
|
|
|
|
default :
|
|
p++;
|
|
break;
|
|
}
|
|
}
|
|
|
|
p++;
|
|
|
|
if (c && (i = IsDefinitionKeyword(dllName)) != (WORD)-1) {
|
|
return(i);
|
|
}
|
|
|
|
while (*p && (*p == ' ' || *p == '\t')) {
|
|
p++;
|
|
}
|
|
|
|
if (c == ' ' || c == '\t') {
|
|
c = *p++;
|
|
}
|
|
|
|
if (c == '=') {
|
|
// Internal name used
|
|
|
|
dllName = _tcstok(p, Delimiters);
|
|
p = strchr(dllName, '.');
|
|
if (*p) {
|
|
*p++ = '\0';
|
|
}
|
|
}
|
|
|
|
if (c == '@') {
|
|
DWORD dwOrdinal;
|
|
|
|
// Ordinal was specified.
|
|
|
|
if ((sscanf(p, "%lu", &dwOrdinal) != 1) ||
|
|
(dwOrdinal == 0) ||
|
|
(dwOrdinal > 0xFFFF)) {
|
|
Fatal(DefFilename, BADORDINAL, p);
|
|
}
|
|
}
|
|
}
|
|
} while (Argument = ReadDefinitionFile());
|
|
|
|
return((WORD)-1);
|
|
}
|
|
|
|
|
|
WORD
|
|
ParseDefStub (
|
|
char *Stubname
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Inserts a -STUB: directive into the export lib.
|
|
|
|
Arguments:
|
|
|
|
Stubname - the name of the stub .exe.
|
|
|
|
Return Value:
|
|
|
|
Index of definition keyword, -1 otherwise.
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
char directiveBuf[MAXDIRECTIVESIZE];
|
|
char *p;
|
|
char *pp;
|
|
|
|
InternalError.Phase = "ParseDefStub";
|
|
|
|
if (Stubname && *Stubname) {
|
|
p = Stubname;
|
|
while (*p == ' ' || *p == '\t') {
|
|
++p;
|
|
}
|
|
if (*p == '\'') {
|
|
++p;
|
|
if (*p && ((pp = _tcsrchr(Stubname, '\'')) != NULL)) {
|
|
*pp = '\0';
|
|
}
|
|
}
|
|
strcpy(directiveBuf, "/STUB:");
|
|
strcat(directiveBuf, p);
|
|
CreateDirective(directiveBuf);
|
|
}
|
|
|
|
return(SkipToNextKeyword());
|
|
}
|
|
|
|
|
|
void
|
|
ParseDefinitionFile (
|
|
PIMAGE pimage,
|
|
const char *szDefFile
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Parse the definition file.
|
|
|
|
Arguments:
|
|
|
|
pst - External symbol table.
|
|
|
|
szDefFile - module definition file.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
WORD i;
|
|
char *token;
|
|
char *p;
|
|
DWORD reserveSize, commitSize;
|
|
char sizeBuf[25];
|
|
char directiveBuf[MAXDIRECTIVESIZE];
|
|
|
|
// Open the definition file.
|
|
|
|
InternalError.Phase = "ParseDefinitionFile";
|
|
|
|
if (!(DefStream = fopen(szDefFile, "rt"))) {
|
|
Fatal(NULL, CANTOPENFILE, szDefFile);
|
|
}
|
|
|
|
// Find the first Keyword in the definiton file.
|
|
|
|
i = SkipToNextKeyword();
|
|
|
|
while (i != (WORD)-1) {
|
|
if (pimage->ImgFileHdr.Machine != IMAGE_FILE_MACHINE_M68K) {
|
|
switch (i) {
|
|
case NAME :
|
|
case LIBRARY :
|
|
while (Argument && *Argument++);
|
|
i = ParseDefNameOrLibrary(pimage, i == LIBRARY);
|
|
break;
|
|
|
|
case DESCRIPTION :
|
|
while (Argument && *Argument++);
|
|
i = ParseDefDescription(Argument);
|
|
if ((pimageDeflib->imaget == imagetVXD) &&
|
|
(DescriptionString[0] != '\0')) {
|
|
DescriptionString[MAXDIRECTIVESIZE-11] = '\0';
|
|
|
|
strcpy(directiveBuf,"/COMMENT:\"");
|
|
strcat(directiveBuf, DescriptionString);
|
|
strcat(directiveBuf, "\"");
|
|
|
|
CreateDirective(directiveBuf);
|
|
}
|
|
break;
|
|
|
|
case HEAPSIZE :
|
|
while (Argument && *Argument++);
|
|
reserveSize = commitSize = 0;
|
|
i = ParseSizes("HEAP", &reserveSize, &commitSize);
|
|
if (reserveSize) {
|
|
strcpy(directiveBuf, "/HEAP:0x");
|
|
_ultoa(reserveSize, sizeBuf, 16);
|
|
strcat(directiveBuf, sizeBuf);
|
|
if (commitSize) {
|
|
strcat(directiveBuf, ",0x");
|
|
_ultoa(commitSize, sizeBuf, 16);
|
|
strcat(directiveBuf, sizeBuf);
|
|
}
|
|
CreateDirective(directiveBuf);
|
|
}
|
|
break;
|
|
|
|
case STACKSIZE :
|
|
while (Argument && *Argument++);
|
|
reserveSize = commitSize = 0;
|
|
i = ParseSizes("STACK", &reserveSize, &commitSize);
|
|
if (reserveSize) {
|
|
strcpy(directiveBuf, "/STACK:0x");
|
|
_ultoa(reserveSize, sizeBuf, 16);
|
|
strcat(directiveBuf, sizeBuf);
|
|
if (commitSize) {
|
|
strcat(directiveBuf, ",0x");
|
|
_ultoa(commitSize, sizeBuf, 16);
|
|
strcat(directiveBuf, sizeBuf);
|
|
}
|
|
CreateDirective(directiveBuf);
|
|
}
|
|
CreateDirective(directiveBuf);
|
|
break;
|
|
|
|
case CODE :
|
|
i = ParseDefCode();
|
|
break;
|
|
|
|
case DATA :
|
|
i = ParseDefData();
|
|
break;
|
|
|
|
case OBJECTS :
|
|
case SEGMENTS :
|
|
case SECTIONS :
|
|
while (Argument && *Argument++);
|
|
i = ParseDefSections(DefinitionKeywords[i], Argument);
|
|
break;
|
|
|
|
case EXPORTS :
|
|
while (Argument && *Argument++);
|
|
i = ParseDefExports(pimage, Argument);
|
|
break;
|
|
|
|
case IMPORTS :
|
|
while (Argument && *Argument++);
|
|
Warning(DefFilename, IGNOREKEYWORD, DefinitionKeywords[i]);
|
|
i = ParseDefImports(Argument);
|
|
break;
|
|
|
|
case VERSION :
|
|
while (Argument && *Argument++);
|
|
if (pimage->ImgFileHdr.Machine != IMAGE_FILE_MACHINE_M68K) {
|
|
reserveSize = commitSize = 0; // major, minor
|
|
if ((p = strchr(Argument, '.')) != NULL) {
|
|
if ((sscanf(++p, "%li", &commitSize) != 1) || commitSize > 0x7fff) {
|
|
Fatal(DefFilename, DEFSYNTAX, "VERSION");
|
|
}
|
|
}
|
|
if ((sscanf(Argument, "%li", &reserveSize) != 1) || reserveSize > 0x7fff) {
|
|
Fatal(DefFilename, DEFSYNTAX, "VERSION");
|
|
}
|
|
UserVersionNumber = (reserveSize << 16) + commitSize;
|
|
if (UserVersionNumber) {
|
|
strcpy(directiveBuf, "/VERSION:0x");
|
|
_ultoa(reserveSize, sizeBuf, 16);
|
|
strcat(directiveBuf, sizeBuf);
|
|
if (commitSize) {
|
|
strcat(directiveBuf, ".0x");
|
|
_ultoa(commitSize, sizeBuf, 16);
|
|
strcat(directiveBuf, sizeBuf);
|
|
}
|
|
CreateDirective(directiveBuf);
|
|
}
|
|
i = SkipToNextKeyword();
|
|
}
|
|
break;
|
|
|
|
case VXD :
|
|
while (Argument && *Argument++);
|
|
if (pimageDeflib->imaget == imagetVXD) {
|
|
i = ParseDefNameOrLibrary(pimage, FALSE);
|
|
} else {
|
|
Warning(DefFilename, IGNOREKEYWORD, DefinitionKeywords[i]);
|
|
i = SkipToNextKeyword();
|
|
}
|
|
break;
|
|
|
|
case STUB :
|
|
while (Argument && *Argument++);
|
|
if (pimageDeflib->imaget == imagetVXD) {
|
|
i = ParseDefStub(Argument);
|
|
} else {
|
|
Warning(DefFilename, IGNOREKEYWORD, DefinitionKeywords[i]);
|
|
i = SkipToNextKeyword();
|
|
}
|
|
break;
|
|
|
|
case EXETYPE :
|
|
while (Argument && *Argument++);
|
|
if (pimageDeflib->imaget == imagetVXD) {
|
|
// If linking a VxD and the exetype is anything
|
|
// other than "DEV386", give a warning.
|
|
|
|
// UNDONE: Why call _tcstok? This isn't done for non-VXD.
|
|
|
|
token = _tcstok(Argument, Delimiters);
|
|
if (!_stricmp(token, "dev386")) {
|
|
i = SkipToNextKeyword();
|
|
break;
|
|
}
|
|
} else {
|
|
// If the exetype is anything other than "WINDOWS"
|
|
// give a warning.
|
|
|
|
if (!_stricmp(Argument, "windows")) {
|
|
i = SkipToNextKeyword();
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Fall through
|
|
|
|
case OLD :
|
|
case REALMODE :
|
|
case APPLOADER :
|
|
// Ignore, but give a warning
|
|
|
|
Warning(DefFilename, IGNOREKEYWORD, DefinitionKeywords[i]);
|
|
|
|
// Fall through
|
|
|
|
case PROTMODE :
|
|
case FUNCTIONS :
|
|
case INCLUDE :
|
|
// Ignore
|
|
i = SkipToNextKeyword();
|
|
break;
|
|
|
|
default :
|
|
// Ignore, but give a warning
|
|
|
|
Warning(DefFilename, IGNOREKEYWORD, DefinitionKeywords[i]);
|
|
i = SkipToNextKeyword();
|
|
break;
|
|
}
|
|
} else {
|
|
// fM68K
|
|
switch (i) {
|
|
case LIBRARY :
|
|
while (Argument && *Argument++);
|
|
i = ParseDefNameOrLibrary(pimage, TRUE);
|
|
break;
|
|
|
|
case VERSION :
|
|
while (Argument && *Argument++);
|
|
if (UserVersionNumber != 0 ||
|
|
CchParseMacVersion(Argument, &UserVersionNumber) == 0) {
|
|
Fatal(DefFilename, DEFSYNTAX, "VERSION");
|
|
}
|
|
i = SkipToNextKeyword();
|
|
break;
|
|
|
|
case STUB :
|
|
while (Argument && *Argument++);
|
|
//*** VXD stuff does not apply to Mac ***
|
|
//if (pimageDeflib->imaget == imagetVXD) {
|
|
// i = ParseDefStub(Argument);
|
|
//} else {
|
|
Warning(DefFilename, IGNOREKEYWORD, DefinitionKeywords[i]);
|
|
i = SkipToNextKeyword();
|
|
//}
|
|
break;
|
|
|
|
case EXETYPE :
|
|
while (Argument && *Argument++);
|
|
|
|
if (!_stricmp(Argument, "WINDOWS")) {
|
|
i = SkipToNextKeyword();
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case FLAGS :
|
|
while (Argument && *Argument++);
|
|
i = ParseDefMacFlags(Argument, szDefFile);
|
|
break;
|
|
|
|
case LOADHEAP :
|
|
while (Argument && *Argument++);
|
|
i = ParseDefLoadHeap(Argument);
|
|
break;
|
|
|
|
case CLIENTDATA :
|
|
while (Argument && *Argument++);
|
|
i = ParseDefClientData(Argument, DefinitionKeywords[i]);
|
|
break;
|
|
|
|
case EXPORTS :
|
|
while (Argument && *Argument++);
|
|
i = ParseDefExports(pimage, Argument);
|
|
break;
|
|
|
|
case BADKEYWORD :
|
|
Fatal(DefFilename, BADDEFFILEKEYWORD, Argument);
|
|
break;
|
|
|
|
default :
|
|
// Ignore, but give a warning
|
|
Warning(DefFilename, IGNOREKEYWORD, DefinitionKeywords[i]);
|
|
i = SkipToNextKeyword();
|
|
// fall through
|
|
|
|
case PROTMODE :
|
|
case FUNCTIONS :
|
|
case INCLUDE :
|
|
// Ignore
|
|
i = SkipToNextKeyword();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// All done with the definition file.
|
|
|
|
fclose(DefStream);
|
|
}
|
|
|
|
|
|
DWORD
|
|
CsymCreateThunkSymbols(
|
|
PIMAGE pimage
|
|
)
|
|
{
|
|
PST pst;
|
|
LEXT *plextHead;
|
|
PEXTERNAL pext;
|
|
DWORD csym;
|
|
|
|
InternalError.Phase = "CsymCreateThunkSymbols";
|
|
|
|
pst = pimage->pst;
|
|
|
|
// Make a linked list of the exported symbols.
|
|
|
|
plextHead = NULL;
|
|
InitEnumerateExternals(pst);
|
|
while ((pext = PexternalEnumerateNext(pst)) != NULL) {
|
|
LEXT *plext;
|
|
|
|
if ((pext->Flags & EXTERN_DEFINED) == 0) {
|
|
continue;
|
|
}
|
|
|
|
if ((pext->Flags & EXTERN_PRIVATE) != 0) {
|
|
continue;
|
|
}
|
|
|
|
plext = (LEXT *) PvAlloc(sizeof(LEXT));
|
|
plext->pext = pext;
|
|
plext->plextNext = plextHead;
|
|
|
|
plextHead = plext;
|
|
}
|
|
TerminateEnumerateExternals(pst);
|
|
|
|
// Create an __imp_ symbol for each exported symbol
|
|
|
|
csym = 0;
|
|
|
|
while (plextHead != NULL) {
|
|
char *szExportName;
|
|
char *szIatName;
|
|
PEXTERNAL pextNew;
|
|
LEXT *plextNext;
|
|
|
|
pext = plextHead->pext;
|
|
|
|
plextNext = plextHead->plextNext;
|
|
FreePv(plextHead);
|
|
plextHead = plextNext;
|
|
|
|
szExportName = SzNamePext(pext, pst);
|
|
|
|
szIatName = (char *) PvAlloc(strlen(szExportName) + sizeof(szIATPrefix));
|
|
strcpy(szIatName, szIATPrefix);
|
|
strcat(szIatName, szExportName);
|
|
pextNew = LookupExternSz(pst, szIatName, NULL);
|
|
|
|
SetDefinedExt(pextNew, TRUE, pst);
|
|
pextNew->Flags |= EXTERN_IMPLIB_ONLY;
|
|
pextNew->FinalValue = 0;
|
|
pextNew->ArchiveMemberIndex = pext->ArchiveMemberIndex;
|
|
pextNew->pcon = pext->pcon;
|
|
csym++;
|
|
|
|
if (FExportProcPext(pext)) {
|
|
if (pimage->ImgFileHdr.Machine == IMAGE_FILE_MACHINE_POWERPC) {
|
|
char *szExtryName;
|
|
|
|
// Add an additional member for the entry point symbol
|
|
|
|
// Refresh pointer which may have been invalidated by insert
|
|
|
|
szExportName = SzNamePext(pext, pst);
|
|
|
|
szExtryName = (char *) PvAlloc(sizeof(PpcNamePrefix) + strlen(szExportName));
|
|
strcpy(szExtryName, PpcNamePrefix);
|
|
strcat(szExtryName, szExportName);
|
|
pextNew = LookupExternSz(pst, szExtryName, NULL);
|
|
|
|
SetDefinedExt(pextNew, TRUE, pst);
|
|
pextNew->Flags |= EXTERN_IMPLIB_ONLY;
|
|
pextNew->FinalValue = 0;
|
|
pextNew->ArchiveMemberIndex = pext->ArchiveMemberIndex;
|
|
pextNew->pcon = pext->pcon;
|
|
csym++;
|
|
}
|
|
}
|
|
}
|
|
|
|
return(csym);
|
|
}
|
|
|
|
|
|
void
|
|
IdentifyAssignedOrdinals (
|
|
PST pst
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Build flags so ordinal numbers can later be assigned.
|
|
|
|
Arguments:
|
|
|
|
pst - Pointer to external structure.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PPEXTERNAL rgpext;
|
|
DWORD cext;
|
|
DWORD iext;
|
|
|
|
InternalError.Phase = "IdentifyAssignedOrdinals";
|
|
|
|
rgpext = RgpexternalByName(pst);
|
|
cext = Cexternal(pst);
|
|
|
|
for (iext = 0; iext < cext; iext++) {
|
|
PEXTERNAL pext;
|
|
|
|
pext = rgpext[iext];
|
|
|
|
if (pext->Flags & EXTERN_DEFINED) {
|
|
DWORD li;
|
|
|
|
if ((li = pext->ImageSymbol.OrdinalNumber) != 0) {
|
|
// Ordinal was user defined.
|
|
|
|
li -= SmallestOrdinal;
|
|
|
|
if (rgfOrdinalAssigned[li]) {
|
|
Fatal(DefFilename, DUPLICATEORDINAL, li + SmallestOrdinal);
|
|
}
|
|
|
|
rgfOrdinalAssigned[li] = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
EmitLinkerMembers (
|
|
DWORD NumSymbolsCount,
|
|
PST pst
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Outputs the linker members to the library.
|
|
|
|
Arguments:
|
|
|
|
NumSymbolsCount - Number of symbols that will be in the linker member.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
LONG MachineIndependentInteger;
|
|
LONG lfa;
|
|
LONG li;
|
|
|
|
// Build standard linker member (sorted by offsets).
|
|
|
|
InternalError.Phase = "EmitLinkerMembers";
|
|
|
|
FileSeek(FileWriteHandle, sizeof(IMAGE_ARCHIVE_MEMBER_HEADER), SEEK_CUR);
|
|
MachineIndependentInteger = sputl(&NumSymbolsCount);
|
|
FileWrite(FileWriteHandle, &MachineIndependentInteger, sizeof(DWORD));
|
|
FileSeek(FileWriteHandle, NumSymbolsCount*sizeof(DWORD), SEEK_CUR);
|
|
EmitStrings(pst, FALSE);
|
|
lfa = FileTell(FileWriteHandle);
|
|
|
|
FileSeek(FileWriteHandle, IMAGE_ARCHIVE_START_SIZE, SEEK_SET);
|
|
WriteMemberHeader("", FALSE, timeCur, 0, lfa-sizeof(IMAGE_ARCHIVE_MEMBER_HEADER)-IMAGE_ARCHIVE_START_SIZE);
|
|
|
|
FileSeek(FileWriteHandle, lfa, SEEK_SET);
|
|
if (lfa & 1) {
|
|
FileWrite(FileWriteHandle, IMAGE_ARCHIVE_PAD, 1);
|
|
}
|
|
|
|
// Build new linker member (sorted by symbol name).
|
|
|
|
NewLinkerMember = FileTell(FileWriteHandle);
|
|
FileSeek(FileWriteHandle, sizeof(IMAGE_ARCHIVE_MEMBER_HEADER), SEEK_CUR);
|
|
|
|
// Write number of offsets.
|
|
|
|
li = (LONG) NextMember;
|
|
FileWrite(FileWriteHandle, &li, sizeof(DWORD));
|
|
|
|
// Save room for offsets.
|
|
|
|
FileSeek(FileWriteHandle, li*sizeof(DWORD), SEEK_CUR);
|
|
|
|
// Write number of symbols.
|
|
|
|
FileWrite(FileWriteHandle, &NumSymbolsCount, sizeof(DWORD));
|
|
|
|
// Save room for offset indexes.
|
|
|
|
FileSeek(FileWriteHandle, NumSymbolsCount*sizeof(WORD), SEEK_CUR);
|
|
|
|
// Write symbols (sorted).
|
|
|
|
EmitStrings(pst, TRUE);
|
|
lfa = FileTell(FileWriteHandle);
|
|
|
|
FileSeek(FileWriteHandle, NewLinkerMember, SEEK_SET);
|
|
WriteMemberHeader("", FALSE, timeCur, 0, lfa-NewLinkerMember-sizeof(IMAGE_ARCHIVE_MEMBER_HEADER));
|
|
|
|
FileSeek(FileWriteHandle, lfa, SEEK_SET);
|
|
if (lfa & 1) {
|
|
FileWrite(FileWriteHandle, IMAGE_ARCHIVE_PAD, 1);
|
|
}
|
|
|
|
// Emit long filename table.
|
|
|
|
li = cchDllName + strlen(pimageDeflib->Switch.Lib.DllExtension) + 1;
|
|
|
|
MemberName = (char *) PvAlloc(li);
|
|
strcpy(MemberName, pimageDeflib->Switch.Lib.DllName);
|
|
strcat(MemberName, pimageDeflib->Switch.Lib.DllExtension);
|
|
|
|
// Save the correct name so that it can be used for CodeView information
|
|
|
|
szCvMemberName = MemberName;
|
|
cchCvMemberName = (BYTE) strlen(szCvMemberName);
|
|
|
|
if (li > 16) {
|
|
IsMemberNameLongName = TRUE;
|
|
|
|
WriteMemberHeader("/", FALSE, timeCur, 0, li);
|
|
|
|
FileWrite(FileWriteHandle, MemberName, li);
|
|
if (li & 1) {
|
|
FileWrite(FileWriteHandle, IMAGE_ARCHIVE_PAD, 1);
|
|
}
|
|
|
|
MemberName = "0";
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
EmitImportDescriptor (
|
|
const THUNK_INFO *ThunkInfo,
|
|
PIMAGE pimage
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Outputs the Import descriptor table to the library.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
IMAGE_SECTION_HEADER sectionHdr;
|
|
IMAGE_SYMBOL sym;
|
|
IMAGE_RELOCATION reloc;
|
|
DWORD cbHeaders;
|
|
DWORD cbCvData;
|
|
DWORD cbRawData;
|
|
DWORD cbStringTable;
|
|
char *stringTable;
|
|
char *st;
|
|
WORD csection = 2;
|
|
WORD creloc = 3;
|
|
WORD csym = 7;
|
|
DWORD dllExtensionLen;
|
|
|
|
InternalError.Phase = "EmitImportDescriptor";
|
|
|
|
// Create long string table.
|
|
|
|
dllExtensionLen = strlen(pimage->Switch.Lib.DllExtension)+1; // include the NULL
|
|
|
|
cbStringTable = sizeof(DWORD) +
|
|
sizeof(szDescriptorPrefix) + cchDllName +
|
|
strlen(szNullThunkName) + 1 +
|
|
sizeof(szNullDescriptor);
|
|
|
|
stringTable = st = (char *) PvAlloc((size_t) cbStringTable);
|
|
*(DWORD *) stringTable = cbStringTable;
|
|
st += sizeof(DWORD);
|
|
|
|
cbCvData = 0;
|
|
|
|
if (pimage->Switch.Link.DebugType & CvDebug) {
|
|
csection++;
|
|
|
|
cbCvData = sizeof(CvSig) +
|
|
sizeof(CvObjName) + sizeof(BYTE) + cchCvMemberName +
|
|
sizeof(CvCompile) + sizeof(BYTE) + cchLinkVer;
|
|
}
|
|
|
|
cbHeaders = sizeof(IMAGE_FILE_HEADER) +
|
|
pimage->ImgFileHdr.SizeOfOptionalHeader +
|
|
(csection * sizeof(IMAGE_SECTION_HEADER));
|
|
|
|
cbRawData = cbCvData +
|
|
sizeof(IMAGE_IMPORT_DESCRIPTOR) +
|
|
EvenByteAlign(cchDllName + dllExtensionLen);
|
|
|
|
MemberStart[ARCHIVE + 0] = FileTell(FileWriteHandle);
|
|
WriteMemberHeader(MemberName,
|
|
IsMemberNameLongName,
|
|
timeCur,
|
|
0,
|
|
cbHeaders +
|
|
cbRawData +
|
|
(creloc * sizeof(IMAGE_RELOCATION)) +
|
|
(csym * sizeof(IMAGE_SYMBOL)) +
|
|
cbStringTable);
|
|
|
|
pimage->ImgFileHdr.NumberOfSections = csection;
|
|
pimage->ImgFileHdr.PointerToSymbolTable = cbHeaders + cbRawData + (sizeof(IMAGE_RELOCATION)*creloc);
|
|
pimage->ImgFileHdr.NumberOfSymbols = csym;
|
|
WriteFileHeader(FileWriteHandle, &pimage->ImgFileHdr);
|
|
|
|
// All fields of the optional header are zero (structure initialized such)
|
|
// and should be.
|
|
|
|
WriteOptionalHeader(FileWriteHandle, &pimage->ImgOptHdr, pimage->ImgFileHdr.SizeOfOptionalHeader);
|
|
|
|
// Don't generate anymore optional headers for this library.
|
|
|
|
pimage->ImgFileHdr.SizeOfOptionalHeader = 0;
|
|
|
|
if (pimage->Switch.Link.DebugType & CvDebug) {
|
|
sectionHdr = NullSectionHdr;
|
|
strncpy((char *) sectionHdr.Name, ReservedSection.CvSymbols.Name, IMAGE_SIZEOF_SHORT_NAME);
|
|
sectionHdr.SizeOfRawData = cbCvData;
|
|
sectionHdr.PointerToRawData = cbHeaders;
|
|
sectionHdr.Characteristics = ReservedSection.CvSymbols.Characteristics;
|
|
WriteSectionHeader(FileWriteHandle, §ionHdr);
|
|
}
|
|
|
|
// Write first section header.
|
|
|
|
sectionHdr = NullSectionHdr;
|
|
strncpy((char *) sectionHdr.Name, ReservedSection.ImportDescriptor.Name, IMAGE_SIZEOF_SHORT_NAME);
|
|
sectionHdr.SizeOfRawData = sizeof(IMAGE_IMPORT_DESCRIPTOR);
|
|
sectionHdr.PointerToRawData = cbHeaders + cbCvData;
|
|
sectionHdr.PointerToRelocations = sectionHdr.PointerToRawData + sectionHdr.SizeOfRawData;
|
|
sectionHdr.NumberOfRelocations = 3;
|
|
sectionHdr.Characteristics = ReservedSection.ImportDescriptor.Characteristics;
|
|
WriteSectionHeader(FileWriteHandle, §ionHdr);
|
|
|
|
// Write second section header.
|
|
|
|
strncpy((char *) sectionHdr.Name, DataSectionName, IMAGE_SIZEOF_SHORT_NAME);
|
|
sectionHdr.PointerToRawData += sectionHdr.SizeOfRawData +
|
|
(sizeof(IMAGE_RELOCATION) * (DWORD) sectionHdr.NumberOfRelocations);
|
|
sectionHdr.SizeOfRawData = EvenByteAlign(cchDllName + dllExtensionLen);
|
|
sectionHdr.NumberOfRelocations = 0;
|
|
sectionHdr.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_ALIGN_2BYTES;
|
|
WriteSectionHeader(FileWriteHandle, §ionHdr);
|
|
|
|
if (pimage->Switch.Link.DebugType & CvDebug) {
|
|
// Write the .debug$S section
|
|
|
|
FileWrite(FileWriteHandle, &CvSig, sizeof(CvSig));
|
|
|
|
FileWrite(FileWriteHandle, &CvObjName, sizeof(CvObjName));
|
|
FileWrite(FileWriteHandle, &cchCvMemberName, sizeof(BYTE));
|
|
FileWrite(FileWriteHandle, szCvMemberName, (DWORD) cchCvMemberName);
|
|
|
|
FileWrite(FileWriteHandle, &CvCompile, sizeof(CvCompile));
|
|
FileWrite(FileWriteHandle, &cchLinkVer, sizeof(BYTE));
|
|
FileWrite(FileWriteHandle, szLinkVer, (DWORD) cchLinkVer);
|
|
}
|
|
|
|
// Write the raw data for section 1 (Import descriptor data).
|
|
|
|
FileWrite(FileWriteHandle, &NullImportDescriptor, sizeof(IMAGE_IMPORT_DESCRIPTOR));
|
|
|
|
// Write the relocation for section 1 (Import descriptor).
|
|
|
|
// Fixup to the Dll Name.
|
|
|
|
reloc.VirtualAddress = offsetof(IMAGE_IMPORT_DESCRIPTOR, Name);
|
|
reloc.SymbolTableIndex = 2;
|
|
reloc.Type = ThunkInfo->ImportReloc;
|
|
WriteRelocations(FileWriteHandle, &reloc, 1);
|
|
|
|
// Fixup to the first INT.
|
|
|
|
reloc.VirtualAddress = offsetof(IMAGE_IMPORT_DESCRIPTOR, Characteristics);
|
|
reloc.SymbolTableIndex++;
|
|
WriteRelocations(FileWriteHandle, &reloc, 1);
|
|
|
|
// Fixup to the first IAT.
|
|
|
|
reloc.VirtualAddress = offsetof(IMAGE_IMPORT_DESCRIPTOR, FirstThunk);
|
|
reloc.SymbolTableIndex++;
|
|
WriteRelocations(FileWriteHandle, &reloc, 1);
|
|
|
|
// Write the raw data for section 2 (DLL name).
|
|
|
|
FileWrite(FileWriteHandle, pimage->Switch.Lib.DllName, (DWORD) cchDllName);
|
|
FileWrite(FileWriteHandle, pimage->Switch.Lib.DllExtension, dllExtensionLen);
|
|
if ((DWORD) cchDllName+dllExtensionLen != sectionHdr.SizeOfRawData) {
|
|
FileWrite(FileWriteHandle, "\0", sizeof(BYTE));
|
|
}
|
|
|
|
// Write the symbol table.
|
|
|
|
// Write the Import descriptor symbol.
|
|
|
|
sym = NullSymbol;
|
|
sym.n_offset = st - stringTable;
|
|
strcpy(st, szDescriptorPrefix);
|
|
strcat(st, pimage->Switch.Lib.DllName);
|
|
st += sizeof(szDescriptorPrefix) + cchDllName;
|
|
sym.SectionNumber = csection - 1;
|
|
sym.StorageClass = IMAGE_SYM_CLASS_EXTERNAL;
|
|
FileWrite(FileWriteHandle, &sym, sizeof(IMAGE_SYMBOL));
|
|
|
|
// Write the Import descriptor section name symbol.
|
|
|
|
sym = NullSymbol;
|
|
strncpy((char *) sym.n_name, ReservedSection.ImportDescriptor.Name, IMAGE_SIZEOF_SHORT_NAME);
|
|
sym.Value = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE;
|
|
sym.SectionNumber = csection - 1;
|
|
sym.StorageClass = IMAGE_SYM_CLASS_SECTION;
|
|
FileWrite(FileWriteHandle, &sym, sizeof(IMAGE_SYMBOL));
|
|
|
|
// Write the dll name symbol.
|
|
|
|
sym = NullSymbol;
|
|
strncpy((char *) sym.n_name, DataSectionName, IMAGE_SIZEOF_SHORT_NAME);
|
|
sym.SectionNumber = csection;
|
|
sym.StorageClass = IMAGE_SYM_CLASS_STATIC;
|
|
FileWrite(FileWriteHandle, &sym, sizeof(IMAGE_SYMBOL));
|
|
|
|
// Write the INT section name symbol.
|
|
|
|
sym = NullSymbol;
|
|
strncpy((char *) sym.n_name, INT_SectionName, IMAGE_SIZEOF_SHORT_NAME);
|
|
sym.Value = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE;;
|
|
sym.SectionNumber = IMAGE_SYM_UNDEFINED;
|
|
sym.StorageClass = IMAGE_SYM_CLASS_SECTION;
|
|
FileWrite(FileWriteHandle, &sym, sizeof(IMAGE_SYMBOL));
|
|
|
|
// Write the IAT section name symbol.
|
|
|
|
strncpy((char *) sym.n_name, IAT_SectionName, IMAGE_SIZEOF_SHORT_NAME);
|
|
FileWrite(FileWriteHandle, &sym, sizeof(IMAGE_SYMBOL));
|
|
|
|
// Write the Null descriptor symbol.
|
|
|
|
sym = NullSymbol;
|
|
sym.n_offset = st - stringTable;
|
|
strcpy(st, szNullDescriptor);
|
|
st += sizeof(szNullDescriptor);
|
|
sym.SectionNumber = IMAGE_SYM_UNDEFINED;
|
|
sym.StorageClass = IMAGE_SYM_CLASS_EXTERNAL;
|
|
FileWrite(FileWriteHandle, &sym, sizeof(IMAGE_SYMBOL));
|
|
|
|
// Write the Null thunk.
|
|
|
|
sym = NullSymbol;
|
|
sym.n_offset = st - stringTable;
|
|
strcpy(st, szNullThunkName);
|
|
st += strlen(szNullThunkName) + 1;
|
|
sym.SectionNumber = IMAGE_SYM_UNDEFINED;
|
|
sym.StorageClass = IMAGE_SYM_CLASS_EXTERNAL;
|
|
FileWrite(FileWriteHandle, &sym, sizeof(IMAGE_SYMBOL));
|
|
|
|
// Write the string table.
|
|
|
|
FileWrite(FileWriteHandle, stringTable, cbStringTable);
|
|
FreePv(stringTable);
|
|
|
|
if (FileTell(FileWriteHandle) & 1) {
|
|
FileWrite(FileWriteHandle, IMAGE_ARCHIVE_PAD, 1);
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
EmitNullImportDescriptor (
|
|
PIMAGE pimage
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Outputs a Null Import descriptor.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD cbStringTable;
|
|
char *stringTable;
|
|
char *st;
|
|
WORD csection;
|
|
DWORD cbCvData;
|
|
DWORD cbHeaders;
|
|
DWORD cbRawData;
|
|
IMAGE_SECTION_HEADER sectionHdr;
|
|
IMAGE_SYMBOL sym;
|
|
|
|
InternalError.Phase = "EmitNullImportDescriptor";
|
|
|
|
// Create long string table.
|
|
|
|
cbStringTable = sizeof(DWORD) + sizeof(szNullDescriptor);
|
|
|
|
stringTable = st = (char *) PvAlloc((size_t) cbStringTable);
|
|
*(DWORD *) stringTable = cbStringTable;
|
|
st += sizeof(DWORD);
|
|
|
|
csection = 1;
|
|
cbCvData = 0;
|
|
|
|
if (pimage->Switch.Link.DebugType & CvDebug) {
|
|
csection++;
|
|
|
|
cbCvData = sizeof(CvSig) +
|
|
sizeof(CvObjName) + sizeof(BYTE) + cchCvMemberName +
|
|
sizeof(CvCompile) + sizeof(BYTE) + cchLinkVer;
|
|
}
|
|
|
|
cbHeaders = sizeof(IMAGE_FILE_HEADER) + (csection * sizeof(IMAGE_SECTION_HEADER));
|
|
|
|
cbRawData = cbCvData + sizeof(IMAGE_IMPORT_DESCRIPTOR);
|
|
|
|
MemberStart[ARCHIVE + 1] = FileTell(FileWriteHandle);
|
|
WriteMemberHeader(MemberName,
|
|
IsMemberNameLongName,
|
|
timeCur,
|
|
0,
|
|
cbHeaders +
|
|
cbRawData +
|
|
sizeof(IMAGE_SYMBOL) +
|
|
cbStringTable);
|
|
|
|
pimage->ImgFileHdr.NumberOfSections = csection;
|
|
pimage->ImgFileHdr.PointerToSymbolTable = cbHeaders + cbRawData;
|
|
pimage->ImgFileHdr.NumberOfSymbols = 1;
|
|
WriteFileHeader(FileWriteHandle, &pimage->ImgFileHdr);
|
|
|
|
if (pimage->Switch.Link.DebugType & CvDebug) {
|
|
sectionHdr = NullSectionHdr;
|
|
strncpy((char *) sectionHdr.Name, ReservedSection.CvSymbols.Name, IMAGE_SIZEOF_SHORT_NAME);
|
|
sectionHdr.SizeOfRawData = cbCvData;
|
|
sectionHdr.PointerToRawData = cbHeaders;
|
|
sectionHdr.Characteristics = ReservedSection.CvSymbols.Characteristics;
|
|
WriteSectionHeader(FileWriteHandle, §ionHdr);
|
|
}
|
|
|
|
sectionHdr = NullSectionHdr;
|
|
strncpy((char *) sectionHdr.Name, NullDescriptorSectionName, IMAGE_SIZEOF_SHORT_NAME);
|
|
sectionHdr.SizeOfRawData = sizeof(IMAGE_IMPORT_DESCRIPTOR);
|
|
sectionHdr.PointerToRawData = cbHeaders + cbCvData;
|
|
sectionHdr.Characteristics = ReservedSection.ImportDescriptor.Characteristics;
|
|
WriteSectionHeader(FileWriteHandle, §ionHdr);
|
|
|
|
// Write the data for all sections
|
|
|
|
if (pimage->Switch.Link.DebugType & CvDebug) {
|
|
// Write the .debug$S section
|
|
|
|
FileWrite(FileWriteHandle, &CvSig, sizeof(CvSig));
|
|
|
|
FileWrite(FileWriteHandle, &CvObjName, sizeof(CvObjName));
|
|
FileWrite(FileWriteHandle, &cchCvMemberName, sizeof(BYTE));
|
|
FileWrite(FileWriteHandle, szCvMemberName, (DWORD) cchCvMemberName);
|
|
|
|
FileWrite(FileWriteHandle, &CvCompile, sizeof(CvCompile));
|
|
FileWrite(FileWriteHandle, &cchLinkVer, sizeof(BYTE));
|
|
FileWrite(FileWriteHandle, szLinkVer, (DWORD) cchLinkVer);
|
|
}
|
|
|
|
FileWrite(FileWriteHandle, &NullImportDescriptor, sizeof(IMAGE_IMPORT_DESCRIPTOR));
|
|
|
|
// Write the Import descriptor symbol.
|
|
|
|
sym = NullSymbol;
|
|
sym.n_offset = st - stringTable;
|
|
strcpy(st, szNullDescriptor);
|
|
st += sizeof(szNullDescriptor);
|
|
sym.SectionNumber = csection;
|
|
sym.StorageClass = IMAGE_SYM_CLASS_EXTERNAL;
|
|
FileWrite(FileWriteHandle, &sym, sizeof(IMAGE_SYMBOL));
|
|
|
|
// Write the string table.
|
|
|
|
FileWrite(FileWriteHandle, stringTable, cbStringTable);
|
|
FreePv(stringTable);
|
|
|
|
if (FileTell(FileWriteHandle) & 1) {
|
|
FileWrite(FileWriteHandle, IMAGE_ARCHIVE_PAD, 1);
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
EmitNullThunkData (
|
|
PIMAGE pimage
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Outputs a Null Thunk.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
BYTE *zero;
|
|
DWORD cbStringTable;
|
|
char *stringTable;
|
|
char *st;
|
|
WORD csection;
|
|
DWORD cbCvData;
|
|
DWORD cbHeaders;
|
|
DWORD cbRawData;
|
|
IMAGE_SECTION_HEADER sectionHdr;
|
|
IMAGE_SYMBOL sym;
|
|
|
|
InternalError.Phase = "EmitNullThunkData";
|
|
|
|
zero = (BYTE *) PvAllocZ(sizeof(IMAGE_THUNK_DATA));
|
|
|
|
// Create long string table.
|
|
|
|
cbStringTable = sizeof(DWORD) + strlen(szNullThunkName) + 1;
|
|
|
|
stringTable = st = (char *) PvAlloc((size_t) cbStringTable);
|
|
*(DWORD *) stringTable = cbStringTable;
|
|
st += sizeof(DWORD);
|
|
|
|
csection = 2;
|
|
cbCvData = 0;
|
|
|
|
if (pimage->Switch.Link.DebugType & CvDebug) {
|
|
csection++;
|
|
|
|
cbCvData = sizeof(CvSig) +
|
|
sizeof(CvObjName) + sizeof(BYTE) + cchCvMemberName +
|
|
sizeof(CvCompile) + sizeof(BYTE) + cchLinkVer;
|
|
}
|
|
|
|
cbHeaders = sizeof(IMAGE_FILE_HEADER) + (csection * sizeof(IMAGE_SECTION_HEADER));
|
|
|
|
cbRawData = cbCvData + (2 * sizeof(IMAGE_THUNK_DATA));
|
|
|
|
MemberStart[ARCHIVE + 2] = FileTell(FileWriteHandle);
|
|
WriteMemberHeader(MemberName,
|
|
IsMemberNameLongName,
|
|
timeCur,
|
|
0,
|
|
cbHeaders +
|
|
cbRawData +
|
|
sizeof(IMAGE_SYMBOL) +
|
|
cbStringTable);
|
|
|
|
pimage->ImgFileHdr.NumberOfSections = csection;
|
|
pimage->ImgFileHdr.PointerToSymbolTable = cbHeaders + cbRawData;
|
|
pimage->ImgFileHdr.NumberOfSymbols = 1;
|
|
WriteFileHeader(FileWriteHandle, &pimage->ImgFileHdr);
|
|
|
|
// Force NULL data to end of all other thunk data for this dll by
|
|
// setting name to a higher search order.
|
|
|
|
if (pimage->Switch.Link.DebugType & CvDebug) {
|
|
sectionHdr = NullSectionHdr;
|
|
strncpy((char *) sectionHdr.Name, ReservedSection.CvSymbols.Name, IMAGE_SIZEOF_SHORT_NAME);
|
|
sectionHdr.SizeOfRawData = cbCvData;
|
|
sectionHdr.PointerToRawData = cbHeaders;
|
|
sectionHdr.Characteristics = ReservedSection.CvSymbols.Characteristics;
|
|
WriteSectionHeader(FileWriteHandle, §ionHdr);
|
|
}
|
|
|
|
// Write section header 1.
|
|
|
|
sectionHdr = NullSectionHdr;
|
|
strncpy((char *) sectionHdr.Name, IAT_SectionName, IMAGE_SIZEOF_SHORT_NAME);
|
|
sectionHdr.SizeOfRawData = sizeof(IMAGE_THUNK_DATA);
|
|
sectionHdr.PointerToRawData = cbHeaders + cbCvData;
|
|
sectionHdr.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_ALIGN_4BYTES;
|
|
WriteSectionHeader(FileWriteHandle, §ionHdr);
|
|
|
|
// Write section header 2.
|
|
|
|
strncpy((char *) sectionHdr.Name, INT_SectionName, IMAGE_SIZEOF_SHORT_NAME);
|
|
sectionHdr.PointerToRawData += sizeof(IMAGE_THUNK_DATA);
|
|
WriteSectionHeader(FileWriteHandle, §ionHdr);
|
|
|
|
if (pimage->Switch.Link.DebugType & CvDebug) {
|
|
// Write the .debug$S section
|
|
|
|
FileWrite(FileWriteHandle, &CvSig, sizeof(CvSig));
|
|
|
|
FileWrite(FileWriteHandle, &CvObjName, sizeof(CvObjName));
|
|
FileWrite(FileWriteHandle, &cchCvMemberName, sizeof(BYTE));
|
|
FileWrite(FileWriteHandle, szCvMemberName, (DWORD) cchCvMemberName);
|
|
|
|
FileWrite(FileWriteHandle, &CvCompile, sizeof(CvCompile));
|
|
FileWrite(FileWriteHandle, &cchLinkVer, sizeof(BYTE));
|
|
FileWrite(FileWriteHandle, szLinkVer, (DWORD) cchLinkVer);
|
|
}
|
|
|
|
// Write the raw data for section 1 (null thunk).
|
|
|
|
FileWrite(FileWriteHandle, zero, sizeof(IMAGE_THUNK_DATA));
|
|
|
|
// Write the raw data for section 2 (null thunk).
|
|
|
|
FileWrite(FileWriteHandle, zero, sizeof(IMAGE_THUNK_DATA));
|
|
|
|
// Write the Null Thunk symbol.
|
|
|
|
sym = NullSymbol;
|
|
sym.n_offset = st - stringTable;
|
|
strcpy(st, szNullThunkName);
|
|
sym.SectionNumber = csection - 1;
|
|
sym.StorageClass = IMAGE_SYM_CLASS_EXTERNAL;
|
|
FileWrite(FileWriteHandle, &sym, sizeof(IMAGE_SYMBOL));
|
|
|
|
// Write the string table.
|
|
|
|
FileWrite(FileWriteHandle, stringTable, cbStringTable);
|
|
FreePv(stringTable);
|
|
|
|
if (FileTell(FileWriteHandle) & 1) {
|
|
FileWrite(FileWriteHandle, IMAGE_ARCHIVE_PAD, 1);
|
|
}
|
|
|
|
FreePv(zero);
|
|
}
|
|
|
|
|
|
void
|
|
BuildRawDataFromExternTable (
|
|
PST pst, // symbol table for name lookup
|
|
BLK *pblkRawData, // raw data block (growable at end)
|
|
DWORD *pibNameOffset, // current location in name pointer array
|
|
DWORD *pibOrdinalOffset // current location in ordinal array
|
|
)
|
|
// For each external symbol, appends the symbol name to StringTable.
|
|
{
|
|
PPEXTERNAL rgpext;
|
|
DWORD cext;
|
|
DWORD iext;
|
|
|
|
InternalError.Phase = "BuildRawDataFromExternTable";
|
|
|
|
rgpext = RgpexternalByName(pst);
|
|
cext = Cexternal(pst);
|
|
|
|
for (iext = 0; iext < cext; iext++) {
|
|
PEXTERNAL pext;
|
|
|
|
pext = rgpext[iext];
|
|
|
|
if (pext->Flags & EXTERN_DEFINED &&
|
|
!(pext->Flags & EXTERN_IMPLIB_ONLY))
|
|
{
|
|
DWORD Ordinal;
|
|
|
|
if (pext->ImageSymbol.OrdinalNumber != 0) {
|
|
// Use user assigned ordinal.
|
|
|
|
Ordinal = pext->ImageSymbol.OrdinalNumber - SmallestOrdinal;
|
|
|
|
pext->ImageSymbol.OrdinalNumber |= IMAGE_ORDINAL_FLAG;
|
|
} else {
|
|
|
|
// Find a free ordinal to assign.
|
|
|
|
Ordinal = 0;
|
|
|
|
while (rgfOrdinalAssigned[Ordinal]) {
|
|
Ordinal++;
|
|
}
|
|
|
|
rgfOrdinalAssigned[Ordinal] = TRUE;
|
|
|
|
pext->ImageSymbol.OrdinalNumber = Ordinal + SmallestOrdinal;
|
|
}
|
|
|
|
if ((pext->Flags & EXTERN_EXP_NONAME) == 0) {
|
|
char *szName;
|
|
|
|
szName = (char *) SzNamePext(pext, pst);
|
|
|
|
if (pimageDeflib->ImgFileHdr.Machine != IMAGE_FILE_MACHINE_MPPC_601) {
|
|
if (PrependUnderscore &&
|
|
(szName[0] != '?') &&
|
|
(szName[0] != '@')) {
|
|
szName++;
|
|
}
|
|
|
|
if ((pext->Flags & EXTERN_FUZZYMATCH)) {
|
|
char *p;
|
|
|
|
if ((szName[0] == '?') ||
|
|
(szName[0] == '@') ||
|
|
(SkipUnderscore && (szName[0] == '_'))) {
|
|
szName++;
|
|
}
|
|
|
|
szName = SzDup(szName);
|
|
|
|
if ((p = strchr(szName, '@')) != NULL) {
|
|
*p = '\0';
|
|
}
|
|
}
|
|
}
|
|
|
|
*(DWORD *) &pblkRawData->pb[*pibNameOffset] = pblkRawData->cb;
|
|
*pibNameOffset += sizeof(DWORD);
|
|
|
|
if ((pimageDeflib->ImgFileHdr.Machine == IMAGE_FILE_MACHINE_MPPC_601) &&
|
|
(pext->szOtherName != NULL)) {
|
|
|
|
// When a PowerMac export is aliased, the .ppcldr section should
|
|
// contain the alias. However, when linking the DLL, the internal
|
|
// name is needed to identify the actual export. Unlike Win32,
|
|
// there are no relocations in .EXP object to identify the internal
|
|
// name. So include both the names in the .ppcshl section with the internal
|
|
// name followed by "!" followed by the alias. Another point to note is that
|
|
// both the internal and aliased names in the .ppcshl section are decorated
|
|
// in the case of PowerMac.
|
|
|
|
IbAppendBlk(pblkRawData, pext->szOtherName, strlen(pext->szOtherName));
|
|
IbAppendBlk(pblkRawData, "!", 1);
|
|
}
|
|
|
|
IbAppendBlk(pblkRawData, szName, strlen(szName) + 1);
|
|
|
|
if ((pimageDeflib->ImgFileHdr.Machine != IMAGE_FILE_MACHINE_MPPC_601) &&
|
|
(pext->Flags & EXTERN_FUZZYMATCH)) {
|
|
FreePv(szName);
|
|
}
|
|
|
|
*(WORD *) &pblkRawData->pb[*pibOrdinalOffset] = (WORD) Ordinal;
|
|
*pibOrdinalOffset += sizeof(WORD);
|
|
}
|
|
|
|
if (pext->Flags & EXTERN_FORWARDER) {
|
|
pext->FinalValue = IbAppendBlk(pblkRawData,
|
|
pext->szOtherName,
|
|
strlen(pext->szOtherName) + 1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
ReSortExportNamePtrs (
|
|
BYTE *RawData,
|
|
DWORD ibNameOffset,
|
|
DWORD ibOrdinalOffset,
|
|
DWORD NumNames
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Walks the export name ptr table making sure everythings sorted correctly.
|
|
Symbols that are sorted in the symbol table may be come unsorted when
|
|
the decorated name is removed.
|
|
|
|
Arguments:
|
|
|
|
RawData - Pointer to buffer that sortes the name ptrs and name strings.
|
|
|
|
NamePtr - Pointer to exports name ptr table.
|
|
|
|
NameOrdinalPtr - Pointer to exports name ordinal ptr table.
|
|
|
|
NumNames - The number of pointers in table.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
WORD ts;
|
|
DWORD i, j, tl;
|
|
DWORD *NamePtr = (DWORD *) (RawData + ibNameOffset);
|
|
WORD *NameOrdinalPtr = (WORD *) (RawData + ibOrdinalOffset);
|
|
|
|
InternalError.Phase = "ReSortExportNamePtrs";
|
|
|
|
for (i = 0; i+1 < NumNames; i++) {
|
|
for (j = i+1; j < NumNames; j++) {
|
|
if (strcmp((const char *)(RawData + NamePtr[j]), (const char *)(RawData + NamePtr[i])) < 0) {
|
|
tl = NamePtr[i];
|
|
NamePtr[i] = NamePtr[j];
|
|
NamePtr[j] = tl;
|
|
|
|
ts = NameOrdinalPtr[i];
|
|
NameOrdinalPtr[i] = NameOrdinalPtr[j];
|
|
NameOrdinalPtr[j] = ts;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
BuildOrdinalToHintMap (
|
|
BYTE *RawData,
|
|
DWORD ibNameOrdinalPtr,
|
|
DWORD NumNames
|
|
)
|
|
{
|
|
DWORD i;
|
|
WORD *NameOrdinalPtr = (WORD *) (RawData + ibNameOrdinalPtr);
|
|
|
|
for (i = 0; i < NumNames; i++) {
|
|
rgwHint[NameOrdinalPtr[i]] = (WORD) i;
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
AddInternalNamesToStringTable (
|
|
PST pst)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Makes sure all internal names are in the string table.
|
|
|
|
Arguments:
|
|
|
|
pst - Pointer to external structure.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PPEXTERNAL rgpext;
|
|
DWORD cext;
|
|
DWORD iext;
|
|
|
|
InternalError.Phase = "AddInternalNamesToStringTable";
|
|
|
|
rgpext = RgpexternalByName(pst);
|
|
cext = Cexternal(pst);
|
|
|
|
for (iext = 0; iext < cext; iext++) {
|
|
PEXTERNAL pext;
|
|
|
|
pext = rgpext[iext];
|
|
|
|
if (pext->Flags & EXTERN_DEFINED &&
|
|
!(pext->Flags & EXTERN_EMITTED)) {
|
|
|
|
if (pext->szOtherName && !(pext->Flags & EXTERN_FORWARDER)) {
|
|
if (strlen(pext->szOtherName) > IMAGE_SIZEOF_SHORT_NAME) {
|
|
// Add the internal name to the string table.
|
|
|
|
LookupLongName(pst, pext->szOtherName);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
EmitExportDataFixups (
|
|
INT ExpFileHandle,
|
|
PST pst,
|
|
DWORD EAT_Addr,
|
|
DWORD ibNamePtr,
|
|
WORD RelocType
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Emits the fixups for the Export Address Table and the Name Ptr Table.
|
|
|
|
Arguments:
|
|
|
|
pst - pointer to external structure
|
|
|
|
EAT_Addr - Offset of Export Address Table.
|
|
|
|
ibNamePtr - Offset of the Name Table Pointers.
|
|
|
|
RelocType - Relocation type needed for the fixups.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PPEXTERNAL rgpext;
|
|
DWORD cext;
|
|
DWORD iext;
|
|
WORD NextSymIndex = 1;
|
|
|
|
InternalError.Phase = "EmitExportDataFixups";
|
|
|
|
rgpext = RgpexternalByName(pst);
|
|
cext = Cexternal(pst);
|
|
|
|
for (iext = 0; iext < cext; iext++) {
|
|
PEXTERNAL pext;
|
|
|
|
pext = rgpext[iext];
|
|
|
|
if (pext->Flags & EXTERN_IMPLIB_ONLY) {
|
|
continue;
|
|
}
|
|
|
|
if (pext->Flags & EXTERN_DEFINED) {
|
|
IMAGE_RELOCATION reloc;
|
|
|
|
// Relocation for function address.
|
|
|
|
reloc.VirtualAddress = EAT_Addr +
|
|
(IMAGE_ORDINAL(pext->ImageSymbol.OrdinalNumber) - SmallestOrdinal) * sizeof(DWORD);
|
|
reloc.SymbolTableIndex = NextSymIndex++;
|
|
reloc.Type = RelocType;
|
|
WriteRelocations(ExpFileHandle, &reloc, 1);
|
|
|
|
if ((pext->Flags & EXTERN_EXP_NONAME) == 0) {
|
|
// Relocation for function name.
|
|
|
|
reloc.VirtualAddress = ibNamePtr;
|
|
reloc.SymbolTableIndex = 0;
|
|
reloc.Type = RelocType;
|
|
WriteRelocations(ExpFileHandle, &reloc, 1);
|
|
|
|
ibNamePtr += sizeof(DWORD);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
EmitDefLibExternals (
|
|
INT ExpFileHandle,
|
|
PST pst)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Writes the defined external symbols to the image file.
|
|
|
|
Arguments:
|
|
|
|
pst - Pointer to external structure.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PPEXTERNAL rgpext;
|
|
DWORD cext;
|
|
DWORD iext;
|
|
|
|
InternalError.Phase = "EmitDefLibExternals";
|
|
|
|
rgpext = RgpexternalByName(pst);
|
|
cext = Cexternal(pst);
|
|
|
|
for (iext = 0; iext < cext; iext++) {
|
|
PEXTERNAL pext;
|
|
IMAGE_SYMBOL sym;
|
|
|
|
pext = rgpext[iext];
|
|
|
|
if (pext->Flags & EXTERN_IMPLIB_ONLY) {
|
|
continue;
|
|
}
|
|
|
|
if (pext->Flags & EXTERN_EMITTED) {
|
|
continue;
|
|
}
|
|
|
|
if ((pext->Flags & EXTERN_DEFINED) == 0) {
|
|
continue;
|
|
}
|
|
|
|
// Use the internal name if one was specified. For forwarders, the
|
|
// symbol name is the forwarded symbol. This is just out of kindness.
|
|
// The name doesn't mean anything since the symbol is static.
|
|
|
|
sym = pext->ImageSymbol;
|
|
|
|
if (pext->szOtherName && ((pext->Flags & EXTERN_FORWARDER) == 0)) {
|
|
if (strlen(pext->szOtherName) > IMAGE_SIZEOF_SHORT_NAME) {
|
|
// Internal name should already be in the string table.
|
|
|
|
sym.n_zeroes = 0;
|
|
sym.n_offset = LookupLongName(pst, pext->szOtherName);
|
|
} else {
|
|
strncpy((char *) sym.n_name, pext->szOtherName, IMAGE_SIZEOF_SHORT_NAME);
|
|
}
|
|
} else if (IsLongName(sym)) {
|
|
sym.n_zeroes = 0;
|
|
}
|
|
|
|
sym.Value = pext->FinalValue;
|
|
|
|
if (pext->Flags & EXTERN_FORWARDER) {
|
|
// Section 1 is the section number of the .edata section. The
|
|
// FinalValue is the offset into this section of the forwarder
|
|
// string. This was set in BuildRawDataFromExternTable.
|
|
|
|
sym.SectionNumber = 1;
|
|
sym.StorageClass = IMAGE_SYM_CLASS_STATIC;
|
|
} else {
|
|
if (pext->pcon != NULL) {
|
|
sym.SectionNumber = PsecPCON(pext->pcon)->isec;
|
|
}
|
|
}
|
|
|
|
sym.Type = IMAGE_SYM_TYPE_NULL;
|
|
sym.NumberOfAuxSymbols = 0;
|
|
|
|
WriteSymbolTableEntry(ExpFileHandle, &sym);
|
|
|
|
pext->Flags |= EXTERN_EMITTED;
|
|
|
|
csymDebug++;
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
EmitDllExportDirectory (
|
|
PIMAGE pimage,
|
|
DWORD NumberOfEntriesInEAT,
|
|
DWORD NumberOfFunctions,
|
|
DWORD NumberOfNoNameExports,
|
|
const THUNK_INFO *ThunkInfo,
|
|
BOOL fPass1
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Outputs the DLL export section to the library.
|
|
Also outputs a section for the def file description if there is one.
|
|
|
|
Arguments:
|
|
|
|
NumberOfEntriesInEAT - The number of entries for the Export Address Table.
|
|
|
|
NumberOfFunctions - The number of functions that will be in the export table.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
INT ExpFileHandle;
|
|
PST pst;
|
|
DWORD NumberOfNames;
|
|
BOOL fNoEdata;
|
|
WORD csection;
|
|
WORD creloc;
|
|
WORD csym;
|
|
BLK blkEdata;
|
|
DWORD ibAddressOfFunctions;
|
|
DWORD ibAddressOfNames;
|
|
DWORD ibNextNamePtr;
|
|
DWORD ibAddressOfNameOrdinals;
|
|
DWORD ibNextOrdinalPtr;
|
|
DWORD ibName;
|
|
DWORD cbEdata;
|
|
BYTE cchExportFilename;
|
|
DWORD cbCvData;
|
|
DWORD cchDescription;
|
|
DWORD cbDescription;
|
|
DWORD cbDirectives;
|
|
DWORD cbPpcShl;
|
|
DWORD cbHeaders;
|
|
DWORD cbRawData;
|
|
DWORD foCur;
|
|
DWORD foPpcShl;
|
|
IMAGE_SECTION_HEADER sectionHdr;
|
|
IMAGE_RELOCATION reloc;
|
|
IMAGE_SYMBOL sym;
|
|
|
|
InternalError.Phase = "EmitDllExportDirectory";
|
|
|
|
ExpFileHandle = FileOpen(szExportFilename, O_RDWR | O_BINARY | O_CREAT | O_TRUNC, S_IREAD | S_IWRITE);
|
|
|
|
pst = pimage->pst;
|
|
|
|
NumberOfNames = NumberOfFunctions - NumberOfNoNameExports;
|
|
|
|
fNoEdata = (pimage->ImgFileHdr.Machine == IMAGE_FILE_MACHINE_MPPC_601) ||
|
|
(pimage->imaget == imagetVXD);
|
|
|
|
if (fNoEdata) {
|
|
csection = 0;
|
|
creloc = 0;
|
|
csym = 0;
|
|
} else {
|
|
csection = 1;
|
|
creloc = (WORD) (4 + NumberOfFunctions + NumberOfNames);
|
|
csym = 1;
|
|
}
|
|
|
|
if (pimage->imaget != imagetVXD) {
|
|
csym += (WORD) NumberOfFunctions;
|
|
}
|
|
|
|
InitBlk(&blkEdata);
|
|
|
|
IbAppendBlkZ(&blkEdata, sizeof(IMAGE_EXPORT_DIRECTORY));
|
|
|
|
// Save space for Export Address Table.
|
|
|
|
ibAddressOfFunctions =
|
|
IbAppendBlkZ(&blkEdata, NumberOfEntriesInEAT * sizeof(DWORD));
|
|
|
|
// Save space for Name Pointers.
|
|
|
|
ibAddressOfNames =
|
|
IbAppendBlkZ(&blkEdata, NumberOfNames * sizeof(DWORD));
|
|
ibNextNamePtr = ibAddressOfNames;
|
|
|
|
// Save space for parallel Ordinal Table.
|
|
|
|
ibAddressOfNameOrdinals =
|
|
IbAppendBlkZ(&blkEdata, NumberOfNames * sizeof(WORD));
|
|
ibNextOrdinalPtr = ibAddressOfNameOrdinals;
|
|
|
|
// Store the export DLL name pointer.
|
|
|
|
ibName = IbAppendBlk(&blkEdata, pimage->Switch.Lib.DllName,
|
|
strlen(pimage->Switch.Lib.DllName));
|
|
|
|
// Store the extension
|
|
|
|
IbAppendBlk(&blkEdata, pimage->Switch.Lib.DllExtension,
|
|
strlen(pimage->Switch.Lib.DllExtension) + 1);
|
|
|
|
// Store the function names into the raw data.
|
|
|
|
BuildRawDataFromExternTable(pst, &blkEdata, &ibNextNamePtr,
|
|
&ibNextOrdinalPtr);
|
|
|
|
if (fPass1) {
|
|
ReSortExportNamePtrs(blkEdata.pb, ibAddressOfNames, ibAddressOfNameOrdinals,
|
|
NumberOfNames);
|
|
}
|
|
|
|
// Build a map from Ordinal to Hint to use when emitting thunks
|
|
|
|
BuildOrdinalToHintMap(blkEdata.pb,
|
|
ibAddressOfNameOrdinals,
|
|
NumberOfNames);
|
|
|
|
cbEdata = Align(sizeof(WORD), blkEdata.cb);
|
|
|
|
if (pimage->Switch.Link.DebugType & CvDebug) {
|
|
csection++;
|
|
|
|
cchExportFilename = (BYTE) strlen(szExportFilename);
|
|
|
|
cbCvData = sizeof(CvSig) +
|
|
sizeof(CvObjName) + sizeof(BYTE) + cchExportFilename +
|
|
sizeof(CvCompile) + sizeof(BYTE) + cchLinkVer;
|
|
} else {
|
|
cbCvData = 0;
|
|
}
|
|
|
|
if ((DescriptionString != NULL) && (pimage->imaget != imagetVXD)) {
|
|
// For a non-VXD we emit the description as an .rdata contribution.
|
|
// For VXD's the description is generated as name in the .exe
|
|
// header (TODO).
|
|
|
|
csection++;
|
|
|
|
cchDescription = (DWORD) strlen(DescriptionString) + 1;
|
|
|
|
cbDescription = Align(sizeof(WORD), cchDescription);
|
|
} else {
|
|
cbDescription = 0;
|
|
}
|
|
|
|
if (blkDirectives.pb != NULL) {
|
|
csection++;
|
|
|
|
IbAppendBlk(&blkDirectives, "", 1); // append null byte
|
|
|
|
cbDirectives = Align(sizeof(WORD), blkDirectives.cb);
|
|
} else {
|
|
cbDirectives = 0;
|
|
}
|
|
|
|
if (pimage->ImgFileHdr.Machine == IMAGE_FILE_MACHINE_MPPC_601) {
|
|
csection++;
|
|
|
|
cbPpcShl = sizeof(SHL_HEADER) + (NumberOfNames * EXPORT_NAMESZ);
|
|
} else {
|
|
cbPpcShl = 0;
|
|
}
|
|
|
|
AddInternalNamesToStringTable(pst);
|
|
|
|
cbHeaders = sizeof(IMAGE_FILE_HEADER) +
|
|
(sizeof(IMAGE_SECTION_HEADER) * csection);
|
|
|
|
cbRawData = (fNoEdata ? 0 : cbEdata) +
|
|
cbCvData +
|
|
cbDescription +
|
|
cbDirectives +
|
|
cbPpcShl;
|
|
|
|
pimage->ImgFileHdr.NumberOfSections = csection;
|
|
pimage->ImgFileHdr.PointerToSymbolTable = cbHeaders + cbRawData +
|
|
(sizeof(IMAGE_RELOCATION) * creloc);
|
|
pimage->ImgFileHdr.NumberOfSymbols = csym;
|
|
if (pimage->ImgFileHdr.Machine == IMAGE_FILE_MACHINE_MPPC_601) {
|
|
pimage->ImgFileHdr.Characteristics |= IMAGE_FILE_MPPC_DLL;
|
|
}
|
|
WriteFileHeader(ExpFileHandle, &pimage->ImgFileHdr);
|
|
|
|
// Write first section header.
|
|
|
|
foCur = cbHeaders;
|
|
|
|
if (!fNoEdata) {
|
|
sectionHdr = NullSectionHdr;
|
|
strncpy((char *) sectionHdr.Name, ReservedSection.Export.Name, IMAGE_SIZEOF_SHORT_NAME);
|
|
sectionHdr.SizeOfRawData = blkEdata.cb;
|
|
sectionHdr.PointerToRawData = foCur;
|
|
sectionHdr.PointerToRelocations = foCur + cbEdata;
|
|
sectionHdr.NumberOfRelocations = (WORD) creloc;
|
|
sectionHdr.Characteristics = ReservedSection.Export.Characteristics;
|
|
|
|
WriteSectionHeader(ExpFileHandle, §ionHdr);
|
|
|
|
foCur += cbEdata + sizeof(IMAGE_RELOCATION) * creloc;
|
|
}
|
|
|
|
// Write second section header.
|
|
|
|
if (pimage->Switch.Link.DebugType & CvDebug) {
|
|
sectionHdr = NullSectionHdr;
|
|
strncpy((char *) sectionHdr.Name, ReservedSection.CvSymbols.Name, IMAGE_SIZEOF_SHORT_NAME);
|
|
sectionHdr.SizeOfRawData = cbCvData;
|
|
sectionHdr.PointerToRawData = foCur;
|
|
sectionHdr.Characteristics = ReservedSection.CvSymbols.Characteristics;
|
|
|
|
WriteSectionHeader(ExpFileHandle, §ionHdr);
|
|
|
|
foCur += cbCvData;
|
|
}
|
|
|
|
if (cbDescription != 0) {
|
|
sectionHdr = NullSectionHdr;
|
|
strncpy((char *) sectionHdr.Name, ReservedSection.ReadOnlyData.Name, IMAGE_SIZEOF_SHORT_NAME);
|
|
sectionHdr.SizeOfRawData = cchDescription;
|
|
sectionHdr.PointerToRawData = foCur;
|
|
sectionHdr.Characteristics = ReservedSection.ReadOnlyData.Characteristics;
|
|
|
|
WriteSectionHeader(ExpFileHandle, §ionHdr);
|
|
|
|
foCur += cbDescription;
|
|
}
|
|
|
|
// Write section header that contains the directives.
|
|
|
|
if (blkDirectives.pb != NULL) {
|
|
sectionHdr = NullSectionHdr;
|
|
strncpy((char *) sectionHdr.Name, ReservedSection.Directive.Name, IMAGE_SIZEOF_SHORT_NAME);
|
|
sectionHdr.SizeOfRawData = blkDirectives.cb;
|
|
sectionHdr.PointerToRawData = foCur;
|
|
sectionHdr.Characteristics = ReservedSection.Directive.Characteristics;
|
|
|
|
WriteSectionHeader(ExpFileHandle, §ionHdr);
|
|
|
|
foCur += cbDirectives;
|
|
}
|
|
|
|
// Write the special PowerMac DLL section header
|
|
|
|
if (pimage->ImgFileHdr.Machine == IMAGE_FILE_MACHINE_MPPC_601) {
|
|
foPpcShl = foCur;
|
|
|
|
sectionHdr = NullSectionHdr;
|
|
strncpy((char *) sectionHdr.Name, ".ppcshl", IMAGE_SIZEOF_SHORT_NAME);
|
|
sectionHdr.SizeOfRawData = cbPpcShl;
|
|
sectionHdr.PointerToRawData = foCur;
|
|
sectionHdr.Characteristics = IMAGE_SCN_MEM_DISCARDABLE | IMAGE_SCN_LNK_REMOVE;
|
|
WriteSectionHeader(ExpFileHandle, §ionHdr);
|
|
|
|
foCur += cbPpcShl;
|
|
}
|
|
|
|
// Write the raw data (export table).
|
|
|
|
if (!fNoEdata) {
|
|
IMAGE_EXPORT_DIRECTORY exportDirectory;
|
|
|
|
// Build the raw data (Directory, EAT, Name Ptr Table &
|
|
// Ordinal Table, Names).
|
|
|
|
exportDirectory.Characteristics = 0;
|
|
exportDirectory.TimeDateStamp = pimage->ImgFileHdr.TimeDateStamp;
|
|
exportDirectory.MajorVersion = exportDirectory.MinorVersion = 0;
|
|
exportDirectory.Base = SmallestOrdinal;
|
|
exportDirectory.NumberOfFunctions = NumberOfEntriesInEAT;
|
|
exportDirectory.NumberOfNames = NumberOfNames;
|
|
|
|
// Store the address fields in exportDirectory. These are mistyped as
|
|
// pointers when they are really offsets, hence the casts.
|
|
|
|
exportDirectory.Name = ibName;
|
|
exportDirectory.AddressOfFunctions = (PDWORD *) ibAddressOfFunctions;
|
|
exportDirectory.AddressOfNames = (PDWORD *) ibAddressOfNames;
|
|
exportDirectory.AddressOfNameOrdinals = (PWORD *) ibAddressOfNameOrdinals;
|
|
|
|
memcpy(blkEdata.pb, &exportDirectory, sizeof(IMAGE_EXPORT_DIRECTORY));
|
|
|
|
FileWrite(ExpFileHandle, blkEdata.pb, blkEdata.cb);
|
|
|
|
if (cbEdata != blkEdata.cb) {
|
|
FileWrite(ExpFileHandle, "\0\0\0\0", cbEdata - blkEdata.cb);
|
|
}
|
|
|
|
// Write the fixups.
|
|
|
|
reloc.VirtualAddress = offsetof(IMAGE_EXPORT_DIRECTORY, Name);
|
|
reloc.SymbolTableIndex = 0;
|
|
reloc.Type = ThunkInfo->ExportReloc;
|
|
WriteRelocations(ExpFileHandle, &reloc, 1);
|
|
|
|
reloc.VirtualAddress = offsetof(IMAGE_EXPORT_DIRECTORY, AddressOfFunctions);
|
|
WriteRelocations(ExpFileHandle, &reloc, 1);
|
|
|
|
reloc.VirtualAddress = offsetof(IMAGE_EXPORT_DIRECTORY, AddressOfNames);
|
|
WriteRelocations(ExpFileHandle, &reloc, 1);
|
|
|
|
reloc.VirtualAddress = offsetof(IMAGE_EXPORT_DIRECTORY, AddressOfNameOrdinals);
|
|
WriteRelocations(ExpFileHandle, &reloc, 1);
|
|
|
|
EmitExportDataFixups(ExpFileHandle,
|
|
pst,
|
|
ibAddressOfFunctions,
|
|
ibAddressOfNames,
|
|
ThunkInfo->ExportReloc);
|
|
}
|
|
|
|
if (pimage->Switch.Link.DebugType & CvDebug) {
|
|
// Write the .debug$S section
|
|
|
|
FileWrite(ExpFileHandle, &CvSig, sizeof(CvSig));
|
|
|
|
CvObjName.wLen = (WORD) (sizeof(CvObjName) + sizeof(BYTE) + cchExportFilename - sizeof(WORD));
|
|
|
|
FileWrite(ExpFileHandle, &CvObjName, sizeof(CvObjName));
|
|
FileWrite(ExpFileHandle, &cchExportFilename, sizeof(BYTE));
|
|
FileWrite(ExpFileHandle, szExportFilename, (DWORD) cchExportFilename);
|
|
|
|
FileWrite(ExpFileHandle, &CvCompile, sizeof(CvCompile));
|
|
FileWrite(ExpFileHandle, &cchLinkVer, sizeof(BYTE));
|
|
FileWrite(ExpFileHandle, szLinkVer, (DWORD) cchLinkVer);
|
|
}
|
|
|
|
// Write the raw data for section 2 (description string).
|
|
|
|
if (cbDescription != 0) {
|
|
FileWrite(ExpFileHandle, DescriptionString, cchDescription);
|
|
|
|
if (cbDescription != cchDescription) {
|
|
FileWrite(ExpFileHandle, "\0\0\0\0", cbDescription - cchDescription);
|
|
}
|
|
}
|
|
|
|
// Write the raw data for section 3 (directives).
|
|
|
|
if (blkDirectives.pb != NULL) {
|
|
FileWrite(ExpFileHandle, blkDirectives.pb, blkDirectives.cb);
|
|
|
|
if (cbDirectives != blkDirectives.cb) {
|
|
FileWrite(ExpFileHandle, "\0\0\0\0", cbDirectives - blkDirectives.cb);
|
|
}
|
|
|
|
FreeBlk(&blkDirectives);
|
|
}
|
|
|
|
// Write the raw data for PowerMac SHL section
|
|
|
|
if (pimage->ImgFileHdr.Machine == IMAGE_FILE_MACHINE_MPPC_601) {
|
|
InternalError.Phase = "MppcWriteShlSection";
|
|
|
|
MppcWriteShlSection(ExpFileHandle,
|
|
pimage->Switch.Lib.DllName,
|
|
blkEdata.pb,
|
|
ibAddressOfNames,
|
|
NumberOfNames,
|
|
foPpcShl);
|
|
|
|
InternalError.Phase = "EmitDllExportDirectory";
|
|
}
|
|
|
|
if (!fNoEdata) {
|
|
// Write the symbol table.
|
|
|
|
sym = NullSymbol;
|
|
strncpy((char *) sym.n_name, ReservedSection.Export.Name, IMAGE_SIZEOF_SHORT_NAME);
|
|
sym.SectionNumber = 1;
|
|
sym.StorageClass = IMAGE_SYM_CLASS_STATIC;
|
|
FileWrite(ExpFileHandle, &sym, sizeof(IMAGE_SYMBOL));
|
|
}
|
|
|
|
if (pimage->imaget != imagetVXD) {
|
|
EmitDefLibExternals(ExpFileHandle, pst);
|
|
}
|
|
|
|
WriteStringTable(ExpFileHandle, pst);
|
|
|
|
FreeBlk(&blkEdata);
|
|
|
|
FileClose(ExpFileHandle, TRUE);
|
|
}
|
|
|
|
|
|
void
|
|
BuildThunkSectionHeader (
|
|
IMAGE_SECTION_HEADER *psechdr,
|
|
DWORD *pfo,
|
|
const char *szName,
|
|
DWORD cb,
|
|
WORD creloc,
|
|
DWORD dwCharacteristics
|
|
)
|
|
{
|
|
DWORD fo;
|
|
|
|
memset(psechdr, 0, sizeof(IMAGE_SECTION_HEADER));
|
|
|
|
strncpy((char *) psechdr->Name, szName, IMAGE_SIZEOF_SHORT_NAME);
|
|
psechdr->SizeOfRawData = cb;
|
|
psechdr->NumberOfRelocations = creloc;
|
|
psechdr->Characteristics = dwCharacteristics;
|
|
|
|
fo = Align(sizeof(WORD), *pfo);
|
|
|
|
psechdr->PointerToRawData = fo;
|
|
|
|
fo += cb;
|
|
|
|
if (creloc != 0) {
|
|
fo = Align(sizeof(WORD), fo);
|
|
|
|
psechdr->PointerToRelocations = fo;
|
|
|
|
fo += creloc * sizeof(IMAGE_RELOCATION);
|
|
}
|
|
|
|
*pfo = fo;
|
|
}
|
|
|
|
|
|
void
|
|
FilePad (
|
|
INT Handle,
|
|
DWORD cbAlign
|
|
)
|
|
{
|
|
DWORD fo;
|
|
DWORD cbPad;
|
|
|
|
fo = FileTell(Handle);
|
|
|
|
cbPad = Align(cbAlign, fo) - fo;
|
|
|
|
while (cbPad-- > 0) {
|
|
static const BYTE bZero = 0;
|
|
|
|
FileWrite(Handle, &bZero, 1);
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
EmitThunk (
|
|
PIMAGE pimage,
|
|
PEXTERNAL PtrExtern,
|
|
const THUNK_INFO *ThunkInfo
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Outputs thunk code and data to the library.
|
|
|
|
Arguments:
|
|
|
|
PtrExtern - Pointer to the symbol table.
|
|
|
|
ThunkInfo - Machine specific thunk information.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
char *szName;
|
|
char *szExport;
|
|
char *szCvName;
|
|
char *stringTable;
|
|
char *st;
|
|
size_t cchExport;
|
|
size_t cchName;
|
|
DWORD cbStringTable;
|
|
WORD csection;
|
|
WORD creloc;
|
|
WORD csym;
|
|
BOOL fExportByOrdinal;
|
|
DWORD fo;
|
|
SHORT isec;
|
|
SHORT mpthksecisec[thksecMax];
|
|
IMAGE_SECTION_HEADER rgsechdr[thksecMax];
|
|
BYTE cchCvName;
|
|
size_t cbPad;
|
|
THKSEC thksec;
|
|
WORD isym;
|
|
WORD mpthksymisym[thksymMax];
|
|
IMAGE_SYMBOL sym;
|
|
IMAGE_AUX_SYMBOL auxsym;
|
|
IMAGE_RELOCATION reloc;
|
|
IMAGE_THUNK_DATA thunk_data;
|
|
WORD i;
|
|
PST pst;
|
|
|
|
InternalError.Phase = "EmitThunk";
|
|
|
|
pst = pimage->pst;
|
|
|
|
szName = SzNamePext(PtrExtern, pst);
|
|
|
|
DebugVerbose({printf("%s\n", szName);});
|
|
|
|
if (PtrExtern->Flags & EXTERN_FUZZYMATCH) {
|
|
char *pchT;
|
|
|
|
// Name was found via fuzzy lookup.
|
|
// Strip decoration from exported name.
|
|
|
|
szExport = SzDup(szName);
|
|
|
|
// UNDONE: Memory leak
|
|
|
|
if ((szExport[0] == '?') ||
|
|
(szExport[0] == '@') ||
|
|
(SkipUnderscore && (szExport[0] == '_'))) {
|
|
szExport++;
|
|
}
|
|
|
|
if ((pchT = strchr(szExport, '@')) != NULL) {
|
|
*pchT = '\0';
|
|
}
|
|
} else {
|
|
szExport = szName;
|
|
}
|
|
|
|
cchExport = strlen(szExport) + 1;
|
|
if (PrependUnderscore && (szExport[0] != '?') && (szExport[0] != '@')) {
|
|
cchExport--;
|
|
}
|
|
|
|
if (pimage->Switch.Link.DebugType & CvDebug) {
|
|
if (szName[0] == '?') {
|
|
szCvName = SzUndecorateNameOnly(szName);
|
|
|
|
// UNDONE: Memory leak
|
|
} else if (PtrExtern->Flags & EXTERN_FUZZYMATCH) {
|
|
szCvName = szExport;
|
|
} else {
|
|
char *pchT;
|
|
|
|
szCvName = SzDup(szName);
|
|
|
|
// UNDONE: Memory leak
|
|
|
|
if ((szCvName[0] == '@') ||
|
|
(SkipUnderscore && (szCvName[0] == '_'))) {
|
|
szCvName++;
|
|
}
|
|
|
|
if ((pchT = strchr(szCvName, '@')) != NULL) {
|
|
*pchT = '\0';
|
|
}
|
|
}
|
|
|
|
cchCvName = (BYTE) strlen(szCvName);
|
|
}
|
|
|
|
// Create long string table.
|
|
|
|
cchName = strlen(szName);
|
|
|
|
cbStringTable = sizeof(DWORD);
|
|
|
|
// The name without the IAT prefix will point into
|
|
// the middle of the IAT prefixed name (all platforms
|
|
// except ppc. ppc addsother symbols to the table)
|
|
//
|
|
if (((pimage->ImgFileHdr.Machine == IMAGE_FILE_MACHINE_POWERPC) ||
|
|
(PtrExtern->Flags & EXTERN_EXP_CONST)) &&
|
|
(cchName > IMAGE_SIZEOF_SHORT_NAME)) {
|
|
cbStringTable += cchName + 1; // Include null.
|
|
}
|
|
|
|
cbStringTable += sizeof(szIATPrefix) + cchName;
|
|
cbStringTable += sizeof(szDescriptorPrefix) + cchDllName;
|
|
|
|
csection = 3;
|
|
creloc = 2;
|
|
csym = 9;
|
|
|
|
fExportByOrdinal = IMAGE_SNAP_BY_ORDINAL(PtrExtern->ImageSymbol.OrdinalNumber);
|
|
|
|
if (pimage->Switch.Link.DebugType & CvDebug) {
|
|
// Need section and section symbol
|
|
|
|
csection += 1;
|
|
csym += 1;
|
|
}
|
|
|
|
// If not exporting data, need to output code that jumps to
|
|
// the thunk routine, and the debug data.
|
|
|
|
if (FExportProcPext(PtrExtern)) {
|
|
// Need section & aux symbols
|
|
|
|
csection += 1;
|
|
csym += 2;
|
|
|
|
creloc += ThunkInfo->EntryCodeRelocsCount;
|
|
|
|
if (pimage->ImgFileHdr.Machine == IMAGE_FILE_MACHINE_POWERPC) {
|
|
// Sections are emitted for .pdata and .rdata
|
|
|
|
csection += 2;
|
|
|
|
// There are three relocations on .pdata and two on .rdata
|
|
// and one for the IMGLUE TOC restore.
|
|
|
|
creloc += 6;
|
|
|
|
// Symbols are emitted for the .pdata section (2), the .rdata
|
|
// section (2), the function descriptor, and the .toc
|
|
|
|
csym += 6;
|
|
|
|
// The string table has space for the function descriptor
|
|
// symbol name. Add space for the function entry point name;
|
|
|
|
if ((sizeof(PpcNamePrefix) + cchName - 1) > IMAGE_SIZEOF_SHORT_NAME) {
|
|
cbStringTable += sizeof(PpcNamePrefix) + cchName;
|
|
}
|
|
}
|
|
|
|
if (pimage->Switch.Link.DebugType & CvDebug) {
|
|
csection++;
|
|
creloc += 2;
|
|
csym += 2;
|
|
}
|
|
} else if (PtrExtern->Flags & EXTERN_EXP_DATA) {
|
|
// Data-only export ... this causes us to omit the symbol whose
|
|
// name is the exact name of the exported thing (since there is no
|
|
// way for importing modules to get a fixup to the thing itself).
|
|
|
|
csym -= 1;
|
|
}
|
|
|
|
if (fExportByOrdinal) {
|
|
// If export by ordinal, the export name is not needed nor are
|
|
// the relocations to this name,
|
|
|
|
csection -= 1;
|
|
csym -= 2;
|
|
creloc -= 2;
|
|
}
|
|
|
|
stringTable = (char *) PvAlloc((size_t) cbStringTable);
|
|
memset(stringTable, '\0', cbStringTable);
|
|
*(DWORD *) stringTable = cbStringTable;
|
|
|
|
// Calculate section number and initialize section headers
|
|
|
|
isec = 1;
|
|
|
|
fo = sizeof(IMAGE_FILE_HEADER) + (sizeof(IMAGE_SECTION_HEADER) * csection);
|
|
|
|
memset(mpthksecisec, 0, sizeof(mpthksecisec));
|
|
|
|
if (pimage->Switch.Link.DebugType & CvDebug) {
|
|
DWORD cb;
|
|
|
|
// Build the .debug$S section header
|
|
|
|
mpthksecisec[thksecCv] = isec;
|
|
isec++;
|
|
|
|
cb = sizeof(CvSig) +
|
|
sizeof(CvObjName) + sizeof(BYTE) + cchCvMemberName +
|
|
sizeof(CvCompile) + sizeof(BYTE) + cchLinkVer;
|
|
|
|
BuildThunkSectionHeader(rgsechdr + thksecCv,
|
|
&fo,
|
|
ReservedSection.CvSymbols.Name,
|
|
cb,
|
|
0,
|
|
ReservedSection.CvSymbols.Characteristics);
|
|
}
|
|
|
|
if (FExportProcPext(PtrExtern)) {
|
|
DWORD dwCharacteristics;
|
|
|
|
// Build the .text section header
|
|
|
|
mpthksecisec[thksecText] = isec;
|
|
isec++;
|
|
|
|
dwCharacteristics = IMAGE_SCN_LNK_COMDAT | IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ;
|
|
|
|
switch (pimage->ImgFileHdr.Machine) {
|
|
case IMAGE_FILE_MACHINE_I386 :
|
|
dwCharacteristics |= IMAGE_SCN_ALIGN_2BYTES;
|
|
break;
|
|
|
|
case IMAGE_FILE_MACHINE_ALPHA :
|
|
dwCharacteristics |= IMAGE_SCN_ALIGN_16BYTES;
|
|
break;
|
|
|
|
default:
|
|
dwCharacteristics |= IMAGE_SCN_ALIGN_4BYTES;
|
|
break;
|
|
}
|
|
|
|
BuildThunkSectionHeader(rgsechdr + thksecText,
|
|
&fo,
|
|
CodeSectionName,
|
|
ThunkInfo->EntryCodeSize,
|
|
ThunkInfo->EntryCodeRelocsCount,
|
|
dwCharacteristics);
|
|
|
|
if (pimage->Switch.Link.DebugType & CvDebug) {
|
|
DWORD cb;
|
|
|
|
// Build the associative .debug$S section header.
|
|
|
|
mpthksecisec[thksecCvThunk] = isec;
|
|
isec++;
|
|
|
|
cb = sizeof(CvThunk) + sizeof(BYTE) + cchCvName + sizeof(CvEnd);
|
|
|
|
BuildThunkSectionHeader(rgsechdr + thksecCvThunk,
|
|
&fo,
|
|
ReservedSection.CvSymbols.Name,
|
|
cb,
|
|
2,
|
|
ReservedSection.CvSymbols.Characteristics | IMAGE_SCN_LNK_COMDAT);
|
|
}
|
|
|
|
if (pimage->ImgFileHdr.Machine == IMAGE_FILE_MACHINE_POWERPC) {
|
|
// Build the .pdata section header.
|
|
|
|
mpthksecisec[thksecPdata] = isec;
|
|
isec++;
|
|
|
|
BuildThunkSectionHeader(rgsechdr + thksecPdata,
|
|
&fo,
|
|
ReservedSection.Exception.Name,
|
|
sizeof(PpcEntryCodeFte),
|
|
4,
|
|
ReservedSection.Exception.Characteristics | IMAGE_SCN_LNK_COMDAT | IMAGE_SCN_ALIGN_4BYTES);
|
|
|
|
// Build the .rdata section header.
|
|
|
|
mpthksecisec[thksecRdata] = isec;
|
|
isec++;
|
|
|
|
BuildThunkSectionHeader(rgsechdr + thksecRdata,
|
|
&fo,
|
|
ReservedSection.ReadOnlyData.Name,
|
|
sizeof(PpcEntryCodeDesc),
|
|
2,
|
|
ReservedSection.ReadOnlyData.Characteristics | IMAGE_SCN_LNK_COMDAT | IMAGE_SCN_ALIGN_8BYTES);
|
|
}
|
|
}
|
|
|
|
// Build IAT section header.
|
|
|
|
mpthksecisec[thksecIAT] = isec;
|
|
isec++;
|
|
|
|
BuildThunkSectionHeader(rgsechdr + thksecIAT,
|
|
&fo,
|
|
IAT_SectionName,
|
|
sizeof(IMAGE_THUNK_DATA),
|
|
(WORD) (fExportByOrdinal ? 0 : 1),
|
|
IMAGE_SCN_LNK_COMDAT | IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_ALIGN_4BYTES);
|
|
|
|
// Build Name Table section header.
|
|
|
|
mpthksecisec[thksecINT] = isec;
|
|
isec++;
|
|
|
|
BuildThunkSectionHeader(rgsechdr + thksecINT,
|
|
&fo,
|
|
INT_SectionName,
|
|
sizeof(IMAGE_THUNK_DATA),
|
|
(WORD)(fExportByOrdinal ? 0 : 1),
|
|
IMAGE_SCN_LNK_COMDAT | IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_ALIGN_4BYTES);
|
|
|
|
if (!fExportByOrdinal) {
|
|
// Build data section header.
|
|
|
|
mpthksecisec[thksecName] = isec;
|
|
isec++;
|
|
|
|
cbPad = Align(sizeof(WORD), cchExport);
|
|
cbPad -= cchExport;
|
|
|
|
BuildThunkSectionHeader(rgsechdr + thksecName,
|
|
&fo,
|
|
DataSectionName,
|
|
sizeof(WORD) + cchExport + cbPad,
|
|
0,
|
|
IMAGE_SCN_LNK_COMDAT | IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_ALIGN_2BYTES);
|
|
}
|
|
|
|
// Align symbol table on WORD boundary
|
|
|
|
fo = Align(sizeof(WORD), fo);
|
|
|
|
MemberStart[PtrExtern->ArchiveMemberIndex] = FileTell(FileWriteHandle);
|
|
|
|
WriteMemberHeader(MemberName,
|
|
IsMemberNameLongName,
|
|
timeCur,
|
|
0,
|
|
fo + (csym * sizeof(IMAGE_SYMBOL)) + cbStringTable);
|
|
|
|
// Write the file header
|
|
|
|
pimage->ImgFileHdr.NumberOfSections = csection;
|
|
pimage->ImgFileHdr.PointerToSymbolTable = fo;
|
|
pimage->ImgFileHdr.NumberOfSymbols = csym;
|
|
WriteFileHeader(FileWriteHandle, &pimage->ImgFileHdr);
|
|
|
|
// Write the section headers
|
|
|
|
for (thksec = (THKSEC) 0; thksec < thksecMax; thksec = (THKSEC) (thksec + 1)) {
|
|
if (mpthksecisec[thksec] != 0) {
|
|
WriteSectionHeader(FileWriteHandle, rgsechdr + thksec);
|
|
}
|
|
}
|
|
|
|
// Calculate the symbol numbers for the interesting symbols. This is
|
|
// needed now so that these symbols can be referenced by relocations.
|
|
|
|
isym = 0;
|
|
|
|
if (pimage->Switch.Link.DebugType & CvDebug) {
|
|
// Account for one symbol for the .debug$S section
|
|
|
|
isym++;
|
|
}
|
|
|
|
if (FExportProcPext(PtrExtern)) {
|
|
// Account for two symbols for the .text section
|
|
|
|
isym += 2;
|
|
|
|
// Account for one symbol for function thunk
|
|
|
|
mpthksymisym[thksymExport] = isym;
|
|
isym++;
|
|
|
|
if (pimage->Switch.Link.DebugType & CvDebug) {
|
|
// Account for two symbols for the associative .debug$S section
|
|
|
|
isym += 2;
|
|
}
|
|
|
|
if (pimage->ImgFileHdr.Machine == IMAGE_FILE_MACHINE_POWERPC) {
|
|
// Account for two symbols for the .pdata section
|
|
|
|
isym += 2;
|
|
|
|
// Account for two symbols for the .rdata section
|
|
|
|
isym += 2;
|
|
|
|
// Account for one symbol for function descriptor
|
|
|
|
isym++;
|
|
}
|
|
}
|
|
|
|
// Account for two symbols for IAT section (.idata$5)
|
|
|
|
isym += 2;
|
|
|
|
// Account for one symbol for IAT symbol name (__imp_Foo)
|
|
|
|
mpthksymisym[thksymIAT] = isym;
|
|
isym++;
|
|
|
|
if (PtrExtern->Flags & EXTERN_EXP_CONST) {
|
|
// Account for one symbol for data item name
|
|
|
|
mpthksymisym[thksymExport] = isym;
|
|
isym++;
|
|
}
|
|
|
|
// Account for two symbols for INT section (.idata$4)
|
|
|
|
isym += 2;
|
|
|
|
if (!fExportByOrdinal) {
|
|
// Account for two symbols for export name section (.idata$6)
|
|
|
|
mpthksymisym[thksymName] = isym;
|
|
isym += 2;
|
|
}
|
|
|
|
if (FExportProcPext(PtrExtern)) {
|
|
if (pimage->ImgFileHdr.Machine == IMAGE_FILE_MACHINE_POWERPC) {
|
|
// Account for one symbol for the TOC
|
|
|
|
mpthksymisym[thksymToc] = isym;
|
|
isym++;
|
|
}
|
|
}
|
|
|
|
// Account for one symbol for the import descriptor
|
|
|
|
isym++;
|
|
|
|
// Write the data and relocations for all sections
|
|
|
|
if (pimage->Switch.Link.DebugType & CvDebug) {
|
|
// Write the .debug$S section
|
|
|
|
FilePad(FileWriteHandle, sizeof(WORD));
|
|
|
|
FileWrite(FileWriteHandle, &CvSig, sizeof(CvSig));
|
|
|
|
FileWrite(FileWriteHandle, &CvObjName, sizeof(CvObjName));
|
|
FileWrite(FileWriteHandle, &cchCvMemberName, sizeof(BYTE));
|
|
FileWrite(FileWriteHandle, szCvMemberName, (DWORD) cchCvMemberName);
|
|
|
|
FileWrite(FileWriteHandle, &CvCompile, sizeof(CvCompile));
|
|
FileWrite(FileWriteHandle, &cchLinkVer, sizeof(BYTE));
|
|
FileWrite(FileWriteHandle, szLinkVer, (DWORD) cchLinkVer);
|
|
}
|
|
|
|
if (FExportProcPext(PtrExtern)) {
|
|
// Write the raw data for code section (thunk code) if not exporting data.
|
|
|
|
FilePad(FileWriteHandle, sizeof(WORD));
|
|
FileWrite(FileWriteHandle, ThunkInfo->EntryCode, ThunkInfo->EntryCodeSize);
|
|
|
|
// Write the relocation for section 1 (thunk code).
|
|
|
|
FilePad(FileWriteHandle, sizeof(WORD));
|
|
|
|
for (i = 0; i < ThunkInfo->EntryCodeRelocsCount; i++) {
|
|
reloc.VirtualAddress = ThunkInfo->EntryCodeRelocs[i].VirtualAddress;
|
|
reloc.SymbolTableIndex = mpthksymisym[ThunkInfo->EntryCodeRelocs[i].thksym];
|
|
reloc.Type = ThunkInfo->EntryCodeRelocs[i].Type;
|
|
|
|
switch (pimageDeflib->ImgFileHdr.Machine) {
|
|
case IMAGE_FILE_MACHINE_R3000 :
|
|
case IMAGE_FILE_MACHINE_R4000 :
|
|
if (reloc.Type == IMAGE_REL_MIPS_PAIR) {
|
|
reloc.SymbolTableIndex = (WORD) ThunkInfo->EntryCodeRelocs[i].thksym;
|
|
}
|
|
break;
|
|
|
|
case IMAGE_FILE_MACHINE_ALPHA :
|
|
if (reloc.Type == IMAGE_REL_ALPHA_MATCH) {
|
|
reloc.SymbolTableIndex = (WORD) ThunkInfo->EntryCodeRelocs[i].thksym;
|
|
}
|
|
break;
|
|
}
|
|
|
|
WriteRelocations(FileWriteHandle, &reloc, 1);
|
|
}
|
|
|
|
if (pimage->Switch.Link.DebugType & CvDebug) {
|
|
// Write the associative .debug$S section
|
|
|
|
FilePad(FileWriteHandle, sizeof(WORD));
|
|
|
|
CvThunk.wLen = (WORD) (sizeof(CvThunk) + sizeof(BYTE) + cchCvName - sizeof(WORD));
|
|
CvThunk.cb = (WORD) ThunkInfo->EntryCodeSize;
|
|
|
|
FileWrite(FileWriteHandle, &CvThunk, sizeof(CvThunk));
|
|
FileWrite(FileWriteHandle, &cchCvName, sizeof(BYTE));
|
|
FileWrite(FileWriteHandle, szCvName, (DWORD) cchCvName);
|
|
|
|
FileWrite(FileWriteHandle, &CvEnd, sizeof(CvEnd));
|
|
|
|
// Write the relocation for section 5 (function address).
|
|
|
|
FilePad(FileWriteHandle, sizeof(WORD));
|
|
|
|
reloc.VirtualAddress = offsetof(struct CVTHUNK, ib);
|
|
reloc.SymbolTableIndex = mpthksymisym[thksymExport];
|
|
reloc.Type = ThunkInfo->DebugSectionRelReloc;
|
|
WriteRelocations(FileWriteHandle, &reloc, 1);
|
|
|
|
// Write the relocation for section 5 (function section).
|
|
|
|
reloc.VirtualAddress = offsetof(struct CVTHUNK, sn);
|
|
reloc.Type = ThunkInfo->DebugSectionNumReloc;
|
|
WriteRelocations(FileWriteHandle, &reloc, 1);
|
|
}
|
|
|
|
if (pimage->ImgFileHdr.Machine == IMAGE_FILE_MACHINE_POWERPC) {
|
|
// Write the raw data for section 2 (exception table entry).
|
|
|
|
FilePad(FileWriteHandle, sizeof(WORD));
|
|
FileWrite(FileWriteHandle, PpcEntryCodeFte, sizeof(PpcEntryCodeFte));
|
|
|
|
// Write the relocation for section 2 (exception table entry).
|
|
|
|
FilePad(FileWriteHandle, sizeof(WORD));
|
|
|
|
for (i = 0; i < 4; i++) {
|
|
if (PpcEntryCodeFteRelocs[i].Type == IMAGE_REL_PPC_IMGLUE) {
|
|
reloc.VirtualAddress = PpcTocRestoreCode;
|
|
} else {
|
|
reloc.VirtualAddress = PpcEntryCodeFteRelocs[i].VirtualAddress;
|
|
}
|
|
|
|
reloc.SymbolTableIndex = mpthksymisym[PpcEntryCodeFteRelocs[i].thksym];
|
|
reloc.Type = PpcEntryCodeFteRelocs[i].Type;
|
|
WriteRelocations(FileWriteHandle, &reloc, 1L);
|
|
}
|
|
|
|
// Write the raw data for section 3 (function descriptor).
|
|
|
|
FilePad(FileWriteHandle, sizeof(WORD));
|
|
FileWrite(FileWriteHandle, PpcEntryCodeDesc, sizeof(PpcEntryCodeDesc));
|
|
|
|
// Write the raw data for section 3 (function descriptor).
|
|
|
|
FilePad(FileWriteHandle, sizeof(WORD));
|
|
|
|
for (i = 0; i < 2; i++) {
|
|
reloc.VirtualAddress = PpcEntryCodeDescRelocs[i].VirtualAddress;
|
|
reloc.SymbolTableIndex = mpthksymisym[PpcEntryCodeDescRelocs[i].thksym];
|
|
reloc.Type = PpcEntryCodeDescRelocs[i].Type;
|
|
WriteRelocations(FileWriteHandle, &reloc, 1L);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (fExportByOrdinal) {
|
|
// Write the raw data for the IAT.
|
|
|
|
thunk_data.u1.Ordinal = PtrExtern->ImageSymbol.OrdinalNumber;
|
|
|
|
FilePad(FileWriteHandle, sizeof(WORD));
|
|
FileWrite(FileWriteHandle, &thunk_data, sizeof(IMAGE_THUNK_DATA));
|
|
|
|
// Write the same thing for the INT.
|
|
|
|
FilePad(FileWriteHandle, sizeof(WORD));
|
|
FileWrite(FileWriteHandle, &thunk_data, sizeof(IMAGE_THUNK_DATA));
|
|
} else {
|
|
// Write the raw data for the IAT.
|
|
|
|
thunk_data.u1.Function = 0;
|
|
|
|
FilePad(FileWriteHandle, sizeof(WORD));
|
|
FileWrite(FileWriteHandle, &thunk_data, sizeof(IMAGE_THUNK_DATA));
|
|
|
|
// Write the relocation for section 3 (point IAT to name).
|
|
|
|
FilePad(FileWriteHandle, sizeof(WORD));
|
|
|
|
reloc.VirtualAddress = offsetof(IMAGE_THUNK_DATA, u1.Function);
|
|
reloc.SymbolTableIndex = mpthksymisym[thksymName];
|
|
reloc.Type = ThunkInfo->ThunkReloc;
|
|
WriteRelocations(FileWriteHandle, &reloc, 1);
|
|
|
|
// Write the same thing for the INT.
|
|
|
|
FilePad(FileWriteHandle, sizeof(WORD));
|
|
FileWrite(FileWriteHandle, &thunk_data, sizeof(IMAGE_THUNK_DATA));
|
|
|
|
FilePad(FileWriteHandle, sizeof(WORD));
|
|
WriteRelocations(FileWriteHandle, &reloc, 1);
|
|
|
|
// Write the raw data for data section (thunk by name and function name).
|
|
|
|
FilePad(FileWriteHandle, sizeof(WORD));
|
|
FileWrite(FileWriteHandle, rgwHint + PtrExtern->ImageSymbol.OrdinalNumber - SmallestOrdinal, sizeof(WORD));
|
|
st = szExport;
|
|
if (PrependUnderscore && (st[0] != '?') && (st[0] != '@')) {
|
|
st++;
|
|
}
|
|
FileWrite(FileWriteHandle, st, (DWORD) cchExport);
|
|
if (cbPad) {
|
|
FileWrite(FileWriteHandle, "\0\0\0\0", cbPad);
|
|
}
|
|
}
|
|
|
|
// Write the symbol table.
|
|
|
|
st = stringTable;
|
|
st += sizeof(DWORD);
|
|
|
|
FilePad(FileWriteHandle, sizeof(WORD));
|
|
|
|
if (pimage->Switch.Link.DebugType & CvDebug) {
|
|
// Write the section symbol for the .debug$S section
|
|
|
|
sym = NullSymbol;
|
|
strncpy((char *) sym.n_name, ReservedSection.CvSymbols.Name, IMAGE_SIZEOF_SHORT_NAME);
|
|
sym.SectionNumber = mpthksecisec[thksecCv];
|
|
sym.StorageClass = IMAGE_SYM_CLASS_STATIC;
|
|
sym.NumberOfAuxSymbols = 0;
|
|
FileWrite(FileWriteHandle, &sym, sizeof(IMAGE_SYMBOL));
|
|
}
|
|
|
|
if (FExportProcPext(PtrExtern)) {
|
|
// Write the section symbol for the .text COMDAT section.
|
|
|
|
sym = NullSymbol;
|
|
strncpy((char *) sym.n_name, CodeSectionName, IMAGE_SIZEOF_SHORT_NAME);
|
|
sym.SectionNumber = mpthksecisec[thksecText];
|
|
sym.StorageClass = IMAGE_SYM_CLASS_STATIC;
|
|
sym.NumberOfAuxSymbols = 1;
|
|
FileWrite(FileWriteHandle, &sym, sizeof(IMAGE_SYMBOL));
|
|
|
|
// Write the aux symbol with COMDAT info.
|
|
|
|
auxsym.Section.Length = rgsechdr[thksecText].SizeOfRawData;
|
|
auxsym.Section.NumberOfRelocations = 1;
|
|
auxsym.Section.NumberOfLinenumbers = 0;
|
|
auxsym.Section.CheckSum = 0;
|
|
auxsym.Section.Number = 0;
|
|
auxsym.Section.Selection = IMAGE_COMDAT_SELECT_NODUPLICATES;
|
|
FileWrite(FileWriteHandle, &auxsym, sizeof(IMAGE_SYMBOL));
|
|
|
|
sym = NullSymbol;
|
|
if (pimage->ImgFileHdr.Machine == IMAGE_FILE_MACHINE_POWERPC) {
|
|
if ((sizeof(PpcNamePrefix) + cchName - 1) > IMAGE_SIZEOF_SHORT_NAME) {
|
|
sym.n_offset = st - stringTable;
|
|
strcpy(st, PpcNamePrefix);
|
|
strcat(st, szName);
|
|
st += sizeof(PpcNamePrefix) + cchName;
|
|
} else {
|
|
strcpy((char *) sym.n_name, PpcNamePrefix);
|
|
strncpy((char *) sym.n_name + sizeof(PpcNamePrefix) - 1, szName, IMAGE_SIZEOF_SHORT_NAME - (sizeof(PpcNamePrefix) - 1));
|
|
}
|
|
} else {
|
|
if (cchName > IMAGE_SIZEOF_SHORT_NAME) {
|
|
// The name without the __imp_ prefix will point into the
|
|
// name with the prefix. The prefixed name is actually copied
|
|
// over later.
|
|
sym.n_offset = st - stringTable + sizeof(szIATPrefix) - 1;
|
|
// sym.n_offset = st - stringTable;
|
|
// strcpy(st, szName);
|
|
// st += cchName + 1; // Include null.
|
|
} else {
|
|
strncpy((char *) sym.n_name, szName, IMAGE_SIZEOF_SHORT_NAME);
|
|
}
|
|
}
|
|
sym.SectionNumber = mpthksecisec[thksecText];
|
|
sym.Type = IMAGE_SYM_TYPE_NULL | (IMAGE_SYM_DTYPE_FUNCTION << N_BTSHFT);
|
|
sym.StorageClass = IMAGE_SYM_CLASS_EXTERNAL;
|
|
FileWrite(FileWriteHandle, &sym, sizeof(IMAGE_SYMBOL));
|
|
|
|
if (pimage->Switch.Link.DebugType & CvDebug) {
|
|
// Write the section symbol for the associative .debug$S section
|
|
|
|
sym = NullSymbol;
|
|
strncpy((char *) sym.n_name, ReservedSection.CvSymbols.Name, IMAGE_SIZEOF_SHORT_NAME);
|
|
sym.SectionNumber = mpthksecisec[thksecCvThunk];
|
|
sym.StorageClass = IMAGE_SYM_CLASS_STATIC;
|
|
sym.NumberOfAuxSymbols = 1;
|
|
FileWrite(FileWriteHandle, &sym, sizeof(IMAGE_SYMBOL));
|
|
|
|
// Write the aux symbol with COMDAT info.
|
|
|
|
auxsym.Section.Length = rgsechdr[thksecCvThunk].SizeOfRawData;
|
|
auxsym.Section.NumberOfRelocations = 2;
|
|
auxsym.Section.NumberOfLinenumbers = 0;
|
|
auxsym.Section.CheckSum = 0;
|
|
auxsym.Section.Number = mpthksecisec[thksecText];
|
|
auxsym.Section.Selection = IMAGE_COMDAT_SELECT_ASSOCIATIVE;
|
|
FileWrite(FileWriteHandle, &auxsym, sizeof(IMAGE_SYMBOL));
|
|
}
|
|
|
|
if (pimage->ImgFileHdr.Machine == IMAGE_FILE_MACHINE_POWERPC) {
|
|
// Write the section symbol for the .pdata COMDAT section.
|
|
|
|
sym = NullSymbol;
|
|
strncpy((char *) sym.n_name, ReservedSection.Exception.Name, IMAGE_SIZEOF_SHORT_NAME);
|
|
sym.SectionNumber = mpthksecisec[thksecPdata];
|
|
sym.StorageClass = IMAGE_SYM_CLASS_STATIC;
|
|
sym.NumberOfAuxSymbols = 1;
|
|
FileWrite(FileWriteHandle, &sym, sizeof(IMAGE_SYMBOL));
|
|
|
|
// Write the aux symbol with COMDAT info.
|
|
|
|
auxsym.Section.Length = rgsechdr[thksecPdata].SizeOfRawData;
|
|
auxsym.Section.NumberOfRelocations = 3;
|
|
auxsym.Section.NumberOfLinenumbers = 0;
|
|
auxsym.Section.CheckSum = 0;
|
|
auxsym.Section.Number = mpthksecisec[thksecText];
|
|
auxsym.Section.Selection = IMAGE_COMDAT_SELECT_ASSOCIATIVE;
|
|
FileWrite(FileWriteHandle, &auxsym, sizeof(IMAGE_SYMBOL));
|
|
|
|
// Write the section symbol for the function descriptor COMDAT section.
|
|
|
|
sym = NullSymbol;
|
|
strncpy((char *) sym.n_name, ReservedSection.ReadOnlyData.Name, IMAGE_SIZEOF_SHORT_NAME);
|
|
sym.SectionNumber = mpthksecisec[thksecRdata];
|
|
sym.StorageClass = IMAGE_SYM_CLASS_STATIC;
|
|
sym.NumberOfAuxSymbols = 1;
|
|
FileWrite(FileWriteHandle, &sym, sizeof(IMAGE_SYMBOL));
|
|
|
|
// Write the aux symbol with COMDAT info.
|
|
|
|
auxsym.Section.Length = rgsechdr[thksecRdata].SizeOfRawData;
|
|
auxsym.Section.NumberOfRelocations = 2;
|
|
auxsym.Section.NumberOfLinenumbers = 0;
|
|
auxsym.Section.CheckSum = 0;
|
|
auxsym.Section.Number = 0;
|
|
auxsym.Section.Selection = IMAGE_COMDAT_SELECT_NODUPLICATES;
|
|
FileWrite(FileWriteHandle, &auxsym, sizeof(IMAGE_SYMBOL));
|
|
|
|
// Write the function descriptor symbol
|
|
|
|
sym = NullSymbol;
|
|
if (cchName > IMAGE_SIZEOF_SHORT_NAME) {
|
|
sym.n_offset = st - stringTable;
|
|
strcpy(st, szName);
|
|
st += cchName + 1; // Include null.
|
|
} else {
|
|
strncpy((char *) sym.n_name, szName, IMAGE_SIZEOF_SHORT_NAME);
|
|
}
|
|
sym.SectionNumber = mpthksecisec[thksecRdata];
|
|
sym.StorageClass = IMAGE_SYM_CLASS_EXTERNAL;
|
|
FileWrite(FileWriteHandle, &sym, sizeof(IMAGE_SYMBOL));
|
|
}
|
|
}
|
|
|
|
// Write the section symbol for the IAT COMDAT section.
|
|
|
|
sym = NullSymbol;
|
|
strncpy((char *) sym.n_name, IAT_SectionName, IMAGE_SIZEOF_SHORT_NAME);
|
|
sym.SectionNumber = mpthksecisec[thksecIAT];
|
|
sym.StorageClass = IMAGE_SYM_CLASS_STATIC;
|
|
sym.NumberOfAuxSymbols = 1;
|
|
FileWrite(FileWriteHandle, &sym, sizeof(IMAGE_SYMBOL));
|
|
|
|
// Write the aux symbol with COMDAT info.
|
|
|
|
auxsym.Section.Length = rgsechdr[thksecIAT].SizeOfRawData;
|
|
auxsym.Section.NumberOfRelocations = (WORD) (fExportByOrdinal ? 0 : 1);
|
|
auxsym.Section.NumberOfLinenumbers = 0;
|
|
auxsym.Section.CheckSum = 0;
|
|
auxsym.Section.Number = 0;
|
|
auxsym.Section.Selection = IMAGE_COMDAT_SELECT_NODUPLICATES;
|
|
FileWrite(FileWriteHandle, &auxsym, sizeof(IMAGE_SYMBOL));
|
|
|
|
// Write the IAT data symbol (__imp_Foo)
|
|
|
|
sym = NullSymbol;
|
|
sym.n_offset = st - stringTable;
|
|
strcpy(st, szIATPrefix);
|
|
st += sizeof(szIATPrefix) - 1; // don't include \0
|
|
strcpy(st, szName);
|
|
st += cchName + 1; // Include null.
|
|
sym.SectionNumber = mpthksecisec[thksecIAT];
|
|
sym.StorageClass = IMAGE_SYM_CLASS_EXTERNAL;
|
|
FileWrite(FileWriteHandle, &sym, sizeof(IMAGE_SYMBOL));
|
|
|
|
if (PtrExtern->Flags & EXTERN_EXP_CONST) {
|
|
// Write additional symbol with the name of the export
|
|
|
|
sym = NullSymbol;
|
|
if (cchName > IMAGE_SIZEOF_SHORT_NAME) {
|
|
sym.n_offset = st - stringTable;
|
|
strcpy(st, szName);
|
|
st += cchName + 1; // Include null.
|
|
} else {
|
|
strncpy((char *) sym.n_name, szName, IMAGE_SIZEOF_SHORT_NAME);
|
|
}
|
|
sym.SectionNumber = mpthksecisec[thksecIAT];
|
|
sym.StorageClass = IMAGE_SYM_CLASS_EXTERNAL;
|
|
FileWrite(FileWriteHandle, &sym, sizeof(IMAGE_SYMBOL));
|
|
}
|
|
|
|
// Write the section symbol for the INT COMDAT section.
|
|
|
|
sym = NullSymbol;
|
|
strncpy((char *) sym.n_name, INT_SectionName, IMAGE_SIZEOF_SHORT_NAME);
|
|
sym.SectionNumber = mpthksecisec[thksecINT];
|
|
sym.StorageClass = IMAGE_SYM_CLASS_STATIC;
|
|
sym.NumberOfAuxSymbols = 1;
|
|
FileWrite(FileWriteHandle, &sym, sizeof(IMAGE_SYMBOL));
|
|
|
|
// Write the aux symbol with COMDAT info.
|
|
|
|
auxsym.Section.Length = rgsechdr[thksecINT].SizeOfRawData;
|
|
auxsym.Section.NumberOfRelocations = (WORD) (fExportByOrdinal ? 0 : 1);
|
|
auxsym.Section.NumberOfLinenumbers = 0;
|
|
auxsym.Section.CheckSum = 0;
|
|
auxsym.Section.Number = mpthksecisec[thksecIAT];
|
|
auxsym.Section.Selection = IMAGE_COMDAT_SELECT_ASSOCIATIVE;
|
|
FileWrite(FileWriteHandle, &auxsym, sizeof(IMAGE_SYMBOL));
|
|
|
|
if (!fExportByOrdinal) {
|
|
// Write the symbol which points to function name.
|
|
|
|
sym = NullSymbol;
|
|
strncpy((char *) sym.n_name, DataSectionName, IMAGE_SIZEOF_SHORT_NAME);
|
|
sym.SectionNumber = mpthksecisec[thksecName];
|
|
sym.StorageClass = IMAGE_SYM_CLASS_STATIC;
|
|
sym.NumberOfAuxSymbols = 1;
|
|
FileWrite(FileWriteHandle, &sym, sizeof(IMAGE_SYMBOL));
|
|
|
|
// Write the aux symbol with comdat info.
|
|
|
|
auxsym.Section.Length = rgsechdr[thksecName].SizeOfRawData;
|
|
auxsym.Section.NumberOfRelocations = 0;
|
|
auxsym.Section.NumberOfLinenumbers = 0;
|
|
auxsym.Section.CheckSum = 0;
|
|
auxsym.Section.Number = mpthksecisec[thksecIAT];
|
|
auxsym.Section.Selection = IMAGE_COMDAT_SELECT_ASSOCIATIVE;
|
|
FileWrite(FileWriteHandle, &auxsym, sizeof(IMAGE_SYMBOL));
|
|
}
|
|
|
|
if (FExportProcPext(PtrExtern)) {
|
|
if (pimage->ImgFileHdr.Machine == IMAGE_FILE_MACHINE_POWERPC) {
|
|
// Write the .toc symbol
|
|
|
|
sym = NullSymbol;
|
|
strncpy((char *) sym.n_name, TocName, IMAGE_SIZEOF_SHORT_NAME);
|
|
sym.SectionNumber = IMAGE_SYM_UNDEFINED;
|
|
sym.StorageClass = IMAGE_SYM_CLASS_EXTERNAL;
|
|
FileWrite(FileWriteHandle, &sym, sizeof(IMAGE_SYMBOL));
|
|
}
|
|
}
|
|
|
|
// Write the Import descriptor symbol.
|
|
|
|
sym = NullSymbol;
|
|
sym.n_offset = st - stringTable;
|
|
strcpy(st, szDescriptorPrefix);
|
|
strcat(st, pimage->Switch.Lib.DllName);
|
|
st += sizeof(szDescriptorPrefix) + cchDllName;
|
|
sym.SectionNumber = IMAGE_SYM_UNDEFINED;
|
|
sym.StorageClass = IMAGE_SYM_CLASS_EXTERNAL;
|
|
FileWrite(FileWriteHandle, &sym, sizeof(IMAGE_SYMBOL));
|
|
|
|
// Write the string table.
|
|
|
|
FileWrite(FileWriteHandle, stringTable, cbStringTable);
|
|
FreePv(stringTable);
|
|
|
|
if (FileTell(FileWriteHandle) & 1) {
|
|
FileWrite(FileWriteHandle, IMAGE_ARCHIVE_PAD, 1);
|
|
}
|
|
}
|
|
|
|
|
|
// EmitDirectiveThunk: Emits a COFF object containing only an -import directive for a specific symbol
|
|
// name & DLL name. The -import directive is currently only supported for PowerMac. (On other
|
|
// platforms the COFF object contains various sections with data structures describing the contents
|
|
// of the import table (.idata section) ... this doesn't work for PowerMac because imports are
|
|
// represented as load-time fixups (and we don't want to allow the contents of COFF sections to be
|
|
// load-time fixups ...).
|
|
//
|
|
void
|
|
EmitDirectiveThunk(PIMAGE pimage, PEXTERNAL pext)
|
|
{
|
|
char *szCOFFSymName;
|
|
char *szImpSymName;
|
|
DWORD cbHeaders;
|
|
DWORD cbRawData;
|
|
DWORD cbSymbols;
|
|
DWORD cbStringTable;
|
|
DWORD cbPad;
|
|
DWORD dwZero = 0;
|
|
IMAGE_SYMBOL sym;
|
|
IMAGE_SECTION_HEADER sechdr;
|
|
char *szMember;
|
|
char szCurrentVer[11];
|
|
char szOldCodeVer[11];
|
|
|
|
InternalError.Phase = "EmitDirectiveThunk";
|
|
|
|
_itoa(dwMaxCurrentVer, szCurrentVer, 10);
|
|
_itoa(dwMinOldCodeVer == UINT_MAX ? 0 : dwMinOldCodeVer, szOldCodeVer, 10);
|
|
|
|
// UNDONE: Is SzDup needed?
|
|
|
|
szCOFFSymName = SzDup(SzNamePext(pext, pimage->pst)); // one with underscore
|
|
szImpSymName = (*szCOFFSymName == '_') ? szCOFFSymName + 1 : szCOFFSymName; // one without
|
|
|
|
MemberStart[pext->ArchiveMemberIndex] = FileTell(FileWriteHandle);
|
|
|
|
szMember = (char *)PvAlloc(strlen(pimageDeflib->Switch.Lib.DllName) +
|
|
strlen(pimageDeflib->Switch.Lib.DllExtension) +
|
|
3); // one for null and two for quotes
|
|
|
|
strcpy(szMember, "\"");
|
|
strcat(szMember, pimageDeflib->Switch.Lib.DllName);
|
|
strcat(szMember, pimageDeflib->Switch.Lib.DllExtension);
|
|
strcat(szMember, "\"");
|
|
|
|
cbHeaders = sizeof(IMAGE_FILE_HEADER) + sizeof(IMAGE_SECTION_HEADER); // 1 section: .drectve
|
|
cbRawData = strlen("/IMPORT:") + strlen(szImpSymName) +
|
|
strlen(",LIB=") + strlen(szMember) +
|
|
strlen(",CURRENTVER=") + strlen(szCurrentVer) +
|
|
strlen(",OLDCODEVER=") + strlen(szOldCodeVer);
|
|
|
|
cbSymbols = IMAGE_SIZEOF_SYMBOL; // just 1
|
|
|
|
sym = NullSymbol;
|
|
sym.SectionNumber = 1;
|
|
sym.StorageClass = IMAGE_SYM_CLASS_EXTERNAL;
|
|
if (strlen(szCOFFSymName) > IMAGE_SIZEOF_SHORT_NAME) {
|
|
sym.n_zeroes = 0;
|
|
sym.n_offset = sizeof(DWORD);
|
|
cbStringTable = sizeof(DWORD) + strlen(szCOFFSymName) + 1;
|
|
} else {
|
|
strncpy((char *) sym.n_name, szCOFFSymName, IMAGE_SIZEOF_SHORT_NAME);
|
|
cbStringTable = sizeof(DWORD);
|
|
}
|
|
|
|
cbPad = (4 - ((cbHeaders + cbRawData + cbSymbols + cbStringTable) & 3)) & 3;
|
|
|
|
WriteMemberHeader(MemberName,
|
|
IsMemberNameLongName,
|
|
timeCur,
|
|
0,
|
|
cbHeaders + cbRawData + cbSymbols + cbStringTable + cbPad);
|
|
|
|
pimage->ImgFileHdr.NumberOfSections = 1;
|
|
pimage->ImgFileHdr.PointerToSymbolTable = cbHeaders + cbRawData;
|
|
pimage->ImgFileHdr.NumberOfSymbols = 1;
|
|
WriteFileHeader(FileWriteHandle, &pimage->ImgFileHdr);
|
|
|
|
memset(&sechdr, 0, sizeof(sechdr));
|
|
strncpy((char *) sechdr.Name, ".drectve", IMAGE_SIZEOF_SHORT_NAME);
|
|
sechdr.SizeOfRawData = cbRawData;
|
|
sechdr.PointerToRawData = cbHeaders;
|
|
sechdr.Characteristics = IMAGE_SCN_LNK_INFO | IMAGE_SCN_LNK_REMOVE;
|
|
FileWrite(FileWriteHandle, &sechdr, IMAGE_SIZEOF_SECTION_HEADER);
|
|
|
|
FileWrite(FileWriteHandle, "/IMPORT:", strlen("/IMPORT:"));
|
|
FileWrite(FileWriteHandle, szImpSymName, strlen(szImpSymName));
|
|
FileWrite(FileWriteHandle, ",LIB=", strlen(",LIB="));
|
|
FileWrite(FileWriteHandle, szMember, strlen(szMember));
|
|
FileWrite(FileWriteHandle, ",CURRENTVER=", strlen(",CURRENTVER="));
|
|
FileWrite(FileWriteHandle, szCurrentVer, strlen(szCurrentVer));
|
|
FileWrite(FileWriteHandle, ",OLDCODEVER=", strlen(",OLDCODEVER="));
|
|
FileWrite(FileWriteHandle, szOldCodeVer, strlen(szOldCodeVer));
|
|
|
|
FileWrite(FileWriteHandle, &sym, IMAGE_SIZEOF_SYMBOL);
|
|
|
|
FileWrite(FileWriteHandle, &cbStringTable, sizeof(DWORD));
|
|
if (cbStringTable > sizeof(DWORD)) {
|
|
FileWrite(FileWriteHandle, szCOFFSymName, strlen(szCOFFSymName) + 1);
|
|
}
|
|
|
|
FileWrite(FileWriteHandle, &dwZero, cbPad);
|
|
|
|
FreePv(szMember);
|
|
free(szCOFFSymName);
|
|
}
|
|
|
|
|
|
void
|
|
EmitAllThunks (
|
|
PIMAGE pimage,
|
|
const THUNK_INFO *ThunkInfo
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Outputs the next thunk code and data to the library.
|
|
|
|
Arguments:
|
|
|
|
pst - Pointer to the symbol table.
|
|
|
|
ThunkInfo - Machine specific thunk information.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PPEXTERNAL rgpext;
|
|
DWORD cext;
|
|
DWORD iext;
|
|
PST pst = pimage->pst;
|
|
|
|
if (pimage->Switch.Link.DebugType & CvDebug) {
|
|
// Refresh
|
|
|
|
CvObjName.wLen = (WORD) (sizeof(CvObjName) + sizeof(BYTE) + cchCvMemberName - sizeof(WORD));
|
|
}
|
|
|
|
rgpext = RgpexternalByName(pst);
|
|
cext = Cexternal(pst);
|
|
|
|
for (iext = 0; iext < cext; iext++) {
|
|
PEXTERNAL pext;
|
|
|
|
pext = rgpext[iext];
|
|
|
|
if (pext->Flags & EXTERN_DEFINED &&
|
|
!(pext->Flags & EXTERN_IMPLIB_ONLY) &&
|
|
!(pext->Flags & EXTERN_PRIVATE))
|
|
{
|
|
if (pimage->ImgFileHdr.Machine == IMAGE_FILE_MACHINE_MPPC_601) {
|
|
EmitDirectiveThunk(pimage, pext);
|
|
} else if (pimage->ImgFileHdr.Machine == IMAGE_FILE_MACHINE_M68K) {
|
|
EmitMacThunk(pimage, pext, ThunkInfo, MemberName);
|
|
} else {
|
|
EmitThunk(pimage, pext, ThunkInfo);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
CompleteLinkerMembers (
|
|
PST pst)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Completes the linker member of the library.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
WORD i;
|
|
LONG objectSize;
|
|
|
|
InternalError.Phase = "CompleteLinkerMembers";
|
|
|
|
// Finish writing offsets.
|
|
|
|
objectSize = IMAGE_ARCHIVE_START_SIZE +
|
|
sizeof(IMAGE_ARCHIVE_MEMBER_HEADER) + sizeof(DWORD);
|
|
FileSeek(FileWriteHandle, objectSize, SEEK_SET);
|
|
EmitOffsets(pst, FALSE);
|
|
|
|
FileSeek(FileWriteHandle, NewLinkerMember +
|
|
sizeof(IMAGE_ARCHIVE_MEMBER_HEADER) +
|
|
sizeof(DWORD), SEEK_SET);
|
|
for (i = 0; i < NextMember; i++) {
|
|
FileWrite(FileWriteHandle, &MemberStart[ARCHIVE + i], sizeof(DWORD));
|
|
}
|
|
|
|
// Skip over number of symbols.
|
|
|
|
FileSeek(FileWriteHandle, sizeof(DWORD), SEEK_CUR);
|
|
|
|
// Write indexes.
|
|
|
|
EmitOffsets(pst, TRUE);
|
|
}
|
|
|
|
|
|
MainFunc
|
|
DefLibMain (
|
|
PIMAGE pimgObj
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Entry point for DefLib.
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
0 Successful.
|
|
1 Failed.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
char szDrive[_MAX_DRIVE];
|
|
char szDir[_MAX_DIR];
|
|
char szFname[_MAX_FNAME];
|
|
BOOL fPass1;
|
|
const THUNK_INFO *ThunkInfo;
|
|
DWORD csym;
|
|
DWORD numEntriesInEAT;
|
|
DWORD numFunctions = 0;
|
|
DWORD cextDataOnlyExports;
|
|
DWORD cextNoNameExports;
|
|
DWORD cextPrivate;
|
|
INT objFileWriteHandle;
|
|
PIMAGE pimage = NULL;
|
|
|
|
InternalError.Phase = "DefLibMain";
|
|
|
|
// pimage is the deflib pimage
|
|
InitImage(&pimage, pimgObj->imaget);
|
|
pimage->ImgFileHdr = pimgObj->ImgFileHdr;
|
|
pimage->ImgOptHdr = pimgObj->ImgOptHdr;
|
|
pimage->Switch = pimgObj->Switch;
|
|
pimage->SwitchInfo = pimgObj->SwitchInfo;
|
|
|
|
// Initialize the contribution manager
|
|
|
|
ContribInit(&pmodLinkerDefined);
|
|
|
|
pimageDeflib = pimage;
|
|
|
|
fPass1 = (ObjectFilenameArguments.Count || ArchiveFilenameArguments.Count);
|
|
|
|
if (fPass1 && (pimage->ImgFileHdr.Machine == IMAGE_FILE_MACHINE_M68K)) {
|
|
Fatal(NULL, MACDLLOBJECT);
|
|
}
|
|
|
|
if (ObjectFilenameArguments.Count) {
|
|
VerifyObjects(pimage);
|
|
}
|
|
|
|
pimage->ImgOptHdr.ImageBase = 0;
|
|
|
|
if (pimage->ImgFileHdr.Machine == IMAGE_FILE_MACHINE_UNKNOWN) {
|
|
// If we don't have a machine type yet, shamelessly default to host
|
|
|
|
pimage->ImgFileHdr.Machine = wDefaultMachine;
|
|
Warning(NULL, HOSTDEFAULT, szHostDefault);
|
|
}
|
|
|
|
switch (pimage->ImgFileHdr.Machine) {
|
|
case IMAGE_FILE_MACHINE_I386 :
|
|
ThunkInfo = &i386ThunkInfo;
|
|
if (!fPass1) {
|
|
PrependUnderscore = TRUE;
|
|
}
|
|
SkipUnderscore = TRUE;
|
|
CvCompile.bMachine = 0x03; /* CV_CFL_80386 */
|
|
break;
|
|
|
|
case IMAGE_FILE_MACHINE_R3000 :
|
|
ThunkInfo = &R3000ThunkInfo;
|
|
CvCompile.bMachine = 0x10; /* CV_CFL_MIPSR4000 */
|
|
break;
|
|
|
|
case IMAGE_FILE_MACHINE_R4000 :
|
|
ThunkInfo = &R4000ThunkInfo;
|
|
CvCompile.bMachine = 0x10; /* CV_CFL_MIPSR4000 */
|
|
break;
|
|
|
|
case IMAGE_FILE_MACHINE_ALPHA :
|
|
ThunkInfo = &AlphaThunkInfo;
|
|
CvCompile.bMachine = 0x30; /* CV_CFL_ALPHA */
|
|
break;
|
|
|
|
case IMAGE_FILE_MACHINE_POWERPC :
|
|
ThunkInfo = &PpcThunkInfo;
|
|
CvCompile.bMachine = 0x40; /* CV_CFL_PPC601 */
|
|
break;
|
|
|
|
case IMAGE_FILE_MACHINE_M68K :
|
|
ThunkInfo = &m68kLargeThunkInfo;
|
|
if (!fPass1) {
|
|
PrependUnderscore = TRUE;
|
|
}
|
|
SkipUnderscore = TRUE;
|
|
CvCompile.bMachine = 0x20; /* CV_CFL_M68000 */
|
|
break;
|
|
|
|
case IMAGE_FILE_MACHINE_MPPC_601 :
|
|
ThunkInfo = NULL;
|
|
if (!fPass1) {
|
|
PrependUnderscore = TRUE;
|
|
}
|
|
SkipUnderscore = TRUE;
|
|
CvCompile.bMachine = 0x40; /* CV_CFL_PPC601 */
|
|
break;
|
|
|
|
default :
|
|
Fatal(NULL, NOMACHINESPECIFIED);
|
|
}
|
|
|
|
if ((pimage->ImgFileHdr.Machine == IMAGE_FILE_MACHINE_M68K) ||
|
|
(pimage->ImgFileHdr.Machine == IMAGE_FILE_MACHINE_MPPC_601)) {
|
|
NextMember = 0;
|
|
pimage->ImgFileHdr.SizeOfOptionalHeader = 0;
|
|
} else {
|
|
// three extra members: import descriptor, null import descriptor, null thunk.
|
|
NextMember = 3;
|
|
}
|
|
|
|
csym = NextMember;
|
|
|
|
if (fPowerMac &&
|
|
(dwMaxCurrentVer != 0 || dwMinOldAPIVer != UINT_MAX)) {
|
|
char szDirective[MAXDIRECTIVESIZE];
|
|
char szVersionBuf[11];
|
|
// Put the version number of the shared library as
|
|
// directives in .EXP file
|
|
strcpy(szDirective, "/IMPORT:CurrentVer=");
|
|
strcat(szDirective, _itoa(dwMaxCurrentVer, szVersionBuf, 10));
|
|
strcat(szDirective, ",OldAPIVer=");
|
|
strcat(szDirective,
|
|
_itoa(dwMinOldAPIVer == UINT_MAX ? 0 : dwMinOldAPIVer, szVersionBuf, 10));
|
|
CreateDirective(szDirective);
|
|
}
|
|
|
|
// Parse the definition file if specified.
|
|
|
|
if (DefFilename[0] != '\0') {
|
|
ParseDefinitionFile(pimage, DefFilename);
|
|
}
|
|
|
|
// Make sure EmitExternals doesn't ignore symbols (ie, Debug:none).
|
|
|
|
pimage->Switch.Link.DebugInfo = Partial;
|
|
|
|
// If object files were specified, then do fuzzy lookup of names.
|
|
|
|
if (fPass1) {
|
|
WORD i;
|
|
PARGUMENT_LIST argument;
|
|
|
|
// UNDONE
|
|
// TEMP HACK!. move all objs/libs to filename list and free the objs
|
|
// and libs list before invoking pass1. AZK.
|
|
|
|
for (i = 0, argument = ObjectFilenameArguments.First;
|
|
i < ObjectFilenameArguments.Count;
|
|
i++, argument = argument->Next) {
|
|
|
|
AddArgumentToList(&FilenameArguments, argument->OriginalName, argument->ModifiedName);
|
|
}
|
|
|
|
FreeArgumentList(&ObjectFilenameArguments);
|
|
|
|
for (i = 0, argument = ArchiveFilenameArguments.First;
|
|
i < ArchiveFilenameArguments.Count;
|
|
i++, argument = argument->Next) {
|
|
|
|
AddArgumentToList(&FilenameArguments, argument->OriginalName, argument->ModifiedName);
|
|
}
|
|
|
|
FreeArgumentList(&ArchiveFilenameArguments);
|
|
|
|
Pass1(pimgObj);
|
|
|
|
// Handle all -export options which were seen on the command line ...
|
|
|
|
for (i = 0, argument = ExportSwitches.First;
|
|
i < ExportSwitches.Count;
|
|
i++, argument = argument->Next)
|
|
{
|
|
ParseExportDirective(argument->OriginalName, pimage,
|
|
argument->ModifiedName != NULL,
|
|
argument->ModifiedName);
|
|
}
|
|
|
|
FuzzyLookup(pimage->pst, pimgObj->pst, pimgObj->libs.plibHead, SkipUnderscore);
|
|
|
|
PrintUndefinedExternals(pimage->pst);
|
|
|
|
if (UndefinedSymbols) {
|
|
Fatal(OutFilename, UNDEFINEDEXTERNALS, UndefinedSymbols);
|
|
}
|
|
|
|
if (BadFuzzyMatch) {
|
|
Fatal(NULL, FAILEDFUZZYMATCH);
|
|
}
|
|
|
|
FreeBlk(&pimgObj->pst->blkStringTable);
|
|
}
|
|
|
|
// We now know the output filename, if we didn't before.
|
|
|
|
if (OutFilename == NULL) {
|
|
Fatal(NULL, NOOUTPUTFILE);
|
|
}
|
|
|
|
_splitpath(OutFilename, szDrive, szDir, szFname, NULL);
|
|
_makepath(szExportFilename, szDrive, szDir, szFname, "exp");
|
|
|
|
// Make sure our two output files don't have the same name
|
|
|
|
if (_tcsicmp(OutFilename, szExportFilename) == 0) {
|
|
Fatal(NULL, DUPLICATEIMPLIB, OutFilename);
|
|
}
|
|
|
|
if (fPass1) {
|
|
CheckDupFilename(OutFilename, FilenameArguments.First);
|
|
|
|
CheckDupFilename(szExportFilename, FilenameArguments.First);
|
|
} else {
|
|
CheckDupFilename(OutFilename, ObjectFilenameArguments.First);
|
|
CheckDupFilename(OutFilename, ArchiveFilenameArguments.First);
|
|
|
|
CheckDupFilename(szExportFilename, ObjectFilenameArguments.First);
|
|
CheckDupFilename(szExportFilename, ArchiveFilenameArguments.First);
|
|
}
|
|
|
|
// Allow for inserts into symbol table
|
|
|
|
AllowInserts(pimage->pst);
|
|
|
|
if (SmallestOrdinal == 0) {
|
|
// If no ordinals have been assigned, start assigning from 1.
|
|
|
|
SmallestOrdinal = 1;
|
|
}
|
|
|
|
// Save filename minus extension as DLL name if name wasn't given in def file.
|
|
|
|
if (pimage->Switch.Lib.DllName == NULL) {
|
|
if (DefFilename[0] != '\0') {
|
|
_splitpath(DefFilename, NULL, NULL, szFname, NULL);
|
|
} else {
|
|
_splitpath(OutFilename, NULL, NULL, szFname, NULL);
|
|
}
|
|
|
|
pimage->Switch.Lib.DllName = SzDup(szFname);
|
|
}
|
|
|
|
cchDllName = strlen(pimage->Switch.Lib.DllName);
|
|
|
|
// Set values in file header that is common to all members.
|
|
|
|
_tzset();
|
|
timeCur = fReproducible ? ((time_t) -1) : time(NULL);
|
|
|
|
pimage->ImgFileHdr.TimeDateStamp = (DWORD) timeCur;
|
|
|
|
// Calculate how many entries we need for the Export Address Table.
|
|
// Usually this will be the number of exported entries, but we
|
|
// have to check if the user assigned ordinals which aren't dense.
|
|
|
|
numFunctions = CountExternTable(pimage->pst, &cextDataOnlyExports, &cextNoNameExports, &cextPrivate);
|
|
if ((LargestOrdinal - SmallestOrdinal + 1) > numFunctions) {
|
|
// The gap between largest and smallest user assigned ordinal is larger than the
|
|
// number of exports. Even with linker assigned ordinals, this range will have
|
|
// unused entried. The size of the EAT is the size of this range.
|
|
|
|
numEntriesInEAT = LargestOrdinal - SmallestOrdinal + 1;
|
|
} else {
|
|
// The gap between largest and smallest user assigned ordinal is not larger than
|
|
// the number of exports. Linker assigned exports will fill this range and may
|
|
// extend beyond it. The size of the EAT is the number of exports.
|
|
|
|
numEntriesInEAT = numFunctions;
|
|
|
|
// If user assigned some ordinal values reset smallest so that we don't assign
|
|
// ordinal values greater than largest ...
|
|
|
|
if ((SmallestOrdinal + numFunctions) > _64K) {
|
|
// The range of ordinals starting with the lowest user assigned ordinal to the
|
|
// maximum ordinal of 65535 is too small to for the number of exports. Reset
|
|
// the smallest ordinal to the highest value that is sufficient.
|
|
|
|
SmallestOrdinal = _64K - numFunctions;
|
|
}
|
|
}
|
|
|
|
// Check if we have hit the exports limit
|
|
|
|
if (pimage->ImgFileHdr.Machine != IMAGE_FILE_MACHINE_M68K) {
|
|
if (numEntriesInEAT >= _64K) {
|
|
Fatal(NULL, EXPORTLIMITHIT);
|
|
}
|
|
}
|
|
|
|
if (pimage->ImgFileHdr.Machine == IMAGE_FILE_MACHINE_M68K) {
|
|
AssignMemberNums(pimage->pst);
|
|
|
|
// UNDONE: Should we subtract cextPrivate here or move the SkipLinkerDefines
|
|
// UNDONE: label up 1.
|
|
|
|
csym = numFunctions;
|
|
goto SkipLinkerDefines; // Skip code which doesn't apply to Mac
|
|
}
|
|
|
|
if (pimage->ImgFileHdr.Machine != IMAGE_FILE_MACHINE_MPPC_601) {
|
|
char *szImportDescriptor;
|
|
PEXTERNAL pext;
|
|
|
|
// For all exports, create a second external symbol named
|
|
// __imp_exportname which represents the export's IAT slot.
|
|
|
|
csym += CsymCreateThunkSymbols(pimage);
|
|
|
|
// Add the Import descriptor, Null Import descriptor, Null thunk data,
|
|
// and thunk routine to the symbol table so there included in
|
|
// the linker member.
|
|
|
|
szImportDescriptor = (char *) PvAlloc(sizeof(szDescriptorPrefix) + cchDllName);
|
|
strcpy(szImportDescriptor, szDescriptorPrefix);
|
|
strcat(szImportDescriptor, pimage->Switch.Lib.DllName);
|
|
|
|
pext = LookupExternSz(pimage->pst, szImportDescriptor, NULL);
|
|
SetDefinedExt(pext, TRUE, pimage->pst);
|
|
pext->Flags |= EXTERN_IMPLIB_ONLY;
|
|
pext->ArchiveMemberIndex = ARCHIVE + 0;
|
|
|
|
FreePv(szImportDescriptor);
|
|
|
|
// Create Null Import Desctiptor __NULL_IMPORT_DESCRIPTOR
|
|
|
|
pext = LookupExternSz(pimage->pst, szNullDescriptor, NULL);
|
|
SetDefinedExt(pext, TRUE, pimage->pst);
|
|
pext->Flags |= EXTERN_IMPLIB_ONLY;
|
|
pext->ArchiveMemberIndex = ARCHIVE + 1;
|
|
|
|
// Create Null Thunk Symbol \177DllName_NULL_THUNK_DATA
|
|
|
|
szNullThunkName = (char *) PvAlloc(1 + cchDllName + sizeof(szNullThunkSuffix));
|
|
|
|
szNullThunkName[0] = 0x7f; // Force end library search.
|
|
strcpy(szNullThunkName + 1, pimage->Switch.Lib.DllName);
|
|
strcat(szNullThunkName, szNullThunkSuffix);
|
|
|
|
pext = LookupExternSz(pimage->pst, szNullThunkName, NULL);
|
|
SetDefinedExt(pext, TRUE, pimage->pst);
|
|
pext->Flags |= EXTERN_IMPLIB_ONLY;
|
|
pext->ArchiveMemberIndex = ARCHIVE + 2;
|
|
}
|
|
|
|
// Don't count private or data only symbols.
|
|
|
|
csym += numFunctions - cextDataOnlyExports - cextPrivate;
|
|
|
|
SkipLinkerDefines:
|
|
MemberStart = (unsigned long *) PvAllocZ((ARCHIVE + NextMember) * sizeof(DWORD));
|
|
|
|
if (pimage->ImgFileHdr.Machine == IMAGE_FILE_MACHINE_M68K) {
|
|
BuildMacVTables(pimage->pst);
|
|
} else {
|
|
// Build the export address table flags.
|
|
// At the same time, make sure there the
|
|
// user didn't duplicate an ordinal number.
|
|
|
|
rgfOrdinalAssigned = (BYTE *) PvAllocZ(numEntriesInEAT);
|
|
|
|
IdentifyAssignedOrdinals(pimage->pst);
|
|
|
|
rgwHint = (WORD *) PvAlloc(numEntriesInEAT * sizeof(WORD));
|
|
}
|
|
|
|
if (pimage->imaget != imagetVXD) {
|
|
Message(BLDIMPLIB, OutFilename, szExportFilename);
|
|
fflush(stdout);
|
|
}
|
|
|
|
// Create the archive file and write the archive header.
|
|
|
|
FileWriteHandle = FileOpen(OutFilename, O_RDWR | O_BINARY | O_CREAT | O_TRUNC, S_IREAD | S_IWRITE);
|
|
FileWrite(FileWriteHandle, IMAGE_ARCHIVE_START, (DWORD)IMAGE_ARCHIVE_START_SIZE);
|
|
|
|
// Write the linker members.
|
|
|
|
EmitLinkerMembers(csym, pimage->pst);
|
|
|
|
if (pimage->Switch.Link.DebugType & CvDebug) {
|
|
CvObjName.wLen = (WORD) (sizeof(CvObjName) + sizeof(BYTE) + cchCvMemberName - sizeof(WORD));
|
|
|
|
// Calculate length at runtime in case version string is patched
|
|
|
|
cchLinkVer = (BYTE) strlen(szLinkVer);
|
|
|
|
CvCompile.wLen = (WORD) (sizeof(CvCompile) + sizeof(BYTE) + cchLinkVer - sizeof(WORD));
|
|
}
|
|
|
|
if (pimage->ImgFileHdr.Machine == IMAGE_FILE_MACHINE_M68K) {
|
|
EmitClientVTableRecs(pimage, MemberName);
|
|
|
|
goto SkipNonMacModules; // Skip code which doesn't apply to Mac
|
|
}
|
|
|
|
if (pimage->ImgFileHdr.Machine != IMAGE_FILE_MACHINE_MPPC_601) {
|
|
// Write the Import descriptor (one per library).
|
|
|
|
EmitImportDescriptor(ThunkInfo, pimage);
|
|
|
|
// Write the NULL Import descriptor (one per library).
|
|
|
|
EmitNullImportDescriptor(pimage);
|
|
|
|
// Write the NULL THUNK data (one per library).
|
|
|
|
EmitNullThunkData(pimage);
|
|
}
|
|
|
|
// Write the DLL export table (one per library).
|
|
|
|
EmitDllExportDirectory(pimage, numEntriesInEAT, numFunctions, cextNoNameExports, ThunkInfo,
|
|
fPass1);
|
|
|
|
FreePv(rgfOrdinalAssigned);
|
|
|
|
SkipNonMacModules:
|
|
// Write the thunks for each function.
|
|
|
|
EmitAllThunks(pimage, ThunkInfo);
|
|
|
|
if (pimage->ImgFileHdr.Machine != IMAGE_FILE_MACHINE_M68K) {
|
|
FreePv(rgwHint);
|
|
} else {
|
|
objFileWriteHandle = FileOpen(szExportFilename, O_RDWR | O_BINARY | O_CREAT | O_TRUNC, S_IREAD | S_IWRITE);
|
|
EmitMacDLLObject(objFileWriteHandle, pimage, szLibraryID, UserVersionNumber);
|
|
FileClose(objFileWriteHandle, TRUE);
|
|
}
|
|
|
|
CompleteLinkerMembers(pimage->pst);
|
|
|
|
FileCloseAll();
|
|
RemoveConvertTempFiles();
|
|
|
|
FreePv(MemberStart);
|
|
|
|
return(0);
|
|
}
|