summaryrefslogtreecommitdiff
path: root/usr/src/cmd
diff options
context:
space:
mode:
authorAli Bahrami <Ali.Bahrami@Sun.COM>2008-11-18 09:57:21 -0700
committerAli Bahrami <Ali.Bahrami@Sun.COM>2008-11-18 09:57:21 -0700
commitca4eed8b351c42874d1c1d9360d832914a0ffd1b (patch)
treed9cc734ae65e6e3661287f5bb90fdc10a06e2426 /usr/src/cmd
parentf7b93e0c289f7c2bc496d313146b7af1bd0bf84e (diff)
downloadillumos-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.c5
-rw-r--r--usr/src/cmd/sgs/libld/common/_libld.h4
-rw-r--r--usr/src/cmd/sgs/libld/common/libld.msg1
-rw-r--r--usr/src/cmd/sgs/libld/common/outfile.c68
-rw-r--r--usr/src/cmd/sgs/libld/common/place.c9
-rw-r--r--usr/src/cmd/sgs/libld/common/relocate.c58
-rw-r--r--usr/src/cmd/sgs/libld/common/sections.c12
-rw-r--r--usr/src/cmd/sgs/libld/common/syms.c7
-rw-r--r--usr/src/cmd/sgs/libld/common/update.c38
-rw-r--r--usr/src/cmd/sgs/liblddbg/common/files.c2
-rw-r--r--usr/src/cmd/sgs/packages/common/SUNWonld-README1
-rw-r--r--usr/src/cmd/sgs/rtld/common/dlfcns.c21
-rw-r--r--usr/src/cmd/sgs/rtld/common/elf.c3
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;
}