RFC: PATCH: PR x86_64/584: Detect call on protected symbol
H. J. Lu
hjl@lucon.org
Wed Jan 19 22:49:00 GMT 2005
X86_64 uses R_X86_64_PC32 for both branch and store/load. Linker
can't tell if a protected symbol reference is local or global just
by relocation. This patch disassembles the code to check for call.
H.J.
----
bfd/
2005-01-19 H.J. Lu <hongjiu.lu@intel.com>
PR 584
* elf64-x86-64.c: Include "dis-asm.h" and "libiberty.h".
(elf64_x86_64_disasm): New.
(elf64_x86_64_relocate_section): Disassembly the instruction
for R_X86_64_PC32 relocation on a protected function symbol
when building shared library for call instruction.
ld/
2005-01-19 H.J. Lu <hongjiu.lu@intel.com>
PR 584
* Makefile.am (BFDLIB): Change it to @BFDLIB@.
(eelf_x86_64.c): Also depend on $(srcdir)/emultempl/needdisasm.em.
(eelf_x86_64_fbsd.c): Likewise.
* configure.in (BFDLIB): New. Substitute
(TESTBFDLIB): Updated.
* configure.tgt (need_opcodes): Set to "yes" for ELF/x86_64.
* emulparams/elf_x86_64.sh (EXTRA_EM_FILE): Set to needdisasm.
* emultempl/needdisasm.em: New.
* Makefile.in: Regenerated.
* configure: Likewise.
--- binutils/bfd/elf64-x86-64.c.prot 2005-01-11 09:10:28.000000000 -0800
+++ binutils/bfd/elf64-x86-64.c 2005-01-19 13:02:51.582973722 -0800
@@ -25,6 +25,16 @@
#include "libbfd.h"
#include "elf-bfd.h"
+/* Used to check which instruction R_X86_64_PC32 is used for. */
+#include "dis-asm.h"
+#include "libiberty.h"
+
+extern void init_disassemble_info
+ (struct disassemble_info *, void *, fprintf_ftype) __attribute__((weak));
+extern void disassemble_init_for_target
+ (struct disassemble_info *) __attribute__((weak));
+extern disassembler_ftype disassembler (bfd *) __attribute__((weak));
+
#include "elf/x86-64.h"
/* In case we're on a 32-bit machine, construct a 64-bit "-1" value. */
@@ -1745,6 +1755,12 @@ tpoff (struct bfd_link_info *info, bfd_v
return address - htab->tls_size - htab->tls_sec->vma;
}
+static int
+elf64_x86_64_disasm (void)
+{
+ return 0;
+}
+
/* Relocate an x86_64 ELF section. */
static bfd_boolean
@@ -1760,6 +1776,7 @@ elf64_x86_64_relocate_section (bfd *outp
bfd_vma *local_got_offsets;
Elf_Internal_Rela *rel;
Elf_Internal_Rela *relend;
+ bfd_vma last_offset;
if (info->relocatable)
return TRUE;
@@ -1769,6 +1786,7 @@ elf64_x86_64_relocate_section (bfd *outp
sym_hashes = elf_sym_hashes (input_bfd);
local_got_offsets = elf_local_got_offsets (input_bfd);
+ last_offset = 0;
rel = relocs;
relend = relocs + input_section->reloc_count;
for (; rel < relend; rel++)
@@ -1952,13 +1970,72 @@ elf64_x86_64_relocate_section (bfd *outp
&& (input_section->flags & SEC_ALLOC) != 0
&& (input_section->flags & SEC_READONLY) != 0)
{
- (*_bfd_error_handler)
- (_("%B: relocation %s against `%s' can not be used when making a shared object; recompile with -fPIC"),
- input_bfd,
- x86_64_elf_howto_table[r_type].name,
- (h) ? h->root.root.string : "a local symbol");
- bfd_set_error (bfd_error_bad_value);
- return FALSE;
+ bfd_boolean call;
+ int octets = -1;
+
+ if (!init_disassemble_info)
+ call = FALSE;
+ else if (h->def_regular
+ && r_type == R_X86_64_PC32
+ && h->type == STT_FUNC
+ && ELF_ST_VISIBILITY (h->other) == STV_PROTECTED)
+ {
+ static struct disassemble_info *dis;
+ static disassembler_ftype dis_fn;
+ bfd_vma offset;
+
+ if (dis == NULL && init_disassemble_info)
+ {
+ dis = xmalloc (sizeof (*dis));
+ init_disassemble_info (dis, NULL,
+ (fprintf_ftype) elf64_x86_64_disasm);
+ dis->flavour = bfd_get_flavour (input_bfd);
+ dis->arch = bfd_get_arch (input_bfd);
+ dis->mach = bfd_get_mach (input_bfd);
+ dis->octets_per_byte = bfd_octets_per_byte (input_bfd);
+ if (bfd_big_endian (input_bfd))
+ dis->display_endian = dis->endian = BFD_ENDIAN_BIG;
+ else
+ dis->display_endian = dis->endian = BFD_ENDIAN_LITTLE;
+ disassemble_init_for_target (dis);
+ dis_fn = disassembler (input_bfd);
+ }
+
+ dis->buffer = contents;
+ dis->buffer_vma = input_section->vma;
+ dis->buffer_length = input_section->size;
+ dis->section = input_section;
+
+ for (offset = last_offset; offset < rel->r_offset;)
+ {
+ octets = (*dis_fn) (input_section->vma + offset,
+ dis);
+ if (octets < 0)
+ break;
+ else
+ offset += octets / dis->octets_per_byte;
+ }
+
+ /* Check if the current instruction is call. */
+ if (octets > 0
+ && *(contents + offset - octets) == 0xe8)
+ call = TRUE;
+ else
+ call = FALSE;
+ }
+ else
+ call = FALSE;
+
+ if (! call)
+ {
+ (*_bfd_error_handler)
+ (_("%B: relocation %s against `%s' can not be used when making a shared object; recompile with -fPIC"),
+ input_bfd,
+ x86_64_elf_howto_table[r_type].name,
+ (h) ? h->root.root.string : "a local symbol");
+ bfd_set_error (bfd_error_bad_value);
+ return FALSE;
+ }
}
/* Fall through. */
@@ -2454,6 +2531,11 @@ elf64_x86_64_relocate_section (bfd *outp
return FALSE;
}
}
+
+ if (last_offset == 0)
+ last_offset = rel->r_offset;
+ else if (rel->r_offset < last_offset)
+ last_offset = rel->r_offset;
}
return TRUE;
--- binutils/ld/Makefile.am.prot 2005-01-19 09:08:58.000000000 -0800
+++ binutils/ld/Makefile.am 2005-01-19 13:47:14.696641705 -0800
@@ -104,7 +104,7 @@ man_MANS = ld.1
INCLUDES = -D_GNU_SOURCE -I. -I$(srcdir) -I../bfd -I$(BFDDIR) -I$(INCDIR) -I$(top_srcdir)/../intl -I../intl $(HDEFINES) $(CFLAGS) -DLOCALEDIR="\"$(datadir)/locale\""
-BFDLIB = ../bfd/libbfd.la
+BFDLIB = @BFDLIB@
LIBIBERTY = ../libiberty/libiberty.a
ALL_EMULATIONS = \
@@ -843,11 +843,13 @@ eelf_i386.c: $(srcdir)/emulparams/elf_i3
$(srcdir)/emultempl/elf32.em $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS}
${GENSCRIPTS} elf_i386 "$(tdir_elf_i386)"
eelf_x86_64.c: $(srcdir)/emulparams/elf_x86_64.sh \
- $(srcdir)/emultempl/elf32.em $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS}
+ $(srcdir)/emultempl/elf32.em $(srcdir)/emultempl/needdisasm.em \
+ $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS}
${GENSCRIPTS} elf_x86_64 "$(tdir_elf_x86_64)"
eelf_x86_64_fbsd.c: $(srcdir)/emulparams/elf_x86_64_fbsd.sh \
$(srcdir)/emulparams/elf_x86_64.sh \
- $(srcdir)/emultempl/elf32.em $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS}
+ $(srcdir)/emultempl/elf32.em $(srcdir)/emultempl/needdisasm.em \
+ $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS}
${GENSCRIPTS} elf_x86_64_fbsd "$(tdir_elf_x86_64_fbsd)"
eelf_i386_be.c: $(srcdir)/emulparams/elf_i386_be.sh \
$(srcdir)/emultempl/elf32.em $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS}
--- binutils/ld/configure.in.prot 2005-01-17 09:32:46.000000000 -0800
+++ binutils/ld/configure.in 2005-01-19 14:30:50.926558757 -0800
@@ -250,10 +250,26 @@ AC_SUBST(LIB_PATH)
EMULATION_LIBPATH=$all_libpath
AC_SUBST(EMULATION_LIBPATH)
+# do we need the opcodes library?
+case "${need_opcodes}" in
+yes)
+ BFDLIB="../bfd/libbfd.la ../opcodes/libopcodes.la"
+ if test x${enable_static} = xno; then
+ TESTBFDLIB="--rpath ../opcodes/.libs ../opcodes/.libs/libopcodes.so"
+ else
+ TESTBFDLIB="../opcodes/.libs/libopcodes.a"
+ fi
+ ;;
+*)
+ BFDLIB="../bfd/libbfd.la"
+ ;;
+esac
+AC_SUBST(BFDLIB)
+
if test x${enable_static} = xno; then
- TESTBFDLIB="--rpath ../bfd/.libs ../bfd/.libs/libbfd.so"
+ TESTBFDLIB="--rpath ../bfd/.libs ../bfd/.libs/libbfd.so $TESTBFDLIB"
else
- TESTBFDLIB="../bfd/.libs/libbfd.a"
+ TESTBFDLIB="../bfd/.libs/libbfd.a $TESTBFDLIB"
fi
AC_SUBST(TESTBFDLIB)
--- binutils/ld/configure.tgt.prot 2005-01-19 09:08:58.000000000 -0800
+++ binutils/ld/configure.tgt 2005-01-19 13:43:01.696239040 -0800
@@ -11,6 +11,9 @@
# targ_extra_ofiles additional objects needed by the emulation
# NATIVE_LIB_DIRS library directories to search on this host
# (if we are a native or sysrooted linker)
+# need_opcodes if libopcodes is needed.
+
+need_opcodes=no
targ_extra_emuls=
targ_extra_ofiles=
@@ -165,6 +168,7 @@ i[3-7]86-*-linux-gnu*) targ_emul=elf_i38
targ_extra_emuls=i386linux
if test x${want64} = xtrue; then
targ_extra_emuls="$targ_extra_emuls elf_x86_64"
+ need_opcodes=yes
fi
tdir_i386linux=${targ_alias}aout
;;
@@ -173,10 +177,12 @@ x86_64-*-linux-gnu*) targ_emul=elf_x86_6
targ_extra_libpath=elf_i386
tdir_i386linux=`echo ${targ_alias}aout | sed -e 's/x86_64/i386/'`
tdir_elf_i386=`echo ${targ_alias} | sed -e 's/x86_64/i386/'`
+ need_opcodes=yes
;;
i[3-7]86-*-sysv[45]*) targ_emul=elf_i386 ;;
i[3-7]86-*-solaris2*) targ_emul=elf_i386_ldso
targ_extra_emuls="elf_i386 elf_x86_64"
+ need_opcodes=yes
;;
i[3-7]86-*-unixware) targ_emul=elf_i386 ;;
i[3-7]86-*-solaris*) targ_emul=elf_i386_ldso
@@ -205,6 +211,7 @@ x86_64-*-netbsd*) targ_emul=elf_x86_64
sed -e 's/netbsd/netbsdelf/'`
;;
esac
+ need_opcodes=yes
;;
i[3-7]86-*-netware) targ_emul=i386nw ;;
i[3-7]86-*-elf*) targ_emul=elf_i386 ;;
@@ -219,6 +226,7 @@ x86_64-*-freebsd* | x86_64-*-kfreebsd*-g
targ_extra_emuls="elf_i386_fbsd elf_x86_64 elf_i386"
tdir_elf_i386=`echo ${targ_alias} \
| sed -e 's/x86_64/i386/'`
+ need_opcodes=yes
;;
i[3-7]86-*-sysv*) targ_emul=i386coff ;;
i[3-7]86-*-ptx*) targ_emul=i386coff ;;
--- binutils/ld/emulparams/elf_x86_64.sh.prot 2004-05-11 13:34:35.000000000 -0700
+++ binutils/ld/emulparams/elf_x86_64.sh 2005-01-19 13:30:54.792473055 -0800
@@ -13,6 +13,7 @@ GENERATE_SHLIB_SCRIPT=yes
GENERATE_PIE_SCRIPT=yes
NO_SMALL_DATA=yes
SEPARATE_GOTPLT=24
+EXTRA_EM_FILE=needdisasm
if [ "x${host}" = "x${target}" ]; then
case " $EMULATION_LIBPATH " in
--- binutils/ld/emultempl/needdisasm.em.prot 2005-01-19 13:30:02.508198053 -0800
+++ binutils/ld/emultempl/needdisasm.em 2005-01-19 13:36:40.558345995 -0800
@@ -0,0 +1,34 @@
+# This shell script emits a C file. -*- C -*-
+# Copyright 2004 Free Software Foundation, Inc.
+#
+# This file is part of GLD, the Gnu Linker.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+
+# This file is sourced from elf32.em. It is used by targets which
+# need disassembler.
+
+cat >>e${EMULATION_NAME}.c <<EOF
+
+#include "dis-asm.h"
+
+void (*disassembler_dummy []) (void) =
+{
+ (void (*) (void)) init_disassemble_info,
+ (void (*) (void)) disassemble_init_for_target,
+ (void (*) (void)) disassembler,
+};
+EOF
More information about the Binutils
mailing list