This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [PATCH][ARM] FreeBSD ARM support, EABI, v3
- From: Richard Earnshaw <rearnsha at arm dot com>
- To: Andreas Tobler <andreast-list at fgznet dot ch>, GCC Patches <gcc-patches at gcc dot gnu dot org>, "ramana dot gcc at googlemail dot com" <ramana dot gcc at googlemail dot com>
- Date: Thu, 08 Jan 2015 16:27:33 +0000
- Subject: Re: [PATCH][ARM] FreeBSD ARM support, EABI, v3
- Authentication-results: sourceware.org; auth=none
- References: <54A1A0FB dot 60407 at fgznet dot ch>
On 29/12/14 18:44, Andreas Tobler wrote:
> All,
>
> here is the third attempt to support ARM with FreeBSD.
>
> In the meantime we found another issue in the unwinder where I had to
> adapt some stuff.
>
> The unwind_phase2_forced function in libgcc calls a stop_fn function.
> This stop_fn is in FreeBSD's libthr implementation and is called
> thread_unwind_stop. This thread_unwind_stop is a generic function used
> on all FreeBSD archs.
>
> The issue is now that this thread_unwind_stop expects a double int for
> the exception_class, like on every other arch. For ARM EABI this
> exception_class is an array of char which is passed in one register as
> pointer vs. two registers for a double int.
>
> To solve this issue we defined the exception_class as double integer for
> FreeBSD.
>
> This adaptation reduced the failure count in libstdc++ by about 40 fails.
>
> I build and test this port on a regular basis and I post the results to
> the usual place.
>
> I'd appreciate some feedback and if possible an ACK if ok for trunk.
>
> Thank you,
> Andreas
>
> Here the previous posts to this subject:
>
> First version:
> https://gcc.gnu.org/ml/gcc-patches/2014-11/msg00029.html
>
> Second version:
> https://gcc.gnu.org/ml/gcc-patches/2014-11/msg03427.html
>
>
> toplevel:
>
> * configure.ac: Don't add ${libgcj} for arm*-*-freebsd*.
> * configure: Regenerate.
> gcc:
> * config.gcc (arm*-*-freebsd*): New configuration.
> * config/arm/freebsd.h: New file.
> * config.host: Add extra components for arm*-*-freebsd*.
> * config/arm/arm.h: Introduce MAX_SYNC_LIBFUNC_SIZE.
> * config/arm/arm.c (arm_init_libfuncs): Use MAX_SYNC_LIBFUNC_SIZE.
> * ginclude/unwind-arm-common.h (_Uwind_Control_Block): Define
> exception_class as double integer for FreeBSD ARM.
> (_Unwind_Exception): Define _Unwind_Exception_Class as double integer
> for FreeBSD ARM.
>
> libgcc:
>
> * config.host (arm*-*-freebsd*): Add new configuration for
> arm*-*-freebsd*.
> * config/arm/freebsd-atomic.c: New file.
> * config/arm/t-freebsd: Likewise.
> * config/arm/unwind-arm.h: Add __FreeBSD__ to the list of
> 'PC-relative indirect' OS's.
>
> libatomic:
>
> * configure.tgt: Exclude arm*-*-freebsd* from try_ifunc.
>
> libstdc++-v3:
>
> * configure.host: Add arm*-*-freebsd* port_specific_symbol_files.
> * libsupc++/unwind-cxx.h (__is_gxx_exception_class,
> __is_dependent_exception): Exclude FreeBSD ARM from the
> __ARM_EABI_UNWINDER__ ifdef.
>
>
Umm, sorry, just seen this update to the previous patch.
The changes to the exception unwinding look a bit more involved. Could
you separate that out into a separate patch, so that it's easier to see
what you're changing?
R.
> gcc5_fbsd_arm_20141230-1.diff
>
>
> Index: configure
> ===================================================================
> --- configure (revision 219100)
> +++ configure (working copy)
> @@ -3425,6 +3425,9 @@
> alpha*-*-*vms*)
> noconfigdirs="$noconfigdirs ${libgcj}"
> ;;
> + arm*-*-freebsd*)
> + noconfigdirs="$noconfigdirs ${libgcj}"
> + ;;
> arm-wince-pe)
> noconfigdirs="$noconfigdirs ${libgcj}"
> ;;
> Index: configure.ac
> ===================================================================
> --- configure.ac (revision 219100)
> +++ configure.ac (working copy)
> @@ -779,6 +779,9 @@
> alpha*-*-*vms*)
> noconfigdirs="$noconfigdirs ${libgcj}"
> ;;
> + arm*-*-freebsd*)
> + noconfigdirs="$noconfigdirs ${libgcj}"
> + ;;
> arm-wince-pe)
> noconfigdirs="$noconfigdirs ${libgcj}"
> ;;
> Index: gcc/config/arm/arm.c
> ===================================================================
> --- gcc/config/arm/arm.c (revision 219100)
> +++ gcc/config/arm/arm.c (working copy)
> @@ -2160,7 +2160,7 @@
> {
> /* For Linux, we have access to kernel support for atomic operations. */
> if (arm_abi == ARM_ABI_AAPCS_LINUX)
> - init_sync_libfuncs (2 * UNITS_PER_WORD);
> + init_sync_libfuncs (MAX_SYNC_LIBFUNC_SIZE);
>
> /* There are no special library functions unless we are using the
> ARM BPABI. */
> Index: gcc/config/arm/arm.h
> ===================================================================
> --- gcc/config/arm/arm.h (revision 219100)
> +++ gcc/config/arm/arm.h (working copy)
> @@ -766,6 +766,11 @@
> #define PCC_BITFIELD_TYPE_MATTERS TARGET_AAPCS_BASED
> #endif
>
> +/* The maximum size of the sync library functions supported. */
> +#ifndef MAX_SYNC_LIBFUNC_SIZE
> +#define MAX_SYNC_LIBFUNC_SIZE (2 * UNITS_PER_WORD);
> +#endif
> +
>
> /* Standard register usage. */
>
> Index: gcc/config/arm/freebsd.h
> ===================================================================
> --- gcc/config/arm/freebsd.h (revision 0)
> +++ gcc/config/arm/freebsd.h (working copy)
> @@ -0,0 +1,180 @@
> +/* Definitions of target machine for GNU compiler, FreeBSD/arm version.
> + Copyright (C) 2002-2014 Free Software Foundation, Inc.
> + Contributed by Wasabi Systems, Inc.
> +
> + This file is part of GCC.
> +
> + GCC is free software; you can redistribute it and/or modify it
> + under the terms of the GNU General Public License as published
> + by the Free Software Foundation; either version 3, or (at your
> + option) any later version.
> +
> + GCC 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 General Public
> + License for more details.
> +
> + Under Section 7 of GPL version 3, you are granted additional
> + permissions described in the GCC Runtime Library Exception, version
> + 3.1, as published by the Free Software Foundation.
> +
> + You should have received a copy of the GNU General Public License
> + along with GCC; see the file COPYING3. If not see
> + <http://www.gnu.org/licenses/>. */
> +
> +#undef SUBTARGET_CPP_SPEC
> +#define SUBTARGET_CPP_SPEC FBSD_CPP_SPEC
> +
> +#undef SUBTARGET_EXTRA_SPECS
> +#define SUBTARGET_EXTRA_SPECS \
> + { "subtarget_extra_asm_spec", SUBTARGET_EXTRA_ASM_SPEC }, \
> + { "subtarget_asm_float_spec", SUBTARGET_ASM_FLOAT_SPEC }, \
> + { "fbsd_dynamic_linker", FBSD_DYNAMIC_LINKER }
> +
> +#undef SUBTARGET_EXTRA_ASM_SPEC
> +#define SUBTARGET_EXTRA_ASM_SPEC \
> + "%{mabi=apcs-gnu|mabi=atpcs:-meabi=gnu;:-meabi=5} " TARGET_FIX_V4BX_SPEC " \
> + %{fpic|fpie:-k} %{fPIC|fPIE:-k}"
> +
> +#undef SUBTARGET_ASM_FLOAT_SPEC
> +#ifdef TARGET_FREEBSD_ARM_HARD_FLOAT
> +/* Default to full vfp if we build for arm*hf. */
> +#define SUBTARGET_ASM_FLOAT_SPEC "%{!mfpu=*:-mfpu=vfp}"
> +#else
> +#define SUBTARGET_ASM_FLOAT_SPEC "%{!mfpu=*:-mfpu=softvfp}"
> +#endif
> +
> +#undef LINK_SPEC
> +#define LINK_SPEC " \
> + %{p:%nconsider using `-pg' instead of `-p' with gprof (1) } \
> + %{v:-V} \
> + %{assert*} %{R*} %{rpath*} %{defsym*} \
> + %{shared:-Bshareable %{h*} %{soname*}} \
> + %{!shared: \
> + %{!static: \
> + %{rdynamic:-export-dynamic} \
> + %{!dynamic-linker:-dynamic-linker %(fbsd_dynamic_linker) }} \
> + %{static:-Bstatic}} \
> + %{!static:--hash-style=both --enable-new-dtags} \
> + %{symbolic:-Bsymbolic} \
> + -X %{mbig-endian:-EB} %{mlittle-endian:-EL}"
> +
> +/* TARGET_BIG_ENDIAN_DEFAULT is set in
> + config.gcc for big endian configurations. */
> +#if TARGET_BIG_ENDIAN_DEFAULT
> +#define TARGET_ENDIAN_DEFAULT MASK_BIG_END
> +#define TARGET_ENDIAN_OPTION "mbig-endian"
> +#define TARGET_LINKER_EMULATION "armelfb_fbsd"
> +#else
> +#define TARGET_ENDIAN_DEFAULT 0
> +#define TARGET_ENDIAN_OPTION "mlittle-endian"
> +#define TARGET_LINKER_EMULATION "armelf_fbsd"
> +#endif
> +
> +#undef SUBTARGET_EXTRA_LINK_SPEC
> +#define SUBTARGET_EXTRA_LINK_SPEC " -m " TARGET_LINKER_EMULATION " -p"
> +
> +#undef TARGET_OS_CPP_BUILTINS
> +#define TARGET_OS_CPP_BUILTINS() \
> + do \
> + { \
> + FBSD_TARGET_OS_CPP_BUILTINS (); \
> + TARGET_BPABI_CPP_BUILTINS (); \
> + } \
> + while (false)
> +
> +/* We default to a soft-float ABI so that binaries can run on all
> + target hardware. */
> +#undef TARGET_DEFAULT_FLOAT_ABI
> +#ifdef TARGET_FREEBSD_ARM_HARD_FLOAT
> +#define TARGET_DEFAULT_FLOAT_ABI ARM_FLOAT_ABI_HARD
> +#else
> +#define TARGET_DEFAULT_FLOAT_ABI ARM_FLOAT_ABI_SOFT
> +#endif
> +
> +#undef ARM_DEFAULT_ABI
> +
> +/* AACPS_LINUX has access to kernel atomic ops while we don't.
> + But AACPS defaults to short_enums. */
> +#define ARM_DEFAULT_ABI ARM_ABI_AAPCS_LINUX
> +
> +#undef TARGET_DEFAULT
> +#define TARGET_DEFAULT (MASK_INTERWORK | TARGET_ENDIAN_DEFAULT)
> +
> +/* We do not have any MULTILIB_OPTIONS specified, so there are no
> + MULTILIB_DEFAULTS. */
> +#undef MULTILIB_DEFAULTS
> +
> +/* Use the AAPCS type for wchar_t, override the one from config/freebsd.h. */
> +#undef WCHAR_TYPE
> +#define WCHAR_TYPE "unsigned int"
> +
> +#undef WCHAR_TYPE_SIZE
> +#define WCHAR_TYPE_SIZE BITS_PER_WORD
> +
> +#if defined (TARGET_FREEBSD_ARMv6)
> +#undef SUBTARGET_CPU_DEFAULT
> +#define SUBTARGET_CPU_DEFAULT TARGET_CPU_arm1176jzs
> +#else
> +#undef SUBTARGET_CPU_DEFAULT
> +#define SUBTARGET_CPU_DEFAULT TARGET_CPU_arm9
> +#endif
> +
> +#define SUBTARGET_OVERRIDE_OPTIONS \
> +do { \
> + if (unaligned_access) \
> + unaligned_access = 0; \
> +} while (0)
> +
> +#undef MAX_SYNC_LIBFUNC_SIZE
> +#define MAX_SYNC_LIBFUNC_SIZE 4 /* UNITS_PER_WORD not defined yet. */
> +
> +/* FreeBSD does its profiling differently to the Acorn compiler. We
> + don't need a word following the mcount call; and to skip it
> + requires either an assembly stub or use of fomit-frame-pointer when
> + compiling the profiling functions. Since we break Acorn CC
> + compatibility below a little more won't hurt. */
> +
> +#undef ARM_FUNCTION_PROFILER
> +#define ARM_FUNCTION_PROFILER(STREAM,LABELNO) \
> +{ \
> + asm_fprintf (STREAM, "\tmov\t%Rip, %Rlr\n"); \
> + asm_fprintf (STREAM, "\tbl\t__mcount%s\n", \
> + (TARGET_ARM && NEED_PLT_RELOC) \
> + ? "(PLT)" : ""); \
> +}
> +
> +/* Clear the instruction cache from `BEG' to `END'. This makes a
> + call to the ARM_SYNC_ICACHE architecture specific syscall. */
> +#define CLEAR_INSN_CACHE(BEG, END) \
> +do \
> + { \
> + extern int sysarch (int number, void *args); \
> + struct \
> + { \
> + unsigned int addr; \
> + int len; \
> + } s; \
> + s.addr = (unsigned int) (BEG); \
> + s.len = (END) - (BEG); \
> + (void) sysarch (0, &s); \
> + } \
> +while (0)
> +
> +/* This is how we tell the assembler that two symbols have the same value. */
> +#define ASM_OUTPUT_DEF(FILE, NAME1, NAME2) \
> + do \
> + { \
> + assemble_name (FILE, NAME1); \
> + fputs (" = ", FILE); \
> + assemble_name (FILE, NAME2); \
> + fputc ('\n', FILE); \
> + } \
> + while (0)
> +
> +/* Add .note.GNU-stack. */
> +#undef NEED_INDICATE_EXEC_STACK
> +#define NEED_INDICATE_EXEC_STACK 1
> +
> +#define ARM_TARGET2_DWARF_FORMAT (DW_EH_PE_pcrel | DW_EH_PE_indirect)
> +
> Index: gcc/config.gcc
> ===================================================================
> --- gcc/config.gcc (revision 219100)
> +++ gcc/config.gcc (working copy)
> @@ -259,7 +259,6 @@
> arm*-wince-pe* \
> | arm*-*-ecos-elf \
> | arm*-*-elf \
> - | arm*-*-freebsd* \
> | arm*-*-linux* \
> | arm*-*-uclinux* \
> | i[34567]86-go32-* \
> @@ -1010,6 +1009,27 @@
> extra_options="${extra_options} arm/vxworks.opt"
> tmake_file="${tmake_file} arm/t-arm arm/t-vxworks"
> ;;
> +arm*-*-freebsd*) # ARM FreeBSD EABI
> + tm_file="dbxelf.h elfos.h ${fbsd_tm_file} arm/elf.h"
> + case $target in
> + arm*b-*-freebsd*)
> + tm_defines="${tm_defines} TARGET_BIG_ENDIAN_DEFAULT=1"
> + ;;
> + esac
> + tmake_file="${tmake_file} arm/t-arm arm/t-bpabi"
> + tm_file="${tm_file} arm/bpabi.h arm/freebsd.h arm/aout.h arm/arm.h"
> + case $target in
> + armv6*-*-freebsd*)
> + tm_defines="${tm_defines} TARGET_FREEBSD_ARMv6=1"
> + ;;
> + esac
> + case $target in
> + arm*hf-*-freebsd*)
> + tm_defines="${tm_defines} TARGET_FREEBSD_ARM_HARD_FLOAT=1"
> + ;;
> + esac
> + with_tls=${with_tls:-gnu}
> + ;;
> arm*-*-netbsdelf*)
> tm_file="dbxelf.h elfos.h netbsd.h netbsd-elf.h arm/elf.h arm/aout.h ${tm_file} arm/netbsd-elf.h"
> extra_options="${extra_options} netbsd.opt netbsd-elf.opt"
> Index: gcc/config.host
> ===================================================================
> --- gcc/config.host (revision 219100)
> +++ gcc/config.host (working copy)
> @@ -99,7 +99,7 @@
> esac
>
> case ${host} in
> - arm*-*-linux*)
> + arm*-*-freebsd* | arm*-*-linux*)
> case ${target} in
> arm*-*-*)
> host_extra_gcc_objs="driver-arm.o"
> Index: gcc/ginclude/unwind-arm-common.h
> ===================================================================
> --- gcc/ginclude/unwind-arm-common.h (revision 219100)
> +++ gcc/ginclude/unwind-arm-common.h (working copy)
> @@ -82,7 +82,11 @@
>
> struct _Unwind_Control_Block
> {
> +#ifdef __FreeBSD__
> + unsigned exception_class __attribute__((__mode__(__DI__)));
> +#else
> char exception_class[8];
> +#endif
> void (*exception_cleanup)(_Unwind_Reason_Code, _Unwind_Control_Block *);
> /* Unwinder cache, private fields for the unwinder's use */
> struct
> @@ -181,7 +185,11 @@
>
> /* Support functions for the PR. */
> #define _Unwind_Exception _Unwind_Control_Block
> +#ifdef __FreeBSD__
> + typedef unsigned _Unwind_Exception_Class __attribute__((__mode__(__DI__)));
> +#else
> typedef char _Unwind_Exception_Class[8];
> +#endif
>
> void * _Unwind_GetLanguageSpecificData (_Unwind_Context *);
> _Unwind_Ptr _Unwind_GetRegionStart (_Unwind_Context *);
> Index: libatomic/configure.tgt
> ===================================================================
> --- libatomic/configure.tgt (revision 219100)
> +++ libatomic/configure.tgt (working copy)
> @@ -37,10 +37,15 @@
>
> arm*)
> ARCH=arm
> - # ??? Detect when -march=armv7 is already enabled.
> - try_ifunc=yes
> - ;;
> -
> + case "${target}" in
> + arm*-*-freebsd*)
> + ;;
> + *)
> + # ??? Detect when -march=armv7 is already enabled.
> + try_ifunc=yes
> + ;;
> + esac
> + ;;
> sparc)
> case " ${CC} ${CFLAGS} " in
> *" -m64 "*)
> Index: libgcc/config/arm/freebsd-atomic.c
> ===================================================================
> --- libgcc/config/arm/freebsd-atomic.c (revision 0)
> +++ libgcc/config/arm/freebsd-atomic.c (working copy)
> @@ -0,0 +1,224 @@
> +/* FreeBSD specific atomic operations for ARM EABI.
> + Copyright (C) 2014 Free Software Foundation, Inc.
> +
> +This file is part of GCC.
> +
> +GCC is free software; you can redistribute it and/or modify it under
> +the terms of the GNU General Public License as published by the Free
> +Software Foundation; either version 3, or (at your option) any later
> +version.
> +
> +GCC 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 General Public License
> +for more details.
> +
> +Under Section 7 of GPL version 3, you are granted additional
> +permissions described in the GCC Runtime Library Exception, version
> +3.1, as published by the Free Software Foundation.
> +
> +You should have received a copy of the GNU General Public License and
> +a copy of the GCC Runtime Library Exception along with this program;
> +see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
> +<http://www.gnu.org/licenses/>. */
> +
> +#include <sys/types.h>
> +
> +#define HIDDEN __attribute__ ((visibility ("hidden")))
> +
> +#define ARM_VECTORS_HIGH 0xffff0000U
> +#define ARM_TP_ADDRESS (ARM_VECTORS_HIGH + 0x1000)
> +#define ARM_RAS_START (ARM_TP_ADDRESS + 4)
> +
> +void HIDDEN
> +__sync_synchronize (void)
> +{
> +#if defined (__ARM_ARCH_6__) || defined (__ARM_ARCH_6J__) \
> + || defined (__ARM_ARCH_6K__) || defined (__ARM_ARCH_6T2__) \
> + || defined (__ARM_ARCH_6Z__) || defined (__ARM_ARCH_6ZK__) \
> + || defined (__ARM_ARCH_7__) || defined (__ARM_ARCH_7A__)
> +#if defined (__ARM_ARCH_7__) || defined (__ARM_ARCH_7A__)
> + __asm __volatile ("dmb" : : : "memory");
> +#else
> + __asm __volatile ("mcr p15, 0, r0, c7, c10, 5" : : : "memory");
> +#endif
> +#else
> + __asm __volatile ("nop" : : : "memory");
> +#endif
> +}
> +
> +#if defined (__ARM_ARCH_6__) || defined (__ARM_ARCH_6J__) \
> + || defined (__ARM_ARCH_6K__) || defined (__ARM_ARCH_6T2__) \
> + || defined (__ARM_ARCH_6Z__) || defined (__ARM_ARCH_6ZK__) \
> + || defined (__ARM_ARCH_7__) || defined (__ARM_ARCH_7A__)
> +
> +/* These systems should be supported by the compiler. */
> +
> +#else /* __ARM_ARCH_5__ */
> +
> +#define SYNC_LOCK_TEST_AND_SET_N(N, TYPE, LDR, STR) \
> +TYPE HIDDEN \
> +__sync_lock_test_and_set_##N (TYPE *mem, TYPE val) \
> +{ \
> + unsigned int old, temp, ras_start; \
> + \
> + ras_start = ARM_RAS_START; \
> + __asm volatile ( \
> + /* Set up Restartable Atomic Sequence. */ \
> + "1:" \
> + "\tadr %2, 1b\n" \
> + "\tstr %2, [%5]\n" \
> + "\tadr %2, 2f\n" \
> + "\tstr %2, [%5, #4]\n" \
> + \
> + "\t"LDR" %0, %4\n" /* Load old value. */ \
> + "\t"STR" %3, %1\n" /* Store new value. */ \
> + \
> + /* Tear down Restartable Atomic Sequence. */ \
> + "2:" \
> + "\tmov %2, #0x00000000\n" \
> + "\tstr %2, [%5]\n" \
> + "\tmov %2, #0xffffffff\n" \
> + "\tstr %2, [%5, #4]\n" \
> + : "=&r" (old), "=m" (*mem), "=&r" (temp) \
> + : "r" (val), "m" (*mem), "r" (ras_start)); \
> + return (old); \
> +}
> +
> +#define SYNC_LOCK_RELEASE_N(N, TYPE) \
> +void HIDDEN \
> +__sync_lock_release_##N (TYPE *ptr) \
> +{ \
> + /* All writes before this point must be seen before we release \
> + the lock itself. */ \
> + __sync_synchronize (); \
> + *ptr = 0; \
> +}
> +
> +#define SYNC_VAL_CAS_N(N, TYPE, LDR, STREQ) \
> +TYPE HIDDEN \
> +__sync_val_compare_and_swap_##N (TYPE *mem, TYPE expected, \
> + TYPE desired) \
> +{ \
> + unsigned int old, temp, ras_start; \
> + \
> + ras_start = ARM_RAS_START; \
> + __asm volatile ( \
> + /* Set up Restartable Atomic Sequence. */ \
> + "1:" \
> + "\tadr %2, 1b\n" \
> + "\tstr %2, [%6]\n" \
> + "\tadr %2, 2f\n" \
> + "\tstr %2, [%6, #4]\n" \
> + \
> + "\t"LDR" %0, %5\n" /* Load old value. */ \
> + "\tcmp %0, %3\n" /* Compare to expected value. */\
> + "\t"STREQ" %4, %1\n" /* Store new value. */ \
> + \
> + /* Tear down Restartable Atomic Sequence. */ \
> + "2:" \
> + "\tmov %2, #0x00000000\n" \
> + "\tstr %2, [%6]\n" \
> + "\tmov %2, #0xffffffff\n" \
> + "\tstr %2, [%6, #4]\n" \
> + : "=&r" (old), "=m" (*mem), "=&r" (temp) \
> + : "r" (expected), "r" (desired), "m" (*mem), \
> + "r" (ras_start)); \
> + return (old); \
> +}
> +
> +typedef unsigned char bool;
> +
> +#define SYNC_BOOL_CAS_N(N, TYPE) \
> +bool HIDDEN \
> +__sync_bool_compare_and_swap_##N (TYPE *ptr, TYPE oldval, \
> + TYPE newval) \
> +{ \
> + TYPE actual_oldval \
> + = __sync_val_compare_and_swap_##N (ptr, oldval, newval); \
> + return (oldval == actual_oldval); \
> +}
> +
> +#define SYNC_FETCH_AND_OP_N(N, TYPE, LDR, STR, NAME, OP) \
> +TYPE HIDDEN \
> +__sync_fetch_and_##NAME##_##N (TYPE *mem, TYPE val) \
> +{ \
> + unsigned int old, temp, ras_start; \
> + \
> + ras_start = ARM_RAS_START; \
> + __asm volatile ( \
> + /* Set up Restartable Atomic Sequence. */ \
> + "1:" \
> + "\tadr %2, 1b\n" \
> + "\tstr %2, [%5]\n" \
> + "\tadr %2, 2f\n" \
> + "\tstr %2, [%5, #4]\n" \
> + \
> + "\t"LDR" %0, %4\n" /* Load old value. */ \
> + "\t"OP" %2, %0, %3\n" /* Calculate new value. */ \
> + "\t"STR" %2, %1\n" /* Store new value. */ \
> + \
> + /* Tear down Restartable Atomic Sequence. */ \
> + "2:" \
> + "\tmov %2, #0x00000000\n" \
> + "\tstr %2, [%5]\n" \
> + "\tmov %2, #0xffffffff\n" \
> + "\tstr %2, [%5, #4]\n" \
> + : "=&r" (old), "=m" (*mem), "=&r" (temp) \
> + : "r" (val), "m" (*mem), "r" (ras_start)); \
> + return (old); \
> +}
> +
> +#define SYNC_OP_AND_FETCH_N(N, TYPE, LDR, STR, NAME, OP) \
> +TYPE HIDDEN \
> +__sync_##NAME##_and_fetch_##N (TYPE *mem, TYPE val) \
> +{ \
> + unsigned int old, temp, ras_start; \
> + \
> + ras_start = ARM_RAS_START; \
> + __asm volatile ( \
> + /* Set up Restartable Atomic Sequence. */ \
> + "1:" \
> + "\tadr %2, 1b\n" \
> + "\tstr %2, [%5]\n" \
> + "\tadr %2, 2f\n" \
> + "\tstr %2, [%5, #4]\n" \
> + \
> + "\t"LDR" %0, %4\n" /* Load old value. */ \
> + "\t"OP" %2, %0, %3\n" /* Calculate new value. */ \
> + "\t"STR" %2, %1\n" /* Store new value. */ \
> + \
> + /* Tear down Restartable Atomic Sequence. */ \
> + "2:" \
> + "\tmov %2, #0x00000000\n" \
> + "\tstr %2, [%5]\n" \
> + "\tmov %2, #0xffffffff\n" \
> + "\tstr %2, [%5, #4]\n" \
> + : "=&r" (old), "=m" (*mem), "=&r" (temp) \
> + : "r" (val), "m" (*mem), "r" (ras_start)); \
> + return (old); \
> +}
> +
> +#define EMIT_ALL_OPS_N(N, TYPE, LDR, STR, STREQ) \
> +SYNC_LOCK_TEST_AND_SET_N (N, TYPE, LDR, STR) \
> +SYNC_LOCK_RELEASE_N (N, TYPE) \
> +SYNC_VAL_CAS_N (N, TYPE, LDR, STREQ) \
> +SYNC_BOOL_CAS_N (N, TYPE) \
> +SYNC_FETCH_AND_OP_N (N, TYPE, LDR, STR, add, "add") \
> +SYNC_FETCH_AND_OP_N (N, TYPE, LDR, STR, and, "and") \
> +SYNC_FETCH_AND_OP_N (N, TYPE, LDR, STR, or, "orr") \
> +SYNC_FETCH_AND_OP_N (N, TYPE, LDR, STR, sub, "sub") \
> +SYNC_FETCH_AND_OP_N (N, TYPE, LDR, STR, xor, "eor") \
> +SYNC_OP_AND_FETCH_N (N, TYPE, LDR, STR, add, "add") \
> +SYNC_OP_AND_FETCH_N (N, TYPE, LDR, STR, and, "and") \
> +SYNC_OP_AND_FETCH_N (N, TYPE, LDR, STR, or, "orr") \
> +SYNC_OP_AND_FETCH_N (N, TYPE, LDR, STR, sub, "sub") \
> +SYNC_OP_AND_FETCH_N (N, TYPE, LDR, STR, xor, "eor")
> +
> +
> +
> +EMIT_ALL_OPS_N (1, unsigned char, "ldrb", "strb", "streqb")
> +EMIT_ALL_OPS_N (2, unsigned short, "ldrh", "strh", "streqh")
> +EMIT_ALL_OPS_N (4, unsigned int, "ldr", "str", "streq")
> +
> +#endif
> Index: libgcc/config/arm/t-freebsd
> ===================================================================
> --- libgcc/config/arm/t-freebsd (revision 0)
> +++ libgcc/config/arm/t-freebsd (working copy)
> @@ -0,0 +1,9 @@
> +# Just for these, we omit the frame pointer since it makes such a big
> +# difference. It is then pointless adding debugging.
> +HOST_LIBGCC2_CFLAGS += -fomit-frame-pointer
> +
> +LIB2ADD_ST += $(srcdir)/config/arm/freebsd-atomic.c
> +
> +# Use a version of div0 which raises SIGFPE.
> +LIB1ASMFUNCS := $(filter-out _dvmd_tls,$(LIB1ASMFUNCS)) _dvmd_lnx
> +
> Index: libgcc/config/arm/unwind-arm.h
> ===================================================================
> --- libgcc/config/arm/unwind-arm.h (revision 219100)
> +++ libgcc/config/arm/unwind-arm.h (working copy)
> @@ -48,7 +48,8 @@
> if (!tmp)
> return 0;
>
> -#if (defined(linux) && !defined(__uClinux__)) || defined(__NetBSD__)
> +#if (defined(linux) && !defined(__uClinux__)) || defined(__NetBSD__) \
> + || defined(__FreeBSD__)
> /* Pc-relative indirect. */
> #define _GLIBCXX_OVERRIDE_TTYPE_ENCODING (DW_EH_PE_pcrel | DW_EH_PE_indirect)
> tmp += ptr;
> Index: libgcc/config.host
> ===================================================================
> --- libgcc/config.host (revision 219100)
> +++ libgcc/config.host (working copy)
> @@ -366,6 +366,13 @@
> tmake_file="$tmake_file arm/t-arm arm/t-elf t-softfp-sfdf t-softfp-excl arm/t-softfp t-softfp"
> extra_parts="$extra_parts crti.o crtn.o"
> ;;
> +arm*-*-freebsd*) # ARM FreeBSD EABI
> + tmake_file="${tmake_file} arm/t-arm t-fixedpoint-gnu-prefix arm/t-elf"
> + tmake_file="${tmake_file} arm/t-bpabi arm/t-freebsd t-slibgcc-libgcc"
> + tm_file="${tm_file} arm/bpabi-lib.h"
> + unwind_header=config/arm/unwind-arm.h
> + tmake_file="${tmake_file} t-softfp-sfdf t-softfp-excl arm/t-softfp t-softfp"
> + ;;
> arm*-*-netbsdelf*)
> tmake_file="$tmake_file arm/t-arm arm/t-netbsd t-slibgcc-gld-nover"
> ;;
> Index: libstdc++-v3/configure.host
> ===================================================================
> --- libstdc++-v3/configure.host (revision 219100)
> +++ libstdc++-v3/configure.host (working copy)
> @@ -366,6 +366,9 @@
> ;;
> esac
> ;;
> + arm*-*-freebsd*)
> + port_specific_symbol_files="\$(srcdir)/../config/os/gnu-linux/arm-eabi-extra.ver"
> + ;;
> powerpc*-*-darwin*)
> port_specific_symbol_files="\$(srcdir)/../config/os/bsd/darwin/ppc-extra.ver"
> ;;
> Index: libstdc++-v3/libsupc++/unwind-cxx.h
> ===================================================================
> --- libstdc++-v3/libsupc++/unwind-cxx.h (revision 219100)
> +++ libstdc++-v3/libsupc++/unwind-cxx.h (working copy)
> @@ -235,7 +235,7 @@
> return reinterpret_cast<__cxa_dependent_exception *>(exc + 1) - 1;
> }
>
> -#ifdef __ARM_EABI_UNWINDER__
> +#if defined (__ARM_EABI_UNWINDER__) && !defined (__FreeBSD__)
> static inline bool
> __is_gxx_exception_class(_Unwind_Exception_Class c)
> {
> @@ -309,13 +309,7 @@
> c[6] = 'R';
> c[7] = '\0';
> }
> -
> -static inline void*
> -__gxx_caught_object(_Unwind_Exception* eo)
> -{
> - return (void*)eo->barrier_cache.bitpattern[0];
> -}
> -#else // !__ARM_EABI_UNWINDER__
> +#else // !__ARM_EABI_UNWINDER__ || __FreeBSD__
> // This is the primary exception class we report -- "GNUCC++\0".
> const _Unwind_Exception_Class __gxx_primary_exception_class
> = ((((((((_Unwind_Exception_Class) 'G'
> @@ -339,6 +333,16 @@
> << 8 | (_Unwind_Exception_Class) '+')
> << 8 | (_Unwind_Exception_Class) '\x01');
>
> +const _Unwind_Exception_Class __gxx_forced_unwind_class
> += ((((((((_Unwind_Exception_Class) 'G'
> + << 8 | (_Unwind_Exception_Class) 'N')
> + << 8 | (_Unwind_Exception_Class) 'U')
> + << 8 | (_Unwind_Exception_Class) 'C')
> + << 8 | (_Unwind_Exception_Class) 'F')
> + << 8 | (_Unwind_Exception_Class) 'O')
> + << 8 | (_Unwind_Exception_Class) 'R')
> + << 8 | (_Unwind_Exception_Class) '\0');
> +
> static inline bool
> __is_gxx_exception_class(_Unwind_Exception_Class c)
> {
> @@ -346,6 +350,12 @@
> || c == __gxx_dependent_exception_class;
> }
>
> +static inline bool
> +__is_gxx_forced_unwind_class(_Unwind_Exception_Class c)
> +{
> + return c == __gxx_forced_unwind_class;
> +}
> +
> // Only checks for primary or dependent, but not that it is a C++ exception at
> // all.
> static inline bool
> @@ -357,7 +367,18 @@
> #define __GXX_INIT_PRIMARY_EXCEPTION_CLASS(c) c = __gxx_primary_exception_class
> #define __GXX_INIT_DEPENDENT_EXCEPTION_CLASS(c) \
> c = __gxx_dependent_exception_class
> +#define __GXX_INIT_FORCED_UNWIND_CLASS(c) c = __gxx_forced_unwind_class
> +#endif // __ARM_EABI_UNWINDER__ && !__FreeBSD__
>
> +#ifdef __ARM_EABI_UNWINDER__
> +static inline void*
> +__gxx_caught_object(_Unwind_Exception* eo)
> +{
> + return (void*)eo->barrier_cache.bitpattern[0];
> +}
> +
> +#else // !__ARM_EABI_UNWINDER__
> +
> // GNU C++ personality routine, Version 0.
> extern "C" _Unwind_Reason_Code __gxx_personality_v0
> (int, _Unwind_Action, _Unwind_Exception_Class,
>