This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
[RFA:] support different(-sized) GOT entries in bfd_elf_gc_common_final_link
- From: Hans-Peter Nilsson <hans-peter dot nilsson at axis dot com>
- To: binutils at sourceware dot org
- Date: Wed, 19 Nov 2008 16:10:34 +0100
- Subject: [RFA:] support different(-sized) GOT entries in bfd_elf_gc_common_final_link
There are three files using bfd_elf_gc_common_final_link for
their bfd_elf32_bfd_final_link (allocating GOT offsets), namely
elf32-vax.c, elf32-bfin.c and elf32-cris.c. With the following
change, maybe more targets can use it. Without it, for the TLS
changes in the CRIS port, I'd have to replicate
bfd_elf_gc_common_final_link in elf32-cris.c.
With this change, different GOT entries are supported.
Trivially, just different-sized GOT entries are supported. With
a little help from the target, multiple different-sized GOT
entries for the same symbol can be handled; they're then
supposed to be exposed through the callback-function as one big
GOT entry. (The back-end returns the sum of their sizes and is
required to keep the sum in h->got.refcount and
elf_local_got_refcounts() and to keep track of their individual
positions.) Maybe the extract from the elf32-cris.c patch for
TLS below helps as a showcase.
Intended use: for TLS (for most N-bit targets), you have a
relocation that affects a two-N-bit-sized structure in the GOT,
requiring 2*N-bit "entries". This doesn't match the hardcoded
(bed->s->arch_size / 8). A bed->s entry that is just a variable
doesn't quite fit the bill either, it has to be a function, as
below.
Also, you get entries with *different contents validly referring
to the same symbol*: if you've compiled one file for the
global-dynamic (GD) model and one with initial-exec (IE), you'll
need two different GOT entries. You can't use the same GOT
entry for that (unless of course, your target *requires*
link-time optimization from GD to IE so you'll get just one
dynamic TLS entry).
The new callback takes three arguments (see the elf-bfd.h patch
and elf_cris_got_elt_size), but the last two are only used when
the first one is NULL ("global" symbol vs. local symbol without
a elf_link_hash_entry). Not sure how to do that cleaner, but it
doesn't seem a big enough deal to worry about.
Tested crosses to cris-axis-elf, cris-axis-linux-gnu,
bfin-uclinux and vax-linux, and native i686-pc-linux-gnu for
good measure, no regressions.
Ok to commit?
bfd:
* elf-bfd.h (struct elf_backend_data): New member got_elt_size.
(_bfd_elf_default_got_elt_size): Declare.
* elflink.c (struct alloc_got_off_arg): Replace member got_elt_size
by new member info.
(elf_gc_allocate_got_offsets): Adjust for calling bed->got_elt_size
to get the element size instead of using a gofarg entry.
(bfd_elf_gc_common_finalize_got_offsets): Similar.
(_bfd_elf_default_got_elt_size): New function.
* elfxx-target.h: New macro elf_backend_got_elt_size.
(elfNN_bed): Use it.
Index: elf-bfd.h
===================================================================
RCS file: /cvs/src/src/bfd/elf-bfd.h,v
retrieving revision 1.268
diff -p -u -r1.268 elf-bfd.h
--- elf-bfd.h 20 Oct 2008 10:57:33 -0000 1.268
+++ elf-bfd.h 19 Nov 2008 12:31:39 -0000
@@ -1147,6 +1147,12 @@ struct elf_backend_data
so-called reserved entries on some systems. */
bfd_vma got_header_size;
+ /* The size of the GOT entry for the symbol pointed to by H if non-NULL,
+ otherwise by the local symbol with index SYMNDX in IBFD. */
+ bfd_vma (*got_elt_size) (bfd *, struct bfd_link_info *,
+ struct elf_link_hash_entry *h,
+ bfd *ibfd, unsigned long symndx);
+
/* The vendor name to use for a processor-standard attributes section. */
const char *obj_attrs_vendor;
@@ -2070,6 +2076,10 @@ extern asection *_bfd_elf_common_section
extern void _bfd_dwarf2_cleanup_debug_info
(bfd *);
+extern bfd_vma _bfd_elf_default_got_elt_size
+(bfd *, struct bfd_link_info *, struct elf_link_hash_entry *, bfd *,
+ unsigned long);
+
extern bfd_reloc_status_type _bfd_elf_rel_vtable_reloc_fn
(bfd *, arelent *, struct bfd_symbol *, void *,
asection *, bfd *, char **);
Index: elflink.c
===================================================================
RCS file: /cvs/src/src/bfd/elflink.c,v
retrieving revision 1.315
diff -p -u -r1.315 elflink.c
--- elflink.c 20 Oct 2008 10:57:33 -0000 1.315
+++ elflink.c 19 Nov 2008 12:31:42 -0000
@@ -11786,7 +11786,7 @@ bfd_elf_gc_record_vtentry (bfd *abfd ATT
struct alloc_got_off_arg {
bfd_vma gotoff;
- unsigned int got_elt_size;
+ struct bfd_link_info *info;
};
/* We need a special top-level link routine to convert got reference counts
@@ -11796,6 +11796,8 @@ static bfd_boolean
elf_gc_allocate_got_offsets (struct elf_link_hash_entry *h, void *arg)
{
struct alloc_got_off_arg *gofarg = arg;
+ bfd *obfd = gofarg->info->output_bfd;
+ const struct elf_backend_data *bed = get_elf_backend_data (obfd);
if (h->root.type == bfd_link_hash_warning)
h = (struct elf_link_hash_entry *) h->root.u.i.link;
@@ -11803,7 +11805,7 @@ elf_gc_allocate_got_offsets (struct elf_
if (h->got.refcount > 0)
{
h->got.offset = gofarg->gotoff;
- gofarg->gotoff += gofarg->got_elt_size;
+ gofarg->gotoff += bed->got_elt_size (obfd, gofarg->info, h, NULL, 0);
}
else
h->got.offset = (bfd_vma) -1;
@@ -11821,9 +11823,10 @@ bfd_elf_gc_common_finalize_got_offsets (
bfd *i;
const struct elf_backend_data *bed = get_elf_backend_data (abfd);
bfd_vma gotoff;
- unsigned int got_elt_size = bed->s->arch_size / 8;
struct alloc_got_off_arg gofarg;
+ BFD_ASSERT (abfd == info->output_bfd);
+
if (! is_elf_hash_table (info->hash))
return FALSE;
@@ -11859,7 +11862,7 @@ bfd_elf_gc_common_finalize_got_offsets (
if (local_got[j] > 0)
{
local_got[j] = gotoff;
- gotoff += got_elt_size;
+ gotoff += bed->got_elt_size (abfd, info, NULL, i, j);
}
else
local_got[j] = (bfd_vma) -1;
@@ -11869,7 +11872,7 @@ bfd_elf_gc_common_finalize_got_offsets (
/* Then the global .got entries. .plt refcounts are handled by
adjust_dynamic_symbol */
gofarg.gotoff = gotoff;
- gofarg.got_elt_size = got_elt_size;
+ gofarg.info = info;
elf_link_hash_traverse (elf_hash_table (info),
elf_gc_allocate_got_offsets,
&gofarg);
@@ -12255,3 +12258,14 @@ _bfd_elf_common_section (asection *sec A
{
return bfd_com_section_ptr;
}
+
+bfd_vma
+_bfd_elf_default_got_elt_size (bfd *abfd,
+ struct bfd_link_info *info ATTRIBUTE_UNUSED,
+ struct elf_link_hash_entry *h ATTRIBUTE_UNUSED,
+ bfd *ibfd ATTRIBUTE_UNUSED,
+ unsigned long symndx ATTRIBUTE_UNUSED)
+{
+ const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+ return bed->s->arch_size / 8;
+}
Index: elfxx-target.h
===================================================================
RCS file: /cvs/src/src/bfd/elfxx-target.h,v
retrieving revision 1.115
diff -p -u -r1.115 elfxx-target.h
--- elfxx-target.h 7 Aug 2008 20:04:32 -0000 1.115
+++ elfxx-target.h 19 Nov 2008 12:31:42 -0000
@@ -446,6 +446,9 @@
#ifndef elf_backend_got_header_size
#define elf_backend_got_header_size 0
#endif
+#ifndef elf_backend_got_elt_size
+#define elf_backend_got_elt_size _bfd_elf_default_got_elt_size
+#endif
#ifndef elf_backend_obj_attrs_vendor
#define elf_backend_obj_attrs_vendor NULL
#endif
@@ -712,6 +715,7 @@ static struct elf_backend_data elfNN_bed
&elf_backend_size_info,
elf_backend_special_sections,
elf_backend_got_header_size,
+ elf_backend_got_elt_size,
elf_backend_obj_attrs_vendor,
elf_backend_obj_attrs_section,
elf_backend_obj_attrs_arg_type,
Index: elf32-cris.c
===================================================================
RCS file: /cvs/src/src/bfd/elf32-cris.c,v
retrieving revision 1.86
diff -p -u -r1.86 elf32-cris.c
--- elf32-cris.c 4 Oct 2008 17:18:36 -0000 1.86
+++ elf32-cris.c 19 Nov 2008 12:31:40 -0000
(TLS-part elided ...PATCH EXTRACT, DO NOT APPLY...)
@@ -3400,6 +4092,64 @@ elf_cris_reloc_type_class (rela)
return reloc_class_normal;
}
}
+
+/* The elf_backend_got_elt_size worker. For one symbol, we can have
+ up to two GOT entries from three different-sized types. We fake it
+ as a single entry, so we can use the regular offset-calculation
+ machinery. */
+
+static bfd_vma
+elf_cris_got_elt_size (bfd *abfd ATTRIBUTE_UNUSED,
+ struct bfd_link_info *info ATTRIBUTE_UNUSED,
+ struct elf_link_hash_entry *hr,
+ bfd *ibfd,
+ unsigned long symndx)
+{
+ struct elf_link_hash_entry *h = (struct elf_link_hash_entry *) hr;
+ bfd_vma eltsiz = 0;
+
+ /* We may have one regular GOT entry or up to two TLS GOT
+ entries. */
+ if (h == NULL)
+ {
+ bfd_signed_vma *local_got_refcounts = elf_local_got_refcounts (ibfd);
+
+ BFD_ASSERT (local_got_refcounts != NULL);
+
+ if (local_got_refcounts[LGOT_REG_NDX (symndx)] > 0)
+ {
+ /* We can't have a variable referred to both as a regular
+ variable and through TLS relocs. */
+ BFD_ASSERT (local_got_refcounts[LGOT_DTP_NDX (symndx)] == 0
+ && local_got_refcounts[LGOT_TPREL_NDX (symndx)] == 0);
+ return 4;
+ }
+
+ if (local_got_refcounts[LGOT_DTP_NDX (symndx)] > 0)
+ eltsiz += 8;
+
+ if (local_got_refcounts[LGOT_TPREL_NDX (symndx)] > 0)
+ eltsiz += 4;
+ }
+ else
+ {
+ struct elf_cris_link_hash_entry *hh = elf_cris_hash_entry (h);
+ if (hh->reg_got_refcount > 0)
+ {
+ /* The actual error-on-input is emitted elsewhere. */
+ BFD_ASSERT (hh->dtp_refcount == 0 && hh->tprel_refcount == 0);
+ return 4;
+ }
+
+ if (hh->dtp_refcount > 0)
+ eltsiz += 8;
+
+ if (hh->tprel_refcount > 0)
+ eltsiz += 4;
+ }
+
+ return eltsiz;
+}
#define ELF_ARCH bfd_arch_cris
#define ELF_MACHINE_CODE EM_CRIS
@@ -3456,6 +4206,7 @@ elf_cris_reloc_type_class (rela)
#define elf_backend_plt_readonly 1
#define elf_backend_want_plt_sym 0
#define elf_backend_got_header_size 12
+#define elf_backend_got_elt_size elf_cris_got_elt_size
/* Later, we my want to optimize RELA entries into REL entries for dynamic
linking and libraries (if it's a win of any significance). Until then,
brgds, H-P