aboutsummaryrefslogtreecommitdiff
path: root/binutils
diff options
context:
space:
mode:
authorH.J. Lu <hjl.tools@gmail.com>2018-11-06 09:38:33 -0800
committerH.J. Lu <hjl.tools@gmail.com>2018-11-06 09:38:51 -0800
commit8a6b075bc07f66678ed0176f895847df3ea7fcef (patch)
treeb900eb85546d6700c2ff9af49d863bf08e5e490a /binutils
parentddea148b3da27eb681504bf341f45abb7a74580b (diff)
downloadbinutils-8a6b075bc07f66678ed0176f895847df3ea7fcef.zip
binutils-8a6b075bc07f66678ed0176f895847df3ea7fcef.tar.gz
binutils-8a6b075bc07f66678ed0176f895847df3ea7fcef.tar.bz2
elfedit: Add --enable-x86-feature/--disable-x86-feature
Add --enable-x86-feature and --disable-x86-feature options to elfedit to set and clear the IBT and SHSTK bits in program property in ELF executables and shared objects. binutils/ * doc/binutils.texi: Document --enable-x86-feature and --disable-x86-feature options for elfedit. * elfedit.c: Include "config.h" and <sys/mman.h>. (enable_x86_features): New. (disable_x86_features): Likewise. (update_gnu_property): Likewise. (elf_x86_feature): Likewise. (process_file): Call update_gnu_property on ET_EXEC or ET_DYN file. (command_line_switch): Add OPTION_ENABLE_X86_FEATURE and OPTION_DISABLE_X86_FEATURE. (options): Add--enable-x86-feature and --disable-x86-feature. (usage): Likewise. (main): Handle OPTION_ENABLE_X86_FEATURE and OPTION_DISABLE_X86_FEATURE. ld/ * testsuite/config/default.exp (ELFEDIT): New. * testsuite/ld-elf/linux-x86.exp (elfedit_test): New proc. Run elfedit tests. * testsuite/ld-elf/x86-feature-1a.rd: New file. * testsuite/ld-elf/x86-feature-1b.rd: Likewise. * testsuite/ld-elf/x86-feature-1c.rd: Likewise. * testsuite/ld-elf/x86-feature-1d.rd: Likewise. * testsuite/ld-elf/x86-feature-1e.rd: Likewise.
Diffstat (limited to 'binutils')
-rw-r--r--binutils/ChangeLog18
-rw-r--r--binutils/doc/binutils.texi34
-rw-r--r--binutils/elfedit.c256
3 files changed, 298 insertions, 10 deletions
diff --git a/binutils/ChangeLog b/binutils/ChangeLog
index bdbee0f..f484f92 100644
--- a/binutils/ChangeLog
+++ b/binutils/ChangeLog
@@ -1,3 +1,21 @@
+2018-11-06 H.J. Lu <hongjiu.lu@intel.com>
+
+ * doc/binutils.texi: Document --enable-x86-feature and
+ --disable-x86-feature options for elfedit.
+ * elfedit.c: Include "config.h" and <sys/mman.h>.
+ (enable_x86_features): New.
+ (disable_x86_features): Likewise.
+ (update_gnu_property): Likewise.
+ (elf_x86_feature): Likewise.
+ (process_file): Call update_gnu_property on ET_EXEC or ET_DYN
+ file.
+ (command_line_switch): Add OPTION_ENABLE_X86_FEATURE and
+ OPTION_DISABLE_X86_FEATURE.
+ (options): Add--enable-x86-feature and --disable-x86-feature.
+ (usage): Likewise.
+ (main): Handle OPTION_ENABLE_X86_FEATURE and
+ OPTION_DISABLE_X86_FEATURE.
+
2018-11-03 H.J. Lu <hongjiu.lu@intel.com>
* elfedit.c (update_elf_header): Move EI_MAG? check to ...
diff --git a/binutils/doc/binutils.texi b/binutils/doc/binutils.texi
index 6edd7b1..6cfda45 100644
--- a/binutils/doc/binutils.texi
+++ b/binutils/doc/binutils.texi
@@ -42,7 +42,7 @@ section entitled ``GNU Free Documentation License''.
* size: (binutils)size. List section sizes and total size.
* strings: (binutils)strings. List printable strings from files.
* strip: (binutils)strip. Discard symbols.
-* elfedit: (binutils)elfedit. Update the ELF header of ELF files.
+* elfedit: (binutils)elfedit. Update ELF header and property of ELF files.
* windmc: (binutils)windmc. Generator for Windows message resources.
* windres: (binutils)windres. Manipulate Windows resources.
@end direntry
@@ -111,7 +111,7 @@ List printable strings from files
Discard symbols
@item elfedit
-Update the ELF header of ELF files.
+Update the ELF header and program property of ELF files.
@item c++filt
Demangle encoded C++ symbols (on MS-DOS, this program is named
@@ -151,7 +151,7 @@ in the section entitled ``GNU Free Documentation License''.
* windres:: Manipulate Windows resources
* dlltool:: Create files needed to build and use DLLs
* readelf:: Display the contents of ELF format files
-* elfedit:: Update the ELF header of ELF files
+* elfedit:: Update ELF header and property of ELF files
* Common Options:: Command-line options for all utilities
* Selecting the Target System:: How these utilities determine the target
* Reporting Bugs:: Reporting Bugs
@@ -4725,7 +4725,7 @@ objdump(1), and the Info entries for @file{binutils}.
@cindex Update ELF header
@kindex elfedit
-@c man title elfedit Update the ELF header of ELF files.
+@c man title elfedit Update ELF header and program property of ELF files.
@smallexample
@c man begin SYNOPSIS elfedit
@@ -4735,6 +4735,8 @@ elfedit [@option{--input-mach=}@var{machine}]
@option{--output-mach=}@var{machine}
@option{--output-type=}@var{type}
@option{--output-osabi=}@var{osabi}
+ @option{--enable-x86-feature=}@var{feature}
+ @option{--disable-x86-feature=}@var{feature}
[@option{-v}|@option{--version}]
[@option{-h}|@option{--help}]
@var{elffile}@dots{}
@@ -4743,9 +4745,10 @@ elfedit [@option{--input-mach=}@var{machine}]
@c man begin DESCRIPTION elfedit
-@command{elfedit} updates the ELF header of ELF files which have
-the matching ELF machine and file types. The options control how and
-which fields in the ELF header should be updated.
+@command{elfedit} updates the ELF header and program property of ELF
+files which have the matching ELF machine and file types. The options
+control how and which fields in the ELF header and program property
+should be updated.
@var{elffile}@dots{} are the ELF files to be updated. 32-bit and
64-bit ELF files are supported, as are archives containing ELF files.
@@ -4755,7 +4758,9 @@ which fields in the ELF header should be updated.
The long and short forms of options, shown here as alternatives, are
equivalent. At least one of the @option{--output-mach},
-@option{--output-type} and @option{--output-osabi} options must be given.
+@option{--output-type}, @option{--output-osabi},
+@option{--enable-x86-feature} and @option{--disable-x86-feature}
+options must be given.
@table @env
@@ -4795,6 +4800,19 @@ The supported ELF OSABIs are, @var{none}, @var{HPUX}, @var{NetBSD},
Change the ELF OSABI in the ELF header to @var{osabi}. The
supported ELF OSABI are the same as @option{--input-osabi}.
+@item --enable-x86-feature=@var{feature}
+Set the @var{feature} bit in program property in @var{exec} or @var{dyn}
+ELF files with machine types of @var{i386} or @var{x86-64}. The
+supported features are, @var{ibt} and @var{shstk}.
+
+@item --disable-x86-feature=@var{feature}
+Clear the @var{feature} bit in program property in @var{exec} or
+@var{dyn} ELF files with machine types of @var{i386} or @var{x86-64}.
+The supported features are the same as @option{--enable-x86-feature}.
+
+Note: @option{--enable-x86-feature} and @option{--disable-x86-feature}
+are available only on hosts with @samp{mmap} support.
+
@item -v
@itemx --version
Display the version number of @command{elfedit}.
diff --git a/binutils/elfedit.c b/binutils/elfedit.c
index a9f7c9d..98d4fd7 100644
--- a/binutils/elfedit.c
+++ b/binutils/elfedit.c
@@ -18,6 +18,7 @@
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
02110-1301, USA. */
+#include "config.h"
#include "sysdep.h"
#include <assert.h>
@@ -65,6 +66,217 @@ enum elfclass
static enum elfclass input_elf_class = ELF_CLASS_UNKNOWN;
static enum elfclass output_elf_class = ELF_CLASS_BOTH;
+#ifdef HAVE_MMAP
+#include <sys/mman.h>
+
+static unsigned int enable_x86_features;
+static unsigned int disable_x86_features;
+
+static int
+update_gnu_property (const char *file_name, FILE *file)
+{
+ char *map;
+ Elf_Internal_Phdr *phdrs;
+ struct stat st_buf;
+ unsigned int i;
+ int ret;
+
+ if (!enable_x86_features && !disable_x86_features)
+ return 0;
+
+ if (elf_header.e_machine != EM_386
+ && elf_header.e_machine != EM_X86_64)
+ {
+ error (_("%s: Not an i386 nor x86-64 ELF file\n"), file_name);
+ return 0;
+ }
+
+ if (fstat (fileno (file), &st_buf) < 0)
+ {
+ error (_("%s: stat () failed\n"), file_name);
+ return 1;
+ }
+
+ map = mmap (NULL, st_buf.st_size, PROT_READ | PROT_WRITE,
+ MAP_SHARED, fileno (file), 0);
+ if (map == MAP_FAILED)
+ {
+ error (_("%s: mmap () failed\n"), file_name);
+ return 0;
+ }
+
+ phdrs = xmalloc (elf_header.e_phnum * sizeof (*phdrs));
+
+ if (elf_header.e_ident[EI_CLASS] == ELFCLASS32)
+ {
+ Elf32_External_Phdr *phdrs32
+ = (Elf32_External_Phdr *) (map + elf_header.e_phoff);
+ for (i = 0; i < elf_header.e_phnum; i++)
+ {
+ phdrs[i].p_type = BYTE_GET (phdrs32[i].p_type);
+ phdrs[i].p_offset = BYTE_GET (phdrs32[i].p_offset);
+ phdrs[i].p_vaddr = BYTE_GET (phdrs32[i].p_vaddr);
+ phdrs[i].p_paddr = BYTE_GET (phdrs32[i].p_paddr);
+ phdrs[i].p_filesz = BYTE_GET (phdrs32[i].p_filesz);
+ phdrs[i].p_memsz = BYTE_GET (phdrs32[i].p_memsz);
+ phdrs[i].p_flags = BYTE_GET (phdrs32[i].p_flags);
+ phdrs[i].p_align = BYTE_GET (phdrs32[i].p_align);
+ }
+ }
+ else
+ {
+ Elf64_External_Phdr *phdrs64
+ = (Elf64_External_Phdr *) (map + elf_header.e_phoff);
+ for (i = 0; i < elf_header.e_phnum; i++)
+ {
+ phdrs[i].p_type = BYTE_GET (phdrs64[i].p_type);
+ phdrs[i].p_offset = BYTE_GET (phdrs64[i].p_offset);
+ phdrs[i].p_vaddr = BYTE_GET (phdrs64[i].p_vaddr);
+ phdrs[i].p_paddr = BYTE_GET (phdrs64[i].p_paddr);
+ phdrs[i].p_filesz = BYTE_GET (phdrs64[i].p_filesz);
+ phdrs[i].p_memsz = BYTE_GET (phdrs64[i].p_memsz);
+ phdrs[i].p_flags = BYTE_GET (phdrs64[i].p_flags);
+ phdrs[i].p_align = BYTE_GET (phdrs64[i].p_align);
+ }
+ }
+
+ ret = 0;
+ for (i = 0; i < elf_header.e_phnum; i++)
+ if (phdrs[i].p_type == PT_NOTE)
+ {
+ size_t offset = phdrs[i].p_offset;
+ size_t size = phdrs[i].p_filesz;
+ size_t align = phdrs[i].p_align;
+ char *buf = map + offset;
+ char *p = buf;
+
+ while (p < buf + size)
+ {
+ Elf_External_Note *xnp = (Elf_External_Note *) p;
+ Elf_Internal_Note in;
+
+ if (offsetof (Elf_External_Note, name) > buf - p + size)
+ {
+ ret = 1;
+ goto out;
+ }
+
+ in.type = BYTE_GET (xnp->type);
+ in.namesz = BYTE_GET (xnp->namesz);
+ in.namedata = xnp->name;
+ if (in.namesz > buf - in.namedata + size)
+ {
+ ret = 1;
+ goto out;
+ }
+
+ in.descsz = BYTE_GET (xnp->descsz);
+ in.descdata = p + ELF_NOTE_DESC_OFFSET (in.namesz, align);
+ in.descpos = offset + (in.descdata - buf);
+ if (in.descsz != 0
+ && (in.descdata >= buf + size
+ || in.descsz > buf - in.descdata + size))
+ {
+ ret = 1;
+ goto out;
+ }
+
+ if (in.namesz == sizeof "GNU"
+ && strcmp (in.namedata, "GNU") == 0
+ && in.type == NT_GNU_PROPERTY_TYPE_0)
+ {
+ unsigned char *ptr;
+ unsigned char *ptr_end;
+
+ if (in.descsz < 8 || (in.descsz % align) != 0)
+ {
+ ret = 1;
+ goto out;
+ }
+
+ ptr = (unsigned char *) in.descdata;
+ ptr_end = ptr + in.descsz;
+
+ do
+ {
+ unsigned int type = byte_get (ptr, 4);
+ unsigned int datasz = byte_get (ptr + 4, 4);
+ unsigned int bitmask, old_bitmask;
+
+ ptr += 8;
+ if ((ptr + datasz) > ptr_end)
+ {
+ ret = 1;
+ goto out;
+ }
+
+ if (type == GNU_PROPERTY_X86_FEATURE_1_AND)
+ {
+ if (datasz != 4)
+ {
+ ret = 1;
+ goto out;
+ }
+
+ old_bitmask = byte_get (ptr, 4);
+ bitmask = old_bitmask;
+ if (enable_x86_features)
+ bitmask |= enable_x86_features;
+ if (disable_x86_features)
+ bitmask &= ~disable_x86_features;
+ if (old_bitmask != bitmask)
+ BYTE_PUT (ptr, bitmask);
+ goto out;
+ }
+
+ ptr += ELF_ALIGN_UP (datasz, align);
+ }
+ while ((ptr_end - ptr) >= 8);
+ }
+
+ p += ELF_NOTE_NEXT_OFFSET (in.namesz, in.descsz, align);
+ }
+ }
+
+out:
+ if (ret != 0)
+ error (_("%s: Invalid PT_NOTE segment\n"), file_name);
+
+ free (phdrs);
+ munmap (map, st_buf.st_size);
+
+ return ret;
+}
+
+/* Set enable_x86_features and disable_x86_features for a feature
+ string, FEATURE. */
+
+static int
+elf_x86_feature (const char *feature, int enable)
+{
+ unsigned int x86_feature;
+ if (strcasecmp (feature, "ibt") == 0)
+ x86_feature = GNU_PROPERTY_X86_FEATURE_1_IBT;
+ else if (strcasecmp (feature, "shstk") == 0)
+ x86_feature = GNU_PROPERTY_X86_FEATURE_1_SHSTK;
+ else
+ return -1;
+
+ if (enable)
+ {
+ enable_x86_features |= x86_feature;
+ disable_x86_features &= ~x86_feature;
+ }
+ else
+ {
+ disable_x86_features |= x86_feature;
+ enable_x86_features &= ~x86_feature;
+ }
+
+ return 0;
+}
+#endif
+
/* Return ELF class for a machine type, MACH. */
static enum elfclass
@@ -533,6 +745,12 @@ process_file (const char *file_name)
rewind (file);
archive_file_size = archive_file_offset = 0;
ret = process_object (file_name, file);
+#ifdef HAVE_MMAP
+ if (!ret
+ && (elf_header.e_type == ET_EXEC
+ || elf_header.e_type == ET_DYN))
+ ret = update_gnu_property (file_name, file);
+#endif
}
fclose (file);
@@ -632,7 +850,11 @@ enum command_line_switch
OPTION_INPUT_TYPE,
OPTION_OUTPUT_TYPE,
OPTION_INPUT_OSABI,
- OPTION_OUTPUT_OSABI
+ OPTION_OUTPUT_OSABI,
+#ifdef HAVE_MMAP
+ OPTION_ENABLE_X86_FEATURE,
+ OPTION_DISABLE_X86_FEATURE,
+#endif
};
static struct option options[] =
@@ -643,6 +865,12 @@ static struct option options[] =
{"output-type", required_argument, 0, OPTION_OUTPUT_TYPE},
{"input-osabi", required_argument, 0, OPTION_INPUT_OSABI},
{"output-osabi", required_argument, 0, OPTION_OUTPUT_OSABI},
+#ifdef HAVE_MMAP
+ {"enable-x86-feature",
+ required_argument, 0, OPTION_ENABLE_X86_FEATURE},
+ {"disable-x86-feature",
+ required_argument, 0, OPTION_DISABLE_X86_FEATURE},
+#endif
{"version", no_argument, 0, 'v'},
{"help", no_argument, 0, 'h'},
{0, no_argument, 0, 0}
@@ -661,7 +889,15 @@ usage (FILE *stream, int exit_status)
--input-type <type> Set input file type to <type>\n\
--output-type <type> Set output file type to <type>\n\
--input-osabi <osabi> Set input OSABI to <osabi>\n\
- --output-osabi <osabi> Set output OSABI to <osabi>\n\
+ --output-osabi <osabi> Set output OSABI to <osabi>\n"));
+#ifdef HAVE_MMAP
+ fprintf (stream, _("\
+ --enable-x86-feature <feature>\n\
+ Enable x86 feature <feature>\n\
+ --disable-x86-feature <feature>\n\
+ Disable x86 feature <feature>\n"));
+#endif
+ fprintf (stream, _("\
-h --help Display this information\n\
-v --version Display the version number of %s\n\
"),
@@ -734,6 +970,18 @@ main (int argc, char ** argv)
return 1;
break;
+#ifdef HAVE_MMAP
+ case OPTION_ENABLE_X86_FEATURE:
+ if (elf_x86_feature (optarg, 1) < 0)
+ return 1;
+ break;
+
+ case OPTION_DISABLE_X86_FEATURE:
+ if (elf_x86_feature (optarg, 0) < 0)
+ return 1;
+ break;
+#endif
+
case 'h':
usage (stdout, 0);
@@ -748,6 +996,10 @@ main (int argc, char ** argv)
if (optind == argc
|| (output_elf_machine == -1
+#ifdef HAVE_MMAP
+ && ! enable_x86_features
+ && ! disable_x86_features
+#endif
&& output_elf_type == -1
&& output_elf_osabi == -1))
usage (stderr, 1);