summaryrefslogtreecommitdiffstats
path: root/src/strip.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/strip.c')
-rw-r--r--src/strip.c1769
1 files changed, 0 insertions, 1769 deletions
diff --git a/src/strip.c b/src/strip.c
deleted file mode 100644
index e5c4289c..00000000
--- a/src/strip.c
+++ /dev/null
@@ -1,1769 +0,0 @@
-/* Discard section not used at runtime from object files.
- Copyright (C) 2000, 2001, 2002, 2003, 2004 Red Hat, Inc.
- Written by Ulrich Drepper <drepper@redhat.com>, 2000.
-
- 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 <argp.h>
-#include <assert.h>
-#include <byteswap.h>
-#include <endian.h>
-#include <error.h>
-#include <fcntl.h>
-#include <gelf.h>
-#include <libelf.h>
-#include <libintl.h>
-#include <locale.h>
-#include <mcheck.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdio_ext.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/param.h>
-#include <sys/time.h>
-
-#include <elf-knowledge.h>
-#include <libebl.h>
-#include <system.h>
-
-
-/* Name and version of program. */
-static void print_version (FILE *stream, struct argp_state *state);
-void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version;
-
-
-/* Values for the parameters which have no short form. */
-#define OPT_REMOVE_COMMENT 0x100
-#define OPT_PERMISSIVE 0x101
-
-
-/* Definitions of arguments for argp functions. */
-static const struct argp_option options[] =
-{
- { NULL, 0, NULL, 0, N_("Output selection:") },
- { NULL, 'o', "FILE", 0, N_("Place stripped output into FILE") },
- { NULL, 'f', "FILE", 0, N_("Extract the removed sections into FILE") },
-
- { NULL, 0, NULL, 0, N_("Output options:") },
- { "strip-debug", 'g', NULL, 0, N_("Remove all debugging symbols") },
- { "preserve-dates", 'p', NULL, 0,
- N_("Copy modified/access timestamps to the output") },
- { "remove-comment", OPT_REMOVE_COMMENT, NULL, 0,
- N_("Remove .comment section") },
- { "permissive", OPT_PERMISSIVE, NULL, 0,
- N_("Relax a few rules to handle slightly broken ELF files") },
- { NULL, 0, NULL, 0, NULL }
-};
-
-/* Short description of program. */
-static const char doc[] = N_("Discard symbols from object files.");
-
-/* Strings for arguments in help texts. */
-static const char args_doc[] = N_("[FILE...]");
-
-/* Prototype for option handler. */
-static error_t parse_opt (int key, char *arg, struct argp_state *state);
-
-/* Function to print some extra text in the help message. */
-static char *more_help (int key, const char *text, void *input);
-
-/* Data structure to communicate with argp functions. */
-static struct argp argp =
-{
- options, parse_opt, args_doc, doc, NULL, more_help
-};
-
-
-/* Print symbols in file named FNAME. */
-static int process_file (const char *fname);
-
-/* Handle one ELF file. */
-static int handle_elf (int fd, Elf *elf, const char *prefix,
- const char *fname, mode_t mode, struct timeval tvp[2]);
-
-/* Handle all files contained in the archive. */
-static int handle_ar (int fd, Elf *elf, const char *prefix, const char *fname,
- struct timeval tvp[2]);
-
-#define INTERNAL_ERROR(fname) \
- error (EXIT_FAILURE, 0, gettext ("%s: INTERNAL ERROR %d (%s-%s): %s"), \
- fname, __LINE__, VERSION, __DATE__, elf_errmsg (-1))
-
-
-/* Name of the output file. */
-static const char *output_fname;
-
-/* Name of the debug output file. */
-static const char *debug_fname;
-
-/* If true output files shall have same date as the input file. */
-static bool preserve_dates;
-
-/* If true .comment sections will be removed. */
-static bool remove_comment;
-
-/* If true remove all debug sections. */
-static bool remove_debug;
-
-/* If true relax some ELF rules for input files. */
-static bool permissive;
-
-
-int
-main (int argc, char *argv[])
-{
- int remaining;
- int result = 0;
-
- /* Make memory leak detection possible. */
- mtrace ();
-
- /* We use no threads here which can interfere with handling a stream. */
- __fsetlocking (stdin, FSETLOCKING_BYCALLER);
- __fsetlocking (stdout, FSETLOCKING_BYCALLER);
- __fsetlocking (stderr, FSETLOCKING_BYCALLER);
-
- /* Set locale. */
- setlocale (LC_ALL, "");
-
- /* Make sure the message catalog can be found. */
- bindtextdomain (PACKAGE, LOCALEDIR);
-
- /* Initialize the message catalog. */
- textdomain (PACKAGE);
-
- /* Parse and process arguments. */
- argp_parse (&argp, argc, argv, 0, &remaining, NULL);
-
- /* Tell the library which version we are expecting. */
- elf_version (EV_CURRENT);
-
- if (remaining == argc)
- /* The user didn't specify a name so we use a.out. */
- result = process_file ("a.out");
- else
- {
- /* If we have seen the `-o' or '-f' option there must be exactly one
- input file. */
- if ((output_fname != NULL || debug_fname != NULL)
- && remaining + 1 < argc)
- error (EXIT_FAILURE, 0, gettext ("\
-Only one input file allowed together with '-o' and '-f'"));
-
- /* Process all the remaining files. */
- do
- result |= process_file (argv[remaining]);
- while (++remaining < argc);
- }
-
- return result;
-}
-
-
-/* Print the version information. */
-static void
-print_version (FILE *stream, struct argp_state *state)
-{
- fprintf (stream, "strip (%s) %s\n", PACKAGE_NAME, VERSION);
- fprintf (stream, gettext ("\
-Copyright (C) %s Red Hat, Inc.\n\
-This is free software; see the source for copying conditions. There is NO\n\
-warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
-"), "2004");
- fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper");
-}
-
-
-/* Handle program arguments. */
-static error_t
-parse_opt (int key, char *arg, struct argp_state *state)
-{
- switch (key)
- {
- case 'f':
- debug_fname = arg;
- break;
-
- case 'o':
- output_fname = arg;
- break;
-
- case 'p':
- preserve_dates = true;
- break;
-
- case OPT_REMOVE_COMMENT:
- remove_comment = true;
- break;
-
- case 'g':
- remove_debug = true;
- break;
-
- case OPT_PERMISSIVE:
- permissive = true;
- break;
-
- default:
- return ARGP_ERR_UNKNOWN;
- }
- return 0;
-}
-
-
-static char *
-more_help (int key, const char *text, void *input)
-{
- char *buf;
-
- switch (key)
- {
- case ARGP_KEY_HELP_EXTRA:
- /* We print some extra information. */
- if (asprintf (&buf, gettext ("Please report bugs to %s.\n"),
- PACKAGE_BUGREPORT) < 0)
- buf = NULL;
- return buf;
-
- default:
- break;
- }
- return (char *) text;
-}
-
-
-static int
-process_file (const char *fname)
-{
- /* If we have to preserve the modify and access timestamps get them
- now. We cannot use fstat() after opening the file since the open
- would change the access time. */
- struct stat64 pre_st;
- struct timeval tv[2];
- again:
- if (preserve_dates)
- {
- if (stat64 (fname, &pre_st) != 0)
- {
- error (0, errno, gettext ("cannot stat input file \"%s\""), fname);
- return 1;
- }
-
- /* If we have to preserve the timestamp, we need it in the
- format utimes() understands. */
- TIMESPEC_TO_TIMEVAL (&tv[0], &pre_st.st_atim);
- TIMESPEC_TO_TIMEVAL (&tv[1], &pre_st.st_mtim);
- }
-
- /* Open the file. */
- int fd = open (fname, O_RDWR);
- if (fd == -1)
- {
- error (0, errno, gettext ("while opening \"%s\""), fname);
- return 1;
- }
-
- /* We always use fstat() even if we called stat() before. This is
- done to make sure the information returned by stat() is for the
- same file. */
- struct stat64 st;
- if (fstat64 (fd, &st) != 0)
- {
- error (0, errno, gettext ("cannot stat input file \"%s\""), fname);
- return 1;
- }
- /* Paranoid mode on. */
- if (preserve_dates
- && (st.st_ino != pre_st.st_ino || st.st_dev != pre_st.st_dev))
- {
- /* We detected a race. Try again. */
- close (fd);
- goto again;
- }
-
- /* Now get the ELF descriptor. */
- Elf *elf = elf_begin (fd, ELF_C_RDWR, NULL);
- int result;
- switch (elf_kind (elf))
- {
- case ELF_K_ELF:
- result = handle_elf (fd, elf, NULL, fname, st.st_mode & ACCESSPERMS,
- preserve_dates ? tv : NULL);
- break;
-
- case ELF_K_AR:
- /* It is not possible to strip the content of an archive direct
- the output to a specific file. */
- if (unlikely (output_fname != NULL))
- {
- error (0, 0, gettext ("%s: cannot use -o when stripping archive"),
- fname);
- result = 1;
- }
- else
- result = handle_ar (fd, elf, NULL, fname, preserve_dates ? tv : NULL);
- break;
-
- default:
- error (0, 0, gettext ("%s: File format not recognized"), fname);
- result = 1;
- break;
- }
-
- if (unlikely (elf_end (elf) != 0))
- INTERNAL_ERROR (fname);
-
- close (fd);
-
- return result;
-}
-
-
-/* Maximum size of array allocated on stack. */
-#define MAX_STACK_ALLOC (400 * 1024)
-
-
-static uint32_t
-crc32_file (int fd, uint32_t *resp)
-{
- unsigned char buffer[1024 * 8];
- uint32_t crc = 0;
- ssize_t count;
-
- /* We have to rewind. */
- if (lseek (fd, 0, SEEK_SET) < 0)
- return 1;
-
- while ((count = TEMP_FAILURE_RETRY (read (fd, buffer, sizeof (buffer)))) > 0)
- crc = crc32 (crc, buffer, count);
-
- *resp = crc;
-
- return count != 0;
-}
-
-
-static int
-handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
- mode_t mode, struct timeval tvp[2])
-{
- size_t prefix_len = prefix == NULL ? 0 : strlen (prefix);
- size_t fname_len = strlen (fname) + 1;
- char *fullname = alloca (prefix_len + 1 + fname_len);
- char *cp = fullname;
- Elf *newelf;
- Elf *debugelf = NULL;
- char *tmp_debug_fname = NULL;
- int result = 0;
- GElf_Ehdr ehdr_mem;
- GElf_Ehdr *ehdr;
- size_t shstrndx;
- size_t shnum;
- struct shdr_info
- {
- Elf_Scn *scn;
- GElf_Shdr shdr;
- Elf_Data *data;
- const char *name;
- Elf32_Word idx; /* Index in new file. */
- Elf32_Word old_sh_link; /* Original value of shdr.sh_link. */
- Elf32_Word symtab_idx;
- Elf32_Word version_idx;
- Elf32_Word group_idx;
- Elf32_Word group_cnt;
- Elf_Scn *newscn;
- struct Ebl_Strent *se;
- Elf32_Word *newsymidx;
- } *shdr_info = NULL;
- Elf_Scn *scn;
- size_t cnt;
- size_t idx;
- bool changes;
- GElf_Ehdr newehdr_mem;
- GElf_Ehdr *newehdr;
- GElf_Ehdr debugehdr_mem;
- GElf_Ehdr *debugehdr;
- struct Ebl_Strtab *shst = NULL;
- uint32_t debug_crc;
- bool any_symtab_changes = false;
- Elf_Data *shstrtab_data = NULL;
-
- /* Create the full name of the file. */
- if (prefix != NULL)
- {
- cp = mempcpy (cp, prefix, prefix_len);
- *cp++ = ':';
- }
- memcpy (cp, fname, fname_len);
-
- /* If we are not replacing the input file open a new file here. */
- if (output_fname != NULL)
- {
- fd = open (output_fname, O_RDWR | O_CREAT, mode);
- if (unlikely (fd == -1))
- {
- error (0, errno, gettext ("cannot open `%s'"), output_fname);
- return 1;
- }
- }
-
- int debug_fd = -1;
-
- /* Get the EBL handling. The -g option is currently the only reason
- we need EBL so dont open the backend unless necessary. */
- Ebl *ebl = NULL;
- if (remove_debug)
- {
- ebl = ebl_openbackend (elf);
- if (ebl == NULL)
- {
- error (0, errno, gettext ("cannot open EBL backend"));
- result = 1;
- goto fail;
- }
- }
-
- /* Open the additional file the debug information will be stored in. */
- if (debug_fname != NULL)
- {
- /* Create a temporary file name. We do not want to overwrite
- the debug file if the file would not contain any
- information. */
- size_t debug_fname_len = strlen (debug_fname);
- tmp_debug_fname = (char *) alloca (debug_fname_len + sizeof (".XXXXXX"));
- strcpy (mempcpy (tmp_debug_fname, debug_fname, debug_fname_len),
- ".XXXXXX");
-
- debug_fd = mkstemp (tmp_debug_fname);
- if (unlikely (debug_fd == -1))
- {
- error (0, errno, gettext ("cannot open `%s'"), debug_fname);
- result = 1;
- goto fail;
- }
- }
-
- /* Get the information from the old file. */
- ehdr = gelf_getehdr (elf, &ehdr_mem);
- if (ehdr == NULL)
- INTERNAL_ERROR (fname);
-
- /* Get the section header string table index. */
- if (unlikely (elf_getshstrndx (elf, &shstrndx) < 0))
- error (EXIT_FAILURE, 0,
- gettext ("cannot get section header string table index"));
-
- /* We now create a new ELF descriptor for the same file. We
- construct it almost exactly in the same way with some information
- dropped. */
- if (output_fname != NULL)
- newelf = elf_begin (fd, ELF_C_WRITE_MMAP, NULL);
- else
- newelf = elf_clone (elf, ELF_C_EMPTY);
-
- if (unlikely (gelf_newehdr (newelf, gelf_getclass (elf)) == 0)
- || (ehdr->e_type != ET_REL
- && unlikely (gelf_newphdr (newelf, ehdr->e_phnum) == 0)))
- {
- error (0, 0, gettext ("cannot create new file `%s': %s"),
- output_fname, elf_errmsg (-1));
- goto fail;
- }
-
- /* Copy over the old program header if needed. */
- if (ehdr->e_type != ET_REL)
- for (cnt = 0; cnt < ehdr->e_phnum; ++cnt)
- {
- GElf_Phdr phdr_mem;
- GElf_Phdr *phdr;
-
- phdr = gelf_getphdr (elf, cnt, &phdr_mem);
- if (phdr == NULL
- || unlikely (gelf_update_phdr (newelf, cnt, phdr) == 0))
- INTERNAL_ERROR (fname);
- }
-
- if (debug_fname != NULL)
- {
- /* Also create an ELF descriptor for the debug file */
- debugelf = elf_begin (debug_fd, ELF_C_WRITE_MMAP, NULL);
- if (unlikely (gelf_newehdr (debugelf, gelf_getclass (elf)) == 0)
- || (ehdr->e_type != ET_REL
- && unlikely (gelf_newphdr (debugelf, ehdr->e_phnum) == 0)))
- {
- error (0, 0, gettext ("cannot create new file `%s': %s"),
- debug_fname, elf_errmsg (-1));
- goto fail_close;
- }
-
- /* Copy over the old program header if needed. */
- if (ehdr->e_type != ET_REL)
- for (cnt = 0; cnt < ehdr->e_phnum; ++cnt)
- {
- GElf_Phdr phdr_mem;
- GElf_Phdr *phdr;
-
- phdr = gelf_getphdr (elf, cnt, &phdr_mem);
- if (phdr == NULL
- || unlikely (gelf_update_phdr (debugelf, cnt, phdr) == 0))
- INTERNAL_ERROR (fname);
- }
- }
-
- /* Number of sections. */
- if (unlikely (elf_getshnum (elf, &shnum) < 0))
- {
- error (0, 0, gettext ("cannot determine number of sections: %s"),
- elf_errmsg (-1));
- goto fail_close;
- }
-
- /* Storage for section information. We leave room for two more
- entries since we unconditionally create a section header string
- table. Maybe some weird tool created an ELF file without one.
- The other one is used for the debug link section. */
- if ((shnum + 2) * sizeof (struct shdr_info) > MAX_STACK_ALLOC)
- shdr_info = (struct shdr_info *) xcalloc (shnum + 2,
- sizeof (struct shdr_info));
- else
- {
- shdr_info = (struct shdr_info *) alloca ((shnum + 2)
- * sizeof (struct shdr_info));
- memset (shdr_info, '\0', (shnum + 2) * sizeof (struct shdr_info));
- }
-
- /* Prepare section information data structure. */
- scn = NULL;
- cnt = 1;
- while ((scn = elf_nextscn (elf, scn)) != NULL)
- {
- /* This should always be true (i.e., there should not be any
- holes in the numbering). */
- assert (elf_ndxscn (scn) == cnt);
-
- shdr_info[cnt].scn = scn;
-
- /* Get the header. */
- if (gelf_getshdr (scn, &shdr_info[cnt].shdr) == NULL)
- INTERNAL_ERROR (fname);
-
- /* Get the name of the section. */
- shdr_info[cnt].name = elf_strptr (elf, shstrndx,
- shdr_info[cnt].shdr.sh_name);
- if (shdr_info[cnt].name == NULL)
- {
- error (0, 0, gettext ("illformed file `%s'"), fname);
- goto fail_close;
- }
-
- /* Mark them as present but not yet investigated. */
- shdr_info[cnt].idx = 1;
-
- /* Remember the shdr.sh_link value. */
- shdr_info[cnt].old_sh_link = shdr_info[cnt].shdr.sh_link;
-
- /* Sections in files other than relocatable object files which
- are not loaded can be freely moved by us. In relocatable
- object files everything can be moved. */
- if (ehdr->e_type == ET_REL
- || (shdr_info[cnt].shdr.sh_flags & SHF_ALLOC) == 0)
- shdr_info[cnt].shdr.sh_offset = 0;
-
- /* If this is an extended section index table store an
- appropriate reference. */
- if (unlikely (shdr_info[cnt].shdr.sh_type == SHT_SYMTAB_SHNDX))
- {
- assert (shdr_info[shdr_info[cnt].shdr.sh_link].symtab_idx == 0);
- shdr_info[shdr_info[cnt].shdr.sh_link].symtab_idx = cnt;
- }
- else if (unlikely (shdr_info[cnt].shdr.sh_type == SHT_GROUP))
- {
- Elf32_Word *grpref;
- size_t inner;
-
- /* Cross-reference the sections contained in the section
- group. */
- shdr_info[cnt].data = elf_getdata (shdr_info[cnt].scn, NULL);
- if (shdr_info[cnt].data == NULL)
- INTERNAL_ERROR (fname);
-
- /* XXX Fix for unaligned access. */
- grpref = (Elf32_Word *) shdr_info[cnt].data->d_buf;
- for (inner = 1;
- inner < shdr_info[cnt].data->d_size / sizeof (Elf32_Word);
- ++inner)
- shdr_info[grpref[inner]].group_idx = cnt;
-
- if (inner == 1 || (inner == 2 && (grpref[0] & GRP_COMDAT) == 0))
- /* If the section group contains only one element and this
- is n COMDAT section we can drop it right away. */
- shdr_info[cnt].idx = 0;
- else
- shdr_info[cnt].group_cnt = inner - 1;
- }
- else if (unlikely (shdr_info[cnt].shdr.sh_type == SHT_GNU_versym))
- {
- assert (shdr_info[shdr_info[cnt].shdr.sh_link].version_idx == 0);
- shdr_info[shdr_info[cnt].shdr.sh_link].version_idx = cnt;
- }
-
- /* If this section is part of a group make sure it is not
- discarded right away. */
- if ((shdr_info[cnt].shdr.sh_flags & SHF_GROUP) != 0)
- {
- assert (shdr_info[cnt].group_idx != 0);
-
- if (shdr_info[shdr_info[cnt].group_idx].idx == 0)
- {
- /* The section group section will be removed. */
- shdr_info[cnt].group_idx = 0;
- shdr_info[cnt].shdr.sh_flags &= ~SHF_GROUP;
- }
- }
-
- /* Increment the counter. */
- ++cnt;
- }
-
- /* Now determine which sections can go away. The general rule is that
- all sections which are not used at runtime are stripped out. But
- there are a few exceptions:
-
- - special sections named ".comment" and ".note" are kept
- - OS or architecture specific sections are kept since we might not
- know how to handle them
- - if a section is referred to from a section which is not removed
- in the sh_link or sh_info element it cannot be removed either
- */
- for (cnt = 1; cnt < shnum; ++cnt)
- /* Check whether the section can be removed. */
- if (SECTION_STRIP_P (ebl, elf, ehdr, &shdr_info[cnt].shdr,
- shdr_info[cnt].name, remove_comment, remove_debug))
- {
- /* For now assume this section will be removed. */
- shdr_info[cnt].idx = 0;
-
- idx = shdr_info[cnt].group_idx;
- while (idx != 0)
- {
- /* If the references section group is a normal section
- group and has one element remaining, or if it is an
- empty COMDAT section group it is removed. */
- bool is_comdat;
-
- /* The section group data is already loaded. */
- assert (shdr_info[idx].data != NULL);
-
- is_comdat = (((Elf32_Word *) shdr_info[idx].data->d_buf)[0]
- & GRP_COMDAT) != 0;
-
- --shdr_info[idx].group_cnt;
- if ((!is_comdat && shdr_info[idx].group_cnt == 1)
- || (is_comdat && shdr_info[idx].group_cnt == 0))
- {
- shdr_info[idx].idx = 0;
- /* Continue recursively. */
- idx = shdr_info[idx].group_idx;
- }
- else
- break;
- }
- }
-
- /* Mark the SHT_NULL section as handled. */
- shdr_info[0].idx = 2;
-
-
- /* Handle exceptions: section groups and cross-references. We might
- have to repeat this a few times since the resetting of the flag
- might propagate. */
- do
- {
- changes = false;
-
- for (cnt = 1; cnt < shnum; ++cnt)
- {
- if (shdr_info[cnt].idx == 0)
- {
- /* If a relocation section is marked as being removed make
- sure the section it is relocating is removed, too. */
- if ((shdr_info[cnt].shdr.sh_type == SHT_REL
- || shdr_info[cnt].shdr.sh_type == SHT_RELA)
- && shdr_info[shdr_info[cnt].shdr.sh_info].idx != 0)
- shdr_info[cnt].idx = 1;
- }
-
- if (shdr_info[cnt].idx == 1)
- {
- /* The content of symbol tables we don't remove must not
- reference any section which we do remove. Otherwise
- we cannot remove the section. */
- if (shdr_info[cnt].shdr.sh_type == SHT_DYNSYM
- || shdr_info[cnt].shdr.sh_type == SHT_SYMTAB)
- {
- Elf_Data *symdata;
- Elf_Data *xndxdata;
- size_t elsize;
-
- /* Make sure the data is loaded. */
- if (shdr_info[cnt].data == NULL)
- {
- shdr_info[cnt].data
- = elf_getdata (shdr_info[cnt].scn, NULL);
- if (shdr_info[cnt].data == NULL)
- INTERNAL_ERROR (fname);
- }
- symdata = shdr_info[cnt].data;
-
- /* If there is an extended section index table load it
- as well. */
- if (shdr_info[cnt].symtab_idx != 0
- && shdr_info[shdr_info[cnt].symtab_idx].data == NULL)
- {
- assert (shdr_info[cnt].shdr.sh_type == SHT_SYMTAB);
-
- shdr_info[shdr_info[cnt].symtab_idx].data
- = elf_getdata (shdr_info[shdr_info[cnt].symtab_idx].scn,
- NULL);
- if (shdr_info[shdr_info[cnt].symtab_idx].data == NULL)
- INTERNAL_ERROR (fname);
- }
- xndxdata = shdr_info[shdr_info[cnt].symtab_idx].data;
-
- /* Go through all symbols and make sure the section they
- reference is not removed. */
- elsize = gelf_fsize (elf, ELF_T_SYM, 1, ehdr->e_version);
-
- for (size_t inner = 0;
- inner < shdr_info[cnt].data->d_size / elsize;
- ++inner)
- {
- GElf_Sym sym_mem;
- Elf32_Word xndx;
- GElf_Sym *sym;
- size_t scnidx;
-
- sym = gelf_getsymshndx (symdata, xndxdata, inner,
- &sym_mem, &xndx);
- if (sym == NULL)
- INTERNAL_ERROR (fname);
-
- scnidx = sym->st_shndx;
- if (scnidx == SHN_UNDEF || scnidx >= shnum
- || (scnidx >= SHN_LORESERVE
- && scnidx <= SHN_HIRESERVE
- && scnidx != SHN_XINDEX)
- /* Don't count in the section symbols. */
- || GELF_ST_TYPE (sym->st_info) == STT_SECTION)
- /* This is no section index, leave it alone. */
- continue;
- else if (scnidx == SHN_XINDEX)
- scnidx = xndx;
-
- if (shdr_info[scnidx].idx == 0)
- {
- /* Mark this section as used. */
- shdr_info[scnidx].idx = 1;
- changes |= scnidx < cnt;
- }
- }
- }
-
- /* Cross referencing happens:
- - for the cases the ELF specification says. That are
- + SHT_DYNAMIC in sh_link to string table
- + SHT_HASH in sh_link to symbol table
- + SHT_REL and SHT_RELA in sh_link to symbol table
- + SHT_SYMTAB and SHT_DYNSYM in sh_link to string table
- + SHT_GROUP in sh_link to symbol table
- + SHT_SYMTAB_SHNDX in sh_link to symbol table
- Other (OS or architecture-specific) sections might as
- well use this field so we process it unconditionally.
- - references inside section groups
- - specially marked references in sh_info if the SHF_INFO_LINK
- flag is set
- */
-
- if (shdr_info[shdr_info[cnt].shdr.sh_link].idx == 0)
- {
- shdr_info[shdr_info[cnt].shdr.sh_link].idx = 1;
- changes |= shdr_info[cnt].shdr.sh_link < cnt;
- }
-
- /* Handle references through sh_info. */
- if (SH_INFO_LINK_P (&shdr_info[cnt].shdr)
- && shdr_info[shdr_info[cnt].shdr.sh_info].idx == 0)
- {
- shdr_info[shdr_info[cnt].shdr.sh_info].idx = 1;
- changes |= shdr_info[cnt].shdr.sh_info < cnt;
- }
-
- /* Mark the section as investigated. */
- shdr_info[cnt].idx = 2;
- }
- }
- }
- while (changes);
-
- /* Write out a copy of all the sections to the debug output file.
- The ones that are not removed in the stripped file are SHT_NOBITS */
- if (debug_fname != NULL)
- {
- for (cnt = 1; cnt < shnum; ++cnt)
- {
- Elf_Data *debugdata;
- GElf_Shdr debugshdr;
- int discard_section;
-
- scn = elf_newscn (debugelf);
- if (scn == NULL)
- error (EXIT_FAILURE, 0,
- gettext ("while generating output file: %s"),
- elf_errmsg (-1));
-
- discard_section = shdr_info[cnt].idx > 0 && cnt != ehdr->e_shstrndx;
-
- /* Set the section header in the new file. */
- debugshdr = shdr_info[cnt].shdr;
- if (discard_section)
- debugshdr.sh_type = SHT_NOBITS;
-
- if (unlikely (gelf_update_shdr (scn, &debugshdr)) == 0)
- /* There cannot be any overflows. */
- INTERNAL_ERROR (fname);
-
- /* Get the data from the old file if necessary. */
- if (shdr_info[cnt].data == NULL)
- {
- shdr_info[cnt].data = elf_getdata (shdr_info[cnt].scn, NULL);
- if (shdr_info[cnt].data == NULL)
- INTERNAL_ERROR (fname);
- }
-
- /* Set the data. This is done by copying from the old file. */
- debugdata = elf_newdata (scn);
- if (debugdata == NULL)
- INTERNAL_ERROR (fname);
-
- /* Copy the structure. */
- *debugdata = *shdr_info[cnt].data;
- if (discard_section)
- debugdata->d_buf = NULL;
- }
-
- /* Finish the ELF header. Fill in the fields not handled by
- libelf from the old file. */
- debugehdr = gelf_getehdr (debugelf, &debugehdr_mem);
- if (debugehdr == NULL)
- INTERNAL_ERROR (fname);
-
- memcpy (debugehdr->e_ident, ehdr->e_ident, EI_NIDENT);
- debugehdr->e_type = ehdr->e_type;
- debugehdr->e_machine = ehdr->e_machine;
- debugehdr->e_version = ehdr->e_version;
- debugehdr->e_entry = ehdr->e_entry;
- debugehdr->e_flags = ehdr->e_flags;
- debugehdr->e_shstrndx = ehdr->e_shstrndx;
-
- if (unlikely (gelf_update_ehdr (debugelf, debugehdr)) == 0)
- {
- error (0, 0, gettext ("%s: error while creating ELF header: %s"),
- debug_fname, elf_errmsg (-1));
- result = 1;
- goto fail_close;
- }
-
- /* Finally write the file. */
- if (unlikely (elf_update (debugelf, ELF_C_WRITE)) == -1)
- {
- error (0, 0, gettext ("while writing `%s': %s"),
- debug_fname, elf_errmsg (-1));
- result = 1;
- goto fail_close;
- }
-
- /* Create the real output file. First rename, then change the
- mode. */
- if (rename (tmp_debug_fname, debug_fname) != 0
- || fchmod (debug_fd, mode) != 0)
- {
- error (0, errno, gettext ("while creating '%s'"), debug_fname);
- result = 1;
- goto fail_close;
- }
-
- /* The temporary file does not exist anymore. */
- tmp_debug_fname = NULL;
-
- /* Compute the checksum which we will add to the executable. */
- if (crc32_file (debug_fd, &debug_crc) != 0)
- {
- error (0, errno,
- gettext ("while computing checksum for debug information"));
- unlink (debug_fname);
- result = 1;
- goto fail_close;
- }
-
- }
-
- /* Mark the section header string table as unused, we will create
- a new one. */
- shdr_info[shstrndx].idx = 0;
-
- /* We need a string table for the section headers. */
- shst = ebl_strtabinit (true);
- if (shst == NULL)
- error (EXIT_FAILURE, errno, gettext ("while preparing output for `%s'"),
- output_fname ?: fname);
-
- /* Assign new section numbers. */
- shdr_info[0].idx = 0;
- for (cnt = idx = 1; cnt < shnum; ++cnt)
- if (shdr_info[cnt].idx > 0)
- {
- shdr_info[cnt].idx = idx++;
-
- /* Create a new section. */
- shdr_info[cnt].newscn = elf_newscn (newelf);
- if (shdr_info[cnt].newscn == NULL)
- error (EXIT_FAILURE, 0, gettext ("while generating output file: %s"),
- elf_errmsg (-1));
-
- assert (elf_ndxscn (shdr_info[cnt].newscn) == shdr_info[cnt].idx);
-
- /* Add this name to the section header string table. */
- shdr_info[cnt].se = ebl_strtabadd (shst, shdr_info[cnt].name, 0);
- }
-
- /* Test whether we are doing anything at all. */
- if (cnt == idx)
- /* Nope, all removable sections are already gone. */
- goto fail_close;
-
- /* Create the reference to the file with the debug info. */
- if (debug_fname != NULL)
- {
- char *debug_basename;
- off_t crc_offset;
-
- /* Add the section header string table section name. */
- shdr_info[cnt].se = ebl_strtabadd (shst, ".gnu_debuglink", 15);
- shdr_info[cnt].idx = idx++;
-
- /* Create the section header. */
- shdr_info[cnt].shdr.sh_type = SHT_PROGBITS;
- shdr_info[cnt].shdr.sh_flags = 0;
- shdr_info[cnt].shdr.sh_addr = 0;
- shdr_info[cnt].shdr.sh_link = SHN_UNDEF;
- shdr_info[cnt].shdr.sh_info = SHN_UNDEF;
- shdr_info[cnt].shdr.sh_entsize = 0;
- shdr_info[cnt].shdr.sh_addralign = 4;
- /* We set the offset to zero here. Before we write the ELF file the
- field must have the correct value. This is done in the final
- loop over all section. Then we have all the information needed. */
- shdr_info[cnt].shdr.sh_offset = 0;
-
- /* Create the section. */
- shdr_info[cnt].newscn = elf_newscn (newelf);
- if (shdr_info[cnt].newscn == NULL)
- error (EXIT_FAILURE, 0,
- gettext ("while create section header section: %s"),
- elf_errmsg (-1));
- assert (elf_ndxscn (shdr_info[cnt].newscn) == shdr_info[cnt].idx);
-
- shdr_info[cnt].data = elf_newdata (shdr_info[cnt].newscn);
- if (shdr_info[cnt].data == NULL)
- error (EXIT_FAILURE, 0, gettext ("cannot allocate section data: %s"),
- elf_errmsg (-1));
-
- debug_basename = basename (debug_fname);
- crc_offset = strlen (debug_basename) + 1;
- /* Align to 4 byte boundary */
- crc_offset = ((crc_offset - 1) & ~3) + 4;
-
- shdr_info[cnt].data->d_align = 4;
- shdr_info[cnt].shdr.sh_size = shdr_info[cnt].data->d_size
- = crc_offset + 4;
- shdr_info[cnt].data->d_buf = xcalloc (1, shdr_info[cnt].data->d_size);
-
- strcpy (shdr_info[cnt].data->d_buf, debug_basename);
- /* Store the crc value in the correct byteorder */
- if ((__BYTE_ORDER == __LITTLE_ENDIAN
- && ehdr->e_ident[EI_DATA] == ELFDATA2MSB)
- || (__BYTE_ORDER == __BIG_ENDIAN
- && ehdr->e_ident[EI_DATA] == ELFDATA2LSB))
- debug_crc = bswap_32 (debug_crc);
- memcpy ((char *)shdr_info[cnt].data->d_buf + crc_offset,
- (char *) &debug_crc, 4);
-
- /* One more section done. */
- ++cnt;
- }
-
- /* Index of the section header table in the shdr_info array. */
- size_t shdridx = cnt;
-
- /* Add the section header string table section name. */
- shdr_info[cnt].se = ebl_strtabadd (shst, ".shstrtab", 10);
- shdr_info[cnt].idx = idx;
-
- /* Create the section header. */
- shdr_info[cnt].shdr.sh_type = SHT_STRTAB;
- shdr_info[cnt].shdr.sh_flags = 0;
- shdr_info[cnt].shdr.sh_addr = 0;
- shdr_info[cnt].shdr.sh_link = SHN_UNDEF;
- shdr_info[cnt].shdr.sh_info = SHN_UNDEF;
- shdr_info[cnt].shdr.sh_entsize = 0;
- /* We set the offset to zero here. Before we write the ELF file the
- field must have the correct value. This is done in the final
- loop over all section. Then we have all the information needed. */
- shdr_info[cnt].shdr.sh_offset = 0;
- shdr_info[cnt].shdr.sh_addralign = 1;
-
- /* Create the section. */
- shdr_info[cnt].newscn = elf_newscn (newelf);
- if (shdr_info[cnt].newscn == NULL)
- error (EXIT_FAILURE, 0,
- gettext ("while create section header section: %s"),
- elf_errmsg (-1));
- assert (elf_ndxscn (shdr_info[cnt].newscn) == idx);
-
- /* Finalize the string table and fill in the correct indices in the
- section headers. */
- shstrtab_data = elf_newdata (shdr_info[cnt].newscn);
- if (shstrtab_data == NULL)
- error (EXIT_FAILURE, 0,
- gettext ("while create section header string table: %s"),
- elf_errmsg (-1));
- ebl_strtabfinalize (shst, shstrtab_data);
-
- /* We have to set the section size. */
- shdr_info[cnt].shdr.sh_size = shstrtab_data->d_size;
-
- /* Update the section information. */
- GElf_Off lastoffset = 0;
- for (cnt = 1; cnt <= shdridx; ++cnt)
- if (shdr_info[cnt].idx > 0)
- {
- Elf_Data *newdata;
-
- scn = elf_getscn (newelf, shdr_info[cnt].idx);
- assert (scn != NULL);
-
- /* Update the name. */
- shdr_info[cnt].shdr.sh_name = ebl_strtaboffset (shdr_info[cnt].se);
-
- /* Update the section header from the input file. Some fields
- might be section indeces which now have to be adjusted. */
- if (shdr_info[cnt].shdr.sh_link != 0)
- shdr_info[cnt].shdr.sh_link =
- shdr_info[shdr_info[cnt].shdr.sh_link].idx;
-
- if (shdr_info[cnt].shdr.sh_type == SHT_GROUP)
- {
- assert (shdr_info[cnt].data != NULL);
-
- Elf32_Word *grpref = (Elf32_Word *) shdr_info[cnt].data->d_buf;
- for (size_t inner = 0;
- inner < shdr_info[cnt].data->d_size / sizeof (Elf32_Word);
- ++inner)
- grpref[inner] = shdr_info[grpref[inner]].idx;
- }
-
- /* Handle the SHT_REL, SHT_RELA, and SHF_INFO_LINK flag. */
- if (SH_INFO_LINK_P (&shdr_info[cnt].shdr))
- shdr_info[cnt].shdr.sh_info =
- shdr_info[shdr_info[cnt].shdr.sh_info].idx;
-
- /* Get the data from the old file if necessary. We already
- created the data for the section header string table. */
- if (cnt < shnum)
- {
- if (shdr_info[cnt].data == NULL)
- {
- shdr_info[cnt].data = elf_getdata (shdr_info[cnt].scn, NULL);
- if (shdr_info[cnt].data == NULL)
- INTERNAL_ERROR (fname);
- }
-
- /* Set the data. This is done by copying from the old file. */
- newdata = elf_newdata (scn);
- if (newdata == NULL)
- INTERNAL_ERROR (fname);
-
- /* Copy the structure. */
- *newdata = *shdr_info[cnt].data;
-
- /* We know the size. */
- shdr_info[cnt].shdr.sh_size = shdr_info[cnt].data->d_size;
-
- /* We have to adjust symtol tables. The st_shndx member might
- have to be updated. */
- if (shdr_info[cnt].shdr.sh_type == SHT_DYNSYM
- || shdr_info[cnt].shdr.sh_type == SHT_SYMTAB)
- {
- Elf_Data *versiondata = NULL;
- Elf_Data *shndxdata = NULL;
-
- size_t elsize = gelf_fsize (elf, ELF_T_SYM, 1,
- ehdr->e_version);
-
- if (shdr_info[cnt].symtab_idx != 0)
- {
- assert (shdr_info[cnt].shdr.sh_type == SHT_SYMTAB_SHNDX);
- /* This section has extended section information.
- We have to modify that information, too. */
- shndxdata = elf_getdata (shdr_info[shdr_info[cnt].symtab_idx].scn,
- NULL);
-
- assert ((versiondata->d_size / sizeof (Elf32_Word))
- >= shdr_info[cnt].data->d_size / elsize);
- }
-
- if (shdr_info[cnt].version_idx != 0)
- {
- assert (shdr_info[cnt].shdr.sh_type == SHT_DYNSYM);
- /* This section has associated version
- information. We have to modify that
- information, too. */
- versiondata = elf_getdata (shdr_info[shdr_info[cnt].version_idx].scn,
- NULL);
-
- assert ((versiondata->d_size / sizeof (GElf_Versym))
- >= shdr_info[cnt].data->d_size / elsize);
- }
-
- shdr_info[cnt].newsymidx
- = (Elf32_Word *) xcalloc (shdr_info[cnt].data->d_size
- / elsize, sizeof (Elf32_Word));
-
- bool last_was_local = true;
- size_t destidx;
- size_t inner;
- for (destidx = inner = 1;
- inner < shdr_info[cnt].data->d_size / elsize;
- ++inner)
- {
- Elf32_Word sec;
- GElf_Sym sym_mem;
- Elf32_Word xshndx;
- GElf_Sym *sym = gelf_getsymshndx (shdr_info[cnt].data,
- shndxdata, inner,
- &sym_mem, &xshndx);
- if (sym == NULL)
- INTERNAL_ERROR (fname);
-
- if (sym->st_shndx == SHN_UNDEF
- || (sym->st_shndx >= shnum
- && sym->st_shndx != SHN_XINDEX))
- {
- /* This is no section index, leave it alone
- unless it is moved. */
- if (destidx != inner
- && gelf_update_symshndx (shdr_info[cnt].data,
- shndxdata,
- destidx, sym,
- xshndx) == 0)
- INTERNAL_ERROR (fname);
-
- shdr_info[cnt].newsymidx[inner] = destidx++;
-
- if (last_was_local
- && GELF_ST_BIND (sym->st_info) != STB_LOCAL)
- {
- last_was_local = false;
- shdr_info[cnt].shdr.sh_info = destidx - 1;
- }
-
- continue;
- }
-
- /* Get the full section index, if necessary from the
- XINDEX table. */
- if (sym->st_shndx != SHN_XINDEX)
- sec = shdr_info[sym->st_shndx].idx;
- else
- {
- assert (shndxdata != NULL);
-
- sec = shdr_info[xshndx].idx;
- }
-
- if (sec != 0)
- {
- GElf_Section nshndx;
- Elf32_Word nxshndx;
-
- if (sec < SHN_LORESERVE)
- {
- nshndx = sec;
- nxshndx = 0;
- }
- else
- {
- nshndx = SHN_XINDEX;
- nxshndx = sec;
- }
-
- assert (sec < SHN_LORESERVE || shndxdata != NULL);
-
- if ((inner != destidx || nshndx != sym->st_shndx
- || (shndxdata != NULL && nxshndx != xshndx))
- && (sym->st_shndx = nshndx,
- gelf_update_symshndx (shdr_info[cnt].data,
- shndxdata,
- destidx, sym,
- nxshndx) == 0))
- INTERNAL_ERROR (fname);
-
- shdr_info[cnt].newsymidx[inner] = destidx++;
-
- if (last_was_local
- && GELF_ST_BIND (sym->st_info) != STB_LOCAL)
- {
- last_was_local = false;
- shdr_info[cnt].shdr.sh_info = destidx - 1;
- }
- }
- else
- /* This is a section symbol for a section which has
- been removed. */
- assert (GELF_ST_TYPE (sym->st_info) == STT_SECTION);
- }
-
- if (destidx != inner)
- {
- /* The size of the symbol table changed. */
- shdr_info[cnt].shdr.sh_size = newdata->d_size
- = destidx * elsize;
- any_symtab_changes = true;
- }
- else
- {
- /* The symbol table didn't really change. */
- free (shdr_info[cnt].newsymidx);
- shdr_info[cnt].newsymidx = NULL;
- }
- }
- }
-
- /* If we have to, compute the offset of the section. */
- if (shdr_info[cnt].shdr.sh_offset == 0)
- shdr_info[cnt].shdr.sh_offset
- = ((lastoffset + shdr_info[cnt].shdr.sh_addralign - 1)
- & ~((GElf_Off) (shdr_info[cnt].shdr.sh_addralign - 1)));
-
- /* Set the section header in the new file. */
- if (unlikely (gelf_update_shdr (scn, &shdr_info[cnt].shdr) == 0))
- /* There cannot be any overflows. */
- INTERNAL_ERROR (fname);
-
- /* Remember the last section written so far. */
- GElf_Off filesz = (shdr_info[cnt].shdr.sh_type != SHT_NOBITS
- ? shdr_info[cnt].shdr.sh_size : 0);
- if (lastoffset < shdr_info[cnt].shdr.sh_offset + filesz)
- lastoffset = shdr_info[cnt].shdr.sh_offset + filesz;
- }
-
- /* Adjust symbol references if symbol tables changed. */
- if (any_symtab_changes)
- {
- /* Find all relocation sections which use this
- symbol table. */
- for (cnt = 1; cnt <= shdridx; ++cnt)
- {
- if (shdr_info[cnt].idx == 0)
- /* Ignore sections which are discarded. */
- continue;
-
- if (shdr_info[cnt].shdr.sh_type == SHT_REL
- || shdr_info[cnt].shdr.sh_type == SHT_RELA)
- {
- /* If the symbol table hasn't changed, do not do anything. */
- if (shdr_info[shdr_info[cnt].old_sh_link].newsymidx == NULL)
- continue;
-
- Elf32_Word *newsymidx
- = shdr_info[shdr_info[cnt].old_sh_link].newsymidx;
- Elf_Data *d = elf_getdata (elf_getscn (newelf,
- shdr_info[cnt].idx),
- NULL);
- assert (d != NULL);
- size_t nrels = (shdr_info[cnt].shdr.sh_size
- / shdr_info[cnt].shdr.sh_entsize);
-
- if (shdr_info[cnt].shdr.sh_type == SHT_REL)
- for (size_t relidx = 0; relidx < nrels; ++relidx)
- {
- GElf_Rel rel_mem;
- if (gelf_getrel (d, relidx, &rel_mem) == NULL)
- INTERNAL_ERROR (fname);
-
- size_t symidx = GELF_R_SYM (rel_mem.r_info);
- if (newsymidx[symidx] != symidx)
- {
- rel_mem.r_info
- = GELF_R_INFO (newsymidx[symidx],
- GELF_R_TYPE (rel_mem.r_info));
-
- if (gelf_update_rel (d, relidx, &rel_mem) == 0)
- INTERNAL_ERROR (fname);
- }
- }
- else
- for (size_t relidx = 0; relidx < nrels; ++relidx)
- {
- GElf_Rela rel_mem;
- if (gelf_getrela (d, relidx, &rel_mem) == NULL)
- INTERNAL_ERROR (fname);
-
- size_t symidx = GELF_R_SYM (rel_mem.r_info);
- if (newsymidx[symidx] != symidx)
- {
- rel_mem.r_info
- = GELF_R_INFO (newsymidx[symidx],
- GELF_R_TYPE (rel_mem.r_info));
-
- if (gelf_update_rela (d, relidx, &rel_mem) == 0)
- INTERNAL_ERROR (fname);
- }
- }
- }
- else if (shdr_info[cnt].shdr.sh_type == SHT_HASH)
- {
- /* We have to recompute the hash table. */
- Elf32_Word symtabidx = shdr_info[cnt].old_sh_link;
-
- /* We do not have to do anything if the symbol table was
- not changed. */
- if (shdr_info[symtabidx].newsymidx == NULL)
- continue;
-
- /* The symbol version section in the new file. */
- scn = elf_getscn (newelf, shdr_info[cnt].idx);
-
- /* The symbol table data. */
- Elf_Data *symd = elf_getdata (elf_getscn (newelf,
- shdr_info[symtabidx].idx),
- NULL);
- assert (symd != NULL);
-
- /* The hash table data. */
- Elf_Data *hashd = elf_getdata (scn, NULL);
- assert (hashd != NULL);
-
- if (shdr_info[cnt].shdr.sh_entsize == sizeof (Elf32_Word))
- {
- /* Sane arches first. */
- Elf32_Word *bucket = (Elf32_Word *) hashd->d_buf;
-
- size_t strshndx = shdr_info[symtabidx].old_sh_link;
- size_t elsize = gelf_fsize (elf, ELF_T_SYM, 1,
- ehdr->e_version);
-
- /* Convert to the correct byte order. */
- if (gelf_xlatetom (newelf, hashd, hashd,
- BYTE_ORDER == LITTLE_ENDIAN
- ? ELFDATA2LSB : ELFDATA2MSB) == NULL)
- INTERNAL_ERROR (fname);
-
- /* Adjust the nchain value. The symbol table size
- changed. We keep the same size for the bucket array. */
- bucket[1] = symd->d_size / elsize;
- Elf32_Word nbucket = bucket[0];
- bucket += 2;
- Elf32_Word *chain = bucket + nbucket;
-
- /* New size of the section. */
- GElf_Shdr shdr_mem;
- GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
- shdr->sh_size = hashd->d_size
- = (2 + symd->d_size / elsize + nbucket)
- * sizeof (Elf32_Word);
- (void) gelf_update_shdr (scn, shdr);
-
- /* Clear the arrays. */
- memset (bucket, '\0',
- (symd->d_size / elsize + nbucket)
- * sizeof (Elf32_Word));
-
- for (size_t inner = shdr_info[symtabidx].shdr.sh_info;
- inner < symd->d_size / elsize; ++inner)
- {
- GElf_Sym sym_mem;
- GElf_Sym *sym = gelf_getsym (symd, inner, &sym_mem);
- assert (sym != NULL);
-
- const char *name = elf_strptr (elf, strshndx,
- sym->st_name);
- assert (name != NULL);
- size_t hidx = elf_hash (name) % nbucket;
-
- if (bucket[hidx] == 0)
- bucket[hidx] = inner;
- else
- {
- hidx = bucket[hidx];
-
- while (chain[hidx] != 0)
- hidx = chain[hidx];
-
- chain[hidx] = inner;
- }
- }
- }
- else
- {
- /* Alpha and S390 64-bit use 64-bit SHT_HASH entries. */
- assert (shdr_info[cnt].shdr.sh_entsize
- == sizeof (Elf64_Xword));
-
- Elf64_Xword *bucket = (Elf64_Xword *) hashd->d_buf;
-
- size_t strshndx = shdr_info[symtabidx].old_sh_link;
- size_t elsize = gelf_fsize (elf, ELF_T_SYM, 1,
- ehdr->e_version);
-
- /* Convert to the correct byte order. */
- if (gelf_xlatetom (newelf, hashd, hashd,
- BYTE_ORDER == LITTLE_ENDIAN
- ? ELFDATA2LSB : ELFDATA2MSB) == NULL)
- INTERNAL_ERROR (fname);
-
- /* Adjust the nchain value. The symbol table size
- changed. We keep the same size for the bucket array. */
- bucket[1] = symd->d_size / elsize;
- Elf64_Xword nbucket = bucket[0];
- bucket += 2;
- Elf64_Xword *chain = bucket + nbucket;
-
- /* New size of the section. */
- GElf_Shdr shdr_mem;
- GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
- shdr->sh_size = hashd->d_size
- = (2 + symd->d_size / elsize + nbucket)
- * sizeof (Elf64_Xword);
- (void) gelf_update_shdr (scn, shdr);
-
- /* Clear the arrays. */
- memset (bucket, '\0',
- (symd->d_size / elsize + nbucket)
- * sizeof (Elf64_Xword));
-
- for (size_t inner = shdr_info[symtabidx].shdr.sh_info;
- inner < symd->d_size / elsize; ++inner)
- {
- GElf_Sym sym_mem;
- GElf_Sym *sym = gelf_getsym (symd, inner, &sym_mem);
- assert (sym != NULL);
-
- const char *name = elf_strptr (elf, strshndx,
- sym->st_name);
- assert (name != NULL);
- size_t hidx = elf_hash (name) % nbucket;
-
- if (bucket[hidx] == 0)
- bucket[hidx] = inner;
- else
- {
- hidx = bucket[hidx];
-
- while (chain[hidx] != 0)
- hidx = chain[hidx];
-
- chain[hidx] = inner;
- }
- }
- }
-
- /* Convert back to the file byte order. */
- if (gelf_xlatetof (newelf, hashd, hashd,
- BYTE_ORDER == LITTLE_ENDIAN
- ? ELFDATA2LSB : ELFDATA2MSB) == NULL)
- INTERNAL_ERROR (fname);
- }
- else if (shdr_info[cnt].shdr.sh_type == SHT_GNU_versym)
- {
- /* If the symbol table changed we have to adjust the
- entries. */
- Elf32_Word symtabidx = shdr_info[cnt].old_sh_link;
-
- /* We do not have to do anything if the symbol table was
- not changed. */
- if (shdr_info[symtabidx].newsymidx == NULL)
- continue;
-
- /* The symbol version section in the new file. */
- scn = elf_getscn (newelf, shdr_info[cnt].idx);
-
- /* The symbol table data. */
- Elf_Data *symd = elf_getdata (elf_getscn (newelf,
- shdr_info[symtabidx].idx),
- NULL);
- assert (symd != NULL);
-
- /* The version symbol data. */
- Elf_Data *verd = elf_getdata (scn, NULL);
- assert (verd != NULL);
-
- /* Convert to the correct byte order. */
- if (gelf_xlatetom (newelf, verd, verd,
- BYTE_ORDER == LITTLE_ENDIAN
- ? ELFDATA2LSB : ELFDATA2MSB) == NULL)
- INTERNAL_ERROR (fname);
-
- /* The symbol version array. */
- GElf_Half *verstab = (GElf_Half *) verd->d_buf;
-
- /* New indices of the symbols. */
- Elf32_Word *newsymidx = shdr_info[symtabidx].newsymidx;
-
- /* Walk through the list and */
- size_t elsize = gelf_fsize (elf, verd->d_type, 1,
- ehdr->e_version);
- for (size_t inner = 1; inner < verd->d_size / elsize; ++inner)
- if (newsymidx[inner] != 0)
- /* Overwriting the same array works since the
- reordering can only move entries to lower indices
- in the array. */
- verstab[newsymidx[inner]] = verstab[inner];
-
- /* New size of the section. */
- GElf_Shdr shdr_mem;
- GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
- shdr->sh_size = verd->d_size
- = gelf_fsize (newelf, verd->d_type,
- symd->d_size / gelf_fsize (elf, symd->d_type, 1,
- ehdr->e_version),
- ehdr->e_version);
- (void) gelf_update_shdr (scn, shdr);
-
- /* Convert back to the file byte order. */
- if (gelf_xlatetof (newelf, verd, verd,
- BYTE_ORDER == LITTLE_ENDIAN
- ? ELFDATA2LSB : ELFDATA2MSB) == NULL)
- INTERNAL_ERROR (fname);
- }
- else if (shdr_info[cnt].shdr.sh_type == SHT_GROUP)
- {
- /* Check whether the associated symbol table changed. */
- if (shdr_info[shdr_info[cnt].old_sh_link].newsymidx != NULL)
- {
- /* Yes the symbol table changed. Update the section
- header of the section group. */
- scn = elf_getscn (newelf, shdr_info[cnt].idx);
- GElf_Shdr shdr_mem;
- GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
- assert (shdr != NULL);
-
- size_t stabidx = shdr_info[cnt].old_sh_link;
- shdr->sh_info = shdr_info[stabidx].newsymidx[shdr->sh_info];
-
- (void) gelf_update_shdr (scn, shdr);
- }
- }
- }
- }
-
- /* Finally finish the ELF header. Fill in the fields not handled by
- libelf from the old file. */
- newehdr = gelf_getehdr (newelf, &newehdr_mem);
- if (newehdr == NULL)
- INTERNAL_ERROR (fname);
-
- memcpy (newehdr->e_ident, ehdr->e_ident, EI_NIDENT);
- newehdr->e_type = ehdr->e_type;
- newehdr->e_machine = ehdr->e_machine;
- newehdr->e_version = ehdr->e_version;
- newehdr->e_entry = ehdr->e_entry;
- newehdr->e_flags = ehdr->e_flags;
- newehdr->e_phoff = ehdr->e_phoff;
- /* We need to position the section header table. */
- const size_t offsize = gelf_fsize (elf, ELF_T_OFF, 1, EV_CURRENT);
- newehdr->e_shoff = ((shdr_info[shdridx].shdr.sh_offset
- + shdr_info[shdridx].shdr.sh_size + offsize - 1)
- & ~((GElf_Off) (offsize - 1)));
- newehdr->e_shentsize = gelf_fsize (elf, ELF_T_SHDR, 1, EV_CURRENT);
-
- /* The new section header string table index. */
- if (likely (idx < SHN_HIRESERVE) && likely (idx != SHN_XINDEX))
- newehdr->e_shstrndx = idx;
- else
- {
- /* The index does not fit in the ELF header field. */
- shdr_info[0].scn = elf_getscn (elf, 0);
-
- if (gelf_getshdr (shdr_info[0].scn, &shdr_info[0].shdr) == NULL)
- INTERNAL_ERROR (fname);
-
- shdr_info[0].shdr.sh_link = idx;
- (void) gelf_update_shdr (shdr_info[0].scn, &shdr_info[0].shdr);
-
- newehdr->e_shstrndx = SHN_XINDEX;
- }
-
- if (gelf_update_ehdr (newelf, newehdr) == 0)
- {
- error (0, 0, gettext ("%s: error while creating ELF header: %s"),
- fname, elf_errmsg (-1));
- return 1;
- }
-
- /* We have everything from the old file. */
- if (elf_cntl (elf, ELF_C_FDDONE) != 0)
- {
- error (0, 0, gettext ("%s: error while reading the file: %s"),
- fname, elf_errmsg (-1));
- return 1;
- }
-
- /* The ELF library better follows our layout when this is not a
- relocatable object file. */
- elf_flagelf (newelf, ELF_C_SET,
- (ehdr->e_type != ET_REL ? ELF_F_LAYOUT : 0)
- | (permissive ? ELF_F_PERMISSIVE : 0));
-
- /* Finally write the file. */
- if (elf_update (newelf, ELF_C_WRITE) == -1)
- {
- error (0, 0, gettext ("while writing `%s': %s"),
- fname, elf_errmsg (-1));
- result = 1;
- }
-
- fail_close:
- if (shdr_info != NULL)
- {
- /* For some sections we might have created an table to map symbol
- table indices. */
- if (any_symtab_changes)
- for (cnt = 1; cnt <= shdridx; ++cnt)
- free (shdr_info[cnt].newsymidx);
-
- /* Free the memory. */
- if ((shnum + 2) * sizeof (struct shdr_info) > MAX_STACK_ALLOC)
- free (shdr_info);
- }
-
- /* Free other resources. */
- if (shstrtab_data != NULL)
- free (shstrtab_data->d_buf);
- if (shst != NULL)
- ebl_strtabfree (shst);
-
- /* That was it. Close the descriptors. */
- if (elf_end (newelf) != 0)
- {
- error (0, 0, gettext ("error while finishing `%s': %s"), fname,
- elf_errmsg (-1));
- result = 1;
- }
-
- if (debugelf != NULL && elf_end (debugelf) != 0)
- {
- error (0, 0, gettext ("error while finishing `%s': %s"), debug_fname,
- elf_errmsg (-1));
- result = 1;
- }
-
- fail:
- /* Close the EBL backend. */
- if (ebl != NULL)
- ebl_closebackend (ebl);
-
- /* Close debug file descriptor, if opened */
- if (debug_fd >= 0)
- {
- if (tmp_debug_fname != NULL)
- unlink (tmp_debug_fname);
- close (debug_fd);
- }
-
- /* If requested, preserve the timestamp. */
- if (tvp != NULL)
- {
- if (futimes (fd, tvp) != 0)
- {
- error (0, errno, gettext ("\
-cannot set access and modification date of \"%s\""),
- output_fname ?: fname);
- result = 1;
- }
- }
-
- /* Close the file descriptor if we created a new file. */
- if (output_fname != NULL)
- close (fd);
-
- return result;
-}
-
-
-static int
-handle_ar (int fd, Elf *elf, const char *prefix, const char *fname,
- struct timeval tvp[2])
-{
- size_t prefix_len = prefix == NULL ? 0 : strlen (prefix);
- size_t fname_len = strlen (fname) + 1;
- char new_prefix[prefix_len + 1 + fname_len];
- char *cp = new_prefix;
-
- /* Create the full name of the file. */
- if (prefix != NULL)
- {
- cp = mempcpy (cp, prefix, prefix_len);
- *cp++ = ':';
- }
- memcpy (cp, fname, fname_len);
-
-
- /* Process all the files contained in the archive. */
- Elf *subelf;
- Elf_Cmd cmd = ELF_C_RDWR;
- int result = 0;
- while ((subelf = elf_begin (fd, cmd, elf)) != NULL)
- {
- /* The the header for this element. */
- Elf_Arhdr *arhdr = elf_getarhdr (subelf);
-
- if (elf_kind (subelf) == ELF_K_ELF)
- result |= handle_elf (fd, subelf, new_prefix, arhdr->ar_name, 0, NULL);
- else if (elf_kind (subelf) == ELF_K_AR)
- result |= handle_ar (fd, subelf, new_prefix, arhdr->ar_name, NULL);
-
- /* Get next archive element. */
- cmd = elf_next (subelf);
- if (unlikely (elf_end (subelf) != 0))
- INTERNAL_ERROR (fname);
- }
-
- if (tvp != NULL)
- {
- if (unlikely (futimes (fd, tvp) != 0))
- {
- error (0, errno, gettext ("\
-cannot set access and modification date of \"%s\""), fname);
- result = 1;
- }
- }
-
- if (unlikely (close (fd) != 0))
- error (EXIT_FAILURE, errno, gettext ("while closing `%s'"), fname);
-
- return result;
-}