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
55aefb655Srie * Common Development and Distribution License (the "License").
65aefb655Srie * 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 */
215aefb655Srie
227c478bd9Sstevel@tonic-gate /*
23*f441771bSRod Evans * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
247c478bd9Sstevel@tonic-gate */
257257d1b4Sraf
267c478bd9Sstevel@tonic-gate /*
277c478bd9Sstevel@tonic-gate * Object file dependent support for ELF objects.
287c478bd9Sstevel@tonic-gate */
297c478bd9Sstevel@tonic-gate
307c478bd9Sstevel@tonic-gate #include <stdio.h>
317c478bd9Sstevel@tonic-gate #include <sys/procfs.h>
327c478bd9Sstevel@tonic-gate #include <sys/mman.h>
337c478bd9Sstevel@tonic-gate #include <dlfcn.h>
345aefb655Srie #include <debug.h>
355aefb655Srie #include <conv.h>
367c478bd9Sstevel@tonic-gate #include "_rtld.h"
377c478bd9Sstevel@tonic-gate #include "_audit.h"
387c478bd9Sstevel@tonic-gate #include "_elf.h"
39*f441771bSRod Evans #include "_inline_gen.h"
407c478bd9Sstevel@tonic-gate #include "msg.h"
417c478bd9Sstevel@tonic-gate
42466e2a62Srie /*
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
497c478bd9Sstevel@tonic-gate /*
5056deab07SRod Evans * Warning message for bad move target.
5156deab07SRod Evans */
5256deab07SRod Evans void
elf_move_bad(Lm_list * lml,Rt_map * lmp,Sym * sym,ulong_t num,Addr addr)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.
797c478bd9Sstevel@tonic-gate */
80466e2a62Srie int
move_data(Rt_map * lmp,APlist ** textrel)8156deab07SRod Evans move_data(Rt_map *lmp, APlist **textrel)
827c478bd9Sstevel@tonic-gate {
8356deab07SRod Evans Lm_list *lml = LIST(lmp);
8456deab07SRod Evans Move *mv = MOVETAB(lmp);
8556deab07SRod Evans ulong_t num, mvnum = MOVESZ(lmp) / MOVEENT(lmp);
8656deab07SRod Evans 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);
957c478bd9Sstevel@tonic-gate
965aefb655Srie DBG_CALL(Dbg_move_data(lmp));
975aefb655Srie for (num = 0; num < mvnum; num++, mv++) {
9856deab07SRod Evans mmapobj_result_t *mpp;
9956deab07SRod Evans Addr addr, taddr;
10056deab07SRod Evans Half rep, repno, stride;
10156deab07SRod Evans Sym *sym;
1027c478bd9Sstevel@tonic-gate
1037c478bd9Sstevel@tonic-gate if ((sym = (Sym *)SYMTAB(lmp) + ELF_M_SYM(mv->m_info)) == 0)
1047c478bd9Sstevel@tonic-gate continue;
1057c478bd9Sstevel@tonic-gate
1067c478bd9Sstevel@tonic-gate 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;
1167c478bd9Sstevel@tonic-gate
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));
1317c478bd9Sstevel@tonic-gate
1327c478bd9Sstevel@tonic-gate switch (ELF_M_SIZE(mv->m_info)) {
1337c478bd9Sstevel@tonic-gate case 1:
1347c478bd9Sstevel@tonic-gate *((char *)taddr) = (char)mv->m_value;
1357c478bd9Sstevel@tonic-gate taddr += stride;
136466e2a62Srie repno++;
1377c478bd9Sstevel@tonic-gate break;
1387c478bd9Sstevel@tonic-gate case 2:
1397c478bd9Sstevel@tonic-gate /* LINTED */
1407c478bd9Sstevel@tonic-gate *((Half *)taddr) = (Half)mv->m_value;
1417c478bd9Sstevel@tonic-gate taddr += 2 * stride;
142466e2a62Srie repno++;
1437c478bd9Sstevel@tonic-gate break;
1447c478bd9Sstevel@tonic-gate case 4:
1457c478bd9Sstevel@tonic-gate /* LINTED */
1467c478bd9Sstevel@tonic-gate *((Word *)taddr) = (Word)mv->m_value;
1477c478bd9Sstevel@tonic-gate taddr += 4 * stride;
148466e2a62Srie repno++;
1497c478bd9Sstevel@tonic-gate break;
1507c478bd9Sstevel@tonic-gate case 8:
1517c478bd9Sstevel@tonic-gate /* LINTED */
1527c478bd9Sstevel@tonic-gate *((unsigned long long *)taddr) = mv->m_value;
1537c478bd9Sstevel@tonic-gate taddr += 8 * stride;
154466e2a62Srie repno++;
1557c478bd9Sstevel@tonic-gate break;
1567c478bd9Sstevel@tonic-gate default:
1575aefb655Srie eprintf(lml, ERR_NONE, MSG_INTL(MSG_MOVE_ERR1));
1587c478bd9Sstevel@tonic-gate break;
1597c478bd9Sstevel@tonic-gate }
1607c478bd9Sstevel@tonic-gate }
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);
170466e2a62Srie }
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
is_move_data(caddr_t addr)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);
1997c478bd9Sstevel@tonic-gate }
200466e2a62Srie return (0);
2017c478bd9Sstevel@tonic-gate }
202