xref: /illumos-gate/usr/src/cmd/sgs/rtld/common/move.c (revision f441771b)
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