17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
52926dd2eSrie * Common Development and Distribution License (the "License").
62926dd2eSrie * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
212926dd2eSrie
227c478bd9Sstevel@tonic-gate /*
23*08278a5eSRod Evans * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
247c478bd9Sstevel@tonic-gate * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate */
267c478bd9Sstevel@tonic-gate
277c478bd9Sstevel@tonic-gate #include <libelf.h>
287c478bd9Sstevel@tonic-gate #include <dlfcn.h>
297c478bd9Sstevel@tonic-gate #include "machdep.h"
307c478bd9Sstevel@tonic-gate #include "reloc.h"
317c478bd9Sstevel@tonic-gate #include "msg.h"
327c478bd9Sstevel@tonic-gate #include "_librtld.h"
332926dd2eSrie #include "alist.h"
347c478bd9Sstevel@tonic-gate
357c478bd9Sstevel@tonic-gate static const char *unknown = 0; /* Stash MSG_INTL(MSG_STR_UNKNOWN) */
367c478bd9Sstevel@tonic-gate
377c478bd9Sstevel@tonic-gate /*
387c478bd9Sstevel@tonic-gate * Process all relocation records. A new `Reloc' structure is allocated to
397c478bd9Sstevel@tonic-gate * cache the processing decisions deduced, and these will be applied during
407c478bd9Sstevel@tonic-gate * update_reloc().
417c478bd9Sstevel@tonic-gate * A count of the number of null relocations (i.e., relocations that will be
427c478bd9Sstevel@tonic-gate * fixed and whoes records will be nulled out), data and function relocations
437c478bd9Sstevel@tonic-gate * is maintained. This allows the relocation records themselves to be
447c478bd9Sstevel@tonic-gate * rearranged (localized) later if necessary. Note that the number of function
457c478bd9Sstevel@tonic-gate * relocations, although coounted, shouldn't differ from the original file,
467c478bd9Sstevel@tonic-gate * the index of a .plt must be maintained to the index of its relocation record
477c478bd9Sstevel@tonic-gate * within the associated relocation section.
487c478bd9Sstevel@tonic-gate *
497c478bd9Sstevel@tonic-gate * The intention behind this file is to maintain as much relocation logic as
507c478bd9Sstevel@tonic-gate * possible in a generic form.
517c478bd9Sstevel@tonic-gate */
527c478bd9Sstevel@tonic-gate int
count_reloc(Cache * cache,Cache * _cache,Rt_map * lmp,int flags,Addr addr,Xword * null,Xword * data,Xword * func,Alist * nodirect)537c478bd9Sstevel@tonic-gate count_reloc(Cache *cache, Cache *_cache, Rt_map *lmp, int flags, Addr addr,
542926dd2eSrie Xword *null, Xword *data, Xword *func, Alist *nodirect)
557c478bd9Sstevel@tonic-gate {
567c478bd9Sstevel@tonic-gate Rel *rel;
577c478bd9Sstevel@tonic-gate Reloc *reloc;
587c478bd9Sstevel@tonic-gate Shdr *shdr;
597c478bd9Sstevel@tonic-gate Xword ent, cnt, _cnt;
607c478bd9Sstevel@tonic-gate Sym *syms;
617c478bd9Sstevel@tonic-gate const char *strs;
627c478bd9Sstevel@tonic-gate Cache *__cache;
637c478bd9Sstevel@tonic-gate Xword pltndx = 0;
647c478bd9Sstevel@tonic-gate
657c478bd9Sstevel@tonic-gate /*
667c478bd9Sstevel@tonic-gate * Determine the number of relocation entries we'll be dealing with.
677c478bd9Sstevel@tonic-gate */
687c478bd9Sstevel@tonic-gate shdr = _cache->c_shdr;
697c478bd9Sstevel@tonic-gate rel = (Rel *)_cache->c_data->d_buf;
707c478bd9Sstevel@tonic-gate ent = shdr->sh_entsize;
717c478bd9Sstevel@tonic-gate cnt = shdr->sh_size / ent;
727c478bd9Sstevel@tonic-gate
737c478bd9Sstevel@tonic-gate /*
747c478bd9Sstevel@tonic-gate * Allocate a relocation structure for this relocation section.
757c478bd9Sstevel@tonic-gate */
767c478bd9Sstevel@tonic-gate if ((reloc = calloc(cnt, sizeof (Reloc))) == 0)
777c478bd9Sstevel@tonic-gate return (1);
787c478bd9Sstevel@tonic-gate _cache->c_info = (void *)reloc;
797c478bd9Sstevel@tonic-gate
807c478bd9Sstevel@tonic-gate /*
817c478bd9Sstevel@tonic-gate * Determine the relocations associated symbol and string table.
827c478bd9Sstevel@tonic-gate */
837c478bd9Sstevel@tonic-gate __cache = &cache[shdr->sh_link];
847c478bd9Sstevel@tonic-gate syms = (Sym *)__cache->c_data->d_buf;
857c478bd9Sstevel@tonic-gate shdr = __cache->c_shdr;
867c478bd9Sstevel@tonic-gate __cache = &cache[shdr->sh_link];
877c478bd9Sstevel@tonic-gate strs = (const char *)__cache->c_data->d_buf;
887c478bd9Sstevel@tonic-gate
897c478bd9Sstevel@tonic-gate /*
907c478bd9Sstevel@tonic-gate * Loop through the relocation table.
917c478bd9Sstevel@tonic-gate */
927c478bd9Sstevel@tonic-gate for (_cnt = 0; _cnt < cnt; _cnt++, reloc++,
937c478bd9Sstevel@tonic-gate rel = (Rel *)((uintptr_t)rel + ent)) {
947c478bd9Sstevel@tonic-gate const char *name;
957c478bd9Sstevel@tonic-gate /* LINTED */
96ba2be530Sab196087 uchar_t type = (uchar_t)ELF_R_TYPE(rel->r_info, M_MACH);
977c478bd9Sstevel@tonic-gate uchar_t bind;
987c478bd9Sstevel@tonic-gate ulong_t offset = rel->r_offset + addr;
997c478bd9Sstevel@tonic-gate Rt_map *_lmp;
1007c478bd9Sstevel@tonic-gate int _bound, _weak;
1017c478bd9Sstevel@tonic-gate ulong_t rsymndx = ELF_R_SYM(rel->r_info);
1027c478bd9Sstevel@tonic-gate Slookup sl;
103*08278a5eSRod Evans Sresult sr;
1047c478bd9Sstevel@tonic-gate uint_t binfo;
1057c478bd9Sstevel@tonic-gate Sym *_sym, *sym = (syms + rsymndx);
1067c478bd9Sstevel@tonic-gate
1077c478bd9Sstevel@tonic-gate if (type == M_R_JMP_SLOT)
1087c478bd9Sstevel@tonic-gate reloc->r_pltndx = ++pltndx;
1097c478bd9Sstevel@tonic-gate
1107c478bd9Sstevel@tonic-gate /*
1117c478bd9Sstevel@tonic-gate * Analyze the case where no relocations are to be applied.
1127c478bd9Sstevel@tonic-gate */
1137c478bd9Sstevel@tonic-gate if ((flags & RTLD_REL_ALL) == 0) {
1147c478bd9Sstevel@tonic-gate /*
1157c478bd9Sstevel@tonic-gate * Don't apply any relocations to the new image but
1167c478bd9Sstevel@tonic-gate * insure their offsets are incremented to reflect any
1177c478bd9Sstevel@tonic-gate * new fixed address.
1187c478bd9Sstevel@tonic-gate */
1197c478bd9Sstevel@tonic-gate reloc->r_flags = FLG_R_INC;
1207c478bd9Sstevel@tonic-gate
1217c478bd9Sstevel@tonic-gate /*
1227c478bd9Sstevel@tonic-gate * Undo any relocations that might have already been
1237c478bd9Sstevel@tonic-gate * applied to the memory image.
1247c478bd9Sstevel@tonic-gate */
1257c478bd9Sstevel@tonic-gate if (flags & RTLD_MEMORY) {
1267c478bd9Sstevel@tonic-gate reloc->r_flags |= FLG_R_UNDO;
1277c478bd9Sstevel@tonic-gate
1287c478bd9Sstevel@tonic-gate /*
1297c478bd9Sstevel@tonic-gate * If a copy relocation is involved we'll need
1307c478bd9Sstevel@tonic-gate * to know the size of the copy.
1317c478bd9Sstevel@tonic-gate */
1327c478bd9Sstevel@tonic-gate if (type == M_R_COPY)
1337c478bd9Sstevel@tonic-gate reloc->r_size = sym->st_size;
1347c478bd9Sstevel@tonic-gate else
1357c478bd9Sstevel@tonic-gate reloc->r_size = 0;
1367c478bd9Sstevel@tonic-gate }
1377c478bd9Sstevel@tonic-gate
1387c478bd9Sstevel@tonic-gate /*
1397c478bd9Sstevel@tonic-gate * Save the objects new address.
1407c478bd9Sstevel@tonic-gate */
1417c478bd9Sstevel@tonic-gate reloc->r_value = addr;
1427c478bd9Sstevel@tonic-gate
1437c478bd9Sstevel@tonic-gate if (type == M_R_JMP_SLOT)
1447c478bd9Sstevel@tonic-gate (*func)++;
1457c478bd9Sstevel@tonic-gate else
1467c478bd9Sstevel@tonic-gate (*data)++;
1477c478bd9Sstevel@tonic-gate continue;
1487c478bd9Sstevel@tonic-gate }
1497c478bd9Sstevel@tonic-gate
1507c478bd9Sstevel@tonic-gate /*
1517c478bd9Sstevel@tonic-gate * Determine the symbol binding of the relocation. Don't assume
1527c478bd9Sstevel@tonic-gate * that relative relocations are simply M_R_RELATIVE. Although
1537c478bd9Sstevel@tonic-gate * a pic generated shared object can normally be viewed as
1547c478bd9Sstevel@tonic-gate * having relative and non-relative relocations, a non-pic
1557c478bd9Sstevel@tonic-gate * shared object will contain a number of relocations against
1567c478bd9Sstevel@tonic-gate * local symbols (normally sections). If a relocation is
1577c478bd9Sstevel@tonic-gate * against a local symbol it qualifies as a relative relocation.
1587c478bd9Sstevel@tonic-gate */
1597c478bd9Sstevel@tonic-gate if ((type == M_R_RELATIVE) || (type == M_R_NONE) ||
1607c478bd9Sstevel@tonic-gate (ELF_ST_BIND(sym->st_info) == STB_LOCAL))
1617c478bd9Sstevel@tonic-gate bind = STB_LOCAL;
1627c478bd9Sstevel@tonic-gate else
1637c478bd9Sstevel@tonic-gate bind = STB_GLOBAL;
1647c478bd9Sstevel@tonic-gate
1657c478bd9Sstevel@tonic-gate /*
1667c478bd9Sstevel@tonic-gate * Analyze the case where only relative relocations are to be
1677c478bd9Sstevel@tonic-gate * applied.
1687c478bd9Sstevel@tonic-gate */
1697c478bd9Sstevel@tonic-gate if ((flags & RTLD_REL_ALL) == RTLD_REL_RELATIVE) {
1707c478bd9Sstevel@tonic-gate if (flags & RTLD_MEMORY) {
1717c478bd9Sstevel@tonic-gate if (bind == STB_LOCAL) {
1727c478bd9Sstevel@tonic-gate /*
1737c478bd9Sstevel@tonic-gate * Save the relative relocations from
1747c478bd9Sstevel@tonic-gate * the memory image. The data itself
1757c478bd9Sstevel@tonic-gate * might already have been relocated,
1767c478bd9Sstevel@tonic-gate * thus clear the relocation record so
1777c478bd9Sstevel@tonic-gate * that it will not be performed again.
1787c478bd9Sstevel@tonic-gate */
1797c478bd9Sstevel@tonic-gate reloc->r_flags = FLG_R_CLR;
1807c478bd9Sstevel@tonic-gate (*null)++;
1817c478bd9Sstevel@tonic-gate } else {
1827c478bd9Sstevel@tonic-gate /*
1837c478bd9Sstevel@tonic-gate * Any non-relative relocation must be
1847c478bd9Sstevel@tonic-gate * undone, and the relocation records
1857c478bd9Sstevel@tonic-gate * offset updated to any new fixed
1867c478bd9Sstevel@tonic-gate * address.
1877c478bd9Sstevel@tonic-gate */
1887c478bd9Sstevel@tonic-gate reloc->r_flags =
1897c478bd9Sstevel@tonic-gate (FLG_R_UNDO | FLG_R_INC);
1907c478bd9Sstevel@tonic-gate reloc->r_value = addr;
1917c478bd9Sstevel@tonic-gate if (type == M_R_JMP_SLOT)
1927c478bd9Sstevel@tonic-gate (*func)++;
1937c478bd9Sstevel@tonic-gate else
1947c478bd9Sstevel@tonic-gate (*data)++;
1957c478bd9Sstevel@tonic-gate }
1967c478bd9Sstevel@tonic-gate } else {
1977c478bd9Sstevel@tonic-gate if (bind == STB_LOCAL) {
1987c478bd9Sstevel@tonic-gate /*
1997c478bd9Sstevel@tonic-gate * Apply relative relocation to the
2007c478bd9Sstevel@tonic-gate * file image. Clear the relocation
2017c478bd9Sstevel@tonic-gate * record so that it will not be
2027c478bd9Sstevel@tonic-gate * performed again.
2037c478bd9Sstevel@tonic-gate */
2047c478bd9Sstevel@tonic-gate reloc->r_flags =
2057c478bd9Sstevel@tonic-gate (FLG_R_APPLY | FLG_R_CLR);
2067c478bd9Sstevel@tonic-gate reloc->r_value = addr;
2077c478bd9Sstevel@tonic-gate if (IS_PC_RELATIVE(type))
2087c478bd9Sstevel@tonic-gate reloc->r_value -= offset;
2097c478bd9Sstevel@tonic-gate
2107c478bd9Sstevel@tonic-gate if (unknown == 0)
21160758829Srie unknown =
21260758829Srie MSG_INTL(MSG_STR_UNKNOWN);
2137c478bd9Sstevel@tonic-gate reloc->r_name = unknown;
2147c478bd9Sstevel@tonic-gate (*null)++;
2157c478bd9Sstevel@tonic-gate } else {
2167c478bd9Sstevel@tonic-gate /*
2177c478bd9Sstevel@tonic-gate * Any non-relative relocation should be
2187c478bd9Sstevel@tonic-gate * left alone, but its offset should be
2197c478bd9Sstevel@tonic-gate * updated to any new fixed address.
2207c478bd9Sstevel@tonic-gate */
2217c478bd9Sstevel@tonic-gate reloc->r_flags = FLG_R_INC;
2227c478bd9Sstevel@tonic-gate reloc->r_value = addr;
2237c478bd9Sstevel@tonic-gate if (type == M_R_JMP_SLOT)
2247c478bd9Sstevel@tonic-gate (*func)++;
2257c478bd9Sstevel@tonic-gate else
2267c478bd9Sstevel@tonic-gate (*data)++;
2277c478bd9Sstevel@tonic-gate }
2287c478bd9Sstevel@tonic-gate }
2297c478bd9Sstevel@tonic-gate continue;
2307c478bd9Sstevel@tonic-gate }
2317c478bd9Sstevel@tonic-gate
2327c478bd9Sstevel@tonic-gate /*
2337c478bd9Sstevel@tonic-gate * Analyze the case where more than just relative relocations
2347c478bd9Sstevel@tonic-gate * are to be applied.
2357c478bd9Sstevel@tonic-gate */
2367c478bd9Sstevel@tonic-gate if (bind == STB_LOCAL) {
2377c478bd9Sstevel@tonic-gate if (flags & RTLD_MEMORY) {
2387c478bd9Sstevel@tonic-gate /*
2397c478bd9Sstevel@tonic-gate * Save the relative relocations from the memory
2407c478bd9Sstevel@tonic-gate * image. The data itself has already been
2417c478bd9Sstevel@tonic-gate * relocated, thus clear the relocation record
2427c478bd9Sstevel@tonic-gate * so that it will not be performed again.
2437c478bd9Sstevel@tonic-gate */
2447c478bd9Sstevel@tonic-gate reloc->r_flags = FLG_R_CLR;
2457c478bd9Sstevel@tonic-gate } else {
2467c478bd9Sstevel@tonic-gate /*
2477c478bd9Sstevel@tonic-gate * Apply relative relocation to the file image.
2487c478bd9Sstevel@tonic-gate * Clear the relocation record so that it will
2497c478bd9Sstevel@tonic-gate * not be performed again.
2507c478bd9Sstevel@tonic-gate */
2517c478bd9Sstevel@tonic-gate reloc->r_flags = (FLG_R_APPLY | FLG_R_CLR);
2527c478bd9Sstevel@tonic-gate reloc->r_value = addr;
2537c478bd9Sstevel@tonic-gate if (IS_PC_RELATIVE(type))
2547c478bd9Sstevel@tonic-gate reloc->r_value -= offset;
2557c478bd9Sstevel@tonic-gate
2567c478bd9Sstevel@tonic-gate if (unknown == 0)
2577c478bd9Sstevel@tonic-gate unknown = MSG_INTL(MSG_STR_UNKNOWN);
2587c478bd9Sstevel@tonic-gate reloc->r_name = unknown;
2597c478bd9Sstevel@tonic-gate }
2607c478bd9Sstevel@tonic-gate (*null)++;
2617c478bd9Sstevel@tonic-gate continue;
2627c478bd9Sstevel@tonic-gate }
2637c478bd9Sstevel@tonic-gate
2647c478bd9Sstevel@tonic-gate /*
2657c478bd9Sstevel@tonic-gate * At this point we're dealing with a non-relative relocation
2667c478bd9Sstevel@tonic-gate * that requires the symbol definition.
2677c478bd9Sstevel@tonic-gate */
2687c478bd9Sstevel@tonic-gate name = strs + sym->st_name;
2697c478bd9Sstevel@tonic-gate
2707c478bd9Sstevel@tonic-gate /*
2717c478bd9Sstevel@tonic-gate * Find the symbol. As the object being investigated is already
2727c478bd9Sstevel@tonic-gate * a part of this process, the symbol lookup will likely
2737c478bd9Sstevel@tonic-gate * succeed. However, because of lazy binding, there is still
2747c478bd9Sstevel@tonic-gate * the possibility of a dangling .plt relocation. dldump()
2757c478bd9Sstevel@tonic-gate * users might be encouraged to set LD_FLAGS=loadavail (crle(1)
2767c478bd9Sstevel@tonic-gate * does this for them).
27775e7992aSrie *
278*08278a5eSRod Evans * Initialize the symbol lookup, and symbol result, data
279*08278a5eSRod Evans * structures.
2807c478bd9Sstevel@tonic-gate */
28175e7992aSrie SLOOKUP_INIT(sl, name, lmp, LIST(lmp)->lm_head, ld_entry_cnt,
28275e7992aSrie 0, rsymndx, sym, type, LKUP_STDRELOC);
283*08278a5eSRod Evans SRESULT_INIT(sr, name);
2847c478bd9Sstevel@tonic-gate
2857c478bd9Sstevel@tonic-gate _bound = _weak = 0;
2867c478bd9Sstevel@tonic-gate _sym = sym;
287*08278a5eSRod Evans if (lookup_sym(&sl, &sr, &binfo, NULL)) {
288*08278a5eSRod Evans _lmp = sr.sr_dmap;
289*08278a5eSRod Evans sym = sr.sr_sym;
290*08278a5eSRod Evans
2917c478bd9Sstevel@tonic-gate /*
2927c478bd9Sstevel@tonic-gate * Determine from the various relocation requirements
2937c478bd9Sstevel@tonic-gate * whether this binding is appropriate. If we're called
2947c478bd9Sstevel@tonic-gate * from crle(1), RTLD_CONFSET is set, then only inspect
2957c478bd9Sstevel@tonic-gate * objects selected from the configuration file
2967c478bd9Sstevel@tonic-gate * (FL1_RT_CONFSET was set during load()).
2977c478bd9Sstevel@tonic-gate */
2987c478bd9Sstevel@tonic-gate if (!(flags & RTLD_CONFSET) ||
2997c478bd9Sstevel@tonic-gate (FLAGS1(_lmp) & FL1_RT_CONFSET)) {
3007c478bd9Sstevel@tonic-gate if (((flags & RTLD_REL_ALL) == RTLD_REL_ALL) ||
3017c478bd9Sstevel@tonic-gate ((flags & RTLD_REL_EXEC) &&
3027c478bd9Sstevel@tonic-gate (FLAGS(_lmp) & FLG_RT_ISMAIN)) ||
3037c478bd9Sstevel@tonic-gate ((flags & RTLD_REL_DEPENDS) &&
3047c478bd9Sstevel@tonic-gate (!(FLAGS(_lmp) & FLG_RT_ISMAIN))) ||
3057c478bd9Sstevel@tonic-gate ((flags & RTLD_REL_PRELOAD) &&
3067c478bd9Sstevel@tonic-gate (FLAGS(_lmp) & FLG_RT_PRELOAD)) ||
3072926dd2eSrie ((flags & RTLD_REL_SELF) &&
3082926dd2eSrie (lmp == _lmp))) {
309cce0e03bSab196087 Aliste idx;
3102926dd2eSrie Word *ndx;
3112926dd2eSrie
3127c478bd9Sstevel@tonic-gate _bound = 1;
3132926dd2eSrie
3142926dd2eSrie /*
3152926dd2eSrie * If this symbol is explicitly defined
3162926dd2eSrie * as nodirect, don't allow any local
3172926dd2eSrie * binding.
3182926dd2eSrie */
319cce0e03bSab196087 for (ALIST_TRAVERSE(nodirect, idx,
3202926dd2eSrie ndx)) {
3212926dd2eSrie if (*ndx == rsymndx) {
3222926dd2eSrie _bound = 0;
3232926dd2eSrie break;
3242926dd2eSrie }
3252926dd2eSrie }
3262926dd2eSrie }
3277c478bd9Sstevel@tonic-gate }
3287c478bd9Sstevel@tonic-gate } else {
3297c478bd9Sstevel@tonic-gate /*
3307c478bd9Sstevel@tonic-gate * If this is a weak reference and we've been asked to
3317c478bd9Sstevel@tonic-gate * bind unresolved weak references consider ourself
3327c478bd9Sstevel@tonic-gate * bound. This category is typically set by clre(1) for
3337c478bd9Sstevel@tonic-gate * an application cache.
3347c478bd9Sstevel@tonic-gate */
3357c478bd9Sstevel@tonic-gate if ((ELF_ST_BIND(_sym->st_info) == STB_WEAK) &&
3367c478bd9Sstevel@tonic-gate (_sym->st_shndx == SHN_UNDEF) &&
3377c478bd9Sstevel@tonic-gate (flags & RTLD_REL_WEAK))
3387c478bd9Sstevel@tonic-gate _bound = _weak = 1;
3397c478bd9Sstevel@tonic-gate }
3407c478bd9Sstevel@tonic-gate
3417c478bd9Sstevel@tonic-gate if (flags & RTLD_MEMORY) {
3427c478bd9Sstevel@tonic-gate if (_bound) {
3437c478bd9Sstevel@tonic-gate /*
3447c478bd9Sstevel@tonic-gate * We know that all data relocations will have
3457c478bd9Sstevel@tonic-gate * been performed at process startup thus clear
3467c478bd9Sstevel@tonic-gate * the relocation record so that it will not be
3477c478bd9Sstevel@tonic-gate * performed again. However, we don't know what
3487c478bd9Sstevel@tonic-gate * function relocations have been performed
3497c478bd9Sstevel@tonic-gate * because of lazy binding - regardless, we can
3507c478bd9Sstevel@tonic-gate * leave all the function relocation records in
3517c478bd9Sstevel@tonic-gate * place, because if the function has already
3527c478bd9Sstevel@tonic-gate * been bound the record won't be referenced
3537c478bd9Sstevel@tonic-gate * anyway. In the case of using LD_BIND_NOW,
3547c478bd9Sstevel@tonic-gate * a function may be bound twice - so what.
3557c478bd9Sstevel@tonic-gate */
3567c478bd9Sstevel@tonic-gate if (type == M_R_JMP_SLOT) {
3577c478bd9Sstevel@tonic-gate reloc->r_flags = FLG_R_INC;
3587c478bd9Sstevel@tonic-gate (*func)++;
3597c478bd9Sstevel@tonic-gate } else {
3607c478bd9Sstevel@tonic-gate if (type != M_R_COPY)
3617c478bd9Sstevel@tonic-gate reloc->r_flags = FLG_R_CLR;
3627c478bd9Sstevel@tonic-gate (*null)++;
3637c478bd9Sstevel@tonic-gate }
3647c478bd9Sstevel@tonic-gate } else {
3657c478bd9Sstevel@tonic-gate /*
3667c478bd9Sstevel@tonic-gate * Clear any unrequired relocation.
3677c478bd9Sstevel@tonic-gate */
3687c478bd9Sstevel@tonic-gate reloc->r_flags = FLG_R_UNDO | FLG_R_INC;
3697c478bd9Sstevel@tonic-gate reloc->r_value = addr;
3707c478bd9Sstevel@tonic-gate if (type == M_R_JMP_SLOT)
3717c478bd9Sstevel@tonic-gate (*func)++;
3727c478bd9Sstevel@tonic-gate else
3737c478bd9Sstevel@tonic-gate (*data)++;
3747c478bd9Sstevel@tonic-gate }
3757c478bd9Sstevel@tonic-gate } else {
3767c478bd9Sstevel@tonic-gate if (_bound) {
3777c478bd9Sstevel@tonic-gate /*
3787c478bd9Sstevel@tonic-gate * Apply the global relocation to the file
3797c478bd9Sstevel@tonic-gate * image. Clear the relocation record so that
3807c478bd9Sstevel@tonic-gate * it will not be performed again.
3817c478bd9Sstevel@tonic-gate */
3827c478bd9Sstevel@tonic-gate if (_weak) {
3837c478bd9Sstevel@tonic-gate reloc->r_value = 0;
3847c478bd9Sstevel@tonic-gate reloc->r_size = 0;
3857c478bd9Sstevel@tonic-gate } else {
3867c478bd9Sstevel@tonic-gate reloc->r_value = sym->st_value;
3877c478bd9Sstevel@tonic-gate if (IS_PC_RELATIVE(type))
3887c478bd9Sstevel@tonic-gate reloc->r_value -= offset;
3897c478bd9Sstevel@tonic-gate if ((!(FLAGS(_lmp) & FLG_RT_FIXED)) &&
3907c478bd9Sstevel@tonic-gate (sym->st_shndx != SHN_ABS))
3917c478bd9Sstevel@tonic-gate reloc->r_value += ADDR(_lmp);
3927c478bd9Sstevel@tonic-gate reloc->r_size = sym->st_size;
3937c478bd9Sstevel@tonic-gate }
3947c478bd9Sstevel@tonic-gate
3957c478bd9Sstevel@tonic-gate reloc->r_flags = FLG_R_APPLY | FLG_R_CLR;
3967c478bd9Sstevel@tonic-gate reloc->r_name = name;
3977c478bd9Sstevel@tonic-gate if (type == M_R_JMP_SLOT)
3987c478bd9Sstevel@tonic-gate (*func)++;
3997c478bd9Sstevel@tonic-gate else
4007c478bd9Sstevel@tonic-gate (*null)++;
4017c478bd9Sstevel@tonic-gate } else {
4027c478bd9Sstevel@tonic-gate /*
4037c478bd9Sstevel@tonic-gate * Do not apply any unrequired relocations.
4047c478bd9Sstevel@tonic-gate */
4057c478bd9Sstevel@tonic-gate reloc->r_flags = FLG_R_INC;
4067c478bd9Sstevel@tonic-gate reloc->r_value = addr;
4077c478bd9Sstevel@tonic-gate if (type == M_R_JMP_SLOT)
4087c478bd9Sstevel@tonic-gate (*func)++;
4097c478bd9Sstevel@tonic-gate else
4107c478bd9Sstevel@tonic-gate (*data)++;
4117c478bd9Sstevel@tonic-gate }
4127c478bd9Sstevel@tonic-gate }
4137c478bd9Sstevel@tonic-gate }
4147c478bd9Sstevel@tonic-gate return (0);
4157c478bd9Sstevel@tonic-gate }
4167c478bd9Sstevel@tonic-gate
4177c478bd9Sstevel@tonic-gate
4187c478bd9Sstevel@tonic-gate /*
4197c478bd9Sstevel@tonic-gate * Perform any relocation updates to the new image using the information from
4207c478bd9Sstevel@tonic-gate * the `Reloc' structure constructed during count_reloc().
4217c478bd9Sstevel@tonic-gate */
4227c478bd9Sstevel@tonic-gate void
update_reloc(Cache * ocache,Cache * icache,Cache * _icache,const char * name,Rt_map * lmp,Rel ** null,Rel ** data,Rel ** func)4237c478bd9Sstevel@tonic-gate update_reloc(Cache *ocache, Cache *icache, Cache *_icache, const char *name,
4247c478bd9Sstevel@tonic-gate Rt_map *lmp, Rel **null, Rel **data, Rel **func)
4257c478bd9Sstevel@tonic-gate {
4267c478bd9Sstevel@tonic-gate Shdr *shdr;
4277c478bd9Sstevel@tonic-gate Rel *rel;
4287c478bd9Sstevel@tonic-gate Reloc *reloc;
4297c478bd9Sstevel@tonic-gate Xword ent, cnt, _cnt;
4307c478bd9Sstevel@tonic-gate Cache *orcache, *ircache = 0;
4317c478bd9Sstevel@tonic-gate Half ndx;
4327c478bd9Sstevel@tonic-gate
4337c478bd9Sstevel@tonic-gate /*
4347c478bd9Sstevel@tonic-gate * Set up to read the output relocation table.
4357c478bd9Sstevel@tonic-gate */
4367c478bd9Sstevel@tonic-gate shdr = _icache->c_shdr;
4377c478bd9Sstevel@tonic-gate rel = (Rel *)_icache->c_data->d_buf;
4387c478bd9Sstevel@tonic-gate reloc = (Reloc *)_icache->c_info;
4397c478bd9Sstevel@tonic-gate ent = shdr->sh_entsize;
4407c478bd9Sstevel@tonic-gate cnt = shdr->sh_size / ent;
4417c478bd9Sstevel@tonic-gate
4427c478bd9Sstevel@tonic-gate /*
4437c478bd9Sstevel@tonic-gate * Loop through the relocation table.
4447c478bd9Sstevel@tonic-gate */
4457c478bd9Sstevel@tonic-gate for (_cnt = 0; _cnt < cnt; _cnt++, reloc++,
4467c478bd9Sstevel@tonic-gate rel = (Rel *)((uintptr_t)rel + ent)) {
4477c478bd9Sstevel@tonic-gate uchar_t *iaddr, *oaddr;
4487c478bd9Sstevel@tonic-gate /* LINTED */
449ba2be530Sab196087 uchar_t type = (uchar_t)ELF_R_TYPE(rel->r_info, M_MACH);
4507c478bd9Sstevel@tonic-gate Addr off, bgn, end;
4517c478bd9Sstevel@tonic-gate
4527c478bd9Sstevel@tonic-gate /*
4537c478bd9Sstevel@tonic-gate * Ignore null relocations (these may have been created from a
4547c478bd9Sstevel@tonic-gate * previous dldump() of this image).
4557c478bd9Sstevel@tonic-gate */
4567c478bd9Sstevel@tonic-gate if (type == M_R_NONE) {
4577c478bd9Sstevel@tonic-gate (*null)++;
4587c478bd9Sstevel@tonic-gate continue;
4597c478bd9Sstevel@tonic-gate }
4607c478bd9Sstevel@tonic-gate
4617c478bd9Sstevel@tonic-gate /*
4627c478bd9Sstevel@tonic-gate * Determine the section being relocated if we haven't already
4637c478bd9Sstevel@tonic-gate * done so (we may have had to skip over some null relocation to
4647c478bd9Sstevel@tonic-gate * get to the first valid offset). The System V ABI states that
4657c478bd9Sstevel@tonic-gate * a relocation sections sh_info field indicates the section
4667c478bd9Sstevel@tonic-gate * that must be relocated. However, on Intel it seems that the
4677c478bd9Sstevel@tonic-gate * .rel.plt sh_info records the section index of the .plt, when
4687c478bd9Sstevel@tonic-gate * in fact it's the .got that gets relocated. In addition we
4697c478bd9Sstevel@tonic-gate * now create combined relocation sections with -zcomreloc. To
4707c478bd9Sstevel@tonic-gate * generically be able to cope with these anomalies, search for
4717c478bd9Sstevel@tonic-gate * the appropriate section to be relocated by comparing the
4727c478bd9Sstevel@tonic-gate * offset of the first relocation record against each sections
4737c478bd9Sstevel@tonic-gate * offset and size.
4747c478bd9Sstevel@tonic-gate */
47560758829Srie /* BEGIN CSTYLED */
4767c478bd9Sstevel@tonic-gate #if !defined(__lint)
4777c478bd9Sstevel@tonic-gate if ((ircache == (Cache *)0) || (rel->r_offset < bgn) ||
4787c478bd9Sstevel@tonic-gate (rel->r_offset > end)) {
4797c478bd9Sstevel@tonic-gate #else
4807c478bd9Sstevel@tonic-gate /*
4817c478bd9Sstevel@tonic-gate * lint sees `bgn' and `end' as potentially referenced
4827c478bd9Sstevel@tonic-gate * before being set.
4837c478bd9Sstevel@tonic-gate */
4847c478bd9Sstevel@tonic-gate if (ircache == (Cache *)0) {
4857c478bd9Sstevel@tonic-gate #endif
4867c478bd9Sstevel@tonic-gate _icache = icache;
4877c478bd9Sstevel@tonic-gate _icache++;
4887c478bd9Sstevel@tonic-gate
4897c478bd9Sstevel@tonic-gate for (ndx = 1; _icache->c_flags != FLG_C_END; ndx++,
4907c478bd9Sstevel@tonic-gate _icache++) {
4917c478bd9Sstevel@tonic-gate
4927c478bd9Sstevel@tonic-gate shdr = _icache->c_shdr;
4937c478bd9Sstevel@tonic-gate bgn = shdr->sh_addr;
4947c478bd9Sstevel@tonic-gate end = bgn + shdr->sh_size;
4957c478bd9Sstevel@tonic-gate
4967c478bd9Sstevel@tonic-gate if ((rel->r_offset >= bgn) &&
4977c478bd9Sstevel@tonic-gate (rel->r_offset <= end))
4987c478bd9Sstevel@tonic-gate break;
4997c478bd9Sstevel@tonic-gate }
5007c478bd9Sstevel@tonic-gate ircache = &icache[ndx];
5017c478bd9Sstevel@tonic-gate orcache = &ocache[ndx];
5027c478bd9Sstevel@tonic-gate }
50360758829Srie /* END CSTYLED */
5047c478bd9Sstevel@tonic-gate
5057c478bd9Sstevel@tonic-gate /*
5067c478bd9Sstevel@tonic-gate * Determine the relocation location of both the input and
5077c478bd9Sstevel@tonic-gate * output data. Take into account that an input section may be
5087c478bd9Sstevel@tonic-gate * NOBITS (ppc .plt for example).
5097c478bd9Sstevel@tonic-gate */
5107c478bd9Sstevel@tonic-gate off = rel->r_offset - ircache->c_shdr->sh_addr;
5117c478bd9Sstevel@tonic-gate if (ircache->c_data->d_buf)
5127c478bd9Sstevel@tonic-gate iaddr = (uchar_t *)ircache->c_data->d_buf + off;
5137c478bd9Sstevel@tonic-gate else
5147c478bd9Sstevel@tonic-gate iaddr = 0;
5157c478bd9Sstevel@tonic-gate oaddr = (uchar_t *)orcache->c_data->d_buf + off;
5167c478bd9Sstevel@tonic-gate
5177c478bd9Sstevel@tonic-gate /*
5187c478bd9Sstevel@tonic-gate * Apply the relocation to the new output image. Any base
5197c478bd9Sstevel@tonic-gate * address, or symbol value, will have been saved in the reloc
5207c478bd9Sstevel@tonic-gate * structure during count_reloc().
5217c478bd9Sstevel@tonic-gate */
5227c478bd9Sstevel@tonic-gate if (reloc->r_flags & FLG_R_APPLY)
5237c478bd9Sstevel@tonic-gate apply_reloc(rel, reloc, name, oaddr, lmp);
5247c478bd9Sstevel@tonic-gate
5257c478bd9Sstevel@tonic-gate /*
5267c478bd9Sstevel@tonic-gate * Undo any relocation that might already been applied to the
5277c478bd9Sstevel@tonic-gate * memory image by the runtime linker. Using the original
5287c478bd9Sstevel@tonic-gate * file, determine the relocation offset original value and
5297c478bd9Sstevel@tonic-gate * restore the new image to that value.
5307c478bd9Sstevel@tonic-gate */
5317c478bd9Sstevel@tonic-gate if ((reloc->r_flags & FLG_R_UNDO) &&
5327c478bd9Sstevel@tonic-gate (FLAGS(lmp) & FLG_RT_RELOCED))
5337c478bd9Sstevel@tonic-gate undo_reloc(rel, oaddr, iaddr, reloc);
5347c478bd9Sstevel@tonic-gate
5357c478bd9Sstevel@tonic-gate /*
5367c478bd9Sstevel@tonic-gate * If a relocation has been applied then the relocation record
5377c478bd9Sstevel@tonic-gate * should be cleared so that the relocation isn't applied again
5387c478bd9Sstevel@tonic-gate * when the new image is used.
5397c478bd9Sstevel@tonic-gate */
5407c478bd9Sstevel@tonic-gate if (reloc->r_flags & FLG_R_CLR) {
5417c478bd9Sstevel@tonic-gate if (type == M_R_JMP_SLOT) {
5427c478bd9Sstevel@tonic-gate clear_reloc(*func);
5437c478bd9Sstevel@tonic-gate *func = (Rel *)((uintptr_t)*func + ent);
5447c478bd9Sstevel@tonic-gate } else {
5457c478bd9Sstevel@tonic-gate clear_reloc(*null);
5467c478bd9Sstevel@tonic-gate *null = (Rel *)((uintptr_t)*null + ent);
5477c478bd9Sstevel@tonic-gate }
5487c478bd9Sstevel@tonic-gate }
5497c478bd9Sstevel@tonic-gate
5507c478bd9Sstevel@tonic-gate /*
5517c478bd9Sstevel@tonic-gate * If a relocation isn't applied, update the relocation record
5527c478bd9Sstevel@tonic-gate * to take into account the new address of the image.
5537c478bd9Sstevel@tonic-gate */
5547c478bd9Sstevel@tonic-gate if (reloc->r_flags & FLG_R_INC) {
5557c478bd9Sstevel@tonic-gate if (type == M_R_JMP_SLOT) {
5567c478bd9Sstevel@tonic-gate inc_reloc(*func, rel, reloc, oaddr, iaddr);
5577c478bd9Sstevel@tonic-gate *func = (Rel *)((uintptr_t)*func + ent);
5587c478bd9Sstevel@tonic-gate } else {
5597c478bd9Sstevel@tonic-gate inc_reloc(*data, rel, reloc, oaddr, iaddr);
5607c478bd9Sstevel@tonic-gate *data = (Rel *)((uintptr_t)*data + ent);
5617c478bd9Sstevel@tonic-gate }
5627c478bd9Sstevel@tonic-gate }
5637c478bd9Sstevel@tonic-gate }
5647c478bd9Sstevel@tonic-gate }
565