Release 961208
[wine/multimedia.git] / tools / build.c
blob2381002eeed275d473c958ed2eab9b520acf13a4
1 /*
2 * Copyright 1993 Robert J. Amstadt
3 * Copyright 1995 Martin von Loewis
4 * Copyright 1995, 1996 Alexandre Julliard
5 */
7 #ifndef WINELIB
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <ctype.h>
13 #include <unistd.h>
14 #include "wintypes.h"
15 #include "registers.h"
16 #include "winerror.h" /* for ERROR_CALL_NOT_IMPLEMENTED */
17 #include "module.h"
18 #include "neexe.h"
19 #include "windows.h"
21 #ifdef NEED_UNDERSCORE_PREFIX
22 # define PREFIX "_"
23 #else
24 # define PREFIX
25 #endif
27 typedef enum
29 TYPE_INVALID,
30 TYPE_BYTE, /* byte variable */
31 TYPE_WORD, /* word variable */
32 TYPE_LONG, /* long variable */
33 TYPE_PASCAL_16, /* pascal function with 16-bit return (Win16) */
34 TYPE_PASCAL, /* pascal function with 32-bit return (Win16) */
35 TYPE_REGISTER, /* register function */
36 TYPE_ABS, /* absolute value */
37 TYPE_RETURN, /* simple return value function */
38 TYPE_STUB, /* unimplemented stub */
39 TYPE_STDCALL, /* stdcall function (Win32) */
40 TYPE_CDECL, /* cdecl function (Win32) */
41 TYPE_EXTERN, /* external symbol (Win32) */
42 TYPE_NBTYPES
43 } ORD_TYPE;
45 static const char * const TypeNames[TYPE_NBTYPES] =
47 NULL,
48 "byte", /* TYPE_BYTE */
49 "word", /* TYPE_WORD */
50 "long", /* TYPE_LONG */
51 "pascal16", /* TYPE_PASCAL_16 */
52 "pascal", /* TYPE_PASCAL */
53 "register", /* TYPE_REGISTER */
54 "equate", /* TYPE_ABS */
55 "return", /* TYPE_RETURN */
56 "stub", /* TYPE_STUB */
57 "stdcall", /* TYPE_STDCALL */
58 "cdecl", /* TYPE_CDECL */
59 "extern" /* TYPE_EXTERN */
62 #define MAX_ORDINALS 1299
64 /* Callback function used for stub functions */
65 #define STUB_CALLBACK \
66 ((SpecType == SPEC_WIN16) ? "RELAY_Unimplemented16": "RELAY_Unimplemented32")
68 typedef enum
70 SPEC_INVALID,
71 SPEC_WIN16,
72 SPEC_WIN32
73 } SPEC_TYPE;
75 typedef struct
77 int n_values;
78 int *values;
79 } ORD_VARIABLE;
81 typedef struct
83 int n_args;
84 char arg_types[32];
85 char link_name[80];
86 } ORD_FUNCTION;
88 typedef struct
90 int arg_size;
91 int ret_value;
92 } ORD_RETURN;
94 typedef struct
96 int value;
97 } ORD_ABS;
99 typedef struct
101 char link_name[80];
102 } ORD_EXTERN;
104 typedef struct
106 ORD_TYPE type;
107 int offset;
108 char name[80];
109 union
111 ORD_VARIABLE var;
112 ORD_FUNCTION func;
113 ORD_RETURN ret;
114 ORD_ABS abs;
115 ORD_EXTERN ext;
116 } u;
117 } ORDDEF;
119 static ORDDEF OrdinalDefinitions[MAX_ORDINALS];
121 static SPEC_TYPE SpecType = SPEC_INVALID;
122 char DLLName[80];
123 int Limit = 0;
124 int Base = 0;
125 int DLLHeapSize = 0;
126 FILE *SpecFp;
128 char *ParseBuffer = NULL;
129 char *ParseNext;
130 char ParseSaveChar;
131 int Line;
133 static int debugging = 1;
135 /* Offset of register relative to the end of the SIGCONTEXT struct */
136 #define SIGCONTEXTOFFSET(reg) \
137 ((int)&reg##_reg((SIGCONTEXT *)0) - sizeof(SIGCONTEXT))
139 /* Offset of register relative to the start of the CONTEXT struct */
140 #define CONTEXTOFFSET(reg) ((int)&((CONTEXT *)0)->reg)
142 static void *xmalloc (size_t size)
144 void *res;
146 res = malloc (size ? size : 1);
147 if (res == NULL)
149 fprintf (stderr, "Virtual memory exhausted.\n");
150 exit (1);
152 return res;
156 static void *xrealloc (void *ptr, size_t size)
158 void *res = realloc (ptr, size);
159 if (res == NULL)
161 fprintf (stderr, "Virtual memory exhausted.\n");
162 exit (1);
164 return res;
168 static int IsNumberString(char *s)
170 while (*s != '\0')
171 if (!isdigit(*s++))
172 return 0;
174 return 1;
177 static char *strupper(char *s)
179 char *p;
181 for(p = s; *p != '\0'; p++)
182 *p = toupper(*p);
184 return s;
187 static char * GetTokenInLine(void)
189 char *p;
190 char *token;
192 if (ParseNext != ParseBuffer)
194 if (ParseSaveChar == '\0')
195 return NULL;
196 *ParseNext = ParseSaveChar;
200 * Remove initial white space.
202 for (p = ParseNext; isspace(*p); p++)
205 if ((*p == '\0') || (*p == '#'))
206 return NULL;
209 * Find end of token.
211 token = p++;
212 if (*token != '(' && *token != ')')
213 while (*p != '\0' && *p != '(' && *p != ')' && !isspace(*p))
214 p++;
216 ParseSaveChar = *p;
217 ParseNext = p;
218 *p = '\0';
220 return token;
223 static char * GetToken(void)
225 char *token;
227 if (ParseBuffer == NULL)
229 ParseBuffer = xmalloc(512);
230 ParseNext = ParseBuffer;
231 Line++;
232 while (1)
234 if (fgets(ParseBuffer, 511, SpecFp) == NULL)
235 return NULL;
236 if (ParseBuffer[0] != '#')
237 break;
241 while ((token = GetTokenInLine()) == NULL)
243 ParseNext = ParseBuffer;
244 Line++;
245 while (1)
247 if (fgets(ParseBuffer, 511, SpecFp) == NULL)
248 return NULL;
249 if (ParseBuffer[0] != '#')
250 break;
254 return token;
258 /*******************************************************************
259 * ParseVariable
261 * Parse a variable definition.
263 static int ParseVariable( ORDDEF *odp )
265 char *endptr;
266 int *value_array;
267 int n_values;
268 int value_array_size;
270 char *token = GetToken();
271 if (*token != '(')
273 fprintf(stderr, "%d: Expected '(' got '%s'\n", Line, token);
274 return -1;
277 n_values = 0;
278 value_array_size = 25;
279 value_array = xmalloc(sizeof(*value_array) * value_array_size);
281 while ((token = GetToken()) != NULL)
283 if (*token == ')')
284 break;
286 value_array[n_values++] = strtol(token, &endptr, 0);
287 if (n_values == value_array_size)
289 value_array_size += 25;
290 value_array = xrealloc(value_array,
291 sizeof(*value_array) * value_array_size);
294 if (endptr == NULL || *endptr != '\0')
296 fprintf(stderr, "%d: Expected number value, got '%s'\n", Line,
297 token);
298 return -1;
302 if (token == NULL)
304 fprintf(stderr, "%d: End of file in variable declaration\n", Line);
305 return -1;
308 odp->u.var.n_values = n_values;
309 odp->u.var.values = xrealloc(value_array, sizeof(*value_array) * n_values);
311 return 0;
315 /*******************************************************************
316 * ParseExportFunction
318 * Parse a function definition.
320 static int ParseExportFunction( ORDDEF *odp )
322 char *token;
323 int i;
325 switch(SpecType)
327 case SPEC_WIN16:
328 if (odp->type == TYPE_STDCALL)
330 fprintf( stderr, "%d: 'stdcall' not supported for Win16\n", Line );
331 return -1;
333 if (odp->type == TYPE_CDECL)
335 fprintf( stderr, "%d: 'cdecl' not supported for Win16\n", Line );
336 return -1;
338 break;
339 case SPEC_WIN32:
340 if ((odp->type == TYPE_PASCAL) || (odp->type == TYPE_PASCAL_16))
342 fprintf( stderr, "%d: 'pascal' not supported for Win32\n", Line );
343 return -1;
345 break;
346 default:
347 break;
350 token = GetToken();
351 if (*token != '(')
353 fprintf(stderr, "%d: Expected '(' got '%s'\n", Line, token);
354 return -1;
357 for (i = 0; i < sizeof(odp->u.func.arg_types)-1; i++)
359 token = GetToken();
360 if (*token == ')')
361 break;
363 if (!strcmp(token, "byte") || !strcmp(token, "word"))
364 odp->u.func.arg_types[i] = 'w';
365 else if (!strcmp(token, "s_byte") || !strcmp(token, "s_word"))
366 odp->u.func.arg_types[i] = 's';
367 else if (!strcmp(token, "long") || !strcmp(token, "segptr"))
368 odp->u.func.arg_types[i] = 'l';
369 else if (!strcmp(token, "ptr"))
370 odp->u.func.arg_types[i] = 'p';
371 else
373 fprintf(stderr, "%d: Unknown variable type '%s'\n", Line, token);
374 return -1;
376 if (SpecType == SPEC_WIN32)
378 if (strcmp(token, "long") && strcmp(token, "ptr"))
380 fprintf( stderr, "%d: Type '%s' not supported for Win32\n",
381 Line, token );
382 return -1;
386 if (*token != ')')
388 fprintf( stderr, "%d: Too many arguments\n", Line );
389 return -1;
391 odp->u.func.arg_types[i] = '\0';
392 if ((odp->type == TYPE_STDCALL) && !i)
393 odp->type = TYPE_CDECL; /* stdcall is the same as cdecl for 0 args */
394 strcpy(odp->u.func.link_name, GetToken());
395 return 0;
399 /*******************************************************************
400 * ParseEquate
402 * Parse an 'equate' definition.
404 static int ParseEquate( ORDDEF *odp )
406 char *endptr;
408 char *token = GetToken();
409 int value = strtol(token, &endptr, 0);
410 if (endptr == NULL || *endptr != '\0')
412 fprintf(stderr, "%d: Expected number value, got '%s'\n", Line,
413 token);
414 return -1;
417 odp->u.abs.value = value;
418 return 0;
422 /*******************************************************************
423 * ParseReturn
425 * Parse a 'return' definition.
427 static int ParseReturn( ORDDEF *odp )
429 char *token;
430 char *endptr;
432 token = GetToken();
433 odp->u.ret.arg_size = strtol(token, &endptr, 0);
434 if (endptr == NULL || *endptr != '\0')
436 fprintf(stderr, "%d: Expected number value, got '%s'\n", Line,
437 token);
438 return -1;
441 token = GetToken();
442 odp->u.ret.ret_value = strtol(token, &endptr, 0);
443 if (endptr == NULL || *endptr != '\0')
445 fprintf(stderr, "%d: Expected number value, got '%s'\n", Line,
446 token);
447 return -1;
450 return 0;
454 /*******************************************************************
455 * ParseStub
457 * Parse a 'stub' definition.
459 static int ParseStub( ORDDEF *odp )
461 odp->u.func.arg_types[0] = '\0';
462 strcpy( odp->u.func.link_name, STUB_CALLBACK );
463 return 0;
467 /*******************************************************************
468 * ParseExtern
470 * Parse an 'extern' definition.
472 static int ParseExtern( ORDDEF *odp )
474 if (SpecType == SPEC_WIN16)
476 fprintf( stderr, "%d: 'extern' not supported for Win16\n", Line );
477 return -1;
479 strcpy( odp->u.ext.link_name, GetToken() );
480 return 0;
484 /*******************************************************************
485 * ParseOrdinal
487 * Parse an ordinal definition.
489 static int ParseOrdinal(int ordinal)
491 ORDDEF *odp;
492 char *token;
494 if (ordinal >= MAX_ORDINALS)
496 fprintf(stderr, "%d: Ordinal number too large\n", Line);
497 return -1;
499 if (ordinal > Limit) Limit = ordinal;
501 odp = &OrdinalDefinitions[ordinal];
502 if (!(token = GetToken()))
504 fprintf(stderr, "%d: Expected type after ordinal\n", Line);
505 return -1;
508 for (odp->type = 0; odp->type < TYPE_NBTYPES; odp->type++)
509 if (TypeNames[odp->type] && !strcmp( token, TypeNames[odp->type] ))
510 break;
512 if (odp->type >= TYPE_NBTYPES)
514 fprintf( stderr,
515 "%d: Expected type after ordinal, found '%s' instead\n",
516 Line, token );
517 return -1;
520 if (!(token = GetToken()))
522 fprintf( stderr, "%d: Expected name after type\n", Line );
523 return -1;
525 strcpy( odp->name, token );
527 switch(odp->type)
529 case TYPE_BYTE:
530 case TYPE_WORD:
531 case TYPE_LONG:
532 return ParseVariable( odp );
533 case TYPE_PASCAL_16:
534 case TYPE_PASCAL:
535 case TYPE_REGISTER:
536 case TYPE_STDCALL:
537 case TYPE_CDECL:
538 return ParseExportFunction( odp );
539 case TYPE_ABS:
540 return ParseEquate( odp );
541 case TYPE_RETURN:
542 return ParseReturn( odp );
543 case TYPE_STUB:
544 return ParseStub( odp );
545 case TYPE_EXTERN:
546 return ParseExtern( odp );
547 default:
548 fprintf( stderr, "Should not happen\n" );
549 return -1;
554 /*******************************************************************
555 * ParseTopLevel
557 * Parse a spec file.
559 static int ParseTopLevel(void)
561 char *token;
563 while ((token = GetToken()) != NULL)
565 if (strcmp(token, "name") == 0)
567 strcpy(DLLName, GetToken());
568 strupper(DLLName);
570 else if (strcmp(token, "type") == 0)
572 token = GetToken();
573 if (!strcmp(token, "win16" )) SpecType = SPEC_WIN16;
574 else if (!strcmp(token, "win32" )) SpecType = SPEC_WIN32;
575 else
577 fprintf(stderr, "%d: Type must be 'win16' or 'win32'\n", Line);
578 return -1;
581 else if (strcmp(token, "base") == 0)
583 token = GetToken();
584 if (!IsNumberString(token))
586 fprintf(stderr, "%d: Expected number after base\n", Line);
587 return -1;
589 Base = atoi(token);
591 else if (strcmp(token, "heap") == 0)
593 token = GetToken();
594 if (!IsNumberString(token))
596 fprintf(stderr, "%d: Expected number after heap\n", Line);
597 return -1;
599 DLLHeapSize = atoi(token);
601 else if (IsNumberString(token))
603 int ordinal;
604 int rv;
606 ordinal = atoi(token);
607 if ((rv = ParseOrdinal(ordinal)) < 0)
608 return rv;
610 else
612 fprintf(stderr,
613 "%d: Expected name, id, length or ordinal\n", Line);
614 return -1;
618 return 0;
622 /*******************************************************************
623 * StoreVariableCode
625 * Store a list of ints into a byte array.
627 static int StoreVariableCode( unsigned char *buffer, int size, ORDDEF *odp )
629 int i;
631 switch(size)
633 case 1:
634 for (i = 0; i < odp->u.var.n_values; i++)
635 buffer[i] = odp->u.var.values[i];
636 break;
637 case 2:
638 for (i = 0; i < odp->u.var.n_values; i++)
639 ((unsigned short *)buffer)[i] = odp->u.var.values[i];
640 break;
641 case 4:
642 for (i = 0; i < odp->u.var.n_values; i++)
643 ((unsigned int *)buffer)[i] = odp->u.var.values[i];
644 break;
646 return odp->u.var.n_values * size;
650 /*******************************************************************
651 * DumpBytes
653 * Dump a byte stream into the assembly code.
655 static void DumpBytes( FILE *outfile, const unsigned char *data, int len,
656 const char *section, const char *label_start )
658 int i;
659 if (section) fprintf( outfile, "\t%s\n", section );
660 if (label_start) fprintf( outfile, "%s:\n", label_start );
661 for (i = 0; i < len; i++)
663 if (!(i & 0x0f)) fprintf( outfile, "\t.byte " );
664 fprintf( outfile, "%d", *data++ );
665 if (i < len - 1)
666 fprintf( outfile, "%c", ((i & 0x0f) != 0x0f) ? ',' : '\n' );
668 fprintf( outfile, "\n" );
672 /*******************************************************************
673 * BuildModule16
675 * Build the in-memory representation of a 16-bit NE module, and dump it
676 * as a byte stream into the assembly code.
678 static int BuildModule16( FILE *outfile, int max_code_offset,
679 int max_data_offset )
681 ORDDEF *odp;
682 int i;
683 char *buffer;
684 NE_MODULE *pModule;
685 SEGTABLEENTRY *pSegment;
686 OFSTRUCT *pFileInfo;
687 BYTE *pstr, *bundle;
688 WORD *pword;
690 /* Module layout:
691 * NE_MODULE Module
692 * OFSTRUCT File information
693 * SEGTABLEENTRY Segment 1 (code)
694 * SEGTABLEENTRY Segment 2 (data)
695 * WORD[2] Resource table (empty)
696 * BYTE[2] Imported names (empty)
697 * BYTE[n] Resident names table
698 * BYTE[n] Entry table
701 buffer = xmalloc( 0x10000 );
703 pModule = (NE_MODULE *)buffer;
704 pModule->magic = NE_SIGNATURE;
705 pModule->count = 1;
706 pModule->next = 0;
707 pModule->flags = NE_FFLAGS_SINGLEDATA | NE_FFLAGS_BUILTIN | NE_FFLAGS_LIBMODULE;
708 pModule->dgroup = 2;
709 pModule->heap_size = DLLHeapSize;
710 pModule->stack_size = 0;
711 pModule->ip = 0;
712 pModule->cs = 0;
713 pModule->sp = 0;
714 pModule->ss = 0;
715 pModule->seg_count = 2;
716 pModule->modref_count = 0;
717 pModule->nrname_size = 0;
718 pModule->modref_table = 0;
719 pModule->nrname_fpos = 0;
720 pModule->moveable_entries = 0;
721 pModule->alignment = 0;
722 pModule->truetype = 0;
723 pModule->os_flags = NE_OSFLAGS_WINDOWS;
724 pModule->misc_flags = 0;
725 pModule->dlls_to_init = 0;
726 pModule->nrname_handle = 0;
727 pModule->min_swap_area = 0;
728 pModule->expected_version = 0x030a;
729 pModule->pe_module = NULL;
730 pModule->self = 0;
731 pModule->self_loading_sel = 0;
733 /* File information */
735 pFileInfo = (OFSTRUCT *)(pModule + 1);
736 pModule->fileinfo = (int)pFileInfo - (int)pModule;
737 memset( pFileInfo, 0, sizeof(*pFileInfo) - sizeof(pFileInfo->szPathName) );
738 pFileInfo->cBytes = sizeof(*pFileInfo) - sizeof(pFileInfo->szPathName)
739 + strlen(DLLName) + 4;
740 sprintf( pFileInfo->szPathName, "%s.DLL", DLLName );
741 pstr = (char *)pFileInfo + pFileInfo->cBytes + 1;
743 /* Segment table */
745 pSegment = (SEGTABLEENTRY *)pstr;
746 pModule->seg_table = (int)pSegment - (int)pModule;
747 pSegment->filepos = 0;
748 pSegment->size = max_code_offset;
749 pSegment->flags = 0;
750 pSegment->minsize = max_code_offset;
751 pSegment->selector = 0;
752 pSegment++;
754 pModule->dgroup_entry = (int)pSegment - (int)pModule;
755 pSegment->filepos = 0;
756 pSegment->size = max_data_offset;
757 pSegment->flags = NE_SEGFLAGS_DATA;
758 pSegment->minsize = max_data_offset;
759 pSegment->selector = 0;
760 pSegment++;
762 /* Resource table */
764 pword = (WORD *)pSegment;
765 pModule->res_table = (int)pword - (int)pModule;
766 *pword++ = 0;
767 *pword++ = 0;
769 /* Imported names table */
771 pstr = (char *)pword;
772 pModule->import_table = (int)pstr - (int)pModule;
773 *pstr++ = 0;
774 *pstr++ = 0;
776 /* Resident names table */
778 pModule->name_table = (int)pstr - (int)pModule;
779 /* First entry is module name */
780 *pstr = strlen(DLLName );
781 strcpy( pstr + 1, DLLName );
782 pstr += *pstr + 1;
783 *(WORD *)pstr = 0;
784 pstr += sizeof(WORD);
785 /* Store all ordinals */
786 odp = OrdinalDefinitions + 1;
787 for (i = 1; i <= Limit; i++, odp++)
789 if (!odp->name[0]) continue;
790 *pstr = strlen( odp->name );
791 strcpy( pstr + 1, odp->name );
792 strupper( pstr + 1 );
793 pstr += *pstr + 1;
794 *(WORD *)pstr = i;
795 pstr += sizeof(WORD);
797 *pstr++ = 0;
799 /* Entry table */
801 pModule->entry_table = (int)pstr - (int)pModule;
802 bundle = NULL;
803 odp = OrdinalDefinitions + 1;
804 for (i = 1; i <= Limit; i++, odp++)
806 int selector = 0;
808 switch (odp->type)
810 case TYPE_PASCAL:
811 case TYPE_PASCAL_16:
812 case TYPE_REGISTER:
813 case TYPE_RETURN:
814 case TYPE_STUB:
815 selector = 1; /* Code selector */
816 break;
818 case TYPE_BYTE:
819 case TYPE_WORD:
820 case TYPE_LONG:
821 selector = 2; /* Data selector */
822 break;
824 case TYPE_ABS:
825 selector = 0xfe; /* Constant selector */
826 break;
828 default:
829 selector = 0; /* Invalid selector */
830 break;
833 /* create a new bundle if necessary */
834 if (!bundle || (bundle[0] >= 254) || (bundle[1] != selector))
836 bundle = pstr;
837 bundle[0] = 0;
838 bundle[1] = selector;
839 pstr += 2;
842 (*bundle)++;
843 if (selector != 0)
845 *pstr++ = 1;
846 *(WORD *)pstr = odp->offset;
847 pstr += sizeof(WORD);
850 *pstr++ = 0;
852 /* Dump the module content */
854 DumpBytes( outfile, (char *)pModule, (int)pstr - (int)pModule,
855 ".data", "Module_Start" );
856 return (int)pstr - (int)pModule;
860 /*******************************************************************
861 * BuildModule32
863 * Build the in-memory representation of a 32-bit pseudo-NE module, and dump it
864 * as a byte stream into the assembly code.
866 static int BuildModule32( FILE *outfile )
868 char *buffer;
869 NE_MODULE *pModule;
870 OFSTRUCT *pFileInfo;
871 BYTE *pstr;
872 WORD *pword;
874 /* Module layout:
875 * NE_MODULE Module
876 * OFSTRUCT File information
877 * SEGTABLEENTRY Segment table (empty)
878 * WORD[2] Resource table (empty)
879 * BYTE[2] Imported names (empty)
880 * BYTE[n] Resident names table (1 entry)
881 * BYTE[n] Entry table (empty)
884 buffer = xmalloc( 0x10000 );
886 pModule = (NE_MODULE *)buffer;
887 pModule->magic = NE_SIGNATURE;
888 pModule->count = 1;
889 pModule->next = 0;
890 pModule->dgroup_entry = 0;
891 pModule->flags = NE_FFLAGS_SINGLEDATA | NE_FFLAGS_BUILTIN |
892 NE_FFLAGS_LIBMODULE | NE_FFLAGS_WIN32;
893 pModule->dgroup = 0;
894 pModule->heap_size = DLLHeapSize;
895 pModule->stack_size = 0;
896 pModule->ip = 0;
897 pModule->cs = 0;
898 pModule->sp = 0;
899 pModule->ss = 0;
900 pModule->seg_count = 0;
901 pModule->modref_count = 0;
902 pModule->nrname_size = 0;
903 pModule->modref_table = 0;
904 pModule->nrname_fpos = 0;
905 pModule->moveable_entries = 0;
906 pModule->alignment = 0;
907 pModule->truetype = 0;
908 pModule->os_flags = NE_OSFLAGS_WINDOWS;
909 pModule->misc_flags = 0;
910 pModule->dlls_to_init = 0;
911 pModule->nrname_handle = 0;
912 pModule->min_swap_area = 0;
913 pModule->expected_version = 0x030a;
914 pModule->pe_module = NULL;
915 pModule->self = 0;
916 pModule->self_loading_sel = 0;
918 /* File information */
920 pFileInfo = (OFSTRUCT *)(pModule + 1);
921 pModule->fileinfo = (int)pFileInfo - (int)pModule;
922 memset( pFileInfo, 0, sizeof(*pFileInfo) - sizeof(pFileInfo->szPathName) );
923 pFileInfo->cBytes = sizeof(*pFileInfo) - sizeof(pFileInfo->szPathName)
924 + strlen(DLLName) + 4;
925 sprintf( pFileInfo->szPathName, "%s.DLL", DLLName );
926 pstr = (char *)pFileInfo + pFileInfo->cBytes + 1;
928 /* Segment table */
930 pModule->seg_table = (int)pstr - (int)pModule;
932 /* Resource table */
934 pword = (WORD *)pstr;
935 pModule->res_table = (int)pword - (int)pModule;
936 *pword++ = 0;
937 *pword++ = 0;
939 /* Imported names table */
941 pstr = (char *)pword;
942 pModule->import_table = (int)pstr - (int)pModule;
943 *pstr++ = 0;
944 *pstr++ = 0;
946 /* Resident names table */
948 pModule->name_table = (int)pstr - (int)pModule;
949 /* First entry is module name */
950 *pstr = strlen(DLLName );
951 strcpy( pstr + 1, DLLName );
952 pstr += *pstr + 1;
953 *(WORD *)pstr = 0;
954 pstr += sizeof(WORD);
955 *pstr++ = 0;
957 /* Entry table */
959 pModule->entry_table = (int)pstr - (int)pModule;
960 *pstr++ = 0;
962 /* Dump the module content */
964 DumpBytes( outfile, (char *)pModule, (int)pstr - (int)pModule,
965 ".data", "Module_Start" );
966 return (int)pstr - (int)pModule;
970 /*******************************************************************
971 * BuildSpec32File
973 * Build a Win32 assembly file from a spec file.
975 static int BuildSpec32File( FILE *outfile )
977 ORDDEF *odp;
978 int i, module_size, len;
979 char buffer[1024];
981 fprintf( outfile, "/* File generated automatically; do not edit! */\n" );
982 fprintf( outfile, "\t.text\n" );
983 fprintf( outfile, "\t.align 4\n" );
984 fprintf( outfile, "Code_Start:\n\n" );
986 odp = OrdinalDefinitions;
987 for (i = 0; i <= Limit; i++, odp++)
989 switch (odp->type)
991 case TYPE_INVALID:
992 break;
994 case TYPE_STDCALL:
995 case TYPE_CDECL:
996 case TYPE_STUB:
997 case TYPE_REGISTER:
998 fprintf( outfile, "/* %s.%d (%s) */\n", DLLName, i, odp->name);
999 fprintf( outfile, "%s_%d:\n", DLLName, i );
1000 fprintf( outfile, "\tpushl %%ebp\n" );
1001 fprintf( outfile, "\tpushl $" PREFIX "%s\n",odp->u.func.link_name);
1002 fprintf( outfile, "\tcall " PREFIX "CallFrom32_%s_%d\n",
1003 (odp->type == TYPE_REGISTER) ? "regs" :
1004 ((odp->type == TYPE_STDCALL) ? "stdcall" : "cdecl"),
1005 strlen(odp->u.func.arg_types));
1006 fprintf( outfile, "\tnop\n" );
1007 break;
1009 case TYPE_RETURN:
1010 fprintf( outfile, "/* %s.%d (%s) */\n", DLLName, i, odp->name);
1011 fprintf( outfile, "%s_%d:\n", DLLName, i );
1012 fprintf( outfile, "\tmovl $%d,%%eax\n",ERROR_CALL_NOT_IMPLEMENTED);
1013 fprintf( outfile, "\tmovl %%eax," PREFIX "WIN32_LastError\n" );
1014 fprintf( outfile, "\tmovl $%d,%%eax\n", odp->u.ret.ret_value );
1015 if (odp->u.ret.arg_size)
1017 fprintf( outfile, "\tret $%d\n", odp->u.ret.arg_size );
1018 fprintf( outfile, "\tnop\n" );
1019 fprintf( outfile, "\tnop\n" );
1021 else fprintf( outfile, "\tret\n" );
1022 break;
1024 case TYPE_BYTE:
1025 fprintf( outfile, "/* %s.%d (%s) */\n", DLLName, i, odp->name);
1026 fprintf( outfile, "\t.data\n" );
1027 fprintf( outfile, "%s_%d:\n", DLLName, i );
1028 len = StoreVariableCode( buffer, 1, odp );
1029 DumpBytes( outfile, buffer, len, NULL, NULL );
1030 fprintf( outfile, "\t.text\n" );
1031 break;
1033 case TYPE_WORD:
1034 fprintf( outfile, "/* %s.%d (%s) */\n",
1035 DLLName, i, odp->name);
1036 fprintf( outfile, "\t.data\n" );
1037 fprintf( outfile, "%s_%d:\n", DLLName, i );
1038 len = StoreVariableCode( buffer, 2, odp );
1039 DumpBytes( outfile, buffer, len, NULL, NULL );
1040 fprintf( outfile, "\t.text\n" );
1041 break;
1043 case TYPE_LONG:
1044 fprintf( outfile, "/* %s.%d (%s) */\n",
1045 DLLName, i, odp->name);
1046 fprintf( outfile, "\t.data\n" );
1047 fprintf( outfile, "%s_%d:\n", DLLName, i );
1048 len = StoreVariableCode( buffer, 4, odp );
1049 DumpBytes( outfile, buffer, len, NULL, NULL );
1050 fprintf( outfile, "\t.text\n" );
1051 break;
1053 case TYPE_EXTERN:
1054 break;
1056 default:
1057 fprintf(stderr,"build: function type %d not available for Win32\n",
1058 odp->type);
1059 return -1;
1063 module_size = BuildModule32( outfile );
1065 /* Output the DLL functions table */
1067 fprintf( outfile, "\t.text\n" );
1068 fprintf( outfile, "\t.align 4\n" );
1069 fprintf( outfile, "Functions:\n" );
1070 odp = OrdinalDefinitions;
1071 for (i = 0; i <= Limit; i++, odp++)
1073 switch(odp->type)
1075 case TYPE_INVALID:
1076 fprintf( outfile, "\t.long 0\n" );
1077 break;
1078 case TYPE_EXTERN:
1079 fprintf( outfile, "\t.long " PREFIX "%s\n", odp->u.ext.link_name );
1080 break;
1081 default:
1082 fprintf( outfile, "\t.long %s_%d\n", DLLName, i );
1083 break;
1087 /* Output the DLL names table */
1089 fprintf( outfile, "FuncNames:\n" );
1090 odp = OrdinalDefinitions;
1091 for (i = 0; i <= Limit; i++, odp++)
1093 if (odp->type == TYPE_INVALID) fprintf( outfile, "\t.long 0\n" );
1094 else fprintf( outfile, "\t.long Name_%d\n", i );
1097 /* Output the DLL names */
1099 for (i = 0, odp = OrdinalDefinitions; i <= Limit; i++, odp++)
1101 if (odp->type != TYPE_INVALID)
1102 fprintf( outfile, "Name_%d:\t.ascii \"%s\\0\"\n", i, odp->name );
1105 /* Output the DLL descriptor */
1107 fprintf( outfile, "DLLName:\t.ascii \"%s\\0\"\n", DLLName );
1108 fprintf( outfile, "\t.align 4\n" );
1109 fprintf( outfile, "\t.globl " PREFIX "%s_Descriptor\n", DLLName );
1110 fprintf( outfile, PREFIX "%s_Descriptor:\n", DLLName );
1111 fprintf( outfile, "\t.long DLLName\n" ); /* Name */
1112 fprintf( outfile, "\t.long Module_Start\n" ); /* Module start */
1113 fprintf( outfile, "\t.long %d\n", module_size ); /* Module size */
1114 fprintf( outfile, "\t.long %d\n", Base ); /* Base */
1115 fprintf( outfile, "\t.long %d\n", Limit+1 ); /* Size */
1116 fprintf( outfile, "\t.long Code_Start\n" ); /* Code start */
1117 fprintf( outfile, "\t.long Functions\n" ); /* Functions */
1118 fprintf( outfile, "\t.long FuncNames\n" ); /* Function names */
1119 return 0;
1123 /*******************************************************************
1124 * BuildSpec16File
1126 * Build a Win16 assembly file from a spec file.
1128 static int BuildSpec16File( FILE *outfile )
1130 ORDDEF *odp;
1131 int i;
1132 int code_offset, data_offset, module_size;
1133 unsigned char *data;
1135 data = (unsigned char *)xmalloc( 0x10000 );
1136 memset( data, 0, 16 );
1137 data_offset = 16;
1139 fprintf( outfile, "/* File generated automatically; do not edit! */\n" );
1140 fprintf( outfile, "\t.text\n" );
1141 fprintf( outfile, "Code_Start:\n" );
1142 code_offset = 0;
1144 odp = OrdinalDefinitions;
1145 for (i = 0; i <= Limit; i++, odp++)
1147 switch (odp->type)
1149 case TYPE_INVALID:
1150 odp->offset = 0xffff;
1151 break;
1153 case TYPE_ABS:
1154 odp->offset = LOWORD(odp->u.abs.value);
1155 break;
1157 case TYPE_BYTE:
1158 odp->offset = data_offset;
1159 data_offset += StoreVariableCode( data + data_offset, 1, odp);
1160 break;
1162 case TYPE_WORD:
1163 odp->offset = data_offset;
1164 data_offset += StoreVariableCode( data + data_offset, 2, odp);
1165 break;
1167 case TYPE_LONG:
1168 odp->offset = data_offset;
1169 data_offset += StoreVariableCode( data + data_offset, 4, odp);
1170 break;
1172 case TYPE_RETURN:
1173 fprintf( outfile,"/* %s.%d */\n", DLLName, i);
1174 fprintf( outfile,"\tmovw $%d,%%ax\n",LOWORD(odp->u.ret.ret_value));
1175 fprintf( outfile,"\tmovw $%d,%%dx\n",HIWORD(odp->u.ret.ret_value));
1176 fprintf( outfile,"\t.byte 0x66\n");
1177 if (odp->u.ret.arg_size != 0)
1178 fprintf( outfile, "\tlret $%d\n\n", odp->u.ret.arg_size);
1179 else
1181 fprintf( outfile, "\tlret\n");
1182 fprintf( outfile, "\tnop\n");
1183 fprintf( outfile, "\tnop\n\n");
1185 odp->offset = code_offset;
1186 code_offset += 12; /* Assembly code is 12 bytes long */
1187 break;
1189 case TYPE_REGISTER:
1190 case TYPE_PASCAL:
1191 case TYPE_PASCAL_16:
1192 case TYPE_STUB:
1193 fprintf( outfile, "/* %s.%d */\n", DLLName, i);
1194 fprintf( outfile, "\tpushw %%bp\n" );
1195 fprintf( outfile, "\tpushl $" PREFIX "%s\n",odp->u.func.link_name);
1196 /* FreeBSD does not understand lcall, so do it the hard way */
1197 fprintf( outfile, "\t.byte 0x9a /*lcall*/\n" );
1198 fprintf( outfile, "\t.long " PREFIX "CallFrom16_%s_%s\n",
1199 (odp->type == TYPE_REGISTER) ? "regs" :
1200 (odp->type == TYPE_PASCAL) ? "long" : "word",
1201 odp->u.func.arg_types );
1202 fprintf( outfile,"\t.byte 0x%02x,0x%02x\n", /* Some asms don't have .word */
1203 LOBYTE(WINE_CODE_SELECTOR), HIBYTE(WINE_CODE_SELECTOR) );
1204 fprintf( outfile, "\tnop\n" );
1205 fprintf( outfile, "\tnop\n\n" );
1206 odp->offset = code_offset;
1207 code_offset += 16; /* Assembly code is 16 bytes long */
1208 break;
1210 default:
1211 fprintf(stderr,"build: function type %d not available for Win16\n",
1212 odp->type);
1213 return -1;
1217 if (!code_offset) /* Make sure the code segment is not empty */
1219 fprintf( outfile, "\t.byte 0\n" );
1220 code_offset++;
1223 /* Output data segment */
1225 DumpBytes( outfile, data, data_offset, NULL, "Data_Start" );
1227 /* Build the module */
1229 module_size = BuildModule16( outfile, code_offset, data_offset );
1231 /* Output the DLL descriptor */
1233 fprintf( outfile, "\t.text\n" );
1234 fprintf( outfile, "DLLName:\t.ascii \"%s\\0\"\n", DLLName );
1235 fprintf( outfile, "\t.align 4\n" );
1236 fprintf( outfile, "\t.globl " PREFIX "%s_Descriptor\n", DLLName );
1237 fprintf( outfile, PREFIX "%s_Descriptor:\n", DLLName );
1238 fprintf( outfile, "\t.long DLLName\n" ); /* Name */
1239 fprintf( outfile, "\t.long Module_Start\n" ); /* Module start */
1240 fprintf( outfile, "\t.long %d\n", module_size ); /* Module size */
1241 fprintf( outfile, "\t.long Code_Start\n" ); /* Code start */
1242 fprintf( outfile, "\t.long Data_Start\n" ); /* Data start */
1243 return 0;
1247 /*******************************************************************
1248 * BuildSpecFile
1250 * Build an assembly file from a spec file.
1252 static int BuildSpecFile( FILE *outfile, char *specname )
1254 SpecFp = fopen( specname, "r");
1255 if (SpecFp == NULL)
1257 fprintf(stderr, "Could not open specification file, '%s'\n", specname);
1258 return -1;
1261 if (ParseTopLevel() < 0) return -1;
1263 switch(SpecType)
1265 case SPEC_WIN16:
1266 return BuildSpec16File( outfile );
1267 case SPEC_WIN32:
1268 return BuildSpec32File( outfile );
1269 default:
1270 fprintf( stderr, "%s: Missing 'type' declaration\n", specname );
1271 return -1;
1276 /*******************************************************************
1277 * BuildCall32LargeStack
1279 * Build the function used to switch to the original 32-bit stack
1280 * before calling a 32-bit function from 32-bit code. This is used for
1281 * functions that need a large stack, like X bitmaps functions.
1283 * The generated function has the following prototype:
1284 * int CallTo32_LargeStack( int (*func)(), int nbargs, ... )
1286 * Stack layout:
1287 * ... ...
1288 * (ebp+20) arg2
1289 * (ebp+16) arg1
1290 * (ebp+12) nbargs
1291 * (ebp+8) func
1292 * (ebp+4) ret addr
1293 * (ebp) ebp
1295 static void BuildCall32LargeStack( FILE *outfile )
1297 /* Function header */
1299 fprintf( outfile, "\n\t.align 4\n" );
1300 fprintf( outfile, "\t.globl " PREFIX "CallTo32_LargeStack\n" );
1301 fprintf( outfile, PREFIX "CallTo32_LargeStack:\n" );
1303 /* Entry code */
1305 fprintf( outfile, "\tpushl %%ebp\n" );
1306 fprintf( outfile, "\tmovl %%esp,%%ebp\n" );
1308 /* Save registers */
1310 fprintf( outfile, "\tpushl %%ecx\n" );
1311 fprintf( outfile, "\tpushl %%esi\n" );
1312 fprintf( outfile, "\tpushl %%edi\n" );
1314 /* Retrieve the original 32-bit stack pointer and switch to it if any */
1316 fprintf( outfile, "\tmovl " PREFIX "IF1632_Original32_esp, %%eax\n" );
1317 fprintf( outfile, "\torl %%eax,%%eax\n" );
1318 fprintf( outfile, "\tje no_orig_esp\n" );
1319 fprintf( outfile, "\tmovl %%eax,%%esp\n" );
1320 fprintf( outfile, "no_orig_esp:\n" );
1322 /* Transfer the arguments */
1324 fprintf( outfile, "\tmovl 12(%%ebp),%%ecx\n" );
1325 fprintf( outfile, "\torl %%ecx,%%ecx\n" );
1326 fprintf( outfile, "\tje no_args\n" );
1327 fprintf( outfile, "\tleal 16(%%ebp),%%esi\n" );
1328 fprintf( outfile, "\tshll $2,%%ecx\n" );
1329 fprintf( outfile, "\tsubl %%ecx,%%esp\n" );
1330 fprintf( outfile, "\tmovl %%esp,%%edi\n" );
1331 fprintf( outfile, "\tshrl $2,%%ecx\n" );
1332 fprintf( outfile, "\tcld\n" );
1333 fprintf( outfile, "\trep; movsl\n" );
1334 fprintf( outfile, "no_args:\n" );
1336 /* Call the function */
1338 fprintf( outfile, "\tcall 8(%%ebp)\n" );
1340 /* Switch back to the normal stack */
1342 fprintf( outfile, "\tleal -12(%%ebp),%%esp\n" );
1344 /* Restore registers and return */
1346 fprintf( outfile, "\tpopl %%edi\n" );
1347 fprintf( outfile, "\tpopl %%esi\n" );
1348 fprintf( outfile, "\tpopl %%ecx\n" );
1349 fprintf( outfile, "\tpopl %%ebp\n" );
1350 fprintf( outfile, "\tret\n" );
1354 /*******************************************************************
1355 * TransferArgs16To32
1357 * Get the arguments from the 16-bit stack and push them on the 32-bit stack.
1358 * The 16-bit stack layout is:
1359 * ... ...
1360 * (bp+8) arg2
1361 * (bp+6) arg1
1362 * (bp+4) cs
1363 * (bp+2) ip
1364 * (bp) bp
1366 static int TransferArgs16To32( FILE *outfile, char *args )
1368 int i, pos16, pos32;
1370 /* Save ebx first */
1372 fprintf( outfile, "\tpushl %%ebx\n" );
1374 /* Get the 32-bit stack pointer */
1376 fprintf( outfile, "\tmovl " PREFIX "IF1632_Saved32_esp,%%ebx\n" );
1378 /* Copy the arguments */
1380 pos16 = 6; /* skip bp and return address */
1381 pos32 = 0;
1383 for (i = strlen(args); i > 0; i--)
1385 pos32 -= 4;
1386 switch(args[i-1])
1388 case 'w': /* word */
1389 fprintf( outfile, "\tmovzwl %d(%%ebp),%%eax\n", pos16 );
1390 fprintf( outfile, "\tmovl %%eax,%d(%%ebx)\n", pos32 );
1391 pos16 += 2;
1392 break;
1394 case 's': /* s_word */
1395 fprintf( outfile, "\tmovswl %d(%%ebp),%%eax\n", pos16 );
1396 fprintf( outfile, "\tmovl %%eax,%d(%%ebx)\n", pos32 );
1397 pos16 += 2;
1398 break;
1400 case 'l': /* long */
1401 fprintf( outfile, "\tmovl %d(%%ebp),%%eax\n", pos16 );
1402 fprintf( outfile, "\tmovl %%eax,%d(%%ebx)\n", pos32 );
1403 pos16 += 4;
1404 break;
1406 case 'p': /* ptr */
1407 /* Get the selector */
1408 fprintf( outfile, "\tmovw %d(%%ebp),%%ax\n", pos16 + 2 );
1409 /* Get the selector base */
1410 fprintf( outfile, "\tandl $0xfff8,%%eax\n" );
1411 fprintf( outfile, "\tmovl " PREFIX "ldt_copy(%%eax),%%eax\n" );
1412 fprintf( outfile, "\tmovl %%eax,%d(%%ebx)\n", pos32 );
1413 /* Add the offset */
1414 fprintf( outfile, "\tmovzwl %d(%%ebp),%%eax\n", pos16 );
1415 fprintf( outfile, "\taddl %%eax,%d(%%ebx)\n", pos32 );
1416 pos16 += 4;
1417 break;
1419 default:
1420 fprintf( stderr, "Unknown arg type '%c'\n", args[i-1] );
1424 /* Restore ebx */
1426 fprintf( outfile, "\tpopl %%ebx\n" );
1428 return pos16 - 6; /* Return the size of the 16-bit args */
1432 /*******************************************************************
1433 * BuildContext16
1435 * Build the context structure on the 32-bit stack.
1436 * The only valid registers in the context structure are:
1437 * eax, ebx, ecx, edx, esi, edi, ds, es, (some of the) flags
1439 static void BuildContext16( FILE *outfile )
1441 /* Save ebx first */
1443 fprintf( outfile, "\tpushl %%ebx\n" );
1445 /* Get the 32-bit stack pointer */
1447 fprintf( outfile, "\tmovl " PREFIX "IF1632_Saved32_esp,%%ebx\n" );
1449 /* Store the registers */
1451 fprintf( outfile, "\tpopl %d(%%ebx)\n", SIGCONTEXTOFFSET(EBX) ); /* Get ebx from stack*/
1452 fprintf( outfile, "\tmovl %%eax,%d(%%ebx)\n", SIGCONTEXTOFFSET(EAX) );
1453 fprintf( outfile, "\tmovl %%ecx,%d(%%ebx)\n", SIGCONTEXTOFFSET(ECX) );
1454 fprintf( outfile, "\tmovl %%edx,%d(%%ebx)\n", SIGCONTEXTOFFSET(EDX) );
1455 fprintf( outfile, "\tmovl %%esi,%d(%%ebx)\n", SIGCONTEXTOFFSET(ESI) );
1456 fprintf( outfile, "\tmovl %%edi,%d(%%ebx)\n", SIGCONTEXTOFFSET(EDI) );
1457 fprintf( outfile, "\tmovw -10(%%ebp),%%ax\n" ); /*Get saved ds from stack*/
1458 fprintf( outfile, "\tmovw %%ax,%d(%%ebx)\n", SIGCONTEXTOFFSET(DS) );
1459 fprintf( outfile, "\tmovw -6(%%ebp),%%ax\n" ); /*Get saved es from stack*/
1460 fprintf( outfile, "\tmovw %%ax,%d(%%ebx)\n", SIGCONTEXTOFFSET(ES) );
1461 fprintf( outfile, "\tpushfl\n" );
1462 fprintf( outfile, "\tpopl %d(%%ebx)\n", SIGCONTEXTOFFSET(EFL) );
1466 /*******************************************************************
1467 * RestoreContext16
1469 * Restore the registers from the context structure
1471 static void RestoreContext16( FILE *outfile )
1473 /* Get the 32-bit stack pointer */
1475 fprintf( outfile, "\tmovl " PREFIX "IF1632_Saved32_esp,%%ebx\n" );
1477 /* Restore the registers */
1479 fprintf( outfile, "\tmovl %d(%%ebx),%%ecx\n", SIGCONTEXTOFFSET(ECX) );
1480 fprintf( outfile, "\tmovl %d(%%ebx),%%edx\n", SIGCONTEXTOFFSET(EDX) );
1481 fprintf( outfile, "\tmovl %d(%%ebx),%%esi\n", SIGCONTEXTOFFSET(ESI) );
1482 fprintf( outfile, "\tmovl %d(%%ebx),%%edi\n", SIGCONTEXTOFFSET(EDI) );
1483 fprintf( outfile, "\tpopl %%eax\n" ); /* Remove old ds and ip from stack */
1484 fprintf( outfile, "\tpopl %%eax\n" ); /* Remove old cs and es from stack */
1485 fprintf( outfile, "\tpushw %d(%%ebx)\n", SIGCONTEXTOFFSET(DS) ); /* Push new ds */
1486 fprintf( outfile, "\tpushw %d(%%ebx)\n", SIGCONTEXTOFFSET(ES) ); /*Push new es */
1487 fprintf( outfile, "\tpushl %d(%%ebx)\n", SIGCONTEXTOFFSET(EFL) );
1488 fprintf( outfile, "\tpopfl\n" );
1489 fprintf( outfile, "\tmovl %d(%%ebx),%%eax\n", SIGCONTEXTOFFSET(EAX) );
1490 fprintf( outfile, "\tmovl %d(%%ebx),%%ebx\n", SIGCONTEXTOFFSET(EBX) );
1494 /*******************************************************************
1495 * BuildCallFrom16Func
1497 * Build a 16-bit-to-Wine callback function. The syntax of the function
1498 * profile is: type_xxxxx, where 'type' is one of 'regs', 'word' or
1499 * 'long' and each 'x' is an argument ('w'=word, 's'=signed word,
1500 * 'l'=long, 'p'=pointer).
1501 * For register functions, the arguments are ignored, but they are still
1502 * removed from the stack upon return.
1504 * Stack layout upon entry to the callback function:
1505 * ... ...
1506 * (sp+18) word first 16-bit arg
1507 * (sp+16) word cs
1508 * (sp+14) word ip
1509 * (sp+12) word bp
1510 * (sp+8) long 32-bit entry point
1511 * (sp+6) word high word of cs (always 0, used to store es)
1512 * (sp+4) word low word of cs of 16-bit entry point
1513 * (sp+2) word high word of ip (always 0, used to store ds)
1514 * (sp) word low word of ip of 16-bit entry point
1517 static void BuildCallFrom16Func( FILE *outfile, char *profile )
1519 int argsize = 0;
1520 int short_ret = 0;
1521 int reg_func = 0;
1522 char *args = profile + 5;
1524 /* Parse function type */
1526 if (!strncmp( "word_", profile, 5 )) short_ret = 1;
1527 else if (!strncmp( "regs_", profile, 5 )) reg_func = 1;
1528 else if (strncmp( "long_", profile, 5 ))
1530 fprintf( stderr, "Invalid function name '%s', ignored\n", profile );
1531 return;
1534 /* Function header */
1536 fprintf( outfile, "\n\t.align 4\n" );
1537 fprintf( outfile, "\t.globl " PREFIX "CallFrom16_%s\n", profile );
1538 fprintf( outfile, PREFIX "CallFrom16_%s:\n", profile );
1540 /* Setup bp to point to its copy on the stack */
1542 fprintf( outfile, "\tmovzwl %%sp,%%ebp\n" );
1543 fprintf( outfile, "\taddw $12,%%bp\n" );
1545 /* Save 16-bit ds and es */
1547 /* Stupid FreeBSD assembler doesn't know these either */
1548 /* fprintf( outfile, "\tmovw %%ds,-10(%%ebp)\n" ); */
1549 fprintf( outfile, "\t.byte 0x66,0x8c,0x5d,0xf6\n" );
1550 /* fprintf( outfile, "\tmovw %%es,-6(%%ebp)\n" ); */
1551 fprintf( outfile, "\t.byte 0x66,0x8c,0x45,0xfa\n" );
1553 /* Restore 32-bit ds and es */
1555 fprintf( outfile, "\tpushl $0x%04x%04x\n",
1556 WINE_DATA_SELECTOR, WINE_DATA_SELECTOR );
1557 fprintf( outfile, "\tpopw %%ds\n" );
1558 fprintf( outfile, "\tpopw %%es\n" );
1561 /* Save the 16-bit stack */
1563 fprintf( outfile, "\tpushw " PREFIX "IF1632_Saved16_sp\n" );
1564 fprintf( outfile, "\tpushw " PREFIX "IF1632_Saved16_ss\n" );
1565 #ifdef __svr4__
1566 fprintf( outfile,"\tdata16\n");
1567 #endif
1568 fprintf( outfile, "\tmovw %%ss," PREFIX "IF1632_Saved16_ss\n" );
1569 fprintf( outfile, "\tmovw %%sp," PREFIX "IF1632_Saved16_sp\n" );
1571 /* Transfer the arguments */
1573 if (reg_func) BuildContext16( outfile );
1574 else if (*args) argsize = TransferArgs16To32( outfile, args );
1576 /* Get the address of the API function */
1578 fprintf( outfile, "\tmovl -4(%%ebp),%%eax\n" );
1580 /* If necessary, save %edx over the API function address */
1582 if (!reg_func && short_ret)
1583 fprintf( outfile, "\tmovl %%edx,-4(%%ebp)\n" );
1585 /* Switch to the 32-bit stack */
1587 fprintf( outfile, "\tmovl " PREFIX "IF1632_Saved32_esp,%%ebp\n" );
1588 fprintf( outfile, "\tpushw %%ds\n" );
1589 fprintf( outfile, "\tpopw %%ss\n" );
1590 fprintf( outfile, "\tleal -%d(%%ebp),%%esp\n",
1591 reg_func ? sizeof(SIGCONTEXT) : 4 * strlen(args) );
1592 if (reg_func) /* Push the address of the context struct */
1593 fprintf( outfile, "\tpushl %%esp\n" );
1595 /* Setup %ebp to point to the previous stack frame (built by CallTo16) */
1597 fprintf( outfile, "\taddl $24,%%ebp\n" );
1599 /* Print the debug information before the call */
1601 if (debugging)
1603 fprintf( outfile, "\tpushl %%eax\n" );
1604 fprintf( outfile, "\tpushl $Profile_%s\n", profile );
1605 fprintf( outfile, "\tpushl $%d\n", reg_func ? 2 : (short_ret ? 1 : 0));
1606 fprintf( outfile, "\tcall " PREFIX "RELAY_DebugCallFrom16\n" );
1607 fprintf( outfile, "\tpopl %%eax\n" );
1608 fprintf( outfile, "\tpopl %%eax\n" );
1609 fprintf( outfile, "\tpopl %%eax\n" );
1612 /* Call the entry point */
1614 fprintf( outfile, "\tcall %%eax\n" );
1616 /* Print the debug information after the call */
1618 if (debugging)
1620 fprintf( outfile, "\tpushl %%eax\n" );
1621 fprintf( outfile, "\tpushl $%d\n", reg_func ? 2 : (short_ret ? 1 : 0));
1622 fprintf( outfile, "\tcall " PREFIX "RELAY_DebugCallFrom16Ret\n" );
1623 fprintf( outfile, "\tpopl %%eax\n" );
1624 fprintf( outfile, "\tpopl %%eax\n" );
1627 /* Restore the 16-bit stack */
1629 #ifdef __svr4__
1630 fprintf( outfile, "\tdata16\n");
1631 #endif
1632 fprintf( outfile, "\tmovw " PREFIX "IF1632_Saved16_ss,%%ss\n" );
1633 fprintf( outfile, "\tmovw " PREFIX "IF1632_Saved16_sp,%%sp\n" );
1634 #ifdef __svr4__
1635 fprintf( outfile, "\tdata16\n");
1636 #endif
1637 fprintf( outfile, "\tpopw " PREFIX "IF1632_Saved16_ss\n" );
1638 #ifdef __svr4__
1639 fprintf( outfile, "\tdata16\n");
1640 #endif
1641 fprintf( outfile, "\tpopw " PREFIX "IF1632_Saved16_sp\n" );
1643 if (reg_func)
1645 /* Restore registers from the context structure */
1646 RestoreContext16( outfile );
1648 /* Calc the arguments size */
1649 while (*args)
1651 switch(*args)
1653 case 'w':
1654 case 's':
1655 argsize += 2;
1656 break;
1657 case 'p':
1658 case 'l':
1659 argsize += 4;
1660 break;
1661 default:
1662 fprintf( stderr, "Unknown arg type '%c'\n", *args );
1664 args++;
1667 /* Restore ds and es */
1668 fprintf( outfile, "\tpopw %%es\n" );
1669 fprintf( outfile, "\tpopw %%ds\n" );
1671 /* Remove the entry point from the stack */
1672 /* (we don't use add to avoid modifying the carry flag) */
1673 fprintf( outfile, "\tpopl %%ebp\n" );
1675 else
1677 /* Restore ds and es */
1678 fprintf( outfile, "\tpopw %%bp\n" ); /* Remove ip */
1679 fprintf( outfile, "\tpopl %%ebp\n" ); /* Remove ds and cs */
1680 fprintf( outfile, "\tmovw %%bp,%%ds\n" ); /* Restore ds */
1681 fprintf( outfile, "\tpopw %%es\n" ); /* Restore es */
1683 if (short_ret) fprintf( outfile, "\tpopl %%edx\n" ); /* Restore edx */
1684 else
1686 /* Get the return value into dx:ax */
1687 fprintf( outfile, "\tpushl %%eax\n" );
1688 fprintf( outfile, "\tpopw %%ax\n" );
1689 fprintf( outfile, "\tpopw %%dx\n" );
1690 /* Remove API entry point */
1691 fprintf( outfile, "\taddl $4,%%esp\n" );
1695 /* Restore bp */
1697 fprintf( outfile, "\tpopw %%bp\n" );
1699 /* Remove the arguments and return */
1701 if (argsize)
1703 fprintf( outfile, "\t.byte 0x66\n" );
1704 fprintf( outfile, "\tlret $%d\n", argsize );
1706 else
1708 fprintf( outfile, "\t.byte 0x66\n" );
1709 fprintf( outfile, "\tlret\n" );
1714 /*******************************************************************
1715 * BuildCallTo16Func
1717 * Build a Wine-to-16-bit callback function.
1719 * Stack frame of the callback function:
1720 * ... ...
1721 * (ebp+20) arg2
1722 * (ebp+16) arg1
1723 * (ebp+12) func to call
1724 * (ebp+8) code selector
1725 * (ebp+4) return address
1726 * (ebp) previous ebp
1728 * Prototypes for the CallTo16 functions:
1729 * extern WORD CallTo16_word_xxx( FARPROC16 func, args... );
1730 * extern LONG CallTo16_long_xxx( FARPROC16 func, args... );
1731 * extern void CallTo16_regs_( FARPROC16 func, WORD ds, WORD es, WORD bp,
1732 * WORD ax, WORD bx, WORD cx, WORD dx,
1733 * WORD si, WORD di );
1735 static void BuildCallTo16Func( FILE *outfile, char *profile )
1737 int short_ret = 0;
1738 int reg_func = 0;
1739 char *args = profile + 5;
1741 if (!strncmp( "word_", profile, 5 )) short_ret = 1;
1742 else if (!strncmp( "regs_", profile, 5 )) reg_func = short_ret = 1;
1743 else if (strncmp( "long_", profile, 5 ))
1745 fprintf( stderr, "Invalid function name '%s', ignored\n", profile );
1746 return;
1749 /* Function header */
1751 fprintf( outfile, "\n\t.align 4\n" );
1752 fprintf( outfile, "\t.globl " PREFIX "CallTo16_%s\n", profile );
1753 fprintf( outfile, PREFIX "CallTo16_%s:\n", profile );
1755 /* Push code selector before return address to simulate a lcall */
1757 fprintf( outfile, "\tpopl %%eax\n" );
1758 fprintf( outfile, "\tpushl $0x%04x\n", WINE_CODE_SELECTOR );
1759 fprintf( outfile, "\tpushl %%eax\n" );
1761 /* Entry code */
1763 fprintf( outfile, "\tpushl %%ebp\n" );
1764 fprintf( outfile, "\tmovl %%esp,%%ebp\n" );
1766 /* Save the 32-bit registers */
1768 fprintf( outfile, "\tpushl %%ebx\n" );
1769 fprintf( outfile, "\tpushl %%ecx\n" );
1770 fprintf( outfile, "\tpushl %%edx\n" );
1771 fprintf( outfile, "\tpushl %%esi\n" );
1772 fprintf( outfile, "\tpushl %%edi\n" );
1774 /* Save the 32-bit stack */
1776 fprintf( outfile, "\tpushl " PREFIX "IF1632_Saved32_esp\n" );
1777 fprintf( outfile, "\tmovl %%esp," PREFIX "IF1632_Saved32_esp\n" );
1778 fprintf( outfile, "\tmovl %%ebp,%%ebx\n" );
1780 /* Print debugging info */
1782 if (debugging)
1784 /* Push the address of the first argument */
1785 fprintf( outfile, "\tmovl %%ebx,%%eax\n" );
1786 fprintf( outfile, "\taddl $12,%%eax\n" );
1787 fprintf( outfile, "\tpushl $%d\n", reg_func ? 8 : strlen(args) );
1788 fprintf( outfile, "\tpushl %%eax\n" );
1789 fprintf( outfile, "\tcall " PREFIX "RELAY_DebugCallTo16\n" );
1790 fprintf( outfile, "\tpopl %%eax\n" );
1791 fprintf( outfile, "\tpopl %%eax\n" );
1794 /* Switch to the 16-bit stack */
1796 #ifdef __svr4__
1797 fprintf( outfile,"\tdata16\n");
1798 #endif
1799 fprintf( outfile, "\tmovw " PREFIX "IF1632_Saved16_ss,%%ss\n" );
1800 fprintf( outfile, "\tmovw " PREFIX "IF1632_Saved16_sp,%%sp\n" );
1802 /* Transfer the arguments */
1804 if (reg_func)
1806 /* Get the registers. ebx is handled later on. */
1807 fprintf( outfile, "\tpushw 20(%%ebx)\n" );
1808 fprintf( outfile, "\tpopw %%es\n" );
1809 fprintf( outfile, "\tmovl 24(%%ebx),%%ebp\n" );
1810 fprintf( outfile, "\tmovl 28(%%ebx),%%eax\n" );
1811 fprintf( outfile, "\tmovl 36(%%ebx),%%ecx\n" );
1812 fprintf( outfile, "\tmovl 40(%%ebx),%%edx\n" );
1813 fprintf( outfile, "\tmovl 44(%%ebx),%%esi\n" );
1814 fprintf( outfile, "\tmovl 48(%%ebx),%%edi\n" );
1816 else /* not a register function */
1818 int pos = 16; /* first argument position */
1820 /* Make %bp point to the previous stackframe (built by CallFrom16) */
1821 fprintf( outfile, "\tmovzwl %%sp,%%ebp\n" );
1822 fprintf( outfile, "\taddw $16,%%bp\n" );
1824 while (*args)
1826 switch(*args++)
1828 case 'w': /* word */
1829 fprintf( outfile, "\tpushw %d(%%ebx)\n", pos );
1830 break;
1831 case 'l': /* long */
1832 fprintf( outfile, "\tpushl %d(%%ebx)\n", pos );
1833 break;
1835 pos += 4;
1839 /* Push the return address */
1841 fprintf( outfile, "\tpushl " PREFIX "CALLTO16_RetAddr_%s\n",
1842 short_ret ? "word" : "long" );
1844 /* Push the called routine address */
1846 fprintf( outfile, "\tpushl 12(%%ebx)\n" );
1848 /* Get the 16-bit ds */
1850 if (reg_func)
1852 fprintf( outfile, "\tpushw 16(%%ebx)\n" );
1853 /* Get ebx from the 32-bit stack */
1854 fprintf( outfile, "\tmovl 32(%%ebx),%%ebx\n" );
1855 fprintf( outfile, "\tpopw %%ds\n" );
1857 else
1859 /* Get previous ds from the 16-bit stack and */
1860 /* set ax equal to ds for window procedures. */
1861 fprintf( outfile, "\tmovw -10(%%ebp),%%ax\n" );
1862 #ifdef __svr4__
1863 fprintf( outfile, "\tdata16\n");
1864 #endif
1865 fprintf( outfile, "\tmovw %%ax,%%ds\n" );
1868 /* Jump to the called routine */
1870 fprintf( outfile, "\t.byte 0x66\n" );
1871 fprintf( outfile, "\tlret\n" );
1875 /*******************************************************************
1876 * BuildRet16Func
1878 * Build the return code for 16-bit callbacks
1880 static void BuildRet16Func( FILE *outfile )
1882 fprintf( outfile, "\t.globl " PREFIX "CALLTO16_Ret_word\n" );
1883 fprintf( outfile, "\t.globl " PREFIX "CALLTO16_Ret_long\n" );
1885 /* Put return value into eax */
1887 fprintf( outfile, PREFIX "CALLTO16_Ret_long:\n" );
1888 fprintf( outfile, "\tpushw %%dx\n" );
1889 fprintf( outfile, "\tpushw %%ax\n" );
1890 fprintf( outfile, "\tpopl %%eax\n" );
1891 fprintf( outfile, PREFIX "CALLTO16_Ret_word:\n" );
1893 /* Restore 32-bit segment registers */
1895 fprintf( outfile, "\tmovw $0x%04x,%%bx\n", WINE_DATA_SELECTOR );
1896 #ifdef __svr4__
1897 fprintf( outfile, "\tdata16\n");
1898 #endif
1899 fprintf( outfile, "\tmovw %%bx,%%ds\n" );
1900 #ifdef __svr4__
1901 fprintf( outfile, "\tdata16\n");
1902 #endif
1903 fprintf( outfile, "\tmovw %%bx,%%es\n" );
1904 #ifdef __svr4__
1905 fprintf( outfile, "\tdata16\n");
1906 #endif
1907 fprintf( outfile, "\tmovw %%bx,%%ss\n" );
1909 /* Restore the 32-bit stack */
1911 fprintf( outfile, "\tmovl " PREFIX "IF1632_Saved32_esp,%%esp\n" );
1912 fprintf( outfile, "\tpopl " PREFIX "IF1632_Saved32_esp\n" );
1914 /* Restore the 32-bit registers */
1916 fprintf( outfile, "\tpopl %%edi\n" );
1917 fprintf( outfile, "\tpopl %%esi\n" );
1918 fprintf( outfile, "\tpopl %%edx\n" );
1919 fprintf( outfile, "\tpopl %%ecx\n" );
1920 fprintf( outfile, "\tpopl %%ebx\n" );
1922 /* Return to caller */
1924 fprintf( outfile, "\tpopl %%ebp\n" );
1925 fprintf( outfile, "\tlret\n" );
1927 /* Declare the return address variables */
1929 fprintf( outfile, "\t.data\n" );
1930 fprintf( outfile, "\t.globl " PREFIX "CALLTO16_RetAddr_word\n" );
1931 fprintf( outfile, "\t.globl " PREFIX "CALLTO16_RetAddr_long\n" );
1932 fprintf( outfile, PREFIX "CALLTO16_RetAddr_word:\t.long 0\n" );
1933 fprintf( outfile, PREFIX "CALLTO16_RetAddr_long:\t.long 0\n" );
1934 fprintf( outfile, "\t.text\n" );
1938 /*******************************************************************
1939 * BuildContext32
1941 * Build the context structure on the stack.
1943 static void BuildContext32( FILE *outfile )
1945 /* Build the context structure */
1947 fprintf( outfile, "\tpushfl\n" );
1948 fprintf( outfile, "\tsubl $%d,%%esp\n", sizeof(CONTEXT) );
1949 fprintf( outfile, "\tmovl %%eax,%d(%%esp)\n", CONTEXTOFFSET(Eax) );
1950 fprintf( outfile, "\tmovl %%ebx,%d(%%esp)\n", CONTEXTOFFSET(Ebx) );
1951 fprintf( outfile, "\tmovl %%ecx,%d(%%esp)\n", CONTEXTOFFSET(Ecx) );
1952 fprintf( outfile, "\tmovl %%edx,%d(%%esp)\n", CONTEXTOFFSET(Edx) );
1953 fprintf( outfile, "\tmovl %%esi,%d(%%esp)\n", CONTEXTOFFSET(Esi) );
1954 fprintf( outfile, "\tmovl %%edi,%d(%%esp)\n", CONTEXTOFFSET(Edi) );
1956 fprintf( outfile, "\tmovl %d(%%esp),%%eax\n", sizeof(CONTEXT) );
1957 fprintf( outfile, "\tmovl %%eax,%d(%%esp)\n", CONTEXTOFFSET(EFlags) );
1959 fprintf( outfile, "\tmovl %%cs,%d(%%esp)\n", CONTEXTOFFSET(SegCs) );
1960 fprintf( outfile, "\tmovl %%ds,%d(%%esp)\n", CONTEXTOFFSET(SegDs) );
1961 fprintf( outfile, "\tmovl %%es,%d(%%esp)\n", CONTEXTOFFSET(SegEs) );
1962 fprintf( outfile, "\tmovl %%fs,%d(%%esp)\n", CONTEXTOFFSET(SegFs) );
1963 fprintf( outfile, "\tmovl %%gs,%d(%%esp)\n", CONTEXTOFFSET(SegGs) );
1964 fprintf( outfile, "\tmovl %%ss,%d(%%esp)\n", CONTEXTOFFSET(SegSs) );
1966 fprintf( outfile, "\tfsave %d(%%esp)\n", CONTEXTOFFSET(FloatSave) );
1968 fprintf( outfile, "\tmovl 4(%%ebp),%%eax\n" ); /* %eip at time of call */
1969 fprintf( outfile, "\tmovl %%eax,%d(%%esp)\n", CONTEXTOFFSET(Eip) );
1970 fprintf( outfile, "\tmovl 0(%%ebp),%%eax\n" ); /* %ebp at time of call */
1971 fprintf( outfile, "\tmovl %%eax,%d(%%esp)\n", CONTEXTOFFSET(Ebp) );
1972 fprintf( outfile, "\tleal 8(%%ebp),%%eax\n" ); /* %esp at time of call */
1973 fprintf( outfile, "\tmovl %%eax,%d(%%esp)\n", CONTEXTOFFSET(Esp) );
1975 /* Push pointer to context */
1977 fprintf( outfile, "\tpushl %%esp\n" );
1981 /*******************************************************************
1982 * RestoreContext32
1984 * Restore the registers from the context structure
1986 static void RestoreContext32( FILE *outfile )
1988 /* Restore the context structure */
1990 fprintf( outfile, "\tleal %d(%%ebp),%%esp\n", -sizeof(CONTEXT)-12 );
1991 fprintf( outfile, "\tfrstor %d(%%esp)\n", CONTEXTOFFSET(FloatSave) );
1993 fprintf( outfile, "\tmovl %d(%%esp),%%ebx\n", CONTEXTOFFSET(Ebx) );
1994 fprintf( outfile, "\tmovl %d(%%esp),%%ecx\n", CONTEXTOFFSET(Ecx) );
1995 fprintf( outfile, "\tmovl %d(%%esp),%%edx\n", CONTEXTOFFSET(Edx) );
1996 fprintf( outfile, "\tmovl %d(%%esp),%%esi\n", CONTEXTOFFSET(Esi) );
1997 fprintf( outfile, "\tmovl %d(%%esp),%%edi\n", CONTEXTOFFSET(Edi) );
1999 fprintf( outfile, "\tmovl %d(%%esp),%%eax\n", CONTEXTOFFSET(EFlags) );
2000 fprintf( outfile, "\tmovl %%eax,%d(%%esp)\n", sizeof(CONTEXT) );
2002 /* fprintf( outfile, "\tmovl %d(%%esp),%%cs\n", CONTEXTOFFSET(SegCs) ); */
2003 fprintf( outfile, "\tmovl %d(%%esp),%%ds\n", CONTEXTOFFSET(SegDs) );
2004 fprintf( outfile, "\tmovl %d(%%esp),%%es\n", CONTEXTOFFSET(SegEs) );
2005 fprintf( outfile, "\tmovl %d(%%esp),%%fs\n", CONTEXTOFFSET(SegFs) );
2006 fprintf( outfile, "\tmovl %d(%%esp),%%gs\n", CONTEXTOFFSET(SegGs) );
2008 fprintf( outfile, "\tmovl %d(%%esp),%%eax\n", CONTEXTOFFSET(Eip) );
2009 fprintf( outfile, "\tmovl %%eax,4(%%ebp)\n" ); /* %eip at time of call */
2010 fprintf( outfile, "\tmovl %d(%%esp),%%eax\n", CONTEXTOFFSET(Ebp) );
2011 fprintf( outfile, "\tmovl %%eax,0(%%ebp)\n" ); /* %ebp at time of call */
2013 /* fprintf( outfile, "\tmovl %d(%%esp),%%ss\n", CONTEXTOFFSET(SegSs) ); */
2014 /* fprintf( outfile, "\tmovl %d(%%esp),%%eax\n", CONTEXTOFFSET(Esp) ); */
2016 fprintf( outfile, "\tmovl %d(%%esp),%%eax\n", CONTEXTOFFSET(Eax) );
2018 fprintf( outfile, "\taddl $%d,%%esp\n", sizeof(CONTEXT) );
2019 fprintf( outfile, "\tpopfl\n" );
2023 /*******************************************************************
2024 * BuildCallFrom32Func
2026 * Build a 32-bit-to-Wine call-back function.
2027 * 'args' is the number of dword arguments.
2029 * Stack layout:
2030 * ... ...
2031 * (ebp+12) arg2
2032 * (ebp+8) arg1
2033 * (ebp+4) ret addr
2034 * (ebp) ebp
2035 * (ebp-4) entry point
2036 * (ebp-8) relay addr
2038 static void BuildCallFrom32Func( FILE *outfile, const char *profile )
2040 int args, stdcall, reg_func;
2042 if (!strncmp( profile, "stdcall", 7 ))
2044 stdcall = 1;
2045 reg_func = 0;
2046 args = atoi( profile + 8 );
2048 else if (!strncmp( profile, "cdecl", 5 ))
2050 stdcall = reg_func = 0;
2051 args = atoi( profile + 6 );
2053 else if (!strncmp( profile, "regs", 4 ))
2055 stdcall = reg_func = 1;
2056 args = atoi( profile + 5 );
2058 else
2060 fprintf( stderr, "Invalid function profile '%s', ignored\n", profile );
2061 return;
2064 /* Function header */
2066 fprintf( outfile, "\n\t.align 4\n" );
2067 fprintf( outfile, "\t.globl " PREFIX "CallFrom32_%s\n", profile );
2068 fprintf( outfile, PREFIX "CallFrom32_%s:\n", profile );
2070 /* Entry code */
2072 fprintf( outfile, "\tleal 8(%%esp),%%ebp\n" );
2074 /* Transfer the arguments */
2076 if (reg_func) BuildContext32( outfile );
2078 if (args)
2080 int i;
2081 for (i = args; i > 0; i--)
2082 fprintf( outfile, "\tpushl %d(%%ebp)\n", 4 * i + 4 );
2084 else if (!reg_func)
2086 /* Push the address of the arguments. The called function will */
2087 /* ignore this if it really takes no arguments. */
2088 fprintf( outfile, "\tleal 8(%%ebp),%%eax\n" );
2089 fprintf( outfile, "\tpushl %%eax\n" );
2092 /* Print the debugging info */
2094 if (debugging)
2096 fprintf( outfile, "\tpushl $%d\n", reg_func ? -1 : args); /* Nb args */
2097 fprintf( outfile, "\tpushl %%ebp\n" );
2098 fprintf( outfile, "\tcall " PREFIX "RELAY_DebugCallFrom32\n" );
2099 fprintf( outfile, "\tadd $8, %%esp\n" );
2102 /* Call the function */
2104 fprintf( outfile, "\tcall -4(%%ebp)\n" );
2106 /* Print the debugging info */
2108 if (debugging)
2110 fprintf( outfile, "\tpushl %%eax\n" );
2111 fprintf( outfile, "\tpushl $%d\n", reg_func ? -1 : args); /* Nb args */
2112 fprintf( outfile, "\tpushl %%ebp\n" );
2113 fprintf( outfile, "\tcall " PREFIX "RELAY_DebugCallFrom32Ret\n" );
2114 fprintf( outfile, "\tpopl %%eax\n" );
2115 fprintf( outfile, "\tpopl %%eax\n" );
2116 fprintf( outfile, "\tpopl %%eax\n" );
2119 if (reg_func) RestoreContext32( outfile );
2121 fprintf( outfile, "\tmovl %%ebp,%%esp\n" );
2122 fprintf( outfile, "\tpopl %%ebp\n" );
2124 /* Return, removing arguments */
2126 if (args && stdcall) fprintf( outfile, "\tret $%d\n", args * 4 );
2127 else fprintf( outfile, "\tret\n" );
2131 /*******************************************************************
2132 * BuildCallTo32Func
2134 * Build a Wine-to-32-bit callback function.
2136 * Stack frame of the callback function:
2137 * ... ...
2138 * (ebp+16) arg2
2139 * (ebp+12) arg1
2140 * (ebp+8) func to call
2141 * (ebp+4) return address
2142 * (ebp) previous ebp
2144 * Prototype for the CallTo32 functions:
2145 * extern LONG CallTo32_nn( FARPROC32 func, args... );
2147 static void BuildCallTo32Func( FILE *outfile, int args )
2149 /* Function header */
2151 fprintf( outfile, "\n\t.align 4\n" );
2152 fprintf( outfile, "\t.globl " PREFIX "CallTo32_%d\n", args );
2153 fprintf( outfile, PREFIX "CallTo32_%d:\n", args );
2155 /* Entry code */
2157 fprintf( outfile, "\tpushl %%ebp\n" );
2158 fprintf( outfile, "\tmovl %%esp,%%ebp\n" );
2160 /* Transfer arguments */
2162 if (args)
2164 int i;
2165 for (i = args; i > 0; i--)
2166 fprintf( outfile, "\tpushl %d(%%ebp)\n", 4 * i + 8 );
2169 /* Print the debugging output */
2171 if (debugging)
2173 fprintf( outfile, "\tpushl $%d\n", args );
2174 fprintf( outfile, "\tpushl 8(%%ebp)\n" );
2175 fprintf( outfile, "\tcall " PREFIX "RELAY_DebugCallTo32\n" );
2176 fprintf( outfile, "\taddl $8,%%esp\n" );
2179 /* Call the function */
2181 fprintf( outfile, "\tcall 8(%%ebp)\n" );
2183 /* Return to Wine */
2185 fprintf( outfile, "\tmovl %%ebp,%%esp\n" );
2186 fprintf( outfile, "\tpopl %%ebp\n" );
2187 fprintf( outfile, "\tret\n" );
2191 /*******************************************************************
2192 * BuildSpec
2194 * Build the spec files
2196 static int BuildSpec( FILE *outfile, int argc, char *argv[] )
2198 int i;
2199 for (i = 2; i < argc; i++)
2200 if (BuildSpecFile( outfile, argv[i] ) < 0) return -1;
2201 return 0;
2205 /*******************************************************************
2206 * BuildCallFrom16
2208 * Build the 16-bit-to-Wine callbacks
2210 static int BuildCallFrom16( FILE *outfile, int argc, char *argv[] )
2212 int i;
2214 /* File header */
2216 fprintf( outfile, "/* File generated automatically. Do not edit! */\n\n" );
2217 fprintf( outfile, "\t.text\n" );
2219 /* Build the 32-bit large stack callback */
2221 BuildCall32LargeStack( outfile );
2223 /* Build the callback functions */
2225 for (i = 2; i < argc; i++) BuildCallFrom16Func( outfile, argv[i] );
2227 /* Output the argument debugging strings */
2229 if (debugging)
2231 fprintf( outfile, "/* Argument strings */\n" );
2232 for (i = 2; i < argc; i++)
2234 fprintf( outfile, "Profile_%s:\n", argv[i] );
2235 fprintf( outfile, "\t.ascii \"%s\\0\"\n", argv[i] + 5 );
2238 return 0;
2242 /*******************************************************************
2243 * BuildCallTo16
2245 * Build the Wine-to-16-bit callbacks
2247 static int BuildCallTo16( FILE *outfile, int argc, char *argv[] )
2249 int i;
2251 /* File header */
2253 fprintf( outfile, "/* File generated automatically. Do not edit! */\n\n" );
2254 fprintf( outfile, "\t.text\n" );
2255 fprintf( outfile, "\t.globl " PREFIX "CALLTO16_Start\n" );
2256 fprintf( outfile, PREFIX "CALLTO16_Start:\n" );
2258 /* Build the callback functions */
2260 for (i = 2; i < argc; i++) BuildCallTo16Func( outfile, argv[i] );
2262 /* Output the 16-bit return code */
2264 BuildRet16Func( outfile );
2266 fprintf( outfile, "\t.globl " PREFIX "CALLTO16_End\n" );
2267 fprintf( outfile, PREFIX "CALLTO16_End:\n" );
2268 return 0;
2272 /*******************************************************************
2273 * BuildCallFrom32
2275 * Build the 32-bit-to-Wine callbacks
2277 static int BuildCallFrom32( FILE *outfile, int argc, char *argv[] )
2279 int i;
2281 /* File header */
2283 fprintf( outfile, "/* File generated automatically. Do not edit! */\n\n" );
2284 fprintf( outfile, "\t.text\n" );
2286 /* Build the callback functions */
2288 for (i = 2; i < argc; i++) BuildCallFrom32Func( outfile, argv[i] );
2289 return 0;
2293 /*******************************************************************
2294 * BuildCallTo32
2296 * Build the Wine-to-32-bit callbacks
2298 static int BuildCallTo32( FILE *outfile, int argc, char *argv[] )
2300 int i;
2302 /* File header */
2304 fprintf( outfile, "/* File generated automatically. Do not edit! */\n\n" );
2305 fprintf( outfile, "\t.text\n" );
2307 /* Build the callback functions */
2309 for (i = 2; i < argc; i++) BuildCallTo32Func( outfile, atoi(argv[i]) );
2310 return 0;
2314 /*******************************************************************
2315 * usage
2317 static void usage(void)
2319 fprintf(stderr, "usage: build [-o outfile] -spec SPECNAMES\n"
2320 " build [-o outfile] -callfrom16 FUNCTION_PROFILES\n"
2321 " build [-o outfile] -callto16 FUNCTION_PROFILES\n"
2322 " build [-o outfile] -callfrom32 FUNCTION_PROFILES\n"
2323 " build [-o outfile] -callto32 FUNCTION_PROFILES\n");
2324 exit(1);
2328 /*******************************************************************
2329 * main
2331 int main(int argc, char **argv)
2333 char *outname = NULL;
2334 FILE *outfile = stdout;
2335 int res = -1;
2337 if (argc <= 2) usage();
2339 if (!strcmp( argv[1], "-o" ))
2341 outname = argv[2];
2342 argv += 2;
2343 argc -= 2;
2344 if (argc <= 2) usage();
2345 if (!(outfile = fopen( outname, "w" )))
2347 fprintf( stderr, "Unable to create output file '%s'\n", outname );
2348 exit(1);
2352 if (!strcmp( argv[1], "-spec" ))
2353 res = BuildSpec( outfile, argc, argv );
2354 else if (!strcmp( argv[1], "-callfrom16" ))
2355 res = BuildCallFrom16( outfile, argc, argv );
2356 else if (!strcmp( argv[1], "-callto16" ))
2357 res = BuildCallTo16( outfile, argc, argv );
2358 else if (!strcmp( argv[1], "-callfrom32" ))
2359 res = BuildCallFrom32( outfile, argc, argv );
2360 else if (!strcmp( argv[1], "-callto32" ))
2361 res = BuildCallTo32( outfile, argc, argv );
2362 else
2364 fclose( outfile );
2365 unlink( outname );
2366 usage();
2369 fclose( outfile );
2370 if (res < 0)
2372 unlink( outname );
2373 return 1;
2375 return 0;
2378 #endif /* WINELIB */