[SPEC2DEF] Implement support for import symbol aliases

This commit is contained in:
Timo Kreuzer 2024-05-19 19:17:52 +03:00
parent bc2621812f
commit 60f4493a68
2 changed files with 113 additions and 9 deletions

View file

@ -317,11 +317,12 @@ function(generate_import_lib _libname _dllname _spec_file __version_arg)
set(_def_file ${CMAKE_CURRENT_BINARY_DIR}/${_libname}_implib.def)
set(_asm_stubs_file ${CMAKE_CURRENT_BINARY_DIR}/${_libname}_stubs.asm)
set(_asm_impalias_file ${CMAKE_CURRENT_BINARY_DIR}/${_libname}_impalias.asm)
# Generate the def and asm stub files
# Generate the def, asm stub and alias files
add_custom_command(
OUTPUT ${_asm_stubs_file} ${_def_file}
COMMAND native-spec2def --ms ${__version_arg} -a=${SPEC2DEF_ARCH} --implib -n=${_dllname} -d=${_def_file} -l=${_asm_stubs_file} ${CMAKE_CURRENT_SOURCE_DIR}/${_spec_file}
OUTPUT ${_asm_stubs_file} ${_def_file} ${_asm_impalias_file}
COMMAND native-spec2def --ms ${__version_arg} -a=${SPEC2DEF_ARCH} --implib -n=${_dllname} -d=${_def_file} -l=${_asm_stubs_file} -i=${_asm_impalias_file} ${CMAKE_CURRENT_SOURCE_DIR}/${_spec_file}
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${_spec_file} native-spec2def)
# Compile the generated asm stub file
@ -351,7 +352,7 @@ function(generate_import_lib _libname _dllname _spec_file __version_arg)
# By giving the import lib as an object input, LIB extracts the relevant object files and make a new library.
# This allows us to treat the implib as a regular static library
set_source_files_properties(${_libfile_tmp} PROPERTIES EXTERNAL_OBJECT TRUE)
add_library(${_libname} STATIC ${_libfile_tmp})
add_library(${_libname} STATIC ${_libfile_tmp} ${_asm_impalias_file})
set_target_properties(${_libname} PROPERTIES LINKER_LANGUAGE "C")
endfunction()
@ -364,7 +365,7 @@ if(ARCH STREQUAL "amd64")
elseif(ARCH STREQUAL "arm")
set(SPEC2DEF_ARCH arm)
elseif(ARCH STREQUAL "arm64")
add_definitions(/D__arm64__)
add_definitions(/D__arm64__)
set(SPEC2DEF_ARCH arm64)
else()
set(SPEC2DEF_ARCH i386)

View file

@ -85,6 +85,7 @@ enum
FL_NORELAY = 16,
FL_RET64 = 32,
FL_REGISTER = 64,
FL_IMPSYM = 128,
};
enum
@ -612,6 +613,11 @@ PrintName(FILE *fileDest, EXPORT *pexp, PSTRING pstr, int fDeco)
fprintf(fileDest, "%.*s@%d", nNameLength, pcName, pexp->nStackBytes);
}
}
else if (fDeco && (pexp->nCallingConvention == CC_CDECL) && gbMSComp)
{
/* Print with cdecl decoration */
fprintf(fileDest, "_%.*s", nNameLength, pcName);
}
else
{
/* Print the undecorated function name */
@ -685,7 +691,7 @@ OutputLine_def_GCC(FILE *fileDest, EXPORT *pexp)
DbgPrint("Got redirect '%.*s'\n", pexp->strTarget.len, pexp->strTarget.buf);
/* print the target name, don't decorate if it is external */
fprintf(fileDest, "=");
fprintf(fileDest, pexp->uFlags & FL_IMPSYM ? "==" : "=");
PrintName(fileDest, pexp, &pexp->strTarget, !fIsExternal);
}
else if (((pexp->uFlags & FL_STUB) || (pexp->nCallingConvention == CC_STUB)) &&
@ -747,6 +753,17 @@ OutputLine_def(FILE *fileDest, EXPORT *pexp)
return 1;
}
/* Handle import symbols */
if (pexp->uFlags & FL_IMPSYM)
{
/* Skip these, if we are not creating an import lib, or if this is MS */
if (!gbImportLib || gbMSComp)
{
DbgPrint("OutputLine_def: skipping import symbol '%.*s'...\n", pexp->strName.len, pexp->strName.buf);
return 1;
}
}
/* For MS linker, forwarded externs are managed via #pragma comment(linker,"/export:_data=org.data,DATA") */
if (gbMSComp && !gbImportLib && (pexp->nCallingConvention == CC_EXTERN) &&
(pexp->strTarget.buf != NULL) && !!ScanToken(pexp->strTarget.buf, '.'))
@ -790,6 +807,54 @@ OutputLine_def(FILE *fileDest, EXPORT *pexp)
return 1;
}
void
PrintNameOrImpName(FILE *fileDest, EXPORT *pexp, PSTRING pstr, int fDeco, int fImp)
{
if (fImp)
{
fprintf(fileDest, "__imp_");
}
PrintName(fileDest, pexp, pstr, fDeco);
}
void
OutputAlias(FILE *fileDest, EXPORT *pexp, int fImp)
{
if ((giArch == ARCH_ARM) || (giArch == ARCH_ARM64))
{
fprintf(fileDest, " IMPORT ");
PrintNameOrImpName(fileDest, pexp, &pexp->strName, 1, fImp);
fprintf(fileDest, ", WEAK ");
PrintNameOrImpName(fileDest, pexp, &pexp->strTarget, 1, fImp);
fprintf(fileDest, "\n");
}
else
{
fprintf(fileDest, " EXTERN ");
PrintNameOrImpName(fileDest, pexp, &pexp->strTarget, 1, fImp);
fprintf(fileDest, ":PROC\n ALIAS <");
PrintNameOrImpName(fileDest, pexp, &pexp->strName, 1, fImp);
fprintf(fileDest, "> = <");
PrintNameOrImpName(fileDest, pexp, &pexp->strTarget, 1, fImp);
fprintf(fileDest, ">\n");
}
}
int
OutputLine_implib_asm(FILE *fileDest, EXPORT *pexp)
{
if ((pexp->uFlags & FL_IMPSYM) == 0)
{
return 1;
}
OutputAlias(fileDest, pexp, 0);
OutputAlias(fileDest, pexp, 1);
return 1;
}
void
Fatalv(
const char* filename,
@ -1090,6 +1155,10 @@ ParseFile(char* pcStart, FILE *fileDest, unsigned *cExports)
{
exp.uFlags |= FL_ORDINAL | FL_NONAME;
}
else if (CompareToken(pc, "-impsym"))
{
exp.uFlags |= FL_IMPSYM;
}
else if (CompareToken(pc, "-ordinal"))
{
exp.uFlags |= FL_ORDINAL;
@ -1298,6 +1367,12 @@ ParseFile(char* pcStart, FILE *fileDest, unsigned *cExports)
Fatal(pszSourceFileName, nLine, pcLine, pc, 0, "Ordinal export without ordinal");
}
/* Check for import symbol without target */
if ((exp.uFlags & FL_IMPSYM) && (exp.strTarget.buf == NULL))
{
Fatal(pszSourceFileName, nLine, pcLine, pc, 1, "Import symbol without target");
}
/*
* Check for special handling of OLE exports, only when MSVC
* is not used, since otherwise this is handled by MS LINK.EXE.
@ -1395,6 +1470,7 @@ void usage(void)
" -l=<file> generate an asm lib stub\n"
" -d=<file> generate a def file\n"
" -s=<file> generate a stub file\n"
" -i=<file> generate an import alias file\n"
" --ms MSVC compatibility\n"
" -n=<name> name of the dll\n"
" --version=<version> Sets the version to create exports for\n"
@ -1408,6 +1484,7 @@ int main(int argc, char *argv[])
{
size_t nFileSize;
char *pszSource, *pszDefFileName = NULL, *pszStubFileName = NULL, *pszLibStubName = NULL;
char *pszImpLibAliasFileName = NULL;
const char* pszVersionOption = "--version=0x";
char achDllName[40];
FILE *file;
@ -1441,6 +1518,10 @@ int main(int argc, char *argv[])
{
pszStubFileName = argv[i] + 3;
}
else if (argv[i][1] == 'i' && argv[i][2] == '=')
{
pszImpLibAliasFileName = argv[i] + 3;
}
else if (argv[i][1] == 'n' && argv[i][2] == '=')
{
pszDllName = argv[i] + 3;
@ -1574,7 +1655,7 @@ int main(int argc, char *argv[])
file = fopen(pszDefFileName, "w");
if (!file)
{
fprintf(stderr, "error: could not open output file %s\n", argv[i + 1]);
fprintf(stderr, "error: could not open output file %s\n", pszDefFileName);
return -5;
}
@ -1595,7 +1676,7 @@ int main(int argc, char *argv[])
file = fopen(pszStubFileName, "w");
if (!file)
{
fprintf(stderr, "error: could not open output file %s\n", argv[i + 1]);
fprintf(stderr, "error: could not open output file %s\n", pszStubFileName);
return -5;
}
@ -1616,7 +1697,7 @@ int main(int argc, char *argv[])
file = fopen(pszLibStubName, "w");
if (!file)
{
fprintf(stderr, "error: could not open output file %s\n", argv[i + 1]);
fprintf(stderr, "error: could not open output file %s\n", pszLibStubName);
return -5;
}
@ -1632,6 +1713,28 @@ int main(int argc, char *argv[])
fclose(file);
}
if (pszImpLibAliasFileName)
{
/* Open output file */
file = fopen(pszImpLibAliasFileName, "w");
if (!file)
{
fprintf(stderr, "error: could not open output file %s\n", pszImpLibAliasFileName);
return -5;
}
OutputHeader_asmstub(file, pszDllName);
for (i = 0; i < cExports; i++)
{
if (pexports[i].bVersionIncluded)
OutputLine_implib_asm(file, &pexports[i]);
}
fprintf(file, "\n END\n");
fclose(file);
}
free(pexports);
return 0;