arm: libgcc: provide implementations of __sync_synchronize

Prior to Armv6 there was no architected method to synchronize data
across processors.  Armv6 saw the first introduction of
multi-processor support, using a CP15 operation; but this was
deprecated in Armv7 and is not supported on m-profile devices of any
form.  Armv7 (and armv6-m) and later support data synchronization via
the DMB instruction.

This all leads to difficulties when linking programs as the user
generally needs to know which synchronization method is needed, but
there seems no easy way around this, when there are no OS-related
primitives available.

I've addressed this by adding multiple variants of __sync_synchronize
to libgcc, one for each of the above use cases.  I've named these
__sync_synchronize_none, __sync_synchronize_cp15dmb and
__sync_synchronize_dmb.  I've also added three specs files that can be
used to direct the linker to pick the appropriate implementation.
Using specs fragments for this is preferable to directing the user to
directly use --defsym as the latter has to be placed at the correct
position on the command line to be effective and the spec rule ensures
this automatically.

I've also added a default implementation of __sync_synchronize.  The
default implementation will use DMB if that is available in the target
ISA, or fall back to a nul-implementation if it isn't.  In the latter
case it will cause the linker (GNU LD) to emit a warning that
specifies how to pick a specific implementation.  I've chosen not to
permit this default to use the CP15 solution as that has been
deprecated.

libgcc:

	* config.host (arm*-*-eabi* | arm*-*-rtems*):
	Add arm/t-sync to the makefile rules.
	* config/arm/lib1funcs.S (__sync_synchronize_none)
	(__sync_synchronize_cp15dmb, __sync_synchronize_dmb)
	(__sync_synchronize): New functions.
	* config/arm/t-sync: New file.
	* config/arm/sync-none.specs: Likewise.
	* config/arm/sync-dmb.specs: Likewise.
	* config/arm/sync-cp15dmb.specs: Likewise.
This commit is contained in:
Richard Earnshaw 2023-11-20 14:04:17 +00:00
parent 1802f64e67
commit 439779bace
6 changed files with 98 additions and 1 deletions

View file

@ -554,7 +554,7 @@ arm*-*-eabi* | arm*-*-symbianelf* | arm*-*-rtems*)
tm_file="$tm_file arm/bpabi-lib.h"
case ${host} in
arm*-*-eabi* | arm*-*-rtems*)
tmake_file="${tmake_file} arm/t-bpabi t-crtfm"
tmake_file="${tmake_file} arm/t-bpabi arm/t-sync t-crtfm"
extra_parts="crtbegin.o crtend.o crti.o crtn.o"
;;
arm*-*-symbianelf*)

View file

@ -2147,6 +2147,78 @@ LSYM(Lchange_\register):
SIZE (__gnu_thumb1_case_uhi)
#endif
#ifdef L_sync_none
/* Null implementation of __sync_synchronize, for use when
it is known that the system is single threaded. */
.text
.align 0
FUNC_START sync_synchronize_none
bx lr
FUNC_END sync_synchronize_none
#endif
#ifdef L_sync_dmb
/* Full memory barrier using DMB. Requires Armv7 (all profiles)
or armv6-m, or later. */
.text
.align 0
#if __ARM_ARCH_PROFILE == 'M'
.arch armv6-m
#else
.arch armv7-a
#endif
FUNC_START sync_synchronize_dmb
/* M-profile devices only support SY as the synchronization level,
but that's probably what we want here anyway. */
dmb
RET
FUNC_END sync_synchronize_dmb
#endif
#ifdef L_sync_cp15dmb
#ifndef NOT_ISA_TARGET_32BIT
/* Implementation of DMB using CP15 operations. This was first
defined in Armv6, but deprecated in Armv7 and can give
sub-optimal performance. */
.text
.align 0
ARM_FUNC_START sync_synchronize_cp15dmb
mcr p15, 0, r0, c7, c10, 5
RET
FUNC_END sync_synchronize_cp15dmb
#endif
#endif
#ifdef L_sync_synchronize
/* Generic version of the synchronization primitive. If we know
that DMB exists, then use it. Otherwise, arrange for a link
time warning explaining how to pick a suitable alternative.
We choose not to use CP15DMB because it is performance
deprecated. We only define this function if generating
ELF binaries as otherwise we can't rely on the warning being
generated. */
#ifdef __ELF__
.text
.align 0
FUNC_START sync_synchronize
#if __ARM_ARCH >= 7 || __ARM_ARCH_PROFILE == 'M'
dmb
#endif
RET
FUNC_END sync_synchronize
#if !(__ARM_ARCH >= 7 || __ARM_ARCH_PROFILE == 'M')
.section .gnu.warning.__sync_synchronize
.align 0
.ascii "This implementation of __sync_synchronize is a stub with "
.ascii "no effect. Relink with\n"
.ascii " -specs=sync-{none,dmb,cp15dmb}.specs\n"
.ascii "to specify exactly which barrier format to use and avoid "
.ascii "this warning.\n\0"
#endif
#endif
#endif
#ifdef L_thumb1_case_si
.text

View file

@ -0,0 +1,4 @@
%rename link sync_sync_link
*link:
--defsym=__sync_synchronize=__sync_synchronize_cp15dmb %(sync_sync_link)

View file

@ -0,0 +1,4 @@
%rename link sync_sync_link
*link:
--defsym=__sync_synchronize=__sync_synchronize_dmb %(sync_sync_link)

View file

@ -0,0 +1,4 @@
%rename link sync_sync_link
*link:
--defsym=__sync_synchronize=__sync_synchronize_none %(sync_sync_link)

13
libgcc/config/arm/t-sync Normal file
View file

@ -0,0 +1,13 @@
LIB1ASMFUNCS += _sync_none _sync_dmb _sync_cp15dmb _sync_synchronize
EXTRA_PARTS += sync-none.specs sync-dmb.specs sync-cp15dmb.specs
sync-none.specs: $(srcdir)/config/arm/sync-none.specs
cp $< .
sync-dmb.specs: $(srcdir)/config/arm/sync-dmb.specs
cp $< .
sync-cp15dmb.specs: $(srcdir)/config/arm/sync-cp15dmb.specs
cp $< .