diff options
author | emaste <emaste@FreeBSD.org> | 2016-02-12 20:54:02 +0000 |
---|---|---|
committer | emaste <emaste@FreeBSD.org> | 2016-02-12 20:54:02 +0000 |
commit | a6ae90983efabb9784f1e105ffb29eaec3c0573c (patch) | |
tree | cd8537a698afe8dd30dc9c4d04c193e5b3b2e94f /contrib/elftoolchain/elfcopy | |
parent | 0309ab8781484f9cf0561cbbc3cab6df7139d629 (diff) | |
parent | 85217dee0e24c5f3ac285420e843063b4b52c1a0 (diff) | |
download | FreeBSD-src-a6ae90983efabb9784f1e105ffb29eaec3c0573c.zip FreeBSD-src-a6ae90983efabb9784f1e105ffb29eaec3c0573c.tar.gz |
Update ELF Tool Chain to upstream rev 3400
Some notable improvements include:
readelf:
- Add AArch64 relocation definitions.
- Report value of unknown relocation types.
elfcopy:
- Consider symbols with STB_GNU_UNIQUE binding as global symbols.
- Fixed support for VMA adjustment for loadable sections found
in relocatable objects.
- Handle nameless global symbols.
- Improve wildcard matching for !-prefixed symbols.
- Add PE/COFF support.
elfdump:
- Improve section type reporting.
- Add MIPS-specific section types.
This update also includes a significant number of bug fixes.
PR: 207091 [exp-run]
Sponsored by: The FreeBSD Foundation
Diffstat (limited to 'contrib/elftoolchain/elfcopy')
-rw-r--r-- | contrib/elftoolchain/elfcopy/Makefile | 23 | ||||
-rw-r--r-- | contrib/elftoolchain/elfcopy/archive.c | 6 | ||||
-rw-r--r-- | contrib/elftoolchain/elfcopy/elfcopy.1 | 19 | ||||
-rw-r--r-- | contrib/elftoolchain/elfcopy/elfcopy.h | 3 | ||||
-rw-r--r-- | contrib/elftoolchain/elfcopy/main.c | 20 | ||||
-rw-r--r-- | contrib/elftoolchain/elfcopy/pe.c | 233 | ||||
-rw-r--r-- | contrib/elftoolchain/elfcopy/sections.c | 107 | ||||
-rw-r--r-- | contrib/elftoolchain/elfcopy/segments.c | 18 | ||||
-rw-r--r-- | contrib/elftoolchain/elfcopy/symbols.c | 126 |
9 files changed, 457 insertions, 98 deletions
diff --git a/contrib/elftoolchain/elfcopy/Makefile b/contrib/elftoolchain/elfcopy/Makefile index cb1a31b..8b208e0 100644 --- a/contrib/elftoolchain/elfcopy/Makefile +++ b/contrib/elftoolchain/elfcopy/Makefile @@ -1,10 +1,13 @@ -# $Id: Makefile 2290 2011-12-04 07:20:46Z jkoshy $ +# $Id: Makefile 3381 2016-01-30 19:39:47Z jkoshy $ TOP= .. +.include "${TOP}/mk/elftoolchain.components.mk" + PROG= elfcopy -SRCS= archive.c ascii.c binary.c main.c sections.c segments.c symbols.c +SRCS= archive.c ascii.c binary.c main.c sections.c segments.c \ + symbols.c WARNS?= 5 @@ -15,14 +18,24 @@ LDADD= -lelf -lelftc LDADD+= -larchive .endif +.if defined(WITH_PE) && ${WITH_PE:tl} == "yes" +SRCS+= pe.c +CFLAGS+= -DWITH_PE=1 + +DPADD+= ${LIBPE} +LDADD+= -lpe +.endif + MAN= elfcopy.1 mcs.1 strip.1 +MLINKS= elfcopy.1 objcopy.1 NO_SHARED?= yes -LINKS= ${BINDIR}/elfcopy ${BINDIR}/strip \ - ${BINDIR}/elfcopy ${BINDIR}/mcs +LINKS= ${BINDIR}/elfcopy ${BINDIR}/mcs \ + ${BINDIR}/elfcopy ${BINDIR}/objcopy \ + ${BINDIR}/elfcopy ${BINDIR}/strip -EXTRA_TARGETS= strip mcs +EXTRA_TARGETS= mcs strip objcopy CLEANFILES+= ${EXTRA_TARGETS} diff --git a/contrib/elftoolchain/elfcopy/archive.c b/contrib/elftoolchain/elfcopy/archive.c index 682a1df..97e2498 100644 --- a/contrib/elftoolchain/elfcopy/archive.c +++ b/contrib/elftoolchain/elfcopy/archive.c @@ -38,7 +38,7 @@ #include "elfcopy.h" -ELFTC_VCSID("$Id: archive.c 3174 2015-03-27 17:13:41Z emaste $"); +ELFTC_VCSID("$Id: archive.c 3287 2015-12-31 16:58:48Z emaste $"); #define _ARMAG_LEN 8 /* length of ar magic string */ #define _ARHDR_LEN 60 /* length of ar header */ @@ -382,7 +382,7 @@ ac_read_objs(struct elfcopy *ecp, int ifd) if (lseek(ifd, 0, SEEK_SET) == -1) err(EXIT_FAILURE, "lseek failed"); if ((a = archive_read_new()) == NULL) - errx(EXIT_FAILURE, "%s", archive_error_string(a)); + errx(EXIT_FAILURE, "archive_read_new failed"); archive_read_support_format_ar(a); AC(archive_read_open_fd(a, ifd, 10240)); for(;;) { @@ -443,7 +443,7 @@ ac_write_objs(struct elfcopy *ecp, int ofd) int nr; if ((a = archive_write_new()) == NULL) - errx(EXIT_FAILURE, "%s", archive_error_string(a)); + errx(EXIT_FAILURE, "archive_write_new failed"); archive_write_set_format_ar_svr4(a); AC(archive_write_open_fd(a, ofd)); diff --git a/contrib/elftoolchain/elfcopy/elfcopy.1 b/contrib/elftoolchain/elfcopy/elfcopy.1 index 83cda5d..b7b0ce4 100644 --- a/contrib/elftoolchain/elfcopy/elfcopy.1 +++ b/contrib/elftoolchain/elfcopy/elfcopy.1 @@ -21,13 +21,14 @@ .\" out of the use of this software, even if advised of the possibility of .\" such damage. .\" -.\" $Id: elfcopy.1 3266 2015-12-07 15:38:26Z emaste $ +.\" $Id: elfcopy.1 3381 2016-01-30 19:39:47Z jkoshy $ .\" -.Dd December 7, 2015 +.Dd January 29, 2016 .Os .Dt ELFCOPY 1 .Sh NAME -.Nm elfcopy +.Nm elfcopy , +.Nm objcopy .Nd copy and translate object files .Sh SYNOPSIS .Nm @@ -85,7 +86,7 @@ .Sh DESCRIPTION The .Nm -utility copies the content of the ELF object named by argument +utility copies the content of the binary object named by argument .Ar infile to that named by argument .Ar outfile , @@ -121,6 +122,10 @@ to the output. .It Fl O Ar objformat | Fl -output-target= Ns Ar objformat Write the output file using the object format specified in argument .Ar objformat . +The argument +.Ar objformat +should be one of the target names recognized by +.Xr elftc_bfd_find_target 3 . .It Fl R Ar sectionname | Fl -remove-section= Ns Ar sectionname Remove any section with name .Ar sectionname @@ -330,8 +335,14 @@ Do not copy symbols that are not needed for relocation processing. .Xr mcs 1 , .Xr strip 1 , .Xr elf 3 , +.Xr elftc_bfd_find_target 3 , .Xr ar 5 , .Xr elf 5 +.Sh COMPATIBILITY +The +.Nm +utility is expected to be option compatible with GNU +.Nm objcopy . .Sh HISTORY .Nm has been implemented by diff --git a/contrib/elftoolchain/elfcopy/elfcopy.h b/contrib/elftoolchain/elfcopy/elfcopy.h index 48574b5..614c0e7 100644 --- a/contrib/elftoolchain/elfcopy/elfcopy.h +++ b/contrib/elftoolchain/elfcopy/elfcopy.h @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: elfcopy.h 3221 2015-05-24 23:42:43Z kaiwang27 $ + * $Id: elfcopy.h 3310 2016-01-10 09:10:54Z kaiwang27 $ */ #include <sys/queue.h> @@ -287,6 +287,7 @@ struct section *create_external_section(struct elfcopy *_ecp, const char *_name, int _loadable); void create_external_symtab(struct elfcopy *_ecp); void create_ihex(int _ifd, int _ofd); +void create_pe(struct elfcopy *_ecp, int _ifd, int _ofd); void create_scn(struct elfcopy *_ecp); void create_srec(struct elfcopy *_ecp, int _ifd, int _ofd, const char *_ofn); void create_symtab(struct elfcopy *_ecp); diff --git a/contrib/elftoolchain/elfcopy/main.c b/contrib/elftoolchain/elfcopy/main.c index e2685b4..b51ba4e 100644 --- a/contrib/elftoolchain/elfcopy/main.c +++ b/contrib/elftoolchain/elfcopy/main.c @@ -39,7 +39,7 @@ #include "elfcopy.h" -ELFTC_VCSID("$Id: main.c 3268 2015-12-07 20:30:55Z emaste $"); +ELFTC_VCSID("$Id: main.c 3399 2016-02-12 18:07:56Z emaste $"); enum options { @@ -316,6 +316,7 @@ create_elf(struct elfcopy *ecp) oeh.e_entry = ieh.e_entry; oeh.e_version = ieh.e_version; + ecp->flags &= ~(EXECUTABLE | DYNAMIC | RELOCATABLE); if (ieh.e_type == ET_EXEC) ecp->flags |= EXECUTABLE; else if (ieh.e_type == ET_DYN) @@ -722,6 +723,15 @@ create_file(struct elfcopy *ecp, const char *src, const char *dst) create_srec(ecp, ofd, ofd0, dst != NULL ? dst : src); break; + case ETF_PE: + case ETF_EFI: +#if WITH_PE + create_pe(ecp, ofd, ofd0); +#else + errx(EXIT_FAILURE, "PE/EFI support not enabled" + " at compile time"); +#endif + break; default: errx(EXIT_FAILURE, "Internal: unsupported" " output flavour %d", ecp->oec); @@ -1345,6 +1355,9 @@ set_output_target(struct elfcopy *ecp, const char *target_name) ecp->oed = elftc_bfd_target_byteorder(tgt); ecp->oem = elftc_bfd_target_machine(tgt); } + if (ecp->otf == ETF_EFI || ecp->otf == ETF_PE) + ecp->oem = elftc_bfd_target_machine(tgt); + ecp->otgt = target_name; } @@ -1366,7 +1379,7 @@ set_osabi(struct elfcopy *ecp, const char *abi) #define ELFCOPY_USAGE_MESSAGE "\ Usage: %s [options] infile [outfile]\n\ - Transform an ELF object.\n\n\ + Transform object files.\n\n\ Options:\n\ -d | -g | --strip-debug Remove debugging information from the output.\n\ -j SECTION | --only-section=SECTION\n\ @@ -1382,6 +1395,8 @@ Usage: %s [options] infile [outfile]\n\ -N SYM | --strip-symbol=SYM Do not copy symbol SYM to the output.\n\ -O FORMAT | --output-target=FORMAT\n\ Specify object format for the output file.\n\ + FORMAT should be a target name understood by\n\ + elftc_bfd_find_target(3).\n\ -R NAME | --remove-section=NAME\n\ Remove the named section.\n\ -S | --strip-all Remove all symbol and relocation information\n\ @@ -1471,6 +1486,7 @@ Usage: %s [options] file...\n\ Options:\n\ -d | -g | -S | --strip-debug Remove debugging symbols.\n\ -h | --help Print a help message.\n\ + -o FILE | --output-file FILE Write output to FILE.\n\ --only-keep-debug Keep debugging information only.\n\ -p | --preserve-dates Preserve access and modification times.\n\ -s | --strip-all Remove all symbols.\n\ diff --git a/contrib/elftoolchain/elfcopy/pe.c b/contrib/elftoolchain/elfcopy/pe.c new file mode 100644 index 0000000..0d075c5 --- /dev/null +++ b/contrib/elftoolchain/elfcopy/pe.c @@ -0,0 +1,233 @@ +/*- + * Copyright (c) 2016 Kai Wang + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/param.h> +#include <err.h> +#include <gelf.h> +#include <libpe.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#include "elfcopy.h" + +ELFTC_VCSID("$Id: pe.c 3312 2016-01-10 09:23:51Z kaiwang27 $"); + +/* Convert ELF object to Portable Executable (PE). */ +void +create_pe(struct elfcopy *ecp, int ifd, int ofd) +{ + Elf *e; + Elf_Scn *scn; + Elf_Data *d; + GElf_Ehdr eh; + GElf_Shdr sh; + PE *pe; + PE_Scn *ps; + PE_SecHdr psh; + PE_CoffHdr pch; + PE_OptHdr poh; + PE_Object po; + PE_Buffer *pb; + const char *name; + size_t indx; + int elferr, i; + + if (ecp->otf == ETF_EFI || ecp->oem == EM_X86_64) + po = PE_O_PE32P; + else + po = PE_O_PE32; + + if ((e = elf_begin(ifd, ELF_C_READ, NULL)) == NULL) + errx(EXIT_FAILURE, "elf_begin() failed: %s", + elf_errmsg(-1)); + + if (gelf_getehdr(e, &eh) == NULL) + errx(EXIT_FAILURE, "gelf_getehdr() failed: %s", + elf_errmsg(-1)); + + if (elf_getshstrndx(ecp->ein, &indx) == 0) + errx(EXIT_FAILURE, "elf_getshstrndx() failed: %s", + elf_errmsg(-1)); + + if ((pe = pe_init(ofd, PE_C_WRITE, po)) == NULL) + err(EXIT_FAILURE, "pe_init() failed"); + + /* Setup PE COFF header. */ + memset(&pch, 0, sizeof(pch)); + switch (ecp->oem) { + case EM_386: + pch.ch_machine = IMAGE_FILE_MACHINE_I386; + break; + case EM_X86_64: + pch.ch_machine = IMAGE_FILE_MACHINE_AMD64; + break; + default: + pch.ch_machine = IMAGE_FILE_MACHINE_UNKNOWN; + break; + } + pch.ch_timestamp = (uint32_t) time(NULL); + if (pe_update_coff_header(pe, &pch) < 0) + err(EXIT_FAILURE, "pe_update_coff_header() failed"); + + /* Setup PE optional header. */ + memset(&poh, 0, sizeof(poh)); + if (ecp->otf == ETF_EFI) + poh.oh_subsystem = IMAGE_SUBSYSTEM_EFI_APPLICATION; + poh.oh_entry = (uint32_t) eh.e_entry; + + /* + * Default section alignment and file alignment. (Here the + * section alignment is set to the default page size of the + * archs supported. We should use different section alignment + * for some arch. (e.g. IA64) + */ + poh.oh_secalign = 0x1000; + poh.oh_filealign = 0x200; + + /* Copy sections. */ + scn = NULL; + while ((scn = elf_nextscn(e, scn)) != NULL) { + + /* + * Read in ELF section. + */ + + if (gelf_getshdr(scn, &sh) == NULL) { + warnx("gelf_getshdr() failed: %s", elf_errmsg(-1)); + (void) elf_errno(); + continue; + } + if ((name = elf_strptr(ecp->ein, indx, sh.sh_name)) == + NULL) { + warnx("elf_strptr() failed: %s", elf_errmsg(-1)); + (void) elf_errno(); + continue; + } + + /* Skip sections unneeded. */ + if (strcmp(name, ".shstrtab") == 0 || + strcmp(name, ".symtab") == 0 || + strcmp(name, ".strtab") == 0) + continue; + + if ((d = elf_getdata(scn, NULL)) == NULL) { + warnx("elf_getdata() failed: %s", elf_errmsg(-1)); + (void) elf_errno(); + continue; + } + + if (strcmp(name, ".text") == 0) { + poh.oh_textbase = (uint32_t) sh.sh_addr; + poh.oh_textsize = (uint32_t) roundup(sh.sh_size, + poh.oh_filealign); + } else { + if (po == PE_O_PE32 && strcmp(name, ".data") == 0) + poh.oh_database = sh.sh_addr; + if (sh.sh_type == SHT_NOBITS) + poh.oh_bsssize += (uint32_t) + roundup(sh.sh_size, poh.oh_filealign); + else if (sh.sh_flags & SHF_ALLOC) + poh.oh_datasize += (uint32_t) + roundup(sh.sh_size, poh.oh_filealign); + } + + /* + * Create PE/COFF section. + */ + + if ((ps = pe_newscn(pe)) == NULL) { + warn("pe_newscn() failed"); + continue; + } + + /* + * Setup PE/COFF section header. The section name is not + * NUL-terminated if its length happens to be 8. Long + * section name should be truncated for PE image according + * to the PE/COFF specification. + */ + memset(&psh, 0, sizeof(psh)); + strncpy(psh.sh_name, name, sizeof(psh.sh_name)); + psh.sh_addr = sh.sh_addr; + psh.sh_virtsize = sh.sh_size; + if (sh.sh_type != SHT_NOBITS) + psh.sh_rawsize = sh.sh_size; + else + psh.sh_char |= IMAGE_SCN_CNT_UNINITIALIZED_DATA; + + /* + * Translate ELF section flags to PE/COFF section flags. + */ + psh.sh_char |= IMAGE_SCN_MEM_READ; + if (sh.sh_flags & SHF_WRITE) + psh.sh_char |= IMAGE_SCN_MEM_WRITE; + if (sh.sh_flags & SHF_EXECINSTR) + psh.sh_char |= IMAGE_SCN_MEM_EXECUTE | + IMAGE_SCN_CNT_CODE; + if ((sh.sh_flags & SHF_ALLOC) && (psh.sh_char & 0xF0) == 0) + psh.sh_char |= IMAGE_SCN_CNT_INITIALIZED_DATA; + for (i = 0xE; i > 0; i--) { + if (sh.sh_addralign & (1U << (i - 1))) { + psh.sh_char |= i << 20; + break; + } + } + + /* Mark relocation section "discardable". */ + if (strcmp(name, ".reloc") == 0) + psh.sh_char |= IMAGE_SCN_MEM_DISCARDABLE; + + if (pe_update_section_header(ps, &psh) < 0) { + warn("pe_update_section_header() failed"); + continue; + } + + /* Copy section content. */ + if ((pb = pe_newbuffer(ps)) == NULL) { + warn("pe_newbuffer() failed"); + continue; + } + pb->pb_align = 1; + pb->pb_off = 0; + pb->pb_size = sh.sh_size; + pb->pb_buf = d->d_buf; + } + elferr = elf_errno(); + if (elferr != 0) + warnx("elf_nextscn() failed: %s", elf_errmsg(elferr)); + + /* Update PE optional header. */ + if (pe_update_opt_header(pe, &poh) < 0) + err(EXIT_FAILURE, "pe_update_opt_header() failed"); + + /* Write out PE/COFF object. */ + if (pe_update(pe) < 0) + err(EXIT_FAILURE, "pe_update() failed"); + + pe_finish(pe); + elf_end(e); +} diff --git a/contrib/elftoolchain/elfcopy/sections.c b/contrib/elftoolchain/elfcopy/sections.c index a17c9ab..2ba3d48 100644 --- a/contrib/elftoolchain/elfcopy/sections.c +++ b/contrib/elftoolchain/elfcopy/sections.c @@ -34,7 +34,7 @@ #include "elfcopy.h" -ELFTC_VCSID("$Id: sections.c 3272 2015-12-11 20:00:54Z kaiwang27 $"); +ELFTC_VCSID("$Id: sections.c 3346 2016-01-17 20:09:15Z kaiwang27 $"); static void add_gnu_debuglink(struct elfcopy *ecp); static uint32_t calc_crc32(const char *p, size_t len, uint32_t crc); @@ -223,6 +223,7 @@ static int is_debug_section(const char *name) { const char *dbg_sec[] = { + ".apple_", ".debug", ".gnu.linkonce.wi.", ".line", @@ -369,7 +370,7 @@ create_scn(struct elfcopy *ecp) is = NULL; while ((is = elf_nextscn(ecp->ein, is)) != NULL) { if (gelf_getshdr(is, &ish) == NULL) - errx(EXIT_FAILURE, "219 gelf_getshdr failed: %s", + errx(EXIT_FAILURE, "gelf_getshdr failed: %s", elf_errmsg(-1)); if ((name = elf_strptr(ecp->ein, indx, ish.sh_name)) == NULL) errx(EXIT_FAILURE, "elf_strptr failed: %s", @@ -416,12 +417,19 @@ create_scn(struct elfcopy *ecp) * is loadable, but if user explicitly set section flags * while neither "load" nor "alloc" is set, we make the * section unloadable. + * + * Sections in relocatable object is loadable if + * section flag SHF_ALLOC is set. */ if (sec_flags && (sec_flags & (SF_LOAD | SF_ALLOC)) == 0) s->loadable = 0; - else + else { s->loadable = add_to_inseg_list(ecp, s); + if ((ecp->flags & RELOCATABLE) && + (ish.sh_flags & SHF_ALLOC)) + s->loadable = 1; + } } else { /* Assuming .shstrtab is "unloadable". */ s = ecp->shstrtab; @@ -875,10 +883,10 @@ resync_sections(struct elfcopy *ecp) if (s->align == 0) s->align = 1; if (off <= s->off) { - if (!s->loadable) + if (!s->loadable || (ecp->flags & RELOCATABLE)) s->off = roundup(off, s->align); } else { - if (s->loadable) + if (s->loadable && (ecp->flags & RELOCATABLE) == 0) warnx("moving loadable section %s, " "is this intentional?", s->name); s->off = roundup(off, s->align); @@ -1028,8 +1036,11 @@ print_section(struct section *s) print_data(s->buf, s->sz); } else { id = NULL; - while ((id = elf_getdata(s->is, id)) != NULL) + while ((id = elf_getdata(s->is, id)) != NULL || + (id = elf_rawdata(s->is, id)) != NULL) { + (void) elf_errno(); print_data(id->d_buf, id->d_size); + } elferr = elf_errno(); if (elferr != 0) errx(EXIT_FAILURE, "elf_getdata() failed: %s", @@ -1049,7 +1060,9 @@ read_section(struct section *s, size_t *size) sz = 0; b = NULL; id = NULL; - while ((id = elf_getdata(s->is, id)) != NULL) { + while ((id = elf_getdata(s->is, id)) != NULL || + (id = elf_rawdata(s->is, id)) != NULL) { + (void) elf_errno(); if (b == NULL) b = malloc(id->d_size); else @@ -1077,10 +1090,10 @@ copy_shdr(struct elfcopy *ecp, struct section *s, const char *name, int copy, GElf_Shdr ish, osh; if (gelf_getshdr(s->is, &ish) == NULL) - errx(EXIT_FAILURE, "526 gelf_getshdr() failed: %s", + errx(EXIT_FAILURE, "gelf_getshdr() failed: %s", elf_errmsg(-1)); if (gelf_getshdr(s->os, &osh) == NULL) - errx(EXIT_FAILURE, "529 gelf_getshdr() failed: %s", + errx(EXIT_FAILURE, "gelf_getshdr() failed: %s", elf_errmsg(-1)); if (copy) @@ -1097,19 +1110,32 @@ copy_shdr(struct elfcopy *ecp, struct section *s, const char *name, int copy, if (sec_flags) { osh.sh_flags = 0; - if (sec_flags & SF_ALLOC) { + if (sec_flags & SF_ALLOC) osh.sh_flags |= SHF_ALLOC; - if (!s->loadable) - warnx("set SHF_ALLOC flag for " - "unloadable section %s", - s->name); - } if ((sec_flags & SF_READONLY) == 0) osh.sh_flags |= SHF_WRITE; if (sec_flags & SF_CODE) osh.sh_flags |= SHF_EXECINSTR; + if ((sec_flags & SF_CONTENTS) && + s->type == SHT_NOBITS && s->sz > 0) { + /* + * Convert SHT_NOBITS section to section with + * (zero'ed) content on file. + */ + osh.sh_type = s->type = SHT_PROGBITS; + if ((s->buf = calloc(1, s->sz)) == NULL) + err(EXIT_FAILURE, "malloc failed"); + s->nocopy = 1; + } } else { osh.sh_flags = ish.sh_flags; + /* + * Newer binutils as(1) emits the section flag + * SHF_INFO_LINK for relocation sections. elfcopy + * emits this flag in the output section if it's + * missing in the input section, to remain compatible + * with binutils. + */ if (ish.sh_type == SHT_REL || ish.sh_type == SHT_RELA) osh.sh_flags |= SHF_INFO_LINK; } @@ -1135,11 +1161,14 @@ copy_data(struct section *s) return; if ((id = elf_getdata(s->is, NULL)) == NULL) { - elferr = elf_errno(); - if (elferr != 0) - errx(EXIT_FAILURE, "elf_getdata() failed: %s", - elf_errmsg(elferr)); - return; + (void) elf_errno(); + if ((id = elf_rawdata(s->is, NULL)) == NULL) { + elferr = elf_errno(); + if (elferr != 0) + errx(EXIT_FAILURE, "failed to read section:" + " %s", s->name); + return; + } } if ((od = elf_newdata(s->os)) == NULL) @@ -1245,6 +1274,7 @@ insert_sections(struct elfcopy *ecp) struct sec_add *sa; struct section *s; size_t off; + uint64_t stype; /* Put these sections in the end of current list. */ off = 0; @@ -1259,8 +1289,20 @@ insert_sections(struct elfcopy *ecp) /* TODO: Add section header vma/lma, flag changes here */ + /* + * The default section type for user added section is + * SHT_PROGBITS. If the section name match certain patterns, + * elfcopy will try to set a more appropriate section type. + * However, data type is always set to ELF_T_BYTE and no + * translation is performed by libelf. + */ + stype = SHT_PROGBITS; + if (strcmp(sa->name, ".note") == 0 || + strncmp(sa->name, ".note.", strlen(".note.")) == 0) + stype = SHT_NOTE; + (void) create_external_section(ecp, sa->name, NULL, sa->content, - sa->size, off, SHT_PROGBITS, ELF_T_BYTE, 0, 1, 0, 0); + sa->size, off, stype, ELF_T_BYTE, 0, 1, 0, 0); } } @@ -1285,7 +1327,7 @@ update_shdr(struct elfcopy *ecp, int update_link) continue; if (gelf_getshdr(s->os, &osh) == NULL) - errx(EXIT_FAILURE, "668 gelf_getshdr failed: %s", + errx(EXIT_FAILURE, "gelf_getshdr failed: %s", elf_errmsg(-1)); /* Find section name in string table and set sh_name. */ @@ -1364,7 +1406,7 @@ set_shstrtab(struct elfcopy *ecp) } if (gelf_getshdr(s->os, &sh) == NULL) - errx(EXIT_FAILURE, "692 gelf_getshdr() failed: %s", + errx(EXIT_FAILURE, "gelf_getshdr() failed: %s", elf_errmsg(-1)); sh.sh_addr = 0; sh.sh_addralign = 1; @@ -1431,14 +1473,17 @@ add_section(struct elfcopy *ecp, const char *arg) if (stat(fn, &sb) == -1) err(EXIT_FAILURE, "stat failed"); sa->size = sb.st_size; - if ((sa->content = malloc(sa->size)) == NULL) - err(EXIT_FAILURE, "malloc failed"); - if ((fp = fopen(fn, "r")) == NULL) - err(EXIT_FAILURE, "can not open %s", fn); - if (fread(sa->content, 1, sa->size, fp) == 0 || - ferror(fp)) - err(EXIT_FAILURE, "fread failed"); - fclose(fp); + if (sa->size > 0) { + if ((sa->content = malloc(sa->size)) == NULL) + err(EXIT_FAILURE, "malloc failed"); + if ((fp = fopen(fn, "r")) == NULL) + err(EXIT_FAILURE, "can not open %s", fn); + if (fread(sa->content, 1, sa->size, fp) == 0 || + ferror(fp)) + err(EXIT_FAILURE, "fread failed"); + fclose(fp); + } else + sa->content = NULL; STAILQ_INSERT_TAIL(&ecp->v_sadd, sa, sadd_list); ecp->flags |= SEC_ADD; diff --git a/contrib/elftoolchain/elfcopy/segments.c b/contrib/elftoolchain/elfcopy/segments.c index 837cea5..8ce0b83 100644 --- a/contrib/elftoolchain/elfcopy/segments.c +++ b/contrib/elftoolchain/elfcopy/segments.c @@ -34,7 +34,7 @@ #include "elfcopy.h" -ELFTC_VCSID("$Id: segments.c 3269 2015-12-11 18:38:43Z kaiwang27 $"); +ELFTC_VCSID("$Id: segments.c 3397 2016-02-12 14:35:19Z emaste $"); static void insert_to_inseg_list(struct segment *seg, struct section *sec); @@ -107,11 +107,11 @@ adjust_addr(struct elfcopy *ecp) TAILQ_FOREACH(s, &ecp->v_sec, sec_list) { /* Only adjust loadable section's address. */ - if (!s->loadable || s->seg == NULL) + if (!s->loadable) continue; /* Apply global LMA adjustment. */ - if (ecp->change_addr != 0) + if (ecp->change_addr != 0 && s->seg != NULL) s->lma += ecp->change_addr; if (!s->pseudo) { @@ -135,7 +135,10 @@ adjust_addr(struct elfcopy *ecp) */ TAILQ_FOREACH(s, &ecp->v_sec, sec_list) { - /* Only adjust loadable section's LMA. */ + /* + * Only loadable section that's inside a segment can have + * LMA adjusted. + */ if (!s->loadable || s->seg == NULL) continue; @@ -173,7 +176,7 @@ adjust_addr(struct elfcopy *ecp) if (lma % s->align != 0) errx(EXIT_FAILURE, "The load address %#jx for " "section %s is not aligned to %ju", - (uintmax_t) lma, s->name, s->align); + (uintmax_t) lma, s->name, (uintmax_t) s->align); if (lma < s->lma) { /* Move section to lower address. */ @@ -214,7 +217,8 @@ adjust_addr(struct elfcopy *ecp) continue; errx(EXIT_FAILURE, "The extent of segment containing " "section %s overlaps with segment(%#jx,%#jx)", - s->name, seg->addr, seg->addr + seg->msz); + s->name, (uintmax_t) seg->addr, + (uintmax_t) (seg->addr + seg->msz)); } /* @@ -485,7 +489,7 @@ copy_phdr(struct elfcopy *ecp) ophdr.p_filesz = seg->fsz; ophdr.p_memsz = seg->msz; if (!gelf_update_phdr(ecp->eout, i, &ophdr)) - err(EXIT_FAILURE, "gelf_update_phdr failed :%s", + errx(EXIT_FAILURE, "gelf_update_phdr failed: %s", elf_errmsg(-1)); i++; diff --git a/contrib/elftoolchain/elfcopy/symbols.c b/contrib/elftoolchain/elfcopy/symbols.c index 05bcd7a..4423ca2 100644 --- a/contrib/elftoolchain/elfcopy/symbols.c +++ b/contrib/elftoolchain/elfcopy/symbols.c @@ -25,6 +25,7 @@ */ #include <sys/param.h> +#include <assert.h> #include <err.h> #include <fnmatch.h> #include <stdio.h> @@ -33,7 +34,13 @@ #include "elfcopy.h" -ELFTC_VCSID("$Id: symbols.c 3222 2015-05-24 23:47:23Z kaiwang27 $"); +ELFTC_VCSID("$Id: symbols.c 3376 2016-01-26 18:41:39Z emaste $"); + +/* Backwards compatibility for systems with older ELF definitions. */ +#ifndef STB_GNU_UNIQUE +#define STB_GNU_UNIQUE 10 +#endif + /* Symbol table buffer structure. */ struct symbuf { @@ -79,7 +86,6 @@ static int lookup_exact_string(hash_head *hash, const char *buf, static int generate_symbols(struct elfcopy *ecp); static void mark_reloc_symbols(struct elfcopy *ecp, size_t sc); static void mark_section_group_symbols(struct elfcopy *ecp, size_t sc); -static int match_wildcard(const char *name, const char *pattern); uint32_t str_hash(const char *s); /* Convenient bit vector operation macros. */ @@ -102,7 +108,8 @@ static int is_global_symbol(unsigned char st_info) { - if (GELF_ST_BIND(st_info) == STB_GLOBAL) + if (GELF_ST_BIND(st_info) == STB_GLOBAL || + GELF_ST_BIND(st_info) == STB_GNU_UNIQUE) return (1); return (0); @@ -190,12 +197,6 @@ is_remove_symbol(struct elfcopy *ecp, size_t sc, int i, GElf_Sym *s, SHN_UNDEF, /* st_shndx */ }; - if (lookup_symop_list(ecp, name, SYMOP_KEEP) != NULL) - return (0); - - if (lookup_symop_list(ecp, name, SYMOP_STRIP) != NULL) - return (1); - /* * Keep the first symbol if it is the special reserved symbol. * XXX Should we generate one if it's missing? @@ -208,15 +209,34 @@ is_remove_symbol(struct elfcopy *ecp, size_t sc, int i, GElf_Sym *s, ecp->secndx[s->st_shndx] == 0) return (1); + /* Keep the symbol if specified by command line option -K. */ + if (lookup_symop_list(ecp, name, SYMOP_KEEP) != NULL) + return (0); + if (ecp->strip == STRIP_ALL) return (1); + /* Mark symbols used in relocation. */ if (ecp->v_rel == NULL) mark_reloc_symbols(ecp, sc); + /* Mark symbols used in section groups. */ if (ecp->v_grp == NULL) mark_section_group_symbols(ecp, sc); + /* + * Strip the symbol if specified by command line option -N, + * unless it's used in relocation. + */ + if (lookup_symop_list(ecp, name, SYMOP_STRIP) != NULL) { + if (BIT_ISSET(ecp->v_rel, i)) { + warnx("not stripping symbol `%s' because it is named" + " in a relocation", name); + return (0); + } + return (1); + } + if (is_needed_symbol(ecp, i, s)) return (0); @@ -565,8 +585,11 @@ generate_symbols(struct elfcopy *ecp) * If the symbol is a STT_SECTION symbol, mark the section * it points to. */ - if (GELF_ST_TYPE(sym.st_info) == STT_SECTION) + if (GELF_ST_TYPE(sym.st_info) == STT_SECTION && + sym.st_shndx < SHN_LORESERVE) { + assert(ecp->secndx[sym.st_shndx] < (uint64_t)ecp->nos); BIT_SET(ecp->v_secsym, ecp->secndx[sym.st_shndx]); + } } /* @@ -861,6 +884,8 @@ add_to_symtab(struct elfcopy *ecp, const char *name, uint64_t st_value, * It handles buffer growing, st_name calculating and st_shndx * updating for symbols with non-special section index. */ +#define _ST_NAME_EMPTY_l 0 +#define _ST_NAME_EMPTY_g -1 #define _ADDSYM(B, SZ) do { \ if (sy_buf->B##SZ == NULL) { \ sy_buf->B##SZ = malloc(sy_buf->B##cap * \ @@ -920,7 +945,8 @@ add_to_symtab(struct elfcopy *ecp, const char *name, uint64_t st_value, st_buf->B.sz += strlen(name) + 1; \ } \ } else \ - sy_buf->B##SZ[sy_buf->n##B##s].st_name = 0; \ + sy_buf->B##SZ[sy_buf->n##B##s].st_name = \ + (Elf##SZ##_Word)_ST_NAME_EMPTY_##B; \ sy_buf->n##B##s++; \ } while (0) @@ -945,6 +971,8 @@ add_to_symtab(struct elfcopy *ecp, const char *name, uint64_t st_value, ecp->strtab->sz = st_buf->l.sz + st_buf->g.sz; #undef _ADDSYM +#undef _ST_NAME_EMPTY_l +#undef _ST_NAME_EMPTY_g } void @@ -961,10 +989,17 @@ finalize_external_symtab(struct elfcopy *ecp) sy_buf = ecp->symtab->buf; st_buf = ecp->strtab->buf; for (i = 0; (size_t) i < sy_buf->ngs; i++) { - if (ecp->oec == ELFCLASS32) - sy_buf->g32[i].st_name += st_buf->l.sz; - else - sy_buf->g64[i].st_name += st_buf->l.sz; + if (ecp->oec == ELFCLASS32) { + if (sy_buf->g32[i].st_name == (Elf32_Word)-1) + sy_buf->g32[i].st_name = 0; + else + sy_buf->g32[i].st_name += st_buf->l.sz; + } else { + if (sy_buf->g64[i].st_name == (Elf64_Word)-1) + sy_buf->g64[i].st_name = 0; + else + sy_buf->g64[i].st_name += st_buf->l.sz; + } } } @@ -1105,46 +1140,47 @@ add_to_symop_list(struct elfcopy *ecp, const char *name, const char *newname, { struct symop *s; - if ((s = lookup_symop_list(ecp, name, ~0U)) == NULL) { - if ((s = calloc(1, sizeof(*s))) == NULL) - errx(EXIT_FAILURE, "not enough memory"); - s->name = name; - if (op == SYMOP_REDEF) - s->newname = newname; - } + assert (name != NULL); + STAILQ_FOREACH(s, &ecp->v_symop, symop_list) + if (!strcmp(name, s->name)) + goto found; - s->op |= op; + if ((s = calloc(1, sizeof(*s))) == NULL) + errx(EXIT_FAILURE, "not enough memory"); STAILQ_INSERT_TAIL(&ecp->v_symop, s, symop_list); -} - -static int -match_wildcard(const char *name, const char *pattern) -{ - int reverse, match; - - reverse = 0; - if (*pattern == '!') { - reverse = 1; - pattern++; - } - - match = 0; - if (!fnmatch(pattern, name, 0)) - match = 1; - - return (reverse ? !match : match); + s->name = name; +found: + if (op == SYMOP_REDEF) + s->newname = newname; + s->op |= op; } struct symop * lookup_symop_list(struct elfcopy *ecp, const char *name, unsigned int op) { - struct symop *s; + struct symop *s, *ret; + const char *pattern; STAILQ_FOREACH(s, &ecp->v_symop, symop_list) { - if (name == NULL || !strcmp(name, s->name) || - ((ecp->flags & WILDCARD) && match_wildcard(name, s->name))) - if ((s->op & op) != 0) + if ((s->op & op) == 0) + continue; + if (name == NULL || !strcmp(name, s->name)) return (s); + if ((ecp->flags & WILDCARD) == 0) + continue; + + /* Handle wildcards. */ + pattern = s->name; + if (pattern[0] == '!') { + /* Negative match. */ + pattern++; + ret = NULL; + } else { + /* Regular wildcard match. */ + ret = s; + } + if (!fnmatch(pattern, name, 0)) + return (ret); } return (NULL); |