f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans/*
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans * CDDL HEADER START
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans *
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans * The contents of this file are subject to the terms of the
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans * Common Development and Distribution License (the "License").
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans * You may not use this file except in compliance with the License.
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans *
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans * or http://www.opensolaris.org/os/licensing.
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans * See the License for the specific language governing permissions
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans * and limitations under the License.
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans *
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans * When distributing Covered Code, include this CDDL HEADER in each
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans * If applicable, add the following below this CDDL HEADER, with the
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans * fields enclosed by brackets "[]" replaced with your own identifying
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans * information: Portions Copyright [yyyy] [name of copyright owner]
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans *
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans * CDDL HEADER END
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans */
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans/*
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans */
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans#ifndef _INLINE_RELOC_H
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans#define _INLINE_RELOC_H
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans#include <sys/types.h>
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans#include <rtld.h>
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans#include <debug.h>
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans/*
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans * Generic relative relocation function.
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans */
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evansinline static ulong_t
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans/* LINTED */
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans/* ARGSUSED4 */
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans_elf_reloc_relative(ulong_t rbgn, ulong_t base, Rt_map *lmp, APlist **textrel,
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans int add)
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans{
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans mmapobj_result_t *mpp;
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans ulong_t roffset;
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans roffset = ((M_RELOC *)rbgn)->r_offset;
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans roffset += base;
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans /*
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans * If this relocation is against an address that is not associated with
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans * a mapped segment, fall back to the generic relocation loop to
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans * collect the associated error.
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans */
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans if ((mpp = find_segment((caddr_t)roffset, lmp)) == NULL)
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans return (0);
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans /*
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans * If this relocation is against a segment that does not provide write
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans * access, set the write permission for all non-writable mappings.
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans */
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans if (((mpp->mr_prot & PROT_WRITE) == 0) && textrel &&
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans ((set_prot(lmp, mpp, 1) == 0) ||
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans (aplist_append(textrel, mpp, AL_CNT_TEXTREL) == NULL)))
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans return (0);
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans /*
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans * Perform a base address update. This simple operation is required
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans * for updating .plt relocations in preparation for lazy binding.
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans */
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans#if defined(__x86)
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans if (add) {
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans *((ulong_t *)roffset) += base;
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans return (1);
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans }
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans#endif
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans /*
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans * Perform the actual relocation. Note, for backward compatibility,
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans * SPARC relocations are added to the offset contents (there was a time
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans * when the offset was used to contain the addend, rather than using
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans * the addend itself).
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans */
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans#if defined(__sparc)
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans *((ulong_t *)roffset) += base + ((M_RELOC *)rbgn)->r_addend;
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans#elif defined(__amd64)
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans *((ulong_t *)roffset) = base + ((M_RELOC *)rbgn)->r_addend;
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans#else
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans *((ulong_t *)roffset) += base;
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans#endif
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans return (1);
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans}
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans/*
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans * When a generic relocation loop realizes that it's dealing with relative
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans * relocations, but no DT_RELCOUNT .dynamic tag is present, this tighter loop
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans * is entered as an optimization.
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans */
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evansinline static ulong_t
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans/* LINTED */
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evanself_reloc_relative(ulong_t rbgn, ulong_t rend, ulong_t rsize, ulong_t base,
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans Rt_map *lmp, APlist **textrel, int add)
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans{
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans uchar_t rtype;
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans do {
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans if (_elf_reloc_relative(rbgn, base, lmp, textrel, add) == 0)
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans break;
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans rbgn += rsize;
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans if (rbgn >= rend)
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans break;
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans /*
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans * Make sure the next type is a relative relocation.
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans */
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans rtype = ELF_R_TYPE(((M_RELOC *)rbgn)->r_info, M_MACH);
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans } while (rtype == M_R_RELATIVE);
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans return (rbgn);
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans}
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans/*
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans * This is the tightest loop for RELATIVE relocations for those objects built
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans * with the DT_RELACOUNT .dynamic entry.
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans */
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evansinline static ulong_t
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans/* LINTED */
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evanself_reloc_relative_count(ulong_t rbgn, ulong_t rcount, ulong_t rsize,
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans ulong_t base, Rt_map *lmp, APlist **textrel, int add)
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans{
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans for (; rcount; rcount--) {
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans if (_elf_reloc_relative(rbgn, base, lmp, textrel, add) == 0)
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans break;
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans rbgn += rsize;
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans }
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans return (rbgn);
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans}
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans/*
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans * Determine, from a symbols Syminfo information, whether a symbol reference
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans * is deferred. This routine is called from elf_reloc() as part of processing
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans * an objects relocations.
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans */
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evansinline static int
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans/* LINTED */
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evansis_sym_deferred(ulong_t rbgn, ulong_t base, Rt_map *lmp, APlist **textrel,
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans Syminfo *sip, ulong_t sndx)
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans{
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans Syminfo *sipe;
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans /*
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans * ldd(1) by default, sets LD_DEFERRED to force deferred dependency
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans * processing. ldd -D disables LD_DEFERRED, which allows ld.so.1's
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans * default action of skipping deferred dependencies.
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans */
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans if (rtld_flags & RT_FL_DEFERRED)
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans return (0);
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans /* LINTED */
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans sipe = (Syminfo *)((char *)sip + (sndx * SYMINENT(lmp)));
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans if (sipe->si_flags & SYMINFO_FLG_DEFERRED) {
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans /*
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans * This .plt relocation should be skipped at this time, as
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans * deferred references are only processed when the associated
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans * function is explicitly called.
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans *
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans * On i386 and amd64 platforms the relocation offset needs
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans * adjusting to add this objects base address. If the object
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans * has already been relocated without RTLD_NOW, then this
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans * update will have already been carried out. However, if this
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans * is an initial RTLD_NOW relocation pass, this relocation
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans * offset needs updating now.
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans */
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans#if defined(__x86)
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans if ((FLAGS(lmp) & FLG_RT_RELOCED) == 0)
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans (void) _elf_reloc_relative(rbgn, base, lmp, textrel, 1);
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans#endif
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans return (1);
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans }
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans return (0);
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans}
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans
f441771b0ce9f9d6122d318ff8290cb1a2848f9dRod Evans#endif /* _INLINE_RELOC_H */