/* 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   ___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     ds_alias_ok
        movb    $0x4c, %ah
        int     $0x21

ds_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     dos_alloc_ok
        movb    $0x4c, %ah
        int     $0x21

dos_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,U_SYSTEM_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     use_stubinfo_stack_size /* use the larger of the two */
        movl    %ecx, %eax
        movl    %eax, __stklen    /* store the actual stack length */
use_stubinfo_stack_size:
        pushl   %eax
        call    ___sbrk          /* allocate the memory */
        cmpl    $-1, %eax
        je      no_memory
        movl    %eax, ___djgpp_stack_limit      /* Bottom of stack */
        addl    $256,%eax
        movl    %eax,__stkbottom               /* for stack checks */
        movl    %eax,U_SYSTEM_STACKBOTTOM

        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

no_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      no_exception
        pushl   %ecx
        call    *_exception_exit
        popl    %ecx
no_exception:
        cli                          /* Just in case they didn't unhook ints */
        FREESEL U_SYSTEM_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     brk_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     brk_common
        stc                                  /* Put carry back */
        jmp     brk_common

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

brk_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     brk_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     brk_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      no_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      no_deadbeef
        movl    $0xdeadbeef, %eax              /* something really easy to spot */
no_deadbeef:
        shrl    $2, %ecx                        /* div 4 Longwords not bytes */
        cld
        rep
        stosl
no_fill_sbrk_memory:
        movl    %edx, __what_size_dpmi_thinks_we_are

brk_nochange:                              /* successful return */
        movl    __what_we_return_to_app_as_old_size, %eax
        jmp     brk_return

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

brk_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,U_SYSTEM_GO32_INFO_BLOCK+26
        leave
        ret
        .align 2,0x90
.L24:
        movw %ax,U_SYSTEM_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 U_SYSTEM_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,U_SYSTEM_GO32_INFO_BLOCK+8
        movl $655360,U_SYSTEM_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,U_SYSTEM_GO32_INFO_BLOCK+4
        movl $753664,U_SYSTEM_GO32_INFO_BLOCK+8
        leave
        ret
        .align 2,0x90
.L29:
        movl $753664,U_SYSTEM_GO32_INFO_BLOCK+4
        movl $720896,U_SYSTEM_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,U_SYSTEM_GO32_INFO_BLOCK
        movl __stubinfo,%edx
        movzwl 36(%edx),%eax
        sall $4,%eax
        movl %eax,U_SYSTEM_GO32_INFO_BLOCK+12
        movzwl 32(%edx),%ecx
        movl %ecx,U_SYSTEM_GO32_INFO_BLOCK+16
        movzwl 38(%edx),%ecx
        movl %ecx,U_SYSTEM_GO32_INFO_BLOCK+20
        movb -3(%ebp),%al
        movb %al,U_SYSTEM_GO32_INFO_BLOCK+24
        movb -2(%ebp),%al
        movb %al,U_SYSTEM_GO32_INFO_BLOCK+25
        movl $-1,U_SYSTEM_GO32_INFO_BLOCK+28
        pushl $U_SYSTEM_GO32_INFO_BLOCK+32
        movzwl 38(%edx),%eax
        pushl %eax
        call ___dpmi_get_segment_base_address
        movw $4,U_SYSTEM_GO32_INFO_BLOCK+36
        movb -8(%ebp),%dl
        salw $8,%dx
        movzbw -7(%ebp),%ax
        orw %ax,%dx
        movw %dx,U_SYSTEM_GO32_INFO_BLOCK+38
        call copy_to_c_go32_info_block
        leave
        ret

copy_to_c_go32_info_block:
        leal U_SYSTEM_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   U_SYSTEM_ENVP
        pushl   ___crt0_argv
        pushl   ___crt0_argc
        call    _pascal_start
        pushl   %eax
/*      call _exit changed to */
        call    exit
        .align 2,0x90
/* .comm U_SYSTEM_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    U_SYSTEM_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,U_SYSTEM_ENVP
        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   U_SYSTEM_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
        .globl  _environ
_environ:
         .long 0

/* 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  __crt0_startup_flags
__crt0_startup_flags:
        .long   0

        .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
