[PATCH v2] elf: Add optimization barrier for __ehdr_start and _end

Florian Weimer fweimer@redhat.com
Mon Jun 16 06:31:24 GMT 2025


* H. J. Lu:

> On Mon, Jun 16, 2025 at 1:48 PM Florian Weimer <fweimer@redhat.com> wrote:
>>
>> * H. J. Lu:
>>
>> > On Mon, Jun 16, 2025 at 12:55 PM Florian Weimer <fweimer@redhat.com> wrote:
>> >>
>> >> * H. J. Lu:
>> >>
>> >> > diff --git a/elf/rtld.c b/elf/rtld.c
>> >> > index 8e8f0e6253..e6a181dc31 100644
>> >> > --- a/elf/rtld.c
>> >> > +++ b/elf/rtld.c
>> >> > @@ -477,7 +477,10 @@ _dl_start_final (void *arg, struct dl_start_final_info *info)
>> >> >    _dl_setup_hash (&_dl_rtld_map);
>> >> >    _dl_rtld_map.l_real = &_dl_rtld_map;
>> >> >    _dl_rtld_map.l_map_start = (ElfW(Addr)) &__ehdr_start;
>> >> > +  /* Prevent run-time relocations against __ehdr_start and _end.  */
>> >> > +  asm ("" : "+g" (_dl_rtld_map.l_map_start));
>> >> >    _dl_rtld_map.l_map_end = (ElfW(Addr)) _end;
>> >> > +  asm ("" : "+g" (_dl_rtld_map.l_map_end));
>> >> >    /* Copy the TLS related data if necessary.  */
>> >> >  #ifndef DONT_USE_BOOTSTRAP_MAP
>> >> >  # if NO_TLS_OFFSET != 0
>> >>
>> >> This needs a better comment about why we are doing this, and exactly how
>> >> it prevents this problem.
>> >
>> > How about
>> >
>> > Prevent compiler vectorizer from loading hidden variables into vector registers.
>>
>> It doesn't say why "g" is the appropriate constraint here.
>
> "+g" is the least restricted constraint.  It tells compilers that the
> operand is both input and output.

If it's least restricted, why can't this trigger the use of a vector
register?  It seems to increase the risk of the bug happening, not
suppress it.

>> > Vector instructions are OK in rtld.c:
>>
>> For the most part, yes, but are they in performance-critical code?
>
> rtld.c is used by all programs.  Every bit of performance helps.

I'm not sure if the use of vector registers by GCC is an optimization
here.  It requires additional non-shareable memory and relocations.

>> If we do not use -mgeneral-regs-only, there is bound to be another
>> combination of compiler option that tries to load pointers directly into
>> vector registers before initial self-relocation.
>
> The list of these hidden variables is small, which can be checked by
> the newly added test.

There are additional places where GCC uses this technique to load
pointers, notably this place:

/* Dummy allocation object used if allocating the message buffer
   fails.  */
static void
oom_exception (struct dl_exception *exception)
{
  exception->objname = "";
  exception->errstring = _dl_out_of_memory;
  exception->message_buffer = NULL;
}

And this (the rfv variable):

/* Functions for resolving symbols in the VDSO link map.  */
static inline void *
dl_vdso_vsym (const char *name)
{
  struct link_map *map = GLRO (dl_sysinfo_map);
  if (map == NULL)
    return NULL;

  /* Use a WEAK REF so we don't error out if the symbol is not found.  */
  ElfW (Sym) wsym = { 0 };
  wsym.st_info = (unsigned char) ELFW (ST_INFO (STB_WEAK, STT_NOTYPE));

  const struct r_found_version rfv = { VDSO_NAME, VDSO_HASH, 1, NULL };

  /* Search the scope of the vdso map.  */
  const ElfW (Sym) *ref = &wsym;
  lookup_t result = GLRO (dl_lookup_symbol_x) (name, map, &ref,
					       map->l_local_scope,
					       &rfv, 0, 0, NULL);
  return ref != NULL ? DL_SYMBOL_ADDRESS (result, ref) : NULL;
}

These two do not even involved named objects, the relocations are
against string literals.

I think the new test should cover all of ld.so, and only accept the
IRELATIVE relocation and the initialization of _rtld_global_ro, and no
other run-time relocations.  (Maybe it has to be restricted to !Hurd,
though.)

Thanks,
Florian



More information about the Libc-alpha mailing list