diff options
author | Ali Bahrami <Ali.Bahrami@Sun.COM> | 2009-01-22 09:54:25 -0700 |
---|---|---|
committer | Ali Bahrami <Ali.Bahrami@Sun.COM> | 2009-01-22 09:54:25 -0700 |
commit | 6b3ba5bde920961dbf915c89b7736f96ff487d20 (patch) | |
tree | c0a022a29ab20652140ff131405c715a82d65714 /usr/src | |
parent | 63528ae45fc8c92cddd3c3b0dc846a9be84f44ac (diff) | |
download | illumos-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.h | 20 | ||||
-rw-r--r-- | usr/src/cmd/sgs/libld/common/_libld.h | 18 | ||||
-rw-r--r-- | usr/src/cmd/sgs/libld/common/debug.c | 15 | ||||
-rw-r--r-- | usr/src/cmd/sgs/libld/common/files.c | 3 | ||||
-rw-r--r-- | usr/src/cmd/sgs/libld/common/groups.c | 70 | ||||
-rw-r--r-- | usr/src/cmd/sgs/libld/common/libs.c | 4 | ||||
-rw-r--r-- | usr/src/cmd/sgs/libld/common/place.c | 54 | ||||
-rw-r--r-- | usr/src/cmd/sgs/libld/common/relocate.c | 172 | ||||
-rw-r--r-- | usr/src/cmd/sgs/libld/common/sections.c | 19 | ||||
-rw-r--r-- | usr/src/cmd/sgs/libld/common/syms.c | 327 | ||||
-rw-r--r-- | usr/src/cmd/sgs/libld/common/util.c | 32 | ||||
-rw-r--r-- | usr/src/cmd/sgs/packages/common/SUNWonld-README | 1 | ||||
-rw-r--r-- | usr/src/cmd/sgs/tools/common/string_table.c | 31 |
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'; |