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