Questions regarding manipulation of IFUNC selection and tunables like glibc.cpu.hwcap_mask

Szabolcs Nagy szabolcs.nagy@arm.com
Thu Aug 25 10:47:45 GMT 2022


The 08/25/2022 11:54, Stefan Liebler via Libc-alpha wrote:
> on s390x, the IFUNC'ed functions or other hw-dependent code-paths are
> usually selected by either the HWCAPs or the facility-list retrieved via
> stfle-instruction.
> 
> Now we need a possibility to manipulate the IFUNC selection. As the
> current IFUNC-resolvers always select the functions for the newest
> features, we only need a possibility to disable features.
> 
> According to <glibc>/manual/tunables.texi:
> @deftp Tunable glibc.cpu.hwcap_mask
> This tunable supersedes the @env{LD_HWCAP_MASK} environment variable and is
> identical in features.
> 
> The @code{AT_HWCAP} key in the Auxiliary Vector specifies instruction set
> extensions available in the processor at runtime for some architectures.
>  The
> @code{glibc.cpu.hwcap_mask} tunable allows the user to mask out those
> capabilities at runtime, thus disabling use of those extensions.
> @end deftp

iirc LD_HWCAP_MASK was purely for the old hwcap based
lib path lookup.

> But a small testprogram (see attached tst-ifunc-manipulation.c) shows
> that neither setting the environment variable
> GLIBC_TUNABLES="glibc.cpu.hwcap_mask=0" nor LD_HWCAP_MASK="0x0
> influences the HWCAPs.
> 
> On s390x, the IFUNC-resolvers get the HWCAPs as argument (the most other
> architectures don't have this argument). Other code-paths can get the
> HWCAPs via getauxval(AT_HWCAP). In both cases the HWCAPs are loaded from
> "GLRO(dl_hwcap)". See:

i think hwcap_mask was not for completely hiding hwcaps
like that.

maybe we need a mechanism for hiding too (can be useful
for testing), however since it is in userspace, the kernel
and hw will behave as if HWCAP is present which may be
observable even if the libc tries to hide it.

also if this is useful then we need hwcap2 mask too,
and allow using hwcap names like "glibc.cpu.hwcaps" does
on x86.



> -
> https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/s390/dl-irel.h;h=20e4887467d80a1b3f95da00bb98386e3eadfe47;hb=HEAD#l33
> -
> https://sourceware.org/git/?p=glibc.git;a=blob;f=misc/getauxval.c;h=714ce5bd62ec33c38356b187e6ec067b72b77afb;hb=HEAD#l32
> 
> 
> Is it a bug or the intention that the HWCAP values are not influenced by
> glibc.cpu.hwcap_mask tunable?
> 
> If it is a bug, would it be possible to apply the mask after
> __tunables_init() like this:
> GLRO(dl_hwcap) &= GET_HWCAP_MASK();
> This would affect the IFUNC-resolver, getauxval(AT_HWCAP) and more (e.g.
> if lock-elision is available or not) on all architectures. This would
> also change the behavior of programs/libraries using getauxval(AT_HWCAP).
> 
> As alternative, we could also introduce a new s390-specific tunable
> like: glibc.cpu.s390.hwcap_mask which influences only the s390-IFUNCS /
> s390-code-pathes within glibc. The behaviour of programs/libraries using
> getauxval(AT_HWCAP) is not changed.
> 
> Independent of the HWCAPs, we need to introduce a new s390-specific
> tunable like glibc.cpu.s390.stfle_mask in order to influence the
> s390-IFUNCs within glibc which are dependent on the facility-list.
> 
> Are there other hints?
> 
> Thanks in advance,
> Stefan

> #include <stdio.h>
> #include <stdlib.h>
> #include <sys/auxv.h>
> 
> /* Run with/without environment variables does not influence HWCAPs:
> 
>    GLIBC_TUNABLES=""
>    LD_HWCAP_MASK=""
>    HWCAPs passed as argument to ifunc-resolver: 0x67ffff
>    HWCAPs from getauxval (AT_HWCAP): 0x67ffff
> 
>    GLIBC_TUNABLES="glibc.cpu.hwcap_mask=0"
>    LD_HWCAP_MASK=""
>    HWCAPs passed as argument to ifunc-resolver: 0x67ffff
>    HWCAPs from getauxval (AT_HWCAP): 0x67ffff
> 
>    GLIBC_TUNABLES=""
>    LD_HWCAP_MASK="0x0"
>    HWCAPs passed as argument to ifunc-resolver: 0x67ffff
>    HWCAPs from getauxval (AT_HWCAP): 0x67ffff
> */
> 
> static unsigned long global_hwcaps = 0;
> 
> static int impl(void)
> {
>   printf ("HWCAPs passed as argument to ifunc-resolver: 0x%lx\n",
> 	  global_hwcaps);
>   return 42;
> }
> static void *resolver(unsigned long hwcap)
> {
>   global_hwcaps = hwcap;
>   return impl;
> }
> int ifunc(void) __attribute__((ifunc("resolver")));
> 
> int
> main (void)
> {
>   printf ("GLIBC_TUNABLES=\"%s\"\n", getenv ("GLIBC_TUNABLES") ? : "");
>   printf ("LD_HWCAP_MASK=\"%s\"\n", getenv ("LD_HWCAP_MASK") ? : "");
> 
>   ifunc ();
>   printf ("HWCAPs from getauxval (AT_HWCAP): 0x%lx\n", getauxval (AT_HWCAP));
> 
>   return EXIT_SUCCESS;
> }



More information about the Libc-alpha mailing list