15aefb655Srie /* 25aefb655Srie * CDDL HEADER START 35aefb655Srie * 45aefb655Srie * The contents of this file are subject to the terms of the 55aefb655Srie * Common Development and Distribution License (the "License"). 65aefb655Srie * You may not use this file except in compliance with the License. 75aefb655Srie * 85aefb655Srie * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 95aefb655Srie * or http://www.opensolaris.org/os/licensing. 105aefb655Srie * See the License for the specific language governing permissions 115aefb655Srie * and limitations under the License. 125aefb655Srie * 135aefb655Srie * When distributing Covered Code, include this CDDL HEADER in each 145aefb655Srie * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 155aefb655Srie * If applicable, add the following below this CDDL HEADER, with the 165aefb655Srie * fields enclosed by brackets "[]" replaced with your own identifying 175aefb655Srie * information: Portions Copyright [yyyy] [name of copyright owner] 185aefb655Srie * 195aefb655Srie * CDDL HEADER END 205aefb655Srie */ 215aefb655Srie 225aefb655Srie /* 23*f441771bSRod Evans * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved. 245aefb655Srie */ 257257d1b4Sraf 265aefb655Srie /* 275aefb655Srie * Object file dependent support for ELF objects. 285aefb655Srie */ 295aefb655Srie 305aefb655Srie #include <stdio.h> 315aefb655Srie #include <sys/procfs.h> 325aefb655Srie #include <sys/mman.h> 335aefb655Srie #include <dlfcn.h> 345aefb655Srie #include <debug.h> 355aefb655Srie #include <conv.h> 365aefb655Srie #include "_rtld.h" 375aefb655Srie #include "_audit.h" 385aefb655Srie #include "_elf.h" 39*f441771bSRod Evans #include "_inline_gen.h" 405aefb655Srie #include "msg.h" 415aefb655Srie 425aefb655Srie /* 43466e2a62Srie * For backward compatibility copy relocation processing, it can be necessary to 44466e2a62Srie * determine if a copy destination is also the recipient of a move record. For 45466e2a62Srie * these instances, the move record addresses are retained for is_move_data(). 46466e2a62Srie */ 47466e2a62Srie static APlist *alp = NULL; 48466e2a62Srie 49466e2a62Srie /* 5056deab07SRod Evans * Warning message for bad move target. 5156deab07SRod Evans */ 5256deab07SRod Evans void 5356deab07SRod Evans elf_move_bad(Lm_list *lml, Rt_map *lmp, Sym *sym, ulong_t num, Addr addr) 5456deab07SRod Evans { 5556deab07SRod Evans const char *name; 5656deab07SRod Evans int trace; 5756deab07SRod Evans 5856deab07SRod Evans trace = (lml->lm_flags & LML_FLG_TRC_ENABLE) && 5956deab07SRod Evans (((rtld_flags & RT_FL_SILENCERR) == 0) || 6056deab07SRod Evans (lml->lm_flags & (LML_FLG_TRC_VERBOSE | LML_FLG_TRC_WARN))); 6156deab07SRod Evans 6256deab07SRod Evans if ((trace == 0) && (DBG_ENABLED == 0)) 6356deab07SRod Evans return; 6456deab07SRod Evans 6556deab07SRod Evans if (ELF_ST_BIND(sym->st_info) != STB_LOCAL) 6656deab07SRod Evans name = (const char *)(STRTAB(lmp) + sym->st_name); 6756deab07SRod Evans else 6856deab07SRod Evans name = MSG_INTL(MSG_STR_UNKNOWN); 6956deab07SRod Evans 7056deab07SRod Evans if (trace) 7156deab07SRod Evans (void) printf(MSG_INTL(MSG_LDD_MOVE_ERR), EC_XWORD(num), name, 7256deab07SRod Evans EC_ADDR(addr)); 7356deab07SRod Evans else 7456deab07SRod Evans DBG_CALL(Dbg_move_bad(lml, num, name, addr)); 7556deab07SRod Evans } 7656deab07SRod Evans 7756deab07SRod Evans /* 7856deab07SRod Evans * Move data. Apply sparse initialization to data in zeroed bss. 795aefb655Srie */ 80466e2a62Srie int 8156deab07SRod Evans move_data(Rt_map *lmp, APlist **textrel) 825aefb655Srie { 835aefb655Srie Lm_list *lml = LIST(lmp); 845aefb655Srie Move *mv = MOVETAB(lmp); 855aefb655Srie ulong_t num, mvnum = MOVESZ(lmp) / MOVEENT(lmp); 86466e2a62Srie int moves; 87466e2a62Srie 88466e2a62Srie /* 89466e2a62Srie * If these records are against the executable, and the executable was 90466e2a62Srie * built prior to Solaris 8, keep track of the move record symbol. See 91466e2a62Srie * comment in analyze.c:lookup_sym_interpose() in regards Solaris 8 92466e2a62Srie * objects and DT_FLAGS. 93466e2a62Srie */ 9456deab07SRod Evans moves = (lmp == lml->lm_head) && ((FLAGS1(lmp) & FL1_RT_DTFLAGS) == 0); 955aefb655Srie 965aefb655Srie DBG_CALL(Dbg_move_data(lmp)); 975aefb655Srie for (num = 0; num < mvnum; num++, mv++) { 9856deab07SRod Evans mmapobj_result_t *mpp; 99466e2a62Srie Addr addr, taddr; 100466e2a62Srie Half rep, repno, stride; 1015aefb655Srie Sym *sym; 1025aefb655Srie 1035aefb655Srie if ((sym = (Sym *)SYMTAB(lmp) + ELF_M_SYM(mv->m_info)) == 0) 1045aefb655Srie continue; 1055aefb655Srie 1065aefb655Srie stride = mv->m_stride + 1; 107466e2a62Srie addr = sym->st_value; 10856deab07SRod Evans 10956deab07SRod Evans /* 11056deab07SRod Evans * Determine the move data target, and verify the address is 11156deab07SRod Evans * writable. 11256deab07SRod Evans */ 113466e2a62Srie if ((FLAGS(lmp) & FLG_RT_FIXED) == 0) 114466e2a62Srie addr += ADDR(lmp); 115466e2a62Srie taddr = addr + mv->m_poffset; 1165aefb655Srie 11756deab07SRod Evans if ((mpp = find_segment((caddr_t)taddr, lmp)) == NULL) { 11856deab07SRod Evans elf_move_bad(lml, lmp, sym, num, taddr); 11956deab07SRod Evans continue; 12056deab07SRod Evans } 12156deab07SRod Evans if (((mpp->mr_prot & PROT_WRITE) == 0) && 12256deab07SRod Evans ((set_prot(lmp, mpp, 1) == 0) || 12356deab07SRod Evans (aplist_append(textrel, mpp, AL_CNT_TEXTREL) == NULL))) 12456deab07SRod Evans return (0); 12556deab07SRod Evans 1265aefb655Srie DBG_CALL(Dbg_move_entry2(lml, mv, sym->st_name, 1275aefb655Srie (const char *)(sym->st_name + STRTAB(lmp)))); 1285aefb655Srie 129466e2a62Srie for (rep = 0, repno = 0; rep < mv->m_repeat; rep++) { 1305aefb655Srie DBG_CALL(Dbg_move_expand(lml, mv, taddr)); 1315aefb655Srie 1325aefb655Srie switch (ELF_M_SIZE(mv->m_info)) { 1335aefb655Srie case 1: 1345aefb655Srie *((char *)taddr) = (char)mv->m_value; 1355aefb655Srie taddr += stride; 136466e2a62Srie repno++; 1375aefb655Srie break; 1385aefb655Srie case 2: 1395aefb655Srie /* LINTED */ 1405aefb655Srie *((Half *)taddr) = (Half)mv->m_value; 1415aefb655Srie taddr += 2 * stride; 142466e2a62Srie repno++; 1435aefb655Srie break; 1445aefb655Srie case 4: 1455aefb655Srie /* LINTED */ 1465aefb655Srie *((Word *)taddr) = (Word)mv->m_value; 1475aefb655Srie taddr += 4 * stride; 148466e2a62Srie repno++; 1495aefb655Srie break; 1505aefb655Srie case 8: 1515aefb655Srie /* LINTED */ 1525aefb655Srie *((unsigned long long *)taddr) = mv->m_value; 1535aefb655Srie taddr += 8 * stride; 154466e2a62Srie repno++; 1555aefb655Srie break; 1565aefb655Srie default: 1575aefb655Srie eprintf(lml, ERR_NONE, MSG_INTL(MSG_MOVE_ERR1)); 1585aefb655Srie break; 1595aefb655Srie } 1605aefb655Srie } 161466e2a62Srie 162466e2a62Srie /* 163466e2a62Srie * If any move records have been applied to this symbol, retain 164466e2a62Srie * the symbol address if required for backward compatibility 165466e2a62Srie * copy relocation processing. 166466e2a62Srie */ 167466e2a62Srie if (moves && repno && 16856deab07SRod Evans (aplist_append(&alp, (void *)addr, AL_CNT_MOVES) == NULL)) 169466e2a62Srie return (0); 1705aefb655Srie } 171466e2a62Srie 172466e2a62Srie /* 173466e2a62Srie * Binaries built in the early 1990's prior to Solaris 8, using the ild 174466e2a62Srie * incremental linker are known to have zero filled move sections 175466e2a62Srie * (presumably place holders for new, incoming move sections). If no 176466e2a62Srie * move records have been processed, remove the move identifier to 177466e2a62Srie * optimize the amount of backward compatibility copy relocation 178466e2a62Srie * processing that is needed. 179466e2a62Srie */ 180466e2a62Srie if (moves && (alp == NULL)) 181466e2a62Srie FLAGS(lmp) &= ~FLG_RT_MOVE; 182466e2a62Srie 183466e2a62Srie return (1); 184466e2a62Srie } 185466e2a62Srie 186466e2a62Srie /* 187466e2a62Srie * Determine whether an address is the recipient of a move record. 188466e2a62Srie * Returns 1 if the address matches a move symbol, 0 otherwise. 189466e2a62Srie */ 190466e2a62Srie int 191466e2a62Srie is_move_data(caddr_t addr) 192466e2a62Srie { 193466e2a62Srie caddr_t maddr; 194466e2a62Srie Aliste idx; 195466e2a62Srie 196466e2a62Srie for (APLIST_TRAVERSE(alp, idx, maddr)) { 197466e2a62Srie if (addr == maddr) 198466e2a62Srie return (1); 199466e2a62Srie } 200466e2a62Srie return (0); 2015aefb655Srie } 202