Index: trunk/libc/Makefile.kmk
===================================================================
--- trunk/libc/Makefile.kmk	(revision 3894)
+++ trunk/libc/Makefile.kmk	(revision 3895)
@@ -327,8 +327,40 @@
 startupobjs_SOURCES :=
 ifeq ($(BUILD_TARGET),os2)
+
+ifdef CFG_LIBC_USE_WATCOM
+define def_startup
+$(PATH_TARGET)/crt0$(i).obj: src/libc/startup/os2/x86/crt0.asm | $(call DIRDEP,$(PATH_TARGET))
+	$(RM) -f $$@
+	$$(TOOL_$$(TEMPLATE_libcasm_ASTOOL)_AS) $(TEMPLATE_libcasm_ASFLAGS) -Iinclude/ \
+		$(addprefix -D,$(DEFS) $(ASDEFS) $(DEFS.$(KBUILD_TARGET)) $(ASDEFS.$(KBUILD_TARGET)) ) \
+		$(subst wild, 	-DARGS_WILD, \
+		$(subst resp, 	-DARGS_RESP, \
+		$(subst noux, 	-DNOUNIX, \
+		$(subst nofork, -DNOFORK, \
+		$(subst hi, 	-DHIGHMEM, $i) )))) \
+		-o $$@ \
+		$$<
+$$(eval startupobjs_SOURCES += $(PATH_TARGET)/crt0$(i).obj)
+
+ifeq ($(subst resp,,$(subst wild,,$(i))),$(i))
+$(PATH_TARGET)/dll0$(i).obj: src/libc/startup/os2/x86/dll0.asm | $(call DIRDEP,$(PATH_TARGET))
+	$(RM) -f $$@
+	$$(TOOL_$$(TEMPLATE_libcasm_ASTOOL)_AS) $(TEMPLATE_libcasm_ASFLAGS) -Iinclude/ \
+		$(addprefix -D,$(DEFS) $(ASDEFS) $(DEFS.$(KBUILD_TARGET)) $(ASDEFS.$(KBUILD_TARGET)) ) \
+		$(subst wild, 	-DARGS_WILD, \
+		$(subst resp, 	-DARGS_RESP, \
+		$(subst noux, 	-DNOUNIX, \
+		$(subst nofork, -DNOFORK, \
+		$(subst hi, 	-DHIGHMEM, $i) )))) \
+		-o $$@ \
+		$$<
+$$(eval startupobjs_SOURCES += $(PATH_TARGET)/dll0$(i).obj)
+endif
+endef # def_startup
+
+else # !CFG_LIBC_USE_WATCOM
 define def_startup
 $(PATH_TARGET)/crt0$(i).o: src/libc/startup/os2/x86/crt0.s | $(call DIRDEP,$(PATH_TARGET))
 	$(RM) -f $$@ $$@bj
-	echo "i=$i"
 	gcc -c -Iinclude -x assembler-with-cpp \
 		$(subst wild, 	-DARGS_WILD, \
@@ -364,5 +396,6 @@
 endif
 endif
-endef
+endef # def_startup
+endif # !CFG_LIBC_USE_WATCOM
 
 # generate
@@ -418,11 +451,20 @@
 
 # binmode
+ifdef CFG_LIBC_USE_WATCOM
+$(PATH_TARGET)/binmode.obj: src/libc/io/386/binmode.asm
+	$(RM) -f $@
+	$(TOOL_$(TEMPLATE_libcasm_ASTOOL)_AS) $(TEMPLATE_libcasm_ASFLAGS) -Iinclude/ \
+		$(addprefix -D,$(DEFS) $(ASDEFS) $(DEFS.$(KBUILD_TARGET)) $(ASDEFS.$(KBUILD_TARGET)) ) \
+		-o $@ $<
+startupobjs_SOURCES += $(PATH_TARGET)/binmode.obj
+else
 $(PATH_TARGET)/binmode.o: src/libc/io/386/binmode.s
 	gcc -c -o $@ $<
 startupobjs_SOURCES += $(PATH_TARGET)/binmode.o
-ifdef ($(BUILD_TARGET),os2)
+ ifdef ($(BUILD_TARGET),os2)
 $(PATH_TARGET)/binmode.obj: $(PATH_TARGET)/binmode.o
 	emxomf -o $@ $<
 startupobjs_SOURCES += $(PATH_TARGET)/binmode.obj
+ endif
 endif
 
Index: trunk/libc/include/klibc/initterm.h
===================================================================
--- trunk/libc/include/klibc/initterm.h	(revision 3894)
+++ trunk/libc/include/klibc/initterm.h	(revision 3895)
@@ -62,4 +62,5 @@
 
 /** @name Flags for __libc_InitDll, __libc_InitExe, __libc_TermDll and __libc_TermExe.
+ * @remarks also defined in initterm.mac.
  * @{ */
 #define __LIBC_INIT_FLAGS_MEM_HIGH                 1
Index: trunk/libc/include/klibc/initterm.mac
===================================================================
--- trunk/libc/include/klibc/initterm.mac	(revision 3895)
+++ trunk/libc/include/klibc/initterm.mac	(revision 3895)
@@ -0,0 +1,20 @@
+; $Id$
+;; @file
+; kLibC - initialization and termination defines for NASM/YASM.
+;
+; @copyright   Copyright (c) 1992-1994 by Eberhard Mattes
+;              Copyright (C) 2004-2014 knut st. osmundsen <bird-klibc-spam-xiv@anduin.net>
+; @licenses    MIT, BSD2, BSD3, BSD4, LGPLv2.1, LGPLv3, LGPLvFuture.
+;
+
+%ifndef __klibc_initterm_mac__
+%define __klibc_initterm_mac__
+
+%define __LIBC_INIT_FLAGS_MEM_HIGH                 1
+%define __LIBC_INIT_FLAGS_NO_UNIX                  2
+%define __LIBC_INIT_FLAGS_EXPAND_RESPONSE_FILE     4
+%define __LIBC_INIT_FLAGS_EXPAND_WILDCARDS         8
+%define __LIBC_INIT_FLAGS_PROCESS                  0x40000000
+
+%endif
+
Index: trunk/libc/include/klibc/os2/asmdefs.mac
===================================================================
--- trunk/libc/include/klibc/os2/asmdefs.mac	(revision 3894)
+++ trunk/libc/include/klibc/os2/asmdefs.mac	(revision 3895)
@@ -20,5 +20,29 @@
 ; Segment definitions.
 ;
+
+;; Defines the set-vector %1 (for crt0/dll0).
+%macro KLIBC_OS2_SET_VECTOR_DEFINE 1
+ segment SET1_ %+ %1
+ GLOBAL_DATA %1
+ NAME_DATA(%1):
+       dd      0xfffffffe              ; terminates the array
+ segment SET2_ %+ %1
+ %1 %+_Dummy2:
+ segment SET3_ %+ %1
+ %1 %+_Dummy3:
+       dd      0                       ; terminates the array
+%endmacro
+;; Lists the segment names for set-vector %1.
+%define KLIBC_OS2_SET_VECTOR_NAMES(a_Name) SET1_ %+ a_Name  SET2_ %+ a_Name  SET3_ %+ a_Name
+
+
 %if KLIBC_OBJFMT = KLIBC_OBJFMT_AOUT
+ %macro KLIBC_OS2_SET_VECTOR_DECLARE 1
+  %error "Dunno how to do set-vectors in AOUT/NASM."
+ %endmacro
+ %macro KLIBC_OS2_SET_VECTOR_ADD 2
+  %error "Dunno how to do set-vectors in AOUT/NASM."
+ %endmacro
+
  %define SEG_BEGIN_CODE     section .text
  %define SEG_BEGIN_DATA     section .data
@@ -26,5 +50,12 @@
  %define SEG_BEGIN_BSS      section .bss
 
+
 %elif KLIBC_OBJFMT = KLIBC_OBJFMT_OMF
+ %macro KLIBC_OS2_SET_VECTOR_DECLARE 1
+  segment SET1_ %+ %1 use32 align=4 public class=DATA
+  segment SET2_ %+ %1 use32 align=4 public class=DATA
+  segment SET3_ %+ %1 use32 align=4 public class=DATA
+ %endmacro
+
  %define SEG_BEGIN_CODE     segment CODE32
  %define SEG_BEGIN_DATA     segment DATA32
@@ -34,31 +65,40 @@
  segment CODE32 use32 flat align=16 public class=CODE
  segment DATA32 use32 align=16 public class=DATA
-
- segment SET1___fork_child1__ use32 align=4 public class=DATA
- segment SET2___fork_child1__ use32 align=4 public class=DATA
- segment SET3___fork_child1__ use32 align=4 public class=DATA
-
- segment SET1___fork_parent1__ use32 align=4 public class=DATA
- segment SET2___fork_parent1__ use32 align=4 public class=DATA
- segment SET3___fork_parent1__ use32 align=4 public class=DATA
-
- segment SET1___crtinit1__ use32 align=4 public class=DATA
- segment SET2___crtinit1__ use32 align=4 public class=DATA
- segment SET3___crtinit1__ use32 align=4 public class=DATA
-
- segment SET1___crtexit1__ use32 align=4 public class=DATA
- segment SET2___crtexit1__ use32 align=4 public class=DATA
- segment SET3___crtexit1__ use32 align=4 public class=DATA
-
+ KLIBC_OS2_SET_VECTOR_DECLARE _os2dll
+ KLIBC_OS2_SET_VECTOR_DECLARE __CTOR_LIST__
+ KLIBC_OS2_SET_VECTOR_DECLARE __DTOR_LIST__
+ KLIBC_OS2_SET_VECTOR_DECLARE __crtinit1__
+ KLIBC_OS2_SET_VECTOR_DECLARE __crtexit1__
+ KLIBC_OS2_SET_VECTOR_DECLARE __libc_sysctl__
+ KLIBC_OS2_SET_VECTOR_DECLARE __fork_child1__
+ KLIBC_OS2_SET_VECTOR_DECLARE __fork_parent1__
+ KLIBC_OS2_SET_VECTOR_DECLARE __eh_frame__
+ KLIBC_OS2_SET_VECTOR_DECLARE __eh_init__
+ KLIBC_OS2_SET_VECTOR_DECLARE __eh_term__
  segment BSS32  use32 align=16 public class=BSS
- group DGROUP DATA32 BSS32 \
-    SET1___fork_parent1__ SET2___fork_parent1__ SET3___fork_parent1__ \
-    SET1___fork_child1__  SET2___fork_child1__  SET3___fork_child1__ \
-    SET1___crtinit1__     SET2___crtinit1__     SET3___crtinit1__ \
-    SET1___crtexit1__     SET2___crtexit1__     SET3___crtexit1__
+ group DGROUP DATA32 \
+    KLIBC_OS2_SET_VECTOR_NAMES(_os2dll) \
+    KLIBC_OS2_SET_VECTOR_NAMES(__CTOR_LIST__) \
+    KLIBC_OS2_SET_VECTOR_NAMES(__DTOR_LIST__) \
+    KLIBC_OS2_SET_VECTOR_NAMES(__crtinit1__) \
+    KLIBC_OS2_SET_VECTOR_NAMES(__crtexit1__) \
+    KLIBC_OS2_SET_VECTOR_NAMES(__libc_sysctl__) \
+    KLIBC_OS2_SET_VECTOR_NAMES(__fork_child1__) \
+    KLIBC_OS2_SET_VECTOR_NAMES(__fork_parent1__) \
+    KLIBC_OS2_SET_VECTOR_NAMES(__eh_frame__) \
+    KLIBC_OS2_SET_VECTOR_NAMES(__eh_init__) \
+    KLIBC_OS2_SET_VECTOR_NAMES(__eh_term__) \
+    BSS32
 
  segment CODE16 use16 align=16 public class=CODE
 
-%elif KLIBC_OBJFMT = KLIBC_OBJFMT_ELF32 || KLIBC_OBJFMT = KLIBC_OBJFMT_COFF32 ; latter is just for testing!
+
+%elif KLIBC_OBJFMT = KLIBC_OBJFMT_ELF32
+ %macro KLIBC_OS2_SET_VECTOR_DECLARE 1
+  segment SET1_ %+ %1 use32 align=4 public class=DATA
+  segment SET2_ %+ %1 use32 align=4 public class=DATA
+  segment SET3_ %+ %1 use32 align=4 public class=DATA
+ %endmacro
+
  %define SEG_BEGIN_CODE     section .text
  %define SEG_BEGIN_DATA     section .data
@@ -66,6 +106,27 @@
  %define SEG_BEGIN_BSS      section .bss
 
+ KLIBC_OS2_SET_VECTOR_DECLARE _os2dll
+ KLIBC_OS2_SET_VECTOR_DECLARE __CTOR_LIST__
+ KLIBC_OS2_SET_VECTOR_DECLARE __DTOR_LIST__
+ KLIBC_OS2_SET_VECTOR_DECLARE __crtinit1__
+ KLIBC_OS2_SET_VECTOR_DECLARE __crtexit1__
+ KLIBC_OS2_SET_VECTOR_DECLARE __libc_sysctl__
+ KLIBC_OS2_SET_VECTOR_DECLARE __fork_child1__
+ KLIBC_OS2_SET_VECTOR_DECLARE __fork_parent1__
+ KLIBC_OS2_SET_VECTOR_DECLARE __eh_frame__
+ KLIBC_OS2_SET_VECTOR_DECLARE __eh_init__
+ KLIBC_OS2_SET_VECTOR_DECLARE __eh_term__
+
 %else
  %fatal Object format __OUTPUT_FORMAT__ is not supported by kLibC on OS/2.
+%endif
+
+%ifndef KLIBC_OS2_SET_VECTOR_ADD
+ ;; Adds the address of %2 to the set-vector %1.
+ %macro KLIBC_OS2_SET_VECTOR_ADD 2
+  segment SET2_ %+ %1
+        dd      %2
+  SEG_BEGIN_CODE
+ %endmacro
 %endif
 
Index: trunk/libc/src/libc/io/386/binmode.asm
===================================================================
--- trunk/libc/src/libc/io/386/binmode.asm	(revision 3895)
+++ trunk/libc/src/libc/io/386/binmode.asm	(revision 3895)
@@ -0,0 +1,24 @@
+; $Id$
+;; @file
+; kNIX - Switch default fopen mode from text to binary.
+;
+; @copyright   Copyright (C) 2014 knut st. osmundsen <bird-klibc-spam-xiv@anduin.net>
+; @licenses    MIT, BSD2, BSD3, BSD4, LGPLv2.1, LGPLv3, LGPLvFuture.
+;
+
+
+;*******************************************************************************
+;*  Header Files                                                               *
+;*******************************************************************************
+%include "klibc/asmdefs.mac"
+
+extern NAME_DATA(_fmode_bin)
+
+SEG_BEGIN_CODE
+set_fmode_bin_to_1:
+        mov     dword [NAME_DATA(_fmode_bin)], 1
+        xor     eax, eax
+        ret
+
+KLIBC_OS2_SET_VECTOR_ADD ___CTOR_LIST__, set_fmode_bin_to_1
+
Index: trunk/libc/src/libc/startup/os2/x86/crt0.asm
===================================================================
--- trunk/libc/src/libc/startup/os2/x86/crt0.asm	(revision 3895)
+++ trunk/libc/src/libc/startup/os2/x86/crt0.asm	(revision 3895)
@@ -0,0 +1,207 @@
+; $Id$
+;; @file
+; kNIX - Pre-main() startup code, OS/2.
+;
+; @copyright   Copyright (C) 2006-2014 knut st. osmundsen <bird-klibc-spam-xiv@anduin.net>
+; @licenses    MIT, BSD2, BSD3, BSD4, LGPLv2.1, LGPLv3, LGPLvFuture.
+;
+
+
+;*******************************************************************************
+;*  Header Files                                                               *
+;*******************************************************************************
+%include "klibc/asmdefs.mac"
+%include "klibc/initterm.mac"
+
+
+SEG_BEGIN_CODE
+
+extern NAME_FUNC(main)
+extern NAME_FUNC(exit)
+extern NAME_FUNC(__libc_ForkRegisterModule)
+extern NAME_FUNC(__libc_InitExe)
+extern NAME_FUNC(_atfork_callback)
+extern __libc_Back_exceptionHandler ; _System
+; Add a symbol table entry which drags _end in libend into OMF links.
+extern __end
+extern _end
+
+
+;;
+; The OS/2 executable entry point.
+;
+; EAX = EBX = ECX = EDX = ESI = EDI = EBP = GS = 0.
+; CS = flat code selector.
+; DS = ES = SS = flat data selector.
+; FS = TIB selector.
+; EFLAGS=undefined
+;
+; @returns exit code to pass to DosExit(1, rc);
+; @param   hmod         [ebp +  8h]   The executable module handle.
+; @param   Reserved     [ebp + 0ch]   Reserved (probably 0).
+; @param   pszzEnv      [ebp + 10h]   Pointer to the environment data object.
+; @param   pszzCmdline  [ebp + 14h]   Pointer to the commandline.
+;
+GLOBAL_FUNC _text
+NAME_FUNC(_text):
+..start:
+        ;
+        ; Clear DF, create a stack frame, register the exception handler,
+        ; and allocate the main argument frame.
+        ;
+        cld
+        push    ebp
+        mov     ebp, esp
+
+        push    __libc_Back_exceptionHandler
+        push    dword [fs:0]            ; tib_pexchain
+        mov     dword [fs:0], esp
+
+        and     esp, 0xfffffff0         ; make sure it's properly aligned.
+        sub     esp, 10h
+
+
+%ifndef NOFORK
+ %ifndef NOUNIX
+        ;
+        ; Update g_ForkModule.hmod and call __libc_ForkRegisterModule(&g_ForkModule) to
+        ; register the fork module. If we're forking, this call will never return.
+        ;
+        mov     eax, [ebp + 8]          ; hmod
+        mov     [g_ForkModule_hmod], eax
+
+        mov     dword [esp], g_ForkModule
+        call    NAME_FUNC(__libc_ForkRegisterModule)
+ %endif
+%endif
+
+        ;
+        ; Call __libc_InitExe(hmod, &hmod, fFlags, &MainArgs) to initialized
+        ; the CRT and get the arguments for main().
+        ;
+        mov     ecx, esp
+        push    ecx                        ; pMainFrame
+%ifdef HIGHMEM
+ %define F1     __LIBC_INIT_FLAGS_MEM_HIGH
+%else
+ %define F1     0
+%endif
+%ifdef NOUNIX
+ %define F2     __LIBC_INIT_FLAGS_NO_UNIX
+%else
+ %define F2     0
+%endif
+%ifdef ARGS_RESP
+ %define F3     __LIBC_INIT_FLAGS_EXPAND_RESPONSE_FILE
+%else
+ %define F3     0
+%endif
+%ifdef ARGS_WILD
+ %define F4     __LIBC_INIT_FLAGS_EXPAND_WILDCARDS
+%else
+ %define F4     0
+%endif
+        push    F1+F2+F3+F4
+        lea     edx, [ebp + 8]
+        push    edx                     ; pvOS
+        mov     eax, [ebp + 8]
+        push    eax                     ; hmod
+        call    NAME_FUNC(__libc_InitExe)
+        add     esp, 10h
+
+        ;
+        ; We can call main(). Should main return, invoke exit with the return code.
+        ;
+        ; Should some bright guy override exit() and make it return, we'll loop
+        ; eating 4 bytes of stack for each call to exit(). Eventually we'll crash
+        ; when we run out of stack.
+        ;
+        call    NAME_FUNC(main)
+
+        mov     esi, eax
+.do_exit:
+        mov     [esp], esi
+        call    NAME_FUNC(exit)
+        jmp     .do_exit
+
+
+;;
+; __data_start (and __data) marks the start of the data segment.
+;
+; By convention required by emxbind, the datasegment starts with
+; a magic number followed by a pointer to the list of OS/2 DLL
+; references. When linking OMF this is not used by anyone.
+;
+SEG_BEGIN_DATA
+GLOBAL_DATA __data_start
+GLOBAL_DATA _data
+NAME_DATA(__data_start):
+NAME_DATA(_data):
+        dd  0x00ba0bab                  ; Magic number (error detection).
+        dd  NAME_DATA(_os2dll)          ; List of OS/2 DLL references.
+
+%ifndef NOFORK
+ %ifndef NOUNIX
+;;
+; The fork module structure.
+;
+g_ForkModule:
+        dd  0x00010001                  ; uVersion (__LIBC_FORK_MODULE_VERSION)
+        dd  NAME_FUNC(_atfork_callback) ; pfnAtFork
+        dd  ___fork_parent1__           ; papParent1
+        dd  ___fork_child1__            ; papChild1
+        dd  ___data_start               ; pvDataSegBase
+        dd  _end                        ; pvDataSegEnd
+        dd  0x00000001                  ; fFlags - __LIBC_FORKMODULE_FLAGS_EXECUTABLE
+        dd  0                           ; pNext
+g_ForkModule_hmod:                      ;
+        dd  0                           ; hmod
+        dd  0                           ; uReserved[7]
+        dd  0                           ; uReserved[7]
+        dd  0                           ; uReserved[7]
+        dd  0                           ; uReserved[7]
+        dd  0                           ; uReserved[7]
+        dd  0                           ; uReserved[7]
+        dd  0                           ; uReserved[7]
+ %endif
+%endif
+
+
+;
+; Start all the a.out SETs the CRT and GCC are making use of.
+;
+;      _os2dll is used by emxbind/ld for dll imports.
+;      __CTOR_LIST__ and __DTOR_LIST__ are lists of static constructors and destructors.
+;      __crtinit1__ is the list of static crt init routines.
+;      __crtinit2__ is the list of static crt termination routines.
+;      __eh_frame__, __eh_init__ and __eh_term__ are GCC exception handling info.
+;      __fork_parent1__ and __fork_child1__ are lists with fork time callbacks.
+;      __libc_sysctl__ are lists with sysctl registration structure pointers.
+;
+%if KLIBC_OBJFMT == KLIBC_OBJFMT_AOUT
+ %fatal "AOUT is not suported.
+%endif
+KLIBC_OS2_SET_VECTOR_DEFINE _os2dll
+KLIBC_OS2_SET_VECTOR_DEFINE __CTOR_LIST__
+KLIBC_OS2_SET_VECTOR_DEFINE __DTOR_LIST__
+KLIBC_OS2_SET_VECTOR_DEFINE __crtinit1__
+KLIBC_OS2_SET_VECTOR_DEFINE __crtexit1__
+KLIBC_OS2_SET_VECTOR_DEFINE __libc_sysctl__
+%ifndef NOFORK
+ %ifndef NOUNIX
+KLIBC_OS2_SET_VECTOR_DEFINE __fork_child1__
+KLIBC_OS2_SET_VECTOR_DEFINE __fork_parent1__
+ %endif
+%endif
+KLIBC_OS2_SET_VECTOR_DEFINE __eh_frame__
+KLIBC_OS2_SET_VECTOR_DEFINE __eh_init__
+KLIBC_OS2_SET_VECTOR_DEFINE __eh_term__
+
+
+;;
+; __bss_start marks where the BSS segment starts.
+;
+SEG_BEGIN_BSS
+GLOBAL_DATA __bss_start
+NAME_DATA(__bss_start):
+
Index: trunk/libc/src/libc/startup/os2/x86/dll0.asm
===================================================================
--- trunk/libc/src/libc/startup/os2/x86/dll0.asm	(revision 3895)
+++ trunk/libc/src/libc/startup/os2/x86/dll0.asm	(revision 3895)
@@ -0,0 +1,353 @@
+; $Id$
+;; @file
+; kNIX - Pre-_DLL_InitTerm() startup code, OS/2.
+;
+; @copyright   Copyright (C) 2006-2014 knut st. osmundsen <bird-klibc-spam-xiv@anduin.net>
+; @licenses    MIT, BSD2, BSD3, BSD4, LGPLv2.1, LGPLv3, LGPLvFuture.
+;
+
+
+;*******************************************************************************
+;*  Header Files                                                               *
+;*******************************************************************************
+%include "klibc/asmdefs.mac"
+%include "klibc/initterm.mac"
+
+
+
+extern _DLL_InitTerm                ; System
+extern NAME_FUNC(__libc_ForkRegisterModule)
+extern NAME_FUNC(__libc_ForkDeregisterModule)
+extern NAME_FUNC(__libc_InitDll)
+extern NAME_FUNC(__libc_TermDll)
+extern NAME_FUNC(__libc_Back_initDllLoadException)
+extern NAME_FUNC(_atfork_callback)
+; Add a symbol table entry which drags _end in libend into OMF links.
+extern __end
+extern _end
+
+
+SEG_BEGIN_CODE
+
+;;
+; The OS/2 library entry point.
+;
+; We emulate _DLL_InitTerm for EMX and VAC compatibility up to a point.
+; That is, we don't let the extra termination call on load failure get
+; to _DLL_InitTerm(). Should a fatal exception arise during init we
+; will catch it and make the load fail.
+;
+; EAX = EBX = ECX = EDX = ESI = EDI = EBP = GS = 0.
+; CS = flat code selector.
+; DS = ES = SS = flat data selector.
+; FS = TIB selector.
+; EFLAGS=undefined
+;
+;
+; @returns exit code to pass to DosExit(1, rc);
+; @param   hmod         [ebp +  8h]   The executable module handle.
+; @param   fFlag        [ebp + 0ch]   Why we're called.
+;
+GLOBAL_FUNC _text
+..start:
+NAME_FUNC(_text):
+        ;
+        ; Clear DF, create a stack frame, and setup the exception handler.
+        ;
+        cld
+        push    ebp
+        mov     ebp, esp
+
+        push    dll0_exception_handler
+        push    dword [fs:0]            ; tib_pexchain
+        mov     dword [fs:0], esp
+
+        sub     esp, 01ch
+
+        ;
+        ; What are we in for?
+        ;
+        mov     eax, [ebp + 0ch]
+        or      eax, eax
+        je      .dll0_init
+        cmp     eax, 1
+        je      .dll0_term
+        jmp     .return_failure         ; something's busted.
+
+
+;
+; Initialize the DLL.
+;
+.dll0_init:
+%ifndef NOFORK
+ %ifndef NOUNIX
+        ;
+        ; Update g_ForkModule.hmod and call __libc_ForkRegisterModule(&g_ForkModule) to
+        ; register the fork module. The return code is < 0 on error, 0 on normal load, > 0 on fork.
+        ;
+        mov     eax, [ebp + 8]          ; hmod
+        mov     [g_ForkModule_hmod], eax
+
+        mov     dword [esp], g_ForkModule
+        call    NAME_FUNC(__libc_ForkRegisterModule)
+        cmp     eax, 0
+        je      .dll0_init_not_forking
+        jg      .return_success         ; %eax > 0: we're forking; no init.
+        jmp     .return_failure         ; %eax < 0: the call failed.
+.dll0_init_not_forking:
+        mov      byte [g_fCalledForkRegisterModule], 1
+ %endif
+%endif
+
+        ;
+        ; Call __libc_InitDll(hmod, NULL, fFlags) to initialized the CRT for this DLL.
+        ;
+%ifdef HIGHMEM
+ %define F1     __LIBC_INIT_FLAGS_MEM_HIGH
+%else
+ %define F1     0
+%endif
+%ifdef NOUNIX
+ %define F2     __LIBC_INIT_FLAGS_NO_UNIX
+%else
+ %define F2     0
+%endif
+%ifdef ARGS_RESP
+ %define F3     __LIBC_INIT_FLAGS_EXPAND_RESPONSE_FILE
+%else
+ %define F3     0
+%endif
+%ifdef ARGS_WILD
+ %define F4     __LIBC_INIT_FLAGS_EXPAND_WILDCARDS
+%else
+ %define F4     0
+%endif
+        mov     dword [esp + 8], F1+F2+F3+F4  ; fFlags
+        mov     dword [esp + 4], 0      ; pvOS
+        mov     eax, [ebp + 8]
+        mov     [esp], eax              ; hmod
+        call    NAME_FUNC(__libc_InitDll)
+        or      eax, eax
+        jnz     .dll0_term_fork_module
+        mov     byte [g_fCalledInitDll], 1
+
+        ;
+        ; We can now invoke _DLL_InitTerm(hmod, 0).
+        ;
+        mov     dword [esp + 4], 0      ; fFlags = 0
+        mov     eax, [ebp + 8]
+        mov     [esp], eax              ; hmod
+        call    _DLL_InitTerm
+        or      eax, eax,
+        jz      .dll0_term_crt          ; it failed.
+        mov     byte [g_fCalled_DLL_InitTerm], 1
+
+.return_success:
+        mov     edx, [ebp -8]
+        mov     [fs:0], edx
+
+        mov    eax, 1
+        leave
+        ret
+
+
+;
+; DLL Termination / Init Bailout.
+;
+; The termination return code is ignored, so we return 'failure' (0) regardless
+; of we're cleaning up from a failed init or are actually in a real termination call.
+;
+.dll0_term:
+        ;
+        ; _DLL_InitTerm(hmod, 1).
+        ;
+        cmp     byte [g_fCalled_DLL_InitTerm], 1
+        jne     .dll0_term_crt
+
+        mov     dword [esp + 4], 1      ; fFlags = 1 = termination
+        mov     eax, [ebp + 8]
+        mov     [esp], eax              ; hmod
+        mov     byte [g_fCalled_DLL_InitTerm], 0
+        call    _DLL_InitTerm
+
+        ;
+        ; Call __libc_TermDll(hmod, NULL, fFlags).
+        ;
+.dll0_term_crt:
+        cmp     byte [g_fCalledInitDll], 1
+        jne     .dll0_term_fork_module
+
+        mov     dword [esp + 8], F1+F2+F3+F4 ; fFlags
+        mov     dword [esp + 4], 0      ; pvOS
+        mov     eax, [ebp + 8]
+        mov     [esp], eax              ; hmod
+        mov     byte [g_fCalledInitDll], 0
+        call    NAME_FUNC(__libc_TermDll)
+
+        ;
+        ; __libc_ForkDeregisterModule($g_ForkModule)
+        ;
+.dll0_term_fork_module:
+%ifndef NOFORK
+ %ifndef NOUNIX
+        cmp     byte [g_fCalledForkRegisterModule], 1
+        jne     .dll0_term_done
+
+        mov     dword [esp], g_ForkModule
+        mov     byte [g_fCalledForkRegisterModule], 0
+        call    NAME_FUNC(__libc_ForkDeregisterModule)
+
+.dll0_term_done:
+ %endif
+%endif
+
+.return_failure:
+        mov     edx, [ebp - 8]
+        mov     [fs:0], edx
+
+        xor     eax, eax
+        leave
+        ret
+
+
+;;
+; Exception handler.
+;
+; @param   pXcptRepRec     [ebp + 0x08]
+; @param   pXcptRegRec     [ebp + 0x0c]
+; @param   pCtx            [ebp + 0x10]
+; @param   pvWhatever      [ebp + 0x14]
+;
+dll0_exception_handler:
+        cld
+        push    ebp
+        mov     ebp, esp
+
+        ;
+        ; Call ___libc_Back_initDllLoadException and let it decide what to do.
+        ; It returns 0 if we should continue search the exception handler chain.
+        ; It returns -1 if we resume execution.
+        ; All other return codes means that we should abort the DLL load.
+        ;
+        push    dword [ebp + 14h]
+        push    dword [ebp + 10h]
+        push    dword [ebp + 0ch]
+        push    dword [ebp + 08h]
+        call    NAME_FUNC(__libc_Back_initDllLoadException)
+        or      eax, eax
+        jz      .dll0_xcpt_return
+        cmp     eax, 0ffffffffh
+        je      .dll0_xcpt_return
+
+        ;
+        ; Abort the loading / termination.
+        ; We use pXcptRegRec as a navigation point to calculate %ebp and %esp.
+        ;
+        mov     eax, [ebp + 0ch]
+        lea     ebp, [eax + 8]
+        lea     esp, [eax - 14h]
+        ;; @todo Have to save non-volatile registes for this to really work!
+        jmp     NAME_FUNC(_text).dll0_term
+
+        ;
+        ; Continue search or execution.
+        ;
+.dll0_xcpt_return:
+        leave
+        ret
+
+
+
+;
+; __data_start (and __data) marks the start of the data segment.
+;
+; By convention required by emxbind, the datasegment starts with
+; a magic number followed by a pointer to the list of OS/2 DLL
+; references. When linking OMF this is not used by anyone.
+;
+SEG_BEGIN_DATA
+GLOBAL_DATA __data_start
+GLOBAL_DATA _data
+NAME_DATA(__data_start):
+NAME_DATA(_data):
+        dd  0x00ba0bab                  ; Magic number (error detection).
+        dd  NAME_DATA(_os2dll)          ; List of OS/2 DLL references.
+
+;; Indicates that we've called __libc_InitDll() and should call __libc_TermDll().
+g_fCalledInitDll:
+        db  0
+;; Indicates that we've called _DLL_InitTerm(,0) and should call _DLL_InitTerm(,1).
+g_fCalled_DLL_InitTerm:
+        db   0
+;; Indicates that we've called __libc_ForkRegisterModule() and should call __libc_ForkDeregisterModule().
+g_fCalledForkRegisterModule:
+        db  0
+        db  0                           ;  alignment
+        dd  0                           ;  alignment
+
+%ifndef NOFORK
+ %ifndef NOUNIX
+;;
+; The fork module structure.
+;
+g_ForkModule:
+        dd  0x00010001                  ; uVersion (__LIBC_FORK_MODULE_VERSION)
+        dd  NAME_FUNC(_atfork_callback) ; pfnAtFork
+        dd  ___fork_parent1__           ; papParent1
+        dd  ___fork_child1__            ; papChild1
+        dd  ___data_start               ; pvDataSegBase
+        dd  _end                        ; pvDataSegEnd
+        dd  0x00000000                  ; fFlags
+        dd  0                           ; pNext
+g_ForkModule_hmod:
+        dd  0                           ; hmod
+        dd  0                           ; uReserved[7]
+        dd  0                           ; uReserved[7]
+        dd  0                           ; uReserved[7]
+        dd  0                           ; uReserved[7]
+        dd  0                           ; uReserved[7]
+        dd  0                           ; uReserved[7]
+        dd  0                           ; uReserved[7]
+ %endif
+%endif
+
+
+
+;
+; Start all the a.out SETs the CRT and GCC are making use of.
+;
+;      _os2dll is used by emxbind/ld for dll imports.
+;      __CTOR_LIST__ and __DTOR_LIST__ are lists of static constructors and destructors.
+;      __crtinit1__ is the list of static crt init routines.
+;      __crtinit2__ is the list of static crt termination routines.
+;      __eh_frame__, __eh_init__ and __eh_term__ are GCC exception handling info.
+;      __fork_parent1__ and __fork_child1__ are lists with fork time callbacks.
+;      __libc_sysctl__ are lists with sysctl registration structure pointers.
+;
+%if KLIBC_OBJFMT == KLIBC_OBJFMT_AOUT
+ %fatal "AOUT is not suported.
+%endif
+KLIBC_OS2_SET_VECTOR_DEFINE _os2dll
+KLIBC_OS2_SET_VECTOR_DEFINE __CTOR_LIST__
+KLIBC_OS2_SET_VECTOR_DEFINE __DTOR_LIST__
+KLIBC_OS2_SET_VECTOR_DEFINE __crtinit1__
+KLIBC_OS2_SET_VECTOR_DEFINE __crtexit1__
+KLIBC_OS2_SET_VECTOR_DEFINE __libc_sysctl__
+%ifndef NOFORK
+ %ifndef NOUNIX
+KLIBC_OS2_SET_VECTOR_DEFINE __fork_child1__
+KLIBC_OS2_SET_VECTOR_DEFINE __fork_parent1__
+ %endif
+%endif
+KLIBC_OS2_SET_VECTOR_DEFINE __eh_frame__
+KLIBC_OS2_SET_VECTOR_DEFINE __eh_init__
+KLIBC_OS2_SET_VECTOR_DEFINE __eh_term__
+
+
+;;
+; __bss_start marks where the BSS segment starts.
+;
+SEG_BEGIN_BSS
+GLOBAL_DATA __bss_start
+NAME_DATA(__bss_start):
+
