/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright (c) 1988 AT&T
* All Rights Reserved
*
*/
/*
* Symbol table resolution
*/
#define ELF_TARGET_AMD64
#include <stdio.h>
#include <debug.h>
#include "msg.h"
#include "_libld.h"
/*
* Categorize the symbol types that are applicable to the resolution process.
*/
typedef enum {
} Symtype;
/*
* Do nothing.
*/
/* ARGSUSED0 */
static void
{
}
static void
{
/* Warnings are only issued when -z verbose is specified */
return;
}
/*
* STV_VISIBILITY rules for STV_DEFAULT/INTERNAL/HIDDEN/PROTECTED say that the
* most restrictive visibility value should be taken. The precedence is:
*
* (most restrictive) INTERNAL -> HIDDEN -> PROTECTED -> DEFAULT (least)
*
* The STV_EXPORT and STV_SINGLETON visibilities are slightly different, in that
* the visibility must remain global and can not be reduced in any way.
*
* Resolution of different visibilities between two relocatable objects can
* take the following actions:
*
* i. if applicable, the most restrictive action is silently taken.
* ii. if a mapfile visibility definition competes with a more restrictive
* relocatable object definition, then a warning is generated, but the
* the more restrictive visibility is taken.
* iii. in the case of conflicts with an EXPORTED or SINGLETON symbol with
* any type of visibility between relocatable objects, the combination
* is deemed fatal.
*
* new visibility
* D I H P X S
* ------------------------------------------------------------
* D | D I(mw) H(mw) P X S
* where:
*
* mw - mapfile warning: if the original symbol originates from a mapfile
* then warn the user that their scope definition is being overridden.
* of - object definitions are fatal: any combination of relocatable object
* visibilities that conflict with a SINGLETON and EXPORTED are fatal.
*
* Note, an eliminate symbol (STV_ELIMINATE) is treated as hidden (STV_HIDDEN)
* for processing through this state table.
*/
static Half
{
/*
* If the original visibilities are eliminate, assign them hidden for
* the state table processing. The original visibility, rather than
* the working visibility, will be returned to the caller.
*/
if (wovis == STV_ELIMINATE)
wovis = STV_HIDDEN;
if (wnvis == STV_ELIMINATE)
wnvis = STV_HIDDEN;
/*
* The most complex visibility resolution is between two relocatable
* objects. However, in the case of SINGLETONS we also want to catch
* any singleton definitions within shared objects. Relocatable objects
* that bind to these symbols inherit the singleton visibility as this
* efficiently triggers ld.so.1 into carrying out the appropriate
* runtime symbol search. Any other resolution between a relocatable
* object and a shared object will retain the relocatable objects
* visibility.
*/
return (STV_SINGLETON);
else
return (ovis);
}
return (STV_SINGLETON);
else
return (nvis);
}
/*
* If the visibilities are the same, we're done. If the working
* visibilities differ from the original, then one must have been
* STV_HIDDEN and the other STV_ELIMINATE.
*/
return (nvis);
else
return (STV_ELIMINATE);
}
/*
* An EXPORTED symbol or SINGLETON symbol can not be demoted, any
* conflicting visibility from another object is fatal. A conflicting
* visibility from a mapfile produces a warning, as the mapfile
* definition can be overridden.
*/
(wovis != STV_SINGLETON)) {
} else {
}
}
return (nvis);
}
if (wovis == STV_SINGLETON) {
return (STV_SINGLETON);
} else {
}
return (nvis);
}
if (wovis == STV_EXPORTED) {
if (wnvis == STV_SINGLETON)
return (STV_SINGLETON);
if (wnvis == STV_DEFAULT)
return (STV_EXPORTED);
} else {
}
return (nvis);
}
/*
* Now that symbols with the same visibility, and all instances of
* SINGLETON's have been dealt with, we're left with visibilities that
* differ, but can be dealt with in the order of how restrictive the
* visibilities are. When a differing visibility originates from a
* mapfile definition, produces a warning, as the mapfile definition
* can be overridden by the relocatable object.
*/
if ((wnvis == STV_INTERNAL) &&
}
return (STV_INTERNAL);
if ((wnvis == STV_HIDDEN) &&
}
/*
* In the case of STV_ELIMINATE and STV_HIDDEN, the working
* visibility can differ from the original visibility, so make
* sure to return the original visibility.
*/
return (STV_ELIMINATE);
else
return (STV_HIDDEN);
return (STV_PROTECTED);
return (STV_DEFAULT);
}
/*
* Check if two symbols types are compatible
*/
/*ARGSUSED4*/
static void
{
/*
* Perform any machine specific type checking.
*/
return;
/*
* NOTYPE's can be combined with other types, only give an error if
* combining two differing types without NOTYPE.
*/
return;
}
/*ARGSUSED4*/
static void
{
/*
* Perform any machine specific type checking.
*/
}
/*
* Promote the symbols reference.
*/
static void
/* ARGSUSED4 */
{
/*
* If the old symbol is from a shared object and the new symbol is a
* reference from a relocatable object, promote the old symbols
* reference.
*/
/*
* If this is an undefined symbol it must be a relocatable
* object overriding a shared object. In this case also
* override the reference name so that any undefined symbol
* diagnostics will refer to the relocatable object name.
*/
/*
* If this symbol is an undefined, or common, determine whether
* it is a global or weak reference (see build_osym(), where
* REF_DYN_NEED definitions are returned back to undefines).
*/
(shndx == SHN_COMMON))) &&
}
}
/*
* Override a symbol.
*/
static void
{
/*
* In the case of a WEAK UNDEF symbol don't let a symbol from an
* unavailable object override the symbol definition. This is because
* this symbol *may* not be present in a future object and by promoting
* this symbol we are actually causing bindings (PLTS) to be formed
* to this symbol. Instead let the 'generic' weak binding take place.
*/
return;
/*
* This symbol has already been compared to an SO definition,
* as per the runtime behavior, ignore extra definitions.
*/
return;
/*
* Mark the symbol as available and copy the new symbols contents.
*/
/*
* If the new symbol has PROTECTED visibility, mark it. If a PROTECTED
* symbol is copy relocated, a warning message will be printed. See
* reloc_exec().
*/
else
/*
* Establish the symbols reference. If the new symbol originates from a
* relocatable object then this reference becomes needed, otherwise
* the new symbol must be from a shared object. In this case only
* promote the symbol to needed if we presently have a reference from a
* relocatable object.
*/
/*
* If this is an undefined symbol, then we can only be
* attempting to override an existing undefined symbol.
* The original symbol is either:
*
* - a mapfile definition
* - a previous relocatable object whose visibility
* or type should be overridden by this new symbol
* - a previous shared object
*
* If the original undefined symbol stems from a mapfile
* then don't alter the reference file name. Should we
* end up with some form of 'undefined' symbol error,
* the characteristics of that error are most likely to
* have originated from a mapfile.
*
* Otherwise, update the reference file name to indicate
* this symbol.
*/
} else {
/*
* Under -Bnodirect, all exported interfaces that have
* not explicitly been defined protected or directly
* bound to, are tagged to prevent direct binding.
*/
(FLG_SY_PROTECT | FLG_SY_DIR)) == 0))
}
/*
* If this symbol is an undefined, or common, determine whether
* it is a global or weak reference (see build_osym(), where
* REF_DYN_NEED definitions are returned back to undefines).
*/
((nsdflags & FLG_SY_SPECSEC) &&
else
} else {
/*
* Determine the symbols availability. A symbol is determined
* to be unavailable if it belongs to a version of a shared
* object that this user does not wish to use, or if it belongs
* to an implicit shared object.
*/
if (ifl->ifl_vercnt) {
/*
* If this is the first occurrence of an
* unavailable symbol record it for possible
* use in later error diagnostics
* (see sym_undef).
*/
}
}
}
/*
* Make sure any symbol association maintained by the original symbol
* is cleared and then update the symbols file reference.
*/
}
/*
* Update the input section descriptor to that of the new input file
*/
if (((nsdflags & FLG_SY_SPECSEC) == 0) &&
}
/*
* Resolve two undefines (only called for two relocatable objects).
*/
static void
{
/*
* If two relocatable objects define a weak and non-weak undefined
* reference, take the non-weak definition.
*
* -- or --
*
* If two relocatable objects define a NOTYPE & another, then
* take the other.
*/
return;
}
}
/*
* Resolve two real definitions.
*/
static void
{
int warn = 0;
/*
* If both definitions are from relocatable objects, and have non-weak
* binding then this is a fatal condition.
*/
0, &inv_buf2));
return;
}
/*
* Perform any machine specific type checking.
*/
return;
/*
* Check the symbols type and size.
*/
0, &inv_buf2));
warn++;
warn++;
}
}
/*
* Having provided the user with any necessary warnings, take the
* appropriate symbol:
*
* - if one symbol is from a shared object and the other is from a
* relocatable object, take the relocatable objects symbol (the
* run-time linker is always going to find the relocatable object
* symbol regardless of the binding), else
*
* - if both symbols are from relocatable objects and one symbol is
* weak take the non-weak symbol (two non-weak symbols would have
* generated the fatal error condition above unless -z muldefs is
* in effect), else
*
* - take the first symbol definition encountered.
*/
if (warn)
return;
if (warn)
return;
} else {
if (warn)
return;
}
}
/*
* Resolve a real and tentative definition.
*/
static void
{
int warn = 0;
/*
* Special rules for functions.
*
* - If both definitions are from relocatable objects, have the same
* binding (ie. two weaks or two non-weaks), and the real
* definition is a function (the other must be tentative), treat
* this as a multiply defined symbol error, else
*
* - if the real symbol definition is a function within a shared
* library and the tentative symbol is a relocatable object, and
* the tentative is not weak and the function real, then retain the
* tentative definition.
*/
} else {
}
0, &inv_buf2));
return;
return;
else {
return;
}
}
return;
} else
return;
}
}
if (nsdflags & FLG_SY_TENTSYM)
/*
* Check the symbols type and size.
*/
0, &inv_buf2));
warn++;
/*
* If both definitions are from relocatable objects we have a
* potential fatal error condition. If the tentative is larger
* than the real definition treat this as a multiple definition.
* Note that if only one symbol is weak, the non-weak will be
* taken.
*/
} else {
warn++;
}
}
}
/*
* Having provided the user with any necessary warnings, take the
* appropriate symbol:
*
* - if the original symbol is from relocatable file and it is
* a protected tentative symbol, take the original one.
*
* - if the original symbol is from shared object and the new
* symbol is a protected tentative symbol from a relocatable file,
* take the new one.
*
* - if the original symbol is tentative, and providing the original
* symbol isn't strong and the new symbol weak, take the real
* symbol, else
*
* - if the original symbol is weak and the new tentative symbol is
* strong take the new symbol.
*
* Refer to the System V ABI Page 4-27 for a description of the binding
* requirements of tentative and weak symbols.
*/
(ovis == STV_PROTECTED)) {
return;
}
(nvis == STV_PROTECTED)) {
return;
}
if (warn)
return;
}
if (warn)
return;
} else {
if (warn)
return;
}
}
/*
* Resolve two tentative symbols.
*/
static void
{
#if defined(_ELF64)
/*
* If the original and new symbols are both COMMON, but of
* a different size model, take the small one.
*/
/*
* Take the original symbol.
*/
return;
/*
* Take the new symbol.
*/
nsdflags);
return;
}
}
#endif
/*
* Check the alignment of the symbols. This can only be tested for if
* the symbols are not real definitions to a SHT_NOBITS section (ie.
* they were originally tentative), as in this case the symbol would
* have a displacement value rather than an alignment. In other words
* we can only test this for two relocatable objects.
*/
/* BEGIN CSTYLED */
(nsdflags & FLG_SY_SPECSEC) &&
#if defined(_ELF64)
(nsdflags & FLG_SY_SPECSEC) &&
#else
#endif
/* END CSTYLED */
const char *file;
} else {
}
/*
* If the smaller alignment fits smoothly into the
* larger alignment - we take it with no warning.
*/
alignscompliment = 1;
else
alignscompliment = 0;
/*
* Having provided the necessary warning indicate which
* relocatable object we are going to take.
*
* - if one symbol is weak and the other is non-weak
* take the non-weak symbol, else
*
* - take the largest alignment (as we still have to check
* the symbols size simply save the largest value for
* updating later).
*/
else {
}
}
/*
* Check the size of the symbols.
*/
const char *file;
/*
* This symbol has already been compared to an SO definition,
* as per the runtime behavior, ignore extra definitions.
*/
return;
}
/*
* Having provided the necessary warning indicate what course
* of action we are going to take.
*
* - if the file types differ, take the relocatable object
* and apply the largest symbol size, else
* - if one symbol is weak and the other is non-weak, take
* the non-weak symbol, else
* - simply take the largest symbol reference.
*/
}
} else {
}
}
} else
} else {
} else
}
if (size)
} else {
/*
* If the sizes are the same
*
* - if the file types differ, take the relocatable object,
* else
*
* - if one symbol is weak and the other is non-weak, take
* the non-weak symbol, else
*
* - take the first reference.
*/
return;
else
}
/*
* Enforce the largest alignment if necessary.
*/
if (value)
}
/*
* Symbol resolution state table. `Action' describes the required
* procedure to be called (if any).
*/
/* defined undef tent */
/* ET_REL ET_REL ET_REL */
/* defined undef tent */
/* ET_DYN ET_DYN ET_DYN */
};
{
/*
* Determine the original symbols definition (defines row in Action[]).
*/
if (osdflags & FLG_SY_TENTSYM)
row = SYM_TENTATIVE;
row = SYM_UNDEFINED;
else
row = SYM_DEFINED;
/*
* If the input file is an implicit shared object then we don't need
* to bind to any symbols within it other than to verify that any
* undefined references will be closed (implicit shared objects are only
* processed when no undefined symbols are required as a result of the
* link-edit (see process_dynamic())).
*/
(row != SYM_UNDEFINED))
return (1);
/*
* Finish computing the Action[] row by applying the symbols reference
* together with the input files type.
*/
/*
* If either the original or new symbol originates from a relocatable
* object, determine the appropriate visibility for the resolved symbol.
*/
/*
* Determine the new symbols definition (defines column in Action[]).
*/
if ((nsdflags & FLG_SY_SPECSEC) &&
#if defined(_ELF64)
(nsdflags & FLG_SY_SPECSEC) &&
#endif
} else {
/*
* If the new symbol is from a shared library and it is
* associated with a SHT_NOBITS section then this symbol
* originated from a tentative symbol.
*/
}
}
}
/*
* Record the input filename on the defined files list for possible
* later diagnostics. The `sa_dfiles' list is used to maintain the list
* of shared objects that define the same symbol. This list is only
* generated when the -m option is in effect and is used to list
* multiple (interposed) definitions of a symbol (refer to ldmap_out()).
*/
((nsdflags & FLG_SY_SPECSEC) == 0))
AL_CNT_SDP_DFILES) == NULL)
return (S_ERROR);
/*
* Perform the required resolution.
*/
/*
* Apply any visibility requirements. If a SINGLETON has been
* established, make sure no symbol reduction indicators remain
* associated with the symbol, and indicate that the symbol can not
* be directly bound to.
*/
if (vis == STV_EXPORTED)
else {
ofl->ofl_flags1 |=
}
}
} else if (vis == STV_PROTECTED) {
} else if (vis == STV_ELIMINATE) {
}
}
/*
* If the symbol has been resolved to the new input file, and this is
* a versioned relocatable object, then the version information of the
* new symbol must be promoted to the versioning of the output file.
*/
/*
* Determine whether a mapfile reference has been satisfied. Mapfile
* symbol references augment symbols that should be contributed from
* the relocatable objects used to build the output image. If a
* relocatable object doesn't provide one of the mapfile symbol
* references then somethings amiss, and will be flagged during symbol
* validation.
*/
/*
* Extern and parent references are satisfied by references from
* a relocatable object. Note that we let *any* symbol type
* satisfy this reference, to be as flexible as possible with
* user written mapfiles. It could be questionable, for
* example, if what a user expects to be an extern reference is
* actually found to be a definition in a relocatable object.
*
* Any other mapfile reference (typically for versioning
* information) simply augments a relocatables definition.
*/
}
/*
* Make sure any special symbol requirements are carried over.
*/
return (1);
}