2 * Copyright 1993 Robert J. Amstadt
3 * Copyright 1995 Martin von Loewis
4 * Copyright 1995, 1996 Alexandre Julliard
13 #include "registers.h"
14 #include "winerror.h" /* for ERROR_CALL_NOT_IMPLEMENTED */
19 /* ELF symbols do not have an underscore in front */
20 #if defined (__ELF__) || defined (__svr4__) || defined(_SCO_DS)
26 #define TYPE_INVALID 0
27 #define TYPE_BYTE 1 /* byte variable */
28 #define TYPE_WORD 2 /* word variable */
29 #define TYPE_LONG 3 /* long variable */
30 #define TYPE_PASCAL_16 4 /* pascal function with 16-bit return (Win16) */
31 #define TYPE_PASCAL 5 /* pascal function with 32-bit return (Win16) */
32 #define TYPE_REGISTER 6 /* register function (Win16) */
33 #define TYPE_ABS 7 /* absolute value */
34 #define TYPE_RETURN 8 /* simple return value function */
35 #define TYPE_STUB 9 /* unimplemented stub */
36 #define TYPE_STDCALL 10 /* stdcall function (Win32) */
37 #define TYPE_CDECL 11 /* cdecl function (Win32) */
39 #define MAX_ORDINALS 1299
41 /* Callback function used for stub functions */
42 #define STUB_CALLBACK \
43 ((SpecType == SPEC_WIN16) ? "RELAY_Unimplemented16": "RELAY_Unimplemented32")
52 typedef struct ordinal_definition_s
57 void *additional_data
;
60 typedef struct ordinal_variable_definition_s
66 typedef struct ordinal_function_definition_s
70 char internal_name
[80];
73 typedef struct ordinal_return_definition_s
79 static ORDDEF OrdinalDefinitions
[MAX_ORDINALS
];
81 static enum SPEC_TYPE SpecType
= SPEC_INVALID
;
88 char *ParseBuffer
= NULL
;
93 static int debugging
= 1;
95 /* Offset of register relative to the end of the context struct */
96 #define CONTEXTOFFSET(reg) \
97 ((int)®##_reg((SIGCONTEXT *)0) - sizeof(SIGCONTEXT))
99 static void *xmalloc (size_t size
)
103 res
= malloc (size
? size
: 1);
106 fprintf (stderr
, "Virtual memory exhausted.\n");
113 static void *xrealloc (void *ptr
, size_t size
)
115 void *res
= realloc (ptr
, size
);
118 fprintf (stderr
, "Virtual memory exhausted.\n");
125 static int IsNumberString(char *s
)
134 static char *strupper(char *s
)
138 for(p
= s
; *p
!= '\0'; p
++)
144 static char * GetTokenInLine(void)
149 if (ParseNext
!= ParseBuffer
)
151 if (ParseSaveChar
== '\0')
153 *ParseNext
= ParseSaveChar
;
157 * Remove initial white space.
159 for (p
= ParseNext
; isspace(*p
); p
++)
162 if ((*p
== '\0') || (*p
== '#'))
169 if (*token
!= '(' && *token
!= ')')
170 while (*p
!= '\0' && *p
!= '(' && *p
!= ')' && !isspace(*p
))
180 static char * GetToken(void)
184 if (ParseBuffer
== NULL
)
186 ParseBuffer
= xmalloc(512);
187 ParseNext
= ParseBuffer
;
191 if (fgets(ParseBuffer
, 511, SpecFp
) == NULL
)
193 if (ParseBuffer
[0] != '#')
198 while ((token
= GetTokenInLine()) == NULL
)
200 ParseNext
= ParseBuffer
;
204 if (fgets(ParseBuffer
, 511, SpecFp
) == NULL
)
206 if (ParseBuffer
[0] != '#')
214 static int ParseVariable(int ordinal
, int type
)
218 char export_name
[80];
223 int value_array_size
;
225 strcpy(export_name
, GetToken());
230 fprintf(stderr
, "%d: Expected '(' got '%s'\n", Line
, token
);
235 value_array_size
= 25;
236 value_array
= xmalloc(sizeof(*value_array
) * value_array_size
);
238 while ((token
= GetToken()) != NULL
)
243 value_array
[n_values
++] = strtol(token
, &endptr
, 0);
244 if (n_values
== value_array_size
)
246 value_array_size
+= 25;
247 value_array
= xrealloc(value_array
,
248 sizeof(*value_array
) * value_array_size
);
251 if (endptr
== NULL
|| *endptr
!= '\0')
253 fprintf(stderr
, "%d: Expected number value, got '%s'\n", Line
,
261 fprintf(stderr
, "%d: End of file in variable declaration\n", Line
);
265 if (ordinal
>= MAX_ORDINALS
)
267 fprintf(stderr
, "%d: Ordinal number too large\n", Line
);
271 odp
= &OrdinalDefinitions
[ordinal
];
273 strcpy(odp
->export_name
, export_name
);
275 vdp
= xmalloc(sizeof(*vdp
));
276 odp
->additional_data
= vdp
;
278 vdp
->n_values
= n_values
;
279 vdp
->values
= xrealloc(value_array
, sizeof(*value_array
) * n_values
);
284 static int ParseExportFunction(int ordinal
, int type
)
294 if (type
== TYPE_STDCALL
)
296 fprintf( stderr
, "%d: 'stdcall' not supported for Win16\n", Line
);
299 if (type
== TYPE_CDECL
)
301 fprintf( stderr
, "%d: 'cdecl' not supported for Win16\n", Line
);
306 if ((type
== TYPE_PASCAL
) || (type
== TYPE_PASCAL_16
))
308 fprintf( stderr
, "%d: 'pascal' not supported for Win32\n", Line
);
315 odp
= &OrdinalDefinitions
[ordinal
];
316 strcpy(odp
->export_name
, GetToken());
318 fdp
= xmalloc(sizeof(*fdp
));
319 odp
->additional_data
= fdp
;
324 fprintf(stderr
, "%d: Expected '(' got '%s'\n", Line
, token
);
328 for (i
= 0; i
< sizeof(fdp
->arg_types
)-1; i
++)
334 if (!strcmp(token
, "byte") || !strcmp(token
, "word"))
335 fdp
->arg_types
[i
] = 'w';
336 else if (!strcmp(token
, "s_byte") || !strcmp(token
, "s_word"))
337 fdp
->arg_types
[i
] = 's';
338 else if (!strcmp(token
, "long") || !strcmp(token
, "segptr"))
339 fdp
->arg_types
[i
] = 'l';
340 else if (!strcmp(token
, "ptr"))
341 fdp
->arg_types
[i
] = 'p';
344 fprintf(stderr
, "%d: Unknown variable type '%s'\n", Line
, token
);
347 if (SpecType
== SPEC_WIN32
)
349 if (strcmp(token
, "long") && strcmp(token
, "ptr"))
351 fprintf( stderr
, "%d: Type '%s' not supported for Win32\n",
359 fprintf( stderr
, "%d: Too many arguments\n", Line
);
362 fdp
->arg_types
[i
] = '\0';
363 if ((type
== TYPE_STDCALL
) && !i
)
364 odp
->type
= TYPE_CDECL
; /* stdcall is the same as cdecl for 0 args */
365 strcpy(fdp
->internal_name
, GetToken());
369 static int ParseEquate(int ordinal
)
376 odp
= &OrdinalDefinitions
[ordinal
];
377 strcpy(odp
->export_name
, GetToken());
380 value
= strtol(token
, &endptr
, 0);
381 if (endptr
== NULL
|| *endptr
!= '\0')
383 fprintf(stderr
, "%d: Expected number value, got '%s'\n", Line
,
388 odp
->type
= TYPE_ABS
;
389 odp
->additional_data
= (void *) value
;
394 static int ParseReturn(int ordinal
)
401 rdp
= xmalloc(sizeof(*rdp
));
403 odp
= &OrdinalDefinitions
[ordinal
];
404 strcpy(odp
->export_name
, GetToken());
405 odp
->type
= TYPE_RETURN
;
406 odp
->additional_data
= rdp
;
409 rdp
->arg_size
= strtol(token
, &endptr
, 0);
410 if (endptr
== NULL
|| *endptr
!= '\0')
412 fprintf(stderr
, "%d: Expected number value, got '%s'\n", Line
,
418 rdp
->ret_value
= strtol(token
, &endptr
, 0);
419 if (endptr
== NULL
|| *endptr
!= '\0')
421 fprintf(stderr
, "%d: Expected number value, got '%s'\n", Line
,
430 static int ParseStub( int ordinal
)
435 odp
= &OrdinalDefinitions
[ordinal
];
436 strcpy( odp
->export_name
, GetToken() );
437 odp
->type
= TYPE_STUB
;
438 fdp
= xmalloc(sizeof(*fdp
));
439 odp
->additional_data
= fdp
;
440 fdp
->arg_types
[0] = '\0';
441 strcpy( fdp
->internal_name
, STUB_CALLBACK
);
446 static int ParseOrdinal(int ordinal
)
450 if (ordinal
>= MAX_ORDINALS
)
452 fprintf(stderr
, "%d: Ordinal number too large\n", Line
);
455 if (ordinal
> Limit
) Limit
= ordinal
;
460 fprintf(stderr
, "%d: Expected type after ordinal\n", Line
);
464 if (strcmp(token
, "byte") == 0)
465 return ParseVariable(ordinal
, TYPE_BYTE
);
466 if (strcmp(token
, "word") == 0)
467 return ParseVariable(ordinal
, TYPE_WORD
);
468 if (strcmp(token
, "long") == 0)
469 return ParseVariable(ordinal
, TYPE_LONG
);
470 if (strcmp(token
, "pascal") == 0)
471 return ParseExportFunction(ordinal
, TYPE_PASCAL
);
472 if (strcmp(token
, "pascal16") == 0)
473 return ParseExportFunction(ordinal
, TYPE_PASCAL_16
);
474 if (strcmp(token
, "register") == 0)
475 return ParseExportFunction(ordinal
, TYPE_REGISTER
);
476 if (strcmp(token
, "stdcall") == 0)
477 return ParseExportFunction(ordinal
, TYPE_STDCALL
);
478 if (strcmp(token
, "cdecl") == 0)
479 return ParseExportFunction(ordinal
, TYPE_CDECL
);
480 if (strcmp(token
, "equate") == 0)
481 return ParseEquate(ordinal
);
482 if (strcmp(token
, "return") == 0)
483 return ParseReturn(ordinal
);
484 if (strcmp(token
, "stub") == 0)
485 return ParseStub(ordinal
);
487 "%d: Expected type after ordinal, found '%s' instead\n",
492 static int ParseTopLevel(void)
496 while ((token
= GetToken()) != NULL
)
498 if (strcmp(token
, "name") == 0)
500 strcpy(DLLName
, GetToken());
503 else if (strcmp(token
, "type") == 0)
506 if (!strcmp(token
, "win16" )) SpecType
= SPEC_WIN16
;
507 else if (!strcmp(token
, "win32" )) SpecType
= SPEC_WIN32
;
510 fprintf(stderr
, "%d: Type must be 'win16' or 'win32'\n", Line
);
514 else if (strcmp(token
, "base") == 0)
517 if (!IsNumberString(token
))
519 fprintf(stderr
, "%d: Expected number after base\n", Line
);
524 else if (strcmp(token
, "heap") == 0)
527 if (!IsNumberString(token
))
529 fprintf(stderr
, "%d: Expected number after heap\n", Line
);
532 DLLHeapSize
= atoi(token
);
534 else if (IsNumberString(token
))
539 ordinal
= atoi(token
);
540 if ((rv
= ParseOrdinal(ordinal
)) < 0)
546 "%d: Expected name, id, length or ordinal\n", Line
);
555 /*******************************************************************
558 * Store a list of ints into a byte array.
560 static int StoreVariableCode( unsigned char *buffer
, int size
, ORDDEF
*odp
)
565 vdp
= odp
->additional_data
;
569 for (i
= 0; i
< vdp
->n_values
; i
++)
570 buffer
[i
] = vdp
->values
[i
];
573 for (i
= 0; i
< vdp
->n_values
; i
++)
574 ((unsigned short *)buffer
)[i
] = vdp
->values
[i
];
577 for (i
= 0; i
< vdp
->n_values
; i
++)
578 ((unsigned int *)buffer
)[i
] = vdp
->values
[i
];
581 return vdp
->n_values
* size
;
585 /*******************************************************************
588 * Dump a byte stream into the assembly code.
590 static void DumpBytes( const unsigned char *data
, int len
,
591 const char *section
, const char *label_start
)
594 if (section
) printf( "\t%s\n", section
);
595 if (label_start
) printf( "%s:\n", label_start
);
596 for (i
= 0; i
< len
; i
++)
598 if (!(i
& 0x0f)) printf( "\t.byte " );
599 printf( "%d", *data
++ );
600 if (i
< len
- 1) printf( "%c", ((i
& 0x0f) != 0x0f) ? ',' : '\n' );
606 /*******************************************************************
609 * Build the in-memory representation of a 16-bit NE module, and dump it
610 * as a byte stream into the assembly code.
612 static int BuildModule16( int max_code_offset
, int max_data_offset
)
618 SEGTABLEENTRY
*pSegment
;
625 * OFSTRUCT File information
626 * SEGTABLEENTRY Segment 1 (code)
627 * SEGTABLEENTRY Segment 2 (data)
628 * WORD[2] Resource table (empty)
629 * BYTE[2] Imported names (empty)
630 * BYTE[n] Resident names table
631 * BYTE[n] Entry table
634 buffer
= xmalloc( 0x10000 );
636 pModule
= (NE_MODULE
*)buffer
;
637 pModule
->magic
= NE_SIGNATURE
;
640 pModule
->flags
= NE_FFLAGS_SINGLEDATA
| NE_FFLAGS_BUILTIN
| NE_FFLAGS_LIBMODULE
;
642 pModule
->heap_size
= DLLHeapSize
;
643 pModule
->stack_size
= 0;
648 pModule
->seg_count
= 2;
649 pModule
->modref_count
= 0;
650 pModule
->nrname_size
= 0;
651 pModule
->modref_table
= 0;
652 pModule
->nrname_fpos
= 0;
653 pModule
->moveable_entries
= 0;
654 pModule
->alignment
= 0;
655 pModule
->truetype
= 0;
656 pModule
->os_flags
= NE_OSFLAGS_WINDOWS
;
657 pModule
->misc_flags
= 0;
658 pModule
->dlls_to_init
= 0;
659 pModule
->nrname_handle
= 0;
660 pModule
->min_swap_area
= 0;
661 pModule
->expected_version
= 0x030a;
662 pModule
->pe_module
= NULL
;
664 pModule
->self_loading_sel
= 0;
666 /* File information */
668 pFileInfo
= (OFSTRUCT
*)(pModule
+ 1);
669 pModule
->fileinfo
= (int)pFileInfo
- (int)pModule
;
670 memset( pFileInfo
, 0, sizeof(*pFileInfo
) - sizeof(pFileInfo
->szPathName
) );
671 pFileInfo
->cBytes
= sizeof(*pFileInfo
) - sizeof(pFileInfo
->szPathName
)
672 + strlen(DLLName
) + 4;
673 sprintf( pFileInfo
->szPathName
, "%s.DLL", DLLName
);
674 pstr
= (char *)pFileInfo
+ pFileInfo
->cBytes
+ 1;
678 pSegment
= (SEGTABLEENTRY
*)pstr
;
679 pModule
->seg_table
= (int)pSegment
- (int)pModule
;
680 pSegment
->filepos
= 0;
681 pSegment
->size
= max_code_offset
;
683 pSegment
->minsize
= max_code_offset
;
684 pSegment
->selector
= 0;
687 pModule
->dgroup_entry
= (int)pSegment
- (int)pModule
;
688 pSegment
->filepos
= 0;
689 pSegment
->size
= max_data_offset
;
690 pSegment
->flags
= NE_SEGFLAGS_DATA
;
691 pSegment
->minsize
= max_data_offset
;
692 pSegment
->selector
= 0;
697 pword
= (WORD
*)pSegment
;
698 pModule
->res_table
= (int)pword
- (int)pModule
;
702 /* Imported names table */
704 pstr
= (char *)pword
;
705 pModule
->import_table
= (int)pstr
- (int)pModule
;
709 /* Resident names table */
711 pModule
->name_table
= (int)pstr
- (int)pModule
;
712 /* First entry is module name */
713 *pstr
= strlen(DLLName
);
714 strcpy( pstr
+ 1, DLLName
);
717 pstr
+= sizeof(WORD
);
718 /* Store all ordinals */
719 odp
= OrdinalDefinitions
+ 1;
720 for (i
= 1; i
<= Limit
; i
++, odp
++)
722 if (!odp
->export_name
[0]) continue;
723 *pstr
= strlen( odp
->export_name
);
724 strcpy( pstr
+ 1, odp
->export_name
);
725 strupper( pstr
+ 1 );
728 pstr
+= sizeof(WORD
);
734 pModule
->entry_table
= (int)pstr
- (int)pModule
;
736 odp
= OrdinalDefinitions
+ 1;
737 for (i
= 1; i
<= Limit
; i
++, odp
++)
744 selector
= 0; /* Invalid selector */
752 selector
= 1; /* Code selector */
758 selector
= 2; /* Data selector */
762 selector
= 0xfe; /* Constant selector */
766 /* create a new bundle if necessary */
767 if (!bundle
|| (bundle
[0] >= 254) || (bundle
[1] != selector
))
771 bundle
[1] = selector
;
779 *(WORD
*)pstr
= odp
->offset
;
780 pstr
+= sizeof(WORD
);
785 /* Dump the module content */
787 DumpBytes( (char *)pModule
, (int)pstr
- (int)pModule
,
788 ".data", "Module_Start" );
789 return (int)pstr
- (int)pModule
;
793 /*******************************************************************
796 * Build the in-memory representation of a 32-bit pseudo-NE module, and dump it
797 * as a byte stream into the assembly code.
799 static int BuildModule32(void)
809 * OFSTRUCT File information
810 * SEGTABLEENTRY Segment table (empty)
811 * WORD[2] Resource table (empty)
812 * BYTE[2] Imported names (empty)
813 * BYTE[n] Resident names table (1 entry)
814 * BYTE[n] Entry table (empty)
817 buffer
= xmalloc( 0x10000 );
819 pModule
= (NE_MODULE
*)buffer
;
820 pModule
->magic
= NE_SIGNATURE
;
823 pModule
->dgroup_entry
= 0;
824 pModule
->flags
= NE_FFLAGS_SINGLEDATA
| NE_FFLAGS_BUILTIN
|
825 NE_FFLAGS_LIBMODULE
| NE_FFLAGS_WIN32
;
827 pModule
->heap_size
= DLLHeapSize
;
828 pModule
->stack_size
= 0;
833 pModule
->seg_count
= 0;
834 pModule
->modref_count
= 0;
835 pModule
->nrname_size
= 0;
836 pModule
->modref_table
= 0;
837 pModule
->nrname_fpos
= 0;
838 pModule
->moveable_entries
= 0;
839 pModule
->alignment
= 0;
840 pModule
->truetype
= 0;
841 pModule
->os_flags
= NE_OSFLAGS_WINDOWS
;
842 pModule
->misc_flags
= 0;
843 pModule
->dlls_to_init
= 0;
844 pModule
->nrname_handle
= 0;
845 pModule
->min_swap_area
= 0;
846 pModule
->expected_version
= 0x030a;
847 pModule
->pe_module
= NULL
;
849 pModule
->self_loading_sel
= 0;
851 /* File information */
853 pFileInfo
= (OFSTRUCT
*)(pModule
+ 1);
854 pModule
->fileinfo
= (int)pFileInfo
- (int)pModule
;
855 memset( pFileInfo
, 0, sizeof(*pFileInfo
) - sizeof(pFileInfo
->szPathName
) );
856 pFileInfo
->cBytes
= sizeof(*pFileInfo
) - sizeof(pFileInfo
->szPathName
)
857 + strlen(DLLName
) + 4;
858 sprintf( pFileInfo
->szPathName
, "%s.DLL", DLLName
);
859 pstr
= (char *)pFileInfo
+ pFileInfo
->cBytes
+ 1;
863 pModule
->seg_table
= (int)pstr
- (int)pModule
;
867 pword
= (WORD
*)pstr
;
868 pModule
->res_table
= (int)pword
- (int)pModule
;
872 /* Imported names table */
874 pstr
= (char *)pword
;
875 pModule
->import_table
= (int)pstr
- (int)pModule
;
879 /* Resident names table */
881 pModule
->name_table
= (int)pstr
- (int)pModule
;
882 /* First entry is module name */
883 *pstr
= strlen(DLLName
);
884 strcpy( pstr
+ 1, DLLName
);
887 pstr
+= sizeof(WORD
);
892 pModule
->entry_table
= (int)pstr
- (int)pModule
;
895 /* Dump the module content */
897 DumpBytes( (char *)pModule
, (int)pstr
- (int)pModule
,
898 ".data", "Module_Start" );
899 return (int)pstr
- (int)pModule
;
903 /*******************************************************************
906 * Build a Win32 assembly file from a spec file.
908 static void BuildSpec32Files(void)
913 int i
, module_size
, len
;
916 printf( "/* File generated automatically; do not edit! */\n" );
917 printf( "\t.text\n" );
918 printf( "\t.align 4\n" );
919 printf( "Code_Start:\n\n" );
921 odp
= OrdinalDefinitions
;
922 for (i
= 0; i
<= Limit
; i
++, odp
++)
924 fdp
= odp
->additional_data
;
925 rdp
= odp
->additional_data
;
935 printf( "/* %s.%d (%s) */\n",
936 DLLName
, i
, odp
->export_name
);
937 printf( "%s_%d:\n", DLLName
, i
);
938 printf( "\tpushl %%ebp\n" );
939 printf( "\tpushl $" PREFIX
"%s\n", fdp
->internal_name
);
940 printf( "\tcall " PREFIX
"CallFrom32_%s_%d\n",
941 (odp
->type
== TYPE_STDCALL
) ? "stdcall" : "cdecl",
942 strlen(fdp
->arg_types
));
947 printf( "/* %s.%d (%s) */\n",
948 DLLName
, i
, odp
->export_name
);
949 printf( "%s_%d:\n", DLLName
, i
);
950 printf( "\tmovl $%d,%%eax\n", ERROR_CALL_NOT_IMPLEMENTED
);
951 printf( "\tmovl %%eax," PREFIX
"WIN32_LastError\n" );
952 printf( "\tmovl $%d,%%eax\n", rdp
->ret_value
);
955 printf( "\tret $%d\n", rdp
->arg_size
);
959 else printf( "\tret\n" );
963 printf( "/* %s.%d (%s) */\n",
964 DLLName
, i
, odp
->export_name
);
965 printf( "\t.data\n" );
966 printf( "%s_%d:\n", DLLName
, i
);
967 len
= StoreVariableCode( buffer
, 1, odp
);
968 DumpBytes( buffer
, len
, NULL
, NULL
);
969 printf( "\t.text\n" );
973 printf( "/* %s.%d (%s) */\n",
974 DLLName
, i
, odp
->export_name
);
975 printf( "\t.data\n" );
976 printf( "%s_%d:\n", DLLName
, i
);
977 len
= StoreVariableCode( buffer
, 2, odp
);
978 DumpBytes( buffer
, len
, NULL
, NULL
);
979 printf( "\t.text\n" );
983 printf( "/* %s.%d (%s) */\n",
984 DLLName
, i
, odp
->export_name
);
985 printf( "\t.data\n" );
986 printf( "%s_%d:\n", DLLName
, i
);
987 len
= StoreVariableCode( buffer
, 4, odp
);
988 DumpBytes( buffer
, len
, NULL
, NULL
);
989 printf( "\t.text\n" );
993 fprintf(stderr
,"build: function type %d not available for Win32\n",
999 module_size
= BuildModule32();
1001 /* Output the DLL functions table */
1003 printf( "\t.text\n" );
1004 printf( "\t.align 4\n" );
1005 printf( "Functions:\n" );
1006 odp
= OrdinalDefinitions
;
1007 for (i
= 0; i
<= Limit
; i
++, odp
++)
1009 if (odp
->type
== TYPE_INVALID
) printf( "\t.long 0\n" );
1010 else printf("\t.long %s_%d\n", DLLName
, i
);
1013 /* Output the DLL names table */
1015 printf( "FuncNames:\n" );
1016 odp
= OrdinalDefinitions
;
1017 for (i
= 0; i
<= Limit
; i
++, odp
++)
1019 if (odp
->type
== TYPE_INVALID
) printf( "\t.long 0\n" );
1020 else printf( "\t.long Name_%d\n", i
);
1023 /* Output the DLL names */
1025 for (i
= 0, odp
= OrdinalDefinitions
; i
<= Limit
; i
++, odp
++)
1027 if (odp
->type
!= TYPE_INVALID
)
1028 printf( "Name_%d:\t.ascii \"%s\\0\"\n", i
, odp
->export_name
);
1031 /* Output the DLL descriptor */
1033 printf( "DLLName:\t.ascii \"%s\\0\"\n", DLLName
);
1034 printf( "\t.align 4\n" );
1035 printf( "\t.globl " PREFIX
"%s_Descriptor\n", DLLName
);
1036 printf( PREFIX
"%s_Descriptor:\n", DLLName
);
1037 printf( "\t.long DLLName\n" ); /* Name */
1038 printf( "\t.long Module_Start\n" ); /* Module start */
1039 printf( "\t.long %d\n", module_size
); /* Module size */
1040 printf( "\t.long %d\n", Base
); /* Base */
1041 printf( "\t.long %d\n", Limit
); /* Limit */
1042 printf( "\t.long Functions\n" ); /* Functions */
1043 printf( "\t.long FuncNames\n" ); /* Function names */
1047 /*******************************************************************
1050 * Build a Win16 assembly file from a spec file.
1052 static void BuildSpec16Files(void)
1058 int code_offset
, data_offset
, module_size
;
1059 unsigned char *data
;
1061 data
= (unsigned char *)xmalloc( 0x10000 );
1062 memset( data
, 0, 16 );
1065 printf( "/* File generated automatically; do not edit! */\n" );
1066 printf( "\t.text\n" );
1067 printf( "Code_Start:\n" );
1070 odp
= OrdinalDefinitions
;
1071 for (i
= 0; i
<= Limit
; i
++, odp
++)
1073 fdp
= odp
->additional_data
;
1074 rdp
= odp
->additional_data
;
1079 odp
->offset
= 0xffff;
1083 odp
->offset
= (int)odp
->additional_data
& 0xffff;
1087 odp
->offset
= data_offset
;
1088 data_offset
+= StoreVariableCode( data
+ data_offset
, 1, odp
);
1092 odp
->offset
= data_offset
;
1093 data_offset
+= StoreVariableCode( data
+ data_offset
, 2, odp
);
1097 odp
->offset
= data_offset
;
1098 data_offset
+= StoreVariableCode( data
+ data_offset
, 4, odp
);
1102 printf( "/* %s.%d */\n", DLLName
, i
);
1103 printf( "\tmovw $%d,%%ax\n", rdp
->ret_value
& 0xffff );
1104 printf( "\tmovw $%d,%%dx\n", (rdp
->ret_value
>> 16) & 0xffff);
1105 printf( "\t.byte 0x66\n");
1106 if (rdp
->arg_size
!= 0)
1107 printf( "\tlret $%d\n\n", rdp
->arg_size
);
1110 printf( "\tlret\n");
1112 printf( "\tnop\n\n");
1114 odp
->offset
= code_offset
;
1115 code_offset
+= 12; /* Assembly code is 12 bytes long */
1120 case TYPE_PASCAL_16
:
1122 printf( "/* %s.%d */\n", DLLName
, i
);
1123 printf( "\tpushw %%bp\n" );
1124 printf( "\tpushl $" PREFIX
"%s\n", fdp
->internal_name
);
1125 /* FreeBSD does not understand lcall, so do it the hard way */
1126 printf( "\t.byte 0x9a /*lcall*/\n" );
1127 printf( "\t.long " PREFIX
"CallFrom16_%s_%s\n",
1128 (odp
->type
== TYPE_REGISTER
) ? "regs" :
1129 (odp
->type
== TYPE_PASCAL
) ? "long" : "word",
1131 printf( "\t.byte 0x%02x,0x%02x\n", /* Some asms don't have .word */
1132 LOBYTE(WINE_CODE_SELECTOR
), HIBYTE(WINE_CODE_SELECTOR
) );
1133 printf( "\tnop\n" );
1134 printf( "\tnop\n\n" );
1135 odp
->offset
= code_offset
;
1136 code_offset
+= 16; /* Assembly code is 16 bytes long */
1140 fprintf(stderr
,"build: function type %d not available for Win16\n",
1146 if (!code_offset
) /* Make sure the code segment is not empty */
1148 printf( "\t.byte 0\n" );
1152 /* Output data segment */
1154 DumpBytes( data
, data_offset
, NULL
, "Data_Start" );
1156 /* Build the module */
1158 module_size
= BuildModule16( code_offset
, data_offset
);
1160 /* Output the DLL descriptor */
1162 printf( "\t.text\n" );
1163 printf( "DLLName:\t.ascii \"%s\\0\"\n", DLLName
);
1164 printf( "\t.align 4\n" );
1165 printf( "\t.globl " PREFIX
"%s_Descriptor\n", DLLName
);
1166 printf( PREFIX
"%s_Descriptor:\n", DLLName
);
1167 printf( "\t.long DLLName\n" ); /* Name */
1168 printf( "\t.long Module_Start\n" ); /* Module start */
1169 printf( "\t.long %d\n", module_size
); /* Module size */
1170 printf( "\t.long Code_Start\n" ); /* Code start */
1171 printf( "\t.long Data_Start\n" ); /* Data start */
1175 /*******************************************************************
1178 * Build an assembly file from a spec file.
1180 static void BuildSpecFiles( char *specname
)
1182 SpecFp
= fopen( specname
, "r");
1185 fprintf(stderr
, "Could not open specification file, '%s'\n", specname
);
1193 fprintf( stderr
, "%s: Missing 'type' declaration\n", specname
);
1205 /*******************************************************************
1206 * BuildCall32LargeStack
1208 * Build the function used to switch to the original 32-bit stack
1209 * before calling a 32-bit function from 32-bit code. This is used for
1210 * functions that need a large stack, like X bitmaps functions.
1212 * The generated function has the following prototype:
1213 * int CallTo32_LargeStack( int (*func)(), int nbargs, ... )
1224 static void BuildCall32LargeStack(void)
1226 /* Function header */
1228 printf( "/**********\n" );
1229 printf( " * " PREFIX
"CallTo32_LargeStack\n" );
1230 printf( " **********/\n" );
1231 printf( "\t.align 4\n" );
1232 printf( "\t.globl " PREFIX
"CallTo32_LargeStack\n\n" );
1233 printf( PREFIX
"CallTo32_LargeStack:\n" );
1237 printf( "\tpushl %%ebp\n" );
1238 printf( "\tmovl %%esp,%%ebp\n" );
1240 /* Save registers */
1242 printf( "\tpushl %%ecx\n" );
1243 printf( "\tpushl %%esi\n" );
1244 printf( "\tpushl %%edi\n" );
1246 /* Retrieve the original 32-bit stack pointer and switch to it if any */
1248 printf( "\tmovl " PREFIX
"IF1632_Original32_esp, %%eax\n" );
1249 printf( "\torl %%eax,%%eax\n" );
1250 printf( "\tje no_orig_esp\n" );
1251 printf( "\tmovl %%eax,%%esp\n" );
1252 printf( "no_orig_esp:\n" );
1254 /* Transfer the arguments */
1256 printf( "\tmovl 12(%%ebp),%%ecx\n" );
1257 printf( "\torl %%ecx,%%ecx\n" );
1258 printf( "\tje no_args\n" );
1259 printf( "\tleal 16(%%ebp),%%esi\n" );
1260 printf( "\tshll $2,%%ecx\n" );
1261 printf( "\tsubl %%ecx,%%esp\n" );
1262 printf( "\tmovl %%esp,%%edi\n" );
1263 printf( "\tshrl $2,%%ecx\n" );
1264 printf( "\tcld\n" );
1265 printf( "\trep; movsl\n" );
1266 printf( "no_args:\n" );
1268 /* Call the function */
1270 printf( "\tcall 8(%%ebp)\n" );
1272 /* Switch back to the normal stack */
1274 printf( "\tleal -12(%%ebp),%%esp\n" );
1276 /* Restore registers and return */
1278 printf( "\tpopl %%edi\n" );
1279 printf( "\tpopl %%esi\n" );
1280 printf( "\tpopl %%ecx\n" );
1281 printf( "\tpopl %%ebp\n" );
1282 printf( "\tret\n" );
1286 /*******************************************************************
1287 * TransferArgs16To32
1289 * Get the arguments from the 16-bit stack and push them on the 32-bit stack.
1290 * The 16-bit stack layout is:
1298 static int TransferArgs16To32( char *args
)
1300 int i
, pos16
, pos32
;
1302 /* Save ebx first */
1304 printf( "\tpushl %%ebx\n" );
1306 /* Get the 32-bit stack pointer */
1308 printf( "\tmovl " PREFIX
"IF1632_Saved32_esp,%%ebx\n" );
1310 /* Copy the arguments */
1312 pos16
= 6; /* skip bp and return address */
1315 for (i
= strlen(args
); i
> 0; i
--)
1320 case 'w': /* word */
1321 printf( "\tmovzwl %d(%%ebp),%%eax\n", pos16
);
1322 printf( "\tmovl %%eax,%d(%%ebx)\n", pos32
);
1326 case 's': /* s_word */
1327 printf( "\tmovswl %d(%%ebp),%%eax\n", pos16
);
1328 printf( "\tmovl %%eax,%d(%%ebx)\n", pos32
);
1332 case 'l': /* long */
1333 printf( "\tmovl %d(%%ebp),%%eax\n", pos16
);
1334 printf( "\tmovl %%eax,%d(%%ebx)\n", pos32
);
1339 /* Get the selector */
1340 printf( "\tmovw %d(%%ebp),%%ax\n", pos16
+ 2 );
1341 /* Get the selector base */
1342 printf( "\tandl $0xfff8,%%eax\n" );
1343 printf( "\tmovl " PREFIX
"ldt_copy(%%eax),%%eax\n" );
1344 printf( "\tmovl %%eax,%d(%%ebx)\n", pos32
);
1345 /* Add the offset */
1346 printf( "\tmovzwl %d(%%ebp),%%eax\n", pos16
);
1347 printf( "\taddl %%eax,%d(%%ebx)\n", pos32
);
1352 fprintf( stderr
, "Unknown arg type '%c'\n", args
[i
-1] );
1358 printf( "\tpopl %%ebx\n" );
1360 return pos16
- 6; /* Return the size of the 16-bit args */
1364 /*******************************************************************
1367 * Build the context structure on the 32-bit stack.
1368 * The only valid registers in the context structure are:
1369 * eax, ebx, ecx, edx, esi, edi, ds, es, (some of the) flags
1371 static void BuildContext(void)
1373 /* Save ebx first */
1375 printf( "\tpushl %%ebx\n" );
1377 /* Get the 32-bit stack pointer */
1379 printf( "\tmovl " PREFIX
"IF1632_Saved32_esp,%%ebx\n" );
1381 /* Store the registers */
1383 printf( "\tpopl %d(%%ebx)\n", CONTEXTOFFSET(EBX
) ); /* Get ebx from stack*/
1384 printf( "\tmovl %%eax,%d(%%ebx)\n", CONTEXTOFFSET(EAX
) );
1385 printf( "\tmovl %%ecx,%d(%%ebx)\n", CONTEXTOFFSET(ECX
) );
1386 printf( "\tmovl %%edx,%d(%%ebx)\n", CONTEXTOFFSET(EDX
) );
1387 printf( "\tmovl %%esi,%d(%%ebx)\n", CONTEXTOFFSET(ESI
) );
1388 printf( "\tmovl %%edi,%d(%%ebx)\n", CONTEXTOFFSET(EDI
) );
1389 printf( "\tmovw -10(%%ebp),%%ax\n" ); /* Get saved ds from stack */
1390 printf( "\tmovw %%ax,%d(%%ebx)\n", CONTEXTOFFSET(DS
) );
1391 printf( "\tmovw -6(%%ebp),%%ax\n" ); /* Get saved es from stack */
1392 printf( "\tmovw %%ax,%d(%%ebx)\n", CONTEXTOFFSET(ES
) );
1393 printf( "\tpushfl\n" );
1394 printf( "\tpopl %d(%%ebx)\n", CONTEXTOFFSET(EFL
) );
1398 /*******************************************************************
1401 * Restore the registers from the context structure
1403 static void RestoreContext(void)
1405 /* Get the 32-bit stack pointer */
1407 printf( "\tmovl " PREFIX
"IF1632_Saved32_esp,%%ebx\n" );
1409 /* Restore the registers */
1411 printf( "\tmovl %d(%%ebx),%%ecx\n", CONTEXTOFFSET(ECX
) );
1412 printf( "\tmovl %d(%%ebx),%%edx\n", CONTEXTOFFSET(EDX
) );
1413 printf( "\tmovl %d(%%ebx),%%esi\n", CONTEXTOFFSET(ESI
) );
1414 printf( "\tmovl %d(%%ebx),%%edi\n", CONTEXTOFFSET(EDI
) );
1415 printf( "\tpopl %%eax\n" ); /* Remove old ds and ip from stack */
1416 printf( "\tpopl %%eax\n" ); /* Remove old cs and es from stack */
1417 printf( "\tpushw %d(%%ebx)\n", CONTEXTOFFSET(DS
) ); /* Push new ds */
1418 printf( "\tpushw %d(%%ebx)\n", CONTEXTOFFSET(ES
) ); /* Push new es */
1419 printf( "\tpushl %d(%%ebx)\n", CONTEXTOFFSET(EFL
) );
1420 printf( "\tpopfl\n" );
1421 printf( "\tmovl %d(%%ebx),%%eax\n", CONTEXTOFFSET(EAX
) );
1422 printf( "\tmovl %d(%%ebx),%%ebx\n", CONTEXTOFFSET(EBX
) );
1426 /*******************************************************************
1427 * BuildCallFrom16Func
1429 * Build a 16-bit-to-Wine callback function. The syntax of the function
1430 * profile is: type_xxxxx, where 'type' is one of 'regs', 'word' or
1431 * 'long' and each 'x' is an argument ('w'=word, 's'=signed word,
1432 * 'l'=long, 'p'=pointer).
1433 * For register functions, the arguments are ignored, but they are still
1434 * removed from the stack upon return.
1436 * Stack layout upon entry to the callback function:
1438 * (sp+18) word first 16-bit arg
1442 * (sp+8) long 32-bit entry point
1443 * (sp+6) word high word of cs (always 0, used to store es)
1444 * (sp+4) word low word of cs of 16-bit entry point
1445 * (sp+2) word high word of ip (always 0, used to store ds)
1446 * (sp) word low word of ip of 16-bit entry point
1449 static void BuildCallFrom16Func( char *profile
)
1454 char *args
= profile
+ 5;
1456 /* Parse function type */
1458 if (!strncmp( "word_", profile
, 5 )) short_ret
= 1;
1459 else if (!strncmp( "regs_", profile
, 5 )) reg_func
= 1;
1460 else if (strncmp( "long_", profile
, 5 ))
1462 fprintf( stderr
, "Invalid function name '%s', ignored\n", profile
);
1466 /* Function header */
1468 printf( "/**********\n" );
1469 printf( " * " PREFIX
"CallFrom16_%s\n", profile
);
1470 printf( " **********/\n" );
1471 printf( "\t.align 4\n" );
1472 printf( "\t.globl " PREFIX
"CallFrom16_%s\n\n", profile
);
1473 printf( PREFIX
"CallFrom16_%s:\n", profile
);
1475 /* Setup bp to point to its copy on the stack */
1477 printf( "\tmovzwl %%sp,%%ebp\n" );
1478 printf( "\taddw $12,%%bp\n" );
1480 /* Save 16-bit ds and es */
1482 /* Stupid FreeBSD assembler doesn't know these either */
1483 /* printf( "\tmovw %%ds,-10(%%ebp)\n" ); */
1484 printf( "\t.byte 0x66,0x8c,0x5d,0xf6\n" );
1485 /* printf( "\tmovw %%es,-6(%%ebp)\n" ); */
1486 printf( "\t.byte 0x66,0x8c,0x45,0xfa\n" );
1488 /* Restore 32-bit ds and es */
1490 printf( "\tpushl $0x%04x%04x\n", WINE_DATA_SELECTOR
, WINE_DATA_SELECTOR
);
1491 printf( "\tpopw %%ds\n" );
1492 printf( "\tpopw %%es\n" );
1495 /* Save the 16-bit stack */
1497 printf( "\tpushw " PREFIX
"IF1632_Saved16_sp\n" );
1498 printf( "\tpushw " PREFIX
"IF1632_Saved16_ss\n" );
1500 printf("\tdata16\n");
1502 printf( "\tmovw %%ss," PREFIX
"IF1632_Saved16_ss\n" );
1503 printf( "\tmovw %%sp," PREFIX
"IF1632_Saved16_sp\n" );
1505 /* Transfer the arguments */
1507 if (reg_func
) BuildContext();
1508 else if (*args
) argsize
= TransferArgs16To32( args
);
1510 /* Get the address of the API function */
1512 printf( "\tmovl -4(%%ebp),%%eax\n" );
1514 /* If necessary, save %edx over the API function address */
1516 if (!reg_func
&& short_ret
)
1517 printf( "\tmovl %%edx,-4(%%ebp)\n" );
1519 /* Switch to the 32-bit stack */
1521 printf( "\tmovl " PREFIX
"IF1632_Saved32_esp,%%ebp\n" );
1522 printf( "\tpushw %%ds\n" );
1523 printf( "\tpopw %%ss\n" );
1524 printf( "\tleal -%d(%%ebp),%%esp\n",
1525 reg_func
? sizeof(SIGCONTEXT
) : 4 * strlen(args
) );
1526 if (reg_func
) /* Push the address of the context struct */
1527 printf( "\tpushl %%esp\n" );
1529 /* Setup %ebp to point to the previous stack frame (built by CallTo16) */
1531 printf( "\taddl $24,%%ebp\n" );
1533 /* Print the debug information before the call */
1537 printf( "\tpushl %%eax\n" );
1538 printf( "\tpushl $Profile_%s\n", profile
);
1539 printf( "\tpushl $%d\n", reg_func
? 2 : (short_ret
? 1 : 0) );
1540 printf( "\tcall " PREFIX
"RELAY_DebugCallFrom16\n" );
1541 printf( "\tpopl %%eax\n" );
1542 printf( "\tpopl %%eax\n" );
1543 printf( "\tpopl %%eax\n" );
1546 /* Call the entry point */
1548 printf( "\tcall %%eax\n" );
1550 /* Print the debug information after the call */
1554 printf( "\tpushl %%eax\n" );
1555 printf( "\tpushl $%d\n", reg_func
? 2 : (short_ret
? 1 : 0) );
1556 printf( "\tcall " PREFIX
"RELAY_DebugCallFrom16Ret\n" );
1557 printf( "\tpopl %%eax\n" );
1558 printf( "\tpopl %%eax\n" );
1561 /* Restore the 16-bit stack */
1564 printf( "\tdata16\n");
1566 printf( "\tmovw " PREFIX
"IF1632_Saved16_ss,%%ss\n" );
1567 printf( "\tmovw " PREFIX
"IF1632_Saved16_sp,%%sp\n" );
1569 printf( "\tdata16\n");
1571 printf( "\tpopw " PREFIX
"IF1632_Saved16_ss\n" );
1573 printf( "\tdata16\n");
1575 printf( "\tpopw " PREFIX
"IF1632_Saved16_sp\n" );
1579 /* Restore registers from the context structure */
1582 /* Calc the arguments size */
1596 fprintf( stderr
, "Unknown arg type '%c'\n", *args
);
1601 /* Restore ds and es */
1602 printf( "\tpopw %%es\n" );
1603 printf( "\tpopw %%ds\n" );
1605 /* Remove the entry point from the stack */
1606 /* (we don't use add to avoid modifying the carry flag) */
1607 printf( "\tpopl %%ebp\n" );
1611 /* Restore ds and es */
1612 printf( "\tpopw %%bp\n" ); /* Remove ip */
1613 printf( "\tpopl %%ebp\n" ); /* Remove ds and cs */
1614 printf( "\tmovw %%bp,%%ds\n" ); /* Restore ds */
1615 printf( "\tpopw %%es\n" ); /* Restore es */
1617 if (short_ret
) printf( "\tpopl %%edx\n" ); /* Restore edx */
1620 /* Get the return value into dx:ax */
1621 printf( "\tpushl %%eax\n" );
1622 printf( "\tpopw %%ax\n" );
1623 printf( "\tpopw %%dx\n" );
1624 /* Remove API entry point */
1625 printf( "\taddl $4,%%esp\n" );
1631 printf( "\tpopw %%bp\n" );
1633 /* Remove the arguments and return */
1637 printf( "\t.byte 0x66\n" );
1638 printf( "\tlret $%d\n", argsize
);
1642 printf( "\t.byte 0x66\n" );
1643 printf( "\tlret\n" );
1648 /*******************************************************************
1651 * Build a Wine-to-16-bit callback function.
1653 * Stack frame of the callback function:
1657 * (ebp+16) 16-bit ds
1658 * (ebp+12) func to call
1659 * (ebp+8) code selector
1660 * (ebp+4) return address
1661 * (ebp) previous ebp
1663 * Prototypes for the CallTo16 functions:
1664 * extern WORD CallTo16_word_xxx( FARPROC16 func, WORD ds, args... );
1665 * extern LONG CallTo16_long_xxx( FARPROC16 func, WORD ds, args... );
1666 * extern void CallTo16_regs_( FARPROC16 func, WORD ds, WORD es, WORD bp,
1667 * WORD ax, WORD bx, WORD cx, WORD dx,
1668 * WORD si, WORD di );
1670 static void BuildCallTo16Func( char *profile
)
1674 char *args
= profile
+ 5;
1676 if (!strncmp( "word_", profile
, 5 )) short_ret
= 1;
1677 else if (!strncmp( "regs_", profile
, 5 )) reg_func
= short_ret
= 1;
1678 else if (strncmp( "long_", profile
, 5 ))
1680 fprintf( stderr
, "Invalid function name '%s', ignored\n", profile
);
1684 /* Function header */
1686 printf( "/**********\n" );
1687 printf( " * " PREFIX
"CallTo16_%s\n", profile
);
1688 printf( " **********/\n" );
1689 printf( "\t.align 4\n" );
1690 printf( "\t.globl " PREFIX
"CallTo16_%s\n\n", profile
);
1691 printf( PREFIX
"CallTo16_%s:\n", profile
);
1693 /* Push code selector before return address to simulate a lcall */
1695 printf( "\tpopl %%eax\n" );
1696 printf( "\tpushl $0x%04x\n", WINE_CODE_SELECTOR
);
1697 printf( "\tpushl %%eax\n" );
1701 printf( "\tpushl %%ebp\n" );
1702 printf( "\tmovl %%esp,%%ebp\n" );
1704 /* Save the 32-bit registers */
1706 printf( "\tpushl %%ebx\n" );
1707 printf( "\tpushl %%ecx\n" );
1708 printf( "\tpushl %%edx\n" );
1709 printf( "\tpushl %%esi\n" );
1710 printf( "\tpushl %%edi\n" );
1712 /* Save the 32-bit stack */
1714 printf( "\tpushl " PREFIX
"IF1632_Saved32_esp\n" );
1715 printf( "\tmovl %%esp," PREFIX
"IF1632_Saved32_esp\n" );
1716 printf( "\tmovl %%ebp,%%ebx\n" );
1718 /* Print debugging info */
1722 /* Push the address of the first argument */
1723 printf( "\tmovl %%ebx,%%eax\n" );
1724 printf( "\taddl $12,%%eax\n" );
1725 printf( "\tpushl $%d\n", reg_func
? 8 : strlen(args
) );
1726 printf( "\tpushl %%eax\n" );
1727 printf( "\tcall " PREFIX
"RELAY_DebugCallTo16\n" );
1728 printf( "\tpopl %%eax\n" );
1729 printf( "\tpopl %%eax\n" );
1732 /* Switch to the 16-bit stack */
1735 printf("\tdata16\n");
1737 printf( "\tmovw " PREFIX
"IF1632_Saved16_ss,%%ss\n" );
1738 printf( "\tmovw " PREFIX
"IF1632_Saved16_sp,%%sp\n" );
1740 /* Transfer the arguments */
1744 /* Get the registers. ebx is handled later on. */
1745 printf( "\tpushw 20(%%ebx)\n" );
1746 printf( "\tpopw %%es\n" );
1747 printf( "\tmovl 24(%%ebx),%%ebp\n" );
1748 printf( "\tmovl 28(%%ebx),%%eax\n" );
1749 printf( "\tmovl 36(%%ebx),%%ecx\n" );
1750 printf( "\tmovl 40(%%ebx),%%edx\n" );
1751 printf( "\tmovl 44(%%ebx),%%esi\n" );
1752 printf( "\tmovl 48(%%ebx),%%edi\n" );
1754 else /* not a register function */
1756 int pos
= 20; /* first argument position */
1758 /* Make %bp point to the previous stackframe (built by CallFrom16) */
1759 printf( "\tmovw %%sp,%%bp\n" );
1760 printf( "\taddw $16,%%bp\n" );
1766 case 'w': /* word */
1767 printf( "\tpushw %d(%%ebx)\n", pos
);
1769 case 'l': /* long */
1770 printf( "\tpushl %d(%%ebx)\n", pos
);
1777 /* Push the return address */
1779 printf( "\tpushl " PREFIX
"CALLTO16_RetAddr_%s\n",
1780 short_ret
? "word" : "long" );
1782 /* Push the called routine address */
1784 printf( "\tpushl 12(%%ebx)\n" );
1786 /* Get the 16-bit ds */
1790 printf( "\tpushw 16(%%ebx)\n" );
1791 printf( "\tmovl 32(%%ebx),%%ebx\n" ); /*Get ebx from the 32-bit stack*/
1792 printf( "\tpopw %%ds\n" );
1796 /* Set ax equal to ds for window procedures */
1797 printf( "\tmovw 16(%%ebx),%%ax\n" );
1799 printf( "\tdata16\n");
1801 printf( "\tmovw %%ax,%%ds\n" );
1804 /* Jump to the called routine */
1806 printf( "\t.byte 0x66\n" );
1807 printf( "\tlret\n" );
1811 /*******************************************************************
1814 * Build the return code for 16-bit callbacks
1816 static void BuildRet16Func()
1818 printf( "\t.globl " PREFIX
"CALLTO16_Ret_word\n" );
1819 printf( "\t.globl " PREFIX
"CALLTO16_Ret_long\n" );
1821 /* Put return value into eax */
1823 printf( PREFIX
"CALLTO16_Ret_long:\n" );
1824 printf( "\tpushw %%dx\n" );
1825 printf( "\tpushw %%ax\n" );
1826 printf( "\tpopl %%eax\n" );
1827 printf( PREFIX
"CALLTO16_Ret_word:\n" );
1829 /* Restore 32-bit segment registers */
1831 printf( "\tmovw $0x%04x,%%bx\n", WINE_DATA_SELECTOR
);
1833 printf( "\tdata16\n");
1835 printf( "\tmovw %%bx,%%ds\n" );
1837 printf( "\tdata16\n");
1839 printf( "\tmovw %%bx,%%es\n" );
1841 printf( "\tdata16\n");
1843 printf( "\tmovw %%bx,%%ss\n" );
1845 /* Restore the 32-bit stack */
1847 printf( "\tmovl " PREFIX
"IF1632_Saved32_esp,%%esp\n" );
1848 printf( "\tpopl " PREFIX
"IF1632_Saved32_esp\n" );
1850 /* Restore the 32-bit registers */
1852 printf( "\tpopl %%edi\n" );
1853 printf( "\tpopl %%esi\n" );
1854 printf( "\tpopl %%edx\n" );
1855 printf( "\tpopl %%ecx\n" );
1856 printf( "\tpopl %%ebx\n" );
1858 /* Return to caller */
1860 printf( "\tpopl %%ebp\n" );
1861 printf( "\tlret\n" );
1863 /* Declare the return address variables */
1865 printf( "\t.data\n" );
1866 printf( "\t.globl " PREFIX
"CALLTO16_RetAddr_word\n" );
1867 printf( "\t.globl " PREFIX
"CALLTO16_RetAddr_long\n" );
1868 printf( PREFIX
"CALLTO16_RetAddr_word:\t.long 0\n" );
1869 printf( PREFIX
"CALLTO16_RetAddr_long:\t.long 0\n" );
1870 printf( "\t.text\n" );
1874 /*******************************************************************
1875 * BuildCallFrom32Func
1877 * Build a 32-bit-to-Wine call-back function.
1878 * 'args' is the number of dword arguments.
1886 * (ebp-4) entry point
1889 static void BuildCallFrom32Func( const char *profile
)
1893 if (!strncmp( profile
, "stdcall", 7 ))
1896 args
= atoi( profile
+ 8 );
1898 else if (!strncmp( profile
, "cdecl", 5 ))
1901 args
= atoi( profile
+ 6 );
1905 fprintf( stderr
, "Invalid function profile '%s'\n", profile
);
1909 /* Function header */
1911 printf( "/**********\n" );
1912 printf( " * " PREFIX
"CallFrom32_%s\n", profile
);
1913 printf( " **********/\n" );
1914 printf( "\t.align 4\n" );
1915 printf( "\t.globl " PREFIX
"CallFrom32_%s\n\n", profile
);
1916 printf( PREFIX
"CallFrom32_%s:\n", profile
);
1920 printf( "\tleal 8(%%esp),%%ebp\n" );
1922 /* Print the debugging info */
1926 printf( "\tpushl $%d\n", args
);
1927 printf( "\tcall " PREFIX
"RELAY_DebugCallFrom32\n" );
1928 printf( "\tadd $4, %%esp\n" );
1931 /* Transfer the arguments */
1936 for (i
= args
; i
> 0; i
--) printf( "\tpushl %d(%%ebp)\n", 4 * i
+ 4 );
1940 /* Push the address of the arguments. The called function will */
1941 /* ignore this if it really takes no arguments. */
1942 printf( "\tleal 8(%%ebp),%%eax\n" );
1943 printf( "\tpushl %%eax\n" );
1946 /* Call the function */
1948 printf( "\tcall -4(%%ebp)\n" );
1950 /* Print the debugging info */
1954 printf( "\tadd $%d,%%esp\n", args
? (args
* 4) : 4 );
1955 printf( "\tpushl %%eax\n" );
1956 printf( "\tcall " PREFIX
"RELAY_DebugCallFrom32Ret\n" );
1957 printf( "\tpopl %%eax\n" );
1960 printf( "\tmovl %%ebp,%%esp\n" );
1961 printf( "\tpopl %%ebp\n" );
1963 /* Return, removing arguments */
1965 if (args
&& stdcall) printf( "\tret $%d\n", args
* 4 );
1966 else printf( "\tret\n" );
1970 /*******************************************************************
1973 * Build a Wine-to-32-bit callback function.
1975 * Stack frame of the callback function:
1979 * (ebp+8) func to call
1980 * (ebp+4) return address
1981 * (ebp) previous ebp
1983 * Prototype for the CallTo32 functions:
1984 * extern LONG CallTo32_nn( FARPROC32 func, args... );
1986 static void BuildCallTo32Func( int args
)
1988 /* Function header */
1990 printf( "/**********\n" );
1991 printf( " * " PREFIX
"CallTo32_%d\n", args
);
1992 printf( " **********/\n" );
1993 printf( "\t.align 4\n" );
1994 printf( "\t.globl " PREFIX
"CallTo32_%d\n\n", args
);
1995 printf( PREFIX
"CallTo32_%d:\n", args
);
1999 printf( "\tpushl %%ebp\n" );
2000 printf( "\tmovl %%esp,%%ebp\n" );
2002 /* Transfer arguments */
2007 for (i
= args
; i
> 0; i
--) printf( "\tpushl %d(%%ebp)\n", 4 * i
+ 8 );
2010 /* Print the debugging output */
2014 printf( "\tpushl $%d\n", args
);
2015 printf( "\tpushl 8(%%ebp)\n" );
2016 printf( "\tcall " PREFIX
"RELAY_DebugCallTo32\n" );
2017 printf( "\taddl $8,%%esp\n" );
2020 /* Call the function */
2022 printf( "\tcall 8(%%ebp)\n" );
2024 /* Return to Wine */
2026 printf( "\tmovl %%ebp,%%esp\n" );
2027 printf( "\tpopl %%ebp\n" );
2028 printf( "\tret\n" );
2032 static void usage(void)
2034 fprintf(stderr
, "usage: build -spec SPECNAMES\n"
2035 " build -callfrom16 FUNCTION_PROFILES\n"
2036 " build -callto16 FUNCTION_PROFILES\n"
2037 " build -callfrom32 FUNCTION_PROFILES\n"
2038 " build -callto32 FUNCTION_PROFILES\n" );
2043 int main(int argc
, char **argv
)
2047 if (argc
<= 2) usage();
2049 if (!strcmp( argv
[1], "-spec" ))
2051 for (i
= 2; i
< argc
; i
++) BuildSpecFiles( argv
[i
] );
2053 else if (!strcmp( argv
[1], "-callfrom16" )) /* 16-bit-to-Wine callbacks */
2057 printf( "/* File generated automatically. Do not edit! */\n\n" );
2058 printf( "\t.text\n" );
2060 /* Build the 32-bit large stack callback */
2062 BuildCall32LargeStack();
2064 /* Build the callback functions */
2066 for (i
= 2; i
< argc
; i
++) BuildCallFrom16Func( argv
[i
] );
2068 /* Output the argument debugging strings */
2072 printf( "/* Argument strings */\n" );
2073 for (i
= 2; i
< argc
; i
++)
2075 printf( "Profile_%s:\n", argv
[i
] );
2076 printf( "\t.ascii \"%s\\0\"\n", argv
[i
] + 5 );
2080 else if (!strcmp( argv
[1], "-callto16" )) /* Wine-to-16-bit callbacks */
2084 printf( "/* File generated automatically. Do not edit! */\n\n" );
2085 printf( "\t.text\n" );
2086 printf( "\t.globl " PREFIX
"CALLTO16_Start\n" );
2087 printf( PREFIX
"CALLTO16_Start:\n" );
2089 /* Build the callback functions */
2091 for (i
= 2; i
< argc
; i
++) BuildCallTo16Func( argv
[i
] );
2093 /* Output the 16-bit return code */
2097 printf( "\t.globl " PREFIX
"CALLTO16_End\n" );
2098 printf( PREFIX
"CALLTO16_End:\n" );
2100 else if (!strcmp( argv
[1], "-callfrom32" )) /* 32-bit-to-Wine callbacks */
2104 printf( "/* File generated automatically. Do not edit! */\n\n" );
2105 printf( "\t.text\n" );
2107 /* Build the callback functions */
2109 for (i
= 2; i
< argc
; i
++) BuildCallFrom32Func( argv
[i
] );
2111 else if (!strcmp( argv
[1], "-callto32" )) /* Wine-to-32-bit callbacks */
2115 printf( "/* File generated automatically. Do not edit! */\n\n" );
2116 printf( "\t.text\n" );
2118 /* Build the callback functions */
2120 for (i
= 2; i
< argc
; i
++) BuildCallTo32Func( atoi(argv
[i
]) );
2127 #endif /* WINELIB */