update.c revision deec6be0d2203ed491be67ac7ebf52f91a24b83d
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Copyright (c) 1988 AT&T
* All Rights Reserved
*/
#include <memory.h>
#include <malloc.h>
#include <limits.h>
#include <sgs.h>
#include "decl.h"
#include "msg.h"
/*
* This module is compiled twice, the second time having
* -D_ELF64 defined. The following set of macros, along
* with machelf.h, represent the differences between the
* two compilations. Be careful *not* to add any class-
* dependent code (anything that has elf32 or elf64 in the
* name) to this code without hiding it behind a switch-
* able macro like these.
*/
#if defined(_ELF64)
#define FSZ_LONG ELF64_FSZ_XWORD
#define ELFCLASS ELFCLASS64
#define _elf_snode_init _elf64_snode_init
#define _elfxx_cookscn _elf64_cookscn
#define _elf_upd_lib _elf64_upd_lib
#define elf_fsize elf64_fsize
#define _elf_entsz _elf64_entsz
#define _elf_msize _elf64_msize
#define _elf_upd_usr _elf64_upd_usr
#define elf_xlatetof elf64_xlatetof
#define _elfxx_update _elf64_update
#else /* ELF32 */
#define FSZ_LONG ELF32_FSZ_WORD
#define ELFCLASS ELFCLASS32
#define _elf_snode_init _elf32_snode_init
#define _elfxx_cookscn _elf32_cookscn
#define _elf_upd_lib _elf32_upd_lib
#define elf_fsize elf32_fsize
#define _elf_entsz _elf32_entsz
#define _elf_msize _elf32_msize
#define _elf_upd_usr _elf32_upd_usr
#define elf_xlatetof elf32_xlatetof
#define _elfxx_update _elf32_update
#endif /* ELF64 */
#define TEST_SIZE
/*
* Handle the decision of whether the current linker can handle the
* desired object size, and if not, which error to issue.
*
* Input is the desired size. On failure, an error has been issued
* and 0 is returned. On success, 1 is returned.
*/
static int
{
#ifndef _LP64 /* 32-bit linker */
/*
* A 32-bit libelf is limited to a 2GB output file. This limit
* is due to the fact that off_t is a signed value, and that
* libelf cannot support large file support:
* - ABI reasons
* - Memory use generally is 2x output file size anyway,
* so lifting the file size limit will just send
* you crashing into the 32-bit VM limit.
* If the output is an ELFCLASS64 object, or an ELFCLASS32 object
* under 4GB, switching to the 64-bit version of libelf will help.
* However, an ELFCLASS32 object must not exceed 4GB.
*/
#ifndef _ELF64
/* ELFCLASS32 object is fundamentally too big? */
return (0);
}
#endif /* _ELF64 */
/* Should switch to the 64-bit libelf? */
return (0);
}
#endif /* !_LP64 */
/*
* A 64-bit linker can produce any size output
* file, but if the resulting file is ELFCLASS32,
* it must not exceed 4GB.
*/
return (0);
}
#endif
return (1);
}
#endif /* TEST_SIZE */
/*
* Output file update
* These functions walk an Elf structure, update its information,
* and optionally write the output file. Because the application
* may control of the output file layout, two upd_... routines
* exist. They're similar but too different to merge cleanly.
*
* The library defines a "dirty" bit to force parts of the file
* to be written on update. These routines ignore the dirty bit
* and do everything. A minimal update routine might be useful
* someday.
*/
static size_t
{
Elf_Scn * s;
/*
* Ehdr and Phdr table go first
*/
/* LINTED */
/* LINTED */
/* LINTED */
/* LINTED */
} else {
eh->e_phentsize = 0;
}
/*
* Obtain the first section header. Typically, this section has NULL
* contents, however in the case of Extended ELF Sections this section
* is used to hold an alternative e_shnum, e_shstrndx and e_phnum.
* On initial allocation (see _elf_snode) the elements of this section
* would have been zeroed. The e_shnum is initialized later, after the
* section header count has been determined. The e_shstrndx and
* e_phnum may have already been initialized by the caller (for example,
* gelf_update_shdr() in mcs(1)).
*/
scncnt = 0;
} else {
s = s->s_next;
scncnt = 1;
}
/*
* Loop through sections. Compute section size before changing hi.
* Allow null buffers for NOBITS.
*/
hibit = 0;
for (; s != 0; s = s->s_next) {
register Dnode *d;
scncnt++;
continue;
}
(void) _elfxx_cookscn(s);
/* LINTED */
sz = 0;
1, ver)) == 0)
return (0);
if (j > sh->sh_addralign)
if (sz % j != 0)
}
}
/*
* We want to take into account the offsets for NOBITS
* sections and let the "sh_offsets" point to where
* the section would 'conceptually' fit within
* the file (as required by the ABI).
*
* But - we must also make sure that the NOBITS does
* not take up any actual space in the file. We preserve
* the actual offset into the file in the 'hibit' variable.
* When we come to the first non-NOBITS section after a
* encountering a NOBITS section the hi counter is restored
* to its proper place in the file.
*/
if (hibit == 0)
} else {
if (hibit) {
hibit = 0;
}
}
j = sh->sh_addralign;
/* LINTED */
}
/*
* if last section was a 'NOBITS' section then we need to
* restore the 'hi' counter to point to the end of the last
* non 'NOBITS' section.
*/
if (hibit) {
hibit = 0;
}
/*
* Shdr table last
*/
if (scncnt != 0) {
/* LINTED */
/*
* If we are using 'extended sections' then the
* e_shnum is stored in the sh_size field of the
* first section header.
*
* NOTE: we set e_shnum to '0' because it's specified
* this way in the gABI, and in the hopes that
* this will cause less problems to unaware
* tools then if we'd set it to SHN_XINDEX (0xffff).
*/
if (scncnt < SHN_LORESERVE)
else {
}
/* LINTED */
} else {
eh->e_shentsize = 0;
}
#ifdef TEST_SIZE
return (0);
#endif
}
static size_t
{
Elf_Scn * s;
/*
* Ehdr and Phdr table go first
*/
/* LINTED */
/* LINTED */
/*
* If phnum is zero, phoff "should" be zero too,
* but the application is responsible for it.
* Allow a non-zero value here and update the
* hi water mark accordingly.
*/
/* LINTED */
else
eh->e_phentsize = 0;
/*
* Loop through sections, skipping index zero.
* Compute section size before changing hi.
* Allow null buffers for NOBITS.
*/
scncnt = 0;
} else {
scncnt = 1;
s = s->s_next;
}
for (; s != 0; s = s->s_next) {
register Dnode *d;
(void) _elfxx_cookscn(s);
++scncnt;
sz = 0;
ver)) == 0)
return (0);
sz = j;
}
_elf_seterr(EFMT_SCNSZ, 0);
return (0);
}
}
/*
*/
if (scncnt != 0) {
/* LINTED */
if (scncnt < SHN_LORESERVE) {
} else {
}
} else {
eh->e_shentsize = 0;
}
#ifdef TEST_SIZE
return (0);
#endif
}
static size_t
{
unsigned flag;
char *image;
Elf_Scn *s;
unsigned encode;
int byte;
/*
* If this is an ELF_C_WRIMAGE write, then we encode into the
* byte order of the system we are running on rather than that of
* of the object. For ld.so.1, this is the same order, but
* for 'ld', it might not be in the case where we are cross
* linking an object for a different target. In this later case,
* the linker-host byte order is necessary so that the linker can
* manipulate the resulting image. It is expected that the linker
* will call elf_swap_wrimage() if necessary to convert the image
* to the target byte order.
*/
/*
* Two issues can cause trouble for the output file.
* First, begin() with ELF_C_RDWR opens a file for both
* read and write. On the write update(), the library
* has to read everything it needs before truncating
* the file. Second, using mmap for both read and write
* is too tricky. Consequently, the library disables mmap
* on the read side. Using mmap for the output saves swap
* space, because that mapping is SHARED, not PRIVATE.
*
* If the file is write-only, there can be nothing of
* interest to bother with.
*
* The following reads the entire file, which might be
* more than necessary. Better safe than sorry.
*/
return (0);
return (0);
if (flag == 0)
/*
* If an error occurs below, a "dirty" bit may be cleared
* improperly. To save a second pass through the file,
* this code sets the dirty bit on the elf descriptor
* when an error happens, assuming that will "cover" any
* accidents.
*/
/*
* Hi is needed only when 'fill' is non-zero.
* Fill is non-zero only when the library
* The lib guarantees they increase monotonically.
* That guarantees proper filling below.
*/
/*
* Ehdr first
*/
return (0);
/*
* Phdr table if one exists
*/
unsigned work;
/*
* Unlike other library data, phdr table is
* in the user version. Change src buffer
* version here, fix it after translation.
*/
return (0);
}
}
/*
* Loop through sections
*/
char *here;
/* Only use the execfill function on SHF_EXECINSTR sections */
/*
* Just "clean" DIRTY flag for "empty" sections. Even if
* NOBITS needs padding, the next thing in the
* file will provide it. (And if this NOBITS is
* the last thing in the file, no padding needed.)
*/
d->db_uflags &= ~ELF_F_DIRTY;
continue;
}
/*
* Clear out the memory between the end of the last
* section and the begining of this section.
*/
}
d->db_uflags &= ~ELF_F_DIRTY;
/*
* Clear out the memory between the end of the
* last update and the start of this data buffer.
*
* These buffers represent input sections that have
* been concatenated into an output section, so if
* the output section is executable (SHF_EXECINSTR)
* and a fill function has been registered, use the
* function. Otherwise, use the fill byte.
*/
else
}
if ((d->db_myflags & DBF_READY) == 0) {
SCNLOCK(s);
&d->db_data) {
SCNUNLOCK(s);
return (0);
}
SCNUNLOCK(s);
}
/*
* Copy the translated bits out to the destination
* image.
*/
return (0);
}
}
}
/*
* Shdr table last
*/
}
s->s_shflags &= ~ELF_F_DIRTY;
s->s_uflags &= ~ELF_F_DIRTY;
return (0);
}
}
/*
* ELF_C_WRIMAGE signifyes that we build the memory image, but
* that we do not actually write it to disk. This is used
* by ld(1) to build up a full image of an elf file and then
* to process the file before it's actually written out to
* disk. This saves ld(1) the overhead of having to write
* the image out to disk twice.
*/
if (update_cmd == ELF_C_WRIMAGE) {
return (outsz);
}
return (outsz);
}
return (0);
}
/*
* The following is a private interface between the linkers (ld & ld.so.1)
* and libelf:
*
* elf_update(elf, ELF_C_WRIMAGE)
* This will cause full image representing the elf file
* described by the elf pointer to be built in memory. If the
* elf pointer has a valid file descriptor associated with it
* we will attempt to build the memory image from mmap()'ed
* storage. If the elf descriptor does not have a valid
* file descriptor (opened with elf_begin(0, ELF_C_IMAGE, 0))
* then the image will be allocated from dynamic memory (malloc()).
*
* elf_update() will return the size of the memory image built
* when sucessful.
*
* When a subsequent call to elf_update() with ELF_C_WRITE as
* the command is performed it will sync the image created
* by ELF_C_WRIMAGE to disk (if fd available) and
* free the memory allocated.
*/
{
unsigned u;
if (elf == 0)
return (-1);
switch (cmd) {
default:
_elf_seterr(EREQ_UPDATE, 0);
return (-1);
case ELF_C_WRIMAGE:
_elf_seterr(EREQ_UPDWRT, 0);
return (-1);
}
break;
case ELF_C_WRITE:
_elf_seterr(EREQ_UPDWRT, 0);
return (-1);
}
if (elf->ed_wrimage) {
/*
* The size is still returned even
* though nothing is actually written
* out. This is just to be consistant
* with the rest of the interface.
*/
elf->ed_wrimage = 0;
elf->ed_wrimagesz = 0;
}
elf->ed_wrimage = 0;
elf->ed_wrimagesz = 0;
}
/* FALLTHROUGH */
case ELF_C_NULL:
break;
}
if (eh == 0) {
_elf_seterr(ESEQ_EHDR, 0);
return (-1);
}
_elf_seterr(EREQ_VER, 0);
return (-1);
}
if (u == EV_NONE)
unsigned encode;
if (encode == ELFDATANONE) {
_elf_seterr(EREQ_ENCODE, 0);
return (-1);
}
/* LINTED */
}
u = 1;
u = 0;
} else
if (sz == 0) {
return (-1);
}
}
/*
* When wrt() processes an ELF_C_WRIMAGE request, the resulting image
* gets the byte order (encoding) of the platform running the linker
* rather than that of the target host. This allows the linker to modify
* the image, prior to flushing it to the output file. This routine
* is used to re-translate such an image into the byte order of the
* target host.
*/
int
{
Elf_Scn *s;
unsigned ver;
unsigned encode;
/*
* Ehdr first
*/
return (1);
}
/*
* Phdr table if one exists
*/
if (e_phnum != 0) {
unsigned work;
/*
* Unlike other library data, phdr table is
* in the user version.
*/
return (1);
}
}
/*
* Loop through sections
*/
continue;
if ((d->db_myflags & DBF_READY) == 0) {
SCNLOCK(s);
&d->db_data) {
SCNUNLOCK(s);
return (1);
}
SCNUNLOCK(s);
}
return (1);
}
}
}
/*
* Shdr table
*/
return (1);
}
}
return (0);
}
#ifndef _ELF64
/* class-independent, only needs to be compiled once */
{
if (elf == 0)
return (-1);
}
_elf_seterr(EREQ_CLASS, 0);
return (-1);
}
int
{
if (elf == 0)
return (0);
return (_elf32_swap_wrimage(elf));
return (_elf64_swap_wrimage(elf));
_elf_seterr(EREQ_CLASS, 0);
return (0);
}
/*
* 4106312, 4106398, This is an ad-hoc means for the 32-bit
* Elf64 version of libld.so.3 to get around the limitation
* of a 32-bit d_off field. This is only intended to be
* used by libld to relocate symbols in large NOBITS sections.
*/
_elf_getxoff(Elf_Data * d)
{
}
#endif /* !_ELF64 */