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 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 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