summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
authorAli Bahrami <Ali.Bahrami@Sun.COM>2009-01-22 09:54:25 -0700
committerAli Bahrami <Ali.Bahrami@Sun.COM>2009-01-22 09:54:25 -0700
commit6b3ba5bde920961dbf915c89b7736f96ff487d20 (patch)
treec0a022a29ab20652140ff131405c715a82d65714 /usr/src
parent63528ae45fc8c92cddd3c3b0dc846a9be84f44ac (diff)
downloadillumos-gate-6b3ba5bde920961dbf915c89b7736f96ff487d20.tar.gz
6792836 ld is slow when processing GNU linkonce sections
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/cmd/sgs/include/libld.h20
-rw-r--r--usr/src/cmd/sgs/libld/common/_libld.h18
-rw-r--r--usr/src/cmd/sgs/libld/common/debug.c15
-rw-r--r--usr/src/cmd/sgs/libld/common/files.c3
-rw-r--r--usr/src/cmd/sgs/libld/common/groups.c70
-rw-r--r--usr/src/cmd/sgs/libld/common/libs.c4
-rw-r--r--usr/src/cmd/sgs/libld/common/place.c54
-rw-r--r--usr/src/cmd/sgs/libld/common/relocate.c172
-rw-r--r--usr/src/cmd/sgs/libld/common/sections.c19
-rw-r--r--usr/src/cmd/sgs/libld/common/syms.c327
-rw-r--r--usr/src/cmd/sgs/libld/common/util.c32
-rw-r--r--usr/src/cmd/sgs/packages/common/SUNWonld-README1
-rw-r--r--usr/src/cmd/sgs/tools/common/string_table.c31
13 files changed, 412 insertions, 354 deletions
diff --git a/usr/src/cmd/sgs/include/libld.h b/usr/src/cmd/sgs/include/libld.h
index 211a02b9a9..c9a1e69d63 100644
--- a/usr/src/cmd/sgs/include/libld.h
+++ b/usr/src/cmd/sgs/include/libld.h
@@ -128,6 +128,16 @@ typedef struct {
} Gottable;
/*
+ * The link-editor caches the results of sloppy relocation processing
+ * in a variable of this type. Symbols come for processing in sorted
+ * order, so a 1 element cache suffices to eliminate duplicate lookups.
+ */
+typedef struct sreloc_cache {
+ Sym_desc *sr_osdp; /* Original symbol */
+ Sym_desc *sr_rsdp; /* Replacement symbol */
+} Sreloc_cache;
+
+/*
* Output file processing structure
*/
typedef Lword ofl_flag_t;
@@ -279,6 +289,8 @@ struct ofl_desc {
Xword ofl_sfcap_1; /* software capabilities */
Lm_list *ofl_lml; /* runtime link-map list */
Gottable *ofl_gottable; /* debugging got information */
+ Sreloc_cache ofl_sr_cache; /* Cache last result from */
+ /* sloppy_comdat_reloc() */
};
#define FLG_OF_DYNAMIC 0x00000001 /* generate dynamic output module */
@@ -559,6 +571,8 @@ struct is_desc { /* input section descriptor */
/* input section */
Elf_Data *is_indata; /* input sections raw data */
Is_desc *is_symshndx; /* related SHT_SYM_SHNDX section */
+ Is_desc *is_comdatkeep; /* If COMDAT section is discarded, */
+ /* this is section that was kept */
Word is_scnndx; /* original section index in file */
Word is_txtndx; /* Index for section. Used to decide */
/* where to insert section when */
@@ -590,15 +604,15 @@ struct os_desc { /* Output section descriptor */
Elf_Scn *os_scn; /* the elf section descriptor */
Shdr *os_shdr; /* the elf section header */
Os_desc *os_relosdesc; /* the output relocation section */
- List os_relisdescs; /* reloc input section descriptors */
+ APlist *os_relisdescs; /* reloc input section descriptors */
/* for this output section */
List os_isdescs; /* list of input sections in output */
APlist *os_mstrisdescs; /* FLG_IS_INSTRMRG input sections */
Sort_desc *os_sort; /* used for sorting sections */
Sg_desc *os_sgdesc; /* segment os_desc is placed on */
Elf_Data *os_outdata; /* output sections raw data */
- APlist *os_comdats; /* list of COMDAT sections present */
- /* in current output section */
+ avl_tree_t *os_comdats; /* AVL tree of COMDAT input sections */
+ /* associated to output section */
Word os_scnsymndx; /* index in output symtab of section */
/* symbol for this section */
Word os_txtndx; /* Index for section. Used to decide */
diff --git a/usr/src/cmd/sgs/libld/common/_libld.h b/usr/src/cmd/sgs/libld/common/_libld.h
index d35501a9ca..2788ed3aea 100644
--- a/usr/src/cmd/sgs/libld/common/_libld.h
+++ b/usr/src/cmd/sgs/libld/common/_libld.h
@@ -305,7 +305,7 @@ struct _ld_heap {
void *lh_end;
};
-#define HEAPBLOCK 0x68000 /* default allocation block size */
+#define HEAPBLOCK 0x800000 /* default allocation block size */
#define HEAPALIGN 0x8 /* heap blocks alignment requirement */
/*
@@ -334,6 +334,7 @@ typedef struct {
#define AL_CNT_OFL_DTSFLTRS 4 /* ofl_dtsfltrs initial alist count */
#define AL_CNT_OFL_SYMFLTRS 20 /* ofl_symfltrs initial alist count */
#define AL_CNT_OS_MSTRISDESCS 10 /* os_mstrisdescs */
+#define AL_CNT_OS_RELISDESCS 100 /* os_relisdescs */
#define AL_CNT_OS_COMDATS 20 /* os_comdats */
#define AL_CNT_SG_OSDESC 40 /* sg_osdescs initial alist count */
#define AL_CNT_SG_SECORDER 40 /* sg_secorder initial alist count */
@@ -474,7 +475,6 @@ extern const int dynsymsort_symtype[STT_NUM];
(*_cnt_var)_inc_or_dec_op; /* Increment/Decrement */ \
}
-
/*
* The OFL_SWAP_RELOC macros are used to determine whether
* relocation processing needs to swap the data being relocated.
@@ -482,12 +482,21 @@ extern const int dynsymsort_symtype[STT_NUM];
* the function call in the case where the linker host and the
* target have the same byte order.
*/
-
#define OFL_SWAP_RELOC_DATA(_ofl, _rel) \
(((_ofl)->ofl_flags1 & FLG_OF1_ENCDIFF) && \
ld_swap_reloc_data(_ofl, _rel))
/*
+ * Define an AVL node for maintaining input section descriptors. AVL trees of
+ * these descriptors are used to process group and COMDAT section.
+ */
+typedef struct {
+ avl_node_t isd_avl; /* avl book-keeping (see SGSOFFSETOF) */
+ Is_desc *isd_isp; /* input section descriptor */
+ uint_t isd_hash; /* input section name hash value */
+} Isd_node;
+
+/*
* Local functions.
*/
extern char *add_string(char *, char *);
@@ -504,6 +513,8 @@ extern Listnode *list_insertc(List *, const void *, Listnode *);
extern Listnode *list_prependc(List *, const void *);
extern Listnode *list_where(List *, Word num);
+extern int isdavl_compare(const void *, const void *);
+
extern Sdf_desc *sdf_add(const char *, List *);
extern Sdf_desc *sdf_find(const char *, List *);
@@ -802,7 +813,6 @@ extern Word hashbkts(Word);
extern Xword lcm(Xword, Xword);
extern Listnode *list_where(List *, Word);
-
/*
* Most platforms have both a 32 and 64-bit variant (e.g. EM_SPARC and
* EM_SPARCV9). To support this, there many files in libld that are built
diff --git a/usr/src/cmd/sgs/libld/common/debug.c b/usr/src/cmd/sgs/libld/common/debug.c
index 36c34fdb25..6508b422a9 100644
--- a/usr/src/cmd/sgs/libld/common/debug.c
+++ b/usr/src/cmd/sgs/libld/common/debug.c
@@ -20,10 +20,9 @@
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
#include <stdio.h>
#include <stdarg.h>
@@ -49,7 +48,7 @@
* dbg_print() can require the output filename for use in the diagnostics
* created. Save the address of the output filename pointer for this use.
*/
-static const char **Name = 0;
+static const char **Name = NULL;
static int Phase = 0;
uintptr_t
@@ -73,7 +72,7 @@ dbg_setup(const char *options, Dbg_desc *dbp, const char **name, int phase)
void
dbg_print(Lm_list *lml, const char *format, ...)
{
- static char *prestr = 0;
+ static char *prestr = NULL;
va_list args;
#if defined(lint)
@@ -81,7 +80,7 @@ dbg_print(Lm_list *lml, const char *format, ...)
* The lml argument is only meaningful for diagnostics sent to ld.so.1.
* Supress the lint error by making a dummy assignment.
*/
- lml = 0;
+ lml = NULL;
#endif
/*
* Knock off any newline indicator to signify that a diagnostic has
@@ -94,7 +93,7 @@ dbg_print(Lm_list *lml, const char *format, ...)
* If the debugging options have requested each diagnostic line
* be prepended by a name create a prefix string.
*/
- if ((prestr == 0) && *Name) {
+ if ((prestr == NULL) && *Name) {
const char *name, *cls;
size_t len;
@@ -106,7 +105,7 @@ dbg_print(Lm_list *lml, const char *format, ...)
name = *Name;
else {
if ((name =
- strrchr(*Name, '/')) == 0)
+ strrchr(*Name, '/')) == NULL)
name = *Name;
else
name++;
@@ -130,7 +129,7 @@ dbg_print(Lm_list *lml, const char *format, ...)
/*
* Allocate a string to build the prefix.
*/
- if ((prestr = malloc(len)) == 0)
+ if ((prestr = libld_malloc(len)) == NULL)
prestr = (char *)MSG_INTL(MSG_DBG_DFLT_FMT);
else {
(void) snprintf(prestr, len,
diff --git a/usr/src/cmd/sgs/libld/common/files.c b/usr/src/cmd/sgs/libld/common/files.c
index 1062e34326..26700a1fed 100644
--- a/usr/src/cmd/sgs/libld/common/files.c
+++ b/usr/src/cmd/sgs/libld/common/files.c
@@ -1368,7 +1368,8 @@ rel_process(Is_desc *isc, Ifl_desc *ifl, Ofl_desc *ofl)
isc->is_name, risc->is_name);
return (0);
}
- if (list_appendc(&osp->os_relisdescs, isc) == 0)
+ if (aplist_append(&osp->os_relisdescs, isc,
+ AL_CNT_OS_RELISDESCS) == NULL)
return (S_ERROR);
}
return (1);
diff --git a/usr/src/cmd/sgs/libld/common/groups.c b/usr/src/cmd/sgs/libld/common/groups.c
index aa76e2ed4a..d2053c2144 100644
--- a/usr/src/cmd/sgs/libld/common/groups.c
+++ b/usr/src/cmd/sgs/libld/common/groups.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -32,43 +32,6 @@
#include "_libld.h"
/*
- * Define an AVL node for maintain group names, together with a compare function
- * for the Grp_node AVL tree.
- */
-typedef struct {
- const char *gn_name; /* group name */
- Is_desc *gn_isc; /* group input section */
- avl_node_t gn_avl; /* avl book-keeping (see SGSOFFSETOF) */
- uint_t gn_hash; /* group name hash value */
-} Grp_node;
-
-static int
-gnavl_compare(const void *n1, const void *n2)
-{
- uint_t hash1, hash2;
- const char *st1, *st2;
- int rc;
-
- hash1 = ((Grp_node *)n1)->gn_hash;
- hash2 = ((Grp_node *)n2)->gn_hash;
-
- if (hash1 > hash2)
- return (1);
- if (hash1 < hash2)
- return (-1);
-
- st1 = ((Grp_node *)n1)->gn_name;
- st2 = ((Grp_node *)n2)->gn_name;
-
- rc = strcmp(st1, st2);
- if (rc > 0)
- return (1);
- if (rc < 0)
- return (-1);
- return (0);
-}
-
-/*
* Determine whether a (COMDAT) group has already been encountered. If so,
* indicate that the group descriptor has an overriding group (gd_oisc). This
* indication triggers the ld_place_section() to discard this group, while the
@@ -79,40 +42,39 @@ gnavl_compare(const void *n1, const void *n2)
static uintptr_t
gpavl_loaded(Ofl_desc *ofl, Group_desc *gdp)
{
- Grp_node gpn, *gpnp;
+ Isd_node isd, *isdp;
avl_tree_t *avlt;
avl_index_t where;
/*
- * Create an avl tree if required.
+ * Create a groups avl tree if required.
*/
- if ((avlt = ofl->ofl_groups) == 0) {
- if ((avlt = calloc(sizeof (avl_tree_t), 1)) == NULL)
+ if ((avlt = ofl->ofl_groups) == NULL) {
+ if ((avlt = libld_calloc(sizeof (avl_tree_t), 1)) == NULL)
return (S_ERROR);
- avl_create(avlt, gnavl_compare, sizeof (Grp_node),
- SGSOFFSETOF(Grp_node, gn_avl));
+ avl_create(avlt, isdavl_compare, sizeof (Isd_node),
+ SGSOFFSETOF(Isd_node, isd_avl));
ofl->ofl_groups = avlt;
}
- gpn.gn_name = gdp->gd_name;
- gpn.gn_hash = sgs_str_hash(gdp->gd_name);
+ isd.isd_hash = sgs_str_hash(gdp->gd_isc->is_name);
+ isd.isd_isp = gdp->gd_isc;
- if ((gpnp = avl_find(avlt, &gpn, &where)) != NULL) {
- gdp->gd_oisc = gpnp->gn_isc;
+ if ((isdp = avl_find(avlt, &isd, &where)) != NULL) {
+ gdp->gd_oisc = isdp->isd_isp;
return (1);
}
/*
- * This is a new group, save it.
+ * This is a new group - so keep it.
*/
- if ((gpnp = calloc(sizeof (Grp_node), 1)) == NULL)
+ if ((isdp = libld_calloc(sizeof (Isd_node), 1)) == NULL)
return (S_ERROR);
- gpnp->gn_name = gpn.gn_name;
- gpnp->gn_hash = gpn.gn_hash;
- gpnp->gn_isc = gdp->gd_isc;
+ isdp->isd_hash = isd.isd_hash;
+ isdp->isd_isp = isd.isd_isp;
- avl_insert(avlt, gpnp, where);
+ avl_insert(avlt, isdp, where);
return (0);
}
diff --git a/usr/src/cmd/sgs/libld/common/libs.c b/usr/src/cmd/sgs/libld/common/libs.c
index bb84ecad8b..f19321f599 100644
--- a/usr/src/cmd/sgs/libld/common/libs.c
+++ b/usr/src/cmd/sgs/libld/common/libs.c
@@ -23,7 +23,7 @@
* Copyright (c) 1988 AT&T
* All Rights Reserved
*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -171,7 +171,7 @@ process_member(Ar_mem *amp, const char *name, Sym_desc *sdp, Ofl_desc *ofl)
continue;
}
- if (strcmp(strs + syms->st_name, name) == NULL)
+ if (strcmp(strs + syms->st_name, name) == 0)
return (1);
}
return (0);
diff --git a/usr/src/cmd/sgs/libld/common/place.c b/usr/src/cmd/sgs/libld/common/place.c
index 178820df09..0a13708393 100644
--- a/usr/src/cmd/sgs/libld/common/place.c
+++ b/usr/src/cmd/sgs/libld/common/place.c
@@ -23,7 +23,7 @@
* Copyright (c) 1988 AT&T
* All Rights Reserved
*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -152,13 +152,24 @@ ld_append_isp(Ofl_desc * ofl, Os_desc *osp, Is_desc *isp, int mstr_only)
static uintptr_t
add_comdat(Ofl_desc *ofl, Os_desc *osp, Is_desc *isp)
{
- Aliste idx;
- Is_desc *cisp;
+ Isd_node isd, *isdp;
+ avl_tree_t *avlt;
+ avl_index_t where;
- for (APLIST_TRAVERSE(osp->os_comdats, idx, cisp)) {
- if (strcmp(isp->is_name, cisp->is_name))
- continue;
+ /*
+ * Create a COMDAT avl tree for this output section if required.
+ */
+ if ((avlt = osp->os_comdats) == NULL) {
+ if ((avlt = libld_calloc(sizeof (avl_tree_t), 1)) == NULL)
+ return (S_ERROR);
+ avl_create(avlt, isdavl_compare, sizeof (Isd_node),
+ SGSOFFSETOF(Isd_node, isd_avl));
+ osp->os_comdats = avlt;
+ }
+ isd.isd_hash = sgs_str_hash(isp->is_name);
+ isd.isd_isp = isp;
+ if ((isdp = avl_find(avlt, &isd, &where)) != NULL) {
isp->is_osdesc = osp;
/*
@@ -167,7 +178,9 @@ add_comdat(Ofl_desc *ofl, Os_desc *osp, Is_desc *isp)
*/
if ((isp->is_flags & FLG_IS_DISCARD) == 0) {
isp->is_flags |= FLG_IS_DISCARD;
- DBG_CALL(Dbg_sec_discarded(ofl->ofl_lml, isp, cisp));
+ isp->is_comdatkeep = isdp->isd_isp;
+ DBG_CALL(Dbg_sec_discarded(ofl->ofl_lml, isp,
+ isdp->isd_isp));
}
/*
@@ -178,18 +191,19 @@ add_comdat(Ofl_desc *ofl, Os_desc *osp, Is_desc *isp)
* output section so that the sloppy relocation logic will have
* the information necessary to do its work.
*/
- if (ofl->ofl_flags1 & FLG_OF1_RLXREL)
- return (1);
- else
- return (0);
+ return (0);
}
/*
* This is a new COMDAT section - so keep it.
*/
- if (aplist_append(&(osp->os_comdats), isp, AL_CNT_OS_COMDATS) == NULL)
+ if ((isdp = libld_calloc(sizeof (Isd_node), 1)) == NULL)
return (S_ERROR);
+ isdp->isd_hash = isd.isd_hash;
+ isdp->isd_isp = isp;
+
+ avl_insert(avlt, isdp, where);
return (1);
}
@@ -223,7 +237,7 @@ gnu_comdat_sym(Ifl_desc *ifl, Is_desc *gisp)
* link-edits. For now, size the section name dynamically.
*/
ssize = strlen(isp->is_name);
- if ((strncmp(isp->is_name, gisp->is_name, ssize) != NULL) &&
+ if ((strncmp(isp->is_name, gisp->is_name, ssize) != 0) &&
(gisp->is_name[ssize] == '.'))
return ((char *)&gisp->is_name[ssize]);
}
@@ -382,7 +396,7 @@ ld_place_section(Ofl_desc *ofl, Is_desc *isp, int ident, Word link)
* the information necessary to do its work.
*/
if (!(ofl->ofl_flags1 & FLG_OF1_RLXREL))
- return ((Os_desc *)0);
+ return (NULL);
}
}
@@ -393,7 +407,7 @@ ld_place_section(Ofl_desc *ofl, Is_desc *isp, int ident, Word link)
if (shdr->sh_type == SHT_GROUP) {
if ((ofl->ofl_flags & FLG_OF_RELOBJ) == 0) {
isp->is_flags |= FLG_IS_DISCARD;
- return ((Os_desc *)0);
+ return (NULL);
}
}
}
@@ -429,7 +443,7 @@ ld_place_section(Ofl_desc *ofl, Is_desc *isp, int ident, Word link)
char *file;
int found = 0;
- if (isp->is_file == 0)
+ if (isp->is_file == NULL)
continue;
for (LIST_TRAVERSE(&(enp->ec_files), lnp2, file)) {
@@ -461,7 +475,7 @@ ld_place_section(Ofl_desc *ofl, Is_desc *isp, int ident, Word link)
break;
}
- if ((sgp = enp->ec_segment) == 0)
+ if ((sgp = enp->ec_segment) == NULL)
sgp = ((Ent_desc *)(ofl->ofl_ents.tail->data))->ec_segment;
/*
@@ -785,9 +799,9 @@ ld_place_section(Ofl_desc *ofl, Is_desc *isp, int ident, Word link)
/*
* Create a new output section descriptor.
*/
- if ((osp = libld_calloc(sizeof (Os_desc), 1)) == 0)
+ if ((osp = libld_calloc(sizeof (Os_desc), 1)) == NULL)
return ((Os_desc *)S_ERROR);
- if ((osp->os_shdr = libld_calloc(sizeof (Shdr), 1)) == 0)
+ if ((osp->os_shdr = libld_calloc(sizeof (Shdr), 1)) == NULL)
return ((Os_desc *)S_ERROR);
/*
@@ -805,7 +819,7 @@ ld_place_section(Ofl_desc *ofl, Is_desc *isp, int ident, Word link)
shdr->sh_type = SHT_PROGBITS;
}
if ((isp->is_flags & FLG_IS_COMDAT) &&
- (aplist_append(&(osp->os_comdats), isp, AL_CNT_OS_COMDATS) == NULL))
+ (add_comdat(ofl, osp, isp) == S_ERROR))
return ((Os_desc *)S_ERROR);
osp->os_shdr->sh_type = shdr->sh_type;
diff --git a/usr/src/cmd/sgs/libld/common/relocate.c b/usr/src/cmd/sgs/libld/common/relocate.c
index 2e41e760e9..498fd79d79 100644
--- a/usr/src/cmd/sgs/libld/common/relocate.c
+++ b/usr/src/cmd/sgs/libld/common/relocate.c
@@ -23,7 +23,7 @@
* Copyright (c) 1988 AT&T
* All Rights Reserved
*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -1363,11 +1363,13 @@ ld_process_sym_reloc(Ofl_desc *ofl, Rel_desc *reld, Rel *reloc, Is_desc *isp,
*
* entry:
* reld - Relocation
- * orig_sdp - Symbol to be replaced. Must be a local symbol (STB_LOCAL).
+ * sdp - Symbol to be replaced. Must be a local symbol (STB_LOCAL).
*
* exit:
* Returns address of replacement symbol descriptor if one was
- * found, and NULL otherwise.
+ * found, and NULL otherwise. The result is also cached in
+ * ofl->ofl_sr_cache as an optimization to speed following calls
+ * for the same value of sdp.
*
* note:
* The word "COMDAT" is used to refer to actual COMDAT sections, COMDAT
@@ -1383,7 +1385,7 @@ ld_process_sym_reloc(Ofl_desc *ofl, Rel_desc *reld, Rel *reloc, Is_desc *isp,
* really supply the correct information. However, we see a couple of
* situations where it is useful to do this: (1) Older Sun C compilers
* generated DWARF sections that would refer to one of the COMDAT
- * sections, and (2) gcc, when its COMDAT feature is enabled.
+ * sections, and (2) gcc, when its GNU linkonce COMDAT feature is enabled.
* It turns out that the GNU ld does these sloppy remappings.
*
* The GNU ld takes an approach that hard wires special section
@@ -1393,35 +1395,39 @@ ld_process_sym_reloc(Ofl_desc *ofl, Rel_desc *reld, Rel *reloc, Is_desc *isp,
* that our heuristic is somewhat different than theirs, but the
* end result is close enough to solve the same problem.
*
- * gcc may eventually phase out the need for sloppy relocations, and
+ * gcc is in the process of converting to SHF_GROUP. This will
+ * eventually phase out the need for sloppy relocations, and
* then this logic won't be needed. In the meantime, relaxed relocation
* processing allows us to interoperate.
- *
- * Here is how we do it: The symbol points at the input section,
- * and the input section points at the output section to which it
- * is assigned. The output section contains a list of all of the
- * input sections that have been mapped to it, including the
- * corresponding COMDAT section that was kept. The kept COMDAT
- * section contains a reference to its input file, where we can find
- * the array of all the symbols in that file. From the input file,
- * we then locate the corresponding symbol that references the kept
- * COMDAT section.
- *
*/
static Sym_desc *
sloppy_comdat_reloc(Ofl_desc *ofl, Rel_desc *reld, Sym_desc *sdp)
{
- Listnode *lnp;
Is_desc *rep_isp;
- Sym *sym = sdp->sd_sym;
- Is_desc *isp = sdp->sd_isc;
- Ifl_desc *ifl = sdp->sd_file;
+ Sym *sym, *rep_sym;
+ Is_desc *isp;
+ Ifl_desc *ifl;
Conv_inv_buf_t inv_buf;
+ Word scnndx, symscnt;
+ Sym_desc **oldndx, *rep_sdp;
/*
- * Examine each input section assigned to this output section.
- * The replacement section must:
- * - Have the same name as the original
+ * If we looked up the same symbol on the previous call, we can
+ * return the cached value.
+ */
+ if (sdp == ofl->ofl_sr_cache.sr_osdp)
+ return (ofl->ofl_sr_cache.sr_rsdp);
+
+ ofl->ofl_sr_cache.sr_osdp = sdp;
+ sym = sdp->sd_sym;
+ isp = sdp->sd_isc;
+ ifl = sdp->sd_file;
+
+ /*
+ * When a COMDAT section is discarded in favor of another COMDAT
+ * section, the replacement is recorded in its section descriptor
+ * (is_comdatkeep). We must validate the replacement before using
+ * it. The replacement section must:
* - Not have been discarded
* - Have the same size (*)
* - Have the same section type
@@ -1434,81 +1440,74 @@ sloppy_comdat_reloc(Ofl_desc *ofl, Rel_desc *reld, Sym_desc *sdp)
* ld. If the sections are not the same size, the chance of them
* being interchangeable drops significantly.
*/
- /* BEGIN CSTYLED */
- for (LIST_TRAVERSE(&isp->is_osdesc->os_isdescs, lnp, rep_isp)) {
+ if (((rep_isp = isp->is_comdatkeep) == NULL) ||
+ ((rep_isp->is_flags & FLG_IS_DISCARD) != 0) ||
+ ((rep_isp->is_flags & FLG_IS_COMDAT) == 0) ||
+ (isp->is_indata->d_size != rep_isp->is_indata->d_size) ||
+ (isp->is_shdr->sh_type != rep_isp->is_shdr->sh_type) ||
+ ((isp->is_shdr->sh_flags & SHF_GROUP) !=
+ (rep_isp->is_shdr->sh_flags & SHF_GROUP)))
+ return (ofl->ofl_sr_cache.sr_rsdp = NULL);
+
+ /*
+ * We found the kept COMDAT section. Now, look at all of the
+ * symbols from the input file that contains it to find the
+ * symbol that corresponds to the one we started with:
+ * - Hasn't been discarded
+ * - Has section index of kept section
+ * - If one symbol has a name, the other must have
+ * the same name. The st_name field of a symbol
+ * is 0 if there is no name, and is a string
+ * table offset otherwise. The string table
+ * offsets may well not agree --- it is the
+ * actual string that matters.
+ * - Type and binding attributes match (st_info)
+ * - Values match (st_value)
+ * - Sizes match (st_size)
+ * - Visibility matches (st_other)
+ */
+ scnndx = rep_isp->is_scnndx;
+ oldndx = rep_isp->is_file->ifl_oldndx;
+ symscnt = rep_isp->is_file->ifl_symscnt;
+ while (symscnt--) {
+ rep_sdp = *oldndx++;
+ if ((rep_sdp == NULL) || (rep_sdp->sd_flags & FLG_SY_ISDISC) ||
+ ((rep_sym = rep_sdp->sd_sym)->st_shndx != scnndx) ||
+ ((sym->st_name == 0) != (rep_sym->st_name == 0)) ||
+ ((sym->st_name != 0) &&
+ (strcmp(sdp->sd_name, rep_sdp->sd_name) != 0)) ||
+ (sym->st_info != rep_sym->st_info) ||
+ (sym->st_value != rep_sym->st_value) ||
+ (sym->st_size != rep_sym->st_size) ||
+ (sym->st_other != rep_sym->st_other))
+ continue;
- if (((rep_isp->is_flags &
- (FLG_IS_COMDAT | FLG_IS_DISCARD)) == FLG_IS_COMDAT) &&
- (isp->is_indata->d_size == rep_isp->is_indata->d_size) &&
- (isp->is_shdr->sh_type == rep_isp->is_shdr->sh_type) &&
- ((isp->is_shdr->sh_flags & SHF_GROUP) ==
- (rep_isp->is_shdr->sh_flags & SHF_GROUP)) &&
- (strcmp(rep_isp->is_name, isp->is_name) == 0)) {
- /*
- * We found the kept COMDAT section. Now, look at all of the
- * symbols from the input file that contains it to find the
- * symbol that corresponds to the one we started with:
- * - Hasn't been discarded
- * - Has section index of kept section
- * - If one symbol has a name, the other must have
- * the same name. The st_name field of a symbol
- * is 0 if there is no name, and is a string
- * table offset otherwise. The string table
- * offsets may well not agree --- it is the
- * actual string that matters.
- * - Type and binding attributes match (st_info)
- * - Values match (st_value)
- * - Sizes match (st_size)
- * - Visibility matches (st_other)
- */
- Word scnndx = rep_isp->is_scnndx;
- Sym_desc **oldndx = rep_isp->is_file->ifl_oldndx;
- Word symscnt = rep_isp->is_file->ifl_symscnt;
- Sym_desc *rep_sdp;
- Sym *rep_sym;
-
- while (symscnt--) {
- rep_sdp = *oldndx++;
- if (rep_sdp && !(rep_sdp->sd_flags & FLG_SY_ISDISC) &&
- ((rep_sym = rep_sdp->sd_sym)->st_shndx == scnndx) &&
- ((sym->st_name == 0) == (rep_sym->st_name == 0)) &&
- !((sym->st_name != 0) &&
- (strcmp(sdp->sd_name, rep_sdp->sd_name) != 0)) &&
- (sym->st_info == rep_sym->st_info) &&
- (sym->st_value == rep_sym->st_value) &&
- (sym->st_size == rep_sym->st_size) &&
- (sym->st_other == rep_sym->st_other)) {
-
- if (ofl->ofl_flags & FLG_OF_VERBOSE) {
- if (sym->st_name != 0) {
+
+ if (ofl->ofl_flags & FLG_OF_VERBOSE) {
+ if (sym->st_name != 0) {
eprintf(ofl->ofl_lml, ERR_WARNING,
MSG_INTL(MSG_REL_SLOPCDATNAM),
conv_reloc_type(ifl->ifl_ehdr->e_machine,
- reld->rel_rtype, 0, &inv_buf),
+ reld->rel_rtype, 0, &inv_buf),
ifl->ifl_name, reld->rel_isdesc->is_name,
rep_sdp->sd_name, isp->is_name,
rep_sdp->sd_file->ifl_name);
- } else {
+ } else {
eprintf(ofl->ofl_lml, ERR_WARNING,
MSG_INTL(MSG_REL_SLOPCDATNONAM),
- conv_reloc_type(
- ifl->ifl_ehdr->e_machine,
- reld->rel_rtype, 0, &inv_buf),
+ conv_reloc_type(ifl->ifl_ehdr->e_machine,
+ reld->rel_rtype, 0, &inv_buf),
ifl->ifl_name, reld->rel_isdesc->is_name,
isp->is_name, rep_sdp->sd_file->ifl_name);
- }
}
- DBG_CALL(Dbg_reloc_sloppycomdat(ofl->ofl_lml,
- isp->is_name, rep_sdp));
- return (rep_sdp);
- }
}
- }
+ DBG_CALL(Dbg_reloc_sloppycomdat(ofl->ofl_lml,
+ isp->is_name, rep_sdp));
+ return (ofl->ofl_sr_cache.sr_rsdp = rep_sdp);
}
- /* END CSTYLED */
/* If didn't return above, we didn't find it */
- return (NULL);
+ return (ofl->ofl_sr_cache.sr_rsdp = NULL);
}
/*
@@ -1905,11 +1904,11 @@ reloc_segments(int wr_flag, Ofl_desc *ofl)
continue;
for (APLIST_TRAVERSE(sgp->sg_osdescs, idx, osp)) {
- Is_desc *risp;
- Listnode *lnp3;
+ Is_desc *risp;
+ Aliste idx;
osp->os_szoutrels = 0;
- for (LIST_TRAVERSE(&(osp->os_relisdescs), lnp3, risp)) {
+ for (APLIST_TRAVERSE(osp->os_relisdescs, idx, risp)) {
Word indx;
/*
@@ -1935,7 +1934,7 @@ reloc_segments(int wr_flag, Ofl_desc *ofl)
* Check for relocations against non-writable
* allocatable sections.
*/
- if ((osp->os_szoutrels) &&
+ if (osp->os_szoutrels &&
(sgp->sg_phdr.p_type == PT_LOAD) &&
((sgp->sg_phdr.p_flags & PF_W) == 0)) {
ofl->ofl_flags |= FLG_OF_TEXTREL;
@@ -2135,6 +2134,7 @@ ld_reloc_init(Ofl_desc *ofl)
if (reloc_segments(PF_W, ofl) == S_ERROR)
return (S_ERROR);
+
/*
* Process any extra relocations. These are relocation sections that
* have a NULL sh_info.
diff --git a/usr/src/cmd/sgs/libld/common/sections.c b/usr/src/cmd/sgs/libld/common/sections.c
index dfd8cd7d7a..933c28dd51 100644
--- a/usr/src/cmd/sgs/libld/common/sections.c
+++ b/usr/src/cmd/sgs/libld/common/sections.c
@@ -23,7 +23,7 @@
* Copyright (c) 1988 AT&T
* All Rights Reserved
*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -1905,27 +1905,24 @@ make_reloc(Ofl_desc *ofl, Os_desc *osp)
shdr->sh_flags |= SHF_INFO_LINK;
}
- /*
- * Associate this relocation section to the section its going to
- * relocate.
- */
rosp = ld_place_section(ofl, isec, ld_targ.t_id.id_rel, 0);
if (rosp == (Os_desc *)S_ERROR)
return (S_ERROR);
+ /*
+ * Associate this relocation section to the section its going to
+ * relocate.
+ */
if (osp) {
- Listnode *lnp;
- Is_desc *risp;
+ Aliste idx;
+ Is_desc *risp;
/*
- * We associate the input relocation sections - with
- * the newly created output relocation section.
- *
* This is used primarily so that we can update
* SHT_GROUP[sect_no] entries to point to the
* created output relocation sections.
*/
- for (LIST_TRAVERSE(&(osp->os_relisdescs), lnp, risp)) {
+ for (APLIST_TRAVERSE(osp->os_relisdescs, idx, risp)) {
risp->is_osdesc = rosp;
/*
diff --git a/usr/src/cmd/sgs/libld/common/syms.c b/usr/src/cmd/sgs/libld/common/syms.c
index 52ca5e28ec..43a09d3ac3 100644
--- a/usr/src/cmd/sgs/libld/common/syms.c
+++ b/usr/src/cmd/sgs/libld/common/syms.c
@@ -24,7 +24,7 @@
* All Rights Reserved
*
*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -43,15 +43,15 @@
/*
* AVL tree comparator function:
*
- * The primary key is the 'sa_hashval' with a secondary
- * key of the symbol name itself.
+ * The primary key is the symbol name hash with a secondary key of the symbol
+ * name itself.
*/
int
ld_sym_avl_comp(const void *elem1, const void *elem2)
{
- int res;
Sym_avlnode *sav1 = (Sym_avlnode *)elem1;
Sym_avlnode *sav2 = (Sym_avlnode *)elem2;
+ int res;
res = sav1->sav_hash - sav2->sav_hash;
@@ -71,7 +71,6 @@ ld_sym_avl_comp(const void *elem1, const void *elem2)
return (-1);
}
-
/*
* Focal point for verifying symbol names.
*/
@@ -80,21 +79,21 @@ string(Ofl_desc *ofl, Ifl_desc *ifl, Sym *sym, const char *strs, size_t strsize,
int symndx, Word shndx, const char *symsecname, const char *strsecname,
Word *flags)
{
- Word name = sym->st_name;
+ Word name = sym->st_name;
if (name) {
if ((ifl->ifl_flags & FLG_IF_HSTRTAB) == 0) {
eprintf(ofl->ofl_lml, ERR_FATAL,
MSG_INTL(MSG_FIL_NOSTRTABLE), ifl->ifl_name,
symsecname, symndx, EC_XWORD(name));
- return (0);
+ return (NULL);
}
if (name >= (Word)strsize) {
eprintf(ofl->ofl_lml, ERR_FATAL,
MSG_INTL(MSG_FIL_EXCSTRTABLE), ifl->ifl_name,
symsecname, symndx, EC_XWORD(name),
strsecname, EC_XWORD(strsize));
- return (0);
+ return (NULL);
}
}
@@ -107,7 +106,7 @@ string(Ofl_desc *ofl, Ifl_desc *ifl, Sym *sym, const char *strs, size_t strsize,
sym, strs, symndx, shndx, symsecname, flags);
if (regname == (const char *)S_ERROR) {
- return (0);
+ return (NULL);
}
if (regname)
return (regname);
@@ -128,7 +127,6 @@ string(Ofl_desc *ofl, Ifl_desc *ifl, Sym *sym, const char *strs, size_t strsize,
return (strs + name);
}
-
/*
* For producing symbol names strings to use in error messages.
* If the symbol has a non-null name, then the string returned by
@@ -145,13 +143,11 @@ demangle_symname(const char *name, const char *symtab_name, Word symndx)
{
#define INIT_BUFSIZE 256
- static char *buf;
- static size_t bufsize = 0;
-
+ static char *buf;
+ static size_t bufsize = 0;
size_t len;
int use_name;
-
use_name = (name != NULL) && (*name != '\0');
if (use_name) {
@@ -172,8 +168,7 @@ demangle_symname(const char *name, const char *symtab_name, Word symndx)
new_bufsize = INIT_BUFSIZE;
while (len > new_bufsize)
new_bufsize *= 2;
- new_buf = libld_malloc(new_bufsize);
- if (new_buf == NULL)
+ if ((new_buf = libld_malloc(new_bufsize)) == NULL)
return (name);
buf = new_buf;
bufsize = new_bufsize;
@@ -270,7 +265,7 @@ ld_sym_copy(Sym_desc *sdp)
Sym *nsym;
if (sdp->sd_flags & FLG_SY_CLEAN) {
- if ((nsym = libld_malloc(sizeof (Sym))) == 0)
+ if ((nsym = libld_malloc(sizeof (Sym))) == NULL)
return (S_ERROR);
*nsym = *(sdp->sd_sym);
sdp->sd_sym = nsym;
@@ -287,8 +282,7 @@ ld_sym_copy(Sym_desc *sdp)
Sym_desc *
ld_sym_find(const char *name, Word hash, avl_index_t *where, Ofl_desc *ofl)
{
- Sym_avlnode qsav;
- Sym_avlnode *sav;
+ Sym_avlnode qsav, *sav;
if (hash == SYM_NOHASH)
/* LINTED */
@@ -306,8 +300,8 @@ ld_sym_find(const char *name, Word hash, avl_index_t *where, Ofl_desc *ofl)
/*
* If symbol was not found in the avl tree, return null to show that.
*/
- if (sav == 0)
- return (0);
+ if (sav == NULL)
+ return (NULL);
/*
* Return symbol found.
@@ -315,7 +309,6 @@ ld_sym_find(const char *name, Word hash, avl_index_t *where, Ofl_desc *ofl)
return (sav->sav_symdesc);
}
-
/*
* Enter a new symbol into the link editors internal symbol table.
* If the symbol is from an input file, information regarding the input file
@@ -351,7 +344,7 @@ ld_sym_enter(const char *name, Sym *osym, Word hash, Ifl_desc *ifl,
* contiguously.
*/
if ((savl = libld_calloc(sizeof (Sym_avlnode) + sizeof (Sym_desc) +
- sizeof (Sym_aux), 1)) == 0)
+ sizeof (Sym_aux), 1)) == NULL)
return ((Sym_desc *)S_ERROR);
sdp = (Sym_desc *)((uintptr_t)savl + sizeof (Sym_avlnode));
sap = (Sym_aux *)((uintptr_t)sdp + sizeof (Sym_desc));
@@ -371,7 +364,7 @@ ld_sym_enter(const char *name, Sym *osym, Word hash, Ifl_desc *ifl,
sdp->sd_flags |= sdflags;
sdp->sd_flags1 |= sdflags1;
- if ((_name = libld_malloc(strlen(name) + 1)) == 0)
+ if ((_name = libld_malloc(strlen(name) + 1)) == NULL)
return ((Sym_desc *)S_ERROR);
savl->sav_name = sdp->sd_name = (const char *)strcpy(_name, name);
@@ -387,7 +380,7 @@ ld_sym_enter(const char *name, Sym *osym, Word hash, Ifl_desc *ifl,
*/
where = &_where;
_savl = avl_find(&ofl->ofl_symavl, savl, where);
- assert(_savl == 0);
+ assert(_savl == NULL);
}
avl_insert(&ofl->ofl_symavl, savl, *where);
@@ -409,7 +402,7 @@ ld_sym_enter(const char *name, Sym *osym, Word hash, Ifl_desc *ifl,
* caller can continue processing all symbols, and hence flush
* out as many error conditions as possible.
*/
- if ((etype == ET_REL) && (sdp->sd_isc == 0)) {
+ if ((etype == ET_REL) && (sdp->sd_isc == NULL)) {
eprintf(ofl->ofl_lml, ERR_FATAL,
MSG_INTL(MSG_SYM_INVSEC), name, ifl->ifl_name,
EC_XWORD(shndx));
@@ -555,10 +548,10 @@ ld_sym_enter(const char *name, Sym *osym, Word hash, Ifl_desc *ifl,
* The `sa_dfiles' list is used to maintain the list of files that
* define the same symbol. This list can be used for two reasons:
*
- * o To save the first definition of a symbol that is not available
+ * - To save the first definition of a symbol that is not available
* for this link-edit.
*
- * o To save all definitions of a symbol when the -m option is in
+ * - To save all definitions of a symbol when the -m option is in
* effect. This is optional as it is used to list multiple
* (interposed) definitions of a symbol (refer to ldmap_out()),
* and can be quite expensive.
@@ -609,7 +602,7 @@ ld_sym_enter(const char *name, Sym *osym, Word hash, Ifl_desc *ifl,
* information, therefore the diagnosing of the symbol is deferred until
* later (see Dbg_map_symbol()).
*/
- if ((ifl == 0) || ((ifl->ifl_flags & FLG_IF_MAPFILE) == 0))
+ if ((ifl == NULL) || ((ifl->ifl_flags & FLG_IF_MAPFILE) == 0))
DBG_CALL(Dbg_syms_entered(ofl, nsym, sdp));
return (sdp);
}
@@ -707,7 +700,7 @@ sym_add_spec(const char *name, const char *uname, Word sdaux_id,
/*
* If the symbol does not exist create it.
*/
- if ((sym = libld_calloc(sizeof (Sym), 1)) == 0)
+ if ((sym = libld_calloc(sizeof (Sym), 1)) == NULL)
return (S_ERROR);
sym->st_shndx = SHN_ABS;
sym->st_info = ELF_ST_INFO(STB_GLOBAL, STT_OBJECT);
@@ -813,17 +806,17 @@ sym_undef_title(Ofl_desc *ofl)
/*
* Undefined symbols can fall into one of four types:
*
- * o the symbol is really undefined (SHN_UNDEF).
+ * - the symbol is really undefined (SHN_UNDEF).
*
- * o versioning has been enabled, however this symbol has not been assigned
+ * - versioning has been enabled, however this symbol has not been assigned
* to one of the defined versions.
*
- * o the symbol has been defined by an implicitly supplied library, ie. one
+ * - the symbol has been defined by an implicitly supplied library, ie. one
* which was encounted because it was NEEDED by another library, rather
* than from a command line supplied library which would become the only
* dependency of the output file being produced.
*
- * o the symbol has been defined by a version of a shared object that is
+ * - the symbol has been defined by a version of a shared object that is
* not permitted for this link-edit.
*
* In all cases the file who made the first reference to this symbol will have
@@ -1068,15 +1061,15 @@ ensure_array_local(Ofl_desc *ofl, List *list, const char *str)
* counting has been carried out (ie. no more symbols will be read, generated,
* or modified), validate and count the relevant entries:
*
- * o check and print any undefined symbols remaining. Note that
+ * - check and print any undefined symbols remaining. Note that
* if a symbol has been defined by virtue of the inclusion of
* an implicit shared library, it is still classed as undefined.
*
- * o count the number of global needed symbols together with the
+ * - count the number of global needed symbols together with the
* size of their associated name strings (if scoping has been
* indicated these symbols may be reduced to locals).
*
- * o establish the size and alignment requirements for the global
+ * - establish the size and alignment requirements for the global
* .bss section (the alignment of this section is based on the
* first symbol that it will contain).
*/
@@ -1201,7 +1194,7 @@ ld_sym_validate(Ofl_desc *ofl)
Is_desc *isp = sdp->sd_isc;
Ifl_desc *ifl = sdp->sd_file;
- if ((isp == 0) || (isp->is_shdr == 0) ||
+ if ((isp == NULL) || (isp->is_shdr == NULL) ||
((isp->is_shdr->sh_flags & SHF_TLS) == 0)) {
eprintf(ofl->ofl_lml, ERR_FATAL,
MSG_INTL(MSG_SYM_TLS),
@@ -1558,10 +1551,10 @@ ld_sym_validate(Ofl_desc *ofl)
int ndx;
for (ndx = 0; ndx < ofl->ofl_regsymsno; ndx++) {
- if ((sdp = ofl->ofl_regsyms[ndx]) == 0)
+ if ((sdp = ofl->ofl_regsyms[ndx]) == NULL)
continue;
if (sdp->sd_ref != REF_REL_NEED) {
- ofl->ofl_regsyms[ndx] = 0;
+ ofl->ofl_regsyms[ndx] = NULL;
continue;
}
@@ -1666,29 +1659,41 @@ ld_sym_validate(Ofl_desc *ofl)
/*
* qsort(3c) comparison function. As an optimization for associating weak
* symbols to their strong counterparts sort global symbols according to their
- * address and binding.
+ * section index, address and binding.
*/
static int
-compare(const void * sdpp1, const void * sdpp2)
+compare(const void *sdpp1, const void *sdpp2)
{
- Sym_desc * sdp1 = *((Sym_desc **)sdpp1);
- Sym_desc * sdp2 = *((Sym_desc **)sdpp2);
- Sym * sym1, * sym2;
+ Sym_desc *sdp1 = *((Sym_desc **)sdpp1);
+ Sym_desc *sdp2 = *((Sym_desc **)sdpp2);
+ Sym *sym1, *sym2;
uchar_t bind1, bind2;
/*
* Symbol descriptors may be zero, move these to the front of the
* sorted array.
*/
- if (sdp1 == 0)
+ if (sdp1 == NULL)
return (-1);
- if (sdp2 == 0)
+ if (sdp2 == NULL)
return (1);
sym1 = sdp1->sd_sym;
sym2 = sdp2->sd_sym;
/*
+ * Compare the symbols section index. This is important when sorting
+ * the symbol tables of relocatable objects. In this case, a symbols
+ * value is the offset within the associated section, and thus many
+ * symbols can have the same value, but are effectively different
+ * addresses.
+ */
+ if (sym1->st_shndx > sym2->st_shndx)
+ return (1);
+ if (sym1->st_shndx < sym2->st_shndx)
+ return (-1);
+
+ /*
* Compare the symbols value (address).
*/
if (sym1->st_value > sym2->st_value)
@@ -1711,7 +1716,6 @@ compare(const void * sdpp1, const void * sdpp2)
return (0);
}
-
/*
* Issue a MSG_SYM_BADADDR error from ld_sym_process(). This error
* is issued when a symbol address/size is not contained by the
@@ -1759,10 +1763,10 @@ issue_badaddr_msg(Ifl_desc *ifl, Ofl_desc *ofl, Sym_desc *sdp,
* input sections from this input file have been assigned an input section
* descriptor which is saved in the `ifl_isdesc' array.
*
- * o local symbols are saved (as is) if the input file is a
+ * - local symbols are saved (as is) if the input file is a
* relocatable object
*
- * o global symbols are added to the linkers internal symbol
+ * - global symbols are added to the linkers internal symbol
* table if they are not already present, otherwise a symbol
* resolution function is called upon to resolve the conflict.
*/
@@ -1801,7 +1805,7 @@ ld_sym_process(Is_desc *isc, Ifl_desc *ifl, Ofl_desc *ofl)
Conv_inv_buf_t inv_buf;
Sym *sym = (Sym *)isc->is_indata->d_buf;
- Word *symshndx = 0;
+ Word *symshndx = NULL;
Shdr *shdr = isc->is_shdr;
Sym_desc *sdp;
size_t strsize;
@@ -1812,7 +1816,7 @@ ld_sym_process(Is_desc *isc, Ifl_desc *ifl, Ofl_desc *ofl)
int etype_rel;
const char *symsecname, *strsecname;
avl_index_t where;
- int test_gnu_hidden_bit;
+ int test_gnu_hidden_bit, weak;
/*
* Its possible that a file may contain more that one symbol table,
@@ -1880,12 +1884,12 @@ ld_sym_process(Is_desc *isc, Ifl_desc *ifl, Ofl_desc *ofl)
* image, they are used as part of symbol resolution.
*/
if ((ifl->ifl_oldndx = libld_malloc((size_t)(total *
- sizeof (Sym_desc *)))) == 0)
+ sizeof (Sym_desc *)))) == NULL)
return (S_ERROR);
etype_rel = (etype == ET_REL);
if (etype_rel && local) {
if ((ifl->ifl_locs =
- libld_calloc(sizeof (Sym_desc), local)) == 0)
+ libld_calloc(sizeof (Sym_desc), local)) == NULL)
return (S_ERROR);
/* LINTED */
ifl->ifl_locscnt = (Word)local;
@@ -1923,7 +1927,7 @@ ld_sym_process(Is_desc *isc, Ifl_desc *ifl, Ofl_desc *ofl)
* Check if st_name has a valid value or not.
*/
if ((name = string(ofl, ifl, sym, strs, strsize, ndx,
- shndx, symsecname, strsecname, &sdflags)) == 0) {
+ shndx, symsecname, strsecname, &sdflags)) == NULL) {
ofl->ofl_flags |= FLG_OF_FATAL;
continue;
}
@@ -1971,7 +1975,7 @@ ld_sym_process(Is_desc *isc, Ifl_desc *ifl, Ofl_desc *ofl)
if (etype == ET_DYN) {
if ((sdp = libld_calloc(
- sizeof (Sym_desc), 1)) == 0)
+ sizeof (Sym_desc), 1)) == NULL)
return (S_ERROR);
sdp->sd_ref = REF_DYN_SEEN;
@@ -1984,11 +1988,11 @@ ld_sym_process(Is_desc *isc, Ifl_desc *ifl, Ofl_desc *ofl)
/*
* Fill in the remaining symbol descriptor information.
*/
- if (sdp == 0) {
+ if (sdp == NULL) {
sdp = &(ifl->ifl_locs[ndx]);
sdp->sd_ref = REF_REL_NEED;
}
- if (rsdp == 0) {
+ if (rsdp == NULL) {
sdp->sd_name = name;
sdp->sd_sym = sym;
sdp->sd_shndx = shndx;
@@ -2027,7 +2031,7 @@ ld_sym_process(Is_desc *isc, Ifl_desc *ifl, Ofl_desc *ofl)
* The presence of FLG_SY_REGSYM means that
* the pointers in ld_targ.t_ms are non-NULL.
*/
- if ((rsdp == 0) &&
+ if ((rsdp == NULL) &&
((*ld_targ.t_ms.ms_reg_enter)(sdp, ofl) ==
0))
return (S_ERROR);
@@ -2119,7 +2123,7 @@ ld_sym_process(Is_desc *isc, Ifl_desc *ifl, Ofl_desc *ofl)
(sym->st_shndx != SHN_COMMON))) {
Is_desc *isp = sdp->sd_isc;
- if ((isp == 0) || (isp->is_shdr == 0) ||
+ if ((isp == NULL) || (isp->is_shdr == NULL) ||
((isp->is_shdr->sh_flags & SHF_TLS) == 0)) {
eprintf(ofl->ofl_lml, ERR_FATAL,
MSG_INTL(MSG_SYM_TLS),
@@ -2142,7 +2146,7 @@ ld_sym_process(Is_desc *isc, Ifl_desc *ifl, Ofl_desc *ofl)
((sym->st_shndx == SHN_COMMON)) ||
((type == STT_FILE) &&
(sym->st_shndx != SHN_ABS))) ||
- (sdp->sd_isc && (sdp->sd_isc->is_osdesc == 0))) {
+ (sdp->sd_isc && (sdp->sd_isc->is_osdesc == NULL))) {
eprintf(ofl->ofl_lml, ERR_WARNING,
MSG_INTL(MSG_SYM_INVSHNDX),
demangle_symname(name, isc->is_name, ndx),
@@ -2200,6 +2204,7 @@ ld_sym_process(Is_desc *isc, Ifl_desc *ifl, Ofl_desc *ofl)
*/
sym = (Sym *)isc->is_indata->d_buf;
sym += local;
+ weak = 0;
/* LINTED */
for (ndx = (int)local; ndx < total; sym++, ndx++) {
const char *name;
@@ -2222,7 +2227,7 @@ ld_sym_process(Is_desc *isc, Ifl_desc *ifl, Ofl_desc *ofl)
* Check if st_name has a valid value or not.
*/
if ((name = string(ofl, ifl, sym, strs, strsize, ndx, shndx,
- symsecname, strsecname, &sdflags)) == 0) {
+ symsecname, strsecname, &sdflags)) == NULL) {
ofl->ofl_flags |= FLG_OF_FATAL;
continue;
}
@@ -2282,6 +2287,8 @@ ld_sym_process(Is_desc *isc, Ifl_desc *ifl, Ofl_desc *ofl)
conv_sym_info_bind(bind, 0, &inv_buf));
continue;
}
+ if (bind == STB_WEAK)
+ weak++;
/*
* If this symbol falls within the range of a section being
@@ -2309,7 +2316,7 @@ ld_sym_process(Is_desc *isc, Ifl_desc *ifl, Ofl_desc *ofl)
isp = ifl->ifl_isdesc[shndx];
if (isp && (isp->is_flags & FLG_IS_DISCARD)) {
if ((sdp =
- libld_calloc(sizeof (Sym_desc), 1)) == 0)
+ libld_calloc(sizeof (Sym_desc), 1)) == NULL)
return (S_ERROR);
/*
@@ -2376,7 +2383,7 @@ ld_sym_process(Is_desc *isc, Ifl_desc *ifl, Ofl_desc *ofl)
* the pointers in ld_targ.t_ms are non-NULL.
*/
rsdp = (*ld_targ.t_ms.ms_reg_find)(sdp->sd_sym, ofl);
- if (rsdp == 0) {
+ if (rsdp == NULL) {
if ((*ld_targ.t_ms.ms_reg_enter)(sdp, ofl) == 0)
return (S_ERROR);
} else if (rsdp != sdp) {
@@ -2409,53 +2416,75 @@ ld_sym_process(Is_desc *isc, Ifl_desc *ifl, Ofl_desc *ofl)
}
/*
- * If this is a shared object scan the globals one more time and
- * associate any weak/global associations. This association is needed
- * should the weak definition satisfy a reference in the dynamic
- * executable:
+ * Associate weak (alias) symbols to their non-weak counterparts by
+ * scaning the global symbols one more time.
+ *
+ * This association is needed when processing the symbols from a shared
+ * object dependency when a a weak definition satisfies a reference:
*
- * o if the symbol is a data item it will be copied to the
- * executables address space, thus we must also reassociate the
- * alias symbol with its new location in the executable.
+ * - When building a dynamic executable, if a referenced symbol is a
+ * data item, the symbol data is copied to the executables address
+ * space. In this copy-relocation case, we must also reassociate
+ * the alias symbol with its new location in the executable.
*
- * o if the symbol is a function then we may need to promote the
- * symbols binding from undefined weak to undefined, otherwise the
- * run-time linker will not generate the correct relocation error
- * should the symbol not be found.
+ * - If the referenced symbol is a function then we may need to
+ * promote the symbols binding from undefined weak to undefined,
+ * otherwise the run-time linker will not generate the correct
+ * relocation error should the symbol not be found.
+ *
+ * Weak alias association is also required when a local dynsym table
+ * is being created. This table should only contain one instance of a
+ * symbol that is associated to a given address.
*
* The true association between a weak/strong symbol pair is that both
- * symbol entries are identical, thus first we created a sorted symbol
- * list keyed off of the symbols value (if the value is the same chances
- * are the rest of the symbols data is). This list is then scanned for
- * weak symbols, and if one is found then any strong association will
- * exist in the following entries. Thus we just have to scan one
- * (typical single alias) or more (in the uncommon instance of multiple
- * weak to strong associations) entries to determine if a match exists.
+ * symbol entries are identical, thus first we create a sorted symbol
+ * list keyed off of the symbols section index and value. If the symbol
+ * belongs to the same section and has the same value, then the chances
+ * are that the rest of the symbols data is the same. This list is then
+ * scanned for weak symbols, and if one is found then any strong
+ * association will exist in the entries that follow. Thus we just have
+ * to scan one (typically a single alias) or more (in the uncommon
+ * instance of multiple weak to strong associations) entries to
+ * determine if a match exists.
*/
- if ((OFL_ALLOW_LDYNSYM(ofl) || (etype == ET_DYN)) &&
+ if (weak && (OFL_ALLOW_LDYNSYM(ofl) || (etype == ET_DYN)) &&
(total > local)) {
- Sym_desc ** sort;
- size_t size = (total - local) * sizeof (Sym_desc *);
+ static Sym_desc **sort;
+ static size_t osize = 0;
+ size_t nsize = (total - local) * sizeof (Sym_desc *);
- if ((sort = libld_malloc(size)) == 0)
- return (S_ERROR);
- (void) memcpy((void *)sort, &ifl->ifl_oldndx[local], size);
+ /*
+ * As we might be processing many input files, and many symbols,
+ * try and reuse a static sort buffer. Note, presently we're
+ * playing the game of never freeing any buffers as there's a
+ * belief this wastes time.
+ */
+ if ((osize == 0) || (nsize > osize)) {
+ if ((sort = libld_malloc(nsize)) == NULL)
+ return (S_ERROR);
+ osize = nsize;
+ }
+ (void) memcpy((void *)sort, &ifl->ifl_oldndx[local], nsize);
qsort(sort, (total - local), sizeof (Sym_desc *), compare);
for (ndx = 0; ndx < (total - local); ndx++) {
- Sym_desc * wsdp = sort[ndx];
- Sym * wsym;
+ Sym_desc *wsdp = sort[ndx];
+ Sym *wsym;
int sndx;
- if (wsdp == 0)
+ /*
+ * Ignore any empty symbol descriptor, or the case where
+ * the symbol has been resolved to a different file.
+ */
+ if ((wsdp == NULL) || (wsdp->sd_file != ifl))
continue;
wsym = wsdp->sd_sym;
- if ((ELF_ST_BIND(wsym->st_info) != STB_WEAK) ||
- (wsdp->sd_sym->st_shndx == SHN_UNDEF) ||
- (wsdp->sd_flags & FLG_SY_SPECSEC))
+ if ((wsym->st_shndx == SHN_UNDEF) ||
+ (wsdp->sd_flags & FLG_SY_SPECSEC) ||
+ (ELF_ST_BIND(wsym->st_info) != STB_WEAK))
continue;
/*
@@ -2467,66 +2496,70 @@ ld_sym_process(Is_desc *isc, Ifl_desc *ifl, Ofl_desc *ofl)
* the last weak).
*/
for (sndx = ndx + 1; sndx < (total - local); sndx++) {
- Sym_desc * ssdp = sort[sndx];
- Sym * ssym;
+ Sym_desc *ssdp = sort[sndx];
+ Sym *ssym;
+ int w_dynbits, s_dynbits;
- if (ssdp == 0)
- break;
+ /*
+ * Ignore any empty symbol descriptor, or the
+ * case where the symbol has been resolved to a
+ * different file.
+ */
+ if ((ssdp == NULL) || (ssdp->sd_file != ifl))
+ continue;
ssym = ssdp->sd_sym;
- if (wsym->st_value != ssym->st_value)
+ if (ssym->st_shndx == SHN_UNDEF)
+ continue;
+
+ if ((ssym->st_shndx != wsym->st_shndx) ||
+ (ssym->st_value != wsym->st_value))
break;
- if ((ssdp->sd_file == ifl) &&
- (wsdp->sd_file == ifl) &&
- (wsym->st_size == ssym->st_size) &&
- (ssdp->sd_sym->st_shndx != SHN_UNDEF) &&
- (ELF_ST_BIND(ssym->st_info) != STB_WEAK) &&
- ((ssdp->sd_flags & FLG_SY_SPECSEC) == 0)) {
- int w_dynbits, s_dynbits;
+ if ((ssym->st_size != wsym->st_size) ||
+ (ssdp->sd_flags & FLG_SY_SPECSEC) ||
+ (ELF_ST_BIND(ssym->st_info) == STB_WEAK))
+ continue;
- /*
- * If a sharable object, set link
- * fields so they reference each other
- */
- if (etype == ET_DYN) {
- ssdp->sd_aux->sa_linkndx =
- (Word)wsdp->sd_symndx;
- wsdp->sd_aux->sa_linkndx =
- (Word)ssdp->sd_symndx;
- }
- /*
- * Determine which of these two symbols
- * go into the sort section. If the
- * mapfile has made explicit settings
- * of the FLG_SY_*DYNSORT flags for both
- * symbols, then we do what they say.
- * If one has the DYNSORT flags set,
- * we set the NODYNSORT bit in the
- * other. And if neither has an
- * explicit setting, then we favor the
- * weak symbol because they usually
- * lack the leading underscore.
- */
- w_dynbits = wsdp->sd_flags &
- (FLG_SY_DYNSORT | FLG_SY_NODYNSORT);
- s_dynbits = ssdp->sd_flags &
- (FLG_SY_DYNSORT | FLG_SY_NODYNSORT);
- if (!(w_dynbits && s_dynbits)) {
- if (s_dynbits) {
- if (s_dynbits ==
- FLG_SY_DYNSORT)
+ /*
+ * If a sharable object, set link fields so
+ * that they reference each other.`
+ */
+ if (etype == ET_DYN) {
+ ssdp->sd_aux->sa_linkndx =
+ (Word)wsdp->sd_symndx;
+ wsdp->sd_aux->sa_linkndx =
+ (Word)ssdp->sd_symndx;
+ }
+
+ /*
+ * Determine which of these two symbols go into
+ * the sort section. If a mapfile has made
+ * explicit settings of the FLG_SY_*DYNSORT
+ * flags for both symbols, then we do what they
+ * say. If one has the DYNSORT flags set, we
+ * set the NODYNSORT bit in the other. And if
+ * neither has an explicit setting, then we
+ * favor the weak symbol because they usually
+ * lack the leading underscore.
+ */
+ w_dynbits = wsdp->sd_flags &
+ (FLG_SY_DYNSORT | FLG_SY_NODYNSORT);
+ s_dynbits = ssdp->sd_flags &
+ (FLG_SY_DYNSORT | FLG_SY_NODYNSORT);
+ if (!(w_dynbits && s_dynbits)) {
+ if (s_dynbits) {
+ if (s_dynbits == FLG_SY_DYNSORT)
wsdp->sd_flags |=
FLG_SY_NODYNSORT;
- } else if (w_dynbits !=
- FLG_SY_NODYNSORT) {
- ssdp->sd_flags |=
- FLG_SY_NODYNSORT;
- }
+ } else if (w_dynbits !=
+ FLG_SY_NODYNSORT) {
+ ssdp->sd_flags |=
+ FLG_SY_NODYNSORT;
}
- break;
}
+ break;
}
}
}
@@ -2546,7 +2579,7 @@ Sym_desc *
ld_sym_add_u(const char *name, Ofl_desc *ofl, Msg mid)
{
Sym *sym;
- Ifl_desc *ifl = 0, *_ifl;
+ Ifl_desc *ifl = NULL, *_ifl;
Sym_desc *sdp;
Word hash;
Listnode *lnp;
@@ -2582,14 +2615,14 @@ ld_sym_add_u(const char *name, Ofl_desc *ofl, Msg mid)
/*
* If no descriptor exists create one.
*/
- if (ifl == 0) {
+ if (ifl == NULL) {
if ((ifl = libld_calloc(sizeof (Ifl_desc), 1)) ==
(Ifl_desc *)0)
return ((Sym_desc *)S_ERROR);
ifl->ifl_name = reference;
ifl->ifl_flags = FLG_IF_NEEDED | FLG_IF_FILEREF;
if ((ifl->ifl_ehdr = libld_calloc(sizeof (Ehdr),
- 1)) == 0)
+ 1)) == NULL)
return ((Sym_desc *)S_ERROR);
ifl->ifl_ehdr->e_type = ET_REL;
@@ -2600,7 +2633,7 @@ ld_sym_add_u(const char *name, Ofl_desc *ofl, Msg mid)
/*
* Allocate a symbol structure and add it to the global symbol table.
*/
- if ((sym = libld_calloc(sizeof (Sym), 1)) == 0)
+ if ((sym = libld_calloc(sizeof (Sym), 1)) == NULL)
return ((Sym_desc *)S_ERROR);
sym->st_info = ELF_ST_INFO(STB_GLOBAL, STT_NOTYPE);
sym->st_shndx = SHN_UNDEF;
diff --git a/usr/src/cmd/sgs/libld/common/util.c b/usr/src/cmd/sgs/libld/common/util.c
index c5e144db80..5d5c4bfc84 100644
--- a/usr/src/cmd/sgs/libld/common/util.c
+++ b/usr/src/cmd/sgs/libld/common/util.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -722,9 +722,37 @@ ld_getopt(Lm_list *lml, int ndx, int argc, char **argv)
}
/*
- * Messaging support - funnel everything through dgettext().
+ * A compare routine for Isd_node AVLT trees.
*/
+int
+isdavl_compare(const void *n1, const void *n2)
+{
+ uint_t hash1, hash2;
+ const char *st1, *st2;
+ int rc;
+
+ hash1 = ((Isd_node *)n1)->isd_hash;
+ hash2 = ((Isd_node *)n2)->isd_hash;
+
+ if (hash1 > hash2)
+ return (1);
+ if (hash1 < hash2)
+ return (-1);
+
+ st1 = ((Isd_node *)n1)->isd_isp->is_name;
+ st2 = ((Isd_node *)n2)->isd_isp->is_name;
+
+ rc = strcmp(st1, st2);
+ if (rc > 0)
+ return (1);
+ if (rc < 0)
+ return (-1);
+ return (0);
+}
+/*
+ * Messaging support - funnel everything through dgettext().
+ */
const char *
_libld_msg(Msg mid)
{
diff --git a/usr/src/cmd/sgs/packages/common/SUNWonld-README b/usr/src/cmd/sgs/packages/common/SUNWonld-README
index b737cc01a1..a7538897fb 100644
--- a/usr/src/cmd/sgs/packages/common/SUNWonld-README
+++ b/usr/src/cmd/sgs/packages/common/SUNWonld-README
@@ -1432,3 +1432,4 @@ Bugid Risk Synopsis
6792906 ld -z nopartial fix breaks TLS
6686372 ld.so.1 should use mmapobj(2)
6726108 dlopen() performance could be improved.
+6792836 ld is slow when processing GNU linkonce sections
diff --git a/usr/src/cmd/sgs/tools/common/string_table.c b/usr/src/cmd/sgs/tools/common/string_table.c
index e174acaf04..c15473150e 100644
--- a/usr/src/cmd/sgs/tools/common/string_table.c
+++ b/usr/src/cmd/sgs/tools/common/string_table.c
@@ -20,12 +20,10 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <_string_table.h>
#include <strings.h>
#include <sgs.h>
@@ -160,7 +158,7 @@ st_new(uint_t flags)
{
Str_tbl *stp;
- if ((stp = calloc(sizeof (Str_tbl), 1)) == NULL)
+ if ((stp = calloc(sizeof (*stp), 1)) == NULL)
return (NULL);
/*
@@ -175,7 +173,7 @@ st_new(uint_t flags)
if ((stp->st_flags & FLG_STTAB_COMPRESS) == 0)
return (stp);
- if ((stp->st_lentree = calloc(sizeof (avl_tree_t), 1)) == NULL)
+ if ((stp->st_lentree = calloc(sizeof (*stp->st_lentree), 1)) == NULL)
return (NULL);
avl_create(stp->st_lentree, &avl_len_compare, sizeof (LenNode),
@@ -187,9 +185,9 @@ st_new(uint_t flags)
/*
* Insert a new string into the Str_tbl. There are two AVL trees used.
*
- * . The first LenNode AVL tree maintains a tree of nodes based on string
+ * - The first LenNode AVL tree maintains a tree of nodes based on string
* sizes.
- * . Each LenNode maintains a StrNode AVL tree for each string. Large
+ * - Each LenNode maintains a StrNode AVL tree for each string. Large
* applications have been known to contribute thousands of strings of
* the same size. Should strings need to be removed (-z ignore), then
* the string AVL tree makes this removal efficient and scalable.
@@ -227,12 +225,13 @@ st_insert(Str_tbl *stp, const char *str)
*/
ln.ln_strlen = len;
if ((lnp = avl_find(stp->st_lentree, &ln, &where)) == NULL) {
- if ((lnp = calloc(sizeof (LenNode), 1)) == NULL)
+ if ((lnp = calloc(sizeof (*lnp), 1)) == NULL)
return (-1);
lnp->ln_strlen = len;
avl_insert(stp->st_lentree, lnp, where);
- if ((lnp->ln_strtree = calloc(sizeof (avl_tree_t), 1)) == NULL)
+ if ((lnp->ln_strtree = calloc(sizeof (*lnp->ln_strtree), 1)) ==
+ NULL)
return (0);
avl_create(lnp->ln_strtree, &avl_str_compare, sizeof (StrNode),
@@ -246,7 +245,7 @@ st_insert(Str_tbl *stp, const char *str)
*/
sn.sn_str = str;
if ((snp = avl_find(lnp->ln_strtree, &sn, &where)) == NULL) {
- if ((snp = calloc(sizeof (StrNode), 1)) == NULL)
+ if ((snp = calloc(sizeof (*snp), 1)) == NULL)
return (-1);
snp->sn_str = str;
avl_insert(lnp->ln_strtree, snp, where);
@@ -513,7 +512,7 @@ st_hash_insert(Str_tbl *stp, const char *str, size_t len)
/*
* allocate a new master string
*/
- if ((mstr = calloc(sizeof (Str_hash), 1)) == 0)
+ if ((mstr = calloc(sizeof (*mstr), 1)) == 0)
return (-1);
mstr->sm_next = stp->st_mstrlist;
stp->st_mstrlist = mstr;
@@ -528,7 +527,7 @@ st_hash_insert(Str_tbl *stp, const char *str, size_t len)
stp->st_strsize += len - mstr->sm_strlen;
}
- if ((sthash = calloc(sizeof (Str_hash), 1)) == 0)
+ if ((sthash = calloc(sizeof (*sthash), 1)) == 0)
return (-1);
mstr->sm_hashval = sthash->hi_hashval = hashval;
@@ -569,8 +568,8 @@ st_getstrtab_sz(Str_tbl *stp)
* strings input.
*/
stp->st_hbckcnt = findprime(stp->st_strcnt);
- if ((stp->st_hashbcks =
- calloc(sizeof (Str_hash), stp->st_hbckcnt)) == NULL)
+ if ((stp->st_hashbcks = calloc(sizeof (*stp->st_hashbcks),
+ stp->st_hbckcnt)) == NULL)
return (0);
/*
@@ -673,8 +672,8 @@ st_setstrbuf(Str_tbl *stp, char *stbuf, size_t bufsize)
#ifdef DEBUG
/*
* for debug builds - start with a stringtable filled in
- * with '0xff'. This makes it very easy to find wholes
- * which we failed to fill in - in the strtab.
+ * with '0xff'. This makes it very easy to spot unfilled
+ * holes in the strtab.
*/
memset(stbuf, 0xff, bufsize);
stbuf[0] = '\0';