diff --git a/bsd-user/elfload.c b/bsd-user/elfload.c
index 8c8ed6a..0cd5fc4 100644
--- a/bsd-user/elfload.c
+++ b/bsd-user/elfload.c
@@ -27,6 +27,7 @@
 
 #include "qemu.h"
 #include "disas/disas.h"
+#include "target_os_stack.h"
 
 #ifdef _ARCH_PPC64
 #undef ARCH_DLINFO
@@ -712,38 +713,29 @@ static abi_ulong copy_elf_strings(int argc,char ** argv, void **page,
 static abi_ulong setup_arg_pages(abi_ulong p, struct bsd_binprm *bprm,
                                  struct image_info *info)
 {
-    abi_ulong stack_base, size, error;
-    int i;
+    abi_ulong stack_base, size;
+    abi_long addr;
 
     /* Create enough stack to hold everything.  If we don't use
      * it for args, we'll use it for something else...
      */
     size = target_dflssiz;
     stack_base = TARGET_USRSTACK - size;
-    error = target_mmap(0,
-                        size + qemu_host_page_size,
-                        PROT_READ | PROT_WRITE,
-                        MAP_PRIVATE | MAP_ANON,
-                        -1, 0);
-    if (error == -1) {
+    addr = target_mmap(stack_base , size + qemu_host_page_size,
+            PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
+    if (addr == -1) {
         perror("stk mmap");
         exit(-1);
     }
     /* we reserve one extra page at the top of the stack as guard */
-    target_mprotect(error + size, qemu_host_page_size, PROT_NONE);
-
-    stack_base = error + size - MAX_ARG_PAGES*TARGET_PAGE_SIZE;
-    p += stack_base;
+    target_mprotect(addr + size, qemu_host_page_size, PROT_NONE);
 
-    for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
-        if (bprm->page[i]) {
-            info->rss++;
-            /* FIXME - check return value of memcpy_to_target() for failure */
-            memcpy_to_target(stack_base, bprm->page[i], TARGET_PAGE_SIZE);
-            g_free(bprm->page[i]);
-        }
-        stack_base += TARGET_PAGE_SIZE;
+    p = setup_initial_stack(p, bprm, stack_base, size, addr);
+    if (p == 0) {
+        perror("stk setup");
+        exit(-1);
     }
+
     return p;
 }
 
diff --git a/bsd-user/freebsd/target_os_stack.h b/bsd-user/freebsd/target_os_stack.h
new file mode 100644
index 0000000..f600009
--- /dev/null
+++ b/bsd-user/freebsd/target_os_stack.h
@@ -0,0 +1,124 @@
+#ifndef _TARGET_OS_STACK_H_
+#define _TARGET_OS_STACK_H_
+
+#include <sys/param.h>
+#include "target_arch_sigtramp.h"
+
+/*
+ * The inital FreeBSD stack is as follows:
+ * (see kern/kern_exec.c exec_copyout_strings() )
+ *
+ *  Hi Address -> char **ps_argvstr  (struct ps_strings for ps, w, etc.)
+ *                unsigned ps_nargvstr
+ *                char **ps_envstr
+ *  PS_STRINGS -> unsigned ps_nenvstr
+ *
+ *                machine dependent sigcode (sv_sigcode of size
+ *                                           sv_szsigcode)
+ *
+ *                execpath          (absolute image path for rtld)
+ *
+ *                SSP Canary        (sizeof(long) * 8)
+ *
+ *                page sizes array  (usually sizeof(u_long) )
+ *
+ *  "destp" ->    argv, env strings (up to 262144 bytes)
+ */
+static inline abi_ulong setup_initial_stack(abi_ulong p,
+        struct bsd_binprm *bprm, abi_ulong stack_base, abi_ulong size,
+        abi_ulong addr)
+{
+    int i;
+    abi_ulong stack_hi_addr;
+    size_t execpath_len;
+    abi_ulong destp, argvp, envp;
+    struct target_ps_strings ps_strs;
+    char canary[sizeof(abi_long) * 8];
+
+    stack_hi_addr = p = addr + size;
+
+    /* Save some space for ps_strings. */
+    p -= sizeof(struct target_ps_strings);
+
+#ifdef TARGET_SZSIGCODE
+    /* Add machine depedent sigcode. */
+    p -= TARGET_SZSIGCODE;
+    if (setup_sigtramp(p, (unsigned)offsetof(struct target_sigframe, sf_uc),
+            TARGET_FREEBSD_NR_sigreturn)) {
+        return 0;
+    }
+#endif
+    if (bprm->fullpath) {
+        execpath_len = strlen(bprm->fullpath) + 1;
+        p -= roundup(execpath_len, sizeof(abi_ulong));
+        if (memcpy_to_target(p, bprm->fullpath, execpath_len)) {
+            return 0;
+        }
+    }
+    /* Add canary for SSP. */
+    arc4random_buf(canary, sizeof(canary));
+    p -= roundup(sizeof(canary), sizeof(abi_ulong));
+    if (memcpy_to_target(p, canary, sizeof(canary))) {
+        return 0;
+    }
+    /* Add page sizes array. */
+    p -= sizeof(abi_ulong);
+    if (put_user_ual(TARGET_PAGE_SIZE, p)) {
+        return 0;
+    }
+    argvp = p - TARGET_SPACE_USRSPACE;
+    p = destp = p - TARGET_SPACE_USRSPACE - TARGET_ARG_MAX;
+    /* XXX check strlen(argv and envp strings) < TARGET_ARG_MAX ? */
+
+    /*
+     * Add argv strings.  Note that the argv[] vectors are added by
+     * loader_build_argptr()
+     */
+    envp = argvp + (bprm->argc + 2) * sizeof(abi_ulong);
+    ps_strs.ps_argvstr = tswapl(argvp);
+    ps_strs.ps_nargvstr = tswap32(bprm->argc);
+    for (i = 0; i < bprm->argc; ++i) {
+        size_t len = strlen(bprm->argv[i]) + 1;
+
+        if (memcpy_to_target(destp, bprm->argv[i], len)) {
+            return 0;
+        }
+        if (put_user_ual(destp, argvp)) {
+            return 0;
+        }
+        argvp += sizeof(abi_ulong);
+        destp += len;
+    }
+    if (put_user_ual(0, argvp)) {
+        return 0;
+    }
+    /*
+     * Add env strings. Note that the envp[] vectors are added by
+     * loader_build_argptr().
+     */
+    ps_strs.ps_envstr = tswapl(envp);
+    ps_strs.ps_nenvstr = tswap32(bprm->envc);
+    for (i = 0; i < bprm->envc; ++i) {
+        size_t len = strlen(bprm->envp[i]) + 1;
+
+        if (memcpy_to_target(destp, bprm->envp[i], len)) {
+            return 0;
+        }
+        if (put_user_ual(destp, envp)) {
+            return 0;
+        }
+        envp += sizeof(abi_ulong);
+        destp += len;
+    }
+    if (put_user_ual(0, envp)) {
+        return 0;
+    }
+    if (memcpy_to_target(stack_hi_addr - sizeof(ps_strs), &ps_strs,
+                sizeof(ps_strs))) {
+        return 0;
+    }
+
+    return p;
+ }
+
+#endif /* !_TARGET_OS_STACK_H_ */
diff --git a/bsd-user/i386/target_arch_sigtramp.h b/bsd-user/i386/target_arch_sigtramp.h
new file mode 100644
index 0000000..f0f36d1
--- /dev/null
+++ b/bsd-user/i386/target_arch_sigtramp.h
@@ -0,0 +1,11 @@
+
+#ifndef _TARGET_ARCH_SIGTRAMP_H_
+#define _TARGET_ARCH_SIGTRAMP_H_
+
+static inline abi_long setup_sigtramp(abi_ulong offset, unsigned sigf_uc,
+        unsigned sys_sigreturn)
+{
+
+    return -TARGET_EOPNOTSUPP;
+}
+#endif /* _TARGET_ARCH_SIGTRAMP_H_ */
diff --git a/bsd-user/mips/target_arch_signal.h b/bsd-user/mips/target_arch_signal.h
index cc7e750..f68034f 100644
--- a/bsd-user/mips/target_arch_signal.h
+++ b/bsd-user/mips/target_arch_signal.h
@@ -22,7 +22,7 @@
 
 #define TARGET_INSN_SIZE    4       /* mips instruction size */
 
-/* Size of the signal trampolin code placed on the stack. */
+/* Size of the signal trampolin code. See insall_sigtramp(). */
 #define TARGET_SZSIGCODE    ((abi_ulong)(4 * TARGET_INSN_SIZE))
 
 /* compare to mips/include/_limits.h */
diff --git a/bsd-user/mips/target_arch_sigtramp.h b/bsd-user/mips/target_arch_sigtramp.h
new file mode 100644
index 0000000..5e3c69a
--- /dev/null
+++ b/bsd-user/mips/target_arch_sigtramp.h
@@ -0,0 +1,23 @@
+
+#ifndef _TARGET_ARCH_SIGTRAMP_H_
+#define _TARGET_ARCH_SIGTRAMP_H_
+
+/* Compare to mips/mips/locore.S sigcode() */
+static inline abi_long setup_sigtramp(abi_ulong offset, unsigned sigf_uc,
+        unsigned sys_sigreturn)
+{
+    int i;
+    uint32_t sigtramp_code[TARGET_SZSIGCODE/TARGET_INSN_SIZE] = {
+    /* 1 */ 0x67A40000 + sigf_uc,       /* daddu   $a0, $sp, (sigf_uc) */
+    /* 2 */ 0x24020000 + sys_sigreturn, /* li      $v0, (sys_sigreturn) */
+    /* 3 */ 0x0000000C,                 /* syscall */
+    /* 4 */ 0x0000000D                  /* break */
+    };
+
+    for (i = 0; i < 4; i++) {
+        tswap32s(&sigtramp_code[i]);
+    }
+
+    return memcpy_to_target(offset, sigtramp_code, TARGET_SZSIGCODE);
+}
+#endif /* _TARGET_ARCH_SIGTRAMP_H_ */
diff --git a/bsd-user/mips64/target_arch_sigtramp.h b/bsd-user/mips64/target_arch_sigtramp.h
new file mode 100644
index 0000000..5e3c69a
--- /dev/null
+++ b/bsd-user/mips64/target_arch_sigtramp.h
@@ -0,0 +1,23 @@
+
+#ifndef _TARGET_ARCH_SIGTRAMP_H_
+#define _TARGET_ARCH_SIGTRAMP_H_
+
+/* Compare to mips/mips/locore.S sigcode() */
+static inline abi_long setup_sigtramp(abi_ulong offset, unsigned sigf_uc,
+        unsigned sys_sigreturn)
+{
+    int i;
+    uint32_t sigtramp_code[TARGET_SZSIGCODE/TARGET_INSN_SIZE] = {
+    /* 1 */ 0x67A40000 + sigf_uc,       /* daddu   $a0, $sp, (sigf_uc) */
+    /* 2 */ 0x24020000 + sys_sigreturn, /* li      $v0, (sys_sigreturn) */
+    /* 3 */ 0x0000000C,                 /* syscall */
+    /* 4 */ 0x0000000D                  /* break */
+    };
+
+    for (i = 0; i < 4; i++) {
+        tswap32s(&sigtramp_code[i]);
+    }
+
+    return memcpy_to_target(offset, sigtramp_code, TARGET_SZSIGCODE);
+}
+#endif /* _TARGET_ARCH_SIGTRAMP_H_ */
diff --git a/bsd-user/netbsd/target_os_stack.h b/bsd-user/netbsd/target_os_stack.h
new file mode 100644
index 0000000..a852ae6
--- /dev/null
+++ b/bsd-user/netbsd/target_os_stack.h
@@ -0,0 +1,31 @@
+#ifndef _TARGET_OS_STACK_H_
+#define _TARGET_OS_STACK_H_
+
+#include "target_arch_sigtramp.h"
+
+static inline abi_ulong setup_initial_stack(abi_ulong p,
+        struct bsd_binprm *bprm, abi_ulong sbase, abi_ulong size,
+        abi_ulong addr)
+{
+    int i;
+    abi_ulong stack_base;
+
+    stack_base = addr + size - MAX_ARG_PAGES * TARGET_PAGE_SIZE;
+    p += stack_base;
+
+    for (i = 0; i < MAX_ARG_PAGES; i++) {
+        if (bprm->page[i]) {
+            info->rss++;
+            if (!memcpy_to_target(stack_base, bprm->page[i],
+                        TARGET_PAGE_SIZE)) {
+                return 0;
+            }
+            g_free(bprm->page[i]);
+        }
+        stack_base += TARGET_PAGE_SIZE;
+    }
+
+    return p;
+}
+
+#endif /* !_TARGET_OS_STACK_H_ */
diff --git a/bsd-user/openbsd/target_os_stack.h b/bsd-user/openbsd/target_os_stack.h
new file mode 100644
index 0000000..a852ae6
--- /dev/null
+++ b/bsd-user/openbsd/target_os_stack.h
@@ -0,0 +1,31 @@
+#ifndef _TARGET_OS_STACK_H_
+#define _TARGET_OS_STACK_H_
+
+#include "target_arch_sigtramp.h"
+
+static inline abi_ulong setup_initial_stack(abi_ulong p,
+        struct bsd_binprm *bprm, abi_ulong sbase, abi_ulong size,
+        abi_ulong addr)
+{
+    int i;
+    abi_ulong stack_base;
+
+    stack_base = addr + size - MAX_ARG_PAGES * TARGET_PAGE_SIZE;
+    p += stack_base;
+
+    for (i = 0; i < MAX_ARG_PAGES; i++) {
+        if (bprm->page[i]) {
+            info->rss++;
+            if (!memcpy_to_target(stack_base, bprm->page[i],
+                        TARGET_PAGE_SIZE)) {
+                return 0;
+            }
+            g_free(bprm->page[i]);
+        }
+        stack_base += TARGET_PAGE_SIZE;
+    }
+
+    return p;
+}
+
+#endif /* !_TARGET_OS_STACK_H_ */
diff --git a/bsd-user/sparc/target_arch_sigtramp.h b/bsd-user/sparc/target_arch_sigtramp.h
new file mode 100644
index 0000000..f0f36d1
--- /dev/null
+++ b/bsd-user/sparc/target_arch_sigtramp.h
@@ -0,0 +1,11 @@
+
+#ifndef _TARGET_ARCH_SIGTRAMP_H_
+#define _TARGET_ARCH_SIGTRAMP_H_
+
+static inline abi_long setup_sigtramp(abi_ulong offset, unsigned sigf_uc,
+        unsigned sys_sigreturn)
+{
+
+    return -TARGET_EOPNOTSUPP;
+}
+#endif /* _TARGET_ARCH_SIGTRAMP_H_ */
diff --git a/bsd-user/sparc64/target_arch_sigtramp.h b/bsd-user/sparc64/target_arch_sigtramp.h
new file mode 100644
index 0000000..f0f36d1
--- /dev/null
+++ b/bsd-user/sparc64/target_arch_sigtramp.h
@@ -0,0 +1,11 @@
+
+#ifndef _TARGET_ARCH_SIGTRAMP_H_
+#define _TARGET_ARCH_SIGTRAMP_H_
+
+static inline abi_long setup_sigtramp(abi_ulong offset, unsigned sigf_uc,
+        unsigned sys_sigreturn)
+{
+
+    return -TARGET_EOPNOTSUPP;
+}
+#endif /* _TARGET_ARCH_SIGTRAMP_H_ */
diff --git a/bsd-user/x86_64/target_arch_sigtramp.h b/bsd-user/x86_64/target_arch_sigtramp.h
new file mode 100644
index 0000000..f0f36d1
--- /dev/null
+++ b/bsd-user/x86_64/target_arch_sigtramp.h
@@ -0,0 +1,11 @@
+
+#ifndef _TARGET_ARCH_SIGTRAMP_H_
+#define _TARGET_ARCH_SIGTRAMP_H_
+
+static inline abi_long setup_sigtramp(abi_ulong offset, unsigned sigf_uc,
+        unsigned sys_sigreturn)
+{
+
+    return -TARGET_EOPNOTSUPP;
+}
+#endif /* _TARGET_ARCH_SIGTRAMP_H_ */
