/*
* 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
*/
/*
*/
/*
* Processing of SHF_ORDERED sections.
*/
#include <stdio.h>
#include <fcntl.h>
#include <link.h>
#include <debug.h>
#include "msg.h"
#include "_libld.h"
/*
* Section Ordering History/Background:
*
* There are two forms of section ordering, SHF_ORDERED, and SHF_LINK_ORDER.
*
* SHF_ORDERED was invented at Sun in order to support the PowerPC port
* of Solaris 2.6, which used it for sorting tag words which describe
* the state of callee saves registers for given PC ranges. It was defined
* in the OS specific ELF section flag range. Some other values were defined
* at the same time:
* SHF_EXCLUDE - Section is to be excluded from executables or shared
* objects, and only kept in relocatable object output.
* SHN_BEFORE/SHN_AFTER - Sections are placed before/after all other
* sections, in the order they are encountered by the linker.
* Although initially conceived to support the PowerPC, the functionality
* was implemented for all platforms, and was later used to manage C++
* exceptions and stack unwinding. The PowerPC port was discontinued after
* one release, but SHF_ORDERED lives on.
*
* SHF_LINK_ORDER was invented later by the wider ELF community, and is
* therefore assigned a value in the generic ELF section flag range. It is
* essentially a simpler version of SHF_ORDERED, dispensing with some
* unnecessary features. The Solaris implementation of SHF_LINK_ORDER uses
* SHF_EXCLUDE, and SHF_BEFORE/SHN_AFTER as well, but it appears that these
* are still Solaris-only extensions not used by other implementations.
* SHF_LINK_ORDER has superseded SHF_ORDERED. The older mechanism is
* supported for the benefit of old pre-existing objects.
*
* -----
*
* SHF_ORDERED offers two distinct and separate abilities:
*
* (1) To specify the output section
* (2) To optionally be sorted relative to other sorted sections,
* using a non-sorted section as a sort key.
*
* To do this, it uses both the sh_link, and sh_info fields:
*
* sh_link
* Specifies the output section to receive this input section.
* The sh_link field of an SHF_ORDERED section forms a linked list of
* sections, all of which must have identical section header flags
* (including SHF_ORDERED). The list is terminated by a final section
* with a sh_link that points at itself. All input sections in this list
* are assigned to the output section of the final section in the list.
* Hence, if a section points at itself, the effect is that it gets
* assigned to an output section in the usual default manner (i.e. an
* output section with the same name as the input). However, it can
* point at any arbitrary other section. This is a way to put a section
* with one name into an output section with a different name. It should
* be noted that this is of little value overall, because the link-editor
* already supports a more general feature for directing input sections
* to output sections: An input section named .text%foo will be sent to
* an output section named ".text", and this works for all sections,
* not just ordered ones.
*
* sh_info
* If sh_info is in the range (1 <= value < shnum), then this input section
* is added to the group of sorted sections. The section referenced by
* sh_info must be unsorted, and is used as the sort key.
*
*
* If sh_info is "invalid" (typically 0), then this section is added to
* the group of non-sorted sections, and goes into the output file in the
* order it arrives. This is not a valuable feature, as the same effect
* can be achieved more simply by not setting SHF_ORDERED at all.
*
* SHF_LINK_ORDER is a simplification of SHF_ORDERED. It uses sh_link to specify
* the section to use as a sort key and sh_info is set to 0. The standard
* ".text%foo" mechanism is used to direct input sections to output sections,
* and unordered sections indicate that by not setting SHF_LINK_ORDER.
*/
/*
* A "keyshndx" is the section index for the unordered section that should
* be used as a sort key for a ordered section. Verify that the given
* keyshndx is valid.
*
* exit:
* Returns 0 if the keyshndx is valid. A non-zero DBG_ORDER_ code is
* returned if the keyshndx is not valid to describe the problem.
*/
inline static Word
{
return (0);
/*
* Validate the key range.
*/
return (DBG_ORDER_LINK_OUTRANGE);
/*
* The section pointed to by keyshndx should not be an ordered section.
* Strictly speaking, we could test for SHF_ORDERED here instead of
* ALL_SHF_ORDER as the two ordering flags are not supposed to be
* mixed. Using ALL_SHF_ORDER costs the same and ensures that such
* mixing doesn't go undetected.
*/
return (DBG_ORDER_INFO_ORDER);
return (0);
}
/*
* The sh_link field of an SHF_ORDERED section forms a linked list of
* sections. The list is terminated by a final section with a sh_link
* that points at itself. Given the index of an SHF_ORDERED section, find
* the index of the final section in the list.
*
* entry:
* ofl - Output file descriptor
* ifl - Input file descriptor
* ndx - Section index of SHF_ORDERED section
* alt_os_name - Address of pointer to string. If the final section
* name is different than the section given by ndx, *alt_os_name
* will be updated with the name of the final section. The caller
* should initialize *alt_os_name to NULL before calling
* this routine.
*
* exit:
* On success: If the final section is different than the section
* given by ndx, then *alt_os_name is set to its name. TRUE is returned.
*
* On failure, FALSE is returned.
*/
static Boolean
const char **alt_os_name)
{
int error = 0;
/*
* Traverse the list until we find the termination, or encounter
* an invalid condition in the object that prevents ordering.
*/
do {
/*
* Obtain index of next section in list. Ensure it is in range.
*/
break;
}
/* The section flags must match exactly */
/*
* The case where the next section in the list does
* not have the same ordered flag set as the original
* ordered section gets a unique error code. This
*/
break;
}
/*
* The sh_info field specifies the section index of an
* unorderd section which will be used as a sort key.
* Ensure it is in range. If not, we terminate the list
* at the current node instead of continuing on.
*/
break;
/* If the section points at itself, it terminates the list */
break;
/*
* Advance to next section in list
*/
/*
* If we loop more times than the input file has sections,
* we have encountered a malformed object in which the list
* of SHF_ORDERED sections has a cycle. This can only happen
* if the compiler generating the object has a bad bug.
*/
break;
}
/* CONSTANTCONDITION */
} while (1);
/*
* If we have found a problem, issue a debug diagnostic and map
* the output section to 0. This indicates that the section should
* remove the ordering flag and treat it as a standard section.
*/
if (error != 0) {
isp2_ndx = 0;
}
/* Report success */
if (isp2_ndx != 0) {
/*
* If the destination section is different than the input
* section, then set *alt_os_name to the destination name.
*/
return (TRUE);
}
/* If we get here, there is no valid destination */
return (FALSE);
}
/*
* Called when an ordered section has a problem that prevents ordering.
* The order flag is removed, and then the section is placed as an
* unsorted section.
*/
static uintptr_t
{
}
/*
* Process ordered input section. Called from process_elf() after
* all the non-ordered sections have been placed.
*
* entry:
* ofl - Output file descriptor
* ifl - Input file descriptor
* ndx - Section index of SHF_ORDERED section
*
* exit:
*/
{
int error = 0;
/*
* Obtain the sort key section index for this ordered section.
* SHF_ORDERED uses sh_info, while SHF_LINK_ORDER uses sh_link.
* In order for this function to be called, one of SHF_ORDERED
* or SHF_LINK_ORDER must be set. Testing for one implies the
* state of the other.
*/
/*
* Validate the sort key section index. If something is wrong,
* fall back to treating it as a non-ordered section.
*/
}
/*
* If SHF_ORDERED is in effect, validate the destination section
* name given by sh_link, and set alt_os_name to the name of the
* destination if it differs from the section being processed.
*/
if ((shflags & SHF_ORDERED) &&
/*
* Place the section into its output section. It's possible that this
* section is discarded (possibly because it's defined COMDAT), in
* which case we're done.
*/
}
/*
* If the output section is not yet on the ordered list, place it on
* the list.
*/
/*
* Output section has been found - set up its sorting information.
*/
return (S_ERROR);
}
/*
* Indicate that this ordered input section will require a
* sort key. Propagate the key requirement through to the
* associated output section, segment and file, to trigger
* the sort key creation. See ld_sec_validate();
*/
}
}
/*
* Traverse all segments looking for section ordering information that hasn't
* been used. If found give a warning message to the user. Also, check if
* there are any ordered key sections, and if so set up sort key values.
*/
void
{
}
}
continue;
continue;
/*
* The input sections used as sort keys are required
* to be unordered, so we only have to look at the
* DEFAULT list of input sections.
*/
}
}
}
}
static int
{
else
else
return (1);
return (-1);
return (0);
}
/*
* Sort ordered input sections
*/
{
/*
* If this output section has a non-empty list of ordered
* input sections, sort their APlist in place into their
* final order.
*/
if (apl_nitems != 0)
}
return (0);
}