Message ID | alpine.LSU.2.20.1705191233300.20726@zhemvz.fhfr.qr |
---|---|
State | New |
Headers | show |
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 > }; >
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 > > }; > > > >
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 > > > }; > > > > > > > > >
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 > > > > }; > > > > > > > > > > > > > > > >
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
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
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.
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.
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
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.
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
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 };
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
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 };
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 };