Release 970804
[wine/multimedia.git] / tools / build.c
blob6ab1a55fa263796a58e347900cf323ff342620bd
1 /*
2 * Copyright 1993 Robert J. Amstadt
3 * Copyright 1995 Martin von Loewis
4 * Copyright 1995, 1996 Alexandre Julliard
5 * Copyright 1997 Eric Youngdale
6 */
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <ctype.h>
12 #include <unistd.h>
14 #include "windows.h"
15 #include "winnt.h"
16 #include "module.h"
17 #include "neexe.h"
18 #include "selectors.h"
20 #ifdef NEED_UNDERSCORE_PREFIX
21 # define PREFIX "_"
22 #else
23 # define PREFIX
24 #endif
26 #if defined(__GNUC__) && !defined(__svr4__)
27 # define USE_STABS
28 #else
29 # undef USE_STABS
30 #endif
32 typedef enum
34 TYPE_INVALID,
35 TYPE_BYTE, /* byte variable */
36 TYPE_WORD, /* word variable */
37 TYPE_LONG, /* long variable */
38 TYPE_PASCAL_16, /* pascal function with 16-bit return (Win16) */
39 TYPE_PASCAL, /* pascal function with 32-bit return (Win16) */
40 TYPE_REGISTER, /* register function */
41 TYPE_ABS, /* absolute value */
42 TYPE_RETURN, /* simple return value function */
43 TYPE_STUB, /* unimplemented stub */
44 TYPE_STDCALL, /* stdcall function (Win32) */
45 TYPE_CDECL, /* cdecl function (Win32) */
46 TYPE_EXTERN, /* external symbol (Win32) */
47 TYPE_NBTYPES
48 } ORD_TYPE;
50 static const char * const TypeNames[TYPE_NBTYPES] =
52 NULL,
53 "byte", /* TYPE_BYTE */
54 "word", /* TYPE_WORD */
55 "long", /* TYPE_LONG */
56 "pascal16", /* TYPE_PASCAL_16 */
57 "pascal", /* TYPE_PASCAL */
58 "register", /* TYPE_REGISTER */
59 "equate", /* TYPE_ABS */
60 "return", /* TYPE_RETURN */
61 "stub", /* TYPE_STUB */
62 "stdcall", /* TYPE_STDCALL */
63 "cdecl", /* TYPE_CDECL */
64 "extern" /* TYPE_EXTERN */
67 #define MAX_ORDINALS 1299
69 /* Callback function used for stub functions */
70 #define STUB_CALLBACK \
71 ((SpecType == SPEC_WIN16) ? "RELAY_Unimplemented16": "RELAY_Unimplemented32")
73 typedef enum
75 SPEC_INVALID,
76 SPEC_WIN16,
77 SPEC_WIN32
78 } SPEC_TYPE;
80 typedef struct
82 int n_values;
83 int *values;
84 } ORD_VARIABLE;
86 typedef struct
88 int n_args;
89 char arg_types[32];
90 char link_name[80];
91 } ORD_FUNCTION;
93 typedef struct
95 int arg_size;
96 int ret_value;
97 } ORD_RETURN;
99 typedef struct
101 int value;
102 } ORD_ABS;
104 typedef struct
106 char link_name[80];
107 } ORD_EXTERN;
109 typedef struct
111 ORD_TYPE type;
112 int offset;
113 int lineno;
114 char name[80];
115 union
117 ORD_VARIABLE var;
118 ORD_FUNCTION func;
119 ORD_RETURN ret;
120 ORD_ABS abs;
121 ORD_EXTERN ext;
122 } u;
123 } ORDDEF;
125 static ORDDEF OrdinalDefinitions[MAX_ORDINALS];
127 static SPEC_TYPE SpecType = SPEC_INVALID;
128 static char DLLName[80];
129 static char DLLFileName[80];
130 int Limit = 0;
131 int Base = 0;
132 int DLLHeapSize = 0;
133 FILE *SpecFp;
135 char *ParseBuffer = NULL;
136 char *ParseNext;
137 char ParseSaveChar;
138 int Line;
140 static int debugging = 1;
142 /* Offset of register relative to the start of the CONTEXT struct */
143 #define CONTEXTOFFSET(reg) ((int)&((CONTEXT *)0)->reg)
145 static void *xmalloc (size_t size)
147 void *res;
149 res = malloc (size ? size : 1);
150 if (res == NULL)
152 fprintf (stderr, "Virtual memory exhausted.\n");
153 exit (1);
155 return res;
159 static void *xrealloc (void *ptr, size_t size)
161 void *res = realloc (ptr, size);
162 if (res == NULL)
164 fprintf (stderr, "Virtual memory exhausted.\n");
165 exit (1);
167 return res;
171 static int IsNumberString(char *s)
173 while (*s != '\0')
174 if (!isdigit(*s++))
175 return 0;
177 return 1;
180 static char *strupper(char *s)
182 char *p;
184 for(p = s; *p != '\0'; p++)
185 *p = toupper(*p);
187 return s;
190 static char * GetTokenInLine(void)
192 char *p;
193 char *token;
195 if (ParseNext != ParseBuffer)
197 if (ParseSaveChar == '\0')
198 return NULL;
199 *ParseNext = ParseSaveChar;
203 * Remove initial white space.
205 for (p = ParseNext; isspace(*p); p++)
208 if ((*p == '\0') || (*p == '#'))
209 return NULL;
212 * Find end of token.
214 token = p++;
215 if (*token != '(' && *token != ')')
216 while (*p != '\0' && *p != '(' && *p != ')' && !isspace(*p))
217 p++;
219 ParseSaveChar = *p;
220 ParseNext = p;
221 *p = '\0';
223 return token;
226 static char * GetToken(void)
228 char *token;
230 if (ParseBuffer == NULL)
232 ParseBuffer = xmalloc(512);
233 ParseNext = ParseBuffer;
234 Line++;
235 while (1)
237 if (fgets(ParseBuffer, 511, SpecFp) == NULL)
238 return NULL;
239 if (ParseBuffer[0] != '#')
240 break;
244 while ((token = GetTokenInLine()) == NULL)
246 ParseNext = ParseBuffer;
247 Line++;
248 while (1)
250 if (fgets(ParseBuffer, 511, SpecFp) == NULL)
251 return NULL;
252 if (ParseBuffer[0] != '#')
253 break;
257 return token;
261 /*******************************************************************
262 * ParseVariable
264 * Parse a variable definition.
266 static int ParseVariable( ORDDEF *odp )
268 char *endptr;
269 int *value_array;
270 int n_values;
271 int value_array_size;
273 char *token = GetToken();
274 if (*token != '(')
276 fprintf(stderr, "%d: Expected '(' got '%s'\n", Line, token);
277 return -1;
280 n_values = 0;
281 value_array_size = 25;
282 value_array = xmalloc(sizeof(*value_array) * value_array_size);
284 while ((token = GetToken()) != NULL)
286 if (*token == ')')
287 break;
289 value_array[n_values++] = strtol(token, &endptr, 0);
290 if (n_values == value_array_size)
292 value_array_size += 25;
293 value_array = xrealloc(value_array,
294 sizeof(*value_array) * value_array_size);
297 if (endptr == NULL || *endptr != '\0')
299 fprintf(stderr, "%d: Expected number value, got '%s'\n", Line,
300 token);
301 return -1;
305 if (token == NULL)
307 fprintf(stderr, "%d: End of file in variable declaration\n", Line);
308 return -1;
311 odp->u.var.n_values = n_values;
312 odp->u.var.values = xrealloc(value_array, sizeof(*value_array) * n_values);
314 return 0;
318 /*******************************************************************
319 * ParseExportFunction
321 * Parse a function definition.
323 static int ParseExportFunction( ORDDEF *odp )
325 char *token;
326 int i;
328 switch(SpecType)
330 case SPEC_WIN16:
331 if (odp->type == TYPE_STDCALL)
333 fprintf( stderr, "%d: 'stdcall' not supported for Win16\n", Line );
334 return -1;
336 if (odp->type == TYPE_CDECL)
338 fprintf( stderr, "%d: 'cdecl' not supported for Win16\n", Line );
339 return -1;
341 break;
342 case SPEC_WIN32:
343 if ((odp->type == TYPE_PASCAL) || (odp->type == TYPE_PASCAL_16))
345 fprintf( stderr, "%d: 'pascal' not supported for Win32\n", Line );
346 return -1;
348 break;
349 default:
350 break;
353 token = GetToken();
354 if (*token != '(')
356 fprintf(stderr, "%d: Expected '(' got '%s'\n", Line, token);
357 return -1;
360 for (i = 0; i < sizeof(odp->u.func.arg_types)-1; i++)
362 token = GetToken();
363 if (*token == ')')
364 break;
366 if (!strcmp(token, "byte") || !strcmp(token, "word"))
367 odp->u.func.arg_types[i] = 'w';
368 else if (!strcmp(token, "s_byte") || !strcmp(token, "s_word"))
369 odp->u.func.arg_types[i] = 's';
370 else if (!strcmp(token, "long") || !strcmp(token, "segptr"))
371 odp->u.func.arg_types[i] = 'l';
372 else if (!strcmp(token, "ptr"))
373 odp->u.func.arg_types[i] = 'p';
374 else if (!strcmp(token, "str"))
375 odp->u.func.arg_types[i] = 't';
376 else if (!strcmp(token, "segstr"))
377 odp->u.func.arg_types[i] = 'T';
378 else
380 fprintf(stderr, "%d: Unknown variable type '%s'\n", Line, token);
381 return -1;
383 if (SpecType == SPEC_WIN32)
385 if (strcmp(token, "long") && strcmp(token, "ptr"))
387 fprintf( stderr, "%d: Type '%s' not supported for Win32\n",
388 Line, token );
389 return -1;
393 if (*token != ')')
395 fprintf( stderr, "%d: Too many arguments\n", Line );
396 return -1;
398 odp->u.func.arg_types[i] = '\0';
399 if ((odp->type == TYPE_STDCALL) && !i)
400 odp->type = TYPE_CDECL; /* stdcall is the same as cdecl for 0 args */
401 strcpy(odp->u.func.link_name, GetToken());
402 return 0;
406 /*******************************************************************
407 * ParseEquate
409 * Parse an 'equate' definition.
411 static int ParseEquate( ORDDEF *odp )
413 char *endptr;
415 char *token = GetToken();
416 int value = strtol(token, &endptr, 0);
417 if (endptr == NULL || *endptr != '\0')
419 fprintf(stderr, "%d: Expected number value, got '%s'\n", Line,
420 token);
421 return -1;
424 odp->u.abs.value = value;
425 return 0;
429 /*******************************************************************
430 * ParseReturn
432 * Parse a 'return' definition.
434 static int ParseReturn( ORDDEF *odp )
436 char *token;
437 char *endptr;
439 token = GetToken();
440 odp->u.ret.arg_size = strtol(token, &endptr, 0);
441 if (endptr == NULL || *endptr != '\0')
443 fprintf(stderr, "%d: Expected number value, got '%s'\n", Line,
444 token);
445 return -1;
448 token = GetToken();
449 odp->u.ret.ret_value = strtol(token, &endptr, 0);
450 if (endptr == NULL || *endptr != '\0')
452 fprintf(stderr, "%d: Expected number value, got '%s'\n", Line,
453 token);
454 return -1;
457 return 0;
461 /*******************************************************************
462 * ParseStub
464 * Parse a 'stub' definition.
466 static int ParseStub( ORDDEF *odp )
468 odp->u.func.arg_types[0] = '\0';
469 strcpy( odp->u.func.link_name, STUB_CALLBACK );
470 return 0;
474 /*******************************************************************
475 * ParseExtern
477 * Parse an 'extern' definition.
479 static int ParseExtern( ORDDEF *odp )
481 if (SpecType == SPEC_WIN16)
483 fprintf( stderr, "%d: 'extern' not supported for Win16\n", Line );
484 return -1;
486 strcpy( odp->u.ext.link_name, GetToken() );
487 return 0;
491 /*******************************************************************
492 * ParseOrdinal
494 * Parse an ordinal definition.
496 static int ParseOrdinal(int ordinal)
498 ORDDEF *odp;
499 char *token;
501 if (ordinal >= MAX_ORDINALS)
503 fprintf(stderr, "%d: Ordinal number too large\n", Line);
504 return -1;
506 if (ordinal > Limit) Limit = ordinal;
508 odp = &OrdinalDefinitions[ordinal];
509 if (!(token = GetToken()))
511 fprintf(stderr, "%d: Expected type after ordinal\n", Line);
512 return -1;
515 for (odp->type = 0; odp->type < TYPE_NBTYPES; odp->type++)
516 if (TypeNames[odp->type] && !strcmp( token, TypeNames[odp->type] ))
517 break;
519 if (odp->type >= TYPE_NBTYPES)
521 fprintf( stderr,
522 "%d: Expected type after ordinal, found '%s' instead\n",
523 Line, token );
524 return -1;
527 if (!(token = GetToken()))
529 fprintf( stderr, "%d: Expected name after type\n", Line );
530 return -1;
532 strcpy( odp->name, token );
533 odp->lineno = Line;
535 switch(odp->type)
537 case TYPE_BYTE:
538 case TYPE_WORD:
539 case TYPE_LONG:
540 return ParseVariable( odp );
541 case TYPE_PASCAL_16:
542 case TYPE_PASCAL:
543 case TYPE_REGISTER:
544 case TYPE_STDCALL:
545 case TYPE_CDECL:
546 return ParseExportFunction( odp );
547 case TYPE_ABS:
548 return ParseEquate( odp );
549 case TYPE_RETURN:
550 return ParseReturn( odp );
551 case TYPE_STUB:
552 return ParseStub( odp );
553 case TYPE_EXTERN:
554 return ParseExtern( odp );
555 default:
556 fprintf( stderr, "Should not happen\n" );
557 return -1;
562 /*******************************************************************
563 * ParseTopLevel
565 * Parse a spec file.
567 static int ParseTopLevel(void)
569 char *token;
571 while ((token = GetToken()) != NULL)
573 if (strcmp(token, "name") == 0)
575 strcpy(DLLName, GetToken());
576 strupper(DLLName);
577 if (!DLLFileName[0]) sprintf( DLLFileName, "%s.DLL", DLLName );
579 else if (strcmp(token, "file") == 0)
581 strcpy(DLLFileName, GetToken());
582 strupper(DLLFileName);
584 else if (strcmp(token, "type") == 0)
586 token = GetToken();
587 if (!strcmp(token, "win16" )) SpecType = SPEC_WIN16;
588 else if (!strcmp(token, "win32" )) SpecType = SPEC_WIN32;
589 else
591 fprintf(stderr, "%d: Type must be 'win16' or 'win32'\n", Line);
592 return -1;
595 else if (strcmp(token, "base") == 0)
597 token = GetToken();
598 if (!IsNumberString(token))
600 fprintf(stderr, "%d: Expected number after base\n", Line);
601 return -1;
603 Base = atoi(token);
605 else if (strcmp(token, "heap") == 0)
607 token = GetToken();
608 if (!IsNumberString(token))
610 fprintf(stderr, "%d: Expected number after heap\n", Line);
611 return -1;
613 DLLHeapSize = atoi(token);
615 else if (IsNumberString(token))
617 int ordinal;
618 int rv;
620 ordinal = atoi(token);
621 if ((rv = ParseOrdinal(ordinal)) < 0)
622 return rv;
624 else
626 fprintf(stderr,
627 "%d: Expected name, id, length or ordinal\n", Line);
628 return -1;
632 return 0;
636 /*******************************************************************
637 * StoreVariableCode
639 * Store a list of ints into a byte array.
641 static int StoreVariableCode( unsigned char *buffer, int size, ORDDEF *odp )
643 int i;
645 switch(size)
647 case 1:
648 for (i = 0; i < odp->u.var.n_values; i++)
649 buffer[i] = odp->u.var.values[i];
650 break;
651 case 2:
652 for (i = 0; i < odp->u.var.n_values; i++)
653 ((unsigned short *)buffer)[i] = odp->u.var.values[i];
654 break;
655 case 4:
656 for (i = 0; i < odp->u.var.n_values; i++)
657 ((unsigned int *)buffer)[i] = odp->u.var.values[i];
658 break;
660 return odp->u.var.n_values * size;
664 /*******************************************************************
665 * DumpBytes
667 * Dump a byte stream into the assembly code.
669 static void DumpBytes( FILE *outfile, const unsigned char *data, int len,
670 const char *section, const char *label_start )
672 int i;
673 if (section) fprintf( outfile, "\t%s\n", section );
674 if (label_start) fprintf( outfile, "%s:\n", label_start );
675 for (i = 0; i < len; i++)
677 if (!(i & 0x0f)) fprintf( outfile, "\t.byte " );
678 fprintf( outfile, "%d", *data++ );
679 if (i < len - 1)
680 fprintf( outfile, "%c", ((i & 0x0f) != 0x0f) ? ',' : '\n' );
682 fprintf( outfile, "\n" );
686 /*******************************************************************
687 * BuildModule16
689 * Build the in-memory representation of a 16-bit NE module, and dump it
690 * as a byte stream into the assembly code.
692 static int BuildModule16( FILE *outfile, int max_code_offset,
693 int max_data_offset )
695 ORDDEF *odp;
696 int i;
697 char *buffer;
698 NE_MODULE *pModule;
699 SEGTABLEENTRY *pSegment;
700 OFSTRUCT *pFileInfo;
701 BYTE *pstr, *bundle;
702 WORD *pword;
704 /* Module layout:
705 * NE_MODULE Module
706 * OFSTRUCT File information
707 * SEGTABLEENTRY Segment 1 (code)
708 * SEGTABLEENTRY Segment 2 (data)
709 * WORD[2] Resource table (empty)
710 * BYTE[2] Imported names (empty)
711 * BYTE[n] Resident names table
712 * BYTE[n] Entry table
715 buffer = xmalloc( 0x10000 );
717 pModule = (NE_MODULE *)buffer;
718 pModule->magic = IMAGE_OS2_SIGNATURE;
719 pModule->count = 1;
720 pModule->next = 0;
721 pModule->flags = NE_FFLAGS_SINGLEDATA | NE_FFLAGS_BUILTIN | NE_FFLAGS_LIBMODULE;
722 pModule->dgroup = 2;
723 pModule->heap_size = DLLHeapSize;
724 pModule->stack_size = 0;
725 pModule->ip = 0;
726 pModule->cs = 0;
727 pModule->sp = 0;
728 pModule->ss = 0;
729 pModule->seg_count = 2;
730 pModule->modref_count = 0;
731 pModule->nrname_size = 0;
732 pModule->modref_table = 0;
733 pModule->nrname_fpos = 0;
734 pModule->moveable_entries = 0;
735 pModule->alignment = 0;
736 pModule->truetype = 0;
737 pModule->os_flags = NE_OSFLAGS_WINDOWS;
738 pModule->misc_flags = 0;
739 pModule->dlls_to_init = 0;
740 pModule->nrname_handle = 0;
741 pModule->min_swap_area = 0;
742 pModule->expected_version = 0x030a;
743 pModule->pe_module = NULL;
744 pModule->self = 0;
745 pModule->self_loading_sel = 0;
747 /* File information */
749 pFileInfo = (OFSTRUCT *)(pModule + 1);
750 pModule->fileinfo = (int)pFileInfo - (int)pModule;
751 memset( pFileInfo, 0, sizeof(*pFileInfo) - sizeof(pFileInfo->szPathName) );
752 pFileInfo->cBytes = sizeof(*pFileInfo) - sizeof(pFileInfo->szPathName)
753 + strlen(DLLFileName);
754 strcpy( pFileInfo->szPathName, DLLFileName );
755 pstr = (char *)pFileInfo + pFileInfo->cBytes + 1;
757 /* Segment table */
759 pSegment = (SEGTABLEENTRY *)pstr;
760 pModule->seg_table = (int)pSegment - (int)pModule;
761 pSegment->filepos = 0;
762 pSegment->size = max_code_offset;
763 pSegment->flags = 0;
764 pSegment->minsize = max_code_offset;
765 pSegment->selector = 0;
766 pSegment++;
768 pModule->dgroup_entry = (int)pSegment - (int)pModule;
769 pSegment->filepos = 0;
770 pSegment->size = max_data_offset;
771 pSegment->flags = NE_SEGFLAGS_DATA;
772 pSegment->minsize = max_data_offset;
773 pSegment->selector = 0;
774 pSegment++;
776 /* Resource table */
778 pword = (WORD *)pSegment;
779 pModule->res_table = (int)pword - (int)pModule;
780 *pword++ = 0;
781 *pword++ = 0;
783 /* Imported names table */
785 pstr = (char *)pword;
786 pModule->import_table = (int)pstr - (int)pModule;
787 *pstr++ = 0;
788 *pstr++ = 0;
790 /* Resident names table */
792 pModule->name_table = (int)pstr - (int)pModule;
793 /* First entry is module name */
794 *pstr = strlen(DLLName );
795 strcpy( pstr + 1, DLLName );
796 pstr += *pstr + 1;
797 *(WORD *)pstr = 0;
798 pstr += sizeof(WORD);
799 /* Store all ordinals */
800 odp = OrdinalDefinitions + 1;
801 for (i = 1; i <= Limit; i++, odp++)
803 if (!odp->name[0]) continue;
804 *pstr = strlen( odp->name );
805 strcpy( pstr + 1, odp->name );
806 strupper( pstr + 1 );
807 pstr += *pstr + 1;
808 *(WORD *)pstr = i;
809 pstr += sizeof(WORD);
811 *pstr++ = 0;
813 /* Entry table */
815 pModule->entry_table = (int)pstr - (int)pModule;
816 bundle = NULL;
817 odp = OrdinalDefinitions + 1;
818 for (i = 1; i <= Limit; i++, odp++)
820 int selector = 0;
822 switch (odp->type)
824 case TYPE_PASCAL:
825 case TYPE_PASCAL_16:
826 case TYPE_REGISTER:
827 case TYPE_RETURN:
828 case TYPE_STUB:
829 selector = 1; /* Code selector */
830 break;
832 case TYPE_BYTE:
833 case TYPE_WORD:
834 case TYPE_LONG:
835 selector = 2; /* Data selector */
836 break;
838 case TYPE_ABS:
839 selector = 0xfe; /* Constant selector */
840 break;
842 default:
843 selector = 0; /* Invalid selector */
844 break;
847 /* create a new bundle if necessary */
848 if (!bundle || (bundle[0] >= 254) || (bundle[1] != selector))
850 bundle = pstr;
851 bundle[0] = 0;
852 bundle[1] = selector;
853 pstr += 2;
856 (*bundle)++;
857 if (selector != 0)
859 *pstr++ = 1;
860 *(WORD *)pstr = odp->offset;
861 pstr += sizeof(WORD);
864 *pstr++ = 0;
866 /* Dump the module content */
868 DumpBytes( outfile, (char *)pModule, (int)pstr - (int)pModule,
869 ".data", "Module_Start" );
870 return (int)pstr - (int)pModule;
874 /*******************************************************************
875 * BuildModule32
877 * Build the in-memory representation of a 32-bit pseudo-NE module, and dump it
878 * as a byte stream into the assembly code.
880 static int BuildModule32( FILE *outfile )
882 char *buffer;
883 NE_MODULE *pModule;
884 OFSTRUCT *pFileInfo;
885 BYTE *pstr;
886 WORD *pword;
888 /* Module layout:
889 * NE_MODULE Module
890 * OFSTRUCT File information
891 * SEGTABLEENTRY Segment table (empty)
892 * WORD[2] Resource table (empty)
893 * BYTE[2] Imported names (empty)
894 * BYTE[n] Resident names table (1 entry)
895 * BYTE[n] Entry table (empty)
898 buffer = xmalloc( 0x10000 );
900 pModule = (NE_MODULE *)buffer;
901 pModule->magic = IMAGE_OS2_SIGNATURE;
902 pModule->count = 1;
903 pModule->next = 0;
904 pModule->dgroup_entry = 0;
905 pModule->flags = NE_FFLAGS_SINGLEDATA | NE_FFLAGS_BUILTIN |
906 NE_FFLAGS_LIBMODULE | NE_FFLAGS_WIN32;
907 pModule->dgroup = 0;
908 pModule->heap_size = DLLHeapSize;
909 pModule->stack_size = 0;
910 pModule->ip = 0;
911 pModule->cs = 0;
912 pModule->sp = 0;
913 pModule->ss = 0;
914 pModule->seg_count = 0;
915 pModule->modref_count = 0;
916 pModule->nrname_size = 0;
917 pModule->modref_table = 0;
918 pModule->nrname_fpos = 0;
919 pModule->moveable_entries = 0;
920 pModule->alignment = 0;
921 pModule->truetype = 0;
922 pModule->os_flags = NE_OSFLAGS_WINDOWS;
923 pModule->misc_flags = 0;
924 pModule->dlls_to_init = 0;
925 pModule->nrname_handle = 0;
926 pModule->min_swap_area = 0;
927 pModule->expected_version = 0x030a;
928 pModule->pe_module = NULL;
929 pModule->self = 0;
930 pModule->self_loading_sel = 0;
932 /* File information */
934 pFileInfo = (OFSTRUCT *)(pModule + 1);
935 pModule->fileinfo = (int)pFileInfo - (int)pModule;
936 memset( pFileInfo, 0, sizeof(*pFileInfo) - sizeof(pFileInfo->szPathName) );
937 pFileInfo->cBytes = sizeof(*pFileInfo) - sizeof(pFileInfo->szPathName)
938 + strlen(DLLFileName);
939 strcpy( pFileInfo->szPathName, DLLFileName );
940 pstr = (char *)pFileInfo + pFileInfo->cBytes + 1;
942 /* Segment table */
944 pModule->seg_table = (int)pstr - (int)pModule;
946 /* Resource table */
948 pword = (WORD *)pstr;
949 pModule->res_table = (int)pword - (int)pModule;
950 *pword++ = 0;
951 *pword++ = 0;
953 /* Imported names table */
955 pstr = (char *)pword;
956 pModule->import_table = (int)pstr - (int)pModule;
957 *pstr++ = 0;
958 *pstr++ = 0;
960 /* Resident names table */
962 pModule->name_table = (int)pstr - (int)pModule;
963 /* First entry is module name */
964 *pstr = strlen(DLLName );
965 strcpy( pstr + 1, DLLName );
966 pstr += *pstr + 1;
967 *(WORD *)pstr = 0;
968 pstr += sizeof(WORD);
969 *pstr++ = 0;
971 /* Entry table */
973 pModule->entry_table = (int)pstr - (int)pModule;
974 *pstr++ = 0;
976 /* Dump the module content */
978 DumpBytes( outfile, (char *)pModule, (int)pstr - (int)pModule,
979 ".data", "Module_Start" );
980 return (int)pstr - (int)pModule;
984 /*******************************************************************
985 * BuildSpec32File
987 * Build a Win32 assembly file from a spec file.
989 static int BuildSpec32File( char * specfile, FILE *outfile )
991 ORDDEF *odp;
992 int i, module_size, len;
993 char buffer[1024];
995 fprintf( outfile, "/* File generated automatically; do not edit! */\n" );
996 fprintf( outfile, "\t.file\t\"%s\"\n", specfile );
997 #ifdef USE_STABS
998 getcwd(buffer, sizeof(buffer));
1001 * The stabs help the internal debugger as they are an indication that it
1002 * is sensible to step into a thunk/trampoline.
1004 fprintf( outfile, ".stabs \"%s/\",100,0,0,Code_Start\n", buffer);
1005 fprintf( outfile, ".stabs \"%s\",100,0,0,Code_Start\n", specfile);
1006 #endif
1008 fprintf( outfile, "\t.text\n" );
1009 fprintf( outfile, "\t.align 4\n" );
1010 fprintf( outfile, "Code_Start:\n\n" );
1012 odp = OrdinalDefinitions;
1013 for (i = 0; i <= Limit; i++, odp++)
1015 switch (odp->type)
1017 case TYPE_INVALID:
1018 break;
1020 case TYPE_STDCALL:
1021 case TYPE_CDECL:
1022 case TYPE_STUB:
1023 case TYPE_REGISTER:
1024 fprintf( outfile, "/* %s.%d (%s) */\n", DLLName, i, odp->name);
1025 #ifdef USE_STABS
1026 fprintf( outfile, ".stabs \"%s_%d:F1\",36,0,%d,%s_%d\n",
1027 DLLName, i, odp->lineno, DLLName, i);
1028 #endif
1029 fprintf( outfile, "%s_%d:\n", DLLName, i );
1030 #ifdef USE_STABS
1031 fprintf( outfile, ".stabn 68,0,%d,0\n", odp->lineno);
1032 #endif
1033 fprintf( outfile, "\tpushl %%ebp\n" );
1034 fprintf( outfile, "\tpushl $" PREFIX "%s\n",odp->u.func.link_name);
1035 fprintf( outfile, "\tcall " PREFIX "CallFrom32_%s_%d\n",
1036 (odp->type == TYPE_REGISTER) ? "regs" :
1037 ((odp->type == TYPE_STDCALL) ? "stdcall" : "cdecl"),
1038 strlen(odp->u.func.arg_types));
1039 fprintf( outfile, "\tnop\n" );
1040 break;
1042 case TYPE_RETURN:
1043 fprintf( outfile, "/* %s.%d (%s) */\n", DLLName, i, odp->name);
1044 #ifdef USE_STABS
1045 fprintf( outfile, ".stabs \"%s_%d:F1\",36,0,%d,%s_%d\n",
1046 DLLName, i, odp->lineno, DLLName, i);
1047 #endif
1048 fprintf( outfile, "%s_%d:\n", DLLName, i );
1049 #ifdef USE_STABS
1050 fprintf( outfile, ".stabn 68,0,%d,0\n", odp->lineno);
1051 #endif
1052 fprintf( outfile, "\tmovl $%d,%%eax\n", odp->u.ret.ret_value );
1053 if (odp->u.ret.arg_size)
1055 fprintf( outfile, "\tret $%d\n", odp->u.ret.arg_size );
1057 else
1059 fprintf( outfile, "\tret\n" );
1060 fprintf( outfile, "\tnop\n" );
1061 fprintf( outfile, "\tnop\n" );
1063 break;
1065 case TYPE_BYTE:
1066 fprintf( outfile, "/* %s.%d (%s) */\n", DLLName, i, odp->name);
1067 fprintf( outfile, "\t.data\n" );
1068 fprintf( outfile, "%s_%d:\n", DLLName, i );
1069 len = StoreVariableCode( buffer, 1, odp );
1070 DumpBytes( outfile, buffer, len, NULL, NULL );
1071 fprintf( outfile, "\t.text\n" );
1072 break;
1074 case TYPE_WORD:
1075 fprintf( outfile, "/* %s.%d (%s) */\n",
1076 DLLName, i, odp->name);
1077 fprintf( outfile, "\t.data\n" );
1078 fprintf( outfile, "%s_%d:\n", DLLName, i );
1079 len = StoreVariableCode( buffer, 2, odp );
1080 DumpBytes( outfile, buffer, len, NULL, NULL );
1081 fprintf( outfile, "\t.text\n" );
1082 break;
1084 case TYPE_LONG:
1085 fprintf( outfile, "/* %s.%d (%s) */\n",
1086 DLLName, i, odp->name);
1087 fprintf( outfile, "\t.data\n" );
1088 fprintf( outfile, "%s_%d:\n", DLLName, i );
1089 len = StoreVariableCode( buffer, 4, odp );
1090 DumpBytes( outfile, buffer, len, NULL, NULL );
1091 fprintf( outfile, "\t.text\n" );
1092 break;
1094 case TYPE_EXTERN:
1095 break;
1097 default:
1098 fprintf(stderr,"build: function type %d not available for Win32\n",
1099 odp->type);
1100 return -1;
1104 module_size = BuildModule32( outfile );
1106 /* Output the DLL functions table */
1108 fprintf( outfile, "\t.text\n" );
1109 fprintf( outfile, "\t.align 4\n" );
1110 fprintf( outfile, "Functions:\n" );
1111 odp = OrdinalDefinitions;
1112 for (i = 0; i <= Limit; i++, odp++)
1114 switch(odp->type)
1116 case TYPE_INVALID:
1117 fprintf( outfile, "\t.long 0\n" );
1118 break;
1119 case TYPE_EXTERN:
1120 fprintf( outfile, "\t.long " PREFIX "%s\n", odp->u.ext.link_name );
1121 break;
1122 default:
1123 fprintf( outfile, "\t.long %s_%d\n", DLLName, i );
1124 break;
1128 /* Output the DLL names table */
1130 fprintf( outfile, "FuncNames:\n" );
1131 odp = OrdinalDefinitions;
1132 for (i = 0; i <= Limit; i++, odp++)
1134 if (odp->type == TYPE_INVALID) fprintf( outfile, "\t.long 0\n" );
1135 else fprintf( outfile, "\t.long Name_%d\n", i );
1138 /* Output the DLL names */
1140 for (i = 0, odp = OrdinalDefinitions; i <= Limit; i++, odp++)
1142 if (odp->type != TYPE_INVALID)
1143 fprintf( outfile, "Name_%d:\t.ascii \"%s\\0\"\n", i, odp->name );
1146 /* Output the DLL descriptor */
1148 fprintf( outfile, "DLLName:\t.ascii \"%s\\0\"\n", DLLName );
1149 fprintf( outfile, "\t.align 4\n" );
1150 fprintf( outfile, "\t.globl " PREFIX "%s_Descriptor\n", DLLName );
1151 fprintf( outfile, PREFIX "%s_Descriptor:\n", DLLName );
1152 fprintf( outfile, "\t.long DLLName\n" ); /* Name */
1153 fprintf( outfile, "\t.long Module_Start\n" ); /* Module start */
1154 fprintf( outfile, "\t.long %d\n", module_size ); /* Module size */
1155 fprintf( outfile, "\t.long %d\n", Base ); /* Base */
1156 fprintf( outfile, "\t.long %d\n", Limit+1 ); /* Size */
1157 fprintf( outfile, "\t.long Code_Start\n" ); /* Code start */
1158 fprintf( outfile, "\t.long Functions\n" ); /* Functions */
1159 fprintf( outfile, "\t.long FuncNames\n" ); /* Function names */
1160 #ifdef USE_STABS
1161 fprintf( outfile, "\t.text\n");
1162 fprintf( outfile, "\t.stabs \"\",100,0,0,.Letext\n");
1163 fprintf( outfile, ".Letext:\n");
1164 #endif
1165 return 0;
1169 /*******************************************************************
1170 * BuildSpec16File
1172 * Build a Win16 assembly file from a spec file.
1174 static int BuildSpec16File( char * specfile, FILE *outfile )
1176 ORDDEF *odp;
1177 int i;
1178 int code_offset, data_offset, module_size;
1179 unsigned char *data;
1181 data = (unsigned char *)xmalloc( 0x10000 );
1182 memset( data, 0, 16 );
1183 data_offset = 16;
1185 fprintf( outfile, "/* File generated automatically; do not edit! */\n" );
1186 fprintf( outfile, "\t.text\n" );
1187 fprintf( outfile, "Code_Start:\n" );
1188 code_offset = 0;
1190 odp = OrdinalDefinitions;
1191 for (i = 0; i <= Limit; i++, odp++)
1193 switch (odp->type)
1195 case TYPE_INVALID:
1196 odp->offset = 0xffff;
1197 break;
1199 case TYPE_ABS:
1200 odp->offset = LOWORD(odp->u.abs.value);
1201 break;
1203 case TYPE_BYTE:
1204 odp->offset = data_offset;
1205 data_offset += StoreVariableCode( data + data_offset, 1, odp);
1206 break;
1208 case TYPE_WORD:
1209 odp->offset = data_offset;
1210 data_offset += StoreVariableCode( data + data_offset, 2, odp);
1211 break;
1213 case TYPE_LONG:
1214 odp->offset = data_offset;
1215 data_offset += StoreVariableCode( data + data_offset, 4, odp);
1216 break;
1218 case TYPE_RETURN:
1219 fprintf( outfile,"/* %s.%d */\n", DLLName, i);
1220 fprintf( outfile,"\tmovw $%d,%%ax\n",LOWORD(odp->u.ret.ret_value));
1221 fprintf( outfile,"\tmovw $%d,%%dx\n",HIWORD(odp->u.ret.ret_value));
1222 fprintf( outfile,"\t.byte 0x66\n");
1223 if (odp->u.ret.arg_size != 0)
1224 fprintf( outfile, "\tlret $%d\n\n", odp->u.ret.arg_size);
1225 else
1227 fprintf( outfile, "\tlret\n");
1228 fprintf( outfile, "\tnop\n");
1229 fprintf( outfile, "\tnop\n\n");
1231 odp->offset = code_offset;
1232 code_offset += 12; /* Assembly code is 12 bytes long */
1233 break;
1235 case TYPE_REGISTER:
1236 case TYPE_PASCAL:
1237 case TYPE_PASCAL_16:
1238 case TYPE_STUB:
1239 fprintf( outfile, "/* %s.%d */\n", DLLName, i);
1240 fprintf( outfile, "\tpushw %%bp\n" );
1241 fprintf( outfile, "\tpushl $" PREFIX "%s\n",odp->u.func.link_name);
1242 /* FreeBSD does not understand lcall, so do it the hard way */
1243 fprintf( outfile, "\t.byte 0x9a\n" );
1244 fprintf( outfile, "\t.long " PREFIX "CallFrom16_%s_%s\n",
1245 (odp->type == TYPE_REGISTER) ? "regs" :
1246 (odp->type == TYPE_PASCAL) ? "long" : "word",
1247 odp->u.func.arg_types );
1248 fprintf( outfile,"\t.byte 0x%02x,0x%02x\n", /* Some asms don't have .word */
1249 LOBYTE(WINE_CODE_SELECTOR), HIBYTE(WINE_CODE_SELECTOR) );
1250 fprintf( outfile, "\tnop\n" );
1251 fprintf( outfile, "\tnop\n\n" );
1252 odp->offset = code_offset;
1253 code_offset += 16; /* Assembly code is 16 bytes long */
1254 break;
1256 default:
1257 fprintf(stderr,"build: function type %d not available for Win16\n",
1258 odp->type);
1259 return -1;
1263 if (!code_offset) /* Make sure the code segment is not empty */
1265 fprintf( outfile, "\t.byte 0\n" );
1266 code_offset++;
1269 /* Output data segment */
1271 DumpBytes( outfile, data, data_offset, NULL, "Data_Start" );
1273 /* Build the module */
1275 module_size = BuildModule16( outfile, code_offset, data_offset );
1277 /* Output the DLL descriptor */
1279 fprintf( outfile, "\t.text\n" );
1280 fprintf( outfile, "DLLName:\t.ascii \"%s\\0\"\n", DLLName );
1281 fprintf( outfile, "\t.align 4\n" );
1282 fprintf( outfile, "\t.globl " PREFIX "%s_Descriptor\n", DLLName );
1283 fprintf( outfile, PREFIX "%s_Descriptor:\n", DLLName );
1284 fprintf( outfile, "\t.long DLLName\n" ); /* Name */
1285 fprintf( outfile, "\t.long Module_Start\n" ); /* Module start */
1286 fprintf( outfile, "\t.long %d\n", module_size ); /* Module size */
1287 fprintf( outfile, "\t.long Code_Start\n" ); /* Code start */
1288 fprintf( outfile, "\t.long Data_Start\n" ); /* Data start */
1289 return 0;
1293 /*******************************************************************
1294 * BuildSpecFile
1296 * Build an assembly file from a spec file.
1298 static int BuildSpecFile( FILE *outfile, char *specname )
1300 SpecFp = fopen( specname, "r");
1301 if (SpecFp == NULL)
1303 fprintf(stderr, "Could not open specification file, '%s'\n", specname);
1304 return -1;
1307 if (ParseTopLevel() < 0) return -1;
1309 switch(SpecType)
1311 case SPEC_WIN16:
1312 return BuildSpec16File( specname, outfile );
1313 case SPEC_WIN32:
1314 return BuildSpec32File( specname, outfile );
1315 default:
1316 fprintf( stderr, "%s: Missing 'type' declaration\n", specname );
1317 return -1;
1322 /*******************************************************************
1323 * BuildCall32LargeStack
1325 * Build the function used to switch to the original 32-bit stack
1326 * before calling a 32-bit function from 32-bit code. This is used for
1327 * functions that need a large stack, like X bitmaps functions.
1329 * The generated function has the following prototype:
1330 * int CallTo32_LargeStack( int (*func)(), int nbargs, ... )
1332 * Stack layout:
1333 * ... ...
1334 * (ebp+20) arg2
1335 * (ebp+16) arg1
1336 * (ebp+12) nbargs
1337 * (ebp+8) func
1338 * (ebp+4) ret addr
1339 * (ebp) ebp
1341 static void BuildCall32LargeStack( FILE *outfile )
1343 /* Function header */
1345 fprintf( outfile, "\n\t.align 4\n" );
1346 #ifdef USE_STABS
1347 fprintf( outfile, ".stabs \"CallTo32_LargeStack:F1\",36,0,0," PREFIX "CallTo32_LargeStack\n");
1348 #endif
1349 fprintf( outfile, "\t.globl " PREFIX "CallTo32_LargeStack\n" );
1350 fprintf( outfile, PREFIX "CallTo32_LargeStack:\n" );
1352 /* Entry code */
1354 fprintf( outfile, "\tpushl %%ebp\n" );
1355 fprintf( outfile, "\tmovl %%esp,%%ebp\n" );
1357 /* Save registers */
1359 fprintf( outfile, "\tpushl %%ecx\n" );
1360 fprintf( outfile, "\tpushl %%esi\n" );
1361 fprintf( outfile, "\tpushl %%edi\n" );
1363 /* Retrieve the original 32-bit stack pointer and switch to it if any */
1365 fprintf( outfile, "\tmovl " PREFIX "IF1632_Original32_esp, %%eax\n" );
1366 fprintf( outfile, "\torl %%eax,%%eax\n" );
1367 fprintf( outfile, "\tje no_orig_esp\n" );
1368 fprintf( outfile, "\tmovl %%eax,%%esp\n" );
1369 fprintf( outfile, "no_orig_esp:\n" );
1371 /* Transfer the arguments */
1373 fprintf( outfile, "\tmovl 12(%%ebp),%%ecx\n" );
1374 fprintf( outfile, "\torl %%ecx,%%ecx\n" );
1375 fprintf( outfile, "\tje no_args\n" );
1376 fprintf( outfile, "\tleal 16(%%ebp),%%esi\n" );
1377 fprintf( outfile, "\tshll $2,%%ecx\n" );
1378 fprintf( outfile, "\tsubl %%ecx,%%esp\n" );
1379 fprintf( outfile, "\tmovl %%esp,%%edi\n" );
1380 fprintf( outfile, "\tshrl $2,%%ecx\n" );
1381 fprintf( outfile, "\tcld\n" );
1382 fprintf( outfile, "\trep; movsl\n" );
1383 fprintf( outfile, "no_args:\n" );
1385 /* Call the function */
1387 fprintf( outfile, "\tcall 8(%%ebp)\n" );
1389 /* Switch back to the normal stack */
1391 fprintf( outfile, "\tleal -12(%%ebp),%%esp\n" );
1393 /* Restore registers and return */
1395 fprintf( outfile, "\tpopl %%edi\n" );
1396 fprintf( outfile, "\tpopl %%esi\n" );
1397 fprintf( outfile, "\tpopl %%ecx\n" );
1398 fprintf( outfile, "\tpopl %%ebp\n" );
1399 fprintf( outfile, "\tret\n" );
1403 /*******************************************************************
1404 * TransferArgs16To32
1406 * Get the arguments from the 16-bit stack and push them on the 32-bit stack.
1407 * The 16-bit stack layout is:
1408 * ... ...
1409 * (bp+8) arg2
1410 * (bp+6) arg1
1411 * (bp+4) cs
1412 * (bp+2) ip
1413 * (bp) bp
1415 static int TransferArgs16To32( FILE *outfile, char *args )
1417 int i, pos16, pos32;
1419 /* Save ebx first */
1421 fprintf( outfile, "\tpushl %%ebx\n" );
1423 /* Get the 32-bit stack pointer */
1425 fprintf( outfile, "\tmovl " PREFIX "IF1632_Saved32_esp,%%ebx\n" );
1427 /* Copy the arguments */
1429 pos16 = 6; /* skip bp and return address */
1430 pos32 = 0;
1432 for (i = strlen(args); i > 0; i--)
1434 pos32 -= 4;
1435 switch(args[i-1])
1437 case 'w': /* word */
1438 fprintf( outfile, "\tmovzwl %d(%%ebp),%%eax\n", pos16 );
1439 fprintf( outfile, "\tmovl %%eax,%d(%%ebx)\n", pos32 );
1440 pos16 += 2;
1441 break;
1443 case 's': /* s_word */
1444 fprintf( outfile, "\tmovswl %d(%%ebp),%%eax\n", pos16 );
1445 fprintf( outfile, "\tmovl %%eax,%d(%%ebx)\n", pos32 );
1446 pos16 += 2;
1447 break;
1449 case 'l': /* long or segmented pointer */
1450 case 'T': /* segmented pointer to null-terminated string */
1451 fprintf( outfile, "\tmovl %d(%%ebp),%%eax\n", pos16 );
1452 fprintf( outfile, "\tmovl %%eax,%d(%%ebx)\n", pos32 );
1453 pos16 += 4;
1454 break;
1456 case 'p': /* linear pointer */
1457 case 't': /* linear pointer to null-terminated string */
1458 /* Get the selector */
1459 fprintf( outfile, "\tmovw %d(%%ebp),%%ax\n", pos16 + 2 );
1460 /* Get the selector base */
1461 fprintf( outfile, "\tandl $0xfff8,%%eax\n" );
1462 fprintf( outfile, "\tmovl " PREFIX "ldt_copy(%%eax),%%eax\n" );
1463 fprintf( outfile, "\tmovl %%eax,%d(%%ebx)\n", pos32 );
1464 /* Add the offset */
1465 fprintf( outfile, "\tmovzwl %d(%%ebp),%%eax\n", pos16 );
1466 fprintf( outfile, "\taddl %%eax,%d(%%ebx)\n", pos32 );
1467 pos16 += 4;
1468 break;
1470 default:
1471 fprintf( stderr, "Unknown arg type '%c'\n", args[i-1] );
1475 /* Restore ebx */
1477 fprintf( outfile, "\tpopl %%ebx\n" );
1479 return pos16 - 6; /* Return the size of the 16-bit args */
1483 /*******************************************************************
1484 * BuildContext16
1486 * Build the context structure on the 32-bit stack.
1488 static void BuildContext16( FILE *outfile )
1490 /* Save ebx first */
1492 fprintf( outfile, "\tpushl %%ebx\n" );
1494 /* Get the 32-bit stack pointer */
1496 fprintf( outfile, "\tmovl " PREFIX "IF1632_Saved32_esp,%%ebx\n" );
1498 /* Store the registers */
1500 fprintf( outfile, "\tpopl %d(%%ebx)\n", /* Get ebx from stack*/
1501 CONTEXTOFFSET(Ebx) - sizeof(CONTEXT) );
1502 fprintf( outfile, "\tmovl %%eax,%d(%%ebx)\n",
1503 CONTEXTOFFSET(Eax) - sizeof(CONTEXT) );
1504 fprintf( outfile, "\tmovl %%ecx,%d(%%ebx)\n",
1505 CONTEXTOFFSET(Ecx) - sizeof(CONTEXT) );
1506 fprintf( outfile, "\tmovl %%edx,%d(%%ebx)\n",
1507 CONTEXTOFFSET(Edx) - sizeof(CONTEXT) );
1508 fprintf( outfile, "\tmovl %%esi,%d(%%ebx)\n",
1509 CONTEXTOFFSET(Esi) - sizeof(CONTEXT) );
1510 fprintf( outfile, "\tmovl %%edi,%d(%%ebx)\n",
1511 CONTEXTOFFSET(Edi) - sizeof(CONTEXT) );
1513 fprintf( outfile, "\tmovzwl -10(%%ebp),%%eax\n" ); /* Get %ds from stack*/
1514 fprintf( outfile, "\tmovl %%eax,%d(%%ebx)\n",
1515 CONTEXTOFFSET(SegDs) - sizeof(CONTEXT) );
1516 fprintf( outfile, "\tmovzwl -6(%%ebp),%%eax\n" ); /* Get %es from stack*/
1517 fprintf( outfile, "\tmovl %%eax,%d(%%ebx)\n",
1518 CONTEXTOFFSET(SegEs) - sizeof(CONTEXT) );
1519 fprintf( outfile, "\tpushfl\n" );
1520 fprintf( outfile, "\tpopl %d(%%ebx)\n",
1521 CONTEXTOFFSET(EFlags) - sizeof(CONTEXT) );
1522 fprintf( outfile, "\tmovl -16(%%ebp),%%eax\n" ); /* Get %ebp from stack */
1523 fprintf( outfile, "\tmovl %%eax,%d(%%ebx)\n",
1524 CONTEXTOFFSET(Ebp) - sizeof(CONTEXT) );
1525 fprintf( outfile, "\tmovzwl 2(%%ebp),%%eax\n" ); /* Get %ip from stack */
1526 fprintf( outfile, "\tmovl %%eax,%d(%%ebx)\n",
1527 CONTEXTOFFSET(Eip) - sizeof(CONTEXT) );
1528 fprintf( outfile, "\tmovzwl 4(%%ebp),%%eax\n" ); /* Get %cs from stack */
1529 fprintf( outfile, "\tmovl %%eax,%d(%%ebx)\n",
1530 CONTEXTOFFSET(SegCs) - sizeof(CONTEXT) );
1531 fprintf( outfile, "\tmovw %%fs,%%ax\n" );
1532 fprintf( outfile, "\tmovl %%eax,%d(%%ebx)\n",
1533 CONTEXTOFFSET(SegFs) - sizeof(CONTEXT) );
1534 fprintf( outfile, "\tmovw %%gs,%%ax\n" );
1535 fprintf( outfile, "\tmovl %%eax,%d(%%ebx)\n",
1536 CONTEXTOFFSET(SegGs) - sizeof(CONTEXT) );
1537 fprintf( outfile, "\tmovw %%ss,%%ax\n" );
1538 fprintf( outfile, "\tmovl %%eax,%d(%%ebx)\n",
1539 CONTEXTOFFSET(SegSs) - sizeof(CONTEXT) );
1540 #if 0
1541 fprintf( outfile, "\tfsave %d(%%ebx)\n",
1542 CONTEXTOFFSET(FloatSave) - sizeof(CONTEXT) );
1543 #endif
1547 /*******************************************************************
1548 * RestoreContext16
1550 * Restore the registers from the context structure
1552 static void RestoreContext16( FILE *outfile )
1554 /* Get the 32-bit stack pointer */
1556 fprintf( outfile, "\tmovl " PREFIX "IF1632_Saved32_esp,%%ebx\n" );
1558 /* Remove everything up to the return address from the 16-bit stack */
1560 fprintf( outfile, "\taddl $18,%%esp\n" );
1562 /* Restore the registers */
1564 fprintf( outfile, "\tmovl %d(%%ebx),%%ecx\n",
1565 CONTEXTOFFSET(Ecx) - sizeof(CONTEXT) );
1566 fprintf( outfile, "\tmovl %d(%%ebx),%%edx\n",
1567 CONTEXTOFFSET(Edx) - sizeof(CONTEXT) );
1568 fprintf( outfile, "\tmovl %d(%%ebx),%%esi\n",
1569 CONTEXTOFFSET(Esi) - sizeof(CONTEXT) );
1570 fprintf( outfile, "\tmovl %d(%%ebx),%%edi\n",
1571 CONTEXTOFFSET(Edi) - sizeof(CONTEXT) );
1572 fprintf( outfile, "\tmovl %d(%%ebx),%%ebp\n",
1573 CONTEXTOFFSET(Ebp) - sizeof(CONTEXT) );
1574 fprintf( outfile, "\tpushw %d(%%ebx)\n", /* Push new ds */
1575 CONTEXTOFFSET(SegDs) - sizeof(CONTEXT) );
1576 fprintf( outfile, "\tpushw %d(%%ebx)\n", /* Push new es */
1577 CONTEXTOFFSET(SegEs) - sizeof(CONTEXT) );
1578 fprintf( outfile, "\tpushl %d(%%ebx)\n",
1579 CONTEXTOFFSET(EFlags) - sizeof(CONTEXT) );
1580 fprintf( outfile, "\tpopfl\n" );
1581 fprintf( outfile, "\tmovl %d(%%ebx),%%eax\n",
1582 CONTEXTOFFSET(Eax) - sizeof(CONTEXT) );
1583 fprintf( outfile, "\tmovl %d(%%ebx),%%ebx\n",
1584 CONTEXTOFFSET(Ebx) - sizeof(CONTEXT) );
1585 fprintf( outfile, "\tpopw %%es\n" ); /* Set es */
1586 fprintf( outfile, "\tpopw %%ds\n" ); /* Set ds */
1590 /*******************************************************************
1591 * BuildCallFrom16Func
1593 * Build a 16-bit-to-Wine callback function. The syntax of the function
1594 * profile is: type_xxxxx, where 'type' is one of 'regs', 'word' or
1595 * 'long' and each 'x' is an argument ('w'=word, 's'=signed word,
1596 * 'l'=long, 'p'=linear pointer, 't'=linear pointer to null-terminated string,
1597 * 'T'=segmented pointer to null-terminated string).
1598 * For register functions, the arguments are ignored, but they are still
1599 * removed from the stack upon return.
1601 * Stack layout upon entry to the callback function:
1602 * ... ...
1603 * (sp+18) word first 16-bit arg
1604 * (sp+16) word cs
1605 * (sp+14) word ip
1606 * (sp+12) word bp
1607 * (sp+8) long 32-bit entry point (used to store edx)
1608 * (sp+6) word high word of cs (always 0, used to store es)
1609 * (sp+4) word low word of cs of 16-bit entry point
1610 * (sp+2) word high word of ip (always 0, used to store ds)
1611 * (sp) word low word of ip of 16-bit entry point
1613 * Added on the stack:
1614 * (sp-4) long ebp
1615 * (sp-6) word saved previous sp
1616 * (sp-8) word saved previous ss
1618 static void BuildCallFrom16Func( FILE *outfile, char *profile )
1620 int argsize = 0;
1621 int short_ret = 0;
1622 int reg_func = 0;
1623 char *args = profile + 5;
1625 /* Parse function type */
1627 if (!strncmp( "word_", profile, 5 )) short_ret = 1;
1628 else if (!strncmp( "regs_", profile, 5 )) reg_func = 1;
1629 else if (strncmp( "long_", profile, 5 ))
1631 fprintf( stderr, "Invalid function name '%s', ignored\n", profile );
1632 return;
1635 /* Function header */
1637 fprintf( outfile, "\n\t.align 4\n" );
1638 #ifdef USE_STABS
1639 fprintf( outfile, ".stabs \"CallFrom16_%s:F1\",36,0,0," PREFIX "CallFrom16_%s\n",
1640 profile, profile);
1641 #endif
1642 fprintf( outfile, "\t.globl " PREFIX "CallFrom16_%s\n", profile );
1643 fprintf( outfile, PREFIX "CallFrom16_%s:\n", profile );
1645 /* Setup bp to point to its copy on the stack */
1647 fprintf( outfile, "\tpushl %%ebp\n" ); /* Save the full 32-bit ebp */
1648 fprintf( outfile, "\tmovzwl %%sp,%%ebp\n" );
1649 fprintf( outfile, "\taddw $16,%%bp\n" );
1651 /* Save 16-bit ds and es */
1653 /* Stupid FreeBSD assembler doesn't know these either */
1654 /* fprintf( outfile, "\tmovw %%ds,-10(%%ebp)\n" ); */
1655 fprintf( outfile, "\t.byte 0x66,0x8c,0x5d,0xf6\n" );
1656 /* fprintf( outfile, "\tmovw %%es,-6(%%ebp)\n" ); */
1657 fprintf( outfile, "\t.byte 0x66,0x8c,0x45,0xfa\n" );
1659 /* Restore 32-bit ds and es */
1661 fprintf( outfile, "\tpushl $0x%04x%04x\n",
1662 WINE_DATA_SELECTOR, WINE_DATA_SELECTOR );
1663 fprintf( outfile, "\tpopw %%ds\n" );
1664 fprintf( outfile, "\tpopw %%es\n" );
1667 /* Save the 16-bit stack */
1669 fprintf( outfile, "\tpushl " PREFIX "IF1632_Saved16_ss_sp\n" );
1670 #ifdef __svr4__
1671 fprintf( outfile,"\tdata16\n");
1672 #endif
1673 fprintf( outfile, "\tmovw %%ss," PREFIX "IF1632_Saved16_ss_sp+2\n" );
1674 fprintf( outfile, "\tmovw %%sp," PREFIX "IF1632_Saved16_ss_sp\n" );
1676 /* Transfer the arguments */
1678 if (reg_func) BuildContext16( outfile );
1679 else if (*args) argsize = TransferArgs16To32( outfile, args );
1681 /* Get the address of the API function */
1683 fprintf( outfile, "\tmovl -4(%%ebp),%%eax\n" );
1685 /* If necessary, save %edx over the API function address */
1687 if (!reg_func && short_ret)
1688 fprintf( outfile, "\tmovl %%edx,-4(%%ebp)\n" );
1690 /* Switch to the 32-bit stack */
1692 fprintf( outfile, "\tmovl " PREFIX "IF1632_Saved32_esp,%%ebp\n" );
1693 fprintf( outfile, "\tpushw %%ds\n" );
1694 fprintf( outfile, "\tpopw %%ss\n" );
1695 fprintf( outfile, "\tleal -%d(%%ebp),%%esp\n",
1696 reg_func ? sizeof(CONTEXT) : 4 * strlen(args) );
1697 if (reg_func) /* Push the address of the context struct */
1698 fprintf( outfile, "\tpushl %%esp\n" );
1700 /* Setup %ebp to point to the previous stack frame (built by CallTo16) */
1702 fprintf( outfile, "\taddl $24,%%ebp\n" );
1704 /* Print the debug information before the call */
1706 if (debugging)
1708 fprintf( outfile, "\tpushl %%eax\n" );
1709 fprintf( outfile, "\tpushl $Profile_%s\n", profile );
1710 fprintf( outfile, "\tpushl $%d\n", reg_func ? 2 : (short_ret ? 1 : 0));
1711 fprintf( outfile, "\tcall " PREFIX "RELAY_DebugCallFrom16\n" );
1712 fprintf( outfile, "\tpopl %%eax\n" );
1713 fprintf( outfile, "\tpopl %%eax\n" );
1714 fprintf( outfile, "\tpopl %%eax\n" );
1717 /* Call the entry point */
1719 fprintf( outfile, "\tcall %%eax\n" );
1721 /* Print the debug information after the call */
1723 if (debugging)
1725 fprintf( outfile, "\tpushl %%eax\n" );
1726 fprintf( outfile, "\tpushl $%d\n", reg_func ? 2 : (short_ret ? 1 : 0));
1727 fprintf( outfile, "\tcall " PREFIX "RELAY_DebugCallFrom16Ret\n" );
1728 fprintf( outfile, "\tpopl %%eax\n" );
1729 fprintf( outfile, "\tpopl %%eax\n" );
1732 /* Restore the 16-bit stack */
1734 #ifdef __svr4__
1735 fprintf( outfile, "\tdata16\n");
1736 #endif
1737 fprintf( outfile, "\tmovw " PREFIX "IF1632_Saved16_ss_sp+2,%%ss\n" );
1738 fprintf( outfile, "\tmovw " PREFIX "IF1632_Saved16_ss_sp,%%sp\n" );
1739 fprintf( outfile, "\tpopl " PREFIX "IF1632_Saved16_ss_sp\n" );
1741 if (reg_func)
1743 /* Calc the arguments size */
1744 while (*args)
1746 switch(*args)
1748 case 'w':
1749 case 's':
1750 argsize += 2;
1751 break;
1752 case 'p':
1753 case 't':
1754 case 'l':
1755 case 'T':
1756 argsize += 4;
1757 break;
1758 default:
1759 fprintf( stderr, "Unknown arg type '%c'\n", *args );
1761 args++;
1764 /* Restore registers from the context structure */
1765 RestoreContext16( outfile );
1767 else
1769 /* Restore high 16 bits of ebp */
1770 fprintf( outfile, "\tpopl %%ebp\n" );
1772 /* Restore ds and es */
1773 fprintf( outfile, "\tincl %%esp\n" ); /* Remove ip */
1774 fprintf( outfile, "\tincl %%esp\n" );
1775 fprintf( outfile, "\tpopl %%edx\n" ); /* Remove cs and ds */
1776 fprintf( outfile, "\tmovw %%dx,%%ds\n" ); /* and restore ds */
1777 fprintf( outfile, "\tpopw %%es\n" ); /* Restore es */
1779 if (short_ret) fprintf( outfile, "\tpopl %%edx\n" ); /* Restore edx */
1780 else
1782 /* Get the return value into dx:ax */
1783 fprintf( outfile, "\tmovl %%eax,%%edx\n" );
1784 fprintf( outfile, "\tshrl $16,%%edx\n" );
1785 /* Remove API entry point */
1786 fprintf( outfile, "\taddl $4,%%esp\n" );
1789 /* Restore low 16 bits of ebp */
1790 fprintf( outfile, "\tpopw %%bp\n" );
1793 /* Remove the arguments and return */
1795 if (argsize)
1797 fprintf( outfile, "\t.byte 0x66\n" );
1798 fprintf( outfile, "\tlret $%d\n", argsize );
1800 else
1802 fprintf( outfile, "\t.byte 0x66\n" );
1803 fprintf( outfile, "\tlret\n" );
1808 /*******************************************************************
1809 * BuildCallTo16Func
1811 * Build a Wine-to-16-bit callback function.
1813 * Stack frame of the callback function:
1814 * ... ...
1815 * (ebp+20) arg2
1816 * (ebp+16) arg1
1817 * (ebp+12) func to call
1818 * (ebp+8) code selector
1819 * (ebp+4) return address
1820 * (ebp) previous ebp
1822 * Prototypes for the CallTo16 functions:
1823 * extern WORD CallTo16_word_xxx( FARPROC16 func, args... );
1824 * extern LONG CallTo16_long_xxx( FARPROC16 func, args... );
1825 * extern void CallTo16_regs_( const CONTEXT *context );
1827 static void BuildCallTo16Func( FILE *outfile, char *profile )
1829 int short_ret = 0;
1830 int reg_func = 0;
1831 char *args = profile + 5;
1833 if (!strncmp( "word_", profile, 5 )) short_ret = 1;
1834 else if (!strncmp( "regs_", profile, 5 )) reg_func = short_ret = 1;
1835 else if (strncmp( "long_", profile, 5 ))
1837 fprintf( stderr, "Invalid function name '%s', ignored\n", profile );
1838 return;
1841 /* Function header */
1843 fprintf( outfile, "\n\t.align 4\n" );
1844 #ifdef USE_STABS
1845 fprintf( outfile, ".stabs \"CallTo16_%s:F1\",36,0,0," PREFIX "CallTo16_%s\n",
1846 profile, profile);
1847 #endif
1848 fprintf( outfile, "\t.globl " PREFIX "CallTo16_%s\n", profile );
1849 fprintf( outfile, PREFIX "CallTo16_%s:\n", profile );
1851 /* Push code selector before return address to simulate a lcall */
1853 fprintf( outfile, "\tpopl %%eax\n" );
1854 fprintf( outfile, "\tpushl $0x%04x\n", WINE_CODE_SELECTOR );
1855 fprintf( outfile, "\tpushl %%eax\n" );
1857 /* Entry code */
1859 fprintf( outfile, "\tpushl %%ebp\n" );
1860 fprintf( outfile, "\tmovl %%esp,%%ebp\n" );
1862 /* Save the 32-bit registers */
1864 fprintf( outfile, "\tpushl %%ebx\n" );
1865 fprintf( outfile, "\tpushl %%ecx\n" );
1866 fprintf( outfile, "\tpushl %%edx\n" );
1867 fprintf( outfile, "\tpushl %%esi\n" );
1868 fprintf( outfile, "\tpushl %%edi\n" );
1870 /* Save the 32-bit stack */
1872 fprintf( outfile, "\tpushl " PREFIX "IF1632_Saved32_esp\n" );
1873 fprintf( outfile, "\tmovl %%esp," PREFIX "IF1632_Saved32_esp\n" );
1874 fprintf( outfile, "\tmovl %%ebp,%%ebx\n" );
1876 /* Print debugging info */
1878 if (debugging)
1880 /* Push the address of the first argument */
1881 fprintf( outfile, "\tleal 12(%%ebx),%%eax\n" );
1882 fprintf( outfile, "\tpushl $%d\n", reg_func ? -1 : strlen(args) );
1883 fprintf( outfile, "\tpushl %%eax\n" );
1884 fprintf( outfile, "\tcall " PREFIX "RELAY_DebugCallTo16\n" );
1885 fprintf( outfile, "\tpopl %%eax\n" );
1886 fprintf( outfile, "\tpopl %%eax\n" );
1889 /* Switch to the 16-bit stack */
1891 #ifdef __svr4__
1892 fprintf( outfile,"\tdata16\n");
1893 #endif
1894 fprintf( outfile, "\tmovw " PREFIX "IF1632_Saved16_ss_sp+2,%%ss\n" );
1895 fprintf( outfile, "\tmovw " PREFIX "IF1632_Saved16_ss_sp,%%sp\n" );
1897 /* Transfer the arguments */
1899 if (reg_func)
1901 /* Get the registers. ebx is handled later on. */
1902 fprintf( outfile, "\tmovl 12(%%ebx),%%ebx\n" );
1903 fprintf( outfile, "\tmovl %d(%%ebx),%%eax\n", CONTEXTOFFSET(SegEs) );
1904 fprintf( outfile, "\tmovw %%ax,%%es\n" );
1905 fprintf( outfile, "\tmovl %d(%%ebx),%%ebp\n", CONTEXTOFFSET(Ebp) );
1906 fprintf( outfile, "\tmovl %d(%%ebx),%%eax\n", CONTEXTOFFSET(Eax) );
1907 fprintf( outfile, "\tmovl %d(%%ebx),%%ecx\n", CONTEXTOFFSET(Ecx) );
1908 fprintf( outfile, "\tmovl %d(%%ebx),%%edx\n", CONTEXTOFFSET(Edx) );
1909 fprintf( outfile, "\tmovl %d(%%ebx),%%esi\n", CONTEXTOFFSET(Esi) );
1910 fprintf( outfile, "\tmovl %d(%%ebx),%%edi\n", CONTEXTOFFSET(Edi) );
1912 else /* not a register function */
1914 int pos = 16; /* first argument position */
1916 /* Make %bp point to the previous stackframe (built by CallFrom16) */
1917 fprintf( outfile, "\tmovzwl %%sp,%%ebp\n" );
1918 fprintf( outfile, "\taddw $20,%%bp\n" );
1920 while (*args)
1922 switch(*args++)
1924 case 'w': /* word */
1925 fprintf( outfile, "\tpushw %d(%%ebx)\n", pos );
1926 break;
1927 case 'l': /* long */
1928 fprintf( outfile, "\tpushl %d(%%ebx)\n", pos );
1929 break;
1930 default:
1931 fprintf( stderr, "Unexpected case '%c' in BuildCallTo16Func\n",
1932 args[-1] );
1934 pos += 4;
1938 /* Push the return address */
1940 fprintf( outfile, "\tpushl " PREFIX "CALLTO16_RetAddr_%s\n",
1941 short_ret ? "word" : "long" );
1943 if (reg_func)
1945 /* Push the called routine address */
1947 fprintf( outfile, "\tpushw %d(%%ebx)\n", CONTEXTOFFSET(SegCs) );
1948 fprintf( outfile, "\tpushw %d(%%ebx)\n", CONTEXTOFFSET(Eip) );
1950 /* Get the 16-bit ds */
1952 fprintf( outfile, "\tpushw %d(%%ebx)\n", CONTEXTOFFSET(SegDs) );
1953 /* Get ebx from the 32-bit stack */
1954 fprintf( outfile, "\tmovl %d(%%ebx),%%ebx\n", CONTEXTOFFSET(Ebx) );
1955 fprintf( outfile, "\tpopw %%ds\n" );
1957 else
1959 /* Push the called routine address */
1961 fprintf( outfile, "\tpushl 12(%%ebx)\n" );
1963 /* Get previous ds from the 16-bit stack and */
1964 /* set ax equal to ds for window procedures. */
1965 fprintf( outfile, "\tmovw -10(%%ebp),%%ax\n" );
1966 #ifdef __svr4__
1967 fprintf( outfile, "\tdata16\n");
1968 #endif
1969 fprintf( outfile, "\tmovw %%ax,%%ds\n" );
1972 /* Jump to the called routine */
1974 fprintf( outfile, "\t.byte 0x66\n" );
1975 fprintf( outfile, "\tlret\n" );
1979 /*******************************************************************
1980 * BuildRet16Func
1982 * Build the return code for 16-bit callbacks
1984 static void BuildRet16Func( FILE *outfile )
1986 fprintf( outfile, "\t.globl " PREFIX "CALLTO16_Ret_word\n" );
1987 fprintf( outfile, "\t.globl " PREFIX "CALLTO16_Ret_long\n" );
1989 /* Put return value into eax */
1991 fprintf( outfile, PREFIX "CALLTO16_Ret_long:\n" );
1992 fprintf( outfile, "\tpushw %%dx\n" );
1993 fprintf( outfile, "\tpushw %%ax\n" );
1994 fprintf( outfile, "\tpopl %%eax\n" );
1995 fprintf( outfile, PREFIX "CALLTO16_Ret_word:\n" );
1997 /* Restore 32-bit segment registers */
1999 fprintf( outfile, "\tmovw $0x%04x,%%bx\n", WINE_DATA_SELECTOR );
2000 #ifdef __svr4__
2001 fprintf( outfile, "\tdata16\n");
2002 #endif
2003 fprintf( outfile, "\tmovw %%bx,%%ds\n" );
2004 #ifdef __svr4__
2005 fprintf( outfile, "\tdata16\n");
2006 #endif
2007 fprintf( outfile, "\tmovw %%bx,%%es\n" );
2008 #ifdef __svr4__
2009 fprintf( outfile, "\tdata16\n");
2010 #endif
2011 fprintf( outfile, "\tmovw %%bx,%%ss\n" );
2013 /* Restore the 32-bit stack */
2015 fprintf( outfile, "\tmovl " PREFIX "IF1632_Saved32_esp,%%esp\n" );
2016 fprintf( outfile, "\tpopl " PREFIX "IF1632_Saved32_esp\n" );
2018 /* Restore the 32-bit registers */
2020 fprintf( outfile, "\tpopl %%edi\n" );
2021 fprintf( outfile, "\tpopl %%esi\n" );
2022 fprintf( outfile, "\tpopl %%edx\n" );
2023 fprintf( outfile, "\tpopl %%ecx\n" );
2024 fprintf( outfile, "\tpopl %%ebx\n" );
2026 /* Return to caller */
2028 fprintf( outfile, "\tpopl %%ebp\n" );
2029 fprintf( outfile, "\tlret\n" );
2031 /* Declare the return address variables */
2033 fprintf( outfile, "\t.data\n" );
2034 fprintf( outfile, "\t.globl " PREFIX "CALLTO16_RetAddr_word\n" );
2035 fprintf( outfile, "\t.globl " PREFIX "CALLTO16_RetAddr_long\n" );
2036 fprintf( outfile, PREFIX "CALLTO16_RetAddr_word:\t.long 0\n" );
2037 fprintf( outfile, PREFIX "CALLTO16_RetAddr_long:\t.long 0\n" );
2038 fprintf( outfile, "\t.text\n" );
2042 /*******************************************************************
2043 * BuildContext32
2045 * Build the CONTEXT structure on the stack.
2047 static void BuildContext32( FILE *outfile )
2049 /* Build the context structure */
2051 fprintf( outfile, "\tpushw $0\n" );
2052 fprintf( outfile, "\tpushw %%ss\n" );
2053 fprintf( outfile, "\tpushl %%eax\n" ); /* %esp */
2054 fprintf( outfile, "\tpushfl\n" );
2055 fprintf( outfile, "\tpushw $0\n" );
2056 fprintf( outfile, "\tpushw %%cs\n" );
2057 fprintf( outfile, "\tsubl $8,%%esp\n" ); /* %eip + %ebp */
2059 fprintf( outfile, "\tpushl %%eax\n" );
2060 fprintf( outfile, "\tpushl %%ecx\n" );
2061 fprintf( outfile, "\tpushl %%edx\n" );
2062 fprintf( outfile, "\tpushl %%ebx\n" );
2063 fprintf( outfile, "\tpushl %%esi\n" );
2064 fprintf( outfile, "\tpushl %%edi\n" );
2066 fprintf( outfile, "\txorl %%eax,%%eax\n" );
2067 fprintf( outfile, "\tmovw %%ds,%%ax\n" );
2068 fprintf( outfile, "\tpushl %%eax\n" );
2069 fprintf( outfile, "\tmovw %%es,%%ax\n" );
2070 fprintf( outfile, "\tpushl %%eax\n" );
2071 fprintf( outfile, "\tmovw %%fs,%%ax\n" );
2072 fprintf( outfile, "\tpushl %%eax\n" );
2073 fprintf( outfile, "\tmovw %%gs,%%ax\n" );
2074 fprintf( outfile, "\tpushl %%eax\n" );
2076 fprintf( outfile, "\tsubl $%d,%%esp\n",
2077 sizeof(FLOATING_SAVE_AREA) + 6 * sizeof(DWORD) /* DR regs */ );
2078 fprintf( outfile, "\tpushl $0x0001001f\n" ); /* ContextFlags */
2080 fprintf( outfile, "\tfsave %d(%%esp)\n", CONTEXTOFFSET(FloatSave) );
2082 fprintf( outfile, "\tmovl 4(%%ebp),%%eax\n" ); /* %eip at time of call */
2083 fprintf( outfile, "\tmovl %%eax,%d(%%esp)\n", CONTEXTOFFSET(Eip) );
2084 fprintf( outfile, "\tmovl 0(%%ebp),%%eax\n" ); /* %ebp at time of call */
2085 fprintf( outfile, "\tmovl %%eax,%d(%%esp)\n", CONTEXTOFFSET(Ebp) );
2086 fprintf( outfile, "\tleal 8(%%ebp),%%eax\n" ); /* %esp at time of call */
2087 fprintf( outfile, "\tmovl %%eax,%d(%%esp)\n", CONTEXTOFFSET(Esp) );
2089 /* Push pointer to context */
2091 fprintf( outfile, "\tpushl %%esp\n" );
2095 /*******************************************************************
2096 * RestoreContext32
2098 * Restore the registers from the context structure.
2099 * All registers except %cs and %ss are restored.
2101 static void RestoreContext32( FILE *outfile )
2103 /* Restore the context structure */
2105 fprintf( outfile, "\tleal %d(%%ebp),%%esp\n", -sizeof(CONTEXT)-8 );
2106 fprintf( outfile, "\tfrstor %d(%%esp)\n", CONTEXTOFFSET(FloatSave) );
2108 /* Store flags over the relay addr */
2109 fprintf( outfile, "\tmovl %d(%%esp),%%eax\n", CONTEXTOFFSET(EFlags) );
2110 fprintf( outfile, "\tmovl %%eax,%d(%%esp)\n", sizeof(CONTEXT) );
2112 /* Get the new stack addr */
2113 fprintf( outfile, "\tmovl %d(%%esp),%%ebx\n", CONTEXTOFFSET(Esp) );
2115 /* Set eip and ebp value onto the new stack */
2116 fprintf( outfile, "\tmovl %d(%%esp),%%eax\n", CONTEXTOFFSET(Eip) );
2117 fprintf( outfile, "\tmovl %%eax,-4(%%ebx)\n" ); /* %eip at time of call */
2118 fprintf( outfile, "\tmovl %d(%%esp),%%eax\n", CONTEXTOFFSET(Ebp) );
2119 fprintf( outfile, "\tmovl %%eax,-8(%%ebx)\n" ); /* %ebp at time of call */
2121 /* Set ebp to point to the new stack */
2122 fprintf( outfile, "\tleal -8(%%ebx),%%ebp\n" );
2124 /* Restore all registers */
2125 fprintf( outfile, "\taddl $%d,%%esp\n",
2126 sizeof(FLOATING_SAVE_AREA) + 7 * sizeof(DWORD) );
2127 fprintf( outfile, "\tpopl %%eax\n" );
2128 fprintf( outfile, "\tmovw %%ax,%%gs\n" );
2129 fprintf( outfile, "\tpopl %%eax\n" );
2130 fprintf( outfile, "\tmovw %%ax,%%fs\n" );
2131 fprintf( outfile, "\tpopl %%eax\n" );
2132 fprintf( outfile, "\tmovw %%ax,%%es\n" );
2133 fprintf( outfile, "\tpopl %%eax\n" );
2134 fprintf( outfile, "\tmovw %%ax,%%ds\n" );
2136 fprintf( outfile, "\tpopl %%edi\n" );
2137 fprintf( outfile, "\tpopl %%esi\n" );
2138 fprintf( outfile, "\tpopl %%ebx\n" );
2139 fprintf( outfile, "\tpopl %%edx\n" );
2140 fprintf( outfile, "\tpopl %%ecx\n" );
2141 fprintf( outfile, "\tpopl %%eax\n" );
2143 fprintf( outfile, "\taddl $%d,%%esp\n",
2144 6 * sizeof(DWORD) /* %ebp + %eip + %cs + %efl + %esp + %ss */ );
2145 fprintf( outfile, "\tpopfl\n" );
2149 /*******************************************************************
2150 * BuildCallFrom32Func
2152 * Build a 32-bit-to-Wine call-back function.
2153 * 'args' is the number of dword arguments.
2155 * Stack layout:
2156 * ... ...
2157 * (ebp+12) arg2
2158 * (ebp+8) arg1
2159 * (ebp+4) ret addr
2160 * (ebp) ebp
2161 * (ebp-4) entry point
2162 * (ebp-8) relay addr
2164 static void BuildCallFrom32Func( FILE *outfile, const char *profile )
2166 int args, stdcall, reg_func;
2168 if (!strncmp( profile, "stdcall", 7 ))
2170 stdcall = 1;
2171 reg_func = 0;
2172 args = atoi( profile + 8 );
2174 else if (!strncmp( profile, "cdecl", 5 ))
2176 stdcall = reg_func = 0;
2177 args = atoi( profile + 6 );
2179 else if (!strncmp( profile, "regs", 4 ))
2181 stdcall = reg_func = 1;
2182 args = atoi( profile + 5 );
2184 else
2186 fprintf( stderr, "Invalid function profile '%s', ignored\n", profile );
2187 return;
2190 /* Function header */
2192 fprintf( outfile, "\n\t.align 4\n" );
2193 #ifdef USE_STABS
2194 fprintf( outfile, ".stabs \"CallFrom32_%s:F1\",36,0,0," PREFIX "CallFrom32_%s\n",
2195 profile, profile);
2196 #endif
2197 fprintf( outfile, "\t.globl " PREFIX "CallFrom32_%s\n", profile );
2198 fprintf( outfile, PREFIX "CallFrom32_%s:\n", profile );
2200 /* Entry code */
2202 fprintf( outfile, "\tleal 8(%%esp),%%ebp\n" );
2204 /* Transfer the arguments */
2206 if (reg_func) BuildContext32( outfile );
2208 if (args)
2210 int i;
2211 for (i = args; i > 0; i--)
2212 fprintf( outfile, "\tpushl %d(%%ebp)\n", 4 * i + 4 );
2214 else if (!reg_func)
2216 /* Push the address of the arguments. The called function will */
2217 /* ignore this if it really takes no arguments. */
2218 fprintf( outfile, "\tleal 8(%%ebp),%%eax\n" );
2219 fprintf( outfile, "\tpushl %%eax\n" );
2222 /* Set %es = %ds */
2224 fprintf( outfile, "\tmovw %%ds,%%ax\n" );
2225 fprintf( outfile, "\tmovw %%ax,%%es\n" );
2227 /* Print the debugging info */
2229 if (debugging)
2231 fprintf( outfile, "\tpushl $%d\n", /* Nb args */
2232 reg_func ? args | 0x80000000 : args);
2233 fprintf( outfile, "\tpushl %%ebp\n" );
2234 fprintf( outfile, "\tcall " PREFIX "RELAY_DebugCallFrom32\n" );
2235 fprintf( outfile, "\tadd $8, %%esp\n" );
2238 /* Call the function */
2240 fprintf( outfile, "\tcall -4(%%ebp)\n" );
2242 /* Print the debugging info */
2244 if (debugging)
2246 fprintf( outfile, "\tpushl %%eax\n" );
2247 fprintf( outfile, "\tpushl $%d\n", /* Nb args */
2248 reg_func ? args | 0x80000000 : args);
2249 fprintf( outfile, "\tpushl %%ebp\n" );
2250 fprintf( outfile, "\tcall " PREFIX "RELAY_DebugCallFrom32Ret\n" );
2251 fprintf( outfile, "\tpopl %%eax\n" );
2252 fprintf( outfile, "\tpopl %%eax\n" );
2253 fprintf( outfile, "\tpopl %%eax\n" );
2256 if (reg_func) RestoreContext32( outfile );
2258 fprintf( outfile, "\tmovl %%ebp,%%esp\n" );
2259 fprintf( outfile, "\tpopl %%ebp\n" );
2261 /* Return, removing arguments */
2263 if (args && stdcall) fprintf( outfile, "\tret $%d\n", args * 4 );
2264 else fprintf( outfile, "\tret\n" );
2268 /*******************************************************************
2269 * BuildCallTo32Func
2271 * Build a Wine-to-32-bit callback function.
2273 * Stack frame of the callback function:
2274 * ... ...
2275 * (ebp+16) arg2
2276 * (ebp+12) arg1
2277 * (ebp+8) func to call
2278 * (ebp+4) return address
2279 * (ebp) previous ebp
2281 * Prototype for the CallTo32 functions:
2282 * extern LONG CallTo32_nn( FARPROC32 func, args... );
2284 static void BuildCallTo32Func( FILE *outfile, int args )
2286 /* Function header */
2288 fprintf( outfile, "\n\t.align 4\n" );
2289 #ifdef USE_STABS
2290 fprintf( outfile, ".stabs \"CallTo32_%d:F1\",36,0,0," PREFIX "CallTo32_%d\n",
2291 args, args);
2292 #endif
2293 fprintf( outfile, "\t.globl " PREFIX "CallTo32_%d\n", args );
2294 fprintf( outfile, PREFIX "CallTo32_%d:\n", args );
2296 /* Entry code */
2298 fprintf( outfile, "\tpushl %%ebp\n" );
2299 fprintf( outfile, "\tmovl %%esp,%%ebp\n" );
2301 /* Transfer arguments */
2303 if (args)
2305 int i;
2306 for (i = args; i > 0; i--)
2307 fprintf( outfile, "\tpushl %d(%%ebp)\n", 4 * i + 8 );
2310 /* Print the debugging output */
2312 if (debugging)
2314 fprintf( outfile, "\tpushl $%d\n", args );
2315 fprintf( outfile, "\tpushl 8(%%ebp)\n" );
2316 fprintf( outfile, "\tcall " PREFIX "RELAY_DebugCallTo32\n" );
2317 fprintf( outfile, "\taddl $8,%%esp\n" );
2320 /* Call the function */
2322 fprintf( outfile, "\tcall 8(%%ebp)\n" );
2324 /* Return to Wine */
2326 fprintf( outfile, "\tmovl %%ebp,%%esp\n" );
2327 fprintf( outfile, "\tpopl %%ebp\n" );
2328 fprintf( outfile, "\tret\n" );
2332 /*******************************************************************
2333 * BuildSpec
2335 * Build the spec files
2337 static int BuildSpec( FILE *outfile, int argc, char *argv[] )
2339 int i;
2340 for (i = 2; i < argc; i++)
2341 if (BuildSpecFile( outfile, argv[i] ) < 0) return -1;
2342 return 0;
2346 /*******************************************************************
2347 * BuildCallFrom16
2349 * Build the 16-bit-to-Wine callbacks
2351 static int BuildCallFrom16( FILE *outfile, char * outname, int argc, char *argv[] )
2353 int i;
2354 char buffer[1024];
2356 /* File header */
2358 fprintf( outfile, "/* File generated automatically. Do not edit! */\n\n" );
2359 fprintf( outfile, "\t.text\n" );
2361 #ifdef USE_STABS
2362 fprintf( outfile, "\t.file\t\"%s\"\n", outname );
2363 getcwd(buffer, sizeof(buffer));
2366 * The stabs help the internal debugger as they are an indication that it
2367 * is sensible to step into a thunk/trampoline.
2369 fprintf( outfile, ".stabs \"%s/\",100,0,0,Code_Start\n", buffer);
2370 fprintf( outfile, ".stabs \"%s\",100,0,0,Code_Start\n", outname);
2371 fprintf( outfile, "\t.text\n" );
2372 fprintf( outfile, "\t.align 4\n" );
2373 fprintf( outfile, "Code_Start:\n\n" );
2374 #endif
2376 /* Build the 32-bit large stack callback */
2378 BuildCall32LargeStack( outfile );
2380 /* Build the callback functions */
2382 for (i = 2; i < argc; i++) BuildCallFrom16Func( outfile, argv[i] );
2384 /* Output the argument debugging strings */
2386 if (debugging)
2388 fprintf( outfile, "/* Argument strings */\n" );
2389 for (i = 2; i < argc; i++)
2391 fprintf( outfile, "Profile_%s:\n", argv[i] );
2392 fprintf( outfile, "\t.ascii \"%s\\0\"\n", argv[i] + 5 );
2396 #ifdef USE_STABS
2397 fprintf( outfile, "\t.text\n");
2398 fprintf( outfile, "\t.stabs \"\",100,0,0,.Letext\n");
2399 fprintf( outfile, ".Letext:\n");
2400 #endif
2402 return 0;
2406 /*******************************************************************
2407 * BuildCallTo16
2409 * Build the Wine-to-16-bit callbacks
2411 static int BuildCallTo16( FILE *outfile, char * outname, int argc, char *argv[] )
2413 char buffer[1024];
2414 int i;
2416 /* File header */
2418 fprintf( outfile, "/* File generated automatically. Do not edit! */\n\n" );
2419 fprintf( outfile, "\t.text\n" );
2421 #ifdef USE_STABS
2422 fprintf( outfile, "\t.file\t\"%s\"\n", outname );
2423 getcwd(buffer, sizeof(buffer));
2426 * The stabs help the internal debugger as they are an indication that it
2427 * is sensible to step into a thunk/trampoline.
2429 fprintf( outfile, ".stabs \"%s/\",100,0,0,Code_Start\n", buffer);
2430 fprintf( outfile, ".stabs \"%s\",100,0,0,Code_Start\n", outname);
2431 fprintf( outfile, "\t.text\n" );
2432 fprintf( outfile, "\t.align 4\n" );
2433 fprintf( outfile, "Code_Start:\n\n" );
2434 #endif
2436 fprintf( outfile, "\t.globl " PREFIX "CALLTO16_Start\n" );
2437 fprintf( outfile, PREFIX "CALLTO16_Start:\n" );
2439 /* Build the callback functions */
2441 for (i = 2; i < argc; i++) BuildCallTo16Func( outfile, argv[i] );
2443 /* Output the 16-bit return code */
2445 BuildRet16Func( outfile );
2447 fprintf( outfile, "\t.globl " PREFIX "CALLTO16_End\n" );
2448 fprintf( outfile, PREFIX "CALLTO16_End:\n" );
2450 #ifdef USE_STABS
2451 fprintf( outfile, "\t.text\n");
2452 fprintf( outfile, "\t.stabs \"\",100,0,0,.Letext\n");
2453 fprintf( outfile, ".Letext:\n");
2454 #endif
2456 return 0;
2460 /*******************************************************************
2461 * BuildCallFrom32
2463 * Build the 32-bit-to-Wine callbacks
2465 static int BuildCallFrom32( FILE *outfile, char * outname, int argc, char *argv[] )
2467 char buffer[1024];
2468 int i;
2470 /* File header */
2472 fprintf( outfile, "/* File generated automatically. Do not edit! */\n\n" );
2473 fprintf( outfile, "\t.text\n" );
2475 #ifdef USE_STABS
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" );
2488 #endif
2490 /* Build the callback functions */
2492 for (i = 2; i < argc; i++) BuildCallFrom32Func( outfile, argv[i] );
2494 #ifdef USE_STABS
2495 fprintf( outfile, "\t.text\n");
2496 fprintf( outfile, "\t.stabs \"\",100,0,0,.Letext\n");
2497 fprintf( outfile, ".Letext:\n");
2498 #endif
2500 return 0;
2504 /*******************************************************************
2505 * BuildCallTo32
2507 * Build the Wine-to-32-bit callbacks
2509 static int BuildCallTo32( FILE *outfile, char * outname,
2510 int argc, char *argv[] )
2512 char buffer[1024];
2513 int i;
2515 /* File header */
2517 fprintf( outfile, "/* File generated automatically. Do not edit! */\n\n" );
2518 fprintf( outfile, "\t.text\n" );
2521 * Throw in a couple of stabs. The internal debugger doesn't really
2522 * care about trying to step through this crap, but we use the file
2523 * names as an indication that we should just step through it to whatever
2524 * is on the other side.
2526 #ifdef USE_STABS
2527 fprintf( outfile, "\t.file\t\"%s\"\n", outname );
2528 getcwd(buffer, sizeof(buffer));
2531 * The stabs help the internal debugger as they are an indication that it
2532 * is sensible to step into a thunk/trampoline.
2534 fprintf( outfile, ".stabs \"%s/\",100,0,0,Code_Start\n", buffer);
2535 fprintf( outfile, ".stabs \"%s\",100,0,0,Code_Start\n", outname);
2536 fprintf( outfile, "\t.text\n" );
2537 fprintf( outfile, "\t.align 4\n" );
2538 fprintf( outfile, "Code_Start:\n\n" );
2539 #endif
2541 /* Build the callback functions */
2543 for (i = 2; i < argc; i++) BuildCallTo32Func( outfile, atoi(argv[i]) );
2545 #ifdef USE_STABS
2546 fprintf( outfile, "\t.text\n");
2547 fprintf( outfile, "\t.stabs \"\",100,0,0,.Letext\n");
2548 fprintf( outfile, ".Letext:\n");
2549 #endif
2551 return 0;
2555 /*******************************************************************
2556 * usage
2558 static void usage(void)
2560 fprintf(stderr, "usage: build [-o outfile] -spec SPECNAMES\n"
2561 " build [-o outfile] -callfrom16 FUNCTION_PROFILES\n"
2562 " build [-o outfile] -callto16 FUNCTION_PROFILES\n"
2563 " build [-o outfile] -callfrom32 FUNCTION_PROFILES\n"
2564 " build [-o outfile] -callto32 FUNCTION_PROFILES\n");
2565 exit(1);
2569 /*******************************************************************
2570 * main
2572 int main(int argc, char **argv)
2574 char *outname = NULL;
2575 FILE *outfile = stdout;
2576 int res = -1;
2578 if (argc <= 2) usage();
2580 if (!strcmp( argv[1], "-o" ))
2582 outname = argv[2];
2583 argv += 2;
2584 argc -= 2;
2585 if (argc <= 2) usage();
2586 if (!(outfile = fopen( outname, "w" )))
2588 fprintf( stderr, "Unable to create output file '%s'\n", outname );
2589 exit(1);
2593 if (!strcmp( argv[1], "-spec" ))
2594 res = BuildSpec( outfile, argc, argv );
2595 else if (!strcmp( argv[1], "-callfrom16" ))
2596 res = BuildCallFrom16( outfile, outname, argc, argv );
2597 else if (!strcmp( argv[1], "-callto16" ))
2598 res = BuildCallTo16( outfile, outname, argc, argv );
2599 else if (!strcmp( argv[1], "-callfrom32" ))
2600 res = BuildCallFrom32( outfile, outname, argc, argv );
2601 else if (!strcmp( argv[1], "-callto32" ))
2602 res = BuildCallTo32( outfile, outname, argc, argv );
2603 else
2605 fclose( outfile );
2606 unlink( outname );
2607 usage();
2610 fclose( outfile );
2611 if (res < 0)
2613 unlink( outname );
2614 return 1;
2616 return 0;