summaryrefslogtreecommitdiff
path: root/usr/src/cmd/sgs/libld/common/relocate.c
diff options
context:
space:
mode:
authorrie <none@none>2006-01-25 14:52:02 -0800
committerrie <none@none>2006-01-25 14:52:02 -0800
commit141040e8a310da49386b596573e5dde5580572ec (patch)
treeb5527b2c362269cb56233f5267494f647d984d6e /usr/src/cmd/sgs/libld/common/relocate.c
parentff5b2339ca8296ceb5d62fbaa95bad42f885c26d (diff)
downloadillumos-joyent-141040e8a310da49386b596573e5dde5580572ec.tar.gz
6372082 ld -r erroneously creates .got section on i386
6201866 amd64: linker symbol elimination is broken
Diffstat (limited to 'usr/src/cmd/sgs/libld/common/relocate.c')
-rw-r--r--usr/src/cmd/sgs/libld/common/relocate.c194
1 files changed, 176 insertions, 18 deletions
diff --git a/usr/src/cmd/sgs/libld/common/relocate.c b/usr/src/cmd/sgs/libld/common/relocate.c
index 2f651c36dd..c389f8f361 100644
--- a/usr/src/cmd/sgs/libld/common/relocate.c
+++ b/usr/src/cmd/sgs/libld/common/relocate.c
@@ -24,8 +24,7 @@
* Copyright (c) 1988 AT&T
* All Rights Reserved
*
- *
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
@@ -197,7 +196,7 @@ disp_bsearch(const void *key, const void *array)
*/
static Sym_desc *
disp_scansyms(Ifl_desc * ifl, Rel_desc *rld, Boolean rlocal, int inspect,
- Ofl_desc * ofl)
+ Ofl_desc *ofl)
{
Sym_desc *tsdp, *rsdp;
Sym *rsym, *tsym;
@@ -243,7 +242,7 @@ disp_scansyms(Ifl_desc * ifl, Rel_desc *rld, Boolean rlocal, int inspect,
} else {
/*
* If both symbols are local, no copy relocations can occur to
- * either.
+ * either symbol.
*/
if ((rlocal == TRUE) && ((tsdp->sd_flags1 & FLG_SY1_LOCL) ||
((ofl->ofl_flags & FLG_OF_AUTOLCL) &&
@@ -258,7 +257,18 @@ disp_scansyms(Ifl_desc * ifl, Rel_desc *rld, Boolean rlocal, int inspect,
ttype = ELF_ST_TYPE(tsym->st_info);
/*
- * One of the symbols must reference a data element.
+ * If the reference symbol is local, and the target isn't a
+ * data element, then no copy relocations can occur to either
+ * symbol. Note, this catches pc-relative relocations against
+ * the _GLOBAL_OFFSET_TABLE_, which is effectively treated as
+ * a local symbol.
+ */
+ if ((rlocal == TRUE) && (ttype != STT_OBJECT) &&
+ (ttype != STT_SECTION))
+ return (tsdp);
+
+ /*
+ * Finally, one of the symbols must reference a data element.
*/
if ((rtype != STT_OBJECT) && (rtype != STT_SECTION) &&
(ttype != STT_OBJECT) && (ttype != STT_SECTION))
@@ -410,6 +420,85 @@ disp_inspect(Ofl_desc *ofl, Rel_desc *rld, Boolean rlocal)
return (1);
}
+/*
+ * Add an active relocation record.
+ */
+uintptr_t
+add_actrel(Word flags, Rel_desc *rsp, Ofl_desc *ofl)
+{
+ Rel_desc *arsp;
+ Rel_cache *rcp;
+
+ /*
+ * If no relocation cache structures are available, allocate a new
+ * one and link it into the bucket list.
+ */
+ if ((ofl->ofl_actrels.tail == 0) ||
+ ((rcp = (Rel_cache *)ofl->ofl_actrels.tail->data) == 0) ||
+ ((arsp = rcp->rc_free) == rcp->rc_end)) {
+ static size_t nextsize = 0;
+ size_t size;
+
+ /*
+ * Typically, when generating an executable or shared object
+ * there will be an active relocation for every input
+ * relocation.
+ */
+ if (nextsize == 0) {
+ if ((ofl->ofl_flags & FLG_OF_RELOBJ) == 0) {
+ if ((size = ofl->ofl_relocincnt) == 0)
+ size = REL_LAIDESCNO;
+ if (size > REL_HAIDESCNO)
+ nextsize = REL_HAIDESCNO;
+ else
+ nextsize = REL_LAIDESCNO;
+ } else
+ nextsize = size = REL_HAIDESCNO;
+ } else
+ size = nextsize;
+
+ size = size * sizeof (Rel_desc);
+
+ if (((rcp = libld_malloc(sizeof (Rel_cache) + size)) == 0) ||
+ (list_appendc(&ofl->ofl_actrels, rcp) == 0))
+ return (S_ERROR);
+
+ /* LINTED */
+ rcp->rc_free = arsp = (Rel_desc *)(rcp + 1);
+ /* LINTED */
+ rcp->rc_end = (Rel_desc *)((char *)rcp->rc_free + size);
+ }
+
+ *arsp = *rsp;
+ arsp->rel_flags |= flags;
+
+ rcp->rc_free++;
+ ofl->ofl_actrelscnt++;
+
+ /*
+ * Any GOT relocation reference requires the creation of a .got table.
+ * Most references to a .got require a .got entry, which is accounted
+ * for with the ofl_gotcnt counter. However, some references are
+ * relative to the .got table, but require no .got entry. This test
+ * insures a .got is created regardless of the type of reference.
+ */
+ if (IS_GOT_REQUIRED(arsp->rel_rtype))
+ ofl->ofl_flags |= FLG_OF_BLDGOT;
+
+ /*
+ * If this is a displacement relocation generate a warning.
+ */
+ if (arsp->rel_flags & FLG_REL_DISP) {
+ ofl->ofl_dtflags_1 |= DF_1_DISPRELDNE;
+
+ if (ofl->ofl_flags & FLG_OF_VERBOSE)
+ disp_errmsg(MSG_INTL(MSG_REL_DISPREL3), arsp, ofl);
+ }
+
+ DBG_CALL(Dbg_reloc_ars_entry(M_MACH, arsp));
+ return (1);
+}
+
uintptr_t
reloc_GOT_relative(Boolean local, Rel_desc *rsp, Ofl_desc *ofl)
{
@@ -815,6 +904,81 @@ reloc_generic(Rel_desc *rsp, Ofl_desc *ofl)
return (add_actrel(NULL, rsp, ofl));
}
+/*
+ * Process relocations when building a relocatable object. Typically, there
+ * aren't many relocations that can be caught at this point, most are simply
+ * passed through to the output relocatable object.
+ */
+static uintptr_t
+reloc_relobj(Boolean local, Rel_desc *rsp, Ofl_desc *ofl)
+{
+ Word rtype = rsp->rel_rtype;
+ Sym_desc *sdp = rsp->rel_sym;
+ Is_desc *isp = rsp->rel_isdesc;
+ Word oflags = NULL;
+
+ /*
+ * Determine if we can do any relocations at this point. We can if:
+ *
+ * this is local_symbol and a non-GOT relocation, and
+ * the relocation is pc-relative, and
+ * the relocation is against a symbol in same section
+ */
+ if (local && !IS_GOT_RELATIVE(rtype) && !IS_GOT_BASED(rtype) &&
+ !IS_GOT_PC(rtype) && IS_PC_RELATIVE(rtype) &&
+ ((sdp->sd_isc) && (sdp->sd_isc->is_osdesc == isp->is_osdesc)))
+ return (add_actrel(NULL, rsp, ofl));
+
+ /*
+ * If -zredlocsym is in effect, translate all local symbol relocations
+ * to be against section symbols, since section symbols are the only
+ * symbols which will be added to the .symtab.
+ */
+ if (local && (((ofl->ofl_flags1 & FLG_OF1_REDLSYM) &&
+ (ELF_ST_BIND(sdp->sd_sym->st_info) == STB_LOCAL)) ||
+ ((sdp->sd_flags1 & FLG_SY1_ELIM) &&
+ (ofl->ofl_flags & FLG_OF_PROCRED)))) {
+ /*
+ * But if this is PIC code, don't allow it for now.
+ */
+ if (IS_GOT_RELATIVE(rsp->rel_rtype)) {
+ Ifl_desc *ifl = rsp->rel_isdesc->is_file;
+
+ eprintf(ERR_FATAL, MSG_INTL(MSG_REL_PICREDLOC),
+ demangle(rsp->rel_sname), ifl->ifl_name,
+ conv_reloc_type_str(ifl->ifl_ehdr->e_machine,
+ rsp->rel_rtype));
+ return (S_ERROR);
+ }
+
+ /*
+ * Indicate that this relocation should be processed the same
+ * as a section symbol. For SPARC and AMD (Rela), indicate
+ * that the addend also needs to be applied to this relocation.
+ */
+#if defined(__i386)
+ oflags = FLG_REL_SCNNDX;
+#else
+ oflags = FLG_REL_SCNNDX | FLG_REL_ADVAL;
+#endif
+ }
+
+#if defined(__i386)
+ /*
+ * Intel (Rel) relocations do not contain an addend. Any addend is
+ * contained within the file at the location identified by the
+ * relocation offset. Therefore, if we're processing a section symbol,
+ * or a -zredlocsym relocation (that basically transforms a local symbol
+ * reference into a section reference), perform an active relocation to
+ * propagate any addend.
+ */
+ if ((ELF_ST_TYPE(sdp->sd_sym->st_info) == STT_SECTION) ||
+ (oflags == FLG_REL_SCNNDX))
+ if (add_actrel(NULL, rsp, ofl) == S_ERROR)
+ return (S_ERROR);
+#endif
+ return (add_outrel(oflags, rsp, ofl));
+}
uintptr_t
process_sym_reloc(Ofl_desc * ofl, Rel_desc * reld, Rel * reloc,
@@ -1474,20 +1638,14 @@ reloc_init(Ofl_desc *ofl)
}
/*
- * Make a got section if:
- *
- * BLDGOT flag set
- * or
- * ofl_gotcnt != GOT_XNumber
- * or
- * not-relobj & GOT symbol referenced
- *
+ * GOT sections are created for dynamic executables and shared objects
+ * if the FLG_OF_BLDGOT is set, or explicit reference has been made to
+ * a GOT symbol.
*/
- if ((ofl->ofl_flags & FLG_OF_BLDGOT) ||
- (ofl->ofl_gotcnt != M_GOT_XNumber) ||
- (((ofl->ofl_flags & FLG_OF_RELOBJ) == 0) &&
- ((sym_find(MSG_ORIG(MSG_SYM_GOFTBL), SYM_NOHASH, 0, ofl) != 0) ||
- (sym_find(MSG_ORIG(MSG_SYM_GOFTBL_U), SYM_NOHASH, 0, ofl) != 0)))) {
+ if (((ofl->ofl_flags & FLG_OF_RELOBJ) == 0) &&
+ ((ofl->ofl_flags & FLG_OF_BLDGOT) ||
+ (sym_find(MSG_ORIG(MSG_SYM_GOFTBL), SYM_NOHASH, 0, ofl) != 0) ||
+ (sym_find(MSG_ORIG(MSG_SYM_GOFTBL_U), SYM_NOHASH, 0, ofl) != 0))) {
if (make_got(ofl) == S_ERROR)
return (S_ERROR);