[SPEC2DEF] Set ordinals explicitly in export def file

The reason is that dlltool orders the exports differently than MSVC builds (MSVC orders the exports by symbol name, rather than by export name), so we rely on sorting in the spec file, which was only respected, when ordinals were put into the def file.
On MSVC builds it is left to the linker to determine the correct order, which helps to get the differences between architectures right (different symbol decoration, difference between order for functions like NtLoadKey vs NtLoadKey2, which results from the stdcall decoration on x86, which is missing on other architectures.

TODO: To correctly handle non-x86 architectures with GCC builds, spec2def would need to reorder the export list based on symbol names, which would work for C functions, by taking the calling convention into account, but would require an extra c++-stdcall calling convention to be added to know the corresponding symbol starts with "?".
This commit is contained in:
Timo Kreuzer 2019-09-22 14:59:09 +02:00
parent fb0ebac349
commit 6e80f4d037

View file

@ -732,7 +732,8 @@ OutputLine_def(FILE *fileDest, EXPORT *pexp)
else else
OutputLine_def_GCC(fileDest, pexp); OutputLine_def_GCC(fileDest, pexp);
if (pexp->uFlags & FL_ORDINAL) /* On GCC builds we force ordinals */
if ((pexp->uFlags & FL_ORDINAL) || (!gbMSComp && !gbImportLib))
{ {
fprintf(fileDest, " @%d", pexp->nOrdinal); fprintf(fileDest, " @%d", pexp->nOrdinal);
} }
@ -772,7 +773,7 @@ Fatalv(
/* Get the length of the line */ /* Get the length of the line */
pcLineEnd = strpbrk(pcLine, "\r\n"); pcLineEnd = strpbrk(pcLine, "\r\n");
len = pcLineEnd - pcLine; len = (unsigned)(pcLineEnd - pcLine);
if (pc == NULL) if (pc == NULL)
{ {
@ -1299,6 +1300,52 @@ ParseFile(char* pcStart, FILE *fileDest, unsigned *cExports)
return pexports; return pexports;
} }
int
ApplyOrdinals(EXPORT* pexports, unsigned cExports)
{
unsigned short i, j;
char* used;
/* Allocate a table to mark used ordinals */
used = malloc(65536);
if (used == NULL)
{
fprintf(stderr, "Failed to allocate memory for ordinal use table\n");
return -1;
}
memset(used, 0, 65536);
/* Pass 1: mark the ordinals that are already used */
for (i = 0; i < cExports; i++)
{
if (pexports[i].uFlags & FL_ORDINAL)
{
if (used[pexports[i].nOrdinal] != 0)
{
fprintf(stderr, "Found duplicate ordinal: %u\n", pexports[i].nOrdinal);
return -1;
}
used[pexports[i].nOrdinal] = 1;
}
}
/* Pass 2: apply available ordinals */
for (i = 0, j = 1; i < cExports; i++)
{
if ((pexports[i].uFlags & FL_ORDINAL) == 0)
{
while (used[j] != 0)
j++;
pexports[i].nOrdinal = j;
used[j] = 1;
}
}
free(used);
return 0;
}
void usage(void) void usage(void)
{ {
printf("syntax: spec2def [<options> ...] <spec file>\n" printf("syntax: spec2def [<options> ...] <spec file>\n"
@ -1465,10 +1512,19 @@ int main(int argc, char *argv[])
pexports = ParseFile(pszSource, file, &cExports); pexports = ParseFile(pszSource, file, &cExports);
if (pexports == NULL) if (pexports == NULL)
{ {
fprintf(stderr, "Failed to allocate memory for export data!\n"); fprintf(stderr, "error: could not parse file!\n");
return -1; return -1;
} }
if (!gbMSComp)
{
if (ApplyOrdinals(pexports, cExports) < 0)
{
fprintf(stderr, "error: could not apply ordinals!\n");
return -1;
}
}
if (pszDefFileName) if (pszDefFileName)
{ {
/* Open output file */ /* Open output file */