text: /*
   * 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
   * or http://www.opensolaris.org/os/licensing.
   * 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 (c) 1988 AT&T
   *	  All Rights Reserved
   *
   * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
   *
   * Copyright 2011, Richard Lowe.
   */
  
  /*
   * This file contains the functions responsible for opening the output file
   * image, associating the appropriate input elf structures with the new image,
   * and obtaining new elf structures to define the new image.
   */
  #include	<stdio.h>
  #include	<sys/stat.h>
  #include	<fcntl.h>
  #include	<link.h>
  #include	<errno.h>
  #include	<string.h>
  #include	<limits.h>
  #include	<debug.h>
  #include	<unistd.h>
  #include	"msg.h"
  #include	"_libld.h"
  
  /*
   * Determine a least common multiplier.  Input sections contain an alignment
   * requirement, which elf_update() uses to insure that the section is aligned
   * correctly off of the base of the elf image.  We must also insure that the
   * sections mapping is congruent with this alignment requirement.  For each
   * input section associated with a loadable segment determine whether the
   * segments alignment must be adjusted to compensate for a sections alignment
   * requirements.
   */
  Xword
  ld_lcm(Xword a, Xword b)
  {
  	Xword	_r, _a, _b;
  
  	if ((_a = a) == 0)
  		return (b);
  	if ((_b = b) == 0)
  		return (a);
  
  	if (_a > _b)
  		_a = b, _b = a;
  	while ((_r = _b % _a) != 0)
  		_b = _a, _a = _r;
  	return ((a / _a) * b);
  }
  
  /*
   * Open the output file and insure the correct access modes.
   */
  uintptr_t
  ld_open_outfile(Ofl_desc * ofl)
  {
  	mode_t		mode;
  	struct stat	status;
  
  	/*
  	 * Determine the required file mode from the type of output file we
  	 * are creating.
  	 */
  	mode = (ofl->ofl_flags & (FLG_OF_EXEC | FLG_OF_SHAROBJ))
  	    ? 0777 : 0666;
  
  	/* Determine if the output file already exists */
  	if (stat(ofl->ofl_name, &status) == 0) {
  		if ((status.st_mode & S_IFMT) != S_IFREG) {
  			/*
  			 * It is not a regular file, so don't delete it
  			 * or allow it to be deleted.  This allows root
  			 * users to specify /dev/null output file for
  			 * verification links.
  			 */
  			ofl->ofl_flags1 |= FLG_OF1_NONREG;
  		} else {
  			/*
  			 * It's a regular file, so unlink it. In standard
  			 * Unix fashion, the old file will continue to
  			 * exist until its link count drops to 0 and no
  			 * process has the file open. In the meantime, we
  			 * create a new file (inode) under the same name,
  			 * available for new use.
  			 *
  			 * The advantage of this policy is that creating
  			 * a new executable or sharable library does not
  			 * corrupt existing processes using the old file.
  			 * A possible disadvantage is that if the existing
  			 * file has a (link_count > 1), the other names will
  			 * continue to reference the old inode, thus
  			 * breaking the link.
  			 *
  			 * A subtlety here is that POSIX says we are not
  			 * supposed to replace a non-writable file, which
  			 * is something that unlink() is happy to do. The
  			 * only 100% reliable test against this is to open
  			 * the file for non-destructive write access. If the
  			 * open succeeds, we are clear to unlink it, and if
  			 * not, then the error generated is the error we
  			 * need to report.
  			 */
  			if ((ofl->ofl_fd = open(ofl->ofl_name, O_RDWR,
  			    mode)) < 0) {
  				int	err = errno;
  
  				if (err != ENOENT) {
  					ld_eprintf(ofl, ERR_FATAL,
  					    MSG_INTL(MSG_SYS_OPEN),
  					    ofl->ofl_name, strerror(err));
  					return (S_ERROR);
  				}
  			} else {
  				(void) close(ofl->ofl_fd);
  			}
  
  			if ((unlink(ofl->ofl_name) == -1) &&
  			    (errno != ENOENT)) {
  				int err = errno;
  
  				ld_eprintf(ofl, ERR_FATAL,
  				    MSG_INTL(MSG_SYS_UNLINK),
  				    ofl->ofl_name, strerror(err));
  				return (S_ERROR);
  			}
  		}
  	}
  
  	/*
  	 * Open (or create) the output file name (ofl_fd acts as a global
  	 * flag to ldexit() signifying whether the output file should be
  	 * removed or not on error).
  	 */
  	if ((ofl->ofl_fd = open(ofl->ofl_name, O_RDWR | O_CREAT | O_TRUNC,
  	    mode)) < 0) {
  		int	err = errno;
  
  		ld_eprintf(ofl, ERR_FATAL, MSG_INTL(MSG_SYS_OPEN),
  		    ofl->ofl_name, strerror(err));
  		return (S_ERROR);
  	}
  
  	return (1);
  }
  
  
  /*
   * If we are creating a memory model we need to update the present memory image.
   * Use elf_update(ELF_C_NULL) to calculate the offset of each section and their
   * associated data buffers.  From this information determine what padding is
   * required.
   *
   * Two actions are necessary to convert the present disc image into a memory
   * image:
   *
   *  -	Loadable segments must be padded so that the next segment virtual
   *	address and file offset are the same.
   *
   *  -	NOBITS sections must be converted into allocated, null filled sections.
   */
  static uintptr_t
  pad_outfile(Ofl_desc *ofl)
  {
  	Aliste		idx1;
  	off_t		offset;
  	Elf_Scn		*oscn = 0;
  	Sg_desc		*sgp;
  	Ehdr		*ehdr;
  
  	/*
  	 * Update all the elf structures.  This will assign offsets to the
  	 * section headers and data buffers as they relate to the new image.
  	 */
  	if (elf_update(ofl->ofl_welf, ELF_C_NULL) == -1) {
  		ld_eprintf(ofl, ERR_ELF, MSG_INTL(MSG_ELF_UPDATE),
  		    ofl->ofl_name);
  		return (S_ERROR);
  	}
  	if ((ehdr = elf_getehdr(ofl->ofl_welf)) == NULL) {
  		ld_eprintf(ofl, ERR_ELF, MSG_INTL(MSG_ELF_GETEHDR),
  		    ofl->ofl_name);
  		return (S_ERROR);
  	}
  
  	/*
  	 * Initialize the offset by skipping the Elf header and program
  	 * headers.
  	 */
  	offset = ehdr->e_phoff + (ehdr->e_phnum * ehdr->e_phentsize);
  
  	/*
  	 * Traverse the segment list looking for loadable segments.
  	 */
  	for (APLIST_TRAVERSE(ofl->ofl_segs, idx1, sgp)) {
  		Phdr	*phdr = &(sgp->sg_phdr);
  		Os_desc	*osp;
  		Aliste	idx2;
  
  		/*
  		 * If we've already processed a loadable segment, the `scn'
  		 * variable will be initialized to the last section that was
  		 * part of that segment.  Add sufficient padding to this section
  		 * to cause the next segments virtual address and file offset to
  		 * be the same.
  		 */
  		if (oscn && (phdr->p_type == PT_LOAD)) {
  			Elf_Data *	data;
  			size_t 		size;
  
  			size = (size_t)(S_ROUND(offset, phdr->p_align) -
  			    offset);
  
  			if ((data = elf_newdata(oscn)) == NULL) {
  				ld_eprintf(ofl, ERR_ELF,
  				    MSG_INTL(MSG_ELF_NEWDATA), ofl->ofl_name);
  				return (S_ERROR);
  			}
  			if ((data->d_buf = libld_calloc(size, 1)) == 0)
  				return (S_ERROR);
  
  			data->d_type = ELF_T_BYTE;
  			data->d_size = size;
  			data->d_align = 1;
  			data->d_version = ofl->ofl_dehdr->e_version;
  		}
  
  		/*
  		 * Traverse the output sections for this segment calculating the
  		 * offset of each section. Retain the final section descriptor
  		 * as this will be where any padding buffer will be added.
  		 */
  		for (APLIST_TRAVERSE(sgp->sg_osdescs, idx2, osp)) {
  			Shdr	*shdr = osp->os_shdr;
  
  			offset = (off_t)S_ROUND(offset, shdr->sh_addralign);
  			offset += shdr->sh_size;
  
  			/*
  			 * If this is a NOBITS output section convert all of
  			 * its associated input sections into real, null filled,
  			 * data buffers, and change the section to PROGBITS.
  			 */
  			if (shdr->sh_type == SHT_NOBITS)
  				shdr->sh_type = SHT_PROGBITS;
  		}
  
  		/*
  		 * If this is a loadable segment retain the last output section
  		 * descriptor.  This acts both as a flag that a loadable
  		 * segment has been seen, and as the segment to which a padding
  		 * buffer will be added.
  		 */
  		if (phdr->p_type == PT_LOAD)
  			oscn = osp->os_scn;
  	}
  	return (1);
  }
  
  /*
   * Create an output section.  The first instance of an input section triggers
   * the creation of a new output section.
   */
  static uintptr_t
  create_outsec(Ofl_desc *ofl, Sg_desc *sgp, Os_desc *osp, Word ptype, int shidx,
      Boolean fixalign)
  {
  	Elf_Scn	*scn;
  	Shdr	*shdr;
  
  	/*
  	 * Get a section descriptor for the section.
  	 */
  	if ((scn = elf_newscn(ofl->ofl_welf)) == NULL) {
  		ld_eprintf(ofl, ERR_ELF, MSG_INTL(MSG_ELF_NEWSCN),
  		    ofl->ofl_name);
  		return (S_ERROR);
  	}
  	osp->os_scn = scn;
  
  	/*
  	 * Get a new section header table entry and copy the pertinent
  	 * information from the in-core descriptor.
  	 */
  	if ((shdr = elf_getshdr(scn)) == NULL) {
  		ld_eprintf(ofl, ERR_ELF, MSG_INTL(MSG_ELF_GETSHDR),
  		    ofl->ofl_name);
  		return (S_ERROR);
  	}
  	*shdr = *(osp->os_shdr);
  	osp->os_shdr = shdr;
  
  	/*
  	 * If this is the first section within a loadable segment, and the
  	 * alignment needs to be updated, record this section.
  	 */
  	if ((fixalign == TRUE) && (ptype == PT_LOAD) && (shidx == 1))
  		sgp->sg_fscn = scn;
  
  	/*
  	 * If not building a relocatable object, remove any of the
  	 * following flags, as they have been acted upon and are not
  	 * meaningful in the output:
  	 *	SHF_ORDERED, SHF_LINK_ORDER, SHF_GROUP
  	 * For relocatable objects, we allow them to propagate to
  	 * the output object to be handled by the next linker that
  	 * sees them.
  	 */
  	if ((ofl->ofl_flags & FLG_OF_RELOBJ) == 0)
  		osp->os_shdr->sh_flags &= ~(ALL_SHF_ORDER|SHF_GROUP);
  
  	/*
  	 * If this is a TLS section, save it so that the PT_TLS program header
  	 * information can be established after the output image has been
  	 * initially created.  At this point, all TLS input sections are ordered
  	 * as they will appear in the output image.
  	 */
  	if ((ofl->ofl_flags & FLG_OF_TLSPHDR) &&
  	    (osp->os_shdr->sh_flags & SHF_TLS) &&
  	    (aplist_append(&ofl->ofl_ostlsseg, osp,
  	    AL_CNT_OFL_OSTLSSEG) == NULL))
  		return (S_ERROR);
  
  	return (0);
  }
  
  /*
   * Create the elf structures that allow the input data to be associated with the
   * new image:
   *
   *  -	define the new elf image using elf_begin(),
   *
   *  -	obtain an elf header for the image,
   *
   *  -	traverse the input segments and create a program header array to define
   *	the required segments,
   *
   *  -	traverse the output sections for each segment assigning a new section
   *	descriptor and section header for each,
   *
   *  -	traverse the input sections associated with each output section and
   *	assign a new data descriptor to each (each output section becomes a
   *	linked list of input data buffers).
   */
  uintptr_t
  ld_create_outfile(Ofl_desc *ofl)
  {
  	Sg_desc		*sgp;
  	Os_desc		*osp;
  	Is_desc		*isp;
  	Elf_Data	*tlsdata = 0;
  	Aliste		idx1;
  	ofl_flag_t	flags = ofl->ofl_flags;
  	ofl_flag_t	flags1 = ofl->ofl_flags1;
  	size_t		ndx;
  	Elf_Cmd		cmd;
  	Boolean		fixalign = FALSE;
  	int		fd, nseg = 0, shidx, dataidx, ptloadidx = 0;
  
  	DBG_CALL(Dbg_basic_create(ofl->ofl_lml));
  
  	/*
  	 * If DF_1_NOHDR or FLG_OF1_VADDR were set,
  	 * we need to do alignment adjustment.
  	 */
  	if ((flags1 & FLG_OF1_VADDR) ||
  	    (ofl->ofl_dtflags_1 & DF_1_NOHDR)) {
  		fixalign = TRUE;
  	}
  
  	if (flags1 & FLG_OF1_MEMORY) {
  		cmd = ELF_C_IMAGE;
  		fd = 0;
  	} else {
  		fd = ofl->ofl_fd;
  		cmd = ELF_C_WRITE;
  	}
  
  	/*
  	 * If there are any ordered sections, handle them here.
  	 */
  	if ((ofl->ofl_ordered != NULL) &&
  	    (ld_sort_ordered(ofl) == S_ERROR))
  		return (S_ERROR);
  
  	/*
  	 * Tell the access library about our new temporary file.
  	 */
  	if ((ofl->ofl_welf = elf_begin(fd, cmd, 0)) == NULL) {
  		ld_eprintf(ofl, ERR_ELF, MSG_INTL(MSG_ELF_BEGIN),
  		    ofl->ofl_name);
  		return (S_ERROR);
  	}
  
  	/*
  	 * Obtain a new Elf header.
  	 */
  	if ((ofl->ofl_nehdr = elf_newehdr(ofl->ofl_welf)) == NULL) {
  		ld_eprintf(ofl, ERR_ELF, MSG_INTL(MSG_ELF_NEWEHDR),
  		    ofl->ofl_name);
  		return (S_ERROR);
  	}
  	ofl->ofl_nehdr->e_machine = ofl->ofl_dehdr->e_machine;
  
  	DBG_CALL(Dbg_util_nl(ofl->ofl_lml, DBG_NL_STD));
  	for (APLIST_TRAVERSE(ofl->ofl_segs, idx1, sgp)) {
  		int	frst = 0;
  		Phdr	*phdr = &(sgp->sg_phdr);
  		Word	ptype = phdr->p_type;
  		Aliste	idx2;
  		Os_desc *nonempty = NULL; /* First non-empty section */
  
  		/*
  		 * Count the number of segments that will go in the program
  		 * header table. If a segment is empty, ignore it.
  		 */
  		if (!(flags & FLG_OF_RELOBJ)) {
  			/*
  			 * If the program header type belongs to the os range,
  			 * the resulting object is ELFOSABI_SOLARIS.
  			 */
  			if ((ptype >= PT_LOOS) && (ptype <= PT_HIOS))
  				ofl->ofl_flags |= FLG_OF_OSABI;
  
  			if (ptype == PT_PHDR) {
  				/*
  				 * If we are generating an interp section (and
  				 * thus an associated PT_INTERP program header
  				 * entry) also generate a PT_PHDR program header
  				 * entry.  This allows the kernel to generate
  				 * the appropriate aux vector entries to pass to
  				 * the interpreter (refer to exec/elf/elf.c).
  				 * Note that if an image was generated with an
  				 * interp section, but no associated PT_PHDR
  				 * program header entry, the kernel will simply
  				 * pass the interpreter an open file descriptor
  				 * when the image is executed).
  				 */
  				if (ofl->ofl_osinterp)
  					nseg++;
  			} else if (ptype == PT_INTERP) {
  				if (ofl->ofl_osinterp)
  					nseg++;
  			} else if (ptype == PT_DYNAMIC) {
  				if (flags & FLG_OF_DYNAMIC)
  					nseg++;
  			} else if (ptype == PT_TLS) {
  				if (flags & FLG_OF_TLSPHDR)
  					nseg++;
  			} else if (ptype == PT_SUNW_UNWIND) {
  				if (ofl->ofl_unwindhdr)
  					nseg++;
  			} else if (ptype == PT_SUNWDTRACE) {
  				if (ofl->ofl_dtracesym)
  					nseg++;
  			} else if (ptype == PT_SUNWCAP) {
  				if (ofl->ofl_oscap)
  					nseg++;
  			} else if (ptype == PT_SUNWSTACK) {
  				if ((sgp->sg_flags & FLG_SG_DISABLED) == 0)
  					nseg++;
  			} else if (sgp->sg_flags & FLG_SG_EMPTY) {
  					nseg++;
  			} else if (sgp->sg_osdescs != NULL) {
  				if ((sgp->sg_flags & FLG_SG_PHREQ) == 0) {
  					/*
  					 * If this is a segment for which
  					 * we are not making a program header,
  					 * don't increment nseg
  					 */
  					ptype = (sgp->sg_phdr).p_type = PT_NULL;
  				} else if (ptype != PT_NULL)
  					nseg++;
  			}
  		}
  
  		/*
  		 * Establish any processing unique to the first loadable
  		 * segment.
  		 */
  		if ((ptype == PT_LOAD) && (ptloadidx == 0)) {
  			ptloadidx++;
  
  			/*
  			 * If the first loadable segment is not supposed to
  			 * include the ELF or program headers,  alignments
  			 * of the following segments need to be fixed,
  			 * plus a .dynamic FLAGS1 setting is required.
  			 */
  			if (ofl->ofl_dtflags_1 & DF_1_NOHDR)
  				fixalign = TRUE;
  		}
  
  		shidx = 0;
  		for (APLIST_TRAVERSE(sgp->sg_osdescs, idx2, osp)) {
  			Aliste	idx3;
  			int	os_isdescs_idx;
  
  			dataidx = 0;
  
  			OS_ISDESCS_TRAVERSE(os_isdescs_idx, osp, idx3, isp) {
  				Elf_Data	*data;
  				Ifl_desc	*ifl = isp->is_file;
  
  				/*
  				 * An input section in the list that has
  				 * been previously marked to be discarded
  				 * should be completely ignored.
  				 */
  				if (isp->is_flags & FLG_IS_DISCARD)
  					continue;
  
  				/*
  				 * At this point we know whether a section has
  				 * been referenced.  If it hasn't, and the whole
  				 * file hasn't been referenced (which would have
  				 * been caught in ignore_section_processing()),
  				 * give a diagnostic (-D unused,detail) or
  				 * discard the section if -zignore is in effect.
  				 */
  				if (ifl &&
  				    (((ifl->ifl_flags & FLG_IF_FILEREF) == 0) ||
  				    ((ptype == PT_LOAD) &&
  				    ((isp->is_flags & FLG_IS_SECTREF) == 0) &&
  				    (isp->is_shdr->sh_size > 0)))) {
  					Lm_list	*lml = ofl->ofl_lml;
  
  					if (ifl->ifl_flags & FLG_IF_IGNORE) {
  						isp->is_flags |= FLG_IS_DISCARD;
  						DBG_CALL(Dbg_unused_sec(lml,
  						    isp));
  						continue;
  					} else {
  						DBG_CALL(Dbg_unused_sec(lml,
  						    isp));
  					}
  				}
  
  				/*
  				 * If this section provides no data, and isn't
  				 * referenced, then it can be discarded as well.
  				 * Note, if this is the first input section
  				 * associated to an output section, let it
  				 * through, there may be a legitimate reason why
  				 * the user wants a null section.  Discarding
  				 * additional sections is intended to remove the
  				 * empty clutter the compilers have a habit of
  				 * creating.  Don't provide an unused diagnostic
  				 * as these sections aren't typically the users
  				 * creation.
  				 */
  				if (ifl && dataidx &&
  				    ((isp->is_flags & FLG_IS_SECTREF) == 0) &&
  				    (isp->is_shdr->sh_size == 0)) {
  					isp->is_flags |= FLG_IS_DISCARD;
  					continue;
  				}
  
  				/*
  				 * The first input section triggers the creation
  				 * of the associated output section.
  				 */
  				if (osp->os_scn == NULL) {
  					shidx++;
  
  					if (create_outsec(ofl, sgp, osp, ptype,
  					    shidx, fixalign) == S_ERROR)
  						return (S_ERROR);
  				}
  
  				dataidx++;
  
  				/*
  				 * Create a new output data buffer for each
  				 * input data buffer, thus linking the new
  				 * buffers to the new elf output structures.
  				 * Simply make the new data buffers point to
  				 * the old data.
  				 */
  				if ((data = elf_newdata(osp->os_scn)) == NULL) {
  					ld_eprintf(ofl, ERR_ELF,
  					    MSG_INTL(MSG_ELF_NEWDATA),
  					    ofl->ofl_name);
  					return (S_ERROR);
  				}
  				*data = *(isp->is_indata);
  				isp->is_indata = data;
  
  				if ((fixalign == TRUE) && (ptype == PT_LOAD) &&
  				    (shidx == 1) && (dataidx == 1))
  					data->d_align = sgp->sg_align;
  
  				/*
  				 * Save the first TLS data buffer, as this is
  				 * the start of the TLS segment. Realign this
  				 * buffer based on the alignment requirements
  				 * of all the TLS input sections.
  				 */
  				if ((flags & FLG_OF_TLSPHDR) &&
  				    (isp->is_shdr->sh_flags & SHF_TLS)) {
  					if (tlsdata == 0)
  						tlsdata = data;
  					tlsdata->d_align =
  					    ld_lcm(tlsdata->d_align,
  					    isp->is_shdr->sh_addralign);
  				}
  
  #if	defined(_ELF64) && defined(_ILP32)
  				/*
  				 * 4106312, the 32-bit ELF64 version of ld
  				 * needs to be able to create large .bss
  				 * sections.  The d_size member of Elf_Data
  				 * only allows 32-bits in _ILP32, so we build
  				 * multiple data-items that each fit into 32-
  				 * bits.  libelf (4106398) can summ these up
  				 * into a 64-bit quantity.  This only works
  				 * for NOBITS sections which don't have any
  				 * real data to maintain and don't require
  				 * large file support.
  				 */
  				if (isp->is_shdr->sh_type == SHT_NOBITS) {
  					Xword sz = isp->is_shdr->sh_size;
  
  					while (sz >> 32) {
  						data->d_size = SIZE_MAX;
  						sz -= (Xword)SIZE_MAX;
  
  						data = elf_newdata(osp->os_scn);
  						if (data == NULL)
  							return (S_ERROR);
  					}
  					data->d_size = (size_t)sz;
  				}
  #endif
  
  				/*
  				 * If this segment requires rounding realign the
  				 * first data buffer associated with the first
  				 * section.
  				 */
  				if ((frst++ == 0) &&
  				    (sgp->sg_flags & FLG_SG_ROUND)) {
  					Xword    align;
  
  					if (data->d_align)
  						align = (Xword)
  						    S_ROUND(data->d_align,
  						    sgp->sg_round);
  					else
  						align = sgp->sg_round;
  
  					data->d_align = (size_t)align;
  				}
  
  				if ((data->d_size != 0) && (nonempty == NULL)) {
  					nonempty = osp;
  				}
  			}
  
  			/*
  			 * Clear the szoutrels counter so that it can be used
  			 * again in the building of relocs.  See machrel.c.
  			 */
  			osp->os_szoutrels = 0;
  		}
  
  		/*
  		 * We need to raise the alignment of any empty sections at the
  		 * start of a segment to be at least as aligned as the first
  		 * non-empty section, such that the empty and first non-empty
  		 * sections are placed at the same offset.
  		 */
  		if (nonempty != NULL) {
  			Elf_Data	*ne = NULL;
  			Xword		pad_align = 1;
  
  			ne = elf_getdata(nonempty->os_scn, NULL);
  			assert(ne != NULL);
  
  			do {
  				pad_align = ld_lcm(pad_align, ne->d_align);
  				ne = elf_getdata(nonempty->os_scn, ne);
  			} while (ne != NULL);
  
  			for (APLIST_TRAVERSE(sgp->sg_osdescs, idx2, osp)) {
  				Elf_Data	*d = NULL;
  
  				/* Stop at the first non-empty section */
  				if (osp == nonempty)
  					break;
  
  				d = elf_getdata(osp->os_scn, NULL);
  
  				if (d != NULL)
  					d->d_align = pad_align;
  			}
  		}
  	}
  
  	/*
  	 * Did we use ELF features from the osabi range? If so,
  	 * update the ELF header osabi fields. If this doesn't happen,
  	 * those fields remain 0, reflecting a generic System V ELF ABI.
  	 */
  	if (ofl->ofl_flags & FLG_OF_OSABI) {
  		ofl->ofl_nehdr->e_ident[EI_OSABI] = ELFOSABI_SOLARIS;
  		ofl->ofl_nehdr->e_ident[EI_ABIVERSION] = EAV_SUNW_CURRENT;
  	}
  
  	/*
  	 * Build an empty PHDR.
  	 */
  	if (nseg) {
  		if ((ofl->ofl_phdr = elf_newphdr(ofl->ofl_welf,
  		    nseg)) == NULL) {
  			ld_eprintf(ofl, ERR_ELF, MSG_INTL(MSG_ELF_NEWPHDR),
  			    ofl->ofl_name);
  			return (S_ERROR);
  		}
  	}
  
  	/*
  	 * If we need to generate a memory model, pad the image.
  	 */
  	if (flags1 & FLG_OF1_MEMORY) {
  		if (pad_outfile(ofl) == S_ERROR)
  			return (S_ERROR);
  	}
  
  	/*
  	 * After all the basic input file processing, all data pointers are
  	 * referencing two types of memory:
  	 *
  	 *  -	allocated memory, ie. elf structures, internal link editor
  	 *	structures, and any new sections that have been created.
  	 *
  	 *  -	original input file mmap'ed memory, ie. the actual data
  	 *	sections of the input file images.
  	 *
  	 * Up until now, the only memory modifications have been carried out on
  	 * the allocated memory.  Before carrying out any relocations, write the
  	 * new output file image and reassign any necessary data pointers to the
  	 * output files memory image.  This insures that any relocation
  	 * modifications are made to the output file image and not to the input
  	 * file image, thus preventing the creation of dirty pages and reducing
  	 * the overall swap space requirement.
  	 *
  	 * Write out the elf structure so as to create the new file image.
  	 */
  	if ((ofl->ofl_size = (size_t)elf_update(ofl->ofl_welf,
  	    ELF_C_WRIMAGE)) == (size_t)-1) {
  		ld_eprintf(ofl, ERR_ELF, MSG_INTL(MSG_ELF_UPDATE),
  		    ofl->ofl_name);
  		return (S_ERROR);
  	}
  
  	/*
  	 * Initialize the true `ofl' information with the memory images address
  	 * and size.  This will be used to write() out the image once any
  	 * relocation processing has been completed.  We also use this image
  	 * information to setup a new Elf descriptor, which is used to obtain
  	 * all the necessary elf pointers within the new output image.
  	 */
  	if ((ofl->ofl_elf = elf_begin(0, ELF_C_IMAGE,
  	    ofl->ofl_welf)) == NULL) {
  		ld_eprintf(ofl, ERR_ELF, MSG_INTL(MSG_ELF_BEGIN),
  		    ofl->ofl_name);
  		return (S_ERROR);
  	}
  	if ((ofl->ofl_nehdr = elf_getehdr(ofl->ofl_elf)) == NULL) {
  		ld_eprintf(ofl, ERR_ELF, MSG_INTL(MSG_ELF_GETEHDR),
  		    ofl->ofl_name);
  		return (S_ERROR);
  	}
  	if (!(flags & FLG_OF_RELOBJ))
  		if ((ofl->ofl_phdr = elf_getphdr(ofl->ofl_elf)) == NULL) {
  			ld_eprintf(ofl, ERR_ELF, MSG_INTL(MSG_ELF_GETPHDR),
  			    ofl->ofl_name);
  			return (S_ERROR);
  		}
  
  	/*
  	 * Reinitialize the section descriptors, section headers and obtain new
  	 * output data buffer pointers (these will be used to perform any
  	 * relocations).
  	 */
  	ndx = 0;
  	for (APLIST_TRAVERSE(ofl->ofl_segs, idx1, sgp)) {
  		Phdr	*_phdr = &(sgp->sg_phdr);
  		Os_desc	*osp;
  		Aliste	idx2;
  		Boolean	recorded = FALSE;
  
  		for (APLIST_TRAVERSE(sgp->sg_osdescs, idx2, osp)) {
  			/*
  			 * Make sure that an output section was originally
  			 * created.  Input sections that had been marked as
  			 * discarded may have made an output section
  			 * unnecessary.  Remove this alist entry so that
  			 * future output section descriptor processing doesn't
  			 * have to compensate for this empty section.
  			 */
  			if (osp->os_scn == NULL) {
  				aplist_delete(sgp->sg_osdescs, &idx2);
  				continue;
  			}
  			if ((osp->os_scn =
  			    elf_getscn(ofl->ofl_elf, ++ndx)) == NULL) {
  				ld_eprintf(ofl, ERR_ELF,
  				    MSG_INTL(MSG_ELF_GETSCN), ofl->ofl_name,
  				    ndx);
  				return (S_ERROR);
  			}
  			if ((osp->os_shdr =
  			    elf_getshdr(osp->os_scn)) == NULL) {
  				ld_eprintf(ofl, ERR_ELF,
  				    MSG_INTL(MSG_ELF_GETSHDR), ofl->ofl_name);
  				return (S_ERROR);
  			}
  			if ((fixalign == TRUE) && sgp->sg_fscn &&
  			    (recorded == FALSE)) {
  				size_t	fndx;
  				Elf_Scn *scn;
  
  				scn = sgp->sg_fscn;
  				if ((fndx = elf_ndxscn(scn)) == SHN_UNDEF) {
  					ld_eprintf(ofl, ERR_ELF,
  					    MSG_INTL(MSG_ELF_NDXSCN),
  					    ofl->ofl_name);
  					return (S_ERROR);
  				}
  				if (ndx == fndx) {
  					sgp->sg_fscn = osp->os_scn;
  					recorded = TRUE;
  				}
  			}
  
  			if ((osp->os_outdata =
  			    elf_getdata(osp->os_scn, NULL)) == NULL) {
  				ld_eprintf(ofl, ERR_ELF,
  				    MSG_INTL(MSG_ELF_GETDATA), ofl->ofl_name);
  				return (S_ERROR);
  			}
  
  			/*
  			 * If this section is part of a loadable segment insure
  			 * that the segments alignment is appropriate.
  			 */
  			if (_phdr->p_type == PT_LOAD) {
  				_phdr->p_align = ld_lcm(_phdr->p_align,
  				    osp->os_shdr->sh_addralign);
  			}
  		}
  	}
  	return (1);
  }
  