| /* Copyright (C) 2001, 2002, 2003, 2004, 2005 Red Hat, Inc. |
| Written by Ulrich Drepper <drepper@redhat.com>, 2001. |
| |
| This program is Open Source software; you can redistribute it and/or |
| modify it under the terms of the Open Software License version 1.0 as |
| published by the Open Source Initiative. |
| |
| You should have received a copy of the Open Software License along |
| with this program; if not, you may obtain a copy of the Open Software |
| License version 1.0 from http://www.opensource.org/licenses/osl.php or |
| by writing the Open Source Initiative c/o Lawrence Rosen, Esq., |
| 3001 King Ranch Road, Ukiah, CA 95482. */ |
| |
| #ifdef HAVE_CONFIG_H |
| # include <config.h> |
| #endif |
| |
| #include <assert.h> |
| #include <dlfcn.h> |
| #include <errno.h> |
| #include <error.h> |
| #include <fcntl.h> |
| #include <fnmatch.h> |
| #include <gelf.h> |
| #include <inttypes.h> |
| #include <libintl.h> |
| #include <stdbool.h> |
| #include <stdio_ext.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <unistd.h> |
| #include <sys/param.h> |
| #include <sys/stat.h> |
| |
| #include <system.h> |
| #include "ld.h" |
| #include "list.h" |
| |
| |
| /* Prototypes for local functions. */ |
| static const char **ld_generic_lib_extensions (struct ld_state *) |
| __attribute__ ((__const__)); |
| static int ld_generic_file_close (struct usedfiles *fileinfo, |
| struct ld_state *statep); |
| static int ld_generic_file_process (int fd, struct usedfiles *fileinfo, |
| struct ld_state *statep, |
| struct usedfiles **nextp); |
| static void ld_generic_generate_sections (struct ld_state *statep); |
| static void ld_generic_create_sections (struct ld_state *statep); |
| static int ld_generic_flag_unresolved (struct ld_state *statep); |
| static int ld_generic_open_outfile (struct ld_state *statep, int machine, |
| int class, int data); |
| static int ld_generic_create_outfile (struct ld_state *statep); |
| static void ld_generic_relocate_section (struct ld_state *statep, |
| Elf_Scn *outscn, |
| struct scninfo *firstp, |
| const Elf32_Word *dblindirect); |
| static int ld_generic_finalize (struct ld_state *statep); |
| static bool ld_generic_special_section_number_p (struct ld_state *statep, |
| size_t number); |
| static bool ld_generic_section_type_p (struct ld_state *statep, |
| XElf_Word type); |
| static XElf_Xword ld_generic_dynamic_section_flags (struct ld_state *statep); |
| static void ld_generic_initialize_plt (struct ld_state *statep, Elf_Scn *scn); |
| static void ld_generic_initialize_pltrel (struct ld_state *statep, |
| Elf_Scn *scn); |
| static void ld_generic_initialize_got (struct ld_state *statep, Elf_Scn *scn); |
| static void ld_generic_finalize_plt (struct ld_state *statep, size_t nsym, |
| size_t nsym_dyn); |
| static int ld_generic_rel_type (struct ld_state *statep); |
| static void ld_generic_count_relocations (struct ld_state *statep, |
| struct scninfo *scninfo); |
| static void ld_generic_create_relocations (struct ld_state *statep, |
| const Elf32_Word *dblindirect); |
| |
| static int file_process2 (struct usedfiles *fileinfo); |
| static void mark_section_used (struct scninfo *scninfo, Elf32_Word shndx, |
| struct scninfo **grpscnp); |
| |
| |
| /* Map symbol index to struct symbol record. */ |
| static struct symbol **ndxtosym; |
| |
| /* String table reference to all symbols in the symbol table. */ |
| static struct Ebl_Strent **symstrent; |
| |
| |
| /* Check whether file associated with FD is a DSO. */ |
| static bool |
| is_dso_p (int fd) |
| { |
| /* We have to read the 'e_type' field. It has the same size (16 |
| bits) in 32- and 64-bit ELF. */ |
| XElf_Half e_type; |
| |
| return (pread (fd, &e_type, sizeof (e_type), offsetof (XElf_Ehdr, e_type)) |
| == sizeof (e_type) |
| && e_type == ET_DYN); |
| } |
| |
| |
| /* Print the complete name of a file, including the archive it is |
| contained in. */ |
| static int |
| print_file_name (FILE *s, struct usedfiles *fileinfo, int first_level, |
| int newline) |
| { |
| int npar = 0; |
| |
| if (fileinfo->archive_file != NULL) |
| { |
| npar = print_file_name (s, fileinfo->archive_file, 0, 0) + 1; |
| fputc_unlocked ('(', s); |
| fputs_unlocked (fileinfo->rfname, s); |
| |
| if (first_level) |
| while (npar-- > 0) |
| fputc_unlocked (')', s); |
| } |
| else |
| fputs_unlocked (fileinfo->rfname, s); |
| |
| if (first_level && newline) |
| fputc_unlocked ('\n', s); |
| |
| return npar; |
| } |
| |
| |
| /* Function to determine whether an object will be dynamically linked. */ |
| bool |
| dynamically_linked_p (void) |
| { |
| return (ld_state.file_type == dso_file_type || ld_state.nplt > 0 |
| || ld_state.ngot > 0); |
| } |
| |
| |
| bool |
| linked_from_dso_p (struct scninfo *scninfo, size_t symidx) |
| { |
| struct usedfiles *file = scninfo->fileinfo; |
| |
| /* If this symbol is not undefined in this file it cannot come from |
| a DSO. */ |
| if (symidx < file->nlocalsymbols) |
| return false; |
| |
| struct symbol *sym = file->symref[symidx]; |
| |
| return sym->defined && sym->in_dso; |
| } |
| |
| |
| /* Initialize state object. This callback function is called after the |
| parameters are parsed but before any file is searched for. */ |
| int |
| ld_prepare_state (const char *emulation) |
| { |
| /* When generating DSO we normally allow undefined symbols. */ |
| ld_state.nodefs = true; |
| |
| /* To be able to detect problems we add a .comment section entry by |
| default. */ |
| ld_state.add_ld_comment = true; |
| |
| /* XXX We probably should find a better place for this. The index |
| of the first user-defined version is 2. */ |
| ld_state.nextveridx = 2; |
| |
| /* Pick an not too small number for the initial size of the tables. */ |
| ld_symbol_tab_init (&ld_state.symbol_tab, 1027); |
| ld_section_tab_init (&ld_state.section_tab, 67); |
| ld_version_str_tab_init (&ld_state.version_str_tab, 67); |
| |
| /* Initialize the section header string table. */ |
| ld_state.shstrtab = ebl_strtabinit (true); |
| if (ld_state.shstrtab == NULL) |
| error (EXIT_FAILURE, errno, gettext ("cannot create string table")); |
| |
| /* Initialize the callbacks. These are the defaults, the appropriate |
| backend can later install its own callbacks. */ |
| ld_state.callbacks.lib_extensions = ld_generic_lib_extensions; |
| ld_state.callbacks.file_process = ld_generic_file_process; |
| ld_state.callbacks.file_close = ld_generic_file_close; |
| ld_state.callbacks.generate_sections = ld_generic_generate_sections; |
| ld_state.callbacks.create_sections = ld_generic_create_sections; |
| ld_state.callbacks.flag_unresolved = ld_generic_flag_unresolved; |
| ld_state.callbacks.open_outfile = ld_generic_open_outfile; |
| ld_state.callbacks.create_outfile = ld_generic_create_outfile; |
| ld_state.callbacks.relocate_section = ld_generic_relocate_section; |
| ld_state.callbacks.finalize = ld_generic_finalize; |
| ld_state.callbacks.special_section_number_p = |
| ld_generic_special_section_number_p; |
| ld_state.callbacks.section_type_p = ld_generic_section_type_p; |
| ld_state.callbacks.dynamic_section_flags = ld_generic_dynamic_section_flags; |
| ld_state.callbacks.initialize_plt = ld_generic_initialize_plt; |
| ld_state.callbacks.initialize_pltrel = ld_generic_initialize_pltrel; |
| ld_state.callbacks.initialize_got = ld_generic_initialize_got; |
| ld_state.callbacks.finalize_plt = ld_generic_finalize_plt; |
| ld_state.callbacks.rel_type = ld_generic_rel_type; |
| ld_state.callbacks.count_relocations = ld_generic_count_relocations; |
| ld_state.callbacks.create_relocations = ld_generic_create_relocations; |
| |
| #ifndef BASE_ELF_NAME |
| /* Find the ld backend library. Use EBL to determine the name if |
| the user hasn't provided one on the command line. */ |
| if (emulation == NULL) |
| { |
| emulation = ebl_backend_name (ld_state.ebl); |
| assert (emulation != NULL); |
| } |
| size_t emulation_len = strlen (emulation); |
| |
| /* Construct the file name. */ |
| char *fname = (char *) alloca (sizeof "libld_" - 1 + emulation_len |
| + sizeof ".so"); |
| strcpy (mempcpy (stpcpy (fname, "libld_"), emulation, emulation_len), ".so"); |
| |
| /* Try loading. */ |
| void *h = dlopen (fname, RTLD_LAZY); |
| if (h == NULL) |
| error (EXIT_FAILURE, 0, |
| gettext ("cannot load ld backend library '%s': %s"), |
| fname, dlerror ()); |
| |
| /* Find the initializer. It must be present. */ |
| char *initname = (char *) alloca (emulation_len + sizeof "_ld_init"); |
| strcpy (mempcpy (initname, emulation, emulation_len), "_ld_init"); |
| int (*initfct) (struct ld_state *) |
| = (int (*) (struct ld_state *)) dlsym (h, initname); |
| |
| if (initfct == NULL) |
| error (EXIT_FAILURE, 0, gettext ("\ |
| cannot find init function in ld backend library '%s': %s"), |
| fname, dlerror ()); |
| |
| /* Store the handle. */ |
| ld_state.ldlib = h; |
| |
| /* Call the init function. */ |
| return initfct (&ld_state); |
| #else |
| # define INIT_FCT_NAME(base) _INIT_FCT_NAME(base) |
| # define _INIT_FCT_NAME(base) base##_ld_init |
| /* Declare and call the initialization function. */ |
| extern int INIT_FCT_NAME(BASE_ELF_NAME) (struct ld_state *); |
| return INIT_FCT_NAME(BASE_ELF_NAME) (&ld_state); |
| #endif |
| } |
| |
| |
| static int |
| check_for_duplicate2 (struct usedfiles *newp, struct usedfiles *list) |
| { |
| struct usedfiles *first; |
| struct usedfiles *prevp; |
| |
| if (list == NULL) |
| return 0; |
| |
| prevp = list; |
| list = first = list->next; |
| do |
| { |
| /* When searching the needed list we might come across entries |
| for files which are not yet opened. Stop then, there is |
| nothing more to test. */ |
| if (likely (list->status == not_opened)) |
| break; |
| |
| if (unlikely (list->ino == newp->ino) |
| && unlikely (list->dev == newp->dev)) |
| { |
| close (newp->fd); |
| newp->fd = -1; |
| newp->status = closed; |
| if (newp->file_type == relocatable_file_type) |
| error (0, 0, gettext ("%s listed more than once as input"), |
| newp->rfname); |
| |
| return 1; |
| } |
| list = list->next; |
| } |
| while (likely (list != first)); |
| |
| return 0; |
| } |
| |
| |
| static int |
| check_for_duplicate (struct usedfiles *newp) |
| { |
| struct stat st; |
| |
| if (unlikely (fstat (newp->fd, &st) < 0)) |
| { |
| close (newp->fd); |
| return errno; |
| } |
| |
| newp->dev = st.st_dev; |
| newp->ino = st.st_ino; |
| |
| return (check_for_duplicate2 (newp, ld_state.relfiles) |
| || check_for_duplicate2 (newp, ld_state.dsofiles) |
| || check_for_duplicate2 (newp, ld_state.needed)); |
| } |
| |
| |
| /* Find a file along the path described in the state. */ |
| static int |
| open_along_path2 (struct usedfiles *fileinfo, struct pathelement *path) |
| { |
| const char *fname = fileinfo->fname; |
| size_t fnamelen = strlen (fname); |
| int err = ENOENT; |
| struct pathelement *firstp = path; |
| |
| if (path == NULL) |
| /* Cannot find anything since we have no path. */ |
| return ENOENT; |
| |
| do |
| { |
| if (likely (path->exist >= 0)) |
| { |
| /* Create the file name. */ |
| char *rfname = NULL; |
| size_t dirlen = strlen (path->pname); |
| int fd = -1; |
| |
| if (fileinfo->file_type == archive_file_type) |
| { |
| const char **exts = (ld_state.statically |
| ? (const char *[2]) { ".a", NULL } |
| : LIB_EXTENSION (&ld_state)); |
| |
| /* We have to create the actual file name. We prepend "lib" |
| and add one of the extensions the platform has. */ |
| while (*exts != NULL) |
| { |
| size_t extlen = strlen (*exts); |
| rfname = (char *) alloca (dirlen + 5 + fnamelen + extlen); |
| memcpy (mempcpy (stpcpy (mempcpy (rfname, path->pname, |
| dirlen), |
| "/lib"), |
| fname, fnamelen), |
| *exts, extlen + 1); |
| |
| fd = open (rfname, O_RDONLY); |
| if (likely (fd != -1) || errno != ENOENT) |
| { |
| err = fd == -1 ? errno : 0; |
| break; |
| } |
| |
| /* Next extension. */ |
| ++exts; |
| } |
| } |
| else |
| { |
| assert (fileinfo->file_type == dso_file_type |
| || fileinfo->file_type == dso_needed_file_type); |
| |
| rfname = (char *) alloca (dirlen + 1 + fnamelen + 1); |
| memcpy (stpcpy (mempcpy (rfname, path->pname, dirlen), "/"), |
| fname, fnamelen + 1); |
| |
| fd = open (rfname, O_RDONLY); |
| if (unlikely (fd == -1)) |
| err = errno; |
| } |
| |
| if (likely (fd != -1)) |
| { |
| /* We found the file. This also means the directory |
| exists. */ |
| fileinfo->fd = fd; |
| path->exist = 1; |
| |
| /* Check whether we have this file already loaded. */ |
| if (unlikely (check_for_duplicate (fileinfo) != 0)) |
| return EAGAIN; |
| |
| /* Make a copy of the name. */ |
| fileinfo->rfname = obstack_strdup (&ld_state.smem, rfname); |
| |
| if (unlikely (ld_state.trace_files)) |
| printf (fileinfo->file_type == archive_file_type |
| ? gettext ("%s (for -l%s)\n") |
| : gettext ("%s (for DT_NEEDED %s)\n"), |
| rfname, fname); |
| |
| return 0; |
| } |
| |
| /* The file does not exist. Maybe the whole directory doesn't. |
| Check it unless we know it exists. */ |
| if (unlikely (path->exist == 0)) |
| { |
| struct stat st; |
| |
| /* Keep only the directory name. Note that the path |
| might be relative. This doesn't matter here. We do |
| the test in any case even if there is the chance that |
| somebody wants to change the programs working |
| directory at some point which would make the result |
| of this test void. Since changing the working |
| directory is completely wrong we are not taking this |
| case into account. */ |
| rfname[dirlen] = '\0'; |
| if (unlikely (stat (rfname, &st) < 0) || ! S_ISDIR (st.st_mode)) |
| /* The directory does not exist or the named file is no |
| directory. */ |
| path->exist = -1; |
| else |
| path->exist = 1; |
| } |
| } |
| |
| /* Next path element. */ |
| path = path->next; |
| } |
| while (likely (err == ENOENT && path != firstp)); |
| |
| return err; |
| } |
| |
| |
| static int |
| open_along_path (struct usedfiles *fileinfo) |
| { |
| const char *fname = fileinfo->fname; |
| int err = ENOENT; |
| |
| if (fileinfo->file_type == relocatable_file_type) |
| { |
| /* Only libraries are searched along the path. */ |
| fileinfo->fd = open (fname, O_RDONLY); |
| |
| if (likely (fileinfo->fd != -1)) |
| { |
| /* We found the file. */ |
| if (unlikely (ld_state.trace_files)) |
| print_file_name (stdout, fileinfo, 1, 1); |
| |
| return check_for_duplicate (fileinfo); |
| } |
| |
| /* If the name is an absolute path we are done. */ |
| err = errno; |
| } |
| else |
| { |
| /* If the user specified two parts to the LD_LIBRARY_PATH variable |
| try the first part now. */ |
| err = open_along_path2 (fileinfo, ld_state.ld_library_path1); |
| |
| /* Try the user-specified path next. */ |
| if (err == ENOENT) |
| err = open_along_path2 (fileinfo, |
| fileinfo->file_type == archive_file_type |
| ? ld_state.paths : ld_state.rpath_link); |
| |
| /* Then the second part of the LD_LIBRARY_PATH value. */ |
| if (unlikely (err == ENOENT)) |
| { |
| err = open_along_path2 (fileinfo, ld_state.ld_library_path2); |
| |
| /* In case we look for a DSO handle now the RUNPATH. */ |
| if (err == ENOENT) |
| { |
| if (fileinfo->file_type == dso_file_type) |
| err = open_along_path2 (fileinfo, ld_state.runpath_link); |
| |
| /* Finally the path from the default linker script. */ |
| if (err == ENOENT) |
| err = open_along_path2 (fileinfo, ld_state.default_paths); |
| } |
| } |
| } |
| |
| if (unlikely (err != 0) |
| && (err != EAGAIN || fileinfo->file_type == relocatable_file_type)) |
| error (0, err, gettext ("cannot open %s"), fileinfo->fname); |
| |
| return err; |
| } |
| |
| |
| static void |
| check_type_and_size (const XElf_Sym *sym, struct usedfiles *fileinfo, |
| struct symbol *oldp) |
| { |
| /* We check the type and size of the symbols. In both cases the |
| information can be missing (size is zero, type is STT_NOTYPE) in |
| which case we issue no warnings. Otherwise everything must |
| match. If the type does not match there is no point in checking |
| the size. */ |
| |
| if (XELF_ST_TYPE (sym->st_info) != STT_NOTYPE && oldp->type != STT_NOTYPE |
| && unlikely (oldp->type != XELF_ST_TYPE (sym->st_info))) |
| { |
| char buf1[64]; |
| char buf2[64]; |
| |
| error (0, 0, gettext ("\ |
| Warning: type of `%s' changed from %s in %s to %s in %s"), |
| oldp->name, |
| ebl_symbol_type_name (ld_state.ebl, oldp->type, |
| buf1, sizeof (buf1)), |
| oldp->file->rfname, |
| ebl_symbol_type_name (ld_state.ebl, XELF_ST_TYPE (sym->st_info), |
| buf2, sizeof (buf2)), |
| fileinfo->rfname); |
| } |
| else if (XELF_ST_TYPE (sym->st_info) == STT_OBJECT |
| && oldp->size != 0 |
| && unlikely (oldp->size != sym->st_size)) |
| error (0, 0, gettext ("\ |
| Warning: size of `%s' changed from %" PRIu64 " in %s to %" PRIu64 " in %s"), |
| oldp->name, (uint64_t) oldp->size, oldp->file->rfname, |
| (uint64_t) sym->st_size, fileinfo->rfname); |
| } |
| |
| |
| static int |
| check_definition (const XElf_Sym *sym, size_t symidx, |
| struct usedfiles *fileinfo, struct symbol *oldp) |
| { |
| int result = 0; |
| bool old_in_dso = FILEINFO_EHDR (oldp->file->ehdr).e_type == ET_DYN; |
| bool new_in_dso = FILEINFO_EHDR (fileinfo->ehdr).e_type == ET_DYN; |
| bool use_new_def = false; |
| |
| if (sym->st_shndx != SHN_UNDEF |
| && (! oldp->defined |
| || (sym->st_shndx != SHN_COMMON && oldp->common && ! new_in_dso) |
| || (old_in_dso && ! new_in_dso))) |
| { |
| /* We found a definition for a previously undefined symbol or a |
| real definition for a previous common-only definition or a |
| redefinition of a symbol definition in an object file |
| previously defined in a DSO. First perform some tests which |
| will show whether the common is really matching the |
| definition. */ |
| check_type_and_size (sym, fileinfo, oldp); |
| |
| /* We leave the next element intact to not interrupt the list |
| with the unresolved symbols. Whoever walks the list will |
| have to check the `defined' flag. But we remember that this |
| list element is not unresolved anymore. */ |
| if (! oldp->defined) |
| { |
| /* Remove from the list. */ |
| --ld_state.nunresolved; |
| if (! oldp->weak) |
| --ld_state.nunresolved_nonweak; |
| CDBL_LIST_DEL (ld_state.unresolved, oldp); |
| } |
| else if (oldp->common) |
| /* Remove from the list. */ |
| CDBL_LIST_DEL (ld_state.common_syms, oldp); |
| |
| /* Use the values of the definition from now on. */ |
| use_new_def = true; |
| } |
| else if (sym->st_shndx != SHN_UNDEF |
| && unlikely (! oldp->common) |
| && oldp->defined |
| && sym->st_shndx != SHN_COMMON |
| /* Multiple definitions are no fatal errors if the -z muldefs flag |
| is used. We don't warn about the multiple definition unless we |
| are told to be verbose. */ |
| && (!ld_state.muldefs || verbose) |
| && ! old_in_dso && fileinfo->file_type == relocatable_file_type) |
| { |
| /* We have a double definition. This is a problem. */ |
| char buf[64]; |
| XElf_Sym_vardef (oldsym); |
| struct usedfiles *oldfile; |
| const char *scnname; |
| Elf32_Word xndx; |
| size_t shndx; |
| size_t shnum; |
| |
| if (elf_getshnum (fileinfo->elf, &shnum) < 0) |
| error (EXIT_FAILURE, 0, |
| gettext ("cannot determine number of sections: %s"), |
| elf_errmsg (-1)); |
| |
| /* XXX Use only ebl_section_name. */ |
| if (sym->st_shndx < SHN_LORESERVE // || sym->st_shndx > SHN_HIRESERVE |
| && sym->st_shndx < shnum) |
| scnname = elf_strptr (fileinfo->elf, |
| fileinfo->shstrndx, |
| SCNINFO_SHDR (fileinfo->scninfo[sym->st_shndx].shdr).sh_name); |
| else |
| // XXX extended section |
| scnname = ebl_section_name (ld_state.ebl, sym->st_shndx, 0, |
| buf, sizeof (buf), NULL, shnum); |
| |
| /* XXX Print source file and line number. */ |
| print_file_name (stderr, fileinfo, 1, 0); |
| fprintf (stderr, |
| gettext ("(%s+%#" PRIx64 "): multiple definition of %s `%s'\n"), |
| scnname, |
| (uint64_t) sym->st_value, |
| ebl_symbol_type_name (ld_state.ebl, XELF_ST_TYPE (sym->st_info), |
| buf, sizeof (buf)), |
| oldp->name); |
| |
| oldfile = oldp->file; |
| xelf_getsymshndx (oldfile->symtabdata, oldfile->xndxdata, oldp->symidx, |
| oldsym, xndx); |
| if (oldsym == NULL) |
| /* This should never happen since the same call |
| succeeded before. */ |
| abort (); |
| |
| shndx = oldsym->st_shndx; |
| if (unlikely (oldsym->st_shndx == SHN_XINDEX)) |
| shndx = xndx; |
| |
| /* XXX Use only ebl_section_name. */ |
| if (shndx < SHN_LORESERVE || shndx > SHN_HIRESERVE) |
| scnname = elf_strptr (oldfile->elf, |
| oldfile->shstrndx, |
| SCNINFO_SHDR (oldfile->scninfo[shndx].shdr).sh_name); |
| else |
| scnname = ebl_section_name (ld_state.ebl, oldsym->st_shndx, shndx, buf, |
| sizeof (buf), NULL, shnum); |
| |
| /* XXX Print source file and line number. */ |
| print_file_name (stderr, oldfile, 1, 0); |
| fprintf (stderr, gettext ("(%s+%#" PRIx64 "): first defined here\n"), |
| scnname, (uint64_t) oldsym->st_value); |
| |
| if (likely (!ld_state.muldefs)) |
| result = 1; |
| } |
| else if (old_in_dso && fileinfo->file_type == relocatable_file_type |
| && sym->st_shndx != SHN_UNDEF) |
| /* We use the definition from a normal relocatable file over the |
| definition in a DSO. This is what the dynamic linker would |
| do, too. */ |
| use_new_def = true; |
| else if (old_in_dso && !new_in_dso && oldp->defined && !oldp->on_dsolist) |
| { |
| CDBL_LIST_ADD_REAR (ld_state.from_dso, oldp); |
| ++ld_state.nfrom_dso; |
| |
| /* If the object is a function we allocate a PLT entry, |
| otherwise only a GOT entry. */ |
| if (oldp->type == STT_FUNC) |
| ++ld_state.nplt; |
| else |
| ++ld_state.ngot; |
| |
| oldp->on_dsolist = 1; |
| } |
| else if (oldp->common && sym->st_shndx == SHN_COMMON) |
| { |
| /* The symbol size is the largest of all common definitions. */ |
| oldp->size = MAX (oldp->size, sym->st_size); |
| /* Similarly for the alignment. */ |
| oldp->merge.value = MAX (oldp->merge.value, sym->st_value); |
| } |
| |
| if (unlikely (use_new_def)) |
| { |
| /* Adjust the symbol record appropriately and remove |
| the symbol from the list of symbols which are taken from DSOs. */ |
| if (old_in_dso && fileinfo->file_type == relocatable_file_type) |
| { |
| CDBL_LIST_DEL (ld_state.from_dso, oldp); |
| --ld_state.nfrom_dso; |
| |
| if (likely (oldp->type == STT_FUNC)) |
| --ld_state.nplt; |
| else |
| --ld_state.ngot; |
| |
| oldp->on_dsolist = 0; |
| } |
| |
| /* Use the values of the definition from now on. */ |
| oldp->size = sym->st_size; |
| oldp->type = XELF_ST_TYPE (sym->st_info); |
| oldp->symidx = symidx; |
| oldp->scndx = sym->st_shndx; |
| //oldp->symscndx = THESYMSCNDX must be passed; |
| oldp->file = fileinfo; |
| oldp->defined = 1; |
| oldp->in_dso = new_in_dso; |
| oldp->common = sym->st_shndx == SHN_COMMON; |
| if (likely (fileinfo->file_type == relocatable_file_type)) |
| { |
| /* If the definition comes from a DSO we pertain the weak flag |
| and it's indicating whether the reference is weak or not. */ |
| oldp->weak = XELF_ST_BIND (sym->st_info) == STB_WEAK; |
| |
| if (sym->st_shndx != SHN_COMMON) |
| { |
| struct scninfo *ignore; |
| mark_section_used (&fileinfo->scninfo[sym->st_shndx], |
| sym->st_shndx, &ignore); |
| } |
| } |
| |
| /* Add to the list of symbols used from DSOs if necessary. */ |
| if (new_in_dso && !old_in_dso) |
| { |
| CDBL_LIST_ADD_REAR (ld_state.from_dso, oldp); |
| ++ld_state.nfrom_dso; |
| |
| /* If the object is a function we allocate a PLT entry, |
| otherwise only a GOT entry. */ |
| if (oldp->type == STT_FUNC) |
| ++ld_state.nplt; |
| else |
| ++ld_state.ngot; |
| |
| oldp->on_dsolist = 1; |
| } |
| else if (sym->st_shndx == SHN_COMMON) |
| { |
| /* Store the alignment. */ |
| oldp->merge.value = sym->st_value; |
| |
| CDBL_LIST_ADD_REAR (ld_state.common_syms, oldp); |
| } |
| } |
| |
| return result; |
| } |
| |
| |
| static struct scninfo * |
| find_section_group (struct usedfiles *fileinfo, Elf32_Word shndx, |
| Elf_Data **datap) |
| { |
| struct scninfo *runp; |
| |
| for (runp = fileinfo->groups; runp != NULL; runp = runp->next) |
| if (!runp->used) |
| { |
| Elf32_Word *grpref; |
| size_t cnt; |
| Elf_Data *data; |
| |
| data = elf_getdata (runp->scn, NULL); |
| if (data == NULL) |
| error (EXIT_FAILURE, 0, |
| gettext ("%s: cannot get section group data: %s"), |
| fileinfo->fname, elf_errmsg (-1)); |
| |
| /* There cannot be another data block. */ |
| assert (elf_getdata (runp->scn, data) == NULL); |
| |
| grpref = (Elf32_Word *) data->d_buf; |
| cnt = data->d_size / sizeof (Elf32_Word); |
| /* Note that we stop after looking at index 1 since index 0 |
| contains the flags for the section group. */ |
| while (cnt > 1) |
| if (grpref[--cnt] == shndx) |
| { |
| *datap = data; |
| return runp; |
| } |
| } |
| |
| /* If we come here no section group contained the given section |
| despite the SHF_GROUP flag. This is an error in the input |
| file. */ |
| error (EXIT_FAILURE, 0, gettext ("\ |
| %s: section '%s' with group flag set does not belong to any group"), |
| fileinfo->fname, |
| elf_strptr (fileinfo->elf, fileinfo->shstrndx, |
| SCNINFO_SHDR (fileinfo->scninfo[shndx].shdr).sh_name)); |
| return NULL; |
| } |
| |
| |
| /* Mark all sections which belong to the same group as section SHNDX |
| as used. */ |
| static void |
| mark_section_group (struct usedfiles *fileinfo, Elf32_Word shndx, |
| struct scninfo **grpscnp) |
| { |
| /* First locate the section group. There can be several (many) of |
| them. */ |
| size_t cnt; |
| Elf32_Word *grpref; |
| Elf_Data *data; |
| struct scninfo *grpscn = find_section_group (fileinfo, shndx, &data); |
| *grpscnp = grpscn; |
| |
| /* Mark all the sections as used. |
| |
| XXX Two possible problems here: |
| |
| - the gABI says "The section must be referenced by a section of type |
| SHT_GROUP". I hope everybody reads this as "exactly one section". |
| |
| - section groups are also useful to mark the debugging section which |
| belongs to a text section. Unconditionally adding debugging sections |
| is therefore probably not what is wanted if stripping is required. */ |
| |
| /* Mark the section group as handled. */ |
| grpscn->used = true; |
| |
| grpref = (Elf32_Word *) data->d_buf; |
| cnt = data->d_size / sizeof (Elf32_Word); |
| while (cnt > 1) |
| { |
| Elf32_Word idx = grpref[--cnt]; |
| XElf_Shdr *shdr = &SCNINFO_SHDR (fileinfo->scninfo[idx].shdr); |
| |
| if (fileinfo->scninfo[idx].grpid != 0) |
| error (EXIT_FAILURE, 0, gettext ("\ |
| %s: section [%2d] '%s' is in more than one section group"), |
| fileinfo->fname, (int) idx, |
| elf_strptr (fileinfo->elf, fileinfo->shstrndx, shdr->sh_name)); |
| |
| fileinfo->scninfo[idx].grpid = grpscn->grpid; |
| |
| if (ld_state.strip == strip_none |
| /* If we are stripping, remove debug sections. */ |
| || (!ebl_debugscn_p (ld_state.ebl, |
| elf_strptr (fileinfo->elf, fileinfo->shstrndx, |
| shdr->sh_name)) |
| /* And the relocation sections for the debug sections. */ |
| && ((shdr->sh_type != SHT_RELA && shdr->sh_type != SHT_REL) |
| || !ebl_debugscn_p (ld_state.ebl, |
| elf_strptr (fileinfo->elf, |
| fileinfo->shstrndx, |
| SCNINFO_SHDR (fileinfo->scninfo[shdr->sh_info].shdr).sh_name))))) |
| { |
| struct scninfo *ignore; |
| |
| mark_section_used (&fileinfo->scninfo[idx], idx, &ignore); |
| } |
| } |
| } |
| |
| |
| static void |
| mark_section_used (struct scninfo *scninfo, Elf32_Word shndx, |
| struct scninfo **grpscnp) |
| { |
| if (likely (scninfo->used)) |
| /* Nothing to be done. */ |
| return; |
| |
| /* We need this section. */ |
| scninfo->used = true; |
| |
| /* Make sure the section header has been read from the file. */ |
| XElf_Shdr *shdr = &SCNINFO_SHDR (scninfo->shdr); |
| #if NATIVE_ELF |
| if (unlikely (scninfo->shdr == NULL)) |
| #else |
| if (unlikely (scninfo->shdr.sh_type == SHT_NULL)) |
| #endif |
| { |
| #if NATIVE_ELF != 0 |
| shdr = xelf_getshdr (scninfo->scn, scninfo->shdr); |
| #else |
| xelf_getshdr_copy (scninfo->scn, shdr, scninfo->shdr); |
| #endif |
| if (unlikely (shdr == NULL)) |
| /* Something is very wrong. The calling code will notice it |
| soon and print a message. */ |
| return; |
| } |
| |
| /* Handle section linked by 'sh_link'. */ |
| if (unlikely (shdr->sh_link != 0)) |
| { |
| struct scninfo *ignore; |
| mark_section_used (&scninfo->fileinfo->scninfo[shdr->sh_link], |
| shdr->sh_link, &ignore); |
| } |
| |
| /* Handle section linked by 'sh_info'. */ |
| if (unlikely (shdr->sh_info != 0) && (shdr->sh_flags & SHF_INFO_LINK)) |
| { |
| struct scninfo *ignore; |
| mark_section_used (&scninfo->fileinfo->scninfo[shdr->sh_info], |
| shdr->sh_info, &ignore); |
| } |
| |
| if (unlikely (shdr->sh_flags & SHF_GROUP) && ld_state.gc_sections) |
| /* Find the section group which contains this section. */ |
| mark_section_group (scninfo->fileinfo, shndx, grpscnp); |
| } |
| |
| |
| /* We collect all sections in a hashing table. All sections with the |
| same name are collected in a list. Note that we do not determine |
| which sections are finally collected in the same output section |
| here. This would be terribly inefficient. It will be done later. */ |
| static void |
| add_section (struct usedfiles *fileinfo, struct scninfo *scninfo) |
| { |
| struct scnhead *queued; |
| struct scnhead search; |
| unsigned long int hval; |
| XElf_Shdr *shdr = &SCNINFO_SHDR (scninfo->shdr); |
| struct scninfo *grpscn = NULL; |
| Elf_Data *grpscndata = NULL; |
| |
| /* See whether we can determine right away whether we need this |
| section in the output. |
| |
| XXX I assume here that --gc-sections only affects extraction |
| from an archive. If it also affects objects files given on |
| the command line then somebody must explain to me how the |
| dependency analysis should work. Should the entry point be |
| the root? What if it is a numeric value? */ |
| if (!scninfo->used |
| && (ld_state.strip == strip_none |
| || (shdr->sh_flags & SHF_ALLOC) != 0 |
| || shdr->sh_type == SHT_NOTE |
| || (shdr->sh_type == SHT_PROGBITS |
| && strcmp (elf_strptr (fileinfo->elf, |
| fileinfo->shstrndx, |
| shdr->sh_name), ".comment") == 0)) |
| && (fileinfo->status != in_archive || !ld_state.gc_sections)) |
| /* Mark as used and handle reference recursively if necessary. */ |
| mark_section_used (scninfo, elf_ndxscn (scninfo->scn), &grpscn); |
| |
| if ((shdr->sh_flags & SHF_GROUP) && grpscn == NULL) |
| /* Determine the symbol which name constitutes the signature |
| for the section group. */ |
| grpscn = find_section_group (fileinfo, elf_ndxscn (scninfo->scn), |
| &grpscndata); |
| assert (grpscn == NULL || grpscn->symbols->name != NULL); |
| |
| /* Determine the section name. */ |
| search.name = elf_strptr (fileinfo->elf, fileinfo->shstrndx, shdr->sh_name); |
| search.type = shdr->sh_type; |
| search.flags = shdr->sh_flags; |
| search.entsize = shdr->sh_entsize; |
| search.grp_signature = grpscn != NULL ? grpscn->symbols->name : NULL; |
| search.kind = scn_normal; |
| hval = elf_hash (search.name); |
| |
| /* Find already queued sections. */ |
| queued = ld_section_tab_find (&ld_state.section_tab, hval, &search); |
| if (queued != NULL) |
| { |
| bool is_comdat = false; |
| |
| /* If this section is part of a COMDAT section group we simply |
| ignore it since we already have a copy. */ |
| if (unlikely (shdr->sh_flags & SHF_GROUP)) |
| { |
| /* Get the data of the section group section. */ |
| if (grpscndata == NULL) |
| { |
| grpscndata = elf_getdata (grpscn->scn, NULL); |
| assert (grpscndata != NULL); |
| } |
| |
| /* XXX Possibly unaligned memory access. */ |
| is_comdat = ((Elf32_Word *) grpscndata->d_buf)[0] & GRP_COMDAT; |
| } |
| |
| if (!is_comdat) |
| { |
| /* No COMDAT section, we use the data. */ |
| scninfo->next = queued->last->next; |
| queued->last = queued->last->next = scninfo; |
| |
| queued->flags = SH_FLAGS_COMBINE (queued->flags, shdr->sh_flags); |
| queued->align = MAX (queued->align, shdr->sh_addralign); |
| } |
| } |
| else |
| { |
| /* We do not use obstacks here since the memory might be |
| deallocated. */ |
| queued = (struct scnhead *) xcalloc (sizeof (struct scnhead), 1); |
| queued->kind = scn_normal; |
| queued->name = search.name; |
| queued->type = shdr->sh_type; |
| queued->flags = shdr->sh_flags; |
| queued->align = shdr->sh_addralign; |
| queued->entsize = shdr->sh_entsize; |
| queued->grp_signature = grpscn != NULL ? grpscn->symbols->name : NULL; |
| queued->segment_nr = ~0; |
| queued->last = scninfo->next = scninfo; |
| |
| /* Add to the hash table and possibly overwrite existing value. */ |
| ld_section_tab_insert (&ld_state.section_tab, hval, queued); |
| } |
| } |
| |
| |
| static int |
| add_relocatable_file (struct usedfiles *fileinfo, GElf_Word secttype) |
| { |
| size_t scncnt; |
| size_t cnt; |
| Elf_Data *symtabdata = NULL; |
| Elf_Data *xndxdata = NULL; |
| Elf_Data *versymdata = NULL; |
| Elf_Data *verdefdata = NULL; |
| Elf_Data *verneeddata = NULL; |
| size_t symstridx = 0; |
| size_t nsymbols = 0; |
| size_t nlocalsymbols = 0; |
| bool has_merge_sections = false; |
| |
| /* Prerequisites. */ |
| assert (fileinfo->elf != NULL); |
| |
| /* Allocate memory for the sections. */ |
| if (unlikely (elf_getshnum (fileinfo->elf, &scncnt) < 0)) |
| error (EXIT_FAILURE, 0, |
| gettext ("cannot determine number of sections: %s"), |
| elf_errmsg (-1)); |
| |
| fileinfo->scninfo = (struct scninfo *) |
| obstack_calloc (&ld_state.smem, scncnt * sizeof (struct scninfo)); |
| |
| /* Read all the section headers and find the symbol table. Note |
| that we don't skip the section with index zero. Even though the |
| section itself is always empty the section header contains |
| informaton for the case when the section index for the section |
| header string table is too large to fit in the ELF header. */ |
| for (cnt = 0; cnt < scncnt; ++cnt) |
| { |
| /* Store the handle for the section. */ |
| fileinfo->scninfo[cnt].scn = elf_getscn (fileinfo->elf, cnt); |
| |
| /* Get the ELF section header and data. */ |
| XElf_Shdr *shdr; |
| #if NATIVE_ELF != 0 |
| if (fileinfo->scninfo[cnt].shdr == NULL) |
| #else |
| if (fileinfo->scninfo[cnt].shdr.sh_type == SHT_NULL) |
| #endif |
| { |
| #if NATIVE_ELF != 0 |
| shdr = xelf_getshdr (fileinfo->scninfo[cnt].scn, |
| fileinfo->scninfo[cnt].shdr); |
| #else |
| xelf_getshdr_copy (fileinfo->scninfo[cnt].scn, shdr, |
| fileinfo->scninfo[cnt].shdr); |
| #endif |
| if (shdr == NULL) |
| { |
| /* This should never happen. */ |
| fprintf (stderr, gettext ("%s: invalid ELF file (%s:%d)\n"), |
| fileinfo->rfname, __FILE__, __LINE__); |
| return 1; |
| } |
| } |
| else |
| shdr = &SCNINFO_SHDR (fileinfo->scninfo[cnt].shdr); |
| |
| Elf_Data *data = elf_getdata (fileinfo->scninfo[cnt].scn, NULL); |
| |
| /* Check whether this section is marked as merge-able. */ |
| has_merge_sections |= (shdr->sh_flags & SHF_MERGE) != 0; |
| |
| /* Get the ELF section header and data. */ |
| /* Make the file structure available. */ |
| fileinfo->scninfo[cnt].fileinfo = fileinfo; |
| |
| if (unlikely (shdr->sh_type == SHT_SYMTAB) |
| || unlikely (shdr->sh_type == SHT_DYNSYM)) |
| { |
| if (shdr->sh_type == SHT_SYMTAB) |
| { |
| assert (fileinfo->symtabdata == NULL); |
| fileinfo->symtabdata = data; |
| fileinfo->nsymtab = shdr->sh_size / shdr->sh_entsize; |
| fileinfo->nlocalsymbols = shdr->sh_info; |
| fileinfo->symstridx = shdr->sh_link; |
| } |
| else |
| { |
| assert (fileinfo->dynsymtabdata == NULL); |
| fileinfo->dynsymtabdata = data; |
| fileinfo->ndynsymtab = shdr->sh_size / shdr->sh_entsize; |
| fileinfo->dynsymstridx = shdr->sh_link; |
| } |
| |
| /* If we are looking for the normal symbol table we just |
| found it. */ |
| if (secttype == shdr->sh_type) |
| { |
| assert (symtabdata == NULL); |
| symtabdata = data; |
| symstridx = shdr->sh_link; |
| nsymbols = shdr->sh_size / shdr->sh_entsize; |
| nlocalsymbols = shdr->sh_info; |
| } |
| } |
| else if (unlikely (shdr->sh_type == SHT_SYMTAB_SHNDX)) |
| { |
| assert (xndxdata == NULL); |
| fileinfo->xndxdata = xndxdata = data; |
| } |
| else if (unlikely (shdr->sh_type == SHT_GNU_versym)) |
| { |
| assert (versymdata == 0); |
| fileinfo->versymdata = versymdata = data; |
| } |
| else if (unlikely (shdr->sh_type == SHT_GNU_verdef)) |
| { |
| size_t nversions; |
| |
| assert (verdefdata == 0); |
| fileinfo->verdefdata = verdefdata = data; |
| |
| /* Allocate the arrays flagging the use of the version and |
| to track of allocated names. */ |
| fileinfo->nverdef = nversions = shdr->sh_info; |
| /* We have NVERSIONS + 1 because the indeces used to access the |
| sectino start with one; zero represents local binding. */ |
| fileinfo->verdefused = (XElf_Versym *) |
| obstack_calloc (&ld_state.smem, |
| sizeof (XElf_Versym) * (nversions + 1)); |
| fileinfo->verdefent = (struct Ebl_Strent **) |
| obstack_alloc (&ld_state.smem, |
| sizeof (struct Ebl_Strent *) * (nversions + 1)); |
| } |
| else if (unlikely (shdr->sh_type == SHT_GNU_verneed)) |
| { |
| assert (verneeddata == 0); |
| fileinfo->verneeddata = verneeddata = data; |
| } |
| else if (unlikely (shdr->sh_type == SHT_DYNAMIC)) |
| { |
| assert (fileinfo->dynscn == NULL); |
| fileinfo->dynscn = fileinfo->scninfo[cnt].scn; |
| } |
| else if (unlikely (shdr->sh_type == SHT_GROUP)) |
| { |
| Elf_Scn *symscn; |
| XElf_Shdr_vardef (symshdr); |
| Elf_Data *symdata; |
| |
| if (FILEINFO_EHDR (fileinfo->ehdr).e_type != ET_REL) |
| error (EXIT_FAILURE, 0, gettext ("\ |
| %s: only files of type ET_REL might contain section groups"), |
| fileinfo->fname); |
| |
| fileinfo->scninfo[cnt].next = fileinfo->groups; |
| fileinfo->scninfo[cnt].grpid = cnt; |
| fileinfo->groups = &fileinfo->scninfo[cnt]; |
| |
| /* Determine the signature. We create a symbol record for |
| it. Only the name element is important. */ |
| fileinfo->scninfo[cnt].symbols = (struct symbol *) |
| obstack_calloc (&ld_state.smem, sizeof (struct symbol)); |
| |
| symscn = elf_getscn (fileinfo->elf, shdr->sh_link); |
| xelf_getshdr (symscn, symshdr); |
| symdata = elf_getdata (symscn, NULL); |
| if (symshdr != NULL) |
| { |
| XElf_Sym_vardef (sym); |
| |
| /* We don't need the section index and therefore we don't |
| have to use 'xelf_getsymshndx'. */ |
| xelf_getsym (symdata, shdr->sh_info, sym); |
| if (sym != NULL) |
| { |
| struct symbol *symbol = fileinfo->scninfo[cnt].symbols; |
| |
| symbol->name = elf_strptr (fileinfo->elf, symshdr->sh_link, |
| sym->st_name); |
| symbol->symidx = shdr->sh_info; |
| symbol->file = fileinfo; |
| } |
| } |
| if (fileinfo->scninfo[cnt].symbols->name == NULL) |
| error (EXIT_FAILURE, 0, gettext ("\ |
| %s: cannot determine signature of section group [%2zd] '%s': %s"), |
| fileinfo->fname, |
| elf_ndxscn (fileinfo->scninfo[cnt].scn), |
| elf_strptr (fileinfo->elf, fileinfo->shstrndx, |
| shdr->sh_name), |
| elf_errmsg (-1)); |
| |
| /* The 'used' flag is used to indicate when the information |
| in the section group is used to mark all other sections |
| as used. So it must not be true yet. */ |
| assert (fileinfo->scninfo[cnt].used == false); |
| } |
| else if (! SECTION_TYPE_P (&ld_state, shdr->sh_type) |
| && unlikely ((shdr->sh_flags & SHF_OS_NONCONFORMING) != 0)) |
| /* According to the gABI it is a fatal error if the file contains |
| a section with unknown type and the SHF_OS_NONCONFORMING flag |
| set. */ |
| error (EXIT_FAILURE, 0, |
| gettext ("%s: section '%s' has unknown type: %d"), |
| fileinfo->fname, |
| elf_strptr (fileinfo->elf, fileinfo->shstrndx, |
| shdr->sh_name), |
| (int) shdr->sh_type); |
| /* We don't have to add a few section types here. These will be |
| generated from scratch for the new output file. We also |
| don't add the sections of DSOs here since these sections are |
| not used in the resulting object file. */ |
| else if (likely (fileinfo->file_type == relocatable_file_type) |
| && likely (cnt > 0) |
| && likely (shdr->sh_type == SHT_PROGBITS |
| || shdr->sh_type == SHT_RELA |
| || shdr->sh_type == SHT_REL |
| || shdr->sh_type == SHT_NOTE |
| || shdr->sh_type == SHT_NOBITS |
| || shdr->sh_type == SHT_INIT_ARRAY |
| || shdr->sh_type == SHT_FINI_ARRAY |
| || shdr->sh_type == SHT_PREINIT_ARRAY)) |
| add_section (fileinfo, &fileinfo->scninfo[cnt]); |
| } |
| |
| /* Handle the symbols. Record defined and undefined symbols in the |
| hash table. In theory there can be a file without any symbol |
| table. */ |
| if (likely (symtabdata != NULL)) |
| { |
| /* In case this file contains merge-able sections we have to |
| locate the symbols which are in these sections. */ |
| fileinfo->has_merge_sections = has_merge_sections; |
| if (likely (has_merge_sections)) |
| { |
| fileinfo->symref = (struct symbol **) |
| obstack_calloc (&ld_state.smem, |
| nsymbols * sizeof (struct symbol *)); |
| |
| /* Only handle the local symbols here. */ |
| for (cnt = 0; cnt < nlocalsymbols; ++cnt) |
| { |
| Elf32_Word shndx; |
| XElf_Sym_vardef (sym); |
| |
| xelf_getsymshndx (symtabdata, xndxdata, cnt, sym, shndx); |
| if (sym == NULL) |
| { |
| /* This should never happen. */ |
| fprintf (stderr, gettext ("%s: invalid ELF file (%s:%d)\n"), |
| fileinfo->rfname, __FILE__, __LINE__); |
| return 1; |
| } |
| |
| if (likely (shndx != SHN_XINDEX)) |
| shndx = sym->st_shndx; |
| else if (unlikely (shndx == 0)) |
| { |
| fprintf (stderr, gettext ("%s: invalid ELF file (%s:%d)\n"), |
| fileinfo->rfname, __FILE__, __LINE__); |
| return 1; |
| } |
| |
| if (XELF_ST_TYPE (sym->st_info) != STT_SECTION |
| && (shndx < SHN_LORESERVE || shndx > SHN_HIRESERVE) |
| && (SCNINFO_SHDR (fileinfo->scninfo[shndx].shdr).sh_flags |
| & SHF_MERGE)) |
| { |
| /* Create a symbol record for this symbol and add it |
| to the list for this section. */ |
| struct symbol *newp; |
| |
| newp = (struct symbol *) |
| obstack_calloc (&ld_state.smem, sizeof (struct symbol)); |
| |
| newp->symidx = cnt; |
| newp->scndx = shndx; |
| newp->file = fileinfo; |
| fileinfo->symref[cnt] = newp; |
| |
| if (fileinfo->scninfo[shndx].symbols == NULL) |
| fileinfo->scninfo[shndx].symbols = newp->next_in_scn |
| = newp; |
| else |
| { |
| newp->next_in_scn |
| = fileinfo->scninfo[shndx].symbols->next_in_scn; |
| fileinfo->scninfo[shndx].symbols |
| = fileinfo->scninfo[shndx].symbols->next_in_scn = newp; |
| } |
| } |
| } |
| } |
| else |
| /* Create array with pointers to the symbol definitions. Note |
| that we only allocate memory for the non-local symbols |
| since we have no merge-able sections. But we store the |
| pointer as if it was for the whole symbol table. This |
| saves some memory. */ |
| fileinfo->symref = (struct symbol **) |
| obstack_calloc (&ld_state.smem, ((nsymbols - nlocalsymbols) |
| * sizeof (struct symbol *))) |
| - nlocalsymbols; |
| |
| /* Don't handle local symbols here. It's either not necessary |
| at all or has already happened. */ |
| for (cnt = nlocalsymbols; cnt < nsymbols; ++cnt) |
| { |
| XElf_Sym_vardef (sym); |
| Elf32_Word shndx; |
| xelf_getsymshndx (symtabdata, xndxdata, cnt, sym, shndx); |
| |
| if (sym == NULL) |
| { |
| /* This should never happen. */ |
| fprintf (stderr, gettext ("%s: invalid ELF file (%s:%d)\n"), |
| fileinfo->rfname, __FILE__, __LINE__); |
| return 1; |
| } |
| |
| if (likely (shndx != SHN_XINDEX)) |
| shndx = sym->st_shndx; |
| else if (unlikely (shndx == 0)) |
| { |
| fprintf (stderr, gettext ("%s: invalid ELF file (%s:%d)\n"), |
| fileinfo->rfname, __FILE__, __LINE__); |
| return 1; |
| } |
| |
| /* We ignore ABS symbols from DSOs. */ |
| // XXX Is this correct? |
| if (unlikely (shndx == SHN_ABS) && secttype == SHT_DYNSYM) |
| continue; |
| |
| /* If the DSO uses symbols determine whether this is the default |
| version. Otherwise we'll ignore the symbol. */ |
| if (versymdata != NULL) |
| { |
| XElf_Versym versym; |
| |
| if (xelf_getversym_copy (versymdata, cnt, versym) == NULL) |
| /* XXX Should we handle faulty input files more graceful? */ |
| assert (! "xelf_getversym failed"); |
| |
| if ((versym & 0x8000) != 0) |
| /* Ignore the symbol, it's not the default version. */ |
| continue; |
| } |
| |
| /* See whether we know anything about this symbol. */ |
| struct symbol search; |
| search.name = elf_strptr (fileinfo->elf, symstridx, sym->st_name); |
| unsigned long int hval = elf_hash (search.name); |
| |
| /* We ignore the symbols the linker generates. This are |
| _GLOBAL_OFFSET_TABLE_, _DYNAMIC. */ |
| // XXX This loop is hot and the following tests hardly ever match. |
| // XXX Maybe move the tests somewhere they are executed less often. |
| if (((unlikely (hval == 165832675) |
| && strcmp (search.name, "_DYNAMIC") == 0) |
| || (unlikely (hval == 102264335) |
| && strcmp (search.name, "_GLOBAL_OFFSET_TABLE_") == 0)) |
| && sym->st_shndx != SHN_UNDEF |
| /* If somebody defines such a variable in a relocatable we |
| don't ignore it. Let the user get what s/he deserves. */ |
| && fileinfo->file_type != relocatable_file_type) |
| continue; |
| |
| struct symbol *oldp = ld_symbol_tab_find (&ld_state.symbol_tab, |
| hval, &search); |
| struct symbol *newp; |
| if (likely (oldp == NULL)) |
| { |
| /* No symbol of this name know. Add it. */ |
| newp = (struct symbol *) obstack_alloc (&ld_state.smem, |
| sizeof (*newp)); |
| newp->name = search.name; |
| newp->size = sym->st_size; |
| newp->type = XELF_ST_TYPE (sym->st_info); |
| newp->symidx = cnt; |
| newp->outsymidx = 0; |
| newp->outdynsymidx = 0; |
| newp->scndx = shndx; |
| newp->file = fileinfo; |
| newp->defined = newp->scndx != SHN_UNDEF; |
| newp->common = newp->scndx == SHN_COMMON; |
| newp->weak = XELF_ST_BIND (sym->st_info) == STB_WEAK; |
| newp->added = 0; |
| newp->merged = 0; |
| newp->need_copy = 0; |
| newp->on_dsolist = 0; |
| newp->in_dso = secttype == SHT_DYNSYM; |
| newp->next_in_scn = NULL; |
| #ifndef NDEBUG |
| newp->next = NULL; |
| newp->previous = NULL; |
| #endif |
| |
| if (newp->scndx == SHN_UNDEF) |
| { |
| CDBL_LIST_ADD_REAR (ld_state.unresolved, newp); |
| ++ld_state.nunresolved; |
| if (! newp->weak) |
| ++ld_state.nunresolved_nonweak; |
| } |
| else if (newp->scndx == SHN_COMMON) |
| { |
| /* Store the alignment requirement. */ |
| newp->merge.value = sym->st_value; |
| |
| CDBL_LIST_ADD_REAR (ld_state.common_syms, newp); |
| } |
| |
| /* Insert the new symbol. */ |
| if (unlikely (ld_symbol_tab_insert (&ld_state.symbol_tab, |
| hval, newp) != 0)) |
| /* This cannot happen. */ |
| abort (); |
| |
| fileinfo->symref[cnt] = newp; |
| |
| /* We have a few special symbols to recognize. The symbols |
| _init and _fini are the initialization and finalization |
| functions respectively. They have to be made known in |
| the dynamic section and therefore we have to find out |
| now whether these functions exist or not. */ |
| if (hval == 6685956 && strcmp (newp->name, "_init") == 0) |
| ld_state.init_symbol = newp; |
| else if (hval == 6672457 && strcmp (newp->name, "_fini") == 0) |
| ld_state.fini_symbol = newp; |
| } |
| else if (unlikely (check_definition (sym, cnt, fileinfo, oldp) != 0)) |
| /* A fatal error (multiple definition of a symbol) |
| occurred, no need to continue. */ |
| return 1; |
| else |
| /* Use the previously allocated symbol record. It has |
| been updated in check_definition(), if necessary. */ |
| newp = fileinfo->symref[cnt] = oldp; |
| |
| /* Mark the section the symbol we need comes from as used. */ |
| if (shndx != SHN_UNDEF |
| && (shndx < SHN_LORESERVE || shndx > SHN_HIRESERVE)) |
| { |
| struct scninfo *ignore; |
| |
| #ifndef NDEBUG |
| size_t shnum; |
| assert (elf_getshnum (fileinfo->elf, &shnum) == 0); |
| assert (shndx < shnum); |
| #endif |
| |
| /* Mark section (and all dependencies) as used. */ |
| mark_section_used (&fileinfo->scninfo[shndx], shndx, &ignore); |
| |
| /* Check whether the section is merge-able. In this case we |
| have to record the symbol. */ |
| if (SCNINFO_SHDR (fileinfo->scninfo[shndx].shdr).sh_flags |
| & SHF_MERGE) |
| { |
| if (fileinfo->scninfo[shndx].symbols == NULL) |
| fileinfo->scninfo[shndx].symbols = newp->next_in_scn |
| = newp; |
| else |
| { |
| newp->next_in_scn |
| = fileinfo->scninfo[shndx].symbols->next_in_scn; |
| fileinfo->scninfo[shndx].symbols |
| = fileinfo->scninfo[shndx].symbols->next_in_scn = newp; |
| } |
| } |
| } |
| } |
| |
| /* This file is used. */ |
| if (likely (fileinfo->file_type == relocatable_file_type)) |
| { |
| if (unlikely (ld_state.relfiles == NULL)) |
| ld_state.relfiles = fileinfo->next = fileinfo; |
| else |
| { |
| fileinfo->next = ld_state.relfiles->next; |
| ld_state.relfiles = ld_state.relfiles->next = fileinfo; |
| } |
| |
| /* Update some summary information in the state structure. */ |
| ld_state.nsymtab += fileinfo->nsymtab; |
| ld_state.nlocalsymbols += fileinfo->nlocalsymbols; |
| } |
| else if (likely (fileinfo->file_type == dso_file_type)) |
| { |
| CSNGL_LIST_ADD_REAR (ld_state.dsofiles, fileinfo); |
| ++ld_state.ndsofiles; |
| |
| if (fileinfo->lazyload) |
| /* We have to create another dynamic section entry for the |
| DT_POSFLAG_1 entry. |
| |
| XXX Once more functionality than the lazyloading flag |
| are suppported the test must be extended. */ |
| ++ld_state.ndsofiles; |
| } |
| } |
| |
| return 0; |
| } |
| |
| |
| int |
| ld_handle_filename_list (struct filename_list *fnames) |
| { |
| struct filename_list *runp; |
| int res = 0; |
| |
| for (runp = fnames; runp != NULL; runp = runp->next) |
| { |
| struct usedfiles *curp; |
| |
| /* Create a record for the new file. */ |
| curp = runp->real = ld_new_inputfile (runp->name, relocatable_file_type); |
| |
| /* Set flags for group handling. */ |
| runp->real->group_start = runp->group_start; |
| runp->real->group_end = runp->group_end; |
| |
| /* Read the file and everything else which comes up, including |
| handling groups. */ |
| do |
| res |= FILE_PROCESS (-1, curp, &ld_state, &curp); |
| while (curp != NULL); |
| } |
| |
| /* Free the list. */ |
| while (fnames != NULL) |
| { |
| runp = fnames; |
| fnames = fnames->next; |
| free (runp); |
| } |
| |
| return res; |
| } |
| |
| |
| /* Handle opening of the given file with ELF descriptor. */ |
| static int |
| open_elf (struct usedfiles *fileinfo, Elf *elf) |
| { |
| int res = 0; |
| |
| if (elf == NULL) |
| error (EXIT_FAILURE, 0, |
| gettext ("cannot get descriptor for ELF file (%s:%d): %s\n"), |
| __FILE__, __LINE__, elf_errmsg (-1)); |
| |
| if (unlikely (elf_kind (elf) == ELF_K_NONE)) |
| { |
| struct filename_list *fnames; |
| |
| /* We don't have to look at this file again. */ |
| fileinfo->status = closed; |
| |
| /* Let's see whether this is a linker script. */ |
| if (fileinfo->fd != -1) |
| /* Create a stream from the file handle we know. */ |
| ldin = fdopen (fileinfo->fd, "r"); |
| else |
| { |
| /* Get the memory for the archive member. */ |
| char *content; |
| size_t contentsize; |
| |
| /* Get the content of the file. */ |
| content = elf_rawfile (elf, &contentsize); |
| if (content == NULL) |
| { |
| fprintf (stderr, gettext ("%s: invalid ELF file (%s:%d)\n"), |
| fileinfo->rfname, __FILE__, __LINE__); |
| return 1; |
| } |
| |
| /* The content of the file is available in memory. Read the |
| memory region as a stream. */ |
| ldin = fmemopen (content, contentsize, "r"); |
| } |
| |
| /* No need for locking. */ |
| __fsetlocking (ldin, FSETLOCKING_BYCALLER); |
| |
| if (ldin == NULL) |
| error (EXIT_FAILURE, errno, gettext ("cannot open \"%s\""), |
| fileinfo->rfname); |
| |
| /* Parse the file. If it is a linker script no problems will be |
| reported. */ |
| ld_state.srcfiles = NULL; |
| ldlineno = 1; |
| ld_scan_version_script = 0; |
| ldin_fname = fileinfo->rfname; |
| res = ldparse (); |
| |
| fclose (ldin); |
| if (fileinfo->fd != -1 && !fileinfo->fd_passed) |
| { |
| /* We won't need the file descriptor again. */ |
| close (fileinfo->fd); |
| fileinfo->fd = -1; |
| } |
| |
| elf_end (elf); |
| |
| if (unlikely (res != 0)) |
| /* Something went wrong during parsing. */ |
| return 1; |
| |
| /* This is no ELF file. */ |
| fileinfo->elf = NULL; |
| |
| /* Now we have to handle eventual INPUT and GROUP statements in |
| the script. Read the files mentioned. */ |
| fnames = ld_state.srcfiles; |
| if (fnames != NULL) |
| { |
| struct filename_list *oldp; |
| |
| /* Convert the list into a normal single-linked list. */ |
| oldp = fnames; |
| fnames = fnames->next; |
| oldp->next = NULL; |
| |
| /* Remove the list from the state structure. */ |
| ld_state.srcfiles = NULL; |
| |
| if (unlikely (ld_handle_filename_list (fnames) != 0)) |
| return 1; |
| } |
| |
| return 0; |
| } |
| |
| /* Store the file info. */ |
| fileinfo->elf = elf; |
| |
| /* The file is ready for action. */ |
| fileinfo->status = opened; |
| |
| return 0; |
| } |
| |
| |
| static int |
| add_whole_archive (struct usedfiles *fileinfo) |
| { |
| Elf *arelf; |
| Elf_Cmd cmd = ELF_C_READ_MMAP_PRIVATE; |
| int res = 0; |
| |
| while ((arelf = elf_begin (fileinfo->fd, cmd, fileinfo->elf)) != NULL) |
| { |
| Elf_Arhdr *arhdr = elf_getarhdr (arelf); |
| struct usedfiles *newp; |
| |
| if (arhdr == NULL) |
| abort (); |
| |
| /* Just to be sure; since these are no files in the archive |
| these names should never be returned. */ |
| assert (strcmp (arhdr->ar_name, "/") != 0); |
| assert (strcmp (arhdr->ar_name, "//") != 0); |
| |
| newp = ld_new_inputfile (arhdr->ar_name, relocatable_file_type); |
| newp->archive_file = fileinfo; |
| |
| if (unlikely (ld_state.trace_files)) |
| print_file_name (stdout, newp, 1, 1); |
| |
| /* This shows that this file is contained in an archive. */ |
| newp->fd = -1; |
| /* Store the ELF descriptor. */ |
| newp->elf = arelf; |
| /* Show that we are open for business. */ |
| newp->status = opened; |
| |
| /* Proces the file, add all the symbols etc. */ |
| res = file_process2 (newp); |
| if (unlikely (res != 0)) |
| break; |
| |
| /* Advance to the next archive element. */ |
| cmd = elf_next (arelf); |
| } |
| |
| return res; |
| } |
| |
| |
| static int |
| extract_from_archive (struct usedfiles *fileinfo) |
| { |
| static int archive_seq; |
| int res = 0; |
| |
| /* This is an archive we are not using completely. Give it a |
| unique number. */ |
| fileinfo->archive_seq = ++archive_seq; |
| |
| /* If there are no unresolved symbols don't do anything. */ |
| if ((likely (ld_state.extract_rule == defaultextract) |
| && ld_state.nunresolved_nonweak == 0) |
| || (unlikely (ld_state.extract_rule == weakextract) |
| && ld_state.nunresolved == 0)) |
| return 0; |
| |
| Elf_Arsym *syms; |
| size_t nsyms; |
| |
| /* Get all the symbols. */ |
| syms = elf_getarsym (fileinfo->elf, &nsyms); |
| if (syms == NULL) |
| { |
| cannot_read_archive: |
| error (0, 0, gettext ("cannot read archive `%s': %s"), |
| fileinfo->rfname, elf_errmsg (-1)); |
| |
| /* We cannot use this archive anymore. */ |
| fileinfo->status = closed; |
| |
| return 1; |
| } |
| |
| /* Now add all the symbols to the hash table. Note that there |
| can potentially be duplicate definitions. We'll always use |
| the first definition. */ |
| // XXX Is this a compatible behavior? |
| bool any_used; |
| int nround = 0; |
| do |
| { |
| any_used = false; |
| |
| size_t cnt; |
| for (cnt = 0; cnt < nsyms; ++cnt) |
| { |
| struct symbol search = { .name = syms[cnt].as_name }; |
| struct symbol *sym = ld_symbol_tab_find (&ld_state.symbol_tab, |
| syms[cnt].as_hash, &search); |
| if (sym != NULL && ! sym->defined) |
| { |
| /* The symbol is referenced and not defined. */ |
| Elf *arelf; |
| Elf_Arhdr *arhdr; |
| struct usedfiles *newp; |
| |
| /* Find the archive member for this symbol. */ |
| if (unlikely (elf_rand (fileinfo->elf, syms[cnt].as_off) |
| != syms[cnt].as_off)) |
| goto cannot_read_archive; |
| |
| /* Note: no test of a failing 'elf_begin' call. That's fine |
| since 'elf'getarhdr' will report the problem. */ |
| arelf = elf_begin (fileinfo->fd, ELF_C_READ_MMAP_PRIVATE, |
| fileinfo->elf); |
| arhdr = elf_getarhdr (arelf); |
| if (arhdr == NULL) |
| goto cannot_read_archive; |
| |
| /* We have all the information and an ELF handle for the |
| archive member. Create the normal data structure for |
| a file now. */ |
| newp = ld_new_inputfile (obstack_strdup (&ld_state.smem, |
| arhdr->ar_name), |
| relocatable_file_type); |
| newp->archive_file = fileinfo; |
| |
| if (unlikely (ld_state.trace_files)) |
| print_file_name (stdout, newp, 1, 1); |
| |
| /* This shows that this file is contained in an archive. */ |
| newp->fd = -1; |
| /* Store the ELF descriptor. */ |
| newp->elf = arelf; |
| /* Show that we are open for business. */ |
| newp->status = in_archive; |
| |
| /* Now read the file and add all the symbols. */ |
| res = file_process2 (newp); |
| if (unlikely (res != 0)) |
| return res; |
| |
| any_used = true; |
| } |
| } |
| |
| if (++nround == 1) |
| { |
| /* This is an archive therefore it must have a number. */ |
| assert (fileinfo->archive_seq != 0); |
| ld_state.last_archive_used = fileinfo->archive_seq; |
| } |
| } |
| while (any_used); |
| |
| return res; |
| } |
| |
| |
| static int |
| file_process2 (struct usedfiles *fileinfo) |
| { |
| int res; |
| |
| if (likely (elf_kind (fileinfo->elf) == ELF_K_ELF)) |
| { |
| /* The first time we get here we read the ELF header. */ |
| #if NATIVE_ELF != 0 |
| if (likely (fileinfo->ehdr == NULL)) |
| #else |
| if (likely (FILEINFO_EHDR (fileinfo->ehdr).e_type == ET_NONE)) |
| #endif |
| { |
| XElf_Ehdr *ehdr; |
| #if NATIVE_ELF != 0 |
| ehdr = xelf_getehdr (fileinfo->elf, fileinfo->ehdr); |
| #else |
| xelf_getehdr_copy (fileinfo->elf, ehdr, fileinfo->ehdr); |
| #endif |
| if (ehdr == NULL) |
| { |
| fprintf (stderr, gettext ("%s: invalid ELF file (%s:%d)\n"), |
| fileinfo->rfname, __FILE__, __LINE__); |
| fileinfo->status = closed; |
| return 1; |
| } |
| |
| if (FILEINFO_EHDR (fileinfo->ehdr).e_type != ET_REL |
| && unlikely (FILEINFO_EHDR (fileinfo->ehdr).e_type != ET_DYN)) |
| /* XXX Add ebl* function to query types which are allowed |
| to link in. */ |
| { |
| char buf[64]; |
| |
| print_file_name (stderr, fileinfo, 1, 0); |
| fprintf (stderr, |
| gettext ("file of type %s cannot be linked in\n"), |
| ebl_object_type_name (ld_state.ebl, |
| FILEINFO_EHDR (fileinfo->ehdr).e_type, |
| buf, sizeof (buf))); |
| fileinfo->status = closed; |
| return 1; |
| } |
| |
| /* Determine the section header string table section index. */ |
| if (unlikely (elf_getshstrndx (fileinfo->elf, &fileinfo->shstrndx) |
| < 0)) |
| { |
| fprintf (stderr, gettext ("\ |
| %s: cannot get section header string table index: %s\n"), |
| fileinfo->rfname, elf_errmsg (-1)); |
| fileinfo->status = closed; |
| return 1; |
| } |
| } |
| |
| /* Now handle the different types of files. */ |
| if (FILEINFO_EHDR (fileinfo->ehdr).e_type == ET_REL) |
| { |
| /* Add all the symbol. Relocatable files have symbol |
| tables. */ |
| res = add_relocatable_file (fileinfo, SHT_SYMTAB); |
| } |
| else |
| { |
| bool has_l_name = fileinfo->file_type == archive_file_type; |
| |
| assert (FILEINFO_EHDR (fileinfo->ehdr).e_type == ET_DYN); |
| |
| /* If the file is a DT_NEEDED dependency then the type is |
| already correctly specified. */ |
| if (fileinfo->file_type != dso_needed_file_type) |
| fileinfo->file_type = dso_file_type; |
| |
| /* We cannot use DSOs when generating relocatable objects. */ |
| if (ld_state.file_type == relocatable_file_type) |
| { |
| error (0, 0, gettext ("\ |
| cannot use DSO '%s' when generating relocatable object file"), |
| fileinfo->fname); |
| return 1; |
| } |
| |
| /* Add all the symbols. For DSOs we are looking at the |
| dynamic symbol table. */ |
| res = add_relocatable_file (fileinfo, SHT_DYNSYM); |
| |
| /* We always have to have a dynamic section. */ |
| assert (fileinfo->dynscn != NULL); |
| |
| /* We have to remember the dependencies for this object. It |
| is necessary to look them up. */ |
| XElf_Shdr_vardef (dynshdr); |
| xelf_getshdr (fileinfo->dynscn, dynshdr); |
| |
| Elf_Data *dyndata = elf_getdata (fileinfo->dynscn, NULL); |
| /* XXX Should we flag the failure to get the dynamic section? */ |
| if (dynshdr != NULL) |
| { |
| int cnt = dynshdr->sh_size / dynshdr->sh_entsize; |
| XElf_Dyn_vardef (dyn); |
| |
| while (--cnt >= 0) |
| { |
| xelf_getdyn (dyndata, cnt, dyn); |
| if (dyn != NULL) |
| { |
| if(dyn->d_tag == DT_NEEDED) |
| { |
| struct usedfiles *newp; |
| |
| newp = ld_new_inputfile (elf_strptr (fileinfo->elf, |
| dynshdr->sh_link, |
| dyn->d_un.d_val), |
| dso_needed_file_type); |
| |
| /* Enqueue the newly found dependencies. */ |
| // XXX Check that there not already a file with the |
| // same name. |
| CSNGL_LIST_ADD_REAR (ld_state.needed, newp); |
| } |
| else if (dyn->d_tag == DT_SONAME) |
| { |
| /* We use the DT_SONAME (this is what's there |
| for). */ |
| fileinfo->soname = elf_strptr (fileinfo->elf, |
| dynshdr->sh_link, |
| dyn->d_un.d_val); |
| has_l_name = false; |
| } |
| } |
| } |
| } |
| |
| /* Construct the file name if the DSO has no SONAME and the |
| file name comes from a -lXX parameter on the comment |
| line. */ |
| if (unlikely (has_l_name)) |
| { |
| /* The FNAME is the parameter the user specified on the |
| command line. We prepend "lib" and append ".so". */ |
| size_t len = strlen (fileinfo->fname) + 7; |
| char *newp; |
| |
| newp = (char *) obstack_alloc (&ld_state.smem, len); |
| strcpy (stpcpy (stpcpy (newp, "lib"), fileinfo->fname), ".so"); |
| |
| fileinfo->soname = newp; |
| } |
| } |
| } |
| else if (likely (elf_kind (fileinfo->elf) == ELF_K_AR)) |
| { |
| if (unlikely (ld_state.extract_rule == allextract)) |
| /* Which this option enabled we have to add all the object |
| files in the archive. */ |
| res = add_whole_archive (fileinfo); |
| else if (ld_state.file_type == relocatable_file_type) |
| { |
| /* When generating a relocatable object we don't find files |
| in archives. */ |
| if (verbose) |
| error (0, 0, gettext ("input file '%s' ignored"), fileinfo->fname); |
| |
| res = 0; |
| } |
| else |
| /* Extract only the members from the archive which are |
| currently referenced by unresolved symbols. */ |
| res = extract_from_archive (fileinfo); |
| } |
| else |
| /* This should never happen, we know about no other types. */ |
| abort (); |
| |
| return res; |
| } |
| |
| |
| /* Process a given file. The first parameter is a file descriptor for |
| the file which can be -1 to indicate the file has not yet been |
| found. The second parameter describes the file to be opened, the |
| last one is the state of the linker which among other information |
| contain the paths we look at. */ |
| static int |
| ld_generic_file_process (int fd, struct usedfiles *fileinfo, |
| struct ld_state *statep, struct usedfiles **nextp) |
| { |
| int res = 0; |
| |
| /* By default we go to the next file in the list. */ |
| *nextp = fileinfo->next; |
| |
| /* Set the flag to signal we are looking for a group start. */ |
| if (unlikely (fileinfo->group_start)) |
| { |
| ld_state.group_start_requested = true; |
| fileinfo->group_start = false; |
| } |
| |
| /* If the file isn't open yet, open it now. */ |
| if (likely (fileinfo->status == not_opened)) |
| { |
| bool fd_passed = true; |
| |
| if (likely (fd == -1)) |
| { |
| /* Find the file ourselves. */ |
| int err = open_along_path (fileinfo); |
| if (unlikely (err != 0)) |
| /* We allow libraries and DSOs to be named more than once. |
| Don't report an error to the caller. */ |
| return err == EAGAIN ? 0 : err; |
| |
| fd_passed = false; |
| } |
| else |
| fileinfo->fd = fd; |
| |
| /* Remember where we got the descriptor from. */ |
| fileinfo->fd_passed = fd_passed; |
| |
| /* We found the file. Now test whether it is a file type we can |
| handle. |
| |
| XXX Do we have to have the ability to start from a given |
| position in the search path again to look for another file if |
| the one found has not the right type? */ |
| res = open_elf (fileinfo, elf_begin (fileinfo->fd, |
| is_dso_p (fileinfo->fd) |
| ? ELF_C_READ_MMAP |
| : ELF_C_READ_MMAP_PRIVATE, NULL)); |
| if (unlikely (res != 0)) |
| return res; |
| } |
| |
| /* Now that we have opened the file start processing it. */ |
| if (likely (fileinfo->status != closed)) |
| res = file_process2 (fileinfo); |
| |
| /* Determine which file to look at next. */ |
| if (unlikely (fileinfo->group_backref != NULL)) |
| { |
| /* We only go back if an archive other than the one we would go |
| back to has been used in the last round. */ |
| if (ld_state.last_archive_used > fileinfo->group_backref->archive_seq) |
| { |
| *nextp = fileinfo->group_backref; |
| ld_state.last_archive_used = 0; |
| } |
| else |
| { |
| /* If we come here this means that the archives we read so |
| far are not needed anymore. We can free some of the data |
| now. */ |
| struct usedfiles *runp = ld_state.archives; |
| |
| do |
| { |
| /* We don't need the ELF descriptor anymore. Unless there |
| are no files from the archive used this will not free |
| the whole file but only some data structures. */ |
| elf_end (runp->elf); |
| runp->elf = NULL; |
| |
| runp = runp->next; |
| } |
| while (runp != fileinfo->next); |
| } |
| } |
| else if (unlikely (fileinfo->group_end)) |
| { |
| /* This is the end of a group. We possibly of to go back. |
| Determine which file we would go back to and see whether it |
| makes sense. If there has not been an archive we don't have |
| to do anything. */ |
| if (!ld_state.group_start_requested) |
| { |
| if (ld_state.group_start_archive != ld_state.tailarchives) |
| /* The loop would include more than one archive, add the |
| pointer. */ |
| { |
| *nextp = ld_state.tailarchives->group_backref = |
| ld_state.group_start_archive; |
| ld_state.last_archive_used = 0; |
| } |
| else |
| /* We might still have to go back to the beginning of the |
| group if since the last archive other files have been |
| added. But we go back exactly once. */ |
| if (ld_state.tailarchives != fileinfo) |
| { |
| *nextp = ld_state.group_start_archive; |
| ld_state.last_archive_used = 0; |
| } |
| } |
| |
| /* Clear the flags. */ |
| ld_state.group_start_requested = false; |
| fileinfo->group_end = false; |
| } |
| |
| return res; |
| } |
| |
| |
| /* Library names passed to the linker as -lXX represent files named |
| libXX.YY. The YY part can have different forms, depending on the |
| platform. The generic set is .so and .a (in this order). */ |
| static const char ** |
| ld_generic_lib_extensions (struct ld_state *statep __attribute__ ((__unused__))) |
| { |
| static const char *exts[] = |
| { |
| ".so", ".a", NULL |
| }; |
| |
| return exts; |
| } |
| |
| |
| /* Flag unresolved symbols. */ |
| static int |
| ld_generic_flag_unresolved (struct ld_state *statep) |
| { |
| int retval = 0; |
| |
| if (ld_state.nunresolved_nonweak > 0) |
| { |
| /* Go through the list and determine the unresolved symbols. */ |
| struct symbol *first; |
| struct symbol *s; |
| |
| s = first = ld_state.unresolved->next; |
| do |
| { |
| if (! s->defined && ! s->weak) |
| { |
| /* Two special symbol we recognize: the symbol for the |
| GOT and the dynamic section. */ |
| if (strcmp (s->name, "_GLOBAL_OFFSET_TABLE_") == 0 |
| || strcmp (s->name, "_DYNAMIC") == 0) |
| { |
| /* We will have to fill in more information later. */ |
| ld_state.need_got = true; |
| |
| /* Remember that we found it. */ |
| if (s->name[1] == 'G') |
| ld_state.got_symbol = s; |
| else |
| ld_state.dyn_symbol = s; |
| } |
| else if (ld_state.file_type != dso_file_type || !ld_state.nodefs) |
| { |
| /* XXX The error message should get better. It should use |
| the debugging information if present to tell where in the |
| sources the undefined reference is. */ |
| error (0, 0, gettext ("undefined symbol `%s' in %s"), |
| s->name, s->file->fname); |
| |
| retval = 1; |
| } |
| } |
| |
| /* We cannot decide here what to do with undefined |
| references which will come from DSO since we do not know |
| what kind of symbol we expect. Only when looking at the |
| relocations we can see whether we need a PLT entry or |
| only a GOT entry. */ |
| |
| s = s->next; |
| } |
| while (s != first); |
| } |
| |
| return retval; |
| } |
| |
| |
| /* Close the given file. */ |
| static int |
| ld_generic_file_close (struct usedfiles *fileinfo, struct ld_state *statep) |
| { |
| /* Close the ELF descriptor. */ |
| elf_end (fileinfo->elf); |
| |
| /* If we have opened the file descriptor close it. But we might |
| have done this already in which case FD is -1. */ |
| if (!fileinfo->fd_passed && fileinfo->fd != -1) |
| close (fileinfo->fd); |
| |
| /* We allocated the resolved file name. */ |
| if (fileinfo->fname != fileinfo->rfname) |
| free ((char *) fileinfo->rfname); |
| |
| return 0; |
| } |
| |
| |
| static void |
| new_generated_scn (enum scn_kind kind, const char *name, int type, int flags, |
| int entsize, int align) |
| { |
| struct scnhead *newp; |
| |
| newp = (struct scnhead *) obstack_calloc (&ld_state.smem, |
| sizeof (struct scnhead)); |
| newp->kind = kind; |
| newp->name = name; |
| newp->nameent = ebl_strtabadd (ld_state.shstrtab, name, 0); |
| newp->type = type; |
| newp->flags = flags; |
| newp->entsize = entsize; |
| newp->align = align; |
| newp->grp_signature = NULL; |
| newp->used = true; |
| |
| /* All is well. Create now the data for the section and insert it |
| into the section table. */ |
| ld_section_tab_insert (&ld_state.section_tab, elf_hash (name), newp); |
| } |
| |
| |
| /* Create the sections which are generated by the linker and are not |
| present in the input file. */ |
| static void |
| ld_generic_generate_sections (struct ld_state *statep) |
| { |
| /* The relocation section type. */ |
| int rel_type = REL_TYPE (&ld_state) == DT_REL ? SHT_REL : SHT_RELA; |
| |
| /* When building dynamically linked object we have to include a |
| section containing a string describing the interpreter. This |
| should be at the very beginning of the file together with the |
| other information the ELF loader (kernel or wherever) has to look |
| at. We put it as the first section in the file. |
| |
| We also have to create the dynamic segment which is a special |
| section the dynamic linker locates through an entry in the |
| program header. */ |
| if (dynamically_linked_p ()) |
| { |
| int ndt_needed; |
| /* Use any versioning (defined or required)? */ |
| bool use_versioning = false; |
| /* Use version requirements? */ |
| bool need_version = false; |
| |
| /* First the .interp section. */ |
| new_generated_scn (scn_dot_interp, ".interp", SHT_PROGBITS, SHF_ALLOC, |
| 0, 1); |
| |
| /* Now the .dynamic section. */ |
| new_generated_scn (scn_dot_dynamic, ".dynamic", SHT_DYNAMIC, |
| DYNAMIC_SECTION_FLAGS (&ld_state), |
| xelf_fsize (ld_state.outelf, ELF_T_DYN, 1), |
| xelf_fsize (ld_state.outelf, ELF_T_ADDR, 1)); |
| |
| /* We will need in any case the dynamic symbol table (even in |
| the unlikely case that no symbol is exported or referenced |
| from a DSO). */ |
| ld_state.need_dynsym = true; |
| new_generated_scn (scn_dot_dynsym, ".dynsym", SHT_DYNSYM, SHF_ALLOC, |
| xelf_fsize (ld_state.outelf, ELF_T_SYM, 1), |
| xelf_fsize (ld_state.outelf, ELF_T_ADDR, 1)); |
| /* It comes with a string table. */ |
| new_generated_scn (scn_dot_dynstr, ".dynstr", SHT_STRTAB, SHF_ALLOC, |
| 0, 1); |
| /* And a hashing table. */ |
| // XXX For Linux/Alpha we need other sizes unless they change... |
| new_generated_scn (scn_dot_hash, ".hash", SHT_HASH, SHF_ALLOC, |
| sizeof (Elf32_Word), sizeof (Elf32_Word)); |
| |
| /* By default we add all DSOs provided on the command line. If |
| the user added '-z ignore' to the command line we only add |
| those which are actually used. */ |
| ndt_needed = ld_state.ignore_unused_dsos ? 0 : ld_state.ndsofiles; |
| |
| /* Create the section associated with the PLT if necessary. */ |
| if (ld_state.nplt > 0) |
| { |
| /* Create the .plt section. */ |
| /* XXX We might need a function which returns the section flags. */ |
| new_generated_scn (scn_dot_plt, ".plt", SHT_PROGBITS, |
| SHF_ALLOC | SHF_EXECINSTR, |
| /* XXX Is the size correct? */ |
| xelf_fsize (ld_state.outelf, ELF_T_ADDR, 1), |
| xelf_fsize (ld_state.outelf, ELF_T_ADDR, 1)); |
| |
| /* Create the relocation section for the .plt. This is always |
| separate even if the other relocation sections are combined. */ |
| new_generated_scn (scn_dot_pltrel, ".rel.plt", rel_type, SHF_ALLOC, |
| rel_type == SHT_REL |
| ? xelf_fsize (ld_state.outelf, ELF_T_REL, 1) |
| : xelf_fsize (ld_state.outelf, ELF_T_RELA, 1), |
| xelf_fsize (ld_state.outelf, ELF_T_ADDR, 1)); |
| |
| /* This means we will also need the .got section. */ |
| ld_state.need_got = true; |
| |
| /* Mark all used DSOs as used. Determine whether any referenced |
| object uses symbol versioning. */ |
| if (ld_state.from_dso != NULL) |
| { |
| struct symbol *srunp = ld_state.from_dso; |
| |
| do |
| { |
| srunp->file->used = true; |
| |
| if (srunp->file->verdefdata != NULL) |
| { |
| XElf_Versym versym; |
| |
| /* The input DSO uses versioning. */ |
| use_versioning = true; |
| /* We reference versions. */ |
| need_version = true; |
| |
| if (xelf_getversym_copy (srunp->file->versymdata, |
| srunp->symidx, versym) == NULL) |
| assert (! "xelf_getversym failed"); |
| |
| /* We cannot link explicitly with an older |
| version of a symbol. */ |
| assert ((versym & 0x8000) == 0); |
| /* We cannot reference local (index 0) or plain |
| global (index 1) versions. */ |
| assert (versym > 1); |
| |
| /* Check whether we have already seen the |
| version and if not add it to the referenced |
| versions in the output file. */ |
| if (! srunp->file->verdefused[versym]) |
| { |
| srunp->file->verdefused[versym] = 1; |
| |
| if (++srunp->file->nverdefused == 1) |
| /* Count the file if it is using versioning. */ |
| ++ld_state.nverdeffile; |
| ++ld_state.nverdefused; |
| } |
| } |
| } |
| while ((srunp = srunp->next) != ld_state.from_dso); |
| } |
| |
| /* Create the sections used to record version dependencies. */ |
| if (need_version) |
| new_generated_scn (scn_dot_version_r, ".gnu.version_r", |
| SHT_GNU_verneed, SHF_ALLOC, 0, |
| xelf_fsize (ld_state.outelf, ELF_T_WORD, 1)); |
| |
| /* Now count the used DSOs since this is what the user |
| wants. */ |
| ndt_needed = 0; |
| if (ld_state.ndsofiles > 0) |
| { |
| struct usedfiles *frunp = ld_state.dsofiles; |
| |
| do |
| if (! ld_state.ignore_unused_dsos || frunp->used) |
| { |
| ++ndt_needed; |
| if (frunp->lazyload) |
| /* We have to create another dynamic section |
| entry for the DT_POSFLAG_1 entry. |
| |
| XXX Once more functionality than the |
| lazyloading flag are suppported the test |
| must be extended. */ |
| ++ndt_needed; |
| } |
| while ((frunp = frunp->next) != ld_state.dsofiles); |
| } |
| } |
| |
| if (use_versioning) |
| new_generated_scn (scn_dot_version, ".gnu.version", SHT_GNU_versym, |
| SHF_ALLOC, |
| xelf_fsize (ld_state.outelf, ELF_T_HALF, 1), |
| xelf_fsize (ld_state.outelf, ELF_T_HALF, 1)); |
| |
| /* We need some entries all the time. */ |
| ld_state.ndynamic = (7 + (ld_state.runpath != NULL |
| || ld_state.rpath != NULL) |
| + ndt_needed |
| + (ld_state.init_symbol != NULL ? 1 : 0) |
| + (ld_state.fini_symbol != NULL ? 1 : 0) |
| + (use_versioning ? 1 : 0) |
| + (need_version ? 2 : 0) |
| + (ld_state.nplt > 0 ? 4 : 0) |
| + (ld_state.relsize_total > 0 ? 3 : 0)); |
| } |
| |
| /* When creating a relocatable file or when we are not stripping the |
| output file we create a symbol table. */ |
| ld_state.need_symtab = (ld_state.file_type == relocatable_file_type |
| || ld_state.strip == strip_none); |
| |
| /* Add the .got section if needed. */ |
| if (ld_state.need_got) |
| /* XXX We might need a function which returns the section flags. */ |
| new_generated_scn (scn_dot_got, ".got", SHT_PROGBITS, |
| SHF_ALLOC | SHF_WRITE, |
| xelf_fsize (ld_state.outelf, ELF_T_ADDR, 1), |
| xelf_fsize (ld_state.outelf, ELF_T_ADDR, 1)); |
| |
| /* Add the .rel.dyn section. */ |
| if (ld_state.relsize_total > 0) |
| new_generated_scn (scn_dot_dynrel, ".rel.dyn", rel_type, SHF_ALLOC, |
| rel_type == SHT_REL |
| ? xelf_fsize (ld_state.outelf, ELF_T_REL, 1) |
| : xelf_fsize (ld_state.outelf, ELF_T_RELA, 1), |
| xelf_fsize (ld_state.outelf, ELF_T_ADDR, 1)); |
| } |
| |
| |
| /* Callback function registered with on_exit to make sure the temporary |
| files gets removed if something goes wrong. */ |
| static void |
| remove_tempfile (int status, void *arg) |
| { |
| if (status != 0 && ld_state.tempfname != NULL) |
| unlink (ld_state.tempfname); |
| } |
| |
| |
| /* Create the output file. The file name is given or "a.out". We |
| create as much of the ELF structure as possible. */ |
| static int |
| ld_generic_open_outfile (struct ld_state *statep, int machine, int klass, |
| int data) |
| { |
| /* We do not create the new file right away with the final name. |
| This would destroy an existing file with this name before a |
| replacement is finalized. We create instead a temporary file in |
| the same directory. */ |
| if (ld_state.outfname == NULL) |
| ld_state.outfname = "a.out"; |
| |
| size_t outfname_len = strlen (ld_state.outfname); |
| char *tempfname = (char *) obstack_alloc (&ld_state.smem, |
| outfname_len + sizeof (".XXXXXX")); |
| ld_state.tempfname = tempfname; |
| |
| int fd; |
| int try = 0; |
| while (1) |
| { |
| strcpy (mempcpy (tempfname, ld_state.outfname, outfname_len), ".XXXXXX"); |
| |
| /* The useof mktemp() here is fine. We do not want to use |
| mkstemp() since then the umask isn't used. And the output |
| file will have these permissions anyhow. Any intruder could |
| change the file later if it would be possible now. */ |
| if (mktemp (tempfname) != NULL |
| && (fd = open (tempfname, O_RDWR | O_EXCL | O_CREAT | O_NOFOLLOW, |
| ld_state.file_type == relocatable_file_type |
| ? DEFFILEMODE : ACCESSPERMS)) != -1) |
| break; |
| |
| /* Failed this round. We keep trying a number of times. */ |
| if (++try >= 10) |
| error (EXIT_FAILURE, errno, gettext ("cannot create output file")); |
| } |
| ld_state.outfd = fd; |
| |
| /* Make sure we remove the temporary file in case something goes |
| wrong. */ |
| on_exit (remove_tempfile, NULL); |
| |
| /* Create the ELF file data for the output file. */ |
| Elf *elf = ld_state.outelf = elf_begin (fd, |
| conserve_memory |
| ? ELF_C_WRITE : ELF_C_WRITE_MMAP, |
| NULL); |
| if (elf == NULL) |
| error (EXIT_FAILURE, 0, |
| gettext ("cannot create ELF descriptor for output file: %s"), |
| elf_errmsg (-1)); |
| |
| /* Create the basic data structures. */ |
| if (! xelf_newehdr (elf, klass)) |
| /* Couldn't create the ELF header. Very bad. */ |
| error (EXIT_FAILURE, 0, |
| gettext ("could not create ELF header for output file: %s"), |
| elf_errmsg (-1)); |
| |
| /* And get the current header so that we can modify it. */ |
| XElf_Ehdr_vardef (ehdr); |
| xelf_getehdr (elf, ehdr); |
| assert (ehdr != NULL); |
| |
| /* Set the machine type. */ |
| ehdr->e_machine = machine; |
| |
| /* Modify it according to the info we have here and now. */ |
| if (ld_state.file_type == executable_file_type) |
| ehdr->e_type = ET_EXEC; |
| else if (ld_state.file_type == dso_file_type) |
| ehdr->e_type = ET_DYN; |
| else |
| { |
| assert (ld_state.file_type == relocatable_file_type); |
| ehdr->e_type = ET_REL; |
| } |
| |
| /* Set the ELF version. */ |
| ehdr->e_version = EV_CURRENT; |
| |
| /* Set the endianness. */ |
| ehdr->e_ident[EI_DATA] = data; |
| |
| /* Write the ELF header information back. */ |
| (void) xelf_update_ehdr (elf, ehdr); |
| |
| return 0; |
| } |
| |
| |
| /* We compute the offsets of the various copied objects and the total |
| size of the memory needed. */ |
| // XXX The method used here is simple: go from front to back and pack |
| // the objects in this order. A more space efficient way would |
| // actually trying to pack the objects as dense as possible. But this |
| // is more expensive. |
| static void |
| compute_copy_reloc_offset (XElf_Shdr *shdr) |
| { |
| struct symbol *runp = ld_state.from_dso; |
| assert (runp != NULL); |
| |
| XElf_Off maxalign = 1; |
| XElf_Off offset = 0; |
| |
| do |
| if (runp->need_copy) |
| { |
| /* Determine alignment for the symbol. */ |
| // XXX The question is how? The symbol record itself does not |
| // have the information. So we have to be conservative and |
| // assume the alignment of the section the symbol is in. |
| |
| // XXX We can be more precise. Use the offset from the beginning |
| // of the section and determine the largest power of two with |
| // module zero. |
| XElf_Off symalign = MAX (SCNINFO_SHDR (runp->file->scninfo[runp->scndx].shdr).sh_addralign, 1); |
| /* Keep track of the maximum alignment requirement. */ |
| maxalign = MAX (maxalign, symalign); |
| |
| /* Align current position. */ |
| offset = (offset + symalign - 1) & ~(symalign - 1); |
| |
| runp->merge.value = offset; |
| |
| offset += runp->size; |
| } |
| while ((runp = runp->next) != ld_state.from_dso); |
| |
| shdr->sh_type = SHT_NOBITS; |
| shdr->sh_size = offset; |
| shdr->sh_addralign = maxalign; |
| } |
| |
| |
| static void |
| compute_common_symbol_offset (XElf_Shdr *shdr) |
| { |
| struct symbol *runp = ld_state.common_syms; |
| assert (runp != NULL); |
| |
| XElf_Off maxalign = 1; |
| XElf_Off offset = 0; |
| |
| do |
| { |
| /* Determine alignment for the symbol. */ |
| XElf_Off symalign = runp->merge.value; |
| |
| /* Keep track of the maximum alignment requirement. */ |
| maxalign = MAX (maxalign, symalign); |
| |
| /* Align current position. */ |
| offset = (offset + symalign - 1) & ~(symalign - 1); |
| |
| runp->merge.value = offset; |
| |
| offset += runp->size; |
| } |
| while ((runp = runp->next) != ld_state.common_syms); |
| |
| shdr->sh_type = SHT_NOBITS; |
| shdr->sh_size = offset; |
| shdr->sh_addralign = maxalign; |
| } |
| |
| |
| static void |
| sort_sections_generic (void) |
| { |
| /* XXX TBI */ |
| abort (); |
| } |
| |
| |
| static int |
| match_section (const char *osectname, struct filemask_section_name *sectmask, |
| struct scnhead **scnhead, bool new_section, size_t segment_nr) |
| { |
| struct scninfo *prevp; |
| struct scninfo *runp; |
| struct scninfo *notused; |
| |
| if (fnmatch (sectmask->section_name->name, (*scnhead)->name, 0) != 0) |
| /* The section name does not match. */ |
| return new_section; |
| |
| /* If this is a section generated by the linker it doesn't contain |
| the regular information (i.e., input section data etc) and must |
| be handle special. */ |
| if ((*scnhead)->kind != scn_normal) |
| { |
| (*scnhead)->name = osectname; |
| (*scnhead)->segment_nr = segment_nr; |
| |
| /* We have to count note section since they get their own |
| program header entry. */ |
| if ((*scnhead)->type == SHT_NOTE) |
| ++ld_state.nnotesections; |
| |
| ld_state.allsections[ld_state.nallsections++] = (*scnhead); |
| return true; |
| } |
| |
| /* Now we have to match the file names of the input files. Some of |
| the sections here might not match. */ |
| runp = (*scnhead)->last->next; |
| prevp = (*scnhead)->last; |
| notused = NULL; |
| |
| do |
| { |
| /* Base of the file name the section comes from. */ |
| const char *brfname = basename (runp->fileinfo->rfname); |
| |
| /* If the section isn't used, the name doesn't match the positive |
| inclusion list or the name does match the negative inclusion |
| list, ignore the section. */ |
| if (!runp->used |
| || (sectmask->filemask != NULL |
| && fnmatch (sectmask->filemask, brfname, 0) != 0) |
| || (sectmask->excludemask != NULL |
| && fnmatch (sectmask->excludemask, brfname, 0) == 0)) |
| { |
| /* This file does not match the file name masks. */ |
| if (notused == NULL) |
| notused = runp; |
| |
| prevp = runp; |
| runp = runp->next; |
| if (runp == notused) |
| runp = NULL; |
| } |
| /* The section fulfills all requirements, add it to the output |
| file with the correct section name etc. */ |
| else |
| { |
| struct scninfo *found = runp; |
| |
| /* Remove this input section data buffer from the list. */ |
| if (prevp != runp) |
| runp = prevp->next = runp->next; |
| else |
| { |
| free (*scnhead); |
| *scnhead = NULL; |
| runp = NULL; |
| } |
| |
| /* Create a new section for the output file if the 'new_section' |
| flag says so. Otherwise append the buffer to the last |
| section which we created in one of the last calls. */ |
| if (new_section) |
| { |
| struct scnhead *newp; |
| |
| newp = (struct scnhead *) obstack_calloc (&ld_state.smem, |
| sizeof (*newp)); |
| newp->kind = scn_normal; |
| newp->name = osectname; |
| newp->type = SCNINFO_SHDR (found->shdr).sh_type; |
| newp->flags = SCNINFO_SHDR (found->shdr).sh_flags; |
| newp->segment_nr = segment_nr; |
| newp->last = found->next = found; |
| newp->used = true; |
| newp->relsize = found->relsize; |
| newp->entsize = SCNINFO_SHDR (found->shdr).sh_entsize; |
| |
| /* We have to count note section since they get their own |
| program header entry. */ |
| if (newp->type == SHT_NOTE) |
| ++ld_state.nnotesections; |
| |
| ld_state.allsections[ld_state.nallsections++] = newp; |
| new_section = false; |
| } |
| else |
| { |
| struct scnhead *queued; |
| |
| queued = ld_state.allsections[ld_state.nallsections - 1]; |
| |
| found->next = queued->last->next; |
| queued->last = queued->last->next = found; |
| |
| /* If the linker script forces us to add incompatible |
| sections together do so. But reflect this in the |
| type and flags of the resulting file. */ |
| if (queued->type != SCNINFO_SHDR (found->shdr).sh_type) |
| /* XXX Any better choice? */ |
| queued->type = SHT_PROGBITS; |
| if (queued->flags != SCNINFO_SHDR (found->shdr).sh_flags) |
| queued->flags = ebl_sh_flags_combine (ld_state.ebl, |
| queued->flags, |
| SCNINFO_SHDR (found->shdr).sh_flags); |
| |
| /* Accumulate the relocation section size. */ |
| queued->relsize += found->relsize; |
| } |
| } |
| } |
| while (runp != NULL); |
| |
| return new_section; |
| } |
| |
| |
| static void |
| sort_sections_lscript (void) |
| { |
| struct scnhead *temp[ld_state.nallsections]; |
| |
| /* Make a copy of the section head pointer array. */ |
| memcpy (temp, ld_state.allsections, |
| ld_state.nallsections * sizeof (temp[0])); |
| size_t nallsections = ld_state.nallsections; |
| |
| /* Convert the output segment list in a single-linked list. */ |
| struct output_segment *segment = ld_state.output_segments->next; |
| ld_state.output_segments->next = NULL; |
| ld_state.output_segments = segment; |
| |
| /* Put the sections in the correct order in the array in the state |
| structure. This might involve merging of sections and also |
| renaming the containing section in the output file. */ |
| ld_state.nallsections = 0; |
| size_t segment_nr; |
| size_t last_writable = ~0ul; |
| for (segment_nr = 0; segment != NULL; segment = segment->next, ++segment_nr) |
| { |
| struct output_rule *orule; |
| |
| for (orule = segment->output_rules; orule != NULL; orule = orule->next) |
| if (orule->tag == output_section) |
| { |
| struct input_rule *irule; |
| bool new_section = true; |
| |
| for (irule = orule->val.section.input; irule != NULL; |
| irule = irule->next) |
| if (irule->tag == input_section) |
| { |
| size_t cnt; |
| |
| for (cnt = 0; cnt < nallsections; ++cnt) |
| if (temp[cnt] != NULL) |
| new_section = |
| match_section (orule->val.section.name, |
| irule->val.section, &temp[cnt], |
| new_section, segment_nr); |
| } |
| } |
| |
| if ((segment->mode & PF_W) != 0) |
| last_writable = ld_state.nallsections - 1; |
| } |
| |
| /* In case we have to create copy relocations or we have common |
| symbols, find the last writable segment and add one more data |
| block. It will be a NOBITS block and take up no disk space. |
| This is why it is important to get the last block. */ |
| if (ld_state.ncopy > 0 || ld_state.common_syms != NULL) |
| { |
| if (last_writable == ~0ul) |
| error (EXIT_FAILURE, 0, "no writable segment"); |
| |
| if (ld_state.allsections[last_writable]->type != SHT_NOBITS) |
| { |
| /* Make room in the ALLSECTIONS array for a new section. |
| There is guaranteed room in the array. We add the new |
| entry after the last writable section. */ |
| ++last_writable; |
| memmove (&ld_state.allsections[last_writable + 1], |
| &ld_state.allsections[last_writable], |
| (ld_state.nallsections - last_writable) |
| * sizeof (ld_state.allsections[0])); |
| |
| ld_state.allsections[last_writable] = (struct scnhead *) |
| obstack_calloc (&ld_state.smem, sizeof (struct scnhead)); |
| |
| /* Name for the new section. */ |
| ld_state.allsections[last_writable]->name = ".bss"; |
| /* Type: NOBITS. */ |
| ld_state.allsections[last_writable]->type = SHT_NOBITS; |
| /* Same segment as the last writable section. */ |
| ld_state.allsections[last_writable]->segment_nr |
| = ld_state.allsections[last_writable - 1]->segment_nr; |
| } |
| } |
| |
| /* Create common symbol data block. */ |
| if (ld_state.ncopy > 0) |
| { |
| #if NATIVE_ELF |
| struct scninfo *si = (struct scninfo *) |
| obstack_calloc (&ld_state.smem, sizeof (*si) + sizeof (XElf_Shdr)); |
| si->shdr = (XElf_Shdr *) (si + 1); |
| #else |
| struct scninfo *si = (struct scninfo *) obstack_calloc (&ld_state.smem, |
| sizeof (*si)); |
| #endif |
| |
| /* Get the information regarding the symbols with copy relocations. */ |
| compute_copy_reloc_offset (&SCNINFO_SHDR (si->shdr)); |
| |
| /* This section is needed. */ |
| si->used = true; |
| /* Remember for later the section data structure. */ |
| ld_state.copy_section = si; |
| |
| if (likely (ld_state.allsections[last_writable]->last != NULL)) |
| { |
| si->next = ld_state.allsections[last_writable]->last->next; |
| ld_state.allsections[last_writable]->last->next = si; |
| ld_state.allsections[last_writable]->last = si; |
| } |
| else |
| ld_state.allsections[last_writable]->last = si->next = si; |
| } |
| |
| /* Create common symbol data block. */ |
| if (ld_state.common_syms != NULL) |
| { |
| #if NATIVE_ELF |
| struct scninfo *si = (struct scninfo *) |
| obstack_calloc (&ld_state.smem, sizeof (*si) + sizeof (XElf_Shdr)); |
| si->shdr = (XElf_Shdr *) (si + 1); |
| #else |
| struct scninfo *si = (struct scninfo *) obstack_calloc (&ld_state.smem, |
| sizeof (*si)); |
| #endif |
| |
| /* Get the information regarding the symbols with copy relocations. */ |
| compute_common_symbol_offset (&SCNINFO_SHDR (si->shdr)); |
| |
| /* This section is needed. */ |
| si->used = true; |
| /* Remember for later the section data structure. */ |
| ld_state.common_section = si; |
| |
| if (likely (ld_state.allsections[last_writable]->last != NULL)) |
| { |
| si->next = ld_state.allsections[last_writable]->last->next; |
| ld_state.allsections[last_writable]->last->next = si; |
| ld_state.allsections[last_writable]->last = si; |
| } |
| else |
| ld_state.allsections[last_writable]->last = si->next = si; |
| } |
| } |
| |
| |
| /* Create the output sections now. This requires knowledge about all |
| the sections we will need. It may be necessary to sort sections in |
| the order they are supposed to appear in the executable. The |
| sorting use many different kinds of information to optimize the |
| resulting binary. Important is to respect segment boundaries and |
| the needed alignment. The mode of the segments will be determined |
| afterwards automatically by the output routines. |
| |
| The generic sorting routines work in one of two possible ways: |
| |
| - if a linker script specifies the sections to be used in the |
| output and assigns them to a segment this information is used; |
| |
| - otherwise the linker will order the sections based on permissions |
| and some special knowledge about section names.*/ |
| static void |
| ld_generic_create_sections (struct ld_state *statep) |
| { |
| struct scngroup *groups; |
| size_t cnt; |
| |
| /* For relocatable object we don't have to bother sorting the |
| sections and we do want to preserve the relocation sections as |
| they appear in the input files. */ |
| if (ld_state.file_type != relocatable_file_type) |
| { |
| /* Collect all the relocation sections. They are handled |
| separately. */ |
| struct scninfo *list = NULL; |
| for (cnt = 0; cnt < ld_state.nallsections; ++cnt) |
| if ((ld_state.allsections[cnt]->type == SHT_REL |
| || ld_state.allsections[cnt]->type == SHT_RELA) |
| /* The generated relocation sections are not of any |
| interest here. */ |
| && ld_state.allsections[cnt]->last != NULL) |
| { |
| if (list == NULL) |
| list = ld_state.allsections[cnt]->last; |
| else |
| { |
| /* Merge the sections list. */ |
| struct scninfo *first = list->next; |
| list->next = ld_state.allsections[cnt]->last->next; |
| ld_state.allsections[cnt]->last->next = first; |
| list = ld_state.allsections[cnt]->last; |
| } |
| |
| /* Remove the entry from the section list. */ |
| ld_state.allsections[cnt] = NULL; |
| } |
| ld_state.rellist = list; |
| |
| if (ld_state.output_segments == NULL) |
| /* Sort using builtin rules. */ |
| sort_sections_generic (); |
| else |
| sort_sections_lscript (); |
| } |
| |
| /* Now iterate over the input sections and create the sections in the |
| order they are required in the output file. */ |
| for (cnt = 0; cnt < ld_state.nallsections; ++cnt) |
| { |
| struct scnhead *head = ld_state.allsections[cnt]; |
| Elf_Scn *scn; |
| XElf_Shdr_vardef (shdr); |
| |
| /* Don't handle unused sections. */ |
| if (!head->used) |
| continue; |
| |
| /* We first have to create the section group if necessary. |
| Section group sections must come (in section index order) |
| before any of the section contained. This all is necessary |
| only for relocatable object as other object types are not |
| allowed to contain section groups. */ |
| if (ld_state.file_type == relocatable_file_type |
| && unlikely (head->flags & SHF_GROUP)) |
| { |
| /* There is at least one section which is contained in a |
| section group in the input file. This means we must |
| create a section group here as well. The only problem is |
| that not all input files have to have to same kind of |
| partitioning of the sections. I.e., sections A and B in |
| one input file and sections B and C in another input file |
| can be in one group. That will result in a group |
| containing the sections A, B, and C in the output |
| file. */ |
| struct scninfo *runp; |
| Elf32_Word here_groupidx = 0; |
| struct scngroup *here_group; |
| struct member *newp; |
| |
| /* First check whether any section is already in a group. |
| In this case we have to add this output section, too. */ |
| runp = head->last; |
| do |
| { |
| assert (runp->grpid != 0); |
| |
| here_groupidx = runp->fileinfo->scninfo[runp->grpid].outscnndx; |
| if (here_groupidx != 0) |
| break; |
| } |
| while ((runp = runp->next) != head->last); |
| |
| if (here_groupidx == 0) |
| { |
| /* We need a new section group section. */ |
| scn = elf_newscn (ld_state.outelf); |
| xelf_getshdr (scn, shdr); |
| if (shdr == NULL) |
| error (EXIT_FAILURE, 0, |
| gettext ("cannot create section for output file: %s"), |
| elf_errmsg (-1)); |
| |
| here_group = (struct scngroup *) xmalloc (sizeof (*here_group)); |
| here_group->outscnidx = here_groupidx = elf_ndxscn (scn); |
| here_group->nscns = 0; |
| here_group->member = NULL; |
| here_group->next = ld_state.groups; |
| /* Pick a name for the section. To keep it meaningful |
| we use a name used in the input files. If the |
| section group in the output file should contain |
| section which were in section groups of different |
| names in the input files this is the users |
| problem. */ |
| here_group->nameent |
| = ebl_strtabadd (ld_state.shstrtab, |
| elf_strptr (runp->fileinfo->elf, |
| runp->fileinfo->shstrndx, |
| SCNINFO_SHDR (runp->shdr).sh_name), |
| 0); |
| /* Signature symbol. */ |
| here_group->symbol |
| = runp->fileinfo->scninfo[runp->grpid].symbols; |
| |
| ld_state.groups = here_group; |
| } |
| else |
| { |
| /* Search for the group with this index. */ |
| here_group = ld_state.groups; |
| while (here_group->outscnidx != here_groupidx) |
| here_group = here_group->next; |
| } |
| |
| /* Add the new output section. */ |
| newp = (struct member *) alloca (sizeof (*newp)); |
| newp->scn = head; |
| #ifndef NDT_NEEDED |
| newp->next = NULL; |
| #endif |
| CSNGL_LIST_ADD_REAR (here_group->member, newp); |
| ++here_group->nscns; |
| |
| /* Store the section group index in all input files. */ |
| runp = head->last; |
| do |
| { |
| assert (runp->grpid != 0); |
| |
| if (runp->fileinfo->scninfo[runp->grpid].outscnndx == 0) |
| runp->fileinfo->scninfo[runp->grpid].outscnndx = here_groupidx; |
| else |
| assert (runp->fileinfo->scninfo[runp->grpid].outscnndx |
| == here_groupidx); |
| } |
| while ((runp = runp->next) != head->last); |
| } |
| |
| /* We'll use this section so get it's name in the section header |
| string table. */ |
| if (head->kind == scn_normal) |
| head->nameent = ebl_strtabadd (ld_state.shstrtab, head->name, 0); |
| |
| /* Create a new section in the output file and add all data |
| from all the sections we read. */ |
| scn = elf_newscn (ld_state.outelf); |
| head->scnidx = elf_ndxscn (scn); |
| xelf_getshdr (scn, shdr); |
| if (shdr == NULL) |
| error (EXIT_FAILURE, 0, |
| gettext ("cannot create section for output file: %s"), |
| elf_errmsg (-1)); |
| |
| assert (head->type != SHT_NULL); |
| assert (head->type != SHT_SYMTAB); |
| assert (head->type != SHT_DYNSYM || head->kind != scn_normal); |
| assert (head->type != SHT_STRTAB || head->kind != scn_normal); |
| assert (head->type != SHT_GROUP); |
| shdr->sh_type = head->type; |
| shdr->sh_flags = head->flags; |
| shdr->sh_addralign = head->align; |
| shdr->sh_entsize = head->entsize; |
| assert (shdr->sh_entsize != 0 || (shdr->sh_flags & SHF_MERGE) == 0); |
| (void) xelf_update_shdr (scn, shdr); |
| |
| /* We have to know the section index of the dynamic symbol table |
| right away. */ |
| if (head->kind == scn_dot_dynsym) |
| ld_state.dynsymscnidx = elf_ndxscn (scn); |
| } |
| |
| /* Actually create the section group sections. */ |
| groups = ld_state.groups; |
| while (groups != NULL) |
| { |
| Elf_Scn *scn; |
| Elf_Data *data; |
| Elf32_Word *grpdata; |
| struct member *runp; |
| |
| scn = elf_getscn (ld_state.outelf, groups->outscnidx); |
| assert (scn != NULL); |
| |
| data = elf_newdata (scn); |
| if (data == NULL) |
| error (EXIT_FAILURE, 0, |
| gettext ("cannot create section for output file: %s"), |
| elf_errmsg (-1)); |
| |
| data->d_size = (groups->nscns + 1) * sizeof (Elf32_Word); |
| data->d_buf = grpdata = (Elf32_Word *) xmalloc (data->d_size); |
| data->d_type = ELF_T_WORD; |
| data->d_version = EV_CURRENT; |
| data->d_off = 0; |
| /* XXX What better to use? */ |
| data->d_align = sizeof (Elf32_Word); |
| |
| /* The first word in the section is the flag word. */ |
| /* XXX Set COMDATA flag is necessary. */ |
| grpdata[0] = 0; |
| |
| runp = groups->member->next; |
| cnt = 1; |
| do |
| /* Fill in the index of the section. */ |
| grpdata[cnt++] = runp->scn->scnidx; |
| while ((runp = runp->next) != groups->member->next); |
| |
| groups = groups->next; |
| } |
| } |
| |
| |
| static bool |
| reduce_symbol_p (XElf_Sym *sym, struct Ebl_Strent *strent) |
| { |
| const char *str; |
| const char *version; |
| struct id_list search; |
| struct id_list *verp; |
| bool result = ld_state.default_bind_local; |
| |
| if (XELF_ST_BIND (sym->st_info) == STB_LOCAL || sym->st_shndx == SHN_UNDEF) |
| /* We don't have to do anything to local symbols here. */ |
| /* XXX Any section value in [SHN_LORESERVER,SHN_XINDEX) need |
| special treatment? */ |
| return false; |
| |
| /* XXX Handle other symbol bindings. */ |
| assert (XELF_ST_BIND (sym->st_info) == STB_GLOBAL |
| || XELF_ST_BIND (sym->st_info) == STB_WEAK); |
| |
| str = ebl_string (strent); |
| version = strchr (str, VER_CHR); |
| if (version != NULL) |
| { |
| search.id = strndupa (str, version - str); |
| if (*++version == VER_CHR) |
| /* Skip the second '@' signalling a default definition. */ |
| ++version; |
| } |
| else |
| { |
| search.id = str; |
| version = ""; |
| } |
| |
| verp = ld_version_str_tab_find (&ld_state.version_str_tab, |
| elf_hash (search.id), &search); |
| while (verp != NULL) |
| { |
| /* We have this symbol in the version hash table. Now match the |
| version name. */ |
| if (strcmp (verp->u.s.versionname, version) == 0) |
| /* Match! */ |
| return verp->u.s.local; |
| |
| verp = verp->next; |
| } |
| |
| /* XXX Add test for wildcard version symbols. */ |
| |
| return result; |
| } |
| |
| |
| static XElf_Addr |
| eval_expression (struct expression *expr, XElf_Addr addr) |
| { |
| XElf_Addr val = ~((XElf_Addr) 0); |
| |
| switch (expr->tag) |
| { |
| case exp_num: |
| val = expr->val.num; |
| break; |
| |
| case exp_sizeof_headers: |
| { |
| /* The 'elf_update' call determine the offset of the first |
| section. The the size of the header. */ |
| XElf_Shdr_vardef (shdr); |
| |
| xelf_getshdr (elf_getscn (ld_state.outelf, 1), shdr); |
| assert (shdr != NULL); |
| |
| val = shdr->sh_offset; |
| } |
| break; |
| |
| case exp_pagesize: |
| val = ld_state.pagesize; |
| break; |
| |
| case exp_id: |
| /* We are here computing only address expressions. It seems not |
| to be necessary to handle any variable but ".". Let's avoid |
| the complication. If it turns up to be needed we can add |
| it. */ |
| if (strcmp (expr->val.str, ".") != 0) |
| error (EXIT_FAILURE, 0, gettext ("\ |
| address computation expression contains variable '%s'"), |
| expr->val.str); |
| |
| val = addr; |
| break; |
| |
| case exp_mult: |
| val = (eval_expression (expr->val.binary.left, addr) |
| * eval_expression (expr->val.binary.right, addr)); |
| break; |
| |
| case exp_div: |
| val = (eval_expression (expr->val.binary.left, addr) |
| / eval_expression (expr->val.binary.right, addr)); |
| break; |
| |
| case exp_mod: |
| val = (eval_expression (expr->val.binary.left, addr) |
| % eval_expression (expr->val.binary.right, addr)); |
| break; |
| |
| case exp_plus: |
| val = (eval_expression (expr->val.binary.left, addr) |
| + eval_expression (expr->val.binary.right, addr)); |
| break; |
| |
| case exp_minus: |
| val = (eval_expression (expr->val.binary.left, addr) |
| - eval_expression (expr->val.binary.right, addr)); |
| break; |
| |
| case exp_and: |
| val = (eval_expression (expr->val.binary.left, addr) |
| & eval_expression (expr->val.binary.right, addr)); |
| break; |
| |
| case exp_or: |
| val = (eval_expression (expr->val.binary.left, addr) |
| | eval_expression (expr->val.binary.right, addr)); |
| break; |
| |
| case exp_align: |
| val = eval_expression (expr->val.child, addr); |
| if ((val & (val - 1)) != 0) |
| error (EXIT_FAILURE, 0, gettext ("argument '%" PRIuMAX "' of ALIGN in address computation expression is no power of two"), |
| (uintmax_t) val); |
| val = (addr + val - 1) & ~(val - 1); |
| break; |
| } |
| |
| return val; |
| } |
| |
| |
| /* Find a good as possible size for the hash table so that all the |
| non-zero entries in HASHCODES don't collide too much and the table |
| isn't too large. There is no exact formular for this so we use a |
| heuristic. Depending on the optimization level the search is |
| longer or shorter. */ |
| static size_t |
| optimal_bucket_size (Elf32_Word *hashcodes, size_t maxcnt, int optlevel) |
| { |
| size_t minsize; |
| size_t maxsize; |
| size_t bestsize; |
| uint64_t bestcost; |
| size_t size; |
| uint32_t *counts; |
| uint32_t *lengths; |
| |
| if (maxcnt == 0) |
| return 0; |
| |
| /* When we are not optimizing we run only very few tests. */ |
| if (optlevel <= 0) |
| { |
| minsize = maxcnt; |
| maxsize = maxcnt + 10000 / maxcnt; |
| } |
| else |
| { |
| /* Does not make much sense to start with a smaller table than |
| one which has at least four collisions. */ |
| minsize = MAX (1, maxcnt / 4); |
| /* We look for a best fit in the range of up to eigth times the |
| number of elements. */ |
| maxsize = 2 * maxcnt + (6 * MIN (optlevel, 100) * maxcnt) / 100; |
| } |
| bestsize = maxcnt; |
| bestcost = UINT_MAX; |
| |
| /* Array for counting the collisions and chain lengths. */ |
| counts = (uint32_t *) xmalloc ((maxcnt + 1 + maxsize) * sizeof (uint32_t)); |
| lengths = &counts[maxcnt + 1]; |
| |
| for (size = minsize; size <= maxsize; ++size) |
| { |
| size_t inner; |
| uint64_t cost; |
| uint32_t maxlength; |
| uint64_t success; |
| uint32_t acc; |
| double factor; |
| |
| memset (lengths, '\0', size * sizeof (uint32_t)); |
| memset (counts, '\0', (maxcnt + 1) * sizeof (uint32_t)); |
| |
| /* Determine how often each hash bucket is used. */ |
| for (inner = 0; inner < maxcnt; ++inner) |
| ++lengths[hashcodes[inner] % size]; |
| |
| /* Determine the lengths. */ |
| maxlength = 0; |
| for (inner = 0; inner < size; ++inner) |
| { |
| ++counts[lengths[inner]]; |
| |
| if (lengths[inner] > maxlength) |
| maxlength = lengths[inner]; |
| } |
| |
| /* Determine successful lookup length. */ |
| acc = 0; |
| success = 0; |
| for (inner = 0; inner <= maxlength; ++inner) |
| { |
| acc += inner; |
| success += counts[inner] * acc; |
| } |
| |
| /* We can compute two factors now: the average length of a |
| positive search and the average length of a negative search. |
| We count the number of comparisons which have to look at the |
| names themselves. Recognizing that the chain ended is not |
| accounted for since it's almost for free. |
| |
| Which lookup is more important depends on the kind of DSO. |
| If it is a system DSO like libc it is expected that most |
| lookups succeed. Otherwise most lookups fail. */ |
| if (ld_state.is_system_library) |
| factor = (1.0 * (double) success / (double) maxcnt |
| + 0.3 * (double) maxcnt / (double) size); |
| else |
| factor = (0.3 * (double) success / (double) maxcnt |
| + 1.0 * (double) maxcnt / (double) size); |
| |
| /* Combine the lookup cost factor. The 1/16th addend adds |
| penalties for too large table sizes. */ |
| cost = (2 + maxcnt + size) * (factor + 1.0 / 16.0); |
| |
| #if 0 |
| printf ("maxcnt = %d, size = %d, cost = %Ld, success = %g, fail = %g, factor = %g\n", |
| maxcnt, size, cost, (double) success / (double) maxcnt, (double) maxcnt / (double) size, factor); |
| #endif |
| |
| /* Compare with current best results. */ |
| if (cost < bestcost) |
| { |
| bestcost = cost; |
| bestsize = size; |
| } |
| } |
| |
| free (counts); |
| |
| return bestsize; |
| } |
| |
| |
| static XElf_Addr |
| find_entry_point (void) |
| { |
| XElf_Addr result; |
| |
| if (ld_state.entry != NULL) |
| { |
| struct symbol search = { .name = ld_state.entry }; |
| struct symbol *syment; |
| |
| syment = ld_symbol_tab_find (&ld_state.symbol_tab, |
| elf_hash (ld_state.entry), &search); |
| if (syment != NULL && syment->defined) |
| { |
| /* We found the symbol. */ |
| Elf_Data *data = elf_getdata (elf_getscn (ld_state.outelf, |
| ld_state.symscnidx), NULL); |
| |
| XElf_Sym_vardef (sym); |
| |
| sym = NULL; |
| if (data != NULL) |
| xelf_getsym (data, ld_state.dblindirect[syment->outsymidx], sym); |
| |
| if (sym == NULL && ld_state.need_dynsym && syment->outdynsymidx != 0) |
| { |
| /* Use the dynamic symbol table if available. */ |
| data = elf_getdata (elf_getscn (ld_state.outelf, |
| ld_state.dynsymscnidx), NULL); |
| |
| sym = NULL; |
| if (data != NULL) |
| xelf_getsym (data, syment->outdynsymidx, sym); |
| } |
| |
| if (sym != NULL) |
| return sym->st_value; |
| |
| /* XXX What to do if the output has no non-dynamic symbol |
| table and the dynamic symbol table does not contain the |
| symbol? */ |
| assert (ld_state.need_symtab); |
| assert (ld_state.symscnidx != 0); |
| } |
| } |
| |
| /* We couldn't find the symbol or none was given. Use the first |
| address of the ".text" section then. */ |
| |
| |
| result = 0; |
| |
| /* In DSOs this is no fatal error. They usually have no entry |
| points. In this case we set the entry point to zero, which makes |
| sure it will always fail. */ |
| if (ld_state.file_type == executable_file_type) |
| { |
| if (ld_state.entry != NULL) |
| error (0, 0, gettext ("\ |
| cannot find entry symbol \"%s\": defaulting to %#0*" PRIx64), |
| ld_state.entry, |
| xelf_getclass (ld_state.outelf) == ELFCLASS32 ? 10 : 18, |
| (uint64_t) result); |
| else |
| error (0, 0, gettext ("\ |
| no entry symbol specified: defaulting to %#0*" PRIx64), |
| xelf_getclass (ld_state.outelf) == ELFCLASS32 ? 10 : 18, |
| (uint64_t) result); |
| } |
| |
| return result; |
| } |
| |
| |
| static void |
| fillin_special_symbol (struct symbol *symst, size_t scnidx, size_t nsym, |
| Elf_Data *symdata, struct Ebl_Strtab *strtab) |
| { |
| assert (ld_state.file_type != relocatable_file_type); |
| |
| XElf_Sym_vardef (sym); |
| xelf_getsym_ptr (symdata, nsym, sym); |
| |
| /* The name offset will be filled in later. */ |
| sym->st_name = 0; |
| /* Traditionally: globally visible. */ |
| sym->st_info = XELF_ST_INFO (STB_GLOBAL, symst->type); |
| /* No special visibility or so. */ |
| sym->st_other = 0; |
| /* Reference to the GOT or dynamic section. Since the GOT and |
| dynamic section are only created for executables and DSOs it |
| cannot be that the section index is too large. */ |
| assert (scnidx != 0); |
| assert (scnidx < SHN_LORESERVE || scnidx == SHN_ABS); |
| sym->st_shndx = scnidx; |
| /* We want the beginning of the section. */ |
| sym->st_value = 0; |
| |
| /* Determine the size of the section. */ |
| if (scnidx != SHN_ABS) |
| { |
| Elf_Data *data = elf_getdata (elf_getscn (ld_state.outelf, scnidx), |
| NULL); |
| assert (data != NULL); |
| sym->st_size = data->d_size; |
| /* Make sure there is no second data block. */ |
| assert (elf_getdata (elf_getscn (ld_state.outelf, scnidx), data) |
| == NULL); |
| } |
| |
| /* Insert symbol into the symbol table. Note that we do not have to |
| use xelf_update_symshdx. */ |
| (void) xelf_update_sym (symdata, nsym, sym); |
| |
| /* Cross-references. */ |
| ndxtosym[nsym] = symst; |
| symst->outsymidx = nsym; |
| |
| /* Add the name to the string table. */ |
| symstrent[nsym] = ebl_strtabadd (strtab, symst->name, 0); |
| } |
| |
| |
| static void |
| new_dynamic_entry (Elf_Data *data, int idx, XElf_Sxword tag, XElf_Addr val) |
| { |
| XElf_Dyn_vardef (dyn); |
| xelf_getdyn_ptr (data, idx, dyn); |
| dyn->d_tag = tag; |
| dyn->d_un.d_ptr = val; |
| (void) xelf_update_dyn (data, idx, dyn); |
| } |
| |
| |
| static void |
| allocate_version_names (struct usedfiles *runp, struct Ebl_Strtab *dynstrtab) |
| { |
| /* If this DSO has no versions skip it. */ |
| if (runp->status != opened || runp->verdefdata == NULL) |
| return; |
| |
| /* Add the object name. */ |
| int offset = 0; |
| while (1) |
| { |
| XElf_Verdef_vardef (def); |
| XElf_Verdaux_vardef (aux); |
| |
| /* Get data at the next offset. */ |
| xelf_getverdef (runp->verdefdata, offset, def); |
| assert (def != NULL); |
| xelf_getverdaux (runp->verdefdata, offset + def->vd_aux, aux); |
| assert (aux != NULL); |
| |
| assert (def->vd_ndx <= runp->nverdef); |
| if (def->vd_ndx == 1 || runp->verdefused[def->vd_ndx] != 0) |
| { |
| runp->verdefent[def->vd_ndx] |
| = ebl_strtabadd (dynstrtab, elf_strptr (runp->elf, |
| runp->dynsymstridx, |
| aux->vda_name), 0); |
| |
| if (def->vd_ndx > 1) |
| runp->verdefused[def->vd_ndx] = ld_state.nextveridx++; |
| } |
| |
| if (def->vd_next == 0) |
| /* That were all versions. */ |
| break; |
| |
| offset += def->vd_next; |
| } |
| } |
| |
| |
| XElf_Off |
| create_verneed_data (XElf_Off offset, Elf_Data *verneeddata, |
| struct usedfiles *runp, int *ntotal) |
| { |
| size_t verneed_size = xelf_fsize (ld_state.outelf, ELF_T_VNEED, 1); |
| size_t vernaux_size = xelf_fsize (ld_state.outelf, ELF_T_VNAUX, 1); |
| int need_offset; |
| bool filled = false; |
| GElf_Verneed verneed; |
| GElf_Vernaux vernaux; |
| int ndef = 0; |
| size_t cnt; |
| |
| /* If this DSO has no versions skip it. */ |
| if (runp->nverdefused == 0) |
| return offset; |
| |
| /* We fill in the Verneed record last. Remember the |
| offset. */ |
| need_offset = offset; |
| offset += verneed_size; |
| |
| for (cnt = 2; cnt <= runp->nverdef; ++cnt) |
| if (runp->verdefused[cnt] != 0) |
| { |
| assert (runp->verdefent[cnt] != NULL); |
| |
| if (filled) |
| { |
| vernaux.vna_next = vernaux_size; |
| (void) gelf_update_vernaux (verneeddata, offset, |
| &vernaux); |
| offset += vernaux_size; |
| } |
| |
| vernaux.vna_hash |
| = elf_hash (ebl_string (runp->verdefent[cnt])); |
| vernaux.vna_flags = 0; |
| vernaux.vna_other = runp->verdefused[cnt]; |
| vernaux.vna_name = ebl_strtaboffset (runp->verdefent[cnt]); |
| filled = true; |
| ++ndef; |
| } |
| |
| assert (filled); |
| vernaux.vna_next = 0; |
| (void) gelf_update_vernaux (verneeddata, offset, &vernaux); |
| offset += vernaux_size; |
| |
| verneed.vn_version = VER_NEED_CURRENT; |
| verneed.vn_cnt = ndef; |
| verneed.vn_file = ebl_strtaboffset (runp->verdefent[1]); |
| /* The first auxiliary entry is always found directly |
| after the verneed entry. */ |
| verneed.vn_aux = verneed_size; |
| verneed.vn_next = --*ntotal > 0 ? offset - need_offset : 0; |
| (void) gelf_update_verneed (verneeddata, need_offset, |
| &verneed); |
| |
| return offset; |
| } |
| |
| |
| /* Create the output file. |
| |
| For relocatable files what basically has to happen is that all |
| sections from all input files are written into the output file. |
| Sections with the same name are combined (offsets adjusted |
| accordingly). The symbol tables are combined in one single table. |
| When stripping certain symbol table entries are omitted. |
| |
| For executables (shared or not) we have to create the program header, |
| additional sections like the .interp, eventually (in addition) create |
| a dynamic symbol table and a dynamic section. Also the relocations |
| have to be processed differently. */ |
| static int |
| ld_generic_create_outfile (struct ld_state *statep) |
| { |
| struct scnlist |
| { |
| size_t scnidx; |
| struct scninfo *scninfo; |
| struct scnlist *next; |
| }; |
| struct scnlist *rellist = NULL; |
| size_t cnt; |
| Elf_Scn *symscn = NULL; |
| Elf_Scn *xndxscn = NULL; |
| Elf_Scn *strscn = NULL; |
| struct Ebl_Strtab *strtab = NULL; |
| struct Ebl_Strtab *dynstrtab = NULL; |
| XElf_Shdr_vardef (shdr); |
| Elf_Data *data; |
| Elf_Data *symdata = NULL; |
| Elf_Data *xndxdata = NULL; |
| struct usedfiles *file; |
| size_t nsym; |
| size_t nsym_local; |
| size_t nsym_allocated; |
| size_t nsym_dyn = 0; |
| Elf32_Word *dblindirect = NULL; |
| #ifndef NDEBUG |
| bool need_xndx; |
| #endif |
| Elf_Scn *shstrtab_scn; |
| size_t shstrtab_ndx; |
| XElf_Ehdr_vardef (ehdr); |
| struct Ebl_Strent *symtab_ent = NULL; |
| struct Ebl_Strent *xndx_ent = NULL; |
| struct Ebl_Strent *strtab_ent = NULL; |
| struct Ebl_Strent *shstrtab_ent; |
| struct scngroup *groups; |
| Elf_Scn *dynsymscn = NULL; |
| Elf_Data *dynsymdata = NULL; |
| Elf_Data *dynstrdata = NULL; |
| Elf32_Word *hashcodes = NULL; |
| size_t nsym_dyn_allocated = 0; |
| Elf_Scn *versymscn = NULL; |
| Elf_Data *versymdata = NULL; |
| |
| if (ld_state.need_symtab) |
| { |
| /* First create the symbol table. We need the symbol section itself |
| and the string table for it. */ |
| symscn = elf_newscn (ld_state.outelf); |
| ld_state.symscnidx = elf_ndxscn (symscn); |
| symdata = elf_newdata (symscn); |
| if (symdata == NULL) |
| error (EXIT_FAILURE, 0, |
| gettext ("cannot create symbol table for output file: %s"), |
| elf_errmsg (-1)); |
| |
| symdata->d_type = ELF_T_SYM; |
| /* This is an estimated size, but it will definitely cap the real value. |
| We might have to adjust the number later. */ |
| nsym_allocated = (1 + ld_state.nsymtab + ld_state.nplt + ld_state.ngot |
| + ld_state.nusedsections + ld_state.nlscript_syms); |
| symdata->d_size = xelf_fsize (ld_state.outelf, ELF_T_SYM, |
| nsym_allocated); |
| |
| /* Optionally the extended section table. */ |
| /* XXX Is SHN_LORESERVE correct? Do we need some other sections? */ |
| if (unlikely (ld_state.nusedsections >= SHN_LORESERVE)) |
| { |
| xndxscn = elf_newscn (ld_state.outelf); |
| ld_state.xndxscnidx = elf_ndxscn (xndxscn); |
| |
| xndxdata = elf_newdata (xndxscn); |
| if (xndxdata == NULL) |
| error (EXIT_FAILURE, 0, |
| gettext ("cannot create symbol table for output file: %s"), |
| elf_errmsg (-1)); |
| |
| /* The following relies on the fact that Elf32_Word and Elf64_Word |
| have the same size. */ |
| xndxdata->d_type = ELF_T_WORD; |
| /* This is an estimated size, but it will definitely cap the |
| real value. we might have to adjust the number later. */ |
| xndxdata->d_size = xelf_fsize (ld_state.outelf, ELF_T_WORD, |
| nsym_allocated); |
| /* The first entry is left empty, clear it here and now. */ |
| xndxdata->d_buf = memset (xmalloc (xndxdata->d_size), '\0', |
| xelf_fsize (ld_state.outelf, ELF_T_WORD, |
| 1)); |
| xndxdata->d_off = 0; |
| /* XXX Should use an ebl function. */ |
| xndxdata->d_align = sizeof (Elf32_Word); |
| } |
| } |
| else |
| { |
| assert (ld_state.need_dynsym); |
| |
| /* First create the symbol table. We need the symbol section itself |
| and the string table for it. */ |
| symscn = elf_getscn (ld_state.outelf, ld_state.dynsymscnidx); |
| symdata = elf_newdata (symscn); |
| if (symdata == NULL) |
| error (EXIT_FAILURE, 0, |
| gettext ("cannot create symbol table for output file: %s"), |
| elf_errmsg (-1)); |
| |
| symdata->d_version = EV_CURRENT; |
| symdata->d_type = ELF_T_SYM; |
| /* This is an estimated size, but it will definitely cap the real value. |
| We might have to adjust the number later. */ |
| nsym_allocated = (1 + ld_state.nsymtab + ld_state.nplt + ld_state.ngot |
| - ld_state.nlocalsymbols + ld_state.nlscript_syms); |
| symdata->d_size = xelf_fsize (ld_state.outelf, ELF_T_SYM, |
| nsym_allocated); |
| } |
| |
| /* The first entry is left empty, clear it here and now. */ |
| symdata->d_buf = memset (xmalloc (symdata->d_size), '\0', |
| xelf_fsize (ld_state.outelf, ELF_T_SYM, 1)); |
| symdata->d_off = 0; |
| /* XXX This is ugly but how else can it be done. */ |
| symdata->d_align = xelf_fsize (ld_state.outelf, ELF_T_ADDR, 1); |
| |
| /* Allocate another array to keep track of the handles for the symbol |
| names. */ |
| symstrent = (struct Ebl_Strent **) xcalloc (nsym_allocated, |
| sizeof (struct Ebl_Strent *)); |
| |
| /* By starting at 1 we effectively add a null entry. */ |
| nsym = 1; |
| |
| /* Iteration over all sections. */ |
| for (cnt = 0; cnt < ld_state.nallsections; ++cnt) |
| { |
| struct scnhead *head = ld_state.allsections[cnt]; |
| Elf_Scn *scn; |
| struct scninfo *runp; |
| XElf_Off offset; |
| Elf32_Word xndx; |
| |
| /* Don't handle unused sections at all. */ |
| if (!head->used) |
| continue; |
| |
| /* Get the section handle. */ |
| scn = elf_getscn (ld_state.outelf, head->scnidx); |
| |
| if (unlikely (head->kind == scn_dot_interp)) |
| { |
| Elf_Data *outdata = elf_newdata (scn); |
| if (outdata == NULL) |
| error (EXIT_FAILURE, 0, |
| gettext ("cannot create section for output file: %s"), |
| elf_errmsg (-1)); |
| |
| /* This is the string we'll put in the section. */ |
| const char *interp = ld_state.interp ?: "/lib/ld.so.1"; |
| |
| /* Create the section data. */ |
| outdata->d_buf = (void *) interp; |
| outdata->d_size = strlen (interp) + 1; |
| outdata->d_type = ELF_T_BYTE; |
| outdata->d_off = 0; |
| outdata->d_align = 1; |
| outdata->d_version = EV_CURRENT; |
| |
| /* Remember the index of this section. */ |
| ld_state.interpscnidx = head->scnidx; |
| |
| continue; |
| } |
| |
| if (unlikely (head->kind == scn_dot_got)) |
| { |
| /* Remember the index of this section. */ |
| ld_state.gotscnidx = elf_ndxscn (scn); |
| |
| /* Give the backend the change to initialize the section. */ |
| INITIALIZE_GOT (&ld_state, scn); |
| |
| continue; |
| } |
| |
| if (unlikely (head->kind == scn_dot_dynrel)) |
| { |
| Elf_Data *outdata; |
| |
| outdata = elf_newdata (scn); |
| if (outdata == NULL) |
| error (EXIT_FAILURE, 0, |
| gettext ("cannot create section for output file: %s"), |
| elf_errmsg (-1)); |
| |
| outdata->d_size = ld_state.relsize_total; |
| outdata->d_buf = xmalloc (outdata->d_size); |
| outdata->d_type = (REL_TYPE (&ld_state) == DT_REL |
| ? ELF_T_REL : ELF_T_RELA); |
| outdata->d_off = 0; |
| outdata->d_align = xelf_fsize (ld_state.outelf, ELF_T_ADDR, 1); |
| |
| /* Remember the index of this section. */ |
| ld_state.reldynscnidx = elf_ndxscn (scn); |
| |
| continue; |
| } |
| |
| if (unlikely (head->kind == scn_dot_dynamic)) |
| { |
| /* Only create the data for now. */ |
| Elf_Data *outdata; |
| |
| /* Account for a few more entries we have to add. */ |
| if (ld_state.dt_flags != 0) |
| ++ld_state.ndynamic; |
| if (ld_state.dt_flags_1 != 0) |
| ++ld_state.ndynamic; |
| if (ld_state.dt_feature_1 != 0) |
| ++ld_state.ndynamic; |
| |
| outdata = elf_newdata (scn); |
| if (outdata == NULL) |
| error (EXIT_FAILURE, 0, |
| gettext ("cannot create section for output file: %s"), |
| elf_errmsg (-1)); |
| |
| /* Create the section data. */ |
| outdata->d_size = xelf_fsize (ld_state.outelf, ELF_T_DYN, |
| ld_state.ndynamic); |
| outdata->d_buf = xcalloc (1, outdata->d_size); |
| outdata->d_type = ELF_T_DYN; |
| outdata->d_off = 0; |
| outdata->d_align = xelf_fsize (ld_state.outelf, ELF_T_ADDR, 1); |
| |
| /* Remember the index of this section. */ |
| ld_state.dynamicscnidx = elf_ndxscn (scn); |
| |
| continue; |
| } |
| |
| if (unlikely (head->kind == scn_dot_dynsym)) |
| { |
| /* We already know the section index. */ |
| assert (ld_state.dynsymscnidx == elf_ndxscn (scn)); |
| |
| continue; |
| } |
| |
| if (unlikely (head->kind == scn_dot_dynstr)) |
| { |
| /* Remember the index of this section. */ |
| ld_state.dynstrscnidx = elf_ndxscn (scn); |
| |
| /* Create the string table. */ |
| dynstrtab = ebl_strtabinit (true); |
| |
| /* XXX TBI |
| We have to add all the strings which are needed in the |
| dynamic section here. This means DT_FILTER, |
| DT_AUXILIARY, ... entries. */ |
| if (ld_state.ndsofiles > 0) |
| { |
| struct usedfiles *frunp = ld_state.dsofiles; |
| |
| do |
| if (! ld_state.ignore_unused_dsos || frunp->used) |
| frunp->sonameent = ebl_strtabadd (dynstrtab, frunp->soname, |
| 0); |
| while ((frunp = frunp->next) != ld_state.dsofiles); |
| } |
| |
| |
| /* Add the runtime path information. The strings are stored |
| in the .dynstr section. If both rpath and runpath are defined |
| the runpath information is used. */ |
| if (ld_state.runpath != NULL || ld_state.rpath != NULL) |
| { |
| struct pathelement *startp; |
| struct pathelement *prunp; |
| int tag; |
| size_t len; |
| char *str; |
| char *cp; |
| |
| if (ld_state.runpath != NULL) |
| { |
| startp = ld_state.runpath; |
| tag = DT_RUNPATH; |
| } |
| else |
| { |
| startp = ld_state.rpath; |
| tag = DT_RPATH; |
| } |
| |
| /* Determine how long the string will be. */ |
| for (len = 0, prunp = startp; prunp != NULL; prunp = prunp->next) |
| len += strlen (prunp->pname) + 1; |
| |
| cp = str = (char *) obstack_alloc (&ld_state.smem, len); |
| /* Copy the string. */ |
| for (prunp = startp; prunp != NULL; prunp = prunp->next) |
| { |
| cp = stpcpy (cp, prunp->pname); |
| *cp++ = ':'; |
| } |
| /* Remove the last colon. */ |
| cp[-1] = '\0'; |
| |
| /* Remember the values until we can generate the dynamic |
| section. */ |
| ld_state.rxxpath_strent = ebl_strtabadd (dynstrtab, str, len); |
| ld_state.rxxpath_tag = tag; |
| } |
| |
| continue; |
| } |
| |
| if (unlikely (head->kind == scn_dot_hash)) |
| { |
| /* Remember the index of this section. */ |
| ld_state.hashscnidx = elf_ndxscn (scn); |
| |
| continue; |
| } |
| |
| if (unlikely (head->kind == scn_dot_plt)) |
| { |
| /* Remember the index of this section. */ |
| ld_state.pltscnidx = elf_ndxscn (scn); |
| |
| /* Give the backend the change to initialize the section. */ |
| INITIALIZE_PLT (&ld_state, scn); |
| |
| continue; |
| } |
| |
| if (unlikely (head->kind == scn_dot_pltrel)) |
| { |
| /* Remember the index of this section. */ |
| ld_state.pltrelscnidx = elf_ndxscn (scn); |
| |
| /* Give the backend the change to initialize the section. */ |
| INITIALIZE_PLTREL (&ld_state, scn); |
| |
| continue; |
| } |
| |
| if (unlikely (head->kind == scn_dot_version)) |
| { |
| /* Remember the index of this section. */ |
| ld_state.versymscnidx = elf_ndxscn (scn); |
| |
| continue; |
| } |
| |
| if (unlikely (head->kind == scn_dot_version_r)) |
| { |
| /* Remember the index of this section. */ |
| ld_state.verneedscnidx = elf_ndxscn (scn); |
| |
| continue; |
| } |
| |
| /* If we come here we must be handling a normal section. */ |
| assert (head->kind == scn_normal); |
| |
| /* Create an STT_SECTION entry in the symbol table. But not for |
| the symbolic symbol table. */ |
| if (ld_state.need_symtab) |
| { |
| /* XXX Can we be cleverer and do this only if needed? */ |
| XElf_Sym_vardef (sym); |
| |
| /* Optimization ahead: in the native linker we get a pointer |
| to the final location so that the following code writes |
| directly in the correct place. Otherwise we write into |
| the local variable first. */ |
| xelf_getsym_ptr (symdata, nsym, sym); |
| |
| /* Usual section symbol: local, no specific information, |
| except the section index. The offset here is zero, the |
| start address will later be added. */ |
| sym->st_name = 0; |
| sym->st_info = XELF_ST_INFO (STB_LOCAL, STT_SECTION); |
| sym->st_other = 0; |
| sym->st_value = 0; |
| sym->st_size = 0; |
| /* In relocatable files the section index can be too big for |
| the ElfXX_Sym struct. we have to deal with the extended |
| symbol table. */ |
| if (likely (head->scnidx < SHN_LORESERVE)) |
| { |
| sym->st_shndx = head->scnidx; |
| xndx = 0; |
| } |
| else |
| { |
| sym->st_shndx = SHN_XINDEX; |
| xndx = head->scnidx; |
| } |
| /* Commit the change. See the optimization above, this does |
| not change the symbol table entry. But the extended |
| section index table entry is always written, if there is |
| such a table. */ |
| assert (nsym < nsym_allocated); |
| xelf_update_symshndx (symdata, xndxdata, nsym, sym, xndx, 0); |
| |
| /* Remember the symbol's index in the symbol table. */ |
| head->scnsymidx = nsym++; |
| } |
| |
| if (head->type == SHT_REL || head->type == SHT_RELA) |
| { |
| /* Remember that we have to fill in the symbol table section |
| index. */ |
| if (ld_state.file_type == relocatable_file_type) |
| { |
| struct scnlist *newp; |
| |
| newp = (struct scnlist *) alloca (sizeof (*newp)); |
| newp->scnidx = head->scnidx; |
| newp->scninfo = head->last->next; |
| #ifndef NDEBUG |
| newp->next = NULL; |
| #endif |
| SNGL_LIST_PUSH (rellist, newp); |
| } |
| else |
| { |
| /* When we create an executable or a DSO we don't simply |
| copy the existing relocations. Instead many will be |
| resolved, others will be converted. Create a data buffer |
| large enough to contain the contents which we will fill |
| in later. */ |
| int type = head->type == SHT_REL ? ELF_T_REL : ELF_T_RELA; |
| |
| data = elf_newdata (scn); |
| if (data == NULL) |
| error (EXIT_FAILURE, 0, |
| gettext ("cannot create section for output file: %s"), |
| elf_errmsg (-1)); |
| |
| data->d_size = xelf_fsize (ld_state.outelf, type, head->relsize); |
| data->d_buf = xcalloc (data->d_size, 1); |
| data->d_type = type; |
| data->d_align = xelf_fsize (ld_state.outelf, ELF_T_ADDR, 1); |
| data->d_off = 0; |
| |
| continue; |
| } |
| } |
| |
| /* Recognize string and merge flag and handle them. */ |
| if (head->flags & SHF_MERGE) |
| { |
| /* We merge the contents of the sections. For this we do |
| not look at the contents of section directly. Instead we |
| look at the symbols of the section. */ |
| Elf_Data *outdata; |
| |
| /* Concatenate the lists of symbols for all sections. |
| |
| XXX In case any input section has no symbols associated |
| (this happens for debug sections) we cannot use this |
| method. Implement parsing the other debug sections and |
| find the string pointers. For now we don't merge. */ |
| runp = head->last->next; |
| if (runp->symbols == NULL) |
| { |
| head->flags &= ~SHF_MERGE; |
| goto no_merge; |
| } |
| head->symbols = runp->symbols; |
| |
| while ((runp = runp->next) != head->last->next) |
| { |
| if (runp->symbols == NULL) |
| { |
| head->flags &= ~SHF_MERGE; |
| head->symbols = NULL; |
| goto no_merge; |
| } |
| |
| struct symbol *oldhead = head->symbols->next_in_scn; |
| |
| head->symbols->next_in_scn = runp->symbols->next_in_scn; |
| runp->symbols->next_in_scn = oldhead; |
| head->symbols = runp->symbols; |
| } |
| |
| /* Create the output section. */ |
| outdata = elf_newdata (scn); |
| if (outdata == NULL) |
| error (EXIT_FAILURE, 0, |
| gettext ("cannot create section for output file: %s"), |
| elf_errmsg (-1)); |
| |
| /* We use different merging algorithms for performance |
| reasons. We can easily handle single-byte and |
| wchar_t-wide character strings. All other cases (which |
| really should happen in real life) are handled by the |
| generic code. */ |
| if (SCNINFO_SHDR (head->last->shdr).sh_entsize == 1 |
| && (head->flags & SHF_STRINGS)) |
| { |
| /* Simple, single-byte string matching. */ |
| struct Ebl_Strtab *mergestrtab; |
| struct symbol *symrunp; |
| Elf_Data *locsymdata = NULL; |
| Elf_Data *locdata = NULL; |
| |
| mergestrtab = ebl_strtabinit (false); |
| |
| symrunp = head->symbols->next_in_scn; |
| file = NULL; |
| do |
| { |
| /* Accelarate the loop. We cache the file |
| information since it might very well be the case |
| that the previous entry was from the same |
| file. */ |
| if (symrunp->file != file) |
| { |
| /* Remember the file. */ |
| file = symrunp->file; |
| /* Symbol table data from that file. */ |
| locsymdata = file->symtabdata; |
| /* String section data. */ |
| locdata = elf_rawdata (file->scninfo[symrunp->scndx].scn, |
| NULL); |
| assert (locdata != NULL); |
| /* While we are at it, remember the output |
| section. If we don't access the string data |
| section the section won't be in the output |
| file. So it is sufficient to do the work |
| here. */ |
| file->scninfo[symrunp->scndx].outscnndx = head->scnidx; |
| } |
| |
| /* Get the symbol information. This provides us the |
| offset into the string data section. */ |
| XElf_Sym_vardef (sym); |
| xelf_getsym (locsymdata, symrunp->symidx, sym); |
| assert (sym != NULL); |
| |
| /* Get the data from the file. Note that we access |
| the raw section data; no endian-ness issues with |
| single-byte strings. */ |
| symrunp->merge.handle |
| = ebl_strtabadd (mergestrtab, |
| (char *) locdata->d_buf + sym->st_value, |
| 0); |
| } |
| while ((symrunp = symrunp->next_in_scn) |
| != head->symbols->next_in_scn); |
| |
| /* All strings have been added. Create the final table. */ |
| ebl_strtabfinalize (mergestrtab, outdata); |
| |
| /* Compute the final offsets in the section. */ |
| symrunp = runp->symbols; |
| do |
| { |
| symrunp->merge.value |
| = ebl_strtaboffset (symrunp->merge.handle); |
| symrunp->merged = 1; |
| } |
| while ((symrunp = symrunp->next_in_scn) != runp->symbols); |
| |
| /* We don't need the string table anymore. */ |
| ebl_strtabfree (mergestrtab); |
| } |
| else if (likely (SCNINFO_SHDR (head->last->shdr).sh_entsize |
| == sizeof (wchar_t)) |
| && likely (head->flags & SHF_STRINGS)) |
| { |
| /* Simple, wchar_t string merging. */ |
| struct Ebl_WStrtab *mergestrtab; |
| struct symbol *symrunp; |
| Elf_Data *locsymdata = NULL; |
| Elf_Data *locdata = NULL; |
| |
| mergestrtab = ebl_wstrtabinit (false); |
| |
| symrunp = runp->symbols; |
| file = NULL; |
| do |
| { |
| /* Accelarate the loop. We cache the file |
| information since it might very well be the case |
| that the previous entry was from the same |
| file. */ |
| if (symrunp->file != file) |
| { |
| /* Remember the file. */ |
| file = symrunp->file; |
| /* Symbol table data from that file. */ |
| locsymdata = file->symtabdata; |
| /* String section data. */ |
| locdata = elf_rawdata (file->scninfo[symrunp->scndx].scn, |
| NULL); |
| assert (locdata != NULL); |
| |
| /* While we are at it, remember the output |
| section. If we don't access the string data |
| section the section won't be in the output |
| file. So it is sufficient to do the work |
| here. */ |
| file->scninfo[symrunp->scndx].outscnndx = head->scnidx; |
| } |
| |
| /* Get the symbol information. This provides us the |
| offset into the string data section. */ |
| XElf_Sym_vardef (sym); |
| xelf_getsym (locsymdata, symrunp->symidx, sym); |
| assert (sym != NULL); |
| |
| /* Get the data from the file. Using the raw |
| section data here is possible since we don't |
| interpret the string themselves except for |
| looking for the wide NUL character. The NUL |
| character has fortunately the same representation |
| regardless of the byte order. */ |
| symrunp->merge.handle |
| = ebl_wstrtabadd (mergestrtab, |
| (wchar_t *) ((char *) locdata->d_buf |
| + sym->st_value), 0); |
| } |
| while ((symrunp = symrunp->next_in_scn) != runp->symbols); |
| |
| /* All strings have been added. Create the final table. */ |
| ebl_wstrtabfinalize (mergestrtab, outdata); |
| |
| /* Compute the final offsets in the section. */ |
| symrunp = runp->symbols; |
| do |
| { |
| symrunp->merge.value |
| = ebl_wstrtaboffset (symrunp->merge.handle); |
| symrunp->merged = 1; |
| } |
| while ((symrunp = symrunp->next_in_scn) != runp->symbols); |
| |
| /* We don't need the string table anymore. */ |
| ebl_wstrtabfree (mergestrtab); |
| } |
| else |
| { |
| /* Non-standard merging. */ |
| struct Ebl_GStrtab *mergestrtab; |
| struct symbol *symrunp; |
| Elf_Data *locsymdata = NULL; |
| Elf_Data *locdata = NULL; |
| /* If this is no string section the length of each "string" |
| is always one. */ |
| unsigned int len = (head->flags & SHF_STRINGS) ? 0 : 1; |
| |
| /* This is the generic string table functionality. Much |
| slower than the specialized code. */ |
| mergestrtab |
| = ebl_gstrtabinit (SCNINFO_SHDR (head->last->shdr).sh_entsize, |
| false); |
| |
| symrunp = runp->symbols; |
| file = NULL; |
| do |
| { |
| /* Accelarate the loop. We cache the file |
| information since it might very well be the case |
| that the previous entry was from the same |
| file. */ |
| if (symrunp->file != file) |
| { |
| /* Remember the file. */ |
| file = symrunp->file; |
| /* Symbol table data from that file. */ |
| locsymdata = file->symtabdata; |
| /* String section data. */ |
| locdata = elf_rawdata (file->scninfo[symrunp->scndx].scn, |
| NULL); |
| assert (locdata != NULL); |
| |
| /* While we are at it, remember the output |
| section. If we don't access the string data |
| section the section won't be in the output |
| file. So it is sufficient to do the work |
| here. */ |
| file->scninfo[symrunp->scndx].outscnndx = head->scnidx; |
| } |
| |
| /* Get the symbol information. This provides us the |
| offset into the string data section. */ |
| XElf_Sym_vardef (sym); |
| xelf_getsym (locsymdata, symrunp->symidx, sym); |
| assert (sym != NULL); |
| |
| /* Get the data from the file. Using the raw |
| section data here is possible since we don't |
| interpret the string themselves except for |
| looking for the wide NUL character. The NUL |
| character has fortunately the same representation |
| regardless of the byte order. */ |
| symrunp->merge.handle |
| = ebl_gstrtabadd (mergestrtab, |
| (char *) locdata->d_buf + sym->st_value, |
| len); |
| } |
| while ((symrunp = symrunp->next_in_scn) != runp->symbols); |
| |
| /* Create the final table. */ |
| ebl_gstrtabfinalize (mergestrtab, outdata); |
| |
| /* Compute the final offsets in the section. */ |
| symrunp = runp->symbols; |
| do |
| { |
| symrunp->merge.value |
| = ebl_gstrtaboffset (symrunp->merge.handle); |
| symrunp->merged = 1; |
| } |
| while ((symrunp = symrunp->next_in_scn) != runp->symbols); |
| |
| /* We don't need the string table anymore. */ |
| ebl_gstrtabfree (mergestrtab); |
| } |
| } |
| else |
| { |
| no_merge: |
| assert (head->scnidx == elf_ndxscn (scn)); |
| |
| /* It is important to start with the first list entry (and |
| not just any one) to add the sections in the correct |
| order. */ |
| runp = head->last->next; |
| offset = 0; |
| do |
| { |
| Elf_Data *outdata = elf_newdata (scn); |
| if (outdata == NULL) |
| error (EXIT_FAILURE, 0, |
| gettext ("cannot create section for output file: %s"), |
| elf_errmsg (-1)); |
| |
| /* Exceptional case: if we synthesize a data block SCN |
| is NULL and the sectio header info must be for a |
| SHT_NOBITS block and the size and alignment are |
| filled in. */ |
| if (likely (runp->scn != NULL)) |
| { |
| data = elf_getdata (runp->scn, NULL); |
| assert (data != NULL); |
| |
| /* We reuse the data buffer in the input file. */ |
| *outdata = *data; |
| |
| /* Given that we read the input file from disk we know there |
| cannot be another data part. */ |
| assert (elf_getdata (runp->scn, data) == NULL); |
| } |
| else |
| { |
| /* Must be a NOBITS section. */ |
| assert (SCNINFO_SHDR (runp->shdr).sh_type == SHT_NOBITS); |
| |
| outdata->d_buf = NULL; /* Not needed. */ |
| outdata->d_type = ELF_T_BYTE; |
| outdata->d_version = EV_CURRENT; |
| outdata->d_size = SCNINFO_SHDR (runp->shdr).sh_size; |
| outdata->d_align = SCNINFO_SHDR (runp->shdr).sh_addralign; |
| } |
| |
| XElf_Off align = MAX (1, outdata->d_align); |
| assert (powerof2 (align)); |
| offset = ((offset + align - 1) & ~(align - 1)); |
| |
| runp->offset = offset; |
| runp->outscnndx = head->scnidx; |
| runp->allsectionsidx = cnt; |
| |
| outdata->d_off = offset; |
| |
| offset += outdata->d_size; |
| } |
| while ((runp = runp->next) != head->last->next); |
| |
| /* If necessary add the additional line to the .comment section. */ |
| if (ld_state.add_ld_comment |
| && head->flags == 0 |
| && head->type == SHT_PROGBITS |
| && strcmp (head->name, ".comment") == 0 |
| && head->entsize == 0) |
| { |
| Elf_Data *outdata = elf_newdata (scn); |
| |
| if (outdata == NULL) |
| error (EXIT_FAILURE, 0, |
| gettext ("cannot create section for output file: %s"), |
| elf_errmsg (-1)); |
| |
| outdata->d_buf = (void *) "\0ld (Red Hat " PACKAGE ") " VERSION; |
| outdata->d_size = strlen ((char *) outdata->d_buf + 1) + 2; |
| outdata->d_off = offset; |
| outdata->d_type = ELF_T_BYTE; |
| outdata->d_align = 1; |
| } |
| /* XXX We should create a .comment section if none exists. |
| This requires that we early on detect that no such |
| section exists. This should probably be implemented |
| together with some merging of the section contents. |
| Currently identical entries are not merged. */ |
| } |
| } |
| |
| /* The table we collect the strings in. */ |
| strtab = ebl_strtabinit (true); |
| if (strtab == NULL) |
| error (EXIT_FAILURE, errno, gettext ("cannot create string table")); |
| |
| |
| #ifndef NDEBUG |
| /* Keep track of the use of the XINDEX. */ |
| need_xndx = false; |
| #endif |
| |
| /* We we generate a normal symbol table for an executable and the |
| --export-dynamic option is not given, we need an extra table |
| which keeps track of the symbol entry belonging to the symbol |
| table entry. Note that EXPORT_ALL_DYNAMIC is always set if we |
| generate a DSO so we do not have to test this separately. */ |
| ndxtosym = (struct symbol **) xcalloc (nsym_allocated, |
| sizeof (struct symbol)); |
| |
| /* Create the special symbol for the GOT section. */ |
| if (ld_state.got_symbol != NULL) |
| { |
| assert (nsym < nsym_allocated); |
| fillin_special_symbol (ld_state.got_symbol, ld_state.gotscnidx, |
| nsym++, symdata, strtab); |
| } |
| |
| /* Similarly for the dynamic section symbol. */ |
| if (ld_state.dyn_symbol != NULL) |
| { |
| assert (nsym < nsym_allocated); |
| fillin_special_symbol (ld_state.dyn_symbol, ld_state.dynamicscnidx, |
| nsym++, symdata, strtab); |
| } |
| |
| /* Create symbol table entries for the symbols defined in the linker |
| script. */ |
| if (ld_state.lscript_syms != NULL) |
| { |
| struct symbol *rsym = ld_state.lscript_syms; |
| do |
| { |
| assert (nsym < nsym_allocated); |
| fillin_special_symbol (rsym, SHN_ABS, nsym++, symdata, strtab); |
| } |
| while ((rsym = rsym->next) != NULL); |
| } |
| |
| /* Iterate over all input files to collect the symbols. */ |
| file = ld_state.relfiles->next; |
| symdata = elf_getdata (elf_getscn (ld_state.outelf, ld_state.symscnidx), |
| NULL); |
| do |
| { |
| size_t maxcnt; |
| Elf_Data *insymdata; |
| Elf_Data *inxndxdata; |
| |
| /* There must be no dynamic symbol table when creating |
| relocatable files. */ |
| assert (ld_state.file_type != relocatable_file_type |
| || file->dynsymtabdata == NULL); |
| |
| insymdata = file->symtabdata; |
| assert (insymdata != NULL); |
| inxndxdata = file->xndxdata; |
| |
| maxcnt = file->nsymtab; |
| |
| file->symindirect = (Elf32_Word *) xcalloc (maxcnt, sizeof (Elf32_Word)); |
| |
| /* The dynamic symbol table does not contain local symbols. So |
| we skip those entries. */ |
| for (cnt = ld_state.need_symtab ? 1 : file->nlocalsymbols; cnt < maxcnt; |
| ++cnt) |
| { |
| XElf_Sym_vardef (sym); |
| Elf32_Word xndx; |
| struct symbol *defp = NULL; |
| |
| xelf_getsymshndx (insymdata, inxndxdata, cnt, sym, xndx); |
| assert (sym != NULL); |
| |
| if (unlikely (XELF_ST_TYPE (sym->st_info) == STT_SECTION)) |
| { |
| /* Section symbols should always be local but who knows... */ |
| if (ld_state.need_symtab) |
| { |
| /* Determine the real section index in the source file. |
| Use the XINDEX section content if necessary. We don't |
| add this information to the dynamic symbol table. */ |
| if (sym->st_shndx != SHN_XINDEX) |
| xndx = sym->st_shndx; |
| |
| assert (file->scninfo[xndx].allsectionsidx |
| < ld_state.nallsections); |
| file->symindirect[cnt] = ld_state.allsections[file->scninfo[xndx].allsectionsidx]->scnsymidx; |
| /* Note that the resulting index can be zero here. There is |
| no guarantee that the output file will contain all the |
| sections the input file did. */ |
| } |
| continue; |
| } |
| |
| if ((ld_state.strip >= strip_all || !ld_state.need_symtab) |
| /* XXX Do we need these entries? */ |
| && XELF_ST_TYPE (sym->st_info) == STT_FILE) |
| continue; |
| |
| #if NATIVE_ELF != 0 |
| /* Copy old data. */ |
| XElf_Sym *sym2 = sym; |
| assert (nsym < nsym_allocated); |
| xelf_getsym (symdata, nsym, sym); |
| *sym = *sym2; |
| #endif |
| |
| if (sym->st_shndx != SHN_UNDEF |
| && (sym->st_shndx < SHN_LORESERVE |
| || sym->st_shndx == SHN_XINDEX)) |
| { |
| /* If we are creating an executable with no normal |
| symbol table and we do not export all symbols and |
| this symbol is not defined in a DSO as well, ignore |
| it. */ |
| if (!ld_state.export_all_dynamic && !ld_state.need_symtab) |
| { |
| assert (cnt >= file->nlocalsymbols); |
| defp = file->symref[cnt]; |
| assert (defp != NULL); |
| |
| if (!defp->in_dso) |
| /* Ignore it. */ |
| continue; |
| } |
| |
| /* Determine the real section index in the source file. Use |
| the XINDEX section content if necessary. */ |
| if (sym->st_shndx != SHN_XINDEX) |
| xndx = sym->st_shndx; |
| |
| sym->st_value += file->scninfo[xndx].offset; |
| |
| assert (file->scninfo[xndx].outscnndx < SHN_LORESERVE |
| || file->scninfo[xndx].outscnndx > SHN_HIRESERVE); |
| if (unlikely (file->scninfo[xndx].outscnndx > SHN_LORESERVE)) |
| { |
| /* It is not possible to have an extended section index |
| table for the dynamic symbol table. */ |
| if (!ld_state.need_symtab) |
| error (EXIT_FAILURE, 0, gettext ("\ |
| section index too large in dynamic symbol table")); |
| |
| assert (xndxdata != NULL); |
| sym->st_shndx = SHN_XINDEX; |
| xndx = file->scninfo[xndx].outscnndx; |
| #ifndef NDEBUG |
| need_xndx = true; |
| #endif |
| } |
| else |
| { |
| sym->st_shndx = file->scninfo[xndx].outscnndx; |
| xndx = 0; |
| } |
| } |
| else if (sym->st_shndx == SHN_COMMON || sym->st_shndx == SHN_UNDEF) |
| { |
| /* Check whether we have a (real) definition for this |
| symbol. If this is the case we skip this symbol |
| table entry. */ |
| assert (cnt >= file->nlocalsymbols); |
| defp = file->symref[cnt]; |
| assert (defp != NULL); |
| |
| assert (sym->st_shndx != SHN_COMMON || defp->defined); |
| |
| if ((sym->st_shndx == SHN_COMMON && !defp->common) |
| || (sym->st_shndx == SHN_UNDEF && defp->defined) |
| || defp->added) |
| /* Ignore this symbol table entry, there is a |
| "better" one or we already added it. */ |
| continue; |
| |
| /* Remember that we already added this symbol. */ |
| defp->added = 1; |
| |
| /* Adjust the section number for common symbols. */ |
| if (sym->st_shndx == SHN_COMMON) |
| { |
| sym->st_value = (ld_state.common_section->offset |
| + file->symref[cnt]->merge.value); |
| assert (ld_state.common_section->outscnndx < SHN_LORESERVE); |
| sym->st_shndx = ld_state.common_section->outscnndx; |
| xndx = 0; |
| } |
| } |
| else if (unlikely (sym->st_shndx != SHN_ABS)) |
| { |
| if (SPECIAL_SECTION_NUMBER_P (&ld_state, sym->st_shndx)) |
| /* XXX Add code to handle machine specific special |
| sections. */ |
| abort (); |
| } |
| |
| /* Add the symbol name to the string table. If the user |
| chooses the highest level of stripping avoid adding names |
| for local symbols in the string table. */ |
| if (sym->st_name != 0 |
| && (ld_state.strip < strip_everything |
| || XELF_ST_BIND (sym->st_info) != STB_LOCAL)) |
| symstrent[nsym] = ebl_strtabadd (strtab, |
| elf_strptr (file->elf, |
| file->symstridx, |
| sym->st_name), 0); |
| |
| /* Once we know the name this field will get the correct |
| offset. For now set it to zero which means no name |
| associated. */ |
| sym->st_name = 0; |
| |
| /* If we had to merge sections we have a completely new |
| offset for the symbol. */ |
| if (file->has_merge_sections && file->symref[cnt] != NULL |
| && file->symref[cnt]->merged) |
| sym->st_value = file->symref[cnt]->merge.value; |
| |
| /* Create the record in the output sections. */ |
| assert (nsym < nsym_allocated); |
| xelf_update_symshndx (symdata, xndxdata, nsym, sym, xndx, 0); |
| |
| /* Add the reference to the symbol record in case we need it. |
| Find the symbol if this has not happened yet. We do |
| not need the information for local symbols. */ |
| if (defp == NULL && cnt >= file->nlocalsymbols) |
| { |
| defp = file->symref[cnt]; |
| assert (defp != NULL); |
| } |
| |
| /* Store the reference to the symbol record. The |
| sorting code will have to keep this array in the |
| correct order, too. */ |
| ndxtosym[nsym] = defp; |
| |
| /* One more entry finished. */ |
| if (cnt >= file->nlocalsymbols) |
| { |
| assert (file->symref[cnt]->outsymidx == 0); |
| file->symref[cnt]->outsymidx = nsym; |
| } |
| file->symindirect[cnt] = nsym++; |
| } |
| } |
| while ((file = file->next) != ld_state.relfiles->next); |
| /* Make sure we didn't create the extended section index table for |
| nothing. */ |
| assert (xndxdata == NULL || need_xndx); |
| |
| |
| /* Create the version related sections. */ |
| if (ld_state.verneedscnidx != 0) |
| { |
| /* We know the number of input files and total number of |
| referenced versions. This allows us to allocate the memory |
| and then we iterate over the DSOs to get the version |
| information. */ |
| struct usedfiles *runp; |
| |
| runp = ld_state.dsofiles->next; |
| do |
| allocate_version_names (runp, dynstrtab); |
| while ((runp = runp->next) != ld_state.dsofiles->next); |
| |
| if (ld_state.needed != NULL) |
| { |
| runp = ld_state.needed->next; |
| do |
| allocate_version_names (runp, dynstrtab); |
| while ((runp = runp->next) != ld_state.needed->next); |
| } |
| } |
| |
| /* At this point we should hide symbols and so on. */ |
| if (ld_state.default_bind_local || ld_state.version_str_tab.filled > 0) |
| /* XXX Add one more test when handling of wildcard symbol names |
| is supported. */ |
| { |
| /* Check all non-local symbols whether they are on the export list. */ |
| bool any_reduced = false; |
| |
| for (cnt = 1; cnt < nsym; ++cnt) |
| { |
| XElf_Sym_vardef (sym); |
| |
| /* Note that we don't have to use 'xelf_getsymshndx' since we |
| only need the binding and the symbol name. */ |
| xelf_getsym (symdata, cnt, sym); |
| assert (sym != NULL); |
| |
| if (reduce_symbol_p (sym, symstrent[cnt])) |
| { |
| sym->st_info = XELF_ST_INFO (STB_LOCAL, |
| XELF_ST_TYPE (sym->st_info)); |
| (void) xelf_update_sym (symdata, cnt, sym); |
| |
| /* Show that we don't need this string anymore. */ |
| if (ld_state.strip == strip_everything) |
| { |
| symstrent[cnt] = NULL; |
| any_reduced = true; |
| } |
| } |
| } |
| |
| if (unlikely (any_reduced)) |
| { |
| /* Since we will not write names of local symbols in the |
| output file and we have reduced the binding of some |
| symbols the string table previously constructed contains |
| too many string. Correct it. */ |
| struct Ebl_Strtab *newp = ebl_strtabinit (true); |
| |
| for (cnt = 1; cnt < nsym; ++cnt) |
| if (symstrent[cnt] != NULL) |
| symstrent[cnt] = ebl_strtabadd (newp, |
| ebl_string (symstrent[cnt]), 0); |
| |
| ebl_strtabfree (strtab); |
| strtab = newp; |
| } |
| } |
| |
| /* Add the references to DSOs. We can add these entries this late |
| (after sorting out versioning) because references to DSOs are not |
| effected. */ |
| if (ld_state.from_dso != NULL) |
| { |
| struct symbol *runp; |
| size_t plt_base = nsym + ld_state.nfrom_dso - ld_state.nplt; |
| size_t plt_idx = 0; |
| size_t obj_idx = 0; |
| |
| assert (ld_state.nfrom_dso >= ld_state.nplt); |
| runp = ld_state.from_dso; |
| do |
| { |
| // XXX What about functions which are only referenced via |
| // pointers and not PLT entries? Can we distinguish such uses? |
| size_t idx; |
| if (runp->type == STT_FUNC) |
| { |
| /* Store the PLT entry number. */ |
| runp->merge.value = plt_idx + 1; |
| idx = plt_base + plt_idx++; |
| } |
| else |
| idx = nsym + obj_idx++; |
| |
| XElf_Sym_vardef (sym); |
| xelf_getsym_ptr (symdata, idx, sym); |
| |
| sym->st_value = 0; |
| sym->st_size = runp->size; |
| sym->st_info = XELF_ST_INFO (runp->weak ? STB_WEAK : STB_GLOBAL, |
| runp->type); |
| sym->st_other = STV_DEFAULT; |
| sym->st_shndx = SHN_UNDEF; |
| |
| /* Create the record in the output sections. */ |
| xelf_update_symshndx (symdata, xndxdata, idx, sym, 0, 0); |
| |
| const char *name = runp->name; |
| size_t namelen = 0; |
| |
| if (runp->file->verdefdata != NULL) |
| { |
| // XXX Is it useful to add the versym value to struct symbol? |
| XElf_Versym versym; |
| |
| (void) xelf_getversym_copy (runp->file->versymdata, runp->symidx, |
| versym); |
| |
| /* One can only link with the default version. */ |
| assert ((versym & 0x8000) == 0); |
| |
| const char *versname |
| = ebl_string (runp->file->verdefent[versym]); |
| |
| size_t versname_len = strlen (versname) + 1; |
| namelen = strlen (name) + versname_len + 2; |
| char *newp = (char *) obstack_alloc (&ld_state.smem, namelen); |
| memcpy (stpcpy (stpcpy (newp, name), "@@"), |
| versname, versname_len); |
| name = newp; |
| } |
| |
| symstrent[idx] = ebl_strtabadd (strtab, name, namelen); |
| |
| /* Record the initial index in the symbol table. */ |
| runp->outsymidx = idx; |
| |
| /* Remember the symbol record this ELF symbol came from. */ |
| ndxtosym[idx] = runp; |
| } |
| while ((runp = runp->next) != ld_state.from_dso); |
| |
| assert (nsym + obj_idx == plt_base); |
| assert (plt_idx == ld_state.nplt); |
| nsym = plt_base + plt_idx; |
| } |
| |
| /* Now we know how many symbols will be in the output file. Adjust |
| the count in the section data. */ |
| symdata->d_size = xelf_fsize (ld_state.outelf, ELF_T_SYM, nsym); |
| if (unlikely (xndxdata != NULL)) |
| xndxdata->d_size = xelf_fsize (ld_state.outelf, ELF_T_WORD, nsym); |
| |
| /* Create the symbol string table section. */ |
| strscn = elf_newscn (ld_state.outelf); |
| ld_state.strscnidx = elf_ndxscn (strscn); |
| data = elf_newdata (strscn); |
| xelf_getshdr (strscn, shdr); |
| if (data == NULL || shdr == NULL) |
| error (EXIT_FAILURE, 0, |
| gettext ("cannot create section for output file: %s"), |
| elf_errmsg (-1)); |
| |
| /* Create a compact string table, allocate the memory for it, and |
| fill in the section data information. */ |
| ebl_strtabfinalize (strtab, data); |
| |
| shdr->sh_type = SHT_STRTAB; |
| assert (shdr->sh_entsize == 0); |
| |
| if (unlikely (xelf_update_shdr (strscn, shdr) == 0)) |
| error (EXIT_FAILURE, 0, |
| gettext ("cannot create section for output file: %s"), |
| elf_errmsg (-1)); |
| |
| /* Fill in the offsets of the symbol names. */ |
| for (cnt = 1; cnt < nsym; ++cnt) |
| if (symstrent[cnt] != NULL) |
| { |
| XElf_Sym_vardef (sym); |
| |
| /* Note that we don't have to use 'xelf_getsymshndx' since we don't |
| modify the section index. */ |
| xelf_getsym (symdata, cnt, sym); |
| /* This better worked, we did it before. */ |
| assert (sym != NULL); |
| sym->st_name = ebl_strtaboffset (symstrent[cnt]); |
| (void) xelf_update_sym (symdata, cnt, sym); |
| } |
| |
| /* Since we are going to reorder the symbol table but still have to |
| be able to find the new position based on the old one (since the |
| latter is stored in 'symindirect' information of the input file |
| data structure) we have to create yet another indirection |
| table. */ |
| ld_state.dblindirect = dblindirect |
| = (Elf32_Word *) xmalloc (nsym * sizeof (Elf32_Word)); |
| |
| /* Sort the symbol table so that the local symbols come first. */ |
| /* XXX We don't use stable sorting here. It seems not necessary and |
| would be more expensive. If it turns out to be necessary this can |
| be fixed easily. */ |
| nsym_local = 1; |
| cnt = nsym - 1; |
| while (nsym_local < cnt) |
| { |
| XElf_Sym_vardef (locsym); |
| Elf32_Word locxndx; |
| XElf_Sym_vardef (globsym); |
| Elf32_Word globxndx; |
| |
| do |
| { |
| xelf_getsymshndx (symdata, xndxdata, nsym_local, locsym, locxndx); |
| /* This better works. */ |
| assert (locsym != NULL); |
| |
| if (XELF_ST_BIND (locsym->st_info) != STB_LOCAL |
| && (ld_state.need_symtab || ld_state.export_all_dynamic)) |
| { |
| do |
| { |
| xelf_getsymshndx (symdata, xndxdata, cnt, globsym, globxndx); |
| /* This better works. */ |
| assert (globsym != NULL); |
| |
| if (unlikely (XELF_ST_BIND (globsym->st_info) == STB_LOCAL)) |
| { |
| /* We swap the two entries. */ |
| #if NATIVE_ELF != 0 |
| /* Since we directly modify the data in the ELF |
| data structure we have to make a copy of one |
| of the entries. */ |
| XElf_Sym locsym_copy = *locsym; |
| locsym = &locsym_copy; |
| #endif |
| xelf_update_symshndx (symdata, xndxdata, nsym_local, |
| globsym, globxndx, 1); |
| xelf_update_symshndx (symdata, xndxdata, cnt, |
| locsym, locxndx, 1); |
| |
| /* Also swap the cross references. */ |
| dblindirect[nsym_local] = cnt; |
| dblindirect[cnt] = nsym_local; |
| |
| /* And the entries for the symbol names. */ |
| struct Ebl_Strent *strtmp = symstrent[nsym_local]; |
| symstrent[nsym_local] = symstrent[cnt]; |
| symstrent[cnt] = strtmp; |
| |
| /* And the mapping from symbol table entry to |
| struct symbol record. */ |
| struct symbol *symtmp = ndxtosym[nsym_local]; |
| ndxtosym[nsym_local] = ndxtosym[cnt]; |
| ndxtosym[cnt] = symtmp; |
| |
| /* Go to the next entry. */ |
| ++nsym_local; |
| --cnt; |
| |
| break; |
| } |
| |
| dblindirect[cnt] = cnt; |
| } |
| while (nsym_local < --cnt); |
| |
| break; |
| } |
| |
| dblindirect[nsym_local] = nsym_local; |
| } |
| while (++nsym_local < cnt); |
| } |
| |
| /* The symbol 'nsym_local' is currently pointing to might be local, |
| too. Check and increment the variable if this is the case. */ |
| if (likely (nsym_local < nsym)) |
| { |
| XElf_Sym_vardef (locsym); |
| |
| /* This entry isn't moved. */ |
| dblindirect[nsym_local] = nsym_local; |
| |
| /* Note that it is OK to not use 'xelf_getsymshndx' here. */ |
| xelf_getsym (symdata, nsym_local, locsym); |
| /* This better works. */ |
| assert (locsym != NULL); |
| |
| if (XELF_ST_BIND (locsym->st_info) == STB_LOCAL) |
| ++nsym_local; |
| } |
| |
| |
| /* We need the versym array right away to keep track of the version |
| symbols. */ |
| if (ld_state.versymscnidx != 0) |
| { |
| /* We allocate more memory than we need since the array is morroring |
| the dynamic symbol table and not the normal symbol table. I.e., |
| no local symbols are present. */ |
| versymscn = elf_getscn (ld_state.outelf, ld_state.versymscnidx); |
| versymdata = elf_newdata (versymscn); |
| if (versymdata == NULL) |
| error (EXIT_FAILURE, 0, |
| gettext ("cannot create versioning section: %s"), |
| elf_errmsg (-1)); |
| |
| versymdata->d_size = xelf_fsize (ld_state.outelf, ELF_T_HALF, |
| nsym - nsym_local + 1); |
| versymdata->d_buf = xcalloc (1, versymdata->d_size); |
| versymdata->d_align = xelf_fsize (ld_state.outelf, ELF_T_HALF, 1); |
| versymdata->d_off = 0; |
| versymdata->d_type = ELF_T_HALF; |
| } |
| |
| |
| /* If we have to construct the dynamic symbol table we must not include |
| the local symbols. If the normal symbol has to be emitted as well |
| we haven't done anything else yet and we can construct it from |
| scratch now. */ |
| if (unlikely (!ld_state.need_symtab)) |
| { |
| /* Note that the following code works even if there is no entry |
| to remove since the zeroth entry is always local. */ |
| size_t reduce = xelf_fsize (ld_state.outelf, ELF_T_SYM, nsym_local - 1); |
| |
| XElf_Sym_vardef (nullsym); |
| xelf_getsym_ptr (symdata, nsym_local - 1, nullsym); |
| |
| /* Note that we don't have to use 'xelf_update_symshndx' since |
| this is the dynamic symbol table we write. */ |
| (void) xelf_update_sym (symdata, nsym_local - 1, |
| memset (nullsym, '\0', sizeof (*nullsym))); |
| |
| /* Update the buffer pointer and size in the output data. */ |
| symdata->d_buf = (char *) symdata->d_buf + reduce; |
| symdata->d_size -= reduce; |
| |
| /* Add the version symbol information. */ |
| if (versymdata != NULL) |
| { |
| nsym_dyn = 1; |
| for (cnt = nsym_local; cnt < nsym; ++cnt, ++nsym_dyn) |
| { |
| struct symbol *symp = ndxtosym[cnt]; |
| |
| if (symp->file->versymdata != NULL) |
| { |
| GElf_Versym versym; |
| |
| gelf_getversym (symp->file->versymdata, symp->symidx, |
| &versym); |
| |
| (void) gelf_update_versym (versymdata, nsym_dyn, |
| &symp->file->verdefused[versym]); |
| } |
| } |
| } |
| |
| /* Since we only created the dynamic symbol table the number of |
| dynamic symbols is the total number of symbols. */ |
| nsym_dyn = nsym - nsym_local + 1; |
| |
| /* XXX TBI. Create whatever data structure is missing. */ |
| abort (); |
| } |
| else if (ld_state.need_dynsym) |
| { |
| /* Create the dynamic symbol table section data along with the |
| string table. We look at all non-local symbols we found for |
| the normal symbol table and add those. */ |
| dynsymscn = elf_getscn (ld_state.outelf, ld_state.dynsymscnidx); |
| dynsymdata = elf_newdata (dynsymscn); |
| |
| dynstrdata = elf_newdata (elf_getscn (ld_state.outelf, |
| ld_state.dynstrscnidx)); |
| if (dynsymdata == NULL || dynstrdata == NULL) |
| error (EXIT_FAILURE, 0, gettext ("\ |
| cannot create dynamic symbol table for output file: %s"), |
| elf_errmsg (-1)); |
| |
| nsym_dyn_allocated = nsym - nsym_local + 1; |
| dynsymdata->d_size = xelf_fsize (ld_state.outelf, ELF_T_SYM, |
| nsym_dyn_allocated); |
| dynsymdata->d_buf = memset (xmalloc (dynsymdata->d_size), '\0', |
| xelf_fsize (ld_state.outelf, ELF_T_SYM, 1)); |
| dynsymdata->d_type = ELF_T_SYM; |
| dynsymdata->d_off = 0; |
| dynsymdata->d_align = xelf_fsize (ld_state.outelf, ELF_T_ADDR, 1); |
| |
| /* We need one more array which contains the hash codes of the |
| symbol names. */ |
| hashcodes = (Elf32_Word *) xcalloc (nsym_dyn_allocated, |
| sizeof (Elf32_Word)); |
| |
| /* We have and empty entry at the beginning. */ |
| nsym_dyn = 1; |
| |
| /* We don't mix PLT symbols and others. */ |
| size_t plt_idx = 1; |
| size_t obj_idx = 1 + ld_state.nplt; |
| |
| /* Populate the table. */ |
| for (cnt = nsym_local; cnt < nsym; ++cnt) |
| { |
| XElf_Sym_vardef (sym); |
| |
| xelf_getsym (symdata, cnt, sym); |
| assert (sym != NULL); |
| |
| if (sym->st_shndx == SHN_XINDEX) |
| error (EXIT_FAILURE, 0, gettext ("\ |
| section index too large in dynamic symbol table")); |
| |
| /* We do not add the symbol to the dynamic symbol table if |
| |
| - the symbol is for a file |
| - it is not externally visible (internal, hidden) |
| - if export_all_dynamic is not set and is only defined in |
| the executable (i.e., it is defined, but not (also) in |
| in DSO) |
| |
| Set symstrent[cnt] to NULL in case an entry is ignored. */ |
| if (XELF_ST_TYPE (sym->st_info) == STT_FILE |
| || XELF_ST_VISIBILITY (sym->st_other) == STV_INTERNAL |
| || XELF_ST_VISIBILITY (sym->st_other) == STV_HIDDEN |
| || (!ndxtosym[cnt]->in_dso && ndxtosym[cnt]->defined)) |
| { |
| symstrent[cnt] = NULL; |
| continue; |
| } |
| |
| size_t idx; |
| if (ndxtosym[cnt]->in_dso && ndxtosym[cnt]->type == STT_FUNC) |
| { |
| idx = plt_idx++; |
| assert (idx < 1 + ld_state.nplt); |
| } |
| else |
| { |
| idx = obj_idx++; |
| assert (idx < nsym_dyn_allocated); |
| } |
| |
| /* Add the version information. */ |
| if (versymdata != NULL) |
| { |
| struct symbol *symp = ndxtosym[cnt]; |
| |
| if (symp->file->verdefdata != NULL) |
| { |
| GElf_Versym versym; |
| |
| gelf_getversym (symp->file->versymdata, symp->symidx, |
| &versym); |
| |
| (void) gelf_update_versym (versymdata, idx, |
| &symp->file->verdefused[versym]); |
| } |
| else |
| { |
| /* XXX Add support for version definitions. */ |
| GElf_Versym global = VER_NDX_GLOBAL; |
| (void) gelf_update_versym (versymdata, idx, &global); |
| } |
| } |
| |
| /* Store the index of the symbol in the dynamic symbol table. */ |
| ndxtosym[cnt]->outdynsymidx = idx; |
| |
| /* Create a new string table entry. */ |
| const char *str = ndxtosym[cnt]->name; |
| symstrent[cnt] = ebl_strtabadd (dynstrtab, str, 0); |
| hashcodes[idx] = elf_hash (str); |
| ++nsym_dyn; |
| } |
| assert (nsym_dyn == obj_idx); |
| assert (ld_state.nplt + 1 == plt_idx); |
| |
| /* Update the information about the symbol section. */ |
| if (versymdata != NULL) |
| { |
| /* Correct the size now that we know how many entries the |
| dynamic symbol table has. */ |
| versymdata->d_size = xelf_fsize (ld_state.outelf, ELF_T_HALF, |
| nsym_dyn); |
| |
| /* Add the reference to the symbol table. */ |
| xelf_getshdr (versymscn, shdr); |
| assert (shdr != NULL); |
| |
| shdr->sh_link = ld_state.dynsymscnidx; |
| |
| (void) xelf_update_shdr (versymscn, shdr); |
| } |
| } |
| |
| if (ld_state.file_type != relocatable_file_type) |
| { |
| size_t nbucket; |
| Elf32_Word *bucket; |
| Elf32_Word *chain; |
| size_t nchain; |
| Elf_Scn *hashscn; |
| Elf_Data *hashdata; |
| |
| /* Finalize the dynamic string table. */ |
| ebl_strtabfinalize (dynstrtab, dynstrdata); |
| |
| /* Determine the "optimal" bucket size. */ |
| nbucket = optimal_bucket_size (hashcodes, nsym_dyn, ld_state.optlevel); |
| |
| /* Create the .hash section data structures. */ |
| assert (ld_state.hashscnidx != 0); |
| hashscn = elf_getscn (ld_state.outelf, ld_state.hashscnidx); |
| xelf_getshdr (hashscn, shdr); |
| hashdata = elf_newdata (hashscn); |
| if (shdr == NULL || hashdata == NULL) |
| error (EXIT_FAILURE, 0, gettext ("\ |
| cannot create hash table section for output file: %s"), |
| elf_errmsg (-1)); |
| |
| shdr->sh_link = ld_state.dynsymscnidx; |
| (void) xelf_update_shdr (hashscn, shdr); |
| |
| hashdata->d_size = (2 + nsym_dyn + nbucket) * sizeof (Elf32_Word); |
| hashdata->d_buf = xcalloc (1, hashdata->d_size); |
| hashdata->d_align = sizeof (Elf32_Word); |
| hashdata->d_type = ELF_T_WORD; |
| hashdata->d_off = 0; |
| |
| ((Elf32_Word *) hashdata->d_buf)[0] = nbucket; |
| ((Elf32_Word *) hashdata->d_buf)[1] = nsym_dyn; |
| bucket = &((Elf32_Word *) hashdata->d_buf)[2]; |
| chain = &((Elf32_Word *) hashdata->d_buf)[2 + nbucket]; |
| |
| /* Haven't yet filled in any chain value. */ |
| nchain = 0; |
| |
| /* Now put the names in. */ |
| for (cnt = nsym_local; cnt < nsym; ++cnt) |
| if (symstrent[cnt] != NULL) |
| { |
| XElf_Sym_vardef (sym); |
| size_t hashidx; |
| size_t dynidx = ndxtosym[cnt]->outdynsymidx; |
| |
| #if NATIVE_ELF != 0 |
| XElf_Sym *osym; |
| memcpy (xelf_getsym (dynsymdata, dynidx, sym), |
| xelf_getsym (symdata, cnt, osym), |
| sizeof (XElf_Sym)); |
| #else |
| xelf_getsym (symdata, cnt, sym); |
| assert (sym != NULL); |
| #endif |
| |
| sym->st_name = ebl_strtaboffset (symstrent[cnt]); |
| |
| (void) xelf_update_sym (dynsymdata, dynidx, sym); |
| |
| /* Add to the hash table. */ |
| hashidx = hashcodes[dynidx] % nbucket; |
| if (bucket[hashidx] == 0) |
| bucket[hashidx] = dynidx; |
| else |
| { |
| hashidx = bucket[hashidx]; |
| while (chain[hashidx] != 0) |
| hashidx = chain[hashidx]; |
| |
| chain[hashidx] = dynidx; |
| } |
| } |
| |
| free (hashcodes); |
| |
| /* We don't need the map from the symbol table index to the symbol |
| structure anymore. */ |
| free (ndxtosym); |
| |
| /* Create the required version section. */ |
| if (ld_state.verneedscnidx != 0) |
| { |
| Elf_Scn *verneedscn; |
| Elf_Data *verneeddata; |
| struct usedfiles *runp; |
| size_t verneed_size = xelf_fsize (ld_state.outelf, ELF_T_VNEED, 1); |
| size_t vernaux_size = xelf_fsize (ld_state.outelf, ELF_T_VNAUX, 1); |
| size_t offset; |
| int ntotal; |
| |
| verneedscn = elf_getscn (ld_state.outelf, ld_state.verneedscnidx); |
| xelf_getshdr (verneedscn, shdr); |
| verneeddata = elf_newdata (verneedscn); |
| if (shdr == NULL || verneeddata == NULL) |
| error (EXIT_FAILURE, 0, |
| gettext ("cannot create versioning data: %s"), |
| elf_errmsg (-1)); |
| |
| verneeddata->d_size = (ld_state.nverdeffile * verneed_size |
| + ld_state.nverdefused * vernaux_size); |
| verneeddata->d_buf = xmalloc (verneeddata->d_size); |
| verneeddata->d_type = ELF_T_VNEED; |
| verneeddata->d_align = xelf_fsize (ld_state.outelf, ELF_T_WORD, 1); |
| verneeddata->d_off = 0; |
| |
| offset = 0; |
| ntotal = ld_state.nverdeffile; |
| runp = ld_state.dsofiles->next; |
| do |
| { |
| offset = create_verneed_data (offset, verneeddata, runp, |
| &ntotal); |
| runp = runp->next; |
| } |
| while (ntotal > 0 && runp != ld_state.dsofiles->next); |
| |
| if (ntotal > 0) |
| { |
| runp = ld_state.needed->next; |
| do |
| { |
| offset = create_verneed_data (offset, verneeddata, runp, |
| &ntotal); |
| runp = runp->next; |
| } |
| while (ntotal > 0 && runp != ld_state.needed->next); |
| } |
| |
| assert (offset == verneeddata->d_size); |
| |
| /* Add the needed information to the section header. */ |
| shdr->sh_link = ld_state.dynstrscnidx; |
| shdr->sh_info = ld_state.nverdeffile; |
| (void) xelf_update_shdr (verneedscn, shdr); |
| } |
| |
| /* Adjust the section size. */ |
| dynsymdata->d_size = xelf_fsize (ld_state.outelf, ELF_T_SYM, nsym_dyn); |
| if (versymdata != NULL) |
| versymdata->d_size = xelf_fsize (ld_state.outelf, ELF_T_HALF, |
| nsym_dyn); |
| |
| /* Add the remaining information to the section header. */ |
| xelf_getshdr (dynsymscn, shdr); |
| /* There is always exactly one local symbol. */ |
| shdr->sh_info = 1; |
| /* Reference the string table. */ |
| shdr->sh_link = ld_state.dynstrscnidx; |
| /* Write the updated info back. */ |
| (void) xelf_update_shdr (dynsymscn, shdr); |
| } |
| else |
| /* We don't need the map from the symbol table index to the symbol |
| structure anymore. */ |
| free (ndxtosym); |
| |
| /* We don't need the string table anymore. */ |
| free (symstrent); |
| |
| /* Remember the total number of symbols in the dynamic symbol table. */ |
| ld_state.ndynsym = nsym_dyn; |
| |
| /* Fill in the section header information. */ |
| symscn = elf_getscn (ld_state.outelf, ld_state.symscnidx); |
| xelf_getshdr (symscn, shdr); |
| if (shdr == NULL) |
| error (EXIT_FAILURE, 0, |
| gettext ("cannot create symbol table for output file: %s"), |
| elf_errmsg (-1)); |
| |
| shdr->sh_type = SHT_SYMTAB; |
| shdr->sh_link = ld_state.strscnidx; |
| shdr->sh_info = nsym_local; |
| shdr->sh_entsize = xelf_fsize (ld_state.outelf, ELF_T_SYM, 1); |
| |
| (void) xelf_update_shdr (symscn, shdr); |
| |
| |
| /* Add names for the generated sections. */ |
| if (ld_state.symscnidx != 0) |
| symtab_ent = ebl_strtabadd (ld_state.shstrtab, ".symtab", 8); |
| if (ld_state.xndxscnidx != 0) |
| xndx_ent = ebl_strtabadd (ld_state.shstrtab, ".symtab_shndx", 14); |
| if (ld_state.strscnidx != 0) |
| strtab_ent = ebl_strtabadd (ld_state.shstrtab, ".strtab", 8); |
| /* At this point we would have to test for failures in the |
| allocation. But we skip this. First, the problem will be caught |
| latter when doing more allocations for the section header table. |
| Even if this would not be the case all that would happen is that |
| the section names are empty. The binary would still be usable if |
| it is an executable or a DSO. Not adding the test here saves |
| quite a bit of code. */ |
| |
| |
| /* Finally create the section for the section header string table. */ |
| shstrtab_scn = elf_newscn (ld_state.outelf); |
| shstrtab_ndx = elf_ndxscn (shstrtab_scn); |
| if (unlikely (shstrtab_ndx == SHN_UNDEF)) |
| error (EXIT_FAILURE, 0, |
| gettext ("cannot create section header string section: %s"), |
| elf_errmsg (-1)); |
| |
| /* Add the name of the section to the string table. */ |
| shstrtab_ent = ebl_strtabadd (ld_state.shstrtab, ".shstrtab", 10); |
| if (unlikely (shstrtab_ent == NULL)) |
| error (EXIT_FAILURE, errno, |
| gettext ("cannot create section header string section")); |
| |
| /* Finalize the section header string table. */ |
| data = elf_newdata (shstrtab_scn); |
| if (data == NULL) |
| error (EXIT_FAILURE, 0, |
| gettext ("cannot create section header string section: %s"), |
| elf_errmsg (-1)); |
| ebl_strtabfinalize (ld_state.shstrtab, data); |
| |
| /* Now we know the string offsets for all section names. */ |
| for (cnt = 0; cnt < ld_state.nallsections; ++cnt) |
| if (ld_state.allsections[cnt]->scnidx != 0) |
| { |
| Elf_Scn *scn; |
| |
| scn = elf_getscn (ld_state.outelf, ld_state.allsections[cnt]->scnidx); |
| |
| xelf_getshdr (scn, shdr); |
| assert (shdr != NULL); |
| |
| shdr->sh_name = ebl_strtaboffset (ld_state.allsections[cnt]->nameent); |
| |
| if (xelf_update_shdr (scn, shdr) == 0) |
| assert (0); |
| } |
| |
| /* Add the names for the generated sections to the respective |
| section headers. */ |
| if (symtab_ent != NULL) |
| { |
| Elf_Scn *scn = elf_getscn (ld_state.outelf, ld_state.symscnidx); |
| |
| xelf_getshdr (scn, shdr); |
| /* This cannot fail, we already accessed the header before. */ |
| assert (shdr != NULL); |
| |
| shdr->sh_name = ebl_strtaboffset (symtab_ent); |
| |
| (void) xelf_update_shdr (scn, shdr); |
| } |
| if (xndx_ent != NULL) |
| { |
| Elf_Scn *scn = elf_getscn (ld_state.outelf, ld_state.xndxscnidx); |
| |
| xelf_getshdr (scn, shdr); |
| /* This cannot fail, we already accessed the header before. */ |
| assert (shdr != NULL); |
| |
| shdr->sh_name = ebl_strtaboffset (xndx_ent); |
| |
| (void) xelf_update_shdr (scn, shdr); |
| } |
| if (strtab_ent != NULL) |
| { |
| Elf_Scn *scn = elf_getscn (ld_state.outelf, ld_state.strscnidx); |
| |
| xelf_getshdr (scn, shdr); |
| /* This cannot fail, we already accessed the header before. */ |
| assert (shdr != NULL); |
| |
| shdr->sh_name = ebl_strtaboffset (strtab_ent); |
| |
| (void) xelf_update_shdr (scn, shdr); |
| } |
| |
| /* And the section header table section itself. */ |
| xelf_getshdr (shstrtab_scn, shdr); |
| if (shdr == NULL) |
| error (EXIT_FAILURE, 0, |
| gettext ("cannot create section header string section: %s"), |
| elf_errmsg (-1)); |
| |
| shdr->sh_name = ebl_strtaboffset (shstrtab_ent); |
| shdr->sh_type = SHT_STRTAB; |
| |
| if (unlikely (xelf_update_shdr (shstrtab_scn, shdr) == 0)) |
| error (EXIT_FAILURE, 0, |
| gettext ("cannot create section header string section: %s"), |
| elf_errmsg (-1)); |
| |
| |
| /* Add the correct section header info to the section group sections. */ |
| groups = ld_state.groups; |
| while (groups != NULL) |
| { |
| Elf_Scn *scn; |
| struct scngroup *oldp; |
| Elf32_Word si; |
| |
| scn = elf_getscn (ld_state.outelf, groups->outscnidx); |
| xelf_getshdr (scn, shdr); |
| assert (shdr != NULL); |
| |
| shdr->sh_name = ebl_strtaboffset (groups->nameent); |
| shdr->sh_type = SHT_GROUP; |
| shdr->sh_flags = 0; |
| shdr->sh_link = ld_state.symscnidx; |
| shdr->sh_entsize = sizeof (Elf32_Word); |
| |
| /* Determine the index for the signature symbol. */ |
| si = groups->symbol->file->symindirect[groups->symbol->symidx]; |
| if (si == 0) |
| { |
| assert (groups->symbol->file->symref[groups->symbol->symidx] |
| != NULL); |
| si = groups->symbol->file->symref[groups->symbol->symidx]->outsymidx; |
| assert (si != 0); |
| } |
| shdr->sh_info = ld_state.dblindirect[si]; |
| |
| (void) xelf_update_shdr (scn, shdr); |
| |
| oldp = groups; |
| groups = groups->next; |
| free (oldp); |
| } |
| |
| |
| if (ld_state.file_type != relocatable_file_type) |
| { |
| size_t nphdr; |
| XElf_Addr addr; |
| struct output_segment *segment; |
| Elf_Scn *scn; |
| Elf32_Word nsec; |
| XElf_Phdr_vardef (phdr); |
| |
| /* Every executable needs a program header. The number of entries |
| varies. One exists for each segment. Each SHT_NOTE section gets |
| one, too. For dynamically linked executables we have to create |
| one for the program header, the interpreter, and the dynamic |
| section. First count the number of segments. |
| |
| XXX Determine whether the segment is non-empty. */ |
| nphdr = 0; |
| segment = ld_state.output_segments; |
| while (segment != NULL) |
| { |
| ++nphdr; |
| segment = segment->next; |
| } |
| |
| /* Add the number of SHT_NOTE sections. We counted them earlier. */ |
| nphdr += ld_state.nnotesections; |
| |
| /* If we create a DSO or the file is linked against DSOs we have three |
| more entries: INTERP, PHDR, DYNAMIC. */ |
| if (dynamically_linked_p ()) |
| nphdr += 3; |
| |
| /* Create the program header structure. */ |
| if (xelf_newphdr (ld_state.outelf, nphdr) == 0) |
| error (EXIT_FAILURE, 0, gettext ("cannot create program header: %s"), |
| elf_errmsg (-1)); |
| |
| |
| /* Determine the section sizes and offsets. We have to do this |
| to be able to determine the memory layout (which normally |
| differs from the file layout). */ |
| if (elf_update (ld_state.outelf, ELF_C_NULL) == -1) |
| error (EXIT_FAILURE, 0, gettext ("while determining file layout: %s"), |
| elf_errmsg (-1)); |
| |
| |
| /* Now determine the memory addresses of all the sections and |
| segments. */ |
| nsec = 0; |
| scn = elf_getscn (ld_state.outelf, ld_state.allsections[nsec]->scnidx); |
| xelf_getshdr (scn, shdr); |
| assert (shdr != NULL); |
| |
| /* The address we start with is the offset of the first (not |
| zeroth) section. */ |
| addr = shdr->sh_offset; |
| |
| /* The index of the first loadable segment. */ |
| nphdr = 1 + (dynamically_linked_p () == true) * 2; |
| |
| segment = ld_state.output_segments; |
| while (segment != NULL) |
| { |
| struct output_rule *orule; |
| bool first_section = true; |
| XElf_Off nobits_size = 0; |
| XElf_Off memsize = 0; |
| |
| /* the minimum alignment is a page size. */ |
| segment->align = ld_state.pagesize; |
| |
| for (orule = segment->output_rules; orule != NULL; |
| orule = orule->next) |
| if (orule->tag == output_section) |
| { |
| XElf_Off oldoff; |
| |
| /* See whether this output rule corresponds to the next |
| section. Yes, this is a pointer comparison. */ |
| if (ld_state.allsections[nsec]->name |
| != orule->val.section.name) |
| /* No, ignore this output rule. */ |
| continue; |
| |
| /* We assign addresses only in segments which are actually |
| loaded. */ |
| if (segment->mode != 0) |
| { |
| /* Adjust the offset of the input sections. */ |
| struct scninfo *isect; |
| struct scninfo *first; |
| |
| isect = first = ld_state.allsections[nsec]->last; |
| if (isect != NULL) |
| do |
| isect->offset += addr; |
| while ((isect = isect->next) != first); |
| |
| /* Set the address of current section. */ |
| shdr->sh_addr = addr; |
| |
| /* Write the result back. */ |
| (void) xelf_update_shdr (scn, shdr); |
| |
| /* Remember the address. */ |
| ld_state.allsections[nsec]->addr = addr; |
| } |
| |
| if (first_section) |
| { |
| /* The first segment starts at offset zero. */ |
| if (segment == ld_state.output_segments) |
| { |
| segment->offset = 0; |
| segment->addr = addr - shdr->sh_offset; |
| } |
| else |
| { |
| segment->offset = shdr->sh_offset; |
| segment->addr = addr; |
| } |
| |
| /* Determine the maximum alignment requirement. */ |
| segment->align = MAX (segment->align, shdr->sh_addralign); |
| |
| first_section = false; |
| } |
| |
| memsize = shdr->sh_offset - segment->offset + shdr->sh_size; |
| if (nobits_size != 0 && shdr->sh_type != SHT_NOTE) |
| error (EXIT_FAILURE, 0, gettext ("\ |
| internal error: nobits section follows nobits section")); |
| if (shdr->sh_type == SHT_NOBITS) |
| nobits_size += shdr->sh_size; |
| |
| /* Determine the new address which is computed using |
| the difference of the offsets on the sections. Note |
| that this assumes that the sections following each |
| other in the section header table are also |
| consecutive in the file. This is true here because |
| libelf constructs files this way. */ |
| oldoff = shdr->sh_offset; |
| |
| if (++nsec >= ld_state.nallsections) |
| break; |
| |
| scn = elf_getscn (ld_state.outelf, |
| ld_state.allsections[nsec]->scnidx); |
| xelf_getshdr (scn, shdr); |
| assert (shdr != NULL); |
| |
| /* This is the new address resulting from the offsets |
| in the file. */ |
| assert (oldoff <= shdr->sh_offset); |
| addr += shdr->sh_offset - oldoff; |
| } |
| else |
| { |
| assert (orule->tag == output_assignment); |
| |
| if (strcmp (orule->val.assignment->variable, ".") == 0) |
| /* This is a change of the address. */ |
| addr = eval_expression (orule->val.assignment->expression, |
| addr); |
| else if (orule->val.assignment->sym != NULL) |
| { |
| /* This symbol is used. Update the symbol table |
| entry. */ |
| XElf_Sym_vardef (sym); |
| size_t idx; |
| |
| /* Note that we do not have to use |
| xelf_getsymshndx since we only update the |
| symbol address, not the section |
| information. */ |
| idx = dblindirect[orule->val.assignment->sym->outsymidx]; |
| xelf_getsym (symdata, idx, sym); |
| sym->st_value = addr; |
| (void) xelf_update_sym (symdata, idx, sym); |
| |
| idx = orule->val.assignment->sym->outdynsymidx; |
| if (idx != 0) |
| { |
| assert (dynsymdata != NULL); |
| xelf_getsym (dynsymdata, idx, sym); |
| sym->st_value = addr; |
| (void) xelf_update_sym (dynsymdata, idx, sym); |
| } |
| } |
| } |
| |
| /* Store the segment parameter for loadable segments. */ |
| if (segment->mode != 0) |
| { |
| xelf_getphdr_ptr (ld_state.outelf, nphdr, phdr); |
| |
| phdr->p_type = PT_LOAD; |
| phdr->p_offset = segment->offset; |
| phdr->p_vaddr = segment->addr; |
| phdr->p_paddr = phdr->p_vaddr; |
| phdr->p_filesz = memsize - nobits_size; |
| phdr->p_memsz = memsize; |
| phdr->p_flags = segment->mode; |
| phdr->p_align = segment->align; |
| |
| (void) xelf_update_phdr (ld_state.outelf, nphdr, phdr); |
| ++nphdr; |
| } |
| |
| segment = segment->next; |
| } |
| |
| /* Create the other program header entries. */ |
| xelf_getehdr (ld_state.outelf, ehdr); |
| assert (ehdr != NULL); |
| |
| xelf_getphdr_ptr (ld_state.outelf, 1, phdr); |
| phdr->p_type = PT_PHDR; |
| phdr->p_offset = ehdr->e_phoff; |
| phdr->p_vaddr = ld_state.output_segments->addr + phdr->p_offset; |
| phdr->p_paddr = phdr->p_vaddr; |
| phdr->p_filesz = ehdr->e_phnum * ehdr->e_phentsize; |
| phdr->p_memsz = phdr->p_filesz; |
| phdr->p_flags = 0; /* No need to set PF_R or so. */ |
| phdr->p_align = xelf_fsize (ld_state.outelf, ELF_T_ADDR, 1); |
| (void) xelf_update_phdr (ld_state.outelf, 0, phdr); |
| |
| |
| /* Adjust the addresses in the addresses of the symbol according |
| to the load addresses of the sections. */ |
| if (ld_state.need_symtab) |
| for (cnt = 1; cnt < nsym; ++cnt) |
| { |
| XElf_Sym_vardef (sym); |
| Elf32_Word shndx; |
| |
| xelf_getsymshndx (symdata, xndxdata, cnt, sym, shndx); |
| assert (sym != NULL); |
| |
| if (sym->st_shndx != SHN_XINDEX) |
| shndx = sym->st_shndx; |
| |
| if ((shndx > SHN_UNDEF && shndx < SHN_LORESERVE) |
| || shndx > SHN_HIRESERVE) |
| { |
| /* Note we subtract 1 from the section index since ALLSECTIONS |
| does not store the dummy section with offset zero. */ |
| sym->st_value += ld_state.allsections[shndx - 1]->addr; |
| |
| /* We don't have to use 'xelf_update_symshndx' since the |
| section number doesn't change. */ |
| (void) xelf_update_sym (symdata, cnt, sym); |
| } |
| } |
| |
| if (ld_state.need_dynsym) |
| for (cnt = 1; cnt < nsym_dyn; ++cnt) |
| { |
| XElf_Sym_vardef (sym); |
| |
| xelf_getsym (dynsymdata, cnt, sym); |
| assert (sym != NULL); |
| |
| if (sym->st_shndx > SHN_UNDEF && sym->st_shndx < SHN_LORESERVE) |
| { |
| /* Note we subtract 1 from the section index since ALLSECTIONS |
| does not store the dummy section with offset zero. */ |
| sym->st_value += ld_state.allsections[sym->st_shndx - 1]->addr; |
| |
| /* We don't have to use 'xelf_update_symshndx' since the |
| section number doesn't change. */ |
| (void) xelf_update_sym (dynsymdata, cnt, sym); |
| } |
| } |
| |
| |
| /* Now is a good time to determine the values of all the symbols |
| we encountered. */ |
| // XXX This loop is very inefficient. The hash tab iterator also |
| // returns all symbols in DSOs. |
| struct symbol *se; |
| void *p = NULL; |
| while ((se = ld_symbol_tab_iterate (&ld_state.symbol_tab, &p)) != NULL) |
| if (! se->in_dso) |
| { |
| XElf_Sym_vardef (sym); |
| |
| addr = 0; |
| |
| if (se->outdynsymidx != 0) |
| { |
| xelf_getsym (dynsymdata, se->outdynsymidx, sym); |
| assert (sym != NULL); |
| addr = sym->st_value; |
| } |
| else if (se->outsymidx != 0) |
| { |
| assert (dblindirect[se->outsymidx] != 0); |
| xelf_getsym (symdata, dblindirect[se->outsymidx], sym); |
| assert (sym != NULL); |
| addr = sym->st_value; |
| } |
| else |
| abort (); |
| |
| se->merge.value = addr; |
| } |
| |
| /* Complete the header of the .rel.dyn/.rela.dyn section. Point |
| to the symbol table. The sh_info field is left zero since |
| there is no specific section the contained relocations are |
| for. */ |
| if (ld_state.reldynscnidx != 0) |
| { |
| assert (ld_state.dynsymscnidx != 0); |
| scn = elf_getscn (ld_state.outelf, ld_state.reldynscnidx); |
| xelf_getshdr (scn, shdr); |
| assert (shdr != NULL); |
| |
| shdr->sh_link = ld_state.dynsymscnidx; |
| |
| (void) xelf_update_shdr (scn, shdr); |
| } |
| |
| /* Fill in the dynamic segment/section. */ |
| if (dynamically_linked_p ()) |
| { |
| Elf_Scn *outscn; |
| |
| assert (ld_state.interpscnidx != 0); |
| xelf_getshdr (elf_getscn (ld_state.outelf, ld_state.interpscnidx), |
| shdr); |
| assert (shdr != NULL); |
| |
| /* The interpreter string. */ |
| // XXX Do we need to support files (DSOs) without interpreters? |
| xelf_getphdr_ptr (ld_state.outelf, 1, phdr); |
| phdr->p_type = PT_INTERP; |
| phdr->p_offset = shdr->sh_offset; |
| phdr->p_vaddr = shdr->sh_addr; |
| phdr->p_paddr = phdr->p_vaddr; |
| phdr->p_filesz = shdr->sh_size; |
| phdr->p_memsz = phdr->p_filesz; |
| phdr->p_flags = 0; /* No need to set PF_R or so. */ |
| phdr->p_align = 1; /* It's a string. */ |
| |
| (void) xelf_update_phdr (ld_state.outelf, 1, phdr); |
| |
| /* The pointer to the dynamic section. We this we need to |
| get the information for the dynamic section first. */ |
| assert (ld_state.dynamicscnidx); |
| outscn = elf_getscn (ld_state.outelf, ld_state.dynamicscnidx); |
| xelf_getshdr (outscn, shdr); |
| assert (shdr != NULL); |
| |
| xelf_getphdr_ptr (ld_state.outelf, 2, phdr); |
| phdr->p_type = PT_DYNAMIC; |
| phdr->p_offset = shdr->sh_offset; |
| phdr->p_vaddr = shdr->sh_addr; |
| phdr->p_paddr = phdr->p_vaddr; |
| phdr->p_filesz = shdr->sh_size; |
| phdr->p_memsz = phdr->p_filesz; |
| phdr->p_flags = 0; /* No need to set PF_R or so. */ |
| phdr->p_align = shdr->sh_addralign; |
| |
| (void) xelf_update_phdr (ld_state.outelf, 2, phdr); |
| |
| /* Fill in the reference to the .dynstr section. */ |
| assert (ld_state.dynstrscnidx != 0); |
| shdr->sh_link = ld_state.dynstrscnidx; |
| (void) xelf_update_shdr (outscn, shdr); |
| |
| /* And fill the remaining entries. */ |
| Elf_Data *dyndata = elf_getdata (outscn, NULL); |
| assert (dyndata != NULL); |
| |
| /* Add the DT_NEEDED entries. */ |
| if (ld_state.ndsofiles > 0) |
| { |
| struct usedfiles *runp = ld_state.dsofiles->next; |
| |
| do |
| if (! ld_state.ignore_unused_dsos || runp->used) |
| { |
| /* Add the position-dependent flag if necessary. */ |
| if (runp->lazyload) |
| new_dynamic_entry (dyndata, ld_state.ndynamic_filled++, |
| DT_POSFLAG_1, DF_P1_LAZYLOAD); |
| |
| new_dynamic_entry (dyndata, ld_state.ndynamic_filled++, |
| DT_NEEDED, |
| ebl_strtaboffset (runp->sonameent)); |
| } |
| while ((runp = runp->next) != ld_state.dsofiles->next); |
| } |
| |
| /* We can finish the DT_RUNPATH/DT_RPATH entries now. */ |
| if (ld_state.rxxpath_strent != NULL) |
| new_dynamic_entry (dyndata, ld_state.ndynamic_filled++, |
| ld_state.rxxpath_tag, |
| ebl_strtaboffset (ld_state.rxxpath_strent)); |
| |
| /* Reference to initialization and finalization functions. */ |
| // XXX This code depends on symbol table being relocated. |
| if (ld_state.init_symbol != NULL) |
| { |
| XElf_Sym_vardef (sym); |
| |
| if (ld_state.need_symtab) |
| xelf_getsym (symdata, |
| dblindirect[ld_state.init_symbol->outsymidx], |
| sym); |
| else |
| xelf_getsym (dynsymdata, ld_state.init_symbol->outdynsymidx, |
| sym); |
| assert (sym != NULL); |
| |
| new_dynamic_entry (dyndata, ld_state.ndynamic_filled++, |
| DT_INIT, sym->st_value); |
| } |
| if (ld_state.fini_symbol != NULL) |
| { |
| XElf_Sym_vardef (sym); |
| |
| if (ld_state.need_symtab) |
| xelf_getsym (symdata, |
| dblindirect[ld_state.fini_symbol->outsymidx], |
| sym); |
| else |
| xelf_getsym (dynsymdata, ld_state.fini_symbol->outdynsymidx, |
| sym); |
| assert (sym != NULL); |
| |
| new_dynamic_entry (dyndata, ld_state.ndynamic_filled++, |
| DT_FINI, sym->st_value); |
| } |
| // XXX Support init,fini,preinit arrays |
| |
| /* The hash table which comes with dynamic symbol table. */ |
| xelf_getshdr (elf_getscn (ld_state.outelf, ld_state.hashscnidx), |
| shdr); |
| assert (shdr != NULL); |
| new_dynamic_entry (dyndata, ld_state.ndynamic_filled++, DT_HASH, |
| shdr->sh_addr); |
| |
| /* Reference to the symbol table section. */ |
| assert (ld_state.dynsymscnidx != 0); |
| xelf_getshdr (elf_getscn (ld_state.outelf, ld_state.dynsymscnidx), |
| shdr); |
| assert (shdr != NULL); |
| new_dynamic_entry (dyndata, ld_state.ndynamic_filled++, DT_SYMTAB, |
| shdr->sh_addr); |
| |
| new_dynamic_entry (dyndata, ld_state.ndynamic_filled++, DT_SYMENT, |
| xelf_fsize (ld_state.outelf, ELF_T_SYM, 1)); |
| |
| /* And the string table which comes with it. */ |
| xelf_getshdr (elf_getscn (ld_state.outelf, ld_state.dynstrscnidx), |
| shdr); |
| assert (shdr != NULL); |
| new_dynamic_entry (dyndata, ld_state.ndynamic_filled++, DT_STRTAB, |
| shdr->sh_addr); |
| |
| new_dynamic_entry (dyndata, ld_state.ndynamic_filled++, DT_STRSZ, |
| shdr->sh_size); |
| |
| /* Add the entries related to the .plt. */ |
| if (ld_state.nplt > 0) |
| { |
| xelf_getshdr (elf_getscn (ld_state.outelf, ld_state.gotscnidx), |
| shdr); |
| assert (shdr != NULL); |
| new_dynamic_entry (dyndata, ld_state.ndynamic_filled++, |
| // XXX This should probably be machine |
| // dependent. |
| DT_PLTGOT, shdr->sh_addr); |
| |
| xelf_getshdr (elf_getscn (ld_state.outelf, |
| ld_state.pltrelscnidx), shdr); |
| assert (shdr != NULL); |
| new_dynamic_entry (dyndata, ld_state.ndynamic_filled++, |
| DT_PLTRELSZ, shdr->sh_size); |
| |
| new_dynamic_entry (dyndata, ld_state.ndynamic_filled++, |
| DT_JMPREL, shdr->sh_addr); |
| |
| new_dynamic_entry (dyndata, ld_state.ndynamic_filled++, |
| DT_PLTREL, REL_TYPE (statep)); |
| } |
| |
| if (ld_state.relsize_total > 0) |
| { |
| int rel = REL_TYPE (statep); |
| xelf_getshdr (elf_getscn (ld_state.outelf, |
| ld_state.reldynscnidx), shdr); |
| assert (shdr != NULL); |
| new_dynamic_entry (dyndata, ld_state.ndynamic_filled++, |
| rel, shdr->sh_addr); |
| |
| /* Trick ahead. Use arithmetic to get the right tag. |
| We check the validity of this assumption in the asserts. */ |
| assert (DT_RELASZ - DT_RELA == 1); |
| assert (DT_RELSZ - DT_REL == 1); |
| new_dynamic_entry (dyndata, ld_state.ndynamic_filled++, |
| rel + 1, shdr->sh_size); |
| |
| /* Similar for the entry size tag. */ |
| assert (DT_RELAENT - DT_RELA == 2); |
| assert (DT_RELENT - DT_REL == 2); |
| new_dynamic_entry (dyndata, ld_state.ndynamic_filled++, |
| rel + 2, |
| rel == DT_REL |
| ? xelf_fsize (ld_state.outelf, ELF_T_REL, 1) |
| : xelf_fsize (ld_state.outelf, ELF_T_RELA, |
| 1)); |
| } |
| |
| if (ld_state.verneedscnidx != 0) |
| { |
| xelf_getshdr (elf_getscn (ld_state.outelf, |
| ld_state.verneedscnidx), shdr); |
| assert (shdr != NULL); |
| new_dynamic_entry (dyndata, ld_state.ndynamic_filled++, |
| DT_VERNEED, shdr->sh_addr); |
| |
| new_dynamic_entry (dyndata, ld_state.ndynamic_filled++, |
| DT_VERNEEDNUM, ld_state.nverdeffile); |
| } |
| |
| if (ld_state.versymscnidx != 0) |
| { |
| xelf_getshdr (elf_getscn (ld_state.outelf, |
| ld_state.versymscnidx), shdr); |
| assert (shdr != NULL); |
| new_dynamic_entry (dyndata, ld_state.ndynamic_filled++, |
| DT_VERSYM, shdr->sh_addr); |
| } |
| |
| /* We always create the DT_DEBUG entry. */ |
| new_dynamic_entry (dyndata, ld_state.ndynamic_filled++, DT_DEBUG, 0); |
| assert (ld_state.ndynamic_filled < ld_state.ndynamic); |
| |
| /* Add the flag words if necessary. */ |
| if (ld_state.dt_flags != 0) |
| new_dynamic_entry (dyndata, ld_state.ndynamic_filled++, DT_FLAGS, |
| ld_state.dt_flags); |
| |
| /* Create entry for the DT_FLAGS_1 flag. */ |
| if (ld_state.dt_flags_1 != 0) |
| new_dynamic_entry (dyndata, ld_state.ndynamic_filled++, |
| DT_FLAGS_1, ld_state.dt_flags_1); |
| |
| /* Create entry for the DT_FEATURE_1 flag. */ |
| if (ld_state.dt_feature_1 != 0) |
| new_dynamic_entry (dyndata, ld_state.ndynamic_filled++, |
| DT_FEATURE_1, ld_state.dt_feature_1); |
| |
| assert (ld_state.ndynamic_filled <= ld_state.ndynamic); |
| } |
| } |
| |
| |
| // XXX The following code isn't nice. We use two different |
| // mechanisms to handle relocations, one for relocatable files, one |
| // for executables and DSOs. Maybe this is the best method but also |
| // maybe it can be somewhat unified. |
| |
| /* Now that we created the symbol table we can add the reference to |
| it in the sh_link field of the section headers of the relocation |
| sections. */ |
| while (rellist != NULL) |
| { |
| assert (ld_state.file_type == relocatable_file_type); |
| Elf_Scn *outscn; |
| |
| outscn = elf_getscn (ld_state.outelf, rellist->scnidx); |
| xelf_getshdr (outscn, shdr); |
| /* This must not fail since we did it before. */ |
| assert (shdr != NULL); |
| |
| /* Remember the symbol table which belongs to the relocation section. */ |
| shdr->sh_link = ld_state.symscnidx; |
| |
| /* And the reference to the section which is relocated by this |
| relocation section. We use the info from the first input |
| section but all records should have the same information. */ |
| shdr->sh_info = |
| rellist->scninfo->fileinfo->scninfo[SCNINFO_SHDR (rellist->scninfo->shdr).sh_info].outscnndx; |
| |
| |
| /* Perform the actual relocations. We only have to adjust |
| offsets and symbol indices. */ |
| RELOCATE_SECTION (statep, outscn, rellist->scninfo, dblindirect); |
| |
| /* Store the changes. */ |
| (void) xelf_update_shdr (outscn, shdr); |
| |
| /* Up to the next relocation section. */ |
| rellist = rellist->next; |
| } |
| |
| if (ld_state.rellist != NULL) |
| { |
| assert (ld_state.file_type != relocatable_file_type); |
| /* Create the relocations for the output file. */ |
| CREATE_RELOCATIONS (statep, dblindirect); |
| } |
| |
| |
| /* We need the ELF header once more. */ |
| xelf_getehdr (ld_state.outelf, ehdr); |
| assert (ehdr != NULL); |
| |
| /* Set the section header string table index. */ |
| if (likely (shstrtab_ndx < SHN_HIRESERVE) |
| && likely (shstrtab_ndx != SHN_XINDEX)) |
| ehdr->e_shstrndx = shstrtab_ndx; |
| else |
| { |
| /* We have to put the section index in the sh_link field of the |
| zeroth section header. */ |
| Elf_Scn *scn = elf_getscn (ld_state.outelf, 0); |
| |
| xelf_getshdr (scn, shdr); |
| if (unlikely (shdr == NULL)) |
| error (EXIT_FAILURE, 0, |
| gettext ("cannot get header of 0th section: %s"), |
| elf_errmsg (-1)); |
| |
| shdr->sh_link = shstrtab_ndx; |
| |
| (void) xelf_update_shdr (scn, shdr); |
| |
| ehdr->e_shstrndx = SHN_XINDEX; |
| } |
| |
| if (ld_state.file_type != relocatable_file_type) |
| /* DSOs and executables have to define the entry point symbol. */ |
| ehdr->e_entry = find_entry_point (); |
| |
| if (unlikely (xelf_update_ehdr (ld_state.outelf, ehdr) == 0)) |
| error (EXIT_FAILURE, 0, |
| gettext ("cannot update ELF header: %s"), |
| elf_errmsg (-1)); |
| |
| |
| /* Free the data which we don't need anymore. */ |
| free (ld_state.dblindirect); |
| |
| |
| /* Finalize the .plt section the what belongs to them. */ |
| FINALIZE_PLT (statep, nsym, nsym_dyn); |
| |
| return 0; |
| } |
| |
| |
| /* This is a function which must be specified in all backends. */ |
| static void |
| ld_generic_relocate_section (struct ld_state *statep, Elf_Scn *outscn, |
| struct scninfo *firstp, |
| const Elf32_Word *dblindirect) |
| { |
| error (EXIT_FAILURE, 0, gettext ("\ |
| linker backend didn't specify function to relocate section")); |
| /* NOTREACHED */ |
| } |
| |
| |
| /* Finalize the output file. */ |
| static int |
| ld_generic_finalize (struct ld_state *statep) |
| { |
| /* Write out the ELF file data. */ |
| if (elf_update (ld_state.outelf, ELF_C_WRITE) == -1) |
| error (EXIT_FAILURE, 0, gettext ("while writing output file: %s"), |
| elf_errmsg (-1)); |
| |
| /* Free the resources. */ |
| if (elf_end (ld_state.outelf) != 0) |
| error (EXIT_FAILURE, 0, gettext ("while finishing output file: %s"), |
| elf_errmsg (-1)); |
| |
| /* Get the file status of the temporary file. */ |
| struct stat temp_st; |
| if (fstat (ld_state.outfd, &temp_st) != 0) |
| error (EXIT_FAILURE, errno, gettext ("cannot stat output file")); |
| |
| /* Now it's time to rename the file. Remove an old existing file |
| first. */ |
| if (rename (ld_state.tempfname, ld_state.outfname) != 0) |
| /* Something went wrong. */ |
| error (EXIT_FAILURE, errno, gettext ("cannot rename output file")); |
| |
| /* Make sure the output file is really the one we created. */ |
| struct stat new_st; |
| if (stat (ld_state.outfname, &new_st) != 0 |
| || new_st.st_ino != temp_st.st_ino |
| || new_st.st_dev != temp_st.st_dev) |
| { |
| /* Wow, somebody overwrote the output file, probably some intruder. */ |
| unlink (ld_state.outfname); |
| error (EXIT_FAILURE, 0, gettext ("\ |
| WARNING: temporary output file overwritten before linking finished")); |
| } |
| |
| /* Close the file descriptor. */ |
| (void) close (ld_state.outfd); |
| |
| /* Signal the cleanup handler that the file is correctly created. */ |
| ld_state.tempfname = NULL; |
| |
| return 0; |
| } |
| |
| |
| static bool |
| ld_generic_special_section_number_p (struct ld_state *statep, size_t number) |
| { |
| /* There are no special section numbers in the gABI. */ |
| return false; |
| } |
| |
| |
| static bool |
| ld_generic_section_type_p (struct ld_state *statep, GElf_Word type) |
| { |
| if (type < SHT_NUM |
| /* XXX Enable the following two when implemented. */ |
| // || type == SHT_GNU_LIBLIST |
| // || type == SHT_CHECKSUM |
| /* XXX Eventually include SHT_SUNW_move, SHT_SUNW_COMDAT, and |
| SHT_SUNW_syminfo. */ |
| || (type >= SHT_GNU_verdef && type <= SHT_GNU_versym)) |
| return true; |
| |
| return false; |
| } |
| |
| |
| static XElf_Xword |
| ld_generic_dynamic_section_flags (struct ld_state *statep) |
| { |
| /* By default the .dynamic section is writable (and is of course |
| loaded). Few architecture differ from this. */ |
| return SHF_ALLOC | SHF_WRITE; |
| } |
| |
| |
| static void |
| ld_generic_initialize_plt (struct ld_state *statep, Elf_Scn *scn) |
| { |
| /* This cannot be implemented generally. There should have been a |
| machine dependent implementation and we should never have arrived |
| here. */ |
| error (EXIT_FAILURE, 0, gettext ("no machine specific '%s' implementation"), |
| "initialize_plt"); |
| } |
| |
| |
| static void |
| ld_generic_initialize_pltrel (struct ld_state *statep, Elf_Scn *scn) |
| { |
| /* This cannot be implemented generally. There should have been a |
| machine dependent implementation and we should never have arrived |
| here. */ |
| error (EXIT_FAILURE, 0, gettext ("no machine specific '%s' implementation"), |
| "initialize_pltrel"); |
| } |
| |
| |
| static void |
| ld_generic_initialize_got (struct ld_state *statep, Elf_Scn *scn) |
| { |
| /* This cannot be implemented generally. There should have been a |
| machine dependent implementation and we should never have arrived |
| here. */ |
| error (EXIT_FAILURE, 0, gettext ("no machine specific '%s' implementation"), |
| "initialize_got"); |
| } |
| |
| |
| static void |
| ld_generic_finalize_plt (struct ld_state *statep, size_t nsym, size_t nsym_dyn) |
| { |
| /* By default we assume that nothing has to be done. */ |
| } |
| |
| |
| static int |
| ld_generic_rel_type (struct ld_state *statep) |
| { |
| /* This cannot be implemented generally. There should have been a |
| machine dependent implementation and we should never have arrived |
| here. */ |
| error (EXIT_FAILURE, 0, gettext ("no machine specific '%s' implementation"), |
| "rel_type"); |
| /* Just to keep the compiler calm. */ |
| return 0; |
| } |
| |
| |
| static void |
| ld_generic_count_relocations (struct ld_state *statep, struct scninfo *scninfo) |
| { |
| /* This cannot be implemented generally. There should have been a |
| machine dependent implementation and we should never have arrived |
| here. */ |
| error (EXIT_FAILURE, 0, gettext ("no machine specific '%s' implementation"), |
| "count_relocations"); |
| } |
| |
| |
| static void |
| ld_generic_create_relocations (struct ld_state *statep, |
| const Elf32_Word *dblindirect) |
| { |
| /* This cannot be implemented generally. There should have been a |
| machine dependent implementation and we should never have arrived |
| here. */ |
| error (EXIT_FAILURE, 0, gettext ("no machine specific '%s' implementation"), |
| "create_relocations"); |
| } |