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*de777a60Sab * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate #include <stdio.h> 297c478bd9Sstevel@tonic-gate #include <string.h> 307c478bd9Sstevel@tonic-gate #include <alloca.h> 317c478bd9Sstevel@tonic-gate #include <sys/types.h> 325aefb655Srie #include <debug.h> 337c478bd9Sstevel@tonic-gate #include "msg.h" 347c478bd9Sstevel@tonic-gate #include "_libld.h" 357c478bd9Sstevel@tonic-gate 367c478bd9Sstevel@tonic-gate /* 377c478bd9Sstevel@tonic-gate * Matrix of legal combinations of usage of a given register: 387c478bd9Sstevel@tonic-gate * 397c478bd9Sstevel@tonic-gate * Obj1 \ Obj2 Scratch Named 407c478bd9Sstevel@tonic-gate * Scratch OK NO 417c478bd9Sstevel@tonic-gate * Named NO * 427c478bd9Sstevel@tonic-gate * 437c478bd9Sstevel@tonic-gate * (*) OK if the symbols are identical, NO if they are not. Two symbols 447c478bd9Sstevel@tonic-gate * are identical if and only if one of the following is true: 457c478bd9Sstevel@tonic-gate * A. They are both global and have the same name. 467c478bd9Sstevel@tonic-gate * B. They are both local, have the same name, and are defined in the same 477c478bd9Sstevel@tonic-gate * object. (Note that a local symbol in one object is never identical to 487c478bd9Sstevel@tonic-gate * a local symbol in another object, even if the name is the same.) 497c478bd9Sstevel@tonic-gate * 507c478bd9Sstevel@tonic-gate * Matrix of legal combinations of st_shndx for the same register symbol: 517c478bd9Sstevel@tonic-gate * 527c478bd9Sstevel@tonic-gate * Obj1 \ Obj2 UNDEF ABS 537c478bd9Sstevel@tonic-gate * UNDEF OK OK 547c478bd9Sstevel@tonic-gate * ABS OK NO 557c478bd9Sstevel@tonic-gate * 567c478bd9Sstevel@tonic-gate */ 577c478bd9Sstevel@tonic-gate int 585aefb655Srie ld_reg_check(Sym_desc *sdp, Sym *nsym, const char *nname, Ifl_desc *ifl, 597c478bd9Sstevel@tonic-gate Ofl_desc * ofl) 607c478bd9Sstevel@tonic-gate { 617c478bd9Sstevel@tonic-gate Sym *osym = sdp->sd_sym; 627c478bd9Sstevel@tonic-gate const char *oname = sdp->sd_name; 63*de777a60Sab Conv_inv_buf_t inv_buf1, inv_buf2; 647c478bd9Sstevel@tonic-gate 657c478bd9Sstevel@tonic-gate /* 667c478bd9Sstevel@tonic-gate * Scratch register definitions are compatible. 677c478bd9Sstevel@tonic-gate */ 687c478bd9Sstevel@tonic-gate if ((osym->st_name == 0) && (nsym->st_name == 0)) 697c478bd9Sstevel@tonic-gate return (0); 707c478bd9Sstevel@tonic-gate 717c478bd9Sstevel@tonic-gate /* 727c478bd9Sstevel@tonic-gate * A local and a global, or another local is incompatible. 737c478bd9Sstevel@tonic-gate */ 747c478bd9Sstevel@tonic-gate if ((ELF_ST_BIND(osym->st_info) == STB_LOCAL) || 757c478bd9Sstevel@tonic-gate (ELF_ST_BIND(nsym->st_info) == STB_LOCAL)) { 767c478bd9Sstevel@tonic-gate if (osym->st_value == nsym->st_value) { 77*de777a60Sab 785aefb655Srie eprintf(ofl->ofl_lml, ERR_FATAL, 795aefb655Srie MSG_INTL(MSG_SYM_INCOMPREG3), 80*de777a60Sab conv_sym_SPARC_value(osym->st_value, 0, &inv_buf1), 817c478bd9Sstevel@tonic-gate sdp->sd_file->ifl_name, demangle(oname), 827c478bd9Sstevel@tonic-gate ifl->ifl_name, demangle(nname)); 837c478bd9Sstevel@tonic-gate ofl->ofl_flags |= FLG_OF_FATAL; 847c478bd9Sstevel@tonic-gate return (1); 857c478bd9Sstevel@tonic-gate } 867c478bd9Sstevel@tonic-gate return (0); 877c478bd9Sstevel@tonic-gate } 887c478bd9Sstevel@tonic-gate 897c478bd9Sstevel@tonic-gate if (osym->st_value == nsym->st_value) { 907c478bd9Sstevel@tonic-gate /* 917c478bd9Sstevel@tonic-gate * A scratch register and a named register are incompatible. 927c478bd9Sstevel@tonic-gate * So are two different named registers. 937c478bd9Sstevel@tonic-gate */ 947c478bd9Sstevel@tonic-gate if (((osym->st_name == 0) || (nsym->st_name == 0)) || 957c478bd9Sstevel@tonic-gate (strcmp(oname, nname) != 0)) { 965aefb655Srie eprintf(ofl->ofl_lml, ERR_FATAL, 975aefb655Srie MSG_INTL(MSG_SYM_INCOMPREG1), 98*de777a60Sab conv_sym_SPARC_value(osym->st_value, 0, &inv_buf1), 997c478bd9Sstevel@tonic-gate sdp->sd_file->ifl_name, demangle(oname), 1007c478bd9Sstevel@tonic-gate ifl->ifl_name, demangle(nname)); 1017c478bd9Sstevel@tonic-gate ofl->ofl_flags |= FLG_OF_FATAL; 1027c478bd9Sstevel@tonic-gate return (1); 1037c478bd9Sstevel@tonic-gate } 1047c478bd9Sstevel@tonic-gate 1057c478bd9Sstevel@tonic-gate /* 1067c478bd9Sstevel@tonic-gate * A multiply initialized symbol is also illegal. 1077c478bd9Sstevel@tonic-gate */ 1087c478bd9Sstevel@tonic-gate if ((osym->st_shndx == SHN_ABS) && 1097c478bd9Sstevel@tonic-gate (nsym->st_shndx == SHN_ABS)) { 1105aefb655Srie eprintf(ofl->ofl_lml, ERR_FATAL, 1115aefb655Srie MSG_INTL(MSG_SYM_MULTINIREG), 112*de777a60Sab conv_sym_SPARC_value(osym->st_value, 0, &inv_buf1), 1137c478bd9Sstevel@tonic-gate demangle(nname), sdp->sd_file->ifl_name, 1147c478bd9Sstevel@tonic-gate ifl->ifl_name); 1157c478bd9Sstevel@tonic-gate ofl->ofl_flags |= FLG_OF_FATAL; 1167c478bd9Sstevel@tonic-gate return (1); 1177c478bd9Sstevel@tonic-gate } 1187c478bd9Sstevel@tonic-gate 1197c478bd9Sstevel@tonic-gate } else if (strcmp(oname, nname) == 0) { 1205aefb655Srie eprintf(ofl->ofl_lml, ERR_FATAL, MSG_INTL(MSG_SYM_INCOMPREG2), 1217c478bd9Sstevel@tonic-gate demangle(sdp->sd_name), sdp->sd_file->ifl_name, 122*de777a60Sab conv_sym_SPARC_value(osym->st_value, 0, &inv_buf1), 123*de777a60Sab ifl->ifl_name, 124*de777a60Sab conv_sym_SPARC_value(nsym->st_value, 0, &inv_buf2)); 1257c478bd9Sstevel@tonic-gate ofl->ofl_flags |= FLG_OF_FATAL; 1267c478bd9Sstevel@tonic-gate return (1); 1277c478bd9Sstevel@tonic-gate } 1287c478bd9Sstevel@tonic-gate return (0); 1297c478bd9Sstevel@tonic-gate } 1307c478bd9Sstevel@tonic-gate 1317c478bd9Sstevel@tonic-gate int 1325aefb655Srie ld_mach_sym_typecheck(Sym_desc *sdp, Sym *nsym, Ifl_desc *ifl, Ofl_desc *ofl) 1337c478bd9Sstevel@tonic-gate { 134*de777a60Sab Conv_inv_buf_t inv_buf1, inv_buf2; 135*de777a60Sab Sym *osym = sdp->sd_sym; 136*de777a60Sab Byte otype = ELF_ST_TYPE(osym->st_info); 137*de777a60Sab Byte ntype = ELF_ST_TYPE(nsym->st_info); 1387c478bd9Sstevel@tonic-gate 1397c478bd9Sstevel@tonic-gate if (otype != ntype) { 1407c478bd9Sstevel@tonic-gate if ((otype == STT_SPARC_REGISTER) || 1417c478bd9Sstevel@tonic-gate (ntype == STT_SPARC_REGISTER)) { 1425aefb655Srie eprintf(ofl->ofl_lml, ERR_FATAL, 1435aefb655Srie MSG_INTL(MSG_SYM_DIFFTYPE), demangle(sdp->sd_name)); 1445aefb655Srie eprintf(ofl->ofl_lml, ERR_NONE, 1455aefb655Srie MSG_INTL(MSG_SYM_FILETYPES), 1465aefb655Srie sdp->sd_file->ifl_name, conv_sym_info_type( 147*de777a60Sab sdp->sd_file->ifl_ehdr->e_machine, otype, 148*de777a60Sab 0, &inv_buf1), ifl->ifl_name, 1495aefb655Srie conv_sym_info_type(ifl->ifl_ehdr->e_machine, 150*de777a60Sab ntype, 0, &inv_buf2)); 1517c478bd9Sstevel@tonic-gate ofl->ofl_flags |= FLG_OF_FATAL; 1527c478bd9Sstevel@tonic-gate return (1); 1537c478bd9Sstevel@tonic-gate } 1547c478bd9Sstevel@tonic-gate } else if (otype == STT_SPARC_REGISTER) 1555aefb655Srie return (ld_reg_check(sdp, nsym, sdp->sd_name, ifl, ofl)); 1567c478bd9Sstevel@tonic-gate 1577c478bd9Sstevel@tonic-gate return (0); 1587c478bd9Sstevel@tonic-gate } 1597c478bd9Sstevel@tonic-gate 1607c478bd9Sstevel@tonic-gate static const char *registers[] = { 0, 1617c478bd9Sstevel@tonic-gate MSG_ORIG(MSG_STO_REGISTERG1), MSG_ORIG(MSG_STO_REGISTERG2), 1627c478bd9Sstevel@tonic-gate MSG_ORIG(MSG_STO_REGISTERG3), MSG_ORIG(MSG_STO_REGISTERG4), 1637c478bd9Sstevel@tonic-gate MSG_ORIG(MSG_STO_REGISTERG5), MSG_ORIG(MSG_STO_REGISTERG6), 1647c478bd9Sstevel@tonic-gate MSG_ORIG(MSG_STO_REGISTERG7) 1657c478bd9Sstevel@tonic-gate }; 1667c478bd9Sstevel@tonic-gate 1677c478bd9Sstevel@tonic-gate const char * 1685aefb655Srie ld_is_regsym(Ofl_desc *ofl, Ifl_desc *ifl, Sym *sym, const char *strs, 1695aefb655Srie int symndx, Word shndx, const char *symsecname, Word * flags) 1707c478bd9Sstevel@tonic-gate { 1717c478bd9Sstevel@tonic-gate const char *name; 1727c478bd9Sstevel@tonic-gate 1737c478bd9Sstevel@tonic-gate /* 1747c478bd9Sstevel@tonic-gate * Only do something if this is a register symbol. 1757c478bd9Sstevel@tonic-gate */ 1767c478bd9Sstevel@tonic-gate if (ELF_ST_TYPE(sym->st_info) != STT_SPARC_REGISTER) 1777c478bd9Sstevel@tonic-gate return (0); 1787c478bd9Sstevel@tonic-gate 1797c478bd9Sstevel@tonic-gate /* 1807c478bd9Sstevel@tonic-gate * Check for bogus register number. 1817c478bd9Sstevel@tonic-gate */ 1827c478bd9Sstevel@tonic-gate if ((sym->st_value < STO_SPARC_REGISTER_G1) || 1837c478bd9Sstevel@tonic-gate (sym->st_value > STO_SPARC_REGISTER_G7)) { 1845aefb655Srie eprintf(ofl->ofl_lml, ERR_FATAL, MSG_INTL(MSG_SYM_BADREG), 1855aefb655Srie ifl->ifl_name, symsecname, symndx, EC_XWORD(sym->st_value)); 1867c478bd9Sstevel@tonic-gate return ((const char *)S_ERROR); 1877c478bd9Sstevel@tonic-gate } 1887c478bd9Sstevel@tonic-gate 1897c478bd9Sstevel@tonic-gate /* 1907c478bd9Sstevel@tonic-gate * A register symbol can only be undefined or defined (absolute). 1917c478bd9Sstevel@tonic-gate */ 1927c478bd9Sstevel@tonic-gate if ((shndx != SHN_ABS) && (shndx != SHN_UNDEF)) { 1935aefb655Srie eprintf(ofl->ofl_lml, ERR_FATAL, MSG_INTL(MSG_SYM_BADREG), 1945aefb655Srie ifl->ifl_name, symsecname, symndx, EC_XWORD(sym->st_value)); 1957c478bd9Sstevel@tonic-gate return ((const char *)S_ERROR); 1967c478bd9Sstevel@tonic-gate } 1977c478bd9Sstevel@tonic-gate 1987c478bd9Sstevel@tonic-gate /* 1997c478bd9Sstevel@tonic-gate * Determine whether this is a scratch (unnamed) definition. 2007c478bd9Sstevel@tonic-gate */ 2017c478bd9Sstevel@tonic-gate if (sym->st_name == 0) { 2027c478bd9Sstevel@tonic-gate /* 2037c478bd9Sstevel@tonic-gate * Check for bogus scratch register definitions. 2047c478bd9Sstevel@tonic-gate */ 2057c478bd9Sstevel@tonic-gate if ((ELF_ST_BIND(sym->st_info) != STB_GLOBAL) || 2067c478bd9Sstevel@tonic-gate (shndx != SHN_UNDEF)) { 207*de777a60Sab Conv_inv_buf_t inv_buf; 208*de777a60Sab 2095aefb655Srie eprintf(ofl->ofl_lml, ERR_FATAL, 2105aefb655Srie MSG_INTL(MSG_SYM_BADSCRATCH), 2117c478bd9Sstevel@tonic-gate ifl->ifl_name, symsecname, symndx, 212*de777a60Sab conv_sym_SPARC_value(sym->st_value, 0, &inv_buf)); 2137c478bd9Sstevel@tonic-gate return ((const char *)S_ERROR); 2147c478bd9Sstevel@tonic-gate } 2157c478bd9Sstevel@tonic-gate 2167c478bd9Sstevel@tonic-gate /* 2177c478bd9Sstevel@tonic-gate * Fabricate a name for this register so that this definition 2187c478bd9Sstevel@tonic-gate * can be processed through the symbol resolution engine. 2197c478bd9Sstevel@tonic-gate */ 2207c478bd9Sstevel@tonic-gate name = registers[sym->st_value]; 2217c478bd9Sstevel@tonic-gate } else 2227c478bd9Sstevel@tonic-gate name = strs + sym->st_name; 2237c478bd9Sstevel@tonic-gate 2247c478bd9Sstevel@tonic-gate /* 2257c478bd9Sstevel@tonic-gate * Indicate we're dealing with a register and return its name. 2267c478bd9Sstevel@tonic-gate */ 2277c478bd9Sstevel@tonic-gate *flags |= FLG_SY_REGSYM; 2287c478bd9Sstevel@tonic-gate return (name); 2297c478bd9Sstevel@tonic-gate } 2307c478bd9Sstevel@tonic-gate 2317c478bd9Sstevel@tonic-gate Sym_desc * 2325aefb655Srie ld_reg_find(Sym * sym, Ofl_desc * ofl) 2337c478bd9Sstevel@tonic-gate { 2347c478bd9Sstevel@tonic-gate if (ofl->ofl_regsyms == 0) 2357c478bd9Sstevel@tonic-gate return (0); 2367c478bd9Sstevel@tonic-gate 2377c478bd9Sstevel@tonic-gate return (ofl->ofl_regsyms[sym->st_value]); 2387c478bd9Sstevel@tonic-gate } 2397c478bd9Sstevel@tonic-gate 2407c478bd9Sstevel@tonic-gate int 2415aefb655Srie ld_reg_enter(Sym_desc * sdp, Ofl_desc * ofl) 2427c478bd9Sstevel@tonic-gate { 2437c478bd9Sstevel@tonic-gate if (ofl->ofl_regsyms == 0) { 2447c478bd9Sstevel@tonic-gate ofl->ofl_regsymsno = STO_SPARC_REGISTER_G7 + 1; 2457c478bd9Sstevel@tonic-gate if ((ofl->ofl_regsyms = libld_calloc(sizeof (Sym_desc *), 2467c478bd9Sstevel@tonic-gate ofl->ofl_regsymsno)) == 0) { 2477c478bd9Sstevel@tonic-gate ofl->ofl_flags |= FLG_OF_FATAL; 2487c478bd9Sstevel@tonic-gate return (0); 2497c478bd9Sstevel@tonic-gate } 2507c478bd9Sstevel@tonic-gate } 2517c478bd9Sstevel@tonic-gate 2527c478bd9Sstevel@tonic-gate ofl->ofl_regsyms[sdp->sd_sym->st_value] = sdp; 2537c478bd9Sstevel@tonic-gate return (1); 2547c478bd9Sstevel@tonic-gate } 255