place.c revision 0e233487902b546a8949e2147ff8af45b1afc77c
/*
* 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
*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Map file parsing and input section to output segment mapping.
*/
#include <stdio.h>
#include <string.h>
#include <debug.h>
#include "msg.h"
#include "_libld.h"
/*
* Each time a section is placed, the function set_addralign()
* is called. This function performs:
*
* . if the section is from an external file, check if this is empty or not.
* If not, we know the segment this section will belong needs a program
* header. (Of course, the program is needed only if this section falls
* into a loadable segment.)
* . compute the Least Common Multiplier for setting the segment alignment.
*/
static void
{
/* A discarded section has no influence on the output */
return;
/*
* If this section has data or will be assigned data
* later, mark this segment not-empty.
*/
return;
}
/*
* Append an input section to an output section
*
* entry:
* ofl - File descriptor
* isp - Input section descriptor
* osp - Output section descriptor
* mstr_only - True if should only append to the merge string section
* list.
*
* exit:
* - If mstr_only is not true, the input section is appended to the
* end of the output section's list of input sections (os_isdescs).
* - If the input section is a candidate for string table merging,
* then it is appended to the output section's list of merge
* candidates (os_mstridescs).
*
* On success, returns True (1). On failure, False (0).
*/
int
{
return (0);
/*
* To be mergeable:
* - The SHF_MERGE|SHF_STRINGS flags must be set
* - String table compression must not be disabled (-znocompstrtab)
* - It must not be the generated section being built to
* replace the sections on this list.
*/
(SHF_MERGE | SHF_STRINGS)) ||
return (1);
/*
* Skip sections with (sh_entsize > 1) or (sh_addralign > 1).
*
* sh_entsize:
* We are currently only able to merge string tables containing
* strings with 1-byte (char) characters. Support for wide
* characters will require our string table compression code
* to be extended to handle larger character sizes.
*
* sh_addralign:
* Alignments greater than 1 would require our string table
* compression code to insert null bytes to move each
* string to the required alignment.
*/
return (1);
}
return (0);
/*
* The SHF_MERGE|SHF_STRINGS flags tell us that the program that
* created the section intended it to be mergeable. The
* FLG_IS_INSTRMRG flag says that we have done validity testing
* and decided that it is safe to act on that hint.
*/
return (1);
}
/*
* Determine whether this input COMDAT section already exists for the associated
* output section. If so, then discard this input section. Otherwise, this
* must be the first COMDAT section, thus it is kept for future comparisons.
*/
static uintptr_t
{
continue;
/*
* If this section hasn't already been identified as discarded,
* generate a suitable diagnostic.
*/
}
/*
* A discarded section does not require assignment to an output
* section. However, if relaxed relocations have been enabled
* (either from -z relaxreloc, or asserted with .gnu.linkonce
* processing), then this section must still be assigned to an
* output section so that the sloppy relocation logic will have
* the information necessary to do its work.
*/
return (1);
else
return (0);
}
/*
* This is a new COMDAT section - so keep it.
*/
return (S_ERROR);
return (1);
}
/*
* Determine whether a GNU group COMDAT section name follows the convention
*
* section-name.symbol-name
*
* Each section within the input file is compared to see if the full section
* name matches the beginning of the COMDAT section, with a following '.'.
* A pointer to the symbol name, starting with the '.' is returned so that the
* caller can strip off the required section name.
*/
static char *
{
continue;
/*
* It's questionable whether this size should be cached in the
* Is_desc. However, this seems an infrequent operation and
* adding Is_desc members can escalate memory usage for large
* link-edits. For now, size the section name dynamically.
*/
}
return (NULL);
}
/*
* GNU .gnu.linkonce sections follow a naming convention that indicates the
* required association with an output section. Determine whether this input
* section follows the convention, and if so return the appropriate output
* section name.
*
* .gnu.linkonce.b.* -> .bss
* .gnu.linkonce.d.* -> .data
* .gnu.linkonce.l.* -> .ldata
* .gnu.linkonce.lb.* -> .lbss
* .gnu.linkonce.lr.* -> .lrodata
* .gnu.linkonce.r.* -> .rodata
* .gnu.linkonce.s.* -> .sdata
* .gnu.linkonce.s2.* -> .sdata2
* .gnu.linkonce.sb.* -> .sbss
* .gnu.linkonce.sb2.* -> .sbss2
* .gnu.linkonce.t.* -> .text
* .gnu.linkonce.tb.* -> .tbss
* .gnu.linkonce.td.* -> .tdata
* .gnu.linkonce.wi.* -> .debug_info
*/
static const char *
gnu_linkonce_sec(const char *ostr)
{
switch (*nstr) {
case 'b':
if (NSTR_CH1('.'))
return (MSG_ORIG(MSG_SCN_BSS));
break;
case 'd':
if (NSTR_CH1('.'))
return (MSG_ORIG(MSG_SCN_DATA));
break;
case 'l':
if (NSTR_CH1('.'))
return (MSG_ORIG(MSG_SCN_LDATA));
return (MSG_ORIG(MSG_SCN_LBSS));
return (MSG_ORIG(MSG_SCN_LRODATA));
break;
case 'r':
if (NSTR_CH1('.'))
return (MSG_ORIG(MSG_SCN_RODATA));
break;
case 's':
if (NSTR_CH1('.'))
return (MSG_ORIG(MSG_SCN_SDATA));
return (MSG_ORIG(MSG_SCN_SDATA2));
return (MSG_ORIG(MSG_SCN_SBSS));
return (MSG_ORIG(MSG_SCN_SBSS2));
break;
case 't':
if (NSTR_CH1('.'))
return (MSG_ORIG(MSG_SCN_TEXT));
return (MSG_ORIG(MSG_SCN_TBSS));
return (MSG_ORIG(MSG_SCN_TDATA));
break;
case 'w':
return (MSG_ORIG(MSG_SCN_DEBUG_INFO));
break;
default:
break;
}
/*
* No special name match found.
*/
return (ostr);
}
/*
* Place a section into the appropriate segment.
*/
Os_desc *
{
int os_ndx;
/*
* Define any sections that must be thought of as referenced. These
* sections may not be referenced externaly in a manner ld(1) can
* discover, but they must be retained (ie. not removed by -zignore).
*/
MSG_SCN_INIT, /* MSG_ORIG(MSG_SCN_INIT) */
MSG_SCN_FINI, /* MSG_ORIG(MSG_SCN_FINI) */
MSG_SCN_EX_RANGES, /* MSG_ORIG(MSG_SCN_EX_RANGES) */
MSG_SCN_EX_SHARED, /* MSG_ORIG(MSG_SCN_EX_SHARED) */
MSG_SCN_CTORS, /* MSG_ORIG(MSG_SCN_CTORS) */
MSG_SCN_DTORS, /* MSG_ORIG(MSG_SCN_DTORS) */
MSG_SCN_EHFRAME, /* MSG_ORIG(MSG_SCN_EHFRAME) */
MSG_SCN_EHFRAME_HDR, /* MSG_ORIG(MSG_SCN_EHFRAME_HDR) */
MSG_SCN_JCR, /* MSG_ORIG(MSG_SCN_JCR) */
0
};
/*
* If this section identfies group members, or this section indicates
* that it is a member of a group, determine whether the section is
* still required.
*/
/*
* If this group has been replaced by another group,
* then this section needs to be discarded.
*/
/*
* Since we're discarding the section, we
* can skip assigning it to an output section.
* The exception is that if the user
* specifies -z relaxreloc, then
* we need to assign the output section so
* that the sloppy relocation logic will have
* the information necessary to do its work.
*/
return ((Os_desc *)0);
}
}
/*
* SHT_GROUP sections can only be included into relocatable
* objects.
*/
return ((Os_desc *)0);
}
}
}
/*
* Always assign SHF_TLS sections to the DATA segment (and then the
* PT_TLS embedded inside of there).
*/
/*
* Traverse the entrance criteria list searching for a segment that
* matches the input section we have. If an entrance criterion is set
* then there must be an exact match. If we complete the loop without
* finding a segment, then sgp will be NULL.
*/
if (enp->ec_segment &&
continue;
continue;
if (enp->ec_attrmask &&
/* LINTED */
continue;
continue;
char *file;
int found = 0;
continue;
if (file[0] == '*') {
const char *basename;
basename++;
found++;
break;
}
} else {
found++;
break;
}
}
}
if (!found)
continue;
}
break;
}
/*
* By default, the output section for an input section has the same
* section name as in the input sections name. COMDAT, SHT_GROUP and
* GNU name translations that follow, may indicate that a different
* output section name be the target for this input section.
*/
/*
* Solaris section names may follow the convention:
*
* section-name%symbol-name
*
* This convention has been used to order the layout of sections within
* segments for objects built with the compilers -xF option. However,
* the final object should not contain individual section headers for
* all such input sections, instead the symbol name is stripped from the
* name to establish the final output section name.
*
* This convention has also been followed for COMDAT and sections
* identified though SHT_GROUP data.
*
* Strip out the % from the section name in all cases except:
*
* i. when '-r' is used without '-M', and
* ii. when '-r' is used with '-M' but without the ?O flag.
*/
oname));
}
}
/*
* GNU section names may follow the convention:
*
* .gnu.linkonce.*
*
* The .gnu.linkonce is a section naming convention that indicates a
* COMDAT requirement. Determine whether this section follows the GNU
* pattern, and if so, determine whether this section should be
* discarded or retained. The comparison of 'g' and 'l' are an
* optimization to skip using strncmp() too much.
*/
MSG_SCN_GNU_LINKONCE_SIZE) == 0)) {
if ((oname =
oname));
}
/*
* Explicitly identify this section type as COMDAT. Also,
* enable lazy relocation processing, as this is typically a
* requirement with .gnu.linkonce sections.
*/
}
/*
* GNU section names may also follow the convention:
*
* section-name.symbol-name
*
* This convention is used when defining SHT_GROUP sections of type
* COMDAT. Thus, any group processing will have discovered any group
* sections, and this identification can be triggered by a pattern
* match section names.
*/
oname));
/*
* Enable lazy relocation processing, as this is typically a
* requirement with GNU COMDAT sections.
*/
}
}
/*
* Assign a hash value now that the output section name has been
* finalized.
*/
/*
* If the link is not 0, then the input section is appended to the
* defined output section. The append occurs at the input section
* pointed to by the link.
*/
if (link) {
/*
* Process any COMDAT section, keeping the first and
* discarding all others.
*/
/*
* Set alignment
*/
return (osp);
}
/*
* Determine if section ordering is turned on. If so, return the
* appropriate os_txtndx. This information is derived from the
* Sg_desc->sg_segorder list that was built up from the Mapfile.
*/
os_ndx = 0;
if (sgp->sg_secorder) {
break;
}
}
}
/*
* Mask of section header flags to ignore when
* matching sections. We are more strict with
* relocatable objects, ignoring only the order
* flags, and keeping sections apart if they differ
* otherwise. This follows the policy that sections
* in a relative object should only be merged if their
* flags are the same, and avoids destroying information
* prematurely. For final products however, we ignore all
* flags that do not prevent a merge.
*/
/*
* Traverse the input section list for the output section we have been
* assigned. If we find a matching section simply add this new section.
*/
idx2 = 0;
if ((ident == osp->os_scnsymndx) &&
((shflags & ~shflagmask) ==
/*
* Process any COMDAT section, keeping the first and
* discarding all others.
*/
/*
* Set alignment
*/
/*
* If this section is a non-empty TLS section indicate
* that a PT_TLS program header is required.
*/
/*
* If is_txtndx is 0 then this section was not
* seen in mapfile, so put it at the end.
* If is_txtndx is not 0 and ?O is turned on
* then check to see where this section should
* be inserted.
*/
} else {
isp) == 0)
}
} else {
}
/*
* If this input section and file is associated to an
* artificially referenced output section, make sure
* they are marked as referenced also. This insures this
* input section and file isn't eliminated when -zignore
* is in effect.
* See -zignore comments when creating a new output
* section below.
*/
if (((ifl &&
if (ifl)
}
return (osp);
}
/*
* Do we need to worry about section ordering?
*/
if (os_ndx) {
/* insert section here. */
break;
else {
continue;
}
} else {
/* insert section here. */
break;
}
continue;
}
/*
* If the new sections identifier is less than that of the
* present input section we need to insert the new section
* at this point.
*/
if (ident < osp->os_scnsymndx)
break;
}
/*
* We are adding a new output section. Update the section header
* count and associated string size.
*/
ofl->ofl_shdrcnt++;
/*
* Create a new output section descriptor.
*/
/*
* Convert COMDAT section to PROGBITS as this the first section of the
* output section. Save any COMDAT section for later processing, as
* additional COMDAT sections that match this section need discarding.
*/
}
/*
* See the translate_link() in update.c.
*/
}
/*
* When -zignore is in effect, user supplied sections and files that are
* not referenced from other sections, are eliminated from the object
* being produced. Some sections, although unreferenced, are special,
* and must not be eliminated. Determine if this new output section is
* one of those special sections, and if so mark it artificially as
* referenced. Any input section and file associated to this output
* section is also be marked as referenced, and thus won't be eliminated
* from the final output.
*/
DBG_ENABLED) {
}
break;
}
}
}
/*
* Setions of SHT_GROUP are added to the ofl->ofl_osgroups
* list - so that they can be updated as a group later.
*/
}
/*
* If this section is a non-empty TLS section indicate that a PT_TLS
* program header is required.
*/
/*
* If a non-allocatable section is going to be put into a loadable
* segment then turn on the allocate bit for this section and warn the
* user that we have done so. This could only happen through the use
* of a mapfile.
*/
}
/*
* Retain this sections identifier for future comparisons when placing
* a section (after all sections have been processed this variable will
* be used to hold the sections symbol index as we don't need to retain
* the identifier any more).
*/
osp->os_scnsymndx = ident;
/*
* Set alignment
*/
/*
* Insert the new section at the offset given by idx2. If no
* position for it was identified above, this will be index 0,
* causing the new section to be prepended to the beginning of
* the section list. Otherwise, it is the index following the section
* that was identified.
*/
return (osp);
}