powerpc: Move cache line size to rtld_global_ro

GCC 10.0 enabled -fno-common by default and this started to point that
__cache_line_size had been implemented in 2 different places: loader and
libc.

In order to avoid this duplication, the libc variable has been removed
and the loader variable is moved to rtld_global_ro.

File sysdeps/unix/sysv/linux/powerpc/dl-auxv.h has been added in order
to reuse code for both static and dynamic linking scenarios.

Reviewed-by: Carlos O'Donell <carlos@redhat.com>
This commit is contained in:
Tulio Magno Quites Machado Filho 2020-01-10 19:14:56 -03:00
parent c908ae0492
commit 18363b4f01
20 changed files with 314 additions and 69 deletions

View File

@ -36,6 +36,7 @@
#include <stackinfo.h>
#include <dl-vdso.h>
#include <dl-vdso-setup.h>
#include <dl-auxv.h>
extern char *__progname;
char **_dl_argv = &__progname; /* This is checked for some error messages. */
@ -293,9 +294,7 @@ _dl_aux_init (ElfW(auxv_t) *av)
case AT_RANDOM:
_dl_random = (void *) av->a_un.a_val;
break;
# ifdef DL_PLATFORM_AUXV
DL_PLATFORM_AUXV
# endif
}
if (seen == 0xf)
{

View File

@ -45,6 +45,7 @@
#include <tls.h>
#include <dl-tunables.h>
#include <dl-auxv.h>
extern char **_environ attribute_hidden;
extern char _end[] attribute_hidden;
@ -180,9 +181,7 @@ _dl_sysdep_start (void **start_argptr,
case AT_RANDOM:
_dl_random = (void *) av->a_un.a_val;
break;
#ifdef DL_PLATFORM_AUXV
DL_PLATFORM_AUXV
#endif
}
#ifndef HAVE_AUX_SECURE

21
sysdeps/generic/dl-auxv.h Normal file
View File

@ -0,0 +1,21 @@
/* Auxiliary vector processing. Generic version.
Copyright (C) 2020 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
<https://www.gnu.org/licenses/>. */
/* Define DL_PLATFORM_AUXV in order to process platform-specific AUXV entries
during the initialization of the loader or of a static libc. */
#define DL_PLATFORM_AUXV

View File

@ -14,6 +14,23 @@ mod-tlsopt-powerpc.so-no-z-defs = yes
tests += tst-tlsopt-powerpc
$(objpfx)tst-tlsopt-powerpc: $(objpfx)mod-tlsopt-powerpc.so
tests-static += tst-cache-ppc-static
tests-internal += tst-cache-ppc-static
ifeq (yes,$(build-shared))
modules-names += mod-cache-ppc
tests += tst-cache-ppc tst-cache-ppc-static-dlopen
tests-static += tst-cache-ppc-static-dlopen
test-internal-extras += mod-cache-ppc
mod-cache-ppc.so-no-z-defs = yes
tst-cache-ppc-static-dlopen-ENV = LD_LIBRARY_PATH=$(objpfx):$(common-objpfx):$(common-objpfx)elf
$(objpfx)tst-cache-ppc-static-dlopen: $(common-objpfx)dlfcn/libdl.a
$(objpfx)tst-cache-ppc-static-dlopen.out: $(objpfx)mod-cache-ppc.so
$(objpfx)tst-cache-ppc: $(objpfx)mod-cache-ppc.so
endif
ifneq (no,$(multi-arch))
tests-static += tst-tlsifunc-static
tests-internal += tst-tlsifunc-static

View File

@ -89,5 +89,22 @@ PROCINFO_CLASS const char _dl_powerpc_cap_flags[64][15]
,
#endif
#if !IS_IN (ldconfig)
# if !defined PROCINFO_DECL && defined SHARED
._dl_cache_line_size
# else
PROCINFO_CLASS int _dl_cache_line_size
# endif
# ifndef PROCINFO_DECL
= 0
# endif
# if !defined SHARED || defined PROCINFO_DECL
;
# else
,
# endif
#endif
#undef PROCINFO_DECL
#undef PROCINFO_CLASS

View File

@ -0,0 +1,45 @@
/* Test if an executable can read from rtld_global_ro._dl_cache_line_size.
Copyright (C) 2020 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
<https://www.gnu.org/licenses/>. */
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <sys/auxv.h>
#include <ldsodefs.h>
#include <errno.h>
/* errnop is required in order to work around BZ #20802. */
int
test_cache (int *errnop)
{
int cls1 = GLRO (dl_cache_line_size);
errno = *errnop;
uint64_t cls2 = getauxval (AT_DCACHEBSIZE);
*errnop = errno;
printf ("AT_DCACHEBSIZE = %" PRIu64 " B\n", cls2);
printf ("_dl_cache_line_size = %d B\n", cls1);
if (cls1 != cls2)
{
printf ("error: _dl_cache_line_size != AT_DCACHEBSIZE\n");
return 1;
}
return 0;
}

View File

@ -18,6 +18,7 @@
<https://www.gnu.org/licenses/>. */
#include <sysdep.h>
#include <rtld-global-offsets.h>
#define PREFETCH_AHEAD 4 /* no cache lines SRC prefetching ahead */
#define ZERO_AHEAD 2 /* no cache lines DST zeroing ahead */
@ -106,25 +107,23 @@ EALIGN (memcpy, 5, 0)
L(dst_aligned):
#ifdef SHARED
#ifdef PIC
mflr r0
/* Establishes GOT addressability so we can load __cache_line_size
from static. This value was set from the aux vector during startup. */
/* Establishes GOT addressability so we can load the cache line size
from rtld_global_ro. This value was set from the aux vector during
startup. */
SETUP_GOT_ACCESS(r9,got_label)
addis r9,r9,__cache_line_size-got_label@ha
lwz r9,__cache_line_size-got_label@l(r9)
mtlr r0
#else
/* Load __cache_line_size from static. This value was set from the
aux vector during startup. */
lis r9,__cache_line_size@ha
lwz r9,__cache_line_size@l(r9)
addis r9,r9,_GLOBAL_OFFSET_TABLE_-got_label@ha
addi r9,r9,_GLOBAL_OFFSET_TABLE_-got_label@l
mtlr r0
#endif
__GLRO(r9, r9, _dl_cache_line_size,
RTLD_GLOBAL_RO_DL_CACHE_LINE_SIZE_OFFSET)
cmplwi cr5, r9, 0
bne+ cr5,L(cachelineset)
/* __cache_line_size not set: generic byte copy without much optimization */
/* Cache line size not set: generic byte copy without much optimization */
andi. r0,r5,1 /* If length is odd copy one byte. */
beq L(cachelinenotset_align)
lbz r7,0(r4) /* Read one byte from source. */

View File

@ -25,11 +25,6 @@
#include <dl-machine.h>
#include <_itoa.h>
/* The value __cache_line_size is defined in dl-sysdep.c and is initialised
by _dl_sysdep_start via DL_PLATFORM_INIT. */
extern int __cache_line_size attribute_hidden;
/* Stuff for the PLT. */
#define PLT_INITIAL_ENTRY_WORDS 18
#define PLT_LONGBRANCH_ENTRY_WORDS 0
@ -309,14 +304,14 @@ __elf_machine_runtime_setup (struct link_map *map, int lazy, int profile)
Assumes that dcbst and icbi apply to lines of 16 bytes or
more. Current known line sizes are 16, 32, and 128 bytes.
The following gets the __cache_line_size, when available. */
The following gets the cache line size, when available. */
/* Default minimum 4 words per cache line. */
int line_size_words = 4;
if (lazy && __cache_line_size != 0)
if (lazy && GLRO(dl_cache_line_size) != 0)
/* Convert bytes to words. */
line_size_words = __cache_line_size / 4;
line_size_words = GLRO(dl_cache_line_size) / 4;
size_modified = lazy ? rel_offset_words : 6;
for (i = 0; i < size_modified; i += line_size_words)

View File

@ -17,12 +17,13 @@
<https://www.gnu.org/licenses/>. */
#include <sysdep.h>
#include <rtld-global-offsets.h>
/* void * [r3] memset (void *s [r3], int c [r4], size_t n [r5]));
Returns 's'.
The memset is done in four sizes: byte (8 bits), word (32 bits),
32-byte blocks (256 bits) and __cache_line_size (128, 256, 1024 bits).
32-byte blocks (256 bits) and cache line size (128, 256, 1024 bits).
There is a special case for setting whole cache lines to 0, which
takes advantage of the dcbz instruction. */
@ -95,7 +96,7 @@ L(caligned):
/* Check if we can use the special case for clearing memory using dcbz.
This requires that we know the correct cache line size for this
processor. Getting the __cache_line_size may require establishing GOT
processor. Getting the cache line size may require establishing GOT
addressability, so branch out of line to set this up. */
beq cr1, L(checklinesize)
@ -230,26 +231,22 @@ L(medium_28t):
blr
L(checklinesize):
#ifdef SHARED
/* If the remaining length is less the 32 bytes then don't bother getting
the cache line size. */
beq L(medium)
#ifdef PIC
mflr rTMP
/* If the remaining length is less the 32 bytes then don't bother getting
the cache line size. */
beq L(medium)
/* Establishes GOT addressability so we can load __cache_line_size
from static. This value was set from the aux vector during startup. */
/* Establishes GOT addressability so we can load the cache line size
from rtld_global_ro. This value was set from the aux vector during
startup. */
SETUP_GOT_ACCESS(rGOT,got_label)
addis rGOT,rGOT,__cache_line_size-got_label@ha
lwz rCLS,__cache_line_size-got_label@l(rGOT)
addis rGOT,rGOT,_GLOBAL_OFFSET_TABLE_-got_label@ha
addi rGOT,rGOT,_GLOBAL_OFFSET_TABLE_-got_label@l
mtlr rTMP
#else
/* Load __cache_line_size from static. This value was set from the
aux vector during startup. */
lis rCLS,__cache_line_size@ha
/* If the remaining length is less the 32 bytes then don't bother getting
the cache line size. */
beq L(medium)
lwz rCLS,__cache_line_size@l(rCLS)
#endif
/* Load rtld_global_ro._dl_cache_line_size. */
__GLRO(rCLS, rGOT, _dl_cache_line_size,
RTLD_GLOBAL_RO_DL_CACHE_LINE_SIZE_OFFSET)
/* If the cache line size was not set then goto to L(nondcbz), which is
safe for any cache line size. */

View File

@ -157,4 +157,30 @@ GOT_LABEL: ; \
/* Label in text section. */
#define C_TEXT(name) name
/* Read the value of member from rtld_global_ro. */
#ifdef PIC
# ifdef SHARED
# if IS_IN (rtld)
/* Inside ld.so we use the local alias to avoid runtime GOT
relocations. */
# define __GLRO(rOUT, rGOT, member, offset) \
lwz rOUT,_rtld_local_ro@got(rGOT); \
lwz rOUT,offset(rOUT)
# else
# define __GLRO(rOUT, rGOT, member, offset) \
lwz rOUT,_rtld_global_ro@got(rGOT); \
lwz rOUT,offset(rOUT)
# endif
# else
# define __GLRO(rOUT, rGOT, member, offset) \
lwz rOUT,member@got(rGOT); \
lwz rOUT,0(rOUT)
# endif
#else
/* Position-dependent code does not require access to the GOT. */
# define __GLRO(rOUT, rGOT, member, offset) \
lis rOUT,(member+LOWORD)@ha \
lwz rOUT,(member+LOWORD)@l(rOUT)
#endif /* PIC */
#endif /* __ASSEMBLER__ */

View File

@ -18,6 +18,7 @@
<https://www.gnu.org/licenses/>. */
#include <sysdep.h>
#include <rtld-global-offsets.h>
#ifndef MEMCPY
# define MEMCPY memcpy
@ -27,8 +28,9 @@
#define ZERO_AHEAD 2 /* no cache lines DST zeroing ahead */
.section ".toc","aw"
.LC0:
.tc __cache_line_size[TC],__cache_line_size
__GLRO_DEF(dl_cache_line_size)
.section ".text"
.align 2
@ -55,10 +57,11 @@ ENTRY (MEMCPY, 5)
*/
neg r8,r3 /* LS 4 bits = # bytes to 8-byte dest bdry */
ld r9,.LC0@toc(r2) /* Get cache line size (part 1) */
/* Get the cache line size. */
__GLRO (r9, dl_cache_line_size,
RTLD_GLOBAL_RO_DL_CACHE_LINE_SIZE_OFFSET)
clrldi r8,r8,64-4 /* align to 16byte boundary */
sub r7,r4,r3 /* compute offset to src from dest */
lwz r9,0(r9) /* Get cache line size (part 2) */
cmpldi cr0,r8,0 /* Were we aligned on a 16 byte bdy? */
addi r10,r9,-1 /* Cache line mask */
beq+ L(dst_aligned)
@ -121,7 +124,7 @@ L(dst_aligned):
cmpdi cr0,r9,0 /* Cache line size set? */
bne+ cr0,L(cachelineset)
/* __cache_line_size not set: generic byte copy without much optimization */
/* Cache line size not set: generic byte copy without much optimization */
clrldi. r0,r5,63 /* If length is odd copy one byte */
beq L(cachelinenotset_align)
lbz r7,0(r4) /* Read one byte from source */

View File

@ -17,10 +17,11 @@
<https://www.gnu.org/licenses/>. */
#include <sysdep.h>
#include <rtld-global-offsets.h>
.section ".toc","aw"
.LC0:
.tc __cache_line_size[TC],__cache_line_size
__GLRO_DEF(dl_cache_line_size)
.section ".text"
.align 2
@ -146,8 +147,10 @@ L(zloopstart):
/* If the remaining length is less the 32 bytes, don't bother getting
the cache line size. */
beq L(medium)
ld rCLS,.LC0@toc(r2)
lwz rCLS,0(rCLS)
/* Read the cache line size. */
__GLRO (rCLS, dl_cache_line_size,
RTLD_GLOBAL_RO_DL_CACHE_LINE_SIZE_OFFSET)
/* If the cache line size was not set just goto to L(nondcbz) which is
safe for any cache line size. */
cmpldi cr1,rCLS,0

View File

@ -342,6 +342,30 @@ LT_LABELSUFFIX(name,_name_end): ; \
#define PSEUDO_END_ERRVAL(name) \
END (name)
#ifdef SHARED
# if IS_IN (rtld)
/* Inside ld.so we use the local alias to avoid runtime GOT
relocations. */
# define __GLRO_DEF(var) \
.LC__ ## var: \
.tc _rtld_local_ro[TC],_rtld_local_ro
# else
# define __GLRO_DEF(var) \
.LC__ ## var: \
.tc _rtld_global_ro[TC],_rtld_global_ro
# endif
# define __GLRO(rOUT, var, offset) \
ld rOUT,.LC__ ## var@toc(r2); \
lwz rOUT,offset(rOUT)
#else
# define __GLRO_DEF(var) \
.LC__ ## var: \
.tc _ ## var[TC],_ ## var
# define __GLRO(rOUT, var, offset) \
ld rOUT,.LC__ ## var@toc(r2); \
lwz rOUT,0(rOUT)
#endif
#else /* !__ASSEMBLER__ */
#if _CALL_ELF != 2

View File

@ -6,3 +6,4 @@
RTLD_GLOBAL_RO_DL_HWCAP_OFFSET rtld_global_ro_offsetof (_dl_hwcap)
RTLD_GLOBAL_RO_DL_HWCAP2_OFFSET rtld_global_ro_offsetof (_dl_hwcap2)
RTLD_GLOBAL_RO_DL_CACHE_LINE_SIZE_OFFSET rtld_global_ro_offsetof (_dl_cache_line_size)

View File

@ -0,0 +1,54 @@
/* Test dl_cache_line_size from a dlopen'ed DSO from a static executable.
Copyright (C) 2020 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
<https://www.gnu.org/licenses/>. */
#include <dlfcn.h>
#include <stdio.h>
#include <errno.h>
int test_cache(int *);
static int
do_test (void)
{
int ret;
void *handle;
int (*test_cache) (int *);
handle = dlopen ("mod-cache-ppc.so", RTLD_LAZY | RTLD_LOCAL);
if (handle == NULL)
{
printf ("dlopen (mod-cache-ppc.so): %s\n", dlerror ());
return 1;
}
test_cache = dlsym (handle, "test_cache");
if (test_cache == NULL)
{
printf ("dlsym (test_cache): %s\n", dlerror ());
return 1;
}
ret = test_cache(&errno);
test_cache = NULL;
dlclose (handle);
return ret;
}
#include <support/test-driver.c>

View File

@ -0,0 +1,20 @@
/* Test if an executable can read from _dl_cache_line_size.
Copyright (C) 2020 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
<https://www.gnu.org/licenses/>. */
#include "tst-cache-ppc.c"
#include "mod-cache-ppc.c"

View File

@ -0,0 +1,29 @@
/* Test if an executable can read from rtld_global_ro._dl_cache_line_size.
Copyright (C) 2020 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
<https://www.gnu.org/licenses/>. */
#include <errno.h>
int test_cache(int *);
static int
do_test (void)
{
return test_cache(&errno);
}
#include <support/test-driver.c>

View File

@ -1,5 +1,5 @@
/* Operating system support for run-time dynamic linker. Linux/PPC version.
Copyright (C) 1997-2020 Free Software Foundation, Inc.
/* Auxiliary vector processing. Linux/PPC version.
Copyright (C) 2020 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
@ -16,18 +16,15 @@
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
#include <config.h>
#include <ldsodefs.h>
int __cache_line_size attribute_hidden;
#if IS_IN (libc) && !defined SHARED
int GLRO(dl_cache_line_size);
#endif
/* Scan the Aux Vector for the "Data Cache Block Size" entry. If found
verify that the static extern __cache_line_size is defined by checking
for not NULL. If it is defined then assign the cache block size
value to __cache_line_size. */
/* Scan the Aux Vector for the "Data Cache Block Size" entry and assign it
to dl_cache_line_size. */
#define DL_PLATFORM_AUXV \
case AT_DCACHEBSIZE: \
__cache_line_size = av->a_un.a_val; \
GLRO(dl_cache_line_size) = av->a_un.a_val; \
break;
#include <sysdeps/unix/sysv/linux/dl-sysdep.c>

View File

@ -30,12 +30,14 @@ _dl_var_init (void *array[])
DL_AUXV = 1,
DL_HWCAP = 2,
DL_HWCAP2 = 3,
DL_CACHE_LINE_SIZE = 4
};
GLRO(dl_pagesize) = *((size_t *) array[DL_PAGESIZE]);
GLRO(dl_auxv) = (ElfW(auxv_t) *) *((size_t *) array[DL_AUXV]);
GLRO(dl_hwcap) = *((unsigned long int *) array[DL_HWCAP]);
GLRO(dl_hwcap2) = *((unsigned long int *) array[DL_HWCAP2]);
GLRO(dl_cache_line_size) = (int) *((int *) array[DL_CACHE_LINE_SIZE]);
}
#else
@ -46,6 +48,7 @@ static void *variables[] =
&GLRO(dl_auxv),
&GLRO(dl_hwcap),
&GLRO(dl_hwcap2),
&GLRO(dl_cache_line_size)
};
static void

View File

@ -24,7 +24,6 @@
#include <hwcapinfo.h>
#endif
int __cache_line_size attribute_hidden;
/* The main work is done in the generic function. */
#define LIBC_START_MAIN generic_start_main
#define LIBC_START_DISABLE_INLINE
@ -71,15 +70,12 @@ __libc_start_main (int argc, char **argv,
rtld_fini = NULL;
}
/* Initialize the __cache_line_size variable from the aux vector. For the
static case, we also need _dl_hwcap, _dl_hwcap2 and _dl_platform, so we
can call __tcb_parse_hwcap_and_convert_at_platform (). */
for (ElfW (auxv_t) * av = auxvec; av->a_type != AT_NULL; ++av)
switch (av->a_type)
{
case AT_DCACHEBSIZE:
__cache_line_size = av->a_un.a_val;
break;
/* For the static case, we also need _dl_hwcap, _dl_hwcap2 and
_dl_platform, so we can call
__tcb_parse_hwcap_and_convert_at_platform (). */
#ifndef SHARED
case AT_HWCAP:
_dl_hwcap = (unsigned long int) av->a_un.a_val;