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 * 26*1007fd6fSAli Bahrami * Copyright (c) 1991, 2010, Oracle and/or its affiliates. All rights reserved. 277c478bd9Sstevel@tonic-gate */ 287c478bd9Sstevel@tonic-gate 29ba2be530Sab196087 #define ELF_TARGET_AMD64 30ba2be530Sab196087 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 37ba2be530Sab196087 /* 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. 42ba2be530Sab196087 * 4369112eddSAli Bahrami * The entries in sg_desc must be put in the order defined by the 4469112eddSAli Bahrami * Segment_id enum. 45ba2be530Sab196087 * 4669112eddSAli Bahrami * The entries in sg_desc are initialized using the SG_DESC_INIT macro 47ba2be530Sab196087 * for two reasons: 48ba2be530Sab196087 * 49ba2be530Sab196087 * 1) The first field of the Sg_desc struct is a program header 50ba2be530Sab196087 * entry. ELF32_Phdr and ELF64_Phdr have the same fields, 51ba2be530Sab196087 * but their order is different. Use of a macro allows us 52ba2be530Sab196087 * to handle this transparently. 53ba2be530Sab196087 * 2) Most of the fields in the Sg_desc entries are set to 0. 54ba2be530Sab196087 * 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. 60ba2be530Sab196087 */ 61ba2be530Sab196087 #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} 65ba2be530Sab196087 #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} 69ba2be530Sab196087 #endif 70ba2be530Sab196087 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; 110ba2be530Sab196087 11169112eddSAli Bahrami static const size_t predef_seg_nelts = 11269112eddSAli Bahrami (sizeof (predef_seg_t) / sizeof (Sg_desc)); 113ba2be530Sab196087 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)), 118ba2be530Sab196087 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)), 122ba2be530Sab196087 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)), 126ba2be530Sab196087 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)), 138ba2be530Sab196087 139ba2be530Sab196087 #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)), 143ba2be530Sab196087 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)), 147ba2be530Sab196087 #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)), 151ba2be530Sab196087 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)), 155ba2be530Sab196087 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)), 159ba2be530Sab196087 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)), 163ba2be530Sab196087 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)), 16757ef7aa9SRod Evans 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), 17169112eddSAli Bahrami 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 183ba2be530Sab196087 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. 191ba2be530Sab196087 * 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), 202ba2be530Sab196087 203ba2be530Sab196087 #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), 208ba2be530Sab196087 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), 23008278a5eSRod Evans 23108278a5eSRod Evans EC_DESC_INIT(NULL, SHT_NOBITS, SHF_ALLOC + SHF_WRITE, 23208278a5eSRod Evans SHF_ALLOC + SHF_WRITE, bss, 0), 233ba2be530Sab196087 234ba2be530Sab196087 #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), 237ba2be530Sab196087 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), 243ba2be530Sab196087 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 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 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 * 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 * 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 3535aefb655Srie ld_ent_setup(Ofl_desc *ofl, Xword segalign) 3547c478bd9Sstevel@tonic-gate { 35569112eddSAli Bahrami Ent_desc *enp; 35669112eddSAli Bahrami predef_seg_t *psegs; 3577c478bd9Sstevel@tonic-gate Sg_desc *sgp; 358ba2be530Sab196087 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) { 364*1007fd6fSAli 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), 3737c478bd9Sstevel@tonic-gate 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. 387ba2be530Sab196087 * 388ba2be530Sab196087 * Note that on non-amd64 targets, this allocates a few more 389ba2be530Sab196087 * elements than are needed. For now, we are willing to overallocate 390ba2be530Sab196087 * 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 3977c478bd9Sstevel@tonic-gate /* 39869112eddSAli Bahrami * The data segment and stack permissions can differ: 399ba2be530Sab196087 * 40008278a5eSRod Evans * - Architectural/ABI per-platform differences 401ba2be530Sab196087 * - Whether the object is built statically or dynamically 402ba2be530Sab196087 * 403ba2be530Sab196087 * Those segments so affected have their program header flags 404ba2be530Sab196087 * set here at runtime, rather than in the sg_desc templates above. 405ba2be530Sab196087 */ 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; 410ba2be530Sab196087 #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; 413ba2be530Sab196087 #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; 417ba2be530Sab196087 418ba2be530Sab196087 /* 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 430ba2be530Sab196087 #if defined(_ELF64) 431ba2be530Sab196087 /* Don't use the amd64 entry conditions for non-amd64 targets */ 43269112eddSAli Bahrami if ((enp->ec_attrmask & SHF_AMD64_LARGE) && 433ba2be530Sab196087 (ld_targ.t_m.m_mach != EM_AMD64)) 434ba2be530Sab196087 continue; 435ba2be530Sab196087 #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++) { 4577c478bd9Sstevel@tonic-gate Phdr *phdr = &(sgp->sg_phdr); 4587c478bd9Sstevel@tonic-gate 459ba2be530Sab196087 #if defined(_ELF64) 460ba2be530Sab196087 /* Ignore amd64 segment templates for non-amd64 targets */ 46169112eddSAli Bahrami switch (sgp->sg_id) { 46269112eddSAli Bahrami case SGID_LRODATA: 46369112eddSAli Bahrami case SGID_LDATA: 464ba2be530Sab196087 if ((ld_targ.t_m.m_mach != EM_AMD64)) 465ba2be530Sab196087 continue; 466ba2be530Sab196087 } 467ba2be530Sab196087 #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 47569112eddSAli Bahrami #ifdef 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 } 501ba2be530Sab196087 5027c478bd9Sstevel@tonic-gate return (1); 5037c478bd9Sstevel@tonic-gate } 504