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