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.
1571 lines
42 KiB
1571 lines
42 KiB
/***********************************************************************
|
|
* Microsoft (R) 32-Bit Incremental Linker
|
|
*
|
|
* Copyright (C) Microsoft Corp 1992-1996. All rights reserved.
|
|
*
|
|
* File: lib.cpp
|
|
*
|
|
* File Comments:
|
|
*
|
|
* The NT COFF Librarian.
|
|
*
|
|
***********************************************************************/
|
|
|
|
#include "link.h"
|
|
|
|
/* COMMON ARCHIVE FORMAT
|
|
|
|
ARCHIVE File Organization:
|
|
_____________________________________________
|
|
| IMAGE_ARCHIVE_START |
|
|
|---------------------------------------------|
|
|
| IMAGE_ARCHIVE_MEMBER_HEADER 1 |
|
|
|---------------------------------------------|
|
|
| ---Member 1 Contents--- |
|
|
| if IMAGE_LINKER_MEMBER, then contains the |
|
|
| External symbol directory for entire file |
|
|
| else object or text file |
|
|
|_____________________________________________|
|
|
| IMAGE_ARCHIVE_MEMBER_HEADER 2 |
|
|
|---------------------------------------------|
|
|
| ---Member 2 Contents--- |
|
|
| object or text file |
|
|
|---------------------------------------------|
|
|
| IMAGE_ARCHIVE_MEMBER_HEADER n |
|
|
|---------------------------------------------|
|
|
| ---Member n Contents--- |
|
|
|_____________________________________________|
|
|
|
|
|
|
NOTE: IMAGE_ARCHIVE_MEMBER_HEADER always starts on an even byte.
|
|
If a member's size is odd, a newline '\n' is used to
|
|
pad to even byte boundary.
|
|
*/
|
|
|
|
STATIC char *ExtractMemberName;
|
|
STATIC char *szFileList;
|
|
STATIC PLIB plibDummy;
|
|
STATIC BOOL fRemove;
|
|
|
|
|
|
VOID
|
|
LibrarianUsage(VOID)
|
|
{
|
|
if (fNeedBanner) {
|
|
PrintBanner();
|
|
}
|
|
|
|
puts("usage: LIB [options] [files]\n\n"
|
|
|
|
" options:\n\n"
|
|
|
|
" /DEBUGTYPE:CV\n"
|
|
" /DEF:[filename]\n"
|
|
" /EXPORT:symbol\n"
|
|
" /EXTRACT:membername\n"
|
|
" /IMPORT:[CURRENTVER=#][,][OLDCODEVER=#][,][OLDAPIVER=#]\n" // PowerMac
|
|
" /INCLUDE:symbol\n"
|
|
" /LIST[:filename]\n"
|
|
" /MAC:{INIT=symbol|TERM=symbol}\n"
|
|
" /MACHINE:{IX86|MIPS|ALPHA|PPC|M68K|MPPC}\n"
|
|
" /NAME:filename\n"
|
|
" /NODEFAULTLIB[:library]\n"
|
|
" /NOLOGO\n"
|
|
" /OUT:filename\n"
|
|
" /REMOVE:membername\n"
|
|
" /SUBSYSTEM:{NATIVE|WINDOWS|CONSOLE|POSIX}[,#[.#]]\n"
|
|
" /VERBOSE");
|
|
|
|
fflush(stdout);
|
|
exit(USAGE);
|
|
}
|
|
|
|
|
|
VOID
|
|
ProcessLibrarianSwitches(PIMAGE pimage)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Process all librarian switches.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
#define Switch (pimage->Switch)
|
|
#define ImageFileHdr (pimage->ImgFileHdr)
|
|
#define ImageOptionalHdr (pimage->ImgOptHdr)
|
|
|
|
WORD j, i;
|
|
PARGUMENT_LIST argument;
|
|
char szReproOption[_MAX_PATH + 20];
|
|
|
|
InternalError.Phase = "ProcessLibrarianSwitches";
|
|
|
|
for (i = 0, argument = SwitchArguments.First;
|
|
i < SwitchArguments.Count;
|
|
i++, argument = argument->Next,
|
|
((szReproDir != NULL)
|
|
? fprintf(pfileReproResponse, "/%s\n", szReproOption)
|
|
: 0)) {
|
|
|
|
// The default is to copy the option verbatim to the repro directory,
|
|
// but the option-handling code may change this if the option contains
|
|
// a filename.
|
|
|
|
strcpy(szReproOption, argument->OriginalName);
|
|
|
|
if (!strcmp(argument->OriginalName, "?")) {
|
|
LibrarianUsage();
|
|
assert(FALSE); // doesn't return
|
|
}
|
|
|
|
if (!_stricmp(argument->OriginalName, "verbose")) {
|
|
Verbose = TRUE;
|
|
continue;
|
|
}
|
|
|
|
if (!_strnicmp(argument->OriginalName, "name:", 4)) {
|
|
// valid for -def only, otherwise ignored
|
|
char szFname[_MAX_FNAME];
|
|
char szExt[_MAX_EXT];
|
|
|
|
_splitpath(&argument->OriginalName[5], NULL, NULL, szFname, szExt);
|
|
|
|
if (szFname[0] != '\0') {
|
|
Switch.Lib.DllName = SzDup(szFname);
|
|
}
|
|
|
|
if (szExt[0] != '\0') {
|
|
Switch.Lib.DllExtension = SzDup(szExt);
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
if (!_strnicmp(argument->OriginalName, "out:", 4)) {
|
|
OutFilename = argument->OriginalName+4;
|
|
|
|
if (szReproDir != NULL) {
|
|
char szFname[_MAX_FNAME];
|
|
char szExt[_MAX_EXT];
|
|
|
|
_splitpath(OutFilename, NULL, NULL, szFname, szExt);
|
|
sprintf(szReproOption, "out:.\\%s%s", szFname, szExt);
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if (!_strnicmp(argument->OriginalName, "def:", 4)) {
|
|
Switch.Lib.DefFile = TRUE;
|
|
if (argument->OriginalName[4] != '\0') {
|
|
DefFilename = argument->OriginalName+4;
|
|
|
|
if (szReproDir != NULL) {
|
|
char szFname[_MAX_FNAME];
|
|
char szExt[_MAX_EXT];
|
|
|
|
CopyFileToReproDir(DefFilename, FALSE);
|
|
_splitpath(DefFilename, NULL, NULL, szFname, szExt);
|
|
sprintf(szReproOption, "def:\".\\%s%s\"", szFname, szExt);
|
|
}
|
|
|
|
if (OutFilename == NULL) {
|
|
char szFname[_MAX_FNAME+4];
|
|
|
|
_splitpath(DefFilename, NULL, NULL, szFname, NULL);
|
|
strcat(szFname, ".lib");
|
|
OutFilename = SzDup(szFname);
|
|
}
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if (!_strnicmp(argument->OriginalName, "subsystem:", 10)) {
|
|
if (!_strnicmp(argument->OriginalName+10, "native", 6)) {
|
|
ImageOptionalHdr.Subsystem = IMAGE_SUBSYSTEM_NATIVE;
|
|
continue;
|
|
}
|
|
|
|
if (!_strnicmp(argument->OriginalName+10, "windows", 7)) {
|
|
ImageOptionalHdr.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_GUI;
|
|
continue;
|
|
}
|
|
|
|
if (!_strnicmp(argument->OriginalName+10, "console", 7)) {
|
|
ImageOptionalHdr.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI;
|
|
continue;
|
|
}
|
|
|
|
if (!_strnicmp(argument->OriginalName+10, "posix", 5)) {
|
|
ImageOptionalHdr.Subsystem = IMAGE_SUBSYSTEM_POSIX_CUI;
|
|
continue;
|
|
}
|
|
|
|
if (!_strnicmp(argument->OriginalName+10, "mmosa", 5)) {
|
|
ImageOptionalHdr.Subsystem = IMAGE_SUBSYSTEM_MMOSA;
|
|
continue;
|
|
}
|
|
|
|
Warning(NULL, UNKNOWNSUBSYSTEM, argument->OriginalName+10);
|
|
continue;
|
|
}
|
|
|
|
if (!_strnicmp(argument->OriginalName, "export:", 7)) {
|
|
AddArgumentToList(&ExportSwitches, argument->OriginalName+7, NULL);
|
|
continue;
|
|
}
|
|
|
|
if (!_strnicmp(argument->OriginalName, "import:", 7)) {
|
|
WORD iarpv = 0;
|
|
argument->parp = ParpParseSz(argument->OriginalName);
|
|
if (!FGotVal(argument->parp, iarpv)) {
|
|
Warning(NULL, SWITCHSYNTAX, argument->parp->szArg);
|
|
continue;
|
|
}
|
|
|
|
for (; iarpv < argument->parp->carpv; iarpv++) {
|
|
char *szKey = argument->parp->rgarpv[iarpv].szKeyword;
|
|
char *szVal = argument->parp->rgarpv[iarpv].szVal;
|
|
|
|
// SzDup is necessary here because we want things to get
|
|
// into the .ilk file
|
|
|
|
if (szKey != NULL && !_stricmp(szKey, "CURRENTVER")) {
|
|
if (_strspnp(szVal, "0123456789")) {
|
|
// Not appropriate number
|
|
|
|
Fatal(NULL, SWITCHSYNTAX, argument->parp->szArg);
|
|
} else {
|
|
AddVersionList(NULL, szVal, NULL, NULL);
|
|
}
|
|
} else if (szKey != NULL && !_stricmp(szKey, "OLDCODEVER")) {
|
|
if (_strspnp(szVal, "0123456789")) {
|
|
// Not appropriate number
|
|
|
|
Fatal(NULL, SWITCHSYNTAX, argument->parp->szArg);
|
|
} else {
|
|
AddVersionList(NULL, NULL, szVal, NULL);
|
|
}
|
|
} else if (szKey != NULL && !_stricmp(szKey, "OLDAPIVER")) {
|
|
if (_strspnp(szVal, "0123456789")) {
|
|
// Not appropriate number
|
|
|
|
Fatal(NULL, SWITCHSYNTAX, argument->parp->szArg);
|
|
} else {
|
|
AddVersionList(NULL, NULL, NULL, szVal);
|
|
}
|
|
} else {
|
|
Fatal(NULL, SWITCHSYNTAX, argument->parp->szArg);
|
|
}
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if (!_strnicmp(argument->OriginalName, "include:", 8)) {
|
|
const char *name;
|
|
|
|
name = argument->OriginalName+8;
|
|
|
|
LookupExternSz(pimage->pst, name, NULL);
|
|
continue;
|
|
}
|
|
|
|
if (!_strnicmp(argument->OriginalName, "mac:", 4)) {
|
|
WORD iarpv = 0;
|
|
argument->parp = ParpParseSz(argument->OriginalName);
|
|
|
|
if (!FGotVal(argument->parp, iarpv)) {
|
|
Warning(NULL, SWITCHSYNTAX, argument->parp->szArg);
|
|
continue;
|
|
}
|
|
|
|
for (; iarpv < argument->parp->carpv; iarpv++) {
|
|
char *szKey = argument->parp->rgarpv[iarpv].szKeyword;
|
|
char *szVal = argument->parp->rgarpv[iarpv].szVal;
|
|
|
|
// SzDup is necessary here because we want things to get
|
|
// into the .ilk file
|
|
if (szKey != NULL && !_stricmp(szKey, "init")) {
|
|
MppcSetInitRoutine(pimage, szVal);
|
|
SetOpt(pimage->SwitchInfo, OP_MACINIT);
|
|
} else if (szKey != NULL && !_stricmp(szKey, "term")) {
|
|
MppcSetTermRoutine(pimage, szVal);
|
|
SetOpt(pimage->SwitchInfo, OP_MACTERM);
|
|
} else {
|
|
Fatal(NULL, SWITCHSYNTAX, argument->parp->szArg);
|
|
}
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if (!_strnicmp(argument->OriginalName, "machine:", 8)) {
|
|
if (!_stricmp(argument->OriginalName+8, "I386") ||
|
|
!_stricmp(argument->OriginalName+8, "IX86") ||
|
|
!_stricmp(argument->OriginalName+8, "X86")) {
|
|
ImageFileHdr.Machine = IMAGE_FILE_MACHINE_I386;
|
|
continue;
|
|
}
|
|
|
|
if (!_stricmp(argument->OriginalName+8, "MIPS")) {
|
|
ImageFileHdr.Machine = IMAGE_FILE_MACHINE_R4000;
|
|
continue;
|
|
}
|
|
|
|
if (!_stricmp(argument->OriginalName+8, "ALPHA")) {
|
|
ImageFileHdr.Machine = IMAGE_FILE_MACHINE_ALPHA;
|
|
continue;
|
|
}
|
|
|
|
if (!_stricmp(argument->OriginalName+8, "PPC")) {
|
|
ImageFileHdr.Machine = IMAGE_FILE_MACHINE_POWERPC;
|
|
continue;
|
|
}
|
|
|
|
if (!_stricmp(argument->OriginalName+8, "M68K")) {
|
|
ImageFileHdr.Machine = IMAGE_FILE_MACHINE_M68K;
|
|
fM68K = TRUE;
|
|
continue;
|
|
}
|
|
|
|
if (!_stricmp(argument->OriginalName+8, "MPPC")) {
|
|
ImageFileHdr.Machine = IMAGE_FILE_MACHINE_MPPC_601;
|
|
fPowerMac = TRUE;
|
|
continue;
|
|
}
|
|
|
|
// The MMOSA team needs to be able to create import libraries
|
|
// that are compatible with the R3000. This is undocumented.
|
|
|
|
if (!_stricmp(argument->OriginalName+8, "R3000")) {
|
|
ImageFileHdr.Machine = IMAGE_FILE_MACHINE_R3000;
|
|
continue;
|
|
}
|
|
|
|
if (!_stricmp(argument->OriginalName+8, "MIPSR10")) {
|
|
ImageFileHdr.Machine = IMAGE_FILE_MACHINE_R10000;
|
|
continue;
|
|
}
|
|
|
|
Warning(NULL, UNKNOWNRESPONSE, argument->OriginalName+8, "IX86, MIPS, ALPHA, PPC, M68K, or MPPC");
|
|
continue;
|
|
}
|
|
|
|
if (!_stricmp(argument->OriginalName, "nologo")) {
|
|
fNeedBanner = FALSE;
|
|
continue;
|
|
}
|
|
|
|
j = 0;
|
|
if (!_strnicmp(argument->OriginalName, "debugtype:", 10)) {
|
|
j += 10;
|
|
if (!_strnicmp(argument->OriginalName+j, "coff", 4)) {
|
|
Switch.Link.DebugType = (DEBUG_TYPE) (CoffDebug | FpoDebug);
|
|
} else if (!_strnicmp(argument->OriginalName+j, "cv", 2)) {
|
|
Switch.Link.DebugType = (DEBUG_TYPE) (CvDebug | FpoDebug);
|
|
} else if (!_strnicmp(argument->OriginalName+j, "both", 4)) {
|
|
Switch.Link.DebugType = (DEBUG_TYPE) (CoffDebug | CvDebug | FpoDebug);
|
|
} else {
|
|
Fatal(NULL, SWITCHSYNTAX, argument->OriginalName);
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if (!_strnicmp(argument->OriginalName, "remove:", 7)) {
|
|
fRemove = TRUE;
|
|
continue;
|
|
}
|
|
|
|
if (!_strnicmp(argument->OriginalName, "list:", 5)) {
|
|
Switch.Lib.List = TRUE;
|
|
|
|
if (argument->OriginalName[5] != '\0') {
|
|
|
|
szFileList = argument->OriginalName + 5;
|
|
|
|
if (szReproDir != NULL) {
|
|
char szFname[_MAX_FNAME];
|
|
char szExt[_MAX_EXT];
|
|
|
|
_splitpath(szFileList, NULL, NULL, szFname, szExt);
|
|
sprintf(szReproOption, "list:.\\%s%s", szFname, szExt);
|
|
}
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
if (!_stricmp(argument->OriginalName, "list")) {
|
|
Switch.Lib.List = TRUE;
|
|
continue;
|
|
}
|
|
|
|
if (!_strnicmp(argument->OriginalName, "extract:", 8)) {
|
|
if (!ArchiveFilenameArguments.First) {
|
|
Fatal(NULL, NOLIBRARYFILE);
|
|
}
|
|
ExtractMemberName = argument->OriginalName+8;
|
|
continue;
|
|
}
|
|
|
|
if (!_stricmp(argument->OriginalName, "vxd")) {
|
|
// VXD implies MACHINE:IX86
|
|
|
|
ImageFileHdr.Machine = IMAGE_FILE_MACHINE_I386;
|
|
continue;
|
|
}
|
|
|
|
if (!_strnicmp(argument->OriginalName, "ignore:", 7)) {
|
|
char *pMinus;
|
|
int range;
|
|
int last;
|
|
char *token;
|
|
|
|
token = strtok(argument->OriginalName+7,",");
|
|
while (token) {
|
|
if ((pMinus = strchr(token,'-')) != NULL) {
|
|
*pMinus = '\0';
|
|
last = atoi(pMinus+1);
|
|
for (range = atoi(token); range <= last; range++) {
|
|
DisableWarning(range);
|
|
}
|
|
} else {
|
|
DisableWarning(atoi(token));
|
|
}
|
|
token = strtok(NULL, ",");
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
if (_stricmp(argument->OriginalName, "nodefaultlib") == 0) {
|
|
Switch.Link.fNoDefaultLibs = TRUE;
|
|
|
|
NoDefaultLib(NULL, &pimage->libs);
|
|
continue;
|
|
}
|
|
|
|
if (_strnicmp(argument->OriginalName, "nodefaultlib:", 13) == 0) {
|
|
NoDefaultLib(argument->OriginalName+13, &pimage->libs);
|
|
continue;
|
|
}
|
|
|
|
if (!_stricmp(argument->OriginalName, "Brepro")) {
|
|
fReproducible = TRUE;
|
|
continue;
|
|
}
|
|
|
|
Warning(NULL, WARN_UNKNOWN_SWITCH, argument->OriginalName);
|
|
}
|
|
|
|
#undef Switch
|
|
#undef ImageFileHdr
|
|
#undef ImageOptionalHdr
|
|
}
|
|
|
|
|
|
VOID
|
|
ListLibrary(PLIB plib)
|
|
{
|
|
FILE *pfileList = stdout;
|
|
ENM_MOD enm_mod;
|
|
|
|
InternalError.Phase = "ListLibrary";
|
|
|
|
if (szFileList) {
|
|
if (!(pfileList = fopen(szFileList, "w"))) {
|
|
Fatal(NULL, CANTOPENFILE, szFileList);
|
|
}
|
|
}
|
|
|
|
InitEnmMod(&enm_mod, plib);
|
|
while (FNextEnmMod(&enm_mod)) {
|
|
fprintf(pfileList, "%s\n", SzOrigFilePMOD(enm_mod.pmod));
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
ExtractMember(PIMAGE pimage)
|
|
{
|
|
ENM_LIB enm_lib;
|
|
PLIB plib;
|
|
DWORD foCur;
|
|
DWORD foMax;
|
|
|
|
InternalError.Phase = "ExtractMember";
|
|
|
|
InitEnmLib(&enm_lib, pimage->libs.plibHead);
|
|
|
|
if (!FNextEnmLib(&enm_lib)) {
|
|
assert(0);
|
|
}
|
|
|
|
EndEnmLib(&enm_lib);
|
|
|
|
plib = enm_lib.plib;
|
|
|
|
assert(!plib->plibNext);
|
|
|
|
FileReadHandle = FileOpen(plib->szName, O_RDONLY | O_BINARY, 0);
|
|
|
|
assert(plib->rgbST);
|
|
|
|
foCur = IMAGE_ARCHIVE_START_SIZE;
|
|
foMax = FileLength(FileReadHandle);
|
|
|
|
while (foCur < foMax) {
|
|
IMAGE_ARCHIVE_MEMBER_HEADER member_header;
|
|
DWORD cbMember;
|
|
const char *szMemberName;
|
|
|
|
FileSeek(FileReadHandle, foCur, SEEK_SET);
|
|
FileRead(FileReadHandle, &member_header, sizeof(IMAGE_ARCHIVE_MEMBER_HEADER));
|
|
|
|
foCur += sizeof(IMAGE_ARCHIVE_MEMBER_HEADER);
|
|
|
|
if (sscanf((char *) member_header.Size, "%ld", &cbMember) != 1) {
|
|
Fatal(plib->szName, BADLIBRARY);
|
|
}
|
|
|
|
szMemberName = ExpandMemberName(plib, (char *) member_header.Name);
|
|
if (!szMemberName) {
|
|
Fatal(plib->szName, BADLIBRARY);
|
|
}
|
|
|
|
if (!_tcsicmp(ExtractMemberName, szMemberName)) {
|
|
PVOID pvOutput;
|
|
|
|
if (OutFilename == NULL) {
|
|
char szFname[_MAX_FNAME + _MAX_EXT];
|
|
char szExt[_MAX_EXT];
|
|
|
|
_splitpath(szMemberName, NULL, NULL, szFname, szExt);
|
|
strcat(szFname, szExt);
|
|
OutFilename = SzDup(szFname);
|
|
}
|
|
|
|
FileWriteHandle =
|
|
FileOpen(OutFilename,
|
|
O_RDWR | O_BINARY | O_CREAT | O_TRUNC, S_IREAD | S_IWRITE);
|
|
|
|
pvOutput = PbMappedRegion(FileWriteHandle, 0, cbMember);
|
|
|
|
if (pvOutput != NULL) {
|
|
FileRead(FileReadHandle, pvOutput, cbMember);
|
|
} else {
|
|
DWORD cbRemaining;
|
|
DWORD cbCopy;
|
|
BYTE rgb[512];
|
|
|
|
cbRemaining = cbMember;
|
|
do {
|
|
cbCopy = (cbRemaining > 512) ? 512 : cbRemaining;
|
|
|
|
FileRead(FileReadHandle, rgb, cbCopy);
|
|
FileWrite(FileWriteHandle, rgb, cbCopy);
|
|
} while (cbRemaining -= cbCopy);
|
|
}
|
|
|
|
FreePLIB(&pimage->libs);
|
|
|
|
FileClose(FileWriteHandle, TRUE);
|
|
FileClose(FileReadHandle, FALSE);
|
|
|
|
// UNDONE: This isn't a nice way to exit
|
|
|
|
exit(0);
|
|
}
|
|
|
|
foCur = EvenByteAlign(foCur + cbMember);
|
|
}
|
|
|
|
FileClose(FileReadHandle, FALSE);
|
|
|
|
Warning(NULL, MEMBERNOTFOUND, ExtractMemberName);
|
|
}
|
|
|
|
|
|
VOID
|
|
AddArchiveArg(PIMAGE pimage, const char *szOriginalName)
|
|
{
|
|
PLIB plib;
|
|
DWORD foCur;
|
|
DWORD foMax;
|
|
|
|
InternalError.Phase = "AddArchiveArg";
|
|
|
|
plib = PlibNew(szOriginalName, 0, &pimage->libs);
|
|
|
|
_tcscpy(InternalError.CombinedFilenames, plib->szName);
|
|
|
|
FileReadHandle = FileOpen(plib->szName, O_RDONLY | O_BINARY, 0);
|
|
|
|
ReadSpecialLinkerInterfaceMembers(plib, pimage);
|
|
|
|
foCur = IMAGE_ARCHIVE_START_SIZE;
|
|
foMax = FileLength(FileReadHandle);
|
|
|
|
while (foCur < foMax) {
|
|
IMAGE_ARCHIVE_MEMBER_HEADER member_header;
|
|
DWORD cbMember;
|
|
|
|
FileSeek(FileReadHandle, foCur, SEEK_SET);
|
|
FileRead(FileReadHandle, &member_header, sizeof(IMAGE_ARCHIVE_MEMBER_HEADER));
|
|
|
|
foCur += sizeof(IMAGE_ARCHIVE_MEMBER_HEADER);
|
|
|
|
if (sscanf((char *) member_header.Size, "%ld", &cbMember) != 1) {
|
|
Fatal(plib->szName, BADLIBRARY);
|
|
}
|
|
|
|
// Don't create MODs for the special archive members
|
|
|
|
if (strncmp((char *) member_header.Name, IMAGE_ARCHIVE_LINKER_MEMBER, 16) &&
|
|
strncmp((char *) member_header.Name, IMAGE_ARCHIVE_LONGNAMES_MEMBER, 16)) {
|
|
IMAGE_FILE_HEADER imFileHdr;
|
|
const char *szMemberName;
|
|
|
|
szMemberName = ExpandMemberName(plib, (char *) member_header.Name);
|
|
|
|
if (!szMemberName) {
|
|
Fatal(szOriginalName, BADLIBRARY);
|
|
}
|
|
|
|
szMemberName = SzDup(szMemberName);
|
|
|
|
ReadFileHeader(FileReadHandle, &imFileHdr);
|
|
|
|
PmodNew(NULL,
|
|
szMemberName,
|
|
foCur,
|
|
imFileHdr.PointerToSymbolTable,
|
|
imFileHdr.NumberOfSymbols,
|
|
imFileHdr.SizeOfOptionalHeader,
|
|
imFileHdr.Characteristics,
|
|
imFileHdr.NumberOfSections,
|
|
plib,
|
|
NULL);
|
|
}
|
|
|
|
foCur = EvenByteAlign(foCur + cbMember);
|
|
}
|
|
|
|
FileClose(FileReadHandle, FALSE);
|
|
}
|
|
|
|
|
|
BOOL
|
|
FRemoveModule(PIMAGE pimage, const char *szModuleName)
|
|
{
|
|
ENM_LIB enmLib;
|
|
BOOL fFound = FALSE;
|
|
|
|
InternalError.Phase = "FRemoveModule";
|
|
|
|
InitEnmLib(&enmLib, pimage->libs.plibHead);
|
|
while (FNextEnmLib(&enmLib)) {
|
|
PMOD *ppmod; // this is sleazy wrt the enumerator
|
|
ENM_MOD enmMod;
|
|
|
|
if ((enmLib.plib->flags & LIB_LinkerDefined) != 0) {
|
|
// Ignore command line objects
|
|
|
|
continue;
|
|
}
|
|
|
|
InitEnmMod(&enmMod, enmLib.plib);
|
|
ppmod = &enmLib.plib->pmodNext;
|
|
while (FNextEnmMod(&enmMod)) {
|
|
if (!_tcsicmp(szModuleName, SzOrigFilePMOD(enmMod.pmod))) {
|
|
fFound = TRUE;
|
|
|
|
// Delete from list but keep searching this archive
|
|
|
|
*ppmod = enmMod.pmod->pmodNext;
|
|
} else {
|
|
ppmod = &enmMod.pmod->pmodNext;
|
|
}
|
|
}
|
|
}
|
|
|
|
return(fFound);
|
|
}
|
|
|
|
|
|
DWORD
|
|
CountExternTable(PST pst, DWORD *pcextDataOnly, DWORD *pcextNoName, DWORD *pcextPrivate)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Count the number of defined externals. This routine does not use the
|
|
sorted symbol table service since order is not important and this routine
|
|
is called before the symbol table is complete. Calling the symbol table
|
|
sort services requires that the symbol table be complete.
|
|
|
|
Arguments:
|
|
|
|
pst - Pointer to external structure.
|
|
|
|
Return Value:
|
|
|
|
Number of defined externals.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD cext;
|
|
DWORD cextDataOnly;
|
|
DWORD cextNoName;
|
|
DWORD cextPrivate;
|
|
PEXTERNAL pext;
|
|
|
|
InternalError.Phase = "CountExternTable";
|
|
|
|
cext = cextDataOnly = cextNoName = cextPrivate = 0;
|
|
|
|
InitEnumerateExternals(pst);
|
|
while ((pext = PexternalEnumerateNext(pst)) != NULL) {
|
|
if (pext->Flags & (EXTERN_DEFINED | EXTERN_ALIAS)) {
|
|
cext++;
|
|
|
|
if (pext->Flags & EXTERN_EXP_DATA) {
|
|
cextDataOnly++;
|
|
}
|
|
|
|
if (pext->Flags & EXTERN_EXP_NONAME) {
|
|
cextNoName++;
|
|
}
|
|
|
|
if (pext->Flags & EXTERN_PRIVATE) {
|
|
cextPrivate++;
|
|
}
|
|
}
|
|
}
|
|
|
|
TerminateEnumerateExternals(pst);
|
|
|
|
*pcextDataOnly = cextDataOnly;
|
|
|
|
if (pcextNoName != NULL) {
|
|
*pcextNoName = cextNoName;
|
|
}
|
|
|
|
if (pcextPrivate != NULL) {
|
|
*pcextPrivate = cextPrivate;
|
|
}
|
|
|
|
return(cext);
|
|
}
|
|
|
|
|
|
VOID
|
|
EmitStrings(PST pst, BOOL fNew)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Writes to FileWriteHandle all defined external symbol names
|
|
including the NULL.
|
|
|
|
Arguments:
|
|
|
|
pst - Pointer to external structure.
|
|
|
|
Index - If zero, write strings in sorted order, else write strings
|
|
with ArchiveMemberIndex equal index.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PPEXTERNAL rgpexternal;
|
|
DWORD cpexternal;
|
|
DWORD ipexternal;
|
|
|
|
InternalError.Phase = "EmitStrings";
|
|
|
|
rgpexternal = fNew ? RgpexternalByName(pst) : RgpexternalByModName(pst);
|
|
cpexternal = Cexternal(pst);
|
|
|
|
for (ipexternal = 0; ipexternal < cpexternal; ipexternal++) {
|
|
PEXTERNAL pexternal;
|
|
|
|
pexternal = rgpexternal[ipexternal];
|
|
|
|
if (pexternal->Flags & EXTERN_EXP_DATA) {
|
|
continue; // ignore these
|
|
}
|
|
|
|
if (pexternal->Flags & EXTERN_PRIVATE) {
|
|
continue; // ignore these
|
|
}
|
|
|
|
if (pexternal->Flags & (EXTERN_DEFINED | EXTERN_ALIAS)) {
|
|
const char *szName;
|
|
|
|
szName = SzNamePext(pexternal, pst);
|
|
|
|
// Write the name including the null terminator
|
|
|
|
FileWrite(FileWriteHandle, szName, strlen(szName)+1);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
WriteMemberHeader(const char *Filename, BOOL LongName, time_t ltime, unsigned short mode, LONG Size)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Fills in a member header with Filename, current Date/Time,
|
|
Mode and Size.
|
|
|
|
Arguments:
|
|
|
|
Filename - Pointer to file name.
|
|
|
|
Size - Size of the member in bytes.
|
|
|
|
LongName - If TRUE, Filename is an offset into the long filename table.
|
|
|
|
--*/
|
|
|
|
{
|
|
size_t len;
|
|
IMAGE_ARCHIVE_MEMBER_HEADER ArchiveMemberHeader;
|
|
|
|
InternalError.Phase = "WriteMemberHeader";
|
|
|
|
len = strlen(Filename);
|
|
|
|
if (LongName) {
|
|
ArchiveMemberHeader.Name[0] = '/';
|
|
memcpy(&ArchiveMemberHeader.Name[1], Filename, len);
|
|
++len;
|
|
} else {
|
|
memcpy(ArchiveMemberHeader.Name, Filename, len);
|
|
ArchiveMemberHeader.Name[len++] = '/';
|
|
}
|
|
|
|
// Pad name with spaces.
|
|
|
|
memset(ArchiveMemberHeader.Name+len, ' ', 16-len);
|
|
|
|
// Note: sprintf null terminates each field. This is ok because the
|
|
// fields are written in order so that the terminator is overwritten.
|
|
|
|
sprintf((char *) ArchiveMemberHeader.Date, "%-12ld", ltime);
|
|
|
|
memset(ArchiveMemberHeader.UserID, ' ', sizeof(ArchiveMemberHeader.UserID));
|
|
|
|
memset(ArchiveMemberHeader.GroupID, ' ', sizeof(ArchiveMemberHeader.GroupID));
|
|
|
|
sprintf((char *) ArchiveMemberHeader.Mode, "%-8ho", mode);
|
|
|
|
sprintf((char *) ArchiveMemberHeader.Size, "%-10ld", Size);
|
|
|
|
memcpy(ArchiveMemberHeader.EndHeader, IMAGE_ARCHIVE_END, 2);
|
|
|
|
FileWrite(FileWriteHandle, &ArchiveMemberHeader, sizeof(IMAGE_ARCHIVE_MEMBER_HEADER));
|
|
}
|
|
|
|
|
|
VOID
|
|
EmitOffsets(PST pst, BOOL fNew)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Writes to FileWriteHandle all offsets for defined external symbols.
|
|
The offset is the filepointer to the member that defines the symbol.
|
|
|
|
Arguments:
|
|
|
|
pst - Pointer to external structure.
|
|
|
|
Index - If zero, write offsets in sorted order, else write offsets
|
|
with ArchiveMemberIndex equal index.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PPEXTERNAL rgpexternal;
|
|
DWORD cpexternal;
|
|
DWORD ipexternal;
|
|
|
|
InternalError.Phase = "EmitOffsets";
|
|
rgpexternal = fNew ? RgpexternalByName(pst) : RgpexternalByModName(pst);
|
|
cpexternal = Cexternal(pst);
|
|
|
|
for (ipexternal = 0; ipexternal < cpexternal; ipexternal++) {
|
|
PEXTERNAL pexternal;
|
|
|
|
pexternal = rgpexternal[ipexternal];
|
|
|
|
if (pexternal->Flags & EXTERN_EXP_DATA) {
|
|
// ignore data-only exports ... don't export actual name
|
|
|
|
continue;
|
|
}
|
|
|
|
if (pexternal->Flags & EXTERN_PRIVATE) {
|
|
continue; // ignore these
|
|
}
|
|
|
|
if (pexternal->Flags & (EXTERN_DEFINED | EXTERN_ALIAS)) {
|
|
if (fNew) {
|
|
FileWrite(FileWriteHandle,
|
|
&pexternal->ArchiveMemberIndex, sizeof(WORD));
|
|
} else {
|
|
DWORD MachineIndependentInteger;
|
|
|
|
MachineIndependentInteger =
|
|
sputl(&MemberStart[pexternal->ArchiveMemberIndex]);
|
|
|
|
FileWrite(FileWriteHandle, &MachineIndependentInteger, sizeof(DWORD));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
DWORD
|
|
BuildLinkerMember(PIMAGE pimage, time_t timeCur, DWORD numberofMembers)
|
|
{
|
|
PST pst;
|
|
DWORD numSymbolsCount;
|
|
DWORD cextDataOnly;
|
|
DWORD MachineIndependentInteger;
|
|
DWORD cbObject;
|
|
DWORD NewLinkerMember;
|
|
|
|
InternalError.Phase = "BuildLinkerMember";
|
|
|
|
pst = pimage->pst;
|
|
|
|
// Build standard linker member (sorted by offsets).
|
|
|
|
numSymbolsCount = CountExternTable(pst, &cextDataOnly, NULL, NULL);
|
|
numSymbolsCount -= cextDataOnly; // ignore these entirely
|
|
|
|
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);
|
|
|
|
cbObject = FileTell(FileWriteHandle);
|
|
|
|
FileSeek(FileWriteHandle, IMAGE_ARCHIVE_START_SIZE, SEEK_SET);
|
|
WriteMemberHeader("",
|
|
FALSE,
|
|
timeCur,
|
|
0,
|
|
cbObject -
|
|
sizeof(IMAGE_ARCHIVE_MEMBER_HEADER) -
|
|
IMAGE_ARCHIVE_START_SIZE);
|
|
|
|
FileSeek(FileWriteHandle, cbObject, SEEK_SET);
|
|
|
|
if (cbObject & 1) {
|
|
FileWrite(FileWriteHandle, IMAGE_ARCHIVE_PAD, 1L);
|
|
}
|
|
|
|
// Build new linker member (sorted by symbol name).
|
|
|
|
NewLinkerMember = FileTell(FileWriteHandle);
|
|
FileSeek(FileWriteHandle, sizeof(IMAGE_ARCHIVE_MEMBER_HEADER), SEEK_CUR);
|
|
|
|
// Write number of offsets.
|
|
|
|
FileWrite(FileWriteHandle, &numberofMembers, sizeof(DWORD));
|
|
|
|
// Save room for offsets.
|
|
|
|
FileSeek(FileWriteHandle, numberofMembers * 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);
|
|
|
|
cbObject = FileTell(FileWriteHandle);
|
|
|
|
FileSeek(FileWriteHandle, NewLinkerMember, SEEK_SET);
|
|
WriteMemberHeader("",
|
|
FALSE,
|
|
timeCur,
|
|
0,
|
|
cbObject -
|
|
NewLinkerMember -
|
|
sizeof(IMAGE_ARCHIVE_MEMBER_HEADER));
|
|
|
|
FileSeek(FileWriteHandle, cbObject, SEEK_SET);
|
|
if (cbObject & 1) {
|
|
FileWrite(FileWriteHandle, IMAGE_ARCHIVE_PAD, 1L);
|
|
}
|
|
|
|
return(NewLinkerMember);
|
|
}
|
|
|
|
|
|
VOID
|
|
BuildLibrary(PIMAGE pimage, BOOL fUsingTempFile)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
time_t timeCur;
|
|
WORD i;
|
|
PST pstLongNames;
|
|
ENM_LIB enm_lib;
|
|
PLIB plib;
|
|
ENM_MOD enm_mod;
|
|
PMOD pmod;
|
|
PST pst = pimage->pst;
|
|
DWORD cbObject;
|
|
DWORD NewLinkerMember;
|
|
DWORD numberofMembers;
|
|
|
|
InternalError.Phase = "BuildSymbolTable";
|
|
|
|
_tzset();
|
|
timeCur = fReproducible ? ((time_t) -1) : time(NULL);
|
|
|
|
InitExternalSymbolTable(&pstLongNames, celementInChunkSym, cchunkInDirSym);
|
|
|
|
i = 0;
|
|
|
|
InitEnmLib(&enm_lib, pimage->libs.plibHead);
|
|
while (FNextEnmLib(&enm_lib)) {
|
|
plib = enm_lib.plib;
|
|
|
|
InitEnmMod(&enm_mod, plib);
|
|
while (FNextEnmMod(&enm_mod)) {
|
|
IMAGE_FILE_HEADER ImObjFileHdr;
|
|
|
|
pmod = enm_mod.pmod;
|
|
|
|
// Calculate size of long filename table.
|
|
|
|
if (strlen(SzOrigFilePMOD(pmod)) > 15) {
|
|
// Enter name into long name string table
|
|
|
|
LookupLongName(pstLongNames, SzOrigFilePMOD(pmod));
|
|
}
|
|
|
|
// Build symbol table
|
|
|
|
FileReadHandle = FileOpen(SzFilePMOD(pmod), O_RDONLY | O_BINARY, 0);
|
|
|
|
FileSeek(FileReadHandle, FoMemberPMOD(pmod), SEEK_SET);
|
|
|
|
FileRead(FileReadHandle, &ImObjFileHdr, sizeof(IMAGE_FILE_HEADER));
|
|
|
|
assert(!pimage->fIgnoreDirectives); // we don't save/restore
|
|
pimage->fIgnoreDirectives = TRUE; // ignore .drectve since we're just lib'ing
|
|
|
|
BuildExternalSymbolTable(pimage,
|
|
NULL,
|
|
pmod,
|
|
(WORD) (ARCHIVE + i),
|
|
ImObjFileHdr.Machine);
|
|
|
|
pimage->fIgnoreDirectives = FALSE;
|
|
|
|
FileClose(FileReadHandle, FALSE);
|
|
|
|
i++;
|
|
}
|
|
}
|
|
|
|
numberofMembers = i;
|
|
|
|
if (!numberofMembers) {
|
|
// There's nothing to build a library with. Possibly the user removed
|
|
// the last member.
|
|
|
|
if (fUsingTempFile) {
|
|
OutFilename = NULL;
|
|
}
|
|
|
|
Fatal(NULL, LASTLIBOBJECT);
|
|
}
|
|
|
|
InternalError.CombinedFilenames[0] = '\0';
|
|
|
|
DebugVerbose(DumpExternTable(pst));
|
|
|
|
FileWrite(FileWriteHandle, IMAGE_ARCHIVE_START, IMAGE_ARCHIVE_START_SIZE);
|
|
|
|
NewLinkerMember = BuildLinkerMember(pimage, timeCur, numberofMembers);
|
|
|
|
// Emit long filename table.
|
|
|
|
if (pstLongNames->blkStringTable.cb != 0) {
|
|
DWORD cbLongNames;
|
|
BYTE *pbLongNames;
|
|
|
|
InternalError.Phase = "EmitLongNames";
|
|
|
|
cbLongNames = pstLongNames->blkStringTable.cb - sizeof(DWORD);
|
|
pbLongNames = pstLongNames->blkStringTable.pb + sizeof(DWORD);
|
|
|
|
WriteMemberHeader("/", FALSE, timeCur, 0, cbLongNames);
|
|
|
|
FileWrite(FileWriteHandle, pbLongNames, cbLongNames);
|
|
|
|
if (cbLongNames & 1) {
|
|
FileWrite(FileWriteHandle, IMAGE_ARCHIVE_PAD, 1L);
|
|
}
|
|
}
|
|
|
|
// Emit each member.
|
|
|
|
InternalError.Phase = "EmitMember";
|
|
|
|
MemberStart = (DWORD *) PvAllocZ((numberofMembers+4) * sizeof(DWORD));
|
|
|
|
i = 0;
|
|
|
|
InitEnmLib(&enm_lib, pimage->libs.plibHead);
|
|
while (FNextEnmLib(&enm_lib)) {
|
|
plib = enm_lib.plib;
|
|
|
|
InitEnmMod(&enm_mod, plib);
|
|
while (FNextEnmMod(&enm_mod)) {
|
|
const char *szName;
|
|
BOOL fLongName;
|
|
char szLongName[16];
|
|
time_t timeMember;
|
|
unsigned short modeMember;
|
|
DWORD cbMember;
|
|
PVOID pvOutput;
|
|
|
|
pmod = enm_mod.pmod;
|
|
|
|
DebugVerbose(printf("Appending %s\n", SzOrigFilePMOD(pmod)));
|
|
|
|
szName = SzOrigFilePMOD(pmod);
|
|
|
|
fLongName = (strlen(szName) > 15);
|
|
|
|
if (fLongName) {
|
|
// Lookup name into long name string table
|
|
|
|
_ultoa(LookupLongName(pstLongNames, szName) - sizeof(DWORD), szLongName, 10);
|
|
szName = szLongName;
|
|
}
|
|
|
|
FileReadHandle = FileOpen(SzFilePMOD(pmod), O_RDONLY | O_BINARY, 0);
|
|
|
|
if (FIsLibPMOD(pmod)) {
|
|
IMAGE_ARCHIVE_MEMBER_HEADER member_header;
|
|
|
|
FileSeek(FileReadHandle, FoMemberPMOD(pmod) - sizeof(IMAGE_ARCHIVE_MEMBER_HEADER), SEEK_SET);
|
|
FileRead(FileReadHandle, &member_header, sizeof(IMAGE_ARCHIVE_MEMBER_HEADER));
|
|
|
|
if (sscanf((char *) member_header.Date, "%ld", &timeMember) != 1) {
|
|
timeMember = timeCur;
|
|
}
|
|
|
|
if (sscanf((char *) member_header.Mode, "%ho", &modeMember) != 1) {
|
|
modeMember = 0;
|
|
}
|
|
|
|
if (sscanf((char *) member_header.Size, "%ld", &cbMember) != 1) {
|
|
Fatal(plib->szName, BADLIBRARY);
|
|
}
|
|
} else {
|
|
struct _stat statfile;
|
|
|
|
if (_stat(SzFilePMOD(pmod), &statfile) == -1) {
|
|
timeMember = timeCur;
|
|
modeMember = 0;
|
|
} else {
|
|
timeMember = statfile.st_mtime;
|
|
modeMember = statfile.st_mode;
|
|
}
|
|
|
|
cbMember = FileLength(FileReadHandle);
|
|
}
|
|
|
|
MemberStart[i+1] = FileTell(FileWriteHandle);
|
|
|
|
WriteMemberHeader(szName, fLongName, timeMember, modeMember, cbMember);
|
|
|
|
pvOutput = PbMappedRegion(FileWriteHandle, MemberStart[i+1] + sizeof(IMAGE_ARCHIVE_MEMBER_HEADER), cbMember);
|
|
|
|
if (pvOutput != NULL) {
|
|
FileRead(FileReadHandle, pvOutput, cbMember);
|
|
|
|
FileSeek(FileWriteHandle, cbMember, SEEK_CUR);
|
|
} else {
|
|
DWORD cbRemaining;
|
|
DWORD cbCopy;
|
|
BYTE rgb[512];
|
|
|
|
cbRemaining = cbMember;
|
|
do {
|
|
cbCopy = (cbRemaining > 512) ? 512 : cbRemaining;
|
|
|
|
FileRead(FileReadHandle, rgb, cbCopy);
|
|
FileWrite(FileWriteHandle, rgb, cbCopy);
|
|
} while (cbRemaining -= cbCopy);
|
|
}
|
|
|
|
if (cbMember & 1) {
|
|
FileWrite(FileWriteHandle, IMAGE_ARCHIVE_PAD, 1L);
|
|
}
|
|
|
|
FileClose(FileReadHandle, FALSE);
|
|
|
|
i++;
|
|
}
|
|
}
|
|
|
|
assert(i == numberofMembers);
|
|
|
|
FreeExternalSymbolTable(&pstLongNames);
|
|
|
|
// Finish writing offsets.
|
|
|
|
if (Cexternal(pst)) {
|
|
InternalError.Phase = "EmitOffsets";
|
|
|
|
cbObject = IMAGE_ARCHIVE_START_SIZE+sizeof(IMAGE_ARCHIVE_MEMBER_HEADER)+sizeof(DWORD);
|
|
FileSeek(FileWriteHandle, cbObject, SEEK_SET);
|
|
|
|
EmitOffsets(pst, FALSE);
|
|
|
|
FileSeek(FileWriteHandle, NewLinkerMember+sizeof(IMAGE_ARCHIVE_MEMBER_HEADER)+sizeof(DWORD), SEEK_SET);
|
|
FileWrite(FileWriteHandle, MemberStart+1, numberofMembers * sizeof(DWORD));
|
|
|
|
// Skip over number of symbols.
|
|
|
|
FileSeek(FileWriteHandle, sizeof(DWORD), SEEK_CUR);
|
|
|
|
// Write indexes.
|
|
|
|
EmitOffsets(pst, TRUE);
|
|
}
|
|
|
|
FreePv(MemberStart);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
MainFunc
|
|
LibrarianMain(int Argc, char *Argv[])
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Librarian entrypoint.
|
|
|
|
Arguments:
|
|
|
|
Argc - Standard C argument count.
|
|
|
|
Argv - Standard C argument strings.
|
|
|
|
Return Value:
|
|
|
|
0 Library function was successful.
|
|
!0 Librarian error index.
|
|
|
|
--*/
|
|
|
|
{
|
|
WORD i;
|
|
BOOL usingTempFile = FALSE;
|
|
char nameTemplate[50];
|
|
const char *tempFilename;
|
|
PARGUMENT_LIST argument;
|
|
PIMAGE pimage;
|
|
ENM_LIB enm_lib;
|
|
PLIB plib = NULL;
|
|
char *szOutFullPath;
|
|
IMAGET imaget;
|
|
|
|
InternalError.Phase = "LibrarianMain";
|
|
|
|
if (Argc < 2) {
|
|
LibrarianUsage();
|
|
}
|
|
|
|
CheckForReproDir();
|
|
|
|
ParseCommandLine(Argc, Argv, NULL);
|
|
|
|
imaget = FScanSwitches("vxd") ? imagetVXD : imagetPE;
|
|
|
|
// Initialize image structure
|
|
|
|
InitImage(&pimage, imaget);
|
|
|
|
pimage->ImgOptHdr.Subsystem = IMAGE_SUBSYSTEM_UNKNOWN;
|
|
pimage->ImgFileHdr.Machine = IMAGE_FILE_MACHINE_UNKNOWN;
|
|
|
|
ProcessLibrarianSwitches(pimage);
|
|
|
|
if (fNeedBanner) {
|
|
PrintBanner();
|
|
}
|
|
|
|
if (pimage->Switch.Lib.DefFile) {
|
|
return(DefLibMain(pimage));
|
|
}
|
|
|
|
// If building a library from existing .obj's, preserve all debug info.
|
|
// (This is important when converting .obj's from OMF to COFF format.)
|
|
|
|
pimage->Switch.Link.DebugInfo = Full;
|
|
|
|
// Initialize contribution manager
|
|
|
|
ContribInit(&pmodLinkerDefined);
|
|
|
|
if (!ObjectFilenameArguments.Count &&
|
|
!ArchiveFilenameArguments.Count) {
|
|
|
|
if (szReproDir != NULL) {
|
|
CloseReproDir();
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
for (i = 0, argument = ArchiveFilenameArguments.First;
|
|
i < ArchiveFilenameArguments.Count;
|
|
i++, argument = argument->Next) {
|
|
|
|
if (szReproDir != NULL) {
|
|
CopyFileToReproDir(argument->OriginalName, TRUE);
|
|
}
|
|
|
|
AddArchiveArg(pimage, argument->OriginalName);
|
|
}
|
|
|
|
InternalError.CombinedFilenames[0] = '\0';
|
|
|
|
if (pimage->Switch.Lib.List) {
|
|
InitEnmLib(&enm_lib, pimage->libs.plibHead);
|
|
|
|
if (FNextEnmLib(&enm_lib)) {
|
|
ListLibrary(enm_lib.plib);
|
|
}
|
|
|
|
EndEnmLib(&enm_lib);
|
|
|
|
if (szReproDir != NULL) {
|
|
CloseReproDir();
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
if (ExtractMemberName) {
|
|
ExtractMember(pimage);
|
|
|
|
FreePLIB(&pimage->libs);
|
|
|
|
if (szReproDir != NULL) {
|
|
CloseReproDir();
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
|
|
// If first object isn't an object file, treat this as
|
|
// a archive rather than a library.
|
|
|
|
if (ObjectFilenameArguments.Count) {
|
|
PLIB plibCmdLineObjs;
|
|
|
|
VerifyObjects(pimage);
|
|
|
|
// Put the objects into archive list.
|
|
|
|
plibCmdLineObjs = PlibNew(NULL, 0, &pimage->libs);
|
|
plibCmdLineObjs->flags |= LIB_LinkerDefined;
|
|
|
|
for (i = 0, argument = ObjectFilenameArguments.First;
|
|
i < ObjectFilenameArguments.Count;
|
|
i++, argument = argument->Next) {
|
|
IMAGE_FILE_HEADER imFileHdr;
|
|
BOOL fNewObj;
|
|
|
|
if (szReproDir != NULL) {
|
|
CopyFileToReproDir(argument->ModifiedName, TRUE);
|
|
}
|
|
|
|
// Make sure object file isn't already part of library.
|
|
// If it is, do a replacement.
|
|
|
|
if (FRemoveModule(pimage, argument->OriginalName)) {
|
|
Message(REPLOBJ, argument->OriginalName);
|
|
}
|
|
|
|
_tcscpy(InternalError.CombinedFilenames, argument->OriginalName);
|
|
|
|
FileReadHandle = FileOpen(argument->ModifiedName, O_RDONLY | O_BINARY, 0);
|
|
ReadFileHeader(FileReadHandle, &imFileHdr);
|
|
FileClose(FileReadHandle, FALSE);
|
|
|
|
PmodNew(argument->ModifiedName,
|
|
argument->OriginalName,
|
|
0,
|
|
imFileHdr.PointerToSymbolTable,
|
|
imFileHdr.NumberOfSymbols,
|
|
imFileHdr.SizeOfOptionalHeader,
|
|
imFileHdr.Characteristics,
|
|
imFileHdr.NumberOfSections,
|
|
plibCmdLineObjs,
|
|
&fNewObj);
|
|
|
|
if (!fNewObj) {
|
|
Warning(argument->OriginalName, DUPLICATE_OBJECT);
|
|
}
|
|
}
|
|
|
|
InternalError.CombinedFilenames[0] = '\0';
|
|
}
|
|
|
|
// If requested, remove some members from the library.
|
|
|
|
if (fRemove) {
|
|
PARGUMENT_LIST parg;
|
|
WORD iarg;
|
|
|
|
for (iarg = 0, parg = SwitchArguments.First;
|
|
iarg < SwitchArguments.Count;
|
|
iarg++, parg = parg->Next) {
|
|
|
|
if (_strnicmp(parg->OriginalName, "remove:", 7) != 0) {
|
|
continue;
|
|
}
|
|
|
|
if (!FRemoveModule(pimage, parg->OriginalName+7)) {
|
|
Warning(NULL, MEMBERNOTFOUND, parg->OriginalName+7);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Select output filename as name of first object file or archive,
|
|
// if not specified by user.
|
|
|
|
if (OutFilename == NULL) {
|
|
char szFname[_MAX_FNAME + 4];
|
|
|
|
assert(pargFirst != NULL);
|
|
|
|
_splitpath(pargFirst->OriginalName, NULL, NULL, szFname, NULL);
|
|
strcat(szFname, ".lib");
|
|
|
|
OutFilename = SzDup(szFname);
|
|
}
|
|
|
|
// If updating an existing library, use a temporary file.
|
|
|
|
if ((szOutFullPath = _fullpath(NULL, OutFilename, 0)) == NULL) {
|
|
OutOfMemory();
|
|
}
|
|
|
|
tempFilename = OutFilename;
|
|
InitEnmLib(&enm_lib, pimage->libs.plibHead);
|
|
while (FNextEnmLib(&enm_lib)) {
|
|
char szLibFullPath[_MAX_PATH];
|
|
|
|
plib = enm_lib.plib;
|
|
|
|
_fullpath(szLibFullPath, plib->szName, _MAX_PATH);
|
|
|
|
if (_tcsicmp(szLibFullPath, szOutFullPath) == 0) {
|
|
usingTempFile = TRUE;
|
|
|
|
strncpy(nameTemplate, ToolName, 2);
|
|
nameTemplate[2] = '\0';
|
|
strcat(nameTemplate, "XXXXXX");
|
|
|
|
if ((tempFilename = _mktemp(nameTemplate)) == NULL) {
|
|
Fatal(NULL, CANTOPENFILE, "LIBTEMPFILE");
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
EndEnmLib(&enm_lib);
|
|
|
|
(free)(szOutFullPath);
|
|
|
|
FileWriteHandle = FileOpen(tempFilename,
|
|
O_RDWR | O_BINARY | O_CREAT | O_TRUNC, S_IREAD | S_IWRITE);
|
|
|
|
BuildLibrary(pimage, usingTempFile);
|
|
|
|
FileCloseAll();
|
|
RemoveConvertTempFiles();
|
|
|
|
if (usingTempFile) {
|
|
if (remove(OutFilename)) {
|
|
Fatal(NULL, CANTREMOVEFILE, OutFilename);
|
|
}
|
|
|
|
if (rename(tempFilename, OutFilename)) {
|
|
Fatal(NULL, CANTRENAMEFILE, OutFilename);
|
|
}
|
|
}
|
|
|
|
if (szReproDir != NULL) {
|
|
CloseReproDir();
|
|
}
|
|
|
|
return(0);
|
|
}
|