diff options
| author | Ali Bahrami <Ali.Bahrami@Sun.COM> | 2008-11-18 09:57:21 -0700 |
|---|---|---|
| committer | Ali Bahrami <Ali.Bahrami@Sun.COM> | 2008-11-18 09:57:21 -0700 |
| commit | ca4eed8b351c42874d1c1d9360d832914a0ffd1b (patch) | |
| tree | d9cc734ae65e6e3661287f5bb90fdc10a06e2426 /usr/src/cmd | |
| parent | f7b93e0c289f7c2bc496d313146b7af1bd0bf84e (diff) | |
| download | illumos-joyent-ca4eed8b351c42874d1c1d9360d832914a0ffd1b.tar.gz | |
6763342 sloppy relocations need to get sloppier
Diffstat (limited to 'usr/src/cmd')
| -rw-r--r-- | usr/src/cmd/sgs/libconv/common/dl.c | 5 | ||||
| -rw-r--r-- | usr/src/cmd/sgs/libld/common/_libld.h | 4 | ||||
| -rw-r--r-- | usr/src/cmd/sgs/libld/common/libld.msg | 1 | ||||
| -rw-r--r-- | usr/src/cmd/sgs/libld/common/outfile.c | 68 | ||||
| -rw-r--r-- | usr/src/cmd/sgs/libld/common/place.c | 9 | ||||
| -rw-r--r-- | usr/src/cmd/sgs/libld/common/relocate.c | 58 | ||||
| -rw-r--r-- | usr/src/cmd/sgs/libld/common/sections.c | 12 | ||||
| -rw-r--r-- | usr/src/cmd/sgs/libld/common/syms.c | 7 | ||||
| -rw-r--r-- | usr/src/cmd/sgs/libld/common/update.c | 38 | ||||
| -rw-r--r-- | usr/src/cmd/sgs/liblddbg/common/files.c | 2 | ||||
| -rw-r--r-- | usr/src/cmd/sgs/packages/common/SUNWonld-README | 1 | ||||
| -rw-r--r-- | usr/src/cmd/sgs/rtld/common/dlfcns.c | 21 | ||||
| -rw-r--r-- | usr/src/cmd/sgs/rtld/common/elf.c | 3 |
13 files changed, 196 insertions, 33 deletions
diff --git a/usr/src/cmd/sgs/libconv/common/dl.c b/usr/src/cmd/sgs/libconv/common/dl.c index b85be1da27..7067ea4772 100644 --- a/usr/src/cmd/sgs/libconv/common/dl.c +++ b/usr/src/cmd/sgs/libconv/common/dl.c @@ -20,10 +20,9 @@ */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" #include <string.h> #include "_conv.h" @@ -85,7 +84,7 @@ conv_dl_mode(int mode, int fabricate, Conv_dl_mode_buf_t *dl_mode_buf) if (mode & RTLD_NOW) { *lstr++ = MSG_ORIG(MSG_RTLD_NOW); - } else if (fabricate) { + } else if ((mode & RTLD_LAZY) || fabricate) { *lstr++ = MSG_ORIG(MSG_RTLD_LAZY); } if (mode & RTLD_GLOBAL) { diff --git a/usr/src/cmd/sgs/libld/common/_libld.h b/usr/src/cmd/sgs/libld/common/_libld.h index e0bb4ea2e6..4190eb16e8 100644 --- a/usr/src/cmd/sgs/libld/common/_libld.h +++ b/usr/src/cmd/sgs/libld/common/_libld.h @@ -550,6 +550,7 @@ extern Sdf_desc *sdf_find(const char *, List *); #define ld_process_ifl ld64_process_ifl #define ld_process_ordered ld64_process_ordered #define ld_process_sym_reloc ld64_process_sym_reloc +#define ld_recalc_shdrcnt ld64_recalc_shdrcnt #define ld_reloc_GOT_relative ld64_reloc_GOT_relative #define ld_reloc_plt ld64_reloc_plt #define ld_reloc_remain_entry ld64_reloc_remain_entry @@ -634,6 +635,7 @@ extern Sdf_desc *sdf_find(const char *, List *); #define ld_process_ifl ld32_process_ifl #define ld_process_ordered ld32_process_ordered #define ld_process_sym_reloc ld32_process_sym_reloc +#define ld_recalc_shdrcnt ld32_recalc_shdrcnt #define ld_reloc_GOT_relative ld32_reloc_GOT_relative #define ld_reloc_plt ld32_reloc_plt #define ld_reloc_remain_entry ld32_reloc_remain_entry @@ -738,6 +740,8 @@ extern uintptr_t ld_process_ordered(Ifl_desc *, Ofl_desc *, Word, Word); extern uintptr_t ld_process_sym_reloc(Ofl_desc *, Rel_desc *, Rel *, Is_desc *, const char *); +extern void ld_recalc_shdrcnt(Ofl_desc *); + extern uintptr_t ld_reloc_GOT_relative(Boolean, Rel_desc *, Ofl_desc *); extern uintptr_t ld_reloc_plt(Rel_desc *, Ofl_desc *); extern void ld_reloc_remain_entry(Rel_desc *, Os_desc *, diff --git a/usr/src/cmd/sgs/libld/common/libld.msg b/usr/src/cmd/sgs/libld/common/libld.msg index add70ffa66..6c9a770eda 100644 --- a/usr/src/cmd/sgs/libld/common/libld.msg +++ b/usr/src/cmd/sgs/libld/common/libld.msg @@ -728,6 +728,7 @@ @ MSG_SCN_DTORS ".dtors" @ MSG_SCN_EHFRAME ".eh_frame" @ MSG_SCN_EHFRAME_HDR ".eh_frame_hdr" +@ MSG_SCN_GCC_X_TBL ".gcc_except_table" @ MSG_SCN_JCR ".jcr" # Entry criteria strings (segment names) diff --git a/usr/src/cmd/sgs/libld/common/outfile.c b/usr/src/cmd/sgs/libld/common/outfile.c index 8743b8371b..08c7efc721 100644 --- a/usr/src/cmd/sgs/libld/common/outfile.c +++ b/usr/src/cmd/sgs/libld/common/outfile.c @@ -344,6 +344,74 @@ create_outsec(Ofl_desc *ofl, Sg_desc *sgp, Os_desc *osp, Word ptype, int shidx, } /* + * Recalculate the number of output sections and update ofl->ofl_shdrcnt. + * + * As new sections are placed, ofl->ofl_shdrcnt is incremented to + * track the count. If -z ignore is not in effect, then this is + * sufficient. If -z ignore is in effect however, the sections that + * are removed are not reflected in the value of ofl->ofl_shdrcnt. + * Determining whether ofl->ofl_shdrcnt should get decremented in + * that situation takes some work to determine, and if multiple + * sections are discarded (which is typical), then it would be + * necessary to do that work each time. Instead, we use this + * routine to recompute the number of output sections once at the end. + */ +void +ld_recalc_shdrcnt(Ofl_desc *ofl) +{ + Sg_desc *sgp; + Listnode *lnp1, *lnp2; + Word cnt = 0; + Is_desc *isp; + Os_desc *osp; + Aliste idx; + + + /* + * This code must be kept in sync with the similar code + * found in ld_create_outfile(). + * + * We look at the input sections for every output section, + * looking for at least one input section that won't + * be eliminated. + */ + for (LIST_TRAVERSE(&ofl->ofl_segs, lnp1, sgp)) { + Word ptype = sgp->sg_phdr.p_type; + + for (APLIST_TRAVERSE(sgp->sg_osdescs, idx, osp)) { + + for (LIST_TRAVERSE(&(osp->os_isdescs), lnp2, isp)) { + Ifl_desc *ifl = isp->is_file; + + /* Input section is tagged for discard? */ + if (isp->is_flags & FLG_IS_DISCARD) + continue; + + /* + * If the file is discarded, it will take + * the section with it. + */ + if (ifl && + (((ifl->ifl_flags & FLG_IF_FILEREF) == 0) || + ((ptype == PT_LOAD) && + ((isp->is_flags & FLG_IS_SECTREF) == 0) && + (isp->is_shdr->sh_size > 0))) && + (ifl->ifl_flags & FLG_IF_IGNORE)) + continue; + + /* + * We have found a kept input section. + * so the output section will be created. + */ + cnt++; + break; + } + } + } + ofl->ofl_shdrcnt = cnt; +} + +/* * Create the elf structures that allow the input data to be associated with the * new image: * diff --git a/usr/src/cmd/sgs/libld/common/place.c b/usr/src/cmd/sgs/libld/common/place.c index 279c2d8a30..178820df09 100644 --- a/usr/src/cmd/sgs/libld/common/place.c +++ b/usr/src/cmd/sgs/libld/common/place.c @@ -514,12 +514,13 @@ ld_place_section(Ofl_desc *ofl, Is_desc *isp, int ident, Word link) * The .gnu.linkonce is a section naming convention that indicates a * COMDAT requirement. Determine whether this section follows the GNU * pattern, and if so, determine whether this section should be - * discarded or retained. The comparison of 'g' and 'l' are an - * optimization to skip using strncmp() too much. + * discarded or retained. The comparison of is_name[1] with 'g' + * is an optimization to skip using strncmp() too much. This is safe, + * because we know the name is not NULL, and therefore must have + * at least one character plus a NULL termination. */ if (((ofl->ofl_flags & FLG_OF_RELOBJ) == 0) && - (isp->is_name == oname) && - (isp->is_name[1] == 'g') && (isp->is_name[5] == 'l') && + (isp->is_name == oname) && (isp->is_name[1] == 'g') && (strncmp(MSG_ORIG(MSG_SCN_GNU_LINKONCE), isp->is_name, MSG_SCN_GNU_LINKONCE_SIZE) == 0)) { if ((oname = diff --git a/usr/src/cmd/sgs/libld/common/relocate.c b/usr/src/cmd/sgs/libld/common/relocate.c index da4bb7b829..f9b4886959 100644 --- a/usr/src/cmd/sgs/libld/common/relocate.c +++ b/usr/src/cmd/sgs/libld/common/relocate.c @@ -1423,10 +1423,16 @@ sloppy_comdat_reloc(Ofl_desc *ofl, Rel_desc *reld, Sym_desc *sdp) * The replacement section must: * - Have the same name as the original * - Not have been discarded - * - Have the same size + * - Have the same size (*) * - Have the same section type * - Have the same SHF_GROUP flag setting (either on or off) * - Must be a COMDAT section of one form or the other. + * + * (*) One might imagine that the replacement section could be + * larger than the original, rather than the exact size. However, + * we have verified that this is the same policy used by the GNU + * 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)) { @@ -1688,20 +1694,54 @@ process_reld(Ofl_desc *ofl, Is_desc *isp, Rel_desc *reld, Word rsndx, * determine if this is a reference to a discarded * COMDAT section that can be replaced with a COMDAT * that has been kept. - * - * If a matching symbol can not be found, issue a - * warning and ignore the relocation. Note, the GNU - * linker will act as though the symbol were defined at - * the same offset in the copy of the linkonce section - * that was kept. This seems rather dangerous, and as - * the situation only seems to apply to debugging - * information, our choise is to ignore the relocation. */ if ((ofl->ofl_flags1 & FLG_OF1_RLXREL) && sdp->sd_isc->is_osdesc && (sdp->sd_isc->is_flags & FLG_IS_COMDAT) && ((nsdp = sloppy_comdat_reloc(ofl, reld, sdp)) == NULL)) { + Shdr *is_shdr = reld->rel_isdesc->is_shdr; + + /* + * A matching symbol was not found. We will + * ignore this relocation. First, we must + * decide whether or not to issue a warning. + * Warnings are always issued under -z verbose, + * but otherwise, we will follow the lead of + * the GNU ld and suppress them for certain + * cases: + * - It is a non-allocable debug section. + * The GNU ld tests for these by name, + * but we are willing to extend it to + * any non-allocable section. + * - Target section is .eh_frame. + * Note that on amd64 architectures, + * these sections are SHT_AMD64_UNWIND. + * However, we test it by name: On other + * architectures it is PROGBITS, and on + * amd64, .eh_frame_hdr is also + * SHT_AMD64_UNWIND. + * - The target section is + * .gcc_except_table, which is PROGBITS, + * and must be tested by name + */ + if ((ofl->ofl_flags & FLG_OF_VERBOSE) == 0) { + const char *is_name; + + if (!(is_shdr->sh_flags & SHF_ALLOC)) + return (1); + + is_name = reld->rel_isdesc->is_name; + if ((is_name[1] == 'e') && + (strcmp(is_name, + MSG_ORIG(MSG_SCN_EHFRAME)) == 0)) + return (1); + if ((is_name[1] == 'g') && + (strcmp(is_name, + MSG_ORIG(MSG_SCN_GCC_X_TBL)) == 0)) + return (1); + } + eprintf(ofl->ofl_lml, ERR_WARNING, MSG_INTL(MSG_REL_SLOPCDATNOSYM), conv_reloc_type(ifl->ifl_ehdr->e_machine, diff --git a/usr/src/cmd/sgs/libld/common/sections.c b/usr/src/cmd/sgs/libld/common/sections.c index 46d1c81d18..f4261f2f91 100644 --- a/usr/src/cmd/sgs/libld/common/sections.c +++ b/usr/src/cmd/sgs/libld/common/sections.c @@ -1419,6 +1419,18 @@ make_symtab(Ofl_desc *ofl) Word symcnt; /* + * We increment the number of sections in the output object + * (ofl->ofl_shdrcnt) as we add them. However, if -z ignore + * processing is in effect, the number of sections later removed + * is not reflected in that count. Updating the count as we + * remove these sections is a relatively expensive operation. + * Hence, if -z ignore is in use, we recompute the number of + * sections in a single final pass. + */ + if (ofl->ofl_flags1 & FLG_OF1_IGNPRC) + ld_recalc_shdrcnt(ofl); + + /* * Create the section headers. Note that we supply an ent_cnt * of 0. We won't know the count until the section has been placed. */ diff --git a/usr/src/cmd/sgs/libld/common/syms.c b/usr/src/cmd/sgs/libld/common/syms.c index 0206fd27a9..5ace9ddfa3 100644 --- a/usr/src/cmd/sgs/libld/common/syms.c +++ b/usr/src/cmd/sgs/libld/common/syms.c @@ -27,7 +27,6 @@ * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" /* * Symbol table management routines @@ -1987,6 +1986,9 @@ ld_sym_process(Is_desc *isc, Ifl_desc *ifl, Ofl_desc *ofl) sizeof (Sym_desc), 1)) == 0) return (S_ERROR); sdp->sd_ref = REF_DYN_SEEN; + + /* Will not appear in output object */ + ofl->ofl_locscnt--; } } else if (etype == ET_DYN) continue; @@ -2089,7 +2091,8 @@ ld_sym_process(Is_desc *isc, Ifl_desc *ifl, Ofl_desc *ofl) if (SYM_LOC_BADADDR(sdp, sym, type)) { issue_badaddr_msg(ifl, ofl, sdp, sym, shndx); - continue; + if (ofl->ofl_flags & FLG_OF_FATAL) + continue; } /* diff --git a/usr/src/cmd/sgs/libld/common/update.c b/usr/src/cmd/sgs/libld/common/update.c index b3b1da69b9..af06f02d3c 100644 --- a/usr/src/cmd/sgs/libld/common/update.c +++ b/usr/src/cmd/sgs/libld/common/update.c @@ -193,9 +193,11 @@ update_osym(Ofl_desc *ofl) Sym _sym = {0}, *sym, *symtab = 0; Sym *dynsym = 0, *ldynsym = 0; Word symtab_ndx = 0; /* index into .symtab */ + Word symtab_gbl_bndx; /* .symtab ndx 1st global */ Word ldynsym_ndx = 0; /* index into .SUNW_ldynsym */ Word dynsym_ndx = 0; /* index into .dynsym */ Word scopesym_ndx = 0; /* index into scoped symbols */ + Word scopesym_bndx = 0; /* .symtab ndx 1st scoped sym */ Word ldynscopesym_ndx = 0; /* index to ldynsym scoped syms */ Word *dynsymsort = NULL; /* SUNW_dynsymsort index vector */ Word *dyntlssort = NULL; /* SUNW_dyntlssort index vector */ @@ -603,7 +605,8 @@ update_osym(Ofl_desc *ofl) * to traverse the globals symbol hash array more than once. */ if (symtab) { - scopesym_ndx = symtab_ndx; + scopesym_bndx = symtab_ndx; + scopesym_ndx = scopesym_bndx; symtab_ndx += ofl->ofl_scopecnt; } @@ -686,6 +689,21 @@ update_osym(Ofl_desc *ofl) continue; /* + * If this symbol is from a different file + * than the input descriptor we are processing, + * treat it as if it has FLG_SY_ISDISC set. + * This happens when sloppy_comdat_reloc() + * replaces a symbol to a discarded comdat section + * with an equivalent symbol from a different + * file. We only want to enter such a symbol + * once --- as part of the file that actually + * supplies it. + */ + if (ifl != sdp->sd_file) + continue; + + + /* * Generate an output symbol to represent this input * symbol. Even if the symbol table is to be stripped * we still need to update any local symbols that are @@ -844,6 +862,7 @@ update_osym(Ofl_desc *ofl) } } } + symtab_gbl_bndx = symtab_ndx; /* .symtab index of 1st global entry */ /* * Two special symbols are `_init' and `_fini'. If these are supplied @@ -1850,8 +1869,7 @@ update_osym(Ofl_desc *ofl) if (symtab) { Shdr *shdr = ofl->ofl_ossymtab->os_shdr; - shdr->sh_info = ofl->ofl_shdrcnt + ofl->ofl_locscnt + - ofl->ofl_scopecnt + 2; + shdr->sh_info = symtab_gbl_bndx; /* LINTED */ shdr->sh_link = (Word)elf_ndxscn(ofl->ofl_osstrtab->os_scn); if (symshndx) { @@ -1859,6 +1877,20 @@ update_osym(Ofl_desc *ofl) shdr->sh_link = (Word)elf_ndxscn(ofl->ofl_ossymtab->os_scn); } + + /* + * Ensure that the expected number of symbols + * were entered into the right spots: + * - Scoped symbols in the right range + * - Globals start at the right spot + * (correct number of locals entered) + * - The table is exactly filled + * (correct number of globals entered) + */ + assert((scopesym_bndx + ofl->ofl_scopecnt) == scopesym_ndx); + assert(shdr->sh_info == (ofl->ofl_shdrcnt + + ofl->ofl_locscnt + ofl->ofl_scopecnt + 2)); + assert((shdr->sh_info + ofl->ofl_globcnt) == symtab_ndx); } if (dynsym) { Shdr *shdr = ofl->ofl_osdynsym->os_shdr; diff --git a/usr/src/cmd/sgs/liblddbg/common/files.c b/usr/src/cmd/sgs/liblddbg/common/files.c index 93839d5b14..0e7d263150 100644 --- a/usr/src/cmd/sgs/liblddbg/common/files.c +++ b/usr/src/cmd/sgs/liblddbg/common/files.c @@ -369,7 +369,7 @@ Dbg_file_dlopen(Rt_map *clmp, const char *name, int *in_nfavl, int mode) Dbg_util_nl(lml, DBG_NL_STD); dbg_print(lml, MSG_INTL(MSG_FIL_DLOPEN), name, NAME(clmp), retry, - conv_dl_mode(mode, 1, &dl_mode_buf)); + conv_dl_mode(mode, 0, &dl_mode_buf)); } void diff --git a/usr/src/cmd/sgs/packages/common/SUNWonld-README b/usr/src/cmd/sgs/packages/common/SUNWonld-README index da89a2f0db..672997c5c4 100644 --- a/usr/src/cmd/sgs/packages/common/SUNWonld-README +++ b/usr/src/cmd/sgs/packages/common/SUNWonld-README @@ -1403,3 +1403,4 @@ Bugid Risk Synopsis 6765299 ld --version-script option not compatible with GNU ld (D) 6748160 problem with -zrescan (D) PSARC/2008/651 New ld archive rescan options +6763342 sloppy relocations need to get sloppier diff --git a/usr/src/cmd/sgs/rtld/common/dlfcns.c b/usr/src/cmd/sgs/rtld/common/dlfcns.c index 6b2ceb8ff8..192c653b25 100644 --- a/usr/src/cmd/sgs/rtld/common/dlfcns.c +++ b/usr/src/cmd/sgs/rtld/common/dlfcns.c @@ -29,8 +29,6 @@ * All Rights Reserved */ -#pragma ident "%Z%%M% %I% %E% SMI" - /* * Programmatic interface to the run_time linker. */ @@ -590,6 +588,18 @@ dlmopen_core(Lm_list *lml, const char *path, int mode, Rt_map *clmp, (path ? path : MSG_ORIG(MSG_STR_ZERO)), in_nfavl, mode)); /* + * Having diagnosed the originally defined modes, assign any defaults + * or corrections. + */ + if (((mode & (RTLD_GROUP | RTLD_WORLD)) == 0) && + ((mode & RTLD_NOLOAD) == 0)) + mode |= (RTLD_GROUP | RTLD_WORLD); + if ((mode & RTLD_NOW) && (rtld_flags2 & RT_FL2_BINDLAZY)) { + mode &= ~RTLD_NOW; + mode |= RTLD_LAZY; + } + + /* * If the path specified is null then we're operating on global * objects. Associate a dummy handle with the link-map list. */ @@ -920,13 +930,6 @@ dlmopen_check(Lm_list *lml, const char *path, int mode, Rt_map *clmp) eprintf(lml, ERR_FATAL, MSG_INTL(MSG_ARG_ILLMODE_4)); return (0); } - if (((mode & (RTLD_GROUP | RTLD_WORLD)) == 0) && - ((mode & RTLD_NOLOAD) == 0)) - mode |= (RTLD_GROUP | RTLD_WORLD); - if ((mode & RTLD_NOW) && (rtld_flags2 & RT_FL2_BINDLAZY)) { - mode &= ~RTLD_NOW; - mode |= RTLD_LAZY; - } return (dlmopen_intn(lml, path, mode, clmp, 0, 0)); } diff --git a/usr/src/cmd/sgs/rtld/common/elf.c b/usr/src/cmd/sgs/rtld/common/elf.c index 1bd0e9c4bc..717ad4dd2f 100644 --- a/usr/src/cmd/sgs/rtld/common/elf.c +++ b/usr/src/cmd/sgs/rtld/common/elf.c @@ -2352,8 +2352,7 @@ elf_new_lm(Lm_list *lml, const char *pname, const char *oname, Dyn *ld, VERSYM(lmp) = (Versym *)(ld->d_un.d_ptr + base); break; case DT_BIND_NOW: - if ((ld->d_un.d_val & DF_BIND_NOW) && - ((rtld_flags2 & RT_FL2_BINDLAZY) == 0)) { + if ((rtld_flags2 & RT_FL2_BINDLAZY) == 0) { MODE(lmp) |= RTLD_NOW; MODE(lmp) &= ~RTLD_LAZY; } |
