diff mbox

[1/2] Early LTO debug, simple-object part

Message ID alpine.LSU.2.20.1705191233300.20726@zhemvz.fhfr.qr
State New
Headers show

Commit Message

Richard Biener May 19, 2017, 10:35 a.m. UTC
This is a repost (unchanged) of the simple-object ELF support for
early LTO debug transfer from IL object to a separate debug-only object 
file.

Bootstrapped and tested on x86_64-unknown-linux-gnu.

Richard.

2017-05-19  Richard Biener  <rguenther@suse.de>

	include/
	* simple-object.h (simple_object_copy_lto_debug_sections): New
	function.

	libiberty/
	* simple-object-common.h (struct simple_object_functions): Add
	copy_lto_debug_sections hook.
	* simple-object.c: Include fcntl.h.
	(handle_lto_debug_sections): New helper function.
	(simple_object_copy_lto_debug_sections): New function copying
	early LTO debug sections to regular debug sections in a new file.
	(simple_object_start_write): Handle NULL segment_name.
	* simple-object-coff.c (simple_object_coff_functions): Adjust
	for not implemented copy_lto_debug_sections hook.
	* simple-object-mach-o.c (simple_object_mach_o_functions): Likewise.
	* simple-object-xcoff.c (simple_object_xcoff_functions): Likewise.
	* simple-object-elf.c (SHT_NULL, SHT_SYMTAB, SHT_RELA, SHT_REL,
	SHT_GROUP): Add various sectopn header types.
	(SHF_EXCLUDE): Add flag.
	(Elf32_External_Sym, Elf64_External_Sym): Add symbol struct.
	(ELF_ST_BIND, ELF_ST_TYPE, ELF_ST_INFO): Add accessors.
	(STT_OBJECT, STT_FUNC, STT_TLS, STT_GNU_IFUNC): Add Symbol types.
	(STV_DEFAULT): Add symbol visibility.
	(SHN_COMMON): Add special section index name.
	(struct simple_object_elf_write): New.
	(simple_object_elf_start_write): Adjust for new private data.
	(simple_object_elf_write_shdr): Pass in values for all fields
	we write.
	(simple_object_elf_write_to_file): Adjust.  Copy from recorded
	section headers if requested.
	(simple_object_elf_release_write): Release private data.
	(simple_object_elf_copy_lto_debug_sections): Copy and rename sections
	as denoted by PFN and all their dependences, symbols and relocations
	to the empty destination file.
	(simple_object_elf_functions): Adjust for copy_lto_debug_sections hook.

Comments

Richard Biener June 7, 2017, 8:20 a.m. UTC | #1
On Fri, 19 May 2017, Richard Biener wrote:

> 
> This is a repost (unchanged) of the simple-object ELF support for
> early LTO debug transfer from IL object to a separate debug-only object 
> file.
> 
> Bootstrapped and tested on x86_64-unknown-linux-gnu.

Ping.

> Richard.
> 
> 2017-05-19  Richard Biener  <rguenther@suse.de>
> 
> 	include/
> 	* simple-object.h (simple_object_copy_lto_debug_sections): New
> 	function.
> 
> 	libiberty/
> 	* simple-object-common.h (struct simple_object_functions): Add
> 	copy_lto_debug_sections hook.
> 	* simple-object.c: Include fcntl.h.
> 	(handle_lto_debug_sections): New helper function.
> 	(simple_object_copy_lto_debug_sections): New function copying
> 	early LTO debug sections to regular debug sections in a new file.
> 	(simple_object_start_write): Handle NULL segment_name.
> 	* simple-object-coff.c (simple_object_coff_functions): Adjust
> 	for not implemented copy_lto_debug_sections hook.
> 	* simple-object-mach-o.c (simple_object_mach_o_functions): Likewise.
> 	* simple-object-xcoff.c (simple_object_xcoff_functions): Likewise.
> 	* simple-object-elf.c (SHT_NULL, SHT_SYMTAB, SHT_RELA, SHT_REL,
> 	SHT_GROUP): Add various sectopn header types.
> 	(SHF_EXCLUDE): Add flag.
> 	(Elf32_External_Sym, Elf64_External_Sym): Add symbol struct.
> 	(ELF_ST_BIND, ELF_ST_TYPE, ELF_ST_INFO): Add accessors.
> 	(STT_OBJECT, STT_FUNC, STT_TLS, STT_GNU_IFUNC): Add Symbol types.
> 	(STV_DEFAULT): Add symbol visibility.
> 	(SHN_COMMON): Add special section index name.
> 	(struct simple_object_elf_write): New.
> 	(simple_object_elf_start_write): Adjust for new private data.
> 	(simple_object_elf_write_shdr): Pass in values for all fields
> 	we write.
> 	(simple_object_elf_write_to_file): Adjust.  Copy from recorded
> 	section headers if requested.
> 	(simple_object_elf_release_write): Release private data.
> 	(simple_object_elf_copy_lto_debug_sections): Copy and rename sections
> 	as denoted by PFN and all their dependences, symbols and relocations
> 	to the empty destination file.
> 	(simple_object_elf_functions): Adjust for copy_lto_debug_sections hook.
> 
> Index: early-lto-debug/include/simple-object.h
> ===================================================================
> --- early-lto-debug.orig/include/simple-object.h	2016-10-19 13:19:58.012326431 +0200
> +++ early-lto-debug/include/simple-object.h	2016-10-20 10:51:49.861722998 +0200
> @@ -197,6 +197,14 @@ simple_object_write_to_file (simple_obje
>  extern void
>  simple_object_release_write (simple_object_write *);
>  
> +/* Copy LTO debug sections from SRC_OBJECT to DEST.
> +   If an error occurs, return the errno value in ERR and an error string.  */
> +
> +extern const char *
> +simple_object_copy_lto_debug_sections (simple_object_read *src_object,
> +				       const char *dest,
> +				       int *err);
> +
>  #ifdef __cplusplus
>  }
>  #endif
> Index: early-lto-debug/libiberty/simple-object-common.h
> ===================================================================
> --- early-lto-debug.orig/libiberty/simple-object-common.h	2016-10-19 13:19:58.012326431 +0200
> +++ early-lto-debug/libiberty/simple-object-common.h	2016-10-20 10:51:49.865723045 +0200
> @@ -141,6 +141,12 @@ struct simple_object_functions
>  
>    /* Release the private data for an simple_object_write.  */
>    void (*release_write) (void *);
> +
> +  /* Copy LTO debug sections.  */
> +  const char *(*copy_lto_debug_sections) (simple_object_read *sobj,
> +					  simple_object_write *dobj,
> +					  int (*pfn) (const char **),
> +					  int *err);
>  };
>  
>  /* The known object file formats.  */
> Index: early-lto-debug/libiberty/simple-object-elf.c
> ===================================================================
> --- early-lto-debug.orig/libiberty/simple-object-elf.c	2016-10-19 13:19:58.012326431 +0200
> +++ early-lto-debug/libiberty/simple-object-elf.c	2016-10-20 10:51:49.865723045 +0200
> @@ -183,8 +183,55 @@ typedef struct {
>  
>  /* Values for sh_type field.  */
>  
> +#define SHT_NULL	0		/* Section header table entry unused */
>  #define SHT_PROGBITS	1		/* Program data */
> +#define SHT_SYMTAB	2		/* Link editing symbol table */
>  #define SHT_STRTAB	3		/* A string table */
> +#define SHT_RELA	4		/* Relocation entries with addends */
> +#define SHT_REL		9		/* Relocation entries, no addends */
> +#define SHT_GROUP	17		/* Section contains a section group */
> +
> +/* Values for sh_flags field.  */
> +
> +#define SHF_EXCLUDE	0x80000000	/* Link editor is to exclude this
> +					   section from executable and
> +					   shared library that it builds
> +					   when those objects are not to be
> +					   further relocated.  */
> +/* Symbol table entry.  */
> +
> +typedef struct
> +{
> +  unsigned char st_name[4];                /* Symbol name (string tbl index) */
> +  unsigned char st_value[4];               /* Symbol value */
> +  unsigned char st_size[4];                /* Symbol size */
> +  unsigned char st_info;                /* Symbol type and binding */
> +  unsigned char st_other;               /* Symbol visibility */
> +  unsigned char st_shndx[2];               /* Section index */
> +} Elf32_External_Sym;
> +
> +typedef struct
> +{
> +  unsigned char st_name[4];                /* Symbol name (string tbl index) */
> +  unsigned char st_info;                /* Symbol type and binding */
> +  unsigned char st_other;               /* Symbol visibility */
> +  unsigned char st_shndx[2];               /* Section index */
> +  unsigned char st_value[8];               /* Symbol value */
> +  unsigned char st_size[8];                /* Symbol size */
> +} Elf64_External_Sym;
> +
> +#define ELF_ST_BIND(val)              (((unsigned char) (val)) >> 4)
> +#define ELF_ST_TYPE(val)              ((val) & 0xf)
> +#define ELF_ST_INFO(bind, type)       (((bind) << 4) + ((type) & 0xf))
> +
> +#define STT_OBJECT	1	/* Symbol is a data object */
> +#define STT_FUNC	2	/* Symbol is a code object */
> +#define STT_TLS		6	/* Thread local data object */
> +#define STT_GNU_IFUNC	10	/* Symbol is an indirect code object */
> +
> +#define STV_DEFAULT	0	/* Visibility is specified by binding type */
> +
> +#define SHN_COMMON	0xFFF2	/* Associated symbol is in common */
>  
>  /* Functions to fetch and store different ELF types, depending on the
>     endianness and size.  */
> @@ -348,6 +395,14 @@ struct simple_object_elf_attributes
>    unsigned int flags;
>  };
>  
> +/* Private data for an simple_object_write.  */
> +
> +struct simple_object_elf_write
> +{
> +  struct simple_object_elf_attributes attrs;
> +  unsigned char *shdrs;
> +};
> +
>  /* See if we have an ELF file.  */
>  
>  static void *
> @@ -675,12 +730,13 @@ simple_object_elf_start_write (void *att
>  {
>    struct simple_object_elf_attributes *attrs =
>      (struct simple_object_elf_attributes *) attributes_data;
> -  struct simple_object_elf_attributes *ret;
> +  struct simple_object_elf_write *ret;
>  
>    /* We're just going to record the attributes, but we need to make a
>       copy because the user may delete them.  */
> -  ret = XNEW (struct simple_object_elf_attributes);
> -  *ret = *attrs;
> +  ret = XNEW (struct simple_object_elf_write);
> +  ret->attrs = *attrs;
> +  ret->shdrs = NULL;
>    return ret;
>  }
>  
> @@ -766,8 +822,11 @@ static int
>  simple_object_elf_write_shdr (simple_object_write *sobj, int descriptor,
>  			      off_t offset, unsigned int sh_name,
>  			      unsigned int sh_type, unsigned int sh_flags,
> +			      off_t sh_addr,
>  			      unsigned int sh_offset, unsigned int sh_size,
> -			      unsigned int sh_link, unsigned int sh_addralign,
> +			      unsigned int sh_link, unsigned int sh_info,
> +			      unsigned int sh_addralign,
> +			      unsigned int sh_entsize,
>  			      const char **errmsg, int *err)
>  {
>    struct simple_object_elf_attributes *attrs =
> @@ -788,12 +847,13 @@ simple_object_elf_write_shdr (simple_obj
>    ELF_SET_FIELD (fns, cl, Shdr, buf, sh_name, Elf_Word, sh_name);
>    ELF_SET_FIELD (fns, cl, Shdr, buf, sh_type, Elf_Word, sh_type);
>    ELF_SET_FIELD (fns, cl, Shdr, buf, sh_flags, Elf_Addr, sh_flags);
> +  ELF_SET_FIELD (fns, cl, Shdr, buf, sh_addr, Elf_Addr, sh_addr);
>    ELF_SET_FIELD (fns, cl, Shdr, buf, sh_offset, Elf_Addr, sh_offset);
>    ELF_SET_FIELD (fns, cl, Shdr, buf, sh_size, Elf_Addr, sh_size);
>    ELF_SET_FIELD (fns, cl, Shdr, buf, sh_link, Elf_Word, sh_link);
> -  /* sh_info left as zero.  */
> +  ELF_SET_FIELD (fns, cl, Shdr, buf, sh_info, Elf_Word, sh_info);
>    ELF_SET_FIELD (fns, cl, Shdr, buf, sh_addralign, Elf_Addr, sh_addralign);
> -  /* sh_entsize left as zero.  */
> +  ELF_SET_FIELD (fns, cl, Shdr, buf, sh_entsize, Elf_Word, sh_entsize);
>  
>    return simple_object_internal_write (descriptor, offset, buf, shdr_size,
>  				       errmsg, err);
> @@ -811,8 +871,9 @@ static const char *
>  simple_object_elf_write_to_file (simple_object_write *sobj, int descriptor,
>  				 int *err)
>  {
> -  struct simple_object_elf_attributes *attrs =
> -    (struct simple_object_elf_attributes *) 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;
>    size_t shdr_size;
> @@ -825,6 +886,7 @@ simple_object_elf_write_to_file (simple_
>    unsigned int first_sh_link;
>    size_t sh_name;
>    unsigned char zero;
> +  unsigned secnum;
>  
>    if (!simple_object_elf_write_ehdr (sobj, descriptor, &errmsg, err))
>      return errmsg;
> @@ -862,21 +924,54 @@ simple_object_elf_write_to_file (simple_
>    else
>      first_sh_link = shnum - 1;
>    if (!simple_object_elf_write_shdr (sobj, descriptor, shdr_offset,
> -				     0, 0, 0, 0, first_sh_size, first_sh_link,
> -				     0, &errmsg, err))
> +				     0, 0, 0, 0, 0, first_sh_size, first_sh_link,
> +				     0, 0, 0, &errmsg, err))
>      return errmsg;
>  
>    shdr_offset += shdr_size;
>  
>    sh_name = 1;
> +  secnum = 0;
>    for (section = sobj->sections; section != NULL; section = section->next)
>      {
>        size_t mask;
>        size_t new_sh_offset;
>        size_t sh_size;
>        struct simple_object_write_section_buffer *buffer;
> +      unsigned int sh_type = SHT_PROGBITS;
> +      unsigned int sh_flags = 0;
> +      off_t sh_addr = 0;
> +      unsigned int sh_link = 0;
> +      unsigned int sh_info = 0;
> +      unsigned int sh_addralign = 1U << section->align;
> +      unsigned int sh_entsize = 0;
> +      if (eow->shdrs)
> +	{
> +	  sh_type = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
> +				     eow->shdrs + secnum * shdr_size,
> +				     sh_type, Elf_Word);
> +	  sh_flags = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
> +				      eow->shdrs + secnum * shdr_size,
> +				      sh_flags, Elf_Addr);
> +	  sh_addr = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
> +				     eow->shdrs + secnum * shdr_size,
> +				     sh_addr, Elf_Addr);
> +	  sh_link = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
> +				     eow->shdrs + secnum * shdr_size,
> +				     sh_link, Elf_Word);
> +	  sh_info = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
> +				     eow->shdrs + secnum * shdr_size,
> +				     sh_info, Elf_Word);
> +	  sh_addralign = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
> +					  eow->shdrs + secnum * shdr_size,
> +					  sh_addralign, Elf_Addr);
> +	  sh_entsize = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
> +					eow->shdrs + secnum * shdr_size,
> +					sh_entsize, Elf_Word);
> +	  secnum++;
> +	}
>  
> -      mask = (1U << section->align) - 1;
> +      mask = sh_addralign - 1;
>        new_sh_offset = sh_offset + mask;
>        new_sh_offset &= ~ mask;
>        while (new_sh_offset > sh_offset)
> @@ -906,8 +1001,10 @@ simple_object_elf_write_to_file (simple_
>  	}
>  
>        if (!simple_object_elf_write_shdr (sobj, descriptor, shdr_offset,
> -					 sh_name, SHT_PROGBITS, 0, sh_offset,
> -					 sh_size, 0, 1U << section->align,
> +					 sh_name, sh_type, sh_flags,
> +					 sh_addr, sh_offset,
> +					 sh_size, sh_link, sh_info,
> +					 sh_addralign, sh_entsize,
>  					 &errmsg, err))
>  	return errmsg;
>  
> @@ -917,9 +1014,9 @@ simple_object_elf_write_to_file (simple_
>      }
>  
>    if (!simple_object_elf_write_shdr (sobj, descriptor, shdr_offset,
> -				     sh_name, SHT_STRTAB, 0, sh_offset,
> -				     sh_name + strlen (".shstrtab") + 1, 0,
> -				     1, &errmsg, err))
> +				     sh_name, SHT_STRTAB, 0, 0, sh_offset,
> +				     sh_name + strlen (".shstrtab") + 1, 0, 0,
> +				     1, 0, &errmsg, err))
>      return errmsg;
>  
>    /* .shstrtab has a leading zero byte.  */
> @@ -954,9 +1051,363 @@ simple_object_elf_write_to_file (simple_
>  static void
>  simple_object_elf_release_write (void *data)
>  {
> +  struct simple_object_elf_write *eow = (struct simple_object_elf_write *) data;
> +  if (eow->shdrs)
> +    XDELETE (eow->shdrs);
>    XDELETE (data);
>  }
>  
> +/* Copy all sections in an ELF file.  */
> +
> +static const char *
> +simple_object_elf_copy_lto_debug_sections (simple_object_read *sobj,
> +					   simple_object_write *dobj,
> +					   int (*pfn) (const char **),
> +					   int *err)
> +{
> +  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;
> +  unsigned char ei_class = eor->ei_class;
> +  size_t shdr_size;
> +  unsigned int shnum;
> +  unsigned char *shdrs;
> +  const char *errmsg;
> +  unsigned char *shstrhdr;
> +  size_t name_size;
> +  off_t shstroff;
> +  unsigned char *names;
> +  unsigned int i;
> +  int *pfnret;
> +  const char **pfnname;
> +
> +  shdr_size = (ei_class == ELFCLASS32
> +	       ? sizeof (Elf32_External_Shdr)
> +	       : sizeof (Elf64_External_Shdr));
> +
> +  /* Read the section headers.  We skip section 0, which is not a
> +     useful section.  */
> +
> +  shnum = eor->shnum;
> +  shdrs = XNEWVEC (unsigned char, shdr_size * (shnum - 1));
> +
> +  if (!simple_object_internal_read (sobj->descriptor,
> +				    sobj->offset + eor->shoff + shdr_size,
> +				    shdrs,
> +				    shdr_size * (shnum - 1),
> +				    &errmsg, err))
> +    {
> +      XDELETEVEC (shdrs);
> +      return errmsg;
> +    }
> +
> +  /* Read the section names.  */
> +
> +  shstrhdr = shdrs + (eor->shstrndx - 1) * shdr_size;
> +  name_size = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
> +			       shstrhdr, sh_size, Elf_Addr);
> +  shstroff = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
> +			      shstrhdr, sh_offset, Elf_Addr);
> +  names = XNEWVEC (unsigned char, name_size);
> +  if (!simple_object_internal_read (sobj->descriptor,
> +				    sobj->offset + shstroff,
> +				    names, name_size, &errmsg, err))
> +    {
> +      XDELETEVEC (names);
> +      XDELETEVEC (shdrs);
> +      return errmsg;
> +    }
> +
> +  eow->shdrs = XNEWVEC (unsigned char, shdr_size * (shnum - 1));
> +  pfnret = XNEWVEC (int, shnum);
> +  pfnname = XNEWVEC (const char *, shnum);
> +
> +  /* First perform the callbacks to know which sections to preserve and
> +     what name to use for those.  */
> +  for (i = 1; i < shnum; ++i)
> +    {
> +      unsigned char *shdr;
> +      unsigned int sh_name;
> +      const char *name;
> +      int ret;
> +
> +      shdr = shdrs + (i - 1) * shdr_size;
> +      sh_name = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
> +				 shdr, sh_name, Elf_Word);
> +      if (sh_name >= name_size)
> +	{
> +	  *err = 0;
> +	  XDELETEVEC (names);
> +	  XDELETEVEC (shdrs);
> +	  return "ELF section name out of range";
> +	}
> +
> +      name = (const char *) names + sh_name;
> +
> +      ret = (*pfn) (&name);
> +      pfnret[i - 1] = ret == 1 ? 0 : -1;
> +      pfnname[i - 1] = name;
> +    }
> +
> +  /* Mark sections as preserved that are required by to be preserved
> +     sections.  */
> +  for (i = 1; i < shnum; ++i)
> +    {
> +      unsigned char *shdr;
> +      unsigned int sh_type, sh_info, sh_link;
> +      off_t offset;
> +      off_t length;
> +
> +      shdr = shdrs + (i - 1) * shdr_size;
> +      sh_type = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
> +				 shdr, sh_type, Elf_Word);
> +      sh_info = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
> +				 shdr, sh_info, Elf_Word);
> +      sh_link = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
> +				 shdr, sh_link, Elf_Word);
> +      if (sh_type == SHT_GROUP)
> +	{
> +	  /* Mark groups containing copied sections.  */
> +	  unsigned entsize = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
> +					      shdr, sh_entsize, Elf_Addr);
> +	  unsigned char *ent, *buf;
> +	  int keep = 0;
> +	  offset = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
> +				    shdr, sh_offset, Elf_Addr);
> +	  length = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
> +				    shdr, sh_size, Elf_Addr);
> +	  buf = XNEWVEC (unsigned char, length);
> +	  if (!simple_object_internal_read (sobj->descriptor,
> +					    sobj->offset + offset, buf,
> +					    (size_t) length, &errmsg, err))
> +	    {
> +	      XDELETEVEC (buf);
> +	      XDELETEVEC (names);
> +	      XDELETEVEC (shdrs);
> +	      return errmsg;
> +	    }
> +	  for (ent = buf + entsize; ent < buf + length; ent += entsize)
> +	    {
> +	      unsigned sec = type_functions->fetch_Elf_Word (ent);
> +	      if (pfnret[sec - 1] == 0)
> +		keep = 1;
> +	    }
> +	  if (keep)
> +	    {
> +	      pfnret[sh_link - 1] = 0;
> +	      pfnret[i - 1] = 0;
> +	    }
> +	}
> +      if (sh_type == SHT_RELA
> +	  || sh_type == SHT_REL)
> +	{
> +	  /* Mark relocation sections and symtab of copied sections.  */
> +	  if (pfnret[sh_info - 1] == 0)
> +	    {
> +	      pfnret[sh_link - 1] = 0;
> +	      pfnret[i - 1] = 0;
> +	    }
> +	}
> +      if (sh_type == SHT_SYMTAB)
> +	{
> +	  /* Mark strings sections of copied symtabs.  */
> +	  if (pfnret[i - 1] == 0)
> +	    pfnret[sh_link - 1] = 0;
> +	}
> +    }
> +
> +  /* Then perform the actual copying.  */
> +  for (i = 1; i < shnum; ++i)
> +    {
> +      unsigned char *shdr;
> +      unsigned int sh_name, sh_type;
> +      const char *name;
> +      off_t offset;
> +      off_t length;
> +      int ret;
> +      const char *errmsg;
> +      simple_object_write_section *dest;
> +      off_t flags;
> +      unsigned char *buf;
> +
> +      shdr = shdrs + (i - 1) * shdr_size;
> +      sh_name = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
> +				 shdr, sh_name, Elf_Word);
> +      if (sh_name >= name_size)
> +	{
> +	  *err = 0;
> +	  XDELETEVEC (names);
> +	  XDELETEVEC (shdrs);
> +	  return "ELF section name out of range";
> +	}
> +
> +      name = (const char *) names + sh_name;
> +      offset = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
> +				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);
> +
> +      ret = pfnret[i - 1];
> +      name = ret == 0 ? pfnname[i - 1] : "";
> +
> +      dest = simple_object_write_create_section (dobj, name, 0, &errmsg, err);
> +      if (dest == NULL)
> +	{
> +	  XDELETEVEC (names);
> +	  XDELETEVEC (shdrs);
> +	  return errmsg;
> +	}
> +
> +      /* Record the SHDR of the source.  */
> +      memcpy (eow->shdrs + (i - 1) * shdr_size, shdr, shdr_size);
> +      shdr = eow->shdrs + (i - 1) * shdr_size;
> +
> +      /* Copy the data.
> +	 ???  This is quite wasteful and ideally would be delayed until
> +	 write_to_file ().  Thus it questions the interfacing
> +	 which eventually should contain destination creation plus
> +	 writing.  */
> +      /* Keep empty sections for sections we should discard.  This avoids
> +         the need to rewrite section indices in symtab and relocation
> +	 sections.  */
> +      if (ret == 0)
> +	{
> +	  buf = XNEWVEC (unsigned char, length);
> +	  if (!simple_object_internal_read (sobj->descriptor,
> +					    sobj->offset + offset, buf,
> +					    (size_t) length, &errmsg, err))
> +	    {
> +	      XDELETEVEC (buf);
> +	      XDELETEVEC (names);
> +	      XDELETEVEC (shdrs);
> +	      return errmsg;
> +	    }
> +
> +	  /* If we are processing .symtab purge __gnu_lto_v1 and
> +	     __gnu_lto_slim symbols from it.  */
> +	  if (sh_type == SHT_SYMTAB)
> +	    {
> +	      unsigned entsize = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
> +						  shdr, sh_entsize, Elf_Addr);
> +	      unsigned strtab = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
> +						 shdr, sh_link, Elf_Word);
> +	      unsigned char *strshdr = shdrs + (strtab - 1) * shdr_size;
> +	      off_t stroff = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
> +					      strshdr, sh_offset, Elf_Addr);
> +	      size_t strsz = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
> +					      strshdr, sh_size, Elf_Addr);
> +	      char *strings = XNEWVEC (char, strsz);
> +	      unsigned char *ent;
> +	      simple_object_internal_read (sobj->descriptor,
> +					   sobj->offset + stroff,
> +					   (unsigned char *)strings,
> +					   strsz, &errmsg, err);
> +	      for (ent = buf; ent < buf + length; ent += entsize)
> +		{
> +		  unsigned st_shndx = ELF_FETCH_FIELD (type_functions, ei_class,
> +						       Sym, ent,
> +						       st_shndx, Elf_Half);
> +		  unsigned char *st_info;
> +		  unsigned char *st_other;
> +		  if (ei_class == ELFCLASS32)
> +		    {
> +		      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;
> +		    }
> +		  /* Eliminate all COMMONs - this includes __gnu_lto_v1
> +		     and __gnu_lto_slim which otherwise cause endless
> +		     LTO plugin invocation.  */
> +		  if (st_shndx == SHN_COMMON)
> +		    /* Setting st_name to "" seems to work to purge
> +		       COMMON symbols (in addition to setting their
> +		       size to zero).  */
> +		    ;
> +		  /* We also need to remove symbols refering to sections
> +		     we'll eventually remove as with fat LTO objects
> +		     we otherwise get duplicate symbols at final link
> +		     (with GNU ld, gold is fine and ignores symbols in
> +		     sections marked as EXCLUDE).  ld/20513  */
> +		  else if (st_shndx != 0
> +			   && st_shndx < shnum
> +			   && pfnret[st_shndx - 1] == -1)
> +		    /* Messing with st_shndx doesn't seem to work very
> +		       well.  Likewise changing the symbol type to
> +		       a section symbol or making it local.
> +		       So just keep with making it unnamed.
> +		       Also make all regular symbols STT_OBJECT and
> +		       have default visibility, otherwise GNU ld warns
> +		       about mismatches for the same `' named symbol.  */
> +		    {
> +		      if (ELF_ST_TYPE (*st_info) == STT_FUNC
> +			  || ELF_ST_TYPE (*st_info) == STT_TLS
> +			  || ELF_ST_TYPE (*st_info) == STT_GNU_IFUNC)
> +			*st_info = ELF_ST_INFO (ELF_ST_BIND (*st_info),
> +						STT_OBJECT);
> +		      *st_other = STV_DEFAULT;
> +		    }
> +		  else
> +		    continue;
> +
> +		  /* For all purged symbols make the symbol unnamed.  */
> +		  ELF_SET_FIELD (type_functions, ei_class, Sym,
> +				 ent, st_name, Elf_Word, 0);
> +
> +		  /* At least set st_value and st_size to zero to not go
> +		     out of bounds.  */
> +		  ELF_SET_FIELD (type_functions, ei_class, Sym,
> +				 ent, st_value, Elf_Addr, 0);
> +		  ELF_SET_FIELD (type_functions, ei_class, Sym,
> +				 ent, st_size, Elf_Word, 0);
> +		}
> +	      XDELETEVEC (strings);
> +	    }
> +
> +	  errmsg = simple_object_write_add_data (dobj, dest, buf, length, 1, err);
> +	  XDELETEVEC (buf);
> +	  if (errmsg)
> +	    {
> +	      XDELETEVEC (names);
> +	      XDELETEVEC (shdrs);
> +	      return errmsg;
> +	    }
> +	}
> +      else
> +	{
> +	  /* For deleted sections mark the section header table entry as
> +	     unused.  That allows the link editor to remove it in a partial
> +	     link.  */
> +	  ELF_SET_FIELD (type_functions, ei_class, Shdr,
> +			 shdr, sh_type, Elf_Addr, SHT_NULL);
> +	}
> +
> +      flags = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
> +			       shdr, sh_flags, Elf_Addr);
> +      if (ret == 0)
> +	flags &= ~SHF_EXCLUDE;
> +      else if (ret == -1)
> +	flags |= SHF_EXCLUDE;
> +      ELF_SET_FIELD (type_functions, ei_class, Shdr,
> +		     shdr, sh_flags, Elf_Addr, flags);
> +    }
> +
> +  XDELETEVEC (names);
> +  XDELETEVEC (shdrs);
> +  XDELETEVEC (pfnret);
> +  XDELETEVEC (pfnname);
> +
> +  return NULL;
> +}
> +
> +
>  /* The ELF functions.  */
>  
>  const struct simple_object_functions simple_object_elf_functions =
> @@ -969,5 +1420,6 @@ const struct simple_object_functions sim
>    simple_object_elf_release_attributes,
>    simple_object_elf_start_write,
>    simple_object_elf_write_to_file,
> -  simple_object_elf_release_write
> +  simple_object_elf_release_write,
> +  simple_object_elf_copy_lto_debug_sections
>  };
> Index: early-lto-debug/libiberty/simple-object.c
> ===================================================================
> --- early-lto-debug.orig/libiberty/simple-object.c	2016-10-19 13:19:58.012326431 +0200
> +++ early-lto-debug/libiberty/simple-object.c	2016-10-20 13:58:11.722714041 +0200
> @@ -22,6 +22,7 @@ Boston, MA 02110-1301, USA.  */
>  #include "simple-object.h"
>  
>  #include <errno.h>
> +#include <fcntl.h>
>  
>  #ifdef HAVE_STDLIB_H
>  #include <stdlib.h>
> @@ -249,6 +250,86 @@ simple_object_find_section (simple_objec
>    return 1;
>  }
>  
> +/* Callback to identify and rename LTO debug sections by name.
> +   Returns 1 if NAME is a LTO debug section, 0 if not.  */
> +
> +static int
> +handle_lto_debug_sections (const char **name)
> +{
> +  /* ???  So we can't use .gnu.lto_ prefixed sections as the assembler
> +     complains about bogus section flags.  Which means we need to arrange
> +     for that to be fixed or .gnu.debuglto_ marked as SHF_EXCLUDE (to make
> +     fat lto object tooling work for the fat part).  */
> +  /* ???  For now this handles both .gnu.lto_ and .gnu.debuglto_ prefixed
> +     sections.  */
> +  /* Copy LTO debug sections and rename them to their non-LTO name.  */
> +  if (strncmp (*name, ".gnu.debuglto_", sizeof (".gnu.debuglto_") - 1) == 0)
> +    {
> +      *name = *name + sizeof (".gnu.debuglto_") - 1;
> +      return 1;
> +    }
> +  else if (strncmp (*name, ".gnu.lto_.debug_", sizeof (".gnu.lto_.debug_") -1) == 0)
> +    {
> +      *name = *name + sizeof (".gnu.lto_") - 1;
> +      return 1;
> +    }
> +  return 0;
> +}
> +
> +/* Copy LTO debug sections.  */
> +
> +const char *
> +simple_object_copy_lto_debug_sections (simple_object_read *sobj,
> +				       const char *dest, int *err)
> +{
> +  const char *errmsg;
> +  simple_object_write *dest_sobj;
> +  simple_object_attributes *attrs;
> +  int outfd;
> +
> +  if (! sobj->functions->copy_lto_debug_sections)
> +    {
> +      *err = EINVAL;
> +      return "simple_object_copy_lto_debug_sections not implemented";
> +    }
> +
> +  attrs = simple_object_fetch_attributes (sobj, &errmsg, err);
> +  if (! attrs)
> +    return errmsg;
> +  dest_sobj = simple_object_start_write (attrs, NULL, &errmsg, err);
> +  simple_object_release_attributes (attrs);
> +  if (! dest_sobj)
> +    return errmsg;
> +
> +  errmsg = sobj->functions->copy_lto_debug_sections (sobj, dest_sobj,
> +						     handle_lto_debug_sections,
> +						     err);
> +  if (errmsg)
> +    {
> +      simple_object_release_write (dest_sobj);
> +      return errmsg;
> +    }
> +
> +  outfd = creat (dest, 00777);
> +  if (outfd == -1)
> +    {
> +      *err = errno;
> +      simple_object_release_write (dest_sobj);
> +      return "open failed";
> +    }
> +
> +  errmsg = simple_object_write_to_file (dest_sobj, outfd, err);
> +  close (outfd);
> +  if (errmsg)
> +    {
> +      simple_object_release_write (dest_sobj);
> +      return errmsg;
> +    }
> +
> +  simple_object_release_write (dest_sobj);
> +  return NULL;
> +}
> +
>  /* Fetch attributes.  */
>  
>  simple_object_attributes *
> @@ -315,7 +396,7 @@ simple_object_start_write (simple_object
>      return NULL;
>    ret = XNEW (simple_object_write);
>    ret->functions = attrs->functions;
> -  ret->segment_name = xstrdup (segment_name);
> +  ret->segment_name = segment_name ? xstrdup (segment_name) : NULL;
>    ret->sections = NULL;
>    ret->last_section = NULL;
>    ret->data = data;
> Index: early-lto-debug/libiberty/simple-object-coff.c
> ===================================================================
> --- early-lto-debug.orig/libiberty/simple-object-coff.c	2016-10-19 13:19:58.012326431 +0200
> +++ early-lto-debug/libiberty/simple-object-coff.c	2016-10-20 10:51:49.881723228 +0200
> @@ -800,5 +800,6 @@ const struct simple_object_functions sim
>    simple_object_coff_release_attributes,
>    simple_object_coff_start_write,
>    simple_object_coff_write_to_file,
> -  simple_object_coff_release_write
> +  simple_object_coff_release_write,
> +  NULL
>  };
> Index: early-lto-debug/libiberty/simple-object-mach-o.c
> ===================================================================
> --- early-lto-debug.orig/libiberty/simple-object-mach-o.c	2016-10-19 13:19:58.012326431 +0200
> +++ early-lto-debug/libiberty/simple-object-mach-o.c	2016-10-20 10:51:49.881723228 +0200
> @@ -1374,5 +1374,6 @@ const struct simple_object_functions sim
>    simple_object_mach_o_release_attributes,
>    simple_object_mach_o_start_write,
>    simple_object_mach_o_write_to_file,
> -  simple_object_mach_o_release_write
> +  simple_object_mach_o_release_write,
> +  NULL
>  };
> Index: early-lto-debug/libiberty/simple-object-xcoff.c
> ===================================================================
> --- early-lto-debug.orig/libiberty/simple-object-xcoff.c	2016-10-19 13:19:58.012326431 +0200
> +++ early-lto-debug/libiberty/simple-object-xcoff.c	2016-10-20 10:51:49.881723228 +0200
> @@ -894,5 +894,6 @@ const struct simple_object_functions sim
>    simple_object_xcoff_release_attributes,
>    simple_object_xcoff_start_write,
>    simple_object_xcoff_write_to_file,
> -  simple_object_xcoff_release_write
> +  simple_object_xcoff_release_write,
> +  NULL
>  };
>
Richard Biener June 20, 2017, 11:15 a.m. UTC | #2
On Wed, 7 Jun 2017, Richard Biener wrote:

> On Fri, 19 May 2017, Richard Biener wrote:
> 
> > 
> > This is a repost (unchanged) of the simple-object ELF support for
> > early LTO debug transfer from IL object to a separate debug-only object 
> > file.
> > 
> > Bootstrapped and tested on x86_64-unknown-linux-gnu.
> 
> Ping.

Ping^2.

> > Richard.
> > 
> > 2017-05-19  Richard Biener  <rguenther@suse.de>
> > 
> > 	include/
> > 	* simple-object.h (simple_object_copy_lto_debug_sections): New
> > 	function.
> > 
> > 	libiberty/
> > 	* simple-object-common.h (struct simple_object_functions): Add
> > 	copy_lto_debug_sections hook.
> > 	* simple-object.c: Include fcntl.h.
> > 	(handle_lto_debug_sections): New helper function.
> > 	(simple_object_copy_lto_debug_sections): New function copying
> > 	early LTO debug sections to regular debug sections in a new file.
> > 	(simple_object_start_write): Handle NULL segment_name.
> > 	* simple-object-coff.c (simple_object_coff_functions): Adjust
> > 	for not implemented copy_lto_debug_sections hook.
> > 	* simple-object-mach-o.c (simple_object_mach_o_functions): Likewise.
> > 	* simple-object-xcoff.c (simple_object_xcoff_functions): Likewise.
> > 	* simple-object-elf.c (SHT_NULL, SHT_SYMTAB, SHT_RELA, SHT_REL,
> > 	SHT_GROUP): Add various sectopn header types.
> > 	(SHF_EXCLUDE): Add flag.
> > 	(Elf32_External_Sym, Elf64_External_Sym): Add symbol struct.
> > 	(ELF_ST_BIND, ELF_ST_TYPE, ELF_ST_INFO): Add accessors.
> > 	(STT_OBJECT, STT_FUNC, STT_TLS, STT_GNU_IFUNC): Add Symbol types.
> > 	(STV_DEFAULT): Add symbol visibility.
> > 	(SHN_COMMON): Add special section index name.
> > 	(struct simple_object_elf_write): New.
> > 	(simple_object_elf_start_write): Adjust for new private data.
> > 	(simple_object_elf_write_shdr): Pass in values for all fields
> > 	we write.
> > 	(simple_object_elf_write_to_file): Adjust.  Copy from recorded
> > 	section headers if requested.
> > 	(simple_object_elf_release_write): Release private data.
> > 	(simple_object_elf_copy_lto_debug_sections): Copy and rename sections
> > 	as denoted by PFN and all their dependences, symbols and relocations
> > 	to the empty destination file.
> > 	(simple_object_elf_functions): Adjust for copy_lto_debug_sections hook.
> > 
> > Index: early-lto-debug/include/simple-object.h
> > ===================================================================
> > --- early-lto-debug.orig/include/simple-object.h	2016-10-19 13:19:58.012326431 +0200
> > +++ early-lto-debug/include/simple-object.h	2016-10-20 10:51:49.861722998 +0200
> > @@ -197,6 +197,14 @@ simple_object_write_to_file (simple_obje
> >  extern void
> >  simple_object_release_write (simple_object_write *);
> >  
> > +/* Copy LTO debug sections from SRC_OBJECT to DEST.
> > +   If an error occurs, return the errno value in ERR and an error string.  */
> > +
> > +extern const char *
> > +simple_object_copy_lto_debug_sections (simple_object_read *src_object,
> > +				       const char *dest,
> > +				       int *err);
> > +
> >  #ifdef __cplusplus
> >  }
> >  #endif
> > Index: early-lto-debug/libiberty/simple-object-common.h
> > ===================================================================
> > --- early-lto-debug.orig/libiberty/simple-object-common.h	2016-10-19 13:19:58.012326431 +0200
> > +++ early-lto-debug/libiberty/simple-object-common.h	2016-10-20 10:51:49.865723045 +0200
> > @@ -141,6 +141,12 @@ struct simple_object_functions
> >  
> >    /* Release the private data for an simple_object_write.  */
> >    void (*release_write) (void *);
> > +
> > +  /* Copy LTO debug sections.  */
> > +  const char *(*copy_lto_debug_sections) (simple_object_read *sobj,
> > +					  simple_object_write *dobj,
> > +					  int (*pfn) (const char **),
> > +					  int *err);
> >  };
> >  
> >  /* The known object file formats.  */
> > Index: early-lto-debug/libiberty/simple-object-elf.c
> > ===================================================================
> > --- early-lto-debug.orig/libiberty/simple-object-elf.c	2016-10-19 13:19:58.012326431 +0200
> > +++ early-lto-debug/libiberty/simple-object-elf.c	2016-10-20 10:51:49.865723045 +0200
> > @@ -183,8 +183,55 @@ typedef struct {
> >  
> >  /* Values for sh_type field.  */
> >  
> > +#define SHT_NULL	0		/* Section header table entry unused */
> >  #define SHT_PROGBITS	1		/* Program data */
> > +#define SHT_SYMTAB	2		/* Link editing symbol table */
> >  #define SHT_STRTAB	3		/* A string table */
> > +#define SHT_RELA	4		/* Relocation entries with addends */
> > +#define SHT_REL		9		/* Relocation entries, no addends */
> > +#define SHT_GROUP	17		/* Section contains a section group */
> > +
> > +/* Values for sh_flags field.  */
> > +
> > +#define SHF_EXCLUDE	0x80000000	/* Link editor is to exclude this
> > +					   section from executable and
> > +					   shared library that it builds
> > +					   when those objects are not to be
> > +					   further relocated.  */
> > +/* Symbol table entry.  */
> > +
> > +typedef struct
> > +{
> > +  unsigned char st_name[4];                /* Symbol name (string tbl index) */
> > +  unsigned char st_value[4];               /* Symbol value */
> > +  unsigned char st_size[4];                /* Symbol size */
> > +  unsigned char st_info;                /* Symbol type and binding */
> > +  unsigned char st_other;               /* Symbol visibility */
> > +  unsigned char st_shndx[2];               /* Section index */
> > +} Elf32_External_Sym;
> > +
> > +typedef struct
> > +{
> > +  unsigned char st_name[4];                /* Symbol name (string tbl index) */
> > +  unsigned char st_info;                /* Symbol type and binding */
> > +  unsigned char st_other;               /* Symbol visibility */
> > +  unsigned char st_shndx[2];               /* Section index */
> > +  unsigned char st_value[8];               /* Symbol value */
> > +  unsigned char st_size[8];                /* Symbol size */
> > +} Elf64_External_Sym;
> > +
> > +#define ELF_ST_BIND(val)              (((unsigned char) (val)) >> 4)
> > +#define ELF_ST_TYPE(val)              ((val) & 0xf)
> > +#define ELF_ST_INFO(bind, type)       (((bind) << 4) + ((type) & 0xf))
> > +
> > +#define STT_OBJECT	1	/* Symbol is a data object */
> > +#define STT_FUNC	2	/* Symbol is a code object */
> > +#define STT_TLS		6	/* Thread local data object */
> > +#define STT_GNU_IFUNC	10	/* Symbol is an indirect code object */
> > +
> > +#define STV_DEFAULT	0	/* Visibility is specified by binding type */
> > +
> > +#define SHN_COMMON	0xFFF2	/* Associated symbol is in common */
> >  
> >  /* Functions to fetch and store different ELF types, depending on the
> >     endianness and size.  */
> > @@ -348,6 +395,14 @@ struct simple_object_elf_attributes
> >    unsigned int flags;
> >  };
> >  
> > +/* Private data for an simple_object_write.  */
> > +
> > +struct simple_object_elf_write
> > +{
> > +  struct simple_object_elf_attributes attrs;
> > +  unsigned char *shdrs;
> > +};
> > +
> >  /* See if we have an ELF file.  */
> >  
> >  static void *
> > @@ -675,12 +730,13 @@ simple_object_elf_start_write (void *att
> >  {
> >    struct simple_object_elf_attributes *attrs =
> >      (struct simple_object_elf_attributes *) attributes_data;
> > -  struct simple_object_elf_attributes *ret;
> > +  struct simple_object_elf_write *ret;
> >  
> >    /* We're just going to record the attributes, but we need to make a
> >       copy because the user may delete them.  */
> > -  ret = XNEW (struct simple_object_elf_attributes);
> > -  *ret = *attrs;
> > +  ret = XNEW (struct simple_object_elf_write);
> > +  ret->attrs = *attrs;
> > +  ret->shdrs = NULL;
> >    return ret;
> >  }
> >  
> > @@ -766,8 +822,11 @@ static int
> >  simple_object_elf_write_shdr (simple_object_write *sobj, int descriptor,
> >  			      off_t offset, unsigned int sh_name,
> >  			      unsigned int sh_type, unsigned int sh_flags,
> > +			      off_t sh_addr,
> >  			      unsigned int sh_offset, unsigned int sh_size,
> > -			      unsigned int sh_link, unsigned int sh_addralign,
> > +			      unsigned int sh_link, unsigned int sh_info,
> > +			      unsigned int sh_addralign,
> > +			      unsigned int sh_entsize,
> >  			      const char **errmsg, int *err)
> >  {
> >    struct simple_object_elf_attributes *attrs =
> > @@ -788,12 +847,13 @@ simple_object_elf_write_shdr (simple_obj
> >    ELF_SET_FIELD (fns, cl, Shdr, buf, sh_name, Elf_Word, sh_name);
> >    ELF_SET_FIELD (fns, cl, Shdr, buf, sh_type, Elf_Word, sh_type);
> >    ELF_SET_FIELD (fns, cl, Shdr, buf, sh_flags, Elf_Addr, sh_flags);
> > +  ELF_SET_FIELD (fns, cl, Shdr, buf, sh_addr, Elf_Addr, sh_addr);
> >    ELF_SET_FIELD (fns, cl, Shdr, buf, sh_offset, Elf_Addr, sh_offset);
> >    ELF_SET_FIELD (fns, cl, Shdr, buf, sh_size, Elf_Addr, sh_size);
> >    ELF_SET_FIELD (fns, cl, Shdr, buf, sh_link, Elf_Word, sh_link);
> > -  /* sh_info left as zero.  */
> > +  ELF_SET_FIELD (fns, cl, Shdr, buf, sh_info, Elf_Word, sh_info);
> >    ELF_SET_FIELD (fns, cl, Shdr, buf, sh_addralign, Elf_Addr, sh_addralign);
> > -  /* sh_entsize left as zero.  */
> > +  ELF_SET_FIELD (fns, cl, Shdr, buf, sh_entsize, Elf_Word, sh_entsize);
> >  
> >    return simple_object_internal_write (descriptor, offset, buf, shdr_size,
> >  				       errmsg, err);
> > @@ -811,8 +871,9 @@ static const char *
> >  simple_object_elf_write_to_file (simple_object_write *sobj, int descriptor,
> >  				 int *err)
> >  {
> > -  struct simple_object_elf_attributes *attrs =
> > -    (struct simple_object_elf_attributes *) 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;
> >    size_t shdr_size;
> > @@ -825,6 +886,7 @@ simple_object_elf_write_to_file (simple_
> >    unsigned int first_sh_link;
> >    size_t sh_name;
> >    unsigned char zero;
> > +  unsigned secnum;
> >  
> >    if (!simple_object_elf_write_ehdr (sobj, descriptor, &errmsg, err))
> >      return errmsg;
> > @@ -862,21 +924,54 @@ simple_object_elf_write_to_file (simple_
> >    else
> >      first_sh_link = shnum - 1;
> >    if (!simple_object_elf_write_shdr (sobj, descriptor, shdr_offset,
> > -				     0, 0, 0, 0, first_sh_size, first_sh_link,
> > -				     0, &errmsg, err))
> > +				     0, 0, 0, 0, 0, first_sh_size, first_sh_link,
> > +				     0, 0, 0, &errmsg, err))
> >      return errmsg;
> >  
> >    shdr_offset += shdr_size;
> >  
> >    sh_name = 1;
> > +  secnum = 0;
> >    for (section = sobj->sections; section != NULL; section = section->next)
> >      {
> >        size_t mask;
> >        size_t new_sh_offset;
> >        size_t sh_size;
> >        struct simple_object_write_section_buffer *buffer;
> > +      unsigned int sh_type = SHT_PROGBITS;
> > +      unsigned int sh_flags = 0;
> > +      off_t sh_addr = 0;
> > +      unsigned int sh_link = 0;
> > +      unsigned int sh_info = 0;
> > +      unsigned int sh_addralign = 1U << section->align;
> > +      unsigned int sh_entsize = 0;
> > +      if (eow->shdrs)
> > +	{
> > +	  sh_type = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
> > +				     eow->shdrs + secnum * shdr_size,
> > +				     sh_type, Elf_Word);
> > +	  sh_flags = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
> > +				      eow->shdrs + secnum * shdr_size,
> > +				      sh_flags, Elf_Addr);
> > +	  sh_addr = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
> > +				     eow->shdrs + secnum * shdr_size,
> > +				     sh_addr, Elf_Addr);
> > +	  sh_link = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
> > +				     eow->shdrs + secnum * shdr_size,
> > +				     sh_link, Elf_Word);
> > +	  sh_info = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
> > +				     eow->shdrs + secnum * shdr_size,
> > +				     sh_info, Elf_Word);
> > +	  sh_addralign = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
> > +					  eow->shdrs + secnum * shdr_size,
> > +					  sh_addralign, Elf_Addr);
> > +	  sh_entsize = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
> > +					eow->shdrs + secnum * shdr_size,
> > +					sh_entsize, Elf_Word);
> > +	  secnum++;
> > +	}
> >  
> > -      mask = (1U << section->align) - 1;
> > +      mask = sh_addralign - 1;
> >        new_sh_offset = sh_offset + mask;
> >        new_sh_offset &= ~ mask;
> >        while (new_sh_offset > sh_offset)
> > @@ -906,8 +1001,10 @@ simple_object_elf_write_to_file (simple_
> >  	}
> >  
> >        if (!simple_object_elf_write_shdr (sobj, descriptor, shdr_offset,
> > -					 sh_name, SHT_PROGBITS, 0, sh_offset,
> > -					 sh_size, 0, 1U << section->align,
> > +					 sh_name, sh_type, sh_flags,
> > +					 sh_addr, sh_offset,
> > +					 sh_size, sh_link, sh_info,
> > +					 sh_addralign, sh_entsize,
> >  					 &errmsg, err))
> >  	return errmsg;
> >  
> > @@ -917,9 +1014,9 @@ simple_object_elf_write_to_file (simple_
> >      }
> >  
> >    if (!simple_object_elf_write_shdr (sobj, descriptor, shdr_offset,
> > -				     sh_name, SHT_STRTAB, 0, sh_offset,
> > -				     sh_name + strlen (".shstrtab") + 1, 0,
> > -				     1, &errmsg, err))
> > +				     sh_name, SHT_STRTAB, 0, 0, sh_offset,
> > +				     sh_name + strlen (".shstrtab") + 1, 0, 0,
> > +				     1, 0, &errmsg, err))
> >      return errmsg;
> >  
> >    /* .shstrtab has a leading zero byte.  */
> > @@ -954,9 +1051,363 @@ simple_object_elf_write_to_file (simple_
> >  static void
> >  simple_object_elf_release_write (void *data)
> >  {
> > +  struct simple_object_elf_write *eow = (struct simple_object_elf_write *) data;
> > +  if (eow->shdrs)
> > +    XDELETE (eow->shdrs);
> >    XDELETE (data);
> >  }
> >  
> > +/* Copy all sections in an ELF file.  */
> > +
> > +static const char *
> > +simple_object_elf_copy_lto_debug_sections (simple_object_read *sobj,
> > +					   simple_object_write *dobj,
> > +					   int (*pfn) (const char **),
> > +					   int *err)
> > +{
> > +  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;
> > +  unsigned char ei_class = eor->ei_class;
> > +  size_t shdr_size;
> > +  unsigned int shnum;
> > +  unsigned char *shdrs;
> > +  const char *errmsg;
> > +  unsigned char *shstrhdr;
> > +  size_t name_size;
> > +  off_t shstroff;
> > +  unsigned char *names;
> > +  unsigned int i;
> > +  int *pfnret;
> > +  const char **pfnname;
> > +
> > +  shdr_size = (ei_class == ELFCLASS32
> > +	       ? sizeof (Elf32_External_Shdr)
> > +	       : sizeof (Elf64_External_Shdr));
> > +
> > +  /* Read the section headers.  We skip section 0, which is not a
> > +     useful section.  */
> > +
> > +  shnum = eor->shnum;
> > +  shdrs = XNEWVEC (unsigned char, shdr_size * (shnum - 1));
> > +
> > +  if (!simple_object_internal_read (sobj->descriptor,
> > +				    sobj->offset + eor->shoff + shdr_size,
> > +				    shdrs,
> > +				    shdr_size * (shnum - 1),
> > +				    &errmsg, err))
> > +    {
> > +      XDELETEVEC (shdrs);
> > +      return errmsg;
> > +    }
> > +
> > +  /* Read the section names.  */
> > +
> > +  shstrhdr = shdrs + (eor->shstrndx - 1) * shdr_size;
> > +  name_size = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
> > +			       shstrhdr, sh_size, Elf_Addr);
> > +  shstroff = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
> > +			      shstrhdr, sh_offset, Elf_Addr);
> > +  names = XNEWVEC (unsigned char, name_size);
> > +  if (!simple_object_internal_read (sobj->descriptor,
> > +				    sobj->offset + shstroff,
> > +				    names, name_size, &errmsg, err))
> > +    {
> > +      XDELETEVEC (names);
> > +      XDELETEVEC (shdrs);
> > +      return errmsg;
> > +    }
> > +
> > +  eow->shdrs = XNEWVEC (unsigned char, shdr_size * (shnum - 1));
> > +  pfnret = XNEWVEC (int, shnum);
> > +  pfnname = XNEWVEC (const char *, shnum);
> > +
> > +  /* First perform the callbacks to know which sections to preserve and
> > +     what name to use for those.  */
> > +  for (i = 1; i < shnum; ++i)
> > +    {
> > +      unsigned char *shdr;
> > +      unsigned int sh_name;
> > +      const char *name;
> > +      int ret;
> > +
> > +      shdr = shdrs + (i - 1) * shdr_size;
> > +      sh_name = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
> > +				 shdr, sh_name, Elf_Word);
> > +      if (sh_name >= name_size)
> > +	{
> > +	  *err = 0;
> > +	  XDELETEVEC (names);
> > +	  XDELETEVEC (shdrs);
> > +	  return "ELF section name out of range";
> > +	}
> > +
> > +      name = (const char *) names + sh_name;
> > +
> > +      ret = (*pfn) (&name);
> > +      pfnret[i - 1] = ret == 1 ? 0 : -1;
> > +      pfnname[i - 1] = name;
> > +    }
> > +
> > +  /* Mark sections as preserved that are required by to be preserved
> > +     sections.  */
> > +  for (i = 1; i < shnum; ++i)
> > +    {
> > +      unsigned char *shdr;
> > +      unsigned int sh_type, sh_info, sh_link;
> > +      off_t offset;
> > +      off_t length;
> > +
> > +      shdr = shdrs + (i - 1) * shdr_size;
> > +      sh_type = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
> > +				 shdr, sh_type, Elf_Word);
> > +      sh_info = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
> > +				 shdr, sh_info, Elf_Word);
> > +      sh_link = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
> > +				 shdr, sh_link, Elf_Word);
> > +      if (sh_type == SHT_GROUP)
> > +	{
> > +	  /* Mark groups containing copied sections.  */
> > +	  unsigned entsize = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
> > +					      shdr, sh_entsize, Elf_Addr);
> > +	  unsigned char *ent, *buf;
> > +	  int keep = 0;
> > +	  offset = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
> > +				    shdr, sh_offset, Elf_Addr);
> > +	  length = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
> > +				    shdr, sh_size, Elf_Addr);
> > +	  buf = XNEWVEC (unsigned char, length);
> > +	  if (!simple_object_internal_read (sobj->descriptor,
> > +					    sobj->offset + offset, buf,
> > +					    (size_t) length, &errmsg, err))
> > +	    {
> > +	      XDELETEVEC (buf);
> > +	      XDELETEVEC (names);
> > +	      XDELETEVEC (shdrs);
> > +	      return errmsg;
> > +	    }
> > +	  for (ent = buf + entsize; ent < buf + length; ent += entsize)
> > +	    {
> > +	      unsigned sec = type_functions->fetch_Elf_Word (ent);
> > +	      if (pfnret[sec - 1] == 0)
> > +		keep = 1;
> > +	    }
> > +	  if (keep)
> > +	    {
> > +	      pfnret[sh_link - 1] = 0;
> > +	      pfnret[i - 1] = 0;
> > +	    }
> > +	}
> > +      if (sh_type == SHT_RELA
> > +	  || sh_type == SHT_REL)
> > +	{
> > +	  /* Mark relocation sections and symtab of copied sections.  */
> > +	  if (pfnret[sh_info - 1] == 0)
> > +	    {
> > +	      pfnret[sh_link - 1] = 0;
> > +	      pfnret[i - 1] = 0;
> > +	    }
> > +	}
> > +      if (sh_type == SHT_SYMTAB)
> > +	{
> > +	  /* Mark strings sections of copied symtabs.  */
> > +	  if (pfnret[i - 1] == 0)
> > +	    pfnret[sh_link - 1] = 0;
> > +	}
> > +    }
> > +
> > +  /* Then perform the actual copying.  */
> > +  for (i = 1; i < shnum; ++i)
> > +    {
> > +      unsigned char *shdr;
> > +      unsigned int sh_name, sh_type;
> > +      const char *name;
> > +      off_t offset;
> > +      off_t length;
> > +      int ret;
> > +      const char *errmsg;
> > +      simple_object_write_section *dest;
> > +      off_t flags;
> > +      unsigned char *buf;
> > +
> > +      shdr = shdrs + (i - 1) * shdr_size;
> > +      sh_name = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
> > +				 shdr, sh_name, Elf_Word);
> > +      if (sh_name >= name_size)
> > +	{
> > +	  *err = 0;
> > +	  XDELETEVEC (names);
> > +	  XDELETEVEC (shdrs);
> > +	  return "ELF section name out of range";
> > +	}
> > +
> > +      name = (const char *) names + sh_name;
> > +      offset = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
> > +				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);
> > +
> > +      ret = pfnret[i - 1];
> > +      name = ret == 0 ? pfnname[i - 1] : "";
> > +
> > +      dest = simple_object_write_create_section (dobj, name, 0, &errmsg, err);
> > +      if (dest == NULL)
> > +	{
> > +	  XDELETEVEC (names);
> > +	  XDELETEVEC (shdrs);
> > +	  return errmsg;
> > +	}
> > +
> > +      /* Record the SHDR of the source.  */
> > +      memcpy (eow->shdrs + (i - 1) * shdr_size, shdr, shdr_size);
> > +      shdr = eow->shdrs + (i - 1) * shdr_size;
> > +
> > +      /* Copy the data.
> > +	 ???  This is quite wasteful and ideally would be delayed until
> > +	 write_to_file ().  Thus it questions the interfacing
> > +	 which eventually should contain destination creation plus
> > +	 writing.  */
> > +      /* Keep empty sections for sections we should discard.  This avoids
> > +         the need to rewrite section indices in symtab and relocation
> > +	 sections.  */
> > +      if (ret == 0)
> > +	{
> > +	  buf = XNEWVEC (unsigned char, length);
> > +	  if (!simple_object_internal_read (sobj->descriptor,
> > +					    sobj->offset + offset, buf,
> > +					    (size_t) length, &errmsg, err))
> > +	    {
> > +	      XDELETEVEC (buf);
> > +	      XDELETEVEC (names);
> > +	      XDELETEVEC (shdrs);
> > +	      return errmsg;
> > +	    }
> > +
> > +	  /* If we are processing .symtab purge __gnu_lto_v1 and
> > +	     __gnu_lto_slim symbols from it.  */
> > +	  if (sh_type == SHT_SYMTAB)
> > +	    {
> > +	      unsigned entsize = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
> > +						  shdr, sh_entsize, Elf_Addr);
> > +	      unsigned strtab = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
> > +						 shdr, sh_link, Elf_Word);
> > +	      unsigned char *strshdr = shdrs + (strtab - 1) * shdr_size;
> > +	      off_t stroff = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
> > +					      strshdr, sh_offset, Elf_Addr);
> > +	      size_t strsz = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
> > +					      strshdr, sh_size, Elf_Addr);
> > +	      char *strings = XNEWVEC (char, strsz);
> > +	      unsigned char *ent;
> > +	      simple_object_internal_read (sobj->descriptor,
> > +					   sobj->offset + stroff,
> > +					   (unsigned char *)strings,
> > +					   strsz, &errmsg, err);
> > +	      for (ent = buf; ent < buf + length; ent += entsize)
> > +		{
> > +		  unsigned st_shndx = ELF_FETCH_FIELD (type_functions, ei_class,
> > +						       Sym, ent,
> > +						       st_shndx, Elf_Half);
> > +		  unsigned char *st_info;
> > +		  unsigned char *st_other;
> > +		  if (ei_class == ELFCLASS32)
> > +		    {
> > +		      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;
> > +		    }
> > +		  /* Eliminate all COMMONs - this includes __gnu_lto_v1
> > +		     and __gnu_lto_slim which otherwise cause endless
> > +		     LTO plugin invocation.  */
> > +		  if (st_shndx == SHN_COMMON)
> > +		    /* Setting st_name to "" seems to work to purge
> > +		       COMMON symbols (in addition to setting their
> > +		       size to zero).  */
> > +		    ;
> > +		  /* We also need to remove symbols refering to sections
> > +		     we'll eventually remove as with fat LTO objects
> > +		     we otherwise get duplicate symbols at final link
> > +		     (with GNU ld, gold is fine and ignores symbols in
> > +		     sections marked as EXCLUDE).  ld/20513  */
> > +		  else if (st_shndx != 0
> > +			   && st_shndx < shnum
> > +			   && pfnret[st_shndx - 1] == -1)
> > +		    /* Messing with st_shndx doesn't seem to work very
> > +		       well.  Likewise changing the symbol type to
> > +		       a section symbol or making it local.
> > +		       So just keep with making it unnamed.
> > +		       Also make all regular symbols STT_OBJECT and
> > +		       have default visibility, otherwise GNU ld warns
> > +		       about mismatches for the same `' named symbol.  */
> > +		    {
> > +		      if (ELF_ST_TYPE (*st_info) == STT_FUNC
> > +			  || ELF_ST_TYPE (*st_info) == STT_TLS
> > +			  || ELF_ST_TYPE (*st_info) == STT_GNU_IFUNC)
> > +			*st_info = ELF_ST_INFO (ELF_ST_BIND (*st_info),
> > +						STT_OBJECT);
> > +		      *st_other = STV_DEFAULT;
> > +		    }
> > +		  else
> > +		    continue;
> > +
> > +		  /* For all purged symbols make the symbol unnamed.  */
> > +		  ELF_SET_FIELD (type_functions, ei_class, Sym,
> > +				 ent, st_name, Elf_Word, 0);
> > +
> > +		  /* At least set st_value and st_size to zero to not go
> > +		     out of bounds.  */
> > +		  ELF_SET_FIELD (type_functions, ei_class, Sym,
> > +				 ent, st_value, Elf_Addr, 0);
> > +		  ELF_SET_FIELD (type_functions, ei_class, Sym,
> > +				 ent, st_size, Elf_Word, 0);
> > +		}
> > +	      XDELETEVEC (strings);
> > +	    }
> > +
> > +	  errmsg = simple_object_write_add_data (dobj, dest, buf, length, 1, err);
> > +	  XDELETEVEC (buf);
> > +	  if (errmsg)
> > +	    {
> > +	      XDELETEVEC (names);
> > +	      XDELETEVEC (shdrs);
> > +	      return errmsg;
> > +	    }
> > +	}
> > +      else
> > +	{
> > +	  /* For deleted sections mark the section header table entry as
> > +	     unused.  That allows the link editor to remove it in a partial
> > +	     link.  */
> > +	  ELF_SET_FIELD (type_functions, ei_class, Shdr,
> > +			 shdr, sh_type, Elf_Addr, SHT_NULL);
> > +	}
> > +
> > +      flags = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
> > +			       shdr, sh_flags, Elf_Addr);
> > +      if (ret == 0)
> > +	flags &= ~SHF_EXCLUDE;
> > +      else if (ret == -1)
> > +	flags |= SHF_EXCLUDE;
> > +      ELF_SET_FIELD (type_functions, ei_class, Shdr,
> > +		     shdr, sh_flags, Elf_Addr, flags);
> > +    }
> > +
> > +  XDELETEVEC (names);
> > +  XDELETEVEC (shdrs);
> > +  XDELETEVEC (pfnret);
> > +  XDELETEVEC (pfnname);
> > +
> > +  return NULL;
> > +}
> > +
> > +
> >  /* The ELF functions.  */
> >  
> >  const struct simple_object_functions simple_object_elf_functions =
> > @@ -969,5 +1420,6 @@ const struct simple_object_functions sim
> >    simple_object_elf_release_attributes,
> >    simple_object_elf_start_write,
> >    simple_object_elf_write_to_file,
> > -  simple_object_elf_release_write
> > +  simple_object_elf_release_write,
> > +  simple_object_elf_copy_lto_debug_sections
> >  };
> > Index: early-lto-debug/libiberty/simple-object.c
> > ===================================================================
> > --- early-lto-debug.orig/libiberty/simple-object.c	2016-10-19 13:19:58.012326431 +0200
> > +++ early-lto-debug/libiberty/simple-object.c	2016-10-20 13:58:11.722714041 +0200
> > @@ -22,6 +22,7 @@ Boston, MA 02110-1301, USA.  */
> >  #include "simple-object.h"
> >  
> >  #include <errno.h>
> > +#include <fcntl.h>
> >  
> >  #ifdef HAVE_STDLIB_H
> >  #include <stdlib.h>
> > @@ -249,6 +250,86 @@ simple_object_find_section (simple_objec
> >    return 1;
> >  }
> >  
> > +/* Callback to identify and rename LTO debug sections by name.
> > +   Returns 1 if NAME is a LTO debug section, 0 if not.  */
> > +
> > +static int
> > +handle_lto_debug_sections (const char **name)
> > +{
> > +  /* ???  So we can't use .gnu.lto_ prefixed sections as the assembler
> > +     complains about bogus section flags.  Which means we need to arrange
> > +     for that to be fixed or .gnu.debuglto_ marked as SHF_EXCLUDE (to make
> > +     fat lto object tooling work for the fat part).  */
> > +  /* ???  For now this handles both .gnu.lto_ and .gnu.debuglto_ prefixed
> > +     sections.  */
> > +  /* Copy LTO debug sections and rename them to their non-LTO name.  */
> > +  if (strncmp (*name, ".gnu.debuglto_", sizeof (".gnu.debuglto_") - 1) == 0)
> > +    {
> > +      *name = *name + sizeof (".gnu.debuglto_") - 1;
> > +      return 1;
> > +    }
> > +  else if (strncmp (*name, ".gnu.lto_.debug_", sizeof (".gnu.lto_.debug_") -1) == 0)
> > +    {
> > +      *name = *name + sizeof (".gnu.lto_") - 1;
> > +      return 1;
> > +    }
> > +  return 0;
> > +}
> > +
> > +/* Copy LTO debug sections.  */
> > +
> > +const char *
> > +simple_object_copy_lto_debug_sections (simple_object_read *sobj,
> > +				       const char *dest, int *err)
> > +{
> > +  const char *errmsg;
> > +  simple_object_write *dest_sobj;
> > +  simple_object_attributes *attrs;
> > +  int outfd;
> > +
> > +  if (! sobj->functions->copy_lto_debug_sections)
> > +    {
> > +      *err = EINVAL;
> > +      return "simple_object_copy_lto_debug_sections not implemented";
> > +    }
> > +
> > +  attrs = simple_object_fetch_attributes (sobj, &errmsg, err);
> > +  if (! attrs)
> > +    return errmsg;
> > +  dest_sobj = simple_object_start_write (attrs, NULL, &errmsg, err);
> > +  simple_object_release_attributes (attrs);
> > +  if (! dest_sobj)
> > +    return errmsg;
> > +
> > +  errmsg = sobj->functions->copy_lto_debug_sections (sobj, dest_sobj,
> > +						     handle_lto_debug_sections,
> > +						     err);
> > +  if (errmsg)
> > +    {
> > +      simple_object_release_write (dest_sobj);
> > +      return errmsg;
> > +    }
> > +
> > +  outfd = creat (dest, 00777);
> > +  if (outfd == -1)
> > +    {
> > +      *err = errno;
> > +      simple_object_release_write (dest_sobj);
> > +      return "open failed";
> > +    }
> > +
> > +  errmsg = simple_object_write_to_file (dest_sobj, outfd, err);
> > +  close (outfd);
> > +  if (errmsg)
> > +    {
> > +      simple_object_release_write (dest_sobj);
> > +      return errmsg;
> > +    }
> > +
> > +  simple_object_release_write (dest_sobj);
> > +  return NULL;
> > +}
> > +
> >  /* Fetch attributes.  */
> >  
> >  simple_object_attributes *
> > @@ -315,7 +396,7 @@ simple_object_start_write (simple_object
> >      return NULL;
> >    ret = XNEW (simple_object_write);
> >    ret->functions = attrs->functions;
> > -  ret->segment_name = xstrdup (segment_name);
> > +  ret->segment_name = segment_name ? xstrdup (segment_name) : NULL;
> >    ret->sections = NULL;
> >    ret->last_section = NULL;
> >    ret->data = data;
> > Index: early-lto-debug/libiberty/simple-object-coff.c
> > ===================================================================
> > --- early-lto-debug.orig/libiberty/simple-object-coff.c	2016-10-19 13:19:58.012326431 +0200
> > +++ early-lto-debug/libiberty/simple-object-coff.c	2016-10-20 10:51:49.881723228 +0200
> > @@ -800,5 +800,6 @@ const struct simple_object_functions sim
> >    simple_object_coff_release_attributes,
> >    simple_object_coff_start_write,
> >    simple_object_coff_write_to_file,
> > -  simple_object_coff_release_write
> > +  simple_object_coff_release_write,
> > +  NULL
> >  };
> > Index: early-lto-debug/libiberty/simple-object-mach-o.c
> > ===================================================================
> > --- early-lto-debug.orig/libiberty/simple-object-mach-o.c	2016-10-19 13:19:58.012326431 +0200
> > +++ early-lto-debug/libiberty/simple-object-mach-o.c	2016-10-20 10:51:49.881723228 +0200
> > @@ -1374,5 +1374,6 @@ const struct simple_object_functions sim
> >    simple_object_mach_o_release_attributes,
> >    simple_object_mach_o_start_write,
> >    simple_object_mach_o_write_to_file,
> > -  simple_object_mach_o_release_write
> > +  simple_object_mach_o_release_write,
> > +  NULL
> >  };
> > Index: early-lto-debug/libiberty/simple-object-xcoff.c
> > ===================================================================
> > --- early-lto-debug.orig/libiberty/simple-object-xcoff.c	2016-10-19 13:19:58.012326431 +0200
> > +++ early-lto-debug/libiberty/simple-object-xcoff.c	2016-10-20 10:51:49.881723228 +0200
> > @@ -894,5 +894,6 @@ const struct simple_object_functions sim
> >    simple_object_xcoff_release_attributes,
> >    simple_object_xcoff_start_write,
> >    simple_object_xcoff_write_to_file,
> > -  simple_object_xcoff_release_write
> > +  simple_object_xcoff_release_write,
> > +  NULL
> >  };
> > 
> 
>
Richard Biener July 4, 2017, 11:09 a.m. UTC | #3
On Tue, 20 Jun 2017, Richard Biener wrote:

> On Wed, 7 Jun 2017, Richard Biener wrote:
> 
> > On Fri, 19 May 2017, Richard Biener wrote:
> > 
> > > 
> > > This is a repost (unchanged) of the simple-object ELF support for
> > > early LTO debug transfer from IL object to a separate debug-only object 
> > > file.
> > > 
> > > Bootstrapped and tested on x86_64-unknown-linux-gnu.
> > 
> > Ping.
> 
> Ping^2.

Ping^3.

> > > Richard.
> > > 
> > > 2017-05-19  Richard Biener  <rguenther@suse.de>
> > > 
> > > 	include/
> > > 	* simple-object.h (simple_object_copy_lto_debug_sections): New
> > > 	function.
> > > 
> > > 	libiberty/
> > > 	* simple-object-common.h (struct simple_object_functions): Add
> > > 	copy_lto_debug_sections hook.
> > > 	* simple-object.c: Include fcntl.h.
> > > 	(handle_lto_debug_sections): New helper function.
> > > 	(simple_object_copy_lto_debug_sections): New function copying
> > > 	early LTO debug sections to regular debug sections in a new file.
> > > 	(simple_object_start_write): Handle NULL segment_name.
> > > 	* simple-object-coff.c (simple_object_coff_functions): Adjust
> > > 	for not implemented copy_lto_debug_sections hook.
> > > 	* simple-object-mach-o.c (simple_object_mach_o_functions): Likewise.
> > > 	* simple-object-xcoff.c (simple_object_xcoff_functions): Likewise.
> > > 	* simple-object-elf.c (SHT_NULL, SHT_SYMTAB, SHT_RELA, SHT_REL,
> > > 	SHT_GROUP): Add various sectopn header types.
> > > 	(SHF_EXCLUDE): Add flag.
> > > 	(Elf32_External_Sym, Elf64_External_Sym): Add symbol struct.
> > > 	(ELF_ST_BIND, ELF_ST_TYPE, ELF_ST_INFO): Add accessors.
> > > 	(STT_OBJECT, STT_FUNC, STT_TLS, STT_GNU_IFUNC): Add Symbol types.
> > > 	(STV_DEFAULT): Add symbol visibility.
> > > 	(SHN_COMMON): Add special section index name.
> > > 	(struct simple_object_elf_write): New.
> > > 	(simple_object_elf_start_write): Adjust for new private data.
> > > 	(simple_object_elf_write_shdr): Pass in values for all fields
> > > 	we write.
> > > 	(simple_object_elf_write_to_file): Adjust.  Copy from recorded
> > > 	section headers if requested.
> > > 	(simple_object_elf_release_write): Release private data.
> > > 	(simple_object_elf_copy_lto_debug_sections): Copy and rename sections
> > > 	as denoted by PFN and all their dependences, symbols and relocations
> > > 	to the empty destination file.
> > > 	(simple_object_elf_functions): Adjust for copy_lto_debug_sections hook.
> > > 
> > > Index: early-lto-debug/include/simple-object.h
> > > ===================================================================
> > > --- early-lto-debug.orig/include/simple-object.h	2016-10-19 13:19:58.012326431 +0200
> > > +++ early-lto-debug/include/simple-object.h	2016-10-20 10:51:49.861722998 +0200
> > > @@ -197,6 +197,14 @@ simple_object_write_to_file (simple_obje
> > >  extern void
> > >  simple_object_release_write (simple_object_write *);
> > >  
> > > +/* Copy LTO debug sections from SRC_OBJECT to DEST.
> > > +   If an error occurs, return the errno value in ERR and an error string.  */
> > > +
> > > +extern const char *
> > > +simple_object_copy_lto_debug_sections (simple_object_read *src_object,
> > > +				       const char *dest,
> > > +				       int *err);
> > > +
> > >  #ifdef __cplusplus
> > >  }
> > >  #endif
> > > Index: early-lto-debug/libiberty/simple-object-common.h
> > > ===================================================================
> > > --- early-lto-debug.orig/libiberty/simple-object-common.h	2016-10-19 13:19:58.012326431 +0200
> > > +++ early-lto-debug/libiberty/simple-object-common.h	2016-10-20 10:51:49.865723045 +0200
> > > @@ -141,6 +141,12 @@ struct simple_object_functions
> > >  
> > >    /* Release the private data for an simple_object_write.  */
> > >    void (*release_write) (void *);
> > > +
> > > +  /* Copy LTO debug sections.  */
> > > +  const char *(*copy_lto_debug_sections) (simple_object_read *sobj,
> > > +					  simple_object_write *dobj,
> > > +					  int (*pfn) (const char **),
> > > +					  int *err);
> > >  };
> > >  
> > >  /* The known object file formats.  */
> > > Index: early-lto-debug/libiberty/simple-object-elf.c
> > > ===================================================================
> > > --- early-lto-debug.orig/libiberty/simple-object-elf.c	2016-10-19 13:19:58.012326431 +0200
> > > +++ early-lto-debug/libiberty/simple-object-elf.c	2016-10-20 10:51:49.865723045 +0200
> > > @@ -183,8 +183,55 @@ typedef struct {
> > >  
> > >  /* Values for sh_type field.  */
> > >  
> > > +#define SHT_NULL	0		/* Section header table entry unused */
> > >  #define SHT_PROGBITS	1		/* Program data */
> > > +#define SHT_SYMTAB	2		/* Link editing symbol table */
> > >  #define SHT_STRTAB	3		/* A string table */
> > > +#define SHT_RELA	4		/* Relocation entries with addends */
> > > +#define SHT_REL		9		/* Relocation entries, no addends */
> > > +#define SHT_GROUP	17		/* Section contains a section group */
> > > +
> > > +/* Values for sh_flags field.  */
> > > +
> > > +#define SHF_EXCLUDE	0x80000000	/* Link editor is to exclude this
> > > +					   section from executable and
> > > +					   shared library that it builds
> > > +					   when those objects are not to be
> > > +					   further relocated.  */
> > > +/* Symbol table entry.  */
> > > +
> > > +typedef struct
> > > +{
> > > +  unsigned char st_name[4];                /* Symbol name (string tbl index) */
> > > +  unsigned char st_value[4];               /* Symbol value */
> > > +  unsigned char st_size[4];                /* Symbol size */
> > > +  unsigned char st_info;                /* Symbol type and binding */
> > > +  unsigned char st_other;               /* Symbol visibility */
> > > +  unsigned char st_shndx[2];               /* Section index */
> > > +} Elf32_External_Sym;
> > > +
> > > +typedef struct
> > > +{
> > > +  unsigned char st_name[4];                /* Symbol name (string tbl index) */
> > > +  unsigned char st_info;                /* Symbol type and binding */
> > > +  unsigned char st_other;               /* Symbol visibility */
> > > +  unsigned char st_shndx[2];               /* Section index */
> > > +  unsigned char st_value[8];               /* Symbol value */
> > > +  unsigned char st_size[8];                /* Symbol size */
> > > +} Elf64_External_Sym;
> > > +
> > > +#define ELF_ST_BIND(val)              (((unsigned char) (val)) >> 4)
> > > +#define ELF_ST_TYPE(val)              ((val) & 0xf)
> > > +#define ELF_ST_INFO(bind, type)       (((bind) << 4) + ((type) & 0xf))
> > > +
> > > +#define STT_OBJECT	1	/* Symbol is a data object */
> > > +#define STT_FUNC	2	/* Symbol is a code object */
> > > +#define STT_TLS		6	/* Thread local data object */
> > > +#define STT_GNU_IFUNC	10	/* Symbol is an indirect code object */
> > > +
> > > +#define STV_DEFAULT	0	/* Visibility is specified by binding type */
> > > +
> > > +#define SHN_COMMON	0xFFF2	/* Associated symbol is in common */
> > >  
> > >  /* Functions to fetch and store different ELF types, depending on the
> > >     endianness and size.  */
> > > @@ -348,6 +395,14 @@ struct simple_object_elf_attributes
> > >    unsigned int flags;
> > >  };
> > >  
> > > +/* Private data for an simple_object_write.  */
> > > +
> > > +struct simple_object_elf_write
> > > +{
> > > +  struct simple_object_elf_attributes attrs;
> > > +  unsigned char *shdrs;
> > > +};
> > > +
> > >  /* See if we have an ELF file.  */
> > >  
> > >  static void *
> > > @@ -675,12 +730,13 @@ simple_object_elf_start_write (void *att
> > >  {
> > >    struct simple_object_elf_attributes *attrs =
> > >      (struct simple_object_elf_attributes *) attributes_data;
> > > -  struct simple_object_elf_attributes *ret;
> > > +  struct simple_object_elf_write *ret;
> > >  
> > >    /* We're just going to record the attributes, but we need to make a
> > >       copy because the user may delete them.  */
> > > -  ret = XNEW (struct simple_object_elf_attributes);
> > > -  *ret = *attrs;
> > > +  ret = XNEW (struct simple_object_elf_write);
> > > +  ret->attrs = *attrs;
> > > +  ret->shdrs = NULL;
> > >    return ret;
> > >  }
> > >  
> > > @@ -766,8 +822,11 @@ static int
> > >  simple_object_elf_write_shdr (simple_object_write *sobj, int descriptor,
> > >  			      off_t offset, unsigned int sh_name,
> > >  			      unsigned int sh_type, unsigned int sh_flags,
> > > +			      off_t sh_addr,
> > >  			      unsigned int sh_offset, unsigned int sh_size,
> > > -			      unsigned int sh_link, unsigned int sh_addralign,
> > > +			      unsigned int sh_link, unsigned int sh_info,
> > > +			      unsigned int sh_addralign,
> > > +			      unsigned int sh_entsize,
> > >  			      const char **errmsg, int *err)
> > >  {
> > >    struct simple_object_elf_attributes *attrs =
> > > @@ -788,12 +847,13 @@ simple_object_elf_write_shdr (simple_obj
> > >    ELF_SET_FIELD (fns, cl, Shdr, buf, sh_name, Elf_Word, sh_name);
> > >    ELF_SET_FIELD (fns, cl, Shdr, buf, sh_type, Elf_Word, sh_type);
> > >    ELF_SET_FIELD (fns, cl, Shdr, buf, sh_flags, Elf_Addr, sh_flags);
> > > +  ELF_SET_FIELD (fns, cl, Shdr, buf, sh_addr, Elf_Addr, sh_addr);
> > >    ELF_SET_FIELD (fns, cl, Shdr, buf, sh_offset, Elf_Addr, sh_offset);
> > >    ELF_SET_FIELD (fns, cl, Shdr, buf, sh_size, Elf_Addr, sh_size);
> > >    ELF_SET_FIELD (fns, cl, Shdr, buf, sh_link, Elf_Word, sh_link);
> > > -  /* sh_info left as zero.  */
> > > +  ELF_SET_FIELD (fns, cl, Shdr, buf, sh_info, Elf_Word, sh_info);
> > >    ELF_SET_FIELD (fns, cl, Shdr, buf, sh_addralign, Elf_Addr, sh_addralign);
> > > -  /* sh_entsize left as zero.  */
> > > +  ELF_SET_FIELD (fns, cl, Shdr, buf, sh_entsize, Elf_Word, sh_entsize);
> > >  
> > >    return simple_object_internal_write (descriptor, offset, buf, shdr_size,
> > >  				       errmsg, err);
> > > @@ -811,8 +871,9 @@ static const char *
> > >  simple_object_elf_write_to_file (simple_object_write *sobj, int descriptor,
> > >  				 int *err)
> > >  {
> > > -  struct simple_object_elf_attributes *attrs =
> > > -    (struct simple_object_elf_attributes *) 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;
> > >    size_t shdr_size;
> > > @@ -825,6 +886,7 @@ simple_object_elf_write_to_file (simple_
> > >    unsigned int first_sh_link;
> > >    size_t sh_name;
> > >    unsigned char zero;
> > > +  unsigned secnum;
> > >  
> > >    if (!simple_object_elf_write_ehdr (sobj, descriptor, &errmsg, err))
> > >      return errmsg;
> > > @@ -862,21 +924,54 @@ simple_object_elf_write_to_file (simple_
> > >    else
> > >      first_sh_link = shnum - 1;
> > >    if (!simple_object_elf_write_shdr (sobj, descriptor, shdr_offset,
> > > -				     0, 0, 0, 0, first_sh_size, first_sh_link,
> > > -				     0, &errmsg, err))
> > > +				     0, 0, 0, 0, 0, first_sh_size, first_sh_link,
> > > +				     0, 0, 0, &errmsg, err))
> > >      return errmsg;
> > >  
> > >    shdr_offset += shdr_size;
> > >  
> > >    sh_name = 1;
> > > +  secnum = 0;
> > >    for (section = sobj->sections; section != NULL; section = section->next)
> > >      {
> > >        size_t mask;
> > >        size_t new_sh_offset;
> > >        size_t sh_size;
> > >        struct simple_object_write_section_buffer *buffer;
> > > +      unsigned int sh_type = SHT_PROGBITS;
> > > +      unsigned int sh_flags = 0;
> > > +      off_t sh_addr = 0;
> > > +      unsigned int sh_link = 0;
> > > +      unsigned int sh_info = 0;
> > > +      unsigned int sh_addralign = 1U << section->align;
> > > +      unsigned int sh_entsize = 0;
> > > +      if (eow->shdrs)
> > > +	{
> > > +	  sh_type = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
> > > +				     eow->shdrs + secnum * shdr_size,
> > > +				     sh_type, Elf_Word);
> > > +	  sh_flags = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
> > > +				      eow->shdrs + secnum * shdr_size,
> > > +				      sh_flags, Elf_Addr);
> > > +	  sh_addr = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
> > > +				     eow->shdrs + secnum * shdr_size,
> > > +				     sh_addr, Elf_Addr);
> > > +	  sh_link = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
> > > +				     eow->shdrs + secnum * shdr_size,
> > > +				     sh_link, Elf_Word);
> > > +	  sh_info = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
> > > +				     eow->shdrs + secnum * shdr_size,
> > > +				     sh_info, Elf_Word);
> > > +	  sh_addralign = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
> > > +					  eow->shdrs + secnum * shdr_size,
> > > +					  sh_addralign, Elf_Addr);
> > > +	  sh_entsize = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
> > > +					eow->shdrs + secnum * shdr_size,
> > > +					sh_entsize, Elf_Word);
> > > +	  secnum++;
> > > +	}
> > >  
> > > -      mask = (1U << section->align) - 1;
> > > +      mask = sh_addralign - 1;
> > >        new_sh_offset = sh_offset + mask;
> > >        new_sh_offset &= ~ mask;
> > >        while (new_sh_offset > sh_offset)
> > > @@ -906,8 +1001,10 @@ simple_object_elf_write_to_file (simple_
> > >  	}
> > >  
> > >        if (!simple_object_elf_write_shdr (sobj, descriptor, shdr_offset,
> > > -					 sh_name, SHT_PROGBITS, 0, sh_offset,
> > > -					 sh_size, 0, 1U << section->align,
> > > +					 sh_name, sh_type, sh_flags,
> > > +					 sh_addr, sh_offset,
> > > +					 sh_size, sh_link, sh_info,
> > > +					 sh_addralign, sh_entsize,
> > >  					 &errmsg, err))
> > >  	return errmsg;
> > >  
> > > @@ -917,9 +1014,9 @@ simple_object_elf_write_to_file (simple_
> > >      }
> > >  
> > >    if (!simple_object_elf_write_shdr (sobj, descriptor, shdr_offset,
> > > -				     sh_name, SHT_STRTAB, 0, sh_offset,
> > > -				     sh_name + strlen (".shstrtab") + 1, 0,
> > > -				     1, &errmsg, err))
> > > +				     sh_name, SHT_STRTAB, 0, 0, sh_offset,
> > > +				     sh_name + strlen (".shstrtab") + 1, 0, 0,
> > > +				     1, 0, &errmsg, err))
> > >      return errmsg;
> > >  
> > >    /* .shstrtab has a leading zero byte.  */
> > > @@ -954,9 +1051,363 @@ simple_object_elf_write_to_file (simple_
> > >  static void
> > >  simple_object_elf_release_write (void *data)
> > >  {
> > > +  struct simple_object_elf_write *eow = (struct simple_object_elf_write *) data;
> > > +  if (eow->shdrs)
> > > +    XDELETE (eow->shdrs);
> > >    XDELETE (data);
> > >  }
> > >  
> > > +/* Copy all sections in an ELF file.  */
> > > +
> > > +static const char *
> > > +simple_object_elf_copy_lto_debug_sections (simple_object_read *sobj,
> > > +					   simple_object_write *dobj,
> > > +					   int (*pfn) (const char **),
> > > +					   int *err)
> > > +{
> > > +  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;
> > > +  unsigned char ei_class = eor->ei_class;
> > > +  size_t shdr_size;
> > > +  unsigned int shnum;
> > > +  unsigned char *shdrs;
> > > +  const char *errmsg;
> > > +  unsigned char *shstrhdr;
> > > +  size_t name_size;
> > > +  off_t shstroff;
> > > +  unsigned char *names;
> > > +  unsigned int i;
> > > +  int *pfnret;
> > > +  const char **pfnname;
> > > +
> > > +  shdr_size = (ei_class == ELFCLASS32
> > > +	       ? sizeof (Elf32_External_Shdr)
> > > +	       : sizeof (Elf64_External_Shdr));
> > > +
> > > +  /* Read the section headers.  We skip section 0, which is not a
> > > +     useful section.  */
> > > +
> > > +  shnum = eor->shnum;
> > > +  shdrs = XNEWVEC (unsigned char, shdr_size * (shnum - 1));
> > > +
> > > +  if (!simple_object_internal_read (sobj->descriptor,
> > > +				    sobj->offset + eor->shoff + shdr_size,
> > > +				    shdrs,
> > > +				    shdr_size * (shnum - 1),
> > > +				    &errmsg, err))
> > > +    {
> > > +      XDELETEVEC (shdrs);
> > > +      return errmsg;
> > > +    }
> > > +
> > > +  /* Read the section names.  */
> > > +
> > > +  shstrhdr = shdrs + (eor->shstrndx - 1) * shdr_size;
> > > +  name_size = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
> > > +			       shstrhdr, sh_size, Elf_Addr);
> > > +  shstroff = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
> > > +			      shstrhdr, sh_offset, Elf_Addr);
> > > +  names = XNEWVEC (unsigned char, name_size);
> > > +  if (!simple_object_internal_read (sobj->descriptor,
> > > +				    sobj->offset + shstroff,
> > > +				    names, name_size, &errmsg, err))
> > > +    {
> > > +      XDELETEVEC (names);
> > > +      XDELETEVEC (shdrs);
> > > +      return errmsg;
> > > +    }
> > > +
> > > +  eow->shdrs = XNEWVEC (unsigned char, shdr_size * (shnum - 1));
> > > +  pfnret = XNEWVEC (int, shnum);
> > > +  pfnname = XNEWVEC (const char *, shnum);
> > > +
> > > +  /* First perform the callbacks to know which sections to preserve and
> > > +     what name to use for those.  */
> > > +  for (i = 1; i < shnum; ++i)
> > > +    {
> > > +      unsigned char *shdr;
> > > +      unsigned int sh_name;
> > > +      const char *name;
> > > +      int ret;
> > > +
> > > +      shdr = shdrs + (i - 1) * shdr_size;
> > > +      sh_name = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
> > > +				 shdr, sh_name, Elf_Word);
> > > +      if (sh_name >= name_size)
> > > +	{
> > > +	  *err = 0;
> > > +	  XDELETEVEC (names);
> > > +	  XDELETEVEC (shdrs);
> > > +	  return "ELF section name out of range";
> > > +	}
> > > +
> > > +      name = (const char *) names + sh_name;
> > > +
> > > +      ret = (*pfn) (&name);
> > > +      pfnret[i - 1] = ret == 1 ? 0 : -1;
> > > +      pfnname[i - 1] = name;
> > > +    }
> > > +
> > > +  /* Mark sections as preserved that are required by to be preserved
> > > +     sections.  */
> > > +  for (i = 1; i < shnum; ++i)
> > > +    {
> > > +      unsigned char *shdr;
> > > +      unsigned int sh_type, sh_info, sh_link;
> > > +      off_t offset;
> > > +      off_t length;
> > > +
> > > +      shdr = shdrs + (i - 1) * shdr_size;
> > > +      sh_type = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
> > > +				 shdr, sh_type, Elf_Word);
> > > +      sh_info = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
> > > +				 shdr, sh_info, Elf_Word);
> > > +      sh_link = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
> > > +				 shdr, sh_link, Elf_Word);
> > > +      if (sh_type == SHT_GROUP)
> > > +	{
> > > +	  /* Mark groups containing copied sections.  */
> > > +	  unsigned entsize = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
> > > +					      shdr, sh_entsize, Elf_Addr);
> > > +	  unsigned char *ent, *buf;
> > > +	  int keep = 0;
> > > +	  offset = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
> > > +				    shdr, sh_offset, Elf_Addr);
> > > +	  length = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
> > > +				    shdr, sh_size, Elf_Addr);
> > > +	  buf = XNEWVEC (unsigned char, length);
> > > +	  if (!simple_object_internal_read (sobj->descriptor,
> > > +					    sobj->offset + offset, buf,
> > > +					    (size_t) length, &errmsg, err))
> > > +	    {
> > > +	      XDELETEVEC (buf);
> > > +	      XDELETEVEC (names);
> > > +	      XDELETEVEC (shdrs);
> > > +	      return errmsg;
> > > +	    }
> > > +	  for (ent = buf + entsize; ent < buf + length; ent += entsize)
> > > +	    {
> > > +	      unsigned sec = type_functions->fetch_Elf_Word (ent);
> > > +	      if (pfnret[sec - 1] == 0)
> > > +		keep = 1;
> > > +	    }
> > > +	  if (keep)
> > > +	    {
> > > +	      pfnret[sh_link - 1] = 0;
> > > +	      pfnret[i - 1] = 0;
> > > +	    }
> > > +	}
> > > +      if (sh_type == SHT_RELA
> > > +	  || sh_type == SHT_REL)
> > > +	{
> > > +	  /* Mark relocation sections and symtab of copied sections.  */
> > > +	  if (pfnret[sh_info - 1] == 0)
> > > +	    {
> > > +	      pfnret[sh_link - 1] = 0;
> > > +	      pfnret[i - 1] = 0;
> > > +	    }
> > > +	}
> > > +      if (sh_type == SHT_SYMTAB)
> > > +	{
> > > +	  /* Mark strings sections of copied symtabs.  */
> > > +	  if (pfnret[i - 1] == 0)
> > > +	    pfnret[sh_link - 1] = 0;
> > > +	}
> > > +    }
> > > +
> > > +  /* Then perform the actual copying.  */
> > > +  for (i = 1; i < shnum; ++i)
> > > +    {
> > > +      unsigned char *shdr;
> > > +      unsigned int sh_name, sh_type;
> > > +      const char *name;
> > > +      off_t offset;
> > > +      off_t length;
> > > +      int ret;
> > > +      const char *errmsg;
> > > +      simple_object_write_section *dest;
> > > +      off_t flags;
> > > +      unsigned char *buf;
> > > +
> > > +      shdr = shdrs + (i - 1) * shdr_size;
> > > +      sh_name = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
> > > +				 shdr, sh_name, Elf_Word);
> > > +      if (sh_name >= name_size)
> > > +	{
> > > +	  *err = 0;
> > > +	  XDELETEVEC (names);
> > > +	  XDELETEVEC (shdrs);
> > > +	  return "ELF section name out of range";
> > > +	}
> > > +
> > > +      name = (const char *) names + sh_name;
> > > +      offset = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
> > > +				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);
> > > +
> > > +      ret = pfnret[i - 1];
> > > +      name = ret == 0 ? pfnname[i - 1] : "";
> > > +
> > > +      dest = simple_object_write_create_section (dobj, name, 0, &errmsg, err);
> > > +      if (dest == NULL)
> > > +	{
> > > +	  XDELETEVEC (names);
> > > +	  XDELETEVEC (shdrs);
> > > +	  return errmsg;
> > > +	}
> > > +
> > > +      /* Record the SHDR of the source.  */
> > > +      memcpy (eow->shdrs + (i - 1) * shdr_size, shdr, shdr_size);
> > > +      shdr = eow->shdrs + (i - 1) * shdr_size;
> > > +
> > > +      /* Copy the data.
> > > +	 ???  This is quite wasteful and ideally would be delayed until
> > > +	 write_to_file ().  Thus it questions the interfacing
> > > +	 which eventually should contain destination creation plus
> > > +	 writing.  */
> > > +      /* Keep empty sections for sections we should discard.  This avoids
> > > +         the need to rewrite section indices in symtab and relocation
> > > +	 sections.  */
> > > +      if (ret == 0)
> > > +	{
> > > +	  buf = XNEWVEC (unsigned char, length);
> > > +	  if (!simple_object_internal_read (sobj->descriptor,
> > > +					    sobj->offset + offset, buf,
> > > +					    (size_t) length, &errmsg, err))
> > > +	    {
> > > +	      XDELETEVEC (buf);
> > > +	      XDELETEVEC (names);
> > > +	      XDELETEVEC (shdrs);
> > > +	      return errmsg;
> > > +	    }
> > > +
> > > +	  /* If we are processing .symtab purge __gnu_lto_v1 and
> > > +	     __gnu_lto_slim symbols from it.  */
> > > +	  if (sh_type == SHT_SYMTAB)
> > > +	    {
> > > +	      unsigned entsize = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
> > > +						  shdr, sh_entsize, Elf_Addr);
> > > +	      unsigned strtab = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
> > > +						 shdr, sh_link, Elf_Word);
> > > +	      unsigned char *strshdr = shdrs + (strtab - 1) * shdr_size;
> > > +	      off_t stroff = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
> > > +					      strshdr, sh_offset, Elf_Addr);
> > > +	      size_t strsz = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
> > > +					      strshdr, sh_size, Elf_Addr);
> > > +	      char *strings = XNEWVEC (char, strsz);
> > > +	      unsigned char *ent;
> > > +	      simple_object_internal_read (sobj->descriptor,
> > > +					   sobj->offset + stroff,
> > > +					   (unsigned char *)strings,
> > > +					   strsz, &errmsg, err);
> > > +	      for (ent = buf; ent < buf + length; ent += entsize)
> > > +		{
> > > +		  unsigned st_shndx = ELF_FETCH_FIELD (type_functions, ei_class,
> > > +						       Sym, ent,
> > > +						       st_shndx, Elf_Half);
> > > +		  unsigned char *st_info;
> > > +		  unsigned char *st_other;
> > > +		  if (ei_class == ELFCLASS32)
> > > +		    {
> > > +		      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;
> > > +		    }
> > > +		  /* Eliminate all COMMONs - this includes __gnu_lto_v1
> > > +		     and __gnu_lto_slim which otherwise cause endless
> > > +		     LTO plugin invocation.  */
> > > +		  if (st_shndx == SHN_COMMON)
> > > +		    /* Setting st_name to "" seems to work to purge
> > > +		       COMMON symbols (in addition to setting their
> > > +		       size to zero).  */
> > > +		    ;
> > > +		  /* We also need to remove symbols refering to sections
> > > +		     we'll eventually remove as with fat LTO objects
> > > +		     we otherwise get duplicate symbols at final link
> > > +		     (with GNU ld, gold is fine and ignores symbols in
> > > +		     sections marked as EXCLUDE).  ld/20513  */
> > > +		  else if (st_shndx != 0
> > > +			   && st_shndx < shnum
> > > +			   && pfnret[st_shndx - 1] == -1)
> > > +		    /* Messing with st_shndx doesn't seem to work very
> > > +		       well.  Likewise changing the symbol type to
> > > +		       a section symbol or making it local.
> > > +		       So just keep with making it unnamed.
> > > +		       Also make all regular symbols STT_OBJECT and
> > > +		       have default visibility, otherwise GNU ld warns
> > > +		       about mismatches for the same `' named symbol.  */
> > > +		    {
> > > +		      if (ELF_ST_TYPE (*st_info) == STT_FUNC
> > > +			  || ELF_ST_TYPE (*st_info) == STT_TLS
> > > +			  || ELF_ST_TYPE (*st_info) == STT_GNU_IFUNC)
> > > +			*st_info = ELF_ST_INFO (ELF_ST_BIND (*st_info),
> > > +						STT_OBJECT);
> > > +		      *st_other = STV_DEFAULT;
> > > +		    }
> > > +		  else
> > > +		    continue;
> > > +
> > > +		  /* For all purged symbols make the symbol unnamed.  */
> > > +		  ELF_SET_FIELD (type_functions, ei_class, Sym,
> > > +				 ent, st_name, Elf_Word, 0);
> > > +
> > > +		  /* At least set st_value and st_size to zero to not go
> > > +		     out of bounds.  */
> > > +		  ELF_SET_FIELD (type_functions, ei_class, Sym,
> > > +				 ent, st_value, Elf_Addr, 0);
> > > +		  ELF_SET_FIELD (type_functions, ei_class, Sym,
> > > +				 ent, st_size, Elf_Word, 0);
> > > +		}
> > > +	      XDELETEVEC (strings);
> > > +	    }
> > > +
> > > +	  errmsg = simple_object_write_add_data (dobj, dest, buf, length, 1, err);
> > > +	  XDELETEVEC (buf);
> > > +	  if (errmsg)
> > > +	    {
> > > +	      XDELETEVEC (names);
> > > +	      XDELETEVEC (shdrs);
> > > +	      return errmsg;
> > > +	    }
> > > +	}
> > > +      else
> > > +	{
> > > +	  /* For deleted sections mark the section header table entry as
> > > +	     unused.  That allows the link editor to remove it in a partial
> > > +	     link.  */
> > > +	  ELF_SET_FIELD (type_functions, ei_class, Shdr,
> > > +			 shdr, sh_type, Elf_Addr, SHT_NULL);
> > > +	}
> > > +
> > > +      flags = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
> > > +			       shdr, sh_flags, Elf_Addr);
> > > +      if (ret == 0)
> > > +	flags &= ~SHF_EXCLUDE;
> > > +      else if (ret == -1)
> > > +	flags |= SHF_EXCLUDE;
> > > +      ELF_SET_FIELD (type_functions, ei_class, Shdr,
> > > +		     shdr, sh_flags, Elf_Addr, flags);
> > > +    }
> > > +
> > > +  XDELETEVEC (names);
> > > +  XDELETEVEC (shdrs);
> > > +  XDELETEVEC (pfnret);
> > > +  XDELETEVEC (pfnname);
> > > +
> > > +  return NULL;
> > > +}
> > > +
> > > +
> > >  /* The ELF functions.  */
> > >  
> > >  const struct simple_object_functions simple_object_elf_functions =
> > > @@ -969,5 +1420,6 @@ const struct simple_object_functions sim
> > >    simple_object_elf_release_attributes,
> > >    simple_object_elf_start_write,
> > >    simple_object_elf_write_to_file,
> > > -  simple_object_elf_release_write
> > > +  simple_object_elf_release_write,
> > > +  simple_object_elf_copy_lto_debug_sections
> > >  };
> > > Index: early-lto-debug/libiberty/simple-object.c
> > > ===================================================================
> > > --- early-lto-debug.orig/libiberty/simple-object.c	2016-10-19 13:19:58.012326431 +0200
> > > +++ early-lto-debug/libiberty/simple-object.c	2016-10-20 13:58:11.722714041 +0200
> > > @@ -22,6 +22,7 @@ Boston, MA 02110-1301, USA.  */
> > >  #include "simple-object.h"
> > >  
> > >  #include <errno.h>
> > > +#include <fcntl.h>
> > >  
> > >  #ifdef HAVE_STDLIB_H
> > >  #include <stdlib.h>
> > > @@ -249,6 +250,86 @@ simple_object_find_section (simple_objec
> > >    return 1;
> > >  }
> > >  
> > > +/* Callback to identify and rename LTO debug sections by name.
> > > +   Returns 1 if NAME is a LTO debug section, 0 if not.  */
> > > +
> > > +static int
> > > +handle_lto_debug_sections (const char **name)
> > > +{
> > > +  /* ???  So we can't use .gnu.lto_ prefixed sections as the assembler
> > > +     complains about bogus section flags.  Which means we need to arrange
> > > +     for that to be fixed or .gnu.debuglto_ marked as SHF_EXCLUDE (to make
> > > +     fat lto object tooling work for the fat part).  */
> > > +  /* ???  For now this handles both .gnu.lto_ and .gnu.debuglto_ prefixed
> > > +     sections.  */
> > > +  /* Copy LTO debug sections and rename them to their non-LTO name.  */
> > > +  if (strncmp (*name, ".gnu.debuglto_", sizeof (".gnu.debuglto_") - 1) == 0)
> > > +    {
> > > +      *name = *name + sizeof (".gnu.debuglto_") - 1;
> > > +      return 1;
> > > +    }
> > > +  else if (strncmp (*name, ".gnu.lto_.debug_", sizeof (".gnu.lto_.debug_") -1) == 0)
> > > +    {
> > > +      *name = *name + sizeof (".gnu.lto_") - 1;
> > > +      return 1;
> > > +    }
> > > +  return 0;
> > > +}
> > > +
> > > +/* Copy LTO debug sections.  */
> > > +
> > > +const char *
> > > +simple_object_copy_lto_debug_sections (simple_object_read *sobj,
> > > +				       const char *dest, int *err)
> > > +{
> > > +  const char *errmsg;
> > > +  simple_object_write *dest_sobj;
> > > +  simple_object_attributes *attrs;
> > > +  int outfd;
> > > +
> > > +  if (! sobj->functions->copy_lto_debug_sections)
> > > +    {
> > > +      *err = EINVAL;
> > > +      return "simple_object_copy_lto_debug_sections not implemented";
> > > +    }
> > > +
> > > +  attrs = simple_object_fetch_attributes (sobj, &errmsg, err);
> > > +  if (! attrs)
> > > +    return errmsg;
> > > +  dest_sobj = simple_object_start_write (attrs, NULL, &errmsg, err);
> > > +  simple_object_release_attributes (attrs);
> > > +  if (! dest_sobj)
> > > +    return errmsg;
> > > +
> > > +  errmsg = sobj->functions->copy_lto_debug_sections (sobj, dest_sobj,
> > > +						     handle_lto_debug_sections,
> > > +						     err);
> > > +  if (errmsg)
> > > +    {
> > > +      simple_object_release_write (dest_sobj);
> > > +      return errmsg;
> > > +    }
> > > +
> > > +  outfd = creat (dest, 00777);
> > > +  if (outfd == -1)
> > > +    {
> > > +      *err = errno;
> > > +      simple_object_release_write (dest_sobj);
> > > +      return "open failed";
> > > +    }
> > > +
> > > +  errmsg = simple_object_write_to_file (dest_sobj, outfd, err);
> > > +  close (outfd);
> > > +  if (errmsg)
> > > +    {
> > > +      simple_object_release_write (dest_sobj);
> > > +      return errmsg;
> > > +    }
> > > +
> > > +  simple_object_release_write (dest_sobj);
> > > +  return NULL;
> > > +}
> > > +
> > >  /* Fetch attributes.  */
> > >  
> > >  simple_object_attributes *
> > > @@ -315,7 +396,7 @@ simple_object_start_write (simple_object
> > >      return NULL;
> > >    ret = XNEW (simple_object_write);
> > >    ret->functions = attrs->functions;
> > > -  ret->segment_name = xstrdup (segment_name);
> > > +  ret->segment_name = segment_name ? xstrdup (segment_name) : NULL;
> > >    ret->sections = NULL;
> > >    ret->last_section = NULL;
> > >    ret->data = data;
> > > Index: early-lto-debug/libiberty/simple-object-coff.c
> > > ===================================================================
> > > --- early-lto-debug.orig/libiberty/simple-object-coff.c	2016-10-19 13:19:58.012326431 +0200
> > > +++ early-lto-debug/libiberty/simple-object-coff.c	2016-10-20 10:51:49.881723228 +0200
> > > @@ -800,5 +800,6 @@ const struct simple_object_functions sim
> > >    simple_object_coff_release_attributes,
> > >    simple_object_coff_start_write,
> > >    simple_object_coff_write_to_file,
> > > -  simple_object_coff_release_write
> > > +  simple_object_coff_release_write,
> > > +  NULL
> > >  };
> > > Index: early-lto-debug/libiberty/simple-object-mach-o.c
> > > ===================================================================
> > > --- early-lto-debug.orig/libiberty/simple-object-mach-o.c	2016-10-19 13:19:58.012326431 +0200
> > > +++ early-lto-debug/libiberty/simple-object-mach-o.c	2016-10-20 10:51:49.881723228 +0200
> > > @@ -1374,5 +1374,6 @@ const struct simple_object_functions sim
> > >    simple_object_mach_o_release_attributes,
> > >    simple_object_mach_o_start_write,
> > >    simple_object_mach_o_write_to_file,
> > > -  simple_object_mach_o_release_write
> > > +  simple_object_mach_o_release_write,
> > > +  NULL
> > >  };
> > > Index: early-lto-debug/libiberty/simple-object-xcoff.c
> > > ===================================================================
> > > --- early-lto-debug.orig/libiberty/simple-object-xcoff.c	2016-10-19 13:19:58.012326431 +0200
> > > +++ early-lto-debug/libiberty/simple-object-xcoff.c	2016-10-20 10:51:49.881723228 +0200
> > > @@ -894,5 +894,6 @@ const struct simple_object_functions sim
> > >    simple_object_xcoff_release_attributes,
> > >    simple_object_xcoff_start_write,
> > >    simple_object_xcoff_write_to_file,
> > > -  simple_object_xcoff_release_write
> > > +  simple_object_xcoff_release_write,
> > > +  NULL
> > >  };
> > > 
> > 
> > 
> 
>
Richard Biener July 28, 2017, 12:54 p.m. UTC | #4
On Tue, 4 Jul 2017, Richard Biener wrote:

> On Tue, 20 Jun 2017, Richard Biener wrote:
> 
> > On Wed, 7 Jun 2017, Richard Biener wrote:
> > 
> > > On Fri, 19 May 2017, Richard Biener wrote:
> > > 
> > > > 
> > > > This is a repost (unchanged) of the simple-object ELF support for
> > > > early LTO debug transfer from IL object to a separate debug-only object 
> > > > file.
> > > > 
> > > > Bootstrapped and tested on x86_64-unknown-linux-gnu.
> > > 
> > > Ping.
> > 
> > Ping^2.
> 
> Ping^3.

Ping^4.  Adding some more global reviewers to CC.

Richard.

> > > > Richard.
> > > > 
> > > > 2017-05-19  Richard Biener  <rguenther@suse.de>
> > > > 
> > > > 	include/
> > > > 	* simple-object.h (simple_object_copy_lto_debug_sections): New
> > > > 	function.
> > > > 
> > > > 	libiberty/
> > > > 	* simple-object-common.h (struct simple_object_functions): Add
> > > > 	copy_lto_debug_sections hook.
> > > > 	* simple-object.c: Include fcntl.h.
> > > > 	(handle_lto_debug_sections): New helper function.
> > > > 	(simple_object_copy_lto_debug_sections): New function copying
> > > > 	early LTO debug sections to regular debug sections in a new file.
> > > > 	(simple_object_start_write): Handle NULL segment_name.
> > > > 	* simple-object-coff.c (simple_object_coff_functions): Adjust
> > > > 	for not implemented copy_lto_debug_sections hook.
> > > > 	* simple-object-mach-o.c (simple_object_mach_o_functions): Likewise.
> > > > 	* simple-object-xcoff.c (simple_object_xcoff_functions): Likewise.
> > > > 	* simple-object-elf.c (SHT_NULL, SHT_SYMTAB, SHT_RELA, SHT_REL,
> > > > 	SHT_GROUP): Add various sectopn header types.
> > > > 	(SHF_EXCLUDE): Add flag.
> > > > 	(Elf32_External_Sym, Elf64_External_Sym): Add symbol struct.
> > > > 	(ELF_ST_BIND, ELF_ST_TYPE, ELF_ST_INFO): Add accessors.
> > > > 	(STT_OBJECT, STT_FUNC, STT_TLS, STT_GNU_IFUNC): Add Symbol types.
> > > > 	(STV_DEFAULT): Add symbol visibility.
> > > > 	(SHN_COMMON): Add special section index name.
> > > > 	(struct simple_object_elf_write): New.
> > > > 	(simple_object_elf_start_write): Adjust for new private data.
> > > > 	(simple_object_elf_write_shdr): Pass in values for all fields
> > > > 	we write.
> > > > 	(simple_object_elf_write_to_file): Adjust.  Copy from recorded
> > > > 	section headers if requested.
> > > > 	(simple_object_elf_release_write): Release private data.
> > > > 	(simple_object_elf_copy_lto_debug_sections): Copy and rename sections
> > > > 	as denoted by PFN and all their dependences, symbols and relocations
> > > > 	to the empty destination file.
> > > > 	(simple_object_elf_functions): Adjust for copy_lto_debug_sections hook.
> > > > 
> > > > Index: early-lto-debug/include/simple-object.h
> > > > ===================================================================
> > > > --- early-lto-debug.orig/include/simple-object.h	2016-10-19 13:19:58.012326431 +0200
> > > > +++ early-lto-debug/include/simple-object.h	2016-10-20 10:51:49.861722998 +0200
> > > > @@ -197,6 +197,14 @@ simple_object_write_to_file (simple_obje
> > > >  extern void
> > > >  simple_object_release_write (simple_object_write *);
> > > >  
> > > > +/* Copy LTO debug sections from SRC_OBJECT to DEST.
> > > > +   If an error occurs, return the errno value in ERR and an error string.  */
> > > > +
> > > > +extern const char *
> > > > +simple_object_copy_lto_debug_sections (simple_object_read *src_object,
> > > > +				       const char *dest,
> > > > +				       int *err);
> > > > +
> > > >  #ifdef __cplusplus
> > > >  }
> > > >  #endif
> > > > Index: early-lto-debug/libiberty/simple-object-common.h
> > > > ===================================================================
> > > > --- early-lto-debug.orig/libiberty/simple-object-common.h	2016-10-19 13:19:58.012326431 +0200
> > > > +++ early-lto-debug/libiberty/simple-object-common.h	2016-10-20 10:51:49.865723045 +0200
> > > > @@ -141,6 +141,12 @@ struct simple_object_functions
> > > >  
> > > >    /* Release the private data for an simple_object_write.  */
> > > >    void (*release_write) (void *);
> > > > +
> > > > +  /* Copy LTO debug sections.  */
> > > > +  const char *(*copy_lto_debug_sections) (simple_object_read *sobj,
> > > > +					  simple_object_write *dobj,
> > > > +					  int (*pfn) (const char **),
> > > > +					  int *err);
> > > >  };
> > > >  
> > > >  /* The known object file formats.  */
> > > > Index: early-lto-debug/libiberty/simple-object-elf.c
> > > > ===================================================================
> > > > --- early-lto-debug.orig/libiberty/simple-object-elf.c	2016-10-19 13:19:58.012326431 +0200
> > > > +++ early-lto-debug/libiberty/simple-object-elf.c	2016-10-20 10:51:49.865723045 +0200
> > > > @@ -183,8 +183,55 @@ typedef struct {
> > > >  
> > > >  /* Values for sh_type field.  */
> > > >  
> > > > +#define SHT_NULL	0		/* Section header table entry unused */
> > > >  #define SHT_PROGBITS	1		/* Program data */
> > > > +#define SHT_SYMTAB	2		/* Link editing symbol table */
> > > >  #define SHT_STRTAB	3		/* A string table */
> > > > +#define SHT_RELA	4		/* Relocation entries with addends */
> > > > +#define SHT_REL		9		/* Relocation entries, no addends */
> > > > +#define SHT_GROUP	17		/* Section contains a section group */
> > > > +
> > > > +/* Values for sh_flags field.  */
> > > > +
> > > > +#define SHF_EXCLUDE	0x80000000	/* Link editor is to exclude this
> > > > +					   section from executable and
> > > > +					   shared library that it builds
> > > > +					   when those objects are not to be
> > > > +					   further relocated.  */
> > > > +/* Symbol table entry.  */
> > > > +
> > > > +typedef struct
> > > > +{
> > > > +  unsigned char st_name[4];                /* Symbol name (string tbl index) */
> > > > +  unsigned char st_value[4];               /* Symbol value */
> > > > +  unsigned char st_size[4];                /* Symbol size */
> > > > +  unsigned char st_info;                /* Symbol type and binding */
> > > > +  unsigned char st_other;               /* Symbol visibility */
> > > > +  unsigned char st_shndx[2];               /* Section index */
> > > > +} Elf32_External_Sym;
> > > > +
> > > > +typedef struct
> > > > +{
> > > > +  unsigned char st_name[4];                /* Symbol name (string tbl index) */
> > > > +  unsigned char st_info;                /* Symbol type and binding */
> > > > +  unsigned char st_other;               /* Symbol visibility */
> > > > +  unsigned char st_shndx[2];               /* Section index */
> > > > +  unsigned char st_value[8];               /* Symbol value */
> > > > +  unsigned char st_size[8];                /* Symbol size */
> > > > +} Elf64_External_Sym;
> > > > +
> > > > +#define ELF_ST_BIND(val)              (((unsigned char) (val)) >> 4)
> > > > +#define ELF_ST_TYPE(val)              ((val) & 0xf)
> > > > +#define ELF_ST_INFO(bind, type)       (((bind) << 4) + ((type) & 0xf))
> > > > +
> > > > +#define STT_OBJECT	1	/* Symbol is a data object */
> > > > +#define STT_FUNC	2	/* Symbol is a code object */
> > > > +#define STT_TLS		6	/* Thread local data object */
> > > > +#define STT_GNU_IFUNC	10	/* Symbol is an indirect code object */
> > > > +
> > > > +#define STV_DEFAULT	0	/* Visibility is specified by binding type */
> > > > +
> > > > +#define SHN_COMMON	0xFFF2	/* Associated symbol is in common */
> > > >  
> > > >  /* Functions to fetch and store different ELF types, depending on the
> > > >     endianness and size.  */
> > > > @@ -348,6 +395,14 @@ struct simple_object_elf_attributes
> > > >    unsigned int flags;
> > > >  };
> > > >  
> > > > +/* Private data for an simple_object_write.  */
> > > > +
> > > > +struct simple_object_elf_write
> > > > +{
> > > > +  struct simple_object_elf_attributes attrs;
> > > > +  unsigned char *shdrs;
> > > > +};
> > > > +
> > > >  /* See if we have an ELF file.  */
> > > >  
> > > >  static void *
> > > > @@ -675,12 +730,13 @@ simple_object_elf_start_write (void *att
> > > >  {
> > > >    struct simple_object_elf_attributes *attrs =
> > > >      (struct simple_object_elf_attributes *) attributes_data;
> > > > -  struct simple_object_elf_attributes *ret;
> > > > +  struct simple_object_elf_write *ret;
> > > >  
> > > >    /* We're just going to record the attributes, but we need to make a
> > > >       copy because the user may delete them.  */
> > > > -  ret = XNEW (struct simple_object_elf_attributes);
> > > > -  *ret = *attrs;
> > > > +  ret = XNEW (struct simple_object_elf_write);
> > > > +  ret->attrs = *attrs;
> > > > +  ret->shdrs = NULL;
> > > >    return ret;
> > > >  }
> > > >  
> > > > @@ -766,8 +822,11 @@ static int
> > > >  simple_object_elf_write_shdr (simple_object_write *sobj, int descriptor,
> > > >  			      off_t offset, unsigned int sh_name,
> > > >  			      unsigned int sh_type, unsigned int sh_flags,
> > > > +			      off_t sh_addr,
> > > >  			      unsigned int sh_offset, unsigned int sh_size,
> > > > -			      unsigned int sh_link, unsigned int sh_addralign,
> > > > +			      unsigned int sh_link, unsigned int sh_info,
> > > > +			      unsigned int sh_addralign,
> > > > +			      unsigned int sh_entsize,
> > > >  			      const char **errmsg, int *err)
> > > >  {
> > > >    struct simple_object_elf_attributes *attrs =
> > > > @@ -788,12 +847,13 @@ simple_object_elf_write_shdr (simple_obj
> > > >    ELF_SET_FIELD (fns, cl, Shdr, buf, sh_name, Elf_Word, sh_name);
> > > >    ELF_SET_FIELD (fns, cl, Shdr, buf, sh_type, Elf_Word, sh_type);
> > > >    ELF_SET_FIELD (fns, cl, Shdr, buf, sh_flags, Elf_Addr, sh_flags);
> > > > +  ELF_SET_FIELD (fns, cl, Shdr, buf, sh_addr, Elf_Addr, sh_addr);
> > > >    ELF_SET_FIELD (fns, cl, Shdr, buf, sh_offset, Elf_Addr, sh_offset);
> > > >    ELF_SET_FIELD (fns, cl, Shdr, buf, sh_size, Elf_Addr, sh_size);
> > > >    ELF_SET_FIELD (fns, cl, Shdr, buf, sh_link, Elf_Word, sh_link);
> > > > -  /* sh_info left as zero.  */
> > > > +  ELF_SET_FIELD (fns, cl, Shdr, buf, sh_info, Elf_Word, sh_info);
> > > >    ELF_SET_FIELD (fns, cl, Shdr, buf, sh_addralign, Elf_Addr, sh_addralign);
> > > > -  /* sh_entsize left as zero.  */
> > > > +  ELF_SET_FIELD (fns, cl, Shdr, buf, sh_entsize, Elf_Word, sh_entsize);
> > > >  
> > > >    return simple_object_internal_write (descriptor, offset, buf, shdr_size,
> > > >  				       errmsg, err);
> > > > @@ -811,8 +871,9 @@ static const char *
> > > >  simple_object_elf_write_to_file (simple_object_write *sobj, int descriptor,
> > > >  				 int *err)
> > > >  {
> > > > -  struct simple_object_elf_attributes *attrs =
> > > > -    (struct simple_object_elf_attributes *) 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;
> > > >    size_t shdr_size;
> > > > @@ -825,6 +886,7 @@ simple_object_elf_write_to_file (simple_
> > > >    unsigned int first_sh_link;
> > > >    size_t sh_name;
> > > >    unsigned char zero;
> > > > +  unsigned secnum;
> > > >  
> > > >    if (!simple_object_elf_write_ehdr (sobj, descriptor, &errmsg, err))
> > > >      return errmsg;
> > > > @@ -862,21 +924,54 @@ simple_object_elf_write_to_file (simple_
> > > >    else
> > > >      first_sh_link = shnum - 1;
> > > >    if (!simple_object_elf_write_shdr (sobj, descriptor, shdr_offset,
> > > > -				     0, 0, 0, 0, first_sh_size, first_sh_link,
> > > > -				     0, &errmsg, err))
> > > > +				     0, 0, 0, 0, 0, first_sh_size, first_sh_link,
> > > > +				     0, 0, 0, &errmsg, err))
> > > >      return errmsg;
> > > >  
> > > >    shdr_offset += shdr_size;
> > > >  
> > > >    sh_name = 1;
> > > > +  secnum = 0;
> > > >    for (section = sobj->sections; section != NULL; section = section->next)
> > > >      {
> > > >        size_t mask;
> > > >        size_t new_sh_offset;
> > > >        size_t sh_size;
> > > >        struct simple_object_write_section_buffer *buffer;
> > > > +      unsigned int sh_type = SHT_PROGBITS;
> > > > +      unsigned int sh_flags = 0;
> > > > +      off_t sh_addr = 0;
> > > > +      unsigned int sh_link = 0;
> > > > +      unsigned int sh_info = 0;
> > > > +      unsigned int sh_addralign = 1U << section->align;
> > > > +      unsigned int sh_entsize = 0;
> > > > +      if (eow->shdrs)
> > > > +	{
> > > > +	  sh_type = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
> > > > +				     eow->shdrs + secnum * shdr_size,
> > > > +				     sh_type, Elf_Word);
> > > > +	  sh_flags = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
> > > > +				      eow->shdrs + secnum * shdr_size,
> > > > +				      sh_flags, Elf_Addr);
> > > > +	  sh_addr = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
> > > > +				     eow->shdrs + secnum * shdr_size,
> > > > +				     sh_addr, Elf_Addr);
> > > > +	  sh_link = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
> > > > +				     eow->shdrs + secnum * shdr_size,
> > > > +				     sh_link, Elf_Word);
> > > > +	  sh_info = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
> > > > +				     eow->shdrs + secnum * shdr_size,
> > > > +				     sh_info, Elf_Word);
> > > > +	  sh_addralign = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
> > > > +					  eow->shdrs + secnum * shdr_size,
> > > > +					  sh_addralign, Elf_Addr);
> > > > +	  sh_entsize = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
> > > > +					eow->shdrs + secnum * shdr_size,
> > > > +					sh_entsize, Elf_Word);
> > > > +	  secnum++;
> > > > +	}
> > > >  
> > > > -      mask = (1U << section->align) - 1;
> > > > +      mask = sh_addralign - 1;
> > > >        new_sh_offset = sh_offset + mask;
> > > >        new_sh_offset &= ~ mask;
> > > >        while (new_sh_offset > sh_offset)
> > > > @@ -906,8 +1001,10 @@ simple_object_elf_write_to_file (simple_
> > > >  	}
> > > >  
> > > >        if (!simple_object_elf_write_shdr (sobj, descriptor, shdr_offset,
> > > > -					 sh_name, SHT_PROGBITS, 0, sh_offset,
> > > > -					 sh_size, 0, 1U << section->align,
> > > > +					 sh_name, sh_type, sh_flags,
> > > > +					 sh_addr, sh_offset,
> > > > +					 sh_size, sh_link, sh_info,
> > > > +					 sh_addralign, sh_entsize,
> > > >  					 &errmsg, err))
> > > >  	return errmsg;
> > > >  
> > > > @@ -917,9 +1014,9 @@ simple_object_elf_write_to_file (simple_
> > > >      }
> > > >  
> > > >    if (!simple_object_elf_write_shdr (sobj, descriptor, shdr_offset,
> > > > -				     sh_name, SHT_STRTAB, 0, sh_offset,
> > > > -				     sh_name + strlen (".shstrtab") + 1, 0,
> > > > -				     1, &errmsg, err))
> > > > +				     sh_name, SHT_STRTAB, 0, 0, sh_offset,
> > > > +				     sh_name + strlen (".shstrtab") + 1, 0, 0,
> > > > +				     1, 0, &errmsg, err))
> > > >      return errmsg;
> > > >  
> > > >    /* .shstrtab has a leading zero byte.  */
> > > > @@ -954,9 +1051,363 @@ simple_object_elf_write_to_file (simple_
> > > >  static void
> > > >  simple_object_elf_release_write (void *data)
> > > >  {
> > > > +  struct simple_object_elf_write *eow = (struct simple_object_elf_write *) data;
> > > > +  if (eow->shdrs)
> > > > +    XDELETE (eow->shdrs);
> > > >    XDELETE (data);
> > > >  }
> > > >  
> > > > +/* Copy all sections in an ELF file.  */
> > > > +
> > > > +static const char *
> > > > +simple_object_elf_copy_lto_debug_sections (simple_object_read *sobj,
> > > > +					   simple_object_write *dobj,
> > > > +					   int (*pfn) (const char **),
> > > > +					   int *err)
> > > > +{
> > > > +  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;
> > > > +  unsigned char ei_class = eor->ei_class;
> > > > +  size_t shdr_size;
> > > > +  unsigned int shnum;
> > > > +  unsigned char *shdrs;
> > > > +  const char *errmsg;
> > > > +  unsigned char *shstrhdr;
> > > > +  size_t name_size;
> > > > +  off_t shstroff;
> > > > +  unsigned char *names;
> > > > +  unsigned int i;
> > > > +  int *pfnret;
> > > > +  const char **pfnname;
> > > > +
> > > > +  shdr_size = (ei_class == ELFCLASS32
> > > > +	       ? sizeof (Elf32_External_Shdr)
> > > > +	       : sizeof (Elf64_External_Shdr));
> > > > +
> > > > +  /* Read the section headers.  We skip section 0, which is not a
> > > > +     useful section.  */
> > > > +
> > > > +  shnum = eor->shnum;
> > > > +  shdrs = XNEWVEC (unsigned char, shdr_size * (shnum - 1));
> > > > +
> > > > +  if (!simple_object_internal_read (sobj->descriptor,
> > > > +				    sobj->offset + eor->shoff + shdr_size,
> > > > +				    shdrs,
> > > > +				    shdr_size * (shnum - 1),
> > > > +				    &errmsg, err))
> > > > +    {
> > > > +      XDELETEVEC (shdrs);
> > > > +      return errmsg;
> > > > +    }
> > > > +
> > > > +  /* Read the section names.  */
> > > > +
> > > > +  shstrhdr = shdrs + (eor->shstrndx - 1) * shdr_size;
> > > > +  name_size = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
> > > > +			       shstrhdr, sh_size, Elf_Addr);
> > > > +  shstroff = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
> > > > +			      shstrhdr, sh_offset, Elf_Addr);
> > > > +  names = XNEWVEC (unsigned char, name_size);
> > > > +  if (!simple_object_internal_read (sobj->descriptor,
> > > > +				    sobj->offset + shstroff,
> > > > +				    names, name_size, &errmsg, err))
> > > > +    {
> > > > +      XDELETEVEC (names);
> > > > +      XDELETEVEC (shdrs);
> > > > +      return errmsg;
> > > > +    }
> > > > +
> > > > +  eow->shdrs = XNEWVEC (unsigned char, shdr_size * (shnum - 1));
> > > > +  pfnret = XNEWVEC (int, shnum);
> > > > +  pfnname = XNEWVEC (const char *, shnum);
> > > > +
> > > > +  /* First perform the callbacks to know which sections to preserve and
> > > > +     what name to use for those.  */
> > > > +  for (i = 1; i < shnum; ++i)
> > > > +    {
> > > > +      unsigned char *shdr;
> > > > +      unsigned int sh_name;
> > > > +      const char *name;
> > > > +      int ret;
> > > > +
> > > > +      shdr = shdrs + (i - 1) * shdr_size;
> > > > +      sh_name = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
> > > > +				 shdr, sh_name, Elf_Word);
> > > > +      if (sh_name >= name_size)
> > > > +	{
> > > > +	  *err = 0;
> > > > +	  XDELETEVEC (names);
> > > > +	  XDELETEVEC (shdrs);
> > > > +	  return "ELF section name out of range";
> > > > +	}
> > > > +
> > > > +      name = (const char *) names + sh_name;
> > > > +
> > > > +      ret = (*pfn) (&name);
> > > > +      pfnret[i - 1] = ret == 1 ? 0 : -1;
> > > > +      pfnname[i - 1] = name;
> > > > +    }
> > > > +
> > > > +  /* Mark sections as preserved that are required by to be preserved
> > > > +     sections.  */
> > > > +  for (i = 1; i < shnum; ++i)
> > > > +    {
> > > > +      unsigned char *shdr;
> > > > +      unsigned int sh_type, sh_info, sh_link;
> > > > +      off_t offset;
> > > > +      off_t length;
> > > > +
> > > > +      shdr = shdrs + (i - 1) * shdr_size;
> > > > +      sh_type = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
> > > > +				 shdr, sh_type, Elf_Word);
> > > > +      sh_info = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
> > > > +				 shdr, sh_info, Elf_Word);
> > > > +      sh_link = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
> > > > +				 shdr, sh_link, Elf_Word);
> > > > +      if (sh_type == SHT_GROUP)
> > > > +	{
> > > > +	  /* Mark groups containing copied sections.  */
> > > > +	  unsigned entsize = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
> > > > +					      shdr, sh_entsize, Elf_Addr);
> > > > +	  unsigned char *ent, *buf;
> > > > +	  int keep = 0;
> > > > +	  offset = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
> > > > +				    shdr, sh_offset, Elf_Addr);
> > > > +	  length = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
> > > > +				    shdr, sh_size, Elf_Addr);
> > > > +	  buf = XNEWVEC (unsigned char, length);
> > > > +	  if (!simple_object_internal_read (sobj->descriptor,
> > > > +					    sobj->offset + offset, buf,
> > > > +					    (size_t) length, &errmsg, err))
> > > > +	    {
> > > > +	      XDELETEVEC (buf);
> > > > +	      XDELETEVEC (names);
> > > > +	      XDELETEVEC (shdrs);
> > > > +	      return errmsg;
> > > > +	    }
> > > > +	  for (ent = buf + entsize; ent < buf + length; ent += entsize)
> > > > +	    {
> > > > +	      unsigned sec = type_functions->fetch_Elf_Word (ent);
> > > > +	      if (pfnret[sec - 1] == 0)
> > > > +		keep = 1;
> > > > +	    }
> > > > +	  if (keep)
> > > > +	    {
> > > > +	      pfnret[sh_link - 1] = 0;
> > > > +	      pfnret[i - 1] = 0;
> > > > +	    }
> > > > +	}
> > > > +      if (sh_type == SHT_RELA
> > > > +	  || sh_type == SHT_REL)
> > > > +	{
> > > > +	  /* Mark relocation sections and symtab of copied sections.  */
> > > > +	  if (pfnret[sh_info - 1] == 0)
> > > > +	    {
> > > > +	      pfnret[sh_link - 1] = 0;
> > > > +	      pfnret[i - 1] = 0;
> > > > +	    }
> > > > +	}
> > > > +      if (sh_type == SHT_SYMTAB)
> > > > +	{
> > > > +	  /* Mark strings sections of copied symtabs.  */
> > > > +	  if (pfnret[i - 1] == 0)
> > > > +	    pfnret[sh_link - 1] = 0;
> > > > +	}
> > > > +    }
> > > > +
> > > > +  /* Then perform the actual copying.  */
> > > > +  for (i = 1; i < shnum; ++i)
> > > > +    {
> > > > +      unsigned char *shdr;
> > > > +      unsigned int sh_name, sh_type;
> > > > +      const char *name;
> > > > +      off_t offset;
> > > > +      off_t length;
> > > > +      int ret;
> > > > +      const char *errmsg;
> > > > +      simple_object_write_section *dest;
> > > > +      off_t flags;
> > > > +      unsigned char *buf;
> > > > +
> > > > +      shdr = shdrs + (i - 1) * shdr_size;
> > > > +      sh_name = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
> > > > +				 shdr, sh_name, Elf_Word);
> > > > +      if (sh_name >= name_size)
> > > > +	{
> > > > +	  *err = 0;
> > > > +	  XDELETEVEC (names);
> > > > +	  XDELETEVEC (shdrs);
> > > > +	  return "ELF section name out of range";
> > > > +	}
> > > > +
> > > > +      name = (const char *) names + sh_name;
> > > > +      offset = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
> > > > +				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);
> > > > +
> > > > +      ret = pfnret[i - 1];
> > > > +      name = ret == 0 ? pfnname[i - 1] : "";
> > > > +
> > > > +      dest = simple_object_write_create_section (dobj, name, 0, &errmsg, err);
> > > > +      if (dest == NULL)
> > > > +	{
> > > > +	  XDELETEVEC (names);
> > > > +	  XDELETEVEC (shdrs);
> > > > +	  return errmsg;
> > > > +	}
> > > > +
> > > > +      /* Record the SHDR of the source.  */
> > > > +      memcpy (eow->shdrs + (i - 1) * shdr_size, shdr, shdr_size);
> > > > +      shdr = eow->shdrs + (i - 1) * shdr_size;
> > > > +
> > > > +      /* Copy the data.
> > > > +	 ???  This is quite wasteful and ideally would be delayed until
> > > > +	 write_to_file ().  Thus it questions the interfacing
> > > > +	 which eventually should contain destination creation plus
> > > > +	 writing.  */
> > > > +      /* Keep empty sections for sections we should discard.  This avoids
> > > > +         the need to rewrite section indices in symtab and relocation
> > > > +	 sections.  */
> > > > +      if (ret == 0)
> > > > +	{
> > > > +	  buf = XNEWVEC (unsigned char, length);
> > > > +	  if (!simple_object_internal_read (sobj->descriptor,
> > > > +					    sobj->offset + offset, buf,
> > > > +					    (size_t) length, &errmsg, err))
> > > > +	    {
> > > > +	      XDELETEVEC (buf);
> > > > +	      XDELETEVEC (names);
> > > > +	      XDELETEVEC (shdrs);
> > > > +	      return errmsg;
> > > > +	    }
> > > > +
> > > > +	  /* If we are processing .symtab purge __gnu_lto_v1 and
> > > > +	     __gnu_lto_slim symbols from it.  */
> > > > +	  if (sh_type == SHT_SYMTAB)
> > > > +	    {
> > > > +	      unsigned entsize = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
> > > > +						  shdr, sh_entsize, Elf_Addr);
> > > > +	      unsigned strtab = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
> > > > +						 shdr, sh_link, Elf_Word);
> > > > +	      unsigned char *strshdr = shdrs + (strtab - 1) * shdr_size;
> > > > +	      off_t stroff = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
> > > > +					      strshdr, sh_offset, Elf_Addr);
> > > > +	      size_t strsz = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
> > > > +					      strshdr, sh_size, Elf_Addr);
> > > > +	      char *strings = XNEWVEC (char, strsz);
> > > > +	      unsigned char *ent;
> > > > +	      simple_object_internal_read (sobj->descriptor,
> > > > +					   sobj->offset + stroff,
> > > > +					   (unsigned char *)strings,
> > > > +					   strsz, &errmsg, err);
> > > > +	      for (ent = buf; ent < buf + length; ent += entsize)
> > > > +		{
> > > > +		  unsigned st_shndx = ELF_FETCH_FIELD (type_functions, ei_class,
> > > > +						       Sym, ent,
> > > > +						       st_shndx, Elf_Half);
> > > > +		  unsigned char *st_info;
> > > > +		  unsigned char *st_other;
> > > > +		  if (ei_class == ELFCLASS32)
> > > > +		    {
> > > > +		      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;
> > > > +		    }
> > > > +		  /* Eliminate all COMMONs - this includes __gnu_lto_v1
> > > > +		     and __gnu_lto_slim which otherwise cause endless
> > > > +		     LTO plugin invocation.  */
> > > > +		  if (st_shndx == SHN_COMMON)
> > > > +		    /* Setting st_name to "" seems to work to purge
> > > > +		       COMMON symbols (in addition to setting their
> > > > +		       size to zero).  */
> > > > +		    ;
> > > > +		  /* We also need to remove symbols refering to sections
> > > > +		     we'll eventually remove as with fat LTO objects
> > > > +		     we otherwise get duplicate symbols at final link
> > > > +		     (with GNU ld, gold is fine and ignores symbols in
> > > > +		     sections marked as EXCLUDE).  ld/20513  */
> > > > +		  else if (st_shndx != 0
> > > > +			   && st_shndx < shnum
> > > > +			   && pfnret[st_shndx - 1] == -1)
> > > > +		    /* Messing with st_shndx doesn't seem to work very
> > > > +		       well.  Likewise changing the symbol type to
> > > > +		       a section symbol or making it local.
> > > > +		       So just keep with making it unnamed.
> > > > +		       Also make all regular symbols STT_OBJECT and
> > > > +		       have default visibility, otherwise GNU ld warns
> > > > +		       about mismatches for the same `' named symbol.  */
> > > > +		    {
> > > > +		      if (ELF_ST_TYPE (*st_info) == STT_FUNC
> > > > +			  || ELF_ST_TYPE (*st_info) == STT_TLS
> > > > +			  || ELF_ST_TYPE (*st_info) == STT_GNU_IFUNC)
> > > > +			*st_info = ELF_ST_INFO (ELF_ST_BIND (*st_info),
> > > > +						STT_OBJECT);
> > > > +		      *st_other = STV_DEFAULT;
> > > > +		    }
> > > > +		  else
> > > > +		    continue;
> > > > +
> > > > +		  /* For all purged symbols make the symbol unnamed.  */
> > > > +		  ELF_SET_FIELD (type_functions, ei_class, Sym,
> > > > +				 ent, st_name, Elf_Word, 0);
> > > > +
> > > > +		  /* At least set st_value and st_size to zero to not go
> > > > +		     out of bounds.  */
> > > > +		  ELF_SET_FIELD (type_functions, ei_class, Sym,
> > > > +				 ent, st_value, Elf_Addr, 0);
> > > > +		  ELF_SET_FIELD (type_functions, ei_class, Sym,
> > > > +				 ent, st_size, Elf_Word, 0);
> > > > +		}
> > > > +	      XDELETEVEC (strings);
> > > > +	    }
> > > > +
> > > > +	  errmsg = simple_object_write_add_data (dobj, dest, buf, length, 1, err);
> > > > +	  XDELETEVEC (buf);
> > > > +	  if (errmsg)
> > > > +	    {
> > > > +	      XDELETEVEC (names);
> > > > +	      XDELETEVEC (shdrs);
> > > > +	      return errmsg;
> > > > +	    }
> > > > +	}
> > > > +      else
> > > > +	{
> > > > +	  /* For deleted sections mark the section header table entry as
> > > > +	     unused.  That allows the link editor to remove it in a partial
> > > > +	     link.  */
> > > > +	  ELF_SET_FIELD (type_functions, ei_class, Shdr,
> > > > +			 shdr, sh_type, Elf_Addr, SHT_NULL);
> > > > +	}
> > > > +
> > > > +      flags = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
> > > > +			       shdr, sh_flags, Elf_Addr);
> > > > +      if (ret == 0)
> > > > +	flags &= ~SHF_EXCLUDE;
> > > > +      else if (ret == -1)
> > > > +	flags |= SHF_EXCLUDE;
> > > > +      ELF_SET_FIELD (type_functions, ei_class, Shdr,
> > > > +		     shdr, sh_flags, Elf_Addr, flags);
> > > > +    }
> > > > +
> > > > +  XDELETEVEC (names);
> > > > +  XDELETEVEC (shdrs);
> > > > +  XDELETEVEC (pfnret);
> > > > +  XDELETEVEC (pfnname);
> > > > +
> > > > +  return NULL;
> > > > +}
> > > > +
> > > > +
> > > >  /* The ELF functions.  */
> > > >  
> > > >  const struct simple_object_functions simple_object_elf_functions =
> > > > @@ -969,5 +1420,6 @@ const struct simple_object_functions sim
> > > >    simple_object_elf_release_attributes,
> > > >    simple_object_elf_start_write,
> > > >    simple_object_elf_write_to_file,
> > > > -  simple_object_elf_release_write
> > > > +  simple_object_elf_release_write,
> > > > +  simple_object_elf_copy_lto_debug_sections
> > > >  };
> > > > Index: early-lto-debug/libiberty/simple-object.c
> > > > ===================================================================
> > > > --- early-lto-debug.orig/libiberty/simple-object.c	2016-10-19 13:19:58.012326431 +0200
> > > > +++ early-lto-debug/libiberty/simple-object.c	2016-10-20 13:58:11.722714041 +0200
> > > > @@ -22,6 +22,7 @@ Boston, MA 02110-1301, USA.  */
> > > >  #include "simple-object.h"
> > > >  
> > > >  #include <errno.h>
> > > > +#include <fcntl.h>
> > > >  
> > > >  #ifdef HAVE_STDLIB_H
> > > >  #include <stdlib.h>
> > > > @@ -249,6 +250,86 @@ simple_object_find_section (simple_objec
> > > >    return 1;
> > > >  }
> > > >  
> > > > +/* Callback to identify and rename LTO debug sections by name.
> > > > +   Returns 1 if NAME is a LTO debug section, 0 if not.  */
> > > > +
> > > > +static int
> > > > +handle_lto_debug_sections (const char **name)
> > > > +{
> > > > +  /* ???  So we can't use .gnu.lto_ prefixed sections as the assembler
> > > > +     complains about bogus section flags.  Which means we need to arrange
> > > > +     for that to be fixed or .gnu.debuglto_ marked as SHF_EXCLUDE (to make
> > > > +     fat lto object tooling work for the fat part).  */
> > > > +  /* ???  For now this handles both .gnu.lto_ and .gnu.debuglto_ prefixed
> > > > +     sections.  */
> > > > +  /* Copy LTO debug sections and rename them to their non-LTO name.  */
> > > > +  if (strncmp (*name, ".gnu.debuglto_", sizeof (".gnu.debuglto_") - 1) == 0)
> > > > +    {
> > > > +      *name = *name + sizeof (".gnu.debuglto_") - 1;
> > > > +      return 1;
> > > > +    }
> > > > +  else if (strncmp (*name, ".gnu.lto_.debug_", sizeof (".gnu.lto_.debug_") -1) == 0)
> > > > +    {
> > > > +      *name = *name + sizeof (".gnu.lto_") - 1;
> > > > +      return 1;
> > > > +    }
> > > > +  return 0;
> > > > +}
> > > > +
> > > > +/* Copy LTO debug sections.  */
> > > > +
> > > > +const char *
> > > > +simple_object_copy_lto_debug_sections (simple_object_read *sobj,
> > > > +				       const char *dest, int *err)
> > > > +{
> > > > +  const char *errmsg;
> > > > +  simple_object_write *dest_sobj;
> > > > +  simple_object_attributes *attrs;
> > > > +  int outfd;
> > > > +
> > > > +  if (! sobj->functions->copy_lto_debug_sections)
> > > > +    {
> > > > +      *err = EINVAL;
> > > > +      return "simple_object_copy_lto_debug_sections not implemented";
> > > > +    }
> > > > +
> > > > +  attrs = simple_object_fetch_attributes (sobj, &errmsg, err);
> > > > +  if (! attrs)
> > > > +    return errmsg;
> > > > +  dest_sobj = simple_object_start_write (attrs, NULL, &errmsg, err);
> > > > +  simple_object_release_attributes (attrs);
> > > > +  if (! dest_sobj)
> > > > +    return errmsg;
> > > > +
> > > > +  errmsg = sobj->functions->copy_lto_debug_sections (sobj, dest_sobj,
> > > > +						     handle_lto_debug_sections,
> > > > +						     err);
> > > > +  if (errmsg)
> > > > +    {
> > > > +      simple_object_release_write (dest_sobj);
> > > > +      return errmsg;
> > > > +    }
> > > > +
> > > > +  outfd = creat (dest, 00777);
> > > > +  if (outfd == -1)
> > > > +    {
> > > > +      *err = errno;
> > > > +      simple_object_release_write (dest_sobj);
> > > > +      return "open failed";
> > > > +    }
> > > > +
> > > > +  errmsg = simple_object_write_to_file (dest_sobj, outfd, err);
> > > > +  close (outfd);
> > > > +  if (errmsg)
> > > > +    {
> > > > +      simple_object_release_write (dest_sobj);
> > > > +      return errmsg;
> > > > +    }
> > > > +
> > > > +  simple_object_release_write (dest_sobj);
> > > > +  return NULL;
> > > > +}
> > > > +
> > > >  /* Fetch attributes.  */
> > > >  
> > > >  simple_object_attributes *
> > > > @@ -315,7 +396,7 @@ simple_object_start_write (simple_object
> > > >      return NULL;
> > > >    ret = XNEW (simple_object_write);
> > > >    ret->functions = attrs->functions;
> > > > -  ret->segment_name = xstrdup (segment_name);
> > > > +  ret->segment_name = segment_name ? xstrdup (segment_name) : NULL;
> > > >    ret->sections = NULL;
> > > >    ret->last_section = NULL;
> > > >    ret->data = data;
> > > > Index: early-lto-debug/libiberty/simple-object-coff.c
> > > > ===================================================================
> > > > --- early-lto-debug.orig/libiberty/simple-object-coff.c	2016-10-19 13:19:58.012326431 +0200
> > > > +++ early-lto-debug/libiberty/simple-object-coff.c	2016-10-20 10:51:49.881723228 +0200
> > > > @@ -800,5 +800,6 @@ const struct simple_object_functions sim
> > > >    simple_object_coff_release_attributes,
> > > >    simple_object_coff_start_write,
> > > >    simple_object_coff_write_to_file,
> > > > -  simple_object_coff_release_write
> > > > +  simple_object_coff_release_write,
> > > > +  NULL
> > > >  };
> > > > Index: early-lto-debug/libiberty/simple-object-mach-o.c
> > > > ===================================================================
> > > > --- early-lto-debug.orig/libiberty/simple-object-mach-o.c	2016-10-19 13:19:58.012326431 +0200
> > > > +++ early-lto-debug/libiberty/simple-object-mach-o.c	2016-10-20 10:51:49.881723228 +0200
> > > > @@ -1374,5 +1374,6 @@ const struct simple_object_functions sim
> > > >    simple_object_mach_o_release_attributes,
> > > >    simple_object_mach_o_start_write,
> > > >    simple_object_mach_o_write_to_file,
> > > > -  simple_object_mach_o_release_write
> > > > +  simple_object_mach_o_release_write,
> > > > +  NULL
> > > >  };
> > > > Index: early-lto-debug/libiberty/simple-object-xcoff.c
> > > > ===================================================================
> > > > --- early-lto-debug.orig/libiberty/simple-object-xcoff.c	2016-10-19 13:19:58.012326431 +0200
> > > > +++ early-lto-debug/libiberty/simple-object-xcoff.c	2016-10-20 10:51:49.881723228 +0200
> > > > @@ -894,5 +894,6 @@ const struct simple_object_functions sim
> > > >    simple_object_xcoff_release_attributes,
> > > >    simple_object_xcoff_start_write,
> > > >    simple_object_xcoff_write_to_file,
> > > > -  simple_object_xcoff_release_write
> > > > +  simple_object_xcoff_release_write,
> > > > +  NULL
> > > >  };
> > > > 
> > > 
> > > 
> > 
> > 
> 
>
Jason Merrill July 28, 2017, 9:55 p.m. UTC | #5
On Fri, Jul 28, 2017 at 8:54 AM, Richard Biener <rguenther@suse.de> wrote:
> On Tue, 4 Jul 2017, Richard Biener wrote:
>
>> On Tue, 20 Jun 2017, Richard Biener wrote:
>>
>> > On Wed, 7 Jun 2017, Richard Biener wrote:
>> >
>> > > On Fri, 19 May 2017, Richard Biener wrote:
>> > >
>> > > >
>> > > > This is a repost (unchanged) of the simple-object ELF support for
>> > > > early LTO debug transfer from IL object to a separate debug-only object
>> > > > file.
>> > > >
>> > > > Bootstrapped and tested on x86_64-unknown-linux-gnu.
>> > >
>> > > Ping.
>> >
>> > Ping^2.
>>
>> Ping^3.
>
> Ping^4.  Adding some more global reviewers to CC.

Looking at it now, sorry for the delay.

Jason
Jason Merrill July 28, 2017, 9:58 p.m. UTC | #6
On 07/28/2017 05:55 PM, Jason Merrill wrote:
> On Fri, Jul 28, 2017 at 8:54 AM, Richard Biener <rguenther@suse.de> wrote:
>> On Tue, 4 Jul 2017, Richard Biener wrote:
>>
>>> On Tue, 20 Jun 2017, Richard Biener wrote:
>>>
>>>> On Wed, 7 Jun 2017, Richard Biener wrote:
>>>>
>>>>> On Fri, 19 May 2017, Richard Biener wrote:
>>>>>
>>>>>>
>>>>>> This is a repost (unchanged) of the simple-object ELF support for
>>>>>> early LTO debug transfer from IL object to a separate debug-only object
>>>>>> file.
>>>>>>
>>>>>> Bootstrapped and tested on x86_64-unknown-linux-gnu.
>>>>>
>>>>> Ping.
>>>>
>>>> Ping^2.
>>>
>>> Ping^3.
>>
>> Ping^4.  Adding some more global reviewers to CC.
> 
> Looking at it now, sorry for the delay.

Actually, the simple-object stuff is more Ian's area.  Looking at the 
other part.

Jason
Richard Biener Aug. 4, 2017, 12:25 p.m. UTC | #7
On Fri, 28 Jul 2017, Jason Merrill wrote:

> On 07/28/2017 05:55 PM, Jason Merrill wrote:
> > On Fri, Jul 28, 2017 at 8:54 AM, Richard Biener <rguenther@suse.de> wrote:
> > > On Tue, 4 Jul 2017, Richard Biener wrote:
> > > 
> > > > On Tue, 20 Jun 2017, Richard Biener wrote:
> > > > 
> > > > > On Wed, 7 Jun 2017, Richard Biener wrote:
> > > > > 
> > > > > > On Fri, 19 May 2017, Richard Biener wrote:
> > > > > > 
> > > > > > > 
> > > > > > > This is a repost (unchanged) of the simple-object ELF support for
> > > > > > > early LTO debug transfer from IL object to a separate debug-only
> > > > > > > object
> > > > > > > file.
> > > > > > > 
> > > > > > > Bootstrapped and tested on x86_64-unknown-linux-gnu.
> > > > > > 
> > > > > > Ping.
> > > > > 
> > > > > Ping^2.
> > > > 
> > > > Ping^3.
> > > 
> > > Ping^4.  Adding some more global reviewers to CC.
> > 
> > Looking at it now, sorry for the delay.
> 
> Actually, the simple-object stuff is more Ian's area.  Looking at the other
> part.

Ian, ping -- we're through with the other part
(https://gcc.gnu.org/ml/gcc-patches/2017-08/msg00374.html).  The
simple-object part is unchanged at

https://gcc.gnu.org/ml/gcc-patches/2017-05/msg01541.html

nearly unchanged from the post last year (which also includes 
some description):

https://gcc.gnu.org/ml/gcc-patches/2016-09/msg01292.html

Thanks,
Richard.
Richard Biener Aug. 14, 2017, 1:17 p.m. UTC | #8
On Fri, 4 Aug 2017, Richard Biener wrote:

> On Fri, 28 Jul 2017, Jason Merrill wrote:
> 
> > On 07/28/2017 05:55 PM, Jason Merrill wrote:
> > > On Fri, Jul 28, 2017 at 8:54 AM, Richard Biener <rguenther@suse.de> wrote:
> > > > On Tue, 4 Jul 2017, Richard Biener wrote:
> > > > 
> > > > > On Tue, 20 Jun 2017, Richard Biener wrote:
> > > > > 
> > > > > > On Wed, 7 Jun 2017, Richard Biener wrote:
> > > > > > 
> > > > > > > On Fri, 19 May 2017, Richard Biener wrote:
> > > > > > > 
> > > > > > > > 
> > > > > > > > This is a repost (unchanged) of the simple-object ELF support for
> > > > > > > > early LTO debug transfer from IL object to a separate debug-only
> > > > > > > > object
> > > > > > > > file.
> > > > > > > > 
> > > > > > > > Bootstrapped and tested on x86_64-unknown-linux-gnu.
> > > > > > > 
> > > > > > > Ping.
> > > > > > 
> > > > > > Ping^2.
> > > > > 
> > > > > Ping^3.
> > > > 
> > > > Ping^4.  Adding some more global reviewers to CC.
> > > 
> > > Looking at it now, sorry for the delay.
> > 
> > Actually, the simple-object stuff is more Ian's area.  Looking at the other
> > part.
> 
> Ian, ping -- we're through with the other part
> (https://gcc.gnu.org/ml/gcc-patches/2017-08/msg00374.html).  The
> simple-object part is unchanged at
> 
> https://gcc.gnu.org/ml/gcc-patches/2017-05/msg01541.html
> 
> nearly unchanged from the post last year (which also includes 
> some description):
> 
> https://gcc.gnu.org/ml/gcc-patches/2016-09/msg01292.html

Ian, ping again!  (trying now also with the e-mail listed in
MAINTAINERS)

https://gcc.gnu.org/ml/gcc-patches/2017-05/msg01541.html

Thanks,
Richard.

> Thanks,
> Richard.
Li, Pan2 via Gcc-patches Aug. 14, 2017, 5:49 p.m. UTC | #9
On Mon, Aug 14, 2017 at 6:17 AM, Richard Biener <rguenther@suse.de> wrote:
> On Fri, 4 Aug 2017, Richard Biener wrote:
>
>> On Fri, 28 Jul 2017, Jason Merrill wrote:
>>
>> > On 07/28/2017 05:55 PM, Jason Merrill wrote:
>> > > On Fri, Jul 28, 2017 at 8:54 AM, Richard Biener <rguenther@suse.de> wrote:
>> > > > On Tue, 4 Jul 2017, Richard Biener wrote:
>> > > >
>> > > > > On Tue, 20 Jun 2017, Richard Biener wrote:
>> > > > >
>> > > > > > On Wed, 7 Jun 2017, Richard Biener wrote:
>> > > > > >
>> > > > > > > On Fri, 19 May 2017, Richard Biener wrote:
>> > > > > > >
>> > > > > > > >
>> > > > > > > > This is a repost (unchanged) of the simple-object ELF support for
>> > > > > > > > early LTO debug transfer from IL object to a separate debug-only
>> > > > > > > > object
>> > > > > > > > file.
>> > > > > > > >
>> > > > > > > > Bootstrapped and tested on x86_64-unknown-linux-gnu.
>> > > > > > >
>> > > > > > > Ping.
>> > > > > >
>> > > > > > Ping^2.
>> > > > >
>> > > > > Ping^3.
>> > > >
>> > > > Ping^4.  Adding some more global reviewers to CC.
>> > >
>> > > Looking at it now, sorry for the delay.
>> >
>> > Actually, the simple-object stuff is more Ian's area.  Looking at the other
>> > part.
>>
>> Ian, ping -- we're through with the other part
>> (https://gcc.gnu.org/ml/gcc-patches/2017-08/msg00374.html).  The
>> simple-object part is unchanged at
>>
>> https://gcc.gnu.org/ml/gcc-patches/2017-05/msg01541.html
>>
>> nearly unchanged from the post last year (which also includes
>> some description):
>>
>> https://gcc.gnu.org/ml/gcc-patches/2016-09/msg01292.html
>
> Ian, ping again!  (trying now also with the e-mail listed in
> MAINTAINERS)
>
> https://gcc.gnu.org/ml/gcc-patches/2017-05/msg01541.html

Sorry about that, for some reason GMail didn't flag this message for me.


> +  for (ent = buf + entsize; ent < buf + length; ent += entsize)
> +    {
> +      unsigned sec = type_functions->fetch_Elf_Word (ent);
> +      if (pfnret[sec - 1] == 0)
> +         keep = 1;
> +    }
> +  if (keep)
> +    {
> +      pfnret[sh_link - 1] = 0;
> +      pfnret[i - 1] = 0;
> +    }
> + }

It seems to me that if you keep any section of an SHT_GROUP, you need
to keep all the sections.  Otherwise the section indexes in the group
will be left dangling.


The symbol table handling is pretty awful.  Can't you just remove the
symbols you don't want?  You will have to update the sh_info field of
the SHT_SYMTAB section, which holds the index of the first STB_GLOBAL
symbol in the table.

Ian
Richard Biener Aug. 15, 2017, 8:30 a.m. UTC | #10
On Mon, 14 Aug 2017, Ian Lance Taylor wrote:

> On Mon, Aug 14, 2017 at 6:17 AM, Richard Biener <rguenther@suse.de> wrote:
> > On Fri, 4 Aug 2017, Richard Biener wrote:
> >
> >> On Fri, 28 Jul 2017, Jason Merrill wrote:
> >>
> >> > On 07/28/2017 05:55 PM, Jason Merrill wrote:
> >> > > On Fri, Jul 28, 2017 at 8:54 AM, Richard Biener <rguenther@suse.de> wrote:
> >> > > > On Tue, 4 Jul 2017, Richard Biener wrote:
> >> > > >
> >> > > > > On Tue, 20 Jun 2017, Richard Biener wrote:
> >> > > > >
> >> > > > > > On Wed, 7 Jun 2017, Richard Biener wrote:
> >> > > > > >
> >> > > > > > > On Fri, 19 May 2017, Richard Biener wrote:
> >> > > > > > >
> >> > > > > > > >
> >> > > > > > > > This is a repost (unchanged) of the simple-object ELF support for
> >> > > > > > > > early LTO debug transfer from IL object to a separate debug-only
> >> > > > > > > > object
> >> > > > > > > > file.
> >> > > > > > > >
> >> > > > > > > > Bootstrapped and tested on x86_64-unknown-linux-gnu.
> >> > > > > > >
> >> > > > > > > Ping.
> >> > > > > >
> >> > > > > > Ping^2.
> >> > > > >
> >> > > > > Ping^3.
> >> > > >
> >> > > > Ping^4.  Adding some more global reviewers to CC.
> >> > >
> >> > > Looking at it now, sorry for the delay.
> >> >
> >> > Actually, the simple-object stuff is more Ian's area.  Looking at the other
> >> > part.
> >>
> >> Ian, ping -- we're through with the other part
> >> (https://gcc.gnu.org/ml/gcc-patches/2017-08/msg00374.html).  The
> >> simple-object part is unchanged at
> >>
> >> https://gcc.gnu.org/ml/gcc-patches/2017-05/msg01541.html
> >>
> >> nearly unchanged from the post last year (which also includes
> >> some description):
> >>
> >> https://gcc.gnu.org/ml/gcc-patches/2016-09/msg01292.html
> >
> > Ian, ping again!  (trying now also with the e-mail listed in
> > MAINTAINERS)
> >
> > https://gcc.gnu.org/ml/gcc-patches/2017-05/msg01541.html
> 
> Sorry about that, for some reason GMail didn't flag this message for me.
> 
> 
> > +  for (ent = buf + entsize; ent < buf + length; ent += entsize)
> > +    {
> > +      unsigned sec = type_functions->fetch_Elf_Word (ent);
> > +      if (pfnret[sec - 1] == 0)
> > +         keep = 1;
> > +    }
> > +  if (keep)
> > +    {
> > +      pfnret[sh_link - 1] = 0;
> > +      pfnret[i - 1] = 0;
> > +    }
> > + }
> 
> It seems to me that if you keep any section of an SHT_GROUP, you need
> to keep all the sections.  Otherwise the section indexes in the group
> will be left dangling.

Note that all sections are "kept", removed sections are just marked
as SHT_NULL.  Which means that indeed some group members might
be SHT_NULL.

Note that I don't remember if I actually run into any SHT_GROUP
member being necessary when another is not (IIRC this was with
debug types sections or so).  I'll double-check and add a comment
where this matters for early-debug (the simple-object code tries
to be more generic but obviously all testing was done with
early-debug section copying in mind).

> The symbol table handling is pretty awful.  Can't you just remove the
> symbols you don't want?  You will have to update the sh_info field of
> the SHT_SYMTAB section, which holds the index of the first STB_GLOBAL
> symbol in the table.

Maybe that's what I was missing, let me see if I can make it work.
It looks like if there's no STB_GLOBAL symbol the index is one after
the last symbol and it seems it is the first ! STB_LOCAL symbol
("One greater than the symbol table index of the last local symbol 
(binding STB_LOCAL)").

Ah, and implementing this now I remember why I chose the "awkward"
way.  This was to preserve symtab indices to not need to rewrite
relocation sections...  There isn't a documented way to make
an "none" symtab entry (eventually duplicating UND might work
but IIRC it messes up ordering as UND is STB_LOCAL and thus may
not appear after the first ! STB_LOCAL symbol).  As comments in
the code indicate I tried to mangle things in a way that makes
both GNU ld and gold happy...

Any suggestion how to improve things when not removing symbols?
(I could of course remove things from the end of the symtab)
Like replacing local symbols with UND and globals with
a COMMON of zero size (and no name)?

I suppose rewriting relocation sections is possible but I tried
to do as little as necessary (like not actually removing sections).

Thanks,
Richard.
Li, Pan2 via Gcc-patches Aug. 15, 2017, 12:48 p.m. UTC | #11
On Tue, Aug 15, 2017 at 1:30 AM, Richard Biener <rguenther@suse.de> wrote:
> On Mon, 14 Aug 2017, Ian Lance Taylor wrote:
>
>> It seems to me that if you keep any section of an SHT_GROUP, you need
>> to keep all the sections.  Otherwise the section indexes in the group
>> will be left dangling.
>
> Note that all sections are "kept", removed sections are just marked
> as SHT_NULL.  Which means that indeed some group members might
> be SHT_NULL.
>
> Note that I don't remember if I actually run into any SHT_GROUP
> member being necessary when another is not (IIRC this was with
> debug types sections or so).  I'll double-check and add a comment
> where this matters for early-debug (the simple-object code tries
> to be more generic but obviously all testing was done with
> early-debug section copying in mind).

In general they are SHT_GROUP for a reason, that reason being that if
you keep one of the group sections you need to keep all of them.  If
that didn't matter, there wouldn't be a SHT_GROUP section at all.  So
I think it would be appropriate that if you keep one of a group you
keep all of the group.


>> The symbol table handling is pretty awful.  Can't you just remove the
>> symbols you don't want?  You will have to update the sh_info field of
>> the SHT_SYMTAB section, which holds the index of the first STB_GLOBAL
>> symbol in the table.
>
> Maybe that's what I was missing, let me see if I can make it work.
> It looks like if there's no STB_GLOBAL symbol the index is one after
> the last symbol and it seems it is the first ! STB_LOCAL symbol
> ("One greater than the symbol table index of the last local symbol
> (binding STB_LOCAL)").
>
> Ah, and implementing this now I remember why I chose the "awkward"
> way.  This was to preserve symtab indices to not need to rewrite
> relocation sections...  There isn't a documented way to make
> an "none" symtab entry (eventually duplicating UND might work
> but IIRC it messes up ordering as UND is STB_LOCAL and thus may
> not appear after the first ! STB_LOCAL symbol).  As comments in
> the code indicate I tried to mangle things in a way that makes
> both GNU ld and gold happy...

Bother.

> Any suggestion how to improve things when not removing symbols?
> (I could of course remove things from the end of the symtab)
> Like replacing local symbols with UND and globals with
> a COMMON of zero size (and no name)?

You can have a UND global symbol, after all.  You just shouldn't
simply zero out the entire symbol, as that will indeed change the
binding to STB_LOCAL.  So probably the best approach is to change
every unwanted symbol to SHN_UNDEF, keep the binding as is, and zero
all the other fields.  That should let the linker simply discard the
symbol, I hope.

> I suppose rewriting relocation sections is possible but I tried
> to do as little as necessary (like not actually removing sections).

The patch is OK with the above suggestions, assuming they work.

Ian
Richard Biener Aug. 15, 2017, 12:51 p.m. UTC | #12
On Tue, 15 Aug 2017, Richard Biener wrote:

> On Mon, 14 Aug 2017, Ian Lance Taylor wrote:
> 
> > On Mon, Aug 14, 2017 at 6:17 AM, Richard Biener <rguenther@suse.de> wrote:
> > > On Fri, 4 Aug 2017, Richard Biener wrote:
> > >
> > >> On Fri, 28 Jul 2017, Jason Merrill wrote:
> > >>
> > >> > On 07/28/2017 05:55 PM, Jason Merrill wrote:
> > >> > > On Fri, Jul 28, 2017 at 8:54 AM, Richard Biener <rguenther@suse.de> wrote:
> > >> > > > On Tue, 4 Jul 2017, Richard Biener wrote:
> > >> > > >
> > >> > > > > On Tue, 20 Jun 2017, Richard Biener wrote:
> > >> > > > >
> > >> > > > > > On Wed, 7 Jun 2017, Richard Biener wrote:
> > >> > > > > >
> > >> > > > > > > On Fri, 19 May 2017, Richard Biener wrote:
> > >> > > > > > >
> > >> > > > > > > >
> > >> > > > > > > > This is a repost (unchanged) of the simple-object ELF support for
> > >> > > > > > > > early LTO debug transfer from IL object to a separate debug-only
> > >> > > > > > > > object
> > >> > > > > > > > file.
> > >> > > > > > > >
> > >> > > > > > > > Bootstrapped and tested on x86_64-unknown-linux-gnu.
> > >> > > > > > >
> > >> > > > > > > Ping.
> > >> > > > > >
> > >> > > > > > Ping^2.
> > >> > > > >
> > >> > > > > Ping^3.
> > >> > > >
> > >> > > > Ping^4.  Adding some more global reviewers to CC.
> > >> > >
> > >> > > Looking at it now, sorry for the delay.
> > >> >
> > >> > Actually, the simple-object stuff is more Ian's area.  Looking at the other
> > >> > part.
> > >>
> > >> Ian, ping -- we're through with the other part
> > >> (https://gcc.gnu.org/ml/gcc-patches/2017-08/msg00374.html).  The
> > >> simple-object part is unchanged at
> > >>
> > >> https://gcc.gnu.org/ml/gcc-patches/2017-05/msg01541.html
> > >>
> > >> nearly unchanged from the post last year (which also includes
> > >> some description):
> > >>
> > >> https://gcc.gnu.org/ml/gcc-patches/2016-09/msg01292.html
> > >
> > > Ian, ping again!  (trying now also with the e-mail listed in
> > > MAINTAINERS)
> > >
> > > https://gcc.gnu.org/ml/gcc-patches/2017-05/msg01541.html
> > 
> > Sorry about that, for some reason GMail didn't flag this message for me.
> > 
> > 
> > > +  for (ent = buf + entsize; ent < buf + length; ent += entsize)
> > > +    {
> > > +      unsigned sec = type_functions->fetch_Elf_Word (ent);
> > > +      if (pfnret[sec - 1] == 0)
> > > +         keep = 1;
> > > +    }
> > > +  if (keep)
> > > +    {
> > > +      pfnret[sh_link - 1] = 0;
> > > +      pfnret[i - 1] = 0;
> > > +    }
> > > + }
> > 
> > It seems to me that if you keep any section of an SHT_GROUP, you need
> > to keep all the sections.  Otherwise the section indexes in the group
> > will be left dangling.
> 
> Note that all sections are "kept", removed sections are just marked
> as SHT_NULL.  Which means that indeed some group members might
> be SHT_NULL.
> 
> Note that I don't remember if I actually run into any SHT_GROUP
> member being necessary when another is not (IIRC this was with
> debug types sections or so).  I'll double-check and add a comment
> where this matters for early-debug (the simple-object code tries
> to be more generic but obviously all testing was done with
> early-debug section copying in mind).

That said, the callback is supposed to mark interesting stuff as not
deleted.  The simple-object interface is only giving some leeway
to simplify things (pulling in the container, directly dependent
sections) to generate a valid ELF output.

> > The symbol table handling is pretty awful.  Can't you just remove the
> > symbols you don't want?  You will have to update the sh_info field of
> > the SHT_SYMTAB section, which holds the index of the first STB_GLOBAL
> > symbol in the table.
> 
> Maybe that's what I was missing, let me see if I can make it work.
> It looks like if there's no STB_GLOBAL symbol the index is one after
> the last symbol and it seems it is the first ! STB_LOCAL symbol
> ("One greater than the symbol table index of the last local symbol 
> (binding STB_LOCAL)").
> 
> Ah, and implementing this now I remember why I chose the "awkward"
> way.  This was to preserve symtab indices to not need to rewrite
> relocation sections...  There isn't a documented way to make
> an "none" symtab entry (eventually duplicating UND might work
> but IIRC it messes up ordering as UND is STB_LOCAL and thus may
> not appear after the first ! STB_LOCAL symbol).  As comments in
> the code indicate I tried to mangle things in a way that makes
> both GNU ld and gold happy...
> 
> Any suggestion how to improve things when not removing symbols?
> (I could of course remove things from the end of the symtab)
> Like replacing local symbols with UND and globals with
> a COMMON of zero size (and no name)?
> 
> I suppose rewriting relocation sections is possible but I tried
> to do as little as necessary (like not actually removing sections).

So the following is an update which changes how I remove symbols
by making removed locals copies of UND and removed globals
global commons of size zero:

Symbol table '.symtab' contains 22 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     1: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS t.c
     2: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     3: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     4: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     5: 0000000000000000     0 SECTION LOCAL  DEFAULT    4 
     6: 0000000000000000     0 SECTION LOCAL  DEFAULT    6 
     7: 0000000000000000     0 SECTION LOCAL  DEFAULT    7 
     8: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND 
...
    18: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND 
    19: 0000000000000000     0 NOTYPE  WEAK   HIDDEN     4 t.c.39a678c9
    20: 0000000000000000     0 OBJECT  GLOBAL DEFAULT  COM 
    21: 0000000000000000     0 OBJECT  GLOBAL DEFAULT  COM 

Does that look better?

Smoke-tested on x86_64-unknown-linux-gnu.

Ok for trunk?

Thanks,
Richard.

2017-06-15  Richard Biener  <rguenther@suse.de>

	include/
	* simple-object.h (simple_object_copy_lto_debug_sections): New
	function.

	libiberty/
	* simple-object-common.h (struct simple_object_functions): Add
	copy_lto_debug_sections hook.
	* simple-object.c: Include fcntl.h.
	(handle_lto_debug_sections): New helper function.
	(simple_object_copy_lto_debug_sections): New function copying
	early LTO debug sections to regular debug sections in a new file.
	(simple_object_start_write): Handle NULL segment_name.
	* simple-object-coff.c (simple_object_coff_functions): Adjust
	for not implemented copy_lto_debug_sections hook.
	* simple-object-mach-o.c (simple_object_mach_o_functions): Likewise.
	* simple-object-xcoff.c (simple_object_xcoff_functions): Likewise.
	* simple-object-elf.c (SHT_NULL, SHT_SYMTAB, SHT_RELA, SHT_REL,
	SHT_GROUP): Add various sectopn header types.
	(SHF_EXCLUDE): Add flag.
	(Elf32_External_Sym, Elf64_External_Sym): Add symbol struct.
	(ELF_ST_BIND, ELF_ST_TYPE, ELF_ST_INFO): Add accessors.
	(STT_OBJECT, STT_FUNC, STT_TLS, STT_GNU_IFUNC): Add Symbol types.
	(STV_DEFAULT): Add symbol visibility.
	(SHN_COMMON): Add special section index name.
	(struct simple_object_elf_write): New.
	(simple_object_elf_start_write): Adjust for new private data.
	(simple_object_elf_write_shdr): Pass in values for all fields
	we write.
	(simple_object_elf_write_to_file): Adjust.  Copy from recorded
	section headers if requested.
	(simple_object_elf_release_write): Release private data.
	(simple_object_elf_copy_lto_debug_sections): Copy and rename sections
	as denoted by PFN and all their dependences, symbols and relocations
	to the empty destination file.
	(simple_object_elf_functions): Adjust for copy_lto_debug_sections hook.

Index: early-lto-debug/include/simple-object.h
===================================================================
*** early-lto-debug.orig/include/simple-object.h	2017-08-15 12:25:07.078117298 +0200
--- early-lto-debug/include/simple-object.h	2017-08-15 12:27:26.520468153 +0200
*************** simple_object_write_to_file (simple_obje
*** 197,202 ****
--- 197,210 ----
  extern void
  simple_object_release_write (simple_object_write *);
  
+ /* Copy LTO debug sections from SRC_OBJECT to DEST.
+    If an error occurs, return the errno value in ERR and an error string.  */
+ 
+ extern const char *
+ simple_object_copy_lto_debug_sections (simple_object_read *src_object,
+ 				       const char *dest,
+ 				       int *err);
+ 
  #ifdef __cplusplus
  }
  #endif
Index: early-lto-debug/libiberty/simple-object-common.h
===================================================================
*** early-lto-debug.orig/libiberty/simple-object-common.h	2017-08-15 12:25:07.078117298 +0200
--- early-lto-debug/libiberty/simple-object-common.h	2017-08-15 12:27:26.524468220 +0200
*************** struct simple_object_functions
*** 141,146 ****
--- 141,152 ----
  
    /* Release the private data for an simple_object_write.  */
    void (*release_write) (void *);
+ 
+   /* Copy LTO debug sections.  */
+   const char *(*copy_lto_debug_sections) (simple_object_read *sobj,
+ 					  simple_object_write *dobj,
+ 					  int (*pfn) (const char **),
+ 					  int *err);
  };
  
  /* The known object file formats.  */
Index: early-lto-debug/libiberty/simple-object-elf.c
===================================================================
*** early-lto-debug.orig/libiberty/simple-object-elf.c	2017-08-15 12:25:07.078117298 +0200
--- early-lto-debug/libiberty/simple-object-elf.c	2017-08-15 14:42:06.404490972 +0200
*************** typedef struct {
*** 122,130 ****
--- 122,133 ----
  
  /* Special section index values.  */
  
+ #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_XINDEX	0xFFFF		/* Section index is held elsewhere */
  
+ 
  /* 32-bit ELF program header.  */
  
  typedef struct {
*************** typedef struct {
*** 183,190 ****
--- 186,242 ----
  
  /* Values for sh_type field.  */
  
+ #define SHT_NULL	0		/* Section header table entry unused */
  #define SHT_PROGBITS	1		/* Program data */
+ #define SHT_SYMTAB	2		/* Link editing symbol table */
  #define SHT_STRTAB	3		/* A string table */
+ #define SHT_RELA	4		/* Relocation entries with addends */
+ #define SHT_REL		9		/* Relocation entries, no addends */
+ #define SHT_GROUP	17		/* Section contains a section group */
+ 
+ /* Values for sh_flags field.  */
+ 
+ #define SHF_EXCLUDE	0x80000000	/* Link editor is to exclude this
+ 					   section from executable and
+ 					   shared library that it builds
+ 					   when those objects are not to be
+ 					   further relocated.  */
+ /* Symbol table entry.  */
+ 
+ typedef struct
+ {
+   unsigned char st_name[4];                /* Symbol name (string tbl index) */
+   unsigned char st_value[4];               /* Symbol value */
+   unsigned char st_size[4];                /* Symbol size */
+   unsigned char st_info;                /* Symbol type and binding */
+   unsigned char st_other;               /* Symbol visibility */
+   unsigned char st_shndx[2];               /* Section index */
+ } Elf32_External_Sym;
+ 
+ typedef struct
+ {
+   unsigned char st_name[4];                /* Symbol name (string tbl index) */
+   unsigned char st_info;                /* Symbol type and binding */
+   unsigned char st_other;               /* Symbol visibility */
+   unsigned char st_shndx[2];               /* Section index */
+   unsigned char st_value[8];               /* Symbol value */
+   unsigned char st_size[8];                /* Symbol size */
+ } Elf64_External_Sym;
+ 
+ #define ELF_ST_BIND(val)              (((unsigned char) (val)) >> 4)
+ #define ELF_ST_TYPE(val)              ((val) & 0xf)
+ #define ELF_ST_INFO(bind, type)       (((bind) << 4) + ((type) & 0xf))
+ 
+ #define STT_NOTYPE	0	/* Symbol type is unspecified */
+ #define STT_OBJECT	1	/* Symbol is a data object */
+ #define STT_FUNC	2	/* Symbol is a code object */
+ #define STT_TLS		6	/* Thread local data object */
+ #define STT_GNU_IFUNC	10	/* Symbol is an indirect code object */
+ 
+ #define STB_LOCAL	0	/* Local symbol */
+ #define STB_GLOBAL	1	/* Global symbol */
+ 
+ #define STV_DEFAULT	0	/* Visibility is specified by binding type */
  
  /* Functions to fetch and store different ELF types, depending on the
     endianness and size.  */
*************** struct simple_object_elf_attributes
*** 348,353 ****
--- 400,413 ----
    unsigned int flags;
  };
  
+ /* Private data for an simple_object_write.  */
+ 
+ struct simple_object_elf_write
+ {
+   struct simple_object_elf_attributes attrs;
+   unsigned char *shdrs;
+ };
+ 
  /* See if we have an ELF file.  */
  
  static void *
*************** simple_object_elf_start_write (void *att
*** 675,686 ****
  {
    struct simple_object_elf_attributes *attrs =
      (struct simple_object_elf_attributes *) attributes_data;
!   struct simple_object_elf_attributes *ret;
  
    /* We're just going to record the attributes, but we need to make a
       copy because the user may delete them.  */
!   ret = XNEW (struct simple_object_elf_attributes);
!   *ret = *attrs;
    return ret;
  }
  
--- 735,747 ----
  {
    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
       copy because the user may delete them.  */
!   ret = XNEW (struct simple_object_elf_write);
!   ret->attrs = *attrs;
!   ret->shdrs = NULL;
    return ret;
  }
  
*************** static int
*** 766,773 ****
  simple_object_elf_write_shdr (simple_object_write *sobj, int descriptor,
  			      off_t offset, unsigned int sh_name,
  			      unsigned int sh_type, unsigned int sh_flags,
  			      unsigned int sh_offset, unsigned int sh_size,
! 			      unsigned int sh_link, unsigned int sh_addralign,
  			      const char **errmsg, int *err)
  {
    struct simple_object_elf_attributes *attrs =
--- 827,837 ----
  simple_object_elf_write_shdr (simple_object_write *sobj, int descriptor,
  			      off_t offset, unsigned int sh_name,
  			      unsigned int sh_type, unsigned int sh_flags,
+ 			      off_t sh_addr,
  			      unsigned int sh_offset, unsigned int sh_size,
! 			      unsigned int sh_link, unsigned int sh_info,
! 			      unsigned int sh_addralign,
! 			      unsigned int sh_entsize,
  			      const char **errmsg, int *err)
  {
    struct simple_object_elf_attributes *attrs =
*************** simple_object_elf_write_shdr (simple_obj
*** 788,799 ****
    ELF_SET_FIELD (fns, cl, Shdr, buf, sh_name, Elf_Word, sh_name);
    ELF_SET_FIELD (fns, cl, Shdr, buf, sh_type, Elf_Word, sh_type);
    ELF_SET_FIELD (fns, cl, Shdr, buf, sh_flags, Elf_Addr, sh_flags);
    ELF_SET_FIELD (fns, cl, Shdr, buf, sh_offset, Elf_Addr, sh_offset);
    ELF_SET_FIELD (fns, cl, Shdr, buf, sh_size, Elf_Addr, sh_size);
    ELF_SET_FIELD (fns, cl, Shdr, buf, sh_link, Elf_Word, sh_link);
!   /* sh_info left as zero.  */
    ELF_SET_FIELD (fns, cl, Shdr, buf, sh_addralign, Elf_Addr, sh_addralign);
!   /* sh_entsize left as zero.  */
  
    return simple_object_internal_write (descriptor, offset, buf, shdr_size,
  				       errmsg, err);
--- 852,864 ----
    ELF_SET_FIELD (fns, cl, Shdr, buf, sh_name, Elf_Word, sh_name);
    ELF_SET_FIELD (fns, cl, Shdr, buf, sh_type, Elf_Word, sh_type);
    ELF_SET_FIELD (fns, cl, Shdr, buf, sh_flags, Elf_Addr, sh_flags);
+   ELF_SET_FIELD (fns, cl, Shdr, buf, sh_addr, Elf_Addr, sh_addr);
    ELF_SET_FIELD (fns, cl, Shdr, buf, sh_offset, Elf_Addr, sh_offset);
    ELF_SET_FIELD (fns, cl, Shdr, buf, sh_size, Elf_Addr, sh_size);
    ELF_SET_FIELD (fns, cl, Shdr, buf, sh_link, Elf_Word, sh_link);
!   ELF_SET_FIELD (fns, cl, Shdr, buf, sh_info, Elf_Word, sh_info);
    ELF_SET_FIELD (fns, cl, Shdr, buf, sh_addralign, Elf_Addr, sh_addralign);
!   ELF_SET_FIELD (fns, cl, Shdr, buf, sh_entsize, Elf_Word, sh_entsize);
  
    return simple_object_internal_write (descriptor, offset, buf, shdr_size,
  				       errmsg, err);
*************** static const char *
*** 811,818 ****
  simple_object_elf_write_to_file (simple_object_write *sobj, int descriptor,
  				 int *err)
  {
!   struct simple_object_elf_attributes *attrs =
!     (struct simple_object_elf_attributes *) sobj->data;
    unsigned char cl;
    size_t ehdr_size;
    size_t shdr_size;
--- 876,884 ----
  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_attributes *attrs = &eow->attrs;
    unsigned char cl;
    size_t ehdr_size;
    size_t shdr_size;
*************** simple_object_elf_write_to_file (simple_
*** 825,830 ****
--- 891,897 ----
    unsigned int first_sh_link;
    size_t sh_name;
    unsigned char zero;
+   unsigned secnum;
  
    if (!simple_object_elf_write_ehdr (sobj, descriptor, &errmsg, err))
      return errmsg;
*************** simple_object_elf_write_to_file (simple_
*** 862,882 ****
    else
      first_sh_link = shnum - 1;
    if (!simple_object_elf_write_shdr (sobj, descriptor, shdr_offset,
! 				     0, 0, 0, 0, first_sh_size, first_sh_link,
! 				     0, &errmsg, err))
      return errmsg;
  
    shdr_offset += shdr_size;
  
    sh_name = 1;
    for (section = sobj->sections; section != NULL; section = section->next)
      {
        size_t mask;
        size_t new_sh_offset;
        size_t sh_size;
        struct simple_object_write_section_buffer *buffer;
  
!       mask = (1U << section->align) - 1;
        new_sh_offset = sh_offset + mask;
        new_sh_offset &= ~ mask;
        while (new_sh_offset > sh_offset)
--- 929,982 ----
    else
      first_sh_link = shnum - 1;
    if (!simple_object_elf_write_shdr (sobj, descriptor, shdr_offset,
! 				     0, 0, 0, 0, 0, first_sh_size, first_sh_link,
! 				     0, 0, 0, &errmsg, err))
      return errmsg;
  
    shdr_offset += shdr_size;
  
    sh_name = 1;
+   secnum = 0;
    for (section = sobj->sections; section != NULL; section = section->next)
      {
        size_t mask;
        size_t new_sh_offset;
        size_t sh_size;
        struct simple_object_write_section_buffer *buffer;
+       unsigned int sh_type = SHT_PROGBITS;
+       unsigned int sh_flags = 0;
+       off_t sh_addr = 0;
+       unsigned int sh_link = 0;
+       unsigned int sh_info = 0;
+       unsigned int sh_addralign = 1U << section->align;
+       unsigned int sh_entsize = 0;
+       if (eow->shdrs)
+ 	{
+ 	  sh_type = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
+ 				     eow->shdrs + secnum * shdr_size,
+ 				     sh_type, Elf_Word);
+ 	  sh_flags = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
+ 				      eow->shdrs + secnum * shdr_size,
+ 				      sh_flags, Elf_Addr);
+ 	  sh_addr = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
+ 				     eow->shdrs + secnum * shdr_size,
+ 				     sh_addr, Elf_Addr);
+ 	  sh_link = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
+ 				     eow->shdrs + secnum * shdr_size,
+ 				     sh_link, Elf_Word);
+ 	  sh_info = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
+ 				     eow->shdrs + secnum * shdr_size,
+ 				     sh_info, Elf_Word);
+ 	  sh_addralign = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
+ 					  eow->shdrs + secnum * shdr_size,
+ 					  sh_addralign, Elf_Addr);
+ 	  sh_entsize = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
+ 					eow->shdrs + secnum * shdr_size,
+ 					sh_entsize, Elf_Word);
+ 	  secnum++;
+ 	}
  
!       mask = sh_addralign - 1;
        new_sh_offset = sh_offset + mask;
        new_sh_offset &= ~ mask;
        while (new_sh_offset > sh_offset)
*************** simple_object_elf_write_to_file (simple_
*** 906,913 ****
  	}
  
        if (!simple_object_elf_write_shdr (sobj, descriptor, shdr_offset,
! 					 sh_name, SHT_PROGBITS, 0, sh_offset,
! 					 sh_size, 0, 1U << section->align,
  					 &errmsg, err))
  	return errmsg;
  
--- 1006,1015 ----
  	}
  
        if (!simple_object_elf_write_shdr (sobj, descriptor, shdr_offset,
! 					 sh_name, sh_type, sh_flags,
! 					 sh_addr, sh_offset,
! 					 sh_size, sh_link, sh_info,
! 					 sh_addralign, sh_entsize,
  					 &errmsg, err))
  	return errmsg;
  
*************** simple_object_elf_write_to_file (simple_
*** 917,925 ****
      }
  
    if (!simple_object_elf_write_shdr (sobj, descriptor, shdr_offset,
! 				     sh_name, SHT_STRTAB, 0, sh_offset,
! 				     sh_name + strlen (".shstrtab") + 1, 0,
! 				     1, &errmsg, err))
      return errmsg;
  
    /* .shstrtab has a leading zero byte.  */
--- 1019,1027 ----
      }
  
    if (!simple_object_elf_write_shdr (sobj, descriptor, shdr_offset,
! 				     sh_name, SHT_STRTAB, 0, 0, sh_offset,
! 				     sh_name + strlen (".shstrtab") + 1, 0, 0,
! 				     1, 0, &errmsg, err))
      return errmsg;
  
    /* .shstrtab has a leading zero byte.  */
*************** simple_object_elf_write_to_file (simple_
*** 954,962 ****
--- 1056,1422 ----
  static void
  simple_object_elf_release_write (void *data)
  {
+   struct simple_object_elf_write *eow = (struct simple_object_elf_write *) data;
+   if (eow->shdrs)
+     XDELETE (eow->shdrs);
    XDELETE (data);
  }
  
+ /* Copy all sections in an ELF file.  */
+ 
+ static const char *
+ simple_object_elf_copy_lto_debug_sections (simple_object_read *sobj,
+ 					   simple_object_write *dobj,
+ 					   int (*pfn) (const char **),
+ 					   int *err)
+ {
+   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;
+   unsigned char ei_class = eor->ei_class;
+   size_t shdr_size;
+   unsigned int shnum;
+   unsigned char *shdrs;
+   const char *errmsg;
+   unsigned char *shstrhdr;
+   size_t name_size;
+   off_t shstroff;
+   unsigned char *names;
+   unsigned int i;
+   int *pfnret;
+   const char **pfnname;
+ 
+   shdr_size = (ei_class == ELFCLASS32
+ 	       ? sizeof (Elf32_External_Shdr)
+ 	       : sizeof (Elf64_External_Shdr));
+ 
+   /* Read the section headers.  We skip section 0, which is not a
+      useful section.  */
+ 
+   shnum = eor->shnum;
+   shdrs = XNEWVEC (unsigned char, shdr_size * (shnum - 1));
+ 
+   if (!simple_object_internal_read (sobj->descriptor,
+ 				    sobj->offset + eor->shoff + shdr_size,
+ 				    shdrs,
+ 				    shdr_size * (shnum - 1),
+ 				    &errmsg, err))
+     {
+       XDELETEVEC (shdrs);
+       return errmsg;
+     }
+ 
+   /* Read the section names.  */
+ 
+   shstrhdr = shdrs + (eor->shstrndx - 1) * shdr_size;
+   name_size = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ 			       shstrhdr, sh_size, Elf_Addr);
+   shstroff = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ 			      shstrhdr, sh_offset, Elf_Addr);
+   names = XNEWVEC (unsigned char, name_size);
+   if (!simple_object_internal_read (sobj->descriptor,
+ 				    sobj->offset + shstroff,
+ 				    names, name_size, &errmsg, err))
+     {
+       XDELETEVEC (names);
+       XDELETEVEC (shdrs);
+       return errmsg;
+     }
+ 
+   eow->shdrs = XNEWVEC (unsigned char, shdr_size * (shnum - 1));
+   pfnret = XNEWVEC (int, shnum);
+   pfnname = XNEWVEC (const char *, shnum);
+ 
+   /* First perform the callbacks to know which sections to preserve and
+      what name to use for those.  */
+   for (i = 1; i < shnum; ++i)
+     {
+       unsigned char *shdr;
+       unsigned int sh_name;
+       const char *name;
+       int ret;
+ 
+       shdr = shdrs + (i - 1) * shdr_size;
+       sh_name = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ 				 shdr, sh_name, Elf_Word);
+       if (sh_name >= name_size)
+ 	{
+ 	  *err = 0;
+ 	  XDELETEVEC (names);
+ 	  XDELETEVEC (shdrs);
+ 	  return "ELF section name out of range";
+ 	}
+ 
+       name = (const char *) names + sh_name;
+ 
+       ret = (*pfn) (&name);
+       pfnret[i - 1] = ret == 1 ? 0 : -1;
+       pfnname[i - 1] = name;
+     }
+ 
+   /* Mark sections as preserved that are required by to be preserved
+      sections.  */
+   for (i = 1; i < shnum; ++i)
+     {
+       unsigned char *shdr;
+       unsigned int sh_type, sh_info, sh_link;
+       off_t offset;
+       off_t length;
+ 
+       shdr = shdrs + (i - 1) * shdr_size;
+       sh_type = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ 				 shdr, sh_type, Elf_Word);
+       sh_info = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ 				 shdr, sh_info, Elf_Word);
+       sh_link = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ 				 shdr, sh_link, Elf_Word);
+       if (sh_type == SHT_GROUP)
+ 	{
+ 	  /* Mark groups containing copied sections.  */
+ 	  unsigned entsize = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ 					      shdr, sh_entsize, Elf_Addr);
+ 	  unsigned char *ent, *buf;
+ 	  int keep = 0;
+ 	  offset = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ 				    shdr, sh_offset, Elf_Addr);
+ 	  length = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ 				    shdr, sh_size, Elf_Addr);
+ 	  buf = XNEWVEC (unsigned char, length);
+ 	  if (!simple_object_internal_read (sobj->descriptor,
+ 					    sobj->offset + offset, buf,
+ 					    (size_t) length, &errmsg, err))
+ 	    {
+ 	      XDELETEVEC (buf);
+ 	      XDELETEVEC (names);
+ 	      XDELETEVEC (shdrs);
+ 	      return errmsg;
+ 	    }
+ 	  for (ent = buf + entsize; ent < buf + length; ent += entsize)
+ 	    {
+ 	      unsigned sec = type_functions->fetch_Elf_Word (ent);
+ 	      if (pfnret[sec - 1] == 0)
+ 		keep = 1;
+ 	    }
+ 	  if (keep)
+ 	    {
+ 	      pfnret[sh_link - 1] = 0;
+ 	      pfnret[i - 1] = 0;
+ 	    }
+ 	}
+       if (sh_type == SHT_RELA
+ 	  || sh_type == SHT_REL)
+ 	{
+ 	  /* Mark relocation sections and symtab of copied sections.  */
+ 	  if (pfnret[sh_info - 1] == 0)
+ 	    {
+ 	      pfnret[sh_link - 1] = 0;
+ 	      pfnret[i - 1] = 0;
+ 	    }
+ 	}
+       if (sh_type == SHT_SYMTAB)
+ 	{
+ 	  /* Mark strings sections of copied symtabs.  */
+ 	  if (pfnret[i - 1] == 0)
+ 	    pfnret[sh_link - 1] = 0;
+ 	}
+     }
+ 
+   /* Then perform the actual copying.  */
+   for (i = 1; i < shnum; ++i)
+     {
+       unsigned char *shdr;
+       unsigned int sh_name, sh_type;
+       const char *name;
+       off_t offset;
+       off_t length;
+       int ret;
+       const char *errmsg;
+       simple_object_write_section *dest;
+       off_t flags;
+       unsigned char *buf;
+ 
+       shdr = shdrs + (i - 1) * shdr_size;
+       sh_name = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ 				 shdr, sh_name, Elf_Word);
+       if (sh_name >= name_size)
+ 	{
+ 	  *err = 0;
+ 	  XDELETEVEC (names);
+ 	  XDELETEVEC (shdrs);
+ 	  return "ELF section name out of range";
+ 	}
+ 
+       name = (const char *) names + sh_name;
+       offset = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ 				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);
+ 
+       ret = pfnret[i - 1];
+       name = ret == 0 ? pfnname[i - 1] : "";
+ 
+       dest = simple_object_write_create_section (dobj, name, 0, &errmsg, err);
+       if (dest == NULL)
+ 	{
+ 	  XDELETEVEC (names);
+ 	  XDELETEVEC (shdrs);
+ 	  return errmsg;
+ 	}
+ 
+       /* Record the SHDR of the source.  */
+       memcpy (eow->shdrs + (i - 1) * shdr_size, shdr, shdr_size);
+       shdr = eow->shdrs + (i - 1) * shdr_size;
+ 
+       /* Copy the data.
+ 	 ???  This is quite wasteful and ideally would be delayed until
+ 	 write_to_file ().  Thus it questions the interfacing
+ 	 which eventually should contain destination creation plus
+ 	 writing.  */
+       /* Keep empty sections for sections we should discard.  This avoids
+          the need to rewrite section indices in symtab and relocation
+ 	 sections.  */
+       if (ret == 0)
+ 	{
+ 	  buf = XNEWVEC (unsigned char, length);
+ 	  if (!simple_object_internal_read (sobj->descriptor,
+ 					    sobj->offset + offset, buf,
+ 					    (size_t) length, &errmsg, err))
+ 	    {
+ 	      XDELETEVEC (buf);
+ 	      XDELETEVEC (names);
+ 	      XDELETEVEC (shdrs);
+ 	      return errmsg;
+ 	    }
+ 
+ 	  /* If we are processing .symtab purge __gnu_lto_v1 and
+ 	     __gnu_lto_slim symbols from it.  */
+ 	  if (sh_type == SHT_SYMTAB)
+ 	    {
+ 	      unsigned entsize = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ 						  shdr, sh_entsize, Elf_Addr);
+ 	      unsigned strtab = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ 						 shdr, sh_link, Elf_Word);
+ 	      unsigned char *strshdr = shdrs + (strtab - 1) * shdr_size;
+ 	      off_t stroff = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ 					      strshdr, sh_offset, Elf_Addr);
+ 	      size_t strsz = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ 					      strshdr, sh_size, Elf_Addr);
+ 	      char *strings = XNEWVEC (char, strsz);
+ 	      unsigned char *ent;
+ 	      simple_object_internal_read (sobj->descriptor,
+ 					   sobj->offset + stroff,
+ 					   (unsigned char *)strings,
+ 					   strsz, &errmsg, err);
+ 	      for (ent = buf; ent < buf + length; ent += entsize)
+ 		{
+ 		  unsigned st_shndx = ELF_FETCH_FIELD (type_functions, ei_class,
+ 						       Sym, ent,
+ 						       st_shndx, Elf_Half);
+ 		  unsigned char *st_info;
+ 		  unsigned char *st_other;
+ 		  int discard = 0;
+ 		  if (ei_class == ELFCLASS32)
+ 		    {
+ 		      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;
+ 		    }
+ 		  /* Eliminate all COMMONs - this includes __gnu_lto_v1
+ 		     and __gnu_lto_slim which otherwise cause endless
+ 		     LTO plugin invocation.  */
+ 		  if (st_shndx == SHN_COMMON)
+ 		    /* Setting st_name to "" seems to work to purge
+ 		       COMMON symbols (in addition to setting their
+ 		       size to zero).  */
+ 		    discard = 1;
+ 		  /* We also need to remove symbols refering to sections
+ 		     we'll eventually remove as with fat LTO objects
+ 		     we otherwise get duplicate symbols at final link
+ 		     (with GNU ld, gold is fine and ignores symbols in
+ 		     sections marked as EXCLUDE).  ld/20513  */
+ 		  else if (st_shndx != SHN_UNDEF
+ 			   && st_shndx < shnum
+ 			   && pfnret[st_shndx - 1] == -1)
+ 		    discard = 1;
+ 
+ 		  if (discard)
+ 		    {
+ 		      /* For all purged symbols make the symbol unnamed.  */
+ 		      ELF_SET_FIELD (type_functions, ei_class, Sym,
+ 				     ent, st_name, Elf_Word, 0);
+ 		      /* At least set st_value and st_size to zero to not go
+ 			 out of bounds.  */
+ 		      ELF_SET_FIELD (type_functions, ei_class, Sym,
+ 				     ent, st_value, Elf_Addr, 0);
+ 		      ELF_SET_FIELD (type_functions, ei_class, Sym,
+ 				     ent, st_size, Elf_Word, 0);
+ 		      *st_other = STV_DEFAULT;
+ 		      if (ELF_ST_BIND (*st_info) == STB_LOCAL)
+ 			{
+ 			  /* Make discarded STB_LOCAL symbols copy of UND.  */
+ 			  ELF_SET_FIELD (type_functions, ei_class, Sym,
+ 					 ent, st_shndx, Elf_Half, SHN_UNDEF);
+ 			  *st_info = ELF_ST_INFO (STB_LOCAL, STT_NOTYPE);
+ 			}
+ 		      else
+ 			{
+ 			  /* Make discarded global symbols zero-sized
+ 			     commons.  */
+ 			  ELF_SET_FIELD (type_functions, ei_class, Sym,
+ 					 ent, st_shndx, Elf_Half, SHN_COMMON);
+ 			  *st_info = ELF_ST_INFO (STB_GLOBAL, STT_OBJECT);
+ 			}
+ 		    }
+ 		}
+ 	      XDELETEVEC (strings);
+ 	    }
+ 
+ 	  errmsg = simple_object_write_add_data (dobj, dest,
+ 						 buf, length, 1, err);
+ 	  XDELETEVEC (buf);
+ 	  if (errmsg)
+ 	    {
+ 	      XDELETEVEC (names);
+ 	      XDELETEVEC (shdrs);
+ 	      return errmsg;
+ 	    }
+ 	}
+       else
+ 	{
+ 	  /* For deleted sections mark the section header table entry as
+ 	     unused.  That allows the link editor to remove it in a partial
+ 	     link.  */
+ 	  ELF_SET_FIELD (type_functions, ei_class, Shdr,
+ 			 shdr, sh_type, Elf_Addr, SHT_NULL);
+ 	}
+ 
+       flags = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ 			       shdr, sh_flags, Elf_Addr);
+       if (ret == 0)
+ 	flags &= ~SHF_EXCLUDE;
+       else if (ret == -1)
+ 	flags |= SHF_EXCLUDE;
+       ELF_SET_FIELD (type_functions, ei_class, Shdr,
+ 		     shdr, sh_flags, Elf_Addr, flags);
+     }
+ 
+   XDELETEVEC (names);
+   XDELETEVEC (shdrs);
+   XDELETEVEC (pfnret);
+   XDELETEVEC (pfnname);
+ 
+   return NULL;
+ }
+ 
+ 
  /* The ELF functions.  */
  
  const struct simple_object_functions simple_object_elf_functions =
*************** const struct simple_object_functions sim
*** 969,973 ****
    simple_object_elf_release_attributes,
    simple_object_elf_start_write,
    simple_object_elf_write_to_file,
!   simple_object_elf_release_write
  };
--- 1429,1434 ----
    simple_object_elf_release_attributes,
    simple_object_elf_start_write,
    simple_object_elf_write_to_file,
!   simple_object_elf_release_write,
!   simple_object_elf_copy_lto_debug_sections
  };
Index: early-lto-debug/libiberty/simple-object.c
===================================================================
*** early-lto-debug.orig/libiberty/simple-object.c	2017-08-15 12:25:07.078117298 +0200
--- early-lto-debug/libiberty/simple-object.c	2017-08-15 12:27:26.524468220 +0200
*************** Boston, MA 02110-1301, USA.  */
*** 22,27 ****
--- 22,28 ----
  #include "simple-object.h"
  
  #include <errno.h>
+ #include <fcntl.h>
  
  #ifdef HAVE_STDLIB_H
  #include <stdlib.h>
*************** simple_object_find_section (simple_objec
*** 249,254 ****
--- 250,335 ----
    return 1;
  }
  
+ /* Callback to identify and rename LTO debug sections by name.
+    Returns 1 if NAME is a LTO debug section, 0 if not.  */
+ 
+ static int
+ handle_lto_debug_sections (const char **name)
+ {
+   /* ???  So we can't use .gnu.lto_ prefixed sections as the assembler
+      complains about bogus section flags.  Which means we need to arrange
+      for that to be fixed or .gnu.debuglto_ marked as SHF_EXCLUDE (to make
+      fat lto object tooling work for the fat part).  */
+   /* ???  For now this handles both .gnu.lto_ and .gnu.debuglto_ prefixed
+      sections.  */
+   /* Copy LTO debug sections and rename them to their non-LTO name.  */
+   if (strncmp (*name, ".gnu.debuglto_", sizeof (".gnu.debuglto_") - 1) == 0)
+     {
+       *name = *name + sizeof (".gnu.debuglto_") - 1;
+       return 1;
+     }
+   else if (strncmp (*name, ".gnu.lto_.debug_", sizeof (".gnu.lto_.debug_") -1) == 0)
+     {
+       *name = *name + sizeof (".gnu.lto_") - 1;
+       return 1;
+     }
+   return 0;
+ }
+ 
+ /* Copy LTO debug sections.  */
+ 
+ const char *
+ simple_object_copy_lto_debug_sections (simple_object_read *sobj,
+ 				       const char *dest, int *err)
+ {
+   const char *errmsg;
+   simple_object_write *dest_sobj;
+   simple_object_attributes *attrs;
+   int outfd;
+ 
+   if (! sobj->functions->copy_lto_debug_sections)
+     {
+       *err = EINVAL;
+       return "simple_object_copy_lto_debug_sections not implemented";
+     }
+ 
+   attrs = simple_object_fetch_attributes (sobj, &errmsg, err);
+   if (! attrs)
+     return errmsg;
+   dest_sobj = simple_object_start_write (attrs, NULL, &errmsg, err);
+   simple_object_release_attributes (attrs);
+   if (! dest_sobj)
+     return errmsg;
+ 
+   errmsg = sobj->functions->copy_lto_debug_sections (sobj, dest_sobj,
+ 						     handle_lto_debug_sections,
+ 						     err);
+   if (errmsg)
+     {
+       simple_object_release_write (dest_sobj);
+       return errmsg;
+     }
+ 
+   outfd = creat (dest, 00777);
+   if (outfd == -1)
+     {
+       *err = errno;
+       simple_object_release_write (dest_sobj);
+       return "open failed";
+     }
+ 
+   errmsg = simple_object_write_to_file (dest_sobj, outfd, err);
+   close (outfd);
+   if (errmsg)
+     {
+       simple_object_release_write (dest_sobj);
+       return errmsg;
+     }
+ 
+   simple_object_release_write (dest_sobj);
+   return NULL;
+ }
+ 
  /* Fetch attributes.  */
  
  simple_object_attributes *
*************** simple_object_start_write (simple_object
*** 315,321 ****
      return NULL;
    ret = XNEW (simple_object_write);
    ret->functions = attrs->functions;
!   ret->segment_name = xstrdup (segment_name);
    ret->sections = NULL;
    ret->last_section = NULL;
    ret->data = data;
--- 396,402 ----
      return NULL;
    ret = XNEW (simple_object_write);
    ret->functions = attrs->functions;
!   ret->segment_name = segment_name ? xstrdup (segment_name) : NULL;
    ret->sections = NULL;
    ret->last_section = NULL;
    ret->data = data;
Index: early-lto-debug/libiberty/simple-object-coff.c
===================================================================
*** early-lto-debug.orig/libiberty/simple-object-coff.c	2017-08-15 12:25:07.078117298 +0200
--- early-lto-debug/libiberty/simple-object-coff.c	2017-08-15 12:27:26.524468220 +0200
*************** const struct simple_object_functions sim
*** 800,804 ****
    simple_object_coff_release_attributes,
    simple_object_coff_start_write,
    simple_object_coff_write_to_file,
!   simple_object_coff_release_write
  };
--- 800,805 ----
    simple_object_coff_release_attributes,
    simple_object_coff_start_write,
    simple_object_coff_write_to_file,
!   simple_object_coff_release_write,
!   NULL
  };
Index: early-lto-debug/libiberty/simple-object-mach-o.c
===================================================================
*** early-lto-debug.orig/libiberty/simple-object-mach-o.c	2017-08-15 12:25:07.078117298 +0200
--- early-lto-debug/libiberty/simple-object-mach-o.c	2017-08-15 12:27:26.524468220 +0200
*************** const struct simple_object_functions sim
*** 1374,1378 ****
    simple_object_mach_o_release_attributes,
    simple_object_mach_o_start_write,
    simple_object_mach_o_write_to_file,
!   simple_object_mach_o_release_write
  };
--- 1374,1379 ----
    simple_object_mach_o_release_attributes,
    simple_object_mach_o_start_write,
    simple_object_mach_o_write_to_file,
!   simple_object_mach_o_release_write,
!   NULL
  };
Index: early-lto-debug/libiberty/simple-object-xcoff.c
===================================================================
*** early-lto-debug.orig/libiberty/simple-object-xcoff.c	2017-08-15 12:25:07.078117298 +0200
--- early-lto-debug/libiberty/simple-object-xcoff.c	2017-08-15 12:27:26.524468220 +0200
*************** const struct simple_object_functions sim
*** 1006,1010 ****
    simple_object_xcoff_release_attributes,
    simple_object_xcoff_start_write,
    simple_object_xcoff_write_to_file,
!   simple_object_xcoff_release_write
  };
--- 1006,1011 ----
    simple_object_xcoff_release_attributes,
    simple_object_xcoff_start_write,
    simple_object_xcoff_write_to_file,
!   simple_object_xcoff_release_write,
!   NULL
  };
Li, Pan2 via Gcc-patches Aug. 15, 2017, 12:55 p.m. UTC | #13
On Tue, Aug 15, 2017 at 5:51 AM, Richard Biener <rguenther@suse.de> wrote:
> On Tue, 15 Aug 2017, Richard Biener wrote:
>
>> On Mon, 14 Aug 2017, Ian Lance Taylor wrote:
>>
>> > On Mon, Aug 14, 2017 at 6:17 AM, Richard Biener <rguenther@suse.de> wrote:
>> > > On Fri, 4 Aug 2017, Richard Biener wrote:
>> > >
>> > >> On Fri, 28 Jul 2017, Jason Merrill wrote:
>> > >>
>> > >> > On 07/28/2017 05:55 PM, Jason Merrill wrote:
>> > >> > > On Fri, Jul 28, 2017 at 8:54 AM, Richard Biener <rguenther@suse.de> wrote:
>> > >> > > > On Tue, 4 Jul 2017, Richard Biener wrote:
>> > >> > > >
>> > >> > > > > On Tue, 20 Jun 2017, Richard Biener wrote:
>> > >> > > > >
>> > >> > > > > > On Wed, 7 Jun 2017, Richard Biener wrote:
>> > >> > > > > >
>> > >> > > > > > > On Fri, 19 May 2017, Richard Biener wrote:
>> > >> > > > > > >
>> > >> > > > > > > >
>> > >> > > > > > > > This is a repost (unchanged) of the simple-object ELF support for
>> > >> > > > > > > > early LTO debug transfer from IL object to a separate debug-only
>> > >> > > > > > > > object
>> > >> > > > > > > > file.
>> > >> > > > > > > >
>> > >> > > > > > > > Bootstrapped and tested on x86_64-unknown-linux-gnu.
>> > >> > > > > > >
>> > >> > > > > > > Ping.
>> > >> > > > > >
>> > >> > > > > > Ping^2.
>> > >> > > > >
>> > >> > > > > Ping^3.
>> > >> > > >
>> > >> > > > Ping^4.  Adding some more global reviewers to CC.
>> > >> > >
>> > >> > > Looking at it now, sorry for the delay.
>> > >> >
>> > >> > Actually, the simple-object stuff is more Ian's area.  Looking at the other
>> > >> > part.
>> > >>
>> > >> Ian, ping -- we're through with the other part
>> > >> (https://gcc.gnu.org/ml/gcc-patches/2017-08/msg00374.html).  The
>> > >> simple-object part is unchanged at
>> > >>
>> > >> https://gcc.gnu.org/ml/gcc-patches/2017-05/msg01541.html
>> > >>
>> > >> nearly unchanged from the post last year (which also includes
>> > >> some description):
>> > >>
>> > >> https://gcc.gnu.org/ml/gcc-patches/2016-09/msg01292.html
>> > >
>> > > Ian, ping again!  (trying now also with the e-mail listed in
>> > > MAINTAINERS)
>> > >
>> > > https://gcc.gnu.org/ml/gcc-patches/2017-05/msg01541.html
>> >
>> > Sorry about that, for some reason GMail didn't flag this message for me.
>> >
>> >
>> > > +  for (ent = buf + entsize; ent < buf + length; ent += entsize)
>> > > +    {
>> > > +      unsigned sec = type_functions->fetch_Elf_Word (ent);
>> > > +      if (pfnret[sec - 1] == 0)
>> > > +         keep = 1;
>> > > +    }
>> > > +  if (keep)
>> > > +    {
>> > > +      pfnret[sh_link - 1] = 0;
>> > > +      pfnret[i - 1] = 0;
>> > > +    }
>> > > + }
>> >
>> > It seems to me that if you keep any section of an SHT_GROUP, you need
>> > to keep all the sections.  Otherwise the section indexes in the group
>> > will be left dangling.
>>
>> Note that all sections are "kept", removed sections are just marked
>> as SHT_NULL.  Which means that indeed some group members might
>> be SHT_NULL.
>>
>> Note that I don't remember if I actually run into any SHT_GROUP
>> member being necessary when another is not (IIRC this was with
>> debug types sections or so).  I'll double-check and add a comment
>> where this matters for early-debug (the simple-object code tries
>> to be more generic but obviously all testing was done with
>> early-debug section copying in mind).
>
> That said, the callback is supposed to mark interesting stuff as not
> deleted.  The simple-object interface is only giving some leeway
> to simplify things (pulling in the container, directly dependent
> sections) to generate a valid ELF output.
>
>> > The symbol table handling is pretty awful.  Can't you just remove the
>> > symbols you don't want?  You will have to update the sh_info field of
>> > the SHT_SYMTAB section, which holds the index of the first STB_GLOBAL
>> > symbol in the table.
>>
>> Maybe that's what I was missing, let me see if I can make it work.
>> It looks like if there's no STB_GLOBAL symbol the index is one after
>> the last symbol and it seems it is the first ! STB_LOCAL symbol
>> ("One greater than the symbol table index of the last local symbol
>> (binding STB_LOCAL)").
>>
>> Ah, and implementing this now I remember why I chose the "awkward"
>> way.  This was to preserve symtab indices to not need to rewrite
>> relocation sections...  There isn't a documented way to make
>> an "none" symtab entry (eventually duplicating UND might work
>> but IIRC it messes up ordering as UND is STB_LOCAL and thus may
>> not appear after the first ! STB_LOCAL symbol).  As comments in
>> the code indicate I tried to mangle things in a way that makes
>> both GNU ld and gold happy...
>>
>> Any suggestion how to improve things when not removing symbols?
>> (I could of course remove things from the end of the symtab)
>> Like replacing local symbols with UND and globals with
>> a COMMON of zero size (and no name)?
>>
>> I suppose rewriting relocation sections is possible but I tried
>> to do as little as necessary (like not actually removing sections).
>
> So the following is an update which changes how I remove symbols
> by making removed locals copies of UND and removed globals
> global commons of size zero:
>
> Symbol table '.symtab' contains 22 entries:
>    Num:    Value          Size Type    Bind   Vis      Ndx Name
>      0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND
>      1: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS t.c
>      2: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND
>      3: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND
>      4: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND
>      5: 0000000000000000     0 SECTION LOCAL  DEFAULT    4
>      6: 0000000000000000     0 SECTION LOCAL  DEFAULT    6
>      7: 0000000000000000     0 SECTION LOCAL  DEFAULT    7
>      8: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND
> ...
>     18: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND
>     19: 0000000000000000     0 NOTYPE  WEAK   HIDDEN     4 t.c.39a678c9
>     20: 0000000000000000     0 OBJECT  GLOBAL DEFAULT  COM
>     21: 0000000000000000     0 OBJECT  GLOBAL DEFAULT  COM
>
> Does that look better?

As noted in crossing message, I think SHN_UNDEF is better than
SHN_COMMON.  Patch is OK with that change, assuming that works.

Ian
Richard Biener Aug. 15, 2017, 1:04 p.m. UTC | #14
On Tue, 15 Aug 2017, Ian Lance Taylor wrote:

> On Tue, Aug 15, 2017 at 5:51 AM, Richard Biener <rguenther@suse.de> wrote:
> > On Tue, 15 Aug 2017, Richard Biener wrote:
> >
> >> On Mon, 14 Aug 2017, Ian Lance Taylor wrote:
> >>
> >> > On Mon, Aug 14, 2017 at 6:17 AM, Richard Biener <rguenther@suse.de> wrote:
> >> > > On Fri, 4 Aug 2017, Richard Biener wrote:
> >> > >
> >> > >> On Fri, 28 Jul 2017, Jason Merrill wrote:
> >> > >>
> >> > >> > On 07/28/2017 05:55 PM, Jason Merrill wrote:
> >> > >> > > On Fri, Jul 28, 2017 at 8:54 AM, Richard Biener <rguenther@suse.de> wrote:
> >> > >> > > > On Tue, 4 Jul 2017, Richard Biener wrote:
> >> > >> > > >
> >> > >> > > > > On Tue, 20 Jun 2017, Richard Biener wrote:
> >> > >> > > > >
> >> > >> > > > > > On Wed, 7 Jun 2017, Richard Biener wrote:
> >> > >> > > > > >
> >> > >> > > > > > > On Fri, 19 May 2017, Richard Biener wrote:
> >> > >> > > > > > >
> >> > >> > > > > > > >
> >> > >> > > > > > > > This is a repost (unchanged) of the simple-object ELF support for
> >> > >> > > > > > > > early LTO debug transfer from IL object to a separate debug-only
> >> > >> > > > > > > > object
> >> > >> > > > > > > > file.
> >> > >> > > > > > > >
> >> > >> > > > > > > > Bootstrapped and tested on x86_64-unknown-linux-gnu.
> >> > >> > > > > > >
> >> > >> > > > > > > Ping.
> >> > >> > > > > >
> >> > >> > > > > > Ping^2.
> >> > >> > > > >
> >> > >> > > > > Ping^3.
> >> > >> > > >
> >> > >> > > > Ping^4.  Adding some more global reviewers to CC.
> >> > >> > >
> >> > >> > > Looking at it now, sorry for the delay.
> >> > >> >
> >> > >> > Actually, the simple-object stuff is more Ian's area.  Looking at the other
> >> > >> > part.
> >> > >>
> >> > >> Ian, ping -- we're through with the other part
> >> > >> (https://gcc.gnu.org/ml/gcc-patches/2017-08/msg00374.html).  The
> >> > >> simple-object part is unchanged at
> >> > >>
> >> > >> https://gcc.gnu.org/ml/gcc-patches/2017-05/msg01541.html
> >> > >>
> >> > >> nearly unchanged from the post last year (which also includes
> >> > >> some description):
> >> > >>
> >> > >> https://gcc.gnu.org/ml/gcc-patches/2016-09/msg01292.html
> >> > >
> >> > > Ian, ping again!  (trying now also with the e-mail listed in
> >> > > MAINTAINERS)
> >> > >
> >> > > https://gcc.gnu.org/ml/gcc-patches/2017-05/msg01541.html
> >> >
> >> > Sorry about that, for some reason GMail didn't flag this message for me.
> >> >
> >> >
> >> > > +  for (ent = buf + entsize; ent < buf + length; ent += entsize)
> >> > > +    {
> >> > > +      unsigned sec = type_functions->fetch_Elf_Word (ent);
> >> > > +      if (pfnret[sec - 1] == 0)
> >> > > +         keep = 1;
> >> > > +    }
> >> > > +  if (keep)
> >> > > +    {
> >> > > +      pfnret[sh_link - 1] = 0;
> >> > > +      pfnret[i - 1] = 0;
> >> > > +    }
> >> > > + }
> >> >
> >> > It seems to me that if you keep any section of an SHT_GROUP, you need
> >> > to keep all the sections.  Otherwise the section indexes in the group
> >> > will be left dangling.
> >>
> >> Note that all sections are "kept", removed sections are just marked
> >> as SHT_NULL.  Which means that indeed some group members might
> >> be SHT_NULL.
> >>
> >> Note that I don't remember if I actually run into any SHT_GROUP
> >> member being necessary when another is not (IIRC this was with
> >> debug types sections or so).  I'll double-check and add a comment
> >> where this matters for early-debug (the simple-object code tries
> >> to be more generic but obviously all testing was done with
> >> early-debug section copying in mind).
> >
> > That said, the callback is supposed to mark interesting stuff as not
> > deleted.  The simple-object interface is only giving some leeway
> > to simplify things (pulling in the container, directly dependent
> > sections) to generate a valid ELF output.
> >
> >> > The symbol table handling is pretty awful.  Can't you just remove the
> >> > symbols you don't want?  You will have to update the sh_info field of
> >> > the SHT_SYMTAB section, which holds the index of the first STB_GLOBAL
> >> > symbol in the table.
> >>
> >> Maybe that's what I was missing, let me see if I can make it work.
> >> It looks like if there's no STB_GLOBAL symbol the index is one after
> >> the last symbol and it seems it is the first ! STB_LOCAL symbol
> >> ("One greater than the symbol table index of the last local symbol
> >> (binding STB_LOCAL)").
> >>
> >> Ah, and implementing this now I remember why I chose the "awkward"
> >> way.  This was to preserve symtab indices to not need to rewrite
> >> relocation sections...  There isn't a documented way to make
> >> an "none" symtab entry (eventually duplicating UND might work
> >> but IIRC it messes up ordering as UND is STB_LOCAL and thus may
> >> not appear after the first ! STB_LOCAL symbol).  As comments in
> >> the code indicate I tried to mangle things in a way that makes
> >> both GNU ld and gold happy...
> >>
> >> Any suggestion how to improve things when not removing symbols?
> >> (I could of course remove things from the end of the symtab)
> >> Like replacing local symbols with UND and globals with
> >> a COMMON of zero size (and no name)?
> >>
> >> I suppose rewriting relocation sections is possible but I tried
> >> to do as little as necessary (like not actually removing sections).
> >
> > So the following is an update which changes how I remove symbols
> > by making removed locals copies of UND and removed globals
> > global commons of size zero:
> >
> > Symbol table '.symtab' contains 22 entries:
> >    Num:    Value          Size Type    Bind   Vis      Ndx Name
> >      0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND
> >      1: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS t.c
> >      2: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND
> >      3: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND
> >      4: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND
> >      5: 0000000000000000     0 SECTION LOCAL  DEFAULT    4
> >      6: 0000000000000000     0 SECTION LOCAL  DEFAULT    6
> >      7: 0000000000000000     0 SECTION LOCAL  DEFAULT    7
> >      8: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND
> > ...
> >     18: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND
> >     19: 0000000000000000     0 NOTYPE  WEAK   HIDDEN     4 t.c.39a678c9
> >     20: 0000000000000000     0 OBJECT  GLOBAL DEFAULT  COM
> >     21: 0000000000000000     0 OBJECT  GLOBAL DEFAULT  COM
> >
> > Does that look better?
> 
> As noted in crossing message, I think SHN_UNDEF is better than
> SHN_COMMON.  Patch is OK with that change, assuming that works.

Seems to work:

...
    19: 0000000000000000     0 NOTYPE  WEAK   HIDDEN     4 t.c.39a678c9
    20: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND 
    21: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND 

LTO bootstrap with that in progress, I'll commit the patch series
once sourceware stabilized.

Thanks,
Richard.

2017-06-15  Richard Biener  <rguenther@suse.de>

	include/
	* simple-object.h (simple_object_copy_lto_debug_sections): New
	function.

	libiberty/
	* simple-object-common.h (struct simple_object_functions): Add
	copy_lto_debug_sections hook.
	* simple-object.c: Include fcntl.h.
	(handle_lto_debug_sections): New helper function.
	(simple_object_copy_lto_debug_sections): New function copying
	early LTO debug sections to regular debug sections in a new file.
	(simple_object_start_write): Handle NULL segment_name.
	* simple-object-coff.c (simple_object_coff_functions): Adjust
	for not implemented copy_lto_debug_sections hook.
	* simple-object-mach-o.c (simple_object_mach_o_functions): Likewise.
	* simple-object-xcoff.c (simple_object_xcoff_functions): Likewise.
	* simple-object-elf.c (SHT_NULL, SHT_SYMTAB, SHT_RELA, SHT_REL,
	SHT_GROUP): Add various sectopn header types.
	(SHF_EXCLUDE): Add flag.
	(Elf32_External_Sym, Elf64_External_Sym): Add symbol struct.
	(ELF_ST_BIND, ELF_ST_TYPE, ELF_ST_INFO): Add accessors.
	(STT_OBJECT, STT_FUNC, STT_TLS, STT_GNU_IFUNC): Add Symbol types.
	(STV_DEFAULT): Add symbol visibility.
	(SHN_COMMON): Add special section index name.
	(struct simple_object_elf_write): New.
	(simple_object_elf_start_write): Adjust for new private data.
	(simple_object_elf_write_shdr): Pass in values for all fields
	we write.
	(simple_object_elf_write_to_file): Adjust.  Copy from recorded
	section headers if requested.
	(simple_object_elf_release_write): Release private data.
	(simple_object_elf_copy_lto_debug_sections): Copy and rename sections
	as denoted by PFN and all their dependences, symbols and relocations
	to the empty destination file.
	(simple_object_elf_functions): Adjust for copy_lto_debug_sections hook.

Index: early-lto-debug/include/simple-object.h
===================================================================
*** early-lto-debug.orig/include/simple-object.h	2017-08-15 12:25:07.078117298 +0200
--- early-lto-debug/include/simple-object.h	2017-08-15 12:27:26.520468153 +0200
*************** simple_object_write_to_file (simple_obje
*** 197,202 ****
--- 197,210 ----
  extern void
  simple_object_release_write (simple_object_write *);
  
+ /* Copy LTO debug sections from SRC_OBJECT to DEST.
+    If an error occurs, return the errno value in ERR and an error string.  */
+ 
+ extern const char *
+ simple_object_copy_lto_debug_sections (simple_object_read *src_object,
+ 				       const char *dest,
+ 				       int *err);
+ 
  #ifdef __cplusplus
  }
  #endif
Index: early-lto-debug/libiberty/simple-object-common.h
===================================================================
*** early-lto-debug.orig/libiberty/simple-object-common.h	2017-08-15 12:25:07.078117298 +0200
--- early-lto-debug/libiberty/simple-object-common.h	2017-08-15 12:27:26.524468220 +0200
*************** struct simple_object_functions
*** 141,146 ****
--- 141,152 ----
  
    /* Release the private data for an simple_object_write.  */
    void (*release_write) (void *);
+ 
+   /* Copy LTO debug sections.  */
+   const char *(*copy_lto_debug_sections) (simple_object_read *sobj,
+ 					  simple_object_write *dobj,
+ 					  int (*pfn) (const char **),
+ 					  int *err);
  };
  
  /* The known object file formats.  */
Index: early-lto-debug/libiberty/simple-object-elf.c
===================================================================
*** early-lto-debug.orig/libiberty/simple-object-elf.c	2017-08-15 12:25:07.078117298 +0200
--- early-lto-debug/libiberty/simple-object-elf.c	2017-08-15 15:00:46.987720830 +0200
*************** typedef struct {
*** 122,130 ****
--- 122,133 ----
  
  /* Special section index values.  */
  
+ #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_XINDEX	0xFFFF		/* Section index is held elsewhere */
  
+ 
  /* 32-bit ELF program header.  */
  
  typedef struct {
*************** typedef struct {
*** 183,190 ****
--- 186,242 ----
  
  /* Values for sh_type field.  */
  
+ #define SHT_NULL	0		/* Section header table entry unused */
  #define SHT_PROGBITS	1		/* Program data */
+ #define SHT_SYMTAB	2		/* Link editing symbol table */
  #define SHT_STRTAB	3		/* A string table */
+ #define SHT_RELA	4		/* Relocation entries with addends */
+ #define SHT_REL		9		/* Relocation entries, no addends */
+ #define SHT_GROUP	17		/* Section contains a section group */
+ 
+ /* Values for sh_flags field.  */
+ 
+ #define SHF_EXCLUDE	0x80000000	/* Link editor is to exclude this
+ 					   section from executable and
+ 					   shared library that it builds
+ 					   when those objects are not to be
+ 					   further relocated.  */
+ /* Symbol table entry.  */
+ 
+ typedef struct
+ {
+   unsigned char st_name[4];                /* Symbol name (string tbl index) */
+   unsigned char st_value[4];               /* Symbol value */
+   unsigned char st_size[4];                /* Symbol size */
+   unsigned char st_info;                /* Symbol type and binding */
+   unsigned char st_other;               /* Symbol visibility */
+   unsigned char st_shndx[2];               /* Section index */
+ } Elf32_External_Sym;
+ 
+ typedef struct
+ {
+   unsigned char st_name[4];                /* Symbol name (string tbl index) */
+   unsigned char st_info;                /* Symbol type and binding */
+   unsigned char st_other;               /* Symbol visibility */
+   unsigned char st_shndx[2];               /* Section index */
+   unsigned char st_value[8];               /* Symbol value */
+   unsigned char st_size[8];                /* Symbol size */
+ } Elf64_External_Sym;
+ 
+ #define ELF_ST_BIND(val)              (((unsigned char) (val)) >> 4)
+ #define ELF_ST_TYPE(val)              ((val) & 0xf)
+ #define ELF_ST_INFO(bind, type)       (((bind) << 4) + ((type) & 0xf))
+ 
+ #define STT_NOTYPE	0	/* Symbol type is unspecified */
+ #define STT_OBJECT	1	/* Symbol is a data object */
+ #define STT_FUNC	2	/* Symbol is a code object */
+ #define STT_TLS		6	/* Thread local data object */
+ #define STT_GNU_IFUNC	10	/* Symbol is an indirect code object */
+ 
+ #define STB_LOCAL	0	/* Local symbol */
+ #define STB_GLOBAL	1	/* Global symbol */
+ 
+ #define STV_DEFAULT	0	/* Visibility is specified by binding type */
  
  /* Functions to fetch and store different ELF types, depending on the
     endianness and size.  */
*************** struct simple_object_elf_attributes
*** 348,353 ****
--- 400,413 ----
    unsigned int flags;
  };
  
+ /* Private data for an simple_object_write.  */
+ 
+ struct simple_object_elf_write
+ {
+   struct simple_object_elf_attributes attrs;
+   unsigned char *shdrs;
+ };
+ 
  /* See if we have an ELF file.  */
  
  static void *
*************** simple_object_elf_start_write (void *att
*** 675,686 ****
  {
    struct simple_object_elf_attributes *attrs =
      (struct simple_object_elf_attributes *) attributes_data;
!   struct simple_object_elf_attributes *ret;
  
    /* We're just going to record the attributes, but we need to make a
       copy because the user may delete them.  */
!   ret = XNEW (struct simple_object_elf_attributes);
!   *ret = *attrs;
    return ret;
  }
  
--- 735,747 ----
  {
    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
       copy because the user may delete them.  */
!   ret = XNEW (struct simple_object_elf_write);
!   ret->attrs = *attrs;
!   ret->shdrs = NULL;
    return ret;
  }
  
*************** static int
*** 766,773 ****
  simple_object_elf_write_shdr (simple_object_write *sobj, int descriptor,
  			      off_t offset, unsigned int sh_name,
  			      unsigned int sh_type, unsigned int sh_flags,
  			      unsigned int sh_offset, unsigned int sh_size,
! 			      unsigned int sh_link, unsigned int sh_addralign,
  			      const char **errmsg, int *err)
  {
    struct simple_object_elf_attributes *attrs =
--- 827,837 ----
  simple_object_elf_write_shdr (simple_object_write *sobj, int descriptor,
  			      off_t offset, unsigned int sh_name,
  			      unsigned int sh_type, unsigned int sh_flags,
+ 			      off_t sh_addr,
  			      unsigned int sh_offset, unsigned int sh_size,
! 			      unsigned int sh_link, unsigned int sh_info,
! 			      unsigned int sh_addralign,
! 			      unsigned int sh_entsize,
  			      const char **errmsg, int *err)
  {
    struct simple_object_elf_attributes *attrs =
*************** simple_object_elf_write_shdr (simple_obj
*** 788,799 ****
    ELF_SET_FIELD (fns, cl, Shdr, buf, sh_name, Elf_Word, sh_name);
    ELF_SET_FIELD (fns, cl, Shdr, buf, sh_type, Elf_Word, sh_type);
    ELF_SET_FIELD (fns, cl, Shdr, buf, sh_flags, Elf_Addr, sh_flags);
    ELF_SET_FIELD (fns, cl, Shdr, buf, sh_offset, Elf_Addr, sh_offset);
    ELF_SET_FIELD (fns, cl, Shdr, buf, sh_size, Elf_Addr, sh_size);
    ELF_SET_FIELD (fns, cl, Shdr, buf, sh_link, Elf_Word, sh_link);
!   /* sh_info left as zero.  */
    ELF_SET_FIELD (fns, cl, Shdr, buf, sh_addralign, Elf_Addr, sh_addralign);
!   /* sh_entsize left as zero.  */
  
    return simple_object_internal_write (descriptor, offset, buf, shdr_size,
  				       errmsg, err);
--- 852,864 ----
    ELF_SET_FIELD (fns, cl, Shdr, buf, sh_name, Elf_Word, sh_name);
    ELF_SET_FIELD (fns, cl, Shdr, buf, sh_type, Elf_Word, sh_type);
    ELF_SET_FIELD (fns, cl, Shdr, buf, sh_flags, Elf_Addr, sh_flags);
+   ELF_SET_FIELD (fns, cl, Shdr, buf, sh_addr, Elf_Addr, sh_addr);
    ELF_SET_FIELD (fns, cl, Shdr, buf, sh_offset, Elf_Addr, sh_offset);
    ELF_SET_FIELD (fns, cl, Shdr, buf, sh_size, Elf_Addr, sh_size);
    ELF_SET_FIELD (fns, cl, Shdr, buf, sh_link, Elf_Word, sh_link);
!   ELF_SET_FIELD (fns, cl, Shdr, buf, sh_info, Elf_Word, sh_info);
    ELF_SET_FIELD (fns, cl, Shdr, buf, sh_addralign, Elf_Addr, sh_addralign);
!   ELF_SET_FIELD (fns, cl, Shdr, buf, sh_entsize, Elf_Word, sh_entsize);
  
    return simple_object_internal_write (descriptor, offset, buf, shdr_size,
  				       errmsg, err);
*************** static const char *
*** 811,818 ****
  simple_object_elf_write_to_file (simple_object_write *sobj, int descriptor,
  				 int *err)
  {
!   struct simple_object_elf_attributes *attrs =
!     (struct simple_object_elf_attributes *) sobj->data;
    unsigned char cl;
    size_t ehdr_size;
    size_t shdr_size;
--- 876,884 ----
  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_attributes *attrs = &eow->attrs;
    unsigned char cl;
    size_t ehdr_size;
    size_t shdr_size;
*************** simple_object_elf_write_to_file (simple_
*** 825,830 ****
--- 891,897 ----
    unsigned int first_sh_link;
    size_t sh_name;
    unsigned char zero;
+   unsigned secnum;
  
    if (!simple_object_elf_write_ehdr (sobj, descriptor, &errmsg, err))
      return errmsg;
*************** simple_object_elf_write_to_file (simple_
*** 862,882 ****
    else
      first_sh_link = shnum - 1;
    if (!simple_object_elf_write_shdr (sobj, descriptor, shdr_offset,
! 				     0, 0, 0, 0, first_sh_size, first_sh_link,
! 				     0, &errmsg, err))
      return errmsg;
  
    shdr_offset += shdr_size;
  
    sh_name = 1;
    for (section = sobj->sections; section != NULL; section = section->next)
      {
        size_t mask;
        size_t new_sh_offset;
        size_t sh_size;
        struct simple_object_write_section_buffer *buffer;
  
!       mask = (1U << section->align) - 1;
        new_sh_offset = sh_offset + mask;
        new_sh_offset &= ~ mask;
        while (new_sh_offset > sh_offset)
--- 929,982 ----
    else
      first_sh_link = shnum - 1;
    if (!simple_object_elf_write_shdr (sobj, descriptor, shdr_offset,
! 				     0, 0, 0, 0, 0, first_sh_size, first_sh_link,
! 				     0, 0, 0, &errmsg, err))
      return errmsg;
  
    shdr_offset += shdr_size;
  
    sh_name = 1;
+   secnum = 0;
    for (section = sobj->sections; section != NULL; section = section->next)
      {
        size_t mask;
        size_t new_sh_offset;
        size_t sh_size;
        struct simple_object_write_section_buffer *buffer;
+       unsigned int sh_type = SHT_PROGBITS;
+       unsigned int sh_flags = 0;
+       off_t sh_addr = 0;
+       unsigned int sh_link = 0;
+       unsigned int sh_info = 0;
+       unsigned int sh_addralign = 1U << section->align;
+       unsigned int sh_entsize = 0;
+       if (eow->shdrs)
+ 	{
+ 	  sh_type = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
+ 				     eow->shdrs + secnum * shdr_size,
+ 				     sh_type, Elf_Word);
+ 	  sh_flags = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
+ 				      eow->shdrs + secnum * shdr_size,
+ 				      sh_flags, Elf_Addr);
+ 	  sh_addr = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
+ 				     eow->shdrs + secnum * shdr_size,
+ 				     sh_addr, Elf_Addr);
+ 	  sh_link = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
+ 				     eow->shdrs + secnum * shdr_size,
+ 				     sh_link, Elf_Word);
+ 	  sh_info = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
+ 				     eow->shdrs + secnum * shdr_size,
+ 				     sh_info, Elf_Word);
+ 	  sh_addralign = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
+ 					  eow->shdrs + secnum * shdr_size,
+ 					  sh_addralign, Elf_Addr);
+ 	  sh_entsize = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
+ 					eow->shdrs + secnum * shdr_size,
+ 					sh_entsize, Elf_Word);
+ 	  secnum++;
+ 	}
  
!       mask = sh_addralign - 1;
        new_sh_offset = sh_offset + mask;
        new_sh_offset &= ~ mask;
        while (new_sh_offset > sh_offset)
*************** simple_object_elf_write_to_file (simple_
*** 906,913 ****
  	}
  
        if (!simple_object_elf_write_shdr (sobj, descriptor, shdr_offset,
! 					 sh_name, SHT_PROGBITS, 0, sh_offset,
! 					 sh_size, 0, 1U << section->align,
  					 &errmsg, err))
  	return errmsg;
  
--- 1006,1015 ----
  	}
  
        if (!simple_object_elf_write_shdr (sobj, descriptor, shdr_offset,
! 					 sh_name, sh_type, sh_flags,
! 					 sh_addr, sh_offset,
! 					 sh_size, sh_link, sh_info,
! 					 sh_addralign, sh_entsize,
  					 &errmsg, err))
  	return errmsg;
  
*************** simple_object_elf_write_to_file (simple_
*** 917,925 ****
      }
  
    if (!simple_object_elf_write_shdr (sobj, descriptor, shdr_offset,
! 				     sh_name, SHT_STRTAB, 0, sh_offset,
! 				     sh_name + strlen (".shstrtab") + 1, 0,
! 				     1, &errmsg, err))
      return errmsg;
  
    /* .shstrtab has a leading zero byte.  */
--- 1019,1027 ----
      }
  
    if (!simple_object_elf_write_shdr (sobj, descriptor, shdr_offset,
! 				     sh_name, SHT_STRTAB, 0, 0, sh_offset,
! 				     sh_name + strlen (".shstrtab") + 1, 0, 0,
! 				     1, 0, &errmsg, err))
      return errmsg;
  
    /* .shstrtab has a leading zero byte.  */
*************** simple_object_elf_write_to_file (simple_
*** 954,962 ****
--- 1056,1409 ----
  static void
  simple_object_elf_release_write (void *data)
  {
+   struct simple_object_elf_write *eow = (struct simple_object_elf_write *) data;
+   if (eow->shdrs)
+     XDELETE (eow->shdrs);
    XDELETE (data);
  }
  
+ /* Copy all sections in an ELF file.  */
+ 
+ static const char *
+ simple_object_elf_copy_lto_debug_sections (simple_object_read *sobj,
+ 					   simple_object_write *dobj,
+ 					   int (*pfn) (const char **),
+ 					   int *err)
+ {
+   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;
+   unsigned char ei_class = eor->ei_class;
+   size_t shdr_size;
+   unsigned int shnum;
+   unsigned char *shdrs;
+   const char *errmsg;
+   unsigned char *shstrhdr;
+   size_t name_size;
+   off_t shstroff;
+   unsigned char *names;
+   unsigned int i;
+   int *pfnret;
+   const char **pfnname;
+ 
+   shdr_size = (ei_class == ELFCLASS32
+ 	       ? sizeof (Elf32_External_Shdr)
+ 	       : sizeof (Elf64_External_Shdr));
+ 
+   /* Read the section headers.  We skip section 0, which is not a
+      useful section.  */
+ 
+   shnum = eor->shnum;
+   shdrs = XNEWVEC (unsigned char, shdr_size * (shnum - 1));
+ 
+   if (!simple_object_internal_read (sobj->descriptor,
+ 				    sobj->offset + eor->shoff + shdr_size,
+ 				    shdrs,
+ 				    shdr_size * (shnum - 1),
+ 				    &errmsg, err))
+     {
+       XDELETEVEC (shdrs);
+       return errmsg;
+     }
+ 
+   /* Read the section names.  */
+ 
+   shstrhdr = shdrs + (eor->shstrndx - 1) * shdr_size;
+   name_size = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ 			       shstrhdr, sh_size, Elf_Addr);
+   shstroff = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ 			      shstrhdr, sh_offset, Elf_Addr);
+   names = XNEWVEC (unsigned char, name_size);
+   if (!simple_object_internal_read (sobj->descriptor,
+ 				    sobj->offset + shstroff,
+ 				    names, name_size, &errmsg, err))
+     {
+       XDELETEVEC (names);
+       XDELETEVEC (shdrs);
+       return errmsg;
+     }
+ 
+   eow->shdrs = XNEWVEC (unsigned char, shdr_size * (shnum - 1));
+   pfnret = XNEWVEC (int, shnum);
+   pfnname = XNEWVEC (const char *, shnum);
+ 
+   /* First perform the callbacks to know which sections to preserve and
+      what name to use for those.  */
+   for (i = 1; i < shnum; ++i)
+     {
+       unsigned char *shdr;
+       unsigned int sh_name;
+       const char *name;
+       int ret;
+ 
+       shdr = shdrs + (i - 1) * shdr_size;
+       sh_name = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ 				 shdr, sh_name, Elf_Word);
+       if (sh_name >= name_size)
+ 	{
+ 	  *err = 0;
+ 	  XDELETEVEC (names);
+ 	  XDELETEVEC (shdrs);
+ 	  return "ELF section name out of range";
+ 	}
+ 
+       name = (const char *) names + sh_name;
+ 
+       ret = (*pfn) (&name);
+       pfnret[i - 1] = ret == 1 ? 0 : -1;
+       pfnname[i - 1] = name;
+     }
+ 
+   /* Mark sections as preserved that are required by to be preserved
+      sections.  */
+   for (i = 1; i < shnum; ++i)
+     {
+       unsigned char *shdr;
+       unsigned int sh_type, sh_info, sh_link;
+       off_t offset;
+       off_t length;
+ 
+       shdr = shdrs + (i - 1) * shdr_size;
+       sh_type = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ 				 shdr, sh_type, Elf_Word);
+       sh_info = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ 				 shdr, sh_info, Elf_Word);
+       sh_link = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ 				 shdr, sh_link, Elf_Word);
+       if (sh_type == SHT_GROUP)
+ 	{
+ 	  /* Mark groups containing copied sections.  */
+ 	  unsigned entsize = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ 					      shdr, sh_entsize, Elf_Addr);
+ 	  unsigned char *ent, *buf;
+ 	  int keep = 0;
+ 	  offset = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ 				    shdr, sh_offset, Elf_Addr);
+ 	  length = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ 				    shdr, sh_size, Elf_Addr);
+ 	  buf = XNEWVEC (unsigned char, length);
+ 	  if (!simple_object_internal_read (sobj->descriptor,
+ 					    sobj->offset + offset, buf,
+ 					    (size_t) length, &errmsg, err))
+ 	    {
+ 	      XDELETEVEC (buf);
+ 	      XDELETEVEC (names);
+ 	      XDELETEVEC (shdrs);
+ 	      return errmsg;
+ 	    }
+ 	  for (ent = buf + entsize; ent < buf + length; ent += entsize)
+ 	    {
+ 	      unsigned sec = type_functions->fetch_Elf_Word (ent);
+ 	      if (pfnret[sec - 1] == 0)
+ 		keep = 1;
+ 	    }
+ 	  if (keep)
+ 	    {
+ 	      pfnret[sh_link - 1] = 0;
+ 	      pfnret[i - 1] = 0;
+ 	    }
+ 	}
+       if (sh_type == SHT_RELA
+ 	  || sh_type == SHT_REL)
+ 	{
+ 	  /* Mark relocation sections and symtab of copied sections.  */
+ 	  if (pfnret[sh_info - 1] == 0)
+ 	    {
+ 	      pfnret[sh_link - 1] = 0;
+ 	      pfnret[i - 1] = 0;
+ 	    }
+ 	}
+       if (sh_type == SHT_SYMTAB)
+ 	{
+ 	  /* Mark strings sections of copied symtabs.  */
+ 	  if (pfnret[i - 1] == 0)
+ 	    pfnret[sh_link - 1] = 0;
+ 	}
+     }
+ 
+   /* Then perform the actual copying.  */
+   for (i = 1; i < shnum; ++i)
+     {
+       unsigned char *shdr;
+       unsigned int sh_name, sh_type;
+       const char *name;
+       off_t offset;
+       off_t length;
+       int ret;
+       const char *errmsg;
+       simple_object_write_section *dest;
+       off_t flags;
+       unsigned char *buf;
+ 
+       shdr = shdrs + (i - 1) * shdr_size;
+       sh_name = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ 				 shdr, sh_name, Elf_Word);
+       if (sh_name >= name_size)
+ 	{
+ 	  *err = 0;
+ 	  XDELETEVEC (names);
+ 	  XDELETEVEC (shdrs);
+ 	  return "ELF section name out of range";
+ 	}
+ 
+       name = (const char *) names + sh_name;
+       offset = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ 				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);
+ 
+       ret = pfnret[i - 1];
+       name = ret == 0 ? pfnname[i - 1] : "";
+ 
+       dest = simple_object_write_create_section (dobj, name, 0, &errmsg, err);
+       if (dest == NULL)
+ 	{
+ 	  XDELETEVEC (names);
+ 	  XDELETEVEC (shdrs);
+ 	  return errmsg;
+ 	}
+ 
+       /* Record the SHDR of the source.  */
+       memcpy (eow->shdrs + (i - 1) * shdr_size, shdr, shdr_size);
+       shdr = eow->shdrs + (i - 1) * shdr_size;
+ 
+       /* Copy the data.
+ 	 ???  This is quite wasteful and ideally would be delayed until
+ 	 write_to_file ().  Thus it questions the interfacing
+ 	 which eventually should contain destination creation plus
+ 	 writing.  */
+       /* Keep empty sections for sections we should discard.  This avoids
+          the need to rewrite section indices in symtab and relocation
+ 	 sections.  */
+       if (ret == 0)
+ 	{
+ 	  buf = XNEWVEC (unsigned char, length);
+ 	  if (!simple_object_internal_read (sobj->descriptor,
+ 					    sobj->offset + offset, buf,
+ 					    (size_t) length, &errmsg, err))
+ 	    {
+ 	      XDELETEVEC (buf);
+ 	      XDELETEVEC (names);
+ 	      XDELETEVEC (shdrs);
+ 	      return errmsg;
+ 	    }
+ 
+ 	  /* If we are processing .symtab purge __gnu_lto_v1 and
+ 	     __gnu_lto_slim symbols from it.  */
+ 	  if (sh_type == SHT_SYMTAB)
+ 	    {
+ 	      unsigned entsize = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ 						  shdr, sh_entsize, Elf_Addr);
+ 	      unsigned strtab = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ 						 shdr, sh_link, Elf_Word);
+ 	      unsigned char *strshdr = shdrs + (strtab - 1) * shdr_size;
+ 	      off_t stroff = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ 					      strshdr, sh_offset, Elf_Addr);
+ 	      size_t strsz = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ 					      strshdr, sh_size, Elf_Addr);
+ 	      char *strings = XNEWVEC (char, strsz);
+ 	      unsigned char *ent;
+ 	      simple_object_internal_read (sobj->descriptor,
+ 					   sobj->offset + stroff,
+ 					   (unsigned char *)strings,
+ 					   strsz, &errmsg, err);
+ 	      for (ent = buf; ent < buf + length; ent += entsize)
+ 		{
+ 		  unsigned st_shndx = ELF_FETCH_FIELD (type_functions, ei_class,
+ 						       Sym, ent,
+ 						       st_shndx, Elf_Half);
+ 		  unsigned char *st_info;
+ 		  unsigned char *st_other;
+ 		  int discard = 0;
+ 		  if (ei_class == ELFCLASS32)
+ 		    {
+ 		      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;
+ 		    }
+ 		  /* Eliminate all COMMONs - this includes __gnu_lto_v1
+ 		     and __gnu_lto_slim which otherwise cause endless
+ 		     LTO plugin invocation.  */
+ 		  if (st_shndx == SHN_COMMON)
+ 		    /* Setting st_name to "" seems to work to purge
+ 		       COMMON symbols (in addition to setting their
+ 		       size to zero).  */
+ 		    discard = 1;
+ 		  /* We also need to remove symbols refering to sections
+ 		     we'll eventually remove as with fat LTO objects
+ 		     we otherwise get duplicate symbols at final link
+ 		     (with GNU ld, gold is fine and ignores symbols in
+ 		     sections marked as EXCLUDE).  ld/20513  */
+ 		  else if (st_shndx != SHN_UNDEF
+ 			   && st_shndx < shnum
+ 			   && pfnret[st_shndx - 1] == -1)
+ 		    discard = 1;
+ 
+ 		  if (discard)
+ 		    {
+ 		      /* Make discarded symbols undefined and unnamed.  */
+ 		      ELF_SET_FIELD (type_functions, ei_class, Sym,
+ 				     ent, st_name, Elf_Word, 0);
+ 		      ELF_SET_FIELD (type_functions, ei_class, Sym,
+ 				     ent, st_value, Elf_Addr, 0);
+ 		      ELF_SET_FIELD (type_functions, ei_class, Sym,
+ 				     ent, st_size, Elf_Word, 0);
+ 		      ELF_SET_FIELD (type_functions, ei_class, Sym,
+ 				     ent, st_shndx, Elf_Half, SHN_UNDEF);
+ 		      *st_info = ELF_ST_INFO (ELF_ST_BIND (*st_info),
+ 					      STT_NOTYPE);
+ 		      *st_other = STV_DEFAULT;
+ 		    }
+ 		}
+ 	      XDELETEVEC (strings);
+ 	    }
+ 
+ 	  errmsg = simple_object_write_add_data (dobj, dest,
+ 						 buf, length, 1, err);
+ 	  XDELETEVEC (buf);
+ 	  if (errmsg)
+ 	    {
+ 	      XDELETEVEC (names);
+ 	      XDELETEVEC (shdrs);
+ 	      return errmsg;
+ 	    }
+ 	}
+       else
+ 	{
+ 	  /* For deleted sections mark the section header table entry as
+ 	     unused.  That allows the link editor to remove it in a partial
+ 	     link.  */
+ 	  ELF_SET_FIELD (type_functions, ei_class, Shdr,
+ 			 shdr, sh_type, Elf_Addr, SHT_NULL);
+ 	}
+ 
+       flags = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+ 			       shdr, sh_flags, Elf_Addr);
+       if (ret == 0)
+ 	flags &= ~SHF_EXCLUDE;
+       else if (ret == -1)
+ 	flags |= SHF_EXCLUDE;
+       ELF_SET_FIELD (type_functions, ei_class, Shdr,
+ 		     shdr, sh_flags, Elf_Addr, flags);
+     }
+ 
+   XDELETEVEC (names);
+   XDELETEVEC (shdrs);
+   XDELETEVEC (pfnret);
+   XDELETEVEC (pfnname);
+ 
+   return NULL;
+ }
+ 
+ 
  /* The ELF functions.  */
  
  const struct simple_object_functions simple_object_elf_functions =
*************** const struct simple_object_functions sim
*** 969,973 ****
    simple_object_elf_release_attributes,
    simple_object_elf_start_write,
    simple_object_elf_write_to_file,
!   simple_object_elf_release_write
  };
--- 1416,1421 ----
    simple_object_elf_release_attributes,
    simple_object_elf_start_write,
    simple_object_elf_write_to_file,
!   simple_object_elf_release_write,
!   simple_object_elf_copy_lto_debug_sections
  };
Index: early-lto-debug/libiberty/simple-object.c
===================================================================
*** early-lto-debug.orig/libiberty/simple-object.c	2017-08-15 12:25:07.078117298 +0200
--- early-lto-debug/libiberty/simple-object.c	2017-08-15 12:27:26.524468220 +0200
*************** Boston, MA 02110-1301, USA.  */
*** 22,27 ****
--- 22,28 ----
  #include "simple-object.h"
  
  #include <errno.h>
+ #include <fcntl.h>
  
  #ifdef HAVE_STDLIB_H
  #include <stdlib.h>
*************** simple_object_find_section (simple_objec
*** 249,254 ****
--- 250,335 ----
    return 1;
  }
  
+ /* Callback to identify and rename LTO debug sections by name.
+    Returns 1 if NAME is a LTO debug section, 0 if not.  */
+ 
+ static int
+ handle_lto_debug_sections (const char **name)
+ {
+   /* ???  So we can't use .gnu.lto_ prefixed sections as the assembler
+      complains about bogus section flags.  Which means we need to arrange
+      for that to be fixed or .gnu.debuglto_ marked as SHF_EXCLUDE (to make
+      fat lto object tooling work for the fat part).  */
+   /* ???  For now this handles both .gnu.lto_ and .gnu.debuglto_ prefixed
+      sections.  */
+   /* Copy LTO debug sections and rename them to their non-LTO name.  */
+   if (strncmp (*name, ".gnu.debuglto_", sizeof (".gnu.debuglto_") - 1) == 0)
+     {
+       *name = *name + sizeof (".gnu.debuglto_") - 1;
+       return 1;
+     }
+   else if (strncmp (*name, ".gnu.lto_.debug_", sizeof (".gnu.lto_.debug_") -1) == 0)
+     {
+       *name = *name + sizeof (".gnu.lto_") - 1;
+       return 1;
+     }
+   return 0;
+ }
+ 
+ /* Copy LTO debug sections.  */
+ 
+ const char *
+ simple_object_copy_lto_debug_sections (simple_object_read *sobj,
+ 				       const char *dest, int *err)
+ {
+   const char *errmsg;
+   simple_object_write *dest_sobj;
+   simple_object_attributes *attrs;
+   int outfd;
+ 
+   if (! sobj->functions->copy_lto_debug_sections)
+     {
+       *err = EINVAL;
+       return "simple_object_copy_lto_debug_sections not implemented";
+     }
+ 
+   attrs = simple_object_fetch_attributes (sobj, &errmsg, err);
+   if (! attrs)
+     return errmsg;
+   dest_sobj = simple_object_start_write (attrs, NULL, &errmsg, err);
+   simple_object_release_attributes (attrs);
+   if (! dest_sobj)
+     return errmsg;
+ 
+   errmsg = sobj->functions->copy_lto_debug_sections (sobj, dest_sobj,
+ 						     handle_lto_debug_sections,
+ 						     err);
+   if (errmsg)
+     {
+       simple_object_release_write (dest_sobj);
+       return errmsg;
+     }
+ 
+   outfd = creat (dest, 00777);
+   if (outfd == -1)
+     {
+       *err = errno;
+       simple_object_release_write (dest_sobj);
+       return "open failed";
+     }
+ 
+   errmsg = simple_object_write_to_file (dest_sobj, outfd, err);
+   close (outfd);
+   if (errmsg)
+     {
+       simple_object_release_write (dest_sobj);
+       return errmsg;
+     }
+ 
+   simple_object_release_write (dest_sobj);
+   return NULL;
+ }
+ 
  /* Fetch attributes.  */
  
  simple_object_attributes *
*************** simple_object_start_write (simple_object
*** 315,321 ****
      return NULL;
    ret = XNEW (simple_object_write);
    ret->functions = attrs->functions;
!   ret->segment_name = xstrdup (segment_name);
    ret->sections = NULL;
    ret->last_section = NULL;
    ret->data = data;
--- 396,402 ----
      return NULL;
    ret = XNEW (simple_object_write);
    ret->functions = attrs->functions;
!   ret->segment_name = segment_name ? xstrdup (segment_name) : NULL;
    ret->sections = NULL;
    ret->last_section = NULL;
    ret->data = data;
Index: early-lto-debug/libiberty/simple-object-coff.c
===================================================================
*** early-lto-debug.orig/libiberty/simple-object-coff.c	2017-08-15 12:25:07.078117298 +0200
--- early-lto-debug/libiberty/simple-object-coff.c	2017-08-15 12:27:26.524468220 +0200
*************** const struct simple_object_functions sim
*** 800,804 ****
    simple_object_coff_release_attributes,
    simple_object_coff_start_write,
    simple_object_coff_write_to_file,
!   simple_object_coff_release_write
  };
--- 800,805 ----
    simple_object_coff_release_attributes,
    simple_object_coff_start_write,
    simple_object_coff_write_to_file,
!   simple_object_coff_release_write,
!   NULL
  };
Index: early-lto-debug/libiberty/simple-object-mach-o.c
===================================================================
*** early-lto-debug.orig/libiberty/simple-object-mach-o.c	2017-08-15 12:25:07.078117298 +0200
--- early-lto-debug/libiberty/simple-object-mach-o.c	2017-08-15 12:27:26.524468220 +0200
*************** const struct simple_object_functions sim
*** 1374,1378 ****
    simple_object_mach_o_release_attributes,
    simple_object_mach_o_start_write,
    simple_object_mach_o_write_to_file,
!   simple_object_mach_o_release_write
  };
--- 1374,1379 ----
    simple_object_mach_o_release_attributes,
    simple_object_mach_o_start_write,
    simple_object_mach_o_write_to_file,
!   simple_object_mach_o_release_write,
!   NULL
  };
Index: early-lto-debug/libiberty/simple-object-xcoff.c
===================================================================
*** early-lto-debug.orig/libiberty/simple-object-xcoff.c	2017-08-15 12:25:07.078117298 +0200
--- early-lto-debug/libiberty/simple-object-xcoff.c	2017-08-15 12:27:26.524468220 +0200
*************** const struct simple_object_functions sim
*** 1006,1010 ****
    simple_object_xcoff_release_attributes,
    simple_object_xcoff_start_write,
    simple_object_xcoff_write_to_file,
!   simple_object_xcoff_release_write
  };
--- 1006,1011 ----
    simple_object_xcoff_release_attributes,
    simple_object_xcoff_start_write,
    simple_object_xcoff_write_to_file,
!   simple_object_xcoff_release_write,
!   NULL
  };
diff mbox

Patch

Index: early-lto-debug/include/simple-object.h
===================================================================
--- early-lto-debug.orig/include/simple-object.h	2016-10-19 13:19:58.012326431 +0200
+++ early-lto-debug/include/simple-object.h	2016-10-20 10:51:49.861722998 +0200
@@ -197,6 +197,14 @@  simple_object_write_to_file (simple_obje
 extern void
 simple_object_release_write (simple_object_write *);
 
+/* Copy LTO debug sections from SRC_OBJECT to DEST.
+   If an error occurs, return the errno value in ERR and an error string.  */
+
+extern const char *
+simple_object_copy_lto_debug_sections (simple_object_read *src_object,
+				       const char *dest,
+				       int *err);
+
 #ifdef __cplusplus
 }
 #endif
Index: early-lto-debug/libiberty/simple-object-common.h
===================================================================
--- early-lto-debug.orig/libiberty/simple-object-common.h	2016-10-19 13:19:58.012326431 +0200
+++ early-lto-debug/libiberty/simple-object-common.h	2016-10-20 10:51:49.865723045 +0200
@@ -141,6 +141,12 @@  struct simple_object_functions
 
   /* Release the private data for an simple_object_write.  */
   void (*release_write) (void *);
+
+  /* Copy LTO debug sections.  */
+  const char *(*copy_lto_debug_sections) (simple_object_read *sobj,
+					  simple_object_write *dobj,
+					  int (*pfn) (const char **),
+					  int *err);
 };
 
 /* The known object file formats.  */
Index: early-lto-debug/libiberty/simple-object-elf.c
===================================================================
--- early-lto-debug.orig/libiberty/simple-object-elf.c	2016-10-19 13:19:58.012326431 +0200
+++ early-lto-debug/libiberty/simple-object-elf.c	2016-10-20 10:51:49.865723045 +0200
@@ -183,8 +183,55 @@  typedef struct {
 
 /* Values for sh_type field.  */
 
+#define SHT_NULL	0		/* Section header table entry unused */
 #define SHT_PROGBITS	1		/* Program data */
+#define SHT_SYMTAB	2		/* Link editing symbol table */
 #define SHT_STRTAB	3		/* A string table */
+#define SHT_RELA	4		/* Relocation entries with addends */
+#define SHT_REL		9		/* Relocation entries, no addends */
+#define SHT_GROUP	17		/* Section contains a section group */
+
+/* Values for sh_flags field.  */
+
+#define SHF_EXCLUDE	0x80000000	/* Link editor is to exclude this
+					   section from executable and
+					   shared library that it builds
+					   when those objects are not to be
+					   further relocated.  */
+/* Symbol table entry.  */
+
+typedef struct
+{
+  unsigned char st_name[4];                /* Symbol name (string tbl index) */
+  unsigned char st_value[4];               /* Symbol value */
+  unsigned char st_size[4];                /* Symbol size */
+  unsigned char st_info;                /* Symbol type and binding */
+  unsigned char st_other;               /* Symbol visibility */
+  unsigned char st_shndx[2];               /* Section index */
+} Elf32_External_Sym;
+
+typedef struct
+{
+  unsigned char st_name[4];                /* Symbol name (string tbl index) */
+  unsigned char st_info;                /* Symbol type and binding */
+  unsigned char st_other;               /* Symbol visibility */
+  unsigned char st_shndx[2];               /* Section index */
+  unsigned char st_value[8];               /* Symbol value */
+  unsigned char st_size[8];                /* Symbol size */
+} Elf64_External_Sym;
+
+#define ELF_ST_BIND(val)              (((unsigned char) (val)) >> 4)
+#define ELF_ST_TYPE(val)              ((val) & 0xf)
+#define ELF_ST_INFO(bind, type)       (((bind) << 4) + ((type) & 0xf))
+
+#define STT_OBJECT	1	/* Symbol is a data object */
+#define STT_FUNC	2	/* Symbol is a code object */
+#define STT_TLS		6	/* Thread local data object */
+#define STT_GNU_IFUNC	10	/* Symbol is an indirect code object */
+
+#define STV_DEFAULT	0	/* Visibility is specified by binding type */
+
+#define SHN_COMMON	0xFFF2	/* Associated symbol is in common */
 
 /* Functions to fetch and store different ELF types, depending on the
    endianness and size.  */
@@ -348,6 +395,14 @@  struct simple_object_elf_attributes
   unsigned int flags;
 };
 
+/* Private data for an simple_object_write.  */
+
+struct simple_object_elf_write
+{
+  struct simple_object_elf_attributes attrs;
+  unsigned char *shdrs;
+};
+
 /* See if we have an ELF file.  */
 
 static void *
@@ -675,12 +730,13 @@  simple_object_elf_start_write (void *att
 {
   struct simple_object_elf_attributes *attrs =
     (struct simple_object_elf_attributes *) attributes_data;
-  struct simple_object_elf_attributes *ret;
+  struct simple_object_elf_write *ret;
 
   /* We're just going to record the attributes, but we need to make a
      copy because the user may delete them.  */
-  ret = XNEW (struct simple_object_elf_attributes);
-  *ret = *attrs;
+  ret = XNEW (struct simple_object_elf_write);
+  ret->attrs = *attrs;
+  ret->shdrs = NULL;
   return ret;
 }
 
@@ -766,8 +822,11 @@  static int
 simple_object_elf_write_shdr (simple_object_write *sobj, int descriptor,
 			      off_t offset, unsigned int sh_name,
 			      unsigned int sh_type, unsigned int sh_flags,
+			      off_t sh_addr,
 			      unsigned int sh_offset, unsigned int sh_size,
-			      unsigned int sh_link, unsigned int sh_addralign,
+			      unsigned int sh_link, unsigned int sh_info,
+			      unsigned int sh_addralign,
+			      unsigned int sh_entsize,
 			      const char **errmsg, int *err)
 {
   struct simple_object_elf_attributes *attrs =
@@ -788,12 +847,13 @@  simple_object_elf_write_shdr (simple_obj
   ELF_SET_FIELD (fns, cl, Shdr, buf, sh_name, Elf_Word, sh_name);
   ELF_SET_FIELD (fns, cl, Shdr, buf, sh_type, Elf_Word, sh_type);
   ELF_SET_FIELD (fns, cl, Shdr, buf, sh_flags, Elf_Addr, sh_flags);
+  ELF_SET_FIELD (fns, cl, Shdr, buf, sh_addr, Elf_Addr, sh_addr);
   ELF_SET_FIELD (fns, cl, Shdr, buf, sh_offset, Elf_Addr, sh_offset);
   ELF_SET_FIELD (fns, cl, Shdr, buf, sh_size, Elf_Addr, sh_size);
   ELF_SET_FIELD (fns, cl, Shdr, buf, sh_link, Elf_Word, sh_link);
-  /* sh_info left as zero.  */
+  ELF_SET_FIELD (fns, cl, Shdr, buf, sh_info, Elf_Word, sh_info);
   ELF_SET_FIELD (fns, cl, Shdr, buf, sh_addralign, Elf_Addr, sh_addralign);
-  /* sh_entsize left as zero.  */
+  ELF_SET_FIELD (fns, cl, Shdr, buf, sh_entsize, Elf_Word, sh_entsize);
 
   return simple_object_internal_write (descriptor, offset, buf, shdr_size,
 				       errmsg, err);
@@ -811,8 +871,9 @@  static const char *
 simple_object_elf_write_to_file (simple_object_write *sobj, int descriptor,
 				 int *err)
 {
-  struct simple_object_elf_attributes *attrs =
-    (struct simple_object_elf_attributes *) 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;
   size_t shdr_size;
@@ -825,6 +886,7 @@  simple_object_elf_write_to_file (simple_
   unsigned int first_sh_link;
   size_t sh_name;
   unsigned char zero;
+  unsigned secnum;
 
   if (!simple_object_elf_write_ehdr (sobj, descriptor, &errmsg, err))
     return errmsg;
@@ -862,21 +924,54 @@  simple_object_elf_write_to_file (simple_
   else
     first_sh_link = shnum - 1;
   if (!simple_object_elf_write_shdr (sobj, descriptor, shdr_offset,
-				     0, 0, 0, 0, first_sh_size, first_sh_link,
-				     0, &errmsg, err))
+				     0, 0, 0, 0, 0, first_sh_size, first_sh_link,
+				     0, 0, 0, &errmsg, err))
     return errmsg;
 
   shdr_offset += shdr_size;
 
   sh_name = 1;
+  secnum = 0;
   for (section = sobj->sections; section != NULL; section = section->next)
     {
       size_t mask;
       size_t new_sh_offset;
       size_t sh_size;
       struct simple_object_write_section_buffer *buffer;
+      unsigned int sh_type = SHT_PROGBITS;
+      unsigned int sh_flags = 0;
+      off_t sh_addr = 0;
+      unsigned int sh_link = 0;
+      unsigned int sh_info = 0;
+      unsigned int sh_addralign = 1U << section->align;
+      unsigned int sh_entsize = 0;
+      if (eow->shdrs)
+	{
+	  sh_type = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
+				     eow->shdrs + secnum * shdr_size,
+				     sh_type, Elf_Word);
+	  sh_flags = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
+				      eow->shdrs + secnum * shdr_size,
+				      sh_flags, Elf_Addr);
+	  sh_addr = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
+				     eow->shdrs + secnum * shdr_size,
+				     sh_addr, Elf_Addr);
+	  sh_link = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
+				     eow->shdrs + secnum * shdr_size,
+				     sh_link, Elf_Word);
+	  sh_info = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
+				     eow->shdrs + secnum * shdr_size,
+				     sh_info, Elf_Word);
+	  sh_addralign = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
+					  eow->shdrs + secnum * shdr_size,
+					  sh_addralign, Elf_Addr);
+	  sh_entsize = ELF_FETCH_FIELD (attrs->type_functions, attrs->ei_class, Shdr,
+					eow->shdrs + secnum * shdr_size,
+					sh_entsize, Elf_Word);
+	  secnum++;
+	}
 
-      mask = (1U << section->align) - 1;
+      mask = sh_addralign - 1;
       new_sh_offset = sh_offset + mask;
       new_sh_offset &= ~ mask;
       while (new_sh_offset > sh_offset)
@@ -906,8 +1001,10 @@  simple_object_elf_write_to_file (simple_
 	}
 
       if (!simple_object_elf_write_shdr (sobj, descriptor, shdr_offset,
-					 sh_name, SHT_PROGBITS, 0, sh_offset,
-					 sh_size, 0, 1U << section->align,
+					 sh_name, sh_type, sh_flags,
+					 sh_addr, sh_offset,
+					 sh_size, sh_link, sh_info,
+					 sh_addralign, sh_entsize,
 					 &errmsg, err))
 	return errmsg;
 
@@ -917,9 +1014,9 @@  simple_object_elf_write_to_file (simple_
     }
 
   if (!simple_object_elf_write_shdr (sobj, descriptor, shdr_offset,
-				     sh_name, SHT_STRTAB, 0, sh_offset,
-				     sh_name + strlen (".shstrtab") + 1, 0,
-				     1, &errmsg, err))
+				     sh_name, SHT_STRTAB, 0, 0, sh_offset,
+				     sh_name + strlen (".shstrtab") + 1, 0, 0,
+				     1, 0, &errmsg, err))
     return errmsg;
 
   /* .shstrtab has a leading zero byte.  */
@@ -954,9 +1051,363 @@  simple_object_elf_write_to_file (simple_
 static void
 simple_object_elf_release_write (void *data)
 {
+  struct simple_object_elf_write *eow = (struct simple_object_elf_write *) data;
+  if (eow->shdrs)
+    XDELETE (eow->shdrs);
   XDELETE (data);
 }
 
+/* Copy all sections in an ELF file.  */
+
+static const char *
+simple_object_elf_copy_lto_debug_sections (simple_object_read *sobj,
+					   simple_object_write *dobj,
+					   int (*pfn) (const char **),
+					   int *err)
+{
+  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;
+  unsigned char ei_class = eor->ei_class;
+  size_t shdr_size;
+  unsigned int shnum;
+  unsigned char *shdrs;
+  const char *errmsg;
+  unsigned char *shstrhdr;
+  size_t name_size;
+  off_t shstroff;
+  unsigned char *names;
+  unsigned int i;
+  int *pfnret;
+  const char **pfnname;
+
+  shdr_size = (ei_class == ELFCLASS32
+	       ? sizeof (Elf32_External_Shdr)
+	       : sizeof (Elf64_External_Shdr));
+
+  /* Read the section headers.  We skip section 0, which is not a
+     useful section.  */
+
+  shnum = eor->shnum;
+  shdrs = XNEWVEC (unsigned char, shdr_size * (shnum - 1));
+
+  if (!simple_object_internal_read (sobj->descriptor,
+				    sobj->offset + eor->shoff + shdr_size,
+				    shdrs,
+				    shdr_size * (shnum - 1),
+				    &errmsg, err))
+    {
+      XDELETEVEC (shdrs);
+      return errmsg;
+    }
+
+  /* Read the section names.  */
+
+  shstrhdr = shdrs + (eor->shstrndx - 1) * shdr_size;
+  name_size = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+			       shstrhdr, sh_size, Elf_Addr);
+  shstroff = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+			      shstrhdr, sh_offset, Elf_Addr);
+  names = XNEWVEC (unsigned char, name_size);
+  if (!simple_object_internal_read (sobj->descriptor,
+				    sobj->offset + shstroff,
+				    names, name_size, &errmsg, err))
+    {
+      XDELETEVEC (names);
+      XDELETEVEC (shdrs);
+      return errmsg;
+    }
+
+  eow->shdrs = XNEWVEC (unsigned char, shdr_size * (shnum - 1));
+  pfnret = XNEWVEC (int, shnum);
+  pfnname = XNEWVEC (const char *, shnum);
+
+  /* First perform the callbacks to know which sections to preserve and
+     what name to use for those.  */
+  for (i = 1; i < shnum; ++i)
+    {
+      unsigned char *shdr;
+      unsigned int sh_name;
+      const char *name;
+      int ret;
+
+      shdr = shdrs + (i - 1) * shdr_size;
+      sh_name = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+				 shdr, sh_name, Elf_Word);
+      if (sh_name >= name_size)
+	{
+	  *err = 0;
+	  XDELETEVEC (names);
+	  XDELETEVEC (shdrs);
+	  return "ELF section name out of range";
+	}
+
+      name = (const char *) names + sh_name;
+
+      ret = (*pfn) (&name);
+      pfnret[i - 1] = ret == 1 ? 0 : -1;
+      pfnname[i - 1] = name;
+    }
+
+  /* Mark sections as preserved that are required by to be preserved
+     sections.  */
+  for (i = 1; i < shnum; ++i)
+    {
+      unsigned char *shdr;
+      unsigned int sh_type, sh_info, sh_link;
+      off_t offset;
+      off_t length;
+
+      shdr = shdrs + (i - 1) * shdr_size;
+      sh_type = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+				 shdr, sh_type, Elf_Word);
+      sh_info = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+				 shdr, sh_info, Elf_Word);
+      sh_link = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+				 shdr, sh_link, Elf_Word);
+      if (sh_type == SHT_GROUP)
+	{
+	  /* Mark groups containing copied sections.  */
+	  unsigned entsize = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+					      shdr, sh_entsize, Elf_Addr);
+	  unsigned char *ent, *buf;
+	  int keep = 0;
+	  offset = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+				    shdr, sh_offset, Elf_Addr);
+	  length = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+				    shdr, sh_size, Elf_Addr);
+	  buf = XNEWVEC (unsigned char, length);
+	  if (!simple_object_internal_read (sobj->descriptor,
+					    sobj->offset + offset, buf,
+					    (size_t) length, &errmsg, err))
+	    {
+	      XDELETEVEC (buf);
+	      XDELETEVEC (names);
+	      XDELETEVEC (shdrs);
+	      return errmsg;
+	    }
+	  for (ent = buf + entsize; ent < buf + length; ent += entsize)
+	    {
+	      unsigned sec = type_functions->fetch_Elf_Word (ent);
+	      if (pfnret[sec - 1] == 0)
+		keep = 1;
+	    }
+	  if (keep)
+	    {
+	      pfnret[sh_link - 1] = 0;
+	      pfnret[i - 1] = 0;
+	    }
+	}
+      if (sh_type == SHT_RELA
+	  || sh_type == SHT_REL)
+	{
+	  /* Mark relocation sections and symtab of copied sections.  */
+	  if (pfnret[sh_info - 1] == 0)
+	    {
+	      pfnret[sh_link - 1] = 0;
+	      pfnret[i - 1] = 0;
+	    }
+	}
+      if (sh_type == SHT_SYMTAB)
+	{
+	  /* Mark strings sections of copied symtabs.  */
+	  if (pfnret[i - 1] == 0)
+	    pfnret[sh_link - 1] = 0;
+	}
+    }
+
+  /* Then perform the actual copying.  */
+  for (i = 1; i < shnum; ++i)
+    {
+      unsigned char *shdr;
+      unsigned int sh_name, sh_type;
+      const char *name;
+      off_t offset;
+      off_t length;
+      int ret;
+      const char *errmsg;
+      simple_object_write_section *dest;
+      off_t flags;
+      unsigned char *buf;
+
+      shdr = shdrs + (i - 1) * shdr_size;
+      sh_name = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+				 shdr, sh_name, Elf_Word);
+      if (sh_name >= name_size)
+	{
+	  *err = 0;
+	  XDELETEVEC (names);
+	  XDELETEVEC (shdrs);
+	  return "ELF section name out of range";
+	}
+
+      name = (const char *) names + sh_name;
+      offset = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+				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);
+
+      ret = pfnret[i - 1];
+      name = ret == 0 ? pfnname[i - 1] : "";
+
+      dest = simple_object_write_create_section (dobj, name, 0, &errmsg, err);
+      if (dest == NULL)
+	{
+	  XDELETEVEC (names);
+	  XDELETEVEC (shdrs);
+	  return errmsg;
+	}
+
+      /* Record the SHDR of the source.  */
+      memcpy (eow->shdrs + (i - 1) * shdr_size, shdr, shdr_size);
+      shdr = eow->shdrs + (i - 1) * shdr_size;
+
+      /* Copy the data.
+	 ???  This is quite wasteful and ideally would be delayed until
+	 write_to_file ().  Thus it questions the interfacing
+	 which eventually should contain destination creation plus
+	 writing.  */
+      /* Keep empty sections for sections we should discard.  This avoids
+         the need to rewrite section indices in symtab and relocation
+	 sections.  */
+      if (ret == 0)
+	{
+	  buf = XNEWVEC (unsigned char, length);
+	  if (!simple_object_internal_read (sobj->descriptor,
+					    sobj->offset + offset, buf,
+					    (size_t) length, &errmsg, err))
+	    {
+	      XDELETEVEC (buf);
+	      XDELETEVEC (names);
+	      XDELETEVEC (shdrs);
+	      return errmsg;
+	    }
+
+	  /* If we are processing .symtab purge __gnu_lto_v1 and
+	     __gnu_lto_slim symbols from it.  */
+	  if (sh_type == SHT_SYMTAB)
+	    {
+	      unsigned entsize = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+						  shdr, sh_entsize, Elf_Addr);
+	      unsigned strtab = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+						 shdr, sh_link, Elf_Word);
+	      unsigned char *strshdr = shdrs + (strtab - 1) * shdr_size;
+	      off_t stroff = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+					      strshdr, sh_offset, Elf_Addr);
+	      size_t strsz = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+					      strshdr, sh_size, Elf_Addr);
+	      char *strings = XNEWVEC (char, strsz);
+	      unsigned char *ent;
+	      simple_object_internal_read (sobj->descriptor,
+					   sobj->offset + stroff,
+					   (unsigned char *)strings,
+					   strsz, &errmsg, err);
+	      for (ent = buf; ent < buf + length; ent += entsize)
+		{
+		  unsigned st_shndx = ELF_FETCH_FIELD (type_functions, ei_class,
+						       Sym, ent,
+						       st_shndx, Elf_Half);
+		  unsigned char *st_info;
+		  unsigned char *st_other;
+		  if (ei_class == ELFCLASS32)
+		    {
+		      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;
+		    }
+		  /* Eliminate all COMMONs - this includes __gnu_lto_v1
+		     and __gnu_lto_slim which otherwise cause endless
+		     LTO plugin invocation.  */
+		  if (st_shndx == SHN_COMMON)
+		    /* Setting st_name to "" seems to work to purge
+		       COMMON symbols (in addition to setting their
+		       size to zero).  */
+		    ;
+		  /* We also need to remove symbols refering to sections
+		     we'll eventually remove as with fat LTO objects
+		     we otherwise get duplicate symbols at final link
+		     (with GNU ld, gold is fine and ignores symbols in
+		     sections marked as EXCLUDE).  ld/20513  */
+		  else if (st_shndx != 0
+			   && st_shndx < shnum
+			   && pfnret[st_shndx - 1] == -1)
+		    /* Messing with st_shndx doesn't seem to work very
+		       well.  Likewise changing the symbol type to
+		       a section symbol or making it local.
+		       So just keep with making it unnamed.
+		       Also make all regular symbols STT_OBJECT and
+		       have default visibility, otherwise GNU ld warns
+		       about mismatches for the same `' named symbol.  */
+		    {
+		      if (ELF_ST_TYPE (*st_info) == STT_FUNC
+			  || ELF_ST_TYPE (*st_info) == STT_TLS
+			  || ELF_ST_TYPE (*st_info) == STT_GNU_IFUNC)
+			*st_info = ELF_ST_INFO (ELF_ST_BIND (*st_info),
+						STT_OBJECT);
+		      *st_other = STV_DEFAULT;
+		    }
+		  else
+		    continue;
+
+		  /* For all purged symbols make the symbol unnamed.  */
+		  ELF_SET_FIELD (type_functions, ei_class, Sym,
+				 ent, st_name, Elf_Word, 0);
+
+		  /* At least set st_value and st_size to zero to not go
+		     out of bounds.  */
+		  ELF_SET_FIELD (type_functions, ei_class, Sym,
+				 ent, st_value, Elf_Addr, 0);
+		  ELF_SET_FIELD (type_functions, ei_class, Sym,
+				 ent, st_size, Elf_Word, 0);
+		}
+	      XDELETEVEC (strings);
+	    }
+
+	  errmsg = simple_object_write_add_data (dobj, dest, buf, length, 1, err);
+	  XDELETEVEC (buf);
+	  if (errmsg)
+	    {
+	      XDELETEVEC (names);
+	      XDELETEVEC (shdrs);
+	      return errmsg;
+	    }
+	}
+      else
+	{
+	  /* For deleted sections mark the section header table entry as
+	     unused.  That allows the link editor to remove it in a partial
+	     link.  */
+	  ELF_SET_FIELD (type_functions, ei_class, Shdr,
+			 shdr, sh_type, Elf_Addr, SHT_NULL);
+	}
+
+      flags = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
+			       shdr, sh_flags, Elf_Addr);
+      if (ret == 0)
+	flags &= ~SHF_EXCLUDE;
+      else if (ret == -1)
+	flags |= SHF_EXCLUDE;
+      ELF_SET_FIELD (type_functions, ei_class, Shdr,
+		     shdr, sh_flags, Elf_Addr, flags);
+    }
+
+  XDELETEVEC (names);
+  XDELETEVEC (shdrs);
+  XDELETEVEC (pfnret);
+  XDELETEVEC (pfnname);
+
+  return NULL;
+}
+
+
 /* The ELF functions.  */
 
 const struct simple_object_functions simple_object_elf_functions =
@@ -969,5 +1420,6 @@  const struct simple_object_functions sim
   simple_object_elf_release_attributes,
   simple_object_elf_start_write,
   simple_object_elf_write_to_file,
-  simple_object_elf_release_write
+  simple_object_elf_release_write,
+  simple_object_elf_copy_lto_debug_sections
 };
Index: early-lto-debug/libiberty/simple-object.c
===================================================================
--- early-lto-debug.orig/libiberty/simple-object.c	2016-10-19 13:19:58.012326431 +0200
+++ early-lto-debug/libiberty/simple-object.c	2016-10-20 13:58:11.722714041 +0200
@@ -22,6 +22,7 @@  Boston, MA 02110-1301, USA.  */
 #include "simple-object.h"
 
 #include <errno.h>
+#include <fcntl.h>
 
 #ifdef HAVE_STDLIB_H
 #include <stdlib.h>
@@ -249,6 +250,86 @@  simple_object_find_section (simple_objec
   return 1;
 }
 
+/* Callback to identify and rename LTO debug sections by name.
+   Returns 1 if NAME is a LTO debug section, 0 if not.  */
+
+static int
+handle_lto_debug_sections (const char **name)
+{
+  /* ???  So we can't use .gnu.lto_ prefixed sections as the assembler
+     complains about bogus section flags.  Which means we need to arrange
+     for that to be fixed or .gnu.debuglto_ marked as SHF_EXCLUDE (to make
+     fat lto object tooling work for the fat part).  */
+  /* ???  For now this handles both .gnu.lto_ and .gnu.debuglto_ prefixed
+     sections.  */
+  /* Copy LTO debug sections and rename them to their non-LTO name.  */
+  if (strncmp (*name, ".gnu.debuglto_", sizeof (".gnu.debuglto_") - 1) == 0)
+    {
+      *name = *name + sizeof (".gnu.debuglto_") - 1;
+      return 1;
+    }
+  else if (strncmp (*name, ".gnu.lto_.debug_", sizeof (".gnu.lto_.debug_") -1) == 0)
+    {
+      *name = *name + sizeof (".gnu.lto_") - 1;
+      return 1;
+    }
+  return 0;
+}
+
+/* Copy LTO debug sections.  */
+
+const char *
+simple_object_copy_lto_debug_sections (simple_object_read *sobj,
+				       const char *dest, int *err)
+{
+  const char *errmsg;
+  simple_object_write *dest_sobj;
+  simple_object_attributes *attrs;
+  int outfd;
+
+  if (! sobj->functions->copy_lto_debug_sections)
+    {
+      *err = EINVAL;
+      return "simple_object_copy_lto_debug_sections not implemented";
+    }
+
+  attrs = simple_object_fetch_attributes (sobj, &errmsg, err);
+  if (! attrs)
+    return errmsg;
+  dest_sobj = simple_object_start_write (attrs, NULL, &errmsg, err);
+  simple_object_release_attributes (attrs);
+  if (! dest_sobj)
+    return errmsg;
+
+  errmsg = sobj->functions->copy_lto_debug_sections (sobj, dest_sobj,
+						     handle_lto_debug_sections,
+						     err);
+  if (errmsg)
+    {
+      simple_object_release_write (dest_sobj);
+      return errmsg;
+    }
+
+  outfd = creat (dest, 00777);
+  if (outfd == -1)
+    {
+      *err = errno;
+      simple_object_release_write (dest_sobj);
+      return "open failed";
+    }
+
+  errmsg = simple_object_write_to_file (dest_sobj, outfd, err);
+  close (outfd);
+  if (errmsg)
+    {
+      simple_object_release_write (dest_sobj);
+      return errmsg;
+    }
+
+  simple_object_release_write (dest_sobj);
+  return NULL;
+}
+
 /* Fetch attributes.  */
 
 simple_object_attributes *
@@ -315,7 +396,7 @@  simple_object_start_write (simple_object
     return NULL;
   ret = XNEW (simple_object_write);
   ret->functions = attrs->functions;
-  ret->segment_name = xstrdup (segment_name);
+  ret->segment_name = segment_name ? xstrdup (segment_name) : NULL;
   ret->sections = NULL;
   ret->last_section = NULL;
   ret->data = data;
Index: early-lto-debug/libiberty/simple-object-coff.c
===================================================================
--- early-lto-debug.orig/libiberty/simple-object-coff.c	2016-10-19 13:19:58.012326431 +0200
+++ early-lto-debug/libiberty/simple-object-coff.c	2016-10-20 10:51:49.881723228 +0200
@@ -800,5 +800,6 @@  const struct simple_object_functions sim
   simple_object_coff_release_attributes,
   simple_object_coff_start_write,
   simple_object_coff_write_to_file,
-  simple_object_coff_release_write
+  simple_object_coff_release_write,
+  NULL
 };
Index: early-lto-debug/libiberty/simple-object-mach-o.c
===================================================================
--- early-lto-debug.orig/libiberty/simple-object-mach-o.c	2016-10-19 13:19:58.012326431 +0200
+++ early-lto-debug/libiberty/simple-object-mach-o.c	2016-10-20 10:51:49.881723228 +0200
@@ -1374,5 +1374,6 @@  const struct simple_object_functions sim
   simple_object_mach_o_release_attributes,
   simple_object_mach_o_start_write,
   simple_object_mach_o_write_to_file,
-  simple_object_mach_o_release_write
+  simple_object_mach_o_release_write,
+  NULL
 };
Index: early-lto-debug/libiberty/simple-object-xcoff.c
===================================================================
--- early-lto-debug.orig/libiberty/simple-object-xcoff.c	2016-10-19 13:19:58.012326431 +0200
+++ early-lto-debug/libiberty/simple-object-xcoff.c	2016-10-20 10:51:49.881723228 +0200
@@ -894,5 +894,6 @@  const struct simple_object_functions sim
   simple_object_xcoff_release_attributes,
   simple_object_xcoff_start_write,
   simple_object_xcoff_write_to_file,
-  simple_object_xcoff_release_write
+  simple_object_xcoff_release_write,
+  NULL
 };