ldmain.c revision 5aefb6555731130ca4fd295960123d71f2d21fe8
/*
* 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 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* ld -- link/editor main program
*/
#include <sys/types.h>
#include <sys/mman.h>
#include <string.h>
#include <stdio.h>
#include <locale.h>
#include <stdarg.h>
#include <debug.h>
#include "msg.h"
#include "_libld.h"
/*
* A default library search path is used if one was not supplied on the command
* line. Note: these strings can not use MSG_ORIG() since they are modified as
* part of the path processing.
*/
#if defined(_ELF64)
static char def_Plibpath[] = "/lib/64:/usr/lib/64";
#else
static char def_Plibpath[] = "/usr/ccs/lib:/lib:/usr/lib";
#endif
/*
* A default elf header provides for simplifying diagnostic processing.
*/
static Ehdr def_ehdr = { { ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3,
M_CLASS, M_DATA }, 0, M_MACH, EV_CURRENT };
/*
* The main program
*/
int
ld_main(int argc, char **argv)
{
char *sgs_support; /* SGS_SUPPORT environment string */
Half etype;
uint_t stflags;
int suplib = 0;
Ofl_desc *ofl;
/*
* Initialize signal handlers, and output file variables. Establish a
* default output ELF header to satisfy diagnostic requirements.
*/
if ((ofl = libld_calloc(1, sizeof (Ofl_desc))) == 0)
return (1);
ofl->ofl_dehdr = &def_ehdr;
ld_init(ofl);
/*
* Build up linker version string
*/
if ((ofl->ofl_sgsid = (char *)libld_calloc(MSG_SGS_ID_SIZE +
strlen(link_ver_string) + 1, 1)) == NULL)
return (1);
(void) strcpy(ofl->ofl_sgsid, MSG_ORIG(MSG_SGS_ID));
(void) strcat(ofl->ofl_sgsid, link_ver_string);
/*
* Argument pass one. Get all the input flags (skip any files) and
* check for consistency. After this point any map file processing
* would have been completed and the entrance criteria and segment
* descriptor lists will be complete.
*/
if (ld_process_flags(ofl, argc, argv) == S_ERROR)
return (1);
if (ofl->ofl_flags & FLG_OF_FATAL) {
eprintf(ofl->ofl_lml, ERR_FATAL, MSG_INTL(MSG_ARG_FLAGS));
return (1);
}
/*
* At this point a call such as ld -V is considered complete.
*/
if (ofl->ofl_flags1 & FLG_OF1_DONE)
return (0);
/*
* Initialize string tables, by default we compress the
* stringtables.
*/
if (ofl->ofl_flags1 & FLG_OF1_NCSTTAB)
stflags = 0;
else
stflags = FLG_STNEW_COMPRESS;
if ((ofl->ofl_shdrsttab = st_new(stflags)) == 0)
return (1);
if ((ofl->ofl_strtab = st_new(stflags)) == 0)
return (1);
if ((ofl->ofl_dynstrtab = st_new(stflags)) == 0)
return (1);
/*
* Determine whether any support libraries been loaded (either through
* the SGS_SUPPORT environment variable and/or through the -S option).
* By default the support library libldstab.so.1 is loaded provided the
* user hasn't specified their own -S libraries.
*/
#if defined(_LP64)
if ((sgs_support = getenv(MSG_ORIG(MSG_SGS_SUPPORT_64))) == NULL)
#else
if ((sgs_support = getenv(MSG_ORIG(MSG_SGS_SUPPORT_32))) == NULL)
#endif
sgs_support = getenv(MSG_ORIG(MSG_SGS_SUPPORT));
if (sgs_support && (*sgs_support != '\0')) {
const char *sep = MSG_ORIG(MSG_STR_COLON);
char *lib;
char *lasts;
DBG_CALL(Dbg_support_req(ofl->ofl_lml, sgs_support,
DBG_SUP_ENVIRON));
if ((lib = strtok_r(sgs_support, sep, &lasts)) != NULL) {
do {
if (strcmp(lib,
MSG_ORIG(MSG_FIL_LIBSTAB)) == 0) {
if (suplib++)
continue;
}
if (ld_sup_loadso(ofl, lib) == S_ERROR)
return (ld_exit(ofl));
} while ((lib = strtok_r(NULL, sep, &lasts)) != NULL);
}
}
if (lib_support.head) {
Listnode *lnp;
char *lib;
for (LIST_TRAVERSE(&lib_support, lnp, lib)) {
DBG_CALL(Dbg_support_req(ofl->ofl_lml, lib,
DBG_SUP_CMDLINE));
if (ld_sup_loadso(ofl, lib) == S_ERROR)
return (ld_exit(ofl));
}
} else {
if (suplib == 0) {
DBG_CALL(Dbg_support_req(ofl->ofl_lml,
MSG_ORIG(MSG_FIL_LIBSTAB), DBG_SUP_DEFAULT));
if (ld_sup_loadso(ofl, MSG_ORIG(MSG_FIL_LIBSTAB)) ==
S_ERROR)
return (ld_exit(ofl));
}
}
DBG_CALL(Dbg_ent_print(ofl->ofl_lml, ofl->ofl_dehdr->e_machine,
&ofl->ofl_ents, (ofl->ofl_flags & FLG_OF_DYNAMIC)));
DBG_CALL(Dbg_seg_list(ofl->ofl_lml, ofl->ofl_dehdr->e_machine,
&ofl->ofl_segs));
/*
* The objscnt and soscnt variables were used to estimate the expected
* input files, and size the symbol hash buckets accordingly. Reset
* these values now, so as to gain an accurate count from pass two, for
* later statistics diagnostics.
*/
ofl->ofl_objscnt = ofl->ofl_soscnt = 0;
/*
* Determine whether we can create the file before going any further.
*/
if (ld_open_outfile(ofl) == S_ERROR)
return (ld_exit(ofl));
/*
* If the user didn't supply a library path supply a default. And, if
* no run-path has been specified (-R), see if the environment variable
* is in use (historic). Also assign a default starting address.
* Don't use MSG_ORIG() for these strings, they're written to later.
*/
if (Plibpath == NULL)
Plibpath = def_Plibpath;
if (ofl->ofl_rpath == NULL) {
char *rpath;
if (((rpath = getenv(MSG_ORIG(MSG_LD_RUN_PATH))) != NULL) &&
(strcmp((const char *)rpath, MSG_ORIG(MSG_STR_EMPTY))))
ofl->ofl_rpath = rpath;
}
if (ofl->ofl_flags & FLG_OF_EXEC)
ofl->ofl_segorigin = M_SEGM_ORIGIN;
/*
* Argument pass two. Input all libraries and objects.
*/
if (ld_lib_setup(ofl) == S_ERROR)
return (ld_exit(ofl));
/*
* Call ld_start() with the etype of our output file and the
* output file name.
*/
if (ofl->ofl_flags & FLG_OF_SHAROBJ)
etype = ET_DYN;
else if (ofl->ofl_flags & FLG_OF_RELOBJ)
etype = ET_REL;
else
etype = ET_EXEC;
ld_sup_start(ofl, etype, argv[0]);
/*
* Process all input files.
*/
if (ld_process_files(ofl, argc, argv) == S_ERROR)
return (ld_exit(ofl));
if (ofl->ofl_flags & FLG_OF_FATAL) {
eprintf(ofl->ofl_lml, ERR_FATAL, MSG_INTL(MSG_ARG_FILES),
ofl->ofl_name);
return (ld_exit(ofl));
}
ld_sup_input_done(ofl);
/*
* If there were any partially initialized symbol,
* do preparation works.
*/
if (ofl->ofl_ismove.head != 0) {
if (ld_sunwmove_preprocess(ofl) == S_ERROR)
return (ld_exit(ofl));
}
/*
* Before validating all symbols count the number of relocation entries.
* If copy relocations exist, COMMON symbols must be generated which are
* assigned to the executables .bss. During sym_validate() the actual
* size and alignment of the .bss is calculated. Doing things in this
* order reduces the number of symbol table traversals required (however
* it does take a little longer for the user to be told of any undefined
* symbol errors).
*/
if (ld_reloc_init(ofl) == S_ERROR)
return (ld_exit(ofl));
/*
* Now that all symbol processing is complete see if any undefined
* references still remain. If we observed undefined symbols the
* FLG_OF_FATAL bit will be set: If creating a static executable, or a
* dynamic executable or shared object with the -zdefs flag set, this
* condition is fatal. If creating a shared object with the -Bsymbolic
* flag set, this condition is simply a warning.
*/
if (ld_sym_validate(ofl) == S_ERROR)
return (ld_exit(ofl));
if (ofl->ofl_flags1 & FLG_OF1_OVRFLW) {
eprintf(ofl->ofl_lml, ERR_FATAL, MSG_INTL(MSG_ARG_FILES),
ofl->ofl_name);
return (ld_exit(ofl));
} else if (ofl->ofl_flags & FLG_OF_FATAL) {
eprintf(ofl->ofl_lml, ERR_FATAL, MSG_INTL(MSG_ARG_SYM_FATAL),
ofl->ofl_name);
return (ld_exit(ofl));
} else if (ofl->ofl_flags & FLG_OF_WARN)
eprintf(ofl->ofl_lml, ERR_WARNING, MSG_INTL(MSG_ARG_SYM_WARN));
/*
* Generate any necessary sections.
*/
if (ld_make_sections(ofl) == S_ERROR)
return (ld_exit(ofl));
/*
* Now that all sections have been added to the output file, check to
* see if any section ordering was specified and if so give a warning
* if any ordering directives were not matched.
* Also, if SHF_ORDERED sections exist, set up sort key values.
*/
ld_sec_validate(ofl);
/*
* Having collected all the input data create the initial output file
* image, assign virtual addresses to the image, and generate a load
* map if the user requested one.
*/
if (ld_create_outfile(ofl) == S_ERROR)
return (ld_exit(ofl));
if (ld_update_outfile(ofl) == S_ERROR)
return (ld_exit(ofl));
if (ofl->ofl_flags & FLG_OF_GENMAP)
ld_map_out(ofl);
/*
* Build relocation sections and perform any relocation updates.
*/
if (ld_reloc_process(ofl) == S_ERROR)
return (ld_exit(ofl));
#if defined(__x86) && defined(_ELF64)
/*
* Fill in contents for Unwind Header
*/
if (populate_amd64_unwindhdr(ofl) == S_ERROR)
return (ld_exit(ofl));
#endif
/*
* Finally create the files elf checksum.
*/
if (ofl->ofl_checksum)
*ofl->ofl_checksum = (Xword)elf_checksum(ofl->ofl_elf);
/*
* We're done, so make sure the updates are flushed to the output file.
*/
if ((ofl->ofl_size = elf_update(ofl->ofl_welf, ELF_C_WRITE)) == 0) {
eprintf(ofl->ofl_lml, ERR_ELF, MSG_INTL(MSG_ELF_UPDATE),
ofl->ofl_name);
return (ld_exit(ofl));
}
ld_sup_atexit(ofl, 0);
DBG_CALL(Dbg_statistics_ld(ofl));
/*
* For performance reasons we don't actually free up the memory we've
* allocated, it will be freed when we exit.
*
* But the below line can be uncommented if/when we want to measure how
* our memory consumption and freeing are doing. We should be able to
* free all the memory that has been allocated as part of the link-edit
* process.
*
* ofl_cleanup(ofl);
*/
return (0);
}
/*
* Cleanup an Ifl_desc.
*/
static void
ifl_list_cleanup(List *ifl_list)
{
Listnode *lnp;
Ifl_desc *ifl;
for (LIST_TRAVERSE(ifl_list, lnp, ifl))
if (ifl->ifl_elf)
(void) elf_end(ifl->ifl_elf);
ifl_list->head = 0;
ifl_list->tail = 0;
}
/*
* Cleanup all memory that has been dynamically allocated during libld
* processing and elf_end() all Elf descriptors that are still open.
*/
void
ld_ofl_cleanup(Ofl_desc *ofl)
{
Ld_heap *chp, *php;
Ar_desc *adp;
Listnode *lnp;
ifl_list_cleanup(&ofl->ofl_objs);
ifl_list_cleanup(&ofl->ofl_sos);
for (LIST_TRAVERSE(&ofl->ofl_ars, lnp, adp)) {
Ar_aux *aup;
Elf_Arsym *arsym;
for (arsym = adp->ad_start, aup = adp->ad_aux;
arsym->as_name; ++arsym, ++aup) {
if ((aup->au_mem) && (aup->au_mem != FLG_ARMEM_PROC)) {
(void) elf_end(aup->au_mem->am_elf);
/*
* Null out all entries to this member so
* that we don't attempt to elf_end() it again.
*/
ld_ar_member(adp, arsym, aup, 0);
}
}
(void) elf_end(adp->ad_elf);
}
(void) elf_end(ofl->ofl_elf);
(void) elf_end(ofl->ofl_welf);
for (chp = ld_heap, php = 0; chp; php = chp, chp = chp->lh_next) {
if (php)
(void) munmap((void *)php,
(size_t)php->lh_end - (size_t)php);
}
if (php)
(void) munmap((void *)php, (size_t)php->lh_end - (size_t)php);
ld_heap = 0;
}