/*
* 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
*
*/
#define ELF_TARGET_AMD64
#include <stdio.h>
#include <memory.h>
#include <debug.h>
#include "msg.h"
#include "_libld.h"
/*
* The link-editor uses a segment descriptor list to describe the program
* headers, and related output segments, it can potentially create. This
* list is initially seeded using the templates contained in the sg_desc
* array below. Additional segments may be added using a mapfile.
*
* The entries in sg_desc must be put in the order defined by the
* Segment_id enum.
*
* The entries in sg_desc are initialized using the SG_DESC_INIT macro
* for two reasons:
*
* 1) The first field of the Sg_desc struct is a program header
* entry. ELF32_Phdr and ELF64_Phdr have the same fields,
* but their order is different. Use of a macro allows us
* to handle this transparently.
* 2) Most of the fields in the Sg_desc entries are set to 0.
* Use of a macro allows us to hide the clutter.
*
* If a given program header can be referenced via an entrance criteria
* (i.e. can serve as a segment), then it must be given a unique sg_name.
* Program headers that cannot be a segment (PHDR, INTERP, DYNAMIC, etc)
* must have a NULL sg_name --- their program header type identifies them.
*/
#ifdef _ELF64
#else
#endif
/*
* Predefined segment descriptors:
*
* The C language guarantees that a structure containing only fields of
* identical type is indistinguishable from a simple array containing
* the same number of items of the same type. They will have the same
* size, alignment, and internal layout:
*
* - A pointer to one is equivalent to a pointer to the other, and you
* can cast safely between them.
*
* - You can put both into a union, and access the elements within
* either way (by index, or by name).
*
* We use this fact here to create an "array" of predefined segment
* descriptors, assigning each one a mnemonic name that can be used to point
* at it from a predefined entrance criteria descriptor (below). These
* segments are positioned in the default order that will result in the
* output object, unless a mapfile alters things.
*/
typedef struct {
#if defined(_ELF64)
#endif
} predef_seg_t;
(sizeof (predef_seg_t) / sizeof (Sg_desc));
/* psg_phdr */
(FLG_SG_P_TYPE | FLG_SG_P_FLAGS)),
/* psg_interp */
(FLG_SG_P_TYPE | FLG_SG_P_FLAGS)),
/* psg_sunwcap */
(FLG_SG_P_TYPE | FLG_SG_P_FLAGS)),
/* psg_text */
(FLG_SG_P_TYPE | FLG_SG_P_FLAGS)),
/* psg_data */
(FLG_SG_P_TYPE | FLG_SG_P_FLAGS)),
/* psg_bss */
#if defined(_ELF64)
/* psg_lrodata (amd64-only ) */
(FLG_SG_P_TYPE | FLG_SG_P_FLAGS)),
/* psg_ldata (amd64-only ) */
(FLG_SG_P_TYPE | FLG_SG_P_FLAGS)),
#endif
/* psg_dynamic */
(FLG_SG_P_TYPE | FLG_SG_P_FLAGS)),
/* psg_sunwdtrace */
(FLG_SG_P_TYPE | FLG_SG_P_FLAGS)),
/* psg_tls */
(FLG_SG_P_TYPE | FLG_SG_P_FLAGS)),
/* psg_unwind */
(FLG_SG_P_TYPE | FLG_SG_P_FLAGS)),
/* psg_sunwstack */
/* psg_note */
/*
* psg_extra
*
* This segment is referenced by the final entrance criteria descriptor
* to catch any segment not otherwise placed. It cannot be disabled
* via a mapfile.
*/
};
/*
* The processing of input files by the link-editor involves matching the
* input file sections against an ordered list of entrance criteria
* descriptors. The following template defines the built in entrance criteria
* list. This list can be augmented using a mapfile. Each entrance criteria
* is associated with a segment descriptor, providing the means for mapping
* input sections to output segments.
*
* As with the segment descriptors, the EC_DESC_INIT macro is used
* to reduce boilerplate clutter.
*/
_seg_field, ec_flags) \
#if defined(_ELF64) /* (amd64-only) */
#endif
/*
* Explicitly assign the .tdata section to bss. The design of TLS
* provides for initialized data being assigned to a .tdata section,
* and uninitialized data being assigned to a .tbss section. These
* sections should be laid out adjacent to each other, with little or
* no gap between them. A PT_TLS program header is created that
* defines the address range of the two sections. This header is
* passed to libc to instantiate the appropriate thread allocation.
*
* By default a separate bss segment is disabled, however users can
* trigger the creation of a bss segment with a mapfile. By default,
* all bss sections are assigned to the data segment, and the section
* identifiers of .tdata and .tbss ensure that these two sections are
* adjacent to each other.
*
* However, if a bss segment is enabled, the adjacency of the .tdata
* and .tbss sections can only be retained by having an explicit .tdata
* entrance criteria.
*/
#if defined(_ELF64) /* (amd64-only) */
#endif
data, 0),
/*
* Final catchall rule sends remaining sections to "extra"
* NULL segment, which has been tagged as FLG_SG_NODISABLE,
* and which will therefore always accept them.
*/
};
/*
* AVL comparison function for Sg_desc items in ofl_segs_avl.
*
* entry:
* n1, n2 - pointers to nodes to be compared
*
* exit:
* Returns -1 if (n1 < n2), 0 if they are equal, and 1 if (n1 > n2)
*/
static int
{
int rc;
if (rc > 0)
return (1);
if (rc < 0)
return (-1);
return (0);
}
/*
* AVL comparison function for Ent_desc items in ofl_ents_avl.
*
* entry:
* n1, n2 - pointers to nodes to be compared
*
* exit:
* Returns -1 if (n1 < n2), 0 if they are equal, and 1 if (n1 > n2)
*/
static int
{
int rc;
/*
* There are entrance criteria nodes with NULL pointer names,
* but they are never entered into the AVL tree. Hence, we can
* assume that both nodes have names.
*/
if (rc > 0)
return (1);
if (rc < 0)
return (-1);
return (0);
}
/*
* Lookup a segment descriptor by name.
*
* entry:
* ofl - Output descriptor
* name - Name of desired segment
*
* exit:
* On success, returns pointer to descriptor. On failure, returns NULL.
*/
Sg_desc *
{
}
/*
* Look up an entrance criteria record by name
*
* entry:
* mf - Mapfile descriptor
* name - Name of entrance criteria to locate
*
* exit:
* On success, a pointer to the entrace criteria record is
* returned. On failure, NULL is returned.
*
* note:
* Entrance criteria are not required to have names. Only
* named entrance criteria can be looked up via this method.
*/
Ent_desc *
{
}
/*
* Initialize new entrance and segment descriptors and add them as lists to
* the output file descriptor.
*/
{
/*
* Initialize the elf library.
*/
return (S_ERROR);
}
/*
* Initialize internal Global Symbol Table AVL tree
*/
/* Initialize segment AVL tree */
/* Initialize entrance criteria AVL tree */
/*
* Allocate and initialize writable copies of both the entrance and
* segment descriptors.
*
* Note that on non-amd64 targets, this allocates a few more
* elements than are needed. For now, we are willing to overallocate
* a small amount to simplify the code.
*/
return (S_ERROR);
/*
* The data segment and stack permissions can differ:
*
* - Architectural/ABI per-platform differences
* - Whether the object is built statically or dynamically
*
* Those segments so affected have their program header flags
* set here at runtime, rather than in the sg_desc templates above.
*/
#if defined(_ELF64)
#endif
/*
* Traverse the new entrance descriptor list converting the segment
* pointer entries to the absolute address within the new segment
* descriptor list. Add each entrance descriptor to the output file
* list.
*/
return (S_ERROR);
enp++) {
#if defined(_ELF64)
/* Don't use the amd64 entry conditions for non-amd64 targets */
continue;
#endif
AL_CNT_OFL_ENTRANCE) == NULL)
return (S_ERROR);
/*
* The segment pointer is currently pointing at a template
* segment descriptor in sg_desc. Compute its array index,
* and then use that index to compute the address of the
* corresponding descriptor in the writable copy.
*/
enp->ec_segment =
}
/*
* Add each segment descriptor to the segment descriptor list. The
* ones with non-NULL sg_name are also entered into the AVL tree.
* For each loadable segment initialize a default alignment. Note
* that ld(1) and ld.so.1 initialize this differently.
*/
#if defined(_ELF64)
/* Ignore amd64 segment templates for non-amd64 targets */
case SGID_LRODATA:
case SGID_LDATA:
continue;
}
#endif
AL_CNT_SEGMENTS)) == NULL)
return (S_ERROR);
#ifdef NDEBUG /* assert() is enabled */
/*
* Enforce the segment name rule: Any segment that can
* be referenced by an entrance descriptor must have
* a name. Any segment that cannot, must have a NULL
* name pointer.
*/
case PT_LOAD:
case PT_NOTE:
case PT_NULL:
break;
default:
break;
}
#endif
/*
* Add named segment descriptors to the AVL tree to
* provide O(logN) lookups.
*/
}
return (1);
}