This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
-Bdirect linking patch
- From: michael meeks <michael dot meeks at novell dot com>
- To: binutils <binutils at sources dot redhat dot com>
- Cc: drepper at redhat dot com
- Date: Fri, 28 Oct 2005 14:57:52 +0100
- Subject: -Bdirect linking patch
- Reply-to: michael dot meeks at novell dot com
Hi guys,
So - I have an evily hackish prototype for glibc & binutils that gives
me a really nice speedup with relocation processing. It's inspired by
the Solaris -Bdirect feature of the same name, and is implemented in the
same way - by adding a section containing a 16bit word per .dynsym entry
with an index into the libraries DT_NEEDED table, built at library link
time.
This then is replayed by the runtime linker removing the num_libs term
from the order of linking (for non-vague symbols) and thus giving a
substantial speedup with apps with large numbers of libraries &
relocations [ie. any large C++ app]. My tests yield these results for
runs of OpenOffice writer:
Times in ms to fully loaded:
Old glibc: 3968, 3978, 3983 Avg: 3980
Just new glibc: 4224, 4238, 4250 Avg: 4240 [260ms slower - hmm]
all -Bdirected: 2148, 2168, 2215 Avg: 2180 [1800ms faster - 45%]
Times in secs from instrumenting dlopen top/tail:
before: 2.693, 2.721, 2.714 Avg: 2.709
after: 0.675, 0.679, 0.682 Avg: 0.679 [75% faster]
Punch line - it saves ~2 seconds from the OO.o warm start time, making
it nearly twice as fast.
There are (at least) the following issues / questions.
+ How are new elf sections allocated ? and/or typically named
I know DT_DIRECT / '.direct' are prolly beyond the pale
The Solaris linker uses a .SUNW_syminfo section.
cf. http://blogs.sun.com/roller/page/msw/20050614
+ LD_PRELOADs need handling for the direct dl-lookup.c
case ? but that requires a search scope. Perhaps it'd
be possible to use the first N entries of the existing
searchlist (?)
+ Is there a better way to achieve what I do in dl-deps.c ?
the umpteen-string compares are clearly highly evil.
+ How did I lose 260ms on OO.o startup with this
patch for the no .direct section case ?
[ could be a self-build glibc problem of course ]
+ In binutils - what is the best way to filter out the
crucial 'Vague Linkage' symbols ? clearly we don't want to
bind any of them - the current approach is clearly a gross
C++ specific, partial hack.
+ should we propagate this information from target
libraries ? ie. libc can advertise 'foo_baa' as not
to be direct linked against ?
+ should the compiler generate / markup the vague
linkage pieces to avoid yet-another link map type
thing ?
+ If we fail to find the symbol in the direct scope should we
check the dependents of that library - to allow some limited
re-factoring later; or just fallback to the global scope ?
+ Should we compress the .direct table more ? I can't envisage
more than 12bits (4096) of DT_NEEDED libraries ever - prolly
we should mask / save that space for future expansion
along with a few special values perhaps ?
+ How useful is this generally ? - clearly OO.o is a
pathalogical case; but how much is interposing used in a
typical Linux system ?
Sorry to mail you directly Ulrich - but don't know where glibc /
development cogitation occurs.
I append the binutils & glibc patches in-line.
---- glibc ----
diff -u -r -x '*.o' -x '*.1' -x 'Makefile*' -x 'config*' -x libtool -x '*.info' -x '*.tex' glibc-2.3-pristine/elf/dl-close.c glibc-2.3/elf/dl-close.c
--- glibc-2.3-pristine/elf/dl-close.c 2005-07-18 08:35:33.000000000 +0100
+++ glibc-2.3/elf/dl-close.c 2005-10-19 21:48:52.000000000 +0100
@@ -506,6 +506,9 @@
/* Remove the searchlists. */
free (imap->l_initfini);
+ /* Remove the dtneeded list */
+ free (imap->l_dtneeded.r_list);
+
/* Remove the scope array if we allocated it. */
if (imap->l_scope != imap->l_scope_mem)
free (imap->l_scope);
diff -u -r -x '*.o' -x '*.1' -x 'Makefile*' -x 'config*' -x libtool -x '*.info' -x '*.tex' glibc-2.3-pristine/elf/dl-deps.c glibc-2.3/elf/dl-deps.c
--- glibc-2.3-pristine/elf/dl-deps.c 2005-04-06 07:57:05.000000000 +0100
+++ glibc-2.3/elf/dl-deps.c 2005-10-21 17:47:15.000000000 +0100
@@ -39,6 +39,9 @@
#define FILTERTAG (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM \
+ DT_EXTRATAGIDX (DT_FILTER))
+#ifndef VERSYMIDX
+# define VERSYMIDX(sym) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGIDX (sym))
+#endif
/* When loading auxiliary objects we must ignore errors. It's ok if
an object is missing. */
@@ -139,6 +142,65 @@
__result; })
+static void
+setup_direct (struct link_map *map, struct r_scope_elem *scope)
+{
+ if (map->l_info[VERSYMIDX(DT_DIRECT)] && map->l_info[DT_NEEDED])
+ {
+ const ElfW(Dyn) *d;
+ unsigned int i;
+ const char *strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
+
+ if (GLRO(dl_debug_mask) & DL_DEBUG_DIRECT)
+ _dl_debug_printf ("** direct linkage section in '%s' **\n",
+ map->l_name ? map->l_name : "<null>");
+
+ map->l_dtneeded.r_nlist = 1;
+ for (d = map->l_ld; d->d_tag != DT_NULL; ++d)
+ {
+ if (__builtin_expect (d->d_tag, DT_NEEDED) == DT_NEEDED)
+ map->l_dtneeded.r_nlist++;
+ }
+
+ map->l_dtneeded.r_list = (struct link_map **)
+ malloc (map->l_dtneeded.r_nlist * sizeof (struct link_map *));
+
+ map->l_dtneeded.r_list[0] = map;
+ for (i = 1, d = map->l_ld; d->d_tag != DT_NULL; ++d)
+ {
+ const char *name;
+ unsigned int j;
+
+ if (d->d_tag != DT_NEEDED)
+ continue;
+
+ name = expand_dst (map, strtab + d->d_un.d_val, 0);
+ if (GLRO(dl_debug_mask) & DL_DEBUG_DIRECT)
+ _dl_debug_printf (" direct index %u object '%s'\n", i, name);
+ for (j = 0; j < scope->r_nlist; j++)
+ {
+ if (scope->r_list[j] &&
+ _dl_name_match_p (name, scope->r_list[j]))
+ {
+ map->l_dtneeded.r_list[i] = scope->r_list[j];
+ break;
+ }
+ }
+ if (!map->l_dtneeded.r_list[i])
+ _dl_debug_printf (" impossible error - can't find '%s'\n", name);
+ i++;
+ }
+ }
+ else
+ {
+ if (GLRO(dl_debug_mask) & DL_DEBUG_DIRECT)
+ _dl_debug_printf ("no direct linkage section in '%s'\n",
+ map->l_name ? map->l_name : "<null>");
+ map->l_dtneeded.r_nlist = 0;
+ map->l_dtneeded.r_list = NULL;
+ }
+}
+
void
internal_function
_dl_map_object_deps (struct link_map *map,
@@ -555,6 +617,10 @@
}
}
+ /* Setup direct linkage dtneeded table */
+ for (i = 0; i < nlist; ++i)
+ setup_direct (map->l_searchlist.r_list[i], &map->l_searchlist);
+
/* Maybe we can remove some relocation dependencies now. */
assert (map->l_searchlist.r_list[0] == map);
for (i = 0; i < map->l_reldepsact; ++i)
diff -u -r -x '*.o' -x '*.1' -x 'Makefile*' -x 'config*' -x libtool -x '*.info' -x '*.tex' glibc-2.3-pristine/elf/dl-lookup.c glibc-2.3/elf/dl-lookup.c
--- glibc-2.3-pristine/elf/dl-lookup.c 2005-04-06 07:57:05.000000000 +0100
+++ glibc-2.3/elf/dl-lookup.c 2005-10-19 22:23:15.000000000 +0100
@@ -32,6 +32,10 @@
#define VERSTAG(tag) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGIDX (tag))
+#ifndef VERSYMIDX
+# define VERSYMIDX(sym) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGIDX (sym))
+#endif
+
/* We need this string more than once. */
static const char undefined_msg[] = "undefined symbol: ";
@@ -209,6 +213,7 @@
const unsigned long int hash = _dl_elf_hash (undef_name);
struct sym_val current_value = { NULL, NULL };
struct r_scope_elem **scope = symbol_scope;
+ size_t i = 0;
bump_num_relocations ();
@@ -216,7 +221,74 @@
up a versioned symbol. */
assert (version == NULL || flags == 0 || flags == DL_LOOKUP_ADD_DEPENDENCY);
- size_t i = 0;
+ if (undef_map && undef_map->l_dtneeded.r_nlist && *ref)
+ {
+ unsigned int idx, noffset;
+ const ElfW(Sym) *symtab;
+ ElfW(Addr) direct;
+
+ /* We need a dynsym index ... */
+ symtab = (const void *) D_PTR (undef_map, l_info[DT_SYMTAB]);
+ direct = D_PTR (undef_map, l_info[VERSYMIDX(DT_DIRECT)]);
+
+ idx = *ref - symtab;
+ if (GLRO(dl_debug_mask) & DL_DEBUG_DIRECT)
+ _dl_debug_printf ("dynamic symbol index %u from '%s' for %s base direct 0x%x start 0x%x\n", idx,
+ undef_map->l_name ? undef_map->l_name : "<noname>",
+ undef_name ? undef_name : "<undef>",
+ (int) direct, (int) undef_map->l_map_start);
+ direct += idx * 2;
+ if (direct >= undef_map->l_map_end || direct <= undef_map->l_map_start)
+ _dl_debug_printf ("broken: off end of map 0x%x\n", (int) direct);
+ else
+ {
+ noffset = *(uint16_t *)direct;
+ if (GLRO(dl_debug_mask) & DL_DEBUG_DIRECT)
+ _dl_debug_printf ("dynamic symbol offset %u from %u\n", noffset, (int) direct);
+ if (noffset < undef_map->l_dtneeded.r_nlist)
+ {
+ int res;
+ struct r_scope_elem direct_elem;
+
+ /* FIXME - requires LD_PRELOAD support ... */
+ direct_elem.r_list = undef_map->l_dtneeded.r_list + noffset;
+ direct_elem.r_nlist = 1;
+
+ if (direct_elem.r_list[0] == skip_map)
+ goto normal_lookup; /* FIXME - correct ? */
+
+ res = do_lookup_x (undef_name, hash, *ref, ¤t_value, &direct_elem,
+ 0, version, flags, skip_map, type_class);
+ if (res > 0)
+ {
+ if (GLRO(dl_debug_mask) & DL_DEBUG_DIRECT)
+ _dl_debug_printf ("direct lookup ...\n");
+ goto match;
+ }
+ else
+ _dl_debug_printf ("Error in lookup %u - missing (?) - fallback "
+ "to deps & then global ? ...\n", res);
+ }
+ else if (noffset == 0xffff)
+ {
+ _dl_debug_printf ("unknown/undefined symbol '%s'\n",
+ undef_name ? undef_name : "<undef>");
+ }
+ else if (noffset == 0xfffe)
+ {
+ if (GLRO(dl_debug_mask) & DL_DEBUG_DIRECT)
+ _dl_debug_printf ("vague symbol\n");
+ }
+ else
+ {
+ _dl_debug_printf ("Error: foo symbol '%s' 0 < %u < %u\n",
+ undef_name ? undef_name : "<undef>",
+ noffset, undef_map->l_dtneeded.r_nlist);
+ }
+ }
+ }
+ normal_lookup:
+
if (__builtin_expect (skip_map != NULL, 0))
{
/* Search the relevant loaded objects for a definition. */
@@ -258,7 +330,7 @@
return 0;
}
}
-
+ match:
if (__builtin_expect (current_value.s == NULL, 0))
{
if ((*ref == NULL || ELFW(ST_BIND) ((*ref)->st_info) != STB_WEAK)
diff -u -r -x '*.o' -x '*.1' -x 'Makefile*' -x 'config*' -x libtool -x '*.info' -x '*.tex' glibc-2.3-pristine/elf/dynamic-link.h glibc-2.3/elf/dynamic-link.h
--- glibc-2.3-pristine/elf/dynamic-link.h 2005-10-18 15:29:20.000000000 +0100
+++ glibc-2.3/elf/dynamic-link.h 2005-10-19 21:01:06.000000000 +0100
@@ -94,6 +94,7 @@
ADJUST_DYN_INFO (DT_PLTGOT);
ADJUST_DYN_INFO (DT_STRTAB);
ADJUST_DYN_INFO (DT_SYMTAB);
+ ADJUST_DYN_INFO (VERSYMIDX(DT_DIRECT));
# if ! ELF_MACHINE_NO_RELA
ADJUST_DYN_INFO (DT_RELA);
# endif
diff -u -r -x '*.o' -x '*.1' -x 'Makefile*' -x 'config*' -x libtool -x '*.info' -x '*.tex' glibc-2.3-pristine/elf/elf.h glibc-2.3/elf/elf.h
--- glibc-2.3-pristine/elf/elf.h 2004-11-15 09:35:22.000000000 +0000
+++ glibc-2.3/elf/elf.h 2005-10-18 15:58:28.000000000 +0100
@@ -714,6 +714,7 @@
/* The versioning entry types. The next are defined as part of the
GNU extension. */
#define DT_VERSYM 0x6ffffff0
+#define DT_DIRECT 0x6ffffff1 /* FIXME - how are these allocated ? */
#define DT_RELACOUNT 0x6ffffff9
#define DT_RELCOUNT 0x6ffffffa
diff -u -r -x '*.o' -x '*.1' -x 'Makefile*' -x 'config*' -x libtool -x '*.info' -x '*.tex' glibc-2.3-pristine/elf/rtld.c glibc-2.3/elf/rtld.c
--- glibc-2.3-pristine/elf/rtld.c 2005-10-18 15:29:20.000000000 +0100
+++ glibc-2.3/elf/rtld.c 2005-10-19 21:59:08.000000000 +0100
@@ -2056,11 +2056,13 @@
DL_DEBUG_SYMBOLS | DL_DEBUG_IMPCALLS },
{ LEN_AND_STR ("bindings"), "display information about symbol binding",
DL_DEBUG_BINDINGS | DL_DEBUG_IMPCALLS },
+ { LEN_AND_STR ("direct"), "display information about direct binding",
+ DL_DEBUG_DIRECT | DL_DEBUG_IMPCALLS },
{ LEN_AND_STR ("versions"), "display version dependencies",
DL_DEBUG_VERSIONS | DL_DEBUG_IMPCALLS },
{ LEN_AND_STR ("all"), "all previous options combined",
DL_DEBUG_LIBS | DL_DEBUG_RELOC | DL_DEBUG_FILES | DL_DEBUG_SYMBOLS
- | DL_DEBUG_BINDINGS | DL_DEBUG_VERSIONS | DL_DEBUG_IMPCALLS },
+ | DL_DEBUG_BINDINGS | DL_DEBUG_DIRECT | DL_DEBUG_VERSIONS | DL_DEBUG_IMPCALLS },
{ LEN_AND_STR ("statistics"), "display relocation statistics",
DL_DEBUG_STATISTICS },
{ LEN_AND_STR ("unused"), "determined unused DSOs",
Only in glibc-2.3/elf: rtld.c~
diff -u -r -x '*.o' -x '*.1' -x 'Makefile*' -x 'config*' -x libtool -x '*.info' -x '*.tex' glibc-2.3-pristine/include/link.h glibc-2.3/include/link.h
--- glibc-2.3-pristine/include/link.h 2005-10-18 15:29:20.000000000 +0100
+++ glibc-2.3/include/link.h 2005-10-19 21:13:12.000000000 +0100
@@ -299,6 +299,10 @@
done. */
ElfW(Addr) l_relro_addr;
size_t l_relro_size;
+
+ /* Array of DT_NEEDED dependencies in order for use in
+ direct linkage - l_dtneeded[0] entry is self */
+ struct r_scope_elem l_dtneeded;
};
struct dl_phdr_info
diff -u -r -x '*.o' -x '*.1' -x 'Makefile*' -x 'config*' -x libtool -x '*.info' -x '*.tex' glibc-2.3-pristine/sysdeps/generic/ldsodefs.h glibc-2.3/sysdeps/generic/ldsodefs.h
--- glibc-2.3-pristine/sysdeps/generic/ldsodefs.h 2005-10-18 15:29:20.000000000 +0100
+++ glibc-2.3/sysdeps/generic/ldsodefs.h 2005-10-19 21:58:12.000000000 +0100
@@ -388,6 +388,7 @@
/* These two are used only internally. */
#define DL_DEBUG_HELP (1 << 9)
#define DL_DEBUG_PRELINK (1 << 10)
+#define DL_DEBUG_DIRECT (1 << 11)
/* Cached value of `getpagesize ()'. */
EXTERN size_t _dl_pagesize;
---- binutils ----
diff -u -r -x '*.o' -x '*.1' -x 'Makefile*' -x 'config*' -x libtool -x '*.info' -x '*.tex' binutils-2.16/bfd/elf-bfd.h binutils.current/bfd/elf-bfd.h
--- binutils-2.16/bfd/elf-bfd.h 2005-03-03 20:52:31.000000000 +0000
+++ binutils.current/bfd/elf-bfd.h 2005-10-17 11:47:08.000000000 +0100
@@ -396,6 +396,9 @@
asection *tls_sec;
bfd_size_type tls_size;
+ /* Direct linkage output section */
+ asection *direct_sec;
+
/* A linked list of BFD's loaded in the link. */
struct elf_link_loaded_list *loaded;
@@ -1238,6 +1241,7 @@
name actually used, which will be the DT_SONAME entry if there is
one. */
const char *dt_name;
+ int dt_needed_idx;
/* Records the result of `get_program_header_size'. */
bfd_size_type program_header_size;
@@ -1338,6 +1342,7 @@
#define elf_local_got_offsets(bfd) (elf_tdata(bfd) -> local_got.offsets)
#define elf_local_got_ents(bfd) (elf_tdata(bfd) -> local_got.ents)
#define elf_dt_name(bfd) (elf_tdata(bfd) -> dt_name)
+#define elf_dt_needed_idx(bfd) (elf_tdata(bfd) -> dt_needed_idx)
#define elf_dyn_lib_class(bfd) (elf_tdata(bfd) -> dyn_lib_class)
#define elf_bad_symtab(bfd) (elf_tdata(bfd) -> bad_symtab)
#define elf_flags_init(bfd) (elf_tdata(bfd) -> flags_init)
Only in binutils.current/bfd: elf-bfd.h~
diff -u -r -x '*.o' -x '*.1' -x 'Makefile*' -x 'config*' -x libtool -x '*.info' -x '*.tex' binutils-2.16/bfd/elf.c binutils.current/bfd/elf.c
--- binutils-2.16/bfd/elf.c 2005-03-06 02:02:15.000000000 +0000
+++ binutils.current/bfd/elf.c 2005-10-19 20:25:03.000000000 +0100
@@ -1145,6 +1145,7 @@
case DT_RELCOUNT: name = "RELCOUNT"; break;
case DT_FLAGS_1: name = "FLAGS_1"; break;
case DT_VERSYM: name = "VERSYM"; break;
+ case DT_DIRECT: name = "DIRECT"; break;
case DT_VERDEF: name = "VERDEF"; break;
case DT_VERDEFNUM: name = "VERDEFNUM"; break;
case DT_VERNEED: name = "VERNEED"; break;
@@ -1495,6 +1496,7 @@
table->runpath = NULL;
table->tls_sec = NULL;
table->tls_size = 0;
+ table->direct_sec = NULL;
table->loaded = NULL;
table->is_relocatable_executable = FALSE;
Only in binutils.current/bfd: elf.c~
diff -u -r -x '*.o' -x '*.1' -x 'Makefile*' -x 'config*' -x libtool -x '*.info' -x '*.tex' binutils-2.16/bfd/elflink.c binutils.current/bfd/elflink.c
--- binutils-2.16/bfd/elflink.c 2005-04-29 14:40:22.000000000 +0100
+++ binutils.current/bfd/elflink.c 2005-10-20 17:15:26.000000000 +0100
@@ -172,6 +172,16 @@
elf_hash_table (info)->eh_info.hdr_sec = s;
}
+ if ( info->direct && ! info->executable )
+ {
+ s = bfd_make_section (abfd, ".direct");
+ if (s == NULL
+ || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY)
+ || ! bfd_set_section_alignment (abfd, s, 2))
+ return FALSE;
+ elf_hash_table (info)->direct_sec = s;
+ }
+
/* Create sections to hold version informations. These are removed
if they are not needed. */
s = bfd_make_section (abfd, ".gnu.version_d");
@@ -2193,7 +2203,9 @@
return TRUE;
}
+
+
/* Fix up the flags for a symbol. This handles various cases which
can only be fixed after all the input files are seen. This is
currently called by both adjust_dynamic_symbol and
@@ -2848,6 +2860,9 @@
if (!_bfd_elf_add_dynamic_entry (info, DT_NEEDED, strindex))
return -1;
+ elf_dt_needed_idx (abfd) = ++(info->dt_needed_index);
+/* fprintf (stderr, "Set soname '%s' as index %d\n",
+ soname, info->dt_needed_index); */
}
else
/* We were just checking for existence of the tag. */
@@ -5671,6 +5686,24 @@
return FALSE;
}
+ /* Create the direct bindings section - 1 entry per dynsym */
+ s = bfd_get_section_by_name (dynobj, ".direct");
+ if (s)
+ {
+ if (dynsymcount == 0)
+ _bfd_strip_section_from_output (info, s);
+ else
+ {
+ s->size = dynsymcount * sizeof (Elf_External_Direct);
+ s->contents = bfd_zalloc (output_bfd, s->size);
+ if (s->contents == NULL)
+ return FALSE;
+
+ if (!_bfd_elf_add_dynamic_entry (info, DT_DIRECT, 0))
+ return FALSE;
+ }
+ }
+
/* Set the size of the .dynsym and .hash sections. We counted
the number of dynamic symbols in elf_link_add_object_symbols.
We will build the contents of .dynsym and .hash when we build
@@ -5749,6 +5782,8 @@
asection *hash_sec;
/* symbol version section (.gnu.version). */
asection *symver_sec;
+ /* .direct linkage section */
+ asection *direct_sec;
/* Buffer large enough to hold contents of any section. */
bfd_byte *contents;
/* Buffer large enough to hold external relocs of any section. */
@@ -6603,6 +6638,40 @@
eversym += h->dynindx;
_bfd_elf_swap_versym_out (finfo->output_bfd, &iversym, eversym);
}
+
+ if (finfo->direct_sec)
+ {
+ bfd_vma offset = 2 * h->dynindx;
+ if (offset > finfo->direct_sec->size)
+ fprintf (stderr, "Out of bounds direct section index %d\n",
+ (int) offset);
+ else
+ {
+ int dt_index = 0xffff;
+
+/* fprintf (stderr, "Symbol '%s' type %d\n",
+ h->root.root.string, h->root.type); */
+
+ if (finfo->info->direct_vague (finfo->info, h->root.root.string))
+ {
+/* fprintf (stderr, "Symbol is vague !\n"); */
+ dt_index = 0xfffe;
+ }
+ else if (h->root.type == bfd_link_hash_defined
+ || h->root.type == bfd_link_hash_defweak)
+ {
+ asection *sec = h->root.u.def.section;
+ if (sec && sec->owner)
+ dt_index = elf_dt_needed_idx (sec->owner);
+/* fprintf (stderr, "Section %p, owner '%s' [%d] offset %d\n",
+ sec, sec && sec->owner ? sec->owner->filename : "<noowner?>",
+ dt_index, (int) offset); */
+ }
+ bfd_put_16 (finfo->output_bfd,
+ dt_index,
+ finfo->direct_sec->contents + offset);
+ }
+ }
}
/* If we're stripping it, then it was just a dynamic symbol, and
@@ -7732,6 +7801,7 @@
finfo.dynsym_sec = NULL;
finfo.hash_sec = NULL;
finfo.symver_sec = NULL;
+ finfo.direct_sec = NULL;
}
else
{
@@ -7740,6 +7810,7 @@
BFD_ASSERT (finfo.dynsym_sec != NULL && finfo.hash_sec != NULL);
finfo.symver_sec = bfd_get_section_by_name (dynobj, ".gnu.version");
/* Note that it is OK if symver_sec is NULL. */
+ finfo.direct_sec = bfd_get_section_by_name (dynobj, ".direct");
}
finfo.contents = NULL;
@@ -8492,6 +8563,9 @@
case DT_VERNEED:
name = ".gnu.version_r";
goto get_vma;
+ case DT_DIRECT:
+ name = ".direct";
+ goto get_vma;
case DT_VERSYM:
name = ".gnu.version";
get_vma:
diff -u -r -x '*.o' -x '*.1' -x 'Makefile*' -x 'config*' -x libtool -x '*.info' -x '*.tex' binutils-2.16/binutils/readelf.c binutils.current/binutils/readelf.c
--- binutils-2.16/binutils/readelf.c 2005-04-20 19:43:36.000000000 +0100
+++ binutils.current/binutils/readelf.c 2005-10-19 21:08:57.000000000 +0100
@@ -143,6 +143,7 @@
int do_dynamic;
int do_syms;
int do_reloc;
+int do_direct;
int do_sections;
int do_section_groups;
int do_segments;
@@ -1519,6 +1520,7 @@
case DT_SYMINFO: return "SYMINFO"; /* aka ADDRRNGHI */
case DT_VERSYM: return "VERSYM";
+ case DT_DIRECT: return "DIRECT";
case DT_RELACOUNT: return "RELACOUNT";
case DT_RELCOUNT: return "RELCOUNT";
@@ -2590,6 +2592,7 @@
{"symbols", no_argument, 0, 's'},
{"syms", no_argument, 0, 's'},
{"relocs", no_argument, 0, 'r'},
+ {"direct", no_argument, 0, 'y'},
{"notes", no_argument, 0, 'n'},
{"dynamic", no_argument, 0, 'd'},
{"arch-specific", no_argument, 0, 'A'},
@@ -2626,6 +2629,7 @@
--symbols An alias for --syms\n\
-n --notes Display the core notes (if present)\n\
-r --relocs Display the relocations (if present)\n\
+ -y --direct Display direct linkage table (if present)\n\
-u --unwind Display the unwind info (if present)\n\
-d --dynamic Display the dynamic section (if present)\n\
-V --version-info Display the version sections (if present)\n\
@@ -2693,7 +2697,7 @@
usage ();
while ((c = getopt_long
- (argc, argv, "ersuahnldSDAIgw::x:i:vVWH", options, NULL)) != EOF)
+ (argc, argv, "erysuahnldSDAIgw::x:i:vVWH", options, NULL)) != EOF)
{
char *cp;
int section;
@@ -2710,6 +2714,7 @@
case 'a':
do_syms++;
do_reloc++;
+ do_direct++;
do_unwind++;
do_dynamic++;
do_header++;
@@ -2738,6 +2743,9 @@
case 'r':
do_reloc++;
break;
+ case 'y':
+ do_direct++;
+ break;
case 'u':
do_unwind++;
break;
@@ -2943,7 +2951,7 @@
}
}
- if (!do_dynamic && !do_syms && !do_reloc && !do_unwind && !do_sections
+ if (!do_dynamic && !do_syms && !do_reloc && !do_direct && !do_unwind && !do_sections
&& !do_segments && !do_header && !do_dump && !do_version
&& !do_histogram && !do_debugging && !do_arch && !do_notes
&& !do_section_groups)
@@ -4328,6 +4336,131 @@
return 1;
}
+static void
+print_dt_needed_name (int idx)
+{
+ const char *name = NULL;
+ Elf_Internal_Dyn *entry;
+
+ switch (idx)
+ {
+ case 0:
+ name = _("<self>");
+ break;
+ case 0xffff:
+ name = _("<unknown>");
+ break;
+ case 0xfffe:
+ name = _("<vague>");
+ break;
+ default:
+ idx--;
+
+ for (entry = dynamic_section;
+ entry < dynamic_section + dynamic_nent && idx > 0;
+ entry++)
+ if (entry->d_tag == DT_NEEDED)
+ idx--;
+
+ if (idx == 0)
+ {
+ if (VALID_DYNAMIC_NAME (entry->d_un.d_val))
+ name = GET_DYNAMIC_NAME (entry->d_un.d_val);
+ else
+ name = NULL;
+ }
+ break;
+ }
+
+ if (!name)
+ name = _("<out-of-range>");
+ if (do_wide)
+ printf ("%s", name);
+ else
+ printf ("%-25s", name);
+}
+
+static int
+process_direct (FILE *file)
+{
+ unsigned int i;
+ unsigned int si;
+ char *strtab;
+ unsigned char *directtab;
+ Elf_Internal_Sym *symtab = NULL;
+ Elf_Internal_Sym *psym;
+ Elf_Internal_Shdr *direct = NULL;
+ Elf_Internal_Shdr *dynsym = NULL;
+ Elf_Internal_Shdr *section;
+
+ if (!do_direct)
+ return 1;
+ if (!dynamic_symbols || !dynamic_section || !dynamic_strings)
+ return 1;
+
+ for (i = 0, section = section_headers;
+ i < elf_header.e_shnum;
+ i++, section++)
+ {
+ if (section->sh_type == SHT_DYNSYM)
+ dynsym = section;
+ if (!strcmp (SECTION_NAME (section), ".direct"))
+ direct = section;
+ }
+ if (!dynsym || !direct)
+ return 1;
+
+ symtab = GET_ELF_SYMBOLS (file, dynsym);
+ if (!symtab)
+ return 1;
+
+ directtab = get_data (NULL, file, direct->sh_offset,
+ direct->sh_size, _("direct linkage table"));
+ if (!symtab)
+ {
+ free (symtab);
+ return 1;
+ }
+
+ if (dynsym->sh_link == elf_header.e_shstrndx)
+ strtab = string_table;
+ else
+ {
+ Elf_Internal_Shdr *string_sec;
+
+ string_sec = SECTION_HEADER (dynsym->sh_link);
+
+ strtab = get_data (NULL, file, string_sec->sh_offset,
+ string_sec->sh_size, _("string table"));
+ }
+
+ assert (strtab != NULL);
+
+ printf (_("\nDirect relocations for image:\n"));
+ printf (_(" Num: Index Binding Symbol\n"));
+ for (si = 0, psym = symtab;
+ si < dynsym->sh_size / dynsym->sh_entsize;
+ si++, psym++)
+ {
+ unsigned int field;
+ printf ("%6d: ", si);
+ field = byte_get (directtab + (si * 2), 2);
+ printf ("[0x%.4x] ", field);
+ print_dt_needed_name (field);
+ printf (" ");
+ print_symbol (25, strtab + psym->st_name);
+ printf ("\n");
+ }
+
+
+ free (symtab);
+ if (strtab != string_table)
+ free (strtab);
+
+ return 1;
+}
+
+
/* Process the unwind section. */
#include "unwind-ia64.h"
@@ -11784,6 +11917,8 @@
process_relocs (file);
+ process_direct (file);
+
process_unwind (file);
process_symbol_table (file);
diff -u -r -x '*.o' -x '*.1' -x 'Makefile*' -x 'config*' -x libtool -x '*.info' -x '*.tex' binutils-2.16/include/bfdlink.h binutils.current/include/bfdlink.h
--- binutils-2.16/include/bfdlink.h 2005-03-03 11:58:00.000000000 +0000
+++ binutils.current/include/bfdlink.h 2005-10-19 20:39:19.000000000 +0100
@@ -244,6 +244,9 @@
/* TRUE if BFD should pre-bind symbols in a shared object. */
unsigned int symbolic: 1;
+ /* TRUE if BFD should bind symbols directly to resolved at link time. */
+ unsigned int direct: 1;
+
/* TRUE if BFD should export all symbols in the dynamic symbol table
of an executable, rather than only those used. */
unsigned int export_dynamic: 1;
@@ -416,6 +419,12 @@
/* Start and end of RELRO region. */
bfd_vma relro_start, relro_end;
+
+ /* function to filter out symbols that must not be directly linked */
+ int (*direct_vague) (struct bfd_link_info *, const char *symbol);
+
+ /* current max dtinfo section number */
+ int dt_needed_index;
};
/* This structures holds a set of callback functions. These are
Only in binutils.current/include: bfdlink.h~
diff -u -r -x '*.o' -x '*.1' -x 'Makefile*' -x 'config*' -x libtool -x '*.info' -x '*.tex' binutils-2.16/include/elf/common.h binutils.current/include/elf/common.h
--- binutils-2.16/include/elf/common.h 2004-10-08 14:55:08.000000000 +0100
+++ binutils.current/include/elf/common.h 2005-10-15 11:31:38.000000000 +0100
@@ -586,6 +586,7 @@
/* This tag is a GNU extension to the Solaris version scheme. */
#define DT_VERSYM 0x6ffffff0
+#define DT_DIRECT 0x6ffffff1 /* FIXME - how are these allocated ? */
#define DT_LOPROC 0x70000000
#define DT_HIPROC 0x7fffffff
Only in binutils.current/include/elf: common.h~
diff -u -r -x '*.o' -x '*.1' -x 'Makefile*' -x 'config*' -x libtool -x '*.info' -x '*.tex' binutils-2.16/include/elf/external.h binutils.current/include/elf/external.h
--- binutils-2.16/include/elf/external.h 2005-03-03 11:58:05.000000000 +0000
+++ binutils.current/include/elf/external.h 2005-10-15 11:29:45.000000000 +0100
@@ -213,6 +213,10 @@
unsigned char vd_next[4];
} Elf_External_Verdef;
+typedef struct {
+ unsigned char dir_libidx[2];
+} Elf_External_Direct;
+
/* This structure appears in a SHT_GNU_verdef section. */
typedef struct {
Only in binutils.current/include/elf: external.h~
Files binutils-2.16/ld/ld-new and binutils.current/ld/ld-new differ
diff -u -r -x '*.o' -x '*.1' -x 'Makefile*' -x 'config*' -x libtool -x '*.info' -x '*.tex' binutils-2.16/ld/lexsup.c binutils.current/ld/lexsup.c
--- binutils-2.16/ld/lexsup.c 2005-03-03 11:52:00.000000000 +0000
+++ binutils.current/ld/lexsup.c 2005-10-20 14:57:01.000000000 +0100
@@ -70,6 +70,7 @@
OPTION_CREF,
OPTION_DEFSYM,
OPTION_DEMANGLE,
+ OPTION_DIRECT,
OPTION_DYNAMIC_LINKER,
OPTION_SYSROOT,
OPTION_EB,
@@ -341,6 +342,8 @@
'\0', NULL, NULL, ONE_DASH },
{ {"Bsymbolic", no_argument, NULL, OPTION_SYMBOLIC},
'\0', NULL, N_("Bind global references locally"), ONE_DASH },
+ { {"Bdirect", no_argument, NULL, OPTION_DIRECT},
+ '\0', NULL, N_("Direct-linkage the the shared libraries"), ONE_DASH },
{ {"check-sections", no_argument, NULL, OPTION_CHECK_SECTIONS},
'\0', NULL, N_("Check section addresses for overlaps (default)"),
TWO_DASHES },
@@ -522,6 +525,25 @@
#define OPTION_COUNT ARRAY_SIZE (ld_options)
+static int
+is_direct_vague (struct bfd_link_info *info, const char *symbol)
+{
+ int ret = 0;
+
+ /* C++ typeinfo foo */
+ if (symbol && getenv ("KILL_CPP_VAGUE"))
+ {
+ if (symbol[0] == '_' && symbol[1] == 'Z' && symbol[2] == 'T'
+ && (symbol[3] == 'I' || symbol[3] == 'S'))
+ ret = 1;
+ }
+
+/* fprintf (stderr, "Is '%s' %c%c%c vague (%d)\n",
+ symbol, symbol[0], symbol[1], symbol[2], ret); */
+
+ return ret;
+}
+
void
parse_args (unsigned argc, char **argv)
{
@@ -746,6 +768,10 @@
cplus_demangle_set_style (style);
}
break;
+ case OPTION_DIRECT:
+ link_info.direct = TRUE;
+ link_info.direct_vague = is_direct_vague;
+ break;
case 'I': /* Used on Solaris. */
case OPTION_DYNAMIC_LINKER:
command_line.interpreter = optarg;
Thanks,
Michael.
--
michael.meeks@novell.com <><, Pseudo Engineer, itinerant idiot