2 * Copyright 1993 Robert J. Amstadt
3 * Copyright 1995 Martin von Loewis
4 * Copyright 1995, 1996 Alexandre Julliard
15 #include "registers.h"
16 #include "winerror.h" /* for ERROR_CALL_NOT_IMPLEMENTED */
21 #ifdef NEED_UNDERSCORE_PREFIX
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) */
45 static const char * const TypeNames
[TYPE_NBTYPES
] =
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")
119 static ORDDEF OrdinalDefinitions
[MAX_ORDINALS
];
121 static SPEC_TYPE SpecType
= SPEC_INVALID
;
128 char *ParseBuffer
= NULL
;
133 static int debugging
= 1;
135 /* Offset of register relative to the end of the SIGCONTEXT struct */
136 #define SIGCONTEXTOFFSET(reg) \
137 ((int)®##_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
)
146 res
= malloc (size
? size
: 1);
149 fprintf (stderr
, "Virtual memory exhausted.\n");
156 static void *xrealloc (void *ptr
, size_t size
)
158 void *res
= realloc (ptr
, size
);
161 fprintf (stderr
, "Virtual memory exhausted.\n");
168 static int IsNumberString(char *s
)
177 static char *strupper(char *s
)
181 for(p
= s
; *p
!= '\0'; p
++)
187 static char * GetTokenInLine(void)
192 if (ParseNext
!= ParseBuffer
)
194 if (ParseSaveChar
== '\0')
196 *ParseNext
= ParseSaveChar
;
200 * Remove initial white space.
202 for (p
= ParseNext
; isspace(*p
); p
++)
205 if ((*p
== '\0') || (*p
== '#'))
212 if (*token
!= '(' && *token
!= ')')
213 while (*p
!= '\0' && *p
!= '(' && *p
!= ')' && !isspace(*p
))
223 static char * GetToken(void)
227 if (ParseBuffer
== NULL
)
229 ParseBuffer
= xmalloc(512);
230 ParseNext
= ParseBuffer
;
234 if (fgets(ParseBuffer
, 511, SpecFp
) == NULL
)
236 if (ParseBuffer
[0] != '#')
241 while ((token
= GetTokenInLine()) == NULL
)
243 ParseNext
= ParseBuffer
;
247 if (fgets(ParseBuffer
, 511, SpecFp
) == NULL
)
249 if (ParseBuffer
[0] != '#')
258 /*******************************************************************
261 * Parse a variable definition.
263 static int ParseVariable( ORDDEF
*odp
)
268 int value_array_size
;
270 char *token
= GetToken();
273 fprintf(stderr
, "%d: Expected '(' got '%s'\n", Line
, token
);
278 value_array_size
= 25;
279 value_array
= xmalloc(sizeof(*value_array
) * value_array_size
);
281 while ((token
= GetToken()) != NULL
)
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
,
304 fprintf(stderr
, "%d: End of file in variable declaration\n", Line
);
308 odp
->u
.var
.n_values
= n_values
;
309 odp
->u
.var
.values
= xrealloc(value_array
, sizeof(*value_array
) * n_values
);
315 /*******************************************************************
316 * ParseExportFunction
318 * Parse a function definition.
320 static int ParseExportFunction( ORDDEF
*odp
)
328 if (odp
->type
== TYPE_STDCALL
)
330 fprintf( stderr
, "%d: 'stdcall' not supported for Win16\n", Line
);
333 if (odp
->type
== TYPE_CDECL
)
335 fprintf( stderr
, "%d: 'cdecl' not supported for Win16\n", Line
);
340 if ((odp
->type
== TYPE_PASCAL
) || (odp
->type
== TYPE_PASCAL_16
))
342 fprintf( stderr
, "%d: 'pascal' not supported for Win32\n", Line
);
353 fprintf(stderr
, "%d: Expected '(' got '%s'\n", Line
, token
);
357 for (i
= 0; i
< sizeof(odp
->u
.func
.arg_types
)-1; i
++)
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';
373 fprintf(stderr
, "%d: Unknown variable type '%s'\n", Line
, token
);
376 if (SpecType
== SPEC_WIN32
)
378 if (strcmp(token
, "long") && strcmp(token
, "ptr"))
380 fprintf( stderr
, "%d: Type '%s' not supported for Win32\n",
388 fprintf( stderr
, "%d: Too many arguments\n", Line
);
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());
399 /*******************************************************************
402 * Parse an 'equate' definition.
404 static int ParseEquate( ORDDEF
*odp
)
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
,
417 odp
->u
.abs
.value
= value
;
422 /*******************************************************************
425 * Parse a 'return' definition.
427 static int ParseReturn( ORDDEF
*odp
)
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
,
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
,
454 /*******************************************************************
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
);
467 /*******************************************************************
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
);
479 strcpy( odp
->u
.ext
.link_name
, GetToken() );
484 /*******************************************************************
487 * Parse an ordinal definition.
489 static int ParseOrdinal(int ordinal
)
494 if (ordinal
>= MAX_ORDINALS
)
496 fprintf(stderr
, "%d: Ordinal number too large\n", Line
);
499 if (ordinal
> Limit
) Limit
= ordinal
;
501 odp
= &OrdinalDefinitions
[ordinal
];
502 if (!(token
= GetToken()))
504 fprintf(stderr
, "%d: Expected type after ordinal\n", Line
);
508 for (odp
->type
= 0; odp
->type
< TYPE_NBTYPES
; odp
->type
++)
509 if (TypeNames
[odp
->type
] && !strcmp( token
, TypeNames
[odp
->type
] ))
512 if (odp
->type
>= TYPE_NBTYPES
)
515 "%d: Expected type after ordinal, found '%s' instead\n",
520 if (!(token
= GetToken()))
522 fprintf( stderr
, "%d: Expected name after type\n", Line
);
525 strcpy( odp
->name
, token
);
532 return ParseVariable( odp
);
538 return ParseExportFunction( odp
);
540 return ParseEquate( odp
);
542 return ParseReturn( odp
);
544 return ParseStub( odp
);
546 return ParseExtern( odp
);
548 fprintf( stderr
, "Should not happen\n" );
554 /*******************************************************************
559 static int ParseTopLevel(void)
563 while ((token
= GetToken()) != NULL
)
565 if (strcmp(token
, "name") == 0)
567 strcpy(DLLName
, GetToken());
570 else if (strcmp(token
, "type") == 0)
573 if (!strcmp(token
, "win16" )) SpecType
= SPEC_WIN16
;
574 else if (!strcmp(token
, "win32" )) SpecType
= SPEC_WIN32
;
577 fprintf(stderr
, "%d: Type must be 'win16' or 'win32'\n", Line
);
581 else if (strcmp(token
, "base") == 0)
584 if (!IsNumberString(token
))
586 fprintf(stderr
, "%d: Expected number after base\n", Line
);
591 else if (strcmp(token
, "heap") == 0)
594 if (!IsNumberString(token
))
596 fprintf(stderr
, "%d: Expected number after heap\n", Line
);
599 DLLHeapSize
= atoi(token
);
601 else if (IsNumberString(token
))
606 ordinal
= atoi(token
);
607 if ((rv
= ParseOrdinal(ordinal
)) < 0)
613 "%d: Expected name, id, length or ordinal\n", Line
);
622 /*******************************************************************
625 * Store a list of ints into a byte array.
627 static int StoreVariableCode( unsigned char *buffer
, int size
, ORDDEF
*odp
)
634 for (i
= 0; i
< odp
->u
.var
.n_values
; i
++)
635 buffer
[i
] = odp
->u
.var
.values
[i
];
638 for (i
= 0; i
< odp
->u
.var
.n_values
; i
++)
639 ((unsigned short *)buffer
)[i
] = odp
->u
.var
.values
[i
];
642 for (i
= 0; i
< odp
->u
.var
.n_values
; i
++)
643 ((unsigned int *)buffer
)[i
] = odp
->u
.var
.values
[i
];
646 return odp
->u
.var
.n_values
* size
;
650 /*******************************************************************
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
)
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
++ );
666 fprintf( outfile
, "%c", ((i
& 0x0f) != 0x0f) ? ',' : '\n' );
668 fprintf( outfile
, "\n" );
672 /*******************************************************************
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
)
685 SEGTABLEENTRY
*pSegment
;
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
;
707 pModule
->flags
= NE_FFLAGS_SINGLEDATA
| NE_FFLAGS_BUILTIN
| NE_FFLAGS_LIBMODULE
;
709 pModule
->heap_size
= DLLHeapSize
;
710 pModule
->stack_size
= 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
;
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;
745 pSegment
= (SEGTABLEENTRY
*)pstr
;
746 pModule
->seg_table
= (int)pSegment
- (int)pModule
;
747 pSegment
->filepos
= 0;
748 pSegment
->size
= max_code_offset
;
750 pSegment
->minsize
= max_code_offset
;
751 pSegment
->selector
= 0;
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;
764 pword
= (WORD
*)pSegment
;
765 pModule
->res_table
= (int)pword
- (int)pModule
;
769 /* Imported names table */
771 pstr
= (char *)pword
;
772 pModule
->import_table
= (int)pstr
- (int)pModule
;
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
);
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 );
795 pstr
+= sizeof(WORD
);
801 pModule
->entry_table
= (int)pstr
- (int)pModule
;
803 odp
= OrdinalDefinitions
+ 1;
804 for (i
= 1; i
<= Limit
; i
++, odp
++)
815 selector
= 1; /* Code selector */
821 selector
= 2; /* Data selector */
825 selector
= 0xfe; /* Constant selector */
829 selector
= 0; /* Invalid selector */
833 /* create a new bundle if necessary */
834 if (!bundle
|| (bundle
[0] >= 254) || (bundle
[1] != selector
))
838 bundle
[1] = selector
;
846 *(WORD
*)pstr
= odp
->offset
;
847 pstr
+= sizeof(WORD
);
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 /*******************************************************************
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
)
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
;
890 pModule
->dgroup_entry
= 0;
891 pModule
->flags
= NE_FFLAGS_SINGLEDATA
| NE_FFLAGS_BUILTIN
|
892 NE_FFLAGS_LIBMODULE
| NE_FFLAGS_WIN32
;
894 pModule
->heap_size
= DLLHeapSize
;
895 pModule
->stack_size
= 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
;
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;
930 pModule
->seg_table
= (int)pstr
- (int)pModule
;
934 pword
= (WORD
*)pstr
;
935 pModule
->res_table
= (int)pword
- (int)pModule
;
939 /* Imported names table */
941 pstr
= (char *)pword
;
942 pModule
->import_table
= (int)pstr
- (int)pModule
;
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
);
954 pstr
+= sizeof(WORD
);
959 pModule
->entry_table
= (int)pstr
- (int)pModule
;
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 /*******************************************************************
973 * Build a Win32 assembly file from a spec file.
975 static int BuildSpec32File( FILE *outfile
)
978 int i
, module_size
, len
;
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
++)
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" );
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" );
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" );
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" );
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" );
1057 fprintf(stderr
,"build: function type %d not available for Win32\n",
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
++)
1076 fprintf( outfile
, "\t.long 0\n" );
1079 fprintf( outfile
, "\t.long " PREFIX
"%s\n", odp
->u
.ext
.link_name
);
1082 fprintf( outfile
, "\t.long %s_%d\n", DLLName
, i
);
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 */
1123 /*******************************************************************
1126 * Build a Win16 assembly file from a spec file.
1128 static int BuildSpec16File( FILE *outfile
)
1132 int code_offset
, data_offset
, module_size
;
1133 unsigned char *data
;
1135 data
= (unsigned char *)xmalloc( 0x10000 );
1136 memset( data
, 0, 16 );
1139 fprintf( outfile
, "/* File generated automatically; do not edit! */\n" );
1140 fprintf( outfile
, "\t.text\n" );
1141 fprintf( outfile
, "Code_Start:\n" );
1144 odp
= OrdinalDefinitions
;
1145 for (i
= 0; i
<= Limit
; i
++, odp
++)
1150 odp
->offset
= 0xffff;
1154 odp
->offset
= LOWORD(odp
->u
.abs
.value
);
1158 odp
->offset
= data_offset
;
1159 data_offset
+= StoreVariableCode( data
+ data_offset
, 1, odp
);
1163 odp
->offset
= data_offset
;
1164 data_offset
+= StoreVariableCode( data
+ data_offset
, 2, odp
);
1168 odp
->offset
= data_offset
;
1169 data_offset
+= StoreVariableCode( data
+ data_offset
, 4, odp
);
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
);
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 */
1191 case TYPE_PASCAL_16
:
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\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 */
1211 fprintf(stderr
,"build: function type %d not available for Win16\n",
1217 if (!code_offset
) /* Make sure the code segment is not empty */
1219 fprintf( outfile
, "\t.byte 0\n" );
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 */
1247 /*******************************************************************
1250 * Build an assembly file from a spec file.
1252 static int BuildSpecFile( FILE *outfile
, char *specname
)
1254 SpecFp
= fopen( specname
, "r");
1257 fprintf(stderr
, "Could not open specification file, '%s'\n", specname
);
1261 if (ParseTopLevel() < 0) return -1;
1266 return BuildSpec16File( outfile
);
1268 return BuildSpec32File( outfile
);
1270 fprintf( stderr
, "%s: Missing 'type' declaration\n", specname
);
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, ... )
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" );
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:
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 */
1383 for (i
= strlen(args
); i
> 0; i
--)
1388 case 'w': /* word */
1389 fprintf( outfile
, "\tmovzwl %d(%%ebp),%%eax\n", pos16
);
1390 fprintf( outfile
, "\tmovl %%eax,%d(%%ebx)\n", pos32
);
1394 case 's': /* s_word */
1395 fprintf( outfile
, "\tmovswl %d(%%ebp),%%eax\n", pos16
);
1396 fprintf( outfile
, "\tmovl %%eax,%d(%%ebx)\n", pos32
);
1400 case 'l': /* long */
1401 fprintf( outfile
, "\tmovl %d(%%ebp),%%eax\n", pos16
);
1402 fprintf( outfile
, "\tmovl %%eax,%d(%%ebx)\n", pos32
);
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
);
1420 fprintf( stderr
, "Unknown arg type '%c'\n", args
[i
-1] );
1426 fprintf( outfile
, "\tpopl %%ebx\n" );
1428 return pos16
- 6; /* Return the size of the 16-bit args */
1432 /*******************************************************************
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 /*******************************************************************
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:
1506 * (sp+18) word first 16-bit arg
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
)
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
);
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" );
1566 fprintf( outfile
,"\tdata16\n");
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 */
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 */
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 */
1630 fprintf( outfile
, "\tdata16\n");
1632 fprintf( outfile
, "\tmovw " PREFIX
"IF1632_Saved16_ss,%%ss\n" );
1633 fprintf( outfile
, "\tmovw " PREFIX
"IF1632_Saved16_sp,%%sp\n" );
1635 fprintf( outfile
, "\tdata16\n");
1637 fprintf( outfile
, "\tpopw " PREFIX
"IF1632_Saved16_ss\n" );
1639 fprintf( outfile
, "\tdata16\n");
1641 fprintf( outfile
, "\tpopw " PREFIX
"IF1632_Saved16_sp\n" );
1645 /* Restore registers from the context structure */
1646 RestoreContext16( outfile
);
1648 /* Calc the arguments size */
1662 fprintf( stderr
, "Unknown arg type '%c'\n", *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" );
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 */
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" );
1697 fprintf( outfile
, "\tpopw %%bp\n" );
1699 /* Remove the arguments and return */
1703 fprintf( outfile
, "\t.byte 0x66\n" );
1704 fprintf( outfile
, "\tlret $%d\n", argsize
);
1708 fprintf( outfile
, "\t.byte 0x66\n" );
1709 fprintf( outfile
, "\tlret\n" );
1714 /*******************************************************************
1717 * Build a Wine-to-16-bit callback function.
1719 * Stack frame of the callback function:
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
)
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
);
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" );
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 */
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 */
1797 fprintf( outfile
,"\tdata16\n");
1799 fprintf( outfile
, "\tmovw " PREFIX
"IF1632_Saved16_ss,%%ss\n" );
1800 fprintf( outfile
, "\tmovw " PREFIX
"IF1632_Saved16_sp,%%sp\n" );
1802 /* Transfer the arguments */
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" );
1828 case 'w': /* word */
1829 fprintf( outfile
, "\tpushw %d(%%ebx)\n", pos
);
1831 case 'l': /* long */
1832 fprintf( outfile
, "\tpushl %d(%%ebx)\n", pos
);
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 */
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" );
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" );
1863 fprintf( outfile
, "\tdata16\n");
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 /*******************************************************************
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
);
1897 fprintf( outfile
, "\tdata16\n");
1899 fprintf( outfile
, "\tmovw %%bx,%%ds\n" );
1901 fprintf( outfile
, "\tdata16\n");
1903 fprintf( outfile
, "\tmovw %%bx,%%es\n" );
1905 fprintf( outfile
, "\tdata16\n");
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 /*******************************************************************
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 /*******************************************************************
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.
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 ))
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 );
2060 fprintf( stderr
, "Invalid function profile '%s', ignored\n", profile
);
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
);
2072 fprintf( outfile
, "\tleal 8(%%esp),%%ebp\n" );
2074 /* Transfer the arguments */
2076 if (reg_func
) BuildContext32( outfile
);
2081 for (i
= args
; i
> 0; i
--)
2082 fprintf( outfile
, "\tpushl %d(%%ebp)\n", 4 * i
+ 4 );
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 */
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 */
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 /*******************************************************************
2134 * Build a Wine-to-32-bit callback function.
2136 * Stack frame of the callback function:
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
);
2157 fprintf( outfile
, "\tpushl %%ebp\n" );
2158 fprintf( outfile
, "\tmovl %%esp,%%ebp\n" );
2160 /* Transfer arguments */
2165 for (i
= args
; i
> 0; i
--)
2166 fprintf( outfile
, "\tpushl %d(%%ebp)\n", 4 * i
+ 8 );
2169 /* Print the debugging output */
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 /*******************************************************************
2194 * Build the spec files
2196 static int BuildSpec( FILE *outfile
, int argc
, char *argv
[] )
2199 for (i
= 2; i
< argc
; i
++)
2200 if (BuildSpecFile( outfile
, argv
[i
] ) < 0) return -1;
2205 /*******************************************************************
2208 * Build the 16-bit-to-Wine callbacks
2210 static int BuildCallFrom16( FILE *outfile
, int argc
, char *argv
[] )
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 */
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 );
2242 /*******************************************************************
2245 * Build the Wine-to-16-bit callbacks
2247 static int BuildCallTo16( FILE *outfile
, int argc
, char *argv
[] )
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" );
2272 /*******************************************************************
2275 * Build the 32-bit-to-Wine callbacks
2277 static int BuildCallFrom32( FILE *outfile
, int argc
, char *argv
[] )
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
] );
2293 /*******************************************************************
2296 * Build the Wine-to-32-bit callbacks
2298 static int BuildCallTo32( FILE *outfile
, int argc
, char *argv
[] )
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
]) );
2314 /*******************************************************************
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");
2328 /*******************************************************************
2331 int main(int argc
, char **argv
)
2333 char *outname
= NULL
;
2334 FILE *outfile
= stdout
;
2337 if (argc
<= 2) usage();
2339 if (!strcmp( argv
[1], "-o" ))
2344 if (argc
<= 2) usage();
2345 if (!(outfile
= fopen( outname
, "w" )))
2347 fprintf( stderr
, "Unable to create output file '%s'\n", outname
);
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
);
2378 #endif /* WINELIB */