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

521 lines
9.8 KiB

/***********************************************************************
* Microsoft (R) 32-Bit Incremental Linker
*
* Copyright (C) Microsoft Corp 1992-95. All rights reserved.
*
* File: convert.cpp
*
* File Comments:
*
* Functions to verify and convert to COFF objects
*
***********************************************************************/
#include "link.h"
BOOL FConvertOmfToCoff(const char *, const char *);
VOID
ConvertAnOmf (
PARGUMENT_LIST argument
)
/*++
Routine Description:
Converts a single OMF file to COFF.
Arguments:
argument - has the name of file.
Return Value:
None.
--*/
{
char *szCoff;
if ((szCoff = _tempnam(NULL, "lnk")) == NULL) {
Fatal(NULL, CANTOPENFILE, "TEMPFILE");
}
argument->ModifiedName = SzDup(szCoff);
// UNDONE: fixfix for multiple builds
FileClose(FileOpen(argument->ModifiedName, O_RDWR | O_BINARY | O_CREAT | O_TRUNC, S_IREAD | S_IWRITE), TRUE);
(free)(szCoff);
if (!FConvertOmfToCoff(argument->OriginalName, argument->ModifiedName)) {
Fatal(argument->OriginalName, CONVERSIONERROR);
}
Warning(argument->OriginalName, CONVERT_OMF);
}
VOID
ConvertOmfToCoffObject (
PARGUMENT_LIST argument,
WORD *pwMachine
)
/*++
Routine Description:
Arguments:
pwMachine - ptr to machine type
Return Value:
None.
--*/
{
FileClose(FileReadHandle, TRUE);
ConvertAnOmf(argument);
FileReadHandle = FileOpen(argument->ModifiedName, O_RDONLY | O_BINARY, 0);
FileRead(FileReadHandle, pwMachine, sizeof(WORD));
}
VOID
ConvertResFile (
IN PARGUMENT_LIST argument,
WORD MachineType
)
/*++
Routine Description:
Converts 16-bit res file to 32-bit res file.
Arguments:
argument - The argument to process.
Return Value:
None.
--*/
{
const char *argv[7];
const char *szMachine;
char *szTempFile;
char szOutArg[7+_MAX_PATH];
char szInArg[2+_MAX_PATH];
int rc;
char szDir[_MAX_DIR];
char szDrive[_MAX_DRIVE];
char szCvtresPath[_MAX_PATH];
char *szCvtres;
if (MachineType == IMAGE_FILE_MACHINE_UNKNOWN) {
// If we don't have a machine type yet, shamelessly default to host
MachineType = wDefaultMachine;
Warning(NULL, HOSTDEFAULT, szHostDefault);
}
switch (MachineType) {
case IMAGE_FILE_MACHINE_I386 :
szMachine = "/machine:ix86";
break;
case IMAGE_FILE_MACHINE_R4000 :
case IMAGE_FILE_MACHINE_R10000 :
szMachine = "/machine:mips";
break;
case IMAGE_FILE_MACHINE_ALPHA :
szMachine = "/machine:alpha";
break;
case IMAGE_FILE_MACHINE_POWERPC :
szMachine = "/machine:ppc";
break;
case IMAGE_FILE_MACHINE_M68K :
case IMAGE_FILE_MACHINE_MPPC_601 :
Fatal(NULL, MACBADFILE, argument->OriginalName);
break;
default:
assert(FALSE);
}
if ((szTempFile = _tempnam(NULL, "lnk")) == NULL) {
Fatal(NULL, CANTOPENFILE, "TEMPFILE");
}
// UNDONE: fixfix for multiple builds
FileClose(FileOpen(szTempFile, O_RDWR | O_BINARY | O_CREAT | O_TRUNC, S_IREAD | S_IWRITE), TRUE);
argument->ModifiedName = SzDup(szTempFile);
(free)(szTempFile);
strcpy(szOutArg, "/out:");
strcat(szOutArg, "\"");
strcat(szOutArg, argument->ModifiedName);
strcat(szOutArg, "\"");
strcpy(szInArg, "\"");
strcat(szInArg, argument->OriginalName);
strcat(szInArg, "\"");
argv[0] = "cvtres";
argv[1] = szMachine;
argv[2] = "/nologo";
argv[3] = szOutArg;
argv[4] = "/readonly";
argv[5] = szInArg;
argv[6] = NULL;
fflush(NULL);
// Look for CVTRES.EXE in this the directory from which we were loaded
_splitpath(_pgmptr, szDrive, szDir, NULL, NULL);
_makepath(szCvtresPath, szDrive, szDir, "cvtres", ".exe");
if (_access(szCvtresPath, 0) == 0) {
// Run the CVTRES.EXE that we found
rc = _spawnv(P_WAIT, szCvtresPath, argv);
szCvtres = szCvtresPath;
} else {
// Run CVTRES.EXE from the path
rc = _spawnvp(P_WAIT, "cvtres.exe", argv);
szCvtres = "cvtres.exe";
}
if (rc != 0) {
// Distinguish between spawn failure and an inavlid RES file
if (rc == -1) {
Fatal(NULL, SPAWNFAILED, szCvtres);
}
Fatal(argument->OriginalName, CONVERSIONERROR);
}
}
VOID
ConvertResToCoffObject(
PARGUMENT_LIST argument,
WORD *pwMachine,
PIMAGE_FILE_HEADER pImgFileHdr
)
/*++
Routine Description:
Arguments:
pwMachine - ptr to machine type
Return Value:
None.
--*/
{
FileClose(FileReadHandle, TRUE);
ConvertResFile(argument, pImgFileHdr->Machine);
FileReadHandle = FileOpen(argument->ModifiedName, O_RDONLY | O_BINARY, 0);
FileRead(FileReadHandle, pwMachine, sizeof(WORD));
}
WORD
EnsureCoffObject (
PARGUMENT_LIST argument,
PIMAGE pimage
)
/*++
Routine Description:
Verifies that a single object is targeted for the same machine.
Arguments:
None.
Return Value:
None.
--*/
{
DWORD dw;
WORD machine;
// Read and then verify target environment.
FileSeek(FileReadHandle, 0L, SEEK_SET);
FileRead(FileReadHandle, &dw, sizeof(DWORD));
if ((BYTE) dw == THEADR) {
// If it is an OMF object convert to a COFF object right away.
ConvertOmfToCoffObject(argument, &machine);
} else if (dw == 0L) {
// This may be a 32 bit resource.
// UNDONE: It may also be a COFF object with IMAGE_FILE_MACHINE_UNKNOWN
// UNDONE: and no sections. Should we read more of the file to
// UNDONE: recognize it is a .RES file. There is a known 32 byte
// UNDONE: header on 32 bit .RES files.
ConvertResToCoffObject(argument, &machine, &pimage->ImgFileHdr);
} else {
machine = (WORD) dw;
switch (machine) {
case IMAGE_FILE_MACHINE_UNKNOWN :
case IMAGE_FILE_MACHINE_I386 :
case IMAGE_FILE_MACHINE_R3000 :
case IMAGE_FILE_MACHINE_R4000 :
case IMAGE_FILE_MACHINE_R10000 :
case IMAGE_FILE_MACHINE_ALPHA :
case IMAGE_FILE_MACHINE_POWERPC :
case IMAGE_FILE_MACHINE_M68K :
case IMAGE_FILE_MACHINE_MPPC_601 :
break;
default:
Fatal(argument->OriginalName, BAD_FILE);
break;
}
}
return(machine);
}
WORD
VerifyAnObject (
PARGUMENT_LIST argument,
PIMAGE pimage
)
/*++
Routine Description:
Verifies that a single object is targeted for the same machine.
Arguments:
None.
Return Value:
None.
--*/
{
WORD machine;
machine = EnsureCoffObject(argument, pimage);
if (machine == IMAGE_FILE_MACHINE_UNKNOWN) {
// Not specific to any particular machine
return machine;
}
if (pimage->ImgFileHdr.Machine == IMAGE_FILE_MACHINE_UNKNOWN) {
// Target machine hasn't been determined yet, so assign it.
// Test for the case where the user specified a MIPS resource first
// and the resource is stamped with a R3000 signature.
if (machine == IMAGE_FILE_MACHINE_R3000) {
machine = IMAGE_FILE_MACHINE_R4000;
}
pimage->ImgFileHdr.Machine = machine;
} else {
VerifyMachine(argument->OriginalName, machine, &pimage->ImgFileHdr);
}
return machine;
}
VOID
VerifyObjects (
PIMAGE pimage
)
/*++
Routine Description:
Loops thru all objects and verify there all targeted for the same machine.
Arguments:
None.
Return Value:
None.
--*/
{
WORD i;
PARGUMENT_LIST argument;
for (i = 0, argument = ObjectFilenameArguments.First;
i < ObjectFilenameArguments.Count;
i++, argument = argument->Next) {
FileReadHandle = FileOpen(argument->OriginalName, O_RDONLY | O_BINARY, 0);
VerifyAnObject(argument, pimage);
FileClose(FileReadHandle, FALSE);
}
}
VOID
ConvertOmfObjects(void)
/*++
Routine Description:
Loops thru all objects and converts INTEL OMF to COFF if need be.
Arguments:
fWarn: if true prints a warning for each object converted.
Return Value:
None.
--*/
{
WORD i;
PARGUMENT_LIST argument;
for (i = 0, argument = ObjectFilenameArguments.First;
i < ObjectFilenameArguments.Count;
i++, argument = argument->Next) {
BYTE b;
// Read first byte from file.
FileReadHandle = FileOpen(argument->OriginalName, O_RDONLY | O_BINARY, 0);
if (FileRead(FileReadHandle, &b, sizeof(BYTE)) != sizeof(BYTE)) {
Fatal(argument->OriginalName, BAD_FILE);
}
FileClose(FileReadHandle, FALSE);
// Check to see if object needs to be converted.
if (b == THEADR) {
ConvertAnOmf(argument);
}
}
}
VOID
RemoveConvertTempFilesPNL (
PNAME_LIST pnl
)
/*++
Routine Description:
Walks the list & removes any temp files.
Arguments:
pnl - pointer to the list.
Return Value:
None.
--*/
{
WORD i;
PARGUMENT_LIST argument;
for (i = 0, argument = pnl->First;
i < pnl->Count;
i++, argument = argument->Next) {
if (strcmp(argument->OriginalName, argument->ModifiedName)) {
if (remove(argument->ModifiedName) == -1) {
Fatal(NULL, CANTREMOVEFILE, argument->ModifiedName);
}
}
}
}
VOID
RemoveConvertTempFiles (
VOID
)
/*++
Routine Description:
Loops thru all objects and removes any temp files built for cvtomf & cvtres.
Arguments:
None.
Return Value:
None.
--*/
{
// walk the two lists and remove temp files.
RemoveConvertTempFilesPNL(&FilenameArguments);
RemoveConvertTempFilesPNL(&ObjectFilenameArguments);
}