xref: /illumos-gate/usr/src/cmd/sgs/libelf/common/update.c (revision 7c478bd9)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*	Copyright (c) 1988 AT&T	*/
23*7c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
24*7c478bd9Sstevel@tonic-gate 
25*7c478bd9Sstevel@tonic-gate 
26*7c478bd9Sstevel@tonic-gate /*
27*7c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
28*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
29*7c478bd9Sstevel@tonic-gate  */
30*7c478bd9Sstevel@tonic-gate 
31*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
32*7c478bd9Sstevel@tonic-gate 
33*7c478bd9Sstevel@tonic-gate #if !defined(_ELF64)
34*7c478bd9Sstevel@tonic-gate #pragma weak elf_update = _elf_update
35*7c478bd9Sstevel@tonic-gate #endif
36*7c478bd9Sstevel@tonic-gate 
37*7c478bd9Sstevel@tonic-gate #include "syn.h"
38*7c478bd9Sstevel@tonic-gate #include <memory.h>
39*7c478bd9Sstevel@tonic-gate #include <malloc.h>
40*7c478bd9Sstevel@tonic-gate #include <limits.h>
41*7c478bd9Sstevel@tonic-gate 
42*7c478bd9Sstevel@tonic-gate #include <sgs.h>
43*7c478bd9Sstevel@tonic-gate #include "decl.h"
44*7c478bd9Sstevel@tonic-gate #include "msg.h"
45*7c478bd9Sstevel@tonic-gate 
46*7c478bd9Sstevel@tonic-gate /*
47*7c478bd9Sstevel@tonic-gate  * This module is compiled twice, the second time having
48*7c478bd9Sstevel@tonic-gate  * -D_ELF64 defined.  The following set of macros, along
49*7c478bd9Sstevel@tonic-gate  * with machelf.h, represent the differences between the
50*7c478bd9Sstevel@tonic-gate  * two compilations.  Be careful *not* to add any class-
51*7c478bd9Sstevel@tonic-gate  * dependent code (anything that has elf32 or elf64 in the
52*7c478bd9Sstevel@tonic-gate  * name) to this code without hiding it behind a switch-
53*7c478bd9Sstevel@tonic-gate  * able macro like these.
54*7c478bd9Sstevel@tonic-gate  */
55*7c478bd9Sstevel@tonic-gate #if	defined(_ELF64)
56*7c478bd9Sstevel@tonic-gate 
57*7c478bd9Sstevel@tonic-gate #define	FSZ_LONG	ELF64_FSZ_XWORD
58*7c478bd9Sstevel@tonic-gate #define	ELFCLASS	ELFCLASS64
59*7c478bd9Sstevel@tonic-gate #define	_elf_snode_init	_elf64_snode_init
60*7c478bd9Sstevel@tonic-gate #define	_elfxx_cookscn	_elf64_cookscn
61*7c478bd9Sstevel@tonic-gate #define	_elf_upd_lib	_elf64_upd_lib
62*7c478bd9Sstevel@tonic-gate #define	elf_fsize	elf64_fsize
63*7c478bd9Sstevel@tonic-gate #define	_elf_entsz	_elf64_entsz
64*7c478bd9Sstevel@tonic-gate #define	_elf_msize	_elf64_msize
65*7c478bd9Sstevel@tonic-gate #define	_elf_upd_usr	_elf64_upd_usr
66*7c478bd9Sstevel@tonic-gate #define	wrt		wrt64
67*7c478bd9Sstevel@tonic-gate #define	elf_xlatetof	elf64_xlatetof
68*7c478bd9Sstevel@tonic-gate #define	_elfxx_update	_elf64_update
69*7c478bd9Sstevel@tonic-gate 
70*7c478bd9Sstevel@tonic-gate #else	/* ELF32 */
71*7c478bd9Sstevel@tonic-gate 
72*7c478bd9Sstevel@tonic-gate #define	FSZ_LONG	ELF32_FSZ_WORD
73*7c478bd9Sstevel@tonic-gate #define	ELFCLASS	ELFCLASS32
74*7c478bd9Sstevel@tonic-gate #define	_elf_snode_init	_elf32_snode_init
75*7c478bd9Sstevel@tonic-gate #define	_elfxx_cookscn	_elf32_cookscn
76*7c478bd9Sstevel@tonic-gate #define	_elf_upd_lib	_elf32_upd_lib
77*7c478bd9Sstevel@tonic-gate #define	elf_fsize	elf32_fsize
78*7c478bd9Sstevel@tonic-gate #define	_elf_entsz	_elf32_entsz
79*7c478bd9Sstevel@tonic-gate #define	_elf_msize	_elf32_msize
80*7c478bd9Sstevel@tonic-gate #define	_elf_upd_usr	_elf32_upd_usr
81*7c478bd9Sstevel@tonic-gate #define	wrt		wrt32
82*7c478bd9Sstevel@tonic-gate #define	elf_xlatetof	elf32_xlatetof
83*7c478bd9Sstevel@tonic-gate #define	_elfxx_update	_elf32_update
84*7c478bd9Sstevel@tonic-gate 
85*7c478bd9Sstevel@tonic-gate #endif /* ELF64 */
86*7c478bd9Sstevel@tonic-gate 
87*7c478bd9Sstevel@tonic-gate 
88*7c478bd9Sstevel@tonic-gate /*
89*7c478bd9Sstevel@tonic-gate  * Output file update
90*7c478bd9Sstevel@tonic-gate  *	These functions walk an Elf structure, update its information,
91*7c478bd9Sstevel@tonic-gate  *	and optionally write the output file.  Because the application
92*7c478bd9Sstevel@tonic-gate  *	may control of the output file layout, two upd_... routines
93*7c478bd9Sstevel@tonic-gate  *	exist.  They're similar but too different to merge cleanly.
94*7c478bd9Sstevel@tonic-gate  *
95*7c478bd9Sstevel@tonic-gate  *	The library defines a "dirty" bit to force parts of the file
96*7c478bd9Sstevel@tonic-gate  *	to be written on update.  These routines ignore the dirty bit
97*7c478bd9Sstevel@tonic-gate  *	and do everything.  A minimal update routine might be useful
98*7c478bd9Sstevel@tonic-gate  *	someday.
99*7c478bd9Sstevel@tonic-gate  */
100*7c478bd9Sstevel@tonic-gate 
101*7c478bd9Sstevel@tonic-gate 
102*7c478bd9Sstevel@tonic-gate static size_t
103*7c478bd9Sstevel@tonic-gate _elf_upd_lib(Elf * elf)
104*7c478bd9Sstevel@tonic-gate {
105*7c478bd9Sstevel@tonic-gate 	NOTE(ASSUMING_PROTECTED(*elf))
106*7c478bd9Sstevel@tonic-gate 	Lword		hi;
107*7c478bd9Sstevel@tonic-gate 	Lword		hibit;
108*7c478bd9Sstevel@tonic-gate 	Elf_Scn *	s;
109*7c478bd9Sstevel@tonic-gate 	register Xword	sz;
110*7c478bd9Sstevel@tonic-gate 	Ehdr *		eh = elf->ed_ehdr;
111*7c478bd9Sstevel@tonic-gate 	unsigned	ver = eh->e_version;
112*7c478bd9Sstevel@tonic-gate 	register char	*p = (char *)eh->e_ident;
113*7c478bd9Sstevel@tonic-gate 	size_t		scncnt;
114*7c478bd9Sstevel@tonic-gate 
115*7c478bd9Sstevel@tonic-gate 
116*7c478bd9Sstevel@tonic-gate 	/*
117*7c478bd9Sstevel@tonic-gate 	 * Ehdr and Phdr table go first
118*7c478bd9Sstevel@tonic-gate 	 */
119*7c478bd9Sstevel@tonic-gate 	p[EI_MAG0] = ELFMAG0;
120*7c478bd9Sstevel@tonic-gate 	p[EI_MAG1] = ELFMAG1;
121*7c478bd9Sstevel@tonic-gate 	p[EI_MAG2] = ELFMAG2;
122*7c478bd9Sstevel@tonic-gate 	p[EI_MAG3] = ELFMAG3;
123*7c478bd9Sstevel@tonic-gate 	p[EI_CLASS] = ELFCLASS;
124*7c478bd9Sstevel@tonic-gate 	/* LINTED */
125*7c478bd9Sstevel@tonic-gate 	p[EI_VERSION] = (Byte)ver;
126*7c478bd9Sstevel@tonic-gate 	hi = elf_fsize(ELF_T_EHDR, 1, ver);
127*7c478bd9Sstevel@tonic-gate 	/* LINTED */
128*7c478bd9Sstevel@tonic-gate 	eh->e_ehsize = (Half)hi;
129*7c478bd9Sstevel@tonic-gate 	if (eh->e_phnum != 0) {
130*7c478bd9Sstevel@tonic-gate 		/* LINTED */
131*7c478bd9Sstevel@tonic-gate 		eh->e_phentsize = (Half)elf_fsize(ELF_T_PHDR, 1, ver);
132*7c478bd9Sstevel@tonic-gate 		/* LINTED */
133*7c478bd9Sstevel@tonic-gate 		eh->e_phoff = (Off)hi;
134*7c478bd9Sstevel@tonic-gate 		hi += eh->e_phentsize * eh->e_phnum;
135*7c478bd9Sstevel@tonic-gate 	} else {
136*7c478bd9Sstevel@tonic-gate 		eh->e_phoff = 0;
137*7c478bd9Sstevel@tonic-gate 		eh->e_phentsize = 0;
138*7c478bd9Sstevel@tonic-gate 	}
139*7c478bd9Sstevel@tonic-gate 
140*7c478bd9Sstevel@tonic-gate 
141*7c478bd9Sstevel@tonic-gate 	/*
142*7c478bd9Sstevel@tonic-gate 	 * Loop through sections, skipping index zero.
143*7c478bd9Sstevel@tonic-gate 	 * Compute section size before changing hi.
144*7c478bd9Sstevel@tonic-gate 	 * Allow null buffers for NOBITS.
145*7c478bd9Sstevel@tonic-gate 	 */
146*7c478bd9Sstevel@tonic-gate 
147*7c478bd9Sstevel@tonic-gate 	if ((s = elf->ed_hdscn) == 0) {
148*7c478bd9Sstevel@tonic-gate 		eh->e_shnum = 0;
149*7c478bd9Sstevel@tonic-gate 		scncnt = 0;
150*7c478bd9Sstevel@tonic-gate 	} else {
151*7c478bd9Sstevel@tonic-gate 		scncnt = 1;
152*7c478bd9Sstevel@tonic-gate 		*(Shdr *)s->s_shdr = _elf_snode_init.sb_shdr;
153*7c478bd9Sstevel@tonic-gate 		s = s->s_next;
154*7c478bd9Sstevel@tonic-gate 	}
155*7c478bd9Sstevel@tonic-gate 
156*7c478bd9Sstevel@tonic-gate 	hibit = 0;
157*7c478bd9Sstevel@tonic-gate 	for (; s != 0; s = s->s_next) {
158*7c478bd9Sstevel@tonic-gate 		register Dnode	*d;
159*7c478bd9Sstevel@tonic-gate 		register Lword	fsz, j;
160*7c478bd9Sstevel@tonic-gate 		Shdr *sh = s->s_shdr;
161*7c478bd9Sstevel@tonic-gate 
162*7c478bd9Sstevel@tonic-gate 		scncnt++;
163*7c478bd9Sstevel@tonic-gate 		if (sh->sh_type == SHT_NULL) {
164*7c478bd9Sstevel@tonic-gate 			*sh = _elf_snode_init.sb_shdr;
165*7c478bd9Sstevel@tonic-gate 			continue;
166*7c478bd9Sstevel@tonic-gate 		}
167*7c478bd9Sstevel@tonic-gate 
168*7c478bd9Sstevel@tonic-gate 		if ((s->s_myflags & SF_READY) == 0)
169*7c478bd9Sstevel@tonic-gate 			(void) _elfxx_cookscn(s);
170*7c478bd9Sstevel@tonic-gate 
171*7c478bd9Sstevel@tonic-gate 		sh->sh_addralign = 1;
172*7c478bd9Sstevel@tonic-gate 		if ((sz = (Xword)_elf_entsz(sh->sh_type, ver)) != 0)
173*7c478bd9Sstevel@tonic-gate 			/* LINTED */
174*7c478bd9Sstevel@tonic-gate 			sh->sh_entsize = (Half)sz;
175*7c478bd9Sstevel@tonic-gate 		sz = 0;
176*7c478bd9Sstevel@tonic-gate 		for (d = s->s_hdnode; d != 0; d = d->db_next) {
177*7c478bd9Sstevel@tonic-gate 			if ((fsz = elf_fsize(d->db_data.d_type,
178*7c478bd9Sstevel@tonic-gate 			    1, ver)) == 0)
179*7c478bd9Sstevel@tonic-gate 				return (0);
180*7c478bd9Sstevel@tonic-gate 
181*7c478bd9Sstevel@tonic-gate 			j = _elf_msize(d->db_data.d_type, ver);
182*7c478bd9Sstevel@tonic-gate 			fsz *= (d->db_data.d_size / j);
183*7c478bd9Sstevel@tonic-gate 			d->db_osz = (size_t)fsz;
184*7c478bd9Sstevel@tonic-gate 			if ((j = d->db_data.d_align) > 1) {
185*7c478bd9Sstevel@tonic-gate 				if (j > sh->sh_addralign)
186*7c478bd9Sstevel@tonic-gate 					sh->sh_addralign = (Xword)j;
187*7c478bd9Sstevel@tonic-gate 
188*7c478bd9Sstevel@tonic-gate 				if (sz % j != 0)
189*7c478bd9Sstevel@tonic-gate 					sz += j - sz % j;
190*7c478bd9Sstevel@tonic-gate 			}
191*7c478bd9Sstevel@tonic-gate 			d->db_data.d_off = (off_t)sz;
192*7c478bd9Sstevel@tonic-gate 			d->db_xoff = sz;
193*7c478bd9Sstevel@tonic-gate 			sz += (Xword)fsz;
194*7c478bd9Sstevel@tonic-gate 		}
195*7c478bd9Sstevel@tonic-gate 
196*7c478bd9Sstevel@tonic-gate 		sh->sh_size = sz;
197*7c478bd9Sstevel@tonic-gate 		/*
198*7c478bd9Sstevel@tonic-gate 		 * We want to take into account the offsets for NOBITS
199*7c478bd9Sstevel@tonic-gate 		 * sections and let the "sh_offsets" point to where
200*7c478bd9Sstevel@tonic-gate 		 * the section would 'conceptually' fit within
201*7c478bd9Sstevel@tonic-gate 		 * the file (as required by the ABI).
202*7c478bd9Sstevel@tonic-gate 		 *
203*7c478bd9Sstevel@tonic-gate 		 * But - we must also make sure that the NOBITS does
204*7c478bd9Sstevel@tonic-gate 		 * not take up any actual space in the file.  We preserve
205*7c478bd9Sstevel@tonic-gate 		 * the actual offset into the file in the 'hibit' variable.
206*7c478bd9Sstevel@tonic-gate 		 * When we come to the first non-NOBITS section after a
207*7c478bd9Sstevel@tonic-gate 		 * encountering a NOBITS section the hi counter is restored
208*7c478bd9Sstevel@tonic-gate 		 * to its proper place in the file.
209*7c478bd9Sstevel@tonic-gate 		 */
210*7c478bd9Sstevel@tonic-gate 		if (sh->sh_type == SHT_NOBITS) {
211*7c478bd9Sstevel@tonic-gate 			if (hibit == 0)
212*7c478bd9Sstevel@tonic-gate 				hibit = hi;
213*7c478bd9Sstevel@tonic-gate 		} else {
214*7c478bd9Sstevel@tonic-gate 			if (hibit) {
215*7c478bd9Sstevel@tonic-gate 				hi = hibit;
216*7c478bd9Sstevel@tonic-gate 				hibit = 0;
217*7c478bd9Sstevel@tonic-gate 			}
218*7c478bd9Sstevel@tonic-gate 		}
219*7c478bd9Sstevel@tonic-gate 		j = sh->sh_addralign;
220*7c478bd9Sstevel@tonic-gate 		if ((fsz = hi % j) != 0)
221*7c478bd9Sstevel@tonic-gate 			hi += j - fsz;
222*7c478bd9Sstevel@tonic-gate 
223*7c478bd9Sstevel@tonic-gate 		/* LINTED */
224*7c478bd9Sstevel@tonic-gate 		sh->sh_offset = (Off)hi;
225*7c478bd9Sstevel@tonic-gate 		hi += sz;
226*7c478bd9Sstevel@tonic-gate 	}
227*7c478bd9Sstevel@tonic-gate 
228*7c478bd9Sstevel@tonic-gate 	/*
229*7c478bd9Sstevel@tonic-gate 	 * if last section was a 'NOBITS' section then we need to
230*7c478bd9Sstevel@tonic-gate 	 * restore the 'hi' counter to point to the end of the last
231*7c478bd9Sstevel@tonic-gate 	 * non 'NOBITS' section.
232*7c478bd9Sstevel@tonic-gate 	 */
233*7c478bd9Sstevel@tonic-gate 	if (hibit) {
234*7c478bd9Sstevel@tonic-gate 		hi = hibit;
235*7c478bd9Sstevel@tonic-gate 		hibit = 0;
236*7c478bd9Sstevel@tonic-gate 	}
237*7c478bd9Sstevel@tonic-gate 
238*7c478bd9Sstevel@tonic-gate 	/*
239*7c478bd9Sstevel@tonic-gate 	 * Shdr table last
240*7c478bd9Sstevel@tonic-gate 	 */
241*7c478bd9Sstevel@tonic-gate 	if (scncnt != 0) {
242*7c478bd9Sstevel@tonic-gate 		if (hi % FSZ_LONG != 0)
243*7c478bd9Sstevel@tonic-gate 			hi += FSZ_LONG - hi % FSZ_LONG;
244*7c478bd9Sstevel@tonic-gate 		/* LINTED */
245*7c478bd9Sstevel@tonic-gate 		eh->e_shoff = (Off)hi;
246*7c478bd9Sstevel@tonic-gate 		/*
247*7c478bd9Sstevel@tonic-gate 		 * If we are using 'extended sections' then the
248*7c478bd9Sstevel@tonic-gate 		 * e_shnum is stored in the sh_size field of the
249*7c478bd9Sstevel@tonic-gate 		 * first section header.
250*7c478bd9Sstevel@tonic-gate 		 *
251*7c478bd9Sstevel@tonic-gate 		 * NOTE: we set e_shnum to '0' because it's specified
252*7c478bd9Sstevel@tonic-gate 		 * this way in the gABI, and in the hopes that
253*7c478bd9Sstevel@tonic-gate 		 * this will cause less problems to unaware
254*7c478bd9Sstevel@tonic-gate 		 * tools then if we'd set it to SHN_XINDEX (0xffff).
255*7c478bd9Sstevel@tonic-gate 		 */
256*7c478bd9Sstevel@tonic-gate 		if (scncnt < SHN_LORESERVE)
257*7c478bd9Sstevel@tonic-gate 			eh->e_shnum = scncnt;
258*7c478bd9Sstevel@tonic-gate 		else {
259*7c478bd9Sstevel@tonic-gate 			Shdr	*sh;
260*7c478bd9Sstevel@tonic-gate 			sh = (Shdr *)elf->ed_hdscn->s_shdr;
261*7c478bd9Sstevel@tonic-gate 			sh->sh_size = scncnt;
262*7c478bd9Sstevel@tonic-gate 			eh->e_shnum = 0;
263*7c478bd9Sstevel@tonic-gate 		}
264*7c478bd9Sstevel@tonic-gate 		/* LINTED */
265*7c478bd9Sstevel@tonic-gate 		eh->e_shentsize = (Half)elf_fsize(ELF_T_SHDR, 1, ver);
266*7c478bd9Sstevel@tonic-gate 		hi += eh->e_shentsize * scncnt;
267*7c478bd9Sstevel@tonic-gate 	} else {
268*7c478bd9Sstevel@tonic-gate 		eh->e_shoff = 0;
269*7c478bd9Sstevel@tonic-gate 		eh->e_shentsize = 0;
270*7c478bd9Sstevel@tonic-gate 	}
271*7c478bd9Sstevel@tonic-gate 
272*7c478bd9Sstevel@tonic-gate #if	!(defined(_LP64) && defined(_ELF64))
273*7c478bd9Sstevel@tonic-gate 	if (hi > INT_MAX) {
274*7c478bd9Sstevel@tonic-gate 		_elf_seterr(EFMT_FBIG, 0);
275*7c478bd9Sstevel@tonic-gate 		return (0);
276*7c478bd9Sstevel@tonic-gate 	}
277*7c478bd9Sstevel@tonic-gate #endif
278*7c478bd9Sstevel@tonic-gate 
279*7c478bd9Sstevel@tonic-gate 	return ((size_t)hi);
280*7c478bd9Sstevel@tonic-gate }
281*7c478bd9Sstevel@tonic-gate 
282*7c478bd9Sstevel@tonic-gate 
283*7c478bd9Sstevel@tonic-gate 
284*7c478bd9Sstevel@tonic-gate static size_t
285*7c478bd9Sstevel@tonic-gate _elf_upd_usr(Elf * elf)
286*7c478bd9Sstevel@tonic-gate {
287*7c478bd9Sstevel@tonic-gate 	NOTE(ASSUMING_PROTECTED(*elf))
288*7c478bd9Sstevel@tonic-gate 	Lword		hi;
289*7c478bd9Sstevel@tonic-gate 	Elf_Scn *	s;
290*7c478bd9Sstevel@tonic-gate 	register Xword	sz;
291*7c478bd9Sstevel@tonic-gate 	Ehdr *		eh = elf->ed_ehdr;
292*7c478bd9Sstevel@tonic-gate 	unsigned	ver = eh->e_version;
293*7c478bd9Sstevel@tonic-gate 	register char	*p = (char *)eh->e_ident;
294*7c478bd9Sstevel@tonic-gate 
295*7c478bd9Sstevel@tonic-gate 
296*7c478bd9Sstevel@tonic-gate 	/*
297*7c478bd9Sstevel@tonic-gate 	 * Ehdr and Phdr table go first
298*7c478bd9Sstevel@tonic-gate 	 */
299*7c478bd9Sstevel@tonic-gate 	p[EI_MAG0] = ELFMAG0;
300*7c478bd9Sstevel@tonic-gate 	p[EI_MAG1] = ELFMAG1;
301*7c478bd9Sstevel@tonic-gate 	p[EI_MAG2] = ELFMAG2;
302*7c478bd9Sstevel@tonic-gate 	p[EI_MAG3] = ELFMAG3;
303*7c478bd9Sstevel@tonic-gate 	p[EI_CLASS] = ELFCLASS;
304*7c478bd9Sstevel@tonic-gate 	/* LINTED */
305*7c478bd9Sstevel@tonic-gate 	p[EI_VERSION] = (Byte)ver;
306*7c478bd9Sstevel@tonic-gate 	hi = elf_fsize(ELF_T_EHDR, 1, ver);
307*7c478bd9Sstevel@tonic-gate 	/* LINTED */
308*7c478bd9Sstevel@tonic-gate 	eh->e_ehsize = (Half)hi;
309*7c478bd9Sstevel@tonic-gate 
310*7c478bd9Sstevel@tonic-gate 	/*
311*7c478bd9Sstevel@tonic-gate 	 * If phnum is zero, phoff "should" be zero too,
312*7c478bd9Sstevel@tonic-gate 	 * but the application is responsible for it.
313*7c478bd9Sstevel@tonic-gate 	 * Allow a non-zero value here and update the
314*7c478bd9Sstevel@tonic-gate 	 * hi water mark accordingly.
315*7c478bd9Sstevel@tonic-gate 	 */
316*7c478bd9Sstevel@tonic-gate 
317*7c478bd9Sstevel@tonic-gate 	if (eh->e_phnum != 0)
318*7c478bd9Sstevel@tonic-gate 		/* LINTED */
319*7c478bd9Sstevel@tonic-gate 		eh->e_phentsize = (Half)elf_fsize(ELF_T_PHDR, 1, ver);
320*7c478bd9Sstevel@tonic-gate 	else
321*7c478bd9Sstevel@tonic-gate 		eh->e_phentsize = 0;
322*7c478bd9Sstevel@tonic-gate 	if ((sz = eh->e_phoff + eh->e_phentsize * eh->e_phnum) > hi)
323*7c478bd9Sstevel@tonic-gate 		hi = sz;
324*7c478bd9Sstevel@tonic-gate 
325*7c478bd9Sstevel@tonic-gate 	/*
326*7c478bd9Sstevel@tonic-gate 	 * Loop through sections, skipping index zero.
327*7c478bd9Sstevel@tonic-gate 	 * Compute section size before changing hi.
328*7c478bd9Sstevel@tonic-gate 	 * Allow null buffers for NOBITS.
329*7c478bd9Sstevel@tonic-gate 	 */
330*7c478bd9Sstevel@tonic-gate 
331*7c478bd9Sstevel@tonic-gate 	if ((s = elf->ed_hdscn) == 0)
332*7c478bd9Sstevel@tonic-gate 		eh->e_shnum = 0;
333*7c478bd9Sstevel@tonic-gate 	else {
334*7c478bd9Sstevel@tonic-gate 		eh->e_shnum = 1;
335*7c478bd9Sstevel@tonic-gate 		*(Shdr*)s->s_shdr = _elf_snode_init.sb_shdr;
336*7c478bd9Sstevel@tonic-gate 		s = s->s_next;
337*7c478bd9Sstevel@tonic-gate 	}
338*7c478bd9Sstevel@tonic-gate 	for (; s != 0; s = s->s_next) {
339*7c478bd9Sstevel@tonic-gate 		register Dnode	*d;
340*7c478bd9Sstevel@tonic-gate 		register Xword	fsz, j;
341*7c478bd9Sstevel@tonic-gate 		Shdr *sh = s->s_shdr;
342*7c478bd9Sstevel@tonic-gate 
343*7c478bd9Sstevel@tonic-gate 		if ((s->s_myflags & SF_READY) == 0)
344*7c478bd9Sstevel@tonic-gate 			(void) _elfxx_cookscn(s);
345*7c478bd9Sstevel@tonic-gate 
346*7c478bd9Sstevel@tonic-gate 		++eh->e_shnum;
347*7c478bd9Sstevel@tonic-gate 		sz = 0;
348*7c478bd9Sstevel@tonic-gate 		for (d = s->s_hdnode; d != 0; d = d->db_next) {
349*7c478bd9Sstevel@tonic-gate 			if ((fsz = (Xword)elf_fsize(d->db_data.d_type, 1,
350*7c478bd9Sstevel@tonic-gate 			    ver)) == 0)
351*7c478bd9Sstevel@tonic-gate 				return (0);
352*7c478bd9Sstevel@tonic-gate 			j = (Xword)_elf_msize(d->db_data.d_type, ver);
353*7c478bd9Sstevel@tonic-gate 			fsz *= (Xword)(d->db_data.d_size / j);
354*7c478bd9Sstevel@tonic-gate 			d->db_osz = (size_t)fsz;
355*7c478bd9Sstevel@tonic-gate 
356*7c478bd9Sstevel@tonic-gate 			if ((sh->sh_type != SHT_NOBITS) &&
357*7c478bd9Sstevel@tonic-gate 			((j = (Xword)(d->db_data.d_off + d->db_osz)) > sz))
358*7c478bd9Sstevel@tonic-gate 				sz = j;
359*7c478bd9Sstevel@tonic-gate 		}
360*7c478bd9Sstevel@tonic-gate 		if (sh->sh_size < sz) {
361*7c478bd9Sstevel@tonic-gate 			_elf_seterr(EFMT_SCNSZ, 0);
362*7c478bd9Sstevel@tonic-gate 			return (0);
363*7c478bd9Sstevel@tonic-gate 		}
364*7c478bd9Sstevel@tonic-gate 		if ((sh->sh_type != SHT_NOBITS) &&
365*7c478bd9Sstevel@tonic-gate 		    (hi < sh->sh_offset + sh->sh_size))
366*7c478bd9Sstevel@tonic-gate 			hi = sh->sh_offset + sh->sh_size;
367*7c478bd9Sstevel@tonic-gate 	}
368*7c478bd9Sstevel@tonic-gate 
369*7c478bd9Sstevel@tonic-gate 	/*
370*7c478bd9Sstevel@tonic-gate 	 * Shdr table last.  Comment above for phnum/phoff applies here.
371*7c478bd9Sstevel@tonic-gate 	 */
372*7c478bd9Sstevel@tonic-gate 	if (eh->e_shnum != 0)
373*7c478bd9Sstevel@tonic-gate 		/* LINTED */
374*7c478bd9Sstevel@tonic-gate 		eh->e_shentsize = (Half)elf_fsize(ELF_T_SHDR, 1, ver);
375*7c478bd9Sstevel@tonic-gate 	else
376*7c478bd9Sstevel@tonic-gate 		eh->e_shentsize = 0;
377*7c478bd9Sstevel@tonic-gate 
378*7c478bd9Sstevel@tonic-gate 	if ((sz = eh->e_shoff + eh->e_shentsize * eh->e_shnum) > hi)
379*7c478bd9Sstevel@tonic-gate 		hi = sz;
380*7c478bd9Sstevel@tonic-gate 
381*7c478bd9Sstevel@tonic-gate #if	!(defined(_LP64) && defined(_ELF64))
382*7c478bd9Sstevel@tonic-gate 	if (hi > INT_MAX) {
383*7c478bd9Sstevel@tonic-gate 		_elf_seterr(EFMT_FBIG, 0);
384*7c478bd9Sstevel@tonic-gate 		return (0);
385*7c478bd9Sstevel@tonic-gate 	}
386*7c478bd9Sstevel@tonic-gate #endif
387*7c478bd9Sstevel@tonic-gate 
388*7c478bd9Sstevel@tonic-gate 	return ((size_t)hi);
389*7c478bd9Sstevel@tonic-gate }
390*7c478bd9Sstevel@tonic-gate 
391*7c478bd9Sstevel@tonic-gate 
392*7c478bd9Sstevel@tonic-gate static size_t
393*7c478bd9Sstevel@tonic-gate wrt(Elf * elf, Xword outsz, unsigned fill, int update_cmd)
394*7c478bd9Sstevel@tonic-gate {
395*7c478bd9Sstevel@tonic-gate 	NOTE(ASSUMING_PROTECTED(*elf))
396*7c478bd9Sstevel@tonic-gate 	Elf_Data	dst, src;
397*7c478bd9Sstevel@tonic-gate 	unsigned	flag;
398*7c478bd9Sstevel@tonic-gate 	Xword		hi, sz;
399*7c478bd9Sstevel@tonic-gate 	char		*image;
400*7c478bd9Sstevel@tonic-gate 	Elf_Scn		*s;
401*7c478bd9Sstevel@tonic-gate 	Ehdr		*eh = elf->ed_ehdr;
402*7c478bd9Sstevel@tonic-gate 	unsigned	ver = eh->e_version;
403*7c478bd9Sstevel@tonic-gate 	unsigned	encode = eh->e_ident[EI_DATA];
404*7c478bd9Sstevel@tonic-gate 	int		byte;
405*7c478bd9Sstevel@tonic-gate 
406*7c478bd9Sstevel@tonic-gate 	/*
407*7c478bd9Sstevel@tonic-gate 	 * Two issues can cause trouble for the output file.
408*7c478bd9Sstevel@tonic-gate 	 * First, begin() with ELF_C_RDWR opens a file for both
409*7c478bd9Sstevel@tonic-gate 	 * read and write.  On the write update(), the library
410*7c478bd9Sstevel@tonic-gate 	 * has to read everything it needs before truncating
411*7c478bd9Sstevel@tonic-gate 	 * the file.  Second, using mmap for both read and write
412*7c478bd9Sstevel@tonic-gate 	 * is too tricky.  Consequently, the library disables mmap
413*7c478bd9Sstevel@tonic-gate 	 * on the read side.  Using mmap for the output saves swap
414*7c478bd9Sstevel@tonic-gate 	 * space, because that mapping is SHARED, not PRIVATE.
415*7c478bd9Sstevel@tonic-gate 	 *
416*7c478bd9Sstevel@tonic-gate 	 * If the file is write-only, there can be nothing of
417*7c478bd9Sstevel@tonic-gate 	 * interest to bother with.
418*7c478bd9Sstevel@tonic-gate 	 *
419*7c478bd9Sstevel@tonic-gate 	 * The following reads the entire file, which might be
420*7c478bd9Sstevel@tonic-gate 	 * more than necessary.  Better safe than sorry.
421*7c478bd9Sstevel@tonic-gate 	 */
422*7c478bd9Sstevel@tonic-gate 
423*7c478bd9Sstevel@tonic-gate 	if ((elf->ed_myflags & EDF_READ) &&
424*7c478bd9Sstevel@tonic-gate 	    (_elf_vm(elf, (size_t)0, elf->ed_fsz) != OK_YES))
425*7c478bd9Sstevel@tonic-gate 		return (0);
426*7c478bd9Sstevel@tonic-gate 
427*7c478bd9Sstevel@tonic-gate 	flag = elf->ed_myflags & EDF_WRALLOC;
428*7c478bd9Sstevel@tonic-gate 	if ((image = _elf_outmap(elf->ed_fd, outsz, &flag)) == 0)
429*7c478bd9Sstevel@tonic-gate 		return (0);
430*7c478bd9Sstevel@tonic-gate 
431*7c478bd9Sstevel@tonic-gate 	if (flag == 0)
432*7c478bd9Sstevel@tonic-gate 		elf->ed_myflags |= EDF_IMALLOC;
433*7c478bd9Sstevel@tonic-gate 
434*7c478bd9Sstevel@tonic-gate 	/*
435*7c478bd9Sstevel@tonic-gate 	 * If an error occurs below, a "dirty" bit may be cleared
436*7c478bd9Sstevel@tonic-gate 	 * improperly.  To save a second pass through the file,
437*7c478bd9Sstevel@tonic-gate 	 * this code sets the dirty bit on the elf descriptor
438*7c478bd9Sstevel@tonic-gate 	 * when an error happens, assuming that will "cover" any
439*7c478bd9Sstevel@tonic-gate 	 * accidents.
440*7c478bd9Sstevel@tonic-gate 	 */
441*7c478bd9Sstevel@tonic-gate 
442*7c478bd9Sstevel@tonic-gate 	/*
443*7c478bd9Sstevel@tonic-gate 	 * Hi is needed only when 'fill' is non-zero.
444*7c478bd9Sstevel@tonic-gate 	 * Fill is non-zero only when the library
445*7c478bd9Sstevel@tonic-gate 	 * calculates file/section/data buffer offsets.
446*7c478bd9Sstevel@tonic-gate 	 * The lib guarantees they increase monotonically.
447*7c478bd9Sstevel@tonic-gate 	 * That guarantees proper filling below.
448*7c478bd9Sstevel@tonic-gate 	 */
449*7c478bd9Sstevel@tonic-gate 
450*7c478bd9Sstevel@tonic-gate 
451*7c478bd9Sstevel@tonic-gate 	/*
452*7c478bd9Sstevel@tonic-gate 	 * Ehdr first
453*7c478bd9Sstevel@tonic-gate 	 */
454*7c478bd9Sstevel@tonic-gate 
455*7c478bd9Sstevel@tonic-gate 	src.d_buf = (Elf_Void *)eh;
456*7c478bd9Sstevel@tonic-gate 	src.d_type = ELF_T_EHDR;
457*7c478bd9Sstevel@tonic-gate 	src.d_size = sizeof (Ehdr);
458*7c478bd9Sstevel@tonic-gate 	src.d_version = EV_CURRENT;
459*7c478bd9Sstevel@tonic-gate 	dst.d_buf = (Elf_Void *)image;
460*7c478bd9Sstevel@tonic-gate 	dst.d_size = eh->e_ehsize;
461*7c478bd9Sstevel@tonic-gate 	dst.d_version = ver;
462*7c478bd9Sstevel@tonic-gate 	if (elf_xlatetof(&dst, &src, encode) == 0)
463*7c478bd9Sstevel@tonic-gate 		return (0);
464*7c478bd9Sstevel@tonic-gate 	elf->ed_ehflags &= ~ELF_F_DIRTY;
465*7c478bd9Sstevel@tonic-gate 	hi = eh->e_ehsize;
466*7c478bd9Sstevel@tonic-gate 
467*7c478bd9Sstevel@tonic-gate 	/*
468*7c478bd9Sstevel@tonic-gate 	 * Phdr table if one exists
469*7c478bd9Sstevel@tonic-gate 	 */
470*7c478bd9Sstevel@tonic-gate 
471*7c478bd9Sstevel@tonic-gate 	if (eh->e_phnum != 0) {
472*7c478bd9Sstevel@tonic-gate 		unsigned	work;
473*7c478bd9Sstevel@tonic-gate 		/*
474*7c478bd9Sstevel@tonic-gate 		 * Unlike other library data, phdr table is
475*7c478bd9Sstevel@tonic-gate 		 * in the user version.  Change src buffer
476*7c478bd9Sstevel@tonic-gate 		 * version here, fix it after translation.
477*7c478bd9Sstevel@tonic-gate 		 */
478*7c478bd9Sstevel@tonic-gate 
479*7c478bd9Sstevel@tonic-gate 		src.d_buf = (Elf_Void *)elf->ed_phdr;
480*7c478bd9Sstevel@tonic-gate 		src.d_type = ELF_T_PHDR;
481*7c478bd9Sstevel@tonic-gate 		src.d_size = elf->ed_phdrsz;
482*7c478bd9Sstevel@tonic-gate 		ELFACCESSDATA(work, _elf_work)
483*7c478bd9Sstevel@tonic-gate 		src.d_version = work;
484*7c478bd9Sstevel@tonic-gate 		dst.d_buf = (Elf_Void *)(image + eh->e_phoff);
485*7c478bd9Sstevel@tonic-gate 		dst.d_size = eh->e_phnum * eh->e_phentsize;
486*7c478bd9Sstevel@tonic-gate 		hi = (Xword)(eh->e_phoff + dst.d_size);
487*7c478bd9Sstevel@tonic-gate 		if (elf_xlatetof(&dst, &src, encode) == 0) {
488*7c478bd9Sstevel@tonic-gate 			elf->ed_uflags |= ELF_F_DIRTY;
489*7c478bd9Sstevel@tonic-gate 			return (0);
490*7c478bd9Sstevel@tonic-gate 		}
491*7c478bd9Sstevel@tonic-gate 		elf->ed_phflags &= ~ELF_F_DIRTY;
492*7c478bd9Sstevel@tonic-gate 		src.d_version = EV_CURRENT;
493*7c478bd9Sstevel@tonic-gate 	}
494*7c478bd9Sstevel@tonic-gate 
495*7c478bd9Sstevel@tonic-gate 	/*
496*7c478bd9Sstevel@tonic-gate 	 * Loop through sections
497*7c478bd9Sstevel@tonic-gate 	 */
498*7c478bd9Sstevel@tonic-gate 
499*7c478bd9Sstevel@tonic-gate 	ELFACCESSDATA(byte, _elf_byte);
500*7c478bd9Sstevel@tonic-gate 	for (s = elf->ed_hdscn; s != 0; s = s->s_next) {
501*7c478bd9Sstevel@tonic-gate 		register Dnode	*d, *prevd;
502*7c478bd9Sstevel@tonic-gate 		Xword		off = 0;
503*7c478bd9Sstevel@tonic-gate 		Shdr		*sh = s->s_shdr;
504*7c478bd9Sstevel@tonic-gate 		char		*start = image + sh->sh_offset;
505*7c478bd9Sstevel@tonic-gate 		char		*here;
506*7c478bd9Sstevel@tonic-gate 
507*7c478bd9Sstevel@tonic-gate 		/*
508*7c478bd9Sstevel@tonic-gate 		 * Just "clean" DIRTY flag for "empty" sections.  Even if
509*7c478bd9Sstevel@tonic-gate 		 * NOBITS needs padding, the next thing in the
510*7c478bd9Sstevel@tonic-gate 		 * file will provide it.  (And if this NOBITS is
511*7c478bd9Sstevel@tonic-gate 		 * the last thing in the file, no padding needed.)
512*7c478bd9Sstevel@tonic-gate 		 */
513*7c478bd9Sstevel@tonic-gate 		if ((sh->sh_type == SHT_NOBITS) ||
514*7c478bd9Sstevel@tonic-gate 		    (sh->sh_type == SHT_NULL)) {
515*7c478bd9Sstevel@tonic-gate 			d = s->s_hdnode, prevd = 0;
516*7c478bd9Sstevel@tonic-gate 			for (; d != 0; prevd = d, d = d->db_next)
517*7c478bd9Sstevel@tonic-gate 				d->db_uflags &= ~ELF_F_DIRTY;
518*7c478bd9Sstevel@tonic-gate 			continue;
519*7c478bd9Sstevel@tonic-gate 		}
520*7c478bd9Sstevel@tonic-gate 		/*
521*7c478bd9Sstevel@tonic-gate 		 * Clear out the memory between the end of the last
522*7c478bd9Sstevel@tonic-gate 		 * section and the begining of this section.
523*7c478bd9Sstevel@tonic-gate 		 */
524*7c478bd9Sstevel@tonic-gate 		if (fill && (sh->sh_offset > hi)) {
525*7c478bd9Sstevel@tonic-gate 			sz = sh->sh_offset - hi;
526*7c478bd9Sstevel@tonic-gate 			(void) memset(start - sz, byte, sz);
527*7c478bd9Sstevel@tonic-gate 		}
528*7c478bd9Sstevel@tonic-gate 
529*7c478bd9Sstevel@tonic-gate 
530*7c478bd9Sstevel@tonic-gate 		for (d = s->s_hdnode, prevd = 0;
531*7c478bd9Sstevel@tonic-gate 		    d != 0; prevd = d, d = d->db_next) {
532*7c478bd9Sstevel@tonic-gate 			d->db_uflags &= ~ELF_F_DIRTY;
533*7c478bd9Sstevel@tonic-gate 			here = start + d->db_data.d_off;
534*7c478bd9Sstevel@tonic-gate 
535*7c478bd9Sstevel@tonic-gate 			/*
536*7c478bd9Sstevel@tonic-gate 			 * Clear out the memory between the end of the
537*7c478bd9Sstevel@tonic-gate 			 * last update and the start of this data buffer.
538*7c478bd9Sstevel@tonic-gate 			 */
539*7c478bd9Sstevel@tonic-gate 			if (fill && (d->db_data.d_off > off)) {
540*7c478bd9Sstevel@tonic-gate 				sz = (Xword)(d->db_data.d_off - off);
541*7c478bd9Sstevel@tonic-gate 				(void) memset(here - sz, byte, sz);
542*7c478bd9Sstevel@tonic-gate 			}
543*7c478bd9Sstevel@tonic-gate 
544*7c478bd9Sstevel@tonic-gate 			if ((d->db_myflags & DBF_READY) == 0) {
545*7c478bd9Sstevel@tonic-gate 				SCNLOCK(s);
546*7c478bd9Sstevel@tonic-gate 				if (_elf_locked_getdata(s, &prevd->db_data) !=
547*7c478bd9Sstevel@tonic-gate 				    &d->db_data) {
548*7c478bd9Sstevel@tonic-gate 					elf->ed_uflags |= ELF_F_DIRTY;
549*7c478bd9Sstevel@tonic-gate 					SCNUNLOCK(s);
550*7c478bd9Sstevel@tonic-gate 					return (0);
551*7c478bd9Sstevel@tonic-gate 				}
552*7c478bd9Sstevel@tonic-gate 				SCNUNLOCK(s);
553*7c478bd9Sstevel@tonic-gate 			}
554*7c478bd9Sstevel@tonic-gate 			dst.d_buf = (Elf_Void *)here;
555*7c478bd9Sstevel@tonic-gate 			dst.d_size = d->db_osz;
556*7c478bd9Sstevel@tonic-gate 
557*7c478bd9Sstevel@tonic-gate 			/*
558*7c478bd9Sstevel@tonic-gate 			 * Copy the translated bits out to the destination
559*7c478bd9Sstevel@tonic-gate 			 * image.
560*7c478bd9Sstevel@tonic-gate 			 */
561*7c478bd9Sstevel@tonic-gate 			if (elf_xlatetof(&dst, &d->db_data, encode) == 0) {
562*7c478bd9Sstevel@tonic-gate 				elf->ed_uflags |= ELF_F_DIRTY;
563*7c478bd9Sstevel@tonic-gate 				return (0);
564*7c478bd9Sstevel@tonic-gate 			}
565*7c478bd9Sstevel@tonic-gate 
566*7c478bd9Sstevel@tonic-gate 			off = (Xword)(d->db_data.d_off + dst.d_size);
567*7c478bd9Sstevel@tonic-gate 		}
568*7c478bd9Sstevel@tonic-gate 		hi = sh->sh_offset + sh->sh_size;
569*7c478bd9Sstevel@tonic-gate 	}
570*7c478bd9Sstevel@tonic-gate 
571*7c478bd9Sstevel@tonic-gate 	/*
572*7c478bd9Sstevel@tonic-gate 	 * Shdr table last
573*7c478bd9Sstevel@tonic-gate 	 */
574*7c478bd9Sstevel@tonic-gate 
575*7c478bd9Sstevel@tonic-gate 	if (fill && (eh->e_shoff > hi)) {
576*7c478bd9Sstevel@tonic-gate 		sz = eh->e_shoff - hi;
577*7c478bd9Sstevel@tonic-gate 		(void) memset(image + hi, byte, sz);
578*7c478bd9Sstevel@tonic-gate 	}
579*7c478bd9Sstevel@tonic-gate 
580*7c478bd9Sstevel@tonic-gate 	src.d_type = ELF_T_SHDR;
581*7c478bd9Sstevel@tonic-gate 	src.d_size = sizeof (Shdr);
582*7c478bd9Sstevel@tonic-gate 	dst.d_buf = (Elf_Void *)(image + eh->e_shoff);
583*7c478bd9Sstevel@tonic-gate 	dst.d_size = eh->e_shentsize;
584*7c478bd9Sstevel@tonic-gate 	for (s = elf->ed_hdscn; s != 0; s = s->s_next) {
585*7c478bd9Sstevel@tonic-gate 		assert((uintptr_t)dst.d_buf < ((uintptr_t)image + outsz));
586*7c478bd9Sstevel@tonic-gate 		s->s_shflags &= ~ELF_F_DIRTY;
587*7c478bd9Sstevel@tonic-gate 		s->s_uflags &= ~ELF_F_DIRTY;
588*7c478bd9Sstevel@tonic-gate 		src.d_buf = s->s_shdr;
589*7c478bd9Sstevel@tonic-gate 
590*7c478bd9Sstevel@tonic-gate 		if (elf_xlatetof(&dst, &src, encode) == 0) {
591*7c478bd9Sstevel@tonic-gate 			elf->ed_uflags |= ELF_F_DIRTY;
592*7c478bd9Sstevel@tonic-gate 			return (0);
593*7c478bd9Sstevel@tonic-gate 		}
594*7c478bd9Sstevel@tonic-gate 
595*7c478bd9Sstevel@tonic-gate 		dst.d_buf = (char *)dst.d_buf + eh->e_shentsize;
596*7c478bd9Sstevel@tonic-gate 	}
597*7c478bd9Sstevel@tonic-gate 	/*
598*7c478bd9Sstevel@tonic-gate 	 * ELF_C_WRIMAGE signifyes that we build the memory image, but
599*7c478bd9Sstevel@tonic-gate 	 * that we do not actually write it to disk.  This is used
600*7c478bd9Sstevel@tonic-gate 	 * by ld(1) to build up a full image of an elf file and then
601*7c478bd9Sstevel@tonic-gate 	 * to process the file before it's actually written out to
602*7c478bd9Sstevel@tonic-gate 	 * disk.  This saves ld(1) the overhead of having to write
603*7c478bd9Sstevel@tonic-gate 	 * the image out to disk twice.
604*7c478bd9Sstevel@tonic-gate 	 */
605*7c478bd9Sstevel@tonic-gate 	if (update_cmd == ELF_C_WRIMAGE) {
606*7c478bd9Sstevel@tonic-gate 		elf->ed_uflags &= ~ELF_F_DIRTY;
607*7c478bd9Sstevel@tonic-gate 		elf->ed_wrimage = image;
608*7c478bd9Sstevel@tonic-gate 		elf->ed_wrimagesz = outsz;
609*7c478bd9Sstevel@tonic-gate 		return (outsz);
610*7c478bd9Sstevel@tonic-gate 	}
611*7c478bd9Sstevel@tonic-gate 
612*7c478bd9Sstevel@tonic-gate 	if (_elf_outsync(elf->ed_fd, image, outsz,
613*7c478bd9Sstevel@tonic-gate 	    ((elf->ed_myflags & EDF_IMALLOC) ? 0 : 1)) != 0) {
614*7c478bd9Sstevel@tonic-gate 		elf->ed_uflags &= ~ELF_F_DIRTY;
615*7c478bd9Sstevel@tonic-gate 		elf->ed_myflags &= ~EDF_IMALLOC;
616*7c478bd9Sstevel@tonic-gate 		return (outsz);
617*7c478bd9Sstevel@tonic-gate 	}
618*7c478bd9Sstevel@tonic-gate 
619*7c478bd9Sstevel@tonic-gate 	elf->ed_uflags |= ELF_F_DIRTY;
620*7c478bd9Sstevel@tonic-gate 	return (0);
621*7c478bd9Sstevel@tonic-gate }
622*7c478bd9Sstevel@tonic-gate 
623*7c478bd9Sstevel@tonic-gate 
624*7c478bd9Sstevel@tonic-gate 
625*7c478bd9Sstevel@tonic-gate 
626*7c478bd9Sstevel@tonic-gate /*
627*7c478bd9Sstevel@tonic-gate  * The following is a private interface between the linkers (ld & ld.so.1)
628*7c478bd9Sstevel@tonic-gate  * and libelf:
629*7c478bd9Sstevel@tonic-gate  *
630*7c478bd9Sstevel@tonic-gate  * elf_update(elf, ELF_C_WRIMAGE)
631*7c478bd9Sstevel@tonic-gate  *	This will cause full image representing the elf file
632*7c478bd9Sstevel@tonic-gate  *	described by the elf pointer to be built in memory.  If the
633*7c478bd9Sstevel@tonic-gate  *	elf pointer has a valid file descriptor associated with it
634*7c478bd9Sstevel@tonic-gate  *	we will attempt to build the memory image from mmap()'ed
635*7c478bd9Sstevel@tonic-gate  *	storage.  If the elf descriptor does not have a valid
636*7c478bd9Sstevel@tonic-gate  *	file descriptor (opened with elf_begin(0, ELF_C_IMAGE, 0))
637*7c478bd9Sstevel@tonic-gate  *	then the image will be allocated from dynamic memory (malloc()).
638*7c478bd9Sstevel@tonic-gate  *
639*7c478bd9Sstevel@tonic-gate  *	elf_update() will return the size of the memory image built
640*7c478bd9Sstevel@tonic-gate  *	when sucessful.
641*7c478bd9Sstevel@tonic-gate  *
642*7c478bd9Sstevel@tonic-gate  *	When a subsequent call to elf_update() with ELF_C_WRITE as
643*7c478bd9Sstevel@tonic-gate  *	the command is performed it will sync the image created
644*7c478bd9Sstevel@tonic-gate  *	by ELF_C_WRIMAGE to disk (if fd available) and
645*7c478bd9Sstevel@tonic-gate  *	free the memory allocated.
646*7c478bd9Sstevel@tonic-gate  */
647*7c478bd9Sstevel@tonic-gate 
648*7c478bd9Sstevel@tonic-gate off_t
649*7c478bd9Sstevel@tonic-gate _elfxx_update(Elf * elf, Elf_Cmd cmd)
650*7c478bd9Sstevel@tonic-gate {
651*7c478bd9Sstevel@tonic-gate 	size_t		sz;
652*7c478bd9Sstevel@tonic-gate 	unsigned	u;
653*7c478bd9Sstevel@tonic-gate 	Ehdr		*eh = elf->ed_ehdr;
654*7c478bd9Sstevel@tonic-gate 
655*7c478bd9Sstevel@tonic-gate 	if (elf == 0)
656*7c478bd9Sstevel@tonic-gate 		return (-1);
657*7c478bd9Sstevel@tonic-gate 
658*7c478bd9Sstevel@tonic-gate 	ELFWLOCK(elf)
659*7c478bd9Sstevel@tonic-gate 	switch (cmd) {
660*7c478bd9Sstevel@tonic-gate 	default:
661*7c478bd9Sstevel@tonic-gate 		_elf_seterr(EREQ_UPDATE, 0);
662*7c478bd9Sstevel@tonic-gate 		ELFUNLOCK(elf)
663*7c478bd9Sstevel@tonic-gate 		return (-1);
664*7c478bd9Sstevel@tonic-gate 
665*7c478bd9Sstevel@tonic-gate 	case ELF_C_WRIMAGE:
666*7c478bd9Sstevel@tonic-gate 		if ((elf->ed_myflags & EDF_WRITE) == 0) {
667*7c478bd9Sstevel@tonic-gate 			_elf_seterr(EREQ_UPDWRT, 0);
668*7c478bd9Sstevel@tonic-gate 			ELFUNLOCK(elf)
669*7c478bd9Sstevel@tonic-gate 			return (-1);
670*7c478bd9Sstevel@tonic-gate 		}
671*7c478bd9Sstevel@tonic-gate 		break;
672*7c478bd9Sstevel@tonic-gate 	case ELF_C_WRITE:
673*7c478bd9Sstevel@tonic-gate 		if ((elf->ed_myflags & EDF_WRITE) == 0) {
674*7c478bd9Sstevel@tonic-gate 			_elf_seterr(EREQ_UPDWRT, 0);
675*7c478bd9Sstevel@tonic-gate 			ELFUNLOCK(elf)
676*7c478bd9Sstevel@tonic-gate 			return (-1);
677*7c478bd9Sstevel@tonic-gate 		}
678*7c478bd9Sstevel@tonic-gate 		if (elf->ed_wrimage) {
679*7c478bd9Sstevel@tonic-gate 			if (elf->ed_myflags & EDF_WRALLOC) {
680*7c478bd9Sstevel@tonic-gate 				free(elf->ed_wrimage);
681*7c478bd9Sstevel@tonic-gate 				/*
682*7c478bd9Sstevel@tonic-gate 				 * The size is still returned even
683*7c478bd9Sstevel@tonic-gate 				 * though nothing is actually written
684*7c478bd9Sstevel@tonic-gate 				 * out.  This is just to be consistant
685*7c478bd9Sstevel@tonic-gate 				 * with the rest of the interface.
686*7c478bd9Sstevel@tonic-gate 				 */
687*7c478bd9Sstevel@tonic-gate 				sz = elf->ed_wrimagesz;
688*7c478bd9Sstevel@tonic-gate 				elf->ed_wrimage = 0;
689*7c478bd9Sstevel@tonic-gate 				elf->ed_wrimagesz = 0;
690*7c478bd9Sstevel@tonic-gate 				ELFUNLOCK(elf);
691*7c478bd9Sstevel@tonic-gate 				return ((off_t)sz);
692*7c478bd9Sstevel@tonic-gate 			}
693*7c478bd9Sstevel@tonic-gate 			sz = _elf_outsync(elf->ed_fd, elf->ed_wrimage,
694*7c478bd9Sstevel@tonic-gate 				elf->ed_wrimagesz,
695*7c478bd9Sstevel@tonic-gate 				(elf->ed_myflags & EDF_IMALLOC ? 0 : 1));
696*7c478bd9Sstevel@tonic-gate 			elf->ed_myflags &= ~EDF_IMALLOC;
697*7c478bd9Sstevel@tonic-gate 			elf->ed_wrimage = 0;
698*7c478bd9Sstevel@tonic-gate 			elf->ed_wrimagesz = 0;
699*7c478bd9Sstevel@tonic-gate 			ELFUNLOCK(elf);
700*7c478bd9Sstevel@tonic-gate 			return ((off_t)sz);
701*7c478bd9Sstevel@tonic-gate 		}
702*7c478bd9Sstevel@tonic-gate 		/* FALLTHROUGH */
703*7c478bd9Sstevel@tonic-gate 	case ELF_C_NULL:
704*7c478bd9Sstevel@tonic-gate 		break;
705*7c478bd9Sstevel@tonic-gate 	}
706*7c478bd9Sstevel@tonic-gate 
707*7c478bd9Sstevel@tonic-gate 	if (eh == 0) {
708*7c478bd9Sstevel@tonic-gate 		_elf_seterr(ESEQ_EHDR, 0);
709*7c478bd9Sstevel@tonic-gate 		ELFUNLOCK(elf)
710*7c478bd9Sstevel@tonic-gate 		return (-1);
711*7c478bd9Sstevel@tonic-gate 	}
712*7c478bd9Sstevel@tonic-gate 
713*7c478bd9Sstevel@tonic-gate 	if ((u = eh->e_version) > EV_CURRENT) {
714*7c478bd9Sstevel@tonic-gate 		_elf_seterr(EREQ_VER, 0);
715*7c478bd9Sstevel@tonic-gate 		ELFUNLOCK(elf)
716*7c478bd9Sstevel@tonic-gate 		return (-1);
717*7c478bd9Sstevel@tonic-gate 	}
718*7c478bd9Sstevel@tonic-gate 
719*7c478bd9Sstevel@tonic-gate 	if (u == EV_NONE)
720*7c478bd9Sstevel@tonic-gate 		eh->e_version = EV_CURRENT;
721*7c478bd9Sstevel@tonic-gate 
722*7c478bd9Sstevel@tonic-gate 	if ((u = eh->e_ident[EI_DATA]) == ELFDATANONE) {
723*7c478bd9Sstevel@tonic-gate 		unsigned	encode;
724*7c478bd9Sstevel@tonic-gate 
725*7c478bd9Sstevel@tonic-gate 		ELFACCESSDATA(encode, _elf_encode)
726*7c478bd9Sstevel@tonic-gate 		if (encode == ELFDATANONE) {
727*7c478bd9Sstevel@tonic-gate 			_elf_seterr(EREQ_ENCODE, 0);
728*7c478bd9Sstevel@tonic-gate 			ELFUNLOCK(elf)
729*7c478bd9Sstevel@tonic-gate 			return (-1);
730*7c478bd9Sstevel@tonic-gate 		}
731*7c478bd9Sstevel@tonic-gate 		/* LINTED */
732*7c478bd9Sstevel@tonic-gate 		eh->e_ident[EI_DATA] = (Byte)encode;
733*7c478bd9Sstevel@tonic-gate 	}
734*7c478bd9Sstevel@tonic-gate 
735*7c478bd9Sstevel@tonic-gate 	u = 1;
736*7c478bd9Sstevel@tonic-gate 	if (elf->ed_uflags & ELF_F_LAYOUT) {
737*7c478bd9Sstevel@tonic-gate 		sz = _elf_upd_usr(elf);
738*7c478bd9Sstevel@tonic-gate 		u = 0;
739*7c478bd9Sstevel@tonic-gate 	} else
740*7c478bd9Sstevel@tonic-gate 		sz = _elf_upd_lib(elf);
741*7c478bd9Sstevel@tonic-gate 
742*7c478bd9Sstevel@tonic-gate 	if ((sz != 0) && ((cmd == ELF_C_WRITE) || (cmd == ELF_C_WRIMAGE)))
743*7c478bd9Sstevel@tonic-gate 		sz = wrt(elf, (Xword)sz, u, cmd);
744*7c478bd9Sstevel@tonic-gate 
745*7c478bd9Sstevel@tonic-gate 	if (sz == 0) {
746*7c478bd9Sstevel@tonic-gate 		ELFUNLOCK(elf)
747*7c478bd9Sstevel@tonic-gate 		return (-1);
748*7c478bd9Sstevel@tonic-gate 	}
749*7c478bd9Sstevel@tonic-gate 
750*7c478bd9Sstevel@tonic-gate 	ELFUNLOCK(elf)
751*7c478bd9Sstevel@tonic-gate 	return ((off_t)sz);
752*7c478bd9Sstevel@tonic-gate }
753*7c478bd9Sstevel@tonic-gate 
754*7c478bd9Sstevel@tonic-gate 
755*7c478bd9Sstevel@tonic-gate #ifndef _ELF64
756*7c478bd9Sstevel@tonic-gate /* class-independent, only needs to be compiled once */
757*7c478bd9Sstevel@tonic-gate 
758*7c478bd9Sstevel@tonic-gate off_t
759*7c478bd9Sstevel@tonic-gate elf_update(Elf *elf, Elf_Cmd cmd)
760*7c478bd9Sstevel@tonic-gate {
761*7c478bd9Sstevel@tonic-gate 	if (elf == 0)
762*7c478bd9Sstevel@tonic-gate 		return (-1);
763*7c478bd9Sstevel@tonic-gate 
764*7c478bd9Sstevel@tonic-gate 	if (elf->ed_class == ELFCLASS32)
765*7c478bd9Sstevel@tonic-gate 		return (_elf32_update(elf, cmd));
766*7c478bd9Sstevel@tonic-gate 	else if (elf->ed_class == ELFCLASS64) {
767*7c478bd9Sstevel@tonic-gate 		return (_elf64_update(elf, cmd));
768*7c478bd9Sstevel@tonic-gate 	}
769*7c478bd9Sstevel@tonic-gate 
770*7c478bd9Sstevel@tonic-gate 	_elf_seterr(EREQ_CLASS, 0);
771*7c478bd9Sstevel@tonic-gate 	return (-1);
772*7c478bd9Sstevel@tonic-gate }
773*7c478bd9Sstevel@tonic-gate 
774*7c478bd9Sstevel@tonic-gate /*
775*7c478bd9Sstevel@tonic-gate  * 4106312, 4106398, This is an ad-hoc means for the 32-bit
776*7c478bd9Sstevel@tonic-gate  * Elf64 version of libld.so.3 to get around the limitation
777*7c478bd9Sstevel@tonic-gate  * of a 32-bit d_off field.  This is only intended to be
778*7c478bd9Sstevel@tonic-gate  * used by libld to relocate symbols in large NOBITS sections.
779*7c478bd9Sstevel@tonic-gate  */
780*7c478bd9Sstevel@tonic-gate Elf64_Off
781*7c478bd9Sstevel@tonic-gate _elf_getxoff(Elf_Data * d)
782*7c478bd9Sstevel@tonic-gate {
783*7c478bd9Sstevel@tonic-gate 	return (((Dnode *)d)->db_xoff);
784*7c478bd9Sstevel@tonic-gate }
785*7c478bd9Sstevel@tonic-gate #endif /* !_ELF64 */
786