I am trying to build a gccgo (go language) cross compiler targetting an
ARM system. Go uses the context control routines for coorperative
multithreading. uClibc however does not implement them, so I am trying
to port the functions to uClibc.
The routines are available in glibc and eglibc, and for other
architectures [1]. My port builds correctly, but segfaults while running.
I noticed that (for example) the getcontext routine is quite different
from the setjmp routine shipped with uClibc. Can anybody give me some
pointers in what should be altered?
A patch of my attempt is attached.
[1]
http://git.stlinux.com/?p=stm/uclibc.git;a=commit;h=5bc8059626bea83f157017ba6ed14faea0158089
--- uClibc-0.9.33.2/Makefile.in.org 2012-06-26 11:06:17.989987413 +0200
+++ uClibc-0.9.33.2/Makefile.in 2012-06-26 11:05:02.517987412 +0200
@@ -165,6 +165,7 @@ headers: $(top_builddir)include/bits/uCl
subdirs: $(addprefix $(top_builddir),$(subdirs))
pregen-headers: $(top_builddir)include/bits/sysnum.h $(pregen-headers-y)
pregen: headers pregen-headers
+ $(Q)$(MAKE) libc_arch_headers
$(Q)$(if $(UCLIBC_HAS_LOCALE),$(MAKE) -C extra/locale locale_headers)
$(top_builddir)include/bits/sysnum.h: $(top_srcdir)extra/scripts/gen_bits_syscall_h.sh | $(top_builddir)include/bits
--- uClibc-0.9.33.2/include/ucontext.h 2012-05-15 09:20:09.000000000 +0200
+++ uclibc/include/ucontext.h 2012-06-26 10:45:46.389987413 +0200
@@ -16,6 +16,8 @@
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
+/* System V ABI compliant user-level context switching support. */
+
#ifndef _UCONTEXT_H
#define _UCONTEXT_H 1
@@ -24,9 +26,28 @@
/* Get machine dependent definition of data structures. */
#include <sys/ucontext.h>
-/* The System V ABI user-level context switching support functions
- * are marked obsolescent by SuSv3, and are not implemented by
- * uClibc. This header is therefore empty. */
+__BEGIN_DECLS
+
+/* Get user context and store it in variable pointed to by UCP. */
+extern int getcontext (ucontext_t *__ucp) __THROW;
+
+/* Set user context from information of variable pointed to by UCP. */
+extern int setcontext (__const ucontext_t *__ucp) __THROW;
+
+/* Save current context in context variable pointed to by OUCP and set
+ context from variable pointed to by UCP. */
+extern int swapcontext (ucontext_t *__restrict __oucp,
+ __const ucontext_t *__restrict __ucp) __THROW;
+
+/* Manipulate user context UCP to continue with calling functions FUNC
+ and the ARGC-1 parameters following ARGC when the context is used
+ the next time in `setcontext' or `swapcontext'.
+
+ We cannot say anything about the parameters FUNC takes; `void'
+ is as good as any other choice. */
+extern void makecontext (ucontext_t *__ucp, void (*__func) (void),
+ int __argc, ...) __THROW;
+__END_DECLS
#endif /* ucontext.h */
--- uClibc-0.9.33.2/libc/sysdeps/linux/arm/getcontext.S 1970-01-01 01:00:00.000000000 +0100
+++ uclibc/libc/sysdeps/linux/arm/getcontext.S 2012-06-26 10:44:33.997987413 +0200
@@ -0,0 +1,106 @@
+/* Copyright (C) 2012 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <sysdep.h>
+
+#include "ucontext_i.h"
+
+ .syntax unified
+ .text
+
+/* int getcontext (ucontext_t *ucp) */
+
+ENTRY(__getcontext)
+ /* No need to save r0-r3, d0-d7, or d16-d31. */
+ add r1, r0, #MCONTEXT_ARM_R4
+ stmia r1, {r4-r11}
+
+ /* Save R13 separately as Thumb can't STM it. */
+ str r13, [r0, #MCONTEXT_ARM_SP]
+ str r14, [r0, #MCONTEXT_ARM_LR]
+ /* Return to LR */
+ str r14, [r0, #MCONTEXT_ARM_PC]
+ /* Return zero */
+ mov r2, #0
+ str r2, [r0, #MCONTEXT_ARM_R0]
+
+ /* Save ucontext_t * across the next call. */
+ mov r4, r0
+
+ /* __sigprocmask(SIG_BLOCK, NULL, &(ucontext->uc_sigmask)) */
+ mov r0, #SIG_BLOCK
+ mov r1, #0
+ add r2, r4, #UCONTEXT_SIGMASK
+ bl PLTJMP(sigprocmask)
+
+ /* Store FP regs. Much of the FP code is copied from arm/eabi/setjmp.S. */
+#ifdef __PIC__
+# ldr r2, 1f
+# ldr r1, Lrtld_global_ro
+#0: add r2, pc, r2
+# ldr r2, [r2, r1]
+# ldr r2, [r2, #RTLD_GLOBAL_RO_DL_HWCAP_OFFSET]
+#else
+# ldr r2, Lhwcap
+# ldr r2, [r2, #0]
+#endif
+
+ add r0, r4, #UCONTEXT_REGSPACE
+
+#if defined __UCLIBC_HAS_FLOATS__ && ! defined __UCLIBC_HAS_SOFT_FLOAT__
+# ifdef __VFP_FP__
+ /* Store the VFP registers. */
+ /* Following instruction is fstmiax ip!, {d8-d15}. */
+ stc p11, cr8, [r0], #64
+ /* Store the floating-point status register. */
+ /* Following instruction is fmrx r2, fpscr. */
+ mrc p10, 7, r1, cr1, cr0, 0
+ str r1, [r0], #4
+# endif
+#endif
+#ifdef __IWMMXT__
+ /* Save the call-preserved iWMMXt registers. */
+ /* Following instructions are wstrd wr10, [r0], #8 (etc.) */
+ stcl p1, cr10, [r0], #8
+ stcl p1, cr11, [r0], #8
+ stcl p1, cr12, [r0], #8
+ stcl p1, cr13, [r0], #8
+ stcl p1, cr14, [r0], #8
+ stcl p1, cr15, [r0], #8
+#endif
+
+ /* Restore the clobbered R4 and LR. */
+ ldr r14, [r4, #MCONTEXT_ARM_LR]
+ ldr r4, [r4, #MCONTEXT_ARM_R4]
+
+ mov r0, #0
+
+ DO_RET(r14)
+
+END(__getcontext)
+
+#ifdef __PIC__
+#1: .long _GLOBAL_OFFSET_TABLE_ - 0b - 8
+#Lrtld_global_ro:
+# .long C_SYMBOL_NAME(_rtld_global_ro)(GOT)
+#else
+#Lhwcap:
+# .long C_SYMBOL_NAME(_dl_hwcap)
+#endif
+
+
+weak_alias(__getcontext, getcontext)
--- uClibc-0.9.33.2/libc/sysdeps/linux/arm/makecontext.c 1970-01-01 01:00:00.000000000 +0100
+++ uclibc/libc/sysdeps/linux/arm/makecontext.c 2012-06-26 10:44:33.997987413 +0200
@@ -0,0 +1,73 @@
+/* Copyright (C) 2012 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <stdarg.h>
+#include <ucontext.h>
+
+/* Number of arguments that go in registers. */
+#define NREG_ARGS 4
+
+/* Take a context previously prepared via getcontext() and set to
+ call func() with the given int only args. */
+void
+__makecontext (ucontext_t *ucp, void (*func) (void), int argc, ...)
+{
+ extern void __startcontext (void);
+ unsigned long *funcstack;
+ va_list vl;
+ unsigned long *regptr;
+ unsigned int reg;
+ int misaligned;
+
+ /* Start at the top of stack. */
+ funcstack = (unsigned long *) (ucp->uc_stack.ss_sp + ucp->uc_stack.ss_size);
+
+ /* Ensure the stack stays eight byte aligned. */
+ misaligned = ((unsigned long) funcstack & 4) != 0;
+
+ if ((argc > NREG_ARGS) && (argc & 1) != 0)
+ misaligned = !misaligned;
+
+ if (misaligned)
+ funcstack -= 1;
+
+ va_start (vl, argc);
+
+ /* Reserve space for the on-stack arguments. */
+ if (argc > NREG_ARGS)
+ funcstack -= (argc - NREG_ARGS);
+
+ ucp->uc_mcontext.arm_sp = (unsigned long) funcstack;
+ ucp->uc_mcontext.arm_pc = (unsigned long) func;
+
+ /* Exit to startcontext() with the next context in R4 */
+ ucp->uc_mcontext.arm_r4 = (unsigned long) ucp->uc_link;
+ ucp->uc_mcontext.arm_lr = (unsigned long) __startcontext;
+
+ /* The first four arguments go into registers. */
+ regptr = &(ucp->uc_mcontext.arm_r0);
+
+ for (reg = 0; (reg < argc) && (reg < NREG_ARGS); reg++)
+ *regptr++ = va_arg (vl, unsigned long);
+
+ /* And the remainder on the stack. */
+ for (; reg < argc; reg++)
+ *funcstack++ = va_arg (vl, unsigned long);
+
+ va_end (vl);
+}
+weak_alias (__makecontext, makecontext)
--- uClibc-0.9.33.2/libc/sysdeps/linux/arm/Makefile.arch 2012-05-15 09:20:09.000000000 +0200
+++ uclibc/libc/sysdeps/linux/arm/Makefile.arch 2012-06-26 10:52:48.569987412 +0200
@@ -12,6 +12,31 @@ SSRC := \
bsd-_setjmp.S sigrestorer.S mmap64.S \
vfork.S clone.S
+ifeq ($(UCLIBC_HAS_CONTEXT_FUNCS),y)
+CSRC += makecontext.c
+SSRC += getcontext.S setcontext.S swapcontext.S
+
+LIBC_ARCH_DIR := $(top_srcdir)/libc/sysdeps/linux/$(TARGET_ARCH)
+LIBC_ARCH_OUT := $(top_builddir)/libc/sysdeps/linux/$(TARGET_ARCH)
+
+libc_arch_headers : $(LIBC_ARCH_OUT)/ucontext_i.h
+headers_clean-y += libc_arch_headers_clean
+
+CFLAGS-ucontext_i.c = -S
+
+$(LIBC_ARCH_OUT)/ucontext_i.c: $(LIBC_ARCH_DIR)/ucontext_i.sym
+ $(do_awk) $(top_srcdir)extra/scripts/gen-as-const.awk $< > $@
+
+$(LIBC_ARCH_OUT)/ucontext_i.s: $(LIBC_ARCH_OUT)/ucontext_i.c
+ $(compile.c)
+
+$(LIBC_ARCH_OUT)/ucontext_i.h: $(LIBC_ARCH_OUT)/ucontext_i.s
+ $(do_sed) -n "s/^.*@@@name@@@\([^@]*\)@@@value@@@[^0-9Xxa-fA-F-]*\([0-9Xxa-fA-F-][0-9Xxa-fA-F-]*\).*@@@end@@@.*$\/#define \1 \2/p" $< > $@
+
+libc_arch_headers_clean:
+ $(do_rm) $(addprefix $(LIBC_ARCH_OUT)/ucontext_i., c h s)
+endif
+
ifeq ($(UCLIBC_HAS_THREADS_NATIVE),y)
SSRC += libc-aeabi_read_tp.S libc-thumb_atomics.S
endif
--- uClibc-0.9.33.2/libc/sysdeps/linux/arm/setcontext.S 1970-01-01 01:00:00.000000000 +0100
+++ uclibc/libc/sysdeps/linux/arm/setcontext.S 2012-06-26 10:44:33.997987413 +0200
@@ -0,0 +1,97 @@
+/* Copyright (C) 2012 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <sysdep.h>
+
+#include "ucontext_i.h"
+
+ .syntax unified
+ .text
+
+/* int setcontext (const ucontext_t *ucp) */
+
+ENTRY(__setcontext)
+ mov r4, r0
+ add r0, r0, #UCONTEXT_REGSPACE
+
+ /* Restore the VFP registers. Copied from arm/eabi/__longjmp.S. */
+#ifdef __PIC__
+# ldr r2, 1f
+# ldr r1, Lrtld_global_ro
+#0: add r2, pc, r2
+# ldr r2, [r2, r1]
+# ldr r2, [r2, #RTLD_GLOBAL_RO_DL_HWCAP_OFFSET]
+#else
+# ldr r2, Lhwcap
+# ldr r2, [r2, #0]
+#endif
+
+#ifdef __VFP_FP__
+ /* Following instruction is vldmia r0!, {d8-d15}. */
+ ldc p11, cr8, [r0], #64
+ /* Restore the floating-point status register. */
+ ldr r1, [r0], #4
+ /* Following instruction is fmxr fpscr, r1. */
+ mcr p10, 7, r1, cr1, cr0, 0
+#endif
+
+#ifdef __IWMMXT__
+ /* Restore the call-preserved iWMMXt registers. */
+ /* Following instructions are wldrd wr10, [r0], #8 (etc.) */
+ ldcl p1, cr10, [r0], #8
+ ldcl p1, cr11, [r0], #8
+ ldcl p1, cr12, [r0], #8
+ ldcl p1, cr13, [r0], #8
+ ldcl p1, cr14, [r0], #8
+ ldcl p1, cr15, [r0], #8
+#endif
+
+ /* Now bring back the signal status. */
+ mov r0, #SIG_SETMASK
+ add r1, r4, #UCONTEXT_SIGMASK
+ mov r2, #0
+ bl PLTJMP(sigprocmask)
+
+ /* Loading r0-r3 makes makecontext easier. */
+ add r14, r4, #MCONTEXT_ARM_R0
+ ldmia r14, {r0-r12}
+ ldr r13, [r14, #(MCONTEXT_ARM_SP - MCONTEXT_ARM_R0)]
+ add r14, r14, #(MCONTEXT_ARM_LR - MCONTEXT_ARM_R0)
+ ldmia r14, {r14, pc}
+
+END(setcontext)
+weak_alias(__setcontext, setcontext)
+
+ /* Called when a makecontext() context returns. Start the
+ context in R4 or fall through to exit(). */
+ENTRY(__startcontext)
+ movs r0, r4
+ bne PLTJMP(__setcontext)
+
+ @ New context was 0 - exit
+ b PLTJMP(_exit)
+END(__startcontext)
+
+#ifdef __PIC__
+#1: .long _GLOBAL_OFFSET_TABLE_ - 0b - 8
+#Lrtld_global_ro:
+# .long C_SYMBOL_NAME(_rtld_global_ro)(GOT)
+#else
+#Lhwcap:
+# .long C_SYMBOL_NAME(_dl_hwcap)
+#endif
+
--- uClibc-0.9.33.2/libc/sysdeps/linux/arm/swapcontext.S 1970-01-01 01:00:00.000000000 +0100
+++ uclibc/libc/sysdeps/linux/arm/swapcontext.S 2012-06-26 10:44:33.997987413 +0200
@@ -0,0 +1,63 @@
+/* Copyright (C) 2012 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <sysdep.h>
+
+#include "ucontext_i.h"
+
+ .syntax unified
+ .text
+
+/* int swapcontext (ucontext_t *oucp, const ucontext_t *ucp) */
+
+ENTRY(swapcontext)
+
+ /* Have getcontext() do most of the work then fix up
+ LR afterwards. Save R3 to keep the stack aligned. */
+ push {r0,r1,r3,r14}
+ cfi_adjust_cfa_offset (16)
+ cfi_rel_offset (r0,0)
+ cfi_rel_offset (r1,4)
+ cfi_rel_offset (r3,8)
+ cfi_rel_offset (r14,12)
+
+ bl __getcontext
+ mov r4, r0
+
+ pop {r0,r1,r3,r14}
+ cfi_adjust_cfa_offset (-16)
+ cfi_restore (r0)
+ cfi_restore (r1)
+ cfi_restore (r3)
+ cfi_restore (r14)
+
+ /* Exit if getcontext() failed. */
+ cmp r4, #0
+ itt ne
+ movne r0, r4
+ RETINSTR(ne, r14)
+
+ /* Fix up LR and the PC. */
+ str r13,[r0, #MCONTEXT_ARM_SP]
+ str r14,[r0, #MCONTEXT_ARM_LR]
+ str r14,[r0, #MCONTEXT_ARM_PC]
+
+ /* And swap using swapcontext(). */
+ mov r0, r1
+ b __setcontext
+
+END(swapcontext)
--- uClibc-0.9.33.2/libc/sysdeps/linux/arm/ucontext_i.sym 1970-01-01 01:00:00.000000000 +0100
+++ uclibc/libc/sysdeps/linux/arm/ucontext_i.sym 2012-06-26 10:46:46.001987413 +0200
@@ -0,0 +1,30 @@
+#include <inttypes.h>
+#include <signal.h>
+#include <stddef.h>
+#include <sys/ucontext.h>
+
+SIG_BLOCK
+SIG_SETMASK
+
+-- Offsets of the fields in the ucontext_t structure.
+#define ucontext(member) offsetof (ucontext_t, member)
+#define mcontext(member) ucontext (uc_mcontext.member)
+
+UCONTEXT_FLAGS ucontext (uc_flags)
+UCONTEXT_LINK ucontext (uc_link)
+UCONTEXT_STACK ucontext (uc_stack)
+UCONTEXT_MCONTEXT ucontext (uc_mcontext)
+UCONTEXT_SIGMASK ucontext (uc_sigmask)
+
+UCONTEXT_REGSPACE ucontext (uc_regspace)
+
+MCONTEXT_TRAP_NO mcontext (trap_no)
+MCONTEXT_ERROR_CODE mcontext (error_code)
+MCONTEXT_OLDMASK mcontext (oldmask)
+MCONTEXT_ARM_R0 mcontext (arm_r0)
+MCONTEXT_ARM_R4 mcontext (arm_r4)
+MCONTEXT_ARM_SP mcontext (arm_sp)
+MCONTEXT_ARM_LR mcontext (arm_lr)
+MCONTEXT_ARM_PC mcontext (arm_pc)
+MCONTEXT_ARM_CPSR mcontext (arm_cpsr)
+MCONTEXT_FAULT_ADDRESS mcontext (fault_address)
_______________________________________________
uClibc mailing list
uClibc@uclibc.org
http://lists.busybox.net/mailman/listinfo/uclibc