xref: /illumos-gate/usr/src/cmd/sgs/libld/common/machsym.sparc.c (revision 8b80e8cb6855118d46f605e91b5ed4ce83417395)
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 #define	ELF_TARGET_SPARC
29 
30 #include	<stdio.h>
31 #include	<string.h>
32 #include	<alloca.h>
33 #include	<sys/types.h>
34 #include	<debug.h>
35 #include	"msg.h"
36 #include	"_libld.h"
37 #include	"machsym.sparc.h"
38 
39 /*
40  * Matrix of legal combinations of usage of a given register:
41  *
42  *	Obj1 \ Obj2      Scratch	Named
43  *	Scratch          OK		NO
44  *	Named            NO		*
45  *
46  * (*) OK if the symbols are identical, NO if they are not.  Two symbols
47  * are identical if and only if one of the following is true:
48  *   A. They are both global and have the same name.
49  *   B. They are both local, have the same name, and are defined in the same
50  *	object.  (Note that a local symbol in one object is never identical to
51  *	a local symbol in another object, even if the name is the same.)
52  *
53  * Matrix of legal combinations of st_shndx for the same register symbol:
54  *
55  *	Obj1 \ Obj2      UNDEF		ABS
56  *	UNDEF            OK		OK
57  *	ABS              OK		NO
58  *
59  */
60 int
61 ld_reg_check_sparc(Sym_desc *sdp, Sym *nsym, const char *nname, Ifl_desc *ifl,
62     Ofl_desc * ofl)
63 {
64 	Sym		*osym = sdp->sd_sym;
65 	const char	*oname = sdp->sd_name;
66 	Conv_inv_buf_t	inv_buf1, inv_buf2;
67 
68 	/*
69 	 * Scratch register definitions are compatible.
70 	 */
71 	if ((osym->st_name == 0) && (nsym->st_name == 0))
72 		return (0);
73 
74 	/*
75 	 * A local and a global, or another local is incompatible.
76 	 */
77 	if ((ELF_ST_BIND(osym->st_info) == STB_LOCAL) ||
78 	    (ELF_ST_BIND(nsym->st_info) == STB_LOCAL)) {
79 		if (osym->st_value == nsym->st_value) {
80 
81 			eprintf(ofl->ofl_lml, ERR_FATAL,
82 			    MSG_INTL(MSG_SYM_INCOMPREG3),
83 			    conv_sym_SPARC_value(osym->st_value, 0, &inv_buf1),
84 			    sdp->sd_file->ifl_name, demangle(oname),
85 			    ifl->ifl_name, demangle(nname));
86 			ofl->ofl_flags |= FLG_OF_FATAL;
87 			return (1);
88 		}
89 		return (0);
90 	}
91 
92 	if (osym->st_value == nsym->st_value) {
93 		/*
94 		 * A scratch register and a named register are incompatible.
95 		 * So are two different named registers.
96 		 */
97 		if (((osym->st_name == 0) || (nsym->st_name == 0)) ||
98 		    (strcmp(oname, nname) != 0)) {
99 			eprintf(ofl->ofl_lml, ERR_FATAL,
100 			    MSG_INTL(MSG_SYM_INCOMPREG1),
101 			    conv_sym_SPARC_value(osym->st_value, 0, &inv_buf1),
102 			    sdp->sd_file->ifl_name, demangle(oname),
103 			    ifl->ifl_name, demangle(nname));
104 			ofl->ofl_flags |= FLG_OF_FATAL;
105 			return (1);
106 		}
107 
108 		/*
109 		 * A multiply initialized symbol is also illegal.
110 		 */
111 		if ((osym->st_shndx == SHN_ABS) &&
112 		    (nsym->st_shndx == SHN_ABS)) {
113 			eprintf(ofl->ofl_lml, ERR_FATAL,
114 			    MSG_INTL(MSG_SYM_MULTINIREG),
115 			    conv_sym_SPARC_value(osym->st_value, 0, &inv_buf1),
116 			    demangle(nname), sdp->sd_file->ifl_name,
117 			    ifl->ifl_name);
118 			ofl->ofl_flags |= FLG_OF_FATAL;
119 			return (1);
120 		}
121 
122 	} else if (strcmp(oname, nname) == 0) {
123 		eprintf(ofl->ofl_lml, ERR_FATAL, MSG_INTL(MSG_SYM_INCOMPREG2),
124 		    demangle(sdp->sd_name), sdp->sd_file->ifl_name,
125 		    conv_sym_SPARC_value(osym->st_value, 0, &inv_buf1),
126 		    ifl->ifl_name,
127 		    conv_sym_SPARC_value(nsym->st_value, 0, &inv_buf2));
128 		ofl->ofl_flags |= FLG_OF_FATAL;
129 		return (1);
130 	}
131 	return (0);
132 }
133 
134 int
135 ld_mach_sym_typecheck_sparc(Sym_desc *sdp, Sym *nsym, Ifl_desc *ifl,
136     Ofl_desc *ofl)
137 {
138 	Conv_inv_buf_t	inv_buf1, inv_buf2;
139 	Sym		*osym = sdp->sd_sym;
140 	Byte		otype = ELF_ST_TYPE(osym->st_info);
141 	Byte		ntype = ELF_ST_TYPE(nsym->st_info);
142 
143 	if (otype != ntype) {
144 		if ((otype == STT_SPARC_REGISTER) ||
145 		    (ntype == STT_SPARC_REGISTER)) {
146 			eprintf(ofl->ofl_lml, ERR_FATAL,
147 			    MSG_INTL(MSG_SYM_DIFFTYPE), demangle(sdp->sd_name));
148 			eprintf(ofl->ofl_lml, ERR_NONE,
149 			    MSG_INTL(MSG_SYM_FILETYPES),
150 			    sdp->sd_file->ifl_name, conv_sym_info_type(
151 			    sdp->sd_file->ifl_ehdr->e_machine, otype,
152 			    0, &inv_buf1), ifl->ifl_name,
153 			    conv_sym_info_type(ifl->ifl_ehdr->e_machine,
154 			    ntype, 0, &inv_buf2));
155 			ofl->ofl_flags |= FLG_OF_FATAL;
156 			return (1);
157 		}
158 	} else if (otype == STT_SPARC_REGISTER)
159 		return (ld_reg_check_sparc(sdp, nsym, sdp->sd_name, ifl, ofl));
160 
161 	return (0);
162 }
163 
164 static const char *registers[] = { 0,
165 	MSG_ORIG(MSG_STO_REGISTERG1),	MSG_ORIG(MSG_STO_REGISTERG2),
166 	MSG_ORIG(MSG_STO_REGISTERG3),	MSG_ORIG(MSG_STO_REGISTERG4),
167 	MSG_ORIG(MSG_STO_REGISTERG5),	MSG_ORIG(MSG_STO_REGISTERG6),
168 	MSG_ORIG(MSG_STO_REGISTERG7)
169 };
170 
171 const char *
172 ld_is_regsym_sparc(Ofl_desc *ofl, Ifl_desc *ifl, Sym *sym, const char *strs,
173     int symndx, Word shndx, const char *symsecname, Word * flags)
174 {
175 	const char	*name;
176 
177 	/*
178 	 * Only do something if this is a register symbol.
179 	 */
180 	if (ELF_ST_TYPE(sym->st_info) != STT_SPARC_REGISTER)
181 		return (0);
182 
183 	/*
184 	 * Check for bogus register number.
185 	 */
186 	if ((sym->st_value < STO_SPARC_REGISTER_G1) ||
187 	    (sym->st_value > STO_SPARC_REGISTER_G7)) {
188 		eprintf(ofl->ofl_lml, ERR_FATAL, MSG_INTL(MSG_SYM_BADREG),
189 		    ifl->ifl_name, symsecname, symndx, EC_XWORD(sym->st_value));
190 		return ((const char *)S_ERROR);
191 	}
192 
193 	/*
194 	 * A register symbol can only be undefined or defined (absolute).
195 	 */
196 	if ((shndx != SHN_ABS) && (shndx != SHN_UNDEF)) {
197 		eprintf(ofl->ofl_lml, ERR_FATAL, MSG_INTL(MSG_SYM_BADREG),
198 		    ifl->ifl_name, symsecname, symndx, EC_XWORD(sym->st_value));
199 		return ((const char *)S_ERROR);
200 	}
201 
202 	/*
203 	 * Determine whether this is a scratch (unnamed) definition.
204 	 */
205 	if (sym->st_name == 0) {
206 		/*
207 		 * Check for bogus scratch register definitions.
208 		 */
209 		if ((ELF_ST_BIND(sym->st_info) != STB_GLOBAL) ||
210 		    (shndx != SHN_UNDEF)) {
211 			Conv_inv_buf_t inv_buf;
212 
213 			eprintf(ofl->ofl_lml, ERR_FATAL,
214 			    MSG_INTL(MSG_SYM_BADSCRATCH),
215 			    ifl->ifl_name, symsecname, symndx,
216 			    conv_sym_SPARC_value(sym->st_value, 0, &inv_buf));
217 			return ((const char *)S_ERROR);
218 		}
219 
220 		/*
221 		 * Fabricate a name for this register so that this definition
222 		 * can be processed through the symbol resolution engine.
223 		 */
224 		name = registers[sym->st_value];
225 	} else
226 		name = strs + sym->st_name;
227 
228 	/*
229 	 * Indicate we're dealing with a register and return its name.
230 	 */
231 	*flags |= FLG_SY_REGSYM;
232 	return (name);
233 }
234 
235 Sym_desc *
236 ld_reg_find_sparc(Sym * sym, Ofl_desc * ofl)
237 {
238 	if (ofl->ofl_regsyms == 0)
239 		return (0);
240 
241 	return (ofl->ofl_regsyms[sym->st_value]);
242 }
243 
244 int
245 ld_reg_enter_sparc(Sym_desc * sdp, Ofl_desc * ofl)
246 {
247 	if (ofl->ofl_regsyms == 0) {
248 		ofl->ofl_regsymsno = STO_SPARC_REGISTER_G7 + 1;
249 		if ((ofl->ofl_regsyms = libld_calloc(sizeof (Sym_desc *),
250 		    ofl->ofl_regsymsno)) == 0) {
251 			ofl->ofl_flags |= FLG_OF_FATAL;
252 			return (0);
253 		}
254 	}
255 
256 	ofl->ofl_regsyms[sdp->sd_sym->st_value] = sdp;
257 	return (1);
258 }
259