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.
This commit is contained in:
H.J. Lu 2018-11-06 09:38:33 -08:00
parent ddea148b3d
commit 8a6b075bc0
11 changed files with 389 additions and 10 deletions

View File

@ -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 ...

View File

@ -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}.

View File

@ -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);

View File

@ -1,3 +1,14 @@
2018-11-06 H.J. Lu <hongjiu.lu@intel.com>
* 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.
2018-11-05 H.J. Lu <hongjiu.lu@intel.com>
PR gas/23854

View File

@ -243,6 +243,10 @@ if ![info exists READELFFLAGS] then {
set READELFFLAGS {}
}
if ![info exists ELFEDIT] then {
set ELFEDIT [findfile $base_dir/../binutils/elfedit]
}
if ![info exists LD] then {
set LD [findfile $base_dir/ld-new ./ld-new [transform ld]]
}

View File

@ -44,3 +44,49 @@ run_ld_link_exec_tests [list \
"asm" \
] \
]
run_ld_link_tests [list \
[list \
"Build x86-feature-1" \
"-z separate-code -z shstk" \
"" \
"-mx86-used-note=yes" \
{ start.s } \
{{readelf -n x86-feature-1a.rd}} \
"x86-feature-1" \
] \
]
proc elfedit_test { options test output } {
global ELFEDIT
global READELF
global srcdir
global subdir
set test_name "elfedit $options"
send_log "$ELFEDIT $options tmpdir/$test\n"
set got [remote_exec host "$ELFEDIT $options tmpdir/$test" "" "/dev/null"]
if { [lindex $got 0] != 0 || ![string match "" [lindex $got 1]] } then {
send_log "$got\n"
unresolved "$test_name"
}
send_log "$READELF -n $options tmpdir/$test > tmpdir/$output.out\n"
set got [remote_exec host "$READELF -n tmpdir/$test" "" "/dev/null" "tmpdir/$output.out"]
if { [lindex $got 0] != 0 || ![string match "" [lindex $got 1]] } then {
send_log "$got\n"
unresolved "$test_name"
}
if { [regexp_diff tmpdir/$output.out $srcdir/$subdir/$output.rd] } then {
fail "$test_name"
} else {
pass "$test_name"
}
}
elfedit_test "--enable-x86-feature ibt --disable-x86-feature shstk" \
x86-feature-1 x86-feature-1b
elfedit_test "--enable-x86-feature ibt" x86-feature-1 x86-feature-1b
elfedit_test "--disable-x86-feature shstk" x86-feature-1 x86-feature-1c
elfedit_test "--disable-x86-feature ibt" x86-feature-1 x86-feature-1d
elfedit_test "--enable-x86-feature ibt --enable-x86-feature shstk" \
x86-feature-1 x86-feature-1e

View File

@ -0,0 +1,6 @@
Displaying notes found in: .note.gnu.property
Owner Data size Description
GNU 0x[0-9a-f]+ NT_GNU_PROPERTY_TYPE_0
Properties: x86 feature: SHSTK
x86 ISA used: <None>
x86 feature used: x86

View File

@ -0,0 +1,6 @@
Displaying notes found in: .note.gnu.property
Owner Data size Description
GNU 0x[0-9a-f]+ NT_GNU_PROPERTY_TYPE_0
Properties: x86 feature: IBT
x86 ISA used: <None>
x86 feature used: x86

View File

@ -0,0 +1,6 @@
Displaying notes found in: .note.gnu.property
Owner Data size Description
GNU 0x[0-9a-f]+ NT_GNU_PROPERTY_TYPE_0
Properties: x86 feature: IBT
x86 ISA used: <None>
x86 feature used: x86

View File

@ -0,0 +1,6 @@
Displaying notes found in: .note.gnu.property
Owner Data size Description
GNU 0x[0-9a-f]+ NT_GNU_PROPERTY_TYPE_0
Properties: x86 feature: <None>
x86 ISA used: <None>
x86 feature used: x86

View File

@ -0,0 +1,6 @@
Displaying notes found in: .note.gnu.property
Owner Data size Description
GNU 0x[0-9a-f]+ NT_GNU_PROPERTY_TYPE_0
Properties: x86 feature: IBT, SHSTK
x86 ISA used: <None>
x86 feature used: x86