This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [PATCH][1/2] Early LTO debug, simple-object part
- From: Richard Biener <rguenther at suse dot de>
- To: Ian Lance Taylor <iant at google dot com>
- Cc: Ian Lance Taylor <ian at airs dot com>, gcc-patches List <gcc-patches at gcc dot gnu dot org>, Jakub Jelinek <jakub at redhat dot com>, Jeff Law <law at redhat dot com>
- Date: Tue, 15 Aug 2017 14:51:32 +0200 (CEST)
- Subject: Re: [PATCH][1/2] Early LTO debug, simple-object part
- Authentication-results: sourceware.org; auth=none
- References: <alpine.LSU.2.20.1705191233300.20726@zhemvz.fhfr.qr> <alpine.LSU.2.20.1706071020460.7349@zhemvz.fhfr.qr> <alpine.LSU.2.20.1706201315510.22867@zhemvz.fhfr.qr> <alpine.LSU.2.20.1707041309350.23185@zhemvz.fhfr.qr> <alpine.LSU.2.20.1707281453340.10808@zhemvz.fhfr.qr> <CADzB+2=uzC4XgBHL-28bzxn8Nnk6_VchevxXgFjTxqsHfHb3QQ@mail.gmail.com> <fb1684b2-efea-d4ab-7a73-3c85d5a64acd@redhat.com> <alpine.LSU.2.20.1708041422080.10808@zhemvz.fhfr.qr> <alpine.LSU.2.20.1708141514280.14191@zhemvz.fhfr.qr> <CAKOQZ8y-AQd5ECmRSd5xiysNCsZ0UuyTom=NJONqh2=uO-cbOw@mail.gmail.com> <alpine.LSU.2.20.1708150944230.14191@zhemvz.fhfr.qr>
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
};