2 * Copyright 1993 Robert J. Amstadt
3 * Copyright 1995 Martin von Loewis
4 * Copyright 1995, 1996 Alexandre Julliard
5 * Copyright 1997 Eric Youngdale
18 #include "selectors.h"
19 #include "stackframe.h"
21 #ifdef NEED_UNDERSCORE_PREFIX
27 #if defined(__GNUC__) && !defined(__svr4__)
36 TYPE_BYTE, /* byte variable */
37 TYPE_WORD, /* word variable */
38 TYPE_LONG, /* long variable */
39 TYPE_PASCAL_16, /* pascal function with 16-bit return (Win16) */
40 TYPE_PASCAL, /* pascal function with 32-bit return (Win16) */
41 TYPE_REGISTER, /* register function */
42 TYPE_ABS, /* absolute value */
43 TYPE_RETURN, /* simple return value function */
44 TYPE_STUB, /* unimplemented stub */
45 TYPE_STDCALL, /* stdcall function (Win32) */
46 TYPE_CDECL, /* cdecl function (Win32) */
47 TYPE_VARARGS, /* varargs function (Win32) */
48 TYPE_EXTERN, /* external symbol (Win32) */
52 static const char * const TypeNames[TYPE_NBTYPES] =
55 "byte", /* TYPE_BYTE */
56 "word", /* TYPE_WORD */
57 "long", /* TYPE_LONG */
58 "pascal16", /* TYPE_PASCAL_16 */
59 "pascal", /* TYPE_PASCAL */
60 "register", /* TYPE_REGISTER */
61 "equate", /* TYPE_ABS */
62 "return", /* TYPE_RETURN */
63 "stub", /* TYPE_STUB */
64 "stdcall", /* TYPE_STDCALL */
65 "cdecl", /* TYPE_CDECL */
66 "varargs", /* TYPE_VARARGS */
67 "extern" /* TYPE_EXTERN */
70 #define MAX_ORDINALS 1299
72 /* Callback function used for stub functions */
73 #define STUB_CALLBACK \
74 ((SpecType == SPEC_WIN16) ? "RELAY_Unimplemented16": "RELAY_Unimplemented32")
134 static ORDDEF OrdinalDefinitions[MAX_ORDINALS];
136 static SPEC_TYPE SpecType = SPEC_INVALID;
137 static char DLLName[80];
138 static char DLLFileName[80];
140 int Base = MAX_ORDINALS;
145 char *ParseBuffer = NULL;
150 static int debugging = 1;
152 /* Offset of a structure field relative to the start of the struct */
153 #define STRUCTOFFSET(type,field) ((int)&((type *)0)->field)
155 /* Offset of register relative to the start of the CONTEXT struct */
156 #define CONTEXTOFFSET(reg) STRUCTOFFSET(CONTEXT,reg)
158 static void *xmalloc (size_t size)
162 res = malloc (size ? size : 1);
165 fprintf (stderr, "Virtual memory exhausted.\n");
172 static void *xrealloc (void *ptr, size_t size)
174 void *res = realloc (ptr, size);
177 fprintf (stderr, "Virtual memory exhausted.\n");
184 static int IsNumberString(char *s)
193 static char *strupper(char *s)
197 for(p = s; *p != '\0'; p++)
203 static char * GetTokenInLine(void)
208 if (ParseNext != ParseBuffer)
210 if (ParseSaveChar == '\0')
212 *ParseNext = ParseSaveChar;
216 * Remove initial white space.
218 for (p = ParseNext; isspace(*p); p++)
221 if ((*p == '\0') || (*p == '#'))
228 if (*token != '(' && *token != ')')
229 while (*p != '\0' && *p != '(' && *p != ')' && !isspace(*p))
239 static char * GetToken(void)
243 if (ParseBuffer == NULL)
245 ParseBuffer = xmalloc(512);
246 ParseNext = ParseBuffer;
250 if (fgets(ParseBuffer, 511, SpecFp) == NULL)
252 if (ParseBuffer[0] != '#')
257 while ((token = GetTokenInLine()) == NULL)
259 ParseNext = ParseBuffer;
263 if (fgets(ParseBuffer, 511, SpecFp) == NULL)
265 if (ParseBuffer[0] != '#')
274 /*******************************************************************
277 * Parse a variable definition.
279 static int ParseVariable( ORDDEF *odp )
284 int value_array_size;
286 char *token = GetToken();
289 fprintf(stderr, "%s:%d: Expected '(' got '%s'\n",
290 SpecName, Line, token);
295 value_array_size = 25;
296 value_array = xmalloc(sizeof(*value_array) * value_array_size);
298 while ((token = GetToken()) != NULL)
303 value_array[n_values++] = strtol(token, &endptr, 0);
304 if (n_values == value_array_size)
306 value_array_size += 25;
307 value_array = xrealloc(value_array,
308 sizeof(*value_array) * value_array_size);
311 if (endptr == NULL || *endptr != '\0')
313 fprintf(stderr, "%s:%d: Expected number value, got '%s'\n",
314 SpecName, Line, token);
321 fprintf(stderr, "%s:%d: End of file in variable declaration\n",
326 odp->u.var.n_values = n_values;
327 odp->u.var.values = xrealloc(value_array, sizeof(*value_array) * n_values);
333 /*******************************************************************
334 * ParseExportFunction
336 * Parse a function definition.
338 static int ParseExportFunction( ORDDEF *odp )
346 if (odp->type == TYPE_STDCALL)
348 fprintf( stderr, "%s:%d: 'stdcall' not supported for Win16\n",
352 if (odp->type == TYPE_CDECL)
354 fprintf( stderr, "%s:%d: 'cdecl' not supported for Win16\n",
360 if ((odp->type == TYPE_PASCAL) || (odp->type == TYPE_PASCAL_16))
362 fprintf( stderr, "%s:%d: 'pascal' not supported for Win32\n",
374 fprintf(stderr, "%s:%d: Expected '(' got '%s'\n",
375 SpecName, Line, token);
379 for (i = 0; i < sizeof(odp->u.func.arg_types)-1; i++)
385 if (!strcmp(token, "word"))
386 odp->u.func.arg_types[i] = 'w';
387 else if (!strcmp(token, "s_word"))
388 odp->u.func.arg_types[i] = 's';
389 else if (!strcmp(token, "long") || !strcmp(token, "segptr"))
390 odp->u.func.arg_types[i] = 'l';
391 else if (!strcmp(token, "ptr"))
392 odp->u.func.arg_types[i] = 'p';
393 else if (!strcmp(token, "str"))
394 odp->u.func.arg_types[i] = 't';
395 else if (!strcmp(token, "segstr"))
396 odp->u.func.arg_types[i] = 'T';
397 else if (!strcmp(token, "double"))
399 odp->u.func.arg_types[i++] = 'l';
400 odp->u.func.arg_types[i] = 'l';
404 fprintf(stderr, "%s:%d: Unknown variable type '%s'\n",
405 SpecName, Line, token);
408 if (SpecType == SPEC_WIN32)
410 if (strcmp(token, "long") &&
411 strcmp(token, "ptr") &&
412 strcmp(token, "double"))
414 fprintf( stderr, "%s:%d: Type '%s' not supported for Win32\n",
415 SpecName, Line, token );
420 if ((*token != ')') || (i >= sizeof(odp->u.func.arg_types)))
422 fprintf( stderr, "%s:%d: Too many arguments\n", SpecName, Line );
425 odp->u.func.arg_types[i] = '\0';
426 if ((odp->type == TYPE_STDCALL) && !i)
427 odp->type = TYPE_CDECL; /* stdcall is the same as cdecl for 0 args */
428 strcpy(odp->u.func.link_name, GetToken());
433 /*******************************************************************
436 * Parse an 'equate' definition.
438 static int ParseEquate( ORDDEF *odp )
442 char *token = GetToken();
443 int value = strtol(token, &endptr, 0);
444 if (endptr == NULL || *endptr != '\0')
446 fprintf(stderr, "%s:%d: Expected number value, got '%s'\n",
447 SpecName, Line, token);
451 odp->u.abs.value = value;
456 /*******************************************************************
459 * Parse a 'return' definition.
461 static int ParseReturn( ORDDEF *odp )
467 odp->u.ret.arg_size = strtol(token, &endptr, 0);
468 if (endptr == NULL || *endptr != '\0')
470 fprintf(stderr, "%s:%d: Expected number value, got '%s'\n",
471 SpecName, Line, token);
476 odp->u.ret.ret_value = strtol(token, &endptr, 0);
477 if (endptr == NULL || *endptr != '\0')
479 fprintf(stderr, "%s:%d: Expected number value, got '%s'\n",
480 SpecName, Line, token);
488 /*******************************************************************
491 * Parse a 'stub' definition.
493 static int ParseStub( ORDDEF *odp )
495 odp->u.func.arg_types[0] = '\0';
496 strcpy( odp->u.func.link_name, STUB_CALLBACK );
501 /*******************************************************************
504 * Parse an 'varargs' definition.
506 static int ParseVarargs( ORDDEF *odp )
510 if (SpecType == SPEC_WIN16)
512 fprintf( stderr, "%s:%d: 'varargs' not supported for Win16\n",
520 fprintf(stderr, "%s:%d: Expected '(' got '%s'\n",
521 SpecName, Line, token);
527 fprintf(stderr, "%s:%d: Expected ')' got '%s'\n",
528 SpecName, Line, token);
532 strcpy( odp->u.vargs.link_name, GetToken() );
537 /*******************************************************************
540 * Parse an 'extern' definition.
542 static int ParseExtern( ORDDEF *odp )
544 if (SpecType == SPEC_WIN16)
546 fprintf( stderr, "%s:%d: 'extern' not supported for Win16\n",
550 strcpy( odp->u.ext.link_name, GetToken() );
555 /*******************************************************************
558 * Parse an ordinal definition.
560 static int ParseOrdinal(int ordinal)
565 if (ordinal >= MAX_ORDINALS)
567 fprintf(stderr, "%s:%d: Ordinal number too large\n", SpecName, Line );
570 if (ordinal > Limit) Limit = ordinal;
571 if (ordinal < Base) Base = ordinal;
573 odp = &OrdinalDefinitions[ordinal];
574 if (!(token = GetToken()))
576 fprintf(stderr, "%s:%d: Expected type after ordinal\n", SpecName, Line);
580 for (odp->type = 0; odp->type < TYPE_NBTYPES; odp->type++)
581 if (TypeNames[odp->type] && !strcmp( token, TypeNames[odp->type] ))
584 if (odp->type >= TYPE_NBTYPES)
587 "%s:%d: Expected type after ordinal, found '%s' instead\n",
588 SpecName, Line, token );
592 if (!(token = GetToken()))
594 fprintf( stderr, "%s:%d: Expected name after type\n", SpecName, Line );
597 strcpy( odp->name, token );
605 return ParseVariable( odp );
611 return ParseExportFunction( odp );
613 return ParseEquate( odp );
615 return ParseReturn( odp );
617 return ParseStub( odp );
619 return ParseVarargs( odp );
621 return ParseExtern( odp );
623 fprintf( stderr, "Should not happen\n" );
629 /*******************************************************************
634 static int ParseTopLevel(void)
638 while ((token = GetToken()) != NULL)
640 if (strcmp(token, "name") == 0)
642 strcpy(DLLName, GetToken());
644 if (!DLLFileName[0]) sprintf( DLLFileName, "%s.DLL", DLLName );
646 else if (strcmp(token, "file") == 0)
648 strcpy(DLLFileName, GetToken());
649 strupper(DLLFileName);
651 else if (strcmp(token, "type") == 0)
654 if (!strcmp(token, "win16" )) SpecType = SPEC_WIN16;
655 else if (!strcmp(token, "win32" )) SpecType = SPEC_WIN32;
658 fprintf(stderr, "%s:%d: Type must be 'win16' or 'win32'\n",
663 else if (strcmp(token, "heap") == 0)
666 if (!IsNumberString(token))
668 fprintf(stderr, "%s:%d: Expected number after heap\n",
672 DLLHeapSize = atoi(token);
674 else if (IsNumberString(token))
679 ordinal = atoi(token);
680 if ((rv = ParseOrdinal(ordinal)) < 0)
686 "%s:%d: Expected name, id, length or ordinal\n",
696 /*******************************************************************
699 * Store a list of ints into a byte array.
701 static int StoreVariableCode( unsigned char *buffer, int size, ORDDEF *odp )
708 for (i = 0; i < odp->u.var.n_values; i++)
709 buffer[i] = odp->u.var.values[i];
712 for (i = 0; i < odp->u.var.n_values; i++)
713 ((unsigned short *)buffer)[i] = odp->u.var.values[i];
716 for (i = 0; i < odp->u.var.n_values; i++)
717 ((unsigned int *)buffer)[i] = odp->u.var.values[i];
720 return odp->u.var.n_values * size;
724 /*******************************************************************
727 * Dump a byte stream into the assembly code.
729 static void DumpBytes( FILE *outfile, const unsigned char *data, int len,
730 const char *section, const char *label_start )
733 if (section) fprintf( outfile, "\t%s\n", section );
734 if (label_start) fprintf( outfile, "%s:\n", label_start );
735 for (i = 0; i < len; i++)
737 if (!(i & 0x0f)) fprintf( outfile, "\t.byte " );
738 fprintf( outfile, "%d", *data++ );
740 fprintf( outfile, "%c", ((i & 0x0f) != 0x0f) ? ',' : '\n' );
742 fprintf( outfile, "\n" );
746 /*******************************************************************
749 * Build the in-memory representation of a 16-bit NE module, and dump it
750 * as a byte stream into the assembly code.
752 static int BuildModule16( FILE *outfile, int max_code_offset,
753 int max_data_offset )
759 SEGTABLEENTRY *pSegment;
766 * OFSTRUCT File information
767 * SEGTABLEENTRY Segment 1 (code)
768 * SEGTABLEENTRY Segment 2 (data)
769 * WORD[2] Resource table (empty)
770 * BYTE[2] Imported names (empty)
771 * BYTE[n] Resident names table
772 * BYTE[n] Entry table
775 buffer = xmalloc( 0x10000 );
777 pModule = (NE_MODULE *)buffer;
778 pModule->magic = IMAGE_OS2_SIGNATURE;
781 pModule->flags = NE_FFLAGS_SINGLEDATA | NE_FFLAGS_BUILTIN | NE_FFLAGS_LIBMODULE;
783 pModule->heap_size = DLLHeapSize;
784 pModule->stack_size = 0;
789 pModule->seg_count = 2;
790 pModule->modref_count = 0;
791 pModule->nrname_size = 0;
792 pModule->modref_table = 0;
793 pModule->nrname_fpos = 0;
794 pModule->moveable_entries = 0;
795 pModule->alignment = 0;
796 pModule->truetype = 0;
797 pModule->os_flags = NE_OSFLAGS_WINDOWS;
798 pModule->misc_flags = 0;
799 pModule->dlls_to_init = 0;
800 pModule->nrname_handle = 0;
801 pModule->min_swap_area = 0;
802 pModule->expected_version = 0x030a;
803 pModule->pe_module = NULL;
805 pModule->self_loading_sel = 0;
807 /* File information */
809 pFileInfo = (OFSTRUCT *)(pModule + 1);
810 pModule->fileinfo = (int)pFileInfo - (int)pModule;
811 memset( pFileInfo, 0, sizeof(*pFileInfo) - sizeof(pFileInfo->szPathName) );
812 pFileInfo->cBytes = sizeof(*pFileInfo) - sizeof(pFileInfo->szPathName)
813 + strlen(DLLFileName);
814 strcpy( pFileInfo->szPathName, DLLFileName );
815 pstr = (char *)pFileInfo + pFileInfo->cBytes + 1;
819 pSegment = (SEGTABLEENTRY *)pstr;
820 pModule->seg_table = (int)pSegment - (int)pModule;
821 pSegment->filepos = 0;
822 pSegment->size = max_code_offset;
824 pSegment->minsize = max_code_offset;
825 pSegment->selector = 0;
828 pModule->dgroup_entry = (int)pSegment - (int)pModule;
829 pSegment->filepos = 0;
830 pSegment->size = max_data_offset;
831 pSegment->flags = NE_SEGFLAGS_DATA;
832 pSegment->minsize = max_data_offset;
833 pSegment->selector = 0;
838 pword = (WORD *)pSegment;
839 pModule->res_table = (int)pword - (int)pModule;
843 /* Imported names table */
845 pstr = (char *)pword;
846 pModule->import_table = (int)pstr - (int)pModule;
850 /* Resident names table */
852 pModule->name_table = (int)pstr - (int)pModule;
853 /* First entry is module name */
854 *pstr = strlen(DLLName );
855 strcpy( pstr + 1, DLLName );
858 pstr += sizeof(WORD);
859 /* Store all ordinals */
860 odp = OrdinalDefinitions + 1;
861 for (i = 1; i <= Limit; i++, odp++)
863 if (!odp->name[0]) continue;
864 *pstr = strlen( odp->name );
865 strcpy( pstr + 1, odp->name );
866 strupper( pstr + 1 );
869 pstr += sizeof(WORD);
875 pModule->entry_table = (int)pstr - (int)pModule;
877 odp = OrdinalDefinitions + 1;
878 for (i = 1; i <= Limit; i++, odp++)
889 selector = 1; /* Code selector */
895 selector = 2; /* Data selector */
899 selector = 0xfe; /* Constant selector */
903 selector = 0; /* Invalid selector */
907 /* create a new bundle if necessary */
908 if (!bundle || (bundle[0] >= 254) || (bundle[1] != selector))
912 bundle[1] = selector;
920 *(WORD *)pstr = odp->offset;
921 pstr += sizeof(WORD);
926 /* Dump the module content */
928 DumpBytes( outfile, (char *)pModule, (int)pstr - (int)pModule,
929 ".data", "Module_Start" );
930 return (int)pstr - (int)pModule;
934 /*******************************************************************
937 * Build the in-memory representation of a 32-bit pseudo-NE module, and dump it
938 * as a byte stream into the assembly code.
940 static int BuildModule32( FILE *outfile )
950 * OFSTRUCT File information
951 * SEGTABLEENTRY Segment table (empty)
952 * WORD[2] Resource table (empty)
953 * BYTE[2] Imported names (empty)
954 * BYTE[n] Resident names table (1 entry)
955 * BYTE[n] Entry table (empty)
958 buffer = xmalloc( 0x10000 );
960 pModule = (NE_MODULE *)buffer;
961 pModule->magic = IMAGE_OS2_SIGNATURE;
964 pModule->dgroup_entry = 0;
965 pModule->flags = NE_FFLAGS_SINGLEDATA | NE_FFLAGS_BUILTIN |
966 NE_FFLAGS_LIBMODULE | NE_FFLAGS_WIN32;
968 pModule->heap_size = DLLHeapSize;
969 pModule->stack_size = 0;
974 pModule->seg_count = 0;
975 pModule->modref_count = 0;
976 pModule->nrname_size = 0;
977 pModule->modref_table = 0;
978 pModule->nrname_fpos = 0;
979 pModule->moveable_entries = 0;
980 pModule->alignment = 0;
981 pModule->truetype = 0;
982 pModule->os_flags = NE_OSFLAGS_WINDOWS;
983 pModule->misc_flags = 0;
984 pModule->dlls_to_init = 0;
985 pModule->nrname_handle = 0;
986 pModule->min_swap_area = 0;
987 pModule->expected_version = 0x030a;
988 pModule->pe_module = NULL;
990 pModule->self_loading_sel = 0;
992 /* File information */
994 pFileInfo = (OFSTRUCT *)(pModule + 1);
995 pModule->fileinfo = (int)pFileInfo - (int)pModule;
996 memset( pFileInfo, 0, sizeof(*pFileInfo) - sizeof(pFileInfo->szPathName) );
997 pFileInfo->cBytes = sizeof(*pFileInfo) - sizeof(pFileInfo->szPathName)
998 + strlen(DLLFileName);
999 strcpy( pFileInfo->szPathName, DLLFileName );
1000 pstr = (char *)pFileInfo + pFileInfo->cBytes + 1;
1004 pModule->seg_table = (int)pstr - (int)pModule;
1006 /* Resource table */
1008 pword = (WORD *)pstr;
1009 pModule->res_table = (int)pword - (int)pModule;
1013 /* Imported names table */
1015 pstr = (char *)pword;
1016 pModule->import_table = (int)pstr - (int)pModule;
1020 /* Resident names table */
1022 pModule->name_table = (int)pstr - (int)pModule;
1023 /* First entry is module name */
1024 *pstr = strlen(DLLName );
1025 strcpy( pstr + 1, DLLName );
1028 pstr += sizeof(WORD);
1033 pModule->entry_table = (int)pstr - (int)pModule;
1036 /* Dump the module content */
1038 DumpBytes( outfile, (char *)pModule, (int)pstr - (int)pModule,
1039 ".data", "Module_Start" );
1040 return (int)pstr - (int)pModule;
1044 /*******************************************************************
1047 * Build a Win32 assembly file from a spec file.
1049 static int BuildSpec32File( char * specfile, FILE *outfile )
1052 int i, module_size, len;
1055 fprintf( outfile, "/* File generated automatically; do not edit! */\n" );
1056 fprintf( outfile, "\t.file\t\"%s\"\n", specfile );
1058 getcwd(buffer, sizeof(buffer));
1061 * The stabs help the internal debugger as they are an indication that it
1062 * is sensible to step into a thunk/trampoline.
1064 fprintf( outfile, ".stabs \"%s/\",100,0,0,Code_Start\n", buffer);
1065 fprintf( outfile, ".stabs \"%s\",100,0,0,Code_Start\n", specfile);
1068 fprintf( outfile, "\t.text\n" );
1069 fprintf( outfile, "\t.align 4\n" );
1070 fprintf( outfile, "Code_Start:\n\n" );
1072 for (i = Base, odp = OrdinalDefinitions + Base; i <= Limit; i++, odp++)
1083 fprintf( outfile, "/* %s.%d (%s) */\n", DLLName, i, odp->name);
1085 fprintf( outfile, ".stabs \"%s_%d:F1\",36,0,%d,%s_%d\n",
1086 DLLName, i, odp->lineno, DLLName, i);
1088 fprintf( outfile, "%s_%d:\n", DLLName, i );
1090 fprintf( outfile, ".stabn 68,0,%d,0\n", odp->lineno);
1092 fprintf( outfile, "\tpushl %%ebp\n" );
1093 fprintf( outfile, "\tpushl $" PREFIX "%s\n",odp->u.func.link_name);
1094 fprintf( outfile, "\tcall " PREFIX "CallFrom32_%s_%d\n",
1095 (odp->type == TYPE_REGISTER) ? "regs" :
1096 ((odp->type == TYPE_STDCALL) ? "stdcall" : "cdecl"),
1097 strlen(odp->u.func.arg_types));
1098 fprintf( outfile, "\tnop\n" );
1102 fprintf( outfile, "/* %s.%d (%s) */\n", DLLName, i, odp->name);
1104 fprintf( outfile, ".stabs \"%s_%d:F1\",36,0,%d,%s_%d\n",
1105 DLLName, i, odp->lineno, DLLName, i);
1107 fprintf( outfile, "%s_%d:\n", DLLName, i );
1109 fprintf( outfile, ".stabn 68,0,%d,0\n", odp->lineno);
1111 fprintf( outfile, "\tmovl $%d,%%eax\n", odp->u.ret.ret_value );
1112 if (odp->u.ret.arg_size)
1114 fprintf( outfile, "\tret $%d\n", odp->u.ret.arg_size );
1118 fprintf( outfile, "\tret\n" );
1119 fprintf( outfile, "\tnop\n" );
1120 fprintf( outfile, "\tnop\n" );
1125 fprintf( outfile, "/* %s.%d (%s) */\n", DLLName, i, odp->name);
1126 fprintf( outfile, "\t.data\n" );
1127 fprintf( outfile, "%s_%d:\n", DLLName, i );
1128 len = StoreVariableCode( buffer, 1, odp );
1129 DumpBytes( outfile, buffer, len, NULL, NULL );
1130 fprintf( outfile, "\t.text\n" );
1134 fprintf( outfile, "/* %s.%d (%s) */\n",
1135 DLLName, i, odp->name);
1136 fprintf( outfile, "\t.data\n" );
1137 fprintf( outfile, "%s_%d:\n", DLLName, i );
1138 len = StoreVariableCode( buffer, 2, odp );
1139 DumpBytes( outfile, buffer, len, NULL, NULL );
1140 fprintf( outfile, "\t.text\n" );
1144 fprintf( outfile, "/* %s.%d (%s) */\n",
1145 DLLName, i, odp->name);
1146 fprintf( outfile, "\t.data\n" );
1147 fprintf( outfile, "%s_%d:\n", DLLName, i );
1148 len = StoreVariableCode( buffer, 4, odp );
1149 DumpBytes( outfile, buffer, len, NULL, NULL );
1150 fprintf( outfile, "\t.text\n" );
1158 fprintf(stderr,"build: function type %d not available for Win32\n",
1164 module_size = BuildModule32( outfile );
1166 /* Output the DLL functions table for no debugging code */
1168 fprintf( outfile, "\t.text\n" );
1169 fprintf( outfile, "\t.align 4\n" );
1170 fprintf( outfile, "NoDbg_Functions:\n" );
1171 for (i = Base, odp = OrdinalDefinitions + Base; i <= Limit; i++, odp++)
1176 fprintf( outfile, "\t.long 0\n" );
1179 fprintf( outfile, "\t.long " PREFIX "%s\n",odp->u.vargs.link_name);
1182 fprintf( outfile, "\t.long " PREFIX "%s\n", odp->u.ext.link_name );
1186 fprintf( outfile, "\t.long " PREFIX "%s\n", odp->u.func.link_name);
1189 fprintf( outfile, "\t.long %s_%d\n", DLLName, i );
1194 /* Output the DLL functions table for debugging code */
1196 fprintf( outfile, "\t.text\n" );
1197 fprintf( outfile, "\t.align 4\n" );
1198 fprintf( outfile, "Functions:\n" );
1199 for (i = Base, odp = OrdinalDefinitions + Base; i <= Limit; i++, odp++)
1204 fprintf( outfile, "\t.long 0\n" );
1207 fprintf( outfile, "\t.long " PREFIX "%s\n",odp->u.vargs.link_name);
1210 fprintf( outfile, "\t.long " PREFIX "%s\n", odp->u.ext.link_name );
1213 fprintf( outfile, "\t.long %s_%d\n", DLLName, i );
1218 /* Output the DLL names table */
1220 fprintf( outfile, "FuncNames:\n" );
1221 for (i = Base, odp = OrdinalDefinitions + Base; i <= Limit; i++, odp++)
1223 if (odp->type == TYPE_INVALID) fprintf( outfile, "\t.long 0\n" );
1224 else fprintf( outfile, "\t.long Name_%d\n", i );
1227 /* Output the DLL names */
1229 for (i = Base, odp = OrdinalDefinitions + Base; i <= Limit; i++, odp++)
1231 if (odp->type != TYPE_INVALID)
1232 fprintf( outfile, "Name_%d:\t.ascii \"%s\\0\"\n", i, odp->name );
1235 /* Output the DLL descriptor */
1237 fprintf( outfile, "DLLName:\t.ascii \"%s\\0\"\n", DLLName );
1238 fprintf( outfile, "\t.align 4\n" );
1239 fprintf( outfile, "\t.globl " PREFIX "%s_Descriptor\n", DLLName );
1240 fprintf( outfile, PREFIX "%s_Descriptor:\n", DLLName );
1241 fprintf( outfile, "\t.long DLLName\n" ); /* Name */
1242 fprintf( outfile, "\t.long Module_Start\n" ); /* Module start */
1243 fprintf( outfile, "\t.long %d\n", module_size ); /* Module size */
1244 fprintf( outfile, "\t.long %d\n", Base ); /* Base */
1245 fprintf( outfile, "\t.long %d\n", Limit+1-Base ); /* Size */
1246 fprintf( outfile, "\t.long Code_Start\n" ); /* Code start */
1247 fprintf( outfile, "\t.long Functions\n" ); /* Functions */
1248 fprintf( outfile, "\t.long NoDbg_Functions\n" ); /* Funcs without debug*/
1249 fprintf( outfile, "\t.long FuncNames\n" ); /* Function names */
1251 fprintf( outfile, "\t.text\n");
1252 fprintf( outfile, "\t.stabs \"\",100,0,0,.Letext\n");
1253 fprintf( outfile, ".Letext:\n");
1259 /*******************************************************************
1262 * Build a Win16 assembly file from a spec file.
1264 static int BuildSpec16File( char * specfile, FILE *outfile )
1268 int code_offset, data_offset, module_size;
1269 unsigned char *data;
1271 data = (unsigned char *)xmalloc( 0x10000 );
1272 memset( data, 0, 16 );
1275 fprintf( outfile, "/* File generated automatically; do not edit! */\n" );
1276 fprintf( outfile, "\t.text\n" );
1277 fprintf( outfile, "Code_Start:\n" );
1280 odp = OrdinalDefinitions;
1281 for (i = 0; i <= Limit; i++, odp++)
1286 odp->offset = 0xffff;
1290 odp->offset = LOWORD(odp->u.abs.value);
1294 odp->offset = data_offset;
1295 data_offset += StoreVariableCode( data + data_offset, 1, odp);
1299 odp->offset = data_offset;
1300 data_offset += StoreVariableCode( data + data_offset, 2, odp);
1304 odp->offset = data_offset;
1305 data_offset += StoreVariableCode( data + data_offset, 4, odp);
1309 fprintf( outfile,"/* %s.%d */\n", DLLName, i);
1310 fprintf( outfile,"\tmovw $%d,%%ax\n",LOWORD(odp->u.ret.ret_value));
1311 fprintf( outfile,"\tmovw $%d,%%dx\n",HIWORD(odp->u.ret.ret_value));
1312 fprintf( outfile,"\t.byte 0x66\n");
1313 if (odp->u.ret.arg_size != 0)
1314 fprintf( outfile, "\tlret $%d\n\n", odp->u.ret.arg_size);
1317 fprintf( outfile, "\tlret\n");
1318 fprintf( outfile, "\tnop\n");
1319 fprintf( outfile, "\tnop\n\n");
1321 odp->offset = code_offset;
1322 code_offset += 12; /* Assembly code is 12 bytes long */
1327 case TYPE_PASCAL_16:
1329 fprintf( outfile, "/* %s.%d */\n", DLLName, i);
1330 fprintf( outfile, "\tpushw %%bp\n" );
1331 fprintf( outfile, "\tpushl $" PREFIX "%s\n",odp->u.func.link_name);
1332 /* FreeBSD does not understand lcall, so do it the hard way */
1333 fprintf( outfile, "\t.byte 0x9a\n" );
1334 fprintf( outfile, "\t.long " PREFIX "CallFrom16_%s_%s\n",
1335 (odp->type == TYPE_REGISTER) ? "regs" :
1336 (odp->type == TYPE_PASCAL) ? "long" : "word",
1337 odp->u.func.arg_types );
1338 fprintf( outfile,"\t.byte 0x%02x,0x%02x\n", /* Some asms don't have .word */
1339 LOBYTE(WINE_CODE_SELECTOR), HIBYTE(WINE_CODE_SELECTOR) );
1340 fprintf( outfile, "\tnop\n" );
1341 fprintf( outfile, "\tnop\n\n" );
1342 odp->offset = code_offset;
1343 code_offset += 16; /* Assembly code is 16 bytes long */
1347 fprintf(stderr,"build: function type %d not available for Win16\n",
1353 if (!code_offset) /* Make sure the code segment is not empty */
1355 fprintf( outfile, "\t.byte 0\n" );
1359 /* Output data segment */
1361 DumpBytes( outfile, data, data_offset, NULL, "Data_Start" );
1363 /* Build the module */
1365 module_size = BuildModule16( outfile, code_offset, data_offset );
1367 /* Output the DLL descriptor */
1369 fprintf( outfile, "\t.text\n" );
1370 fprintf( outfile, "DLLName:\t.ascii \"%s\\0\"\n", DLLName );
1371 fprintf( outfile, "\t.align 4\n" );
1372 fprintf( outfile, "\t.globl " PREFIX "%s_Descriptor\n", DLLName );
1373 fprintf( outfile, PREFIX "%s_Descriptor:\n", DLLName );
1374 fprintf( outfile, "\t.long DLLName\n" ); /* Name */
1375 fprintf( outfile, "\t.long Module_Start\n" ); /* Module start */
1376 fprintf( outfile, "\t.long %d\n", module_size ); /* Module size */
1377 fprintf( outfile, "\t.long Code_Start\n" ); /* Code start */
1378 fprintf( outfile, "\t.long Data_Start\n" ); /* Data start */
1383 /*******************************************************************
1386 * Build an assembly file from a spec file.
1388 static int BuildSpecFile( FILE *outfile, char *specname )
1390 SpecName = specname;
1391 SpecFp = fopen( specname, "r");
1394 fprintf(stderr, "Could not open specification file, '%s'\n", specname);
1398 if (ParseTopLevel() < 0) return -1;
1403 return BuildSpec16File( specname, outfile );
1405 return BuildSpec32File( specname, outfile );
1407 fprintf( stderr, "%s: Missing 'type' declaration\n", specname );
1413 /*******************************************************************
1414 * BuildCall32LargeStack
1416 * Build the function used to switch to the original 32-bit stack
1417 * before calling a 32-bit function from 32-bit code. This is used for
1418 * functions that need a large stack, like X bitmaps functions.
1420 * The generated function has the following prototype:
1421 * int xxx( int (*func)(), void *arg );
1423 * The pointer to the function can be retrieved by calling CALL32_Init,
1424 * which also takes care of saving the current 32-bit stack pointer.
1433 static void BuildCall32LargeStack( FILE *outfile )
1435 /* Initialization function */
1437 fprintf( outfile, "\n\t.align 4\n" );
1439 fprintf( outfile, ".stabs \"CALL32_Init:F1\",36,0,0," PREFIX "CALL32_Init\n");
1441 fprintf( outfile, "\t.globl " PREFIX "CALL32_Init\n" );
1442 fprintf( outfile, PREFIX "CALL32_Init:\n" );
1443 fprintf( outfile, "\tleal -256(%%esp),%%eax\n" );
1444 fprintf( outfile, "\tmovl %%eax,CALL32_Original32_esp\n" );
1445 fprintf( outfile, "\tmovl $CALL32_LargeStack,%%eax\n" );
1446 fprintf( outfile, "\tret\n" );
1448 /* Function header */
1450 fprintf( outfile, "\n\t.align 4\n" );
1452 fprintf( outfile, ".stabs \"CALL32_LargeStack:F1\",36,0,0,CALL32_LargeStack\n");
1454 fprintf( outfile, "CALL32_LargeStack:\n" );
1458 fprintf( outfile, "\tpushl %%ebp\n" );
1459 fprintf( outfile, "\tmovl %%esp,%%ebp\n" );
1461 /* Switch to the original 32-bit stack pointer */
1463 fprintf( outfile, "\tmovl CALL32_Original32_esp, %%esp\n" );
1465 /* Transfer the argument and call the function */
1467 fprintf( outfile, "\tpushl 12(%%ebp)\n" );
1468 fprintf( outfile, "\tcall 8(%%ebp)\n" );
1470 /* Restore registers and return */
1472 fprintf( outfile, "\tmovl %%ebp,%%esp\n" );
1473 fprintf( outfile, "\tpopl %%ebp\n" );
1474 fprintf( outfile, "\tret\n" );
1478 fprintf( outfile, "\t.data\n" );
1479 fprintf( outfile, "CALL32_Original32_esp:\t.long 0\n" );
1480 fprintf( outfile, "\t.text\n" );
1484 /*******************************************************************
1485 * TransferArgs16To32
1487 * Get the arguments from the 16-bit stack and push them on the 32-bit stack.
1488 * The 16-bit stack layout is:
1496 static int TransferArgs16To32( FILE *outfile, char *args )
1498 int i, pos16, pos32;
1500 /* Save ebx first */
1502 fprintf( outfile, "\tpushl %%ebx\n" );
1504 /* Get the 32-bit stack pointer */
1506 fprintf( outfile, "\tmovl " PREFIX "CALLTO16_Saved32_esp,%%ebx\n" );
1508 /* Copy the arguments */
1510 pos16 = 6; /* skip bp and return address */
1513 for (i = strlen(args); i > 0; i--)
1518 case 'w': /* word */
1519 fprintf( outfile, "\tmovzwl %d(%%ebp),%%eax\n", pos16 );
1520 fprintf( outfile, "\tmovl %%eax,%d(%%ebx)\n", pos32 );
1524 case 's': /* s_word */
1525 fprintf( outfile, "\tmovswl %d(%%ebp),%%eax\n", pos16 );
1526 fprintf( outfile, "\tmovl %%eax,%d(%%ebx)\n", pos32 );
1530 case 'l': /* long or segmented pointer */
1531 case 'T': /* segmented pointer to null-terminated string */
1532 fprintf( outfile, "\tmovl %d(%%ebp),%%eax\n", pos16 );
1533 fprintf( outfile, "\tmovl %%eax,%d(%%ebx)\n", pos32 );
1537 case 'p': /* linear pointer */
1538 case 't': /* linear pointer to null-terminated string */
1539 /* Get the selector */
1540 fprintf( outfile, "\tmovw %d(%%ebp),%%ax\n", pos16 + 2 );
1541 /* Get the selector base */
1542 fprintf( outfile, "\tandl $0xfff8,%%eax\n" );
1543 fprintf( outfile, "\tmovl " PREFIX "ldt_copy(%%eax),%%eax\n" );
1544 fprintf( outfile, "\tmovl %%eax,%d(%%ebx)\n", pos32 );
1545 /* Add the offset */
1546 fprintf( outfile, "\tmovzwl %d(%%ebp),%%eax\n", pos16 );
1547 fprintf( outfile, "\taddl %%eax,%d(%%ebx)\n", pos32 );
1552 fprintf( stderr, "Unknown arg type '%c'\n", args[i-1] );
1558 fprintf( outfile, "\tpopl %%ebx\n" );
1560 return pos16 - 6; /* Return the size of the 16-bit args */
1564 /*******************************************************************
1567 * Build the context structure on the 32-bit stack.
1569 static void BuildContext16( FILE *outfile )
1571 /* Save ebx first */
1573 fprintf( outfile, "\tpushl %%ebx\n" );
1575 /* Get the 32-bit stack pointer */
1577 fprintf( outfile, "\tmovl " PREFIX "CALLTO16_Saved32_esp,%%ebx\n" );
1579 /* Store the registers */
1581 fprintf( outfile, "\tpopl %d(%%ebx)\n", /* Get ebx from stack*/
1582 CONTEXTOFFSET(Ebx) - sizeof(CONTEXT) );
1583 fprintf( outfile, "\tmovl %%eax,%d(%%ebx)\n",
1584 CONTEXTOFFSET(Eax) - sizeof(CONTEXT) );
1585 fprintf( outfile, "\tmovl %%ecx,%d(%%ebx)\n",
1586 CONTEXTOFFSET(Ecx) - sizeof(CONTEXT) );
1587 fprintf( outfile, "\tmovl %%edx,%d(%%ebx)\n",
1588 CONTEXTOFFSET(Edx) - sizeof(CONTEXT) );
1589 fprintf( outfile, "\tmovl %%esi,%d(%%ebx)\n",
1590 CONTEXTOFFSET(Esi) - sizeof(CONTEXT) );
1591 fprintf( outfile, "\tmovl %%edi,%d(%%ebx)\n",
1592 CONTEXTOFFSET(Edi) - sizeof(CONTEXT) );
1594 fprintf( outfile, "\tmovzwl -10(%%ebp),%%eax\n" ); /* Get %ds from stack*/
1595 fprintf( outfile, "\tmovl %%eax,%d(%%ebx)\n",
1596 CONTEXTOFFSET(SegDs) - sizeof(CONTEXT) );
1597 fprintf( outfile, "\tmovzwl -6(%%ebp),%%eax\n" ); /* Get %es from stack*/
1598 fprintf( outfile, "\tmovl %%eax,%d(%%ebx)\n",
1599 CONTEXTOFFSET(SegEs) - sizeof(CONTEXT) );
1600 fprintf( outfile, "\tpushfl\n" );
1601 fprintf( outfile, "\tpopl %d(%%ebx)\n",
1602 CONTEXTOFFSET(EFlags) - sizeof(CONTEXT) );
1603 fprintf( outfile, "\tmovl -16(%%ebp),%%eax\n" ); /* Get %ebp from stack */
1604 fprintf( outfile, "\tmovl %%eax,%d(%%ebx)\n",
1605 CONTEXTOFFSET(Ebp) - sizeof(CONTEXT) );
1606 fprintf( outfile, "\tmovzwl 2(%%ebp),%%eax\n" ); /* Get %ip from stack */
1607 fprintf( outfile, "\tmovl %%eax,%d(%%ebx)\n",
1608 CONTEXTOFFSET(Eip) - sizeof(CONTEXT) );
1609 fprintf( outfile, "\tmovzwl 4(%%ebp),%%eax\n" ); /* Get %cs from stack */
1610 fprintf( outfile, "\tmovl %%eax,%d(%%ebx)\n",
1611 CONTEXTOFFSET(SegCs) - sizeof(CONTEXT) );
1612 fprintf( outfile, "\tmovw %%fs,%%ax\n" );
1613 fprintf( outfile, "\tmovl %%eax,%d(%%ebx)\n",
1614 CONTEXTOFFSET(SegFs) - sizeof(CONTEXT) );
1615 fprintf( outfile, "\tmovw %%gs,%%ax\n" );
1616 fprintf( outfile, "\tmovl %%eax,%d(%%ebx)\n",
1617 CONTEXTOFFSET(SegGs) - sizeof(CONTEXT) );
1618 fprintf( outfile, "\tmovw %%ss,%%ax\n" );
1619 fprintf( outfile, "\tmovl %%eax,%d(%%ebx)\n",
1620 CONTEXTOFFSET(SegSs) - sizeof(CONTEXT) );
1622 fprintf( outfile, "\tfsave %d(%%ebx)\n",
1623 CONTEXTOFFSET(FloatSave) - sizeof(CONTEXT) );
1628 /*******************************************************************
1631 * Restore the registers from the context structure.
1632 * %edx must point to the 32-bit stack top.
1634 static void RestoreContext16( FILE *outfile )
1636 /* Get the 32-bit stack pointer */
1638 fprintf( outfile, "\tmovl %%edx,%%ebx\n" );
1640 /* Remove everything up to the return address from the 16-bit stack */
1642 fprintf( outfile, "\taddl $22,%%esp\n" );
1644 /* Restore the registers */
1646 fprintf( outfile, "\tmovl %d(%%ebx),%%ecx\n",
1647 CONTEXTOFFSET(Ecx) - sizeof(CONTEXT) );
1648 fprintf( outfile, "\tmovl %d(%%ebx),%%edx\n",
1649 CONTEXTOFFSET(Edx) - sizeof(CONTEXT) );
1650 fprintf( outfile, "\tmovl %d(%%ebx),%%esi\n",
1651 CONTEXTOFFSET(Esi) - sizeof(CONTEXT) );
1652 fprintf( outfile, "\tmovl %d(%%ebx),%%edi\n",
1653 CONTEXTOFFSET(Edi) - sizeof(CONTEXT) );
1654 fprintf( outfile, "\tmovl %d(%%ebx),%%ebp\n",
1655 CONTEXTOFFSET(Ebp) - sizeof(CONTEXT) );
1656 fprintf( outfile, "\tpushw %d(%%ebx)\n", /* Push new cs */
1657 CONTEXTOFFSET(SegCs) - sizeof(CONTEXT) );
1658 fprintf( outfile, "\tpushw %d(%%ebx)\n", /* Push new ip */
1659 CONTEXTOFFSET(Eip) - sizeof(CONTEXT) );
1660 fprintf( outfile, "\tpushw %d(%%ebx)\n", /* Push new ds */
1661 CONTEXTOFFSET(SegDs) - sizeof(CONTEXT) );
1662 fprintf( outfile, "\tpushw %d(%%ebx)\n", /* Push new es */
1663 CONTEXTOFFSET(SegEs) - sizeof(CONTEXT) );
1664 fprintf( outfile, "\tpushl %d(%%ebx)\n",
1665 CONTEXTOFFSET(EFlags) - sizeof(CONTEXT) );
1666 fprintf( outfile, "\tpopfl\n" );
1667 fprintf( outfile, "\tmovl %d(%%ebx),%%eax\n",
1668 CONTEXTOFFSET(Eax) - sizeof(CONTEXT) );
1669 fprintf( outfile, "\tmovl %d(%%ebx),%%ebx\n",
1670 CONTEXTOFFSET(Ebx) - sizeof(CONTEXT) );
1671 fprintf( outfile, "\tpopw %%es\n" ); /* Set es */
1672 fprintf( outfile, "\tpopw %%ds\n" ); /* Set ds */
1676 /*******************************************************************
1677 * BuildCallFrom16Func
1679 * Build a 16-bit-to-Wine callback function. The syntax of the function
1680 * profile is: type_xxxxx, where 'type' is one of 'regs', 'word' or
1681 * 'long' and each 'x' is an argument ('w'=word, 's'=signed word,
1682 * 'l'=long, 'p'=linear pointer, 't'=linear pointer to null-terminated string,
1683 * 'T'=segmented pointer to null-terminated string).
1684 * For register functions, the arguments are ignored, but they are still
1685 * removed from the stack upon return.
1687 * Stack layout upon entry to the callback function:
1689 * (sp+18) word first 16-bit arg
1693 * (sp+8) long 32-bit entry point (used to store edx)
1694 * (sp+6) word high word of cs (always 0, used to store es)
1695 * (sp+4) word low word of cs of 16-bit entry point
1696 * (sp+2) word high word of ip (always 0, used to store ds)
1697 * (sp) word low word of ip of 16-bit entry point
1699 * Added on the stack:
1701 * (sp-6) word saved previous sp
1702 * (sp-8) word saved previous ss
1704 static void BuildCallFrom16Func( FILE *outfile, char *profile )
1709 char *args = profile + 5;
1711 /* Parse function type */
1713 if (!strncmp( "word_", profile, 5 )) short_ret = 1;
1714 else if (!strncmp( "regs_", profile, 5 )) reg_func = 1;
1715 else if (strncmp( "long_", profile, 5 ))
1717 fprintf( stderr, "Invalid function name '%s', ignored\n", profile );
1721 /* Function header */
1723 fprintf( outfile, "\n\t.align 4\n" );
1725 fprintf( outfile, ".stabs \"CallFrom16_%s:F1\",36,0,0," PREFIX "CallFrom16_%s\n",
1728 fprintf( outfile, "\t.globl " PREFIX "CallFrom16_%s\n", profile );
1729 fprintf( outfile, PREFIX "CallFrom16_%s:\n", profile );
1731 /* Setup bp to point to its copy on the stack */
1733 fprintf( outfile, "\tpushl %%ebp\n" ); /* Save the full 32-bit ebp */
1734 fprintf( outfile, "\tmovzwl %%sp,%%ebp\n" );
1735 fprintf( outfile, "\taddw $16,%%bp\n" );
1737 /* Save 16-bit ds and es */
1739 /* Stupid FreeBSD assembler doesn't know these either */
1740 /* fprintf( outfile, "\tmovw %%ds,-10(%%ebp)\n" ); */
1741 fprintf( outfile, "\t.byte 0x66,0x8c,0x5d,0xf6\n" );
1742 /* fprintf( outfile, "\tmovw %%es,-6(%%ebp)\n" ); */
1743 fprintf( outfile, "\t.byte 0x66,0x8c,0x45,0xfa\n" );
1745 /* Restore 32-bit ds and es */
1747 fprintf( outfile, "\tpushl $0x%04x%04x\n",
1748 WINE_DATA_SELECTOR, WINE_DATA_SELECTOR );
1749 fprintf( outfile, "\tpopw %%ds\n" );
1750 fprintf( outfile, "\tpopw %%es\n" );
1753 /* Save the 16-bit stack */
1755 fprintf( outfile, "\tpushl " PREFIX "IF1632_Saved16_ss_sp\n" );
1757 fprintf( outfile,"\tdata16\n");
1759 fprintf( outfile, "\tmovw %%ss," PREFIX "IF1632_Saved16_ss_sp+2\n" );
1760 fprintf( outfile, "\tmovw %%sp," PREFIX "IF1632_Saved16_ss_sp\n" );
1762 /* Transfer the arguments */
1764 if (reg_func) BuildContext16( outfile );
1765 else if (*args) argsize = TransferArgs16To32( outfile, args );
1767 /* Get the address of the API function */
1769 fprintf( outfile, "\tmovl -4(%%ebp),%%eax\n" );
1771 /* If necessary, save %edx over the API function address */
1773 if (!reg_func && short_ret)
1774 fprintf( outfile, "\tmovl %%edx,-4(%%ebp)\n" );
1776 /* Switch to the 32-bit stack */
1778 fprintf( outfile, "\tmovl " PREFIX "CALLTO16_Saved32_esp,%%ebp\n" );
1779 fprintf( outfile, "\tpushw %%ds\n" );
1780 fprintf( outfile, "\tpopw %%ss\n" );
1781 fprintf( outfile, "\tleal -%d(%%ebp),%%esp\n",
1782 reg_func ? sizeof(CONTEXT) : 4 * strlen(args) );
1783 if (reg_func) /* Push the address of the context struct */
1784 fprintf( outfile, "\tpushl %%esp\n" );
1786 /* Setup %ebp to point to the previous stack frame (built by CallTo16) */
1788 fprintf( outfile, "\taddl $%d,%%ebp\n", STRUCTOFFSET(STACK32FRAME,ebp) );
1790 /* Print the debug information before the call */
1794 fprintf( outfile, "\tpushl %%eax\n" );
1795 fprintf( outfile, "\tpushl $Profile_%s\n", profile );
1796 fprintf( outfile, "\tpushl $%d\n", reg_func ? 2 : (short_ret ? 1 : 0));
1797 fprintf( outfile, "\tcall " PREFIX "RELAY_DebugCallFrom16\n" );
1798 fprintf( outfile, "\tpopl %%eax\n" );
1799 fprintf( outfile, "\tpopl %%eax\n" );
1800 fprintf( outfile, "\tpopl %%eax\n" );
1803 /* Call the entry point */
1805 fprintf( outfile, "\tcall %%eax\n" );
1807 /* Print the debug information after the call */
1813 /* Push again the address of the context struct in case */
1814 /* it has been removed by an stdcall function */
1815 fprintf( outfile, "\tleal -%d(%%ebp),%%esp\n",
1816 sizeof(CONTEXT) + 32 );
1817 fprintf( outfile, "\tpushl %%esp\n" );
1819 fprintf( outfile, "\tpushl %%eax\n" );
1820 fprintf( outfile, "\tpushl $%d\n", reg_func ? 2 : (short_ret ? 1 : 0));
1821 fprintf( outfile, "\tcall " PREFIX "RELAY_DebugCallFrom16Ret\n" );
1822 fprintf( outfile, "\tpopl %%eax\n" );
1823 fprintf( outfile, "\tpopl %%eax\n" );
1826 /* Restore the value of the saved 32-bit stack pointer */
1828 fprintf( outfile, "\tleal -%d(%%ebp),%%edx\n",
1829 STRUCTOFFSET(STACK32FRAME,ebp) );
1830 fprintf( outfile, "movl %%edx," PREFIX "CALLTO16_Saved32_esp\n" );
1832 /* Restore the 16-bit stack */
1835 fprintf( outfile, "\tdata16\n");
1837 fprintf( outfile, "\tmovw " PREFIX "IF1632_Saved16_ss_sp+2,%%ss\n" );
1838 fprintf( outfile, "\tmovw " PREFIX "IF1632_Saved16_ss_sp,%%sp\n" );
1839 fprintf( outfile, "\tpopl " PREFIX "IF1632_Saved16_ss_sp\n" );
1843 /* Calc the arguments size */
1859 fprintf( stderr, "Unknown arg type '%c'\n", *args );
1864 /* Restore registers from the context structure */
1865 RestoreContext16( outfile );
1869 /* Restore high 16 bits of ebp */
1870 fprintf( outfile, "\tpopl %%ebp\n" );
1872 /* Restore ds and es */
1873 fprintf( outfile, "\tincl %%esp\n" ); /* Remove ip */
1874 fprintf( outfile, "\tincl %%esp\n" );
1875 fprintf( outfile, "\tpopl %%edx\n" ); /* Remove cs and ds */
1876 fprintf( outfile, "\tmovw %%dx,%%ds\n" ); /* and restore ds */
1877 fprintf( outfile, "\tpopw %%es\n" ); /* Restore es */
1879 if (short_ret) fprintf( outfile, "\tpopl %%edx\n" ); /* Restore edx */
1882 /* Get the return value into dx:ax */
1883 fprintf( outfile, "\tmovl %%eax,%%edx\n" );
1884 fprintf( outfile, "\tshrl $16,%%edx\n" );
1885 /* Remove API entry point */
1886 fprintf( outfile, "\taddl $4,%%esp\n" );
1889 /* Restore low 16 bits of ebp */
1890 fprintf( outfile, "\tpopw %%bp\n" );
1893 /* Remove the arguments and return */
1897 fprintf( outfile, "\t.byte 0x66\n" );
1898 fprintf( outfile, "\tlret $%d\n", argsize );
1902 fprintf( outfile, "\t.byte 0x66\n" );
1903 fprintf( outfile, "\tlret\n" );
1908 /*******************************************************************
1911 * Build a Wine-to-16-bit callback function.
1913 * Stack frame of the callback function:
1917 * (ebp+8) func to call
1918 * (ebp+4) return address
1919 * (ebp) previous ebp
1921 * Prototypes for the CallTo16 functions:
1922 * extern WINAPI WORD CallTo16_word_xxx( FARPROC16 func, args... );
1923 * extern WINAPI LONG CallTo16_long_xxx( FARPROC16 func, args... );
1924 * extern WINAPI void CallTo16_regs_( const CONTEXT *context );
1926 static void BuildCallTo16Func( FILE *outfile, char *profile )
1930 char *args = profile + 5;
1932 if (!strncmp( "word_", profile, 5 )) short_ret = 1;
1933 else if (!strncmp( "regs_", profile, 5 )) reg_func = 1;
1934 else if (strncmp( "long_", profile, 5 ))
1936 fprintf( stderr, "Invalid function name '%s', ignored\n", profile );
1940 /* Function header */
1942 fprintf( outfile, "\n\t.align 4\n" );
1944 fprintf( outfile, ".stabs \"CallTo16_%s:F1\",36,0,0," PREFIX "CallTo16_%s\n",
1947 fprintf( outfile, "\t.globl " PREFIX "CallTo16_%s\n", profile );
1948 fprintf( outfile, PREFIX "CallTo16_%s:\n", profile );
1952 fprintf( outfile, "\tpushl %%ebp\n" );
1953 fprintf( outfile, "\tmovl %%esp,%%ebp\n" );
1955 /* Call the actual CallTo16 routine (simulate a lcall) */
1957 fprintf( outfile, "\tpushw $0\n" );
1958 fprintf( outfile, "\tpushw %%cs\n" );
1959 fprintf( outfile, "\tcall do_callto16_%s\n", profile );
1963 /* FIXME: this is a hack because of task.c */
1964 if (!strcmp( profile, "word_" ))
1966 fprintf( outfile, ".globl " PREFIX "CALLTO16_Restore\n" );
1967 fprintf( outfile, PREFIX "CALLTO16_Restore:\n" );
1969 fprintf( outfile, "\tpopl %%ebp\n" );
1970 fprintf( outfile, "\tret $%d\n", strlen(args) + 1 );
1972 /* Start of the actual CallTo16 routine */
1974 /* Save the 32-bit registers */
1976 fprintf( outfile, "do_callto16_%s:\n", profile );
1977 fprintf( outfile, "\tpushl %%ebx\n" );
1978 fprintf( outfile, "\tpushl %%ecx\n" );
1979 fprintf( outfile, "\tpushl %%edx\n" );
1980 fprintf( outfile, "\tpushl %%esi\n" );
1981 fprintf( outfile, "\tpushl %%edi\n" );
1983 /* Save the 32-bit stack */
1985 fprintf( outfile, "\tmovl %%esp," PREFIX "CALLTO16_Saved32_esp\n" );
1986 fprintf( outfile, "\tmovl %%ebp,%%ebx\n" );
1988 /* Print debugging info */
1992 /* Push the address of the first argument */
1993 fprintf( outfile, "\tleal 8(%%ebp),%%eax\n" );
1994 fprintf( outfile, "\tpushl $%d\n", reg_func ? -1 : strlen(args) );
1995 fprintf( outfile, "\tpushl %%eax\n" );
1996 fprintf( outfile, "\tcall " PREFIX "RELAY_DebugCallTo16\n" );
1997 fprintf( outfile, "\tpopl %%eax\n" );
1998 fprintf( outfile, "\tpopl %%eax\n" );
2003 /* Switch to the 16-bit stack, saving the current %%esp, */
2004 /* and adding the specified offset to the new sp */
2005 fprintf( outfile, "\tmovzwl " PREFIX "IF1632_Saved16_ss_sp,%%edx\n" );
2006 fprintf( outfile, "\tleal -4(%%edx),%%edx\n" );
2007 fprintf( outfile, "\tmovl 12(%%ebx),%%eax\n" ); /* Get the offset */
2008 fprintf( outfile, "\taddl %%edx,%%eax\n" );
2010 fprintf( outfile,"\tdata16\n");
2012 fprintf( outfile, "\tmovw " PREFIX "IF1632_Saved16_ss_sp+2,%%ss\n" );
2013 fprintf( outfile, "\txchgl %%esp,%%eax\n" );
2014 fprintf( outfile, "\t.byte 0x36\n" /* %ss: */ );
2015 fprintf( outfile, "\tmovl %%eax,0(%%edx)\n" );
2017 /* Get the registers. ebx is handled later on. */
2019 fprintf( outfile, "\tmovl 8(%%ebx),%%ebx\n" );
2020 fprintf( outfile, "\tmovl %d(%%ebx),%%eax\n", CONTEXTOFFSET(SegEs) );
2021 fprintf( outfile, "\tmovw %%ax,%%es\n" );
2022 fprintf( outfile, "\tmovl %d(%%ebx),%%ebp\n", CONTEXTOFFSET(Ebp) );
2023 fprintf( outfile, "\tmovl %d(%%ebx),%%eax\n", CONTEXTOFFSET(Eax) );
2024 fprintf( outfile, "\tmovl %d(%%ebx),%%ecx\n", CONTEXTOFFSET(Ecx) );
2025 fprintf( outfile, "\tmovl %d(%%ebx),%%edx\n", CONTEXTOFFSET(Edx) );
2026 fprintf( outfile, "\tmovl %d(%%ebx),%%esi\n", CONTEXTOFFSET(Esi) );
2027 fprintf( outfile, "\tmovl %d(%%ebx),%%edi\n", CONTEXTOFFSET(Edi) );
2029 /* Push the return address */
2031 fprintf( outfile, "\tpushl " PREFIX "CALLTO16_RetAddr_long\n" );
2033 /* Push the called routine address */
2035 fprintf( outfile, "\tpushw %d(%%ebx)\n", CONTEXTOFFSET(SegCs) );
2036 fprintf( outfile, "\tpushw %d(%%ebx)\n", CONTEXTOFFSET(Eip) );
2038 /* Get the 16-bit ds */
2040 fprintf( outfile, "\tpushw %d(%%ebx)\n", CONTEXTOFFSET(SegDs) );
2041 /* Get ebx from the 32-bit stack */
2042 fprintf( outfile, "\tmovl %d(%%ebx),%%ebx\n", CONTEXTOFFSET(Ebx) );
2043 fprintf( outfile, "\tpopw %%ds\n" );
2045 else /* not a register function */
2047 int pos = 12; /* first argument position */
2049 /* Switch to the 16-bit stack, saving the current %%esp */
2050 fprintf( outfile, "\tmovl %%esp,%%eax\n" );
2052 fprintf( outfile,"\tdata16\n");
2054 fprintf( outfile, "\tmovw " PREFIX "IF1632_Saved16_ss_sp+2,%%ss\n" );
2055 fprintf( outfile, "\tmovw " PREFIX "IF1632_Saved16_ss_sp,%%sp\n" );
2056 fprintf( outfile, "\tpushl %%eax\n" );
2058 /* Make %bp point to the previous stackframe (built by CallFrom16) */
2059 fprintf( outfile, "\tmovzwl %%sp,%%ebp\n" );
2060 fprintf( outfile, "\tleal %d(%%ebp),%%ebp\n",
2061 STRUCTOFFSET(STACK16FRAME,bp) + 4 /* for saved %%esp */ );
2063 /* Transfer the arguments */
2069 case 'w': /* word */
2070 fprintf( outfile, "\tpushw %d(%%ebx)\n", pos );
2072 case 'l': /* long */
2073 fprintf( outfile, "\tpushl %d(%%ebx)\n", pos );
2076 fprintf( stderr, "Unexpected case '%c' in BuildCallTo16Func\n",
2082 /* Push the return address */
2084 fprintf( outfile, "\tpushl " PREFIX "CALLTO16_RetAddr_%s\n",
2085 short_ret ? "word" : "long" );
2087 /* Push the called routine address */
2089 fprintf( outfile, "\tpushl 8(%%ebx)\n" );
2091 /* Set %ds and %es (and %ax just in case) equal to %ss */
2093 fprintf( outfile, "\tmovw %%ss,%%ax\n" );
2094 fprintf( outfile, "\tmovw %%ax,%%ds\n" );
2095 fprintf( outfile, "\tmovw %%ax,%%es\n" );
2098 /* Jump to the called routine */
2100 fprintf( outfile, "\t.byte 0x66\n" );
2101 fprintf( outfile, "\tlret\n" );
2105 /*******************************************************************
2108 * Build the return code for 16-bit callbacks
2110 static void BuildRet16Func( FILE *outfile )
2112 fprintf( outfile, "\t.globl " PREFIX "CALLTO16_Ret_word\n" );
2113 fprintf( outfile, "\t.globl " PREFIX "CALLTO16_Ret_long\n" );
2115 /* Put return value into eax */
2117 fprintf( outfile, PREFIX "CALLTO16_Ret_long:\n" );
2118 fprintf( outfile, "\tshll $16,%%edx\n" );
2119 fprintf( outfile, "\tmovw %%ax,%%dx\n" );
2120 fprintf( outfile, "\tmovl %%edx,%%eax\n" );
2121 fprintf( outfile, PREFIX "CALLTO16_Ret_word:\n" );
2123 /* Restore 32-bit segment registers */
2125 fprintf( outfile, "\tpopl %%ecx\n" ); /* Get the saved %%esp */
2126 fprintf( outfile, "\tmovw $0x%04x,%%bx\n", WINE_DATA_SELECTOR );
2128 fprintf( outfile, "\tdata16\n");
2130 fprintf( outfile, "\tmovw %%bx,%%ds\n" );
2132 fprintf( outfile, "\tdata16\n");
2134 fprintf( outfile, "\tmovw %%bx,%%es\n" );
2136 /* Restore the 32-bit stack */
2139 fprintf( outfile, "\tdata16\n");
2141 fprintf( outfile, "\tmovw %%bx,%%ss\n" );
2142 fprintf( outfile, "\tmovl %%ecx,%%esp\n" );
2144 /* Restore the 32-bit registers */
2146 fprintf( outfile, "\tpopl %%edi\n" );
2147 fprintf( outfile, "\tpopl %%esi\n" );
2148 fprintf( outfile, "\tpopl %%edx\n" );
2149 fprintf( outfile, "\tpopl %%ecx\n" );
2150 fprintf( outfile, "\tpopl %%ebx\n" );
2152 /* Return to caller */
2154 fprintf( outfile, "\tlret\n" );
2156 /* Declare the return address variables */
2158 fprintf( outfile, "\t.data\n" );
2159 fprintf( outfile, "\t.globl " PREFIX "CALLTO16_RetAddr_word\n" );
2160 fprintf( outfile, "\t.globl " PREFIX "CALLTO16_RetAddr_long\n" );
2161 fprintf( outfile, "\t.globl " PREFIX "CALLTO16_Saved32_esp\n" );
2162 fprintf( outfile, PREFIX "CALLTO16_RetAddr_word:\t.long 0\n" );
2163 fprintf( outfile, PREFIX "CALLTO16_RetAddr_long:\t.long 0\n" );
2164 fprintf( outfile, PREFIX "CALLTO16_Saved32_esp:\t.long 0\n" );
2165 fprintf( outfile, "\t.text\n" );
2169 /*******************************************************************
2172 * Build the CONTEXT structure on the stack.
2174 static void BuildContext32( FILE *outfile )
2176 /* Build the context structure */
2178 fprintf( outfile, "\tpushw $0\n" );
2179 fprintf( outfile, "\tpushw %%ss\n" );
2180 fprintf( outfile, "\tpushl %%eax\n" ); /* %esp */
2181 fprintf( outfile, "\tpushfl\n" );
2182 fprintf( outfile, "\tpushw $0\n" );
2183 fprintf( outfile, "\tpushw %%cs\n" );
2184 fprintf( outfile, "\tsubl $8,%%esp\n" ); /* %eip + %ebp */
2186 fprintf( outfile, "\tpushl %%eax\n" );
2187 fprintf( outfile, "\tpushl %%ecx\n" );
2188 fprintf( outfile, "\tpushl %%edx\n" );
2189 fprintf( outfile, "\tpushl %%ebx\n" );
2190 fprintf( outfile, "\tpushl %%esi\n" );
2191 fprintf( outfile, "\tpushl %%edi\n" );
2193 fprintf( outfile, "\txorl %%eax,%%eax\n" );
2194 fprintf( outfile, "\tmovw %%ds,%%ax\n" );
2195 fprintf( outfile, "\tpushl %%eax\n" );
2196 fprintf( outfile, "\tmovw %%es,%%ax\n" );
2197 fprintf( outfile, "\tpushl %%eax\n" );
2198 fprintf( outfile, "\tmovw %%fs,%%ax\n" );
2199 fprintf( outfile, "\tpushl %%eax\n" );
2200 fprintf( outfile, "\tmovw %%gs,%%ax\n" );
2201 fprintf( outfile, "\tpushl %%eax\n" );
2203 fprintf( outfile, "\tsubl $%d,%%esp\n",
2204 sizeof(FLOATING_SAVE_AREA) + 6 * sizeof(DWORD) /* DR regs */ );
2205 fprintf( outfile, "\tpushl $0x0001001f\n" ); /* ContextFlags */
2207 fprintf( outfile, "\tfsave %d(%%esp)\n", CONTEXTOFFSET(FloatSave) );
2209 fprintf( outfile, "\tmovl 4(%%ebp),%%eax\n" ); /* %eip at time of call */
2210 fprintf( outfile, "\tmovl %%eax,%d(%%esp)\n", CONTEXTOFFSET(Eip) );
2211 fprintf( outfile, "\tmovl 0(%%ebp),%%eax\n" ); /* %ebp at time of call */
2212 fprintf( outfile, "\tmovl %%eax,%d(%%esp)\n", CONTEXTOFFSET(Ebp) );
2213 fprintf( outfile, "\tleal 8(%%ebp),%%eax\n" ); /* %esp at time of call */
2214 fprintf( outfile, "\tmovl %%eax,%d(%%esp)\n", CONTEXTOFFSET(Esp) );
2216 /* Push pointer to context */
2218 fprintf( outfile, "\tpushl %%esp\n" );
2222 /*******************************************************************
2225 * Restore the registers from the context structure.
2226 * All registers except %cs and %ss are restored.
2228 static void RestoreContext32( FILE *outfile )
2230 /* Restore the context structure */
2232 fprintf( outfile, "\tleal %d(%%ebp),%%esp\n", -sizeof(CONTEXT)-8 );
2233 fprintf( outfile, "\tfrstor %d(%%esp)\n", CONTEXTOFFSET(FloatSave) );
2235 /* Store flags over the relay addr */
2236 fprintf( outfile, "\tmovl %d(%%esp),%%eax\n", CONTEXTOFFSET(EFlags) );
2237 fprintf( outfile, "\tmovl %%eax,%d(%%esp)\n", sizeof(CONTEXT) );
2239 /* Get the new stack addr */
2240 fprintf( outfile, "\tmovl %d(%%esp),%%ebx\n", CONTEXTOFFSET(Esp) );
2242 /* Set eip and ebp value onto the new stack */
2243 fprintf( outfile, "\tmovl %d(%%esp),%%eax\n", CONTEXTOFFSET(Eip) );
2244 fprintf( outfile, "\tmovl %%eax,-4(%%ebx)\n" ); /* %eip at time of call */
2245 fprintf( outfile, "\tmovl %d(%%esp),%%eax\n", CONTEXTOFFSET(Ebp) );
2246 fprintf( outfile, "\tmovl %%eax,-8(%%ebx)\n" ); /* %ebp at time of call */
2248 /* Set ebp to point to the new stack */
2249 fprintf( outfile, "\tleal -8(%%ebx),%%ebp\n" );
2251 /* Restore all registers */
2252 fprintf( outfile, "\taddl $%d,%%esp\n",
2253 sizeof(FLOATING_SAVE_AREA) + 7 * sizeof(DWORD) );
2254 fprintf( outfile, "\tpopl %%eax\n" );
2255 fprintf( outfile, "\tmovw %%ax,%%gs\n" );
2256 fprintf( outfile, "\tpopl %%eax\n" );
2257 fprintf( outfile, "\tmovw %%ax,%%fs\n" );
2258 fprintf( outfile, "\tpopl %%eax\n" );
2259 fprintf( outfile, "\tmovw %%ax,%%es\n" );
2260 fprintf( outfile, "\tpopl %%eax\n" );
2261 fprintf( outfile, "\tmovw %%ax,%%ds\n" );
2263 fprintf( outfile, "\tpopl %%edi\n" );
2264 fprintf( outfile, "\tpopl %%esi\n" );
2265 fprintf( outfile, "\tpopl %%ebx\n" );
2266 fprintf( outfile, "\tpopl %%edx\n" );
2267 fprintf( outfile, "\tpopl %%ecx\n" );
2268 fprintf( outfile, "\tpopl %%eax\n" );
2270 fprintf( outfile, "\taddl $%d,%%esp\n",
2271 6 * sizeof(DWORD) /* %ebp + %eip + %cs + %efl + %esp + %ss */ );
2272 fprintf( outfile, "\tpopfl\n" );
2276 /*******************************************************************
2277 * BuildCallFrom32Func
2279 * Build a 32-bit-to-Wine call-back function.
2280 * 'args' is the number of dword arguments.
2288 * (ebp-4) entry point
2289 * (ebp-8) relay addr
2291 static void BuildCallFrom32Func( FILE *outfile, const char *profile )
2293 int args, stdcall, reg_func;
2295 if (!strncmp( profile, "stdcall", 7 ))
2299 args = atoi( profile + 8 );
2301 else if (!strncmp( profile, "cdecl", 5 ))
2303 stdcall = reg_func = 0;
2304 args = atoi( profile + 6 );
2306 else if (!strncmp( profile, "regs", 4 ))
2308 stdcall = reg_func = 1;
2309 args = atoi( profile + 5 );
2313 fprintf( stderr, "Invalid function profile '%s', ignored\n", profile );
2317 /* Function header */
2319 fprintf( outfile, "\n\t.align 4\n" );
2321 fprintf( outfile, ".stabs \"CallFrom32_%s:F1\",36,0,0," PREFIX "CallFrom32_%s\n",
2324 fprintf( outfile, "\t.globl " PREFIX "CallFrom32_%s\n", profile );
2325 fprintf( outfile, PREFIX "CallFrom32_%s:\n", profile );
2329 fprintf( outfile, "\tleal 8(%%esp),%%ebp\n" );
2331 /* Transfer the arguments */
2333 if (reg_func) BuildContext32( outfile );
2338 for (i = args; i > 0; i--)
2339 fprintf( outfile, "\tpushl %d(%%ebp)\n", 4 * i + 4 );
2345 fprintf( outfile, "\tmovw %%ds,%%ax\n" );
2346 fprintf( outfile, "\tmovw %%ax,%%es\n" );
2349 /* Print the debugging info */
2353 fprintf( outfile, "\tpushl $%d\n", /* Nb args */
2354 reg_func ? args | 0x80000000 : args);
2355 fprintf( outfile, "\tpushl %%ebp\n" );
2356 fprintf( outfile, "\tcall " PREFIX "RELAY_DebugCallFrom32\n" );
2357 fprintf( outfile, "\tadd $8, %%esp\n" );
2360 /* Call the function */
2362 fprintf( outfile, "\tcall -4(%%ebp)\n" );
2364 /* Print the debugging info */
2368 fprintf( outfile, "\tpushl %%eax\n" );
2369 fprintf( outfile, "\tpushl $%d\n", /* Nb args */
2370 reg_func ? args | 0x80000000 : args);
2371 fprintf( outfile, "\tpushl %%ebp\n" );
2372 fprintf( outfile, "\tcall " PREFIX "RELAY_DebugCallFrom32Ret\n" );
2373 fprintf( outfile, "\tpopl %%eax\n" );
2374 fprintf( outfile, "\tpopl %%eax\n" );
2375 fprintf( outfile, "\tpopl %%eax\n" );
2378 if (reg_func) RestoreContext32( outfile );
2380 fprintf( outfile, "\tmovl %%ebp,%%esp\n" );
2381 fprintf( outfile, "\tpopl %%ebp\n" );
2383 /* Return, removing arguments */
2385 if (args && stdcall) fprintf( outfile, "\tret $%d\n", args * 4 );
2386 else fprintf( outfile, "\tret\n" );
2390 /*******************************************************************
2393 * Build the spec files
2395 static int BuildSpec( FILE *outfile, int argc, char *argv[] )
2398 for (i = 2; i < argc; i++)
2399 if (BuildSpecFile( outfile, argv[i] ) < 0) return -1;
2404 /*******************************************************************
2407 * Build the 16-bit-to-Wine callbacks
2409 static int BuildCallFrom16( FILE *outfile, char * outname, int argc, char *argv[] )
2416 fprintf( outfile, "/* File generated automatically. Do not edit! */\n\n" );
2417 fprintf( outfile, "\t.text\n" );
2420 fprintf( outfile, "\t.file\t\"%s\"\n", outname );
2421 getcwd(buffer, sizeof(buffer));
2424 * The stabs help the internal debugger as they are an indication that it
2425 * is sensible to step into a thunk/trampoline.
2427 fprintf( outfile, ".stabs \"%s/\",100,0,0,Code_Start\n", buffer);
2428 fprintf( outfile, ".stabs \"%s\",100,0,0,Code_Start\n", outname);
2429 fprintf( outfile, "\t.text\n" );
2430 fprintf( outfile, "\t.align 4\n" );
2431 fprintf( outfile, "Code_Start:\n\n" );
2434 /* Build the callback functions */
2436 for (i = 2; i < argc; i++) BuildCallFrom16Func( outfile, argv[i] );
2438 /* Output the argument debugging strings */
2442 fprintf( outfile, "/* Argument strings */\n" );
2443 for (i = 2; i < argc; i++)
2445 fprintf( outfile, "Profile_%s:\n", argv[i] );
2446 fprintf( outfile, "\t.ascii \"%s\\0\"\n", argv[i] + 5 );
2451 fprintf( outfile, "\t.text\n");
2452 fprintf( outfile, "\t.stabs \"\",100,0,0,.Letext\n");
2453 fprintf( outfile, ".Letext:\n");
2460 /*******************************************************************
2463 * Build the Wine-to-16-bit callbacks
2465 static int BuildCallTo16( FILE *outfile, char * outname, int argc, char *argv[] )
2472 fprintf( outfile, "/* File generated automatically. Do not edit! */\n\n" );
2473 fprintf( outfile, "\t.text\n" );
2476 fprintf( outfile, "\t.file\t\"%s\"\n", outname );
2477 getcwd(buffer, sizeof(buffer));
2480 * The stabs help the internal debugger as they are an indication that it
2481 * is sensible to step into a thunk/trampoline.
2483 fprintf( outfile, ".stabs \"%s/\",100,0,0,Code_Start\n", buffer);
2484 fprintf( outfile, ".stabs \"%s\",100,0,0,Code_Start\n", outname);
2485 fprintf( outfile, "\t.text\n" );
2486 fprintf( outfile, "\t.align 4\n" );
2487 fprintf( outfile, "Code_Start:\n\n" );
2490 fprintf( outfile, "\t.globl " PREFIX "CALLTO16_Start\n" );
2491 fprintf( outfile, PREFIX "CALLTO16_Start:\n" );
2493 /* Build the callback functions */
2495 for (i = 2; i < argc; i++) BuildCallTo16Func( outfile, argv[i] );
2497 /* Output the 16-bit return code */
2499 BuildRet16Func( outfile );
2501 fprintf( outfile, "\t.globl " PREFIX "CALLTO16_End\n" );
2502 fprintf( outfile, PREFIX "CALLTO16_End:\n" );
2505 fprintf( outfile, "\t.text\n");
2506 fprintf( outfile, "\t.stabs \"\",100,0,0,.Letext\n");
2507 fprintf( outfile, ".Letext:\n");
2514 /*******************************************************************
2517 * Build the 32-bit-to-Wine callbacks
2519 static int BuildCallFrom32( FILE *outfile, char * outname, int argc, char *argv[] )
2526 fprintf( outfile, "/* File generated automatically. Do not edit! */\n\n" );
2527 fprintf( outfile, "\t.text\n" );
2530 fprintf( outfile, "\t.file\t\"%s\"\n", outname );
2531 getcwd(buffer, sizeof(buffer));
2534 * The stabs help the internal debugger as they are an indication that it
2535 * is sensible to step into a thunk/trampoline.
2537 fprintf( outfile, ".stabs \"%s/\",100,0,0,Code_Start\n", buffer);
2538 fprintf( outfile, ".stabs \"%s\",100,0,0,Code_Start\n", outname);
2539 fprintf( outfile, "\t.text\n" );
2540 fprintf( outfile, "\t.align 4\n" );
2541 fprintf( outfile, "Code_Start:\n\n" );
2544 /* Build the callback functions */
2546 for (i = 2; i < argc; i++) BuildCallFrom32Func( outfile, argv[i] );
2548 /* Build the 32-bit large stack callback */
2550 BuildCall32LargeStack( outfile );
2553 fprintf( outfile, "\t.text\n");
2554 fprintf( outfile, "\t.stabs \"\",100,0,0,.Letext\n");
2555 fprintf( outfile, ".Letext:\n");
2562 /*******************************************************************
2565 static void usage(void)
2568 "usage: build [-o outfile] -spec SPECNAMES\n"
2569 " build [-o outfile] -callfrom16 FUNCTION_PROFILES\n"
2570 " build [-o outfile] -callto16 FUNCTION_PROFILES\n"
2571 " build [-o outfile] -callfrom32 FUNCTION_PROFILES\n" );
2576 /*******************************************************************
2579 int main(int argc, char **argv)
2581 char *outname = NULL;
2582 FILE *outfile = stdout;
2585 if (argc <= 2) usage();
2587 if (!strcmp( argv[1], "-o" ))
2592 if (argc <= 2) usage();
2593 if (!(outfile = fopen( outname, "w" )))
2595 fprintf( stderr, "Unable to create output file '%s'\n", outname );
2600 if (!strcmp( argv[1], "-spec" ))
2601 res = BuildSpec( outfile, argc, argv );
2602 else if (!strcmp( argv[1], "-callfrom16" ))
2603 res = BuildCallFrom16( outfile, outname, argc, argv );
2604 else if (!strcmp( argv[1], "-callto16" ))
2605 res = BuildCallTo16( outfile, outname, argc, argv );
2606 else if (!strcmp( argv[1], "-callfrom32" ))
2607 res = BuildCallFrom32( outfile, outname, argc, argv );