xref: /illumos-gate/usr/src/cmd/sgs/libld/common/entry.c (revision 0bc0887e)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
55aefb655Srie  * Common Development and Distribution License (the "License").
65aefb655Srie  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
215aefb655Srie 
227c478bd9Sstevel@tonic-gate /*
237c478bd9Sstevel@tonic-gate  *	Copyright (c) 1988 AT&T
247c478bd9Sstevel@tonic-gate  *	  All Rights Reserved
257c478bd9Sstevel@tonic-gate  *
261007fd6fSAli Bahrami  * Copyright (c) 1991, 2010, Oracle and/or its affiliates. All rights reserved.
277c478bd9Sstevel@tonic-gate  */
287c478bd9Sstevel@tonic-gate 
29ba2be530Sab #define	ELF_TARGET_AMD64
30ba2be530Sab 
317c478bd9Sstevel@tonic-gate #include	<stdio.h>
327c478bd9Sstevel@tonic-gate #include	<memory.h>
335aefb655Srie #include	<debug.h>
347c478bd9Sstevel@tonic-gate #include	"msg.h"
357c478bd9Sstevel@tonic-gate #include	"_libld.h"
367c478bd9Sstevel@tonic-gate 
377c478bd9Sstevel@tonic-gate /*
3869112eddSAli Bahrami  * The link-editor uses a segment descriptor list to describe the program
3969112eddSAli Bahrami  * headers, and related output segments, it can potentially create. This
4069112eddSAli Bahrami  * list is initially seeded using the templates contained in the sg_desc
4169112eddSAli Bahrami  * array below. Additional segments may be added using a mapfile.
42ba2be530Sab  *
4369112eddSAli Bahrami  * The entries in sg_desc must be put in the order defined by the
4469112eddSAli Bahrami  * Segment_id enum.
45ba2be530Sab  *
4669112eddSAli Bahrami  * The entries in sg_desc are initialized using the SG_DESC_INIT macro
47ba2be530Sab  * for two reasons:
48ba2be530Sab  *
49ba2be530Sab  *	1) The first field of the Sg_desc struct is a program header
50ba2be530Sab  *		entry. ELF32_Phdr and ELF64_Phdr have the same fields,
51ba2be530Sab  *		but their order is different. Use of a macro allows us
52ba2be530Sab  *		to handle this transparently.
53ba2be530Sab  *	2) Most of the fields in the Sg_desc entries are set to 0.
54ba2be530Sab  *		Use of a macro allows us to hide the clutter.
5569112eddSAli Bahrami  *
5669112eddSAli Bahrami  * If a given program header can be referenced via an entrance criteria
5769112eddSAli Bahrami  * (i.e. can serve as a segment), then it must be given a unique sg_name.
5869112eddSAli Bahrami  * Program headers that cannot be a segment (PHDR, INTERP, DYNAMIC, etc)
5969112eddSAli Bahrami  * must have a NULL sg_name --- their program header type identifies them.
607c478bd9Sstevel@tonic-gate  */
61ba2be530Sab #ifdef _ELF64
6257ef7aa9SRod Evans #define	SG_DESC_INIT(id, p_type, p_flags, sg_name, sg_flags) \
6357ef7aa9SRod Evans 	{ id, { p_type, p_flags, 0, 0, 0, 0, 0, 0}, \
6469112eddSAli Bahrami 	    sg_name, 0, 0, NULL, NULL, NULL, sg_flags, NULL, 0, NULL}
65ba2be530Sab #else
6657ef7aa9SRod Evans #define	SG_DESC_INIT(id, p_type, p_flags, sg_name, sg_flags) \
6757ef7aa9SRod Evans 	{ id, { p_type, 0, 0, 0, 0, 0, p_flags, 0}, \
6869112eddSAli Bahrami 	    sg_name, 0, 0, NULL, NULL, NULL, sg_flags, NULL, 0, NULL}
69ba2be530Sab #endif
70ba2be530Sab 
7169112eddSAli Bahrami /*
7269112eddSAli Bahrami  * Predefined segment descriptors:
7369112eddSAli Bahrami  *
7469112eddSAli Bahrami  * The C language guarantees that a structure containing only fields of
7569112eddSAli Bahrami  * identical type is indistinguishable from a simple array containing
7669112eddSAli Bahrami  * the same number of items of the same type. They will have the same
7769112eddSAli Bahrami  * size, alignment, and internal layout:
7869112eddSAli Bahrami  *
7969112eddSAli Bahrami  * -	A pointer to one is equivalent to a pointer to the other, and you
8069112eddSAli Bahrami  *	can cast safely between them.
8169112eddSAli Bahrami  *
8269112eddSAli Bahrami  * -	You can put both into a union, and access the elements within
8369112eddSAli Bahrami  *	either way (by index, or by name).
8469112eddSAli Bahrami  *
8569112eddSAli Bahrami  * We use this fact here to create an "array" of predefined segment
8669112eddSAli Bahrami  * descriptors, assigning each one a mnemonic name that can be used to point
8769112eddSAli Bahrami  * at it from a predefined entrance criteria descriptor (below). These
8869112eddSAli Bahrami  * segments are positioned in the default order that will result in the
8969112eddSAli Bahrami  * output object, unless a mapfile alters things.
9069112eddSAli Bahrami  */
9169112eddSAli Bahrami typedef struct {
9269112eddSAli Bahrami 	Sg_desc	psg_phdr;
9369112eddSAli Bahrami 	Sg_desc psg_interp;
9469112eddSAli Bahrami 	Sg_desc psg_sunwcap;
9569112eddSAli Bahrami 	Sg_desc psg_text;
9669112eddSAli Bahrami 	Sg_desc psg_data;
9769112eddSAli Bahrami 	Sg_desc psg_bss;
9869112eddSAli Bahrami #if	defined(_ELF64)
9969112eddSAli Bahrami 	Sg_desc	psg_lrodata;	/* (amd64-only) */
10069112eddSAli Bahrami 	Sg_desc psg_ldata;	/* (amd64-only) */
10169112eddSAli Bahrami #endif
10269112eddSAli Bahrami 	Sg_desc	psg_dynamic;
10369112eddSAli Bahrami 	Sg_desc	psg_sunwdtrace;
10469112eddSAli Bahrami 	Sg_desc	psg_tls;
10569112eddSAli Bahrami 	Sg_desc	psg_unwind;
10669112eddSAli Bahrami 	Sg_desc	psg_sunwstack;
10769112eddSAli Bahrami 	Sg_desc	psg_note;
10869112eddSAli Bahrami 	Sg_desc	psg_extra;
10969112eddSAli Bahrami } predef_seg_t;
11069112eddSAli Bahrami 
11169112eddSAli Bahrami static const size_t predef_seg_nelts =
11269112eddSAli Bahrami 	(sizeof (predef_seg_t) / sizeof (Sg_desc));
11369112eddSAli Bahrami 
11469112eddSAli Bahrami static predef_seg_t sg_desc = {
11569112eddSAli Bahrami 	/* psg_phdr */
11669112eddSAli Bahrami 	SG_DESC_INIT(SGID_PHDR, PT_PHDR, PF_R + PF_X, NULL,
11769112eddSAli Bahrami 	    (FLG_SG_P_TYPE | FLG_SG_P_FLAGS)),
11869112eddSAli Bahrami 
11969112eddSAli Bahrami 	/* psg_interp */
12069112eddSAli Bahrami 	SG_DESC_INIT(SGID_INTERP, PT_INTERP, PF_R, NULL,
12169112eddSAli Bahrami 	    (FLG_SG_P_TYPE | FLG_SG_P_FLAGS)),
12269112eddSAli Bahrami 
12369112eddSAli Bahrami 	/* psg_sunwcap */
12469112eddSAli Bahrami 	SG_DESC_INIT(SGID_SUNWCAP, PT_SUNWCAP, PF_R, NULL,
12569112eddSAli Bahrami 	    (FLG_SG_P_TYPE | FLG_SG_P_FLAGS)),
12669112eddSAli Bahrami 
12769112eddSAli Bahrami 	/* psg_text */
12869112eddSAli Bahrami 	SG_DESC_INIT(SGID_TEXT, PT_LOAD, PF_R + PF_X, MSG_ORIG(MSG_ENT_TEXT),
12969112eddSAli Bahrami 	    (FLG_SG_P_TYPE | FLG_SG_P_FLAGS)),
13069112eddSAli Bahrami 
13169112eddSAli Bahrami 	/* psg_data */
13269112eddSAli Bahrami 	SG_DESC_INIT(SGID_DATA, PT_LOAD, 0, MSG_ORIG(MSG_ENT_DATA),
13369112eddSAli Bahrami 	    (FLG_SG_P_TYPE | FLG_SG_P_FLAGS)),
13469112eddSAli Bahrami 
13569112eddSAli Bahrami 	/* psg_bss */
13669112eddSAli Bahrami 	SG_DESC_INIT(SGID_BSS, PT_LOAD, 0, MSG_ORIG(MSG_ENT_BSS),
13769112eddSAli Bahrami 	    (FLG_SG_P_TYPE | FLG_SG_P_FLAGS | FLG_SG_DISABLED)),
138ba2be530Sab 
1395aefb655Srie #if	defined(_ELF64)
14069112eddSAli Bahrami 	/* psg_lrodata (amd64-only ) */
14169112eddSAli Bahrami 	SG_DESC_INIT(SGID_LRODATA, PT_LOAD, PF_R, MSG_ORIG(MSG_ENT_LRODATA),
14269112eddSAli Bahrami 	    (FLG_SG_P_TYPE | FLG_SG_P_FLAGS)),
143ba2be530Sab 
14469112eddSAli Bahrami 	/* psg_ldata (amd64-only ) */
14569112eddSAli Bahrami 	SG_DESC_INIT(SGID_LDATA, PT_LOAD, 0, MSG_ORIG(MSG_ENT_LDATA),
14669112eddSAli Bahrami 	    (FLG_SG_P_TYPE | FLG_SG_P_FLAGS)),
14754d82594Sseizo #endif
14869112eddSAli Bahrami 	/* psg_dynamic */
14969112eddSAli Bahrami 	SG_DESC_INIT(SGID_DYN, PT_DYNAMIC, 0, NULL,
15069112eddSAli Bahrami 	    (FLG_SG_P_TYPE | FLG_SG_P_FLAGS)),
15169112eddSAli Bahrami 
15269112eddSAli Bahrami 	/* psg_sunwdtrace */
15369112eddSAli Bahrami 	SG_DESC_INIT(SGID_DTRACE, PT_SUNWDTRACE, 0, NULL,
15469112eddSAli Bahrami 	    (FLG_SG_P_TYPE | FLG_SG_P_FLAGS)),
155ba2be530Sab 
15669112eddSAli Bahrami 	/* psg_tls */
15769112eddSAli Bahrami 	SG_DESC_INIT(SGID_TLS, PT_TLS, PF_R, NULL,
15869112eddSAli Bahrami 	    (FLG_SG_P_TYPE | FLG_SG_P_FLAGS)),
159ba2be530Sab 
16069112eddSAli Bahrami 	/* psg_unwind */
16169112eddSAli Bahrami 	SG_DESC_INIT(SGID_UNWIND, PT_SUNW_UNWIND, PF_R, NULL,
16269112eddSAli Bahrami 	    (FLG_SG_P_TYPE | FLG_SG_P_FLAGS)),
163ba2be530Sab 
16469112eddSAli Bahrami 	/* psg_sunwstack */
16569112eddSAli Bahrami 	SG_DESC_INIT(SGID_SUNWSTACK, PT_SUNWSTACK, 0, NULL,
16669112eddSAli Bahrami 	    (FLG_SG_P_TYPE | FLG_SG_P_FLAGS | FLG_SG_DISABLED)),
167ba2be530Sab 
16869112eddSAli Bahrami 	/* psg_note */
16969112eddSAli Bahrami 	SG_DESC_INIT(SGID_NOTE, PT_NOTE, 0, MSG_ORIG(MSG_ENT_NOTE),
17069112eddSAli Bahrami 	    FLG_SG_P_TYPE),
171ba2be530Sab 
17269112eddSAli Bahrami 	/*
17369112eddSAli Bahrami 	 * psg_extra
17469112eddSAli Bahrami 	 *
17569112eddSAli Bahrami 	 * This segment is referenced by the final entrance criteria descriptor
17669112eddSAli Bahrami 	 * to catch any segment not otherwise placed. It cannot be disabled
17769112eddSAli Bahrami 	 * via a mapfile.
17869112eddSAli Bahrami 	 */
17969112eddSAli Bahrami 	SG_DESC_INIT(SGID_EXTRA, PT_NULL, 0, MSG_ORIG(MSG_ENT_EXTRA),
18069112eddSAli Bahrami 	    (FLG_SG_P_TYPE | FLG_SG_NODISABLE))
1817c478bd9Sstevel@tonic-gate };
18269112eddSAli Bahrami #undef SG_DESC_INIT
183ba2be530Sab 
1847c478bd9Sstevel@tonic-gate /*
18557ef7aa9SRod Evans  * The processing of input files by the link-editor involves matching the
18669112eddSAli Bahrami  * input file sections against an ordered list of entrance criteria
18769112eddSAli Bahrami  * descriptors. The following template defines the built in entrance criteria
18869112eddSAli Bahrami  * list. This list can be augmented using a mapfile. Each entrance criteria
18969112eddSAli Bahrami  * is associated with a segment descriptor, providing the means for mapping
19069112eddSAli Bahrami  * input sections to output segments.
191ba2be530Sab  *
19269112eddSAli Bahrami  * As with the segment descriptors, the EC_DESC_INIT macro is used
19369112eddSAli Bahrami  * to reduce boilerplate clutter.
1947c478bd9Sstevel@tonic-gate  */
19508278a5eSRod Evans #define	EC_DESC_INIT(ec_is_name, ec_type, ec_attrmask, ec_attrbits, \
19608278a5eSRod Evans     _seg_field, ec_flags) \
19708278a5eSRod Evans 	{ NULL, NULL, ec_is_name, ec_type, ec_attrmask, ec_attrbits, \
19869112eddSAli Bahrami 	    &sg_desc.psg_ ## _seg_field, 0, FLG_EC_BUILTIN | ec_flags }
19969112eddSAli Bahrami 
2007c478bd9Sstevel@tonic-gate static const Ent_desc	ent_desc[] = {
20108278a5eSRod Evans 	EC_DESC_INIT(NULL, SHT_NOTE, 0, 0, note, 0),
202ba2be530Sab 
203ba2be530Sab #if	defined(_ELF64)		/* (amd64-only) */
20408278a5eSRod Evans 	EC_DESC_INIT(NULL, 0, SHF_ALLOC + SHF_WRITE + SHF_AMD64_LARGE,
20569112eddSAli Bahrami 	    SHF_ALLOC + SHF_AMD64_LARGE, lrodata, 0),
20654d82594Sseizo #endif
20708278a5eSRod Evans 	EC_DESC_INIT(NULL, 0, SHF_ALLOC + SHF_WRITE, SHF_ALLOC, text, 0),
20808278a5eSRod Evans 
20908278a5eSRod Evans 	/*
21008278a5eSRod Evans 	 * Explicitly assign the .tdata section to bss.  The design of TLS
21108278a5eSRod Evans 	 * provides for initialized data being assigned to a .tdata section,
21208278a5eSRod Evans 	 * and uninitialized data being assigned to a .tbss section.  These
21308278a5eSRod Evans 	 * sections should be laid out adjacent to each other, with little or
21408278a5eSRod Evans 	 * no gap between them.  A PT_TLS program header is created that
21508278a5eSRod Evans 	 * defines the address range of the two sections.  This header is
21608278a5eSRod Evans 	 * passed to libc to instantiate the appropriate thread allocation.
21708278a5eSRod Evans 	 *
21808278a5eSRod Evans 	 * By default a separate bss segment is disabled, however users can
21908278a5eSRod Evans 	 * trigger the creation of a bss segment with a mapfile.  By default,
22008278a5eSRod Evans 	 * all bss sections are assigned to the data segment, and the section
22108278a5eSRod Evans 	 * identifiers of .tdata and .tbss ensure that these two sections are
22208278a5eSRod Evans 	 * adjacent to each other.
22308278a5eSRod Evans 	 *
22408278a5eSRod Evans 	 * However, if a bss segment is enabled, the adjacency of the .tdata
22508278a5eSRod Evans 	 * and .tbss sections can only be retained by having an explicit .tdata
22608278a5eSRod Evans 	 * entrance criteria.
22708278a5eSRod Evans 	 */
22808278a5eSRod Evans 	EC_DESC_INIT(MSG_ORIG(MSG_SCN_TDATA), 0, SHF_ALLOC + SHF_WRITE,
22908278a5eSRod Evans 	    SHF_ALLOC + SHF_WRITE, bss, 0),
230ba2be530Sab 
23108278a5eSRod Evans 	EC_DESC_INIT(NULL, SHT_NOBITS, SHF_ALLOC + SHF_WRITE,
23208278a5eSRod Evans 	    SHF_ALLOC + SHF_WRITE, bss, 0),
233ba2be530Sab 
234ba2be530Sab #if	defined(_ELF64)		/* (amd64-only) */
23508278a5eSRod Evans 	EC_DESC_INIT(NULL, SHT_NOBITS, SHF_ALLOC + SHF_WRITE + SHF_AMD64_LARGE,
23669112eddSAli Bahrami 	    SHF_ALLOC + SHF_WRITE + SHF_AMD64_LARGE, data, 0),
23769112eddSAli Bahrami 
23808278a5eSRod Evans 	EC_DESC_INIT(NULL, 0, SHF_ALLOC + SHF_WRITE + SHF_AMD64_LARGE,
23969112eddSAli Bahrami 	    SHF_ALLOC + SHF_WRITE + SHF_AMD64_LARGE, ldata, 0),
24054d82594Sseizo #endif
24108278a5eSRod Evans 	EC_DESC_INIT(NULL, 0, SHF_ALLOC + SHF_WRITE, SHF_ALLOC + SHF_WRITE,
24208278a5eSRod Evans 	    data, 0),
243ba2be530Sab 
24469112eddSAli Bahrami 	/*
24569112eddSAli Bahrami 	 * Final catchall rule sends remaining sections to "extra"
24669112eddSAli Bahrami 	 * NULL segment, which has been tagged as FLG_SG_NODISABLE,
24769112eddSAli Bahrami 	 * and which will therefore always accept them.
24869112eddSAli Bahrami 	 */
24908278a5eSRod Evans 	EC_DESC_INIT(NULL, 0, 0, 0, extra, FLG_EC_CATCHALL)
2507c478bd9Sstevel@tonic-gate };
25169112eddSAli Bahrami #undef EC_DESC_INIT
25269112eddSAli Bahrami 
25369112eddSAli Bahrami /*
25469112eddSAli Bahrami  * AVL comparison function for Sg_desc items in ofl_segs_avl.
25569112eddSAli Bahrami  *
25669112eddSAli Bahrami  * entry:
25769112eddSAli Bahrami  *	n1, n2 - pointers to nodes to be compared
25869112eddSAli Bahrami  *
25969112eddSAli Bahrami  * exit:
26069112eddSAli Bahrami  *	Returns -1 if (n1 < n2), 0 if they are equal, and 1 if (n1 > n2)
26169112eddSAli Bahrami  */
26269112eddSAli Bahrami static int
ofl_segs_avl_cmp(const void * n1,const void * n2)26369112eddSAli Bahrami ofl_segs_avl_cmp(const void *n1, const void *n2)
26469112eddSAli Bahrami {
26569112eddSAli Bahrami 	int		rc;
26669112eddSAli Bahrami 
26769112eddSAli Bahrami 	rc = strcmp(((Sg_desc *)n1)->sg_name, ((Sg_desc *)n2)->sg_name);
26869112eddSAli Bahrami 
26969112eddSAli Bahrami 	if (rc > 0)
27069112eddSAli Bahrami 		return (1);
27169112eddSAli Bahrami 	if (rc < 0)
27269112eddSAli Bahrami 		return (-1);
27369112eddSAli Bahrami 	return (0);
27469112eddSAli Bahrami }
27569112eddSAli Bahrami 
27669112eddSAli Bahrami /*
27769112eddSAli Bahrami  * AVL comparison function for Ent_desc items in ofl_ents_avl.
27869112eddSAli Bahrami  *
27969112eddSAli Bahrami  * entry:
28069112eddSAli Bahrami  *	n1, n2 - pointers to nodes to be compared
28169112eddSAli Bahrami  *
28269112eddSAli Bahrami  * exit:
28369112eddSAli Bahrami  *	Returns -1 if (n1 < n2), 0 if they are equal, and 1 if (n1 > n2)
28469112eddSAli Bahrami  */
28569112eddSAli Bahrami static int
ofl_ents_avl_cmp(const void * n1,const void * n2)28669112eddSAli Bahrami ofl_ents_avl_cmp(const void *n1, const void *n2)
28769112eddSAli Bahrami {
28869112eddSAli Bahrami 	int		rc;
28969112eddSAli Bahrami 
29069112eddSAli Bahrami 	/*
29169112eddSAli Bahrami 	 * There are entrance criteria nodes with NULL pointer names,
29269112eddSAli Bahrami 	 * but they are never entered into the AVL tree. Hence, we can
29369112eddSAli Bahrami 	 * assume that both nodes have names.
29469112eddSAli Bahrami 	 */
29569112eddSAli Bahrami 	rc = strcmp(((Ent_desc *)n1)->ec_name, ((Ent_desc *)n2)->ec_name);
29669112eddSAli Bahrami 
29769112eddSAli Bahrami 	if (rc > 0)
29869112eddSAli Bahrami 		return (1);
29969112eddSAli Bahrami 	if (rc < 0)
30069112eddSAli Bahrami 		return (-1);
30169112eddSAli Bahrami 	return (0);
30269112eddSAli Bahrami }
30369112eddSAli Bahrami 
30469112eddSAli Bahrami /*
30569112eddSAli Bahrami  * Lookup a segment descriptor by name.
30669112eddSAli Bahrami  *
30769112eddSAli Bahrami  * entry:
30869112eddSAli Bahrami  *	ofl - Output descriptor
30969112eddSAli Bahrami  *	name - Name of desired segment
31069112eddSAli Bahrami  *
31169112eddSAli Bahrami  * exit:
31269112eddSAli Bahrami  *	On success, returns pointer to descriptor. On failure, returns NULL.
31369112eddSAli Bahrami  */
31469112eddSAli Bahrami Sg_desc *
ld_seg_lookup(Ofl_desc * ofl,const char * name,avl_index_t * where)31569112eddSAli Bahrami ld_seg_lookup(Ofl_desc *ofl, const char *name, avl_index_t *where)
31669112eddSAli Bahrami {
31769112eddSAli Bahrami 	Sg_desc		sg;
31869112eddSAli Bahrami 
31969112eddSAli Bahrami 	sg.sg_name = name;
32069112eddSAli Bahrami 	return (avl_find(&ofl->ofl_segs_avl, &sg, where));
32169112eddSAli Bahrami }
32269112eddSAli Bahrami 
32369112eddSAli Bahrami 
32469112eddSAli Bahrami /*
32569112eddSAli Bahrami  * Look up an entrance criteria record by name
32669112eddSAli Bahrami  *
32769112eddSAli Bahrami  * entry:
32869112eddSAli Bahrami  *	mf - Mapfile descriptor
32969112eddSAli Bahrami  *	name - Name of entrance criteria to locate
33069112eddSAli Bahrami  *
33169112eddSAli Bahrami  * exit:
33269112eddSAli Bahrami  *	On success, a pointer to the entrace criteria record is
33369112eddSAli Bahrami  *	returned. On failure, NULL is returned.
33469112eddSAli Bahrami  *
33569112eddSAli Bahrami  * note:
33669112eddSAli Bahrami  *	Entrance criteria are not required to have names. Only
33769112eddSAli Bahrami  *	named entrance criteria can be looked up via this method.
33869112eddSAli Bahrami  */
33969112eddSAli Bahrami Ent_desc *
ld_ent_lookup(Ofl_desc * ofl,const char * name,avl_index_t * where)34069112eddSAli Bahrami ld_ent_lookup(Ofl_desc *ofl, const char *name, avl_index_t *where)
34169112eddSAli Bahrami {
34269112eddSAli Bahrami 	Ent_desc	en;
34369112eddSAli Bahrami 
34469112eddSAli Bahrami 	en.ec_name = name;
34569112eddSAli Bahrami 	return (avl_find(&ofl->ofl_ents_avl, &en, where));
34669112eddSAli Bahrami }
3477c478bd9Sstevel@tonic-gate 
3487c478bd9Sstevel@tonic-gate /*
3497c478bd9Sstevel@tonic-gate  * Initialize new entrance and segment descriptors and add them as lists to
3507c478bd9Sstevel@tonic-gate  * the output file descriptor.
3517c478bd9Sstevel@tonic-gate  */
3527c478bd9Sstevel@tonic-gate uintptr_t
ld_ent_setup(Ofl_desc * ofl,Xword segalign)353d1827f25Srie ld_ent_setup(Ofl_desc *ofl, Xword segalign)
3547c478bd9Sstevel@tonic-gate {
35569112eddSAli Bahrami 	Ent_desc	*enp;
35669112eddSAli Bahrami 	predef_seg_t	*psegs;
357d1827f25Srie 	Sg_desc		*sgp;
358ba2be530Sab 	size_t		idx;
3597c478bd9Sstevel@tonic-gate 
3607c478bd9Sstevel@tonic-gate 	/*
3617c478bd9Sstevel@tonic-gate 	 * Initialize the elf library.
3627c478bd9Sstevel@tonic-gate 	 */
3637c478bd9Sstevel@tonic-gate 	if (elf_version(EV_CURRENT) == EV_NONE) {
3641007fd6fSAli Bahrami 		ld_eprintf(ofl, ERR_FATAL, MSG_INTL(MSG_ELF_LIBELF),
3655aefb655Srie 		    EV_CURRENT);
3667c478bd9Sstevel@tonic-gate 		return (S_ERROR);
3677c478bd9Sstevel@tonic-gate 	}
3687c478bd9Sstevel@tonic-gate 
3697c478bd9Sstevel@tonic-gate 	/*
3707c478bd9Sstevel@tonic-gate 	 * Initialize internal Global Symbol Table AVL tree
3717c478bd9Sstevel@tonic-gate 	 */
3725aefb655Srie 	avl_create(&ofl->ofl_symavl, &ld_sym_avl_comp, sizeof (Sym_avlnode),
3735aefb655Srie 	    SGSOFFSETOF(Sym_avlnode, sav_node));
3745aefb655Srie 
37569112eddSAli Bahrami 	/* Initialize segment AVL tree */
37669112eddSAli Bahrami 	avl_create(&ofl->ofl_segs_avl, ofl_segs_avl_cmp,
37769112eddSAli Bahrami 	    sizeof (Sg_desc), SGSOFFSETOF(Sg_desc, sg_avlnode));
37869112eddSAli Bahrami 
37969112eddSAli Bahrami 	/* Initialize entrance criteria AVL tree */
38069112eddSAli Bahrami 	avl_create(&ofl->ofl_ents_avl, ofl_ents_avl_cmp, sizeof (Ent_desc),
38169112eddSAli Bahrami 	    SGSOFFSETOF(Ent_desc, ec_avlnode));
38269112eddSAli Bahrami 
38369112eddSAli Bahrami 
3847c478bd9Sstevel@tonic-gate 	/*
3857c478bd9Sstevel@tonic-gate 	 * Allocate and initialize writable copies of both the entrance and
3867c478bd9Sstevel@tonic-gate 	 * segment descriptors.
387ba2be530Sab 	 *
388ba2be530Sab 	 * Note that on non-amd64 targets, this allocates a few more
389ba2be530Sab 	 * elements than are needed. For now, we are willing to overallocate
390ba2be530Sab 	 * a small amount to simplify the code.
3917c478bd9Sstevel@tonic-gate 	 */
39269112eddSAli Bahrami 	if ((psegs = libld_malloc(sizeof (sg_desc))) == NULL)
3937c478bd9Sstevel@tonic-gate 		return (S_ERROR);
39469112eddSAli Bahrami 	(void) memcpy(psegs, &sg_desc, sizeof (sg_desc));
39569112eddSAli Bahrami 	sgp = (Sg_desc *) psegs;
3967c478bd9Sstevel@tonic-gate 
397ba2be530Sab 	/*
39869112eddSAli Bahrami 	 * The data segment and stack permissions can differ:
399ba2be530Sab 	 *
40008278a5eSRod Evans 	 *	- Architectural/ABI per-platform differences
401ba2be530Sab 	 *	- Whether the object is built statically or dynamically
402ba2be530Sab 	 *
403ba2be530Sab 	 * Those segments so affected have their program header flags
404ba2be530Sab 	 * set here at runtime, rather than in the sg_desc templates above.
405ba2be530Sab 	 */
40669112eddSAli Bahrami 	psegs->psg_data.sg_phdr.p_flags = ld_targ.t_m.m_dataseg_perm;
40769112eddSAli Bahrami 	psegs->psg_bss.sg_phdr.p_flags = ld_targ.t_m.m_dataseg_perm;
40869112eddSAli Bahrami 	psegs->psg_dynamic.sg_phdr.p_flags = ld_targ.t_m.m_dataseg_perm;
40969112eddSAli Bahrami 	psegs->psg_sunwdtrace.sg_phdr.p_flags = ld_targ.t_m.m_dataseg_perm;
410ba2be530Sab #if	defined(_ELF64)
41169112eddSAli Bahrami 	psegs->psg_ldata.sg_phdr.p_flags = ld_targ.t_m.m_dataseg_perm;
41269112eddSAli Bahrami 	psegs->psg_sunwdtrace.sg_phdr.p_flags |= PF_X;
413ba2be530Sab #endif
41469112eddSAli Bahrami 	psegs->psg_sunwstack.sg_phdr.p_flags = ld_targ.t_m.m_stack_perm;
41535450702SAli Bahrami 	if ((ofl->ofl_flags & FLG_OF_DYNAMIC) == 0)
41669112eddSAli Bahrami 		psegs->psg_data.sg_phdr.p_flags |= PF_X;
417ba2be530Sab 
4187c478bd9Sstevel@tonic-gate 	/*
4197c478bd9Sstevel@tonic-gate 	 * Traverse the new entrance descriptor list converting the segment
4207c478bd9Sstevel@tonic-gate 	 * pointer entries to the absolute address within the new segment
4217c478bd9Sstevel@tonic-gate 	 * descriptor list.  Add each entrance descriptor to the output file
4227c478bd9Sstevel@tonic-gate 	 * list.
4237c478bd9Sstevel@tonic-gate 	 */
42469112eddSAli Bahrami 	if ((enp = libld_malloc(sizeof (ent_desc))) == NULL)
42569112eddSAli Bahrami 		return (S_ERROR);
42669112eddSAli Bahrami 	(void) memcpy(enp, ent_desc, sizeof (ent_desc));
42769112eddSAli Bahrami 	for (idx = 0; idx < (sizeof (ent_desc) / sizeof (ent_desc[0])); idx++,
42869112eddSAli Bahrami 	    enp++) {
42957ef7aa9SRod Evans 
430ba2be530Sab #if	defined(_ELF64)
431ba2be530Sab 		/* Don't use the amd64 entry conditions for non-amd64 targets */
43269112eddSAli Bahrami 		if ((enp->ec_attrmask & SHF_AMD64_LARGE) &&
433ba2be530Sab 		    (ld_targ.t_m.m_mach != EM_AMD64))
434ba2be530Sab 			continue;
435ba2be530Sab #endif
43669112eddSAli Bahrami 		if (aplist_append(&ofl->ofl_ents, enp,
43769112eddSAli Bahrami 		    AL_CNT_OFL_ENTRANCE) == NULL)
4387c478bd9Sstevel@tonic-gate 			return (S_ERROR);
43957ef7aa9SRod Evans 
44069112eddSAli Bahrami 		/*
44169112eddSAli Bahrami 		 * The segment pointer is currently pointing at a template
44269112eddSAli Bahrami 		 * segment descriptor in sg_desc. Compute its array index,
44369112eddSAli Bahrami 		 * and then use that index to compute the address of the
44469112eddSAli Bahrami 		 * corresponding descriptor in the writable copy.
44569112eddSAli Bahrami 		 */
44669112eddSAli Bahrami 		enp->ec_segment =
44769112eddSAli Bahrami 		    &sgp[(enp->ec_segment - (Sg_desc *) &sg_desc)];
4487c478bd9Sstevel@tonic-gate 	}
4497c478bd9Sstevel@tonic-gate 
4507c478bd9Sstevel@tonic-gate 	/*
45169112eddSAli Bahrami 	 * Add each segment descriptor to the segment descriptor list. The
45269112eddSAli Bahrami 	 * ones with non-NULL sg_name are also entered into the AVL tree.
45369112eddSAli Bahrami 	 * For each loadable segment initialize a default alignment. Note
45469112eddSAli Bahrami 	 * that ld(1) and ld.so.1 initialize this differently.
4557c478bd9Sstevel@tonic-gate 	 */
45669112eddSAli Bahrami 	for (idx = 0; idx < predef_seg_nelts; idx++, sgp++) {
457d1827f25Srie 		Phdr	*phdr = &(sgp->sg_phdr);
4587c478bd9Sstevel@tonic-gate 
459ba2be530Sab #if	defined(_ELF64)
460ba2be530Sab 		/* Ignore amd64 segment templates for non-amd64 targets */
46169112eddSAli Bahrami 		switch (sgp->sg_id) {
46269112eddSAli Bahrami 		case SGID_LRODATA:
46369112eddSAli Bahrami 		case SGID_LDATA:
464ba2be530Sab 			if ((ld_targ.t_m.m_mach != EM_AMD64))
465ba2be530Sab 				continue;
466ba2be530Sab 		}
467ba2be530Sab #endif
46869112eddSAli Bahrami 		if (phdr->p_type == PT_LOAD)
46969112eddSAli Bahrami 			phdr->p_align = segalign;
47069112eddSAli Bahrami 
47157ef7aa9SRod Evans 		if ((aplist_append(&ofl->ofl_segs, sgp,
47257ef7aa9SRod Evans 		    AL_CNT_SEGMENTS)) == NULL)
4737c478bd9Sstevel@tonic-gate 			return (S_ERROR);
47469112eddSAli Bahrami 
475*0bc0887eSRichard Lowe #ifndef NDEBUG			/* assert() is enabled */
47669112eddSAli Bahrami 		/*
47769112eddSAli Bahrami 		 * Enforce the segment name rule: Any segment that can
47869112eddSAli Bahrami 		 * be referenced by an entrance descriptor must have
47969112eddSAli Bahrami 		 * a name. Any segment that cannot, must have a NULL
48069112eddSAli Bahrami 		 * name pointer.
48169112eddSAli Bahrami 		 */
48269112eddSAli Bahrami 		switch (phdr->p_type) {
48369112eddSAli Bahrami 		case PT_LOAD:
48469112eddSAli Bahrami 		case PT_NOTE:
48569112eddSAli Bahrami 		case PT_NULL:
48669112eddSAli Bahrami 			assert(sgp->sg_name != NULL);
48769112eddSAli Bahrami 			break;
48869112eddSAli Bahrami 		default:
48969112eddSAli Bahrami 			assert(sgp->sg_name == NULL);
49069112eddSAli Bahrami 			break;
49169112eddSAli Bahrami 		}
49269112eddSAli Bahrami #endif
49369112eddSAli Bahrami 
49469112eddSAli Bahrami 		/*
49569112eddSAli Bahrami 		 * Add named segment descriptors to the AVL tree to
49669112eddSAli Bahrami 		 * provide O(logN) lookups.
49769112eddSAli Bahrami 		 */
49869112eddSAli Bahrami 		if (sgp->sg_name != NULL)
49969112eddSAli Bahrami 			avl_add(&ofl->ofl_segs_avl, sgp);
5007c478bd9Sstevel@tonic-gate 	}
501ba2be530Sab 
5027c478bd9Sstevel@tonic-gate 	return (1);
5037c478bd9Sstevel@tonic-gate }
504