static char RCSId[] = "$Id: build.c,v 1.3 1993/07/04 04:04:21 root Exp root $"; static char Copyright[] = "Copyright Robert J. Amstadt, 1993"; #include #include #include #include #ifdef linux #define UTEXTSEL 0x23 #endif #if defined(__NetBSD__) || defined(__FreeBSD__) #define UTEXTSEL 0x1f #endif #define VARTYPE_BYTE 0 #define VARTYPE_SIGNEDWORD 0 #define VARTYPE_WORD 1 #define VARTYPE_LONG 2 #define VARTYPE_FARPTR 3 #define FUNCTYPE_PASCAL 16 #define FUNCTYPE_C 17 #define FUNCTYPE_REG 19 #define EQUATETYPE_ABS 18 #define TYPE_RETURN 20 #define MAX_ORDINALS 1024 typedef struct ordinal_definition_s { int valid; int type; char export_name[80]; void *additional_data; } ORDDEF; typedef struct ordinal_variable_definition_s { int n_values; int *values; } ORDVARDEF; typedef struct ordinal_function_definition_s { int n_args_16; int arg_types_16[16]; int arg_16_offsets[16]; int arg_16_size; char internal_name[80]; int n_args_32; int arg_indices_32[16]; } ORDFUNCDEF; typedef struct ordinal_return_definition_s { int arg_size; int ret_value; } ORDRETDEF; ORDDEF OrdinalDefinitions[MAX_ORDINALS]; char LowerDLLName[80]; char UpperDLLName[80]; int Limit; int DLLId; FILE *SpecFp; char *ParseBuffer = NULL; char *ParseNext; char ParseSaveChar; int Line; int IsNumberString(char *s) { while (*s != '\0') if (!isdigit(*s++)) return 0; return 1; } char *strlower(char *s) { char *p; for(p = s; *p != '\0'; p++) *p = tolower(*p); return s; } char *strupper(char *s) { char *p; for(p = s; *p != '\0'; p++) *p = toupper(*p); return s; } int stricmp(char *s1, char *s2) { if (strlen(s1) != strlen(s2)) return -1; while (*s1 != '\0') if (*s1++ != *s2++) return -1; return 0; } char * GetTokenInLine(void) { char *p; char *token; if (ParseNext != ParseBuffer) { if (ParseSaveChar == '\0') return NULL; *ParseNext = ParseSaveChar; } /* * Remove initial white space. */ for (p = ParseNext; isspace(*p); p++) ; if (*p == '\0') return NULL; /* * Find end of token. */ token = p++; if (*token != '(' && *token != ')') while (*p != '\0' && *p != '(' && *p != ')' && !isspace(*p)) p++; ParseSaveChar = *p; ParseNext = p; *p = '\0'; return token; } char * GetToken(void) { char *token; if (ParseBuffer == NULL) { ParseBuffer = malloc(512); ParseNext = ParseBuffer; Line++; while (1) { if (fgets(ParseBuffer, 511, SpecFp) == NULL) return NULL; if (ParseBuffer[0] != '#') break; } } while ((token = GetTokenInLine()) == NULL) { ParseNext = ParseBuffer; Line++; while (1) { if (fgets(ParseBuffer, 511, SpecFp) == NULL) return NULL; if (ParseBuffer[0] != '#') break; } } return token; } int ParseVariable(int ordinal, int type) { ORDDEF *odp; ORDVARDEF *vdp; char export_name[80]; char *token; char *endptr; int *value_array; int n_values; int value_array_size; strcpy(export_name, GetToken()); token = GetToken(); if (*token != '(') { fprintf(stderr, "%d: Expected '(' got '%s'\n", Line, token); exit(1); } n_values = 0; value_array_size = 25; value_array = malloc(sizeof(*value_array) * value_array_size); while ((token = GetToken()) != NULL) { if (*token == ')') break; value_array[n_values++] = strtol(token, &endptr, 0); if (n_values == value_array_size) { value_array_size += 25; value_array = realloc(value_array, sizeof(*value_array) * value_array_size); } if (endptr == NULL || *endptr != '\0') { fprintf(stderr, "%d: Expected number value, got '%s'\n", Line, token); exit(1); } } if (token == NULL) { fprintf(stderr, "%d: End of file in variable declaration\n", Line); exit(1); } if (ordinal >= MAX_ORDINALS) { fprintf(stderr, "%d: Ordinal number too large\n", Line); exit(1); } odp = &OrdinalDefinitions[ordinal]; odp->valid = 1; odp->type = type; strcpy(odp->export_name, export_name); vdp = malloc(sizeof(*vdp)); odp->additional_data = vdp; vdp->n_values = n_values; vdp->values = realloc(value_array, sizeof(*value_array) * n_values); return 0; } int ParseExportFunction(int ordinal, int type) { char *token; ORDDEF *odp; ORDFUNCDEF *fdp; int arg_types[16]; int i; int arg_num; int current_offset; int arg_size; if (ordinal >= MAX_ORDINALS) { fprintf(stderr, "%d: Ordinal number too large\n", Line); exit(1); } odp = &OrdinalDefinitions[ordinal]; strcpy(odp->export_name, GetToken()); odp->valid = 1; odp->type = type; fdp = malloc(sizeof(*fdp)); odp->additional_data = fdp; token = GetToken(); if (*token != '(') { fprintf(stderr, "%d: Expected '(' got '%s'\n", Line, token); exit(1); } fdp->arg_16_size = 0; for (i = 0; i < 16; i++) { token = GetToken(); if (*token == ')') break; if (stricmp(token, "byte") == 0 || stricmp(token, "word") == 0) { fdp->arg_types_16[i] = VARTYPE_WORD; fdp->arg_16_size += 2; fdp->arg_16_offsets[i] = 2; } else if (stricmp(token, "s_byte") == 0 || stricmp(token, "s_word") == 0) { fdp->arg_types_16[i] = VARTYPE_SIGNEDWORD; fdp->arg_16_size += 2; fdp->arg_16_offsets[i] = 2; } else if (stricmp(token, "long") == 0 || stricmp(token, "s_long") == 0) { fdp->arg_types_16[i] = VARTYPE_LONG; fdp->arg_16_size += 4; fdp->arg_16_offsets[i] = 4; } else if (stricmp(token, "ptr") == 0) { fdp->arg_types_16[i] = VARTYPE_FARPTR; fdp->arg_16_size += 4; fdp->arg_16_offsets[i] = 4; } else { fprintf(stderr, "%d: Unknown variable type '%s'\n", Line, token); exit(1); } } fdp->n_args_16 = i; if (type == FUNCTYPE_PASCAL || type == FUNCTYPE_REG) { current_offset = 0; for (i--; i >= 0; i--) { arg_size = fdp->arg_16_offsets[i]; fdp->arg_16_offsets[i] = current_offset; current_offset += arg_size; } } else { current_offset = 0; for (i = 0; i < fdp->n_args_16; i++) { arg_size = fdp->arg_16_offsets[i]; fdp->arg_16_offsets[i] = current_offset; current_offset += arg_size; } } strcpy(fdp->internal_name, GetToken()); token = GetToken(); if (*token != '(') { fprintf(stderr, "%d: Expected '(' got '%s'\n", Line, token); exit(1); } for (i = 0; i < 16; i++) { token = GetToken(); if (*token == ')') break; fdp->arg_indices_32[i] = atoi(token); if (fdp->arg_indices_32[i] < 1 || fdp->arg_indices_32[i] > fdp->n_args_16) { fprintf(stderr, "%d: Bad argument index %d\n", Line, fdp->arg_indices_32[i]); exit(1); } } fdp->n_args_32 = i; return 0; } int ParseEquate(int ordinal) { ORDDEF *odp; char *token; char *endptr; int value; if (ordinal >= MAX_ORDINALS) { fprintf(stderr, "%d: Ordinal number too large\n", Line); exit(1); } odp = &OrdinalDefinitions[ordinal]; strcpy(odp->export_name, GetToken()); token = GetToken(); value = strtol(token, &endptr, 0); if (endptr == NULL || *endptr != '\0') { fprintf(stderr, "%d: Expected number value, got '%s'\n", Line, token); exit(1); } odp->valid = 1; odp->type = EQUATETYPE_ABS; odp->additional_data = (void *) value; return 0; } int ParseReturn(int ordinal) { ORDDEF *odp; ORDRETDEF *rdp; char *token; char *endptr; int value; if (ordinal >= MAX_ORDINALS) { fprintf(stderr, "%d: Ordinal number too large\n", Line); exit(1); } rdp = malloc(sizeof(*rdp)); odp = &OrdinalDefinitions[ordinal]; strcpy(odp->export_name, GetToken()); odp->valid = 1; odp->type = TYPE_RETURN; odp->additional_data = rdp; token = GetToken(); rdp->arg_size = strtol(token, &endptr, 0); if (endptr == NULL || *endptr != '\0') { fprintf(stderr, "%d: Expected number value, got '%s'\n", Line, token); exit(1); } token = GetToken(); rdp->ret_value = strtol(token, &endptr, 0); if (endptr == NULL || *endptr != '\0') { fprintf(stderr, "%d: Expected number value, got '%s'\n", Line, token); exit(1); } return 0; } int ParseOrdinal(int ordinal) { char *token; token = GetToken(); if (token == NULL) { fprintf(stderr, "%d: Expected type after ordinal\n", Line); exit(1); } if (stricmp(token, "byte") == 0) return ParseVariable(ordinal, VARTYPE_BYTE); else if (stricmp(token, "word") == 0) return ParseVariable(ordinal, VARTYPE_WORD); else if (stricmp(token, "long") == 0) return ParseVariable(ordinal, VARTYPE_LONG); else if (stricmp(token, "c") == 0) return ParseExportFunction(ordinal, FUNCTYPE_C); else if (stricmp(token, "p") == 0) return ParseExportFunction(ordinal, FUNCTYPE_PASCAL); else if (stricmp(token, "pascal") == 0) return ParseExportFunction(ordinal, FUNCTYPE_PASCAL); else if (stricmp(token, "register") == 0) return ParseExportFunction(ordinal, FUNCTYPE_REG); else if (stricmp(token, "equate") == 0) return ParseEquate(ordinal); else if (stricmp(token, "return") == 0) return ParseReturn(ordinal); else { fprintf(stderr, "%d: Expected type after ordinal, found '%s' instead\n", Line, token); exit(1); } } int ParseTopLevel(void) { char *token; while ((token = GetToken()) != NULL) { if (stricmp(token, "name") == 0) { strcpy(LowerDLLName, GetToken()); strlower(LowerDLLName); strcpy(UpperDLLName, LowerDLLName); strupper(UpperDLLName); } else if (stricmp(token, "id") == 0) { token = GetToken(); if (!IsNumberString(token)) { fprintf(stderr, "%d: Expected number after id\n", Line); exit(1); } DLLId = atoi(token); } else if (stricmp(token, "length") == 0) { token = GetToken(); if (!IsNumberString(token)) { fprintf(stderr, "%d: Expected number after length\n", Line); exit(1); } Limit = atoi(token); } else if (IsNumberString(token)) { int ordinal; int rv; ordinal = atoi(token); if ((rv = ParseOrdinal(ordinal)) < 0) return rv; } else { fprintf(stderr, "%d: Expected name, id, length or ordinal\n", Line); exit(1); } } return 0; } void OutputVariableCode(FILE *fp, char *storage, ORDDEF *odp) { ORDVARDEF *vdp; int i; fprintf(fp, "_%s_Ordinal_%d:\n", UpperDLLName, i); vdp = odp->additional_data; for (i = 0; i < vdp->n_values; i++) { if ((i & 7) == 0) fprintf(fp, "\t%s\t", storage); fprintf(fp, "%d", vdp->values[i]); if ((i & 7) == 7 || i == vdp->n_values - 1) fprintf(fp, "\n"); else fprintf(fp, ", "); } fprintf(fp, "\n"); } main(int argc, char **argv) { ORDDEF *odp; ORDFUNCDEF *fdp; ORDRETDEF *rdp; FILE *fp; char filename[80]; char buffer[80]; char *p; int i; if (argc < 2) { fprintf(stderr, "usage: build SPECNAME\n"); exit(1); } SpecFp = fopen(argv[1], "r"); if (SpecFp == NULL) { fprintf(stderr, "Could not open specification file, '%s'\n", argv[1]); exit(1); } ParseTopLevel(); sprintf(filename, "dll_%s.S", LowerDLLName); fp = fopen(filename, "w"); fprintf(fp, "\t.globl _%s_Dispatch\n", UpperDLLName); fprintf(fp, "_%s_Dispatch:\n", UpperDLLName); fprintf(fp, "\tandl\t$0x0000ffff,%%esp\n"); fprintf(fp, "\tandl\t$0x0000ffff,%%ebp\n"); fprintf(fp, "\torl\t$0x%08x,%%eax\n", DLLId << 16); fprintf(fp, "\tjmp\t_CallTo32\n\n"); odp = OrdinalDefinitions; for (i = 0; i <= Limit; i++, odp++) { fprintf(fp, "\t.globl _%s_Ordinal_%d\n", UpperDLLName, i); if (!odp->valid) { fprintf(fp, "_%s_Ordinal_%d:\n", UpperDLLName, i); #ifdef BOB_SAYS_NO fprintf(fp, "\tandl\t$0x0000ffff,%%esp\n"); fprintf(fp, "\tandl\t$0x0000ffff,%%ebp\n"); #endif fprintf(fp, "\tmovl\t$%d,%%eax\n", i); fprintf(fp, "\tpushw\t$0\n"); fprintf(fp, "\tjmp\t_%s_Dispatch\n\n", UpperDLLName); } else { fdp = odp->additional_data; rdp = odp->additional_data; switch (odp->type) { case EQUATETYPE_ABS: fprintf(fp, "_%s_Ordinal_%d = %d\n\n", UpperDLLName, i, (int) odp->additional_data); break; case VARTYPE_BYTE: OutputVariableCode(fp, ".byte", odp); break; case VARTYPE_WORD: OutputVariableCode(fp, ".word", odp); break; case VARTYPE_LONG: OutputVariableCode(fp, ".long", odp); break; case TYPE_RETURN: fprintf(fp, "_%s_Ordinal_%d:\n", UpperDLLName, i); fprintf(fp, "\tmovw\t$%d,%%ax\n", rdp->ret_value & 0xffff); fprintf(fp, "\tmovw\t$%d,%%dx\n", (rdp->ret_value >> 16) & 0xffff); fprintf(fp, "\t.byte\t0x66\n"); if (rdp->arg_size != 0) fprintf(fp, "\tlret\t$%d\n", rdp->arg_size); else fprintf(fp, "\tlret\n"); break; case FUNCTYPE_REG: fprintf(fp, "_%s_Ordinal_%d:\n", UpperDLLName, i); fprintf(fp, "\tandl\t$0x0000ffff,%%esp\n"); fprintf(fp, "\tandl\t$0x0000ffff,%%ebp\n"); fprintf(fp, "\tpushl\t$0\n"); /* cr2 */ fprintf(fp, "\tpushl\t$0\n"); /* oldmask */ fprintf(fp, "\tpushl\t$0\n"); /* i387 */ fprintf(fp, "\tpushw\t$0\n"); /* __ssh */ fprintf(fp, "\tpushw\t%%ss\n"); /* ss */ fprintf(fp, "\tpushl\t%%esp\n"); /* esp */ fprintf(fp, "\tpushfl\n"); /* eflags */ fprintf(fp, "\tpushw\t$0\n"); /* __csh */ fprintf(fp, "\tpushw\t%%cs\n"); /* cs */ fprintf(fp, "\tpushl\t$0\n"); /* eip */ fprintf(fp, "\tpushl\t$0\n"); /* err */ fprintf(fp, "\tpushl\t$0\n"); /* trapno */ fprintf(fp, "\tpushal\n"); /* AX, ... */ fprintf(fp, "\tpushw\t$0\n"); /* __dsh */ fprintf(fp, "\tpushw\t%%ds\n"); /* ds */ fprintf(fp, "\tpushw\t$0\n"); /* __esh */ fprintf(fp, "\tpushw\t%%es\n"); /* es */ fprintf(fp, "\tpushw\t$0\n"); /* __fsh */ fprintf(fp, "\tpushw\t%%fs\n"); /* fs */ fprintf(fp, "\tpushw\t$0\n"); /* __gsh */ fprintf(fp, "\tpushw\t%%gs\n"); /* gs */ fprintf(fp, "\tmovl\t%%ebp,%%eax\n"); fprintf(fp, "\tmovw\t%%esp,%%ebp\n"); fprintf(fp, "\tpushl\t88(%%ebp)\n"); fprintf(fp, "\tmovl\t%%eax,%%ebp\n"); fprintf(fp, "\tmovl\t$%d,%%eax\n", i); fprintf(fp, "\tpushw\t$92\n"); fprintf(fp, "\tjmp\t_%s_Dispatch\n\n", UpperDLLName); #if 0 fprintf(fp, "\tpushw\t%%ax\n"); fprintf(fp, "\tpushw\t%%cx\n"); fprintf(fp, "\tpushw\t%%dx\n"); fprintf(fp, "\tpushw\t%%bx\n"); fprintf(fp, "\tpushw\t%%sp\n"); fprintf(fp, "\tpushw\t%%bp\n"); fprintf(fp, "\tpushw\t%%si\n"); fprintf(fp, "\tpushw\t%%di\n"); fprintf(fp, "\tpushw\t%%ds\n"); fprintf(fp, "\tpushw\t%%es\n"); fprintf(fp, "\tmovl\t%%ebp,%%eax\n"); fprintf(fp, "\tmovw\t%%esp,%%ebp\n"); fprintf(fp, "\tpushl\t20(%%ebp)\n"); fprintf(fp, "\tmovl\t%%eax,%%ebp\n"); fprintf(fp, "\tmovl\t$%d,%%eax\n", i); fprintf(fp, "\tpushw\t$24\n"); fprintf(fp, "\tjmp\t_%s_Dispatch\n\n", UpperDLLName); #endif break; case FUNCTYPE_PASCAL: fprintf(fp, "_%s_Ordinal_%d:\n", UpperDLLName, i); #ifdef BOB_SAYS_NO fprintf(fp, "\tandl\t$0x0000ffff,%%esp\n"); fprintf(fp, "\tandl\t$0x0000ffff,%%ebp\n"); #endif fprintf(fp, "\tmovl\t$%d,%%eax\n", i); fprintf(fp, "\tpushw\t$%d\n", fdp->arg_16_size); fprintf(fp, "\tjmp\t_%s_Dispatch\n\n", UpperDLLName); break; case FUNCTYPE_C: default: fprintf(fp, "_%s_Ordinal_%d:\n", UpperDLLName, i); #ifdef BOB_SAYS_NO fprintf(fp, "\tandl\t$0x0000ffff,%%esp\n"); fprintf(fp, "\tandl\t$0x0000ffff,%%ebp\n"); #endif fprintf(fp, "\tmovl\t$%d,%%eax\n", i); fprintf(fp, "\tpushw\t$0\n"); fprintf(fp, "\tjmp\t_%s_Dispatch\n\n", UpperDLLName); break; } } } fclose(fp); #ifndef SHORTNAMES sprintf(filename, "dll_%s_tab.c", LowerDLLName); #else sprintf(filename, "dtb_%s.c", LowerDLLName); #endif fp = fopen(filename, "w"); fprintf(fp, "#include \n"); fprintf(fp, "#include \n"); fprintf(fp, "#include \042dlls.h\042\n\n"); for (i = 0; i <= Limit; i++) { fprintf(fp, "extern void %s_Ordinal_%d();\n", UpperDLLName, i); } odp = OrdinalDefinitions; for (i = 0; i <= Limit; i++, odp++) { if (odp->valid && (odp->type == FUNCTYPE_PASCAL || odp->type == FUNCTYPE_C || odp->type == FUNCTYPE_REG)) { fdp = odp->additional_data; fprintf(fp, "extern int %s();\n", fdp->internal_name); } } fprintf(fp, "\nstruct dll_table_entry_s %s_table[%d] =\n", UpperDLLName, Limit + 1); fprintf(fp, "{\n"); odp = OrdinalDefinitions; for (i = 0; i <= Limit; i++, odp++) { fdp = odp->additional_data; if (!odp->valid) odp->type = -1; switch (odp->type) { case FUNCTYPE_PASCAL: case FUNCTYPE_REG: fprintf(fp, " { 0x%x, %s_Ordinal_%d, ", UTEXTSEL, UpperDLLName, i); fprintf(fp, "\042%s\042, ", odp->export_name); fprintf(fp, "%s, DLL_HANDLERTYPE_PASCAL, ", fdp->internal_name); #ifdef WINESTAT fprintf(fp, "0, "); #endif fprintf(fp, "%d, ", fdp->n_args_32); if (fdp->n_args_32 > 0) { int argnum; fprintf(fp, "\n {\n"); for (argnum = 0; argnum < fdp->n_args_32; argnum++) { fprintf(fp, " { %d, %d },\n", fdp->arg_16_offsets[fdp->arg_indices_32[argnum]-1], fdp->arg_types_16[argnum]); } fprintf(fp, " }\n "); } fprintf(fp, "}, \n"); break; case FUNCTYPE_C: fprintf(fp, " { 0x%x, %s_Ordinal_%d, ", UTEXTSEL, UpperDLLName, i); fprintf(fp, "\042%s\042, ", odp->export_name); fprintf(fp, "%s, DLL_HANDLERTYPE_C, ", fdp->internal_name); #ifdef WINESTAT fprintf(fp, "0, "); #endif fprintf(fp, "%d, ", fdp->n_args_32); if (fdp->n_args_32 > 0) { int argnum; fprintf(fp, "\n {\n"); for (argnum = 0; argnum < fdp->n_args_32; argnum++) { fprintf(fp, " { %d, %d },\n", fdp->arg_16_offsets[fdp->arg_indices_32[argnum]-1], fdp->arg_types_16[argnum]); } fprintf(fp, " }\n "); } fprintf(fp, "}, \n"); break; default: fprintf(fp, " { 0x%x, %s_Ordinal_%d, \042\042, NULL },\n", UTEXTSEL, UpperDLLName, i); break; } } fprintf(fp, "};\n"); fclose(fp); }