summaryrefslogtreecommitdiffstats
path: root/contrib/elftoolchain/elfcopy
diff options
context:
space:
mode:
authoremaste <emaste@FreeBSD.org>2016-02-12 20:54:02 +0000
committeremaste <emaste@FreeBSD.org>2016-02-12 20:54:02 +0000
commita6ae90983efabb9784f1e105ffb29eaec3c0573c (patch)
treecd8537a698afe8dd30dc9c4d04c193e5b3b2e94f /contrib/elftoolchain/elfcopy
parent0309ab8781484f9cf0561cbbc3cab6df7139d629 (diff)
parent85217dee0e24c5f3ac285420e843063b4b52c1a0 (diff)
downloadFreeBSD-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/Makefile23
-rw-r--r--contrib/elftoolchain/elfcopy/archive.c6
-rw-r--r--contrib/elftoolchain/elfcopy/elfcopy.119
-rw-r--r--contrib/elftoolchain/elfcopy/elfcopy.h3
-rw-r--r--contrib/elftoolchain/elfcopy/main.c20
-rw-r--r--contrib/elftoolchain/elfcopy/pe.c233
-rw-r--r--contrib/elftoolchain/elfcopy/sections.c107
-rw-r--r--contrib/elftoolchain/elfcopy/segments.c18
-rw-r--r--contrib/elftoolchain/elfcopy/symbols.c126
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);
OpenPOWER on IntegriCloud