[PATCH 09/11] elf: Add glibc-hwcaps subdirectory support to ld.so cache processing

Adhemerval Zanella adhemerval.zanella@linaro.org
Wed Dec 2 12:08:13 GMT 2020



On 01/12/2020 17:45, Florian Weimer wrote:
> * Adhemerval Zanella via Libc-alpha:
> 
>> On 09/11/2020 15:41, Florian Weimer via Libc-alpha wrote:
>>> This recognizes the DL_CACHE_HWCAP_EXTENSION flag and picks up
>>> the supported cache entry with the highest priority.
>>
>> Maybe add a brief description of what DL_CACHE_HWCAP_EXTENSION aims to
>> do?
> 
> It's documented in sysdeps/generic/dl-cache.h, added in the previous
> commit:
> 
> /* This bit in the hwcap field of struct file_entry_new indicates that
>    the lower 32 bits contain an index into the
>    cache_extension_tag_glibc_hwcaps section.  Older glibc versions do
>    not know about this HWCAP bit, so they will ignore these
>    entries.  */
> #define DL_CACHE_HWCAP_EXTENSION (1ULL << 62)

I meant to commit message, but I don't have a strong opinion about it.

> 
>>> +/* Return the priority of the cache_extension_tag_glibc_hwcaps section
>>> +   entry at INDEX.  Zero means do not use.  Otherwise, lower values
>>> +   indicate greater preference.  */
>>> +static uint32_t __attribute__ ((noinline, noclone))
>>> +glibc_hwcaps_priority (uint32_t index)
>>
>> I have a feeling I have asked it before, but why does it need noclone/noinline
>> here?
> 
> I don't recall such a discussion.  It's a leftover from previous
> debugging efforts.

Ack.

> 
>>> +{
>>> +  /* Using a zero-length array as an indicator that nothing has been
>>> +     loaded is not a problem: It does not lead to repeated
>>> +     initialization attempts because caches without an extension
>>> +     section are processed without calling this function (unless the
>>> +     file is corrupted).  */
>>> +  if (glibc_hwcaps_priorities_length == 0)
>>
>> Maybe an early exit here? It allow move the code one identation left
>> and makes it more readable.
> 
> I've moved this into a separate initialization function.

Ack.

> 
>>> +      while (left < left_end && right < right_end)
>>> +	{
>>> +	  uint32_t string_table_index = *left;
>>> +	  if (string_table_index < cachesize)
>>> +	    {
>>> +	      const char *left_name
>>> +		= (const char *) cache + string_table_index;
>>> +	      uint32_t left_name_length = strlen (left_name);
>>> +	      uint32_t to_compare;
>>> +	      if (left_name_length < right->name_length)
>>> +		to_compare = left_name_length;
>>> +	      else
>>> +		to_compare = right->name_length;
>>> +	      int cmp = memcmp (left_name, right->name, to_compare);
>>> +	      if (cmp == 0)
>>> +		{
>>> +		  if (left_name_length < right->name_length)
>>> +		    cmp = -1;
>>> +		  else if (left_name_length > right->name_length)
>>> +		    cmp = 1;
>>> +		}
>>> +	      if (cmp == 0)
>>> +		{
>>> +		  *result = right->priority;
>>> +		  ++result;
>>> +		  ++left;
>>> +		  ++right;
>>> +		}
>>
>> Maybe add as the 'else' within the 'cmp == 0' below?
>>
>>> +	      else if (cmp < 0)
>>> +		{
>>> +		  *result = 0;
>>> +		  ++result;
>>> +		  ++left;
>>> +		}
>>> +	      else
>>> +		++right;
> 
> You mean like this?
> 
> 	  if (cmp == 0)
> 	    {
> 	      *result = right->priority;
> 	      ++result;
> 	      ++left;
> 	    }
> 	  if (cmp < 0)
> 	    {
> 	      *result = 0;
> 	      ++result;
> 	      ++left;
> 	    }
>           if (cmp >= 0)
> 	    ++right;

The v5 seems more readable in fact.


> 
> I don't think that's an improvement.
> 
>>> +struct dl_hwcaps_priority *_dl_hwcaps_priorities;
>>> +uint32_t _dl_hwcaps_priorities_length;
>>> +
>>> +/* Allocate _dl_hwcaps_priorities and fill it with data.  */
>>> +static void
>>> +compute_priorities (size_t total_count, const char *prepend,
>>> +		    int32_t bitmask, const char *mask)
>>
>> I think bitmask should be a 'uint32' here.
> 
> Right, fixed.
> 
>>> +int
>>> +main (int argc, char **argv)
>>> +{
>>> +  /* Run ldconfig to populate the cache.  */
>>> +  {
>>> +    char *command = xasprintf ("%s/ldconfig", support_install_rootsbindir);
>>> +    if (system (command) != 0)
>>> +      return 1;
>>> +    free (command);
>>> +  }
>>> +
>>> +  /* Reuse tst-glibc-hwcaps.  Since this code is running in a
>>> +     container, we can launch it directly.  */
>>> +  char *path = xasprintf ("%s/elf/tst-glibc-hwcaps", support_objdir_root);
>>> +  execv (path, argv);
>>> +  printf ("error: execv of %s failed: %m\n", path);
>>> +  return 1;
>>> +}
>>
>> Ok, it should be simple enough to require use libsupport fork/timeout
>> check.
> 
> Yes, we run ldconfig without timeout elsewhere, and tst-glibc-hwcaps has
> its own timeout check.
> 
>> Should we test the case of shared memory removal, for instance:
>>
>>   1. Remove second override, without ldconfig
>>   2. Remove third override, run ldconfig
>>   3. Add both second and third back, run ldconfig, remove third
>>   4. Keep second, run ldconfig
> 
> I added this:
> 
> +  /* Remove the second override again, without running ldconfig.
> +     Ideally, this would revert to implementation 2.  However, in the
> +     current implementation, the cache returns exactly one file name
> +     which does not exist after unlinking, so the dlopen fails.  */
> +  xunlink ("/glibc-test/lib/glibc-hwcaps/prepend3/" SONAME);
> +  TEST_VERIFY (dlopen (SONAME, RTLD_NOW) == NULL);
> +  run_ldconfig ();
> +  system("/sbin/ldconfig -p");

I think this might a leftover of debugging.

> +  {
> +    /* After running ldconfig, the second implementation is available
> +       once more.  */
> +    void *handle = xdlopen (SONAME, RTLD_NOW);
> +    int (*marker1) (void) = xdlsym (handle, "marker1");
> +    TEST_COMPARE (marker1 (), 2);
> +    xdlclose (handle);
> +  }
> 
> I think I know what I have to do to fix this in elf/dl-load.c.
> 
> I feel this is a pre-existing issue.  It also applies to the legacy
> hwcaps subdirectories.  This only happens for ld.so.cache bringing in
> libraries from a non-searched directory, otherwise the LD_LIBRARY_PATH
> processing will find an implementation if it exists.  I'd like to fix it
> in a follow-up patch.

Fair enough.


More information about the Libc-alpha mailing list