summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authormidipix <writeonce@midipix.org>2015-04-05 17:05:57 -0400
committermidipix <writeonce@midipix.org>2015-04-05 17:05:57 -0400
commit296178913c5dfbc2b35842fc16ed680ef51fd402 (patch)
tree6720928dbc03c3d656229d2509eda38f6eb0628b
parent20a5ca45ef2f5716e8f2dea42c7e8a6b3367619f (diff)
downloadmmglue-296178913c5dfbc2b35842fc16ed680ef51fd402.tar.bz2
mmglue-296178913c5dfbc2b35842fc16ed680ef51fd402.tar.xz
nt32: initial commit of core port files.
signed-off by Z. Gilboa; see copying.midipix (9cd0746c) for additional information.
-rw-r--r--arch/nt32/atomic.h7
-rw-r--r--arch/nt32/psxglue.h63
-rw-r--r--arch/nt32/pthread_arch.h74
-rw-r--r--arch/nt32/reloc.h6
-rw-r--r--arch/nt32/src/crt_glue.c87
-rw-r--r--arch/nt32/src/crt_pe.c7
-rw-r--r--arch/nt32/src/crt_tls.c27
-rw-r--r--arch/nt32/src/libc_entry_point.c10
-rw-r--r--arch/nt32/src/syscall_disp.c22
-rw-r--r--arch/nt32/src/vtbl.c12
-rw-r--r--arch/nt32/syscall_arch.h58
-rw-r--r--crt/nt32/Scrt1.c2
-rw-r--r--crt/nt32/crt1.c33
-rw-r--r--crt/nt32/crtdev.c3
-rw-r--r--crt/nt32/crte.s19
-rw-r--r--crt/nt32/crti.s41
-rw-r--r--crt/nt32/crtn.s13
-rw-r--r--crt/nt32/crtposix.c3
-rw-r--r--src/env/nt32/__environ.s11
-rw-r--r--src/fcntl/nt32/posix_fadvise.c14
-rw-r--r--src/internal/nt32/libc.c7
-rw-r--r--src/internal/nt32/syscall.s5
-rw-r--r--src/ldso/nt32/dl_iterate_phdr.c10
-rw-r--r--src/ldso/nt32/dynlink.c62
-rw-r--r--src/ldso/nt32/start.s2
-rw-r--r--src/ldso/nt32/tlsdesc.c8
-rw-r--r--src/setjmp/nt32/longjmp.s9
-rw-r--r--src/setjmp/nt32/setjmp.s14
-rw-r--r--src/stdio/nt32/fflush.c6
-rw-r--r--src/thread/nt32/__set_thread_area.c13
-rw-r--r--src/thread/nt32/__tls_get_addr.c2
-rw-r--r--src/thread/nt32/clone.c54
-rw-r--r--src/thread/nt32/pthread_detach.c6
-rw-r--r--src/thread/nt32/pthread_equal.c6
-rw-r--r--src/thread/nt32/pthread_self.c10
-rw-r--r--src/thread/nt32/syscall_cp.s15
36 files changed, 741 insertions, 0 deletions
diff --git a/arch/nt32/atomic.h b/arch/nt32/atomic.h
new file mode 100644
index 0000000..d7d9365
--- /dev/null
+++ b/arch/nt32/atomic.h
@@ -0,0 +1,7 @@
+#ifndef _INTERNAL_ATOMIC_NT64_H
+#define _INTERNAL_ATOMIC_NT64_H
+
+#include "../i386/atomic.h"
+
+#endif
+
diff --git a/arch/nt32/psxglue.h b/arch/nt32/psxglue.h
new file mode 100644
index 0000000..73ad2b0
--- /dev/null
+++ b/arch/nt32/psxglue.h
@@ -0,0 +1,63 @@
+#ifndef _PSXGLUE_H_
+#define _PSXGLUE_H_
+
+#define __PSXOPT_NATIVE 0x0
+#define __PSXOPT_POSIX 0x1
+#define __PSXOPT_TTYDBG 0x2
+#define __PSXOPT_LDSO 0x4
+
+typedef int __ldso_dladdr(const void * addr, void * info);
+typedef int __ldso_dlinfo(void * dso, int req, void * res);
+typedef void * __ldso_dlsym(void * p, const char * s, void * ra);
+typedef void * __ldso_dlopen(const char * file, int mode);
+typedef int __ldso_dlclose(void *p);
+typedef char * __ldso_dlerror(void);
+typedef void __ldso_reset_tls(void);
+
+typedef void __psx_convert_thread(void);
+typedef void __psx_unmapself(void *, void *);
+typedef void * __psx_get_osfhandle(int fd);
+
+struct __ldso_vtbl {
+ __ldso_dladdr * dladdr;
+ __ldso_dlinfo * dlinfo;
+ __ldso_dlsym * dlsym;
+ __ldso_dlopen * dlopen;
+ __ldso_dlclose * dlclose;
+ __ldso_dlerror * dlerror;
+ __ldso_reset_tls * reset_tls;
+};
+
+struct __psx_vtbl {
+ __psx_convert_thread * convert_thread;
+ __psx_unmapself * unmapself;
+ __psx_get_osfhandle * get_osfhandle;
+};
+
+struct __psx_context {
+ int size;
+ int options;
+ void *** sys_vtbl;
+ struct __ldso_vtbl * ldso_vtbl;
+ struct __psx_vtbl * psx_vtbl;
+ unsigned int teb_sys_idx;
+ unsigned int teb_libc_idx;
+ void * pthread_surrogate_fn;
+ void * pthread_create_fn;
+};
+
+struct __tlca {
+ void * pthread_self;
+ int * pthread_set_child_tid;
+ int * pthread_clear_child_tid;
+ char * pthread_tls;
+ char ***pthread_dtls;
+};
+
+typedef int __psx_init_routine(
+ int * argc,
+ char *** argv,
+ char *** envp,
+ struct __psx_context * ctx);
+
+#endif
diff --git a/arch/nt32/pthread_arch.h b/arch/nt32/pthread_arch.h
new file mode 100644
index 0000000..d5f2553
--- /dev/null
+++ b/arch/nt32/pthread_arch.h
@@ -0,0 +1,74 @@
+#include <stddef.h>
+
+#define TP_ADJ(p) (p)
+#define CANCEL_REG_IP 16
+
+extern uintptr_t __teb_sys_idx;
+extern uintptr_t __teb_libc_idx;
+
+struct __os_tib {
+ void * exception_list;
+ void * stack_base;
+ void * stack_limit;
+};
+
+static __inline__ void * __os_get_teb_address(void)
+{
+ void * ptrRet;
+ __asm__ __volatile__ (
+ "mov %%fs:0x18, %0\n\t"
+ : "=r" (ptrRet) : :
+ );
+ return ptrRet;
+}
+
+
+static inline void __pthread_convert(void)
+{
+ /* (third-party thread support) */
+ __asm__ __volatile__ (
+ "push %eax\n\t"
+ "mov ___psx_vtbl,%eax\n\t"
+ "call *(%eax)\n\t"
+ "pop %eax\n\t"
+ );
+}
+
+
+static inline struct pthread ** __psx_tlca(void)
+{
+ struct pthread ** ptlca;
+ struct __os_tib * tib;
+ void ** slots;
+ void *** xslots;
+ uintptr_t sys_idx;
+
+ tib = __os_get_teb_address();
+ sys_idx = __teb_sys_idx;
+
+ if (sys_idx < 64) {
+ slots = (void **)((uintptr_t)tib + 0xa40);
+ ptlca = (struct pthread **)(slots[sys_idx]);
+ } else {
+ xslots = (void ***)((uintptr_t)tib + 0xbc0);
+ slots = *xslots;
+ ptlca = (struct pthread **)(slots[sys_idx - 64]);
+ }
+
+ return ptlca;
+}
+
+
+static inline struct pthread * __pthread_self(void)
+{
+ struct pthread ** ptlca;
+
+ ptlca = __psx_tlca();
+ if (ptlca) return *ptlca;
+
+ /* (third-party thread) */
+ __pthread_convert();
+ ptlca = __psx_tlca();
+ return *ptlca;
+}
+
diff --git a/arch/nt32/reloc.h b/arch/nt32/reloc.h
new file mode 100644
index 0000000..20abf44
--- /dev/null
+++ b/arch/nt32/reloc.h
@@ -0,0 +1,6 @@
+#define LDSO_ARCH "PE32+"
+
+static int remap_rel(int type)
+{
+ return 0;
+}
diff --git a/arch/nt32/src/crt_glue.c b/arch/nt32/src/crt_glue.c
new file mode 100644
index 0000000..abfd1fe
--- /dev/null
+++ b/arch/nt32/src/crt_glue.c
@@ -0,0 +1,87 @@
+#include <unistd.h>
+#include <pthread.h>
+#include "atomic.h"
+#include "syscall.h"
+#include "psxglue.h"
+#include "pthread_impl.h"
+
+extern struct __ldso_vtbl * __ldso_vtbl;
+extern struct __psx_vtbl * __psx_vtbl;
+
+typedef int __app_main();
+typedef int __pthread_surrogate_routine(struct pthread *);
+
+extern int _init(void);
+static int __pthread_surrogate_init(struct pthread * self);
+
+extern int __libc_start_main(
+ void * main,
+ int argc,
+ char ** argv);
+
+void __libc_entry_routine(
+ __app_main * __main,
+ __psx_init_routine * __psx_init,
+ int options)
+{
+ int argc;
+ char ** argv;
+ char ** envp;
+ struct __psx_context ctx;
+
+ /* ctx init */
+ ctx.size = sizeof(ctx);
+ ctx.options = options;
+ ctx.pthread_create_fn = pthread_create;
+ ctx.pthread_surrogate_fn= __pthread_surrogate_init;
+
+ /* __psx_init must succeed... */
+ if (__psx_init(&argc,&argv,&envp,&ctx))
+ a_crash();
+
+ /* ...and conform */
+ else if (envp != argv + (argc + 1))
+ a_crash();
+
+ /* dso init routines */
+ _init();
+
+ /* write once */
+ __syscall_vtbl = (unsigned long **)ctx.sys_vtbl;
+ __ldso_vtbl = ctx.ldso_vtbl;
+ __psx_vtbl = ctx.psx_vtbl;
+ __teb_sys_idx = ctx.teb_sys_idx;
+ __teb_libc_idx = ctx.teb_libc_idx;
+
+ /* enter libc */
+ __libc_start_main(__main,argc,argv);
+
+ /* guard */
+ a_crash();
+}
+
+static int __pthread_surrogate_init(struct pthread * self)
+{
+ /**
+ * invoked by psxscl upon creation of a surrogate libc
+ * thread, which in turn may only call pthread_create();
+ *
+ * the purpose of this mecahnism is to support a scenario
+ * where a third-party library creates a non-posix thread
+ * which then calls, be it directly or via a callback
+ * function, a libc api that depends on a valid
+ * pthread_self.
+ *
+ * self: a pointer to an already zero'ed memory page
+ *
+ * struct pthread relevant members:
+ * --------------------------------
+ * cancel (already zero)
+ * canary (already zero)
+ *
+ * pthread_create() reference:
+ * 1a47ed15eebf96d0c8d5de4aea54108bc8cc3f53
+ **/
+
+ return 0;
+}
diff --git a/arch/nt32/src/crt_pe.c b/arch/nt32/src/crt_pe.c
new file mode 100644
index 0000000..0dc75a4
--- /dev/null
+++ b/arch/nt32/src/crt_pe.c
@@ -0,0 +1,7 @@
+#include "pthread_impl.h"
+#include <threads.h>
+
+void * __pthread_getspecific_impl(pthread_key_t k)
+{
+ return (__pthread_self())->tsd[k];
+}
diff --git a/arch/nt32/src/crt_tls.c b/arch/nt32/src/crt_tls.c
new file mode 100644
index 0000000..15183d3
--- /dev/null
+++ b/arch/nt32/src/crt_tls.c
@@ -0,0 +1,27 @@
+#include <stdint.h>
+#include <stddef.h>
+#include "psxglue.h"
+#include "pthread_arch.h"
+
+typedef unsigned int __tls_word __attribute__((mode(word)));
+typedef unsigned int __tls_ptr __attribute__((mode(pointer)));
+
+struct __emutls_object
+{
+ __tls_word size;
+ __tls_word align;
+ ptrdiff_t offset;
+ void * defval;
+};
+
+void * __emutls_get_address (struct __emutls_object * obj)
+{
+ int dsoidx = obj->align & 0xFFFF0000;
+ struct __tlca * tlca = (struct __tlca *)__psx_tlca();
+
+ if (dsoidx)
+ return (*tlca->pthread_dtls)[dsoidx >> 16] + obj->offset;
+ else
+ return tlca->pthread_tls + obj->offset;
+}
+
diff --git a/arch/nt32/src/libc_entry_point.c b/arch/nt32/src/libc_entry_point.c
new file mode 100644
index 0000000..0929cc4
--- /dev/null
+++ b/arch/nt32/src/libc_entry_point.c
@@ -0,0 +1,10 @@
+typedef unsigned int uint32_t;
+
+int __libc_entry_point(
+ void * hinstance,
+ uint32_t reason,
+ void * reserved)
+{
+ return 1;
+}
+
diff --git a/arch/nt32/src/syscall_disp.c b/arch/nt32/src/syscall_disp.c
new file mode 100644
index 0000000..3369ca0
--- /dev/null
+++ b/arch/nt32/src/syscall_disp.c
@@ -0,0 +1,22 @@
+#include <stdint.h>
+#include <stddef.h>
+#include "syscall.h"
+#include "psxglue.h"
+
+extern struct __psx_vtbl * __psx_vtbl;
+
+void __unmapself(void * base, size_t size)
+{
+ __psx_vtbl->unmapself(base,(void *)size);
+}
+
+uintptr_t __syscall_disp(long n,
+ uintptr_t a1,
+ uintptr_t a2,
+ uintptr_t a3,
+ uintptr_t a4,
+ uintptr_t a5,
+ uintptr_t a6)
+{
+ return __syscall(n,a1,a2,a3,a4,a5,a6);
+}
diff --git a/arch/nt32/src/vtbl.c b/arch/nt32/src/vtbl.c
new file mode 100644
index 0000000..7e9c0e8
--- /dev/null
+++ b/arch/nt32/src/vtbl.c
@@ -0,0 +1,12 @@
+#include "psxglue.h"
+
+unsigned long ** __syscall_vtbl = 0;
+struct __ldso_vtbl * __ldso_vtbl = 0;
+struct __psx_vtbl * __psx_vtbl = 0;
+unsigned long __teb_sys_idx = 0;
+unsigned long __teb_libc_idx = 0;
+
+void __chkstk_ms(void)
+{
+}
+
diff --git a/arch/nt32/syscall_arch.h b/arch/nt32/syscall_arch.h
new file mode 100644
index 0000000..fb3cc46
--- /dev/null
+++ b/arch/nt32/syscall_arch.h
@@ -0,0 +1,58 @@
+extern unsigned long ** __syscall_vtbl;
+
+typedef long __syscall0_fn(void);
+typedef long __syscall1_fn(long a1);
+typedef long __syscall2_fn(long a1, long a2);
+typedef long __syscall3_fn(long a1, long a2, long a3);
+typedef long __syscall4_fn(long a1, long a2, long a3, long a4);
+typedef long __syscall5_fn(long a1, long a2, long a3, long a4, long a5);
+typedef long __syscall6_fn(long a1, long a2, long a3, long a4, long a5, long a6);
+
+#define sysfn_from_fn(x) \
+ x * sysfn = (x *)__syscall_vtbl[n]
+
+static __inline long __syscall0(long n)
+{
+ sysfn_from_fn(__syscall0_fn);
+ return sysfn();
+}
+
+static __inline long __syscall1(long n, long a1)
+{
+ sysfn_from_fn(__syscall1_fn);
+ return sysfn(a1);
+}
+
+static __inline long __syscall2(long n, long a1, long a2)
+{
+ sysfn_from_fn(__syscall2_fn);
+ return sysfn(a1, a2);
+}
+
+static __inline long __syscall3(long n, long a1, long a2, long a3)
+{
+ sysfn_from_fn(__syscall3_fn);
+ return sysfn(a1, a2, a3);
+}
+
+static __inline long __syscall4(long n, long a1, long a2, long a3, long a4)
+{
+ sysfn_from_fn(__syscall4_fn);
+ return sysfn(a1, a2, a3, a4);
+}
+
+static __inline long __syscall5(long n, long a1, long a2, long a3, long a4, long a5)
+{
+ sysfn_from_fn(__syscall5_fn);
+ return sysfn(a1, a2, a3, a4, a5);
+}
+
+static __inline long __syscall6(long n, long a1, long a2, long a3, long a4, long a5, long a6)
+{
+ sysfn_from_fn(__syscall6_fn);
+ return sysfn(a1, a2, a3, a4, a5, a6);
+}
+
+
+#define __SYSCALL_LL_E(x) (x)
+#define __SYSCALL_LL_O(x) (x)
diff --git a/crt/nt32/Scrt1.c b/crt/nt32/Scrt1.c
new file mode 100644
index 0000000..ff5789f
--- /dev/null
+++ b/crt/nt32/Scrt1.c
@@ -0,0 +1,2 @@
+#define LIBC_STATIC
+#include "crt1.c"
diff --git a/crt/nt32/crt1.c b/crt/nt32/crt1.c
new file mode 100644
index 0000000..6d22669
--- /dev/null
+++ b/crt/nt32/crt1.c
@@ -0,0 +1,33 @@
+#ifdef LIBC_STATIC
+#define __external_routine
+#else
+#define __external_routine __attribute__((dllimport))
+#endif
+
+#include "psxglue.h"
+
+/**
+ * options: posix session, fallback terminal emulator
+ * x86_64-nt64-midipix-gcc --target-help | grep -A2 posix
+**/
+
+static const int __disabled = 0;
+extern const int __crtopt_posix __attribute((weak,alias("__disabled")));
+extern const int __crtopt_ttydbg __attribute((weak,alias("__disabled")));
+
+int main();
+
+__external_routine
+__psx_init_routine __psx_init;
+
+__external_routine
+void __libc_entry_routine(void *,void *,int);
+
+void _start(void)
+{
+ __libc_entry_routine(
+ main,
+ __psx_init,
+ __crtopt_posix | __crtopt_ttydbg);
+}
+
diff --git a/crt/nt32/crtdev.c b/crt/nt32/crtdev.c
new file mode 100644
index 0000000..8aa80e6
--- /dev/null
+++ b/crt/nt32/crtdev.c
@@ -0,0 +1,3 @@
+#include "psxglue.h"
+
+const int __crtopt_ttydbg = __PSXOPT_TTYDBG;
diff --git a/crt/nt32/crte.s b/crt/nt32/crte.s
new file mode 100644
index 0000000..56fa138
--- /dev/null
+++ b/crt/nt32/crte.s
@@ -0,0 +1,19 @@
+.text
+.globl __so_entry_point
+__so_entry_point:
+ cmp $0x1,%edx
+ jne _dso_main_routine
+ mov %edx,%eax
+ ret
+
+___dso_main_routine:
+ ret
+
+ .weak _dso_main_routine
+ .set _dso_main_routine,___dso_main_routine
+
+.section .midipix
+ .long _dso_main_routine
+ .long __so_entry_point
+ .long __init
+ .long __fini
diff --git a/crt/nt32/crti.s b/crt/nt32/crti.s
new file mode 100644
index 0000000..7b1a642
--- /dev/null
+++ b/crt/nt32/crti.s
@@ -0,0 +1,41 @@
+.text
+.globl __pei386_runtime_relocator
+__pei386_runtime_relocator:
+ ret
+
+.globl __init
+__init:
+ call .init
+ ret
+
+.globl __fini
+__fini:
+ call .fini
+ ret
+
+.section .init
+ xor %eax,%eax
+ push %eax
+ push %ecx
+ push %edx
+ nop
+ nop
+
+.section .fini
+ xor %eax,%eax
+ push %eax
+ push %ecx
+ push %edx
+ nop
+ nop
+
+.section .midipix
+ .ascii "e35ed272"
+ .ascii "9e55"
+ .ascii "46c1"
+ .ascii "8251"
+ .ascii "022a59e6c480"
+ .long 0
+ .long 1
+ .long 0
+ .long 0
diff --git a/crt/nt32/crtn.s b/crt/nt32/crtn.s
new file mode 100644
index 0000000..2d0295e
--- /dev/null
+++ b/crt/nt32/crtn.s
@@ -0,0 +1,13 @@
+.section .init
+ pop %edx
+ pop %ecx
+ pop %ebx
+ or %ebx,%eax
+ ret
+
+.section .fini
+ pop %edx
+ pop %ecx
+ pop %ebx
+ or %ebx,%eax
+ ret
diff --git a/crt/nt32/crtposix.c b/crt/nt32/crtposix.c
new file mode 100644
index 0000000..b8e5113
--- /dev/null
+++ b/crt/nt32/crtposix.c
@@ -0,0 +1,3 @@
+#include "psxglue.h"
+
+const int __crtopt_posix = __PSXOPT_POSIX;
diff --git a/src/env/nt32/__environ.s b/src/env/nt32/__environ.s
new file mode 100644
index 0000000..62b9ee6
--- /dev/null
+++ b/src/env/nt32/__environ.s
@@ -0,0 +1,11 @@
+.globl ____environ
+.globl ___environ
+.globl __environ
+.globl _environ
+
+.data
+____environ:
+___environ:
+__environ:
+_environ:
+ .long 0
diff --git a/src/fcntl/nt32/posix_fadvise.c b/src/fcntl/nt32/posix_fadvise.c
new file mode 100644
index 0000000..c95d7f4
--- /dev/null
+++ b/src/fcntl/nt32/posix_fadvise.c
@@ -0,0 +1,14 @@
+#include "fcntl.h"
+#include "syscall_arch.h"
+
+int posix_fadvise (int fd, off_t base, off_t len, int advice)
+{
+ /**
+ * __syscall is needed here due to the odd semantics
+ * of posix_fadvise(), which for us means calling
+ * __sys_fadvise() directly.
+ **/
+
+ return 0; /* __sys_fadvise (fd, base, len, advice); */
+}
+
diff --git a/src/internal/nt32/libc.c b/src/internal/nt32/libc.c
new file mode 100644
index 0000000..43face8
--- /dev/null
+++ b/src/internal/nt32/libc.c
@@ -0,0 +1,7 @@
+#include "../libc.h"
+
+/* todo: teach the linker to export weak symbols */
+#undef weak_alias
+#define weak_alias(old,new) extern __typeof(old) new __attribute__((alias(#old)))
+
+#include "../libc.c"
diff --git a/src/internal/nt32/syscall.s b/src/internal/nt32/syscall.s
new file mode 100644
index 0000000..3fcd5bb
--- /dev/null
+++ b/src/internal/nt32/syscall.s
@@ -0,0 +1,5 @@
+.text
+.global ___syscall
+
+___syscall:
+ jmp ___syscall_disp
diff --git a/src/ldso/nt32/dl_iterate_phdr.c b/src/ldso/nt32/dl_iterate_phdr.c
new file mode 100644
index 0000000..f98a509
--- /dev/null
+++ b/src/ldso/nt32/dl_iterate_phdr.c
@@ -0,0 +1,10 @@
+#include <stddef.h>
+#include <dlfcn.h>
+#include <link.h>
+
+typedef int __ldso_phdr_callback(struct dl_phdr_info * info, size_t size, void * data);
+
+int dl_iterate_phdr(__ldso_phdr_callback * callback, void * data)
+{
+ return -1;
+}
diff --git a/src/ldso/nt32/dynlink.c b/src/ldso/nt32/dynlink.c
new file mode 100644
index 0000000..c3cb23e
--- /dev/null
+++ b/src/ldso/nt32/dynlink.c
@@ -0,0 +1,62 @@
+#define _BSD_SOURCE
+
+#include <dlfcn.h>
+#include "psxglue.h"
+#include "pthread_impl.h"
+
+extern struct __ldso_vtbl * __ldso_vtbl;
+
+int __dladdr(const void * addr, Dl_info * info)
+{
+ return __ldso_vtbl->dladdr(addr,info);
+}
+
+int __dlinfo(void * dso, int req, void * res)
+{
+ return __ldso_vtbl->dlinfo(dso,req,res);
+}
+
+void *__dlsym(void * restrict p, const char * restrict s, void * restrict ra)
+{
+ return __ldso_vtbl->dlsym(p,s,ra);
+}
+
+void * dlopen(const char * file, int mode)
+{
+ return __ldso_vtbl->dlopen(file,mode);
+}
+
+int dlclose(void *p)
+{
+ return __ldso_vtbl->dlclose(p);
+}
+
+char * dlerror(void)
+{
+ return __ldso_vtbl->dlerror();
+}
+
+void __reset_tls(void)
+{
+ __ldso_vtbl->reset_tls();
+}
+
+void *__copy_tls(unsigned char * mem)
+{
+ /**
+ * this is always the simple case, since:
+ * emutls is based on PE named sections; and
+ * tls allocation and initialization are handled by clone(2)
+ **/
+
+ pthread_t td;
+ void ** dtv;
+
+ dtv = (void **)mem;
+ dtv[0] = 0;
+
+ td = (void *)(dtv + 1);
+ td->dtv = dtv;
+
+ return td;
+}
diff --git a/src/ldso/nt32/start.s b/src/ldso/nt32/start.s
new file mode 100644
index 0000000..32dc52f
--- /dev/null
+++ b/src/ldso/nt32/start.s
@@ -0,0 +1,2 @@
+# standard dynamic loader is not required
+# optional dynamic loader [to be] provided by libldso/libpsxscl
diff --git a/src/ldso/nt32/tlsdesc.c b/src/ldso/nt32/tlsdesc.c
new file mode 100644
index 0000000..7015e30
--- /dev/null
+++ b/src/ldso/nt32/tlsdesc.c
@@ -0,0 +1,8 @@
+#include <stddef.h>
+
+ptrdiff_t __tlsdesc_static(void)
+{
+ return 0;
+}
+
+ptrdiff_t __tlsdesc_dynamic(void) __attribute__((alias("__tlsdesc_static")));
diff --git a/src/setjmp/nt32/longjmp.s b/src/setjmp/nt32/longjmp.s
new file mode 100644
index 0000000..095a47f
--- /dev/null
+++ b/src/setjmp/nt32/longjmp.s
@@ -0,0 +1,9 @@
+.text
+.globl ___longjmp
+.globl __longjmp
+.globl _longjmp
+
+___longjmp:
+__longjmp:
+_longjmp:
+ test %edx, %edx # is val zero?
diff --git a/src/setjmp/nt32/setjmp.s b/src/setjmp/nt32/setjmp.s
new file mode 100644
index 0000000..1865f0c
--- /dev/null
+++ b/src/setjmp/nt32/setjmp.s
@@ -0,0 +1,14 @@
+.text
+.globl ___setjmp
+.globl __setjmp
+.globl _setjmp
+
+___setjmp:
+__setjmp:
+_setjmp:
+ pop (%ecx) # return address
+ mov %esp, 0x04(%ecx) # caller's stack pointer
+ push (%ecx) # restore own stack pointer
+
+ xor %eax, %eax
+ ret
diff --git a/src/stdio/nt32/fflush.c b/src/stdio/nt32/fflush.c
new file mode 100644
index 0000000..4c88f20
--- /dev/null
+++ b/src/stdio/nt32/fflush.c
@@ -0,0 +1,6 @@
+#include "../fflush.c"
+
+int __fflush_unlocked_impl(FILE *f)
+{
+ return __fflush_unlocked(f);
+}
diff --git a/src/thread/nt32/__set_thread_area.c b/src/thread/nt32/__set_thread_area.c
new file mode 100644
index 0000000..c50f6c6
--- /dev/null
+++ b/src/thread/nt32/__set_thread_area.c
@@ -0,0 +1,13 @@
+#include <errno.h>
+#include "pthread_impl.h"
+
+int __set_thread_area(void * p)
+{
+ struct pthread ** ptlca;
+
+ ptlca = __psx_tlca();
+ if (!ptlca) return -ESRCH;
+
+ *ptlca = p;
+ return 0;
+}
diff --git a/src/thread/nt32/__tls_get_addr.c b/src/thread/nt32/__tls_get_addr.c
new file mode 100644
index 0000000..ad8d845
--- /dev/null
+++ b/src/thread/nt32/__tls_get_addr.c
@@ -0,0 +1,2 @@
+/* using a custom, register-based __emutls_get_address */
+typedef int dummy;
diff --git a/src/thread/nt32/clone.c b/src/thread/nt32/clone.c
new file mode 100644
index 0000000..fb53501
--- /dev/null
+++ b/src/thread/nt32/clone.c
@@ -0,0 +1,54 @@
+#include <syscall.h>
+
+struct pt_regs {
+ unsigned long ebp;
+ unsigned long ebx;
+ unsigned long eax;
+ unsigned long ecx;
+ unsigned long edx;
+ unsigned long esi;
+ unsigned long edi;
+ unsigned long orig_eax;
+ unsigned long eip;
+ unsigned long cs;
+ unsigned long eflags;
+ unsigned long esp;
+ unsigned long ss;
+};
+
+typedef long __sys_clone(
+ unsigned long flags,
+ void * child_stack,
+ void * ptid,
+ void * ctid,
+ struct pt_regs *regs);
+
+typedef int __entry_point(void *);
+
+extern unsigned long ** __syscall_vtbl;
+
+int __clone(
+ __entry_point * fn,
+ void * child_stack,
+ int flags,
+ void * arg,
+ int * ptid,
+ void * pthread_self_addr,
+ int * ctid)
+{
+ struct pt_regs regs;
+ __sys_clone * pfn_clone;
+
+ regs.eip = (unsigned long)fn;
+ regs.ecx = (unsigned long)arg;
+ regs.edx = (unsigned long)pthread_self_addr;
+
+ pfn_clone = (__sys_clone *)(__syscall_vtbl[SYS_clone]);
+
+ return (int)pfn_clone(
+ flags,
+ child_stack,
+ ptid,
+ ctid,
+ &regs);
+}
diff --git a/src/thread/nt32/pthread_detach.c b/src/thread/nt32/pthread_detach.c
new file mode 100644
index 0000000..85db4cb
--- /dev/null
+++ b/src/thread/nt32/pthread_detach.c
@@ -0,0 +1,6 @@
+#include "../pthread_detach.c"
+
+int __pthread_detach_impl(pthread_t t)
+{
+ return thrd_detach(t);
+}
diff --git a/src/thread/nt32/pthread_equal.c b/src/thread/nt32/pthread_equal.c
new file mode 100644
index 0000000..a8fcd79
--- /dev/null
+++ b/src/thread/nt32/pthread_equal.c
@@ -0,0 +1,6 @@
+#include "../pthread_equal.c"
+
+int __pthread_equal_impl(pthread_t a, pthread_t b)
+{
+ return thrd_equal(a,b);
+}
diff --git a/src/thread/nt32/pthread_self.c b/src/thread/nt32/pthread_self.c
new file mode 100644
index 0000000..23fbc53
--- /dev/null
+++ b/src/thread/nt32/pthread_self.c
@@ -0,0 +1,10 @@
+#include "pthread_impl.h"
+#include <threads.h>
+#include "libc.h"
+
+pthread_t pthread_self()
+{
+ return __pthread_self();
+}
+
+weak_alias(pthread_self, thrd_current);
diff --git a/src/thread/nt32/syscall_cp.s b/src/thread/nt32/syscall_cp.s
new file mode 100644
index 0000000..c52731f
--- /dev/null
+++ b/src/thread/nt32/syscall_cp.s
@@ -0,0 +1,15 @@
+.text
+.globl ___syscall_cp_asm
+.globl ___cp_begin
+.globl ___cp_end
+
+___syscall_cp_asm:
+___cp_begin:
+ mov (%ecx), %ecx /* check content of ptr */
+ test %ecx, %ecx
+ jnz ___cancel /* thread is pending cancellation */
+
+ jmp ___syscall
+
+___cp_end:
+ ret