/* $Id$ */ /* 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) * 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 .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 */ 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 */ 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 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: movb 4(%esp), %al exit: movb %al, %cl 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 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 pushl %eax lcall sbrk16_api_ofs setc %dl /* Save carry */ popl %eax /* restore interrupts */ int $0x31 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 ___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 $-1, %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 */ /* 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 /* .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 _setup_core_selector call _setup_screens call _setup_go32_info_block incl ___environ_changed finit /* initialize fpu */ fwait fldcw ___fpucw 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 .globl ___environ_changed ___environ_changed: .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 /* 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 */ 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 _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 /* $Log$ Revision 1.4 1998-10-14 21:28:45 peter * initialize fpu so sigfpe is finally generated for fpu errors Revision 1.3 1998/08/19 10:56:35 pierre + added some special code for C interface to avoid loading of crt1.o or dpmiexcp.o from the libc.a Revision 1.2 1998/05/22 00:39:38 peter * go32v1, go32v2 recompiles with the new objects * remake3 works again with go32v2 - removed some "optimizes" from daniel which were wrong */