xref: /illumos-gate/usr/src/cmd/sgs/rtld/common/move.c (revision e13e346d8734036862432c746042cff8470e8ebd)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 /*
29  * Object file dependent support for ELF objects.
30  */
31 #include	"_synonyms.h"
32 
33 #include	<stdio.h>
34 #include	<sys/procfs.h>
35 #include	<sys/mman.h>
36 #include	<dlfcn.h>
37 #include	<debug.h>
38 #include	<conv.h>
39 #include	"_rtld.h"
40 #include	"_audit.h"
41 #include	"_elf.h"
42 #include	"msg.h"
43 
44 /*
45  * For backward compatibility copy relocation processing, it can be necessary to
46  * determine if a copy destination is also the recipient of a move record.  For
47  * these instances, the move record addresses are retained for is_move_data().
48  */
49 static	APlist	*alp = NULL;
50 
51 /*
52  * Move data
53  */
54 int
55 move_data(Rt_map *lmp)
56 {
57 	Lm_list	*lml = LIST(lmp);
58 	Move	*mv = MOVETAB(lmp);
59 	Phdr	*pptr = SUNWBSS(lmp);
60 	ulong_t	num, mvnum = MOVESZ(lmp) / MOVEENT(lmp);
61 	int	moves;
62 
63 	/*
64 	 * If these records are against the executable, and the executable was
65 	 * built prior to Solaris 8, keep track of the move record symbol.  See
66 	 * comment in analyze.c:lookup_sym_interpose() in regards Solaris 8
67 	 * objects and DT_FLAGS.
68 	 */
69 	moves = (lmp == lml->lm_head) && ((FLAGS2(lmp) & FL2_RT_DTFLAGS) == 0);
70 
71 	DBG_CALL(Dbg_move_data(lmp));
72 	for (num = 0; num < mvnum; num++, mv++) {
73 		Addr	addr, taddr;
74 		Half 	rep, repno, stride;
75 		Sym	*sym;
76 
77 		/*
78 		 * If the target address needs to be mapped in,
79 		 * map it first.
80 		 *	(You have to protect the code, thread safe)
81 		 */
82 		if (FLAGS(lmp) & FLG_RT_SUNWBSS) {
83 			long	zlen;
84 			Off	foff;
85 			caddr_t	zaddr, eaddr;
86 
87 			foff = (Off) (pptr->p_vaddr + ADDR(lmp));
88 			zaddr = (caddr_t)M_PROUND(foff);
89 			eaddr = pptr->p_vaddr + ADDR(lmp) +
90 			    (caddr_t)pptr->p_memsz;
91 			zero((caddr_t)foff, (long)(zaddr - foff));
92 			zlen = eaddr - zaddr;
93 			if (zlen > 0) {
94 				if (dz_map(lml, zaddr, zlen,
95 				    (PROT_READ | PROT_WRITE),
96 				    (MAP_FIXED | MAP_PRIVATE)) == MAP_FAILED)
97 					return (0);
98 			}
99 
100 			FLAGS(lmp) &= ~FLG_RT_SUNWBSS;
101 		}
102 
103 		if ((sym = (Sym *)SYMTAB(lmp) + ELF_M_SYM(mv->m_info)) == 0)
104 			continue;
105 
106 		stride = mv->m_stride + 1;
107 		addr = sym->st_value;
108 		if ((FLAGS(lmp) & FLG_RT_FIXED) == 0)
109 			addr += ADDR(lmp);
110 		taddr = addr + mv->m_poffset;
111 
112 		DBG_CALL(Dbg_move_entry2(lml, mv, sym->st_name,
113 		    (const char *)(sym->st_name + STRTAB(lmp))));
114 
115 		for (rep = 0, repno = 0; rep < mv->m_repeat; rep++) {
116 			DBG_CALL(Dbg_move_expand(lml, mv, taddr));
117 
118 			switch (ELF_M_SIZE(mv->m_info)) {
119 			case 1:
120 				*((char *)taddr) = (char)mv->m_value;
121 				taddr += stride;
122 				repno++;
123 				break;
124 			case 2:
125 				/* LINTED */
126 				*((Half *)taddr) = (Half)mv->m_value;
127 				taddr += 2 * stride;
128 				repno++;
129 				break;
130 			case 4:
131 				/* LINTED */
132 				*((Word *)taddr) = (Word)mv->m_value;
133 				taddr += 4 * stride;
134 				repno++;
135 				break;
136 			case 8:
137 				/* LINTED */
138 				*((unsigned long long *)taddr) = mv->m_value;
139 				taddr += 8 * stride;
140 				repno++;
141 				break;
142 			default:
143 				eprintf(lml, ERR_NONE, MSG_INTL(MSG_MOVE_ERR1));
144 				break;
145 			}
146 		}
147 
148 		/*
149 		 * If any move records have been applied to this symbol, retain
150 		 * the symbol address if required for backward compatibility
151 		 * copy relocation processing.
152 		 */
153 		if (moves && repno &&
154 		    (aplist_append(&alp, (void *)addr, AL_CNT_MOVES) == 0))
155 			return (0);
156 	}
157 
158 	/*
159 	 * Binaries built in the early 1990's prior to Solaris 8, using the ild
160 	 * incremental linker are known to have zero filled move sections
161 	 * (presumably place holders for new, incoming move sections).  If no
162 	 * move records have been processed, remove the move identifier to
163 	 * optimize the amount of backward compatibility copy relocation
164 	 * processing that is needed.
165 	 */
166 	if (moves && (alp == NULL))
167 		FLAGS(lmp) &= ~FLG_RT_MOVE;
168 
169 	return (1);
170 }
171 
172 /*
173  * Determine whether an address is the recipient of a move record.
174  * Returns 1 if the address matches a move symbol, 0 otherwise.
175  */
176 int
177 is_move_data(caddr_t addr)
178 {
179 	caddr_t	maddr;
180 	Aliste	idx;
181 
182 	for (APLIST_TRAVERSE(alp, idx, maddr)) {
183 		if (addr == maddr)
184 			return (1);
185 	}
186 	return (0);
187 }
188