summaryrefslogtreecommitdiff
path: root/rtl/go32v2/v2prt0.as
blob: 6314e6d54ba595f77a751249071980e51c27844c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
/* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */
/*****************************************************************************\
 * Interface to 32-bit executable (from stub.asm)
 *
 *   cs:eip     according to COFF header
 *   ds  32-bit data segment for COFF program
 *   fs  selector for our data segment (fs:0 is stubinfo)
 *   ss:sp      our stack (ss to be freed)
 *   <others>   All unspecified registers have unspecified values in them.
\*****************************************************************************/
/* modified by Pierre Muller to become the prt0.s for FPC Pascal */

        .file "v2prt0.as"

/* #include "stubinfo.h" */
 STUBINFO = 0
 STUBINFO_MAGIC = 0
 STUBINFO_SIZE = 0x10
 STUBINFO_MINSTACK = 0x14
 STUBINFO_MEMORY_HANDLE = 0x18
 STUBINFO_INITIAL_SIZE = 0x1c
 STUBINFO_MINKEEP = 0x20
 STUBINFO_DS_SELECTOR = 0x22
 STUBINFO_DS_SEGMENT = 0x24
 STUBINFO_PSP_SELECTOR = 0x26
 STUBINFO_CS_SELECTOR = 0x28
 STUBINFO_ENV_SIZE = 0x2a
 STUBINFO_BASENAME = 0x2c
 STUBINFO_ARGV0 = 0x34
 STUBINFO_DPMI_SERVER = 0x44
 STUBINFO_END = 0x54


/*      .comm   __stklen, 4
        this is added to the compiler so that we can specify
        the stack size */
        .comm   __stkbottom,4
        .comm   __stubinfo, 4
        .comm   ___djgpp_base_address, 4
        .comm   ___djgpp_selector_limit, 4
        .comm   __crt0_startup_flags, 4
        .comm   ___djgpp_stack_limit, 4
        .lcomm  sel_buf, 8

/* ___djgpp_ds_alias defined in go32/exceptn.s */
/* inserted at the end of this file  */
/* we use a local copy that will be copied to exceptn.s */
        .globl ___v2prt0_ds_alias
___v2prt0_ds_alias:
        .long  0
/* allocate 32*4 bytes for RMCB under the $ffff limit for Windows NT */
   .globl ___v2prt0_rmcb_regs
___v2prt0_rmcb_regs:
   .long  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
   .long  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
.data

___djgpp_memory_handle_pointer:
        .long   ___djgpp_memory_handle_list+8      /* Next free, first for stub */
        .comm   ___djgpp_memory_handle_list, 2048       /* Enough for 256 handles */

   /* simply get current state */
___sbrk_interrupt_state:
        .long   0x902

sbrk16_first_byte:
.include "sbrk16.ah"
sbrk16_last_byte:

sbrk16_api_ofs:
        .long   0
sbrk16_api_seg:
        .word   0
zero:
        .long   0

exit16_first_byte:
.include "exit16.ah"
exit16_last_byte:

/* hook_387_emulator:
        .long   ___emu387_load_hook */

/* this is for when main comes from a library */
        .long   _main


.text
        .globl  start
start:
        pushl   %ds                  /* set %es same as %ds */
        popl    %es                  /* push/pop 4 bytes shorter than ax */

/* Enable NULL pointer protection if DPMI supports it */
        testb   $0x1, __crt0_startup_flags+1        /* include/crt0.h */
        jnz     1f
        movl    $start, %eax
        cmpl    $0x1000, %eax
        jl      1f
        movw    $0x507, %ax
        .byte 0x64 /* fs: */
        movl    STUBINFO_MEMORY_HANDLE, %esi
        xorl    %ebx, %ebx                    /* Offset 0 in mem block */
        movl    $1, %ecx                        /* Set one page */
        movl    $zero, %edx
        int     $0x31              /* Make null page uncommitted */
        jnc     1f
        call    v2prt0_windows
1:
/* Create an alias for DS to be used by real-mode callbacks (exception handler messes with DS itself) */

        movw    %ds, %bx
        movw    $0x000a, %ax
        int     $0x31
        jnc     .Lds_alias_ok
        movb    $0x4c, %ah
        int     $0x21

.Lds_alias_ok:
        movw    %ax, ___v2prt0_ds_alias
        movl    %eax, %ebx
        movw    $0x0009, %ax
        movw    %cs, %cx        /* get CPL from %cs */
        andl    $3, %ecx
        shll    $5, %ecx                /* move it into place */
        orw     $0xc093, %cx
        int     $0x31      /* set access rights for alias */

/* Maybe set our DS limit to 4Gb in size if flag set */
        testb   $0x80, __crt0_startup_flags          /* include/crt0.h */
        jz      2f
        movw    $0xffff, %cx
        movl    %ecx, %edx
        movw    $0x0008, %ax                        /* reset alias limit to -1 */
        int     $0x31
        movw    %cs, %bx
        movw    $0x0008, %ax                        /* reset DS limit to -1 */
        int     $0x31
        movw    %ds, %bx
        movw    $0x0008, %ax                        /* reset DS limit to -1 */
        int     $0x31
        lsl     %ebx, %ebx                            /* Should be -1 */
        incl    %ebx
        jz      2f
        andb    $0x7f, __crt0_startup_flags          /* clear it if failure */
2:
/* Allocate some DOS memory and copy our sbrk helper into it. */
        movl    $sbrk16_first_byte, %esi
        movzwl  8(%esi), %ebx
        shrl    $4, %ebx
        movw    $0x0100, %ax
        int     $0x31
        jnc     .Ldos_alloc_ok
        movb    $0x4c, %ah
        int     $0x21

.Ldos_alloc_ok:
        movw    %cs, 2(%esi)
/* store API information */
        movw    %ds, 4(%esi)
        movw    %dx, 6(%esi)
/* selector for allocated block */

        movzwl  (%esi), %eax                /* calculate API address */
        movl    %eax, sbrk16_api_ofs

        pushl   %es                          /* move the data */
        movw    %dx, %es
        movl    $(sbrk16_last_byte - sbrk16_first_byte), %ecx
        shrl    $2,%ecx
        xorl    %edi, %edi
        cld
        rep
        movsl
        popl    %es

        movl    %edx, %ebx                    /* dos memory selector */
        movw    $0x000b, %ax                /* get descriptor */
        movl    $sel_buf, %edi
        int     $0x31

        andb    $0xbf, sel_buf+6                /* make 16-bit */
        andb    $0xf0, sel_buf+5                /* remove old type */
        orb     $0x0a, sel_buf+5                /* set new type to code/read */

        xorl    %eax, %eax                    /* allocate new selector */
        movw    $0x0001, %cx
        int     $0x31
        movw    %ax, sbrk16_api_seg

        movl    %eax, %ebx
        movw    $0x000c, %ax                /* set descriptor */
        movl    $sel_buf, %edi
        int     $0x31

/* Initialize the brk/sbrk variables */

/*      movl    $end, __what_size_app_thinks_it_is */
        .byte 0x64 /* fs: */
        movl    STUBINFO_INITIAL_SIZE, %eax
        movl    %eax, __what_size_dpmi_thinks_we_are

/* Maybe lock the initial block, expects BX:CX */
        movl    %ecx,%ebx
        movl    %edx,%ecx
        addw    $4096,%cx                      /* Skip null page */
        adcl    $0,%ebx
        subl    $4096,%eax
        pushl   %eax
        call    lock_memory

        .byte 0x64 /* fs: */
        movl    STUBINFO_MEMORY_HANDLE, %eax
        movl    %eax, ___djgpp_memory_handle_list

        .byte 0x64 /* fs: */                /* copy stubinfo into local memory */
        movl    STUBINFO_SIZE, %eax
        pushl   %eax
        call    ___sbrk
        movl    %eax, __stubinfo
        movl  %eax,operatingsystem_stub_info
        movl    %eax, %edi
        .byte 0x64 /* fs: */
        movl    STUBINFO_SIZE, %ecx
        shrl    $2, %ecx
        xorl    %esi, %esi                    /* Zero */
        pushl   %ds
        pushl   %fs
        popl    %ds
        cld
        rep
        movsl
        popl    %ds
        movl    __stklen, %eax    /* get program-requested stack size */
        .byte 0x64 /* fs: */
        movl    STUBINFO_MINSTACK, %ecx /* get stub-requested stack size */
        cmpl    %ecx, %eax
        jge     .Luse_stubinfo_stack_size /* use the larger of the two */
        movl    %ecx, %eax
        movl    %eax, __stklen    /* store the actual stack length */
.Luse_stubinfo_stack_size:
        pushl   %eax
        call    ___sbrk          /* allocate the memory */
        cmpl    $-1, %eax
        je      .Lno_memory
        movl    %eax, ___djgpp_stack_limit      /* Bottom of stack */
        addl    $256,%eax
        movl    %eax,__stkbottom               /* for stack checks */
        /* movl    %eax,operatingsystem_stackbottom  */
        /* StackBottom is
        a ThrteadVar and can not be given a symbol with name,
        copying value of __stkbottom to system.STackBottom variable
        is done in system unit startup code. PM */

        movl    ___djgpp_stack_limit,%eax       /* Bottom of stack */
        addl    __stklen, %eax
        movw    %ds, %dx                /* set stack */
        movw    %dx, %ss
        andl    $0xfffffffc,%eax
        movl    %eax, %esp

        xorl    %ebp, %ebp
        call    ___prt1_startup  /* run program */
        jmp     exit

.Lno_memory:
        movb    $0xff, %al
        jmp     exit

/*-----------------------------------------------------------------------------*/

/* #define FREESEL(x) movw x, %bx; movw $0x0001, %ax; int $0x31 */
   .macro FREESEL x
     movw \x,%bx
     movw $0x0001,%ax
     int $0x31
   .endm

        .global ___exit
        .align  2
___exit:
/* special exit from dpmiexcp.c */
        .global __exit
__exit:
        movl    4(%esp),%eax
exit:
        movl    %eax,%ecx
        xorl    %eax,%eax
        movw    %ax,%fs
        movw    %ax,%gs
        cmpl    $0,_exception_exit
        jz      .Lno_exception
        pushl   %ecx
        call    *_exception_exit
        popl    %ecx
.Lno_exception:
        cli                          /* Just in case they didn't unhook ints */
        FREESEL operatingsystem_go32_info_block+26     /* selector for linear memory */
        FREESEL ___v2prt0_ds_alias      /* DS alias for rmcb exceptions */
        FREESEL sbrk16_api_seg    /* sbrk cs */
        movw    sbrk16_first_byte+6,%dx /* selector for allocated DOS mem */
        movw    $0x101, %ax
        int     $0x31              /* Free block and selector */
9:
        movl    __stubinfo, %edx
        movl    STUBINFO_CS_SELECTOR(%edx), %eax
        movw    %ax, sbrk16_api_seg
        xorl    %edi, %edi
        movl    %edi, sbrk16_api_ofs    /* Offset is zero */

        movw    STUBINFO_DS_SELECTOR(%edx), %es
        movb    %cl, %dl                /* Exit status */
        movl    $exit16_first_byte, %esi
        movl    $(exit16_last_byte - exit16_first_byte), %ecx
        cld
        rep
        movsb

        movw    %es,%ax          /* We will free stack! */
        movw    %ax,%ss
        movl    $0x400,%esp          /* Transfer buffer >= 1024 bytes */

        xorl    %ebp, %ebp                            /* V1.10 bug fix */
        movl    ___djgpp_memory_handle_list, %edi
        movl    ___djgpp_memory_handle_list+2, %esi     /* Skip word prefixes */

        FREESEL %ds
        movw    %cs, %bx
/* Call exit procedure with BX=32-bit CS; SI+DI=32-bit handle; DL=exit status */
        .byte 0x2e
        ljmp    sbrk16_api_ofs

/*-----------------------------------------------------------------------------*/

/*      .lcomm  __what_size_app_thinks_it_is, 4 */
__what_size_app_thinks_it_is:
        .long   end
        .lcomm  __what_we_return_to_app_as_old_size, 4
        .lcomm  __what_size_dpmi_thinks_we_are, 4

lock_memory:
        /* BX:CX should be linear address; size is pushed on stack */
        testb   $0x10, __crt0_startup_flags+1      /* include/crt0.h */
        jz      13f
        pushl   %esi
        pushl   %edi
        pushl   %eax
        movl    16(%esp),%edi
        movw    18(%esp),%si
        movw    $0x600,%ax
        int     $0x31
        popl    %eax
        popl    %edi
        popl    %esi
13:     ret     $4                    /* Pop the argument */


        .global ___sbrk
        .align  2
___sbrk:
        movl    __what_size_app_thinks_it_is, %eax
        movl    4(%esp), %ecx              /* Increment size */
        addl    %ecx, %eax
        jnc     .Lbrk_common
        /* Carry is only set if a negative increment or wrap happens. Negative
           increment is semi-OK, wrap (only for multiple zone sbrk) isn't. */
        test    $0x80000000, %ecx              /* Clears carry */
        jnz     .Lbrk_common
        stc                                  /* Put carry back */
        jmp     .Lbrk_common

        .globl  ___brk
        .align  2
___brk:
        movl    4(%esp), %eax
        clc

.Lbrk_common:
        pushl   %esi
        pushl   %edi
        pushl   %ebx

        movl    __what_size_app_thinks_it_is, %edx            /* save info */
        movl    %edx, __what_we_return_to_app_as_old_size
        movl    %eax, __what_size_app_thinks_it_is

        /* multi code is not present */
        /* jc      10f                                           Wrap for multi-zone */
        cmpl    __what_size_dpmi_thinks_we_are, %eax        /* don't bother shrinking */
        jbe     .Lbrk_nochange

        addl    $0x0000ffff, %eax                              /* round up to 64K block */
        andl    $0xffff0000, %eax
        push    %eax                                        /* size - save for later */

        movl    ___djgpp_memory_handle_list, %edi              /* request new size */
        movw    ___djgpp_memory_handle_list+2, %si
        movl    %eax, %ecx                                    /* size not limit */
        movl    %eax, %ebx                                    /* size not limit */
        shrl    $16, %ebx                                      /* BX:CX size */

        movw    $0x0900, %ax                                /* disable interrupts */
        int     $0x31
        movl    %eax,___sbrk_interrupt_state
        lcall   sbrk16_api_ofs
        setc    %dl                                          /* Save carry */

        /* popl    %eax                                restore interrupts
        int     $0x31 postponed after ds alias is set correctly */

        test    %dl,%dl
        popl    %edx
        jne     .Lbrk_error

        movl    %edi, ___djgpp_memory_handle_list              /* store new handle */
        movw    %si, ___djgpp_memory_handle_list+2
        movl    %ecx, ___djgpp_base_address                  /* store new base address */
        movw    %bx, ___djgpp_base_address+2

        movl    %edx, %eax
        movl    __what_size_dpmi_thinks_we_are, %ecx
        subl    %ecx, %eax

        addl    ___djgpp_base_address, %ecx
        movl    %ecx, %ebx
        shrl    $16, %ebx                                      /* BX:CX addr */
        pushl   %eax                                        /* Size */
        call    lock_memory

        decl    %edx                                        /* limit now, not size */
5:      movl    %edx, ___djgpp_selector_limit
        orw     $0x0fff, %dx                                /* low bits set */
        movw    $0x0008, %ax                                /* reset CS limit */
        movw    %cs, %bx
        movl    %edx, %ecx
        shrl    $16, %ecx
        int     $0x31                                      /* CX:DX is limit */

        testb   $0x80, __crt0_startup_flags                  /* include/crt0.h */
        jnz     3f
        movw    $0x0008, %ax                                /* reset DS limit */
        movw    %ds, %bx
        int     $0x31

        movw    $0x0008, %ax                                /* reset DS alias limit */
        movl    ___v2prt0_ds_alias, %ebx
        int     $0x31
3:
        movw    $0x0007, %ax                                /* reset DS alias base */
        movl    ___v2prt0_ds_alias, %ebx
        movl    ___djgpp_base_address, %edx
        movw    ___djgpp_base_address+2, %cx
        int     $0x31

        movl    ___sbrk_interrupt_state,%eax                /* restore interrupts */
        int     $0x31
        movl    ___djgpp_selector_limit, %edx
12:     incl    %edx                                        /* Size not limit */
        testb   $0x60, __crt0_startup_flags     /* include/crt0.h */
        jz      .Lno_fill_sbrk_memory
        pushl   %ds
        popl    %es

        movl    __what_size_dpmi_thinks_we_are, %edi        /* set all newly resized bytes zero */
        movl    %edx, %ecx                                    /* Limit */
        subl    %edi, %ecx                    /* Adjust count for base */
        xorl    %eax, %eax
        testb   $0x40, __crt0_startup_flags
        jz      .Lno_deadbeef
        movl    $0xdeadbeef, %eax              /* something really easy to spot */
.Lno_deadbeef:
        shrl    $2, %ecx                        /* div 4 Longwords not bytes */
        cld
        rep
        stosl
.Lno_fill_sbrk_memory:
        movl    %edx, __what_size_dpmi_thinks_we_are

.Lbrk_nochange:                              /* successful return */
        movl    __what_we_return_to_app_as_old_size, %eax
        jmp     .Lbrk_return

.Lbrk_error:                                    /* error return */
        movl    __what_we_return_to_app_as_old_size, %eax
        movl    %eax, __what_size_app_thinks_it_is
        movl    $0, %eax

.Lbrk_return:
        popl    %ebx
        popl    %edi
        popl    %esi
        ret

/* From here on this are parts of crt1.c converted to assembler
and without any call to libc, so that it works without anything else
additions made by Pierre Muller*/
/* from dpmidefs.h * /
/* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */
/* from include <libc/asmdefs.h> */
/* all macros removed here */
/* #define FUNC(x)            .globl x; x: */

/* #define ENTER                pushl %ebp; movl %esp,%ebp */

/* #define LEAVE(x)     movl %ebp,%esp; popl %ebp; ret $(x) */
/* #define ARG1  8(%ebp)
#define ARG1h      10(%ebp)
#define ARG2        12(%ebp)
#define ARG2h      14(%ebp)
#define ARG3        16(%ebp)
#define ARG4        20(%ebp)
#define ARG5        24(%ebp)
#define ARG6        28(%ebp)
#define ARG7        32(%ebp)
#define ARG8        36(%ebp) */

        .comm   ___dpmi_error,2

/* from dpmi0000.s */
/*      .globl ___dpmi_allocate_ldt_descriptors */
/* using pascal convention => not usabel by C code */
___dpmi_allocate_ldt_descriptors:
        pushl %ebp; movl %esp,%ebp

        movl    8(%ebp), %ecx
        movl $0x0000, %eax
        int $0x31
        jnc .L_noerror0000
        movw %ax,___dpmi_error
        movl $-1,%eax
        jmp .L_leave0000
.L_noerror0000:
        movzwl  %ax,%eax
.L_leave0000:
        movl %ebp,%esp
        popl %ebp
        ret $4

/* from file dpmi0008.s */
/*      .globl ___dpmi_set_segment_limit */
___dpmi_set_segment_limit:
   pushl %ebp; movl %esp,%ebp

        movl    8(%ebp), %ebx
        movzwl  12(%ebp), %edx
        movzwl  14(%ebp),%ecx

        movl     $0x0008,%eax
        int $0x31
        jnc .L_noerror0008
        movw %ax,___dpmi_error
        movl $-1,%eax
        jmp .L_leave0008
.L_noerror0008:
        xorl    %eax,%eax
.L_leave0008:
        movl %ebp,%esp
        popl %ebp
        ret $8

/*      .globl ___dpmi_get_version */
___dpmi_get_version:
   pushl %ebp; movl %esp,%ebp

        movl     $0x0400,%eax
        int $0x31
        jnc .L_noerror0400
        movw %ax,___dpmi_error
        movl $-1,%eax
        jmp .L_leave0400
.L_noerror0400:
        movl    8(%ebp), %esi
        movb    %ah, (%esi)
        movb    %al, 1(%esi)
        movw    %bx, 2(%esi)
        movb    %cl, 4(%esi)
        movb    %dh, 5(%esi)
        movb    %dl, 6(%esi)

        xorl    %eax,%eax
.L_leave0400:

        movl %ebp,%esp
        popl %ebp
        ret $4

_set_os_trueversion:
        pushl %ebp
        movl  %esp,%ebp
        movl  $0x3306,%eax
        xorl  %ebx,%ebx
        int   $0x21
        movzbl %bl,%eax
        shll  $8,%eax
        shrl  $8,%ebx
        andl  $0xff,%ebx
        addl  %ebx,%eax
        movw  %ax,__os_trueversion
        popl  %ebp
        ret
/*       .globl ___dpmi_get_segment_base_address*/
___dpmi_get_segment_base_address:
   pushl %ebp; movl %esp,%ebp

        movl    8(%ebp), %ebx
        movl     $0x0006,%eax
        int $0x31
        jnc .L_noerror0006
        movw %ax,___dpmi_error
        movl $-1,%eax
        jmp .L_leave0006
.L_noerror0006:

        movl    12(%ebp), %ebx
        movl    %edx, (%ebx)
        movw    %cx, 2(%ebx)

        xorl    %eax,%eax
.L_leave0006:
        movl %ebp,%esp
        popl %ebp
        ret $8

.globl ___bss_count
.data
        .align 2
___bss_count:
        .long 1
.text
        .align 2
        .globl _setup_core_selector
_setup_core_selector:
        pushl %ebp
        movl %esp,%ebp
        pushl $1
        call ___dpmi_allocate_ldt_descriptors
        /* addl $4,%esp */
        cmpl $-1,%eax
        jne .L24
        movw $0,operatingsystem_go32_info_block+26
        leave
        ret
        .align 2,0x90
.L24:
        movw %ax,operatingsystem_go32_info_block+26
        movw %ax,_core_selector
        pushl $0x10ffff
        andl $0xffff,%eax
        pushl %eax
        call ___dpmi_set_segment_limit
        leave
        ret
        .align 2
        .globl _setup_screens
_setup_screens:
        pushl %ebp
        movl %esp,%ebp
        movw operatingsystem_go32_info_block+26,%dx
        movl $1048563,%ecx
/APP
        movw %dx, %gs
        .byte 0x65
        movw (%ecx),%ax
/NO_APP
        cmpw $64896,%ax
        jne .L26
        movl $655360,operatingsystem_go32_info_block+8
        movl $655360,operatingsystem_go32_info_block+4
        leave
        ret
        .align 2,0x90
.L26:
        movl $1097,%ecx
/APP
        movw %dx,%gs
        .byte 0x65
        movb (%ecx),%al
/NO_APP
        cmpb $7,%al
        jne .L29
        movl $720896,operatingsystem_go32_info_block+4
        movl $753664,operatingsystem_go32_info_block+8
        leave
        ret
        .align 2,0x90
.L29:
        movl $753664,operatingsystem_go32_info_block+4
        movl $720896,operatingsystem_go32_info_block+8
        leave
        ret

        .align 2
        .globl _setup_go32_info_block
_setup_go32_info_block:
        pushl %ebp
        movl %esp,%ebp
        subl $8,%esp
        leal -8(%ebp),%eax
        pushl %eax
        call ___dpmi_get_version
        movl $40,operatingsystem_go32_info_block
        movl __stubinfo,%edx
        movzwl 36(%edx),%eax
        sall $4,%eax
        movl %eax,operatingsystem_go32_info_block+12
        movzwl 32(%edx),%ecx
        movl %ecx,operatingsystem_go32_info_block+16
        movzwl 38(%edx),%ecx
        movl %ecx,operatingsystem_go32_info_block+20
        movb -3(%ebp),%al
        movb %al,operatingsystem_go32_info_block+24
        movb -2(%ebp),%al
        movb %al,operatingsystem_go32_info_block+25
        movl $-1,operatingsystem_go32_info_block+28
        pushl $operatingsystem_go32_info_block+32
        movzwl 38(%edx),%eax
        pushl %eax
        call ___dpmi_get_segment_base_address
        movw $4,operatingsystem_go32_info_block+36
        movb -8(%ebp),%dl
        salw $8,%dx
        movzbw -7(%ebp),%ax
        orw %ax,%dx
        movw %dx,operatingsystem_go32_info_block+38
        call copy_to_c_go32_info_block
        leave
        ret

copy_to_c_go32_info_block:
        leal operatingsystem_go32_info_block,%esi
        leal __go32_info_block,%edi
        movl $10,%ecx
        rep
        movsl
        ret

.data
        /* fpu codeword */
___fpucw:
        .long   0x1332
        /* __go32_info_block for C programs */
        .align 2
        .globl __go32_info_block
.comm   __go32_info_block,40

/*
  -- prt1_startup --
*/
.text
        .align 2
        .globl ___prt1_startup
___prt1_startup:
        pushl %ebp
        movl %esp,%ebp
        pushl %ebx
        incl ___bss_count
        movl $0,___crt0_argv
        call _set_os_trueversion
        call _setup_core_selector
        call _setup_screens
        call _setup_go32_info_block
        incl ___environ_changed
        /* call set_processor emulation */
        /* neede to avoid FPU exception if calling from anothe DPMI program */
        movl    $0xe01,%eax
        movl    $1,%ebx
        int     $0x31
        fninit             /* initialize fpu */
        push    %eax       /* Dummy for status store check */
        movl    %esp,%esi
        movw    $0x5a5a,(%esi)
        /* fwait  maybe this one is responsible of exceptions */
        fnstsw  (%esi)
        cmpb    $0,(%esi)
        jne     .Lno_387
        fldcw   ___fpucw
.Lno_387:
        popl %eax
        pushl   operatingsystem_parameter_envp
        pushl   ___crt0_argv
        pushl   ___crt0_argc
        call    _pascal_start
        pushl   %eax
/*      call _exit changed to */
        call    exit
        .align 2,0x90
/* .comm dos_argv0,4 */
        .comm ___dos_argv0,4
        .comm ___crt0_argc,4
        .comm ___crt0_argv,4
        .comm ___environ_changed,4
/* ___environ_changed: not in data because it is defined in putenv.c */
/*        .long  0 */
        .globl _exception_exit
_exception_exit:
        .long  0
        .globl _swap_in
_swap_in:
        .long  0
        .globl _swap_out
_swap_out:
        .long  0
        .global _v2prt0_exceptions_on
_v2prt0_exceptions_on:
        .long  0

// Fill null page with NOPs
// and a jmp windows_error at the end
   .globl v2prt0_windows
v2prt0_windows:
        movl $0x90909090,%eax
        xorl %edi,%edi
        movl $0x400,%ecx
   cld
        rep
        stosl
   movl $0xffB,%edi
   movb $0xe9,%al
   stosb
   movl $_fpc_windows_error-4,%eax
   subl %edi,%eax
   stosl
   ret

// Raise SIGILL with  UD2 opcode

   .globl _fpc_windows_error
_fpc_windows_error:
   cmpl $0,_exception_exit
   je   .L_error_216
   .byte 0x0f,0x0b
.L_error_216:
        pushl   $216
        call    __exit
        jmp     exit
#enif

/* this was the prt0.s from the go32v1 version */
//
// call as start(argc, argv, envp) (C-calling convention)
//
        .globl  _pascal_start
_pascal_start:
        /* %ebx doesn't contain ScreenPrimary */
        movl    operatingsystem_go32_info_block+4,%ebx
        movl    %ebx,_ScreenPrimary
        /*  core selector in %fs */
        /*  keep original fs for debuggers !!!!! (PM) */
        movw    %fs,%ax
             movw       %ax,___v2prt0_start_fs

        movw    _core_selector,%ax
        movw    %ax,%fs

// Top of frame
        movl    $0x0,%ebp
        movl    %esp,%ebx
        movl    12(%ebx),%eax
        movl    %eax,operatingsystem_parameter_envp
        movl    %eax,__environ
        movl    %eax,_environ
        movl    8(%ebx),%eax
        movl    %eax,_args
        movl    4(%ebx),%eax
        movl    %eax,_argc

        call    PASCALMAIN
        movl    $0,%eax
        /* no error if passing here */
/*      movl    $0x4c00,%eax
        int     $0x21 */

        ret

        .data

/*      .comm   operatingsystem_parameter_envp,4 */
        .globl  _ScreenPrimary
_ScreenPrimary:
        .long   0
        .globl  _argc
_argc:
        .long   0
        .globl  _args
_args:
        .long   0
        .globl  _run_mode
_run_mode:
        .word   4
        .globl  _core_selector
_core_selector:
        .word   0
        .globl ___v2prt0_start_fs
___v2prt0_start_fs:
        .word 0
         /* DJGPP CVS crt1.c code uses __environ symbol */
         /* corresponding to _environ C variable */
         /* instead of _environ symbol since commit rev 1.11 */
         /* Thu Aug 19 9:11:52 2004 UTC by peuha */
         /* Provide both here to avoid crt1.o loading. */
        .comm  __environ,4
        .comm  _environ,4


/* Here Pierre Muller added all what was in crt1.c  */
/* in assembler                              */
/* Copyright (C) 1996 DJ Delorie, see COPYING.DJ for details */
/* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */
/* adapted to assembler for FPC by Pierre Muller             */

/* Global variables */


/* This gets incremented each time the program is started.
   Programs (such as Emacs) which dump their code to create
   a new executable, cause this to be larger than 2.  Library
   functions that cache info in static variables should check
   the value of `__bss_count' if they need to reinitialize
   the static storage.  */
        .data
        .globl  ___bss_count
___bs_count:
        .long   1

        .globl  __dos_ds
__dos_ds:
        .long   0

        .globl ___PROXY
___PROXY:
        .ascii " !proxy"
        .byte  0

        .globl ___PROXY_LEN
___PROXY_LEN:
        .long 7

        .comm __os_trueversion,2