> Am 06.09.2024 um 20:50 schrieb Jakub Jelinek <ja...@redhat.com>:
> 
> Hi!
> 
> cat abc.C
> #define A(n) struct T##n {} t##n;
> #define B(n) A(n##0) A(n##1) A(n##2) A(n##3) A(n##4) A(n##5) A(n##6) A(n##7) 
> A(n##8) A(n##9)
> #define C(n) B(n##0) B(n##1) B(n##2) B(n##3) B(n##4) B(n##5) B(n##6) B(n##7) 
> B(n##8) B(n##9)
> #define D(n) C(n##0) C(n##1) C(n##2) C(n##3) C(n##4) C(n##5) C(n##6) C(n##7) 
> C(n##8) C(n##9)
> #define E(n) D(n##0) D(n##1) D(n##2) D(n##3) D(n##4) D(n##5) D(n##6) D(n##7) 
> D(n##8) D(n##9)
> E(1) E(2) E(3)
> int main () { return 0; }
> ./xg++ -B ./ -o abc{.o,.C} -flto -flto-partition=1to1 -O2 -g 
> -fdebug-types-section -c
> ./xgcc -B ./ -o abc{,.o} -flto -flto-partition=1to1 -O2
> (not included in testsuite as it takes a while to compile) FAILs with
> lto-wrapper: fatal error: Too many copied sections: Operation not supported
> compilation terminated.
> /usr/bin/ld: error: lto-wrapper failed
> collect2: error: ld returned 1 exit status
> 
> The following patch fixes that.  Most of the 64K+ section support for
> reading and writing was already there years ago (and especially reading used
> quite often already) and a further bug fixed in it in the PR104617 fix.
> 
> Yet, the fix isn't solely about removing the
>  if (new_i - 1 >= SHN_LORESERVE)
>    {
>      *err = ENOTSUP;
>      return "Too many copied sections";
>    }
> 5 lines, the missing part was that the function only handled reading of
> the .symtab_shndx section but not copying/updating of it.
> If the result has less than 64K-epsilon sections, that actually wasn't
> needed, but e.g. with -fdebug-types-section one can exceed that pretty
> easily (reported to us on WebKitGtk build on ppc64le).
> Updating the section is slightly more complicated, because it basically
> needs to be done in lock step with updating the .symtab section, if one
> doesn't need to use SHN_XINDEX in there, the section should (or should be
> updated to) contain SHN_UNDEF entry, otherwise needs to have whatever would
> be overwise stored but couldn't fix.  But repeating due to that all the
> symtab decisions what to discard and how to rewrite it would be ugly.
> 
> So, the patch instead emits the .symtab_shndx section (or sections) last
> and prepares the content during the .symtab processing and in a second
> pass when going just through .symtab_shndx sections just uses the saved
> content.

Ah, good idea.

> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

Ok, I suppose also OK for the 14 branch after a bit.

Thanks,
Richard 

> 2024-09-06  Jakub Jelinek  <ja...@redhat.com>
> 
>    PR lto/116614
>    * simple-object-elf.c (SHN_COMMON): Align comment with neighbouring
>    comments.
>    (SHN_HIRESERVE): Use uppercase hex digits instead of lowercase for
>    consistency.
>    (simple_object_elf_find_sections): Formatting fixes.
>    (simple_object_elf_fetch_attributes): Likewise.
>    (simple_object_elf_attributes_merge): Likewise.
>    (simple_object_elf_start_write): Likewise.
>    (simple_object_elf_write_ehdr): Likewise.
>    (simple_object_elf_write_shdr): Likewise.
>    (simple_object_elf_write_to_file): Likewise.
>    (simple_object_elf_copy_lto_debug_section): Likewise.  Don't fail for
>    new_i - 1 >= SHN_LORESERVE, instead arrange in that case to copy
>    over .symtab_shndx sections, though emit those last and compute their
>    section content when processing associated .symtab sections.  Handle
>    simple_object_internal_read failure even in the .symtab_shndx reading
>    case.
> 
> --- libiberty/simple-object-elf.c.jj    2024-01-03 12:07:48.461085637 +0100
> +++ libiberty/simple-object-elf.c    2024-09-06 13:34:12.796669098 +0200
> @@ -128,9 +128,9 @@ typedef struct {
> 
> #define SHN_UNDEF    0        /* Undefined section */
> #define SHN_LORESERVE    0xFF00        /* Begin range of reserved indices */
> -#define SHN_COMMON    0xFFF2    /* Associated symbol is in common */
> +#define SHN_COMMON    0xFFF2        /* Associated symbol is in common */
> #define SHN_XINDEX    0xFFFF        /* Section index is held elsewhere */
> -#define SHN_HIRESERVE    0xffff        /* End of reserved indices */
> +#define SHN_HIRESERVE    0xFFFF        /* End of reserved indices */
> 
> 
> /* 32-bit ELF program header.  */
> @@ -569,8 +569,8 @@ simple_object_elf_find_sections (simple_
>                 void *data,
>                 int *err)
> {
> -  struct simple_object_elf_read *eor =
> -    (struct simple_object_elf_read *) sobj->data;
> +  struct simple_object_elf_read *eor
> +    = (struct simple_object_elf_read *) sobj->data;
>   const struct elf_type_functions *type_functions = eor->type_functions;
>   unsigned char ei_class = eor->ei_class;
>   size_t shdr_size;
> @@ -662,8 +662,8 @@ simple_object_elf_fetch_attributes (simp
>                    const char **errmsg ATTRIBUTE_UNUSED,
>                    int *err ATTRIBUTE_UNUSED)
> {
> -  struct simple_object_elf_read *eor =
> -    (struct simple_object_elf_read *) sobj->data;
> +  struct simple_object_elf_read *eor
> +    = (struct simple_object_elf_read *) sobj->data;
>   struct simple_object_elf_attributes *ret;
> 
>   ret = XNEW (struct simple_object_elf_attributes);
> @@ -689,10 +689,10 @@ simple_object_elf_release_read (void *da
> static const char *
> simple_object_elf_attributes_merge (void *todata, void *fromdata, int *err)
> {
> -  struct simple_object_elf_attributes *to =
> -    (struct simple_object_elf_attributes *) todata;
> -  struct simple_object_elf_attributes *from =
> -    (struct simple_object_elf_attributes *) fromdata;
> +  struct simple_object_elf_attributes *to
> +    = (struct simple_object_elf_attributes *) todata;
> +  struct simple_object_elf_attributes *from
> +    = (struct simple_object_elf_attributes *) fromdata;
> 
>   if (to->ei_data != from->ei_data || to->ei_class != from->ei_class)
>     {
> @@ -751,8 +751,8 @@ simple_object_elf_start_write (void *att
>                   const char **errmsg ATTRIBUTE_UNUSED,
>                   int *err ATTRIBUTE_UNUSED)
> {
> -  struct simple_object_elf_attributes *attrs =
> -    (struct simple_object_elf_attributes *) attributes_data;
> +  struct simple_object_elf_attributes *attrs
> +    = (struct simple_object_elf_attributes *) attributes_data;
>   struct simple_object_elf_write *ret;
> 
>   /* We're just going to record the attributes, but we need to make a
> @@ -769,8 +769,8 @@ static int
> simple_object_elf_write_ehdr (simple_object_write *sobj, int descriptor,
>                  const char **errmsg, int *err)
> {
> -  struct simple_object_elf_attributes *attrs =
> -    (struct simple_object_elf_attributes *) sobj->data;
> +  struct simple_object_elf_attributes *attrs
> +    = (struct simple_object_elf_attributes *) sobj->data;
>   const struct elf_type_functions* fns;
>   unsigned char cl;
>   size_t ehdr_size;
> @@ -852,8 +852,8 @@ simple_object_elf_write_shdr (simple_obj
>                  size_t sh_entsize,
>                  const char **errmsg, int *err)
> {
> -  struct simple_object_elf_attributes *attrs =
> -    (struct simple_object_elf_attributes *) sobj->data;
> +  struct simple_object_elf_attributes *attrs
> +    = (struct simple_object_elf_attributes *) sobj->data;
>   const struct elf_type_functions* fns;
>   unsigned char cl;
>   size_t shdr_size;
> @@ -894,8 +894,8 @@ static const char *
> simple_object_elf_write_to_file (simple_object_write *sobj, int descriptor,
>                 int *err)
> {
> -  struct simple_object_elf_write *eow =
> -    (struct simple_object_elf_write *) sobj->data;
> +  struct simple_object_elf_write *eow
> +    = (struct simple_object_elf_write *) sobj->data;
>   struct simple_object_elf_attributes *attrs = &eow->attrs;
>   unsigned char cl;
>   size_t ehdr_size;
> @@ -1088,11 +1088,11 @@ simple_object_elf_copy_lto_debug_section
>                       char *(*pfn) (const char *),
>                       int *err)
> {
> -  struct simple_object_elf_read *eor =
> -    (struct simple_object_elf_read *) sobj->data;
> +  struct simple_object_elf_read *eor
> +    = (struct simple_object_elf_read *) sobj->data;
>   const struct elf_type_functions *type_functions = eor->type_functions;
> -  struct simple_object_elf_write *eow =
> -    (struct simple_object_elf_write *) dobj->data;
> +  struct simple_object_elf_write *eow
> +    = (struct simple_object_elf_write *) dobj->data;
>   unsigned char ei_class = eor->ei_class;
>   size_t shdr_size;
>   unsigned int shnum;
> @@ -1106,10 +1106,13 @@ simple_object_elf_copy_lto_debug_section
>   int changed;
>   int *pfnret;
>   const char **pfnname;
> -  unsigned new_i;
> +  unsigned new_i, new_count;
>   unsigned *sh_map;
>   unsigned first_shndx = 0;
>   unsigned int *symtab_indices_shndx;
> +  int pass_symtab_indices_shndx;
> +  unsigned int first_symtab_indices_shndx;
> +  unsigned char **symtab_indices_shndx_buf;
> 
>   shdr_size = (ei_class == ELFCLASS32
>           ? sizeof (Elf32_External_Shdr)
> @@ -1179,8 +1182,7 @@ simple_object_elf_copy_lto_debug_section
>       ret = (*pfn) (name);
>       pfnret[i - 1] = ret == NULL ? -1 : 0;
>       pfnname[i - 1] = ret == NULL ? name : ret;
> -      if (first_shndx == 0
> -      && pfnret[i - 1] == 0)
> +      if (first_shndx == 0 && pfnret[i - 1] == 0)
>    first_shndx = i;
> 
>       /* Remember the indexes of existing SHT_SYMTAB_SHNDX sections.  */
> @@ -1191,11 +1193,12 @@ simple_object_elf_copy_lto_debug_section
>      unsigned int sh_link;
>      sh_link = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
>                     shdr, sh_link, Elf_Word);
> -      symtab_indices_shndx[sh_link - 1] = i - 1;
> -      /* Always discard the extended index sections, after
> -         copying it will not be needed.  This way we don't need to
> -         update it and deal with the ordering constraints of
> -         processing the existing symtab and changing the index.  */
> +      symtab_indices_shndx[sh_link - 1] = i;
> +      /* Discard the extended index sections, after copying it will not
> +         be needed, unless we need more than SHN_LORESERVE - 1 sections
> +         in the output.  This way we don't need to update it and deal with
> +         the ordering constraints of processing the existing symtab and
> +         changing the index.  */
>      pfnret[i - 1] = -1;
>    }
>     }
> @@ -1291,16 +1294,25 @@ simple_object_elf_copy_lto_debug_section
>       else
>    sh_map[i] = new_i++;
>     }
> +  first_symtab_indices_shndx = new_i;
> +  symtab_indices_shndx_buf = NULL;
>   if (new_i - 1 >= SHN_LORESERVE)
> -    {
> -      *err = ENOTSUP;
> -      return "Too many copied sections";
> -    }
> -  eow->shdrs = XNEWVEC (unsigned char, shdr_size * (new_i - 1));
> +    for (i = 1; i < shnum; ++i)
> +      if (pfnret[i - 1] == 0 && symtab_indices_shndx[i - 1] != 0)
> +    {
> +      pfnret[symtab_indices_shndx[i - 1] - 1] = 0;
> +      sh_map[symtab_indices_shndx[i - 1]] = new_i++;
> +    }
> +  new_count = new_i;
> +  if (new_count != first_symtab_indices_shndx)
> +    symtab_indices_shndx_buf
> +      = XNEWVEC (unsigned char *, new_count - first_symtab_indices_shndx);
> +  eow->shdrs = XNEWVEC (unsigned char, shdr_size * (new_count - 1));
> 
>   /* Then perform the actual copying.  */
>   new_i = 0;
> -  for (i = 1; i < shnum; ++i)
> +  pass_symtab_indices_shndx = 0;
> +  for (i = 1; i <= shnum; ++i)
>     {
>       unsigned char *shdr;
>       unsigned int sh_name, sh_type;
> @@ -1311,11 +1323,30 @@ simple_object_elf_copy_lto_debug_section
>       off_t flags;
>       unsigned char *buf;
> 
> +      if (i == shnum)
> +    {
> +      if (new_count - 1 < SHN_LORESERVE || pass_symtab_indices_shndx)
> +        break;
> +      i = 0;
> +      pass_symtab_indices_shndx = 1;
> +      continue;
> +    }
> +
>       if (pfnret[i - 1])
>    continue;
> 
> -      new_i++;
>       shdr = shdrs + (i - 1) * shdr_size;
> +      sh_type = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
> +                 shdr, sh_type, Elf_Word);
> +      if (sh_type == SHT_SYMTAB_SHNDX)
> +    {
> +      if (!pass_symtab_indices_shndx)
> +        continue;
> +    }
> +      else if (pass_symtab_indices_shndx)
> +    continue;
> +
> +      new_i++;
>       sh_name = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
>                 shdr, sh_name, Elf_Word);
>       if (sh_name >= name_size)
> @@ -1324,6 +1355,7 @@ simple_object_elf_copy_lto_debug_section
>      XDELETEVEC (names);
>      XDELETEVEC (shdrs);
>      XDELETEVEC (symtab_indices_shndx);
> +      XDELETEVEC (symtab_indices_shndx_buf);
>      return "ELF section name out of range";
>    }
> 
> @@ -1332,16 +1364,14 @@ simple_object_elf_copy_lto_debug_section
>                shdr, sh_offset, Elf_Addr);
>       length = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
>                shdr, sh_size, Elf_Addr);
> -      sh_type = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
> -                 shdr, sh_type, Elf_Word);
> 
> -      dest = simple_object_write_create_section (dobj, pfnname[i - 1],
> -                         0, &errmsg, err);
> +      dest = simple_object_write_create_section (dobj, name, 0, &errmsg, 
> err);
>       if (dest == NULL)
>    {
>      XDELETEVEC (names);
>      XDELETEVEC (shdrs);
>      XDELETEVEC (symtab_indices_shndx);
> +      XDELETEVEC (symtab_indices_shndx_buf);
>      return errmsg;
>    }
> 
> @@ -1363,6 +1393,7 @@ simple_object_elf_copy_lto_debug_section
>      XDELETEVEC (names);
>      XDELETEVEC (shdrs);
>      XDELETEVEC (symtab_indices_shndx);
> +      XDELETEVEC (symtab_indices_shndx_buf);
>      return errmsg;
>    }
> 
> @@ -1378,7 +1409,8 @@ simple_object_elf_copy_lto_debug_section
>      /* Read the section index table if present.  */
>      if (symtab_indices_shndx[i - 1] != 0)
>        {
> -          unsigned char *sidxhdr = shdrs + symtab_indices_shndx[i - 1] * 
> shdr_size;
> +          unsigned char *sidxhdr
> +        = shdrs + (symtab_indices_shndx[i - 1] - 1) * shdr_size;
>          off_t sidxoff = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
>                           sidxhdr, sh_offset, Elf_Addr);
>          size_t sidxsz = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
> @@ -1388,11 +1420,20 @@ simple_object_elf_copy_lto_debug_section
>                   sidxhdr, sh_type, Elf_Word);
>          if (shndx_type != SHT_SYMTAB_SHNDX)
>        return "Wrong section type of a SYMTAB SECTION INDICES section";
> -          shndx_table = (unsigned *)XNEWVEC (char, sidxsz);
> -          simple_object_internal_read (sobj->descriptor,
> -                       sobj->offset + sidxoff,
> -                       (unsigned char *)shndx_table,
> -                       sidxsz, &errmsg, err);
> +          shndx_table = (unsigned *) XNEWVEC (char, sidxsz);
> +          if (!simple_object_internal_read (sobj->descriptor,
> +                        sobj->offset + sidxoff,
> +                        (unsigned char *) shndx_table,
> +                        sidxsz, &errmsg, err))
> +        {
> +          XDELETEVEC (buf);
> +          XDELETEVEC (names);
> +          XDELETEVEC (shdrs);
> +          XDELETEVEC (symtab_indices_shndx);
> +          XDELETEVEC (shndx_table);
> +          XDELETEVEC (symtab_indices_shndx_buf);
> +          return errmsg;
> +        }
>        }
> 
>      /* Find a WEAK HIDDEN symbol which name we will use for removed
> @@ -1407,17 +1448,20 @@ simple_object_elf_copy_lto_debug_section
>          unsigned char *st_other;
>          if (ei_class == ELFCLASS32)
>        {
> -          st_info = &((Elf32_External_Sym *)ent)->st_info;
> -          st_other = &((Elf32_External_Sym *)ent)->st_other;
> +          st_info = &((Elf32_External_Sym *) ent)->st_info;
> +          st_other = &((Elf32_External_Sym *) ent)->st_other;
>        }
>          else
>        {
> -          st_info = &((Elf64_External_Sym *)ent)->st_info;
> -          st_other = &((Elf64_External_Sym *)ent)->st_other;
> +          st_info = &((Elf64_External_Sym *) ent)->st_info;
> +          st_other = &((Elf64_External_Sym *) ent)->st_other;
>        }
>          if (st_shndx == SHN_XINDEX)
> -        st_shndx = type_functions->fetch_Elf_Word
> -            ((unsigned char *)(shndx_table + (ent - buf) / entsize));
> +        {
> +          unsigned char *ndx_ptr
> +            = (unsigned char *) (shndx_table + (ent - buf) / entsize);
> +          st_shndx = type_functions->fetch_Elf_Word (ndx_ptr);
> +        }
> 
>          if (st_shndx != SHN_COMMON
>          && !(st_shndx != SHN_UNDEF
> @@ -1442,19 +1486,26 @@ simple_object_elf_copy_lto_debug_section
>          unsigned char *st_info;
>          unsigned char *st_other;
>          int discard = 0;
> +          unsigned char *ndx_ptr = NULL;
>          if (ei_class == ELFCLASS32)
>        {
> -          st_info = &((Elf32_External_Sym *)ent)->st_info;
> -          st_other = &((Elf32_External_Sym *)ent)->st_other;
> +          st_info = &((Elf32_External_Sym *) ent)->st_info;
> +          st_other = &((Elf32_External_Sym *) ent)->st_other;
>        }
>          else
>        {
> -          st_info = &((Elf64_External_Sym *)ent)->st_info;
> -          st_other = &((Elf64_External_Sym *)ent)->st_other;
> +          st_info = &((Elf64_External_Sym *) ent)->st_info;
> +          st_other = &((Elf64_External_Sym *) ent)->st_other;
>        }
> +          if (shndx_table)
> +        ndx_ptr
> +          = (unsigned char *) (shndx_table + (ent - buf) / entsize);
> +
>          if (st_shndx == SHN_XINDEX)
> -        st_shndx = type_functions->fetch_Elf_Word
> -            ((unsigned char *)(shndx_table + (ent - buf) / entsize));
> +        {
> +          st_shndx = type_functions->fetch_Elf_Word (ndx_ptr);
> +          type_functions->set_Elf_Word (ndx_ptr, SHN_UNDEF);
> +        }
>          /* Eliminate all COMMONs - this includes __gnu_lto_slim
>         which otherwise cause endless LTO plugin invocation.
>         FIXME: remove the condition once we remove emission
> @@ -1488,9 +1539,14 @@ simple_object_elf_copy_lto_debug_section
>             defined in the first prevailing section.  */
>              ELF_SET_FIELD (type_functions, ei_class, Sym,
>                     ent, st_name, Elf_Word, 0);
> +              st_shndx = sh_map[first_shndx];
> +              if (st_shndx >= SHN_LORESERVE)
> +            {
> +              type_functions->set_Elf_Word (ndx_ptr, st_shndx);
> +              st_shndx = SHN_XINDEX;
> +            }
>              ELF_SET_FIELD (type_functions, ei_class, Sym,
> -                     ent, st_shndx, Elf_Half,
> -                     sh_map[first_shndx]);
> +                     ent, st_shndx, Elf_Half, st_shndx);
>            }
>          else
>            {
> @@ -1514,11 +1570,24 @@ simple_object_elf_copy_lto_debug_section
>        }
>          else if (raw_st_shndx < SHN_LORESERVE
>               || raw_st_shndx == SHN_XINDEX)
> -        /* Remap the section reference.  */
> -        ELF_SET_FIELD (type_functions, ei_class, Sym,
> -                   ent, st_shndx, Elf_Half, sh_map[st_shndx]);
> +        {
> +          /* Remap the section reference.  */
> +          st_shndx = sh_map[st_shndx];
> +          if (st_shndx >= SHN_LORESERVE)
> +            {
> +              type_functions->set_Elf_Word (ndx_ptr, st_shndx);
> +              st_shndx = SHN_XINDEX;
> +            }
> +          ELF_SET_FIELD (type_functions, ei_class, Sym,
> +                 ent, st_shndx, Elf_Half, st_shndx);
> +        }
>        }
> -      XDELETEVEC (shndx_table);
> +      if (symtab_indices_shndx_buf)
> +        symtab_indices_shndx_buf[sh_map[symtab_indices_shndx[i - 1]]
> +                     - first_symtab_indices_shndx]
> +          = (unsigned char *) shndx_table;
> +      else
> +        XDELETEVEC (shndx_table);
>    }
>       else if (sh_type == SHT_GROUP)
>    {
> @@ -1538,15 +1607,21 @@ simple_object_elf_copy_lto_debug_section
>      /* Adjust the length.  */
>      length = dst - buf;
>    }
> +      else if (sh_type == SHT_SYMTAB_SHNDX)
> +    {
> +      XDELETEVEC (buf);
> +      buf = symtab_indices_shndx_buf[new_i - first_symtab_indices_shndx];
> +      symtab_indices_shndx_buf[new_i - first_symtab_indices_shndx] = NULL;
> +    }
> 
> -      errmsg = simple_object_write_add_data (dobj, dest,
> -                         buf, length, 1, err);
> +      errmsg = simple_object_write_add_data (dobj, dest, buf, length, 1, 
> err);
>       XDELETEVEC (buf);
>       if (errmsg)
>    {
>      XDELETEVEC (names);
>      XDELETEVEC (shdrs);
>      XDELETEVEC (symtab_indices_shndx);
> +      XDELETEVEC (symtab_indices_shndx_buf);
>      return errmsg;
>    }
> 
> @@ -1586,6 +1661,7 @@ simple_object_elf_copy_lto_debug_section
>   XDELETEVEC (pfnname);
>   XDELETEVEC (symtab_indices_shndx);
>   XDELETEVEC (sh_map);
> +  XDELETEVEC (symtab_indices_shndx_buf);
> 
>   return NULL;
> }
> 
>    Jakub
> 

Reply via email to