10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*1682Srie * Common Development and Distribution License (the "License"). 6*1682Srie * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate 220Sstevel@tonic-gate /* 23*1682Srie * Copyright (c) 1988 AT&T 24*1682Srie * All Rights Reserved 25*1682Srie * 26*1682Srie * 27*1682Srie * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 280Sstevel@tonic-gate * Use is subject to license terms. 290Sstevel@tonic-gate */ 300Sstevel@tonic-gate 310Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 320Sstevel@tonic-gate 330Sstevel@tonic-gate #if !defined(_ELF64) 340Sstevel@tonic-gate #pragma weak elf_update = _elf_update 350Sstevel@tonic-gate #endif 360Sstevel@tonic-gate 370Sstevel@tonic-gate #include "syn.h" 380Sstevel@tonic-gate #include <memory.h> 390Sstevel@tonic-gate #include <malloc.h> 400Sstevel@tonic-gate #include <limits.h> 410Sstevel@tonic-gate 420Sstevel@tonic-gate #include <sgs.h> 430Sstevel@tonic-gate #include "decl.h" 440Sstevel@tonic-gate #include "msg.h" 450Sstevel@tonic-gate 460Sstevel@tonic-gate /* 470Sstevel@tonic-gate * This module is compiled twice, the second time having 480Sstevel@tonic-gate * -D_ELF64 defined. The following set of macros, along 490Sstevel@tonic-gate * with machelf.h, represent the differences between the 500Sstevel@tonic-gate * two compilations. Be careful *not* to add any class- 510Sstevel@tonic-gate * dependent code (anything that has elf32 or elf64 in the 520Sstevel@tonic-gate * name) to this code without hiding it behind a switch- 530Sstevel@tonic-gate * able macro like these. 540Sstevel@tonic-gate */ 550Sstevel@tonic-gate #if defined(_ELF64) 560Sstevel@tonic-gate 570Sstevel@tonic-gate #define FSZ_LONG ELF64_FSZ_XWORD 580Sstevel@tonic-gate #define ELFCLASS ELFCLASS64 590Sstevel@tonic-gate #define _elf_snode_init _elf64_snode_init 600Sstevel@tonic-gate #define _elfxx_cookscn _elf64_cookscn 610Sstevel@tonic-gate #define _elf_upd_lib _elf64_upd_lib 620Sstevel@tonic-gate #define elf_fsize elf64_fsize 630Sstevel@tonic-gate #define _elf_entsz _elf64_entsz 640Sstevel@tonic-gate #define _elf_msize _elf64_msize 650Sstevel@tonic-gate #define _elf_upd_usr _elf64_upd_usr 660Sstevel@tonic-gate #define wrt wrt64 670Sstevel@tonic-gate #define elf_xlatetof elf64_xlatetof 680Sstevel@tonic-gate #define _elfxx_update _elf64_update 690Sstevel@tonic-gate 700Sstevel@tonic-gate #else /* ELF32 */ 710Sstevel@tonic-gate 720Sstevel@tonic-gate #define FSZ_LONG ELF32_FSZ_WORD 730Sstevel@tonic-gate #define ELFCLASS ELFCLASS32 740Sstevel@tonic-gate #define _elf_snode_init _elf32_snode_init 750Sstevel@tonic-gate #define _elfxx_cookscn _elf32_cookscn 760Sstevel@tonic-gate #define _elf_upd_lib _elf32_upd_lib 770Sstevel@tonic-gate #define elf_fsize elf32_fsize 780Sstevel@tonic-gate #define _elf_entsz _elf32_entsz 790Sstevel@tonic-gate #define _elf_msize _elf32_msize 800Sstevel@tonic-gate #define _elf_upd_usr _elf32_upd_usr 810Sstevel@tonic-gate #define wrt wrt32 820Sstevel@tonic-gate #define elf_xlatetof elf32_xlatetof 830Sstevel@tonic-gate #define _elfxx_update _elf32_update 840Sstevel@tonic-gate 850Sstevel@tonic-gate #endif /* ELF64 */ 860Sstevel@tonic-gate 870Sstevel@tonic-gate 880Sstevel@tonic-gate /* 890Sstevel@tonic-gate * Output file update 900Sstevel@tonic-gate * These functions walk an Elf structure, update its information, 910Sstevel@tonic-gate * and optionally write the output file. Because the application 920Sstevel@tonic-gate * may control of the output file layout, two upd_... routines 930Sstevel@tonic-gate * exist. They're similar but too different to merge cleanly. 940Sstevel@tonic-gate * 950Sstevel@tonic-gate * The library defines a "dirty" bit to force parts of the file 960Sstevel@tonic-gate * to be written on update. These routines ignore the dirty bit 970Sstevel@tonic-gate * and do everything. A minimal update routine might be useful 980Sstevel@tonic-gate * someday. 990Sstevel@tonic-gate */ 1000Sstevel@tonic-gate 1010Sstevel@tonic-gate static size_t 1020Sstevel@tonic-gate _elf_upd_lib(Elf * elf) 1030Sstevel@tonic-gate { 1040Sstevel@tonic-gate NOTE(ASSUMING_PROTECTED(*elf)) 1050Sstevel@tonic-gate Lword hi; 1060Sstevel@tonic-gate Lword hibit; 1070Sstevel@tonic-gate Elf_Scn * s; 1080Sstevel@tonic-gate register Xword sz; 1090Sstevel@tonic-gate Ehdr * eh = elf->ed_ehdr; 1100Sstevel@tonic-gate unsigned ver = eh->e_version; 1110Sstevel@tonic-gate register char *p = (char *)eh->e_ident; 1120Sstevel@tonic-gate size_t scncnt; 1130Sstevel@tonic-gate 1140Sstevel@tonic-gate /* 1150Sstevel@tonic-gate * Ehdr and Phdr table go first 1160Sstevel@tonic-gate */ 1170Sstevel@tonic-gate p[EI_MAG0] = ELFMAG0; 1180Sstevel@tonic-gate p[EI_MAG1] = ELFMAG1; 1190Sstevel@tonic-gate p[EI_MAG2] = ELFMAG2; 1200Sstevel@tonic-gate p[EI_MAG3] = ELFMAG3; 1210Sstevel@tonic-gate p[EI_CLASS] = ELFCLASS; 1220Sstevel@tonic-gate /* LINTED */ 1230Sstevel@tonic-gate p[EI_VERSION] = (Byte)ver; 1240Sstevel@tonic-gate hi = elf_fsize(ELF_T_EHDR, 1, ver); 1250Sstevel@tonic-gate /* LINTED */ 1260Sstevel@tonic-gate eh->e_ehsize = (Half)hi; 1270Sstevel@tonic-gate if (eh->e_phnum != 0) { 1280Sstevel@tonic-gate /* LINTED */ 1290Sstevel@tonic-gate eh->e_phentsize = (Half)elf_fsize(ELF_T_PHDR, 1, ver); 1300Sstevel@tonic-gate /* LINTED */ 1310Sstevel@tonic-gate eh->e_phoff = (Off)hi; 1320Sstevel@tonic-gate hi += eh->e_phentsize * eh->e_phnum; 1330Sstevel@tonic-gate } else { 1340Sstevel@tonic-gate eh->e_phoff = 0; 1350Sstevel@tonic-gate eh->e_phentsize = 0; 1360Sstevel@tonic-gate } 1370Sstevel@tonic-gate 1380Sstevel@tonic-gate /* 139*1682Srie * Obtain the first section header. Typically, this section has NULL 140*1682Srie * contents, however in the case of Extended ELF Sections this section 141*1682Srie * is used to hold an alternative e_shnum, e_shstrndx and e_phnum. 142*1682Srie * On initial allocation (see _elf_snode) the elements of this section 143*1682Srie * would have been zeroed. The e_shnum is initialized later, after the 144*1682Srie * section header count has been determined. The e_shstrndx and 145*1682Srie * e_phnum may have already been initialized by the caller (for example, 146*1682Srie * gelf_update_shdr() in mcs(1)). 1470Sstevel@tonic-gate */ 1480Sstevel@tonic-gate if ((s = elf->ed_hdscn) == 0) { 1490Sstevel@tonic-gate eh->e_shnum = 0; 1500Sstevel@tonic-gate scncnt = 0; 1510Sstevel@tonic-gate } else { 152*1682Srie s = s->s_next; 1530Sstevel@tonic-gate scncnt = 1; 1540Sstevel@tonic-gate } 1550Sstevel@tonic-gate 156*1682Srie /* 157*1682Srie * Loop through sections. Compute section size before changing hi. 158*1682Srie * Allow null buffers for NOBITS. 159*1682Srie */ 1600Sstevel@tonic-gate hibit = 0; 1610Sstevel@tonic-gate for (; s != 0; s = s->s_next) { 1620Sstevel@tonic-gate register Dnode *d; 1630Sstevel@tonic-gate register Lword fsz, j; 1640Sstevel@tonic-gate Shdr *sh = s->s_shdr; 1650Sstevel@tonic-gate 1660Sstevel@tonic-gate scncnt++; 1670Sstevel@tonic-gate if (sh->sh_type == SHT_NULL) { 1680Sstevel@tonic-gate *sh = _elf_snode_init.sb_shdr; 1690Sstevel@tonic-gate continue; 1700Sstevel@tonic-gate } 1710Sstevel@tonic-gate 1720Sstevel@tonic-gate if ((s->s_myflags & SF_READY) == 0) 1730Sstevel@tonic-gate (void) _elfxx_cookscn(s); 1740Sstevel@tonic-gate 1750Sstevel@tonic-gate sh->sh_addralign = 1; 1760Sstevel@tonic-gate if ((sz = (Xword)_elf_entsz(sh->sh_type, ver)) != 0) 1770Sstevel@tonic-gate /* LINTED */ 1780Sstevel@tonic-gate sh->sh_entsize = (Half)sz; 1790Sstevel@tonic-gate sz = 0; 1800Sstevel@tonic-gate for (d = s->s_hdnode; d != 0; d = d->db_next) { 1810Sstevel@tonic-gate if ((fsz = elf_fsize(d->db_data.d_type, 1820Sstevel@tonic-gate 1, ver)) == 0) 1830Sstevel@tonic-gate return (0); 1840Sstevel@tonic-gate 1850Sstevel@tonic-gate j = _elf_msize(d->db_data.d_type, ver); 1860Sstevel@tonic-gate fsz *= (d->db_data.d_size / j); 1870Sstevel@tonic-gate d->db_osz = (size_t)fsz; 1880Sstevel@tonic-gate if ((j = d->db_data.d_align) > 1) { 1890Sstevel@tonic-gate if (j > sh->sh_addralign) 1900Sstevel@tonic-gate sh->sh_addralign = (Xword)j; 1910Sstevel@tonic-gate 1920Sstevel@tonic-gate if (sz % j != 0) 1930Sstevel@tonic-gate sz += j - sz % j; 1940Sstevel@tonic-gate } 1950Sstevel@tonic-gate d->db_data.d_off = (off_t)sz; 1960Sstevel@tonic-gate d->db_xoff = sz; 1970Sstevel@tonic-gate sz += (Xword)fsz; 1980Sstevel@tonic-gate } 1990Sstevel@tonic-gate 2000Sstevel@tonic-gate sh->sh_size = sz; 2010Sstevel@tonic-gate /* 2020Sstevel@tonic-gate * We want to take into account the offsets for NOBITS 2030Sstevel@tonic-gate * sections and let the "sh_offsets" point to where 2040Sstevel@tonic-gate * the section would 'conceptually' fit within 2050Sstevel@tonic-gate * the file (as required by the ABI). 2060Sstevel@tonic-gate * 2070Sstevel@tonic-gate * But - we must also make sure that the NOBITS does 2080Sstevel@tonic-gate * not take up any actual space in the file. We preserve 2090Sstevel@tonic-gate * the actual offset into the file in the 'hibit' variable. 2100Sstevel@tonic-gate * When we come to the first non-NOBITS section after a 2110Sstevel@tonic-gate * encountering a NOBITS section the hi counter is restored 2120Sstevel@tonic-gate * to its proper place in the file. 2130Sstevel@tonic-gate */ 2140Sstevel@tonic-gate if (sh->sh_type == SHT_NOBITS) { 2150Sstevel@tonic-gate if (hibit == 0) 2160Sstevel@tonic-gate hibit = hi; 2170Sstevel@tonic-gate } else { 2180Sstevel@tonic-gate if (hibit) { 2190Sstevel@tonic-gate hi = hibit; 2200Sstevel@tonic-gate hibit = 0; 2210Sstevel@tonic-gate } 2220Sstevel@tonic-gate } 2230Sstevel@tonic-gate j = sh->sh_addralign; 2240Sstevel@tonic-gate if ((fsz = hi % j) != 0) 2250Sstevel@tonic-gate hi += j - fsz; 2260Sstevel@tonic-gate 2270Sstevel@tonic-gate /* LINTED */ 2280Sstevel@tonic-gate sh->sh_offset = (Off)hi; 2290Sstevel@tonic-gate hi += sz; 2300Sstevel@tonic-gate } 2310Sstevel@tonic-gate 2320Sstevel@tonic-gate /* 2330Sstevel@tonic-gate * if last section was a 'NOBITS' section then we need to 2340Sstevel@tonic-gate * restore the 'hi' counter to point to the end of the last 2350Sstevel@tonic-gate * non 'NOBITS' section. 2360Sstevel@tonic-gate */ 2370Sstevel@tonic-gate if (hibit) { 2380Sstevel@tonic-gate hi = hibit; 2390Sstevel@tonic-gate hibit = 0; 2400Sstevel@tonic-gate } 2410Sstevel@tonic-gate 2420Sstevel@tonic-gate /* 2430Sstevel@tonic-gate * Shdr table last 2440Sstevel@tonic-gate */ 2450Sstevel@tonic-gate if (scncnt != 0) { 2460Sstevel@tonic-gate if (hi % FSZ_LONG != 0) 2470Sstevel@tonic-gate hi += FSZ_LONG - hi % FSZ_LONG; 2480Sstevel@tonic-gate /* LINTED */ 2490Sstevel@tonic-gate eh->e_shoff = (Off)hi; 2500Sstevel@tonic-gate /* 2510Sstevel@tonic-gate * If we are using 'extended sections' then the 2520Sstevel@tonic-gate * e_shnum is stored in the sh_size field of the 2530Sstevel@tonic-gate * first section header. 2540Sstevel@tonic-gate * 2550Sstevel@tonic-gate * NOTE: we set e_shnum to '0' because it's specified 2560Sstevel@tonic-gate * this way in the gABI, and in the hopes that 2570Sstevel@tonic-gate * this will cause less problems to unaware 2580Sstevel@tonic-gate * tools then if we'd set it to SHN_XINDEX (0xffff). 2590Sstevel@tonic-gate */ 2600Sstevel@tonic-gate if (scncnt < SHN_LORESERVE) 2610Sstevel@tonic-gate eh->e_shnum = scncnt; 2620Sstevel@tonic-gate else { 2630Sstevel@tonic-gate Shdr *sh; 2640Sstevel@tonic-gate sh = (Shdr *)elf->ed_hdscn->s_shdr; 2650Sstevel@tonic-gate sh->sh_size = scncnt; 2660Sstevel@tonic-gate eh->e_shnum = 0; 2670Sstevel@tonic-gate } 2680Sstevel@tonic-gate /* LINTED */ 2690Sstevel@tonic-gate eh->e_shentsize = (Half)elf_fsize(ELF_T_SHDR, 1, ver); 2700Sstevel@tonic-gate hi += eh->e_shentsize * scncnt; 2710Sstevel@tonic-gate } else { 2720Sstevel@tonic-gate eh->e_shoff = 0; 2730Sstevel@tonic-gate eh->e_shentsize = 0; 2740Sstevel@tonic-gate } 2750Sstevel@tonic-gate 2760Sstevel@tonic-gate #if !(defined(_LP64) && defined(_ELF64)) 2770Sstevel@tonic-gate if (hi > INT_MAX) { 2780Sstevel@tonic-gate _elf_seterr(EFMT_FBIG, 0); 2790Sstevel@tonic-gate return (0); 2800Sstevel@tonic-gate } 2810Sstevel@tonic-gate #endif 2820Sstevel@tonic-gate 2830Sstevel@tonic-gate return ((size_t)hi); 2840Sstevel@tonic-gate } 2850Sstevel@tonic-gate 2860Sstevel@tonic-gate 2870Sstevel@tonic-gate 2880Sstevel@tonic-gate static size_t 2890Sstevel@tonic-gate _elf_upd_usr(Elf * elf) 2900Sstevel@tonic-gate { 2910Sstevel@tonic-gate NOTE(ASSUMING_PROTECTED(*elf)) 2920Sstevel@tonic-gate Lword hi; 2930Sstevel@tonic-gate Elf_Scn * s; 2940Sstevel@tonic-gate register Xword sz; 2950Sstevel@tonic-gate Ehdr * eh = elf->ed_ehdr; 2960Sstevel@tonic-gate unsigned ver = eh->e_version; 2970Sstevel@tonic-gate register char *p = (char *)eh->e_ident; 2980Sstevel@tonic-gate 2990Sstevel@tonic-gate 3000Sstevel@tonic-gate /* 3010Sstevel@tonic-gate * Ehdr and Phdr table go first 3020Sstevel@tonic-gate */ 3030Sstevel@tonic-gate p[EI_MAG0] = ELFMAG0; 3040Sstevel@tonic-gate p[EI_MAG1] = ELFMAG1; 3050Sstevel@tonic-gate p[EI_MAG2] = ELFMAG2; 3060Sstevel@tonic-gate p[EI_MAG3] = ELFMAG3; 3070Sstevel@tonic-gate p[EI_CLASS] = ELFCLASS; 3080Sstevel@tonic-gate /* LINTED */ 3090Sstevel@tonic-gate p[EI_VERSION] = (Byte)ver; 3100Sstevel@tonic-gate hi = elf_fsize(ELF_T_EHDR, 1, ver); 3110Sstevel@tonic-gate /* LINTED */ 3120Sstevel@tonic-gate eh->e_ehsize = (Half)hi; 3130Sstevel@tonic-gate 3140Sstevel@tonic-gate /* 3150Sstevel@tonic-gate * If phnum is zero, phoff "should" be zero too, 3160Sstevel@tonic-gate * but the application is responsible for it. 3170Sstevel@tonic-gate * Allow a non-zero value here and update the 3180Sstevel@tonic-gate * hi water mark accordingly. 3190Sstevel@tonic-gate */ 3200Sstevel@tonic-gate 3210Sstevel@tonic-gate if (eh->e_phnum != 0) 3220Sstevel@tonic-gate /* LINTED */ 3230Sstevel@tonic-gate eh->e_phentsize = (Half)elf_fsize(ELF_T_PHDR, 1, ver); 3240Sstevel@tonic-gate else 3250Sstevel@tonic-gate eh->e_phentsize = 0; 3260Sstevel@tonic-gate if ((sz = eh->e_phoff + eh->e_phentsize * eh->e_phnum) > hi) 3270Sstevel@tonic-gate hi = sz; 3280Sstevel@tonic-gate 3290Sstevel@tonic-gate /* 3300Sstevel@tonic-gate * Loop through sections, skipping index zero. 3310Sstevel@tonic-gate * Compute section size before changing hi. 3320Sstevel@tonic-gate * Allow null buffers for NOBITS. 3330Sstevel@tonic-gate */ 3340Sstevel@tonic-gate 3350Sstevel@tonic-gate if ((s = elf->ed_hdscn) == 0) 3360Sstevel@tonic-gate eh->e_shnum = 0; 3370Sstevel@tonic-gate else { 3380Sstevel@tonic-gate eh->e_shnum = 1; 3390Sstevel@tonic-gate *(Shdr*)s->s_shdr = _elf_snode_init.sb_shdr; 3400Sstevel@tonic-gate s = s->s_next; 3410Sstevel@tonic-gate } 3420Sstevel@tonic-gate for (; s != 0; s = s->s_next) { 3430Sstevel@tonic-gate register Dnode *d; 3440Sstevel@tonic-gate register Xword fsz, j; 3450Sstevel@tonic-gate Shdr *sh = s->s_shdr; 3460Sstevel@tonic-gate 3470Sstevel@tonic-gate if ((s->s_myflags & SF_READY) == 0) 3480Sstevel@tonic-gate (void) _elfxx_cookscn(s); 3490Sstevel@tonic-gate 3500Sstevel@tonic-gate ++eh->e_shnum; 3510Sstevel@tonic-gate sz = 0; 3520Sstevel@tonic-gate for (d = s->s_hdnode; d != 0; d = d->db_next) { 3530Sstevel@tonic-gate if ((fsz = (Xword)elf_fsize(d->db_data.d_type, 1, 3540Sstevel@tonic-gate ver)) == 0) 3550Sstevel@tonic-gate return (0); 3560Sstevel@tonic-gate j = (Xword)_elf_msize(d->db_data.d_type, ver); 3570Sstevel@tonic-gate fsz *= (Xword)(d->db_data.d_size / j); 3580Sstevel@tonic-gate d->db_osz = (size_t)fsz; 3590Sstevel@tonic-gate 3600Sstevel@tonic-gate if ((sh->sh_type != SHT_NOBITS) && 3610Sstevel@tonic-gate ((j = (Xword)(d->db_data.d_off + d->db_osz)) > sz)) 3620Sstevel@tonic-gate sz = j; 3630Sstevel@tonic-gate } 3640Sstevel@tonic-gate if (sh->sh_size < sz) { 3650Sstevel@tonic-gate _elf_seterr(EFMT_SCNSZ, 0); 3660Sstevel@tonic-gate return (0); 3670Sstevel@tonic-gate } 3680Sstevel@tonic-gate if ((sh->sh_type != SHT_NOBITS) && 3690Sstevel@tonic-gate (hi < sh->sh_offset + sh->sh_size)) 3700Sstevel@tonic-gate hi = sh->sh_offset + sh->sh_size; 3710Sstevel@tonic-gate } 3720Sstevel@tonic-gate 3730Sstevel@tonic-gate /* 3740Sstevel@tonic-gate * Shdr table last. Comment above for phnum/phoff applies here. 3750Sstevel@tonic-gate */ 3760Sstevel@tonic-gate if (eh->e_shnum != 0) 3770Sstevel@tonic-gate /* LINTED */ 3780Sstevel@tonic-gate eh->e_shentsize = (Half)elf_fsize(ELF_T_SHDR, 1, ver); 3790Sstevel@tonic-gate else 3800Sstevel@tonic-gate eh->e_shentsize = 0; 3810Sstevel@tonic-gate 3820Sstevel@tonic-gate if ((sz = eh->e_shoff + eh->e_shentsize * eh->e_shnum) > hi) 3830Sstevel@tonic-gate hi = sz; 3840Sstevel@tonic-gate 3850Sstevel@tonic-gate #if !(defined(_LP64) && defined(_ELF64)) 3860Sstevel@tonic-gate if (hi > INT_MAX) { 3870Sstevel@tonic-gate _elf_seterr(EFMT_FBIG, 0); 3880Sstevel@tonic-gate return (0); 3890Sstevel@tonic-gate } 3900Sstevel@tonic-gate #endif 3910Sstevel@tonic-gate 3920Sstevel@tonic-gate return ((size_t)hi); 3930Sstevel@tonic-gate } 3940Sstevel@tonic-gate 3950Sstevel@tonic-gate 3960Sstevel@tonic-gate static size_t 3970Sstevel@tonic-gate wrt(Elf * elf, Xword outsz, unsigned fill, int update_cmd) 3980Sstevel@tonic-gate { 3990Sstevel@tonic-gate NOTE(ASSUMING_PROTECTED(*elf)) 4000Sstevel@tonic-gate Elf_Data dst, src; 4010Sstevel@tonic-gate unsigned flag; 4020Sstevel@tonic-gate Xword hi, sz; 4030Sstevel@tonic-gate char *image; 4040Sstevel@tonic-gate Elf_Scn *s; 4050Sstevel@tonic-gate Ehdr *eh = elf->ed_ehdr; 4060Sstevel@tonic-gate unsigned ver = eh->e_version; 4070Sstevel@tonic-gate unsigned encode = eh->e_ident[EI_DATA]; 4080Sstevel@tonic-gate int byte; 4090Sstevel@tonic-gate 4100Sstevel@tonic-gate /* 4110Sstevel@tonic-gate * Two issues can cause trouble for the output file. 4120Sstevel@tonic-gate * First, begin() with ELF_C_RDWR opens a file for both 4130Sstevel@tonic-gate * read and write. On the write update(), the library 4140Sstevel@tonic-gate * has to read everything it needs before truncating 4150Sstevel@tonic-gate * the file. Second, using mmap for both read and write 4160Sstevel@tonic-gate * is too tricky. Consequently, the library disables mmap 4170Sstevel@tonic-gate * on the read side. Using mmap for the output saves swap 4180Sstevel@tonic-gate * space, because that mapping is SHARED, not PRIVATE. 4190Sstevel@tonic-gate * 4200Sstevel@tonic-gate * If the file is write-only, there can be nothing of 4210Sstevel@tonic-gate * interest to bother with. 4220Sstevel@tonic-gate * 4230Sstevel@tonic-gate * The following reads the entire file, which might be 4240Sstevel@tonic-gate * more than necessary. Better safe than sorry. 4250Sstevel@tonic-gate */ 4260Sstevel@tonic-gate 4270Sstevel@tonic-gate if ((elf->ed_myflags & EDF_READ) && 4280Sstevel@tonic-gate (_elf_vm(elf, (size_t)0, elf->ed_fsz) != OK_YES)) 4290Sstevel@tonic-gate return (0); 4300Sstevel@tonic-gate 4310Sstevel@tonic-gate flag = elf->ed_myflags & EDF_WRALLOC; 4320Sstevel@tonic-gate if ((image = _elf_outmap(elf->ed_fd, outsz, &flag)) == 0) 4330Sstevel@tonic-gate return (0); 4340Sstevel@tonic-gate 4350Sstevel@tonic-gate if (flag == 0) 4360Sstevel@tonic-gate elf->ed_myflags |= EDF_IMALLOC; 4370Sstevel@tonic-gate 4380Sstevel@tonic-gate /* 4390Sstevel@tonic-gate * If an error occurs below, a "dirty" bit may be cleared 4400Sstevel@tonic-gate * improperly. To save a second pass through the file, 4410Sstevel@tonic-gate * this code sets the dirty bit on the elf descriptor 4420Sstevel@tonic-gate * when an error happens, assuming that will "cover" any 4430Sstevel@tonic-gate * accidents. 4440Sstevel@tonic-gate */ 4450Sstevel@tonic-gate 4460Sstevel@tonic-gate /* 4470Sstevel@tonic-gate * Hi is needed only when 'fill' is non-zero. 4480Sstevel@tonic-gate * Fill is non-zero only when the library 4490Sstevel@tonic-gate * calculates file/section/data buffer offsets. 4500Sstevel@tonic-gate * The lib guarantees they increase monotonically. 4510Sstevel@tonic-gate * That guarantees proper filling below. 4520Sstevel@tonic-gate */ 4530Sstevel@tonic-gate 4540Sstevel@tonic-gate 4550Sstevel@tonic-gate /* 4560Sstevel@tonic-gate * Ehdr first 4570Sstevel@tonic-gate */ 4580Sstevel@tonic-gate 4590Sstevel@tonic-gate src.d_buf = (Elf_Void *)eh; 4600Sstevel@tonic-gate src.d_type = ELF_T_EHDR; 4610Sstevel@tonic-gate src.d_size = sizeof (Ehdr); 4620Sstevel@tonic-gate src.d_version = EV_CURRENT; 4630Sstevel@tonic-gate dst.d_buf = (Elf_Void *)image; 4640Sstevel@tonic-gate dst.d_size = eh->e_ehsize; 4650Sstevel@tonic-gate dst.d_version = ver; 4660Sstevel@tonic-gate if (elf_xlatetof(&dst, &src, encode) == 0) 4670Sstevel@tonic-gate return (0); 4680Sstevel@tonic-gate elf->ed_ehflags &= ~ELF_F_DIRTY; 4690Sstevel@tonic-gate hi = eh->e_ehsize; 4700Sstevel@tonic-gate 4710Sstevel@tonic-gate /* 4720Sstevel@tonic-gate * Phdr table if one exists 4730Sstevel@tonic-gate */ 4740Sstevel@tonic-gate 4750Sstevel@tonic-gate if (eh->e_phnum != 0) { 4760Sstevel@tonic-gate unsigned work; 4770Sstevel@tonic-gate /* 4780Sstevel@tonic-gate * Unlike other library data, phdr table is 4790Sstevel@tonic-gate * in the user version. Change src buffer 4800Sstevel@tonic-gate * version here, fix it after translation. 4810Sstevel@tonic-gate */ 4820Sstevel@tonic-gate 4830Sstevel@tonic-gate src.d_buf = (Elf_Void *)elf->ed_phdr; 4840Sstevel@tonic-gate src.d_type = ELF_T_PHDR; 4850Sstevel@tonic-gate src.d_size = elf->ed_phdrsz; 4860Sstevel@tonic-gate ELFACCESSDATA(work, _elf_work) 4870Sstevel@tonic-gate src.d_version = work; 4880Sstevel@tonic-gate dst.d_buf = (Elf_Void *)(image + eh->e_phoff); 4890Sstevel@tonic-gate dst.d_size = eh->e_phnum * eh->e_phentsize; 4900Sstevel@tonic-gate hi = (Xword)(eh->e_phoff + dst.d_size); 4910Sstevel@tonic-gate if (elf_xlatetof(&dst, &src, encode) == 0) { 4920Sstevel@tonic-gate elf->ed_uflags |= ELF_F_DIRTY; 4930Sstevel@tonic-gate return (0); 4940Sstevel@tonic-gate } 4950Sstevel@tonic-gate elf->ed_phflags &= ~ELF_F_DIRTY; 4960Sstevel@tonic-gate src.d_version = EV_CURRENT; 4970Sstevel@tonic-gate } 4980Sstevel@tonic-gate 4990Sstevel@tonic-gate /* 5000Sstevel@tonic-gate * Loop through sections 5010Sstevel@tonic-gate */ 5020Sstevel@tonic-gate 5030Sstevel@tonic-gate ELFACCESSDATA(byte, _elf_byte); 5040Sstevel@tonic-gate for (s = elf->ed_hdscn; s != 0; s = s->s_next) { 5050Sstevel@tonic-gate register Dnode *d, *prevd; 5060Sstevel@tonic-gate Xword off = 0; 5070Sstevel@tonic-gate Shdr *sh = s->s_shdr; 5080Sstevel@tonic-gate char *start = image + sh->sh_offset; 5090Sstevel@tonic-gate char *here; 5100Sstevel@tonic-gate 5110Sstevel@tonic-gate /* 5120Sstevel@tonic-gate * Just "clean" DIRTY flag for "empty" sections. Even if 5130Sstevel@tonic-gate * NOBITS needs padding, the next thing in the 5140Sstevel@tonic-gate * file will provide it. (And if this NOBITS is 5150Sstevel@tonic-gate * the last thing in the file, no padding needed.) 5160Sstevel@tonic-gate */ 5170Sstevel@tonic-gate if ((sh->sh_type == SHT_NOBITS) || 5180Sstevel@tonic-gate (sh->sh_type == SHT_NULL)) { 5190Sstevel@tonic-gate d = s->s_hdnode, prevd = 0; 5200Sstevel@tonic-gate for (; d != 0; prevd = d, d = d->db_next) 5210Sstevel@tonic-gate d->db_uflags &= ~ELF_F_DIRTY; 5220Sstevel@tonic-gate continue; 5230Sstevel@tonic-gate } 5240Sstevel@tonic-gate /* 5250Sstevel@tonic-gate * Clear out the memory between the end of the last 5260Sstevel@tonic-gate * section and the begining of this section. 5270Sstevel@tonic-gate */ 5280Sstevel@tonic-gate if (fill && (sh->sh_offset > hi)) { 5290Sstevel@tonic-gate sz = sh->sh_offset - hi; 5300Sstevel@tonic-gate (void) memset(start - sz, byte, sz); 5310Sstevel@tonic-gate } 5320Sstevel@tonic-gate 5330Sstevel@tonic-gate 5340Sstevel@tonic-gate for (d = s->s_hdnode, prevd = 0; 5350Sstevel@tonic-gate d != 0; prevd = d, d = d->db_next) { 5360Sstevel@tonic-gate d->db_uflags &= ~ELF_F_DIRTY; 5370Sstevel@tonic-gate here = start + d->db_data.d_off; 5380Sstevel@tonic-gate 5390Sstevel@tonic-gate /* 5400Sstevel@tonic-gate * Clear out the memory between the end of the 5410Sstevel@tonic-gate * last update and the start of this data buffer. 5420Sstevel@tonic-gate */ 5430Sstevel@tonic-gate if (fill && (d->db_data.d_off > off)) { 5440Sstevel@tonic-gate sz = (Xword)(d->db_data.d_off - off); 5450Sstevel@tonic-gate (void) memset(here - sz, byte, sz); 5460Sstevel@tonic-gate } 5470Sstevel@tonic-gate 5480Sstevel@tonic-gate if ((d->db_myflags & DBF_READY) == 0) { 5490Sstevel@tonic-gate SCNLOCK(s); 5500Sstevel@tonic-gate if (_elf_locked_getdata(s, &prevd->db_data) != 5510Sstevel@tonic-gate &d->db_data) { 5520Sstevel@tonic-gate elf->ed_uflags |= ELF_F_DIRTY; 5530Sstevel@tonic-gate SCNUNLOCK(s); 5540Sstevel@tonic-gate return (0); 5550Sstevel@tonic-gate } 5560Sstevel@tonic-gate SCNUNLOCK(s); 5570Sstevel@tonic-gate } 5580Sstevel@tonic-gate dst.d_buf = (Elf_Void *)here; 5590Sstevel@tonic-gate dst.d_size = d->db_osz; 5600Sstevel@tonic-gate 5610Sstevel@tonic-gate /* 5620Sstevel@tonic-gate * Copy the translated bits out to the destination 5630Sstevel@tonic-gate * image. 5640Sstevel@tonic-gate */ 5650Sstevel@tonic-gate if (elf_xlatetof(&dst, &d->db_data, encode) == 0) { 5660Sstevel@tonic-gate elf->ed_uflags |= ELF_F_DIRTY; 5670Sstevel@tonic-gate return (0); 5680Sstevel@tonic-gate } 5690Sstevel@tonic-gate 5700Sstevel@tonic-gate off = (Xword)(d->db_data.d_off + dst.d_size); 5710Sstevel@tonic-gate } 5720Sstevel@tonic-gate hi = sh->sh_offset + sh->sh_size; 5730Sstevel@tonic-gate } 5740Sstevel@tonic-gate 5750Sstevel@tonic-gate /* 5760Sstevel@tonic-gate * Shdr table last 5770Sstevel@tonic-gate */ 5780Sstevel@tonic-gate 5790Sstevel@tonic-gate if (fill && (eh->e_shoff > hi)) { 5800Sstevel@tonic-gate sz = eh->e_shoff - hi; 5810Sstevel@tonic-gate (void) memset(image + hi, byte, sz); 5820Sstevel@tonic-gate } 5830Sstevel@tonic-gate 5840Sstevel@tonic-gate src.d_type = ELF_T_SHDR; 5850Sstevel@tonic-gate src.d_size = sizeof (Shdr); 5860Sstevel@tonic-gate dst.d_buf = (Elf_Void *)(image + eh->e_shoff); 5870Sstevel@tonic-gate dst.d_size = eh->e_shentsize; 5880Sstevel@tonic-gate for (s = elf->ed_hdscn; s != 0; s = s->s_next) { 5890Sstevel@tonic-gate assert((uintptr_t)dst.d_buf < ((uintptr_t)image + outsz)); 5900Sstevel@tonic-gate s->s_shflags &= ~ELF_F_DIRTY; 5910Sstevel@tonic-gate s->s_uflags &= ~ELF_F_DIRTY; 5920Sstevel@tonic-gate src.d_buf = s->s_shdr; 5930Sstevel@tonic-gate 5940Sstevel@tonic-gate if (elf_xlatetof(&dst, &src, encode) == 0) { 5950Sstevel@tonic-gate elf->ed_uflags |= ELF_F_DIRTY; 5960Sstevel@tonic-gate return (0); 5970Sstevel@tonic-gate } 5980Sstevel@tonic-gate 5990Sstevel@tonic-gate dst.d_buf = (char *)dst.d_buf + eh->e_shentsize; 6000Sstevel@tonic-gate } 6010Sstevel@tonic-gate /* 6020Sstevel@tonic-gate * ELF_C_WRIMAGE signifyes that we build the memory image, but 6030Sstevel@tonic-gate * that we do not actually write it to disk. This is used 6040Sstevel@tonic-gate * by ld(1) to build up a full image of an elf file and then 6050Sstevel@tonic-gate * to process the file before it's actually written out to 6060Sstevel@tonic-gate * disk. This saves ld(1) the overhead of having to write 6070Sstevel@tonic-gate * the image out to disk twice. 6080Sstevel@tonic-gate */ 6090Sstevel@tonic-gate if (update_cmd == ELF_C_WRIMAGE) { 6100Sstevel@tonic-gate elf->ed_uflags &= ~ELF_F_DIRTY; 6110Sstevel@tonic-gate elf->ed_wrimage = image; 6120Sstevel@tonic-gate elf->ed_wrimagesz = outsz; 6130Sstevel@tonic-gate return (outsz); 6140Sstevel@tonic-gate } 6150Sstevel@tonic-gate 6160Sstevel@tonic-gate if (_elf_outsync(elf->ed_fd, image, outsz, 6170Sstevel@tonic-gate ((elf->ed_myflags & EDF_IMALLOC) ? 0 : 1)) != 0) { 6180Sstevel@tonic-gate elf->ed_uflags &= ~ELF_F_DIRTY; 6190Sstevel@tonic-gate elf->ed_myflags &= ~EDF_IMALLOC; 6200Sstevel@tonic-gate return (outsz); 6210Sstevel@tonic-gate } 6220Sstevel@tonic-gate 6230Sstevel@tonic-gate elf->ed_uflags |= ELF_F_DIRTY; 6240Sstevel@tonic-gate return (0); 6250Sstevel@tonic-gate } 6260Sstevel@tonic-gate 6270Sstevel@tonic-gate 6280Sstevel@tonic-gate 6290Sstevel@tonic-gate 6300Sstevel@tonic-gate /* 6310Sstevel@tonic-gate * The following is a private interface between the linkers (ld & ld.so.1) 6320Sstevel@tonic-gate * and libelf: 6330Sstevel@tonic-gate * 6340Sstevel@tonic-gate * elf_update(elf, ELF_C_WRIMAGE) 6350Sstevel@tonic-gate * This will cause full image representing the elf file 6360Sstevel@tonic-gate * described by the elf pointer to be built in memory. If the 6370Sstevel@tonic-gate * elf pointer has a valid file descriptor associated with it 6380Sstevel@tonic-gate * we will attempt to build the memory image from mmap()'ed 6390Sstevel@tonic-gate * storage. If the elf descriptor does not have a valid 6400Sstevel@tonic-gate * file descriptor (opened with elf_begin(0, ELF_C_IMAGE, 0)) 6410Sstevel@tonic-gate * then the image will be allocated from dynamic memory (malloc()). 6420Sstevel@tonic-gate * 6430Sstevel@tonic-gate * elf_update() will return the size of the memory image built 6440Sstevel@tonic-gate * when sucessful. 6450Sstevel@tonic-gate * 6460Sstevel@tonic-gate * When a subsequent call to elf_update() with ELF_C_WRITE as 6470Sstevel@tonic-gate * the command is performed it will sync the image created 6480Sstevel@tonic-gate * by ELF_C_WRIMAGE to disk (if fd available) and 6490Sstevel@tonic-gate * free the memory allocated. 6500Sstevel@tonic-gate */ 6510Sstevel@tonic-gate 6520Sstevel@tonic-gate off_t 6530Sstevel@tonic-gate _elfxx_update(Elf * elf, Elf_Cmd cmd) 6540Sstevel@tonic-gate { 6550Sstevel@tonic-gate size_t sz; 6560Sstevel@tonic-gate unsigned u; 6570Sstevel@tonic-gate Ehdr *eh = elf->ed_ehdr; 6580Sstevel@tonic-gate 6590Sstevel@tonic-gate if (elf == 0) 6600Sstevel@tonic-gate return (-1); 6610Sstevel@tonic-gate 6620Sstevel@tonic-gate ELFWLOCK(elf) 6630Sstevel@tonic-gate switch (cmd) { 6640Sstevel@tonic-gate default: 6650Sstevel@tonic-gate _elf_seterr(EREQ_UPDATE, 0); 6660Sstevel@tonic-gate ELFUNLOCK(elf) 6670Sstevel@tonic-gate return (-1); 6680Sstevel@tonic-gate 6690Sstevel@tonic-gate case ELF_C_WRIMAGE: 6700Sstevel@tonic-gate if ((elf->ed_myflags & EDF_WRITE) == 0) { 6710Sstevel@tonic-gate _elf_seterr(EREQ_UPDWRT, 0); 6720Sstevel@tonic-gate ELFUNLOCK(elf) 6730Sstevel@tonic-gate return (-1); 6740Sstevel@tonic-gate } 6750Sstevel@tonic-gate break; 6760Sstevel@tonic-gate case ELF_C_WRITE: 6770Sstevel@tonic-gate if ((elf->ed_myflags & EDF_WRITE) == 0) { 6780Sstevel@tonic-gate _elf_seterr(EREQ_UPDWRT, 0); 6790Sstevel@tonic-gate ELFUNLOCK(elf) 6800Sstevel@tonic-gate return (-1); 6810Sstevel@tonic-gate } 6820Sstevel@tonic-gate if (elf->ed_wrimage) { 6830Sstevel@tonic-gate if (elf->ed_myflags & EDF_WRALLOC) { 6840Sstevel@tonic-gate free(elf->ed_wrimage); 6850Sstevel@tonic-gate /* 6860Sstevel@tonic-gate * The size is still returned even 6870Sstevel@tonic-gate * though nothing is actually written 6880Sstevel@tonic-gate * out. This is just to be consistant 6890Sstevel@tonic-gate * with the rest of the interface. 6900Sstevel@tonic-gate */ 6910Sstevel@tonic-gate sz = elf->ed_wrimagesz; 6920Sstevel@tonic-gate elf->ed_wrimage = 0; 6930Sstevel@tonic-gate elf->ed_wrimagesz = 0; 6940Sstevel@tonic-gate ELFUNLOCK(elf); 6950Sstevel@tonic-gate return ((off_t)sz); 6960Sstevel@tonic-gate } 6970Sstevel@tonic-gate sz = _elf_outsync(elf->ed_fd, elf->ed_wrimage, 6980Sstevel@tonic-gate elf->ed_wrimagesz, 6990Sstevel@tonic-gate (elf->ed_myflags & EDF_IMALLOC ? 0 : 1)); 7000Sstevel@tonic-gate elf->ed_myflags &= ~EDF_IMALLOC; 7010Sstevel@tonic-gate elf->ed_wrimage = 0; 7020Sstevel@tonic-gate elf->ed_wrimagesz = 0; 7030Sstevel@tonic-gate ELFUNLOCK(elf); 7040Sstevel@tonic-gate return ((off_t)sz); 7050Sstevel@tonic-gate } 7060Sstevel@tonic-gate /* FALLTHROUGH */ 7070Sstevel@tonic-gate case ELF_C_NULL: 7080Sstevel@tonic-gate break; 7090Sstevel@tonic-gate } 7100Sstevel@tonic-gate 7110Sstevel@tonic-gate if (eh == 0) { 7120Sstevel@tonic-gate _elf_seterr(ESEQ_EHDR, 0); 7130Sstevel@tonic-gate ELFUNLOCK(elf) 7140Sstevel@tonic-gate return (-1); 7150Sstevel@tonic-gate } 7160Sstevel@tonic-gate 7170Sstevel@tonic-gate if ((u = eh->e_version) > EV_CURRENT) { 7180Sstevel@tonic-gate _elf_seterr(EREQ_VER, 0); 7190Sstevel@tonic-gate ELFUNLOCK(elf) 7200Sstevel@tonic-gate return (-1); 7210Sstevel@tonic-gate } 7220Sstevel@tonic-gate 7230Sstevel@tonic-gate if (u == EV_NONE) 7240Sstevel@tonic-gate eh->e_version = EV_CURRENT; 7250Sstevel@tonic-gate 7260Sstevel@tonic-gate if ((u = eh->e_ident[EI_DATA]) == ELFDATANONE) { 7270Sstevel@tonic-gate unsigned encode; 7280Sstevel@tonic-gate 7290Sstevel@tonic-gate ELFACCESSDATA(encode, _elf_encode) 7300Sstevel@tonic-gate if (encode == ELFDATANONE) { 7310Sstevel@tonic-gate _elf_seterr(EREQ_ENCODE, 0); 7320Sstevel@tonic-gate ELFUNLOCK(elf) 7330Sstevel@tonic-gate return (-1); 7340Sstevel@tonic-gate } 7350Sstevel@tonic-gate /* LINTED */ 7360Sstevel@tonic-gate eh->e_ident[EI_DATA] = (Byte)encode; 7370Sstevel@tonic-gate } 7380Sstevel@tonic-gate 7390Sstevel@tonic-gate u = 1; 7400Sstevel@tonic-gate if (elf->ed_uflags & ELF_F_LAYOUT) { 7410Sstevel@tonic-gate sz = _elf_upd_usr(elf); 7420Sstevel@tonic-gate u = 0; 7430Sstevel@tonic-gate } else 7440Sstevel@tonic-gate sz = _elf_upd_lib(elf); 7450Sstevel@tonic-gate 7460Sstevel@tonic-gate if ((sz != 0) && ((cmd == ELF_C_WRITE) || (cmd == ELF_C_WRIMAGE))) 7470Sstevel@tonic-gate sz = wrt(elf, (Xword)sz, u, cmd); 7480Sstevel@tonic-gate 7490Sstevel@tonic-gate if (sz == 0) { 7500Sstevel@tonic-gate ELFUNLOCK(elf) 7510Sstevel@tonic-gate return (-1); 7520Sstevel@tonic-gate } 7530Sstevel@tonic-gate 7540Sstevel@tonic-gate ELFUNLOCK(elf) 7550Sstevel@tonic-gate return ((off_t)sz); 7560Sstevel@tonic-gate } 7570Sstevel@tonic-gate 7580Sstevel@tonic-gate 7590Sstevel@tonic-gate #ifndef _ELF64 7600Sstevel@tonic-gate /* class-independent, only needs to be compiled once */ 7610Sstevel@tonic-gate 7620Sstevel@tonic-gate off_t 7630Sstevel@tonic-gate elf_update(Elf *elf, Elf_Cmd cmd) 7640Sstevel@tonic-gate { 7650Sstevel@tonic-gate if (elf == 0) 7660Sstevel@tonic-gate return (-1); 7670Sstevel@tonic-gate 7680Sstevel@tonic-gate if (elf->ed_class == ELFCLASS32) 7690Sstevel@tonic-gate return (_elf32_update(elf, cmd)); 7700Sstevel@tonic-gate else if (elf->ed_class == ELFCLASS64) { 7710Sstevel@tonic-gate return (_elf64_update(elf, cmd)); 7720Sstevel@tonic-gate } 7730Sstevel@tonic-gate 7740Sstevel@tonic-gate _elf_seterr(EREQ_CLASS, 0); 7750Sstevel@tonic-gate return (-1); 7760Sstevel@tonic-gate } 7770Sstevel@tonic-gate 7780Sstevel@tonic-gate /* 7790Sstevel@tonic-gate * 4106312, 4106398, This is an ad-hoc means for the 32-bit 7800Sstevel@tonic-gate * Elf64 version of libld.so.3 to get around the limitation 7810Sstevel@tonic-gate * of a 32-bit d_off field. This is only intended to be 7820Sstevel@tonic-gate * used by libld to relocate symbols in large NOBITS sections. 7830Sstevel@tonic-gate */ 7840Sstevel@tonic-gate Elf64_Off 7850Sstevel@tonic-gate _elf_getxoff(Elf_Data * d) 7860Sstevel@tonic-gate { 7870Sstevel@tonic-gate return (((Dnode *)d)->db_xoff); 7880Sstevel@tonic-gate } 7890Sstevel@tonic-gate #endif /* !_ELF64 */ 790