10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
52850Srie * Common Development and Distribution License (the "License").
62850Srie * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
212850Srie
220Sstevel@tonic-gate /*
23*11827SRod.Evans@Sun.COM * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
240Sstevel@tonic-gate * Use is subject to license terms.
250Sstevel@tonic-gate */
260Sstevel@tonic-gate
270Sstevel@tonic-gate #include <libelf.h>
280Sstevel@tonic-gate #include <dlfcn.h>
290Sstevel@tonic-gate #include "machdep.h"
300Sstevel@tonic-gate #include "reloc.h"
310Sstevel@tonic-gate #include "msg.h"
320Sstevel@tonic-gate #include "_librtld.h"
332850Srie #include "alist.h"
340Sstevel@tonic-gate
350Sstevel@tonic-gate static const char *unknown = 0; /* Stash MSG_INTL(MSG_STR_UNKNOWN) */
360Sstevel@tonic-gate
370Sstevel@tonic-gate /*
380Sstevel@tonic-gate * Process all relocation records. A new `Reloc' structure is allocated to
390Sstevel@tonic-gate * cache the processing decisions deduced, and these will be applied during
400Sstevel@tonic-gate * update_reloc().
410Sstevel@tonic-gate * A count of the number of null relocations (i.e., relocations that will be
420Sstevel@tonic-gate * fixed and whoes records will be nulled out), data and function relocations
430Sstevel@tonic-gate * is maintained. This allows the relocation records themselves to be
440Sstevel@tonic-gate * rearranged (localized) later if necessary. Note that the number of function
450Sstevel@tonic-gate * relocations, although coounted, shouldn't differ from the original file,
460Sstevel@tonic-gate * the index of a .plt must be maintained to the index of its relocation record
470Sstevel@tonic-gate * within the associated relocation section.
480Sstevel@tonic-gate *
490Sstevel@tonic-gate * The intention behind this file is to maintain as much relocation logic as
500Sstevel@tonic-gate * possible in a generic form.
510Sstevel@tonic-gate */
520Sstevel@tonic-gate int
count_reloc(Cache * cache,Cache * _cache,Rt_map * lmp,int flags,Addr addr,Xword * null,Xword * data,Xword * func,Alist * nodirect)530Sstevel@tonic-gate count_reloc(Cache *cache, Cache *_cache, Rt_map *lmp, int flags, Addr addr,
542850Srie Xword *null, Xword *data, Xword *func, Alist *nodirect)
550Sstevel@tonic-gate {
560Sstevel@tonic-gate Rel *rel;
570Sstevel@tonic-gate Reloc *reloc;
580Sstevel@tonic-gate Shdr *shdr;
590Sstevel@tonic-gate Xword ent, cnt, _cnt;
600Sstevel@tonic-gate Sym *syms;
610Sstevel@tonic-gate const char *strs;
620Sstevel@tonic-gate Cache *__cache;
630Sstevel@tonic-gate Xword pltndx = 0;
640Sstevel@tonic-gate
650Sstevel@tonic-gate /*
660Sstevel@tonic-gate * Determine the number of relocation entries we'll be dealing with.
670Sstevel@tonic-gate */
680Sstevel@tonic-gate shdr = _cache->c_shdr;
690Sstevel@tonic-gate rel = (Rel *)_cache->c_data->d_buf;
700Sstevel@tonic-gate ent = shdr->sh_entsize;
710Sstevel@tonic-gate cnt = shdr->sh_size / ent;
720Sstevel@tonic-gate
730Sstevel@tonic-gate /*
740Sstevel@tonic-gate * Allocate a relocation structure for this relocation section.
750Sstevel@tonic-gate */
760Sstevel@tonic-gate if ((reloc = calloc(cnt, sizeof (Reloc))) == 0)
770Sstevel@tonic-gate return (1);
780Sstevel@tonic-gate _cache->c_info = (void *)reloc;
790Sstevel@tonic-gate
800Sstevel@tonic-gate /*
810Sstevel@tonic-gate * Determine the relocations associated symbol and string table.
820Sstevel@tonic-gate */
830Sstevel@tonic-gate __cache = &cache[shdr->sh_link];
840Sstevel@tonic-gate syms = (Sym *)__cache->c_data->d_buf;
850Sstevel@tonic-gate shdr = __cache->c_shdr;
860Sstevel@tonic-gate __cache = &cache[shdr->sh_link];
870Sstevel@tonic-gate strs = (const char *)__cache->c_data->d_buf;
880Sstevel@tonic-gate
890Sstevel@tonic-gate /*
900Sstevel@tonic-gate * Loop through the relocation table.
910Sstevel@tonic-gate */
920Sstevel@tonic-gate for (_cnt = 0; _cnt < cnt; _cnt++, reloc++,
930Sstevel@tonic-gate rel = (Rel *)((uintptr_t)rel + ent)) {
940Sstevel@tonic-gate const char *name;
950Sstevel@tonic-gate /* LINTED */
966206Sab196087 uchar_t type = (uchar_t)ELF_R_TYPE(rel->r_info, M_MACH);
970Sstevel@tonic-gate uchar_t bind;
980Sstevel@tonic-gate ulong_t offset = rel->r_offset + addr;
990Sstevel@tonic-gate Rt_map *_lmp;
1000Sstevel@tonic-gate int _bound, _weak;
1010Sstevel@tonic-gate ulong_t rsymndx = ELF_R_SYM(rel->r_info);
1020Sstevel@tonic-gate Slookup sl;
103*11827SRod.Evans@Sun.COM Sresult sr;
1040Sstevel@tonic-gate uint_t binfo;
1050Sstevel@tonic-gate Sym *_sym, *sym = (syms + rsymndx);
1060Sstevel@tonic-gate
1070Sstevel@tonic-gate if (type == M_R_JMP_SLOT)
1080Sstevel@tonic-gate reloc->r_pltndx = ++pltndx;
1090Sstevel@tonic-gate
1100Sstevel@tonic-gate /*
1110Sstevel@tonic-gate * Analyze the case where no relocations are to be applied.
1120Sstevel@tonic-gate */
1130Sstevel@tonic-gate if ((flags & RTLD_REL_ALL) == 0) {
1140Sstevel@tonic-gate /*
1150Sstevel@tonic-gate * Don't apply any relocations to the new image but
1160Sstevel@tonic-gate * insure their offsets are incremented to reflect any
1170Sstevel@tonic-gate * new fixed address.
1180Sstevel@tonic-gate */
1190Sstevel@tonic-gate reloc->r_flags = FLG_R_INC;
1200Sstevel@tonic-gate
1210Sstevel@tonic-gate /*
1220Sstevel@tonic-gate * Undo any relocations that might have already been
1230Sstevel@tonic-gate * applied to the memory image.
1240Sstevel@tonic-gate */
1250Sstevel@tonic-gate if (flags & RTLD_MEMORY) {
1260Sstevel@tonic-gate reloc->r_flags |= FLG_R_UNDO;
1270Sstevel@tonic-gate
1280Sstevel@tonic-gate /*
1290Sstevel@tonic-gate * If a copy relocation is involved we'll need
1300Sstevel@tonic-gate * to know the size of the copy.
1310Sstevel@tonic-gate */
1320Sstevel@tonic-gate if (type == M_R_COPY)
1330Sstevel@tonic-gate reloc->r_size = sym->st_size;
1340Sstevel@tonic-gate else
1350Sstevel@tonic-gate reloc->r_size = 0;
1360Sstevel@tonic-gate }
1370Sstevel@tonic-gate
1380Sstevel@tonic-gate /*
1390Sstevel@tonic-gate * Save the objects new address.
1400Sstevel@tonic-gate */
1410Sstevel@tonic-gate reloc->r_value = addr;
1420Sstevel@tonic-gate
1430Sstevel@tonic-gate if (type == M_R_JMP_SLOT)
1440Sstevel@tonic-gate (*func)++;
1450Sstevel@tonic-gate else
1460Sstevel@tonic-gate (*data)++;
1470Sstevel@tonic-gate continue;
1480Sstevel@tonic-gate }
1490Sstevel@tonic-gate
1500Sstevel@tonic-gate /*
1510Sstevel@tonic-gate * Determine the symbol binding of the relocation. Don't assume
1520Sstevel@tonic-gate * that relative relocations are simply M_R_RELATIVE. Although
1530Sstevel@tonic-gate * a pic generated shared object can normally be viewed as
1540Sstevel@tonic-gate * having relative and non-relative relocations, a non-pic
1550Sstevel@tonic-gate * shared object will contain a number of relocations against
1560Sstevel@tonic-gate * local symbols (normally sections). If a relocation is
1570Sstevel@tonic-gate * against a local symbol it qualifies as a relative relocation.
1580Sstevel@tonic-gate */
1590Sstevel@tonic-gate if ((type == M_R_RELATIVE) || (type == M_R_NONE) ||
1600Sstevel@tonic-gate (ELF_ST_BIND(sym->st_info) == STB_LOCAL))
1610Sstevel@tonic-gate bind = STB_LOCAL;
1620Sstevel@tonic-gate else
1630Sstevel@tonic-gate bind = STB_GLOBAL;
1640Sstevel@tonic-gate
1650Sstevel@tonic-gate /*
1660Sstevel@tonic-gate * Analyze the case where only relative relocations are to be
1670Sstevel@tonic-gate * applied.
1680Sstevel@tonic-gate */
1690Sstevel@tonic-gate if ((flags & RTLD_REL_ALL) == RTLD_REL_RELATIVE) {
1700Sstevel@tonic-gate if (flags & RTLD_MEMORY) {
1710Sstevel@tonic-gate if (bind == STB_LOCAL) {
1720Sstevel@tonic-gate /*
1730Sstevel@tonic-gate * Save the relative relocations from
1740Sstevel@tonic-gate * the memory image. The data itself
1750Sstevel@tonic-gate * might already have been relocated,
1760Sstevel@tonic-gate * thus clear the relocation record so
1770Sstevel@tonic-gate * that it will not be performed again.
1780Sstevel@tonic-gate */
1790Sstevel@tonic-gate reloc->r_flags = FLG_R_CLR;
1800Sstevel@tonic-gate (*null)++;
1810Sstevel@tonic-gate } else {
1820Sstevel@tonic-gate /*
1830Sstevel@tonic-gate * Any non-relative relocation must be
1840Sstevel@tonic-gate * undone, and the relocation records
1850Sstevel@tonic-gate * offset updated to any new fixed
1860Sstevel@tonic-gate * address.
1870Sstevel@tonic-gate */
1880Sstevel@tonic-gate reloc->r_flags =
1890Sstevel@tonic-gate (FLG_R_UNDO | FLG_R_INC);
1900Sstevel@tonic-gate reloc->r_value = addr;
1910Sstevel@tonic-gate if (type == M_R_JMP_SLOT)
1920Sstevel@tonic-gate (*func)++;
1930Sstevel@tonic-gate else
1940Sstevel@tonic-gate (*data)++;
1950Sstevel@tonic-gate }
1960Sstevel@tonic-gate } else {
1970Sstevel@tonic-gate if (bind == STB_LOCAL) {
1980Sstevel@tonic-gate /*
1990Sstevel@tonic-gate * Apply relative relocation to the
2000Sstevel@tonic-gate * file image. Clear the relocation
2010Sstevel@tonic-gate * record so that it will not be
2020Sstevel@tonic-gate * performed again.
2030Sstevel@tonic-gate */
2040Sstevel@tonic-gate reloc->r_flags =
2050Sstevel@tonic-gate (FLG_R_APPLY | FLG_R_CLR);
2060Sstevel@tonic-gate reloc->r_value = addr;
2070Sstevel@tonic-gate if (IS_PC_RELATIVE(type))
2080Sstevel@tonic-gate reloc->r_value -= offset;
2090Sstevel@tonic-gate
2100Sstevel@tonic-gate if (unknown == 0)
2115220Srie unknown =
2125220Srie MSG_INTL(MSG_STR_UNKNOWN);
2130Sstevel@tonic-gate reloc->r_name = unknown;
2140Sstevel@tonic-gate (*null)++;
2150Sstevel@tonic-gate } else {
2160Sstevel@tonic-gate /*
2170Sstevel@tonic-gate * Any non-relative relocation should be
2180Sstevel@tonic-gate * left alone, but its offset should be
2190Sstevel@tonic-gate * updated to any new fixed address.
2200Sstevel@tonic-gate */
2210Sstevel@tonic-gate reloc->r_flags = FLG_R_INC;
2220Sstevel@tonic-gate reloc->r_value = addr;
2230Sstevel@tonic-gate if (type == M_R_JMP_SLOT)
2240Sstevel@tonic-gate (*func)++;
2250Sstevel@tonic-gate else
2260Sstevel@tonic-gate (*data)++;
2270Sstevel@tonic-gate }
2280Sstevel@tonic-gate }
2290Sstevel@tonic-gate continue;
2300Sstevel@tonic-gate }
2310Sstevel@tonic-gate
2320Sstevel@tonic-gate /*
2330Sstevel@tonic-gate * Analyze the case where more than just relative relocations
2340Sstevel@tonic-gate * are to be applied.
2350Sstevel@tonic-gate */
2360Sstevel@tonic-gate if (bind == STB_LOCAL) {
2370Sstevel@tonic-gate if (flags & RTLD_MEMORY) {
2380Sstevel@tonic-gate /*
2390Sstevel@tonic-gate * Save the relative relocations from the memory
2400Sstevel@tonic-gate * image. The data itself has already been
2410Sstevel@tonic-gate * relocated, thus clear the relocation record
2420Sstevel@tonic-gate * so that it will not be performed again.
2430Sstevel@tonic-gate */
2440Sstevel@tonic-gate reloc->r_flags = FLG_R_CLR;
2450Sstevel@tonic-gate } else {
2460Sstevel@tonic-gate /*
2470Sstevel@tonic-gate * Apply relative relocation to the file image.
2480Sstevel@tonic-gate * Clear the relocation record so that it will
2490Sstevel@tonic-gate * not be performed again.
2500Sstevel@tonic-gate */
2510Sstevel@tonic-gate reloc->r_flags = (FLG_R_APPLY | FLG_R_CLR);
2520Sstevel@tonic-gate reloc->r_value = addr;
2530Sstevel@tonic-gate if (IS_PC_RELATIVE(type))
2540Sstevel@tonic-gate reloc->r_value -= offset;
2550Sstevel@tonic-gate
2560Sstevel@tonic-gate if (unknown == 0)
2570Sstevel@tonic-gate unknown = MSG_INTL(MSG_STR_UNKNOWN);
2580Sstevel@tonic-gate reloc->r_name = unknown;
2590Sstevel@tonic-gate }
2600Sstevel@tonic-gate (*null)++;
2610Sstevel@tonic-gate continue;
2620Sstevel@tonic-gate }
2630Sstevel@tonic-gate
2640Sstevel@tonic-gate /*
2650Sstevel@tonic-gate * At this point we're dealing with a non-relative relocation
2660Sstevel@tonic-gate * that requires the symbol definition.
2670Sstevel@tonic-gate */
2680Sstevel@tonic-gate name = strs + sym->st_name;
2690Sstevel@tonic-gate
2700Sstevel@tonic-gate /*
2710Sstevel@tonic-gate * Find the symbol. As the object being investigated is already
2720Sstevel@tonic-gate * a part of this process, the symbol lookup will likely
2730Sstevel@tonic-gate * succeed. However, because of lazy binding, there is still
2740Sstevel@tonic-gate * the possibility of a dangling .plt relocation. dldump()
2750Sstevel@tonic-gate * users might be encouraged to set LD_FLAGS=loadavail (crle(1)
2760Sstevel@tonic-gate * does this for them).
2775950Srie *
278*11827SRod.Evans@Sun.COM * Initialize the symbol lookup, and symbol result, data
279*11827SRod.Evans@Sun.COM * structures.
2800Sstevel@tonic-gate */
2815950Srie SLOOKUP_INIT(sl, name, lmp, LIST(lmp)->lm_head, ld_entry_cnt,
2825950Srie 0, rsymndx, sym, type, LKUP_STDRELOC);
283*11827SRod.Evans@Sun.COM SRESULT_INIT(sr, name);
2840Sstevel@tonic-gate
2850Sstevel@tonic-gate _bound = _weak = 0;
2860Sstevel@tonic-gate _sym = sym;
287*11827SRod.Evans@Sun.COM if (lookup_sym(&sl, &sr, &binfo, NULL)) {
288*11827SRod.Evans@Sun.COM _lmp = sr.sr_dmap;
289*11827SRod.Evans@Sun.COM sym = sr.sr_sym;
290*11827SRod.Evans@Sun.COM
2910Sstevel@tonic-gate /*
2920Sstevel@tonic-gate * Determine from the various relocation requirements
2930Sstevel@tonic-gate * whether this binding is appropriate. If we're called
2940Sstevel@tonic-gate * from crle(1), RTLD_CONFSET is set, then only inspect
2950Sstevel@tonic-gate * objects selected from the configuration file
2960Sstevel@tonic-gate * (FL1_RT_CONFSET was set during load()).
2970Sstevel@tonic-gate */
2980Sstevel@tonic-gate if (!(flags & RTLD_CONFSET) ||
2990Sstevel@tonic-gate (FLAGS1(_lmp) & FL1_RT_CONFSET)) {
3000Sstevel@tonic-gate if (((flags & RTLD_REL_ALL) == RTLD_REL_ALL) ||
3010Sstevel@tonic-gate ((flags & RTLD_REL_EXEC) &&
3020Sstevel@tonic-gate (FLAGS(_lmp) & FLG_RT_ISMAIN)) ||
3030Sstevel@tonic-gate ((flags & RTLD_REL_DEPENDS) &&
3040Sstevel@tonic-gate (!(FLAGS(_lmp) & FLG_RT_ISMAIN))) ||
3050Sstevel@tonic-gate ((flags & RTLD_REL_PRELOAD) &&
3060Sstevel@tonic-gate (FLAGS(_lmp) & FLG_RT_PRELOAD)) ||
3072850Srie ((flags & RTLD_REL_SELF) &&
3082850Srie (lmp == _lmp))) {
3095892Sab196087 Aliste idx;
3102850Srie Word *ndx;
3112850Srie
3120Sstevel@tonic-gate _bound = 1;
3132850Srie
3142850Srie /*
3152850Srie * If this symbol is explicitly defined
3162850Srie * as nodirect, don't allow any local
3172850Srie * binding.
3182850Srie */
3195892Sab196087 for (ALIST_TRAVERSE(nodirect, idx,
3202850Srie ndx)) {
3212850Srie if (*ndx == rsymndx) {
3222850Srie _bound = 0;
3232850Srie break;
3242850Srie }
3252850Srie }
3262850Srie }
3270Sstevel@tonic-gate }
3280Sstevel@tonic-gate } else {
3290Sstevel@tonic-gate /*
3300Sstevel@tonic-gate * If this is a weak reference and we've been asked to
3310Sstevel@tonic-gate * bind unresolved weak references consider ourself
3320Sstevel@tonic-gate * bound. This category is typically set by clre(1) for
3330Sstevel@tonic-gate * an application cache.
3340Sstevel@tonic-gate */
3350Sstevel@tonic-gate if ((ELF_ST_BIND(_sym->st_info) == STB_WEAK) &&
3360Sstevel@tonic-gate (_sym->st_shndx == SHN_UNDEF) &&
3370Sstevel@tonic-gate (flags & RTLD_REL_WEAK))
3380Sstevel@tonic-gate _bound = _weak = 1;
3390Sstevel@tonic-gate }
3400Sstevel@tonic-gate
3410Sstevel@tonic-gate if (flags & RTLD_MEMORY) {
3420Sstevel@tonic-gate if (_bound) {
3430Sstevel@tonic-gate /*
3440Sstevel@tonic-gate * We know that all data relocations will have
3450Sstevel@tonic-gate * been performed at process startup thus clear
3460Sstevel@tonic-gate * the relocation record so that it will not be
3470Sstevel@tonic-gate * performed again. However, we don't know what
3480Sstevel@tonic-gate * function relocations have been performed
3490Sstevel@tonic-gate * because of lazy binding - regardless, we can
3500Sstevel@tonic-gate * leave all the function relocation records in
3510Sstevel@tonic-gate * place, because if the function has already
3520Sstevel@tonic-gate * been bound the record won't be referenced
3530Sstevel@tonic-gate * anyway. In the case of using LD_BIND_NOW,
3540Sstevel@tonic-gate * a function may be bound twice - so what.
3550Sstevel@tonic-gate */
3560Sstevel@tonic-gate if (type == M_R_JMP_SLOT) {
3570Sstevel@tonic-gate reloc->r_flags = FLG_R_INC;
3580Sstevel@tonic-gate (*func)++;
3590Sstevel@tonic-gate } else {
3600Sstevel@tonic-gate if (type != M_R_COPY)
3610Sstevel@tonic-gate reloc->r_flags = FLG_R_CLR;
3620Sstevel@tonic-gate (*null)++;
3630Sstevel@tonic-gate }
3640Sstevel@tonic-gate } else {
3650Sstevel@tonic-gate /*
3660Sstevel@tonic-gate * Clear any unrequired relocation.
3670Sstevel@tonic-gate */
3680Sstevel@tonic-gate reloc->r_flags = FLG_R_UNDO | FLG_R_INC;
3690Sstevel@tonic-gate reloc->r_value = addr;
3700Sstevel@tonic-gate if (type == M_R_JMP_SLOT)
3710Sstevel@tonic-gate (*func)++;
3720Sstevel@tonic-gate else
3730Sstevel@tonic-gate (*data)++;
3740Sstevel@tonic-gate }
3750Sstevel@tonic-gate } else {
3760Sstevel@tonic-gate if (_bound) {
3770Sstevel@tonic-gate /*
3780Sstevel@tonic-gate * Apply the global relocation to the file
3790Sstevel@tonic-gate * image. Clear the relocation record so that
3800Sstevel@tonic-gate * it will not be performed again.
3810Sstevel@tonic-gate */
3820Sstevel@tonic-gate if (_weak) {
3830Sstevel@tonic-gate reloc->r_value = 0;
3840Sstevel@tonic-gate reloc->r_size = 0;
3850Sstevel@tonic-gate } else {
3860Sstevel@tonic-gate reloc->r_value = sym->st_value;
3870Sstevel@tonic-gate if (IS_PC_RELATIVE(type))
3880Sstevel@tonic-gate reloc->r_value -= offset;
3890Sstevel@tonic-gate if ((!(FLAGS(_lmp) & FLG_RT_FIXED)) &&
3900Sstevel@tonic-gate (sym->st_shndx != SHN_ABS))
3910Sstevel@tonic-gate reloc->r_value += ADDR(_lmp);
3920Sstevel@tonic-gate reloc->r_size = sym->st_size;
3930Sstevel@tonic-gate }
3940Sstevel@tonic-gate
3950Sstevel@tonic-gate reloc->r_flags = FLG_R_APPLY | FLG_R_CLR;
3960Sstevel@tonic-gate reloc->r_name = name;
3970Sstevel@tonic-gate if (type == M_R_JMP_SLOT)
3980Sstevel@tonic-gate (*func)++;
3990Sstevel@tonic-gate else
4000Sstevel@tonic-gate (*null)++;
4010Sstevel@tonic-gate } else {
4020Sstevel@tonic-gate /*
4030Sstevel@tonic-gate * Do not apply any unrequired relocations.
4040Sstevel@tonic-gate */
4050Sstevel@tonic-gate reloc->r_flags = FLG_R_INC;
4060Sstevel@tonic-gate reloc->r_value = addr;
4070Sstevel@tonic-gate if (type == M_R_JMP_SLOT)
4080Sstevel@tonic-gate (*func)++;
4090Sstevel@tonic-gate else
4100Sstevel@tonic-gate (*data)++;
4110Sstevel@tonic-gate }
4120Sstevel@tonic-gate }
4130Sstevel@tonic-gate }
4140Sstevel@tonic-gate return (0);
4150Sstevel@tonic-gate }
4160Sstevel@tonic-gate
4170Sstevel@tonic-gate
4180Sstevel@tonic-gate /*
4190Sstevel@tonic-gate * Perform any relocation updates to the new image using the information from
4200Sstevel@tonic-gate * the `Reloc' structure constructed during count_reloc().
4210Sstevel@tonic-gate */
4220Sstevel@tonic-gate void
update_reloc(Cache * ocache,Cache * icache,Cache * _icache,const char * name,Rt_map * lmp,Rel ** null,Rel ** data,Rel ** func)4230Sstevel@tonic-gate update_reloc(Cache *ocache, Cache *icache, Cache *_icache, const char *name,
4240Sstevel@tonic-gate Rt_map *lmp, Rel **null, Rel **data, Rel **func)
4250Sstevel@tonic-gate {
4260Sstevel@tonic-gate Shdr *shdr;
4270Sstevel@tonic-gate Rel *rel;
4280Sstevel@tonic-gate Reloc *reloc;
4290Sstevel@tonic-gate Xword ent, cnt, _cnt;
4300Sstevel@tonic-gate Cache *orcache, *ircache = 0;
4310Sstevel@tonic-gate Half ndx;
4320Sstevel@tonic-gate
4330Sstevel@tonic-gate /*
4340Sstevel@tonic-gate * Set up to read the output relocation table.
4350Sstevel@tonic-gate */
4360Sstevel@tonic-gate shdr = _icache->c_shdr;
4370Sstevel@tonic-gate rel = (Rel *)_icache->c_data->d_buf;
4380Sstevel@tonic-gate reloc = (Reloc *)_icache->c_info;
4390Sstevel@tonic-gate ent = shdr->sh_entsize;
4400Sstevel@tonic-gate cnt = shdr->sh_size / ent;
4410Sstevel@tonic-gate
4420Sstevel@tonic-gate /*
4430Sstevel@tonic-gate * Loop through the relocation table.
4440Sstevel@tonic-gate */
4450Sstevel@tonic-gate for (_cnt = 0; _cnt < cnt; _cnt++, reloc++,
4460Sstevel@tonic-gate rel = (Rel *)((uintptr_t)rel + ent)) {
4470Sstevel@tonic-gate uchar_t *iaddr, *oaddr;
4480Sstevel@tonic-gate /* LINTED */
4496206Sab196087 uchar_t type = (uchar_t)ELF_R_TYPE(rel->r_info, M_MACH);
4500Sstevel@tonic-gate Addr off, bgn, end;
4510Sstevel@tonic-gate
4520Sstevel@tonic-gate /*
4530Sstevel@tonic-gate * Ignore null relocations (these may have been created from a
4540Sstevel@tonic-gate * previous dldump() of this image).
4550Sstevel@tonic-gate */
4560Sstevel@tonic-gate if (type == M_R_NONE) {
4570Sstevel@tonic-gate (*null)++;
4580Sstevel@tonic-gate continue;
4590Sstevel@tonic-gate }
4600Sstevel@tonic-gate
4610Sstevel@tonic-gate /*
4620Sstevel@tonic-gate * Determine the section being relocated if we haven't already
4630Sstevel@tonic-gate * done so (we may have had to skip over some null relocation to
4640Sstevel@tonic-gate * get to the first valid offset). The System V ABI states that
4650Sstevel@tonic-gate * a relocation sections sh_info field indicates the section
4660Sstevel@tonic-gate * that must be relocated. However, on Intel it seems that the
4670Sstevel@tonic-gate * .rel.plt sh_info records the section index of the .plt, when
4680Sstevel@tonic-gate * in fact it's the .got that gets relocated. In addition we
4690Sstevel@tonic-gate * now create combined relocation sections with -zcomreloc. To
4700Sstevel@tonic-gate * generically be able to cope with these anomalies, search for
4710Sstevel@tonic-gate * the appropriate section to be relocated by comparing the
4720Sstevel@tonic-gate * offset of the first relocation record against each sections
4730Sstevel@tonic-gate * offset and size.
4740Sstevel@tonic-gate */
4755220Srie /* BEGIN CSTYLED */
4760Sstevel@tonic-gate #if !defined(__lint)
4770Sstevel@tonic-gate if ((ircache == (Cache *)0) || (rel->r_offset < bgn) ||
4780Sstevel@tonic-gate (rel->r_offset > end)) {
4790Sstevel@tonic-gate #else
4800Sstevel@tonic-gate /*
4810Sstevel@tonic-gate * lint sees `bgn' and `end' as potentially referenced
4820Sstevel@tonic-gate * before being set.
4830Sstevel@tonic-gate */
4840Sstevel@tonic-gate if (ircache == (Cache *)0) {
4850Sstevel@tonic-gate #endif
4860Sstevel@tonic-gate _icache = icache;
4870Sstevel@tonic-gate _icache++;
4880Sstevel@tonic-gate
4890Sstevel@tonic-gate for (ndx = 1; _icache->c_flags != FLG_C_END; ndx++,
4900Sstevel@tonic-gate _icache++) {
4910Sstevel@tonic-gate
4920Sstevel@tonic-gate shdr = _icache->c_shdr;
4930Sstevel@tonic-gate bgn = shdr->sh_addr;
4940Sstevel@tonic-gate end = bgn + shdr->sh_size;
4950Sstevel@tonic-gate
4960Sstevel@tonic-gate if ((rel->r_offset >= bgn) &&
4970Sstevel@tonic-gate (rel->r_offset <= end))
4980Sstevel@tonic-gate break;
4990Sstevel@tonic-gate }
5000Sstevel@tonic-gate ircache = &icache[ndx];
5010Sstevel@tonic-gate orcache = &ocache[ndx];
5020Sstevel@tonic-gate }
5035220Srie /* END CSTYLED */
5040Sstevel@tonic-gate
5050Sstevel@tonic-gate /*
5060Sstevel@tonic-gate * Determine the relocation location of both the input and
5070Sstevel@tonic-gate * output data. Take into account that an input section may be
5080Sstevel@tonic-gate * NOBITS (ppc .plt for example).
5090Sstevel@tonic-gate */
5100Sstevel@tonic-gate off = rel->r_offset - ircache->c_shdr->sh_addr;
5110Sstevel@tonic-gate if (ircache->c_data->d_buf)
5120Sstevel@tonic-gate iaddr = (uchar_t *)ircache->c_data->d_buf + off;
5130Sstevel@tonic-gate else
5140Sstevel@tonic-gate iaddr = 0;
5150Sstevel@tonic-gate oaddr = (uchar_t *)orcache->c_data->d_buf + off;
5160Sstevel@tonic-gate
5170Sstevel@tonic-gate /*
5180Sstevel@tonic-gate * Apply the relocation to the new output image. Any base
5190Sstevel@tonic-gate * address, or symbol value, will have been saved in the reloc
5200Sstevel@tonic-gate * structure during count_reloc().
5210Sstevel@tonic-gate */
5220Sstevel@tonic-gate if (reloc->r_flags & FLG_R_APPLY)
5230Sstevel@tonic-gate apply_reloc(rel, reloc, name, oaddr, lmp);
5240Sstevel@tonic-gate
5250Sstevel@tonic-gate /*
5260Sstevel@tonic-gate * Undo any relocation that might already been applied to the
5270Sstevel@tonic-gate * memory image by the runtime linker. Using the original
5280Sstevel@tonic-gate * file, determine the relocation offset original value and
5290Sstevel@tonic-gate * restore the new image to that value.
5300Sstevel@tonic-gate */
5310Sstevel@tonic-gate if ((reloc->r_flags & FLG_R_UNDO) &&
5320Sstevel@tonic-gate (FLAGS(lmp) & FLG_RT_RELOCED))
5330Sstevel@tonic-gate undo_reloc(rel, oaddr, iaddr, reloc);
5340Sstevel@tonic-gate
5350Sstevel@tonic-gate /*
5360Sstevel@tonic-gate * If a relocation has been applied then the relocation record
5370Sstevel@tonic-gate * should be cleared so that the relocation isn't applied again
5380Sstevel@tonic-gate * when the new image is used.
5390Sstevel@tonic-gate */
5400Sstevel@tonic-gate if (reloc->r_flags & FLG_R_CLR) {
5410Sstevel@tonic-gate if (type == M_R_JMP_SLOT) {
5420Sstevel@tonic-gate clear_reloc(*func);
5430Sstevel@tonic-gate *func = (Rel *)((uintptr_t)*func + ent);
5440Sstevel@tonic-gate } else {
5450Sstevel@tonic-gate clear_reloc(*null);
5460Sstevel@tonic-gate *null = (Rel *)((uintptr_t)*null + ent);
5470Sstevel@tonic-gate }
5480Sstevel@tonic-gate }
5490Sstevel@tonic-gate
5500Sstevel@tonic-gate /*
5510Sstevel@tonic-gate * If a relocation isn't applied, update the relocation record
5520Sstevel@tonic-gate * to take into account the new address of the image.
5530Sstevel@tonic-gate */
5540Sstevel@tonic-gate if (reloc->r_flags & FLG_R_INC) {
5550Sstevel@tonic-gate if (type == M_R_JMP_SLOT) {
5560Sstevel@tonic-gate inc_reloc(*func, rel, reloc, oaddr, iaddr);
5570Sstevel@tonic-gate *func = (Rel *)((uintptr_t)*func + ent);
5580Sstevel@tonic-gate } else {
5590Sstevel@tonic-gate inc_reloc(*data, rel, reloc, oaddr, iaddr);
5600Sstevel@tonic-gate *data = (Rel *)((uintptr_t)*data + ent);
5610Sstevel@tonic-gate }
5620Sstevel@tonic-gate }
5630Sstevel@tonic-gate }
5640Sstevel@tonic-gate }
565