version.c revision 6075882998740edfaff4dd844974e188f8bd6793
/*
* 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 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <string.h>
#include <stdio.h>
#include <debug.h>
#include "msg.h"
#include "_libld.h"
/*
* Locate a version descriptor.
*/
Ver_desc *
{
continue;
return (vdp);
}
return (0);
}
/*
* Add a new version descriptor to a version descriptor list. Note, users of
* this are responsible for determining if the version descriptor already
* exists (this can reduce the need to allocate storage for descriptor names
* until it is determined a descriptor need be created (see map_symbol())).
*/
Ver_desc *
{
else
return (vdp);
}
/*
* Now that all explict files have been processed validate any version
* definitions. Insure that any version references are available (a version
* has been defined when it's been assigned an index). Also calculate the
* number of .version section entries that will be required to hold this
* information.
*/
typedef struct {
int ver_sp;
int ver_lmt;
} Ver_Stack;
static uintptr_t
{
static int err = 0;
int tmp_sp;
/*
* If there was any fatal error,
* just return.
*/
return (err);
/*
* if this is called from, ver_check_defs(), initialize sp.
*/
if (flag == 0)
/*
* Check if passed version pointer vp is already in the stack.
*/
Ver_desc *v;
if (v == vp) {
/*
* cyclic dependency.
*/
if (err == 0) {
err = 1;
}
if ((v->vd_flags & FLG_VER_CYCLIC) == 0) {
v->vd_flags |= FLG_VER_CYCLIC;
v->vd_name);
}
}
}
return (err);
}
}
/*
* Push version on the stack.
*/
return (S_ERROR);
}
/*
* Now visit children.
*/
return (S_ERROR);
/*
* Pop version from the stack.
*/
return (err);
}
{
/*
* First check if there are any cyclic dependency
*/
return (S_ERROR);
if (is_cyclic)
unsigned char bind;
continue;
}
/*
* If a version definition contains no symbols this is possibly
* a mapfile error.
*/
/*
* Update the version entry count to account for this new
* version descriptor (the count is the size in bytes).
*/
/*
* Traverse this versions dependency list to determine what
* additional version dependencies we must account for against
* this descriptor.
*/
cnt = 1;
#if defined(__lint)
/* get lint to think `_vdp' is used... */
#endif
cnt++;
}
/*
* Except for the base version descriptor, generate an absolute
* symbol to reflect this version.
*/
continue;
else
bind = STB_GLOBAL;
/*
* If the symbol already exists and is undefined or was
* defined in a shared library, convert it to an
* absolute.
*/
/*
* If the reference originated from a mapfile
* insure we mark the symbol as used.
*/
}
} else {
/*
* If the symbol does not exist create it.
*/
return (S_ERROR);
return (S_ERROR);
}
}
return (1);
}
/*
* Dereference dependencies as a part of normalizing (allows recursion).
*/
static void
{
/*
* If the head of the list was a weak then we only clear out
* weak dependencies, but if the head of the list was 'strong'
* we clear the REFER bit on all dependencies.
*/
}
/*
* If we need to record the versions of any needed dependencies traverse the
* shared object dependency list and calculate what version needed entries are
* required.
*/
{
/*
* Traverse the shared object list looking for dependencies.
*/
continue;
continue;
/*
* If version needed definitions were specified in
* a mapfile ($SPECVERS=) then record those definitions
*/
sdv)) {
return (S_ERROR);
}
return (S_ERROR);
continue;
}
/*
* Scan the version index list and if any weak version
* definition has been referenced by the user promote the
* dependency to be non-weak. Weak version dependencies do not
* cause fatal errors from the runtime linker, non-weak
* dependencies do.
*/
/*
* Mark any weak reference as referred to so as to
* simplify normalization and later version dependency
* manipulation.
*/
}
/*
* Scan the version dependency list to normalize the referenced
* dependencies. Any needed version that is inherited by
* another like version is derefereced as it is not necessary
* to make this part of the version dependencies.
*/
int type;
continue;
}
/*
* Finally, determine how many of the version dependencies need
* to be recorded.
*/
/*
* If a version has been referenced then record it as a
* version dependency.
*/
return (S_ERROR);
need++;
}
}
if (need) {
return (S_ERROR);
}
}
/*
* If no version needed information is required unset the output file
* flag.
*/
if (ofl->ofl_verneedsz == 0)
return (1);
}
/*
* Indicate dependency selection (allows recursion).
*/
static void
{
}
static Ver_index *
{
/*
* Allocate an index array large enough to hold all of the files
* version descriptors.
*/
(count + 1))) == 0)
/*
* Any relocatable object versions, and the `base' version are
* always available.
*/
/*
* If this is a weak version mark it as such. Weak versions
* are always dragged into any version dependencies created,
* and if a weak version is referenced it will be promoted to
* a non-weak version dependency.
*/
/*
* If this version is mentioned in a mapfile
* $ADDVERS syntax then add a FLG_IF_NEEDED flag now
*/
break;
}
}
}
}
/*
* if $ADDVER was specified for this object verify that
* all of it's dependent upon versions were refered to.
*/
int fail = 0;
if (fail == 0) {
fail++;
}
}
}
if (fail)
}
return (vip);
}
/*
* Process a version symbol index section.
*/
int
{
/*
* Verify that the versym is the same size as the linked symbol table.
* If these two get out of sync the file is considered corrupted.
*/
vershdr->sh_entsize)) {
return (1);
}
return (1);
}
/*
* Process a version definition section from an input file. A list of version
* descriptors is created and associated with the input files descriptor. If
* this is a shared object these descriptors will be used to indicate the
* availability of each version. If this is a relocatable object then these
* descriptors will be promoted (concatenated) to the output files image.
*/
{
int relobj;
/*
* If there is no version section then simply indicate that all version
* definitions asked for do not exist.
*/
if (isp == 0) {
}
return (0);
}
/*
* Verify the version revision. We only check the first version
* structure as it is assumed all other version structures in this
* data section will be of the same revision.
*/
relobj = 1;
else
relobj = 0;
/*
* Loop through the version information setting up a version descriptor
* for each version definition.
*/
const char *name;
/*
* Keep track of the largest index for use in creating a
* version index array later, and create a version descriptor.
*/
/* LINTED */
return (S_ERROR);
}
/*
* If we're processing a relocatable object then this version
* definition needs to be propagated to the output file.
* Generate a new output file version and associated this input
* version to it. During symbol processing the version index of
* the symbol will be promoted from the input file to the output
* files version definition.
*/
if (relobj) {
/*
* If no version descriptors have yet been set
* up, initialize a base version to represent
* the output file itself. This `base' version
* catches any internally generated symbols
* (_end, _etext, etc.) and
* serves to initialize the output version
* descriptor count.
*/
if (ofl->ofl_vercnt == 0) {
if (ld_vers_base(ofl) ==
return (S_ERROR);
}
&ofl->ofl_verdesc)) == 0) {
&ofl->ofl_verdesc)) ==
return (S_ERROR);
/* LINTED */
}
}
/*
* Maintain the association between the input version
* descriptor and the output version descriptor so that
* an associated symbols will be assigned to the
* correct version.
*/
}
/*
* Process any dependencies this version may have.
*/
/* LINTED */
&ifl->ifl_verdesc)) == 0) {
&ifl->ifl_verdesc)) ==
return (S_ERROR);
}
return (S_ERROR);
}
}
/*
* Now that we know the total number of version definitions for this
* file, build an index array for fast access when processing symbols.
*/
if ((ifl->ifl_verndx =
return (S_ERROR);
if (relobj)
return (1);
/*
* If this object has version control definitions against it then these
* must be processed so as to select those version definitions to which
* symbol bindings can occur. Otherwise simply mark all versions as
* available.
*/
int found = 0;
found++;
break;
}
}
if (found)
else {
}
}
} else {
int cnt;
}
}
/*
* If this is an explict dependency indicate that this file is a
* candidate for requiring version needed information to be recorded in
* the image we're creating.
*/
return (1);
}
/*
* Process a version needed section.
*/
{
/*
* Verify the version revision. We only check the first version
* structure as it is assumed all other version structures in this
* data section will be of the same revision.
*/
}
/*
* Loop through the version information setting up a version descriptor
* for each version definition.
*/
const char *name;
/*
* Set up a shared object descriptor and add to it the necessary
* needed versions. This information may also have been added
* by a mapfile (see map_dash()).
*/
return (S_ERROR);
}
if (!(sdv =
return (S_ERROR);
return (S_ERROR);
}
}
return (1);
}
/*
* If a symbol is obtained from a versioned relocatable object then the symbols
* version association must be promoted to the version definition as it will be
* represented in the output file.
*/
void
{
/*
* A version symbol index of 0 implies the symbol is local. A value of
* VER_NDX_GLOBAL implies the symbol is global but has not been
* assigned to a specfic version definition.
*/
if (vndx == 0) {
return;
}
if (vndx == VER_NDX_ELIMINATE) {
return;
}
if (vndx == VER_NDX_GLOBAL) {
return;
}
/*
* Any other version index requires association to the appropriate
* version definition.
*/
return;
}
/*
* Promote the symbols version index to the appropriate output version
* definition.
*/
}
}
/*
* If any versioning is called for make sure an initial version descriptor is
* assigned to represent the file itself. Known as the base version.
*/
Ver_desc *
{
const char *name;
/*
* Determine the filename to associate to the version descriptor. This
* is either the SONAME (if one has been supplied) or the basename of
* the output file.
*/
while (*str != '\0') {
if (*str++ == '/')
}
if (name == 0)
}
/*
* Generate the version descriptor.
*/
/* LINTED */
/*
* Assign the base index to this version and initialize the output file
* descriptor with the number of version descriptors presently in use.
*/
return (vdp);
}
/*
* Now that all input shared objects have been processed, verify that all
* version requirements have been met. Any version control requirements will
* have been specified by the user (and placed on the ofl_oscntl list) and are
* verified at the time the object was processed (see ver_def_process()).
* Here we process all version requirements established from shared objects
* themselves (ie,. NEEDED dependencies).
*/
int
{
char *nv;
/*
* As with the runtime environment, disable all version verification if
* requested.
*/
#if defined(_ELF64)
#else
#endif
return (1);
continue;
/*
* If this file contains no version definitions then ignore
* any versioning verification. This is the same model as
* carried out by ld.so.1 and is intended to allow backward
* compatibility should a shared object with a version
* requirment be returned to an older system on which a
* non-versioned shared object exists.
*/
continue;
/*
* If individual versions were specified for this file make
* sure that they actually exist in the appropriate file, and
* that they are available for binding.
*/
int found = 0;
found++;
break;
}
}
if (found) {
}
} else {
}
}
}
return (1);
}