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
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.
795aefb655Srie */
80466e2a62Srie int
move_data(Rt_map * lmp,APlist ** textrel)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
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);
199466e2a62Srie }
200466e2a62Srie return (0);
2015aefb655Srie }
202